]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_keychain/lib/SecTrustSettings.cpp
Security-59754.41.1.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 <Security/SecCertificatePriv.h>
31 #include <Security/SecTrustSettings.h>
32 #include <Security/SecTrustSettingsPriv.h>
33 #include "SecTrustSettingsCertificates.h"
34 #include "SecCFRelease.h"
35 #include "TrustSettingsUtils.h"
36 #include "TrustSettings.h"
37 #include "TrustSettingsSchema.h"
38 #include "TrustKeychains.h"
39 #include "Trust.h"
40 #include "SecKeychainPriv.h"
41 #include "Globals.h"
42 #include <security_utilities/threading.h>
43 #include <security_utilities/globalizer.h>
44 #include <security_utilities/errors.h>
45 #include <security_cdsa_utilities/cssmerrors.h>
46 #include <security_utilities/logging.h>
47 #include <security_utilities/debugging.h>
48 #include <security_utilities/simpleprefs.h>
49 #include <securityd_client/dictionary.h>
50 #include <securityd_client/ssclient.h>
51 #include <security_utilities/simulatecrash_assert.h>
52 #include <dlfcn.h>
53 #include <libproc.h>
54 #include <syslog.h>
55 #include <vector>
56 #include <CommonCrypto/CommonDigest.h>
57 #include <CoreFoundation/CFPreferences.h>
58 #include <utilities/SecCFRelease.h>
59
60 #define trustSettingsDbg(args...) secinfo("trustSettings", ## args)
61
62 /*
63 * Ideally we'd like to implement our own lock to protect the state of the cert stores
64 * without grabbing the global Sec API lock, but we deal with SecCFObjects, so we'll have
65 * to bite the bullet and grab the big lock. We also have our own lock protecting the
66 * global trust settings cache which is also used by the keychain callback function
67 * (which does not grab the Sec API lock).
68 */
69
70 #define BEGIN_RCSAPI \
71 OSStatus __secapiresult; \
72 try {
73 #define END_RCSAPI \
74 __secapiresult=errSecSuccess; \
75 } \
76 catch (const MacOSError &err) { __secapiresult=err.osStatus(); } \
77 catch (const CommonError &err) { __secapiresult=SecKeychainErrFromOSStatus(err.osStatus()); } \
78 catch (const std::bad_alloc &) { __secapiresult=errSecAllocate; } \
79 catch (...) { __secapiresult=errSecInternalComponent; } \
80 return __secapiresult;
81
82 #define END_RCSAPI0 \
83 catch (...) {} \
84 return;
85
86
87 #pragma mark --- TrustSettings preferences ---
88
89 /*
90 * If Colonel Klink wants to disable user-level Trust Settings, he'll have
91 * to restart the apps which will be affected after he does so. We are not
92 * going to consult system prefs every time we do a cert evaluation. We
93 * consult it once per process and cache the results here.
94 */
95 static bool tsUserTrustDisableValid = false; /* true once we consult prefs */
96 static bool tsUserTrustDisable = false; /* the cached value */
97
98 /*
99 * Determine whether user-level Trust Settings disabled.
100 */
101 static bool tsUserTrustSettingsDisabled()
102 {
103 if(tsUserTrustDisableValid) {
104 return tsUserTrustDisable;
105 }
106 tsUserTrustDisable = false;
107
108 Dictionary* dictionary = Dictionary::CreateDictionary(kSecTrustSettingsPrefsDomain, Dictionary::US_System);
109 if (dictionary)
110 {
111 unique_ptr<Dictionary> prefsDict(dictionary);
112 /* this returns false if the pref isn't there, just like we want */
113 tsUserTrustDisable = prefsDict->getBoolValue(kSecTrustSettingsDisableUserTrustSettings);
114 }
115
116 tsUserTrustDisableValid = true;
117 return tsUserTrustDisable;
118 }
119
120 #pragma mark --- TrustSettings global cache ---
121
122 /***
123 *** cache submodule - keeps per-app copy of zero or one TrustSettings
124 *** for each domain. Used only by SecTrustSettingsEvaluateCert()
125 *** and SecTrustSettingsCopyQualifiedCerts(); results of
126 *** manipulation by public API functions are not cached.
127 ***/
128
129 /*
130 * API/client code has to hold this lock when doing anything with any of
131 * the TrustSettings maintained here.
132 * It's recursive to accomodate CodeSigning's need to do cert verification
133 * (while we evaluate app equivalence).
134 */
135 static ModuleNexus<RecursiveMutex> sutCacheLock;
136
137 #define TRUST_SETTINGS_NUM_DOMAINS 3
138
139 /*
140 * The three global TrustSettings.
141 * We rely on the fact the the domain enums start with 0; we use
142 * the domain value as an index into the following two arrays.
143 */
144 static TrustSettings *globalTrustSettings[TRUST_SETTINGS_NUM_DOMAINS] =
145 {NULL, NULL, NULL};
146
147 /*
148 * Indicates "the associated global here is currently valid; if there isn't a
149 * globalTrustSettings[domain], don't try to find one"
150 */
151 static bool globalTrustSettingsValid[TRUST_SETTINGS_NUM_DOMAINS] =
152 {false, false, false};
153
154 /* remember the fact that we've registered our KC callback */
155 static bool sutRegisteredCallback = false;
156
157 static void tsRegisterCallback();
158
159 /*
160 * Assign global TrustSetting to new incoming value, which may be NULL.
161 * Caller holds sutCacheLock.
162 */
163 static void tsSetGlobalTrustSettings(
164 TrustSettings *ts,
165 SecTrustSettingsDomain domain)
166 {
167 assert(((int)domain >= 0) && ((int)domain < TRUST_SETTINGS_NUM_DOMAINS));
168
169 trustSettingsDbg("tsSetGlobalTrustSettings domain %d: caching TS %p old TS %p",
170 (int)domain, ts, globalTrustSettings[domain]);
171 delete globalTrustSettings[domain];
172 globalTrustSettings[domain] = ts;
173 globalTrustSettingsValid[domain] = ts ? true : false;
174 tsRegisterCallback();
175 }
176
177 /*
178 * Obtain global TrustSettings for specified domain if it exists.
179 * Returns NULL if there is simply no TS for that domain.
180 * The TS, if returned, belongs to this cache module.
181 * Caller holds sutCacheLock.
182 */
183 static TrustSettings *tsGetGlobalTrustSettings(
184 SecTrustSettingsDomain domain)
185 {
186 assert(((int)domain >= 0) && ((int)domain < TRUST_SETTINGS_NUM_DOMAINS));
187
188 if((domain == kSecTrustSettingsDomainUser) && tsUserTrustSettingsDisabled()) {
189 trustSettingsDbg("tsGetGlobalTrustSettings: skipping DISABLED user domain");
190 return NULL;
191 }
192
193 if(globalTrustSettingsValid[domain]) {
194 // ready or not, use this
195 return globalTrustSettings[domain];
196 }
197 assert(globalTrustSettings[domain] == NULL);
198
199 /* try to find one */
200 OSStatus result = errSecSuccess;
201 TrustSettings *ts = NULL;
202 /* don't create; trim if found */
203 result = TrustSettings::CreateTrustSettings(domain, CREATE_NO, TRIM_YES, ts);
204 if ( (domain != kSecTrustSettingsDomainSystem)
205 && (result == errSecInternalComponent)) {
206 /*
207 * Could not connect to ocspd to get the user/admin domain trust settings
208 * This happens in single user mode for example.
209 * Valid flag is set to false and continue.
210 */
211 trustSettingsDbg("tsGetGlobalTrustSettings: could not connect to ocspd for domain (%d)",(int)domain);
212 globalTrustSettingsValid[domain] = false;
213 tsRegisterCallback();
214 return NULL;
215 }
216 else if (result == errSecNoTrustSettings) {
217 /*
218 * No TrustSettings for this domain, actually a fairly common case.
219 * Optimize: don't bother trying this again.
220 */
221 trustSettingsDbg("tsGetGlobalTrustSettings: flagging known NULL");
222 globalTrustSettingsValid[domain] = true;
223 tsRegisterCallback();
224 return NULL;
225 }
226 else if(result != errSecSuccess) {
227 /* gross error */
228 MacOSError::throwMe(result);
229 }
230
231 tsSetGlobalTrustSettings(ts, domain);
232 return ts;
233 }
234
235 /*
236 * Purge TrustSettings cache.
237 * Called by Keychain Event callback and by our API functions that
238 * modify trust settings.
239 * Caller can NOT hold sutCacheLock.
240 */
241 static void tsPurgeCache()
242 {
243 int domain;
244
245 StLock<Mutex> _(sutCacheLock());
246 trustSettingsDbg("tsPurgeCache");
247 for(domain=0; domain<TRUST_SETTINGS_NUM_DOMAINS; domain++) {
248 tsSetGlobalTrustSettings(NULL, (SecTrustSettingsDomain) domain);
249 }
250 }
251
252 /*
253 * Keychain event callback function, for notification by other processes that
254 * user trust list(s) has/have changed.
255 */
256 static OSStatus tsTrustSettingsCallback (
257 SecKeychainEvent keychainEvent,
258 SecKeychainCallbackInfo *info,
259 void *context)
260 {
261 trustSettingsDbg("tsTrustSettingsCallback, event %d", (int)keychainEvent);
262 if(keychainEvent != kSecTrustSettingsChangedEvent) {
263 /* should not happen, right? */
264 return errSecSuccess;
265 }
266 if(info->pid == getpid()) {
267 /*
268 * Avoid dup cache invalidates: we already dealt with this event.
269 */
270 trustSettingsDbg("cacheEventCallback: our pid, skipping");
271 }
272 else {
273 tsPurgeCache();
274 }
275 return errSecSuccess;
276 }
277
278 /*
279 * Ensure that we've registered for kSecTrustSettingsChangedEvent callbacks
280 */
281 static void tsRegisterCallback()
282 {
283 if(sutRegisteredCallback) {
284 return;
285 }
286 trustSettingsDbg("tsRegisterCallback: registering callback");
287 OSStatus ortn = SecKeychainAddCallback(tsTrustSettingsCallback,
288 kSecTrustSettingsChangedEventMask, NULL);
289 if(ortn) {
290 trustSettingsDbg("tsRegisterCallback: SecKeychainAddCallback returned %d", (int)ortn);
291 /* Not sure how this could ever happen - maybe if there is no run loop active? */
292 }
293 sutRegisteredCallback = true;
294 }
295
296 #pragma mark --- Static functions ---
297
298
299 /*
300 * Called by API code when a trust list has changed; we notify other processes
301 * and purge our own cache.
302 */
303 static void tsTrustSettingsChanged()
304 {
305 tsPurgeCache();
306 SecTrustSettingsPurgeUserAdminCertsCache();
307
308 /* The only interesting data is our pid */
309 NameValueDictionary nvd;
310 pid_t ourPid = getpid();
311 nvd.Insert (new NameValuePair (PID_KEY,
312 CssmData (reinterpret_cast<void*>(&ourPid), sizeof (pid_t))));
313 CssmData data;
314 nvd.Export (data);
315
316 trustSettingsDbg("tsTrustSettingsChanged: posting notification");
317 SecurityServer::ClientSession cs (Allocator::standard(), Allocator::standard());
318 cs.postNotification (SecurityServer::kNotificationDomainDatabase,
319 kSecTrustSettingsChangedEvent, data);
320 free (data.data ());
321 }
322
323 /*
324 * Common code for SecTrustSettingsCopyTrustSettings(),
325 * SecTrustSettingsCopyModificationDate().
326 */
327 static OSStatus tsCopyTrustSettings(
328 SecCertificateRef cert,
329 SecTrustSettingsDomain domain,
330 CFArrayRef *trustSettings, /* optionally RETURNED */
331 CFDateRef *modDate) /* optionally RETURNED */
332 {
333 BEGIN_RCSAPI
334
335 TS_REQUIRED(cert)
336
337 /* obtain fresh full copy from disk */
338 OSStatus result;
339 TrustSettings* ts;
340
341 result = TrustSettings::CreateTrustSettings(domain, CREATE_NO, TRIM_NO, ts);
342
343 // rather than throw these results, just return them because we are at the top level
344 if (result == errSecNoTrustSettings) {
345 return errSecItemNotFound;
346 }
347 else if (result != errSecSuccess) {
348 return result;
349 }
350
351 unique_ptr<TrustSettings>_(ts); // make sure this gets deleted just in case something throws underneath
352
353 if(trustSettings) {
354 *trustSettings = ts->copyTrustSettings(cert);
355 }
356 if(modDate) {
357 *modDate = ts->copyModDate(cert);
358 }
359
360 END_RCSAPI
361 }
362
363 /*
364 * Common code for SecTrustSettingsCopyTrustSettings(),
365 * SecTrustSettingsCopyModificationDate().
366 */
367 static OSStatus tsCopyTrustSettings_cached(
368 SecCertificateRef cert,
369 SecTrustSettingsDomain domain,
370 CFArrayRef CF_RETURNS_RETAINED *trustSettings)
371 {
372 BEGIN_RCSAPI
373
374 TS_REQUIRED(cert)
375
376 StLock<Mutex> _(sutCacheLock());
377 TrustSettings* ts = tsGetGlobalTrustSettings(domain);
378
379 // rather than throw these results, just return them because we are at the top level
380 if (ts == NULL) {
381 return errSecItemNotFound;
382 }
383
384 if(trustSettings) {
385 *trustSettings = ts->copyTrustSettings(cert);
386 }
387
388 END_RCSAPI
389 }
390
391 static OSStatus tsContains(
392 SecCertificateRef cert,
393 SecTrustSettingsDomain domain)
394 {
395 BEGIN_RCSAPI
396
397 TS_REQUIRED(cert)
398
399 StLock<Mutex> _(sutCacheLock());
400 TrustSettings* ts = tsGetGlobalTrustSettings(domain);
401
402 // rather than throw these results, just return them because we are at the top level
403 if (ts == NULL) {
404 return errSecItemNotFound;
405 }
406
407 if (ts->contains(cert)) {
408 return errSecSuccess;
409 } else {
410 return errSecItemNotFound;
411 }
412
413 END_RCSAPI
414 }
415
416 static void tsAddConditionalCerts(CFMutableArrayRef certArray);
417
418 /*
419 * Common code for SecTrustSettingsCopyQualifiedCerts() and
420 * SecTrustSettingsCopyUnrestrictedRoots().
421 */
422 static OSStatus tsCopyCertsCommon(
423 /* usage constraints, all optional */
424 const CSSM_OID *policyOID,
425 const char *policyString,
426 SecTrustSettingsKeyUsage keyUsage,
427 /* constrain to only roots */
428 bool onlyRoots,
429 /* per-domain enables */
430 bool user,
431 bool admin,
432 bool system,
433 CFArrayRef *certArray) /* RETURNED */
434 {
435 StLock<Mutex> _TC(sutCacheLock());
436 StLock<Mutex> _TK(SecTrustKeychainsGetMutex());
437
438 TS_REQUIRED(certArray)
439
440 /* this relies on the domain enums being numbered 0..2, user..system */
441 bool domainEnable[3] = {user, admin, system};
442
443 /* we'll retain it again before successful exit */
444 CFRef<CFMutableArrayRef> outArray(CFArrayCreateMutable(NULL, 0,
445 &kCFTypeArrayCallBacks));
446
447 /*
448 * Search all keychains - user's keychain list, System.keychain,
449 * and system root store
450 */
451 StorageManager::KeychainList keychains;
452 Keychain adminKc;
453 if(user) {
454 globals().storageManager.getSearchList(keychains);
455 }
456 if(user || admin) {
457 adminKc = globals().storageManager.make(ADMIN_CERT_STORE_PATH, false);
458 keychains.push_back(adminKc);
459 }
460 Keychain sysRootKc = globals().storageManager.make(SYSTEM_ROOT_STORE_PATH, false);
461 keychains.push_back(sysRootKc);
462
463 assert(kSecTrustSettingsDomainUser == 0);
464 for(unsigned domain=0; domain<TRUST_SETTINGS_NUM_DOMAINS; domain++) {
465 if(!domainEnable[domain]) {
466 continue;
467 }
468 TrustSettings *ts = tsGetGlobalTrustSettings((SecTrustSettingsDomain)domain);
469 if(ts == NULL) {
470 continue;
471 }
472 ts->findQualifiedCerts(keychains,
473 false, /* !findAll */
474 onlyRoots,
475 policyOID, policyString, keyUsage,
476 outArray);
477 }
478 if (system) {
479 tsAddConditionalCerts(outArray);
480 }
481 *certArray = outArray;
482 CFRetainSafe(*certArray);
483 trustSettingsDbg("tsCopyCertsCommon: %ld certs found",
484 CFArrayGetCount(outArray));
485 return errSecSuccess;
486 }
487
488 static void tsAddConditionalCerts(CFMutableArrayRef certArray)
489 {
490 #if TARGET_OS_OSX
491 struct certmap_entry_s {
492 CFStringRef bundleId;
493 const UInt8* data;
494 const CFIndex length;
495 };
496 typedef struct certmap_entry_s certmap_entry_t;
497
498 CFBundleRef bundle = CFBundleGetMainBundle();
499 CFStringRef bundleIdentifier = (bundle) ? CFBundleGetIdentifier(bundle) : NULL;
500 if (!bundleIdentifier || !certArray) { return; }
501
502 // conditionally include 1024-bit compatibility roots for specific apps
503 const certmap_entry_t certmap[] = {
504 { CFSTR("com.autodesk.AdSSO"), _GTECyberTrustGlobalRootCA, sizeof(_GTECyberTrustGlobalRootCA) }, // rdar://25916338
505 { CFSTR("com.clo3d.MD5"), _ThawtePremiumServerCA, sizeof(_ThawtePremiumServerCA) }, // rdar://26281864
506 };
507
508 unsigned int i, certmaplen = sizeof(certmap) / sizeof(certmap_entry_t);
509 for (i=0; i<certmaplen; i++) {
510 if (CFStringCompare(bundleIdentifier, certmap[i].bundleId, 0) == kCFCompareEqualTo) {
511 SecCertificateRef cert = SecCertificateCreateWithBytes(NULL, certmap[i].data, certmap[i].length);
512 if (!cert) { continue; }
513 CFArrayAppendValue(certArray, cert);
514 CFRelease(cert);
515 cert = NULL;
516 }
517 }
518 #else
519 // this function is a no-op on iOS platforms
520 #endif
521 }
522
523
524 #pragma mark --- SPI functions ---
525
526
527 /*
528 * Fundamental routine used by TP to ascertain status of one cert.
529 *
530 * Returns true in *foundMatchingEntry if a trust setting matching
531 * specific constraints was found for the cert. Returns true in
532 * *foundAnyEntry if any entry was found for the cert, even if it
533 * did not match the specified constraints. The TP uses this to
534 * optimize for the case where a cert is being evaluated for
535 * one type of usage, and then later for another type. If
536 * foundAnyEntry is false, the second evaluation need not occur.
537 *
538 * Returns the domain in which a setting was found in *foundDomain.
539 *
540 * Allowed errors applying to the specified cert evaluation
541 * are returned in a mallocd array in *allowedErrors and must
542 * be freed by caller.
543 *
544 * The design of the entire TrustSettings module is centered around
545 * optimizing the performance of this routine (security concerns
546 * aside, that is). It's why the per-cert dictionaries are stored
547 * as a dictionary, keyed off of the cert hash. It's why TrustSettings
548 * are cached in memory by tsGetGlobalTrustSettings(), and why those
549 * cached TrustSettings objects are 'trimmed' of dictionary fields
550 * which are not needed to verify a cert.
551 *
552 * The API functions which are used to manipulate Trust Settings
553 * are called infrequently and need not be particularly fast since
554 * they result in user interaction for authentication. Thus they do
555 * not use cached TrustSettings as this function does.
556 */
557 OSStatus SecTrustSettingsEvaluateCert(
558 CFStringRef certHashStr,
559 /* parameters describing the current cert evalaution */
560 const CSSM_OID *policyOID,
561 const char *policyString, /* optional */
562 uint32 policyStringLen,
563 SecTrustSettingsKeyUsage keyUsage, /* optional */
564 bool isRootCert, /* for checking default setting */
565 /* RETURNED values */
566 SecTrustSettingsDomain *foundDomain,
567 CSSM_RETURN **allowedErrors, /* mallocd */
568 uint32 *numAllowedErrors,
569 SecTrustSettingsResult *resultType,
570 bool *foundMatchingEntry,
571 bool *foundAnyEntry)
572 {
573 BEGIN_RCSAPI
574
575 StLock<Mutex> _(sutCacheLock());
576
577 TS_REQUIRED(certHashStr)
578 TS_REQUIRED(foundDomain)
579 TS_REQUIRED(allowedErrors)
580 TS_REQUIRED(numAllowedErrors)
581 TS_REQUIRED(resultType)
582 TS_REQUIRED(foundMatchingEntry)
583 TS_REQUIRED(foundAnyEntry)
584
585 /* ensure a NULL_terminated string */
586 auto_array<char> polStr;
587 if(policyString != NULL && policyStringLen > 0) {
588 polStr.allocate(policyStringLen + 1);
589 memmove(polStr.get(), policyString, policyStringLen);
590 if(policyString[policyStringLen - 1] != '\0') {
591 (polStr.get())[policyStringLen] = '\0';
592 }
593 }
594
595 /* initial condition - this can grow if we inspect multiple TrustSettings */
596 *allowedErrors = NULL;
597 *numAllowedErrors = 0;
598
599 /*
600 * This loop relies on the ordering of the SecTrustSettingsDomain enum:
601 * search user first, then admin, then system.
602 */
603 assert(kSecTrustSettingsDomainAdmin == (kSecTrustSettingsDomainUser + 1));
604 assert(kSecTrustSettingsDomainSystem == (kSecTrustSettingsDomainAdmin + 1));
605 bool foundAny = false;
606 for(unsigned domain=kSecTrustSettingsDomainUser;
607 domain<=kSecTrustSettingsDomainSystem;
608 domain++) {
609 TrustSettings *ts = tsGetGlobalTrustSettings((SecTrustSettingsDomain)domain);
610 if(ts == NULL) {
611 continue;
612 }
613
614 /* validate cert returns true if matching entry was found */
615 bool foundAnyHere = false;
616 bool found = ts->evaluateCert(certHashStr, policyOID,
617 polStr.get(), keyUsage, isRootCert,
618 allowedErrors, numAllowedErrors, resultType, &foundAnyHere);
619
620 if(found) {
621 /*
622 * Note this, even though we may overwrite it later if this
623 * is an Unspecified entry and we find a definitive entry
624 * later
625 */
626 *foundDomain = (SecTrustSettingsDomain)domain;
627 }
628 if(found && (*resultType != kSecTrustSettingsResultUnspecified)) {
629 trustSettingsDbg("SecTrustSettingsEvaluateCert: found in domain %d", domain);
630 *foundAnyEntry = true;
631 *foundMatchingEntry = true;
632 return errSecSuccess;
633 }
634 foundAny |= foundAnyHere;
635 }
636 trustSettingsDbg("SecTrustSettingsEvaluateCert: NOT FOUND");
637 *foundAnyEntry = foundAny;
638 *foundMatchingEntry = false;
639 return errSecSuccess;
640 END_RCSAPI
641 }
642
643 /*
644 * Obtain trusted certs which match specified usage.
645 * Only certs with a SecTrustSettingsResult of
646 * kSecTrustSettingsResultTrustRoot or
647 * or kSecTrustSettingsResultTrustAsRoot will be returned.
648 * To be used by SecureTransport for its SSLSetTrustedRoots() call;
649 * I hope nothing else has to use this...
650 * Caller must CFRelease the returned CFArrayRef.
651 */
652 OSStatus SecTrustSettingsCopyQualifiedCerts(
653 const CSSM_OID *policyOID,
654 const char *policyString, /* optional */
655 uint32 policyStringLen,
656 SecTrustSettingsKeyUsage keyUsage, /* optional */
657 CFArrayRef *certArray) /* RETURNED */
658 {
659 BEGIN_RCSAPI
660
661 /* ensure a NULL_terminated string */
662 auto_array<char> polStr;
663 if(policyString != NULL) {
664 polStr.allocate(policyStringLen + 1);
665 memmove(polStr.get(), policyString, policyStringLen);
666 if(policyString[policyStringLen - 1] != '\0') {
667 (polStr.get())[policyStringLen] = '\0';
668 }
669 }
670
671 return tsCopyCertsCommon(policyOID, polStr.get(), keyUsage,
672 false, /* !onlyRoots */
673 true, true, true, /* all domains */
674 certArray);
675
676 END_RCSAPI
677 }
678
679 /*
680 * Obtain unrestricted root certs from the specified domain(s).
681 * Only returns roots with no usage constraints.
682 * Caller must CFRelease the returned CFArrayRef.
683 */
684 OSStatus SecTrustSettingsCopyUnrestrictedRoots(
685 Boolean user,
686 Boolean admin,
687 Boolean system,
688 CFArrayRef *certArray) /* RETURNED */
689 {
690 BEGIN_RCSAPI
691
692 OSStatus status = tsCopyCertsCommon(NULL, NULL, NULL, /* no constraints */
693 true, /* onlyRoots */
694 user, admin, system,
695 certArray);
696
697 return status;
698
699 END_RCSAPI
700 }
701
702 static const char hexChars[16] = {
703 '0', '1', '2', '3', '4', '5', '6', '7',
704 '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
705 };
706
707 /*
708 * Obtain a string representing a cert's SHA1 digest. This string is
709 * the key used to look up per-cert trust settings in a TrustSettings record.
710 */
711 CFStringRef SecTrustSettingsCertHashStrFromCert(
712 SecCertificateRef certRef)
713 {
714 if(certRef == NULL) {
715 return NULL;
716 }
717
718 if(certRef == kSecTrustSettingsDefaultRootCertSetting) {
719 /* use this string instead of the cert hash as the dictionary key */
720 trustSettingsDbg("SecTrustSettingsCertHashStrFromCert: DefaultSetting");
721 secerror("Caller passed kSecTrustSettingsDefaultRootCertSetting. This constant is deprecated and no longer affects the behavior of the system.");
722 return kSecTrustRecordDefaultRootCert;
723 }
724
725 CSSM_DATA certData;
726 OSStatus ortn = SecCertificateGetData(certRef, &certData);
727 if(ortn) {
728 return NULL;
729 }
730 return SecTrustSettingsCertHashStrFromData(certData.Data, certData.Length);
731 }
732
733 CFStringRef SecTrustSettingsCertHashStrFromData(
734 const void *cert,
735 size_t certLen)
736 {
737 unsigned char digest[CC_SHA1_DIGEST_LENGTH];
738 char asciiDigest[(2 * CC_SHA1_DIGEST_LENGTH) + 1];
739 unsigned dex;
740 char *outp = asciiDigest;
741 unsigned char *inp = digest;
742
743 if(cert == NULL) {
744 return NULL;
745 }
746
747 CC_SHA1(cert, (CC_LONG)certLen, digest);
748
749 for(dex=0; dex<CC_SHA1_DIGEST_LENGTH; dex++) {
750 unsigned c = *inp++;
751 outp[1] = hexChars[c & 0xf];
752 c >>= 4;
753 outp[0] = hexChars[c];
754 outp += 2;
755 }
756 *outp = 0;
757 return CFStringCreateWithCString(NULL, asciiDigest, kCFStringEncodingASCII);
758 }
759
760 /*
761 * Add a cert's TrustSettings to a non-persistent TrustSettings record.
762 * No locking or cache flushing here; it's all local to the TrustSettings
763 * we construct here.
764 */
765 OSStatus SecTrustSettingsSetTrustSettingsExternal(
766 CFDataRef settingsIn, /* optional */
767 SecCertificateRef certRef, /* optional */
768 CFTypeRef trustSettingsDictOrArray, /* optional */
769 CFDataRef *settingsOut) /* RETURNED */
770 {
771 BEGIN_RCSAPI
772
773 TS_REQUIRED(settingsOut)
774
775 OSStatus result;
776 TrustSettings* ts;
777
778 result = TrustSettings::CreateTrustSettings((SecTrustSettingsDomain)kSecTrustSettingsDomainMemory, settingsIn, ts);
779 if (result != errSecSuccess) {
780 return result;
781 }
782
783 unique_ptr<TrustSettings>_(ts);
784
785 if(certRef != NULL) {
786 ts->setTrustSettings(certRef, trustSettingsDictOrArray);
787 }
788 *settingsOut = ts->createExternal();
789 return errSecSuccess;
790
791 END_RCSAPI
792 }
793
794 void SecTrustSettingsPurgeCache(void) {
795 tsPurgeCache();
796 }
797
798 OSStatus SecTrustSettingsCopyTrustSettings_Cached(
799 SecCertificateRef certRef,
800 SecTrustSettingsDomain domain,
801 CFArrayRef CF_RETURNS_RETAINED *trustSettings) /* RETURNED */
802 {
803 TS_REQUIRED(certRef)
804 TS_REQUIRED(trustSettings)
805
806 OSStatus result = tsCopyTrustSettings_cached(certRef, domain, trustSettings);
807 if (result == errSecSuccess && *trustSettings == NULL) {
808 result = errSecItemNotFound; /* documented result if no trust settings exist */
809 }
810 return result;
811 }
812
813 #pragma mark --- API functions ---
814
815 OSStatus SecTrustSettingsCopyTrustSettings(
816 SecCertificateRef certRef,
817 SecTrustSettingsDomain domain,
818 CFArrayRef *trustSettings) /* RETURNED */
819 {
820 TS_REQUIRED(certRef)
821 TS_REQUIRED(trustSettings)
822
823 OSStatus result = tsCopyTrustSettings(certRef, domain, trustSettings, NULL);
824 if (result == errSecSuccess && *trustSettings == NULL) {
825 result = errSecItemNotFound; /* documented result if no trust settings exist */
826 }
827 return result;
828 }
829
830 OSStatus SecTrustSettingsCopyModificationDate(
831 SecCertificateRef certRef,
832 SecTrustSettingsDomain domain,
833 CFDateRef *modificationDate) /* RETURNED */
834 {
835 TS_REQUIRED(certRef)
836 TS_REQUIRED(modificationDate)
837
838 OSStatus result = tsCopyTrustSettings(certRef, domain, NULL, modificationDate);
839 if (result == errSecSuccess && *modificationDate == NULL) {
840 result = errSecItemNotFound; /* documented result if no trust settings exist */
841 }
842 return result;
843 }
844
845 /* works with existing and with new cert */
846 OSStatus SecTrustSettingsSetTrustSettings(
847 SecCertificateRef certRef,
848 SecTrustSettingsDomain domain,
849 CFTypeRef trustSettingsDictOrArray)
850 {
851 BEGIN_RCSAPI
852
853 TS_REQUIRED(certRef)
854
855 if(domain == kSecTrustSettingsDomainSystem) {
856 return errSecDataNotModifiable;
857 }
858
859 OSStatus result;
860 TrustSettings* ts;
861
862 result = TrustSettings::CreateTrustSettings(domain, CREATE_YES, TRIM_NO, ts);
863 if (result != errSecSuccess) {
864 return result;
865 }
866
867 unique_ptr<TrustSettings>_(ts);
868
869 ts->setTrustSettings(certRef, trustSettingsDictOrArray);
870 ts->flushToDisk();
871 tsTrustSettingsChanged();
872 return errSecSuccess;
873
874 END_RCSAPI
875 }
876
877 OSStatus SecTrustSettingsRemoveTrustSettings(
878 SecCertificateRef cert,
879 SecTrustSettingsDomain domain)
880 {
881 BEGIN_RCSAPI
882
883 TS_REQUIRED(cert)
884
885 if(domain == kSecTrustSettingsDomainSystem) {
886 return errSecDataNotModifiable;
887 }
888
889 OSStatus result;
890 TrustSettings* ts;
891
892 result = TrustSettings::CreateTrustSettings(domain, CREATE_NO, TRIM_NO, ts);
893 if (result != errSecSuccess) {
894 return result;
895 }
896
897 unique_ptr<TrustSettings>_(ts);
898
899 /* deleteTrustSettings throws if record not found */
900 trustSettingsDbg("SecTrustSettingsRemoveTrustSettings: deleting from domain %d",
901 (int)domain);
902 ts->deleteTrustSettings(cert);
903 ts->flushToDisk();
904 tsTrustSettingsChanged();
905 return errSecSuccess;
906
907 END_RCSAPI
908 }
909
910 /* get all certs listed in specified domain */
911 OSStatus SecTrustSettingsCopyCertificates(
912 SecTrustSettingsDomain domain,
913 CFArrayRef *certArray)
914 {
915 BEGIN_RCSAPI
916
917 TS_REQUIRED(certArray)
918
919 OSStatus status;
920 TrustSettings* ts;
921 CFMutableArrayRef trustedCertArray = NULL;
922 SecTrustRef trust = NULL;
923
924 status = TrustSettings::CreateTrustSettings(domain, CREATE_NO, TRIM_NO, ts);
925 if (status != errSecSuccess) {
926 return status;
927 }
928
929 unique_ptr<TrustSettings>_(ts);
930
931 CFMutableArrayRef outArray = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
932
933 /*
934 * Keychains to search: user's search list, System.keychain, system root store
935 */
936 StorageManager::KeychainList keychains;
937 Keychain adminKc;
938 Keychain sysRootKc;
939 switch(domain) {
940 case kSecTrustSettingsDomainUser:
941 /* user search list */
942 globals().storageManager.getSearchList(keychains);
943 /* drop thru to next case */
944 case kSecTrustSettingsDomainAdmin:
945 /* admin certs in system keychain */
946 adminKc = globals().storageManager.make(ADMIN_CERT_STORE_PATH, false);
947 keychains.push_back(adminKc);
948 /* drop thru to next case */
949 case kSecTrustSettingsDomainSystem:
950 /* and, for all cases, immutable system root store */
951 sysRootKc = globals().storageManager.make(SYSTEM_ROOT_STORE_PATH, false);
952 keychains.push_back(sysRootKc);
953 default:
954 /* already validated when we created the TrustSettings */
955 break;
956 }
957 ts->findCerts(keychains, outArray);
958 CFIndex count = outArray ? CFArrayGetCount(outArray) : 0;
959 if(count == 0) {
960 CFReleaseSafe(outArray);
961 return errSecNoTrustSettings;
962 }
963 /* Go through outArray and do a SecTrustEvaluate only for DomainSystem */
964 if (kSecTrustSettingsDomainSystem == domain) {
965 CFIndex i;
966 SecPolicyRef policy = SecPolicyCreateBasicX509();
967 trustedCertArray = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
968 for (i = 0; i < count ; i++) {
969 SecTrustResultType result;
970 SecCertificateRef certificate = (SecCertificateRef) CFArrayGetValueAtIndex(outArray, i);
971 status = SecTrustCreateWithCertificates(certificate, policy, &trust);
972 if (status != errSecSuccess) {
973 CFReleaseSafe(policy);
974 goto out;
975 }
976 status = SecTrustEvaluate(trust, &result);
977 if (status != errSecSuccess) {
978 CFReleaseSafe(policy);
979 goto out;
980 }
981 if (result != kSecTrustResultFatalTrustFailure) {
982 CFArrayAppendValue(trustedCertArray, certificate);
983 }
984 CFReleaseNull(trust);
985 }
986 tsAddConditionalCerts(trustedCertArray);
987 if (CFArrayGetCount(trustedCertArray) == 0) {
988 status = errSecNoTrustSettings;
989 } else {
990 *certArray = trustedCertArray;
991 CFReleaseSafe(outArray);
992 }
993 CFReleaseSafe(policy);
994 } else {
995 *certArray = outArray;
996 }
997 out:
998 if (status != errSecSuccess) {
999 CFReleaseSafe(outArray);
1000 CFReleaseSafe(trustedCertArray);
1001 }
1002 CFReleaseNull(trust);
1003 return status;
1004 END_RCSAPI
1005 }
1006
1007 static CFArrayRef gUserAdminCerts = NULL;
1008 static bool gUserAdminCertsCacheBuilt = false;
1009 static ModuleNexus<ReadWriteLock> gUserAdminCertsLock;
1010
1011 void SecTrustSettingsPurgeUserAdminCertsCache(void) {
1012 StReadWriteLock _(gUserAdminCertsLock(), StReadWriteLock::Write);
1013 CFReleaseNull(gUserAdminCerts);
1014 gUserAdminCertsCacheBuilt = false;
1015 }
1016
1017 OSStatus SecTrustSettingsCopyCertificatesForUserAdminDomains(
1018 CFArrayRef *certArray)
1019 {
1020 TS_REQUIRED(certArray);
1021 OSStatus result = errSecSuccess;
1022
1023 { /* Hold the read lock for the check */
1024 StReadWriteLock _(gUserAdminCertsLock(), StReadWriteLock::Read);
1025 if (gUserAdminCertsCacheBuilt) {
1026 if (gUserAdminCerts) {
1027 *certArray = (CFArrayRef)CFRetain(gUserAdminCerts);
1028 return errSecSuccess;
1029 } else {
1030 return errSecNoTrustSettings;
1031 }
1032 }
1033 }
1034
1035 /* There were no cached results. We'll have to recreate them. */
1036 CFMutableArrayRef outArray = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
1037 if (!outArray) {
1038 return errSecAllocate;
1039 }
1040
1041 CFArrayRef userTrusted = NULL, adminTrusted = NULL;
1042 OSStatus userStatus = SecTrustSettingsCopyCertificates(kSecTrustSettingsDomainUser, &userTrusted);
1043 if ((userStatus == errSecSuccess) && (userTrusted != NULL)) {
1044 CFArrayAppendArray(outArray, userTrusted, CFRangeMake(0, CFArrayGetCount(userTrusted)));
1045 CFRelease(userTrusted);
1046 }
1047
1048 OSStatus adminStatus = SecTrustSettingsCopyCertificates(kSecTrustSettingsDomainAdmin, &adminTrusted);
1049 if ((adminStatus == errSecSuccess) && (adminTrusted != NULL)) {
1050 CFArrayAppendArray(outArray, adminTrusted, CFRangeMake(0, CFArrayGetCount(adminTrusted)));
1051 CFRelease(adminTrusted);
1052 }
1053
1054 /* Lack of trust settings for a domain results in an error above. Only fail
1055 * if we weren't able to get trust settings for both domains. */
1056 if (userStatus != errSecSuccess && adminStatus != errSecSuccess) {
1057 result = userStatus;
1058 }
1059
1060 if (result != errSecSuccess && outArray) {
1061 CFRelease(outArray);
1062 outArray = NULL;
1063 }
1064
1065 *certArray = outArray;
1066
1067 /* For valid results, update the global cache */
1068 if (result == errSecSuccess || result == errSecNoTrustSettings) {
1069 StReadWriteLock _(gUserAdminCertsLock(), StReadWriteLock::Write);
1070 CFReleaseNull(gUserAdminCerts);
1071 gUserAdminCerts = (CFArrayRef)CFRetainSafe(outArray);
1072 gUserAdminCertsCacheBuilt = true;
1073 }
1074
1075 return result;
1076 }
1077
1078 bool SecTrustSettingsUserAdminDomainsContain(SecCertificateRef certRef)
1079 {
1080 TS_REQUIRED(certRef)
1081 if (tsContains(certRef, kSecTrustSettingsDomainAdmin) == errSecSuccess ||
1082 tsContains(certRef, kSecTrustSettingsDomainUser) == errSecSuccess) {
1083 return true;
1084 }
1085 return false;
1086 }
1087
1088 /*
1089 * Obtain an external, portable representation of the specified
1090 * domain's TrustSettings. Caller must CFRelease the returned data.
1091 */
1092 OSStatus SecTrustSettingsCreateExternalRepresentation(
1093 SecTrustSettingsDomain domain,
1094 CFDataRef *trustSettings)
1095 {
1096 BEGIN_RCSAPI
1097
1098 TS_REQUIRED(trustSettings)
1099
1100 OSStatus result;
1101 TrustSettings* ts;
1102
1103 result = TrustSettings::CreateTrustSettings(domain, CREATE_NO, TRIM_NO, ts);
1104 if (result != errSecSuccess) {
1105 return result;
1106 }
1107
1108 unique_ptr<TrustSettings>_(ts);
1109
1110 *trustSettings = ts->createExternal();
1111 return errSecSuccess;
1112
1113 END_RCSAPI
1114 }
1115
1116 /*
1117 * Import trust settings, obtained via SecTrustSettingsCreateExternalRepresentation,
1118 * into the specified domain.
1119 */
1120 OSStatus SecTrustSettingsImportExternalRepresentation(
1121 SecTrustSettingsDomain domain,
1122 CFDataRef trustSettings) /* optional - NULL means empty settings */
1123 {
1124 BEGIN_RCSAPI
1125
1126 if(domain == kSecTrustSettingsDomainSystem) {
1127 return errSecDataNotModifiable;
1128 }
1129
1130 OSStatus result;
1131 TrustSettings* ts;
1132
1133 result = TrustSettings::CreateTrustSettings(domain, trustSettings, ts);
1134 if (result != errSecSuccess) {
1135 return result;
1136 }
1137
1138 unique_ptr<TrustSettings>_(ts);
1139
1140 ts->flushToDisk();
1141 tsTrustSettingsChanged();
1142 return errSecSuccess;
1143
1144 END_RCSAPI
1145 }
1146
1147 /*
1148 * SecTrustSettingsSetTrustSettings convenience wrapper function.
1149 */
1150 void SecTrustSettingsSetTrustedCertificateForSSLHost(
1151 SecCertificateRef certificate,
1152 CFStringRef hostname,
1153 void (^result)(SecTrustSettingsResult trustResult, CFErrorRef error))
1154 {
1155 __block CFMutableArrayRef trustSettings = NULL;
1156 __block CFNumberRef trustSettingsResult = NULL;
1157 __block SecTrustSettingsDomain domain = kSecTrustSettingsDomainUser;
1158
1159 CFDictionaryRef policyProperties = NULL;
1160 CFStringRef policyOid = NULL;
1161 SecPolicyRef policy = NULL;
1162
1163 Boolean isSelfSigned = false;
1164 Boolean hasPolicyConstraint = false;
1165 Boolean hasPolicyValue = false;
1166 Boolean policyConstraintChanged = false;
1167 CFIndex indexOfEntryWithAllowedErrorForExpiredCert = kCFNotFound;
1168 CFIndex indexOfEntryWithAllowedErrorForHostnameMismatch = kCFNotFound;
1169 CFIndex i, count;
1170 int32_t trustSettingsResultCode = kSecTrustSettingsResultTrustAsRoot;
1171 OSStatus status = errSecSuccess;
1172
1173 CFRetainSafe(certificate);
1174 CFRetainSafe(hostname);
1175 if (!certificate || !hostname) {
1176 status = errSecParam;
1177 } else {
1178 status = SecCertificateIsSelfSigned(certificate, &isSelfSigned);
1179 }
1180 if (status != errSecSuccess) {
1181 goto reportErr;
1182 }
1183 if (isSelfSigned) {
1184 trustSettingsResultCode = kSecTrustSettingsResultTrustRoot;
1185 }
1186 trustSettingsResult = CFNumberCreate(NULL, kCFNumberSInt32Type, &trustSettingsResultCode);
1187
1188 /* start with the existing trust settings for this certificate, if any */
1189 {
1190 CFArrayRef curTrustSettings = NULL;
1191 (void)SecTrustSettingsCopyTrustSettings(certificate, domain, &curTrustSettings);
1192 if (curTrustSettings) {
1193 trustSettings = CFArrayCreateMutableCopy(NULL, 0, curTrustSettings);
1194 CFReleaseNull(curTrustSettings);
1195 } else {
1196 trustSettings = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
1197 }
1198 }
1199 if (!trustSettings || !trustSettingsResult) {
1200 status = errSecAllocate;
1201 goto reportErr;
1202 }
1203
1204 /* set up policy and value instances to trust the certificate for SSL for a given hostname */
1205 policy = SecPolicyCreateSSL(true, hostname);
1206 if (!policy) {
1207 status = errSecInternal;
1208 goto reportErr;
1209 }
1210 policyProperties = SecPolicyCopyProperties(policy);
1211 if (!policyProperties) {
1212 status = errSecInternal;
1213 goto reportErr;
1214 }
1215 policyOid = (CFStringRef)CFDictionaryGetValue(policyProperties, kSecPolicyOid);
1216 CFRetainSafe(policyOid);
1217 if (!policyOid) {
1218 status = errSecInternal;
1219 goto reportErr;
1220 }
1221
1222 /* look for dictionaries in the trust settings array for this policy and value */
1223 count = CFArrayGetCount(trustSettings);
1224 for (i=0; i < count; i++) {
1225 CFDictionaryRef constraints = (CFDictionaryRef)CFArrayGetValueAtIndex(trustSettings, i);
1226 if (!constraints) { continue; }
1227 SecPolicyRef aPolicy = (SecPolicyRef)CFDictionaryGetValue(constraints, kSecTrustSettingsPolicy);
1228 if (!aPolicy) { continue; }
1229 CFDictionaryRef properties = SecPolicyCopyProperties(aPolicy);
1230 if (!properties) { continue; }
1231 CFStringRef aPolicyOid = (CFStringRef)CFDictionaryGetValue(properties, kSecPolicyOid);
1232 if (aPolicyOid && kCFCompareEqualTo == CFStringCompare(aPolicyOid, policyOid, 0)) {
1233 CFStringRef aPolicyString = (CFStringRef)CFDictionaryGetValue(constraints, kSecTrustSettingsPolicyString);
1234 if (aPolicyString && kCFCompareEqualTo == CFStringCompare(aPolicyString, hostname, kCFCompareCaseInsensitive)) {
1235 /* found existing entry */
1236 CFNumberRef allowedErr = (CFNumberRef)CFDictionaryGetValue(constraints, kSecTrustSettingsAllowedError);
1237 int32_t eOld = 0;
1238 if (!allowedErr || !CFNumberGetValue(allowedErr, kCFNumberSInt32Type, &eOld)) {
1239 eOld = CSSM_OK;
1240 }
1241 CFNumberRef tsResult = (CFNumberRef)CFDictionaryGetValue(constraints, kSecTrustSettingsResult);
1242 int32_t rOld = 0;
1243 if (!tsResult || !CFNumberGetValue(allowedErr, kCFNumberSInt32Type, &rOld)) {
1244 rOld = kSecTrustSettingsResultTrustRoot;
1245 }
1246 if (!hasPolicyValue) { hasPolicyValue = (aPolicyString != NULL); }
1247 if (!hasPolicyConstraint) { hasPolicyConstraint = true; }
1248 if (eOld == CSSMERR_TP_CERT_EXPIRED) {
1249 indexOfEntryWithAllowedErrorForExpiredCert = i;
1250 } else if (eOld == CSSMERR_APPLETP_HOSTNAME_MISMATCH) {
1251 indexOfEntryWithAllowedErrorForHostnameMismatch = i;
1252 }
1253 if (trustSettingsResultCode != rOld) {
1254 policyConstraintChanged = true; // we are changing existing policy constraint's result
1255 }
1256 }
1257 }
1258 CFReleaseSafe(properties);
1259 }
1260
1261 if (!hasPolicyConstraint) {
1262 policyConstraintChanged = true; // we are adding a new policy constraint
1263 } else if (hostname && !hasPolicyValue) {
1264 policyConstraintChanged = true; // we need to add the hostname to an existing policy constraint
1265 } else if ((indexOfEntryWithAllowedErrorForExpiredCert == kCFNotFound) ||
1266 (indexOfEntryWithAllowedErrorForHostnameMismatch == kCFNotFound)) {
1267 policyConstraintChanged = true; // we are missing one of the expected allowed-error entries for this policy
1268 }
1269
1270 if (policyConstraintChanged) {
1271 CFMutableDictionaryRef policyDict[2] = { NULL, NULL };
1272 policyDict[0] = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
1273 policyDict[1] = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
1274 int32_t certExpiredCode = (int32_t)CSSMERR_TP_CERT_EXPIRED;
1275 CFNumberRef certExpired = CFNumberCreate(NULL, kCFNumberSInt32Type, &certExpiredCode);
1276 int32_t hostnameMismatchCode = (int32_t)CSSMERR_APPLETP_HOSTNAME_MISMATCH;
1277 CFNumberRef hostnameMismatch = CFNumberCreate(NULL, kCFNumberSInt32Type, &hostnameMismatchCode);
1278 if (!policyDict[0] || !policyDict[1] || !certExpired || !hostnameMismatch) {
1279 status = errSecInternal;
1280 } else {
1281 /* set up entry for policy, hostname, expired cert error, and result */
1282 CFDictionarySetValue(policyDict[0], kSecTrustSettingsPolicy, policy);
1283 CFDictionarySetValue(policyDict[0], kSecTrustSettingsPolicyString, hostname);
1284 CFDictionarySetValue(policyDict[0], kSecTrustSettingsAllowedError, certExpired);
1285 CFDictionarySetValue(policyDict[0], kSecTrustSettingsResult, trustSettingsResult);
1286 if (indexOfEntryWithAllowedErrorForExpiredCert != kCFNotFound) {
1287 /* if we found an existing constraint for this policy, hostname, and allowed error, replace it */
1288 CFArraySetValueAtIndex(trustSettings, indexOfEntryWithAllowedErrorForExpiredCert, policyDict[0]);
1289 } else if (!(hasPolicyValue)) {
1290 /* add a new policy constraint */
1291 CFArrayAppendValue(trustSettings, policyDict[0]);
1292 }
1293 /* set up additional entry for policy, hostname, hostname mismatch error, and result */
1294 CFDictionarySetValue(policyDict[1], kSecTrustSettingsPolicy, policy);
1295 CFDictionarySetValue(policyDict[1], kSecTrustSettingsPolicyString, hostname);
1296 CFDictionarySetValue(policyDict[1], kSecTrustSettingsAllowedError, hostnameMismatch);
1297 CFDictionarySetValue(policyDict[1], kSecTrustSettingsResult, trustSettingsResult);
1298 if (indexOfEntryWithAllowedErrorForHostnameMismatch != kCFNotFound) {
1299 /* if we found an existing constraint for this policy, hostname, and allowed error, replace it */
1300 CFArraySetValueAtIndex(trustSettings, indexOfEntryWithAllowedErrorForHostnameMismatch, policyDict[1]);
1301 } else if (!(hasPolicyValue)) {
1302 /* add a new policy constraint */
1303 CFArrayAppendValue(trustSettings, policyDict[1]);
1304 }
1305 }
1306 CFReleaseSafe(policyDict[0]);
1307 CFReleaseSafe(policyDict[1]);
1308 CFReleaseSafe(certExpired);
1309 CFReleaseSafe(hostnameMismatch);
1310 }
1311
1312 if (status != errSecSuccess) {
1313 goto reportErr;
1314 }
1315 CFReleaseSafe(policyOid);
1316 CFReleaseSafe(policyProperties);
1317 CFReleaseSafe(policy);
1318
1319 dispatch_async(dispatch_get_main_queue(), ^{
1320 /* add certificate to keychain first */
1321 OSStatus status = SecCertificateAddToKeychain(certificate, NULL);
1322 if (status == errSecSuccess || status == errSecDuplicateItem) {
1323 /* this will block on authorization UI... */
1324 status = SecTrustSettingsSetTrustSettings(certificate,
1325 domain, trustSettings);
1326 }
1327 if (result) {
1328 CFErrorRef error = NULL;
1329 if (status) {
1330 error = CFErrorCreate(NULL, kCFErrorDomainOSStatus, status, NULL);
1331 }
1332 int32_t tsrc;
1333 if (!CFNumberGetValue(trustSettingsResult, kCFNumberSInt32Type, (int32_t*)&tsrc)) {
1334 tsrc = (int32_t)kSecTrustSettingsResultUnspecified;
1335 }
1336 result((SecTrustSettingsResult)tsrc, error);
1337 CFReleaseSafe(error);
1338 }
1339 CFRelease(trustSettingsResult);
1340 CFRelease(trustSettings);
1341 CFRelease(certificate);
1342 CFRelease(hostname);
1343 });
1344
1345 return;
1346
1347 reportErr:
1348 CFReleaseSafe(policyOid);
1349 CFReleaseSafe(policyProperties);
1350 CFReleaseSafe(policy);
1351 CFReleaseSafe(trustSettingsResult);
1352 CFReleaseSafe(trustSettings);
1353 CFReleaseSafe(certificate);
1354 CFReleaseSafe(hostname);
1355 if (result) {
1356 CFErrorRef error = CFErrorCreate(NULL, kCFErrorDomainOSStatus, status, NULL);
1357 result(kSecTrustSettingsResultInvalid, error);
1358 CFReleaseSafe(error);
1359 }
1360 }