2 * Copyright (c) 2008-2018 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
25 * SecPolicyServer.c - Engine for evaluating certificate paths against trust policies.
28 #include <securityd/SecPolicyServer.h>
29 #include <Security/SecPolicyInternal.h>
30 #include <Security/SecPolicyPriv.h>
31 #include <Security/SecTask.h>
32 #include <securityd/policytree.h>
33 #include <securityd/nameconstraints.h>
34 #include <CoreFoundation/CFTimeZone.h>
36 #include <libDER/oids.h>
37 #include <CoreFoundation/CFNumber.h>
38 #include <Security/SecCertificateInternal.h>
39 #include <AssertMacros.h>
40 #include <utilities/debugging.h>
41 #include <utilities/SecInternalReleasePriv.h>
42 #include <security_asn1/SecAsn1Coder.h>
43 #include <security_asn1/ocspTemplates.h>
44 #include <security_asn1/oidsalg.h>
45 #include <security_asn1/oidsocsp.h>
46 #include <CommonCrypto/CommonDigest.h>
47 #include <Security/SecFramework.h>
48 #include <Security/SecPolicyInternal.h>
49 #include <Security/SecTrustPriv.h>
50 #include <Security/SecTrustInternal.h>
51 #include <Security/SecTrustSettingsPriv.h>
52 #include <Security/SecInternal.h>
53 #include <Security/SecKeyPriv.h>
54 #include <Security/SecTask.h>
55 #include <SystemConfiguration/SCDynamicStoreCopySpecific.h>
57 #include <securityd/SecTrustServer.h>
58 #include <securityd/SecTrustLoggingServer.h>
59 #include <securityd/SecRevocationServer.h>
60 #include <securityd/SecCertificateServer.h>
61 #include <securityd/SecCertificateSource.h>
62 #include <securityd/SecOCSPResponse.h>
63 #include <utilities/array_size.h>
64 #include <utilities/SecCFWrappers.h>
65 #include <utilities/SecAppleAnchorPriv.h>
66 #include "OTATrustUtilities.h"
67 #include "personalization.h"
68 #include <sys/codesign.h>
71 #include <Security/SecTaskPriv.h>
74 /* Set this to 1 to dump the ocsp responses received in DER form in /tmp. */
75 #ifndef DUMP_OCSPRESPONSES
76 #define DUMP_OCSPRESPONSES 0
79 #if DUMP_OCSPRESPONSES
84 static void secdumpdata(CFDataRef data
, const char *name
) {
85 int fd
= open(name
, O_CREAT
| O_WRONLY
| O_TRUNC
, 0666);
86 write(fd
, CFDataGetBytePtr(data
), CFDataGetLength(data
));
93 /********************************************************
94 ****************** SecPolicy object ********************
95 ********************************************************/
97 static SecCertificateRef
SecPVCGetCertificateAtIndex(SecPVCRef pvc
, CFIndex ix
);
98 static CFIndex
SecPVCGetCertificateCount(SecPVCRef pvc
);
99 static CFAbsoluteTime
SecPVCGetVerifyTime(SecPVCRef pvc
);
101 static CFMutableDictionaryRef gSecPolicyLeafCallbacks
= NULL
;
102 static CFMutableDictionaryRef gSecPolicyPathCallbacks
= NULL
;
104 static CFArrayRef
SecPolicyAnchorDigestsForEVPolicy(const DERItem
*policyOID
)
106 CFArrayRef result
= NULL
;
107 SecOTAPKIRef otapkiRef
= SecOTAPKICopyCurrentOTAPKIRef();
108 if (NULL
== otapkiRef
)
113 CFDictionaryRef evToPolicyAnchorDigest
= SecOTAPKICopyEVPolicyToAnchorMapping(otapkiRef
);
114 CFRelease(otapkiRef
);
116 if (NULL
== evToPolicyAnchorDigest
)
121 CFArrayRef roots
= NULL
;
122 CFStringRef oid
= SecDERItemCopyOIDDecimalRepresentation(kCFAllocatorDefault
, policyOID
);
123 if (oid
&& evToPolicyAnchorDigest
)
125 result
= (CFArrayRef
)CFDictionaryGetValue(evToPolicyAnchorDigest
, oid
);
126 if (roots
&& CFGetTypeID(result
) != CFArrayGetTypeID())
128 secerror("EVRoot.plist has non array value");
133 CFReleaseSafe(evToPolicyAnchorDigest
);
138 bool SecPolicyIsEVPolicy(const DERItem
*policyOID
) {
139 return SecPolicyAnchorDigestsForEVPolicy(policyOID
);
142 static bool SecPolicyRootCACertificateIsEV(SecCertificateRef certificate
,
143 policy_set_t valid_policies
) {
144 CFDictionaryRef keySizes
= NULL
;
145 CFNumberRef rsaSize
= NULL
, ecSize
= NULL
;
147 /* Ensure that this certificate is a valid anchor for one of the
148 certificate policy oids specified in the leaf. */
149 CFDataRef digest
= SecCertificateGetSHA1Digest(certificate
);
151 bool good_ev_anchor
= false;
152 for (ix
= valid_policies
; ix
; ix
= ix
->oid_next
) {
153 CFArrayRef digests
= SecPolicyAnchorDigestsForEVPolicy(&ix
->oid
);
154 if (digests
&& CFArrayContainsValue(digests
,
155 CFRangeMake(0, CFArrayGetCount(digests
)), digest
)) {
156 secdebug("ev", "found anchor for policy oid");
157 good_ev_anchor
= true;
161 require_action_quiet(good_ev_anchor
, notEV
, secnotice("ev", "anchor not in plist"));
163 CFAbsoluteTime october2006
= 178761600;
164 if (SecCertificateNotValidBefore(certificate
) >= october2006
) {
165 require_action_quiet(SecCertificateVersion(certificate
) >= 3, notEV
,
166 secnotice("ev", "Anchor issued after October 2006 and is not v3"));
168 if (SecCertificateVersion(certificate
) >= 3
169 && SecCertificateNotValidBefore(certificate
) >= october2006
) {
170 const SecCEBasicConstraints
*bc
= SecCertificateGetBasicConstraints(certificate
);
171 require_action_quiet(bc
&& bc
->isCA
== true, notEV
,
172 secnotice("ev", "Anchor has invalid basic constraints"));
173 SecKeyUsage ku
= SecCertificateGetKeyUsage(certificate
);
174 require_action_quiet((ku
& (kSecKeyUsageKeyCertSign
| kSecKeyUsageCRLSign
))
175 == (kSecKeyUsageKeyCertSign
| kSecKeyUsageCRLSign
), notEV
,
176 secnotice("ev", "Anchor has invalid key usage %u", ku
));
179 /* At least RSA 2048 or ECC NIST P-256. */
180 require_quiet(rsaSize
= CFNumberCreateWithCFIndex(NULL
, 2048), notEV
);
181 require_quiet(ecSize
= CFNumberCreateWithCFIndex(NULL
, 256), notEV
);
182 const void *keys
[] = { kSecAttrKeyTypeRSA
, kSecAttrKeyTypeEC
};
183 const void *values
[] = { rsaSize
, ecSize
};
184 require_quiet(keySizes
= CFDictionaryCreate(NULL
, keys
, values
, 2,
185 &kCFTypeDictionaryKeyCallBacks
,
186 &kCFTypeDictionaryValueCallBacks
), notEV
);
187 require_action_quiet(SecCertificateIsAtLeastMinKeySize(certificate
, keySizes
), notEV
,
188 secnotice("ev", "Anchor's public key is too weak for EV"));
193 CFReleaseNull(rsaSize
);
194 CFReleaseNull(ecSize
);
195 CFReleaseNull(keySizes
);
199 static bool SecPolicySubordinateCACertificateCouldBeEV(SecCertificateRef certificate
) {
200 CFMutableDictionaryRef keySizes
= NULL
;
201 CFNumberRef rsaSize
= NULL
, ecSize
= NULL
;
204 const SecCECertificatePolicies
*cp
;
205 cp
= SecCertificateGetCertificatePolicies(certificate
);
206 require_action_quiet(cp
&& cp
->numPolicies
> 0, notEV
,
207 secnotice("ev", "SubCA missing certificate policies"));
208 CFArrayRef cdp
= SecCertificateGetCRLDistributionPoints(certificate
);
209 require_action_quiet(cdp
&& CFArrayGetCount(cdp
) > 0, notEV
,
210 secnotice("ev", "SubCA missing CRLDP"));
211 const SecCEBasicConstraints
*bc
= SecCertificateGetBasicConstraints(certificate
);
212 require_action_quiet(bc
&& bc
->isCA
== true, notEV
,
213 secnotice("ev", "SubCA has invalid basic constraints"));
214 SecKeyUsage ku
= SecCertificateGetKeyUsage(certificate
);
215 require_action_quiet((ku
& (kSecKeyUsageKeyCertSign
| kSecKeyUsageCRLSign
))
216 == (kSecKeyUsageKeyCertSign
| kSecKeyUsageCRLSign
), notEV
,
217 secnotice("ev", "SubCA has invalid key usage %u", ku
));
219 /* 6.1.5 Key Sizes */
220 CFAbsoluteTime jan2011
= 315532800;
221 CFAbsoluteTime jan2014
= 410227200;
222 require_quiet(ecSize
= CFNumberCreateWithCFIndex(NULL
, 256), notEV
);
223 require_quiet(keySizes
= CFDictionaryCreateMutable(NULL
, 2, &kCFTypeDictionaryKeyCallBacks
,
224 &kCFTypeDictionaryValueCallBacks
), notEV
);
225 CFDictionaryAddValue(keySizes
, kSecAttrKeyTypeEC
, ecSize
);
226 if (SecCertificateNotValidBefore(certificate
) < jan2011
||
227 SecCertificateNotValidAfter(certificate
) < jan2014
) {
228 /* At least RSA 1024 or ECC NIST P-256. */
229 require_quiet(rsaSize
= CFNumberCreateWithCFIndex(NULL
, 1024), notEV
);
230 CFDictionaryAddValue(keySizes
, kSecAttrKeyTypeRSA
, rsaSize
);
231 require_action_quiet(SecCertificateIsAtLeastMinKeySize(certificate
, keySizes
), notEV
,
232 secnotice("ev", "SubCA's public key is too small for issuance before 2011 or expiration before 2014"));
234 /* At least RSA 2028 or ECC NIST P-256. */
235 require_quiet(rsaSize
= CFNumberCreateWithCFIndex(NULL
, 2048), notEV
);
236 CFDictionaryAddValue(keySizes
, kSecAttrKeyTypeRSA
, rsaSize
);
237 require_action_quiet(SecCertificateIsAtLeastMinKeySize(certificate
, keySizes
), notEV
,
238 secnotice("ev", "SubCA's public key is too small for issuance after 2010 or expiration after 2013"));
241 /* 7.1.3 Algorithm Object Identifiers */
242 CFAbsoluteTime jan2016
= 473299200;
243 if (SecCertificateNotValidBefore(certificate
) > jan2016
) {
245 require_action_quiet(SecCertificateGetSignatureHashAlgorithm(certificate
) > kSecSignatureHashAlgorithmSHA1
,
246 notEV
, secnotice("ev", "SubCA was issued with SHA-1 after 2015"));
252 CFReleaseNull(rsaSize
);
253 CFReleaseNull(ecSize
);
254 CFReleaseNull(keySizes
);
258 /********************************************************
259 **************** SecPolicy Callbacks *******************
260 ********************************************************/
261 static void SecPolicyCheckCriticalExtensions(SecPVCRef pvc
,
265 static void SecPolicyCheckIdLinkage(SecPVCRef pvc
,
267 CFIndex ix
, count
= SecPVCGetCertificateCount(pvc
);
268 CFDataRef parentSubjectKeyID
= NULL
;
269 for (ix
= count
- 1; ix
>= 0; --ix
) {
270 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, ix
);
271 /* If the previous certificate in the chain had a SubjectKeyID,
272 make sure it matches the current certificates AuthorityKeyID. */
273 if (parentSubjectKeyID
) {
274 /* @@@ According to RFC 2459 neither AuthorityKeyID nor
275 SubjectKeyID can be critical. Currenty we don't check
277 CFDataRef authorityKeyID
= SecCertificateGetAuthorityKeyID(cert
);
278 if (authorityKeyID
) {
279 if (!CFEqual(parentSubjectKeyID
, authorityKeyID
)) {
280 /* AuthorityKeyID doesn't match issuers SubjectKeyID. */
281 if (!SecPVCSetResult(pvc
, key
, ix
, kCFBooleanFalse
))
287 parentSubjectKeyID
= SecCertificateGetSubjectKeyID(cert
);
291 static void SecPolicyCheckKeyUsage(SecPVCRef pvc
,
293 SecCertificateRef leaf
= SecPVCGetCertificateAtIndex(pvc
, 0);
294 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
295 CFTypeRef xku
= CFDictionaryGetValue(policy
->_options
, key
);
296 if (!SecPolicyCheckCertKeyUsage(leaf
, xku
)) {
297 SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
);
301 /* AUDIT[securityd](done):
302 policy->_options is a caller provided dictionary, only its cf type has
305 static void SecPolicyCheckExtendedKeyUsage(SecPVCRef pvc
, CFStringRef key
) {
306 SecCertificateRef leaf
= SecPVCGetCertificateAtIndex(pvc
, 0);
307 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
308 CFTypeRef xeku
= CFDictionaryGetValue(policy
->_options
, key
);
309 if (!SecPolicyCheckCertExtendedKeyUsage(leaf
, xeku
)){
310 SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
);
314 static void SecPolicyCheckBasicConstraints(SecPVCRef pvc
,
316 //SecPolicyCheckBasicContraintsCommon(pvc, key, false);
319 static void SecPolicyCheckNonEmptySubject(SecPVCRef pvc
,
321 CFIndex ix
, count
= SecPVCGetCertificateCount(pvc
);
322 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
323 CFTypeRef pvcValue
= CFDictionaryGetValue(policy
->_options
, key
);
324 for (ix
= 0; ix
< count
; ++ix
) {
325 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, ix
);
326 if (!SecPolicyCheckCertNonEmptySubject(cert
, pvcValue
)) {
327 if (!SecPVCSetResult(pvc
, key
, ix
, kCFBooleanFalse
))
333 /* AUDIT[securityd](done):
334 policy->_options is a caller provided dictionary, only its cf type has
337 static void SecPolicyCheckSSLHostname(SecPVCRef pvc
,
339 /* @@@ Consider what to do if the caller passes in no hostname. Should
340 we then still fail if the leaf has no dnsNames or IPAddresses at all? */
341 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
342 CFStringRef hostName
= (CFStringRef
)
343 CFDictionaryGetValue(policy
->_options
, key
);
344 if (!isString(hostName
)) {
345 /* @@@ We can't return an error here and making the evaluation fail
346 won't help much either. */
350 SecCertificateRef leaf
= SecPVCGetCertificateAtIndex(pvc
, 0);
351 bool dnsMatch
= SecPolicyCheckCertSSLHostname(leaf
, hostName
);
354 /* Hostname mismatch or no hostnames found in certificate. */
355 SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
);
360 /* AUDIT[securityd](done):
361 policy->_options is a caller provided dictionary, only its cf type has
364 static void SecPolicyCheckEmail(SecPVCRef pvc
, CFStringRef key
) {
365 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
366 CFStringRef email
= (CFStringRef
)CFDictionaryGetValue(policy
->_options
, key
);
367 if (!isString(email
)) {
368 /* We can't return an error here and making the evaluation fail
369 won't help much either. */
373 SecCertificateRef leaf
= SecPVCGetCertificateAtIndex(pvc
, 0);
375 if (!SecPolicyCheckCertEmail(leaf
, email
)) {
376 /* Hostname mismatch or no hostnames found in certificate. */
377 SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
);
381 static void SecPolicyCheckTemporalValidity(SecPVCRef pvc
,
383 CFIndex ix
, count
= SecPVCGetCertificateCount(pvc
);
384 CFAbsoluteTime verifyTime
= SecPVCGetVerifyTime(pvc
);
385 for (ix
= 0; ix
< count
; ++ix
) {
386 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, ix
);
387 if (!SecCertificateIsValid(cert
, verifyTime
)) {
388 /* Intermediate certificate has expired. */
389 if (!SecPVCSetResult(pvc
, key
, ix
, kCFBooleanFalse
))
395 /* AUDIT[securityd](done):
396 policy->_options is a caller provided dictionary, only its cf type has
399 static void SecPolicyCheckIssuerCommonName(SecPVCRef pvc
,
401 CFIndex count
= SecPVCGetCertificateCount(pvc
);
403 /* Can't check intermediates common name if there is no intermediate. */
404 SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
);
408 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, 1);
409 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
410 CFStringRef commonName
=
411 (CFStringRef
)CFDictionaryGetValue(policy
->_options
, key
);
412 if (!isString(commonName
)) {
413 /* @@@ We can't return an error here and making the evaluation fail
414 won't help much either. */
417 if (!SecPolicyCheckCertSubjectCommonName(cert
, commonName
)) {
418 SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
);
422 /* AUDIT[securityd](done):
423 policy->_options is a caller provided dictionary, only its cf type has
426 static void SecPolicyCheckSubjectCommonName(SecPVCRef pvc
,
428 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, 0);
429 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
430 CFStringRef common_name
= (CFStringRef
)CFDictionaryGetValue(policy
->_options
,
432 if (!isString(common_name
)) {
433 /* @@@ We can't return an error here and making the evaluation fail
434 won't help much either. */
437 if (!SecPolicyCheckCertSubjectCommonName(cert
, common_name
)) {
438 SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
);
442 /* AUDIT[securityd](done):
443 policy->_options is a caller provided dictionary, only its cf type has
446 static void SecPolicyCheckSubjectCommonNamePrefix(SecPVCRef pvc
,
448 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, 0);
449 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
450 CFStringRef prefix
= (CFStringRef
)CFDictionaryGetValue(policy
->_options
,
452 if (!isString(prefix
)) {
453 /* @@@ We can't return an error here and making the evaluation fail
454 won't help much either. */
457 if (!SecPolicyCheckCertSubjectCommonNamePrefix(cert
, prefix
)) {
458 SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
);
462 /* AUDIT[securityd](done):
463 policy->_options is a caller provided dictionary, only its cf type has
466 static void SecPolicyCheckSubjectCommonNameTEST(SecPVCRef pvc
,
468 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, 0);
469 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
470 CFStringRef common_name
= (CFStringRef
)CFDictionaryGetValue(policy
->_options
,
472 if (!isString(common_name
)) {
473 /* @@@ We can't return an error here and making the evaluation fail
474 won't help much either. */
477 if (!SecPolicyCheckCertSubjectCommonNameTEST(cert
, common_name
)) {
478 SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
);
482 /* AUDIT[securityd](done):
483 policy->_options is a caller provided dictionary, only its cf type has
486 static void SecPolicyCheckNotValidBefore(SecPVCRef pvc
,
488 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, 0);
489 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
490 CFDateRef date
= (CFDateRef
)CFDictionaryGetValue(policy
->_options
, key
);
492 /* @@@ We can't return an error here and making the evaluation fail
493 won't help much either. */
496 if (!SecPolicyCheckCertNotValidBefore(cert
, date
)) {
497 if (!SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
))
502 /* AUDIT[securityd](done):
503 policy->_options is a caller provided dictionary, only its cf type has
506 static void SecPolicyCheckChainLength(SecPVCRef pvc
,
508 CFIndex count
= SecPVCGetCertificateCount(pvc
);
509 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
510 CFNumberRef chainLength
=
511 (CFNumberRef
)CFDictionaryGetValue(policy
->_options
, key
);
513 if (!chainLength
|| CFGetTypeID(chainLength
) != CFNumberGetTypeID() ||
514 !CFNumberGetValue(chainLength
, kCFNumberCFIndexType
, &value
)) {
515 /* @@@ We can't return an error here and making the evaluation fail
516 won't help much either. */
519 if (value
!= count
) {
520 /* Chain length doesn't match policy requirement. */
521 if (!SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
))
526 static bool isDigestInPolicy(SecPVCRef pvc
, CFStringRef key
, CFDataRef digest
) {
527 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
528 CFTypeRef value
= CFDictionaryGetValue(policy
->_options
, key
);
530 bool foundMatch
= false;
532 foundMatch
= CFEqual(digest
, value
);
533 else if (isArray(value
))
534 foundMatch
= CFArrayContainsValue((CFArrayRef
) value
, CFRangeMake(0, CFArrayGetCount((CFArrayRef
) value
)), digest
);
536 /* @@@ We only support Data and Array but we can't return an error here so.
537 we let the evaluation fail (not much help) and assert in debug. */
544 static void SecPolicyCheckAnchorSHA256(SecPVCRef pvc
, CFStringRef key
) {
545 CFIndex count
= SecPVCGetCertificateCount(pvc
);
546 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, count
- 1);
547 CFDataRef anchorSHA256
= NULL
;
548 anchorSHA256
= SecCertificateCopySHA256Digest(cert
);
550 if (!isDigestInPolicy(pvc
, key
, anchorSHA256
)) {
551 SecPVCSetResult(pvc
, kSecPolicyCheckAnchorSHA256
, count
-1, kCFBooleanFalse
);
554 CFReleaseNull(anchorSHA256
);
559 /* AUDIT[securityd](done):
560 policy->_options is a caller provided dictionary, only its cf type has
563 static void SecPolicyCheckAnchorSHA1(SecPVCRef pvc
,
565 CFIndex count
= SecPVCGetCertificateCount(pvc
);
566 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, count
- 1);
567 CFDataRef anchorSHA1
= SecCertificateGetSHA1Digest(cert
);
569 if (!isDigestInPolicy(pvc
, key
, anchorSHA1
))
570 if (!SecPVCSetResult(pvc
, kSecPolicyCheckAnchorSHA1
, count
-1, kCFBooleanFalse
))
577 Check the SHA256 of SPKI of the first intermediate CA certificate in the path
578 policy->_options is a caller provided dictionary, only its cf type has
581 static void SecPolicyCheckIntermediateSPKISHA256(SecPVCRef pvc
,
583 SecCertificateRef cert
= NULL
;
584 CFDataRef digest
= NULL
;
586 if (SecPVCGetCertificateCount(pvc
) < 2) {
587 SecPVCSetResult(pvc
, kSecPolicyCheckIntermediateSPKISHA256
, 0, kCFBooleanFalse
);
591 cert
= SecPVCGetCertificateAtIndex(pvc
, 1);
592 digest
= SecCertificateCopySubjectPublicKeyInfoSHA256Digest(cert
);
594 if (!isDigestInPolicy(pvc
, key
, digest
)) {
595 SecPVCSetResult(pvc
, kSecPolicyCheckIntermediateSPKISHA256
, 1, kCFBooleanFalse
);
597 CFReleaseNull(digest
);
601 policy->_options is a caller provided dictionary, only its cf type has
604 static void SecPolicyCheckAnchorApple(SecPVCRef pvc
,
606 CFIndex count
= SecPVCGetCertificateCount(pvc
);
607 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, count
- 1);
608 SecAppleTrustAnchorFlags flags
= 0;
611 bool foundMatch
= SecIsAppleTrustAnchor(cert
, flags
);
614 if (!SecPVCSetResult(pvc
, kSecPolicyCheckAnchorApple
, 0, kCFBooleanFalse
))
621 /* AUDIT[securityd](done):
622 policy->_options is a caller provided dictionary, only its cf type has
625 static void SecPolicyCheckSubjectOrganization(SecPVCRef pvc
,
627 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, 0);
628 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
629 CFStringRef org
= (CFStringRef
)CFDictionaryGetValue(policy
->_options
,
631 if (!isString(org
)) {
632 /* @@@ We can't return an error here and making the evaluation fail
633 won't help much either. */
636 if (!SecPolicyCheckCertSubjectOrganization(cert
, org
)) {
637 /* Leaf Subject Organization mismatch. */
638 SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
);
642 static void SecPolicyCheckSubjectOrganizationalUnit(SecPVCRef pvc
,
644 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, 0);
645 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
646 CFStringRef orgUnit
= (CFStringRef
)CFDictionaryGetValue(policy
->_options
,
648 if (!isString(orgUnit
)) {
649 /* @@@ We can't return an error here and making the evaluation fail
650 won't help much either. */
653 if (!SecPolicyCheckCertSubjectOrganizationalUnit(cert
, orgUnit
)) {
654 /* Leaf Subject Organization mismatch. */
655 SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
);
659 /* AUDIT[securityd](done):
660 policy->_options is a caller provided dictionary, only its cf type has
663 static void SecPolicyCheckEAPTrustedServerNames(SecPVCRef pvc
,
665 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
666 CFArrayRef trustedServerNames
= (CFArrayRef
)
667 CFDictionaryGetValue(policy
->_options
, key
);
668 /* No names specified means we accept any name. */
669 if (!trustedServerNames
)
671 if (!isArray(trustedServerNames
)) {
672 /* @@@ We can't return an error here and making the evaluation fail
673 won't help much either. */
677 SecCertificateRef leaf
= SecPVCGetCertificateAtIndex(pvc
, 0);
678 if (!SecPolicyCheckCertEAPTrustedServerNames(leaf
, trustedServerNames
)) {
679 /* Hostname mismatch or no hostnames found in certificate. */
680 SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
);
684 static const unsigned char UTN_USERFirst_Hardware_Serial
[][16] = {
685 { 0xd8, 0xf3, 0x5f, 0x4e, 0xb7, 0x87, 0x2b, 0x2d, 0xab, 0x06, 0x92, 0xe3, 0x15, 0x38, 0x2f, 0xb0 },
686 { 0x92, 0x39, 0xd5, 0x34, 0x8f, 0x40, 0xd1, 0x69, 0x5a, 0x74, 0x54, 0x70, 0xe1, 0xf2, 0x3f, 0x43 },
687 { 0xb0, 0xb7, 0x13, 0x3e, 0xd0, 0x96, 0xf9, 0xb5, 0x6f, 0xae, 0x91, 0xc8, 0x74, 0xbd, 0x3a, 0xc0 },
688 { 0xe9, 0x02, 0x8b, 0x95, 0x78, 0xe4, 0x15, 0xdc, 0x1a, 0x71, 0x0a, 0x2b, 0x88, 0x15, 0x44, 0x47 },
689 { 0x39, 0x2a, 0x43, 0x4f, 0x0e, 0x07, 0xdf, 0x1f, 0x8a, 0xa3, 0x05, 0xde, 0x34, 0xe0, 0xc2, 0x29 },
690 { 0x3e, 0x75, 0xce, 0xd4, 0x6b, 0x69, 0x30, 0x21, 0x21, 0x88, 0x30, 0xae, 0x86, 0xa8, 0x2a, 0x71 },
691 { 0xd7, 0x55, 0x8f, 0xda, 0xf5, 0xf1, 0x10, 0x5b, 0xb2, 0x13, 0x28, 0x2b, 0x70, 0x77, 0x29, 0xa3 },
692 { 0x04, 0x7e, 0xcb, 0xe9, 0xfc, 0xa5, 0x5f, 0x7b, 0xd0, 0x9e, 0xae, 0x36, 0xe1, 0x0c, 0xae, 0x1e },
693 { 0xf5, 0xc8, 0x6a, 0xf3, 0x61, 0x62, 0xf1, 0x3a, 0x64, 0xf5, 0x4f, 0x6d, 0xc9, 0x58, 0x7c, 0x06 } };
695 static const unsigned char UTN_USERFirst_Hardware_Normalized_Issuer
[] = {
696 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55,
697 0x53, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x02,
698 0x55, 0x54, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x07, 0x13,
699 0x0e, 0x53, 0x41, 0x4c, 0x54, 0x20, 0x4c, 0x41, 0x4b, 0x45, 0x20, 0x43,
700 0x49, 0x54, 0x59, 0x31, 0x1e, 0x30, 0x1c, 0x06, 0x03, 0x55, 0x04, 0x0a,
701 0x13, 0x15, 0x54, 0x48, 0x45, 0x20, 0x55, 0x53, 0x45, 0x52, 0x54, 0x52,
702 0x55, 0x53, 0x54, 0x20, 0x4e, 0x45, 0x54, 0x57, 0x4f, 0x52, 0x4b, 0x31,
703 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x18, 0x48, 0x54,
704 0x54, 0x50, 0x3a, 0x2f, 0x2f, 0x57, 0x57, 0x57, 0x2e, 0x55, 0x53, 0x45,
705 0x52, 0x54, 0x52, 0x55, 0x53, 0x54, 0x2e, 0x43, 0x4f, 0x4d, 0x31, 0x1f,
706 0x30, 0x1d, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x16, 0x55, 0x54, 0x4e,
707 0x2d, 0x55, 0x53, 0x45, 0x52, 0x46, 0x49, 0x52, 0x53, 0x54, 0x2d, 0x48,
708 0x41, 0x52, 0x44, 0x57, 0x41, 0x52, 0x45
710 static const unsigned int UTN_USERFirst_Hardware_Normalized_Issuer_len
= 151;
713 static void SecPolicyCheckBlackListedLeaf(SecPVCRef pvc
,
715 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, 0);
716 CFDataRef issuer
= cert
? SecCertificateGetNormalizedIssuerContent(cert
) : NULL
;
718 if (issuer
&& (CFDataGetLength(issuer
) == (CFIndex
)UTN_USERFirst_Hardware_Normalized_Issuer_len
) &&
719 (0 == memcmp(UTN_USERFirst_Hardware_Normalized_Issuer
, CFDataGetBytePtr(issuer
),
720 UTN_USERFirst_Hardware_Normalized_Issuer_len
)))
722 CFDataRef serial
= SecCertificateCopySerialNumberData(cert
, NULL
);
724 CFIndex serial_length
= CFDataGetLength(serial
);
725 const uint8_t *serial_ptr
= CFDataGetBytePtr(serial
);
727 while ((serial_length
> 0) && (*serial_ptr
== 0)) {
732 if (serial_length
== (CFIndex
)sizeof(*UTN_USERFirst_Hardware_Serial
)) {
734 for (i
= 0; i
< array_size(UTN_USERFirst_Hardware_Serial
); i
++)
736 if (0 == memcmp(UTN_USERFirst_Hardware_Serial
[i
],
737 serial_ptr
, sizeof(*UTN_USERFirst_Hardware_Serial
)))
739 SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
);
740 CFReleaseSafe(serial
);
749 SecOTAPKIRef otapkiRef
= SecOTAPKICopyCurrentOTAPKIRef();
750 if (NULL
!= otapkiRef
)
752 CFSetRef blackListedKeys
= SecOTAPKICopyBlackListSet(otapkiRef
);
753 CFRelease(otapkiRef
);
754 if (NULL
!= blackListedKeys
)
756 /* Check for blacklisted intermediates keys. */
757 CFDataRef dgst
= SecCertificateCopyPublicKeySHA1Digest(cert
);
760 /* Check dgst against blacklist. */
761 if (CFSetContainsValue(blackListedKeys
, dgst
))
763 SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
);
767 CFRelease(blackListedKeys
);
772 static void SecPolicyCheckGrayListedLeaf(SecPVCRef pvc
, CFStringRef key
)
774 SecOTAPKIRef otapkiRef
= SecOTAPKICopyCurrentOTAPKIRef();
775 if (NULL
!= otapkiRef
)
777 CFSetRef grayListedKeys
= SecOTAPKICopyGrayList(otapkiRef
);
778 CFRelease(otapkiRef
);
779 if (NULL
!= grayListedKeys
)
781 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, 0);
783 CFDataRef dgst
= SecCertificateCopyPublicKeySHA1Digest(cert
);
786 /* Check dgst against gray. */
787 if (CFSetContainsValue(grayListedKeys
, dgst
))
789 SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
);
793 CFRelease(grayListedKeys
);
798 static void SecPolicyCheckLeafMarkerOid(SecPVCRef pvc
, CFStringRef key
)
800 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, 0);
801 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
802 CFTypeRef value
= CFDictionaryGetValue(policy
->_options
, key
);
804 if (!SecPolicyCheckCertLeafMarkerOid(cert
, value
)) {
805 SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
);
809 static void SecPolicyCheckLeafMarkerOidWithoutValueCheck(SecPVCRef pvc
, CFStringRef key
)
811 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, 0);
812 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
813 CFTypeRef value
= CFDictionaryGetValue(policy
->_options
, key
);
815 if (!SecPolicyCheckCertLeafMarkerOidWithoutValueCheck(cert
, value
)) {
816 SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
);
822 * The value is a dictionary. The dictionary contains keys indicating
823 * whether the value is for Prod or QA. The values are the same as
824 * in the options dictionary for SecPolicyCheckLeafMarkerOid.
826 static void SecPolicyCheckLeafMarkersProdAndQA(SecPVCRef pvc
, CFStringRef key
)
828 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, 0);
829 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
830 CFDictionaryRef value
= CFDictionaryGetValue(policy
->_options
, key
);
831 CFTypeRef prodValue
= CFDictionaryGetValue(value
, kSecPolicyLeafMarkerProd
);
833 if (!SecPolicyCheckCertLeafMarkerOid(cert
, prodValue
)) {
836 SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
);
841 static void SecPolicyCheckIntermediateMarkerOid(SecPVCRef pvc
, CFStringRef key
)
843 CFIndex ix
, count
= SecPVCGetCertificateCount(pvc
);
844 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
845 CFTypeRef value
= CFDictionaryGetValue(policy
->_options
, key
);
847 for (ix
= 1; ix
< count
- 1; ix
++) {
848 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, ix
);
849 if (SecCertificateHasMarkerExtension(cert
, value
))
852 SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
);
855 static void SecPolicyCheckIntermediateEKU(SecPVCRef pvc
, CFStringRef key
)
857 CFIndex ix
, count
= SecPVCGetCertificateCount(pvc
);
858 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
859 CFTypeRef peku
= CFDictionaryGetValue(policy
->_options
, key
);
861 for (ix
= 1; ix
< count
- 1; ix
++) {
862 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, ix
);
863 if (!SecPolicyCheckCertExtendedKeyUsage(cert
, peku
)) {
864 SecPVCSetResult(pvc
, key
, ix
, kCFBooleanFalse
);
869 static void SecPolicyCheckIntermediateOrganization(SecPVCRef pvc
, CFStringRef key
)
871 CFIndex ix
, count
= SecPVCGetCertificateCount(pvc
);
872 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
873 CFTypeRef organization
= CFDictionaryGetValue(policy
->_options
, key
);
875 for (ix
= 1; ix
< count
- 1; ix
++) {
876 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, ix
);
877 if (!SecPolicyCheckCertSubjectOrganization(cert
, organization
)) {
878 SecPVCSetResult(pvc
, key
, ix
, kCFBooleanFalse
);
883 static void SecPolicyCheckIntermediateCountry(SecPVCRef pvc
, CFStringRef key
)
885 CFIndex ix
, count
= SecPVCGetCertificateCount(pvc
);
886 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
887 CFTypeRef country
= CFDictionaryGetValue(policy
->_options
, key
);
889 for (ix
= 1; ix
< count
- 1; ix
++) {
890 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, ix
);
891 if (!SecPolicyCheckCertSubjectCountry(cert
, country
)) {
892 SecPVCSetResult(pvc
, key
, ix
, kCFBooleanFalse
);
897 /****************************************************************************
898 *********************** New rfc5280 Chain Validation ***********************
899 ****************************************************************************/
901 #define POLICY_MAPPING 1
902 #define POLICY_SUBTREES 1
904 /* rfc5280 basic cert processing. */
905 static void SecPolicyCheckBasicCertificateProcessing(SecPVCRef pvc
,
909 CFIndex count
= SecPVCGetCertificateCount(pvc
);
910 SecCertificatePathVCRef path
= SecPathBuilderGetPath(pvc
->builder
);
911 /* 64 bits cast: worst case here is we truncate the number of cert, and the validation may fail */
912 assert((unsigned long)count
<=UINT32_MAX
); /* Debug check. Correct as long as CFIndex is long */
913 uint32_t n
= (uint32_t)count
;
915 bool is_anchored
= SecPathBuilderIsAnchored(pvc
->builder
);
916 bool is_anchor_trusted
= false;
918 CFArrayRef constraints
= SecCertificatePathVCGetUsageConstraintsAtIndex(path
, n
- 1);
919 if (CFArrayGetCount(constraints
) == 0) {
920 /* Given that the path builder has already indicated the last cert in this chain has
921 * trust set on it, empty constraints means trusted. */
922 is_anchor_trusted
= true;
924 /* Determine whether constraints say to trust this cert for this PVC. */
925 SecTrustSettingsResult tsResult
= SecPVCGetTrustSettingsResult(pvc
, SecCertificatePathVCGetCertificateAtIndex(path
, n
- 1),
927 if (tsResult
== kSecTrustSettingsResultTrustRoot
|| tsResult
== kSecTrustSettingsResultTrustAsRoot
) {
928 is_anchor_trusted
= true;
933 if (is_anchor_trusted
) {
934 /* If the anchor is trusted we don't process the last cert in the
938 /* trust may be restored for a path with an untrusted root that matches the allow list.
939 (isAllowlisted is set by revocation check, which is performed prior to path checks) */
940 if (!SecCertificatePathVCIsAllowlisted(path
)) {
941 Boolean isSelfSigned
= false;
942 (void) SecCertificateIsSelfSigned(SecCertificatePathVCGetCertificateAtIndex(path
, n
- 1), &isSelfSigned
);
944 /* Add a detail for the root not being trusted. */
945 if (!SecPVCSetResultForced(pvc
, kSecPolicyCheckAnchorTrusted
,
946 n
- 1, kCFBooleanFalse
, true)) {
950 /* Add a detail for the missing intermediate. */
951 if (!SecPVCSetResultForced(pvc
, kSecPolicyCheckMissingIntermediate
,
952 n
- 1, kCFBooleanFalse
, true)) {
959 CFAbsoluteTime verify_time
= SecPVCGetVerifyTime(pvc
);
960 //policy_set_t user_initial_policy_set = NULL;
961 //trust_anchor_t anchor;
965 CFMutableArrayRef permitted_subtrees
= NULL
;
966 CFMutableArrayRef excluded_subtrees
= NULL
;
967 permitted_subtrees
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
);
968 excluded_subtrees
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
);
969 require_action_quiet(permitted_subtrees
!= NULL
, errOut
,
970 SecPVCSetResultForced(pvc
, kSecPolicyCheckNameConstraints
, 0, kCFBooleanFalse
, true));
971 require_action_quiet(excluded_subtrees
!= NULL
, errOut
,
972 SecPVCSetResultForced(pvc
, kSecPolicyCheckNameConstraints
, 0, kCFBooleanFalse
, true));
975 if (!SecCertificatePathVCVerifyPolicyTree(path
, is_anchor_trusted
)) {
976 if (!SecPVCSetResultForced(pvc
, kSecPolicyCheckPolicyConstraints
, 0, kCFBooleanFalse
, true)) {
982 /* Path builder ensures we only get cert chains with proper issuer
983 chaining with valid signatures along the way. */
984 algorithm_id_t working_public_key_algorithm
= anchor
->public_key_algorithm
;
985 SecKeyRef working_public_key
= anchor
->public_key
;
986 x500_name_t working_issuer_name
= anchor
->issuer_name
;
988 uint32_t i
, max_path_length
= n
;
989 SecCertificateRef cert
= NULL
;
990 for (i
= 1; i
<= n
; ++i
) {
992 cert
= SecPVCGetCertificateAtIndex(pvc
, n
- i
);
993 bool is_self_issued
= SecCertificatePathVCIsCertificateAtIndexSelfIssued(SecPathBuilderGetPath(pvc
->builder
), n
- i
);
995 /* (a) Verify the basic certificate information. */
996 /* @@@ Ensure that cert was signed with working_public_key_algorithm
997 using the working_public_key and the working_public_key_parameters. */
999 /* Already done by chain builder. */
1000 if (!SecCertificateIsValid(cert
, verify_time
)) {
1001 if (!SecPVCSetResult(pvc
, kSecPolicyCheckTemporalValidity
, n
- i
, kCFBooleanFalse
)) {
1005 if (SecCertificateIsWeakKey(cert
)) {
1006 if (!SecPVCSetResult(pvc
, kSecPolicyCheckWeakKeySize
, n
- i
, kCFBooleanFalse
)) {
1010 if (!SecPolicyCheckCertWeakSignature(cert
, NULL
)) {
1011 if (!SecPVCSetResult(pvc
, kSecPolicyCheckWeakSignature
, n
- i
, kCFBooleanFalse
)) {
1016 /* @@@ cert.issuer == working_issuer_name. */
1020 if (!is_self_issued
|| i
== n
) {
1022 /* Verify certificate Subject Name and SubjectAltNames are not within any of the excluded_subtrees */
1023 if(excluded_subtrees
&& CFArrayGetCount(excluded_subtrees
)) {
1024 if ((errSecSuccess
!= SecNameContraintsMatchSubtrees(cert
, excluded_subtrees
, &found
, false)) || found
) {
1025 secnotice("policy", "name in excluded subtrees");
1026 if(!SecPVCSetResultForced(pvc
, kSecPolicyCheckNameConstraints
, n
- i
, kCFBooleanFalse
, true)) { goto errOut
; }
1029 /* Verify certificate Subject Name and SubjectAltNames are within the permitted_subtrees */
1030 if(permitted_subtrees
&& CFArrayGetCount(permitted_subtrees
)) {
1031 if ((errSecSuccess
!= SecNameContraintsMatchSubtrees(cert
, permitted_subtrees
, &found
, true)) || !found
) {
1032 secnotice("policy", "name not in permitted subtrees");
1033 if(!SecPVCSetResultForced(pvc
, kSecPolicyCheckNameConstraints
, n
- i
, kCFBooleanFalse
, true)) { goto errOut
; }
1038 /* (d) (e) (f) handled by SecCertificatePathVCVerifyPolicyTree */
1040 /* If Last Cert in Path */
1044 /* Prepare for Next Cert */
1045 /* (a) (b) Done by SecCertificatePathVCVerifyPolicyTree */
1046 /* (c)(d)(e)(f) Done by SecPathBuilderGetNext and SecCertificatePathVCVerify */
1048 /* (g) If a name constraints extension is included in the certificate, modify the permitted_subtrees and excluded_subtrees state variables.
1050 CFArrayRef permitted_subtrees_in_cert
= SecCertificateGetPermittedSubtrees(cert
);
1051 if (permitted_subtrees_in_cert
) {
1052 SecNameConstraintsIntersectSubtrees(permitted_subtrees
, permitted_subtrees_in_cert
);
1055 // could do something smart here to avoid inserting the exact same constraint
1056 CFArrayRef excluded_subtrees_in_cert
= SecCertificateGetExcludedSubtrees(cert
);
1057 if (excluded_subtrees_in_cert
) {
1058 CFIndex num_trees
= CFArrayGetCount(excluded_subtrees_in_cert
);
1059 CFRange range
= { 0, num_trees
};
1060 CFArrayAppendArray(excluded_subtrees
, excluded_subtrees_in_cert
, range
);
1063 /* (h), (i), (j) done by SecCertificatePathVCVerifyPolicyTree */
1065 /* (k) Checked in chain builder pre signature verify already. SecPVCParentCertificateChecks */
1068 if (!is_self_issued
) {
1069 if (max_path_length
> 0) {
1072 /* max_path_len exceeded, illegal. */
1073 if (!SecPVCSetResultForced(pvc
, kSecPolicyCheckBasicConstraintsPathLen
,
1074 n
- i
, kCFBooleanFalse
, true)) {
1080 const SecCEBasicConstraints
*bc
= SecCertificateGetBasicConstraints(cert
);
1081 if (bc
&& bc
->pathLenConstraintPresent
1082 && bc
->pathLenConstraint
< max_path_length
) {
1083 max_path_length
= bc
->pathLenConstraint
;
1085 #if 0 /* Checked in chain builder pre signature verify already. SecPVCParentCertificateChecks */
1086 /* (n) If a key usage extension is present, verify that the keyCertSign bit is set. */
1087 SecKeyUsage keyUsage
= SecCertificateGetKeyUsage(cert
);
1088 if (keyUsage
&& !(keyUsage
& kSecKeyUsageKeyCertSign
)) {
1089 if (!SecPVCSetResultForced(pvc
, kSecPolicyCheckKeyUsage
,
1090 n
- i
, kCFBooleanFalse
, true)) {
1095 /* (o) Recognize and process any other critical extension present in the certificate. Process any other recognized non-critical extension present in the certificate that is relevant to path processing. */
1096 if (SecCertificateHasUnknownCriticalExtension(cert
)) {
1097 /* Certificate contains one or more unknown critical extensions. */
1098 if (!SecPVCSetResult(pvc
, kSecPolicyCheckCriticalExtensions
,
1099 n
- i
, kCFBooleanFalse
)) {
1103 } /* end loop over certs in path */
1105 /* (a) (b) done by SecCertificatePathVCVerifyPolicyTree */
1108 /* If the subjectPublicKeyInfo field of the certificate contains an algorithm field with null parameters or parameters are omitted, compare the certificate subjectPublicKey algorithm to the working_public_key_algorithm. If the certificate subjectPublicKey algorithm and the
1109 working_public_key_algorithm are different, set the working_public_key_parameters to null. */
1111 /* (f) Recognize and process any other critical extension present in the certificate n. Process any other recognized non-critical extension present in certificate n that is relevant to path processing. */
1112 if (SecCertificateHasUnknownCriticalExtension(cert
)) {
1113 /* Certificate contains one or more unknown critical extensions. */
1114 if (!SecPVCSetResult(pvc
, kSecPolicyCheckCriticalExtensions
,
1115 0, kCFBooleanFalse
)) {
1119 /* (g) done by SecCertificatePathVCVerifyPolicyTree */
1122 CFReleaseNull(permitted_subtrees
);
1123 CFReleaseNull(excluded_subtrees
);
1126 static policy_set_t
policies_for_cert(SecCertificateRef cert
) {
1127 policy_set_t policies
= NULL
;
1128 const SecCECertificatePolicies
*cp
=
1129 SecCertificateGetCertificatePolicies(cert
);
1130 size_t policy_ix
, policy_count
= cp
? cp
->numPolicies
: 0;
1131 for (policy_ix
= 0; policy_ix
< policy_count
; ++policy_ix
) {
1132 policy_set_add(&policies
, &cp
->policies
[policy_ix
].policyIdentifier
);
1137 static void SecPolicyCheckEV(SecPVCRef pvc
,
1139 CFIndex ix
, count
= SecPVCGetCertificateCount(pvc
);
1140 policy_set_t valid_policies
= NULL
;
1142 /* 6.1.7. Key Usage Purposes */
1144 CFAbsoluteTime jul2016
= 489024000;
1145 SecCertificateRef leaf
= SecPVCGetCertificateAtIndex(pvc
, 0);
1146 if (SecCertificateNotValidBefore(leaf
) > jul2016
&& count
< 3) {
1147 /* Root CAs may not sign subscriber certificates after 30 June 2016. */
1148 if (SecPVCSetResultForced(pvc
, key
,
1149 0, kCFBooleanFalse
, true)) {
1155 for (ix
= 0; ix
< count
; ++ix
) {
1156 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, ix
);
1157 policy_set_t policies
= policies_for_cert(cert
);
1160 /* anyPolicy in the leaf isn't allowed for EV, so only init
1161 valid_policies if we have real policies. */
1162 if (!policy_set_contains(policies
, &oidAnyPolicy
)) {
1163 valid_policies
= policies
;
1166 } else if (ix
< count
- 1) {
1167 /* Subordinate CA */
1168 if (!SecPolicySubordinateCACertificateCouldBeEV(cert
)) {
1169 secnotice("ev", "subordinate certificate is not ev");
1170 if (SecPVCSetResultForced(pvc
, key
,
1171 ix
, kCFBooleanFalse
, true)) {
1172 policy_set_free(valid_policies
);
1173 policy_set_free(policies
);
1177 policy_set_intersect(&valid_policies
, policies
);
1180 if (!SecPolicyRootCACertificateIsEV(cert
, valid_policies
)) {
1181 secnotice("ev", "anchor certificate is not ev");
1182 if (SecPVCSetResultForced(pvc
, key
,
1183 ix
, kCFBooleanFalse
, true)) {
1184 policy_set_free(valid_policies
);
1185 policy_set_free(policies
);
1190 policy_set_free(policies
);
1191 if (!valid_policies
) {
1192 secnotice("ev", "valid_policies set is empty: chain not ev");
1193 /* If we ever get into a state where no policies are valid anymore
1194 this can't be an ev chain. */
1195 if (SecPVCSetResultForced(pvc
, key
,
1196 ix
, kCFBooleanFalse
, true)) {
1202 policy_set_free(valid_policies
);
1204 /* (a) EV Subscriber Certificates Each EV Certificate issued by the CA to a
1205 Subscriber MUST contain an OID defined by the CA in the certificate’s
1206 certificatePolicies extension that: (i) indicates which CA policy statement relates
1207 to that certificate, (ii) asserts the CA’s adherence to and compliance with these
1208 Guidelines, and (iii), by pre-agreement with the Application Software Vendor,
1209 marks the certificate as being an EV Certificate.
1210 (b) EV Subordinate CA Certificates
1211 (1) Certificates issued to Subordinate CAs that are not controlled by the issuing
1212 CA MUST contain one or more OIDs defined by the issuing CA that
1213 explicitly identify the EV Policies that are implemented by the Subordinate
1215 (2) Certificates issued to Subordinate CAs that are controlled by the Root CA
1216 MAY contain the special anyPolicy OID (2.5.29.32.0).
1217 (c) Root CA Certificates Root CA Certificates SHOULD NOT contain the
1218 certificatePolicies or extendedKeyUsage extensions.
1224 * MARK: Certificate Transparency support
1230 Version sct_version; // 1 byte
1231 LogID id; // 32 bytes
1232 uint64 timestamp; // 8 bytes
1233 CtExtensions extensions; // 2 bytes len field, + n bytes data
1234 digitally-signed struct { // 1 byte hash alg, 1 byte sig alg, n bytes signature
1235 Version sct_version;
1236 SignatureType signature_type = certificate_timestamp;
1238 LogEntryType entry_type;
1239 select(entry_type) {
1240 case x509_entry: ASN.1Cert;
1241 case precert_entry: PreCert;
1243 CtExtensions extensions;
1245 } SignedCertificateTimestamp;
1249 #include <Security/SecureTransportPriv.h>
1252 SecAsn1Oid
*oidForSigAlg(SSL_HashAlgorithm hash
, SSL_SignatureAlgorithm alg
)
1255 case SSL_SignatureAlgorithmRSA
:
1257 case SSL_HashAlgorithmSHA1
:
1258 return &CSSMOID_SHA1WithRSA
;
1259 case SSL_HashAlgorithmSHA256
:
1260 return &CSSMOID_SHA256WithRSA
;
1261 case SSL_HashAlgorithmSHA384
:
1262 return &CSSMOID_SHA384WithRSA
;
1266 case SSL_SignatureAlgorithmECDSA
:
1268 case SSL_HashAlgorithmSHA1
:
1269 return &CSSMOID_ECDSA_WithSHA1
;
1270 case SSL_HashAlgorithmSHA256
:
1271 return &CSSMOID_ECDSA_WithSHA256
;
1272 case SSL_HashAlgorithmSHA384
:
1273 return &CSSMOID_ECDSA_WithSHA384
;
1285 static size_t SSLDecodeUint16(const uint8_t *p
)
1287 return (p
[0]<<8 | p
[1]);
1290 static uint8_t *SSLEncodeUint16(uint8_t *p
, size_t len
)
1292 p
[0] = (len
>> 8)&0xff;
1293 p
[1] = (len
& 0xff);
1297 static uint8_t *SSLEncodeUint24(uint8_t *p
, size_t len
)
1299 p
[0] = (len
>> 16)&0xff;
1300 p
[1] = (len
>> 8)&0xff;
1301 p
[2] = (len
& 0xff);
1307 uint64_t SSLDecodeUint64(const uint8_t *p
)
1310 for(int i
=0; i
<8; i
++) {
1317 #include <libDER/DER_CertCrl.h>
1318 #include <libDER/DER_Encode.h>
1319 #include <libDER/asn1Types.h>
1322 static CFDataRef
copy_x509_entry_from_chain(SecPVCRef pvc
)
1324 SecCertificateRef leafCert
= SecPVCGetCertificateAtIndex(pvc
, 0);
1326 CFMutableDataRef data
= CFDataCreateMutable(kCFAllocatorDefault
, 3+SecCertificateGetLength(leafCert
));
1328 CFDataSetLength(data
, 3+SecCertificateGetLength(leafCert
));
1330 uint8_t *q
= CFDataGetMutableBytePtr(data
);
1331 q
= SSLEncodeUint24(q
, SecCertificateGetLength(leafCert
));
1332 memcpy(q
, SecCertificateGetBytePtr(leafCert
), SecCertificateGetLength(leafCert
));
1338 static CFDataRef
copy_precert_entry_from_chain(SecPVCRef pvc
)
1340 SecCertificateRef leafCert
= NULL
;
1341 SecCertificateRef issuer
= NULL
;
1342 CFDataRef issuerKeyHash
= NULL
;
1343 CFDataRef tbs_precert
= NULL
;
1344 CFMutableDataRef data
= NULL
;
1346 require_quiet(SecPVCGetCertificateCount(pvc
)>=2, out
); //we need the issuer key for precerts.
1347 leafCert
= SecPVCGetCertificateAtIndex(pvc
, 0);
1348 issuer
= SecPVCGetCertificateAtIndex(pvc
, 1);
1350 require(leafCert
, out
);
1351 require(issuer
, out
); // Those two would likely indicate an internal error, since we already checked the chain length above.
1352 issuerKeyHash
= SecCertificateCopySubjectPublicKeyInfoSHA256Digest(issuer
);
1353 tbs_precert
= SecCertificateCopyPrecertTBS(leafCert
);
1355 require(issuerKeyHash
, out
);
1356 require(tbs_precert
, out
);
1357 data
= CFDataCreateMutable(kCFAllocatorDefault
, CFDataGetLength(issuerKeyHash
) + 3 + CFDataGetLength(tbs_precert
));
1358 CFDataSetLength(data
, CFDataGetLength(issuerKeyHash
) + 3 + CFDataGetLength(tbs_precert
));
1360 uint8_t *q
= CFDataGetMutableBytePtr(data
);
1361 memcpy(q
, CFDataGetBytePtr(issuerKeyHash
), CFDataGetLength(issuerKeyHash
)); q
+= CFDataGetLength(issuerKeyHash
); // issuer key hash
1362 q
= SSLEncodeUint24(q
, CFDataGetLength(tbs_precert
));
1363 memcpy(q
, CFDataGetBytePtr(tbs_precert
), CFDataGetLength(tbs_precert
));
1366 CFReleaseSafe(issuerKeyHash
);
1367 CFReleaseSafe(tbs_precert
);
1372 CFAbsoluteTime
TimestampToCFAbsoluteTime(uint64_t ts
)
1374 return (ts
/ 1000) - kCFAbsoluteTimeIntervalSince1970
;
1378 uint64_t TimestampFromCFAbsoluteTime(CFAbsoluteTime at
)
1380 return (uint64_t)(at
+ kCFAbsoluteTimeIntervalSince1970
) * 1000;
1387 If the 'sct' is valid, add it to the validatingLogs dictionary.
1390 - validatingLogs: mutable dictionary to which to add the log that validate this SCT.
1392 - entry_type: 0 for x509 cert, 1 for precert.
1393 - entry: the cert or precert data.
1394 - vt: verification time timestamp (as used in SCTs: ms since 1970 Epoch)
1395 - trustedLog: Dictionary contain the Trusted Logs.
1397 The SCT is valid if:
1398 - It decodes properly.
1399 - Its timestamp is less than 'verifyTime'.
1400 - It is signed by a log in 'trustedLogs'.
1401 - If entry_type = 0, the log must be currently qualified.
1402 - If entry_type = 1, the log may be expired.
1404 If the SCT is valid, it's added to the validatinLogs dictionary using the log dictionary as the key, and the timestamp as value.
1405 If an entry for the same log already existing in the dictionary, the entry is replaced only if the timestamp of this SCT is earlier.
1410 static CFDictionaryRef
getSCTValidatingLog(CFDataRef sct
, int entry_type
, CFDataRef entry
, uint64_t vt
, CFArrayRef trustedLogs
, CFAbsoluteTime
*sct_at
)
1413 const uint8_t *logID
;
1414 const uint8_t *timestampData
;
1416 size_t extensionsLen
;
1417 const uint8_t *extensionsData
;
1420 size_t signatureLen
;
1421 const uint8_t *signatureData
;
1422 SecKeyRef pubKey
= NULL
;
1423 uint8_t *signed_data
= NULL
;
1424 const SecAsn1Oid
*oid
= NULL
;
1426 CFDataRef logIDData
= NULL
;
1427 CFDictionaryRef result
= 0;
1429 const uint8_t *p
= CFDataGetBytePtr(sct
);
1430 size_t len
= CFDataGetLength(sct
);
1432 require(len
>=43, out
);
1434 version
= p
[0]; p
++; len
--;
1435 logID
= p
; p
+=32; len
-=32;
1436 timestampData
= p
; p
+=8; len
-=8;
1437 extensionsLen
= SSLDecodeUint16(p
); p
+=2; len
-=2;
1439 require(len
>=extensionsLen
, out
);
1440 extensionsData
= p
; p
+=extensionsLen
; len
-=extensionsLen
;
1442 require(len
>=4, out
);
1443 hashAlg
=p
[0]; p
++; len
--;
1444 sigAlg
=p
[0]; p
++; len
--;
1445 signatureLen
= SSLDecodeUint16(p
); p
+=2; len
-=2;
1446 require(len
==signatureLen
, out
); /* We do not tolerate any extra data after the signature */
1449 /* verify version: only v1(0) is supported */
1451 secerror("SCT version unsupported: %d\n", version
);
1455 /* verify timestamp not in the future */
1456 timestamp
= SSLDecodeUint64(timestampData
);
1457 if(timestamp
> vt
) {
1458 secerror("SCT is in the future: %llu > %llu\n", timestamp
, vt
);
1465 size_t signed_data_len
= 12 + CFDataGetLength(entry
) + 2 + extensionsLen
;
1466 signed_data
= malloc(signed_data_len
);
1467 require(signed_data
, out
);
1470 *q
++ = 0; // certificate_timestamp
1471 memcpy(q
, timestampData
, 8); q
+=8;
1472 q
= SSLEncodeUint16(q
, entry_type
); // logentry type: 0=cert 1=precert
1473 memcpy(q
, CFDataGetBytePtr(entry
), CFDataGetLength(entry
)); q
+= CFDataGetLength(entry
);
1474 q
= SSLEncodeUint16(q
, extensionsLen
);
1475 memcpy(q
, extensionsData
, extensionsLen
);
1477 logIDData
= CFDataCreateWithBytesNoCopy(kCFAllocatorDefault
, logID
, 32, kCFAllocatorNull
);
1479 CFDictionaryRef logData
= CFArrayGetValueMatching(trustedLogs
, ^bool(const void *dict
) {
1480 const void *key_data
;
1481 if(!isDictionary(dict
)) return false;
1482 if(!CFDictionaryGetValueIfPresent(dict
, CFSTR("key"), &key_data
)) return false;
1483 if(!isData(key_data
)) return false;
1484 CFDataRef valueID
= SecSHA256DigestCreateFromData(kCFAllocatorDefault
, (CFDataRef
)key_data
);
1485 bool result
= (bool)(CFDataCompare(logIDData
, valueID
)==kCFCompareEqualTo
);
1486 CFReleaseSafe(valueID
);
1489 require(logData
, out
);
1492 // For external SCTs, only keep SCTs from currently valid logs.
1493 require(!CFDictionaryContainsKey(logData
, CFSTR("expiry")), out
);
1496 CFDataRef logKeyData
= CFDictionaryGetValue(logData
, CFSTR("key"));
1497 require(logKeyData
, out
); // This failing would be an internal logic error
1498 pubKey
= SecKeyCreateFromSubjectPublicKeyInfoData(kCFAllocatorDefault
, logKeyData
);
1499 require(pubKey
, out
);
1501 oid
= oidForSigAlg(hashAlg
, sigAlg
);
1504 algId
.algorithm
= *oid
;
1505 algId
.parameters
.Data
= NULL
;
1506 algId
.parameters
.Length
= 0;
1508 if(SecKeyDigestAndVerify(pubKey
, &algId
, signed_data
, signed_data_len
, signatureData
, signatureLen
)==0) {
1509 *sct_at
= TimestampToCFAbsoluteTime(timestamp
);
1512 secerror("SCT signature failed (log=%@)\n", logData
);
1516 CFReleaseSafe(logIDData
);
1517 CFReleaseSafe(pubKey
);
1523 static void addValidatingLog(CFMutableDictionaryRef validatingLogs
, CFDictionaryRef log
, CFAbsoluteTime sct_at
)
1525 CFDateRef validated_time
= CFDictionaryGetValue(validatingLogs
, log
);
1527 if(validated_time
==NULL
|| (sct_at
< CFDateGetAbsoluteTime(validated_time
))) {
1528 CFDateRef sct_time
= CFDateCreate(kCFAllocatorDefault
, sct_at
);
1529 CFDictionarySetValue(validatingLogs
, log
, sct_time
);
1530 CFReleaseSafe(sct_time
);
1534 static CFArrayRef
copy_ocsp_scts(SecPVCRef pvc
)
1536 CFMutableArrayRef SCTs
= NULL
;
1537 SecCertificateRef leafCert
= NULL
;
1538 SecCertificateRef issuer
= NULL
;
1539 CFArrayRef ocspResponsesData
= NULL
;
1540 SecOCSPRequestRef ocspRequest
= NULL
;
1542 ocspResponsesData
= SecPathBuilderCopyOCSPResponses(pvc
->builder
);
1543 require_quiet(ocspResponsesData
, out
);
1545 require_quiet(SecPVCGetCertificateCount(pvc
)>=2, out
); //we need the issuer key for precerts.
1546 leafCert
= SecPVCGetCertificateAtIndex(pvc
, 0);
1547 issuer
= SecPVCGetCertificateAtIndex(pvc
, 1);
1549 require(leafCert
, out
);
1550 require(issuer
, out
); // not quiet: Those two would likely indicate an internal error, since we already checked the chain length above.
1551 ocspRequest
= SecOCSPRequestCreate(leafCert
, issuer
);
1553 SCTs
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
);
1556 CFArrayForEach(ocspResponsesData
, ^(const void *value
) {
1557 /* TODO: Should the builder already have the appropriate SecOCSPResponseRef ? */
1558 SecOCSPResponseRef ocspResponse
= SecOCSPResponseCreate(value
);
1559 if(ocspResponse
&& SecOCSPGetResponseStatus(ocspResponse
)==kSecOCSPSuccess
) {
1560 SecOCSPSingleResponseRef ocspSingleResponse
= SecOCSPResponseCopySingleResponse(ocspResponse
, ocspRequest
);
1561 if(ocspSingleResponse
) {
1562 CFArrayRef singleResponseSCTs
= SecOCSPSingleResponseCopySCTs(ocspSingleResponse
);
1563 if(singleResponseSCTs
) {
1564 CFArrayAppendArray(SCTs
, singleResponseSCTs
, CFRangeMake(0, CFArrayGetCount(singleResponseSCTs
)));
1565 CFRelease(singleResponseSCTs
);
1567 SecOCSPSingleResponseDestroy(ocspSingleResponse
);
1570 if(ocspResponse
) SecOCSPResponseFinalize(ocspResponse
);
1573 if(CFArrayGetCount(SCTs
)==0) {
1574 CFReleaseNull(SCTs
);
1578 CFReleaseSafe(ocspResponsesData
);
1580 SecOCSPRequestFinalize(ocspRequest
);
1585 static void SecPolicyCheckCT(SecPVCRef pvc
)
1587 SecCertificateRef leafCert
= SecPVCGetCertificateAtIndex(pvc
, 0);
1588 CFArrayRef embeddedScts
= SecCertificateCopySignedCertificateTimestamps(leafCert
);
1589 CFArrayRef builderScts
= SecPathBuilderCopySignedCertificateTimestamps(pvc
->builder
);
1590 CFArrayRef trustedLogs
= SecPathBuilderCopyTrustedLogs(pvc
->builder
);
1591 CFArrayRef ocspScts
= copy_ocsp_scts(pvc
);
1592 CFDataRef precertEntry
= copy_precert_entry_from_chain(pvc
);
1593 CFDataRef x509Entry
= copy_x509_entry_from_chain(pvc
);
1594 __block
uint32_t trustedSCTCount
= 0;
1595 __block CFAbsoluteTime issuanceTime
= SecPVCGetVerifyTime(pvc
);
1596 TA_CTFailureReason failureReason
= TA_CTNoFailure
;
1598 // This eventually contain list of logs who validated the SCT.
1599 CFMutableDictionaryRef currentLogsValidatingScts
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
1600 CFMutableDictionaryRef logsValidatingEmbeddedScts
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
1602 uint64_t vt
= TimestampFromCFAbsoluteTime(SecPVCGetVerifyTime(pvc
));
1604 __block
bool at_least_one_currently_valid_external
= 0;
1605 __block
bool at_least_one_currently_valid_embedded
= 0;
1606 __block
bool unknown_log
= 0;
1607 __block
bool disqualified_log
= 0;
1609 require(logsValidatingEmbeddedScts
, out
);
1610 require(currentLogsValidatingScts
, out
);
1612 /* Skip if there are no SCTs. */
1613 require_action((embeddedScts
&& CFArrayGetCount(embeddedScts
) > 0) ||
1614 (builderScts
&& CFArrayGetCount(builderScts
) > 0) ||
1615 (ocspScts
&& CFArrayGetCount(ocspScts
) > 0),
1617 TrustAnalyticsBuilder
*analytics
= SecPathBuilderGetAnalyticsData(pvc
->builder
);
1619 analytics
->ct_failure_reason
= TA_CTNoSCTs
;
1623 if(trustedLogs
) { // Don't bother trying to validate SCTs if we don't have any trusted logs.
1624 if(embeddedScts
&& precertEntry
) { // Don't bother if we could not get the precert.
1625 CFArrayForEach(embeddedScts
, ^(const void *value
){
1626 CFAbsoluteTime sct_at
;
1627 CFDictionaryRef log
= getSCTValidatingLog(value
, 1, precertEntry
, vt
, trustedLogs
, &sct_at
);
1629 addValidatingLog(logsValidatingEmbeddedScts
, log
, sct_at
);
1630 if(!CFDictionaryContainsKey(log
, CFSTR("expiry"))) {
1631 addValidatingLog(currentLogsValidatingScts
, log
, sct_at
);
1632 at_least_one_currently_valid_embedded
= true;
1635 disqualified_log
= true;
1643 if(builderScts
&& x509Entry
) { // Don't bother if we could not get the cert.
1644 CFArrayForEach(builderScts
, ^(const void *value
){
1645 CFAbsoluteTime sct_at
;
1646 CFDictionaryRef log
= getSCTValidatingLog(value
, 0, x509Entry
, vt
, trustedLogs
, &sct_at
);
1648 addValidatingLog(currentLogsValidatingScts
, log
, sct_at
);
1649 at_least_one_currently_valid_external
= true;
1657 if(ocspScts
&& x509Entry
) {
1658 CFArrayForEach(ocspScts
, ^(const void *value
){
1659 CFAbsoluteTime sct_at
;
1660 CFDictionaryRef log
= getSCTValidatingLog(value
, 0, x509Entry
, vt
, trustedLogs
, &sct_at
);
1662 addValidatingLog(currentLogsValidatingScts
, log
, sct_at
);
1663 at_least_one_currently_valid_external
= true;
1671 failureReason
= TA_CTMissingLogs
;
1675 /* We now have 2 sets of logs that validated those SCTS, count them and make a final decision.
1678 is_ct = (A1 AND A2) OR (B1 AND B2).
1680 A1: embedded SCTs from 2+ to 5+ logs valid at issuance time
1681 A2: At least one embedded SCT from a currently valid log.
1683 B1: SCTs from 2 currently valid logs (from any source)
1684 B2: At least 1 external SCT from a currently valid log.
1688 bool hasValidExternalSCT
= (at_least_one_currently_valid_external
&& CFDictionaryGetCount(currentLogsValidatingScts
)>=2);
1689 bool hasValidEmbeddedSCT
= (at_least_one_currently_valid_embedded
);
1690 SecCertificatePathVCRef path
= SecPathBuilderGetPath(pvc
->builder
);
1691 SecCertificatePathVCSetIsCT(path
, false);
1693 if (hasValidEmbeddedSCT
) {
1694 /* Calculate issuance time based on timestamp of SCTs from current logs */
1695 CFDictionaryForEach(currentLogsValidatingScts
, ^(const void *key
, const void *value
) {
1696 CFDictionaryRef log
= key
;
1697 if(!CFDictionaryContainsKey(log
, CFSTR("expiry"))) {
1698 // Log is still qualified
1699 CFDateRef ts
= (CFDateRef
) value
;
1700 CFAbsoluteTime timestamp
= CFDateGetAbsoluteTime(ts
);
1701 if(timestamp
< issuanceTime
) {
1702 issuanceTime
= timestamp
;
1706 SecCertificatePathVCSetIssuanceTime(path
, issuanceTime
);
1708 if (hasValidExternalSCT
) {
1709 /* Note: since external SCT validates this cert, we do not need to
1710 override issuance time here. If the cert also has a valid embedded
1711 SCT, issuanceTime will be calculated and set in the block above. */
1712 SecCertificatePathVCSetIsCT(path
, true);
1713 } else if (hasValidEmbeddedSCT
) {
1714 __block
int lifetime
; // in Months
1715 __block
unsigned once_or_current_qualified_embedded
= 0;
1718 __block
bool failed_once_check
= false;
1719 CFDictionaryForEach(logsValidatingEmbeddedScts
, ^(const void *key
, const void *value
) {
1720 CFDictionaryRef log
= key
;
1721 CFDateRef ts
= value
;
1722 CFDateRef expiry
= CFDictionaryGetValue(log
, CFSTR("expiry"));
1723 if (expiry
== NULL
) { // Currently qualified OR
1724 once_or_current_qualified_embedded
++;
1725 } else if (CFDateCompare(ts
, expiry
, NULL
) == kCFCompareLessThan
&& // Once qualified. That is, qualified at the time of SCT AND
1726 issuanceTime
< CFDateGetAbsoluteTime(expiry
)) { // at the time of issuance.)
1727 once_or_current_qualified_embedded
++;
1730 failed_once_check
= true;
1734 SecCFCalendarDoWithZuluCalendar(^(CFCalendarRef zuluCalendar
) {
1736 CFCalendarGetComponentDifference(zuluCalendar
,
1737 SecCertificateNotValidBefore(leafCert
),
1738 SecCertificateNotValidAfter(leafCert
),
1739 0, "M", &_lifetime
);
1740 lifetime
= _lifetime
;
1743 unsigned requiredEmbeddedSctsCount
;
1745 if (lifetime
< 15) {
1746 requiredEmbeddedSctsCount
= 2;
1747 } else if (lifetime
<= 27) {
1748 requiredEmbeddedSctsCount
= 3;
1749 } else if (lifetime
<= 39) {
1750 requiredEmbeddedSctsCount
= 4;
1752 requiredEmbeddedSctsCount
= 5;
1755 if(once_or_current_qualified_embedded
>= requiredEmbeddedSctsCount
){
1756 SecCertificatePathVCSetIsCT(path
, true);
1758 /* Not enough "once or currently qualified" SCTs */
1759 if (failed_once_check
) {
1760 failureReason
= TA_CTEmbeddedNotEnoughDisqualified
;
1761 } else if (unknown_log
) {
1762 failureReason
= TA_CTEmbeddedNotEnoughUnknown
;
1764 failureReason
= TA_CTEmbeddedNotEnough
;
1767 } else if (!at_least_one_currently_valid_embedded
&& !at_least_one_currently_valid_external
) {
1768 /* No currently valid SCTs */
1769 if (disqualified_log
) {
1770 failureReason
= TA_CTNoCurrentSCTsDisqualifiedLog
;
1771 } else if (unknown_log
) {
1772 failureReason
= TA_CTNoCurrentSCTsUnknownLog
;
1774 } else if (at_least_one_currently_valid_external
) {
1775 /* One presented current SCT but failed total current check */
1776 if (disqualified_log
) {
1777 failureReason
= TA_CTPresentedNotEnoughDisqualified
;
1778 } else if (unknown_log
) {
1779 failureReason
= TA_CTPresentedNotEnoughUnknown
;
1781 failureReason
= TA_CTPresentedNotEnough
;
1785 /* Record analytics data for CT */
1786 TrustAnalyticsBuilder
*analytics
= SecPathBuilderGetAnalyticsData(pvc
->builder
);
1787 require_quiet(analytics
, out
);
1788 uint32_t sctCount
= 0;
1789 /* Count the total number of SCTs we found and report where we got them */
1790 if (embeddedScts
&& CFArrayGetCount(embeddedScts
) > 0) {
1791 analytics
->sct_sources
|= TA_SCTEmbedded
;
1792 sctCount
+= CFArrayGetCount(embeddedScts
);
1794 if (builderScts
&& CFArrayGetCount(builderScts
) > 0) {
1795 analytics
->sct_sources
|= TA_SCT_TLS
;
1796 sctCount
+= CFArrayGetCount(builderScts
);
1798 if (ocspScts
&& CFArrayGetCount(ocspScts
) > 0) {
1799 analytics
->sct_sources
|= TA_SCT_OCSP
;
1800 sctCount
+= CFArrayGetCount(ocspScts
);
1802 /* Report how many of those SCTs were once or currently qualified */
1803 analytics
->number_trusted_scts
= trustedSCTCount
;
1804 /* Report how many SCTs we got */
1805 analytics
->number_scts
= sctCount
;
1807 analytics
->ct_failure_reason
= failureReason
;
1808 /* Only one current SCT -- close to failure */
1809 if (CFDictionaryGetCount(currentLogsValidatingScts
) == 1) {
1810 analytics
->ct_one_current
= true;
1813 CFReleaseSafe(logsValidatingEmbeddedScts
);
1814 CFReleaseSafe(currentLogsValidatingScts
);
1815 CFReleaseSafe(builderScts
);
1816 CFReleaseSafe(embeddedScts
);
1817 CFReleaseSafe(ocspScts
);
1818 CFReleaseSafe(precertEntry
);
1819 CFReleaseSafe(trustedLogs
);
1820 CFReleaseSafe(x509Entry
);
1823 static bool checkPolicyOidData(SecPVCRef pvc
, CFDataRef oid
) {
1824 CFIndex ix
, count
= SecPVCGetCertificateCount(pvc
);
1826 key_value
.data
= (DERByte
*)CFDataGetBytePtr(oid
);
1827 key_value
.length
= (DERSize
)CFDataGetLength(oid
);
1829 for (ix
= 0; ix
< count
; ix
++) {
1830 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, ix
);
1831 policy_set_t policies
= policies_for_cert(cert
);
1833 if (policy_set_contains(policies
, &key_value
)) {
1834 policy_set_free(policies
);
1837 policy_set_free(policies
);
1842 static void SecPolicyCheckCertificatePolicy(SecPVCRef pvc
, CFStringRef key
)
1844 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
1845 CFTypeRef value
= CFDictionaryGetValue(policy
->_options
, key
);
1846 bool result
= false;
1848 if (CFGetTypeID(value
) == CFDataGetTypeID())
1850 result
= checkPolicyOidData(pvc
, value
);
1851 } else if (CFGetTypeID(value
) == CFStringGetTypeID()) {
1852 CFDataRef dataOid
= SecCertificateCreateOidDataFromString(NULL
, value
);
1854 result
= checkPolicyOidData(pvc
, dataOid
);
1859 SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
);
1864 static void SecPolicyCheckRevocation(SecPVCRef pvc
,
1866 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
1867 CFTypeRef value
= CFDictionaryGetValue(policy
->_options
, key
);
1868 if (isString(value
)) {
1869 SecPathBuilderSetRevocationMethod(pvc
->builder
, value
);
1873 static void SecPolicyCheckRevocationResponseRequired(SecPVCRef pvc
,
1875 pvc
->require_revocation_response
= true;
1876 secdebug("policy", "revocation response required");
1879 static void SecPolicyCheckRevocationOnline(SecPVCRef pvc
, CFStringRef key
) {
1880 SecPathBuilderSetCheckRevocationOnline(pvc
->builder
);
1883 static void SecPolicyCheckRevocationIfTrusted(SecPVCRef pvc
, CFStringRef key
) {
1884 SecPathBuilderSetCheckRevocationIfTrusted(pvc
->builder
);
1887 static void SecPolicyCheckNoNetworkAccess(SecPVCRef pvc
,
1889 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
1890 CFTypeRef value
= CFDictionaryGetValue(policy
->_options
, key
);
1891 if (value
== kCFBooleanTrue
) {
1892 SecPathBuilderSetCanAccessNetwork(pvc
->builder
, false);
1894 SecPathBuilderSetCanAccessNetwork(pvc
->builder
, true);
1898 static void SecPolicyCheckWeakKeySize(SecPVCRef pvc
,
1900 CFIndex ix
, count
= SecPVCGetCertificateCount(pvc
);
1901 for (ix
= 0; ix
< count
; ++ix
) {
1902 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, ix
);
1903 if (cert
&& SecCertificateIsWeakKey(cert
)) {
1904 /* Intermediate certificate has a weak key. */
1905 if (!SecPVCSetResult(pvc
, key
, ix
, kCFBooleanFalse
))
1911 static void SecPolicyCheckKeySize(SecPVCRef pvc
, CFStringRef key
) {
1912 CFIndex ix
, count
= SecPVCGetCertificateCount(pvc
);
1913 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
1914 CFDictionaryRef keySizes
= CFDictionaryGetValue(policy
->_options
, key
);
1915 for (ix
= 0; ix
< count
; ++ix
) {
1916 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, ix
);
1917 if (!SecCertificateIsAtLeastMinKeySize(cert
, keySizes
)) {
1918 if (!SecPVCSetResult(pvc
, key
, ix
, kCFBooleanFalse
))
1924 static void SecPolicyCheckWeakSignature(SecPVCRef pvc
, CFStringRef key
) {
1925 CFIndex ix
, count
= SecPVCGetCertificateCount(pvc
);
1926 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
1927 CFTypeRef pvcValue
= CFDictionaryGetValue(policy
->_options
, key
);
1928 for (ix
= 0; ix
< count
; ++ix
) {
1929 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, ix
);
1930 if (!SecPolicyCheckCertWeakSignature(cert
, pvcValue
)) {
1931 if (!SecPVCSetResult(pvc
, key
, ix
, kCFBooleanFalse
))
1937 static void SecPolicyCheckSignatureHashAlgorithms(SecPVCRef pvc
,
1939 CFIndex ix
, count
= SecPVCGetCertificateCount(pvc
);
1940 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
1941 CFSetRef disallowedHashAlgorithms
= CFDictionaryGetValue(policy
->_options
, key
);
1942 for (ix
= 0; ix
< count
; ++ix
) {
1943 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, ix
);
1944 if (!SecPolicyCheckCertSignatureHashAlgorithms(cert
, disallowedHashAlgorithms
)) {
1945 if (!SecPVCSetResult(pvc
, key
, ix
, kCFBooleanFalse
))
1951 static bool leaf_is_on_weak_hash_whitelist(SecPVCRef pvc
) {
1952 SecCertificateRef leaf
= SecPVCGetCertificateAtIndex(pvc
, 0);
1953 require_quiet(leaf
, out
);
1955 /* And now a special snowflake from our tests */
1957 /* subject:/C=AU/ST=NSW/L=St Leonards/O=VODAFONE HUTCHISON AUSTRALIA PTY LIMITED/OU=Technology Shared Services/CN=mybill.vodafone.com.au */
1958 /* issuer :/C=UK/O=Vodafone Group/CN=Vodafone (Corporate Services 2009) */
1959 /* Not After : May 26 09:37:50 2017 GMT */
1960 static const uint8_t vodafone
[] = {
1961 0xde, 0x77, 0x63, 0x97, 0x79, 0x47, 0xee, 0x6e, 0xc1, 0x3a,
1962 0x7b, 0x3b, 0xad, 0x43, 0x88, 0xa9, 0x66, 0x59, 0xa8, 0x18
1965 CFDataRef leafFingerprint
= SecCertificateGetSHA1Digest(leaf
);
1966 require_quiet(leafFingerprint
, out
);
1967 const unsigned int len
= 20;
1968 const uint8_t *dp
= CFDataGetBytePtr(leafFingerprint
);
1969 if (dp
&& (!memcmp(vodafone
, dp
, len
))) {
1977 static bool SecPVCKeyIsConstraintPolicyOption(SecPVCRef pvc
, CFStringRef key
);
1979 static void SecPolicyCheckSystemTrustedWeakHash(SecPVCRef pvc
,
1981 CFIndex ix
, count
= SecPVCGetCertificateCount(pvc
);
1983 Boolean keyInPolicy
= false;
1984 CFArrayRef policies
= pvc
->policies
;
1985 CFIndex policyIX
, policyCount
= CFArrayGetCount(policies
);
1986 for (policyIX
= 0; policyIX
< policyCount
; ++policyIX
) {
1987 SecPolicyRef policy
= (SecPolicyRef
)CFArrayGetValueAtIndex(policies
, policyIX
);
1988 if (policy
&& CFDictionaryContainsKey(policy
->_options
, key
)) {
1993 /* We only enforce this check when *both* of the following are true:
1994 * 1. One of the certs in the path has this usage constraint, and
1995 * 2. One of the policies in the PVC has this key
1996 * (As compared to normal policy options which require only one to be true..) */
1997 require_quiet(SecPVCKeyIsConstraintPolicyOption(pvc
, key
) &&
2000 /* Ignore the anchor if it's trusted */
2001 if (SecPathBuilderIsAnchored(pvc
->builder
)) {
2004 for (ix
= 0; ix
< count
; ++ix
) {
2005 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, ix
);
2006 if (SecCertificateIsWeakHash(cert
)) {
2007 if (!leaf_is_on_weak_hash_whitelist(pvc
)) {
2008 if (!SecPVCSetResult(pvc
, key
, ix
, kCFBooleanFalse
)) {
2018 static void SecPolicyCheckSystemTrustedWeakKey(SecPVCRef pvc
,
2020 CFIndex ix
, count
= SecPVCGetCertificateCount(pvc
);
2022 Boolean keyInPolicy
= false;
2023 CFArrayRef policies
= pvc
->policies
;
2024 CFIndex policyIX
, policyCount
= CFArrayGetCount(policies
);
2025 for (policyIX
= 0; policyIX
< policyCount
; ++policyIX
) {
2026 SecPolicyRef policy
= (SecPolicyRef
)CFArrayGetValueAtIndex(policies
, policyIX
);
2027 if (policy
&& CFDictionaryContainsKey(policy
->_options
, key
)) {
2032 /* We only enforce this check when *both* of the following are true:
2033 * 1. One of the certs in the path has this usage constraint, and
2034 * 2. One of the policies in the PVC has this key
2035 * (As compared to normal policy options which require only one to be true..) */
2036 require_quiet(SecPVCKeyIsConstraintPolicyOption(pvc
, key
) &&
2039 /* Ignore the anchor if it's trusted */
2040 if (SecPathBuilderIsAnchored(pvc
->builder
)) {
2043 for (ix
= 0; ix
< count
; ++ix
) {
2044 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, ix
);
2045 if (!SecCertificateIsStrongKey(cert
)) {
2046 if (!SecPVCSetResult(pvc
, key
, ix
, kCFBooleanFalse
)) {
2056 static void SecPolicyCheckPinningRequired(SecPVCRef pvc
, CFStringRef key
) {
2057 /* Pinning is disabled on the system, skip. */
2058 if (SecIsInternalRelease()) {
2059 if (CFPreferencesGetAppBooleanValue(CFSTR("AppleServerAuthenticationNoPinning"),
2060 CFSTR("com.apple.security"), NULL
)) {
2065 CFArrayRef policies
= pvc
->policies
;
2066 CFIndex policyIX
, policyCount
= CFArrayGetCount(policies
);
2067 for (policyIX
= 0; policyIX
< policyCount
; ++policyIX
) {
2068 SecPolicyRef policy
= (SecPolicyRef
)CFArrayGetValueAtIndex(policies
, policyIX
);
2069 CFStringRef policyName
= SecPolicyGetName(policy
);
2070 if (CFEqualSafe(policyName
, kSecPolicyNameSSLServer
)) {
2071 /* policy required pinning, but we didn't use a pinning policy */
2072 if (!SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
)) {
2079 void SecPolicyServerInitialize(void) {
2080 gSecPolicyLeafCallbacks
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0,
2081 &kCFTypeDictionaryKeyCallBacks
, NULL
);
2082 gSecPolicyPathCallbacks
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0,
2083 &kCFTypeDictionaryKeyCallBacks
, NULL
);
2085 #undef POLICYCHECKMACRO
2086 #define __PC_ADD_CHECK_(NAME)
2087 #define __PC_ADD_CHECK_L(NAME) CFDictionaryAddValue(gSecPolicyLeafCallbacks, kSecPolicyCheck##NAME, SecPolicyCheck##NAME);
2088 #define __PC_ADD_CHECK_A(NAME) CFDictionaryAddValue(gSecPolicyPathCallbacks, kSecPolicyCheck##NAME, SecPolicyCheck##NAME);
2090 #define POLICYCHECKMACRO(NAME, TRUSTRESULT, SUBTYPE, LEAFCHECK, PATHCHECK, LEAFONLY, CSSMERR, OSSTATUS) \
2091 __PC_ADD_CHECK_##LEAFCHECK(NAME) \
2092 __PC_ADD_CHECK_##PATHCHECK(NAME)
2093 #include "../Security/SecPolicyChecks.list"
2095 /* Some of these don't follow the naming conventions but are in the Pinning DB.
2096 * <rdar://34537018> fix policy check constant values */
2097 CFDictionaryAddValue(gSecPolicyLeafCallbacks
, CFSTR("CheckLeafMarkerOid"), SecPolicyCheckLeafMarkerOid
);
2098 CFDictionaryAddValue(gSecPolicyLeafCallbacks
, CFSTR("CheckLeafMarkersProdAndQA"), SecPolicyCheckLeafMarkersProdAndQA
);
2099 CFDictionaryAddValue(gSecPolicyPathCallbacks
, CFSTR("CheckIntermediateMarkerOid"), SecPolicyCheckIntermediateMarkerOid
);
2100 CFDictionaryAddValue(gSecPolicyPathCallbacks
, CFSTR("CheckIntermediateCountry"), SecPolicyCheckIntermediateCountry
);
2101 CFDictionaryAddValue(gSecPolicyPathCallbacks
, CFSTR("CheckIntermediateOrganization"), SecPolicyCheckIntermediateOrganization
);
2106 /********************************************************
2107 ****************** SecPVCRef Functions *****************
2108 ********************************************************/
2110 void SecPVCInit(SecPVCRef pvc
, SecPathBuilderRef builder
, CFArrayRef policies
) {
2111 secdebug("alloc", "pvc %p", pvc
);
2112 // Weird logging policies crashes.
2113 //secdebug("policy", "%@", policies);
2115 // Zero the pvc struct so only non-zero fields need to be explicitly set
2116 memset(pvc
, 0, sizeof(struct OpaqueSecPVC
));
2117 pvc
->builder
= builder
;
2118 pvc
->policies
= policies
;
2121 pvc
->result
= kSecTrustResultUnspecified
;
2123 CFMutableDictionaryRef certDetail
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0,
2124 &kCFTypeDictionaryKeyCallBacks
,
2125 &kCFTypeDictionaryValueCallBacks
);
2126 pvc
->leafDetails
= CFArrayCreate(kCFAllocatorDefault
, (const void **)&certDetail
,
2127 1, &kCFTypeArrayCallBacks
);
2128 CFRelease(certDetail
);
2131 void SecPVCDelete(SecPVCRef pvc
) {
2132 secdebug("alloc", "delete pvc %p", pvc
);
2133 CFReleaseNull(pvc
->policies
);
2134 CFReleaseNull(pvc
->details
);
2135 CFReleaseNull(pvc
->leafDetails
);
2138 void SecPVCSetPath(SecPVCRef pvc
, SecCertificatePathVCRef path
) {
2139 secdebug("policy", "%@", path
);
2141 pvc
->result
= kSecTrustResultUnspecified
;
2142 CFReleaseNull(pvc
->details
);
2145 void SecPVCComputeDetails(SecPVCRef pvc
, SecCertificatePathVCRef path
) {
2148 /* Since we don't run the LeafChecks again, we need to preserve the
2149 * result the leaf had. */
2150 CFIndex ix
, pathLength
= SecCertificatePathVCGetCount(path
);
2151 CFMutableArrayRef details
= CFArrayCreateMutableCopy(kCFAllocatorDefault
,
2152 pathLength
, pvc
->leafDetails
);
2153 for (ix
= 1; ix
< pathLength
; ++ix
) {
2154 CFMutableDictionaryRef certDetail
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0,
2155 &kCFTypeDictionaryKeyCallBacks
,
2156 &kCFTypeDictionaryValueCallBacks
);
2157 CFArrayAppendValue(details
, certDetail
);
2158 CFRelease(certDetail
);
2160 CFRetainAssign(pvc
->details
, details
);
2161 pvc
->result
= pvc
->leafResult
;
2162 CFReleaseSafe(details
);
2165 SecPolicyRef
SecPVCGetPolicy(SecPVCRef pvc
) {
2166 return (SecPolicyRef
)CFArrayGetValueAtIndex(pvc
->policies
, pvc
->policyIX
);
2169 static CFIndex
SecPVCGetCertificateCount(SecPVCRef pvc
) {
2170 return SecPathBuilderGetCertificateCount(pvc
->builder
);
2173 static SecCertificateRef
SecPVCGetCertificateAtIndex(SecPVCRef pvc
, CFIndex ix
) {
2174 return SecPathBuilderGetCertificateAtIndex(pvc
->builder
, ix
);
2177 static CFAbsoluteTime
SecPVCGetVerifyTime(SecPVCRef pvc
) {
2178 return SecPathBuilderGetVerifyTime(pvc
->builder
);
2181 static bool SecPVCIsExceptedError(SecPVCRef pvc
, CFIndex ix
, CFStringRef key
, CFTypeRef value
) {
2182 CFArrayRef exceptions
= SecPathBuilderGetExceptions(pvc
->builder
);
2183 if (!exceptions
) { return false; }
2184 CFIndex exceptionsCount
= CFArrayGetCount(exceptions
);
2186 /* There are two types of exceptions:
2187 * 1. Those that are built from SecTrustCopyExceptions, which are particular to the
2188 * certs in the chain -- as indicated by the SHA1 digest in the exception dictionary.
2189 * 2. On macOS, those built from SecTrustSetOptions, which are generic excepted errors.
2192 CFDictionaryRef options
= CFArrayGetValueAtIndex(exceptions
, 0);
2194 if (exceptionsCount
== 1 && (ix
> 0 || !CFDictionaryContainsKey(options
, kSecCertificateDetailSHA1Digest
))) {
2195 /* SHA1Digest not allowed */
2196 if (CFDictionaryContainsKey(options
, kSecCertificateDetailSHA1Digest
)) { return false; }
2198 if (CFDictionaryContainsKey(options
, key
)) {
2199 /* Special case -- AnchorTrusted only for self-signed certs */
2200 if (CFEqual(kSecPolicyCheckAnchorTrusted
, key
)) {
2201 Boolean isSelfSigned
= false;
2202 SecCertificateRef cert
= SecPathBuilderGetCertificateAtIndex(pvc
->builder
, ix
);
2203 if (!cert
|| (errSecSuccess
!= SecCertificateIsSelfSigned(cert
, &isSelfSigned
)) || !isSelfSigned
) {
2208 } else if (CFEqual(key
, kSecPolicyCheckTemporalValidity
) && CFDictionaryContainsKey(options
, kSecPolicyCheckValidRoot
)) {
2209 /* Another special case - ValidRoot excepts Valid only for self-signed certs */
2210 Boolean isSelfSigned
= false;
2211 SecCertificateRef cert
= SecPathBuilderGetCertificateAtIndex(pvc
->builder
, ix
);
2212 if (!cert
|| (errSecSuccess
!= SecCertificateIsSelfSigned(cert
, &isSelfSigned
)) || !isSelfSigned
) {
2221 if (ix
>= exceptionsCount
) { return false; }
2222 CFDictionaryRef exception
= CFArrayGetValueAtIndex(exceptions
, ix
);
2224 /* Compare the cert hash */
2225 if (!CFDictionaryContainsKey(exception
, kSecCertificateDetailSHA1Digest
)) { return false; }
2226 SecCertificateRef cert
= SecPathBuilderGetCertificateAtIndex(pvc
->builder
, ix
);
2227 if (!CFEqual(SecCertificateGetSHA1Digest(cert
), CFDictionaryGetValue(exception
, kSecCertificateDetailSHA1Digest
))) {
2232 CFTypeRef exceptionValue
= CFDictionaryGetValue(exception
, key
);
2233 if (exceptionValue
&& CFEqual(value
, exceptionValue
)) {
2234 /* Only change result if PVC is already ok */
2235 if (SecPVCIsOkResult(pvc
)) {
2236 // Chains that pass due to exceptions get Proceed result.
2237 pvc
->result
= kSecTrustResultProceed
;
2245 static int32_t detailKeyToCssmErr(CFStringRef key
) {
2248 if (CFEqual(key
, kSecPolicyCheckSSLHostname
)) {
2249 result
= -2147408896; // CSSMERR_APPLETP_HOSTNAME_MISMATCH
2251 else if (CFEqual(key
, kSecPolicyCheckEmail
)) {
2252 result
= -2147408872; // CSSMERR_APPLETP_SMIME_EMAIL_ADDRS_NOT_FOUND
2254 else if (CFEqual(key
, kSecPolicyCheckTemporalValidity
)) {
2255 result
= -2147409654; // CSSMERR_TP_CERT_EXPIRED
2261 static bool SecPVCMeetsConstraint(SecPVCRef pvc
, SecCertificateRef certificate
, CFDictionaryRef constraint
);
2263 static bool SecPVCIsAllowedError(SecPVCRef pvc
, CFIndex ix
, CFStringRef key
) {
2264 bool result
= false;
2265 SecCertificatePathVCRef path
= SecPathBuilderGetPath(pvc
->builder
);
2266 CFArrayRef constraints
= SecCertificatePathVCGetUsageConstraintsAtIndex(path
, ix
);
2267 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, ix
);
2268 CFIndex constraintIX
, constraintCount
= CFArrayGetCount(constraints
);
2270 for (constraintIX
= 0; constraintIX
< constraintCount
; constraintIX
++) {
2271 CFDictionaryRef constraint
= (CFDictionaryRef
)CFArrayGetValueAtIndex(constraints
, constraintIX
);
2272 CFNumberRef allowedErrorNumber
= NULL
;
2273 if (!isDictionary(constraint
)) {
2276 allowedErrorNumber
= (CFNumberRef
)CFDictionaryGetValue(constraint
, kSecTrustSettingsAllowedError
);
2277 int32_t allowedErrorValue
= 0;
2278 if (!isNumber(allowedErrorNumber
) || !CFNumberGetValue(allowedErrorNumber
, kCFNumberSInt32Type
, &allowedErrorValue
)) {
2282 if (SecPVCMeetsConstraint(pvc
, cert
, constraint
)) {
2283 if (allowedErrorValue
== detailKeyToCssmErr(key
)) {
2292 static bool SecPVCKeyIsConstraintPolicyOption(SecPVCRef pvc
, CFStringRef key
) {
2293 CFIndex certIX
, certCount
= SecPVCGetCertificateCount(pvc
);
2294 for (certIX
= 0; certIX
< certCount
; certIX
++) {
2295 SecCertificatePathVCRef path
= SecPathBuilderGetPath(pvc
->builder
);
2296 CFArrayRef constraints
= SecCertificatePathVCGetUsageConstraintsAtIndex(path
, certIX
);
2297 CFIndex constraintIX
, constraintCount
= CFArrayGetCount(constraints
);
2298 for (constraintIX
= 0; constraintIX
< constraintCount
; constraintIX
++) {
2299 CFDictionaryRef constraint
= (CFDictionaryRef
)CFArrayGetValueAtIndex(constraints
, constraintIX
);
2300 if (!isDictionary(constraint
)) {
2304 CFDictionaryRef policyOptions
= NULL
;
2305 policyOptions
= (CFDictionaryRef
)CFDictionaryGetValue(constraint
, kSecTrustSettingsPolicyOptions
);
2306 if (policyOptions
&& isDictionary(policyOptions
) &&
2307 CFDictionaryContainsKey(policyOptions
, key
)) {
2315 static SecTrustResultType
trust_result_for_key(CFStringRef key
) {
2316 SecTrustResultType result
= kSecTrustResultRecoverableTrustFailure
;
2317 #undef POLICYCHECKMACRO
2318 #define __PC_TYPE_MEMBER_ false
2319 #define __PC_TYPE_MEMBER_R false
2320 #define __PC_TYPE_MEMBER_F true
2321 #define __PC_TYPE_MEMBER_D true
2323 #define __TRUSTRESULT_ kSecTrustResultRecoverableTrustFailure
2324 #define __TRUSTRESULT_F kSecTrustResultFatalTrustFailure
2325 #define __TRUSTRESULT_D kSecTrustResultDeny
2326 #define __TRUSTRESULT_R kSecTrustResultRecoverableTrustFailure
2328 #define POLICYCHECKMACRO(NAME, TRUSTRESULT, SUBTYPE, LEAFCHECK, PATHCHECK, LEAFONLY, CSSMERR, OSSTATUS) \
2329 if (__PC_TYPE_MEMBER_##TRUSTRESULT && CFEqual(key,CFSTR(#NAME))) { \
2330 result = __TRUSTRESULT_##TRUSTRESULT; \
2332 #include "../Security/SecPolicyChecks.list"
2337 /* AUDIT[securityd](done):
2338 policy->_options is a caller provided dictionary, only its cf type has
2341 bool SecPVCSetResultForced(SecPVCRef pvc
,
2342 CFStringRef key
, CFIndex ix
, CFTypeRef result
, bool force
) {
2344 secnotice("policy", "cert[%d]: %@ =(%s)[%s]> %@", (int) ix
, key
,
2345 (pvc
->callbacks
== gSecPolicyLeafCallbacks
? "leaf"
2346 : (pvc
->callbacks
== gSecPolicyPathCallbacks
? "path"
2348 (force
? "force" : ""), result
);
2350 /* If this is not something the current policy cares about ignore
2351 this error and return true so our caller continues evaluation. */
2353 /* Either the policy or the usage constraints have to have this key */
2354 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
2355 if (!(SecPVCKeyIsConstraintPolicyOption(pvc
, key
) ||
2356 (policy
&& CFDictionaryContainsKey(policy
->_options
, key
)))) {
2361 /* Check to see if the SecTrustSettings for the certificate in question
2362 tell us to ignore this error. */
2363 if (SecPVCIsAllowedError(pvc
, ix
, key
)) {
2364 secinfo("policy", "cert[%d]: skipped allowed error %@", (int) ix
, key
);
2368 /* Check to see if exceptions tells us to ignore this error. */
2369 if (SecPVCIsExceptedError(pvc
, ix
, key
, result
)) {
2370 secinfo("policy", "cert[%d]: skipped exception error %@", (int) ix
, key
);
2374 /* Avoid resetting deny or fatal to recoverable */
2375 SecTrustResultType trustResult
= trust_result_for_key(key
);
2376 if (SecPVCIsOkResult(pvc
) || trustResult
== kSecTrustResultFatalTrustFailure
) {
2377 pvc
->result
= trustResult
;
2378 } else if (trustResult
== kSecTrustResultDeny
&&
2379 pvc
->result
== kSecTrustResultRecoverableTrustFailure
) {
2380 pvc
->result
= trustResult
;
2386 CFMutableDictionaryRef detail
=
2387 (CFMutableDictionaryRef
)CFArrayGetValueAtIndex(pvc
->details
, ix
);
2389 /* Perhaps detail should have an array of results per key? As it stands
2390 in the case of multiple policy failures the last failure stands. */
2391 CFDictionarySetValue(detail
, key
, result
);
2396 bool SecPVCSetResult(SecPVCRef pvc
,
2397 CFStringRef key
, CFIndex ix
, CFTypeRef result
) {
2398 return SecPVCSetResultForced(pvc
, key
, ix
, result
, false);
2401 /* AUDIT[securityd](done):
2402 key(ok) is a caller provided.
2403 value(ok, unused) is a caller provided.
2405 static void SecPVCValidateKey(const void *key
, const void *value
,
2407 SecPVCRef pvc
= (SecPVCRef
)context
;
2409 /* If our caller doesn't want full details and we failed earlier there is
2410 no point in doing additional checks. */
2411 if (!SecPVCIsOkResult(pvc
) && !pvc
->details
)
2414 SecPolicyCheckFunction fcn
= (SecPolicyCheckFunction
)
2415 CFDictionaryGetValue(pvc
->callbacks
, key
);
2418 /* "Optional" policy checks. This may be a new key from the
2419 * pinning DB which is not implemented in this OS version. Log a
2420 * warning, and on debug builds fail evaluation, to encourage us
2421 * to ensure that checks are synchronized across the same build. */
2422 if (pvc
->callbacks
== gSecPolicyLeafCallbacks
) {
2423 if (!CFDictionaryContainsKey(gSecPolicyPathCallbacks
, key
)) {
2424 secwarning("policy: unknown policy key %@, skipping", key
);
2426 pvc
->result
= kSecTrustResultOtherError
;
2429 } else if (pvc
->callbacks
== gSecPolicyPathCallbacks
) {
2430 if (!CFDictionaryContainsKey(gSecPolicyLeafCallbacks
, key
)) {
2431 secwarning("policy: unknown policy key %@, skipping", key
);
2433 pvc
->result
= kSecTrustResultOtherError
;
2437 /* Non standard validation phase, nothing is optional. */
2438 pvc
->result
= kSecTrustResultOtherError
;
2443 fcn(pvc
, (CFStringRef
)key
);
2446 /* AUDIT[securityd](done):
2447 policy->_options is a caller provided dictionary, only its cf type has
2450 SecTrustResultType
SecPVCLeafChecks(SecPVCRef pvc
) {
2451 /* We need to compute details for the leaf. */
2452 CFRetainAssign(pvc
->details
, pvc
->leafDetails
);
2454 CFArrayRef policies
= pvc
->policies
;
2455 CFIndex ix
, count
= CFArrayGetCount(policies
);
2456 for (ix
= 0; ix
< count
; ++ix
) {
2457 SecPolicyRef policy
= (SecPolicyRef
)CFArrayGetValueAtIndex(policies
, ix
);
2459 /* Validate all keys for all policies. */
2460 pvc
->callbacks
= gSecPolicyLeafCallbacks
;
2461 CFDictionaryApplyFunction(policy
->_options
, SecPVCValidateKey
, pvc
);
2464 pvc
->leafResult
= pvc
->result
;
2465 CFRetainAssign(pvc
->leafDetails
, pvc
->details
);
2470 bool SecPVCIsOkResult(SecPVCRef pvc
) {
2471 if (pvc
->result
== kSecTrustResultRecoverableTrustFailure
||
2472 pvc
->result
== kSecTrustResultDeny
||
2473 pvc
->result
== kSecTrustResultFatalTrustFailure
||
2474 pvc
->result
== kSecTrustResultOtherError
) {
2480 bool SecPVCParentCertificateChecks(SecPVCRef pvc
, CFIndex ix
) {
2481 /* Check stuff common to intermediate and anchors. */
2482 CFAbsoluteTime verifyTime
= SecPVCGetVerifyTime(pvc
);
2483 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, ix
);
2484 CFIndex anchor_ix
= SecPVCGetCertificateCount(pvc
) - 1;
2485 bool is_anchor
= (ix
== anchor_ix
&& SecPathBuilderIsAnchored(pvc
->builder
));
2487 if (!SecCertificateIsValid(cert
, verifyTime
)) {
2488 /* Certificate has expired. */
2489 if (!SecPVCSetResult(pvc
, kSecPolicyCheckTemporalValidity
, ix
, kCFBooleanFalse
)) {
2494 if (SecCertificateIsWeakKey(cert
)) {
2495 /* Certificate uses weak key. */
2496 if (!SecPVCSetResult(pvc
, kSecPolicyCheckWeakKeySize
, ix
, kCFBooleanFalse
)) {
2501 if (!SecPolicyCheckCertWeakSignature(cert
, NULL
)) {
2502 /* Certificate uses weak hash. */
2503 if (!SecPVCSetResult(pvc
, kSecPolicyCheckWeakSignature
, ix
, kCFBooleanFalse
)) {
2509 /* Perform anchor specific checks. */
2510 /* Don't think we have any of these. */
2512 /* Perform intermediate specific checks. */
2514 /* (k) Basic constraints only relevant for v3 and later. */
2515 if (SecCertificateVersion(cert
) >= 3) {
2516 const SecCEBasicConstraints
*bc
=
2517 SecCertificateGetBasicConstraints(cert
);
2519 /* Basic constraints not present, illegal. */
2520 if (!SecPVCSetResultForced(pvc
, kSecPolicyCheckBasicConstraints
,
2521 ix
, kCFBooleanFalse
, true)) {
2524 } else if (!bc
->isCA
) {
2525 /* Basic constraints not marked as isCA, illegal. */
2526 if (!SecPVCSetResultForced(pvc
, kSecPolicyCheckBasicConstraintsCA
,
2527 ix
, kCFBooleanFalse
, true)) {
2532 /* For a v1 or v2 certificate in an intermediate slot (not a leaf and
2533 not an anchor), we additionally require that the certificate chain
2534 does not end in a v3 or later anchor. [rdar://32204517] */
2535 else if (ix
> 0 && ix
< anchor_ix
) {
2536 SecCertificateRef anchor
= SecPVCGetCertificateAtIndex(pvc
, anchor_ix
);
2537 if (SecCertificateVersion(anchor
) >= 3) {
2538 if (!SecPVCSetResultForced(pvc
, kSecPolicyCheckBasicConstraints
,
2539 ix
, kCFBooleanFalse
, true)) {
2544 /* (l) max_path_length is checked elsewhere. */
2546 /* (n) If a key usage extension is present, verify that the keyCertSign bit is set. */
2547 SecKeyUsage keyUsage
= SecCertificateGetKeyUsage(cert
);
2548 if (keyUsage
&& !(keyUsage
& kSecKeyUsageKeyCertSign
)) {
2549 if (!SecPVCSetResultForced(pvc
, kSecPolicyCheckKeyUsage
,
2550 ix
, kCFBooleanFalse
, true)) {
2557 return SecPVCIsOkResult(pvc
);
2560 static bool SecPVCBlackListedKeyChecks(SecPVCRef pvc
, CFIndex ix
) {
2561 /* Check stuff common to intermediate and anchors. */
2563 SecOTAPKIRef otapkiRef
= SecOTAPKICopyCurrentOTAPKIRef();
2564 if (NULL
!= otapkiRef
)
2566 CFSetRef blackListedKeys
= SecOTAPKICopyBlackListSet(otapkiRef
);
2567 CFRelease(otapkiRef
);
2568 if (NULL
!= blackListedKeys
)
2570 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, ix
);
2571 CFIndex count
= SecPVCGetCertificateCount(pvc
);
2572 bool is_last
= (ix
== count
- 1);
2573 bool is_anchor
= (is_last
&& SecPathBuilderIsAnchored(pvc
->builder
));
2575 /* Check for blacklisted intermediate issuer keys. */
2576 CFDataRef dgst
= SecCertificateCopyPublicKeySHA1Digest(cert
);
2578 /* Check dgst against blacklist. */
2579 if (CFSetContainsValue(blackListedKeys
, dgst
)) {
2580 /* Check allow list for this blacklisted issuer key,
2581 which is the authority key of the issued cert at ix-1.
2583 SecCertificatePathVCRef path
= SecPathBuilderGetPath(pvc
->builder
);
2584 bool allowed
= path
&& SecCertificatePathVCIsAllowlisted(path
);
2586 SecPVCSetResultForced(pvc
, kSecPolicyCheckBlackListedKey
,
2587 ix
, kCFBooleanFalse
, true);
2593 CFRelease(blackListedKeys
);
2594 return SecPVCIsOkResult(pvc
);
2601 static bool SecPVCGrayListedKeyChecks(SecPVCRef pvc
, CFIndex ix
)
2603 /* Check stuff common to intermediate and anchors. */
2604 SecOTAPKIRef otapkiRef
= SecOTAPKICopyCurrentOTAPKIRef();
2605 if (NULL
!= otapkiRef
)
2607 CFSetRef grayListKeys
= SecOTAPKICopyGrayList(otapkiRef
);
2608 CFRelease(otapkiRef
);
2609 if (NULL
!= grayListKeys
)
2611 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, ix
);
2612 CFIndex count
= SecPVCGetCertificateCount(pvc
);
2613 bool is_last
= (ix
== count
- 1);
2614 bool is_anchor
= (is_last
&& SecPathBuilderIsAnchored(pvc
->builder
));
2616 /* Check for gray listed intermediate issuer keys. */
2617 CFDataRef dgst
= SecCertificateCopyPublicKeySHA1Digest(cert
);
2619 /* Check dgst against gray list. */
2620 if (CFSetContainsValue(grayListKeys
, dgst
)) {
2621 /* Check allow list for this graylisted issuer key,
2622 which is the authority key of the issued cert at ix-1.
2624 SecCertificatePathVCRef path
= SecPathBuilderGetPath(pvc
->builder
);
2625 bool allowed
= path
&& SecCertificatePathVCIsAllowlisted(path
);
2627 SecPVCSetResultForced(pvc
, kSecPolicyCheckGrayListedKey
,
2628 ix
, kCFBooleanFalse
, true);
2634 CFRelease(grayListKeys
);
2635 return SecPVCIsOkResult(pvc
);
2642 static bool SecPVCContainsPolicy(SecPVCRef pvc
, CFStringRef searchOid
, CFStringRef searchName
, CFIndex
*policyIX
) {
2643 if (!isString(searchName
) && !isString(searchOid
)) {
2646 CFArrayRef policies
= pvc
->policies
;
2647 CFIndex ix
, count
= CFArrayGetCount(policies
);
2648 for (ix
= 0; ix
< count
; ++ix
) {
2649 SecPolicyRef policy
= (SecPolicyRef
)CFArrayGetValueAtIndex(policies
, ix
);
2650 CFStringRef policyName
= SecPolicyGetName(policy
);
2651 CFStringRef policyOid
= SecPolicyGetOidString(policy
);
2652 /* Prefer a match of both name and OID */
2653 if (searchOid
&& searchName
&& policyOid
&& policyName
) {
2654 if (CFEqual(searchOid
, policyOid
) &&
2655 CFEqual(searchName
, policyName
)) {
2656 if (policyIX
) { *policyIX
= ix
; }
2659 /* <rdar://40617139> sslServer trust settings need to apply to evals using policyName pinning
2660 * but make sure we don't use this for SSL Client trust settings or policies. */
2661 if (CFEqual(searchOid
, policyOid
) &&
2662 CFEqual(searchName
, kSecPolicyNameSSLServer
) && !CFEqual(policyName
, kSecPolicyNameSSLClient
)) {
2663 if (policyIX
) { *policyIX
= ix
; }
2667 /* Next best is just OID. */
2668 if (!searchName
&& searchOid
&& policyOid
) {
2669 if (CFEqual(searchOid
, policyOid
)) {
2670 if (policyIX
) { *policyIX
= ix
; }
2674 if (!searchOid
&& searchName
&& policyName
) {
2675 if (CFEqual(searchName
, policyName
)) {
2676 if (policyIX
) { *policyIX
= ix
; }
2684 static bool SecPVCContainsString(SecPVCRef pvc
, CFIndex policyIX
, CFStringRef stringValue
) {
2685 if (!isString(stringValue
)) {
2688 bool result
= false;
2690 CFStringRef tmpStringValue
= NULL
;
2691 if (CFStringGetCharacterAtIndex(stringValue
, CFStringGetLength(stringValue
) -1) == (UniChar
)0x0000) {
2692 tmpStringValue
= CFStringCreateTruncatedCopy(stringValue
, CFStringGetLength(stringValue
) - 1);
2694 tmpStringValue
= CFStringCreateCopy(NULL
, stringValue
);
2696 if (policyIX
>= 0 && policyIX
< CFArrayGetCount(pvc
->policies
)) {
2697 SecPolicyRef policy
= (SecPolicyRef
)CFArrayGetValueAtIndex(pvc
->policies
, policyIX
);
2698 /* Have to look for all the possible locations of name string */
2699 CFStringRef policyString
= NULL
;
2700 policyString
= CFDictionaryGetValue(policy
->_options
, kSecPolicyCheckSSLHostname
);
2701 if (!policyString
) {
2702 policyString
= CFDictionaryGetValue(policy
->_options
, kSecPolicyCheckEmail
);
2704 if (policyString
&& (CFStringCompare(tmpStringValue
, policyString
, kCFCompareCaseInsensitive
) == kCFCompareEqualTo
)) {
2709 CFArrayRef policyStrings
= NULL
;
2710 policyStrings
= CFDictionaryGetValue(policy
->_options
, kSecPolicyCheckEAPTrustedServerNames
);
2711 if (policyStrings
&& CFArrayContainsValue(policyStrings
,
2712 CFRangeMake(0, CFArrayGetCount(policyStrings
)),
2720 CFReleaseNull(tmpStringValue
);
2725 static uint32_t ts_key_usage_for_kuNumber(CFNumberRef keyUsageNumber
) {
2726 uint32_t ourTSKeyUsage
= 0;
2727 uint32_t keyUsage
= 0;
2728 if (keyUsageNumber
&&
2729 CFNumberGetValue(keyUsageNumber
, kCFNumberSInt32Type
, &keyUsage
)) {
2730 if (keyUsage
& kSecKeyUsageDigitalSignature
) {
2731 ourTSKeyUsage
|= kSecTrustSettingsKeyUseSignature
;
2733 if (keyUsage
& kSecKeyUsageDataEncipherment
) {
2734 ourTSKeyUsage
|= kSecTrustSettingsKeyUseEnDecryptData
;
2736 if (keyUsage
& kSecKeyUsageKeyEncipherment
) {
2737 ourTSKeyUsage
|= kSecTrustSettingsKeyUseEnDecryptKey
;
2739 if (keyUsage
& kSecKeyUsageKeyAgreement
) {
2740 ourTSKeyUsage
|= kSecTrustSettingsKeyUseKeyExchange
;
2742 if (keyUsage
== kSecKeyUsageAll
) {
2743 ourTSKeyUsage
= kSecTrustSettingsKeyUseAny
;
2746 return ourTSKeyUsage
;
2749 static uint32_t ts_key_usage_for_policy(SecPolicyRef policy
) {
2750 uint32_t ourTSKeyUsage
= 0;
2751 CFTypeRef policyKeyUsageType
= NULL
;
2753 policyKeyUsageType
= (CFTypeRef
)CFDictionaryGetValue(policy
->_options
, kSecPolicyCheckKeyUsage
);
2754 if (isArray(policyKeyUsageType
)) {
2755 CFIndex ix
, count
= CFArrayGetCount(policyKeyUsageType
);
2756 for (ix
= 0; ix
< count
; ix
++) {
2757 CFNumberRef policyKeyUsageNumber
= NULL
;
2758 policyKeyUsageNumber
= (CFNumberRef
)CFArrayGetValueAtIndex(policyKeyUsageType
, ix
);
2759 ourTSKeyUsage
|= ts_key_usage_for_kuNumber(policyKeyUsageNumber
);
2761 } else if (isNumber(policyKeyUsageType
)) {
2762 ourTSKeyUsage
|= ts_key_usage_for_kuNumber(policyKeyUsageType
);
2765 return ourTSKeyUsage
;
2768 static bool SecPVCContainsTrustSettingsKeyUsage(SecPVCRef pvc
,
2769 SecCertificateRef certificate
, CFIndex policyIX
, CFNumberRef keyUsageNumber
) {
2770 int64_t keyUsageValue
= 0;
2771 uint32_t ourKeyUsage
= 0;
2773 if (!isNumber(keyUsageNumber
) || !CFNumberGetValue(keyUsageNumber
, kCFNumberSInt64Type
, &keyUsageValue
)) {
2777 if (keyUsageValue
== kSecTrustSettingsKeyUseAny
) {
2781 /* We're using the key for revocation if we have the OCSPSigner policy.
2782 * @@@ If we support CRLs, we'd need to check for that policy here too.
2784 if (SecPVCContainsPolicy(pvc
, kSecPolicyAppleOCSPSigner
, NULL
, NULL
)) {
2785 ourKeyUsage
|= kSecTrustSettingsKeyUseSignRevocation
;
2788 /* We're using the key for verifying a cert if it's a root/intermediate
2789 * in the chain. If the cert isn't in the path yet, we're about to add it,
2790 * so it's a root/intermediate. If there is no path, this is the leaf.
2792 CFIndex pathIndex
= -1;
2793 SecCertificatePathVCRef path
= SecPathBuilderGetPath(pvc
->builder
);
2795 pathIndex
= SecCertificatePathVCGetIndexOfCertificate(path
, certificate
);
2799 if (pathIndex
!= 0) {
2800 ourKeyUsage
|= kSecTrustSettingsKeyUseSignCert
;
2803 /* The rest of the key usages may be specified by the policy(ies). */
2804 if (policyIX
>= 0 && policyIX
< CFArrayGetCount(pvc
->policies
)) {
2805 SecPolicyRef policy
= (SecPolicyRef
)CFArrayGetValueAtIndex(pvc
->policies
, policyIX
);
2806 ourKeyUsage
|= ts_key_usage_for_policy(policy
);
2808 /* Get key usage from ALL policies */
2809 CFIndex ix
, count
= CFArrayGetCount(pvc
->policies
);
2810 for (ix
= 0; ix
< count
; ix
++) {
2811 SecPolicyRef policy
= (SecPolicyRef
)CFArrayGetValueAtIndex(pvc
->policies
, ix
);
2812 ourKeyUsage
|= ts_key_usage_for_policy(policy
);
2816 if (ourKeyUsage
== (uint32_t)(keyUsageValue
& 0x00ffffffff)) {
2824 #include <Security/SecTrustedApplicationPriv.h>
2825 #include <Security/SecTask.h>
2826 #include <Security/SecTaskPriv.h>
2827 #include <bsm/libbsm.h>
2828 #include <libproc.h>
2830 extern OSStatus
SecTaskValidateForRequirement(SecTaskRef task
, CFStringRef requirement
);
2832 static bool SecPVCCallerIsApplication(CFDataRef clientAuditToken
, CFTypeRef appRef
) {
2833 bool result
= false;
2834 audit_token_t auditToken
= {};
2835 SecTaskRef task
= NULL
;
2836 SecRequirementRef requirement
= NULL
;
2837 CFStringRef stringRequirement
= NULL
;
2839 require(appRef
&& clientAuditToken
, out
);
2840 require(CFGetTypeID(appRef
) == SecTrustedApplicationGetTypeID(), out
);
2841 require_noerr(SecTrustedApplicationCopyRequirement((SecTrustedApplicationRef
)appRef
, &requirement
), out
);
2842 require(requirement
, out
);
2843 require_noerr(SecRequirementsCopyString(requirement
, kSecCSDefaultFlags
, &stringRequirement
), out
);
2844 require(stringRequirement
, out
);
2846 require(sizeof(auditToken
) == CFDataGetLength(clientAuditToken
), out
);
2847 CFDataGetBytes(clientAuditToken
, CFRangeMake(0, sizeof(auditToken
)), (uint8_t *)&auditToken
);
2848 require(task
= SecTaskCreateWithAuditToken(NULL
, auditToken
), out
);
2850 if(errSecSuccess
== SecTaskValidateForRequirement(task
, stringRequirement
)) {
2855 CFReleaseNull(task
);
2856 CFReleaseNull(requirement
);
2857 CFReleaseNull(stringRequirement
);
2862 static bool SecPVCContainsTrustSettingsPolicyOption(SecPVCRef pvc
, CFDictionaryRef options
) {
2863 if (!isDictionary(options
)) {
2868 CFDictionaryRef currentCallbacks
= pvc
->callbacks
;
2870 /* We need to run the leaf and path checks using these options. */
2871 pvc
->callbacks
= gSecPolicyLeafCallbacks
;
2872 CFDictionaryApplyFunction(options
, SecPVCValidateKey
, pvc
);
2874 pvc
->callbacks
= gSecPolicyPathCallbacks
;
2875 CFDictionaryApplyFunction(options
, SecPVCValidateKey
, pvc
);
2878 pvc
->callbacks
= currentCallbacks
;
2880 /* Our work here is done; no need to claim a match */
2884 static bool SecPVCMeetsConstraint(SecPVCRef pvc
, SecCertificateRef certificate
, CFDictionaryRef constraint
) {
2885 CFStringRef policyOid
= NULL
, policyString
= NULL
, policyName
= NULL
;
2886 CFNumberRef keyUsageNumber
= NULL
;
2887 CFTypeRef trustedApplicationData
= NULL
;
2888 CFDictionaryRef policyOptions
= NULL
;
2890 bool policyMatch
= false, policyStringMatch
= false, applicationMatch
= false ,
2891 keyUsageMatch
= false, policyOptionMatch
= false;
2892 bool result
= false;
2894 #if TARGET_OS_MAC && !TARGET_OS_IPHONE
2895 /* OS X returns a SecPolicyRef in the constraints. Convert to the oid string. */
2896 SecPolicyRef policy
= NULL
;
2897 policy
= (SecPolicyRef
)CFDictionaryGetValue(constraint
, kSecTrustSettingsPolicy
);
2898 policyOid
= (policy
) ? policy
->_oid
: NULL
;
2900 policyOid
= (CFStringRef
)CFDictionaryGetValue(constraint
, kSecTrustSettingsPolicy
);
2902 policyName
= (CFStringRef
)CFDictionaryGetValue(constraint
, kSecTrustSettingsPolicyName
);
2903 policyString
= (CFStringRef
)CFDictionaryGetValue(constraint
, kSecTrustSettingsPolicyString
);
2904 keyUsageNumber
= (CFNumberRef
)CFDictionaryGetValue(constraint
, kSecTrustSettingsKeyUsage
);
2905 policyOptions
= (CFDictionaryRef
)CFDictionaryGetValue(constraint
, kSecTrustSettingsPolicyOptions
);
2907 CFIndex policyIX
= -1;
2908 policyMatch
= SecPVCContainsPolicy(pvc
, policyOid
, policyName
, &policyIX
);
2909 policyStringMatch
= SecPVCContainsString(pvc
, policyIX
, policyString
);
2910 keyUsageMatch
= SecPVCContainsTrustSettingsKeyUsage(pvc
, certificate
, policyIX
, keyUsageNumber
);
2911 policyOptionMatch
= SecPVCContainsTrustSettingsPolicyOption(pvc
, policyOptions
);
2913 #if TARGET_OS_MAC && !TARGET_OS_IPHONE
2914 trustedApplicationData
= CFDictionaryGetValue(constraint
, kSecTrustSettingsApplication
);
2915 CFDataRef clientAuditToken
= SecPathBuilderCopyClientAuditToken(pvc
->builder
);
2916 applicationMatch
= SecPVCCallerIsApplication(clientAuditToken
, trustedApplicationData
);
2917 CFReleaseNull(clientAuditToken
);
2919 if(CFDictionaryContainsKey(constraint
, kSecTrustSettingsApplication
)) {
2920 secerror("kSecTrustSettingsApplication is not yet supported on this platform");
2924 /* If we either didn't find the parameter in the dictionary or we got a match
2925 * against that parameter, for all possible parameters in the dictionary, then
2926 * this trust setting result applies to the output. */
2927 if (((!policyOid
&& !policyName
) || policyMatch
) &&
2928 (!policyString
|| policyStringMatch
) &&
2929 (!trustedApplicationData
|| applicationMatch
) &&
2930 (!keyUsageNumber
|| keyUsageMatch
) &&
2931 (!policyOptions
|| policyOptionMatch
)) {
2938 SecTrustSettingsResult
SecPVCGetTrustSettingsResult(SecPVCRef pvc
, SecCertificateRef certificate
, CFArrayRef constraints
) {
2939 SecTrustSettingsResult result
= kSecTrustSettingsResultInvalid
;
2940 CFIndex constraintIX
, constraintCount
= CFArrayGetCount(constraints
);
2941 for (constraintIX
= 0; constraintIX
< constraintCount
; constraintIX
++) {
2942 CFDictionaryRef constraint
= (CFDictionaryRef
)CFArrayGetValueAtIndex(constraints
, constraintIX
);
2943 if (!isDictionary(constraint
)) {
2947 CFNumberRef resultNumber
= NULL
;
2948 resultNumber
= (CFNumberRef
)CFDictionaryGetValue(constraint
, kSecTrustSettingsResult
);
2949 uint32_t resultValue
= kSecTrustSettingsResultInvalid
;
2950 if (!isNumber(resultNumber
) || !CFNumberGetValue(resultNumber
, kCFNumberSInt32Type
, &resultValue
)) {
2951 /* no SecTrustSettingsResult entry defaults to TrustRoot*/
2952 resultValue
= kSecTrustSettingsResultTrustRoot
;
2955 if (SecPVCMeetsConstraint(pvc
, certificate
, constraint
)) {
2956 result
= resultValue
;
2963 static void SecPVCCheckUsageConstraints(SecPVCRef pvc
) {
2964 CFIndex certIX
, certCount
= SecPVCGetCertificateCount(pvc
);
2965 for (certIX
= 0; certIX
< certCount
; certIX
++) {
2966 SecCertificatePathVCRef path
= SecPathBuilderGetPath(pvc
->builder
);
2967 CFArrayRef constraints
= SecCertificatePathVCGetUsageConstraintsAtIndex(path
, certIX
);
2968 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, certIX
);
2969 SecTrustSettingsResult result
= SecPVCGetTrustSettingsResult(pvc
, cert
, constraints
);
2971 /* Set the pvc trust result based on the usage constraints and anchor source. */
2972 if (result
== kSecTrustSettingsResultDeny
) {
2973 SecPVCSetResultForced(pvc
, kSecPolicyCheckUsageConstraints
, certIX
, kCFBooleanFalse
, true);
2974 } else if ((result
== kSecTrustSettingsResultTrustRoot
|| result
== kSecTrustSettingsResultTrustAsRoot
||
2975 result
== kSecTrustSettingsResultInvalid
) && SecPVCIsOkResult(pvc
)) {
2976 /* If we already think the PVC is ok and this cert is from one of the user/
2977 * admin anchor sources, trustRoot, trustAsRoot, and Invalid (no constraints),
2978 * all mean we should use the special "Proceed" trust result. */
2979 #if TARGET_OS_IPHONE
2980 if (SecPathBuilderIsAnchorSource(pvc
->builder
, kSecUserAnchorSource
) &&
2981 SecCertificateSourceContains(kSecUserAnchorSource
, cert
)) {
2983 if (SecPathBuilderIsAnchorSource(pvc
->builder
, kSecLegacyAnchorSource
) &&
2984 SecCertificateSourceContains(kSecLegacyAnchorSource
, cert
)) {
2986 pvc
->result
= kSecTrustResultProceed
;
2992 static const UInt8 kTestDateConstraintsRoot
[kSecPolicySHA256Size
] = {
2993 0x51,0xA0,0xF3,0x1F,0xC0,0x1D,0xEC,0x87,0x32,0xB6,0xFD,0x13,0x6A,0x43,0x4D,0x6C,
2994 0x87,0xCD,0x62,0xE0,0x38,0xB4,0xFB,0xD6,0x40,0xB0,0xFD,0x62,0x4D,0x1F,0xCF,0x6D
2996 static const UInt8 kWS_CA1_G2
[kSecPolicySHA256Size
] = {
2997 0xD4,0x87,0xA5,0x6F,0x83,0xB0,0x74,0x82,0xE8,0x5E,0x96,0x33,0x94,0xC1,0xEC,0xC2,
2998 0xC9,0xE5,0x1D,0x09,0x03,0xEE,0x94,0x6B,0x02,0xC3,0x01,0x58,0x1E,0xD9,0x9E,0x16
3000 static const UInt8 kWS_CA1_NEW
[kSecPolicySHA256Size
] = {
3001 0x4B,0x22,0xD5,0xA6,0xAE,0xC9,0x9F,0x3C,0xDB,0x79,0xAA,0x5E,0xC0,0x68,0x38,0x47,
3002 0x9C,0xD5,0xEC,0xBA,0x71,0x64,0xF7,0xF2,0x2D,0xC1,0xD6,0x5F,0x63,0xD8,0x57,0x08
3004 static const UInt8 kWS_CA2_NEW
[kSecPolicySHA256Size
] = {
3005 0xD6,0xF0,0x34,0xBD,0x94,0xAA,0x23,0x3F,0x02,0x97,0xEC,0xA4,0x24,0x5B,0x28,0x39,
3006 0x73,0xE4,0x47,0xAA,0x59,0x0F,0x31,0x0C,0x77,0xF4,0x8F,0xDF,0x83,0x11,0x22,0x54
3008 static const UInt8 kWS_ECC
[kSecPolicySHA256Size
] = {
3009 0x8B,0x45,0xDA,0x1C,0x06,0xF7,0x91,0xEB,0x0C,0xAB,0xF2,0x6B,0xE5,0x88,0xF5,0xFB,
3010 0x23,0x16,0x5C,0x2E,0x61,0x4B,0xF8,0x85,0x56,0x2D,0x0D,0xCE,0x50,0xB2,0x9B,0x02
3012 static const UInt8 kSC_SFSCA
[kSecPolicySHA256Size
] = {
3013 0xC7,0x66,0xA9,0xBE,0xF2,0xD4,0x07,0x1C,0x86,0x3A,0x31,0xAA,0x49,0x20,0xE8,0x13,
3014 0xB2,0xD1,0x98,0x60,0x8C,0xB7,0xB7,0xCF,0xE2,0x11,0x43,0xB8,0x36,0xDF,0x09,0xEA
3016 static const UInt8 kSC_SHA2
[kSecPolicySHA256Size
] = {
3017 0xE1,0x78,0x90,0xEE,0x09,0xA3,0xFB,0xF4,0xF4,0x8B,0x9C,0x41,0x4A,0x17,0xD6,0x37,
3018 0xB7,0xA5,0x06,0x47,0xE9,0xBC,0x75,0x23,0x22,0x72,0x7F,0xCC,0x17,0x42,0xA9,0x11
3020 static const UInt8 kSC_G2
[kSecPolicySHA256Size
] = {
3021 0xC7,0xBA,0x65,0x67,0xDE,0x93,0xA7,0x98,0xAE,0x1F,0xAA,0x79,0x1E,0x71,0x2D,0x37,
3022 0x8F,0xAE,0x1F,0x93,0xC4,0x39,0x7F,0xEA,0x44,0x1B,0xB7,0xCB,0xE6,0xFD,0x59,0x95
3025 static void SecPVCCheckIssuerDateConstraints(SecPVCRef pvc
) {
3026 static CFSetRef sConstrainedRoots
= NULL
;
3027 static dispatch_once_t _t
;
3028 dispatch_once(&_t
, ^{
3029 const UInt8
*v_hashes
[] = {
3030 kWS_CA1_G2
, kWS_CA1_NEW
, kWS_CA2_NEW
, kWS_ECC
,
3031 kSC_SFSCA
, kSC_SHA2
, kSC_G2
, kTestDateConstraintsRoot
3033 CFMutableSetRef set
= CFSetCreateMutable(NULL
, 0, &kCFTypeSetCallBacks
);
3034 CFIndex ix
, count
= sizeof(v_hashes
)/sizeof(*v_hashes
);
3035 for (ix
=0; ix
<count
; ix
++) {
3036 CFDataRef hash
= CFDataCreateWithBytesNoCopy(NULL
, v_hashes
[ix
],
3037 kSecPolicySHA256Size
, kCFAllocatorNull
);
3039 CFSetAddValue(set
, hash
);
3043 sConstrainedRoots
= set
;
3046 bool shouldDeny
= false;
3047 CFIndex certIX
, certCount
= SecPVCGetCertificateCount(pvc
);
3048 for (certIX
= certCount
- 1; certIX
>= 0 && !shouldDeny
; certIX
--) {
3049 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, certIX
);
3050 CFDataRef sha256
= SecCertificateCopySHA256Digest(cert
);
3051 if (sha256
&& CFSetContainsValue(sConstrainedRoots
, sha256
)) {
3052 /* matched a constrained root; check notBefore dates on all its children. */
3053 CFIndex childIX
= certIX
;
3054 while (--childIX
>= 0) {
3055 SecCertificateRef child
= SecPVCGetCertificateAtIndex(pvc
, childIX
);
3056 /* 1 Dec 2016 00:00:00 GMT */
3057 if (child
&& (CFAbsoluteTime
)502243200.0 <= SecCertificateNotValidBefore(child
)) {
3058 SecPVCSetResultForced(pvc
, kSecPolicyCheckBlackListedKey
, certIX
, kCFBooleanFalse
, true);
3064 CFReleaseNull(sha256
);
3068 static bool SecPVCIsSSLServerAuthenticationPolicy(SecPVCRef pvc
) {
3069 if (!pvc
|| !pvc
->policies
) {
3072 SecPolicyRef policy
= (SecPolicyRef
)CFArrayGetValueAtIndex(pvc
->policies
, 0);
3076 CFStringRef policyName
= SecPolicyGetName(policy
);
3077 if (CFEqualSafe(policyName
, kSecPolicyNameSSLServer
)) {
3080 CFDictionaryRef options
= policy
->_options
;
3081 if (options
&& CFDictionaryGetValue(options
, kSecPolicyCheckSSLHostname
)) {
3088 1. SecPVCCheckRequireCTConstraints must be called after SecPolicyCheckCT,
3089 so earliest issuance time has already been obtained from SCTs.
3090 2. If the issuance time value is 0 (i.e. 2001-01-01) or earlier, we
3091 assume it was not set, and thus we did not have CT info.
3093 static void SecPVCCheckRequireCTConstraints(SecPVCRef pvc
) {
3094 SecCertificatePathVCRef path
= (pvc
) ? SecPathBuilderGetPath(pvc
->builder
) : NULL
;
3098 /* If we are evaluating for a SSL server authentication policy, make sure
3099 SCT issuance time is prior to the earliest not-after date constraint.
3100 Note that CT will already be required if there is a not-after date
3101 constraint present (set in SecRVCProcessValidDateConstraints).
3103 if (SecPVCIsSSLServerAuthenticationPolicy(pvc
)) {
3104 CFIndex ix
, certCount
= SecCertificatePathVCGetCount(path
);
3105 SecCertificateRef certificate
= SecPathBuilderGetCertificateAtIndex(pvc
->builder
, 0);
3106 CFAbsoluteTime earliestNotAfter
= 31556908800.0; /* default: 3001-01-01 00:00:00-0000 */
3107 CFAbsoluteTime issuanceTime
= SecCertificatePathVCIssuanceTime(path
);
3108 if (issuanceTime
<= 0) {
3109 /* if not set (or prior to 2001-01-01), use leaf's not-before time. */
3110 issuanceTime
= SecCertificateNotValidBefore(certificate
);
3112 for (ix
= 0; ix
< certCount
; ix
++) {
3113 SecRVCRef rvc
= SecCertificatePathVCGetRVCAtIndex(path
, ix
);
3114 if (!rvc
|| !rvc
->valid_info
|| !rvc
->valid_info
->hasDateConstraints
|| !rvc
->valid_info
->notAfterDate
) {
3117 /* Found CA certificate with a not-after date constraint. */
3118 CFAbsoluteTime caNotAfter
= CFDateGetAbsoluteTime(rvc
->valid_info
->notAfterDate
);
3119 if (caNotAfter
< earliestNotAfter
) {
3120 earliestNotAfter
= caNotAfter
;
3122 if (issuanceTime
> earliestNotAfter
) {
3123 /* Issuance time violates the not-after date constraint. */
3124 secnotice("rvc", "certificate issuance time (%f) is later than allowed value (%f)",
3125 issuanceTime
, earliestNotAfter
);
3126 SecRVCSetValidDeterminedErrorResult(rvc
);
3131 /* If path is CT validated, nothing further to do here. */
3132 if (SecCertificatePathVCIsCT(path
)) {
3136 /* Path is not CT validated, so check if CT was required. */
3137 SecPathCTPolicy ctp
= SecCertificatePathVCRequiresCT(path
);
3138 if (ctp
<= kSecPathCTNotRequired
|| !SecPVCIsSSLServerAuthenticationPolicy(pvc
)) {
3141 /* CT was required. Error is always set on leaf certificate. */
3142 SecPVCSetResultForced(pvc
, kSecPolicyCheckCTRequired
,
3143 0, kCFBooleanFalse
, true);
3144 if (ctp
!= kSecPathCTRequiredOverridable
) {
3145 /* Normally kSecPolicyCheckCTRequired is recoverable,
3146 so need to manually change trust result here. */
3147 pvc
->result
= kSecTrustResultFatalTrustFailure
;
3151 /* AUDIT[securityd](done):
3152 policy->_options is a caller provided dictionary, only its cf type has
3155 void SecPVCPathChecks(SecPVCRef pvc
) {
3156 secdebug("policy", "begin path: %@", SecPathBuilderGetPath(pvc
->builder
));
3157 SecCertificatePathVCRef path
= SecPathBuilderGetPath(pvc
->builder
);
3158 /* This needs to be initialized before we call any function that might call
3159 SecPVCSetResultForced(). */
3161 SecPolicyCheckIdLinkage(pvc
, kSecPolicyCheckIdLinkage
);
3162 if (SecPVCIsOkResult(pvc
) || pvc
->details
) {
3163 SecPolicyCheckBasicCertificateProcessing(pvc
,
3164 kSecPolicyCheckBasicCertificateProcessing
);
3167 CFArrayRef policies
= pvc
->policies
;
3168 CFIndex count
= CFArrayGetCount(policies
);
3169 for (; pvc
->policyIX
< count
; ++pvc
->policyIX
) {
3170 /* Validate all keys for all policies. */
3171 pvc
->callbacks
= gSecPolicyPathCallbacks
;
3172 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
3173 CFDictionaryApplyFunction(policy
->_options
, SecPVCValidateKey
, pvc
);
3174 if (!SecPVCIsOkResult(pvc
) && !pvc
->details
)
3181 /* Check whether the TrustSettings say to deny a cert in the path. */
3182 SecPVCCheckUsageConstraints(pvc
);
3184 /* Check for Blocklisted certs */
3185 SecPVCCheckIssuerDateConstraints(pvc
);
3187 count
= SecCertificatePathVCGetCount(path
);
3188 for (ix
= 1; ix
< count
; ix
++) {
3189 SecPVCGrayListedKeyChecks(pvc
, ix
);
3190 SecPVCBlackListedKeyChecks(pvc
, ix
);
3193 /* Path-based check tests. */
3194 if (!SecCertificatePathVCIsPathValidated(path
)) {
3195 bool ev_check_ok
= false;
3196 if (SecCertificatePathVCIsOptionallyEV(path
)) {
3197 SecTrustResultType pre_ev_check_result
= pvc
->result
;
3198 SecPolicyCheckEV(pvc
, kSecPolicyCheckExtendedValidation
);
3199 ev_check_ok
= SecPVCIsOkResult(pvc
);
3200 /* If ev checking failed, we still want to accept this chain
3201 as a non EV one, if it was valid as such. */
3202 pvc
->result
= pre_ev_check_result
;
3206 /* This call will set the value of pvc->is_ct, but won't change the result (pvc->result) */
3207 SecPolicyCheckCT(pvc
);
3209 /* Certs are only EV if they are also CT verified */
3210 if (ev_check_ok
&& SecCertificatePathVCIsCT(path
)) {
3211 SecCertificatePathVCSetIsEV(path
, true);
3215 /* Check that this path meets CT constraints. */
3216 SecPVCCheckRequireCTConstraints(pvc
);
3218 /* Check that this path meets known-intermediate constraints. */
3219 SecPathBuilderCheckKnownIntermediateConstraints(pvc
->builder
);
3221 secdebug("policy", "end %strusted path: %@",
3222 (SecPVCIsOkResult(pvc
) ? "" : "not "), SecPathBuilderGetPath(pvc
->builder
));
3224 SecCertificatePathVCSetPathValidated(SecPathBuilderGetPath(pvc
->builder
));
3228 void SecPVCPathCheckRevocationResponsesReceived(SecPVCRef pvc
) {
3230 /* Since we don't currently allow networking on watchOS,
3231 * don't enforce the revocation-required check here. (32728029) */
3232 bool required
= false;
3234 bool required
= true;
3236 SecCertificatePathVCRef path
= SecPathBuilderGetPath(pvc
->builder
);
3237 CFIndex ix
, certCount
= SecCertificatePathVCGetCount(path
);
3238 for (ix
= 0; ix
< certCount
; ix
++) {
3239 SecRVCRef rvc
= SecCertificatePathVCGetRVCAtIndex(path
, ix
);
3240 /* Do we have a valid revocation response? */
3241 if (SecRVCGetEarliestNextUpdate(rvc
) == NULL_TIME
) {
3242 /* No valid revocation response.
3243 * Do we require revocation (for that cert per the
3244 * SecCertificateVCRef, or per the pvc)? */
3245 if (required
&& (SecCertificatePathVCIsRevocationRequiredForCertificateAtIndex(path
, ix
) ||
3246 ((ix
== 0) && pvc
->require_revocation_response
))) {
3247 SecPVCSetResultForced(pvc
, kSecPolicyCheckRevocationResponseRequired
,
3248 ix
, kCFBooleanFalse
, true);
3250 /* Do we have a definitive Valid revocation result for this cert? */
3251 if (SecRVCHasDefinitiveValidInfo(rvc
) && SecRVCHasRevokedValidInfo(rvc
)) {
3252 SecRVCSetValidDeterminedErrorResult(rvc
);