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
);
151 static void SecTrustEvaluateIfNecessaryFastAsync(SecTrustRef trust
,
152 dispatch_queue_t queue
,
153 void (^handler
)(OSStatus status
));
155 /* Static functions. */
156 static CFStringRef
SecTrustCopyFormatDescription(CFTypeRef cf
, CFDictionaryRef formatOptions
) {
157 SecTrustRef trust
= (SecTrustRef
)cf
;
158 return CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
,
159 CFSTR("<SecTrustRef: %p>"), trust
);
162 static void SecTrustDestroy(CFTypeRef cf
) {
163 SecTrustRef trust
= (SecTrustRef
)cf
;
165 dispatch_release_null(trust
->_trustQueue
);
166 CFReleaseNull(trust
->_certificates
);
167 CFReleaseNull(trust
->_policies
);
168 CFReleaseNull(trust
->_responses
);
169 CFReleaseNull(trust
->_SCTs
);
170 CFReleaseNull(trust
->_trustedLogs
);
171 CFReleaseNull(trust
->_verifyDate
);
172 CFReleaseNull(trust
->_anchors
);
173 CFReleaseNull(trust
->_chain
);
174 CFReleaseNull(trust
->_publicKey
);
175 CFReleaseNull(trust
->_details
);
176 CFReleaseNull(trust
->_info
);
177 CFReleaseNull(trust
->_exceptions
);
179 if (trust
->_legacy_info_array
) {
180 free(trust
->_legacy_info_array
);
182 if (trust
->_legacy_status_array
) {
183 free(trust
->_legacy_status_array
);
187 /* Public API functions. */
188 CFGiblisFor(SecTrust
)
190 OSStatus
SecTrustCreateWithCertificates(CFTypeRef certificates
,
191 CFTypeRef policies
, SecTrustRef
*trust
) {
192 OSStatus status
= errSecParam
;
193 CFAllocatorRef allocator
= kCFAllocatorDefault
;
194 CFArrayRef l_certs
= NULL
, l_policies
= NULL
;
195 SecTrustRef result
= NULL
;
196 dispatch_queue_t queue
= NULL
;
200 CFTypeID certType
= CFGetTypeID(certificates
);
201 if (certType
== CFArrayGetTypeID()) {
202 CFIndex idx
, count
= CFArrayGetCount(certificates
);
203 /* We need at least 1 certificate. */
204 require_quiet(count
> 0, errOut
);
205 l_certs
= (CFArrayRef
) CFArrayCreateMutable(allocator
, count
,
206 &kCFTypeArrayCallBacks
);
208 status
= errSecAllocate
;
211 for (idx
= 0; idx
< count
; idx
++) {
212 CFTypeRef val
= CFArrayGetValueAtIndex(certificates
, idx
);
213 if (val
) { CFArrayAppendValue((CFMutableArrayRef
)l_certs
, val
); }
215 require_quiet(count
== CFArrayGetCount(l_certs
), errOut
);
216 } else if (certType
== SecCertificateGetTypeID()) {
217 l_certs
= CFArrayCreate(allocator
, &certificates
, 1,
218 &kCFTypeArrayCallBacks
);
223 status
= errSecAllocate
;
228 CFTypeRef policy
= SecPolicyCreateBasicX509();
229 l_policies
= CFArrayCreate(allocator
, &policy
, 1,
230 &kCFTypeArrayCallBacks
);
233 else if (CFGetTypeID(policies
) == CFArrayGetTypeID()) {
234 CFIndex idx
, count
= CFArrayGetCount(policies
);
235 /* We need at least 1 policy. */
236 require_quiet(count
> 0, errOut
);
237 l_policies
= (CFArrayRef
) CFArrayCreateMutable(allocator
, count
,
238 &kCFTypeArrayCallBacks
);
240 status
= errSecAllocate
;
243 for (idx
= 0; idx
< count
; idx
++) {
244 CFTypeRef val
= CFArrayGetValueAtIndex(policies
, idx
);
245 if (val
) { CFArrayAppendValue((CFMutableArrayRef
)l_policies
, val
); }
247 require_quiet(count
== CFArrayGetCount(l_policies
), errOut
);
249 else if (CFGetTypeID(policies
) == SecPolicyGetTypeID()) {
250 l_policies
= CFArrayCreate(allocator
, &policies
, 1,
251 &kCFTypeArrayCallBacks
);
256 status
= errSecAllocate
;
260 queue
= dispatch_queue_create("trust", DISPATCH_QUEUE_SERIAL
);
262 status
= errSecAllocate
;
266 CFIndex size
= sizeof(struct __SecTrust
);
267 require_quiet(result
= (SecTrustRef
)_CFRuntimeCreateInstance(allocator
,
268 SecTrustGetTypeID(), size
- sizeof(CFRuntimeBase
), 0), errOut
);
269 memset((char*)result
+ sizeof(result
->_base
), 0,
270 sizeof(*result
) - sizeof(result
->_base
));
271 status
= errSecSuccess
;
275 CFReleaseSafe(result
);
276 CFReleaseSafe(l_certs
);
277 CFReleaseSafe(l_policies
);
278 dispatch_release_null(queue
);
280 result
->_certificates
= l_certs
;
281 result
->_policies
= l_policies
;
282 result
->_keychainsAllowed
= true;
283 result
->_trustQueue
= queue
;
287 CFReleaseSafe(result
);
292 OSStatus
SecTrustCopyInputCertificates(SecTrustRef trust
, CFArrayRef
*certificates
) {
293 if (!trust
|| !certificates
) {
296 __block CFArrayRef certArray
= NULL
;
297 dispatch_sync(trust
->_trustQueue
, ^{
298 certArray
= CFArrayCreateCopy(NULL
, trust
->_certificates
);
301 return errSecAllocate
;
303 *certificates
= certArray
;
304 return errSecSuccess
;
307 OSStatus
SecTrustAddToInputCertificates(SecTrustRef trust
, CFTypeRef certificates
) {
308 if (!trust
|| !certificates
) {
311 __block CFMutableArrayRef newCertificates
= NULL
;
312 dispatch_sync(trust
->_trustQueue
, ^{
313 newCertificates
= CFArrayCreateMutableCopy(NULL
, 0, trust
->_certificates
);
316 if (isArray(certificates
)) {
317 CFArrayAppendArray(newCertificates
, certificates
,
318 CFRangeMake(0, CFArrayGetCount(certificates
)));
319 } else if (CFGetTypeID(certificates
) == SecCertificateGetTypeID()) {
320 CFArrayAppendValue(newCertificates
, certificates
);
322 CFReleaseNull(newCertificates
);
326 dispatch_sync(trust
->_trustQueue
, ^{
327 CFReleaseNull(trust
->_certificates
);
328 trust
->_certificates
= (CFArrayRef
)newCertificates
;
331 return errSecSuccess
;
334 void SecTrustSetNeedsEvaluation(SecTrustRef trust
) {
337 dispatch_sync(trust
->_trustQueue
, ^{
338 trust
->_trustResult
= kSecTrustResultInvalid
;
343 OSStatus
SecTrustSetAnchorCertificatesOnly(SecTrustRef trust
,
344 Boolean anchorCertificatesOnly
) {
348 SecTrustSetNeedsEvaluation(trust
);
349 trust
->_anchorsOnly
= anchorCertificatesOnly
;
351 return errSecSuccess
;
354 OSStatus
SecTrustSetAnchorCertificates(SecTrustRef trust
,
355 CFArrayRef anchorCertificates
) {
359 SecTrustSetNeedsEvaluation(trust
);
360 __block CFArrayRef anchorsArray
= NULL
;
361 if (anchorCertificates
) {
362 if (CFGetTypeID(anchorCertificates
) == CFArrayGetTypeID()) {
363 CFIndex idx
, count
= CFArrayGetCount(anchorCertificates
);
364 anchorsArray
= (CFArrayRef
) CFArrayCreateMutable(NULL
, count
,
365 &kCFTypeArrayCallBacks
);
367 return errSecAllocate
;
369 for (idx
= 0; idx
< count
; idx
++) {
370 CFTypeRef val
= CFArrayGetValueAtIndex(anchorCertificates
, idx
);
371 if (val
) { CFArrayAppendValue((CFMutableArrayRef
)anchorsArray
, val
); }
373 if (count
!= CFArrayGetCount(anchorsArray
)) {
374 CFReleaseSafe(anchorsArray
);
382 dispatch_sync(trust
->_trustQueue
, ^{
383 CFReleaseSafe(trust
->_anchors
);
384 trust
->_anchors
= anchorsArray
;
386 trust
->_anchorsOnly
= (anchorCertificates
!= NULL
);
388 return errSecSuccess
;
391 OSStatus
SecTrustCopyCustomAnchorCertificates(SecTrustRef trust
,
392 CFArrayRef
*anchors
) {
393 if (!trust
|| !anchors
) {
396 __block CFArrayRef anchorsArray
= NULL
;
397 dispatch_sync(trust
->_trustQueue
, ^{
398 if (trust
->_anchors
) {
399 anchorsArray
= CFArrayCreateCopy(kCFAllocatorDefault
, trust
->_anchors
);
403 *anchors
= anchorsArray
;
404 return errSecSuccess
;
407 // Return false on error, true on success.
408 static bool to_bool_error_request(enum SecXPCOperation op
, CFErrorRef
*error
) {
409 __block
bool result
= false;
410 securityd_send_sync_and_do(op
, error
, NULL
, ^bool(xpc_object_t response
, CFErrorRef
*error
) {
411 result
= !(error
&& *error
);
417 Boolean
SecTrustFlushResponseCache(CFErrorRef
*error
) {
418 CFErrorRef localError
= NULL
;
419 os_activity_t activity
= os_activity_create("SecTrustFlushResponseCache", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_DEFAULT
);
420 os_activity_scope(activity
);
421 bool result
= TRUSTD_XPC(sec_ocsp_cache_flush
, to_bool_error_request
, &localError
);
422 os_release(activity
);
425 } else if (localError
) {
426 CFRelease(localError
);
431 OSStatus
SecTrustSetOCSPResponse(SecTrustRef trust
, CFTypeRef responseData
) {
435 SecTrustSetNeedsEvaluation(trust
);
436 __block CFArrayRef responseArray
= NULL
;
438 if (CFGetTypeID(responseData
) == CFArrayGetTypeID()) {
439 CFIndex idx
, count
= CFArrayGetCount(responseData
);
440 responseArray
= (CFArrayRef
) CFArrayCreateMutable(NULL
, count
,
441 &kCFTypeArrayCallBacks
);
442 if (!responseArray
) {
443 return errSecAllocate
;
445 for (idx
= 0; idx
< count
; idx
++) {
446 CFTypeRef val
= CFArrayGetValueAtIndex(responseData
, idx
);
447 if (val
) { CFArrayAppendValue((CFMutableArrayRef
)responseArray
, val
); }
449 if (count
!= CFArrayGetCount(responseArray
)) {
450 CFReleaseSafe(responseArray
);
453 } else if (CFGetTypeID(responseData
) == CFDataGetTypeID()) {
454 responseArray
= CFArrayCreate(kCFAllocatorDefault
, &responseData
, 1,
455 &kCFTypeArrayCallBacks
);
461 dispatch_sync(trust
->_trustQueue
, ^{
462 CFReleaseSafe(trust
->_responses
);
463 trust
->_responses
= responseArray
;
466 return errSecSuccess
;
469 OSStatus
SecTrustSetSignedCertificateTimestamps(SecTrustRef trust
, CFArrayRef sctArray
) {
473 SecTrustSetNeedsEvaluation(trust
);
474 dispatch_sync(trust
->_trustQueue
, ^{
475 CFRetainAssign(trust
->_SCTs
, sctArray
);
477 return errSecSuccess
;
480 OSStatus
SecTrustSetTrustedLogs(SecTrustRef trust
, CFArrayRef trustedLogs
) {
484 SecTrustSetNeedsEvaluation(trust
);
485 dispatch_sync(trust
->_trustQueue
, ^{
486 CFRetainAssign(trust
->_trustedLogs
, trustedLogs
);
488 return errSecSuccess
;
491 OSStatus
SecTrustSetVerifyDate(SecTrustRef trust
, CFDateRef verifyDate
) {
495 SecTrustSetNeedsEvaluation(trust
);
497 dispatch_sync(trust
->_trustQueue
, ^{
498 CFRetainAssign(trust
->_verifyDate
, verifyDate
);
500 return errSecSuccess
;
503 OSStatus
SecTrustSetPolicies(SecTrustRef trust
, CFTypeRef newPolicies
) {
504 if (!trust
|| !newPolicies
) {
507 SecTrustSetNeedsEvaluation(trust
);
510 __block CFArrayRef policyArray
= NULL
;
511 if (CFGetTypeID(newPolicies
) == CFArrayGetTypeID()) {
512 CFIndex idx
, count
= CFArrayGetCount(newPolicies
);
513 /* We need at least 1 policy. */
517 policyArray
= (CFArrayRef
) CFArrayCreateMutable(NULL
, count
,
518 &kCFTypeArrayCallBacks
);
520 return errSecAllocate
;
522 for (idx
= 0; idx
< count
; idx
++) {
523 CFTypeRef val
= CFArrayGetValueAtIndex(newPolicies
, idx
);
524 if (val
) { CFArrayAppendValue((CFMutableArrayRef
)policyArray
, val
); }
526 if (count
!= CFArrayGetCount(policyArray
)) {
527 CFReleaseSafe(policyArray
);
530 } else if (CFGetTypeID(newPolicies
) == SecPolicyGetTypeID()) {
531 policyArray
= CFArrayCreate(kCFAllocatorDefault
, &newPolicies
, 1,
532 &kCFTypeArrayCallBacks
);
537 dispatch_sync(trust
->_trustQueue
, ^{
538 CFReleaseSafe(trust
->_policies
);
539 trust
->_policies
= policyArray
;
542 return errSecSuccess
;
545 OSStatus
SecTrustSetPinningPolicyName(SecTrustRef trust
, CFStringRef policyName
) {
546 if (!trust
|| !policyName
) {
550 SecTrustSetNeedsEvaluation(trust
);
552 dispatch_sync(trust
->_trustQueue
, ^{
553 CFArrayForEach(trust
->_policies
, ^(const void *value
) {
554 SecPolicyRef policy
= (SecPolicyRef
)value
;
555 SecPolicySetName(policy
, policyName
);
556 secinfo("SecPinningDb", "Set %@ as name on all policies", policyName
);
559 return errSecSuccess
;
562 OSStatus
SecTrustSetKeychainsAllowed(SecTrustRef trust
, Boolean allowed
) {
566 SecTrustSetNeedsEvaluation(trust
);
567 trust
->_keychainsAllowed
= allowed
;
569 return errSecSuccess
;
572 OSStatus
SecTrustGetKeychainsAllowed(SecTrustRef trust
, Boolean
*allowed
) {
573 if (!trust
|| !allowed
) {
576 *allowed
= trust
->_keychainsAllowed
;
578 return errSecSuccess
;
581 OSStatus
SecTrustCopyPolicies(SecTrustRef trust
, CFArrayRef
*policies
) {
582 if (!trust
|| !policies
) {
585 __block CFArrayRef policyArray
= NULL
;
586 dispatch_sync(trust
->_trustQueue
, ^{
587 policyArray
= CFArrayCreateCopy(kCFAllocatorDefault
, trust
->_policies
);
590 return errSecAllocate
;
592 *policies
= policyArray
;
593 return errSecSuccess
;
596 static OSStatus
SecTrustSetOptionInPolicies(CFArrayRef policies
, CFStringRef key
, CFTypeRef value
) {
597 OSStatus status
= errSecSuccess
;
598 require_action(policies
&& CFGetTypeID(policies
) == CFArrayGetTypeID(), out
, status
= errSecInternal
);
599 for (int i
=0; i
< CFArrayGetCount(policies
); i
++) {
600 SecPolicyRef policy
= NULL
;
601 require_action_quiet(policy
= (SecPolicyRef
)CFArrayGetValueAtIndex(policies
, i
), out
, status
= errSecInternal
);
602 CFMutableDictionaryRef options
= NULL
;
603 require_action_quiet(options
= CFDictionaryCreateMutableCopy(NULL
, 0, policy
->_options
), out
, status
= errSecAllocate
);
604 CFDictionarySetValue(options
, key
, value
);
605 CFReleaseNull(policy
->_options
);
606 policy
->_options
= options
;
612 static OSStatus
SecTrustRemoveOptionInPolicies(CFArrayRef policies
, CFStringRef key
) {
613 OSStatus status
= errSecSuccess
;
614 require_action(policies
&& CFGetTypeID(policies
) == CFArrayGetTypeID(), out
, status
= errSecInternal
);
615 for (int i
=0; i
< CFArrayGetCount(policies
); i
++) {
616 SecPolicyRef policy
= NULL
;
617 require_action_quiet(policy
= (SecPolicyRef
)CFArrayGetValueAtIndex(policies
, i
), out
, status
= errSecInternal
);
618 if (CFDictionaryGetValue(policy
->_options
, key
)) {
619 CFMutableDictionaryRef options
= NULL
;
620 require_action_quiet(options
= CFDictionaryCreateMutableCopy(NULL
, 0, policy
->_options
), out
, status
= errSecAllocate
);
621 CFDictionaryRemoveValue(options
, key
);
622 CFReleaseNull(policy
->_options
);
623 policy
->_options
= options
;
630 static CF_RETURNS_RETAINED CFArrayRef
SecTrustCopyOptionsFromPolicies(CFArrayRef policies
, CFStringRef key
) {
631 CFMutableArrayRef foundValues
= NULL
;
632 foundValues
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
633 for (int i
=0; i
< CFArrayGetCount(policies
); i
++) {
634 SecPolicyRef policy
= (SecPolicyRef
)CFArrayGetValueAtIndex(policies
, i
);
635 CFTypeRef value
= CFDictionaryGetValue(policy
->_options
, key
);
637 CFArrayAppendValue(foundValues
, value
);
640 if (!CFArrayGetCount(foundValues
)) {
641 CFReleaseNull(foundValues
);
649 /* The only effective way to disable network fetch is within the policy options:
650 * presence of the kSecPolicyCheckNoNetworkAccess key in any of the policies
651 * will prevent network access for fetching.
652 * The current SecTrustServer implementation doesn't distinguish between network
653 * access for revocation and network access for fetching.
655 OSStatus
SecTrustSetNetworkFetchAllowed(SecTrustRef trust
, Boolean allowFetch
) {
659 __block OSStatus status
= errSecSuccess
;
660 __block
bool oldAllowFetch
= true;
661 dispatch_sync(trust
->_trustQueue
, ^{
662 CFArrayRef foundValues
= SecTrustCopyOptionsFromPolicies(trust
->_policies
, kSecPolicyCheckNoNetworkAccess
);
664 /* We only disable fetch if there is a policy option set for NoNetworkAccess, so the old fetch
665 * status was false (don't allow network) if we find this option set in the policies. */
666 oldAllowFetch
= false;
667 CFReleaseNull(foundValues
);
670 status
= SecTrustSetOptionInPolicies(trust
->_policies
, kSecPolicyCheckNoNetworkAccess
, kCFBooleanTrue
);
672 status
= SecTrustRemoveOptionInPolicies(trust
->_policies
, kSecPolicyCheckNoNetworkAccess
);
675 /* If we switched from NoNetworkAccess to allowing access, we need to re-run the trust evaluation */
676 if (allowFetch
&& !oldAllowFetch
) {
677 SecTrustSetNeedsEvaluation(trust
);
682 OSStatus
SecTrustGetNetworkFetchAllowed(SecTrustRef trust
, Boolean
*allowFetch
) {
683 if (!trust
|| !allowFetch
) {
686 __block CFArrayRef foundValues
= NULL
;
687 dispatch_sync(trust
->_trustQueue
, ^{
688 foundValues
= SecTrustCopyOptionsFromPolicies(trust
->_policies
, kSecPolicyCheckNoNetworkAccess
);
695 CFReleaseNull(foundValues
);
696 return errSecSuccess
;
699 OSStatus
SecTrustSetPinningException(SecTrustRef trust
) {
700 if (!trust
) { return errSecParam
; }
701 __block OSStatus status
= errSecSuccess
;
702 dispatch_sync(trust
->_trustQueue
, ^{
703 status
= SecTrustRemoveOptionInPolicies(trust
->_policies
, kSecPolicyCheckPinningRequired
);
708 CFAbsoluteTime
SecTrustGetVerifyTime(SecTrustRef trust
) {
709 __block CFAbsoluteTime verifyTime
= CFAbsoluteTimeGetCurrent();
713 dispatch_sync(trust
->_trustQueue
, ^{
714 if (trust
->_verifyDate
) {
715 verifyTime
= CFDateGetAbsoluteTime(trust
->_verifyDate
);
717 trust
->_verifyDate
= CFDateCreate(CFGetAllocator(trust
), verifyTime
);
724 CFArrayRef
SecTrustGetDetails(SecTrustRef trust
) {
728 SecTrustEvaluateIfNecessary(trust
);
729 return trust
->_details
;
732 OSStatus
SecTrustGetTrustResult(SecTrustRef trust
,
733 SecTrustResultType
*result
) {
734 if (!trust
|| !result
) {
737 SecTrustEvaluateIfNecessary(trust
);
738 dispatch_sync(trust
->_trustQueue
, ^{
739 *result
= trust
->_trustResult
;
741 return errSecSuccess
;
744 static CFDictionaryRef
SecTrustGetExceptionForCertificateAtIndex(SecTrustRef trust
, CFIndex ix
) {
745 CFDictionaryRef exception
= NULL
;
746 __block CFArrayRef exceptions
= NULL
;
747 dispatch_sync(trust
->_trustQueue
, ^{
748 exceptions
= CFRetainSafe(trust
->_exceptions
);
750 if (!exceptions
|| ix
>= CFArrayGetCount(exceptions
)) {
754 SecCertificateRef certificate
= SecTrustGetCertificateAtIndex(trust
, ix
);
759 exception
= (CFDictionaryRef
)CFArrayGetValueAtIndex(exceptions
, ix
);
760 if (CFGetTypeID(exception
) != CFDictionaryGetTypeID()) {
765 /* If the exception contains the current certificates sha1Digest in the
766 kSecCertificateDetailSHA1Digest key then we use it otherwise we ignore it. */
767 CFDataRef sha1Digest
= SecCertificateGetSHA1Digest(certificate
);
768 CFTypeRef digestValue
= CFDictionaryGetValue(exception
, kSecCertificateDetailSHA1Digest
);
769 if (!digestValue
|| !CFEqual(sha1Digest
, digestValue
))
773 CFReleaseSafe(exceptions
);
777 CFArrayRef
SecTrustCopyFilteredDetails(SecTrustRef trust
) {
781 SecTrustEvaluateIfNecessary(trust
);
782 __block CFArrayRef details
= NULL
;
783 dispatch_sync(trust
->_trustQueue
, ^{
784 details
= CFRetainSafe(trust
->_details
);
787 /* Done automatically by the Policy Server with SecPVCIsExceptedError */
791 Boolean
SecTrustIsExpiredOnly(SecTrustRef trust
) {
792 /* Returns true if one or more certificates in the chain have expired,
793 * expiration is an error (i.e. is not covered by existing trust settings),
794 * and it is the only error encountered.
795 * Returns false if the certificate is valid, or if the trust chain has
796 * other errors beside expiration.
798 Boolean result
= false;
799 Boolean foundExpired
= false;
800 CFArrayRef details
= SecTrustCopyFilteredDetails(trust
);
801 require(details
!= NULL
, out
);
803 CFIndex ix
, pathLength
= CFArrayGetCount(details
);
804 for (ix
= 0; ix
< pathLength
; ++ix
) {
805 CFDictionaryRef detail
= (CFDictionaryRef
)CFArrayGetValueAtIndex(details
, ix
);
806 CFIndex count
= (detail
) ? CFDictionaryGetCount(detail
) : 0;
807 require(count
<= 1, out
);
809 CFBooleanRef valid
= (CFBooleanRef
)CFDictionaryGetValue(detail
, kSecPolicyCheckTemporalValidity
);
810 require(isBoolean(valid
) && CFEqual(valid
, kCFBooleanFalse
), out
);
814 result
= foundExpired
;
816 CFReleaseSafe(details
);
821 static CFArrayRef
SecTrustCreatePolicyAnchorsArray(const UInt8
* certData
, CFIndex certLength
)
823 CFArrayRef array
= NULL
;
824 CFAllocatorRef allocator
= kCFAllocatorDefault
;
825 SecCertificateRef cert
= SecCertificateCreateWithBytes(allocator
, certData
, certLength
);
827 array
= CFArrayCreate(allocator
, (const void **)&cert
, 1, &kCFTypeArrayCallBacks
);
834 static void SecTrustAddPolicyAnchors(SecTrustRef trust
)
836 /* Provide anchor certificates specifically required by certain policies.
837 This is used to evaluate test policies where the anchor is not provided
838 in the root store and may not be able to be supplied by the caller.
840 if (!trust
) { return; }
841 __block CFArrayRef policies
= NULL
;
842 dispatch_sync(trust
->_trustQueue
, ^{
843 policies
= CFRetain(trust
->_policies
);
845 CFIndex ix
, count
= CFArrayGetCount(policies
);
846 for (ix
= 0; ix
< count
; ++ix
) {
847 SecPolicyRef policy
= (SecPolicyRef
) CFArrayGetValueAtIndex(policies
, ix
);
850 if (CFEqual(policy
->_oid
, kSecPolicyAppleTestSMPEncryption
)) {
851 __block CFArrayRef policyAnchors
= SecTrustCreatePolicyAnchorsArray(_SEC_TestAppleRootCAECC
, sizeof(_SEC_TestAppleRootCAECC
));
852 dispatch_sync(trust
->_trustQueue
, ^{
853 CFReleaseSafe(trust
->_anchors
);
854 trust
->_anchors
= policyAnchors
;
856 trust
->_anchorsOnly
= true;
862 CFReleaseSafe(policies
);
865 // uncomment for verbose debug logging (debug builds only)
866 //#define CERT_TRUST_DUMP 1
869 static void sectrustlog(int priority
, const char *format
, ...)
874 if (priority
< LOG_NOTICE
) // log warnings and errors
878 va_start(list
, format
);
879 vsyslog(priority
, format
, list
);
884 static void sectrustshow(CFTypeRef obj
, const char *context
)
887 CFStringRef desc
= CFCopyDescription(obj
);
890 CFIndex length
= CFStringGetMaximumSizeForEncoding(CFStringGetLength(desc
), kCFStringEncodingUTF8
) + 1;
891 char* buffer
= (char*) malloc(length
);
893 Boolean converted
= CFStringGetCString(desc
, buffer
, length
, kCFStringEncodingUTF8
);
895 const char *prefix
= (context
) ? context
: "";
896 const char *separator
= (context
) ? " " : "";
897 sectrustlog(LOG_NOTICE
, "%s%s%s", prefix
, separator
, buffer
);
905 static void cert_trust_dump(SecTrustRef trust
) {
906 SecCertificateRef leaf
= SecTrustGetCertificateAtIndex(trust
, 0);
907 CFStringRef name
= (leaf
) ? SecCertificateCopySubjectSummary(leaf
) : NULL
;
908 secerror("leaf \"%@\"", name
);
909 secerror(": result = %d", (int) trust
->_trustResult
);
911 CFIndex ix
, count
= CFArrayGetCount(trust
->_chain
);
912 CFMutableArrayRef chain
= CFArrayCreateMutable(kCFAllocatorDefault
, count
, &kCFTypeArrayCallBacks
);
913 for (ix
= 0; ix
< count
; ix
++) {
914 SecCertificateRef cert
= (SecCertificateRef
)CFArrayGetValueAtIndex(trust
->_chain
, ix
);
916 CFArrayAppendValue(chain
, cert
);
919 sectrustshow(chain
, "chain:");
920 CFReleaseSafe(chain
);
922 secerror(": %ld certificates, %ld anchors, %ld policies, %ld details",
923 (trust
->_certificates
) ? (long)CFArrayGetCount(trust
->_certificates
) : 0,
924 (trust
->_anchors
) ? (long)CFArrayGetCount(trust
->_anchors
) : 0,
925 (trust
->_policies
) ? (long)CFArrayGetCount(trust
->_policies
) : 0,
926 (trust
->_details
) ? (long)CFArrayGetCount(trust
->_details
) : 0);
928 sectrustshow(trust
->_verifyDate
, "verify date:");
929 sectrustshow(trust
->_certificates
, "certificates:");
930 sectrustshow(trust
->_anchors
, "anchors:");
931 sectrustshow(trust
->_policies
, "policies:");
932 sectrustshow(trust
->_details
, "details:");
933 sectrustshow(trust
->_info
, "info:");
938 static void cert_trust_dump(SecTrustRef trust
) {}
942 OSStatus
SecTrustEvaluate(SecTrustRef trust
, SecTrustResultType
*result
) {
944 *result
= kSecTrustResultInvalid
;
949 OSStatus status
= SecTrustEvaluateIfNecessary(trust
);
953 /* post-process trust result based on exceptions */
954 __block SecTrustResultType trustResult
= kSecTrustResultInvalid
;
955 dispatch_sync(trust
->_trustQueue
, ^{
956 trustResult
= trust
->_trustResult
;
959 /* log to syslog when there is a trust failure */
960 if (trustResult
!= kSecTrustResultProceed
&&
961 trustResult
!= kSecTrustResultUnspecified
) {
962 CFStringRef failureDesc
= SecTrustCopyFailureDescription(trust
);
963 secerror("Trust evaluate failure:%{public}@", failureDesc
);
964 CFRelease(failureDesc
);
969 *result
= trustResult
;
975 static CFStringRef
SecTrustCopyChainSummary(SecTrustRef trust
) {
976 CFMutableStringRef summary
= CFStringCreateMutable(NULL
, 0);
977 __block CFArrayRef chain
= NULL
;
978 dispatch_sync(trust
->_trustQueue
, ^{
979 chain
= trust
->_chain
;
981 CFIndex ix
, count
= CFArrayGetCount(chain
);
982 for (ix
= 0; ix
< count
; ix
++) {
983 if (ix
!= 0) { CFStringAppend(summary
, CFSTR(",")); }
984 CFStringRef certSummary
= SecCertificateCopySubjectSummary((SecCertificateRef
)CFArrayGetValueAtIndex(chain
, ix
));
985 CFStringAppendFormat(summary
, NULL
, CFSTR("\"%@\""), certSummary
);
986 CFReleaseNull(certSummary
);
992 kSecTrustErrorSubTypeBlocked
,
993 kSecTrustErrorSubTypeRevoked
,
994 kSecTrustErrorSubTypeKeySize
,
995 kSecTrustErrorSubTypeWeakHash
,
996 kSecTrustErrorSubTypeDenied
,
997 kSecTrustErrorSubTypeCompliance
,
998 kSecTrustErrorSubTypePinning
,
999 kSecTrustErrorSubTypeTrust
,
1000 kSecTrustErrorSubTypeUsage
,
1001 kSecTrustErrorSubTypeName
,
1002 kSecTrustErrorSubTypeExpired
,
1003 kSecTrustErrorSubTypeInvalid
,
1004 } SecTrustErrorSubType
;
1006 #define SecCopyTrustString(KEY) SecFrameworkCopyLocalizedString(KEY, CFSTR("Trust"))
1008 struct checkmap_entry_s
{
1009 SecTrustErrorSubType type
;
1011 const CFStringRef errorKey
;
1014 typedef struct checkmap_entry_s checkmap_entry_t
;
1016 const checkmap_entry_t checkmap
[] = {
1017 #undef POLICYCHECKMACRO
1018 #define __PC_SUBTYPE_ kSecTrustErrorSubTypeInvalid
1019 #define __PC_SUBTYPE_N kSecTrustErrorSubTypeName
1020 #define __PC_SUBTYPE_E kSecTrustErrorSubTypeExpired
1021 #define __PC_SUBTYPE_S kSecTrustErrorSubTypeKeySize
1022 #define __PC_SUBTYPE_H kSecTrustErrorSubTypeWeakHash
1023 #define __PC_SUBTYPE_U kSecTrustErrorSubTypeUsage
1024 #define __PC_SUBTYPE_P kSecTrustErrorSubTypePinning
1025 #define __PC_SUBTYPE_V kSecTrustErrorSubTypeRevoked
1026 #define __PC_SUBTYPE_T kSecTrustErrorSubTypeTrust
1027 #define __PC_SUBTYPE_C kSecTrustErrorSubTypeCompliance
1028 #define __PC_SUBTYPE_D kSecTrustErrorSubTypeDenied
1029 #define __PC_SUBTYPE_B kSecTrustErrorSubTypeBlocked
1030 #define POLICYCHECKMACRO(NAME, TRUSTRESULT, SUBTYPE, LEAFCHECK, PATHCHECK, LEAFONLY, CSSMERR, OSSTATUS) \
1031 { __PC_SUBTYPE_##SUBTYPE , OSSTATUS, SEC_TRUST_ERROR_##NAME },
1032 #include "SecPolicyChecks.list"
1035 static OSStatus
SecTrustCopyErrorStrings(SecTrustRef trust
,
1036 CFStringRef
* CF_RETURNS_RETAINED simpleError
,
1037 CFStringRef
* CF_RETURNS_RETAINED fullError
) {
1038 if (!simpleError
|| !fullError
) {
1041 __block CFArrayRef details
= NULL
;
1042 dispatch_sync(trust
->_trustQueue
, ^{
1043 details
= CFRetainSafe(trust
->_details
);
1046 return errSecInternal
;
1048 /* We need to map the policy check constants to indexes into our checkmap table. */
1049 static dispatch_once_t onceToken
;
1050 static CFArrayRef policyChecks
= NULL
;
1051 dispatch_once(&onceToken
, ^{
1052 CFMutableArrayRef _policyChecks
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
1053 #undef POLICYCHECKMACRO
1054 #define POLICYCHECKMACRO(NAME, TRUSTRESULT, SUBTYPE, LEAFCHECK, PATHCHECK, LEAFONLY, CSSMERR, ERRORSTRING) \
1055 CFArrayAppendValue(_policyChecks, kSecPolicyCheck##NAME);
1056 #include "SecPolicyChecks.list"
1057 policyChecks
= _policyChecks
;
1060 /* Build the errors for each cert in the detailed results array */
1061 __block CFMutableStringRef fullMutableError
= CFStringCreateMutable(NULL
, 0);
1062 __block SecTrustErrorSubType simpleErrorSubType
= kSecTrustErrorSubTypeInvalid
;
1063 __block OSStatus simpleErrorStatus
= errSecInternalError
;
1064 __block CFIndex simpleErrorCertIndex
= kCFNotFound
;
1066 CFIndex count
= CFArrayGetCount(details
);
1067 for (ix
= 0; ix
< count
; ix
++) {
1068 CFDictionaryRef perCertDetails
= (CFDictionaryRef
)CFArrayGetValueAtIndex(details
, ix
);
1069 if (CFDictionaryGetCount(perCertDetails
) == 0) { continue; } // no errors on this cert
1071 /* Get the cert summary and start the full error details string for this cert */
1072 CFStringRef certSummary
= SecCertificateCopySubjectSummary(SecTrustGetCertificateAtIndex(trust
, ix
));
1073 CFStringRef format
= SecCopyTrustString(SEC_TRUST_CERTIFICATE_ERROR
);
1074 CFStringAppendFormat(fullMutableError
, NULL
, format
,
1076 CFReleaseNull(certSummary
);
1077 CFReleaseNull(format
);
1079 /* Figure out the errors */
1080 __block
bool firstError
= true;
1081 CFDictionaryForEach(perCertDetails
, ^(const void *key
, const void * __unused value
) {
1082 CFIndex policyCheckIndex
= CFArrayGetFirstIndexOfValue(policyChecks
, CFRangeMake(0, CFArrayGetCount(policyChecks
)), key
);
1083 if (policyCheckIndex
== kCFNotFound
) { return; }
1084 /* Keep track of the highest priority error encountered during this evaluation.
1085 * If multiple certs have errors of the same subtype we keep the lowest indexed cert. */
1086 if (simpleErrorSubType
> checkmap
[policyCheckIndex
].type
) {
1087 simpleErrorSubType
= checkmap
[policyCheckIndex
].type
;
1088 simpleErrorCertIndex
= ix
;
1089 simpleErrorStatus
= checkmap
[policyCheckIndex
].status
;
1091 /* Add this error to the full error */
1092 if (!firstError
) { CFStringAppend(fullMutableError
, CFSTR(", ")); }
1093 CFStringRef errorString
= SecCopyTrustString(checkmap
[policyCheckIndex
].errorKey
);
1094 CFStringAppend(fullMutableError
, errorString
);
1095 CFReleaseNull(errorString
);
1098 CFStringAppend(fullMutableError
, CFSTR(";"));
1100 CFReleaseNull(details
);
1102 /* Build the simple error */
1103 if (simpleErrorCertIndex
== kCFNotFound
) { simpleErrorCertIndex
= 0; }
1104 CFStringRef format
= NULL
;
1105 CFStringRef certSummary
= SecCertificateCopySubjectSummary(SecTrustGetCertificateAtIndex(trust
, simpleErrorCertIndex
));
1106 switch (simpleErrorSubType
) {
1107 case kSecTrustErrorSubTypeBlocked
: {
1108 format
= SecCopyTrustString(SEC_TRUST_ERROR_SUBTYPE_BLOCKED
);
1111 case kSecTrustErrorSubTypeRevoked
: {
1112 format
= SecCopyTrustString(SEC_TRUST_ERROR_SUBTYPE_REVOKED
);
1115 case kSecTrustErrorSubTypeKeySize
: {
1116 format
= SecCopyTrustString(SEC_TRUST_ERROR_SUBTYPE_KEYSIZE
);
1119 case kSecTrustErrorSubTypeWeakHash
: {
1120 format
= SecCopyTrustString(SEC_TRUST_ERROR_SUBTYPE_WEAKHASH
);
1123 case kSecTrustErrorSubTypeDenied
: {
1124 format
= SecCopyTrustString(SEC_TRUST_ERROR_SUBTYPE_DENIED
);
1127 case kSecTrustErrorSubTypeCompliance
: {
1128 format
= SecCopyTrustString(SEC_TRUST_ERROR_SUBTYPE_COMPLIANCE
);
1131 case kSecTrustErrorSubTypeExpired
: {
1132 format
= SecCopyTrustString(SEC_TRUST_ERROR_SUBTYPE_EXPIRED
);
1135 case kSecTrustErrorSubTypeTrust
: {
1136 format
= SecCopyTrustString(SEC_TRUST_ERROR_SUBTYPE_TRUST
);
1139 case kSecTrustErrorSubTypeName
: {
1140 format
= SecCopyTrustString(SEC_TRUST_ERROR_SUBTYPE_NAME
);
1143 case kSecTrustErrorSubTypeUsage
: {
1144 format
= SecCopyTrustString(SEC_TRUST_ERROR_SUBTYPE_USAGE
);
1147 case kSecTrustErrorSubTypePinning
: {
1148 format
= SecCopyTrustString(SEC_TRUST_ERROR_SUBTYPE_PINNING
);
1149 CFAssignRetained(certSummary
, SecTrustCopyChainSummary(trust
));
1153 format
= SecCopyTrustString(SEC_TRUST_ERROR_SUBTYPE_INVALID
);
1157 if (format
&& certSummary
) {
1158 *simpleError
= CFStringCreateWithFormat(NULL
, NULL
, format
, certSummary
);
1160 CFReleaseNull(format
);
1161 CFReleaseNull(certSummary
);
1162 *fullError
= fullMutableError
;
1163 return simpleErrorStatus
;
1166 static CF_RETURNS_RETAINED CFErrorRef
SecTrustCopyError(SecTrustRef trust
) {
1167 if (!trust
) { return NULL
; }
1168 (void)SecTrustEvaluateIfNecessary(trust
);
1169 OSStatus status
= errSecSuccess
;
1170 __block SecTrustResultType trustResult
= kSecTrustResultInvalid
;
1171 dispatch_sync(trust
->_trustQueue
, ^{
1172 trustResult
= trust
->_trustResult
;
1174 if (trustResult
== kSecTrustResultProceed
|| trustResult
== kSecTrustResultUnspecified
) {
1178 CFStringRef detailedError
= NULL
;
1179 CFStringRef simpleError
= NULL
;
1180 status
= SecTrustCopyErrorStrings(trust
, &simpleError
, &detailedError
);
1181 /* failure to obtain either string must not cause a failure to create the CFErrorRef */
1183 simpleError
= SecCopyErrorMessageString(status
, NULL
);
1185 if (!detailedError
) {
1186 detailedError
= SecCopyErrorMessageString(status
, NULL
);
1188 CFDictionaryRef userInfo
= CFDictionaryCreate(NULL
, (const void **)&kCFErrorLocalizedDescriptionKey
,
1189 (const void **)&detailedError
, 1,
1190 &kCFTypeDictionaryKeyCallBacks
,
1191 &kCFTypeDictionaryValueCallBacks
);
1192 CFErrorRef underlyingError
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, status
, userInfo
);
1193 CFReleaseNull(userInfo
);
1194 CFReleaseNull(detailedError
);
1196 const void *keys
[] = { kCFErrorLocalizedDescriptionKey
, kCFErrorUnderlyingErrorKey
};
1197 const void *values
[] = { simpleError
, underlyingError
};
1198 userInfo
= CFDictionaryCreate(NULL
, keys
, values
, 2,
1199 &kCFTypeDictionaryKeyCallBacks
,
1200 &kCFTypeDictionaryValueCallBacks
);
1201 CFErrorRef error
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, status
, userInfo
);
1202 CFReleaseNull(userInfo
);
1203 CFReleaseNull(simpleError
);
1204 CFReleaseNull(underlyingError
);
1208 bool SecTrustEvaluateWithError(SecTrustRef trust
, CFErrorRef
*error
) {
1209 SecTrustResultType trustResult
= kSecTrustResultInvalid
;
1210 OSStatus status
= SecTrustEvaluate(trust
, &trustResult
);
1211 if (status
== errSecSuccess
&& (trustResult
== kSecTrustResultProceed
|| trustResult
== kSecTrustResultUnspecified
)) {
1218 if (status
!= errSecSuccess
) {
1219 *error
= SecCopyLastError(status
);
1221 *error
= SecTrustCopyError(trust
);
1227 OSStatus
SecTrustEvaluateAsync(SecTrustRef trust
,
1228 dispatch_queue_t queue
, SecTrustCallback result
)
1230 CFRetainSafe(trust
);
1231 dispatch_async(queue
, ^{
1232 SecTrustResultType trustResult
;
1233 if (errSecSuccess
!= SecTrustEvaluate(trust
, &trustResult
)) {
1234 trustResult
= kSecTrustResultInvalid
;
1236 result(trust
, trustResult
);
1237 CFReleaseSafe(trust
);
1239 return errSecSuccess
;
1242 OSStatus
SecTrustEvaluateFastAsync(SecTrustRef trust
,
1243 dispatch_queue_t queue
, SecTrustCallback result
)
1245 if (trust
== NULL
|| queue
== NULL
|| result
== NULL
) {
1249 dispatch_assert_queue(queue
);
1250 SecTrustEvaluateIfNecessaryFastAsync(trust
, queue
, ^(OSStatus status
) {
1251 if (status
!= noErr
) {
1252 result(trust
, kSecTrustResultInvalid
);
1255 __block SecTrustResultType trustResult
= kSecTrustResultInvalid
;
1256 dispatch_sync(trust
->_trustQueue
, ^{
1257 trustResult
= trust
->_trustResult
;
1259 /* log to syslog when there is a trust failure */
1260 if (trustResult
!= kSecTrustResultProceed
&&
1261 trustResult
!= kSecTrustResultUnspecified
) {
1262 CFStringRef failureDesc
= SecTrustCopyFailureDescription(trust
);
1263 secerror("Trust evaluate failure:%{public}@", failureDesc
);
1264 CFRelease(failureDesc
);
1268 result(trust
, trustResult
);
1270 return errSecSuccess
;
1273 static bool append_certificate_to_xpc_array(SecCertificateRef certificate
, xpc_object_t xpc_certificates
);
1274 static xpc_object_t
copy_xpc_certificates_array(CFArrayRef certificates
);
1275 xpc_object_t
copy_xpc_policies_array(CFArrayRef policies
);
1276 OSStatus
validate_array_of_items(CFArrayRef array
, CFStringRef arrayItemType
, CFTypeID itemTypeID
, bool required
);
1278 static bool append_certificate_to_xpc_array(SecCertificateRef certificate
, xpc_object_t xpc_certificates
) {
1280 return true; // NOOP
1282 size_t length
= SecCertificateGetLength(certificate
);
1283 const uint8_t *bytes
= SecCertificateGetBytePtr(certificate
);
1284 if (!length
|| !bytes
) {
1287 xpc_array_set_data(xpc_certificates
, XPC_ARRAY_APPEND
, bytes
, length
);
1291 static xpc_object_t
copy_xpc_certificates_array(CFArrayRef certificates
) {
1292 xpc_object_t xpc_certificates
= xpc_array_create(NULL
, 0);
1293 if (!xpc_certificates
) {
1296 CFIndex ix
, count
= CFArrayGetCount(certificates
);
1297 for (ix
= 0; ix
< count
; ++ix
) {
1298 SecCertificateRef certificate
= (SecCertificateRef
) CFArrayGetValueAtIndex(certificates
, ix
);
1299 #if SECTRUST_VERBOSE_DEBUG
1300 size_t length
= SecCertificateGetLength(certificate
);
1301 const uint8_t *bytes
= SecCertificateGetBytePtr(certificate
);
1302 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
);
1304 if (!append_certificate_to_xpc_array(certificate
, xpc_certificates
)) {
1305 xpc_release(xpc_certificates
);
1306 xpc_certificates
= NULL
;
1310 return xpc_certificates
;
1313 static bool SecXPCDictionarySetCertificates(xpc_object_t message
, const char *key
, CFArrayRef certificates
, CFErrorRef
*error
) {
1314 xpc_object_t xpc_certificates
= copy_xpc_certificates_array(certificates
);
1315 if (!xpc_certificates
) {
1316 SecError(errSecAllocate
, error
, CFSTR("failed to create xpc_array of certificates"));
1319 xpc_dictionary_set_value(message
, key
, xpc_certificates
);
1320 xpc_release(xpc_certificates
);
1324 static bool SecXPCDictionarySetPolicies(xpc_object_t message
, const char *key
, CFArrayRef policies
, CFErrorRef
*error
) {
1325 xpc_object_t xpc_policies
= copy_xpc_policies_array(policies
);
1326 if (!xpc_policies
) {
1327 SecError(errSecAllocate
, error
, CFSTR("failed to create xpc_array of policies"));
1330 xpc_dictionary_set_value(message
, key
, xpc_policies
);
1331 xpc_release(xpc_policies
);
1336 static bool CFDataAppendToXPCArray(CFDataRef data
, xpc_object_t xpc_data_array
, CFErrorRef
*error
) {
1338 return true; // NOOP
1340 size_t length
= CFDataGetLength(data
);
1341 const uint8_t *bytes
= CFDataGetBytePtr(data
);
1342 if (!length
|| !bytes
)
1343 return SecError(errSecParam
, error
, CFSTR("invalid CFDataRef"));
1345 xpc_array_set_data(xpc_data_array
, XPC_ARRAY_APPEND
, bytes
, length
);
1350 static xpc_object_t
CFDataArrayCopyXPCArray(CFArrayRef data_array
, CFErrorRef
*error
) {
1351 xpc_object_t xpc_data_array
;
1352 require_action_quiet(xpc_data_array
= xpc_array_create(NULL
, 0), exit
,
1353 SecError(errSecAllocate
, error
, CFSTR("failed to create xpc_array")));
1354 CFIndex ix
, count
= CFArrayGetCount(data_array
);
1355 for (ix
= 0; ix
< count
; ++ix
) {
1356 if (!CFDataAppendToXPCArray((CFDataRef
)CFArrayGetValueAtIndex(data_array
, ix
), xpc_data_array
, error
)) {
1357 xpc_release(xpc_data_array
);
1363 return xpc_data_array
;
1366 static bool SecXPCDictionarySetDataArray(xpc_object_t message
, const char *key
, CFArrayRef data_array
, CFErrorRef
*error
) {
1367 xpc_object_t xpc_data_array
= CFDataArrayCopyXPCArray(data_array
, error
);
1368 if (!xpc_data_array
)
1370 xpc_dictionary_set_value(message
, key
, xpc_data_array
);
1371 xpc_release(xpc_data_array
);
1375 static bool SecXPCDictionaryCopyChainOptional(xpc_object_t message
, const char *key
, CFArrayRef
*path
, CFErrorRef
*error
) {
1376 xpc_object_t xpc_path
= xpc_dictionary_get_value(message
, key
);
1377 CFMutableArrayRef output
= NULL
;
1383 require_action_quiet(xpc_get_type(xpc_path
) == XPC_TYPE_ARRAY
, exit
, SecError(errSecDecode
, error
, CFSTR("xpc_path value is not an array")));
1384 require_action_quiet(count
= xpc_array_get_count(xpc_path
), exit
, SecError(errSecDecode
, error
, CFSTR("xpc_path array count == 0")));
1385 output
= CFArrayCreateMutable(NULL
, count
, &kCFTypeArrayCallBacks
);
1388 for (ix
= 0; ix
< count
; ++ix
) {
1389 SecCertificateRef certificate
= SecCertificateCreateWithXPCArrayAtIndex(xpc_path
, ix
, error
);
1391 CFArrayAppendValue(output
, certificate
);
1392 CFReleaseNull(certificate
);
1394 CFReleaseNull(output
);
1407 static int SecXPCDictionaryGetNonZeroInteger(xpc_object_t message
, const char *key
, CFErrorRef
*error
) {
1408 int64_t value
= xpc_dictionary_get_int64(message
, key
);
1410 SecError(errSecInternal
, error
, CFSTR("object for key %s is 0"), key
);
1415 static SecTrustResultType
handle_trust_evaluate_xpc(enum SecXPCOperation op
, CFArrayRef certificates
,
1416 CFArrayRef anchors
, bool anchorsOnly
,
1417 bool keychainsAllowed
, CFArrayRef policies
, CFArrayRef responses
,
1418 CFArrayRef SCTs
, CFArrayRef trustedLogs
,
1419 CFAbsoluteTime verifyTime
, __unused CFArrayRef accessGroups
, CFArrayRef exceptions
,
1420 CFArrayRef
*details
, CFDictionaryRef
*info
, CFArrayRef
*chain
, CFErrorRef
*error
)
1422 __block SecTrustResultType tr
= kSecTrustResultInvalid
;
1423 securityd_send_sync_and_do(op
, error
, ^bool(xpc_object_t message
, CFErrorRef
*error
) {
1424 if (!SecXPCDictionarySetCertificates(message
, kSecTrustCertificatesKey
, certificates
, error
))
1426 if (anchors
&& !SecXPCDictionarySetCertificates(message
, kSecTrustAnchorsKey
, anchors
, error
))
1429 xpc_dictionary_set_bool(message
, kSecTrustAnchorsOnlyKey
, anchorsOnly
);
1430 xpc_dictionary_set_bool(message
, kSecTrustKeychainsAllowedKey
, keychainsAllowed
);
1431 if (!SecXPCDictionarySetPolicies(message
, kSecTrustPoliciesKey
, policies
, error
))
1433 if (responses
&& !SecXPCDictionarySetDataArray(message
, kSecTrustResponsesKey
, responses
, error
))
1435 if (SCTs
&& !SecXPCDictionarySetDataArray(message
, kSecTrustSCTsKey
, SCTs
, error
))
1437 if (trustedLogs
&& !SecXPCDictionarySetPList(message
, kSecTrustTrustedLogsKey
, trustedLogs
, error
))
1439 xpc_dictionary_set_double(message
, kSecTrustVerifyDateKey
, verifyTime
);
1440 if (exceptions
&& !SecXPCDictionarySetPList(message
, kSecTrustExceptionsKey
, exceptions
, error
))
1443 }, ^bool(xpc_object_t response
, CFErrorRef
*error
) {
1444 secdebug("trust", "response: %@", response
);
1445 return SecXPCDictionaryCopyArrayOptional(response
, kSecTrustDetailsKey
, details
, error
) &&
1446 SecXPCDictionaryCopyDictionaryOptional(response
, kSecTrustInfoKey
, info
, error
) &&
1447 SecXPCDictionaryCopyChainOptional(response
, kSecTrustChainKey
, chain
, error
) &&
1448 ((tr
= SecXPCDictionaryGetNonZeroInteger(response
, kSecTrustResultKey
, error
)) != kSecTrustResultInvalid
);
1453 typedef void (^trust_handler_t
)(SecTrustResultType tr
, CFErrorRef error
);
1455 static void handle_trust_evaluate_xpc_async(dispatch_queue_t replyq
, trust_handler_t trustHandler
,
1456 enum SecXPCOperation op
, CFArrayRef certificates
,
1457 CFArrayRef anchors
, bool anchorsOnly
,
1458 bool keychainsAllowed
, CFArrayRef policies
,
1459 CFArrayRef responses
, CFArrayRef SCTs
, CFArrayRef trustedLogs
,
1460 CFAbsoluteTime verifyTime
, __unused CFArrayRef accessGroups
,
1461 CFArrayRef exceptions
, CFArrayRef
*details
,
1462 CFDictionaryRef
*info
, CFArrayRef
*chain
)
1464 securityd_send_async_and_do(op
, replyq
, ^bool(xpc_object_t message
, CFErrorRef
*error
) {
1465 if (!SecXPCDictionarySetCertificates(message
, kSecTrustCertificatesKey
, certificates
, error
))
1467 if (anchors
&& !SecXPCDictionarySetCertificates(message
, kSecTrustAnchorsKey
, anchors
, error
))
1470 xpc_dictionary_set_bool(message
, kSecTrustAnchorsOnlyKey
, anchorsOnly
);
1471 xpc_dictionary_set_bool(message
, kSecTrustKeychainsAllowedKey
, keychainsAllowed
);
1472 if (!SecXPCDictionarySetPolicies(message
, kSecTrustPoliciesKey
, policies
, error
))
1474 if (responses
&& !SecXPCDictionarySetDataArray(message
, kSecTrustResponsesKey
, responses
, error
))
1476 if (SCTs
&& !SecXPCDictionarySetDataArray(message
, kSecTrustSCTsKey
, SCTs
, error
))
1478 if (trustedLogs
&& !SecXPCDictionarySetPList(message
, kSecTrustTrustedLogsKey
, trustedLogs
, error
))
1480 xpc_dictionary_set_double(message
, kSecTrustVerifyDateKey
, verifyTime
);
1481 if (exceptions
&& !SecXPCDictionarySetPList(message
, kSecTrustExceptionsKey
, exceptions
, error
))
1484 }, ^(xpc_object_t response
, CFErrorRef error
) {
1485 secdebug("trust", "response: %@", response
);
1486 if (response
== NULL
|| error
!= NULL
) {
1487 trustHandler(kSecTrustResultInvalid
, error
);
1490 SecTrustResultType tr
= kSecTrustResultInvalid
;
1491 CFErrorRef error2
= NULL
;
1492 if (SecXPCDictionaryCopyArrayOptional(response
, kSecTrustDetailsKey
, details
, &error2
) &&
1493 SecXPCDictionaryCopyDictionaryOptional(response
, kSecTrustInfoKey
, info
, &error2
) &&
1494 SecXPCDictionaryCopyChainOptional(response
, kSecTrustChainKey
, chain
, &error2
)) {
1495 tr
= SecXPCDictionaryGetNonZeroInteger(response
, kSecTrustResultKey
, &error2
);
1497 trustHandler(tr
, error2
);
1498 CFReleaseNull(error2
);
1502 OSStatus
validate_array_of_items(CFArrayRef array
, CFStringRef arrayItemType
, CFTypeID itemTypeID
, bool required
) {
1503 OSStatus result
= errSecSuccess
;
1504 CFIndex index
, count
;
1505 count
= (array
) ? CFArrayGetCount(array
) : 0;
1506 if (!count
&& required
) {
1507 secerror("no %@ in array!", arrayItemType
);
1508 result
= errSecParam
;
1510 for (index
= 0; index
< count
; index
++) {
1511 CFTypeRef item
= (CFTypeRef
) CFArrayGetValueAtIndex(array
, index
);
1513 secerror("%@ %@ (index %d)", arrayItemType
, CFSTR("reference is nil"), (int)index
);
1514 result
= errSecParam
;
1517 if (CFGetTypeID(item
) != itemTypeID
) {
1518 secerror("%@ %@ (index %d)", arrayItemType
, CFSTR("is not the expected CF type"), (int)index
);
1519 result
= errSecParam
;
1522 if (CFGetTypeID(item
) == SecCertificateGetTypeID()) {
1523 SecCertificateRef certificate
= (SecCertificateRef
) item
;
1524 CFIndex length
= SecCertificateGetLength(certificate
);
1525 const UInt8
*bytes
= SecCertificateGetBytePtr(certificate
);
1527 secerror("%@ %@ (index %d)", arrayItemType
, CFSTR("has zero length"), (int)index
);
1528 result
= errSecParam
;
1531 secerror("%@ %@ (index %d)", arrayItemType
, CFSTR("has nil bytes"), (int)index
);
1532 result
= errSecParam
;
1534 #if SECTRUST_VERBOSE_DEBUG
1535 secerror("%@[%d] of %d = %ld bytes @ 0x%lX", arrayItemType
, (int)index
, (int)count
, (size_t)length
, (uintptr_t)bytes
);
1539 if (CFGetTypeID(item
) == SecPolicyGetTypeID()) {
1540 SecPolicyRef policy
= (SecPolicyRef
) item
;
1541 CFStringRef oidStr
= policy
->_oid
;
1542 if (!oidStr
|| (CFGetTypeID(oidStr
) != CFStringGetTypeID())) {
1543 oidStr
= CFSTR("has invalid OID string!");
1544 secerror("%@ %@ (index %d)", arrayItemType
, oidStr
, (int)index
);
1546 #if SECTRUST_VERBOSE_DEBUG
1547 secerror("%@[%d] of %d = \"%@\" 0x%lX", arrayItemType
, (int)index
, (int)count
, oidStr
, (uintptr_t)policy
);
1554 static OSStatus
SecTrustValidateInput(SecTrustRef trust
) {
1555 OSStatus status
, result
= errSecSuccess
;
1557 // certificates (required)
1558 status
= validate_array_of_items(trust
->_certificates
, CFSTR("certificate"), SecCertificateGetTypeID(), true);
1559 if (status
) result
= status
;
1560 // anchors (optional)
1561 status
= validate_array_of_items(trust
->_anchors
, CFSTR("input anchor"), SecCertificateGetTypeID(), false);
1562 if (status
) result
= status
;
1563 // policies (required??)
1564 status
= validate_array_of_items(trust
->_policies
, CFSTR("policy"), SecPolicyGetTypeID(), true);
1565 if (status
) result
= status
;
1566 // _responses, _SCTs, _trustedLogs, ...
1567 // verify time: SecTrustGetVerifyTime(trust)
1568 // access groups: SecAccessGroupsGetCurrent()
1573 static OSStatus
SecTrustEvaluateIfNecessary(SecTrustRef trust
) {
1574 __block OSStatus result
;
1579 __block CFAbsoluteTime verifyTime
= SecTrustGetVerifyTime(trust
);
1580 SecTrustAddPolicyAnchors(trust
);
1581 dispatch_sync(trust
->_trustQueue
, ^{
1582 if (trust
->_trustResult
!= kSecTrustResultInvalid
) {
1583 result
= errSecSuccess
;
1587 trust
->_trustResult
= kSecTrustResultOtherError
; /* to avoid potential recursion */
1589 CFReleaseNull(trust
->_chain
);
1590 CFReleaseNull(trust
->_details
);
1591 CFReleaseNull(trust
->_info
);
1592 if (trust
->_legacy_info_array
) {
1593 free(trust
->_legacy_info_array
);
1594 trust
->_legacy_info_array
= NULL
;
1596 if (trust
->_legacy_status_array
) {
1597 free(trust
->_legacy_status_array
);
1598 trust
->_legacy_status_array
= NULL
;
1601 os_activity_initiate("SecTrustEvaluateIfNecessary", OS_ACTIVITY_FLAG_DEFAULT
, ^{
1602 SecTrustValidateInput(trust
);
1604 /* @@@ 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. */
1605 result
= SecOSStatusWith(^bool (CFErrorRef
*error
) {
1606 trust
->_trustResult
= TRUSTD_XPC(sec_trust_evaluate
,
1607 handle_trust_evaluate_xpc
,
1608 trust
->_certificates
, trust
->_anchors
, trust
->_anchorsOnly
, trust
->_keychainsAllowed
,
1609 trust
->_policies
, trust
->_responses
, trust
->_SCTs
, trust
->_trustedLogs
,
1610 verifyTime
, SecAccessGroupsGetCurrent(), trust
->_exceptions
,
1611 &trust
->_details
, &trust
->_info
, &trust
->_chain
, error
);
1612 if (trust
->_trustResult
== kSecTrustResultInvalid
/* TODO check domain */ &&
1613 SecErrorGetOSStatus(*error
) == errSecNotAvailable
&&
1614 CFArrayGetCount(trust
->_certificates
)) {
1615 /* We failed to talk to securityd. The only time this should
1616 happen is when we are running prior to launchd enabling
1617 registration of services. This currently happens when we
1618 are running from the ramdisk. To make ASR happy we initialize
1619 _chain and return success with a failure as the trustResult, to
1620 make it seem like we did a cert evaluation, so ASR can extract
1621 the public key from the leaf. */
1622 SecCertificateRef leafCert
= (SecCertificateRef
)CFArrayGetValueAtIndex(trust
->_certificates
, 0);
1623 CFArrayRef leafCertArray
= CFArrayCreate(NULL
, (const void**)&leafCert
, 1, &kCFTypeArrayCallBacks
);
1624 trust
->_chain
= leafCertArray
;
1626 CFReleaseNull(*error
);
1629 return trust
->_trustResult
!= kSecTrustResultInvalid
;
1636 // IMPORTANT: this MUST be called on the provided queue as it will call the handler synchronously
1637 // if no asynchronous work is needed
1638 static void SecTrustEvaluateIfNecessaryFastAsync(SecTrustRef trust
,
1639 dispatch_queue_t queue
,
1640 void (^handler
)(OSStatus status
)) {
1644 if (handler
== NULL
) {
1647 if (trust
== NULL
|| queue
== NULL
) {
1648 handler(errSecParam
);
1652 __block
bool shouldReturnSuccess
= false;
1653 __block CFAbsoluteTime verifyTime
= SecTrustGetVerifyTime(trust
);
1654 SecTrustAddPolicyAnchors(trust
);
1655 dispatch_sync(trust
->_trustQueue
, ^{
1656 if (trust
->_trustResult
!= kSecTrustResultInvalid
) {
1657 shouldReturnSuccess
= true;
1661 trust
->_trustResult
= kSecTrustResultOtherError
; /* to avoid potential recursion */
1663 CFReleaseNull(trust
->_chain
);
1664 CFReleaseNull(trust
->_details
);
1665 CFReleaseNull(trust
->_info
);
1666 if (trust
->_legacy_info_array
) {
1667 free(trust
->_legacy_info_array
);
1668 trust
->_legacy_info_array
= NULL
;
1670 if (trust
->_legacy_status_array
) {
1671 free(trust
->_legacy_status_array
);
1672 trust
->_legacy_status_array
= NULL
;
1675 os_activity_t activity
= os_activity_create("SecTrustEvaluateIfNecessaryFastAsync",
1676 OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_DEFAULT
);
1677 __block
struct os_activity_scope_state_s activityState
;
1678 os_activity_scope_enter(activity
, &activityState
);
1679 os_release(activity
);
1681 SecTrustValidateInput(trust
);
1683 CFRetainSafe(trust
);
1684 TRUSTD_XPC_ASYNC(sec_trust_evaluate
,
1685 handle_trust_evaluate_xpc_async
,
1687 ^(SecTrustResultType tr
, CFErrorRef error
) {
1688 __block OSStatus result
= errSecInternalError
;
1689 dispatch_sync(trust
->_trustQueue
, ^{
1690 trust
->_trustResult
= tr
;
1691 if (trust
->_trustResult
== kSecTrustResultInvalid
/* TODO check domain */ &&
1692 SecErrorGetOSStatus(error
) == errSecNotAvailable
&&
1693 CFArrayGetCount(trust
->_certificates
)) {
1694 /* We failed to talk to securityd. The only time this should
1695 happen is when we are running prior to launchd enabling
1696 registration of services. This currently happens when we
1697 are running from the ramdisk. To make ASR happy we initialize
1698 _chain and return success with a failure as the trustResult, to
1699 make it seem like we did a cert evaluation, so ASR can extract
1700 the public key from the leaf. */
1701 SecCertificateRef leafCert
= (SecCertificateRef
)CFArrayGetValueAtIndex(trust
->_certificates
, 0);
1702 CFArrayRef leafCertArray
= CFArrayCreate(NULL
, (const void**)&leafCert
, 1, &kCFTypeArrayCallBacks
);
1703 trust
->_chain
= leafCertArray
;
1704 result
= errSecSuccess
;
1707 result
= SecOSStatusWith(^bool (CFErrorRef
*error2
) {
1708 if (error2
!= NULL
) {
1711 return trust
->_trustResult
!= kSecTrustResultInvalid
;
1714 os_activity_scope_leave(&activityState
);
1716 CFReleaseSafe(trust
);
1718 trust
->_certificates
, trust
->_anchors
, trust
->_anchorsOnly
, trust
->_keychainsAllowed
,
1719 trust
->_policies
, trust
->_responses
, trust
->_SCTs
, trust
->_trustedLogs
,
1720 verifyTime
, SecAccessGroupsGetCurrent(), trust
->_exceptions
,
1721 &trust
->_details
, &trust
->_info
, &trust
->_chain
);
1723 if (shouldReturnSuccess
) {
1724 handler(errSecSuccess
);
1728 /* Helper for the qsort below. */
1729 static int compare_strings(const void *a1
, const void *a2
) {
1730 CFStringRef s1
= *(CFStringRef
*)a1
;
1731 CFStringRef s2
= *(CFStringRef
*)a2
;
1732 return (int) CFStringCompare(s1
, s2
, kCFCompareForcedOrdering
);
1735 CFStringRef
SecTrustCopyFailureDescription(SecTrustRef trust
) {
1739 CFMutableStringRef reason
= CFStringCreateMutable(NULL
, 0);
1740 SecTrustEvaluateIfNecessary(trust
);
1741 __block CFArrayRef details
= NULL
;
1742 dispatch_sync(trust
->_trustQueue
, ^{
1743 details
= CFRetainSafe(trust
->_details
);
1745 CFIndex pathLength
= details
? CFArrayGetCount(details
) : 0;
1746 for (CFIndex ix
= 0; ix
< pathLength
; ++ix
) {
1747 CFDictionaryRef detail
= (CFDictionaryRef
)CFArrayGetValueAtIndex(details
, ix
);
1748 CFIndex dCount
= CFDictionaryGetCount(detail
);
1751 CFStringAppend(reason
, CFSTR(" [leaf"));
1752 else if (ix
== pathLength
- 1)
1753 CFStringAppend(reason
, CFSTR(" [root"));
1755 CFStringAppendFormat(reason
, NULL
, CFSTR(" [ca%" PRIdCFIndex
), ix
);
1757 const void *keys
[dCount
];
1758 CFDictionaryGetKeysAndValues(detail
, &keys
[0], NULL
);
1759 qsort(&keys
[0], dCount
, sizeof(keys
[0]), compare_strings
);
1760 for (CFIndex kix
= 0; kix
< dCount
; ++kix
) {
1761 CFStringRef key
= keys
[kix
];
1762 const void *value
= CFDictionaryGetValue(detail
, key
);
1763 CFStringAppendFormat(reason
, NULL
, CFSTR(" %@%@"), key
,
1764 (CFGetTypeID(value
) == CFBooleanGetTypeID()
1765 ? CFSTR("") : value
));
1767 CFStringAppend(reason
, CFSTR("]"));
1770 CFReleaseSafe(details
);
1775 /* On OS X we need SecTrustCopyPublicKey to give us a CDSA-based SecKeyRef,
1776 so we will refer to this one internally as SecTrustCopyPublicKey_ios,
1777 and call it from SecTrustCopyPublicKey.
1779 SecKeyRef
SecTrustCopyPublicKey_ios(SecTrustRef trust
)
1781 SecKeyRef
SecTrustCopyPublicKey(SecTrustRef trust
)
1787 __block SecKeyRef publicKey
= NULL
;
1788 dispatch_sync(trust
->_trustQueue
, ^{
1789 if (trust
->_publicKey
) {
1790 publicKey
= CFRetainSafe(trust
->_publicKey
);
1793 SecCertificateRef leaf
= (SecCertificateRef
)CFArrayGetValueAtIndex(trust
->_certificates
, 0);
1794 trust
->_publicKey
= SecCertificateCopyKey(leaf
);
1795 if (trust
->_publicKey
) {
1796 publicKey
= CFRetainSafe(trust
->_publicKey
);
1799 /* If we couldn't get a public key from the leaf cert alone. */
1801 SecTrustEvaluateIfNecessary(trust
);
1802 dispatch_sync(trust
->_trustQueue
, ^{
1803 if (trust
->_chain
) {
1804 SecCertificateRef cert
= (SecCertificateRef
)CFArrayGetValueAtIndex(trust
->_chain
, 0);
1805 trust
->_publicKey
= SecCertificateCopyKey(cert
);
1806 publicKey
= CFRetainSafe(trust
->_publicKey
);
1813 CFIndex
SecTrustGetCertificateCount(SecTrustRef trust
) {
1817 SecTrustEvaluateIfNecessary(trust
);
1818 __block CFIndex certCount
= 1;
1819 dispatch_sync(trust
->_trustQueue
, ^{
1820 if (trust
->_chain
) {
1821 certCount
= CFArrayGetCount(trust
->_chain
);
1827 SecCertificateRef
SecTrustGetCertificateAtIndex(SecTrustRef trust
,
1832 __block SecCertificateRef cert
= NULL
;
1834 dispatch_sync(trust
->_trustQueue
, ^{
1835 cert
= (SecCertificateRef
)CFArrayGetValueAtIndex(trust
->_certificates
, 0);
1839 SecTrustEvaluateIfNecessary(trust
);
1840 dispatch_sync(trust
->_trustQueue
, ^{
1841 if (trust
->_chain
) {
1842 cert
= (SecCertificateRef
)CFArrayGetValueAtIndex(trust
->_chain
, ix
);
1848 CFDictionaryRef
SecTrustCopyInfo(SecTrustRef trust
) {
1852 SecTrustEvaluateIfNecessary(trust
);
1853 __block CFDictionaryRef info
= NULL
;
1854 dispatch_sync(trust
->_trustQueue
, ^{
1855 info
= CFRetainSafe(trust
->_info
);
1860 CFArrayRef
SecTrustGetTrustExceptionsArray(SecTrustRef trust
) {
1864 __block CFArrayRef exceptions
= NULL
;
1865 dispatch_sync(trust
->_trustQueue
, ^{
1866 exceptions
= trust
->_exceptions
;
1871 CFDataRef
SecTrustCopyExceptions(SecTrustRef trust
) {
1872 /* Stash the old exceptions and run an evaluation with no exceptions filtered. */
1873 __block CFArrayRef oldExceptions
= NULL
;
1874 dispatch_sync(trust
->_trustQueue
, ^{
1875 if (trust
->_exceptions
) {
1876 oldExceptions
= trust
->_exceptions
;
1877 trust
->_exceptions
= NULL
;
1880 SecTrustSetNeedsEvaluation(trust
);
1882 /* Create the new exceptions based on an unfiltered eval. */
1883 __block CFArrayRef details
= NULL
;
1884 SecTrustEvaluateIfNecessary(trust
);
1885 dispatch_sync(trust
->_trustQueue
, ^{
1886 details
= CFRetainSafe(trust
->_details
);
1888 CFIndex pathLength
= details
? CFArrayGetCount(details
) : 0;
1889 CFMutableArrayRef exceptions
= CFArrayCreateMutable(kCFAllocatorDefault
, pathLength
, &kCFTypeArrayCallBacks
);
1891 for (ix
= 0; ix
< pathLength
; ++ix
) {
1892 CFDictionaryRef detail
= (CFDictionaryRef
)CFArrayGetValueAtIndex(details
, ix
);
1893 CFIndex detailCount
= CFDictionaryGetCount(detail
);
1894 CFMutableDictionaryRef exception
;
1895 if (ix
== 0 || detailCount
> 0) {
1896 exception
= CFDictionaryCreateMutableCopy(kCFAllocatorDefault
, detailCount
+ 1, detail
);
1897 SecCertificateRef certificate
= SecTrustGetCertificateAtIndex(trust
, ix
);
1898 CFDataRef digest
= SecCertificateGetSHA1Digest(certificate
);
1899 CFDictionaryAddValue(exception
, kSecCertificateDetailSHA1Digest
, digest
);
1901 /* Add empty exception dictionaries for non leaf certs which have no exceptions to save space. */
1902 exception
= (CFMutableDictionaryRef
)CFDictionaryCreate(kCFAllocatorDefault
, NULL
, NULL
, 0,
1903 &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
1905 CFArrayAppendValue(exceptions
, exception
);
1906 CFReleaseNull(exception
);
1909 /* Restore the stashed exceptions. */
1910 if (oldExceptions
) {
1911 dispatch_sync(trust
->_trustQueue
, ^{
1912 trust
->_exceptions
= oldExceptions
;
1914 SecTrustSetNeedsEvaluation(trust
);
1917 /* Remove any trailing empty dictionaries to save even more space (we skip the leaf
1918 since it will never be empty). */
1919 for (ix
= pathLength
; ix
-- > 1;) {
1920 CFDictionaryRef exception
= (CFDictionaryRef
)CFArrayGetValueAtIndex(exceptions
, ix
);
1921 if (CFDictionaryGetCount(exception
) == 0) {
1922 CFArrayRemoveValueAtIndex(exceptions
, ix
);
1928 CFDataRef encodedExceptions
= CFPropertyListCreateData(kCFAllocatorDefault
,
1929 exceptions
, kCFPropertyListBinaryFormat_v1_0
, 0, NULL
);
1930 CFRelease(exceptions
);
1931 CFReleaseSafe(details
);
1932 return encodedExceptions
;
1935 bool SecTrustSetExceptions(SecTrustRef trust
, CFDataRef encodedExceptions
) {
1939 CFArrayRef exceptions
= NULL
;
1941 if (NULL
!= encodedExceptions
) {
1942 exceptions
= (CFArrayRef
)CFPropertyListCreateWithData(kCFAllocatorDefault
,
1943 encodedExceptions
, kCFPropertyListImmutable
, NULL
, NULL
);
1946 if (exceptions
&& CFGetTypeID(exceptions
) != CFArrayGetTypeID()) {
1947 CFRelease(exceptions
);
1951 dispatch_sync(trust
->_trustQueue
, ^{
1952 CFReleaseSafe(trust
->_exceptions
);
1953 trust
->_exceptions
= exceptions
;
1956 /* We changed the exceptions -- so we need to re-evaluate */
1957 SecTrustSetNeedsEvaluation(trust
);
1959 /* If there is a valid exception entry for our current leaf we're golden. */
1960 if (SecTrustGetExceptionForCertificateAtIndex(trust
, 0))
1963 /* The passed in exceptions didn't match our current leaf, so we discard it. */
1964 dispatch_sync(trust
->_trustQueue
, ^{
1965 CFReleaseNull(trust
->_exceptions
);
1972 SecTrustSetOptions(SecTrustRef trustRef
, SecTrustOptionFlags options
)
1974 /* bridge to support API functionality for legacy callers */
1975 OSStatus status
= errSecSuccess
;
1977 /* No options or none that trigger the exceptions behavior */
1979 0 == (options
& (kSecTrustOptionAllowExpired
|
1980 kSecTrustOptionImplicitAnchors
|
1981 kSecTrustOptionAllowExpiredRoot
))) {
1985 __block CFMutableArrayRef exceptions
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
1986 if (!exceptions
) { return errSecAllocate
; }
1988 /* Add the new options to the old_exceptions when those exceptions are tied to a particular cert.
1989 * If not tied to a particular cert, we reset the exceptions based on the input options. */
1990 CFArrayRef old_exceptions
= SecTrustGetTrustExceptionsArray(trustRef
);
1991 if (old_exceptions
&& SecTrustGetExceptionForCertificateAtIndex(trustRef
, 0)) {
1992 CFIndex ix
, count
= CFArrayGetCount(old_exceptions
);
1993 for (ix
= 0; ix
< count
; ix
++) {
1994 CFMutableDictionaryRef exception_dictionary
= CFDictionaryCreateMutableCopy(NULL
, 0, (CFDictionaryRef
)CFArrayGetValueAtIndex(old_exceptions
, ix
));
1995 if (!exception_dictionary
) { status
= errSecAllocate
; goto out
; }
1996 if ((options
& kSecTrustOptionAllowExpired
) != 0) {
1997 CFDictionaryAddValue(exception_dictionary
, kSecPolicyCheckTemporalValidity
, kCFBooleanFalse
);
1999 if ((options
& (kSecTrustOptionImplicitAnchors
| kSecTrustOptionAllowExpiredRoot
)) != 0) {
2000 /* Check that root is self-signed. */
2001 Boolean isSelfSigned
= false;
2002 SecCertificateRef cert
= SecTrustGetCertificateAtIndex(trustRef
, ix
);
2003 if (cert
&& (errSecSuccess
== SecCertificateIsSelfSigned(cert
, &isSelfSigned
)) &&
2005 if ((options
& kSecTrustOptionImplicitAnchors
) != 0) {
2006 CFDictionaryAddValue(exception_dictionary
, kSecPolicyCheckAnchorTrusted
, kCFBooleanFalse
);
2007 } else if ((options
& kSecTrustOptionAllowExpiredRoot
) != 0) {
2008 CFDictionaryAddValue(exception_dictionary
, kSecPolicyCheckTemporalValidity
, kCFBooleanFalse
);
2012 CFArrayAppendValue(exceptions
, exception_dictionary
);
2013 CFReleaseNull(exception_dictionary
);
2016 /* Create a new exceptions array. Warning, this takes advantage of implementation details of the exceptions mechanism. */
2017 CFMutableDictionaryRef exception_dictionary
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
,
2018 &kCFTypeDictionaryValueCallBacks
);
2019 if (!exception_dictionary
) { status
= errSecAllocate
; goto out
; }
2020 if ((options
& kSecTrustOptionAllowExpired
) != 0) {
2021 CFDictionaryAddValue(exception_dictionary
, kSecPolicyCheckTemporalValidity
, kCFBooleanFalse
);
2023 if ((options
& kSecTrustOptionAllowExpiredRoot
) != 0) {
2024 CFDictionaryAddValue(exception_dictionary
, kSecPolicyCheckValidRoot
, kCFBooleanFalse
);
2026 if ((options
& kSecTrustOptionImplicitAnchors
) != 0) {
2027 CFDictionaryAddValue(exception_dictionary
, kSecPolicyCheckAnchorTrusted
, kCFBooleanFalse
);
2029 CFArrayAppendValue(exceptions
, exception_dictionary
);
2030 CFReleaseNull(exception_dictionary
);
2033 /* Set exceptions */
2034 dispatch_sync(trustRef
->_trustQueue
, ^{
2035 CFReleaseSafe(trustRef
->_exceptions
);
2036 trustRef
->_exceptions
= CFRetainSafe(exceptions
);
2038 /* We changed the exceptions -- so we need to re-evaluate */
2039 SecTrustSetNeedsEvaluation(trustRef
);
2042 CFReleaseNull(exceptions
);
2047 CFArrayRef
SecTrustCopySummaryPropertiesAtIndex(SecTrustRef trust
, CFIndex ix
) {
2048 CFMutableArrayRef summary
;
2049 SecCertificateRef certificate
= SecTrustGetCertificateAtIndex(trust
, ix
);
2050 summary
= SecCertificateCopySummaryProperties(certificate
,
2051 SecTrustGetVerifyTime(trust
));
2052 /* FIXME Add more details in the failure case. */
2057 CFArrayRef
SecTrustCopyDetailedPropertiesAtIndex(SecTrustRef trust
, CFIndex ix
) {
2059 SecCertificateRef certificate
= SecTrustGetCertificateAtIndex(trust
, ix
);
2060 summary
= SecCertificateCopyProperties(certificate
);
2065 struct TrustFailures
{
2067 bool unknownCritExtn
;
2068 bool untrustedAnchor
;
2069 bool missingIntermediate
;
2070 bool hostnameMismatch
;
2078 static void applyDetailProperty(const void *_key
, const void *_value
,
2080 CFStringRef key
= (CFStringRef
)_key
;
2081 struct TrustFailures
*tf
= (struct TrustFailures
*)context
;
2082 if (CFGetTypeID(_value
) != CFBooleanGetTypeID()) {
2083 /* Value isn't a CFBooleanRef, oh no! */
2086 CFBooleanRef value
= (CFBooleanRef
)_value
;
2087 if (CFBooleanGetValue(value
)) {
2088 /* Not an actual failure so we don't report it. */
2092 /* @@@ FIXME: Report a different return value when something is in the
2093 details but masked out by an exception and use that below for display
2095 if (CFEqual(key
, kSecPolicyCheckIdLinkage
)) {
2096 tf
->badLinkage
= true;
2097 } else if (CFEqual(key
, kSecPolicyCheckCriticalExtensions
)) {
2098 tf
->unknownCritExtn
= true;
2099 } else if (CFEqual(key
, kSecPolicyCheckAnchorTrusted
)
2100 || CFEqual(key
, kSecPolicyCheckAnchorSHA1
)
2101 || CFEqual(key
, kSecPolicyCheckAnchorSHA256
)
2102 || CFEqual(key
, kSecPolicyCheckAnchorApple
)) {
2103 tf
->untrustedAnchor
= true;
2104 } else if (CFEqual(key
, kSecPolicyCheckMissingIntermediate
)) {
2105 tf
->missingIntermediate
= true;
2106 } else if (CFEqual(key
, kSecPolicyCheckSSLHostname
)) {
2107 tf
->hostnameMismatch
= true;
2108 } else if (CFEqual(key
, kSecPolicyCheckTemporalValidity
)) {
2109 tf
->invalidCert
= true;
2110 } else if (CFEqual(key
, kSecPolicyCheckWeakKeySize
)) {
2112 } else if (CFEqual(key
, kSecPolicyCheckWeakSignature
)) {
2113 tf
->weakHash
= true;
2114 } else if (CFEqual(key
, kSecPolicyCheckRevocation
)) {
2115 tf
->revocation
= true;
2117 /* Anything else is a policy failure. */
2119 if (CFEqual(key
, kSecPolicyCheckNonEmptySubject
)
2120 || CFEqual(key
, kSecPolicyCheckBasicConstraints
)
2121 || CFEqual(key
, kSecPolicyCheckKeyUsage
)
2122 || CFEqual(key
, kSecPolicyCheckExtendedKeyUsage
)
2123 || CFEqual(key
, kSecPolicyCheckIssuerCommonName
)
2124 || CFEqual(key
, kSecPolicyCheckSubjectCommonNamePrefix
)
2125 || CFEqual(key
, kSecPolicyCheckChainLength
)
2126 || CFEqual(key
, kSecPolicyCheckNotValidBefore
))
2129 tf
->policyFail
= true;
2133 static void appendError(CFMutableArrayRef properties
, CFStringRef error
, bool localized
) {
2134 CFStringRef localizedError
= NULL
;
2137 } else if (localized
) {
2138 //%%% "SecCertificate" should be changed to "Certificate": rdar://37517120
2139 localizedError
= SecFrameworkCopyLocalizedString(error
, CFSTR("SecCertificate"));
2141 localizedError
= (CFStringRef
) CFRetainSafe(error
);
2143 appendProperty(properties
, kSecPropertyTypeError
, NULL
, NULL
,
2144 localizedError
, localized
);
2145 CFReleaseNull(localizedError
);
2149 /* OS X properties array has a different structure and is implemented SecTrust.cpp. */
2150 CFArrayRef
SecTrustCopyProperties_ios(SecTrustRef trust
)
2152 CFArrayRef
SecTrustCopyProperties(SecTrustRef trust
)
2158 SecTrustEvaluateIfNecessary(trust
);
2159 bool localized
= true;
2160 __block CFArrayRef details
= NULL
;
2161 dispatch_sync(trust
->_trustQueue
, ^{
2162 details
= CFRetainSafe(trust
->_details
);
2167 struct TrustFailures tf
= {};
2169 CFIndex ix
, count
= CFArrayGetCount(details
);
2170 for (ix
= 0; ix
< count
; ++ix
) {
2171 CFDictionaryRef detail
= (CFDictionaryRef
)
2172 CFArrayGetValueAtIndex(details
, ix
);
2173 /* We now have a detail dictionary for certificate at index ix, with
2174 a key value pair for each failed policy check. Let's convert it
2175 from Ro-Man form into something a Hu-Man can understand. */
2176 CFDictionaryApplyFunction(detail
, applyDetailProperty
, &tf
);
2179 CFMutableArrayRef properties
= CFArrayCreateMutable(kCFAllocatorDefault
, 0,
2180 &kCFTypeArrayCallBacks
);
2181 /* The badLinkage and unknownCritExtn failures are short circuited, since
2182 you can't recover from those errors. */
2183 if (tf
.badLinkage
) {
2184 appendError(properties
, CFSTR("Invalid certificate chain linkage."), localized
);
2185 } else if (tf
.unknownCritExtn
) {
2186 appendError(properties
, CFSTR("One or more unsupported critical extensions found."), localized
);
2188 if (tf
.untrustedAnchor
) {
2189 appendError(properties
, CFSTR("Root certificate is not trusted."), localized
);
2191 if (tf
.missingIntermediate
) {
2192 appendError(properties
, CFSTR("Unable to build chain to root certificate."), localized
);
2194 if (tf
.hostnameMismatch
) {
2195 appendError(properties
, CFSTR("Hostname mismatch."), localized
);
2197 if (tf
.policyFail
) {
2198 appendError(properties
, CFSTR("Policy requirements not met."), localized
);
2200 if (tf
.invalidCert
) {
2201 appendError(properties
, CFSTR("One or more certificates have expired or are not valid yet."), localized
);
2204 appendError(properties
, CFSTR("One or more certificates is using a weak key size."), localized
);
2207 appendError(properties
, CFSTR("One or more certificates is using a weak signature algorithm."), localized
);
2209 if (tf
.revocation
) {
2210 appendError(properties
, CFSTR("One or more certificates have been revoked."), localized
);
2214 if (CFArrayGetCount(properties
) == 0) {
2215 /* The certificate chain is trusted, return an empty plist */
2216 CFReleaseNull(properties
);
2219 CFReleaseNull(details
);
2224 static void _AppendStatusCode(CFMutableArrayRef array
, OSStatus statusCode
) {
2228 SInt32 num
= statusCode
;
2229 CFNumberRef numRef
= CFNumberCreate(NULL
, kCFNumberSInt32Type
, &num
);
2233 CFArrayAppendValue(array
, numRef
);
2238 static CFArrayRef
_SecTrustCopyDetails(SecTrustRef trust
) {
2242 __block CFArrayRef details
= NULL
;
2243 dispatch_sync(trust
->_trustQueue
, ^{
2244 details
= CFRetainSafe(trust
->_details
);
2247 // Include status codes in the per-certificate details (rdar://27930542)
2248 CFMutableArrayRef newDetails
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
2250 CFReleaseSafe(details
);
2253 CFIndex index
, chainLen
= (details
) ? CFArrayGetCount(details
) : 0;
2254 for (index
= 0; index
< chainLen
; index
++) {
2255 CFDictionaryRef detailDict
= CFArrayGetValueAtIndex(details
, index
);
2256 CFMutableDictionaryRef newDict
= CFDictionaryCreateMutableCopy(NULL
, 0, detailDict
);
2257 CFMutableArrayRef statusCodes
= CFArrayCreateMutable(kCFAllocatorDefault
,
2258 0, &kCFTypeArrayCallBacks
);
2260 CFIndex i
, numCodes
= 0;
2261 SInt32
*codes
= SecTrustCopyStatusCodes(trust
, index
, &numCodes
);
2263 for (i
= 0; i
< numCodes
; i
++) {
2264 OSStatus scode
= (OSStatus
)codes
[i
];
2265 _AppendStatusCode(statusCodes
, scode
);
2269 if (CFArrayGetCount(statusCodes
) > 0) {
2270 CFDictionarySetValue(newDict
, kSecCertificateDetailStatusCodes
, statusCodes
);
2272 CFRelease(statusCodes
);
2275 CFArrayAppendValue(newDetails
, newDict
);
2279 CFReleaseSafe(details
);
2286 CFDictionaryRef
SecTrustCopyResult(SecTrustRef trust
) {
2287 // Builds and returns a dictionary of evaluation results.
2291 __block CFMutableDictionaryRef results
= CFDictionaryCreateMutable(NULL
, 0,
2292 &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
2294 SecTrustEvaluateIfNecessary(trust
);
2295 __block CFArrayRef details
= _SecTrustCopyDetails(trust
);
2297 dispatch_sync(trust
->_trustQueue
, ^{
2298 // kSecTrustResultDetails (per-cert results)
2300 CFDictionarySetValue(results
, (const void *)kSecTrustResultDetails
, (const void *)details
);
2304 // kSecTrustResultValue (overall trust result)
2305 CFNumberRef numValue
= CFNumberCreate(NULL
, kCFNumberSInt32Type
, &trust
->_trustResult
);
2307 CFDictionarySetValue(results
, (const void *)kSecTrustResultValue
, (const void *)numValue
);
2308 CFRelease(numValue
);
2310 CFDictionaryRef info
= trust
->_info
;
2311 if (trust
->_trustResult
== kSecTrustResultInvalid
|| !info
) {
2312 return; // we have nothing more to add
2315 // kSecTrustEvaluationDate
2316 CFDateRef evaluationDate
= trust
->_verifyDate
;
2317 if (evaluationDate
) {
2318 CFDictionarySetValue(results
, (const void *)kSecTrustEvaluationDate
, (const void *)evaluationDate
);
2321 // kSecTrustCertificateTransparency
2322 CFBooleanRef ctValue
;
2323 if (CFDictionaryGetValueIfPresent(info
, kSecTrustInfoCertificateTransparencyKey
, (const void **)&ctValue
)) {
2324 CFDictionarySetValue(results
, (const void *)kSecTrustCertificateTransparency
, (const void *)ctValue
);
2327 // kSecTrustExtendedValidation
2328 CFBooleanRef evValue
;
2329 if (CFDictionaryGetValueIfPresent(info
, kSecTrustInfoExtendedValidationKey
, (const void **)&evValue
)) {
2330 CFDictionarySetValue(results
, (const void *)kSecTrustExtendedValidation
, (const void *)evValue
);
2333 // kSecTrustOrganizationName
2334 CFStringRef organizationName
;
2335 if (CFDictionaryGetValueIfPresent(info
, kSecTrustInfoCompanyNameKey
, (const void **)&organizationName
)) {
2336 CFDictionarySetValue(results
, (const void *)kSecTrustOrganizationName
, (const void *)organizationName
);
2339 // kSecTrustRevocationChecked
2340 CFBooleanRef revocationChecked
;
2341 if (CFDictionaryGetValueIfPresent(info
, kSecTrustRevocationChecked
, (const void **)&revocationChecked
)) {
2342 CFDictionarySetValue(results
, (const void *)kSecTrustRevocationChecked
, (const void *)revocationChecked
);
2345 // kSecTrustRevocationReason
2346 CFNumberRef revocationReason
;
2347 if (CFDictionaryGetValueIfPresent(info
, kSecTrustRevocationReason
, (const void **)&revocationReason
)) {
2348 CFDictionarySetValue(results
, (const void *)kSecTrustRevocationReason
, (const void *)revocationReason
);
2351 // kSecTrustRevocationValidUntilDate
2352 CFDateRef validUntilDate
;
2353 if (CFDictionaryGetValueIfPresent(info
, kSecTrustRevocationValidUntilDate
, (const void **)&validUntilDate
)) {
2354 CFDictionarySetValue(results
, (const void *)kSecTrustRevocationValidUntilDate
, (const void *)validUntilDate
);
2361 #define do_if_registered(sdp, ...) if (gTrustd && gTrustd->sdp) { return gTrustd->sdp(__VA_ARGS__); }
2363 static bool xpc_dictionary_entry_is_type(xpc_object_t dictionary
, const char *key
, xpc_type_t type
) {
2364 xpc_object_t value
= xpc_dictionary_get_value(dictionary
, key
);
2365 return value
&& (xpc_get_type(value
) == type
);
2368 static uint64_t do_ota_pki_op (enum SecXPCOperation op
, CFErrorRef
*error
) {
2370 xpc_object_t message
= securityd_create_message(op
, error
);
2372 xpc_object_t response
= securityd_message_with_reply_sync(message
, error
);
2373 if (response
&& xpc_dictionary_entry_is_type(response
, kSecXPCKeyResult
, XPC_TYPE_UINT64
)) {
2374 num
= (int64_t) xpc_dictionary_get_uint64(response
, kSecXPCKeyResult
);
2376 if (response
&& error
&& xpc_dictionary_entry_is_type(response
, kSecXPCKeyError
, XPC_TYPE_DICTIONARY
)) {
2377 xpc_object_t xpc_error
= xpc_dictionary_get_value(response
, kSecXPCKeyError
);
2379 *error
= SecCreateCFErrorWithXPCObject(xpc_error
);
2382 xpc_release_safe(message
);
2383 xpc_release_safe(response
);
2389 // version 0 -> error, so we need to start at version 1 or later.
2390 uint64_t SecTrustGetTrustStoreVersionNumber(CFErrorRef
*error
) {
2391 do_if_registered(sec_ota_pki_trust_store_version
, error
);
2393 os_activity_t activity
= os_activity_create("SecTrustGetTrustStoreVersionNumber", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_DEFAULT
);
2394 os_activity_scope(activity
);
2396 uint64_t num
= do_ota_pki_op(sec_ota_pki_trust_store_version_id
, error
);
2398 os_release(activity
);
2402 uint64_t SecTrustGetAssetVersionNumber(CFErrorRef
*error
) {
2403 do_if_registered(sec_ota_pki_asset_version
, error
);
2405 os_activity_t activity
= os_activity_create("SecTrustGetAssetVersionNumber", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_DEFAULT
);
2406 os_activity_scope(activity
);
2408 uint64_t num
= do_ota_pki_op(sec_ota_pki_asset_version_id
, error
);
2410 os_release(activity
);
2414 uint64_t SecTrustOTAPKIGetUpdatedAsset(CFErrorRef
*error
) {
2415 do_if_registered(sec_ota_pki_get_new_asset
, error
);
2417 os_activity_t activity
= os_activity_create("SecTrustOTAPKIGetUpdatedAsset", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_DEFAULT
);
2418 os_activity_scope(activity
);
2420 uint64_t num
= do_ota_pki_op(kSecXPCOpOTAPKIGetNewAsset
, error
);
2422 os_release(activity
);
2426 bool SecTrustReportTLSAnalytics(CFStringRef eventName
, xpc_object_t eventAttributes
, CFErrorRef
*error
) {
2427 if (!eventName
|| !eventAttributes
) {
2430 do_if_registered(sec_networking_analytics_report
, eventName
, eventAttributes
, error
);
2432 os_activity_t activity
= os_activity_create("SecTrustReportTLSAnalytics", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_DEFAULT
);
2433 os_activity_scope(activity
);
2435 __block
bool result
= false;
2436 securityd_send_sync_and_do(kSecXPCOpNetworkingAnalyticsReport
, error
, ^bool(xpc_object_t message
, CFErrorRef
*block_error
) {
2437 if (!SecXPCDictionarySetString(message
, kSecTrustEventNameKey
, eventName
, block_error
)) {
2440 xpc_dictionary_set_value(message
, kSecTrustEventAttributesKey
, eventAttributes
);
2442 }, ^bool(xpc_object_t response
, CFErrorRef
*block_error
) {
2443 result
= SecXPCDictionaryGetBool(response
, kSecXPCKeyResult
, block_error
);
2447 os_release(activity
);
2451 bool SecTrustReportNetworkingAnalytics(const char *eventNameString
, xpc_object_t eventAttributes
) {
2452 if (!eventNameString
|| !eventAttributes
) {
2456 CFStringRef eventName
= CFStringCreateWithCString(kCFAllocatorDefault
, eventNameString
, kCFStringEncodingUTF8
);
2458 secerror("CFStringCreateWithCString failed");
2462 CFErrorRef error
= NULL
;
2463 if (gTrustd
&& gTrustd
->sec_networking_analytics_report
) {
2464 bool result
= gTrustd
->sec_networking_analytics_report(eventName
, eventAttributes
, &error
);
2465 if (error
!= NULL
) {
2466 secerror("SecTrustReportNetworkingAnalytics failed with error: %d", (int)CFErrorGetCode(error
));
2468 CFReleaseNull(eventName
);
2469 CFReleaseNull(error
);
2473 os_activity_t activity
= os_activity_create("SecTrustReportNetworkingAnalytics", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_DEFAULT
);
2474 os_activity_scope(activity
);
2476 __block
bool result
= false;
2477 securityd_send_sync_and_do(kSecXPCOpNetworkingAnalyticsReport
, &error
, ^bool(xpc_object_t message
, CFErrorRef
*block_error
) {
2478 if (!SecXPCDictionarySetString(message
, kSecTrustEventNameKey
, eventName
, block_error
)) {
2481 xpc_dictionary_set_value(message
, kSecTrustEventAttributesKey
, eventAttributes
);
2483 }, ^bool(xpc_object_t response
, CFErrorRef
*block_error
) {
2484 result
= SecXPCDictionaryGetBool(response
, kSecXPCKeyResult
, block_error
);
2488 if (error
!= NULL
) {
2489 secerror("SecTrustReportNetworkingAnalytics failed with error: %d", (int)CFErrorGetCode(error
));
2491 CFReleaseNull(error
);
2492 CFReleaseNull(eventName
);
2494 os_release(activity
);
2499 * This function performs an evaluation of the leaf certificate only, and
2500 * does so in the process that called it. Its primary use is in SecItemCopyMatching
2501 * when kSecMatchPolicy is in the dictionary.
2503 OSStatus
SecTrustEvaluateLeafOnly(SecTrustRef trust
, SecTrustResultType
*result
) {
2507 OSStatus status
= errSecSuccess
;
2508 SecTrustResultType trustResult
= kSecTrustResultInvalid
;
2509 if((status
= SecTrustValidateInput(trust
))) {
2513 struct OpaqueSecLeafPVC pvc
;
2514 SecCertificateRef leaf
= SecTrustGetCertificateAtIndex(trust
, 0);
2515 __block CFArrayRef policies
= NULL
;
2516 dispatch_sync(trust
->_trustQueue
, ^{
2517 policies
= CFRetainSafe(trust
->_policies
);
2519 SecLeafPVCInit(&pvc
, leaf
, policies
, SecTrustGetVerifyTime(trust
));
2521 if(!SecLeafPVCLeafChecks(&pvc
)) {
2522 trustResult
= kSecTrustResultRecoverableTrustFailure
;
2524 trustResult
= kSecTrustResultUnspecified
;
2527 /* Set other result context information */
2528 dispatch_sync(trust
->_trustQueue
, ^{
2529 trust
->_trustResult
= trustResult
;
2530 trust
->_details
= CFRetainSafe(pvc
.details
);
2531 trust
->_info
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0,
2532 &kCFTypeDictionaryKeyCallBacks
,
2533 &kCFTypeDictionaryValueCallBacks
);
2534 CFMutableArrayRef leafCert
= CFArrayCreateMutableCopy(NULL
, 1, trust
->_certificates
);
2535 trust
->_chain
= leafCert
;
2538 SecLeafPVCDelete(&pvc
);
2540 /* log to syslog when there is a trust failure */
2541 if (trustResult
!= kSecTrustResultUnspecified
) {
2542 CFStringRef failureDesc
= SecTrustCopyFailureDescription(trust
);
2543 secerror("%@", failureDesc
);
2544 CFRelease(failureDesc
);
2548 *result
= trustResult
;
2551 CFReleaseSafe(policies
);
2555 static void deserializeCert(const void *value
, void *context
) {
2556 CFDataRef certData
= (CFDataRef
)value
;
2557 if (isData(certData
)) {
2558 SecCertificateRef cert
= SecCertificateCreateWithData(NULL
, certData
);
2560 CFArrayAppendValue((CFMutableArrayRef
)context
, cert
);
2566 static CF_RETURNS_RETAINED CFArrayRef
SecCertificateArrayDeserialize(CFArrayRef serializedCertificates
) {
2567 CFMutableArrayRef result
= NULL
;
2568 require_quiet(isArray(serializedCertificates
), errOut
);
2569 CFIndex count
= CFArrayGetCount(serializedCertificates
);
2570 result
= CFArrayCreateMutable(kCFAllocatorDefault
, count
, &kCFTypeArrayCallBacks
);
2571 CFRange all_certs
= { 0, count
};
2572 CFArrayApplyFunction(serializedCertificates
, all_certs
, deserializeCert
, result
);
2577 static void serializeCertificate(const void *value
, void *context
) {
2578 SecCertificateRef cert
= (SecCertificateRef
)value
;
2579 if (cert
&& SecCertificateGetTypeID() == CFGetTypeID(cert
)) {
2580 CFDataRef certData
= SecCertificateCopyData(cert
);
2582 CFArrayAppendValue((CFMutableArrayRef
)context
, certData
);
2583 CFRelease(certData
);
2588 static CF_RETURNS_RETAINED CFArrayRef
SecCertificateArraySerialize(CFArrayRef certificates
) {
2589 CFMutableArrayRef result
= NULL
;
2590 require_quiet(isArray(certificates
), errOut
);
2591 CFIndex count
= CFArrayGetCount(certificates
);
2592 result
= CFArrayCreateMutable(NULL
, count
, &kCFTypeArrayCallBacks
);
2593 CFRange all_certificates
= { 0, count
};
2594 CFArrayApplyFunction(certificates
, all_certificates
, serializeCertificate
, result
);
2599 static CFPropertyListRef
SecTrustCopyPlist(SecTrustRef trust
) {
2600 __block CFMutableDictionaryRef output
= NULL
;
2601 output
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
,
2602 &kCFTypeDictionaryValueCallBacks
);
2604 dispatch_sync(trust
->_trustQueue
, ^{
2605 if (trust
->_certificates
) {
2606 CFArrayRef serializedCerts
= SecCertificateArraySerialize(trust
->_certificates
);
2607 if (serializedCerts
) {
2608 CFDictionaryAddValue(output
, CFSTR(kSecTrustCertificatesKey
), serializedCerts
);
2609 CFRelease(serializedCerts
);
2612 if (trust
->_anchors
) {
2613 CFArrayRef serializedAnchors
= SecCertificateArraySerialize(trust
->_anchors
);
2614 if (serializedAnchors
) {
2615 CFDictionaryAddValue(output
, CFSTR(kSecTrustAnchorsKey
), serializedAnchors
);
2616 CFRelease(serializedAnchors
);
2619 if (trust
->_policies
) {
2620 CFArrayRef serializedPolicies
= SecPolicyArrayCreateSerialized(trust
->_policies
);
2621 if (serializedPolicies
) {
2622 CFDictionaryAddValue(output
, CFSTR(kSecTrustPoliciesKey
), serializedPolicies
);
2623 CFRelease(serializedPolicies
);
2626 if (trust
->_responses
) {
2627 CFDictionaryAddValue(output
, CFSTR(kSecTrustResponsesKey
), trust
->_responses
);
2630 CFDictionaryAddValue(output
, CFSTR(kSecTrustSCTsKey
), trust
->_SCTs
);
2632 if (trust
->_trustedLogs
) {
2633 CFDictionaryAddValue(output
, CFSTR(kSecTrustTrustedLogsKey
), trust
->_trustedLogs
);
2635 if (trust
->_verifyDate
) {
2636 CFDictionaryAddValue(output
, CFSTR(kSecTrustVerifyDateKey
), trust
->_verifyDate
);
2638 if (trust
->_chain
) {
2639 CFArrayRef serializedCerts
= SecCertificateArraySerialize(trust
->_chain
);
2640 if (serializedCerts
) {
2641 CFDictionaryAddValue(output
, CFSTR(kSecTrustChainKey
), serializedCerts
);
2642 CFRelease(serializedCerts
);
2645 if (trust
->_details
) {
2646 CFDictionaryAddValue(output
, CFSTR(kSecTrustDetailsKey
), trust
->_details
);
2649 CFDictionaryAddValue(output
, CFSTR(kSecTrustInfoKey
), trust
->_info
);
2651 if (trust
->_exceptions
) {
2652 CFDictionaryAddValue(output
, CFSTR(kSecTrustExceptionsKey
), trust
->_exceptions
);
2654 CFNumberRef trustResult
= CFNumberCreate(NULL
, kCFNumberSInt32Type
, &trust
->_trustResult
);
2656 CFDictionaryAddValue(output
, CFSTR(kSecTrustResultKey
), trustResult
);
2658 CFReleaseNull(trustResult
);
2659 if (trust
->_anchorsOnly
) {
2660 CFDictionaryAddValue(output
, CFSTR(kSecTrustAnchorsOnlyKey
), kCFBooleanTrue
);
2662 CFDictionaryAddValue(output
, CFSTR(kSecTrustAnchorsOnlyKey
), kCFBooleanFalse
);
2664 if (trust
->_keychainsAllowed
) {
2665 CFDictionaryAddValue(output
, CFSTR(kSecTrustKeychainsAllowedKey
), kCFBooleanTrue
);
2667 CFDictionaryAddValue(output
, CFSTR(kSecTrustKeychainsAllowedKey
), kCFBooleanFalse
);
2674 CFDataRef
SecTrustSerialize(SecTrustRef trust
, CFErrorRef
*error
) {
2675 CFPropertyListRef plist
= NULL
;
2676 CFDataRef derTrust
= NULL
;
2677 require_action_quiet(trust
, out
,
2678 SecError(errSecParam
, error
, CFSTR("null trust input")));
2679 require_action_quiet(plist
= SecTrustCopyPlist(trust
), out
,
2680 SecError(errSecDecode
, error
, CFSTR("unable to create trust plist")));
2681 require_quiet(derTrust
= CFPropertyListCreateDERData(NULL
, plist
, error
), out
);
2684 CFReleaseNull(plist
);
2688 static OSStatus
SecTrustCreateFromPlist(CFPropertyListRef plist
, SecTrustRef CF_RETURNS_RETAINED
*trust
) {
2689 OSStatus status
= errSecParam
;
2690 SecTrustRef output
= NULL
;
2691 CFTypeRef serializedCertificates
= NULL
, serializedPolicies
= NULL
, serializedAnchors
= NULL
;
2692 CFNumberRef trustResultNum
= NULL
;
2693 CFArrayRef certificates
= NULL
, policies
= NULL
, anchors
= NULL
, responses
= NULL
,
2694 SCTs
= NULL
, trustedLogs
= NULL
, details
= NULL
, exceptions
= NULL
, chain
= NULL
;
2695 CFDateRef verifyDate
= NULL
;
2696 CFDictionaryRef info
= NULL
;
2698 require_quiet(CFDictionaryGetTypeID() == CFGetTypeID(plist
), out
);
2699 require_quiet(serializedCertificates
= CFDictionaryGetValue(plist
, CFSTR(kSecTrustCertificatesKey
)), out
);
2700 require_quiet(certificates
= SecCertificateArrayDeserialize(serializedCertificates
), out
);
2701 require_quiet(serializedPolicies
= CFDictionaryGetValue(plist
, CFSTR(kSecTrustPoliciesKey
)), out
);
2702 require_quiet(policies
= SecPolicyArrayCreateDeserialized(serializedPolicies
), out
);
2703 require_noerr_quiet(status
= SecTrustCreateWithCertificates(certificates
, policies
, &output
), out
);
2705 serializedAnchors
= CFDictionaryGetValue(plist
, CFSTR(kSecTrustAnchorsKey
));
2706 if (isArray(serializedAnchors
)) {
2707 anchors
= SecCertificateArrayDeserialize(serializedAnchors
);
2708 output
->_anchors
= anchors
;
2710 responses
= CFDictionaryGetValue(plist
, CFSTR(kSecTrustResponsesKey
));
2711 if (isArray(responses
)) {
2712 output
->_responses
= CFRetainSafe(responses
);
2714 SCTs
= CFDictionaryGetValue(plist
, CFSTR(kSecTrustSCTsKey
));
2715 if (isArray(SCTs
)) {
2716 output
->_SCTs
= CFRetainSafe(SCTs
);
2718 trustedLogs
= CFDictionaryGetValue(plist
, CFSTR(kSecTrustTrustedLogsKey
));
2719 if (isArray(trustedLogs
)) {
2720 output
->_trustedLogs
= CFRetainSafe(trustedLogs
);
2722 verifyDate
= CFDictionaryGetValue(plist
, CFSTR(kSecTrustVerifyDateKey
));
2723 if (isDate(verifyDate
)) {
2724 output
->_verifyDate
= CFRetainSafe(verifyDate
);
2726 chain
= CFDictionaryGetValue(plist
, CFSTR(kSecTrustChainKey
));
2727 if (isArray(chain
)) {
2728 output
->_chain
= SecCertificateArrayDeserialize(chain
);
2730 details
= CFDictionaryGetValue(plist
, CFSTR(kSecTrustDetailsKey
));
2731 if (isArray(details
)) {
2732 output
->_details
= CFRetainSafe(details
);
2734 info
= CFDictionaryGetValue(plist
, CFSTR(kSecTrustInfoKey
));
2735 if (isDictionary(info
)) {
2736 output
->_info
= CFRetainSafe(info
);
2738 exceptions
= CFDictionaryGetValue(plist
, CFSTR(kSecTrustExceptionsKey
));
2739 if (isArray(exceptions
)) {
2740 output
->_exceptions
= CFRetainSafe(exceptions
);
2742 int32_t trustResult
= -1;
2743 trustResultNum
= CFDictionaryGetValue(plist
, CFSTR(kSecTrustResultKey
));
2744 if (isNumber(trustResultNum
) && CFNumberGetValue(trustResultNum
, kCFNumberSInt32Type
, &trustResult
) &&
2745 (trustResult
>= 0)) {
2746 output
->_trustResult
= trustResult
;
2748 status
= errSecParam
;
2750 if (CFDictionaryGetValue(plist
, CFSTR(kSecTrustAnchorsOnlyKey
)) == kCFBooleanTrue
) {
2751 output
->_anchorsOnly
= true;
2752 } /* false is set by default */
2753 if (CFDictionaryGetValue(plist
, CFSTR(kSecTrustKeychainsAllowedKey
)) == kCFBooleanFalse
) {
2754 output
->_keychainsAllowed
= false;
2755 } /* true is set by default */
2758 if (errSecSuccess
== status
&& trust
) {
2761 CFReleaseNull(policies
);
2762 CFReleaseNull(certificates
);
2766 SecTrustRef
SecTrustDeserialize(CFDataRef serializedTrust
, CFErrorRef
*error
) {
2767 SecTrustRef trust
= NULL
;
2768 CFPropertyListRef plist
= NULL
;
2769 OSStatus status
= errSecSuccess
;
2770 require_action_quiet(serializedTrust
, out
,
2771 SecError(errSecParam
, error
, CFSTR("null serialized trust input")));
2772 require_quiet(plist
= CFPropertyListCreateWithDERData(NULL
, serializedTrust
,
2773 kCFPropertyListImmutable
, NULL
, error
), out
);
2774 require_noerr_action_quiet(status
= SecTrustCreateFromPlist(plist
, &trust
), out
,
2775 SecError(status
, error
, CFSTR("unable to create trust ref")));
2778 CFReleaseNull(plist
);