2 * Copyright (c) 2008-2017 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
25 * SecPolicyServer.c - Engine for evaluating certificate paths against trust policies.
28 #include <securityd/SecPolicyServer.h>
29 #include <Security/SecPolicyInternal.h>
30 #include <Security/SecPolicyPriv.h>
31 #include <Security/SecTask.h>
32 #include <securityd/asynchttp.h>
33 #include <securityd/policytree.h>
34 #include <securityd/nameconstraints.h>
35 #include <CoreFoundation/CFTimeZone.h>
37 #include <libDER/oids.h>
38 #include <CoreFoundation/CFNumber.h>
39 #include <Security/SecCertificateInternal.h>
40 #include <AssertMacros.h>
41 #include <utilities/debugging.h>
42 #include <utilities/SecInternalReleasePriv.h>
43 #include <security_asn1/SecAsn1Coder.h>
44 #include <security_asn1/ocspTemplates.h>
45 #include <security_asn1/oidsalg.h>
46 #include <security_asn1/oidsocsp.h>
47 #include <CommonCrypto/CommonDigest.h>
48 #include <Security/SecFramework.h>
49 #include <Security/SecPolicyInternal.h>
50 #include <Security/SecTrustPriv.h>
51 #include <Security/SecTrustInternal.h>
52 #include <Security/SecTrustSettingsPriv.h>
53 #include <Security/SecInternal.h>
54 #include <Security/SecKeyPriv.h>
55 #include <Security/SecTask.h>
56 #include <CFNetwork/CFHTTPMessage.h>
57 #include <CFNetwork/CFHTTPStream.h>
58 #include <SystemConfiguration/SCDynamicStoreCopySpecific.h>
60 #include <securityd/SecTrustServer.h>
61 #include <securityd/SecTrustLoggingServer.h>
62 #include <securityd/SecRevocationServer.h>
63 #include <securityd/SecCertificateServer.h>
64 #include <securityd/SecCertificateSource.h>
65 #include <securityd/SecOCSPResponse.h>
66 #include <utilities/array_size.h>
67 #include <utilities/SecCFWrappers.h>
68 #include <utilities/SecAppleAnchorPriv.h>
69 #include "OTATrustUtilities.h"
70 #include "personalization.h"
71 #include <sys/codesign.h>
74 #include <Security/SecTaskPriv.h>
77 /* Set this to 1 to dump the ocsp responses received in DER form in /tmp. */
78 #ifndef DUMP_OCSPRESPONSES
79 #define DUMP_OCSPRESPONSES 0
82 #if DUMP_OCSPRESPONSES
87 static void secdumpdata(CFDataRef data
, const char *name
) {
88 int fd
= open(name
, O_CREAT
| O_WRONLY
| O_TRUNC
, 0666);
89 write(fd
, CFDataGetBytePtr(data
), CFDataGetLength(data
));
96 /********************************************************
97 ****************** SecPolicy object ********************
98 ********************************************************/
100 static SecCertificateRef
SecPVCGetCertificateAtIndex(SecPVCRef pvc
, CFIndex ix
);
101 static CFIndex
SecPVCGetCertificateCount(SecPVCRef pvc
);
102 static CFAbsoluteTime
SecPVCGetVerifyTime(SecPVCRef pvc
);
104 static CFMutableDictionaryRef gSecPolicyLeafCallbacks
= NULL
;
105 static CFMutableDictionaryRef gSecPolicyPathCallbacks
= NULL
;
107 static CFArrayRef
SecPolicyAnchorDigestsForEVPolicy(const DERItem
*policyOID
)
109 CFArrayRef result
= NULL
;
110 SecOTAPKIRef otapkiRef
= SecOTAPKICopyCurrentOTAPKIRef();
111 if (NULL
== otapkiRef
)
116 CFDictionaryRef evToPolicyAnchorDigest
= SecOTAPKICopyEVPolicyToAnchorMapping(otapkiRef
);
117 CFRelease(otapkiRef
);
119 if (NULL
== evToPolicyAnchorDigest
)
124 CFArrayRef roots
= NULL
;
125 CFStringRef oid
= SecDERItemCopyOIDDecimalRepresentation(kCFAllocatorDefault
, policyOID
);
126 if (oid
&& evToPolicyAnchorDigest
)
128 result
= (CFArrayRef
)CFDictionaryGetValue(evToPolicyAnchorDigest
, oid
);
129 if (roots
&& CFGetTypeID(result
) != CFArrayGetTypeID())
131 secerror("EVRoot.plist has non array value");
136 CFReleaseSafe(evToPolicyAnchorDigest
);
141 bool SecPolicyIsEVPolicy(const DERItem
*policyOID
) {
142 return SecPolicyAnchorDigestsForEVPolicy(policyOID
);
145 static bool SecPolicyRootCACertificateIsEV(SecCertificateRef certificate
,
146 policy_set_t valid_policies
) {
147 CFDictionaryRef keySizes
= NULL
;
148 CFNumberRef rsaSize
= NULL
, ecSize
= NULL
;
150 /* Ensure that this certificate is a valid anchor for one of the
151 certificate policy oids specified in the leaf. */
152 CFDataRef digest
= SecCertificateGetSHA1Digest(certificate
);
154 bool good_ev_anchor
= false;
155 for (ix
= valid_policies
; ix
; ix
= ix
->oid_next
) {
156 CFArrayRef digests
= SecPolicyAnchorDigestsForEVPolicy(&ix
->oid
);
157 if (digests
&& CFArrayContainsValue(digests
,
158 CFRangeMake(0, CFArrayGetCount(digests
)), digest
)) {
159 secdebug("ev", "found anchor for policy oid");
160 good_ev_anchor
= true;
164 require_action_quiet(good_ev_anchor
, notEV
, secnotice("ev", "anchor not in plist"));
166 CFAbsoluteTime october2006
= 178761600;
167 if (SecCertificateNotValidBefore(certificate
) >= october2006
) {
168 require_action_quiet(SecCertificateVersion(certificate
) >= 3, notEV
,
169 secnotice("ev", "Anchor issued after October 2006 and is not v3"));
171 if (SecCertificateVersion(certificate
) >= 3
172 && SecCertificateNotValidBefore(certificate
) >= october2006
) {
173 const SecCEBasicConstraints
*bc
= SecCertificateGetBasicConstraints(certificate
);
174 require_action_quiet(bc
&& bc
->isCA
== true, notEV
,
175 secnotice("ev", "Anchor has invalid basic constraints"));
176 SecKeyUsage ku
= SecCertificateGetKeyUsage(certificate
);
177 require_action_quiet((ku
& (kSecKeyUsageKeyCertSign
| kSecKeyUsageCRLSign
))
178 == (kSecKeyUsageKeyCertSign
| kSecKeyUsageCRLSign
), notEV
,
179 secnotice("ev", "Anchor has invalid key usage %u", ku
));
182 /* At least RSA 2048 or ECC NIST P-256. */
183 require_quiet(rsaSize
= CFNumberCreateWithCFIndex(NULL
, 2048), notEV
);
184 require_quiet(ecSize
= CFNumberCreateWithCFIndex(NULL
, 256), notEV
);
185 const void *keys
[] = { kSecAttrKeyTypeRSA
, kSecAttrKeyTypeEC
};
186 const void *values
[] = { rsaSize
, ecSize
};
187 require_quiet(keySizes
= CFDictionaryCreate(NULL
, keys
, values
, 2,
188 &kCFTypeDictionaryKeyCallBacks
,
189 &kCFTypeDictionaryValueCallBacks
), notEV
);
190 require_action_quiet(SecCertificateIsAtLeastMinKeySize(certificate
, keySizes
), notEV
,
191 secnotice("ev", "Anchor's public key is too weak for EV"));
196 CFReleaseNull(rsaSize
);
197 CFReleaseNull(ecSize
);
198 CFReleaseNull(keySizes
);
202 static bool SecPolicySubordinateCACertificateCouldBeEV(SecCertificateRef certificate
) {
203 CFMutableDictionaryRef keySizes
= NULL
;
204 CFNumberRef rsaSize
= NULL
, ecSize
= NULL
;
207 const SecCECertificatePolicies
*cp
;
208 cp
= SecCertificateGetCertificatePolicies(certificate
);
209 require_action_quiet(cp
&& cp
->numPolicies
> 0, notEV
,
210 secnotice("ev", "SubCA missing certificate policies"));
211 CFArrayRef cdp
= SecCertificateGetCRLDistributionPoints(certificate
);
212 require_action_quiet(cdp
&& CFArrayGetCount(cdp
) > 0, notEV
,
213 secnotice("ev", "SubCA missing CRLDP"));
214 const SecCEBasicConstraints
*bc
= SecCertificateGetBasicConstraints(certificate
);
215 require_action_quiet(bc
&& bc
->isCA
== true, notEV
,
216 secnotice("ev", "SubCA has invalid basic constraints"));
217 SecKeyUsage ku
= SecCertificateGetKeyUsage(certificate
);
218 require_action_quiet((ku
& (kSecKeyUsageKeyCertSign
| kSecKeyUsageCRLSign
))
219 == (kSecKeyUsageKeyCertSign
| kSecKeyUsageCRLSign
), notEV
,
220 secnotice("ev", "SubCA has invalid key usage %u", ku
));
222 /* 6.1.5 Key Sizes */
223 CFAbsoluteTime jan2011
= 315532800;
224 CFAbsoluteTime jan2014
= 410227200;
225 require_quiet(ecSize
= CFNumberCreateWithCFIndex(NULL
, 256), notEV
);
226 require_quiet(keySizes
= CFDictionaryCreateMutable(NULL
, 2, &kCFTypeDictionaryKeyCallBacks
,
227 &kCFTypeDictionaryValueCallBacks
), notEV
);
228 CFDictionaryAddValue(keySizes
, kSecAttrKeyTypeEC
, ecSize
);
229 if (SecCertificateNotValidBefore(certificate
) < jan2011
||
230 SecCertificateNotValidAfter(certificate
) < jan2014
) {
231 /* At least RSA 1024 or ECC NIST P-256. */
232 require_quiet(rsaSize
= CFNumberCreateWithCFIndex(NULL
, 1024), notEV
);
233 CFDictionaryAddValue(keySizes
, kSecAttrKeyTypeRSA
, rsaSize
);
234 require_action_quiet(SecCertificateIsAtLeastMinKeySize(certificate
, keySizes
), notEV
,
235 secnotice("ev", "SubCA's public key is too small for issuance before 2011 or expiration before 2014"));
237 /* At least RSA 2028 or ECC NIST P-256. */
238 require_quiet(rsaSize
= CFNumberCreateWithCFIndex(NULL
, 2048), notEV
);
239 CFDictionaryAddValue(keySizes
, kSecAttrKeyTypeRSA
, rsaSize
);
240 require_action_quiet(SecCertificateIsAtLeastMinKeySize(certificate
, keySizes
), notEV
,
241 secnotice("ev", "SubCA's public key is too small for issuance after 2010 or expiration after 2013"));
244 /* 7.1.3 Algorithm Object Identifiers */
245 CFAbsoluteTime jan2016
= 473299200;
246 if (SecCertificateNotValidBefore(certificate
) > jan2016
) {
248 require_action_quiet(SecCertificateGetSignatureHashAlgorithm(certificate
) > kSecSignatureHashAlgorithmSHA1
,
249 notEV
, secnotice("ev", "SubCA was issued with SHA-1 after 2015"));
255 CFReleaseNull(rsaSize
);
256 CFReleaseNull(ecSize
);
257 CFReleaseNull(keySizes
);
261 /********************************************************
262 **************** SecPolicy Callbacks *******************
263 ********************************************************/
264 static void SecPolicyCheckCriticalExtensions(SecPVCRef pvc
,
268 static void SecPolicyCheckIdLinkage(SecPVCRef pvc
,
270 CFIndex ix
, count
= SecPVCGetCertificateCount(pvc
);
271 CFDataRef parentSubjectKeyID
= NULL
;
272 for (ix
= count
- 1; ix
>= 0; --ix
) {
273 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, ix
);
274 /* If the previous certificate in the chain had a SubjectKeyID,
275 make sure it matches the current certificates AuthorityKeyID. */
276 if (parentSubjectKeyID
) {
277 /* @@@ According to RFC 2459 neither AuthorityKeyID nor
278 SubjectKeyID can be critical. Currenty we don't check
280 CFDataRef authorityKeyID
= SecCertificateGetAuthorityKeyID(cert
);
281 if (authorityKeyID
) {
282 if (!CFEqual(parentSubjectKeyID
, authorityKeyID
)) {
283 /* AuthorityKeyID doesn't match issuers SubjectKeyID. */
284 if (!SecPVCSetResult(pvc
, key
, ix
, kCFBooleanFalse
))
290 parentSubjectKeyID
= SecCertificateGetSubjectKeyID(cert
);
294 static void SecPolicyCheckKeyUsage(SecPVCRef pvc
,
296 SecCertificateRef leaf
= SecPVCGetCertificateAtIndex(pvc
, 0);
297 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
298 CFTypeRef xku
= CFDictionaryGetValue(policy
->_options
, key
);
299 if (!SecPolicyCheckCertKeyUsage(leaf
, xku
)) {
300 SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
);
304 /* AUDIT[securityd](done):
305 policy->_options is a caller provided dictionary, only its cf type has
308 static void SecPolicyCheckExtendedKeyUsage(SecPVCRef pvc
, CFStringRef key
) {
309 SecCertificateRef leaf
= SecPVCGetCertificateAtIndex(pvc
, 0);
310 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
311 CFTypeRef xeku
= CFDictionaryGetValue(policy
->_options
, key
);
312 if (!SecPolicyCheckCertExtendedKeyUsage(leaf
, xeku
)){
313 SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
);
317 static void SecPolicyCheckBasicConstraints(SecPVCRef pvc
,
319 //SecPolicyCheckBasicContraintsCommon(pvc, key, false);
322 static void SecPolicyCheckNonEmptySubject(SecPVCRef pvc
,
324 CFIndex ix
, count
= SecPVCGetCertificateCount(pvc
);
325 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
326 CFTypeRef pvcValue
= CFDictionaryGetValue(policy
->_options
, key
);
327 for (ix
= 0; ix
< count
; ++ix
) {
328 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, ix
);
329 if (!SecPolicyCheckCertNonEmptySubject(cert
, pvcValue
)) {
330 if (!SecPVCSetResult(pvc
, key
, ix
, kCFBooleanFalse
))
336 /* AUDIT[securityd](done):
337 policy->_options is a caller provided dictionary, only its cf type has
340 static void SecPolicyCheckSSLHostname(SecPVCRef pvc
,
342 /* @@@ Consider what to do if the caller passes in no hostname. Should
343 we then still fail if the leaf has no dnsNames or IPAddresses at all? */
344 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
345 CFStringRef hostName
= (CFStringRef
)
346 CFDictionaryGetValue(policy
->_options
, key
);
347 if (!isString(hostName
)) {
348 /* @@@ We can't return an error here and making the evaluation fail
349 won't help much either. */
353 SecCertificateRef leaf
= SecPVCGetCertificateAtIndex(pvc
, 0);
354 bool dnsMatch
= SecPolicyCheckCertSSLHostname(leaf
, hostName
);
357 /* Hostname mismatch or no hostnames found in certificate. */
358 SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
);
363 /* AUDIT[securityd](done):
364 policy->_options is a caller provided dictionary, only its cf type has
367 static void SecPolicyCheckEmail(SecPVCRef pvc
, CFStringRef key
) {
368 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
369 CFStringRef email
= (CFStringRef
)CFDictionaryGetValue(policy
->_options
, key
);
370 if (!isString(email
)) {
371 /* We can't return an error here and making the evaluation fail
372 won't help much either. */
376 SecCertificateRef leaf
= SecPVCGetCertificateAtIndex(pvc
, 0);
378 if (!SecPolicyCheckCertEmail(leaf
, email
)) {
379 /* Hostname mismatch or no hostnames found in certificate. */
380 SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
);
384 static void SecPolicyCheckTemporalValidity(SecPVCRef pvc
,
386 CFIndex ix
, count
= SecPVCGetCertificateCount(pvc
);
387 CFAbsoluteTime verifyTime
= SecPVCGetVerifyTime(pvc
);
388 for (ix
= 0; ix
< count
; ++ix
) {
389 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, ix
);
390 if (!SecCertificateIsValid(cert
, verifyTime
)) {
391 /* Intermediate certificate has expired. */
392 if (!SecPVCSetResult(pvc
, key
, ix
, kCFBooleanFalse
))
398 /* AUDIT[securityd](done):
399 policy->_options is a caller provided dictionary, only its cf type has
402 static void SecPolicyCheckIssuerCommonName(SecPVCRef pvc
,
404 CFIndex count
= SecPVCGetCertificateCount(pvc
);
406 /* Can't check intermediates common name if there is no intermediate. */
407 SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
);
411 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, 1);
412 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
413 CFStringRef commonName
=
414 (CFStringRef
)CFDictionaryGetValue(policy
->_options
, key
);
415 if (!isString(commonName
)) {
416 /* @@@ We can't return an error here and making the evaluation fail
417 won't help much either. */
420 if (!SecPolicyCheckCertSubjectCommonName(cert
, commonName
)) {
421 SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
);
425 /* AUDIT[securityd](done):
426 policy->_options is a caller provided dictionary, only its cf type has
429 static void SecPolicyCheckSubjectCommonName(SecPVCRef pvc
,
431 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, 0);
432 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
433 CFStringRef common_name
= (CFStringRef
)CFDictionaryGetValue(policy
->_options
,
435 if (!isString(common_name
)) {
436 /* @@@ We can't return an error here and making the evaluation fail
437 won't help much either. */
440 if (!SecPolicyCheckCertSubjectCommonName(cert
, common_name
)) {
441 SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
);
445 /* AUDIT[securityd](done):
446 policy->_options is a caller provided dictionary, only its cf type has
449 static void SecPolicyCheckSubjectCommonNamePrefix(SecPVCRef pvc
,
451 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, 0);
452 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
453 CFStringRef prefix
= (CFStringRef
)CFDictionaryGetValue(policy
->_options
,
455 if (!isString(prefix
)) {
456 /* @@@ We can't return an error here and making the evaluation fail
457 won't help much either. */
460 if (!SecPolicyCheckCertSubjectCommonNamePrefix(cert
, prefix
)) {
461 SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
);
465 /* AUDIT[securityd](done):
466 policy->_options is a caller provided dictionary, only its cf type has
469 static void SecPolicyCheckSubjectCommonNameTEST(SecPVCRef pvc
,
471 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, 0);
472 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
473 CFStringRef common_name
= (CFStringRef
)CFDictionaryGetValue(policy
->_options
,
475 if (!isString(common_name
)) {
476 /* @@@ We can't return an error here and making the evaluation fail
477 won't help much either. */
480 if (!SecPolicyCheckCertSubjectCommonNameTEST(cert
, common_name
)) {
481 SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
);
485 /* AUDIT[securityd](done):
486 policy->_options is a caller provided dictionary, only its cf type has
489 static void SecPolicyCheckNotValidBefore(SecPVCRef pvc
,
491 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, 0);
492 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
493 CFDateRef date
= (CFDateRef
)CFDictionaryGetValue(policy
->_options
, key
);
495 /* @@@ We can't return an error here and making the evaluation fail
496 won't help much either. */
499 if (!SecPolicyCheckCertNotValidBefore(cert
, date
)) {
500 if (!SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
))
505 /* AUDIT[securityd](done):
506 policy->_options is a caller provided dictionary, only its cf type has
509 static void SecPolicyCheckChainLength(SecPVCRef pvc
,
511 CFIndex count
= SecPVCGetCertificateCount(pvc
);
512 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
513 CFNumberRef chainLength
=
514 (CFNumberRef
)CFDictionaryGetValue(policy
->_options
, key
);
516 if (!chainLength
|| CFGetTypeID(chainLength
) != CFNumberGetTypeID() ||
517 !CFNumberGetValue(chainLength
, kCFNumberCFIndexType
, &value
)) {
518 /* @@@ We can't return an error here and making the evaluation fail
519 won't help much either. */
522 if (value
!= count
) {
523 /* Chain length doesn't match policy requirement. */
524 if (!SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
))
529 static bool isDigestInPolicy(SecPVCRef pvc
, CFStringRef key
, CFDataRef digest
) {
530 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
531 CFTypeRef value
= CFDictionaryGetValue(policy
->_options
, key
);
533 bool foundMatch
= false;
535 foundMatch
= CFEqual(digest
, value
);
536 else if (isArray(value
))
537 foundMatch
= CFArrayContainsValue((CFArrayRef
) value
, CFRangeMake(0, CFArrayGetCount((CFArrayRef
) value
)), digest
);
539 /* @@@ We only support Data and Array but we can't return an error here so.
540 we let the evaluation fail (not much help) and assert in debug. */
547 static void SecPolicyCheckAnchorSHA256(SecPVCRef pvc
, CFStringRef key
) {
548 CFIndex count
= SecPVCGetCertificateCount(pvc
);
549 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, count
- 1);
550 CFDataRef anchorSHA256
= NULL
;
551 anchorSHA256
= SecCertificateCopySHA256Digest(cert
);
553 if (!isDigestInPolicy(pvc
, key
, anchorSHA256
)) {
554 SecPVCSetResult(pvc
, kSecPolicyCheckAnchorSHA256
, count
-1, kCFBooleanFalse
);
557 CFReleaseNull(anchorSHA256
);
562 /* AUDIT[securityd](done):
563 policy->_options is a caller provided dictionary, only its cf type has
566 static void SecPolicyCheckAnchorSHA1(SecPVCRef pvc
,
568 CFIndex count
= SecPVCGetCertificateCount(pvc
);
569 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, count
- 1);
570 CFDataRef anchorSHA1
= SecCertificateGetSHA1Digest(cert
);
572 if (!isDigestInPolicy(pvc
, key
, anchorSHA1
))
573 if (!SecPVCSetResult(pvc
, kSecPolicyCheckAnchorSHA1
, count
-1, kCFBooleanFalse
))
580 Check the SHA256 of SPKI of the first intermediate CA certificate in the path
581 policy->_options is a caller provided dictionary, only its cf type has
584 static void SecPolicyCheckIntermediateSPKISHA256(SecPVCRef pvc
,
586 SecCertificateRef cert
= NULL
;
587 CFDataRef digest
= NULL
;
589 if (SecPVCGetCertificateCount(pvc
) < 2) {
590 SecPVCSetResult(pvc
, kSecPolicyCheckIntermediateSPKISHA256
, 0, kCFBooleanFalse
);
594 cert
= SecPVCGetCertificateAtIndex(pvc
, 1);
595 digest
= SecCertificateCopySubjectPublicKeyInfoSHA256Digest(cert
);
597 if (!isDigestInPolicy(pvc
, key
, digest
)) {
598 SecPVCSetResult(pvc
, kSecPolicyCheckIntermediateSPKISHA256
, 1, kCFBooleanFalse
);
600 CFReleaseNull(digest
);
604 policy->_options is a caller provided dictionary, only its cf type has
607 static void SecPolicyCheckAnchorApple(SecPVCRef pvc
,
609 CFIndex count
= SecPVCGetCertificateCount(pvc
);
610 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, count
- 1);
611 SecAppleTrustAnchorFlags flags
= 0;
614 bool foundMatch
= SecIsAppleTrustAnchor(cert
, flags
);
617 if (!SecPVCSetResult(pvc
, kSecPolicyCheckAnchorApple
, 0, kCFBooleanFalse
))
624 /* AUDIT[securityd](done):
625 policy->_options is a caller provided dictionary, only its cf type has
628 static void SecPolicyCheckSubjectOrganization(SecPVCRef pvc
,
630 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, 0);
631 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
632 CFStringRef org
= (CFStringRef
)CFDictionaryGetValue(policy
->_options
,
634 if (!isString(org
)) {
635 /* @@@ We can't return an error here and making the evaluation fail
636 won't help much either. */
639 if (!SecPolicyCheckCertSubjectOrganization(cert
, org
)) {
640 /* Leaf Subject Organization mismatch. */
641 SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
);
645 static void SecPolicyCheckSubjectOrganizationalUnit(SecPVCRef pvc
,
647 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, 0);
648 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
649 CFStringRef orgUnit
= (CFStringRef
)CFDictionaryGetValue(policy
->_options
,
651 if (!isString(orgUnit
)) {
652 /* @@@ We can't return an error here and making the evaluation fail
653 won't help much either. */
656 if (!SecPolicyCheckCertSubjectOrganizationalUnit(cert
, orgUnit
)) {
657 /* Leaf Subject Organization mismatch. */
658 SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
);
662 /* AUDIT[securityd](done):
663 policy->_options is a caller provided dictionary, only its cf type has
666 static void SecPolicyCheckEAPTrustedServerNames(SecPVCRef pvc
,
668 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
669 CFArrayRef trustedServerNames
= (CFArrayRef
)
670 CFDictionaryGetValue(policy
->_options
, key
);
671 /* No names specified means we accept any name. */
672 if (!trustedServerNames
)
674 if (!isArray(trustedServerNames
)) {
675 /* @@@ We can't return an error here and making the evaluation fail
676 won't help much either. */
680 SecCertificateRef leaf
= SecPVCGetCertificateAtIndex(pvc
, 0);
681 if (!SecPolicyCheckCertEAPTrustedServerNames(leaf
, trustedServerNames
)) {
682 /* Hostname mismatch or no hostnames found in certificate. */
683 SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
);
687 static const unsigned char UTN_USERFirst_Hardware_Serial
[][16] = {
688 { 0xd8, 0xf3, 0x5f, 0x4e, 0xb7, 0x87, 0x2b, 0x2d, 0xab, 0x06, 0x92, 0xe3, 0x15, 0x38, 0x2f, 0xb0 },
689 { 0x92, 0x39, 0xd5, 0x34, 0x8f, 0x40, 0xd1, 0x69, 0x5a, 0x74, 0x54, 0x70, 0xe1, 0xf2, 0x3f, 0x43 },
690 { 0xb0, 0xb7, 0x13, 0x3e, 0xd0, 0x96, 0xf9, 0xb5, 0x6f, 0xae, 0x91, 0xc8, 0x74, 0xbd, 0x3a, 0xc0 },
691 { 0xe9, 0x02, 0x8b, 0x95, 0x78, 0xe4, 0x15, 0xdc, 0x1a, 0x71, 0x0a, 0x2b, 0x88, 0x15, 0x44, 0x47 },
692 { 0x39, 0x2a, 0x43, 0x4f, 0x0e, 0x07, 0xdf, 0x1f, 0x8a, 0xa3, 0x05, 0xde, 0x34, 0xe0, 0xc2, 0x29 },
693 { 0x3e, 0x75, 0xce, 0xd4, 0x6b, 0x69, 0x30, 0x21, 0x21, 0x88, 0x30, 0xae, 0x86, 0xa8, 0x2a, 0x71 },
694 { 0xd7, 0x55, 0x8f, 0xda, 0xf5, 0xf1, 0x10, 0x5b, 0xb2, 0x13, 0x28, 0x2b, 0x70, 0x77, 0x29, 0xa3 },
695 { 0x04, 0x7e, 0xcb, 0xe9, 0xfc, 0xa5, 0x5f, 0x7b, 0xd0, 0x9e, 0xae, 0x36, 0xe1, 0x0c, 0xae, 0x1e },
696 { 0xf5, 0xc8, 0x6a, 0xf3, 0x61, 0x62, 0xf1, 0x3a, 0x64, 0xf5, 0x4f, 0x6d, 0xc9, 0x58, 0x7c, 0x06 } };
698 static const unsigned char UTN_USERFirst_Hardware_Normalized_Issuer
[] = {
699 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55,
700 0x53, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x02,
701 0x55, 0x54, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x07, 0x13,
702 0x0e, 0x53, 0x41, 0x4c, 0x54, 0x20, 0x4c, 0x41, 0x4b, 0x45, 0x20, 0x43,
703 0x49, 0x54, 0x59, 0x31, 0x1e, 0x30, 0x1c, 0x06, 0x03, 0x55, 0x04, 0x0a,
704 0x13, 0x15, 0x54, 0x48, 0x45, 0x20, 0x55, 0x53, 0x45, 0x52, 0x54, 0x52,
705 0x55, 0x53, 0x54, 0x20, 0x4e, 0x45, 0x54, 0x57, 0x4f, 0x52, 0x4b, 0x31,
706 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x18, 0x48, 0x54,
707 0x54, 0x50, 0x3a, 0x2f, 0x2f, 0x57, 0x57, 0x57, 0x2e, 0x55, 0x53, 0x45,
708 0x52, 0x54, 0x52, 0x55, 0x53, 0x54, 0x2e, 0x43, 0x4f, 0x4d, 0x31, 0x1f,
709 0x30, 0x1d, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x16, 0x55, 0x54, 0x4e,
710 0x2d, 0x55, 0x53, 0x45, 0x52, 0x46, 0x49, 0x52, 0x53, 0x54, 0x2d, 0x48,
711 0x41, 0x52, 0x44, 0x57, 0x41, 0x52, 0x45
713 static const unsigned int UTN_USERFirst_Hardware_Normalized_Issuer_len
= 151;
716 static void SecPolicyCheckBlackListedLeaf(SecPVCRef pvc
,
718 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, 0);
719 CFDataRef issuer
= cert
? SecCertificateGetNormalizedIssuerContent(cert
) : NULL
;
721 if (issuer
&& (CFDataGetLength(issuer
) == (CFIndex
)UTN_USERFirst_Hardware_Normalized_Issuer_len
) &&
722 (0 == memcmp(UTN_USERFirst_Hardware_Normalized_Issuer
, CFDataGetBytePtr(issuer
),
723 UTN_USERFirst_Hardware_Normalized_Issuer_len
)))
725 #if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE))
726 CFDataRef serial
= SecCertificateCopySerialNumber(cert
, NULL
);
728 CFDataRef serial
= SecCertificateCopySerialNumber(cert
);
732 CFIndex serial_length
= CFDataGetLength(serial
);
733 const uint8_t *serial_ptr
= CFDataGetBytePtr(serial
);
735 while ((serial_length
> 0) && (*serial_ptr
== 0)) {
740 if (serial_length
== (CFIndex
)sizeof(*UTN_USERFirst_Hardware_Serial
)) {
742 for (i
= 0; i
< array_size(UTN_USERFirst_Hardware_Serial
); i
++)
744 if (0 == memcmp(UTN_USERFirst_Hardware_Serial
[i
],
745 serial_ptr
, sizeof(*UTN_USERFirst_Hardware_Serial
)))
747 SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
);
748 CFReleaseSafe(serial
);
757 SecOTAPKIRef otapkiRef
= SecOTAPKICopyCurrentOTAPKIRef();
758 if (NULL
!= otapkiRef
)
760 CFSetRef blackListedKeys
= SecOTAPKICopyBlackListSet(otapkiRef
);
761 CFRelease(otapkiRef
);
762 if (NULL
!= blackListedKeys
)
764 /* Check for blacklisted intermediates keys. */
765 CFDataRef dgst
= SecCertificateCopyPublicKeySHA1Digest(cert
);
768 /* Check dgst against blacklist. */
769 if (CFSetContainsValue(blackListedKeys
, dgst
))
771 SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
);
775 CFRelease(blackListedKeys
);
780 static void SecPolicyCheckGrayListedLeaf(SecPVCRef pvc
, CFStringRef key
)
782 SecOTAPKIRef otapkiRef
= SecOTAPKICopyCurrentOTAPKIRef();
783 if (NULL
!= otapkiRef
)
785 CFSetRef grayListedKeys
= SecOTAPKICopyGrayList(otapkiRef
);
786 CFRelease(otapkiRef
);
787 if (NULL
!= grayListedKeys
)
789 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, 0);
791 CFDataRef dgst
= SecCertificateCopyPublicKeySHA1Digest(cert
);
794 /* Check dgst against gray. */
795 if (CFSetContainsValue(grayListedKeys
, dgst
))
797 SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
);
801 CFRelease(grayListedKeys
);
806 static void SecPolicyCheckLeafMarkerOid(SecPVCRef pvc
, CFStringRef key
)
808 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, 0);
809 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
810 CFTypeRef value
= CFDictionaryGetValue(policy
->_options
, key
);
812 if (!SecPolicyCheckCertLeafMarkerOid(cert
, value
)) {
813 SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
);
817 static void SecPolicyCheckLeafMarkerOidWithoutValueCheck(SecPVCRef pvc
, CFStringRef key
)
819 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, 0);
820 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
821 CFTypeRef value
= CFDictionaryGetValue(policy
->_options
, key
);
823 if (!SecPolicyCheckCertLeafMarkerOidWithoutValueCheck(cert
, value
)) {
824 SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
);
830 * The value is a dictionary. The dictionary contains keys indicating
831 * whether the value is for Prod or QA. The values are the same as
832 * in the options dictionary for SecPolicyCheckLeafMarkerOid.
834 static void SecPolicyCheckLeafMarkersProdAndQA(SecPVCRef pvc
, CFStringRef key
)
836 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, 0);
837 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
838 CFDictionaryRef value
= CFDictionaryGetValue(policy
->_options
, key
);
839 CFTypeRef prodValue
= CFDictionaryGetValue(value
, kSecPolicyLeafMarkerProd
);
841 if (!SecPolicyCheckCertLeafMarkerOid(cert
, prodValue
)) {
844 SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
);
849 static void SecPolicyCheckIntermediateMarkerOid(SecPVCRef pvc
, CFStringRef key
)
851 CFIndex ix
, count
= SecPVCGetCertificateCount(pvc
);
852 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
853 CFTypeRef value
= CFDictionaryGetValue(policy
->_options
, key
);
855 for (ix
= 1; ix
< count
- 1; ix
++) {
856 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, ix
);
857 if (SecCertificateHasMarkerExtension(cert
, value
))
860 SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
);
863 static void SecPolicyCheckIntermediateEKU(SecPVCRef pvc
, CFStringRef key
)
865 CFIndex ix
, count
= SecPVCGetCertificateCount(pvc
);
866 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
867 CFTypeRef peku
= CFDictionaryGetValue(policy
->_options
, key
);
869 for (ix
= 1; ix
< count
- 1; ix
++) {
870 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, ix
);
871 if (!SecPolicyCheckCertExtendedKeyUsage(cert
, peku
)) {
872 SecPVCSetResult(pvc
, key
, ix
, kCFBooleanFalse
);
877 static void SecPolicyCheckIntermediateOrganization(SecPVCRef pvc
, CFStringRef key
)
879 CFIndex ix
, count
= SecPVCGetCertificateCount(pvc
);
880 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
881 CFTypeRef organization
= CFDictionaryGetValue(policy
->_options
, key
);
883 for (ix
= 1; ix
< count
- 1; ix
++) {
884 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, ix
);
885 if (!SecPolicyCheckCertSubjectOrganization(cert
, organization
)) {
886 SecPVCSetResult(pvc
, key
, ix
, kCFBooleanFalse
);
891 static void SecPolicyCheckIntermediateCountry(SecPVCRef pvc
, CFStringRef key
)
893 CFIndex ix
, count
= SecPVCGetCertificateCount(pvc
);
894 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
895 CFTypeRef country
= CFDictionaryGetValue(policy
->_options
, key
);
897 for (ix
= 1; ix
< count
- 1; ix
++) {
898 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, ix
);
899 if (!SecPolicyCheckCertSubjectCountry(cert
, country
)) {
900 SecPVCSetResult(pvc
, key
, ix
, kCFBooleanFalse
);
905 /****************************************************************************
906 *********************** New rfc5280 Chain Validation ***********************
907 ****************************************************************************/
909 #define POLICY_MAPPING 1
910 #define POLICY_SUBTREES 1
912 /* rfc5280 basic cert processing. */
913 static void SecPolicyCheckBasicCertificateProcessing(SecPVCRef pvc
,
917 CFIndex count
= SecPVCGetCertificateCount(pvc
);
918 SecCertificatePathVCRef path
= SecPathBuilderGetPath(pvc
->builder
);
919 /* 64 bits cast: worst case here is we truncate the number of cert, and the validation may fail */
920 assert((unsigned long)count
<=UINT32_MAX
); /* Debug check. Correct as long as CFIndex is long */
921 uint32_t n
= (uint32_t)count
;
923 bool is_anchored
= SecPathBuilderIsAnchored(pvc
->builder
);
924 bool is_anchor_trusted
= false;
926 CFArrayRef constraints
= SecCertificatePathVCGetUsageConstraintsAtIndex(path
, n
- 1);
927 if (CFArrayGetCount(constraints
) == 0) {
928 /* Given that the path builder has already indicated the last cert in this chain has
929 * trust set on it, empty constraints means trusted. */
930 is_anchor_trusted
= true;
932 /* Determine whether constraints say to trust this cert for this PVC. */
933 SecTrustSettingsResult tsResult
= SecPVCGetTrustSettingsResult(pvc
, SecCertificatePathVCGetCertificateAtIndex(path
, n
- 1),
935 if (tsResult
== kSecTrustSettingsResultTrustRoot
|| tsResult
== kSecTrustSettingsResultTrustAsRoot
) {
936 is_anchor_trusted
= true;
941 if (is_anchor_trusted
) {
942 /* If the anchor is trusted we don't process the last cert in the
946 /* trust may be restored for a path with an untrusted root that matches the allow list.
947 (isAllowlisted is set by revocation check, which is performed prior to path checks) */
948 if (!SecCertificatePathVCIsAllowlisted(path
)) {
949 Boolean isSelfSigned
= false;
950 (void) SecCertificateIsSelfSigned(SecCertificatePathVCGetCertificateAtIndex(path
, n
- 1), &isSelfSigned
);
952 /* Add a detail for the root not being trusted. */
953 if (!SecPVCSetResultForced(pvc
, kSecPolicyCheckAnchorTrusted
,
954 n
- 1, kCFBooleanFalse
, true)) {
958 /* Add a detail for the missing intermediate. */
959 if (!SecPVCSetResultForced(pvc
, kSecPolicyCheckMissingIntermediate
,
960 n
- 1, kCFBooleanFalse
, true)) {
967 CFAbsoluteTime verify_time
= SecPVCGetVerifyTime(pvc
);
968 //policy_set_t user_initial_policy_set = NULL;
969 //trust_anchor_t anchor;
973 CFMutableArrayRef permitted_subtrees
= NULL
;
974 CFMutableArrayRef excluded_subtrees
= NULL
;
975 permitted_subtrees
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
);
976 excluded_subtrees
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
);
977 require_action_quiet(permitted_subtrees
!= NULL
, errOut
,
978 SecPVCSetResultForced(pvc
, kSecPolicyCheckNameConstraints
, 0, kCFBooleanFalse
, true));
979 require_action_quiet(excluded_subtrees
!= NULL
, errOut
,
980 SecPVCSetResultForced(pvc
, kSecPolicyCheckNameConstraints
, 0, kCFBooleanFalse
, true));
983 if (!SecCertificatePathVCVerifyPolicyTree(path
, is_anchor_trusted
)) {
984 if (!SecPVCSetResultForced(pvc
, kSecPolicyCheckPolicyConstraints
, 0, kCFBooleanFalse
, true)) {
990 /* Path builder ensures we only get cert chains with proper issuer
991 chaining with valid signatures along the way. */
992 algorithm_id_t working_public_key_algorithm
= anchor
->public_key_algorithm
;
993 SecKeyRef working_public_key
= anchor
->public_key
;
994 x500_name_t working_issuer_name
= anchor
->issuer_name
;
996 uint32_t i
, max_path_length
= n
;
997 SecCertificateRef cert
= NULL
;
998 for (i
= 1; i
<= n
; ++i
) {
1000 cert
= SecPVCGetCertificateAtIndex(pvc
, n
- i
);
1001 bool is_self_issued
= SecCertificatePathVCIsCertificateAtIndexSelfIssued(SecPathBuilderGetPath(pvc
->builder
), n
- i
);
1003 /* (a) Verify the basic certificate information. */
1004 /* @@@ Ensure that cert was signed with working_public_key_algorithm
1005 using the working_public_key and the working_public_key_parameters. */
1007 /* Already done by chain builder. */
1008 if (!SecCertificateIsValid(cert
, verify_time
)) {
1009 if (!SecPVCSetResult(pvc
, kSecPolicyCheckTemporalValidity
, n
- i
, kCFBooleanFalse
)) {
1013 if (SecCertificateIsWeakKey(cert
)) {
1014 if (!SecPVCSetResult(pvc
, kSecPolicyCheckWeakKeySize
, n
- i
, kCFBooleanFalse
)) {
1018 if (!SecPolicyCheckCertWeakSignature(cert
, NULL
)) {
1019 if (!SecPVCSetResult(pvc
, kSecPolicyCheckWeakSignature
, n
- i
, kCFBooleanFalse
)) {
1024 /* @@@ cert.issuer == working_issuer_name. */
1028 if (!is_self_issued
|| i
== n
) {
1030 /* Verify certificate Subject Name and SubjectAltNames are not within any of the excluded_subtrees */
1031 if(excluded_subtrees
&& CFArrayGetCount(excluded_subtrees
)) {
1032 if ((errSecSuccess
!= SecNameContraintsMatchSubtrees(cert
, excluded_subtrees
, &found
, false)) || found
) {
1033 secnotice("policy", "name in excluded subtrees");
1034 if(!SecPVCSetResultForced(pvc
, kSecPolicyCheckNameConstraints
, n
- i
, kCFBooleanFalse
, true)) { goto errOut
; }
1037 /* Verify certificate Subject Name and SubjectAltNames are within the permitted_subtrees */
1038 if(permitted_subtrees
&& CFArrayGetCount(permitted_subtrees
)) {
1039 if ((errSecSuccess
!= SecNameContraintsMatchSubtrees(cert
, permitted_subtrees
, &found
, true)) || !found
) {
1040 secnotice("policy", "name not in permitted subtrees");
1041 if(!SecPVCSetResultForced(pvc
, kSecPolicyCheckNameConstraints
, n
- i
, kCFBooleanFalse
, true)) { goto errOut
; }
1046 /* (d) (e) (f) handled by SecCertificatePathVCVerifyPolicyTree */
1048 /* If Last Cert in Path */
1052 /* Prepare for Next Cert */
1053 /* (a) (b) Done by SecCertificatePathVCVerifyPolicyTree */
1054 /* (c)(d)(e)(f) Done by SecPathBuilderGetNext and SecCertificatePathVCVerify */
1055 //working_issuer_name = SecCertificateGetNormalizedSubjectContent(cert);
1056 //working_public_key = SecCertificateCopyPublicKey(cert);
1057 //working_public_key_parameters = SecCertificateCopyPublicKeyParameters(cert);
1058 //working_public_key_algorithm = SecCertificateCopyPublicKeyAlgorithm(cert);
1060 /* (g) If a name constraints extension is included in the certificate, modify the permitted_subtrees and excluded_subtrees state variables.
1062 CFArrayRef permitted_subtrees_in_cert
= SecCertificateGetPermittedSubtrees(cert
);
1063 if (permitted_subtrees_in_cert
) {
1064 SecNameConstraintsIntersectSubtrees(permitted_subtrees
, permitted_subtrees_in_cert
);
1067 // could do something smart here to avoid inserting the exact same constraint
1068 CFArrayRef excluded_subtrees_in_cert
= SecCertificateGetExcludedSubtrees(cert
);
1069 if (excluded_subtrees_in_cert
) {
1070 CFIndex num_trees
= CFArrayGetCount(excluded_subtrees_in_cert
);
1071 CFRange range
= { 0, num_trees
};
1072 CFArrayAppendArray(excluded_subtrees
, excluded_subtrees_in_cert
, range
);
1075 /* (h), (i), (j) done by SecCertificatePathVCVerifyPolicyTree */
1077 /* (k) Checked in chain builder pre signature verify already. SecPVCParentCertificateChecks */
1080 if (!is_self_issued
) {
1081 if (max_path_length
> 0) {
1084 /* max_path_len exceeded, illegal. */
1085 if (!SecPVCSetResultForced(pvc
, kSecPolicyCheckBasicConstraintsPathLen
,
1086 n
- i
, kCFBooleanFalse
, true)) {
1092 const SecCEBasicConstraints
*bc
= SecCertificateGetBasicConstraints(cert
);
1093 if (bc
&& bc
->pathLenConstraintPresent
1094 && bc
->pathLenConstraint
< max_path_length
) {
1095 max_path_length
= bc
->pathLenConstraint
;
1097 #if 0 /* Checked in chain builder pre signature verify already. SecPVCParentCertificateChecks */
1098 /* (n) If a key usage extension is present, verify that the keyCertSign bit is set. */
1099 SecKeyUsage keyUsage
= SecCertificateGetKeyUsage(cert
);
1100 if (keyUsage
&& !(keyUsage
& kSecKeyUsageKeyCertSign
)) {
1101 if (!SecPVCSetResultForced(pvc
, kSecPolicyCheckKeyUsage
,
1102 n
- i
, kCFBooleanFalse
, true)) {
1107 /* (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. */
1108 if (SecCertificateHasUnknownCriticalExtension(cert
)) {
1109 /* Certificate contains one or more unknown critical extensions. */
1110 if (!SecPVCSetResult(pvc
, kSecPolicyCheckCriticalExtensions
,
1111 n
- i
, kCFBooleanFalse
)) {
1115 } /* end loop over certs in path */
1117 /* (a) (b) done by SecCertificatePathVCVerifyPolicyTree */
1119 //working_public_key = SecCertificateCopyPublicKey(cert);
1121 /* 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
1122 working_public_key_algorithm are different, set the working_public_key_parameters to null. */
1123 //working_public_key_parameters = SecCertificateCopyPublicKeyParameters(cert);
1125 //working_public_key_algorithm = SecCertificateCopyPublicKeyAlgorithm(cert);
1126 /* (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. */
1127 if (SecCertificateHasUnknownCriticalExtension(cert
)) {
1128 /* Certificate contains one or more unknown critical extensions. */
1129 if (!SecPVCSetResult(pvc
, kSecPolicyCheckCriticalExtensions
,
1130 0, kCFBooleanFalse
)) {
1134 /* (g) done by SecCertificatePathVCVerifyPolicyTree */
1137 CFReleaseNull(permitted_subtrees
);
1138 CFReleaseNull(excluded_subtrees
);
1141 static policy_set_t
policies_for_cert(SecCertificateRef cert
) {
1142 policy_set_t policies
= NULL
;
1143 const SecCECertificatePolicies
*cp
=
1144 SecCertificateGetCertificatePolicies(cert
);
1145 size_t policy_ix
, policy_count
= cp
? cp
->numPolicies
: 0;
1146 for (policy_ix
= 0; policy_ix
< policy_count
; ++policy_ix
) {
1147 policy_set_add(&policies
, &cp
->policies
[policy_ix
].policyIdentifier
);
1152 static void SecPolicyCheckEV(SecPVCRef pvc
,
1154 CFIndex ix
, count
= SecPVCGetCertificateCount(pvc
);
1155 policy_set_t valid_policies
= NULL
;
1157 /* 6.1.7. Key Usage Purposes */
1159 CFAbsoluteTime jul2016
= 489024000;
1160 SecCertificateRef leaf
= SecPVCGetCertificateAtIndex(pvc
, 0);
1161 if (SecCertificateNotValidBefore(leaf
) > jul2016
&& count
< 3) {
1162 /* Root CAs may not sign subscriber certificates after 30 June 2016. */
1163 if (SecPVCSetResultForced(pvc
, key
,
1164 0, kCFBooleanFalse
, true)) {
1170 for (ix
= 0; ix
< count
; ++ix
) {
1171 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, ix
);
1172 policy_set_t policies
= policies_for_cert(cert
);
1175 /* anyPolicy in the leaf isn't allowed for EV, so only init
1176 valid_policies if we have real policies. */
1177 if (!policy_set_contains(policies
, &oidAnyPolicy
)) {
1178 valid_policies
= policies
;
1181 } else if (ix
< count
- 1) {
1182 /* Subordinate CA */
1183 if (!SecPolicySubordinateCACertificateCouldBeEV(cert
)) {
1184 secnotice("ev", "subordinate certificate is not ev");
1185 if (SecPVCSetResultForced(pvc
, key
,
1186 ix
, kCFBooleanFalse
, true)) {
1187 policy_set_free(valid_policies
);
1188 policy_set_free(policies
);
1192 policy_set_intersect(&valid_policies
, policies
);
1195 if (!SecPolicyRootCACertificateIsEV(cert
, valid_policies
)) {
1196 secnotice("ev", "anchor certificate is not ev");
1197 if (SecPVCSetResultForced(pvc
, key
,
1198 ix
, kCFBooleanFalse
, true)) {
1199 policy_set_free(valid_policies
);
1200 policy_set_free(policies
);
1205 policy_set_free(policies
);
1206 if (!valid_policies
) {
1207 secnotice("ev", "valid_policies set is empty: chain not ev");
1208 /* If we ever get into a state where no policies are valid anymore
1209 this can't be an ev chain. */
1210 if (SecPVCSetResultForced(pvc
, key
,
1211 ix
, kCFBooleanFalse
, true)) {
1217 policy_set_free(valid_policies
);
1219 /* (a) EV Subscriber Certificates Each EV Certificate issued by the CA to a
1220 Subscriber MUST contain an OID defined by the CA in the certificate’s
1221 certificatePolicies extension that: (i) indicates which CA policy statement relates
1222 to that certificate, (ii) asserts the CA’s adherence to and compliance with these
1223 Guidelines, and (iii), by pre-agreement with the Application Software Vendor,
1224 marks the certificate as being an EV Certificate.
1225 (b) EV Subordinate CA Certificates
1226 (1) Certificates issued to Subordinate CAs that are not controlled by the issuing
1227 CA MUST contain one or more OIDs defined by the issuing CA that
1228 explicitly identify the EV Policies that are implemented by the Subordinate
1230 (2) Certificates issued to Subordinate CAs that are controlled by the Root CA
1231 MAY contain the special anyPolicy OID (2.5.29.32.0).
1232 (c) Root CA Certificates Root CA Certificates SHOULD NOT contain the
1233 certificatePolicies or extendedKeyUsage extensions.
1239 * MARK: Certificate Transparency support
1245 Version sct_version; // 1 byte
1246 LogID id; // 32 bytes
1247 uint64 timestamp; // 8 bytes
1248 CtExtensions extensions; // 2 bytes len field, + n bytes data
1249 digitally-signed struct { // 1 byte hash alg, 1 byte sig alg, n bytes signature
1250 Version sct_version;
1251 SignatureType signature_type = certificate_timestamp;
1253 LogEntryType entry_type;
1254 select(entry_type) {
1255 case x509_entry: ASN.1Cert;
1256 case precert_entry: PreCert;
1258 CtExtensions extensions;
1260 } SignedCertificateTimestamp;
1264 #include <Security/SecureTransportPriv.h>
1267 SecAsn1Oid
*oidForSigAlg(SSL_HashAlgorithm hash
, SSL_SignatureAlgorithm alg
)
1270 case SSL_SignatureAlgorithmRSA
:
1272 case SSL_HashAlgorithmSHA1
:
1273 return &CSSMOID_SHA1WithRSA
;
1274 case SSL_HashAlgorithmSHA256
:
1275 return &CSSMOID_SHA256WithRSA
;
1276 case SSL_HashAlgorithmSHA384
:
1277 return &CSSMOID_SHA384WithRSA
;
1281 case SSL_SignatureAlgorithmECDSA
:
1283 case SSL_HashAlgorithmSHA1
:
1284 return &CSSMOID_ECDSA_WithSHA1
;
1285 case SSL_HashAlgorithmSHA256
:
1286 return &CSSMOID_ECDSA_WithSHA256
;
1287 case SSL_HashAlgorithmSHA384
:
1288 return &CSSMOID_ECDSA_WithSHA384
;
1300 static size_t SSLDecodeUint16(const uint8_t *p
)
1302 return (p
[0]<<8 | p
[1]);
1305 static uint8_t *SSLEncodeUint16(uint8_t *p
, size_t len
)
1307 p
[0] = (len
>> 8)&0xff;
1308 p
[1] = (len
& 0xff);
1312 static uint8_t *SSLEncodeUint24(uint8_t *p
, size_t len
)
1314 p
[0] = (len
>> 16)&0xff;
1315 p
[1] = (len
>> 8)&0xff;
1316 p
[2] = (len
& 0xff);
1322 uint64_t SSLDecodeUint64(const uint8_t *p
)
1325 for(int i
=0; i
<8; i
++) {
1332 #include <libDER/DER_CertCrl.h>
1333 #include <libDER/DER_Encode.h>
1334 #include <libDER/asn1Types.h>
1337 static CFDataRef
copy_x509_entry_from_chain(SecPVCRef pvc
)
1339 SecCertificateRef leafCert
= SecPVCGetCertificateAtIndex(pvc
, 0);
1341 CFMutableDataRef data
= CFDataCreateMutable(kCFAllocatorDefault
, 3+SecCertificateGetLength(leafCert
));
1343 CFDataSetLength(data
, 3+SecCertificateGetLength(leafCert
));
1345 uint8_t *q
= CFDataGetMutableBytePtr(data
);
1346 q
= SSLEncodeUint24(q
, SecCertificateGetLength(leafCert
));
1347 memcpy(q
, SecCertificateGetBytePtr(leafCert
), SecCertificateGetLength(leafCert
));
1353 static CFDataRef
copy_precert_entry_from_chain(SecPVCRef pvc
)
1355 SecCertificateRef leafCert
= NULL
;
1356 SecCertificateRef issuer
= NULL
;
1357 CFDataRef issuerKeyHash
= NULL
;
1358 CFDataRef tbs_precert
= NULL
;
1359 CFMutableDataRef data
= NULL
;
1361 require_quiet(SecPVCGetCertificateCount(pvc
)>=2, out
); //we need the issuer key for precerts.
1362 leafCert
= SecPVCGetCertificateAtIndex(pvc
, 0);
1363 issuer
= SecPVCGetCertificateAtIndex(pvc
, 1);
1365 require(leafCert
, out
);
1366 require(issuer
, out
); // Those two would likely indicate an internal error, since we already checked the chain length above.
1367 issuerKeyHash
= SecCertificateCopySubjectPublicKeyInfoSHA256Digest(issuer
);
1368 tbs_precert
= SecCertificateCopyPrecertTBS(leafCert
);
1370 require(issuerKeyHash
, out
);
1371 require(tbs_precert
, out
);
1372 data
= CFDataCreateMutable(kCFAllocatorDefault
, CFDataGetLength(issuerKeyHash
) + 3 + CFDataGetLength(tbs_precert
));
1373 CFDataSetLength(data
, CFDataGetLength(issuerKeyHash
) + 3 + CFDataGetLength(tbs_precert
));
1375 uint8_t *q
= CFDataGetMutableBytePtr(data
);
1376 memcpy(q
, CFDataGetBytePtr(issuerKeyHash
), CFDataGetLength(issuerKeyHash
)); q
+= CFDataGetLength(issuerKeyHash
); // issuer key hash
1377 q
= SSLEncodeUint24(q
, CFDataGetLength(tbs_precert
));
1378 memcpy(q
, CFDataGetBytePtr(tbs_precert
), CFDataGetLength(tbs_precert
));
1381 CFReleaseSafe(issuerKeyHash
);
1382 CFReleaseSafe(tbs_precert
);
1387 CFAbsoluteTime
TimestampToCFAbsoluteTime(uint64_t ts
)
1389 return (ts
/ 1000) - kCFAbsoluteTimeIntervalSince1970
;
1393 uint64_t TimestampFromCFAbsoluteTime(CFAbsoluteTime at
)
1395 return (uint64_t)(at
+ kCFAbsoluteTimeIntervalSince1970
) * 1000;
1402 If the 'sct' is valid, add it to the validatingLogs dictionary.
1405 - validatingLogs: mutable dictionary to which to add the log that validate this SCT.
1407 - entry_type: 0 for x509 cert, 1 for precert.
1408 - entry: the cert or precert data.
1409 - vt: verification time timestamp (as used in SCTs: ms since 1970 Epoch)
1410 - trustedLog: Dictionary contain the Trusted Logs.
1412 The SCT is valid if:
1413 - It decodes properly.
1414 - Its timestamp is less than 'verifyTime'.
1415 - It is signed by a log in 'trustedLogs'.
1416 - If entry_type = 0, the log must be currently qualified.
1417 - If entry_type = 1, the log may be expired.
1419 If the SCT is valid, it's added to the validatinLogs dictionary using the log dictionary as the key, and the timestamp as value.
1420 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.
1425 static CFDictionaryRef
getSCTValidatingLog(CFDataRef sct
, int entry_type
, CFDataRef entry
, uint64_t vt
, CFArrayRef trustedLogs
, CFAbsoluteTime
*sct_at
)
1428 const uint8_t *logID
;
1429 const uint8_t *timestampData
;
1431 size_t extensionsLen
;
1432 const uint8_t *extensionsData
;
1435 size_t signatureLen
;
1436 const uint8_t *signatureData
;
1437 SecKeyRef pubKey
= NULL
;
1438 uint8_t *signed_data
= NULL
;
1439 const SecAsn1Oid
*oid
= NULL
;
1441 CFDataRef logIDData
= NULL
;
1442 CFDictionaryRef result
= 0;
1444 const uint8_t *p
= CFDataGetBytePtr(sct
);
1445 size_t len
= CFDataGetLength(sct
);
1447 require(len
>=43, out
);
1449 version
= p
[0]; p
++; len
--;
1450 logID
= p
; p
+=32; len
-=32;
1451 timestampData
= p
; p
+=8; len
-=8;
1452 extensionsLen
= SSLDecodeUint16(p
); p
+=2; len
-=2;
1454 require(len
>=extensionsLen
, out
);
1455 extensionsData
= p
; p
+=extensionsLen
; len
-=extensionsLen
;
1457 require(len
>=4, out
);
1458 hashAlg
=p
[0]; p
++; len
--;
1459 sigAlg
=p
[0]; p
++; len
--;
1460 signatureLen
= SSLDecodeUint16(p
); p
+=2; len
-=2;
1461 require(len
==signatureLen
, out
); /* We do not tolerate any extra data after the signature */
1464 /* verify version: only v1(0) is supported */
1466 secerror("SCT version unsupported: %d\n", version
);
1470 /* verify timestamp not in the future */
1471 timestamp
= SSLDecodeUint64(timestampData
);
1472 if(timestamp
> vt
) {
1473 secerror("SCT is in the future: %llu > %llu\n", timestamp
, vt
);
1480 size_t signed_data_len
= 12 + CFDataGetLength(entry
) + 2 + extensionsLen
;
1481 signed_data
= malloc(signed_data_len
);
1482 require(signed_data
, out
);
1485 *q
++ = 0; // certificate_timestamp
1486 memcpy(q
, timestampData
, 8); q
+=8;
1487 q
= SSLEncodeUint16(q
, entry_type
); // logentry type: 0=cert 1=precert
1488 memcpy(q
, CFDataGetBytePtr(entry
), CFDataGetLength(entry
)); q
+= CFDataGetLength(entry
);
1489 q
= SSLEncodeUint16(q
, extensionsLen
);
1490 memcpy(q
, extensionsData
, extensionsLen
);
1492 logIDData
= CFDataCreateWithBytesNoCopy(kCFAllocatorDefault
, logID
, 32, kCFAllocatorNull
);
1494 CFDictionaryRef logData
= CFArrayGetValueMatching(trustedLogs
, ^bool(const void *dict
) {
1495 const void *key_data
;
1496 if(!isDictionary(dict
)) return false;
1497 if(!CFDictionaryGetValueIfPresent(dict
, CFSTR("key"), &key_data
)) return false;
1498 if(!isData(key_data
)) return false;
1499 CFDataRef valueID
= SecSHA256DigestCreateFromData(kCFAllocatorDefault
, (CFDataRef
)key_data
);
1500 bool result
= (bool)(CFDataCompare(logIDData
, valueID
)==kCFCompareEqualTo
);
1501 CFReleaseSafe(valueID
);
1504 require(logData
, out
);
1507 // For external SCTs, only keep SCTs from currently valid logs.
1508 require(!CFDictionaryContainsKey(logData
, CFSTR("expiry")), out
);
1511 CFDataRef logKeyData
= CFDictionaryGetValue(logData
, CFSTR("key"));
1512 require(logKeyData
, out
); // This failing would be an internal logic error
1513 pubKey
= SecKeyCreateFromSubjectPublicKeyInfoData(kCFAllocatorDefault
, logKeyData
);
1514 require(pubKey
, out
);
1516 oid
= oidForSigAlg(hashAlg
, sigAlg
);
1519 algId
.algorithm
= *oid
;
1520 algId
.parameters
.Data
= NULL
;
1521 algId
.parameters
.Length
= 0;
1523 if(SecKeyDigestAndVerify(pubKey
, &algId
, signed_data
, signed_data_len
, signatureData
, signatureLen
)==0) {
1524 *sct_at
= TimestampToCFAbsoluteTime(timestamp
);
1527 secerror("SCT signature failed (log=%@)\n", logData
);
1531 CFReleaseSafe(logIDData
);
1532 CFReleaseSafe(pubKey
);
1538 static void addValidatingLog(CFMutableDictionaryRef validatingLogs
, CFDictionaryRef log
, CFAbsoluteTime sct_at
)
1540 CFDateRef validated_time
= CFDictionaryGetValue(validatingLogs
, log
);
1542 if(validated_time
==NULL
|| (sct_at
< CFDateGetAbsoluteTime(validated_time
))) {
1543 CFDateRef sct_time
= CFDateCreate(kCFAllocatorDefault
, sct_at
);
1544 CFDictionarySetValue(validatingLogs
, log
, sct_time
);
1545 CFReleaseSafe(sct_time
);
1549 static CFArrayRef
copy_ocsp_scts(SecPVCRef pvc
)
1551 CFMutableArrayRef SCTs
= NULL
;
1552 SecCertificateRef leafCert
= NULL
;
1553 SecCertificateRef issuer
= NULL
;
1554 CFArrayRef ocspResponsesData
= NULL
;
1555 SecOCSPRequestRef ocspRequest
= NULL
;
1557 ocspResponsesData
= SecPathBuilderCopyOCSPResponses(pvc
->builder
);
1558 require_quiet(ocspResponsesData
, out
);
1560 require_quiet(SecPVCGetCertificateCount(pvc
)>=2, out
); //we need the issuer key for precerts.
1561 leafCert
= SecPVCGetCertificateAtIndex(pvc
, 0);
1562 issuer
= SecPVCGetCertificateAtIndex(pvc
, 1);
1564 require(leafCert
, out
);
1565 require(issuer
, out
); // not quiet: Those two would likely indicate an internal error, since we already checked the chain length above.
1566 ocspRequest
= SecOCSPRequestCreate(leafCert
, issuer
);
1568 SCTs
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
);
1571 CFArrayForEach(ocspResponsesData
, ^(const void *value
) {
1572 /* TODO: Should the builder already have the appropriate SecOCSPResponseRef ? */
1573 SecOCSPResponseRef ocspResponse
= SecOCSPResponseCreate(value
);
1574 if(ocspResponse
&& SecOCSPGetResponseStatus(ocspResponse
)==kSecOCSPSuccess
) {
1575 SecOCSPSingleResponseRef ocspSingleResponse
= SecOCSPResponseCopySingleResponse(ocspResponse
, ocspRequest
);
1576 if(ocspSingleResponse
) {
1577 CFArrayRef singleResponseSCTs
= SecOCSPSingleResponseCopySCTs(ocspSingleResponse
);
1578 if(singleResponseSCTs
) {
1579 CFArrayAppendArray(SCTs
, singleResponseSCTs
, CFRangeMake(0, CFArrayGetCount(singleResponseSCTs
)));
1580 CFRelease(singleResponseSCTs
);
1582 SecOCSPSingleResponseDestroy(ocspSingleResponse
);
1585 if(ocspResponse
) SecOCSPResponseFinalize(ocspResponse
);
1588 if(CFArrayGetCount(SCTs
)==0) {
1589 CFReleaseNull(SCTs
);
1593 CFReleaseSafe(ocspResponsesData
);
1595 SecOCSPRequestFinalize(ocspRequest
);
1600 static void SecPolicyCheckCT(SecPVCRef pvc
)
1602 SecCertificateRef leafCert
= SecPVCGetCertificateAtIndex(pvc
, 0);
1603 CFArrayRef embeddedScts
= SecCertificateCopySignedCertificateTimestamps(leafCert
);
1604 CFArrayRef builderScts
= SecPathBuilderCopySignedCertificateTimestamps(pvc
->builder
);
1605 CFArrayRef trustedLogs
= SecPathBuilderCopyTrustedLogs(pvc
->builder
);
1606 CFArrayRef ocspScts
= copy_ocsp_scts(pvc
);
1607 CFDataRef precertEntry
= copy_precert_entry_from_chain(pvc
);
1608 CFDataRef x509Entry
= copy_x509_entry_from_chain(pvc
);
1609 __block
uint32_t trustedSCTCount
= 0;
1610 __block CFIndex totalSCTSize
= 0;
1612 // This eventually contain list of logs who validated the SCT.
1613 CFMutableDictionaryRef currentLogsValidatingScts
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
1614 CFMutableDictionaryRef logsValidatingEmbeddedScts
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
1616 uint64_t vt
= TimestampFromCFAbsoluteTime(SecPVCGetVerifyTime(pvc
));
1618 __block
bool at_least_one_currently_valid_external
= 0;
1619 __block
bool at_least_one_currently_valid_embedded
= 0;
1621 require(logsValidatingEmbeddedScts
, out
);
1622 require(currentLogsValidatingScts
, out
);
1624 if(trustedLogs
) { // Don't bother trying to validate SCTs if we don't have any trusted logs.
1625 if(embeddedScts
&& precertEntry
) { // Don't bother if we could not get the precert.
1626 CFArrayForEach(embeddedScts
, ^(const void *value
){
1627 CFAbsoluteTime sct_at
;
1628 CFDictionaryRef log
= getSCTValidatingLog(value
, 1, precertEntry
, vt
, trustedLogs
, &sct_at
);
1630 addValidatingLog(logsValidatingEmbeddedScts
, log
, sct_at
);
1631 if(!CFDictionaryContainsKey(log
, CFSTR("expiry"))) {
1632 addValidatingLog(currentLogsValidatingScts
, log
, sct_at
);
1633 at_least_one_currently_valid_embedded
= true;
1637 totalSCTSize
+= CFDataGetLength(value
);
1641 if(builderScts
&& x509Entry
) { // Don't bother if we could not get the cert.
1642 CFArrayForEach(builderScts
, ^(const void *value
){
1643 CFAbsoluteTime sct_at
;
1644 CFDictionaryRef log
= getSCTValidatingLog(value
, 0, x509Entry
, vt
, trustedLogs
, &sct_at
);
1646 addValidatingLog(currentLogsValidatingScts
, log
, sct_at
);
1647 at_least_one_currently_valid_external
= true;
1650 totalSCTSize
+= CFDataGetLength(value
);
1654 if(ocspScts
&& x509Entry
) {
1655 CFArrayForEach(ocspScts
, ^(const void *value
){
1656 CFAbsoluteTime sct_at
;
1657 CFDictionaryRef log
= getSCTValidatingLog(value
, 0, x509Entry
, vt
, trustedLogs
, &sct_at
);
1659 addValidatingLog(currentLogsValidatingScts
, log
, sct_at
);
1660 at_least_one_currently_valid_external
= true;
1663 totalSCTSize
+= CFDataGetLength(value
);
1669 /* We now have 2 sets of logs that validated those SCTS, count them and make a final decision.
1672 is_ct = (A1 AND A2) OR (B1 AND B2).
1674 A1: embedded SCTs from 2+ to 5+ logs valid at issuance time
1675 A2: At least one embedded SCT from a currently valid log.
1677 B1: SCTs from 2 currently valid logs (from any source)
1678 B2: At least 1 external SCT from a currently valid log.
1682 SecCertificatePathVCSetIsCT(SecPathBuilderGetPath(pvc
->builder
), false);
1684 if(at_least_one_currently_valid_external
&& CFDictionaryGetCount(currentLogsValidatingScts
)>=2) {
1685 SecCertificatePathVCSetIsCT(SecPathBuilderGetPath(pvc
->builder
), true);
1686 } else if(at_least_one_currently_valid_embedded
) {
1687 __block CFAbsoluteTime issuanceTime
= SecPVCGetVerifyTime(pvc
);
1688 __block
int lifetime
; // in Months
1689 __block
unsigned once_or_current_qualified_embedded
= 0;
1691 /* Calculate issuance time based on timestamp of SCTs from current logs */
1692 CFDictionaryForEach(currentLogsValidatingScts
, ^(const void *key
, const void *value
) {
1693 CFDictionaryRef log
= key
;
1694 if(!CFDictionaryContainsKey(log
, CFSTR("expiry"))) {
1695 // Log is still qualified
1696 CFDateRef ts
= (CFDateRef
) value
;
1697 CFAbsoluteTime timestamp
= CFDateGetAbsoluteTime(ts
);
1698 if(timestamp
< issuanceTime
) {
1699 issuanceTime
= timestamp
;
1705 CFDictionaryForEach(logsValidatingEmbeddedScts
, ^(const void *key
, const void *value
) {
1706 CFDictionaryRef log
= key
;
1707 CFDateRef ts
= value
;
1708 CFDateRef expiry
= CFDictionaryGetValue(log
, CFSTR("expiry"));
1709 if (expiry
== NULL
) { // Currently qualified OR
1710 once_or_current_qualified_embedded
++;
1711 } else if (CFDateCompare(ts
, expiry
, NULL
) == kCFCompareLessThan
&& // Once qualified. That is, qualified at the time of SCT AND
1712 issuanceTime
< CFDateGetAbsoluteTime(expiry
)) { // at the time of issuance.)
1713 once_or_current_qualified_embedded
++;
1718 SecCFCalendarDoWithZuluCalendar(^(CFCalendarRef zuluCalendar
) {
1720 CFCalendarGetComponentDifference(zuluCalendar
,
1721 SecCertificateNotValidBefore(leafCert
),
1722 SecCertificateNotValidAfter(leafCert
),
1723 0, "M", &_lifetime
);
1724 lifetime
= _lifetime
;
1727 unsigned requiredEmbeddedSctsCount
;
1729 if (lifetime
< 15) {
1730 requiredEmbeddedSctsCount
= 2;
1731 } else if (lifetime
<= 27) {
1732 requiredEmbeddedSctsCount
= 3;
1733 } else if (lifetime
<= 39) {
1734 requiredEmbeddedSctsCount
= 4;
1736 requiredEmbeddedSctsCount
= 5;
1739 if(once_or_current_qualified_embedded
>= requiredEmbeddedSctsCount
){
1740 SecCertificatePathVCSetIsCT(SecPathBuilderGetPath(pvc
->builder
), true);
1744 /* Record analytics data for CT */
1745 TrustAnalyticsBuilder
*analytics
= SecPathBuilderGetAnalyticsData(pvc
->builder
);
1746 require_quiet(analytics
, out
);
1747 uint32_t sctCount
= 0;
1748 /* Count the total number of SCTs we found and report where we got them */
1749 if (embeddedScts
&& CFArrayGetCount(embeddedScts
) > 0) {
1750 analytics
->sct_sources
|= TA_SCTEmbedded
;
1751 sctCount
+= CFArrayGetCount(embeddedScts
);
1753 if (builderScts
&& CFArrayGetCount(builderScts
) > 0) {
1754 analytics
->sct_sources
|= TA_SCT_TLS
;
1755 sctCount
+= CFArrayGetCount(builderScts
);
1757 if (ocspScts
&& CFArrayGetCount(ocspScts
) > 0) {
1758 analytics
->sct_sources
|= TA_SCT_OCSP
;
1759 sctCount
+= CFArrayGetCount(ocspScts
);
1761 /* Report how many of those SCTs were once or currently qualified */
1762 analytics
->number_trusted_scts
= trustedSCTCount
;
1763 /* Report the total number of bytes in the SCTs */
1764 analytics
->total_sct_size
= totalSCTSize
;
1765 /* Report how many SCTs we got */
1766 analytics
->number_scts
= sctCount
;
1769 CFReleaseSafe(logsValidatingEmbeddedScts
);
1770 CFReleaseSafe(currentLogsValidatingScts
);
1771 CFReleaseSafe(builderScts
);
1772 CFReleaseSafe(embeddedScts
);
1773 CFReleaseSafe(ocspScts
);
1774 CFReleaseSafe(precertEntry
);
1775 CFReleaseSafe(trustedLogs
);
1776 CFReleaseSafe(x509Entry
);
1779 static bool checkPolicyOidData(SecPVCRef pvc
, CFDataRef oid
) {
1780 CFIndex ix
, count
= SecPVCGetCertificateCount(pvc
);
1782 key_value
.data
= (DERByte
*)CFDataGetBytePtr(oid
);
1783 key_value
.length
= (DERSize
)CFDataGetLength(oid
);
1785 for (ix
= 0; ix
< count
; ix
++) {
1786 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, ix
);
1787 policy_set_t policies
= policies_for_cert(cert
);
1789 if (policy_set_contains(policies
, &key_value
)) {
1790 policy_set_free(policies
);
1793 policy_set_free(policies
);
1798 static void SecPolicyCheckCertificatePolicy(SecPVCRef pvc
, CFStringRef key
)
1800 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
1801 CFTypeRef value
= CFDictionaryGetValue(policy
->_options
, key
);
1802 bool result
= false;
1804 if (CFGetTypeID(value
) == CFDataGetTypeID())
1806 result
= checkPolicyOidData(pvc
, value
);
1807 } else if (CFGetTypeID(value
) == CFStringGetTypeID()) {
1808 CFDataRef dataOid
= SecCertificateCreateOidDataFromString(NULL
, value
);
1810 result
= checkPolicyOidData(pvc
, dataOid
);
1815 SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
);
1820 static void SecPolicyCheckRevocation(SecPVCRef pvc
,
1822 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
1823 CFTypeRef value
= CFDictionaryGetValue(policy
->_options
, key
);
1824 if (isString(value
)) {
1825 SecPathBuilderSetRevocationMethod(pvc
->builder
, value
);
1829 static void SecPolicyCheckRevocationResponseRequired(SecPVCRef pvc
,
1831 pvc
->require_revocation_response
= true;
1832 secdebug("policy", "revocation response required");
1835 static void SecPolicyCheckRevocationOnline(SecPVCRef pvc
, CFStringRef key
) {
1836 SecPathBuilderSetCheckRevocationOnline(pvc
->builder
);
1839 static void SecPolicyCheckRevocationIfTrusted(SecPVCRef pvc
, CFStringRef key
) {
1840 SecPathBuilderSetCheckRevocationIfTrusted(pvc
->builder
);
1843 static void SecPolicyCheckNoNetworkAccess(SecPVCRef pvc
,
1845 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
1846 CFTypeRef value
= CFDictionaryGetValue(policy
->_options
, key
);
1847 if (value
== kCFBooleanTrue
) {
1848 SecPathBuilderSetCanAccessNetwork(pvc
->builder
, false);
1850 SecPathBuilderSetCanAccessNetwork(pvc
->builder
, true);
1854 static void SecPolicyCheckWeakKeySize(SecPVCRef pvc
,
1856 CFIndex ix
, count
= SecPVCGetCertificateCount(pvc
);
1857 for (ix
= 0; ix
< count
; ++ix
) {
1858 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, ix
);
1859 if (cert
&& SecCertificateIsWeakKey(cert
)) {
1860 /* Intermediate certificate has a weak key. */
1861 if (!SecPVCSetResult(pvc
, key
, ix
, kCFBooleanFalse
))
1867 static void SecPolicyCheckKeySize(SecPVCRef pvc
, CFStringRef key
) {
1868 CFIndex ix
, count
= SecPVCGetCertificateCount(pvc
);
1869 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
1870 CFDictionaryRef keySizes
= CFDictionaryGetValue(policy
->_options
, key
);
1871 for (ix
= 0; ix
< count
; ++ix
) {
1872 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, ix
);
1873 if (!SecCertificateIsAtLeastMinKeySize(cert
, keySizes
)) {
1874 if (!SecPVCSetResult(pvc
, key
, ix
, kCFBooleanFalse
))
1880 static void SecPolicyCheckWeakSignature(SecPVCRef pvc
, CFStringRef key
) {
1881 CFIndex ix
, count
= SecPVCGetCertificateCount(pvc
);
1882 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
1883 CFTypeRef pvcValue
= CFDictionaryGetValue(policy
->_options
, key
);
1884 for (ix
= 0; ix
< count
; ++ix
) {
1885 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, ix
);
1886 if (!SecPolicyCheckCertWeakSignature(cert
, pvcValue
)) {
1887 if (!SecPVCSetResult(pvc
, key
, ix
, kCFBooleanFalse
))
1893 static void SecPolicyCheckSignatureHashAlgorithms(SecPVCRef pvc
,
1895 CFIndex ix
, count
= SecPVCGetCertificateCount(pvc
);
1896 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
1897 CFSetRef disallowedHashAlgorithms
= CFDictionaryGetValue(policy
->_options
, key
);
1898 for (ix
= 0; ix
< count
; ++ix
) {
1899 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, ix
);
1900 if (!SecPolicyCheckCertSignatureHashAlgorithms(cert
, disallowedHashAlgorithms
)) {
1901 if (!SecPVCSetResult(pvc
, key
, ix
, kCFBooleanFalse
))
1907 static bool leaf_is_on_weak_hash_whitelist(SecPVCRef pvc
) {
1908 SecCertificateRef leaf
= SecPVCGetCertificateAtIndex(pvc
, 0);
1909 require_quiet(leaf
, out
);
1911 /* And now a special snowflake from our tests */
1913 /* subject:/C=AU/ST=NSW/L=St Leonards/O=VODAFONE HUTCHISON AUSTRALIA PTY LIMITED/OU=Technology Shared Services/CN=mybill.vodafone.com.au */
1914 /* issuer :/C=UK/O=Vodafone Group/CN=Vodafone (Corporate Services 2009) */
1915 /* Not After : May 26 09:37:50 2017 GMT */
1916 static const uint8_t vodafone
[] = {
1917 0xde, 0x77, 0x63, 0x97, 0x79, 0x47, 0xee, 0x6e, 0xc1, 0x3a,
1918 0x7b, 0x3b, 0xad, 0x43, 0x88, 0xa9, 0x66, 0x59, 0xa8, 0x18
1921 CFDataRef leafFingerprint
= SecCertificateGetSHA1Digest(leaf
);
1922 require_quiet(leafFingerprint
, out
);
1923 const unsigned int len
= 20;
1924 const uint8_t *dp
= CFDataGetBytePtr(leafFingerprint
);
1925 if (dp
&& (!memcmp(vodafone
, dp
, len
))) {
1933 static bool SecPVCKeyIsConstraintPolicyOption(SecPVCRef pvc
, CFStringRef key
);
1935 static void SecPolicyCheckSystemTrustedWeakHash(SecPVCRef pvc
,
1937 CFIndex ix
, count
= SecPVCGetCertificateCount(pvc
);
1939 Boolean keyInPolicy
= false;
1940 CFArrayRef policies
= pvc
->policies
;
1941 CFIndex policyIX
, policyCount
= CFArrayGetCount(policies
);
1942 for (policyIX
= 0; policyIX
< policyCount
; ++policyIX
) {
1943 SecPolicyRef policy
= (SecPolicyRef
)CFArrayGetValueAtIndex(policies
, policyIX
);
1944 if (policy
&& CFDictionaryContainsKey(policy
->_options
, key
)) {
1949 /* We only enforce this check when *both* of the following are true:
1950 * 1. One of the certs in the path has this usage constraint, and
1951 * 2. One of the policies in the PVC has this key
1952 * (As compared to normal policy options which require only one to be true..) */
1953 require_quiet(SecPVCKeyIsConstraintPolicyOption(pvc
, key
) &&
1956 /* Ignore the anchor if it's trusted */
1957 if (SecPathBuilderIsAnchored(pvc
->builder
)) {
1960 for (ix
= 0; ix
< count
; ++ix
) {
1961 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, ix
);
1962 if (SecCertificateIsWeakHash(cert
)) {
1963 if (!leaf_is_on_weak_hash_whitelist(pvc
)) {
1964 if (!SecPVCSetResult(pvc
, key
, ix
, kCFBooleanFalse
)) {
1974 static void SecPolicyCheckSystemTrustedWeakKey(SecPVCRef pvc
,
1976 CFIndex ix
, count
= SecPVCGetCertificateCount(pvc
);
1978 Boolean keyInPolicy
= false;
1979 CFArrayRef policies
= pvc
->policies
;
1980 CFIndex policyIX
, policyCount
= CFArrayGetCount(policies
);
1981 for (policyIX
= 0; policyIX
< policyCount
; ++policyIX
) {
1982 SecPolicyRef policy
= (SecPolicyRef
)CFArrayGetValueAtIndex(policies
, policyIX
);
1983 if (policy
&& CFDictionaryContainsKey(policy
->_options
, key
)) {
1988 /* We only enforce this check when *both* of the following are true:
1989 * 1. One of the certs in the path has this usage constraint, and
1990 * 2. One of the policies in the PVC has this key
1991 * (As compared to normal policy options which require only one to be true..) */
1992 require_quiet(SecPVCKeyIsConstraintPolicyOption(pvc
, key
) &&
1995 /* Ignore the anchor if it's trusted */
1996 if (SecPathBuilderIsAnchored(pvc
->builder
)) {
1999 for (ix
= 0; ix
< count
; ++ix
) {
2000 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, ix
);
2001 if (!SecCertificateIsStrongKey(cert
)) {
2002 if (!SecPVCSetResult(pvc
, key
, ix
, kCFBooleanFalse
)) {
2012 static void SecPolicyCheckPinningRequired(SecPVCRef pvc
, CFStringRef key
) {
2013 /* Pinning is disabled on the system, skip. */
2014 if (SecIsInternalRelease()) {
2015 if (CFPreferencesGetAppBooleanValue(CFSTR("AppleServerAuthenticationNoPinning"),
2016 CFSTR("com.apple.security"), NULL
)) {
2021 CFArrayRef policies
= pvc
->policies
;
2022 CFIndex policyIX
, policyCount
= CFArrayGetCount(policies
);
2023 for (policyIX
= 0; policyIX
< policyCount
; ++policyIX
) {
2024 SecPolicyRef policy
= (SecPolicyRef
)CFArrayGetValueAtIndex(policies
, policyIX
);
2025 CFStringRef policyName
= SecPolicyGetName(policy
);
2026 if (CFEqualSafe(policyName
, kSecPolicyNameSSLServer
)) {
2027 /* policy required pinning, but we didn't use a pinning policy */
2028 if (!SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
)) {
2035 void SecPolicyServerInitialize(void) {
2036 gSecPolicyLeafCallbacks
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0,
2037 &kCFTypeDictionaryKeyCallBacks
, NULL
);
2038 gSecPolicyPathCallbacks
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0,
2039 &kCFTypeDictionaryKeyCallBacks
, NULL
);
2041 #undef POLICYCHECKMACRO
2042 #define __PC_ADD_CHECK_(NAME)
2043 #define __PC_ADD_CHECK_L(NAME) CFDictionaryAddValue(gSecPolicyLeafCallbacks, kSecPolicyCheck##NAME, SecPolicyCheck##NAME);
2044 #define __PC_ADD_CHECK_A(NAME) CFDictionaryAddValue(gSecPolicyPathCallbacks, kSecPolicyCheck##NAME, SecPolicyCheck##NAME);
2046 #define POLICYCHECKMACRO(NAME, TRUSTRESULT, SUBTYPE, LEAFCHECK, PATHCHECK, LEAFONLY, CSSMERR, OSSTATUS) \
2047 __PC_ADD_CHECK_##LEAFCHECK(NAME) \
2048 __PC_ADD_CHECK_##PATHCHECK(NAME)
2049 #include "../Security/SecPolicyChecks.list"
2051 /* Some of these don't follow the naming conventions but are in the Pinning DB.
2052 * <rdar://34537018> fix policy check constant values */
2053 CFDictionaryAddValue(gSecPolicyLeafCallbacks
, CFSTR("CheckLeafMarkerOid"), SecPolicyCheckLeafMarkerOid
);
2054 CFDictionaryAddValue(gSecPolicyLeafCallbacks
, CFSTR("CheckLeafMarkersProdAndQA"), SecPolicyCheckLeafMarkersProdAndQA
);
2055 CFDictionaryAddValue(gSecPolicyPathCallbacks
, CFSTR("CheckIntermediateMarkerOid"), SecPolicyCheckIntermediateMarkerOid
);
2056 CFDictionaryAddValue(gSecPolicyPathCallbacks
, CFSTR("CheckIntermediateCountry"), SecPolicyCheckIntermediateCountry
);
2057 CFDictionaryAddValue(gSecPolicyPathCallbacks
, CFSTR("CheckIntermediateOrganization"), SecPolicyCheckIntermediateOrganization
);
2062 /********************************************************
2063 ****************** SecPVCRef Functions *****************
2064 ********************************************************/
2066 void SecPVCInit(SecPVCRef pvc
, SecPathBuilderRef builder
, CFArrayRef policies
) {
2067 secdebug("alloc", "%p", pvc
);
2068 // Weird logging policies crashes.
2069 //secdebug("policy", "%@", policies);
2071 // Zero the pvc struct so only non-zero fields need to be explicitly set
2072 memset(pvc
, 0, sizeof(struct OpaqueSecPVC
));
2073 pvc
->builder
= builder
;
2074 pvc
->policies
= policies
;
2077 pvc
->result
= kSecTrustResultUnspecified
;
2079 CFMutableDictionaryRef certDetail
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0,
2080 &kCFTypeDictionaryKeyCallBacks
,
2081 &kCFTypeDictionaryValueCallBacks
);
2082 pvc
->leafDetails
= CFArrayCreate(kCFAllocatorDefault
, (const void **)&certDetail
,
2083 1, &kCFTypeArrayCallBacks
);
2084 CFRelease(certDetail
);
2087 void SecPVCDelete(SecPVCRef pvc
) {
2088 secdebug("alloc", "%p", pvc
);
2089 CFReleaseNull(pvc
->policies
);
2090 CFReleaseNull(pvc
->details
);
2091 CFReleaseNull(pvc
->leafDetails
);
2094 void SecPVCSetPath(SecPVCRef pvc
, SecCertificatePathVCRef path
) {
2095 secdebug("policy", "%@", path
);
2097 pvc
->result
= kSecTrustResultUnspecified
;
2098 CFReleaseNull(pvc
->details
);
2101 void SecPVCComputeDetails(SecPVCRef pvc
, SecCertificatePathVCRef path
) {
2104 /* Since we don't run the LeafChecks again, we need to preserve the
2105 * result the leaf had. */
2106 CFIndex ix
, pathLength
= SecCertificatePathVCGetCount(path
);
2107 CFMutableArrayRef details
= CFArrayCreateMutableCopy(kCFAllocatorDefault
,
2108 pathLength
, pvc
->leafDetails
);
2109 for (ix
= 1; ix
< pathLength
; ++ix
) {
2110 CFMutableDictionaryRef certDetail
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0,
2111 &kCFTypeDictionaryKeyCallBacks
,
2112 &kCFTypeDictionaryValueCallBacks
);
2113 CFArrayAppendValue(details
, certDetail
);
2114 CFRelease(certDetail
);
2116 CFRetainAssign(pvc
->details
, details
);
2117 pvc
->result
= pvc
->leafResult
;
2118 CFReleaseSafe(details
);
2121 SecPolicyRef
SecPVCGetPolicy(SecPVCRef pvc
) {
2122 return (SecPolicyRef
)CFArrayGetValueAtIndex(pvc
->policies
, pvc
->policyIX
);
2125 static CFIndex
SecPVCGetCertificateCount(SecPVCRef pvc
) {
2126 return SecPathBuilderGetCertificateCount(pvc
->builder
);
2129 static SecCertificateRef
SecPVCGetCertificateAtIndex(SecPVCRef pvc
, CFIndex ix
) {
2130 return SecPathBuilderGetCertificateAtIndex(pvc
->builder
, ix
);
2133 static CFAbsoluteTime
SecPVCGetVerifyTime(SecPVCRef pvc
) {
2134 return SecPathBuilderGetVerifyTime(pvc
->builder
);
2137 static bool SecPVCIsExceptedError(SecPVCRef pvc
, CFIndex ix
, CFStringRef key
, CFTypeRef value
) {
2138 CFArrayRef exceptions
= SecPathBuilderGetExceptions(pvc
->builder
);
2139 if (!exceptions
) { return false; }
2140 CFIndex exceptionsCount
= CFArrayGetCount(exceptions
);
2142 /* There are two types of exceptions:
2143 * 1. Those that are built from SecTrustCopyExceptions, which are particular to the
2144 * certs in the chain -- as indicated by the SHA1 digest in the exception dictionary.
2145 * 2. On macOS, those built from SecTrustSetOptions, which are generic excepted errors.
2148 CFDictionaryRef options
= CFArrayGetValueAtIndex(exceptions
, 0);
2150 if (exceptionsCount
== 1 && (ix
> 0 || !CFDictionaryContainsKey(options
, kSecCertificateDetailSHA1Digest
))) {
2151 /* SHA1Digest not allowed */
2152 if (CFDictionaryContainsKey(options
, kSecCertificateDetailSHA1Digest
)) { return false; }
2154 if (CFDictionaryContainsKey(options
, key
)) {
2155 /* Special case -- AnchorTrusted only for self-signed certs */
2156 if (CFEqual(kSecPolicyCheckAnchorTrusted
, key
)) {
2157 Boolean isSelfSigned
= false;
2158 SecCertificateRef cert
= SecPathBuilderGetCertificateAtIndex(pvc
->builder
, ix
);
2159 if (!cert
|| (errSecSuccess
!= SecCertificateIsSelfSigned(cert
, &isSelfSigned
)) || !isSelfSigned
) {
2164 } else if (CFEqual(key
, kSecPolicyCheckTemporalValidity
) && CFDictionaryContainsKey(options
, kSecPolicyCheckValidRoot
)) {
2165 /* Another special case - ValidRoot excepts Valid only for self-signed certs */
2166 Boolean isSelfSigned
= false;
2167 SecCertificateRef cert
= SecPathBuilderGetCertificateAtIndex(pvc
->builder
, ix
);
2168 if (!cert
|| (errSecSuccess
!= SecCertificateIsSelfSigned(cert
, &isSelfSigned
)) || !isSelfSigned
) {
2177 if (ix
>= exceptionsCount
) { return false; }
2178 CFDictionaryRef exception
= CFArrayGetValueAtIndex(exceptions
, ix
);
2180 /* Compare the cert hash */
2181 if (!CFDictionaryContainsKey(exception
, kSecCertificateDetailSHA1Digest
)) { return false; }
2182 SecCertificateRef cert
= SecPathBuilderGetCertificateAtIndex(pvc
->builder
, ix
);
2183 if (!CFEqual(SecCertificateGetSHA1Digest(cert
), CFDictionaryGetValue(exception
, kSecCertificateDetailSHA1Digest
))) {
2188 CFTypeRef exceptionValue
= CFDictionaryGetValue(exception
, key
);
2189 if (exceptionValue
&& CFEqual(value
, exceptionValue
)) {
2190 /* Only change result if PVC is already ok */
2191 if (SecPVCIsOkResult(pvc
)) {
2192 // Chains that pass due to exceptions get Proceed result.
2193 pvc
->result
= kSecTrustResultProceed
;
2201 static int32_t detailKeyToCssmErr(CFStringRef key
) {
2204 if (CFEqual(key
, kSecPolicyCheckSSLHostname
)) {
2205 result
= -2147408896; // CSSMERR_APPLETP_HOSTNAME_MISMATCH
2207 else if (CFEqual(key
, kSecPolicyCheckEmail
)) {
2208 result
= -2147408872; // CSSMERR_APPLETP_SMIME_EMAIL_ADDRS_NOT_FOUND
2210 else if (CFEqual(key
, kSecPolicyCheckTemporalValidity
)) {
2211 result
= -2147409654; // CSSMERR_TP_CERT_EXPIRED
2217 static bool SecPVCMeetsConstraint(SecPVCRef pvc
, SecCertificateRef certificate
, CFDictionaryRef constraint
);
2219 static bool SecPVCIsAllowedError(SecPVCRef pvc
, CFIndex ix
, CFStringRef key
) {
2220 bool result
= false;
2221 SecCertificatePathVCRef path
= SecPathBuilderGetPath(pvc
->builder
);
2222 CFArrayRef constraints
= SecCertificatePathVCGetUsageConstraintsAtIndex(path
, ix
);
2223 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, ix
);
2224 CFIndex constraintIX
, constraintCount
= CFArrayGetCount(constraints
);
2226 for (constraintIX
= 0; constraintIX
< constraintCount
; constraintIX
++) {
2227 CFDictionaryRef constraint
= (CFDictionaryRef
)CFArrayGetValueAtIndex(constraints
, constraintIX
);
2228 CFNumberRef allowedErrorNumber
= NULL
;
2229 if (!isDictionary(constraint
)) {
2232 allowedErrorNumber
= (CFNumberRef
)CFDictionaryGetValue(constraint
, kSecTrustSettingsAllowedError
);
2233 int32_t allowedErrorValue
= 0;
2234 if (!isNumber(allowedErrorNumber
) || !CFNumberGetValue(allowedErrorNumber
, kCFNumberSInt32Type
, &allowedErrorValue
)) {
2238 if (SecPVCMeetsConstraint(pvc
, cert
, constraint
)) {
2239 if (allowedErrorValue
== detailKeyToCssmErr(key
)) {
2248 static bool SecPVCKeyIsConstraintPolicyOption(SecPVCRef pvc
, CFStringRef key
) {
2249 CFIndex certIX
, certCount
= SecPVCGetCertificateCount(pvc
);
2250 for (certIX
= 0; certIX
< certCount
; certIX
++) {
2251 SecCertificatePathVCRef path
= SecPathBuilderGetPath(pvc
->builder
);
2252 CFArrayRef constraints
= SecCertificatePathVCGetUsageConstraintsAtIndex(path
, certIX
);
2253 CFIndex constraintIX
, constraintCount
= CFArrayGetCount(constraints
);
2254 for (constraintIX
= 0; constraintIX
< constraintCount
; constraintIX
++) {
2255 CFDictionaryRef constraint
= (CFDictionaryRef
)CFArrayGetValueAtIndex(constraints
, constraintIX
);
2256 if (!isDictionary(constraint
)) {
2260 CFDictionaryRef policyOptions
= NULL
;
2261 policyOptions
= (CFDictionaryRef
)CFDictionaryGetValue(constraint
, kSecTrustSettingsPolicyOptions
);
2262 if (policyOptions
&& isDictionary(policyOptions
) &&
2263 CFDictionaryContainsKey(policyOptions
, key
)) {
2271 static SecTrustResultType
trust_result_for_key(CFStringRef key
) {
2272 SecTrustResultType result
= kSecTrustResultRecoverableTrustFailure
;
2273 #undef POLICYCHECKMACRO
2274 #define __PC_TYPE_MEMBER_ false
2275 #define __PC_TYPE_MEMBER_R false
2276 #define __PC_TYPE_MEMBER_F true
2277 #define __PC_TYPE_MEMBER_D true
2279 #define __TRUSTRESULT_ kSecTrustResultRecoverableTrustFailure
2280 #define __TRUSTRESULT_F kSecTrustResultFatalTrustFailure
2281 #define __TRUSTRESULT_D kSecTrustResultDeny
2282 #define __TRUSTRESULT_R kSecTrustResultRecoverableTrustFailure
2284 #define POLICYCHECKMACRO(NAME, TRUSTRESULT, SUBTYPE, LEAFCHECK, PATHCHECK, LEAFONLY, CSSMERR, OSSTATUS) \
2285 if (__PC_TYPE_MEMBER_##TRUSTRESULT && CFEqual(key,CFSTR(#NAME))) { \
2286 result = __TRUSTRESULT_##TRUSTRESULT; \
2288 #include "../Security/SecPolicyChecks.list"
2293 /* AUDIT[securityd](done):
2294 policy->_options is a caller provided dictionary, only its cf type has
2297 bool SecPVCSetResultForced(SecPVCRef pvc
,
2298 CFStringRef key
, CFIndex ix
, CFTypeRef result
, bool force
) {
2300 secnotice("policy", "cert[%d]: %@ =(%s)[%s]> %@", (int) ix
, key
,
2301 (pvc
->callbacks
== gSecPolicyLeafCallbacks
? "leaf"
2302 : (pvc
->callbacks
== gSecPolicyPathCallbacks
? "path"
2304 (force
? "force" : ""), result
);
2306 /* If this is not something the current policy cares about ignore
2307 this error and return true so our caller continues evaluation. */
2309 /* Either the policy or the usage constraints have to have this key */
2310 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
2311 if (!(SecPVCKeyIsConstraintPolicyOption(pvc
, key
) ||
2312 (policy
&& CFDictionaryContainsKey(policy
->_options
, key
)))) {
2317 /* Check to see if the SecTrustSettings for the certificate in question
2318 tell us to ignore this error. */
2319 if (SecPVCIsAllowedError(pvc
, ix
, key
)) {
2320 secinfo("policy", "cert[%d]: skipped allowed error %@", (int) ix
, key
);
2324 /* Check to see if exceptions tells us to ignore this error. */
2325 if (SecPVCIsExceptedError(pvc
, ix
, key
, result
)) {
2326 secinfo("policy", "cert[%d]: skipped exception error %@", (int) ix
, key
);
2330 /* Avoid resetting deny or fatal to recoverable */
2331 SecTrustResultType trustResult
= trust_result_for_key(key
);
2332 if (SecPVCIsOkResult(pvc
) || trustResult
== kSecTrustResultFatalTrustFailure
) {
2333 pvc
->result
= trustResult
;
2334 } else if (trustResult
== kSecTrustResultDeny
&&
2335 pvc
->result
== kSecTrustResultRecoverableTrustFailure
) {
2336 pvc
->result
= trustResult
;
2342 CFMutableDictionaryRef detail
=
2343 (CFMutableDictionaryRef
)CFArrayGetValueAtIndex(pvc
->details
, ix
);
2345 /* Perhaps detail should have an array of results per key? As it stands
2346 in the case of multiple policy failures the last failure stands. */
2347 CFDictionarySetValue(detail
, key
, result
);
2352 bool SecPVCSetResult(SecPVCRef pvc
,
2353 CFStringRef key
, CFIndex ix
, CFTypeRef result
) {
2354 return SecPVCSetResultForced(pvc
, key
, ix
, result
, false);
2357 /* AUDIT[securityd](done):
2358 key(ok) is a caller provided.
2359 value(ok, unused) is a caller provided.
2361 static void SecPVCValidateKey(const void *key
, const void *value
,
2363 SecPVCRef pvc
= (SecPVCRef
)context
;
2365 /* If our caller doesn't want full details and we failed earlier there is
2366 no point in doing additional checks. */
2367 if (!SecPVCIsOkResult(pvc
) && !pvc
->details
)
2370 SecPolicyCheckFunction fcn
= (SecPolicyCheckFunction
)
2371 CFDictionaryGetValue(pvc
->callbacks
, key
);
2374 /* "Optional" policy checks. This may be a new key from the
2375 * pinning DB which is not implemented in this OS version. Log a
2376 * warning, and on debug builds fail evaluation, to encourage us
2377 * to ensure that checks are synchronized across the same build. */
2378 if (pvc
->callbacks
== gSecPolicyLeafCallbacks
) {
2379 if (!CFDictionaryContainsKey(gSecPolicyPathCallbacks
, key
)) {
2380 secwarning("policy: unknown policy key %@, skipping", key
);
2382 pvc
->result
= kSecTrustResultOtherError
;
2385 } else if (pvc
->callbacks
== gSecPolicyPathCallbacks
) {
2386 if (!CFDictionaryContainsKey(gSecPolicyLeafCallbacks
, key
)) {
2387 secwarning("policy: unknown policy key %@, skipping", key
);
2389 pvc
->result
= kSecTrustResultOtherError
;
2393 /* Non standard validation phase, nothing is optional. */
2394 pvc
->result
= kSecTrustResultOtherError
;
2399 fcn(pvc
, (CFStringRef
)key
);
2402 /* AUDIT[securityd](done):
2403 policy->_options is a caller provided dictionary, only its cf type has
2406 SecTrustResultType
SecPVCLeafChecks(SecPVCRef pvc
) {
2407 /* We need to compute details for the leaf. */
2408 CFRetainAssign(pvc
->details
, pvc
->leafDetails
);
2410 CFArrayRef policies
= pvc
->policies
;
2411 CFIndex ix
, count
= CFArrayGetCount(policies
);
2412 for (ix
= 0; ix
< count
; ++ix
) {
2413 SecPolicyRef policy
= (SecPolicyRef
)CFArrayGetValueAtIndex(policies
, ix
);
2415 /* Validate all keys for all policies. */
2416 pvc
->callbacks
= gSecPolicyLeafCallbacks
;
2417 CFDictionaryApplyFunction(policy
->_options
, SecPVCValidateKey
, pvc
);
2420 pvc
->leafResult
= pvc
->result
;
2421 CFRetainAssign(pvc
->leafDetails
, pvc
->details
);
2426 bool SecPVCIsOkResult(SecPVCRef pvc
) {
2427 if (pvc
->result
== kSecTrustResultRecoverableTrustFailure
||
2428 pvc
->result
== kSecTrustResultDeny
||
2429 pvc
->result
== kSecTrustResultFatalTrustFailure
||
2430 pvc
->result
== kSecTrustResultOtherError
) {
2436 bool SecPVCParentCertificateChecks(SecPVCRef pvc
, CFIndex ix
) {
2437 /* Check stuff common to intermediate and anchors. */
2438 CFAbsoluteTime verifyTime
= SecPVCGetVerifyTime(pvc
);
2439 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, ix
);
2440 CFIndex anchor_ix
= SecPVCGetCertificateCount(pvc
) - 1;
2441 bool is_anchor
= (ix
== anchor_ix
&& SecPathBuilderIsAnchored(pvc
->builder
));
2443 if (!SecCertificateIsValid(cert
, verifyTime
)) {
2444 /* Certificate has expired. */
2445 if (!SecPVCSetResult(pvc
, kSecPolicyCheckTemporalValidity
, ix
, kCFBooleanFalse
)) {
2450 if (SecCertificateIsWeakKey(cert
)) {
2451 /* Certificate uses weak key. */
2452 if (!SecPVCSetResult(pvc
, kSecPolicyCheckWeakKeySize
, ix
, kCFBooleanFalse
)) {
2457 if (!SecPolicyCheckCertWeakSignature(cert
, NULL
)) {
2458 /* Certificate uses weak hash. */
2459 if (!SecPVCSetResult(pvc
, kSecPolicyCheckWeakSignature
, ix
, kCFBooleanFalse
)) {
2465 /* Perform anchor specific checks. */
2466 /* Don't think we have any of these. */
2468 /* Perform intermediate specific checks. */
2470 /* (k) Basic constraints only relevant for v3 and later. */
2471 if (SecCertificateVersion(cert
) >= 3) {
2472 const SecCEBasicConstraints
*bc
=
2473 SecCertificateGetBasicConstraints(cert
);
2475 /* Basic constraints not present, illegal. */
2476 if (!SecPVCSetResultForced(pvc
, kSecPolicyCheckBasicConstraints
,
2477 ix
, kCFBooleanFalse
, true)) {
2480 } else if (!bc
->isCA
) {
2481 /* Basic constraints not marked as isCA, illegal. */
2482 if (!SecPVCSetResultForced(pvc
, kSecPolicyCheckBasicConstraintsCA
,
2483 ix
, kCFBooleanFalse
, true)) {
2488 /* For a v1 or v2 certificate in an intermediate slot (not a leaf and
2489 not an anchor), we additionally require that the certificate chain
2490 does not end in a v3 or later anchor. [rdar://32204517] */
2491 else if (ix
> 0 && ix
< anchor_ix
) {
2492 SecCertificateRef anchor
= SecPVCGetCertificateAtIndex(pvc
, anchor_ix
);
2493 if (SecCertificateVersion(anchor
) >= 3) {
2494 if (!SecPVCSetResultForced(pvc
, kSecPolicyCheckBasicConstraints
,
2495 ix
, kCFBooleanFalse
, true)) {
2500 /* (l) max_path_length is checked elsewhere. */
2502 /* (n) If a key usage extension is present, verify that the keyCertSign bit is set. */
2503 SecKeyUsage keyUsage
= SecCertificateGetKeyUsage(cert
);
2504 if (keyUsage
&& !(keyUsage
& kSecKeyUsageKeyCertSign
)) {
2505 if (!SecPVCSetResultForced(pvc
, kSecPolicyCheckKeyUsage
,
2506 ix
, kCFBooleanFalse
, true)) {
2513 return SecPVCIsOkResult(pvc
);
2516 static bool SecPVCBlackListedKeyChecks(SecPVCRef pvc
, CFIndex ix
) {
2517 /* Check stuff common to intermediate and anchors. */
2519 SecOTAPKIRef otapkiRef
= SecOTAPKICopyCurrentOTAPKIRef();
2520 if (NULL
!= otapkiRef
)
2522 CFSetRef blackListedKeys
= SecOTAPKICopyBlackListSet(otapkiRef
);
2523 CFRelease(otapkiRef
);
2524 if (NULL
!= blackListedKeys
)
2526 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, ix
);
2527 CFIndex count
= SecPVCGetCertificateCount(pvc
);
2528 bool is_last
= (ix
== count
- 1);
2529 bool is_anchor
= (is_last
&& SecPathBuilderIsAnchored(pvc
->builder
));
2531 /* Check for blacklisted intermediate issuer keys. */
2532 CFDataRef dgst
= SecCertificateCopyPublicKeySHA1Digest(cert
);
2534 /* Check dgst against blacklist. */
2535 if (CFSetContainsValue(blackListedKeys
, dgst
)) {
2536 /* Check allow list for this blacklisted issuer key,
2537 which is the authority key of the issued cert at ix-1.
2539 SecCertificatePathVCRef path
= SecPathBuilderGetPath(pvc
->builder
);
2540 bool allowed
= path
&& SecCertificatePathVCIsAllowlisted(path
);
2542 SecPVCSetResultForced(pvc
, kSecPolicyCheckBlackListedKey
,
2543 ix
, kCFBooleanFalse
, true);
2549 CFRelease(blackListedKeys
);
2550 return SecPVCIsOkResult(pvc
);
2557 static bool SecPVCGrayListedKeyChecks(SecPVCRef pvc
, CFIndex ix
)
2559 /* Check stuff common to intermediate and anchors. */
2560 SecOTAPKIRef otapkiRef
= SecOTAPKICopyCurrentOTAPKIRef();
2561 if (NULL
!= otapkiRef
)
2563 CFSetRef grayListKeys
= SecOTAPKICopyGrayList(otapkiRef
);
2564 CFRelease(otapkiRef
);
2565 if (NULL
!= grayListKeys
)
2567 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, ix
);
2568 CFIndex count
= SecPVCGetCertificateCount(pvc
);
2569 bool is_last
= (ix
== count
- 1);
2570 bool is_anchor
= (is_last
&& SecPathBuilderIsAnchored(pvc
->builder
));
2572 /* Check for gray listed intermediate issuer keys. */
2573 CFDataRef dgst
= SecCertificateCopyPublicKeySHA1Digest(cert
);
2575 /* Check dgst against gray list. */
2576 if (CFSetContainsValue(grayListKeys
, dgst
)) {
2577 /* Check allow list for this graylisted issuer key,
2578 which is the authority key of the issued cert at ix-1.
2580 SecCertificatePathVCRef path
= SecPathBuilderGetPath(pvc
->builder
);
2581 bool allowed
= path
&& SecCertificatePathVCIsAllowlisted(path
);
2583 SecPVCSetResultForced(pvc
, kSecPolicyCheckGrayListedKey
,
2584 ix
, kCFBooleanFalse
, true);
2590 CFRelease(grayListKeys
);
2591 return SecPVCIsOkResult(pvc
);
2598 static bool SecPVCContainsPolicy(SecPVCRef pvc
, CFStringRef searchOid
, CFStringRef searchName
, CFIndex
*policyIX
) {
2599 if (!isString(searchName
) && !isString(searchOid
)) {
2602 CFArrayRef policies
= pvc
->policies
;
2603 CFIndex ix
, count
= CFArrayGetCount(policies
);
2604 for (ix
= 0; ix
< count
; ++ix
) {
2605 SecPolicyRef policy
= (SecPolicyRef
)CFArrayGetValueAtIndex(policies
, ix
);
2606 CFStringRef policyName
= SecPolicyGetName(policy
);
2607 CFStringRef policyOid
= SecPolicyGetOidString(policy
);
2608 /* Prefer a match of both name and OID */
2609 if (searchOid
&& searchName
&& policyOid
&& policyName
) {
2610 if (CFEqual(searchOid
, policyOid
) &&
2611 CFEqual(searchName
, policyName
)) {
2612 if (policyIX
) { *policyIX
= ix
; }
2615 /* <rdar://40617139> sslServer trust settings need to apply to evals using policyName pinning
2616 * but make sure we don't use this for SSL Client trust settings or policies. */
2617 if (CFEqual(searchOid
, policyOid
) &&
2618 CFEqual(searchName
, kSecPolicyNameSSLServer
) && !CFEqual(policyName
, kSecPolicyNameSSLClient
)) {
2619 if (policyIX
) { *policyIX
= ix
; }
2623 /* Next best is just OID. */
2624 if (!searchName
&& searchOid
&& policyOid
) {
2625 if (CFEqual(searchOid
, policyOid
)) {
2626 if (policyIX
) { *policyIX
= ix
; }
2630 if (!searchOid
&& searchName
&& policyName
) {
2631 if (CFEqual(searchName
, policyName
)) {
2632 if (policyIX
) { *policyIX
= ix
; }
2640 static bool SecPVCContainsString(SecPVCRef pvc
, CFIndex policyIX
, CFStringRef stringValue
) {
2641 if (!isString(stringValue
)) {
2644 bool result
= false;
2646 CFStringRef tmpStringValue
= NULL
;
2647 if (CFStringGetCharacterAtIndex(stringValue
, CFStringGetLength(stringValue
) -1) == (UniChar
)0x0000) {
2648 tmpStringValue
= CFStringCreateTruncatedCopy(stringValue
, CFStringGetLength(stringValue
) - 1);
2650 tmpStringValue
= CFStringCreateCopy(NULL
, stringValue
);
2652 if (policyIX
>= 0 && policyIX
< CFArrayGetCount(pvc
->policies
)) {
2653 SecPolicyRef policy
= (SecPolicyRef
)CFArrayGetValueAtIndex(pvc
->policies
, policyIX
);
2654 /* Have to look for all the possible locations of name string */
2655 CFStringRef policyString
= NULL
;
2656 policyString
= CFDictionaryGetValue(policy
->_options
, kSecPolicyCheckSSLHostname
);
2657 if (!policyString
) {
2658 policyString
= CFDictionaryGetValue(policy
->_options
, kSecPolicyCheckEmail
);
2660 if (policyString
&& (CFStringCompare(tmpStringValue
, policyString
, kCFCompareCaseInsensitive
) == kCFCompareEqualTo
)) {
2665 CFArrayRef policyStrings
= NULL
;
2666 policyStrings
= CFDictionaryGetValue(policy
->_options
, kSecPolicyCheckEAPTrustedServerNames
);
2667 if (policyStrings
&& CFArrayContainsValue(policyStrings
,
2668 CFRangeMake(0, CFArrayGetCount(policyStrings
)),
2676 CFReleaseNull(tmpStringValue
);
2681 static uint32_t ts_key_usage_for_kuNumber(CFNumberRef keyUsageNumber
) {
2682 uint32_t ourTSKeyUsage
= 0;
2683 uint32_t keyUsage
= 0;
2684 if (keyUsageNumber
&&
2685 CFNumberGetValue(keyUsageNumber
, kCFNumberSInt32Type
, &keyUsage
)) {
2686 if (keyUsage
& kSecKeyUsageDigitalSignature
) {
2687 ourTSKeyUsage
|= kSecTrustSettingsKeyUseSignature
;
2689 if (keyUsage
& kSecKeyUsageDataEncipherment
) {
2690 ourTSKeyUsage
|= kSecTrustSettingsKeyUseEnDecryptData
;
2692 if (keyUsage
& kSecKeyUsageKeyEncipherment
) {
2693 ourTSKeyUsage
|= kSecTrustSettingsKeyUseEnDecryptKey
;
2695 if (keyUsage
& kSecKeyUsageKeyAgreement
) {
2696 ourTSKeyUsage
|= kSecTrustSettingsKeyUseKeyExchange
;
2698 if (keyUsage
== kSecKeyUsageAll
) {
2699 ourTSKeyUsage
= kSecTrustSettingsKeyUseAny
;
2702 return ourTSKeyUsage
;
2705 static uint32_t ts_key_usage_for_policy(SecPolicyRef policy
) {
2706 uint32_t ourTSKeyUsage
= 0;
2707 CFTypeRef policyKeyUsageType
= NULL
;
2709 policyKeyUsageType
= (CFTypeRef
)CFDictionaryGetValue(policy
->_options
, kSecPolicyCheckKeyUsage
);
2710 if (isArray(policyKeyUsageType
)) {
2711 CFIndex ix
, count
= CFArrayGetCount(policyKeyUsageType
);
2712 for (ix
= 0; ix
< count
; ix
++) {
2713 CFNumberRef policyKeyUsageNumber
= NULL
;
2714 policyKeyUsageNumber
= (CFNumberRef
)CFArrayGetValueAtIndex(policyKeyUsageType
, ix
);
2715 ourTSKeyUsage
|= ts_key_usage_for_kuNumber(policyKeyUsageNumber
);
2717 } else if (isNumber(policyKeyUsageType
)) {
2718 ourTSKeyUsage
|= ts_key_usage_for_kuNumber(policyKeyUsageType
);
2721 return ourTSKeyUsage
;
2724 static bool SecPVCContainsTrustSettingsKeyUsage(SecPVCRef pvc
,
2725 SecCertificateRef certificate
, CFIndex policyIX
, CFNumberRef keyUsageNumber
) {
2726 int64_t keyUsageValue
= 0;
2727 uint32_t ourKeyUsage
= 0;
2729 if (!isNumber(keyUsageNumber
) || !CFNumberGetValue(keyUsageNumber
, kCFNumberSInt64Type
, &keyUsageValue
)) {
2733 if (keyUsageValue
== kSecTrustSettingsKeyUseAny
) {
2737 /* We're using the key for revocation if we have the OCSPSigner policy.
2738 * @@@ If we support CRLs, we'd need to check for that policy here too.
2740 if (SecPVCContainsPolicy(pvc
, kSecPolicyAppleOCSPSigner
, NULL
, NULL
)) {
2741 ourKeyUsage
|= kSecTrustSettingsKeyUseSignRevocation
;
2744 /* We're using the key for verifying a cert if it's a root/intermediate
2745 * in the chain. If the cert isn't in the path yet, we're about to add it,
2746 * so it's a root/intermediate. If there is no path, this is the leaf.
2748 CFIndex pathIndex
= -1;
2749 SecCertificatePathVCRef path
= SecPathBuilderGetPath(pvc
->builder
);
2751 pathIndex
= SecCertificatePathVCGetIndexOfCertificate(path
, certificate
);
2755 if (pathIndex
!= 0) {
2756 ourKeyUsage
|= kSecTrustSettingsKeyUseSignCert
;
2759 /* The rest of the key usages may be specified by the policy(ies). */
2760 if (policyIX
>= 0 && policyIX
< CFArrayGetCount(pvc
->policies
)) {
2761 SecPolicyRef policy
= (SecPolicyRef
)CFArrayGetValueAtIndex(pvc
->policies
, policyIX
);
2762 ourKeyUsage
|= ts_key_usage_for_policy(policy
);
2764 /* Get key usage from ALL policies */
2765 CFIndex ix
, count
= CFArrayGetCount(pvc
->policies
);
2766 for (ix
= 0; ix
< count
; ix
++) {
2767 SecPolicyRef policy
= (SecPolicyRef
)CFArrayGetValueAtIndex(pvc
->policies
, ix
);
2768 ourKeyUsage
|= ts_key_usage_for_policy(policy
);
2772 if (ourKeyUsage
== (uint32_t)(keyUsageValue
& 0x00ffffffff)) {
2780 #include <Security/SecTrustedApplicationPriv.h>
2781 #include <Security/SecTask.h>
2782 #include <Security/SecTaskPriv.h>
2783 #include <bsm/libbsm.h>
2784 #include <libproc.h>
2786 extern OSStatus
SecTaskValidateForRequirement(SecTaskRef task
, CFStringRef requirement
);
2788 static bool SecPVCCallerIsApplication(CFDataRef clientAuditToken
, CFTypeRef appRef
) {
2789 bool result
= false;
2790 audit_token_t auditToken
= {};
2791 SecTaskRef task
= NULL
;
2792 SecRequirementRef requirement
= NULL
;
2793 CFStringRef stringRequirement
= NULL
;
2795 require(appRef
&& clientAuditToken
, out
);
2796 require(CFGetTypeID(appRef
) == SecTrustedApplicationGetTypeID(), out
);
2797 require_noerr(SecTrustedApplicationCopyRequirement((SecTrustedApplicationRef
)appRef
, &requirement
), out
);
2798 require(requirement
, out
);
2799 require_noerr(SecRequirementsCopyString(requirement
, kSecCSDefaultFlags
, &stringRequirement
), out
);
2800 require(stringRequirement
, out
);
2802 require(sizeof(auditToken
) == CFDataGetLength(clientAuditToken
), out
);
2803 CFDataGetBytes(clientAuditToken
, CFRangeMake(0, sizeof(auditToken
)), (uint8_t *)&auditToken
);
2804 require(task
= SecTaskCreateWithAuditToken(NULL
, auditToken
), out
);
2806 if(errSecSuccess
== SecTaskValidateForRequirement(task
, stringRequirement
)) {
2811 CFReleaseNull(task
);
2812 CFReleaseNull(requirement
);
2813 CFReleaseNull(stringRequirement
);
2818 static bool SecPVCContainsTrustSettingsPolicyOption(SecPVCRef pvc
, CFDictionaryRef options
) {
2819 if (!isDictionary(options
)) {
2824 CFDictionaryRef currentCallbacks
= pvc
->callbacks
;
2826 /* We need to run the leaf and path checks using these options. */
2827 pvc
->callbacks
= gSecPolicyLeafCallbacks
;
2828 CFDictionaryApplyFunction(options
, SecPVCValidateKey
, pvc
);
2830 pvc
->callbacks
= gSecPolicyPathCallbacks
;
2831 CFDictionaryApplyFunction(options
, SecPVCValidateKey
, pvc
);
2834 pvc
->callbacks
= currentCallbacks
;
2836 /* Our work here is done; no need to claim a match */
2840 static bool SecPVCMeetsConstraint(SecPVCRef pvc
, SecCertificateRef certificate
, CFDictionaryRef constraint
) {
2841 CFStringRef policyOid
= NULL
, policyString
= NULL
, policyName
= NULL
;
2842 CFNumberRef keyUsageNumber
= NULL
;
2843 CFTypeRef trustedApplicationData
= NULL
;
2844 CFDictionaryRef policyOptions
= NULL
;
2846 bool policyMatch
= false, policyStringMatch
= false, applicationMatch
= false ,
2847 keyUsageMatch
= false, policyOptionMatch
= false;
2848 bool result
= false;
2850 #if TARGET_OS_MAC && !TARGET_OS_IPHONE
2851 /* OS X returns a SecPolicyRef in the constraints. Convert to the oid string. */
2852 SecPolicyRef policy
= NULL
;
2853 policy
= (SecPolicyRef
)CFDictionaryGetValue(constraint
, kSecTrustSettingsPolicy
);
2854 policyOid
= (policy
) ? policy
->_oid
: NULL
;
2856 policyOid
= (CFStringRef
)CFDictionaryGetValue(constraint
, kSecTrustSettingsPolicy
);
2858 policyName
= (CFStringRef
)CFDictionaryGetValue(constraint
, kSecTrustSettingsPolicyName
);
2859 policyString
= (CFStringRef
)CFDictionaryGetValue(constraint
, kSecTrustSettingsPolicyString
);
2860 keyUsageNumber
= (CFNumberRef
)CFDictionaryGetValue(constraint
, kSecTrustSettingsKeyUsage
);
2861 policyOptions
= (CFDictionaryRef
)CFDictionaryGetValue(constraint
, kSecTrustSettingsPolicyOptions
);
2863 CFIndex policyIX
= -1;
2864 policyMatch
= SecPVCContainsPolicy(pvc
, policyOid
, policyName
, &policyIX
);
2865 policyStringMatch
= SecPVCContainsString(pvc
, policyIX
, policyString
);
2866 keyUsageMatch
= SecPVCContainsTrustSettingsKeyUsage(pvc
, certificate
, policyIX
, keyUsageNumber
);
2867 policyOptionMatch
= SecPVCContainsTrustSettingsPolicyOption(pvc
, policyOptions
);
2869 #if TARGET_OS_MAC && !TARGET_OS_IPHONE
2870 trustedApplicationData
= CFDictionaryGetValue(constraint
, kSecTrustSettingsApplication
);
2871 CFDataRef clientAuditToken
= SecPathBuilderCopyClientAuditToken(pvc
->builder
);
2872 applicationMatch
= SecPVCCallerIsApplication(clientAuditToken
, trustedApplicationData
);
2873 CFReleaseNull(clientAuditToken
);
2875 if(CFDictionaryContainsKey(constraint
, kSecTrustSettingsApplication
)) {
2876 secerror("kSecTrustSettingsApplication is not yet supported on this platform");
2880 /* If we either didn't find the parameter in the dictionary or we got a match
2881 * against that parameter, for all possible parameters in the dictionary, then
2882 * this trust setting result applies to the output. */
2883 if (((!policyOid
&& !policyName
) || policyMatch
) &&
2884 (!policyString
|| policyStringMatch
) &&
2885 (!trustedApplicationData
|| applicationMatch
) &&
2886 (!keyUsageNumber
|| keyUsageMatch
) &&
2887 (!policyOptions
|| policyOptionMatch
)) {
2894 SecTrustSettingsResult
SecPVCGetTrustSettingsResult(SecPVCRef pvc
, SecCertificateRef certificate
, CFArrayRef constraints
) {
2895 SecTrustSettingsResult result
= kSecTrustSettingsResultInvalid
;
2896 CFIndex constraintIX
, constraintCount
= CFArrayGetCount(constraints
);
2897 for (constraintIX
= 0; constraintIX
< constraintCount
; constraintIX
++) {
2898 CFDictionaryRef constraint
= (CFDictionaryRef
)CFArrayGetValueAtIndex(constraints
, constraintIX
);
2899 if (!isDictionary(constraint
)) {
2903 CFNumberRef resultNumber
= NULL
;
2904 resultNumber
= (CFNumberRef
)CFDictionaryGetValue(constraint
, kSecTrustSettingsResult
);
2905 uint32_t resultValue
= kSecTrustSettingsResultInvalid
;
2906 if (!isNumber(resultNumber
) || !CFNumberGetValue(resultNumber
, kCFNumberSInt32Type
, &resultValue
)) {
2907 /* no SecTrustSettingsResult entry defaults to TrustRoot*/
2908 resultValue
= kSecTrustSettingsResultTrustRoot
;
2911 if (SecPVCMeetsConstraint(pvc
, certificate
, constraint
)) {
2912 result
= resultValue
;
2919 static void SecPVCCheckUsageConstraints(SecPVCRef pvc
) {
2920 CFIndex certIX
, certCount
= SecPVCGetCertificateCount(pvc
);
2921 for (certIX
= 0; certIX
< certCount
; certIX
++) {
2922 SecCertificatePathVCRef path
= SecPathBuilderGetPath(pvc
->builder
);
2923 CFArrayRef constraints
= SecCertificatePathVCGetUsageConstraintsAtIndex(path
, certIX
);
2924 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, certIX
);
2925 SecTrustSettingsResult result
= SecPVCGetTrustSettingsResult(pvc
, cert
, constraints
);
2927 /* Set the pvc trust result based on the usage constraints and anchor source. */
2928 if (result
== kSecTrustSettingsResultDeny
) {
2929 SecPVCSetResultForced(pvc
, kSecPolicyCheckUsageConstraints
, certIX
, kCFBooleanFalse
, true);
2930 } else if ((result
== kSecTrustSettingsResultTrustRoot
|| result
== kSecTrustSettingsResultTrustAsRoot
||
2931 result
== kSecTrustSettingsResultInvalid
) && SecPVCIsOkResult(pvc
)) {
2932 /* If we already think the PVC is ok and this cert is from one of the user/
2933 * admin anchor sources, trustRoot, trustAsRoot, and Invalid (no constraints),
2934 * all mean we should use the special "Proceed" trust result. */
2935 #if TARGET_OS_IPHONE
2936 if (SecPathBuilderIsAnchorSource(pvc
->builder
, kSecUserAnchorSource
) &&
2937 SecCertificateSourceContains(kSecUserAnchorSource
, cert
)) {
2939 if (SecPathBuilderIsAnchorSource(pvc
->builder
, kSecLegacyAnchorSource
) &&
2940 SecCertificateSourceContains(kSecLegacyAnchorSource
, cert
)) {
2942 pvc
->result
= kSecTrustResultProceed
;
2948 static const UInt8 kTestDateConstraintsRoot
[kSecPolicySHA256Size
] = {
2949 0x51,0xA0,0xF3,0x1F,0xC0,0x1D,0xEC,0x87,0x32,0xB6,0xFD,0x13,0x6A,0x43,0x4D,0x6C,
2950 0x87,0xCD,0x62,0xE0,0x38,0xB4,0xFB,0xD6,0x40,0xB0,0xFD,0x62,0x4D,0x1F,0xCF,0x6D
2952 static const UInt8 kWS_CA1_G2
[kSecPolicySHA256Size
] = {
2953 0xD4,0x87,0xA5,0x6F,0x83,0xB0,0x74,0x82,0xE8,0x5E,0x96,0x33,0x94,0xC1,0xEC,0xC2,
2954 0xC9,0xE5,0x1D,0x09,0x03,0xEE,0x94,0x6B,0x02,0xC3,0x01,0x58,0x1E,0xD9,0x9E,0x16
2956 static const UInt8 kWS_CA1_NEW
[kSecPolicySHA256Size
] = {
2957 0x4B,0x22,0xD5,0xA6,0xAE,0xC9,0x9F,0x3C,0xDB,0x79,0xAA,0x5E,0xC0,0x68,0x38,0x47,
2958 0x9C,0xD5,0xEC,0xBA,0x71,0x64,0xF7,0xF2,0x2D,0xC1,0xD6,0x5F,0x63,0xD8,0x57,0x08
2960 static const UInt8 kWS_CA2_NEW
[kSecPolicySHA256Size
] = {
2961 0xD6,0xF0,0x34,0xBD,0x94,0xAA,0x23,0x3F,0x02,0x97,0xEC,0xA4,0x24,0x5B,0x28,0x39,
2962 0x73,0xE4,0x47,0xAA,0x59,0x0F,0x31,0x0C,0x77,0xF4,0x8F,0xDF,0x83,0x11,0x22,0x54
2964 static const UInt8 kWS_ECC
[kSecPolicySHA256Size
] = {
2965 0x8B,0x45,0xDA,0x1C,0x06,0xF7,0x91,0xEB,0x0C,0xAB,0xF2,0x6B,0xE5,0x88,0xF5,0xFB,
2966 0x23,0x16,0x5C,0x2E,0x61,0x4B,0xF8,0x85,0x56,0x2D,0x0D,0xCE,0x50,0xB2,0x9B,0x02
2968 static const UInt8 kSC_SFSCA
[kSecPolicySHA256Size
] = {
2969 0xC7,0x66,0xA9,0xBE,0xF2,0xD4,0x07,0x1C,0x86,0x3A,0x31,0xAA,0x49,0x20,0xE8,0x13,
2970 0xB2,0xD1,0x98,0x60,0x8C,0xB7,0xB7,0xCF,0xE2,0x11,0x43,0xB8,0x36,0xDF,0x09,0xEA
2972 static const UInt8 kSC_SHA2
[kSecPolicySHA256Size
] = {
2973 0xE1,0x78,0x90,0xEE,0x09,0xA3,0xFB,0xF4,0xF4,0x8B,0x9C,0x41,0x4A,0x17,0xD6,0x37,
2974 0xB7,0xA5,0x06,0x47,0xE9,0xBC,0x75,0x23,0x22,0x72,0x7F,0xCC,0x17,0x42,0xA9,0x11
2976 static const UInt8 kSC_G2
[kSecPolicySHA256Size
] = {
2977 0xC7,0xBA,0x65,0x67,0xDE,0x93,0xA7,0x98,0xAE,0x1F,0xAA,0x79,0x1E,0x71,0x2D,0x37,
2978 0x8F,0xAE,0x1F,0x93,0xC4,0x39,0x7F,0xEA,0x44,0x1B,0xB7,0xCB,0xE6,0xFD,0x59,0x95
2981 static void SecPVCCheckIssuerDateConstraints(SecPVCRef pvc
) {
2982 static CFSetRef sConstrainedRoots
= NULL
;
2983 static dispatch_once_t _t
;
2984 dispatch_once(&_t
, ^{
2985 const UInt8
*v_hashes
[] = {
2986 kWS_CA1_G2
, kWS_CA1_NEW
, kWS_CA2_NEW
, kWS_ECC
,
2987 kSC_SFSCA
, kSC_SHA2
, kSC_G2
, kTestDateConstraintsRoot
2989 CFMutableSetRef set
= CFSetCreateMutable(NULL
, 0, &kCFTypeSetCallBacks
);
2990 CFIndex ix
, count
= sizeof(v_hashes
)/sizeof(*v_hashes
);
2991 for (ix
=0; ix
<count
; ix
++) {
2992 CFDataRef hash
= CFDataCreateWithBytesNoCopy(NULL
, v_hashes
[ix
],
2993 kSecPolicySHA256Size
, kCFAllocatorNull
);
2995 CFSetAddValue(set
, hash
);
2999 sConstrainedRoots
= set
;
3002 bool shouldDeny
= false;
3003 CFIndex certIX
, certCount
= SecPVCGetCertificateCount(pvc
);
3004 for (certIX
= certCount
- 1; certIX
>= 0 && !shouldDeny
; certIX
--) {
3005 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, certIX
);
3006 CFDataRef sha256
= SecCertificateCopySHA256Digest(cert
);
3007 if (sha256
&& CFSetContainsValue(sConstrainedRoots
, sha256
)) {
3008 /* matched a constrained root; check notBefore dates on all its children. */
3009 CFIndex childIX
= certIX
;
3010 while (--childIX
>= 0) {
3011 SecCertificateRef child
= SecPVCGetCertificateAtIndex(pvc
, childIX
);
3012 /* 1 Dec 2016 00:00:00 GMT */
3013 if (child
&& (CFAbsoluteTime
)502243200.0 <= SecCertificateNotValidBefore(child
)) {
3014 SecPVCSetResultForced(pvc
, kSecPolicyCheckBlackListedKey
, certIX
, kCFBooleanFalse
, true);
3020 CFReleaseNull(sha256
);
3024 static bool SecPVCIsSSLServerAuthenticationPolicy(SecPVCRef pvc
) {
3025 if (!pvc
|| !pvc
->policies
) {
3028 SecPolicyRef policy
= (SecPolicyRef
)CFArrayGetValueAtIndex(pvc
->policies
, 0);
3032 CFStringRef policyName
= SecPolicyGetName(policy
);
3033 if (CFEqualSafe(policyName
, kSecPolicyNameSSLServer
)) {
3036 CFDictionaryRef options
= policy
->_options
;
3037 if (options
&& CFDictionaryGetValue(options
, kSecPolicyCheckSSLHostname
)) {
3043 /* AUDIT[securityd](done):
3044 policy->_options is a caller provided dictionary, only its cf type has
3047 void SecPVCPathChecks(SecPVCRef pvc
) {
3048 secdebug("policy", "begin path: %@", SecPathBuilderGetPath(pvc
->builder
));
3049 SecCertificatePathVCRef path
= SecPathBuilderGetPath(pvc
->builder
);
3050 /* This needs to be initialized before we call any function that might call
3051 SecPVCSetResultForced(). */
3053 SecPolicyCheckIdLinkage(pvc
, kSecPolicyCheckIdLinkage
);
3054 if (SecPVCIsOkResult(pvc
) || pvc
->details
) {
3055 SecPolicyCheckBasicCertificateProcessing(pvc
,
3056 kSecPolicyCheckBasicCertificateProcessing
);
3059 CFArrayRef policies
= pvc
->policies
;
3060 CFIndex count
= CFArrayGetCount(policies
);
3061 for (; pvc
->policyIX
< count
; ++pvc
->policyIX
) {
3062 /* Validate all keys for all policies. */
3063 pvc
->callbacks
= gSecPolicyPathCallbacks
;
3064 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
3065 CFDictionaryApplyFunction(policy
->_options
, SecPVCValidateKey
, pvc
);
3066 if (!SecPVCIsOkResult(pvc
) && !pvc
->details
)
3073 /* Check whether the TrustSettings say to deny a cert in the path. */
3074 SecPVCCheckUsageConstraints(pvc
);
3076 /* Check for Blocklisted certs */
3077 SecPVCCheckIssuerDateConstraints(pvc
);
3079 count
= SecCertificatePathVCGetCount(path
);
3080 for (ix
= 1; ix
< count
; ix
++) {
3081 SecPVCGrayListedKeyChecks(pvc
, ix
);
3082 SecPVCBlackListedKeyChecks(pvc
, ix
);
3085 /* Path-based check tests. */
3086 if (!SecCertificatePathVCIsPathValidated(path
)) {
3087 bool ev_check_ok
= false;
3088 if (SecCertificatePathVCIsOptionallyEV(path
)) {
3089 SecTrustResultType pre_ev_check_result
= pvc
->result
;
3090 SecPolicyCheckEV(pvc
, kSecPolicyCheckExtendedValidation
);
3091 ev_check_ok
= SecPVCIsOkResult(pvc
);
3092 /* If ev checking failed, we still want to accept this chain
3093 as a non EV one, if it was valid as such. */
3094 pvc
->result
= pre_ev_check_result
;
3098 /* This call will set the value of pvc->is_ct, but won't change the result (pvc->result) */
3099 SecPolicyCheckCT(pvc
);
3101 /* Certs are only EV if they are also CT verified */
3102 if (ev_check_ok
&& SecCertificatePathVCIsCT(path
)) {
3103 SecCertificatePathVCSetIsEV(path
, true);
3107 /* Check that this path meets CT constraints. */
3108 if (!SecCertificatePathVCIsCT(path
)) {
3109 SecPathCTPolicy ctp
= SecCertificatePathVCRequiresCT(path
);
3110 if (ctp
> kSecPathCTNotRequired
&& SecPVCIsSSLServerAuthenticationPolicy(pvc
)) {
3111 /* CT was required. Error is always set on leaf certificate. */
3112 SecPVCSetResultForced(pvc
, kSecPolicyCheckCTRequired
,
3113 0, kCFBooleanFalse
, true);
3114 if (ctp
!= kSecPathCTRequiredOverridable
) {
3115 /* Normally kSecPolicyCheckCTRequired is recoverable,
3116 so need to manually change trust result here. */
3117 pvc
->result
= kSecTrustResultFatalTrustFailure
;
3122 secdebug("policy", "end %strusted path: %@",
3123 (SecPVCIsOkResult(pvc
) ? "" : "not "), SecPathBuilderGetPath(pvc
->builder
));
3125 SecCertificatePathVCSetPathValidated(SecPathBuilderGetPath(pvc
->builder
));
3129 void SecPVCPathCheckRevocationResponsesReceived(SecPVCRef pvc
) {
3131 /* Since we don't currently allow networking on watchOS,
3132 * don't enforce the revocation-required check here. (32728029) */
3133 bool required
= false;
3135 bool required
= true;
3137 SecCertificatePathVCRef path
= SecPathBuilderGetPath(pvc
->builder
);
3138 CFIndex ix
, certCount
= SecCertificatePathVCGetCount(path
);
3139 for (ix
= 0; ix
< certCount
; ix
++) {
3140 SecRVCRef rvc
= SecCertificatePathVCGetRVCAtIndex(path
, ix
);
3141 /* Do we have a valid revocation response? */
3142 if (SecRVCGetEarliestNextUpdate(rvc
) == NULL_TIME
) {
3143 /* No valid revocation response.
3144 * Do we require revocation (for that cert per the
3145 * SecCertificateVCRef, or per the pvc)? */
3146 if (required
&& (SecCertificatePathVCIsRevocationRequiredForCertificateAtIndex(path
, ix
) ||
3147 ((ix
== 0) && pvc
->require_revocation_response
))) {
3148 SecPVCSetResultForced(pvc
, kSecPolicyCheckRevocationResponseRequired
,
3149 ix
, kCFBooleanFalse
, true);
3151 /* Do we have a definitive Valid revocation result for this cert? */
3152 if (SecRVCHasDefinitiveValidInfo(rvc
) && SecRVCHasRevokedValidInfo(rvc
)) {
3153 SecRVCSetRevokedResult(rvc
);