2 * Copyright (c) 2006-2018 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@
23 * SecTrust.c - CoreFoundation based certificate trust evaluator
27 #include <Security/SecTrustPriv.h>
28 #include <Security/SecTrustInternal.h>
29 #include <Security/SecTrustStatusCodes.h>
30 #include <Security/SecItemPriv.h>
31 #include <Security/SecCertificateInternal.h>
32 #include <Security/SecFramework.h>
33 #include <Security/SecPolicyCerts.h>
34 #include <Security/SecPolicyInternal.h>
35 #include <Security/SecPolicyPriv.h>
36 #include <Security/SecuritydXPC.h>
37 #include <Security/SecInternal.h>
38 #include <Security/SecBasePriv.h>
39 #include <Security/SecFrameworkStrings.h>
40 #include <CoreFoundation/CFRuntime.h>
41 #include <CoreFoundation/CFSet.h>
42 #include <CoreFoundation/CFString.h>
43 #include <CoreFoundation/CFNumber.h>
44 #include <CoreFoundation/CFArray.h>
45 #include <CoreFoundation/CFPropertyList.h>
46 #include <CoreFoundation/CFError.h>
47 #include <AssertMacros.h>
53 #include <os/activity.h>
55 #include <utilities/SecIOFormat.h>
56 #include <utilities/SecCFError.h>
57 #include <utilities/SecCFWrappers.h>
58 #include <utilities/debugging.h>
59 #include <utilities/der_plist.h>
60 #include <utilities/SecDispatchRelease.h>
61 #include <utilities/SecXPCError.h>
63 #include "SecRSAKey.h"
64 #include <libDER/oids.h>
66 #include <ipc/securityd_client.h>
68 #include <securityd/SecTrustServer.h>
70 #pragma clang diagnostic ignored "-Wformat=2"
72 #define SEC_CONST_DECL(k,v) const CFStringRef k = CFSTR(v);
74 SEC_CONST_DECL (kSecCertificateDetailSHA1Digest
, "SHA1Digest");
75 SEC_CONST_DECL (kSecCertificateDetailStatusCodes
, "StatusCodes");
77 SEC_CONST_DECL (kSecTrustInfoExtendedValidationKey
, "ExtendedValidation");
78 SEC_CONST_DECL (kSecTrustInfoCompanyNameKey
, "CompanyName");
79 SEC_CONST_DECL (kSecTrustInfoRevocationKey
, "Revocation");
80 SEC_CONST_DECL (kSecTrustInfoRevocationValidUntilKey
, "RevocationValidUntil");
81 SEC_CONST_DECL (kSecTrustInfoCertificateTransparencyKey
, "CertificateTransparency");
83 /* Public trust result constants */
84 SEC_CONST_DECL (kSecTrustEvaluationDate
, "TrustEvaluationDate");
85 SEC_CONST_DECL (kSecTrustExtendedValidation
, "TrustExtendedValidation");
86 SEC_CONST_DECL (kSecTrustOrganizationName
, "Organization");
87 SEC_CONST_DECL (kSecTrustResultValue
, "TrustResultValue");
88 SEC_CONST_DECL (kSecTrustRevocationChecked
, "TrustRevocationChecked");
89 SEC_CONST_DECL (kSecTrustRevocationReason
, "TrustRevocationReason");
90 SEC_CONST_DECL (kSecTrustRevocationValidUntilDate
, "TrustExpirationDate");
91 SEC_CONST_DECL (kSecTrustResultDetails
, "TrustResultDetails");
92 SEC_CONST_DECL (kSecTrustCertificateTransparency
, "TrustCertificateTransparency");
93 SEC_CONST_DECL (kSecTrustCertificateTransparencyWhiteList
, "TrustCertificateTransparencyWhiteList");
98 /********************************************************
99 ****************** SecTrust object *********************
100 ********************************************************/
103 CFArrayRef _certificates
;
106 CFArrayRef _responses
;
108 CFArrayRef _trustedLogs
;
109 CFDateRef _verifyDate
;
111 SecKeyRef _publicKey
;
113 CFDictionaryRef _info
;
114 CFArrayRef _exceptions
;
116 /* Note that a value of kSecTrustResultInvalid (0)
117 * indicates the trust must be (re)evaluated; any
118 * functions which modify trust parameters in a way
119 * that would invalidate the current result must set
120 * this value back to kSecTrustResultInvalid.
122 SecTrustResultType _trustResult
;
124 /* If true we don't trust any anchors other than the ones in _anchors. */
126 /* If false we shouldn't search keychains for parents or anchors. */
127 bool _keychainsAllowed
;
129 /* Data blobs for legacy CSSM_TP_APPLE_EVIDENCE_INFO structure,
130 * to support callers of SecTrustGetResult on OS X. Since fields of
131 * one structure contain pointers into the other, these cannot be
132 * serialized; if a SecTrust is being serialized or copied, these values
133 * should just be initialized to NULL in the copy and built when needed. */
134 void* _legacy_info_array
;
135 void* _legacy_status_array
;
137 /* Dispatch queue for thread-safety */
138 dispatch_queue_t _trustQueue
;
140 /* === IMPORTANT! ===
141 * Any change to this structure definition
142 * must also be made in the TSecTrust structure,
143 * located in SecTrust.cpp. To avoid problems,
144 * new fields should always be appended at the
145 * end of the structure.
149 /* Forward declarations of static functions. */
150 static OSStatus
SecTrustEvaluateIfNecessary(SecTrustRef trust
);
152 /* Static functions. */
153 static CFStringRef
SecTrustCopyFormatDescription(CFTypeRef cf
, CFDictionaryRef formatOptions
) {
154 SecTrustRef trust
= (SecTrustRef
)cf
;
155 return CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
,
156 CFSTR("<SecTrustRef: %p>"), trust
);
159 static void SecTrustDestroy(CFTypeRef cf
) {
160 SecTrustRef trust
= (SecTrustRef
)cf
;
162 dispatch_release_null(trust
->_trustQueue
);
163 CFReleaseNull(trust
->_certificates
);
164 CFReleaseNull(trust
->_policies
);
165 CFReleaseNull(trust
->_responses
);
166 CFReleaseNull(trust
->_SCTs
);
167 CFReleaseNull(trust
->_trustedLogs
);
168 CFReleaseNull(trust
->_verifyDate
);
169 CFReleaseNull(trust
->_anchors
);
170 CFReleaseNull(trust
->_chain
);
171 CFReleaseNull(trust
->_publicKey
);
172 CFReleaseNull(trust
->_details
);
173 CFReleaseNull(trust
->_info
);
174 CFReleaseNull(trust
->_exceptions
);
176 if (trust
->_legacy_info_array
) {
177 free(trust
->_legacy_info_array
);
179 if (trust
->_legacy_status_array
) {
180 free(trust
->_legacy_status_array
);
184 /* Public API functions. */
185 CFGiblisFor(SecTrust
)
187 OSStatus
SecTrustCreateWithCertificates(CFTypeRef certificates
,
188 CFTypeRef policies
, SecTrustRef
*trust
) {
189 OSStatus status
= errSecParam
;
190 CFAllocatorRef allocator
= kCFAllocatorDefault
;
191 CFArrayRef l_certs
= NULL
, l_policies
= NULL
;
192 SecTrustRef result
= NULL
;
193 dispatch_queue_t queue
= NULL
;
197 CFTypeID certType
= CFGetTypeID(certificates
);
198 if (certType
== CFArrayGetTypeID()) {
199 CFIndex idx
, count
= CFArrayGetCount(certificates
);
200 /* We need at least 1 certificate. */
201 require_quiet(count
> 0, errOut
);
202 l_certs
= (CFArrayRef
) CFArrayCreateMutable(allocator
, count
,
203 &kCFTypeArrayCallBacks
);
205 status
= errSecAllocate
;
208 for (idx
= 0; idx
< count
; idx
++) {
209 CFTypeRef val
= CFArrayGetValueAtIndex(certificates
, idx
);
210 if (val
) { CFArrayAppendValue((CFMutableArrayRef
)l_certs
, val
); }
212 require_quiet(count
== CFArrayGetCount(l_certs
), errOut
);
213 } else if (certType
== SecCertificateGetTypeID()) {
214 l_certs
= CFArrayCreate(allocator
, &certificates
, 1,
215 &kCFTypeArrayCallBacks
);
220 status
= errSecAllocate
;
225 CFTypeRef policy
= SecPolicyCreateBasicX509();
226 l_policies
= CFArrayCreate(allocator
, &policy
, 1,
227 &kCFTypeArrayCallBacks
);
230 else if (CFGetTypeID(policies
) == CFArrayGetTypeID()) {
231 CFIndex idx
, count
= CFArrayGetCount(policies
);
232 /* We need at least 1 policy. */
233 require_quiet(count
> 0, errOut
);
234 l_policies
= (CFArrayRef
) CFArrayCreateMutable(allocator
, count
,
235 &kCFTypeArrayCallBacks
);
237 status
= errSecAllocate
;
240 for (idx
= 0; idx
< count
; idx
++) {
241 CFTypeRef val
= CFArrayGetValueAtIndex(policies
, idx
);
242 if (val
) { CFArrayAppendValue((CFMutableArrayRef
)l_policies
, val
); }
244 require_quiet(count
== CFArrayGetCount(l_policies
), errOut
);
246 else if (CFGetTypeID(policies
) == SecPolicyGetTypeID()) {
247 l_policies
= CFArrayCreate(allocator
, &policies
, 1,
248 &kCFTypeArrayCallBacks
);
253 status
= errSecAllocate
;
257 queue
= dispatch_queue_create("trust", DISPATCH_QUEUE_SERIAL
);
259 status
= errSecAllocate
;
263 CFIndex size
= sizeof(struct __SecTrust
);
264 require_quiet(result
= (SecTrustRef
)_CFRuntimeCreateInstance(allocator
,
265 SecTrustGetTypeID(), size
- sizeof(CFRuntimeBase
), 0), errOut
);
266 memset((char*)result
+ sizeof(result
->_base
), 0,
267 sizeof(*result
) - sizeof(result
->_base
));
268 status
= errSecSuccess
;
272 CFReleaseSafe(result
);
273 CFReleaseSafe(l_certs
);
274 CFReleaseSafe(l_policies
);
275 dispatch_release_null(queue
);
277 result
->_certificates
= l_certs
;
278 result
->_policies
= l_policies
;
279 result
->_keychainsAllowed
= true;
280 result
->_trustQueue
= queue
;
284 CFReleaseSafe(result
);
289 OSStatus
SecTrustCopyInputCertificates(SecTrustRef trust
, CFArrayRef
*certificates
) {
290 if (!trust
|| !certificates
) {
293 __block CFArrayRef certArray
= NULL
;
294 dispatch_sync(trust
->_trustQueue
, ^{
295 certArray
= CFArrayCreateCopy(NULL
, trust
->_certificates
);
298 return errSecAllocate
;
300 *certificates
= certArray
;
301 return errSecSuccess
;
304 OSStatus
SecTrustAddToInputCertificates(SecTrustRef trust
, CFTypeRef certificates
) {
305 if (!trust
|| !certificates
) {
308 __block CFMutableArrayRef newCertificates
= NULL
;
309 dispatch_sync(trust
->_trustQueue
, ^{
310 newCertificates
= CFArrayCreateMutableCopy(NULL
, 0, trust
->_certificates
);
313 if (isArray(certificates
)) {
314 CFArrayAppendArray(newCertificates
, certificates
,
315 CFRangeMake(0, CFArrayGetCount(certificates
)));
316 } else if (CFGetTypeID(certificates
) == SecCertificateGetTypeID()) {
317 CFArrayAppendValue(newCertificates
, certificates
);
319 CFReleaseNull(newCertificates
);
323 dispatch_sync(trust
->_trustQueue
, ^{
324 CFReleaseNull(trust
->_certificates
);
325 trust
->_certificates
= (CFArrayRef
)newCertificates
;
328 return errSecSuccess
;
331 static void SecTrustSetNeedsEvaluation(SecTrustRef trust
) {
334 dispatch_sync(trust
->_trustQueue
, ^{
335 trust
->_trustResult
= kSecTrustResultInvalid
;
340 OSStatus
SecTrustSetAnchorCertificatesOnly(SecTrustRef trust
,
341 Boolean anchorCertificatesOnly
) {
345 SecTrustSetNeedsEvaluation(trust
);
346 trust
->_anchorsOnly
= anchorCertificatesOnly
;
348 return errSecSuccess
;
351 OSStatus
SecTrustSetAnchorCertificates(SecTrustRef trust
,
352 CFArrayRef anchorCertificates
) {
356 SecTrustSetNeedsEvaluation(trust
);
357 __block CFArrayRef anchorsArray
= NULL
;
358 if (anchorCertificates
) {
359 if (CFGetTypeID(anchorCertificates
) == CFArrayGetTypeID()) {
360 CFIndex idx
, count
= CFArrayGetCount(anchorCertificates
);
361 anchorsArray
= (CFArrayRef
) CFArrayCreateMutable(NULL
, count
,
362 &kCFTypeArrayCallBacks
);
364 return errSecAllocate
;
366 for (idx
= 0; idx
< count
; idx
++) {
367 CFTypeRef val
= CFArrayGetValueAtIndex(anchorCertificates
, idx
);
368 if (val
) { CFArrayAppendValue((CFMutableArrayRef
)anchorsArray
, val
); }
370 if (count
!= CFArrayGetCount(anchorsArray
)) {
371 CFReleaseSafe(anchorsArray
);
379 dispatch_sync(trust
->_trustQueue
, ^{
380 CFReleaseSafe(trust
->_anchors
);
381 trust
->_anchors
= anchorsArray
;
383 trust
->_anchorsOnly
= (anchorCertificates
!= NULL
);
385 return errSecSuccess
;
388 OSStatus
SecTrustCopyCustomAnchorCertificates(SecTrustRef trust
,
389 CFArrayRef
*anchors
) {
390 if (!trust
|| !anchors
) {
393 __block CFArrayRef anchorsArray
= NULL
;
394 dispatch_sync(trust
->_trustQueue
, ^{
395 if (trust
->_anchors
) {
396 anchorsArray
= CFArrayCreateCopy(kCFAllocatorDefault
, trust
->_anchors
);
400 *anchors
= anchorsArray
;
401 return errSecSuccess
;
404 // Return false on error, true on success.
405 static bool to_bool_error_request(enum SecXPCOperation op
, CFErrorRef
*error
) {
406 __block
bool result
= false;
407 securityd_send_sync_and_do(op
, error
, NULL
, ^bool(xpc_object_t response
, CFErrorRef
*error
) {
408 result
= !(error
&& *error
);
414 Boolean
SecTrustFlushResponseCache(CFErrorRef
*error
) {
415 CFErrorRef localError
= NULL
;
416 os_activity_t activity
= os_activity_create("SecTrustFlushResponseCache", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_DEFAULT
);
417 os_activity_scope(activity
);
418 bool result
= TRUSTD_XPC(sec_ocsp_cache_flush
, to_bool_error_request
, &localError
);
419 os_release(activity
);
422 } else if (localError
) {
423 CFRelease(localError
);
428 OSStatus
SecTrustSetOCSPResponse(SecTrustRef trust
, CFTypeRef responseData
) {
432 SecTrustSetNeedsEvaluation(trust
);
433 __block CFArrayRef responseArray
= NULL
;
435 if (CFGetTypeID(responseData
) == CFArrayGetTypeID()) {
436 CFIndex idx
, count
= CFArrayGetCount(responseData
);
437 responseArray
= (CFArrayRef
) CFArrayCreateMutable(NULL
, count
,
438 &kCFTypeArrayCallBacks
);
439 if (!responseArray
) {
440 return errSecAllocate
;
442 for (idx
= 0; idx
< count
; idx
++) {
443 CFTypeRef val
= CFArrayGetValueAtIndex(responseData
, idx
);
444 if (val
) { CFArrayAppendValue((CFMutableArrayRef
)responseArray
, val
); }
446 if (count
!= CFArrayGetCount(responseArray
)) {
447 CFReleaseSafe(responseArray
);
450 } else if (CFGetTypeID(responseData
) == CFDataGetTypeID()) {
451 responseArray
= CFArrayCreate(kCFAllocatorDefault
, &responseData
, 1,
452 &kCFTypeArrayCallBacks
);
458 dispatch_sync(trust
->_trustQueue
, ^{
459 CFReleaseSafe(trust
->_responses
);
460 trust
->_responses
= responseArray
;
463 return errSecSuccess
;
466 OSStatus
SecTrustSetSignedCertificateTimestamps(SecTrustRef trust
, CFArrayRef sctArray
) {
470 SecTrustSetNeedsEvaluation(trust
);
471 dispatch_sync(trust
->_trustQueue
, ^{
472 CFRetainAssign(trust
->_SCTs
, sctArray
);
474 return errSecSuccess
;
477 OSStatus
SecTrustSetTrustedLogs(SecTrustRef trust
, CFArrayRef trustedLogs
) {
481 SecTrustSetNeedsEvaluation(trust
);
482 dispatch_sync(trust
->_trustQueue
, ^{
483 CFRetainAssign(trust
->_trustedLogs
, trustedLogs
);
485 return errSecSuccess
;
488 OSStatus
SecTrustSetVerifyDate(SecTrustRef trust
, CFDateRef verifyDate
) {
492 SecTrustSetNeedsEvaluation(trust
);
494 dispatch_sync(trust
->_trustQueue
, ^{
495 CFRetainAssign(trust
->_verifyDate
, verifyDate
);
497 return errSecSuccess
;
500 OSStatus
SecTrustSetPolicies(SecTrustRef trust
, CFTypeRef newPolicies
) {
501 if (!trust
|| !newPolicies
) {
504 SecTrustSetNeedsEvaluation(trust
);
507 __block CFArrayRef policyArray
= NULL
;
508 if (CFGetTypeID(newPolicies
) == CFArrayGetTypeID()) {
509 CFIndex idx
, count
= CFArrayGetCount(newPolicies
);
510 /* We need at least 1 policy. */
514 policyArray
= (CFArrayRef
) CFArrayCreateMutable(NULL
, count
,
515 &kCFTypeArrayCallBacks
);
517 return errSecAllocate
;
519 for (idx
= 0; idx
< count
; idx
++) {
520 CFTypeRef val
= CFArrayGetValueAtIndex(newPolicies
, idx
);
521 if (val
) { CFArrayAppendValue((CFMutableArrayRef
)policyArray
, val
); }
523 if (count
!= CFArrayGetCount(policyArray
)) {
524 CFReleaseSafe(policyArray
);
527 } else if (CFGetTypeID(newPolicies
) == SecPolicyGetTypeID()) {
528 policyArray
= CFArrayCreate(kCFAllocatorDefault
, &newPolicies
, 1,
529 &kCFTypeArrayCallBacks
);
534 dispatch_sync(trust
->_trustQueue
, ^{
535 CFReleaseSafe(trust
->_policies
);
536 trust
->_policies
= policyArray
;
539 return errSecSuccess
;
542 OSStatus
SecTrustSetPinningPolicyName(SecTrustRef trust
, CFStringRef policyName
) {
543 if (!trust
|| !policyName
) {
547 SecTrustSetNeedsEvaluation(trust
);
549 dispatch_sync(trust
->_trustQueue
, ^{
550 CFArrayForEach(trust
->_policies
, ^(const void *value
) {
551 SecPolicyRef policy
= (SecPolicyRef
)value
;
552 SecPolicySetName(policy
, policyName
);
553 secinfo("SecPinningDb", "Set %@ as name on all policies", policyName
);
556 return errSecSuccess
;
559 OSStatus
SecTrustSetKeychainsAllowed(SecTrustRef trust
, Boolean allowed
) {
563 SecTrustSetNeedsEvaluation(trust
);
564 trust
->_keychainsAllowed
= allowed
;
566 return errSecSuccess
;
569 OSStatus
SecTrustGetKeychainsAllowed(SecTrustRef trust
, Boolean
*allowed
) {
570 if (!trust
|| !allowed
) {
573 *allowed
= trust
->_keychainsAllowed
;
575 return errSecSuccess
;
578 OSStatus
SecTrustCopyPolicies(SecTrustRef trust
, CFArrayRef
*policies
) {
579 if (!trust
|| !policies
) {
582 __block CFArrayRef policyArray
= NULL
;
583 dispatch_sync(trust
->_trustQueue
, ^{
584 policyArray
= CFArrayCreateCopy(kCFAllocatorDefault
, trust
->_policies
);
587 return errSecAllocate
;
589 *policies
= policyArray
;
590 return errSecSuccess
;
593 static OSStatus
SecTrustSetOptionInPolicies(CFArrayRef policies
, CFStringRef key
, CFTypeRef value
) {
594 OSStatus status
= errSecSuccess
;
595 require_action(policies
&& CFGetTypeID(policies
) == CFArrayGetTypeID(), out
, status
= errSecInternal
);
596 for (int i
=0; i
< CFArrayGetCount(policies
); i
++) {
597 SecPolicyRef policy
= NULL
;
598 require_action_quiet(policy
= (SecPolicyRef
)CFArrayGetValueAtIndex(policies
, i
), out
, status
= errSecInternal
);
599 CFMutableDictionaryRef options
= NULL
;
600 require_action_quiet(options
= CFDictionaryCreateMutableCopy(NULL
, 0, policy
->_options
), out
, status
= errSecAllocate
);
601 CFDictionarySetValue(options
, key
, value
);
602 CFReleaseNull(policy
->_options
);
603 policy
->_options
= options
;
609 static OSStatus
SecTrustRemoveOptionInPolicies(CFArrayRef policies
, CFStringRef key
) {
610 OSStatus status
= errSecSuccess
;
611 require_action(policies
&& CFGetTypeID(policies
) == CFArrayGetTypeID(), out
, status
= errSecInternal
);
612 for (int i
=0; i
< CFArrayGetCount(policies
); i
++) {
613 SecPolicyRef policy
= NULL
;
614 require_action_quiet(policy
= (SecPolicyRef
)CFArrayGetValueAtIndex(policies
, i
), out
, status
= errSecInternal
);
615 if (CFDictionaryGetValue(policy
->_options
, key
)) {
616 CFMutableDictionaryRef options
= NULL
;
617 require_action_quiet(options
= CFDictionaryCreateMutableCopy(NULL
, 0, policy
->_options
), out
, status
= errSecAllocate
);
618 CFDictionaryRemoveValue(options
, key
);
619 CFReleaseNull(policy
->_options
);
620 policy
->_options
= options
;
627 static CF_RETURNS_RETAINED CFArrayRef
SecTrustCopyOptionsFromPolicies(CFArrayRef policies
, CFStringRef key
) {
628 CFMutableArrayRef foundValues
= NULL
;
629 foundValues
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
630 for (int i
=0; i
< CFArrayGetCount(policies
); i
++) {
631 SecPolicyRef policy
= (SecPolicyRef
)CFArrayGetValueAtIndex(policies
, i
);
632 CFTypeRef value
= CFDictionaryGetValue(policy
->_options
, key
);
634 CFArrayAppendValue(foundValues
, value
);
637 if (!CFArrayGetCount(foundValues
)) {
638 CFReleaseNull(foundValues
);
646 /* The only effective way to disable network fetch is within the policy options:
647 * presence of the kSecPolicyCheckNoNetworkAccess key in any of the policies
648 * will prevent network access for fetching.
649 * The current SecTrustServer implementation doesn't distinguish between network
650 * access for revocation and network access for fetching.
652 OSStatus
SecTrustSetNetworkFetchAllowed(SecTrustRef trust
, Boolean allowFetch
) {
656 __block OSStatus status
= errSecSuccess
;
657 __block
bool oldAllowFetch
= true;
658 dispatch_sync(trust
->_trustQueue
, ^{
659 CFArrayRef foundValues
= SecTrustCopyOptionsFromPolicies(trust
->_policies
, kSecPolicyCheckNoNetworkAccess
);
661 /* We only disable fetch if there is a policy option set for NoNetworkAccess, so the old fetch
662 * status was false (don't allow network) if we find this option set in the policies. */
663 oldAllowFetch
= false;
664 CFReleaseNull(foundValues
);
667 status
= SecTrustSetOptionInPolicies(trust
->_policies
, kSecPolicyCheckNoNetworkAccess
, kCFBooleanTrue
);
669 status
= SecTrustRemoveOptionInPolicies(trust
->_policies
, kSecPolicyCheckNoNetworkAccess
);
672 /* If we switched from NoNetworkAccess to allowing access, we need to re-run the trust evaluation */
673 if (allowFetch
&& !oldAllowFetch
) {
674 SecTrustSetNeedsEvaluation(trust
);
679 OSStatus
SecTrustGetNetworkFetchAllowed(SecTrustRef trust
, Boolean
*allowFetch
) {
680 if (!trust
|| !allowFetch
) {
683 __block CFArrayRef foundValues
= NULL
;
684 dispatch_sync(trust
->_trustQueue
, ^{
685 foundValues
= SecTrustCopyOptionsFromPolicies(trust
->_policies
, kSecPolicyCheckNoNetworkAccess
);
692 CFReleaseNull(foundValues
);
693 return errSecSuccess
;
696 OSStatus
SecTrustSetPinningException(SecTrustRef trust
) {
697 if (!trust
) { return errSecParam
; }
698 __block OSStatus status
= errSecSuccess
;
699 dispatch_sync(trust
->_trustQueue
, ^{
700 status
= SecTrustRemoveOptionInPolicies(trust
->_policies
, kSecPolicyCheckPinningRequired
);
705 CFAbsoluteTime
SecTrustGetVerifyTime(SecTrustRef trust
) {
706 __block CFAbsoluteTime verifyTime
= CFAbsoluteTimeGetCurrent();
710 dispatch_sync(trust
->_trustQueue
, ^{
711 if (trust
->_verifyDate
) {
712 verifyTime
= CFDateGetAbsoluteTime(trust
->_verifyDate
);
714 trust
->_verifyDate
= CFDateCreate(CFGetAllocator(trust
), verifyTime
);
721 CFArrayRef
SecTrustGetDetails(SecTrustRef trust
) {
725 SecTrustEvaluateIfNecessary(trust
);
726 return trust
->_details
;
729 OSStatus
SecTrustGetTrustResult(SecTrustRef trust
,
730 SecTrustResultType
*result
) {
731 if (!trust
|| !result
) {
734 SecTrustEvaluateIfNecessary(trust
);
735 dispatch_sync(trust
->_trustQueue
, ^{
736 *result
= trust
->_trustResult
;
738 return errSecSuccess
;
741 static CFDictionaryRef
SecTrustGetExceptionForCertificateAtIndex(SecTrustRef trust
, CFIndex ix
) {
742 CFDictionaryRef exception
= NULL
;
743 __block CFArrayRef exceptions
= NULL
;
744 dispatch_sync(trust
->_trustQueue
, ^{
745 exceptions
= CFRetainSafe(trust
->_exceptions
);
747 if (!exceptions
|| ix
>= CFArrayGetCount(exceptions
)) {
751 SecCertificateRef certificate
= SecTrustGetCertificateAtIndex(trust
, ix
);
756 exception
= (CFDictionaryRef
)CFArrayGetValueAtIndex(exceptions
, ix
);
757 if (CFGetTypeID(exception
) != CFDictionaryGetTypeID()) {
762 /* If the exception contains the current certificates sha1Digest in the
763 kSecCertificateDetailSHA1Digest key then we use it otherwise we ignore it. */
764 CFDataRef sha1Digest
= SecCertificateGetSHA1Digest(certificate
);
765 CFTypeRef digestValue
= CFDictionaryGetValue(exception
, kSecCertificateDetailSHA1Digest
);
766 if (!digestValue
|| !CFEqual(sha1Digest
, digestValue
))
770 CFReleaseSafe(exceptions
);
774 CFArrayRef
SecTrustCopyFilteredDetails(SecTrustRef trust
) {
778 SecTrustEvaluateIfNecessary(trust
);
779 __block CFArrayRef details
= NULL
;
780 dispatch_sync(trust
->_trustQueue
, ^{
781 details
= CFRetainSafe(trust
->_details
);
784 /* Done automatically by the Policy Server with SecPVCIsExceptedError */
788 Boolean
SecTrustIsExpiredOnly(SecTrustRef trust
) {
789 /* Returns true if one or more certificates in the chain have expired,
790 * expiration is an error (i.e. is not covered by existing trust settings),
791 * and it is the only error encountered.
792 * Returns false if the certificate is valid, or if the trust chain has
793 * other errors beside expiration.
795 Boolean result
= false;
796 Boolean foundExpired
= false;
797 CFArrayRef details
= SecTrustCopyFilteredDetails(trust
);
798 require(details
!= NULL
, out
);
800 CFIndex ix
, pathLength
= CFArrayGetCount(details
);
801 for (ix
= 0; ix
< pathLength
; ++ix
) {
802 CFDictionaryRef detail
= (CFDictionaryRef
)CFArrayGetValueAtIndex(details
, ix
);
803 CFIndex count
= (detail
) ? CFDictionaryGetCount(detail
) : 0;
804 require(count
<= 1, out
);
806 CFBooleanRef valid
= (CFBooleanRef
)CFDictionaryGetValue(detail
, kSecPolicyCheckTemporalValidity
);
807 require(isBoolean(valid
) && CFEqual(valid
, kCFBooleanFalse
), out
);
811 result
= foundExpired
;
813 CFReleaseSafe(details
);
818 static CFArrayRef
SecTrustCreatePolicyAnchorsArray(const UInt8
* certData
, CFIndex certLength
)
820 CFArrayRef array
= NULL
;
821 CFAllocatorRef allocator
= kCFAllocatorDefault
;
822 SecCertificateRef cert
= SecCertificateCreateWithBytes(allocator
, certData
, certLength
);
824 array
= CFArrayCreate(allocator
, (const void **)&cert
, 1, &kCFTypeArrayCallBacks
);
831 static void SecTrustAddPolicyAnchors(SecTrustRef trust
)
833 /* Provide anchor certificates specifically required by certain policies.
834 This is used to evaluate test policies where the anchor is not provided
835 in the root store and may not be able to be supplied by the caller.
837 if (!trust
) { return; }
838 __block CFArrayRef policies
= NULL
;
839 dispatch_sync(trust
->_trustQueue
, ^{
840 policies
= CFRetain(trust
->_policies
);
842 CFIndex ix
, count
= CFArrayGetCount(policies
);
843 for (ix
= 0; ix
< count
; ++ix
) {
844 SecPolicyRef policy
= (SecPolicyRef
) CFArrayGetValueAtIndex(policies
, ix
);
847 if (CFEqual(policy
->_oid
, kSecPolicyAppleTestSMPEncryption
)) {
848 __block CFArrayRef policyAnchors
= SecTrustCreatePolicyAnchorsArray(_SEC_TestAppleRootCAECC
, sizeof(_SEC_TestAppleRootCAECC
));
849 dispatch_sync(trust
->_trustQueue
, ^{
850 CFReleaseSafe(trust
->_anchors
);
851 trust
->_anchors
= policyAnchors
;
853 trust
->_anchorsOnly
= true;
859 CFReleaseSafe(policies
);
862 // uncomment for verbose debug logging (debug builds only)
863 //#define CERT_TRUST_DUMP 1
866 static void sectrustlog(int priority
, const char *format
, ...)
871 if (priority
< LOG_NOTICE
) // log warnings and errors
875 va_start(list
, format
);
876 vsyslog(priority
, format
, list
);
881 static void sectrustshow(CFTypeRef obj
, const char *context
)
884 CFStringRef desc
= CFCopyDescription(obj
);
887 CFIndex length
= CFStringGetMaximumSizeForEncoding(CFStringGetLength(desc
), kCFStringEncodingUTF8
) + 1;
888 char* buffer
= (char*) malloc(length
);
890 Boolean converted
= CFStringGetCString(desc
, buffer
, length
, kCFStringEncodingUTF8
);
892 const char *prefix
= (context
) ? context
: "";
893 const char *separator
= (context
) ? " " : "";
894 sectrustlog(LOG_NOTICE
, "%s%s%s", prefix
, separator
, buffer
);
902 static void cert_trust_dump(SecTrustRef trust
) {
903 SecCertificateRef leaf
= SecTrustGetCertificateAtIndex(trust
, 0);
904 CFStringRef name
= (leaf
) ? SecCertificateCopySubjectSummary(leaf
) : NULL
;
905 secerror("leaf \"%@\"", name
);
906 secerror(": result = %d", (int) trust
->_trustResult
);
908 CFIndex ix
, count
= CFArrayGetCount(trust
->_chain
);
909 CFMutableArrayRef chain
= CFArrayCreateMutable(kCFAllocatorDefault
, count
, &kCFTypeArrayCallBacks
);
910 for (ix
= 0; ix
< count
; ix
++) {
911 SecCertificateRef cert
= (SecCertificateRef
)CFArrayGetValueAtIndex(trust
->_chain
, ix
);
913 CFArrayAppendValue(chain
, cert
);
916 sectrustshow(chain
, "chain:");
917 CFReleaseSafe(chain
);
919 secerror(": %ld certificates, %ld anchors, %ld policies, %ld details",
920 (trust
->_certificates
) ? (long)CFArrayGetCount(trust
->_certificates
) : 0,
921 (trust
->_anchors
) ? (long)CFArrayGetCount(trust
->_anchors
) : 0,
922 (trust
->_policies
) ? (long)CFArrayGetCount(trust
->_policies
) : 0,
923 (trust
->_details
) ? (long)CFArrayGetCount(trust
->_details
) : 0);
925 sectrustshow(trust
->_verifyDate
, "verify date:");
926 sectrustshow(trust
->_certificates
, "certificates:");
927 sectrustshow(trust
->_anchors
, "anchors:");
928 sectrustshow(trust
->_policies
, "policies:");
929 sectrustshow(trust
->_details
, "details:");
930 sectrustshow(trust
->_info
, "info:");
935 static void cert_trust_dump(SecTrustRef trust
) {}
939 OSStatus
SecTrustEvaluate(SecTrustRef trust
, SecTrustResultType
*result
) {
941 *result
= kSecTrustResultInvalid
;
946 OSStatus status
= SecTrustEvaluateIfNecessary(trust
);
950 /* post-process trust result based on exceptions */
951 __block SecTrustResultType trustResult
= kSecTrustResultInvalid
;
952 dispatch_sync(trust
->_trustQueue
, ^{
953 trustResult
= trust
->_trustResult
;
956 /* log to syslog when there is a trust failure */
957 if (trustResult
!= kSecTrustResultProceed
&&
958 trustResult
!= kSecTrustResultUnspecified
) {
959 CFStringRef failureDesc
= SecTrustCopyFailureDescription(trust
);
960 secerror("Trust evaluate failure:%{public}@", failureDesc
);
961 CFRelease(failureDesc
);
966 *result
= trustResult
;
972 static CFStringRef
SecTrustCopyChainSummary(SecTrustRef trust
) {
973 CFMutableStringRef summary
= CFStringCreateMutable(NULL
, 0);
974 __block CFArrayRef chain
= NULL
;
975 dispatch_sync(trust
->_trustQueue
, ^{
976 chain
= trust
->_chain
;
978 CFIndex ix
, count
= CFArrayGetCount(chain
);
979 for (ix
= 0; ix
< count
; ix
++) {
980 if (ix
!= 0) { CFStringAppend(summary
, CFSTR(",")); }
981 CFStringRef certSummary
= SecCertificateCopySubjectSummary((SecCertificateRef
)CFArrayGetValueAtIndex(chain
, ix
));
982 CFStringAppendFormat(summary
, NULL
, CFSTR("\"%@\""), certSummary
);
983 CFReleaseNull(certSummary
);
989 kSecTrustErrorSubTypeRevoked
,
990 kSecTrustErrorSubTypeKeySize
,
991 kSecTrustErrorSubTypeWeakHash
,
992 kSecTrustErrorSubTypeDenied
,
993 kSecTrustErrorSubTypeCompliance
,
994 kSecTrustErrorSubTypePinning
,
995 kSecTrustErrorSubTypeTrust
,
996 kSecTrustErrorSubTypeUsage
,
997 kSecTrustErrorSubTypeName
,
998 kSecTrustErrorSubTypeExpired
,
999 kSecTrustErrorSubTypeInvalid
,
1000 } SecTrustErrorSubType
;
1002 #define SecCopyTrustString(KEY) SecFrameworkCopyLocalizedString(KEY, CFSTR("Trust"))
1004 struct checkmap_entry_s
{
1005 SecTrustErrorSubType type
;
1007 const CFStringRef errorKey
;
1010 typedef struct checkmap_entry_s checkmap_entry_t
;
1012 const checkmap_entry_t checkmap
[] = {
1013 #undef POLICYCHECKMACRO
1014 #define __PC_SUBTYPE_ kSecTrustErrorSubTypeInvalid
1015 #define __PC_SUBTYPE_N kSecTrustErrorSubTypeName
1016 #define __PC_SUBTYPE_E kSecTrustErrorSubTypeExpired
1017 #define __PC_SUBTYPE_S kSecTrustErrorSubTypeKeySize
1018 #define __PC_SUBTYPE_H kSecTrustErrorSubTypeWeakHash
1019 #define __PC_SUBTYPE_U kSecTrustErrorSubTypeUsage
1020 #define __PC_SUBTYPE_P kSecTrustErrorSubTypePinning
1021 #define __PC_SUBTYPE_V kSecTrustErrorSubTypeRevoked
1022 #define __PC_SUBTYPE_T kSecTrustErrorSubTypeTrust
1023 #define __PC_SUBTYPE_C kSecTrustErrorSubTypeCompliance
1024 #define __PC_SUBTYPE_D kSecTrustErrorSubTypeDenied
1025 #define POLICYCHECKMACRO(NAME, TRUSTRESULT, SUBTYPE, LEAFCHECK, PATHCHECK, LEAFONLY, CSSMERR, OSSTATUS) \
1026 { __PC_SUBTYPE_##SUBTYPE , OSSTATUS, SEC_TRUST_ERROR_##NAME },
1027 #include "SecPolicyChecks.list"
1030 static OSStatus
SecTrustCopyErrorStrings(SecTrustRef trust
,
1031 CFStringRef
* CF_RETURNS_RETAINED simpleError
,
1032 CFStringRef
* CF_RETURNS_RETAINED fullError
) {
1033 if (!simpleError
|| !fullError
) {
1036 __block CFArrayRef details
= NULL
;
1037 dispatch_sync(trust
->_trustQueue
, ^{
1038 details
= CFRetainSafe(trust
->_details
);
1041 return errSecInternal
;
1043 /* We need to map the policy check constants to indexes into our checkmap table. */
1044 static dispatch_once_t onceToken
;
1045 static CFArrayRef policyChecks
= NULL
;
1046 dispatch_once(&onceToken
, ^{
1047 CFMutableArrayRef _policyChecks
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
1048 #undef POLICYCHECKMACRO
1049 #define POLICYCHECKMACRO(NAME, TRUSTRESULT, SUBTYPE, LEAFCHECK, PATHCHECK, LEAFONLY, CSSMERR, ERRORSTRING) \
1050 CFArrayAppendValue(_policyChecks, kSecPolicyCheck##NAME);
1051 #include "SecPolicyChecks.list"
1052 policyChecks
= _policyChecks
;
1055 /* Build the errors for each cert in the detailed results array */
1056 __block CFMutableStringRef fullMutableError
= CFStringCreateMutable(NULL
, 0);
1057 __block SecTrustErrorSubType simpleErrorSubType
= kSecTrustErrorSubTypeInvalid
;
1058 __block OSStatus simpleErrorStatus
= errSecInternalError
;
1059 __block CFIndex simpleErrorCertIndex
= kCFNotFound
;
1061 CFIndex count
= CFArrayGetCount(details
);
1062 for (ix
= 0; ix
< count
; ix
++) {
1063 CFDictionaryRef perCertDetails
= (CFDictionaryRef
)CFArrayGetValueAtIndex(details
, ix
);
1064 if (CFDictionaryGetCount(perCertDetails
) == 0) { continue; } // no errors on this cert
1066 /* Get the cert summary and start the full error details string for this cert */
1067 CFStringRef certSummary
= SecCertificateCopySubjectSummary(SecTrustGetCertificateAtIndex(trust
, ix
));
1068 CFStringRef format
= SecCopyTrustString(SEC_TRUST_CERTIFICATE_ERROR
);
1069 CFStringAppendFormat(fullMutableError
, NULL
, format
,
1071 CFReleaseNull(certSummary
);
1072 CFReleaseNull(format
);
1074 /* Figure out the errors */
1075 __block
bool firstError
= true;
1076 CFDictionaryForEach(perCertDetails
, ^(const void *key
, const void * __unused value
) {
1077 CFIndex policyCheckIndex
= CFArrayGetFirstIndexOfValue(policyChecks
, CFRangeMake(0, CFArrayGetCount(policyChecks
)), key
);
1078 if (policyCheckIndex
== kCFNotFound
) { return; }
1079 /* Keep track of the highest priority error encountered during this evaluation.
1080 * If multiple certs have errors of the same subtype we keep the lowest indexed cert. */
1081 if (simpleErrorSubType
> checkmap
[policyCheckIndex
].type
) {
1082 simpleErrorSubType
= checkmap
[policyCheckIndex
].type
;
1083 simpleErrorCertIndex
= ix
;
1084 simpleErrorStatus
= checkmap
[policyCheckIndex
].status
;
1086 /* Add this error to the full error */
1087 if (!firstError
) { CFStringAppend(fullMutableError
, CFSTR(", ")); }
1088 CFStringRef errorString
= SecCopyTrustString(checkmap
[policyCheckIndex
].errorKey
);
1089 CFStringAppend(fullMutableError
, errorString
);
1090 CFReleaseNull(errorString
);
1093 CFStringAppend(fullMutableError
, CFSTR(";"));
1095 CFReleaseNull(details
);
1097 /* Build the simple error */
1098 if (simpleErrorCertIndex
== kCFNotFound
) { simpleErrorCertIndex
= 0; }
1099 CFStringRef format
= NULL
;
1100 CFStringRef certSummary
= SecCertificateCopySubjectSummary(SecTrustGetCertificateAtIndex(trust
, simpleErrorCertIndex
));
1101 switch (simpleErrorSubType
) {
1102 case kSecTrustErrorSubTypeRevoked
: {
1103 format
= SecCopyTrustString(SEC_TRUST_ERROR_SUBTYPE_REVOKED
);
1106 case kSecTrustErrorSubTypeKeySize
: {
1107 format
= SecCopyTrustString(SEC_TRUST_ERROR_SUBTYPE_KEYSIZE
);
1110 case kSecTrustErrorSubTypeWeakHash
: {
1111 format
= SecCopyTrustString(SEC_TRUST_ERROR_SUBTYPE_WEAKHASH
);
1114 case kSecTrustErrorSubTypeDenied
: {
1115 format
= SecCopyTrustString(SEC_TRUST_ERROR_SUBTYPE_DENIED
);
1118 case kSecTrustErrorSubTypeCompliance
: {
1119 format
= SecCopyTrustString(SEC_TRUST_ERROR_SUBTYPE_COMPLIANCE
);
1122 case kSecTrustErrorSubTypeExpired
: {
1123 format
= SecCopyTrustString(SEC_TRUST_ERROR_SUBTYPE_EXPIRED
);
1126 case kSecTrustErrorSubTypeTrust
: {
1127 format
= SecCopyTrustString(SEC_TRUST_ERROR_SUBTYPE_TRUST
);
1130 case kSecTrustErrorSubTypeName
: {
1131 format
= SecCopyTrustString(SEC_TRUST_ERROR_SUBTYPE_NAME
);
1134 case kSecTrustErrorSubTypeUsage
: {
1135 format
= SecCopyTrustString(SEC_TRUST_ERROR_SUBTYPE_USAGE
);
1138 case kSecTrustErrorSubTypePinning
: {
1139 format
= SecCopyTrustString(SEC_TRUST_ERROR_SUBTYPE_PINNING
);
1140 CFAssignRetained(certSummary
, SecTrustCopyChainSummary(trust
));
1144 format
= SecCopyTrustString(SEC_TRUST_ERROR_SUBTYPE_INVALID
);
1148 if (format
&& certSummary
) {
1149 *simpleError
= CFStringCreateWithFormat(NULL
, NULL
, format
, certSummary
);
1151 CFReleaseNull(format
);
1152 CFReleaseNull(certSummary
);
1153 *fullError
= fullMutableError
;
1154 return simpleErrorStatus
;
1157 static CFErrorRef
SecTrustCopyError(SecTrustRef trust
) {
1158 if (!trust
) { return NULL
; }
1159 (void)SecTrustEvaluateIfNecessary(trust
);
1160 OSStatus status
= errSecSuccess
;
1161 __block SecTrustResultType trustResult
= kSecTrustResultInvalid
;
1162 dispatch_sync(trust
->_trustQueue
, ^{
1163 trustResult
= trust
->_trustResult
;
1165 if (trustResult
== kSecTrustResultProceed
|| trustResult
== kSecTrustResultUnspecified
) {
1169 CFStringRef detailedError
= NULL
;
1170 CFStringRef simpleError
= NULL
;
1171 status
= SecTrustCopyErrorStrings(trust
, &simpleError
, &detailedError
);
1172 CFDictionaryRef userInfo
= CFDictionaryCreate(NULL
, (const void **)&kCFErrorLocalizedDescriptionKey
,
1173 (const void **)&detailedError
, 1,
1174 &kCFTypeDictionaryKeyCallBacks
,
1175 &kCFTypeDictionaryValueCallBacks
);
1176 CFErrorRef underlyingError
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, status
, userInfo
);
1177 CFReleaseNull(userInfo
);
1178 CFReleaseNull(detailedError
);
1180 const void *keys
[] = { kCFErrorLocalizedDescriptionKey
, kCFErrorUnderlyingErrorKey
};
1181 const void *values
[] = { simpleError
, underlyingError
};
1182 userInfo
= CFDictionaryCreate(NULL
, keys
, values
, 2,
1183 &kCFTypeDictionaryKeyCallBacks
,
1184 &kCFTypeDictionaryValueCallBacks
);
1185 CFErrorRef error
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, status
, userInfo
);
1186 CFReleaseNull(userInfo
);
1187 CFReleaseNull(simpleError
);
1188 CFReleaseNull(underlyingError
);
1192 bool SecTrustEvaluateWithError(SecTrustRef trust
, CFErrorRef
*error
) {
1193 SecTrustResultType trustResult
= kSecTrustResultInvalid
;
1194 OSStatus status
= SecTrustEvaluate(trust
, &trustResult
);
1195 if (status
== errSecSuccess
&& (trustResult
== kSecTrustResultProceed
|| trustResult
== kSecTrustResultUnspecified
)) {
1202 if (status
!= errSecSuccess
) {
1203 *error
= SecCopyLastError(status
);
1205 *error
= SecTrustCopyError(trust
);
1211 OSStatus
SecTrustEvaluateAsync(SecTrustRef trust
,
1212 dispatch_queue_t queue
, SecTrustCallback result
)
1214 CFRetainSafe(trust
);
1215 dispatch_async(queue
, ^{
1216 SecTrustResultType trustResult
;
1217 if (errSecSuccess
!= SecTrustEvaluate(trust
, &trustResult
)) {
1218 trustResult
= kSecTrustResultInvalid
;
1220 result(trust
, trustResult
);
1221 CFReleaseSafe(trust
);
1223 return errSecSuccess
;
1226 static bool append_certificate_to_xpc_array(SecCertificateRef certificate
, xpc_object_t xpc_certificates
);
1227 static xpc_object_t
copy_xpc_certificates_array(CFArrayRef certificates
);
1228 xpc_object_t
copy_xpc_policies_array(CFArrayRef policies
);
1229 OSStatus
validate_array_of_items(CFArrayRef array
, CFStringRef arrayItemType
, CFTypeID itemTypeID
, bool required
);
1231 static bool append_certificate_to_xpc_array(SecCertificateRef certificate
, xpc_object_t xpc_certificates
) {
1233 return true; // NOOP
1235 size_t length
= SecCertificateGetLength(certificate
);
1236 const uint8_t *bytes
= SecCertificateGetBytePtr(certificate
);
1237 if (!length
|| !bytes
) {
1240 xpc_array_set_data(xpc_certificates
, XPC_ARRAY_APPEND
, bytes
, length
);
1244 static xpc_object_t
copy_xpc_certificates_array(CFArrayRef certificates
) {
1245 xpc_object_t xpc_certificates
= xpc_array_create(NULL
, 0);
1246 if (!xpc_certificates
) {
1249 CFIndex ix
, count
= CFArrayGetCount(certificates
);
1250 for (ix
= 0; ix
< count
; ++ix
) {
1251 SecCertificateRef certificate
= (SecCertificateRef
) CFArrayGetValueAtIndex(certificates
, ix
);
1252 #if SECTRUST_VERBOSE_DEBUG
1253 size_t length
= SecCertificateGetLength(certificate
);
1254 const uint8_t *bytes
= SecCertificateGetBytePtr(certificate
);
1255 secerror("idx=%d of %d; cert=0x%lX length=%ld bytes=0x%lX", (int)ix
, (int)count
, (uintptr_t)certificate
, (size_t)length
, (uintptr_t)bytes
);
1257 if (!append_certificate_to_xpc_array(certificate
, xpc_certificates
)) {
1258 xpc_release(xpc_certificates
);
1259 xpc_certificates
= NULL
;
1263 return xpc_certificates
;
1266 static bool SecXPCDictionarySetCertificates(xpc_object_t message
, const char *key
, CFArrayRef certificates
, CFErrorRef
*error
) {
1267 xpc_object_t xpc_certificates
= copy_xpc_certificates_array(certificates
);
1268 if (!xpc_certificates
) {
1269 SecError(errSecAllocate
, error
, CFSTR("failed to create xpc_array of certificates"));
1272 xpc_dictionary_set_value(message
, key
, xpc_certificates
);
1273 xpc_release(xpc_certificates
);
1277 static bool SecXPCDictionarySetPolicies(xpc_object_t message
, const char *key
, CFArrayRef policies
, CFErrorRef
*error
) {
1278 xpc_object_t xpc_policies
= copy_xpc_policies_array(policies
);
1279 if (!xpc_policies
) {
1280 SecError(errSecAllocate
, error
, CFSTR("failed to create xpc_array of policies"));
1283 xpc_dictionary_set_value(message
, key
, xpc_policies
);
1284 xpc_release(xpc_policies
);
1289 static bool CFDataAppendToXPCArray(CFDataRef data
, xpc_object_t xpc_data_array
, CFErrorRef
*error
) {
1291 return true; // NOOP
1293 size_t length
= CFDataGetLength(data
);
1294 const uint8_t *bytes
= CFDataGetBytePtr(data
);
1295 if (!length
|| !bytes
)
1296 return SecError(errSecParam
, error
, CFSTR("invalid CFDataRef"));
1298 xpc_array_set_data(xpc_data_array
, XPC_ARRAY_APPEND
, bytes
, length
);
1303 static xpc_object_t
CFDataArrayCopyXPCArray(CFArrayRef data_array
, CFErrorRef
*error
) {
1304 xpc_object_t xpc_data_array
;
1305 require_action_quiet(xpc_data_array
= xpc_array_create(NULL
, 0), exit
,
1306 SecError(errSecAllocate
, error
, CFSTR("failed to create xpc_array")));
1307 CFIndex ix
, count
= CFArrayGetCount(data_array
);
1308 for (ix
= 0; ix
< count
; ++ix
) {
1309 if (!CFDataAppendToXPCArray((CFDataRef
)CFArrayGetValueAtIndex(data_array
, ix
), xpc_data_array
, error
)) {
1310 xpc_release(xpc_data_array
);
1316 return xpc_data_array
;
1319 static bool SecXPCDictionarySetDataArray(xpc_object_t message
, const char *key
, CFArrayRef data_array
, CFErrorRef
*error
) {
1320 xpc_object_t xpc_data_array
= CFDataArrayCopyXPCArray(data_array
, error
);
1321 if (!xpc_data_array
)
1323 xpc_dictionary_set_value(message
, key
, xpc_data_array
);
1324 xpc_release(xpc_data_array
);
1328 static bool SecXPCDictionaryCopyChainOptional(xpc_object_t message
, const char *key
, CFArrayRef
*path
, CFErrorRef
*error
) {
1329 xpc_object_t xpc_path
= xpc_dictionary_get_value(message
, key
);
1330 CFMutableArrayRef output
= NULL
;
1336 require_action_quiet(xpc_get_type(xpc_path
) == XPC_TYPE_ARRAY
, exit
, SecError(errSecDecode
, error
, CFSTR("xpc_path value is not an array")));
1337 require_action_quiet(count
= xpc_array_get_count(xpc_path
), exit
, SecError(errSecDecode
, error
, CFSTR("xpc_path array count == 0")));
1338 output
= CFArrayCreateMutable(NULL
, count
, &kCFTypeArrayCallBacks
);
1341 for (ix
= 0; ix
< count
; ++ix
) {
1342 SecCertificateRef certificate
= SecCertificateCreateWithXPCArrayAtIndex(xpc_path
, ix
, error
);
1344 CFArrayAppendValue(output
, certificate
);
1345 CFReleaseNull(certificate
);
1347 CFReleaseNull(output
);
1360 static int SecXPCDictionaryGetNonZeroInteger(xpc_object_t message
, const char *key
, CFErrorRef
*error
) {
1361 int64_t value
= xpc_dictionary_get_int64(message
, key
);
1363 SecError(errSecInternal
, error
, CFSTR("object for key %s is 0"), key
);
1368 static SecTrustResultType
handle_trust_evaluate_xpc(enum SecXPCOperation op
, CFArrayRef certificates
,
1369 CFArrayRef anchors
, bool anchorsOnly
,
1370 bool keychainsAllowed
, CFArrayRef policies
, CFArrayRef responses
,
1371 CFArrayRef SCTs
, CFArrayRef trustedLogs
,
1372 CFAbsoluteTime verifyTime
, __unused CFArrayRef accessGroups
, CFArrayRef exceptions
,
1373 CFArrayRef
*details
, CFDictionaryRef
*info
, CFArrayRef
*chain
, CFErrorRef
*error
)
1375 __block SecTrustResultType tr
= kSecTrustResultInvalid
;
1376 securityd_send_sync_and_do(op
, error
, ^bool(xpc_object_t message
, CFErrorRef
*error
) {
1377 if (!SecXPCDictionarySetCertificates(message
, kSecTrustCertificatesKey
, certificates
, error
))
1379 if (anchors
&& !SecXPCDictionarySetCertificates(message
, kSecTrustAnchorsKey
, anchors
, error
))
1382 xpc_dictionary_set_bool(message
, kSecTrustAnchorsOnlyKey
, anchorsOnly
);
1383 xpc_dictionary_set_bool(message
, kSecTrustKeychainsAllowedKey
, keychainsAllowed
);
1384 if (!SecXPCDictionarySetPolicies(message
, kSecTrustPoliciesKey
, policies
, error
))
1386 if (responses
&& !SecXPCDictionarySetDataArray(message
, kSecTrustResponsesKey
, responses
, error
))
1388 if (SCTs
&& !SecXPCDictionarySetDataArray(message
, kSecTrustSCTsKey
, SCTs
, error
))
1390 if (trustedLogs
&& !SecXPCDictionarySetPList(message
, kSecTrustTrustedLogsKey
, trustedLogs
, error
))
1392 xpc_dictionary_set_double(message
, kSecTrustVerifyDateKey
, verifyTime
);
1393 if (exceptions
&& !SecXPCDictionarySetPList(message
, kSecTrustExceptionsKey
, exceptions
, error
))
1396 }, ^bool(xpc_object_t response
, CFErrorRef
*error
) {
1397 secdebug("trust", "response: %@", response
);
1398 return SecXPCDictionaryCopyArrayOptional(response
, kSecTrustDetailsKey
, details
, error
) &&
1399 SecXPCDictionaryCopyDictionaryOptional(response
, kSecTrustInfoKey
, info
, error
) &&
1400 SecXPCDictionaryCopyChainOptional(response
, kSecTrustChainKey
, chain
, error
) &&
1401 ((tr
= SecXPCDictionaryGetNonZeroInteger(response
, kSecTrustResultKey
, error
)) != kSecTrustResultInvalid
);
1406 OSStatus
validate_array_of_items(CFArrayRef array
, CFStringRef arrayItemType
, CFTypeID itemTypeID
, bool required
) {
1407 OSStatus result
= errSecSuccess
;
1408 CFIndex index
, count
;
1409 count
= (array
) ? CFArrayGetCount(array
) : 0;
1410 if (!count
&& required
) {
1411 secerror("no %@ in array!", arrayItemType
);
1412 result
= errSecParam
;
1414 for (index
= 0; index
< count
; index
++) {
1415 CFTypeRef item
= (CFTypeRef
) CFArrayGetValueAtIndex(array
, index
);
1417 secerror("%@ %@ (index %d)", arrayItemType
, CFSTR("reference is nil"), (int)index
);
1418 result
= errSecParam
;
1421 if (CFGetTypeID(item
) != itemTypeID
) {
1422 secerror("%@ %@ (index %d)", arrayItemType
, CFSTR("is not the expected CF type"), (int)index
);
1423 result
= errSecParam
;
1426 if (CFGetTypeID(item
) == SecCertificateGetTypeID()) {
1427 SecCertificateRef certificate
= (SecCertificateRef
) item
;
1428 CFIndex length
= SecCertificateGetLength(certificate
);
1429 const UInt8
*bytes
= SecCertificateGetBytePtr(certificate
);
1431 secerror("%@ %@ (index %d)", arrayItemType
, CFSTR("has zero length"), (int)index
);
1432 result
= errSecParam
;
1435 secerror("%@ %@ (index %d)", arrayItemType
, CFSTR("has nil bytes"), (int)index
);
1436 result
= errSecParam
;
1438 #if SECTRUST_VERBOSE_DEBUG
1439 secerror("%@[%d] of %d = %ld bytes @ 0x%lX", arrayItemType
, (int)index
, (int)count
, (size_t)length
, (uintptr_t)bytes
);
1443 if (CFGetTypeID(item
) == SecPolicyGetTypeID()) {
1444 SecPolicyRef policy
= (SecPolicyRef
) item
;
1445 CFStringRef oidStr
= policy
->_oid
;
1446 if (!oidStr
|| (CFGetTypeID(oidStr
) != CFStringGetTypeID())) {
1447 oidStr
= CFSTR("has invalid OID string!");
1448 secerror("%@ %@ (index %d)", arrayItemType
, oidStr
, (int)index
);
1450 #if SECTRUST_VERBOSE_DEBUG
1451 secerror("%@[%d] of %d = \"%@\" 0x%lX", arrayItemType
, (int)index
, (int)count
, oidStr
, (uintptr_t)policy
);
1458 static OSStatus
SecTrustValidateInput(SecTrustRef trust
) {
1459 OSStatus status
, result
= errSecSuccess
;
1461 // certificates (required)
1462 status
= validate_array_of_items(trust
->_certificates
, CFSTR("certificate"), SecCertificateGetTypeID(), true);
1463 if (status
) result
= status
;
1464 // anchors (optional)
1465 status
= validate_array_of_items(trust
->_anchors
, CFSTR("input anchor"), SecCertificateGetTypeID(), false);
1466 if (status
) result
= status
;
1467 // policies (required??)
1468 status
= validate_array_of_items(trust
->_policies
, CFSTR("policy"), SecPolicyGetTypeID(), true);
1469 if (status
) result
= status
;
1470 // _responses, _SCTs, _trustedLogs, ...
1471 // verify time: SecTrustGetVerifyTime(trust)
1472 // access groups: SecAccessGroupsGetCurrent()
1477 static OSStatus
SecTrustEvaluateIfNecessary(SecTrustRef trust
) {
1478 __block OSStatus result
;
1483 __block CFAbsoluteTime verifyTime
= SecTrustGetVerifyTime(trust
);
1484 SecTrustAddPolicyAnchors(trust
);
1485 dispatch_sync(trust
->_trustQueue
, ^{
1486 if (trust
->_trustResult
!= kSecTrustResultInvalid
) {
1487 result
= errSecSuccess
;
1491 trust
->_trustResult
= kSecTrustResultOtherError
; /* to avoid potential recursion */
1493 CFReleaseNull(trust
->_chain
);
1494 CFReleaseNull(trust
->_details
);
1495 CFReleaseNull(trust
->_info
);
1496 if (trust
->_legacy_info_array
) {
1497 free(trust
->_legacy_info_array
);
1498 trust
->_legacy_info_array
= NULL
;
1500 if (trust
->_legacy_status_array
) {
1501 free(trust
->_legacy_status_array
);
1502 trust
->_legacy_status_array
= NULL
;
1505 os_activity_initiate("SecTrustEvaluateIfNecessary", OS_ACTIVITY_FLAG_DEFAULT
, ^{
1506 SecTrustValidateInput(trust
);
1508 /* @@@ Consider an optimization where we keep a side dictionary with the SHA1 hash of ever SecCertificateRef we send, so we only send potential duplicates once, and have the server respond with either just the SHA1 hash of a certificate, or the complete certificate in the response depending on whether the client already sent it, so we don't send back certificates to the client it already has. */
1509 result
= SecOSStatusWith(^bool (CFErrorRef
*error
) {
1510 trust
->_trustResult
= TRUSTD_XPC(sec_trust_evaluate
,
1511 handle_trust_evaluate_xpc
,
1512 trust
->_certificates
, trust
->_anchors
, trust
->_anchorsOnly
, trust
->_keychainsAllowed
,
1513 trust
->_policies
, trust
->_responses
, trust
->_SCTs
, trust
->_trustedLogs
,
1514 verifyTime
, SecAccessGroupsGetCurrent(), trust
->_exceptions
,
1515 &trust
->_details
, &trust
->_info
, &trust
->_chain
, error
);
1516 if (trust
->_trustResult
== kSecTrustResultInvalid
/* TODO check domain */ &&
1517 SecErrorGetOSStatus(*error
) == errSecNotAvailable
&&
1518 CFArrayGetCount(trust
->_certificates
)) {
1519 /* We failed to talk to securityd. The only time this should
1520 happen is when we are running prior to launchd enabling
1521 registration of services. This currently happens when we
1522 are running from the ramdisk. To make ASR happy we initialize
1523 _chain and return success with a failure as the trustResult, to
1524 make it seem like we did a cert evaluation, so ASR can extract
1525 the public key from the leaf. */
1526 SecCertificateRef leafCert
= (SecCertificateRef
)CFArrayGetValueAtIndex(trust
->_certificates
, 0);
1527 CFArrayRef leafCertArray
= CFArrayCreate(NULL
, (const void**)&leafCert
, 1, &kCFTypeArrayCallBacks
);
1528 trust
->_chain
= leafCertArray
;
1530 CFReleaseNull(*error
);
1533 return trust
->_trustResult
!= kSecTrustResultInvalid
;
1540 /* Helper for the qsort below. */
1541 static int compare_strings(const void *a1
, const void *a2
) {
1542 CFStringRef s1
= *(CFStringRef
*)a1
;
1543 CFStringRef s2
= *(CFStringRef
*)a2
;
1544 return (int) CFStringCompare(s1
, s2
, kCFCompareForcedOrdering
);
1547 CFStringRef
SecTrustCopyFailureDescription(SecTrustRef trust
) {
1551 CFMutableStringRef reason
= CFStringCreateMutable(NULL
, 0);
1552 SecTrustEvaluateIfNecessary(trust
);
1553 __block CFArrayRef details
= NULL
;
1554 dispatch_sync(trust
->_trustQueue
, ^{
1555 details
= CFRetainSafe(trust
->_details
);
1557 CFIndex pathLength
= details
? CFArrayGetCount(details
) : 0;
1558 for (CFIndex ix
= 0; ix
< pathLength
; ++ix
) {
1559 CFDictionaryRef detail
= (CFDictionaryRef
)CFArrayGetValueAtIndex(details
, ix
);
1560 CFIndex dCount
= CFDictionaryGetCount(detail
);
1563 CFStringAppend(reason
, CFSTR(" [leaf"));
1564 else if (ix
== pathLength
- 1)
1565 CFStringAppend(reason
, CFSTR(" [root"));
1567 CFStringAppendFormat(reason
, NULL
, CFSTR(" [ca%" PRIdCFIndex
), ix
);
1569 const void *keys
[dCount
];
1570 CFDictionaryGetKeysAndValues(detail
, &keys
[0], NULL
);
1571 qsort(&keys
[0], dCount
, sizeof(keys
[0]), compare_strings
);
1572 for (CFIndex kix
= 0; kix
< dCount
; ++kix
) {
1573 CFStringRef key
= keys
[kix
];
1574 const void *value
= CFDictionaryGetValue(detail
, key
);
1575 CFStringAppendFormat(reason
, NULL
, CFSTR(" %@%@"), key
,
1576 (CFGetTypeID(value
) == CFBooleanGetTypeID()
1577 ? CFSTR("") : value
));
1579 CFStringAppend(reason
, CFSTR("]"));
1582 CFReleaseSafe(details
);
1587 /* On OS X we need SecTrustCopyPublicKey to give us a CDSA-based SecKeyRef,
1588 so we will refer to this one internally as SecTrustCopyPublicKey_ios,
1589 and call it from SecTrustCopyPublicKey.
1591 SecKeyRef
SecTrustCopyPublicKey_ios(SecTrustRef trust
)
1593 SecKeyRef
SecTrustCopyPublicKey(SecTrustRef trust
)
1599 __block SecKeyRef publicKey
= NULL
;
1600 dispatch_sync(trust
->_trustQueue
, ^{
1601 if (trust
->_publicKey
) {
1602 publicKey
= CFRetainSafe(trust
->_publicKey
);
1605 SecCertificateRef leaf
= (SecCertificateRef
)CFArrayGetValueAtIndex(trust
->_certificates
, 0);
1607 trust
->_publicKey
= SecCertificateCopyPublicKey_ios(leaf
);
1609 trust
->_publicKey
= SecCertificateCopyPublicKey(leaf
);
1611 if (trust
->_publicKey
) {
1612 publicKey
= CFRetainSafe(trust
->_publicKey
);
1615 /* If we couldn't get a public key from the leaf cert alone. */
1617 SecTrustEvaluateIfNecessary(trust
);
1618 dispatch_sync(trust
->_trustQueue
, ^{
1619 if (trust
->_chain
) {
1620 SecCertificateRef cert
= (SecCertificateRef
)CFArrayGetValueAtIndex(trust
->_chain
, 0);
1622 trust
->_publicKey
= SecCertificateCopyPublicKey_ios(cert
);
1624 trust
->_publicKey
= SecCertificateCopyPublicKey(cert
);
1626 publicKey
= CFRetainSafe(trust
->_publicKey
);
1633 CFIndex
SecTrustGetCertificateCount(SecTrustRef trust
) {
1637 SecTrustEvaluateIfNecessary(trust
);
1638 __block CFIndex certCount
= 1;
1639 dispatch_sync(trust
->_trustQueue
, ^{
1640 if (trust
->_chain
) {
1641 certCount
= CFArrayGetCount(trust
->_chain
);
1647 SecCertificateRef
SecTrustGetCertificateAtIndex(SecTrustRef trust
,
1652 __block SecCertificateRef cert
= NULL
;
1654 dispatch_sync(trust
->_trustQueue
, ^{
1655 cert
= (SecCertificateRef
)CFArrayGetValueAtIndex(trust
->_certificates
, 0);
1659 SecTrustEvaluateIfNecessary(trust
);
1660 dispatch_sync(trust
->_trustQueue
, ^{
1661 if (trust
->_chain
) {
1662 cert
= (SecCertificateRef
)CFArrayGetValueAtIndex(trust
->_chain
, ix
);
1668 CFDictionaryRef
SecTrustCopyInfo(SecTrustRef trust
) {
1672 SecTrustEvaluateIfNecessary(trust
);
1673 __block CFDictionaryRef info
= NULL
;
1674 dispatch_sync(trust
->_trustQueue
, ^{
1675 info
= CFRetainSafe(trust
->_info
);
1680 CFArrayRef
SecTrustGetTrustExceptionsArray(SecTrustRef trust
) {
1684 __block CFArrayRef exceptions
= NULL
;
1685 dispatch_sync(trust
->_trustQueue
, ^{
1686 exceptions
= trust
->_exceptions
;
1691 CFDataRef
SecTrustCopyExceptions(SecTrustRef trust
) {
1692 /* Stash the old exceptions and run an evaluation with no exceptions filtered. */
1693 __block CFArrayRef oldExceptions
= NULL
;
1694 dispatch_sync(trust
->_trustQueue
, ^{
1695 if (trust
->_exceptions
) {
1696 oldExceptions
= trust
->_exceptions
;
1697 trust
->_exceptions
= NULL
;
1700 SecTrustSetNeedsEvaluation(trust
);
1702 /* Create the new exceptions based on an unfiltered eval. */
1703 __block CFArrayRef details
= NULL
;
1704 SecTrustEvaluateIfNecessary(trust
);
1705 dispatch_sync(trust
->_trustQueue
, ^{
1706 details
= CFRetainSafe(trust
->_details
);
1708 CFIndex pathLength
= details
? CFArrayGetCount(details
) : 0;
1709 CFMutableArrayRef exceptions
= CFArrayCreateMutable(kCFAllocatorDefault
, pathLength
, &kCFTypeArrayCallBacks
);
1711 for (ix
= 0; ix
< pathLength
; ++ix
) {
1712 CFDictionaryRef detail
= (CFDictionaryRef
)CFArrayGetValueAtIndex(details
, ix
);
1713 CFIndex detailCount
= CFDictionaryGetCount(detail
);
1714 CFMutableDictionaryRef exception
;
1715 if (ix
== 0 || detailCount
> 0) {
1716 exception
= CFDictionaryCreateMutableCopy(kCFAllocatorDefault
, detailCount
+ 1, detail
);
1717 SecCertificateRef certificate
= SecTrustGetCertificateAtIndex(trust
, ix
);
1718 CFDataRef digest
= SecCertificateGetSHA1Digest(certificate
);
1719 CFDictionaryAddValue(exception
, kSecCertificateDetailSHA1Digest
, digest
);
1721 /* Add empty exception dictionaries for non leaf certs which have no exceptions to save space. */
1722 exception
= (CFMutableDictionaryRef
)CFDictionaryCreate(kCFAllocatorDefault
, NULL
, NULL
, 0,
1723 &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
1725 CFArrayAppendValue(exceptions
, exception
);
1726 CFReleaseNull(exception
);
1729 /* Restore the stashed exceptions. */
1730 if (oldExceptions
) {
1731 dispatch_sync(trust
->_trustQueue
, ^{
1732 trust
->_exceptions
= oldExceptions
;
1734 SecTrustSetNeedsEvaluation(trust
);
1737 /* Remove any trailing empty dictionaries to save even more space (we skip the leaf
1738 since it will never be empty). */
1739 for (ix
= pathLength
; ix
-- > 1;) {
1740 CFDictionaryRef exception
= (CFDictionaryRef
)CFArrayGetValueAtIndex(exceptions
, ix
);
1741 if (CFDictionaryGetCount(exception
) == 0) {
1742 CFArrayRemoveValueAtIndex(exceptions
, ix
);
1748 CFDataRef encodedExceptions
= CFPropertyListCreateData(kCFAllocatorDefault
,
1749 exceptions
, kCFPropertyListBinaryFormat_v1_0
, 0, NULL
);
1750 CFRelease(exceptions
);
1751 CFReleaseSafe(details
);
1752 return encodedExceptions
;
1755 bool SecTrustSetExceptions(SecTrustRef trust
, CFDataRef encodedExceptions
) {
1759 CFArrayRef exceptions
= NULL
;
1761 if (NULL
!= encodedExceptions
) {
1762 exceptions
= (CFArrayRef
)CFPropertyListCreateWithData(kCFAllocatorDefault
,
1763 encodedExceptions
, kCFPropertyListImmutable
, NULL
, NULL
);
1766 if (exceptions
&& CFGetTypeID(exceptions
) != CFArrayGetTypeID()) {
1767 CFRelease(exceptions
);
1771 dispatch_sync(trust
->_trustQueue
, ^{
1772 CFReleaseSafe(trust
->_exceptions
);
1773 trust
->_exceptions
= exceptions
;
1776 /* We changed the exceptions -- so we need to re-evaluate */
1777 SecTrustSetNeedsEvaluation(trust
);
1779 /* If there is a valid exception entry for our current leaf we're golden. */
1780 if (SecTrustGetExceptionForCertificateAtIndex(trust
, 0))
1783 /* The passed in exceptions didn't match our current leaf, so we discard it. */
1784 dispatch_sync(trust
->_trustQueue
, ^{
1785 CFReleaseNull(trust
->_exceptions
);
1792 SecTrustSetOptions(SecTrustRef trustRef
, SecTrustOptionFlags options
)
1794 /* bridge to support API functionality for legacy callers */
1795 OSStatus status
= errSecSuccess
;
1797 /* No options or none that trigger the exceptions behavior */
1799 0 == (options
& (kSecTrustOptionAllowExpired
|
1800 kSecTrustOptionImplicitAnchors
|
1801 kSecTrustOptionAllowExpiredRoot
))) {
1805 __block CFMutableArrayRef exceptions
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
1806 if (!exceptions
) { return errSecAllocate
; }
1808 /* Add the new options to the old_exceptions when those exceptions are tied to a particular cert.
1809 * If not tied to a particular cert, we reset the exceptions based on the input options. */
1810 CFArrayRef old_exceptions
= SecTrustGetTrustExceptionsArray(trustRef
);
1811 if (old_exceptions
&& SecTrustGetExceptionForCertificateAtIndex(trustRef
, 0)) {
1812 CFIndex ix
, count
= CFArrayGetCount(old_exceptions
);
1813 for (ix
= 0; ix
< count
; ix
++) {
1814 CFMutableDictionaryRef exception_dictionary
= CFDictionaryCreateMutableCopy(NULL
, 0, (CFDictionaryRef
)CFArrayGetValueAtIndex(old_exceptions
, ix
));
1815 if (!exception_dictionary
) { status
= errSecAllocate
; goto out
; }
1816 if ((options
& kSecTrustOptionAllowExpired
) != 0) {
1817 CFDictionaryAddValue(exception_dictionary
, kSecPolicyCheckTemporalValidity
, kCFBooleanFalse
);
1819 if ((options
& (kSecTrustOptionImplicitAnchors
| kSecTrustOptionAllowExpiredRoot
)) != 0) {
1820 /* Check that root is self-signed. */
1821 Boolean isSelfSigned
= false;
1822 SecCertificateRef cert
= SecTrustGetCertificateAtIndex(trustRef
, ix
);
1823 if (cert
&& (errSecSuccess
== SecCertificateIsSelfSigned(cert
, &isSelfSigned
)) &&
1825 if ((options
& kSecTrustOptionImplicitAnchors
) != 0) {
1826 CFDictionaryAddValue(exception_dictionary
, kSecPolicyCheckAnchorTrusted
, kCFBooleanFalse
);
1827 } else if ((options
& kSecTrustOptionAllowExpiredRoot
) != 0) {
1828 CFDictionaryAddValue(exception_dictionary
, kSecPolicyCheckTemporalValidity
, kCFBooleanFalse
);
1832 CFArrayAppendValue(exceptions
, exception_dictionary
);
1833 CFReleaseNull(exception_dictionary
);
1836 /* Create a new exceptions array. Warning, this takes advantage of implementation details of the exceptions mechanism. */
1837 CFMutableDictionaryRef exception_dictionary
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
,
1838 &kCFTypeDictionaryValueCallBacks
);
1839 if (!exception_dictionary
) { status
= errSecAllocate
; goto out
; }
1840 if ((options
& kSecTrustOptionAllowExpired
) != 0) {
1841 CFDictionaryAddValue(exception_dictionary
, kSecPolicyCheckTemporalValidity
, kCFBooleanFalse
);
1843 if ((options
& kSecTrustOptionAllowExpiredRoot
) != 0) {
1844 CFDictionaryAddValue(exception_dictionary
, kSecPolicyCheckValidRoot
, kCFBooleanFalse
);
1846 if ((options
& kSecTrustOptionImplicitAnchors
) != 0) {
1847 CFDictionaryAddValue(exception_dictionary
, kSecPolicyCheckAnchorTrusted
, kCFBooleanFalse
);
1849 CFArrayAppendValue(exceptions
, exception_dictionary
);
1850 CFReleaseNull(exception_dictionary
);
1853 /* Set exceptions */
1854 dispatch_sync(trustRef
->_trustQueue
, ^{
1855 CFReleaseSafe(trustRef
->_exceptions
);
1856 trustRef
->_exceptions
= CFRetainSafe(exceptions
);
1858 /* We changed the exceptions -- so we need to re-evaluate */
1859 SecTrustSetNeedsEvaluation(trustRef
);
1862 CFReleaseNull(exceptions
);
1867 CFArrayRef
SecTrustCopySummaryPropertiesAtIndex(SecTrustRef trust
, CFIndex ix
) {
1868 CFMutableArrayRef summary
;
1869 SecCertificateRef certificate
= SecTrustGetCertificateAtIndex(trust
, ix
);
1870 summary
= SecCertificateCopySummaryProperties(certificate
,
1871 SecTrustGetVerifyTime(trust
));
1872 /* FIXME Add more details in the failure case. */
1877 CFArrayRef
SecTrustCopyDetailedPropertiesAtIndex(SecTrustRef trust
, CFIndex ix
) {
1879 SecCertificateRef certificate
= SecTrustGetCertificateAtIndex(trust
, ix
);
1880 summary
= SecCertificateCopyProperties(certificate
);
1885 struct TrustFailures
{
1887 bool unknownCritExtn
;
1888 bool untrustedAnchor
;
1889 bool hostnameMismatch
;
1897 static void applyDetailProperty(const void *_key
, const void *_value
,
1899 CFStringRef key
= (CFStringRef
)_key
;
1900 struct TrustFailures
*tf
= (struct TrustFailures
*)context
;
1901 if (CFGetTypeID(_value
) != CFBooleanGetTypeID()) {
1902 /* Value isn't a CFBooleanRef, oh no! */
1905 CFBooleanRef value
= (CFBooleanRef
)_value
;
1906 if (CFBooleanGetValue(value
)) {
1907 /* Not an actual failure so we don't report it. */
1911 /* @@@ FIXME: Report a different return value when something is in the
1912 details but masked out by an exception and use that below for display
1914 if (CFEqual(key
, kSecPolicyCheckIdLinkage
)) {
1915 tf
->badLinkage
= true;
1916 } else if (CFEqual(key
, kSecPolicyCheckCriticalExtensions
)) {
1917 tf
->unknownCritExtn
= true;
1918 } else if (CFEqual(key
, kSecPolicyCheckAnchorTrusted
)
1919 || CFEqual(key
, kSecPolicyCheckAnchorSHA1
)
1920 || CFEqual(key
, kSecPolicyCheckAnchorSHA256
)
1921 || CFEqual(key
, kSecPolicyCheckAnchorApple
)
1922 || CFEqual(key
, kSecPolicyCheckMissingIntermediate
)) {
1923 tf
->untrustedAnchor
= true;
1924 } else if (CFEqual(key
, kSecPolicyCheckSSLHostname
)) {
1925 tf
->hostnameMismatch
= true;
1926 } else if (CFEqual(key
, kSecPolicyCheckTemporalValidity
)) {
1927 tf
->invalidCert
= true;
1928 } else if (CFEqual(key
, kSecPolicyCheckWeakKeySize
)) {
1930 } else if (CFEqual(key
, kSecPolicyCheckWeakSignature
)) {
1931 tf
->weakHash
= true;
1932 } else if (CFEqual(key
, kSecPolicyCheckRevocation
)) {
1933 tf
->revocation
= true;
1935 /* Anything else is a policy failure. */
1937 if (CFEqual(key
, kSecPolicyCheckNonEmptySubject
)
1938 || CFEqual(key
, kSecPolicyCheckBasicConstraints
)
1939 || CFEqual(key
, kSecPolicyCheckKeyUsage
)
1940 || CFEqual(key
, kSecPolicyCheckExtendedKeyUsage
)
1941 || CFEqual(key
, kSecPolicyCheckIssuerCommonName
)
1942 || CFEqual(key
, kSecPolicyCheckSubjectCommonNamePrefix
)
1943 || CFEqual(key
, kSecPolicyCheckChainLength
)
1944 || CFEqual(key
, kSecPolicyCheckNotValidBefore
))
1947 tf
->policyFail
= true;
1951 static void appendError(CFMutableArrayRef properties
, CFStringRef error
, bool localized
) {
1952 CFStringRef localizedError
= NULL
;
1955 } else if (localized
) {
1956 //%%% "SecCertificate" should be changed to "Certificate": rdar://37517120
1957 localizedError
= SecFrameworkCopyLocalizedString(error
, CFSTR("SecCertificate"));
1959 localizedError
= (CFStringRef
) CFRetainSafe(error
);
1961 appendProperty(properties
, kSecPropertyTypeError
, NULL
, NULL
,
1962 localizedError
, localized
);
1963 CFReleaseNull(localizedError
);
1967 /* OS X properties array has a different structure and is implemented SecTrust.cpp. */
1968 CFArrayRef
SecTrustCopyProperties_ios(SecTrustRef trust
)
1970 CFArrayRef
SecTrustCopyProperties(SecTrustRef trust
)
1976 SecTrustEvaluateIfNecessary(trust
);
1977 bool localized
= true;
1978 __block CFArrayRef details
= NULL
;
1979 dispatch_sync(trust
->_trustQueue
, ^{
1980 details
= CFRetainSafe(trust
->_details
);
1985 struct TrustFailures tf
= {};
1987 CFIndex ix
, count
= CFArrayGetCount(details
);
1988 for (ix
= 0; ix
< count
; ++ix
) {
1989 CFDictionaryRef detail
= (CFDictionaryRef
)
1990 CFArrayGetValueAtIndex(details
, ix
);
1991 /* We now have a detail dictionary for certificate at index ix, with
1992 a key value pair for each failed policy check. Let's convert it
1993 from Ro-Man form into something a Hu-Man can understand. */
1994 CFDictionaryApplyFunction(detail
, applyDetailProperty
, &tf
);
1997 CFMutableArrayRef properties
= CFArrayCreateMutable(kCFAllocatorDefault
, 0,
1998 &kCFTypeArrayCallBacks
);
1999 /* The badLinkage and unknownCritExtn failures are short circuited, since
2000 you can't recover from those errors. */
2001 if (tf
.badLinkage
) {
2002 appendError(properties
, CFSTR("Invalid certificate chain linkage."), localized
);
2003 } else if (tf
.unknownCritExtn
) {
2004 appendError(properties
, CFSTR("One or more unsupported critical extensions found."), localized
);
2006 if (tf
.untrustedAnchor
) {
2007 appendError(properties
, CFSTR("Root certificate is not trusted."), localized
);
2009 if (tf
.hostnameMismatch
) {
2010 appendError(properties
, CFSTR("Hostname mismatch."), localized
);
2012 if (tf
.policyFail
) {
2013 appendError(properties
, CFSTR("Policy requirements not met."), localized
);
2015 if (tf
.invalidCert
) {
2016 appendError(properties
, CFSTR("One or more certificates have expired or are not valid yet."), localized
);
2019 appendError(properties
, CFSTR("One or more certificates is using a weak key size."), localized
);
2022 appendError(properties
, CFSTR("One or more certificates is using a weak signature algorithm."), localized
);
2024 if (tf
.revocation
) {
2025 appendError(properties
, CFSTR("One or more certificates have been revoked."), localized
);
2029 if (CFArrayGetCount(properties
) == 0) {
2030 /* The certificate chain is trusted, return an empty plist */
2031 CFReleaseNull(properties
);
2034 CFReleaseNull(details
);
2039 static void _AppendStatusCode(CFMutableArrayRef array
, OSStatus statusCode
) {
2043 SInt32 num
= statusCode
;
2044 CFNumberRef numRef
= CFNumberCreate(NULL
, kCFNumberSInt32Type
, &num
);
2048 CFArrayAppendValue(array
, numRef
);
2053 static CFArrayRef
_SecTrustCopyDetails(SecTrustRef trust
) {
2057 __block CFArrayRef details
= NULL
;
2058 dispatch_sync(trust
->_trustQueue
, ^{
2059 details
= CFRetainSafe(trust
->_details
);
2062 // Include status codes in the per-certificate details (rdar://27930542)
2063 CFMutableArrayRef newDetails
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
2065 CFReleaseSafe(details
);
2068 CFIndex index
, chainLen
= (details
) ? CFArrayGetCount(details
) : 0;
2069 for (index
= 0; index
< chainLen
; index
++) {
2070 CFDictionaryRef detailDict
= CFArrayGetValueAtIndex(details
, index
);
2071 CFMutableDictionaryRef newDict
= CFDictionaryCreateMutableCopy(NULL
, 0, detailDict
);
2072 CFMutableArrayRef statusCodes
= CFArrayCreateMutable(kCFAllocatorDefault
,
2073 0, &kCFTypeArrayCallBacks
);
2075 CFIndex i
, numCodes
= 0;
2076 SInt32
*codes
= SecTrustCopyStatusCodes(trust
, index
, &numCodes
);
2078 for (i
= 0; i
< numCodes
; i
++) {
2079 OSStatus scode
= (OSStatus
)codes
[i
];
2080 _AppendStatusCode(statusCodes
, scode
);
2084 if (CFArrayGetCount(statusCodes
) > 0) {
2085 CFDictionarySetValue(newDict
, kSecCertificateDetailStatusCodes
, statusCodes
);
2087 CFRelease(statusCodes
);
2090 CFArrayAppendValue(newDetails
, newDict
);
2094 CFReleaseSafe(details
);
2101 CFDictionaryRef
SecTrustCopyResult(SecTrustRef trust
) {
2102 // Builds and returns a dictionary of evaluation results.
2106 __block CFMutableDictionaryRef results
= CFDictionaryCreateMutable(NULL
, 0,
2107 &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
2109 SecTrustEvaluateIfNecessary(trust
);
2110 __block CFArrayRef details
= _SecTrustCopyDetails(trust
);
2112 dispatch_sync(trust
->_trustQueue
, ^{
2113 // kSecTrustResultDetails (per-cert results)
2115 CFDictionarySetValue(results
, (const void *)kSecTrustResultDetails
, (const void *)details
);
2119 // kSecTrustResultValue (overall trust result)
2120 CFNumberRef numValue
= CFNumberCreate(NULL
, kCFNumberSInt32Type
, &trust
->_trustResult
);
2122 CFDictionarySetValue(results
, (const void *)kSecTrustResultValue
, (const void *)numValue
);
2123 CFRelease(numValue
);
2125 CFDictionaryRef info
= trust
->_info
;
2126 if (trust
->_trustResult
== kSecTrustResultInvalid
|| !info
) {
2127 return; // we have nothing more to add
2130 // kSecTrustEvaluationDate
2131 CFDateRef evaluationDate
= trust
->_verifyDate
;
2132 if (evaluationDate
) {
2133 CFDictionarySetValue(results
, (const void *)kSecTrustEvaluationDate
, (const void *)evaluationDate
);
2136 // kSecTrustCertificateTransparency
2137 CFBooleanRef ctValue
;
2138 if (CFDictionaryGetValueIfPresent(info
, kSecTrustInfoCertificateTransparencyKey
, (const void **)&ctValue
)) {
2139 CFDictionarySetValue(results
, (const void *)kSecTrustCertificateTransparency
, (const void *)ctValue
);
2142 // kSecTrustExtendedValidation
2143 CFBooleanRef evValue
;
2144 if (CFDictionaryGetValueIfPresent(info
, kSecTrustInfoExtendedValidationKey
, (const void **)&evValue
)) {
2145 CFDictionarySetValue(results
, (const void *)kSecTrustExtendedValidation
, (const void *)evValue
);
2148 // kSecTrustOrganizationName
2149 CFStringRef organizationName
;
2150 if (CFDictionaryGetValueIfPresent(info
, kSecTrustInfoCompanyNameKey
, (const void **)&organizationName
)) {
2151 CFDictionarySetValue(results
, (const void *)kSecTrustOrganizationName
, (const void *)organizationName
);
2154 // kSecTrustRevocationChecked
2155 CFBooleanRef revocationChecked
;
2156 if (CFDictionaryGetValueIfPresent(info
, kSecTrustRevocationChecked
, (const void **)&revocationChecked
)) {
2157 CFDictionarySetValue(results
, (const void *)kSecTrustRevocationChecked
, (const void *)revocationChecked
);
2160 // kSecTrustRevocationReason
2161 CFNumberRef revocationReason
;
2162 if (CFDictionaryGetValueIfPresent(info
, kSecTrustRevocationReason
, (const void **)&revocationReason
)) {
2163 CFDictionarySetValue(results
, (const void *)kSecTrustRevocationReason
, (const void *)revocationReason
);
2166 // kSecTrustRevocationValidUntilDate
2167 CFDateRef validUntilDate
;
2168 if (CFDictionaryGetValueIfPresent(info
, kSecTrustRevocationValidUntilDate
, (const void **)&validUntilDate
)) {
2169 CFDictionarySetValue(results
, (const void *)kSecTrustRevocationValidUntilDate
, (const void *)validUntilDate
);
2176 #define do_if_registered(sdp, ...) if (gTrustd && gTrustd->sdp) { return gTrustd->sdp(__VA_ARGS__); }
2178 static bool xpc_dictionary_entry_is_type(xpc_object_t dictionary
, const char *key
, xpc_type_t type
) {
2179 xpc_object_t value
= xpc_dictionary_get_value(dictionary
, key
);
2180 return value
&& (xpc_get_type(value
) == type
);
2183 static uint64_t do_ota_pki_op (enum SecXPCOperation op
, CFErrorRef
*error
) {
2185 xpc_object_t message
= securityd_create_message(op
, error
);
2187 xpc_object_t response
= securityd_message_with_reply_sync(message
, error
);
2188 if (response
&& xpc_dictionary_entry_is_type(response
, kSecXPCKeyResult
, XPC_TYPE_UINT64
)) {
2189 num
= (int64_t) xpc_dictionary_get_uint64(response
, kSecXPCKeyResult
);
2191 if (response
&& error
&& xpc_dictionary_entry_is_type(response
, kSecXPCKeyError
, XPC_TYPE_DICTIONARY
)) {
2192 xpc_object_t xpc_error
= xpc_dictionary_get_value(response
, kSecXPCKeyError
);
2194 *error
= SecCreateCFErrorWithXPCObject(xpc_error
);
2197 xpc_release_safe(message
);
2198 xpc_release_safe(response
);
2204 // version 0 -> error, so we need to start at version 1 or later.
2205 uint64_t SecTrustGetTrustStoreVersionNumber(CFErrorRef
*error
) {
2206 do_if_registered(sec_ota_pki_trust_store_version
, error
);
2208 os_activity_t activity
= os_activity_create("SecTrustGetTrustStoreVersionNumber", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_DEFAULT
);
2209 os_activity_scope(activity
);
2211 uint64_t num
= do_ota_pki_op(sec_ota_pki_trust_store_version_id
, error
);
2213 os_release(activity
);
2217 uint64_t SecTrustOTAPKIGetUpdatedAsset(CFErrorRef
*error
) {
2218 do_if_registered(sec_ota_pki_get_new_asset
, error
);
2220 os_activity_t activity
= os_activity_create("SecTrustOTAPKIGetUpdatedAsset", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_DEFAULT
);
2221 os_activity_scope(activity
);
2223 uint64_t num
= do_ota_pki_op(kSecXPCOpOTAPKIGetNewAsset
, error
);
2225 os_release(activity
);
2229 bool SecTrustReportTLSAnalytics(CFStringRef eventName
, xpc_object_t eventAttributes
, CFErrorRef
*error
) {
2230 if (!eventName
|| !eventAttributes
) {
2233 do_if_registered(sec_tls_analytics_report
, eventName
, eventAttributes
, error
);
2235 os_activity_t activity
= os_activity_create("SecTrustReportTLSAnalytics", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_DEFAULT
);
2236 os_activity_scope(activity
);
2238 __block
bool result
= false;
2239 securityd_send_sync_and_do(kSecXPCOpTLSAnaltyicsReport
, error
, ^bool(xpc_object_t message
, CFErrorRef
*block_error
) {
2240 if (!SecXPCDictionarySetString(message
, kSecTrustEventNameKey
, eventName
, block_error
)) {
2243 xpc_dictionary_set_value(message
, kSecTrustEventAttributesKey
, eventAttributes
);
2245 }, ^bool(xpc_object_t response
, CFErrorRef
*block_error
) {
2246 result
= SecXPCDictionaryGetBool(response
, kSecXPCKeyResult
, block_error
);
2250 os_release(activity
);
2255 * This function performs an evaluation of the leaf certificate only, and
2256 * does so in the process that called it. Its primary use is in SecItemCopyMatching
2257 * when kSecMatchPolicy is in the dictionary.
2259 OSStatus
SecTrustEvaluateLeafOnly(SecTrustRef trust
, SecTrustResultType
*result
) {
2263 OSStatus status
= errSecSuccess
;
2264 SecTrustResultType trustResult
= kSecTrustResultInvalid
;
2265 if((status
= SecTrustValidateInput(trust
))) {
2269 struct OpaqueSecLeafPVC pvc
;
2270 SecCertificateRef leaf
= SecTrustGetCertificateAtIndex(trust
, 0);
2271 __block CFArrayRef policies
= NULL
;
2272 dispatch_sync(trust
->_trustQueue
, ^{
2273 policies
= CFRetainSafe(trust
->_policies
);
2275 SecLeafPVCInit(&pvc
, leaf
, policies
, SecTrustGetVerifyTime(trust
));
2277 if(!SecLeafPVCLeafChecks(&pvc
)) {
2278 trustResult
= kSecTrustResultRecoverableTrustFailure
;
2280 trustResult
= kSecTrustResultUnspecified
;
2283 /* Set other result context information */
2284 dispatch_sync(trust
->_trustQueue
, ^{
2285 trust
->_trustResult
= trustResult
;
2286 trust
->_details
= CFRetainSafe(pvc
.details
);
2287 trust
->_info
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0,
2288 &kCFTypeDictionaryKeyCallBacks
,
2289 &kCFTypeDictionaryValueCallBacks
);
2290 CFMutableArrayRef leafCert
= CFArrayCreateMutableCopy(NULL
, 1, trust
->_certificates
);
2291 trust
->_chain
= leafCert
;
2294 SecLeafPVCDelete(&pvc
);
2296 /* log to syslog when there is a trust failure */
2297 if (trustResult
!= kSecTrustResultUnspecified
) {
2298 CFStringRef failureDesc
= SecTrustCopyFailureDescription(trust
);
2299 secerror("%@", failureDesc
);
2300 CFRelease(failureDesc
);
2304 *result
= trustResult
;
2307 CFReleaseSafe(policies
);
2311 static void deserializeCert(const void *value
, void *context
) {
2312 CFDataRef certData
= (CFDataRef
)value
;
2313 if (isData(certData
)) {
2314 SecCertificateRef cert
= SecCertificateCreateWithData(NULL
, certData
);
2316 CFArrayAppendValue((CFMutableArrayRef
)context
, cert
);
2322 static CF_RETURNS_RETAINED CFArrayRef
SecCertificateArrayDeserialize(CFArrayRef serializedCertificates
) {
2323 CFMutableArrayRef result
= NULL
;
2324 require_quiet(isArray(serializedCertificates
), errOut
);
2325 CFIndex count
= CFArrayGetCount(serializedCertificates
);
2326 result
= CFArrayCreateMutable(kCFAllocatorDefault
, count
, &kCFTypeArrayCallBacks
);
2327 CFRange all_certs
= { 0, count
};
2328 CFArrayApplyFunction(serializedCertificates
, all_certs
, deserializeCert
, result
);
2333 static void serializeCertificate(const void *value
, void *context
) {
2334 SecCertificateRef cert
= (SecCertificateRef
)value
;
2335 if (cert
&& SecCertificateGetTypeID() == CFGetTypeID(cert
)) {
2336 CFDataRef certData
= SecCertificateCopyData(cert
);
2338 CFArrayAppendValue((CFMutableArrayRef
)context
, certData
);
2339 CFRelease(certData
);
2344 static CF_RETURNS_RETAINED CFArrayRef
SecCertificateArraySerialize(CFArrayRef certificates
) {
2345 CFMutableArrayRef result
= NULL
;
2346 require_quiet(isArray(certificates
), errOut
);
2347 CFIndex count
= CFArrayGetCount(certificates
);
2348 result
= CFArrayCreateMutable(NULL
, count
, &kCFTypeArrayCallBacks
);
2349 CFRange all_certificates
= { 0, count
};
2350 CFArrayApplyFunction(certificates
, all_certificates
, serializeCertificate
, result
);
2355 static CFPropertyListRef
SecTrustCopyPlist(SecTrustRef trust
) {
2356 __block CFMutableDictionaryRef output
= NULL
;
2357 output
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
,
2358 &kCFTypeDictionaryValueCallBacks
);
2360 dispatch_sync(trust
->_trustQueue
, ^{
2361 if (trust
->_certificates
) {
2362 CFArrayRef serializedCerts
= SecCertificateArraySerialize(trust
->_certificates
);
2363 if (serializedCerts
) {
2364 CFDictionaryAddValue(output
, CFSTR(kSecTrustCertificatesKey
), serializedCerts
);
2365 CFRelease(serializedCerts
);
2368 if (trust
->_anchors
) {
2369 CFArrayRef serializedAnchors
= SecCertificateArraySerialize(trust
->_anchors
);
2370 if (serializedAnchors
) {
2371 CFDictionaryAddValue(output
, CFSTR(kSecTrustAnchorsKey
), serializedAnchors
);
2372 CFRelease(serializedAnchors
);
2375 if (trust
->_policies
) {
2376 CFArrayRef serializedPolicies
= SecPolicyArrayCreateSerialized(trust
->_policies
);
2377 if (serializedPolicies
) {
2378 CFDictionaryAddValue(output
, CFSTR(kSecTrustPoliciesKey
), serializedPolicies
);
2379 CFRelease(serializedPolicies
);
2382 if (trust
->_responses
) {
2383 CFDictionaryAddValue(output
, CFSTR(kSecTrustResponsesKey
), trust
->_responses
);
2386 CFDictionaryAddValue(output
, CFSTR(kSecTrustSCTsKey
), trust
->_SCTs
);
2388 if (trust
->_trustedLogs
) {
2389 CFDictionaryAddValue(output
, CFSTR(kSecTrustTrustedLogsKey
), trust
->_trustedLogs
);
2391 if (trust
->_verifyDate
) {
2392 CFDictionaryAddValue(output
, CFSTR(kSecTrustVerifyDateKey
), trust
->_verifyDate
);
2394 if (trust
->_chain
) {
2395 CFArrayRef serializedCerts
= SecCertificateArraySerialize(trust
->_chain
);
2396 if (serializedCerts
) {
2397 CFDictionaryAddValue(output
, CFSTR(kSecTrustChainKey
), serializedCerts
);
2398 CFRelease(serializedCerts
);
2401 if (trust
->_details
) {
2402 CFDictionaryAddValue(output
, CFSTR(kSecTrustDetailsKey
), trust
->_details
);
2405 CFDictionaryAddValue(output
, CFSTR(kSecTrustInfoKey
), trust
->_info
);
2407 if (trust
->_exceptions
) {
2408 CFDictionaryAddValue(output
, CFSTR(kSecTrustExceptionsKey
), trust
->_exceptions
);
2410 CFNumberRef trustResult
= CFNumberCreate(NULL
, kCFNumberSInt32Type
, &trust
->_trustResult
);
2412 CFDictionaryAddValue(output
, CFSTR(kSecTrustResultKey
), trustResult
);
2414 CFReleaseNull(trustResult
);
2415 if (trust
->_anchorsOnly
) {
2416 CFDictionaryAddValue(output
, CFSTR(kSecTrustAnchorsOnlyKey
), kCFBooleanTrue
);
2418 CFDictionaryAddValue(output
, CFSTR(kSecTrustAnchorsOnlyKey
), kCFBooleanFalse
);
2420 if (trust
->_keychainsAllowed
) {
2421 CFDictionaryAddValue(output
, CFSTR(kSecTrustKeychainsAllowedKey
), kCFBooleanTrue
);
2423 CFDictionaryAddValue(output
, CFSTR(kSecTrustKeychainsAllowedKey
), kCFBooleanFalse
);
2430 CFDataRef
SecTrustSerialize(SecTrustRef trust
, CFErrorRef
*error
) {
2431 CFPropertyListRef plist
= NULL
;
2432 CFDataRef derTrust
= NULL
;
2433 require_action_quiet(trust
, out
,
2434 SecError(errSecParam
, error
, CFSTR("null trust input")));
2435 require_action_quiet(plist
= SecTrustCopyPlist(trust
), out
,
2436 SecError(errSecDecode
, error
, CFSTR("unable to create trust plist")));
2437 require_quiet(derTrust
= CFPropertyListCreateDERData(NULL
, plist
, error
), out
);
2440 CFReleaseNull(plist
);
2444 static OSStatus
SecTrustCreateFromPlist(CFPropertyListRef plist
, SecTrustRef CF_RETURNS_RETAINED
*trust
) {
2445 OSStatus status
= errSecParam
;
2446 SecTrustRef output
= NULL
;
2447 CFTypeRef serializedCertificates
= NULL
, serializedPolicies
= NULL
, serializedAnchors
= NULL
;
2448 CFNumberRef trustResultNum
= NULL
;
2449 CFArrayRef certificates
= NULL
, policies
= NULL
, anchors
= NULL
, responses
= NULL
,
2450 SCTs
= NULL
, trustedLogs
= NULL
, details
= NULL
, exceptions
= NULL
, chain
= NULL
;
2451 CFDateRef verifyDate
= NULL
;
2452 CFDictionaryRef info
= NULL
;
2454 require_quiet(CFDictionaryGetTypeID() == CFGetTypeID(plist
), out
);
2455 require_quiet(serializedCertificates
= CFDictionaryGetValue(plist
, CFSTR(kSecTrustCertificatesKey
)), out
);
2456 require_quiet(certificates
= SecCertificateArrayDeserialize(serializedCertificates
), out
);
2457 require_quiet(serializedPolicies
= CFDictionaryGetValue(plist
, CFSTR(kSecTrustPoliciesKey
)), out
);
2458 require_quiet(policies
= SecPolicyArrayCreateDeserialized(serializedPolicies
), out
);
2459 require_noerr_quiet(status
= SecTrustCreateWithCertificates(certificates
, policies
, &output
), out
);
2461 serializedAnchors
= CFDictionaryGetValue(plist
, CFSTR(kSecTrustAnchorsKey
));
2462 if (isArray(serializedAnchors
)) {
2463 anchors
= SecCertificateArrayDeserialize(serializedAnchors
);
2464 output
->_anchors
= anchors
;
2466 responses
= CFDictionaryGetValue(plist
, CFSTR(kSecTrustResponsesKey
));
2467 if (isArray(responses
)) {
2468 output
->_responses
= CFRetainSafe(responses
);
2470 SCTs
= CFDictionaryGetValue(plist
, CFSTR(kSecTrustSCTsKey
));
2471 if (isArray(responses
)) {
2472 output
->_SCTs
= CFRetainSafe(SCTs
);
2474 trustedLogs
= CFDictionaryGetValue(plist
, CFSTR(kSecTrustTrustedLogsKey
));
2475 if (isArray(trustedLogs
)) {
2476 output
->_trustedLogs
= CFRetainSafe(trustedLogs
);
2478 verifyDate
= CFDictionaryGetValue(plist
, CFSTR(kSecTrustVerifyDateKey
));
2479 if (isDate(verifyDate
)) {
2480 output
->_verifyDate
= CFRetainSafe(verifyDate
);
2482 chain
= CFDictionaryGetValue(plist
, CFSTR(kSecTrustChainKey
));
2483 if (isArray(chain
)) {
2484 output
->_chain
= SecCertificateArrayDeserialize(chain
);
2486 details
= CFDictionaryGetValue(plist
, CFSTR(kSecTrustDetailsKey
));
2487 if (isArray(details
)) {
2488 output
->_details
= CFRetainSafe(details
);
2490 info
= CFDictionaryGetValue(plist
, CFSTR(kSecTrustInfoKey
));
2491 if (isDictionary(info
)) {
2492 output
->_info
= CFRetainSafe(info
);
2494 exceptions
= CFDictionaryGetValue(plist
, CFSTR(kSecTrustExceptionsKey
));
2495 if (isArray(exceptions
)) {
2496 output
->_exceptions
= CFRetainSafe(exceptions
);
2498 int32_t trustResult
= -1;
2499 trustResultNum
= CFDictionaryGetValue(plist
, CFSTR(kSecTrustResultKey
));
2500 if (isNumber(trustResultNum
) && CFNumberGetValue(trustResultNum
, kCFNumberSInt32Type
, &trustResult
) &&
2501 (trustResult
>= 0)) {
2502 output
->_trustResult
= trustResult
;
2504 status
= errSecParam
;
2506 if (CFDictionaryGetValue(plist
, CFSTR(kSecTrustAnchorsOnlyKey
)) == kCFBooleanTrue
) {
2507 output
->_anchorsOnly
= true;
2508 } /* false is set by default */
2509 if (CFDictionaryGetValue(plist
, CFSTR(kSecTrustKeychainsAllowedKey
)) == kCFBooleanFalse
) {
2510 output
->_keychainsAllowed
= false;
2511 } /* true is set by default */
2514 if (errSecSuccess
== status
&& trust
) {
2517 CFReleaseNull(policies
);
2518 CFReleaseNull(certificates
);
2522 SecTrustRef
SecTrustDeserialize(CFDataRef serializedTrust
, CFErrorRef
*error
) {
2523 SecTrustRef trust
= NULL
;
2524 CFPropertyListRef plist
= NULL
;
2525 OSStatus status
= errSecSuccess
;
2526 require_action_quiet(serializedTrust
, out
,
2527 SecError(errSecParam
, error
, CFSTR("null serialized trust input")));
2528 require_quiet(plist
= CFPropertyListCreateWithDERData(NULL
, serializedTrust
,
2529 kCFPropertyListImmutable
, NULL
, error
), out
);
2530 require_noerr_action_quiet(status
= SecTrustCreateFromPlist(plist
, &trust
), out
,
2531 SecError(status
, error
, CFSTR("unable to create trust ref")));
2534 CFReleaseNull(plist
);