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