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