2 * Copyright (c) 2006-2018 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
23 * SecTrust.c - CoreFoundation based certificate trust evaluator
27 #include <Security/SecTrustPriv.h>
28 #include <Security/SecTrustInternal.h>
29 #include <Security/SecTrustStatusCodes.h>
30 #include <Security/SecItemPriv.h>
31 #include <Security/SecCertificateInternal.h>
32 #include <Security/SecFramework.h>
33 #include <Security/SecPolicyCerts.h>
34 #include <Security/SecPolicyInternal.h>
35 #include <Security/SecPolicyPriv.h>
36 #include <Security/SecuritydXPC.h>
37 #include <Security/SecInternal.h>
38 #include <Security/SecBasePriv.h>
39 #include <Security/SecFrameworkStrings.h>
40 #include <CoreFoundation/CFRuntime.h>
41 #include <CoreFoundation/CFSet.h>
42 #include <CoreFoundation/CFString.h>
43 #include <CoreFoundation/CFNumber.h>
44 #include <CoreFoundation/CFArray.h>
45 #include <CoreFoundation/CFPropertyList.h>
46 #include <CoreFoundation/CFError.h>
47 #include <AssertMacros.h>
53 #include <os/activity.h>
55 #include <utilities/SecIOFormat.h>
56 #include <utilities/SecCFError.h>
57 #include <utilities/SecCFWrappers.h>
58 #include <utilities/debugging.h>
59 #include <utilities/der_plist.h>
60 #include <utilities/SecDispatchRelease.h>
61 #include <utilities/SecXPCError.h>
63 #include "SecRSAKey.h"
64 #include <libDER/oids.h>
66 #include <ipc/securityd_client.h>
68 #include <securityd/SecTrustServer.h>
70 #pragma clang diagnostic ignored "-Wformat=2"
72 #define SEC_CONST_DECL(k,v) const CFStringRef k = CFSTR(v);
74 SEC_CONST_DECL (kSecCertificateDetailSHA1Digest
, "SHA1Digest");
75 SEC_CONST_DECL (kSecCertificateDetailStatusCodes
, "StatusCodes");
77 SEC_CONST_DECL (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
);
1043 kSecTrustErrorSubTypeBlocked
,
1044 kSecTrustErrorSubTypeRevoked
,
1045 kSecTrustErrorSubTypeKeySize
,
1046 kSecTrustErrorSubTypeWeakHash
,
1047 kSecTrustErrorSubTypeDenied
,
1048 kSecTrustErrorSubTypeCompliance
,
1049 kSecTrustErrorSubTypePinning
,
1050 kSecTrustErrorSubTypeTrust
,
1051 kSecTrustErrorSubTypeUsage
,
1052 kSecTrustErrorSubTypeName
,
1053 kSecTrustErrorSubTypeExpired
,
1054 kSecTrustErrorSubTypeInvalid
,
1055 } SecTrustErrorSubType
;
1057 #define SecCopyTrustString(KEY) SecFrameworkCopyLocalizedString(KEY, CFSTR("Trust"))
1059 struct checkmap_entry_s
{
1060 SecTrustErrorSubType type
;
1062 const CFStringRef errorKey
;
1064 typedef struct checkmap_entry_s checkmap_entry_t
;
1066 const checkmap_entry_t checkmap
[] = {
1067 #undef POLICYCHECKMACRO
1068 #define __PC_SUBTYPE_ kSecTrustErrorSubTypeInvalid
1069 #define __PC_SUBTYPE_N kSecTrustErrorSubTypeName
1070 #define __PC_SUBTYPE_E kSecTrustErrorSubTypeExpired
1071 #define __PC_SUBTYPE_S kSecTrustErrorSubTypeKeySize
1072 #define __PC_SUBTYPE_H kSecTrustErrorSubTypeWeakHash
1073 #define __PC_SUBTYPE_U kSecTrustErrorSubTypeUsage
1074 #define __PC_SUBTYPE_P kSecTrustErrorSubTypePinning
1075 #define __PC_SUBTYPE_V kSecTrustErrorSubTypeRevoked
1076 #define __PC_SUBTYPE_T kSecTrustErrorSubTypeTrust
1077 #define __PC_SUBTYPE_C kSecTrustErrorSubTypeCompliance
1078 #define __PC_SUBTYPE_D kSecTrustErrorSubTypeDenied
1079 #define __PC_SUBTYPE_B kSecTrustErrorSubTypeBlocked
1080 #define POLICYCHECKMACRO(NAME, TRUSTRESULT, SUBTYPE, LEAFCHECK, PATHCHECK, LEAFONLY, CSSMERR, OSSTATUS) \
1081 { __PC_SUBTYPE_##SUBTYPE , OSSTATUS, SEC_TRUST_ERROR_##NAME },
1082 #include "SecPolicyChecks.list"
1085 static OSStatus
SecTrustCopyErrorStrings(SecTrustRef trust
,
1086 CFStringRef
* CF_RETURNS_RETAINED simpleError
,
1087 CFStringRef
* CF_RETURNS_RETAINED fullError
) {
1088 if (!simpleError
|| !fullError
) {
1091 __block CFArrayRef details
= NULL
;
1092 dispatch_sync(trust
->_trustQueue
, ^{
1093 details
= CFRetainSafe(trust
->_details
);
1096 return errSecInternal
;
1098 /* We need to map the policy check constants to indexes into our checkmap table. */
1099 static dispatch_once_t onceToken
;
1100 static CFArrayRef policyChecks
= NULL
;
1101 dispatch_once(&onceToken
, ^{
1102 CFMutableArrayRef _policyChecks
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
1103 #undef POLICYCHECKMACRO
1104 #define POLICYCHECKMACRO(NAME, TRUSTRESULT, SUBTYPE, LEAFCHECK, PATHCHECK, LEAFONLY, CSSMERR, ERRORSTRING) \
1105 CFArrayAppendValue(_policyChecks, kSecPolicyCheck##NAME);
1106 #include "SecPolicyChecks.list"
1107 policyChecks
= _policyChecks
;
1110 /* Build the errors for each cert in the detailed results array */
1111 __block CFMutableStringRef fullMutableError
= CFStringCreateMutable(NULL
, 0);
1112 __block SecTrustErrorSubType simpleErrorSubType
= kSecTrustErrorSubTypeInvalid
;
1113 __block OSStatus simpleErrorStatus
= errSecInternalError
;
1114 __block CFIndex simpleErrorCertIndex
= kCFNotFound
;
1116 CFIndex count
= CFArrayGetCount(details
);
1117 for (ix
= 0; ix
< count
; ix
++) {
1118 CFDictionaryRef perCertDetails
= (CFDictionaryRef
)CFArrayGetValueAtIndex(details
, ix
);
1119 if (CFDictionaryGetCount(perCertDetails
) == 0) { continue; } // no errors on this cert
1121 /* Get the cert summary and start the full error details string for this cert */
1122 CFStringRef certSummary
= SecCertificateCopySubjectSummary(SecTrustGetCertificateAtIndex(trust
, ix
));
1123 CFStringRef format
= SecCopyTrustString(SEC_TRUST_CERTIFICATE_ERROR
);
1124 CFStringAppendFormat(fullMutableError
, NULL
, format
,
1126 CFReleaseNull(certSummary
);
1127 CFReleaseNull(format
);
1129 /* Figure out the errors */
1130 __block
bool firstError
= true;
1131 CFDictionaryForEach(perCertDetails
, ^(const void *key
, const void * __unused value
) {
1132 CFIndex policyCheckIndex
= CFArrayGetFirstIndexOfValue(policyChecks
, CFRangeMake(0, CFArrayGetCount(policyChecks
)), key
);
1133 if ((policyCheckIndex
< 0) || ((size_t)policyCheckIndex
>= sizeof(checkmap
)/sizeof(checkmap
[0]))) {
1134 secwarning("unknown failure key in details dictionary: %@", key
);
1137 /* Keep track of the highest priority error encountered during this evaluation.
1138 * If multiple certs have errors of the same subtype we keep the lowest indexed cert. */
1139 if (simpleErrorSubType
> checkmap
[policyCheckIndex
].type
) {
1140 simpleErrorSubType
= checkmap
[policyCheckIndex
].type
;
1141 simpleErrorCertIndex
= ix
;
1142 simpleErrorStatus
= checkmap
[policyCheckIndex
].status
;
1144 /* Add this error to the full error */
1145 if (!firstError
) { CFStringAppend(fullMutableError
, CFSTR(", ")); }
1146 CFStringRef errorString
= SecCopyTrustString(checkmap
[policyCheckIndex
].errorKey
);
1147 CFStringAppend(fullMutableError
, errorString
);
1148 CFReleaseNull(errorString
);
1151 CFStringAppend(fullMutableError
, CFSTR(";"));
1153 CFReleaseNull(details
);
1155 /* Build the simple error */
1156 if (simpleErrorCertIndex
== kCFNotFound
) { simpleErrorCertIndex
= 0; }
1157 CFStringRef format
= NULL
;
1158 CFStringRef certSummary
= SecCertificateCopySubjectSummary(SecTrustGetCertificateAtIndex(trust
, simpleErrorCertIndex
));
1159 switch (simpleErrorSubType
) {
1160 case kSecTrustErrorSubTypeBlocked
: {
1161 format
= SecCopyTrustString(SEC_TRUST_ERROR_SUBTYPE_BLOCKED
);
1164 case kSecTrustErrorSubTypeRevoked
: {
1165 format
= SecCopyTrustString(SEC_TRUST_ERROR_SUBTYPE_REVOKED
);
1168 case kSecTrustErrorSubTypeKeySize
: {
1169 format
= SecCopyTrustString(SEC_TRUST_ERROR_SUBTYPE_KEYSIZE
);
1172 case kSecTrustErrorSubTypeWeakHash
: {
1173 format
= SecCopyTrustString(SEC_TRUST_ERROR_SUBTYPE_WEAKHASH
);
1176 case kSecTrustErrorSubTypeDenied
: {
1177 format
= SecCopyTrustString(SEC_TRUST_ERROR_SUBTYPE_DENIED
);
1180 case kSecTrustErrorSubTypeCompliance
: {
1181 format
= SecCopyTrustString(SEC_TRUST_ERROR_SUBTYPE_COMPLIANCE
);
1184 case kSecTrustErrorSubTypeExpired
: {
1185 format
= SecCopyTrustString(SEC_TRUST_ERROR_SUBTYPE_EXPIRED
);
1188 case kSecTrustErrorSubTypeTrust
: {
1189 format
= SecCopyTrustString(SEC_TRUST_ERROR_SUBTYPE_TRUST
);
1192 case kSecTrustErrorSubTypeName
: {
1193 format
= SecCopyTrustString(SEC_TRUST_ERROR_SUBTYPE_NAME
);
1196 case kSecTrustErrorSubTypeUsage
: {
1197 format
= SecCopyTrustString(SEC_TRUST_ERROR_SUBTYPE_USAGE
);
1200 case kSecTrustErrorSubTypePinning
: {
1201 format
= SecCopyTrustString(SEC_TRUST_ERROR_SUBTYPE_PINNING
);
1202 CFAssignRetained(certSummary
, SecTrustCopyChainSummary(trust
));
1206 format
= SecCopyTrustString(SEC_TRUST_ERROR_SUBTYPE_INVALID
);
1210 if (format
&& certSummary
) {
1211 *simpleError
= CFStringCreateWithFormat(NULL
, NULL
, format
, certSummary
);
1213 CFReleaseNull(format
);
1214 CFReleaseNull(certSummary
);
1215 *fullError
= fullMutableError
;
1216 return simpleErrorStatus
;
1219 static CF_RETURNS_RETAINED CFErrorRef
SecTrustCopyError(SecTrustRef trust
) {
1220 if (!trust
) { return NULL
; }
1221 OSStatus status
= errSecSuccess
;
1222 __block SecTrustResultType trustResult
= kSecTrustResultInvalid
;
1223 dispatch_sync(trust
->_trustQueue
, ^{
1224 trustResult
= trust
->_trustResult
;
1226 if (trustResult
== kSecTrustResultProceed
|| trustResult
== kSecTrustResultUnspecified
) {
1230 CFStringRef detailedError
= NULL
;
1231 CFStringRef simpleError
= NULL
;
1232 status
= SecTrustCopyErrorStrings(trust
, &simpleError
, &detailedError
);
1233 /* failure to obtain either string must not cause a failure to create the CFErrorRef */
1235 simpleError
= SecCopyErrorMessageString(status
, NULL
);
1237 if (!detailedError
) {
1238 detailedError
= SecCopyErrorMessageString(status
, NULL
);
1240 CFDictionaryRef userInfo
= CFDictionaryCreate(NULL
, (const void **)&kCFErrorLocalizedDescriptionKey
,
1241 (const void **)&detailedError
, 1,
1242 &kCFTypeDictionaryKeyCallBacks
,
1243 &kCFTypeDictionaryValueCallBacks
);
1244 CFErrorRef underlyingError
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, status
, userInfo
);
1245 CFReleaseNull(userInfo
);
1246 CFReleaseNull(detailedError
);
1248 const void *keys
[] = { kCFErrorLocalizedDescriptionKey
, kCFErrorUnderlyingErrorKey
};
1249 const void *values
[] = { simpleError
, underlyingError
};
1250 userInfo
= CFDictionaryCreate(NULL
, keys
, values
, 2,
1251 &kCFTypeDictionaryKeyCallBacks
,
1252 &kCFTypeDictionaryValueCallBacks
);
1253 CFErrorRef error
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, status
, userInfo
);
1254 CFReleaseNull(userInfo
);
1255 CFReleaseNull(simpleError
);
1256 CFReleaseNull(underlyingError
);
1260 bool SecTrustEvaluateWithError(SecTrustRef trust
, CFErrorRef
*error
) {
1261 SecTrustResultType trustResult
= kSecTrustResultInvalid
;
1262 OSStatus status
= SecTrustEvaluateInternal(trust
, &trustResult
);
1263 if (status
== errSecSuccess
&& (trustResult
== kSecTrustResultProceed
|| trustResult
== kSecTrustResultUnspecified
)) {
1270 if (status
!= errSecSuccess
) {
1271 *error
= SecCopyLastError(status
);
1273 *error
= SecTrustCopyError(trust
);
1279 OSStatus
SecTrustEvaluateAsync(SecTrustRef trust
,
1280 dispatch_queue_t queue
, SecTrustCallback result
)
1282 CFRetainSafe(trust
);
1283 dispatch_async(queue
, ^{
1284 SecTrustResultType trustResult
;
1285 if (errSecSuccess
!= SecTrustEvaluateInternal(trust
, &trustResult
)) {
1286 trustResult
= kSecTrustResultInvalid
;
1288 result(trust
, trustResult
);
1289 CFReleaseSafe(trust
);
1291 return errSecSuccess
;
1295 OSStatus
SecTrustEvaluateFastAsync(SecTrustRef trust
,
1296 dispatch_queue_t queue
, SecTrustCallback result
)
1298 if (trust
== NULL
|| queue
== NULL
|| result
== NULL
) {
1302 dispatch_assert_queue(queue
);
1303 SecTrustEvaluateIfNecessaryFastAsync(trust
, queue
, ^(OSStatus status
) {
1304 if (status
!= noErr
) {
1305 result(trust
, kSecTrustResultInvalid
);
1308 __block SecTrustResultType trustResult
= kSecTrustResultInvalid
;
1309 dispatch_sync(trust
->_trustQueue
, ^{
1310 trustResult
= trust
->_trustResult
;
1312 SecTrustLogFailureDescription(trust
, trustResult
);
1315 result(trust
, trustResult
);
1317 return errSecSuccess
;
1320 OSStatus
SecTrustEvaluateAsyncWithError(SecTrustRef trust
, dispatch_queue_t queue
, SecTrustWithErrorCallback callback
)
1322 if (trust
== NULL
|| queue
== NULL
|| callback
== NULL
) {
1326 dispatch_assert_queue(queue
);
1327 SecTrustEvaluateIfNecessaryFastAsync(trust
, queue
, ^(OSStatus status
) {
1328 if (status
!= noErr
) {
1329 CFErrorRef error
= SecCopyLastError(status
);
1330 callback(trust
, false, error
);
1331 CFReleaseNull(error
);
1335 __block SecTrustResultType trustResult
= kSecTrustResultInvalid
;
1336 dispatch_sync(trust
->_trustQueue
, ^{
1337 trustResult
= trust
->_trustResult
;
1339 SecTrustLogFailureDescription(trust
, trustResult
);
1342 CFErrorRef error
= SecTrustCopyError(trust
);
1343 bool result
= (trustResult
== kSecTrustResultProceed
|| trustResult
== kSecTrustResultUnspecified
);
1344 callback(trust
, result
, error
);
1345 CFReleaseNull(error
);
1348 return errSecSuccess
;
1351 static bool append_certificate_to_xpc_array(SecCertificateRef certificate
, xpc_object_t xpc_certificates
);
1352 static xpc_object_t
copy_xpc_certificates_array(CFArrayRef certificates
);
1353 xpc_object_t
copy_xpc_policies_array(CFArrayRef policies
);
1354 OSStatus
validate_array_of_items(CFArrayRef array
, CFStringRef arrayItemType
, CFTypeID itemTypeID
, bool required
);
1356 static bool append_certificate_to_xpc_array(SecCertificateRef certificate
, xpc_object_t xpc_certificates
) {
1358 return true; // NOOP
1360 size_t length
= SecCertificateGetLength(certificate
);
1361 const uint8_t *bytes
= SecCertificateGetBytePtr(certificate
);
1362 if (!length
|| !bytes
) {
1365 xpc_array_set_data(xpc_certificates
, XPC_ARRAY_APPEND
, bytes
, length
);
1369 static xpc_object_t
copy_xpc_certificates_array(CFArrayRef certificates
) {
1370 xpc_object_t xpc_certificates
= xpc_array_create(NULL
, 0);
1371 if (!xpc_certificates
) {
1374 CFIndex ix
, count
= CFArrayGetCount(certificates
);
1375 for (ix
= 0; ix
< count
; ++ix
) {
1376 SecCertificateRef certificate
= (SecCertificateRef
) CFArrayGetValueAtIndex(certificates
, ix
);
1377 #if SECTRUST_VERBOSE_DEBUG
1378 size_t length
= SecCertificateGetLength(certificate
);
1379 const uint8_t *bytes
= SecCertificateGetBytePtr(certificate
);
1380 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
);
1382 if (!append_certificate_to_xpc_array(certificate
, xpc_certificates
)) {
1383 xpc_release(xpc_certificates
);
1384 xpc_certificates
= NULL
;
1388 return xpc_certificates
;
1391 static bool SecXPCDictionarySetCertificates(xpc_object_t message
, const char *key
, CFArrayRef certificates
, CFErrorRef
*error
) {
1392 xpc_object_t xpc_certificates
= copy_xpc_certificates_array(certificates
);
1393 if (!xpc_certificates
) {
1394 SecError(errSecAllocate
, error
, CFSTR("failed to create xpc_array of certificates"));
1397 xpc_dictionary_set_value(message
, key
, xpc_certificates
);
1398 xpc_release(xpc_certificates
);
1402 static bool SecXPCDictionarySetPolicies(xpc_object_t message
, const char *key
, CFArrayRef policies
, CFErrorRef
*error
) {
1403 xpc_object_t xpc_policies
= copy_xpc_policies_array(policies
);
1404 if (!xpc_policies
) {
1405 SecError(errSecAllocate
, error
, CFSTR("failed to create xpc_array of policies"));
1408 xpc_dictionary_set_value(message
, key
, xpc_policies
);
1409 xpc_release(xpc_policies
);
1414 static bool CFDataAppendToXPCArray(CFDataRef data
, xpc_object_t xpc_data_array
, CFErrorRef
*error
) {
1416 return true; // NOOP
1418 size_t length
= CFDataGetLength(data
);
1419 const uint8_t *bytes
= CFDataGetBytePtr(data
);
1420 if (!length
|| !bytes
)
1421 return SecError(errSecParam
, error
, CFSTR("invalid CFDataRef"));
1423 xpc_array_set_data(xpc_data_array
, XPC_ARRAY_APPEND
, bytes
, length
);
1428 static xpc_object_t
CFDataArrayCopyXPCArray(CFArrayRef data_array
, CFErrorRef
*error
) {
1429 xpc_object_t xpc_data_array
;
1430 require_action_quiet(xpc_data_array
= xpc_array_create(NULL
, 0), exit
,
1431 SecError(errSecAllocate
, error
, CFSTR("failed to create xpc_array")));
1432 CFIndex ix
, count
= CFArrayGetCount(data_array
);
1433 for (ix
= 0; ix
< count
; ++ix
) {
1434 if (!CFDataAppendToXPCArray((CFDataRef
)CFArrayGetValueAtIndex(data_array
, ix
), xpc_data_array
, error
)) {
1435 xpc_release(xpc_data_array
);
1441 return xpc_data_array
;
1444 static bool SecXPCDictionarySetDataArray(xpc_object_t message
, const char *key
, CFArrayRef data_array
, CFErrorRef
*error
) {
1445 xpc_object_t xpc_data_array
= CFDataArrayCopyXPCArray(data_array
, error
);
1446 if (!xpc_data_array
)
1448 xpc_dictionary_set_value(message
, key
, xpc_data_array
);
1449 xpc_release(xpc_data_array
);
1453 static bool SecXPCDictionaryCopyChainOptional(xpc_object_t message
, const char *key
, CFArrayRef
*path
, CFErrorRef
*error
) {
1454 xpc_object_t xpc_path
= xpc_dictionary_get_value(message
, key
);
1455 CFMutableArrayRef output
= NULL
;
1461 require_action_quiet(xpc_get_type(xpc_path
) == XPC_TYPE_ARRAY
, exit
, SecError(errSecDecode
, error
, CFSTR("xpc_path value is not an array")));
1462 require_action_quiet(count
= xpc_array_get_count(xpc_path
), exit
, SecError(errSecDecode
, error
, CFSTR("xpc_path array count == 0")));
1463 output
= CFArrayCreateMutable(NULL
, count
, &kCFTypeArrayCallBacks
);
1466 for (ix
= 0; ix
< count
; ++ix
) {
1467 SecCertificateRef certificate
= SecCertificateCreateWithXPCArrayAtIndex(xpc_path
, ix
, error
);
1469 CFArrayAppendValue(output
, certificate
);
1470 CFReleaseNull(certificate
);
1472 CFReleaseNull(output
);
1485 static int SecXPCDictionaryGetNonZeroInteger(xpc_object_t message
, const char *key
, CFErrorRef
*error
) {
1486 int64_t value
= xpc_dictionary_get_int64(message
, key
);
1488 SecError(errSecInternal
, error
, CFSTR("object for key %s is 0"), key
);
1493 static SecTrustResultType
handle_trust_evaluate_xpc(enum SecXPCOperation op
, CFArrayRef certificates
,
1494 CFArrayRef anchors
, bool anchorsOnly
,
1495 bool keychainsAllowed
, CFArrayRef policies
, CFArrayRef responses
,
1496 CFArrayRef SCTs
, CFArrayRef trustedLogs
,
1497 CFAbsoluteTime verifyTime
, __unused CFArrayRef accessGroups
, CFArrayRef exceptions
,
1498 CFArrayRef
*details
, CFDictionaryRef
*info
, CFArrayRef
*chain
, CFErrorRef
*error
)
1500 __block SecTrustResultType tr
= kSecTrustResultInvalid
;
1501 securityd_send_sync_and_do(op
, error
, ^bool(xpc_object_t message
, CFErrorRef
*blockError
) {
1502 if (!SecXPCDictionarySetCertificates(message
, kSecTrustCertificatesKey
, certificates
, blockError
))
1504 if (anchors
&& !SecXPCDictionarySetCertificates(message
, kSecTrustAnchorsKey
, anchors
, blockError
))
1507 xpc_dictionary_set_bool(message
, kSecTrustAnchorsOnlyKey
, anchorsOnly
);
1508 xpc_dictionary_set_bool(message
, kSecTrustKeychainsAllowedKey
, keychainsAllowed
);
1509 if (!SecXPCDictionarySetPolicies(message
, kSecTrustPoliciesKey
, policies
, blockError
))
1511 if (responses
&& !SecXPCDictionarySetDataArray(message
, kSecTrustResponsesKey
, responses
, blockError
))
1513 if (SCTs
&& !SecXPCDictionarySetDataArray(message
, kSecTrustSCTsKey
, SCTs
, blockError
))
1515 if (trustedLogs
&& !SecXPCDictionarySetPList(message
, kSecTrustTrustedLogsKey
, trustedLogs
, blockError
))
1517 xpc_dictionary_set_double(message
, kSecTrustVerifyDateKey
, verifyTime
);
1518 if (exceptions
&& !SecXPCDictionarySetPList(message
, kSecTrustExceptionsKey
, exceptions
, blockError
))
1521 }, ^bool(xpc_object_t response
, CFErrorRef
*blockError
) {
1522 secdebug("trust", "response: %@", response
);
1523 return SecXPCDictionaryCopyArrayOptional(response
, kSecTrustDetailsKey
, details
, blockError
) &&
1524 SecXPCDictionaryCopyDictionaryOptional(response
, kSecTrustInfoKey
, info
, blockError
) &&
1525 SecXPCDictionaryCopyChainOptional(response
, kSecTrustChainKey
, chain
, blockError
) &&
1526 ((tr
= SecXPCDictionaryGetNonZeroInteger(response
, kSecTrustResultKey
, blockError
)) != kSecTrustResultInvalid
);
1531 typedef void (^trust_handler_t
)(SecTrustResultType tr
, CFErrorRef error
);
1533 static void handle_trust_evaluate_xpc_async(dispatch_queue_t replyq
, trust_handler_t trustHandler
,
1534 enum SecXPCOperation op
, CFArrayRef certificates
,
1535 CFArrayRef anchors
, bool anchorsOnly
,
1536 bool keychainsAllowed
, CFArrayRef policies
,
1537 CFArrayRef responses
, CFArrayRef SCTs
, CFArrayRef trustedLogs
,
1538 CFAbsoluteTime verifyTime
, __unused CFArrayRef accessGroups
,
1539 CFArrayRef exceptions
, CFArrayRef
*details
,
1540 CFDictionaryRef
*info
, CFArrayRef
*chain
)
1542 securityd_send_async_and_do(op
, replyq
, ^bool(xpc_object_t message
, CFErrorRef
*error
) {
1543 if (!SecXPCDictionarySetCertificates(message
, kSecTrustCertificatesKey
, certificates
, error
))
1545 if (anchors
&& !SecXPCDictionarySetCertificates(message
, kSecTrustAnchorsKey
, anchors
, error
))
1548 xpc_dictionary_set_bool(message
, kSecTrustAnchorsOnlyKey
, anchorsOnly
);
1549 xpc_dictionary_set_bool(message
, kSecTrustKeychainsAllowedKey
, keychainsAllowed
);
1550 if (!SecXPCDictionarySetPolicies(message
, kSecTrustPoliciesKey
, policies
, error
))
1552 if (responses
&& !SecXPCDictionarySetDataArray(message
, kSecTrustResponsesKey
, responses
, error
))
1554 if (SCTs
&& !SecXPCDictionarySetDataArray(message
, kSecTrustSCTsKey
, SCTs
, error
))
1556 if (trustedLogs
&& !SecXPCDictionarySetPList(message
, kSecTrustTrustedLogsKey
, trustedLogs
, error
))
1558 xpc_dictionary_set_double(message
, kSecTrustVerifyDateKey
, verifyTime
);
1559 if (exceptions
&& !SecXPCDictionarySetPList(message
, kSecTrustExceptionsKey
, exceptions
, error
))
1562 }, ^(xpc_object_t response
, CFErrorRef error
) {
1563 secdebug("trust", "response: %@", response
);
1564 if (response
== NULL
|| error
!= NULL
) {
1565 trustHandler(kSecTrustResultInvalid
, error
);
1568 SecTrustResultType tr
= kSecTrustResultInvalid
;
1569 CFErrorRef error2
= NULL
;
1570 if (SecXPCDictionaryCopyArrayOptional(response
, kSecTrustDetailsKey
, details
, &error2
) &&
1571 SecXPCDictionaryCopyDictionaryOptional(response
, kSecTrustInfoKey
, info
, &error2
) &&
1572 SecXPCDictionaryCopyChainOptional(response
, kSecTrustChainKey
, chain
, &error2
)) {
1573 tr
= SecXPCDictionaryGetNonZeroInteger(response
, kSecTrustResultKey
, &error2
);
1575 trustHandler(tr
, error2
);
1576 CFReleaseNull(error2
);
1580 OSStatus
validate_array_of_items(CFArrayRef array
, CFStringRef arrayItemType
, CFTypeID itemTypeID
, bool required
) {
1581 OSStatus result
= errSecSuccess
;
1582 CFIndex index
, count
;
1583 count
= (array
) ? CFArrayGetCount(array
) : 0;
1584 if (!count
&& required
) {
1585 secerror("no %@ in array!", arrayItemType
);
1586 result
= errSecParam
;
1588 for (index
= 0; index
< count
; index
++) {
1589 CFTypeRef item
= (CFTypeRef
) CFArrayGetValueAtIndex(array
, index
);
1591 secerror("%@ %@ (index %d)", arrayItemType
, CFSTR("reference is nil"), (int)index
);
1592 result
= errSecParam
;
1595 if (CFGetTypeID(item
) != itemTypeID
) {
1596 secerror("%@ %@ (index %d)", arrayItemType
, CFSTR("is not the expected CF type"), (int)index
);
1597 result
= errSecParam
;
1600 if (CFGetTypeID(item
) == SecCertificateGetTypeID()) {
1601 SecCertificateRef certificate
= (SecCertificateRef
) item
;
1602 CFIndex length
= SecCertificateGetLength(certificate
);
1603 const UInt8
*bytes
= SecCertificateGetBytePtr(certificate
);
1605 secerror("%@ %@ (index %d)", arrayItemType
, CFSTR("has zero length"), (int)index
);
1606 result
= errSecParam
;
1609 secerror("%@ %@ (index %d)", arrayItemType
, CFSTR("has nil bytes"), (int)index
);
1610 result
= errSecParam
;
1612 #if SECTRUST_VERBOSE_DEBUG
1613 secerror("%@[%d] of %d = %ld bytes @ 0x%lX", arrayItemType
, (int)index
, (int)count
, (size_t)length
, (uintptr_t)bytes
);
1617 if (CFGetTypeID(item
) == SecPolicyGetTypeID()) {
1618 SecPolicyRef policy
= (SecPolicyRef
) item
;
1619 CFStringRef oidStr
= policy
->_oid
;
1620 if (!oidStr
|| (CFGetTypeID(oidStr
) != CFStringGetTypeID())) {
1621 oidStr
= CFSTR("has invalid OID string!");
1622 secerror("%@ %@ (index %d)", arrayItemType
, oidStr
, (int)index
);
1624 #if SECTRUST_VERBOSE_DEBUG
1625 secerror("%@[%d] of %d = \"%@\" 0x%lX", arrayItemType
, (int)index
, (int)count
, oidStr
, (uintptr_t)policy
);
1632 static OSStatus
SecTrustValidateInput(SecTrustRef trust
) {
1633 OSStatus status
, result
= errSecSuccess
;
1635 // certificates (required)
1636 status
= validate_array_of_items(trust
->_certificates
, CFSTR("certificate"), SecCertificateGetTypeID(), true);
1637 if (status
) result
= status
;
1638 // anchors (optional)
1639 status
= validate_array_of_items(trust
->_anchors
, CFSTR("input anchor"), SecCertificateGetTypeID(), false);
1640 if (status
) result
= status
;
1641 // policies (required??)
1642 status
= validate_array_of_items(trust
->_policies
, CFSTR("policy"), SecPolicyGetTypeID(), true);
1643 if (status
) result
= status
;
1644 // _responses, _SCTs, _trustedLogs, ...
1645 // verify time: SecTrustGetVerifyTime(trust)
1646 // access groups: SecAccessGroupsGetCurrent()
1651 static CFArrayRef
SecTrustGetCurrentAccessGroups(void) {
1652 static CFArrayRef accessGroups
= NULL
;
1653 static dispatch_once_t onceToken
;
1654 dispatch_once(&onceToken
, ^{
1655 accessGroups
= CFArrayCreateForCFTypes(kCFAllocatorDefault
,
1656 CFSTR("com.apple.trustd"),
1657 CFSTR("com.apple.trusttests"),
1660 return accessGroups
;
1663 static OSStatus
SecTrustEvaluateIfNecessary(SecTrustRef trust
) {
1664 __block OSStatus result
;
1669 __block CFAbsoluteTime verifyTime
= SecTrustGetVerifyTime(trust
);
1670 SecTrustAddPolicyAnchors(trust
);
1671 dispatch_sync(trust
->_trustQueue
, ^{
1672 if (trust
->_trustResult
!= kSecTrustResultInvalid
) {
1673 result
= errSecSuccess
;
1677 trust
->_trustResult
= kSecTrustResultOtherError
; /* to avoid potential recursion */
1679 CFReleaseNull(trust
->_chain
);
1680 CFReleaseNull(trust
->_details
);
1681 CFReleaseNull(trust
->_info
);
1682 if (trust
->_legacy_info_array
) {
1683 free(trust
->_legacy_info_array
);
1684 trust
->_legacy_info_array
= NULL
;
1686 if (trust
->_legacy_status_array
) {
1687 free(trust
->_legacy_status_array
);
1688 trust
->_legacy_status_array
= NULL
;
1691 os_activity_initiate("SecTrustEvaluateIfNecessary", OS_ACTIVITY_FLAG_DEFAULT
, ^{
1692 SecTrustValidateInput(trust
);
1694 /* @@@ 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. */
1695 result
= SecOSStatusWith(^bool (CFErrorRef
*error
) {
1696 trust
->_trustResult
= TRUSTD_XPC(sec_trust_evaluate
,
1697 handle_trust_evaluate_xpc
,
1698 trust
->_certificates
, trust
->_anchors
, trust
->_anchorsOnly
, trust
->_keychainsAllowed
,
1699 trust
->_policies
, trust
->_responses
, trust
->_SCTs
, trust
->_trustedLogs
,
1700 verifyTime
, SecTrustGetCurrentAccessGroups(), trust
->_exceptions
,
1701 &trust
->_details
, &trust
->_info
, &trust
->_chain
, error
);
1702 if (trust
->_trustResult
== kSecTrustResultInvalid
/* TODO check domain */ &&
1703 SecErrorGetOSStatus(*error
) == errSecNotAvailable
&&
1704 CFArrayGetCount(trust
->_certificates
)) {
1705 /* We failed to talk to securityd. The only time this should
1706 happen is when we are running prior to launchd enabling
1707 registration of services. This currently happens when we
1708 are running from the ramdisk. To make ASR happy we initialize
1709 _chain and return success with a failure as the trustResult, to
1710 make it seem like we did a cert evaluation, so ASR can extract
1711 the public key from the leaf. */
1712 SecCertificateRef leafCert
= (SecCertificateRef
)CFArrayGetValueAtIndex(trust
->_certificates
, 0);
1713 CFArrayRef leafCertArray
= CFArrayCreate(NULL
, (const void**)&leafCert
, 1, &kCFTypeArrayCallBacks
);
1714 trust
->_chain
= leafCertArray
;
1716 CFReleaseNull(*error
);
1719 return trust
->_trustResult
!= kSecTrustResultInvalid
;
1726 // IMPORTANT: this MUST be called on the provided queue as it will call the handler synchronously
1727 // if no asynchronous work is needed
1728 static void SecTrustEvaluateIfNecessaryFastAsync(SecTrustRef trust
,
1729 dispatch_queue_t queue
,
1730 void (^handler
)(OSStatus status
)) {
1734 if (handler
== NULL
) {
1737 if (trust
== NULL
|| queue
== NULL
) {
1738 handler(errSecParam
);
1742 __block
bool shouldReturnSuccess
= false;
1743 __block CFAbsoluteTime verifyTime
= SecTrustGetVerifyTime(trust
);
1744 SecTrustAddPolicyAnchors(trust
);
1745 dispatch_sync(trust
->_trustQueue
, ^{
1746 if (trust
->_trustResult
!= kSecTrustResultInvalid
) {
1747 shouldReturnSuccess
= true;
1751 trust
->_trustResult
= kSecTrustResultOtherError
; /* to avoid potential recursion */
1753 CFReleaseNull(trust
->_chain
);
1754 CFReleaseNull(trust
->_details
);
1755 CFReleaseNull(trust
->_info
);
1756 if (trust
->_legacy_info_array
) {
1757 free(trust
->_legacy_info_array
);
1758 trust
->_legacy_info_array
= NULL
;
1760 if (trust
->_legacy_status_array
) {
1761 free(trust
->_legacy_status_array
);
1762 trust
->_legacy_status_array
= NULL
;
1765 os_activity_t activity
= os_activity_create("SecTrustEvaluateIfNecessaryFastAsync",
1766 OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_DEFAULT
);
1767 __block
struct os_activity_scope_state_s activityState
;
1768 os_activity_scope_enter(activity
, &activityState
);
1769 os_release(activity
);
1771 SecTrustValidateInput(trust
);
1773 CFRetainSafe(trust
);
1774 TRUSTD_XPC_ASYNC(sec_trust_evaluate
,
1775 handle_trust_evaluate_xpc_async
,
1777 ^(SecTrustResultType tr
, CFErrorRef error
) {
1778 __block OSStatus result
= errSecInternalError
;
1779 dispatch_sync(trust
->_trustQueue
, ^{
1780 trust
->_trustResult
= tr
;
1781 if (trust
->_trustResult
== kSecTrustResultInvalid
/* TODO check domain */ &&
1782 SecErrorGetOSStatus(error
) == errSecNotAvailable
&&
1783 CFArrayGetCount(trust
->_certificates
)) {
1784 /* We failed to talk to securityd. The only time this should
1785 happen is when we are running prior to launchd enabling
1786 registration of services. This currently happens when we
1787 are running from the ramdisk. To make ASR happy we initialize
1788 _chain and return success with a failure as the trustResult, to
1789 make it seem like we did a cert evaluation, so ASR can extract
1790 the public key from the leaf. */
1791 SecCertificateRef leafCert
= (SecCertificateRef
)CFArrayGetValueAtIndex(trust
->_certificates
, 0);
1792 CFArrayRef leafCertArray
= CFArrayCreate(NULL
, (const void**)&leafCert
, 1, &kCFTypeArrayCallBacks
);
1793 trust
->_chain
= leafCertArray
;
1794 result
= errSecSuccess
;
1797 result
= SecOSStatusWith(^bool (CFErrorRef
*error2
) {
1798 if (error2
!= NULL
) {
1801 return trust
->_trustResult
!= kSecTrustResultInvalid
;
1804 os_activity_scope_leave(&activityState
);
1806 CFReleaseSafe(trust
);
1808 trust
->_certificates
, trust
->_anchors
, trust
->_anchorsOnly
, trust
->_keychainsAllowed
,
1809 trust
->_policies
, trust
->_responses
, trust
->_SCTs
, trust
->_trustedLogs
,
1810 verifyTime
, SecTrustGetCurrentAccessGroups(), trust
->_exceptions
,
1811 &trust
->_details
, &trust
->_info
, &trust
->_chain
);
1813 if (shouldReturnSuccess
) {
1814 handler(errSecSuccess
);
1818 /* Helper for the qsort below. */
1819 static int compare_strings(const void *a1
, const void *a2
) {
1820 CFStringRef s1
= *(CFStringRef
*)a1
;
1821 CFStringRef s2
= *(CFStringRef
*)a2
;
1822 return (int) CFStringCompare(s1
, s2
, kCFCompareForcedOrdering
);
1825 CFStringRef
SecTrustCopyFailureDescription(SecTrustRef trust
) {
1829 CFMutableStringRef reason
= CFStringCreateMutable(NULL
, 0);
1830 SecTrustEvaluateIfNecessary(trust
);
1831 __block CFArrayRef details
= NULL
;
1832 dispatch_sync(trust
->_trustQueue
, ^{
1833 details
= CFRetainSafe(trust
->_details
);
1835 CFIndex pathLength
= details
? CFArrayGetCount(details
) : 0;
1836 for (CFIndex ix
= 0; ix
< pathLength
; ++ix
) {
1837 CFDictionaryRef detail
= (CFDictionaryRef
)CFArrayGetValueAtIndex(details
, ix
);
1838 CFIndex dCount
= CFDictionaryGetCount(detail
);
1841 CFStringAppend(reason
, CFSTR(" [leaf"));
1842 else if (ix
== pathLength
- 1)
1843 CFStringAppend(reason
, CFSTR(" [root"));
1845 CFStringAppendFormat(reason
, NULL
, CFSTR(" [ca%" PRIdCFIndex
), ix
);
1847 const void *keys
[dCount
];
1848 CFDictionaryGetKeysAndValues(detail
, &keys
[0], NULL
);
1849 qsort(&keys
[0], dCount
, sizeof(keys
[0]), compare_strings
);
1850 for (CFIndex kix
= 0; kix
< dCount
; ++kix
) {
1851 CFStringRef key
= keys
[kix
];
1852 const void *value
= CFDictionaryGetValue(detail
, key
);
1853 CFStringAppendFormat(reason
, NULL
, CFSTR(" %@%@"), key
,
1854 (CFGetTypeID(value
) == CFBooleanGetTypeID()
1855 ? CFSTR("") : value
));
1857 CFStringAppend(reason
, CFSTR("]"));
1860 CFReleaseSafe(details
);
1865 /* On OS X we need SecTrustCopyPublicKey to give us a CDSA-based SecKeyRef,
1866 so we will refer to this one internally as SecTrustCopyPublicKey_ios,
1867 and call it from SecTrustCopyPublicKey.
1869 SecKeyRef
SecTrustCopyPublicKey_ios(SecTrustRef trust
)
1871 SecKeyRef
SecTrustCopyPublicKey(SecTrustRef trust
)
1877 __block SecKeyRef publicKey
= NULL
;
1878 dispatch_sync(trust
->_trustQueue
, ^{
1879 if (trust
->_publicKey
) {
1880 publicKey
= CFRetainSafe(trust
->_publicKey
);
1883 SecCertificateRef leaf
= (SecCertificateRef
)CFArrayGetValueAtIndex(trust
->_certificates
, 0);
1884 trust
->_publicKey
= SecCertificateCopyKey(leaf
);
1885 if (trust
->_publicKey
) {
1886 publicKey
= CFRetainSafe(trust
->_publicKey
);
1889 /* If we couldn't get a public key from the leaf cert alone. */
1891 SecTrustEvaluateIfNecessary(trust
);
1892 dispatch_sync(trust
->_trustQueue
, ^{
1893 if (trust
->_chain
) {
1894 SecCertificateRef cert
= (SecCertificateRef
)CFArrayGetValueAtIndex(trust
->_chain
, 0);
1895 trust
->_publicKey
= SecCertificateCopyKey(cert
);
1896 publicKey
= CFRetainSafe(trust
->_publicKey
);
1903 CFIndex
SecTrustGetCertificateCount(SecTrustRef trust
) {
1907 SecTrustEvaluateIfNecessary(trust
);
1908 __block CFIndex certCount
= 1;
1909 dispatch_sync(trust
->_trustQueue
, ^{
1910 if (trust
->_chain
) {
1911 certCount
= CFArrayGetCount(trust
->_chain
);
1917 SecCertificateRef
SecTrustGetCertificateAtIndex(SecTrustRef trust
,
1922 __block SecCertificateRef cert
= NULL
;
1924 dispatch_sync(trust
->_trustQueue
, ^{
1925 cert
= (SecCertificateRef
)CFArrayGetValueAtIndex(trust
->_certificates
, 0);
1929 SecTrustEvaluateIfNecessary(trust
);
1930 dispatch_sync(trust
->_trustQueue
, ^{
1931 if (trust
->_chain
) {
1932 cert
= (SecCertificateRef
)CFArrayGetValueAtIndex(trust
->_chain
, ix
);
1938 CFDictionaryRef
SecTrustCopyInfo(SecTrustRef trust
) {
1942 SecTrustEvaluateIfNecessary(trust
);
1943 __block CFDictionaryRef info
= NULL
;
1944 dispatch_sync(trust
->_trustQueue
, ^{
1945 info
= CFRetainSafe(trust
->_info
);
1950 CFArrayRef
SecTrustGetTrustExceptionsArray(SecTrustRef trust
) {
1954 __block CFArrayRef exceptions
= NULL
;
1955 dispatch_sync(trust
->_trustQueue
, ^{
1956 exceptions
= trust
->_exceptions
;
1961 CFDataRef
SecTrustCopyExceptions(SecTrustRef trust
) {
1962 /* Stash the old exceptions and run an evaluation with no exceptions filtered. */
1963 __block CFArrayRef oldExceptions
= NULL
;
1964 dispatch_sync(trust
->_trustQueue
, ^{
1965 if (trust
->_exceptions
) {
1966 oldExceptions
= trust
->_exceptions
;
1967 trust
->_exceptions
= NULL
;
1970 SecTrustSetNeedsEvaluation(trust
);
1972 /* Create the new exceptions based on an unfiltered eval. */
1973 __block CFArrayRef details
= NULL
;
1974 SecTrustEvaluateIfNecessary(trust
);
1975 dispatch_sync(trust
->_trustQueue
, ^{
1976 details
= CFRetainSafe(trust
->_details
);
1978 CFIndex pathLength
= details
? CFArrayGetCount(details
) : 0;
1979 CFMutableArrayRef exceptions
= CFArrayCreateMutable(kCFAllocatorDefault
, pathLength
, &kCFTypeArrayCallBacks
);
1980 #if TARGET_OS_IPHONE
1981 /* Fetch the current exceptions epoch and tag each exception with it. */
1982 CFErrorRef exceptionResetCountError
= NULL
;
1983 uint64_t exceptionResetCount
= SecTrustGetExceptionResetCount(&exceptionResetCountError
);
1984 secinfo("trust", "The current exceptions epoch is %llu. (%{public}s)", exceptionResetCount
, exceptionResetCountError
? "Error" : "OK");
1985 CFNumberRef exceptionResetCountRef
= CFNumberCreate(NULL
, kCFNumberSInt64Type
, &exceptionResetCount
);
1988 for (ix
= 0; ix
< pathLength
; ++ix
) {
1989 CFDictionaryRef detail
= (CFDictionaryRef
)CFArrayGetValueAtIndex(details
, ix
);
1990 CFIndex detailCount
= CFDictionaryGetCount(detail
);
1991 CFMutableDictionaryRef exception
;
1992 if (ix
== 0 || detailCount
> 0) {
1993 exception
= CFDictionaryCreateMutableCopy(kCFAllocatorDefault
, detailCount
+ 1, detail
);
1994 SecCertificateRef certificate
= SecTrustGetCertificateAtIndex(trust
, ix
);
1995 CFDataRef digest
= SecCertificateGetSHA1Digest(certificate
);
1996 CFDictionaryAddValue(exception
, kSecCertificateDetailSHA1Digest
, digest
);
1997 #if TARGET_OS_IPHONE
1998 if (exceptionResetCount
&& !exceptionResetCountError
&& exceptionResetCountRef
) {
1999 CFDictionaryAddValue(exception
, kSecCertificateExceptionResetCount
, exceptionResetCountRef
);
2003 /* Add empty exception dictionaries for non leaf certs which have no exceptions to save space. */
2004 exception
= (CFMutableDictionaryRef
)CFDictionaryCreate(kCFAllocatorDefault
, NULL
, NULL
, 0,
2005 &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
2007 CFArrayAppendValue(exceptions
, exception
);
2008 CFReleaseNull(exception
);
2011 /* Restore the stashed exceptions. */
2012 if (oldExceptions
) {
2013 dispatch_sync(trust
->_trustQueue
, ^{
2014 trust
->_exceptions
= oldExceptions
;
2016 SecTrustSetNeedsEvaluation(trust
);
2019 /* Remove any trailing empty dictionaries to save even more space (we skip the leaf
2020 since it will never be empty). */
2021 for (ix
= pathLength
; ix
-- > 1;) {
2022 CFDictionaryRef exception
= (CFDictionaryRef
)CFArrayGetValueAtIndex(exceptions
, ix
);
2023 if (CFDictionaryGetCount(exception
) == 0) {
2024 CFArrayRemoveValueAtIndex(exceptions
, ix
);
2030 CFDataRef encodedExceptions
= CFPropertyListCreateData(kCFAllocatorDefault
,
2031 exceptions
, kCFPropertyListBinaryFormat_v1_0
, 0, NULL
);
2032 CFRelease(exceptions
);
2033 CFReleaseSafe(details
);
2034 #if TARGET_OS_IPHONE
2035 CFReleaseSafe(exceptionResetCountRef
);
2037 return encodedExceptions
;
2040 #if TARGET_OS_IPHONE
2041 static bool SecTrustExceptionsValidForThisEpoch(CFArrayRef exceptions
) {
2045 CFDictionaryRef exception
= (CFDictionaryRef
)CFArrayGetValueAtIndex(exceptions
, 0);
2047 CFErrorRef currentExceptionResetCountError
= NULL
;
2048 uint64_t currentExceptionResetCount
= SecTrustGetExceptionResetCount(¤tExceptionResetCountError
);
2049 secinfo("trust", "The current exceptions epoch is %llu. (%{public}s)", currentExceptionResetCount
, currentExceptionResetCountError
? "Error" : "OK");
2050 /* Fail closed: if we were unable to get the current exceptions epoch consider the exceptions invalid. */
2051 if (currentExceptionResetCountError
) {
2052 secerror("Failed to get the current exceptions epoch.");
2055 /* If this is the first epoch ever there is no point in checking whether any exceptions belong in the past. */
2056 if (currentExceptionResetCount
== 0) {
2060 CFNumberRef resetCountRef
= CFDictionaryGetValue(exception
, kSecCertificateExceptionResetCount
);
2061 if (!resetCountRef
) {
2062 secerror("Failed to get the exception's epoch.");
2066 uint64_t exceptionResetCount
;
2067 if (!CFNumberGetValue(resetCountRef
, kCFNumberSInt64Type
, &exceptionResetCount
)) {
2068 secerror("Failed to parse the current exceptions epoch as a uint64.");
2072 if (exceptionResetCount
!= currentExceptionResetCount
) {
2073 secerror("The current exception's epoch (%llu) is not the current epoch. (%llu)", exceptionResetCount
, currentExceptionResetCount
);
2077 secinfo("trust", "Exceptions are valid for the current exceptions epoch. (%llu)", currentExceptionResetCount
);
2082 bool SecTrustSetExceptions(SecTrustRef trust
, CFDataRef encodedExceptions
) {
2086 CFArrayRef exceptions
= NULL
;
2088 if (NULL
!= encodedExceptions
) {
2089 exceptions
= (CFArrayRef
)CFPropertyListCreateWithData(kCFAllocatorDefault
,
2090 encodedExceptions
, kCFPropertyListImmutable
, NULL
, NULL
);
2093 if (exceptions
&& CFGetTypeID(exceptions
) != CFArrayGetTypeID()) {
2094 CFRelease(exceptions
);
2098 dispatch_sync(trust
->_trustQueue
, ^{
2099 CFReleaseSafe(trust
->_exceptions
);
2100 trust
->_exceptions
= exceptions
;
2103 /* We changed the exceptions -- so we need to re-evaluate */
2104 SecTrustSetNeedsEvaluation(trust
);
2106 /* If there is a valid exception entry for our current leaf we're golden. */
2107 #if TARGET_OS_IPHONE
2108 if (SecTrustGetExceptionForCertificateAtIndex(trust
, 0) && SecTrustExceptionsValidForThisEpoch(exceptions
)) {
2110 if (SecTrustGetExceptionForCertificateAtIndex(trust
, 0)) {
2115 /* The passed in exceptions didn't match our current leaf, so we discard it. */
2116 dispatch_sync(trust
->_trustQueue
, ^{
2117 CFReleaseNull(trust
->_exceptions
);
2124 SecTrustSetOptions(SecTrustRef trustRef
, SecTrustOptionFlags options
)
2126 /* bridge to support API functionality for legacy callers */
2127 OSStatus status
= errSecSuccess
;
2129 /* No options or none that trigger the exceptions behavior */
2131 0 == (options
& (kSecTrustOptionAllowExpired
|
2132 kSecTrustOptionImplicitAnchors
|
2133 kSecTrustOptionAllowExpiredRoot
))) {
2137 __block CFMutableArrayRef exceptions
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
2138 if (!exceptions
) { return errSecAllocate
; }
2140 /* Add the new options to the old_exceptions when those exceptions are tied to a particular cert.
2141 * If not tied to a particular cert, we reset the exceptions based on the input options. */
2142 CFArrayRef old_exceptions
= SecTrustGetTrustExceptionsArray(trustRef
);
2143 if (old_exceptions
&& SecTrustGetExceptionForCertificateAtIndex(trustRef
, 0)) {
2144 CFIndex ix
, count
= CFArrayGetCount(old_exceptions
);
2145 for (ix
= 0; ix
< count
; ix
++) {
2146 CFMutableDictionaryRef exception_dictionary
= CFDictionaryCreateMutableCopy(NULL
, 0, (CFDictionaryRef
)CFArrayGetValueAtIndex(old_exceptions
, ix
));
2147 if (!exception_dictionary
) { status
= errSecAllocate
; goto out
; }
2148 if ((options
& kSecTrustOptionAllowExpired
) != 0) {
2149 CFDictionaryAddValue(exception_dictionary
, kSecPolicyCheckTemporalValidity
, kCFBooleanFalse
);
2151 if ((options
& (kSecTrustOptionImplicitAnchors
| kSecTrustOptionAllowExpiredRoot
)) != 0) {
2152 /* Check that root is self-signed. */
2153 Boolean isSelfSigned
= false;
2154 SecCertificateRef cert
= SecTrustGetCertificateAtIndex(trustRef
, ix
);
2155 if (cert
&& (errSecSuccess
== SecCertificateIsSelfSigned(cert
, &isSelfSigned
)) &&
2157 if ((options
& kSecTrustOptionImplicitAnchors
) != 0) {
2158 CFDictionaryAddValue(exception_dictionary
, kSecPolicyCheckAnchorTrusted
, kCFBooleanFalse
);
2159 } else if ((options
& kSecTrustOptionAllowExpiredRoot
) != 0) {
2160 CFDictionaryAddValue(exception_dictionary
, kSecPolicyCheckTemporalValidity
, kCFBooleanFalse
);
2164 CFArrayAppendValue(exceptions
, exception_dictionary
);
2165 CFReleaseNull(exception_dictionary
);
2168 /* Create a new exceptions array. Warning, this takes advantage of implementation details of the exceptions mechanism. */
2169 CFMutableDictionaryRef exception_dictionary
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
,
2170 &kCFTypeDictionaryValueCallBacks
);
2171 if (!exception_dictionary
) { status
= errSecAllocate
; goto out
; }
2172 if ((options
& kSecTrustOptionAllowExpired
) != 0) {
2173 CFDictionaryAddValue(exception_dictionary
, kSecPolicyCheckTemporalValidity
, kCFBooleanFalse
);
2175 if ((options
& kSecTrustOptionAllowExpiredRoot
) != 0) {
2176 CFDictionaryAddValue(exception_dictionary
, kSecPolicyCheckValidRoot
, kCFBooleanFalse
);
2178 if ((options
& kSecTrustOptionImplicitAnchors
) != 0) {
2179 CFDictionaryAddValue(exception_dictionary
, kSecPolicyCheckAnchorTrusted
, kCFBooleanFalse
);
2181 CFArrayAppendValue(exceptions
, exception_dictionary
);
2182 CFReleaseNull(exception_dictionary
);
2185 /* Set exceptions */
2186 dispatch_sync(trustRef
->_trustQueue
, ^{
2187 CFReleaseSafe(trustRef
->_exceptions
);
2188 trustRef
->_exceptions
= CFRetainSafe(exceptions
);
2190 /* We changed the exceptions -- so we need to re-evaluate */
2191 SecTrustSetNeedsEvaluation(trustRef
);
2194 CFReleaseNull(exceptions
);
2199 CFArrayRef
SecTrustCopySummaryPropertiesAtIndex(SecTrustRef trust
, CFIndex ix
) {
2200 CFMutableArrayRef summary
;
2201 SecCertificateRef certificate
= SecTrustGetCertificateAtIndex(trust
, ix
);
2202 summary
= SecCertificateCopySummaryProperties(certificate
,
2203 SecTrustGetVerifyTime(trust
));
2204 /* FIXME Add more details in the failure case. */
2209 CFArrayRef
SecTrustCopyDetailedPropertiesAtIndex(SecTrustRef trust
, CFIndex ix
) {
2211 SecCertificateRef certificate
= SecTrustGetCertificateAtIndex(trust
, ix
);
2212 summary
= SecCertificateCopyProperties(certificate
);
2217 struct TrustFailures
{
2219 bool unknownCritExtn
;
2220 bool untrustedAnchor
;
2221 bool missingIntermediate
;
2222 bool hostnameMismatch
;
2230 static void applyDetailProperty(const void *_key
, const void *_value
,
2232 CFStringRef key
= (CFStringRef
)_key
;
2233 struct TrustFailures
*tf
= (struct TrustFailures
*)context
;
2234 if (CFGetTypeID(_value
) != CFBooleanGetTypeID()) {
2235 /* Value isn't a CFBooleanRef, oh no! */
2238 CFBooleanRef value
= (CFBooleanRef
)_value
;
2239 if (CFBooleanGetValue(value
)) {
2240 /* Not an actual failure so we don't report it. */
2244 /* @@@ FIXME: Report a different return value when something is in the
2245 details but masked out by an exception and use that below for display
2247 if (CFEqual(key
, kSecPolicyCheckIdLinkage
)) {
2248 tf
->badLinkage
= true;
2249 } else if (CFEqual(key
, kSecPolicyCheckCriticalExtensions
)) {
2250 tf
->unknownCritExtn
= true;
2251 } else if (CFEqual(key
, kSecPolicyCheckAnchorTrusted
)
2252 || CFEqual(key
, kSecPolicyCheckAnchorSHA1
)
2253 || CFEqual(key
, kSecPolicyCheckAnchorSHA256
)
2254 || CFEqual(key
, kSecPolicyCheckAnchorApple
)) {
2255 tf
->untrustedAnchor
= true;
2256 } else if (CFEqual(key
, kSecPolicyCheckMissingIntermediate
)) {
2257 tf
->missingIntermediate
= true;
2258 } else if (CFEqual(key
, kSecPolicyCheckSSLHostname
)) {
2259 tf
->hostnameMismatch
= true;
2260 } else if (CFEqual(key
, kSecPolicyCheckTemporalValidity
)) {
2261 tf
->invalidCert
= true;
2262 } else if (CFEqual(key
, kSecPolicyCheckWeakKeySize
)
2263 || CFEqualSafe(key
, kSecPolicyCheckKeySize
)
2264 || CFEqualSafe(key
, kSecPolicyCheckSystemTrustedWeakKey
)) {
2266 } else if (CFEqual(key
, kSecPolicyCheckWeakSignature
)
2267 || CFEqualSafe(key
, kSecPolicyCheckSignatureHashAlgorithms
)
2268 || CFEqualSafe(key
, kSecPolicyCheckSystemTrustedWeakHash
)) {
2269 tf
->weakHash
= true;
2270 } else if (CFEqual(key
, kSecPolicyCheckRevocation
)) {
2271 tf
->revocation
= true;
2273 /* Anything else is a policy failure. */
2274 tf
->policyFail
= true;
2278 static void appendError(CFMutableArrayRef properties
, CFStringRef error
, bool localized
) {
2279 CFStringRef localizedError
= NULL
;
2282 } else if (localized
) {
2283 //%%% "SecCertificate" should be changed to "Certificate": rdar://37517120
2284 localizedError
= SecFrameworkCopyLocalizedString(error
, CFSTR("SecCertificate"));
2286 localizedError
= (CFStringRef
) CFRetainSafe(error
);
2288 appendProperty(properties
, kSecPropertyTypeError
, NULL
, NULL
,
2289 localizedError
, localized
);
2290 CFReleaseNull(localizedError
);
2294 /* OS X properties array has a different structure and is implemented SecTrust.cpp. */
2295 CFArrayRef
SecTrustCopyProperties_ios(SecTrustRef trust
)
2297 CFArrayRef
SecTrustCopyProperties(SecTrustRef trust
)
2303 SecTrustEvaluateIfNecessary(trust
);
2304 bool localized
= true;
2305 __block CFArrayRef details
= NULL
;
2306 dispatch_sync(trust
->_trustQueue
, ^{
2307 details
= CFRetainSafe(trust
->_details
);
2313 struct TrustFailures tf
= {};
2315 CFIndex ix
, count
= CFArrayGetCount(details
);
2316 for (ix
= 0; ix
< count
; ++ix
) {
2317 CFDictionaryRef detail
= (CFDictionaryRef
)
2318 CFArrayGetValueAtIndex(details
, ix
);
2319 /* We now have a detail dictionary for certificate at index ix, with
2320 a key value pair for each failed policy check. Let's convert it
2321 from Ro-Man form into something a Hu-Man can understand. */
2322 CFDictionaryApplyFunction(detail
, applyDetailProperty
, &tf
);
2325 CFMutableArrayRef properties
= CFArrayCreateMutable(kCFAllocatorDefault
, 0,
2326 &kCFTypeArrayCallBacks
);
2327 /* The badLinkage and unknownCritExtn failures are short circuited, since
2328 you can't recover from those errors. */
2329 if (tf
.badLinkage
) {
2330 appendError(properties
, CFSTR("Invalid certificate chain linkage."), localized
);
2331 } else if (tf
.unknownCritExtn
) {
2332 appendError(properties
, CFSTR("One or more unsupported critical extensions found."), localized
);
2334 if (tf
.untrustedAnchor
) {
2335 appendError(properties
, CFSTR("Root certificate is not trusted."), localized
);
2337 if (tf
.missingIntermediate
) {
2338 appendError(properties
, CFSTR("Unable to build chain to root certificate."), localized
);
2340 if (tf
.hostnameMismatch
) {
2341 appendError(properties
, CFSTR("Hostname mismatch."), localized
);
2343 if (tf
.policyFail
) {
2344 appendError(properties
, CFSTR("Policy requirements not met."), localized
);
2346 if (tf
.invalidCert
) {
2347 appendError(properties
, CFSTR("One or more certificates have expired or are not valid yet."), localized
);
2350 appendError(properties
, CFSTR("One or more certificates is using a weak key size."), localized
);
2353 appendError(properties
, CFSTR("One or more certificates is using a weak signature algorithm."), localized
);
2355 if (tf
.revocation
) {
2356 appendError(properties
, CFSTR("One or more certificates have been revoked."), localized
);
2360 if (CFArrayGetCount(properties
) == 0) {
2361 /* The certificate chain is trusted, return an empty plist */
2362 CFReleaseNull(properties
);
2365 CFReleaseNull(details
);
2370 static void _AppendStatusCode(CFMutableArrayRef array
, OSStatus statusCode
) {
2374 SInt32 num
= statusCode
;
2375 CFNumberRef numRef
= CFNumberCreate(NULL
, kCFNumberSInt32Type
, &num
);
2379 CFArrayAppendValue(array
, numRef
);
2384 static CFArrayRef
_SecTrustCopyDetails(SecTrustRef trust
) {
2388 __block CFArrayRef details
= NULL
;
2389 dispatch_sync(trust
->_trustQueue
, ^{
2390 details
= CFRetainSafe(trust
->_details
);
2393 // Include status codes in the per-certificate details (rdar://27930542)
2394 CFMutableArrayRef newDetails
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
2396 CFReleaseSafe(details
);
2399 CFIndex index
, chainLen
= (details
) ? CFArrayGetCount(details
) : 0;
2400 for (index
= 0; index
< chainLen
; index
++) {
2401 CFDictionaryRef detailDict
= CFArrayGetValueAtIndex(details
, index
);
2402 CFMutableDictionaryRef newDict
= CFDictionaryCreateMutableCopy(NULL
, 0, detailDict
);
2403 CFMutableArrayRef statusCodes
= CFArrayCreateMutable(kCFAllocatorDefault
,
2404 0, &kCFTypeArrayCallBacks
);
2406 CFIndex i
, numCodes
= 0;
2407 SInt32
*codes
= SecTrustCopyStatusCodes(trust
, index
, &numCodes
);
2409 for (i
= 0; i
< numCodes
; i
++) {
2410 OSStatus scode
= (OSStatus
)codes
[i
];
2411 _AppendStatusCode(statusCodes
, scode
);
2415 if (CFArrayGetCount(statusCodes
) > 0) {
2416 CFDictionarySetValue(newDict
, kSecCertificateDetailStatusCodes
, statusCodes
);
2418 CFRelease(statusCodes
);
2421 CFArrayAppendValue(newDetails
, newDict
);
2425 CFReleaseSafe(details
);
2432 CFDictionaryRef
SecTrustCopyResult(SecTrustRef trust
) {
2433 // Builds and returns a dictionary of evaluation results.
2437 __block CFMutableDictionaryRef results
= CFDictionaryCreateMutable(NULL
, 0,
2438 &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
2440 SecTrustEvaluateIfNecessary(trust
);
2441 __block CFArrayRef details
= _SecTrustCopyDetails(trust
);
2443 dispatch_sync(trust
->_trustQueue
, ^{
2444 // kSecTrustResultDetails (per-cert results)
2446 CFDictionarySetValue(results
, (const void *)kSecTrustResultDetails
, (const void *)details
);
2450 // kSecTrustResultValue (overall trust result)
2451 CFNumberRef numValue
= CFNumberCreate(NULL
, kCFNumberSInt32Type
, &trust
->_trustResult
);
2453 CFDictionarySetValue(results
, (const void *)kSecTrustResultValue
, (const void *)numValue
);
2454 CFRelease(numValue
);
2456 CFDictionaryRef info
= trust
->_info
;
2457 if (trust
->_trustResult
== kSecTrustResultInvalid
|| !info
) {
2458 return; // we have nothing more to add
2461 // kSecTrustEvaluationDate
2462 CFDateRef evaluationDate
= trust
->_verifyDate
;
2463 if (evaluationDate
) {
2464 CFDictionarySetValue(results
, (const void *)kSecTrustEvaluationDate
, (const void *)evaluationDate
);
2467 // kSecTrustCertificateTransparency
2468 CFBooleanRef ctValue
;
2469 if (CFDictionaryGetValueIfPresent(info
, kSecTrustInfoCertificateTransparencyKey
, (const void **)&ctValue
)) {
2470 CFDictionarySetValue(results
, (const void *)kSecTrustCertificateTransparency
, (const void *)ctValue
);
2473 // kSecTrustExtendedValidation
2474 CFBooleanRef evValue
;
2475 if (CFDictionaryGetValueIfPresent(info
, kSecTrustInfoExtendedValidationKey
, (const void **)&evValue
)) {
2476 CFDictionarySetValue(results
, (const void *)kSecTrustExtendedValidation
, (const void *)evValue
);
2479 // kSecTrustOrganizationName
2480 CFStringRef organizationName
;
2481 if (CFDictionaryGetValueIfPresent(info
, kSecTrustInfoCompanyNameKey
, (const void **)&organizationName
)) {
2482 CFDictionarySetValue(results
, (const void *)kSecTrustOrganizationName
, (const void *)organizationName
);
2485 // kSecTrustRevocationChecked
2486 CFBooleanRef revocationChecked
;
2487 if (CFDictionaryGetValueIfPresent(info
, kSecTrustRevocationChecked
, (const void **)&revocationChecked
)) {
2488 CFDictionarySetValue(results
, (const void *)kSecTrustRevocationChecked
, (const void *)revocationChecked
);
2491 // kSecTrustRevocationReason
2492 CFNumberRef revocationReason
;
2493 if (CFDictionaryGetValueIfPresent(info
, kSecTrustRevocationReason
, (const void **)&revocationReason
)) {
2494 CFDictionarySetValue(results
, (const void *)kSecTrustRevocationReason
, (const void *)revocationReason
);
2497 // kSecTrustRevocationValidUntilDate
2498 CFDateRef validUntilDate
;
2499 if (CFDictionaryGetValueIfPresent(info
, kSecTrustRevocationValidUntilDate
, (const void **)&validUntilDate
)) {
2500 CFDictionarySetValue(results
, (const void *)kSecTrustRevocationValidUntilDate
, (const void *)validUntilDate
);
2507 #define do_if_registered(sdp, ...) if (gTrustd && gTrustd->sdp) { return gTrustd->sdp(__VA_ARGS__); }
2509 static bool xpc_dictionary_entry_is_type(xpc_object_t dictionary
, const char *key
, xpc_type_t type
) {
2510 xpc_object_t value
= xpc_dictionary_get_value(dictionary
, key
);
2511 return value
&& (xpc_get_type(value
) == type
);
2514 static uint64_t do_ota_pki_op (enum SecXPCOperation op
, CFErrorRef
*error
) {
2516 xpc_object_t message
= securityd_create_message(op
, error
);
2518 xpc_object_t response
= securityd_message_with_reply_sync(message
, error
);
2519 if (response
&& xpc_dictionary_entry_is_type(response
, kSecXPCKeyResult
, XPC_TYPE_UINT64
)) {
2520 num
= (int64_t) xpc_dictionary_get_uint64(response
, kSecXPCKeyResult
);
2522 if (response
&& error
&& xpc_dictionary_entry_is_type(response
, kSecXPCKeyError
, XPC_TYPE_DICTIONARY
)) {
2523 xpc_object_t xpc_error
= xpc_dictionary_get_value(response
, kSecXPCKeyError
);
2525 *error
= SecCreateCFErrorWithXPCObject(xpc_error
);
2528 xpc_release_safe(message
);
2529 xpc_release_safe(response
);
2534 // version 0 -> error, so we need to start at version 1 or later.
2535 uint64_t SecTrustGetTrustStoreVersionNumber(CFErrorRef
*error
) {
2536 do_if_registered(sec_ota_pki_trust_store_version
, error
);
2538 os_activity_t activity
= os_activity_create("SecTrustGetTrustStoreVersionNumber", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_DEFAULT
);
2539 os_activity_scope(activity
);
2541 uint64_t num
= do_ota_pki_op(sec_ota_pki_trust_store_version_id
, error
);
2543 os_release(activity
);
2547 uint64_t SecTrustGetAssetVersionNumber(CFErrorRef
*error
) {
2548 do_if_registered(sec_ota_pki_asset_version
, error
);
2550 os_activity_t activity
= os_activity_create("SecTrustGetAssetVersionNumber", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_DEFAULT
);
2551 os_activity_scope(activity
);
2553 uint64_t num
= do_ota_pki_op(sec_ota_pki_asset_version_id
, error
);
2555 os_release(activity
);
2559 uint64_t SecTrustOTAPKIGetUpdatedAsset(CFErrorRef
*error
) {
2560 do_if_registered(sec_ota_pki_get_new_asset
, error
);
2562 os_activity_t activity
= os_activity_create("SecTrustOTAPKIGetUpdatedAsset", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_DEFAULT
);
2563 os_activity_scope(activity
);
2565 uint64_t num
= do_ota_pki_op(kSecXPCOpOTAPKIGetNewAsset
, error
);
2567 os_release(activity
);
2571 uint64_t SecTrustOTASecExperimentGetUpdatedAsset(CFErrorRef
*error
) {
2572 do_if_registered(sec_ota_secexperiment_get_new_asset
, error
);
2574 os_activity_t activity
= os_activity_create("SecTrustOTASecExperimentGetUpdatedAsset", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_DEFAULT
);
2575 os_activity_scope(activity
);
2577 uint64_t num
= do_ota_pki_op(kSecXPCOpOTASecExperimentGetNewAsset
, error
);
2579 os_release(activity
);
2583 CFDictionaryRef
SecTrustOTASecExperimentCopyAsset(CFErrorRef
*error
) {
2584 __block CFDictionaryRef result
= NULL
;
2585 do_if_registered(sec_ota_secexperiment_get_asset
, error
);
2587 securityd_send_sync_and_do(kSecXPCOpOTASecExperimentGetAsset
, error
, ^bool(xpc_object_t message
, CFErrorRef
*blockError
) {
2588 // input: set message parameters here
2590 }, ^bool(xpc_object_t response
, CFErrorRef
*blockError
) {
2591 // output: get array from response object
2592 xpc_object_t xpc_dict
= NULL
;
2594 xpc_dict
= xpc_dictionary_get_value(response
, kSecXPCKeyResult
);
2596 if (xpc_dict
&& (xpc_get_type(xpc_dict
) == XPC_TYPE_DICTIONARY
)) {
2597 result
= (CFDictionaryRef
)_CFXPCCreateCFObjectFromXPCObject(xpc_dict
);
2599 return SecError(errSecInternal
, blockError
, CFSTR("Unable to get SecExperiment Assets"));
2601 return result
!= NULL
;
2606 bool SecTrustReportTLSAnalytics(CFStringRef eventName
, xpc_object_t eventAttributes
, CFErrorRef
*error
) {
2607 if (!eventName
|| !eventAttributes
) {
2610 do_if_registered(sec_networking_analytics_report
, eventName
, eventAttributes
, error
);
2612 os_activity_t activity
= os_activity_create("SecTrustReportTLSAnalytics", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_DEFAULT
);
2613 os_activity_scope(activity
);
2615 __block
bool result
= false;
2616 securityd_send_sync_and_do(kSecXPCOpNetworkingAnalyticsReport
, error
, ^bool(xpc_object_t message
, CFErrorRef
*block_error
) {
2617 if (!SecXPCDictionarySetString(message
, kSecTrustEventNameKey
, eventName
, block_error
)) {
2620 xpc_dictionary_set_value(message
, kSecTrustEventAttributesKey
, eventAttributes
);
2622 }, ^bool(xpc_object_t response
, CFErrorRef
*block_error
) {
2623 result
= SecXPCDictionaryGetBool(response
, kSecXPCKeyResult
, block_error
);
2627 os_release(activity
);
2631 bool SecTrustReportNetworkingAnalytics(const char *eventNameString
, xpc_object_t eventAttributes
) {
2632 if (!eventNameString
|| !eventAttributes
) {
2636 CFStringRef eventName
= CFStringCreateWithCString(kCFAllocatorDefault
, eventNameString
, kCFStringEncodingUTF8
);
2638 secerror("CFStringCreateWithCString failed");
2642 CFErrorRef error
= NULL
;
2643 if (gTrustd
&& gTrustd
->sec_networking_analytics_report
) {
2644 bool result
= gTrustd
->sec_networking_analytics_report(eventName
, eventAttributes
, &error
);
2645 if (error
!= NULL
) {
2646 secerror("SecTrustReportNetworkingAnalytics failed with error: %d", (int)CFErrorGetCode(error
));
2648 CFReleaseNull(eventName
);
2649 CFReleaseNull(error
);
2653 os_activity_t activity
= os_activity_create("SecTrustReportNetworkingAnalytics", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_DEFAULT
);
2654 os_activity_scope(activity
);
2656 __block
bool result
= false;
2657 securityd_send_sync_and_do(kSecXPCOpNetworkingAnalyticsReport
, &error
, ^bool(xpc_object_t message
, CFErrorRef
*block_error
) {
2658 if (!SecXPCDictionarySetString(message
, kSecTrustEventNameKey
, eventName
, block_error
)) {
2661 xpc_dictionary_set_value(message
, kSecTrustEventAttributesKey
, eventAttributes
);
2663 }, ^bool(xpc_object_t response
, CFErrorRef
*block_error
) {
2664 result
= SecXPCDictionaryGetBool(response
, kSecXPCKeyResult
, block_error
);
2668 if (error
!= NULL
) {
2669 secerror("SecTrustReportNetworkingAnalytics failed with error: %d", (int)CFErrorGetCode(error
));
2671 CFReleaseNull(error
);
2672 CFReleaseNull(eventName
);
2674 os_release(activity
);
2680 * This function performs an evaluation of the leaf certificate only, and
2681 * does so in the process that called it. Its primary use is in SecItemCopyMatching
2682 * when kSecMatchPolicy is in the dictionary.
2684 OSStatus
SecTrustEvaluateLeafOnly(SecTrustRef trust
, SecTrustResultType
*result
) {
2688 OSStatus status
= errSecSuccess
;
2689 SecTrustResultType trustResult
= kSecTrustResultInvalid
;
2690 if((status
= SecTrustValidateInput(trust
))) {
2694 struct OpaqueSecLeafPVC pvc
;
2695 SecCertificateRef leaf
= SecTrustGetCertificateAtIndex(trust
, 0);
2696 __block CFArrayRef policies
= NULL
;
2697 dispatch_sync(trust
->_trustQueue
, ^{
2698 policies
= CFRetainSafe(trust
->_policies
);
2700 SecLeafPVCInit(&pvc
, leaf
, policies
, SecTrustGetVerifyTime(trust
));
2702 if(!SecLeafPVCLeafChecks(&pvc
)) {
2703 trustResult
= kSecTrustResultRecoverableTrustFailure
;
2705 trustResult
= kSecTrustResultUnspecified
;
2708 /* Set other result context information */
2709 dispatch_sync(trust
->_trustQueue
, ^{
2710 trust
->_trustResult
= trustResult
;
2711 trust
->_details
= CFRetainSafe(pvc
.details
);
2712 trust
->_info
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0,
2713 &kCFTypeDictionaryKeyCallBacks
,
2714 &kCFTypeDictionaryValueCallBacks
);
2715 CFMutableArrayRef leafCert
= CFArrayCreateMutableCopy(NULL
, 1, trust
->_certificates
);
2716 trust
->_chain
= leafCert
;
2719 SecLeafPVCDelete(&pvc
);
2721 /* log to syslog when there is a trust failure */
2722 if (trustResult
!= kSecTrustResultUnspecified
) {
2723 CFStringRef failureDesc
= SecTrustCopyFailureDescription(trust
);
2724 secerror("%@", failureDesc
);
2725 CFRelease(failureDesc
);
2729 *result
= trustResult
;
2732 CFReleaseSafe(policies
);
2736 static void deserializeCert(const void *value
, void *context
) {
2737 CFDataRef certData
= (CFDataRef
)value
;
2738 if (isData(certData
)) {
2739 SecCertificateRef cert
= SecCertificateCreateWithData(NULL
, certData
);
2741 CFArrayAppendValue((CFMutableArrayRef
)context
, cert
);
2747 static CF_RETURNS_RETAINED CFArrayRef
SecCertificateArrayDeserialize(CFArrayRef serializedCertificates
) {
2748 CFMutableArrayRef result
= NULL
;
2749 require_quiet(isArray(serializedCertificates
), errOut
);
2750 CFIndex count
= CFArrayGetCount(serializedCertificates
);
2751 result
= CFArrayCreateMutable(kCFAllocatorDefault
, count
, &kCFTypeArrayCallBacks
);
2752 CFRange all_certs
= { 0, count
};
2753 CFArrayApplyFunction(serializedCertificates
, all_certs
, deserializeCert
, result
);
2758 static void serializeCertificate(const void *value
, void *context
) {
2759 SecCertificateRef cert
= (SecCertificateRef
)value
;
2760 if (cert
&& SecCertificateGetTypeID() == CFGetTypeID(cert
)) {
2761 CFDataRef certData
= SecCertificateCopyData(cert
);
2763 CFArrayAppendValue((CFMutableArrayRef
)context
, certData
);
2764 CFRelease(certData
);
2769 static CF_RETURNS_RETAINED CFArrayRef
SecCertificateArraySerialize(CFArrayRef certificates
) {
2770 CFMutableArrayRef result
= NULL
;
2771 require_quiet(isArray(certificates
), errOut
);
2772 CFIndex count
= CFArrayGetCount(certificates
);
2773 result
= CFArrayCreateMutable(NULL
, count
, &kCFTypeArrayCallBacks
);
2774 CFRange all_certificates
= { 0, count
};
2775 CFArrayApplyFunction(certificates
, all_certificates
, serializeCertificate
, result
);
2780 static CFPropertyListRef
SecTrustCopyPlist(SecTrustRef trust
) {
2781 __block CFMutableDictionaryRef output
= NULL
;
2782 output
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
,
2783 &kCFTypeDictionaryValueCallBacks
);
2785 dispatch_sync(trust
->_trustQueue
, ^{
2786 if (trust
->_certificates
) {
2787 CFArrayRef serializedCerts
= SecCertificateArraySerialize(trust
->_certificates
);
2788 if (serializedCerts
) {
2789 CFDictionaryAddValue(output
, CFSTR(kSecTrustCertificatesKey
), serializedCerts
);
2790 CFRelease(serializedCerts
);
2793 if (trust
->_anchors
) {
2794 CFArrayRef serializedAnchors
= SecCertificateArraySerialize(trust
->_anchors
);
2795 if (serializedAnchors
) {
2796 CFDictionaryAddValue(output
, CFSTR(kSecTrustAnchorsKey
), serializedAnchors
);
2797 CFRelease(serializedAnchors
);
2800 if (trust
->_policies
) {
2801 CFArrayRef serializedPolicies
= SecPolicyArrayCreateSerialized(trust
->_policies
);
2802 if (serializedPolicies
) {
2803 CFDictionaryAddValue(output
, CFSTR(kSecTrustPoliciesKey
), serializedPolicies
);
2804 CFRelease(serializedPolicies
);
2807 if (trust
->_responses
) {
2808 CFDictionaryAddValue(output
, CFSTR(kSecTrustResponsesKey
), trust
->_responses
);
2811 CFDictionaryAddValue(output
, CFSTR(kSecTrustSCTsKey
), trust
->_SCTs
);
2813 if (trust
->_trustedLogs
) {
2814 CFDictionaryAddValue(output
, CFSTR(kSecTrustTrustedLogsKey
), trust
->_trustedLogs
);
2816 if (trust
->_verifyDate
) {
2817 CFDictionaryAddValue(output
, CFSTR(kSecTrustVerifyDateKey
), trust
->_verifyDate
);
2819 if (trust
->_chain
) {
2820 CFArrayRef serializedCerts
= SecCertificateArraySerialize(trust
->_chain
);
2821 if (serializedCerts
) {
2822 CFDictionaryAddValue(output
, CFSTR(kSecTrustChainKey
), serializedCerts
);
2823 CFRelease(serializedCerts
);
2826 if (trust
->_details
) {
2827 CFDictionaryAddValue(output
, CFSTR(kSecTrustDetailsKey
), trust
->_details
);
2830 CFDictionaryAddValue(output
, CFSTR(kSecTrustInfoKey
), trust
->_info
);
2832 if (trust
->_exceptions
) {
2833 CFDictionaryAddValue(output
, CFSTR(kSecTrustExceptionsKey
), trust
->_exceptions
);
2835 CFNumberRef trustResult
= CFNumberCreate(NULL
, kCFNumberSInt32Type
, &trust
->_trustResult
);
2837 CFDictionaryAddValue(output
, CFSTR(kSecTrustResultKey
), trustResult
);
2839 CFReleaseNull(trustResult
);
2840 if (trust
->_anchorsOnly
) {
2841 CFDictionaryAddValue(output
, CFSTR(kSecTrustAnchorsOnlyKey
), kCFBooleanTrue
);
2843 CFDictionaryAddValue(output
, CFSTR(kSecTrustAnchorsOnlyKey
), kCFBooleanFalse
);
2845 if (trust
->_keychainsAllowed
) {
2846 CFDictionaryAddValue(output
, CFSTR(kSecTrustKeychainsAllowedKey
), kCFBooleanTrue
);
2848 CFDictionaryAddValue(output
, CFSTR(kSecTrustKeychainsAllowedKey
), kCFBooleanFalse
);
2855 CFDataRef
SecTrustSerialize(SecTrustRef trust
, CFErrorRef
*error
) {
2856 CFPropertyListRef plist
= NULL
;
2857 CFDataRef derTrust
= NULL
;
2858 require_action_quiet(trust
, out
,
2859 SecError(errSecParam
, error
, CFSTR("null trust input")));
2860 require_action_quiet(plist
= SecTrustCopyPlist(trust
), out
,
2861 SecError(errSecDecode
, error
, CFSTR("unable to create trust plist")));
2862 require_quiet(derTrust
= CFPropertyListCreateDERData(NULL
, plist
, error
), out
);
2865 CFReleaseNull(plist
);
2869 static OSStatus
SecTrustCreateFromPlist(CFPropertyListRef plist
, SecTrustRef CF_RETURNS_RETAINED
*trust
) {
2870 OSStatus status
= errSecParam
;
2871 SecTrustRef output
= NULL
;
2872 CFTypeRef serializedCertificates
= NULL
, serializedPolicies
= NULL
, serializedAnchors
= NULL
;
2873 CFNumberRef trustResultNum
= NULL
;
2874 CFArrayRef certificates
= NULL
, policies
= NULL
, anchors
= NULL
, responses
= NULL
,
2875 SCTs
= NULL
, trustedLogs
= NULL
, details
= NULL
, exceptions
= NULL
, chain
= NULL
;
2876 CFDateRef verifyDate
= NULL
;
2877 CFDictionaryRef info
= NULL
;
2879 require_quiet(CFDictionaryGetTypeID() == CFGetTypeID(plist
), out
);
2880 require_quiet(serializedCertificates
= CFDictionaryGetValue(plist
, CFSTR(kSecTrustCertificatesKey
)), out
);
2881 require_quiet(certificates
= SecCertificateArrayDeserialize(serializedCertificates
), out
);
2882 require_quiet(serializedPolicies
= CFDictionaryGetValue(plist
, CFSTR(kSecTrustPoliciesKey
)), out
);
2883 require_quiet(policies
= SecPolicyArrayCreateDeserialized(serializedPolicies
), out
);
2884 require_noerr_quiet(status
= SecTrustCreateWithCertificates(certificates
, policies
, &output
), out
);
2886 serializedAnchors
= CFDictionaryGetValue(plist
, CFSTR(kSecTrustAnchorsKey
));
2887 if (isArray(serializedAnchors
)) {
2888 anchors
= SecCertificateArrayDeserialize(serializedAnchors
);
2889 output
->_anchors
= anchors
;
2891 responses
= CFDictionaryGetValue(plist
, CFSTR(kSecTrustResponsesKey
));
2892 if (isArray(responses
)) {
2893 output
->_responses
= CFRetainSafe(responses
);
2895 SCTs
= CFDictionaryGetValue(plist
, CFSTR(kSecTrustSCTsKey
));
2896 if (isArray(SCTs
)) {
2897 output
->_SCTs
= CFRetainSafe(SCTs
);
2899 trustedLogs
= CFDictionaryGetValue(plist
, CFSTR(kSecTrustTrustedLogsKey
));
2900 if (isArray(trustedLogs
)) {
2901 output
->_trustedLogs
= CFRetainSafe(trustedLogs
);
2903 verifyDate
= CFDictionaryGetValue(plist
, CFSTR(kSecTrustVerifyDateKey
));
2904 if (isDate(verifyDate
)) {
2905 output
->_verifyDate
= CFRetainSafe(verifyDate
);
2907 chain
= CFDictionaryGetValue(plist
, CFSTR(kSecTrustChainKey
));
2908 if (isArray(chain
)) {
2909 output
->_chain
= SecCertificateArrayDeserialize(chain
);
2911 details
= CFDictionaryGetValue(plist
, CFSTR(kSecTrustDetailsKey
));
2912 if (isArray(details
)) {
2913 output
->_details
= CFRetainSafe(details
);
2915 info
= CFDictionaryGetValue(plist
, CFSTR(kSecTrustInfoKey
));
2916 if (isDictionary(info
)) {
2917 output
->_info
= CFRetainSafe(info
);
2919 exceptions
= CFDictionaryGetValue(plist
, CFSTR(kSecTrustExceptionsKey
));
2920 if (isArray(exceptions
)) {
2921 output
->_exceptions
= CFRetainSafe(exceptions
);
2923 int32_t trustResult
= -1;
2924 trustResultNum
= CFDictionaryGetValue(plist
, CFSTR(kSecTrustResultKey
));
2925 if (isNumber(trustResultNum
) && CFNumberGetValue(trustResultNum
, kCFNumberSInt32Type
, &trustResult
) &&
2926 (trustResult
>= 0)) {
2927 output
->_trustResult
= trustResult
;
2929 status
= errSecParam
;
2931 if (CFDictionaryGetValue(plist
, CFSTR(kSecTrustAnchorsOnlyKey
)) == kCFBooleanTrue
) {
2932 output
->_anchorsOnly
= true;
2933 } /* false is set by default */
2934 if (CFDictionaryGetValue(plist
, CFSTR(kSecTrustKeychainsAllowedKey
)) == kCFBooleanFalse
) {
2935 output
->_keychainsAllowed
= false;
2936 } /* true is set by default */
2939 if (errSecSuccess
== status
&& trust
) {
2942 CFReleaseNull(policies
);
2943 CFReleaseNull(certificates
);
2947 SecTrustRef
SecTrustDeserialize(CFDataRef serializedTrust
, CFErrorRef
*error
) {
2948 SecTrustRef trust
= NULL
;
2949 CFPropertyListRef plist
= NULL
;
2950 OSStatus status
= errSecSuccess
;
2951 require_action_quiet(serializedTrust
, out
,
2952 SecError(errSecParam
, error
, CFSTR("null serialized trust input")));
2953 require_quiet(plist
= CFPropertyListCreateWithDERData(NULL
, serializedTrust
,
2954 kCFPropertyListImmutable
, NULL
, error
), out
);
2955 require_noerr_action_quiet(status
= SecTrustCreateFromPlist(plist
, &trust
), out
,
2956 SecError(status
, error
, CFSTR("unable to create trust ref")));
2959 CFReleaseNull(plist
);
2963 #if TARGET_OS_IPHONE
2964 static uint64_t to_uint_error_request(enum SecXPCOperation op
, CFErrorRef
*error
) {
2965 __block
uint64_t result
= 0;
2967 securityd_send_sync_and_do(op
, error
, NULL
, ^bool(xpc_object_t response
, CFErrorRef
*localError
) {
2968 uint64_t temp_result
= xpc_dictionary_get_uint64(response
, kSecXPCKeyResult
);
2969 /* plists do not support unsigned integers. */
2970 if (temp_result
<= INT64_MAX
) {
2971 result
= temp_result
;
2973 secerror("Invalid exceptions epoch.");
2975 *error
= CFErrorCreate(NULL
, kCFErrorDomainPOSIX
, ERANGE
, NULL
);
2978 if (error
&& localError
&& *localError
) {
2979 *error
= *localError
;
2987 uint64_t SecTrustGetExceptionResetCount(CFErrorRef
*error
) {
2988 os_activity_t activity
= os_activity_create("SecTrustExceptionGetResetCount", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_DEFAULT
);
2989 os_activity_scope(activity
);
2990 uint64_t exceptionResetCount
= TRUSTD_XPC(sec_trust_get_exception_reset_count
, to_uint_error_request
, error
);
2991 os_release(activity
);
2992 if (error
&& *error
) {
2993 secerror("Failed to get the exceptions epoch.");
2995 secinfo("trust", "The exceptions epoch is %lld.", exceptionResetCount
);
2997 return exceptionResetCount
;
3000 OSStatus
SecTrustIncrementExceptionResetCount(CFErrorRef
*error
) {
3001 OSStatus status
= errSecInternal
;
3003 os_activity_t activity
= os_activity_create("SecTrustIncrementExceptionResetCount", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_DEFAULT
);
3004 os_activity_scope(activity
);
3005 bool success
= TRUSTD_XPC(sec_trust_increment_exception_reset_count
, to_bool_error_request
, error
);
3006 os_release(activity
);
3007 if ((error
&& *error
) || !success
) {
3008 secerror("Failed to increment the exceptions epoch.");
3011 status
= errSecSuccess
;