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 "trust/trustd/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 (kSecCertificateExceptionResetCount
, "ExceptionResetCount");
80 SEC_CONST_DECL (kSecTrustInfoExtendedValidationKey
, "ExtendedValidation");
81 SEC_CONST_DECL (kSecTrustInfoCompanyNameKey
, "CompanyName");
82 SEC_CONST_DECL (kSecTrustInfoRevocationKey
, "Revocation");
83 SEC_CONST_DECL (kSecTrustInfoRevocationValidUntilKey
, "RevocationValidUntil");
84 SEC_CONST_DECL (kSecTrustInfoCertificateTransparencyKey
, "CertificateTransparency");
86 /* Public trust result constants */
87 SEC_CONST_DECL (kSecTrustEvaluationDate
, "TrustEvaluationDate");
88 SEC_CONST_DECL (kSecTrustExtendedValidation
, "TrustExtendedValidation");
89 SEC_CONST_DECL (kSecTrustOrganizationName
, "Organization");
90 SEC_CONST_DECL (kSecTrustResultValue
, "TrustResultValue");
91 SEC_CONST_DECL (kSecTrustRevocationChecked
, "TrustRevocationChecked");
92 SEC_CONST_DECL (kSecTrustRevocationReason
, "TrustRevocationReason");
93 SEC_CONST_DECL (kSecTrustRevocationValidUntilDate
, "TrustExpirationDate");
94 SEC_CONST_DECL (kSecTrustResultDetails
, "TrustResultDetails");
95 SEC_CONST_DECL (kSecTrustCertificateTransparency
, "TrustCertificateTransparency");
96 SEC_CONST_DECL (kSecTrustCertificateTransparencyWhiteList
, "TrustCertificateTransparencyWhiteList");
101 /********************************************************
102 ****************** SecTrust object *********************
103 ********************************************************/
106 CFArrayRef _certificates
;
109 CFArrayRef _responses
;
111 CFArrayRef _trustedLogs
;
112 CFDateRef _verifyDate
;
114 SecKeyRef _publicKey
;
116 CFDictionaryRef _info
;
117 CFArrayRef _exceptions
;
119 /* Note that a value of kSecTrustResultInvalid (0)
120 * indicates the trust must be (re)evaluated; any
121 * functions which modify trust parameters in a way
122 * that would invalidate the current result must set
123 * this value back to kSecTrustResultInvalid.
125 SecTrustResultType _trustResult
;
127 /* If true we don't trust any anchors other than the ones in _anchors. */
129 /* If false we shouldn't search keychains for parents or anchors. */
130 bool _keychainsAllowed
;
132 /* Data blobs for legacy CSSM_TP_APPLE_EVIDENCE_INFO structure,
133 * to support callers of SecTrustGetResult on OS X. Since fields of
134 * one structure contain pointers into the other, these cannot be
135 * serialized; if a SecTrust is being serialized or copied, these values
136 * should just be initialized to NULL in the copy and built when needed. */
137 void* _legacy_info_array
;
138 void* _legacy_status_array
;
140 /* Dispatch queue for thread-safety */
141 dispatch_queue_t _trustQueue
;
143 /* === IMPORTANT! ===
144 * Any change to this structure definition
145 * must also be made in the TSecTrust structure,
146 * located in SecTrust.cpp. To avoid problems,
147 * new fields should always be appended at the
148 * end of the structure.
152 /* Forward declarations of static functions. */
153 static OSStatus
SecTrustEvaluateIfNecessary(SecTrustRef trust
);
154 static void SecTrustEvaluateIfNecessaryFastAsync(SecTrustRef trust
,
155 dispatch_queue_t queue
,
156 void (^handler
)(OSStatus status
));
158 /* Static functions. */
159 static CFStringRef
SecTrustCopyFormatDescription(CFTypeRef cf
, CFDictionaryRef formatOptions
) {
160 SecTrustRef trust
= (SecTrustRef
)cf
;
161 return CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
,
162 CFSTR("<SecTrustRef: %p>"), trust
);
165 static void SecTrustDestroy(CFTypeRef cf
) {
166 SecTrustRef trust
= (SecTrustRef
)cf
;
168 dispatch_release_null(trust
->_trustQueue
);
169 CFReleaseNull(trust
->_certificates
);
170 CFReleaseNull(trust
->_policies
);
171 CFReleaseNull(trust
->_responses
);
172 CFReleaseNull(trust
->_SCTs
);
173 CFReleaseNull(trust
->_trustedLogs
);
174 CFReleaseNull(trust
->_verifyDate
);
175 CFReleaseNull(trust
->_anchors
);
176 CFReleaseNull(trust
->_chain
);
177 CFReleaseNull(trust
->_publicKey
);
178 CFReleaseNull(trust
->_details
);
179 CFReleaseNull(trust
->_info
);
180 CFReleaseNull(trust
->_exceptions
);
182 if (trust
->_legacy_info_array
) {
183 free(trust
->_legacy_info_array
);
185 if (trust
->_legacy_status_array
) {
186 free(trust
->_legacy_status_array
);
190 /* Public API functions. */
191 CFGiblisFor(SecTrust
)
193 OSStatus
SecTrustCreateWithCertificates(CFTypeRef certificates
,
194 CFTypeRef policies
, SecTrustRef
*trust
) {
195 OSStatus status
= errSecParam
;
196 CFAllocatorRef allocator
= kCFAllocatorDefault
;
197 CFArrayRef l_certs
= NULL
, l_policies
= NULL
;
198 SecTrustRef result
= NULL
;
199 dispatch_queue_t queue
= NULL
;
203 CFTypeID certType
= CFGetTypeID(certificates
);
204 if (certType
== CFArrayGetTypeID()) {
205 CFIndex idx
, count
= CFArrayGetCount(certificates
);
206 /* We need at least 1 certificate. */
207 require_quiet(count
> 0, errOut
);
208 l_certs
= (CFArrayRef
) CFArrayCreateMutable(allocator
, count
,
209 &kCFTypeArrayCallBacks
);
211 status
= errSecAllocate
;
214 for (idx
= 0; idx
< count
; idx
++) {
215 CFTypeRef val
= CFArrayGetValueAtIndex(certificates
, idx
);
216 if (val
&& CFGetTypeID(val
) == SecCertificateGetTypeID()) {
217 CFArrayAppendValue((CFMutableArrayRef
)l_certs
, val
);
219 secerror("BUG IN SECURITY CLIENT: certificates array contains non-certificate value");
222 require_quiet(count
== CFArrayGetCount(l_certs
), errOut
);
223 } else if (certType
== SecCertificateGetTypeID()) {
224 l_certs
= CFArrayCreate(allocator
, &certificates
, 1,
225 &kCFTypeArrayCallBacks
);
227 secerror("BUG IN SECURITY CLIENT: certificates contains unsupported value type");
231 status
= errSecAllocate
;
236 CFTypeRef policy
= SecPolicyCreateBasicX509();
237 l_policies
= CFArrayCreate(allocator
, &policy
, 1,
238 &kCFTypeArrayCallBacks
);
240 } else if (CFGetTypeID(policies
) == CFArrayGetTypeID()) {
241 CFIndex idx
, count
= CFArrayGetCount(policies
);
242 /* We need at least 1 policy. */
243 require_quiet(count
> 0, errOut
);
244 l_policies
= (CFArrayRef
) CFArrayCreateMutable(allocator
, count
,
245 &kCFTypeArrayCallBacks
);
247 status
= errSecAllocate
;
250 for (idx
= 0; idx
< count
; idx
++) {
251 CFTypeRef val
= CFArrayGetValueAtIndex(policies
, idx
);
252 if (val
&& CFGetTypeID(val
) == SecPolicyGetTypeID()) {
253 CFArrayAppendValue((CFMutableArrayRef
)l_policies
, val
);
255 secerror("BUG IN SECURITY CLIENT: policies array contains non-policy value");
258 require_quiet(count
== CFArrayGetCount(l_policies
), errOut
);
259 } else if (CFGetTypeID(policies
) == SecPolicyGetTypeID()) {
260 l_policies
= CFArrayCreate(allocator
, &policies
, 1,
261 &kCFTypeArrayCallBacks
);
263 secerror("BUG IN SECURITY CLIENT: policies contains unsupported value type");
267 status
= errSecAllocate
;
271 queue
= dispatch_queue_create("trust", DISPATCH_QUEUE_SERIAL
);
273 status
= errSecAllocate
;
277 CFIndex size
= sizeof(struct __SecTrust
);
278 require_quiet(result
= (SecTrustRef
)_CFRuntimeCreateInstance(allocator
,
279 SecTrustGetTypeID(), size
- sizeof(CFRuntimeBase
), 0), errOut
);
280 memset((char*)result
+ sizeof(result
->_base
), 0,
281 sizeof(*result
) - sizeof(result
->_base
));
282 status
= errSecSuccess
;
286 CFReleaseSafe(result
);
287 CFReleaseSafe(l_certs
);
288 CFReleaseSafe(l_policies
);
289 dispatch_release_null(queue
);
291 result
->_certificates
= l_certs
;
292 result
->_policies
= l_policies
;
293 result
->_keychainsAllowed
= true;
294 result
->_trustQueue
= queue
;
298 CFReleaseSafe(result
);
303 OSStatus
SecTrustCopyInputCertificates(SecTrustRef trust
, CFArrayRef
*certificates
) {
304 if (!trust
|| !certificates
) {
307 __block CFArrayRef certArray
= NULL
;
308 dispatch_sync(trust
->_trustQueue
, ^{
309 certArray
= CFArrayCreateCopy(NULL
, trust
->_certificates
);
312 return errSecAllocate
;
314 *certificates
= certArray
;
315 return errSecSuccess
;
318 OSStatus
SecTrustAddToInputCertificates(SecTrustRef trust
, CFTypeRef certificates
) {
319 if (!trust
|| !certificates
) {
322 __block CFMutableArrayRef newCertificates
= NULL
;
323 dispatch_sync(trust
->_trustQueue
, ^{
324 newCertificates
= CFArrayCreateMutableCopy(NULL
, 0, trust
->_certificates
);
327 if (isArray(certificates
)) {
328 CFIndex originalCount
= CFArrayGetCount(newCertificates
);
329 CFArrayForEach(certificates
, ^(const void *value
) {
330 if (CFGetTypeID(value
) == SecCertificateGetTypeID()) {
331 CFArrayAppendValue(newCertificates
, value
);
333 secerror("BUG IN SECURITY CLIENT: certificates array contains non-certificate value");
336 if (CFArrayGetCount(newCertificates
) != originalCount
+ CFArrayGetCount(certificates
)) {
337 CFReleaseNull(newCertificates
);
340 } else if (CFGetTypeID(certificates
) == SecCertificateGetTypeID()) {
341 CFArrayAppendValue(newCertificates
, certificates
);
343 secerror("BUG IN SECURITY CLIENT: certificates contains unsupported value type");
344 CFReleaseNull(newCertificates
);
348 dispatch_sync(trust
->_trustQueue
, ^{
349 CFReleaseNull(trust
->_certificates
);
350 trust
->_certificates
= (CFArrayRef
)newCertificates
;
353 return errSecSuccess
;
356 void SecTrustSetNeedsEvaluation(SecTrustRef trust
) {
359 dispatch_sync(trust
->_trustQueue
, ^{
360 trust
->_trustResult
= kSecTrustResultInvalid
;
365 OSStatus
SecTrustSetAnchorCertificatesOnly(SecTrustRef trust
,
366 Boolean anchorCertificatesOnly
) {
370 SecTrustSetNeedsEvaluation(trust
);
371 dispatch_sync(trust
->_trustQueue
, ^{
372 trust
->_anchorsOnly
= anchorCertificatesOnly
;
375 return errSecSuccess
;
378 OSStatus
SecTrustSetAnchorCertificates(SecTrustRef trust
,
379 CFArrayRef anchorCertificates
) {
383 SecTrustSetNeedsEvaluation(trust
);
384 __block CFArrayRef anchorsArray
= NULL
;
385 if (anchorCertificates
) {
386 if (CFGetTypeID(anchorCertificates
) == CFArrayGetTypeID()) {
387 CFIndex idx
, count
= CFArrayGetCount(anchorCertificates
);
388 anchorsArray
= (CFArrayRef
) CFArrayCreateMutable(NULL
, count
,
389 &kCFTypeArrayCallBacks
);
391 return errSecAllocate
;
393 for (idx
= 0; idx
< count
; idx
++) {
394 CFTypeRef val
= CFArrayGetValueAtIndex(anchorCertificates
, idx
);
395 if (val
&& CFGetTypeID(val
) == SecCertificateGetTypeID()) {
396 CFArrayAppendValue((CFMutableArrayRef
)anchorsArray
, val
);
398 secerror("BUG IN SECURITY CLIENT: anchorCertificates array contains non-certificate value");
401 if (count
!= CFArrayGetCount(anchorsArray
)) {
402 CFReleaseSafe(anchorsArray
);
410 dispatch_sync(trust
->_trustQueue
, ^{
411 CFReleaseSafe(trust
->_anchors
);
412 trust
->_anchors
= anchorsArray
;
413 trust
->_anchorsOnly
= (anchorCertificates
!= NULL
);
416 return errSecSuccess
;
419 OSStatus
SecTrustCopyCustomAnchorCertificates(SecTrustRef trust
,
420 CFArrayRef
*anchors
) {
421 if (!trust
|| !anchors
) {
424 __block CFArrayRef anchorsArray
= NULL
;
425 dispatch_sync(trust
->_trustQueue
, ^{
426 if (trust
->_anchors
) {
427 anchorsArray
= CFArrayCreateCopy(kCFAllocatorDefault
, trust
->_anchors
);
431 *anchors
= anchorsArray
;
432 return errSecSuccess
;
435 // Return false on error, true on success.
436 static bool to_bool_error_request(enum SecXPCOperation op
, CFErrorRef
*error
) {
437 __block
bool result
= false;
438 securityd_send_sync_and_do(op
, error
, NULL
, ^bool(xpc_object_t response
, CFErrorRef
*blockError
) {
439 result
= !(blockError
&& *blockError
);
445 Boolean
SecTrustFlushResponseCache(CFErrorRef
*error
) {
446 CFErrorRef localError
= NULL
;
447 os_activity_t activity
= os_activity_create("SecTrustFlushResponseCache", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_DEFAULT
);
448 os_activity_scope(activity
);
449 bool result
= TRUSTD_XPC(sec_ocsp_cache_flush
, to_bool_error_request
, &localError
);
450 os_release(activity
);
453 } else if (localError
) {
454 CFRelease(localError
);
459 OSStatus
SecTrustSetOCSPResponse(SecTrustRef trust
, CFTypeRef responseData
) {
463 SecTrustSetNeedsEvaluation(trust
);
464 __block CFArrayRef responseArray
= NULL
;
466 if (CFGetTypeID(responseData
) == CFArrayGetTypeID()) {
467 CFIndex idx
, count
= CFArrayGetCount(responseData
);
468 responseArray
= (CFArrayRef
) CFArrayCreateMutable(NULL
, count
,
469 &kCFTypeArrayCallBacks
);
470 if (!responseArray
) {
471 return errSecAllocate
;
473 for (idx
= 0; idx
< count
; idx
++) {
474 CFTypeRef val
= CFArrayGetValueAtIndex(responseData
, idx
);
476 CFArrayAppendValue((CFMutableArrayRef
)responseArray
, val
);
478 secerror("BUG IN SECURITY CLIENT: responseData array contains non-data value");
481 if (count
!= CFArrayGetCount(responseArray
)) {
482 CFReleaseSafe(responseArray
);
485 } else if (CFGetTypeID(responseData
) == CFDataGetTypeID()) {
486 responseArray
= CFArrayCreate(kCFAllocatorDefault
, &responseData
, 1,
487 &kCFTypeArrayCallBacks
);
489 secerror("BUG IN SECURITY CLIENT: responseData contains unsupported value type");
494 dispatch_sync(trust
->_trustQueue
, ^{
495 CFReleaseSafe(trust
->_responses
);
496 trust
->_responses
= responseArray
;
499 return errSecSuccess
;
502 OSStatus
SecTrustSetSignedCertificateTimestamps(SecTrustRef trust
, CFArrayRef sctArray
) {
506 SecTrustSetNeedsEvaluation(trust
);
507 dispatch_sync(trust
->_trustQueue
, ^{
508 CFRetainAssign(trust
->_SCTs
, sctArray
);
510 return errSecSuccess
;
513 OSStatus
SecTrustSetTrustedLogs(SecTrustRef trust
, CFArrayRef trustedLogs
) {
517 SecTrustSetNeedsEvaluation(trust
);
518 dispatch_sync(trust
->_trustQueue
, ^{
519 CFRetainAssign(trust
->_trustedLogs
, trustedLogs
);
521 return errSecSuccess
;
524 OSStatus
SecTrustSetVerifyDate(SecTrustRef trust
, CFDateRef verifyDate
) {
525 if (!trust
|| !isDate(verifyDate
)) {
528 SecTrustSetNeedsEvaluation(trust
);
529 dispatch_sync(trust
->_trustQueue
, ^{
530 CFRetainAssign(trust
->_verifyDate
, verifyDate
);
532 return errSecSuccess
;
535 OSStatus
SecTrustSetPolicies(SecTrustRef trust
, CFTypeRef newPolicies
) {
536 if (!trust
|| !newPolicies
) {
539 SecTrustSetNeedsEvaluation(trust
);
542 __block CFArrayRef policyArray
= NULL
;
543 if (CFGetTypeID(newPolicies
) == CFArrayGetTypeID()) {
544 CFIndex idx
, count
= CFArrayGetCount(newPolicies
);
545 /* We need at least 1 policy. */
549 policyArray
= (CFArrayRef
) CFArrayCreateMutable(NULL
, count
,
550 &kCFTypeArrayCallBacks
);
552 return errSecAllocate
;
554 for (idx
= 0; idx
< count
; idx
++) {
555 CFTypeRef val
= CFArrayGetValueAtIndex(newPolicies
, idx
);
556 if (val
&& CFGetTypeID(val
) == SecPolicyGetTypeID()) {
557 CFArrayAppendValue((CFMutableArrayRef
)policyArray
, val
);
559 secerror("BUG IN SECURITY CLIENT: newPolicies array contains non-policy value");
562 if (count
!= CFArrayGetCount(policyArray
)) {
563 CFReleaseSafe(policyArray
);
566 } else if (CFGetTypeID(newPolicies
) == SecPolicyGetTypeID()) {
567 policyArray
= CFArrayCreate(kCFAllocatorDefault
, &newPolicies
, 1,
568 &kCFTypeArrayCallBacks
);
570 secerror("BUG IN SECURITY CLIENT: newPolicies contains unsupported value type");
574 dispatch_sync(trust
->_trustQueue
, ^{
575 CFReleaseSafe(trust
->_policies
);
576 trust
->_policies
= policyArray
;
579 return errSecSuccess
;
582 OSStatus
SecTrustSetPinningPolicyName(SecTrustRef trust
, CFStringRef policyName
) {
583 if (!trust
|| !policyName
) {
587 SecTrustSetNeedsEvaluation(trust
);
589 dispatch_sync(trust
->_trustQueue
, ^{
590 CFArrayForEach(trust
->_policies
, ^(const void *value
) {
591 SecPolicyRef policy
= (SecPolicyRef
)value
;
592 SecPolicySetName(policy
, policyName
);
593 secinfo("SecPinningDb", "Set %@ as name on all policies", policyName
);
596 return errSecSuccess
;
599 OSStatus
SecTrustSetKeychainsAllowed(SecTrustRef trust
, Boolean allowed
) {
603 SecTrustSetNeedsEvaluation(trust
);
604 dispatch_sync(trust
->_trustQueue
, ^{
605 trust
->_keychainsAllowed
= allowed
;
608 return errSecSuccess
;
611 OSStatus
SecTrustGetKeychainsAllowed(SecTrustRef trust
, Boolean
*allowed
) {
612 if (!trust
|| !allowed
) {
615 *allowed
= trust
->_keychainsAllowed
;
617 return errSecSuccess
;
620 OSStatus
SecTrustCopyPolicies(SecTrustRef trust
, CFArrayRef
*policies
) {
621 if (!trust
|| !policies
) {
624 __block CFArrayRef policyArray
= NULL
;
625 dispatch_sync(trust
->_trustQueue
, ^{
626 policyArray
= CFArrayCreateCopy(kCFAllocatorDefault
, trust
->_policies
);
629 return errSecAllocate
;
631 *policies
= policyArray
;
632 return errSecSuccess
;
635 static OSStatus
SecTrustSetOptionInPolicies(CFArrayRef policies
, CFStringRef key
, CFTypeRef value
) {
636 OSStatus status
= errSecSuccess
;
637 require_action(policies
&& CFGetTypeID(policies
) == CFArrayGetTypeID(), out
, status
= errSecInternal
);
638 for (int i
=0; i
< CFArrayGetCount(policies
); i
++) {
639 SecPolicyRef policy
= NULL
;
640 require_action_quiet(policy
= (SecPolicyRef
)CFArrayGetValueAtIndex(policies
, i
), out
, status
= errSecInternal
);
641 CFMutableDictionaryRef options
= NULL
;
642 require_action_quiet(options
= CFDictionaryCreateMutableCopy(NULL
, 0, policy
->_options
), out
, status
= errSecAllocate
);
643 CFDictionarySetValue(options
, key
, value
);
644 CFReleaseNull(policy
->_options
);
645 policy
->_options
= options
;
651 static OSStatus
SecTrustRemoveOptionInPolicies(CFArrayRef policies
, CFStringRef key
) {
652 OSStatus status
= errSecSuccess
;
653 require_action(policies
&& CFGetTypeID(policies
) == CFArrayGetTypeID(), out
, status
= errSecInternal
);
654 for (int i
=0; i
< CFArrayGetCount(policies
); i
++) {
655 SecPolicyRef policy
= NULL
;
656 require_action_quiet(policy
= (SecPolicyRef
)CFArrayGetValueAtIndex(policies
, i
), out
, status
= errSecInternal
);
657 if (CFDictionaryGetValue(policy
->_options
, key
)) {
658 CFMutableDictionaryRef options
= NULL
;
659 require_action_quiet(options
= CFDictionaryCreateMutableCopy(NULL
, 0, policy
->_options
), out
, status
= errSecAllocate
);
660 CFDictionaryRemoveValue(options
, key
);
661 CFReleaseNull(policy
->_options
);
662 policy
->_options
= options
;
669 static CF_RETURNS_RETAINED CFArrayRef
SecTrustCopyOptionsFromPolicies(CFArrayRef policies
, CFStringRef key
) {
670 CFMutableArrayRef foundValues
= NULL
;
671 foundValues
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
672 for (int i
=0; i
< CFArrayGetCount(policies
); i
++) {
673 SecPolicyRef policy
= (SecPolicyRef
)CFArrayGetValueAtIndex(policies
, i
);
674 CFTypeRef value
= CFDictionaryGetValue(policy
->_options
, key
);
676 CFArrayAppendValue(foundValues
, value
);
679 if (!CFArrayGetCount(foundValues
)) {
680 CFReleaseNull(foundValues
);
688 /* The only effective way to disable network fetch is within the policy options:
689 * presence of the kSecPolicyCheckNoNetworkAccess key in any of the policies
690 * will prevent network access for fetching.
691 * The current SecTrustServer implementation doesn't distinguish between network
692 * access for revocation and network access for fetching.
694 OSStatus
SecTrustSetNetworkFetchAllowed(SecTrustRef trust
, Boolean allowFetch
) {
698 __block OSStatus status
= errSecSuccess
;
699 __block
bool oldAllowFetch
= true;
700 dispatch_sync(trust
->_trustQueue
, ^{
701 CFArrayRef foundValues
= SecTrustCopyOptionsFromPolicies(trust
->_policies
, kSecPolicyCheckNoNetworkAccess
);
703 /* We only disable fetch if there is a policy option set for NoNetworkAccess, so the old fetch
704 * status was false (don't allow network) if we find this option set in the policies. */
705 oldAllowFetch
= false;
706 CFReleaseNull(foundValues
);
709 status
= SecTrustSetOptionInPolicies(trust
->_policies
, kSecPolicyCheckNoNetworkAccess
, kCFBooleanTrue
);
711 status
= SecTrustRemoveOptionInPolicies(trust
->_policies
, kSecPolicyCheckNoNetworkAccess
);
714 /* If we switched from NoNetworkAccess to allowing access, we need to re-run the trust evaluation */
715 if (allowFetch
&& !oldAllowFetch
) {
716 SecTrustSetNeedsEvaluation(trust
);
721 OSStatus
SecTrustGetNetworkFetchAllowed(SecTrustRef trust
, Boolean
*allowFetch
) {
722 if (!trust
|| !allowFetch
) {
725 __block CFArrayRef foundValues
= NULL
;
726 dispatch_sync(trust
->_trustQueue
, ^{
727 foundValues
= SecTrustCopyOptionsFromPolicies(trust
->_policies
, kSecPolicyCheckNoNetworkAccess
);
730 CFArrayForEach(foundValues
, ^(CFTypeRef value
) {
731 if (isBoolean(value
)) {
732 *allowFetch
= !CFBooleanGetValue(value
);
738 CFReleaseNull(foundValues
);
739 return errSecSuccess
;
742 OSStatus
SecTrustSetPinningException(SecTrustRef trust
) {
743 if (!trust
) { return errSecParam
; }
744 __block OSStatus status
= errSecSuccess
;
745 dispatch_sync(trust
->_trustQueue
, ^{
746 status
= SecTrustRemoveOptionInPolicies(trust
->_policies
, kSecPolicyCheckPinningRequired
);
751 CFAbsoluteTime
SecTrustGetVerifyTime(SecTrustRef trust
) {
752 __block CFAbsoluteTime verifyTime
= CFAbsoluteTimeGetCurrent();
756 dispatch_sync(trust
->_trustQueue
, ^{
757 if (trust
->_verifyDate
) {
758 verifyTime
= CFDateGetAbsoluteTime(trust
->_verifyDate
);
760 trust
->_verifyDate
= CFDateCreate(CFGetAllocator(trust
), verifyTime
);
767 CFArrayRef
SecTrustGetDetails(SecTrustRef trust
) {
771 SecTrustEvaluateIfNecessary(trust
);
772 return trust
->_details
;
775 OSStatus
SecTrustGetTrustResult(SecTrustRef trust
,
776 SecTrustResultType
*result
) {
777 if (!trust
|| !result
) {
780 SecTrustEvaluateIfNecessary(trust
);
781 dispatch_sync(trust
->_trustQueue
, ^{
782 *result
= trust
->_trustResult
;
784 return errSecSuccess
;
787 static CFDictionaryRef
SecTrustGetExceptionForCertificateAtIndex(SecTrustRef trust
, CFIndex ix
) {
788 CFDictionaryRef exception
= NULL
;
789 __block CFArrayRef exceptions
= NULL
;
790 dispatch_sync(trust
->_trustQueue
, ^{
791 exceptions
= CFRetainSafe(trust
->_exceptions
);
793 if (!exceptions
|| ix
>= CFArrayGetCount(exceptions
)) {
797 SecCertificateRef certificate
= SecTrustGetCertificateAtIndex(trust
, ix
);
802 exception
= (CFDictionaryRef
)CFArrayGetValueAtIndex(exceptions
, ix
);
803 if (CFGetTypeID(exception
) != CFDictionaryGetTypeID()) {
808 /* If the exception contains the current certificates sha1Digest in the
809 kSecCertificateDetailSHA1Digest key then we use it otherwise we ignore it. */
810 CFDataRef sha1Digest
= SecCertificateGetSHA1Digest(certificate
);
811 CFTypeRef digestValue
= CFDictionaryGetValue(exception
, kSecCertificateDetailSHA1Digest
);
812 if (!digestValue
|| !CFEqual(sha1Digest
, digestValue
))
816 CFReleaseSafe(exceptions
);
820 CFArrayRef
SecTrustCopyFilteredDetails(SecTrustRef trust
) {
824 SecTrustEvaluateIfNecessary(trust
);
825 __block CFArrayRef details
= NULL
;
826 dispatch_sync(trust
->_trustQueue
, ^{
827 details
= CFRetainSafe(trust
->_details
);
830 /* Done automatically by the Policy Server with SecPVCIsExceptedError */
834 Boolean
SecTrustIsExpiredOnly(SecTrustRef trust
) {
835 /* Returns true if one or more certificates in the chain have expired,
836 * expiration is an error (i.e. is not covered by existing trust settings),
837 * and it is the only error encountered.
838 * Returns false if the certificate is valid, or if the trust chain has
839 * other errors beside expiration.
841 Boolean result
= false;
842 Boolean foundExpired
= false;
843 CFArrayRef details
= SecTrustCopyFilteredDetails(trust
);
844 require(details
!= NULL
, out
);
846 CFIndex ix
, pathLength
= CFArrayGetCount(details
);
847 for (ix
= 0; ix
< pathLength
; ++ix
) {
848 CFDictionaryRef detail
= (CFDictionaryRef
)CFArrayGetValueAtIndex(details
, ix
);
849 CFIndex count
= (detail
) ? CFDictionaryGetCount(detail
) : 0;
850 require(count
<= 1, out
);
852 CFBooleanRef valid
= (CFBooleanRef
)CFDictionaryGetValue(detail
, kSecPolicyCheckTemporalValidity
);
853 require(isBoolean(valid
) && CFEqual(valid
, kCFBooleanFalse
), out
);
857 result
= foundExpired
;
859 CFReleaseSafe(details
);
864 static CFArrayRef
SecTrustCreatePolicyAnchorsArray(const UInt8
* certData
, CFIndex certLength
)
866 CFArrayRef array
= NULL
;
867 CFAllocatorRef allocator
= kCFAllocatorDefault
;
868 SecCertificateRef cert
= SecCertificateCreateWithBytes(allocator
, certData
, certLength
);
870 array
= CFArrayCreate(allocator
, (const void **)&cert
, 1, &kCFTypeArrayCallBacks
);
877 static void SecTrustAddPolicyAnchors(SecTrustRef trust
)
879 /* Provide anchor certificates specifically required by certain policies.
880 This is used to evaluate test policies where the anchor is not provided
881 in the root store and may not be able to be supplied by the caller.
883 if (!trust
) { return; }
884 __block CFArrayRef policies
= NULL
;
885 dispatch_sync(trust
->_trustQueue
, ^{
886 policies
= CFRetain(trust
->_policies
);
888 CFIndex ix
, count
= CFArrayGetCount(policies
);
889 for (ix
= 0; ix
< count
; ++ix
) {
890 SecPolicyRef policy
= (SecPolicyRef
) CFArrayGetValueAtIndex(policies
, ix
);
893 if (CFEqual(policy
->_oid
, kSecPolicyAppleTestSMPEncryption
)) {
894 __block CFArrayRef policyAnchors
= SecTrustCreatePolicyAnchorsArray(_SEC_TestAppleRootCAECC
, sizeof(_SEC_TestAppleRootCAECC
));
895 dispatch_sync(trust
->_trustQueue
, ^{
896 CFReleaseSafe(trust
->_anchors
);
897 trust
->_anchors
= policyAnchors
;
899 trust
->_anchorsOnly
= true;
905 CFReleaseSafe(policies
);
908 // uncomment for verbose debug logging (debug builds only)
909 //#define CERT_TRUST_DUMP 1
912 static void sectrustlog(int priority
, const char *format
, ...)
917 if (priority
< LOG_NOTICE
) // log warnings and errors
921 va_start(list
, format
);
922 vsyslog(priority
, format
, list
);
927 static void sectrustshow(CFTypeRef obj
, const char *context
)
930 CFStringRef desc
= CFCopyDescription(obj
);
933 CFIndex length
= CFStringGetMaximumSizeForEncoding(CFStringGetLength(desc
), kCFStringEncodingUTF8
) + 1;
934 char* buffer
= (char*) malloc(length
);
936 Boolean converted
= CFStringGetCString(desc
, buffer
, length
, kCFStringEncodingUTF8
);
938 const char *prefix
= (context
) ? context
: "";
939 const char *separator
= (context
) ? " " : "";
940 sectrustlog(LOG_NOTICE
, "%s%s%s", prefix
, separator
, buffer
);
948 static void cert_trust_dump(SecTrustRef trust
) {
949 SecCertificateRef leaf
= SecTrustGetCertificateAtIndex(trust
, 0);
950 CFStringRef name
= (leaf
) ? SecCertificateCopySubjectSummary(leaf
) : NULL
;
951 secerror("leaf \"%@\"", name
);
952 secerror(": result = %d", (int) trust
->_trustResult
);
954 CFIndex ix
, count
= CFArrayGetCount(trust
->_chain
);
955 CFMutableArrayRef chain
= CFArrayCreateMutable(kCFAllocatorDefault
, count
, &kCFTypeArrayCallBacks
);
956 for (ix
= 0; ix
< count
; ix
++) {
957 SecCertificateRef cert
= (SecCertificateRef
)CFArrayGetValueAtIndex(trust
->_chain
, ix
);
959 CFArrayAppendValue(chain
, cert
);
962 sectrustshow(chain
, "chain:");
963 CFReleaseSafe(chain
);
965 secerror(": %ld certificates, %ld anchors, %ld policies, %ld details",
966 (trust
->_certificates
) ? (long)CFArrayGetCount(trust
->_certificates
) : 0,
967 (trust
->_anchors
) ? (long)CFArrayGetCount(trust
->_anchors
) : 0,
968 (trust
->_policies
) ? (long)CFArrayGetCount(trust
->_policies
) : 0,
969 (trust
->_details
) ? (long)CFArrayGetCount(trust
->_details
) : 0);
971 sectrustshow(trust
->_verifyDate
, "verify date:");
972 sectrustshow(trust
->_certificates
, "certificates:");
973 sectrustshow(trust
->_anchors
, "anchors:");
974 sectrustshow(trust
->_policies
, "policies:");
975 sectrustshow(trust
->_details
, "details:");
976 sectrustshow(trust
->_info
, "info:");
981 static void cert_trust_dump(SecTrustRef trust
) {}
984 static void SecTrustLogFailureDescription(SecTrustRef trust
, SecTrustResultType trustResult
)
986 if (trustResult
== kSecTrustResultProceed
|| trustResult
== kSecTrustResultUnspecified
) {
990 CFStringRef failureDesc
= SecTrustCopyFailureDescription(trust
);
991 secerror("Trust evaluate failure:%{public}@", failureDesc
);
992 CFRelease(failureDesc
);
995 static OSStatus
SecTrustEvaluateInternal(SecTrustRef trust
, SecTrustResultType
*result
) {
997 *result
= kSecTrustResultInvalid
;
1002 OSStatus status
= SecTrustEvaluateIfNecessary(trust
);
1006 /* post-process trust result based on exceptions */
1007 __block SecTrustResultType trustResult
= kSecTrustResultInvalid
;
1008 dispatch_sync(trust
->_trustQueue
, ^{
1009 trustResult
= trust
->_trustResult
;
1012 SecTrustLogFailureDescription(trust
, trustResult
);
1016 *result
= trustResult
;
1022 OSStatus
SecTrustEvaluate(SecTrustRef trust
, SecTrustResultType
*result
) {
1023 return SecTrustEvaluateInternal(trust
, result
);
1026 static CFStringRef
SecTrustCopyChainSummary(SecTrustRef trust
) {
1027 CFMutableStringRef summary
= CFStringCreateMutable(NULL
, 0);
1028 __block CFArrayRef chain
= NULL
;
1029 dispatch_sync(trust
->_trustQueue
, ^{
1030 chain
= trust
->_chain
;
1032 CFIndex ix
, count
= CFArrayGetCount(chain
);
1033 for (ix
= 0; ix
< count
; ix
++) {
1034 if (ix
!= 0) { CFStringAppend(summary
, CFSTR(",")); }
1035 CFStringRef certSummary
= SecCertificateCopySubjectSummary((SecCertificateRef
)CFArrayGetValueAtIndex(chain
, ix
));
1036 CFStringAppendFormat(summary
, NULL
, CFSTR("\"%@\""), certSummary
);
1037 CFReleaseNull(certSummary
);
1042 #define SecCopyTrustString(KEY) SecFrameworkCopyLocalizedString(KEY, CFSTR("Trust"))
1044 struct checkmap_entry_s
{
1045 SecTrustErrorSubType type
;
1047 const CFStringRef errorKey
;
1049 typedef struct checkmap_entry_s checkmap_entry_t
;
1051 const checkmap_entry_t checkmap
[] = {
1052 #undef POLICYCHECKMACRO
1053 #define POLICYCHECKMACRO(NAME, TRUSTRESULT, SUBTYPE, LEAFCHECK, PATHCHECK, LEAFONLY, CSSMERR, OSSTATUS) \
1054 { __PC_SUBTYPE_##SUBTYPE , OSSTATUS, SEC_TRUST_ERROR_##NAME },
1055 #include "SecPolicyChecks.list"
1058 static OSStatus
SecTrustCopyErrorStrings(SecTrustRef trust
,
1059 CFStringRef
* CF_RETURNS_RETAINED simpleError
,
1060 CFStringRef
* CF_RETURNS_RETAINED fullError
) {
1061 if (!simpleError
|| !fullError
) {
1064 __block CFArrayRef details
= NULL
;
1065 dispatch_sync(trust
->_trustQueue
, ^{
1066 details
= CFRetainSafe(trust
->_details
);
1069 return errSecInternal
;
1071 /* We need to map the policy check constants to indexes into our checkmap table. */
1072 static dispatch_once_t onceToken
;
1073 static CFArrayRef policyChecks
= NULL
;
1074 dispatch_once(&onceToken
, ^{
1075 CFMutableArrayRef _policyChecks
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
1076 #undef POLICYCHECKMACRO
1077 #define POLICYCHECKMACRO(NAME, TRUSTRESULT, SUBTYPE, LEAFCHECK, PATHCHECK, LEAFONLY, CSSMERR, ERRORSTRING) \
1078 CFArrayAppendValue(_policyChecks, kSecPolicyCheck##NAME);
1079 #include "SecPolicyChecks.list"
1080 policyChecks
= _policyChecks
;
1083 /* Build the errors for each cert in the detailed results array */
1084 __block CFMutableStringRef fullMutableError
= CFStringCreateMutable(NULL
, 0);
1085 __block SecTrustErrorSubType simpleErrorSubType
= kSecTrustErrorSubTypeInvalid
;
1086 __block OSStatus simpleErrorStatus
= errSecInternalError
;
1087 __block CFIndex simpleErrorCertIndex
= kCFNotFound
;
1089 CFIndex count
= CFArrayGetCount(details
);
1090 for (ix
= 0; ix
< count
; ix
++) {
1091 CFDictionaryRef perCertDetails
= (CFDictionaryRef
)CFArrayGetValueAtIndex(details
, ix
);
1092 if (CFDictionaryGetCount(perCertDetails
) == 0) { continue; } // no errors on this cert
1094 /* Get the cert summary and start the full error details string for this cert */
1095 CFStringRef certSummary
= SecCertificateCopySubjectSummary(SecTrustGetCertificateAtIndex(trust
, ix
));
1096 CFStringRef format
= SecCopyTrustString(SEC_TRUST_CERTIFICATE_ERROR
);
1097 CFStringAppendFormat(fullMutableError
, NULL
, format
,
1099 CFReleaseNull(certSummary
);
1100 CFReleaseNull(format
);
1102 /* Figure out the errors */
1103 __block
bool firstError
= true;
1104 CFDictionaryForEach(perCertDetails
, ^(const void *key
, const void * __unused value
) {
1105 CFIndex policyCheckIndex
= CFArrayGetFirstIndexOfValue(policyChecks
, CFRangeMake(0, CFArrayGetCount(policyChecks
)), key
);
1106 if ((policyCheckIndex
< 0) || ((size_t)policyCheckIndex
>= sizeof(checkmap
)/sizeof(checkmap
[0]))) {
1107 secwarning("unknown failure key in details dictionary: %@", key
);
1110 /* Keep track of the highest priority error encountered during this evaluation.
1111 * If multiple certs have errors of the same subtype we keep the lowest indexed cert. */
1112 if (simpleErrorSubType
> checkmap
[policyCheckIndex
].type
) {
1113 simpleErrorSubType
= checkmap
[policyCheckIndex
].type
;
1114 simpleErrorCertIndex
= ix
;
1115 simpleErrorStatus
= checkmap
[policyCheckIndex
].status
;
1117 /* Add this error to the full error */
1118 if (!firstError
) { CFStringAppend(fullMutableError
, CFSTR(", ")); }
1119 CFStringRef errorString
= SecCopyTrustString(checkmap
[policyCheckIndex
].errorKey
);
1120 CFStringAppend(fullMutableError
, errorString
);
1121 CFReleaseNull(errorString
);
1124 CFStringAppend(fullMutableError
, CFSTR(";"));
1126 CFReleaseNull(details
);
1128 /* Build the simple error */
1129 if (simpleErrorCertIndex
== kCFNotFound
) { simpleErrorCertIndex
= 0; }
1130 CFStringRef format
= NULL
;
1131 CFStringRef certSummary
= SecCertificateCopySubjectSummary(SecTrustGetCertificateAtIndex(trust
, simpleErrorCertIndex
));
1132 switch (simpleErrorSubType
) {
1133 case kSecTrustErrorSubTypeBlocked
: {
1134 format
= SecCopyTrustString(SEC_TRUST_ERROR_SUBTYPE_BLOCKED
);
1137 case kSecTrustErrorSubTypeRevoked
: {
1138 format
= SecCopyTrustString(SEC_TRUST_ERROR_SUBTYPE_REVOKED
);
1141 case kSecTrustErrorSubTypeKeySize
: {
1142 format
= SecCopyTrustString(SEC_TRUST_ERROR_SUBTYPE_KEYSIZE
);
1145 case kSecTrustErrorSubTypeWeakHash
: {
1146 format
= SecCopyTrustString(SEC_TRUST_ERROR_SUBTYPE_WEAKHASH
);
1149 case kSecTrustErrorSubTypeDenied
: {
1150 format
= SecCopyTrustString(SEC_TRUST_ERROR_SUBTYPE_DENIED
);
1153 case kSecTrustErrorSubTypeCompliance
: {
1154 format
= SecCopyTrustString(SEC_TRUST_ERROR_SUBTYPE_COMPLIANCE
);
1157 case kSecTrustErrorSubTypeExpired
: {
1158 format
= SecCopyTrustString(SEC_TRUST_ERROR_SUBTYPE_EXPIRED
);
1161 case kSecTrustErrorSubTypeTrust
: {
1162 format
= SecCopyTrustString(SEC_TRUST_ERROR_SUBTYPE_TRUST
);
1165 case kSecTrustErrorSubTypeName
: {
1166 format
= SecCopyTrustString(SEC_TRUST_ERROR_SUBTYPE_NAME
);
1169 case kSecTrustErrorSubTypeUsage
: {
1170 format
= SecCopyTrustString(SEC_TRUST_ERROR_SUBTYPE_USAGE
);
1173 case kSecTrustErrorSubTypePinning
: {
1174 format
= SecCopyTrustString(SEC_TRUST_ERROR_SUBTYPE_PINNING
);
1175 CFAssignRetained(certSummary
, SecTrustCopyChainSummary(trust
));
1179 format
= SecCopyTrustString(SEC_TRUST_ERROR_SUBTYPE_INVALID
);
1183 if (format
&& certSummary
) {
1184 *simpleError
= CFStringCreateWithFormat(NULL
, NULL
, format
, certSummary
);
1186 CFReleaseNull(format
);
1187 CFReleaseNull(certSummary
);
1188 *fullError
= fullMutableError
;
1189 return simpleErrorStatus
;
1192 static CF_RETURNS_RETAINED CFErrorRef
SecTrustCopyError(SecTrustRef trust
) {
1193 if (!trust
) { return NULL
; }
1194 OSStatus status
= errSecSuccess
;
1195 __block SecTrustResultType trustResult
= kSecTrustResultInvalid
;
1196 dispatch_sync(trust
->_trustQueue
, ^{
1197 trustResult
= trust
->_trustResult
;
1199 if (trustResult
== kSecTrustResultProceed
|| trustResult
== kSecTrustResultUnspecified
) {
1203 CFStringRef detailedError
= NULL
;
1204 CFStringRef simpleError
= NULL
;
1205 status
= SecTrustCopyErrorStrings(trust
, &simpleError
, &detailedError
);
1206 /* failure to obtain either string must not cause a failure to create the CFErrorRef */
1208 simpleError
= SecCopyErrorMessageString(status
, NULL
);
1210 if (!detailedError
) {
1211 detailedError
= SecCopyErrorMessageString(status
, NULL
);
1213 CFDictionaryRef userInfo
= CFDictionaryCreate(NULL
, (const void **)&kCFErrorLocalizedDescriptionKey
,
1214 (const void **)&detailedError
, 1,
1215 &kCFTypeDictionaryKeyCallBacks
,
1216 &kCFTypeDictionaryValueCallBacks
);
1217 CFErrorRef underlyingError
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, status
, userInfo
);
1218 CFReleaseNull(userInfo
);
1219 CFReleaseNull(detailedError
);
1221 const void *keys
[] = { kCFErrorLocalizedDescriptionKey
, kCFErrorUnderlyingErrorKey
};
1222 const void *values
[] = { simpleError
, underlyingError
};
1223 userInfo
= CFDictionaryCreate(NULL
, keys
, values
, 2,
1224 &kCFTypeDictionaryKeyCallBacks
,
1225 &kCFTypeDictionaryValueCallBacks
);
1226 CFErrorRef error
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, status
, userInfo
);
1227 CFReleaseNull(userInfo
);
1228 CFReleaseNull(simpleError
);
1229 CFReleaseNull(underlyingError
);
1233 bool SecTrustEvaluateWithError(SecTrustRef trust
, CFErrorRef
*error
) {
1234 SecTrustResultType trustResult
= kSecTrustResultInvalid
;
1235 OSStatus status
= SecTrustEvaluateInternal(trust
, &trustResult
);
1236 if (status
== errSecSuccess
&& (trustResult
== kSecTrustResultProceed
|| trustResult
== kSecTrustResultUnspecified
)) {
1243 if (status
!= errSecSuccess
) {
1244 *error
= SecCopyLastError(status
);
1246 *error
= SecTrustCopyError(trust
);
1252 OSStatus
SecTrustEvaluateAsync(SecTrustRef trust
,
1253 dispatch_queue_t queue
, SecTrustCallback result
)
1255 CFRetainSafe(trust
);
1256 dispatch_async(queue
, ^{
1257 SecTrustResultType trustResult
;
1258 if (errSecSuccess
!= SecTrustEvaluateInternal(trust
, &trustResult
)) {
1259 trustResult
= kSecTrustResultInvalid
;
1261 result(trust
, trustResult
);
1262 CFReleaseSafe(trust
);
1264 return errSecSuccess
;
1268 OSStatus
SecTrustEvaluateFastAsync(SecTrustRef trust
,
1269 dispatch_queue_t queue
, SecTrustCallback result
)
1271 if (trust
== NULL
|| queue
== NULL
|| result
== NULL
) {
1275 dispatch_assert_queue(queue
);
1276 SecTrustEvaluateIfNecessaryFastAsync(trust
, queue
, ^(OSStatus status
) {
1277 if (status
!= noErr
) {
1278 result(trust
, kSecTrustResultInvalid
);
1281 __block SecTrustResultType trustResult
= kSecTrustResultInvalid
;
1282 dispatch_sync(trust
->_trustQueue
, ^{
1283 trustResult
= trust
->_trustResult
;
1285 SecTrustLogFailureDescription(trust
, trustResult
);
1288 result(trust
, trustResult
);
1290 return errSecSuccess
;
1293 OSStatus
SecTrustEvaluateAsyncWithError(SecTrustRef trust
, dispatch_queue_t queue
, SecTrustWithErrorCallback callback
)
1295 if (trust
== NULL
|| queue
== NULL
|| callback
== NULL
) {
1299 dispatch_assert_queue(queue
);
1300 SecTrustEvaluateIfNecessaryFastAsync(trust
, queue
, ^(OSStatus status
) {
1301 if (status
!= noErr
) {
1302 CFErrorRef error
= SecCopyLastError(status
);
1303 callback(trust
, false, error
);
1304 CFReleaseNull(error
);
1308 __block SecTrustResultType trustResult
= kSecTrustResultInvalid
;
1309 dispatch_sync(trust
->_trustQueue
, ^{
1310 trustResult
= trust
->_trustResult
;
1312 SecTrustLogFailureDescription(trust
, trustResult
);
1315 CFErrorRef error
= SecTrustCopyError(trust
);
1316 bool result
= (trustResult
== kSecTrustResultProceed
|| trustResult
== kSecTrustResultUnspecified
);
1317 callback(trust
, result
, error
);
1318 CFReleaseNull(error
);
1321 return errSecSuccess
;
1324 static bool append_certificate_to_xpc_array(SecCertificateRef certificate
, xpc_object_t xpc_certificates
);
1325 static xpc_object_t
copy_xpc_certificates_array(CFArrayRef certificates
);
1326 xpc_object_t
copy_xpc_policies_array(CFArrayRef policies
);
1327 OSStatus
validate_array_of_items(CFArrayRef array
, CFStringRef arrayItemType
, CFTypeID itemTypeID
, bool required
);
1329 static bool append_certificate_to_xpc_array(SecCertificateRef certificate
, xpc_object_t xpc_certificates
) {
1331 return true; // NOOP
1333 size_t length
= SecCertificateGetLength(certificate
);
1334 const uint8_t *bytes
= SecCertificateGetBytePtr(certificate
);
1335 if (!length
|| !bytes
) {
1338 xpc_array_set_data(xpc_certificates
, XPC_ARRAY_APPEND
, bytes
, length
);
1342 static xpc_object_t
copy_xpc_certificates_array(CFArrayRef certificates
) {
1343 xpc_object_t xpc_certificates
= xpc_array_create(NULL
, 0);
1344 if (!xpc_certificates
) {
1347 CFIndex ix
, count
= CFArrayGetCount(certificates
);
1348 for (ix
= 0; ix
< count
; ++ix
) {
1349 SecCertificateRef certificate
= (SecCertificateRef
) CFArrayGetValueAtIndex(certificates
, ix
);
1350 #if SECTRUST_VERBOSE_DEBUG
1351 size_t length
= SecCertificateGetLength(certificate
);
1352 const uint8_t *bytes
= SecCertificateGetBytePtr(certificate
);
1353 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
);
1355 if (!append_certificate_to_xpc_array(certificate
, xpc_certificates
)) {
1356 xpc_release(xpc_certificates
);
1357 xpc_certificates
= NULL
;
1361 return xpc_certificates
;
1364 static bool SecXPCDictionarySetCertificates(xpc_object_t message
, const char *key
, CFArrayRef certificates
, CFErrorRef
*error
) {
1365 xpc_object_t xpc_certificates
= copy_xpc_certificates_array(certificates
);
1366 if (!xpc_certificates
) {
1367 SecError(errSecAllocate
, error
, CFSTR("failed to create xpc_array of certificates"));
1370 xpc_dictionary_set_value(message
, key
, xpc_certificates
);
1371 xpc_release(xpc_certificates
);
1375 static bool SecXPCDictionarySetPolicies(xpc_object_t message
, const char *key
, CFArrayRef policies
, CFErrorRef
*error
) {
1376 xpc_object_t xpc_policies
= copy_xpc_policies_array(policies
);
1377 if (!xpc_policies
) {
1378 SecError(errSecAllocate
, error
, CFSTR("failed to create xpc_array of policies"));
1381 xpc_dictionary_set_value(message
, key
, xpc_policies
);
1382 xpc_release(xpc_policies
);
1387 static bool CFDataAppendToXPCArray(CFDataRef data
, xpc_object_t xpc_data_array
, CFErrorRef
*error
) {
1389 return true; // NOOP
1391 size_t length
= CFDataGetLength(data
);
1392 const uint8_t *bytes
= CFDataGetBytePtr(data
);
1393 if (!length
|| !bytes
)
1394 return SecError(errSecParam
, error
, CFSTR("invalid CFDataRef"));
1396 xpc_array_set_data(xpc_data_array
, XPC_ARRAY_APPEND
, bytes
, length
);
1401 static xpc_object_t
CFDataArrayCopyXPCArray(CFArrayRef data_array
, CFErrorRef
*error
) {
1402 xpc_object_t xpc_data_array
;
1403 require_action_quiet(xpc_data_array
= xpc_array_create(NULL
, 0), exit
,
1404 SecError(errSecAllocate
, error
, CFSTR("failed to create xpc_array")));
1405 CFIndex ix
, count
= CFArrayGetCount(data_array
);
1406 for (ix
= 0; ix
< count
; ++ix
) {
1407 if (!CFDataAppendToXPCArray((CFDataRef
)CFArrayGetValueAtIndex(data_array
, ix
), xpc_data_array
, error
)) {
1408 xpc_release(xpc_data_array
);
1414 return xpc_data_array
;
1417 static bool SecXPCDictionarySetDataArray(xpc_object_t message
, const char *key
, CFArrayRef data_array
, CFErrorRef
*error
) {
1418 xpc_object_t xpc_data_array
= CFDataArrayCopyXPCArray(data_array
, error
);
1419 if (!xpc_data_array
)
1421 xpc_dictionary_set_value(message
, key
, xpc_data_array
);
1422 xpc_release(xpc_data_array
);
1426 static bool SecXPCDictionaryCopyChainOptional(xpc_object_t message
, const char *key
, CFArrayRef
*path
, CFErrorRef
*error
) {
1427 xpc_object_t xpc_path
= xpc_dictionary_get_value(message
, key
);
1428 CFMutableArrayRef output
= NULL
;
1434 require_action_quiet(xpc_get_type(xpc_path
) == XPC_TYPE_ARRAY
, exit
, SecError(errSecDecode
, error
, CFSTR("xpc_path value is not an array")));
1435 require_action_quiet(count
= xpc_array_get_count(xpc_path
), exit
, SecError(errSecDecode
, error
, CFSTR("xpc_path array count == 0")));
1436 output
= CFArrayCreateMutable(NULL
, count
, &kCFTypeArrayCallBacks
);
1439 for (ix
= 0; ix
< count
; ++ix
) {
1440 SecCertificateRef certificate
= SecCertificateCreateWithXPCArrayAtIndex(xpc_path
, ix
, error
);
1442 CFArrayAppendValue(output
, certificate
);
1443 CFReleaseNull(certificate
);
1445 CFReleaseNull(output
);
1458 static int SecXPCDictionaryGetNonZeroInteger(xpc_object_t message
, const char *key
, CFErrorRef
*error
) {
1459 int64_t value
= xpc_dictionary_get_int64(message
, key
);
1461 SecError(errSecInternal
, error
, CFSTR("object for key %s is 0"), key
);
1466 static SecTrustResultType
handle_trust_evaluate_xpc(enum SecXPCOperation op
, CFArrayRef certificates
,
1467 CFArrayRef anchors
, bool anchorsOnly
,
1468 bool keychainsAllowed
, CFArrayRef policies
, CFArrayRef responses
,
1469 CFArrayRef SCTs
, CFArrayRef trustedLogs
,
1470 CFAbsoluteTime verifyTime
, __unused CFArrayRef accessGroups
, CFArrayRef exceptions
,
1471 CFArrayRef
*details
, CFDictionaryRef
*info
, CFArrayRef
*chain
, CFErrorRef
*error
)
1473 __block SecTrustResultType tr
= kSecTrustResultInvalid
;
1474 securityd_send_sync_and_do(op
, error
, ^bool(xpc_object_t message
, CFErrorRef
*blockError
) {
1475 if (!SecXPCDictionarySetCertificates(message
, kSecTrustCertificatesKey
, certificates
, blockError
))
1477 if (anchors
&& !SecXPCDictionarySetCertificates(message
, kSecTrustAnchorsKey
, anchors
, blockError
))
1480 xpc_dictionary_set_bool(message
, kSecTrustAnchorsOnlyKey
, anchorsOnly
);
1481 xpc_dictionary_set_bool(message
, kSecTrustKeychainsAllowedKey
, keychainsAllowed
);
1482 if (!SecXPCDictionarySetPolicies(message
, kSecTrustPoliciesKey
, policies
, blockError
))
1484 if (responses
&& !SecXPCDictionarySetDataArray(message
, kSecTrustResponsesKey
, responses
, blockError
))
1486 if (SCTs
&& !SecXPCDictionarySetDataArray(message
, kSecTrustSCTsKey
, SCTs
, blockError
))
1488 if (trustedLogs
&& !SecXPCDictionarySetPList(message
, kSecTrustTrustedLogsKey
, trustedLogs
, blockError
))
1490 xpc_dictionary_set_double(message
, kSecTrustVerifyDateKey
, verifyTime
);
1491 if (exceptions
&& !SecXPCDictionarySetPList(message
, kSecTrustExceptionsKey
, exceptions
, blockError
))
1494 }, ^bool(xpc_object_t response
, CFErrorRef
*blockError
) {
1495 secdebug("trust", "response: %@", response
);
1496 return SecXPCDictionaryCopyArrayOptional(response
, kSecTrustDetailsKey
, details
, blockError
) &&
1497 SecXPCDictionaryCopyDictionaryOptional(response
, kSecTrustInfoKey
, info
, blockError
) &&
1498 SecXPCDictionaryCopyChainOptional(response
, kSecTrustChainKey
, chain
, blockError
) &&
1499 ((tr
= SecXPCDictionaryGetNonZeroInteger(response
, kSecTrustResultKey
, blockError
)) != kSecTrustResultInvalid
);
1504 typedef void (^trust_handler_t
)(SecTrustResultType tr
, CFErrorRef error
);
1506 static void handle_trust_evaluate_xpc_async(dispatch_queue_t replyq
, trust_handler_t trustHandler
,
1507 enum SecXPCOperation op
, CFArrayRef certificates
,
1508 CFArrayRef anchors
, bool anchorsOnly
,
1509 bool keychainsAllowed
, CFArrayRef policies
,
1510 CFArrayRef responses
, CFArrayRef SCTs
, CFArrayRef trustedLogs
,
1511 CFAbsoluteTime verifyTime
, __unused CFArrayRef accessGroups
,
1512 CFArrayRef exceptions
, CFArrayRef
*details
,
1513 CFDictionaryRef
*info
, CFArrayRef
*chain
)
1515 securityd_send_async_and_do(op
, replyq
, ^bool(xpc_object_t message
, CFErrorRef
*error
) {
1516 if (!SecXPCDictionarySetCertificates(message
, kSecTrustCertificatesKey
, certificates
, error
))
1518 if (anchors
&& !SecXPCDictionarySetCertificates(message
, kSecTrustAnchorsKey
, anchors
, error
))
1521 xpc_dictionary_set_bool(message
, kSecTrustAnchorsOnlyKey
, anchorsOnly
);
1522 xpc_dictionary_set_bool(message
, kSecTrustKeychainsAllowedKey
, keychainsAllowed
);
1523 if (!SecXPCDictionarySetPolicies(message
, kSecTrustPoliciesKey
, policies
, error
))
1525 if (responses
&& !SecXPCDictionarySetDataArray(message
, kSecTrustResponsesKey
, responses
, error
))
1527 if (SCTs
&& !SecXPCDictionarySetDataArray(message
, kSecTrustSCTsKey
, SCTs
, error
))
1529 if (trustedLogs
&& !SecXPCDictionarySetPList(message
, kSecTrustTrustedLogsKey
, trustedLogs
, error
))
1531 xpc_dictionary_set_double(message
, kSecTrustVerifyDateKey
, verifyTime
);
1532 if (exceptions
&& !SecXPCDictionarySetPList(message
, kSecTrustExceptionsKey
, exceptions
, error
))
1535 }, ^(xpc_object_t response
, CFErrorRef error
) {
1536 secdebug("trust", "response: %@", response
);
1537 if (response
== NULL
|| error
!= NULL
) {
1538 trustHandler(kSecTrustResultInvalid
, error
);
1541 SecTrustResultType tr
= kSecTrustResultInvalid
;
1542 CFErrorRef error2
= NULL
;
1543 if (SecXPCDictionaryCopyArrayOptional(response
, kSecTrustDetailsKey
, details
, &error2
) &&
1544 SecXPCDictionaryCopyDictionaryOptional(response
, kSecTrustInfoKey
, info
, &error2
) &&
1545 SecXPCDictionaryCopyChainOptional(response
, kSecTrustChainKey
, chain
, &error2
)) {
1546 tr
= SecXPCDictionaryGetNonZeroInteger(response
, kSecTrustResultKey
, &error2
);
1548 trustHandler(tr
, error2
);
1549 CFReleaseNull(error2
);
1553 OSStatus
validate_array_of_items(CFArrayRef array
, CFStringRef arrayItemType
, CFTypeID itemTypeID
, bool required
) {
1554 OSStatus result
= errSecSuccess
;
1555 CFIndex index
, count
;
1556 count
= (array
) ? CFArrayGetCount(array
) : 0;
1557 if (!count
&& required
) {
1558 secerror("no %@ in array!", arrayItemType
);
1559 result
= errSecParam
;
1561 for (index
= 0; index
< count
; index
++) {
1562 CFTypeRef item
= (CFTypeRef
) CFArrayGetValueAtIndex(array
, index
);
1564 secerror("%@ %@ (index %d)", arrayItemType
, CFSTR("reference is nil"), (int)index
);
1565 result
= errSecParam
;
1568 if (CFGetTypeID(item
) != itemTypeID
) {
1569 secerror("%@ %@ (index %d)", arrayItemType
, CFSTR("is not the expected CF type"), (int)index
);
1570 result
= errSecParam
;
1573 if (CFGetTypeID(item
) == SecCertificateGetTypeID()) {
1574 SecCertificateRef certificate
= (SecCertificateRef
) item
;
1575 CFIndex length
= SecCertificateGetLength(certificate
);
1576 const UInt8
*bytes
= SecCertificateGetBytePtr(certificate
);
1578 secerror("%@ %@ (index %d)", arrayItemType
, CFSTR("has zero length"), (int)index
);
1579 result
= errSecParam
;
1582 secerror("%@ %@ (index %d)", arrayItemType
, CFSTR("has nil bytes"), (int)index
);
1583 result
= errSecParam
;
1585 #if SECTRUST_VERBOSE_DEBUG
1586 secerror("%@[%d] of %d = %ld bytes @ 0x%lX", arrayItemType
, (int)index
, (int)count
, (size_t)length
, (uintptr_t)bytes
);
1590 if (CFGetTypeID(item
) == SecPolicyGetTypeID()) {
1591 SecPolicyRef policy
= (SecPolicyRef
) item
;
1592 CFStringRef oidStr
= policy
->_oid
;
1593 if (!oidStr
|| (CFGetTypeID(oidStr
) != CFStringGetTypeID())) {
1594 oidStr
= CFSTR("has invalid OID string!");
1595 secerror("%@ %@ (index %d)", arrayItemType
, oidStr
, (int)index
);
1597 #if SECTRUST_VERBOSE_DEBUG
1598 secerror("%@[%d] of %d = \"%@\" 0x%lX", arrayItemType
, (int)index
, (int)count
, oidStr
, (uintptr_t)policy
);
1605 static OSStatus
SecTrustValidateInput(SecTrustRef trust
) {
1606 OSStatus status
, result
= errSecSuccess
;
1608 // certificates (required)
1609 status
= validate_array_of_items(trust
->_certificates
, CFSTR("certificate"), SecCertificateGetTypeID(), true);
1610 if (status
) result
= status
;
1611 // anchors (optional)
1612 status
= validate_array_of_items(trust
->_anchors
, CFSTR("input anchor"), SecCertificateGetTypeID(), false);
1613 if (status
) result
= status
;
1614 // policies (required??)
1615 status
= validate_array_of_items(trust
->_policies
, CFSTR("policy"), SecPolicyGetTypeID(), true);
1616 if (status
) result
= status
;
1617 // _responses, _SCTs, _trustedLogs, ...
1618 // verify time: SecTrustGetVerifyTime(trust)
1619 // access groups: SecAccessGroupsGetCurrent()
1624 static CFArrayRef
SecTrustGetCurrentAccessGroups(void) {
1625 static CFArrayRef accessGroups
= NULL
;
1626 static dispatch_once_t onceToken
;
1627 dispatch_once(&onceToken
, ^{
1628 accessGroups
= CFArrayCreateForCFTypes(kCFAllocatorDefault
,
1629 CFSTR("com.apple.trustd"),
1630 CFSTR("com.apple.trusttests"),
1633 return accessGroups
;
1636 static OSStatus
SecTrustEvaluateIfNecessary(SecTrustRef trust
) {
1637 __block OSStatus result
;
1642 __block CFAbsoluteTime verifyTime
= SecTrustGetVerifyTime(trust
);
1643 SecTrustAddPolicyAnchors(trust
);
1644 dispatch_sync(trust
->_trustQueue
, ^{
1645 if (trust
->_trustResult
!= kSecTrustResultInvalid
) {
1646 result
= errSecSuccess
;
1650 trust
->_trustResult
= kSecTrustResultOtherError
; /* to avoid potential recursion */
1652 CFReleaseNull(trust
->_chain
);
1653 CFReleaseNull(trust
->_details
);
1654 CFReleaseNull(trust
->_info
);
1655 if (trust
->_legacy_info_array
) {
1656 free(trust
->_legacy_info_array
);
1657 trust
->_legacy_info_array
= NULL
;
1659 if (trust
->_legacy_status_array
) {
1660 free(trust
->_legacy_status_array
);
1661 trust
->_legacy_status_array
= NULL
;
1664 os_activity_initiate("SecTrustEvaluateIfNecessary", OS_ACTIVITY_FLAG_DEFAULT
, ^{
1665 SecTrustValidateInput(trust
);
1667 /* @@@ 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. */
1668 result
= SecOSStatusWith(^bool (CFErrorRef
*error
) {
1669 trust
->_trustResult
= TRUSTD_XPC(sec_trust_evaluate
,
1670 handle_trust_evaluate_xpc
,
1671 trust
->_certificates
, trust
->_anchors
, trust
->_anchorsOnly
, trust
->_keychainsAllowed
,
1672 trust
->_policies
, trust
->_responses
, trust
->_SCTs
, trust
->_trustedLogs
,
1673 verifyTime
, SecTrustGetCurrentAccessGroups(), trust
->_exceptions
,
1674 &trust
->_details
, &trust
->_info
, &trust
->_chain
, error
);
1675 if (trust
->_trustResult
== kSecTrustResultInvalid
/* TODO check domain */ &&
1676 SecErrorGetOSStatus(*error
) == errSecNotAvailable
&&
1677 CFArrayGetCount(trust
->_certificates
)) {
1678 /* We failed to talk to securityd. The only time this should
1679 happen is when we are running prior to launchd enabling
1680 registration of services. This currently happens when we
1681 are running from the ramdisk. To make ASR happy we initialize
1682 _chain and return success with a failure as the trustResult, to
1683 make it seem like we did a cert evaluation, so ASR can extract
1684 the public key from the leaf. */
1685 SecCertificateRef leafCert
= (SecCertificateRef
)CFArrayGetValueAtIndex(trust
->_certificates
, 0);
1686 CFArrayRef leafCertArray
= CFArrayCreate(NULL
, (const void**)&leafCert
, 1, &kCFTypeArrayCallBacks
);
1687 trust
->_chain
= leafCertArray
;
1689 CFReleaseNull(*error
);
1692 return trust
->_trustResult
!= kSecTrustResultInvalid
;
1699 // IMPORTANT: this MUST be called on the provided queue as it will call the handler synchronously
1700 // if no asynchronous work is needed
1701 static void SecTrustEvaluateIfNecessaryFastAsync(SecTrustRef trust
,
1702 dispatch_queue_t queue
,
1703 void (^handler
)(OSStatus status
)) {
1707 if (handler
== NULL
) {
1710 if (trust
== NULL
|| queue
== NULL
) {
1711 handler(errSecParam
);
1715 __block
bool shouldReturnSuccess
= false;
1716 __block CFAbsoluteTime verifyTime
= SecTrustGetVerifyTime(trust
);
1717 SecTrustAddPolicyAnchors(trust
);
1718 dispatch_sync(trust
->_trustQueue
, ^{
1719 if (trust
->_trustResult
!= kSecTrustResultInvalid
) {
1720 shouldReturnSuccess
= true;
1724 trust
->_trustResult
= kSecTrustResultOtherError
; /* to avoid potential recursion */
1726 CFReleaseNull(trust
->_chain
);
1727 CFReleaseNull(trust
->_details
);
1728 CFReleaseNull(trust
->_info
);
1729 if (trust
->_legacy_info_array
) {
1730 free(trust
->_legacy_info_array
);
1731 trust
->_legacy_info_array
= NULL
;
1733 if (trust
->_legacy_status_array
) {
1734 free(trust
->_legacy_status_array
);
1735 trust
->_legacy_status_array
= NULL
;
1738 os_activity_t activity
= os_activity_create("SecTrustEvaluateIfNecessaryFastAsync",
1739 OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_DEFAULT
);
1740 __block
struct os_activity_scope_state_s activityState
;
1741 os_activity_scope_enter(activity
, &activityState
);
1742 os_release(activity
);
1744 SecTrustValidateInput(trust
);
1746 CFRetainSafe(trust
);
1747 TRUSTD_XPC_ASYNC(sec_trust_evaluate
,
1748 handle_trust_evaluate_xpc_async
,
1750 ^(SecTrustResultType tr
, CFErrorRef error
) {
1751 __block OSStatus result
= errSecInternalError
;
1752 dispatch_sync(trust
->_trustQueue
, ^{
1753 trust
->_trustResult
= tr
;
1754 if (trust
->_trustResult
== kSecTrustResultInvalid
/* TODO check domain */ &&
1755 SecErrorGetOSStatus(error
) == errSecNotAvailable
&&
1756 CFArrayGetCount(trust
->_certificates
)) {
1757 /* We failed to talk to securityd. The only time this should
1758 happen is when we are running prior to launchd enabling
1759 registration of services. This currently happens when we
1760 are running from the ramdisk. To make ASR happy we initialize
1761 _chain and return success with a failure as the trustResult, to
1762 make it seem like we did a cert evaluation, so ASR can extract
1763 the public key from the leaf. */
1764 SecCertificateRef leafCert
= (SecCertificateRef
)CFArrayGetValueAtIndex(trust
->_certificates
, 0);
1765 CFArrayRef leafCertArray
= CFArrayCreate(NULL
, (const void**)&leafCert
, 1, &kCFTypeArrayCallBacks
);
1766 trust
->_chain
= leafCertArray
;
1767 result
= errSecSuccess
;
1770 result
= SecOSStatusWith(^bool (CFErrorRef
*error2
) {
1771 if (error2
!= NULL
) {
1774 return trust
->_trustResult
!= kSecTrustResultInvalid
;
1777 os_activity_scope_leave(&activityState
);
1779 CFReleaseSafe(trust
);
1781 trust
->_certificates
, trust
->_anchors
, trust
->_anchorsOnly
, trust
->_keychainsAllowed
,
1782 trust
->_policies
, trust
->_responses
, trust
->_SCTs
, trust
->_trustedLogs
,
1783 verifyTime
, SecTrustGetCurrentAccessGroups(), trust
->_exceptions
,
1784 &trust
->_details
, &trust
->_info
, &trust
->_chain
);
1786 if (shouldReturnSuccess
) {
1787 handler(errSecSuccess
);
1791 /* Helper for the qsort below. */
1792 static int compare_strings(const void *a1
, const void *a2
) {
1793 CFStringRef s1
= *(CFStringRef
*)a1
;
1794 CFStringRef s2
= *(CFStringRef
*)a2
;
1795 return (int) CFStringCompare(s1
, s2
, kCFCompareForcedOrdering
);
1798 CFStringRef
SecTrustCopyFailureDescription(SecTrustRef trust
) {
1802 CFMutableStringRef reason
= CFStringCreateMutable(NULL
, 0);
1803 SecTrustEvaluateIfNecessary(trust
);
1804 __block CFArrayRef details
= NULL
;
1805 dispatch_sync(trust
->_trustQueue
, ^{
1806 details
= CFRetainSafe(trust
->_details
);
1808 CFIndex pathLength
= details
? CFArrayGetCount(details
) : 0;
1809 for (CFIndex ix
= 0; ix
< pathLength
; ++ix
) {
1810 CFDictionaryRef detail
= (CFDictionaryRef
)CFArrayGetValueAtIndex(details
, ix
);
1811 CFIndex dCount
= CFDictionaryGetCount(detail
);
1814 CFStringAppend(reason
, CFSTR(" [leaf"));
1815 else if (ix
== pathLength
- 1)
1816 CFStringAppend(reason
, CFSTR(" [root"));
1818 CFStringAppendFormat(reason
, NULL
, CFSTR(" [ca%" PRIdCFIndex
), ix
);
1820 const void *keys
[dCount
];
1821 CFDictionaryGetKeysAndValues(detail
, &keys
[0], NULL
);
1822 qsort(&keys
[0], dCount
, sizeof(keys
[0]), compare_strings
);
1823 for (CFIndex kix
= 0; kix
< dCount
; ++kix
) {
1824 CFStringRef key
= keys
[kix
];
1825 const void *value
= CFDictionaryGetValue(detail
, key
);
1826 CFStringAppendFormat(reason
, NULL
, CFSTR(" %@%@"), key
,
1827 (CFGetTypeID(value
) == CFBooleanGetTypeID()
1828 ? CFSTR("") : value
));
1830 CFStringAppend(reason
, CFSTR("]"));
1833 CFReleaseSafe(details
);
1837 SecKeyRef
SecTrustCopyKey(SecTrustRef trust
)
1842 __block SecKeyRef publicKey
= NULL
;
1843 dispatch_sync(trust
->_trustQueue
, ^{
1844 if (trust
->_publicKey
) {
1845 publicKey
= CFRetainSafe(trust
->_publicKey
);
1848 SecCertificateRef leaf
= (SecCertificateRef
)CFArrayGetValueAtIndex(trust
->_certificates
, 0);
1849 trust
->_publicKey
= SecCertificateCopyKey(leaf
);
1850 if (trust
->_publicKey
) {
1851 publicKey
= CFRetainSafe(trust
->_publicKey
);
1854 /* If we couldn't get a public key from the leaf cert alone. */
1856 SecTrustEvaluateIfNecessary(trust
);
1857 dispatch_sync(trust
->_trustQueue
, ^{
1858 if (trust
->_chain
) {
1859 SecCertificateRef cert
= (SecCertificateRef
)CFArrayGetValueAtIndex(trust
->_chain
, 0);
1860 trust
->_publicKey
= SecCertificateCopyKey(cert
);
1861 publicKey
= CFRetainSafe(trust
->_publicKey
);
1869 /* On OS X we need SecTrustCopyPublicKey to give us a CDSA-based SecKeyRef,
1870 so we will refer to this one internally as SecTrustCopyPublicKey_ios,
1871 and call it from SecTrustCopyPublicKey.
1873 SecKeyRef
SecTrustCopyPublicKey_ios(SecTrustRef trust
)
1875 SecKeyRef
SecTrustCopyPublicKey(SecTrustRef trust
)
1878 return SecTrustCopyKey(trust
);
1881 CFIndex
SecTrustGetCertificateCount(SecTrustRef trust
) {
1885 SecTrustEvaluateIfNecessary(trust
);
1886 __block CFIndex certCount
= 1;
1887 dispatch_sync(trust
->_trustQueue
, ^{
1888 if (trust
->_chain
) {
1889 certCount
= CFArrayGetCount(trust
->_chain
);
1895 SecCertificateRef
SecTrustGetCertificateAtIndex(SecTrustRef trust
,
1900 __block SecCertificateRef cert
= NULL
;
1902 dispatch_sync(trust
->_trustQueue
, ^{
1903 cert
= (SecCertificateRef
)CFArrayGetValueAtIndex(trust
->_certificates
, 0);
1907 SecTrustEvaluateIfNecessary(trust
);
1908 dispatch_sync(trust
->_trustQueue
, ^{
1909 if (trust
->_chain
) {
1910 cert
= (SecCertificateRef
)CFArrayGetValueAtIndex(trust
->_chain
, ix
);
1916 CFDictionaryRef
SecTrustCopyInfo(SecTrustRef trust
) {
1920 SecTrustEvaluateIfNecessary(trust
);
1921 __block CFDictionaryRef info
= NULL
;
1922 dispatch_sync(trust
->_trustQueue
, ^{
1923 info
= CFRetainSafe(trust
->_info
);
1928 CFArrayRef
SecTrustGetTrustExceptionsArray(SecTrustRef trust
) {
1932 __block CFArrayRef exceptions
= NULL
;
1933 dispatch_sync(trust
->_trustQueue
, ^{
1934 exceptions
= trust
->_exceptions
;
1939 CFDataRef
SecTrustCopyExceptions(SecTrustRef trust
) {
1940 /* Stash the old exceptions and run an evaluation with no exceptions filtered. */
1941 __block CFArrayRef oldExceptions
= NULL
;
1942 dispatch_sync(trust
->_trustQueue
, ^{
1943 if (trust
->_exceptions
) {
1944 oldExceptions
= trust
->_exceptions
;
1945 trust
->_exceptions
= NULL
;
1948 SecTrustSetNeedsEvaluation(trust
);
1950 /* Create the new exceptions based on an unfiltered eval. */
1951 __block CFArrayRef details
= NULL
;
1952 SecTrustEvaluateIfNecessary(trust
);
1953 dispatch_sync(trust
->_trustQueue
, ^{
1954 details
= CFRetainSafe(trust
->_details
);
1956 CFIndex pathLength
= details
? CFArrayGetCount(details
) : 0;
1957 CFMutableArrayRef exceptions
= CFArrayCreateMutable(kCFAllocatorDefault
, pathLength
, &kCFTypeArrayCallBacks
);
1958 #if TARGET_OS_IPHONE
1959 /* Fetch the current exceptions epoch and tag each exception with it. */
1960 CFErrorRef exceptionResetCountError
= NULL
;
1961 uint64_t exceptionResetCount
= SecTrustGetExceptionResetCount(&exceptionResetCountError
);
1962 secinfo("trust", "The current exceptions epoch is %llu. (%{public}s)", exceptionResetCount
, exceptionResetCountError
? "Error" : "OK");
1963 CFNumberRef exceptionResetCountRef
= CFNumberCreate(NULL
, kCFNumberSInt64Type
, &exceptionResetCount
);
1966 for (ix
= 0; ix
< pathLength
; ++ix
) {
1967 CFDictionaryRef detail
= (CFDictionaryRef
)CFArrayGetValueAtIndex(details
, ix
);
1968 CFIndex detailCount
= CFDictionaryGetCount(detail
);
1969 CFMutableDictionaryRef exception
;
1970 if (ix
== 0 || detailCount
> 0) {
1971 exception
= CFDictionaryCreateMutableCopy(kCFAllocatorDefault
, detailCount
+ 1, detail
);
1972 SecCertificateRef certificate
= SecTrustGetCertificateAtIndex(trust
, ix
);
1973 CFDataRef digest
= SecCertificateGetSHA1Digest(certificate
);
1974 CFDictionaryAddValue(exception
, kSecCertificateDetailSHA1Digest
, digest
);
1975 #if TARGET_OS_IPHONE
1976 if (exceptionResetCount
&& !exceptionResetCountError
&& exceptionResetCountRef
) {
1977 CFDictionaryAddValue(exception
, kSecCertificateExceptionResetCount
, exceptionResetCountRef
);
1981 /* Add empty exception dictionaries for non leaf certs which have no exceptions to save space. */
1982 exception
= (CFMutableDictionaryRef
)CFDictionaryCreate(kCFAllocatorDefault
, NULL
, NULL
, 0,
1983 &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
1985 CFArrayAppendValue(exceptions
, exception
);
1986 CFReleaseNull(exception
);
1989 /* Restore the stashed exceptions. */
1990 if (oldExceptions
) {
1991 dispatch_sync(trust
->_trustQueue
, ^{
1992 trust
->_exceptions
= oldExceptions
;
1994 SecTrustSetNeedsEvaluation(trust
);
1997 /* Remove any trailing empty dictionaries to save even more space (we skip the leaf
1998 since it will never be empty). */
1999 for (ix
= pathLength
; ix
-- > 1;) {
2000 CFDictionaryRef exception
= (CFDictionaryRef
)CFArrayGetValueAtIndex(exceptions
, ix
);
2001 if (CFDictionaryGetCount(exception
) == 0) {
2002 CFArrayRemoveValueAtIndex(exceptions
, ix
);
2008 CFDataRef encodedExceptions
= CFPropertyListCreateData(kCFAllocatorDefault
,
2009 exceptions
, kCFPropertyListBinaryFormat_v1_0
, 0, NULL
);
2010 CFRelease(exceptions
);
2011 CFReleaseSafe(details
);
2012 #if TARGET_OS_IPHONE
2013 CFReleaseSafe(exceptionResetCountRef
);
2015 return encodedExceptions
;
2018 #if TARGET_OS_IPHONE
2019 static bool SecTrustExceptionsValidForThisEpoch(CFArrayRef exceptions
) {
2023 CFDictionaryRef exception
= (CFDictionaryRef
)CFArrayGetValueAtIndex(exceptions
, 0);
2025 CFErrorRef currentExceptionResetCountError
= NULL
;
2026 uint64_t currentExceptionResetCount
= SecTrustGetExceptionResetCount(¤tExceptionResetCountError
);
2027 secinfo("trust", "The current exceptions epoch is %llu. (%{public}s)", currentExceptionResetCount
, currentExceptionResetCountError
? "Error" : "OK");
2028 /* Fail closed: if we were unable to get the current exceptions epoch consider the exceptions invalid. */
2029 if (currentExceptionResetCountError
) {
2030 secerror("Failed to get the current exceptions epoch.");
2033 /* If this is the first epoch ever there is no point in checking whether any exceptions belong in the past. */
2034 if (currentExceptionResetCount
== 0) {
2038 CFNumberRef resetCountRef
= CFDictionaryGetValue(exception
, kSecCertificateExceptionResetCount
);
2039 if (!resetCountRef
) {
2040 secerror("Failed to get the exception's epoch.");
2044 uint64_t exceptionResetCount
;
2045 if (!CFNumberGetValue(resetCountRef
, kCFNumberSInt64Type
, &exceptionResetCount
)) {
2046 secerror("Failed to parse the current exceptions epoch as a uint64.");
2050 if (exceptionResetCount
!= currentExceptionResetCount
) {
2051 secerror("The current exception's epoch (%llu) is not the current epoch. (%llu)", exceptionResetCount
, currentExceptionResetCount
);
2055 secinfo("trust", "Exceptions are valid for the current exceptions epoch. (%llu)", currentExceptionResetCount
);
2060 bool SecTrustSetExceptions(SecTrustRef trust
, CFDataRef encodedExceptions
) {
2064 CFArrayRef exceptions
= NULL
;
2066 if (NULL
!= encodedExceptions
) {
2067 exceptions
= (CFArrayRef
)CFPropertyListCreateWithData(kCFAllocatorDefault
,
2068 encodedExceptions
, kCFPropertyListImmutable
, NULL
, NULL
);
2071 if (exceptions
&& CFGetTypeID(exceptions
) != CFArrayGetTypeID()) {
2072 CFRelease(exceptions
);
2076 dispatch_sync(trust
->_trustQueue
, ^{
2077 CFReleaseSafe(trust
->_exceptions
);
2078 trust
->_exceptions
= exceptions
;
2081 /* We changed the exceptions -- so we need to re-evaluate */
2082 SecTrustSetNeedsEvaluation(trust
);
2084 /* If there is a valid exception entry for our current leaf we're golden. */
2085 #if TARGET_OS_IPHONE
2086 if (SecTrustGetExceptionForCertificateAtIndex(trust
, 0) && SecTrustExceptionsValidForThisEpoch(exceptions
)) {
2088 if (SecTrustGetExceptionForCertificateAtIndex(trust
, 0)) {
2093 /* The passed in exceptions didn't match our current leaf, so we discard it. */
2094 dispatch_sync(trust
->_trustQueue
, ^{
2095 CFReleaseNull(trust
->_exceptions
);
2102 SecTrustSetOptions(SecTrustRef trustRef
, SecTrustOptionFlags options
)
2104 /* bridge to support API functionality for legacy callers */
2105 OSStatus status
= errSecSuccess
;
2107 /* No options or none that trigger the exceptions behavior */
2109 0 == (options
& (kSecTrustOptionAllowExpired
|
2110 kSecTrustOptionImplicitAnchors
|
2111 kSecTrustOptionAllowExpiredRoot
))) {
2115 __block CFMutableArrayRef exceptions
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
2116 if (!exceptions
) { return errSecAllocate
; }
2118 /* Add the new options to the old_exceptions when those exceptions are tied to a particular cert.
2119 * If not tied to a particular cert, we reset the exceptions based on the input options. */
2120 CFArrayRef old_exceptions
= SecTrustGetTrustExceptionsArray(trustRef
);
2121 if (old_exceptions
&& SecTrustGetExceptionForCertificateAtIndex(trustRef
, 0)) {
2122 CFIndex ix
, count
= CFArrayGetCount(old_exceptions
);
2123 for (ix
= 0; ix
< count
; ix
++) {
2124 CFMutableDictionaryRef exception_dictionary
= CFDictionaryCreateMutableCopy(NULL
, 0, (CFDictionaryRef
)CFArrayGetValueAtIndex(old_exceptions
, ix
));
2125 if (!exception_dictionary
) { status
= errSecAllocate
; goto out
; }
2126 if ((options
& kSecTrustOptionAllowExpired
) != 0) {
2127 CFDictionaryAddValue(exception_dictionary
, kSecPolicyCheckTemporalValidity
, kCFBooleanFalse
);
2129 if ((options
& (kSecTrustOptionImplicitAnchors
| kSecTrustOptionAllowExpiredRoot
)) != 0) {
2130 /* Check that root is self-signed. */
2131 Boolean isSelfSigned
= false;
2132 SecCertificateRef cert
= SecTrustGetCertificateAtIndex(trustRef
, ix
);
2133 if (cert
&& (errSecSuccess
== SecCertificateIsSelfSigned(cert
, &isSelfSigned
)) &&
2135 if ((options
& kSecTrustOptionImplicitAnchors
) != 0) {
2136 CFDictionaryAddValue(exception_dictionary
, kSecPolicyCheckAnchorTrusted
, kCFBooleanFalse
);
2137 } else if ((options
& kSecTrustOptionAllowExpiredRoot
) != 0) {
2138 CFDictionaryAddValue(exception_dictionary
, kSecPolicyCheckTemporalValidity
, kCFBooleanFalse
);
2142 CFArrayAppendValue(exceptions
, exception_dictionary
);
2143 CFReleaseNull(exception_dictionary
);
2146 /* Create a new exceptions array. Warning, this takes advantage of implementation details of the exceptions mechanism. */
2147 CFMutableDictionaryRef exception_dictionary
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
,
2148 &kCFTypeDictionaryValueCallBacks
);
2149 if (!exception_dictionary
) { status
= errSecAllocate
; goto out
; }
2150 if ((options
& kSecTrustOptionAllowExpired
) != 0) {
2151 CFDictionaryAddValue(exception_dictionary
, kSecPolicyCheckTemporalValidity
, kCFBooleanFalse
);
2153 if ((options
& kSecTrustOptionAllowExpiredRoot
) != 0) {
2154 CFDictionaryAddValue(exception_dictionary
, kSecPolicyCheckValidRoot
, kCFBooleanFalse
);
2156 if ((options
& kSecTrustOptionImplicitAnchors
) != 0) {
2157 CFDictionaryAddValue(exception_dictionary
, kSecPolicyCheckAnchorTrusted
, kCFBooleanFalse
);
2159 CFArrayAppendValue(exceptions
, exception_dictionary
);
2160 CFReleaseNull(exception_dictionary
);
2163 /* Set exceptions */
2164 dispatch_sync(trustRef
->_trustQueue
, ^{
2165 CFReleaseSafe(trustRef
->_exceptions
);
2166 trustRef
->_exceptions
= CFRetainSafe(exceptions
);
2168 /* We changed the exceptions -- so we need to re-evaluate */
2169 SecTrustSetNeedsEvaluation(trustRef
);
2172 CFReleaseNull(exceptions
);
2177 CFArrayRef
SecTrustCopySummaryPropertiesAtIndex(SecTrustRef trust
, CFIndex ix
) {
2178 CFMutableArrayRef summary
;
2179 SecCertificateRef certificate
= SecTrustGetCertificateAtIndex(trust
, ix
);
2180 summary
= SecCertificateCopySummaryProperties(certificate
,
2181 SecTrustGetVerifyTime(trust
));
2182 /* FIXME Add more details in the failure case. */
2187 CFArrayRef
SecTrustCopyDetailedPropertiesAtIndex(SecTrustRef trust
, CFIndex ix
) {
2189 SecCertificateRef certificate
= SecTrustGetCertificateAtIndex(trust
, ix
);
2190 summary
= SecCertificateCopyProperties(certificate
);
2195 struct TrustFailures
{
2197 bool unknownCritExtn
;
2198 bool untrustedAnchor
;
2199 bool missingIntermediate
;
2200 bool hostnameMismatch
;
2208 static void applyDetailProperty(const void *_key
, const void *_value
,
2210 CFStringRef key
= (CFStringRef
)_key
;
2211 struct TrustFailures
*tf
= (struct TrustFailures
*)context
;
2212 if (CFGetTypeID(_value
) != CFBooleanGetTypeID()) {
2213 /* Value isn't a CFBooleanRef, oh no! */
2216 CFBooleanRef value
= (CFBooleanRef
)_value
;
2217 if (CFBooleanGetValue(value
)) {
2218 /* Not an actual failure so we don't report it. */
2222 /* @@@ FIXME: Report a different return value when something is in the
2223 details but masked out by an exception and use that below for display
2225 if (CFEqual(key
, kSecPolicyCheckIdLinkage
)) {
2226 tf
->badLinkage
= true;
2227 } else if (CFEqual(key
, kSecPolicyCheckCriticalExtensions
)) {
2228 tf
->unknownCritExtn
= true;
2229 } else if (CFEqual(key
, kSecPolicyCheckAnchorTrusted
)
2230 || CFEqual(key
, kSecPolicyCheckAnchorSHA256
)
2231 || CFEqual(key
, kSecPolicyCheckAnchorApple
)) {
2232 tf
->untrustedAnchor
= true;
2233 } else if (CFEqual(key
, kSecPolicyCheckMissingIntermediate
)) {
2234 tf
->missingIntermediate
= true;
2235 } else if (CFEqual(key
, kSecPolicyCheckSSLHostname
)) {
2236 tf
->hostnameMismatch
= true;
2237 } else if (CFEqual(key
, kSecPolicyCheckTemporalValidity
)) {
2238 tf
->invalidCert
= true;
2239 } else if (CFEqual(key
, kSecPolicyCheckWeakKeySize
)
2240 || CFEqualSafe(key
, kSecPolicyCheckKeySize
)
2241 || CFEqualSafe(key
, kSecPolicyCheckSystemTrustedWeakKey
)) {
2243 } else if (CFEqual(key
, kSecPolicyCheckWeakSignature
)
2244 || CFEqualSafe(key
, kSecPolicyCheckSignatureHashAlgorithms
)
2245 || CFEqualSafe(key
, kSecPolicyCheckSystemTrustedWeakHash
)) {
2246 tf
->weakHash
= true;
2247 } else if (CFEqual(key
, kSecPolicyCheckRevocation
)) {
2248 tf
->revocation
= true;
2250 /* Anything else is a policy failure. */
2251 tf
->policyFail
= true;
2255 static void appendError(CFMutableArrayRef properties
, CFStringRef error
, bool localized
) {
2256 CFStringRef localizedError
= NULL
;
2259 } else if (localized
) {
2260 //%%% "SecCertificate" should be changed to "Certificate": rdar://37517120
2261 localizedError
= SecFrameworkCopyLocalizedString(error
, CFSTR("SecCertificate"));
2263 localizedError
= (CFStringRef
) CFRetainSafe(error
);
2265 appendProperty(properties
, kSecPropertyTypeError
, NULL
, NULL
,
2266 localizedError
, localized
);
2267 CFReleaseNull(localizedError
);
2271 /* OS X properties array has a different structure and is implemented SecTrust.cpp. */
2272 CFArrayRef
SecTrustCopyProperties_ios(SecTrustRef trust
)
2274 CFArrayRef
SecTrustCopyProperties(SecTrustRef trust
)
2280 SecTrustEvaluateIfNecessary(trust
);
2281 bool localized
= true;
2282 __block CFArrayRef details
= NULL
;
2283 dispatch_sync(trust
->_trustQueue
, ^{
2284 details
= CFRetainSafe(trust
->_details
);
2290 struct TrustFailures tf
= {};
2292 CFIndex ix
, count
= CFArrayGetCount(details
);
2293 for (ix
= 0; ix
< count
; ++ix
) {
2294 CFDictionaryRef detail
= (CFDictionaryRef
)
2295 CFArrayGetValueAtIndex(details
, ix
);
2296 /* We now have a detail dictionary for certificate at index ix, with
2297 a key value pair for each failed policy check. Let's convert it
2298 from Ro-Man form into something a Hu-Man can understand. */
2299 CFDictionaryApplyFunction(detail
, applyDetailProperty
, &tf
);
2302 CFMutableArrayRef properties
= CFArrayCreateMutable(kCFAllocatorDefault
, 0,
2303 &kCFTypeArrayCallBacks
);
2304 /* The badLinkage and unknownCritExtn failures are short circuited, since
2305 you can't recover from those errors. */
2306 if (tf
.badLinkage
) {
2307 appendError(properties
, CFSTR("Invalid certificate chain linkage."), localized
);
2308 } else if (tf
.unknownCritExtn
) {
2309 appendError(properties
, CFSTR("One or more unsupported critical extensions found."), localized
);
2311 if (tf
.untrustedAnchor
) {
2312 appendError(properties
, CFSTR("Root certificate is not trusted."), localized
);
2314 if (tf
.missingIntermediate
) {
2315 appendError(properties
, CFSTR("Unable to build chain to root certificate."), localized
);
2317 if (tf
.hostnameMismatch
) {
2318 appendError(properties
, CFSTR("Hostname mismatch."), localized
);
2320 if (tf
.policyFail
) {
2321 appendError(properties
, CFSTR("Policy requirements not met."), localized
);
2323 if (tf
.invalidCert
) {
2324 appendError(properties
, CFSTR("One or more certificates have expired or are not valid yet."), localized
);
2327 appendError(properties
, CFSTR("One or more certificates is using a weak key size."), localized
);
2330 appendError(properties
, CFSTR("One or more certificates is using a weak signature algorithm."), localized
);
2332 if (tf
.revocation
) {
2333 appendError(properties
, CFSTR("One or more certificates have been revoked."), localized
);
2337 if (CFArrayGetCount(properties
) == 0) {
2338 /* The certificate chain is trusted, return an empty plist */
2339 CFReleaseNull(properties
);
2342 CFReleaseNull(details
);
2347 static void _AppendStatusCode(CFMutableArrayRef array
, OSStatus statusCode
) {
2351 SInt32 num
= statusCode
;
2352 CFNumberRef numRef
= CFNumberCreate(NULL
, kCFNumberSInt32Type
, &num
);
2356 CFArrayAppendValue(array
, numRef
);
2361 static CFArrayRef
_SecTrustCopyDetails(SecTrustRef trust
) {
2365 __block CFArrayRef details
= NULL
;
2366 dispatch_sync(trust
->_trustQueue
, ^{
2367 details
= CFRetainSafe(trust
->_details
);
2370 // Include status codes in the per-certificate details (rdar://27930542)
2371 CFMutableArrayRef newDetails
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
2373 CFReleaseSafe(details
);
2376 CFIndex index
, chainLen
= (details
) ? CFArrayGetCount(details
) : 0;
2377 for (index
= 0; index
< chainLen
; index
++) {
2378 CFDictionaryRef detailDict
= CFArrayGetValueAtIndex(details
, index
);
2379 CFMutableDictionaryRef newDict
= CFDictionaryCreateMutableCopy(NULL
, 0, detailDict
);
2380 CFMutableArrayRef statusCodes
= CFArrayCreateMutable(kCFAllocatorDefault
,
2381 0, &kCFTypeArrayCallBacks
);
2383 CFIndex i
, numCodes
= 0;
2384 SInt32
*codes
= SecTrustCopyStatusCodes(trust
, index
, &numCodes
);
2386 for (i
= 0; i
< numCodes
; i
++) {
2387 OSStatus scode
= (OSStatus
)codes
[i
];
2388 _AppendStatusCode(statusCodes
, scode
);
2392 if (CFArrayGetCount(statusCodes
) > 0) {
2393 CFDictionarySetValue(newDict
, kSecCertificateDetailStatusCodes
, statusCodes
);
2395 CFRelease(statusCodes
);
2398 CFArrayAppendValue(newDetails
, newDict
);
2402 CFReleaseSafe(details
);
2409 CFDictionaryRef
SecTrustCopyResult(SecTrustRef trust
) {
2410 // Builds and returns a dictionary of evaluation results.
2414 __block CFMutableDictionaryRef results
= CFDictionaryCreateMutable(NULL
, 0,
2415 &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
2417 SecTrustEvaluateIfNecessary(trust
);
2418 __block CFArrayRef details
= _SecTrustCopyDetails(trust
);
2420 dispatch_sync(trust
->_trustQueue
, ^{
2421 // kSecTrustResultDetails (per-cert results)
2423 CFDictionarySetValue(results
, (const void *)kSecTrustResultDetails
, (const void *)details
);
2427 // kSecTrustResultValue (overall trust result)
2428 CFNumberRef numValue
= CFNumberCreate(NULL
, kCFNumberSInt32Type
, &trust
->_trustResult
);
2430 CFDictionarySetValue(results
, (const void *)kSecTrustResultValue
, (const void *)numValue
);
2431 CFRelease(numValue
);
2433 CFDictionaryRef info
= trust
->_info
;
2434 if (trust
->_trustResult
== kSecTrustResultInvalid
|| !info
) {
2435 return; // we have nothing more to add
2438 // kSecTrustEvaluationDate
2439 CFDateRef evaluationDate
= trust
->_verifyDate
;
2440 if (evaluationDate
) {
2441 CFDictionarySetValue(results
, (const void *)kSecTrustEvaluationDate
, (const void *)evaluationDate
);
2444 // kSecTrustCertificateTransparency
2445 CFBooleanRef ctValue
;
2446 if (CFDictionaryGetValueIfPresent(info
, kSecTrustInfoCertificateTransparencyKey
, (const void **)&ctValue
)) {
2447 CFDictionarySetValue(results
, (const void *)kSecTrustCertificateTransparency
, (const void *)ctValue
);
2450 // kSecTrustExtendedValidation
2451 CFBooleanRef evValue
;
2452 if (CFDictionaryGetValueIfPresent(info
, kSecTrustInfoExtendedValidationKey
, (const void **)&evValue
)) {
2453 CFDictionarySetValue(results
, (const void *)kSecTrustExtendedValidation
, (const void *)evValue
);
2456 // kSecTrustOrganizationName
2457 CFStringRef organizationName
;
2458 if (CFDictionaryGetValueIfPresent(info
, kSecTrustInfoCompanyNameKey
, (const void **)&organizationName
)) {
2459 CFDictionarySetValue(results
, (const void *)kSecTrustOrganizationName
, (const void *)organizationName
);
2462 // kSecTrustRevocationChecked
2463 CFBooleanRef revocationChecked
;
2464 if (CFDictionaryGetValueIfPresent(info
, kSecTrustRevocationChecked
, (const void **)&revocationChecked
)) {
2465 CFDictionarySetValue(results
, (const void *)kSecTrustRevocationChecked
, (const void *)revocationChecked
);
2468 // kSecTrustRevocationReason
2469 CFNumberRef revocationReason
;
2470 if (CFDictionaryGetValueIfPresent(info
, kSecTrustRevocationReason
, (const void **)&revocationReason
)) {
2471 CFDictionarySetValue(results
, (const void *)kSecTrustRevocationReason
, (const void *)revocationReason
);
2474 // kSecTrustRevocationValidUntilDate
2475 CFDateRef validUntilDate
;
2476 if (CFDictionaryGetValueIfPresent(info
, kSecTrustRevocationValidUntilDate
, (const void **)&validUntilDate
)) {
2477 CFDictionarySetValue(results
, (const void *)kSecTrustRevocationValidUntilDate
, (const void *)validUntilDate
);
2484 #define do_if_registered(sdp, ...) if (gTrustd && gTrustd->sdp) { return gTrustd->sdp(__VA_ARGS__); }
2486 static bool xpc_dictionary_entry_is_type(xpc_object_t dictionary
, const char *key
, xpc_type_t type
) {
2487 xpc_object_t value
= xpc_dictionary_get_value(dictionary
, key
);
2488 return value
&& (xpc_get_type(value
) == type
);
2491 static uint64_t do_ota_pki_op (enum SecXPCOperation op
, CFErrorRef
*error
) {
2493 xpc_object_t message
= securityd_create_message(op
, error
);
2495 xpc_object_t response
= securityd_message_with_reply_sync(message
, error
);
2496 if (response
&& xpc_dictionary_entry_is_type(response
, kSecXPCKeyResult
, XPC_TYPE_UINT64
)) {
2497 num
= (int64_t) xpc_dictionary_get_uint64(response
, kSecXPCKeyResult
);
2499 if (response
&& error
&& xpc_dictionary_entry_is_type(response
, kSecXPCKeyError
, XPC_TYPE_DICTIONARY
)) {
2500 xpc_object_t xpc_error
= xpc_dictionary_get_value(response
, kSecXPCKeyError
);
2502 *error
= SecCreateCFErrorWithXPCObject(xpc_error
);
2505 xpc_release_safe(message
);
2506 xpc_release_safe(response
);
2511 // version 0 -> error, so we need to start at version 1 or later.
2512 uint64_t SecTrustGetTrustStoreVersionNumber(CFErrorRef
*error
) {
2513 do_if_registered(sec_ota_pki_trust_store_version
, error
);
2515 os_activity_t activity
= os_activity_create("SecTrustGetTrustStoreVersionNumber", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_DEFAULT
);
2516 os_activity_scope(activity
);
2518 uint64_t num
= do_ota_pki_op(sec_ota_pki_trust_store_version_id
, error
);
2520 os_release(activity
);
2524 uint64_t SecTrustGetAssetVersionNumber(CFErrorRef
*error
) {
2525 do_if_registered(sec_ota_pki_asset_version
, error
);
2527 os_activity_t activity
= os_activity_create("SecTrustGetAssetVersionNumber", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_DEFAULT
);
2528 os_activity_scope(activity
);
2530 uint64_t num
= do_ota_pki_op(sec_ota_pki_asset_version_id
, error
);
2532 os_release(activity
);
2536 uint64_t SecTrustOTAPKIGetUpdatedAsset(CFErrorRef
*error
) {
2537 do_if_registered(sec_ota_pki_get_new_asset
, error
);
2539 os_activity_t activity
= os_activity_create("SecTrustOTAPKIGetUpdatedAsset", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_DEFAULT
);
2540 os_activity_scope(activity
);
2542 uint64_t num
= do_ota_pki_op(kSecXPCOpOTAPKIGetNewAsset
, error
);
2544 os_release(activity
);
2548 uint64_t SecTrustOTASecExperimentGetUpdatedAsset(CFErrorRef
*error
) {
2549 do_if_registered(sec_ota_secexperiment_get_new_asset
, error
);
2551 os_activity_t activity
= os_activity_create("SecTrustOTASecExperimentGetUpdatedAsset", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_DEFAULT
);
2552 os_activity_scope(activity
);
2554 uint64_t num
= do_ota_pki_op(kSecXPCOpOTASecExperimentGetNewAsset
, error
);
2556 os_release(activity
);
2560 CFDictionaryRef
SecTrustOTASecExperimentCopyAsset(CFErrorRef
*error
) {
2561 __block CFDictionaryRef result
= NULL
;
2562 do_if_registered(sec_ota_secexperiment_get_asset
, error
);
2564 securityd_send_sync_and_do(kSecXPCOpOTASecExperimentGetAsset
, error
, ^bool(xpc_object_t message
, CFErrorRef
*blockError
) {
2565 // input: set message parameters here
2567 }, ^bool(xpc_object_t response
, CFErrorRef
*blockError
) {
2568 // output: get array from response object
2569 xpc_object_t xpc_dict
= NULL
;
2571 xpc_dict
= xpc_dictionary_get_value(response
, kSecXPCKeyResult
);
2573 if (xpc_dict
&& (xpc_get_type(xpc_dict
) == XPC_TYPE_DICTIONARY
)) {
2574 result
= (CFDictionaryRef
)_CFXPCCreateCFObjectFromXPCObject(xpc_dict
);
2576 return SecError(errSecInternal
, blockError
, CFSTR("Unable to get SecExperiment Assets"));
2578 return result
!= NULL
;
2583 bool SecTrustTriggerValidUpdate(CFErrorRef
*error
) {
2584 do_if_registered(sec_valid_update
, error
);
2586 os_activity_t activity
= os_activity_create("SecTrustTriggerValidUpdate", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_DEFAULT
);
2587 os_activity_scope(activity
);
2589 uint64_t num
= do_ota_pki_op(kSecXPCOpValidUpdate
, error
);
2591 os_release(activity
);
2595 bool SecTrustReportTLSAnalytics(CFStringRef eventName
, xpc_object_t eventAttributes
, CFErrorRef
*error
) {
2596 if (!eventName
|| !eventAttributes
) {
2599 do_if_registered(sec_networking_analytics_report
, eventName
, eventAttributes
, error
);
2601 os_activity_t activity
= os_activity_create("SecTrustReportTLSAnalytics", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_DEFAULT
);
2602 os_activity_scope(activity
);
2604 __block
bool result
= false;
2605 securityd_send_sync_and_do(kSecXPCOpNetworkingAnalyticsReport
, error
, ^bool(xpc_object_t message
, CFErrorRef
*block_error
) {
2606 if (!SecXPCDictionarySetString(message
, kSecTrustEventNameKey
, eventName
, block_error
)) {
2609 xpc_dictionary_set_value(message
, kSecTrustEventAttributesKey
, eventAttributes
);
2611 }, ^bool(xpc_object_t response
, CFErrorRef
*block_error
) {
2612 result
= SecXPCDictionaryGetBool(response
, kSecXPCKeyResult
, block_error
);
2616 os_release(activity
);
2620 bool SecTrustReportNetworkingAnalytics(const char *eventNameString
, xpc_object_t eventAttributes
) {
2621 if (!eventNameString
|| !eventAttributes
) {
2625 CFStringRef eventName
= CFStringCreateWithCString(kCFAllocatorDefault
, eventNameString
, kCFStringEncodingUTF8
);
2627 secerror("CFStringCreateWithCString failed");
2631 CFErrorRef error
= NULL
;
2632 if (gTrustd
&& gTrustd
->sec_networking_analytics_report
) {
2633 bool result
= gTrustd
->sec_networking_analytics_report(eventName
, eventAttributes
, &error
);
2634 if (error
!= NULL
) {
2635 secerror("SecTrustReportNetworkingAnalytics failed with error: %d", (int)CFErrorGetCode(error
));
2637 CFReleaseNull(eventName
);
2638 CFReleaseNull(error
);
2642 os_activity_t activity
= os_activity_create("SecTrustReportNetworkingAnalytics", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_DEFAULT
);
2643 os_activity_scope(activity
);
2645 __block
bool result
= false;
2646 securityd_send_sync_and_do(kSecXPCOpNetworkingAnalyticsReport
, &error
, ^bool(xpc_object_t message
, CFErrorRef
*block_error
) {
2647 if (!SecXPCDictionarySetString(message
, kSecTrustEventNameKey
, eventName
, block_error
)) {
2650 xpc_dictionary_set_value(message
, kSecTrustEventAttributesKey
, eventAttributes
);
2652 }, ^bool(xpc_object_t response
, CFErrorRef
*block_error
) {
2653 result
= SecXPCDictionaryGetBool(response
, kSecXPCKeyResult
, block_error
);
2657 if (error
!= NULL
) {
2658 secerror("SecTrustReportNetworkingAnalytics failed with error: %d", (int)CFErrorGetCode(error
));
2660 CFReleaseNull(error
);
2661 CFReleaseNull(eventName
);
2663 os_release(activity
);
2669 * This function performs an evaluation of the leaf certificate only, and
2670 * does so in the process that called it. Its primary use is in SecItemCopyMatching
2671 * when kSecMatchPolicy is in the dictionary.
2673 OSStatus
SecTrustEvaluateLeafOnly(SecTrustRef trust
, SecTrustResultType
*result
) {
2677 OSStatus status
= errSecSuccess
;
2678 SecTrustResultType trustResult
= kSecTrustResultInvalid
;
2679 if((status
= SecTrustValidateInput(trust
))) {
2683 struct OpaqueSecLeafPVC pvc
;
2684 SecCertificateRef leaf
= SecTrustGetCertificateAtIndex(trust
, 0);
2685 __block CFArrayRef policies
= NULL
;
2686 dispatch_sync(trust
->_trustQueue
, ^{
2687 policies
= CFRetainSafe(trust
->_policies
);
2689 SecLeafPVCInit(&pvc
, leaf
, policies
, SecTrustGetVerifyTime(trust
));
2691 if(!SecLeafPVCLeafChecks(&pvc
)) {
2692 trustResult
= kSecTrustResultRecoverableTrustFailure
;
2694 trustResult
= kSecTrustResultUnspecified
;
2697 /* Set other result context information */
2698 dispatch_sync(trust
->_trustQueue
, ^{
2699 trust
->_trustResult
= trustResult
;
2700 trust
->_details
= CFRetainSafe(pvc
.details
);
2701 trust
->_info
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0,
2702 &kCFTypeDictionaryKeyCallBacks
,
2703 &kCFTypeDictionaryValueCallBacks
);
2704 CFMutableArrayRef leafCert
= CFArrayCreateMutableCopy(NULL
, 1, trust
->_certificates
);
2705 trust
->_chain
= leafCert
;
2708 SecLeafPVCDelete(&pvc
);
2710 /* log to syslog when there is a trust failure */
2711 if (trustResult
!= kSecTrustResultUnspecified
) {
2712 CFStringRef failureDesc
= SecTrustCopyFailureDescription(trust
);
2713 secerror("%@", failureDesc
);
2714 CFRelease(failureDesc
);
2718 *result
= trustResult
;
2721 CFReleaseSafe(policies
);
2725 static void deserializeCert(const void *value
, void *context
) {
2726 CFDataRef certData
= (CFDataRef
)value
;
2727 if (isData(certData
)) {
2728 SecCertificateRef cert
= SecCertificateCreateWithData(NULL
, certData
);
2730 CFArrayAppendValue((CFMutableArrayRef
)context
, cert
);
2736 static CF_RETURNS_RETAINED CFArrayRef
SecCertificateArrayDeserialize(CFArrayRef serializedCertificates
) {
2737 CFMutableArrayRef result
= NULL
;
2738 require_quiet(isArray(serializedCertificates
), errOut
);
2739 CFIndex count
= CFArrayGetCount(serializedCertificates
);
2740 result
= CFArrayCreateMutable(kCFAllocatorDefault
, count
, &kCFTypeArrayCallBacks
);
2741 CFRange all_certs
= { 0, count
};
2742 CFArrayApplyFunction(serializedCertificates
, all_certs
, deserializeCert
, result
);
2747 static void serializeCertificate(const void *value
, void *context
) {
2748 SecCertificateRef cert
= (SecCertificateRef
)value
;
2749 if (cert
&& SecCertificateGetTypeID() == CFGetTypeID(cert
)) {
2750 CFDataRef certData
= SecCertificateCopyData(cert
);
2752 CFArrayAppendValue((CFMutableArrayRef
)context
, certData
);
2753 CFRelease(certData
);
2758 static CF_RETURNS_RETAINED CFArrayRef
SecCertificateArraySerialize(CFArrayRef certificates
) {
2759 CFMutableArrayRef result
= NULL
;
2760 require_quiet(isArray(certificates
), errOut
);
2761 CFIndex count
= CFArrayGetCount(certificates
);
2762 result
= CFArrayCreateMutable(NULL
, count
, &kCFTypeArrayCallBacks
);
2763 CFRange all_certificates
= { 0, count
};
2764 CFArrayApplyFunction(certificates
, all_certificates
, serializeCertificate
, result
);
2769 static CFPropertyListRef
SecTrustCopyPlist(SecTrustRef trust
) {
2770 __block CFMutableDictionaryRef output
= NULL
;
2771 output
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
,
2772 &kCFTypeDictionaryValueCallBacks
);
2774 dispatch_sync(trust
->_trustQueue
, ^{
2775 if (trust
->_certificates
) {
2776 CFArrayRef serializedCerts
= SecCertificateArraySerialize(trust
->_certificates
);
2777 if (serializedCerts
) {
2778 CFDictionaryAddValue(output
, CFSTR(kSecTrustCertificatesKey
), serializedCerts
);
2779 CFRelease(serializedCerts
);
2782 if (trust
->_anchors
) {
2783 CFArrayRef serializedAnchors
= SecCertificateArraySerialize(trust
->_anchors
);
2784 if (serializedAnchors
) {
2785 CFDictionaryAddValue(output
, CFSTR(kSecTrustAnchorsKey
), serializedAnchors
);
2786 CFRelease(serializedAnchors
);
2789 if (trust
->_policies
) {
2790 CFArrayRef serializedPolicies
= SecPolicyArrayCreateSerialized(trust
->_policies
);
2791 if (serializedPolicies
) {
2792 CFDictionaryAddValue(output
, CFSTR(kSecTrustPoliciesKey
), serializedPolicies
);
2793 CFRelease(serializedPolicies
);
2796 if (trust
->_responses
) {
2797 CFDictionaryAddValue(output
, CFSTR(kSecTrustResponsesKey
), trust
->_responses
);
2800 CFDictionaryAddValue(output
, CFSTR(kSecTrustSCTsKey
), trust
->_SCTs
);
2802 if (trust
->_trustedLogs
) {
2803 CFDictionaryAddValue(output
, CFSTR(kSecTrustTrustedLogsKey
), trust
->_trustedLogs
);
2805 if (trust
->_verifyDate
) {
2806 CFDictionaryAddValue(output
, CFSTR(kSecTrustVerifyDateKey
), trust
->_verifyDate
);
2808 if (trust
->_chain
) {
2809 CFArrayRef serializedCerts
= SecCertificateArraySerialize(trust
->_chain
);
2810 if (serializedCerts
) {
2811 CFDictionaryAddValue(output
, CFSTR(kSecTrustChainKey
), serializedCerts
);
2812 CFRelease(serializedCerts
);
2815 if (trust
->_details
) {
2816 CFDictionaryAddValue(output
, CFSTR(kSecTrustDetailsKey
), trust
->_details
);
2819 CFDictionaryAddValue(output
, CFSTR(kSecTrustInfoKey
), trust
->_info
);
2821 if (trust
->_exceptions
) {
2822 CFDictionaryAddValue(output
, CFSTR(kSecTrustExceptionsKey
), trust
->_exceptions
);
2824 CFNumberRef trustResult
= CFNumberCreate(NULL
, kCFNumberSInt32Type
, &trust
->_trustResult
);
2826 CFDictionaryAddValue(output
, CFSTR(kSecTrustResultKey
), trustResult
);
2828 CFReleaseNull(trustResult
);
2829 if (trust
->_anchorsOnly
) {
2830 CFDictionaryAddValue(output
, CFSTR(kSecTrustAnchorsOnlyKey
), kCFBooleanTrue
);
2832 CFDictionaryAddValue(output
, CFSTR(kSecTrustAnchorsOnlyKey
), kCFBooleanFalse
);
2834 if (trust
->_keychainsAllowed
) {
2835 CFDictionaryAddValue(output
, CFSTR(kSecTrustKeychainsAllowedKey
), kCFBooleanTrue
);
2837 CFDictionaryAddValue(output
, CFSTR(kSecTrustKeychainsAllowedKey
), kCFBooleanFalse
);
2844 CFDataRef
SecTrustSerialize(SecTrustRef trust
, CFErrorRef
*error
) {
2845 CFPropertyListRef plist
= NULL
;
2846 CFDataRef derTrust
= NULL
;
2847 require_action_quiet(trust
, out
,
2848 SecError(errSecParam
, error
, CFSTR("null trust input")));
2849 require_action_quiet(plist
= SecTrustCopyPlist(trust
), out
,
2850 SecError(errSecDecode
, error
, CFSTR("unable to create trust plist")));
2851 require_quiet(derTrust
= CFPropertyListCreateDERData(NULL
, plist
, error
), out
);
2854 CFReleaseNull(plist
);
2858 static OSStatus
SecTrustCreateFromPlist(CFPropertyListRef plist
, SecTrustRef CF_RETURNS_RETAINED
*trust
) {
2859 OSStatus status
= errSecParam
;
2860 SecTrustRef output
= NULL
;
2861 CFTypeRef serializedCertificates
= NULL
, serializedPolicies
= NULL
, serializedAnchors
= NULL
;
2862 CFNumberRef trustResultNum
= NULL
;
2863 CFArrayRef certificates
= NULL
, policies
= NULL
, anchors
= NULL
, responses
= NULL
,
2864 SCTs
= NULL
, trustedLogs
= NULL
, details
= NULL
, exceptions
= NULL
, chain
= NULL
;
2865 CFDateRef verifyDate
= NULL
;
2866 CFDictionaryRef info
= NULL
;
2868 require_quiet(CFDictionaryGetTypeID() == CFGetTypeID(plist
), out
);
2869 require_quiet(serializedCertificates
= CFDictionaryGetValue(plist
, CFSTR(kSecTrustCertificatesKey
)), out
);
2870 require_quiet(certificates
= SecCertificateArrayDeserialize(serializedCertificates
), out
);
2871 require_quiet(serializedPolicies
= CFDictionaryGetValue(plist
, CFSTR(kSecTrustPoliciesKey
)), out
);
2872 require_quiet(policies
= SecPolicyArrayCreateDeserialized(serializedPolicies
), out
);
2873 require_noerr_quiet(status
= SecTrustCreateWithCertificates(certificates
, policies
, &output
), out
);
2875 serializedAnchors
= CFDictionaryGetValue(plist
, CFSTR(kSecTrustAnchorsKey
));
2876 if (isArray(serializedAnchors
)) {
2877 anchors
= SecCertificateArrayDeserialize(serializedAnchors
);
2878 output
->_anchors
= anchors
;
2880 responses
= CFDictionaryGetValue(plist
, CFSTR(kSecTrustResponsesKey
));
2881 if (isArray(responses
)) {
2882 output
->_responses
= CFRetainSafe(responses
);
2884 SCTs
= CFDictionaryGetValue(plist
, CFSTR(kSecTrustSCTsKey
));
2885 if (isArray(SCTs
)) {
2886 output
->_SCTs
= CFRetainSafe(SCTs
);
2888 trustedLogs
= CFDictionaryGetValue(plist
, CFSTR(kSecTrustTrustedLogsKey
));
2889 if (isArray(trustedLogs
)) {
2890 output
->_trustedLogs
= CFRetainSafe(trustedLogs
);
2892 verifyDate
= CFDictionaryGetValue(plist
, CFSTR(kSecTrustVerifyDateKey
));
2893 if (isDate(verifyDate
)) {
2894 output
->_verifyDate
= CFRetainSafe(verifyDate
);
2896 chain
= CFDictionaryGetValue(plist
, CFSTR(kSecTrustChainKey
));
2897 if (isArray(chain
)) {
2898 output
->_chain
= SecCertificateArrayDeserialize(chain
);
2900 details
= CFDictionaryGetValue(plist
, CFSTR(kSecTrustDetailsKey
));
2901 if (isArray(details
)) {
2902 output
->_details
= CFRetainSafe(details
);
2904 info
= CFDictionaryGetValue(plist
, CFSTR(kSecTrustInfoKey
));
2905 if (isDictionary(info
)) {
2906 output
->_info
= CFRetainSafe(info
);
2908 exceptions
= CFDictionaryGetValue(plist
, CFSTR(kSecTrustExceptionsKey
));
2909 if (isArray(exceptions
)) {
2910 output
->_exceptions
= CFRetainSafe(exceptions
);
2912 int32_t trustResult
= -1;
2913 trustResultNum
= CFDictionaryGetValue(plist
, CFSTR(kSecTrustResultKey
));
2914 if (isNumber(trustResultNum
) && CFNumberGetValue(trustResultNum
, kCFNumberSInt32Type
, &trustResult
) &&
2915 (trustResult
>= 0)) {
2916 output
->_trustResult
= trustResult
;
2918 status
= errSecParam
;
2920 if (CFDictionaryGetValue(plist
, CFSTR(kSecTrustAnchorsOnlyKey
)) == kCFBooleanTrue
) {
2921 output
->_anchorsOnly
= true;
2922 } /* false is set by default */
2923 if (CFDictionaryGetValue(plist
, CFSTR(kSecTrustKeychainsAllowedKey
)) == kCFBooleanFalse
) {
2924 output
->_keychainsAllowed
= false;
2925 } /* true is set by default */
2928 if (errSecSuccess
== status
&& trust
) {
2931 CFReleaseNull(policies
);
2932 CFReleaseNull(certificates
);
2936 SecTrustRef
SecTrustDeserialize(CFDataRef serializedTrust
, CFErrorRef
*error
) {
2937 SecTrustRef trust
= NULL
;
2938 CFPropertyListRef plist
= NULL
;
2939 OSStatus status
= errSecSuccess
;
2940 require_action_quiet(serializedTrust
, out
,
2941 SecError(errSecParam
, error
, CFSTR("null serialized trust input")));
2942 require_quiet(plist
= CFPropertyListCreateWithDERData(NULL
, serializedTrust
,
2943 kCFPropertyListImmutable
, NULL
, error
), out
);
2944 require_noerr_action_quiet(status
= SecTrustCreateFromPlist(plist
, &trust
), out
,
2945 SecError(status
, error
, CFSTR("unable to create trust ref")));
2948 CFReleaseNull(plist
);
2952 #if TARGET_OS_IPHONE
2953 static uint64_t to_uint_error_request(enum SecXPCOperation op
, CFErrorRef
*error
) {
2954 __block
uint64_t result
= 0;
2956 securityd_send_sync_and_do(op
, error
, NULL
, ^bool(xpc_object_t response
, CFErrorRef
*localError
) {
2957 uint64_t temp_result
= xpc_dictionary_get_uint64(response
, kSecXPCKeyResult
);
2958 /* plists do not support unsigned integers. */
2959 if (temp_result
<= INT64_MAX
) {
2960 result
= temp_result
;
2962 secerror("Invalid exceptions epoch.");
2964 *error
= CFErrorCreate(NULL
, kCFErrorDomainPOSIX
, ERANGE
, NULL
);
2967 if (error
&& localError
&& *localError
) {
2968 *error
= *localError
;
2976 uint64_t SecTrustGetExceptionResetCount(CFErrorRef
*error
) {
2977 os_activity_t activity
= os_activity_create("SecTrustExceptionGetResetCount", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_DEFAULT
);
2978 os_activity_scope(activity
);
2979 uint64_t exceptionResetCount
= TRUSTD_XPC(sec_trust_get_exception_reset_count
, to_uint_error_request
, error
);
2980 os_release(activity
);
2981 if (error
&& *error
) {
2982 secerror("Failed to get the exceptions epoch.");
2984 secinfo("trust", "The exceptions epoch is %lld.", exceptionResetCount
);
2986 return exceptionResetCount
;
2989 OSStatus
SecTrustIncrementExceptionResetCount(CFErrorRef
*error
) {
2990 OSStatus status
= errSecInternal
;
2992 os_activity_t activity
= os_activity_create("SecTrustIncrementExceptionResetCount", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_DEFAULT
);
2993 os_activity_scope(activity
);
2994 bool success
= TRUSTD_XPC(sec_trust_increment_exception_reset_count
, to_bool_error_request
, error
);
2995 os_release(activity
);
2996 if ((error
&& *error
) || !success
) {
2997 secerror("Failed to increment the exceptions epoch.");
3000 status
= errSecSuccess
;