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