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>
60 #include "SecRSAKey.h"
61 #include <libDER/oids.h>
63 #include <ipc/securityd_client.h>
65 #include <securityd/SecTrustServer.h>
67 #define SEC_CONST_DECL(k,v) const CFStringRef k = CFSTR(v);
69 SEC_CONST_DECL (kSecTrustInfoExtendedValidationKey
, "ExtendedValidation");
70 SEC_CONST_DECL (kSecTrustInfoCompanyNameKey
, "CompanyName");
71 SEC_CONST_DECL (kSecTrustInfoRevocationKey
, "Revocation");
72 SEC_CONST_DECL (kSecTrustInfoRevocationValidUntilKey
, "RevocationValidUntil");
73 SEC_CONST_DECL (kSecTrustInfoCertificateTransparencyKey
, "CertificateTransparency");
74 SEC_CONST_DECL (kSecTrustInfoCertificateTransparencyWhiteListKey
, "CertificateTransparencyWhiteList");
76 /* Public trust result constants */
77 SEC_CONST_DECL (kSecTrustEvaluationDate
, "TrustEvaluationDate");
78 SEC_CONST_DECL (kSecTrustExtendedValidation
, "TrustExtendedValidation");
79 SEC_CONST_DECL (kSecTrustOrganizationName
, "Organization");
80 SEC_CONST_DECL (kSecTrustResultValue
, "TrustResultValue");
81 SEC_CONST_DECL (kSecTrustRevocationChecked
, "TrustRevocationChecked");
82 SEC_CONST_DECL (kSecTrustRevocationReason
, "TrustRevocationReason");
83 SEC_CONST_DECL (kSecTrustRevocationValidUntilDate
, "TrustExpirationDate");
84 SEC_CONST_DECL (kSecTrustResultDetails
, "TrustResultDetails");
85 SEC_CONST_DECL (kSecTrustCertificateTransparency
, "TrustCertificateTransparency");
86 SEC_CONST_DECL (kSecTrustCertificateTransparencyWhiteList
, "TrustCertificateTransparencyWhiteList");
91 /********************************************************
92 ****************** SecTrust object *********************
93 ********************************************************/
96 CFArrayRef _certificates
;
99 CFArrayRef _responses
;
101 CFArrayRef _trustedLogs
;
102 CFDateRef _verifyDate
;
103 SecCertificatePathRef _chain
;
104 SecKeyRef _publicKey
;
106 CFDictionaryRef _info
;
107 CFArrayRef _exceptions
;
109 /* Note that a value of kSecTrustResultInvalid (0)
110 * indicates the trust must be (re)evaluated; any
111 * functions which modify trust parameters in a way
112 * that would invalidate the current result must set
113 * this value back to kSecTrustResultInvalid.
115 SecTrustResultType _trustResult
;
117 /* If true we don't trust any anchors other than the ones in _anchors. */
119 /* If false we shouldn't search keychains for parents or anchors. */
120 bool _keychainsAllowed
;
122 /* Data blobs for legacy CSSM_TP_APPLE_EVIDENCE_INFO structure,
123 * to support callers of SecTrustGetResult on OS X. Since fields of
124 * one structure contain pointers into the other, these cannot be
125 * serialized; if a SecTrust is being serialized or copied, these values
126 * should just be initialized to NULL in the copy and built when needed. */
127 void* _legacy_info_array
;
128 void* _legacy_status_array
;
130 /* The trust result as determined by the trust server,
131 * before the caller's exceptions are applied.
133 SecTrustResultType _trustResultBeforeExceptions
;
135 /* === IMPORTANT! ===
136 * Any change to this structure definition
137 * must also be made in the TSecTrust structure,
138 * located in SecTrust.cpp. To avoid problems,
139 * new fields should always be appended at the
140 * end of the structure.
144 /* Forward declarations of static functions. */
145 static OSStatus
SecTrustEvaluateIfNecessary(SecTrustRef trust
);
147 /* Static functions. */
148 static CFStringRef
SecTrustCopyFormatDescription(CFTypeRef cf
, CFDictionaryRef formatOptions
) {
149 SecTrustRef trust
= (SecTrustRef
)cf
;
150 return CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
,
151 CFSTR("<SecTrustRef: %p>"), trust
);
154 static void SecTrustDestroy(CFTypeRef cf
) {
155 SecTrustRef trust
= (SecTrustRef
)cf
;
157 CFReleaseSafe(trust
->_certificates
);
158 CFReleaseSafe(trust
->_policies
);
159 CFReleaseSafe(trust
->_responses
);
160 CFReleaseSafe(trust
->_SCTs
);
161 CFReleaseSafe(trust
->_trustedLogs
);
162 CFReleaseSafe(trust
->_verifyDate
);
163 CFReleaseSafe(trust
->_anchors
);
164 CFReleaseSafe(trust
->_chain
);
165 CFReleaseSafe(trust
->_publicKey
);
166 CFReleaseSafe(trust
->_details
);
167 CFReleaseSafe(trust
->_info
);
168 CFReleaseSafe(trust
->_exceptions
);
170 if (trust
->_legacy_info_array
) {
171 free(trust
->_legacy_info_array
);
173 if (trust
->_legacy_status_array
) {
174 free(trust
->_legacy_status_array
);
178 /* Public API functions. */
179 CFGiblisFor(SecTrust
)
181 OSStatus
SecTrustCreateWithCertificates(CFTypeRef certificates
,
182 CFTypeRef policies
, SecTrustRef
*trust
) {
183 OSStatus status
= errSecParam
;
184 CFAllocatorRef allocator
= kCFAllocatorDefault
;
185 CFArrayRef l_certs
= NULL
, l_policies
= NULL
;
186 SecTrustRef result
= NULL
;
190 CFTypeID certType
= CFGetTypeID(certificates
);
191 if (certType
== CFArrayGetTypeID()) {
192 /* We need at least 1 certificate. */
193 require_quiet(CFArrayGetCount(certificates
) > 0, errOut
);
194 l_certs
= CFArrayCreateCopy(allocator
, certificates
);
195 } else if (certType
== SecCertificateGetTypeID()) {
196 l_certs
= CFArrayCreate(allocator
, &certificates
, 1,
197 &kCFTypeArrayCallBacks
);
202 status
= errSecAllocate
;
207 CFTypeRef policy
= SecPolicyCreateBasicX509();
208 l_policies
= CFArrayCreate(allocator
, &policy
, 1,
209 &kCFTypeArrayCallBacks
);
212 else if (CFGetTypeID(policies
) == CFArrayGetTypeID()) {
213 l_policies
= CFArrayCreateCopy(allocator
, policies
);
215 else if (CFGetTypeID(policies
) == SecPolicyGetTypeID()) {
216 l_policies
= CFArrayCreate(allocator
, &policies
, 1,
217 &kCFTypeArrayCallBacks
);
222 status
= errSecAllocate
;
226 CFIndex size
= sizeof(struct __SecTrust
);
227 require_quiet(result
= (SecTrustRef
)_CFRuntimeCreateInstance(allocator
,
228 SecTrustGetTypeID(), size
- sizeof(CFRuntimeBase
), 0), errOut
);
229 memset((char*)result
+ sizeof(result
->_base
), 0,
230 sizeof(*result
) - sizeof(result
->_base
));
231 status
= errSecSuccess
;
235 CFReleaseSafe(result
);
236 CFReleaseSafe(l_certs
);
237 CFReleaseSafe(l_policies
);
239 result
->_certificates
= l_certs
;
240 result
->_policies
= l_policies
;
241 result
->_keychainsAllowed
= true;
245 CFReleaseSafe(result
);
250 static void SecTrustSetNeedsEvaluation(SecTrustRef trust
) {
253 trust
->_trustResult
= kSecTrustResultInvalid
;
254 trust
->_trustResultBeforeExceptions
= kSecTrustResultInvalid
;
258 OSStatus
SecTrustSetAnchorCertificatesOnly(SecTrustRef trust
,
259 Boolean anchorCertificatesOnly
) {
263 SecTrustSetNeedsEvaluation(trust
);
264 trust
->_anchorsOnly
= anchorCertificatesOnly
;
266 return errSecSuccess
;
269 OSStatus
SecTrustSetAnchorCertificates(SecTrustRef trust
,
270 CFArrayRef anchorCertificates
) {
274 SecTrustSetNeedsEvaluation(trust
);
275 if (anchorCertificates
)
276 CFRetain(anchorCertificates
);
278 CFRelease(trust
->_anchors
);
279 trust
->_anchors
= anchorCertificates
;
280 trust
->_anchorsOnly
= (anchorCertificates
!= NULL
);
282 return errSecSuccess
;
285 OSStatus
SecTrustCopyCustomAnchorCertificates(SecTrustRef trust
,
286 CFArrayRef
*anchors
) {
287 if (!trust
|| !anchors
) {
290 CFArrayRef anchorsArray
= NULL
;
291 if (trust
->_anchors
) {
292 anchorsArray
= CFArrayCreateCopy(kCFAllocatorDefault
, trust
->_anchors
);
294 return errSecAllocate
;
297 *anchors
= anchorsArray
;
298 return errSecSuccess
;
301 OSStatus
SecTrustSetOCSPResponse(SecTrustRef trust
, CFTypeRef responseData
) {
305 SecTrustSetNeedsEvaluation(trust
);
306 CFArrayRef responseArray
= NULL
;
308 if (CFGetTypeID(responseData
) == CFArrayGetTypeID()) {
309 responseArray
= CFArrayCreateCopy(kCFAllocatorDefault
, responseData
);
310 } else if (CFGetTypeID(responseData
) == CFDataGetTypeID()) {
311 responseArray
= CFArrayCreate(kCFAllocatorDefault
, &responseData
, 1,
312 &kCFTypeArrayCallBacks
);
317 if (trust
->_responses
)
318 CFRelease(trust
->_responses
);
319 trust
->_responses
= responseArray
;
321 return errSecSuccess
;
324 OSStatus
SecTrustSetSignedCertificateTimestamps(SecTrustRef trust
, CFArrayRef sctArray
) {
328 SecTrustSetNeedsEvaluation(trust
);
329 CFRetainAssign(trust
->_SCTs
, sctArray
);
331 return errSecSuccess
;
334 OSStatus
SecTrustSetTrustedLogs(SecTrustRef trust
, CFArrayRef trustedLogs
) {
338 SecTrustSetNeedsEvaluation(trust
);
339 CFRetainAssign(trust
->_trustedLogs
, trustedLogs
);
341 return errSecSuccess
;
344 OSStatus
SecTrustSetVerifyDate(SecTrustRef trust
, CFDateRef verifyDate
) {
348 SecTrustSetNeedsEvaluation(trust
);
350 CFRetainAssign(trust
->_verifyDate
, verifyDate
);
352 return errSecSuccess
;
355 OSStatus
SecTrustSetPolicies(SecTrustRef trust
, CFTypeRef newPolicies
) {
356 if (!trust
|| !newPolicies
) {
359 SecTrustSetNeedsEvaluation(trust
);
362 CFArrayRef policyArray
= NULL
;
363 if (CFGetTypeID(newPolicies
) == CFArrayGetTypeID()) {
364 policyArray
= CFArrayCreateCopy(kCFAllocatorDefault
, newPolicies
);
365 } else if (CFGetTypeID(newPolicies
) == SecPolicyGetTypeID()) {
366 policyArray
= CFArrayCreate(kCFAllocatorDefault
, &newPolicies
, 1,
367 &kCFTypeArrayCallBacks
);
372 if (trust
->_policies
)
373 CFRelease(trust
->_policies
);
374 trust
->_policies
= policyArray
;
376 return errSecSuccess
;
379 OSStatus
SecTrustSetKeychainsAllowed(SecTrustRef trust
, Boolean allowed
) {
383 SecTrustSetNeedsEvaluation(trust
);
384 trust
->_keychainsAllowed
= allowed
;
386 return errSecSuccess
;
389 OSStatus
SecTrustGetKeychainsAllowed(SecTrustRef trust
, Boolean
*allowed
) {
390 if (!trust
|| !allowed
) {
393 *allowed
= trust
->_keychainsAllowed
;
395 return errSecSuccess
;
398 OSStatus
SecTrustCopyPolicies(SecTrustRef trust
, CFArrayRef
*policies
) {
399 if (!trust
|| !policies
) {
402 if (!trust
->_policies
) {
403 return errSecInternal
;
405 CFArrayRef policyArray
= CFArrayCreateCopy(kCFAllocatorDefault
, trust
->_policies
);
407 return errSecAllocate
;
409 *policies
= policyArray
;
410 return errSecSuccess
;
413 static OSStatus
SecTrustSetOptionInPolicies(CFArrayRef policies
, CFStringRef key
, CFTypeRef value
) {
414 OSStatus status
= errSecSuccess
;
415 require_action(policies
&& CFGetTypeID(policies
) == CFArrayGetTypeID(), out
, status
= errSecInternal
);
416 for (int i
=0; i
< CFArrayGetCount(policies
); i
++) {
417 SecPolicyRef policy
= NULL
;
418 require_action_quiet(policy
= (SecPolicyRef
)CFArrayGetValueAtIndex(policies
, i
), out
, status
= errSecInternal
);
419 CFMutableDictionaryRef options
= NULL
;
420 require_action_quiet(options
= CFDictionaryCreateMutableCopy(NULL
, 0, policy
->_options
), out
, status
= errSecAllocate
);
421 CFDictionaryAddValue(options
, key
, value
);
422 CFReleaseNull(policy
->_options
);
423 policy
->_options
= options
;
429 static OSStatus
SecTrustRemoveOptionInPolicies(CFArrayRef policies
, CFStringRef key
) {
430 OSStatus status
= errSecSuccess
;
431 require_action(policies
&& CFGetTypeID(policies
) == CFArrayGetTypeID(), out
, status
= errSecInternal
);
432 for (int i
=0; i
< CFArrayGetCount(policies
); i
++) {
433 SecPolicyRef policy
= NULL
;
434 require_action_quiet(policy
= (SecPolicyRef
)CFArrayGetValueAtIndex(policies
, i
), out
, status
= errSecInternal
);
435 if (CFDictionaryGetValue(policy
->_options
, key
)) {
436 CFMutableDictionaryRef options
= NULL
;
437 require_action_quiet(options
= CFDictionaryCreateMutableCopy(NULL
, 0, policy
->_options
), out
, status
= errSecAllocate
);
438 CFDictionaryRemoveValue(options
, key
);
439 CFReleaseNull(policy
->_options
);
440 policy
->_options
= options
;
447 static CF_RETURNS_RETAINED CFArrayRef
SecTrustCopyOptionsFromPolicies(CFArrayRef policies
, CFStringRef key
) {
448 CFMutableArrayRef foundValues
= NULL
;
449 foundValues
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
450 for (int i
=0; i
< CFArrayGetCount(policies
); i
++) {
451 SecPolicyRef policy
= (SecPolicyRef
)CFArrayGetValueAtIndex(policies
, i
);
452 CFTypeRef value
= CFDictionaryGetValue(policy
->_options
, key
);
454 CFArrayAppendValue(foundValues
, value
);
457 if (!CFArrayGetCount(foundValues
)) {
458 CFReleaseNull(foundValues
);
466 /* The only effective way to disable network fetch is within the policy options:
467 * presence of the kSecPolicyCheckNoNetworkAccess key in any of the policies
468 * will prevent network access for fetching.
469 * The current SecTrustServer implementation doesn't distinguish between network
470 * access for revocation and network access for fetching.
472 OSStatus
SecTrustSetNetworkFetchAllowed(SecTrustRef trust
, Boolean allowFetch
) {
476 if (!trust
->_policies
) {
477 return errSecInternal
;
480 return SecTrustSetOptionInPolicies(trust
->_policies
, kSecPolicyCheckNoNetworkAccess
, kCFBooleanTrue
);
483 return SecTrustRemoveOptionInPolicies(trust
->_policies
, kSecPolicyCheckNoNetworkAccess
);
485 return errSecSuccess
;
488 OSStatus
SecTrustGetNetworkFetchAllowed(SecTrustRef trust
, Boolean
*allowFetch
) {
489 if (!trust
|| !allowFetch
) {
492 if (!trust
->_policies
) {
493 return errSecInternal
;
495 CFArrayRef foundValues
= NULL
;
496 if ((foundValues
= SecTrustCopyOptionsFromPolicies(trust
->_policies
, kSecPolicyCheckNoNetworkAccess
))) {
502 CFReleaseNull(foundValues
);
503 return errSecSuccess
;
506 CFAbsoluteTime
SecTrustGetVerifyTime(SecTrustRef trust
) {
507 CFAbsoluteTime verifyTime
;
508 if (trust
&& trust
->_verifyDate
) {
509 verifyTime
= CFDateGetAbsoluteTime(trust
->_verifyDate
);
511 verifyTime
= CFAbsoluteTimeGetCurrent();
512 /* Record the verifyDate we ended up using. */
514 trust
->_verifyDate
= CFDateCreate(CFGetAllocator(trust
), verifyTime
);
520 CFArrayRef
SecTrustGetDetails(SecTrustRef trust
) {
524 SecTrustEvaluateIfNecessary(trust
);
525 return trust
->_details
;
528 OSStatus
SecTrustGetTrustResult(SecTrustRef trust
,
529 SecTrustResultType
*result
) {
530 if (!trust
|| !result
) {
533 *result
= trust
->_trustResult
;
534 return errSecSuccess
;
537 static CFStringRef kSecCertificateDetailSHA1Digest
= CFSTR("SHA1Digest");
539 static CFDictionaryRef
SecTrustGetExceptionForCertificateAtIndex(SecTrustRef trust
, CFIndex ix
) {
540 if (!trust
->_exceptions
|| ix
>= CFArrayGetCount(trust
->_exceptions
))
542 CFDictionaryRef exception
= (CFDictionaryRef
)CFArrayGetValueAtIndex(trust
->_exceptions
, ix
);
543 if (CFGetTypeID(exception
) != CFDictionaryGetTypeID())
546 SecCertificateRef certificate
= SecTrustGetCertificateAtIndex(trust
, ix
);
550 /* If the exception contains the current certificates sha1Digest in the
551 kSecCertificateDetailSHA1Digest key then we use it otherwise we ignore it. */
552 CFDataRef sha1Digest
= SecCertificateGetSHA1Digest(certificate
);
553 CFTypeRef digestValue
= CFDictionaryGetValue(exception
, kSecCertificateDetailSHA1Digest
);
554 if (!digestValue
|| !CFEqual(sha1Digest
, digestValue
))
560 struct SecTrustCheckExceptionContext
{
561 CFDictionaryRef exception
;
562 bool exceptionNotFound
;
566 static void SecTrustCheckException(const void *key
, const void *value
, void *context
) {
567 struct SecTrustCheckExceptionContext
*cec
= (struct SecTrustCheckExceptionContext
*)context
;
568 if (cec
->exception
) {
569 CFTypeRef exceptionValue
= CFDictionaryGetValue(cec
->exception
, key
);
570 if (!exceptionValue
|| !CFEqual(value
, exceptionValue
)) {
571 cec
->exceptionNotFound
= true;
574 cec
->exceptionNotFound
= true;
579 static CFArrayRef
SecTrustCreatePolicyAnchorsArray(const UInt8
* certData
, CFIndex certLength
)
581 CFArrayRef array
= NULL
;
582 CFAllocatorRef allocator
= kCFAllocatorDefault
;
583 SecCertificateRef cert
= SecCertificateCreateWithBytes(allocator
, certData
, certLength
);
585 array
= CFArrayCreate(allocator
, (const void **)&cert
, 1, &kCFTypeArrayCallBacks
);
592 static void SecTrustAddPolicyAnchors(SecTrustRef trust
)
594 /* Provide anchor certificates specifically required by certain policies.
595 This is used to evaluate test policies where the anchor is not provided
596 in the root store and may not be able to be supplied by the caller.
598 CFArrayRef policies
= (trust
) ? trust
->_policies
: NULL
;
602 CFIndex ix
, count
= CFArrayGetCount(policies
);
603 for (ix
= 0; ix
< count
; ++ix
) {
604 SecPolicyRef policy
= (SecPolicyRef
) CFArrayGetValueAtIndex(policies
, ix
);
607 if (CFEqual(policy
->_oid
, kSecPolicyAppleTestSMPEncryption
)) {
608 CFReleaseSafe(trust
->_anchors
);
609 trust
->_anchors
= SecTrustCreatePolicyAnchorsArray(_SEC_TestAppleRootCAECC
, sizeof(_SEC_TestAppleRootCAECC
));
610 trust
->_anchorsOnly
= true;
619 // uncomment for verbose debug logging (debug builds only)
620 //#define CERT_TRUST_DUMP 1
623 static void sectrustlog(int priority
, const char *format
, ...)
628 if (priority
< LOG_NOTICE
) // log warnings and errors
632 va_start(list
, format
);
633 vsyslog(priority
, format
, list
);
638 static void sectrustshow(CFTypeRef obj
, const char *context
)
641 CFStringRef desc
= CFCopyDescription(obj
);
644 CFIndex length
= CFStringGetMaximumSizeForEncoding(CFStringGetLength(desc
), kCFStringEncodingUTF8
) + 1;
645 char* buffer
= (char*) malloc(length
);
647 Boolean converted
= CFStringGetCString(desc
, buffer
, length
, kCFStringEncodingUTF8
);
649 const char *prefix
= (context
) ? context
: "";
650 const char *separator
= (context
) ? " " : "";
651 sectrustlog(LOG_NOTICE
, "%s%s%s", prefix
, separator
, buffer
);
659 static void cert_trust_dump(SecTrustRef trust
) {
660 SecCertificateRef leaf
= (SecCertificateRef
) CFArrayGetValueAtIndex(trust
->_certificates
, 0);
661 CFStringRef name
= (leaf
) ? SecCertificateCopySubjectSummary(leaf
) : NULL
;
662 secerror("leaf \"%@\"", name
);
663 secerror(": result = %d", (int) trust
->_trustResult
);
665 CFIndex ix
, count
= SecCertificatePathGetCount(trust
->_chain
);
666 CFMutableArrayRef chain
= CFArrayCreateMutable(kCFAllocatorDefault
, count
, &kCFTypeArrayCallBacks
);
667 for (ix
= 0; ix
< count
; ix
++) {
668 SecCertificateRef cert
= SecCertificatePathGetCertificateAtIndex(trust
->_chain
, ix
);
670 CFArrayAppendValue(chain
, cert
);
673 sectrustshow(chain
, "chain:");
674 CFReleaseSafe(chain
);
676 secerror(": %ld certificates, %ld anchors, %ld policies, %ld details",
677 (trust
->_certificates
) ? (long)CFArrayGetCount(trust
->_certificates
) : 0,
678 (trust
->_anchors
) ? (long)CFArrayGetCount(trust
->_anchors
) : 0,
679 (trust
->_policies
) ? (long)CFArrayGetCount(trust
->_policies
) : 0,
680 (trust
->_details
) ? (long)CFArrayGetCount(trust
->_details
) : 0);
682 sectrustshow(trust
->_verifyDate
, "verify date:");
683 sectrustshow(trust
->_certificates
, "certificates:");
684 sectrustshow(trust
->_anchors
, "anchors:");
685 sectrustshow(trust
->_policies
, "policies:");
686 sectrustshow(trust
->_details
, "details:");
687 sectrustshow(trust
->_info
, "info:");
692 static void cert_trust_dump(SecTrustRef trust
) {}
696 OSStatus
SecTrustEvaluate(SecTrustRef trust
, SecTrustResultType
*result
) {
700 OSStatus status
= SecTrustEvaluateIfNecessary(trust
);
704 /* post-process trust result based on exceptions */
705 SecTrustResultType trustResult
= trust
->_trustResult
;
706 if (trustResult
== kSecTrustResultUnspecified
) {
707 /* If leaf is in exceptions -> proceed, otherwise unspecified. */
708 if (SecTrustGetExceptionForCertificateAtIndex(trust
, 0))
709 trustResult
= kSecTrustResultProceed
;
710 } else if (trustResult
== kSecTrustResultRecoverableTrustFailure
) {
711 /* If we have exceptions get details and match to exceptions. */
712 CFIndex pathLength
= (trust
->_details
) ? CFArrayGetCount(trust
->_details
) : 0;
713 struct SecTrustCheckExceptionContext context
= {};
715 for (ix
= 0; ix
< pathLength
; ++ix
) {
716 CFDictionaryRef detail
= (CFDictionaryRef
)CFArrayGetValueAtIndex(trust
->_details
, ix
);
717 context
.exception
= SecTrustGetExceptionForCertificateAtIndex(trust
, ix
);
718 CFDictionaryApplyFunction(detail
, SecTrustCheckException
, &context
);
719 if (context
.exceptionNotFound
) {
723 if (!trust
->_exceptions
|| !CFArrayGetCount(trust
->_exceptions
)) {
724 goto DoneCheckingTrust
;
726 if (!context
.exceptionNotFound
)
727 trustResult
= kSecTrustResultProceed
;
730 trust
->_trustResult
= trustResult
;
732 /* log to syslog when there is a trust failure */
733 if (trustResult
!= kSecTrustResultProceed
&&
734 trustResult
!= kSecTrustResultConfirm
&&
735 trustResult
!= kSecTrustResultUnspecified
) {
736 CFStringRef failureDesc
= SecTrustCopyFailureDescription(trust
);
737 secerror("%{public}@", failureDesc
);
738 CFRelease(failureDesc
);
743 *result
= trustResult
;
749 OSStatus
SecTrustEvaluateAsync(SecTrustRef trust
,
750 dispatch_queue_t queue
, SecTrustCallback result
)
752 dispatch_async(queue
, ^{
753 SecTrustResultType trustResult
;
754 if (errSecSuccess
!= SecTrustEvaluate(trust
, &trustResult
)) {
755 trustResult
= kSecTrustResultInvalid
;
757 result(trust
, trustResult
);
759 return errSecSuccess
;
762 static bool append_certificate_to_xpc_array(SecCertificateRef certificate
, xpc_object_t xpc_certificates
);
763 static xpc_object_t
copy_xpc_certificates_array(CFArrayRef certificates
);
764 xpc_object_t
copy_xpc_policies_array(CFArrayRef policies
);
765 OSStatus
validate_array_of_items(CFArrayRef array
, CFStringRef arrayItemType
, CFTypeID itemTypeID
, bool required
);
767 static bool append_certificate_to_xpc_array(SecCertificateRef certificate
, xpc_object_t xpc_certificates
) {
771 size_t length
= SecCertificateGetLength(certificate
);
772 const uint8_t *bytes
= SecCertificateGetBytePtr(certificate
);
773 if (!length
|| !bytes
) {
776 xpc_array_set_data(xpc_certificates
, XPC_ARRAY_APPEND
, bytes
, length
);
780 static xpc_object_t
copy_xpc_certificates_array(CFArrayRef certificates
) {
781 xpc_object_t xpc_certificates
= xpc_array_create(NULL
, 0);
782 if (!xpc_certificates
) {
785 CFIndex ix
, count
= CFArrayGetCount(certificates
);
786 for (ix
= 0; ix
< count
; ++ix
) {
787 SecCertificateRef certificate
= (SecCertificateRef
) CFArrayGetValueAtIndex(certificates
, ix
);
788 #if SECTRUST_VERBOSE_DEBUG
789 size_t length
= SecCertificateGetLength(certificate
);
790 const uint8_t *bytes
= SecCertificateGetBytePtr(certificate
);
791 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
);
793 if (!append_certificate_to_xpc_array(certificate
, xpc_certificates
)) {
794 xpc_release(xpc_certificates
);
795 xpc_certificates
= NULL
;
799 return xpc_certificates
;
802 static bool SecXPCDictionarySetCertificates(xpc_object_t message
, const char *key
, CFArrayRef certificates
, CFErrorRef
*error
) {
803 xpc_object_t xpc_certificates
= copy_xpc_certificates_array(certificates
);
804 if (!xpc_certificates
) {
805 SecError(errSecAllocate
, error
, CFSTR("failed to create xpc_array of certificates"));
808 xpc_dictionary_set_value(message
, key
, xpc_certificates
);
809 xpc_release(xpc_certificates
);
813 static bool SecXPCDictionarySetPolicies(xpc_object_t message
, const char *key
, CFArrayRef policies
, CFErrorRef
*error
) {
814 xpc_object_t xpc_policies
= copy_xpc_policies_array(policies
);
816 SecError(errSecAllocate
, error
, CFSTR("failed to create xpc_array of policies"));
819 xpc_dictionary_set_value(message
, key
, xpc_policies
);
820 xpc_release(xpc_policies
);
825 static bool CFDataAppendToXPCArray(CFDataRef data
, xpc_object_t xpc_data_array
, CFErrorRef
*error
) {
829 size_t length
= CFDataGetLength(data
);
830 const uint8_t *bytes
= CFDataGetBytePtr(data
);
831 if (!length
|| !bytes
)
832 return SecError(errSecParam
, error
, CFSTR("invalid CFDataRef"));
834 xpc_array_set_data(xpc_data_array
, XPC_ARRAY_APPEND
, bytes
, length
);
839 static xpc_object_t
CFDataArrayCopyXPCArray(CFArrayRef data_array
, CFErrorRef
*error
) {
840 xpc_object_t xpc_data_array
;
841 require_action_quiet(xpc_data_array
= xpc_array_create(NULL
, 0), exit
,
842 SecError(errSecAllocate
, error
, CFSTR("failed to create xpc_array")));
843 CFIndex ix
, count
= CFArrayGetCount(data_array
);
844 for (ix
= 0; ix
< count
; ++ix
) {
845 if (!CFDataAppendToXPCArray((CFDataRef
)CFArrayGetValueAtIndex(data_array
, ix
), xpc_data_array
, error
)) {
846 xpc_release(xpc_data_array
);
852 return xpc_data_array
;
855 static bool SecXPCDictionarySetDataArray(xpc_object_t message
, const char *key
, CFArrayRef data_array
, CFErrorRef
*error
) {
856 xpc_object_t xpc_data_array
= CFDataArrayCopyXPCArray(data_array
, error
);
859 xpc_dictionary_set_value(message
, key
, xpc_data_array
);
860 xpc_release(xpc_data_array
);
864 static bool SecXPCDictionaryCopyChainOptional(xpc_object_t message
, const char *key
, SecCertificatePathRef
*path
, CFErrorRef
*error
) {
865 xpc_object_t xpc_path
= xpc_dictionary_get_value(message
, key
);
870 *path
= SecCertificatePathCreateWithXPCArray(xpc_path
, error
);
874 static int SecXPCDictionaryGetNonZeroInteger(xpc_object_t message
, const char *key
, CFErrorRef
*error
) {
875 int64_t value
= xpc_dictionary_get_int64(message
, key
);
877 SecError(errSecInternal
, error
, CFSTR("object for key %s is 0"), key
);
882 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
)
884 __block SecTrustResultType tr
= kSecTrustResultInvalid
;
885 securityd_send_sync_and_do(op
, error
, ^bool(xpc_object_t message
, CFErrorRef
*error
) {
886 if (!SecXPCDictionarySetCertificates(message
, kSecTrustCertificatesKey
, certificates
, error
))
888 if (anchors
&& !SecXPCDictionarySetCertificates(message
, kSecTrustAnchorsKey
, anchors
, error
))
891 xpc_dictionary_set_bool(message
, kSecTrustAnchorsOnlyKey
, anchorsOnly
);
892 xpc_dictionary_set_bool(message
, kSecTrustKeychainsAllowedKey
, keychainsAllowed
);
893 if (!SecXPCDictionarySetPolicies(message
, kSecTrustPoliciesKey
, policies
, error
))
895 if (responses
&& !SecXPCDictionarySetDataArray(message
, kSecTrustResponsesKey
, responses
, error
))
897 if (SCTs
&& !SecXPCDictionarySetDataArray(message
, kSecTrustSCTsKey
, SCTs
, error
))
899 if (trustedLogs
&& !SecXPCDictionarySetPList(message
, kSecTrustTrustedLogsKey
, trustedLogs
, error
))
901 xpc_dictionary_set_double(message
, kSecTrustVerifyDateKey
, verifyTime
);
903 }, ^bool(xpc_object_t response
, CFErrorRef
*error
) {
904 secdebug("trust", "response: %@", response
);
905 return SecXPCDictionaryCopyArrayOptional(response
, kSecTrustDetailsKey
, details
, error
) &&
906 SecXPCDictionaryCopyDictionaryOptional(response
, kSecTrustInfoKey
, info
, error
) &&
907 SecXPCDictionaryCopyChainOptional(response
, kSecTrustChainKey
, chain
, error
) &&
908 ((tr
= SecXPCDictionaryGetNonZeroInteger(response
, kSecTrustResultKey
, error
)) != kSecTrustResultInvalid
);
913 OSStatus
validate_array_of_items(CFArrayRef array
, CFStringRef arrayItemType
, CFTypeID itemTypeID
, bool required
) {
914 OSStatus result
= errSecSuccess
;
915 CFIndex index
, count
;
916 count
= (array
) ? CFArrayGetCount(array
) : 0;
917 if (!count
&& required
) {
918 secerror("no %@ in array!", arrayItemType
);
919 result
= errSecParam
;
921 for (index
= 0; index
< count
; index
++) {
922 CFTypeRef item
= (CFTypeRef
) CFArrayGetValueAtIndex(array
, index
);
924 secerror("%@ %@ (index %d)", arrayItemType
, CFSTR("reference is nil"), (int)index
);
925 result
= errSecParam
;
928 if (CFGetTypeID(item
) != itemTypeID
) {
929 secerror("%@ %@ (index %d)", arrayItemType
, CFSTR("is not the expected CF type"), (int)index
);
930 result
= errSecParam
;
933 if (CFGetTypeID(item
) == SecCertificateGetTypeID()) {
934 SecCertificateRef certificate
= (SecCertificateRef
) item
;
935 CFIndex length
= SecCertificateGetLength(certificate
);
936 const UInt8
*bytes
= SecCertificateGetBytePtr(certificate
);
938 secerror("%@ %@ (index %d)", arrayItemType
, CFSTR("has zero length"), (int)index
);
939 result
= errSecParam
;
942 secerror("%@ %@ (index %d)", arrayItemType
, CFSTR("has nil bytes"), (int)index
);
943 result
= errSecParam
;
945 #if SECTRUST_VERBOSE_DEBUG
946 secerror("%@[%d] of %d = %ld bytes @ 0x%lX", arrayItemType
, (int)index
, (int)count
, (size_t)length
, (uintptr_t)bytes
);
950 if (CFGetTypeID(item
) == SecPolicyGetTypeID()) {
951 SecPolicyRef policy
= (SecPolicyRef
) item
;
952 CFStringRef oidStr
= policy
->_oid
;
953 if (!oidStr
|| (CFGetTypeID(oidStr
) != CFStringGetTypeID())) {
954 oidStr
= CFSTR("has invalid OID string!");
955 secerror("%@ %@ (index %d)", arrayItemType
, oidStr
, (int)index
);
957 #if SECTRUST_VERBOSE_DEBUG
958 secerror("%@[%d] of %d = \"%@\" 0x%lX", arrayItemType
, (int)index
, (int)count
, oidStr
, (uintptr_t)policy
);
965 static OSStatus
SecTrustValidateInput(SecTrustRef trust
) {
966 OSStatus status
, result
= errSecSuccess
;
968 // certificates (required)
969 status
= validate_array_of_items(trust
->_certificates
, CFSTR("certificate"), SecCertificateGetTypeID(), true);
970 if (status
) result
= status
;
971 // anchors (optional)
972 status
= validate_array_of_items(trust
->_anchors
, CFSTR("input anchor"), SecCertificateGetTypeID(), false);
973 if (status
) result
= status
;
974 // policies (required??)
975 status
= validate_array_of_items(trust
->_policies
, CFSTR("policy"), SecPolicyGetTypeID(), true);
976 if (status
) result
= status
;
977 // _responses, _SCTs, _trustedLogs, ...
978 // verify time: SecTrustGetVerifyTime(trust)
979 // access groups: SecAccessGroupsGetCurrent()
985 static void SecTrustPostEvaluate(SecTrustRef trust
) {
986 if (!trust
) { return; }
988 CFIndex pathLength
= (trust
->_details
) ? CFArrayGetCount(trust
->_details
) : 0;
990 for (ix
= 0; ix
< pathLength
; ++ix
) {
991 CFDictionaryRef detail
= (CFDictionaryRef
)CFArrayGetValueAtIndex(trust
->_details
, ix
);
992 if ((ix
== 0) && CFDictionaryContainsKey(detail
, kSecPolicyCheckBlackListedLeaf
)) {
993 trust
->_trustResult
= kSecTrustResultFatalTrustFailure
;
996 if (CFDictionaryContainsKey(detail
, kSecPolicyCheckBlackListedKey
)) {
997 trust
->_trustResult
= kSecTrustResultFatalTrustFailure
;
1003 static OSStatus
SecTrustEvaluateIfNecessary(SecTrustRef trust
) {
1004 __block OSStatus result
;
1009 if (trust
->_trustResult
!= kSecTrustResultInvalid
)
1010 return errSecSuccess
;
1012 trust
->_trustResult
= kSecTrustResultOtherError
; /* to avoid potential recursion */
1014 CFReleaseNull(trust
->_chain
);
1015 CFReleaseNull(trust
->_details
);
1016 CFReleaseNull(trust
->_info
);
1017 if (trust
->_legacy_info_array
) {
1018 free(trust
->_legacy_info_array
);
1019 trust
->_legacy_info_array
= NULL
;
1021 if (trust
->_legacy_status_array
) {
1022 free(trust
->_legacy_status_array
);
1023 trust
->_legacy_status_array
= NULL
;
1026 os_activity_initiate("SecTrustEvaluateIfNecessary", OS_ACTIVITY_FLAG_DEFAULT
, ^{
1027 SecTrustAddPolicyAnchors(trust
);
1028 SecTrustValidateInput(trust
);
1030 /* @@@ 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. */
1031 result
= SecOSStatusWith(^bool (CFErrorRef
*error
) {
1032 trust
->_trustResult
= SECURITYD_XPC(sec_trust_evaluate
,
1033 certs_anchors_bool_bool_policies_responses_scts_logs_date_ag_to_details_info_chain_int_error_request
,
1034 trust
->_certificates
, trust
->_anchors
, trust
->_anchorsOnly
, trust
->_keychainsAllowed
,
1035 trust
->_policies
, trust
->_responses
, trust
->_SCTs
, trust
->_trustedLogs
,
1036 SecTrustGetVerifyTime(trust
), SecAccessGroupsGetCurrent(),
1037 &trust
->_details
, &trust
->_info
, &trust
->_chain
, error
);
1038 if (trust
->_trustResult
== kSecTrustResultInvalid
/* TODO check domain */ &&
1039 SecErrorGetOSStatus(*error
) == errSecNotAvailable
&&
1040 CFArrayGetCount(trust
->_certificates
)) {
1041 /* We failed to talk to securityd. The only time this should
1042 happen is when we are running prior to launchd enabling
1043 registration of services. This currently happens when we
1044 are running from the ramdisk. To make ASR happy we initialize
1045 _chain and return success with a failure as the trustResult, to
1046 make it seem like we did a cert evaluation, so ASR can extract
1047 the public key from the leaf. */
1048 trust
->_chain
= SecCertificatePathCreate(NULL
, (SecCertificateRef
)CFArrayGetValueAtIndex(trust
->_certificates
, 0), NULL
);
1050 CFReleaseNull(*error
);
1053 SecTrustPostEvaluate(trust
);
1054 trust
->_trustResultBeforeExceptions
= trust
->_trustResult
;
1055 return trust
->_trustResult
!= kSecTrustResultInvalid
;
1062 /* Helper for the qsort below. */
1063 static int compare_strings(const void *a1
, const void *a2
) {
1064 CFStringRef s1
= *(CFStringRef
*)a1
;
1065 CFStringRef s2
= *(CFStringRef
*)a2
;
1066 return (int) CFStringCompare(s1
, s2
, kCFCompareForcedOrdering
);
1069 CFStringRef
SecTrustCopyFailureDescription(SecTrustRef trust
) {
1070 CFMutableStringRef reason
= CFStringCreateMutable(NULL
, 0);
1071 CFArrayRef details
= SecTrustGetDetails(trust
);
1072 CFIndex pathLength
= details
? CFArrayGetCount(details
) : 0;
1073 for (CFIndex ix
= 0; ix
< pathLength
; ++ix
) {
1074 CFDictionaryRef detail
= (CFDictionaryRef
)CFArrayGetValueAtIndex(details
, ix
);
1075 CFIndex dCount
= CFDictionaryGetCount(detail
);
1078 CFStringAppend(reason
, CFSTR(" [leaf"));
1079 else if (ix
== pathLength
- 1)
1080 CFStringAppend(reason
, CFSTR(" [root"));
1082 CFStringAppendFormat(reason
, NULL
, CFSTR(" [ca%" PRIdCFIndex
), ix
);
1084 const void *keys
[dCount
];
1085 CFDictionaryGetKeysAndValues(detail
, &keys
[0], NULL
);
1086 qsort(&keys
[0], dCount
, sizeof(keys
[0]), compare_strings
);
1087 for (CFIndex kix
= 0; kix
< dCount
; ++kix
) {
1088 CFStringRef key
= keys
[kix
];
1089 const void *value
= CFDictionaryGetValue(detail
, key
);
1090 CFStringAppendFormat(reason
, NULL
, CFSTR(" %@%@"), key
,
1091 (CFGetTypeID(value
) == CFBooleanGetTypeID()
1092 ? CFSTR("") : value
));
1094 CFStringAppend(reason
, CFSTR("]"));
1101 /* On OS X we need SecTrustCopyPublicKey to give us a CDSA-based SecKeyRef,
1102 so we will refer to this one internally as SecTrustCopyPublicKey_ios,
1103 and call it from SecTrustCopyPublicKey.
1105 SecKeyRef
SecTrustCopyPublicKey_ios(SecTrustRef trust
)
1107 SecKeyRef
SecTrustCopyPublicKey(SecTrustRef trust
)
1113 if (!trust
->_publicKey
) {
1114 if (!trust
->_chain
) {
1115 /* Trust hasn't been evaluated yet, first attempt to retrieve public key from leaf cert as is. */
1117 trust
->_publicKey
= SecCertificateCopyPublicKey_ios(SecTrustGetCertificateAtIndex(trust
, 0));
1119 trust
->_publicKey
= SecCertificateCopyPublicKey(SecTrustGetCertificateAtIndex(trust
, 0));
1122 if (!trust
->_publicKey
) {
1123 /* If this fails, use the passed-in certs in order as if they are a valid cert path,
1124 and attempt to extract the key. */
1125 SecCertificatePathRef path
;
1126 // SecCertificatePathCreateWithArray would have crashed if this code was ever called,
1127 // since it expected an array of CFDataRefs, not an array of certificates.
1128 path
= SecCertificatePathCreateWithArray(trust
->_certificates
);
1129 trust
->_publicKey
= SecCertificatePathCopyPublicKeyAtIndex(path
, 0);
1133 if (!trust
->_publicKey
) {
1134 /* Last resort, we evaluate the trust to get a _chain. */
1135 SecTrustEvaluateIfNecessary(trust
);
1138 if (trust
->_chain
) {
1139 trust
->_publicKey
= SecCertificatePathCopyPublicKeyAtIndex(trust
->_chain
, 0);
1143 if (trust
->_publicKey
)
1144 CFRetain(trust
->_publicKey
);
1146 return trust
->_publicKey
;
1149 CFIndex
SecTrustGetCertificateCount(SecTrustRef trust
) {
1153 SecTrustEvaluateIfNecessary(trust
);
1154 return (trust
->_chain
) ? SecCertificatePathGetCount(trust
->_chain
) : 1;
1157 SecCertificateRef
SecTrustGetCertificateAtIndex(SecTrustRef trust
,
1163 return (SecCertificateRef
)CFArrayGetValueAtIndex(trust
->_certificates
, 0);
1165 SecTrustEvaluateIfNecessary(trust
);
1166 return (trust
->_chain
) ? SecCertificatePathGetCertificateAtIndex(trust
->_chain
, ix
) : NULL
;
1169 CFDictionaryRef
SecTrustCopyInfo(SecTrustRef trust
) {
1173 SecTrustEvaluateIfNecessary(trust
);
1174 CFDictionaryRef info
= trust
->_info
;
1180 CFArrayRef
SecTrustGetTrustExceptionsArray(SecTrustRef trust
) {
1181 return trust
->_exceptions
;
1184 CFDataRef
SecTrustCopyExceptions(SecTrustRef trust
) {
1185 CFArrayRef details
= SecTrustGetDetails(trust
);
1186 CFIndex pathLength
= details
? CFArrayGetCount(details
) : 0;
1187 CFMutableArrayRef exceptions
= CFArrayCreateMutable(kCFAllocatorDefault
, pathLength
, &kCFTypeArrayCallBacks
);
1189 for (ix
= 0; ix
< pathLength
; ++ix
) {
1190 CFDictionaryRef detail
= (CFDictionaryRef
)CFArrayGetValueAtIndex(details
, ix
);
1191 CFIndex detailCount
= CFDictionaryGetCount(detail
);
1192 CFMutableDictionaryRef exception
;
1193 if (ix
== 0 || detailCount
> 0) {
1194 exception
= CFDictionaryCreateMutableCopy(kCFAllocatorDefault
, detailCount
+ 1, detail
);
1195 SecCertificateRef certificate
= SecTrustGetCertificateAtIndex(trust
, ix
);
1196 CFDataRef digest
= SecCertificateGetSHA1Digest(certificate
);
1197 CFDictionaryAddValue(exception
, kSecCertificateDetailSHA1Digest
, digest
);
1199 /* Add empty exception dictionaries for non leaf certs which have no exceptions to save space. */
1200 exception
= (CFMutableDictionaryRef
)CFDictionaryCreate(kCFAllocatorDefault
, NULL
, NULL
, 0,
1201 &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
1203 CFArrayAppendValue(exceptions
, exception
);
1204 CFRelease(exception
);
1207 /* Remove any trailing empty dictionaries to save even more space (we skip the leaf
1208 since it will never be empty). */
1209 for (ix
= pathLength
; ix
-- > 1;) {
1210 CFDictionaryRef exception
= (CFDictionaryRef
)CFArrayGetValueAtIndex(exceptions
, ix
);
1211 if (CFDictionaryGetCount(exception
) == 0) {
1212 CFArrayRemoveValueAtIndex(exceptions
, ix
);
1218 CFDataRef encodedExceptions
= CFPropertyListCreateData(kCFAllocatorDefault
,
1219 exceptions
, kCFPropertyListBinaryFormat_v1_0
, 0, NULL
);
1220 CFRelease(exceptions
);
1222 return encodedExceptions
;
1225 bool SecTrustSetExceptions(SecTrustRef trust
, CFDataRef encodedExceptions
) {
1229 CFArrayRef exceptions
= NULL
;
1231 if (NULL
!= encodedExceptions
) {
1232 exceptions
= (CFArrayRef
)CFPropertyListCreateWithData(kCFAllocatorDefault
,
1233 encodedExceptions
, kCFPropertyListImmutable
, NULL
, NULL
);
1236 if (exceptions
&& CFGetTypeID(exceptions
) != CFArrayGetTypeID()) {
1237 CFRelease(exceptions
);
1241 if (trust
->_exceptions
&& !exceptions
) {
1242 /* Exceptions are currently set and now we are clearing them. */
1243 trust
->_trustResult
= trust
->_trustResultBeforeExceptions
;
1246 CFReleaseSafe(trust
->_exceptions
);
1247 trust
->_exceptions
= exceptions
;
1249 /* If there is a valid exception entry for our current leaf we're golden. */
1250 if (SecTrustGetExceptionForCertificateAtIndex(trust
, 0))
1253 /* The passed in exceptions didn't match our current leaf, so we discard it. */
1254 CFReleaseNull(trust
->_exceptions
);
1258 CFArrayRef
SecTrustCopySummaryPropertiesAtIndex(SecTrustRef trust
, CFIndex ix
) {
1259 CFMutableArrayRef summary
;
1260 SecCertificateRef certificate
= SecTrustGetCertificateAtIndex(trust
, ix
);
1261 summary
= SecCertificateCopySummaryProperties(certificate
,
1262 SecTrustGetVerifyTime(trust
));
1263 /* FIXME Add more details in the failure case. */
1268 CFArrayRef
SecTrustCopyDetailedPropertiesAtIndex(SecTrustRef trust
, CFIndex ix
) {
1270 SecCertificateRef certificate
= SecTrustGetCertificateAtIndex(trust
, ix
);
1271 summary
= SecCertificateCopyProperties(certificate
);
1281 Can be on any non root cert in the chain.
1283 Short circuit: Yes (No other errors matter after this one)
1284 Non recoverable error
1285 Trust UI: Invalid certificate chain linkage
1286 Cert UI: Invalid linkage to parent certificate
1288 CFStringRef kSecPolicyCheckIdLinkage
= CFSTR("IdLinkage");
1290 /* X.509 required checks.
1291 Can be on any cert in the chain
1293 Short circuit: Yes (No other errors matter after this one)
1294 Non recoverable error
1295 Trust UI: (One or more) unsupported critical extensions found.
1297 /* If we have no names for the extention oids use:
1298 Cert UI: One or more unsupported critical extensions found (Non recoverable error).
1299 Cert UI: Unsupported 'foo', 'bar', baz' critical extensions found.
1301 CFStringRef kSecPolicyCheckCriticalExtensions
= CFSTR("CriticalExtensions");
1302 /* Cert UI: Unsupported critical Qualified Certificate Statements extension found (Non recoverable error). */
1303 CFStringRef kSecPolicyCheckQualifiedCertStatements
= CFSTR("QualifiedCertStatements");
1304 /* Cert UI: Certificate has an empty subject (and no critial subjectAltname). */
1307 Only apply to the anchor.
1309 Short circuit: No (Under discussion)
1311 Trust UI: Root certificate is not trusted (for this policy/app/host/whatever?)
1312 Cert UI: Not a valid anchor
1314 CFStringRef kSecPolicyCheckAnchorTrusted
= CFSTR("AnchorTrusted");
1315 CFStringRef kSecPolicyCheckAnchorSHA1
= CFSTR("AnchorSHA1");
1317 CFStringRef kSecPolicyCheckAnchorApple
= CFSTR("AnchorApple");
1318 CFStringRef kSecPolicyAppleAnchorIncludeTestRoots
= CFSTR("AnchorAppleTestRoots");
1321 Only applies to leaf
1325 Trust UI: (Hostname|email address) mismatch
1327 CFStringRef kSecPolicyCheckSSLHostname
= CFSTR("SSLHostname");
1329 /* Policy specific checks.
1330 Can be on any cert in the chain
1334 Trust UI: Certificate chain is not valid for the current policy.
1335 OR: (One or more) certificates in the chain are not valid for the current policy/application
1337 CFStringRef kSecPolicyCheckNonEmptySubject
= CFSTR("NonEmptySubject");
1338 /* Cert UI: Non CA certificate used as CA.
1339 Cert UI: CA certificate used as leaf.
1340 Cert UI: Cert chain length exceeded.
1341 Cert UI: Basic constraints extension not critical (non fatal).
1342 Cert UI: Leaf certificate has basic constraints extension (non fatal).
1344 CFStringRef kSecPolicyCheckBasicConstraints
= CFSTR("BasicConstraints");
1345 CFStringRef kSecPolicyCheckKeyUsage
= CFSTR("KeyUsage");
1346 CFStringRef kSecPolicyCheckExtendedKeyUsage
= CFSTR("ExtendedKeyUsage");
1347 /* Checks that the issuer of the leaf has exactly one Common Name and that it
1348 matches the specified string. */
1349 CFStringRef kSecPolicyCheckIssuerCommonName
= CFSTR("IssuerCommonName");
1350 /* Checks that the leaf has exactly one Common Name and that it has the
1351 specified string as a prefix. */
1352 CFStringRef kSecPolicyCheckSubjectCommonNamePrefix
= CFSTR("SubjectCommonNamePrefix");
1353 /* Check that the certificate chain length matches the specificed CFNumberRef
1355 CFStringRef kSecPolicyCheckChainLength
= CFSTR("ChainLength");
1356 CFStringRef kSecPolicyCheckNotValidBefore
= CFSTR("NotValidBefore");
1359 Can be on any cert in the chain
1363 Trust UI: One or more certificates have expired or are not valid yet.
1364 OS: The (root|intermediate|leaf) certificate (expired on 'date'|is not valid until 'date')
1365 Cert UI: Certificate (expired on 'date'|is not valid until 'date')
1367 CFStringRef kSecPolicyCheckValidIntermediates
= CFSTR("ValidIntermediates");
1368 CFStringRef kSecPolicyCheckValidLeaf
= CFSTR("ValidLeaf");
1369 CFStringRef kSecPolicyCheckValidRoot
= CFSTR("ValidRoot");
1373 struct TrustFailures
{
1375 bool unknownCritExtn
;
1376 bool untrustedAnchor
;
1377 bool hostnameMismatch
;
1384 static void applyDetailProperty(const void *_key
, const void *_value
,
1386 CFStringRef key
= (CFStringRef
)_key
;
1387 struct TrustFailures
*tf
= (struct TrustFailures
*)context
;
1388 if (CFGetTypeID(_value
) != CFBooleanGetTypeID()) {
1389 /* Value isn't a CFBooleanRef, oh no! */
1392 CFBooleanRef value
= (CFBooleanRef
)_value
;
1393 if (CFBooleanGetValue(value
)) {
1394 /* Not an actual failure so we don't report it. */
1398 /* @@@ FIXME: Report a different return value when something is in the
1399 details but masked out by an exception and use that below for display
1401 if (CFEqual(key
, kSecPolicyCheckIdLinkage
)) {
1402 tf
->badLinkage
= true;
1403 } else if (CFEqual(key
, kSecPolicyCheckCriticalExtensions
)
1404 || CFEqual(key
, kSecPolicyCheckQualifiedCertStatements
)) {
1405 tf
->unknownCritExtn
= true;
1406 } else if (CFEqual(key
, kSecPolicyCheckAnchorTrusted
)
1407 || CFEqual(key
, kSecPolicyCheckAnchorSHA1
)
1408 || CFEqual(key
, kSecPolicyCheckAnchorSHA256
)
1409 || CFEqual(key
, kSecPolicyCheckAnchorApple
)) {
1410 tf
->untrustedAnchor
= true;
1411 } else if (CFEqual(key
, kSecPolicyCheckSSLHostname
)) {
1412 tf
->hostnameMismatch
= true;
1413 } else if (CFEqual(key
, kSecPolicyCheckValidIntermediates
)
1414 || CFEqual(key
, kSecPolicyCheckValidLeaf
)
1415 || CFEqual(key
, kSecPolicyCheckValidRoot
)) {
1416 tf
->invalidCert
= true;
1417 } else if (CFEqual(key
, kSecPolicyCheckWeakIntermediates
)
1418 || CFEqual(key
, kSecPolicyCheckWeakLeaf
)
1419 || CFEqual(key
, kSecPolicyCheckWeakRoot
)) {
1421 } else if (CFEqual(key
, kSecPolicyCheckRevocation
)) {
1422 tf
->revocation
= true;
1424 /* Anything else is a policy failure. */
1426 if (CFEqual(key
, kSecPolicyCheckNonEmptySubject
)
1427 || CFEqual(key
, kSecPolicyCheckBasicConstraints
)
1428 || CFEqual(key
, kSecPolicyCheckKeyUsage
)
1429 || CFEqual(key
, kSecPolicyCheckExtendedKeyUsage
)
1430 || CFEqual(key
, kSecPolicyCheckIssuerCommonName
)
1431 || CFEqual(key
, kSecPolicyCheckSubjectCommonNamePrefix
)
1432 || CFEqual(key
, kSecPolicyCheckChainLength
)
1433 || CFEqual(key
, kSecPolicyCheckNotValidBefore
))
1436 tf
->policyFail
= true;
1440 static void appendError(CFMutableArrayRef properties
, CFStringRef error
) {
1441 CFStringRef localizedError
= SecFrameworkCopyLocalizedString(error
,
1442 CFSTR("SecCertificate"));
1443 if (!localizedError
) {
1444 //secerror("WARNING: localized error string was not found in Security.framework");
1445 localizedError
= CFRetain(error
);
1447 appendProperty(properties
, kSecPropertyTypeError
, NULL
, NULL
,
1449 CFReleaseNull(localizedError
);
1452 #if SECTRUST_OSX || !TARGET_OS_IPHONE
1453 /* OS X properties array has a different structure and is implemented SecTrust.cpp. */
1454 CFArrayRef
SecTrustCopyProperties_ios(SecTrustRef trust
)
1456 CFArrayRef
SecTrustCopyProperties(SecTrustRef trust
)
1459 CFArrayRef details
= SecTrustGetDetails(trust
);
1463 struct TrustFailures tf
= {};
1465 CFIndex ix
, count
= CFArrayGetCount(details
);
1466 for (ix
= 0; ix
< count
; ++ix
) {
1467 CFDictionaryRef detail
= (CFDictionaryRef
)
1468 CFArrayGetValueAtIndex(details
, ix
);
1469 /* We now have a detail dictionary for certificate at index ix, with
1470 a key value pair for each failed policy check. Let's convert it
1471 from Ro-Man form into something a Hu-Man can understand. */
1472 CFDictionaryApplyFunction(detail
, applyDetailProperty
, &tf
);
1475 CFMutableArrayRef properties
= CFArrayCreateMutable(kCFAllocatorDefault
, 0,
1476 &kCFTypeArrayCallBacks
);
1477 /* The badLinkage and unknownCritExtn failures are short circuited, since
1478 you can't recover from those errors. */
1479 if (tf
.badLinkage
) {
1480 appendError(properties
, CFSTR("Invalid certificate chain linkage."));
1481 } else if (tf
.unknownCritExtn
) {
1482 appendError(properties
, CFSTR("One or more unsupported critical extensions found."));
1484 if (tf
.untrustedAnchor
) {
1485 appendError(properties
, CFSTR("Root certificate is not trusted."));
1487 if (tf
.hostnameMismatch
) {
1488 appendError(properties
, CFSTR("Hostname mismatch."));
1490 if (tf
.policyFail
) {
1491 appendError(properties
, CFSTR("Policy requirements not met."));
1493 if (tf
.invalidCert
) {
1494 appendError(properties
, CFSTR("One or more certificates have expired or are not valid yet."));
1497 appendError(properties
, CFSTR("One or more certificates is using a weak key size."));
1499 if (tf
.revocation
) {
1500 appendError(properties
, CFSTR("One or more certificates have been revoked."));
1504 if (CFArrayGetCount(properties
) == 0) {
1505 /* The certificate chain is trusted, return an empty plist */
1506 CFReleaseNull(properties
);
1512 CFDictionaryRef
SecTrustCopyResult(SecTrustRef trust
) {
1513 // Builds and returns a dictionary of evaluation results.
1517 CFMutableDictionaryRef results
= CFDictionaryCreateMutable(NULL
, 0,
1518 &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
1520 // kSecTrustResultDetails (per-cert results)
1521 CFArrayRef details
= SecTrustGetDetails(trust
);
1523 CFDictionarySetValue(results
, (const void *)kSecTrustResultDetails
, (const void *)details
);
1526 // kSecTrustResultValue (overall trust result)
1527 CFNumberRef numValue
= CFNumberCreate(NULL
, kCFNumberSInt32Type
, &trust
->_trustResult
);
1529 CFDictionarySetValue(results
, (const void *)kSecTrustResultValue
, (const void *)numValue
);
1530 CFRelease(numValue
);
1532 CFDictionaryRef info
= trust
->_info
;
1533 if (trust
->_trustResult
== kSecTrustResultInvalid
|| !info
) {
1534 return results
; // we have nothing more to add
1537 // kSecTrustEvaluationDate
1538 CFDateRef evaluationDate
= trust
->_verifyDate
;
1539 if (evaluationDate
) {
1540 CFDictionarySetValue(results
, (const void *)kSecTrustEvaluationDate
, (const void *)evaluationDate
);
1543 // kSecTrustCertificateTransparency
1544 CFBooleanRef ctValue
;
1545 if (CFDictionaryGetValueIfPresent(info
, kSecTrustInfoCertificateTransparencyKey
, (const void **)&ctValue
)) {
1546 CFDictionarySetValue(results
, (const void *)kSecTrustCertificateTransparency
, (const void *)ctValue
);
1549 // kSecTrustCertificateTransparencyWhiteList
1550 CFBooleanRef ctWhiteListValue
;
1551 if (CFDictionaryGetValueIfPresent(info
, kSecTrustInfoCertificateTransparencyWhiteListKey
, (const void **)&ctWhiteListValue
)) {
1552 CFDictionarySetValue(results
, (const void *)kSecTrustCertificateTransparencyWhiteList
, (const void *)ctWhiteListValue
);
1555 // kSecTrustExtendedValidation
1556 CFBooleanRef evValue
;
1557 if (CFDictionaryGetValueIfPresent(info
, kSecTrustInfoExtendedValidationKey
, (const void **)&evValue
)) {
1558 CFDictionarySetValue(results
, (const void *)kSecTrustExtendedValidation
, (const void *)evValue
);
1561 // kSecTrustOrganizationName
1562 CFStringRef organizationName
;
1563 if (CFDictionaryGetValueIfPresent(info
, kSecTrustInfoCompanyNameKey
, (const void **)&organizationName
)) {
1564 CFDictionarySetValue(results
, (const void *)kSecTrustOrganizationName
, (const void *)organizationName
);
1567 // kSecTrustRevocationChecked
1568 CFBooleanRef revocationChecked
;
1569 if (CFDictionaryGetValueIfPresent(info
, kSecTrustRevocationChecked
, (const void **)&revocationChecked
)) {
1570 CFDictionarySetValue(results
, (const void *)kSecTrustRevocationChecked
, (const void *)revocationChecked
);
1573 // kSecTrustRevocationReason
1574 CFNumberRef revocationReason
;
1575 if (CFDictionaryGetValueIfPresent(info
, kSecTrustRevocationReason
, (const void **)&revocationReason
)) {
1576 CFDictionarySetValue(results
, (const void *)kSecTrustRevocationReason
, (const void *)revocationReason
);
1579 // kSecTrustRevocationValidUntilDate
1580 CFDateRef validUntilDate
;
1581 if (CFDictionaryGetValueIfPresent(info
, kSecTrustRevocationValidUntilDate
, (const void **)&validUntilDate
)) {
1582 CFDictionarySetValue(results
, (const void *)kSecTrustRevocationValidUntilDate
, (const void *)validUntilDate
);
1588 // Return 0 upon error.
1589 static int to_int_error_request(enum SecXPCOperation op
, CFErrorRef
*error
) {
1590 __block
int64_t result
= 0;
1591 securityd_send_sync_and_do(op
, error
, NULL
, ^bool(xpc_object_t response
, CFErrorRef
*error
) {
1592 result
= xpc_dictionary_get_int64(response
, kSecXPCKeyResult
);
1594 return SecError(errSecInternal
, error
, CFSTR("int64 missing in response"));
1600 // version 0 -> error, so we need to start at version 1 or later.
1601 OSStatus
SecTrustGetOTAPKIAssetVersionNumber(int* versionNumber
)
1604 os_activity_t trace_activity
= os_activity_start("SecTrustGetOTAPKIAssetVersionNumber", OS_ACTIVITY_FLAG_DEFAULT
);
1605 result
= SecOSStatusWith(^bool(CFErrorRef
*error
) {
1607 return SecError(errSecParam
, error
, CFSTR("versionNumber is NULL"));
1609 return (*versionNumber
= SECURITYD_XPC(sec_ota_pki_asset_version
, to_int_error_request
, error
)) != 0;
1612 os_activity_end(trace_activity
);
1616 #define do_if_registered(sdp, ...) if (gSecurityd && gSecurityd->sdp) { return gSecurityd->sdp(__VA_ARGS__); }
1618 static bool xpc_dictionary_entry_is_type(xpc_object_t dictionary
, const char *key
, xpc_type_t type
)
1620 xpc_object_t value
= xpc_dictionary_get_value(dictionary
, key
);
1622 return value
&& (xpc_get_type(value
) == type
);
1625 OSStatus
SecTrustOTAPKIGetUpdatedAsset(int* didUpdateAsset
)
1627 CFErrorRef error
= NULL
;
1628 do_if_registered(sec_ota_pki_get_new_asset
, &error
);
1631 xpc_object_t message
= securityd_create_message(kSecXPCOpOTAPKIGetNewAsset
, &error
);
1634 xpc_object_t response
= securityd_message_with_reply_sync(message
, &error
);
1636 if (response
&& xpc_dictionary_entry_is_type(response
, kSecXPCKeyResult
, XPC_TYPE_INT64
))
1638 num
= (int64_t) xpc_dictionary_get_int64(response
, kSecXPCKeyResult
);
1639 xpc_release(response
);
1642 xpc_release(message
);
1645 if (NULL
!= didUpdateAsset
)
1647 *didUpdateAsset
= (int)num
;
1653 * This function performs an evaluation of the leaf certificate only, and
1654 * does so in the process that called it. Its primary use is in SecItemCopyMatching
1655 * when kSecMatchPolicy is in the dictionary.
1657 OSStatus
SecTrustEvaluateLeafOnly(SecTrustRef trust
, SecTrustResultType
*result
) {
1661 OSStatus status
= errSecSuccess
;
1662 if((status
= SecTrustValidateInput(trust
))) {
1666 struct OpaqueSecLeafPVC pvc
;
1667 SecCertificateRef leaf
= (SecCertificateRef
)CFArrayGetValueAtIndex(trust
->_certificates
, 0);
1669 SecLeafPVCInit(&pvc
, leaf
, trust
->_policies
, SecTrustGetVerifyTime(trust
));
1671 if(!SecLeafPVCLeafChecks(&pvc
)) {
1672 trust
->_trustResult
= kSecTrustResultRecoverableTrustFailure
;
1674 trust
->_trustResult
= kSecTrustResultUnspecified
;
1677 /* Set other result context information */
1678 trust
->_details
= CFRetainSafe(pvc
.details
);
1679 trust
->_info
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0,
1680 &kCFTypeDictionaryKeyCallBacks
,
1681 &kCFTypeDictionaryValueCallBacks
);
1682 trust
->_chain
= SecCertificatePathCreate(NULL
, (SecCertificateRef
)CFArrayGetValueAtIndex(trust
->_certificates
, 0), NULL
);
1684 SecLeafPVCDelete(&pvc
);
1686 /* log to syslog when there is a trust failure */
1687 if (trust
->_trustResult
!= kSecTrustResultUnspecified
) {
1688 CFStringRef failureDesc
= SecTrustCopyFailureDescription(trust
);
1689 secerror("%@", failureDesc
);
1690 CFRelease(failureDesc
);
1694 *result
= trust
->_trustResult
;
1700 static void deserializeCert(const void *value
, void *context
) {
1701 CFDataRef certData
= (CFDataRef
)value
;
1702 if (isData(certData
)) {
1703 SecCertificateRef cert
= SecCertificateCreateWithData(NULL
, certData
);
1705 CFArrayAppendValue((CFMutableArrayRef
)context
, cert
);
1711 static CFArrayRef
SecCertificateArrayDeserialize(CFArrayRef serializedCertificates
) {
1712 CFMutableArrayRef result
= NULL
;
1713 require_quiet(isArray(serializedCertificates
), errOut
);
1714 CFIndex count
= CFArrayGetCount(serializedCertificates
);
1715 result
= CFArrayCreateMutable(kCFAllocatorDefault
, count
, &kCFTypeArrayCallBacks
);
1716 CFRange all_certs
= { 0, count
};
1717 CFArrayApplyFunction(serializedCertificates
, all_certs
, deserializeCert
, result
);
1722 static void serializeCertificate(const void *value
, void *context
) {
1723 SecCertificateRef cert
= (SecCertificateRef
)value
;
1724 if (cert
&& SecCertificateGetTypeID() == CFGetTypeID(cert
)) {
1725 CFDataRef certData
= SecCertificateCopyData(cert
);
1727 CFArrayAppendValue((CFMutableArrayRef
)context
, certData
);
1728 CFRelease(certData
);
1733 static CFArrayRef
SecCertificateArraySerialize(CFArrayRef certificates
) {
1734 CFMutableArrayRef result
= NULL
;
1735 require_quiet(isArray(certificates
), errOut
);
1736 CFIndex count
= CFArrayGetCount(certificates
);
1737 result
= CFArrayCreateMutable(NULL
, count
, &kCFTypeArrayCallBacks
);
1738 CFRange all_certificates
= { 0, count
};
1739 CFArrayApplyFunction(certificates
, all_certificates
, serializeCertificate
, result
);
1744 static CFPropertyListRef
SecTrustCopyPlist(SecTrustRef trust
) {
1745 CFMutableDictionaryRef output
= NULL
;
1746 CFNumberRef trustResult
= NULL
;
1748 output
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
,
1749 &kCFTypeDictionaryValueCallBacks
);
1750 if (trust
->_certificates
) {
1751 CFArrayRef serializedCerts
= SecCertificateArraySerialize(trust
->_certificates
);
1752 if (serializedCerts
) {
1753 CFDictionaryAddValue(output
, CFSTR(kSecTrustCertificatesKey
), serializedCerts
);
1754 CFRelease(serializedCerts
);
1757 if (trust
->_anchors
) {
1758 CFArrayRef serializedAnchors
= SecCertificateArraySerialize(trust
->_anchors
);
1759 if (serializedAnchors
) {
1760 CFDictionaryAddValue(output
, CFSTR(kSecTrustAnchorsKey
), serializedAnchors
);
1761 CFRelease(serializedAnchors
);
1764 if (trust
->_policies
) {
1765 CFArrayRef serializedPolicies
= SecPolicyArrayCreateSerialized(trust
->_policies
);
1766 if (serializedPolicies
) {
1767 CFDictionaryAddValue(output
, CFSTR(kSecTrustPoliciesKey
), serializedPolicies
);
1768 CFRelease(serializedPolicies
);
1771 if (trust
->_responses
) {
1772 CFDictionaryAddValue(output
, CFSTR(kSecTrustResponsesKey
), trust
->_responses
);
1775 CFDictionaryAddValue(output
, CFSTR(kSecTrustSCTsKey
), trust
->_SCTs
);
1777 if (trust
->_trustedLogs
) {
1778 CFDictionaryAddValue(output
, CFSTR(kSecTrustTrustedLogsKey
), trust
->_trustedLogs
);
1780 if (trust
->_verifyDate
) {
1781 CFDictionaryAddValue(output
, CFSTR(kSecTrustVerifyDateKey
), trust
->_verifyDate
);
1783 if (trust
->_chain
) {
1784 CFArrayRef serializedChain
= SecCertificatePathCreateSerialized(trust
->_chain
, NULL
);
1785 if (serializedChain
) {
1786 CFDictionaryAddValue(output
, CFSTR(kSecTrustChainKey
), serializedChain
);
1787 CFRelease(serializedChain
);
1790 if (trust
->_details
) {
1791 CFDictionaryAddValue(output
, CFSTR(kSecTrustDetailsKey
), trust
->_details
);
1794 CFDictionaryAddValue(output
, CFSTR(kSecTrustInfoKey
), trust
->_info
);
1796 if (trust
->_exceptions
) {
1797 CFDictionaryAddValue(output
, CFSTR(kSecTrustExceptionsKey
), trust
->_exceptions
);
1799 trustResult
= CFNumberCreate(NULL
, kCFNumberSInt32Type
, &trust
->_trustResult
);
1801 CFDictionaryAddValue(output
, CFSTR(kSecTrustResultKey
), trustResult
);
1803 if (trust
->_anchorsOnly
) {
1804 CFDictionaryAddValue(output
, CFSTR(kSecTrustAnchorsOnlyKey
), kCFBooleanTrue
);
1806 CFDictionaryAddValue(output
, CFSTR(kSecTrustAnchorsOnlyKey
), kCFBooleanFalse
);
1808 if (trust
->_keychainsAllowed
) {
1809 CFDictionaryAddValue(output
, CFSTR(kSecTrustKeychainsAllowedKey
), kCFBooleanTrue
);
1811 CFDictionaryAddValue(output
, CFSTR(kSecTrustKeychainsAllowedKey
), kCFBooleanFalse
);
1814 CFReleaseNull(trustResult
);
1818 CFDataRef
SecTrustSerialize(SecTrustRef trust
, CFErrorRef
*error
) {
1819 CFPropertyListRef plist
= NULL
;
1820 CFDataRef derTrust
= NULL
;
1821 require_action_quiet(trust
, out
,
1822 SecError(errSecParam
, error
, CFSTR("null trust input")));
1823 require_action_quiet(plist
= SecTrustCopyPlist(trust
), out
,
1824 SecError(errSecDecode
, error
, CFSTR("unable to create trust plist")));
1825 require_quiet(derTrust
= CFPropertyListCreateDERData(NULL
, plist
, error
), out
);
1828 CFReleaseNull(plist
);
1832 static OSStatus
SecTrustCreateFromPlist(CFPropertyListRef plist
, SecTrustRef CF_RETURNS_RETAINED
*trust
) {
1833 OSStatus status
= errSecParam
;
1834 SecTrustRef output
= NULL
;
1835 CFTypeRef serializedCertificates
= NULL
, serializedPolicies
= NULL
, serializedAnchors
= NULL
,
1836 serializedChain
= NULL
;
1837 CFNumberRef trustResultNum
= NULL
;
1838 CFArrayRef certificates
= NULL
, policies
= NULL
, anchors
= NULL
, responses
= NULL
,
1839 SCTs
= NULL
, trustedLogs
= NULL
, details
= NULL
, exceptions
= NULL
;
1840 CFDateRef verifyDate
= NULL
;
1841 CFDictionaryRef info
= NULL
;
1842 SecCertificatePathRef chain
= NULL
;
1844 require_quiet(CFDictionaryGetTypeID() == CFGetTypeID(plist
), out
);
1845 require_quiet(serializedCertificates
= CFDictionaryGetValue(plist
, CFSTR(kSecTrustCertificatesKey
)), out
);
1846 require_quiet(certificates
= SecCertificateArrayDeserialize(serializedCertificates
), out
);
1847 require_quiet(serializedPolicies
= CFDictionaryGetValue(plist
, CFSTR(kSecTrustPoliciesKey
)), out
);
1848 require_quiet(policies
= SecPolicyArrayCreateDeserialized(serializedPolicies
), out
);
1849 require_noerr_quiet(status
= SecTrustCreateWithCertificates(certificates
, policies
, &output
), out
);
1851 serializedAnchors
= CFDictionaryGetValue(plist
, CFSTR(kSecTrustAnchorsKey
));
1852 if (isArray(serializedAnchors
)) {
1853 anchors
= SecCertificateArrayDeserialize(serializedAnchors
);
1854 output
->_anchors
= anchors
;
1856 responses
= CFDictionaryGetValue(plist
, CFSTR(kSecTrustResponsesKey
));
1857 if (isArray(responses
)) {
1858 output
->_responses
= CFRetainSafe(responses
);
1860 SCTs
= CFDictionaryGetValue(plist
, CFSTR(kSecTrustSCTsKey
));
1861 if (isArray(responses
)) {
1862 output
->_SCTs
= CFRetainSafe(SCTs
);
1864 trustedLogs
= CFDictionaryGetValue(plist
, CFSTR(kSecTrustTrustedLogsKey
));
1865 if (isArray(trustedLogs
)) {
1866 output
->_trustedLogs
= CFRetainSafe(trustedLogs
);
1868 verifyDate
= CFDictionaryGetValue(plist
, CFSTR(kSecTrustVerifyDateKey
));
1869 if (isDate(verifyDate
)) {
1870 output
->_verifyDate
= CFRetainSafe(verifyDate
);
1872 serializedChain
= CFDictionaryGetValue(plist
, CFSTR(kSecTrustChainKey
));
1873 if (isArray(serializedChain
)) {
1874 chain
= SecCertificatPathCreateDeserialized(serializedChain
, NULL
);
1875 output
->_chain
= chain
;
1877 details
= CFDictionaryGetValue(plist
, CFSTR(kSecTrustDetailsKey
));
1878 if (isArray(details
)) {
1879 output
->_details
= CFRetainSafe(details
);
1881 info
= CFDictionaryGetValue(plist
, CFSTR(kSecTrustInfoKey
));
1882 if (isDictionary(info
)) {
1883 output
->_info
= CFRetainSafe(info
);
1885 exceptions
= CFDictionaryGetValue(plist
, CFSTR(kSecTrustExceptionsKey
));
1886 if (isArray(exceptions
)) {
1887 output
->_exceptions
= CFRetainSafe(exceptions
);
1889 int32_t trustResult
= -1;
1890 trustResultNum
= CFDictionaryGetValue(plist
, CFSTR(kSecTrustResultKey
));
1891 if (isNumber(trustResultNum
) && CFNumberGetValue(trustResultNum
, kCFNumberSInt32Type
, &trustResult
) &&
1892 (trustResult
>= 0)) {
1893 output
->_trustResult
= trustResult
;
1895 status
= errSecParam
;
1897 if (CFDictionaryGetValue(plist
, CFSTR(kSecTrustAnchorsOnlyKey
)) == kCFBooleanTrue
) {
1898 output
->_anchorsOnly
= true;
1899 } /* false is set by default */
1900 if (CFDictionaryGetValue(plist
, CFSTR(kSecTrustKeychainsAllowedKey
)) == kCFBooleanFalse
) {
1901 output
->_keychainsAllowed
= false;
1902 } /* true is set by default */
1905 if (errSecSuccess
== status
&& trust
) {
1908 CFReleaseNull(policies
);
1909 CFReleaseNull(certificates
);
1913 SecTrustRef
SecTrustDeserialize(CFDataRef serializedTrust
, CFErrorRef
*error
) {
1914 SecTrustRef trust
= NULL
;
1915 CFPropertyListRef plist
= NULL
;
1916 OSStatus status
= errSecSuccess
;
1917 require_action_quiet(serializedTrust
, out
,
1918 SecError(errSecParam
, error
, CFSTR("null serialized trust input")));
1919 require_quiet(plist
= CFPropertyListCreateWithDERData(NULL
, serializedTrust
,
1920 kCFPropertyListImmutable
, NULL
, error
), out
);
1921 require_noerr_action_quiet(status
= SecTrustCreateFromPlist(plist
, &trust
), out
,
1922 SecError(status
, error
, CFSTR("unable to create trust ref")));
1925 CFReleaseNull(plist
);
1931 // MARK: SecTrustNode
1932 /********************************************************
1933 **************** SecTrustNode object *******************
1934 ********************************************************/
1935 typedef uint8_t SecFetchingState
;
1937 kSecFetchingStatePassedIn
= 0,
1938 kSecFetchingStateLocal
,
1939 kSecFetchingStateFromURL
,
1940 kSecFetchingStateDone
,
1943 typedef uint8_t SecTrustState
;
1945 kSecTrustStateUnknown
= 0,
1946 kSecTrustStateNotSigner
,
1947 kSecTrustStateValidSigner
,
1950 typedef struct __SecTrustNode
*SecTrustNodeRef
;
1951 struct __SecTrustNode
{
1952 SecTrustNodeRef _child
;
1953 SecCertificateRef _certificate
;
1955 /* Cached information about _certificate */
1959 /* Set of all certificates we have ever considered as a parent. We use
1960 this to avoid having to recheck certs when we go to the next phase. */
1961 CFMutableSet _certificates
;
1963 /* Parents that are still partial chains we haven't yet considered. */
1964 CFMutableSet _partials
;
1965 /* Parents that are still partial chains we have rejected. We reconsider
1966 these if we get to the final phase and we still haven't found a valid
1968 CFMutableSet _rejected_partials
;
1970 /* Parents that are complete chains we haven't yet considered. */
1971 CFMutableSet _candidates
;
1972 /* Parents that are complete chains we have rejected. */
1973 CFMutableSet _rejected_candidates
;
1975 /* State of candidate fetching. */
1976 SecFetchingState _fetchingState
;
1978 /* Trust state of _candidates[_candidateIndex] */
1979 SecTrustState _trustState
;
1981 typedef struct __SecTrustNode SecTrustNode
;
1983 /* Forward declarations of static functions. */
1984 static CFStringRef
SecTrustNodeDescribe(CFTypeRef cf
);
1985 static void SecTrustNodeDestroy(CFTypeRef cf
);
1987 /* Static functions. */
1988 static CFStringRef
SecTrustNodeCopyDescription(CFTypeRef cf
) {
1989 SecTrustNodeRef node
= (SecTrustNodeRef
)cf
;
1990 return CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
,
1991 CFSTR("<SecTrustNodeRef: %p>"), node
);
1994 static void SecTrustNodeDestroy(CFTypeRef cf
) {
1995 SecTrustNodeRef trust
= (SecTrustNodeRef
)cf
;
1996 if (trust
->_child
) {
1997 free(trust
->_child
);
1999 if (trust
->_certificate
) {
2000 free(trust
->_certificate
);
2002 if (trust
->_candidates
) {
2003 CFRelease(trust
->_candidates
);
2007 /* SecTrustNode API functions. */
2008 CFGiblisFor(SecTrustNode
)
2010 SecTrustNodeRef
SecTrustNodeCreate(SecTrustRef trust
,
2011 SecCertificateRef certificate
, SecTrustNodeRef child
) {
2012 CFAllocatorRef allocator
= kCFAllocatorDefault
;
2016 CFIndex size
= sizeof(struct __SecTrustNode
);
2017 SecTrustNodeRef result
= (SecTrustNodeRef
)_CFRuntimeCreateInstance(
2018 allocator
, SecTrustNodeGetTypeID(), size
- sizeof(CFRuntimeBase
), 0);
2022 memset((char*)result
+ sizeof(result
->_base
), 0,
2023 sizeof(*result
) - sizeof(result
->_base
));
2026 result
->_child
= child
;
2028 CFRetain(certificate
);
2029 result
->_certificate
= certificate
;
2030 result
->_isAnchor
= SecTrustCertificateIsAnchor(certificate
);
2035 SecCertificateRef
SecTrustGetCertificate(SecTrustNodeRef node
) {
2037 return node
->_certificate
;
2040 CFArrayRef
SecTrustNodeCopyProperties(SecTrustNodeRef node
,
2041 SecTrustRef trust
) {
2044 CFMutableArrayRef summary
= SecCertificateCopySummaryProperties(
2045 node
->_certificate
, SecTrustGetVerifyTime(trust
));
2046 /* FIXME Add more details in the failure case. */
2050 /* Attempt to verify this node's signature chain down to the child. */
2051 SecTrustState
SecTrustNodeVerifySignatureChain(SecTrustNodeRef node
) {
2053 return kSecTrustStateUnknown
;
2057 /* See if the next candidate works. */
2058 SecTrustNodeRef
SecTrustNodeCopyNextCandidate(SecTrustNodeRef node
,
2059 SecTrustRef trust
, SecFetchingState fetchingState
) {
2063 CFAbsoluteTime verifyTime
= SecTrustGetVerifyTime(trust
);
2066 /* If we have any unconsidered candidates left check those first. */
2067 while (node
->_candidateIndex
< CFArrayGetCount(node
->_candidates
)) {
2068 SecCertificateRef candidate
= (SecCertificateRef
)
2069 CFArrayGetValueAtIndex(node
->_candidates
, node
->_candidateIndex
);
2070 if (node
->_fetchingState
!= kSecFetchingStateDone
) {
2071 /* If we still have potential sources to fetch other candidates
2072 from we ignore expired candidates. */
2073 if (!SecCertificateIsValidOn(candidate
, verifyTime
)) {
2074 node
->_candidateIndex
++;
2079 SecTrustNodeRef parent
= SecTrustNodeCreate(candidate
, node
);
2080 CFArrayRemoveValueAtIndex(node
->_candidates
, node
->_candidateIndex
);
2081 if (SecTrustNodeVerifySignatureChain(parent
) ==
2082 kSecTrustStateNotSigner
) {
2083 /* This candidate parent is not a valid signer of its
2086 /* If another signature failed further down the chain we need
2087 to backtrack down to whatever child is still a valid
2088 candidate and has additional candidates to consider.
2089 @@@ We really want to make the fetchingState a global of
2090 SecTrust itself as well and not have any node go beyond the
2091 current state of SecTrust if there are other (read cheap)
2092 options to consider. */
2098 /* We've run out of candidates in our current state so let's try to
2099 find some more. Note we fetch candidates in increasing order of
2100 cost in the hope we won't ever get to the more expensive fetching
2102 SecCertificateRef certificate
= node
->_certificate
;
2103 switch (node
->_fetchingState
) {
2104 case kSecFetchingStatePassedIn
:
2105 /* Get the list of candidates from SecTrust. */
2106 CFDataRef akid
= SecCertificateGetAuthorityKeyID(certificate
);
2108 SecTrustAppendCandidatesWithAuthorityKeyID(akid
, node
->_candidates
);
2111 SecCertificateGetNormalizedIssuerContent(certificate
);
2112 SecTrustAppendCandidatesWithSubject(issuer
, node
->_candidates
);
2114 node
->_fetchingState
= kSecFetchingStateLocal
;
2116 case kSecFetchingStateLocal
:
2117 /* Lookup candidates in the local database. */
2118 node
->_fetchingState
= kSecFetchingStateFromURL
;
2120 case kSecFetchingStateFromURL
:
2121 node
->_fetchingState
= kSecFetchingStateCheckExpired
;
2123 case kSecFetchingStateCheckExpired
:
2124 /* Time to start considering expired candidates as well. */
2125 node
->_candidateIndex
= 0;
2126 node
->_fetchingState
= kSecFetchingStateDone
;
2128 case kSecFetchingStateDone
;
2133 CFAllocatorRef allocator
= CFGetAllocator(node
);
2135 /* A trust node has a number of states.
2136 1) Look for issuing certificates by asking SecTrust about known
2137 parent certificates.
2138 2) Look for issuing certificates in certificate databases (keychains)
2139 3) Look for issuing certificates by going out to the web if the nodes
2140 certificate has a issuer location URL.
2141 4) Look through expired or not yet valid candidates we have put aside.
2143 We go though the stages 1 though 3 looking for candidate issuer
2144 certificates. If a candidate certificate is not valid at verifyTime
2145 we put it in a to be examined later queue. If a candidate certificate
2146 is valid we verify if it actually signed our certificate (if possible).
2147 If not we discard it and continue on to the next candidate certificate.
2148 If it is we return a new SecTrustNodeRef for that certificate. */
2150 CFMutableArrayRef issuers
= CFArrayCreateMutable(allocator
, 0,
2151 &kCFTypeArrayCallBacks
);
2153 /* Find a node's parent. */
2154 certificate
= node
->_certificate
;
2155 CFDataRef akid
= SecCertificateGetAuthorityKeyID(certificate
);
2156 CFTypeRef candidates
= NULL
;
2158 candidates
= (CFTypeRef
)CFDictionaryGetValueForKey(skidDict
, akid
);
2160 addValidIssuersFrom(issuers
, certificate
, candidates
, true);
2165 SecCertificateGetNormalizedIssuerContent(certificate
);
2166 candidates
= (CFTypeRef
)
2167 CFDictionaryGetValueForKey(subjectDict
, issuer
);
2168 addValidIssuersFrom(issuers
, certificate
, candidates
, false);
2171 if (CFArrayGetCount(issuers
) == 0) {
2172 /* O no! we can't find an issuer for this certificate. Let's see
2173 if we can find one in the local database. */
2176 return errSecSuccess
;
2179 CFArrayRef
SecTrustNodeCopyNextChain(SecTrustNodeRef node
,
2180 SecTrustRef trust
) {
2181 /* Return the next full chain that isn't a reject unless we are in
2182 a state where we consider returning rejects. */
2184 switch (node
->_fetchingState
) {
2185 case kSecFetchingStatePassedIn
:
2186 /* Get the list of candidates from SecTrust. */
2187 CFDataRef akid
= SecCertificateGetAuthorityKeyID(certificate
);
2189 SecTrustAppendCandidatesWithAuthorityKeyID(akid
, node
->_candidates
);
2192 SecCertificateGetNormalizedIssuerContent(certificate
);
2193 SecTrustAppendCandidatesWithSubject(issuer
, node
->_candidates
);
2195 node
->_fetchingState
= kSecFetchingStateLocal
;
2197 case kSecFetchingStateLocal
:
2198 /* Lookup candidates in the local database. */
2199 node
->_fetchingState
= kSecFetchingStateFromURL
;
2201 case kSecFetchingStateFromURL
:
2202 node
->_fetchingState
= kSecFetchingStateCheckExpired
;
2204 case kSecFetchingStateCheckExpired
:
2205 /* Time to start considering expired candidates as well. */
2206 node
->_candidateIndex
= 0;
2207 node
->_fetchingState
= kSecFetchingStateDone
;
2209 case kSecFetchingStateDone
;
2215 Iterator
parentIterator(Cert
);
2221 static bool unique(Node node
) {
2222 if (nodes
.contains(node
))
2228 static bool isAnchor(Cert cert
);
2235 Iterator parentIterator
; /* For current source of parents. */
2237 Node(Cert inCert
) : child(nil
), cert(inCert
), nextSource(0) {}
2238 Node(Node inChild
, Cert inCert
) : child(inChild
), cert(inCert
),
2241 CertPath
certPath() {
2245 path
.add(node
.cert
);
2251 void contains(Cert cert
) {
2254 if (cert
== node
.cert
)
2261 Node
nextParent(Array currentSources
) {
2264 parentIterator
== currentSources
[nextSource
- 1].end()) {
2265 if (nextSource
== currentSources
.count
) {
2266 /* We ran out of parent sources. */
2269 parentIterator
= currentSources
[nextSource
++].begin();
2271 Certificate cert
= *parentIterator
++;
2272 /* Check for cycles and self signed chains. */
2273 if (!contains(cert
)) {
2274 Node node
= Node(this, parent
);
2275 if (!NodeCache
.unique(node
))
2286 Array currentSources
;
2292 PathBuilder(Cert cert
) {
2293 nodes
.append(Node(cert
));
2294 nit
= nodes
.begin();
2295 sourceIT
= allSources
.begin();
2298 nextAnchoredPath() {
2299 if (nit
== nodes
.end()) {
2300 /* We should add another source to the list of sources to
2302 if (sourceIT
== allSources
.end()) {
2303 /* No more sources to add. */
2305 currentSources
+= *sourceIT
++;
2306 /* Resort nodes by size. */
2308 nit
= nodes
.begin();
2309 /* Set the source list for all nodes. */
2312 while (Node node
= *nit
) {
2313 Node candidate
= node
.nextParent(currentSources
);
2315 /* The current node has no more candidate parents so move
2321 if (candidate
.isAnchored
) {
2322 candidates
.append(candidate
);
2324 nodes
.insert(candidate
, nit
);
2329 while (Node node
= nextAnchoredPath()) {
2330 if (node
.isValid()) {
2331 chain
= node
.certPath
;
2334 rejects
.append(node
);