2 * Copyright (c) 2006-2017 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/SecCertificatePath.h>
33 #include <Security/SecFramework.h>
34 #include <Security/SecPolicyCerts.h>
35 #include <Security/SecPolicyInternal.h>
36 #include <Security/SecPolicyPriv.h>
37 #include <Security/SecuritydXPC.h>
38 #include <Security/SecInternal.h>
39 #include <Security/SecBasePriv.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 <AssertMacros.h>
52 #include <os/activity.h>
54 #include <utilities/SecIOFormat.h>
55 #include <utilities/SecCFError.h>
56 #include <utilities/SecCFWrappers.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 (kSecCertificateDetailSHA1Digest
, "SHA1Digest");
71 SEC_CONST_DECL (kSecCertificateDetailStatusCodes
, "StatusCodes");
73 SEC_CONST_DECL (kSecTrustInfoExtendedValidationKey
, "ExtendedValidation");
74 SEC_CONST_DECL (kSecTrustInfoCompanyNameKey
, "CompanyName");
75 SEC_CONST_DECL (kSecTrustInfoRevocationKey
, "Revocation");
76 SEC_CONST_DECL (kSecTrustInfoRevocationValidUntilKey
, "RevocationValidUntil");
77 SEC_CONST_DECL (kSecTrustInfoCertificateTransparencyKey
, "CertificateTransparency");
79 /* Public trust result constants */
80 SEC_CONST_DECL (kSecTrustEvaluationDate
, "TrustEvaluationDate");
81 SEC_CONST_DECL (kSecTrustExtendedValidation
, "TrustExtendedValidation");
82 SEC_CONST_DECL (kSecTrustOrganizationName
, "Organization");
83 SEC_CONST_DECL (kSecTrustResultValue
, "TrustResultValue");
84 SEC_CONST_DECL (kSecTrustRevocationChecked
, "TrustRevocationChecked");
85 SEC_CONST_DECL (kSecTrustRevocationReason
, "TrustRevocationReason");
86 SEC_CONST_DECL (kSecTrustRevocationValidUntilDate
, "TrustExpirationDate");
87 SEC_CONST_DECL (kSecTrustResultDetails
, "TrustResultDetails");
88 SEC_CONST_DECL (kSecTrustCertificateTransparency
, "TrustCertificateTransparency");
89 SEC_CONST_DECL (kSecTrustCertificateTransparencyWhiteList
, "TrustCertificateTransparencyWhiteList");
94 /********************************************************
95 ****************** SecTrust object *********************
96 ********************************************************/
99 CFArrayRef _certificates
;
102 CFArrayRef _responses
;
104 CFArrayRef _trustedLogs
;
105 CFDateRef _verifyDate
;
106 SecCertificatePathRef _chain
;
107 SecKeyRef _publicKey
;
109 CFDictionaryRef _info
;
110 CFArrayRef _exceptions
;
112 /* Note that a value of kSecTrustResultInvalid (0)
113 * indicates the trust must be (re)evaluated; any
114 * functions which modify trust parameters in a way
115 * that would invalidate the current result must set
116 * this value back to kSecTrustResultInvalid.
118 SecTrustResultType _trustResult
;
120 /* If true we don't trust any anchors other than the ones in _anchors. */
122 /* If false we shouldn't search keychains for parents or anchors. */
123 bool _keychainsAllowed
;
125 /* Data blobs for legacy CSSM_TP_APPLE_EVIDENCE_INFO structure,
126 * to support callers of SecTrustGetResult on OS X. Since fields of
127 * one structure contain pointers into the other, these cannot be
128 * serialized; if a SecTrust is being serialized or copied, these values
129 * should just be initialized to NULL in the copy and built when needed. */
130 void* _legacy_info_array
;
131 void* _legacy_status_array
;
133 /* Dispatch queue for thread-safety */
134 dispatch_queue_t _trustQueue
;
136 /* === IMPORTANT! ===
137 * Any change to this structure definition
138 * must also be made in the TSecTrust structure,
139 * located in SecTrust.cpp. To avoid problems,
140 * new fields should always be appended at the
141 * end of the structure.
145 /* Forward declarations of static functions. */
146 static OSStatus
SecTrustEvaluateIfNecessary(SecTrustRef trust
);
148 /* Static functions. */
149 static CFStringRef
SecTrustCopyFormatDescription(CFTypeRef cf
, CFDictionaryRef formatOptions
) {
150 SecTrustRef trust
= (SecTrustRef
)cf
;
151 return CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
,
152 CFSTR("<SecTrustRef: %p>"), trust
);
155 static void SecTrustDestroy(CFTypeRef cf
) {
156 SecTrustRef trust
= (SecTrustRef
)cf
;
158 dispatch_release_null(trust
->_trustQueue
);
159 CFReleaseNull(trust
->_certificates
);
160 CFReleaseNull(trust
->_policies
);
161 CFReleaseNull(trust
->_responses
);
162 CFReleaseNull(trust
->_SCTs
);
163 CFReleaseNull(trust
->_trustedLogs
);
164 CFReleaseNull(trust
->_verifyDate
);
165 CFReleaseNull(trust
->_anchors
);
166 CFReleaseNull(trust
->_chain
);
167 CFReleaseNull(trust
->_publicKey
);
168 CFReleaseNull(trust
->_details
);
169 CFReleaseNull(trust
->_info
);
170 CFReleaseNull(trust
->_exceptions
);
172 if (trust
->_legacy_info_array
) {
173 free(trust
->_legacy_info_array
);
175 if (trust
->_legacy_status_array
) {
176 free(trust
->_legacy_status_array
);
180 /* Public API functions. */
181 CFGiblisFor(SecTrust
)
183 OSStatus
SecTrustCreateWithCertificates(CFTypeRef certificates
,
184 CFTypeRef policies
, SecTrustRef
*trust
) {
185 OSStatus status
= errSecParam
;
186 CFAllocatorRef allocator
= kCFAllocatorDefault
;
187 CFArrayRef l_certs
= NULL
, l_policies
= NULL
;
188 SecTrustRef result
= NULL
;
189 dispatch_queue_t queue
= NULL
;
193 CFTypeID certType
= CFGetTypeID(certificates
);
194 if (certType
== CFArrayGetTypeID()) {
195 CFIndex idx
, count
= CFArrayGetCount(certificates
);
196 /* We need at least 1 certificate. */
197 require_quiet(count
> 0, errOut
);
198 l_certs
= (CFArrayRef
) CFArrayCreateMutable(allocator
, count
,
199 &kCFTypeArrayCallBacks
);
201 status
= errSecAllocate
;
204 for (idx
= 0; idx
< count
; idx
++) {
205 CFTypeRef val
= CFArrayGetValueAtIndex(certificates
, idx
);
206 if (val
) { CFArrayAppendValue((CFMutableArrayRef
)l_certs
, val
); }
208 require_quiet(count
== CFArrayGetCount(l_certs
), errOut
);
209 } else if (certType
== SecCertificateGetTypeID()) {
210 l_certs
= CFArrayCreate(allocator
, &certificates
, 1,
211 &kCFTypeArrayCallBacks
);
216 status
= errSecAllocate
;
221 CFTypeRef policy
= SecPolicyCreateBasicX509();
222 l_policies
= CFArrayCreate(allocator
, &policy
, 1,
223 &kCFTypeArrayCallBacks
);
226 else if (CFGetTypeID(policies
) == CFArrayGetTypeID()) {
227 CFIndex idx
, count
= CFArrayGetCount(policies
);
228 /* We need at least 1 policy. */
229 require_quiet(count
> 0, errOut
);
230 l_policies
= (CFArrayRef
) CFArrayCreateMutable(allocator
, count
,
231 &kCFTypeArrayCallBacks
);
233 status
= errSecAllocate
;
236 for (idx
= 0; idx
< count
; idx
++) {
237 CFTypeRef val
= CFArrayGetValueAtIndex(policies
, idx
);
238 if (val
) { CFArrayAppendValue((CFMutableArrayRef
)l_policies
, val
); }
240 require_quiet(count
== CFArrayGetCount(l_policies
), errOut
);
242 else if (CFGetTypeID(policies
) == SecPolicyGetTypeID()) {
243 l_policies
= CFArrayCreate(allocator
, &policies
, 1,
244 &kCFTypeArrayCallBacks
);
249 status
= errSecAllocate
;
253 queue
= dispatch_queue_create("trust", DISPATCH_QUEUE_SERIAL
);
255 status
= errSecAllocate
;
259 CFIndex size
= sizeof(struct __SecTrust
);
260 require_quiet(result
= (SecTrustRef
)_CFRuntimeCreateInstance(allocator
,
261 SecTrustGetTypeID(), size
- sizeof(CFRuntimeBase
), 0), errOut
);
262 memset((char*)result
+ sizeof(result
->_base
), 0,
263 sizeof(*result
) - sizeof(result
->_base
));
264 status
= errSecSuccess
;
268 CFReleaseSafe(result
);
269 CFReleaseSafe(l_certs
);
270 CFReleaseSafe(l_policies
);
271 dispatch_release_null(queue
);
273 result
->_certificates
= l_certs
;
274 result
->_policies
= l_policies
;
275 result
->_keychainsAllowed
= true;
276 result
->_trustQueue
= queue
;
280 CFReleaseSafe(result
);
285 OSStatus
SecTrustCopyInputCertificates(SecTrustRef trust
, CFArrayRef
*certificates
) {
286 if (!trust
|| !certificates
) {
289 __block CFArrayRef certArray
= NULL
;
290 dispatch_sync(trust
->_trustQueue
, ^{
291 certArray
= CFArrayCreateCopy(NULL
, trust
->_certificates
);
294 return errSecAllocate
;
296 *certificates
= certArray
;
297 return errSecSuccess
;
300 OSStatus
SecTrustAddToInputCertificates(SecTrustRef trust
, CFTypeRef certificates
) {
301 if (!trust
|| !certificates
) {
304 __block CFMutableArrayRef newCertificates
= NULL
;
305 dispatch_sync(trust
->_trustQueue
, ^{
306 newCertificates
= CFArrayCreateMutableCopy(NULL
, 0, trust
->_certificates
);
309 if (isArray(certificates
)) {
310 CFArrayAppendArray(newCertificates
, certificates
,
311 CFRangeMake(0, CFArrayGetCount(certificates
)));
312 } else if (CFGetTypeID(certificates
) == SecCertificateGetTypeID()) {
313 CFArrayAppendValue(newCertificates
, certificates
);
315 CFReleaseNull(newCertificates
);
319 dispatch_sync(trust
->_trustQueue
, ^{
320 CFReleaseNull(trust
->_certificates
);
321 trust
->_certificates
= (CFArrayRef
)newCertificates
;
324 return errSecSuccess
;
327 static void SecTrustSetNeedsEvaluation(SecTrustRef trust
) {
330 dispatch_sync(trust
->_trustQueue
, ^{
331 trust
->_trustResult
= kSecTrustResultInvalid
;
336 OSStatus
SecTrustSetAnchorCertificatesOnly(SecTrustRef trust
,
337 Boolean anchorCertificatesOnly
) {
341 SecTrustSetNeedsEvaluation(trust
);
342 trust
->_anchorsOnly
= anchorCertificatesOnly
;
344 return errSecSuccess
;
347 OSStatus
SecTrustSetAnchorCertificates(SecTrustRef trust
,
348 CFArrayRef anchorCertificates
) {
352 SecTrustSetNeedsEvaluation(trust
);
353 __block CFArrayRef anchorsArray
= NULL
;
354 if (anchorCertificates
) {
355 if (CFGetTypeID(anchorCertificates
) == CFArrayGetTypeID()) {
356 CFIndex idx
, count
= CFArrayGetCount(anchorCertificates
);
357 anchorsArray
= (CFArrayRef
) CFArrayCreateMutable(NULL
, count
,
358 &kCFTypeArrayCallBacks
);
360 return errSecAllocate
;
362 for (idx
= 0; idx
< count
; idx
++) {
363 CFTypeRef val
= CFArrayGetValueAtIndex(anchorCertificates
, idx
);
364 if (val
) { CFArrayAppendValue((CFMutableArrayRef
)anchorsArray
, val
); }
366 if (count
!= CFArrayGetCount(anchorsArray
)) {
367 CFReleaseSafe(anchorsArray
);
375 dispatch_sync(trust
->_trustQueue
, ^{
376 CFReleaseSafe(trust
->_anchors
);
377 trust
->_anchors
= anchorsArray
;
379 trust
->_anchorsOnly
= (anchorCertificates
!= NULL
);
381 return errSecSuccess
;
384 OSStatus
SecTrustCopyCustomAnchorCertificates(SecTrustRef trust
,
385 CFArrayRef
*anchors
) {
386 if (!trust
|| !anchors
) {
389 __block CFArrayRef anchorsArray
= NULL
;
390 dispatch_sync(trust
->_trustQueue
, ^{
391 if (trust
->_anchors
) {
392 anchorsArray
= CFArrayCreateCopy(kCFAllocatorDefault
, trust
->_anchors
);
396 *anchors
= anchorsArray
;
397 return errSecSuccess
;
400 OSStatus
SecTrustSetOCSPResponse(SecTrustRef trust
, CFTypeRef responseData
) {
404 SecTrustSetNeedsEvaluation(trust
);
405 __block CFArrayRef responseArray
= NULL
;
407 if (CFGetTypeID(responseData
) == CFArrayGetTypeID()) {
408 CFIndex idx
, count
= CFArrayGetCount(responseData
);
409 responseArray
= (CFArrayRef
) CFArrayCreateMutable(NULL
, count
,
410 &kCFTypeArrayCallBacks
);
411 if (!responseArray
) {
412 return errSecAllocate
;
414 for (idx
= 0; idx
< count
; idx
++) {
415 CFTypeRef val
= CFArrayGetValueAtIndex(responseData
, idx
);
416 if (val
) { CFArrayAppendValue((CFMutableArrayRef
)responseArray
, val
); }
418 if (count
!= CFArrayGetCount(responseArray
)) {
419 CFReleaseSafe(responseArray
);
422 } else if (CFGetTypeID(responseData
) == CFDataGetTypeID()) {
423 responseArray
= CFArrayCreate(kCFAllocatorDefault
, &responseData
, 1,
424 &kCFTypeArrayCallBacks
);
430 dispatch_sync(trust
->_trustQueue
, ^{
431 CFReleaseSafe(trust
->_responses
);
432 trust
->_responses
= responseArray
;
435 return errSecSuccess
;
438 OSStatus
SecTrustSetSignedCertificateTimestamps(SecTrustRef trust
, CFArrayRef sctArray
) {
442 SecTrustSetNeedsEvaluation(trust
);
443 dispatch_sync(trust
->_trustQueue
, ^{
444 CFRetainAssign(trust
->_SCTs
, sctArray
);
446 return errSecSuccess
;
449 OSStatus
SecTrustSetTrustedLogs(SecTrustRef trust
, CFArrayRef trustedLogs
) {
453 SecTrustSetNeedsEvaluation(trust
);
454 dispatch_sync(trust
->_trustQueue
, ^{
455 CFRetainAssign(trust
->_trustedLogs
, trustedLogs
);
457 return errSecSuccess
;
460 OSStatus
SecTrustSetVerifyDate(SecTrustRef trust
, CFDateRef verifyDate
) {
464 SecTrustSetNeedsEvaluation(trust
);
466 dispatch_sync(trust
->_trustQueue
, ^{
467 CFRetainAssign(trust
->_verifyDate
, verifyDate
);
469 return errSecSuccess
;
472 OSStatus
SecTrustSetPolicies(SecTrustRef trust
, CFTypeRef newPolicies
) {
473 if (!trust
|| !newPolicies
) {
476 SecTrustSetNeedsEvaluation(trust
);
479 __block CFArrayRef policyArray
= NULL
;
480 if (CFGetTypeID(newPolicies
) == CFArrayGetTypeID()) {
481 CFIndex idx
, count
= CFArrayGetCount(newPolicies
);
482 /* We need at least 1 policy. */
486 policyArray
= (CFArrayRef
) CFArrayCreateMutable(NULL
, count
,
487 &kCFTypeArrayCallBacks
);
489 return errSecAllocate
;
491 for (idx
= 0; idx
< count
; idx
++) {
492 CFTypeRef val
= CFArrayGetValueAtIndex(newPolicies
, idx
);
493 if (val
) { CFArrayAppendValue((CFMutableArrayRef
)policyArray
, val
); }
495 if (count
!= CFArrayGetCount(policyArray
)) {
496 CFReleaseSafe(policyArray
);
499 } else if (CFGetTypeID(newPolicies
) == SecPolicyGetTypeID()) {
500 policyArray
= CFArrayCreate(kCFAllocatorDefault
, &newPolicies
, 1,
501 &kCFTypeArrayCallBacks
);
506 dispatch_sync(trust
->_trustQueue
, ^{
507 CFReleaseSafe(trust
->_policies
);
508 trust
->_policies
= policyArray
;
511 return errSecSuccess
;
514 OSStatus
SecTrustSetPinningPolicyName(SecTrustRef trust
, CFStringRef policyName
) {
515 if (!trust
|| !policyName
) {
519 SecTrustSetNeedsEvaluation(trust
);
521 dispatch_sync(trust
->_trustQueue
, ^{
522 CFArrayForEach(trust
->_policies
, ^(const void *value
) {
523 SecPolicyRef policy
= (SecPolicyRef
)value
;
524 SecPolicySetName(policy
, policyName
);
527 return errSecSuccess
;
530 OSStatus
SecTrustSetKeychainsAllowed(SecTrustRef trust
, Boolean allowed
) {
534 SecTrustSetNeedsEvaluation(trust
);
535 trust
->_keychainsAllowed
= allowed
;
537 return errSecSuccess
;
540 OSStatus
SecTrustGetKeychainsAllowed(SecTrustRef trust
, Boolean
*allowed
) {
541 if (!trust
|| !allowed
) {
544 *allowed
= trust
->_keychainsAllowed
;
546 return errSecSuccess
;
549 OSStatus
SecTrustCopyPolicies(SecTrustRef trust
, CFArrayRef
*policies
) {
550 if (!trust
|| !policies
) {
553 __block CFArrayRef policyArray
= NULL
;
554 dispatch_sync(trust
->_trustQueue
, ^{
555 policyArray
= CFArrayCreateCopy(kCFAllocatorDefault
, trust
->_policies
);
558 return errSecAllocate
;
560 *policies
= policyArray
;
561 return errSecSuccess
;
564 static OSStatus
SecTrustSetOptionInPolicies(CFArrayRef policies
, CFStringRef key
, CFTypeRef value
) {
565 OSStatus status
= errSecSuccess
;
566 require_action(policies
&& CFGetTypeID(policies
) == CFArrayGetTypeID(), out
, status
= errSecInternal
);
567 for (int i
=0; i
< CFArrayGetCount(policies
); i
++) {
568 SecPolicyRef policy
= NULL
;
569 require_action_quiet(policy
= (SecPolicyRef
)CFArrayGetValueAtIndex(policies
, i
), out
, status
= errSecInternal
);
570 CFMutableDictionaryRef options
= NULL
;
571 require_action_quiet(options
= CFDictionaryCreateMutableCopy(NULL
, 0, policy
->_options
), out
, status
= errSecAllocate
);
572 CFDictionaryAddValue(options
, key
, value
);
573 CFReleaseNull(policy
->_options
);
574 policy
->_options
= options
;
580 static OSStatus
SecTrustRemoveOptionInPolicies(CFArrayRef policies
, CFStringRef key
) {
581 OSStatus status
= errSecSuccess
;
582 require_action(policies
&& CFGetTypeID(policies
) == CFArrayGetTypeID(), out
, status
= errSecInternal
);
583 for (int i
=0; i
< CFArrayGetCount(policies
); i
++) {
584 SecPolicyRef policy
= NULL
;
585 require_action_quiet(policy
= (SecPolicyRef
)CFArrayGetValueAtIndex(policies
, i
), out
, status
= errSecInternal
);
586 if (CFDictionaryGetValue(policy
->_options
, key
)) {
587 CFMutableDictionaryRef options
= NULL
;
588 require_action_quiet(options
= CFDictionaryCreateMutableCopy(NULL
, 0, policy
->_options
), out
, status
= errSecAllocate
);
589 CFDictionaryRemoveValue(options
, key
);
590 CFReleaseNull(policy
->_options
);
591 policy
->_options
= options
;
598 static CF_RETURNS_RETAINED CFArrayRef
SecTrustCopyOptionsFromPolicies(CFArrayRef policies
, CFStringRef key
) {
599 CFMutableArrayRef foundValues
= NULL
;
600 foundValues
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
601 for (int i
=0; i
< CFArrayGetCount(policies
); i
++) {
602 SecPolicyRef policy
= (SecPolicyRef
)CFArrayGetValueAtIndex(policies
, i
);
603 CFTypeRef value
= CFDictionaryGetValue(policy
->_options
, key
);
605 CFArrayAppendValue(foundValues
, value
);
608 if (!CFArrayGetCount(foundValues
)) {
609 CFReleaseNull(foundValues
);
617 /* The only effective way to disable network fetch is within the policy options:
618 * presence of the kSecPolicyCheckNoNetworkAccess key in any of the policies
619 * will prevent network access for fetching.
620 * The current SecTrustServer implementation doesn't distinguish between network
621 * access for revocation and network access for fetching.
623 OSStatus
SecTrustSetNetworkFetchAllowed(SecTrustRef trust
, Boolean allowFetch
) {
627 __block OSStatus status
= errSecSuccess
;
628 dispatch_sync(trust
->_trustQueue
, ^{
630 status
= SecTrustSetOptionInPolicies(trust
->_policies
, kSecPolicyCheckNoNetworkAccess
, kCFBooleanTrue
);
632 status
= SecTrustRemoveOptionInPolicies(trust
->_policies
, kSecPolicyCheckNoNetworkAccess
);
638 OSStatus
SecTrustGetNetworkFetchAllowed(SecTrustRef trust
, Boolean
*allowFetch
) {
639 if (!trust
|| !allowFetch
) {
642 __block CFArrayRef foundValues
= NULL
;
643 dispatch_sync(trust
->_trustQueue
, ^{
644 foundValues
= SecTrustCopyOptionsFromPolicies(trust
->_policies
, kSecPolicyCheckNoNetworkAccess
);
651 CFReleaseNull(foundValues
);
652 return errSecSuccess
;
655 OSStatus
SecTrustSetPinningException(SecTrustRef trust
) {
656 if (!trust
) { return errSecParam
; }
657 __block OSStatus status
= errSecSuccess
;
658 dispatch_sync(trust
->_trustQueue
, ^{
659 status
= SecTrustRemoveOptionInPolicies(trust
->_policies
, kSecPolicyCheckPinningRequired
);
664 CFAbsoluteTime
SecTrustGetVerifyTime(SecTrustRef trust
) {
665 __block CFAbsoluteTime verifyTime
= CFAbsoluteTimeGetCurrent();
669 dispatch_sync(trust
->_trustQueue
, ^{
670 if (trust
->_verifyDate
) {
671 verifyTime
= CFDateGetAbsoluteTime(trust
->_verifyDate
);
673 trust
->_verifyDate
= CFDateCreate(CFGetAllocator(trust
), verifyTime
);
680 CFArrayRef
SecTrustGetDetails(SecTrustRef trust
) {
684 SecTrustEvaluateIfNecessary(trust
);
685 return trust
->_details
;
688 OSStatus
SecTrustGetTrustResult(SecTrustRef trust
,
689 SecTrustResultType
*result
) {
690 if (!trust
|| !result
) {
693 SecTrustEvaluateIfNecessary(trust
);
694 dispatch_sync(trust
->_trustQueue
, ^{
695 *result
= trust
->_trustResult
;
697 return errSecSuccess
;
700 static CFDictionaryRef
SecTrustGetExceptionForCertificateAtIndex(SecTrustRef trust
, CFIndex ix
) {
701 CFDictionaryRef exception
= NULL
;
702 __block CFArrayRef exceptions
= NULL
;
703 dispatch_sync(trust
->_trustQueue
, ^{
704 exceptions
= CFRetainSafe(trust
->_exceptions
);
706 if (!exceptions
|| ix
>= CFArrayGetCount(exceptions
)) {
710 SecCertificateRef certificate
= SecTrustGetCertificateAtIndex(trust
, ix
);
715 exception
= (CFDictionaryRef
)CFArrayGetValueAtIndex(exceptions
, ix
);
716 if (CFGetTypeID(exception
) != CFDictionaryGetTypeID()) {
721 /* If the exception contains the current certificates sha1Digest in the
722 kSecCertificateDetailSHA1Digest key then we use it otherwise we ignore it. */
723 CFDataRef sha1Digest
= SecCertificateGetSHA1Digest(certificate
);
724 CFTypeRef digestValue
= CFDictionaryGetValue(exception
, kSecCertificateDetailSHA1Digest
);
725 if (!digestValue
|| !CFEqual(sha1Digest
, digestValue
))
729 CFReleaseSafe(exceptions
);
733 CFArrayRef
SecTrustCopyFilteredDetails(SecTrustRef trust
) {
737 SecTrustEvaluateIfNecessary(trust
);
738 __block CFArrayRef details
= NULL
;
739 dispatch_sync(trust
->_trustQueue
, ^{
740 details
= CFRetainSafe(trust
->_details
);
743 /* Done automatically by the Policy Server with SecPVCIsExceptedError */
747 Boolean
SecTrustIsExpiredOnly(SecTrustRef trust
) {
748 /* Returns true if one or more certificates in the chain have expired,
749 * expiration is an error (i.e. is not covered by existing trust settings),
750 * and it is the only error encountered.
751 * Returns false if the certificate is valid, or if the trust chain has
752 * other errors beside expiration.
754 Boolean result
= false;
755 Boolean foundExpired
= false;
756 CFArrayRef details
= SecTrustCopyFilteredDetails(trust
);
757 require(details
!= NULL
, out
);
759 CFIndex ix
, pathLength
= CFArrayGetCount(details
);
760 for (ix
= 0; ix
< pathLength
; ++ix
) {
761 CFDictionaryRef detail
= (CFDictionaryRef
)CFArrayGetValueAtIndex(details
, ix
);
762 CFIndex count
= (detail
) ? CFDictionaryGetCount(detail
) : 0;
763 require(count
<= 1, out
);
765 CFStringRef key
= CFSTR("ValidIntermediates");
767 key
= CFSTR("ValidLeaf");
768 } else if (ix
== pathLength
-1) {
769 key
= CFSTR("ValidRoot");
771 CFBooleanRef valid
= (CFBooleanRef
)CFDictionaryGetValue(detail
, key
);
772 require(isBoolean(valid
) && CFEqual(valid
, kCFBooleanFalse
), out
);
776 result
= foundExpired
;
778 CFReleaseSafe(details
);
783 static CFArrayRef
SecTrustCreatePolicyAnchorsArray(const UInt8
* certData
, CFIndex certLength
)
785 CFArrayRef array
= NULL
;
786 CFAllocatorRef allocator
= kCFAllocatorDefault
;
787 SecCertificateRef cert
= SecCertificateCreateWithBytes(allocator
, certData
, certLength
);
789 array
= CFArrayCreate(allocator
, (const void **)&cert
, 1, &kCFTypeArrayCallBacks
);
796 static void SecTrustAddPolicyAnchors(SecTrustRef trust
)
798 /* Provide anchor certificates specifically required by certain policies.
799 This is used to evaluate test policies where the anchor is not provided
800 in the root store and may not be able to be supplied by the caller.
802 if (!trust
) { return; }
803 __block CFArrayRef policies
= NULL
;
804 dispatch_sync(trust
->_trustQueue
, ^{
805 policies
= CFRetain(trust
->_policies
);
807 CFIndex ix
, count
= CFArrayGetCount(policies
);
808 for (ix
= 0; ix
< count
; ++ix
) {
809 SecPolicyRef policy
= (SecPolicyRef
) CFArrayGetValueAtIndex(policies
, ix
);
812 if (CFEqual(policy
->_oid
, kSecPolicyAppleTestSMPEncryption
)) {
813 __block CFArrayRef policyAnchors
= SecTrustCreatePolicyAnchorsArray(_SEC_TestAppleRootCAECC
, sizeof(_SEC_TestAppleRootCAECC
));
814 dispatch_sync(trust
->_trustQueue
, ^{
815 CFReleaseSafe(trust
->_anchors
);
816 trust
->_anchors
= policyAnchors
;
818 trust
->_anchorsOnly
= true;
824 CFReleaseSafe(policies
);
827 // uncomment for verbose debug logging (debug builds only)
828 //#define CERT_TRUST_DUMP 1
831 static void sectrustlog(int priority
, const char *format
, ...)
836 if (priority
< LOG_NOTICE
) // log warnings and errors
840 va_start(list
, format
);
841 vsyslog(priority
, format
, list
);
846 static void sectrustshow(CFTypeRef obj
, const char *context
)
849 CFStringRef desc
= CFCopyDescription(obj
);
852 CFIndex length
= CFStringGetMaximumSizeForEncoding(CFStringGetLength(desc
), kCFStringEncodingUTF8
) + 1;
853 char* buffer
= (char*) malloc(length
);
855 Boolean converted
= CFStringGetCString(desc
, buffer
, length
, kCFStringEncodingUTF8
);
857 const char *prefix
= (context
) ? context
: "";
858 const char *separator
= (context
) ? " " : "";
859 sectrustlog(LOG_NOTICE
, "%s%s%s", prefix
, separator
, buffer
);
867 static void cert_trust_dump(SecTrustRef trust
) {
868 SecCertificateRef leaf
= SecTrustGetCertificateAtIndex(trust
, 0);
869 CFStringRef name
= (leaf
) ? SecCertificateCopySubjectSummary(leaf
) : NULL
;
870 secerror("leaf \"%@\"", name
);
871 secerror(": result = %d", (int) trust
->_trustResult
);
873 CFIndex ix
, count
= SecCertificatePathGetCount(trust
->_chain
);
874 CFMutableArrayRef chain
= CFArrayCreateMutable(kCFAllocatorDefault
, count
, &kCFTypeArrayCallBacks
);
875 for (ix
= 0; ix
< count
; ix
++) {
876 SecCertificateRef cert
= SecCertificatePathGetCertificateAtIndex(trust
->_chain
, ix
);
878 CFArrayAppendValue(chain
, cert
);
881 sectrustshow(chain
, "chain:");
882 CFReleaseSafe(chain
);
884 secerror(": %ld certificates, %ld anchors, %ld policies, %ld details",
885 (trust
->_certificates
) ? (long)CFArrayGetCount(trust
->_certificates
) : 0,
886 (trust
->_anchors
) ? (long)CFArrayGetCount(trust
->_anchors
) : 0,
887 (trust
->_policies
) ? (long)CFArrayGetCount(trust
->_policies
) : 0,
888 (trust
->_details
) ? (long)CFArrayGetCount(trust
->_details
) : 0);
890 sectrustshow(trust
->_verifyDate
, "verify date:");
891 sectrustshow(trust
->_certificates
, "certificates:");
892 sectrustshow(trust
->_anchors
, "anchors:");
893 sectrustshow(trust
->_policies
, "policies:");
894 sectrustshow(trust
->_details
, "details:");
895 sectrustshow(trust
->_info
, "info:");
900 static void cert_trust_dump(SecTrustRef trust
) {}
904 OSStatus
SecTrustEvaluate(SecTrustRef trust
, SecTrustResultType
*result
) {
906 *result
= kSecTrustResultInvalid
;
911 OSStatus status
= SecTrustEvaluateIfNecessary(trust
);
915 /* post-process trust result based on exceptions */
916 __block SecTrustResultType trustResult
= kSecTrustResultInvalid
;
917 dispatch_sync(trust
->_trustQueue
, ^{
918 trustResult
= trust
->_trustResult
;
921 /* log to syslog when there is a trust failure */
922 if (trustResult
!= kSecTrustResultProceed
&&
923 trustResult
!= kSecTrustResultUnspecified
) {
924 CFStringRef failureDesc
= SecTrustCopyFailureDescription(trust
);
925 secerror("%{public}@", failureDesc
);
926 CFRelease(failureDesc
);
931 *result
= trustResult
;
937 OSStatus
SecTrustEvaluateAsync(SecTrustRef trust
,
938 dispatch_queue_t queue
, SecTrustCallback result
)
941 dispatch_async(queue
, ^{
942 SecTrustResultType trustResult
;
943 if (errSecSuccess
!= SecTrustEvaluate(trust
, &trustResult
)) {
944 trustResult
= kSecTrustResultInvalid
;
946 result(trust
, trustResult
);
947 CFReleaseSafe(trust
);
949 return errSecSuccess
;
952 static bool append_certificate_to_xpc_array(SecCertificateRef certificate
, xpc_object_t xpc_certificates
);
953 static xpc_object_t
copy_xpc_certificates_array(CFArrayRef certificates
);
954 xpc_object_t
copy_xpc_policies_array(CFArrayRef policies
);
955 OSStatus
validate_array_of_items(CFArrayRef array
, CFStringRef arrayItemType
, CFTypeID itemTypeID
, bool required
);
957 static bool append_certificate_to_xpc_array(SecCertificateRef certificate
, xpc_object_t xpc_certificates
) {
961 size_t length
= SecCertificateGetLength(certificate
);
962 const uint8_t *bytes
= SecCertificateGetBytePtr(certificate
);
963 if (!length
|| !bytes
) {
966 xpc_array_set_data(xpc_certificates
, XPC_ARRAY_APPEND
, bytes
, length
);
970 static xpc_object_t
copy_xpc_certificates_array(CFArrayRef certificates
) {
971 xpc_object_t xpc_certificates
= xpc_array_create(NULL
, 0);
972 if (!xpc_certificates
) {
975 CFIndex ix
, count
= CFArrayGetCount(certificates
);
976 for (ix
= 0; ix
< count
; ++ix
) {
977 SecCertificateRef certificate
= (SecCertificateRef
) CFArrayGetValueAtIndex(certificates
, ix
);
978 #if SECTRUST_VERBOSE_DEBUG
979 size_t length
= SecCertificateGetLength(certificate
);
980 const uint8_t *bytes
= SecCertificateGetBytePtr(certificate
);
981 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
);
983 if (!append_certificate_to_xpc_array(certificate
, xpc_certificates
)) {
984 xpc_release(xpc_certificates
);
985 xpc_certificates
= NULL
;
989 return xpc_certificates
;
992 static bool SecXPCDictionarySetCertificates(xpc_object_t message
, const char *key
, CFArrayRef certificates
, CFErrorRef
*error
) {
993 xpc_object_t xpc_certificates
= copy_xpc_certificates_array(certificates
);
994 if (!xpc_certificates
) {
995 SecError(errSecAllocate
, error
, CFSTR("failed to create xpc_array of certificates"));
998 xpc_dictionary_set_value(message
, key
, xpc_certificates
);
999 xpc_release(xpc_certificates
);
1003 static bool SecXPCDictionarySetPolicies(xpc_object_t message
, const char *key
, CFArrayRef policies
, CFErrorRef
*error
) {
1004 xpc_object_t xpc_policies
= copy_xpc_policies_array(policies
);
1005 if (!xpc_policies
) {
1006 SecError(errSecAllocate
, error
, CFSTR("failed to create xpc_array of policies"));
1009 xpc_dictionary_set_value(message
, key
, xpc_policies
);
1010 xpc_release(xpc_policies
);
1015 static bool CFDataAppendToXPCArray(CFDataRef data
, xpc_object_t xpc_data_array
, CFErrorRef
*error
) {
1017 return true; // NOOP
1019 size_t length
= CFDataGetLength(data
);
1020 const uint8_t *bytes
= CFDataGetBytePtr(data
);
1021 if (!length
|| !bytes
)
1022 return SecError(errSecParam
, error
, CFSTR("invalid CFDataRef"));
1024 xpc_array_set_data(xpc_data_array
, XPC_ARRAY_APPEND
, bytes
, length
);
1029 static xpc_object_t
CFDataArrayCopyXPCArray(CFArrayRef data_array
, CFErrorRef
*error
) {
1030 xpc_object_t xpc_data_array
;
1031 require_action_quiet(xpc_data_array
= xpc_array_create(NULL
, 0), exit
,
1032 SecError(errSecAllocate
, error
, CFSTR("failed to create xpc_array")));
1033 CFIndex ix
, count
= CFArrayGetCount(data_array
);
1034 for (ix
= 0; ix
< count
; ++ix
) {
1035 if (!CFDataAppendToXPCArray((CFDataRef
)CFArrayGetValueAtIndex(data_array
, ix
), xpc_data_array
, error
)) {
1036 xpc_release(xpc_data_array
);
1042 return xpc_data_array
;
1045 static bool SecXPCDictionarySetDataArray(xpc_object_t message
, const char *key
, CFArrayRef data_array
, CFErrorRef
*error
) {
1046 xpc_object_t xpc_data_array
= CFDataArrayCopyXPCArray(data_array
, error
);
1047 if (!xpc_data_array
)
1049 xpc_dictionary_set_value(message
, key
, xpc_data_array
);
1050 xpc_release(xpc_data_array
);
1054 static bool SecXPCDictionaryCopyChainOptional(xpc_object_t message
, const char *key
, SecCertificatePathRef
*path
, CFErrorRef
*error
) {
1055 xpc_object_t xpc_path
= xpc_dictionary_get_value(message
, key
);
1060 *path
= SecCertificatePathCreateWithXPCArray(xpc_path
, error
);
1064 static int SecXPCDictionaryGetNonZeroInteger(xpc_object_t message
, const char *key
, CFErrorRef
*error
) {
1065 int64_t value
= xpc_dictionary_get_int64(message
, key
);
1067 SecError(errSecInternal
, error
, CFSTR("object for key %s is 0"), key
);
1072 static SecTrustResultType
handle_trust_evaluate_xpc(enum SecXPCOperation op
, CFArrayRef certificates
,
1073 CFArrayRef anchors
, bool anchorsOnly
,
1074 bool keychainsAllowed
, CFArrayRef policies
, CFArrayRef responses
,
1075 CFArrayRef SCTs
, CFArrayRef trustedLogs
,
1076 CFAbsoluteTime verifyTime
, __unused CFArrayRef accessGroups
, CFArrayRef exceptions
,
1077 CFArrayRef
*details
, CFDictionaryRef
*info
, SecCertificatePathRef
*chain
, CFErrorRef
*error
)
1079 __block SecTrustResultType tr
= kSecTrustResultInvalid
;
1080 securityd_send_sync_and_do(op
, error
, ^bool(xpc_object_t message
, CFErrorRef
*error
) {
1081 if (!SecXPCDictionarySetCertificates(message
, kSecTrustCertificatesKey
, certificates
, error
))
1083 if (anchors
&& !SecXPCDictionarySetCertificates(message
, kSecTrustAnchorsKey
, anchors
, error
))
1086 xpc_dictionary_set_bool(message
, kSecTrustAnchorsOnlyKey
, anchorsOnly
);
1087 xpc_dictionary_set_bool(message
, kSecTrustKeychainsAllowedKey
, keychainsAllowed
);
1088 if (!SecXPCDictionarySetPolicies(message
, kSecTrustPoliciesKey
, policies
, error
))
1090 if (responses
&& !SecXPCDictionarySetDataArray(message
, kSecTrustResponsesKey
, responses
, error
))
1092 if (SCTs
&& !SecXPCDictionarySetDataArray(message
, kSecTrustSCTsKey
, SCTs
, error
))
1094 if (trustedLogs
&& !SecXPCDictionarySetPList(message
, kSecTrustTrustedLogsKey
, trustedLogs
, error
))
1096 xpc_dictionary_set_double(message
, kSecTrustVerifyDateKey
, verifyTime
);
1097 if (exceptions
&& !SecXPCDictionarySetPList(message
, kSecTrustExceptionsKey
, exceptions
, error
))
1100 }, ^bool(xpc_object_t response
, CFErrorRef
*error
) {
1101 secdebug("trust", "response: %@", response
);
1102 return SecXPCDictionaryCopyArrayOptional(response
, kSecTrustDetailsKey
, details
, error
) &&
1103 SecXPCDictionaryCopyDictionaryOptional(response
, kSecTrustInfoKey
, info
, error
) &&
1104 SecXPCDictionaryCopyChainOptional(response
, kSecTrustChainKey
, chain
, error
) &&
1105 ((tr
= SecXPCDictionaryGetNonZeroInteger(response
, kSecTrustResultKey
, error
)) != kSecTrustResultInvalid
);
1110 OSStatus
validate_array_of_items(CFArrayRef array
, CFStringRef arrayItemType
, CFTypeID itemTypeID
, bool required
) {
1111 OSStatus result
= errSecSuccess
;
1112 CFIndex index
, count
;
1113 count
= (array
) ? CFArrayGetCount(array
) : 0;
1114 if (!count
&& required
) {
1115 secerror("no %@ in array!", arrayItemType
);
1116 result
= errSecParam
;
1118 for (index
= 0; index
< count
; index
++) {
1119 CFTypeRef item
= (CFTypeRef
) CFArrayGetValueAtIndex(array
, index
);
1121 secerror("%@ %@ (index %d)", arrayItemType
, CFSTR("reference is nil"), (int)index
);
1122 result
= errSecParam
;
1125 if (CFGetTypeID(item
) != itemTypeID
) {
1126 secerror("%@ %@ (index %d)", arrayItemType
, CFSTR("is not the expected CF type"), (int)index
);
1127 result
= errSecParam
;
1130 if (CFGetTypeID(item
) == SecCertificateGetTypeID()) {
1131 SecCertificateRef certificate
= (SecCertificateRef
) item
;
1132 CFIndex length
= SecCertificateGetLength(certificate
);
1133 const UInt8
*bytes
= SecCertificateGetBytePtr(certificate
);
1135 secerror("%@ %@ (index %d)", arrayItemType
, CFSTR("has zero length"), (int)index
);
1136 result
= errSecParam
;
1139 secerror("%@ %@ (index %d)", arrayItemType
, CFSTR("has nil bytes"), (int)index
);
1140 result
= errSecParam
;
1142 #if SECTRUST_VERBOSE_DEBUG
1143 secerror("%@[%d] of %d = %ld bytes @ 0x%lX", arrayItemType
, (int)index
, (int)count
, (size_t)length
, (uintptr_t)bytes
);
1147 if (CFGetTypeID(item
) == SecPolicyGetTypeID()) {
1148 SecPolicyRef policy
= (SecPolicyRef
) item
;
1149 CFStringRef oidStr
= policy
->_oid
;
1150 if (!oidStr
|| (CFGetTypeID(oidStr
) != CFStringGetTypeID())) {
1151 oidStr
= CFSTR("has invalid OID string!");
1152 secerror("%@ %@ (index %d)", arrayItemType
, oidStr
, (int)index
);
1154 #if SECTRUST_VERBOSE_DEBUG
1155 secerror("%@[%d] of %d = \"%@\" 0x%lX", arrayItemType
, (int)index
, (int)count
, oidStr
, (uintptr_t)policy
);
1162 static OSStatus
SecTrustValidateInput(SecTrustRef trust
) {
1163 OSStatus status
, result
= errSecSuccess
;
1165 // certificates (required)
1166 status
= validate_array_of_items(trust
->_certificates
, CFSTR("certificate"), SecCertificateGetTypeID(), true);
1167 if (status
) result
= status
;
1168 // anchors (optional)
1169 status
= validate_array_of_items(trust
->_anchors
, CFSTR("input anchor"), SecCertificateGetTypeID(), false);
1170 if (status
) result
= status
;
1171 // policies (required??)
1172 status
= validate_array_of_items(trust
->_policies
, CFSTR("policy"), SecPolicyGetTypeID(), true);
1173 if (status
) result
= status
;
1174 // _responses, _SCTs, _trustedLogs, ...
1175 // verify time: SecTrustGetVerifyTime(trust)
1176 // access groups: SecAccessGroupsGetCurrent()
1181 static OSStatus
SecTrustEvaluateIfNecessary(SecTrustRef trust
) {
1182 __block OSStatus result
;
1187 __block CFAbsoluteTime verifyTime
= SecTrustGetVerifyTime(trust
);
1188 SecTrustAddPolicyAnchors(trust
);
1189 dispatch_sync(trust
->_trustQueue
, ^{
1190 if (trust
->_trustResult
!= kSecTrustResultInvalid
) {
1191 result
= errSecSuccess
;
1195 trust
->_trustResult
= kSecTrustResultOtherError
; /* to avoid potential recursion */
1197 CFReleaseNull(trust
->_chain
);
1198 CFReleaseNull(trust
->_details
);
1199 CFReleaseNull(trust
->_info
);
1200 if (trust
->_legacy_info_array
) {
1201 free(trust
->_legacy_info_array
);
1202 trust
->_legacy_info_array
= NULL
;
1204 if (trust
->_legacy_status_array
) {
1205 free(trust
->_legacy_status_array
);
1206 trust
->_legacy_status_array
= NULL
;
1209 os_activity_initiate("SecTrustEvaluateIfNecessary", OS_ACTIVITY_FLAG_DEFAULT
, ^{
1210 SecTrustValidateInput(trust
);
1212 /* @@@ 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. */
1213 result
= SecOSStatusWith(^bool (CFErrorRef
*error
) {
1214 trust
->_trustResult
= TRUSTD_XPC(sec_trust_evaluate
,
1215 handle_trust_evaluate_xpc
,
1216 trust
->_certificates
, trust
->_anchors
, trust
->_anchorsOnly
, trust
->_keychainsAllowed
,
1217 trust
->_policies
, trust
->_responses
, trust
->_SCTs
, trust
->_trustedLogs
,
1218 verifyTime
, SecAccessGroupsGetCurrent(), trust
->_exceptions
,
1219 &trust
->_details
, &trust
->_info
, &trust
->_chain
, error
);
1220 if (trust
->_trustResult
== kSecTrustResultInvalid
/* TODO check domain */ &&
1221 SecErrorGetOSStatus(*error
) == errSecNotAvailable
&&
1222 CFArrayGetCount(trust
->_certificates
)) {
1223 /* We failed to talk to securityd. The only time this should
1224 happen is when we are running prior to launchd enabling
1225 registration of services. This currently happens when we
1226 are running from the ramdisk. To make ASR happy we initialize
1227 _chain and return success with a failure as the trustResult, to
1228 make it seem like we did a cert evaluation, so ASR can extract
1229 the public key from the leaf. */
1230 SecCertificateRef leafCert
= (SecCertificateRef
)CFArrayGetValueAtIndex(trust
->_certificates
, 0);
1231 CFArrayRef leafCertArray
= CFArrayCreate(NULL
, (const void**)&leafCert
, 1, &kCFTypeArrayCallBacks
);
1232 trust
->_chain
= SecCertificatePathCreateWithCertificates(leafCertArray
, NULL
);
1233 CFReleaseNull(leafCertArray
);
1235 CFReleaseNull(*error
);
1238 return trust
->_trustResult
!= kSecTrustResultInvalid
;
1245 /* Helper for the qsort below. */
1246 static int compare_strings(const void *a1
, const void *a2
) {
1247 CFStringRef s1
= *(CFStringRef
*)a1
;
1248 CFStringRef s2
= *(CFStringRef
*)a2
;
1249 return (int) CFStringCompare(s1
, s2
, kCFCompareForcedOrdering
);
1252 CFStringRef
SecTrustCopyFailureDescription(SecTrustRef trust
) {
1256 CFMutableStringRef reason
= CFStringCreateMutable(NULL
, 0);
1257 SecTrustEvaluateIfNecessary(trust
);
1258 __block CFArrayRef details
= NULL
;
1259 dispatch_sync(trust
->_trustQueue
, ^{
1260 details
= CFRetainSafe(trust
->_details
);
1262 CFIndex pathLength
= details
? CFArrayGetCount(details
) : 0;
1263 for (CFIndex ix
= 0; ix
< pathLength
; ++ix
) {
1264 CFDictionaryRef detail
= (CFDictionaryRef
)CFArrayGetValueAtIndex(details
, ix
);
1265 CFIndex dCount
= CFDictionaryGetCount(detail
);
1268 CFStringAppend(reason
, CFSTR(" [leaf"));
1269 else if (ix
== pathLength
- 1)
1270 CFStringAppend(reason
, CFSTR(" [root"));
1272 CFStringAppendFormat(reason
, NULL
, CFSTR(" [ca%" PRIdCFIndex
), ix
);
1274 const void *keys
[dCount
];
1275 CFDictionaryGetKeysAndValues(detail
, &keys
[0], NULL
);
1276 qsort(&keys
[0], dCount
, sizeof(keys
[0]), compare_strings
);
1277 for (CFIndex kix
= 0; kix
< dCount
; ++kix
) {
1278 CFStringRef key
= keys
[kix
];
1279 const void *value
= CFDictionaryGetValue(detail
, key
);
1280 CFStringAppendFormat(reason
, NULL
, CFSTR(" %@%@"), key
,
1281 (CFGetTypeID(value
) == CFBooleanGetTypeID()
1282 ? CFSTR("") : value
));
1284 CFStringAppend(reason
, CFSTR("]"));
1287 CFReleaseSafe(details
);
1292 /* On OS X we need SecTrustCopyPublicKey to give us a CDSA-based SecKeyRef,
1293 so we will refer to this one internally as SecTrustCopyPublicKey_ios,
1294 and call it from SecTrustCopyPublicKey.
1296 SecKeyRef
SecTrustCopyPublicKey_ios(SecTrustRef trust
)
1298 SecKeyRef
SecTrustCopyPublicKey(SecTrustRef trust
)
1304 __block SecKeyRef publicKey
= NULL
;
1305 dispatch_sync(trust
->_trustQueue
, ^{
1306 if (trust
->_publicKey
) {
1307 publicKey
= CFRetainSafe(trust
->_publicKey
);
1310 SecCertificateRef leaf
= (SecCertificateRef
)CFArrayGetValueAtIndex(trust
->_certificates
, 0);
1312 trust
->_publicKey
= SecCertificateCopyPublicKey_ios(leaf
);
1314 trust
->_publicKey
= SecCertificateCopyPublicKey(leaf
);
1316 if (trust
->_publicKey
) {
1317 publicKey
= CFRetainSafe(trust
->_publicKey
);
1320 /* If we couldn't get a public key from the leaf cert alone. */
1322 SecTrustEvaluateIfNecessary(trust
);
1323 dispatch_sync(trust
->_trustQueue
, ^{
1324 if (trust
->_chain
) {
1325 trust
->_publicKey
= SecCertificatePathCopyPublicKeyAtIndex(trust
->_chain
, 0);
1326 publicKey
= CFRetainSafe(trust
->_publicKey
);
1333 CFIndex
SecTrustGetCertificateCount(SecTrustRef trust
) {
1337 SecTrustEvaluateIfNecessary(trust
);
1338 __block CFIndex certCount
= 1;
1339 dispatch_sync(trust
->_trustQueue
, ^{
1340 if (trust
->_chain
) {
1341 certCount
= SecCertificatePathGetCount(trust
->_chain
);
1347 SecCertificateRef
SecTrustGetCertificateAtIndex(SecTrustRef trust
,
1352 __block SecCertificateRef cert
= NULL
;
1354 dispatch_sync(trust
->_trustQueue
, ^{
1355 cert
= (SecCertificateRef
)CFArrayGetValueAtIndex(trust
->_certificates
, 0);
1359 SecTrustEvaluateIfNecessary(trust
);
1360 dispatch_sync(trust
->_trustQueue
, ^{
1361 if (trust
->_chain
) {
1362 cert
= SecCertificatePathGetCertificateAtIndex(trust
->_chain
, ix
);
1368 CFDictionaryRef
SecTrustCopyInfo(SecTrustRef trust
) {
1372 SecTrustEvaluateIfNecessary(trust
);
1373 __block CFDictionaryRef info
= NULL
;
1374 dispatch_sync(trust
->_trustQueue
, ^{
1375 info
= CFRetainSafe(trust
->_info
);
1380 CFArrayRef
SecTrustGetTrustExceptionsArray(SecTrustRef trust
) {
1384 __block CFArrayRef exceptions
= NULL
;
1385 dispatch_sync(trust
->_trustQueue
, ^{
1386 exceptions
= trust
->_exceptions
;
1391 CFDataRef
SecTrustCopyExceptions(SecTrustRef trust
) {
1392 /* Stash the old exceptions and run an evaluation with no exceptions filtered. */
1393 __block CFArrayRef oldExceptions
= NULL
;
1394 dispatch_sync(trust
->_trustQueue
, ^{
1395 if (trust
->_exceptions
) {
1396 oldExceptions
= trust
->_exceptions
;
1397 trust
->_exceptions
= NULL
;
1400 SecTrustSetNeedsEvaluation(trust
);
1402 /* Create the new exceptions based on an unfiltered eval. */
1403 __block CFArrayRef details
= NULL
;
1404 SecTrustEvaluateIfNecessary(trust
);
1405 dispatch_sync(trust
->_trustQueue
, ^{
1406 details
= CFRetainSafe(trust
->_details
);
1408 CFIndex pathLength
= details
? CFArrayGetCount(details
) : 0;
1409 CFMutableArrayRef exceptions
= CFArrayCreateMutable(kCFAllocatorDefault
, pathLength
, &kCFTypeArrayCallBacks
);
1411 for (ix
= 0; ix
< pathLength
; ++ix
) {
1412 CFDictionaryRef detail
= (CFDictionaryRef
)CFArrayGetValueAtIndex(details
, ix
);
1413 CFIndex detailCount
= CFDictionaryGetCount(detail
);
1414 CFMutableDictionaryRef exception
;
1415 if (ix
== 0 || detailCount
> 0) {
1416 exception
= CFDictionaryCreateMutableCopy(kCFAllocatorDefault
, detailCount
+ 1, detail
);
1417 SecCertificateRef certificate
= SecTrustGetCertificateAtIndex(trust
, ix
);
1418 CFDataRef digest
= SecCertificateGetSHA1Digest(certificate
);
1419 CFDictionaryAddValue(exception
, kSecCertificateDetailSHA1Digest
, digest
);
1421 /* Add empty exception dictionaries for non leaf certs which have no exceptions to save space. */
1422 exception
= (CFMutableDictionaryRef
)CFDictionaryCreate(kCFAllocatorDefault
, NULL
, NULL
, 0,
1423 &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
1425 CFArrayAppendValue(exceptions
, exception
);
1426 CFReleaseNull(exception
);
1429 /* Restore the stashed exceptions. */
1430 if (oldExceptions
) {
1431 dispatch_sync(trust
->_trustQueue
, ^{
1432 trust
->_exceptions
= oldExceptions
;
1434 SecTrustSetNeedsEvaluation(trust
);
1437 /* Remove any trailing empty dictionaries to save even more space (we skip the leaf
1438 since it will never be empty). */
1439 for (ix
= pathLength
; ix
-- > 1;) {
1440 CFDictionaryRef exception
= (CFDictionaryRef
)CFArrayGetValueAtIndex(exceptions
, ix
);
1441 if (CFDictionaryGetCount(exception
) == 0) {
1442 CFArrayRemoveValueAtIndex(exceptions
, ix
);
1448 CFDataRef encodedExceptions
= CFPropertyListCreateData(kCFAllocatorDefault
,
1449 exceptions
, kCFPropertyListBinaryFormat_v1_0
, 0, NULL
);
1450 CFRelease(exceptions
);
1451 CFReleaseSafe(details
);
1452 return encodedExceptions
;
1455 bool SecTrustSetExceptions(SecTrustRef trust
, CFDataRef encodedExceptions
) {
1459 CFArrayRef exceptions
= NULL
;
1461 if (NULL
!= encodedExceptions
) {
1462 exceptions
= (CFArrayRef
)CFPropertyListCreateWithData(kCFAllocatorDefault
,
1463 encodedExceptions
, kCFPropertyListImmutable
, NULL
, NULL
);
1466 if (exceptions
&& CFGetTypeID(exceptions
) != CFArrayGetTypeID()) {
1467 CFRelease(exceptions
);
1471 dispatch_sync(trust
->_trustQueue
, ^{
1472 CFReleaseSafe(trust
->_exceptions
);
1473 trust
->_exceptions
= exceptions
;
1476 /* We changed the exceptions -- so we need to re-evaluate */
1477 SecTrustSetNeedsEvaluation(trust
);
1479 /* If there is a valid exception entry for our current leaf we're golden. */
1480 if (SecTrustGetExceptionForCertificateAtIndex(trust
, 0))
1483 /* The passed in exceptions didn't match our current leaf, so we discard it. */
1484 dispatch_sync(trust
->_trustQueue
, ^{
1485 CFReleaseNull(trust
->_exceptions
);
1492 SecTrustSetOptions(SecTrustRef trustRef
, SecTrustOptionFlags options
)
1494 /* bridge to support API functionality for legacy callers */
1495 OSStatus status
= errSecSuccess
;
1497 /* No options or none that trigger the exceptions behavior */
1499 0 == (options
& (kSecTrustOptionAllowExpired
|
1500 kSecTrustOptionImplicitAnchors
|
1501 kSecTrustOptionAllowExpiredRoot
))) {
1505 __block CFMutableArrayRef exceptions
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
1506 if (!exceptions
) { return errSecAllocate
; }
1508 /* Add the new options to the old_exceptions when those exceptions are tied to a particular cert.
1509 * If not tied to a particular cert, we reset the exceptions based on the input options. */
1510 CFArrayRef old_exceptions
= SecTrustGetTrustExceptionsArray(trustRef
);
1511 if (old_exceptions
&& SecTrustGetExceptionForCertificateAtIndex(trustRef
, 0)) {
1512 CFIndex ix
, count
= CFArrayGetCount(old_exceptions
);
1513 for (ix
= 0; ix
< count
; ix
++) {
1514 CFMutableDictionaryRef exception_dictionary
= CFDictionaryCreateMutableCopy(NULL
, 0, (CFDictionaryRef
)CFArrayGetValueAtIndex(old_exceptions
, ix
));
1515 if (!exception_dictionary
) { status
= errSecAllocate
; goto out
; }
1516 if ((options
& kSecTrustOptionAllowExpired
) != 0) {
1517 if (ix
== 0) { CFDictionaryAddValue(exception_dictionary
, CFSTR("ValidLeaf"), kCFBooleanFalse
); }
1518 if (ix
== (count
- 1)) { CFDictionaryAddValue(exception_dictionary
, CFSTR("ValidRoot"), kCFBooleanFalse
); }
1519 if (ix
> 0 && ix
< (count
- 1)) {
1520 CFDictionaryAddValue(exception_dictionary
, CFSTR("ValidIntermediates"), kCFBooleanFalse
); }
1522 if ((options
& kSecTrustOptionAllowExpiredRoot
) != 0) {
1523 if (ix
== (count
- 1)) { CFDictionaryAddValue(exception_dictionary
, CFSTR("ValidRoot"), kCFBooleanFalse
); }
1525 if ((options
& kSecTrustOptionImplicitAnchors
) != 0) {
1526 /* Check that root is self-signed. (Done by trustd for other case.) */
1527 Boolean isSelfSigned
= false;
1528 SecCertificateRef cert
= SecTrustGetCertificateAtIndex(trustRef
, ix
);
1529 if (cert
&& (errSecSuccess
== SecCertificateIsSelfSigned(cert
, &isSelfSigned
)) &&
1531 CFDictionaryAddValue(exception_dictionary
, CFSTR("AnchorTrusted"), kCFBooleanFalse
);
1534 CFArrayAppendValue(exceptions
, exception_dictionary
);
1535 CFReleaseNull(exception_dictionary
);
1538 /* Create a new exceptions array. Warning, this takes advantage of implementation details of the exceptions mechanism. */
1539 CFMutableDictionaryRef exception_dictionary
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
,
1540 &kCFTypeDictionaryValueCallBacks
);
1541 if (!exception_dictionary
) { status
= errSecAllocate
; goto out
; }
1542 if ((options
& kSecTrustOptionAllowExpired
) != 0) {
1543 CFDictionaryAddValue(exception_dictionary
, CFSTR("ValidLeaf"), kCFBooleanFalse
);
1544 CFDictionaryAddValue(exception_dictionary
, CFSTR("ValidIntermediates"), kCFBooleanFalse
);
1545 CFDictionaryAddValue(exception_dictionary
, CFSTR("ValidRoot"), kCFBooleanFalse
);
1547 if ((options
& kSecTrustOptionAllowExpiredRoot
) != 0) {
1548 CFDictionaryAddValue(exception_dictionary
, CFSTR("ValidRoot"), kCFBooleanFalse
);
1550 if ((options
& kSecTrustOptionImplicitAnchors
) != 0) {
1551 CFDictionaryAddValue(exception_dictionary
, CFSTR("AnchorTrusted"), kCFBooleanFalse
);
1553 CFArrayAppendValue(exceptions
, exception_dictionary
);
1554 CFReleaseNull(exception_dictionary
);
1557 /* Set exceptions */
1558 dispatch_sync(trustRef
->_trustQueue
, ^{
1559 CFReleaseSafe(trustRef
->_exceptions
);
1560 trustRef
->_exceptions
= CFRetainSafe(exceptions
);
1562 /* We changed the exceptions -- so we need to re-evaluate */
1563 SecTrustSetNeedsEvaluation(trustRef
);
1566 CFReleaseNull(exceptions
);
1571 CFArrayRef
SecTrustCopySummaryPropertiesAtIndex(SecTrustRef trust
, CFIndex ix
) {
1572 CFMutableArrayRef summary
;
1573 SecCertificateRef certificate
= SecTrustGetCertificateAtIndex(trust
, ix
);
1574 summary
= SecCertificateCopySummaryProperties(certificate
,
1575 SecTrustGetVerifyTime(trust
));
1576 /* FIXME Add more details in the failure case. */
1581 CFArrayRef
SecTrustCopyDetailedPropertiesAtIndex(SecTrustRef trust
, CFIndex ix
) {
1583 SecCertificateRef certificate
= SecTrustGetCertificateAtIndex(trust
, ix
);
1584 summary
= SecCertificateCopyProperties(certificate
);
1594 Can be on any non root cert in the chain.
1596 Short circuit: Yes (No other errors matter after this one)
1597 Non recoverable error
1598 Trust UI: Invalid certificate chain linkage
1599 Cert UI: Invalid linkage to parent certificate
1601 CFStringRef kSecPolicyCheckIdLinkage
= CFSTR("IdLinkage");
1603 /* X.509 required checks.
1604 Can be on any cert in the chain
1606 Short circuit: Yes (No other errors matter after this one)
1607 Non recoverable error
1608 Trust UI: (One or more) unsupported critical extensions found.
1610 /* If we have no names for the extention oids use:
1611 Cert UI: One or more unsupported critical extensions found (Non recoverable error).
1612 Cert UI: Unsupported 'foo', 'bar', baz' critical extensions found.
1614 CFStringRef kSecPolicyCheckCriticalExtensions
= CFSTR("CriticalExtensions");
1615 /* Cert UI: Unsupported critical Qualified Certificate Statements extension found (Non recoverable error). */
1616 CFStringRef kSecPolicyCheckQualifiedCertStatements
= CFSTR("QualifiedCertStatements");
1617 /* Cert UI: Certificate has an empty subject (and no critial subjectAltname). */
1620 Only apply to the anchor.
1622 Short circuit: No (Under discussion)
1624 Trust UI: Root certificate is not trusted (for this policy/app/host/whatever?)
1625 Cert UI: Not a valid anchor
1627 CFStringRef kSecPolicyCheckAnchorTrusted
= CFSTR("AnchorTrusted");
1628 CFStringRef kSecPolicyCheckAnchorSHA1
= CFSTR("AnchorSHA1");
1630 CFStringRef kSecPolicyCheckAnchorApple
= CFSTR("AnchorApple");
1631 CFStringRef kSecPolicyAppleAnchorIncludeTestRoots
= CFSTR("AnchorAppleTestRoots");
1634 Only applies to leaf
1638 Trust UI: (Hostname|email address) mismatch
1640 CFStringRef kSecPolicyCheckSSLHostname
= CFSTR("SSLHostname");
1642 /* Policy specific checks.
1643 Can be on any cert in the chain
1647 Trust UI: Certificate chain is not valid for the current policy.
1648 OR: (One or more) certificates in the chain are not valid for the current policy/application
1650 CFStringRef kSecPolicyCheckNonEmptySubject
= CFSTR("NonEmptySubject");
1651 /* Cert UI: Non CA certificate used as CA.
1652 Cert UI: CA certificate used as leaf.
1653 Cert UI: Cert chain length exceeded.
1654 Cert UI: Basic constraints extension not critical (non fatal).
1655 Cert UI: Leaf certificate has basic constraints extension (non fatal).
1657 CFStringRef kSecPolicyCheckBasicConstraints
= CFSTR("BasicConstraints");
1658 CFStringRef kSecPolicyCheckKeyUsage
= CFSTR("KeyUsage");
1659 CFStringRef kSecPolicyCheckExtendedKeyUsage
= CFSTR("ExtendedKeyUsage");
1660 /* Checks that the issuer of the leaf has exactly one Common Name and that it
1661 matches the specified string. */
1662 CFStringRef kSecPolicyCheckIssuerCommonName
= CFSTR("IssuerCommonName");
1663 /* Checks that the leaf has exactly one Common Name and that it has the
1664 specified string as a prefix. */
1665 CFStringRef kSecPolicyCheckSubjectCommonNamePrefix
= CFSTR("SubjectCommonNamePrefix");
1666 /* Check that the certificate chain length matches the specificed CFNumberRef
1668 CFStringRef kSecPolicyCheckChainLength
= CFSTR("ChainLength");
1669 CFStringRef kSecPolicyCheckNotValidBefore
= CFSTR("NotValidBefore");
1672 Can be on any cert in the chain
1676 Trust UI: One or more certificates have expired or are not valid yet.
1677 OS: The (root|intermediate|leaf) certificate (expired on 'date'|is not valid until 'date')
1678 Cert UI: Certificate (expired on 'date'|is not valid until 'date')
1680 CFStringRef kSecPolicyCheckValidIntermediates
= CFSTR("ValidIntermediates");
1681 CFStringRef kSecPolicyCheckValidLeaf
= CFSTR("ValidLeaf");
1682 CFStringRef kSecPolicyCheckValidRoot
= CFSTR("ValidRoot");
1686 struct TrustFailures
{
1688 bool unknownCritExtn
;
1689 bool untrustedAnchor
;
1690 bool hostnameMismatch
;
1697 static void applyDetailProperty(const void *_key
, const void *_value
,
1699 CFStringRef key
= (CFStringRef
)_key
;
1700 struct TrustFailures
*tf
= (struct TrustFailures
*)context
;
1701 if (CFGetTypeID(_value
) != CFBooleanGetTypeID()) {
1702 /* Value isn't a CFBooleanRef, oh no! */
1705 CFBooleanRef value
= (CFBooleanRef
)_value
;
1706 if (CFBooleanGetValue(value
)) {
1707 /* Not an actual failure so we don't report it. */
1711 /* @@@ FIXME: Report a different return value when something is in the
1712 details but masked out by an exception and use that below for display
1714 if (CFEqual(key
, kSecPolicyCheckIdLinkage
)) {
1715 tf
->badLinkage
= true;
1716 } else if (CFEqual(key
, kSecPolicyCheckCriticalExtensions
)
1717 || CFEqual(key
, kSecPolicyCheckQualifiedCertStatements
)) {
1718 tf
->unknownCritExtn
= true;
1719 } else if (CFEqual(key
, kSecPolicyCheckAnchorTrusted
)
1720 || CFEqual(key
, kSecPolicyCheckAnchorSHA1
)
1721 || CFEqual(key
, kSecPolicyCheckAnchorSHA256
)
1722 || CFEqual(key
, kSecPolicyCheckAnchorApple
)) {
1723 tf
->untrustedAnchor
= true;
1724 } else if (CFEqual(key
, kSecPolicyCheckSSLHostname
)) {
1725 tf
->hostnameMismatch
= true;
1726 } else if (CFEqual(key
, kSecPolicyCheckValidIntermediates
)
1727 || CFEqual(key
, kSecPolicyCheckValidLeaf
)
1728 || CFEqual(key
, kSecPolicyCheckValidRoot
)) {
1729 tf
->invalidCert
= true;
1730 } else if (CFEqual(key
, kSecPolicyCheckWeakIntermediates
)
1731 || CFEqual(key
, kSecPolicyCheckWeakLeaf
)
1732 || CFEqual(key
, kSecPolicyCheckWeakRoot
)) {
1734 } else if (CFEqual(key
, kSecPolicyCheckRevocation
)) {
1735 tf
->revocation
= true;
1737 /* Anything else is a policy failure. */
1739 if (CFEqual(key
, kSecPolicyCheckNonEmptySubject
)
1740 || CFEqual(key
, kSecPolicyCheckBasicConstraints
)
1741 || CFEqual(key
, kSecPolicyCheckKeyUsage
)
1742 || CFEqual(key
, kSecPolicyCheckExtendedKeyUsage
)
1743 || CFEqual(key
, kSecPolicyCheckIssuerCommonName
)
1744 || CFEqual(key
, kSecPolicyCheckSubjectCommonNamePrefix
)
1745 || CFEqual(key
, kSecPolicyCheckChainLength
)
1746 || CFEqual(key
, kSecPolicyCheckNotValidBefore
))
1749 tf
->policyFail
= true;
1753 static void appendError(CFMutableArrayRef properties
, CFStringRef error
) {
1754 CFStringRef localizedError
= SecFrameworkCopyLocalizedString(error
,
1755 CFSTR("SecCertificate"));
1756 if (!localizedError
) {
1757 //secerror("WARNING: localized error string was not found in Security.framework");
1758 localizedError
= CFRetain(error
);
1760 appendProperty(properties
, kSecPropertyTypeError
, NULL
, NULL
,
1762 CFReleaseNull(localizedError
);
1766 /* OS X properties array has a different structure and is implemented SecTrust.cpp. */
1767 CFArrayRef
SecTrustCopyProperties_ios(SecTrustRef trust
)
1769 CFArrayRef
SecTrustCopyProperties(SecTrustRef trust
)
1775 SecTrustEvaluateIfNecessary(trust
);
1776 __block CFArrayRef details
= NULL
;
1777 dispatch_sync(trust
->_trustQueue
, ^{
1778 details
= CFRetainSafe(trust
->_details
);
1783 struct TrustFailures tf
= {};
1785 CFIndex ix
, count
= CFArrayGetCount(details
);
1786 for (ix
= 0; ix
< count
; ++ix
) {
1787 CFDictionaryRef detail
= (CFDictionaryRef
)
1788 CFArrayGetValueAtIndex(details
, ix
);
1789 /* We now have a detail dictionary for certificate at index ix, with
1790 a key value pair for each failed policy check. Let's convert it
1791 from Ro-Man form into something a Hu-Man can understand. */
1792 CFDictionaryApplyFunction(detail
, applyDetailProperty
, &tf
);
1795 CFMutableArrayRef properties
= CFArrayCreateMutable(kCFAllocatorDefault
, 0,
1796 &kCFTypeArrayCallBacks
);
1797 /* The badLinkage and unknownCritExtn failures are short circuited, since
1798 you can't recover from those errors. */
1799 if (tf
.badLinkage
) {
1800 appendError(properties
, CFSTR("Invalid certificate chain linkage."));
1801 } else if (tf
.unknownCritExtn
) {
1802 appendError(properties
, CFSTR("One or more unsupported critical extensions found."));
1804 if (tf
.untrustedAnchor
) {
1805 appendError(properties
, CFSTR("Root certificate is not trusted."));
1807 if (tf
.hostnameMismatch
) {
1808 appendError(properties
, CFSTR("Hostname mismatch."));
1810 if (tf
.policyFail
) {
1811 appendError(properties
, CFSTR("Policy requirements not met."));
1813 if (tf
.invalidCert
) {
1814 appendError(properties
, CFSTR("One or more certificates have expired or are not valid yet."));
1817 appendError(properties
, CFSTR("One or more certificates is using a weak key size."));
1819 if (tf
.revocation
) {
1820 appendError(properties
, CFSTR("One or more certificates have been revoked."));
1824 if (CFArrayGetCount(properties
) == 0) {
1825 /* The certificate chain is trusted, return an empty plist */
1826 CFReleaseNull(properties
);
1829 CFReleaseNull(details
);
1834 static void _AppendStatusCode(CFMutableArrayRef array
, OSStatus statusCode
) {
1838 SInt32 num
= statusCode
;
1839 CFNumberRef numRef
= CFNumberCreate(NULL
, kCFNumberSInt32Type
, &num
);
1843 CFArrayAppendValue(array
, numRef
);
1848 static CFArrayRef
_SecTrustCopyDetails(SecTrustRef trust
) {
1852 __block CFArrayRef details
= NULL
;
1853 dispatch_sync(trust
->_trustQueue
, ^{
1854 details
= CFRetainSafe(trust
->_details
);
1857 // Include status codes in the per-certificate details (rdar://27930542)
1858 CFMutableArrayRef newDetails
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
1860 CFReleaseSafe(details
);
1863 CFIndex index
, chainLen
= (details
) ? CFArrayGetCount(details
) : 0;
1864 for (index
= 0; index
< chainLen
; index
++) {
1865 CFDictionaryRef detailDict
= CFArrayGetValueAtIndex(details
, index
);
1866 CFMutableDictionaryRef newDict
= CFDictionaryCreateMutableCopy(NULL
, 0, detailDict
);
1867 CFMutableArrayRef statusCodes
= CFArrayCreateMutable(kCFAllocatorDefault
,
1868 0, &kCFTypeArrayCallBacks
);
1870 CFIndex i
, numCodes
= 0;
1871 SInt32
*codes
= SecTrustCopyStatusCodes(trust
, index
, &numCodes
);
1873 for (i
= 0; i
< numCodes
; i
++) {
1874 OSStatus scode
= (OSStatus
)codes
[i
];
1875 _AppendStatusCode(statusCodes
, scode
);
1879 if (CFArrayGetCount(statusCodes
) > 0) {
1880 CFDictionarySetValue(newDict
, kSecCertificateDetailStatusCodes
, statusCodes
);
1882 CFRelease(statusCodes
);
1885 CFArrayAppendValue(newDetails
, newDict
);
1889 CFReleaseSafe(details
);
1896 CFDictionaryRef
SecTrustCopyResult(SecTrustRef trust
) {
1897 // Builds and returns a dictionary of evaluation results.
1901 __block CFMutableDictionaryRef results
= CFDictionaryCreateMutable(NULL
, 0,
1902 &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
1904 SecTrustEvaluateIfNecessary(trust
);
1905 __block CFArrayRef details
= _SecTrustCopyDetails(trust
);
1907 dispatch_sync(trust
->_trustQueue
, ^{
1908 // kSecTrustResultDetails (per-cert results)
1910 CFDictionarySetValue(results
, (const void *)kSecTrustResultDetails
, (const void *)details
);
1914 // kSecTrustResultValue (overall trust result)
1915 CFNumberRef numValue
= CFNumberCreate(NULL
, kCFNumberSInt32Type
, &trust
->_trustResult
);
1917 CFDictionarySetValue(results
, (const void *)kSecTrustResultValue
, (const void *)numValue
);
1918 CFRelease(numValue
);
1920 CFDictionaryRef info
= trust
->_info
;
1921 if (trust
->_trustResult
== kSecTrustResultInvalid
|| !info
) {
1922 return; // we have nothing more to add
1925 // kSecTrustEvaluationDate
1926 CFDateRef evaluationDate
= trust
->_verifyDate
;
1927 if (evaluationDate
) {
1928 CFDictionarySetValue(results
, (const void *)kSecTrustEvaluationDate
, (const void *)evaluationDate
);
1931 // kSecTrustCertificateTransparency
1932 CFBooleanRef ctValue
;
1933 if (CFDictionaryGetValueIfPresent(info
, kSecTrustInfoCertificateTransparencyKey
, (const void **)&ctValue
)) {
1934 CFDictionarySetValue(results
, (const void *)kSecTrustCertificateTransparency
, (const void *)ctValue
);
1937 // kSecTrustExtendedValidation
1938 CFBooleanRef evValue
;
1939 if (CFDictionaryGetValueIfPresent(info
, kSecTrustInfoExtendedValidationKey
, (const void **)&evValue
)) {
1940 CFDictionarySetValue(results
, (const void *)kSecTrustExtendedValidation
, (const void *)evValue
);
1943 // kSecTrustOrganizationName
1944 CFStringRef organizationName
;
1945 if (CFDictionaryGetValueIfPresent(info
, kSecTrustInfoCompanyNameKey
, (const void **)&organizationName
)) {
1946 CFDictionarySetValue(results
, (const void *)kSecTrustOrganizationName
, (const void *)organizationName
);
1949 // kSecTrustRevocationChecked
1950 CFBooleanRef revocationChecked
;
1951 if (CFDictionaryGetValueIfPresent(info
, kSecTrustRevocationChecked
, (const void **)&revocationChecked
)) {
1952 CFDictionarySetValue(results
, (const void *)kSecTrustRevocationChecked
, (const void *)revocationChecked
);
1955 // kSecTrustRevocationReason
1956 CFNumberRef revocationReason
;
1957 if (CFDictionaryGetValueIfPresent(info
, kSecTrustRevocationReason
, (const void **)&revocationReason
)) {
1958 CFDictionarySetValue(results
, (const void *)kSecTrustRevocationReason
, (const void *)revocationReason
);
1961 // kSecTrustRevocationValidUntilDate
1962 CFDateRef validUntilDate
;
1963 if (CFDictionaryGetValueIfPresent(info
, kSecTrustRevocationValidUntilDate
, (const void **)&validUntilDate
)) {
1964 CFDictionarySetValue(results
, (const void *)kSecTrustRevocationValidUntilDate
, (const void *)validUntilDate
);
1971 // Return 0 upon error.
1972 static int to_int_error_request(enum SecXPCOperation op
, CFErrorRef
*error
) {
1973 __block
int64_t result
= 0;
1974 securityd_send_sync_and_do(op
, error
, NULL
, ^bool(xpc_object_t response
, CFErrorRef
*error
) {
1975 result
= xpc_dictionary_get_int64(response
, kSecXPCKeyResult
);
1977 return SecError(errSecInternal
, error
, CFSTR("int64 missing in response"));
1983 // version 0 -> error, so we need to start at version 1 or later.
1984 OSStatus
SecTrustGetOTAPKIAssetVersionNumber(int* versionNumber
)
1987 os_activity_t trace_activity
= os_activity_start("SecTrustGetOTAPKIAssetVersionNumber", OS_ACTIVITY_FLAG_DEFAULT
);
1988 result
= SecOSStatusWith(^bool(CFErrorRef
*error
) {
1990 return SecError(errSecParam
, error
, CFSTR("versionNumber is NULL"));
1992 return (*versionNumber
= TRUSTD_XPC(sec_ota_pki_asset_version
, to_int_error_request
, error
)) != 0;
1995 os_activity_end(trace_activity
);
1999 #define do_if_registered(sdp, ...) if (gTrustd && gTrustd->sdp) { return gTrustd->sdp(__VA_ARGS__); }
2001 static bool xpc_dictionary_entry_is_type(xpc_object_t dictionary
, const char *key
, xpc_type_t type
)
2003 xpc_object_t value
= xpc_dictionary_get_value(dictionary
, key
);
2005 return value
&& (xpc_get_type(value
) == type
);
2008 OSStatus
SecTrustOTAPKIGetUpdatedAsset(int* didUpdateAsset
)
2010 CFErrorRef error
= NULL
;
2011 do_if_registered(sec_ota_pki_get_new_asset
, &error
);
2014 xpc_object_t message
= securityd_create_message(kSecXPCOpOTAPKIGetNewAsset
, &error
);
2017 xpc_object_t response
= securityd_message_with_reply_sync(message
, &error
);
2019 if (response
&& xpc_dictionary_entry_is_type(response
, kSecXPCKeyResult
, XPC_TYPE_INT64
))
2021 num
= (int64_t) xpc_dictionary_get_int64(response
, kSecXPCKeyResult
);
2022 xpc_release(response
);
2025 xpc_release(message
);
2028 if (NULL
!= didUpdateAsset
)
2030 *didUpdateAsset
= (int)num
;
2036 * This function performs an evaluation of the leaf certificate only, and
2037 * does so in the process that called it. Its primary use is in SecItemCopyMatching
2038 * when kSecMatchPolicy is in the dictionary.
2040 OSStatus
SecTrustEvaluateLeafOnly(SecTrustRef trust
, SecTrustResultType
*result
) {
2044 OSStatus status
= errSecSuccess
;
2045 SecTrustResultType trustResult
= kSecTrustResultInvalid
;
2046 if((status
= SecTrustValidateInput(trust
))) {
2050 struct OpaqueSecLeafPVC pvc
;
2051 SecCertificateRef leaf
= SecTrustGetCertificateAtIndex(trust
, 0);
2052 __block CFArrayRef policies
= NULL
;
2053 dispatch_sync(trust
->_trustQueue
, ^{
2054 policies
= CFRetainSafe(trust
->_policies
);
2056 SecLeafPVCInit(&pvc
, leaf
, policies
, SecTrustGetVerifyTime(trust
));
2058 if(!SecLeafPVCLeafChecks(&pvc
)) {
2059 trustResult
= kSecTrustResultRecoverableTrustFailure
;
2061 trustResult
= kSecTrustResultUnspecified
;
2064 /* Set other result context information */
2065 dispatch_sync(trust
->_trustQueue
, ^{
2066 trust
->_trustResult
= trustResult
;
2067 trust
->_details
= CFRetainSafe(pvc
.details
);
2068 trust
->_info
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0,
2069 &kCFTypeDictionaryKeyCallBacks
,
2070 &kCFTypeDictionaryValueCallBacks
);
2071 CFMutableArrayRef leafCert
= CFArrayCreateMutableCopy(NULL
, 1, trust
->_certificates
);
2072 trust
->_chain
= SecCertificatePathCreateWithCertificates(leafCert
, NULL
);
2073 CFReleaseNull(leafCert
);
2076 SecLeafPVCDelete(&pvc
);
2078 /* log to syslog when there is a trust failure */
2079 if (trustResult
!= kSecTrustResultUnspecified
) {
2080 CFStringRef failureDesc
= SecTrustCopyFailureDescription(trust
);
2081 secerror("%@", failureDesc
);
2082 CFRelease(failureDesc
);
2086 *result
= trustResult
;
2089 CFReleaseSafe(policies
);
2093 static void deserializeCert(const void *value
, void *context
) {
2094 CFDataRef certData
= (CFDataRef
)value
;
2095 if (isData(certData
)) {
2096 SecCertificateRef cert
= SecCertificateCreateWithData(NULL
, certData
);
2098 CFArrayAppendValue((CFMutableArrayRef
)context
, cert
);
2104 static CF_RETURNS_RETAINED CFArrayRef
SecCertificateArrayDeserialize(CFArrayRef serializedCertificates
) {
2105 CFMutableArrayRef result
= NULL
;
2106 require_quiet(isArray(serializedCertificates
), errOut
);
2107 CFIndex count
= CFArrayGetCount(serializedCertificates
);
2108 result
= CFArrayCreateMutable(kCFAllocatorDefault
, count
, &kCFTypeArrayCallBacks
);
2109 CFRange all_certs
= { 0, count
};
2110 CFArrayApplyFunction(serializedCertificates
, all_certs
, deserializeCert
, result
);
2115 static void serializeCertificate(const void *value
, void *context
) {
2116 SecCertificateRef cert
= (SecCertificateRef
)value
;
2117 if (cert
&& SecCertificateGetTypeID() == CFGetTypeID(cert
)) {
2118 CFDataRef certData
= SecCertificateCopyData(cert
);
2120 CFArrayAppendValue((CFMutableArrayRef
)context
, certData
);
2121 CFRelease(certData
);
2126 static CFArrayRef
SecCertificateArraySerialize(CFArrayRef certificates
) {
2127 CFMutableArrayRef result
= NULL
;
2128 require_quiet(isArray(certificates
), errOut
);
2129 CFIndex count
= CFArrayGetCount(certificates
);
2130 result
= CFArrayCreateMutable(NULL
, count
, &kCFTypeArrayCallBacks
);
2131 CFRange all_certificates
= { 0, count
};
2132 CFArrayApplyFunction(certificates
, all_certificates
, serializeCertificate
, result
);
2137 static CFPropertyListRef
SecTrustCopyPlist(SecTrustRef trust
) {
2138 __block CFMutableDictionaryRef output
= NULL
;
2139 output
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
,
2140 &kCFTypeDictionaryValueCallBacks
);
2142 dispatch_sync(trust
->_trustQueue
, ^{
2143 if (trust
->_certificates
) {
2144 CFArrayRef serializedCerts
= SecCertificateArraySerialize(trust
->_certificates
);
2145 if (serializedCerts
) {
2146 CFDictionaryAddValue(output
, CFSTR(kSecTrustCertificatesKey
), serializedCerts
);
2147 CFRelease(serializedCerts
);
2150 if (trust
->_anchors
) {
2151 CFArrayRef serializedAnchors
= SecCertificateArraySerialize(trust
->_anchors
);
2152 if (serializedAnchors
) {
2153 CFDictionaryAddValue(output
, CFSTR(kSecTrustAnchorsKey
), serializedAnchors
);
2154 CFRelease(serializedAnchors
);
2157 if (trust
->_policies
) {
2158 CFArrayRef serializedPolicies
= SecPolicyArrayCreateSerialized(trust
->_policies
);
2159 if (serializedPolicies
) {
2160 CFDictionaryAddValue(output
, CFSTR(kSecTrustPoliciesKey
), serializedPolicies
);
2161 CFRelease(serializedPolicies
);
2164 if (trust
->_responses
) {
2165 CFDictionaryAddValue(output
, CFSTR(kSecTrustResponsesKey
), trust
->_responses
);
2168 CFDictionaryAddValue(output
, CFSTR(kSecTrustSCTsKey
), trust
->_SCTs
);
2170 if (trust
->_trustedLogs
) {
2171 CFDictionaryAddValue(output
, CFSTR(kSecTrustTrustedLogsKey
), trust
->_trustedLogs
);
2173 if (trust
->_verifyDate
) {
2174 CFDictionaryAddValue(output
, CFSTR(kSecTrustVerifyDateKey
), trust
->_verifyDate
);
2176 if (trust
->_chain
) {
2177 CFArrayRef serializedChain
= SecCertificatePathCreateSerialized(trust
->_chain
, NULL
);
2178 if (serializedChain
) {
2179 CFDictionaryAddValue(output
, CFSTR(kSecTrustChainKey
), serializedChain
);
2180 CFRelease(serializedChain
);
2183 if (trust
->_details
) {
2184 CFDictionaryAddValue(output
, CFSTR(kSecTrustDetailsKey
), trust
->_details
);
2187 CFDictionaryAddValue(output
, CFSTR(kSecTrustInfoKey
), trust
->_info
);
2189 if (trust
->_exceptions
) {
2190 CFDictionaryAddValue(output
, CFSTR(kSecTrustExceptionsKey
), trust
->_exceptions
);
2192 CFNumberRef trustResult
= CFNumberCreate(NULL
, kCFNumberSInt32Type
, &trust
->_trustResult
);
2194 CFDictionaryAddValue(output
, CFSTR(kSecTrustResultKey
), trustResult
);
2196 CFReleaseNull(trustResult
);
2197 if (trust
->_anchorsOnly
) {
2198 CFDictionaryAddValue(output
, CFSTR(kSecTrustAnchorsOnlyKey
), kCFBooleanTrue
);
2200 CFDictionaryAddValue(output
, CFSTR(kSecTrustAnchorsOnlyKey
), kCFBooleanFalse
);
2202 if (trust
->_keychainsAllowed
) {
2203 CFDictionaryAddValue(output
, CFSTR(kSecTrustKeychainsAllowedKey
), kCFBooleanTrue
);
2205 CFDictionaryAddValue(output
, CFSTR(kSecTrustKeychainsAllowedKey
), kCFBooleanFalse
);
2212 CFDataRef
SecTrustSerialize(SecTrustRef trust
, CFErrorRef
*error
) {
2213 CFPropertyListRef plist
= NULL
;
2214 CFDataRef derTrust
= NULL
;
2215 require_action_quiet(trust
, out
,
2216 SecError(errSecParam
, error
, CFSTR("null trust input")));
2217 require_action_quiet(plist
= SecTrustCopyPlist(trust
), out
,
2218 SecError(errSecDecode
, error
, CFSTR("unable to create trust plist")));
2219 require_quiet(derTrust
= CFPropertyListCreateDERData(NULL
, plist
, error
), out
);
2222 CFReleaseNull(plist
);
2226 static OSStatus
SecTrustCreateFromPlist(CFPropertyListRef plist
, SecTrustRef CF_RETURNS_RETAINED
*trust
) {
2227 OSStatus status
= errSecParam
;
2228 SecTrustRef output
= NULL
;
2229 CFTypeRef serializedCertificates
= NULL
, serializedPolicies
= NULL
, serializedAnchors
= NULL
,
2230 serializedChain
= NULL
;
2231 CFNumberRef trustResultNum
= NULL
;
2232 CFArrayRef certificates
= NULL
, policies
= NULL
, anchors
= NULL
, responses
= NULL
,
2233 SCTs
= NULL
, trustedLogs
= NULL
, details
= NULL
, exceptions
= NULL
;
2234 CFDateRef verifyDate
= NULL
;
2235 CFDictionaryRef info
= NULL
;
2236 SecCertificatePathRef chain
= NULL
;
2238 require_quiet(CFDictionaryGetTypeID() == CFGetTypeID(plist
), out
);
2239 require_quiet(serializedCertificates
= CFDictionaryGetValue(plist
, CFSTR(kSecTrustCertificatesKey
)), out
);
2240 require_quiet(certificates
= SecCertificateArrayDeserialize(serializedCertificates
), out
);
2241 require_quiet(serializedPolicies
= CFDictionaryGetValue(plist
, CFSTR(kSecTrustPoliciesKey
)), out
);
2242 require_quiet(policies
= SecPolicyArrayCreateDeserialized(serializedPolicies
), out
);
2243 require_noerr_quiet(status
= SecTrustCreateWithCertificates(certificates
, policies
, &output
), out
);
2245 serializedAnchors
= CFDictionaryGetValue(plist
, CFSTR(kSecTrustAnchorsKey
));
2246 if (isArray(serializedAnchors
)) {
2247 anchors
= SecCertificateArrayDeserialize(serializedAnchors
);
2248 output
->_anchors
= anchors
;
2250 responses
= CFDictionaryGetValue(plist
, CFSTR(kSecTrustResponsesKey
));
2251 if (isArray(responses
)) {
2252 output
->_responses
= CFRetainSafe(responses
);
2254 SCTs
= CFDictionaryGetValue(plist
, CFSTR(kSecTrustSCTsKey
));
2255 if (isArray(responses
)) {
2256 output
->_SCTs
= CFRetainSafe(SCTs
);
2258 trustedLogs
= CFDictionaryGetValue(plist
, CFSTR(kSecTrustTrustedLogsKey
));
2259 if (isArray(trustedLogs
)) {
2260 output
->_trustedLogs
= CFRetainSafe(trustedLogs
);
2262 verifyDate
= CFDictionaryGetValue(plist
, CFSTR(kSecTrustVerifyDateKey
));
2263 if (isDate(verifyDate
)) {
2264 output
->_verifyDate
= CFRetainSafe(verifyDate
);
2266 serializedChain
= CFDictionaryGetValue(plist
, CFSTR(kSecTrustChainKey
));
2267 if (isArray(serializedChain
)) {
2268 chain
= SecCertificatePathCreateDeserialized(serializedChain
, NULL
);
2269 output
->_chain
= chain
;
2271 details
= CFDictionaryGetValue(plist
, CFSTR(kSecTrustDetailsKey
));
2272 if (isArray(details
)) {
2273 output
->_details
= CFRetainSafe(details
);
2275 info
= CFDictionaryGetValue(plist
, CFSTR(kSecTrustInfoKey
));
2276 if (isDictionary(info
)) {
2277 output
->_info
= CFRetainSafe(info
);
2279 exceptions
= CFDictionaryGetValue(plist
, CFSTR(kSecTrustExceptionsKey
));
2280 if (isArray(exceptions
)) {
2281 output
->_exceptions
= CFRetainSafe(exceptions
);
2283 int32_t trustResult
= -1;
2284 trustResultNum
= CFDictionaryGetValue(plist
, CFSTR(kSecTrustResultKey
));
2285 if (isNumber(trustResultNum
) && CFNumberGetValue(trustResultNum
, kCFNumberSInt32Type
, &trustResult
) &&
2286 (trustResult
>= 0)) {
2287 output
->_trustResult
= trustResult
;
2289 status
= errSecParam
;
2291 if (CFDictionaryGetValue(plist
, CFSTR(kSecTrustAnchorsOnlyKey
)) == kCFBooleanTrue
) {
2292 output
->_anchorsOnly
= true;
2293 } /* false is set by default */
2294 if (CFDictionaryGetValue(plist
, CFSTR(kSecTrustKeychainsAllowedKey
)) == kCFBooleanFalse
) {
2295 output
->_keychainsAllowed
= false;
2296 } /* true is set by default */
2299 if (errSecSuccess
== status
&& trust
) {
2302 CFReleaseNull(policies
);
2303 CFReleaseNull(certificates
);
2307 SecTrustRef
SecTrustDeserialize(CFDataRef serializedTrust
, CFErrorRef
*error
) {
2308 SecTrustRef trust
= NULL
;
2309 CFPropertyListRef plist
= NULL
;
2310 OSStatus status
= errSecSuccess
;
2311 require_action_quiet(serializedTrust
, out
,
2312 SecError(errSecParam
, error
, CFSTR("null serialized trust input")));
2313 require_quiet(plist
= CFPropertyListCreateWithDERData(NULL
, serializedTrust
,
2314 kCFPropertyListImmutable
, NULL
, error
), out
);
2315 require_noerr_action_quiet(status
= SecTrustCreateFromPlist(plist
, &trust
), out
,
2316 SecError(status
, error
, CFSTR("unable to create trust ref")));
2319 CFReleaseNull(plist
);