]> git.saurik.com Git - apple/security.git/blob - libsecurity_keychain/lib/SecTrustSettings.cpp
Security-55163.44.tar.gz
[apple/security.git] / libsecurity_keychain / lib / SecTrustSettings.cpp
1 /*
2 * Copyright (c) 2005 Apple Computer, Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 /*
25 * SecTrustSettings.cpp - Public interface for manipulation of Trust Settings.
26 *
27 * Created May 10 2005 by dmitch.
28 */
29
30 #include "SecBridge.h"
31 #include "SecTrustSettings.h"
32 #include "SecTrustSettingsPriv.h"
33 #include "TrustSettingsUtils.h"
34 #include "TrustSettings.h"
35 #include "TrustSettingsSchema.h"
36 #include "TrustKeychains.h"
37 #include "Trust.h"
38 #include "SecKeychainPriv.h"
39 #include "Globals.h"
40 #include <CoreServices/../Frameworks/CarbonCore.framework/Headers/MacErrors.h>
41 #include <security_utilities/threading.h>
42 #include <security_utilities/globalizer.h>
43 #include <security_utilities/errors.h>
44 #include <security_cdsa_utilities/cssmerrors.h>
45 #include <security_utilities/logging.h>
46 #include <security_utilities/debugging.h>
47 #include <security_utilities/simpleprefs.h>
48 #include <securityd_client/dictionary.h>
49 #include <securityd_client/ssclient.h>
50 #include <assert.h>
51 #include <vector>
52 #include <CommonCrypto/CommonDigest.h>
53
54 #define trustSettingsDbg(args...) secdebug("trustSettings", ## args)
55
56 /*
57 * Ideally we'd like to implement our own lock to protect the state of the cert stores
58 * without grabbing the global Sec API lock, but we deal with SecCFObjects, so we'll have
59 * to bite the bullet and grab the big lock. We also have our own lock protecting the
60 * global trust settings cache which is also used by the keychain callback function
61 * (which does not grab the Sec API lock).
62 */
63
64 #define BEGIN_RCSAPI \
65 OSStatus __secapiresult; \
66 try {
67 #define END_RCSAPI \
68 __secapiresult=noErr; \
69 } \
70 catch (const MacOSError &err) { __secapiresult=err.osStatus(); } \
71 catch (const CommonError &err) { __secapiresult=SecKeychainErrFromOSStatus(err.osStatus()); } \
72 catch (const std::bad_alloc &) { __secapiresult=memFullErr; } \
73 catch (...) { __secapiresult=internalComponentErr; } \
74 return __secapiresult;
75
76 #define END_RCSAPI0 \
77 catch (...) {} \
78 return;
79
80
81 #pragma mark --- TrustSettings preferences ---
82
83 /*
84 * If Colonel Klink wants to disable user-level Trust Settings, he'll have
85 * to restart the apps which will be affected after he does so. We are not
86 * going to consult system prefs every time we do a cert evaluation. We
87 * consult it once per process and cache the results here.
88 */
89 static bool tsUserTrustDisableValid = false; /* true once we consult prefs */
90 static bool tsUserTrustDisable = false; /* the cached value */
91
92 /*
93 * Determine whether user-level Trust Settings disabled.
94 */
95 static bool tsUserTrustSettingsDisabled()
96 {
97 if(tsUserTrustDisableValid) {
98 return tsUserTrustDisable;
99 }
100 tsUserTrustDisable = false;
101
102 Dictionary* dictionary = Dictionary::CreateDictionary(kSecTrustSettingsPrefsDomain, Dictionary::US_System);
103 if (dictionary)
104 {
105 auto_ptr<Dictionary> prefsDict(dictionary);
106 /* this returns false if the pref isn't there, just like we want */
107 tsUserTrustDisable = prefsDict->getBoolValue(kSecTrustSettingsDisableUserTrustSettings);
108 }
109
110 tsUserTrustDisableValid = true;
111 return tsUserTrustDisable;
112 }
113
114 #pragma mark --- TrustSettings global cache ---
115
116 /***
117 *** cache submodule - keeps per-app copy of zero or one TrustSettings
118 *** for each domain. Used only by SecTrustSettingsEvaluateCert()
119 *** and SecTrustSettingsCopyQualifiedCerts(); results of
120 *** manipulation by public API functions are not cached.
121 ***/
122
123 /*
124 * API/client code has to hold this lock when doing anything with any of
125 * the TrustSettings maintained here.
126 * It's recursive to accomodate CodeSigning's need to do cert verification
127 * (while we evaluate app equivalence).
128 */
129 static ModuleNexus<RecursiveMutex> sutCacheLock;
130
131 #define TRUST_SETTINGS_NUM_DOMAINS 3
132
133 /*
134 * The three global TrustSettings.
135 * We rely on the fact the the domain enums start with 0; we use
136 * the domain value as an index into the following two arrays.
137 */
138 static TrustSettings *globalTrustSettings[TRUST_SETTINGS_NUM_DOMAINS] =
139 {NULL, NULL, NULL};
140
141 /*
142 * Indicates "the associated global here is currently valid; if there isn't a
143 * globalTrustSettings[domain], don't try to find one"
144 */
145 static bool globalTrustSettingsValid[TRUST_SETTINGS_NUM_DOMAINS] =
146 {false, false, false};
147
148 /* remember the fact that we've registered our KC callback */
149 static bool sutRegisteredCallback = false;
150
151 static void tsRegisterCallback();
152
153 /*
154 * Assign global TrustSetting to new incoming value, which may be NULL.
155 * Caller holds sutCacheLock.
156 */
157 static void tsSetGlobalTrustSettings(
158 TrustSettings *ts,
159 SecTrustSettingsDomain domain)
160 {
161 assert(((int)domain >= 0) && ((int)domain < TRUST_SETTINGS_NUM_DOMAINS));
162
163 trustSettingsDbg("tsSetGlobalTrustSettings domain %d: caching TS %p old TS %p",
164 (int)domain, ts, globalTrustSettings[domain]);
165 delete globalTrustSettings[domain];
166 globalTrustSettings[domain] = ts;
167 globalTrustSettingsValid[domain] = ts ? true : false;
168 tsRegisterCallback();
169 }
170
171 /*
172 * Obtain global TrustSettings for specified domain if it exists.
173 * Returns NULL if there is simply no TS for that domain.
174 * The TS, if returned, belongs to this cache module.
175 * Caller holds sutCacheLock.
176 */
177 static TrustSettings *tsGetGlobalTrustSettings(
178 SecTrustSettingsDomain domain)
179 {
180 assert(((int)domain >= 0) && ((int)domain < TRUST_SETTINGS_NUM_DOMAINS));
181
182 if((domain == kSecTrustSettingsDomainUser) && tsUserTrustSettingsDisabled()) {
183 trustSettingsDbg("tsGetGlobalTrustSettings: skipping DISABLED user domain");
184 return NULL;
185 }
186
187 if(globalTrustSettingsValid[domain]) {
188 // ready or not, use this
189 return globalTrustSettings[domain];
190 }
191 assert(globalTrustSettings[domain] == NULL);
192
193 /* try to find one */
194 OSStatus result = noErr;
195 TrustSettings *ts = NULL;
196 /* don't create; trim if found */
197 result = TrustSettings::CreateTrustSettings(domain, CREATE_NO, TRIM_YES, ts);
198 if(result != noErr && result != errSecNoTrustSettings) {
199 /* gross error */
200 MacOSError::throwMe(result);
201 }
202 else if (result != noErr) {
203 /*
204 * No TrustSettings for this domain, actually a fairly common case.
205 * Optimize: don't bother trying this again.
206 */
207 trustSettingsDbg("tsGetGlobalTrustSettings: flagging known NULL");
208 globalTrustSettingsValid[domain] = true;
209 tsRegisterCallback();
210 return NULL;
211 }
212
213 tsSetGlobalTrustSettings(ts, domain);
214 return ts;
215 }
216
217 /*
218 * Purge TrustSettings cache.
219 * Called by Keychain Event callback and by our API functions that
220 * modify trust settings.
221 * Caller can NOT hold sutCacheLock.
222 */
223 static void tsPurgeCache()
224 {
225 int domain;
226
227 StLock<Mutex> _(sutCacheLock());
228 trustSettingsDbg("tsPurgeCache");
229 for(domain=0; domain<TRUST_SETTINGS_NUM_DOMAINS; domain++) {
230 tsSetGlobalTrustSettings(NULL, domain);
231 }
232 }
233
234 /*
235 * Keychain event callback function, for notification by other processes that
236 * user trust list(s) has/have changed.
237 */
238 static OSStatus tsTrustSettingsCallback (
239 SecKeychainEvent keychainEvent,
240 SecKeychainCallbackInfo *info,
241 void *context)
242 {
243 trustSettingsDbg("tsTrustSettingsCallback, event %d", (int)keychainEvent);
244 if(keychainEvent != kSecTrustSettingsChangedEvent) {
245 /* should not happen, right? */
246 return noErr;
247 }
248 if(info->pid == getpid()) {
249 /*
250 * Avoid dup cache invalidates: we already dealt with this event.
251 */
252 trustSettingsDbg("cacheEventCallback: our pid, skipping");
253 }
254 else {
255 tsPurgeCache();
256 }
257 return noErr;
258 }
259
260 /*
261 * Ensure that we've registered for kSecTrustSettingsChangedEvent callbacks
262 */
263 static void tsRegisterCallback()
264 {
265 if(sutRegisteredCallback) {
266 return;
267 }
268 trustSettingsDbg("tsRegisterCallback: registering callback");
269 OSStatus ortn = SecKeychainAddCallback(tsTrustSettingsCallback,
270 kSecTrustSettingsChangedEventMask, NULL);
271 if(ortn) {
272 trustSettingsDbg("tsRegisterCallback: SecKeychainAddCallback returned %ld", ortn);
273 /* Not sure how this could ever happen - maybe if there is no run loop active? */
274 }
275 sutRegisteredCallback = true;
276 }
277
278 #pragma mark --- Static functions ---
279
280
281 /*
282 * Called by API code when a trust list has changed; we notify other processes
283 * and purge our own cache.
284 */
285 static void tsTrustSettingsChanged()
286 {
287 tsPurgeCache();
288
289 /* The only interesting data is our pid */
290 NameValueDictionary nvd;
291 pid_t ourPid = getpid();
292 nvd.Insert (new NameValuePair (PID_KEY,
293 CssmData (reinterpret_cast<void*>(&ourPid), sizeof (pid_t))));
294 CssmData data;
295 nvd.Export (data);
296
297 trustSettingsDbg("tsTrustSettingsChanged: posting notification");
298 SecurityServer::ClientSession cs (Allocator::standard(), Allocator::standard());
299 cs.postNotification (SecurityServer::kNotificationDomainDatabase,
300 kSecTrustSettingsChangedEvent, data);
301 free (data.data ());
302 }
303
304 /*
305 * Common code for SecTrustSettingsCopyTrustSettings(),
306 * SecTrustSettingsCopyModificationDate().
307 */
308 static OSStatus tsCopyTrustSettings(
309 SecCertificateRef cert,
310 SecTrustSettingsDomain domain,
311 CFArrayRef *trustSettings, /* optionally RETURNED */
312 CFDateRef *modDate) /* optionally RETURNED */
313 {
314 BEGIN_RCSAPI
315
316 TS_REQUIRED(cert)
317
318 /* obtain fresh full copy from disk */
319 OSStatus result;
320 TrustSettings* ts;
321
322 result = TrustSettings::CreateTrustSettings(domain, CREATE_NO, TRIM_NO, ts);
323
324 // rather than throw these results, just return them because we are at the top level
325 if (result == errSecNoTrustSettings) {
326 return errSecItemNotFound;
327 }
328 else if (result != noErr) {
329 return result;
330 }
331
332 auto_ptr<TrustSettings>_(ts); // make sure this gets deleted just in case something throws underneath
333
334 if(trustSettings) {
335 *trustSettings = ts->copyTrustSettings(cert);
336 }
337 if(modDate) {
338 *modDate = ts->copyModDate(cert);
339 }
340
341 END_RCSAPI
342 }
343
344 /*
345 * Common code for SecTrustSettingsCopyQualifiedCerts() and
346 * SecTrustSettingsCopyUnrestrictedRoots().
347 */
348 static OSStatus tsCopyCertsCommon(
349 /* usage constraints, all optional */
350 const CSSM_OID *policyOID,
351 const char *policyString,
352 SecTrustSettingsKeyUsage keyUsage,
353 /* constrain to only roots */
354 bool onlyRoots,
355 /* per-domain enables */
356 bool user,
357 bool admin,
358 bool system,
359 CFArrayRef *certArray) /* RETURNED */
360 {
361 StLock<Mutex> _TC(sutCacheLock());
362 StLock<Mutex> _TK(SecTrustKeychainsGetMutex());
363
364 TS_REQUIRED(certArray)
365
366 /* this relies on the domain enums being numbered 0..2, user..system */
367 bool domainEnable[3] = {user, admin, system};
368
369 /* we'll retain it again before successful exit */
370 CFRef<CFMutableArrayRef> outArray(CFArrayCreateMutable(NULL, 0,
371 &kCFTypeArrayCallBacks));
372
373 /*
374 * Search all keychains - user's, System.keychain, system root store,
375 * system intermdiates as appropriate
376 */
377 StorageManager::KeychainList keychains;
378 Keychain adminKc;
379 if(user) {
380 globals().storageManager.getSearchList(keychains);
381 }
382 if(user || admin) {
383 adminKc = globals().storageManager.make(ADMIN_CERT_STORE_PATH, false);
384 keychains.push_back(adminKc);
385 }
386 Keychain sysRootKc = globals().storageManager.make(SYSTEM_ROOT_STORE_PATH, false);
387 keychains.push_back(sysRootKc);
388 Keychain sysCertKc = globals().storageManager.make(SYSTEM_CERT_STORE_PATH, false);
389 keychains.push_back(sysCertKc);
390
391 assert(kSecTrustSettingsDomainUser == 0);
392 for(unsigned domain=0; domain<TRUST_SETTINGS_NUM_DOMAINS; domain++) {
393 if(!domainEnable[domain]) {
394 continue;
395 }
396 TrustSettings *ts = tsGetGlobalTrustSettings(domain);
397 if(ts == NULL) {
398 continue;
399 }
400 ts->findQualifiedCerts(keychains,
401 false, /* !findAll */
402 onlyRoots,
403 policyOID, policyString, keyUsage,
404 outArray);
405 }
406 *certArray = outArray;
407 CFRetain(*certArray);
408 trustSettingsDbg("tsCopyCertsCommon: %ld certs found",
409 CFArrayGetCount(outArray));
410 return noErr;
411 }
412
413 #pragma mark --- SPI functions ---
414
415
416 /*
417 * Fundamental routine used by TP to ascertain status of one cert.
418 *
419 * Returns true in *foundMatchingEntry if a trust setting matching
420 * specific constraints was found for the cert. Returns true in
421 * *foundAnyEntry if any entry was found for the cert, even if it
422 * did not match the specified constraints. The TP uses this to
423 * optimize for the case where a cert is being evaluated for
424 * one type of usage, and then later for another type. If
425 * foundAnyEntry is false, the second evaluation need not occur.
426 *
427 * Returns the domain in which a setting was found in *foundDomain.
428 *
429 * Allowed errors applying to the specified cert evaluation
430 * are returned in a mallocd array in *allowedErrors and must
431 * be freed by caller.
432 *
433 * The design of the entire TrustSettings module is centered around
434 * optimizing the performance of this routine (security concerns
435 * aside, that is). It's why the per-cert dictionaries are stored
436 * as a dictionary, keyed off of the cert hash. It's why TrustSettings
437 * are cached in memory by tsGetGlobalTrustSettings(), and why those
438 * cached TrustSettings objects are 'trimmed' of dictionary fields
439 * which are not needed to verify a cert.
440 *
441 * The API functions which are used to manipulate Trust Settings
442 * are called infrequently and need not be particularly fast since
443 * they result in user interaction for authentication. Thus they do
444 * not use cached TrustSettings as this function does.
445 */
446 OSStatus SecTrustSettingsEvaluateCert(
447 CFStringRef certHashStr,
448 /* parameters describing the current cert evalaution */
449 const CSSM_OID *policyOID,
450 const char *policyString, /* optional */
451 uint32 policyStringLen,
452 SecTrustSettingsKeyUsage keyUsage, /* optional */
453 bool isRootCert, /* for checking default setting */
454 /* RETURNED values */
455 SecTrustSettingsDomain *foundDomain,
456 CSSM_RETURN **allowedErrors, /* mallocd */
457 uint32 *numAllowedErrors,
458 SecTrustSettingsResult *resultType,
459 bool *foundMatchingEntry,
460 bool *foundAnyEntry)
461 {
462 BEGIN_RCSAPI
463
464 StLock<Mutex> _(sutCacheLock());
465
466 TS_REQUIRED(certHashStr)
467 TS_REQUIRED(foundDomain)
468 TS_REQUIRED(allowedErrors)
469 TS_REQUIRED(numAllowedErrors)
470 TS_REQUIRED(resultType)
471 TS_REQUIRED(foundMatchingEntry)
472 TS_REQUIRED(foundAnyEntry)
473
474 /* ensure a NULL_terminated string */
475 auto_array<char> polStr;
476 if(policyString != NULL && policyStringLen > 0) {
477 polStr.allocate(policyStringLen + 1);
478 memmove(polStr.get(), policyString, policyStringLen);
479 if(policyString[policyStringLen - 1] != '\0') {
480 (polStr.get())[policyStringLen] = '\0';
481 }
482 }
483
484 /* initial condition - this can grow if we inspect multiple TrustSettings */
485 *allowedErrors = NULL;
486 *numAllowedErrors = 0;
487
488 /*
489 * This loop relies on the ordering of the SecTrustSettingsDomain enum:
490 * search user first, then admin, then system.
491 */
492 assert(kSecTrustSettingsDomainAdmin == (kSecTrustSettingsDomainUser + 1));
493 assert(kSecTrustSettingsDomainSystem == (kSecTrustSettingsDomainAdmin + 1));
494 bool foundAny = false;
495 for(unsigned domain=kSecTrustSettingsDomainUser;
496 domain<=kSecTrustSettingsDomainSystem;
497 domain++) {
498 TrustSettings *ts = tsGetGlobalTrustSettings(domain);
499 if(ts == NULL) {
500 continue;
501 }
502
503 /* validate cert returns true if matching entry was found */
504 bool foundAnyHere = false;
505 bool found = ts->evaluateCert(certHashStr, policyOID,
506 polStr.get(), keyUsage, isRootCert,
507 allowedErrors, numAllowedErrors, resultType, &foundAnyHere);
508
509 if(found) {
510 /*
511 * Note this, even though we may overwrite it later if this
512 * is an Unspecified entry and we find a definitive entry
513 * later
514 */
515 *foundDomain = domain;
516 }
517 if(found && (*resultType != kSecTrustSettingsResultUnspecified)) {
518 trustSettingsDbg("SecTrustSettingsEvaluateCert: found in domain %d", domain);
519 *foundAnyEntry = true;
520 *foundMatchingEntry = true;
521 return noErr;
522 }
523 foundAny |= foundAnyHere;
524 }
525 trustSettingsDbg("SecTrustSettingsEvaluateCert: NOT FOUND");
526 *foundAnyEntry = foundAny;
527 *foundMatchingEntry = false;
528 return noErr;
529 END_RCSAPI
530 }
531
532 /*
533 * Obtain trusted certs which match specified usage.
534 * Only certs with a SecTrustSettingsResult of
535 * kSecTrustSettingsResultTrustRoot or
536 * or kSecTrustSettingsResultTrustAsRoot will be returned.
537 * To be used by SecureTransport for its SSLSetTrustedRoots() call;
538 * I hope nothing else has to use this...
539 * Caller must CFRelease the returned CFArrayRef.
540 */
541 OSStatus SecTrustSettingsCopyQualifiedCerts(
542 const CSSM_OID *policyOID,
543 const char *policyString, /* optional */
544 uint32 policyStringLen,
545 SecTrustSettingsKeyUsage keyUsage, /* optional */
546 CFArrayRef *certArray) /* RETURNED */
547 {
548 BEGIN_RCSAPI
549
550 /* ensure a NULL_terminated string */
551 auto_array<char> polStr;
552 if(policyString != NULL) {
553 polStr.allocate(policyStringLen + 1);
554 memmove(polStr.get(), policyString, policyStringLen);
555 if(policyString[policyStringLen - 1] != '\0') {
556 (polStr.get())[policyStringLen] = '\0';
557 }
558 }
559
560 return tsCopyCertsCommon(policyOID, polStr.get(), keyUsage,
561 false, /* !onlyRoots */
562 true, true, true, /* all domains */
563 certArray);
564
565 END_RCSAPI
566 }
567
568 /*
569 * Obtain unrestricted root certs fromt eh specified domain(s).
570 * Only returns roots with no usage constraints.
571 * Caller must CFRelease the returned CFArrayRef.
572 */
573 OSStatus SecTrustSettingsCopyUnrestrictedRoots(
574 Boolean user,
575 Boolean admin,
576 Boolean system,
577 CFArrayRef *certArray) /* RETURNED */
578 {
579 BEGIN_RCSAPI
580
581 return tsCopyCertsCommon(NULL, NULL, NULL, /* no constraints */
582 true, /* onlyRoots */
583 user, admin, system,
584 certArray);
585
586 END_RCSAPI
587 }
588
589 static const char hexChars[16] = {
590 '0', '1', '2', '3', '4', '5', '6', '7',
591 '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
592 };
593
594 /*
595 * Obtain a string representing a cert's SHA1 digest. This string is
596 * the key used to look up per-cert trust settings in a TrustSettings record.
597 */
598 CFStringRef SecTrustSettingsCertHashStrFromCert(
599 SecCertificateRef certRef)
600 {
601 if(certRef == NULL) {
602 return NULL;
603 }
604
605 if(certRef == kSecTrustSettingsDefaultRootCertSetting) {
606 /* use this string instead of the cert hash as the dictionary key */
607 trustSettingsDbg("SecTrustSettingsCertHashStrFromCert: DefaultSetting");
608 return kSecTrustRecordDefaultRootCert;
609 }
610
611 CSSM_DATA certData;
612 OSStatus ortn = SecCertificateGetData(certRef, &certData);
613 if(ortn) {
614 return NULL;
615 }
616 return SecTrustSettingsCertHashStrFromData(certData.Data, certData.Length);
617 }
618
619 CFStringRef SecTrustSettingsCertHashStrFromData(
620 const void *cert,
621 size_t certLen)
622 {
623 unsigned char digest[CC_SHA1_DIGEST_LENGTH];
624 char asciiDigest[(2 * CC_SHA1_DIGEST_LENGTH) + 1];
625 unsigned dex;
626 char *outp = asciiDigest;
627 unsigned char *inp = digest;
628
629 if(cert == NULL) {
630 return NULL;
631 }
632
633 CC_SHA1(cert, certLen, digest);
634
635 for(dex=0; dex<CC_SHA1_DIGEST_LENGTH; dex++) {
636 unsigned c = *inp++;
637 outp[1] = hexChars[c & 0xf];
638 c >>= 4;
639 outp[0] = hexChars[c];
640 outp += 2;
641 }
642 *outp = 0;
643 return CFStringCreateWithCString(NULL, asciiDigest, kCFStringEncodingASCII);
644 }
645
646 /*
647 * Add a cert's TrustSettings to a non-persistent TrustSettings record.
648 * No locking or cache flushing here; it's all local to the TrustSettings
649 * we construct here.
650 */
651 OSStatus SecTrustSettingsSetTrustSettingsExternal(
652 CFDataRef settingsIn, /* optional */
653 SecCertificateRef certRef, /* optional */
654 CFTypeRef trustSettingsDictOrArray, /* optional */
655 CFDataRef *settingsOut) /* RETURNED */
656 {
657 BEGIN_RCSAPI
658
659 TS_REQUIRED(settingsOut)
660
661 OSStatus result;
662 TrustSettings* ts;
663
664 result = TrustSettings::CreateTrustSettings(kSecTrustSettingsDomainMemory, settingsIn, ts);
665 if (result != noErr) {
666 return result;
667 }
668
669 auto_ptr<TrustSettings>_(ts);
670
671 if(certRef != NULL) {
672 ts->setTrustSettings(certRef, trustSettingsDictOrArray);
673 }
674 *settingsOut = ts->createExternal();
675 return noErr;
676
677 END_RCSAPI
678 }
679
680 #pragma mark --- API functions ---
681
682 OSStatus SecTrustSettingsCopyTrustSettings(
683 SecCertificateRef certRef,
684 SecTrustSettingsDomain domain,
685 CFArrayRef *trustSettings) /* RETURNED */
686 {
687 TS_REQUIRED(trustSettings)
688
689 OSStatus result = tsCopyTrustSettings(certRef, domain, trustSettings, NULL);
690 if (result == noErr && *trustSettings == NULL) {
691 result = errSecItemNotFound; /* documented result if no trust settings exist */
692 }
693 return result;
694 }
695
696 OSStatus SecTrustSettingsCopyModificationDate(
697 SecCertificateRef certRef,
698 SecTrustSettingsDomain domain,
699 CFDateRef *modificationDate) /* RETURNED */
700 {
701 TS_REQUIRED(modificationDate)
702
703 OSStatus result = tsCopyTrustSettings(certRef, domain, NULL, modificationDate);
704 if (result == noErr && *modificationDate == NULL) {
705 result = errSecItemNotFound; /* documented result if no trust settings exist */
706 }
707 return result;
708 }
709
710 /* works with existing and with new cert */
711 OSStatus SecTrustSettingsSetTrustSettings(
712 SecCertificateRef certRef,
713 SecTrustSettingsDomain domain,
714 CFTypeRef trustSettingsDictOrArray)
715 {
716 BEGIN_RCSAPI
717
718 TS_REQUIRED(certRef)
719
720 if(domain == kSecTrustSettingsDomainSystem) {
721 return errSecDataNotModifiable;
722 }
723
724 OSStatus result;
725 TrustSettings* ts;
726
727 result = TrustSettings::CreateTrustSettings(domain, CREATE_YES, TRIM_NO, ts);
728 if (result != noErr) {
729 return result;
730 }
731
732 auto_ptr<TrustSettings>_(ts);
733
734 ts->setTrustSettings(certRef, trustSettingsDictOrArray);
735 ts->flushToDisk();
736 tsTrustSettingsChanged();
737 return noErr;
738
739 END_RCSAPI
740 }
741
742 OSStatus SecTrustSettingsRemoveTrustSettings(
743 SecCertificateRef cert,
744 SecTrustSettingsDomain domain)
745 {
746 BEGIN_RCSAPI
747
748 TS_REQUIRED(cert)
749
750 if(domain == kSecTrustSettingsDomainSystem) {
751 return errSecDataNotModifiable;
752 }
753
754 OSStatus result;
755 TrustSettings* ts;
756
757 result = TrustSettings::CreateTrustSettings(domain, CREATE_NO, TRIM_NO, ts);
758 if (result != noErr) {
759 return result;
760 }
761
762 auto_ptr<TrustSettings>_(ts);
763
764 /* deleteTrustSettings throws if record not found */
765 trustSettingsDbg("SecTrustSettingsRemoveTrustSettings: deleting from domain %d",
766 (int)domain);
767 ts->deleteTrustSettings(cert);
768 ts->flushToDisk();
769 tsTrustSettingsChanged();
770 return noErr;
771
772 END_RCSAPI
773 }
774
775 /* get all certs listed in specified domain */
776 OSStatus SecTrustSettingsCopyCertificates(
777 SecTrustSettingsDomain domain,
778 CFArrayRef *certArray)
779 {
780 BEGIN_RCSAPI
781
782 TS_REQUIRED(certArray)
783
784 OSStatus result;
785 TrustSettings* ts;
786
787 result = TrustSettings::CreateTrustSettings(domain, CREATE_NO, TRIM_NO, ts);
788 if (result != noErr) {
789 return result;
790 }
791
792 auto_ptr<TrustSettings>_(ts);
793
794 CFMutableArrayRef outArray = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
795
796 /*
797 * Keychains to search: user's search list, System.keychain, system root store,
798 * system intermdiates, as appropriate
799 */
800 StorageManager::KeychainList keychains;
801 Keychain adminKc;
802 Keychain sysCertKc;
803 Keychain sysRootKc;
804 switch(domain) {
805 case kSecTrustSettingsDomainUser:
806 /* user search list */
807 globals().storageManager.getSearchList(keychains);
808 /* drop thru to next case */
809 case kSecTrustSettingsDomainAdmin:
810 /* admin certs in system keychain */
811 adminKc = globals().storageManager.make(ADMIN_CERT_STORE_PATH, false);
812 keychains.push_back(adminKc);
813 /* system-wide intermediate certs */
814 sysCertKc = globals().storageManager.make(SYSTEM_CERT_STORE_PATH, false);
815 keychains.push_back(sysCertKc);
816 /* drop thru to next case */
817 case kSecTrustSettingsDomainSystem:
818 /* and, for all cases, immutable system root store */
819 sysRootKc = globals().storageManager.make(SYSTEM_ROOT_STORE_PATH, false);
820 keychains.push_back(sysRootKc);
821 default:
822 /* already validated when we created the TrustSettings */
823 break;
824 }
825 ts->findCerts(keychains, outArray);
826 if(CFArrayGetCount(outArray) == 0) {
827 CFRelease(outArray);
828 return errSecNoTrustSettings;
829 }
830 *certArray = outArray;
831 END_RCSAPI
832 }
833
834 /*
835 * Obtain an external, portable representation of the specified
836 * domain's TrustSettings. Caller must CFRelease the returned data.
837 */
838 OSStatus SecTrustSettingsCreateExternalRepresentation(
839 SecTrustSettingsDomain domain,
840 CFDataRef *trustSettings)
841 {
842 BEGIN_RCSAPI
843
844 TS_REQUIRED(trustSettings)
845
846 OSStatus result;
847 TrustSettings* ts;
848
849 result = TrustSettings::CreateTrustSettings(domain, CREATE_NO, TRIM_NO, ts);
850 if (result != noErr) {
851 return result;
852 }
853
854 auto_ptr<TrustSettings>_(ts);
855
856 *trustSettings = ts->createExternal();
857 return noErr;
858
859 END_RCSAPI
860 }
861
862 /*
863 * Import trust settings, obtained via SecTrustSettingsCreateExternalRepresentation,
864 * into the specified domain.
865 */
866 OSStatus SecTrustSettingsImportExternalRepresentation(
867 SecTrustSettingsDomain domain,
868 CFDataRef trustSettings) /* optional - NULL means empty settings */
869 {
870 BEGIN_RCSAPI
871
872 if(domain == kSecTrustSettingsDomainSystem) {
873 return errSecDataNotModifiable;
874 }
875
876 OSStatus result;
877 TrustSettings* ts;
878
879 result = TrustSettings::CreateTrustSettings(domain, trustSettings, ts);
880 if (result != noErr) {
881 return result;
882 }
883
884 auto_ptr<TrustSettings>_(ts);
885
886 ts->flushToDisk();
887 tsTrustSettingsChanged();
888 return noErr;
889
890 END_RCSAPI
891 }
892