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