2 * Copyright (c) 2005,2011-2016 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
25 * SecTrustSettings.cpp - Public interface for manipulation of Trust Settings.
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"
39 #include "SecKeychainPriv.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>
55 #include <CommonCrypto/CommonDigest.h>
56 #include <CoreFoundation/CFPreferences.h>
58 #define trustSettingsDbg(args...) secinfo("trustSettings", ## args)
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).
68 #define BEGIN_RCSAPI \
69 OSStatus __secapiresult; \
72 __secapiresult=errSecSuccess; \
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;
85 #pragma mark --- TrustSettings preferences ---
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.
93 static bool tsUserTrustDisableValid
= false; /* true once we consult prefs */
94 static bool tsUserTrustDisable
= false; /* the cached value */
97 * Determine whether user-level Trust Settings disabled.
99 static bool tsUserTrustSettingsDisabled()
101 if(tsUserTrustDisableValid
) {
102 return tsUserTrustDisable
;
104 tsUserTrustDisable
= false;
106 Dictionary
* dictionary
= Dictionary::CreateDictionary(kSecTrustSettingsPrefsDomain
, Dictionary::US_System
);
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
);
114 tsUserTrustDisableValid
= true;
115 return tsUserTrustDisable
;
118 #pragma mark --- TrustSettings global cache ---
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.
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).
133 static ModuleNexus
<RecursiveMutex
> sutCacheLock
;
135 #define TRUST_SETTINGS_NUM_DOMAINS 3
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.
142 static TrustSettings
*globalTrustSettings
[TRUST_SETTINGS_NUM_DOMAINS
] =
146 * Indicates "the associated global here is currently valid; if there isn't a
147 * globalTrustSettings[domain], don't try to find one"
149 static bool globalTrustSettingsValid
[TRUST_SETTINGS_NUM_DOMAINS
] =
150 {false, false, false};
152 /* remember the fact that we've registered our KC callback */
153 static bool sutRegisteredCallback
= false;
155 static void tsRegisterCallback();
158 * Assign global TrustSetting to new incoming value, which may be NULL.
159 * Caller holds sutCacheLock.
161 static void tsSetGlobalTrustSettings(
163 SecTrustSettingsDomain domain
)
165 assert(((int)domain
>= 0) && ((int)domain
< TRUST_SETTINGS_NUM_DOMAINS
));
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();
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.
181 static TrustSettings
*tsGetGlobalTrustSettings(
182 SecTrustSettingsDomain domain
)
184 assert(((int)domain
>= 0) && ((int)domain
< TRUST_SETTINGS_NUM_DOMAINS
));
186 if((domain
== kSecTrustSettingsDomainUser
) && tsUserTrustSettingsDisabled()) {
187 trustSettingsDbg("tsGetGlobalTrustSettings: skipping DISABLED user domain");
191 if(globalTrustSettingsValid
[domain
]) {
192 // ready or not, use this
193 return globalTrustSettings
[domain
];
195 assert(globalTrustSettings
[domain
] == NULL
);
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
)) {
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.
209 trustSettingsDbg("tsGetGlobalTrustSettings: could not connect to ocspd for domain (%d)",(int)domain
);
210 globalTrustSettingsValid
[domain
] = false;
211 tsRegisterCallback();
214 else if (result
== errSecNoTrustSettings
) {
216 * No TrustSettings for this domain, actually a fairly common case.
217 * Optimize: don't bother trying this again.
219 trustSettingsDbg("tsGetGlobalTrustSettings: flagging known NULL");
220 globalTrustSettingsValid
[domain
] = true;
221 tsRegisterCallback();
224 else if(result
!= errSecSuccess
) {
226 MacOSError::throwMe(result
);
229 tsSetGlobalTrustSettings(ts
, domain
);
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.
239 static void tsPurgeCache()
243 StLock
<Mutex
> _(sutCacheLock());
244 trustSettingsDbg("tsPurgeCache");
245 for(domain
=0; domain
<TRUST_SETTINGS_NUM_DOMAINS
; domain
++) {
246 tsSetGlobalTrustSettings(NULL
, domain
);
251 * Keychain event callback function, for notification by other processes that
252 * user trust list(s) has/have changed.
254 static OSStatus
tsTrustSettingsCallback (
255 SecKeychainEvent keychainEvent
,
256 SecKeychainCallbackInfo
*info
,
259 trustSettingsDbg("tsTrustSettingsCallback, event %d", (int)keychainEvent
);
260 if(keychainEvent
!= kSecTrustSettingsChangedEvent
) {
261 /* should not happen, right? */
262 return errSecSuccess
;
264 if(info
->pid
== getpid()) {
266 * Avoid dup cache invalidates: we already dealt with this event.
268 trustSettingsDbg("cacheEventCallback: our pid, skipping");
273 return errSecSuccess
;
277 * Ensure that we've registered for kSecTrustSettingsChangedEvent callbacks
279 static void tsRegisterCallback()
281 if(sutRegisteredCallback
) {
284 trustSettingsDbg("tsRegisterCallback: registering callback");
285 OSStatus ortn
= SecKeychainAddCallback(tsTrustSettingsCallback
,
286 kSecTrustSettingsChangedEventMask
, NULL
);
288 trustSettingsDbg("tsRegisterCallback: SecKeychainAddCallback returned %d", (int)ortn
);
289 /* Not sure how this could ever happen - maybe if there is no run loop active? */
291 sutRegisteredCallback
= true;
294 #pragma mark --- Static functions ---
298 * Called by API code when a trust list has changed; we notify other processes
299 * and purge our own cache.
301 static void tsTrustSettingsChanged()
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
))));
313 trustSettingsDbg("tsTrustSettingsChanged: posting notification");
314 SecurityServer::ClientSession
cs (Allocator::standard(), Allocator::standard());
315 cs
.postNotification (SecurityServer::kNotificationDomainDatabase
,
316 kSecTrustSettingsChangedEvent
, data
);
321 * Common code for SecTrustSettingsCopyTrustSettings(),
322 * SecTrustSettingsCopyModificationDate().
324 static OSStatus
tsCopyTrustSettings(
325 SecCertificateRef cert
,
326 SecTrustSettingsDomain domain
,
327 CFArrayRef
*trustSettings
, /* optionally RETURNED */
328 CFDateRef
*modDate
) /* optionally RETURNED */
334 /* obtain fresh full copy from disk */
338 result
= TrustSettings::CreateTrustSettings(domain
, CREATE_NO
, TRIM_NO
, ts
);
340 // rather than throw these results, just return them because we are at the top level
341 if (result
== errSecNoTrustSettings
) {
342 return errSecItemNotFound
;
344 else if (result
!= errSecSuccess
) {
348 auto_ptr
<TrustSettings
>_(ts
); // make sure this gets deleted just in case something throws underneath
351 *trustSettings
= ts
->copyTrustSettings(cert
);
354 *modDate
= ts
->copyModDate(cert
);
360 static void tsAddConditionalCerts(CFMutableArrayRef certArray
);
363 * Common code for SecTrustSettingsCopyQualifiedCerts() and
364 * SecTrustSettingsCopyUnrestrictedRoots().
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 */
373 /* per-domain enables */
377 CFArrayRef
*certArray
) /* RETURNED */
379 StLock
<Mutex
> _TC(sutCacheLock());
380 StLock
<Mutex
> _TK(SecTrustKeychainsGetMutex());
382 TS_REQUIRED(certArray
)
384 /* this relies on the domain enums being numbered 0..2, user..system */
385 bool domainEnable
[3] = {user
, admin
, system
};
387 /* we'll retain it again before successful exit */
388 CFRef
<CFMutableArrayRef
> outArray(CFArrayCreateMutable(NULL
, 0,
389 &kCFTypeArrayCallBacks
));
392 * Search all keychains - user's keychain list, System.keychain,
393 * and system root store
395 StorageManager::KeychainList keychains
;
398 globals().storageManager
.getSearchList(keychains
);
401 adminKc
= globals().storageManager
.make(ADMIN_CERT_STORE_PATH
, false);
402 keychains
.push_back(adminKc
);
404 Keychain sysRootKc
= globals().storageManager
.make(SYSTEM_ROOT_STORE_PATH
, false);
405 keychains
.push_back(sysRootKc
);
407 assert(kSecTrustSettingsDomainUser
== 0);
408 for(unsigned domain
=0; domain
<TRUST_SETTINGS_NUM_DOMAINS
; domain
++) {
409 if(!domainEnable
[domain
]) {
412 TrustSettings
*ts
= tsGetGlobalTrustSettings(domain
);
416 ts
->findQualifiedCerts(keychains
,
417 false, /* !findAll */
419 policyOID
, policyString
, keyUsage
,
423 tsAddConditionalCerts(outArray
);
425 *certArray
= outArray
;
426 CFRetain(*certArray
);
427 trustSettingsDbg("tsCopyCertsCommon: %ld certs found",
428 CFArrayGetCount(outArray
));
429 return errSecSuccess
;
432 static void tsAddConditionalCerts(CFMutableArrayRef certArray
)
434 #if TARGET_OS_MAC && !TARGET_IPHONE_SIMULATOR && !TARGET_OS_IPHONE && !TARGET_OS_NANO
435 struct certmap_entry_s
{
436 CFStringRef bundleId
;
438 const CFIndex length
;
440 typedef struct certmap_entry_s certmap_entry_t
;
442 CFBundleRef bundle
= CFBundleGetMainBundle();
443 CFStringRef bundleIdentifier
= (bundle
) ? CFBundleGetIdentifier(bundle
) : NULL
;
444 if (!bundleIdentifier
|| !certArray
) { return; }
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
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
);
463 // this function is a no-op on iOS platforms
468 #pragma mark --- SPI functions ---
472 * Fundamental routine used by TP to ascertain status of one cert.
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.
482 * Returns the domain in which a setting was found in *foundDomain.
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.
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.
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.
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
,
519 StLock
<Mutex
> _(sutCacheLock());
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
)
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';
539 /* initial condition - this can grow if we inspect multiple TrustSettings */
540 *allowedErrors
= NULL
;
541 *numAllowedErrors
= 0;
544 * This loop relies on the ordering of the SecTrustSettingsDomain enum:
545 * search user first, then admin, then system.
547 assert(kSecTrustSettingsDomainAdmin
== (kSecTrustSettingsDomainUser
+ 1));
548 assert(kSecTrustSettingsDomainSystem
== (kSecTrustSettingsDomainAdmin
+ 1));
549 bool foundAny
= false;
550 for(unsigned domain
=kSecTrustSettingsDomainUser
;
551 domain
<=kSecTrustSettingsDomainSystem
;
553 TrustSettings
*ts
= tsGetGlobalTrustSettings(domain
);
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
);
566 * Note this, even though we may overwrite it later if this
567 * is an Unspecified entry and we find a definitive entry
570 *foundDomain
= domain
;
572 if(found
&& (*resultType
!= kSecTrustSettingsResultUnspecified
)) {
573 trustSettingsDbg("SecTrustSettingsEvaluateCert: found in domain %d", domain
);
574 *foundAnyEntry
= true;
575 *foundMatchingEntry
= true;
576 return errSecSuccess
;
578 foundAny
|= foundAnyHere
;
580 trustSettingsDbg("SecTrustSettingsEvaluateCert: NOT FOUND");
581 *foundAnyEntry
= foundAny
;
582 *foundMatchingEntry
= false;
583 return errSecSuccess
;
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.
596 OSStatus
SecTrustSettingsCopyQualifiedCerts(
597 const CSSM_OID
*policyOID
,
598 const char *policyString
, /* optional */
599 uint32 policyStringLen
,
600 SecTrustSettingsKeyUsage keyUsage
, /* optional */
601 CFArrayRef
*certArray
) /* RETURNED */
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';
615 return tsCopyCertsCommon(policyOID
, polStr
.get(), keyUsage
,
616 false, /* !onlyRoots */
617 true, true, true, /* all domains */
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.
628 OSStatus
SecTrustSettingsCopyUnrestrictedRoots(
632 CFArrayRef
*certArray
) /* RETURNED */
636 OSStatus status
= tsCopyCertsCommon(NULL
, NULL
, NULL
, /* no constraints */
637 true, /* onlyRoots */
646 static const char hexChars
[16] = {
647 '0', '1', '2', '3', '4', '5', '6', '7',
648 '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
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.
655 CFStringRef
SecTrustSettingsCertHashStrFromCert(
656 SecCertificateRef certRef
)
658 if(certRef
== NULL
) {
662 if(certRef
== kSecTrustSettingsDefaultRootCertSetting
) {
663 /* use this string instead of the cert hash as the dictionary key */
664 trustSettingsDbg("SecTrustSettingsCertHashStrFromCert: DefaultSetting");
665 return kSecTrustRecordDefaultRootCert
;
669 OSStatus ortn
= SecCertificateGetData(certRef
, &certData
);
673 return SecTrustSettingsCertHashStrFromData(certData
.Data
, certData
.Length
);
676 CFStringRef
SecTrustSettingsCertHashStrFromData(
680 unsigned char digest
[CC_SHA1_DIGEST_LENGTH
];
681 char asciiDigest
[(2 * CC_SHA1_DIGEST_LENGTH
) + 1];
683 char *outp
= asciiDigest
;
684 unsigned char *inp
= digest
;
690 CC_SHA1(cert
, (CC_LONG
)certLen
, digest
);
692 for(dex
=0; dex
<CC_SHA1_DIGEST_LENGTH
; dex
++) {
694 outp
[1] = hexChars
[c
& 0xf];
696 outp
[0] = hexChars
[c
];
700 return CFStringCreateWithCString(NULL
, asciiDigest
, kCFStringEncodingASCII
);
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
708 OSStatus
SecTrustSettingsSetTrustSettingsExternal(
709 CFDataRef settingsIn
, /* optional */
710 SecCertificateRef certRef
, /* optional */
711 CFTypeRef trustSettingsDictOrArray
, /* optional */
712 CFDataRef
*settingsOut
) /* RETURNED */
716 TS_REQUIRED(settingsOut
)
721 result
= TrustSettings::CreateTrustSettings(kSecTrustSettingsDomainMemory
, settingsIn
, ts
);
722 if (result
!= errSecSuccess
) {
726 auto_ptr
<TrustSettings
>_(ts
);
728 if(certRef
!= NULL
) {
729 ts
->setTrustSettings(certRef
, trustSettingsDictOrArray
);
731 *settingsOut
= ts
->createExternal();
732 return errSecSuccess
;
737 #pragma mark --- API functions ---
739 OSStatus
SecTrustSettingsCopyTrustSettings(
740 SecCertificateRef certRef
,
741 SecTrustSettingsDomain domain
,
742 CFArrayRef
*trustSettings
) /* RETURNED */
745 TS_REQUIRED(trustSettings
)
747 OSStatus result
= tsCopyTrustSettings(certRef
, domain
, trustSettings
, NULL
);
748 if (result
== errSecSuccess
&& *trustSettings
== NULL
) {
749 result
= errSecItemNotFound
; /* documented result if no trust settings exist */
754 OSStatus
SecTrustSettingsCopyModificationDate(
755 SecCertificateRef certRef
,
756 SecTrustSettingsDomain domain
,
757 CFDateRef
*modificationDate
) /* RETURNED */
760 TS_REQUIRED(modificationDate
)
762 OSStatus result
= tsCopyTrustSettings(certRef
, domain
, NULL
, modificationDate
);
763 if (result
== errSecSuccess
&& *modificationDate
== NULL
) {
764 result
= errSecItemNotFound
; /* documented result if no trust settings exist */
769 /* works with existing and with new cert */
770 OSStatus
SecTrustSettingsSetTrustSettings(
771 SecCertificateRef certRef
,
772 SecTrustSettingsDomain domain
,
773 CFTypeRef trustSettingsDictOrArray
)
779 if(domain
== kSecTrustSettingsDomainSystem
) {
780 return errSecDataNotModifiable
;
786 result
= TrustSettings::CreateTrustSettings(domain
, CREATE_YES
, TRIM_NO
, ts
);
787 if (result
!= errSecSuccess
) {
791 auto_ptr
<TrustSettings
>_(ts
);
793 ts
->setTrustSettings(certRef
, trustSettingsDictOrArray
);
795 tsTrustSettingsChanged();
796 return errSecSuccess
;
801 OSStatus
SecTrustSettingsRemoveTrustSettings(
802 SecCertificateRef cert
,
803 SecTrustSettingsDomain domain
)
809 if(domain
== kSecTrustSettingsDomainSystem
) {
810 return errSecDataNotModifiable
;
816 result
= TrustSettings::CreateTrustSettings(domain
, CREATE_NO
, TRIM_NO
, ts
);
817 if (result
!= errSecSuccess
) {
821 auto_ptr
<TrustSettings
>_(ts
);
823 /* deleteTrustSettings throws if record not found */
824 trustSettingsDbg("SecTrustSettingsRemoveTrustSettings: deleting from domain %d",
826 ts
->deleteTrustSettings(cert
);
828 tsTrustSettingsChanged();
829 return errSecSuccess
;
834 /* get all certs listed in specified domain */
835 OSStatus
SecTrustSettingsCopyCertificates(
836 SecTrustSettingsDomain domain
,
837 CFArrayRef
*certArray
)
841 TS_REQUIRED(certArray
)
846 result
= TrustSettings::CreateTrustSettings(domain
, CREATE_NO
, TRIM_NO
, ts
);
847 if (result
!= errSecSuccess
) {
851 auto_ptr
<TrustSettings
>_(ts
);
853 CFMutableArrayRef outArray
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
856 * Keychains to search: user's search list, System.keychain, system root store
858 StorageManager::KeychainList keychains
;
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
);
876 /* already validated when we created the TrustSettings */
879 ts
->findCerts(keychains
, outArray
);
880 if(CFArrayGetCount(outArray
) == 0) {
882 return errSecNoTrustSettings
;
884 if (kSecTrustSettingsDomainSystem
== domain
) {
885 tsAddConditionalCerts(outArray
);
887 *certArray
= outArray
;
891 static CFArrayRef gUserAdminCerts
= NULL
;
892 static ReadWriteLock gUserAdminCertsLock
;
894 void SecTrustSettingsPurgeUserAdminCertsCache(void) {
895 StReadWriteLock
_(gUserAdminCertsLock
, StReadWriteLock::Write
);
896 if (gUserAdminCerts
) {
897 CFRelease(gUserAdminCerts
);
898 gUserAdminCerts
= NULL
;
902 OSStatus
SecTrustSettingsCopyCertificatesForUserAdminDomains(
903 CFArrayRef
*certArray
)
905 TS_REQUIRED(certArray
);
906 OSStatus result
= errSecSuccess
;
908 { /* Only hold the lock for the check */
909 StReadWriteLock
_(gUserAdminCertsLock
, StReadWriteLock::Read
);
910 if (gUserAdminCerts
) {
911 *certArray
= (CFArrayRef
)CFRetain(gUserAdminCerts
);
912 return errSecSuccess
;
916 CFMutableArrayRef outArray
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
918 return errSecAllocate
;
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
);
928 OSStatus adminStatus
= SecTrustSettingsCopyCertificates(kSecTrustSettingsDomainAdmin
, &adminTrusted
);
929 if ((adminStatus
== errSecSuccess
) && (adminTrusted
!= NULL
)) {
930 CFArrayAppendArray(outArray
, adminTrusted
, CFRangeMake(0, CFArrayGetCount(adminTrusted
)));
931 CFRelease(adminTrusted
);
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
) {
940 if (result
!= errSecSuccess
&& outArray
) {
945 *certArray
= outArray
;
947 if (certArray
&& *certArray
) {
948 StReadWriteLock
_(gUserAdminCertsLock
, StReadWriteLock::Write
);
949 if (!gUserAdminCerts
) {
950 gUserAdminCerts
= (CFArrayRef
)CFRetain(*certArray
);
958 * Obtain an external, portable representation of the specified
959 * domain's TrustSettings. Caller must CFRelease the returned data.
961 OSStatus
SecTrustSettingsCreateExternalRepresentation(
962 SecTrustSettingsDomain domain
,
963 CFDataRef
*trustSettings
)
967 TS_REQUIRED(trustSettings
)
972 result
= TrustSettings::CreateTrustSettings(domain
, CREATE_NO
, TRIM_NO
, ts
);
973 if (result
!= errSecSuccess
) {
977 auto_ptr
<TrustSettings
>_(ts
);
979 *trustSettings
= ts
->createExternal();
980 return errSecSuccess
;
986 * Import trust settings, obtained via SecTrustSettingsCreateExternalRepresentation,
987 * into the specified domain.
989 OSStatus
SecTrustSettingsImportExternalRepresentation(
990 SecTrustSettingsDomain domain
,
991 CFDataRef trustSettings
) /* optional - NULL means empty settings */
995 if(domain
== kSecTrustSettingsDomainSystem
) {
996 return errSecDataNotModifiable
;
1002 result
= TrustSettings::CreateTrustSettings(domain
, trustSettings
, ts
);
1003 if (result
!= errSecSuccess
) {
1007 auto_ptr
<TrustSettings
>_(ts
);
1010 tsTrustSettingsChanged();
1011 return errSecSuccess
;