2 * Copyright (c) 2008-2017 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
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/asynchttp.h>
33 #include <securityd/policytree.h>
34 #include <securityd/nameconstraints.h>
35 #include <CoreFoundation/CFTimeZone.h>
37 #include <libDER/oidsPriv.h>
38 #include <CoreFoundation/CFNumber.h>
39 #include <Security/SecCertificateInternal.h>
40 #include <AssertMacros.h>
41 #include <utilities/debugging.h>
42 #include <utilities/SecInternalReleasePriv.h>
43 #include <security_asn1/SecAsn1Coder.h>
44 #include <security_asn1/ocspTemplates.h>
45 #include <security_asn1/oidsalg.h>
46 #include <security_asn1/oidsocsp.h>
47 #include <CommonCrypto/CommonDigest.h>
48 #include <Security/SecFramework.h>
49 #include <Security/SecPolicyInternal.h>
50 #include <Security/SecTrustPriv.h>
51 #include <Security/SecTrustInternal.h>
52 #include <Security/SecTrustSettingsPriv.h>
53 #include <Security/SecInternal.h>
54 #include <Security/SecKeyPriv.h>
55 #include <Security/SecTask.h>
56 #include <CFNetwork/CFHTTPMessage.h>
57 #include <CFNetwork/CFHTTPStream.h>
58 #include <SystemConfiguration/SCDynamicStoreCopySpecific.h>
60 #include <securityd/SecTrustServer.h>
61 #include <securityd/SecTrustLoggingServer.h>
62 #include <securityd/SecRevocationServer.h>
63 #include <securityd/SecCertificateServer.h>
64 #include <securityd/SecCertificateSource.h>
65 #include <securityd/SecOCSPResponse.h>
66 #include <utilities/array_size.h>
67 #include <utilities/SecCFWrappers.h>
68 #include <utilities/SecAppleAnchorPriv.h>
69 #include "OTATrustUtilities.h"
70 #include "personalization.h"
71 #include <sys/codesign.h>
74 #include <Security/SecTaskPriv.h>
77 /* Set this to 1 to dump the ocsp responses received in DER form in /tmp. */
78 #ifndef DUMP_OCSPRESPONSES
79 #define DUMP_OCSPRESPONSES 0
82 #if DUMP_OCSPRESPONSES
87 static void secdumpdata(CFDataRef data
, const char *name
) {
88 int fd
= open(name
, O_CREAT
| O_WRONLY
| O_TRUNC
, 0666);
89 write(fd
, CFDataGetBytePtr(data
), CFDataGetLength(data
));
96 /********************************************************
97 ****************** SecPolicy object ********************
98 ********************************************************/
100 static SecCertificateRef
SecPVCGetCertificateAtIndex(SecPVCRef pvc
, CFIndex ix
);
101 static CFIndex
SecPVCGetCertificateCount(SecPVCRef pvc
);
102 static CFAbsoluteTime
SecPVCGetVerifyTime(SecPVCRef pvc
);
104 static CFMutableDictionaryRef gSecPolicyLeafCallbacks
= NULL
;
105 static CFMutableDictionaryRef gSecPolicyPathCallbacks
= NULL
;
107 static CFArrayRef
SecPolicyAnchorDigestsForEVPolicy(const DERItem
*policyOID
)
109 CFArrayRef result
= NULL
;
110 SecOTAPKIRef otapkiRef
= SecOTAPKICopyCurrentOTAPKIRef();
111 if (NULL
== otapkiRef
)
116 CFDictionaryRef evToPolicyAnchorDigest
= SecOTAPKICopyEVPolicyToAnchorMapping(otapkiRef
);
117 CFRelease(otapkiRef
);
119 if (NULL
== evToPolicyAnchorDigest
)
124 CFArrayRef roots
= NULL
;
125 CFStringRef oid
= SecDERItemCopyOIDDecimalRepresentation(kCFAllocatorDefault
, policyOID
);
126 if (oid
&& evToPolicyAnchorDigest
)
128 result
= (CFArrayRef
)CFDictionaryGetValue(evToPolicyAnchorDigest
, oid
);
129 if (roots
&& CFGetTypeID(result
) != CFArrayGetTypeID())
131 secerror("EVRoot.plist has non array value");
136 CFReleaseSafe(evToPolicyAnchorDigest
);
141 bool SecPolicyIsEVPolicy(const DERItem
*policyOID
) {
142 return SecPolicyAnchorDigestsForEVPolicy(policyOID
);
145 static bool SecPolicyRootCACertificateIsEV(SecCertificateRef certificate
,
146 policy_set_t valid_policies
) {
147 CFDictionaryRef keySizes
= NULL
;
148 CFNumberRef rsaSize
= NULL
, ecSize
= NULL
;
150 /* Ensure that this certificate is a valid anchor for one of the
151 certificate policy oids specified in the leaf. */
152 CFDataRef digest
= SecCertificateGetSHA1Digest(certificate
);
154 bool good_ev_anchor
= false;
155 for (ix
= valid_policies
; ix
; ix
= ix
->oid_next
) {
156 CFArrayRef digests
= SecPolicyAnchorDigestsForEVPolicy(&ix
->oid
);
157 if (digests
&& CFArrayContainsValue(digests
,
158 CFRangeMake(0, CFArrayGetCount(digests
)), digest
)) {
159 secdebug("ev", "found anchor for policy oid");
160 good_ev_anchor
= true;
164 require_action_quiet(good_ev_anchor
, notEV
, secnotice("ev", "anchor not in plist"));
166 CFAbsoluteTime october2006
= 178761600;
167 if (SecCertificateNotValidBefore(certificate
) >= october2006
) {
168 require_action_quiet(SecCertificateVersion(certificate
) >= 3, notEV
,
169 secnotice("ev", "Anchor issued after October 2006 and is not v3"));
171 if (SecCertificateVersion(certificate
) >= 3
172 && SecCertificateNotValidBefore(certificate
) >= october2006
) {
173 const SecCEBasicConstraints
*bc
= SecCertificateGetBasicConstraints(certificate
);
174 require_action_quiet(bc
&& bc
->isCA
== true, notEV
,
175 secnotice("ev", "Anchor has invalid basic constraints"));
176 SecKeyUsage ku
= SecCertificateGetKeyUsage(certificate
);
177 require_action_quiet((ku
& (kSecKeyUsageKeyCertSign
| kSecKeyUsageCRLSign
))
178 == (kSecKeyUsageKeyCertSign
| kSecKeyUsageCRLSign
), notEV
,
179 secnotice("ev", "Anchor has invalid key usage %u", ku
));
182 /* At least RSA 2048 or ECC NIST P-256. */
183 require_quiet(rsaSize
= CFNumberCreateWithCFIndex(NULL
, 2048), notEV
);
184 require_quiet(ecSize
= CFNumberCreateWithCFIndex(NULL
, 256), notEV
);
185 const void *keys
[] = { kSecAttrKeyTypeRSA
, kSecAttrKeyTypeEC
};
186 const void *values
[] = { rsaSize
, ecSize
};
187 require_quiet(keySizes
= CFDictionaryCreate(NULL
, keys
, values
, 2,
188 &kCFTypeDictionaryKeyCallBacks
,
189 &kCFTypeDictionaryValueCallBacks
), notEV
);
190 require_action_quiet(SecCertificateIsAtLeastMinKeySize(certificate
, keySizes
), notEV
,
191 secnotice("ev", "Anchor's public key is too weak for EV"));
196 CFReleaseNull(rsaSize
);
197 CFReleaseNull(ecSize
);
198 CFReleaseNull(keySizes
);
202 static bool SecPolicySubordinateCACertificateCouldBeEV(SecCertificateRef certificate
) {
203 CFMutableDictionaryRef keySizes
= NULL
;
204 CFNumberRef rsaSize
= NULL
, ecSize
= NULL
;
207 const SecCECertificatePolicies
*cp
;
208 cp
= SecCertificateGetCertificatePolicies(certificate
);
209 require_action_quiet(cp
&& cp
->numPolicies
> 0, notEV
,
210 secnotice("ev", "SubCA missing certificate policies"));
211 CFArrayRef cdp
= SecCertificateGetCRLDistributionPoints(certificate
);
212 require_action_quiet(cdp
&& CFArrayGetCount(cdp
) > 0, notEV
,
213 secnotice("ev", "SubCA missing CRLDP"));
214 const SecCEBasicConstraints
*bc
= SecCertificateGetBasicConstraints(certificate
);
215 require_action_quiet(bc
&& bc
->isCA
== true, notEV
,
216 secnotice("ev", "SubCA has invalid basic constraints"));
217 SecKeyUsage ku
= SecCertificateGetKeyUsage(certificate
);
218 require_action_quiet((ku
& (kSecKeyUsageKeyCertSign
| kSecKeyUsageCRLSign
))
219 == (kSecKeyUsageKeyCertSign
| kSecKeyUsageCRLSign
), notEV
,
220 secnotice("ev", "SubCA has invalid key usage %u", ku
));
222 /* 6.1.5 Key Sizes */
223 CFAbsoluteTime jan2011
= 315532800;
224 CFAbsoluteTime jan2014
= 410227200;
225 require_quiet(ecSize
= CFNumberCreateWithCFIndex(NULL
, 256), notEV
);
226 require_quiet(keySizes
= CFDictionaryCreateMutable(NULL
, 2, &kCFTypeDictionaryKeyCallBacks
,
227 &kCFTypeDictionaryValueCallBacks
), notEV
);
228 CFDictionaryAddValue(keySizes
, kSecAttrKeyTypeEC
, ecSize
);
229 if (SecCertificateNotValidBefore(certificate
) < jan2011
||
230 SecCertificateNotValidAfter(certificate
) < jan2014
) {
231 /* At least RSA 1024 or ECC NIST P-256. */
232 require_quiet(rsaSize
= CFNumberCreateWithCFIndex(NULL
, 1024), notEV
);
233 CFDictionaryAddValue(keySizes
, kSecAttrKeyTypeRSA
, rsaSize
);
234 require_action_quiet(SecCertificateIsAtLeastMinKeySize(certificate
, keySizes
), notEV
,
235 secnotice("ev", "SubCA's public key is too small for issuance before 2011 or expiration before 2014"));
237 /* At least RSA 2028 or ECC NIST P-256. */
238 require_quiet(rsaSize
= CFNumberCreateWithCFIndex(NULL
, 2048), notEV
);
239 CFDictionaryAddValue(keySizes
, kSecAttrKeyTypeRSA
, rsaSize
);
240 require_action_quiet(SecCertificateIsAtLeastMinKeySize(certificate
, keySizes
), notEV
,
241 secnotice("ev", "SubCA's public key is too small for issuance after 2010 or expiration after 2013"));
244 /* 7.1.3 Algorithm Object Identifiers */
245 CFAbsoluteTime jan2016
= 473299200;
246 if (SecCertificateNotValidBefore(certificate
) > jan2016
) {
248 require_action_quiet(SecCertificateGetSignatureHashAlgorithm(certificate
) > kSecSignatureHashAlgorithmSHA1
,
249 notEV
, secnotice("ev", "SubCA was issued with SHA-1 after 2015"));
255 CFReleaseNull(rsaSize
);
256 CFReleaseNull(ecSize
);
257 CFReleaseNull(keySizes
);
261 /********************************************************
262 **************** SecPolicy Callbacks *******************
263 ********************************************************/
264 static void SecPolicyCheckCriticalExtensions(SecPVCRef pvc
,
268 static void SecPolicyCheckIdLinkage(SecPVCRef pvc
,
270 CFIndex ix
, count
= SecPVCGetCertificateCount(pvc
);
271 CFDataRef parentSubjectKeyID
= NULL
;
272 for (ix
= count
- 1; ix
>= 0; --ix
) {
273 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, ix
);
274 /* If the previous certificate in the chain had a SubjectKeyID,
275 make sure it matches the current certificates AuthorityKeyID. */
276 if (parentSubjectKeyID
) {
277 /* @@@ According to RFC 2459 neither AuthorityKeyID nor
278 SubjectKeyID can be critical. Currenty we don't check
280 CFDataRef authorityKeyID
= SecCertificateGetAuthorityKeyID(cert
);
281 if (authorityKeyID
) {
282 if (!CFEqual(parentSubjectKeyID
, authorityKeyID
)) {
283 /* AuthorityKeyID doesn't match issuers SubjectKeyID. */
284 if (!SecPVCSetResult(pvc
, key
, ix
, kCFBooleanFalse
))
290 parentSubjectKeyID
= SecCertificateGetSubjectKeyID(cert
);
294 static void SecPolicyCheckKeyUsage(SecPVCRef pvc
,
296 SecCertificateRef leaf
= SecPVCGetCertificateAtIndex(pvc
, 0);
297 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
298 CFTypeRef xku
= CFDictionaryGetValue(policy
->_options
, key
);
299 if (!SecPolicyCheckCertKeyUsage(leaf
, xku
)) {
300 SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
);
304 /* AUDIT[securityd](done):
305 policy->_options is a caller provided dictionary, only its cf type has
308 static void SecPolicyCheckExtendedKeyUsage(SecPVCRef pvc
, CFStringRef key
) {
309 SecCertificateRef leaf
= SecPVCGetCertificateAtIndex(pvc
, 0);
310 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
311 CFTypeRef xeku
= CFDictionaryGetValue(policy
->_options
, key
);
312 if (!SecPolicyCheckCertExtendedKeyUsage(leaf
, xeku
)){
313 SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
);
318 static void SecPolicyCheckBasicContraintsCommon(SecPVCRef pvc
,
319 CFStringRef key
, bool strict
) {
320 CFIndex ix
, count
= SecPVCGetCertificateCount(pvc
);
321 for (ix
= 0; ix
< count
; ++ix
) {
322 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, ix
);
323 const SecCEBasicConstraints
*bc
=
324 SecCertificateGetBasicConstraints(cert
);
328 /* Leaf certificate has basic constraints extension. */
329 if (!SecPVCSetResult(pvc
, key
, ix
, kCFBooleanFalse
))
331 } else if (!bc
->critical
) {
332 /* Basic constraints extension is not marked critical. */
333 if (!SecPVCSetResult(pvc
, key
, ix
, kCFBooleanFalse
))
338 if (ix
> 0 || count
== 1) {
340 /* Non leaf certificate marked as isCA false. */
341 if (!SecPVCSetResult(pvc
, key
, ix
, kCFBooleanFalse
))
345 if (bc
->pathLenConstraintPresent
) {
346 if (bc
->pathLenConstraint
< (uint32_t)(ix
- 1)) {
348 /* @@@ If a self signed certificate is issued by
349 another cert that is trusted, then we are supposed
350 to treat the self signed cert itself as the anchor
351 for path length purposes. */
352 CFIndex ssix
= SecCertificatePathSelfSignedIndex(path
);
353 if (ssix
>= 0 && ix
>= ssix
) {
354 /* It's ok if the pathLenConstraint isn't met for
355 certificates signing a self signed cert in the
360 /* Path Length Constraint Exceeded. */
361 if (!SecPVCSetResult(pvc
, key
, ix
,
368 } else if (strict
&& ix
> 0) {
369 /* In strict mode all CA certificates *MUST* have a critical
370 basic constraints extension and the leaf certificate
371 *MUST NOT* have a basic constraints extension. */
372 /* CA certificate is missing basicConstraints extension. */
373 if (!SecPVCSetResult(pvc
, key
, ix
, kCFBooleanFalse
))
380 static void SecPolicyCheckBasicConstraints(SecPVCRef pvc
,
382 //SecPolicyCheckBasicContraintsCommon(pvc, key, false);
385 static void SecPolicyCheckNonEmptySubject(SecPVCRef pvc
,
387 CFIndex ix
, count
= SecPVCGetCertificateCount(pvc
);
388 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
389 CFTypeRef pvcValue
= CFDictionaryGetValue(policy
->_options
, key
);
390 for (ix
= 0; ix
< count
; ++ix
) {
391 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, ix
);
392 if (!SecPolicyCheckCertNonEmptySubject(cert
, pvcValue
)) {
393 if (!SecPVCSetResult(pvc
, key
, ix
, kCFBooleanFalse
))
399 static void SecPolicyCheckQualifiedCertStatements(SecPVCRef pvc
,
403 /* AUDIT[securityd](done):
404 policy->_options is a caller provided dictionary, only its cf type has
407 static void SecPolicyCheckSSLHostname(SecPVCRef pvc
,
409 /* @@@ Consider what to do if the caller passes in no hostname. Should
410 we then still fail if the leaf has no dnsNames or IPAddresses at all? */
411 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
412 CFStringRef hostName
= (CFStringRef
)
413 CFDictionaryGetValue(policy
->_options
, key
);
414 if (!isString(hostName
)) {
415 /* @@@ We can't return an error here and making the evaluation fail
416 won't help much either. */
420 SecCertificateRef leaf
= SecPVCGetCertificateAtIndex(pvc
, 0);
421 bool dnsMatch
= SecPolicyCheckCertSSLHostname(leaf
, hostName
);
424 /* Hostname mismatch or no hostnames found in certificate. */
425 SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
);
430 /* AUDIT[securityd](done):
431 policy->_options is a caller provided dictionary, only its cf type has
434 static void SecPolicyCheckEmail(SecPVCRef pvc
, CFStringRef key
) {
435 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
436 CFStringRef email
= (CFStringRef
)CFDictionaryGetValue(policy
->_options
, key
);
437 if (!isString(email
)) {
438 /* We can't return an error here and making the evaluation fail
439 won't help much either. */
443 SecCertificateRef leaf
= SecPVCGetCertificateAtIndex(pvc
, 0);
445 if (!SecPolicyCheckCertEmail(leaf
, email
)) {
446 /* Hostname mismatch or no hostnames found in certificate. */
447 SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
);
451 static void SecPolicyCheckValidIntermediates(SecPVCRef pvc
,
453 CFIndex ix
, count
= SecPVCGetCertificateCount(pvc
);
454 CFAbsoluteTime verifyTime
= SecPVCGetVerifyTime(pvc
);
455 for (ix
= 1; ix
< count
- 1; ++ix
) {
456 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, ix
);
457 if (!SecCertificateIsValid(cert
, verifyTime
)) {
458 /* Intermediate certificate has expired. */
459 if (!SecPVCSetResult(pvc
, key
, ix
, kCFBooleanFalse
))
465 static void SecPolicyCheckValidLeaf(SecPVCRef pvc
,
467 CFAbsoluteTime verifyTime
= SecPVCGetVerifyTime(pvc
);
468 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, 0);
469 if (!SecCertificateIsValid(cert
, verifyTime
)) {
470 /* Leaf certificate has expired. */
471 if (!SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
))
476 static void SecPolicyCheckValidRoot(SecPVCRef pvc
,
478 CFIndex ix
, count
= SecPVCGetCertificateCount(pvc
);
479 CFAbsoluteTime verifyTime
= SecPVCGetVerifyTime(pvc
);
481 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, ix
);
482 if (!SecCertificateIsValid(cert
, verifyTime
)) {
483 /* Root certificate has expired. */
484 if (!SecPVCSetResult(pvc
, key
, ix
, kCFBooleanFalse
))
489 /* AUDIT[securityd](done):
490 policy->_options is a caller provided dictionary, only its cf type has
493 static void SecPolicyCheckIssuerCommonName(SecPVCRef pvc
,
495 CFIndex count
= SecPVCGetCertificateCount(pvc
);
497 /* Can't check intermediates common name if there is no intermediate. */
498 SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
);
502 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, 1);
503 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
504 CFStringRef commonName
=
505 (CFStringRef
)CFDictionaryGetValue(policy
->_options
, key
);
506 if (!isString(commonName
)) {
507 /* @@@ We can't return an error here and making the evaluation fail
508 won't help much either. */
511 if (!SecPolicyCheckCertSubjectCommonName(cert
, commonName
)) {
512 SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
);
516 /* AUDIT[securityd](done):
517 policy->_options is a caller provided dictionary, only its cf type has
520 static void SecPolicyCheckSubjectCommonName(SecPVCRef pvc
,
522 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, 0);
523 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
524 CFStringRef common_name
= (CFStringRef
)CFDictionaryGetValue(policy
->_options
,
526 if (!isString(common_name
)) {
527 /* @@@ We can't return an error here and making the evaluation fail
528 won't help much either. */
531 if (!SecPolicyCheckCertSubjectCommonName(cert
, common_name
)) {
532 SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
);
536 /* AUDIT[securityd](done):
537 policy->_options is a caller provided dictionary, only its cf type has
540 static void SecPolicyCheckSubjectCommonNamePrefix(SecPVCRef pvc
,
542 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, 0);
543 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
544 CFStringRef prefix
= (CFStringRef
)CFDictionaryGetValue(policy
->_options
,
546 if (!isString(prefix
)) {
547 /* @@@ We can't return an error here and making the evaluation fail
548 won't help much either. */
551 if (!SecPolicyCheckCertSubjectCommonNamePrefix(cert
, prefix
)) {
552 SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
);
556 /* AUDIT[securityd](done):
557 policy->_options is a caller provided dictionary, only its cf type has
560 static void SecPolicyCheckSubjectCommonNameTEST(SecPVCRef pvc
,
562 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, 0);
563 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
564 CFStringRef common_name
= (CFStringRef
)CFDictionaryGetValue(policy
->_options
,
566 if (!isString(common_name
)) {
567 /* @@@ We can't return an error here and making the evaluation fail
568 won't help much either. */
571 if (!SecPolicyCheckCertSubjectCommonNameTEST(cert
, common_name
)) {
572 SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
);
576 /* AUDIT[securityd](done):
577 policy->_options is a caller provided dictionary, only its cf type has
580 static void SecPolicyCheckNotValidBefore(SecPVCRef pvc
,
582 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, 0);
583 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
584 CFDateRef date
= (CFDateRef
)CFDictionaryGetValue(policy
->_options
, key
);
586 /* @@@ We can't return an error here and making the evaluation fail
587 won't help much either. */
590 if (!SecPolicyCheckCertNotValidBefore(cert
, date
)) {
591 if (!SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
))
596 /* AUDIT[securityd](done):
597 policy->_options is a caller provided dictionary, only its cf type has
600 static void SecPolicyCheckChainLength(SecPVCRef pvc
,
602 CFIndex count
= SecPVCGetCertificateCount(pvc
);
603 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
604 CFNumberRef chainLength
=
605 (CFNumberRef
)CFDictionaryGetValue(policy
->_options
, key
);
607 if (!chainLength
|| CFGetTypeID(chainLength
) != CFNumberGetTypeID() ||
608 !CFNumberGetValue(chainLength
, kCFNumberCFIndexType
, &value
)) {
609 /* @@@ We can't return an error here and making the evaluation fail
610 won't help much either. */
613 if (value
!= count
) {
614 /* Chain length doesn't match policy requirement. */
615 if (!SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
))
620 static bool isDigestInPolicy(SecPVCRef pvc
, CFStringRef key
, CFDataRef digest
) {
621 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
622 CFTypeRef value
= CFDictionaryGetValue(policy
->_options
, key
);
624 bool foundMatch
= false;
626 foundMatch
= CFEqual(digest
, value
);
627 else if (isArray(value
))
628 foundMatch
= CFArrayContainsValue((CFArrayRef
) value
, CFRangeMake(0, CFArrayGetCount((CFArrayRef
) value
)), digest
);
630 /* @@@ We only support Data and Array but we can't return an error here so.
631 we let the evaluation fail (not much help) and assert in debug. */
638 static void SecPolicyCheckAnchorSHA256(SecPVCRef pvc
, CFStringRef key
) {
639 CFIndex count
= SecPVCGetCertificateCount(pvc
);
640 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, count
- 1);
641 CFDataRef anchorSHA256
= NULL
;
642 anchorSHA256
= SecCertificateCopySHA256Digest(cert
);
644 if (!isDigestInPolicy(pvc
, key
, anchorSHA256
)) {
645 SecPVCSetResult(pvc
, kSecPolicyCheckAnchorSHA256
, count
-1, kCFBooleanFalse
);
648 CFReleaseNull(anchorSHA256
);
653 /* AUDIT[securityd](done):
654 policy->_options is a caller provided dictionary, only its cf type has
657 static void SecPolicyCheckAnchorSHA1(SecPVCRef pvc
,
659 CFIndex count
= SecPVCGetCertificateCount(pvc
);
660 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, count
- 1);
661 CFDataRef anchorSHA1
= SecCertificateGetSHA1Digest(cert
);
663 if (!isDigestInPolicy(pvc
, key
, anchorSHA1
))
664 if (!SecPVCSetResult(pvc
, kSecPolicyCheckAnchorSHA1
, count
-1, kCFBooleanFalse
))
671 Check the SHA256 of SPKI of the first intermediate CA certificate in the path
672 policy->_options is a caller provided dictionary, only its cf type has
675 static void SecPolicyCheckIntermediateSPKISHA256(SecPVCRef pvc
,
677 SecCertificateRef cert
= NULL
;
678 CFDataRef digest
= NULL
;
680 if (SecPVCGetCertificateCount(pvc
) < 2) {
681 SecPVCSetResult(pvc
, kSecPolicyCheckIntermediateSPKISHA256
, 0, kCFBooleanFalse
);
685 cert
= SecPVCGetCertificateAtIndex(pvc
, 1);
686 digest
= SecCertificateCopySubjectPublicKeyInfoSHA256Digest(cert
);
688 if (!isDigestInPolicy(pvc
, key
, digest
)) {
689 SecPVCSetResult(pvc
, kSecPolicyCheckIntermediateSPKISHA256
, 1, kCFBooleanFalse
);
691 CFReleaseNull(digest
);
695 policy->_options is a caller provided dictionary, only its cf type has
698 static void SecPolicyCheckAnchorApple(SecPVCRef pvc
,
700 CFIndex count
= SecPVCGetCertificateCount(pvc
);
701 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, count
- 1);
702 SecAppleTrustAnchorFlags flags
= 0;
705 bool foundMatch
= SecIsAppleTrustAnchor(cert
, flags
);
708 if (!SecPVCSetResult(pvc
, kSecPolicyCheckAnchorApple
, 0, kCFBooleanFalse
))
715 /* AUDIT[securityd](done):
716 policy->_options is a caller provided dictionary, only its cf type has
719 static void SecPolicyCheckSubjectOrganization(SecPVCRef pvc
,
721 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, 0);
722 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
723 CFStringRef org
= (CFStringRef
)CFDictionaryGetValue(policy
->_options
,
725 if (!isString(org
)) {
726 /* @@@ We can't return an error here and making the evaluation fail
727 won't help much either. */
730 if (!SecPolicyCheckCertSubjectOrganization(cert
, org
)) {
731 /* Leaf Subject Organization mismatch. */
732 SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
);
736 static void SecPolicyCheckSubjectOrganizationalUnit(SecPVCRef pvc
,
738 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, 0);
739 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
740 CFStringRef orgUnit
= (CFStringRef
)CFDictionaryGetValue(policy
->_options
,
742 if (!isString(orgUnit
)) {
743 /* @@@ We can't return an error here and making the evaluation fail
744 won't help much either. */
747 if (!SecPolicyCheckCertSubjectOrganizationalUnit(cert
, orgUnit
)) {
748 /* Leaf Subject Organization mismatch. */
749 SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
);
753 /* AUDIT[securityd](done):
754 policy->_options is a caller provided dictionary, only its cf type has
757 static void SecPolicyCheckEAPTrustedServerNames(SecPVCRef pvc
,
759 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
760 CFArrayRef trustedServerNames
= (CFArrayRef
)
761 CFDictionaryGetValue(policy
->_options
, key
);
762 /* No names specified means we accept any name. */
763 if (!trustedServerNames
)
765 if (!isArray(trustedServerNames
)) {
766 /* @@@ We can't return an error here and making the evaluation fail
767 won't help much either. */
771 SecCertificateRef leaf
= SecPVCGetCertificateAtIndex(pvc
, 0);
772 if (!SecPolicyCheckCertEAPTrustedServerNames(leaf
, trustedServerNames
)) {
773 /* Hostname mismatch or no hostnames found in certificate. */
774 SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
);
778 static const unsigned char UTN_USERFirst_Hardware_Serial
[][16] = {
779 { 0xd8, 0xf3, 0x5f, 0x4e, 0xb7, 0x87, 0x2b, 0x2d, 0xab, 0x06, 0x92, 0xe3, 0x15, 0x38, 0x2f, 0xb0 },
780 { 0x92, 0x39, 0xd5, 0x34, 0x8f, 0x40, 0xd1, 0x69, 0x5a, 0x74, 0x54, 0x70, 0xe1, 0xf2, 0x3f, 0x43 },
781 { 0xb0, 0xb7, 0x13, 0x3e, 0xd0, 0x96, 0xf9, 0xb5, 0x6f, 0xae, 0x91, 0xc8, 0x74, 0xbd, 0x3a, 0xc0 },
782 { 0xe9, 0x02, 0x8b, 0x95, 0x78, 0xe4, 0x15, 0xdc, 0x1a, 0x71, 0x0a, 0x2b, 0x88, 0x15, 0x44, 0x47 },
783 { 0x39, 0x2a, 0x43, 0x4f, 0x0e, 0x07, 0xdf, 0x1f, 0x8a, 0xa3, 0x05, 0xde, 0x34, 0xe0, 0xc2, 0x29 },
784 { 0x3e, 0x75, 0xce, 0xd4, 0x6b, 0x69, 0x30, 0x21, 0x21, 0x88, 0x30, 0xae, 0x86, 0xa8, 0x2a, 0x71 },
785 { 0xd7, 0x55, 0x8f, 0xda, 0xf5, 0xf1, 0x10, 0x5b, 0xb2, 0x13, 0x28, 0x2b, 0x70, 0x77, 0x29, 0xa3 },
786 { 0x04, 0x7e, 0xcb, 0xe9, 0xfc, 0xa5, 0x5f, 0x7b, 0xd0, 0x9e, 0xae, 0x36, 0xe1, 0x0c, 0xae, 0x1e },
787 { 0xf5, 0xc8, 0x6a, 0xf3, 0x61, 0x62, 0xf1, 0x3a, 0x64, 0xf5, 0x4f, 0x6d, 0xc9, 0x58, 0x7c, 0x06 } };
789 static const unsigned char UTN_USERFirst_Hardware_Normalized_Issuer
[] = {
790 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55,
791 0x53, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x02,
792 0x55, 0x54, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x07, 0x13,
793 0x0e, 0x53, 0x41, 0x4c, 0x54, 0x20, 0x4c, 0x41, 0x4b, 0x45, 0x20, 0x43,
794 0x49, 0x54, 0x59, 0x31, 0x1e, 0x30, 0x1c, 0x06, 0x03, 0x55, 0x04, 0x0a,
795 0x13, 0x15, 0x54, 0x48, 0x45, 0x20, 0x55, 0x53, 0x45, 0x52, 0x54, 0x52,
796 0x55, 0x53, 0x54, 0x20, 0x4e, 0x45, 0x54, 0x57, 0x4f, 0x52, 0x4b, 0x31,
797 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x18, 0x48, 0x54,
798 0x54, 0x50, 0x3a, 0x2f, 0x2f, 0x57, 0x57, 0x57, 0x2e, 0x55, 0x53, 0x45,
799 0x52, 0x54, 0x52, 0x55, 0x53, 0x54, 0x2e, 0x43, 0x4f, 0x4d, 0x31, 0x1f,
800 0x30, 0x1d, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x16, 0x55, 0x54, 0x4e,
801 0x2d, 0x55, 0x53, 0x45, 0x52, 0x46, 0x49, 0x52, 0x53, 0x54, 0x2d, 0x48,
802 0x41, 0x52, 0x44, 0x57, 0x41, 0x52, 0x45
804 static const unsigned int UTN_USERFirst_Hardware_Normalized_Issuer_len
= 151;
807 static void SecPolicyCheckBlackListedLeaf(SecPVCRef pvc
,
809 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, 0);
810 CFDataRef issuer
= cert
? SecCertificateGetNormalizedIssuerContent(cert
) : NULL
;
812 if (issuer
&& (CFDataGetLength(issuer
) == (CFIndex
)UTN_USERFirst_Hardware_Normalized_Issuer_len
) &&
813 (0 == memcmp(UTN_USERFirst_Hardware_Normalized_Issuer
, CFDataGetBytePtr(issuer
),
814 UTN_USERFirst_Hardware_Normalized_Issuer_len
)))
816 #if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE))
817 CFDataRef serial
= SecCertificateCopySerialNumber(cert
, NULL
);
819 CFDataRef serial
= SecCertificateCopySerialNumber(cert
);
823 CFIndex serial_length
= CFDataGetLength(serial
);
824 const uint8_t *serial_ptr
= CFDataGetBytePtr(serial
);
826 while ((serial_length
> 0) && (*serial_ptr
== 0)) {
831 if (serial_length
== (CFIndex
)sizeof(*UTN_USERFirst_Hardware_Serial
)) {
833 for (i
= 0; i
< array_size(UTN_USERFirst_Hardware_Serial
); i
++)
835 if (0 == memcmp(UTN_USERFirst_Hardware_Serial
[i
],
836 serial_ptr
, sizeof(*UTN_USERFirst_Hardware_Serial
)))
838 SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
);
839 pvc
->result
= kSecTrustResultFatalTrustFailure
;
840 CFReleaseSafe(serial
);
849 SecOTAPKIRef otapkiRef
= SecOTAPKICopyCurrentOTAPKIRef();
850 if (NULL
!= otapkiRef
)
852 CFSetRef blackListedKeys
= SecOTAPKICopyBlackListSet(otapkiRef
);
853 CFRelease(otapkiRef
);
854 if (NULL
!= blackListedKeys
)
856 /* Check for blacklisted intermediates keys. */
857 CFDataRef dgst
= SecCertificateCopyPublicKeySHA1Digest(cert
);
860 /* Check dgst against blacklist. */
861 if (CFSetContainsValue(blackListedKeys
, dgst
))
863 SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
);
864 pvc
->result
= kSecTrustResultFatalTrustFailure
;
868 CFRelease(blackListedKeys
);
873 static void SecPolicyCheckGrayListedLeaf(SecPVCRef pvc
, CFStringRef key
)
875 SecOTAPKIRef otapkiRef
= SecOTAPKICopyCurrentOTAPKIRef();
876 if (NULL
!= otapkiRef
)
878 CFSetRef grayListedKeys
= SecOTAPKICopyGrayList(otapkiRef
);
879 CFRelease(otapkiRef
);
880 if (NULL
!= grayListedKeys
)
882 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, 0);
884 CFDataRef dgst
= SecCertificateCopyPublicKeySHA1Digest(cert
);
887 /* Check dgst against gray. */
888 if (CFSetContainsValue(grayListedKeys
, dgst
))
890 SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
);
894 CFRelease(grayListedKeys
);
899 static void SecPolicyCheckLeafMarkerOid(SecPVCRef pvc
, CFStringRef key
)
901 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, 0);
902 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
903 CFTypeRef value
= CFDictionaryGetValue(policy
->_options
, key
);
905 if (!SecPolicyCheckCertLeafMarkerOid(cert
, value
)) {
906 SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
);
910 static void SecPolicyCheckLeafMarkerOidWithoutValueCheck(SecPVCRef pvc
, CFStringRef key
)
912 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, 0);
913 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
914 CFTypeRef value
= CFDictionaryGetValue(policy
->_options
, key
);
916 if (!SecPolicyCheckCertLeafMarkerOidWithoutValueCheck(cert
, value
)) {
917 SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
);
922 * The value is a dictionary. The dictionary contains keys indicating
923 * whether the value is for Prod or QA. The values are the same as
924 * in the options dictionary for SecPolicyCheckLeafMarkerOid.
926 static void SecPolicyCheckLeafMarkersProdAndQA(SecPVCRef pvc
, CFStringRef key
)
928 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, 0);
929 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
930 CFDictionaryRef value
= CFDictionaryGetValue(policy
->_options
, key
);
931 CFTypeRef prodValue
= CFDictionaryGetValue(value
, kSecPolicyLeafMarkerProd
);
933 if (!SecPolicyCheckCertLeafMarkerOid(cert
, prodValue
)) {
936 SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
);
941 static void SecPolicyCheckIntermediateMarkerOid(SecPVCRef pvc
, CFStringRef key
)
943 CFIndex ix
, count
= SecPVCGetCertificateCount(pvc
);
944 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
945 CFTypeRef value
= CFDictionaryGetValue(policy
->_options
, key
);
947 for (ix
= 1; ix
< count
- 1; ix
++) {
948 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, ix
);
949 if (SecCertificateHasMarkerExtension(cert
, value
))
952 SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
);
955 static void SecPolicyCheckIntermediateEKU(SecPVCRef pvc
, CFStringRef key
)
957 CFIndex ix
, count
= SecPVCGetCertificateCount(pvc
);
958 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
959 CFTypeRef peku
= CFDictionaryGetValue(policy
->_options
, key
);
961 for (ix
= 1; ix
< count
- 1; ix
++) {
962 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, ix
);
963 if (!SecPolicyCheckCertExtendedKeyUsage(cert
, peku
)) {
964 SecPVCSetResult(pvc
, key
, ix
, kCFBooleanFalse
);
969 static void SecPolicyCheckIntermediateOrganization(SecPVCRef pvc
, CFStringRef key
)
971 CFIndex ix
, count
= SecPVCGetCertificateCount(pvc
);
972 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
973 CFTypeRef organization
= CFDictionaryGetValue(policy
->_options
, key
);
975 for (ix
= 1; ix
< count
- 1; ix
++) {
976 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, ix
);
977 if (!SecPolicyCheckCertSubjectOrganization(cert
, organization
)) {
978 SecPVCSetResult(pvc
, key
, ix
, kCFBooleanFalse
);
983 static void SecPolicyCheckIntermediateCountry(SecPVCRef pvc
, CFStringRef key
)
985 CFIndex ix
, count
= SecPVCGetCertificateCount(pvc
);
986 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
987 CFTypeRef country
= CFDictionaryGetValue(policy
->_options
, key
);
989 for (ix
= 1; ix
< count
- 1; ix
++) {
990 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, ix
);
991 if (!SecPolicyCheckCertSubjectCountry(cert
, country
)) {
992 SecPVCSetResult(pvc
, key
, ix
, kCFBooleanFalse
);
997 /****************************************************************************
998 *********************** New rfc5280 Chain Validation ***********************
999 ****************************************************************************/
1001 #define POLICY_MAPPING 1
1002 #define POLICY_SUBTREES 1
1004 /* rfc5280 basic cert processing. */
1005 static void SecPolicyCheckBasicCertificateProcessing(SecPVCRef pvc
,
1009 CFIndex count
= SecPVCGetCertificateCount(pvc
);
1010 SecCertificatePathVCRef path
= SecPathBuilderGetPath(pvc
->builder
);
1011 /* 64 bits cast: worst case here is we truncate the number of cert, and the validation may fail */
1012 assert((unsigned long)count
<=UINT32_MAX
); /* Debug check. Correct as long as CFIndex is long */
1013 uint32_t n
= (uint32_t)count
;
1015 bool is_anchored
= SecPathBuilderIsAnchored(pvc
->builder
);
1016 bool is_anchor_trusted
= false;
1018 CFArrayRef constraints
= SecCertificatePathVCGetUsageConstraintsAtIndex(path
, n
- 1);
1019 if (CFArrayGetCount(constraints
) == 0) {
1020 /* Given that the path builder has already indicated the last cert in this chain has
1021 * trust set on it, empty constraints means trusted. */
1022 is_anchor_trusted
= true;
1024 /* Determine whether constraints say to trust this cert for this PVC. */
1025 SecTrustSettingsResult tsResult
= SecPVCGetTrustSettingsResult(pvc
, SecCertificatePathVCGetCertificateAtIndex(path
, n
- 1),
1027 if (tsResult
== kSecTrustSettingsResultTrustRoot
|| tsResult
== kSecTrustSettingsResultTrustAsRoot
) {
1028 is_anchor_trusted
= true;
1033 if (is_anchor_trusted
) {
1034 /* If the anchor is trusted we don't process the last cert in the
1038 /* trust may be restored for a path with an untrusted root that matches the allow list.
1039 (isAllowlisted is set by revocation check, which is performed prior to path checks) */
1040 if (!SecCertificatePathVCIsAllowlisted(path
)) {
1041 /* Add a detail for the root not being trusted. */
1042 if (!SecPVCSetResultForced(pvc
, kSecPolicyCheckAnchorTrusted
,
1043 n
- 1, kCFBooleanFalse
, true)) {
1049 CFAbsoluteTime verify_time
= SecPVCGetVerifyTime(pvc
);
1050 //policy_set_t user_initial_policy_set = NULL;
1051 //trust_anchor_t anchor;
1053 /* Initialization */
1055 CFMutableArrayRef permitted_subtrees
= NULL
;
1056 CFMutableArrayRef excluded_subtrees
= NULL
;
1057 permitted_subtrees
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
);
1058 excluded_subtrees
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
);
1059 require_action_quiet(permitted_subtrees
!= NULL
, errOut
,
1060 SecPVCSetResultForced(pvc
, key
, 0, kCFBooleanFalse
, true));
1061 require_action_quiet(excluded_subtrees
!= NULL
, errOut
,
1062 SecPVCSetResultForced(pvc
, key
, 0, kCFBooleanFalse
, true));
1065 if (!SecCertificatePathVCVerifyPolicyTree(path
, is_anchor_trusted
)) {
1066 if (!SecPVCSetResultForced(pvc
, key
, 0, kCFBooleanFalse
, true)) {
1072 /* Path builder ensures we only get cert chains with proper issuer
1073 chaining with valid signatures along the way. */
1074 algorithm_id_t working_public_key_algorithm
= anchor
->public_key_algorithm
;
1075 SecKeyRef working_public_key
= anchor
->public_key
;
1076 x500_name_t working_issuer_name
= anchor
->issuer_name
;
1078 uint32_t i
, max_path_length
= n
;
1079 SecCertificateRef cert
= NULL
;
1080 for (i
= 1; i
<= n
; ++i
) {
1082 cert
= SecPVCGetCertificateAtIndex(pvc
, n
- i
);
1083 bool is_self_issued
= SecCertificatePathVCIsCertificateAtIndexSelfIssued(SecPathBuilderGetPath(pvc
->builder
), n
- i
);
1085 /* (a) Verify the basic certificate information. */
1086 /* @@@ Ensure that cert was signed with working_public_key_algorithm
1087 using the working_public_key and the working_public_key_parameters. */
1089 /* Already done by chain builder. */
1090 if (!SecCertificateIsValid(cert
, verify_time
)) {
1091 CFStringRef fail_key
= i
== n
? kSecPolicyCheckValidLeaf
: kSecPolicyCheckValidIntermediates
;
1092 if (!SecPVCSetResult(pvc
, fail_key
, n
- i
, kCFBooleanFalse
)) {
1096 if (SecCertificateIsWeakKey(cert
)) {
1097 CFStringRef fail_key
= i
== n
? kSecPolicyCheckWeakLeaf
: kSecPolicyCheckWeakIntermediates
;
1098 if (!SecPVCSetResult(pvc
, fail_key
, n
- i
, kCFBooleanFalse
)) {
1101 pvc
->result
= kSecTrustResultFatalTrustFailure
;
1104 /* @@@ cert.issuer == working_issuer_name. */
1108 if (!is_self_issued
|| i
== n
) {
1110 /* Verify certificate Subject Name and SubjectAltNames are not within any of the excluded_subtrees */
1111 if(excluded_subtrees
&& CFArrayGetCount(excluded_subtrees
)) {
1112 if ((errSecSuccess
!= SecNameContraintsMatchSubtrees(cert
, excluded_subtrees
, &found
, false)) || found
) {
1113 secnotice("policy", "name in excluded subtrees");
1114 if(!SecPVCSetResultForced(pvc
, key
, n
- i
, kCFBooleanFalse
, true)) { goto errOut
; }
1117 /* Verify certificate Subject Name and SubjectAltNames are within the permitted_subtrees */
1118 if(permitted_subtrees
&& CFArrayGetCount(permitted_subtrees
)) {
1119 if ((errSecSuccess
!= SecNameContraintsMatchSubtrees(cert
, permitted_subtrees
, &found
, true)) || !found
) {
1120 secnotice("policy", "name not in permitted subtrees");
1121 if(!SecPVCSetResultForced(pvc
, key
, n
- i
, kCFBooleanFalse
, true)) { goto errOut
; }
1126 /* (d) (e) (f) handled by SecCertificatePathVCVerifyPolicyTree */
1128 /* If Last Cert in Path */
1132 /* Prepare for Next Cert */
1133 /* (a) (b) Done by SecCertificatePathVCVerifyPolicyTree */
1134 /* (c)(d)(e)(f) Done by SecPathBuilderGetNext and SecCertificatePathVCVerify */
1135 //working_issuer_name = SecCertificateGetNormalizedSubjectContent(cert);
1136 //working_public_key = SecCertificateCopyPublicKey(cert);
1137 //working_public_key_parameters = SecCertificateCopyPublicKeyParameters(cert);
1138 //working_public_key_algorithm = SecCertificateCopyPublicKeyAlgorithm(cert);
1140 /* (g) If a name constraints extension is included in the certificate, modify the permitted_subtrees and excluded_subtrees state variables.
1142 CFArrayRef permitted_subtrees_in_cert
= SecCertificateGetPermittedSubtrees(cert
);
1143 if (permitted_subtrees_in_cert
) {
1144 SecNameConstraintsIntersectSubtrees(permitted_subtrees
, permitted_subtrees_in_cert
);
1147 // could do something smart here to avoid inserting the exact same constraint
1148 CFArrayRef excluded_subtrees_in_cert
= SecCertificateGetExcludedSubtrees(cert
);
1149 if (excluded_subtrees_in_cert
) {
1150 CFIndex num_trees
= CFArrayGetCount(excluded_subtrees_in_cert
);
1151 CFRange range
= { 0, num_trees
};
1152 CFArrayAppendArray(excluded_subtrees
, excluded_subtrees_in_cert
, range
);
1155 /* (h), (i), (j) done by SecCertificatePathVCVerifyPolicyTree */
1158 const SecCEBasicConstraints
*bc
=
1159 SecCertificateGetBasicConstraints(cert
);
1160 #if 0 /* Checked in chain builder pre signature verify already. SecPVCParentCertificateChecks */
1161 if (!bc
|| !bc
->isCA
) {
1162 /* Basic constraints not present or not marked as isCA, illegal. */
1163 if (!SecPVCSetResult(pvc
, kSecPolicyCheckBasicConstraints
,
1164 n
- i
, kCFBooleanFalse
)) {
1170 if (!is_self_issued
) {
1171 if (max_path_length
> 0) {
1174 /* max_path_len exceeded, illegal. */
1175 if (!SecPVCSetResult(pvc
, kSecPolicyCheckBasicConstraints
,
1176 n
- i
, kCFBooleanFalse
)) {
1182 if (bc
&& bc
->pathLenConstraintPresent
1183 && bc
->pathLenConstraint
< max_path_length
) {
1184 max_path_length
= bc
->pathLenConstraint
;
1186 #if 0 /* Checked in chain builder pre signature verify already. SecPVCParentCertificateChecks */
1187 /* (n) If a key usage extension is present, verify that the keyCertSign bit is set. */
1188 SecKeyUsage keyUsage
= SecCertificateGetKeyUsage(cert
);
1189 if (keyUsage
&& !(keyUsage
& kSecKeyUsageKeyCertSign
)) {
1190 if (!SecPVCSetResultForced(pvc
, kSecPolicyCheckKeyUsage
,
1191 n
- i
, kCFBooleanFalse
, true)) {
1196 /* (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. */
1197 if (SecCertificateHasUnknownCriticalExtension(cert
)) {
1198 /* Certificate contains one or more unknown critical extensions. */
1199 if (!SecPVCSetResult(pvc
, kSecPolicyCheckCriticalExtensions
,
1200 n
- i
, kCFBooleanFalse
)) {
1204 } /* end loop over certs in path */
1206 /* (a) (b) done by SecCertificatePathVCVerifyPolicyTree */
1208 //working_public_key = SecCertificateCopyPublicKey(cert);
1210 /* 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
1211 working_public_key_algorithm are different, set the working_public_key_parameters to null. */
1212 //working_public_key_parameters = SecCertificateCopyPublicKeyParameters(cert);
1214 //working_public_key_algorithm = SecCertificateCopyPublicKeyAlgorithm(cert);
1215 /* (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. */
1216 if (SecCertificateHasUnknownCriticalExtension(cert
)) {
1217 /* Certificate contains one or more unknown critical extensions. */
1218 if (!SecPVCSetResult(pvc
, kSecPolicyCheckCriticalExtensions
,
1219 0, kCFBooleanFalse
)) {
1223 /* (g) done by SecCertificatePathVCVerifyPolicyTree */
1226 CFReleaseNull(permitted_subtrees
);
1227 CFReleaseNull(excluded_subtrees
);
1230 static policy_set_t
policies_for_cert(SecCertificateRef cert
) {
1231 policy_set_t policies
= NULL
;
1232 const SecCECertificatePolicies
*cp
=
1233 SecCertificateGetCertificatePolicies(cert
);
1234 size_t policy_ix
, policy_count
= cp
? cp
->numPolicies
: 0;
1235 for (policy_ix
= 0; policy_ix
< policy_count
; ++policy_ix
) {
1236 policy_set_add(&policies
, &cp
->policies
[policy_ix
].policyIdentifier
);
1241 static void SecPolicyCheckEV(SecPVCRef pvc
,
1243 CFIndex ix
, count
= SecPVCGetCertificateCount(pvc
);
1244 policy_set_t valid_policies
= NULL
;
1246 /* 6.1.7. Key Usage Purposes */
1248 CFAbsoluteTime jul2016
= 489024000;
1249 SecCertificateRef leaf
= SecPVCGetCertificateAtIndex(pvc
, 0);
1250 if (SecCertificateNotValidBefore(leaf
) > jul2016
&& count
< 3) {
1251 /* Root CAs may not sign subscriber certificates after 30 June 2016. */
1252 if (SecPVCSetResultForced(pvc
, key
,
1253 0, kCFBooleanFalse
, true)) {
1259 for (ix
= 0; ix
< count
; ++ix
) {
1260 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, ix
);
1261 policy_set_t policies
= policies_for_cert(cert
);
1264 /* anyPolicy in the leaf isn't allowed for EV, so only init
1265 valid_policies if we have real policies. */
1266 if (!policy_set_contains(policies
, &oidAnyPolicy
)) {
1267 valid_policies
= policies
;
1270 } else if (ix
< count
- 1) {
1271 /* Subordinate CA */
1272 if (!SecPolicySubordinateCACertificateCouldBeEV(cert
)) {
1273 secnotice("ev", "subordinate certificate is not ev");
1274 if (SecPVCSetResultForced(pvc
, key
,
1275 ix
, kCFBooleanFalse
, true)) {
1276 policy_set_free(valid_policies
);
1277 policy_set_free(policies
);
1281 policy_set_intersect(&valid_policies
, policies
);
1284 if (!SecPolicyRootCACertificateIsEV(cert
, valid_policies
)) {
1285 secnotice("ev", "anchor certificate is not ev");
1286 if (SecPVCSetResultForced(pvc
, key
,
1287 ix
, kCFBooleanFalse
, true)) {
1288 policy_set_free(valid_policies
);
1289 policy_set_free(policies
);
1294 policy_set_free(policies
);
1295 if (!valid_policies
) {
1296 secnotice("ev", "valid_policies set is empty: chain not ev");
1297 /* If we ever get into a state where no policies are valid anymore
1298 this can't be an ev chain. */
1299 if (SecPVCSetResultForced(pvc
, key
,
1300 ix
, kCFBooleanFalse
, true)) {
1306 policy_set_free(valid_policies
);
1308 /* (a) EV Subscriber Certificates Each EV Certificate issued by the CA to a
1309 Subscriber MUST contain an OID defined by the CA in the certificate’s
1310 certificatePolicies extension that: (i) indicates which CA policy statement relates
1311 to that certificate, (ii) asserts the CA’s adherence to and compliance with these
1312 Guidelines, and (iii), by pre-agreement with the Application Software Vendor,
1313 marks the certificate as being an EV Certificate.
1314 (b) EV Subordinate CA Certificates
1315 (1) Certificates issued to Subordinate CAs that are not controlled by the issuing
1316 CA MUST contain one or more OIDs defined by the issuing CA that
1317 explicitly identify the EV Policies that are implemented by the Subordinate
1319 (2) Certificates issued to Subordinate CAs that are controlled by the Root CA
1320 MAY contain the special anyPolicy OID (2.5.29.32.0).
1321 (c) Root CA Certificates Root CA Certificates SHOULD NOT contain the
1322 certificatePolicies or extendedKeyUsage extensions.
1328 * MARK: Certificate Transparency support
1334 Version sct_version; // 1 byte
1335 LogID id; // 32 bytes
1336 uint64 timestamp; // 8 bytes
1337 CtExtensions extensions; // 2 bytes len field, + n bytes data
1338 digitally-signed struct { // 1 byte hash alg, 1 byte sig alg, n bytes signature
1339 Version sct_version;
1340 SignatureType signature_type = certificate_timestamp;
1342 LogEntryType entry_type;
1343 select(entry_type) {
1344 case x509_entry: ASN.1Cert;
1345 case precert_entry: PreCert;
1347 CtExtensions extensions;
1349 } SignedCertificateTimestamp;
1353 #include <Security/SecureTransportPriv.h>
1356 SecAsn1Oid
*oidForSigAlg(SSL_HashAlgorithm hash
, SSL_SignatureAlgorithm alg
)
1359 case SSL_SignatureAlgorithmRSA
:
1361 case SSL_HashAlgorithmSHA1
:
1362 return &CSSMOID_SHA1WithRSA
;
1363 case SSL_HashAlgorithmSHA256
:
1364 return &CSSMOID_SHA256WithRSA
;
1365 case SSL_HashAlgorithmSHA384
:
1366 return &CSSMOID_SHA384WithRSA
;
1370 case SSL_SignatureAlgorithmECDSA
:
1372 case SSL_HashAlgorithmSHA1
:
1373 return &CSSMOID_ECDSA_WithSHA1
;
1374 case SSL_HashAlgorithmSHA256
:
1375 return &CSSMOID_ECDSA_WithSHA256
;
1376 case SSL_HashAlgorithmSHA384
:
1377 return &CSSMOID_ECDSA_WithSHA384
;
1389 static size_t SSLDecodeUint16(const uint8_t *p
)
1391 return (p
[0]<<8 | p
[1]);
1394 static uint8_t *SSLEncodeUint16(uint8_t *p
, size_t len
)
1396 p
[0] = (len
>> 8)&0xff;
1397 p
[1] = (len
& 0xff);
1401 static uint8_t *SSLEncodeUint24(uint8_t *p
, size_t len
)
1403 p
[0] = (len
>> 16)&0xff;
1404 p
[1] = (len
>> 8)&0xff;
1405 p
[2] = (len
& 0xff);
1411 uint64_t SSLDecodeUint64(const uint8_t *p
)
1414 for(int i
=0; i
<8; i
++) {
1421 #include <libDER/DER_CertCrl.h>
1422 #include <libDER/DER_Encode.h>
1423 #include <libDER/asn1Types.h>
1426 static CFDataRef
copy_x509_entry_from_chain(SecPVCRef pvc
)
1428 SecCertificateRef leafCert
= SecPVCGetCertificateAtIndex(pvc
, 0);
1430 CFMutableDataRef data
= CFDataCreateMutable(kCFAllocatorDefault
, 3+SecCertificateGetLength(leafCert
));
1432 CFDataSetLength(data
, 3+SecCertificateGetLength(leafCert
));
1434 uint8_t *q
= CFDataGetMutableBytePtr(data
);
1435 q
= SSLEncodeUint24(q
, SecCertificateGetLength(leafCert
));
1436 memcpy(q
, SecCertificateGetBytePtr(leafCert
), SecCertificateGetLength(leafCert
));
1442 static CFDataRef
copy_precert_entry_from_chain(SecPVCRef pvc
)
1444 SecCertificateRef leafCert
= NULL
;
1445 SecCertificateRef issuer
= NULL
;
1446 CFDataRef issuerKeyHash
= NULL
;
1447 CFDataRef tbs_precert
= NULL
;
1448 CFMutableDataRef data
= NULL
;
1450 require_quiet(SecPVCGetCertificateCount(pvc
)>=2, out
); //we need the issuer key for precerts.
1451 leafCert
= SecPVCGetCertificateAtIndex(pvc
, 0);
1452 issuer
= SecPVCGetCertificateAtIndex(pvc
, 1);
1454 require(leafCert
, out
);
1455 require(issuer
, out
); // Those two would likely indicate an internal error, since we already checked the chain length above.
1456 issuerKeyHash
= SecCertificateCopySubjectPublicKeyInfoSHA256Digest(issuer
);
1457 tbs_precert
= SecCertificateCopyPrecertTBS(leafCert
);
1459 require(issuerKeyHash
, out
);
1460 require(tbs_precert
, out
);
1461 data
= CFDataCreateMutable(kCFAllocatorDefault
, CFDataGetLength(issuerKeyHash
) + 3 + CFDataGetLength(tbs_precert
));
1462 CFDataSetLength(data
, CFDataGetLength(issuerKeyHash
) + 3 + CFDataGetLength(tbs_precert
));
1464 uint8_t *q
= CFDataGetMutableBytePtr(data
);
1465 memcpy(q
, CFDataGetBytePtr(issuerKeyHash
), CFDataGetLength(issuerKeyHash
)); q
+= CFDataGetLength(issuerKeyHash
); // issuer key hash
1466 q
= SSLEncodeUint24(q
, CFDataGetLength(tbs_precert
));
1467 memcpy(q
, CFDataGetBytePtr(tbs_precert
), CFDataGetLength(tbs_precert
));
1470 CFReleaseSafe(issuerKeyHash
);
1471 CFReleaseSafe(tbs_precert
);
1476 CFAbsoluteTime
TimestampToCFAbsoluteTime(uint64_t ts
)
1478 return (ts
/ 1000) - kCFAbsoluteTimeIntervalSince1970
;
1482 uint64_t TimestampFromCFAbsoluteTime(CFAbsoluteTime at
)
1484 return (uint64_t)(at
+ kCFAbsoluteTimeIntervalSince1970
) * 1000;
1491 If the 'sct' is valid, add it to the validatingLogs dictionary.
1494 - validatingLogs: mutable dictionary to which to add the log that validate this SCT.
1496 - entry_type: 0 for x509 cert, 1 for precert.
1497 - entry: the cert or precert data.
1498 - vt: verification time timestamp (as used in SCTs: ms since 1970 Epoch)
1499 - trustedLog: Dictionary contain the Trusted Logs.
1501 The SCT is valid if:
1502 - It decodes properly.
1503 - Its timestamp is less than 'verifyTime'.
1504 - It is signed by a log in 'trustedLogs'.
1505 - If entry_type = 0, the log must be currently qualified.
1506 - If entry_type = 1, the log may be expired.
1508 If the SCT is valid, it's added to the validatinLogs dictionary using the log dictionary as the key, and the timestamp as value.
1509 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.
1514 static CFDictionaryRef
getSCTValidatingLog(CFDataRef sct
, int entry_type
, CFDataRef entry
, uint64_t vt
, CFArrayRef trustedLogs
, CFAbsoluteTime
*sct_at
)
1517 const uint8_t *logID
;
1518 const uint8_t *timestampData
;
1520 size_t extensionsLen
;
1521 const uint8_t *extensionsData
;
1524 size_t signatureLen
;
1525 const uint8_t *signatureData
;
1526 SecKeyRef pubKey
= NULL
;
1527 uint8_t *signed_data
= NULL
;
1528 const SecAsn1Oid
*oid
= NULL
;
1530 CFDataRef logIDData
= NULL
;
1531 CFDictionaryRef result
= 0;
1533 const uint8_t *p
= CFDataGetBytePtr(sct
);
1534 size_t len
= CFDataGetLength(sct
);
1536 require(len
>=43, out
);
1538 version
= p
[0]; p
++; len
--;
1539 logID
= p
; p
+=32; len
-=32;
1540 timestampData
= p
; p
+=8; len
-=8;
1541 extensionsLen
= SSLDecodeUint16(p
); p
+=2; len
-=2;
1543 require(len
>=extensionsLen
, out
);
1544 extensionsData
= p
; p
+=extensionsLen
; len
-=extensionsLen
;
1546 require(len
>=4, out
);
1547 hashAlg
=p
[0]; p
++; len
--;
1548 sigAlg
=p
[0]; p
++; len
--;
1549 signatureLen
= SSLDecodeUint16(p
); p
+=2; len
-=2;
1550 require(len
==signatureLen
, out
); /* We do not tolerate any extra data after the signature */
1553 /* verify version: only v1(0) is supported */
1555 secerror("SCT version unsupported: %d\n", version
);
1559 /* verify timestamp not in the future */
1560 timestamp
= SSLDecodeUint64(timestampData
);
1561 if(timestamp
> vt
) {
1562 secerror("SCT is in the future: %llu > %llu\n", timestamp
, vt
);
1569 size_t signed_data_len
= 12 + CFDataGetLength(entry
) + 2 + extensionsLen
;
1570 signed_data
= malloc(signed_data_len
);
1571 require(signed_data
, out
);
1574 *q
++ = 0; // certificate_timestamp
1575 memcpy(q
, timestampData
, 8); q
+=8;
1576 q
= SSLEncodeUint16(q
, entry_type
); // logentry type: 0=cert 1=precert
1577 memcpy(q
, CFDataGetBytePtr(entry
), CFDataGetLength(entry
)); q
+= CFDataGetLength(entry
);
1578 q
= SSLEncodeUint16(q
, extensionsLen
);
1579 memcpy(q
, extensionsData
, extensionsLen
);
1581 logIDData
= CFDataCreateWithBytesNoCopy(kCFAllocatorDefault
, logID
, 32, kCFAllocatorNull
);
1583 CFDictionaryRef logData
= CFArrayGetValueMatching(trustedLogs
, ^bool(const void *dict
) {
1584 const void *key_data
;
1585 if(!isDictionary(dict
)) return false;
1586 if(!CFDictionaryGetValueIfPresent(dict
, CFSTR("key"), &key_data
)) return false;
1587 if(!isData(key_data
)) return false;
1588 CFDataRef valueID
= SecSHA256DigestCreateFromData(kCFAllocatorDefault
, (CFDataRef
)key_data
);
1589 bool result
= (bool)(CFDataCompare(logIDData
, valueID
)==kCFCompareEqualTo
);
1590 CFReleaseSafe(valueID
);
1593 require(logData
, out
);
1596 // For external SCTs, only keep SCTs from currently valid logs.
1597 require(!CFDictionaryContainsKey(logData
, CFSTR("expiry")), out
);
1600 CFDataRef logKeyData
= CFDictionaryGetValue(logData
, CFSTR("key"));
1601 require(logKeyData
, out
); // This failing would be an internal logic error
1602 pubKey
= SecKeyCreateFromSubjectPublicKeyInfoData(kCFAllocatorDefault
, logKeyData
);
1603 require(pubKey
, out
);
1605 oid
= oidForSigAlg(hashAlg
, sigAlg
);
1608 algId
.algorithm
= *oid
;
1609 algId
.parameters
.Data
= NULL
;
1610 algId
.parameters
.Length
= 0;
1612 if(SecKeyDigestAndVerify(pubKey
, &algId
, signed_data
, signed_data_len
, signatureData
, signatureLen
)==0) {
1613 *sct_at
= TimestampToCFAbsoluteTime(timestamp
);
1616 secerror("SCT signature failed (log=%@)\n", logData
);
1620 CFReleaseSafe(logIDData
);
1621 CFReleaseSafe(pubKey
);
1627 static void addValidatingLog(CFMutableDictionaryRef validatingLogs
, CFDictionaryRef log
, CFAbsoluteTime sct_at
)
1629 CFDateRef validated_time
= CFDictionaryGetValue(validatingLogs
, log
);
1631 if(validated_time
==NULL
|| (sct_at
< CFDateGetAbsoluteTime(validated_time
))) {
1632 CFDateRef sct_time
= CFDateCreate(kCFAllocatorDefault
, sct_at
);
1633 CFDictionarySetValue(validatingLogs
, log
, sct_time
);
1634 CFReleaseSafe(sct_time
);
1638 static CFArrayRef
copy_ocsp_scts(SecPVCRef pvc
)
1640 CFMutableArrayRef SCTs
= NULL
;
1641 SecCertificateRef leafCert
= NULL
;
1642 SecCertificateRef issuer
= NULL
;
1643 CFArrayRef ocspResponsesData
= NULL
;
1644 SecOCSPRequestRef ocspRequest
= NULL
;
1646 ocspResponsesData
= SecPathBuilderCopyOCSPResponses(pvc
->builder
);
1647 require_quiet(ocspResponsesData
, out
);
1649 require_quiet(SecPVCGetCertificateCount(pvc
)>=2, out
); //we need the issuer key for precerts.
1650 leafCert
= SecPVCGetCertificateAtIndex(pvc
, 0);
1651 issuer
= SecPVCGetCertificateAtIndex(pvc
, 1);
1653 require(leafCert
, out
);
1654 require(issuer
, out
); // not quiet: Those two would likely indicate an internal error, since we already checked the chain length above.
1655 ocspRequest
= SecOCSPRequestCreate(leafCert
, issuer
);
1657 SCTs
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
);
1660 CFArrayForEach(ocspResponsesData
, ^(const void *value
) {
1661 /* TODO: Should the builder already have the appropriate SecOCSPResponseRef ? */
1662 SecOCSPResponseRef ocspResponse
= SecOCSPResponseCreate(value
);
1663 if(ocspResponse
&& SecOCSPGetResponseStatus(ocspResponse
)==kSecOCSPSuccess
) {
1664 SecOCSPSingleResponseRef ocspSingleResponse
= SecOCSPResponseCopySingleResponse(ocspResponse
, ocspRequest
);
1665 if(ocspSingleResponse
) {
1666 CFArrayRef singleResponseSCTs
= SecOCSPSingleResponseCopySCTs(ocspSingleResponse
);
1667 if(singleResponseSCTs
) {
1668 CFArrayAppendArray(SCTs
, singleResponseSCTs
, CFRangeMake(0, CFArrayGetCount(singleResponseSCTs
)));
1669 CFRelease(singleResponseSCTs
);
1671 SecOCSPSingleResponseDestroy(ocspSingleResponse
);
1674 if(ocspResponse
) SecOCSPResponseFinalize(ocspResponse
);
1677 if(CFArrayGetCount(SCTs
)==0) {
1678 CFReleaseNull(SCTs
);
1682 CFReleaseSafe(ocspResponsesData
);
1684 SecOCSPRequestFinalize(ocspRequest
);
1689 static void SecPolicyCheckCT(SecPVCRef pvc
, CFStringRef key
)
1691 SecCertificateRef leafCert
= SecPVCGetCertificateAtIndex(pvc
, 0);
1692 CFArrayRef embeddedScts
= SecCertificateCopySignedCertificateTimestamps(leafCert
);
1693 CFArrayRef builderScts
= SecPathBuilderCopySignedCertificateTimestamps(pvc
->builder
);
1694 CFArrayRef trustedLogs
= SecPathBuilderCopyTrustedLogs(pvc
->builder
);
1695 CFArrayRef ocspScts
= copy_ocsp_scts(pvc
);
1696 CFDataRef precertEntry
= copy_precert_entry_from_chain(pvc
);
1697 CFDataRef x509Entry
= copy_x509_entry_from_chain(pvc
);
1699 // This eventually contain list of logs who validated the SCT.
1700 CFMutableDictionaryRef currentLogsValidatingScts
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
1701 CFMutableDictionaryRef logsValidatingEmbeddedScts
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
1703 uint64_t vt
= TimestampFromCFAbsoluteTime(SecPVCGetVerifyTime(pvc
));
1705 __block
bool at_least_one_currently_valid_external
= 0;
1706 __block
bool at_least_one_currently_valid_embedded
= 0;
1708 require(logsValidatingEmbeddedScts
, out
);
1709 require(currentLogsValidatingScts
, out
);
1711 if(trustedLogs
) { // Don't bother trying to validate SCTs if we don't have any trusted logs.
1712 if(embeddedScts
&& precertEntry
) { // Don't bother if we could not get the precert.
1713 CFArrayForEach(embeddedScts
, ^(const void *value
){
1714 CFAbsoluteTime sct_at
;
1715 CFDictionaryRef log
= getSCTValidatingLog(value
, 1, precertEntry
, vt
, trustedLogs
, &sct_at
);
1717 addValidatingLog(logsValidatingEmbeddedScts
, log
, sct_at
);
1718 if(!CFDictionaryContainsKey(log
, CFSTR("expiry"))) {
1719 addValidatingLog(currentLogsValidatingScts
, log
, sct_at
);
1720 at_least_one_currently_valid_embedded
= true;
1726 if(builderScts
&& x509Entry
) { // Don't bother if we could not get the cert.
1727 CFArrayForEach(builderScts
, ^(const void *value
){
1728 CFAbsoluteTime sct_at
;
1729 CFDictionaryRef log
= getSCTValidatingLog(value
, 0, x509Entry
, vt
, trustedLogs
, &sct_at
);
1731 addValidatingLog(currentLogsValidatingScts
, log
, sct_at
);
1732 at_least_one_currently_valid_external
= true;
1737 if(ocspScts
&& x509Entry
) {
1738 CFArrayForEach(ocspScts
, ^(const void *value
){
1739 CFAbsoluteTime sct_at
;
1740 CFDictionaryRef log
= getSCTValidatingLog(value
, 0, x509Entry
, vt
, trustedLogs
, &sct_at
);
1742 addValidatingLog(currentLogsValidatingScts
, log
, sct_at
);
1743 at_least_one_currently_valid_external
= true;
1750 /* We now have 2 sets of logs that validated those SCTS, count them and make a final decision.
1753 is_ct = (A1 AND A2) OR (B1 AND B2).
1755 A1: embedded SCTs from 2+ to 5+ logs valid at issuance time
1756 A2: At least one embedded SCT from a currently valid log.
1758 B1: SCTs from 2 currently valid logs (from any source)
1759 B2: At least 1 external SCT from a currently valid log.
1763 SecCertificatePathVCSetIsCT(SecPathBuilderGetPath(pvc
->builder
), false);
1765 if(at_least_one_currently_valid_external
&& CFDictionaryGetCount(currentLogsValidatingScts
)>=2) {
1766 SecCertificatePathVCSetIsCT(SecPathBuilderGetPath(pvc
->builder
), true);
1767 } else if(at_least_one_currently_valid_embedded
) {
1768 __block CFAbsoluteTime issuanceTime
= SecPVCGetVerifyTime(pvc
);
1769 __block
int lifetime
; // in Months
1770 __block
unsigned once_or_current_qualified_embedded
= 0;
1772 /* Calculate issuance time base on timestamp of SCTs from current logs */
1773 CFDictionaryForEach(currentLogsValidatingScts
, ^(const void *key
, const void *value
) {
1774 CFDictionaryRef log
= key
;
1775 if(!CFDictionaryContainsKey(log
, CFSTR("expiry"))) {
1776 // Log is still qualified
1777 CFDateRef ts
= (CFDateRef
) value
;
1778 CFAbsoluteTime timestamp
= CFDateGetAbsoluteTime(ts
);
1779 if(timestamp
< issuanceTime
) {
1780 issuanceTime
= timestamp
;
1786 CFDictionaryForEach(logsValidatingEmbeddedScts
, ^(const void *key
, const void *value
) {
1787 CFDictionaryRef log
= key
;
1788 CFDateRef ts
= value
;
1789 CFDateRef expiry
= CFDictionaryGetValue(log
, CFSTR("expiry"));
1790 if(expiry
== NULL
|| CFDateCompare(ts
, expiry
, NULL
) == kCFCompareLessThan
) {
1791 once_or_current_qualified_embedded
++;
1795 SecCFCalendarDoWithZuluCalendar(^(CFCalendarRef zuluCalendar
) {
1797 CFCalendarGetComponentDifference(zuluCalendar
,
1798 SecCertificateNotValidBefore(leafCert
),
1799 SecCertificateNotValidAfter(leafCert
),
1800 0, "M", &_lifetime
);
1801 lifetime
= _lifetime
;
1804 unsigned requiredEmbeddedSctsCount
;
1806 if (lifetime
< 15) {
1807 requiredEmbeddedSctsCount
= 2;
1808 } else if (lifetime
<= 27) {
1809 requiredEmbeddedSctsCount
= 3;
1810 } else if (lifetime
<= 39) {
1811 requiredEmbeddedSctsCount
= 4;
1813 requiredEmbeddedSctsCount
= 5;
1816 if(once_or_current_qualified_embedded
>= requiredEmbeddedSctsCount
){
1817 SecCertificatePathVCSetIsCT(SecPathBuilderGetPath(pvc
->builder
), true);
1822 CFReleaseSafe(logsValidatingEmbeddedScts
);
1823 CFReleaseSafe(currentLogsValidatingScts
);
1824 CFReleaseSafe(builderScts
);
1825 CFReleaseSafe(embeddedScts
);
1826 CFReleaseSafe(ocspScts
);
1827 CFReleaseSafe(precertEntry
);
1828 CFReleaseSafe(trustedLogs
);
1829 CFReleaseSafe(x509Entry
);
1832 static bool checkPolicyOidData(SecPVCRef pvc
, CFDataRef oid
) {
1833 CFIndex ix
, count
= SecPVCGetCertificateCount(pvc
);
1835 key_value
.data
= (DERByte
*)CFDataGetBytePtr(oid
);
1836 key_value
.length
= (DERSize
)CFDataGetLength(oid
);
1838 for (ix
= 0; ix
< count
; ix
++) {
1839 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, ix
);
1840 policy_set_t policies
= policies_for_cert(cert
);
1842 if (policy_set_contains(policies
, &key_value
)) {
1843 policy_set_free(policies
);
1846 policy_set_free(policies
);
1851 static void SecPolicyCheckCertificatePolicyOid(SecPVCRef pvc
, CFStringRef key
)
1853 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
1854 CFTypeRef value
= CFDictionaryGetValue(policy
->_options
, key
);
1855 bool result
= false;
1857 if (CFGetTypeID(value
) == CFDataGetTypeID())
1859 result
= checkPolicyOidData(pvc
, value
);
1860 } else if (CFGetTypeID(value
) == CFStringGetTypeID()) {
1861 CFDataRef dataOid
= SecCertificateCreateOidDataFromString(NULL
, value
);
1863 result
= checkPolicyOidData(pvc
, dataOid
);
1868 SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
);
1873 static void SecPolicyCheckRevocation(SecPVCRef pvc
,
1875 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
1876 CFTypeRef value
= CFDictionaryGetValue(policy
->_options
, key
);
1877 if (isString(value
)) {
1878 SecPathBuilderSetRevocationMethod(pvc
->builder
, value
);
1882 static void SecPolicyCheckRevocationResponseRequired(SecPVCRef pvc
,
1884 pvc
->require_revocation_response
= true;
1885 secdebug("policy", "revocation response required");
1888 static void SecPolicyCheckRevocationOnline(SecPVCRef pvc
, CFStringRef key
) {
1889 SecPathBuilderSetCheckRevocationOnline(pvc
->builder
);
1892 static void SecPolicyCheckNoNetworkAccess(SecPVCRef pvc
,
1894 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
1895 CFTypeRef value
= CFDictionaryGetValue(policy
->_options
, key
);
1896 if (value
== kCFBooleanTrue
) {
1897 SecPathBuilderSetCanAccessNetwork(pvc
->builder
, false);
1899 SecPathBuilderSetCanAccessNetwork(pvc
->builder
, true);
1903 static void SecPolicyCheckWeakIntermediates(SecPVCRef pvc
,
1905 CFIndex ix
, count
= SecPVCGetCertificateCount(pvc
);
1906 for (ix
= 1; ix
< count
- 1; ++ix
) {
1907 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, ix
);
1908 if (cert
&& SecCertificateIsWeakKey(cert
)) {
1909 /* Intermediate certificate has a weak key. */
1910 if (!SecPVCSetResult(pvc
, key
, ix
, kCFBooleanFalse
))
1912 pvc
->result
= kSecTrustResultFatalTrustFailure
;
1917 static void SecPolicyCheckWeakLeaf(SecPVCRef pvc
,
1919 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, 0);
1920 if (cert
&& SecCertificateIsWeakKey(cert
)) {
1921 /* Leaf certificate has a weak key. */
1922 if (!SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
))
1924 pvc
->result
= kSecTrustResultFatalTrustFailure
;
1928 static void SecPolicyCheckWeakRoot(SecPVCRef pvc
,
1930 CFIndex ix
, count
= SecPVCGetCertificateCount(pvc
);
1932 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, ix
);
1933 if (cert
&& SecCertificateIsWeakKey(cert
)) {
1934 /* Root certificate has a weak key. */
1935 if (!SecPVCSetResult(pvc
, key
, ix
, kCFBooleanFalse
))
1937 pvc
->result
= kSecTrustResultFatalTrustFailure
;
1941 static void SecPolicyCheckKeySize(SecPVCRef pvc
, CFStringRef key
) {
1942 CFIndex ix
, count
= SecPVCGetCertificateCount(pvc
);
1943 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
1944 CFDictionaryRef keySizes
= CFDictionaryGetValue(policy
->_options
, key
);
1945 for (ix
= 0; ix
< count
; ++ix
) {
1946 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, ix
);
1947 if (!SecCertificateIsAtLeastMinKeySize(cert
, keySizes
)) {
1948 if (!SecPVCSetResult(pvc
, key
, ix
, kCFBooleanFalse
))
1954 static void SecPolicyCheckSignatureHashAlgorithms(SecPVCRef pvc
,
1956 CFIndex ix
, count
= SecPVCGetCertificateCount(pvc
);
1957 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
1958 CFSetRef disallowedHashAlgorithms
= CFDictionaryGetValue(policy
->_options
, key
);
1959 for (ix
= 0; ix
< count
; ++ix
) {
1960 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, ix
);
1961 if (!SecPolicyCheckCertSignatureHashAlgorithms(cert
, disallowedHashAlgorithms
)) {
1962 if (!SecPVCSetResult(pvc
, key
, ix
, kCFBooleanFalse
))
1968 static bool leaf_is_on_weak_hash_whitelist(SecPVCRef pvc
) {
1969 SecCertificateRef leaf
= SecPVCGetCertificateAtIndex(pvc
, 0);
1970 require_quiet(leaf
, out
);
1972 /* And now a special snowflake from our tests */
1974 /* subject:/C=AU/ST=NSW/L=St Leonards/O=VODAFONE HUTCHISON AUSTRALIA PTY LIMITED/OU=Technology Shared Services/CN=mybill.vodafone.com.au */
1975 /* issuer :/C=UK/O=Vodafone Group/CN=Vodafone (Corporate Services 2009) */
1976 /* Not After : May 26 09:37:50 2017 GMT */
1977 static const uint8_t vodafone
[] = {
1978 0xde, 0x77, 0x63, 0x97, 0x79, 0x47, 0xee, 0x6e, 0xc1, 0x3a,
1979 0x7b, 0x3b, 0xad, 0x43, 0x88, 0xa9, 0x66, 0x59, 0xa8, 0x18
1982 /* subject:/C=US/ST=Kansas/L=Overland Park/O=Sprint/CN=oma.ssprov.sprint.com */
1983 /* issuer :/C=US/O=Entrust, Inc./OU=www.entrust.net/rpa is incorporated by reference/OU=(c) 2009 Entrust, Inc./CN=Entrust Certification Authority - L1C */
1984 /* Not After : Aug 16 05:04:29 2017 GMT */
1985 static const uint8_t sprint
[] = {
1986 0xa3, 0x18, 0x70, 0x4f, 0xf7, 0xbf, 0xfb, 0x2b, 0xe2, 0x64,
1987 0x3a, 0x2d, 0x2b, 0xb8, 0x10, 0x5f, 0x77, 0xd5, 0x01, 0xab
1990 CFDataRef leafFingerprint
= SecCertificateGetSHA1Digest(leaf
);
1991 require_quiet(leafFingerprint
, out
);
1992 const unsigned int len
= 20;
1993 const uint8_t *dp
= CFDataGetBytePtr(leafFingerprint
);
1994 if (dp
&& (!memcmp(vodafone
, dp
, len
) || !memcmp(sprint
,dp
,len
))) {
2002 static bool SecPVCKeyIsConstraintPolicyOption(SecPVCRef pvc
, CFStringRef key
);
2004 static void SecPolicyCheckSystemTrustedWeakHash(SecPVCRef pvc
,
2006 CFIndex ix
, count
= SecPVCGetCertificateCount(pvc
);
2008 Boolean keyInPolicy
= false;
2009 CFArrayRef policies
= pvc
->policies
;
2010 CFIndex policyIX
, policyCount
= CFArrayGetCount(policies
);
2011 for (policyIX
= 0; policyIX
< policyCount
; ++policyIX
) {
2012 SecPolicyRef policy
= (SecPolicyRef
)CFArrayGetValueAtIndex(policies
, policyIX
);
2013 if (policy
&& CFDictionaryContainsKey(policy
->_options
, key
)) {
2018 /* We only enforce this check when *both* of the following are true:
2019 * 1. One of the certs in the path has this usage constraint, and
2020 * 2. One of the policies in the PVC has this key
2021 * (As compared to normal policy options which require only one to be true..) */
2022 require_quiet(SecPVCKeyIsConstraintPolicyOption(pvc
, key
) &&
2025 /* Ignore the anchor if it's trusted */
2026 if (SecPathBuilderIsAnchored(pvc
->builder
)) {
2029 for (ix
= 0; ix
< count
; ++ix
) {
2030 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, ix
);
2031 if (SecCertificateIsWeakHash(cert
)) {
2032 if (!leaf_is_on_weak_hash_whitelist(pvc
)) {
2033 if (!SecPVCSetResult(pvc
, key
, ix
, kCFBooleanFalse
)) {
2043 static void SecPolicyCheckSystemTrustedWeakKey(SecPVCRef pvc
,
2045 CFIndex ix
, count
= SecPVCGetCertificateCount(pvc
);
2047 Boolean keyInPolicy
= false;
2048 CFArrayRef policies
= pvc
->policies
;
2049 CFIndex policyIX
, policyCount
= CFArrayGetCount(policies
);
2050 for (policyIX
= 0; policyIX
< policyCount
; ++policyIX
) {
2051 SecPolicyRef policy
= (SecPolicyRef
)CFArrayGetValueAtIndex(policies
, policyIX
);
2052 if (policy
&& CFDictionaryContainsKey(policy
->_options
, key
)) {
2057 /* We only enforce this check when *both* of the following are true:
2058 * 1. One of the certs in the path has this usage constraint, and
2059 * 2. One of the policies in the PVC has this key
2060 * (As compared to normal policy options which require only one to be true..) */
2061 require_quiet(SecPVCKeyIsConstraintPolicyOption(pvc
, key
) &&
2064 /* Ignore the anchor if it's trusted */
2065 if (SecPathBuilderIsAnchored(pvc
->builder
)) {
2068 for (ix
= 0; ix
< count
; ++ix
) {
2069 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, ix
);
2070 if (!SecCertificateIsStrongKey(cert
)) {
2071 if (!SecPVCSetResult(pvc
, key
, ix
, kCFBooleanFalse
)) {
2081 static void SecPolicyCheckPinningRequired(SecPVCRef pvc
, CFStringRef key
) {
2082 /* Pinning is disabled on the system, skip. */
2083 if (SecIsInternalRelease()) {
2084 if (CFPreferencesGetAppBooleanValue(CFSTR("AppleServerAuthenticationNoPinning"),
2085 CFSTR("com.apple.security"), NULL
)) {
2090 CFArrayRef policies
= pvc
->policies
;
2091 CFIndex policyIX
, policyCount
= CFArrayGetCount(policies
);
2092 for (policyIX
= 0; policyIX
< policyCount
; ++policyIX
) {
2093 SecPolicyRef policy
= (SecPolicyRef
)CFArrayGetValueAtIndex(policies
, policyIX
);
2094 CFStringRef policyName
= SecPolicyGetName(policy
);
2095 if (CFEqualSafe(policyName
, CFSTR("sslServer"))) {
2096 /* policy required pinning, but we didn't use a pinning policy */
2097 if (!SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
)) {
2104 void SecPolicyServerInitialize(void) {
2105 gSecPolicyLeafCallbacks
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0,
2106 &kCFTypeDictionaryKeyCallBacks
, NULL
);
2107 gSecPolicyPathCallbacks
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0,
2108 &kCFTypeDictionaryKeyCallBacks
, NULL
);
2110 CFDictionaryAddValue(gSecPolicyPathCallbacks
,
2111 kSecPolicyCheckBasicCertificateProcessing
,
2112 SecPolicyCheckBasicCertificateProcessing
);
2113 CFDictionaryAddValue(gSecPolicyPathCallbacks
,
2114 kSecPolicyCheckCriticalExtensions
,
2115 SecPolicyCheckCriticalExtensions
);
2116 CFDictionaryAddValue(gSecPolicyPathCallbacks
,
2117 kSecPolicyCheckIdLinkage
,
2118 SecPolicyCheckIdLinkage
);
2119 CFDictionaryAddValue(gSecPolicyLeafCallbacks
,
2120 kSecPolicyCheckKeyUsage
,
2121 SecPolicyCheckKeyUsage
);
2122 CFDictionaryAddValue(gSecPolicyLeafCallbacks
,
2123 kSecPolicyCheckExtendedKeyUsage
,
2124 SecPolicyCheckExtendedKeyUsage
);
2125 CFDictionaryAddValue(gSecPolicyLeafCallbacks
,
2126 kSecPolicyCheckBasicConstraints
,
2127 SecPolicyCheckBasicConstraints
);
2128 CFDictionaryAddValue(gSecPolicyPathCallbacks
,
2129 kSecPolicyCheckNonEmptySubject
,
2130 SecPolicyCheckNonEmptySubject
);
2131 CFDictionaryAddValue(gSecPolicyLeafCallbacks
,
2132 kSecPolicyCheckQualifiedCertStatements
,
2133 SecPolicyCheckQualifiedCertStatements
);
2134 CFDictionaryAddValue(gSecPolicyLeafCallbacks
,
2135 kSecPolicyCheckSSLHostname
,
2136 SecPolicyCheckSSLHostname
);
2137 CFDictionaryAddValue(gSecPolicyLeafCallbacks
,
2138 kSecPolicyCheckEmail
,
2139 SecPolicyCheckEmail
);
2140 CFDictionaryAddValue(gSecPolicyPathCallbacks
,
2141 kSecPolicyCheckValidIntermediates
,
2142 SecPolicyCheckValidIntermediates
);
2143 CFDictionaryAddValue(gSecPolicyLeafCallbacks
,
2144 kSecPolicyCheckValidLeaf
,
2145 SecPolicyCheckValidLeaf
);
2146 CFDictionaryAddValue(gSecPolicyPathCallbacks
,
2147 kSecPolicyCheckValidRoot
,
2148 SecPolicyCheckValidRoot
);
2149 CFDictionaryAddValue(gSecPolicyPathCallbacks
,
2150 kSecPolicyCheckIssuerCommonName
,
2151 SecPolicyCheckIssuerCommonName
);
2152 CFDictionaryAddValue(gSecPolicyLeafCallbacks
,
2153 kSecPolicyCheckSubjectCommonNamePrefix
,
2154 SecPolicyCheckSubjectCommonNamePrefix
);
2155 CFDictionaryAddValue(gSecPolicyLeafCallbacks
,
2156 kSecPolicyCheckSubjectCommonName
,
2157 SecPolicyCheckSubjectCommonName
);
2158 CFDictionaryAddValue(gSecPolicyLeafCallbacks
,
2159 kSecPolicyCheckNotValidBefore
,
2160 SecPolicyCheckNotValidBefore
);
2161 CFDictionaryAddValue(gSecPolicyPathCallbacks
,
2162 kSecPolicyCheckChainLength
,
2163 SecPolicyCheckChainLength
);
2164 CFDictionaryAddValue(gSecPolicyPathCallbacks
,
2165 kSecPolicyCheckAnchorSHA1
,
2166 SecPolicyCheckAnchorSHA1
);
2167 CFDictionaryAddValue(gSecPolicyPathCallbacks
,
2168 kSecPolicyCheckAnchorSHA256
,
2169 SecPolicyCheckAnchorSHA256
);
2170 CFDictionaryAddValue(gSecPolicyPathCallbacks
,
2171 kSecPolicyCheckAnchorApple
,
2172 SecPolicyCheckAnchorApple
);
2173 CFDictionaryAddValue(gSecPolicyLeafCallbacks
,
2174 kSecPolicyCheckSubjectOrganization
,
2175 SecPolicyCheckSubjectOrganization
);
2176 CFDictionaryAddValue(gSecPolicyLeafCallbacks
,
2177 kSecPolicyCheckSubjectOrganizationalUnit
,
2178 SecPolicyCheckSubjectOrganizationalUnit
);
2179 CFDictionaryAddValue(gSecPolicyLeafCallbacks
,
2180 kSecPolicyCheckEAPTrustedServerNames
,
2181 SecPolicyCheckEAPTrustedServerNames
);
2182 CFDictionaryAddValue(gSecPolicyLeafCallbacks
,
2183 kSecPolicyCheckSubjectCommonNameTEST
,
2184 SecPolicyCheckSubjectCommonNameTEST
);
2185 CFDictionaryAddValue(gSecPolicyLeafCallbacks
,
2186 kSecPolicyCheckRevocation
,
2187 SecPolicyCheckRevocation
);
2188 CFDictionaryAddValue(gSecPolicyLeafCallbacks
,
2189 kSecPolicyCheckRevocationResponseRequired
,
2190 SecPolicyCheckRevocationResponseRequired
);
2191 CFDictionaryAddValue(gSecPolicyLeafCallbacks
,
2192 kSecPolicyCheckRevocationOnline
,
2193 SecPolicyCheckRevocationOnline
);
2194 CFDictionaryAddValue(gSecPolicyLeafCallbacks
,
2195 kSecPolicyCheckNoNetworkAccess
,
2196 SecPolicyCheckNoNetworkAccess
);
2197 CFDictionaryAddValue(gSecPolicyLeafCallbacks
,
2198 kSecPolicyCheckBlackListedLeaf
,
2199 SecPolicyCheckBlackListedLeaf
);
2200 CFDictionaryAddValue(gSecPolicyLeafCallbacks
,
2201 kSecPolicyCheckGrayListedLeaf
,
2202 SecPolicyCheckGrayListedLeaf
);
2203 CFDictionaryAddValue(gSecPolicyLeafCallbacks
,
2204 kSecPolicyCheckLeafMarkerOid
,
2205 SecPolicyCheckLeafMarkerOid
);
2206 CFDictionaryAddValue(gSecPolicyLeafCallbacks
,
2207 kSecPolicyCheckLeafMarkerOidWithoutValueCheck
,
2208 SecPolicyCheckLeafMarkerOidWithoutValueCheck
);
2209 CFDictionaryAddValue(gSecPolicyLeafCallbacks
,
2210 kSecPolicyCheckLeafMarkersProdAndQA
,
2211 SecPolicyCheckLeafMarkersProdAndQA
);
2212 CFDictionaryAddValue(gSecPolicyPathCallbacks
,
2213 kSecPolicyCheckIntermediateSPKISHA256
,
2214 SecPolicyCheckIntermediateSPKISHA256
);
2215 CFDictionaryAddValue(gSecPolicyPathCallbacks
,
2216 kSecPolicyCheckIntermediateEKU
,
2217 SecPolicyCheckIntermediateEKU
);
2218 CFDictionaryAddValue(gSecPolicyPathCallbacks
,
2219 kSecPolicyCheckIntermediateMarkerOid
,
2220 SecPolicyCheckIntermediateMarkerOid
);
2221 CFDictionaryAddValue(gSecPolicyPathCallbacks
,
2222 kSecPolicyCheckCertificatePolicy
,
2223 SecPolicyCheckCertificatePolicyOid
);
2224 CFDictionaryAddValue(gSecPolicyPathCallbacks
,
2225 kSecPolicyCheckWeakIntermediates
,
2226 SecPolicyCheckWeakIntermediates
);
2227 CFDictionaryAddValue(gSecPolicyLeafCallbacks
,
2228 kSecPolicyCheckWeakLeaf
,
2229 SecPolicyCheckWeakLeaf
);
2230 CFDictionaryAddValue(gSecPolicyPathCallbacks
,
2231 kSecPolicyCheckWeakRoot
,
2232 SecPolicyCheckWeakRoot
);
2233 CFDictionaryAddValue(gSecPolicyPathCallbacks
,
2234 kSecPolicyCheckKeySize
,
2235 SecPolicyCheckKeySize
);
2236 CFDictionaryAddValue(gSecPolicyPathCallbacks
,
2237 kSecPolicyCheckSignatureHashAlgorithms
,
2238 SecPolicyCheckSignatureHashAlgorithms
);
2239 CFDictionaryAddValue(gSecPolicyPathCallbacks
,
2240 kSecPolicyCheckSystemTrustedWeakHash
,
2241 SecPolicyCheckSystemTrustedWeakHash
);
2242 CFDictionaryAddValue(gSecPolicyPathCallbacks
,
2243 kSecPolicyCheckSystemTrustedWeakKey
,
2244 SecPolicyCheckSystemTrustedWeakKey
);
2245 CFDictionaryAddValue(gSecPolicyPathCallbacks
,
2246 kSecPolicyCheckIntermediateOrganization
,
2247 SecPolicyCheckIntermediateOrganization
);
2248 CFDictionaryAddValue(gSecPolicyPathCallbacks
,
2249 kSecPolicyCheckIntermediateCountry
,
2250 SecPolicyCheckIntermediateCountry
);
2251 CFDictionaryAddValue(gSecPolicyLeafCallbacks
,
2252 kSecPolicyCheckPinningRequired
,
2253 SecPolicyCheckPinningRequired
);
2258 /********************************************************
2259 ****************** SecPVCRef Functions *****************
2260 ********************************************************/
2262 void SecPVCInit(SecPVCRef pvc
, SecPathBuilderRef builder
, CFArrayRef policies
) {
2263 secdebug("alloc", "%p", pvc
);
2264 // Weird logging policies crashes.
2265 //secdebug("policy", "%@", policies);
2267 // Zero the pvc struct so only non-zero fields need to be explicitly set
2268 memset(pvc
, 0, sizeof(struct OpaqueSecPVC
));
2269 pvc
->builder
= builder
;
2270 pvc
->policies
= policies
;
2273 pvc
->result
= kSecTrustResultUnspecified
;
2275 CFMutableDictionaryRef certDetail
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0,
2276 &kCFTypeDictionaryKeyCallBacks
,
2277 &kCFTypeDictionaryValueCallBacks
);
2278 pvc
->leafDetails
= CFArrayCreate(kCFAllocatorDefault
, (const void **)&certDetail
,
2279 1, &kCFTypeArrayCallBacks
);
2280 CFRelease(certDetail
);
2283 void SecPVCDelete(SecPVCRef pvc
) {
2284 secdebug("alloc", "%p", pvc
);
2285 CFReleaseNull(pvc
->policies
);
2286 CFReleaseNull(pvc
->details
);
2287 CFReleaseNull(pvc
->leafDetails
);
2290 void SecPVCSetPath(SecPVCRef pvc
, SecCertificatePathVCRef path
) {
2291 secdebug("policy", "%@", path
);
2293 pvc
->result
= kSecTrustResultUnspecified
;
2294 CFReleaseNull(pvc
->details
);
2297 void SecPVCComputeDetails(SecPVCRef pvc
, SecCertificatePathVCRef path
) {
2300 /* Since we don't run the LeafChecks again, we need to preserve the
2301 * result the leaf had. */
2302 CFIndex ix
, pathLength
= SecCertificatePathVCGetCount(path
);
2303 CFMutableArrayRef details
= CFArrayCreateMutableCopy(kCFAllocatorDefault
,
2304 pathLength
, pvc
->leafDetails
);
2305 for (ix
= 1; ix
< pathLength
; ++ix
) {
2306 CFMutableDictionaryRef certDetail
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0,
2307 &kCFTypeDictionaryKeyCallBacks
,
2308 &kCFTypeDictionaryValueCallBacks
);
2309 CFArrayAppendValue(details
, certDetail
);
2310 CFRelease(certDetail
);
2312 CFRetainAssign(pvc
->details
, details
);
2313 pvc
->result
= pvc
->leafResult
;
2314 CFReleaseSafe(details
);
2317 SecPolicyRef
SecPVCGetPolicy(SecPVCRef pvc
) {
2318 return (SecPolicyRef
)CFArrayGetValueAtIndex(pvc
->policies
, pvc
->policyIX
);
2321 static CFIndex
SecPVCGetCertificateCount(SecPVCRef pvc
) {
2322 return SecPathBuilderGetCertificateCount(pvc
->builder
);
2325 static SecCertificateRef
SecPVCGetCertificateAtIndex(SecPVCRef pvc
, CFIndex ix
) {
2326 return SecPathBuilderGetCertificateAtIndex(pvc
->builder
, ix
);
2329 static CFAbsoluteTime
SecPVCGetVerifyTime(SecPVCRef pvc
) {
2330 return SecPathBuilderGetVerifyTime(pvc
->builder
);
2333 static bool SecPVCIsExceptedError(SecPVCRef pvc
, CFIndex ix
, CFStringRef key
, CFTypeRef value
) {
2334 CFArrayRef exceptions
= SecPathBuilderGetExceptions(pvc
->builder
);
2335 if (!exceptions
) { return false; }
2336 CFIndex exceptionsCount
= CFArrayGetCount(exceptions
);
2338 /* There are two types of exceptions:
2339 * 1. Those that are built from SecTrustCopyExceptions, which are particular to the
2340 * certs in the chain -- as indicated by the SHA1 digest in the exception dictionary.
2341 * 2. On macOS, those built from SecTrustSetOptions, which are generic excepted errors.
2344 CFDictionaryRef options
= CFArrayGetValueAtIndex(exceptions
, 0);
2346 if (exceptionsCount
== 1 && (ix
> 0 || !CFDictionaryContainsKey(options
, kSecCertificateDetailSHA1Digest
))) {
2347 /* SHA1Digest not allowed */
2348 if (CFDictionaryContainsKey(options
, kSecCertificateDetailSHA1Digest
)) { return false; }
2350 if (CFDictionaryContainsKey(options
, key
)) {
2351 /* Special case -- AnchorTrusted only for self-signed certs */
2352 if (CFEqual(kSecPolicyCheckAnchorTrusted
, key
)) {
2353 Boolean isSelfSigned
= false;
2354 SecCertificateRef cert
= SecPathBuilderGetCertificateAtIndex(pvc
->builder
, ix
);
2355 if (!cert
|| (errSecSuccess
!= SecCertificateIsSelfSigned(cert
, &isSelfSigned
)) || !isSelfSigned
) {
2365 if (ix
>= exceptionsCount
) { return false; }
2366 CFDictionaryRef exception
= CFArrayGetValueAtIndex(exceptions
, ix
);
2368 /* Compare the cert hash */
2369 if (!CFDictionaryContainsKey(exception
, kSecCertificateDetailSHA1Digest
)) { return false; }
2370 SecCertificateRef cert
= SecPathBuilderGetCertificateAtIndex(pvc
->builder
, ix
);
2371 if (!CFEqual(SecCertificateGetSHA1Digest(cert
), CFDictionaryGetValue(exception
, kSecCertificateDetailSHA1Digest
))) {
2376 CFTypeRef exceptionValue
= CFDictionaryGetValue(exception
, key
);
2377 if (exceptionValue
&& CFEqual(value
, exceptionValue
)) {
2378 /* Only change result if PVC is already ok */
2379 if (SecPVCIsOkResult(pvc
)) {
2380 // Chains that pass due to exceptions get Proceed result.
2381 pvc
->result
= kSecTrustResultProceed
;
2389 static int32_t detailKeyToCssmErr(CFStringRef key
) {
2392 if (CFEqual(key
, kSecPolicyCheckSSLHostname
)) {
2393 result
= -2147408896; // CSSMERR_APPLETP_HOSTNAME_MISMATCH
2395 else if (CFEqual(key
, kSecPolicyCheckEmail
)) {
2396 result
= -2147408872; // CSSMERR_APPLETP_SMIME_EMAIL_ADDRS_NOT_FOUND
2398 else if (CFEqual(key
, kSecPolicyCheckValidLeaf
) ||
2399 CFEqual(key
, kSecPolicyCheckValidIntermediates
) ||
2400 CFEqual(key
, kSecPolicyCheckValidRoot
)) {
2401 result
= -2147409654; // CSSMERR_TP_CERT_EXPIRED
2407 static bool SecPVCMeetsConstraint(SecPVCRef pvc
, SecCertificateRef certificate
, CFDictionaryRef constraint
);
2409 static bool SecPVCIsAllowedError(SecPVCRef pvc
, CFIndex ix
, CFStringRef key
) {
2410 bool result
= false;
2411 SecCertificatePathVCRef path
= SecPathBuilderGetPath(pvc
->builder
);
2412 CFArrayRef constraints
= SecCertificatePathVCGetUsageConstraintsAtIndex(path
, ix
);
2413 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, ix
);
2414 CFIndex constraintIX
, constraintCount
= CFArrayGetCount(constraints
);
2416 for (constraintIX
= 0; constraintIX
< constraintCount
; constraintIX
++) {
2417 CFDictionaryRef constraint
= (CFDictionaryRef
)CFArrayGetValueAtIndex(constraints
, constraintIX
);
2418 CFNumberRef allowedErrorNumber
= NULL
;
2419 if (!isDictionary(constraint
)) {
2422 allowedErrorNumber
= (CFNumberRef
)CFDictionaryGetValue(constraint
, kSecTrustSettingsAllowedError
);
2423 int32_t allowedErrorValue
= 0;
2424 if (!isNumber(allowedErrorNumber
) || !CFNumberGetValue(allowedErrorNumber
, kCFNumberSInt32Type
, &allowedErrorValue
)) {
2428 if (SecPVCMeetsConstraint(pvc
, cert
, constraint
)) {
2429 if (allowedErrorValue
== detailKeyToCssmErr(key
)) {
2438 static bool SecPVCKeyIsConstraintPolicyOption(SecPVCRef pvc
, CFStringRef key
) {
2439 CFIndex certIX
, certCount
= SecPVCGetCertificateCount(pvc
);
2440 for (certIX
= 0; certIX
< certCount
; certIX
++) {
2441 SecCertificatePathVCRef path
= SecPathBuilderGetPath(pvc
->builder
);
2442 CFArrayRef constraints
= SecCertificatePathVCGetUsageConstraintsAtIndex(path
, certIX
);
2443 CFIndex constraintIX
, constraintCount
= CFArrayGetCount(constraints
);
2444 for (constraintIX
= 0; constraintIX
< constraintCount
; constraintIX
++) {
2445 CFDictionaryRef constraint
= (CFDictionaryRef
)CFArrayGetValueAtIndex(constraints
, constraintIX
);
2446 if (!isDictionary(constraint
)) {
2450 CFDictionaryRef policyOptions
= NULL
;
2451 policyOptions
= (CFDictionaryRef
)CFDictionaryGetValue(constraint
, kSecTrustSettingsPolicyOptions
);
2452 if (policyOptions
&& isDictionary(policyOptions
) &&
2453 CFDictionaryContainsKey(policyOptions
, key
)) {
2461 /* AUDIT[securityd](done):
2462 policy->_options is a caller provided dictionary, only its cf type has
2465 bool SecPVCSetResultForced(SecPVCRef pvc
,
2466 CFStringRef key
, CFIndex ix
, CFTypeRef result
, bool force
) {
2468 secnotice("policy", "cert[%d]: %@ =(%s)[%s]> %@", (int) ix
, key
,
2469 (pvc
->callbacks
== gSecPolicyLeafCallbacks
? "leaf"
2470 : (pvc
->callbacks
== gSecPolicyPathCallbacks
? "path"
2472 (force
? "force" : ""), result
);
2474 /* If this is not something the current policy cares about ignore
2475 this error and return true so our caller continues evaluation. */
2477 /* Either the policy or the usage constraints have to have this key */
2478 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
2479 if (!(SecPVCKeyIsConstraintPolicyOption(pvc
, key
) ||
2480 (policy
&& CFDictionaryContainsKey(policy
->_options
, key
)))) {
2485 /* Check to see if the SecTrustSettings for the certificate in question
2486 tell us to ignore this error. */
2487 if (SecPVCIsAllowedError(pvc
, ix
, key
)) {
2488 secinfo("policy", "cert[%d]: skipped allowed error %@", (int) ix
, key
);
2492 /* Check to see if exceptions tells us to ignore this error. */
2493 if (SecPVCIsExceptedError(pvc
, ix
, key
, result
)) {
2494 secinfo("policy", "cert[%d]: skipped exception error %@", (int) ix
, key
);
2498 /* Check SecPVCIsOkResult to avoid resetting deny or fatal to recoverable */
2499 if (SecPVCIsOkResult(pvc
)) {
2500 pvc
->result
= kSecTrustResultRecoverableTrustFailure
;
2505 CFMutableDictionaryRef detail
=
2506 (CFMutableDictionaryRef
)CFArrayGetValueAtIndex(pvc
->details
, ix
);
2508 /* Perhaps detail should have an array of results per key? As it stands
2509 in the case of multiple policy failures the last failure stands. */
2510 CFDictionarySetValue(detail
, key
, result
);
2515 bool SecPVCSetResult(SecPVCRef pvc
,
2516 CFStringRef key
, CFIndex ix
, CFTypeRef result
) {
2517 return SecPVCSetResultForced(pvc
, key
, ix
, result
, false);
2520 /* AUDIT[securityd](done):
2521 key(ok) is a caller provided.
2522 value(ok, unused) is a caller provided.
2524 static void SecPVCValidateKey(const void *key
, const void *value
,
2526 SecPVCRef pvc
= (SecPVCRef
)context
;
2528 /* If our caller doesn't want full details and we failed earlier there is
2529 no point in doing additional checks. */
2530 if (!SecPVCIsOkResult(pvc
) && !pvc
->details
)
2533 SecPolicyCheckFunction fcn
= (SecPolicyCheckFunction
)
2534 CFDictionaryGetValue(pvc
->callbacks
, key
);
2537 if (pvc
->callbacks
== gSecPolicyLeafCallbacks
) {
2538 if (!CFDictionaryContainsKey(gSecPolicyPathCallbacks
, key
)) {
2539 pvc
->result
= kSecTrustResultOtherError
;
2541 } else if (pvc
->callbacks
== gSecPolicyPathCallbacks
) {
2542 if (!CFDictionaryContainsKey(gSecPolicyLeafCallbacks
, key
)) {
2543 pvc
->result
= kSecTrustResultOtherError
;
2546 /* Non standard validation phase. This may be a new key from the
2547 * pinning DB which is not implemented in this OS version. Log
2549 secwarning("policy: unknown policy key %@, skipping", key
);
2554 fcn(pvc
, (CFStringRef
)key
);
2557 /* AUDIT[securityd](done):
2558 policy->_options is a caller provided dictionary, only its cf type has
2561 SecTrustResultType
SecPVCLeafChecks(SecPVCRef pvc
) {
2562 /* We need to compute details for the leaf. */
2563 CFRetainAssign(pvc
->details
, pvc
->leafDetails
);
2565 CFArrayRef policies
= pvc
->policies
;
2566 CFIndex ix
, count
= CFArrayGetCount(policies
);
2567 for (ix
= 0; ix
< count
; ++ix
) {
2568 SecPolicyRef policy
= (SecPolicyRef
)CFArrayGetValueAtIndex(policies
, ix
);
2570 /* Validate all keys for all policies. */
2571 pvc
->callbacks
= gSecPolicyLeafCallbacks
;
2572 CFDictionaryApplyFunction(policy
->_options
, SecPVCValidateKey
, pvc
);
2575 pvc
->leafResult
= pvc
->result
;
2576 CFRetainAssign(pvc
->leafDetails
, pvc
->details
);
2581 bool SecPVCIsOkResult(SecPVCRef pvc
) {
2582 if (pvc
->result
== kSecTrustResultRecoverableTrustFailure
||
2583 pvc
->result
== kSecTrustResultDeny
||
2584 pvc
->result
== kSecTrustResultFatalTrustFailure
||
2585 pvc
->result
== kSecTrustResultOtherError
) {
2591 bool SecPVCParentCertificateChecks(SecPVCRef pvc
, CFIndex ix
) {
2592 /* Check stuff common to intermediate and anchors. */
2593 CFAbsoluteTime verifyTime
= SecPVCGetVerifyTime(pvc
);
2594 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, ix
);
2595 CFIndex anchor_ix
= SecPVCGetCertificateCount(pvc
) - 1;
2596 bool is_anchor
= (ix
== anchor_ix
&& SecPathBuilderIsAnchored(pvc
->builder
));
2598 if (!SecCertificateIsValid(cert
, verifyTime
)) {
2599 /* Certificate has expired. */
2600 if (!SecPVCSetResult(pvc
, is_anchor
? kSecPolicyCheckValidRoot
2601 : kSecPolicyCheckValidIntermediates
, ix
, kCFBooleanFalse
)) {
2606 if (SecCertificateIsWeakKey(cert
)) {
2607 /* Certificate uses weak key. */
2608 if (!SecPVCSetResult(pvc
, is_anchor
? kSecPolicyCheckWeakRoot
2609 : kSecPolicyCheckWeakIntermediates
, ix
, kCFBooleanFalse
)) {
2615 /* Perform anchor specific checks. */
2616 /* Don't think we have any of these. */
2618 /* Perform intermediate specific checks. */
2620 /* (k) Basic constraints only relevant for v3 and later. */
2621 if (SecCertificateVersion(cert
) >= 3) {
2622 const SecCEBasicConstraints
*bc
=
2623 SecCertificateGetBasicConstraints(cert
);
2624 if (!bc
|| !bc
->isCA
) {
2625 /* Basic constraints not present or not marked as isCA, illegal. */
2626 if (!SecPVCSetResultForced(pvc
, kSecPolicyCheckBasicConstraints
,
2627 ix
, kCFBooleanFalse
, true)) {
2632 /* For a v1 or v2 certificate in an intermediate slot (not a leaf and
2633 not an anchor), we additionally require that the certificate chain
2634 does not end in a v3 or later anchor. [rdar://32204517] */
2635 else if (ix
> 0 && ix
< anchor_ix
) {
2636 SecCertificateRef anchor
= SecPVCGetCertificateAtIndex(pvc
, anchor_ix
);
2637 if (SecCertificateVersion(anchor
) >= 3) {
2638 if (!SecPVCSetResultForced(pvc
, kSecPolicyCheckBasicConstraints
,
2639 ix
, kCFBooleanFalse
, true)) {
2644 /* (l) max_path_length is checked elsewhere. */
2646 /* (n) If a key usage extension is present, verify that the keyCertSign bit is set. */
2647 SecKeyUsage keyUsage
= SecCertificateGetKeyUsage(cert
);
2648 if (keyUsage
&& !(keyUsage
& kSecKeyUsageKeyCertSign
)) {
2649 if (!SecPVCSetResultForced(pvc
, kSecPolicyCheckKeyUsage
,
2650 ix
, kCFBooleanFalse
, true)) {
2657 return SecPVCIsOkResult(pvc
);
2660 static bool SecPVCBlackListedKeyChecks(SecPVCRef pvc
, CFIndex ix
) {
2661 /* Check stuff common to intermediate and anchors. */
2663 SecOTAPKIRef otapkiRef
= SecOTAPKICopyCurrentOTAPKIRef();
2664 if (NULL
!= otapkiRef
)
2666 CFSetRef blackListedKeys
= SecOTAPKICopyBlackListSet(otapkiRef
);
2667 CFRelease(otapkiRef
);
2668 if (NULL
!= blackListedKeys
)
2670 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, ix
);
2671 CFIndex count
= SecPVCGetCertificateCount(pvc
);
2672 bool is_last
= (ix
== count
- 1);
2673 bool is_anchor
= (is_last
&& SecPathBuilderIsAnchored(pvc
->builder
));
2675 /* Check for blacklisted intermediate issuer keys. */
2676 CFDataRef dgst
= SecCertificateCopyPublicKeySHA1Digest(cert
);
2678 /* Check dgst against blacklist. */
2679 if (CFSetContainsValue(blackListedKeys
, dgst
)) {
2680 /* Check allow list for this blacklisted issuer key,
2681 which is the authority key of the issued cert at ix-1.
2683 SecCertificatePathVCRef path
= SecPathBuilderGetPath(pvc
->builder
);
2684 bool allowed
= path
&& SecCertificatePathVCIsAllowlisted(path
);
2686 SecPVCSetResultForced(pvc
, kSecPolicyCheckBlackListedKey
,
2687 ix
, kCFBooleanFalse
, true);
2688 pvc
->result
= kSecTrustResultFatalTrustFailure
;
2694 CFRelease(blackListedKeys
);
2695 return SecPVCIsOkResult(pvc
);
2702 static bool SecPVCGrayListedKeyChecks(SecPVCRef pvc
, CFIndex ix
)
2704 /* Check stuff common to intermediate and anchors. */
2705 SecOTAPKIRef otapkiRef
= SecOTAPKICopyCurrentOTAPKIRef();
2706 if (NULL
!= otapkiRef
)
2708 CFSetRef grayListKeys
= SecOTAPKICopyGrayList(otapkiRef
);
2709 CFRelease(otapkiRef
);
2710 if (NULL
!= grayListKeys
)
2712 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, ix
);
2713 CFIndex count
= SecPVCGetCertificateCount(pvc
);
2714 bool is_last
= (ix
== count
- 1);
2715 bool is_anchor
= (is_last
&& SecPathBuilderIsAnchored(pvc
->builder
));
2717 /* Check for gray listed intermediate issuer keys. */
2718 CFDataRef dgst
= SecCertificateCopyPublicKeySHA1Digest(cert
);
2720 /* Check dgst against gray list. */
2721 if (CFSetContainsValue(grayListKeys
, dgst
)) {
2722 /* Check allow list for this graylisted issuer key,
2723 which is the authority key of the issued cert at ix-1.
2725 SecCertificatePathVCRef path
= SecPathBuilderGetPath(pvc
->builder
);
2726 bool allowed
= path
&& SecCertificatePathVCIsAllowlisted(path
);
2728 SecPVCSetResultForced(pvc
, kSecPolicyCheckGrayListedKey
,
2729 ix
, kCFBooleanFalse
, true);
2735 CFRelease(grayListKeys
);
2736 return SecPVCIsOkResult(pvc
);
2743 static bool SecPVCContainsPolicy(SecPVCRef pvc
, CFStringRef searchOid
, CFStringRef searchName
, CFIndex
*policyIX
) {
2744 if (!isString(searchName
) && !isString(searchOid
)) {
2747 CFArrayRef policies
= pvc
->policies
;
2748 CFIndex ix
, count
= CFArrayGetCount(policies
);
2749 for (ix
= 0; ix
< count
; ++ix
) {
2750 SecPolicyRef policy
= (SecPolicyRef
)CFArrayGetValueAtIndex(policies
, ix
);
2751 CFStringRef policyName
= SecPolicyGetName(policy
);
2752 CFStringRef policyOid
= SecPolicyGetOidString(policy
);
2753 /* Prefer a match of both name and OID */
2754 if (searchOid
&& searchName
&& policyOid
&& policyName
) {
2755 if (CFEqual(searchOid
, policyOid
) &&
2756 CFEqual(searchName
, policyName
)) {
2757 if (policyIX
) { *policyIX
= ix
; }
2761 /* Next best is just OID. */
2762 if (!searchName
&& searchOid
&& policyOid
) {
2763 if (CFEqual(searchOid
, policyOid
)) {
2764 if (policyIX
) { *policyIX
= ix
; }
2768 if (!searchOid
&& searchName
&& policyName
) {
2769 if (CFEqual(searchName
, policyName
)) {
2770 if (policyIX
) { *policyIX
= ix
; }
2778 static bool SecPVCContainsString(SecPVCRef pvc
, CFIndex policyIX
, CFStringRef stringValue
) {
2779 if (!isString(stringValue
)) {
2782 bool result
= false;
2784 CFStringRef tmpStringValue
= NULL
;
2785 if (CFStringGetCharacterAtIndex(stringValue
, CFStringGetLength(stringValue
) -1) == (UniChar
)0x0000) {
2786 tmpStringValue
= CFStringCreateTruncatedCopy(stringValue
, CFStringGetLength(stringValue
) - 1);
2788 tmpStringValue
= CFStringCreateCopy(NULL
, stringValue
);
2790 if (policyIX
>= 0 && policyIX
< CFArrayGetCount(pvc
->policies
)) {
2791 SecPolicyRef policy
= (SecPolicyRef
)CFArrayGetValueAtIndex(pvc
->policies
, policyIX
);
2792 /* Have to look for all the possible locations of name string */
2793 CFStringRef policyString
= NULL
;
2794 policyString
= CFDictionaryGetValue(policy
->_options
, kSecPolicyCheckSSLHostname
);
2795 if (!policyString
) {
2796 policyString
= CFDictionaryGetValue(policy
->_options
, kSecPolicyCheckEmail
);
2798 if (policyString
&& (CFStringCompare(tmpStringValue
, policyString
, kCFCompareCaseInsensitive
) == kCFCompareEqualTo
)) {
2803 CFArrayRef policyStrings
= NULL
;
2804 policyStrings
= CFDictionaryGetValue(policy
->_options
, kSecPolicyCheckEAPTrustedServerNames
);
2805 if (policyStrings
&& CFArrayContainsValue(policyStrings
,
2806 CFRangeMake(0, CFArrayGetCount(policyStrings
)),
2814 CFReleaseNull(tmpStringValue
);
2819 static uint32_t ts_key_usage_for_kuNumber(CFNumberRef keyUsageNumber
) {
2820 uint32_t ourTSKeyUsage
= 0;
2821 uint32_t keyUsage
= 0;
2822 if (keyUsageNumber
&&
2823 CFNumberGetValue(keyUsageNumber
, kCFNumberSInt32Type
, &keyUsage
)) {
2824 if (keyUsage
& kSecKeyUsageDigitalSignature
) {
2825 ourTSKeyUsage
|= kSecTrustSettingsKeyUseSignature
;
2827 if (keyUsage
& kSecKeyUsageDataEncipherment
) {
2828 ourTSKeyUsage
|= kSecTrustSettingsKeyUseEnDecryptData
;
2830 if (keyUsage
& kSecKeyUsageKeyEncipherment
) {
2831 ourTSKeyUsage
|= kSecTrustSettingsKeyUseEnDecryptKey
;
2833 if (keyUsage
& kSecKeyUsageKeyAgreement
) {
2834 ourTSKeyUsage
|= kSecTrustSettingsKeyUseKeyExchange
;
2836 if (keyUsage
== kSecKeyUsageAll
) {
2837 ourTSKeyUsage
= kSecTrustSettingsKeyUseAny
;
2840 return ourTSKeyUsage
;
2843 static uint32_t ts_key_usage_for_policy(SecPolicyRef policy
) {
2844 uint32_t ourTSKeyUsage
= 0;
2845 CFTypeRef policyKeyUsageType
= NULL
;
2847 policyKeyUsageType
= (CFTypeRef
)CFDictionaryGetValue(policy
->_options
, kSecPolicyCheckKeyUsage
);
2848 if (isArray(policyKeyUsageType
)) {
2849 CFIndex ix
, count
= CFArrayGetCount(policyKeyUsageType
);
2850 for (ix
= 0; ix
< count
; ix
++) {
2851 CFNumberRef policyKeyUsageNumber
= NULL
;
2852 policyKeyUsageNumber
= (CFNumberRef
)CFArrayGetValueAtIndex(policyKeyUsageType
, ix
);
2853 ourTSKeyUsage
|= ts_key_usage_for_kuNumber(policyKeyUsageNumber
);
2855 } else if (isNumber(policyKeyUsageType
)) {
2856 ourTSKeyUsage
|= ts_key_usage_for_kuNumber(policyKeyUsageType
);
2859 return ourTSKeyUsage
;
2862 static bool SecPVCContainsTrustSettingsKeyUsage(SecPVCRef pvc
,
2863 SecCertificateRef certificate
, CFIndex policyIX
, CFNumberRef keyUsageNumber
) {
2864 int64_t keyUsageValue
= 0;
2865 uint32_t ourKeyUsage
= 0;
2867 if (!isNumber(keyUsageNumber
) || !CFNumberGetValue(keyUsageNumber
, kCFNumberSInt64Type
, &keyUsageValue
)) {
2871 if (keyUsageValue
== kSecTrustSettingsKeyUseAny
) {
2875 /* We're using the key for revocation if we have the OCSPSigner policy.
2876 * @@@ If we support CRLs, we'd need to check for that policy here too.
2878 if (SecPVCContainsPolicy(pvc
, kSecPolicyAppleOCSPSigner
, NULL
, NULL
)) {
2879 ourKeyUsage
|= kSecTrustSettingsKeyUseSignRevocation
;
2882 /* We're using the key for verifying a cert if it's a root/intermediate
2883 * in the chain. If the cert isn't in the path yet, we're about to add it,
2884 * so it's a root/intermediate. If there is no path, this is the leaf.
2886 CFIndex pathIndex
= -1;
2887 SecCertificatePathVCRef path
= SecPathBuilderGetPath(pvc
->builder
);
2889 pathIndex
= SecCertificatePathVCGetIndexOfCertificate(path
, certificate
);
2893 if (pathIndex
!= 0) {
2894 ourKeyUsage
|= kSecTrustSettingsKeyUseSignCert
;
2897 /* The rest of the key usages may be specified by the policy(ies). */
2898 if (policyIX
>= 0 && policyIX
< CFArrayGetCount(pvc
->policies
)) {
2899 SecPolicyRef policy
= (SecPolicyRef
)CFArrayGetValueAtIndex(pvc
->policies
, policyIX
);
2900 ourKeyUsage
|= ts_key_usage_for_policy(policy
);
2902 /* Get key usage from ALL policies */
2903 CFIndex ix
, count
= CFArrayGetCount(pvc
->policies
);
2904 for (ix
= 0; ix
< count
; ix
++) {
2905 SecPolicyRef policy
= (SecPolicyRef
)CFArrayGetValueAtIndex(pvc
->policies
, ix
);
2906 ourKeyUsage
|= ts_key_usage_for_policy(policy
);
2910 if (ourKeyUsage
== (uint32_t)(keyUsageValue
& 0x00ffffffff)) {
2918 #include <Security/SecTrustedApplicationPriv.h>
2919 #include <Security/SecTask.h>
2920 #include <Security/SecTaskPriv.h>
2921 #include <bsm/libbsm.h>
2922 #include <libproc.h>
2924 extern OSStatus
SecTaskValidateForRequirement(SecTaskRef task
, CFStringRef requirement
);
2926 static bool SecPVCCallerIsApplication(CFDataRef clientAuditToken
, CFTypeRef appRef
) {
2927 bool result
= false;
2928 audit_token_t auditToken
= {};
2929 SecTaskRef task
= NULL
;
2930 SecRequirementRef requirement
= NULL
;
2931 CFStringRef stringRequirement
= NULL
;
2933 require(appRef
&& clientAuditToken
, out
);
2934 require(CFGetTypeID(appRef
) == SecTrustedApplicationGetTypeID(), out
);
2935 require_noerr(SecTrustedApplicationCopyRequirement((SecTrustedApplicationRef
)appRef
, &requirement
), out
);
2936 require(requirement
, out
);
2937 require_noerr(SecRequirementsCopyString(requirement
, kSecCSDefaultFlags
, &stringRequirement
), out
);
2938 require(stringRequirement
, out
);
2940 require(sizeof(auditToken
) == CFDataGetLength(clientAuditToken
), out
);
2941 CFDataGetBytes(clientAuditToken
, CFRangeMake(0, sizeof(auditToken
)), (uint8_t *)&auditToken
);
2942 require(task
= SecTaskCreateWithAuditToken(NULL
, auditToken
), out
);
2944 if(errSecSuccess
== SecTaskValidateForRequirement(task
, stringRequirement
)) {
2949 CFReleaseNull(task
);
2950 CFReleaseNull(requirement
);
2951 CFReleaseNull(stringRequirement
);
2956 static bool SecPVCContainsTrustSettingsPolicyOption(SecPVCRef pvc
, CFDictionaryRef options
) {
2957 if (!isDictionary(options
)) {
2962 CFDictionaryRef currentCallbacks
= pvc
->callbacks
;
2964 /* We need to run the leaf and path checks using these options. */
2965 pvc
->callbacks
= gSecPolicyLeafCallbacks
;
2966 CFDictionaryApplyFunction(options
, SecPVCValidateKey
, pvc
);
2968 pvc
->callbacks
= gSecPolicyPathCallbacks
;
2969 CFDictionaryApplyFunction(options
, SecPVCValidateKey
, pvc
);
2972 pvc
->callbacks
= currentCallbacks
;
2974 /* Our work here is done; no need to claim a match */
2978 static bool SecPVCMeetsConstraint(SecPVCRef pvc
, SecCertificateRef certificate
, CFDictionaryRef constraint
) {
2979 CFStringRef policyOid
= NULL
, policyString
= NULL
, policyName
= NULL
;
2980 CFNumberRef keyUsageNumber
= NULL
;
2981 CFTypeRef trustedApplicationData
= NULL
;
2982 CFDictionaryRef policyOptions
= NULL
;
2984 bool policyMatch
= false, policyStringMatch
= false, applicationMatch
= false ,
2985 keyUsageMatch
= false, policyOptionMatch
= false;
2986 bool result
= false;
2988 #if TARGET_OS_MAC && !TARGET_OS_IPHONE
2989 /* OS X returns a SecPolicyRef in the constraints. Convert to the oid string. */
2990 SecPolicyRef policy
= NULL
;
2991 policy
= (SecPolicyRef
)CFDictionaryGetValue(constraint
, kSecTrustSettingsPolicy
);
2992 policyOid
= (policy
) ? policy
->_oid
: NULL
;
2994 policyOid
= (CFStringRef
)CFDictionaryGetValue(constraint
, kSecTrustSettingsPolicy
);
2996 policyName
= (CFStringRef
)CFDictionaryGetValue(constraint
, kSecTrustSettingsPolicyName
);
2997 policyString
= (CFStringRef
)CFDictionaryGetValue(constraint
, kSecTrustSettingsPolicyString
);
2998 keyUsageNumber
= (CFNumberRef
)CFDictionaryGetValue(constraint
, kSecTrustSettingsKeyUsage
);
2999 policyOptions
= (CFDictionaryRef
)CFDictionaryGetValue(constraint
, kSecTrustSettingsPolicyOptions
);
3001 CFIndex policyIX
= -1;
3002 policyMatch
= SecPVCContainsPolicy(pvc
, policyOid
, policyName
, &policyIX
);
3003 policyStringMatch
= SecPVCContainsString(pvc
, policyIX
, policyString
);
3004 keyUsageMatch
= SecPVCContainsTrustSettingsKeyUsage(pvc
, certificate
, policyIX
, keyUsageNumber
);
3005 policyOptionMatch
= SecPVCContainsTrustSettingsPolicyOption(pvc
, policyOptions
);
3007 #if TARGET_OS_MAC && !TARGET_OS_IPHONE
3008 trustedApplicationData
= CFDictionaryGetValue(constraint
, kSecTrustSettingsApplication
);
3009 CFDataRef clientAuditToken
= SecPathBuilderCopyClientAuditToken(pvc
->builder
);
3010 applicationMatch
= SecPVCCallerIsApplication(clientAuditToken
, trustedApplicationData
);
3011 CFReleaseNull(clientAuditToken
);
3013 if(CFDictionaryContainsKey(constraint
, kSecTrustSettingsApplication
)) {
3014 secerror("kSecTrustSettingsApplication is not yet supported on this platform");
3018 /* If we either didn't find the parameter in the dictionary or we got a match
3019 * against that parameter, for all possible parameters in the dictionary, then
3020 * this trust setting result applies to the output. */
3021 if (((!policyOid
&& !policyName
) || policyMatch
) &&
3022 (!policyString
|| policyStringMatch
) &&
3023 (!trustedApplicationData
|| applicationMatch
) &&
3024 (!keyUsageNumber
|| keyUsageMatch
) &&
3025 (!policyOptions
|| policyOptionMatch
)) {
3032 SecTrustSettingsResult
SecPVCGetTrustSettingsResult(SecPVCRef pvc
, SecCertificateRef certificate
, CFArrayRef constraints
) {
3033 SecTrustSettingsResult result
= kSecTrustSettingsResultInvalid
;
3034 CFIndex constraintIX
, constraintCount
= CFArrayGetCount(constraints
);
3035 for (constraintIX
= 0; constraintIX
< constraintCount
; constraintIX
++) {
3036 CFDictionaryRef constraint
= (CFDictionaryRef
)CFArrayGetValueAtIndex(constraints
, constraintIX
);
3037 if (!isDictionary(constraint
)) {
3041 CFNumberRef resultNumber
= NULL
;
3042 resultNumber
= (CFNumberRef
)CFDictionaryGetValue(constraint
, kSecTrustSettingsResult
);
3043 uint32_t resultValue
= kSecTrustSettingsResultInvalid
;
3044 if (!isNumber(resultNumber
) || !CFNumberGetValue(resultNumber
, kCFNumberSInt32Type
, &resultValue
)) {
3045 /* no SecTrustSettingsResult entry defaults to TrustRoot*/
3046 resultValue
= kSecTrustSettingsResultTrustRoot
;
3049 if (SecPVCMeetsConstraint(pvc
, certificate
, constraint
)) {
3050 result
= resultValue
;
3057 static void SecPVCCheckUsageConstraints(SecPVCRef pvc
) {
3058 CFIndex certIX
, certCount
= SecPVCGetCertificateCount(pvc
);
3059 for (certIX
= 0; certIX
< certCount
; certIX
++) {
3060 SecCertificatePathVCRef path
= SecPathBuilderGetPath(pvc
->builder
);
3061 CFArrayRef constraints
= SecCertificatePathVCGetUsageConstraintsAtIndex(path
, certIX
);
3062 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, certIX
);
3063 SecTrustSettingsResult result
= SecPVCGetTrustSettingsResult(pvc
, cert
, constraints
);
3065 /* Set the pvc trust result based on the usage constraints and anchor source. */
3066 if (result
== kSecTrustSettingsResultDeny
) {
3067 SecPVCSetResultForced(pvc
, kSecPolicyCheckUsageConstraints
, certIX
, kCFBooleanFalse
, true);
3068 pvc
->result
= kSecTrustResultDeny
;
3069 } else if ((result
== kSecTrustSettingsResultTrustRoot
|| result
== kSecTrustSettingsResultTrustAsRoot
||
3070 result
== kSecTrustSettingsResultInvalid
) && SecPVCIsOkResult(pvc
)) {
3071 /* If we already think the PVC is ok and this cert is from one of the user/
3072 * admin anchor sources, trustRoot, trustAsRoot, and Invalid (no constraints),
3073 * all mean we should use the special "Proceed" trust result. */
3074 #if TARGET_OS_IPHONE
3075 if (SecPathBuilderIsAnchorSource(pvc
->builder
, kSecUserAnchorSource
) &&
3076 SecCertificateSourceContains(kSecUserAnchorSource
, cert
)) {
3078 if (SecPathBuilderIsAnchorSource(pvc
->builder
, kSecLegacyAnchorSource
) &&
3079 SecCertificateSourceContains(kSecLegacyAnchorSource
, cert
)) {
3081 pvc
->result
= kSecTrustResultProceed
;
3087 #define kSecPolicySHA256Size 32
3088 static const UInt8 kTestDateConstraintsRoot
[kSecPolicySHA256Size
] = {
3089 0x51,0xA0,0xF3,0x1F,0xC0,0x1D,0xEC,0x87,0x32,0xB6,0xFD,0x13,0x6A,0x43,0x4D,0x6C,
3090 0x87,0xCD,0x62,0xE0,0x38,0xB4,0xFB,0xD6,0x40,0xB0,0xFD,0x62,0x4D,0x1F,0xCF,0x6D
3092 static const UInt8 kWS_CA1_G2
[kSecPolicySHA256Size
] = {
3093 0xD4,0x87,0xA5,0x6F,0x83,0xB0,0x74,0x82,0xE8,0x5E,0x96,0x33,0x94,0xC1,0xEC,0xC2,
3094 0xC9,0xE5,0x1D,0x09,0x03,0xEE,0x94,0x6B,0x02,0xC3,0x01,0x58,0x1E,0xD9,0x9E,0x16
3096 static const UInt8 kWS_CA1_NEW
[kSecPolicySHA256Size
] = {
3097 0x4B,0x22,0xD5,0xA6,0xAE,0xC9,0x9F,0x3C,0xDB,0x79,0xAA,0x5E,0xC0,0x68,0x38,0x47,
3098 0x9C,0xD5,0xEC,0xBA,0x71,0x64,0xF7,0xF2,0x2D,0xC1,0xD6,0x5F,0x63,0xD8,0x57,0x08
3100 static const UInt8 kWS_CA2_NEW
[kSecPolicySHA256Size
] = {
3101 0xD6,0xF0,0x34,0xBD,0x94,0xAA,0x23,0x3F,0x02,0x97,0xEC,0xA4,0x24,0x5B,0x28,0x39,
3102 0x73,0xE4,0x47,0xAA,0x59,0x0F,0x31,0x0C,0x77,0xF4,0x8F,0xDF,0x83,0x11,0x22,0x54
3104 static const UInt8 kWS_ECC
[kSecPolicySHA256Size
] = {
3105 0x8B,0x45,0xDA,0x1C,0x06,0xF7,0x91,0xEB,0x0C,0xAB,0xF2,0x6B,0xE5,0x88,0xF5,0xFB,
3106 0x23,0x16,0x5C,0x2E,0x61,0x4B,0xF8,0x85,0x56,0x2D,0x0D,0xCE,0x50,0xB2,0x9B,0x02
3108 static const UInt8 kSC_SFSCA
[kSecPolicySHA256Size
] = {
3109 0xC7,0x66,0xA9,0xBE,0xF2,0xD4,0x07,0x1C,0x86,0x3A,0x31,0xAA,0x49,0x20,0xE8,0x13,
3110 0xB2,0xD1,0x98,0x60,0x8C,0xB7,0xB7,0xCF,0xE2,0x11,0x43,0xB8,0x36,0xDF,0x09,0xEA
3112 static const UInt8 kSC_SHA2
[kSecPolicySHA256Size
] = {
3113 0xE1,0x78,0x90,0xEE,0x09,0xA3,0xFB,0xF4,0xF4,0x8B,0x9C,0x41,0x4A,0x17,0xD6,0x37,
3114 0xB7,0xA5,0x06,0x47,0xE9,0xBC,0x75,0x23,0x22,0x72,0x7F,0xCC,0x17,0x42,0xA9,0x11
3116 static const UInt8 kSC_G2
[kSecPolicySHA256Size
] = {
3117 0xC7,0xBA,0x65,0x67,0xDE,0x93,0xA7,0x98,0xAE,0x1F,0xAA,0x79,0x1E,0x71,0x2D,0x37,
3118 0x8F,0xAE,0x1F,0x93,0xC4,0x39,0x7F,0xEA,0x44,0x1B,0xB7,0xCB,0xE6,0xFD,0x59,0x95
3121 static void SecPVCCheckIssuerDateConstraints(SecPVCRef pvc
) {
3122 static CFSetRef sConstrainedRoots
= NULL
;
3123 static dispatch_once_t _t
;
3124 dispatch_once(&_t
, ^{
3125 const UInt8
*v_hashes
[] = {
3126 kWS_CA1_G2
, kWS_CA1_NEW
, kWS_CA2_NEW
, kWS_ECC
,
3127 kSC_SFSCA
, kSC_SHA2
, kSC_G2
, kTestDateConstraintsRoot
3129 CFMutableSetRef set
= CFSetCreateMutable(NULL
, 0, &kCFTypeSetCallBacks
);
3130 CFIndex ix
, count
= sizeof(v_hashes
)/sizeof(*v_hashes
);
3131 for (ix
=0; ix
<count
; ix
++) {
3132 CFDataRef hash
= CFDataCreateWithBytesNoCopy(NULL
, v_hashes
[ix
],
3133 kSecPolicySHA256Size
, kCFAllocatorNull
);
3135 CFSetAddValue(set
, hash
);
3139 sConstrainedRoots
= set
;
3142 bool shouldDeny
= false;
3143 CFIndex certIX
, certCount
= SecPVCGetCertificateCount(pvc
);
3144 for (certIX
= certCount
- 1; certIX
>= 0 && !shouldDeny
; certIX
--) {
3145 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, certIX
);
3146 CFDataRef sha256
= SecCertificateCopySHA256Digest(cert
);
3147 if (sha256
&& CFSetContainsValue(sConstrainedRoots
, sha256
)) {
3148 /* matched a constrained root; check notBefore dates on all its children. */
3149 CFIndex childIX
= certIX
;
3150 while (--childIX
>= 0) {
3151 SecCertificateRef child
= SecPVCGetCertificateAtIndex(pvc
, childIX
);
3152 /* 1 Dec 2016 00:00:00 GMT */
3153 if (child
&& (CFAbsoluteTime
)502243200.0 <= SecCertificateNotValidBefore(child
)) {
3154 SecPVCSetResultForced(pvc
, kSecPolicyCheckBlackListedKey
, certIX
, kCFBooleanFalse
, true);
3155 pvc
->result
= kSecTrustResultFatalTrustFailure
;
3161 CFReleaseNull(sha256
);
3165 /* AUDIT[securityd](done):
3166 policy->_options is a caller provided dictionary, only its cf type has
3169 void SecPVCPathChecks(SecPVCRef pvc
) {
3170 secdebug("policy", "begin path: %@", SecPathBuilderGetPath(pvc
->builder
));
3171 SecCertificatePathVCRef path
= SecPathBuilderGetPath(pvc
->builder
);
3172 /* This needs to be initialized before we call any function that might call
3173 SecPVCSetResultForced(). */
3175 SecPolicyCheckIdLinkage(pvc
, kSecPolicyCheckIdLinkage
);
3176 if (SecPVCIsOkResult(pvc
) || pvc
->details
) {
3177 /* @@@ This theoretically only needs to be done once per path, but since
3178 this function affects the pvc result, we'll run it every time. */
3179 SecPolicyCheckBasicCertificateProcessing(pvc
,
3180 kSecPolicyCheckBasicCertificateProcessing
);
3183 CFArrayRef policies
= pvc
->policies
;
3184 CFIndex count
= CFArrayGetCount(policies
);
3185 for (; pvc
->policyIX
< count
; ++pvc
->policyIX
) {
3186 /* Validate all keys for all policies. */
3187 pvc
->callbacks
= gSecPolicyPathCallbacks
;
3188 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
3189 CFDictionaryApplyFunction(policy
->_options
, SecPVCValidateKey
, pvc
);
3190 if (!SecPVCIsOkResult(pvc
) && !pvc
->details
)
3197 /* Check whether the TrustSettings say to deny a cert in the path. */
3198 SecPVCCheckUsageConstraints(pvc
);
3200 /* Check for Blocklisted certs */
3201 SecPVCCheckIssuerDateConstraints(pvc
);
3203 count
= SecCertificatePathVCGetCount(path
);
3204 for (ix
= 1; ix
< count
; ix
++) {
3205 SecPVCGrayListedKeyChecks(pvc
, ix
);
3206 SecPVCBlackListedKeyChecks(pvc
, ix
);
3209 /* Path-based check tests. */
3210 if (!SecCertificatePathVCIsPathValidated(path
)) {
3211 bool ev_check_ok
= false;
3212 if (SecCertificatePathVCIsOptionallyEV(path
)) {
3213 SecTrustResultType pre_ev_check_result
= pvc
->result
;
3214 SecPolicyCheckEV(pvc
, kSecPolicyCheckExtendedValidation
);
3215 ev_check_ok
= SecPVCIsOkResult(pvc
);
3216 /* If ev checking failed, we still want to accept this chain
3217 as a non EV one, if it was valid as such. */
3218 pvc
->result
= pre_ev_check_result
;
3222 /* This call will set the value of pvc->is_ct, but won't change the result (pvc->result) */
3223 SecPolicyCheckCT(pvc
, kSecPolicyCheckCertificateTransparency
);
3225 /* Certs are only EV if they are also CT verified */
3226 if (ev_check_ok
&& SecCertificatePathVCIsCT(path
)) {
3227 SecCertificatePathVCSetIsEV(path
, true);
3232 secdebug("policy", "end %strusted path: %@",
3233 (SecPVCIsOkResult(pvc
) ? "" : "not "), SecPathBuilderGetPath(pvc
->builder
));
3235 SecCertificatePathVCSetPathValidated(SecPathBuilderGetPath(pvc
->builder
));
3239 void SecPVCPathCheckRevocationRequired(SecPVCRef pvc
) {
3240 SecCertificatePathVCRef path
= SecPathBuilderGetPath(pvc
->builder
);
3241 CFIndex ix
, certCount
= SecCertificatePathVCGetCount(path
);
3242 for (ix
= 0; ix
< certCount
; ix
++) {
3243 /* If we require revocation (for that cert per the SecCertificateVCRef or
3245 if (SecCertificatePathVCIsRevocationRequiredForCertificateAtIndex(path
, ix
) ||
3246 ((ix
== 0) && pvc
->require_revocation_response
)) {
3247 /* Do we have a valid revocation response? */
3248 SecRVCRef rvc
= SecCertificatePathVCGetRVCAtIndex(path
, ix
);
3249 if (SecRVCGetEarliestNextUpdate(rvc
) == NULL_TIME
) {
3250 SecPVCSetResultForced(pvc
, kSecPolicyCheckRevocationResponseRequired
,
3251 ix
, kCFBooleanFalse
, true);