2 * Copyright (c) 2008-2018 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
25 * SecPolicyServer.c - Engine for evaluating certificate paths against trust policies.
28 #include <securityd/SecPolicyServer.h>
29 #include <Security/SecPolicyInternal.h>
30 #include <Security/SecPolicyPriv.h>
31 #include <Security/SecTask.h>
32 #include <securityd/policytree.h>
33 #include <securityd/nameconstraints.h>
34 #include <CoreFoundation/CFTimeZone.h>
36 #include <libDER/oids.h>
37 #include <CoreFoundation/CFNumber.h>
38 #include <Security/SecCertificateInternal.h>
39 #include <AssertMacros.h>
40 #include <utilities/debugging.h>
41 #include <utilities/SecInternalReleasePriv.h>
42 #include <security_asn1/SecAsn1Coder.h>
43 #include <security_asn1/ocspTemplates.h>
44 #include <security_asn1/oidsalg.h>
45 #include <security_asn1/oidsocsp.h>
46 #include <CommonCrypto/CommonDigest.h>
47 #include <Security/SecFramework.h>
48 #include <Security/SecPolicyInternal.h>
49 #include <Security/SecTrustPriv.h>
50 #include <Security/SecTrustInternal.h>
51 #include <Security/SecTrustSettingsPriv.h>
52 #include <Security/SecInternal.h>
53 #include <Security/SecKeyPriv.h>
54 #include <Security/SecTask.h>
55 #include <SystemConfiguration/SCDynamicStoreCopySpecific.h>
57 #include <securityd/SecTrustServer.h>
58 #include <securityd/SecTrustLoggingServer.h>
59 #include <securityd/SecRevocationServer.h>
60 #include <securityd/SecCertificateServer.h>
61 #include <securityd/SecCertificateSource.h>
62 #include <securityd/SecOCSPResponse.h>
63 #include <securityd/SecTrustStoreServer.h>
64 #include <utilities/array_size.h>
65 #include <utilities/SecCFWrappers.h>
66 #include <utilities/SecAppleAnchorPriv.h>
67 #include "OTATrustUtilities.h"
68 #include "personalization.h"
69 #include <sys/codesign.h>
72 #include <Security/SecTaskPriv.h>
75 /* Set this to 1 to dump the ocsp responses received in DER form in /tmp. */
76 #ifndef DUMP_OCSPRESPONSES
77 #define DUMP_OCSPRESPONSES 0
80 #if DUMP_OCSPRESPONSES
85 static void secdumpdata(CFDataRef data
, const char *name
) {
86 int fd
= open(name
, O_CREAT
| O_WRONLY
| O_TRUNC
, 0666);
87 write(fd
, CFDataGetBytePtr(data
), CFDataGetLength(data
));
94 /********************************************************
95 ****************** SecPolicy object ********************
96 ********************************************************/
98 static SecCertificateRef
SecPVCGetCertificateAtIndex(SecPVCRef pvc
, CFIndex ix
);
99 static CFIndex
SecPVCGetCertificateCount(SecPVCRef pvc
);
100 static CFAbsoluteTime
SecPVCGetVerifyTime(SecPVCRef pvc
);
102 static CFMutableDictionaryRef gSecPolicyLeafCallbacks
= NULL
;
103 static CFMutableDictionaryRef gSecPolicyPathCallbacks
= NULL
;
105 static CFArrayRef
SecPolicyAnchorDigestsForEVPolicy(const DERItem
*policyOID
)
107 CFArrayRef result
= NULL
;
108 SecOTAPKIRef otapkiRef
= SecOTAPKICopyCurrentOTAPKIRef();
109 if (NULL
== otapkiRef
)
114 CFDictionaryRef evToPolicyAnchorDigest
= SecOTAPKICopyEVPolicyToAnchorMapping(otapkiRef
);
115 CFRelease(otapkiRef
);
117 if (NULL
== evToPolicyAnchorDigest
)
122 CFArrayRef roots
= NULL
;
123 CFStringRef oid
= SecDERItemCopyOIDDecimalRepresentation(kCFAllocatorDefault
, policyOID
);
124 if (oid
&& evToPolicyAnchorDigest
)
126 result
= (CFArrayRef
)CFDictionaryGetValue(evToPolicyAnchorDigest
, oid
);
127 if (roots
&& CFGetTypeID(result
) != CFArrayGetTypeID())
129 secerror("EVRoot.plist has non array value");
134 CFReleaseSafe(evToPolicyAnchorDigest
);
139 bool SecPolicyIsEVPolicy(const DERItem
*policyOID
) {
140 return SecPolicyAnchorDigestsForEVPolicy(policyOID
);
143 static bool SecPolicyRootCACertificateIsEV(SecCertificateRef certificate
,
144 policy_set_t valid_policies
) {
145 CFDictionaryRef keySizes
= NULL
;
146 CFNumberRef rsaSize
= NULL
, ecSize
= NULL
;
148 /* Ensure that this certificate is a valid anchor for one of the
149 certificate policy oids specified in the leaf. */
150 CFDataRef digest
= SecCertificateGetSHA1Digest(certificate
);
152 bool good_ev_anchor
= false;
153 for (ix
= valid_policies
; ix
; ix
= ix
->oid_next
) {
154 CFArrayRef digests
= SecPolicyAnchorDigestsForEVPolicy(&ix
->oid
);
155 if (digests
&& CFArrayContainsValue(digests
,
156 CFRangeMake(0, CFArrayGetCount(digests
)), digest
)) {
157 secdebug("ev", "found anchor for policy oid");
158 good_ev_anchor
= true;
162 require_action_quiet(good_ev_anchor
, notEV
, secnotice("ev", "anchor not in plist"));
164 CFAbsoluteTime october2006
= 178761600;
165 if (SecCertificateNotValidBefore(certificate
) >= october2006
) {
166 require_action_quiet(SecCertificateVersion(certificate
) >= 3, notEV
,
167 secnotice("ev", "Anchor issued after October 2006 and is not v3"));
169 if (SecCertificateVersion(certificate
) >= 3
170 && SecCertificateNotValidBefore(certificate
) >= october2006
) {
171 const SecCEBasicConstraints
*bc
= SecCertificateGetBasicConstraints(certificate
);
172 require_action_quiet(bc
&& bc
->isCA
== true, notEV
,
173 secnotice("ev", "Anchor has invalid basic constraints"));
174 SecKeyUsage ku
= SecCertificateGetKeyUsage(certificate
);
175 require_action_quiet((ku
& (kSecKeyUsageKeyCertSign
| kSecKeyUsageCRLSign
))
176 == (kSecKeyUsageKeyCertSign
| kSecKeyUsageCRLSign
), notEV
,
177 secnotice("ev", "Anchor has invalid key usage %u", ku
));
180 /* At least RSA 2048 or ECC NIST P-256. */
181 require_quiet(rsaSize
= CFNumberCreateWithCFIndex(NULL
, 2048), notEV
);
182 require_quiet(ecSize
= CFNumberCreateWithCFIndex(NULL
, 256), notEV
);
183 const void *keys
[] = { kSecAttrKeyTypeRSA
, kSecAttrKeyTypeEC
};
184 const void *values
[] = { rsaSize
, ecSize
};
185 require_quiet(keySizes
= CFDictionaryCreate(NULL
, keys
, values
, 2,
186 &kCFTypeDictionaryKeyCallBacks
,
187 &kCFTypeDictionaryValueCallBacks
), notEV
);
188 require_action_quiet(SecCertificateIsAtLeastMinKeySize(certificate
, keySizes
), notEV
,
189 secnotice("ev", "Anchor's public key is too weak for EV"));
194 CFReleaseNull(rsaSize
);
195 CFReleaseNull(ecSize
);
196 CFReleaseNull(keySizes
);
200 static bool SecPolicySubordinateCACertificateCouldBeEV(SecCertificateRef certificate
) {
201 CFMutableDictionaryRef keySizes
= NULL
;
202 CFNumberRef rsaSize
= NULL
, ecSize
= NULL
;
205 const SecCECertificatePolicies
*cp
;
206 cp
= SecCertificateGetCertificatePolicies(certificate
);
207 require_action_quiet(cp
&& cp
->numPolicies
> 0, notEV
,
208 secnotice("ev", "SubCA missing certificate policies"));
209 CFArrayRef cdp
= SecCertificateGetCRLDistributionPoints(certificate
);
210 require_action_quiet(cdp
&& CFArrayGetCount(cdp
) > 0, notEV
,
211 secnotice("ev", "SubCA missing CRLDP"));
212 const SecCEBasicConstraints
*bc
= SecCertificateGetBasicConstraints(certificate
);
213 require_action_quiet(bc
&& bc
->isCA
== true, notEV
,
214 secnotice("ev", "SubCA has invalid basic constraints"));
215 SecKeyUsage ku
= SecCertificateGetKeyUsage(certificate
);
216 require_action_quiet((ku
& (kSecKeyUsageKeyCertSign
| kSecKeyUsageCRLSign
))
217 == (kSecKeyUsageKeyCertSign
| kSecKeyUsageCRLSign
), notEV
,
218 secnotice("ev", "SubCA has invalid key usage %u", ku
));
220 /* 6.1.5 Key Sizes */
221 CFAbsoluteTime jan2011
= 315532800;
222 CFAbsoluteTime jan2014
= 410227200;
223 require_quiet(ecSize
= CFNumberCreateWithCFIndex(NULL
, 256), notEV
);
224 require_quiet(keySizes
= CFDictionaryCreateMutable(NULL
, 2, &kCFTypeDictionaryKeyCallBacks
,
225 &kCFTypeDictionaryValueCallBacks
), notEV
);
226 CFDictionaryAddValue(keySizes
, kSecAttrKeyTypeEC
, ecSize
);
227 if (SecCertificateNotValidBefore(certificate
) < jan2011
||
228 SecCertificateNotValidAfter(certificate
) < jan2014
) {
229 /* At least RSA 1024 or ECC NIST P-256. */
230 require_quiet(rsaSize
= CFNumberCreateWithCFIndex(NULL
, 1024), notEV
);
231 CFDictionaryAddValue(keySizes
, kSecAttrKeyTypeRSA
, rsaSize
);
232 require_action_quiet(SecCertificateIsAtLeastMinKeySize(certificate
, keySizes
), notEV
,
233 secnotice("ev", "SubCA's public key is too small for issuance before 2011 or expiration before 2014"));
235 /* At least RSA 2028 or ECC NIST P-256. */
236 require_quiet(rsaSize
= CFNumberCreateWithCFIndex(NULL
, 2048), notEV
);
237 CFDictionaryAddValue(keySizes
, kSecAttrKeyTypeRSA
, rsaSize
);
238 require_action_quiet(SecCertificateIsAtLeastMinKeySize(certificate
, keySizes
), notEV
,
239 secnotice("ev", "SubCA's public key is too small for issuance after 2010 or expiration after 2013"));
242 /* 7.1.3 Algorithm Object Identifiers */
243 CFAbsoluteTime jan2016
= 473299200;
244 if (SecCertificateNotValidBefore(certificate
) > jan2016
) {
246 require_action_quiet(SecCertificateGetSignatureHashAlgorithm(certificate
) > kSecSignatureHashAlgorithmSHA1
,
247 notEV
, secnotice("ev", "SubCA was issued with SHA-1 after 2015"));
253 CFReleaseNull(rsaSize
);
254 CFReleaseNull(ecSize
);
255 CFReleaseNull(keySizes
);
259 /********************************************************
260 **************** SecPolicy Callbacks *******************
261 ********************************************************/
262 static void SecPolicyCheckCriticalExtensions(SecPVCRef pvc
,
266 static void SecPolicyCheckIdLinkage(SecPVCRef pvc
,
268 CFIndex ix
, count
= SecPVCGetCertificateCount(pvc
);
269 CFDataRef parentSubjectKeyID
= NULL
;
270 for (ix
= count
- 1; ix
>= 0; --ix
) {
271 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, ix
);
272 /* If the previous certificate in the chain had a SubjectKeyID,
273 make sure it matches the current certificates AuthorityKeyID. */
274 if (parentSubjectKeyID
) {
275 /* @@@ According to RFC 2459 neither AuthorityKeyID nor
276 SubjectKeyID can be critical. Currenty we don't check
278 CFDataRef authorityKeyID
= SecCertificateGetAuthorityKeyID(cert
);
279 if (authorityKeyID
) {
280 if (!CFEqual(parentSubjectKeyID
, authorityKeyID
)) {
281 /* AuthorityKeyID doesn't match issuers SubjectKeyID. */
282 if (!SecPVCSetResult(pvc
, key
, ix
, kCFBooleanFalse
))
288 parentSubjectKeyID
= SecCertificateGetSubjectKeyID(cert
);
292 static void SecPolicyCheckKeyUsage(SecPVCRef pvc
,
294 SecCertificateRef leaf
= SecPVCGetCertificateAtIndex(pvc
, 0);
295 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
296 CFTypeRef xku
= CFDictionaryGetValue(policy
->_options
, key
);
297 if (!SecPolicyCheckCertKeyUsage(leaf
, xku
)) {
298 SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
);
302 /* AUDIT[securityd](done):
303 policy->_options is a caller provided dictionary, only its cf type has
306 static void SecPolicyCheckExtendedKeyUsage(SecPVCRef pvc
, CFStringRef key
) {
307 SecCertificateRef leaf
= SecPVCGetCertificateAtIndex(pvc
, 0);
308 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
309 CFTypeRef xeku
= CFDictionaryGetValue(policy
->_options
, key
);
310 if (!SecPolicyCheckCertExtendedKeyUsage(leaf
, xeku
)){
311 SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
);
315 static void SecPolicyCheckBasicConstraints(SecPVCRef pvc
,
317 //SecPolicyCheckBasicContraintsCommon(pvc, key, false);
320 static void SecPolicyCheckNonEmptySubject(SecPVCRef pvc
,
322 CFIndex ix
, count
= SecPVCGetCertificateCount(pvc
);
323 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
324 CFTypeRef pvcValue
= CFDictionaryGetValue(policy
->_options
, key
);
325 for (ix
= 0; ix
< count
; ++ix
) {
326 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, ix
);
327 if (!SecPolicyCheckCertNonEmptySubject(cert
, pvcValue
)) {
328 if (!SecPVCSetResult(pvc
, key
, ix
, kCFBooleanFalse
))
334 /* AUDIT[securityd](done):
335 policy->_options is a caller provided dictionary, only its cf type has
338 static void SecPolicyCheckSSLHostname(SecPVCRef pvc
,
340 /* @@@ Consider what to do if the caller passes in no hostname. Should
341 we then still fail if the leaf has no dnsNames or IPAddresses at all? */
342 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
343 CFStringRef hostName
= (CFStringRef
)
344 CFDictionaryGetValue(policy
->_options
, key
);
345 if (!isString(hostName
)) {
346 /* @@@ We can't return an error here and making the evaluation fail
347 won't help much either. */
351 SecCertificateRef leaf
= SecPVCGetCertificateAtIndex(pvc
, 0);
352 bool dnsMatch
= SecPolicyCheckCertSSLHostname(leaf
, hostName
);
355 /* Hostname mismatch or no hostnames found in certificate. */
356 SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
);
361 /* AUDIT[securityd](done):
362 policy->_options is a caller provided dictionary, only its cf type has
365 static void SecPolicyCheckEmail(SecPVCRef pvc
, CFStringRef key
) {
366 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
367 CFStringRef email
= (CFStringRef
)CFDictionaryGetValue(policy
->_options
, key
);
368 if (!isString(email
)) {
369 /* We can't return an error here and making the evaluation fail
370 won't help much either. */
374 SecCertificateRef leaf
= SecPVCGetCertificateAtIndex(pvc
, 0);
376 if (!SecPolicyCheckCertEmail(leaf
, email
)) {
377 /* Hostname mismatch or no hostnames found in certificate. */
378 SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
);
382 static void SecPolicyCheckTemporalValidity(SecPVCRef pvc
,
384 CFIndex ix
, count
= SecPVCGetCertificateCount(pvc
);
385 CFAbsoluteTime verifyTime
= SecPVCGetVerifyTime(pvc
);
386 for (ix
= 0; ix
< count
; ++ix
) {
387 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, ix
);
388 if (!SecCertificateIsValid(cert
, verifyTime
)) {
389 /* Intermediate certificate has expired. */
390 if (!SecPVCSetResult(pvc
, key
, ix
, kCFBooleanFalse
))
396 /* AUDIT[securityd](done):
397 policy->_options is a caller provided dictionary, only its cf type has
400 static void SecPolicyCheckIssuerCommonName(SecPVCRef pvc
,
402 CFIndex count
= SecPVCGetCertificateCount(pvc
);
404 /* Can't check intermediates common name if there is no intermediate. */
405 SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
);
409 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, 1);
410 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
411 CFStringRef commonName
=
412 (CFStringRef
)CFDictionaryGetValue(policy
->_options
, key
);
413 if (!isString(commonName
)) {
414 /* @@@ We can't return an error here and making the evaluation fail
415 won't help much either. */
418 if (!SecPolicyCheckCertSubjectCommonName(cert
, commonName
)) {
419 SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
);
423 /* AUDIT[securityd](done):
424 policy->_options is a caller provided dictionary, only its cf type has
427 static void SecPolicyCheckSubjectCommonName(SecPVCRef pvc
,
429 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, 0);
430 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
431 CFStringRef common_name
= (CFStringRef
)CFDictionaryGetValue(policy
->_options
,
433 if (!isString(common_name
)) {
434 /* @@@ We can't return an error here and making the evaluation fail
435 won't help much either. */
438 if (!SecPolicyCheckCertSubjectCommonName(cert
, common_name
)) {
439 SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
);
443 /* AUDIT[securityd](done):
444 policy->_options is a caller provided dictionary, only its cf type has
447 static void SecPolicyCheckSubjectCommonNamePrefix(SecPVCRef pvc
,
449 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, 0);
450 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
451 CFStringRef prefix
= (CFStringRef
)CFDictionaryGetValue(policy
->_options
,
453 if (!isString(prefix
)) {
454 /* @@@ We can't return an error here and making the evaluation fail
455 won't help much either. */
458 if (!SecPolicyCheckCertSubjectCommonNamePrefix(cert
, prefix
)) {
459 SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
);
463 /* AUDIT[securityd](done):
464 policy->_options is a caller provided dictionary, only its cf type has
467 static void SecPolicyCheckSubjectCommonNameTEST(SecPVCRef pvc
,
469 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, 0);
470 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
471 CFStringRef common_name
= (CFStringRef
)CFDictionaryGetValue(policy
->_options
,
473 if (!isString(common_name
)) {
474 /* @@@ We can't return an error here and making the evaluation fail
475 won't help much either. */
478 if (!SecPolicyCheckCertSubjectCommonNameTEST(cert
, common_name
)) {
479 SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
);
483 /* AUDIT[securityd](done):
484 policy->_options is a caller provided dictionary, only its cf type has
487 static void SecPolicyCheckNotValidBefore(SecPVCRef pvc
,
489 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, 0);
490 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
491 CFDateRef date
= (CFDateRef
)CFDictionaryGetValue(policy
->_options
, key
);
493 /* @@@ We can't return an error here and making the evaluation fail
494 won't help much either. */
497 if (!SecPolicyCheckCertNotValidBefore(cert
, date
)) {
498 if (!SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
))
503 /* AUDIT[securityd](done):
504 policy->_options is a caller provided dictionary, only its cf type has
507 static void SecPolicyCheckChainLength(SecPVCRef pvc
,
509 CFIndex count
= SecPVCGetCertificateCount(pvc
);
510 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
511 CFNumberRef chainLength
=
512 (CFNumberRef
)CFDictionaryGetValue(policy
->_options
, key
);
514 if (!chainLength
|| CFGetTypeID(chainLength
) != CFNumberGetTypeID() ||
515 !CFNumberGetValue(chainLength
, kCFNumberCFIndexType
, &value
)) {
516 /* @@@ We can't return an error here and making the evaluation fail
517 won't help much either. */
520 if (value
!= count
) {
521 /* Chain length doesn't match policy requirement. */
522 if (!SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
))
527 static bool isDigestInPolicy(SecPVCRef pvc
, CFStringRef key
, CFDataRef digest
) {
528 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
529 CFTypeRef value
= CFDictionaryGetValue(policy
->_options
, key
);
531 bool foundMatch
= false;
533 foundMatch
= CFEqual(digest
, value
);
534 else if (isArray(value
))
535 foundMatch
= CFArrayContainsValue((CFArrayRef
) value
, CFRangeMake(0, CFArrayGetCount((CFArrayRef
) value
)), digest
);
537 /* @@@ We only support Data and Array but we can't return an error here so.
538 we let the evaluation fail (not much help) and assert in debug. */
545 static void SecPolicyCheckAnchorSHA256(SecPVCRef pvc
, CFStringRef key
) {
546 CFIndex count
= SecPVCGetCertificateCount(pvc
);
547 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, count
- 1);
548 CFDataRef anchorSHA256
= NULL
;
549 anchorSHA256
= SecCertificateCopySHA256Digest(cert
);
551 if (!isDigestInPolicy(pvc
, key
, anchorSHA256
)) {
552 SecPVCSetResult(pvc
, kSecPolicyCheckAnchorSHA256
, count
-1, kCFBooleanFalse
);
555 CFReleaseNull(anchorSHA256
);
560 /* AUDIT[securityd](done):
561 policy->_options is a caller provided dictionary, only its cf type has
564 static void SecPolicyCheckAnchorSHA1(SecPVCRef pvc
,
566 CFIndex count
= SecPVCGetCertificateCount(pvc
);
567 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, count
- 1);
568 CFDataRef anchorSHA1
= SecCertificateGetSHA1Digest(cert
);
570 if (!isDigestInPolicy(pvc
, key
, anchorSHA1
))
571 if (!SecPVCSetResult(pvc
, kSecPolicyCheckAnchorSHA1
, count
-1, kCFBooleanFalse
))
578 Check the SHA256 of SPKI of the first intermediate CA certificate in the path
579 policy->_options is a caller provided dictionary, only its cf type has
582 static void SecPolicyCheckIntermediateSPKISHA256(SecPVCRef pvc
,
584 SecCertificateRef cert
= NULL
;
585 CFDataRef digest
= NULL
;
587 if (SecPVCGetCertificateCount(pvc
) < 2) {
588 SecPVCSetResult(pvc
, kSecPolicyCheckIntermediateSPKISHA256
, 0, kCFBooleanFalse
);
592 cert
= SecPVCGetCertificateAtIndex(pvc
, 1);
593 digest
= SecCertificateCopySubjectPublicKeyInfoSHA256Digest(cert
);
595 if (!isDigestInPolicy(pvc
, key
, digest
)) {
596 SecPVCSetResult(pvc
, kSecPolicyCheckIntermediateSPKISHA256
, 1, kCFBooleanFalse
);
598 CFReleaseNull(digest
);
602 policy->_options is a caller provided dictionary, only its cf type has
605 static void SecPolicyCheckAnchorApple(SecPVCRef pvc
,
607 CFIndex count
= SecPVCGetCertificateCount(pvc
);
608 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, count
- 1);
609 SecAppleTrustAnchorFlags flags
= 0;
612 bool foundMatch
= SecIsAppleTrustAnchor(cert
, flags
);
615 if (!SecPVCSetResult(pvc
, kSecPolicyCheckAnchorApple
, 0, kCFBooleanFalse
))
622 /* AUDIT[securityd](done):
623 policy->_options is a caller provided dictionary, only its cf type has
626 static void SecPolicyCheckSubjectOrganization(SecPVCRef pvc
,
628 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, 0);
629 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
630 CFStringRef org
= (CFStringRef
)CFDictionaryGetValue(policy
->_options
,
632 if (!isString(org
)) {
633 /* @@@ We can't return an error here and making the evaluation fail
634 won't help much either. */
637 if (!SecPolicyCheckCertSubjectOrganization(cert
, org
)) {
638 /* Leaf Subject Organization mismatch. */
639 SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
);
643 static void SecPolicyCheckSubjectOrganizationalUnit(SecPVCRef pvc
,
645 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, 0);
646 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
647 CFStringRef orgUnit
= (CFStringRef
)CFDictionaryGetValue(policy
->_options
,
649 if (!isString(orgUnit
)) {
650 /* @@@ We can't return an error here and making the evaluation fail
651 won't help much either. */
654 if (!SecPolicyCheckCertSubjectOrganizationalUnit(cert
, orgUnit
)) {
655 /* Leaf Subject Organization mismatch. */
656 SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
);
660 /* AUDIT[securityd](done):
661 policy->_options is a caller provided dictionary, only its cf type has
664 static void SecPolicyCheckEAPTrustedServerNames(SecPVCRef pvc
,
666 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
667 CFArrayRef trustedServerNames
= (CFArrayRef
)
668 CFDictionaryGetValue(policy
->_options
, key
);
669 /* No names specified means we accept any name. */
670 if (!trustedServerNames
)
672 if (!isArray(trustedServerNames
)) {
673 /* @@@ We can't return an error here and making the evaluation fail
674 won't help much either. */
678 SecCertificateRef leaf
= SecPVCGetCertificateAtIndex(pvc
, 0);
679 if (!SecPolicyCheckCertEAPTrustedServerNames(leaf
, trustedServerNames
)) {
680 /* Hostname mismatch or no hostnames found in certificate. */
681 SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
);
685 static const unsigned char UTN_USERFirst_Hardware_Serial
[][16] = {
686 { 0xd8, 0xf3, 0x5f, 0x4e, 0xb7, 0x87, 0x2b, 0x2d, 0xab, 0x06, 0x92, 0xe3, 0x15, 0x38, 0x2f, 0xb0 },
687 { 0x92, 0x39, 0xd5, 0x34, 0x8f, 0x40, 0xd1, 0x69, 0x5a, 0x74, 0x54, 0x70, 0xe1, 0xf2, 0x3f, 0x43 },
688 { 0xb0, 0xb7, 0x13, 0x3e, 0xd0, 0x96, 0xf9, 0xb5, 0x6f, 0xae, 0x91, 0xc8, 0x74, 0xbd, 0x3a, 0xc0 },
689 { 0xe9, 0x02, 0x8b, 0x95, 0x78, 0xe4, 0x15, 0xdc, 0x1a, 0x71, 0x0a, 0x2b, 0x88, 0x15, 0x44, 0x47 },
690 { 0x39, 0x2a, 0x43, 0x4f, 0x0e, 0x07, 0xdf, 0x1f, 0x8a, 0xa3, 0x05, 0xde, 0x34, 0xe0, 0xc2, 0x29 },
691 { 0x3e, 0x75, 0xce, 0xd4, 0x6b, 0x69, 0x30, 0x21, 0x21, 0x88, 0x30, 0xae, 0x86, 0xa8, 0x2a, 0x71 },
692 { 0xd7, 0x55, 0x8f, 0xda, 0xf5, 0xf1, 0x10, 0x5b, 0xb2, 0x13, 0x28, 0x2b, 0x70, 0x77, 0x29, 0xa3 },
693 { 0x04, 0x7e, 0xcb, 0xe9, 0xfc, 0xa5, 0x5f, 0x7b, 0xd0, 0x9e, 0xae, 0x36, 0xe1, 0x0c, 0xae, 0x1e },
694 { 0xf5, 0xc8, 0x6a, 0xf3, 0x61, 0x62, 0xf1, 0x3a, 0x64, 0xf5, 0x4f, 0x6d, 0xc9, 0x58, 0x7c, 0x06 } };
696 static const unsigned char UTN_USERFirst_Hardware_Normalized_Issuer
[] = {
697 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55,
698 0x53, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x02,
699 0x55, 0x54, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x07, 0x13,
700 0x0e, 0x53, 0x41, 0x4c, 0x54, 0x20, 0x4c, 0x41, 0x4b, 0x45, 0x20, 0x43,
701 0x49, 0x54, 0x59, 0x31, 0x1e, 0x30, 0x1c, 0x06, 0x03, 0x55, 0x04, 0x0a,
702 0x13, 0x15, 0x54, 0x48, 0x45, 0x20, 0x55, 0x53, 0x45, 0x52, 0x54, 0x52,
703 0x55, 0x53, 0x54, 0x20, 0x4e, 0x45, 0x54, 0x57, 0x4f, 0x52, 0x4b, 0x31,
704 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x18, 0x48, 0x54,
705 0x54, 0x50, 0x3a, 0x2f, 0x2f, 0x57, 0x57, 0x57, 0x2e, 0x55, 0x53, 0x45,
706 0x52, 0x54, 0x52, 0x55, 0x53, 0x54, 0x2e, 0x43, 0x4f, 0x4d, 0x31, 0x1f,
707 0x30, 0x1d, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x16, 0x55, 0x54, 0x4e,
708 0x2d, 0x55, 0x53, 0x45, 0x52, 0x46, 0x49, 0x52, 0x53, 0x54, 0x2d, 0x48,
709 0x41, 0x52, 0x44, 0x57, 0x41, 0x52, 0x45
711 static const unsigned int UTN_USERFirst_Hardware_Normalized_Issuer_len
= 151;
714 static void SecPolicyCheckBlackListedLeaf(SecPVCRef pvc
,
716 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, 0);
717 CFDataRef issuer
= cert
? SecCertificateGetNormalizedIssuerContent(cert
) : NULL
;
719 if (issuer
&& (CFDataGetLength(issuer
) == (CFIndex
)UTN_USERFirst_Hardware_Normalized_Issuer_len
) &&
720 (0 == memcmp(UTN_USERFirst_Hardware_Normalized_Issuer
, CFDataGetBytePtr(issuer
),
721 UTN_USERFirst_Hardware_Normalized_Issuer_len
)))
723 CFDataRef serial
= SecCertificateCopySerialNumberData(cert
, NULL
);
725 CFIndex serial_length
= CFDataGetLength(serial
);
726 const uint8_t *serial_ptr
= CFDataGetBytePtr(serial
);
728 while ((serial_length
> 0) && (*serial_ptr
== 0)) {
733 if (serial_length
== (CFIndex
)sizeof(*UTN_USERFirst_Hardware_Serial
)) {
735 for (i
= 0; i
< array_size(UTN_USERFirst_Hardware_Serial
); i
++)
737 if (0 == memcmp(UTN_USERFirst_Hardware_Serial
[i
],
738 serial_ptr
, sizeof(*UTN_USERFirst_Hardware_Serial
)))
740 SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
);
741 CFReleaseSafe(serial
);
750 SecOTAPKIRef otapkiRef
= SecOTAPKICopyCurrentOTAPKIRef();
751 if (NULL
!= otapkiRef
)
753 CFSetRef blackListedKeys
= SecOTAPKICopyBlackListSet(otapkiRef
);
754 CFRelease(otapkiRef
);
755 if (NULL
!= blackListedKeys
)
757 /* Check for blacklisted intermediates keys. */
758 CFDataRef dgst
= SecCertificateCopyPublicKeySHA1Digest(cert
);
761 /* Check dgst against blacklist. */
762 if (CFSetContainsValue(blackListedKeys
, dgst
))
764 SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
);
768 CFRelease(blackListedKeys
);
773 static void SecPolicyCheckGrayListedLeaf(SecPVCRef pvc
, CFStringRef key
)
775 SecOTAPKIRef otapkiRef
= SecOTAPKICopyCurrentOTAPKIRef();
776 if (NULL
!= otapkiRef
)
778 CFSetRef grayListedKeys
= SecOTAPKICopyGrayList(otapkiRef
);
779 CFRelease(otapkiRef
);
780 if (NULL
!= grayListedKeys
)
782 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, 0);
784 CFDataRef dgst
= SecCertificateCopyPublicKeySHA1Digest(cert
);
787 /* Check dgst against gray. */
788 if (CFSetContainsValue(grayListedKeys
, dgst
))
790 SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
);
794 CFRelease(grayListedKeys
);
799 static void SecPolicyCheckLeafMarkerOid(SecPVCRef pvc
, CFStringRef key
)
801 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, 0);
802 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
803 CFTypeRef value
= CFDictionaryGetValue(policy
->_options
, key
);
805 if (!SecPolicyCheckCertLeafMarkerOid(cert
, value
)) {
806 SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
);
810 static void SecPolicyCheckLeafMarkerOidWithoutValueCheck(SecPVCRef pvc
, CFStringRef key
)
812 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, 0);
813 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
814 CFTypeRef value
= CFDictionaryGetValue(policy
->_options
, key
);
816 if (!SecPolicyCheckCertLeafMarkerOidWithoutValueCheck(cert
, value
)) {
817 SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
);
823 * The value is a dictionary. The dictionary contains keys indicating
824 * whether the value is for Prod or QA. The values are the same as
825 * in the options dictionary for SecPolicyCheckLeafMarkerOid.
827 static void SecPolicyCheckLeafMarkersProdAndQA(SecPVCRef pvc
, CFStringRef key
)
829 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, 0);
830 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
831 CFDictionaryRef value
= CFDictionaryGetValue(policy
->_options
, key
);
832 CFTypeRef prodValue
= CFDictionaryGetValue(value
, kSecPolicyLeafMarkerProd
);
834 if (!SecPolicyCheckCertLeafMarkerOid(cert
, prodValue
)) {
837 SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
);
842 static void SecPolicyCheckIntermediateMarkerOid(SecPVCRef pvc
, CFStringRef key
)
844 CFIndex ix
, count
= SecPVCGetCertificateCount(pvc
);
845 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
846 CFTypeRef value
= CFDictionaryGetValue(policy
->_options
, key
);
848 for (ix
= 1; ix
< count
- 1; ix
++) {
849 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, ix
);
850 if (SecCertificateHasMarkerExtension(cert
, value
))
853 SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
);
856 static void SecPolicyCheckIntermediateEKU(SecPVCRef pvc
, CFStringRef key
)
858 CFIndex ix
, count
= SecPVCGetCertificateCount(pvc
);
859 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
860 CFTypeRef peku
= CFDictionaryGetValue(policy
->_options
, key
);
862 for (ix
= 1; ix
< count
- 1; ix
++) {
863 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, ix
);
864 if (!SecPolicyCheckCertExtendedKeyUsage(cert
, peku
)) {
865 SecPVCSetResult(pvc
, key
, ix
, kCFBooleanFalse
);
870 static void SecPolicyCheckIntermediateOrganization(SecPVCRef pvc
, CFStringRef key
)
872 CFIndex ix
, count
= SecPVCGetCertificateCount(pvc
);
873 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
874 CFTypeRef organization
= CFDictionaryGetValue(policy
->_options
, key
);
876 for (ix
= 1; ix
< count
- 1; ix
++) {
877 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, ix
);
878 if (!SecPolicyCheckCertSubjectOrganization(cert
, organization
)) {
879 SecPVCSetResult(pvc
, key
, ix
, kCFBooleanFalse
);
884 static void SecPolicyCheckIntermediateCountry(SecPVCRef pvc
, CFStringRef key
)
886 CFIndex ix
, count
= SecPVCGetCertificateCount(pvc
);
887 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
888 CFTypeRef country
= CFDictionaryGetValue(policy
->_options
, key
);
890 for (ix
= 1; ix
< count
- 1; ix
++) {
891 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, ix
);
892 if (!SecPolicyCheckCertSubjectCountry(cert
, country
)) {
893 SecPVCSetResult(pvc
, key
, ix
, kCFBooleanFalse
);
898 /****************************************************************************
899 *********************** New rfc5280 Chain Validation ***********************
900 ****************************************************************************/
902 #define POLICY_MAPPING 1
903 #define POLICY_SUBTREES 1
905 /* rfc5280 basic cert processing. */
906 static void SecPolicyCheckBasicCertificateProcessing(SecPVCRef pvc
,
910 CFIndex count
= SecPVCGetCertificateCount(pvc
);
911 SecCertificatePathVCRef path
= SecPathBuilderGetPath(pvc
->builder
);
912 /* 64 bits cast: worst case here is we truncate the number of cert, and the validation may fail */
913 assert((unsigned long)count
<=UINT32_MAX
); /* Debug check. Correct as long as CFIndex is long */
914 uint32_t n
= (uint32_t)count
;
916 bool is_anchored
= SecPathBuilderIsAnchored(pvc
->builder
);
917 bool is_anchor_trusted
= false;
919 CFArrayRef constraints
= SecCertificatePathVCGetUsageConstraintsAtIndex(path
, n
- 1);
920 if (CFArrayGetCount(constraints
) == 0) {
921 /* Given that the path builder has already indicated the last cert in this chain has
922 * trust set on it, empty constraints means trusted. */
923 is_anchor_trusted
= true;
925 /* Determine whether constraints say to trust this cert for this PVC. */
926 SecTrustSettingsResult tsResult
= SecPVCGetTrustSettingsResult(pvc
, SecCertificatePathVCGetCertificateAtIndex(path
, n
- 1),
928 if (tsResult
== kSecTrustSettingsResultTrustRoot
|| tsResult
== kSecTrustSettingsResultTrustAsRoot
) {
929 is_anchor_trusted
= true;
934 if (is_anchor_trusted
) {
935 /* If the anchor is trusted we don't process the last cert in the
939 Boolean isSelfSigned
= false;
940 (void) SecCertificateIsSelfSigned(SecCertificatePathVCGetCertificateAtIndex(path
, n
- 1), &isSelfSigned
);
942 /* Add a detail for the root not being trusted. */
943 if (!SecPVCSetResultForced(pvc
, kSecPolicyCheckAnchorTrusted
,
944 n
- 1, kCFBooleanFalse
, true)) {
948 /* Add a detail for the missing intermediate. */
949 if (!SecPVCSetResultForced(pvc
, kSecPolicyCheckMissingIntermediate
,
950 n
- 1, kCFBooleanFalse
, true)) {
956 CFAbsoluteTime verify_time
= SecPVCGetVerifyTime(pvc
);
957 //policy_set_t user_initial_policy_set = NULL;
958 //trust_anchor_t anchor;
962 CFMutableArrayRef permitted_subtrees
= NULL
;
963 CFMutableArrayRef excluded_subtrees
= NULL
;
964 permitted_subtrees
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
);
965 excluded_subtrees
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
);
966 require_action_quiet(permitted_subtrees
!= NULL
, errOut
,
967 SecPVCSetResultForced(pvc
, kSecPolicyCheckNameConstraints
, 0, kCFBooleanFalse
, true));
968 require_action_quiet(excluded_subtrees
!= NULL
, errOut
,
969 SecPVCSetResultForced(pvc
, kSecPolicyCheckNameConstraints
, 0, kCFBooleanFalse
, true));
972 if (!SecCertificatePathVCVerifyPolicyTree(path
, is_anchor_trusted
)) {
973 if (!SecPVCSetResultForced(pvc
, kSecPolicyCheckPolicyConstraints
, 0, kCFBooleanFalse
, true)) {
979 /* Path builder ensures we only get cert chains with proper issuer
980 chaining with valid signatures along the way. */
981 algorithm_id_t working_public_key_algorithm
= anchor
->public_key_algorithm
;
982 SecKeyRef working_public_key
= anchor
->public_key
;
983 x500_name_t working_issuer_name
= anchor
->issuer_name
;
985 uint32_t i
, max_path_length
= n
;
986 SecCertificateRef cert
= NULL
;
987 for (i
= 1; i
<= n
; ++i
) {
989 cert
= SecPVCGetCertificateAtIndex(pvc
, n
- i
);
990 bool is_self_issued
= SecCertificatePathVCIsCertificateAtIndexSelfIssued(SecPathBuilderGetPath(pvc
->builder
), n
- i
);
992 /* (a) Verify the basic certificate information. */
993 /* @@@ Ensure that cert was signed with working_public_key_algorithm
994 using the working_public_key and the working_public_key_parameters. */
996 /* Already done by chain builder. */
997 if (!SecCertificateIsValid(cert
, verify_time
)) {
998 if (!SecPVCSetResult(pvc
, kSecPolicyCheckTemporalValidity
, n
- i
, kCFBooleanFalse
)) {
1002 if (SecCertificateIsWeakKey(cert
)) {
1003 if (!SecPVCSetResult(pvc
, kSecPolicyCheckWeakKeySize
, n
- i
, kCFBooleanFalse
)) {
1007 if (!SecPolicyCheckCertWeakSignature(cert
, NULL
)) {
1008 if (!SecPVCSetResult(pvc
, kSecPolicyCheckWeakSignature
, n
- i
, kCFBooleanFalse
)) {
1013 /* @@@ cert.issuer == working_issuer_name. */
1017 if (!is_self_issued
|| i
== n
) {
1019 /* Verify certificate Subject Name and SubjectAltNames are not within any of the excluded_subtrees */
1020 if(excluded_subtrees
&& CFArrayGetCount(excluded_subtrees
)) {
1021 if ((errSecSuccess
!= SecNameContraintsMatchSubtrees(cert
, excluded_subtrees
, &found
, false)) || found
) {
1022 secnotice("policy", "name in excluded subtrees");
1023 if(!SecPVCSetResultForced(pvc
, kSecPolicyCheckNameConstraints
, n
- i
, kCFBooleanFalse
, true)) { goto errOut
; }
1026 /* Verify certificate Subject Name and SubjectAltNames are within the permitted_subtrees */
1027 if(permitted_subtrees
&& CFArrayGetCount(permitted_subtrees
)) {
1028 if ((errSecSuccess
!= SecNameContraintsMatchSubtrees(cert
, permitted_subtrees
, &found
, true)) || !found
) {
1029 secnotice("policy", "name not in permitted subtrees");
1030 if(!SecPVCSetResultForced(pvc
, kSecPolicyCheckNameConstraints
, n
- i
, kCFBooleanFalse
, true)) { goto errOut
; }
1035 /* (d) (e) (f) handled by SecCertificatePathVCVerifyPolicyTree */
1037 /* If Last Cert in Path */
1041 /* Prepare for Next Cert */
1042 /* (a) (b) Done by SecCertificatePathVCVerifyPolicyTree */
1043 /* (c)(d)(e)(f) Done by SecPathBuilderGetNext and SecCertificatePathVCVerify */
1045 /* (g) If a name constraints extension is included in the certificate, modify the permitted_subtrees and excluded_subtrees state variables.
1047 CFArrayRef permitted_subtrees_in_cert
= SecCertificateGetPermittedSubtrees(cert
);
1048 if (permitted_subtrees_in_cert
) {
1049 SecNameConstraintsIntersectSubtrees(permitted_subtrees
, permitted_subtrees_in_cert
);
1052 // could do something smart here to avoid inserting the exact same constraint
1053 CFArrayRef excluded_subtrees_in_cert
= SecCertificateGetExcludedSubtrees(cert
);
1054 if (excluded_subtrees_in_cert
) {
1055 CFIndex num_trees
= CFArrayGetCount(excluded_subtrees_in_cert
);
1056 CFRange range
= { 0, num_trees
};
1057 CFArrayAppendArray(excluded_subtrees
, excluded_subtrees_in_cert
, range
);
1060 /* (h), (i), (j) done by SecCertificatePathVCVerifyPolicyTree */
1062 /* (k) Checked in chain builder pre signature verify already. SecPVCParentCertificateChecks */
1065 if (!is_self_issued
) {
1066 if (max_path_length
> 0) {
1069 /* max_path_len exceeded, illegal. */
1070 if (!SecPVCSetResultForced(pvc
, kSecPolicyCheckBasicConstraintsPathLen
,
1071 n
- i
, kCFBooleanFalse
, true)) {
1077 const SecCEBasicConstraints
*bc
= SecCertificateGetBasicConstraints(cert
);
1078 if (bc
&& bc
->pathLenConstraintPresent
1079 && bc
->pathLenConstraint
< max_path_length
) {
1080 max_path_length
= bc
->pathLenConstraint
;
1082 #if 0 /* Checked in chain builder pre signature verify already. SecPVCParentCertificateChecks */
1083 /* (n) If a key usage extension is present, verify that the keyCertSign bit is set. */
1084 SecKeyUsage keyUsage
= SecCertificateGetKeyUsage(cert
);
1085 if (keyUsage
&& !(keyUsage
& kSecKeyUsageKeyCertSign
)) {
1086 if (!SecPVCSetResultForced(pvc
, kSecPolicyCheckKeyUsage
,
1087 n
- i
, kCFBooleanFalse
, true)) {
1092 /* (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. */
1093 if (SecCertificateHasUnknownCriticalExtension(cert
)) {
1094 /* Certificate contains one or more unknown critical extensions. */
1095 if (!SecPVCSetResult(pvc
, kSecPolicyCheckCriticalExtensions
,
1096 n
- i
, kCFBooleanFalse
)) {
1100 } /* end loop over certs in path */
1102 /* (a) (b) done by SecCertificatePathVCVerifyPolicyTree */
1105 /* 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
1106 working_public_key_algorithm are different, set the working_public_key_parameters to null. */
1108 /* (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. */
1109 if (SecCertificateHasUnknownCriticalExtension(cert
)) {
1110 /* Certificate contains one or more unknown critical extensions. */
1111 if (!SecPVCSetResult(pvc
, kSecPolicyCheckCriticalExtensions
,
1112 0, kCFBooleanFalse
)) {
1116 /* (g) done by SecCertificatePathVCVerifyPolicyTree */
1119 CFReleaseNull(permitted_subtrees
);
1120 CFReleaseNull(excluded_subtrees
);
1123 static policy_set_t
policies_for_cert(SecCertificateRef cert
) {
1124 policy_set_t policies
= NULL
;
1125 const SecCECertificatePolicies
*cp
=
1126 SecCertificateGetCertificatePolicies(cert
);
1127 size_t policy_ix
, policy_count
= cp
? cp
->numPolicies
: 0;
1128 for (policy_ix
= 0; policy_ix
< policy_count
; ++policy_ix
) {
1129 policy_set_add(&policies
, &cp
->policies
[policy_ix
].policyIdentifier
);
1134 static void SecPolicyCheckEV(SecPVCRef pvc
,
1136 CFIndex ix
, count
= SecPVCGetCertificateCount(pvc
);
1137 policy_set_t valid_policies
= NULL
;
1139 /* 6.1.7. Key Usage Purposes */
1141 CFAbsoluteTime jul2016
= 489024000;
1142 SecCertificateRef leaf
= SecPVCGetCertificateAtIndex(pvc
, 0);
1143 if (SecCertificateNotValidBefore(leaf
) > jul2016
&& count
< 3) {
1144 /* Root CAs may not sign subscriber certificates after 30 June 2016. */
1145 if (SecPVCSetResultForced(pvc
, key
,
1146 0, kCFBooleanFalse
, true)) {
1152 for (ix
= 0; ix
< count
; ++ix
) {
1153 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, ix
);
1154 policy_set_t policies
= policies_for_cert(cert
);
1157 /* anyPolicy in the leaf isn't allowed for EV, so only init
1158 valid_policies if we have real policies. */
1159 if (!policy_set_contains(policies
, &oidAnyPolicy
)) {
1160 valid_policies
= policies
;
1163 } else if (ix
< count
- 1) {
1164 /* Subordinate CA */
1165 if (!SecPolicySubordinateCACertificateCouldBeEV(cert
)) {
1166 secnotice("ev", "subordinate certificate is not ev");
1167 if (SecPVCSetResultForced(pvc
, key
,
1168 ix
, kCFBooleanFalse
, true)) {
1169 policy_set_free(valid_policies
);
1170 policy_set_free(policies
);
1174 policy_set_intersect(&valid_policies
, policies
);
1177 if (!SecPolicyRootCACertificateIsEV(cert
, valid_policies
)) {
1178 secnotice("ev", "anchor certificate is not ev");
1179 if (SecPVCSetResultForced(pvc
, key
,
1180 ix
, kCFBooleanFalse
, true)) {
1181 policy_set_free(valid_policies
);
1182 policy_set_free(policies
);
1187 policy_set_free(policies
);
1188 if (!valid_policies
) {
1189 secnotice("ev", "valid_policies set is empty: chain not ev");
1190 /* If we ever get into a state where no policies are valid anymore
1191 this can't be an ev chain. */
1192 if (SecPVCSetResultForced(pvc
, key
,
1193 ix
, kCFBooleanFalse
, true)) {
1199 policy_set_free(valid_policies
);
1201 /* (a) EV Subscriber Certificates Each EV Certificate issued by the CA to a
1202 Subscriber MUST contain an OID defined by the CA in the certificate’s
1203 certificatePolicies extension that: (i) indicates which CA policy statement relates
1204 to that certificate, (ii) asserts the CA’s adherence to and compliance with these
1205 Guidelines, and (iii), by pre-agreement with the Application Software Vendor,
1206 marks the certificate as being an EV Certificate.
1207 (b) EV Subordinate CA Certificates
1208 (1) Certificates issued to Subordinate CAs that are not controlled by the issuing
1209 CA MUST contain one or more OIDs defined by the issuing CA that
1210 explicitly identify the EV Policies that are implemented by the Subordinate
1212 (2) Certificates issued to Subordinate CAs that are controlled by the Root CA
1213 MAY contain the special anyPolicy OID (2.5.29.32.0).
1214 (c) Root CA Certificates Root CA Certificates SHOULD NOT contain the
1215 certificatePolicies or extendedKeyUsage extensions.
1221 * MARK: Certificate Transparency support
1227 Version sct_version; // 1 byte
1228 LogID id; // 32 bytes
1229 uint64 timestamp; // 8 bytes
1230 CtExtensions extensions; // 2 bytes len field, + n bytes data
1231 digitally-signed struct { // 1 byte hash alg, 1 byte sig alg, n bytes signature
1232 Version sct_version;
1233 SignatureType signature_type = certificate_timestamp;
1235 LogEntryType entry_type;
1236 select(entry_type) {
1237 case x509_entry: ASN.1Cert;
1238 case precert_entry: PreCert;
1240 CtExtensions extensions;
1242 } SignedCertificateTimestamp;
1246 #include <Security/SecureTransportPriv.h>
1249 SecAsn1Oid
*oidForSigAlg(SSL_HashAlgorithm hash
, SSL_SignatureAlgorithm alg
)
1252 case SSL_SignatureAlgorithmRSA
:
1254 case SSL_HashAlgorithmSHA1
:
1255 return &CSSMOID_SHA1WithRSA
;
1256 case SSL_HashAlgorithmSHA256
:
1257 return &CSSMOID_SHA256WithRSA
;
1258 case SSL_HashAlgorithmSHA384
:
1259 return &CSSMOID_SHA384WithRSA
;
1263 case SSL_SignatureAlgorithmECDSA
:
1265 case SSL_HashAlgorithmSHA1
:
1266 return &CSSMOID_ECDSA_WithSHA1
;
1267 case SSL_HashAlgorithmSHA256
:
1268 return &CSSMOID_ECDSA_WithSHA256
;
1269 case SSL_HashAlgorithmSHA384
:
1270 return &CSSMOID_ECDSA_WithSHA384
;
1282 static size_t SSLDecodeUint16(const uint8_t *p
)
1284 return (p
[0]<<8 | p
[1]);
1287 static uint8_t *SSLEncodeUint16(uint8_t *p
, size_t len
)
1289 p
[0] = (len
>> 8)&0xff;
1290 p
[1] = (len
& 0xff);
1294 static uint8_t *SSLEncodeUint24(uint8_t *p
, size_t len
)
1296 p
[0] = (len
>> 16)&0xff;
1297 p
[1] = (len
>> 8)&0xff;
1298 p
[2] = (len
& 0xff);
1304 uint64_t SSLDecodeUint64(const uint8_t *p
)
1307 for(int i
=0; i
<8; i
++) {
1314 #include <libDER/DER_CertCrl.h>
1315 #include <libDER/DER_Encode.h>
1316 #include <libDER/asn1Types.h>
1319 static CFDataRef
copy_x509_entry_from_chain(SecPVCRef pvc
)
1321 SecCertificateRef leafCert
= SecPVCGetCertificateAtIndex(pvc
, 0);
1323 CFMutableDataRef data
= CFDataCreateMutable(kCFAllocatorDefault
, 3+SecCertificateGetLength(leafCert
));
1325 CFDataSetLength(data
, 3+SecCertificateGetLength(leafCert
));
1327 uint8_t *q
= CFDataGetMutableBytePtr(data
);
1328 q
= SSLEncodeUint24(q
, SecCertificateGetLength(leafCert
));
1329 memcpy(q
, SecCertificateGetBytePtr(leafCert
), SecCertificateGetLength(leafCert
));
1335 static CFDataRef
copy_precert_entry_from_chain(SecPVCRef pvc
)
1337 SecCertificateRef leafCert
= NULL
;
1338 SecCertificateRef issuer
= NULL
;
1339 CFDataRef issuerKeyHash
= NULL
;
1340 CFDataRef tbs_precert
= NULL
;
1341 CFMutableDataRef data
= NULL
;
1343 require_quiet(SecPVCGetCertificateCount(pvc
)>=2, out
); //we need the issuer key for precerts.
1344 leafCert
= SecPVCGetCertificateAtIndex(pvc
, 0);
1345 issuer
= SecPVCGetCertificateAtIndex(pvc
, 1);
1347 require(leafCert
, out
);
1348 require(issuer
, out
); // Those two would likely indicate an internal error, since we already checked the chain length above.
1349 issuerKeyHash
= SecCertificateCopySubjectPublicKeyInfoSHA256Digest(issuer
);
1350 tbs_precert
= SecCertificateCopyPrecertTBS(leafCert
);
1352 require(issuerKeyHash
, out
);
1353 require(tbs_precert
, out
);
1354 data
= CFDataCreateMutable(kCFAllocatorDefault
, CFDataGetLength(issuerKeyHash
) + 3 + CFDataGetLength(tbs_precert
));
1355 CFDataSetLength(data
, CFDataGetLength(issuerKeyHash
) + 3 + CFDataGetLength(tbs_precert
));
1357 uint8_t *q
= CFDataGetMutableBytePtr(data
);
1358 memcpy(q
, CFDataGetBytePtr(issuerKeyHash
), CFDataGetLength(issuerKeyHash
)); q
+= CFDataGetLength(issuerKeyHash
); // issuer key hash
1359 q
= SSLEncodeUint24(q
, CFDataGetLength(tbs_precert
));
1360 memcpy(q
, CFDataGetBytePtr(tbs_precert
), CFDataGetLength(tbs_precert
));
1363 CFReleaseSafe(issuerKeyHash
);
1364 CFReleaseSafe(tbs_precert
);
1369 CFAbsoluteTime
TimestampToCFAbsoluteTime(uint64_t ts
)
1371 return (ts
/ 1000) - kCFAbsoluteTimeIntervalSince1970
;
1375 uint64_t TimestampFromCFAbsoluteTime(CFAbsoluteTime at
)
1377 return (uint64_t)(at
+ kCFAbsoluteTimeIntervalSince1970
) * 1000;
1384 If the 'sct' is valid, add it to the validatingLogs dictionary.
1387 - validatingLogs: mutable dictionary to which to add the log that validate this SCT.
1389 - entry_type: 0 for x509 cert, 1 for precert.
1390 - entry: the cert or precert data.
1391 - vt: verification time timestamp (as used in SCTs: ms since 1970 Epoch)
1392 - trustedLog: Dictionary contain the Trusted Logs.
1394 The SCT is valid if:
1395 - It decodes properly.
1396 - Its timestamp is less than 'verifyTime'.
1397 - It is signed by a log in 'trustedLogs'.
1398 - If entry_type = 0, the log must be currently qualified.
1399 - If entry_type = 1, the log may be expired.
1401 If the SCT is valid, it's added to the validatinLogs dictionary using the log dictionary as the key, and the timestamp as value.
1402 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.
1407 static CFDictionaryRef
getSCTValidatingLog(CFDataRef sct
, int entry_type
, CFDataRef entry
, uint64_t vt
, CFArrayRef trustedLogs
, CFAbsoluteTime
*sct_at
)
1410 const uint8_t *logID
;
1411 const uint8_t *timestampData
;
1413 size_t extensionsLen
;
1414 const uint8_t *extensionsData
;
1417 size_t signatureLen
;
1418 const uint8_t *signatureData
;
1419 SecKeyRef pubKey
= NULL
;
1420 uint8_t *signed_data
= NULL
;
1421 const SecAsn1Oid
*oid
= NULL
;
1423 CFDataRef logIDData
= NULL
;
1424 CFDictionaryRef result
= 0;
1426 const uint8_t *p
= CFDataGetBytePtr(sct
);
1427 size_t len
= CFDataGetLength(sct
);
1429 require(len
>=43, out
);
1431 version
= p
[0]; p
++; len
--;
1432 logID
= p
; p
+=32; len
-=32;
1433 timestampData
= p
; p
+=8; len
-=8;
1434 extensionsLen
= SSLDecodeUint16(p
); p
+=2; len
-=2;
1436 require(len
>=extensionsLen
, out
);
1437 extensionsData
= p
; p
+=extensionsLen
; len
-=extensionsLen
;
1439 require(len
>=4, out
);
1440 hashAlg
=p
[0]; p
++; len
--;
1441 sigAlg
=p
[0]; p
++; len
--;
1442 signatureLen
= SSLDecodeUint16(p
); p
+=2; len
-=2;
1443 require(len
==signatureLen
, out
); /* We do not tolerate any extra data after the signature */
1446 /* verify version: only v1(0) is supported */
1448 secerror("SCT version unsupported: %d\n", version
);
1452 /* verify timestamp not in the future */
1453 timestamp
= SSLDecodeUint64(timestampData
);
1454 if(timestamp
> vt
) {
1455 secerror("SCT is in the future: %llu > %llu\n", timestamp
, vt
);
1462 size_t signed_data_len
= 12 + CFDataGetLength(entry
) + 2 + extensionsLen
;
1463 signed_data
= malloc(signed_data_len
);
1464 require(signed_data
, out
);
1467 *q
++ = 0; // certificate_timestamp
1468 memcpy(q
, timestampData
, 8); q
+=8;
1469 q
= SSLEncodeUint16(q
, entry_type
); // logentry type: 0=cert 1=precert
1470 memcpy(q
, CFDataGetBytePtr(entry
), CFDataGetLength(entry
)); q
+= CFDataGetLength(entry
);
1471 q
= SSLEncodeUint16(q
, extensionsLen
);
1472 memcpy(q
, extensionsData
, extensionsLen
);
1474 logIDData
= CFDataCreateWithBytesNoCopy(kCFAllocatorDefault
, logID
, 32, kCFAllocatorNull
);
1476 CFDictionaryRef logData
= CFArrayGetValueMatching(trustedLogs
, ^bool(const void *dict
) {
1477 const void *key_data
;
1478 if(!isDictionary(dict
)) return false;
1479 if(!CFDictionaryGetValueIfPresent(dict
, CFSTR("key"), &key_data
)) return false;
1480 if(!isData(key_data
)) return false;
1481 CFDataRef valueID
= SecSHA256DigestCreateFromData(kCFAllocatorDefault
, (CFDataRef
)key_data
);
1482 bool result
= (bool)(CFDataCompare(logIDData
, valueID
)==kCFCompareEqualTo
);
1483 CFReleaseSafe(valueID
);
1486 require(logData
, out
);
1489 // For external SCTs, only keep SCTs from currently valid logs.
1490 require(!CFDictionaryContainsKey(logData
, CFSTR("expiry")), out
);
1493 CFAbsoluteTime sct_time
= TimestampToCFAbsoluteTime(timestamp
);
1494 CFDateRef frozen_date
= CFDictionaryGetValue(logData
, CFSTR("frozen"));
1495 if (frozen_date
&& (sct_time
> CFDateGetAbsoluteTime(frozen_date
))) {
1496 secerror("Frozen CT log issued SCT after freezing (log=%@)\n", logData
);
1500 CFDataRef logKeyData
= CFDictionaryGetValue(logData
, CFSTR("key"));
1501 require(logKeyData
, out
); // This failing would be an internal logic error
1502 pubKey
= SecKeyCreateFromSubjectPublicKeyInfoData(kCFAllocatorDefault
, logKeyData
);
1503 require(pubKey
, out
);
1505 oid
= oidForSigAlg(hashAlg
, sigAlg
);
1508 algId
.algorithm
= *oid
;
1509 algId
.parameters
.Data
= NULL
;
1510 algId
.parameters
.Length
= 0;
1512 if(SecKeyDigestAndVerify(pubKey
, &algId
, signed_data
, signed_data_len
, signatureData
, signatureLen
)==0) {
1516 secerror("SCT signature failed (log=%@)\n", logData
);
1520 CFReleaseSafe(logIDData
);
1521 CFReleaseSafe(pubKey
);
1527 static void addValidatingLog(CFMutableDictionaryRef validatingLogs
, CFDictionaryRef log
, CFAbsoluteTime sct_at
)
1529 CFDateRef validated_time
= CFDictionaryGetValue(validatingLogs
, log
);
1531 if(validated_time
==NULL
|| (sct_at
< CFDateGetAbsoluteTime(validated_time
))) {
1532 CFDateRef sct_time
= CFDateCreate(kCFAllocatorDefault
, sct_at
);
1533 CFDictionarySetValue(validatingLogs
, log
, sct_time
);
1534 CFReleaseSafe(sct_time
);
1538 static CFArrayRef
copy_ocsp_scts(SecPVCRef pvc
)
1540 CFMutableArrayRef SCTs
= NULL
;
1541 SecCertificateRef leafCert
= NULL
;
1542 SecCertificateRef issuer
= NULL
;
1543 CFArrayRef ocspResponsesData
= NULL
;
1544 SecOCSPRequestRef ocspRequest
= NULL
;
1546 ocspResponsesData
= SecPathBuilderCopyOCSPResponses(pvc
->builder
);
1547 require_quiet(ocspResponsesData
, out
);
1549 require_quiet(SecPVCGetCertificateCount(pvc
)>=2, out
); //we need the issuer key for precerts.
1550 leafCert
= SecPVCGetCertificateAtIndex(pvc
, 0);
1551 issuer
= SecPVCGetCertificateAtIndex(pvc
, 1);
1553 require(leafCert
, out
);
1554 require(issuer
, out
); // not quiet: Those two would likely indicate an internal error, since we already checked the chain length above.
1555 ocspRequest
= SecOCSPRequestCreate(leafCert
, issuer
);
1557 SCTs
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
);
1560 CFArrayForEach(ocspResponsesData
, ^(const void *value
) {
1561 /* TODO: Should the builder already have the appropriate SecOCSPResponseRef ? */
1562 SecOCSPResponseRef ocspResponse
= SecOCSPResponseCreate(value
);
1563 if(ocspResponse
&& SecOCSPGetResponseStatus(ocspResponse
)==kSecOCSPSuccess
) {
1564 SecOCSPSingleResponseRef ocspSingleResponse
= SecOCSPResponseCopySingleResponse(ocspResponse
, ocspRequest
);
1565 if(ocspSingleResponse
) {
1566 CFArrayRef singleResponseSCTs
= SecOCSPSingleResponseCopySCTs(ocspSingleResponse
);
1567 if(singleResponseSCTs
) {
1568 CFArrayAppendArray(SCTs
, singleResponseSCTs
, CFRangeMake(0, CFArrayGetCount(singleResponseSCTs
)));
1569 CFRelease(singleResponseSCTs
);
1571 SecOCSPSingleResponseDestroy(ocspSingleResponse
);
1574 if(ocspResponse
) SecOCSPResponseFinalize(ocspResponse
);
1577 if(CFArrayGetCount(SCTs
)==0) {
1578 CFReleaseNull(SCTs
);
1582 CFReleaseSafe(ocspResponsesData
);
1584 SecOCSPRequestFinalize(ocspRequest
);
1589 static void SecPolicyCheckCT(SecPVCRef pvc
)
1591 SecCertificateRef leafCert
= SecPVCGetCertificateAtIndex(pvc
, 0);
1592 CFArrayRef embeddedScts
= SecCertificateCopySignedCertificateTimestamps(leafCert
);
1593 CFArrayRef builderScts
= SecPathBuilderCopySignedCertificateTimestamps(pvc
->builder
);
1594 CFArrayRef trustedLogs
= SecPathBuilderCopyTrustedLogs(pvc
->builder
);
1595 CFArrayRef ocspScts
= copy_ocsp_scts(pvc
);
1596 CFDataRef precertEntry
= copy_precert_entry_from_chain(pvc
);
1597 CFDataRef x509Entry
= copy_x509_entry_from_chain(pvc
);
1598 __block
uint32_t trustedSCTCount
= 0;
1599 __block CFAbsoluteTime issuanceTime
= SecPVCGetVerifyTime(pvc
);
1600 TA_CTFailureReason failureReason
= TA_CTNoFailure
;
1603 SecOTAPKIRef otapkiref
= SecOTAPKICopyCurrentOTAPKIRef();
1604 trustedLogs
= SecOTAPKICopyTrustedCTLogs(otapkiref
);
1605 CFReleaseSafe(otapkiref
);
1608 // This eventually contain list of logs who validated the SCT.
1609 CFMutableDictionaryRef currentLogsValidatingScts
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
1610 CFMutableDictionaryRef logsValidatingEmbeddedScts
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
1612 uint64_t vt
= TimestampFromCFAbsoluteTime(SecPVCGetVerifyTime(pvc
));
1614 __block
bool at_least_one_currently_valid_external
= 0;
1615 __block
bool at_least_one_currently_valid_embedded
= 0;
1616 __block
bool unknown_log
= 0;
1617 __block
bool disqualified_log
= 0;
1619 require(logsValidatingEmbeddedScts
, out
);
1620 require(currentLogsValidatingScts
, out
);
1622 /* Skip if there are no SCTs. */
1623 require_action((embeddedScts
&& CFArrayGetCount(embeddedScts
) > 0) ||
1624 (builderScts
&& CFArrayGetCount(builderScts
) > 0) ||
1625 (ocspScts
&& CFArrayGetCount(ocspScts
) > 0),
1627 TrustAnalyticsBuilder
*analytics
= SecPathBuilderGetAnalyticsData(pvc
->builder
);
1629 analytics
->ct_failure_reason
= TA_CTNoSCTs
;
1633 if(trustedLogs
) { // Don't bother trying to validate SCTs if we don't have any trusted logs.
1634 if(embeddedScts
&& precertEntry
) { // Don't bother if we could not get the precert.
1635 CFArrayForEach(embeddedScts
, ^(const void *value
){
1636 CFAbsoluteTime sct_at
;
1637 CFDictionaryRef log
= getSCTValidatingLog(value
, 1, precertEntry
, vt
, trustedLogs
, &sct_at
);
1639 addValidatingLog(logsValidatingEmbeddedScts
, log
, sct_at
);
1640 if(!CFDictionaryContainsKey(log
, CFSTR("expiry"))) {
1641 addValidatingLog(currentLogsValidatingScts
, log
, sct_at
);
1642 at_least_one_currently_valid_embedded
= true;
1645 disqualified_log
= true;
1653 if(builderScts
&& x509Entry
) { // Don't bother if we could not get the cert.
1654 CFArrayForEach(builderScts
, ^(const void *value
){
1655 CFAbsoluteTime sct_at
;
1656 CFDictionaryRef log
= getSCTValidatingLog(value
, 0, x509Entry
, vt
, trustedLogs
, &sct_at
);
1658 addValidatingLog(currentLogsValidatingScts
, log
, sct_at
);
1659 at_least_one_currently_valid_external
= true;
1667 if(ocspScts
&& x509Entry
) {
1668 CFArrayForEach(ocspScts
, ^(const void *value
){
1669 CFAbsoluteTime sct_at
;
1670 CFDictionaryRef log
= getSCTValidatingLog(value
, 0, x509Entry
, vt
, trustedLogs
, &sct_at
);
1672 addValidatingLog(currentLogsValidatingScts
, log
, sct_at
);
1673 at_least_one_currently_valid_external
= true;
1681 failureReason
= TA_CTMissingLogs
;
1685 /* We now have 2 sets of logs that validated those SCTS, count them and make a final decision.
1688 is_ct = (A1 AND A2) OR (B1 AND B2).
1690 A1: embedded SCTs from 2+ to 5+ logs valid at issuance time
1691 A2: At least one embedded SCT from a currently valid log.
1693 B1: SCTs from 2 currently valid logs (from any source)
1694 B2: At least 1 external SCT from a currently valid log.
1698 bool hasValidExternalSCT
= (at_least_one_currently_valid_external
&& CFDictionaryGetCount(currentLogsValidatingScts
)>=2);
1699 bool hasValidEmbeddedSCT
= (at_least_one_currently_valid_embedded
);
1700 SecCertificatePathVCRef path
= SecPathBuilderGetPath(pvc
->builder
);
1701 SecCertificatePathVCSetIsCT(path
, false);
1703 if (hasValidEmbeddedSCT
) {
1704 /* Calculate issuance time based on timestamp of SCTs from current logs */
1705 CFDictionaryForEach(currentLogsValidatingScts
, ^(const void *key
, const void *value
) {
1706 CFDictionaryRef log
= key
;
1707 if(!CFDictionaryContainsKey(log
, CFSTR("expiry"))) {
1708 // Log is still qualified
1709 CFDateRef ts
= (CFDateRef
) value
;
1710 CFAbsoluteTime timestamp
= CFDateGetAbsoluteTime(ts
);
1711 if(timestamp
< issuanceTime
) {
1712 issuanceTime
= timestamp
;
1716 SecCertificatePathVCSetIssuanceTime(path
, issuanceTime
);
1718 if (hasValidExternalSCT
) {
1719 /* Note: since external SCT validates this cert, we do not need to
1720 override issuance time here. If the cert also has a valid embedded
1721 SCT, issuanceTime will be calculated and set in the block above. */
1722 SecCertificatePathVCSetIsCT(path
, true);
1723 } else if (hasValidEmbeddedSCT
) {
1724 __block
int lifetime
; // in Months
1725 __block
unsigned once_or_current_qualified_embedded
= 0;
1728 __block
bool failed_once_check
= false;
1729 CFDictionaryForEach(logsValidatingEmbeddedScts
, ^(const void *key
, const void *value
) {
1730 CFDictionaryRef log
= key
;
1731 CFDateRef ts
= value
;
1732 CFDateRef expiry
= CFDictionaryGetValue(log
, CFSTR("expiry"));
1733 if (expiry
== NULL
) { // Currently qualified OR
1734 once_or_current_qualified_embedded
++;
1735 } else if (CFDateCompare(ts
, expiry
, NULL
) == kCFCompareLessThan
&& // Once qualified. That is, qualified at the time of SCT AND
1736 issuanceTime
< CFDateGetAbsoluteTime(expiry
)) { // at the time of issuance.)
1737 once_or_current_qualified_embedded
++;
1740 failed_once_check
= true;
1744 SecCFCalendarDoWithZuluCalendar(^(CFCalendarRef zuluCalendar
) {
1746 CFCalendarGetComponentDifference(zuluCalendar
,
1747 SecCertificateNotValidBefore(leafCert
),
1748 SecCertificateNotValidAfter(leafCert
),
1749 0, "M", &_lifetime
);
1750 lifetime
= _lifetime
;
1753 unsigned requiredEmbeddedSctsCount
;
1755 if (lifetime
< 15) {
1756 requiredEmbeddedSctsCount
= 2;
1757 } else if (lifetime
<= 27) {
1758 requiredEmbeddedSctsCount
= 3;
1759 } else if (lifetime
<= 39) {
1760 requiredEmbeddedSctsCount
= 4;
1762 requiredEmbeddedSctsCount
= 5;
1765 if(once_or_current_qualified_embedded
>= requiredEmbeddedSctsCount
){
1766 SecCertificatePathVCSetIsCT(path
, true);
1768 /* Not enough "once or currently qualified" SCTs */
1769 if (failed_once_check
) {
1770 failureReason
= TA_CTEmbeddedNotEnoughDisqualified
;
1771 } else if (unknown_log
) {
1772 failureReason
= TA_CTEmbeddedNotEnoughUnknown
;
1774 failureReason
= TA_CTEmbeddedNotEnough
;
1777 } else if (!at_least_one_currently_valid_embedded
&& !at_least_one_currently_valid_external
) {
1778 /* No currently valid SCTs */
1779 if (disqualified_log
) {
1780 failureReason
= TA_CTNoCurrentSCTsDisqualifiedLog
;
1781 } else if (unknown_log
) {
1782 failureReason
= TA_CTNoCurrentSCTsUnknownLog
;
1784 } else if (at_least_one_currently_valid_external
) {
1785 /* One presented current SCT but failed total current check */
1786 if (disqualified_log
) {
1787 failureReason
= TA_CTPresentedNotEnoughDisqualified
;
1788 } else if (unknown_log
) {
1789 failureReason
= TA_CTPresentedNotEnoughUnknown
;
1791 failureReason
= TA_CTPresentedNotEnough
;
1795 /* Record analytics data for CT */
1796 TrustAnalyticsBuilder
*analytics
= SecPathBuilderGetAnalyticsData(pvc
->builder
);
1797 require_quiet(analytics
, out
);
1798 uint32_t sctCount
= 0;
1799 /* Count the total number of SCTs we found and report where we got them */
1800 if (embeddedScts
&& CFArrayGetCount(embeddedScts
) > 0) {
1801 analytics
->sct_sources
|= TA_SCTEmbedded
;
1802 sctCount
+= CFArrayGetCount(embeddedScts
);
1804 if (builderScts
&& CFArrayGetCount(builderScts
) > 0) {
1805 analytics
->sct_sources
|= TA_SCT_TLS
;
1806 sctCount
+= CFArrayGetCount(builderScts
);
1808 if (ocspScts
&& CFArrayGetCount(ocspScts
) > 0) {
1809 analytics
->sct_sources
|= TA_SCT_OCSP
;
1810 sctCount
+= CFArrayGetCount(ocspScts
);
1812 /* Report how many of those SCTs were once or currently qualified */
1813 analytics
->number_trusted_scts
= trustedSCTCount
;
1814 /* Report how many SCTs we got */
1815 analytics
->number_scts
= sctCount
;
1817 analytics
->ct_failure_reason
= failureReason
;
1818 /* Only one current SCT -- close to failure */
1819 if (CFDictionaryGetCount(currentLogsValidatingScts
) == 1) {
1820 analytics
->ct_one_current
= true;
1823 CFReleaseSafe(logsValidatingEmbeddedScts
);
1824 CFReleaseSafe(currentLogsValidatingScts
);
1825 CFReleaseSafe(builderScts
);
1826 CFReleaseSafe(embeddedScts
);
1827 CFReleaseSafe(ocspScts
);
1828 CFReleaseSafe(precertEntry
);
1829 CFReleaseSafe(trustedLogs
);
1830 CFReleaseSafe(x509Entry
);
1833 static bool checkPolicyOidData(SecPVCRef pvc
, CFDataRef oid
) {
1834 CFIndex ix
, count
= SecPVCGetCertificateCount(pvc
);
1836 key_value
.data
= (DERByte
*)CFDataGetBytePtr(oid
);
1837 key_value
.length
= (DERSize
)CFDataGetLength(oid
);
1839 for (ix
= 0; ix
< count
; ix
++) {
1840 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, ix
);
1841 policy_set_t policies
= policies_for_cert(cert
);
1843 if (policy_set_contains(policies
, &key_value
)) {
1844 policy_set_free(policies
);
1847 policy_set_free(policies
);
1852 static void SecPolicyCheckCertificatePolicy(SecPVCRef pvc
, CFStringRef key
)
1854 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
1855 CFTypeRef value
= CFDictionaryGetValue(policy
->_options
, key
);
1856 bool result
= false;
1858 if (CFGetTypeID(value
) == CFDataGetTypeID())
1860 result
= checkPolicyOidData(pvc
, value
);
1861 } else if (CFGetTypeID(value
) == CFStringGetTypeID()) {
1862 CFDataRef dataOid
= SecCertificateCreateOidDataFromString(NULL
, value
);
1864 result
= checkPolicyOidData(pvc
, dataOid
);
1869 SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
);
1874 static void SecPolicyCheckRevocation(SecPVCRef pvc
,
1876 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
1877 CFTypeRef value
= CFDictionaryGetValue(policy
->_options
, key
);
1878 if (isString(value
)) {
1879 SecPathBuilderSetRevocationMethod(pvc
->builder
, value
);
1883 static void SecPolicyCheckRevocationResponseRequired(SecPVCRef pvc
,
1885 pvc
->require_revocation_response
= true;
1886 secdebug("policy", "revocation response required");
1889 static void SecPolicyCheckRevocationOnline(SecPVCRef pvc
, CFStringRef key
) {
1890 SecPathBuilderSetCheckRevocationOnline(pvc
->builder
);
1893 static void SecPolicyCheckRevocationIfTrusted(SecPVCRef pvc
, CFStringRef key
) {
1894 SecPathBuilderSetCheckRevocationIfTrusted(pvc
->builder
);
1897 static void SecPolicyCheckNoNetworkAccess(SecPVCRef pvc
,
1899 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
1900 CFTypeRef value
= CFDictionaryGetValue(policy
->_options
, key
);
1901 if (value
== kCFBooleanTrue
) {
1902 SecPathBuilderSetCanAccessNetwork(pvc
->builder
, false);
1904 SecPathBuilderSetCanAccessNetwork(pvc
->builder
, true);
1908 static void SecPolicyCheckWeakKeySize(SecPVCRef pvc
,
1910 CFIndex ix
, count
= SecPVCGetCertificateCount(pvc
);
1911 for (ix
= 0; ix
< count
; ++ix
) {
1912 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, ix
);
1913 if (cert
&& SecCertificateIsWeakKey(cert
)) {
1914 /* Intermediate certificate has a weak key. */
1915 if (!SecPVCSetResult(pvc
, key
, ix
, kCFBooleanFalse
))
1921 static void SecPolicyCheckKeySize(SecPVCRef pvc
, CFStringRef key
) {
1922 CFIndex ix
, count
= SecPVCGetCertificateCount(pvc
);
1923 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
1924 CFDictionaryRef keySizes
= CFDictionaryGetValue(policy
->_options
, key
);
1925 for (ix
= 0; ix
< count
; ++ix
) {
1926 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, ix
);
1927 if (!SecCertificateIsAtLeastMinKeySize(cert
, keySizes
)) {
1928 if (!SecPVCSetResult(pvc
, key
, ix
, kCFBooleanFalse
))
1934 static void SecPolicyCheckWeakSignature(SecPVCRef pvc
, CFStringRef key
) {
1935 CFIndex ix
, count
= SecPVCGetCertificateCount(pvc
);
1936 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
1937 CFTypeRef pvcValue
= CFDictionaryGetValue(policy
->_options
, key
);
1938 for (ix
= 0; ix
< count
; ++ix
) {
1939 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, ix
);
1940 if (!SecPolicyCheckCertWeakSignature(cert
, pvcValue
)) {
1941 if (!SecPVCSetResult(pvc
, key
, ix
, kCFBooleanFalse
))
1947 static void SecPolicyCheckSignatureHashAlgorithms(SecPVCRef pvc
,
1949 CFIndex ix
, count
= SecPVCGetCertificateCount(pvc
);
1950 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
1951 CFSetRef disallowedHashAlgorithms
= CFDictionaryGetValue(policy
->_options
, key
);
1952 for (ix
= 0; ix
< count
; ++ix
) {
1953 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, ix
);
1954 if (!SecPolicyCheckCertSignatureHashAlgorithms(cert
, disallowedHashAlgorithms
)) {
1955 if (!SecPVCSetResult(pvc
, key
, ix
, kCFBooleanFalse
))
1961 static bool leaf_is_on_weak_hash_whitelist(SecPVCRef pvc
) {
1962 SecCertificateRef leaf
= SecPVCGetCertificateAtIndex(pvc
, 0);
1963 require_quiet(leaf
, out
);
1965 /* And now a special snowflake from our tests */
1967 /* subject:/C=AU/ST=NSW/L=St Leonards/O=VODAFONE HUTCHISON AUSTRALIA PTY LIMITED/OU=Technology Shared Services/CN=mybill.vodafone.com.au */
1968 /* issuer :/C=UK/O=Vodafone Group/CN=Vodafone (Corporate Services 2009) */
1969 /* Not After : May 26 09:37:50 2017 GMT */
1970 static const uint8_t vodafone
[] = {
1971 0xde, 0x77, 0x63, 0x97, 0x79, 0x47, 0xee, 0x6e, 0xc1, 0x3a,
1972 0x7b, 0x3b, 0xad, 0x43, 0x88, 0xa9, 0x66, 0x59, 0xa8, 0x18
1975 CFDataRef leafFingerprint
= SecCertificateGetSHA1Digest(leaf
);
1976 require_quiet(leafFingerprint
, out
);
1977 const unsigned int len
= 20;
1978 const uint8_t *dp
= CFDataGetBytePtr(leafFingerprint
);
1979 if (dp
&& (!memcmp(vodafone
, dp
, len
))) {
1987 static bool SecPVCKeyIsConstraintPolicyOption(SecPVCRef pvc
, CFStringRef key
);
1989 static void SecPolicyCheckSystemTrustedWeakHash(SecPVCRef pvc
,
1991 CFIndex ix
, count
= SecPVCGetCertificateCount(pvc
);
1993 Boolean keyInPolicy
= false;
1994 CFArrayRef policies
= pvc
->policies
;
1995 CFIndex policyIX
, policyCount
= CFArrayGetCount(policies
);
1996 for (policyIX
= 0; policyIX
< policyCount
; ++policyIX
) {
1997 SecPolicyRef policy
= (SecPolicyRef
)CFArrayGetValueAtIndex(policies
, policyIX
);
1998 if (policy
&& CFDictionaryContainsKey(policy
->_options
, key
)) {
2003 /* We only enforce this check when *both* of the following are true:
2004 * 1. One of the certs in the path has this usage constraint, and
2005 * 2. One of the policies in the PVC has this key
2006 * (As compared to normal policy options which require only one to be true..) */
2007 require_quiet(SecPVCKeyIsConstraintPolicyOption(pvc
, key
) &&
2010 /* Ignore the anchor if it's trusted */
2011 if (SecPathBuilderIsAnchored(pvc
->builder
)) {
2014 for (ix
= 0; ix
< count
; ++ix
) {
2015 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, ix
);
2016 if (SecCertificateIsWeakHash(cert
)) {
2017 if (!leaf_is_on_weak_hash_whitelist(pvc
)) {
2018 if (!SecPVCSetResult(pvc
, key
, ix
, kCFBooleanFalse
)) {
2028 static void SecPolicyCheckSystemTrustedWeakKey(SecPVCRef pvc
,
2030 CFIndex ix
, count
= SecPVCGetCertificateCount(pvc
);
2032 Boolean keyInPolicy
= false;
2033 CFArrayRef policies
= pvc
->policies
;
2034 CFIndex policyIX
, policyCount
= CFArrayGetCount(policies
);
2035 for (policyIX
= 0; policyIX
< policyCount
; ++policyIX
) {
2036 SecPolicyRef policy
= (SecPolicyRef
)CFArrayGetValueAtIndex(policies
, policyIX
);
2037 if (policy
&& CFDictionaryContainsKey(policy
->_options
, key
)) {
2042 /* We only enforce this check when *both* of the following are true:
2043 * 1. One of the certs in the path has this usage constraint, and
2044 * 2. One of the policies in the PVC has this key
2045 * (As compared to normal policy options which require only one to be true..) */
2046 require_quiet(SecPVCKeyIsConstraintPolicyOption(pvc
, key
) &&
2049 /* Ignore the anchor if it's trusted */
2050 if (SecPathBuilderIsAnchored(pvc
->builder
)) {
2053 for (ix
= 0; ix
< count
; ++ix
) {
2054 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, ix
);
2055 if (!SecCertificateIsStrongKey(cert
)) {
2056 if (!SecPVCSetResult(pvc
, key
, ix
, kCFBooleanFalse
)) {
2066 static void SecPolicyCheckPinningRequired(SecPVCRef pvc
, CFStringRef key
) {
2067 /* Pinning is disabled on the system, skip. */
2068 if (SecIsInternalRelease()) {
2069 if (CFPreferencesGetAppBooleanValue(CFSTR("AppleServerAuthenticationNoPinning"),
2070 CFSTR("com.apple.security"), NULL
)) {
2075 CFArrayRef policies
= pvc
->policies
;
2076 CFIndex policyIX
, policyCount
= CFArrayGetCount(policies
);
2077 for (policyIX
= 0; policyIX
< policyCount
; ++policyIX
) {
2078 SecPolicyRef policy
= (SecPolicyRef
)CFArrayGetValueAtIndex(policies
, policyIX
);
2079 CFStringRef policyName
= SecPolicyGetName(policy
);
2080 if (CFEqualSafe(policyName
, kSecPolicyNameSSLServer
)) {
2081 /* policy required pinning, but we didn't use a pinning policy */
2082 if (!SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
)) {
2089 static bool is_configured_test_system_root(SecCertificateRef root
) {
2090 if (!SecIsInternalRelease()) {
2093 bool result
= false;
2094 CFDataRef rootHash
= SecCertificateCopySHA256Digest(root
);
2095 CFTypeRef value
= CFPreferencesCopyValue(CFSTR("TestCTRequiredSystemRoot"), CFSTR("com.apple.security"),
2096 kCFPreferencesAnyUser
, kCFPreferencesCurrentHost
);
2097 require_quiet(isData(value
), out
);
2098 require_quiet(kCFCompareEqualTo
== CFDataCompare(rootHash
, value
), out
);
2102 CFReleaseNull(value
);
2103 CFReleaseNull(rootHash
);
2107 static bool is_ct_excepted_domain(CFStringRef hostname
, CFStringRef exception
) {
2108 if (kCFCompareEqualTo
== CFStringCompare(exception
, hostname
, kCFCompareCaseInsensitive
)) {
2111 } else if (CFStringHasPrefix(exception
, CFSTR("."))) {
2113 CFIndex elength
= CFStringGetLength(exception
);
2114 CFIndex hlength
= CFStringGetLength(hostname
);
2115 if (hlength
> elength
) {
2116 CFRange compareRange
= { hlength
- elength
, elength
};
2117 if (kCFCompareEqualTo
== CFStringCompareWithOptions(hostname
, exception
, compareRange
, kCFCompareCaseInsensitive
)) {
2120 } else if (hlength
+ 1 == elength
) {
2121 CFRange compareRange
= { 1, hlength
};
2122 if (kCFCompareEqualTo
== CFStringCompareWithOptions(exception
, hostname
, compareRange
, kCFCompareCaseInsensitive
)) {
2130 static OSStatus
is_subtree_dn_with_org(void *context
, SecCEGeneralNameType gnType
, const DERItem
*generalName
) {
2131 if (gnType
!= GNT_DirectoryName
) {
2132 return errSecInternal
;
2135 DERDecodedInfo subtreeName_content
;
2136 if (DR_Success
!= DERDecodeItem(generalName
, &subtreeName_content
) || subtreeName_content
.tag
!= ASN1_CONSTR_SEQUENCE
) {
2137 return errSecDecode
;
2140 CFArrayRef subtree_orgs
= SecCertificateCopyOrganizationFromX501NameContent(&subtreeName_content
.content
);
2142 CFReleaseNull(subtree_orgs
);
2143 return errSecSuccess
;
2145 return errSecInternal
;
2148 static bool has_ct_excepted_key(SecCertificatePathVCRef path
, CFDictionaryRef exception
) {
2149 __block
bool result
= false;
2150 CFDataRef exceptionHash
= CFDictionaryGetValue(exception
, kSecCTExceptionsSPKIHashKey
);
2152 /* exception for a leaf is always allowed */
2153 SecCertificateRef leaf
= SecCertificatePathVCGetCertificateAtIndex(path
, 0);
2154 CFDataRef spkiHash
= SecCertificateCopySubjectPublicKeyInfoSHA256Digest(leaf
);
2155 if (CFEqualSafe(exceptionHash
, spkiHash
)) {
2158 CFReleaseNull(spkiHash
);
2160 if (result
) { return result
; }
2162 /* exceptions for CAs */
2163 for (CFIndex certIX
= 1; certIX
< SecCertificatePathVCGetCount(path
); certIX
++) {
2164 SecCertificateRef ca
= SecCertificatePathVCGetCertificateAtIndex(path
, certIX
);
2166 spkiHash
= SecCertificateCopySubjectPublicKeyInfoSHA256Digest(ca
);
2167 if (!CFEqualSafe(exceptionHash
, spkiHash
)) {
2168 CFReleaseNull(spkiHash
);
2171 CFReleaseNull(spkiHash
);
2173 /* this CA matches but exceptions for CAs have constraints */
2174 if (SecCertificateGetPermittedSubtrees(ca
)) {
2175 /* Constrained CAs have to have a Distinguished Name permitted subtree with an Organization attribute */
2176 CFArrayForEach(SecCertificateGetPermittedSubtrees(ca
), ^(const void *value
) {
2177 CFDataRef subtree
= (CFDataRef
)value
;
2178 const DERItem general_name
= { (unsigned char *)CFDataGetBytePtr(subtree
), CFDataGetLength(subtree
) };
2179 DERDecodedInfo general_name_content
;
2180 if (DR_Success
== DERDecodeItem(&general_name
, &general_name_content
)) {
2181 OSStatus status
= SecCertificateParseGeneralNameContentProperty(general_name_content
.tag
,
2182 &general_name_content
.content
,
2184 is_subtree_dn_with_org
);
2185 if (status
== errSecSuccess
) {
2193 /* The Organization attribute(s) in the CA subject have to exactly match the Organization attribute(s) in the leaf */
2194 CFArrayRef leafOrgs
= SecCertificateCopyOrganization(leaf
);
2195 CFArrayRef caOrgs
= SecCertificateCopyOrganization(ca
);
2196 if (caOrgs
&& leafOrgs
&& CFEqualSafe(leafOrgs
, caOrgs
)) {
2199 CFReleaseNull(leafOrgs
);
2200 CFReleaseNull(caOrgs
);
2211 static bool is_ct_excepted(SecPVCRef pvc
) {
2212 CFDictionaryRef ct_exceptions
= _SecTrustStoreCopyCTExceptions(NULL
, NULL
);
2213 if (!ct_exceptions
) {
2217 __block
bool result
= false;
2218 CFArrayRef domainExceptions
= CFDictionaryGetValue(ct_exceptions
, kSecCTExceptionsDomainsKey
);
2219 if (domainExceptions
) {
2220 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
2221 CFStringRef hostname
= CFDictionaryGetValue(policy
->_options
, kSecPolicyCheckSSLHostname
);
2223 CFArrayForEach(domainExceptions
, ^(const void *value
) {
2224 result
= result
|| is_ct_excepted_domain(hostname
, value
);
2229 secinfo("policy", "domain-based CT exception applied");
2230 CFReleaseNull(ct_exceptions
);
2234 CFArrayRef keyExceptions
= CFDictionaryGetValue(ct_exceptions
, kSecCTExceptionsCAsKey
);
2235 if (keyExceptions
) {
2236 __block SecCertificatePathVCRef path
= SecPathBuilderGetPath(pvc
->builder
);
2237 CFArrayForEach(keyExceptions
, ^(const void *value
) {
2238 result
= result
|| has_ct_excepted_key(path
, value
);
2243 secinfo("policy" , "key-based CT exceptions applied");
2246 CFReleaseNull(ct_exceptions
);
2250 /* <rdar://45466778> some Apple servers not getting certs with embedded SCTs
2251 * <rdar://45545270> some Google apps have their own TLS stacks and aren't passing us TLS SCTs */
2252 static bool is_apple_ca(SecCertificatePathVCRef path
) {
2253 /* subject:/CN=Apple IST CA 8 - G1/OU=Certification Authority/O=Apple Inc./C=US */
2254 /* issuer :/C=US/O=GeoTrust Inc./OU=(c) 2007 GeoTrust Inc. - For authorized use only/CN=GeoTrust Primary Certification Authority - G2 */
2255 static const uint8_t appleISTCA8G1_spkiSHA256
[] = {
2256 0xe2, 0x4f, 0x8e, 0x8c, 0x21, 0x85, 0xda, 0x2f, 0x5e, 0x88, 0xd4, 0x57, 0x9e, 0x81, 0x7c, 0x47,
2257 0xbf, 0x6e, 0xaf, 0xbc, 0x85, 0x05, 0xf0, 0xf9, 0x60, 0xfd, 0x5a, 0x0d, 0xf4, 0x47, 0x3a, 0xd3
2260 /* subject:/CN=Apple IST CA 2 - G1/OU=Certification Authority/O=Apple Inc./C=US */
2261 /* issuer :/C=US/O=GeoTrust Inc./CN=GeoTrust Global CA */
2262 static const uint8_t appleISTCA2G1_spkiSHA256
[] = {
2263 0xb5, 0xcf, 0x82, 0xd4, 0x7e, 0xf9, 0x82, 0x3f, 0x9a, 0xa7, 0x8f, 0x12, 0x31, 0x86, 0xc5, 0x2e,
2264 0x88, 0x79, 0xea, 0x84, 0xb0, 0xf8, 0x22, 0xc9, 0x1d, 0x83, 0xe0, 0x42, 0x79, 0xb7, 0x8f, 0xd5
2267 /* subject:/C=US/O=Google Trust Services/CN=Google Internet Authority G3 */
2268 /* issuer :/OU=GlobalSign Root CA - R2/O=GlobalSign/CN=GlobalSign */
2269 static const uint8_t googleIAG3_spkiSHA256
[] = {
2270 0x7f, 0xc3, 0x67, 0x10, 0x56, 0x71, 0x43, 0x81, 0x31, 0x14, 0xe8, 0x52, 0x37, 0xb1, 0x22, 0x15,
2271 0x6b, 0x62, 0xb9, 0xd6, 0x50, 0x54, 0x3d, 0xa8, 0x63, 0xad, 0x2e, 0x6a, 0xe5, 0x7f, 0x9f, 0xbf
2274 bool result
= false;
2275 for (CFIndex certIX
= 1; certIX
< SecCertificatePathVCGetCount(path
); certIX
++) {
2276 SecCertificateRef ca
= SecCertificatePathVCGetCertificateAtIndex(path
, certIX
);
2278 CFDataRef caSPKIHash
= SecCertificateCopySubjectPublicKeyInfoSHA256Digest(ca
);
2279 const uint8_t *dp
= CFDataGetBytePtr(caSPKIHash
);
2280 if (dp
&& (!memcmp(appleISTCA8G1_spkiSHA256
, dp
, CC_SHA256_DIGEST_LENGTH
) ||
2281 !memcmp(appleISTCA2G1_spkiSHA256
, dp
, CC_SHA256_DIGEST_LENGTH
) ||
2282 !memcmp(googleIAG3_spkiSHA256
, dp
, CC_SHA256_DIGEST_LENGTH
))) {
2285 CFReleaseNull(caSPKIHash
);
2293 static void SecPolicyCheckSystemTrustedCTRequired(SecPVCRef pvc
) {
2294 SecCertificateSourceRef appleAnchorSource
= NULL
;
2295 SecOTAPKIRef otaref
= SecOTAPKICopyCurrentOTAPKIRef();
2296 SecCertificatePathVCRef path
= SecPathBuilderGetPath(pvc
->builder
);
2297 CFArrayRef trustedLogs
= SecPathBuilderCopyTrustedLogs(pvc
->builder
);
2299 /* Skip this check if we haven't done the CT checks yet */
2300 require_quiet(SecCertificatePathVCIsPathValidated(path
), out
);
2302 /* We only enforce this check when all of the following are true:
2303 * 0. Not a pinning policy */
2304 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
2305 require_quiet(CFEqualSafe(SecPolicyGetName(policy
),kSecPolicyNameSSLServer
), out
);
2307 /* 1. Device has checked in to MobileAsset for a current log list within the last 60 days.
2308 * Or the caller passed in the trusted log list. */
2309 require_quiet(SecOTAPKIAssetStalenessLessThanSeconds(otaref
, kSecOTAPKIAssetStalenessDisable
) || trustedLogs
, out
);
2311 /* 2. Leaf issuance date is on or after 16 Oct 2018 at 00:00:00 AM UTC and not expired. */
2312 SecCertificateRef leaf
= SecPVCGetCertificateAtIndex(pvc
, 0);
2313 require_quiet(SecCertificateNotValidBefore(leaf
) >= 561340800.0 &&
2314 SecCertificateIsValid(leaf
, SecPVCGetVerifyTime(pvc
)), out
);
2316 /* 3. Chain is anchored with root in the system anchor source but not the Apple anchor source */
2317 CFIndex count
= SecPVCGetCertificateCount(pvc
);
2318 SecCertificateRef root
= SecPVCGetCertificateAtIndex(pvc
, count
- 1);
2319 appleAnchorSource
= SecMemoryCertificateSourceCreate(SecGetAppleTrustAnchors(false));
2320 require_quiet(SecPathBuilderIsAnchored(pvc
->builder
), out
);
2321 require_quiet((SecCertificateSourceContains(kSecSystemAnchorSource
, root
) &&
2322 appleAnchorSource
&& !SecCertificateSourceContains(appleAnchorSource
, root
) &&
2323 !is_apple_ca(path
)) ||
2324 is_configured_test_system_root(root
), out
);
2326 if (!SecCertificatePathVCIsCT(path
) && !is_ct_excepted(pvc
)) {
2327 /* Set failure. By not using the Forced variant, we implicitly check that this
2328 * policy had this options set. */
2329 SecPVCSetResult(pvc
, kSecPolicyCheckSystemTrustedCTRequired
, 0, kCFBooleanFalse
);
2333 CFReleaseNull(trustedLogs
);
2334 CFReleaseNull(otaref
);
2335 if (appleAnchorSource
) {
2336 SecMemoryCertificateSourceDestroy(appleAnchorSource
);
2340 void SecPolicyServerInitialize(void) {
2341 gSecPolicyLeafCallbacks
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0,
2342 &kCFTypeDictionaryKeyCallBacks
, NULL
);
2343 gSecPolicyPathCallbacks
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0,
2344 &kCFTypeDictionaryKeyCallBacks
, NULL
);
2346 #undef POLICYCHECKMACRO
2347 #define __PC_ADD_CHECK_(NAME)
2348 #define __PC_ADD_CHECK_L(NAME) CFDictionaryAddValue(gSecPolicyLeafCallbacks, kSecPolicyCheck##NAME, SecPolicyCheck##NAME);
2349 #define __PC_ADD_CHECK_A(NAME) CFDictionaryAddValue(gSecPolicyPathCallbacks, kSecPolicyCheck##NAME, SecPolicyCheck##NAME);
2351 #define POLICYCHECKMACRO(NAME, TRUSTRESULT, SUBTYPE, LEAFCHECK, PATHCHECK, LEAFONLY, CSSMERR, OSSTATUS) \
2352 __PC_ADD_CHECK_##LEAFCHECK(NAME) \
2353 __PC_ADD_CHECK_##PATHCHECK(NAME)
2354 #include "../Security/SecPolicyChecks.list"
2356 /* Some of these don't follow the naming conventions but are in the Pinning DB.
2357 * <rdar://34537018> fix policy check constant values */
2358 CFDictionaryAddValue(gSecPolicyLeafCallbacks
, CFSTR("CheckLeafMarkerOid"), SecPolicyCheckLeafMarkerOid
);
2359 CFDictionaryAddValue(gSecPolicyLeafCallbacks
, CFSTR("CheckLeafMarkersProdAndQA"), SecPolicyCheckLeafMarkersProdAndQA
);
2360 CFDictionaryAddValue(gSecPolicyPathCallbacks
, CFSTR("CheckIntermediateMarkerOid"), SecPolicyCheckIntermediateMarkerOid
);
2361 CFDictionaryAddValue(gSecPolicyPathCallbacks
, CFSTR("CheckIntermediateCountry"), SecPolicyCheckIntermediateCountry
);
2362 CFDictionaryAddValue(gSecPolicyPathCallbacks
, CFSTR("CheckIntermediateOrganization"), SecPolicyCheckIntermediateOrganization
);
2367 /********************************************************
2368 ****************** SecPVCRef Functions *****************
2369 ********************************************************/
2371 void SecPVCInit(SecPVCRef pvc
, SecPathBuilderRef builder
, CFArrayRef policies
) {
2372 secdebug("alloc", "pvc %p", pvc
);
2373 // Weird logging policies crashes.
2374 //secdebug("policy", "%@", policies);
2376 // Zero the pvc struct so only non-zero fields need to be explicitly set
2377 memset(pvc
, 0, sizeof(struct OpaqueSecPVC
));
2378 pvc
->builder
= builder
;
2379 pvc
->policies
= policies
;
2382 pvc
->result
= kSecTrustResultUnspecified
;
2384 CFMutableDictionaryRef certDetail
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0,
2385 &kCFTypeDictionaryKeyCallBacks
,
2386 &kCFTypeDictionaryValueCallBacks
);
2387 pvc
->leafDetails
= CFArrayCreate(kCFAllocatorDefault
, (const void **)&certDetail
,
2388 1, &kCFTypeArrayCallBacks
);
2389 CFRelease(certDetail
);
2392 void SecPVCDelete(SecPVCRef pvc
) {
2393 secdebug("alloc", "delete pvc %p", pvc
);
2394 CFReleaseNull(pvc
->policies
);
2395 CFReleaseNull(pvc
->details
);
2396 CFReleaseNull(pvc
->leafDetails
);
2399 void SecPVCSetPath(SecPVCRef pvc
, SecCertificatePathVCRef path
) {
2400 secdebug("policy", "%@", path
);
2402 pvc
->result
= kSecTrustResultUnspecified
;
2403 CFReleaseNull(pvc
->details
);
2406 void SecPVCComputeDetails(SecPVCRef pvc
, SecCertificatePathVCRef path
) {
2409 /* Since we don't run the LeafChecks again, we need to preserve the
2410 * result the leaf had. */
2411 CFIndex ix
, pathLength
= SecCertificatePathVCGetCount(path
);
2412 CFMutableArrayRef details
= CFArrayCreateMutableCopy(kCFAllocatorDefault
,
2413 pathLength
, pvc
->leafDetails
);
2414 for (ix
= 1; ix
< pathLength
; ++ix
) {
2415 CFMutableDictionaryRef certDetail
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0,
2416 &kCFTypeDictionaryKeyCallBacks
,
2417 &kCFTypeDictionaryValueCallBacks
);
2418 CFArrayAppendValue(details
, certDetail
);
2419 CFRelease(certDetail
);
2421 CFRetainAssign(pvc
->details
, details
);
2422 pvc
->result
= pvc
->leafResult
;
2423 CFReleaseSafe(details
);
2426 SecPolicyRef
SecPVCGetPolicy(SecPVCRef pvc
) {
2427 return (SecPolicyRef
)CFArrayGetValueAtIndex(pvc
->policies
, pvc
->policyIX
);
2430 static CFIndex
SecPVCGetCertificateCount(SecPVCRef pvc
) {
2431 return SecPathBuilderGetCertificateCount(pvc
->builder
);
2434 static SecCertificateRef
SecPVCGetCertificateAtIndex(SecPVCRef pvc
, CFIndex ix
) {
2435 return SecPathBuilderGetCertificateAtIndex(pvc
->builder
, ix
);
2438 static CFAbsoluteTime
SecPVCGetVerifyTime(SecPVCRef pvc
) {
2439 return SecPathBuilderGetVerifyTime(pvc
->builder
);
2442 static bool SecPVCIsExceptedError(SecPVCRef pvc
, CFIndex ix
, CFStringRef key
, CFTypeRef value
) {
2443 CFArrayRef exceptions
= SecPathBuilderGetExceptions(pvc
->builder
);
2444 if (!exceptions
) { return false; }
2445 CFIndex exceptionsCount
= CFArrayGetCount(exceptions
);
2447 /* There are two types of exceptions:
2448 * 1. Those that are built from SecTrustCopyExceptions, which are particular to the
2449 * certs in the chain -- as indicated by the SHA1 digest in the exception dictionary.
2450 * 2. On macOS, those built from SecTrustSetOptions, which are generic excepted errors.
2453 CFDictionaryRef options
= CFArrayGetValueAtIndex(exceptions
, 0);
2455 if (exceptionsCount
== 1 && (ix
> 0 || !CFDictionaryContainsKey(options
, kSecCertificateDetailSHA1Digest
))) {
2456 /* SHA1Digest not allowed */
2457 if (CFDictionaryContainsKey(options
, kSecCertificateDetailSHA1Digest
)) { return false; }
2459 if (CFDictionaryContainsKey(options
, key
)) {
2460 /* Special case -- AnchorTrusted only for self-signed certs */
2461 if (CFEqual(kSecPolicyCheckAnchorTrusted
, key
)) {
2462 Boolean isSelfSigned
= false;
2463 SecCertificateRef cert
= SecPathBuilderGetCertificateAtIndex(pvc
->builder
, ix
);
2464 if (!cert
|| (errSecSuccess
!= SecCertificateIsSelfSigned(cert
, &isSelfSigned
)) || !isSelfSigned
) {
2469 } else if (CFEqual(key
, kSecPolicyCheckTemporalValidity
) && CFDictionaryContainsKey(options
, kSecPolicyCheckValidRoot
)) {
2470 /* Another special case - ValidRoot excepts Valid only for self-signed certs */
2471 Boolean isSelfSigned
= false;
2472 SecCertificateRef cert
= SecPathBuilderGetCertificateAtIndex(pvc
->builder
, ix
);
2473 if (!cert
|| (errSecSuccess
!= SecCertificateIsSelfSigned(cert
, &isSelfSigned
)) || !isSelfSigned
) {
2482 if (ix
>= exceptionsCount
) { return false; }
2483 CFDictionaryRef exception
= CFArrayGetValueAtIndex(exceptions
, ix
);
2485 /* Compare the cert hash */
2486 if (!CFDictionaryContainsKey(exception
, kSecCertificateDetailSHA1Digest
)) { return false; }
2487 SecCertificateRef cert
= SecPathBuilderGetCertificateAtIndex(pvc
->builder
, ix
);
2488 if (!CFEqual(SecCertificateGetSHA1Digest(cert
), CFDictionaryGetValue(exception
, kSecCertificateDetailSHA1Digest
))) {
2493 CFTypeRef exceptionValue
= CFDictionaryGetValue(exception
, key
);
2494 if (exceptionValue
&& CFEqual(value
, exceptionValue
)) {
2495 /* Only change result if PVC is already ok */
2496 if (SecPVCIsOkResult(pvc
)) {
2497 // Chains that pass due to exceptions get Proceed result.
2498 pvc
->result
= kSecTrustResultProceed
;
2506 static int32_t detailKeyToCssmErr(CFStringRef key
) {
2509 if (CFEqual(key
, kSecPolicyCheckSSLHostname
)) {
2510 result
= -2147408896; // CSSMERR_APPLETP_HOSTNAME_MISMATCH
2512 else if (CFEqual(key
, kSecPolicyCheckEmail
)) {
2513 result
= -2147408872; // CSSMERR_APPLETP_SMIME_EMAIL_ADDRS_NOT_FOUND
2515 else if (CFEqual(key
, kSecPolicyCheckTemporalValidity
)) {
2516 result
= -2147409654; // CSSMERR_TP_CERT_EXPIRED
2522 static bool SecPVCMeetsConstraint(SecPVCRef pvc
, SecCertificateRef certificate
, CFDictionaryRef constraint
);
2524 static bool SecPVCIsAllowedError(SecPVCRef pvc
, CFIndex ix
, CFStringRef key
) {
2525 bool result
= false;
2526 SecCertificatePathVCRef path
= SecPathBuilderGetPath(pvc
->builder
);
2527 CFArrayRef constraints
= SecCertificatePathVCGetUsageConstraintsAtIndex(path
, ix
);
2528 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, ix
);
2529 CFIndex constraintIX
, constraintCount
= CFArrayGetCount(constraints
);
2531 for (constraintIX
= 0; constraintIX
< constraintCount
; constraintIX
++) {
2532 CFDictionaryRef constraint
= (CFDictionaryRef
)CFArrayGetValueAtIndex(constraints
, constraintIX
);
2533 CFNumberRef allowedErrorNumber
= NULL
;
2534 if (!isDictionary(constraint
)) {
2537 allowedErrorNumber
= (CFNumberRef
)CFDictionaryGetValue(constraint
, kSecTrustSettingsAllowedError
);
2538 int32_t allowedErrorValue
= 0;
2539 if (!isNumber(allowedErrorNumber
) || !CFNumberGetValue(allowedErrorNumber
, kCFNumberSInt32Type
, &allowedErrorValue
)) {
2543 if (SecPVCMeetsConstraint(pvc
, cert
, constraint
)) {
2544 if (allowedErrorValue
== detailKeyToCssmErr(key
)) {
2553 static bool SecPVCKeyIsConstraintPolicyOption(SecPVCRef pvc
, CFStringRef key
) {
2554 CFIndex certIX
, certCount
= SecPVCGetCertificateCount(pvc
);
2555 for (certIX
= 0; certIX
< certCount
; certIX
++) {
2556 SecCertificatePathVCRef path
= SecPathBuilderGetPath(pvc
->builder
);
2557 CFArrayRef constraints
= SecCertificatePathVCGetUsageConstraintsAtIndex(path
, certIX
);
2558 CFIndex constraintIX
, constraintCount
= CFArrayGetCount(constraints
);
2559 for (constraintIX
= 0; constraintIX
< constraintCount
; constraintIX
++) {
2560 CFDictionaryRef constraint
= (CFDictionaryRef
)CFArrayGetValueAtIndex(constraints
, constraintIX
);
2561 if (!isDictionary(constraint
)) {
2565 CFDictionaryRef policyOptions
= NULL
;
2566 policyOptions
= (CFDictionaryRef
)CFDictionaryGetValue(constraint
, kSecTrustSettingsPolicyOptions
);
2567 if (policyOptions
&& isDictionary(policyOptions
) &&
2568 CFDictionaryContainsKey(policyOptions
, key
)) {
2576 static SecTrustResultType
trust_result_for_key(CFStringRef key
) {
2577 SecTrustResultType result
= kSecTrustResultRecoverableTrustFailure
;
2578 #undef POLICYCHECKMACRO
2579 #define __PC_TYPE_MEMBER_ false
2580 #define __PC_TYPE_MEMBER_R false
2581 #define __PC_TYPE_MEMBER_F true
2582 #define __PC_TYPE_MEMBER_D true
2584 #define __TRUSTRESULT_ kSecTrustResultRecoverableTrustFailure
2585 #define __TRUSTRESULT_F kSecTrustResultFatalTrustFailure
2586 #define __TRUSTRESULT_D kSecTrustResultDeny
2587 #define __TRUSTRESULT_R kSecTrustResultRecoverableTrustFailure
2589 #define POLICYCHECKMACRO(NAME, TRUSTRESULT, SUBTYPE, LEAFCHECK, PATHCHECK, LEAFONLY, CSSMERR, OSSTATUS) \
2590 if (__PC_TYPE_MEMBER_##TRUSTRESULT && CFEqual(key,CFSTR(#NAME))) { \
2591 result = __TRUSTRESULT_##TRUSTRESULT; \
2593 #include "../Security/SecPolicyChecks.list"
2598 /* AUDIT[securityd](done):
2599 policy->_options is a caller provided dictionary, only its cf type has
2602 bool SecPVCSetResultForced(SecPVCRef pvc
,
2603 CFStringRef key
, CFIndex ix
, CFTypeRef result
, bool force
) {
2605 secnotice("policy", "cert[%d]: %@ =(%s)[%s]> %@", (int) ix
, key
,
2606 (pvc
->callbacks
== gSecPolicyLeafCallbacks
? "leaf"
2607 : (pvc
->callbacks
== gSecPolicyPathCallbacks
? "path"
2609 (force
? "force" : ""), result
);
2611 /* If this is not something the current policy cares about ignore
2612 this error and return true so our caller continues evaluation. */
2614 /* Either the policy or the usage constraints have to have this key */
2615 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
2616 if (!(SecPVCKeyIsConstraintPolicyOption(pvc
, key
) ||
2617 (policy
&& CFDictionaryContainsKey(policy
->_options
, key
)))) {
2622 /* Check to see if the SecTrustSettings for the certificate in question
2623 tell us to ignore this error. */
2624 if (SecPVCIsAllowedError(pvc
, ix
, key
)) {
2625 secinfo("policy", "cert[%d]: skipped allowed error %@", (int) ix
, key
);
2629 /* Check to see if exceptions tells us to ignore this error. */
2630 if (SecPVCIsExceptedError(pvc
, ix
, key
, result
)) {
2631 secinfo("policy", "cert[%d]: skipped exception error %@", (int) ix
, key
);
2635 /* Avoid resetting deny or fatal to recoverable */
2636 SecTrustResultType trustResult
= trust_result_for_key(key
);
2637 if (SecPVCIsOkResult(pvc
) || trustResult
== kSecTrustResultFatalTrustFailure
) {
2638 pvc
->result
= trustResult
;
2639 } else if (trustResult
== kSecTrustResultDeny
&&
2640 pvc
->result
== kSecTrustResultRecoverableTrustFailure
) {
2641 pvc
->result
= trustResult
;
2647 CFMutableDictionaryRef detail
=
2648 (CFMutableDictionaryRef
)CFArrayGetValueAtIndex(pvc
->details
, ix
);
2650 /* Perhaps detail should have an array of results per key? As it stands
2651 in the case of multiple policy failures the last failure stands. */
2652 CFDictionarySetValue(detail
, key
, result
);
2657 bool SecPVCSetResult(SecPVCRef pvc
,
2658 CFStringRef key
, CFIndex ix
, CFTypeRef result
) {
2659 return SecPVCSetResultForced(pvc
, key
, ix
, result
, false);
2662 /* AUDIT[securityd](done):
2663 key(ok) is a caller provided.
2664 value(ok, unused) is a caller provided.
2666 static void SecPVCValidateKey(const void *key
, const void *value
,
2668 SecPVCRef pvc
= (SecPVCRef
)context
;
2670 /* If our caller doesn't want full details and we failed earlier there is
2671 no point in doing additional checks. */
2672 if (!SecPVCIsOkResult(pvc
) && !pvc
->details
)
2675 SecPolicyCheckFunction fcn
= (SecPolicyCheckFunction
)
2676 CFDictionaryGetValue(pvc
->callbacks
, key
);
2679 /* "Optional" policy checks. This may be a new key from the
2680 * pinning DB which is not implemented in this OS version. Log a
2681 * warning, and on debug builds fail evaluation, to encourage us
2682 * to ensure that checks are synchronized across the same build. */
2683 if (pvc
->callbacks
== gSecPolicyLeafCallbacks
) {
2684 if (!CFDictionaryContainsKey(gSecPolicyPathCallbacks
, key
)) {
2685 secwarning("policy: unknown policy key %@, skipping", key
);
2687 pvc
->result
= kSecTrustResultOtherError
;
2690 } else if (pvc
->callbacks
== gSecPolicyPathCallbacks
) {
2691 if (!CFDictionaryContainsKey(gSecPolicyLeafCallbacks
, key
)) {
2692 secwarning("policy: unknown policy key %@, skipping", key
);
2694 pvc
->result
= kSecTrustResultOtherError
;
2698 /* Non standard validation phase, nothing is optional. */
2699 pvc
->result
= kSecTrustResultOtherError
;
2704 fcn(pvc
, (CFStringRef
)key
);
2707 /* AUDIT[securityd](done):
2708 policy->_options is a caller provided dictionary, only its cf type has
2711 SecTrustResultType
SecPVCLeafChecks(SecPVCRef pvc
) {
2712 /* We need to compute details for the leaf. */
2713 CFRetainAssign(pvc
->details
, pvc
->leafDetails
);
2715 CFArrayRef policies
= pvc
->policies
;
2716 CFIndex ix
, count
= CFArrayGetCount(policies
);
2717 for (ix
= 0; ix
< count
; ++ix
) {
2718 SecPolicyRef policy
= (SecPolicyRef
)CFArrayGetValueAtIndex(policies
, ix
);
2720 /* Validate all keys for all policies. */
2721 pvc
->callbacks
= gSecPolicyLeafCallbacks
;
2722 CFDictionaryApplyFunction(policy
->_options
, SecPVCValidateKey
, pvc
);
2725 pvc
->leafResult
= pvc
->result
;
2726 CFRetainAssign(pvc
->leafDetails
, pvc
->details
);
2731 bool SecPVCIsOkResult(SecPVCRef pvc
) {
2732 if (pvc
->result
== kSecTrustResultRecoverableTrustFailure
||
2733 pvc
->result
== kSecTrustResultDeny
||
2734 pvc
->result
== kSecTrustResultFatalTrustFailure
||
2735 pvc
->result
== kSecTrustResultOtherError
) {
2741 bool SecPVCParentCertificateChecks(SecPVCRef pvc
, CFIndex ix
) {
2742 /* Check stuff common to intermediate and anchors. */
2743 CFAbsoluteTime verifyTime
= SecPVCGetVerifyTime(pvc
);
2744 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, ix
);
2745 CFIndex anchor_ix
= SecPVCGetCertificateCount(pvc
) - 1;
2746 bool is_anchor
= (ix
== anchor_ix
&& SecPathBuilderIsAnchored(pvc
->builder
));
2748 if (!SecCertificateIsValid(cert
, verifyTime
)) {
2749 /* Certificate has expired. */
2750 if (!SecPVCSetResult(pvc
, kSecPolicyCheckTemporalValidity
, ix
, kCFBooleanFalse
)) {
2755 if (SecCertificateIsWeakKey(cert
)) {
2756 /* Certificate uses weak key. */
2757 if (!SecPVCSetResult(pvc
, kSecPolicyCheckWeakKeySize
, ix
, kCFBooleanFalse
)) {
2762 if (!SecPolicyCheckCertWeakSignature(cert
, NULL
)) {
2763 /* Certificate uses weak hash. */
2764 if (!SecPVCSetResult(pvc
, kSecPolicyCheckWeakSignature
, ix
, kCFBooleanFalse
)) {
2770 /* Perform anchor specific checks. */
2771 /* Don't think we have any of these. */
2773 /* Perform intermediate specific checks. */
2775 /* (k) Basic constraints only relevant for v3 and later. */
2776 if (SecCertificateVersion(cert
) >= 3) {
2777 const SecCEBasicConstraints
*bc
=
2778 SecCertificateGetBasicConstraints(cert
);
2780 /* Basic constraints not present, illegal. */
2781 if (!SecPVCSetResultForced(pvc
, kSecPolicyCheckBasicConstraints
,
2782 ix
, kCFBooleanFalse
, true)) {
2785 } else if (!bc
->isCA
) {
2786 /* Basic constraints not marked as isCA, illegal. */
2787 if (!SecPVCSetResultForced(pvc
, kSecPolicyCheckBasicConstraintsCA
,
2788 ix
, kCFBooleanFalse
, true)) {
2793 /* For a v1 or v2 certificate in an intermediate slot (not a leaf and
2794 not an anchor), we additionally require that the certificate chain
2795 does not end in a v3 or later anchor. [rdar://32204517] */
2796 else if (ix
> 0 && ix
< anchor_ix
) {
2797 SecCertificateRef anchor
= SecPVCGetCertificateAtIndex(pvc
, anchor_ix
);
2798 if (SecCertificateVersion(anchor
) >= 3) {
2799 if (!SecPVCSetResultForced(pvc
, kSecPolicyCheckBasicConstraints
,
2800 ix
, kCFBooleanFalse
, true)) {
2805 /* (l) max_path_length is checked elsewhere. */
2807 /* (n) If a key usage extension is present, verify that the keyCertSign bit is set. */
2808 SecKeyUsage keyUsage
= SecCertificateGetKeyUsage(cert
);
2809 if (keyUsage
&& !(keyUsage
& kSecKeyUsageKeyCertSign
)) {
2810 if (!SecPVCSetResultForced(pvc
, kSecPolicyCheckKeyUsage
,
2811 ix
, kCFBooleanFalse
, true)) {
2818 return SecPVCIsOkResult(pvc
);
2821 static bool SecPVCBlackListedKeyChecks(SecPVCRef pvc
, CFIndex ix
) {
2822 /* Check stuff common to intermediate and anchors. */
2824 SecOTAPKIRef otapkiRef
= SecOTAPKICopyCurrentOTAPKIRef();
2825 if (NULL
!= otapkiRef
)
2827 CFSetRef blackListedKeys
= SecOTAPKICopyBlackListSet(otapkiRef
);
2828 CFRelease(otapkiRef
);
2829 if (NULL
!= blackListedKeys
)
2831 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, ix
);
2832 CFIndex count
= SecPVCGetCertificateCount(pvc
);
2833 bool is_last
= (ix
== count
- 1);
2834 bool is_anchor
= (is_last
&& SecPathBuilderIsAnchored(pvc
->builder
));
2836 /* Check for blacklisted intermediate issuer keys. */
2837 CFDataRef dgst
= SecCertificateCopyPublicKeySHA1Digest(cert
);
2839 /* Check dgst against blacklist. */
2840 if (CFSetContainsValue(blackListedKeys
, dgst
)) {
2841 /* Check allow list for this blacklisted issuer key,
2842 which is the authority key of the issued cert at ix-1.
2844 SecCertificatePathVCRef path
= SecPathBuilderGetPath(pvc
->builder
);
2845 bool allowed
= path
&& SecCertificatePathVCIsAllowlisted(path
);
2847 SecPVCSetResultForced(pvc
, kSecPolicyCheckBlackListedKey
,
2848 ix
, kCFBooleanFalse
, true);
2854 CFRelease(blackListedKeys
);
2855 return SecPVCIsOkResult(pvc
);
2862 static bool SecPVCGrayListedKeyChecks(SecPVCRef pvc
, CFIndex ix
)
2864 /* Check stuff common to intermediate and anchors. */
2865 SecOTAPKIRef otapkiRef
= SecOTAPKICopyCurrentOTAPKIRef();
2866 if (NULL
!= otapkiRef
)
2868 CFSetRef grayListKeys
= SecOTAPKICopyGrayList(otapkiRef
);
2869 CFRelease(otapkiRef
);
2870 if (NULL
!= grayListKeys
)
2872 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, ix
);
2873 CFIndex count
= SecPVCGetCertificateCount(pvc
);
2874 bool is_last
= (ix
== count
- 1);
2875 bool is_anchor
= (is_last
&& SecPathBuilderIsAnchored(pvc
->builder
));
2877 /* Check for gray listed intermediate issuer keys. */
2878 CFDataRef dgst
= SecCertificateCopyPublicKeySHA1Digest(cert
);
2880 /* Check dgst against gray list. */
2881 if (CFSetContainsValue(grayListKeys
, dgst
)) {
2882 /* Check allow list for this graylisted issuer key,
2883 which is the authority key of the issued cert at ix-1.
2885 SecCertificatePathVCRef path
= SecPathBuilderGetPath(pvc
->builder
);
2886 bool allowed
= path
&& SecCertificatePathVCIsAllowlisted(path
);
2888 SecPVCSetResultForced(pvc
, kSecPolicyCheckGrayListedKey
,
2889 ix
, kCFBooleanFalse
, true);
2895 CFRelease(grayListKeys
);
2896 return SecPVCIsOkResult(pvc
);
2903 static bool SecPVCContainsPolicy(SecPVCRef pvc
, CFStringRef searchOid
, CFStringRef searchName
, CFIndex
*policyIX
) {
2904 if (!isString(searchName
) && !isString(searchOid
)) {
2907 CFArrayRef policies
= pvc
->policies
;
2908 CFIndex ix
, count
= CFArrayGetCount(policies
);
2909 for (ix
= 0; ix
< count
; ++ix
) {
2910 SecPolicyRef policy
= (SecPolicyRef
)CFArrayGetValueAtIndex(policies
, ix
);
2911 CFStringRef policyName
= SecPolicyGetName(policy
);
2912 CFStringRef policyOid
= SecPolicyGetOidString(policy
);
2913 /* Prefer a match of both name and OID */
2914 if (searchOid
&& searchName
&& policyOid
&& policyName
) {
2915 if (CFEqual(searchOid
, policyOid
) &&
2916 CFEqual(searchName
, policyName
)) {
2917 if (policyIX
) { *policyIX
= ix
; }
2920 /* <rdar://40617139> sslServer trust settings need to apply to evals using policyName pinning
2921 * but make sure we don't use this for SSL Client trust settings or policies. */
2922 if (CFEqual(searchOid
, policyOid
) &&
2923 CFEqual(searchName
, kSecPolicyNameSSLServer
) && !CFEqual(policyName
, kSecPolicyNameSSLClient
)) {
2924 if (policyIX
) { *policyIX
= ix
; }
2928 /* Next best is just OID. */
2929 if (!searchName
&& searchOid
&& policyOid
) {
2930 if (CFEqual(searchOid
, policyOid
)) {
2931 if (policyIX
) { *policyIX
= ix
; }
2935 if (!searchOid
&& searchName
&& policyName
) {
2936 if (CFEqual(searchName
, policyName
)) {
2937 if (policyIX
) { *policyIX
= ix
; }
2945 static bool SecPVCContainsString(SecPVCRef pvc
, CFIndex policyIX
, CFStringRef stringValue
) {
2946 if (!isString(stringValue
)) {
2949 bool result
= false;
2951 CFStringRef tmpStringValue
= NULL
;
2952 if (CFStringGetCharacterAtIndex(stringValue
, CFStringGetLength(stringValue
) -1) == (UniChar
)0x0000) {
2953 tmpStringValue
= CFStringCreateTruncatedCopy(stringValue
, CFStringGetLength(stringValue
) - 1);
2955 tmpStringValue
= CFStringCreateCopy(NULL
, stringValue
);
2957 if (policyIX
>= 0 && policyIX
< CFArrayGetCount(pvc
->policies
)) {
2958 SecPolicyRef policy
= (SecPolicyRef
)CFArrayGetValueAtIndex(pvc
->policies
, policyIX
);
2959 /* Have to look for all the possible locations of name string */
2960 CFStringRef policyString
= NULL
;
2961 policyString
= CFDictionaryGetValue(policy
->_options
, kSecPolicyCheckSSLHostname
);
2962 if (!policyString
) {
2963 policyString
= CFDictionaryGetValue(policy
->_options
, kSecPolicyCheckEmail
);
2965 if (policyString
&& (CFStringCompare(tmpStringValue
, policyString
, kCFCompareCaseInsensitive
) == kCFCompareEqualTo
)) {
2970 CFArrayRef policyStrings
= NULL
;
2971 policyStrings
= CFDictionaryGetValue(policy
->_options
, kSecPolicyCheckEAPTrustedServerNames
);
2972 if (policyStrings
&& CFArrayContainsValue(policyStrings
,
2973 CFRangeMake(0, CFArrayGetCount(policyStrings
)),
2981 CFReleaseNull(tmpStringValue
);
2986 static uint32_t ts_key_usage_for_kuNumber(CFNumberRef keyUsageNumber
) {
2987 uint32_t ourTSKeyUsage
= 0;
2988 uint32_t keyUsage
= 0;
2989 if (keyUsageNumber
&&
2990 CFNumberGetValue(keyUsageNumber
, kCFNumberSInt32Type
, &keyUsage
)) {
2991 if (keyUsage
& kSecKeyUsageDigitalSignature
) {
2992 ourTSKeyUsage
|= kSecTrustSettingsKeyUseSignature
;
2994 if (keyUsage
& kSecKeyUsageDataEncipherment
) {
2995 ourTSKeyUsage
|= kSecTrustSettingsKeyUseEnDecryptData
;
2997 if (keyUsage
& kSecKeyUsageKeyEncipherment
) {
2998 ourTSKeyUsage
|= kSecTrustSettingsKeyUseEnDecryptKey
;
3000 if (keyUsage
& kSecKeyUsageKeyAgreement
) {
3001 ourTSKeyUsage
|= kSecTrustSettingsKeyUseKeyExchange
;
3003 if (keyUsage
== kSecKeyUsageAll
) {
3004 ourTSKeyUsage
= kSecTrustSettingsKeyUseAny
;
3007 return ourTSKeyUsage
;
3010 static uint32_t ts_key_usage_for_policy(SecPolicyRef policy
) {
3011 uint32_t ourTSKeyUsage
= 0;
3012 CFTypeRef policyKeyUsageType
= NULL
;
3014 policyKeyUsageType
= (CFTypeRef
)CFDictionaryGetValue(policy
->_options
, kSecPolicyCheckKeyUsage
);
3015 if (isArray(policyKeyUsageType
)) {
3016 CFIndex ix
, count
= CFArrayGetCount(policyKeyUsageType
);
3017 for (ix
= 0; ix
< count
; ix
++) {
3018 CFNumberRef policyKeyUsageNumber
= NULL
;
3019 policyKeyUsageNumber
= (CFNumberRef
)CFArrayGetValueAtIndex(policyKeyUsageType
, ix
);
3020 ourTSKeyUsage
|= ts_key_usage_for_kuNumber(policyKeyUsageNumber
);
3022 } else if (isNumber(policyKeyUsageType
)) {
3023 ourTSKeyUsage
|= ts_key_usage_for_kuNumber(policyKeyUsageType
);
3026 return ourTSKeyUsage
;
3029 static bool SecPVCContainsTrustSettingsKeyUsage(SecPVCRef pvc
,
3030 SecCertificateRef certificate
, CFIndex policyIX
, CFNumberRef keyUsageNumber
) {
3031 int64_t keyUsageValue
= 0;
3032 uint32_t ourKeyUsage
= 0;
3034 if (!isNumber(keyUsageNumber
) || !CFNumberGetValue(keyUsageNumber
, kCFNumberSInt64Type
, &keyUsageValue
)) {
3038 if (keyUsageValue
== kSecTrustSettingsKeyUseAny
) {
3042 /* We're using the key for revocation if we have the OCSPSigner policy.
3043 * @@@ If we support CRLs, we'd need to check for that policy here too.
3045 if (SecPVCContainsPolicy(pvc
, kSecPolicyAppleOCSPSigner
, NULL
, NULL
)) {
3046 ourKeyUsage
|= kSecTrustSettingsKeyUseSignRevocation
;
3049 /* We're using the key for verifying a cert if it's a root/intermediate
3050 * in the chain. If the cert isn't in the path yet, we're about to add it,
3051 * so it's a root/intermediate. If there is no path, this is the leaf.
3053 CFIndex pathIndex
= -1;
3054 SecCertificatePathVCRef path
= SecPathBuilderGetPath(pvc
->builder
);
3056 pathIndex
= SecCertificatePathVCGetIndexOfCertificate(path
, certificate
);
3060 if (pathIndex
!= 0) {
3061 ourKeyUsage
|= kSecTrustSettingsKeyUseSignCert
;
3064 /* The rest of the key usages may be specified by the policy(ies). */
3065 if (policyIX
>= 0 && policyIX
< CFArrayGetCount(pvc
->policies
)) {
3066 SecPolicyRef policy
= (SecPolicyRef
)CFArrayGetValueAtIndex(pvc
->policies
, policyIX
);
3067 ourKeyUsage
|= ts_key_usage_for_policy(policy
);
3069 /* Get key usage from ALL policies */
3070 CFIndex ix
, count
= CFArrayGetCount(pvc
->policies
);
3071 for (ix
= 0; ix
< count
; ix
++) {
3072 SecPolicyRef policy
= (SecPolicyRef
)CFArrayGetValueAtIndex(pvc
->policies
, ix
);
3073 ourKeyUsage
|= ts_key_usage_for_policy(policy
);
3077 if (ourKeyUsage
== (uint32_t)(keyUsageValue
& 0x00ffffffff)) {
3085 #include <Security/SecTrustedApplicationPriv.h>
3086 #include <Security/SecTask.h>
3087 #include <Security/SecTaskPriv.h>
3088 #include <bsm/libbsm.h>
3089 #include <libproc.h>
3091 extern OSStatus
SecTaskValidateForRequirement(SecTaskRef task
, CFStringRef requirement
);
3093 static bool SecPVCCallerIsApplication(CFDataRef clientAuditToken
, CFTypeRef appRef
) {
3094 bool result
= false;
3095 audit_token_t auditToken
= {};
3096 SecTaskRef task
= NULL
;
3097 SecRequirementRef requirement
= NULL
;
3098 CFStringRef stringRequirement
= NULL
;
3100 require(appRef
&& clientAuditToken
, out
);
3101 require(CFGetTypeID(appRef
) == SecTrustedApplicationGetTypeID(), out
);
3102 require_noerr(SecTrustedApplicationCopyRequirement((SecTrustedApplicationRef
)appRef
, &requirement
), out
);
3103 require(requirement
, out
);
3104 require_noerr(SecRequirementsCopyString(requirement
, kSecCSDefaultFlags
, &stringRequirement
), out
);
3105 require(stringRequirement
, out
);
3107 require(sizeof(auditToken
) == CFDataGetLength(clientAuditToken
), out
);
3108 CFDataGetBytes(clientAuditToken
, CFRangeMake(0, sizeof(auditToken
)), (uint8_t *)&auditToken
);
3109 require(task
= SecTaskCreateWithAuditToken(NULL
, auditToken
), out
);
3111 if(errSecSuccess
== SecTaskValidateForRequirement(task
, stringRequirement
)) {
3116 CFReleaseNull(task
);
3117 CFReleaseNull(requirement
);
3118 CFReleaseNull(stringRequirement
);
3123 static bool SecPVCContainsTrustSettingsPolicyOption(SecPVCRef pvc
, CFDictionaryRef options
) {
3124 if (!isDictionary(options
)) {
3129 CFDictionaryRef currentCallbacks
= pvc
->callbacks
;
3131 /* We need to run the leaf and path checks using these options. */
3132 pvc
->callbacks
= gSecPolicyLeafCallbacks
;
3133 CFDictionaryApplyFunction(options
, SecPVCValidateKey
, pvc
);
3135 pvc
->callbacks
= gSecPolicyPathCallbacks
;
3136 CFDictionaryApplyFunction(options
, SecPVCValidateKey
, pvc
);
3139 pvc
->callbacks
= currentCallbacks
;
3141 /* Our work here is done; no need to claim a match */
3145 static bool SecPVCMeetsConstraint(SecPVCRef pvc
, SecCertificateRef certificate
, CFDictionaryRef constraint
) {
3146 CFStringRef policyOid
= NULL
, policyString
= NULL
, policyName
= NULL
;
3147 CFNumberRef keyUsageNumber
= NULL
;
3148 CFTypeRef trustedApplicationData
= NULL
;
3149 CFDictionaryRef policyOptions
= NULL
;
3151 bool policyMatch
= false, policyStringMatch
= false, applicationMatch
= false ,
3152 keyUsageMatch
= false, policyOptionMatch
= false;
3153 bool result
= false;
3155 #if TARGET_OS_MAC && !TARGET_OS_IPHONE
3156 /* OS X returns a SecPolicyRef in the constraints. Convert to the oid string. */
3157 SecPolicyRef policy
= NULL
;
3158 policy
= (SecPolicyRef
)CFDictionaryGetValue(constraint
, kSecTrustSettingsPolicy
);
3159 policyOid
= (policy
) ? policy
->_oid
: NULL
;
3161 policyOid
= (CFStringRef
)CFDictionaryGetValue(constraint
, kSecTrustSettingsPolicy
);
3163 policyName
= (CFStringRef
)CFDictionaryGetValue(constraint
, kSecTrustSettingsPolicyName
);
3164 policyString
= (CFStringRef
)CFDictionaryGetValue(constraint
, kSecTrustSettingsPolicyString
);
3165 keyUsageNumber
= (CFNumberRef
)CFDictionaryGetValue(constraint
, kSecTrustSettingsKeyUsage
);
3166 policyOptions
= (CFDictionaryRef
)CFDictionaryGetValue(constraint
, kSecTrustSettingsPolicyOptions
);
3168 CFIndex policyIX
= -1;
3169 policyMatch
= SecPVCContainsPolicy(pvc
, policyOid
, policyName
, &policyIX
);
3170 policyStringMatch
= SecPVCContainsString(pvc
, policyIX
, policyString
);
3171 keyUsageMatch
= SecPVCContainsTrustSettingsKeyUsage(pvc
, certificate
, policyIX
, keyUsageNumber
);
3172 policyOptionMatch
= SecPVCContainsTrustSettingsPolicyOption(pvc
, policyOptions
);
3174 #if TARGET_OS_MAC && !TARGET_OS_IPHONE
3175 trustedApplicationData
= CFDictionaryGetValue(constraint
, kSecTrustSettingsApplication
);
3176 CFDataRef clientAuditToken
= SecPathBuilderCopyClientAuditToken(pvc
->builder
);
3177 applicationMatch
= SecPVCCallerIsApplication(clientAuditToken
, trustedApplicationData
);
3178 CFReleaseNull(clientAuditToken
);
3180 if(CFDictionaryContainsKey(constraint
, kSecTrustSettingsApplication
)) {
3181 secerror("kSecTrustSettingsApplication is not yet supported on this platform");
3185 /* If we either didn't find the parameter in the dictionary or we got a match
3186 * against that parameter, for all possible parameters in the dictionary, then
3187 * this trust setting result applies to the output. */
3188 if (((!policyOid
&& !policyName
) || policyMatch
) &&
3189 (!policyString
|| policyStringMatch
) &&
3190 (!trustedApplicationData
|| applicationMatch
) &&
3191 (!keyUsageNumber
|| keyUsageMatch
) &&
3192 (!policyOptions
|| policyOptionMatch
)) {
3199 SecTrustSettingsResult
SecPVCGetTrustSettingsResult(SecPVCRef pvc
, SecCertificateRef certificate
, CFArrayRef constraints
) {
3200 SecTrustSettingsResult result
= kSecTrustSettingsResultInvalid
;
3201 CFIndex constraintIX
, constraintCount
= CFArrayGetCount(constraints
);
3202 for (constraintIX
= 0; constraintIX
< constraintCount
; constraintIX
++) {
3203 CFDictionaryRef constraint
= (CFDictionaryRef
)CFArrayGetValueAtIndex(constraints
, constraintIX
);
3204 if (!isDictionary(constraint
)) {
3208 CFNumberRef resultNumber
= NULL
;
3209 resultNumber
= (CFNumberRef
)CFDictionaryGetValue(constraint
, kSecTrustSettingsResult
);
3210 uint32_t resultValue
= kSecTrustSettingsResultInvalid
;
3211 if (!isNumber(resultNumber
) || !CFNumberGetValue(resultNumber
, kCFNumberSInt32Type
, &resultValue
)) {
3212 /* no SecTrustSettingsResult entry defaults to TrustRoot*/
3213 resultValue
= kSecTrustSettingsResultTrustRoot
;
3216 if (SecPVCMeetsConstraint(pvc
, certificate
, constraint
)) {
3217 result
= resultValue
;
3224 static void SecPVCCheckUsageConstraints(SecPVCRef pvc
) {
3225 CFIndex certIX
, certCount
= SecPVCGetCertificateCount(pvc
);
3226 for (certIX
= 0; certIX
< certCount
; certIX
++) {
3227 SecCertificatePathVCRef path
= SecPathBuilderGetPath(pvc
->builder
);
3228 CFArrayRef constraints
= SecCertificatePathVCGetUsageConstraintsAtIndex(path
, certIX
);
3229 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, certIX
);
3230 SecTrustSettingsResult result
= SecPVCGetTrustSettingsResult(pvc
, cert
, constraints
);
3232 /* Set the pvc trust result based on the usage constraints and anchor source. */
3233 if (result
== kSecTrustSettingsResultDeny
) {
3234 SecPVCSetResultForced(pvc
, kSecPolicyCheckUsageConstraints
, certIX
, kCFBooleanFalse
, true);
3235 } else if ((result
== kSecTrustSettingsResultTrustRoot
|| result
== kSecTrustSettingsResultTrustAsRoot
||
3236 result
== kSecTrustSettingsResultInvalid
) && SecPVCIsOkResult(pvc
)) {
3237 /* If we already think the PVC is ok and this cert is from one of the user/
3238 * admin anchor sources, trustRoot, trustAsRoot, and Invalid (no constraints),
3239 * all mean we should use the special "Proceed" trust result. */
3240 #if TARGET_OS_IPHONE
3241 if (SecPathBuilderIsAnchorSource(pvc
->builder
, kSecUserAnchorSource
) &&
3242 SecCertificateSourceContains(kSecUserAnchorSource
, cert
)) {
3244 if (SecPathBuilderIsAnchorSource(pvc
->builder
, kSecLegacyAnchorSource
) &&
3245 SecCertificateSourceContains(kSecLegacyAnchorSource
, cert
)) {
3247 pvc
->result
= kSecTrustResultProceed
;
3253 static const UInt8 kTestDateConstraintsRoot
[kSecPolicySHA256Size
] = {
3254 0x51,0xA0,0xF3,0x1F,0xC0,0x1D,0xEC,0x87,0x32,0xB6,0xFD,0x13,0x6A,0x43,0x4D,0x6C,
3255 0x87,0xCD,0x62,0xE0,0x38,0xB4,0xFB,0xD6,0x40,0xB0,0xFD,0x62,0x4D,0x1F,0xCF,0x6D
3257 static const UInt8 kWS_CA1_G2
[kSecPolicySHA256Size
] = {
3258 0xD4,0x87,0xA5,0x6F,0x83,0xB0,0x74,0x82,0xE8,0x5E,0x96,0x33,0x94,0xC1,0xEC,0xC2,
3259 0xC9,0xE5,0x1D,0x09,0x03,0xEE,0x94,0x6B,0x02,0xC3,0x01,0x58,0x1E,0xD9,0x9E,0x16
3261 static const UInt8 kWS_CA1_NEW
[kSecPolicySHA256Size
] = {
3262 0x4B,0x22,0xD5,0xA6,0xAE,0xC9,0x9F,0x3C,0xDB,0x79,0xAA,0x5E,0xC0,0x68,0x38,0x47,
3263 0x9C,0xD5,0xEC,0xBA,0x71,0x64,0xF7,0xF2,0x2D,0xC1,0xD6,0x5F,0x63,0xD8,0x57,0x08
3265 static const UInt8 kWS_CA2_NEW
[kSecPolicySHA256Size
] = {
3266 0xD6,0xF0,0x34,0xBD,0x94,0xAA,0x23,0x3F,0x02,0x97,0xEC,0xA4,0x24,0x5B,0x28,0x39,
3267 0x73,0xE4,0x47,0xAA,0x59,0x0F,0x31,0x0C,0x77,0xF4,0x8F,0xDF,0x83,0x11,0x22,0x54
3269 static const UInt8 kWS_ECC
[kSecPolicySHA256Size
] = {
3270 0x8B,0x45,0xDA,0x1C,0x06,0xF7,0x91,0xEB,0x0C,0xAB,0xF2,0x6B,0xE5,0x88,0xF5,0xFB,
3271 0x23,0x16,0x5C,0x2E,0x61,0x4B,0xF8,0x85,0x56,0x2D,0x0D,0xCE,0x50,0xB2,0x9B,0x02
3273 static const UInt8 kSC_SFSCA
[kSecPolicySHA256Size
] = {
3274 0xC7,0x66,0xA9,0xBE,0xF2,0xD4,0x07,0x1C,0x86,0x3A,0x31,0xAA,0x49,0x20,0xE8,0x13,
3275 0xB2,0xD1,0x98,0x60,0x8C,0xB7,0xB7,0xCF,0xE2,0x11,0x43,0xB8,0x36,0xDF,0x09,0xEA
3277 static const UInt8 kSC_SHA2
[kSecPolicySHA256Size
] = {
3278 0xE1,0x78,0x90,0xEE,0x09,0xA3,0xFB,0xF4,0xF4,0x8B,0x9C,0x41,0x4A,0x17,0xD6,0x37,
3279 0xB7,0xA5,0x06,0x47,0xE9,0xBC,0x75,0x23,0x22,0x72,0x7F,0xCC,0x17,0x42,0xA9,0x11
3281 static const UInt8 kSC_G2
[kSecPolicySHA256Size
] = {
3282 0xC7,0xBA,0x65,0x67,0xDE,0x93,0xA7,0x98,0xAE,0x1F,0xAA,0x79,0x1E,0x71,0x2D,0x37,
3283 0x8F,0xAE,0x1F,0x93,0xC4,0x39,0x7F,0xEA,0x44,0x1B,0xB7,0xCB,0xE6,0xFD,0x59,0x95
3286 static void SecPVCCheckIssuerDateConstraints(SecPVCRef pvc
) {
3287 static CFSetRef sConstrainedRoots
= NULL
;
3288 static dispatch_once_t _t
;
3289 dispatch_once(&_t
, ^{
3290 const UInt8
*v_hashes
[] = {
3291 kWS_CA1_G2
, kWS_CA1_NEW
, kWS_CA2_NEW
, kWS_ECC
,
3292 kSC_SFSCA
, kSC_SHA2
, kSC_G2
, kTestDateConstraintsRoot
3294 CFMutableSetRef set
= CFSetCreateMutable(NULL
, 0, &kCFTypeSetCallBacks
);
3295 CFIndex ix
, count
= sizeof(v_hashes
)/sizeof(*v_hashes
);
3296 for (ix
=0; ix
<count
; ix
++) {
3297 CFDataRef hash
= CFDataCreateWithBytesNoCopy(NULL
, v_hashes
[ix
],
3298 kSecPolicySHA256Size
, kCFAllocatorNull
);
3300 CFSetAddValue(set
, hash
);
3304 sConstrainedRoots
= set
;
3307 bool shouldDeny
= false;
3308 CFIndex certIX
, certCount
= SecPVCGetCertificateCount(pvc
);
3309 for (certIX
= certCount
- 1; certIX
>= 0 && !shouldDeny
; certIX
--) {
3310 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, certIX
);
3311 CFDataRef sha256
= SecCertificateCopySHA256Digest(cert
);
3312 if (sha256
&& CFSetContainsValue(sConstrainedRoots
, sha256
)) {
3313 /* matched a constrained root; check notBefore dates on all its children. */
3314 CFIndex childIX
= certIX
;
3315 while (--childIX
>= 0) {
3316 SecCertificateRef child
= SecPVCGetCertificateAtIndex(pvc
, childIX
);
3317 /* 1 Dec 2016 00:00:00 GMT */
3318 if (child
&& (CFAbsoluteTime
)502243200.0 <= SecCertificateNotValidBefore(child
)) {
3319 SecPVCSetResultForced(pvc
, kSecPolicyCheckBlackListedKey
, certIX
, kCFBooleanFalse
, true);
3325 CFReleaseNull(sha256
);
3329 static bool SecPVCIsSSLServerAuthenticationPolicy(SecPVCRef pvc
) {
3330 if (!pvc
|| !pvc
->policies
) {
3333 SecPolicyRef policy
= (SecPolicyRef
)CFArrayGetValueAtIndex(pvc
->policies
, 0);
3337 CFStringRef policyName
= SecPolicyGetName(policy
);
3338 if (CFEqualSafe(policyName
, kSecPolicyNameSSLServer
)) {
3341 CFDictionaryRef options
= policy
->_options
;
3342 if (options
&& CFDictionaryGetValue(options
, kSecPolicyCheckSSLHostname
)) {
3349 1. SecPVCCheckRequireCTConstraints must be called after SecPolicyCheckCT,
3350 so earliest issuance time has already been obtained from SCTs.
3351 2. If the issuance time value is 0 (i.e. 2001-01-01) or earlier, we
3352 assume it was not set, and thus we did not have CT info.
3354 static void SecPVCCheckRequireCTConstraints(SecPVCRef pvc
) {
3355 SecCertificatePathVCRef path
= (pvc
) ? SecPathBuilderGetPath(pvc
->builder
) : NULL
;
3359 /* If we are evaluating for a SSL server authentication policy, make sure
3360 SCT issuance time is prior to the earliest not-after date constraint.
3361 Note that CT will already be required if there is a not-after date
3362 constraint present (set in SecRVCProcessValidDateConstraints).
3364 if (SecPVCIsSSLServerAuthenticationPolicy(pvc
)) {
3365 CFIndex ix
, certCount
= SecCertificatePathVCGetCount(path
);
3366 SecCertificateRef certificate
= SecPathBuilderGetCertificateAtIndex(pvc
->builder
, 0);
3367 CFAbsoluteTime earliestNotAfter
= 31556908800.0; /* default: 3001-01-01 00:00:00-0000 */
3368 CFAbsoluteTime issuanceTime
= SecCertificatePathVCIssuanceTime(path
);
3369 if (issuanceTime
<= 0) {
3370 /* if not set (or prior to 2001-01-01), use leaf's not-before time. */
3371 issuanceTime
= SecCertificateNotValidBefore(certificate
);
3373 for (ix
= 0; ix
< certCount
; ix
++) {
3374 SecRVCRef rvc
= SecCertificatePathVCGetRVCAtIndex(path
, ix
);
3375 if (!rvc
|| !rvc
->valid_info
|| !rvc
->valid_info
->hasDateConstraints
|| !rvc
->valid_info
->notAfterDate
) {
3378 /* Found CA certificate with a not-after date constraint. */
3379 CFAbsoluteTime caNotAfter
= CFDateGetAbsoluteTime(rvc
->valid_info
->notAfterDate
);
3380 if (caNotAfter
< earliestNotAfter
) {
3381 earliestNotAfter
= caNotAfter
;
3383 if (issuanceTime
> earliestNotAfter
) {
3384 /* Issuance time violates the not-after date constraint. */
3385 secnotice("rvc", "certificate issuance time (%f) is later than allowed value (%f)",
3386 issuanceTime
, earliestNotAfter
);
3387 SecRVCSetValidDeterminedErrorResult(rvc
);
3392 /* If path is CT validated, nothing further to do here. */
3393 if (SecCertificatePathVCIsCT(path
)) {
3397 /* Path is not CT validated, so check if CT was required. */
3398 SecPathCTPolicy ctp
= SecCertificatePathVCRequiresCT(path
);
3399 if (ctp
<= kSecPathCTNotRequired
|| !SecPVCIsSSLServerAuthenticationPolicy(pvc
)) {
3402 /* CT was required. Error is always set on leaf certificate. */
3403 SecPVCSetResultForced(pvc
, kSecPolicyCheckCTRequired
,
3404 0, kCFBooleanFalse
, true);
3405 if (ctp
!= kSecPathCTRequiredOverridable
) {
3406 /* Normally kSecPolicyCheckCTRequired is recoverable,
3407 so need to manually change trust result here. */
3408 pvc
->result
= kSecTrustResultFatalTrustFailure
;
3412 /* AUDIT[securityd](done):
3413 policy->_options is a caller provided dictionary, only its cf type has
3416 void SecPVCPathChecks(SecPVCRef pvc
) {
3417 secdebug("policy", "begin path: %@", SecPathBuilderGetPath(pvc
->builder
));
3418 SecCertificatePathVCRef path
= SecPathBuilderGetPath(pvc
->builder
);
3419 /* This needs to be initialized before we call any function that might call
3420 SecPVCSetResultForced(). */
3422 SecPolicyCheckIdLinkage(pvc
, kSecPolicyCheckIdLinkage
);
3423 if (SecPVCIsOkResult(pvc
) || pvc
->details
) {
3424 SecPolicyCheckBasicCertificateProcessing(pvc
,
3425 kSecPolicyCheckBasicCertificateProcessing
);
3428 CFArrayRef policies
= pvc
->policies
;
3429 CFIndex count
= CFArrayGetCount(policies
);
3430 for (; pvc
->policyIX
< count
; ++pvc
->policyIX
) {
3431 /* Validate all keys for all policies. */
3432 pvc
->callbacks
= gSecPolicyPathCallbacks
;
3433 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
3434 CFDictionaryApplyFunction(policy
->_options
, SecPVCValidateKey
, pvc
);
3435 if (!SecPVCIsOkResult(pvc
) && !pvc
->details
)
3442 /* Check whether the TrustSettings say to deny a cert in the path. */
3443 SecPVCCheckUsageConstraints(pvc
);
3445 /* Check for Blocklisted certs */
3446 SecPVCCheckIssuerDateConstraints(pvc
);
3448 count
= SecCertificatePathVCGetCount(path
);
3449 for (ix
= 1; ix
< count
; ix
++) {
3450 SecPVCGrayListedKeyChecks(pvc
, ix
);
3451 SecPVCBlackListedKeyChecks(pvc
, ix
);
3454 /* Path-based check tests. */
3455 if (!SecCertificatePathVCIsPathValidated(path
)) {
3456 bool ev_check_ok
= false;
3457 if (SecCertificatePathVCIsOptionallyEV(path
)) {
3458 SecTrustResultType pre_ev_check_result
= pvc
->result
;
3459 SecPolicyCheckEV(pvc
, kSecPolicyCheckExtendedValidation
);
3460 ev_check_ok
= SecPVCIsOkResult(pvc
);
3461 /* If ev checking failed, we still want to accept this chain
3462 as a non EV one, if it was valid as such. */
3463 pvc
->result
= pre_ev_check_result
;
3467 /* This call will set the value of pvc->is_ct, but won't change the result (pvc->result) */
3468 SecPolicyCheckCT(pvc
);
3470 /* Certs are only EV if they are also CT verified */
3471 if (ev_check_ok
&& SecCertificatePathVCIsCT(path
)) {
3472 SecCertificatePathVCSetIsEV(path
, true);
3476 /* Say that we did the expensive path checks (that we want to skip on the second call) */
3477 SecCertificatePathVCSetPathValidated(SecPathBuilderGetPath(pvc
->builder
));
3479 /* Check that this path meets CT constraints. */
3480 SecPVCCheckRequireCTConstraints(pvc
);
3481 SecPolicyCheckSystemTrustedCTRequired(pvc
);
3483 /* Check that this path meets known-intermediate constraints. */
3484 SecPathBuilderCheckKnownIntermediateConstraints(pvc
->builder
);
3486 secdebug("policy", "end %strusted path: %@",
3487 (SecPVCIsOkResult(pvc
) ? "" : "not "), SecPathBuilderGetPath(pvc
->builder
));
3492 void SecPVCPathCheckRevocationResponsesReceived(SecPVCRef pvc
) {
3494 /* Since we don't currently allow networking on watchOS,
3495 * don't enforce the revocation-required check here. (32728029) */
3496 bool required
= false;
3498 bool required
= true;
3500 SecCertificatePathVCRef path
= SecPathBuilderGetPath(pvc
->builder
);
3501 CFIndex ix
, certCount
= SecCertificatePathVCGetCount(path
);
3502 for (ix
= 0; ix
< certCount
; ix
++) {
3503 SecRVCRef rvc
= SecCertificatePathVCGetRVCAtIndex(path
, ix
);
3504 /* Do we have a valid revocation response? */
3505 if (SecRVCGetEarliestNextUpdate(rvc
) == NULL_TIME
) {
3506 /* No valid revocation response.
3507 * Do we require revocation (for that cert per the
3508 * SecCertificateVCRef, or per the pvc)? */
3509 if (required
&& (SecCertificatePathVCIsRevocationRequiredForCertificateAtIndex(path
, ix
) ||
3510 ((ix
== 0) && pvc
->require_revocation_response
))) {
3511 SecPVCSetResultForced(pvc
, kSecPolicyCheckRevocationResponseRequired
,
3512 ix
, kCFBooleanFalse
, true);
3514 /* Do we have a definitive Valid revocation result for this cert? */
3515 if (SecRVCHasDefinitiveValidInfo(rvc
) && SecRVCHasRevokedValidInfo(rvc
)) {
3516 SecRVCSetValidDeterminedErrorResult(rvc
);