2 * Copyright (c) 2006-2016 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/SecItemPriv.h>
30 #include <Security/SecCertificateInternal.h>
31 #include <Security/SecCertificatePath.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 <CoreFoundation/CFRuntime.h>
40 #include <CoreFoundation/CFSet.h>
41 #include <CoreFoundation/CFString.h>
42 #include <CoreFoundation/CFNumber.h>
43 #include <CoreFoundation/CFArray.h>
44 #include <CoreFoundation/CFPropertyList.h>
45 #include <AssertMacros.h>
51 #include <os/activity.h>
53 #include <utilities/SecIOFormat.h>
54 #include <utilities/SecCFError.h>
55 #include <utilities/SecCFWrappers.h>
56 #include <utilities/SecCertificateTrace.h>
57 #include <utilities/debugging.h>
58 #include <utilities/der_plist.h>
59 #include <utilities/SecDispatchRelease.h>
61 #include "SecRSAKey.h"
62 #include <libDER/oids.h>
64 #include <ipc/securityd_client.h>
66 #include <securityd/SecTrustServer.h>
68 #define SEC_CONST_DECL(k,v) const CFStringRef k = CFSTR(v);
70 SEC_CONST_DECL (kSecTrustInfoExtendedValidationKey
, "ExtendedValidation");
71 SEC_CONST_DECL (kSecTrustInfoCompanyNameKey
, "CompanyName");
72 SEC_CONST_DECL (kSecTrustInfoRevocationKey
, "Revocation");
73 SEC_CONST_DECL (kSecTrustInfoRevocationValidUntilKey
, "RevocationValidUntil");
74 SEC_CONST_DECL (kSecTrustInfoCertificateTransparencyKey
, "CertificateTransparency");
75 SEC_CONST_DECL (kSecTrustInfoCertificateTransparencyWhiteListKey
, "CertificateTransparencyWhiteList");
77 /* Public trust result constants */
78 SEC_CONST_DECL (kSecTrustEvaluationDate
, "TrustEvaluationDate");
79 SEC_CONST_DECL (kSecTrustExtendedValidation
, "TrustExtendedValidation");
80 SEC_CONST_DECL (kSecTrustOrganizationName
, "Organization");
81 SEC_CONST_DECL (kSecTrustResultValue
, "TrustResultValue");
82 SEC_CONST_DECL (kSecTrustRevocationChecked
, "TrustRevocationChecked");
83 SEC_CONST_DECL (kSecTrustRevocationReason
, "TrustRevocationReason");
84 SEC_CONST_DECL (kSecTrustRevocationValidUntilDate
, "TrustExpirationDate");
85 SEC_CONST_DECL (kSecTrustResultDetails
, "TrustResultDetails");
86 SEC_CONST_DECL (kSecTrustCertificateTransparency
, "TrustCertificateTransparency");
87 SEC_CONST_DECL (kSecTrustCertificateTransparencyWhiteList
, "TrustCertificateTransparencyWhiteList");
92 /********************************************************
93 ****************** SecTrust object *********************
94 ********************************************************/
97 CFArrayRef _certificates
;
100 CFArrayRef _responses
;
102 CFArrayRef _trustedLogs
;
103 CFDateRef _verifyDate
;
104 SecCertificatePathRef _chain
;
105 SecKeyRef _publicKey
;
107 CFDictionaryRef _info
;
108 CFArrayRef _exceptions
;
110 /* Note that a value of kSecTrustResultInvalid (0)
111 * indicates the trust must be (re)evaluated; any
112 * functions which modify trust parameters in a way
113 * that would invalidate the current result must set
114 * this value back to kSecTrustResultInvalid.
116 SecTrustResultType _trustResult
;
118 /* If true we don't trust any anchors other than the ones in _anchors. */
120 /* If false we shouldn't search keychains for parents or anchors. */
121 bool _keychainsAllowed
;
123 /* Data blobs for legacy CSSM_TP_APPLE_EVIDENCE_INFO structure,
124 * to support callers of SecTrustGetResult on OS X. Since fields of
125 * one structure contain pointers into the other, these cannot be
126 * serialized; if a SecTrust is being serialized or copied, these values
127 * should just be initialized to NULL in the copy and built when needed. */
128 void* _legacy_info_array
;
129 void* _legacy_status_array
;
131 /* The trust result as determined by the trust server,
132 * before the caller's exceptions are applied.
134 SecTrustResultType _trustResultBeforeExceptions
;
136 /* Dispatch queue for thread-safety */
137 dispatch_queue_t _trustQueue
;
139 /* === IMPORTANT! ===
140 * Any change to this structure definition
141 * must also be made in the TSecTrust structure,
142 * located in SecTrust.cpp. To avoid problems,
143 * new fields should always be appended at the
144 * end of the structure.
148 /* Forward declarations of static functions. */
149 static OSStatus
SecTrustEvaluateIfNecessary(SecTrustRef trust
);
151 /* Static functions. */
152 static CFStringRef
SecTrustCopyFormatDescription(CFTypeRef cf
, CFDictionaryRef formatOptions
) {
153 SecTrustRef trust
= (SecTrustRef
)cf
;
154 return CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
,
155 CFSTR("<SecTrustRef: %p>"), trust
);
158 static void SecTrustDestroy(CFTypeRef cf
) {
159 SecTrustRef trust
= (SecTrustRef
)cf
;
161 dispatch_release_null(trust
->_trustQueue
);
162 CFReleaseNull(trust
->_certificates
);
163 CFReleaseNull(trust
->_policies
);
164 CFReleaseNull(trust
->_responses
);
165 CFReleaseNull(trust
->_SCTs
);
166 CFReleaseNull(trust
->_trustedLogs
);
167 CFReleaseNull(trust
->_verifyDate
);
168 CFReleaseNull(trust
->_anchors
);
169 CFReleaseNull(trust
->_chain
);
170 CFReleaseNull(trust
->_publicKey
);
171 CFReleaseNull(trust
->_details
);
172 CFReleaseNull(trust
->_info
);
173 CFReleaseNull(trust
->_exceptions
);
175 if (trust
->_legacy_info_array
) {
176 free(trust
->_legacy_info_array
);
178 if (trust
->_legacy_status_array
) {
179 free(trust
->_legacy_status_array
);
183 /* Public API functions. */
184 CFGiblisFor(SecTrust
)
186 OSStatus
SecTrustCreateWithCertificates(CFTypeRef certificates
,
187 CFTypeRef policies
, SecTrustRef
*trust
) {
188 OSStatus status
= errSecParam
;
189 CFAllocatorRef allocator
= kCFAllocatorDefault
;
190 CFArrayRef l_certs
= NULL
, l_policies
= NULL
;
191 SecTrustRef result
= NULL
;
195 CFTypeID certType
= CFGetTypeID(certificates
);
196 if (certType
== CFArrayGetTypeID()) {
197 /* We need at least 1 certificate. */
198 require_quiet(CFArrayGetCount(certificates
) > 0, errOut
);
199 l_certs
= CFArrayCreateCopy(allocator
, certificates
);
200 } else if (certType
== SecCertificateGetTypeID()) {
201 l_certs
= CFArrayCreate(allocator
, &certificates
, 1,
202 &kCFTypeArrayCallBacks
);
207 status
= errSecAllocate
;
212 CFTypeRef policy
= SecPolicyCreateBasicX509();
213 l_policies
= CFArrayCreate(allocator
, &policy
, 1,
214 &kCFTypeArrayCallBacks
);
217 else if (CFGetTypeID(policies
) == CFArrayGetTypeID()) {
218 l_policies
= CFArrayCreateCopy(allocator
, policies
);
220 else if (CFGetTypeID(policies
) == SecPolicyGetTypeID()) {
221 l_policies
= CFArrayCreate(allocator
, &policies
, 1,
222 &kCFTypeArrayCallBacks
);
227 status
= errSecAllocate
;
231 CFIndex size
= sizeof(struct __SecTrust
);
232 require_quiet(result
= (SecTrustRef
)_CFRuntimeCreateInstance(allocator
,
233 SecTrustGetTypeID(), size
- sizeof(CFRuntimeBase
), 0), errOut
);
234 memset((char*)result
+ sizeof(result
->_base
), 0,
235 sizeof(*result
) - sizeof(result
->_base
));
236 status
= errSecSuccess
;
240 CFReleaseSafe(result
);
241 CFReleaseSafe(l_certs
);
242 CFReleaseSafe(l_policies
);
244 result
->_certificates
= l_certs
;
245 result
->_policies
= l_policies
;
246 result
->_keychainsAllowed
= true;
247 result
->_trustQueue
= dispatch_queue_create("trust", DISPATCH_QUEUE_SERIAL
);
251 CFReleaseSafe(result
);
256 OSStatus
SecTrustCopyInputCertificates(SecTrustRef trust
, CFArrayRef
*certificates
) {
257 if (!trust
|| !certificates
) {
260 __block CFArrayRef certArray
= NULL
;
261 dispatch_sync(trust
->_trustQueue
, ^{
262 certArray
= CFArrayCreateCopy(NULL
, trust
->_certificates
);
265 return errSecAllocate
;
267 *certificates
= certArray
;
268 return errSecSuccess
;
271 OSStatus
SecTrustAddToInputCertificates(SecTrustRef trust
, CFTypeRef certificates
) {
272 if (!trust
|| !certificates
) {
275 __block CFMutableArrayRef newCertificates
= NULL
;
276 dispatch_sync(trust
->_trustQueue
, ^{
277 newCertificates
= CFArrayCreateMutableCopy(NULL
, 0, trust
->_certificates
);
280 if (isArray(certificates
)) {
281 CFArrayAppendArray(newCertificates
, certificates
,
282 CFRangeMake(0, CFArrayGetCount(certificates
)));
283 } else if (CFGetTypeID(certificates
) == SecCertificateGetTypeID()) {
284 CFArrayAppendValue(newCertificates
, certificates
);
286 CFReleaseNull(newCertificates
);
290 dispatch_sync(trust
->_trustQueue
, ^{
291 CFReleaseNull(trust
->_certificates
);
292 trust
->_certificates
= (CFArrayRef
)newCertificates
;
295 return errSecSuccess
;
298 static void SecTrustSetNeedsEvaluation(SecTrustRef trust
) {
301 dispatch_sync(trust
->_trustQueue
, ^{
302 trust
->_trustResult
= kSecTrustResultInvalid
;
303 trust
->_trustResultBeforeExceptions
= kSecTrustResultInvalid
;
308 OSStatus
SecTrustSetAnchorCertificatesOnly(SecTrustRef trust
,
309 Boolean anchorCertificatesOnly
) {
313 SecTrustSetNeedsEvaluation(trust
);
314 trust
->_anchorsOnly
= anchorCertificatesOnly
;
316 return errSecSuccess
;
319 OSStatus
SecTrustSetAnchorCertificates(SecTrustRef trust
,
320 CFArrayRef anchorCertificates
) {
324 SecTrustSetNeedsEvaluation(trust
);
325 if (anchorCertificates
)
326 CFRetain(anchorCertificates
);
327 dispatch_sync(trust
->_trustQueue
, ^{
329 CFRelease(trust
->_anchors
);
330 trust
->_anchors
= anchorCertificates
;
332 trust
->_anchorsOnly
= (anchorCertificates
!= NULL
);
334 return errSecSuccess
;
337 OSStatus
SecTrustCopyCustomAnchorCertificates(SecTrustRef trust
,
338 CFArrayRef
*anchors
) {
339 if (!trust
|| !anchors
) {
342 __block CFArrayRef anchorsArray
= NULL
;
343 dispatch_sync(trust
->_trustQueue
, ^{
344 if (trust
->_anchors
) {
345 anchorsArray
= CFArrayCreateCopy(kCFAllocatorDefault
, trust
->_anchors
);
349 *anchors
= anchorsArray
;
350 return errSecSuccess
;
353 OSStatus
SecTrustSetOCSPResponse(SecTrustRef trust
, CFTypeRef responseData
) {
357 SecTrustSetNeedsEvaluation(trust
);
358 CFArrayRef responseArray
= NULL
;
360 if (CFGetTypeID(responseData
) == CFArrayGetTypeID()) {
361 responseArray
= CFArrayCreateCopy(kCFAllocatorDefault
, responseData
);
362 } else if (CFGetTypeID(responseData
) == CFDataGetTypeID()) {
363 responseArray
= CFArrayCreate(kCFAllocatorDefault
, &responseData
, 1,
364 &kCFTypeArrayCallBacks
);
369 dispatch_sync(trust
->_trustQueue
, ^{
370 if (trust
->_responses
)
371 CFRelease(trust
->_responses
);
372 trust
->_responses
= responseArray
;
374 return errSecSuccess
;
377 OSStatus
SecTrustSetSignedCertificateTimestamps(SecTrustRef trust
, CFArrayRef sctArray
) {
381 SecTrustSetNeedsEvaluation(trust
);
382 dispatch_sync(trust
->_trustQueue
, ^{
383 CFRetainAssign(trust
->_SCTs
, sctArray
);
385 return errSecSuccess
;
388 OSStatus
SecTrustSetTrustedLogs(SecTrustRef trust
, CFArrayRef trustedLogs
) {
392 SecTrustSetNeedsEvaluation(trust
);
393 dispatch_sync(trust
->_trustQueue
, ^{
394 CFRetainAssign(trust
->_trustedLogs
, trustedLogs
);
396 return errSecSuccess
;
399 OSStatus
SecTrustSetVerifyDate(SecTrustRef trust
, CFDateRef verifyDate
) {
403 SecTrustSetNeedsEvaluation(trust
);
405 dispatch_sync(trust
->_trustQueue
, ^{
406 CFRetainAssign(trust
->_verifyDate
, verifyDate
);
408 return errSecSuccess
;
411 OSStatus
SecTrustSetPolicies(SecTrustRef trust
, CFTypeRef newPolicies
) {
412 if (!trust
|| !newPolicies
) {
415 SecTrustSetNeedsEvaluation(trust
);
418 __block CFArrayRef policyArray
= NULL
;
419 if (CFGetTypeID(newPolicies
) == CFArrayGetTypeID()) {
420 policyArray
= CFArrayCreateCopy(kCFAllocatorDefault
, newPolicies
);
421 } else if (CFGetTypeID(newPolicies
) == SecPolicyGetTypeID()) {
422 policyArray
= CFArrayCreate(kCFAllocatorDefault
, &newPolicies
, 1,
423 &kCFTypeArrayCallBacks
);
428 dispatch_sync(trust
->_trustQueue
, ^{
429 CFReleaseSafe(trust
->_policies
);
430 trust
->_policies
= policyArray
;
433 return errSecSuccess
;
436 OSStatus
SecTrustSetKeychainsAllowed(SecTrustRef trust
, Boolean allowed
) {
440 SecTrustSetNeedsEvaluation(trust
);
441 trust
->_keychainsAllowed
= allowed
;
443 return errSecSuccess
;
446 OSStatus
SecTrustGetKeychainsAllowed(SecTrustRef trust
, Boolean
*allowed
) {
447 if (!trust
|| !allowed
) {
450 *allowed
= trust
->_keychainsAllowed
;
452 return errSecSuccess
;
455 OSStatus
SecTrustCopyPolicies(SecTrustRef trust
, CFArrayRef
*policies
) {
456 if (!trust
|| !policies
) {
459 __block CFArrayRef policyArray
= NULL
;
460 dispatch_sync(trust
->_trustQueue
, ^{
461 policyArray
= CFArrayCreateCopy(kCFAllocatorDefault
, trust
->_policies
);
464 return errSecAllocate
;
466 *policies
= policyArray
;
467 return errSecSuccess
;
470 static OSStatus
SecTrustSetOptionInPolicies(CFArrayRef policies
, CFStringRef key
, CFTypeRef value
) {
471 OSStatus status
= errSecSuccess
;
472 require_action(policies
&& CFGetTypeID(policies
) == CFArrayGetTypeID(), out
, status
= errSecInternal
);
473 for (int i
=0; i
< CFArrayGetCount(policies
); i
++) {
474 SecPolicyRef policy
= NULL
;
475 require_action_quiet(policy
= (SecPolicyRef
)CFArrayGetValueAtIndex(policies
, i
), out
, status
= errSecInternal
);
476 CFMutableDictionaryRef options
= NULL
;
477 require_action_quiet(options
= CFDictionaryCreateMutableCopy(NULL
, 0, policy
->_options
), out
, status
= errSecAllocate
);
478 CFDictionaryAddValue(options
, key
, value
);
479 CFReleaseNull(policy
->_options
);
480 policy
->_options
= options
;
486 static OSStatus
SecTrustRemoveOptionInPolicies(CFArrayRef policies
, CFStringRef key
) {
487 OSStatus status
= errSecSuccess
;
488 require_action(policies
&& CFGetTypeID(policies
) == CFArrayGetTypeID(), out
, status
= errSecInternal
);
489 for (int i
=0; i
< CFArrayGetCount(policies
); i
++) {
490 SecPolicyRef policy
= NULL
;
491 require_action_quiet(policy
= (SecPolicyRef
)CFArrayGetValueAtIndex(policies
, i
), out
, status
= errSecInternal
);
492 if (CFDictionaryGetValue(policy
->_options
, key
)) {
493 CFMutableDictionaryRef options
= NULL
;
494 require_action_quiet(options
= CFDictionaryCreateMutableCopy(NULL
, 0, policy
->_options
), out
, status
= errSecAllocate
);
495 CFDictionaryRemoveValue(options
, key
);
496 CFReleaseNull(policy
->_options
);
497 policy
->_options
= options
;
504 static CF_RETURNS_RETAINED CFArrayRef
SecTrustCopyOptionsFromPolicies(CFArrayRef policies
, CFStringRef key
) {
505 CFMutableArrayRef foundValues
= NULL
;
506 foundValues
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
507 for (int i
=0; i
< CFArrayGetCount(policies
); i
++) {
508 SecPolicyRef policy
= (SecPolicyRef
)CFArrayGetValueAtIndex(policies
, i
);
509 CFTypeRef value
= CFDictionaryGetValue(policy
->_options
, key
);
511 CFArrayAppendValue(foundValues
, value
);
514 if (!CFArrayGetCount(foundValues
)) {
515 CFReleaseNull(foundValues
);
523 /* The only effective way to disable network fetch is within the policy options:
524 * presence of the kSecPolicyCheckNoNetworkAccess key in any of the policies
525 * will prevent network access for fetching.
526 * The current SecTrustServer implementation doesn't distinguish between network
527 * access for revocation and network access for fetching.
529 OSStatus
SecTrustSetNetworkFetchAllowed(SecTrustRef trust
, Boolean allowFetch
) {
533 __block OSStatus status
= errSecSuccess
;
534 dispatch_sync(trust
->_trustQueue
, ^{
536 status
= SecTrustSetOptionInPolicies(trust
->_policies
, kSecPolicyCheckNoNetworkAccess
, kCFBooleanTrue
);
538 status
= SecTrustRemoveOptionInPolicies(trust
->_policies
, kSecPolicyCheckNoNetworkAccess
);
544 OSStatus
SecTrustGetNetworkFetchAllowed(SecTrustRef trust
, Boolean
*allowFetch
) {
545 if (!trust
|| !allowFetch
) {
548 __block CFArrayRef foundValues
= NULL
;
549 dispatch_sync(trust
->_trustQueue
, ^{
550 foundValues
= SecTrustCopyOptionsFromPolicies(trust
->_policies
, kSecPolicyCheckNoNetworkAccess
);
557 CFReleaseNull(foundValues
);
558 return errSecSuccess
;
561 CFAbsoluteTime
SecTrustGetVerifyTime(SecTrustRef trust
) {
562 __block CFAbsoluteTime verifyTime
= CFAbsoluteTimeGetCurrent();
566 dispatch_sync(trust
->_trustQueue
, ^{
567 if (trust
->_verifyDate
) {
568 verifyTime
= CFDateGetAbsoluteTime(trust
->_verifyDate
);
570 trust
->_verifyDate
= CFDateCreate(CFGetAllocator(trust
), verifyTime
);
577 CFArrayRef
SecTrustGetDetails(SecTrustRef trust
) {
581 SecTrustEvaluateIfNecessary(trust
);
582 return trust
->_details
;
585 OSStatus
SecTrustGetTrustResult(SecTrustRef trust
,
586 SecTrustResultType
*result
) {
587 if (!trust
|| !result
) {
590 dispatch_sync(trust
->_trustQueue
, ^{
591 *result
= trust
->_trustResult
;
593 return errSecSuccess
;
596 static CFStringRef kSecCertificateDetailSHA1Digest
= CFSTR("SHA1Digest");
598 static CFDictionaryRef
SecTrustGetExceptionForCertificateAtIndex(SecTrustRef trust
, CFIndex ix
) {
599 CFDictionaryRef exception
= NULL
;
600 __block CFArrayRef exceptions
= NULL
;
601 dispatch_sync(trust
->_trustQueue
, ^{
602 exceptions
= CFRetainSafe(trust
->_exceptions
);
604 if (!exceptions
|| ix
>= CFArrayGetCount(exceptions
)) {
608 SecCertificateRef certificate
= SecTrustGetCertificateAtIndex(trust
, ix
);
613 exception
= (CFDictionaryRef
)CFArrayGetValueAtIndex(exceptions
, ix
);
614 if (CFGetTypeID(exception
) != CFDictionaryGetTypeID()) {
619 /* If the exception contains the current certificates sha1Digest in the
620 kSecCertificateDetailSHA1Digest key then we use it otherwise we ignore it. */
621 CFDataRef sha1Digest
= SecCertificateGetSHA1Digest(certificate
);
622 CFTypeRef digestValue
= CFDictionaryGetValue(exception
, kSecCertificateDetailSHA1Digest
);
623 if (!digestValue
|| !CFEqual(sha1Digest
, digestValue
))
627 CFReleaseSafe(exceptions
);
631 struct SecTrustFilteredDetailContext
{
632 CFDictionaryRef exception
;
633 CFMutableDictionaryRef filteredDetail
;
636 static void SecTrustFilterDetail(const void *key
, const void *value
, void *context
) {
637 struct SecTrustFilteredDetailContext
*ctx
= (struct SecTrustFilteredDetailContext
*)context
;
638 if (!key
|| !value
|| !ctx
->exception
|| !ctx
->filteredDetail
) {
641 if (CFEqual(kSecCertificateDetailSHA1Digest
, key
)) {
642 return; /* ignore SHA1 hash entry */
644 CFTypeRef exceptionValue
= CFDictionaryGetValue(ctx
->exception
, key
);
645 if (exceptionValue
&& CFEqual(exceptionValue
, value
)) {
646 /* both key and value match the exception */
647 CFDictionaryRemoveValue(ctx
->filteredDetail
, key
);
651 CFArrayRef
SecTrustCopyFilteredDetails(SecTrustRef trust
) {
655 SecTrustEvaluateIfNecessary(trust
);
656 __block CFArrayRef details
= NULL
;
657 dispatch_sync(trust
->_trustQueue
, ^{
658 details
= CFRetainSafe(trust
->_details
);
660 CFIndex ix
, pathLength
= details
? CFArrayGetCount(details
) : 0;
661 CFMutableArrayRef filteredDetails
= CFArrayCreateMutable(kCFAllocatorDefault
, pathLength
, &kCFTypeArrayCallBacks
);
662 if (!filteredDetails
) {
663 CFReleaseNull(details
);
666 for (ix
= 0; ix
< pathLength
; ++ix
) {
667 CFDictionaryRef detail
= (CFDictionaryRef
)CFArrayGetValueAtIndex(details
, ix
);
668 CFIndex count
= (detail
) ? CFDictionaryGetCount(detail
) : 0;
669 CFMutableDictionaryRef filteredDetail
= CFDictionaryCreateMutableCopy(kCFAllocatorDefault
, count
, detail
);
670 CFDictionaryRef exception
= SecTrustGetExceptionForCertificateAtIndex(trust
, ix
);
672 /* for each entry in the detail dictionary, remove from filteredDetail
673 if it also appears in the corresponding exception dictionary. */
674 struct SecTrustFilteredDetailContext context
= { exception
, filteredDetail
};
675 CFDictionaryApplyFunction(detail
, SecTrustFilterDetail
, &context
);
677 if (filteredDetail
) {
678 CFArrayAppendValue(filteredDetails
, filteredDetail
);
679 CFReleaseSafe(filteredDetail
);
682 CFReleaseNull(details
);
683 return filteredDetails
;
686 struct SecTrustCheckExceptionContext
{
687 CFDictionaryRef exception
;
688 bool exceptionNotFound
;
692 static void SecTrustCheckException(const void *key
, const void *value
, void *context
) {
693 struct SecTrustCheckExceptionContext
*cec
= (struct SecTrustCheckExceptionContext
*)context
;
694 if (cec
->exception
) {
695 CFTypeRef exceptionValue
= CFDictionaryGetValue(cec
->exception
, key
);
696 if (!exceptionValue
|| !CFEqual(value
, exceptionValue
)) {
697 cec
->exceptionNotFound
= true;
700 cec
->exceptionNotFound
= true;
705 static CFArrayRef
SecTrustCreatePolicyAnchorsArray(const UInt8
* certData
, CFIndex certLength
)
707 CFArrayRef array
= NULL
;
708 CFAllocatorRef allocator
= kCFAllocatorDefault
;
709 SecCertificateRef cert
= SecCertificateCreateWithBytes(allocator
, certData
, certLength
);
711 array
= CFArrayCreate(allocator
, (const void **)&cert
, 1, &kCFTypeArrayCallBacks
);
718 static void SecTrustAddPolicyAnchors(SecTrustRef trust
)
720 /* Provide anchor certificates specifically required by certain policies.
721 This is used to evaluate test policies where the anchor is not provided
722 in the root store and may not be able to be supplied by the caller.
724 if (!trust
) { return; }
725 __block CFArrayRef policies
= NULL
;
726 dispatch_sync(trust
->_trustQueue
, ^{
727 policies
= CFRetain(trust
->_policies
);
729 CFIndex ix
, count
= CFArrayGetCount(policies
);
730 for (ix
= 0; ix
< count
; ++ix
) {
731 SecPolicyRef policy
= (SecPolicyRef
) CFArrayGetValueAtIndex(policies
, ix
);
734 if (CFEqual(policy
->_oid
, kSecPolicyAppleTestSMPEncryption
)) {
735 __block CFArrayRef policyAnchors
= SecTrustCreatePolicyAnchorsArray(_SEC_TestAppleRootCAECC
, sizeof(_SEC_TestAppleRootCAECC
));
736 dispatch_sync(trust
->_trustQueue
, ^{
737 CFReleaseSafe(trust
->_anchors
);
738 trust
->_anchors
= policyAnchors
;
740 trust
->_anchorsOnly
= true;
746 CFReleaseSafe(policies
);
750 // uncomment for verbose debug logging (debug builds only)
751 //#define CERT_TRUST_DUMP 1
754 static void sectrustlog(int priority
, const char *format
, ...)
759 if (priority
< LOG_NOTICE
) // log warnings and errors
763 va_start(list
, format
);
764 vsyslog(priority
, format
, list
);
769 static void sectrustshow(CFTypeRef obj
, const char *context
)
772 CFStringRef desc
= CFCopyDescription(obj
);
775 CFIndex length
= CFStringGetMaximumSizeForEncoding(CFStringGetLength(desc
), kCFStringEncodingUTF8
) + 1;
776 char* buffer
= (char*) malloc(length
);
778 Boolean converted
= CFStringGetCString(desc
, buffer
, length
, kCFStringEncodingUTF8
);
780 const char *prefix
= (context
) ? context
: "";
781 const char *separator
= (context
) ? " " : "";
782 sectrustlog(LOG_NOTICE
, "%s%s%s", prefix
, separator
, buffer
);
790 static void cert_trust_dump(SecTrustRef trust
) {
791 SecCertificateRef leaf
= SecTrustGetCertificateAtIndex(trust
, 0);
792 CFStringRef name
= (leaf
) ? SecCertificateCopySubjectSummary(leaf
) : NULL
;
793 secerror("leaf \"%@\"", name
);
794 secerror(": result = %d", (int) trust
->_trustResult
);
796 CFIndex ix
, count
= SecCertificatePathGetCount(trust
->_chain
);
797 CFMutableArrayRef chain
= CFArrayCreateMutable(kCFAllocatorDefault
, count
, &kCFTypeArrayCallBacks
);
798 for (ix
= 0; ix
< count
; ix
++) {
799 SecCertificateRef cert
= SecCertificatePathGetCertificateAtIndex(trust
->_chain
, ix
);
801 CFArrayAppendValue(chain
, cert
);
804 sectrustshow(chain
, "chain:");
805 CFReleaseSafe(chain
);
807 secerror(": %ld certificates, %ld anchors, %ld policies, %ld details",
808 (trust
->_certificates
) ? (long)CFArrayGetCount(trust
->_certificates
) : 0,
809 (trust
->_anchors
) ? (long)CFArrayGetCount(trust
->_anchors
) : 0,
810 (trust
->_policies
) ? (long)CFArrayGetCount(trust
->_policies
) : 0,
811 (trust
->_details
) ? (long)CFArrayGetCount(trust
->_details
) : 0);
813 sectrustshow(trust
->_verifyDate
, "verify date:");
814 sectrustshow(trust
->_certificates
, "certificates:");
815 sectrustshow(trust
->_anchors
, "anchors:");
816 sectrustshow(trust
->_policies
, "policies:");
817 sectrustshow(trust
->_details
, "details:");
818 sectrustshow(trust
->_info
, "info:");
823 static void cert_trust_dump(SecTrustRef trust
) {}
827 OSStatus
SecTrustEvaluate(SecTrustRef trust
, SecTrustResultType
*result
) {
831 OSStatus status
= SecTrustEvaluateIfNecessary(trust
);
835 /* post-process trust result based on exceptions */
836 __block SecTrustResultType trustResult
= kSecTrustResultInvalid
;
837 dispatch_sync(trust
->_trustQueue
, ^{
838 trustResult
= trust
->_trustResult
;
840 if (trustResult
== kSecTrustResultUnspecified
) {
841 /* If leaf is in exceptions -> proceed, otherwise unspecified. */
842 if (SecTrustGetExceptionForCertificateAtIndex(trust
, 0))
843 trustResult
= kSecTrustResultProceed
;
844 } else if (trustResult
== kSecTrustResultRecoverableTrustFailure
) {
845 /* If we have exceptions get details and match to exceptions. */
846 __block CFArrayRef details
= NULL
;
847 dispatch_sync(trust
->_trustQueue
, ^{
848 details
= CFRetainSafe(trust
->_details
);
850 CFIndex pathLength
= details
? CFArrayGetCount(details
) : 0;
851 struct SecTrustCheckExceptionContext context
= {};
853 for (ix
= 0; ix
< pathLength
; ++ix
) {
854 CFDictionaryRef detail
= (CFDictionaryRef
)CFArrayGetValueAtIndex(details
, ix
);
855 context
.exception
= SecTrustGetExceptionForCertificateAtIndex(trust
, ix
);
856 CFDictionaryApplyFunction(detail
, SecTrustCheckException
, &context
);
857 if (context
.exceptionNotFound
) {
861 CFReleaseSafe(details
);
862 __block
bool done
= false;
863 dispatch_sync(trust
->_trustQueue
, ^{
864 if (!trust
->_exceptions
|| !CFArrayGetCount(trust
->_exceptions
)) {
869 goto DoneCheckingTrust
;
871 if (!context
.exceptionNotFound
)
872 trustResult
= kSecTrustResultProceed
;
875 dispatch_sync(trust
->_trustQueue
, ^{
876 trust
->_trustResult
= trustResult
;
879 /* log to syslog when there is a trust failure */
880 if (trustResult
!= kSecTrustResultProceed
&&
881 trustResult
!= kSecTrustResultConfirm
&&
882 trustResult
!= kSecTrustResultUnspecified
) {
883 CFStringRef failureDesc
= SecTrustCopyFailureDescription(trust
);
884 secerror("%{public}@", failureDesc
);
885 CFRelease(failureDesc
);
890 *result
= trustResult
;
896 OSStatus
SecTrustEvaluateAsync(SecTrustRef trust
,
897 dispatch_queue_t queue
, SecTrustCallback result
)
900 dispatch_async(queue
, ^{
901 SecTrustResultType trustResult
;
902 if (errSecSuccess
!= SecTrustEvaluate(trust
, &trustResult
)) {
903 trustResult
= kSecTrustResultInvalid
;
905 result(trust
, trustResult
);
906 CFReleaseSafe(trust
);
908 return errSecSuccess
;
911 static bool append_certificate_to_xpc_array(SecCertificateRef certificate
, xpc_object_t xpc_certificates
);
912 static xpc_object_t
copy_xpc_certificates_array(CFArrayRef certificates
);
913 xpc_object_t
copy_xpc_policies_array(CFArrayRef policies
);
914 OSStatus
validate_array_of_items(CFArrayRef array
, CFStringRef arrayItemType
, CFTypeID itemTypeID
, bool required
);
916 static bool append_certificate_to_xpc_array(SecCertificateRef certificate
, xpc_object_t xpc_certificates
) {
920 size_t length
= SecCertificateGetLength(certificate
);
921 const uint8_t *bytes
= SecCertificateGetBytePtr(certificate
);
922 if (!length
|| !bytes
) {
925 xpc_array_set_data(xpc_certificates
, XPC_ARRAY_APPEND
, bytes
, length
);
929 static xpc_object_t
copy_xpc_certificates_array(CFArrayRef certificates
) {
930 xpc_object_t xpc_certificates
= xpc_array_create(NULL
, 0);
931 if (!xpc_certificates
) {
934 CFIndex ix
, count
= CFArrayGetCount(certificates
);
935 for (ix
= 0; ix
< count
; ++ix
) {
936 SecCertificateRef certificate
= (SecCertificateRef
) CFArrayGetValueAtIndex(certificates
, ix
);
937 #if SECTRUST_VERBOSE_DEBUG
938 size_t length
= SecCertificateGetLength(certificate
);
939 const uint8_t *bytes
= SecCertificateGetBytePtr(certificate
);
940 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
);
942 if (!append_certificate_to_xpc_array(certificate
, xpc_certificates
)) {
943 xpc_release(xpc_certificates
);
944 xpc_certificates
= NULL
;
948 return xpc_certificates
;
951 static bool SecXPCDictionarySetCertificates(xpc_object_t message
, const char *key
, CFArrayRef certificates
, CFErrorRef
*error
) {
952 xpc_object_t xpc_certificates
= copy_xpc_certificates_array(certificates
);
953 if (!xpc_certificates
) {
954 SecError(errSecAllocate
, error
, CFSTR("failed to create xpc_array of certificates"));
957 xpc_dictionary_set_value(message
, key
, xpc_certificates
);
958 xpc_release(xpc_certificates
);
962 static bool SecXPCDictionarySetPolicies(xpc_object_t message
, const char *key
, CFArrayRef policies
, CFErrorRef
*error
) {
963 xpc_object_t xpc_policies
= copy_xpc_policies_array(policies
);
965 SecError(errSecAllocate
, error
, CFSTR("failed to create xpc_array of policies"));
968 xpc_dictionary_set_value(message
, key
, xpc_policies
);
969 xpc_release(xpc_policies
);
974 static bool CFDataAppendToXPCArray(CFDataRef data
, xpc_object_t xpc_data_array
, CFErrorRef
*error
) {
978 size_t length
= CFDataGetLength(data
);
979 const uint8_t *bytes
= CFDataGetBytePtr(data
);
980 if (!length
|| !bytes
)
981 return SecError(errSecParam
, error
, CFSTR("invalid CFDataRef"));
983 xpc_array_set_data(xpc_data_array
, XPC_ARRAY_APPEND
, bytes
, length
);
988 static xpc_object_t
CFDataArrayCopyXPCArray(CFArrayRef data_array
, CFErrorRef
*error
) {
989 xpc_object_t xpc_data_array
;
990 require_action_quiet(xpc_data_array
= xpc_array_create(NULL
, 0), exit
,
991 SecError(errSecAllocate
, error
, CFSTR("failed to create xpc_array")));
992 CFIndex ix
, count
= CFArrayGetCount(data_array
);
993 for (ix
= 0; ix
< count
; ++ix
) {
994 if (!CFDataAppendToXPCArray((CFDataRef
)CFArrayGetValueAtIndex(data_array
, ix
), xpc_data_array
, error
)) {
995 xpc_release(xpc_data_array
);
1001 return xpc_data_array
;
1004 static bool SecXPCDictionarySetDataArray(xpc_object_t message
, const char *key
, CFArrayRef data_array
, CFErrorRef
*error
) {
1005 xpc_object_t xpc_data_array
= CFDataArrayCopyXPCArray(data_array
, error
);
1006 if (!xpc_data_array
)
1008 xpc_dictionary_set_value(message
, key
, xpc_data_array
);
1009 xpc_release(xpc_data_array
);
1013 static bool SecXPCDictionaryCopyChainOptional(xpc_object_t message
, const char *key
, SecCertificatePathRef
*path
, CFErrorRef
*error
) {
1014 xpc_object_t xpc_path
= xpc_dictionary_get_value(message
, key
);
1019 *path
= SecCertificatePathCreateWithXPCArray(xpc_path
, error
);
1023 static int SecXPCDictionaryGetNonZeroInteger(xpc_object_t message
, const char *key
, CFErrorRef
*error
) {
1024 int64_t value
= xpc_dictionary_get_int64(message
, key
);
1026 SecError(errSecInternal
, error
, CFSTR("object for key %s is 0"), key
);
1031 static SecTrustResultType
certs_anchors_bool_bool_policies_responses_scts_logs_date_ag_to_details_info_chain_int_error_request(enum SecXPCOperation op
, CFArrayRef certificates
, CFArrayRef anchors
, bool anchorsOnly
, bool keychainsAllowed
, CFArrayRef policies
, CFArrayRef responses
, CFArrayRef SCTs
, CFArrayRef trustedLogs
, CFAbsoluteTime verifyTime
, __unused CFArrayRef accessGroups
, CFArrayRef
*details
, CFDictionaryRef
*info
, SecCertificatePathRef
*chain
, CFErrorRef
*error
)
1033 __block SecTrustResultType tr
= kSecTrustResultInvalid
;
1034 securityd_send_sync_and_do(op
, error
, ^bool(xpc_object_t message
, CFErrorRef
*error
) {
1035 if (!SecXPCDictionarySetCertificates(message
, kSecTrustCertificatesKey
, certificates
, error
))
1037 if (anchors
&& !SecXPCDictionarySetCertificates(message
, kSecTrustAnchorsKey
, anchors
, error
))
1040 xpc_dictionary_set_bool(message
, kSecTrustAnchorsOnlyKey
, anchorsOnly
);
1041 xpc_dictionary_set_bool(message
, kSecTrustKeychainsAllowedKey
, keychainsAllowed
);
1042 if (!SecXPCDictionarySetPolicies(message
, kSecTrustPoliciesKey
, policies
, error
))
1044 if (responses
&& !SecXPCDictionarySetDataArray(message
, kSecTrustResponsesKey
, responses
, error
))
1046 if (SCTs
&& !SecXPCDictionarySetDataArray(message
, kSecTrustSCTsKey
, SCTs
, error
))
1048 if (trustedLogs
&& !SecXPCDictionarySetPList(message
, kSecTrustTrustedLogsKey
, trustedLogs
, error
))
1050 xpc_dictionary_set_double(message
, kSecTrustVerifyDateKey
, verifyTime
);
1052 }, ^bool(xpc_object_t response
, CFErrorRef
*error
) {
1053 secdebug("trust", "response: %@", response
);
1054 return SecXPCDictionaryCopyArrayOptional(response
, kSecTrustDetailsKey
, details
, error
) &&
1055 SecXPCDictionaryCopyDictionaryOptional(response
, kSecTrustInfoKey
, info
, error
) &&
1056 SecXPCDictionaryCopyChainOptional(response
, kSecTrustChainKey
, chain
, error
) &&
1057 ((tr
= SecXPCDictionaryGetNonZeroInteger(response
, kSecTrustResultKey
, error
)) != kSecTrustResultInvalid
);
1062 OSStatus
validate_array_of_items(CFArrayRef array
, CFStringRef arrayItemType
, CFTypeID itemTypeID
, bool required
) {
1063 OSStatus result
= errSecSuccess
;
1064 CFIndex index
, count
;
1065 count
= (array
) ? CFArrayGetCount(array
) : 0;
1066 if (!count
&& required
) {
1067 secerror("no %@ in array!", arrayItemType
);
1068 result
= errSecParam
;
1070 for (index
= 0; index
< count
; index
++) {
1071 CFTypeRef item
= (CFTypeRef
) CFArrayGetValueAtIndex(array
, index
);
1073 secerror("%@ %@ (index %d)", arrayItemType
, CFSTR("reference is nil"), (int)index
);
1074 result
= errSecParam
;
1077 if (CFGetTypeID(item
) != itemTypeID
) {
1078 secerror("%@ %@ (index %d)", arrayItemType
, CFSTR("is not the expected CF type"), (int)index
);
1079 result
= errSecParam
;
1082 if (CFGetTypeID(item
) == SecCertificateGetTypeID()) {
1083 SecCertificateRef certificate
= (SecCertificateRef
) item
;
1084 CFIndex length
= SecCertificateGetLength(certificate
);
1085 const UInt8
*bytes
= SecCertificateGetBytePtr(certificate
);
1087 secerror("%@ %@ (index %d)", arrayItemType
, CFSTR("has zero length"), (int)index
);
1088 result
= errSecParam
;
1091 secerror("%@ %@ (index %d)", arrayItemType
, CFSTR("has nil bytes"), (int)index
);
1092 result
= errSecParam
;
1094 #if SECTRUST_VERBOSE_DEBUG
1095 secerror("%@[%d] of %d = %ld bytes @ 0x%lX", arrayItemType
, (int)index
, (int)count
, (size_t)length
, (uintptr_t)bytes
);
1099 if (CFGetTypeID(item
) == SecPolicyGetTypeID()) {
1100 SecPolicyRef policy
= (SecPolicyRef
) item
;
1101 CFStringRef oidStr
= policy
->_oid
;
1102 if (!oidStr
|| (CFGetTypeID(oidStr
) != CFStringGetTypeID())) {
1103 oidStr
= CFSTR("has invalid OID string!");
1104 secerror("%@ %@ (index %d)", arrayItemType
, oidStr
, (int)index
);
1106 #if SECTRUST_VERBOSE_DEBUG
1107 secerror("%@[%d] of %d = \"%@\" 0x%lX", arrayItemType
, (int)index
, (int)count
, oidStr
, (uintptr_t)policy
);
1114 static OSStatus
SecTrustValidateInput(SecTrustRef trust
) {
1115 OSStatus status
, result
= errSecSuccess
;
1117 // certificates (required)
1118 status
= validate_array_of_items(trust
->_certificates
, CFSTR("certificate"), SecCertificateGetTypeID(), true);
1119 if (status
) result
= status
;
1120 // anchors (optional)
1121 status
= validate_array_of_items(trust
->_anchors
, CFSTR("input anchor"), SecCertificateGetTypeID(), false);
1122 if (status
) result
= status
;
1123 // policies (required??)
1124 status
= validate_array_of_items(trust
->_policies
, CFSTR("policy"), SecPolicyGetTypeID(), true);
1125 if (status
) result
= status
;
1126 // _responses, _SCTs, _trustedLogs, ...
1127 // verify time: SecTrustGetVerifyTime(trust)
1128 // access groups: SecAccessGroupsGetCurrent()
1134 static void SecTrustPostEvaluate(SecTrustRef trust
) {
1135 if (!trust
) { return; }
1137 CFIndex pathLength
= (trust
->_details
) ? CFArrayGetCount(trust
->_details
) : 0;
1139 for (ix
= 0; ix
< pathLength
; ++ix
) {
1140 CFDictionaryRef detail
= (CFDictionaryRef
)CFArrayGetValueAtIndex(trust
->_details
, ix
);
1141 if ((ix
== 0) && CFDictionaryContainsKey(detail
, kSecPolicyCheckBlackListedLeaf
)) {
1142 trust
->_trustResult
= kSecTrustResultFatalTrustFailure
;
1145 if (CFDictionaryContainsKey(detail
, kSecPolicyCheckBlackListedKey
)) {
1146 trust
->_trustResult
= kSecTrustResultFatalTrustFailure
;
1152 static OSStatus
SecTrustEvaluateIfNecessary(SecTrustRef trust
) {
1153 __block OSStatus result
;
1158 __block CFAbsoluteTime verifyTime
= SecTrustGetVerifyTime(trust
);
1159 SecTrustAddPolicyAnchors(trust
);
1160 dispatch_sync(trust
->_trustQueue
, ^{
1161 if (trust
->_trustResult
!= kSecTrustResultInvalid
) {
1162 result
= errSecSuccess
;
1166 trust
->_trustResult
= kSecTrustResultOtherError
; /* to avoid potential recursion */
1168 CFReleaseNull(trust
->_chain
);
1169 CFReleaseNull(trust
->_details
);
1170 CFReleaseNull(trust
->_info
);
1171 if (trust
->_legacy_info_array
) {
1172 free(trust
->_legacy_info_array
);
1173 trust
->_legacy_info_array
= NULL
;
1175 if (trust
->_legacy_status_array
) {
1176 free(trust
->_legacy_status_array
);
1177 trust
->_legacy_status_array
= NULL
;
1180 os_activity_initiate("SecTrustEvaluateIfNecessary", OS_ACTIVITY_FLAG_DEFAULT
, ^{
1181 SecTrustValidateInput(trust
);
1183 /* @@@ 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. */
1184 result
= SecOSStatusWith(^bool (CFErrorRef
*error
) {
1185 trust
->_trustResult
= SECURITYD_XPC(sec_trust_evaluate
,
1186 certs_anchors_bool_bool_policies_responses_scts_logs_date_ag_to_details_info_chain_int_error_request
,
1187 trust
->_certificates
, trust
->_anchors
, trust
->_anchorsOnly
, trust
->_keychainsAllowed
,
1188 trust
->_policies
, trust
->_responses
, trust
->_SCTs
, trust
->_trustedLogs
,
1189 verifyTime
, SecAccessGroupsGetCurrent(),
1190 &trust
->_details
, &trust
->_info
, &trust
->_chain
, error
);
1191 if (trust
->_trustResult
== kSecTrustResultInvalid
/* TODO check domain */ &&
1192 SecErrorGetOSStatus(*error
) == errSecNotAvailable
&&
1193 CFArrayGetCount(trust
->_certificates
)) {
1194 /* We failed to talk to securityd. The only time this should
1195 happen is when we are running prior to launchd enabling
1196 registration of services. This currently happens when we
1197 are running from the ramdisk. To make ASR happy we initialize
1198 _chain and return success with a failure as the trustResult, to
1199 make it seem like we did a cert evaluation, so ASR can extract
1200 the public key from the leaf. */
1201 trust
->_chain
= SecCertificatePathCreate(NULL
, (SecCertificateRef
)CFArrayGetValueAtIndex(trust
->_certificates
, 0), NULL
);
1203 CFReleaseNull(*error
);
1206 SecTrustPostEvaluate(trust
);
1207 trust
->_trustResultBeforeExceptions
= trust
->_trustResult
;
1208 return trust
->_trustResult
!= kSecTrustResultInvalid
;
1215 /* Helper for the qsort below. */
1216 static int compare_strings(const void *a1
, const void *a2
) {
1217 CFStringRef s1
= *(CFStringRef
*)a1
;
1218 CFStringRef s2
= *(CFStringRef
*)a2
;
1219 return (int) CFStringCompare(s1
, s2
, kCFCompareForcedOrdering
);
1222 CFStringRef
SecTrustCopyFailureDescription(SecTrustRef trust
) {
1226 CFMutableStringRef reason
= CFStringCreateMutable(NULL
, 0);
1227 SecTrustEvaluateIfNecessary(trust
);
1228 __block CFArrayRef details
= NULL
;
1229 dispatch_sync(trust
->_trustQueue
, ^{
1230 details
= CFRetainSafe(trust
->_details
);
1232 CFIndex pathLength
= details
? CFArrayGetCount(details
) : 0;
1233 for (CFIndex ix
= 0; ix
< pathLength
; ++ix
) {
1234 CFDictionaryRef detail
= (CFDictionaryRef
)CFArrayGetValueAtIndex(details
, ix
);
1235 CFIndex dCount
= CFDictionaryGetCount(detail
);
1238 CFStringAppend(reason
, CFSTR(" [leaf"));
1239 else if (ix
== pathLength
- 1)
1240 CFStringAppend(reason
, CFSTR(" [root"));
1242 CFStringAppendFormat(reason
, NULL
, CFSTR(" [ca%" PRIdCFIndex
), ix
);
1244 const void *keys
[dCount
];
1245 CFDictionaryGetKeysAndValues(detail
, &keys
[0], NULL
);
1246 qsort(&keys
[0], dCount
, sizeof(keys
[0]), compare_strings
);
1247 for (CFIndex kix
= 0; kix
< dCount
; ++kix
) {
1248 CFStringRef key
= keys
[kix
];
1249 const void *value
= CFDictionaryGetValue(detail
, key
);
1250 CFStringAppendFormat(reason
, NULL
, CFSTR(" %@%@"), key
,
1251 (CFGetTypeID(value
) == CFBooleanGetTypeID()
1252 ? CFSTR("") : value
));
1254 CFStringAppend(reason
, CFSTR("]"));
1257 CFReleaseSafe(details
);
1262 /* On OS X we need SecTrustCopyPublicKey to give us a CDSA-based SecKeyRef,
1263 so we will refer to this one internally as SecTrustCopyPublicKey_ios,
1264 and call it from SecTrustCopyPublicKey.
1266 SecKeyRef
SecTrustCopyPublicKey_ios(SecTrustRef trust
)
1268 SecKeyRef
SecTrustCopyPublicKey(SecTrustRef trust
)
1274 __block SecKeyRef publicKey
= NULL
;
1275 dispatch_sync(trust
->_trustQueue
, ^{
1276 if (trust
->_publicKey
) {
1277 publicKey
= CFRetainSafe(trust
->_publicKey
);
1280 SecCertificateRef leaf
= (SecCertificateRef
)CFArrayGetValueAtIndex(trust
->_certificates
, 0);
1282 trust
->_publicKey
= SecCertificateCopyPublicKey_ios(leaf
);
1284 trust
->_publicKey
= SecCertificateCopyPublicKey(leaf
);
1286 if (trust
->_publicKey
) {
1287 publicKey
= CFRetainSafe(trust
->_publicKey
);
1290 /* If we couldn't get a public key from the leaf cert alone. */
1292 SecTrustEvaluateIfNecessary(trust
);
1293 dispatch_sync(trust
->_trustQueue
, ^{
1294 if (trust
->_chain
) {
1295 trust
->_publicKey
= SecCertificatePathCopyPublicKeyAtIndex(trust
->_chain
, 0);
1296 publicKey
= CFRetainSafe(trust
->_publicKey
);
1303 CFIndex
SecTrustGetCertificateCount(SecTrustRef trust
) {
1307 SecTrustEvaluateIfNecessary(trust
);
1308 __block CFIndex certCount
= 1;
1309 dispatch_sync(trust
->_trustQueue
, ^{
1310 if (trust
->_chain
) {
1311 certCount
= SecCertificatePathGetCount(trust
->_chain
);
1317 SecCertificateRef
SecTrustGetCertificateAtIndex(SecTrustRef trust
,
1322 __block SecCertificateRef cert
= NULL
;
1324 dispatch_sync(trust
->_trustQueue
, ^{
1325 cert
= (SecCertificateRef
)CFArrayGetValueAtIndex(trust
->_certificates
, 0);
1329 SecTrustEvaluateIfNecessary(trust
);
1330 dispatch_sync(trust
->_trustQueue
, ^{
1331 if (trust
->_chain
) {
1332 cert
= SecCertificatePathGetCertificateAtIndex(trust
->_chain
, ix
);
1338 CFDictionaryRef
SecTrustCopyInfo(SecTrustRef trust
) {
1342 SecTrustEvaluateIfNecessary(trust
);
1343 __block CFDictionaryRef info
= NULL
;
1344 dispatch_sync(trust
->_trustQueue
, ^{
1345 info
= CFRetainSafe(trust
->_info
);
1350 CFArrayRef
SecTrustGetTrustExceptionsArray(SecTrustRef trust
) {
1351 return trust
->_exceptions
;
1354 CFDataRef
SecTrustCopyExceptions(SecTrustRef trust
) {
1355 __block CFArrayRef details
= NULL
;
1356 SecTrustEvaluateIfNecessary(trust
);
1357 dispatch_sync(trust
->_trustQueue
, ^{
1358 details
= CFRetainSafe(trust
->_details
);
1360 CFIndex pathLength
= details
? CFArrayGetCount(details
) : 0;
1361 CFMutableArrayRef exceptions
= CFArrayCreateMutable(kCFAllocatorDefault
, pathLength
, &kCFTypeArrayCallBacks
);
1363 for (ix
= 0; ix
< pathLength
; ++ix
) {
1364 CFDictionaryRef detail
= (CFDictionaryRef
)CFArrayGetValueAtIndex(details
, ix
);
1365 CFIndex detailCount
= CFDictionaryGetCount(detail
);
1366 CFMutableDictionaryRef exception
;
1367 if (ix
== 0 || detailCount
> 0) {
1368 exception
= CFDictionaryCreateMutableCopy(kCFAllocatorDefault
, detailCount
+ 1, detail
);
1369 SecCertificateRef certificate
= SecTrustGetCertificateAtIndex(trust
, ix
);
1370 CFDataRef digest
= SecCertificateGetSHA1Digest(certificate
);
1371 CFDictionaryAddValue(exception
, kSecCertificateDetailSHA1Digest
, digest
);
1373 /* Add empty exception dictionaries for non leaf certs which have no exceptions to save space. */
1374 exception
= (CFMutableDictionaryRef
)CFDictionaryCreate(kCFAllocatorDefault
, NULL
, NULL
, 0,
1375 &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
1377 CFArrayAppendValue(exceptions
, exception
);
1378 CFRelease(exception
);
1381 /* Remove any trailing empty dictionaries to save even more space (we skip the leaf
1382 since it will never be empty). */
1383 for (ix
= pathLength
; ix
-- > 1;) {
1384 CFDictionaryRef exception
= (CFDictionaryRef
)CFArrayGetValueAtIndex(exceptions
, ix
);
1385 if (CFDictionaryGetCount(exception
) == 0) {
1386 CFArrayRemoveValueAtIndex(exceptions
, ix
);
1392 CFDataRef encodedExceptions
= CFPropertyListCreateData(kCFAllocatorDefault
,
1393 exceptions
, kCFPropertyListBinaryFormat_v1_0
, 0, NULL
);
1394 CFRelease(exceptions
);
1395 CFReleaseSafe(details
);
1396 return encodedExceptions
;
1399 bool SecTrustSetExceptions(SecTrustRef trust
, CFDataRef encodedExceptions
) {
1403 CFArrayRef exceptions
= NULL
;
1405 if (NULL
!= encodedExceptions
) {
1406 exceptions
= (CFArrayRef
)CFPropertyListCreateWithData(kCFAllocatorDefault
,
1407 encodedExceptions
, kCFPropertyListImmutable
, NULL
, NULL
);
1410 if (exceptions
&& CFGetTypeID(exceptions
) != CFArrayGetTypeID()) {
1411 CFRelease(exceptions
);
1415 dispatch_sync(trust
->_trustQueue
, ^{
1416 if (trust
->_exceptions
&& !exceptions
) {
1417 /* Exceptions are currently set and now we are clearing them. */
1418 trust
->_trustResult
= trust
->_trustResultBeforeExceptions
;
1421 CFReleaseSafe(trust
->_exceptions
);
1422 trust
->_exceptions
= exceptions
;
1425 /* If there is a valid exception entry for our current leaf we're golden. */
1426 if (SecTrustGetExceptionForCertificateAtIndex(trust
, 0))
1429 /* The passed in exceptions didn't match our current leaf, so we discard it. */
1430 dispatch_sync(trust
->_trustQueue
, ^{
1431 CFReleaseNull(trust
->_exceptions
);
1436 CFArrayRef
SecTrustCopySummaryPropertiesAtIndex(SecTrustRef trust
, CFIndex ix
) {
1437 CFMutableArrayRef summary
;
1438 SecCertificateRef certificate
= SecTrustGetCertificateAtIndex(trust
, ix
);
1439 summary
= SecCertificateCopySummaryProperties(certificate
,
1440 SecTrustGetVerifyTime(trust
));
1441 /* FIXME Add more details in the failure case. */
1446 CFArrayRef
SecTrustCopyDetailedPropertiesAtIndex(SecTrustRef trust
, CFIndex ix
) {
1448 SecCertificateRef certificate
= SecTrustGetCertificateAtIndex(trust
, ix
);
1449 summary
= SecCertificateCopyProperties(certificate
);
1459 Can be on any non root cert in the chain.
1461 Short circuit: Yes (No other errors matter after this one)
1462 Non recoverable error
1463 Trust UI: Invalid certificate chain linkage
1464 Cert UI: Invalid linkage to parent certificate
1466 CFStringRef kSecPolicyCheckIdLinkage
= CFSTR("IdLinkage");
1468 /* X.509 required checks.
1469 Can be on any cert in the chain
1471 Short circuit: Yes (No other errors matter after this one)
1472 Non recoverable error
1473 Trust UI: (One or more) unsupported critical extensions found.
1475 /* If we have no names for the extention oids use:
1476 Cert UI: One or more unsupported critical extensions found (Non recoverable error).
1477 Cert UI: Unsupported 'foo', 'bar', baz' critical extensions found.
1479 CFStringRef kSecPolicyCheckCriticalExtensions
= CFSTR("CriticalExtensions");
1480 /* Cert UI: Unsupported critical Qualified Certificate Statements extension found (Non recoverable error). */
1481 CFStringRef kSecPolicyCheckQualifiedCertStatements
= CFSTR("QualifiedCertStatements");
1482 /* Cert UI: Certificate has an empty subject (and no critial subjectAltname). */
1485 Only apply to the anchor.
1487 Short circuit: No (Under discussion)
1489 Trust UI: Root certificate is not trusted (for this policy/app/host/whatever?)
1490 Cert UI: Not a valid anchor
1492 CFStringRef kSecPolicyCheckAnchorTrusted
= CFSTR("AnchorTrusted");
1493 CFStringRef kSecPolicyCheckAnchorSHA1
= CFSTR("AnchorSHA1");
1495 CFStringRef kSecPolicyCheckAnchorApple
= CFSTR("AnchorApple");
1496 CFStringRef kSecPolicyAppleAnchorIncludeTestRoots
= CFSTR("AnchorAppleTestRoots");
1499 Only applies to leaf
1503 Trust UI: (Hostname|email address) mismatch
1505 CFStringRef kSecPolicyCheckSSLHostname
= CFSTR("SSLHostname");
1507 /* Policy specific checks.
1508 Can be on any cert in the chain
1512 Trust UI: Certificate chain is not valid for the current policy.
1513 OR: (One or more) certificates in the chain are not valid for the current policy/application
1515 CFStringRef kSecPolicyCheckNonEmptySubject
= CFSTR("NonEmptySubject");
1516 /* Cert UI: Non CA certificate used as CA.
1517 Cert UI: CA certificate used as leaf.
1518 Cert UI: Cert chain length exceeded.
1519 Cert UI: Basic constraints extension not critical (non fatal).
1520 Cert UI: Leaf certificate has basic constraints extension (non fatal).
1522 CFStringRef kSecPolicyCheckBasicConstraints
= CFSTR("BasicConstraints");
1523 CFStringRef kSecPolicyCheckKeyUsage
= CFSTR("KeyUsage");
1524 CFStringRef kSecPolicyCheckExtendedKeyUsage
= CFSTR("ExtendedKeyUsage");
1525 /* Checks that the issuer of the leaf has exactly one Common Name and that it
1526 matches the specified string. */
1527 CFStringRef kSecPolicyCheckIssuerCommonName
= CFSTR("IssuerCommonName");
1528 /* Checks that the leaf has exactly one Common Name and that it has the
1529 specified string as a prefix. */
1530 CFStringRef kSecPolicyCheckSubjectCommonNamePrefix
= CFSTR("SubjectCommonNamePrefix");
1531 /* Check that the certificate chain length matches the specificed CFNumberRef
1533 CFStringRef kSecPolicyCheckChainLength
= CFSTR("ChainLength");
1534 CFStringRef kSecPolicyCheckNotValidBefore
= CFSTR("NotValidBefore");
1537 Can be on any cert in the chain
1541 Trust UI: One or more certificates have expired or are not valid yet.
1542 OS: The (root|intermediate|leaf) certificate (expired on 'date'|is not valid until 'date')
1543 Cert UI: Certificate (expired on 'date'|is not valid until 'date')
1545 CFStringRef kSecPolicyCheckValidIntermediates
= CFSTR("ValidIntermediates");
1546 CFStringRef kSecPolicyCheckValidLeaf
= CFSTR("ValidLeaf");
1547 CFStringRef kSecPolicyCheckValidRoot
= CFSTR("ValidRoot");
1551 struct TrustFailures
{
1553 bool unknownCritExtn
;
1554 bool untrustedAnchor
;
1555 bool hostnameMismatch
;
1562 static void applyDetailProperty(const void *_key
, const void *_value
,
1564 CFStringRef key
= (CFStringRef
)_key
;
1565 struct TrustFailures
*tf
= (struct TrustFailures
*)context
;
1566 if (CFGetTypeID(_value
) != CFBooleanGetTypeID()) {
1567 /* Value isn't a CFBooleanRef, oh no! */
1570 CFBooleanRef value
= (CFBooleanRef
)_value
;
1571 if (CFBooleanGetValue(value
)) {
1572 /* Not an actual failure so we don't report it. */
1576 /* @@@ FIXME: Report a different return value when something is in the
1577 details but masked out by an exception and use that below for display
1579 if (CFEqual(key
, kSecPolicyCheckIdLinkage
)) {
1580 tf
->badLinkage
= true;
1581 } else if (CFEqual(key
, kSecPolicyCheckCriticalExtensions
)
1582 || CFEqual(key
, kSecPolicyCheckQualifiedCertStatements
)) {
1583 tf
->unknownCritExtn
= true;
1584 } else if (CFEqual(key
, kSecPolicyCheckAnchorTrusted
)
1585 || CFEqual(key
, kSecPolicyCheckAnchorSHA1
)
1586 || CFEqual(key
, kSecPolicyCheckAnchorSHA256
)
1587 || CFEqual(key
, kSecPolicyCheckAnchorApple
)) {
1588 tf
->untrustedAnchor
= true;
1589 } else if (CFEqual(key
, kSecPolicyCheckSSLHostname
)) {
1590 tf
->hostnameMismatch
= true;
1591 } else if (CFEqual(key
, kSecPolicyCheckValidIntermediates
)
1592 || CFEqual(key
, kSecPolicyCheckValidLeaf
)
1593 || CFEqual(key
, kSecPolicyCheckValidRoot
)) {
1594 tf
->invalidCert
= true;
1595 } else if (CFEqual(key
, kSecPolicyCheckWeakIntermediates
)
1596 || CFEqual(key
, kSecPolicyCheckWeakLeaf
)
1597 || CFEqual(key
, kSecPolicyCheckWeakRoot
)) {
1599 } else if (CFEqual(key
, kSecPolicyCheckRevocation
)) {
1600 tf
->revocation
= true;
1602 /* Anything else is a policy failure. */
1604 if (CFEqual(key
, kSecPolicyCheckNonEmptySubject
)
1605 || CFEqual(key
, kSecPolicyCheckBasicConstraints
)
1606 || CFEqual(key
, kSecPolicyCheckKeyUsage
)
1607 || CFEqual(key
, kSecPolicyCheckExtendedKeyUsage
)
1608 || CFEqual(key
, kSecPolicyCheckIssuerCommonName
)
1609 || CFEqual(key
, kSecPolicyCheckSubjectCommonNamePrefix
)
1610 || CFEqual(key
, kSecPolicyCheckChainLength
)
1611 || CFEqual(key
, kSecPolicyCheckNotValidBefore
))
1614 tf
->policyFail
= true;
1618 static void appendError(CFMutableArrayRef properties
, CFStringRef error
) {
1619 CFStringRef localizedError
= SecFrameworkCopyLocalizedString(error
,
1620 CFSTR("SecCertificate"));
1621 if (!localizedError
) {
1622 //secerror("WARNING: localized error string was not found in Security.framework");
1623 localizedError
= CFRetain(error
);
1625 appendProperty(properties
, kSecPropertyTypeError
, NULL
, NULL
,
1627 CFReleaseNull(localizedError
);
1631 /* OS X properties array has a different structure and is implemented SecTrust.cpp. */
1632 CFArrayRef
SecTrustCopyProperties_ios(SecTrustRef trust
)
1634 CFArrayRef
SecTrustCopyProperties(SecTrustRef trust
)
1640 SecTrustEvaluateIfNecessary(trust
);
1641 __block CFArrayRef details
= NULL
;
1642 dispatch_sync(trust
->_trustQueue
, ^{
1643 details
= CFRetainSafe(trust
->_details
);
1648 struct TrustFailures tf
= {};
1650 CFIndex ix
, count
= CFArrayGetCount(details
);
1651 for (ix
= 0; ix
< count
; ++ix
) {
1652 CFDictionaryRef detail
= (CFDictionaryRef
)
1653 CFArrayGetValueAtIndex(details
, ix
);
1654 /* We now have a detail dictionary for certificate at index ix, with
1655 a key value pair for each failed policy check. Let's convert it
1656 from Ro-Man form into something a Hu-Man can understand. */
1657 CFDictionaryApplyFunction(detail
, applyDetailProperty
, &tf
);
1660 CFMutableArrayRef properties
= CFArrayCreateMutable(kCFAllocatorDefault
, 0,
1661 &kCFTypeArrayCallBacks
);
1662 /* The badLinkage and unknownCritExtn failures are short circuited, since
1663 you can't recover from those errors. */
1664 if (tf
.badLinkage
) {
1665 appendError(properties
, CFSTR("Invalid certificate chain linkage."));
1666 } else if (tf
.unknownCritExtn
) {
1667 appendError(properties
, CFSTR("One or more unsupported critical extensions found."));
1669 if (tf
.untrustedAnchor
) {
1670 appendError(properties
, CFSTR("Root certificate is not trusted."));
1672 if (tf
.hostnameMismatch
) {
1673 appendError(properties
, CFSTR("Hostname mismatch."));
1675 if (tf
.policyFail
) {
1676 appendError(properties
, CFSTR("Policy requirements not met."));
1678 if (tf
.invalidCert
) {
1679 appendError(properties
, CFSTR("One or more certificates have expired or are not valid yet."));
1682 appendError(properties
, CFSTR("One or more certificates is using a weak key size."));
1684 if (tf
.revocation
) {
1685 appendError(properties
, CFSTR("One or more certificates have been revoked."));
1689 if (CFArrayGetCount(properties
) == 0) {
1690 /* The certificate chain is trusted, return an empty plist */
1691 CFReleaseNull(properties
);
1694 CFReleaseNull(details
);
1698 CFDictionaryRef
SecTrustCopyResult(SecTrustRef trust
) {
1699 // Builds and returns a dictionary of evaluation results.
1703 __block CFMutableDictionaryRef results
= CFDictionaryCreateMutable(NULL
, 0,
1704 &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
1706 SecTrustEvaluateIfNecessary(trust
);
1707 dispatch_sync(trust
->_trustQueue
, ^{
1708 // kSecTrustResultDetails (per-cert results)
1709 CFArrayRef details
= trust
->_details
;
1711 CFDictionarySetValue(results
, (const void *)kSecTrustResultDetails
, (const void *)details
);
1714 // kSecTrustResultValue (overall trust result)
1715 CFNumberRef numValue
= CFNumberCreate(NULL
, kCFNumberSInt32Type
, &trust
->_trustResult
);
1717 CFDictionarySetValue(results
, (const void *)kSecTrustResultValue
, (const void *)numValue
);
1718 CFRelease(numValue
);
1720 CFDictionaryRef info
= trust
->_info
;
1721 if (trust
->_trustResult
== kSecTrustResultInvalid
|| !info
) {
1722 return; // we have nothing more to add
1725 // kSecTrustEvaluationDate
1726 CFDateRef evaluationDate
= trust
->_verifyDate
;
1727 if (evaluationDate
) {
1728 CFDictionarySetValue(results
, (const void *)kSecTrustEvaluationDate
, (const void *)evaluationDate
);
1731 // kSecTrustCertificateTransparency
1732 CFBooleanRef ctValue
;
1733 if (CFDictionaryGetValueIfPresent(info
, kSecTrustInfoCertificateTransparencyKey
, (const void **)&ctValue
)) {
1734 CFDictionarySetValue(results
, (const void *)kSecTrustCertificateTransparency
, (const void *)ctValue
);
1737 // kSecTrustCertificateTransparencyWhiteList
1738 CFBooleanRef ctWhiteListValue
;
1739 if (CFDictionaryGetValueIfPresent(info
, kSecTrustInfoCertificateTransparencyWhiteListKey
, (const void **)&ctWhiteListValue
)) {
1740 CFDictionarySetValue(results
, (const void *)kSecTrustCertificateTransparencyWhiteList
, (const void *)ctWhiteListValue
);
1743 // kSecTrustExtendedValidation
1744 CFBooleanRef evValue
;
1745 if (CFDictionaryGetValueIfPresent(info
, kSecTrustInfoExtendedValidationKey
, (const void **)&evValue
)) {
1746 CFDictionarySetValue(results
, (const void *)kSecTrustExtendedValidation
, (const void *)evValue
);
1749 // kSecTrustOrganizationName
1750 CFStringRef organizationName
;
1751 if (CFDictionaryGetValueIfPresent(info
, kSecTrustInfoCompanyNameKey
, (const void **)&organizationName
)) {
1752 CFDictionarySetValue(results
, (const void *)kSecTrustOrganizationName
, (const void *)organizationName
);
1755 // kSecTrustRevocationChecked
1756 CFBooleanRef revocationChecked
;
1757 if (CFDictionaryGetValueIfPresent(info
, kSecTrustRevocationChecked
, (const void **)&revocationChecked
)) {
1758 CFDictionarySetValue(results
, (const void *)kSecTrustRevocationChecked
, (const void *)revocationChecked
);
1761 // kSecTrustRevocationReason
1762 CFNumberRef revocationReason
;
1763 if (CFDictionaryGetValueIfPresent(info
, kSecTrustRevocationReason
, (const void **)&revocationReason
)) {
1764 CFDictionarySetValue(results
, (const void *)kSecTrustRevocationReason
, (const void *)revocationReason
);
1767 // kSecTrustRevocationValidUntilDate
1768 CFDateRef validUntilDate
;
1769 if (CFDictionaryGetValueIfPresent(info
, kSecTrustRevocationValidUntilDate
, (const void **)&validUntilDate
)) {
1770 CFDictionarySetValue(results
, (const void *)kSecTrustRevocationValidUntilDate
, (const void *)validUntilDate
);
1777 // Return 0 upon error.
1778 static int to_int_error_request(enum SecXPCOperation op
, CFErrorRef
*error
) {
1779 __block
int64_t result
= 0;
1780 securityd_send_sync_and_do(op
, error
, NULL
, ^bool(xpc_object_t response
, CFErrorRef
*error
) {
1781 result
= xpc_dictionary_get_int64(response
, kSecXPCKeyResult
);
1783 return SecError(errSecInternal
, error
, CFSTR("int64 missing in response"));
1789 // version 0 -> error, so we need to start at version 1 or later.
1790 OSStatus
SecTrustGetOTAPKIAssetVersionNumber(int* versionNumber
)
1793 os_activity_t trace_activity
= os_activity_start("SecTrustGetOTAPKIAssetVersionNumber", OS_ACTIVITY_FLAG_DEFAULT
);
1794 result
= SecOSStatusWith(^bool(CFErrorRef
*error
) {
1796 return SecError(errSecParam
, error
, CFSTR("versionNumber is NULL"));
1798 return (*versionNumber
= SECURITYD_XPC(sec_ota_pki_asset_version
, to_int_error_request
, error
)) != 0;
1801 os_activity_end(trace_activity
);
1805 #define do_if_registered(sdp, ...) if (gSecurityd && gSecurityd->sdp) { return gSecurityd->sdp(__VA_ARGS__); }
1807 static bool xpc_dictionary_entry_is_type(xpc_object_t dictionary
, const char *key
, xpc_type_t type
)
1809 xpc_object_t value
= xpc_dictionary_get_value(dictionary
, key
);
1811 return value
&& (xpc_get_type(value
) == type
);
1814 OSStatus
SecTrustOTAPKIGetUpdatedAsset(int* didUpdateAsset
)
1816 CFErrorRef error
= NULL
;
1817 do_if_registered(sec_ota_pki_get_new_asset
, &error
);
1820 xpc_object_t message
= securityd_create_message(kSecXPCOpOTAPKIGetNewAsset
, &error
);
1823 xpc_object_t response
= securityd_message_with_reply_sync(message
, &error
);
1825 if (response
&& xpc_dictionary_entry_is_type(response
, kSecXPCKeyResult
, XPC_TYPE_INT64
))
1827 num
= (int64_t) xpc_dictionary_get_int64(response
, kSecXPCKeyResult
);
1828 xpc_release(response
);
1831 xpc_release(message
);
1834 if (NULL
!= didUpdateAsset
)
1836 *didUpdateAsset
= (int)num
;
1842 * This function performs an evaluation of the leaf certificate only, and
1843 * does so in the process that called it. Its primary use is in SecItemCopyMatching
1844 * when kSecMatchPolicy is in the dictionary.
1846 OSStatus
SecTrustEvaluateLeafOnly(SecTrustRef trust
, SecTrustResultType
*result
) {
1850 OSStatus status
= errSecSuccess
;
1851 SecTrustResultType trustResult
= kSecTrustResultInvalid
;
1852 if((status
= SecTrustValidateInput(trust
))) {
1856 struct OpaqueSecLeafPVC pvc
;
1857 SecCertificateRef leaf
= SecTrustGetCertificateAtIndex(trust
, 0);
1858 __block CFArrayRef policies
= NULL
;
1859 dispatch_sync(trust
->_trustQueue
, ^{
1860 policies
= CFRetainSafe(trust
->_policies
);
1862 SecLeafPVCInit(&pvc
, leaf
, policies
, SecTrustGetVerifyTime(trust
));
1864 if(!SecLeafPVCLeafChecks(&pvc
)) {
1865 trustResult
= kSecTrustResultRecoverableTrustFailure
;
1867 trustResult
= kSecTrustResultUnspecified
;
1870 /* Set other result context information */
1871 dispatch_sync(trust
->_trustQueue
, ^{
1872 trust
->_trustResult
= trustResult
;
1873 trust
->_details
= CFRetainSafe(pvc
.details
);
1874 trust
->_info
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0,
1875 &kCFTypeDictionaryKeyCallBacks
,
1876 &kCFTypeDictionaryValueCallBacks
);
1877 trust
->_chain
= SecCertificatePathCreate(NULL
, (SecCertificateRef
)CFArrayGetValueAtIndex(trust
->_certificates
, 0), NULL
);
1880 SecLeafPVCDelete(&pvc
);
1882 /* log to syslog when there is a trust failure */
1883 if (trustResult
!= kSecTrustResultUnspecified
) {
1884 CFStringRef failureDesc
= SecTrustCopyFailureDescription(trust
);
1885 secerror("%@", failureDesc
);
1886 CFRelease(failureDesc
);
1890 *result
= trustResult
;
1893 CFReleaseSafe(policies
);
1897 static void deserializeCert(const void *value
, void *context
) {
1898 CFDataRef certData
= (CFDataRef
)value
;
1899 if (isData(certData
)) {
1900 SecCertificateRef cert
= SecCertificateCreateWithData(NULL
, certData
);
1902 CFArrayAppendValue((CFMutableArrayRef
)context
, cert
);
1908 static CF_RETURNS_RETAINED CFArrayRef
SecCertificateArrayDeserialize(CFArrayRef serializedCertificates
) {
1909 CFMutableArrayRef result
= NULL
;
1910 require_quiet(isArray(serializedCertificates
), errOut
);
1911 CFIndex count
= CFArrayGetCount(serializedCertificates
);
1912 result
= CFArrayCreateMutable(kCFAllocatorDefault
, count
, &kCFTypeArrayCallBacks
);
1913 CFRange all_certs
= { 0, count
};
1914 CFArrayApplyFunction(serializedCertificates
, all_certs
, deserializeCert
, result
);
1919 static void serializeCertificate(const void *value
, void *context
) {
1920 SecCertificateRef cert
= (SecCertificateRef
)value
;
1921 if (cert
&& SecCertificateGetTypeID() == CFGetTypeID(cert
)) {
1922 CFDataRef certData
= SecCertificateCopyData(cert
);
1924 CFArrayAppendValue((CFMutableArrayRef
)context
, certData
);
1925 CFRelease(certData
);
1930 static CFArrayRef
SecCertificateArraySerialize(CFArrayRef certificates
) {
1931 CFMutableArrayRef result
= NULL
;
1932 require_quiet(isArray(certificates
), errOut
);
1933 CFIndex count
= CFArrayGetCount(certificates
);
1934 result
= CFArrayCreateMutable(NULL
, count
, &kCFTypeArrayCallBacks
);
1935 CFRange all_certificates
= { 0, count
};
1936 CFArrayApplyFunction(certificates
, all_certificates
, serializeCertificate
, result
);
1941 static CFPropertyListRef
SecTrustCopyPlist(SecTrustRef trust
) {
1942 __block CFMutableDictionaryRef output
= NULL
;
1943 output
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
,
1944 &kCFTypeDictionaryValueCallBacks
);
1946 dispatch_sync(trust
->_trustQueue
, ^{
1947 if (trust
->_certificates
) {
1948 CFArrayRef serializedCerts
= SecCertificateArraySerialize(trust
->_certificates
);
1949 if (serializedCerts
) {
1950 CFDictionaryAddValue(output
, CFSTR(kSecTrustCertificatesKey
), serializedCerts
);
1951 CFRelease(serializedCerts
);
1954 if (trust
->_anchors
) {
1955 CFArrayRef serializedAnchors
= SecCertificateArraySerialize(trust
->_anchors
);
1956 if (serializedAnchors
) {
1957 CFDictionaryAddValue(output
, CFSTR(kSecTrustAnchorsKey
), serializedAnchors
);
1958 CFRelease(serializedAnchors
);
1961 if (trust
->_policies
) {
1962 CFArrayRef serializedPolicies
= SecPolicyArrayCreateSerialized(trust
->_policies
);
1963 if (serializedPolicies
) {
1964 CFDictionaryAddValue(output
, CFSTR(kSecTrustPoliciesKey
), serializedPolicies
);
1965 CFRelease(serializedPolicies
);
1968 if (trust
->_responses
) {
1969 CFDictionaryAddValue(output
, CFSTR(kSecTrustResponsesKey
), trust
->_responses
);
1972 CFDictionaryAddValue(output
, CFSTR(kSecTrustSCTsKey
), trust
->_SCTs
);
1974 if (trust
->_trustedLogs
) {
1975 CFDictionaryAddValue(output
, CFSTR(kSecTrustTrustedLogsKey
), trust
->_trustedLogs
);
1977 if (trust
->_verifyDate
) {
1978 CFDictionaryAddValue(output
, CFSTR(kSecTrustVerifyDateKey
), trust
->_verifyDate
);
1980 if (trust
->_chain
) {
1981 CFArrayRef serializedChain
= SecCertificatePathCreateSerialized(trust
->_chain
, NULL
);
1982 if (serializedChain
) {
1983 CFDictionaryAddValue(output
, CFSTR(kSecTrustChainKey
), serializedChain
);
1984 CFRelease(serializedChain
);
1987 if (trust
->_details
) {
1988 CFDictionaryAddValue(output
, CFSTR(kSecTrustDetailsKey
), trust
->_details
);
1991 CFDictionaryAddValue(output
, CFSTR(kSecTrustInfoKey
), trust
->_info
);
1993 if (trust
->_exceptions
) {
1994 CFDictionaryAddValue(output
, CFSTR(kSecTrustExceptionsKey
), trust
->_exceptions
);
1996 CFNumberRef trustResult
= CFNumberCreate(NULL
, kCFNumberSInt32Type
, &trust
->_trustResult
);
1998 CFDictionaryAddValue(output
, CFSTR(kSecTrustResultKey
), trustResult
);
2000 CFReleaseNull(trustResult
);
2001 if (trust
->_anchorsOnly
) {
2002 CFDictionaryAddValue(output
, CFSTR(kSecTrustAnchorsOnlyKey
), kCFBooleanTrue
);
2004 CFDictionaryAddValue(output
, CFSTR(kSecTrustAnchorsOnlyKey
), kCFBooleanFalse
);
2006 if (trust
->_keychainsAllowed
) {
2007 CFDictionaryAddValue(output
, CFSTR(kSecTrustKeychainsAllowedKey
), kCFBooleanTrue
);
2009 CFDictionaryAddValue(output
, CFSTR(kSecTrustKeychainsAllowedKey
), kCFBooleanFalse
);
2016 CFDataRef
SecTrustSerialize(SecTrustRef trust
, CFErrorRef
*error
) {
2017 CFPropertyListRef plist
= NULL
;
2018 CFDataRef derTrust
= NULL
;
2019 require_action_quiet(trust
, out
,
2020 SecError(errSecParam
, error
, CFSTR("null trust input")));
2021 require_action_quiet(plist
= SecTrustCopyPlist(trust
), out
,
2022 SecError(errSecDecode
, error
, CFSTR("unable to create trust plist")));
2023 require_quiet(derTrust
= CFPropertyListCreateDERData(NULL
, plist
, error
), out
);
2026 CFReleaseNull(plist
);
2030 static OSStatus
SecTrustCreateFromPlist(CFPropertyListRef plist
, SecTrustRef CF_RETURNS_RETAINED
*trust
) {
2031 OSStatus status
= errSecParam
;
2032 SecTrustRef output
= NULL
;
2033 CFTypeRef serializedCertificates
= NULL
, serializedPolicies
= NULL
, serializedAnchors
= NULL
,
2034 serializedChain
= NULL
;
2035 CFNumberRef trustResultNum
= NULL
;
2036 CFArrayRef certificates
= NULL
, policies
= NULL
, anchors
= NULL
, responses
= NULL
,
2037 SCTs
= NULL
, trustedLogs
= NULL
, details
= NULL
, exceptions
= NULL
;
2038 CFDateRef verifyDate
= NULL
;
2039 CFDictionaryRef info
= NULL
;
2040 SecCertificatePathRef chain
= NULL
;
2042 require_quiet(CFDictionaryGetTypeID() == CFGetTypeID(plist
), out
);
2043 require_quiet(serializedCertificates
= CFDictionaryGetValue(plist
, CFSTR(kSecTrustCertificatesKey
)), out
);
2044 require_quiet(certificates
= SecCertificateArrayDeserialize(serializedCertificates
), out
);
2045 require_quiet(serializedPolicies
= CFDictionaryGetValue(plist
, CFSTR(kSecTrustPoliciesKey
)), out
);
2046 require_quiet(policies
= SecPolicyArrayCreateDeserialized(serializedPolicies
), out
);
2047 require_noerr_quiet(status
= SecTrustCreateWithCertificates(certificates
, policies
, &output
), out
);
2049 serializedAnchors
= CFDictionaryGetValue(plist
, CFSTR(kSecTrustAnchorsKey
));
2050 if (isArray(serializedAnchors
)) {
2051 anchors
= SecCertificateArrayDeserialize(serializedAnchors
);
2052 output
->_anchors
= anchors
;
2054 responses
= CFDictionaryGetValue(plist
, CFSTR(kSecTrustResponsesKey
));
2055 if (isArray(responses
)) {
2056 output
->_responses
= CFRetainSafe(responses
);
2058 SCTs
= CFDictionaryGetValue(plist
, CFSTR(kSecTrustSCTsKey
));
2059 if (isArray(responses
)) {
2060 output
->_SCTs
= CFRetainSafe(SCTs
);
2062 trustedLogs
= CFDictionaryGetValue(plist
, CFSTR(kSecTrustTrustedLogsKey
));
2063 if (isArray(trustedLogs
)) {
2064 output
->_trustedLogs
= CFRetainSafe(trustedLogs
);
2066 verifyDate
= CFDictionaryGetValue(plist
, CFSTR(kSecTrustVerifyDateKey
));
2067 if (isDate(verifyDate
)) {
2068 output
->_verifyDate
= CFRetainSafe(verifyDate
);
2070 serializedChain
= CFDictionaryGetValue(plist
, CFSTR(kSecTrustChainKey
));
2071 if (isArray(serializedChain
)) {
2072 chain
= SecCertificatePathCreateDeserialized(serializedChain
, NULL
);
2073 output
->_chain
= chain
;
2075 details
= CFDictionaryGetValue(plist
, CFSTR(kSecTrustDetailsKey
));
2076 if (isArray(details
)) {
2077 output
->_details
= CFRetainSafe(details
);
2079 info
= CFDictionaryGetValue(plist
, CFSTR(kSecTrustInfoKey
));
2080 if (isDictionary(info
)) {
2081 output
->_info
= CFRetainSafe(info
);
2083 exceptions
= CFDictionaryGetValue(plist
, CFSTR(kSecTrustExceptionsKey
));
2084 if (isArray(exceptions
)) {
2085 output
->_exceptions
= CFRetainSafe(exceptions
);
2087 int32_t trustResult
= -1;
2088 trustResultNum
= CFDictionaryGetValue(plist
, CFSTR(kSecTrustResultKey
));
2089 if (isNumber(trustResultNum
) && CFNumberGetValue(trustResultNum
, kCFNumberSInt32Type
, &trustResult
) &&
2090 (trustResult
>= 0)) {
2091 output
->_trustResult
= trustResult
;
2093 status
= errSecParam
;
2095 if (CFDictionaryGetValue(plist
, CFSTR(kSecTrustAnchorsOnlyKey
)) == kCFBooleanTrue
) {
2096 output
->_anchorsOnly
= true;
2097 } /* false is set by default */
2098 if (CFDictionaryGetValue(plist
, CFSTR(kSecTrustKeychainsAllowedKey
)) == kCFBooleanFalse
) {
2099 output
->_keychainsAllowed
= false;
2100 } /* true is set by default */
2103 if (errSecSuccess
== status
&& trust
) {
2106 CFReleaseNull(policies
);
2107 CFReleaseNull(certificates
);
2111 SecTrustRef
SecTrustDeserialize(CFDataRef serializedTrust
, CFErrorRef
*error
) {
2112 SecTrustRef trust
= NULL
;
2113 CFPropertyListRef plist
= NULL
;
2114 OSStatus status
= errSecSuccess
;
2115 require_action_quiet(serializedTrust
, out
,
2116 SecError(errSecParam
, error
, CFSTR("null serialized trust input")));
2117 require_quiet(plist
= CFPropertyListCreateWithDERData(NULL
, serializedTrust
,
2118 kCFPropertyListImmutable
, NULL
, error
), out
);
2119 require_noerr_action_quiet(status
= SecTrustCreateFromPlist(plist
, &trust
), out
,
2120 SecError(status
, error
, CFSTR("unable to create trust ref")));
2123 CFReleaseNull(plist
);