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