]> git.saurik.com Git - apple/security.git/blob - trust/trustd/SecPolicyServer.c
Security-59754.80.3.tar.gz
[apple/security.git] / trust / trustd / SecPolicyServer.c
1 /*
2 * Copyright (c) 2008-2020 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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
11 * file.
12 *
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.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 /*
25 * SecPolicyServer.c - Engine for evaluating certificate paths against trust policies.
26 */
27
28 #include <AssertMacros.h>
29 #include <wctype.h>
30 #include <asl.h>
31
32 #include <CommonCrypto/CommonDigest.h>
33 #include <CoreFoundation/CFTimeZone.h>
34 #include <CoreFoundation/CFNumber.h>
35 #include <sys/codesign.h>
36 #include <libDER/DER_CertCrl.h>
37 #include <libDER/DER_Encode.h>
38 #include <libDER/asn1Types.h>
39 #include <libDER/oids.h>
40 #include <SystemConfiguration/SCDynamicStoreCopySpecific.h>
41
42 #include <utilities/array_size.h>
43 #include <utilities/SecCFWrappers.h>
44 #include <utilities/SecAppleAnchorPriv.h>
45 #include <utilities/debugging.h>
46 #include <utilities/SecInternalReleasePriv.h>
47 #include <security_asn1/SecAsn1Coder.h>
48 #include <security_asn1/ocspTemplates.h>
49 #include <security_asn1/oidsalg.h>
50 #include <security_asn1/oidsocsp.h>
51 #include <Security/SecPolicyInternal.h>
52 #include <Security/SecPolicyPriv.h>
53 #include <Security/SecTask.h>
54 #include <Security/SecCertificateInternal.h>
55 #include <Security/SecFramework.h>
56 #include <Security/SecPolicyInternal.h>
57 #include <Security/SecTrustPriv.h>
58 #include <Security/SecTrustInternal.h>
59 #include <Security/SecTrustSettingsPriv.h>
60 #include <Security/SecInternal.h>
61 #include <Security/SecKeyPriv.h>
62
63 #include "trust/trustd/SecPolicyServer.h"
64 #include "trust/trustd/policytree.h"
65 #include "trust/trustd/nameconstraints.h"
66 #include "trust/trustd/SecTrustServer.h"
67 #include "trust/trustd/SecTrustLoggingServer.h"
68 #include "trust/trustd/SecRevocationServer.h"
69 #include "trust/trustd/SecCertificateServer.h"
70 #include "trust/trustd/SecCertificateSource.h"
71 #include "trust/trustd/SecOCSPResponse.h"
72 #include "trust/trustd/SecTrustStoreServer.h"
73 #include "trust/trustd/OTATrustUtilities.h"
74 #include "trust/trustd/personalization.h"
75 #include "trust/trustd/CertificateTransparency.h"
76
77 #if !TARGET_OS_IPHONE
78 #include <Security/SecTaskPriv.h>
79 #endif
80
81 /* Set this to 1 to dump the ocsp responses received in DER form in /tmp. */
82 #ifndef DUMP_OCSPRESPONSES
83 #define DUMP_OCSPRESPONSES 0
84 #endif
85
86 #if DUMP_OCSPRESPONSES
87
88 #include <unistd.h>
89 #include <fcntl.h>
90
91 static void secdumpdata(CFDataRef data, const char *name) {
92 int fd = open(name, O_CREAT | O_WRONLY | O_TRUNC, 0666);
93 write(fd, CFDataGetBytePtr(data), CFDataGetLength(data));
94 close(fd);
95 }
96
97 #endif
98
99
100 /********************************************************
101 ****************** SecPolicy object ********************
102 ********************************************************/
103
104 static SecTrustSettingsResult SecPVCGetTrustSettingsResult(SecPVCRef pvc, SecCertificateRef certificate, CFArrayRef constraints);
105
106 static CFMutableDictionaryRef gSecPolicyLeafCallbacks = NULL;
107 static CFMutableDictionaryRef gSecPolicyPathCallbacks = NULL;
108
109 static CFArrayRef SecPolicyAnchorDigestsForEVPolicy(const DERItem *policyOID)
110 {
111 CFArrayRef result = NULL;
112 SecOTAPKIRef otapkiRef = SecOTAPKICopyCurrentOTAPKIRef();
113 if (NULL == otapkiRef)
114 {
115 return result;
116 }
117
118 CFDictionaryRef evToPolicyAnchorDigest = SecOTAPKICopyEVPolicyToAnchorMapping(otapkiRef);
119 CFRelease(otapkiRef);
120
121 if (NULL == evToPolicyAnchorDigest)
122 {
123 return result;
124 }
125
126 CFArrayRef roots = NULL;
127 CFStringRef oid = SecDERItemCopyOIDDecimalRepresentation(kCFAllocatorDefault, policyOID);
128 if (oid && evToPolicyAnchorDigest)
129 {
130 result = (CFArrayRef)CFDictionaryGetValue(evToPolicyAnchorDigest, oid);
131 if (roots && CFGetTypeID(result) != CFArrayGetTypeID())
132 {
133 secerror("EVRoot.plist has non array value");
134 result = NULL;
135 }
136 CFRelease(oid);
137 }
138 CFReleaseSafe(evToPolicyAnchorDigest);
139 return result;
140 }
141
142
143 bool SecPolicyIsEVPolicy(const DERItem *policyOID) {
144 return SecPolicyAnchorDigestsForEVPolicy(policyOID);
145 }
146
147 static bool SecPolicyRootCACertificateIsEV(SecCertificateRef certificate,
148 policy_set_t valid_policies) {
149 CFDictionaryRef keySizes = NULL;
150 CFNumberRef rsaSize = NULL, ecSize = NULL;
151 bool isEV = false;
152 /* Ensure that this certificate is a valid anchor for one of the
153 certificate policy oids specified in the leaf. */
154 CFDataRef digest = SecCertificateGetSHA1Digest(certificate);
155 policy_set_t ix;
156 bool good_ev_anchor = false;
157 for (ix = valid_policies; ix; ix = ix->oid_next) {
158 CFArrayRef digests = SecPolicyAnchorDigestsForEVPolicy(&ix->oid);
159 if (digests && CFArrayContainsValue(digests,
160 CFRangeMake(0, CFArrayGetCount(digests)), digest)) {
161 secdebug("ev", "found anchor for policy oid");
162 good_ev_anchor = true;
163 break;
164 }
165 }
166 require_action_quiet(good_ev_anchor, notEV, secnotice("ev", "anchor not in plist"));
167
168 CFAbsoluteTime october2006 = 178761600;
169 if (SecCertificateNotValidBefore(certificate) >= october2006) {
170 require_action_quiet(SecCertificateVersion(certificate) >= 3, notEV,
171 secnotice("ev", "Anchor issued after October 2006 and is not v3"));
172 }
173 if (SecCertificateVersion(certificate) >= 3
174 && SecCertificateNotValidBefore(certificate) >= october2006) {
175 const SecCEBasicConstraints *bc = SecCertificateGetBasicConstraints(certificate);
176 require_action_quiet(bc && bc->isCA == true, notEV,
177 secnotice("ev", "Anchor has invalid basic constraints"));
178 SecKeyUsage ku = SecCertificateGetKeyUsage(certificate);
179 require_action_quiet((ku & (kSecKeyUsageKeyCertSign | kSecKeyUsageCRLSign))
180 == (kSecKeyUsageKeyCertSign | kSecKeyUsageCRLSign), notEV,
181 secnotice("ev", "Anchor has invalid key usage %u", ku));
182 }
183
184 /* At least RSA 2048 or ECC NIST P-256. */
185 require_quiet(rsaSize = CFNumberCreateWithCFIndex(NULL, 2048), notEV);
186 require_quiet(ecSize = CFNumberCreateWithCFIndex(NULL, 256), notEV);
187 const void *keys[] = { kSecAttrKeyTypeRSA, kSecAttrKeyTypeEC };
188 const void *values[] = { rsaSize, ecSize };
189 require_quiet(keySizes = CFDictionaryCreate(NULL, keys, values, 2,
190 &kCFTypeDictionaryKeyCallBacks,
191 &kCFTypeDictionaryValueCallBacks), notEV);
192 require_action_quiet(SecCertificateIsAtLeastMinKeySize(certificate, keySizes), notEV,
193 secnotice("ev", "Anchor's public key is too weak for EV"));
194
195 isEV = true;
196
197 notEV:
198 CFReleaseNull(rsaSize);
199 CFReleaseNull(ecSize);
200 CFReleaseNull(keySizes);
201 return isEV;
202 }
203
204 static bool SecPolicySubordinateCACertificateCouldBeEV(SecCertificateRef certificate) {
205 CFMutableDictionaryRef keySizes = NULL;
206 CFNumberRef rsaSize = NULL, ecSize = NULL;
207 bool isEV = false;
208
209 const SecCECertificatePolicies *cp;
210 cp = SecCertificateGetCertificatePolicies(certificate);
211 require_action_quiet(cp && cp->numPolicies > 0, notEV,
212 secnotice("ev", "SubCA missing certificate policies"));
213 CFArrayRef cdp = SecCertificateGetCRLDistributionPoints(certificate);
214 require_action_quiet(cdp && CFArrayGetCount(cdp) > 0, notEV,
215 secnotice("ev", "SubCA missing CRLDP"));
216 const SecCEBasicConstraints *bc = SecCertificateGetBasicConstraints(certificate);
217 require_action_quiet(bc && bc->isCA == true, notEV,
218 secnotice("ev", "SubCA has invalid basic constraints"));
219 SecKeyUsage ku = SecCertificateGetKeyUsage(certificate);
220 require_action_quiet((ku & (kSecKeyUsageKeyCertSign | kSecKeyUsageCRLSign))
221 == (kSecKeyUsageKeyCertSign | kSecKeyUsageCRLSign), notEV,
222 secnotice("ev", "SubCA has invalid key usage %u", ku));
223
224 /* 6.1.5 Key Sizes */
225 CFAbsoluteTime jan2011 = 315532800;
226 CFAbsoluteTime jan2014 = 410227200;
227 require_quiet(ecSize = CFNumberCreateWithCFIndex(NULL, 256), notEV);
228 require_quiet(keySizes = CFDictionaryCreateMutable(NULL, 2, &kCFTypeDictionaryKeyCallBacks,
229 &kCFTypeDictionaryValueCallBacks), notEV);
230 CFDictionaryAddValue(keySizes, kSecAttrKeyTypeEC, ecSize);
231 if (SecCertificateNotValidBefore(certificate) < jan2011 ||
232 SecCertificateNotValidAfter(certificate) < jan2014) {
233 /* At least RSA 1024 or ECC NIST P-256. */
234 require_quiet(rsaSize = CFNumberCreateWithCFIndex(NULL, 1024), notEV);
235 CFDictionaryAddValue(keySizes, kSecAttrKeyTypeRSA, rsaSize);
236 require_action_quiet(SecCertificateIsAtLeastMinKeySize(certificate, keySizes), notEV,
237 secnotice("ev", "SubCA's public key is too small for issuance before 2011 or expiration before 2014"));
238 } else {
239 /* At least RSA 2028 or ECC NIST P-256. */
240 require_quiet(rsaSize = CFNumberCreateWithCFIndex(NULL, 2048), notEV);
241 CFDictionaryAddValue(keySizes, kSecAttrKeyTypeRSA, rsaSize);
242 require_action_quiet(SecCertificateIsAtLeastMinKeySize(certificate, keySizes), notEV,
243 secnotice("ev", "SubCA's public key is too small for issuance after 2010 or expiration after 2013"));
244 }
245
246 /* 7.1.3 Algorithm Object Identifiers */
247 CFAbsoluteTime jan2016 = 473299200;
248 if (SecCertificateNotValidBefore(certificate) > jan2016) {
249 /* SHA-2 only */
250 require_action_quiet(SecCertificateGetSignatureHashAlgorithm(certificate) > kSecSignatureHashAlgorithmSHA1,
251 notEV, secnotice("ev", "SubCA was issued with SHA-1 after 2015"));
252 }
253
254 isEV = true;
255
256 notEV:
257 CFReleaseNull(rsaSize);
258 CFReleaseNull(ecSize);
259 CFReleaseNull(keySizes);
260 return isEV;
261 }
262
263 /********************************************************
264 **************** SecPolicy Callbacks *******************
265 ********************************************************/
266 static void SecPolicyCheckCriticalExtensions(SecPVCRef pvc,
267 CFStringRef key) {
268 }
269
270 static void SecPolicyCheckIdLinkage(SecPVCRef pvc,
271 CFStringRef key) {
272 CFIndex ix, count = SecPVCGetCertificateCount(pvc);
273 CFDataRef parentSubjectKeyID = NULL;
274 for (ix = count - 1; ix >= 0; --ix) {
275 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix);
276 /* If the previous certificate in the chain had a SubjectKeyID,
277 make sure it matches the current certificates AuthorityKeyID. */
278 if (parentSubjectKeyID) {
279 /* @@@ According to RFC 2459 neither AuthorityKeyID nor
280 SubjectKeyID can be critical. Currenty we don't check
281 for this. */
282 CFDataRef authorityKeyID = SecCertificateGetAuthorityKeyID(cert);
283 if (authorityKeyID) {
284 if (!CFEqual(parentSubjectKeyID, authorityKeyID)) {
285 /* AuthorityKeyID doesn't match issuers SubjectKeyID. */
286 if (!SecPVCSetResult(pvc, key, ix, kCFBooleanFalse))
287 return;
288 }
289 }
290 }
291
292 parentSubjectKeyID = SecCertificateGetSubjectKeyID(cert);
293 }
294 }
295
296 static void SecPolicyCheckKeyUsage(SecPVCRef pvc,
297 CFStringRef key) {
298 SecCertificateRef leaf = SecPVCGetCertificateAtIndex(pvc, 0);
299 SecPolicyRef policy = SecPVCGetPolicy(pvc);
300 CFTypeRef xku = CFDictionaryGetValue(policy->_options, key);
301 if (!SecPolicyCheckCertKeyUsage(leaf, xku)) {
302 SecPVCSetResult(pvc, key, 0, kCFBooleanFalse);
303 }
304 }
305
306 /* AUDIT[securityd](done):
307 policy->_options is a caller provided dictionary, only its cf type has
308 been checked.
309 */
310 static void SecPolicyCheckExtendedKeyUsage(SecPVCRef pvc, CFStringRef key) {
311 SecCertificateRef leaf = SecPVCGetCertificateAtIndex(pvc, 0);
312 SecPolicyRef policy = SecPVCGetPolicy(pvc);
313 CFTypeRef xeku = CFDictionaryGetValue(policy->_options, key);
314 /* leaf check enforced */
315 if (!SecPolicyCheckCertExtendedKeyUsage(leaf, xeku)){
316 SecPVCSetResult(pvc, key, 0, kCFBooleanFalse);
317 }
318
319 /* subCA check produces metrics */
320 TrustAnalyticsBuilder *analytics = SecPathBuilderGetAnalyticsData(pvc->builder);
321 CFIndex ix, count = SecPVCGetCertificateCount(pvc);
322 if (count > 2 && analytics) {
323 for (ix = 1; ix < count - 1 ; ++ix) {
324 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix);
325 CFArrayRef ekus = SecCertificateCopyExtendedKeyUsage(cert);
326 if (ekus && CFArrayGetCount(ekus) && // subCA has ekus
327 !SecPolicyCheckCertExtendedKeyUsage(cert, CFSTR("2.5.29.37.0")) && // but not the anyEKU
328 !SecPolicyCheckCertExtendedKeyUsage(cert, xeku)) { // and not the EKUs specified by the policy
329 analytics->ca_fail_eku_check = true;
330 }
331 CFReleaseNull(ekus);
332 }
333 }
334 }
335
336 static void SecPolicyCheckBasicConstraints(SecPVCRef pvc,
337 CFStringRef key) {
338 //SecPolicyCheckBasicContraintsCommon(pvc, key, false);
339 }
340
341 static void SecPolicyCheckNonEmptySubject(SecPVCRef pvc,
342 CFStringRef key) {
343 CFIndex ix, count = SecPVCGetCertificateCount(pvc);
344 SecPolicyRef policy = SecPVCGetPolicy(pvc);
345 CFTypeRef pvcValue = CFDictionaryGetValue(policy->_options, key);
346 for (ix = 0; ix < count; ++ix) {
347 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix);
348 if (!SecPolicyCheckCertNonEmptySubject(cert, pvcValue)) {
349 if (!SecPVCSetResult(pvc, key, ix, kCFBooleanFalse))
350 return;
351 }
352 }
353 }
354
355 /* AUDIT[securityd](done):
356 policy->_options is a caller provided dictionary, only its cf type has
357 been checked.
358 */
359 static void SecPolicyCheckSSLHostname(SecPVCRef pvc,
360 CFStringRef key) {
361 /* @@@ Consider what to do if the caller passes in no hostname. Should
362 we then still fail if the leaf has no dnsNames or IPAddresses at all? */
363 SecPolicyRef policy = SecPVCGetPolicy(pvc);
364 CFStringRef hostName = (CFStringRef)
365 CFDictionaryGetValue(policy->_options, key);
366 if (!isString(hostName)) {
367 /* @@@ We can't return an error here and making the evaluation fail
368 won't help much either. */
369 return;
370 }
371
372 SecCertificateRef leaf = SecPVCGetCertificateAtIndex(pvc, 0);
373 bool dnsMatch = SecPolicyCheckCertSSLHostname(leaf, hostName);
374
375 if (!dnsMatch) {
376 /* Hostname mismatch or no hostnames found in certificate. */
377 SecPVCSetResult(pvc, key, 0, kCFBooleanFalse);
378 }
379
380 }
381
382 /* AUDIT[securityd](done):
383 policy->_options is a caller provided dictionary, only its cf type has
384 been checked.
385 */
386 static void SecPolicyCheckEmail(SecPVCRef pvc, CFStringRef key) {
387 SecPolicyRef policy = SecPVCGetPolicy(pvc);
388 CFStringRef email = (CFStringRef)CFDictionaryGetValue(policy->_options, key);
389 if (!isString(email)) {
390 /* We can't return an error here and making the evaluation fail
391 won't help much either. */
392 return;
393 }
394
395 SecCertificateRef leaf = SecPVCGetCertificateAtIndex(pvc, 0);
396
397 if (!SecPolicyCheckCertEmail(leaf, email)) {
398 /* Hostname mismatch or no hostnames found in certificate. */
399 SecPVCSetResult(pvc, key, 0, kCFBooleanFalse);
400 }
401 }
402
403 static void SecPolicyCheckTemporalValidity(SecPVCRef pvc,
404 CFStringRef key) {
405 CFIndex ix, count = SecPVCGetCertificateCount(pvc);
406 CFAbsoluteTime verifyTime = SecPVCGetVerifyTime(pvc);
407 for (ix = 0; ix < count; ++ix) {
408 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix);
409 if (!SecCertificateIsValid(cert, verifyTime)) {
410 /* Intermediate certificate has expired. */
411 if (!SecPVCSetResult(pvc, key, ix, kCFBooleanFalse))
412 return;
413 }
414 }
415 }
416
417 /* AUDIT[securityd](done):
418 policy->_options is a caller provided dictionary, only its cf type has
419 been checked.
420 */
421 static void SecPolicyCheckIssuerCommonName(SecPVCRef pvc,
422 CFStringRef key) {
423 CFIndex count = SecPVCGetCertificateCount(pvc);
424 if (count < 2) {
425 /* Can't check intermediates common name if there is no intermediate. */
426 SecPVCSetResult(pvc, key, 0, kCFBooleanFalse);
427 return;
428 }
429
430 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, 1);
431 SecPolicyRef policy = SecPVCGetPolicy(pvc);
432 CFStringRef commonName =
433 (CFStringRef)CFDictionaryGetValue(policy->_options, key);
434 if (!isString(commonName)) {
435 /* @@@ We can't return an error here and making the evaluation fail
436 won't help much either. */
437 return;
438 }
439 if (!SecPolicyCheckCertSubjectCommonName(cert, commonName)) {
440 SecPVCSetResult(pvc, key, 0, kCFBooleanFalse);
441 }
442 }
443
444 /* AUDIT[securityd](done):
445 policy->_options is a caller provided dictionary, only its cf type has
446 been checked.
447 */
448 static void SecPolicyCheckSubjectCommonName(SecPVCRef pvc,
449 CFStringRef key) {
450 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, 0);
451 SecPolicyRef policy = SecPVCGetPolicy(pvc);
452 CFStringRef common_name = (CFStringRef)CFDictionaryGetValue(policy->_options,
453 key);
454 if (!isString(common_name)) {
455 /* @@@ We can't return an error here and making the evaluation fail
456 won't help much either. */
457 return;
458 }
459 if (!SecPolicyCheckCertSubjectCommonName(cert, common_name)) {
460 SecPVCSetResult(pvc, key, 0, kCFBooleanFalse);
461 }
462 }
463
464 /* AUDIT[securityd](done):
465 policy->_options is a caller provided dictionary, only its cf type has
466 been checked.
467 */
468 static void SecPolicyCheckSubjectCommonNamePrefix(SecPVCRef pvc,
469 CFStringRef key) {
470 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, 0);
471 SecPolicyRef policy = SecPVCGetPolicy(pvc);
472 CFStringRef prefix = (CFStringRef)CFDictionaryGetValue(policy->_options,
473 key);
474 if (!isString(prefix)) {
475 /* @@@ We can't return an error here and making the evaluation fail
476 won't help much either. */
477 return;
478 }
479 if (!SecPolicyCheckCertSubjectCommonNamePrefix(cert, prefix)) {
480 SecPVCSetResult(pvc, key, 0, kCFBooleanFalse);
481 }
482 }
483
484 /* AUDIT[securityd](done):
485 policy->_options is a caller provided dictionary, only its cf type has
486 been checked.
487 */
488 static void SecPolicyCheckSubjectCommonNameTEST(SecPVCRef pvc,
489 CFStringRef key) {
490 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, 0);
491 SecPolicyRef policy = SecPVCGetPolicy(pvc);
492 CFStringRef common_name = (CFStringRef)CFDictionaryGetValue(policy->_options,
493 key);
494 if (!isString(common_name)) {
495 /* @@@ We can't return an error here and making the evaluation fail
496 won't help much either. */
497 return;
498 }
499 if (!SecPolicyCheckCertSubjectCommonNameTEST(cert, common_name)) {
500 SecPVCSetResult(pvc, key, 0, kCFBooleanFalse);
501 }
502 }
503
504 /* AUDIT[securityd](done):
505 policy->_options is a caller provided dictionary, only its cf type has
506 been checked.
507 */
508 static void SecPolicyCheckNotValidBefore(SecPVCRef pvc,
509 CFStringRef key) {
510 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, 0);
511 SecPolicyRef policy = SecPVCGetPolicy(pvc);
512 CFDateRef date = (CFDateRef)CFDictionaryGetValue(policy->_options, key);
513 if (!isDate(date)) {
514 /* @@@ We can't return an error here and making the evaluation fail
515 won't help much either. */
516 return;
517 }
518 if (!SecPolicyCheckCertNotValidBefore(cert, date)) {
519 if (!SecPVCSetResult(pvc, key, 0, kCFBooleanFalse))
520 return;
521 }
522 }
523
524 /* AUDIT[securityd](done):
525 policy->_options is a caller provided dictionary, only its cf type has
526 been checked.
527 */
528 static void SecPolicyCheckChainLength(SecPVCRef pvc,
529 CFStringRef key) {
530 CFIndex count = SecPVCGetCertificateCount(pvc);
531 SecPolicyRef policy = SecPVCGetPolicy(pvc);
532 CFNumberRef chainLength =
533 (CFNumberRef)CFDictionaryGetValue(policy->_options, key);
534 CFIndex value;
535 if (!chainLength || CFGetTypeID(chainLength) != CFNumberGetTypeID() ||
536 !CFNumberGetValue(chainLength, kCFNumberCFIndexType, &value)) {
537 /* @@@ We can't return an error here and making the evaluation fail
538 won't help much either. */
539 return;
540 }
541 if (value != count) {
542 /* Chain length doesn't match policy requirement. */
543 if (!SecPVCSetResult(pvc, key, 0, kCFBooleanFalse))
544 return;
545 }
546 }
547
548 static bool isDigestInPolicy(SecPVCRef pvc, CFStringRef key, CFDataRef digest) {
549 SecPolicyRef policy = SecPVCGetPolicy(pvc);
550 CFTypeRef value = CFDictionaryGetValue(policy->_options, key);
551
552 bool foundMatch = false;
553 if (isData(value))
554 foundMatch = CFEqual(digest, value);
555 else if (isArray(value))
556 foundMatch = CFArrayContainsValue((CFArrayRef) value, CFRangeMake(0, CFArrayGetCount((CFArrayRef) value)), digest);
557 else {
558 /* @@@ We only support Data and Array but we can't return an error here so.
559 we let the evaluation fail (not much help) and assert in debug. */
560 assert(false);
561 }
562
563 return foundMatch;
564 }
565
566 static void SecPolicyCheckAnchorSHA256(SecPVCRef pvc, CFStringRef key) {
567 CFIndex count = SecPVCGetCertificateCount(pvc);
568 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, count - 1);
569 CFDataRef anchorSHA256 = NULL;
570 anchorSHA256 = SecCertificateCopySHA256Digest(cert);
571
572 if (!isDigestInPolicy(pvc, key, anchorSHA256)) {
573 SecPVCSetResult(pvc, kSecPolicyCheckAnchorSHA256, count-1, kCFBooleanFalse);
574 }
575
576 CFReleaseNull(anchorSHA256);
577 return;
578 }
579
580 /*
581 Check the SHA256 of SPKI of the first intermediate CA certificate in the path.
582 policy->_options is a caller provided dictionary, only its cf type has
583 been checked.
584 */
585 static void SecPolicyCheckIntermediateSPKISHA256(SecPVCRef pvc,
586 CFStringRef key) {
587 SecCertificateRef cert = NULL;
588 CFDataRef digest = NULL;
589
590 if (SecPVCGetCertificateCount(pvc) < 2) {
591 SecPVCSetResult(pvc, kSecPolicyCheckIntermediateSPKISHA256, 0, kCFBooleanFalse);
592 return;
593 }
594
595 cert = SecPVCGetCertificateAtIndex(pvc, 1);
596 digest = SecCertificateCopySubjectPublicKeyInfoSHA256Digest(cert);
597
598 if (!isDigestInPolicy(pvc, key, digest)) {
599 SecPVCSetResult(pvc, kSecPolicyCheckIntermediateSPKISHA256, 1, kCFBooleanFalse);
600 }
601 CFReleaseNull(digest);
602 }
603
604 /*
605 Check the SPKI SHA256 of CA certificates in the path
606 policy->_options is a caller provided dictionary, only its cf type has
607 been checked.
608 */
609 static void SecPolicyCheckCAspkiSHA256(SecPVCRef pvc,
610 CFStringRef key) {
611 SecCertificateRef cert = NULL;
612 CFDataRef digest = NULL;
613
614 if (SecPVCGetCertificateCount(pvc) < 2) {
615 SecPVCSetResult(pvc, kSecPolicyCheckCAspkiSHA256, 0, kCFBooleanFalse);
616 return;
617 }
618
619 bool spkiSHA256match = false;
620 CFIndex count = SecPVCGetCertificateCount(pvc);
621 for (CFIndex i = 1; i < count && spkiSHA256match == false; i++) {
622 cert = SecPVCGetCertificateAtIndex(pvc, i);
623 digest = SecCertificateCopySubjectPublicKeyInfoSHA256Digest(cert);
624
625 if (isDigestInPolicy(pvc, key, digest)) {
626 spkiSHA256match = true;
627 }
628
629 CFReleaseNull(digest);
630 }
631
632 if (spkiSHA256match == true) {
633 return;
634 }
635
636 for (CFIndex i = 1; i < count; i++) {
637 SecPVCSetResult(pvc, kSecPolicyCheckCAspkiSHA256, i, kCFBooleanFalse);
638 }
639 }
640
641 /*
642 Check the SPKI SHA256 of the leaf certificate.
643 policy->_options is a caller provided dictionary, only its cf type has
644 been checked.
645 */
646 static void SecPolicyCheckLeafSPKISHA256(SecPVCRef pvc,
647 CFStringRef key) {
648 SecPolicyRef policy = SecPVCGetPolicy(pvc);
649
650 CFArrayRef leafSPKISHA256 = CFDictionaryGetValue(policy->_options, key);
651 if (isArray(leafSPKISHA256) == false) {
652 /* @@@ We can't return an error here and making the evaluation fail
653 won't help much either. */
654 return;
655 }
656
657 SecCertificateRef leaf = SecPVCGetCertificateAtIndex(pvc, 0);
658 CFDataRef digest = SecCertificateCopySubjectPublicKeyInfoSHA256Digest(leaf);
659 if (!digest) {
660 SecPVCSetResult(pvc, key, 0, kCFBooleanFalse);
661 return;
662 }
663
664 if (!CFArrayContainsValue(leafSPKISHA256, CFRangeMake(0, CFArrayGetCount(leafSPKISHA256)), digest)) {
665 SecPVCSetResult(pvc, key, 0, kCFBooleanFalse);
666 }
667
668 CFReleaseNull(digest);
669 }
670
671 /*
672 policy->_options is a caller provided dictionary, only its cf type has
673 been checked.
674 */
675 static void SecPolicyCheckAnchorApple(SecPVCRef pvc,
676 CFStringRef key) {
677 CFIndex count = SecPVCGetCertificateCount(pvc);
678 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, count - 1);
679 SecAppleTrustAnchorFlags flags = 0;
680
681
682 bool foundMatch = SecIsAppleTrustAnchor(cert, flags);
683
684 if (!foundMatch)
685 if (!SecPVCSetResult(pvc, kSecPolicyCheckAnchorApple, 0, kCFBooleanFalse))
686 return;
687
688 return;
689 }
690
691
692 /* AUDIT[securityd](done):
693 policy->_options is a caller provided dictionary, only its cf type has
694 been checked.
695 */
696 static void SecPolicyCheckSubjectOrganization(SecPVCRef pvc,
697 CFStringRef key) {
698 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, 0);
699 SecPolicyRef policy = SecPVCGetPolicy(pvc);
700 CFStringRef org = (CFStringRef)CFDictionaryGetValue(policy->_options,
701 key);
702 if (!isString(org)) {
703 /* @@@ We can't return an error here and making the evaluation fail
704 won't help much either. */
705 return;
706 }
707 if (!SecPolicyCheckCertSubjectOrganization(cert, org)) {
708 /* Leaf Subject Organization mismatch. */
709 SecPVCSetResult(pvc, key, 0, kCFBooleanFalse);
710 }
711 }
712
713 static void SecPolicyCheckSubjectOrganizationalUnit(SecPVCRef pvc,
714 CFStringRef key) {
715 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, 0);
716 SecPolicyRef policy = SecPVCGetPolicy(pvc);
717 CFStringRef orgUnit = (CFStringRef)CFDictionaryGetValue(policy->_options,
718 key);
719 if (!isString(orgUnit)) {
720 /* @@@ We can't return an error here and making the evaluation fail
721 won't help much either. */
722 return;
723 }
724 if (!SecPolicyCheckCertSubjectOrganizationalUnit(cert, orgUnit)) {
725 /* Leaf Subject Organization mismatch. */
726 SecPVCSetResult(pvc, key, 0, kCFBooleanFalse);
727 }
728 }
729
730 /* AUDIT[securityd](done):
731 policy->_options is a caller provided dictionary, only its cf type has
732 been checked.
733 */
734 static void SecPolicyCheckEAPTrustedServerNames(SecPVCRef pvc,
735 CFStringRef key) {
736 SecPolicyRef policy = SecPVCGetPolicy(pvc);
737 CFArrayRef trustedServerNames = (CFArrayRef)
738 CFDictionaryGetValue(policy->_options, key);
739 /* No names specified means we accept any name. */
740 if (!trustedServerNames)
741 return;
742 if (!isArray(trustedServerNames)) {
743 /* @@@ We can't return an error here and making the evaluation fail
744 won't help much either. */
745 return;
746 }
747
748 SecCertificateRef leaf = SecPVCGetCertificateAtIndex(pvc, 0);
749 if (!SecPolicyCheckCertEAPTrustedServerNames(leaf, trustedServerNames)) {
750 /* Hostname mismatch or no hostnames found in certificate. */
751 SecPVCSetResult(pvc, key, 0, kCFBooleanFalse);
752 }
753 }
754
755 static const unsigned char UTN_USERFirst_Hardware_Serial[][16] = {
756 { 0xd8, 0xf3, 0x5f, 0x4e, 0xb7, 0x87, 0x2b, 0x2d, 0xab, 0x06, 0x92, 0xe3, 0x15, 0x38, 0x2f, 0xb0 },
757 { 0x92, 0x39, 0xd5, 0x34, 0x8f, 0x40, 0xd1, 0x69, 0x5a, 0x74, 0x54, 0x70, 0xe1, 0xf2, 0x3f, 0x43 },
758 { 0xb0, 0xb7, 0x13, 0x3e, 0xd0, 0x96, 0xf9, 0xb5, 0x6f, 0xae, 0x91, 0xc8, 0x74, 0xbd, 0x3a, 0xc0 },
759 { 0xe9, 0x02, 0x8b, 0x95, 0x78, 0xe4, 0x15, 0xdc, 0x1a, 0x71, 0x0a, 0x2b, 0x88, 0x15, 0x44, 0x47 },
760 { 0x39, 0x2a, 0x43, 0x4f, 0x0e, 0x07, 0xdf, 0x1f, 0x8a, 0xa3, 0x05, 0xde, 0x34, 0xe0, 0xc2, 0x29 },
761 { 0x3e, 0x75, 0xce, 0xd4, 0x6b, 0x69, 0x30, 0x21, 0x21, 0x88, 0x30, 0xae, 0x86, 0xa8, 0x2a, 0x71 },
762 { 0xd7, 0x55, 0x8f, 0xda, 0xf5, 0xf1, 0x10, 0x5b, 0xb2, 0x13, 0x28, 0x2b, 0x70, 0x77, 0x29, 0xa3 },
763 { 0x04, 0x7e, 0xcb, 0xe9, 0xfc, 0xa5, 0x5f, 0x7b, 0xd0, 0x9e, 0xae, 0x36, 0xe1, 0x0c, 0xae, 0x1e },
764 { 0xf5, 0xc8, 0x6a, 0xf3, 0x61, 0x62, 0xf1, 0x3a, 0x64, 0xf5, 0x4f, 0x6d, 0xc9, 0x58, 0x7c, 0x06 } };
765
766 static const unsigned char UTN_USERFirst_Hardware_Normalized_Issuer[] = {
767 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55,
768 0x53, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x02,
769 0x55, 0x54, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x07, 0x13,
770 0x0e, 0x53, 0x41, 0x4c, 0x54, 0x20, 0x4c, 0x41, 0x4b, 0x45, 0x20, 0x43,
771 0x49, 0x54, 0x59, 0x31, 0x1e, 0x30, 0x1c, 0x06, 0x03, 0x55, 0x04, 0x0a,
772 0x13, 0x15, 0x54, 0x48, 0x45, 0x20, 0x55, 0x53, 0x45, 0x52, 0x54, 0x52,
773 0x55, 0x53, 0x54, 0x20, 0x4e, 0x45, 0x54, 0x57, 0x4f, 0x52, 0x4b, 0x31,
774 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x18, 0x48, 0x54,
775 0x54, 0x50, 0x3a, 0x2f, 0x2f, 0x57, 0x57, 0x57, 0x2e, 0x55, 0x53, 0x45,
776 0x52, 0x54, 0x52, 0x55, 0x53, 0x54, 0x2e, 0x43, 0x4f, 0x4d, 0x31, 0x1f,
777 0x30, 0x1d, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x16, 0x55, 0x54, 0x4e,
778 0x2d, 0x55, 0x53, 0x45, 0x52, 0x46, 0x49, 0x52, 0x53, 0x54, 0x2d, 0x48,
779 0x41, 0x52, 0x44, 0x57, 0x41, 0x52, 0x45
780 };
781 static const unsigned int UTN_USERFirst_Hardware_Normalized_Issuer_len = 151;
782
783
784 static void SecPolicyCheckBlackListedLeaf(SecPVCRef pvc,
785 CFStringRef key) {
786 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, 0);
787 CFDataRef issuer = cert ? SecCertificateGetNormalizedIssuerContent(cert) : NULL;
788
789 if (issuer && (CFDataGetLength(issuer) == (CFIndex)UTN_USERFirst_Hardware_Normalized_Issuer_len) &&
790 (0 == memcmp(UTN_USERFirst_Hardware_Normalized_Issuer, CFDataGetBytePtr(issuer),
791 UTN_USERFirst_Hardware_Normalized_Issuer_len)))
792 {
793 CFDataRef serial = SecCertificateCopySerialNumberData(cert, NULL);
794 if (serial) {
795 CFIndex serial_length = CFDataGetLength(serial);
796 const uint8_t *serial_ptr = CFDataGetBytePtr(serial);
797
798 while ((serial_length > 0) && (*serial_ptr == 0)) {
799 serial_ptr++;
800 serial_length--;
801 }
802
803 if (serial_length == (CFIndex)sizeof(*UTN_USERFirst_Hardware_Serial)) {
804 unsigned int i;
805 for (i = 0; i < array_size(UTN_USERFirst_Hardware_Serial); i++)
806 {
807 if (0 == memcmp(UTN_USERFirst_Hardware_Serial[i],
808 serial_ptr, sizeof(*UTN_USERFirst_Hardware_Serial)))
809 {
810 SecPVCSetResult(pvc, key, 0, kCFBooleanFalse);
811 CFReleaseSafe(serial);
812 return;
813 }
814 }
815 }
816 CFRelease(serial);
817 }
818 }
819
820 SecOTAPKIRef otapkiRef = SecOTAPKICopyCurrentOTAPKIRef();
821 if (NULL != otapkiRef)
822 {
823 CFSetRef blackListedKeys = SecOTAPKICopyBlackListSet(otapkiRef);
824 CFRelease(otapkiRef);
825 if (NULL != blackListedKeys)
826 {
827 /* Check for blacklisted intermediates keys. */
828 CFDataRef dgst = SecCertificateCopyPublicKeySHA1Digest(cert);
829 if (dgst)
830 {
831 /* Check dgst against blacklist. */
832 if (CFSetContainsValue(blackListedKeys, dgst))
833 {
834 SecPVCSetResult(pvc, key, 0, kCFBooleanFalse);
835 }
836 CFRelease(dgst);
837 }
838 CFRelease(blackListedKeys);
839 }
840 }
841 }
842
843 static void SecPolicyCheckGrayListedLeaf(SecPVCRef pvc, CFStringRef key)
844 {
845 SecOTAPKIRef otapkiRef = SecOTAPKICopyCurrentOTAPKIRef();
846 if (NULL != otapkiRef)
847 {
848 CFSetRef grayListedKeys = SecOTAPKICopyGrayList(otapkiRef);
849 CFRelease(otapkiRef);
850 if (NULL != grayListedKeys)
851 {
852 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, 0);
853
854 CFDataRef dgst = SecCertificateCopyPublicKeySHA1Digest(cert);
855 if (dgst)
856 {
857 /* Check dgst against gray. */
858 if (CFSetContainsValue(grayListedKeys, dgst))
859 {
860 SecPVCSetResult(pvc, key, 0, kCFBooleanFalse);
861 }
862 CFRelease(dgst);
863 }
864 CFRelease(grayListedKeys);
865 }
866 }
867 }
868
869 static void SecPolicyCheckLeafMarkerOid(SecPVCRef pvc, CFStringRef key)
870 {
871 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, 0);
872 SecPolicyRef policy = SecPVCGetPolicy(pvc);
873 CFTypeRef value = CFDictionaryGetValue(policy->_options, key);
874
875 if (!SecPolicyCheckCertLeafMarkerOid(cert, value)) {
876 // Don't use 'key' because that may be the legacy key (see <rdar://34537018>)
877 // Force because we may have gotten the legacy key instead of the new key in the policy
878 SecPVCSetResultForced(pvc, kSecPolicyCheckLeafMarkerOid, 0, kCFBooleanFalse, true);
879 }
880 }
881
882 static void SecPolicyCheckLeafMarkerOidWithoutValueCheck(SecPVCRef pvc, CFStringRef key)
883 {
884 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, 0);
885 SecPolicyRef policy = SecPVCGetPolicy(pvc);
886 CFTypeRef value = CFDictionaryGetValue(policy->_options, key);
887
888 if (!SecPolicyCheckCertLeafMarkerOidWithoutValueCheck(cert, value)) {
889 SecPVCSetResult(pvc, key, 0, kCFBooleanFalse);
890 }
891 }
892
893
894 /*
895 * The value is a dictionary. The dictionary contains keys indicating
896 * whether the value is for Prod or QA. The values are the same as
897 * in the options dictionary for SecPolicyCheckLeafMarkerOid.
898 */
899 static void SecPolicyCheckLeafMarkersProdAndQA(SecPVCRef pvc, CFStringRef key)
900 {
901 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, 0);
902 SecPolicyRef policy = SecPVCGetPolicy(pvc);
903 CFDictionaryRef value = CFDictionaryGetValue(policy->_options, key);
904 CFTypeRef prodValue = CFDictionaryGetValue(value, kSecPolicyLeafMarkerProd);
905
906 if (!SecPolicyCheckCertLeafMarkerOid(cert, prodValue)) {
907 bool result = false;
908 if (!result) {
909 // Don't use 'key' because that may be the legacy key (see <rdar://34537018>)
910 // Force because we may have gotten the legacy key instead of the new key in the policy
911 SecPVCSetResultForced(pvc, kSecPolicyCheckLeafMarkersProdAndQA, 0, kCFBooleanFalse, true);
912 }
913 }
914 }
915
916 static void SecPolicyCheckIntermediateMarkerOid(SecPVCRef pvc, CFStringRef key)
917 {
918 CFIndex ix, count = SecPVCGetCertificateCount(pvc);
919 SecPolicyRef policy = SecPVCGetPolicy(pvc);
920 CFTypeRef value = CFDictionaryGetValue(policy->_options, key);
921
922 for (ix = 1; ix < count - 1; ix++) {
923 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix);
924 if (SecCertificateHasMarkerExtension(cert, value))
925 return;
926 }
927 // Don't use 'key' because that may be the legacy key (see <rdar://34537018>)
928 // Force because we may have gotten the legacy key instead of the new key in the policy
929 SecPVCSetResultForced(pvc, kSecPolicyCheckIntermediateMarkerOid, 0, kCFBooleanFalse, true);
930 }
931
932 static void SecPolicyCheckIntermediateMarkerOidWithoutValueCheck(SecPVCRef pvc, CFStringRef key)
933 {
934 CFIndex ix, count = SecPVCGetCertificateCount(pvc);
935 SecPolicyRef policy = SecPVCGetPolicy(pvc);
936 CFTypeRef value = CFDictionaryGetValue(policy->_options, key);
937
938 for (ix = 1; ix < count - 1; ix++) {
939 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix);
940 if (!SecPolicyCheckCertLeafMarkerOidWithoutValueCheck(cert, value)) {
941 SecPVCSetResult(pvc, key, 0, kCFBooleanFalse);
942 }
943 }
944 }
945
946 static void SecPolicyCheckIntermediateEKU(SecPVCRef pvc, CFStringRef key)
947 {
948 CFIndex ix, count = SecPVCGetCertificateCount(pvc);
949 SecPolicyRef policy = SecPVCGetPolicy(pvc);
950 CFTypeRef peku = CFDictionaryGetValue(policy->_options, key);
951
952 for (ix = 1; ix < count - 1; ix++) {
953 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix);
954 if (!SecPolicyCheckCertExtendedKeyUsage(cert, peku)) {
955 SecPVCSetResult(pvc, key, ix, kCFBooleanFalse);
956 }
957 }
958 }
959
960 static void SecPolicyCheckIntermediateOrganization(SecPVCRef pvc, CFStringRef key)
961 {
962 CFIndex ix, count = SecPVCGetCertificateCount(pvc);
963 SecPolicyRef policy = SecPVCGetPolicy(pvc);
964 CFTypeRef organization = CFDictionaryGetValue(policy->_options, key);
965
966 for (ix = 1; ix < count - 1; ix++) {
967 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix);
968 if (!SecPolicyCheckCertSubjectOrganization(cert, organization)) {
969 // Don't use 'key' because that may be the legacy key (see <rdar://34537018>)
970 // Force because we may have gotten the legacy key instead of the new key in the policy
971 SecPVCSetResultForced(pvc, kSecPolicyCheckIntermediateOrganization, ix, kCFBooleanFalse, true);
972 }
973 }
974 }
975
976 static void SecPolicyCheckIntermediateCountry(SecPVCRef pvc, CFStringRef key)
977 {
978 CFIndex ix, count = SecPVCGetCertificateCount(pvc);
979 SecPolicyRef policy = SecPVCGetPolicy(pvc);
980 CFTypeRef country = CFDictionaryGetValue(policy->_options, key);
981
982 for (ix = 1; ix < count - 1; ix++) {
983 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix);
984 if (!SecPolicyCheckCertSubjectCountry(cert, country)) {
985 // Don't use 'key' because that may be the legacy key (see <rdar://34537018>)
986 // Force because we may have gotten the legacy key instead of the new key in the policy
987 SecPVCSetResultForced(pvc, kSecPolicyCheckIntermediateCountry, ix, kCFBooleanFalse, true);
988 }
989 }
990 }
991
992 /****************************************************************************
993 *********************** New rfc5280 Chain Validation ***********************
994 ****************************************************************************/
995
996 #define POLICY_MAPPING 1
997 #define POLICY_SUBTREES 1
998
999 /* rfc5280 basic cert processing. */
1000 static void SecPolicyCheckBasicCertificateProcessing(SecPVCRef pvc,
1001 CFStringRef key) {
1002 /* Inputs */
1003 //cert_path_t path;
1004 CFIndex count = SecPVCGetCertificateCount(pvc);
1005 SecCertificatePathVCRef path = SecPathBuilderGetPath(pvc->builder);
1006 /* 64 bits cast: worst case here is we truncate the number of cert, and the validation may fail */
1007 assert((unsigned long)count<=UINT32_MAX); /* Debug check. Correct as long as CFIndex is long */
1008 uint32_t n = (uint32_t)count;
1009
1010 bool is_anchored = SecPathBuilderIsAnchored(pvc->builder);
1011 bool is_anchor_trusted = false;
1012 if (is_anchored) {
1013 CFArrayRef constraints = SecCertificatePathVCGetUsageConstraintsAtIndex(path, n - 1);
1014 if (CFArrayGetCount(constraints) == 0) {
1015 /* Given that the path builder has already indicated the last cert in this chain has
1016 * trust set on it, empty constraints means trusted. */
1017 is_anchor_trusted = true;
1018 } else {
1019 /* Determine whether constraints say to trust this cert for this PVC. */
1020 SecTrustSettingsResult tsResult = SecPVCGetTrustSettingsResult(pvc, SecCertificatePathVCGetCertificateAtIndex(path, n - 1),
1021 constraints);
1022 if (tsResult == kSecTrustSettingsResultTrustRoot || tsResult == kSecTrustSettingsResultTrustAsRoot) {
1023 is_anchor_trusted = true;
1024 }
1025 }
1026 }
1027
1028 if (is_anchor_trusted) {
1029 /* If the anchor is trusted we don't process the last cert in the
1030 chain (root). */
1031 n--;
1032 } else {
1033 Boolean isSelfSigned = false;
1034 (void) SecCertificateIsSelfSigned(SecCertificatePathVCGetCertificateAtIndex(path, n - 1), &isSelfSigned);
1035 if (isSelfSigned) {
1036 /* Add a detail for the root not being trusted. */
1037 if (!SecPVCSetResultForced(pvc, kSecPolicyCheckAnchorTrusted,
1038 n - 1, kCFBooleanFalse, true)) {
1039 return;
1040 }
1041 } else {
1042 /* Add a detail for the missing intermediate. */
1043 if (!SecPVCSetResultForced(pvc, kSecPolicyCheckMissingIntermediate,
1044 n - 1, kCFBooleanFalse, true)) {
1045 return;
1046 }
1047 }
1048 }
1049
1050 CFAbsoluteTime verify_time = SecPVCGetVerifyTime(pvc);
1051 //policy_set_t user_initial_policy_set = NULL;
1052 //trust_anchor_t anchor;
1053
1054 /* Initialization */
1055 #if POLICY_SUBTREES
1056 CFMutableArrayRef permitted_subtrees = NULL;
1057 CFMutableArrayRef excluded_subtrees = NULL;
1058 /* set the initial subtrees to the trusted anchor's subtrees, if it has them */
1059 SecCertificateRef anchor = SecCertificatePathVCGetRoot(path);
1060 CFArrayRef anchor_permitted_subtrees = SecCertificateGetPermittedSubtrees(anchor);
1061 if (is_anchor_trusted && anchor_permitted_subtrees) {
1062 permitted_subtrees = CFArrayCreateMutableCopy(NULL, 0, anchor_permitted_subtrees);
1063 } else {
1064 permitted_subtrees = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
1065 }
1066
1067 CFArrayRef anchor_excluded_subtrees = SecCertificateGetExcludedSubtrees(anchor);
1068 if (is_anchor_trusted && anchor_excluded_subtrees) {
1069 excluded_subtrees = CFArrayCreateMutableCopy(NULL, 0, anchor_excluded_subtrees);
1070 } else {
1071 excluded_subtrees = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
1072 }
1073
1074 require_action_quiet(permitted_subtrees != NULL, errOut,
1075 SecPVCSetResultForced(pvc, kSecPolicyCheckNameConstraints, 0, kCFBooleanFalse, true));
1076 require_action_quiet(excluded_subtrees != NULL, errOut,
1077 SecPVCSetResultForced(pvc, kSecPolicyCheckNameConstraints, 0, kCFBooleanFalse, true));
1078 #endif
1079
1080 if (!SecCertificatePathVCVerifyPolicyTree(path, is_anchor_trusted)) {
1081 if (!SecPVCSetResultForced(pvc, kSecPolicyCheckPolicyConstraints, 0, kCFBooleanFalse, true)) {
1082 goto errOut;
1083 }
1084 }
1085
1086 #if 0
1087 /* Path builder ensures we only get cert chains with proper issuer
1088 chaining with valid signatures along the way. */
1089 algorithm_id_t working_public_key_algorithm = anchor->public_key_algorithm;
1090 SecKeyRef working_public_key = anchor->public_key;
1091 x500_name_t working_issuer_name = anchor->issuer_name;
1092 #endif
1093 uint32_t i, max_path_length = n;
1094 SecCertificateRef cert = NULL;
1095 for (i = 1; i <= n; ++i) {
1096 /* Process Cert */
1097 cert = SecPVCGetCertificateAtIndex(pvc, n - i);
1098 bool is_self_issued = SecCertificatePathVCIsCertificateAtIndexSelfIssued(SecPathBuilderGetPath(pvc->builder), n - i);
1099
1100 /* (a) Verify the basic certificate information. */
1101 /* @@@ Ensure that cert was signed with working_public_key_algorithm
1102 using the working_public_key and the working_public_key_parameters. */
1103
1104 /* Already done by chain builder. */
1105 if (!SecCertificateIsValid(cert, verify_time)) {
1106 if (!SecPVCSetResult(pvc, kSecPolicyCheckTemporalValidity, n - i, kCFBooleanFalse)) {
1107 goto errOut;
1108 }
1109 }
1110 if (SecCertificateIsWeakKey(cert)) {
1111 if (!SecPVCSetResult(pvc, kSecPolicyCheckWeakKeySize, n - i, kCFBooleanFalse)) {
1112 goto errOut;
1113 }
1114 }
1115 if (!SecPolicyCheckCertWeakSignature(cert, NULL)) {
1116 if (!SecPVCSetResult(pvc, kSecPolicyCheckWeakSignature, n - i, kCFBooleanFalse)) {
1117 goto errOut;
1118 }
1119 }
1120
1121 /* @@@ cert.issuer == working_issuer_name. */
1122
1123 #if POLICY_SUBTREES
1124 /* (b) (c) */
1125 if (!is_self_issued || i == n) {
1126 bool found = false;
1127 /* Verify certificate Subject Name and SubjectAltNames are not within any of the excluded_subtrees */
1128 if(excluded_subtrees && CFArrayGetCount(excluded_subtrees)) {
1129 if ((errSecSuccess != SecNameContraintsMatchSubtrees(cert, excluded_subtrees, &found, false)) || found) {
1130 secnotice("policy", "name in excluded subtrees");
1131 if(!SecPVCSetResultForced(pvc, kSecPolicyCheckNameConstraints, n - i, kCFBooleanFalse, true)) { goto errOut; }
1132 }
1133 }
1134 /* Verify certificate Subject Name and SubjectAltNames are within the permitted_subtrees */
1135 if(permitted_subtrees && CFArrayGetCount(permitted_subtrees)) {
1136 if ((errSecSuccess != SecNameContraintsMatchSubtrees(cert, permitted_subtrees, &found, true)) || !found) {
1137 secnotice("policy", "name not in permitted subtrees");
1138 if(!SecPVCSetResultForced(pvc, kSecPolicyCheckNameConstraints, n - i, kCFBooleanFalse, true)) { goto errOut; }
1139 }
1140 }
1141 }
1142 #endif
1143 /* (d) (e) (f) handled by SecCertificatePathVCVerifyPolicyTree */
1144
1145 /* If Last Cert in Path */
1146 if (i == n)
1147 break;
1148
1149 /* Prepare for Next Cert */
1150 /* (a) (b) Done by SecCertificatePathVCVerifyPolicyTree */
1151 /* (c)(d)(e)(f) Done by SecPathBuilderGetNext and SecCertificatePathVCVerify */
1152 #if POLICY_SUBTREES
1153 /* (g) If a name constraints extension is included in the certificate, modify the permitted_subtrees and excluded_subtrees state variables.
1154 */
1155 CFArrayRef permitted_subtrees_in_cert = SecCertificateGetPermittedSubtrees(cert);
1156 if (permitted_subtrees_in_cert) {
1157 SecNameConstraintsIntersectSubtrees(permitted_subtrees, permitted_subtrees_in_cert);
1158 }
1159
1160 // could do something smart here to avoid inserting the exact same constraint
1161 CFArrayRef excluded_subtrees_in_cert = SecCertificateGetExcludedSubtrees(cert);
1162 if (excluded_subtrees_in_cert) {
1163 CFIndex num_trees = CFArrayGetCount(excluded_subtrees_in_cert);
1164 CFRange range = { 0, num_trees };
1165 CFArrayAppendArray(excluded_subtrees, excluded_subtrees_in_cert, range);
1166 }
1167 #endif
1168 /* (h), (i), (j) done by SecCertificatePathVCVerifyPolicyTree */
1169
1170 /* (k) Checked in chain builder pre signature verify already. SecPVCParentCertificateChecks */
1171
1172 /* (l) */
1173 if (!is_self_issued) {
1174 if (max_path_length > 0) {
1175 max_path_length--;
1176 } else {
1177 /* max_path_len exceeded, illegal. */
1178 if (!SecPVCSetResultForced(pvc, kSecPolicyCheckBasicConstraintsPathLen,
1179 n - i, kCFBooleanFalse, true)) {
1180 goto errOut;
1181 }
1182 }
1183 }
1184 /* (m) */
1185 const SecCEBasicConstraints *bc = SecCertificateGetBasicConstraints(cert);
1186 if (bc && bc->pathLenConstraintPresent
1187 && bc->pathLenConstraint < max_path_length) {
1188 max_path_length = bc->pathLenConstraint;
1189 }
1190
1191 /* (n) If a key usage extension is present, verify that the keyCertSign bit is set. */
1192 /* Checked in chain builder pre signature verify already. SecPVCParentCertificateChecks */
1193
1194 /* (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. */
1195 if (SecCertificateHasUnknownCriticalExtension(cert)) {
1196 /* Certificate contains one or more unknown critical extensions. */
1197 if (!SecPVCSetResult(pvc, kSecPolicyCheckCriticalExtensions, n - i, kCFBooleanFalse)) {
1198 goto errOut;
1199 }
1200 }
1201
1202 if (SecCertificateGetUnparseableKnownExtension(cert) != kCFNotFound) {
1203 /* Certificate contains one or more known exensions where parsing failed. */
1204 if (!SecPVCSetResultForced(pvc, kSecPolicyCheckUnparseableExtension, n-i, kCFBooleanFalse, true)) {
1205 goto errOut;
1206 }
1207 }
1208
1209 } /* end loop over certs in path */
1210 /* Wrap up */
1211 /* (a) (b) done by SecCertificatePathVCVerifyPolicyTree */
1212 /* (c) */
1213 /* (d) */
1214 /* 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
1215 working_public_key_algorithm are different, set the working_public_key_parameters to null. */
1216 /* (e) */
1217 /* (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. */
1218 if (SecCertificateHasUnknownCriticalExtension(cert)) {
1219 /* Certificate contains one or more unknown critical extensions. */
1220 if (!SecPVCSetResult(pvc, kSecPolicyCheckCriticalExtensions, 0, kCFBooleanFalse)) {
1221 goto errOut;
1222 }
1223 }
1224
1225 if (SecCertificateGetUnparseableKnownExtension(cert) != kCFNotFound) {
1226 /* Certificate contains one or more known exensions where parsing failed. */
1227 if (!SecPVCSetResultForced(pvc, kSecPolicyCheckUnparseableExtension, 0, kCFBooleanFalse, true)) {
1228 goto errOut;
1229 }
1230 }
1231 /* (g) done by SecCertificatePathVCVerifyPolicyTree */
1232
1233 errOut:
1234 CFReleaseNull(permitted_subtrees);
1235 CFReleaseNull(excluded_subtrees);
1236 }
1237
1238 static policy_set_t policies_for_cert(SecCertificateRef cert) {
1239 policy_set_t policies = NULL;
1240 const SecCECertificatePolicies *cp =
1241 SecCertificateGetCertificatePolicies(cert);
1242 size_t policy_ix, policy_count = cp ? cp->numPolicies : 0;
1243 for (policy_ix = 0; policy_ix < policy_count; ++policy_ix) {
1244 policy_set_add(&policies, &cp->policies[policy_ix].policyIdentifier);
1245 }
1246 return policies;
1247 }
1248
1249 static void SecPolicyCheckEV(SecPVCRef pvc,
1250 CFStringRef key) {
1251 CFIndex ix, count = SecPVCGetCertificateCount(pvc);
1252 policy_set_t valid_policies = NULL;
1253
1254 /* 6.1.7. Key Usage Purposes */
1255 if (count) {
1256 CFAbsoluteTime jul2016 = 489024000;
1257 SecCertificateRef leaf = SecPVCGetCertificateAtIndex(pvc, 0);
1258 if (SecCertificateNotValidBefore(leaf) > jul2016 && count < 3) {
1259 /* Root CAs may not sign subscriber certificates after 30 June 2016. */
1260 if (SecPVCSetResultForced(pvc, key,
1261 0, kCFBooleanFalse, true)) {
1262 return;
1263 }
1264 }
1265 }
1266
1267 for (ix = 0; ix < count; ++ix) {
1268 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix);
1269 policy_set_t policies = policies_for_cert(cert);
1270 if (ix == 0) {
1271 /* Subscriber */
1272 /* anyPolicy in the leaf isn't allowed for EV, so only init
1273 valid_policies if we have real policies. */
1274 if (!policy_set_contains(policies, &oidAnyPolicy)) {
1275 valid_policies = policies;
1276 policies = NULL;
1277 }
1278 } else if (ix < count - 1) {
1279 /* Subordinate CA */
1280 if (!SecPolicySubordinateCACertificateCouldBeEV(cert)) {
1281 secnotice("ev", "subordinate certificate is not ev");
1282 if (SecPVCSetResultForced(pvc, key,
1283 ix, kCFBooleanFalse, true)) {
1284 policy_set_free(valid_policies);
1285 policy_set_free(policies);
1286 return;
1287 }
1288 }
1289 policy_set_intersect(&valid_policies, policies);
1290 } else {
1291 /* Root CA */
1292 if (!SecPolicyRootCACertificateIsEV(cert, valid_policies)) {
1293 secnotice("ev", "anchor certificate is not ev");
1294 if (SecPVCSetResultForced(pvc, key,
1295 ix, kCFBooleanFalse, true)) {
1296 policy_set_free(valid_policies);
1297 policy_set_free(policies);
1298 return;
1299 }
1300 }
1301 }
1302 policy_set_free(policies);
1303 if (!valid_policies) {
1304 secnotice("ev", "valid_policies set is empty: chain not ev");
1305 /* If we ever get into a state where no policies are valid anymore
1306 this can't be an ev chain. */
1307 if (SecPVCSetResultForced(pvc, key,
1308 ix, kCFBooleanFalse, true)) {
1309 return;
1310 }
1311 }
1312 }
1313
1314 policy_set_free(valid_policies);
1315
1316 /* (a) EV Subscriber Certificates Each EV Certificate issued by the CA to a
1317 Subscriber MUST contain an OID defined by the CA in the certificate’s
1318 certificatePolicies extension that: (i) indicates which CA policy statement relates
1319 to that certificate, (ii) asserts the CA’s adherence to and compliance with these
1320 Guidelines, and (iii), by pre-agreement with the Application Software Vendor,
1321 marks the certificate as being an EV Certificate.
1322 (b) EV Subordinate CA Certificates
1323 (1) Certificates issued to Subordinate CAs that are not controlled by the issuing
1324 CA MUST contain one or more OIDs defined by the issuing CA that
1325 explicitly identify the EV Policies that are implemented by the Subordinate
1326 CA;
1327 (2) Certificates issued to Subordinate CAs that are controlled by the Root CA
1328 MAY contain the special anyPolicy OID (2.5.29.32.0).
1329 (c) Root CA Certificates Root CA Certificates SHOULD NOT contain the
1330 certificatePolicies or extendedKeyUsage extensions.
1331 */
1332 }
1333
1334 static bool checkPolicyOidData(SecPVCRef pvc, CFDataRef oid) {
1335 CFIndex ix, count = SecPVCGetCertificateCount(pvc);
1336 DERItem key_value;
1337 key_value.data = (DERByte *)CFDataGetBytePtr(oid);
1338 key_value.length = (DERSize)CFDataGetLength(oid);
1339
1340 for (ix = 0; ix < count; ix++) {
1341 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix);
1342 policy_set_t policies = policies_for_cert(cert);
1343
1344 if (policy_set_contains(policies, &key_value)) {
1345 policy_set_free(policies);
1346 return true;
1347 }
1348 policy_set_free(policies);
1349 }
1350 return false;
1351 }
1352
1353 static void SecPolicyCheckCertificatePolicy(SecPVCRef pvc, CFStringRef key)
1354 {
1355 SecPolicyRef policy = SecPVCGetPolicy(pvc);
1356 CFTypeRef value = CFDictionaryGetValue(policy->_options, key);
1357 bool result = false;
1358
1359 if (CFGetTypeID(value) == CFDataGetTypeID())
1360 {
1361 result = checkPolicyOidData(pvc, value);
1362 } else if (CFGetTypeID(value) == CFStringGetTypeID()) {
1363 CFDataRef dataOid = SecCertificateCreateOidDataFromString(NULL, value);
1364 if (dataOid) {
1365 result = checkPolicyOidData(pvc, dataOid);
1366 CFRelease(dataOid);
1367 }
1368 }
1369 if(!result) {
1370 SecPVCSetResult(pvc, key, 0, kCFBooleanFalse);
1371 }
1372 }
1373
1374
1375 static void SecPolicyCheckRevocation(SecPVCRef pvc,
1376 CFStringRef key) {
1377 SecPolicyRef policy = SecPVCGetPolicy(pvc);
1378 CFTypeRef value = CFDictionaryGetValue(policy->_options, key);
1379 if (isString(value)) {
1380 SecPathBuilderSetRevocationMethod(pvc->builder, value);
1381 }
1382 }
1383
1384 static void SecPolicyCheckRevocationResponseRequired(SecPVCRef pvc,
1385 CFStringRef key) {
1386 pvc->require_revocation_response = true;
1387 secdebug("policy", "revocation response required");
1388 }
1389
1390 static void SecPolicyCheckRevocationOnline(SecPVCRef pvc, CFStringRef key) {
1391 SecPathBuilderSetCheckRevocationOnline(pvc->builder);
1392 }
1393
1394 static void SecPolicyCheckRevocationIfTrusted(SecPVCRef pvc, CFStringRef key) {
1395 SecPathBuilderSetCheckRevocationIfTrusted(pvc->builder);
1396 }
1397
1398 static void SecPolicyCheckNoNetworkAccess(SecPVCRef pvc,
1399 CFStringRef key) {
1400 SecPolicyRef policy = SecPVCGetPolicy(pvc);
1401 CFTypeRef value = CFDictionaryGetValue(policy->_options, key);
1402 if (value == kCFBooleanTrue) {
1403 SecPathBuilderSetCanAccessNetwork(pvc->builder, false);
1404 } else {
1405 SecPathBuilderSetCanAccessNetwork(pvc->builder, true);
1406 }
1407 }
1408
1409 static void SecPolicyCheckWeakKeySize(SecPVCRef pvc,
1410 CFStringRef key) {
1411 CFIndex ix, count = SecPVCGetCertificateCount(pvc);
1412 for (ix = 0; ix < count; ++ix) {
1413 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix);
1414 if (cert && SecCertificateIsWeakKey(cert)) {
1415 /* Intermediate certificate has a weak key. */
1416 if (!SecPVCSetResult(pvc, key, ix, kCFBooleanFalse))
1417 return;
1418 }
1419 }
1420 }
1421
1422 static void SecPolicyCheckKeySize(SecPVCRef pvc, CFStringRef key) {
1423 CFIndex ix, count = SecPVCGetCertificateCount(pvc);
1424 SecPolicyRef policy = SecPVCGetPolicy(pvc);
1425 CFDictionaryRef keySizes = CFDictionaryGetValue(policy->_options, key);
1426 SecCertificateRef leaf = SecPVCGetCertificateAtIndex(pvc, 0);
1427
1428 /* Don't check key size for user-anchored leafs */
1429 if (SecPVCIsAnchorPerConstraints(pvc, kSecUserAnchorSource, leaf)) {
1430 return;
1431 }
1432 #if TARGET_OS_OSX
1433 if (SecPVCIsAnchorPerConstraints(pvc, kSecLegacyAnchorSource, leaf)) {
1434 return;
1435 }
1436 #endif
1437
1438 for (ix = 0; ix < count; ++ix) {
1439 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix);
1440 if (!SecCertificateIsAtLeastMinKeySize(cert, keySizes)) {
1441 if (!SecPVCSetResult(pvc, key, ix, kCFBooleanFalse))
1442 return;
1443 }
1444 }
1445 }
1446
1447 static void SecPolicyCheckWeakSignature(SecPVCRef pvc, CFStringRef key) {
1448 CFIndex ix, count = SecPVCGetCertificateCount(pvc);
1449 SecPolicyRef policy = SecPVCGetPolicy(pvc);
1450 CFTypeRef pvcValue = CFDictionaryGetValue(policy->_options, key);
1451 for (ix = 0; ix < count; ++ix) {
1452 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix);
1453 if (!SecPolicyCheckCertWeakSignature(cert, pvcValue)) {
1454 if (!SecPVCSetResult(pvc, key, ix, kCFBooleanFalse))
1455 return;
1456 }
1457 }
1458 }
1459
1460 static void SecPolicyCheckSignatureHashAlgorithms(SecPVCRef pvc,
1461 CFStringRef key) {
1462 CFIndex ix = 0, count = SecPVCGetCertificateCount(pvc);
1463
1464 /* Ignore (a non-self-signed) anchor if it's trusted by the user */
1465 bool userAnchored = SecPVCIsAnchorPerConstraints(pvc, kSecUserAnchorSource, SecPVCGetCertificateAtIndex(pvc, count - 1));
1466 #if TARGET_OS_OSX
1467 userAnchored = userAnchored || SecPVCIsAnchorPerConstraints(pvc, kSecLegacyAnchorSource,
1468 SecPVCGetCertificateAtIndex(pvc, count - 1));
1469 #endif
1470 if (SecPathBuilderIsAnchored(pvc->builder) && userAnchored) {
1471 count--;
1472 }
1473
1474 SecPolicyRef policy = SecPVCGetPolicy(pvc);
1475 CFSetRef disallowedHashAlgorithms = CFDictionaryGetValue(policy->_options, key);
1476 while (ix < count) {
1477 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix);
1478 /* note that these checks skip self-signed certs */
1479 if (!SecPolicyCheckCertSignatureHashAlgorithms(cert, disallowedHashAlgorithms)) {
1480 if (!SecPVCSetResult(pvc, key, ix, kCFBooleanFalse))
1481 return;
1482 }
1483 ix++;
1484 }
1485 }
1486
1487 static bool leaf_is_on_weak_hash_whitelist(SecPVCRef pvc) {
1488 SecCertificateRef leaf = SecPVCGetCertificateAtIndex(pvc, 0);
1489 require_quiet(leaf, out);
1490
1491 /* And now a special snowflake from our tests */
1492
1493 /* subject:/C=AU/ST=NSW/L=St Leonards/O=VODAFONE HUTCHISON AUSTRALIA PTY LIMITED/OU=Technology Shared Services/CN=mybill.vodafone.com.au */
1494 /* issuer :/C=UK/O=Vodafone Group/CN=Vodafone (Corporate Services 2009) */
1495 /* Not After : May 26 09:37:50 2017 GMT */
1496 static const uint8_t vodafone[] = {
1497 0xde, 0x77, 0x63, 0x97, 0x79, 0x47, 0xee, 0x6e, 0xc1, 0x3a,
1498 0x7b, 0x3b, 0xad, 0x43, 0x88, 0xa9, 0x66, 0x59, 0xa8, 0x18
1499 };
1500
1501 CFDataRef leafFingerprint = SecCertificateGetSHA1Digest(leaf);
1502 require_quiet(leafFingerprint, out);
1503 const unsigned int len = 20;
1504 const uint8_t *dp = CFDataGetBytePtr(leafFingerprint);
1505 if (dp && (!memcmp(vodafone, dp, len))) {
1506 return true;
1507 }
1508
1509 out:
1510 return false;
1511 }
1512
1513 static bool SecPVCKeyIsConstraintPolicyOption(SecPVCRef pvc, CFStringRef key);
1514
1515 static void SecPolicyCheckSystemTrustedWeakHash(SecPVCRef pvc,
1516 CFStringRef key) {
1517 CFIndex ix, count = SecPVCGetCertificateCount(pvc);
1518
1519 Boolean keyInPolicy = false;
1520 CFArrayRef policies = pvc->policies;
1521 CFIndex policyIX, policyCount = CFArrayGetCount(policies);
1522 for (policyIX = 0; policyIX < policyCount; ++policyIX) {
1523 SecPolicyRef policy = (SecPolicyRef)CFArrayGetValueAtIndex(policies, policyIX);
1524 if (policy && CFDictionaryContainsKey(policy->_options, key)) {
1525 keyInPolicy = true;
1526 }
1527 }
1528
1529 /* We only enforce this check when *both* of the following are true:
1530 * 1. One of the certs in the path has this usage constraint, and
1531 * 2. One of the policies in the PVC has this key
1532 * (As compared to normal policy options which require only one to be true..) */
1533 require_quiet(SecPVCKeyIsConstraintPolicyOption(pvc, key) &&
1534 keyInPolicy, out);
1535
1536 /* Ignore the anchor if it's trusted */
1537 if (SecPathBuilderIsAnchored(pvc->builder)) {
1538 count--;
1539 }
1540 for (ix = 0; ix < count; ++ix) {
1541 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix);
1542 if (SecCertificateIsWeakHash(cert)) {
1543 if (!leaf_is_on_weak_hash_whitelist(pvc)) {
1544 if (!SecPVCSetResult(pvc, key, ix, kCFBooleanFalse)) {
1545 return;
1546 }
1547 }
1548 }
1549 }
1550 out:
1551 return;
1552 }
1553
1554 static void SecPolicyCheckSystemTrustedWeakKey(SecPVCRef pvc,
1555 CFStringRef key) {
1556 CFIndex ix, count = SecPVCGetCertificateCount(pvc);
1557
1558 Boolean keyInPolicy = false;
1559 CFArrayRef policies = pvc->policies;
1560 CFIndex policyIX, policyCount = CFArrayGetCount(policies);
1561 for (policyIX = 0; policyIX < policyCount; ++policyIX) {
1562 SecPolicyRef policy = (SecPolicyRef)CFArrayGetValueAtIndex(policies, policyIX);
1563 if (policy && CFDictionaryContainsKey(policy->_options, key)) {
1564 keyInPolicy = true;
1565 }
1566 }
1567
1568 /* We only enforce this check when *both* of the following are true:
1569 * 1. One of the certs in the path has this usage constraint, and
1570 * 2. One of the policies in the PVC has this key
1571 * (As compared to normal policy options which require only one to be true..) */
1572 require_quiet(SecPVCKeyIsConstraintPolicyOption(pvc, key) &&
1573 keyInPolicy, out);
1574
1575 /* Ignore the anchor if it's trusted */
1576 if (SecPathBuilderIsAnchored(pvc->builder)) {
1577 count--;
1578 }
1579 for (ix = 0; ix < count; ++ix) {
1580 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix);
1581 if (!SecCertificateIsStrongKey(cert)) {
1582 if (!SecPVCSetResult(pvc, key, ix, kCFBooleanFalse)) {
1583 return;
1584 }
1585 }
1586
1587 } /* Cert loop */
1588 out:
1589 return;
1590 }
1591
1592 static void SecPolicyCheckPinningRequired(SecPVCRef pvc, CFStringRef key) {
1593 /* Pinning is disabled on the system, skip. */
1594 if (SecIsInternalRelease()) {
1595 if (CFPreferencesGetAppBooleanValue(CFSTR("AppleServerAuthenticationNoPinning"),
1596 CFSTR("com.apple.security"), NULL)) {
1597 return;
1598 }
1599 }
1600
1601 CFArrayRef policies = pvc->policies;
1602 CFIndex policyIX, policyCount = CFArrayGetCount(policies);
1603 for (policyIX = 0; policyIX < policyCount; ++policyIX) {
1604 SecPolicyRef policy = (SecPolicyRef)CFArrayGetValueAtIndex(policies, policyIX);
1605 CFStringRef policyName = SecPolicyGetName(policy);
1606 if (CFEqualSafe(policyName, kSecPolicyNameSSLServer)) {
1607 /* policy required pinning, but we didn't use a pinning policy */
1608 if (!SecPVCSetResult(pvc, key, 0, kCFBooleanFalse)) {
1609 return;
1610 }
1611 }
1612 }
1613 }
1614
1615 static bool is_configured_test_system_root(SecCertificateRef root, CFStringRef preference) {
1616 if (!SecIsInternalRelease()) {
1617 return false;
1618 }
1619 bool result = false;
1620 CFDataRef rootHash = SecCertificateCopySHA256Digest(root);
1621 CFTypeRef value = CFPreferencesCopyAppValue(preference, CFSTR("com.apple.security"));
1622 require_quiet(isData(value), out);
1623 require_quiet(CFEqual(rootHash, value), out);
1624 result = true;
1625
1626 out:
1627 CFReleaseNull(value);
1628 CFReleaseNull(rootHash);
1629 return result;
1630 }
1631
1632 static bool is_ct_excepted_domain(CFStringRef hostname, CFStringRef exception) {
1633 if (kCFCompareEqualTo == CFStringCompare(exception, hostname, kCFCompareCaseInsensitive)) {
1634 /* exact match */
1635 return true;
1636 } else if (CFStringHasPrefix(exception, CFSTR("."))) {
1637 /* subdomains */
1638 CFIndex elength = CFStringGetLength(exception);
1639 CFIndex hlength = CFStringGetLength(hostname);
1640 if (hlength > elength) {
1641 CFRange compareRange = { hlength - elength, elength };
1642 if (kCFCompareEqualTo == CFStringCompareWithOptions(hostname, exception, compareRange, kCFCompareCaseInsensitive)) {
1643 return true;
1644 }
1645 } else if (hlength + 1 == elength) {
1646 CFRange compareRange = { 1, hlength };
1647 if (kCFCompareEqualTo == CFStringCompareWithOptions(exception, hostname, compareRange, kCFCompareCaseInsensitive)) {
1648 return true;
1649 }
1650 }
1651 }
1652 return false;
1653 }
1654
1655 static OSStatus is_subtree_dn_with_org(void *context, SecCEGeneralNameType gnType, const DERItem *generalName) {
1656 if (gnType != GNT_DirectoryName) {
1657 return errSecInternal;
1658 }
1659
1660 DERDecodedInfo subtreeName_content;
1661 if (DR_Success != DERDecodeItem(generalName, &subtreeName_content) || subtreeName_content.tag != ASN1_CONSTR_SEQUENCE) {
1662 return errSecDecode;
1663 }
1664
1665 CFArrayRef subtree_orgs = SecCertificateCopyOrganizationFromX501NameContent(&subtreeName_content.content);
1666 if (subtree_orgs) {
1667 CFReleaseNull(subtree_orgs);
1668 return errSecSuccess;
1669 }
1670 return errSecInternal;
1671 }
1672
1673 static bool has_ct_excepted_key(SecCertificatePathVCRef path, CFDictionaryRef exception) {
1674 __block bool result = false;
1675 CFDataRef exceptionHash = CFDictionaryGetValue(exception, kSecCTExceptionsSPKIHashKey);
1676
1677 /* exception for a leaf is always allowed */
1678 SecCertificateRef leaf = SecCertificatePathVCGetCertificateAtIndex(path, 0);
1679 CFDataRef spkiHash = SecCertificateCopySubjectPublicKeyInfoSHA256Digest(leaf);
1680 if (CFEqualSafe(exceptionHash, spkiHash)) {
1681 result = true;
1682 }
1683 CFReleaseNull(spkiHash);
1684
1685 if (result) { return result; }
1686
1687 /* exceptions for CAs */
1688 for (CFIndex certIX = 1; certIX < SecCertificatePathVCGetCount(path); certIX++) {
1689 SecCertificateRef ca = SecCertificatePathVCGetCertificateAtIndex(path, certIX);
1690
1691 spkiHash = SecCertificateCopySubjectPublicKeyInfoSHA256Digest(ca);
1692 if (!CFEqualSafe(exceptionHash, spkiHash)) {
1693 CFReleaseNull(spkiHash);
1694 continue;
1695 }
1696 CFReleaseNull(spkiHash);
1697
1698 /* this CA matches but exceptions for CAs have constraints */
1699 if (SecCertificateGetPermittedSubtrees(ca)) {
1700 /* Constrained CAs have to have a Distinguished Name permitted subtree with an Organization attribute */
1701 CFArrayForEach(SecCertificateGetPermittedSubtrees(ca), ^(const void *value) {
1702 CFDataRef subtree = (CFDataRef)value;
1703 const DERItem general_name = { (unsigned char *)CFDataGetBytePtr(subtree), CFDataGetLength(subtree) };
1704 DERDecodedInfo general_name_content;
1705 if (DR_Success == DERDecodeItem(&general_name, &general_name_content)) {
1706 OSStatus status = SecCertificateParseGeneralNameContentProperty(general_name_content.tag,
1707 &general_name_content.content,
1708 NULL,
1709 is_subtree_dn_with_org);
1710 if (status == errSecSuccess) {
1711 result = true;
1712 }
1713 }
1714 });
1715 }
1716
1717 if (!result) {
1718 /* The Organization attribute(s) in the CA subject have to exactly match the Organization attribute(s) in the leaf */
1719 CFArrayRef leafOrgs = SecCertificateCopyOrganization(leaf);
1720 CFArrayRef caOrgs = SecCertificateCopyOrganization(ca);
1721 if (caOrgs && leafOrgs && CFEqualSafe(leafOrgs, caOrgs)) {
1722 result = true;
1723 }
1724 CFReleaseNull(leafOrgs);
1725 CFReleaseNull(caOrgs);
1726 }
1727
1728 if (result) {
1729 break;
1730 }
1731 }
1732
1733 return result;
1734 }
1735
1736 static bool is_ct_excepted(SecPVCRef pvc) {
1737 CFDictionaryRef ct_exceptions = _SecTrustStoreCopyCTExceptions(NULL, NULL);
1738 if (!ct_exceptions) {
1739 return false;
1740 }
1741
1742 __block bool result = false;
1743 CFArrayRef domainExceptions = CFDictionaryGetValue(ct_exceptions, kSecCTExceptionsDomainsKey);
1744 if (domainExceptions) {
1745 SecPolicyRef policy = SecPVCGetPolicy(pvc);
1746 CFStringRef hostname = CFDictionaryGetValue(policy->_options, kSecPolicyCheckSSLHostname);
1747 if (hostname) {
1748 CFArrayForEach(domainExceptions, ^(const void *value) {
1749 result = result || is_ct_excepted_domain(hostname, value);
1750 });
1751 }
1752 }
1753 if (result) {
1754 secinfo("policy", "domain-based CT exception applied");
1755 CFReleaseNull(ct_exceptions);
1756 return result;
1757 }
1758
1759 CFArrayRef keyExceptions = CFDictionaryGetValue(ct_exceptions, kSecCTExceptionsCAsKey);
1760 if (keyExceptions) {
1761 __block SecCertificatePathVCRef path = SecPathBuilderGetPath(pvc->builder);
1762 CFArrayForEach(keyExceptions, ^(const void *value) {
1763 result = result || has_ct_excepted_key(path, value);
1764 });
1765 }
1766
1767 if (result) {
1768 secinfo("policy" , "key-based CT exceptions applied");
1769 }
1770
1771 CFReleaseNull(ct_exceptions);
1772 return result;
1773 }
1774
1775 /* <rdar://45466778> some Apple servers not getting certs with embedded SCTs */
1776 static bool is_ct_allowlisted_cert(SecCertificateRef leaf) {
1777 if (CFPreferencesGetAppBooleanValue(CFSTR("DisableCTAllowlist"), CFSTR("com.apple.security"), NULL) ||
1778 CFPreferencesGetAppBooleanValue(CFSTR("DisableCTAllowlistApple"), CFSTR("com.apple.security"), NULL)) {
1779 return false;
1780 }
1781
1782 /* subject:/CN=basejumper.apple.com/OU=management:idms.group.110621/O=Apple Inc./ST=California/C=US */
1783 /* issuer :/CN=Apple IST CA 2 - G1/OU=Certification Authority/O=Apple Inc./C=US */
1784 static const uint8_t basejumper_hash[] = {
1785 0x23, 0x32, 0x0b, 0x5a, 0x24, 0xd8, 0x4d, 0x27, 0x8c, 0x43, 0xc9, 0xed, 0x22, 0xed, 0x87, 0xb7,
1786 0xc5, 0x51, 0x43, 0x55, 0xa9, 0x84, 0x79, 0x5a, 0x77, 0xb9, 0xad, 0x0f, 0x88, 0x14, 0x61, 0xac,
1787 };
1788
1789 bool result = false;
1790 CFDataRef leaf_fingerprint = SecCertificateCopySHA256Digest(leaf);
1791 const uint8_t *dp = CFDataGetBytePtr(leaf_fingerprint);
1792 if (dp && !memcmp(basejumper_hash, dp, CC_SHA256_DIGEST_LENGTH)) {
1793 result = true;
1794 }
1795 CFReleaseNull(leaf_fingerprint);
1796 return result;
1797 }
1798
1799 static void SecPolicyCheckSystemTrustedCTRequired(SecPVCRef pvc) {
1800 SecCertificateSourceRef appleAnchorSource = NULL;
1801 SecOTAPKIRef otaref = SecOTAPKICopyCurrentOTAPKIRef();
1802 SecCertificatePathVCRef path = SecPathBuilderGetPath(pvc->builder);
1803 CFDictionaryRef trustedLogs = SecPathBuilderCopyTrustedLogs(pvc->builder);
1804
1805 /* Skip this check if we haven't done the CT checks yet */
1806 require_quiet(SecCertificatePathVCIsPathValidated(path), out);
1807
1808 /* We only enforce this check when all of the following are true:
1809 * 0. Kill Switch not enabled */
1810 require_quiet(!SecOTAPKIKillSwitchEnabled(otaref, kOTAPKIKillSwitchCT), out);
1811
1812 /* 1. Not a pinning policy */
1813 SecPolicyRef policy = SecPVCGetPolicy(pvc);
1814 require_quiet(CFEqualSafe(SecPolicyGetName(policy),kSecPolicyNameSSLServer), out);
1815
1816 /* 2. Device has checked in to MobileAsset for a current log list within the last 60 days.
1817 * Or the caller passed in the trusted log list. */
1818 require_quiet(SecOTAPKIAssetStalenessLessThanSeconds(otaref, kSecOTAPKIAssetStalenessDisable) || trustedLogs, out);
1819
1820 /* 3. Leaf issuance date is on or after 16 Oct 2018 at 00:00:00 AM UTC and not expired. */
1821 SecCertificateRef leaf = SecPVCGetCertificateAtIndex(pvc, 0);
1822 require_quiet(SecCertificateNotValidBefore(leaf) >= 561340800.0 &&
1823 SecCertificateIsValid(leaf, SecPVCGetVerifyTime(pvc)), out);
1824
1825 /* 4. Chain is anchored with root in the system anchor source but not the Apple anchor source
1826 * with certain excepted CAs and configurable included CAs. */
1827 CFIndex count = SecPVCGetCertificateCount(pvc);
1828 SecCertificateRef root = SecPVCGetCertificateAtIndex(pvc, count - 1);
1829 appleAnchorSource = SecMemoryCertificateSourceCreate(SecGetAppleTrustAnchors(false));
1830 require_quiet(SecPathBuilderIsAnchored(pvc->builder), out);
1831 require_quiet((SecCertificateSourceContains(kSecSystemAnchorSource, root) &&
1832 appleAnchorSource && !SecCertificateSourceContains(appleAnchorSource, root) &&
1833 !is_ct_allowlisted_cert(leaf)) ||
1834 is_configured_test_system_root(root, CFSTR("TestCTRequiredSystemRoot")), out);
1835
1836 if (!SecCertificatePathVCIsCT(path) && !is_ct_excepted(pvc)) {
1837 /* Set failure. By not using the Forced variant, we implicitly check that this
1838 * policy had this options set. */
1839 SecPVCSetResult(pvc, kSecPolicyCheckSystemTrustedCTRequired, 0, kCFBooleanFalse);
1840 }
1841
1842 out:
1843 CFReleaseNull(trustedLogs);
1844 CFReleaseNull(otaref);
1845 if (appleAnchorSource) {
1846 SecMemoryCertificateSourceDestroy(appleAnchorSource);
1847 }
1848 }
1849
1850 static bool SecPolicyCheckSystemTrustValidityPeriodMaximums(CFAbsoluteTime notBefore, CFAbsoluteTime notAfter) {
1851 CFAbsoluteTime jul2016 = 489024000.0; // 1 July 2016 00:00:00 UTC
1852 CFAbsoluteTime mar2018 = 541555200.0; // 1 March 2018 00:00:00 UTC
1853 CFAbsoluteTime sep2020 = 620611200.0; // 1 September 2020 00:00:00 UTC
1854 if (notBefore < jul2016) {
1855 /* Validity Period no greater than 60 months.
1856 60 months is no more than 5 years and 2 leap days (and 1 hour slip). */
1857 CFAbsoluteTime maxPeriod = 60*60*24*(365*5+2) + 3600;
1858 if (notAfter - notBefore > maxPeriod) {
1859 secnotice("policy", "System-trusted leaf validity period is more than 60 months");
1860 return false;
1861 }
1862 } else if (notBefore < mar2018) {
1863 /* Validity Period no greater than 39 months.
1864 39 months is no more than 3 years, 2 31-day months,
1865 1 30-day month, and 1 leap day (and 1 hour slip) */
1866 CFAbsoluteTime maxPeriod = 60*60*24*(365*3+2*31+30+1) + 3600;
1867 if (notAfter - notBefore > maxPeriod) {
1868 secnotice("policy", "System-trusted leaf validity period longer than 39 months and issued after 30 June 2016");
1869 return false;
1870 }
1871 } else if (notBefore < sep2020) {
1872 /* Validity Period no greater than 825 days (and 1 hour slip). */
1873 CFAbsoluteTime maxPeriod = 60*60*24*825 + 3600;
1874 if (notAfter - notBefore > maxPeriod) {
1875 secnotice("policy", "System-trusted leaf validity period longer than 825 days and issued on or after 1 March 2018");
1876 return false;
1877 }
1878 } else {
1879 /* Validity Period no greater than 398 days (and no slip). HT211025 */
1880 CFAbsoluteTime maxPeriod = 60*60*24*398;
1881 if (notAfter - notBefore > maxPeriod) {
1882 secnotice("policy", "System-trusted leaf validity period longer than 398 days and issued on or after 1 September 2020");
1883 return false;
1884 }
1885 }
1886 return true;
1887 }
1888
1889 static bool SecPolicyCheckOtherTrustValidityPeriodMaximums(CFAbsoluteTime notBefore, CFAbsoluteTime notAfter) {
1890 /* Check whether we will enforce the validity period maximum for a non-system trusted leaf. */
1891 if (SecIsInternalRelease()) {
1892 if (CFPreferencesGetAppBooleanValue(CFSTR("IgnoreMaximumValidityPeriod"),
1893 CFSTR("com.apple.security"), NULL)) {
1894 return true;
1895 }
1896 }
1897 CFAbsoluteTime jul2019 = 583628400.0; // 1 July 2019 00:00:00 UTC
1898 if (notBefore > jul2019) {
1899 /* Validity Period no greater than 825 days (and 1 hour slip). */
1900 CFAbsoluteTime maxPeriod = 60*60*24*825 + 3600;
1901 if (notAfter - notBefore > maxPeriod) {
1902 secnotice("policy", "Non-system-trusted leaf validity period longer than 825 days and issued on or after 1 July 2019");
1903 return false;
1904 }
1905 }
1906 return true;
1907 }
1908
1909 static void SecPolicyCheckValidityPeriodMaximums(SecPVCRef pvc, CFStringRef key) {
1910 SecCertificateRef leaf = SecPVCGetCertificateAtIndex(pvc, 0);
1911 CFAbsoluteTime notAfter = SecCertificateNotValidAfter(leaf);
1912 CFAbsoluteTime notBefore = SecCertificateNotValidBefore(leaf);
1913
1914 CFIndex count = SecPVCGetCertificateCount(pvc);
1915 SecCertificateRef root = SecPVCGetCertificateAtIndex(pvc, count - 1);
1916 if (SecCertificateSourceContains(kSecSystemAnchorSource, root) || is_configured_test_system_root(root, CFSTR("TestSystemRoot"))) {
1917 if (!SecPolicyCheckSystemTrustValidityPeriodMaximums(notBefore, notAfter)) {
1918 SecPVCSetResult(pvc, key, 0, kCFBooleanFalse);
1919 }
1920 return;
1921 }
1922
1923 /* Don't check validity periods against maximums for user-anchored leafs */
1924 if (SecPVCIsAnchorPerConstraints(pvc, kSecUserAnchorSource, leaf)) {
1925 return;
1926 }
1927 #if TARGET_OS_OSX
1928 if (SecPVCIsAnchorPerConstraints(pvc, kSecLegacyAnchorSource, leaf)) {
1929 return;
1930 }
1931 #endif
1932
1933 /* all other trust */
1934 if (!SecPolicyCheckOtherTrustValidityPeriodMaximums(notBefore, notAfter)) {
1935 SecPVCSetResult(pvc, key, 0, kCFBooleanFalse);
1936 }
1937 }
1938
1939 static void SecPolicyCheckServerAuthEKU(SecPVCRef pvc, CFStringRef key) {
1940 /* The ExtendedKeyUsage check will verify a looser version of this check for all TLS server certs.
1941 * Here we want to be stricter (enforcing that there is an EKU extension and that it contains the
1942 * one true Server Auth EKU OID) for system and app anchors */
1943 SecCertificateRef leaf = SecPVCGetCertificateAtIndex(pvc, 0);
1944 CFIndex count = SecPVCGetCertificateCount(pvc);
1945 SecCertificateRef root = SecPVCGetCertificateAtIndex(pvc, count - 1);
1946 if (SecCertificateSourceContains(kSecSystemAnchorSource, root) || is_configured_test_system_root(root, CFSTR("TestSystemRoot"))) {
1947 /* all system-anchored chains must be compliant */
1948 if (!SecPolicyCheckCertExtendedKeyUsage(leaf, CFSTR("1.3.6.1.5.5.7.3.1"))) { // server auth EKU
1949 SecPVCSetResult(pvc, key, 0, kCFBooleanFalse);
1950 }
1951 /* if any subCA cert has an EKU, it must have the server auth EKU */
1952 if (count > 2) { // chain has subCAs
1953 for (int ix = 1; ix < count - 1; ix++) { // iterate through subCAs
1954 SecCertificateRef subCA = SecPVCGetCertificateAtIndex(pvc, ix);
1955 CFArrayRef eku = NULL;
1956 if ((eku = SecCertificateCopyExtendedKeyUsage(subCA)) && CFArrayGetCount(eku)) { // subCA has EKU set
1957 if (!SecPolicyCheckCertExtendedKeyUsage(subCA, CFSTR("1.3.6.1.5.5.7.3.1")) && // check server auth EKU
1958 !SecPolicyCheckCertExtendedKeyUsage(subCA, CFSTR("2.5.29.37.0"))) { // check anyEKU
1959 SecPVCSetResult(pvc, key, 0, kCFBooleanFalse);
1960 }
1961 }
1962 CFReleaseNull(eku);
1963 }
1964 }
1965 return;
1966 }
1967
1968 /* skip user/admin-anchored chains */
1969 if (SecPVCIsAnchorPerConstraints(pvc, kSecUserAnchorSource, root)) {
1970 return;
1971 }
1972 #if TARGET_OS_OSX
1973 if (SecPVCIsAnchorPerConstraints(pvc, kSecLegacyAnchorSource, root)) {
1974 return;
1975 }
1976 #endif
1977
1978
1979 /* All other anchor types must be compliant if issued on or after 1 July 2019 */
1980 CFAbsoluteTime notBefore = SecCertificateNotValidBefore(leaf);
1981 CFAbsoluteTime jul2019 = 583628400.0; // 1 July 2019 00:00:00 UTC
1982 if (notBefore > jul2019) {
1983 if (!SecPolicyCheckCertExtendedKeyUsage(leaf, CFSTR("1.3.6.1.5.5.7.3.1"))) { // server auth EKU
1984 SecPVCSetResult(pvc, key, 0, kCFBooleanFalse);
1985 }
1986 }
1987 }
1988
1989 static void SecPolicyCheckCTRequired(SecPVCRef pvc, CFStringRef key) {
1990 SecCertificatePathVCRef path = SecPathBuilderGetPath(pvc->builder);
1991 SecCertificatePathVCSetRequiresCT(path, kSecPathCTRequiredOverridable);
1992 }
1993
1994 static void SecPolicyCheckNotCA(SecPVCRef pvc, CFStringRef key) {
1995 SecCertificateRef leaf = SecPVCGetCertificateAtIndex(pvc, 0);
1996 if (SecCertificateIsCA(leaf)) {
1997 SecPVCSetResult(pvc, key, 0, kCFBooleanFalse);
1998 }
1999 }
2000
2001 static void SecPolicyCheckNonTlsCTRequired(SecPVCRef pvc, CFStringRef key) {
2002 // Skip if kill switch enabled or log list not updated
2003 SecOTAPKIRef otaref = SecOTAPKICopyCurrentOTAPKIRef();
2004 CFDictionaryRef trustedLogs = SecPathBuilderCopyTrustedLogs(pvc->builder);
2005 if (!SecOTAPKIKillSwitchEnabled(otaref, kOTAPKIKillSwitchNonTLSCT) &&
2006 (SecOTAPKIAssetStalenessLessThanSeconds(otaref, kSecOTAPKIAssetStalenessDisable) || trustedLogs)) {
2007 // Check CT against the non-TLS log list
2008 if (!SecPolicyCheckNonTlsCT(pvc)) {
2009 SecPVCSetResult(pvc, key, 0, kCFBooleanFalse);
2010 }
2011 }
2012 CFReleaseNull(otaref);
2013 CFReleaseNull(trustedLogs);
2014 }
2015
2016 void SecPolicyServerInitialize(void) {
2017 gSecPolicyLeafCallbacks = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
2018 &kCFTypeDictionaryKeyCallBacks, NULL);
2019 gSecPolicyPathCallbacks = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
2020 &kCFTypeDictionaryKeyCallBacks, NULL);
2021
2022 #undef POLICYCHECKMACRO
2023 #define __PC_ADD_CHECK_(NAME)
2024 #define __PC_ADD_CHECK_L(NAME) CFDictionaryAddValue(gSecPolicyLeafCallbacks, kSecPolicyCheck##NAME, SecPolicyCheck##NAME);
2025 #define __PC_ADD_CHECK_A(NAME) CFDictionaryAddValue(gSecPolicyPathCallbacks, kSecPolicyCheck##NAME, SecPolicyCheck##NAME);
2026
2027 #define POLICYCHECKMACRO(NAME, TRUSTRESULT, SUBTYPE, LEAFCHECK, PATHCHECK, LEAFONLY, CSSMERR, OSSTATUS) \
2028 __PC_ADD_CHECK_##LEAFCHECK(NAME) \
2029 __PC_ADD_CHECK_##PATHCHECK(NAME)
2030 #include "OSX/sec/Security/SecPolicyChecks.list"
2031
2032 /* Some of these don't follow the naming conventions but are in the Pinning DB.
2033 * <rdar://34537018> fix policy check constant values */
2034 CFDictionaryAddValue(gSecPolicyLeafCallbacks, CFSTR("CheckLeafMarkerOid"), SecPolicyCheckLeafMarkerOid);
2035 CFDictionaryAddValue(gSecPolicyLeafCallbacks, CFSTR("CheckLeafMarkersProdAndQA"), SecPolicyCheckLeafMarkersProdAndQA);
2036 CFDictionaryAddValue(gSecPolicyPathCallbacks, CFSTR("CheckIntermediateMarkerOid"), SecPolicyCheckIntermediateMarkerOid);
2037 CFDictionaryAddValue(gSecPolicyPathCallbacks, CFSTR("CheckIntermediateCountry"), SecPolicyCheckIntermediateCountry);
2038 CFDictionaryAddValue(gSecPolicyPathCallbacks, CFSTR("CheckIntermediateOrganization"), SecPolicyCheckIntermediateOrganization);
2039 }
2040
2041 // MARK: -
2042 // MARK: SecPVCRef
2043 /********************************************************
2044 ****************** SecPVCRef Functions *****************
2045 ********************************************************/
2046
2047 void SecPVCInit(SecPVCRef pvc, SecPathBuilderRef builder, CFArrayRef policies) {
2048 secdebug("alloc", "pvc %p", pvc);
2049 // Weird logging policies crashes.
2050 //secdebug("policy", "%@", policies);
2051
2052 // Zero the pvc struct so only non-zero fields need to be explicitly set
2053 memset(pvc, 0, sizeof(struct OpaqueSecPVC));
2054 pvc->builder = builder;
2055 pvc->policies = policies;
2056 if (policies)
2057 CFRetain(policies);
2058 pvc->result = kSecTrustResultUnspecified;
2059
2060 CFMutableDictionaryRef certDetail = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
2061 &kCFTypeDictionaryKeyCallBacks,
2062 &kCFTypeDictionaryValueCallBacks);
2063 pvc->leafDetails = CFArrayCreate(kCFAllocatorDefault, (const void **)&certDetail,
2064 1, &kCFTypeArrayCallBacks);
2065 CFRelease(certDetail);
2066 }
2067
2068 void SecPVCDelete(SecPVCRef pvc) {
2069 secdebug("alloc", "delete pvc %p", pvc);
2070 CFReleaseNull(pvc->policies);
2071 CFReleaseNull(pvc->details);
2072 CFReleaseNull(pvc->leafDetails);
2073 }
2074
2075 void SecPVCSetPath(SecPVCRef pvc, SecCertificatePathVCRef path) {
2076 secdebug("policy", "%@", path);
2077 pvc->policyIX = 0;
2078 pvc->result = kSecTrustResultUnspecified;
2079 CFReleaseNull(pvc->details);
2080 }
2081
2082 void SecPVCComputeDetails(SecPVCRef pvc, SecCertificatePathVCRef path) {
2083 pvc->policyIX = 0;
2084
2085 /* Since we don't run the LeafChecks again, we need to preserve the
2086 * result the leaf had. */
2087 CFIndex ix, pathLength = SecCertificatePathVCGetCount(path);
2088 CFMutableArrayRef details = CFArrayCreateMutableCopy(kCFAllocatorDefault,
2089 pathLength, pvc->leafDetails);
2090 for (ix = 1; ix < pathLength; ++ix) {
2091 CFMutableDictionaryRef certDetail = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
2092 &kCFTypeDictionaryKeyCallBacks,
2093 &kCFTypeDictionaryValueCallBacks);
2094 CFArrayAppendValue(details, certDetail);
2095 CFRelease(certDetail);
2096 }
2097 CFRetainAssign(pvc->details, details);
2098 pvc->result = pvc->leafResult;
2099 CFReleaseSafe(details);
2100 }
2101
2102 SecPolicyRef SecPVCGetPolicy(SecPVCRef pvc) {
2103 return (SecPolicyRef)CFArrayGetValueAtIndex(pvc->policies, pvc->policyIX);
2104 }
2105
2106 CFIndex SecPVCGetCertificateCount(SecPVCRef pvc) {
2107 return SecPathBuilderGetCertificateCount(pvc->builder);
2108 }
2109
2110 SecCertificateRef SecPVCGetCertificateAtIndex(SecPVCRef pvc, CFIndex ix) {
2111 return SecPathBuilderGetCertificateAtIndex(pvc->builder, ix);
2112 }
2113
2114 CFAbsoluteTime SecPVCGetVerifyTime(SecPVCRef pvc) {
2115 return SecPathBuilderGetVerifyTime(pvc->builder);
2116 }
2117
2118 static bool SecPVCIsExceptedError(SecPVCRef pvc, CFIndex ix, CFStringRef key, CFTypeRef value) {
2119 CFArrayRef exceptions = SecPathBuilderGetExceptions(pvc->builder);
2120 if (!exceptions) { return false; }
2121 CFIndex exceptionsCount = CFArrayGetCount(exceptions);
2122
2123 /* There are two types of exceptions:
2124 * 1. Those that are built from SecTrustCopyExceptions, which are particular to the
2125 * certs in the chain -- as indicated by the SHA1 digest in the exception dictionary.
2126 * 2. On macOS, those built from SecTrustSetOptions, which are generic excepted errors.
2127 */
2128 #if TARGET_OS_OSX
2129 CFDictionaryRef options = CFArrayGetValueAtIndex(exceptions, 0);
2130 if (!isDictionary(options)) {
2131 return false;
2132 }
2133 /* Type 2 */
2134 if (exceptionsCount == 1 && (ix > 0 || !CFDictionaryContainsKey(options, kSecCertificateDetailSHA1Digest))) {
2135 /* SHA1Digest not allowed */
2136 if (CFDictionaryContainsKey(options, kSecCertificateDetailSHA1Digest)) { return false; }
2137 /* Key excepted */
2138 if (CFDictionaryContainsKey(options, key)) {
2139 /* Special case -- AnchorTrusted only for self-signed certs */
2140 if (CFEqual(kSecPolicyCheckAnchorTrusted, key)) {
2141 Boolean isSelfSigned = false;
2142 SecCertificateRef cert = SecPathBuilderGetCertificateAtIndex(pvc->builder, ix);
2143 if (!cert || (errSecSuccess != SecCertificateIsSelfSigned(cert, &isSelfSigned)) || !isSelfSigned) {
2144 return false;
2145 }
2146 }
2147 return true;
2148 } else if (CFEqual(key, kSecPolicyCheckTemporalValidity) && CFDictionaryContainsKey(options, kSecPolicyCheckValidRoot)) {
2149 /* Another special case - ValidRoot excepts Valid only for self-signed certs */
2150 Boolean isSelfSigned = false;
2151 SecCertificateRef cert = SecPathBuilderGetCertificateAtIndex(pvc->builder, ix);
2152 if (!cert || (errSecSuccess != SecCertificateIsSelfSigned(cert, &isSelfSigned)) || !isSelfSigned) {
2153 return false;
2154 }
2155 return true;
2156 }
2157 }
2158 #endif
2159
2160 /* Type 1 */
2161 if (ix >= exceptionsCount) { return false; }
2162 CFDictionaryRef exception = CFArrayGetValueAtIndex(exceptions, ix);
2163 if (!isDictionary(exception)) {
2164 return false;
2165 }
2166
2167 /* Compare the cert hash */
2168 if (!CFDictionaryContainsKey(exception, kSecCertificateDetailSHA1Digest)) { return false; }
2169 SecCertificateRef cert = SecPathBuilderGetCertificateAtIndex(pvc->builder, ix);
2170 if (!CFEqual(SecCertificateGetSHA1Digest(cert), CFDictionaryGetValue(exception, kSecCertificateDetailSHA1Digest))) {
2171 return false;
2172 }
2173
2174 /* Key Excepted */
2175 CFTypeRef exceptionValue = CFDictionaryGetValue(exception, key);
2176 if (exceptionValue && CFEqual(value, exceptionValue)) {
2177 /* Only change result if PVC is already ok */
2178 if (SecPVCIsOkResult(pvc)) {
2179 // Chains that pass due to exceptions get Proceed result.
2180 pvc->result = kSecTrustResultProceed;
2181 }
2182 return true;
2183 }
2184
2185 return false;
2186 }
2187
2188 static int32_t detailKeyToCssmErr(CFStringRef key) {
2189 int32_t result = 0;
2190
2191 if (CFEqual(key, kSecPolicyCheckSSLHostname)) {
2192 result = -2147408896; // CSSMERR_APPLETP_HOSTNAME_MISMATCH
2193 }
2194 else if (CFEqual(key, kSecPolicyCheckEmail)) {
2195 result = -2147408872; // CSSMERR_APPLETP_SMIME_EMAIL_ADDRS_NOT_FOUND
2196 }
2197 else if (CFEqual(key, kSecPolicyCheckTemporalValidity)) {
2198 result = -2147409654; // CSSMERR_TP_CERT_EXPIRED
2199 }
2200
2201 return result;
2202 }
2203
2204 static bool SecPVCMeetsConstraint(SecPVCRef pvc, SecCertificateRef certificate, CFDictionaryRef constraint);
2205
2206 static bool SecPVCIsAllowedError(SecPVCRef pvc, CFIndex ix, CFStringRef key) {
2207 bool result = false;
2208 SecCertificatePathVCRef path = SecPathBuilderGetPath(pvc->builder);
2209 CFArrayRef constraints = SecCertificatePathVCGetUsageConstraintsAtIndex(path, ix);
2210 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix);
2211 CFIndex constraintIX, constraintCount = CFArrayGetCount(constraints);
2212
2213 for (constraintIX = 0; constraintIX < constraintCount; constraintIX++) {
2214 CFDictionaryRef constraint = (CFDictionaryRef)CFArrayGetValueAtIndex(constraints, constraintIX);
2215 CFNumberRef allowedErrorNumber = NULL;
2216 if (!isDictionary(constraint)) {
2217 continue;
2218 }
2219 allowedErrorNumber = (CFNumberRef)CFDictionaryGetValue(constraint, kSecTrustSettingsAllowedError);
2220 int32_t allowedErrorValue = 0;
2221 if (!isNumber(allowedErrorNumber) || !CFNumberGetValue(allowedErrorNumber, kCFNumberSInt32Type, &allowedErrorValue)) {
2222 continue;
2223 }
2224
2225 if (SecPVCMeetsConstraint(pvc, cert, constraint)) {
2226 if (allowedErrorValue == detailKeyToCssmErr(key)) {
2227 result = true;
2228 break;
2229 }
2230 }
2231 }
2232 return result;
2233 }
2234
2235 static bool SecPVCKeyIsConstraintPolicyOption(SecPVCRef pvc, CFStringRef key) {
2236 CFIndex certIX, certCount = SecPVCGetCertificateCount(pvc);
2237 for (certIX = 0; certIX < certCount; certIX++) {
2238 SecCertificatePathVCRef path = SecPathBuilderGetPath(pvc->builder);
2239 CFArrayRef constraints = SecCertificatePathVCGetUsageConstraintsAtIndex(path, certIX);
2240 CFIndex constraintIX, constraintCount = CFArrayGetCount(constraints);
2241 for (constraintIX = 0; constraintIX < constraintCount; constraintIX++) {
2242 CFDictionaryRef constraint = (CFDictionaryRef)CFArrayGetValueAtIndex(constraints, constraintIX);
2243 if (!isDictionary(constraint)) {
2244 continue;
2245 }
2246
2247 CFDictionaryRef policyOptions = NULL;
2248 policyOptions = (CFDictionaryRef)CFDictionaryGetValue(constraint, kSecTrustSettingsPolicyOptions);
2249 if (policyOptions && isDictionary(policyOptions) &&
2250 CFDictionaryContainsKey(policyOptions, key)) {
2251 return true;
2252 }
2253 }
2254 }
2255 return false;
2256 }
2257
2258 static SecTrustResultType trust_result_for_key(CFStringRef key) {
2259 SecTrustResultType result = kSecTrustResultRecoverableTrustFailure;
2260 #undef POLICYCHECKMACRO
2261 #define __PC_TYPE_MEMBER_ false
2262 #define __PC_TYPE_MEMBER_R false
2263 #define __PC_TYPE_MEMBER_F true
2264 #define __PC_TYPE_MEMBER_D true
2265
2266 #define __TRUSTRESULT_ kSecTrustResultRecoverableTrustFailure
2267 #define __TRUSTRESULT_F kSecTrustResultFatalTrustFailure
2268 #define __TRUSTRESULT_D kSecTrustResultDeny
2269 #define __TRUSTRESULT_R kSecTrustResultRecoverableTrustFailure
2270
2271 #define POLICYCHECKMACRO(NAME, TRUSTRESULT, SUBTYPE, LEAFCHECK, PATHCHECK, LEAFONLY, CSSMERR, OSSTATUS) \
2272 if (__PC_TYPE_MEMBER_##TRUSTRESULT && CFEqual(key,CFSTR(#NAME))) { \
2273 result = __TRUSTRESULT_##TRUSTRESULT; \
2274 }
2275 #include "OSX/sec/Security/SecPolicyChecks.list"
2276 return result;
2277 }
2278
2279
2280 /* AUDIT[securityd](done):
2281 policy->_options is a caller provided dictionary, only its cf type has
2282 been checked.
2283 */
2284 bool SecPVCSetResultForcedWithTrustResult(SecPVCRef pvc, CFStringRef key, CFIndex ix, CFTypeRef result, bool force,
2285 SecTrustResultType overrideDefaultTR) {
2286
2287 /* If this is not something the current policy cares about ignore
2288 this error and return true so our caller continues evaluation. */
2289 if (!force) {
2290 /* Either the policy or the usage constraints have to have this key */
2291 SecPolicyRef policy = SecPVCGetPolicy(pvc);
2292 if (!(SecPVCKeyIsConstraintPolicyOption(pvc, key) ||
2293 (policy && CFDictionaryContainsKey(policy->_options, key)))) {
2294 return true;
2295 }
2296 }
2297
2298 /* Get the default trust result for this key and override it if the caller needs to
2299 * set a different trust result than the default. */
2300 SecTrustResultType trustResult = trust_result_for_key(key);
2301 if (overrideDefaultTR != kSecTrustResultInvalid) {
2302 trustResult = overrideDefaultTR;
2303 }
2304
2305 /* only recoverable errors can be allowed/excepted */
2306 if (trustResult == kSecTrustResultRecoverableTrustFailure) {
2307 /* Check to see if the SecTrustSettings for the certificate in question
2308 tell us to ignore this error. */
2309 if (SecPVCIsAllowedError(pvc, ix, key)) {
2310 secinfo("policy", "cert[%d]: skipped allowed error %@", (int) ix, key);
2311 return true;
2312 }
2313
2314 /* Check to see if exceptions tells us to ignore this error. */
2315 if (SecPVCIsExceptedError(pvc, ix, key, result)) {
2316 secinfo("policy", "cert[%d]: skipped exception error %@", (int) ix, key);
2317 return true;
2318 }
2319 }
2320
2321 secnotice("policy", "cert[%d]: %@ =(%s)[%s]> %@", (int) ix, key,
2322 (pvc->callbacks == gSecPolicyLeafCallbacks ? "leaf"
2323 : (pvc->callbacks == gSecPolicyPathCallbacks ? "path"
2324 : "custom")),
2325 (force ? "force" : ""), result);
2326
2327 /* Avoid resetting deny or fatal to recoverable */
2328 if (SecPVCIsOkResult(pvc) || trustResult == kSecTrustResultFatalTrustFailure) {
2329 pvc->result = trustResult;
2330 } else if (trustResult == kSecTrustResultDeny &&
2331 pvc->result == kSecTrustResultRecoverableTrustFailure) {
2332 pvc->result = trustResult;
2333 }
2334
2335 if (!pvc->details)
2336 return false;
2337
2338 CFMutableDictionaryRef detail =
2339 (CFMutableDictionaryRef)CFArrayGetValueAtIndex(pvc->details, ix);
2340 if (!detail) {
2341 secerror("SecPVCSetResultForced: failed to get detail at index %ld (array length %ld)",
2342 ix, CFArrayGetCount(pvc->details));
2343 return false;
2344 }
2345
2346 /* Perhaps detail should have an array of results per key? As it stands
2347 in the case of multiple policy failures the last failure stands. */
2348 CFDictionarySetValue(detail, key, result);
2349
2350 return true;
2351 }
2352
2353 bool SecPVCSetResultForced(SecPVCRef pvc, CFStringRef key, CFIndex ix, CFTypeRef result, bool force) {
2354 return SecPVCSetResultForcedWithTrustResult(pvc, key, ix, result, force, kSecTrustResultInvalid);
2355 }
2356
2357 bool SecPVCSetResult(SecPVCRef pvc,
2358 CFStringRef key, CFIndex ix, CFTypeRef result) {
2359 return SecPVCSetResultForced(pvc, key, ix, result, false);
2360 }
2361
2362 /* AUDIT[securityd](done):
2363 key(ok) is a caller provided.
2364 value(ok, unused) is a caller provided.
2365 */
2366 static void SecPVCValidateKey(const void *key, const void *value,
2367 void *context) {
2368 SecPVCRef pvc = (SecPVCRef)context;
2369
2370 /* If our caller doesn't want full details and we failed earlier there is
2371 no point in doing additional checks. */
2372 if (!SecPVCIsOkResult(pvc) && !pvc->details)
2373 return;
2374
2375 SecPolicyCheckFunction fcn = (SecPolicyCheckFunction)
2376 CFDictionaryGetValue(pvc->callbacks, key);
2377
2378 if (!fcn) {
2379 /* "Optional" policy checks. This may be a new key from the
2380 * pinning DB which is not implemented in this OS version. Log a
2381 * warning, and on debug builds fail evaluation, to encourage us
2382 * to ensure that checks are synchronized across the same build. */
2383 if (pvc->callbacks == gSecPolicyLeafCallbacks) {
2384 if (!CFDictionaryContainsKey(gSecPolicyPathCallbacks, key)) {
2385 secwarning("policy: unknown policy key %@, skipping", key);
2386 #if DEBUG
2387 pvc->result = kSecTrustResultOtherError;
2388 #endif
2389 }
2390 } else if (pvc->callbacks == gSecPolicyPathCallbacks) {
2391 if (!CFDictionaryContainsKey(gSecPolicyLeafCallbacks, key)) {
2392 secwarning("policy: unknown policy key %@, skipping", key);
2393 #if DEBUG
2394 pvc->result = kSecTrustResultOtherError;
2395 #endif
2396 }
2397 } else {
2398 /* Non standard validation phase, nothing is optional. */
2399 pvc->result = kSecTrustResultOtherError;
2400 }
2401 return;
2402 }
2403
2404 fcn(pvc, (CFStringRef)key);
2405 }
2406
2407 /* AUDIT[securityd](done):
2408 policy->_options is a caller provided dictionary, only its cf type has
2409 been checked.
2410 */
2411 SecTrustResultType SecPVCLeafChecks(SecPVCRef pvc) {
2412 /* We need to compute details for the leaf. */
2413 CFRetainAssign(pvc->details, pvc->leafDetails);
2414
2415 CFArrayRef policies = pvc->policies;
2416 CFIndex ix, count = CFArrayGetCount(policies);
2417 for (ix = 0; ix < count; ++ix) {
2418 SecPolicyRef policy = (SecPolicyRef)CFArrayGetValueAtIndex(policies, ix);
2419 pvc->policyIX = ix;
2420 /* Validate all keys for all policies. */
2421 pvc->callbacks = gSecPolicyLeafCallbacks;
2422 CFDictionaryApplyFunction(policy->_options, SecPVCValidateKey, pvc);
2423 }
2424
2425 pvc->leafResult = pvc->result;
2426 CFRetainAssign(pvc->leafDetails, pvc->details);
2427
2428 return pvc->result;
2429 }
2430
2431 bool SecPVCIsOkResult(SecPVCRef pvc) {
2432 if (pvc->result == kSecTrustResultRecoverableTrustFailure ||
2433 pvc->result == kSecTrustResultDeny ||
2434 pvc->result == kSecTrustResultFatalTrustFailure ||
2435 pvc->result == kSecTrustResultOtherError) {
2436 return false;
2437 }
2438 return true;
2439 }
2440
2441 bool SecPVCParentCertificateChecks(SecPVCRef pvc, CFIndex ix) {
2442 /* Check stuff common to intermediate and anchors. */
2443 CFAbsoluteTime verifyTime = SecPVCGetVerifyTime(pvc);
2444 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix);
2445 CFIndex anchor_ix = SecPVCGetCertificateCount(pvc) - 1;
2446
2447 if (!SecCertificateIsValid(cert, verifyTime)) {
2448 /* Certificate has expired. */
2449 if (!SecPVCSetResult(pvc, kSecPolicyCheckTemporalValidity, ix, kCFBooleanFalse)) {
2450 goto errOut;
2451 }
2452 }
2453
2454 if (SecCertificateIsWeakKey(cert)) {
2455 /* Certificate uses weak key. */
2456 if (!SecPVCSetResult(pvc, kSecPolicyCheckWeakKeySize, ix, kCFBooleanFalse)) {
2457 goto errOut;
2458 }
2459 }
2460
2461 if (!SecPolicyCheckCertWeakSignature(cert, NULL)) {
2462 /* Certificate uses weak hash. */
2463 if (!SecPVCSetResult(pvc, kSecPolicyCheckWeakSignature, ix, kCFBooleanFalse)) {
2464 goto errOut;
2465 }
2466 }
2467
2468 /* (k) Basic constraints only relevant for v3 and later. */
2469 if (SecCertificateVersion(cert) >= 3) {
2470 const SecCEBasicConstraints *bc =
2471 SecCertificateGetBasicConstraints(cert);
2472 if (!bc) {
2473 /* Basic constraints not present, illegal. */
2474 if (!SecPVCSetResultForced(pvc, kSecPolicyCheckBasicConstraints,
2475 ix, kCFBooleanFalse, true)) {
2476 goto errOut;
2477 }
2478 } else if (!bc->isCA) {
2479 /* Basic constraints not marked as isCA, illegal. */
2480 if (!SecPVCSetResultForced(pvc, kSecPolicyCheckBasicConstraintsCA,
2481 ix, kCFBooleanFalse, true)) {
2482 goto errOut;
2483 }
2484 }
2485 }
2486 /* For a v1 or v2 certificate in an intermediate slot (not a leaf and
2487 not an anchor), we additionally require that the certificate chain
2488 does not end in a v3 or later anchor. [rdar://32204517] */
2489 else if (ix > 0 && ix < anchor_ix) {
2490 SecCertificateRef anchor = SecPVCGetCertificateAtIndex(pvc, anchor_ix);
2491 if (SecCertificateVersion(anchor) >= 3) {
2492 if (!SecPVCSetResultForced(pvc, kSecPolicyCheckBasicConstraints,
2493 ix, kCFBooleanFalse, true)) {
2494 goto errOut;
2495 }
2496 }
2497 }
2498 /* (l) max_path_length is checked elsewhere. */
2499
2500 /* (n) If a key usage extension is present, verify that the keyCertSign bit is set. */
2501 SecKeyUsage keyUsage = SecCertificateGetKeyUsage(cert);
2502 if (keyUsage && !(keyUsage & kSecKeyUsageKeyCertSign)) {
2503 if (!SecPVCSetResultForced(pvc, kSecPolicyCheckKeyUsage,
2504 ix, kCFBooleanFalse, true)) {
2505 goto errOut;
2506 }
2507 }
2508
2509 errOut:
2510 return SecPVCIsOkResult(pvc);
2511 }
2512
2513 static bool SecPVCBlackListedKeyChecks(SecPVCRef pvc, CFIndex ix) {
2514 /* Check stuff common to intermediate and anchors. */
2515
2516 SecOTAPKIRef otapkiRef = SecOTAPKICopyCurrentOTAPKIRef();
2517 if (NULL != otapkiRef)
2518 {
2519 CFSetRef blackListedKeys = SecOTAPKICopyBlackListSet(otapkiRef);
2520 CFRelease(otapkiRef);
2521 if (NULL != blackListedKeys)
2522 {
2523 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix);
2524 CFIndex count = SecPVCGetCertificateCount(pvc);
2525 bool is_last = (ix == count - 1);
2526 bool is_anchor = (is_last && SecPathBuilderIsAnchored(pvc->builder));
2527 if (!is_anchor) {
2528 /* Check for blacklisted intermediate issuer keys. */
2529 CFDataRef dgst = SecCertificateCopyPublicKeySHA1Digest(cert);
2530 if (dgst) {
2531 /* Check dgst against blacklist. */
2532 if (CFSetContainsValue(blackListedKeys, dgst)) {
2533 /* Check allow list for this blacklisted issuer key,
2534 which is the authority key of the issued cert at ix-1.
2535 */
2536 SecCertificatePathVCRef path = SecPathBuilderGetPath(pvc->builder);
2537 bool allowed = path && SecCertificatePathVCIsAllowlisted(path);
2538 if (!allowed) {
2539 SecPVCSetResultForced(pvc, kSecPolicyCheckBlackListedKey,
2540 ix, kCFBooleanFalse, true);
2541 }
2542 }
2543 CFRelease(dgst);
2544 }
2545 }
2546 CFRelease(blackListedKeys);
2547 return SecPVCIsOkResult(pvc);
2548 }
2549 }
2550 // Assume OK
2551 return true;
2552 }
2553
2554 static bool SecPVCGrayListedKeyChecks(SecPVCRef pvc, CFIndex ix)
2555 {
2556 /* Check stuff common to intermediate and anchors. */
2557 SecOTAPKIRef otapkiRef = SecOTAPKICopyCurrentOTAPKIRef();
2558 if (NULL != otapkiRef)
2559 {
2560 CFSetRef grayListKeys = SecOTAPKICopyGrayList(otapkiRef);
2561 CFRelease(otapkiRef);
2562 if (NULL != grayListKeys)
2563 {
2564 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix);
2565 CFIndex count = SecPVCGetCertificateCount(pvc);
2566 bool is_last = (ix == count - 1);
2567 bool is_anchor = (is_last && SecPathBuilderIsAnchored(pvc->builder));
2568 if (!is_anchor) {
2569 /* Check for gray listed intermediate issuer keys. */
2570 CFDataRef dgst = SecCertificateCopyPublicKeySHA1Digest(cert);
2571 if (dgst) {
2572 /* Check dgst against gray list. */
2573 if (CFSetContainsValue(grayListKeys, dgst)) {
2574 /* Check allow list for this graylisted issuer key,
2575 which is the authority key of the issued cert at ix-1.
2576 */
2577 SecCertificatePathVCRef path = SecPathBuilderGetPath(pvc->builder);
2578 bool allowed = path && SecCertificatePathVCIsAllowlisted(path);
2579 if (!allowed) {
2580 SecPVCSetResultForced(pvc, kSecPolicyCheckGrayListedKey,
2581 ix, kCFBooleanFalse, true);
2582 }
2583 }
2584 CFRelease(dgst);
2585 }
2586 }
2587 CFRelease(grayListKeys);
2588 return SecPVCIsOkResult(pvc);
2589 }
2590 }
2591 // Assume ok
2592 return true;
2593 }
2594
2595 static bool SecPVCContainsPolicy(SecPVCRef pvc, CFStringRef searchOid, CFStringRef searchName, CFIndex *policyIX) {
2596 if (!isString(searchName) && !isString(searchOid)) {
2597 return false;
2598 }
2599 CFArrayRef policies = pvc->policies;
2600 CFIndex ix, count = CFArrayGetCount(policies);
2601 for (ix = 0; ix < count; ++ix) {
2602 SecPolicyRef policy = (SecPolicyRef)CFArrayGetValueAtIndex(policies, ix);
2603 CFStringRef policyName = SecPolicyGetName(policy);
2604 CFStringRef policyOid = SecPolicyGetOidString(policy);
2605 /* Prefer a match of both name and OID */
2606 if (searchOid && searchName && policyOid && policyName) {
2607 if (CFEqual(searchOid, policyOid) &&
2608 CFEqual(searchName, policyName)) {
2609 if (policyIX) { *policyIX = ix; }
2610 return true;
2611 }
2612 /* <rdar://40617139> sslServer trust settings need to apply to evals using policyName pinning
2613 * but make sure we don't use this for SSL Client trust settings or policies. */
2614 if (CFEqual(searchOid, policyOid) &&
2615 CFEqual(searchName, kSecPolicyNameSSLServer) && !CFEqual(policyName, kSecPolicyNameSSLClient)) {
2616 if (policyIX) { *policyIX = ix; }
2617 return true;
2618 }
2619 }
2620 /* Next best is just OID. */
2621 if (!searchName && searchOid && policyOid) {
2622 if (CFEqual(searchOid, policyOid)) {
2623 if (policyIX) { *policyIX = ix; }
2624 return true;
2625 }
2626 }
2627 if (!searchOid && searchName && policyName) {
2628 if (CFEqual(searchName, policyName)) {
2629 if (policyIX) { *policyIX = ix; }
2630 return true;
2631 }
2632 }
2633 }
2634 return false;
2635 }
2636
2637 static bool SecPVCContainsString(SecPVCRef pvc, CFIndex policyIX, CFStringRef stringValue) {
2638 if (!isString(stringValue)) {
2639 return false;
2640 }
2641 bool result = false;
2642
2643 /* <rdar://27754596> Previous versions of macOS null-terminated the string, so we need to strip it. */
2644 CFStringRef tmpStringValue = NULL;
2645 if (CFStringGetCharacterAtIndex(stringValue, CFStringGetLength(stringValue) -1) == (UniChar)0x0000) {
2646 tmpStringValue = CFStringCreateTruncatedCopy(stringValue, CFStringGetLength(stringValue) - 1);
2647 } else {
2648 tmpStringValue = CFStringCreateCopy(NULL, stringValue);
2649 }
2650 /* Some users have strings that only contain the null-termination, so we need to check that we
2651 * still have a string. */
2652 require(tmpStringValue, out);
2653
2654 if (policyIX >= 0 && policyIX < CFArrayGetCount(pvc->policies)) {
2655 SecPolicyRef policy = (SecPolicyRef)CFArrayGetValueAtIndex(pvc->policies, policyIX);
2656 /* Have to look for all the possible locations of name string */
2657 CFStringRef policyString = NULL;
2658 policyString = CFDictionaryGetValue(policy->_options, kSecPolicyCheckSSLHostname);
2659 if (!policyString) {
2660 policyString = CFDictionaryGetValue(policy->_options, kSecPolicyCheckEmail);
2661 }
2662 if (policyString && (CFStringCompare(tmpStringValue, policyString, kCFCompareCaseInsensitive) == kCFCompareEqualTo)) {
2663 result = true;
2664 goto out;
2665 }
2666
2667 CFArrayRef policyStrings = NULL;
2668 policyStrings = CFDictionaryGetValue(policy->_options, kSecPolicyCheckEAPTrustedServerNames);
2669 if (policyStrings && CFArrayContainsValue(policyStrings,
2670 CFRangeMake(0, CFArrayGetCount(policyStrings)),
2671 tmpStringValue)) {
2672 result = true;
2673 goto out;
2674 }
2675 }
2676
2677 out:
2678 CFReleaseNull(tmpStringValue);
2679 return result;
2680 }
2681
2682
2683 static uint32_t ts_key_usage_for_kuNumber(CFNumberRef keyUsageNumber) {
2684 uint32_t ourTSKeyUsage = 0;
2685 uint32_t keyUsage = 0;
2686 if (keyUsageNumber &&
2687 CFNumberGetValue(keyUsageNumber, kCFNumberSInt32Type, &keyUsage)) {
2688 if (keyUsage & kSecKeyUsageDigitalSignature) {
2689 ourTSKeyUsage |= kSecTrustSettingsKeyUseSignature;
2690 }
2691 if (keyUsage & kSecKeyUsageDataEncipherment) {
2692 ourTSKeyUsage |= kSecTrustSettingsKeyUseEnDecryptData;
2693 }
2694 if (keyUsage & kSecKeyUsageKeyEncipherment) {
2695 ourTSKeyUsage |= kSecTrustSettingsKeyUseEnDecryptKey;
2696 }
2697 if (keyUsage & kSecKeyUsageKeyAgreement) {
2698 ourTSKeyUsage |= kSecTrustSettingsKeyUseKeyExchange;
2699 }
2700 if (keyUsage == kSecKeyUsageAll) {
2701 ourTSKeyUsage = kSecTrustSettingsKeyUseAny;
2702 }
2703 }
2704 return ourTSKeyUsage;
2705 }
2706
2707 static uint32_t ts_key_usage_for_policy(SecPolicyRef policy) {
2708 uint32_t ourTSKeyUsage = 0;
2709 CFTypeRef policyKeyUsageType = NULL;
2710
2711 policyKeyUsageType = (CFTypeRef)CFDictionaryGetValue(policy->_options, kSecPolicyCheckKeyUsage);
2712 if (isArray(policyKeyUsageType)) {
2713 CFIndex ix, count = CFArrayGetCount(policyKeyUsageType);
2714 for (ix = 0; ix < count; ix++) {
2715 CFNumberRef policyKeyUsageNumber = NULL;
2716 policyKeyUsageNumber = (CFNumberRef)CFArrayGetValueAtIndex(policyKeyUsageType, ix);
2717 ourTSKeyUsage |= ts_key_usage_for_kuNumber(policyKeyUsageNumber);
2718 }
2719 } else if (isNumber(policyKeyUsageType)) {
2720 ourTSKeyUsage |= ts_key_usage_for_kuNumber(policyKeyUsageType);
2721 }
2722
2723 return ourTSKeyUsage;
2724 }
2725
2726 static bool SecPVCContainsTrustSettingsKeyUsage(SecPVCRef pvc,
2727 SecCertificateRef certificate, CFIndex policyIX, CFNumberRef keyUsageNumber) {
2728 int64_t keyUsageValue = 0;
2729 uint32_t ourKeyUsage = 0;
2730
2731 if (!isNumber(keyUsageNumber) || !CFNumberGetValue(keyUsageNumber, kCFNumberSInt64Type, &keyUsageValue)) {
2732 return false;
2733 }
2734
2735 if (keyUsageValue == kSecTrustSettingsKeyUseAny) {
2736 return true;
2737 }
2738
2739 /* We're using the key for revocation if we have the OCSPSigner policy.
2740 * @@@ If we support CRLs, we'd need to check for that policy here too.
2741 */
2742 if (SecPVCContainsPolicy(pvc, kSecPolicyAppleOCSPSigner, NULL, NULL)) {
2743 ourKeyUsage |= kSecTrustSettingsKeyUseSignRevocation;
2744 }
2745
2746 /* We're using the key for verifying a cert if it's a root/intermediate
2747 * in the chain. If the cert isn't in the path yet, we're about to add it,
2748 * so it's a root/intermediate. If there is no path, this is the leaf.
2749 */
2750 CFIndex pathIndex = -1;
2751 SecCertificatePathVCRef path = SecPathBuilderGetPath(pvc->builder);
2752 if (path) {
2753 pathIndex = SecCertificatePathVCGetIndexOfCertificate(path, certificate);
2754 } else {
2755 pathIndex = 0;
2756 }
2757 if (pathIndex != 0) {
2758 ourKeyUsage |= kSecTrustSettingsKeyUseSignCert;
2759 }
2760
2761 /* The rest of the key usages may be specified by the policy(ies). */
2762 if (policyIX >= 0 && policyIX < CFArrayGetCount(pvc->policies)) {
2763 SecPolicyRef policy = (SecPolicyRef)CFArrayGetValueAtIndex(pvc->policies, policyIX);
2764 ourKeyUsage |= ts_key_usage_for_policy(policy);
2765 } else {
2766 /* Get key usage from ALL policies */
2767 CFIndex ix, count = CFArrayGetCount(pvc->policies);
2768 for (ix = 0; ix < count; ix++) {
2769 SecPolicyRef policy = (SecPolicyRef)CFArrayGetValueAtIndex(pvc->policies, ix);
2770 ourKeyUsage |= ts_key_usage_for_policy(policy);
2771 }
2772 }
2773
2774 if (ourKeyUsage == (uint32_t)(keyUsageValue & 0x00ffffffff)) {
2775 return true;
2776 }
2777
2778 return false;
2779 }
2780
2781 #if TARGET_OS_OSX
2782 #include <Security/SecTrustedApplicationPriv.h>
2783 #include <Security/SecTask.h>
2784 #include <Security/SecTaskPriv.h>
2785 #include <bsm/libbsm.h>
2786 #include <libproc.h>
2787
2788 extern OSStatus SecTaskValidateForRequirement(SecTaskRef task, CFStringRef requirement);
2789
2790 static bool SecPVCCallerIsApplication(CFDataRef clientAuditToken, CFTypeRef appRef) {
2791 bool result = false;
2792 audit_token_t auditToken = {};
2793 SecTaskRef task = NULL;
2794 SecRequirementRef requirement = NULL;
2795 CFStringRef stringRequirement = NULL;
2796
2797 require_quiet(appRef && clientAuditToken, out);
2798 require(CFGetTypeID(appRef) == SecTrustedApplicationGetTypeID(), out);
2799 require_noerr(SecTrustedApplicationCopyRequirement((SecTrustedApplicationRef)appRef, &requirement), out);
2800 require(requirement, out);
2801 require_noerr(SecRequirementsCopyString(requirement, kSecCSDefaultFlags, &stringRequirement), out);
2802 require(stringRequirement, out);
2803
2804 require(sizeof(auditToken) == CFDataGetLength(clientAuditToken), out);
2805 CFDataGetBytes(clientAuditToken, CFRangeMake(0, sizeof(auditToken)), (uint8_t *)&auditToken);
2806 require(task = SecTaskCreateWithAuditToken(NULL, auditToken), out);
2807
2808 if(errSecSuccess == SecTaskValidateForRequirement(task, stringRequirement)) {
2809 result = true;
2810 }
2811
2812 out:
2813 CFReleaseNull(task);
2814 CFReleaseNull(requirement);
2815 CFReleaseNull(stringRequirement);
2816 return result;
2817 }
2818 #endif
2819
2820 static bool SecPVCContainsTrustSettingsPolicyOption(SecPVCRef pvc, CFDictionaryRef options) {
2821 if (!isDictionary(options)) {
2822 return false;
2823 }
2824
2825 /* Push */
2826 CFDictionaryRef currentCallbacks = pvc->callbacks;
2827
2828 /* We need to run the leaf and path checks using these options. */
2829 pvc->callbacks = gSecPolicyLeafCallbacks;
2830 CFDictionaryApplyFunction(options, SecPVCValidateKey, pvc);
2831
2832 pvc->callbacks = gSecPolicyPathCallbacks;
2833 CFDictionaryApplyFunction(options, SecPVCValidateKey, pvc);
2834
2835 /* Pop */
2836 pvc->callbacks = currentCallbacks;
2837
2838 /* Our work here is done; no need to claim a match */
2839 return false;
2840 }
2841
2842 static bool SecPVCMeetsConstraint(SecPVCRef pvc, SecCertificateRef certificate, CFDictionaryRef constraint) {
2843 CFStringRef policyOid = NULL, policyString = NULL, policyName = NULL;
2844 CFNumberRef keyUsageNumber = NULL;
2845 CFTypeRef trustedApplicationData = NULL;
2846 CFDictionaryRef policyOptions = NULL;
2847
2848 bool policyMatch = false, policyStringMatch = false, applicationMatch = false ,
2849 keyUsageMatch = false, policyOptionMatch = false;
2850 bool result = false;
2851
2852 #if TARGET_OS_OSX
2853 /* OS X returns a SecPolicyRef in the constraints. Convert to the oid string. */
2854 SecPolicyRef policy = NULL;
2855 policy = (SecPolicyRef)CFDictionaryGetValue(constraint, kSecTrustSettingsPolicy);
2856 policyOid = (policy) ? policy->_oid : NULL;
2857 #else
2858 policyOid = (CFStringRef)CFDictionaryGetValue(constraint, kSecTrustSettingsPolicy);
2859 #endif
2860 policyName = (CFStringRef)CFDictionaryGetValue(constraint, kSecTrustSettingsPolicyName);
2861 policyString = (CFStringRef)CFDictionaryGetValue(constraint, kSecTrustSettingsPolicyString);
2862 keyUsageNumber = (CFNumberRef)CFDictionaryGetValue(constraint, kSecTrustSettingsKeyUsage);
2863 policyOptions = (CFDictionaryRef)CFDictionaryGetValue(constraint, kSecTrustSettingsPolicyOptions);
2864
2865 CFIndex policyIX = -1;
2866 policyMatch = SecPVCContainsPolicy(pvc, policyOid, policyName, &policyIX);
2867 policyStringMatch = SecPVCContainsString(pvc, policyIX, policyString);
2868 keyUsageMatch = SecPVCContainsTrustSettingsKeyUsage(pvc, certificate, policyIX, keyUsageNumber);
2869 policyOptionMatch = SecPVCContainsTrustSettingsPolicyOption(pvc, policyOptions);
2870
2871 #if TARGET_OS_OSX
2872 trustedApplicationData = CFDictionaryGetValue(constraint, kSecTrustSettingsApplication);
2873 CFDataRef clientAuditToken = SecPathBuilderCopyClientAuditToken(pvc->builder);
2874 applicationMatch = SecPVCCallerIsApplication(clientAuditToken, trustedApplicationData);
2875 CFReleaseNull(clientAuditToken);
2876 #else
2877 if(CFDictionaryContainsKey(constraint, kSecTrustSettingsApplication)) {
2878 secerror("kSecTrustSettingsApplication is not yet supported on this platform");
2879 }
2880 #endif
2881
2882 /* If we either didn't find the parameter in the dictionary or we got a match
2883 * against that parameter, for all possible parameters in the dictionary, then
2884 * this trust setting result applies to the output. */
2885 if (((!policyOid && !policyName) || policyMatch) &&
2886 (!policyString || policyStringMatch) &&
2887 (!trustedApplicationData || applicationMatch) &&
2888 (!keyUsageNumber || keyUsageMatch) &&
2889 (!policyOptions || policyOptionMatch)) {
2890 result = true;
2891 }
2892
2893 return result;
2894 }
2895
2896 static SecTrustSettingsResult SecPVCGetTrustSettingsResult(SecPVCRef pvc, SecCertificateRef certificate, CFArrayRef constraints) {
2897 SecTrustSettingsResult result = kSecTrustSettingsResultInvalid;
2898 CFIndex constraintIX, constraintCount = CFArrayGetCount(constraints);
2899 for (constraintIX = 0; constraintIX < constraintCount; constraintIX++) {
2900 CFDictionaryRef constraint = (CFDictionaryRef)CFArrayGetValueAtIndex(constraints, constraintIX);
2901 if (!isDictionary(constraint)) {
2902 continue;
2903 }
2904
2905 CFNumberRef resultNumber = NULL;
2906 resultNumber = (CFNumberRef)CFDictionaryGetValue(constraint, kSecTrustSettingsResult);
2907 uint32_t resultValue = kSecTrustSettingsResultInvalid;
2908 if (!isNumber(resultNumber) || !CFNumberGetValue(resultNumber, kCFNumberSInt32Type, &resultValue)) {
2909 /* no SecTrustSettingsResult entry defaults to TrustRoot*/
2910 resultValue = kSecTrustSettingsResultTrustRoot;
2911 }
2912
2913 if (SecPVCMeetsConstraint(pvc, certificate, constraint)) {
2914 result = resultValue;
2915 break;
2916 }
2917 }
2918 return result;
2919 }
2920
2921 /* This function assumes that the input source is an anchor source */
2922 bool SecPVCIsAnchorPerConstraints(SecPVCRef pvc, SecCertificateSourceRef source, SecCertificateRef certificate) {
2923 __block bool result = false;
2924 CFArrayRef constraints = NULL;
2925 constraints = SecCertificateSourceCopyUsageConstraints(source, certificate);
2926
2927 /* Unrestricted certificates:
2928 * -those that come from anchor sources with no constraints
2929 * -self-signed certificates with empty contraints arrays
2930 */
2931 Boolean selfSigned = false;
2932 require(errSecSuccess == SecCertificateIsSelfSigned(certificate, &selfSigned), out);
2933 if ((NULL == source->copyUsageConstraints) ||
2934 (constraints && (CFArrayGetCount(constraints) == 0) && selfSigned)) {
2935 secinfo("trust", "unrestricted anchor%s",
2936 (NULL == source->copyUsageConstraints) ? " source" : "");
2937 result = true;
2938 goto out;
2939 }
2940
2941 /* Get the trust settings result for the PVC. Only one PVC need match to
2942 * trigger the anchor behavior -- policy validation will handle whether the
2943 * path is truly anchored for that PVC. */
2944 require_quiet(constraints, out);
2945 SecTrustSettingsResult settingsResult = kSecTrustSettingsResultInvalid;
2946 settingsResult = SecPVCGetTrustSettingsResult(pvc,
2947 certificate,
2948 constraints);
2949 if ((selfSigned && settingsResult == kSecTrustSettingsResultTrustRoot) ||
2950 (!selfSigned && settingsResult == kSecTrustSettingsResultTrustAsRoot)) {
2951 // For our purposes, this is an anchor.
2952 secinfo("trust", "complex trust settings anchor");
2953 result = true;
2954 }
2955
2956 if (settingsResult == kSecTrustSettingsResultDeny) {
2957 /* We consider denied certs "anchors" because the trust decision
2958 is set regardless of building the chain further. The policy
2959 validation will handle rejecting this chain. */
2960 secinfo("trust", "complex trust settings denied anchor");
2961 result = true;
2962 }
2963
2964 out:
2965 CFReleaseNull(constraints);
2966 return result;
2967 }
2968
2969 static void SecPVCCheckUsageConstraints(SecPVCRef pvc) {
2970 CFIndex certIX, certCount = SecPVCGetCertificateCount(pvc);
2971 for (certIX = 0; certIX < certCount; certIX++) {
2972 SecCertificatePathVCRef path = SecPathBuilderGetPath(pvc->builder);
2973 CFArrayRef constraints = SecCertificatePathVCGetUsageConstraintsAtIndex(path, certIX);
2974 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, certIX);
2975 SecTrustSettingsResult result = SecPVCGetTrustSettingsResult(pvc, cert, constraints);
2976
2977 /* Set the pvc trust result based on the usage constraints and anchor source. */
2978 if (result == kSecTrustSettingsResultDeny) {
2979 SecPVCSetResultForced(pvc, kSecPolicyCheckUsageConstraints, certIX, kCFBooleanFalse, true);
2980 } else if ((result == kSecTrustSettingsResultTrustRoot || result == kSecTrustSettingsResultTrustAsRoot ||
2981 result == kSecTrustSettingsResultInvalid) && SecPVCIsOkResult(pvc)) {
2982 /* If we already think the PVC is ok and this cert is from one of the user/
2983 * admin anchor sources, trustRoot, trustAsRoot, and Invalid (no constraints),
2984 * all mean we should use the special "Proceed" trust result. */
2985 if (SecPathBuilderIsAnchorSource(pvc->builder, kSecUserAnchorSource) &&
2986 SecCertificateSourceContains(kSecUserAnchorSource, cert)) {
2987 pvc->result = kSecTrustResultProceed;
2988 }
2989 #if TARGET_OS_OSX
2990 if (SecPathBuilderIsAnchorSource(pvc->builder, kSecLegacyAnchorSource) &&
2991 SecCertificateSourceContains(kSecLegacyAnchorSource, cert)) {
2992 pvc->result = kSecTrustResultProceed;
2993 }
2994 #endif
2995 }
2996 }
2997 }
2998
2999 static const UInt8 kTestDateConstraintsRoot[kSecPolicySHA256Size] = {
3000 0x51,0xA0,0xF3,0x1F,0xC0,0x1D,0xEC,0x87,0x32,0xB6,0xFD,0x13,0x6A,0x43,0x4D,0x6C,
3001 0x87,0xCD,0x62,0xE0,0x38,0xB4,0xFB,0xD6,0x40,0xB0,0xFD,0x62,0x4D,0x1F,0xCF,0x6D
3002 };
3003 static const UInt8 kWS_CA1_G2[kSecPolicySHA256Size] = {
3004 0xD4,0x87,0xA5,0x6F,0x83,0xB0,0x74,0x82,0xE8,0x5E,0x96,0x33,0x94,0xC1,0xEC,0xC2,
3005 0xC9,0xE5,0x1D,0x09,0x03,0xEE,0x94,0x6B,0x02,0xC3,0x01,0x58,0x1E,0xD9,0x9E,0x16
3006 };
3007 static const UInt8 kWS_CA1_NEW[kSecPolicySHA256Size] = {
3008 0x4B,0x22,0xD5,0xA6,0xAE,0xC9,0x9F,0x3C,0xDB,0x79,0xAA,0x5E,0xC0,0x68,0x38,0x47,
3009 0x9C,0xD5,0xEC,0xBA,0x71,0x64,0xF7,0xF2,0x2D,0xC1,0xD6,0x5F,0x63,0xD8,0x57,0x08
3010 };
3011 static const UInt8 kWS_CA2_NEW[kSecPolicySHA256Size] = {
3012 0xD6,0xF0,0x34,0xBD,0x94,0xAA,0x23,0x3F,0x02,0x97,0xEC,0xA4,0x24,0x5B,0x28,0x39,
3013 0x73,0xE4,0x47,0xAA,0x59,0x0F,0x31,0x0C,0x77,0xF4,0x8F,0xDF,0x83,0x11,0x22,0x54
3014 };
3015 static const UInt8 kWS_ECC[kSecPolicySHA256Size] = {
3016 0x8B,0x45,0xDA,0x1C,0x06,0xF7,0x91,0xEB,0x0C,0xAB,0xF2,0x6B,0xE5,0x88,0xF5,0xFB,
3017 0x23,0x16,0x5C,0x2E,0x61,0x4B,0xF8,0x85,0x56,0x2D,0x0D,0xCE,0x50,0xB2,0x9B,0x02
3018 };
3019 static const UInt8 kSC_SFSCA[kSecPolicySHA256Size] = {
3020 0xC7,0x66,0xA9,0xBE,0xF2,0xD4,0x07,0x1C,0x86,0x3A,0x31,0xAA,0x49,0x20,0xE8,0x13,
3021 0xB2,0xD1,0x98,0x60,0x8C,0xB7,0xB7,0xCF,0xE2,0x11,0x43,0xB8,0x36,0xDF,0x09,0xEA
3022 };
3023 static const UInt8 kSC_SHA2[kSecPolicySHA256Size] = {
3024 0xE1,0x78,0x90,0xEE,0x09,0xA3,0xFB,0xF4,0xF4,0x8B,0x9C,0x41,0x4A,0x17,0xD6,0x37,
3025 0xB7,0xA5,0x06,0x47,0xE9,0xBC,0x75,0x23,0x22,0x72,0x7F,0xCC,0x17,0x42,0xA9,0x11
3026 };
3027 static const UInt8 kSC_G2[kSecPolicySHA256Size] = {
3028 0xC7,0xBA,0x65,0x67,0xDE,0x93,0xA7,0x98,0xAE,0x1F,0xAA,0x79,0x1E,0x71,0x2D,0x37,
3029 0x8F,0xAE,0x1F,0x93,0xC4,0x39,0x7F,0xEA,0x44,0x1B,0xB7,0xCB,0xE6,0xFD,0x59,0x95
3030 };
3031
3032 static void SecPVCCheckIssuerDateConstraints(SecPVCRef pvc) {
3033 static CFSetRef sConstrainedRoots = NULL;
3034 static dispatch_once_t _t;
3035 dispatch_once(&_t, ^{
3036 const UInt8 *v_hashes[] = {
3037 kWS_CA1_G2, kWS_CA1_NEW, kWS_CA2_NEW, kWS_ECC,
3038 kSC_SFSCA, kSC_SHA2, kSC_G2, kTestDateConstraintsRoot
3039 };
3040 CFMutableSetRef set = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks);
3041 CFIndex ix, count = sizeof(v_hashes)/sizeof(*v_hashes);
3042 for (ix=0; ix<count; ix++) {
3043 CFDataRef hash = CFDataCreateWithBytesNoCopy(NULL, v_hashes[ix],
3044 kSecPolicySHA256Size, kCFAllocatorNull);
3045 if (hash) {
3046 CFSetAddValue(set, hash);
3047 CFRelease(hash);
3048 }
3049 }
3050 sConstrainedRoots = set;
3051 });
3052
3053 bool shouldDeny = false;
3054 CFIndex certIX, certCount = SecPVCGetCertificateCount(pvc);
3055 for (certIX = certCount - 1; certIX >= 0 && !shouldDeny; certIX--) {
3056 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, certIX);
3057 CFDataRef sha256 = SecCertificateCopySHA256Digest(cert);
3058 if (sha256 && CFSetContainsValue(sConstrainedRoots, sha256)) {
3059 /* matched a constrained root; check notBefore dates on all its children. */
3060 CFIndex childIX = certIX;
3061 while (--childIX >= 0) {
3062 SecCertificateRef child = SecPVCGetCertificateAtIndex(pvc, childIX);
3063 /* 1 Dec 2016 00:00:00 GMT */
3064 if (child && (CFAbsoluteTime)502243200.0 <= SecCertificateNotValidBefore(child)) {
3065 SecPVCSetResultForced(pvc, kSecPolicyCheckBlackListedKey, certIX, kCFBooleanFalse, true);
3066 shouldDeny = true;
3067 break;
3068 }
3069 }
3070 }
3071 CFReleaseNull(sha256);
3072 }
3073 }
3074
3075 static bool SecPVCPolicyPermitsCTRequired(SecPVCRef pvc) {
3076 #if TARGET_OS_BRIDGE
3077 return false;
3078 #else // !TARGET_OS_BRIDGE
3079 if (!pvc || !pvc->policies) {
3080 return false;
3081 }
3082 SecPolicyRef policy = (SecPolicyRef)CFArrayGetValueAtIndex(pvc->policies, 0);
3083 if (!policy) {
3084 return false;
3085 }
3086 // SSL policy
3087 CFStringRef policyName = SecPolicyGetName(policy);
3088 if (CFEqualSafe(policyName, kSecPolicyNameSSLServer)) {
3089 return true;
3090 }
3091 // SSL policy by another name
3092 CFDictionaryRef options = policy->_options;
3093 if (options && CFDictionaryGetValue(options, kSecPolicyCheckSSLHostname)) {
3094 return true;
3095 }
3096 // Policy explicitly requires CT
3097 if (options && CFDictionaryGetValue(options, kSecPolicyCheckCTRequired)) {
3098 return true;
3099 }
3100 return false;
3101 #endif // !TARGET_OS_BRIDGE
3102 }
3103
3104 /* ASSUMPTIONS:
3105 1. SecPVCCheckRequireCTConstraints must be called after SecPolicyCheckCT,
3106 so earliest issuance time has already been obtained from SCTs.
3107 2. If the issuance time value is 0 (i.e. 2001-01-01) or earlier, we
3108 assume it was not set, and thus we did not have CT info.
3109 */
3110 static void SecPVCCheckRequireCTConstraints(SecPVCRef pvc) {
3111 SecCertificatePathVCRef path = (pvc) ? SecPathBuilderGetPath(pvc->builder) : NULL;
3112 if (!path) {
3113 return;
3114 }
3115 /* If we are evaluating for a SSL server authentication policy, make sure
3116 SCT issuance time is prior to the earliest not-after date constraint.
3117 Note that CT will already be required if there is a not-after date
3118 constraint present (set in SecRVCProcessValidDateConstraints).
3119 */
3120 if (SecPVCPolicyPermitsCTRequired(pvc)) {
3121 CFIndex ix, certCount = SecCertificatePathVCGetCount(path);
3122 SecCertificateRef certificate = SecPathBuilderGetCertificateAtIndex(pvc->builder, 0);
3123 CFAbsoluteTime earliestNotAfter = 31556908800.0; /* default: 3001-01-01 00:00:00-0000 */
3124 CFAbsoluteTime issuanceTime = SecCertificatePathVCIssuanceTime(path);
3125 if (issuanceTime <= 0) {
3126 /* if not set (or prior to 2001-01-01), use leaf's not-before time. */
3127 issuanceTime = SecCertificateNotValidBefore(certificate);
3128 }
3129 for (ix = 0; ix < certCount; ix++) {
3130 SecRVCRef rvc = SecCertificatePathVCGetRVCAtIndex(path, ix);
3131 if (!rvc || !rvc->valid_info || !rvc->valid_info->hasDateConstraints || !rvc->valid_info->notAfterDate) {
3132 continue;
3133 }
3134 /* Found CA certificate with a not-after date constraint. */
3135 CFAbsoluteTime caNotAfter = CFDateGetAbsoluteTime(rvc->valid_info->notAfterDate);
3136 if (caNotAfter < earliestNotAfter) {
3137 earliestNotAfter = caNotAfter;
3138 }
3139 if (issuanceTime > earliestNotAfter) {
3140 /* Issuance time violates the not-after date constraint. */
3141 secnotice("rvc", "certificate issuance time (%f) is later than allowed value (%f)",
3142 issuanceTime, earliestNotAfter);
3143 SecRVCSetValidDeterminedErrorResult(rvc);
3144 break;
3145 }
3146 }
3147 }
3148 /* If path is CT validated, nothing further to do here. */
3149 if (SecCertificatePathVCIsCT(path)) {
3150 return;
3151 }
3152
3153 /* Path is not CT validated, so check if CT was required. */
3154 SecPathCTPolicy ctp = SecCertificatePathVCRequiresCT(path);
3155 if (ctp <= kSecPathCTNotRequired || !SecPVCPolicyPermitsCTRequired(pvc)) {
3156 return;
3157 }
3158
3159 /* We need to have a recent log list or the CT check may have failed due to the list being out of date.
3160 * Also, honor the CT kill switch. */
3161 SecOTAPKIRef otaref = SecOTAPKICopyCurrentOTAPKIRef();
3162 CFDictionaryRef trustedLogs = SecPathBuilderCopyTrustedLogs(pvc->builder);
3163 if (!SecOTAPKIKillSwitchEnabled(otaref, kOTAPKIKillSwitchCT) &&
3164 (SecOTAPKIAssetStalenessLessThanSeconds(otaref, kSecOTAPKIAssetStalenessDisable) || trustedLogs)) {
3165 /* CT was required. Error is always set on leaf certificate. */
3166 if (ctp != kSecPathCTRequiredOverridable) {
3167 /* Normally kSecPolicyCheckCTRequired is recoverable */
3168 SecPVCSetResultForcedWithTrustResult(pvc, kSecPolicyCheckCTRequired, 0, kCFBooleanFalse, true,
3169 kSecTrustResultFatalTrustFailure);
3170 } else {
3171 SecPVCSetResultForced(pvc, kSecPolicyCheckCTRequired, 0, kCFBooleanFalse, true);
3172 }
3173 }
3174 CFReleaseNull(otaref);
3175 CFReleaseNull(trustedLogs);
3176 }
3177
3178 /* "Deep" copy the details array */
3179 static CFArrayRef CF_RETURNS_RETAINED SecPVCCopyDetailsArray(SecPVCRef pvc) {
3180 CFArrayRef details = pvc->details;
3181 CFMutableArrayRef copiedDetails = CFArrayCreateMutable(NULL, CFArrayGetCount(details), &kCFTypeArrayCallBacks);
3182 CFArrayForEach(details, ^(const void *value) {
3183 CFMutableDictionaryRef copiedValue = CFDictionaryCreateMutableCopy(NULL, 0, (CFDictionaryRef)value);
3184 CFArrayAppendValue(copiedDetails, copiedValue);
3185 CFReleaseNull(copiedValue);
3186 });
3187 return copiedDetails;
3188 }
3189
3190 /* AUDIT[securityd](done):
3191 policy->_options is a caller provided dictionary, only its cf type has
3192 been checked.
3193 */
3194 void SecPVCPathChecks(SecPVCRef pvc) {
3195 secdebug("policy", "begin path: %@", SecPathBuilderGetPath(pvc->builder));
3196 SecCertificatePathVCRef path = SecPathBuilderGetPath(pvc->builder);
3197 /* This needs to be initialized before we call any function that might call
3198 SecPVCSetResultForced(). */
3199 pvc->policyIX = 0;
3200 SecPolicyCheckIdLinkage(pvc, kSecPolicyCheckIdLinkage);
3201 if (SecPVCIsOkResult(pvc) || pvc->details) {
3202 SecPolicyCheckBasicCertificateProcessing(pvc,
3203 kSecPolicyCheckBasicCertificateProcessing);
3204 }
3205
3206 CFArrayRef policies = pvc->policies;
3207 CFIndex count = CFArrayGetCount(policies);
3208 for (; pvc->policyIX < count; ++pvc->policyIX) {
3209 /* Validate all keys for all policies. */
3210 pvc->callbacks = gSecPolicyPathCallbacks;
3211 SecPolicyRef policy = SecPVCGetPolicy(pvc);
3212 CFDictionaryApplyFunction(policy->_options, SecPVCValidateKey, pvc);
3213 if (!SecPVCIsOkResult(pvc) && !pvc->details)
3214 return;
3215 }
3216
3217 // Reset
3218 pvc->policyIX = 0;
3219
3220 /* Check whether the TrustSettings say to deny a cert in the path. */
3221 SecPVCCheckUsageConstraints(pvc);
3222
3223 /* Check for Blocklisted certs */
3224 SecPVCCheckIssuerDateConstraints(pvc);
3225 CFIndex ix;
3226 count = SecCertificatePathVCGetCount(path);
3227 for (ix = 1; ix < count; ix++) {
3228 SecPVCGrayListedKeyChecks(pvc, ix);
3229 SecPVCBlackListedKeyChecks(pvc, ix);
3230 }
3231
3232 /* Path-based check tests. */
3233 if (!SecCertificatePathVCIsPathValidated(path)) {
3234 bool ev_check_ok = false;
3235 if (SecCertificatePathVCIsOptionallyEV(path)) {
3236 SecTrustResultType pre_ev_check_result = pvc->result;
3237 CFArrayRef pre_ev_check_details = pvc->details ? SecPVCCopyDetailsArray(pvc) : NULL;
3238 SecPolicyCheckEV(pvc, kSecPolicyCheckExtendedValidation);
3239 ev_check_ok = SecPVCIsOkResult(pvc);
3240 /* If ev checking failed, we still want to accept this chain
3241 as a non EV one, if it was valid as such. */
3242 pvc->result = pre_ev_check_result;
3243 CFAssignRetained(pvc->details, pre_ev_check_details);
3244 }
3245
3246 /* Check for CT */
3247 /* This call will set the value of pvc->is_ct, but won't change the result (pvc->result) */
3248 SecPolicyCheckCT(pvc);
3249
3250 /* Certs are only EV if they are also CT verified (when the Kill Switch isn't enabled and against a recent log list) */
3251 SecOTAPKIRef otaref = SecOTAPKICopyCurrentOTAPKIRef();
3252 if (ev_check_ok && (SecCertificatePathVCIsCT(path) || SecOTAPKIKillSwitchEnabled(otaref, kOTAPKIKillSwitchCT) ||
3253 !SecOTAPKIAssetStalenessLessThanSeconds(otaref, kSecOTAPKIAssetStalenessDisable))) {
3254 SecCertificatePathVCSetIsEV(path, true);
3255 }
3256 CFReleaseNull(otaref);
3257 }
3258
3259 /* Say that we did the expensive path checks (that we want to skip on the second call) */
3260 SecCertificatePathVCSetPathValidated(SecPathBuilderGetPath(pvc->builder));
3261
3262 /* Check that this path meets CT constraints. */
3263 SecPVCCheckRequireCTConstraints(pvc);
3264 SecPolicyCheckSystemTrustedCTRequired(pvc);
3265
3266 /* Check that this path meets known-intermediate constraints. */
3267 SecPathBuilderCheckKnownIntermediateConstraints(pvc->builder);
3268
3269 secdebug("policy", "end %strusted path: %@",
3270 (SecPVCIsOkResult(pvc) ? "" : "not "), SecPathBuilderGetPath(pvc->builder));
3271
3272 return;
3273 }
3274
3275 void SecPVCPathCheckRevocationResponsesReceived(SecPVCRef pvc) {
3276 #if TARGET_OS_WATCH
3277 /* Since we don't currently allow networking on watchOS,
3278 * don't enforce the revocation-required check here. (32728029) */
3279 bool required = false;
3280 #else
3281 bool required = true;
3282 #endif
3283 SecCertificatePathVCRef path = SecPathBuilderGetPath(pvc->builder);
3284 CFIndex ix, certCount = SecCertificatePathVCGetCount(path);
3285 for (ix = 0; ix < certCount; ix++) {
3286 SecRVCRef rvc = SecCertificatePathVCGetRVCAtIndex(path, ix);
3287 /* Do we have a valid revocation response? */
3288 if (SecRVCGetEarliestNextUpdate(rvc) == NULL_TIME) {
3289 /* No valid revocation response.
3290 * Do we require revocation (for that cert per the
3291 * SecCertificateVCRef, or per the pvc)? */
3292 if (required && (SecCertificatePathVCIsRevocationRequiredForCertificateAtIndex(path, ix) ||
3293 ((ix == 0) && pvc->require_revocation_response))) {
3294 SecPVCSetResultForced(pvc, kSecPolicyCheckRevocationResponseRequired,
3295 ix, kCFBooleanFalse, true);
3296 }
3297 /* Do we have a definitive Valid revocation result for this cert? */
3298 if (SecRVCHasDefinitiveValidInfo(rvc) && SecRVCHasRevokedValidInfo(rvc)) {
3299 SecRVCSetValidDeterminedErrorResult(rvc);
3300 }
3301 }
3302 }
3303 }