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
);
1838 /* On OS X we need SecTrustCopyPublicKey to give us a CDSA-based SecKeyRef,
1839 so we will refer to this one internally as SecTrustCopyPublicKey_ios,
1840 and call it from SecTrustCopyPublicKey.
1842 SecKeyRef
SecTrustCopyPublicKey_ios(SecTrustRef trust
)
1844 SecKeyRef
SecTrustCopyPublicKey(SecTrustRef trust
)
1850 __block SecKeyRef publicKey
= NULL
;
1851 dispatch_sync(trust
->_trustQueue
, ^{
1852 if (trust
->_publicKey
) {
1853 publicKey
= CFRetainSafe(trust
->_publicKey
);
1856 SecCertificateRef leaf
= (SecCertificateRef
)CFArrayGetValueAtIndex(trust
->_certificates
, 0);
1857 trust
->_publicKey
= SecCertificateCopyKey(leaf
);
1858 if (trust
->_publicKey
) {
1859 publicKey
= CFRetainSafe(trust
->_publicKey
);
1862 /* If we couldn't get a public key from the leaf cert alone. */
1864 SecTrustEvaluateIfNecessary(trust
);
1865 dispatch_sync(trust
->_trustQueue
, ^{
1866 if (trust
->_chain
) {
1867 SecCertificateRef cert
= (SecCertificateRef
)CFArrayGetValueAtIndex(trust
->_chain
, 0);
1868 trust
->_publicKey
= SecCertificateCopyKey(cert
);
1869 publicKey
= CFRetainSafe(trust
->_publicKey
);
1876 CFIndex
SecTrustGetCertificateCount(SecTrustRef trust
) {
1880 SecTrustEvaluateIfNecessary(trust
);
1881 __block CFIndex certCount
= 1;
1882 dispatch_sync(trust
->_trustQueue
, ^{
1883 if (trust
->_chain
) {
1884 certCount
= CFArrayGetCount(trust
->_chain
);
1890 SecCertificateRef
SecTrustGetCertificateAtIndex(SecTrustRef trust
,
1895 __block SecCertificateRef cert
= NULL
;
1897 dispatch_sync(trust
->_trustQueue
, ^{
1898 cert
= (SecCertificateRef
)CFArrayGetValueAtIndex(trust
->_certificates
, 0);
1902 SecTrustEvaluateIfNecessary(trust
);
1903 dispatch_sync(trust
->_trustQueue
, ^{
1904 if (trust
->_chain
) {
1905 cert
= (SecCertificateRef
)CFArrayGetValueAtIndex(trust
->_chain
, ix
);
1911 CFDictionaryRef
SecTrustCopyInfo(SecTrustRef trust
) {
1915 SecTrustEvaluateIfNecessary(trust
);
1916 __block CFDictionaryRef info
= NULL
;
1917 dispatch_sync(trust
->_trustQueue
, ^{
1918 info
= CFRetainSafe(trust
->_info
);
1923 CFArrayRef
SecTrustGetTrustExceptionsArray(SecTrustRef trust
) {
1927 __block CFArrayRef exceptions
= NULL
;
1928 dispatch_sync(trust
->_trustQueue
, ^{
1929 exceptions
= trust
->_exceptions
;
1934 CFDataRef
SecTrustCopyExceptions(SecTrustRef trust
) {
1935 /* Stash the old exceptions and run an evaluation with no exceptions filtered. */
1936 __block CFArrayRef oldExceptions
= NULL
;
1937 dispatch_sync(trust
->_trustQueue
, ^{
1938 if (trust
->_exceptions
) {
1939 oldExceptions
= trust
->_exceptions
;
1940 trust
->_exceptions
= NULL
;
1943 SecTrustSetNeedsEvaluation(trust
);
1945 /* Create the new exceptions based on an unfiltered eval. */
1946 __block CFArrayRef details
= NULL
;
1947 SecTrustEvaluateIfNecessary(trust
);
1948 dispatch_sync(trust
->_trustQueue
, ^{
1949 details
= CFRetainSafe(trust
->_details
);
1951 CFIndex pathLength
= details
? CFArrayGetCount(details
) : 0;
1952 CFMutableArrayRef exceptions
= CFArrayCreateMutable(kCFAllocatorDefault
, pathLength
, &kCFTypeArrayCallBacks
);
1953 #if TARGET_OS_IPHONE
1954 /* Fetch the current exceptions epoch and tag each exception with it. */
1955 CFErrorRef exceptionResetCountError
= NULL
;
1956 uint64_t exceptionResetCount
= SecTrustGetExceptionResetCount(&exceptionResetCountError
);
1957 secinfo("trust", "The current exceptions epoch is %llu. (%{public}s)", exceptionResetCount
, exceptionResetCountError
? "Error" : "OK");
1958 CFNumberRef exceptionResetCountRef
= CFNumberCreate(NULL
, kCFNumberSInt64Type
, &exceptionResetCount
);
1961 for (ix
= 0; ix
< pathLength
; ++ix
) {
1962 CFDictionaryRef detail
= (CFDictionaryRef
)CFArrayGetValueAtIndex(details
, ix
);
1963 CFIndex detailCount
= CFDictionaryGetCount(detail
);
1964 CFMutableDictionaryRef exception
;
1965 if (ix
== 0 || detailCount
> 0) {
1966 exception
= CFDictionaryCreateMutableCopy(kCFAllocatorDefault
, detailCount
+ 1, detail
);
1967 SecCertificateRef certificate
= SecTrustGetCertificateAtIndex(trust
, ix
);
1968 CFDataRef digest
= SecCertificateGetSHA1Digest(certificate
);
1969 CFDictionaryAddValue(exception
, kSecCertificateDetailSHA1Digest
, digest
);
1970 #if TARGET_OS_IPHONE
1971 if (exceptionResetCount
&& !exceptionResetCountError
&& exceptionResetCountRef
) {
1972 CFDictionaryAddValue(exception
, kSecCertificateExceptionResetCount
, exceptionResetCountRef
);
1976 /* Add empty exception dictionaries for non leaf certs which have no exceptions to save space. */
1977 exception
= (CFMutableDictionaryRef
)CFDictionaryCreate(kCFAllocatorDefault
, NULL
, NULL
, 0,
1978 &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
1980 CFArrayAppendValue(exceptions
, exception
);
1981 CFReleaseNull(exception
);
1984 /* Restore the stashed exceptions. */
1985 if (oldExceptions
) {
1986 dispatch_sync(trust
->_trustQueue
, ^{
1987 trust
->_exceptions
= oldExceptions
;
1989 SecTrustSetNeedsEvaluation(trust
);
1992 /* Remove any trailing empty dictionaries to save even more space (we skip the leaf
1993 since it will never be empty). */
1994 for (ix
= pathLength
; ix
-- > 1;) {
1995 CFDictionaryRef exception
= (CFDictionaryRef
)CFArrayGetValueAtIndex(exceptions
, ix
);
1996 if (CFDictionaryGetCount(exception
) == 0) {
1997 CFArrayRemoveValueAtIndex(exceptions
, ix
);
2003 CFDataRef encodedExceptions
= CFPropertyListCreateData(kCFAllocatorDefault
,
2004 exceptions
, kCFPropertyListBinaryFormat_v1_0
, 0, NULL
);
2005 CFRelease(exceptions
);
2006 CFReleaseSafe(details
);
2007 #if TARGET_OS_IPHONE
2008 CFReleaseSafe(exceptionResetCountRef
);
2010 return encodedExceptions
;
2013 #if TARGET_OS_IPHONE
2014 static bool SecTrustExceptionsValidForThisEpoch(CFArrayRef exceptions
) {
2018 CFDictionaryRef exception
= (CFDictionaryRef
)CFArrayGetValueAtIndex(exceptions
, 0);
2020 CFErrorRef currentExceptionResetCountError
= NULL
;
2021 uint64_t currentExceptionResetCount
= SecTrustGetExceptionResetCount(¤tExceptionResetCountError
);
2022 secinfo("trust", "The current exceptions epoch is %llu. (%{public}s)", currentExceptionResetCount
, currentExceptionResetCountError
? "Error" : "OK");
2023 /* Fail closed: if we were unable to get the current exceptions epoch consider the exceptions invalid. */
2024 if (currentExceptionResetCountError
) {
2025 secerror("Failed to get the current exceptions epoch.");
2028 /* If this is the first epoch ever there is no point in checking whether any exceptions belong in the past. */
2029 if (currentExceptionResetCount
== 0) {
2033 CFNumberRef resetCountRef
= CFDictionaryGetValue(exception
, kSecCertificateExceptionResetCount
);
2034 if (!resetCountRef
) {
2035 secerror("Failed to get the exception's epoch.");
2039 uint64_t exceptionResetCount
;
2040 if (!CFNumberGetValue(resetCountRef
, kCFNumberSInt64Type
, &exceptionResetCount
)) {
2041 secerror("Failed to parse the current exceptions epoch as a uint64.");
2045 if (exceptionResetCount
!= currentExceptionResetCount
) {
2046 secerror("The current exception's epoch (%llu) is not the current epoch. (%llu)", exceptionResetCount
, currentExceptionResetCount
);
2050 secinfo("trust", "Exceptions are valid for the current exceptions epoch. (%llu)", currentExceptionResetCount
);
2055 bool SecTrustSetExceptions(SecTrustRef trust
, CFDataRef encodedExceptions
) {
2059 CFArrayRef exceptions
= NULL
;
2061 if (NULL
!= encodedExceptions
) {
2062 exceptions
= (CFArrayRef
)CFPropertyListCreateWithData(kCFAllocatorDefault
,
2063 encodedExceptions
, kCFPropertyListImmutable
, NULL
, NULL
);
2066 if (exceptions
&& CFGetTypeID(exceptions
) != CFArrayGetTypeID()) {
2067 CFRelease(exceptions
);
2071 dispatch_sync(trust
->_trustQueue
, ^{
2072 CFReleaseSafe(trust
->_exceptions
);
2073 trust
->_exceptions
= exceptions
;
2076 /* We changed the exceptions -- so we need to re-evaluate */
2077 SecTrustSetNeedsEvaluation(trust
);
2079 /* If there is a valid exception entry for our current leaf we're golden. */
2080 #if TARGET_OS_IPHONE
2081 if (SecTrustGetExceptionForCertificateAtIndex(trust
, 0) && SecTrustExceptionsValidForThisEpoch(exceptions
)) {
2083 if (SecTrustGetExceptionForCertificateAtIndex(trust
, 0)) {
2088 /* The passed in exceptions didn't match our current leaf, so we discard it. */
2089 dispatch_sync(trust
->_trustQueue
, ^{
2090 CFReleaseNull(trust
->_exceptions
);
2097 SecTrustSetOptions(SecTrustRef trustRef
, SecTrustOptionFlags options
)
2099 /* bridge to support API functionality for legacy callers */
2100 OSStatus status
= errSecSuccess
;
2102 /* No options or none that trigger the exceptions behavior */
2104 0 == (options
& (kSecTrustOptionAllowExpired
|
2105 kSecTrustOptionImplicitAnchors
|
2106 kSecTrustOptionAllowExpiredRoot
))) {
2110 __block CFMutableArrayRef exceptions
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
2111 if (!exceptions
) { return errSecAllocate
; }
2113 /* Add the new options to the old_exceptions when those exceptions are tied to a particular cert.
2114 * If not tied to a particular cert, we reset the exceptions based on the input options. */
2115 CFArrayRef old_exceptions
= SecTrustGetTrustExceptionsArray(trustRef
);
2116 if (old_exceptions
&& SecTrustGetExceptionForCertificateAtIndex(trustRef
, 0)) {
2117 CFIndex ix
, count
= CFArrayGetCount(old_exceptions
);
2118 for (ix
= 0; ix
< count
; ix
++) {
2119 CFMutableDictionaryRef exception_dictionary
= CFDictionaryCreateMutableCopy(NULL
, 0, (CFDictionaryRef
)CFArrayGetValueAtIndex(old_exceptions
, ix
));
2120 if (!exception_dictionary
) { status
= errSecAllocate
; goto out
; }
2121 if ((options
& kSecTrustOptionAllowExpired
) != 0) {
2122 CFDictionaryAddValue(exception_dictionary
, kSecPolicyCheckTemporalValidity
, kCFBooleanFalse
);
2124 if ((options
& (kSecTrustOptionImplicitAnchors
| kSecTrustOptionAllowExpiredRoot
)) != 0) {
2125 /* Check that root is self-signed. */
2126 Boolean isSelfSigned
= false;
2127 SecCertificateRef cert
= SecTrustGetCertificateAtIndex(trustRef
, ix
);
2128 if (cert
&& (errSecSuccess
== SecCertificateIsSelfSigned(cert
, &isSelfSigned
)) &&
2130 if ((options
& kSecTrustOptionImplicitAnchors
) != 0) {
2131 CFDictionaryAddValue(exception_dictionary
, kSecPolicyCheckAnchorTrusted
, kCFBooleanFalse
);
2132 } else if ((options
& kSecTrustOptionAllowExpiredRoot
) != 0) {
2133 CFDictionaryAddValue(exception_dictionary
, kSecPolicyCheckTemporalValidity
, kCFBooleanFalse
);
2137 CFArrayAppendValue(exceptions
, exception_dictionary
);
2138 CFReleaseNull(exception_dictionary
);
2141 /* Create a new exceptions array. Warning, this takes advantage of implementation details of the exceptions mechanism. */
2142 CFMutableDictionaryRef exception_dictionary
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
,
2143 &kCFTypeDictionaryValueCallBacks
);
2144 if (!exception_dictionary
) { status
= errSecAllocate
; goto out
; }
2145 if ((options
& kSecTrustOptionAllowExpired
) != 0) {
2146 CFDictionaryAddValue(exception_dictionary
, kSecPolicyCheckTemporalValidity
, kCFBooleanFalse
);
2148 if ((options
& kSecTrustOptionAllowExpiredRoot
) != 0) {
2149 CFDictionaryAddValue(exception_dictionary
, kSecPolicyCheckValidRoot
, kCFBooleanFalse
);
2151 if ((options
& kSecTrustOptionImplicitAnchors
) != 0) {
2152 CFDictionaryAddValue(exception_dictionary
, kSecPolicyCheckAnchorTrusted
, kCFBooleanFalse
);
2154 CFArrayAppendValue(exceptions
, exception_dictionary
);
2155 CFReleaseNull(exception_dictionary
);
2158 /* Set exceptions */
2159 dispatch_sync(trustRef
->_trustQueue
, ^{
2160 CFReleaseSafe(trustRef
->_exceptions
);
2161 trustRef
->_exceptions
= CFRetainSafe(exceptions
);
2163 /* We changed the exceptions -- so we need to re-evaluate */
2164 SecTrustSetNeedsEvaluation(trustRef
);
2167 CFReleaseNull(exceptions
);
2172 CFArrayRef
SecTrustCopySummaryPropertiesAtIndex(SecTrustRef trust
, CFIndex ix
) {
2173 CFMutableArrayRef summary
;
2174 SecCertificateRef certificate
= SecTrustGetCertificateAtIndex(trust
, ix
);
2175 summary
= SecCertificateCopySummaryProperties(certificate
,
2176 SecTrustGetVerifyTime(trust
));
2177 /* FIXME Add more details in the failure case. */
2182 CFArrayRef
SecTrustCopyDetailedPropertiesAtIndex(SecTrustRef trust
, CFIndex ix
) {
2184 SecCertificateRef certificate
= SecTrustGetCertificateAtIndex(trust
, ix
);
2185 summary
= SecCertificateCopyProperties(certificate
);
2190 struct TrustFailures
{
2192 bool unknownCritExtn
;
2193 bool untrustedAnchor
;
2194 bool missingIntermediate
;
2195 bool hostnameMismatch
;
2203 static void applyDetailProperty(const void *_key
, const void *_value
,
2205 CFStringRef key
= (CFStringRef
)_key
;
2206 struct TrustFailures
*tf
= (struct TrustFailures
*)context
;
2207 if (CFGetTypeID(_value
) != CFBooleanGetTypeID()) {
2208 /* Value isn't a CFBooleanRef, oh no! */
2211 CFBooleanRef value
= (CFBooleanRef
)_value
;
2212 if (CFBooleanGetValue(value
)) {
2213 /* Not an actual failure so we don't report it. */
2217 /* @@@ FIXME: Report a different return value when something is in the
2218 details but masked out by an exception and use that below for display
2220 if (CFEqual(key
, kSecPolicyCheckIdLinkage
)) {
2221 tf
->badLinkage
= true;
2222 } else if (CFEqual(key
, kSecPolicyCheckCriticalExtensions
)) {
2223 tf
->unknownCritExtn
= true;
2224 } else if (CFEqual(key
, kSecPolicyCheckAnchorTrusted
)
2225 || CFEqual(key
, kSecPolicyCheckAnchorSHA1
)
2226 || CFEqual(key
, kSecPolicyCheckAnchorSHA256
)
2227 || CFEqual(key
, kSecPolicyCheckAnchorApple
)) {
2228 tf
->untrustedAnchor
= true;
2229 } else if (CFEqual(key
, kSecPolicyCheckMissingIntermediate
)) {
2230 tf
->missingIntermediate
= true;
2231 } else if (CFEqual(key
, kSecPolicyCheckSSLHostname
)) {
2232 tf
->hostnameMismatch
= true;
2233 } else if (CFEqual(key
, kSecPolicyCheckTemporalValidity
)) {
2234 tf
->invalidCert
= true;
2235 } else if (CFEqual(key
, kSecPolicyCheckWeakKeySize
)
2236 || CFEqualSafe(key
, kSecPolicyCheckKeySize
)
2237 || CFEqualSafe(key
, kSecPolicyCheckSystemTrustedWeakKey
)) {
2239 } else if (CFEqual(key
, kSecPolicyCheckWeakSignature
)
2240 || CFEqualSafe(key
, kSecPolicyCheckSignatureHashAlgorithms
)
2241 || CFEqualSafe(key
, kSecPolicyCheckSystemTrustedWeakHash
)) {
2242 tf
->weakHash
= true;
2243 } else if (CFEqual(key
, kSecPolicyCheckRevocation
)) {
2244 tf
->revocation
= true;
2246 /* Anything else is a policy failure. */
2247 tf
->policyFail
= true;
2251 static void appendError(CFMutableArrayRef properties
, CFStringRef error
, bool localized
) {
2252 CFStringRef localizedError
= NULL
;
2255 } else if (localized
) {
2256 //%%% "SecCertificate" should be changed to "Certificate": rdar://37517120
2257 localizedError
= SecFrameworkCopyLocalizedString(error
, CFSTR("SecCertificate"));
2259 localizedError
= (CFStringRef
) CFRetainSafe(error
);
2261 appendProperty(properties
, kSecPropertyTypeError
, NULL
, NULL
,
2262 localizedError
, localized
);
2263 CFReleaseNull(localizedError
);
2267 /* OS X properties array has a different structure and is implemented SecTrust.cpp. */
2268 CFArrayRef
SecTrustCopyProperties_ios(SecTrustRef trust
)
2270 CFArrayRef
SecTrustCopyProperties(SecTrustRef trust
)
2276 SecTrustEvaluateIfNecessary(trust
);
2277 bool localized
= true;
2278 __block CFArrayRef details
= NULL
;
2279 dispatch_sync(trust
->_trustQueue
, ^{
2280 details
= CFRetainSafe(trust
->_details
);
2286 struct TrustFailures tf
= {};
2288 CFIndex ix
, count
= CFArrayGetCount(details
);
2289 for (ix
= 0; ix
< count
; ++ix
) {
2290 CFDictionaryRef detail
= (CFDictionaryRef
)
2291 CFArrayGetValueAtIndex(details
, ix
);
2292 /* We now have a detail dictionary for certificate at index ix, with
2293 a key value pair for each failed policy check. Let's convert it
2294 from Ro-Man form into something a Hu-Man can understand. */
2295 CFDictionaryApplyFunction(detail
, applyDetailProperty
, &tf
);
2298 CFMutableArrayRef properties
= CFArrayCreateMutable(kCFAllocatorDefault
, 0,
2299 &kCFTypeArrayCallBacks
);
2300 /* The badLinkage and unknownCritExtn failures are short circuited, since
2301 you can't recover from those errors. */
2302 if (tf
.badLinkage
) {
2303 appendError(properties
, CFSTR("Invalid certificate chain linkage."), localized
);
2304 } else if (tf
.unknownCritExtn
) {
2305 appendError(properties
, CFSTR("One or more unsupported critical extensions found."), localized
);
2307 if (tf
.untrustedAnchor
) {
2308 appendError(properties
, CFSTR("Root certificate is not trusted."), localized
);
2310 if (tf
.missingIntermediate
) {
2311 appendError(properties
, CFSTR("Unable to build chain to root certificate."), localized
);
2313 if (tf
.hostnameMismatch
) {
2314 appendError(properties
, CFSTR("Hostname mismatch."), localized
);
2316 if (tf
.policyFail
) {
2317 appendError(properties
, CFSTR("Policy requirements not met."), localized
);
2319 if (tf
.invalidCert
) {
2320 appendError(properties
, CFSTR("One or more certificates have expired or are not valid yet."), localized
);
2323 appendError(properties
, CFSTR("One or more certificates is using a weak key size."), localized
);
2326 appendError(properties
, CFSTR("One or more certificates is using a weak signature algorithm."), localized
);
2328 if (tf
.revocation
) {
2329 appendError(properties
, CFSTR("One or more certificates have been revoked."), localized
);
2333 if (CFArrayGetCount(properties
) == 0) {
2334 /* The certificate chain is trusted, return an empty plist */
2335 CFReleaseNull(properties
);
2338 CFReleaseNull(details
);
2343 static void _AppendStatusCode(CFMutableArrayRef array
, OSStatus statusCode
) {
2347 SInt32 num
= statusCode
;
2348 CFNumberRef numRef
= CFNumberCreate(NULL
, kCFNumberSInt32Type
, &num
);
2352 CFArrayAppendValue(array
, numRef
);
2357 static CFArrayRef
_SecTrustCopyDetails(SecTrustRef trust
) {
2361 __block CFArrayRef details
= NULL
;
2362 dispatch_sync(trust
->_trustQueue
, ^{
2363 details
= CFRetainSafe(trust
->_details
);
2366 // Include status codes in the per-certificate details (rdar://27930542)
2367 CFMutableArrayRef newDetails
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
2369 CFReleaseSafe(details
);
2372 CFIndex index
, chainLen
= (details
) ? CFArrayGetCount(details
) : 0;
2373 for (index
= 0; index
< chainLen
; index
++) {
2374 CFDictionaryRef detailDict
= CFArrayGetValueAtIndex(details
, index
);
2375 CFMutableDictionaryRef newDict
= CFDictionaryCreateMutableCopy(NULL
, 0, detailDict
);
2376 CFMutableArrayRef statusCodes
= CFArrayCreateMutable(kCFAllocatorDefault
,
2377 0, &kCFTypeArrayCallBacks
);
2379 CFIndex i
, numCodes
= 0;
2380 SInt32
*codes
= SecTrustCopyStatusCodes(trust
, index
, &numCodes
);
2382 for (i
= 0; i
< numCodes
; i
++) {
2383 OSStatus scode
= (OSStatus
)codes
[i
];
2384 _AppendStatusCode(statusCodes
, scode
);
2388 if (CFArrayGetCount(statusCodes
) > 0) {
2389 CFDictionarySetValue(newDict
, kSecCertificateDetailStatusCodes
, statusCodes
);
2391 CFRelease(statusCodes
);
2394 CFArrayAppendValue(newDetails
, newDict
);
2398 CFReleaseSafe(details
);
2405 CFDictionaryRef
SecTrustCopyResult(SecTrustRef trust
) {
2406 // Builds and returns a dictionary of evaluation results.
2410 __block CFMutableDictionaryRef results
= CFDictionaryCreateMutable(NULL
, 0,
2411 &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
2413 SecTrustEvaluateIfNecessary(trust
);
2414 __block CFArrayRef details
= _SecTrustCopyDetails(trust
);
2416 dispatch_sync(trust
->_trustQueue
, ^{
2417 // kSecTrustResultDetails (per-cert results)
2419 CFDictionarySetValue(results
, (const void *)kSecTrustResultDetails
, (const void *)details
);
2423 // kSecTrustResultValue (overall trust result)
2424 CFNumberRef numValue
= CFNumberCreate(NULL
, kCFNumberSInt32Type
, &trust
->_trustResult
);
2426 CFDictionarySetValue(results
, (const void *)kSecTrustResultValue
, (const void *)numValue
);
2427 CFRelease(numValue
);
2429 CFDictionaryRef info
= trust
->_info
;
2430 if (trust
->_trustResult
== kSecTrustResultInvalid
|| !info
) {
2431 return; // we have nothing more to add
2434 // kSecTrustEvaluationDate
2435 CFDateRef evaluationDate
= trust
->_verifyDate
;
2436 if (evaluationDate
) {
2437 CFDictionarySetValue(results
, (const void *)kSecTrustEvaluationDate
, (const void *)evaluationDate
);
2440 // kSecTrustCertificateTransparency
2441 CFBooleanRef ctValue
;
2442 if (CFDictionaryGetValueIfPresent(info
, kSecTrustInfoCertificateTransparencyKey
, (const void **)&ctValue
)) {
2443 CFDictionarySetValue(results
, (const void *)kSecTrustCertificateTransparency
, (const void *)ctValue
);
2446 // kSecTrustExtendedValidation
2447 CFBooleanRef evValue
;
2448 if (CFDictionaryGetValueIfPresent(info
, kSecTrustInfoExtendedValidationKey
, (const void **)&evValue
)) {
2449 CFDictionarySetValue(results
, (const void *)kSecTrustExtendedValidation
, (const void *)evValue
);
2452 // kSecTrustOrganizationName
2453 CFStringRef organizationName
;
2454 if (CFDictionaryGetValueIfPresent(info
, kSecTrustInfoCompanyNameKey
, (const void **)&organizationName
)) {
2455 CFDictionarySetValue(results
, (const void *)kSecTrustOrganizationName
, (const void *)organizationName
);
2458 // kSecTrustRevocationChecked
2459 CFBooleanRef revocationChecked
;
2460 if (CFDictionaryGetValueIfPresent(info
, kSecTrustRevocationChecked
, (const void **)&revocationChecked
)) {
2461 CFDictionarySetValue(results
, (const void *)kSecTrustRevocationChecked
, (const void *)revocationChecked
);
2464 // kSecTrustRevocationReason
2465 CFNumberRef revocationReason
;
2466 if (CFDictionaryGetValueIfPresent(info
, kSecTrustRevocationReason
, (const void **)&revocationReason
)) {
2467 CFDictionarySetValue(results
, (const void *)kSecTrustRevocationReason
, (const void *)revocationReason
);
2470 // kSecTrustRevocationValidUntilDate
2471 CFDateRef validUntilDate
;
2472 if (CFDictionaryGetValueIfPresent(info
, kSecTrustRevocationValidUntilDate
, (const void **)&validUntilDate
)) {
2473 CFDictionarySetValue(results
, (const void *)kSecTrustRevocationValidUntilDate
, (const void *)validUntilDate
);
2480 #define do_if_registered(sdp, ...) if (gTrustd && gTrustd->sdp) { return gTrustd->sdp(__VA_ARGS__); }
2482 static bool xpc_dictionary_entry_is_type(xpc_object_t dictionary
, const char *key
, xpc_type_t type
) {
2483 xpc_object_t value
= xpc_dictionary_get_value(dictionary
, key
);
2484 return value
&& (xpc_get_type(value
) == type
);
2487 static uint64_t do_ota_pki_op (enum SecXPCOperation op
, CFErrorRef
*error
) {
2489 xpc_object_t message
= securityd_create_message(op
, error
);
2491 xpc_object_t response
= securityd_message_with_reply_sync(message
, error
);
2492 if (response
&& xpc_dictionary_entry_is_type(response
, kSecXPCKeyResult
, XPC_TYPE_UINT64
)) {
2493 num
= (int64_t) xpc_dictionary_get_uint64(response
, kSecXPCKeyResult
);
2495 if (response
&& error
&& xpc_dictionary_entry_is_type(response
, kSecXPCKeyError
, XPC_TYPE_DICTIONARY
)) {
2496 xpc_object_t xpc_error
= xpc_dictionary_get_value(response
, kSecXPCKeyError
);
2498 *error
= SecCreateCFErrorWithXPCObject(xpc_error
);
2501 xpc_release_safe(message
);
2502 xpc_release_safe(response
);
2507 // version 0 -> error, so we need to start at version 1 or later.
2508 uint64_t SecTrustGetTrustStoreVersionNumber(CFErrorRef
*error
) {
2509 do_if_registered(sec_ota_pki_trust_store_version
, error
);
2511 os_activity_t activity
= os_activity_create("SecTrustGetTrustStoreVersionNumber", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_DEFAULT
);
2512 os_activity_scope(activity
);
2514 uint64_t num
= do_ota_pki_op(sec_ota_pki_trust_store_version_id
, error
);
2516 os_release(activity
);
2520 uint64_t SecTrustGetAssetVersionNumber(CFErrorRef
*error
) {
2521 do_if_registered(sec_ota_pki_asset_version
, error
);
2523 os_activity_t activity
= os_activity_create("SecTrustGetAssetVersionNumber", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_DEFAULT
);
2524 os_activity_scope(activity
);
2526 uint64_t num
= do_ota_pki_op(sec_ota_pki_asset_version_id
, error
);
2528 os_release(activity
);
2532 uint64_t SecTrustOTAPKIGetUpdatedAsset(CFErrorRef
*error
) {
2533 do_if_registered(sec_ota_pki_get_new_asset
, error
);
2535 os_activity_t activity
= os_activity_create("SecTrustOTAPKIGetUpdatedAsset", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_DEFAULT
);
2536 os_activity_scope(activity
);
2538 uint64_t num
= do_ota_pki_op(kSecXPCOpOTAPKIGetNewAsset
, error
);
2540 os_release(activity
);
2544 uint64_t SecTrustOTASecExperimentGetUpdatedAsset(CFErrorRef
*error
) {
2545 do_if_registered(sec_ota_secexperiment_get_new_asset
, error
);
2547 os_activity_t activity
= os_activity_create("SecTrustOTASecExperimentGetUpdatedAsset", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_DEFAULT
);
2548 os_activity_scope(activity
);
2550 uint64_t num
= do_ota_pki_op(kSecXPCOpOTASecExperimentGetNewAsset
, error
);
2552 os_release(activity
);
2556 CFDictionaryRef
SecTrustOTASecExperimentCopyAsset(CFErrorRef
*error
) {
2557 __block CFDictionaryRef result
= NULL
;
2558 do_if_registered(sec_ota_secexperiment_get_asset
, error
);
2560 securityd_send_sync_and_do(kSecXPCOpOTASecExperimentGetAsset
, error
, ^bool(xpc_object_t message
, CFErrorRef
*blockError
) {
2561 // input: set message parameters here
2563 }, ^bool(xpc_object_t response
, CFErrorRef
*blockError
) {
2564 // output: get array from response object
2565 xpc_object_t xpc_dict
= NULL
;
2567 xpc_dict
= xpc_dictionary_get_value(response
, kSecXPCKeyResult
);
2569 if (xpc_dict
&& (xpc_get_type(xpc_dict
) == XPC_TYPE_DICTIONARY
)) {
2570 result
= (CFDictionaryRef
)_CFXPCCreateCFObjectFromXPCObject(xpc_dict
);
2572 return SecError(errSecInternal
, blockError
, CFSTR("Unable to get SecExperiment Assets"));
2574 return result
!= NULL
;
2579 bool SecTrustReportTLSAnalytics(CFStringRef eventName
, xpc_object_t eventAttributes
, CFErrorRef
*error
) {
2580 if (!eventName
|| !eventAttributes
) {
2583 do_if_registered(sec_networking_analytics_report
, eventName
, eventAttributes
, error
);
2585 os_activity_t activity
= os_activity_create("SecTrustReportTLSAnalytics", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_DEFAULT
);
2586 os_activity_scope(activity
);
2588 __block
bool result
= false;
2589 securityd_send_sync_and_do(kSecXPCOpNetworkingAnalyticsReport
, error
, ^bool(xpc_object_t message
, CFErrorRef
*block_error
) {
2590 if (!SecXPCDictionarySetString(message
, kSecTrustEventNameKey
, eventName
, block_error
)) {
2593 xpc_dictionary_set_value(message
, kSecTrustEventAttributesKey
, eventAttributes
);
2595 }, ^bool(xpc_object_t response
, CFErrorRef
*block_error
) {
2596 result
= SecXPCDictionaryGetBool(response
, kSecXPCKeyResult
, block_error
);
2600 os_release(activity
);
2604 bool SecTrustReportNetworkingAnalytics(const char *eventNameString
, xpc_object_t eventAttributes
) {
2605 if (!eventNameString
|| !eventAttributes
) {
2609 CFStringRef eventName
= CFStringCreateWithCString(kCFAllocatorDefault
, eventNameString
, kCFStringEncodingUTF8
);
2611 secerror("CFStringCreateWithCString failed");
2615 CFErrorRef error
= NULL
;
2616 if (gTrustd
&& gTrustd
->sec_networking_analytics_report
) {
2617 bool result
= gTrustd
->sec_networking_analytics_report(eventName
, eventAttributes
, &error
);
2618 if (error
!= NULL
) {
2619 secerror("SecTrustReportNetworkingAnalytics failed with error: %d", (int)CFErrorGetCode(error
));
2621 CFReleaseNull(eventName
);
2622 CFReleaseNull(error
);
2626 os_activity_t activity
= os_activity_create("SecTrustReportNetworkingAnalytics", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_DEFAULT
);
2627 os_activity_scope(activity
);
2629 __block
bool result
= false;
2630 securityd_send_sync_and_do(kSecXPCOpNetworkingAnalyticsReport
, &error
, ^bool(xpc_object_t message
, CFErrorRef
*block_error
) {
2631 if (!SecXPCDictionarySetString(message
, kSecTrustEventNameKey
, eventName
, block_error
)) {
2634 xpc_dictionary_set_value(message
, kSecTrustEventAttributesKey
, eventAttributes
);
2636 }, ^bool(xpc_object_t response
, CFErrorRef
*block_error
) {
2637 result
= SecXPCDictionaryGetBool(response
, kSecXPCKeyResult
, block_error
);
2641 if (error
!= NULL
) {
2642 secerror("SecTrustReportNetworkingAnalytics failed with error: %d", (int)CFErrorGetCode(error
));
2644 CFReleaseNull(error
);
2645 CFReleaseNull(eventName
);
2647 os_release(activity
);
2653 * This function performs an evaluation of the leaf certificate only, and
2654 * does so in the process that called it. Its primary use is in SecItemCopyMatching
2655 * when kSecMatchPolicy is in the dictionary.
2657 OSStatus
SecTrustEvaluateLeafOnly(SecTrustRef trust
, SecTrustResultType
*result
) {
2661 OSStatus status
= errSecSuccess
;
2662 SecTrustResultType trustResult
= kSecTrustResultInvalid
;
2663 if((status
= SecTrustValidateInput(trust
))) {
2667 struct OpaqueSecLeafPVC pvc
;
2668 SecCertificateRef leaf
= SecTrustGetCertificateAtIndex(trust
, 0);
2669 __block CFArrayRef policies
= NULL
;
2670 dispatch_sync(trust
->_trustQueue
, ^{
2671 policies
= CFRetainSafe(trust
->_policies
);
2673 SecLeafPVCInit(&pvc
, leaf
, policies
, SecTrustGetVerifyTime(trust
));
2675 if(!SecLeafPVCLeafChecks(&pvc
)) {
2676 trustResult
= kSecTrustResultRecoverableTrustFailure
;
2678 trustResult
= kSecTrustResultUnspecified
;
2681 /* Set other result context information */
2682 dispatch_sync(trust
->_trustQueue
, ^{
2683 trust
->_trustResult
= trustResult
;
2684 trust
->_details
= CFRetainSafe(pvc
.details
);
2685 trust
->_info
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0,
2686 &kCFTypeDictionaryKeyCallBacks
,
2687 &kCFTypeDictionaryValueCallBacks
);
2688 CFMutableArrayRef leafCert
= CFArrayCreateMutableCopy(NULL
, 1, trust
->_certificates
);
2689 trust
->_chain
= leafCert
;
2692 SecLeafPVCDelete(&pvc
);
2694 /* log to syslog when there is a trust failure */
2695 if (trustResult
!= kSecTrustResultUnspecified
) {
2696 CFStringRef failureDesc
= SecTrustCopyFailureDescription(trust
);
2697 secerror("%@", failureDesc
);
2698 CFRelease(failureDesc
);
2702 *result
= trustResult
;
2705 CFReleaseSafe(policies
);
2709 static void deserializeCert(const void *value
, void *context
) {
2710 CFDataRef certData
= (CFDataRef
)value
;
2711 if (isData(certData
)) {
2712 SecCertificateRef cert
= SecCertificateCreateWithData(NULL
, certData
);
2714 CFArrayAppendValue((CFMutableArrayRef
)context
, cert
);
2720 static CF_RETURNS_RETAINED CFArrayRef
SecCertificateArrayDeserialize(CFArrayRef serializedCertificates
) {
2721 CFMutableArrayRef result
= NULL
;
2722 require_quiet(isArray(serializedCertificates
), errOut
);
2723 CFIndex count
= CFArrayGetCount(serializedCertificates
);
2724 result
= CFArrayCreateMutable(kCFAllocatorDefault
, count
, &kCFTypeArrayCallBacks
);
2725 CFRange all_certs
= { 0, count
};
2726 CFArrayApplyFunction(serializedCertificates
, all_certs
, deserializeCert
, result
);
2731 static void serializeCertificate(const void *value
, void *context
) {
2732 SecCertificateRef cert
= (SecCertificateRef
)value
;
2733 if (cert
&& SecCertificateGetTypeID() == CFGetTypeID(cert
)) {
2734 CFDataRef certData
= SecCertificateCopyData(cert
);
2736 CFArrayAppendValue((CFMutableArrayRef
)context
, certData
);
2737 CFRelease(certData
);
2742 static CF_RETURNS_RETAINED CFArrayRef
SecCertificateArraySerialize(CFArrayRef certificates
) {
2743 CFMutableArrayRef result
= NULL
;
2744 require_quiet(isArray(certificates
), errOut
);
2745 CFIndex count
= CFArrayGetCount(certificates
);
2746 result
= CFArrayCreateMutable(NULL
, count
, &kCFTypeArrayCallBacks
);
2747 CFRange all_certificates
= { 0, count
};
2748 CFArrayApplyFunction(certificates
, all_certificates
, serializeCertificate
, result
);
2753 static CFPropertyListRef
SecTrustCopyPlist(SecTrustRef trust
) {
2754 __block CFMutableDictionaryRef output
= NULL
;
2755 output
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
,
2756 &kCFTypeDictionaryValueCallBacks
);
2758 dispatch_sync(trust
->_trustQueue
, ^{
2759 if (trust
->_certificates
) {
2760 CFArrayRef serializedCerts
= SecCertificateArraySerialize(trust
->_certificates
);
2761 if (serializedCerts
) {
2762 CFDictionaryAddValue(output
, CFSTR(kSecTrustCertificatesKey
), serializedCerts
);
2763 CFRelease(serializedCerts
);
2766 if (trust
->_anchors
) {
2767 CFArrayRef serializedAnchors
= SecCertificateArraySerialize(trust
->_anchors
);
2768 if (serializedAnchors
) {
2769 CFDictionaryAddValue(output
, CFSTR(kSecTrustAnchorsKey
), serializedAnchors
);
2770 CFRelease(serializedAnchors
);
2773 if (trust
->_policies
) {
2774 CFArrayRef serializedPolicies
= SecPolicyArrayCreateSerialized(trust
->_policies
);
2775 if (serializedPolicies
) {
2776 CFDictionaryAddValue(output
, CFSTR(kSecTrustPoliciesKey
), serializedPolicies
);
2777 CFRelease(serializedPolicies
);
2780 if (trust
->_responses
) {
2781 CFDictionaryAddValue(output
, CFSTR(kSecTrustResponsesKey
), trust
->_responses
);
2784 CFDictionaryAddValue(output
, CFSTR(kSecTrustSCTsKey
), trust
->_SCTs
);
2786 if (trust
->_trustedLogs
) {
2787 CFDictionaryAddValue(output
, CFSTR(kSecTrustTrustedLogsKey
), trust
->_trustedLogs
);
2789 if (trust
->_verifyDate
) {
2790 CFDictionaryAddValue(output
, CFSTR(kSecTrustVerifyDateKey
), trust
->_verifyDate
);
2792 if (trust
->_chain
) {
2793 CFArrayRef serializedCerts
= SecCertificateArraySerialize(trust
->_chain
);
2794 if (serializedCerts
) {
2795 CFDictionaryAddValue(output
, CFSTR(kSecTrustChainKey
), serializedCerts
);
2796 CFRelease(serializedCerts
);
2799 if (trust
->_details
) {
2800 CFDictionaryAddValue(output
, CFSTR(kSecTrustDetailsKey
), trust
->_details
);
2803 CFDictionaryAddValue(output
, CFSTR(kSecTrustInfoKey
), trust
->_info
);
2805 if (trust
->_exceptions
) {
2806 CFDictionaryAddValue(output
, CFSTR(kSecTrustExceptionsKey
), trust
->_exceptions
);
2808 CFNumberRef trustResult
= CFNumberCreate(NULL
, kCFNumberSInt32Type
, &trust
->_trustResult
);
2810 CFDictionaryAddValue(output
, CFSTR(kSecTrustResultKey
), trustResult
);
2812 CFReleaseNull(trustResult
);
2813 if (trust
->_anchorsOnly
) {
2814 CFDictionaryAddValue(output
, CFSTR(kSecTrustAnchorsOnlyKey
), kCFBooleanTrue
);
2816 CFDictionaryAddValue(output
, CFSTR(kSecTrustAnchorsOnlyKey
), kCFBooleanFalse
);
2818 if (trust
->_keychainsAllowed
) {
2819 CFDictionaryAddValue(output
, CFSTR(kSecTrustKeychainsAllowedKey
), kCFBooleanTrue
);
2821 CFDictionaryAddValue(output
, CFSTR(kSecTrustKeychainsAllowedKey
), kCFBooleanFalse
);
2828 CFDataRef
SecTrustSerialize(SecTrustRef trust
, CFErrorRef
*error
) {
2829 CFPropertyListRef plist
= NULL
;
2830 CFDataRef derTrust
= NULL
;
2831 require_action_quiet(trust
, out
,
2832 SecError(errSecParam
, error
, CFSTR("null trust input")));
2833 require_action_quiet(plist
= SecTrustCopyPlist(trust
), out
,
2834 SecError(errSecDecode
, error
, CFSTR("unable to create trust plist")));
2835 require_quiet(derTrust
= CFPropertyListCreateDERData(NULL
, plist
, error
), out
);
2838 CFReleaseNull(plist
);
2842 static OSStatus
SecTrustCreateFromPlist(CFPropertyListRef plist
, SecTrustRef CF_RETURNS_RETAINED
*trust
) {
2843 OSStatus status
= errSecParam
;
2844 SecTrustRef output
= NULL
;
2845 CFTypeRef serializedCertificates
= NULL
, serializedPolicies
= NULL
, serializedAnchors
= NULL
;
2846 CFNumberRef trustResultNum
= NULL
;
2847 CFArrayRef certificates
= NULL
, policies
= NULL
, anchors
= NULL
, responses
= NULL
,
2848 SCTs
= NULL
, trustedLogs
= NULL
, details
= NULL
, exceptions
= NULL
, chain
= NULL
;
2849 CFDateRef verifyDate
= NULL
;
2850 CFDictionaryRef info
= NULL
;
2852 require_quiet(CFDictionaryGetTypeID() == CFGetTypeID(plist
), out
);
2853 require_quiet(serializedCertificates
= CFDictionaryGetValue(plist
, CFSTR(kSecTrustCertificatesKey
)), out
);
2854 require_quiet(certificates
= SecCertificateArrayDeserialize(serializedCertificates
), out
);
2855 require_quiet(serializedPolicies
= CFDictionaryGetValue(plist
, CFSTR(kSecTrustPoliciesKey
)), out
);
2856 require_quiet(policies
= SecPolicyArrayCreateDeserialized(serializedPolicies
), out
);
2857 require_noerr_quiet(status
= SecTrustCreateWithCertificates(certificates
, policies
, &output
), out
);
2859 serializedAnchors
= CFDictionaryGetValue(plist
, CFSTR(kSecTrustAnchorsKey
));
2860 if (isArray(serializedAnchors
)) {
2861 anchors
= SecCertificateArrayDeserialize(serializedAnchors
);
2862 output
->_anchors
= anchors
;
2864 responses
= CFDictionaryGetValue(plist
, CFSTR(kSecTrustResponsesKey
));
2865 if (isArray(responses
)) {
2866 output
->_responses
= CFRetainSafe(responses
);
2868 SCTs
= CFDictionaryGetValue(plist
, CFSTR(kSecTrustSCTsKey
));
2869 if (isArray(SCTs
)) {
2870 output
->_SCTs
= CFRetainSafe(SCTs
);
2872 trustedLogs
= CFDictionaryGetValue(plist
, CFSTR(kSecTrustTrustedLogsKey
));
2873 if (isArray(trustedLogs
)) {
2874 output
->_trustedLogs
= CFRetainSafe(trustedLogs
);
2876 verifyDate
= CFDictionaryGetValue(plist
, CFSTR(kSecTrustVerifyDateKey
));
2877 if (isDate(verifyDate
)) {
2878 output
->_verifyDate
= CFRetainSafe(verifyDate
);
2880 chain
= CFDictionaryGetValue(plist
, CFSTR(kSecTrustChainKey
));
2881 if (isArray(chain
)) {
2882 output
->_chain
= SecCertificateArrayDeserialize(chain
);
2884 details
= CFDictionaryGetValue(plist
, CFSTR(kSecTrustDetailsKey
));
2885 if (isArray(details
)) {
2886 output
->_details
= CFRetainSafe(details
);
2888 info
= CFDictionaryGetValue(plist
, CFSTR(kSecTrustInfoKey
));
2889 if (isDictionary(info
)) {
2890 output
->_info
= CFRetainSafe(info
);
2892 exceptions
= CFDictionaryGetValue(plist
, CFSTR(kSecTrustExceptionsKey
));
2893 if (isArray(exceptions
)) {
2894 output
->_exceptions
= CFRetainSafe(exceptions
);
2896 int32_t trustResult
= -1;
2897 trustResultNum
= CFDictionaryGetValue(plist
, CFSTR(kSecTrustResultKey
));
2898 if (isNumber(trustResultNum
) && CFNumberGetValue(trustResultNum
, kCFNumberSInt32Type
, &trustResult
) &&
2899 (trustResult
>= 0)) {
2900 output
->_trustResult
= trustResult
;
2902 status
= errSecParam
;
2904 if (CFDictionaryGetValue(plist
, CFSTR(kSecTrustAnchorsOnlyKey
)) == kCFBooleanTrue
) {
2905 output
->_anchorsOnly
= true;
2906 } /* false is set by default */
2907 if (CFDictionaryGetValue(plist
, CFSTR(kSecTrustKeychainsAllowedKey
)) == kCFBooleanFalse
) {
2908 output
->_keychainsAllowed
= false;
2909 } /* true is set by default */
2912 if (errSecSuccess
== status
&& trust
) {
2915 CFReleaseNull(policies
);
2916 CFReleaseNull(certificates
);
2920 SecTrustRef
SecTrustDeserialize(CFDataRef serializedTrust
, CFErrorRef
*error
) {
2921 SecTrustRef trust
= NULL
;
2922 CFPropertyListRef plist
= NULL
;
2923 OSStatus status
= errSecSuccess
;
2924 require_action_quiet(serializedTrust
, out
,
2925 SecError(errSecParam
, error
, CFSTR("null serialized trust input")));
2926 require_quiet(plist
= CFPropertyListCreateWithDERData(NULL
, serializedTrust
,
2927 kCFPropertyListImmutable
, NULL
, error
), out
);
2928 require_noerr_action_quiet(status
= SecTrustCreateFromPlist(plist
, &trust
), out
,
2929 SecError(status
, error
, CFSTR("unable to create trust ref")));
2932 CFReleaseNull(plist
);
2936 #if TARGET_OS_IPHONE
2937 static uint64_t to_uint_error_request(enum SecXPCOperation op
, CFErrorRef
*error
) {
2938 __block
uint64_t result
= 0;
2940 securityd_send_sync_and_do(op
, error
, NULL
, ^bool(xpc_object_t response
, CFErrorRef
*localError
) {
2941 uint64_t temp_result
= xpc_dictionary_get_uint64(response
, kSecXPCKeyResult
);
2942 /* plists do not support unsigned integers. */
2943 if (temp_result
<= INT64_MAX
) {
2944 result
= temp_result
;
2946 secerror("Invalid exceptions epoch.");
2948 *error
= CFErrorCreate(NULL
, kCFErrorDomainPOSIX
, ERANGE
, NULL
);
2951 if (error
&& localError
&& *localError
) {
2952 *error
= *localError
;
2960 uint64_t SecTrustGetExceptionResetCount(CFErrorRef
*error
) {
2961 os_activity_t activity
= os_activity_create("SecTrustExceptionGetResetCount", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_DEFAULT
);
2962 os_activity_scope(activity
);
2963 uint64_t exceptionResetCount
= TRUSTD_XPC(sec_trust_get_exception_reset_count
, to_uint_error_request
, error
);
2964 os_release(activity
);
2965 if (error
&& *error
) {
2966 secerror("Failed to get the exceptions epoch.");
2968 secinfo("trust", "The exceptions epoch is %lld.", exceptionResetCount
);
2970 return exceptionResetCount
;
2973 OSStatus
SecTrustIncrementExceptionResetCount(CFErrorRef
*error
) {
2974 OSStatus status
= errSecInternal
;
2976 os_activity_t activity
= os_activity_create("SecTrustIncrementExceptionResetCount", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_DEFAULT
);
2977 os_activity_scope(activity
);
2978 bool success
= TRUSTD_XPC(sec_trust_increment_exception_reset_count
, to_bool_error_request
, error
);
2979 os_release(activity
);
2980 if ((error
&& *error
) || !success
) {
2981 secerror("Failed to increment the exceptions epoch.");
2984 status
= errSecSuccess
;