]> git.saurik.com Git - apple/security.git/blob - OSX/sec/securityd/SecPolicyServer.c
fda34f81cceb8d2dc5438dee17f6eac5fd64afc0
[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 Boolean isSelfSigned = false;
940 (void) SecCertificateIsSelfSigned(SecCertificatePathVCGetCertificateAtIndex(path, n - 1), &isSelfSigned);
941 if (isSelfSigned) {
942 /* Add a detail for the root not being trusted. */
943 if (!SecPVCSetResultForced(pvc, kSecPolicyCheckAnchorTrusted,
944 n - 1, kCFBooleanFalse, true)) {
945 return;
946 }
947 } else {
948 /* Add a detail for the missing intermediate. */
949 if (!SecPVCSetResultForced(pvc, kSecPolicyCheckMissingIntermediate,
950 n - 1, kCFBooleanFalse, true)) {
951 return;
952 }
953 }
954 }
955
956 CFAbsoluteTime verify_time = SecPVCGetVerifyTime(pvc);
957 //policy_set_t user_initial_policy_set = NULL;
958 //trust_anchor_t anchor;
959
960 /* Initialization */
961 #if POLICY_SUBTREES
962 CFMutableArrayRef permitted_subtrees = NULL;
963 CFMutableArrayRef excluded_subtrees = NULL;
964 permitted_subtrees = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
965 excluded_subtrees = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
966 require_action_quiet(permitted_subtrees != NULL, errOut,
967 SecPVCSetResultForced(pvc, kSecPolicyCheckNameConstraints, 0, kCFBooleanFalse, true));
968 require_action_quiet(excluded_subtrees != NULL, errOut,
969 SecPVCSetResultForced(pvc, kSecPolicyCheckNameConstraints, 0, kCFBooleanFalse, true));
970 #endif
971
972 if (!SecCertificatePathVCVerifyPolicyTree(path, is_anchor_trusted)) {
973 if (!SecPVCSetResultForced(pvc, kSecPolicyCheckPolicyConstraints, 0, kCFBooleanFalse, true)) {
974 goto errOut;
975 }
976 }
977
978 #if 0
979 /* Path builder ensures we only get cert chains with proper issuer
980 chaining with valid signatures along the way. */
981 algorithm_id_t working_public_key_algorithm = anchor->public_key_algorithm;
982 SecKeyRef working_public_key = anchor->public_key;
983 x500_name_t working_issuer_name = anchor->issuer_name;
984 #endif
985 uint32_t i, max_path_length = n;
986 SecCertificateRef cert = NULL;
987 for (i = 1; i <= n; ++i) {
988 /* Process Cert */
989 cert = SecPVCGetCertificateAtIndex(pvc, n - i);
990 bool is_self_issued = SecCertificatePathVCIsCertificateAtIndexSelfIssued(SecPathBuilderGetPath(pvc->builder), n - i);
991
992 /* (a) Verify the basic certificate information. */
993 /* @@@ Ensure that cert was signed with working_public_key_algorithm
994 using the working_public_key and the working_public_key_parameters. */
995
996 /* Already done by chain builder. */
997 if (!SecCertificateIsValid(cert, verify_time)) {
998 if (!SecPVCSetResult(pvc, kSecPolicyCheckTemporalValidity, n - i, kCFBooleanFalse)) {
999 goto errOut;
1000 }
1001 }
1002 if (SecCertificateIsWeakKey(cert)) {
1003 if (!SecPVCSetResult(pvc, kSecPolicyCheckWeakKeySize, n - i, kCFBooleanFalse)) {
1004 goto errOut;
1005 }
1006 }
1007 if (!SecPolicyCheckCertWeakSignature(cert, NULL)) {
1008 if (!SecPVCSetResult(pvc, kSecPolicyCheckWeakSignature, n - i, kCFBooleanFalse)) {
1009 goto errOut;
1010 }
1011 }
1012
1013 /* @@@ cert.issuer == working_issuer_name. */
1014
1015 #if POLICY_SUBTREES
1016 /* (b) (c) */
1017 if (!is_self_issued || i == n) {
1018 bool found = false;
1019 /* Verify certificate Subject Name and SubjectAltNames are not within any of the excluded_subtrees */
1020 if(excluded_subtrees && CFArrayGetCount(excluded_subtrees)) {
1021 if ((errSecSuccess != SecNameContraintsMatchSubtrees(cert, excluded_subtrees, &found, false)) || found) {
1022 secnotice("policy", "name in excluded subtrees");
1023 if(!SecPVCSetResultForced(pvc, kSecPolicyCheckNameConstraints, n - i, kCFBooleanFalse, true)) { goto errOut; }
1024 }
1025 }
1026 /* Verify certificate Subject Name and SubjectAltNames are within the permitted_subtrees */
1027 if(permitted_subtrees && CFArrayGetCount(permitted_subtrees)) {
1028 if ((errSecSuccess != SecNameContraintsMatchSubtrees(cert, permitted_subtrees, &found, true)) || !found) {
1029 secnotice("policy", "name not in permitted subtrees");
1030 if(!SecPVCSetResultForced(pvc, kSecPolicyCheckNameConstraints, n - i, kCFBooleanFalse, true)) { goto errOut; }
1031 }
1032 }
1033 }
1034 #endif
1035 /* (d) (e) (f) handled by SecCertificatePathVCVerifyPolicyTree */
1036
1037 /* If Last Cert in Path */
1038 if (i == n)
1039 break;
1040
1041 /* Prepare for Next Cert */
1042 /* (a) (b) Done by SecCertificatePathVCVerifyPolicyTree */
1043 /* (c)(d)(e)(f) Done by SecPathBuilderGetNext and SecCertificatePathVCVerify */
1044 #if POLICY_SUBTREES
1045 /* (g) If a name constraints extension is included in the certificate, modify the permitted_subtrees and excluded_subtrees state variables.
1046 */
1047 CFArrayRef permitted_subtrees_in_cert = SecCertificateGetPermittedSubtrees(cert);
1048 if (permitted_subtrees_in_cert) {
1049 SecNameConstraintsIntersectSubtrees(permitted_subtrees, permitted_subtrees_in_cert);
1050 }
1051
1052 // could do something smart here to avoid inserting the exact same constraint
1053 CFArrayRef excluded_subtrees_in_cert = SecCertificateGetExcludedSubtrees(cert);
1054 if (excluded_subtrees_in_cert) {
1055 CFIndex num_trees = CFArrayGetCount(excluded_subtrees_in_cert);
1056 CFRange range = { 0, num_trees };
1057 CFArrayAppendArray(excluded_subtrees, excluded_subtrees_in_cert, range);
1058 }
1059 #endif
1060 /* (h), (i), (j) done by SecCertificatePathVCVerifyPolicyTree */
1061
1062 /* (k) Checked in chain builder pre signature verify already. SecPVCParentCertificateChecks */
1063
1064 /* (l) */
1065 if (!is_self_issued) {
1066 if (max_path_length > 0) {
1067 max_path_length--;
1068 } else {
1069 /* max_path_len exceeded, illegal. */
1070 if (!SecPVCSetResultForced(pvc, kSecPolicyCheckBasicConstraintsPathLen,
1071 n - i, kCFBooleanFalse, true)) {
1072 goto errOut;
1073 }
1074 }
1075 }
1076 /* (m) */
1077 const SecCEBasicConstraints *bc = SecCertificateGetBasicConstraints(cert);
1078 if (bc && bc->pathLenConstraintPresent
1079 && bc->pathLenConstraint < max_path_length) {
1080 max_path_length = bc->pathLenConstraint;
1081 }
1082 #if 0 /* Checked in chain builder pre signature verify already. SecPVCParentCertificateChecks */
1083 /* (n) If a key usage extension is present, verify that the keyCertSign bit is set. */
1084 SecKeyUsage keyUsage = SecCertificateGetKeyUsage(cert);
1085 if (keyUsage && !(keyUsage & kSecKeyUsageKeyCertSign)) {
1086 if (!SecPVCSetResultForced(pvc, kSecPolicyCheckKeyUsage,
1087 n - i, kCFBooleanFalse, true)) {
1088 goto errOut;
1089 }
1090 }
1091 #endif
1092 /* (o) Recognize and process any other critical extension present in the certificate. Process any other recognized non-critical extension present in the certificate that is relevant to path processing. */
1093 if (SecCertificateHasUnknownCriticalExtension(cert)) {
1094 /* Certificate contains one or more unknown critical extensions. */
1095 if (!SecPVCSetResult(pvc, kSecPolicyCheckCriticalExtensions,
1096 n - i, kCFBooleanFalse)) {
1097 goto errOut;
1098 }
1099 }
1100 } /* end loop over certs in path */
1101 /* Wrap up */
1102 /* (a) (b) done by SecCertificatePathVCVerifyPolicyTree */
1103 /* (c) */
1104 /* (d) */
1105 /* If the subjectPublicKeyInfo field of the certificate contains an algorithm field with null parameters or parameters are omitted, compare the certificate subjectPublicKey algorithm to the working_public_key_algorithm. If the certificate subjectPublicKey algorithm and the
1106 working_public_key_algorithm are different, set the working_public_key_parameters to null. */
1107 /* (e) */
1108 /* (f) Recognize and process any other critical extension present in the certificate n. Process any other recognized non-critical extension present in certificate n that is relevant to path processing. */
1109 if (SecCertificateHasUnknownCriticalExtension(cert)) {
1110 /* Certificate contains one or more unknown critical extensions. */
1111 if (!SecPVCSetResult(pvc, kSecPolicyCheckCriticalExtensions,
1112 0, kCFBooleanFalse)) {
1113 goto errOut;
1114 }
1115 }
1116 /* (g) done by SecCertificatePathVCVerifyPolicyTree */
1117
1118 errOut:
1119 CFReleaseNull(permitted_subtrees);
1120 CFReleaseNull(excluded_subtrees);
1121 }
1122
1123 static policy_set_t policies_for_cert(SecCertificateRef cert) {
1124 policy_set_t policies = NULL;
1125 const SecCECertificatePolicies *cp =
1126 SecCertificateGetCertificatePolicies(cert);
1127 size_t policy_ix, policy_count = cp ? cp->numPolicies : 0;
1128 for (policy_ix = 0; policy_ix < policy_count; ++policy_ix) {
1129 policy_set_add(&policies, &cp->policies[policy_ix].policyIdentifier);
1130 }
1131 return policies;
1132 }
1133
1134 static void SecPolicyCheckEV(SecPVCRef pvc,
1135 CFStringRef key) {
1136 CFIndex ix, count = SecPVCGetCertificateCount(pvc);
1137 policy_set_t valid_policies = NULL;
1138
1139 /* 6.1.7. Key Usage Purposes */
1140 if (count) {
1141 CFAbsoluteTime jul2016 = 489024000;
1142 SecCertificateRef leaf = SecPVCGetCertificateAtIndex(pvc, 0);
1143 if (SecCertificateNotValidBefore(leaf) > jul2016 && count < 3) {
1144 /* Root CAs may not sign subscriber certificates after 30 June 2016. */
1145 if (SecPVCSetResultForced(pvc, key,
1146 0, kCFBooleanFalse, true)) {
1147 return;
1148 }
1149 }
1150 }
1151
1152 for (ix = 0; ix < count; ++ix) {
1153 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix);
1154 policy_set_t policies = policies_for_cert(cert);
1155 if (ix == 0) {
1156 /* Subscriber */
1157 /* anyPolicy in the leaf isn't allowed for EV, so only init
1158 valid_policies if we have real policies. */
1159 if (!policy_set_contains(policies, &oidAnyPolicy)) {
1160 valid_policies = policies;
1161 policies = NULL;
1162 }
1163 } else if (ix < count - 1) {
1164 /* Subordinate CA */
1165 if (!SecPolicySubordinateCACertificateCouldBeEV(cert)) {
1166 secnotice("ev", "subordinate certificate is not ev");
1167 if (SecPVCSetResultForced(pvc, key,
1168 ix, kCFBooleanFalse, true)) {
1169 policy_set_free(valid_policies);
1170 policy_set_free(policies);
1171 return;
1172 }
1173 }
1174 policy_set_intersect(&valid_policies, policies);
1175 } else {
1176 /* Root CA */
1177 if (!SecPolicyRootCACertificateIsEV(cert, valid_policies)) {
1178 secnotice("ev", "anchor certificate is not ev");
1179 if (SecPVCSetResultForced(pvc, key,
1180 ix, kCFBooleanFalse, true)) {
1181 policy_set_free(valid_policies);
1182 policy_set_free(policies);
1183 return;
1184 }
1185 }
1186 }
1187 policy_set_free(policies);
1188 if (!valid_policies) {
1189 secnotice("ev", "valid_policies set is empty: chain not ev");
1190 /* If we ever get into a state where no policies are valid anymore
1191 this can't be an ev chain. */
1192 if (SecPVCSetResultForced(pvc, key,
1193 ix, kCFBooleanFalse, true)) {
1194 return;
1195 }
1196 }
1197 }
1198
1199 policy_set_free(valid_policies);
1200
1201 /* (a) EV Subscriber Certificates Each EV Certificate issued by the CA to a
1202 Subscriber MUST contain an OID defined by the CA in the certificate’s
1203 certificatePolicies extension that: (i) indicates which CA policy statement relates
1204 to that certificate, (ii) asserts the CA’s adherence to and compliance with these
1205 Guidelines, and (iii), by pre-agreement with the Application Software Vendor,
1206 marks the certificate as being an EV Certificate.
1207 (b) EV Subordinate CA Certificates
1208 (1) Certificates issued to Subordinate CAs that are not controlled by the issuing
1209 CA MUST contain one or more OIDs defined by the issuing CA that
1210 explicitly identify the EV Policies that are implemented by the Subordinate
1211 CA;
1212 (2) Certificates issued to Subordinate CAs that are controlled by the Root CA
1213 MAY contain the special anyPolicy OID (2.5.29.32.0).
1214 (c) Root CA Certificates Root CA Certificates SHOULD NOT contain the
1215 certificatePolicies or extendedKeyUsage extensions.
1216 */
1217 }
1218
1219
1220 /*
1221 * MARK: Certificate Transparency support
1222 */
1223
1224 /***
1225
1226 struct {
1227 Version sct_version; // 1 byte
1228 LogID id; // 32 bytes
1229 uint64 timestamp; // 8 bytes
1230 CtExtensions extensions; // 2 bytes len field, + n bytes data
1231 digitally-signed struct { // 1 byte hash alg, 1 byte sig alg, n bytes signature
1232 Version sct_version;
1233 SignatureType signature_type = certificate_timestamp;
1234 uint64 timestamp;
1235 LogEntryType entry_type;
1236 select(entry_type) {
1237 case x509_entry: ASN.1Cert;
1238 case precert_entry: PreCert;
1239 } signed_entry;
1240 CtExtensions extensions;
1241 };
1242 } SignedCertificateTimestamp;
1243
1244 ***/
1245
1246 #include <Security/SecureTransportPriv.h>
1247
1248 static const
1249 SecAsn1Oid *oidForSigAlg(SSL_HashAlgorithm hash, SSL_SignatureAlgorithm alg)
1250 {
1251 switch(alg) {
1252 case SSL_SignatureAlgorithmRSA:
1253 switch (hash) {
1254 case SSL_HashAlgorithmSHA1:
1255 return &CSSMOID_SHA1WithRSA;
1256 case SSL_HashAlgorithmSHA256:
1257 return &CSSMOID_SHA256WithRSA;
1258 case SSL_HashAlgorithmSHA384:
1259 return &CSSMOID_SHA384WithRSA;
1260 default:
1261 break;
1262 }
1263 case SSL_SignatureAlgorithmECDSA:
1264 switch (hash) {
1265 case SSL_HashAlgorithmSHA1:
1266 return &CSSMOID_ECDSA_WithSHA1;
1267 case SSL_HashAlgorithmSHA256:
1268 return &CSSMOID_ECDSA_WithSHA256;
1269 case SSL_HashAlgorithmSHA384:
1270 return &CSSMOID_ECDSA_WithSHA384;
1271 default:
1272 break;
1273 }
1274 default:
1275 break;
1276 }
1277
1278 return NULL;
1279 }
1280
1281
1282 static size_t SSLDecodeUint16(const uint8_t *p)
1283 {
1284 return (p[0]<<8 | p[1]);
1285 }
1286
1287 static uint8_t *SSLEncodeUint16(uint8_t *p, size_t len)
1288 {
1289 p[0] = (len >> 8)&0xff;
1290 p[1] = (len & 0xff);
1291 return p+2;
1292 }
1293
1294 static uint8_t *SSLEncodeUint24(uint8_t *p, size_t len)
1295 {
1296 p[0] = (len >> 16)&0xff;
1297 p[1] = (len >> 8)&0xff;
1298 p[2] = (len & 0xff);
1299 return p+3;
1300 }
1301
1302
1303 static
1304 uint64_t SSLDecodeUint64(const uint8_t *p)
1305 {
1306 uint64_t u = 0;
1307 for(int i=0; i<8; i++) {
1308 u=(u<<8)|p[0];
1309 p++;
1310 }
1311 return u;
1312 }
1313
1314 #include <libDER/DER_CertCrl.h>
1315 #include <libDER/DER_Encode.h>
1316 #include <libDER/asn1Types.h>
1317
1318
1319 static CFDataRef copy_x509_entry_from_chain(SecPVCRef pvc)
1320 {
1321 SecCertificateRef leafCert = SecPVCGetCertificateAtIndex(pvc, 0);
1322
1323 CFMutableDataRef data = CFDataCreateMutable(kCFAllocatorDefault, 3+SecCertificateGetLength(leafCert));
1324
1325 CFDataSetLength(data, 3+SecCertificateGetLength(leafCert));
1326
1327 uint8_t *q = CFDataGetMutableBytePtr(data);
1328 q = SSLEncodeUint24(q, SecCertificateGetLength(leafCert));
1329 memcpy(q, SecCertificateGetBytePtr(leafCert), SecCertificateGetLength(leafCert));
1330
1331 return data;
1332 }
1333
1334
1335 static CFDataRef copy_precert_entry_from_chain(SecPVCRef pvc)
1336 {
1337 SecCertificateRef leafCert = NULL;
1338 SecCertificateRef issuer = NULL;
1339 CFDataRef issuerKeyHash = NULL;
1340 CFDataRef tbs_precert = NULL;
1341 CFMutableDataRef data= NULL;
1342
1343 require_quiet(SecPVCGetCertificateCount(pvc)>=2, out); //we need the issuer key for precerts.
1344 leafCert = SecPVCGetCertificateAtIndex(pvc, 0);
1345 issuer = SecPVCGetCertificateAtIndex(pvc, 1);
1346
1347 require(leafCert, out);
1348 require(issuer, out); // Those two would likely indicate an internal error, since we already checked the chain length above.
1349 issuerKeyHash = SecCertificateCopySubjectPublicKeyInfoSHA256Digest(issuer);
1350 tbs_precert = SecCertificateCopyPrecertTBS(leafCert);
1351
1352 require(issuerKeyHash, out);
1353 require(tbs_precert, out);
1354 data = CFDataCreateMutable(kCFAllocatorDefault, CFDataGetLength(issuerKeyHash) + 3 + CFDataGetLength(tbs_precert));
1355 CFDataSetLength(data, CFDataGetLength(issuerKeyHash) + 3 + CFDataGetLength(tbs_precert));
1356
1357 uint8_t *q = CFDataGetMutableBytePtr(data);
1358 memcpy(q, CFDataGetBytePtr(issuerKeyHash), CFDataGetLength(issuerKeyHash)); q += CFDataGetLength(issuerKeyHash); // issuer key hash
1359 q = SSLEncodeUint24(q, CFDataGetLength(tbs_precert));
1360 memcpy(q, CFDataGetBytePtr(tbs_precert), CFDataGetLength(tbs_precert));
1361
1362 out:
1363 CFReleaseSafe(issuerKeyHash);
1364 CFReleaseSafe(tbs_precert);
1365 return data;
1366 }
1367
1368 static
1369 CFAbsoluteTime TimestampToCFAbsoluteTime(uint64_t ts)
1370 {
1371 return (ts / 1000) - kCFAbsoluteTimeIntervalSince1970;
1372 }
1373
1374 static
1375 uint64_t TimestampFromCFAbsoluteTime(CFAbsoluteTime at)
1376 {
1377 return (uint64_t)(at + kCFAbsoluteTimeIntervalSince1970) * 1000;
1378 }
1379
1380
1381
1382
1383 /*
1384 If the 'sct' is valid, add it to the validatingLogs dictionary.
1385
1386 Inputs:
1387 - validatingLogs: mutable dictionary to which to add the log that validate this SCT.
1388 - sct: the SCT date
1389 - entry_type: 0 for x509 cert, 1 for precert.
1390 - entry: the cert or precert data.
1391 - vt: verification time timestamp (as used in SCTs: ms since 1970 Epoch)
1392 - trustedLog: Dictionary contain the Trusted Logs.
1393
1394 The SCT is valid if:
1395 - It decodes properly.
1396 - Its timestamp is less than 'verifyTime'.
1397 - It is signed by a log in 'trustedLogs'.
1398 - If entry_type = 0, the log must be currently qualified.
1399 - If entry_type = 1, the log may be expired.
1400
1401 If the SCT is valid, it's added to the validatinLogs dictionary using the log dictionary as the key, and the timestamp as value.
1402 If an entry for the same log already existing in the dictionary, the entry is replaced only if the timestamp of this SCT is earlier.
1403
1404 */
1405
1406
1407 static CFDictionaryRef getSCTValidatingLog(CFDataRef sct, int entry_type, CFDataRef entry, uint64_t vt, CFArrayRef trustedLogs, CFAbsoluteTime *sct_at)
1408 {
1409 uint8_t version;
1410 const uint8_t *logID;
1411 const uint8_t *timestampData;
1412 uint64_t timestamp;
1413 size_t extensionsLen;
1414 const uint8_t *extensionsData;
1415 uint8_t hashAlg;
1416 uint8_t sigAlg;
1417 size_t signatureLen;
1418 const uint8_t *signatureData;
1419 SecKeyRef pubKey = NULL;
1420 uint8_t *signed_data = NULL;
1421 const SecAsn1Oid *oid = NULL;
1422 SecAsn1AlgId algId;
1423 CFDataRef logIDData = NULL;
1424 CFDictionaryRef result = 0;
1425
1426 const uint8_t *p = CFDataGetBytePtr(sct);
1427 size_t len = CFDataGetLength(sct);
1428
1429 require(len>=43, out);
1430
1431 version = p[0]; p++; len--;
1432 logID = p; p+=32; len-=32;
1433 timestampData = p; p+=8; len-=8;
1434 extensionsLen = SSLDecodeUint16(p); p+=2; len-=2;
1435
1436 require(len>=extensionsLen, out);
1437 extensionsData = p; p+=extensionsLen; len-=extensionsLen;
1438
1439 require(len>=4, out);
1440 hashAlg=p[0]; p++; len--;
1441 sigAlg=p[0]; p++; len--;
1442 signatureLen = SSLDecodeUint16(p); p+=2; len-=2;
1443 require(len==signatureLen, out); /* We do not tolerate any extra data after the signature */
1444 signatureData = p;
1445
1446 /* verify version: only v1(0) is supported */
1447 if(version!=0) {
1448 secerror("SCT version unsupported: %d\n", version);
1449 goto out;
1450 }
1451
1452 /* verify timestamp not in the future */
1453 timestamp = SSLDecodeUint64(timestampData);
1454 if(timestamp > vt) {
1455 secerror("SCT is in the future: %llu > %llu\n", timestamp, vt);
1456 goto out;
1457 }
1458
1459 uint8_t *q;
1460
1461 /* signed entry */
1462 size_t signed_data_len = 12 + CFDataGetLength(entry) + 2 + extensionsLen ;
1463 signed_data = malloc(signed_data_len);
1464 require(signed_data, out);
1465 q = signed_data;
1466 *q++ = version;
1467 *q++ = 0; // certificate_timestamp
1468 memcpy(q, timestampData, 8); q+=8;
1469 q = SSLEncodeUint16(q, entry_type); // logentry type: 0=cert 1=precert
1470 memcpy(q, CFDataGetBytePtr(entry), CFDataGetLength(entry)); q += CFDataGetLength(entry);
1471 q = SSLEncodeUint16(q, extensionsLen);
1472 memcpy(q, extensionsData, extensionsLen);
1473
1474 logIDData = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, logID, 32, kCFAllocatorNull);
1475
1476 CFDictionaryRef logData = CFArrayGetValueMatching(trustedLogs, ^bool(const void *dict) {
1477 const void *key_data;
1478 if(!isDictionary(dict)) return false;
1479 if(!CFDictionaryGetValueIfPresent(dict, CFSTR("key"), &key_data)) return false;
1480 if(!isData(key_data)) return false;
1481 CFDataRef valueID = SecSHA256DigestCreateFromData(kCFAllocatorDefault, (CFDataRef)key_data);
1482 bool result = (bool)(CFDataCompare(logIDData, valueID)==kCFCompareEqualTo);
1483 CFReleaseSafe(valueID);
1484 return result;
1485 });
1486 require(logData, out);
1487
1488 if(entry_type==0) {
1489 // For external SCTs, only keep SCTs from currently valid logs.
1490 require(!CFDictionaryContainsKey(logData, CFSTR("expiry")), out);
1491 }
1492
1493 CFAbsoluteTime sct_time = TimestampToCFAbsoluteTime(timestamp);
1494 CFDateRef frozen_date = CFDictionaryGetValue(logData, CFSTR("frozen"));
1495 if (frozen_date && (sct_time > CFDateGetAbsoluteTime(frozen_date))) {
1496 secerror("Frozen CT log issued SCT after freezing (log=%@)\n", logData);
1497 goto out;
1498 }
1499
1500 CFDataRef logKeyData = CFDictionaryGetValue(logData, CFSTR("key"));
1501 require(logKeyData, out); // This failing would be an internal logic error
1502 pubKey = SecKeyCreateFromSubjectPublicKeyInfoData(kCFAllocatorDefault, logKeyData);
1503 require(pubKey, out);
1504
1505 oid = oidForSigAlg(hashAlg, sigAlg);
1506 require(oid, out);
1507
1508 algId.algorithm = *oid;
1509 algId.parameters.Data = NULL;
1510 algId.parameters.Length = 0;
1511
1512 if(SecKeyDigestAndVerify(pubKey, &algId, signed_data, signed_data_len, signatureData, signatureLen)==0) {
1513 *sct_at = sct_time;
1514 result = logData;
1515 } else {
1516 secerror("SCT signature failed (log=%@)\n", logData);
1517 }
1518
1519 out:
1520 CFReleaseSafe(logIDData);
1521 CFReleaseSafe(pubKey);
1522 free(signed_data);
1523 return result;
1524 }
1525
1526
1527 static void addValidatingLog(CFMutableDictionaryRef validatingLogs, CFDictionaryRef log, CFAbsoluteTime sct_at)
1528 {
1529 CFDateRef validated_time = CFDictionaryGetValue(validatingLogs, log);
1530
1531 if(validated_time==NULL || (sct_at < CFDateGetAbsoluteTime(validated_time))) {
1532 CFDateRef sct_time = CFDateCreate(kCFAllocatorDefault, sct_at);
1533 CFDictionarySetValue(validatingLogs, log, sct_time);
1534 CFReleaseSafe(sct_time);
1535 }
1536 }
1537
1538 static CFArrayRef copy_ocsp_scts(SecPVCRef pvc)
1539 {
1540 CFMutableArrayRef SCTs = NULL;
1541 SecCertificateRef leafCert = NULL;
1542 SecCertificateRef issuer = NULL;
1543 CFArrayRef ocspResponsesData = NULL;
1544 SecOCSPRequestRef ocspRequest = NULL;
1545
1546 ocspResponsesData = SecPathBuilderCopyOCSPResponses(pvc->builder);
1547 require_quiet(ocspResponsesData, out);
1548
1549 require_quiet(SecPVCGetCertificateCount(pvc)>=2, out); //we need the issuer key for precerts.
1550 leafCert = SecPVCGetCertificateAtIndex(pvc, 0);
1551 issuer = SecPVCGetCertificateAtIndex(pvc, 1);
1552
1553 require(leafCert, out);
1554 require(issuer, out); // not quiet: Those two would likely indicate an internal error, since we already checked the chain length above.
1555 ocspRequest = SecOCSPRequestCreate(leafCert, issuer);
1556
1557 SCTs = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
1558 require(SCTs, out);
1559
1560 CFArrayForEach(ocspResponsesData, ^(const void *value) {
1561 /* TODO: Should the builder already have the appropriate SecOCSPResponseRef ? */
1562 SecOCSPResponseRef ocspResponse = SecOCSPResponseCreate(value);
1563 if(ocspResponse && SecOCSPGetResponseStatus(ocspResponse)==kSecOCSPSuccess) {
1564 SecOCSPSingleResponseRef ocspSingleResponse = SecOCSPResponseCopySingleResponse(ocspResponse, ocspRequest);
1565 if(ocspSingleResponse) {
1566 CFArrayRef singleResponseSCTs = SecOCSPSingleResponseCopySCTs(ocspSingleResponse);
1567 if(singleResponseSCTs) {
1568 CFArrayAppendArray(SCTs, singleResponseSCTs, CFRangeMake(0, CFArrayGetCount(singleResponseSCTs)));
1569 CFRelease(singleResponseSCTs);
1570 }
1571 SecOCSPSingleResponseDestroy(ocspSingleResponse);
1572 }
1573 }
1574 if(ocspResponse) SecOCSPResponseFinalize(ocspResponse);
1575 });
1576
1577 if(CFArrayGetCount(SCTs)==0) {
1578 CFReleaseNull(SCTs);
1579 }
1580
1581 out:
1582 CFReleaseSafe(ocspResponsesData);
1583 if(ocspRequest)
1584 SecOCSPRequestFinalize(ocspRequest);
1585
1586 return SCTs;
1587 }
1588
1589 static void SecPolicyCheckCT(SecPVCRef pvc)
1590 {
1591 SecCertificateRef leafCert = SecPVCGetCertificateAtIndex(pvc, 0);
1592 CFArrayRef embeddedScts = SecCertificateCopySignedCertificateTimestamps(leafCert);
1593 CFArrayRef builderScts = SecPathBuilderCopySignedCertificateTimestamps(pvc->builder);
1594 CFArrayRef trustedLogs = SecPathBuilderCopyTrustedLogs(pvc->builder);
1595 CFArrayRef ocspScts = copy_ocsp_scts(pvc);
1596 CFDataRef precertEntry = copy_precert_entry_from_chain(pvc);
1597 CFDataRef x509Entry = copy_x509_entry_from_chain(pvc);
1598 __block uint32_t trustedSCTCount = 0;
1599 __block CFAbsoluteTime issuanceTime = SecPVCGetVerifyTime(pvc);
1600 TA_CTFailureReason failureReason = TA_CTNoFailure;
1601
1602 if (!trustedLogs) {
1603 SecOTAPKIRef otapkiref = SecOTAPKICopyCurrentOTAPKIRef();
1604 trustedLogs = SecOTAPKICopyTrustedCTLogs(otapkiref);
1605 CFReleaseSafe(otapkiref);
1606 }
1607
1608 // This eventually contain list of logs who validated the SCT.
1609 CFMutableDictionaryRef currentLogsValidatingScts = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
1610 CFMutableDictionaryRef logsValidatingEmbeddedScts = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
1611
1612 uint64_t vt = TimestampFromCFAbsoluteTime(SecPVCGetVerifyTime(pvc));
1613
1614 __block bool at_least_one_currently_valid_external = 0;
1615 __block bool at_least_one_currently_valid_embedded = 0;
1616 __block bool unknown_log = 0;
1617 __block bool disqualified_log = 0;
1618
1619 require(logsValidatingEmbeddedScts, out);
1620 require(currentLogsValidatingScts, out);
1621
1622 /* Skip if there are no SCTs. */
1623 require_action((embeddedScts && CFArrayGetCount(embeddedScts) > 0) ||
1624 (builderScts && CFArrayGetCount(builderScts) > 0) ||
1625 (ocspScts && CFArrayGetCount(ocspScts) > 0),
1626 out,
1627 TrustAnalyticsBuilder *analytics = SecPathBuilderGetAnalyticsData(pvc->builder);
1628 if (analytics) {
1629 analytics->ct_failure_reason = TA_CTNoSCTs;
1630 }
1631 );
1632
1633 if(trustedLogs) { // Don't bother trying to validate SCTs if we don't have any trusted logs.
1634 if(embeddedScts && precertEntry) { // Don't bother if we could not get the precert.
1635 CFArrayForEach(embeddedScts, ^(const void *value){
1636 CFAbsoluteTime sct_at;
1637 CFDictionaryRef log = getSCTValidatingLog(value, 1, precertEntry, vt, trustedLogs, &sct_at);
1638 if(log) {
1639 addValidatingLog(logsValidatingEmbeddedScts, log, sct_at);
1640 if(!CFDictionaryContainsKey(log, CFSTR("expiry"))) {
1641 addValidatingLog(currentLogsValidatingScts, log, sct_at);
1642 at_least_one_currently_valid_embedded = true;
1643 trustedSCTCount++;
1644 } else {
1645 disqualified_log = true;
1646 }
1647 } else {
1648 unknown_log = true;
1649 }
1650 });
1651 }
1652
1653 if(builderScts && x509Entry) { // Don't bother if we could not get the cert.
1654 CFArrayForEach(builderScts, ^(const void *value){
1655 CFAbsoluteTime sct_at;
1656 CFDictionaryRef log = getSCTValidatingLog(value, 0, x509Entry, vt, trustedLogs, &sct_at);
1657 if(log) {
1658 addValidatingLog(currentLogsValidatingScts, log, sct_at);
1659 at_least_one_currently_valid_external = true;
1660 trustedSCTCount++;
1661 } else {
1662 unknown_log = true;
1663 }
1664 });
1665 }
1666
1667 if(ocspScts && x509Entry) {
1668 CFArrayForEach(ocspScts, ^(const void *value){
1669 CFAbsoluteTime sct_at;
1670 CFDictionaryRef log = getSCTValidatingLog(value, 0, x509Entry, vt, trustedLogs, &sct_at);
1671 if(log) {
1672 addValidatingLog(currentLogsValidatingScts, log, sct_at);
1673 at_least_one_currently_valid_external = true;
1674 trustedSCTCount++;
1675 } else {
1676 unknown_log = true;
1677 }
1678 });
1679 }
1680 } else {
1681 failureReason = TA_CTMissingLogs;
1682 }
1683
1684
1685 /* We now have 2 sets of logs that validated those SCTS, count them and make a final decision.
1686
1687 Current Policy:
1688 is_ct = (A1 AND A2) OR (B1 AND B2).
1689
1690 A1: embedded SCTs from 2+ to 5+ logs valid at issuance time
1691 A2: At least one embedded SCT from a currently valid log.
1692
1693 B1: SCTs from 2 currently valid logs (from any source)
1694 B2: At least 1 external SCT from a currently valid log.
1695
1696 */
1697
1698 bool hasValidExternalSCT = (at_least_one_currently_valid_external && CFDictionaryGetCount(currentLogsValidatingScts)>=2);
1699 bool hasValidEmbeddedSCT = (at_least_one_currently_valid_embedded);
1700 SecCertificatePathVCRef path = SecPathBuilderGetPath(pvc->builder);
1701 SecCertificatePathVCSetIsCT(path, false);
1702
1703 if (hasValidEmbeddedSCT) {
1704 /* Calculate issuance time based on timestamp of SCTs from current logs */
1705 CFDictionaryForEach(currentLogsValidatingScts, ^(const void *key, const void *value) {
1706 CFDictionaryRef log = key;
1707 if(!CFDictionaryContainsKey(log, CFSTR("expiry"))) {
1708 // Log is still qualified
1709 CFDateRef ts = (CFDateRef) value;
1710 CFAbsoluteTime timestamp = CFDateGetAbsoluteTime(ts);
1711 if(timestamp < issuanceTime) {
1712 issuanceTime = timestamp;
1713 }
1714 }
1715 });
1716 SecCertificatePathVCSetIssuanceTime(path, issuanceTime);
1717 }
1718 if (hasValidExternalSCT) {
1719 /* Note: since external SCT validates this cert, we do not need to
1720 override issuance time here. If the cert also has a valid embedded
1721 SCT, issuanceTime will be calculated and set in the block above. */
1722 SecCertificatePathVCSetIsCT(path, true);
1723 } else if (hasValidEmbeddedSCT) {
1724 __block int lifetime; // in Months
1725 __block unsigned once_or_current_qualified_embedded = 0;
1726
1727 /* Count Logs */
1728 __block bool failed_once_check = false;
1729 CFDictionaryForEach(logsValidatingEmbeddedScts, ^(const void *key, const void *value) {
1730 CFDictionaryRef log = key;
1731 CFDateRef ts = value;
1732 CFDateRef expiry = CFDictionaryGetValue(log, CFSTR("expiry"));
1733 if (expiry == NULL) { // Currently qualified OR
1734 once_or_current_qualified_embedded++;
1735 } else if (CFDateCompare(ts, expiry, NULL) == kCFCompareLessThan && // Once qualified. That is, qualified at the time of SCT AND
1736 issuanceTime < CFDateGetAbsoluteTime(expiry)) { // at the time of issuance.)
1737 once_or_current_qualified_embedded++;
1738 trustedSCTCount++;
1739 } else {
1740 failed_once_check = true;
1741 }
1742 });
1743
1744 SecCFCalendarDoWithZuluCalendar(^(CFCalendarRef zuluCalendar) {
1745 int _lifetime;
1746 CFCalendarGetComponentDifference(zuluCalendar,
1747 SecCertificateNotValidBefore(leafCert),
1748 SecCertificateNotValidAfter(leafCert),
1749 0, "M", &_lifetime);
1750 lifetime = _lifetime;
1751 });
1752
1753 unsigned requiredEmbeddedSctsCount;
1754
1755 if (lifetime < 15) {
1756 requiredEmbeddedSctsCount = 2;
1757 } else if (lifetime <= 27) {
1758 requiredEmbeddedSctsCount = 3;
1759 } else if (lifetime <= 39) {
1760 requiredEmbeddedSctsCount = 4;
1761 } else {
1762 requiredEmbeddedSctsCount = 5;
1763 }
1764
1765 if(once_or_current_qualified_embedded >= requiredEmbeddedSctsCount){
1766 SecCertificatePathVCSetIsCT(path, true);
1767 } else {
1768 /* Not enough "once or currently qualified" SCTs */
1769 if (failed_once_check) {
1770 failureReason = TA_CTEmbeddedNotEnoughDisqualified;
1771 } else if (unknown_log) {
1772 failureReason = TA_CTEmbeddedNotEnoughUnknown;
1773 } else {
1774 failureReason = TA_CTEmbeddedNotEnough;
1775 }
1776 }
1777 } else if (!at_least_one_currently_valid_embedded && !at_least_one_currently_valid_external) {
1778 /* No currently valid SCTs */
1779 if (disqualified_log) {
1780 failureReason = TA_CTNoCurrentSCTsDisqualifiedLog;
1781 } else if (unknown_log) {
1782 failureReason = TA_CTNoCurrentSCTsUnknownLog;
1783 }
1784 } else if (at_least_one_currently_valid_external) {
1785 /* One presented current SCT but failed total current check */
1786 if (disqualified_log) {
1787 failureReason = TA_CTPresentedNotEnoughDisqualified;
1788 } else if (unknown_log) {
1789 failureReason = TA_CTPresentedNotEnoughUnknown;
1790 } else {
1791 failureReason = TA_CTPresentedNotEnough;
1792 }
1793 }
1794
1795 /* Record analytics data for CT */
1796 TrustAnalyticsBuilder *analytics = SecPathBuilderGetAnalyticsData(pvc->builder);
1797 require_quiet(analytics, out);
1798 uint32_t sctCount = 0;
1799 /* Count the total number of SCTs we found and report where we got them */
1800 if (embeddedScts && CFArrayGetCount(embeddedScts) > 0) {
1801 analytics->sct_sources |= TA_SCTEmbedded;
1802 sctCount += CFArrayGetCount(embeddedScts);
1803 }
1804 if (builderScts && CFArrayGetCount(builderScts) > 0) {
1805 analytics->sct_sources |= TA_SCT_TLS;
1806 sctCount += CFArrayGetCount(builderScts);
1807 }
1808 if (ocspScts && CFArrayGetCount(ocspScts) > 0) {
1809 analytics->sct_sources |= TA_SCT_OCSP;
1810 sctCount += CFArrayGetCount(ocspScts);
1811 }
1812 /* Report how many of those SCTs were once or currently qualified */
1813 analytics->number_trusted_scts = trustedSCTCount;
1814 /* Report how many SCTs we got */
1815 analytics->number_scts = sctCount;
1816 /* Why we failed */
1817 analytics->ct_failure_reason = failureReason;
1818 /* Only one current SCT -- close to failure */
1819 if (CFDictionaryGetCount(currentLogsValidatingScts) == 1) {
1820 analytics->ct_one_current = true;
1821 }
1822 out:
1823 CFReleaseSafe(logsValidatingEmbeddedScts);
1824 CFReleaseSafe(currentLogsValidatingScts);
1825 CFReleaseSafe(builderScts);
1826 CFReleaseSafe(embeddedScts);
1827 CFReleaseSafe(ocspScts);
1828 CFReleaseSafe(precertEntry);
1829 CFReleaseSafe(trustedLogs);
1830 CFReleaseSafe(x509Entry);
1831 }
1832
1833 static bool checkPolicyOidData(SecPVCRef pvc, CFDataRef oid) {
1834 CFIndex ix, count = SecPVCGetCertificateCount(pvc);
1835 DERItem key_value;
1836 key_value.data = (DERByte *)CFDataGetBytePtr(oid);
1837 key_value.length = (DERSize)CFDataGetLength(oid);
1838
1839 for (ix = 0; ix < count; ix++) {
1840 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix);
1841 policy_set_t policies = policies_for_cert(cert);
1842
1843 if (policy_set_contains(policies, &key_value)) {
1844 policy_set_free(policies);
1845 return true;
1846 }
1847 policy_set_free(policies);
1848 }
1849 return false;
1850 }
1851
1852 static void SecPolicyCheckCertificatePolicy(SecPVCRef pvc, CFStringRef key)
1853 {
1854 SecPolicyRef policy = SecPVCGetPolicy(pvc);
1855 CFTypeRef value = CFDictionaryGetValue(policy->_options, key);
1856 bool result = false;
1857
1858 if (CFGetTypeID(value) == CFDataGetTypeID())
1859 {
1860 result = checkPolicyOidData(pvc, value);
1861 } else if (CFGetTypeID(value) == CFStringGetTypeID()) {
1862 CFDataRef dataOid = SecCertificateCreateOidDataFromString(NULL, value);
1863 if (dataOid) {
1864 result = checkPolicyOidData(pvc, dataOid);
1865 CFRelease(dataOid);
1866 }
1867 }
1868 if(!result) {
1869 SecPVCSetResult(pvc, key, 0, kCFBooleanFalse);
1870 }
1871 }
1872
1873
1874 static void SecPolicyCheckRevocation(SecPVCRef pvc,
1875 CFStringRef key) {
1876 SecPolicyRef policy = SecPVCGetPolicy(pvc);
1877 CFTypeRef value = CFDictionaryGetValue(policy->_options, key);
1878 if (isString(value)) {
1879 SecPathBuilderSetRevocationMethod(pvc->builder, value);
1880 }
1881 }
1882
1883 static void SecPolicyCheckRevocationResponseRequired(SecPVCRef pvc,
1884 CFStringRef key) {
1885 pvc->require_revocation_response = true;
1886 secdebug("policy", "revocation response required");
1887 }
1888
1889 static void SecPolicyCheckRevocationOnline(SecPVCRef pvc, CFStringRef key) {
1890 SecPathBuilderSetCheckRevocationOnline(pvc->builder);
1891 }
1892
1893 static void SecPolicyCheckRevocationIfTrusted(SecPVCRef pvc, CFStringRef key) {
1894 SecPathBuilderSetCheckRevocationIfTrusted(pvc->builder);
1895 }
1896
1897 static void SecPolicyCheckNoNetworkAccess(SecPVCRef pvc,
1898 CFStringRef key) {
1899 SecPolicyRef policy = SecPVCGetPolicy(pvc);
1900 CFTypeRef value = CFDictionaryGetValue(policy->_options, key);
1901 if (value == kCFBooleanTrue) {
1902 SecPathBuilderSetCanAccessNetwork(pvc->builder, false);
1903 } else {
1904 SecPathBuilderSetCanAccessNetwork(pvc->builder, true);
1905 }
1906 }
1907
1908 static void SecPolicyCheckWeakKeySize(SecPVCRef pvc,
1909 CFStringRef key) {
1910 CFIndex ix, count = SecPVCGetCertificateCount(pvc);
1911 for (ix = 0; ix < count; ++ix) {
1912 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix);
1913 if (cert && SecCertificateIsWeakKey(cert)) {
1914 /* Intermediate certificate has a weak key. */
1915 if (!SecPVCSetResult(pvc, key, ix, kCFBooleanFalse))
1916 return;
1917 }
1918 }
1919 }
1920
1921 static void SecPolicyCheckKeySize(SecPVCRef pvc, CFStringRef key) {
1922 CFIndex ix, count = SecPVCGetCertificateCount(pvc);
1923 SecPolicyRef policy = SecPVCGetPolicy(pvc);
1924 CFDictionaryRef keySizes = CFDictionaryGetValue(policy->_options, key);
1925 for (ix = 0; ix < count; ++ix) {
1926 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix);
1927 if (!SecCertificateIsAtLeastMinKeySize(cert, keySizes)) {
1928 if (!SecPVCSetResult(pvc, key, ix, kCFBooleanFalse))
1929 return;
1930 }
1931 }
1932 }
1933
1934 static void SecPolicyCheckWeakSignature(SecPVCRef pvc, CFStringRef key) {
1935 CFIndex ix, count = SecPVCGetCertificateCount(pvc);
1936 SecPolicyRef policy = SecPVCGetPolicy(pvc);
1937 CFTypeRef pvcValue = CFDictionaryGetValue(policy->_options, key);
1938 for (ix = 0; ix < count; ++ix) {
1939 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix);
1940 if (!SecPolicyCheckCertWeakSignature(cert, pvcValue)) {
1941 if (!SecPVCSetResult(pvc, key, ix, kCFBooleanFalse))
1942 return;
1943 }
1944 }
1945 }
1946
1947 static void SecPolicyCheckSignatureHashAlgorithms(SecPVCRef pvc,
1948 CFStringRef key) {
1949 CFIndex ix, count = SecPVCGetCertificateCount(pvc);
1950 SecPolicyRef policy = SecPVCGetPolicy(pvc);
1951 CFSetRef disallowedHashAlgorithms = CFDictionaryGetValue(policy->_options, key);
1952 for (ix = 0; ix < count; ++ix) {
1953 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix);
1954 if (!SecPolicyCheckCertSignatureHashAlgorithms(cert, disallowedHashAlgorithms)) {
1955 if (!SecPVCSetResult(pvc, key, ix, kCFBooleanFalse))
1956 return;
1957 }
1958 }
1959 }
1960
1961 static bool leaf_is_on_weak_hash_whitelist(SecPVCRef pvc) {
1962 SecCertificateRef leaf = SecPVCGetCertificateAtIndex(pvc, 0);
1963 require_quiet(leaf, out);
1964
1965 /* And now a special snowflake from our tests */
1966
1967 /* subject:/C=AU/ST=NSW/L=St Leonards/O=VODAFONE HUTCHISON AUSTRALIA PTY LIMITED/OU=Technology Shared Services/CN=mybill.vodafone.com.au */
1968 /* issuer :/C=UK/O=Vodafone Group/CN=Vodafone (Corporate Services 2009) */
1969 /* Not After : May 26 09:37:50 2017 GMT */
1970 static const uint8_t vodafone[] = {
1971 0xde, 0x77, 0x63, 0x97, 0x79, 0x47, 0xee, 0x6e, 0xc1, 0x3a,
1972 0x7b, 0x3b, 0xad, 0x43, 0x88, 0xa9, 0x66, 0x59, 0xa8, 0x18
1973 };
1974
1975 CFDataRef leafFingerprint = SecCertificateGetSHA1Digest(leaf);
1976 require_quiet(leafFingerprint, out);
1977 const unsigned int len = 20;
1978 const uint8_t *dp = CFDataGetBytePtr(leafFingerprint);
1979 if (dp && (!memcmp(vodafone, dp, len))) {
1980 return true;
1981 }
1982
1983 out:
1984 return false;
1985 }
1986
1987 static bool SecPVCKeyIsConstraintPolicyOption(SecPVCRef pvc, CFStringRef key);
1988
1989 static void SecPolicyCheckSystemTrustedWeakHash(SecPVCRef pvc,
1990 CFStringRef key) {
1991 CFIndex ix, count = SecPVCGetCertificateCount(pvc);
1992
1993 Boolean keyInPolicy = false;
1994 CFArrayRef policies = pvc->policies;
1995 CFIndex policyIX, policyCount = CFArrayGetCount(policies);
1996 for (policyIX = 0; policyIX < policyCount; ++policyIX) {
1997 SecPolicyRef policy = (SecPolicyRef)CFArrayGetValueAtIndex(policies, policyIX);
1998 if (policy && CFDictionaryContainsKey(policy->_options, key)) {
1999 keyInPolicy = true;
2000 }
2001 }
2002
2003 /* We only enforce this check when *both* of the following are true:
2004 * 1. One of the certs in the path has this usage constraint, and
2005 * 2. One of the policies in the PVC has this key
2006 * (As compared to normal policy options which require only one to be true..) */
2007 require_quiet(SecPVCKeyIsConstraintPolicyOption(pvc, key) &&
2008 keyInPolicy, out);
2009
2010 /* Ignore the anchor if it's trusted */
2011 if (SecPathBuilderIsAnchored(pvc->builder)) {
2012 count--;
2013 }
2014 for (ix = 0; ix < count; ++ix) {
2015 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix);
2016 if (SecCertificateIsWeakHash(cert)) {
2017 if (!leaf_is_on_weak_hash_whitelist(pvc)) {
2018 if (!SecPVCSetResult(pvc, key, ix, kCFBooleanFalse)) {
2019 return;
2020 }
2021 }
2022 }
2023 }
2024 out:
2025 return;
2026 }
2027
2028 static void SecPolicyCheckSystemTrustedWeakKey(SecPVCRef pvc,
2029 CFStringRef key) {
2030 CFIndex ix, count = SecPVCGetCertificateCount(pvc);
2031
2032 Boolean keyInPolicy = false;
2033 CFArrayRef policies = pvc->policies;
2034 CFIndex policyIX, policyCount = CFArrayGetCount(policies);
2035 for (policyIX = 0; policyIX < policyCount; ++policyIX) {
2036 SecPolicyRef policy = (SecPolicyRef)CFArrayGetValueAtIndex(policies, policyIX);
2037 if (policy && CFDictionaryContainsKey(policy->_options, key)) {
2038 keyInPolicy = true;
2039 }
2040 }
2041
2042 /* We only enforce this check when *both* of the following are true:
2043 * 1. One of the certs in the path has this usage constraint, and
2044 * 2. One of the policies in the PVC has this key
2045 * (As compared to normal policy options which require only one to be true..) */
2046 require_quiet(SecPVCKeyIsConstraintPolicyOption(pvc, key) &&
2047 keyInPolicy, out);
2048
2049 /* Ignore the anchor if it's trusted */
2050 if (SecPathBuilderIsAnchored(pvc->builder)) {
2051 count--;
2052 }
2053 for (ix = 0; ix < count; ++ix) {
2054 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix);
2055 if (!SecCertificateIsStrongKey(cert)) {
2056 if (!SecPVCSetResult(pvc, key, ix, kCFBooleanFalse)) {
2057 return;
2058 }
2059 }
2060
2061 } /* Cert loop */
2062 out:
2063 return;
2064 }
2065
2066 static void SecPolicyCheckPinningRequired(SecPVCRef pvc, CFStringRef key) {
2067 /* Pinning is disabled on the system, skip. */
2068 if (SecIsInternalRelease()) {
2069 if (CFPreferencesGetAppBooleanValue(CFSTR("AppleServerAuthenticationNoPinning"),
2070 CFSTR("com.apple.security"), NULL)) {
2071 return;
2072 }
2073 }
2074
2075 CFArrayRef policies = pvc->policies;
2076 CFIndex policyIX, policyCount = CFArrayGetCount(policies);
2077 for (policyIX = 0; policyIX < policyCount; ++policyIX) {
2078 SecPolicyRef policy = (SecPolicyRef)CFArrayGetValueAtIndex(policies, policyIX);
2079 CFStringRef policyName = SecPolicyGetName(policy);
2080 if (CFEqualSafe(policyName, kSecPolicyNameSSLServer)) {
2081 /* policy required pinning, but we didn't use a pinning policy */
2082 if (!SecPVCSetResult(pvc, key, 0, kCFBooleanFalse)) {
2083 return;
2084 }
2085 }
2086 }
2087 }
2088
2089 static bool is_configured_test_system_root(SecCertificateRef root) {
2090 if (!SecIsInternalRelease()) {
2091 return false;
2092 }
2093 bool result = false;
2094 CFDataRef rootHash = SecCertificateCopySHA256Digest(root);
2095 CFTypeRef value = CFPreferencesCopyValue(CFSTR("TestCTRequiredSystemRoot"), CFSTR("com.apple.security"),
2096 kCFPreferencesAnyUser, kCFPreferencesCurrentHost);
2097 require_quiet(isData(value), out);
2098 require_quiet(kCFCompareEqualTo == CFDataCompare(rootHash, value), out);
2099 result = true;
2100
2101 out:
2102 CFReleaseNull(value);
2103 CFReleaseNull(rootHash);
2104 return result;
2105 }
2106
2107 static bool is_ct_excepted_domain(CFStringRef hostname, CFStringRef exception) {
2108 if (kCFCompareEqualTo == CFStringCompare(exception, hostname, kCFCompareCaseInsensitive)) {
2109 /* exact match */
2110 return true;
2111 } else if (CFStringHasPrefix(exception, CFSTR("."))) {
2112 /* subdomains */
2113 CFIndex elength = CFStringGetLength(exception);
2114 CFIndex hlength = CFStringGetLength(hostname);
2115 if (hlength > elength) {
2116 CFRange compareRange = { hlength - elength, elength };
2117 if (kCFCompareEqualTo == CFStringCompareWithOptions(hostname, exception, compareRange, kCFCompareCaseInsensitive)) {
2118 return true;
2119 }
2120 } else if (hlength + 1 == elength) {
2121 CFRange compareRange = { 1, hlength };
2122 if (kCFCompareEqualTo == CFStringCompareWithOptions(exception, hostname, compareRange, kCFCompareCaseInsensitive)) {
2123 return true;
2124 }
2125 }
2126 }
2127 return false;
2128 }
2129
2130 static OSStatus is_subtree_dn_with_org(void *context, SecCEGeneralNameType gnType, const DERItem *generalName) {
2131 if (gnType != GNT_DirectoryName) {
2132 return errSecInternal;
2133 }
2134
2135 DERDecodedInfo subtreeName_content;
2136 if (DR_Success != DERDecodeItem(generalName, &subtreeName_content) || subtreeName_content.tag != ASN1_CONSTR_SEQUENCE) {
2137 return errSecDecode;
2138 }
2139
2140 CFArrayRef subtree_orgs = SecCertificateCopyOrganizationFromX501NameContent(&subtreeName_content.content);
2141 if (subtree_orgs) {
2142 CFReleaseNull(subtree_orgs);
2143 return errSecSuccess;
2144 }
2145 return errSecInternal;
2146 }
2147
2148 static bool has_ct_excepted_key(SecCertificatePathVCRef path, CFDictionaryRef exception) {
2149 __block bool result = false;
2150 CFDataRef exceptionHash = CFDictionaryGetValue(exception, kSecCTExceptionsSPKIHashKey);
2151
2152 /* exception for a leaf is always allowed */
2153 SecCertificateRef leaf = SecCertificatePathVCGetCertificateAtIndex(path, 0);
2154 CFDataRef spkiHash = SecCertificateCopySubjectPublicKeyInfoSHA256Digest(leaf);
2155 if (CFEqualSafe(exceptionHash, spkiHash)) {
2156 result = true;
2157 }
2158 CFReleaseNull(spkiHash);
2159
2160 if (result) { return result; }
2161
2162 /* exceptions for CAs */
2163 for (CFIndex certIX = 1; certIX < SecCertificatePathVCGetCount(path); certIX++) {
2164 SecCertificateRef ca = SecCertificatePathVCGetCertificateAtIndex(path, certIX);
2165
2166 spkiHash = SecCertificateCopySubjectPublicKeyInfoSHA256Digest(ca);
2167 if (!CFEqualSafe(exceptionHash, spkiHash)) {
2168 CFReleaseNull(spkiHash);
2169 continue;
2170 }
2171 CFReleaseNull(spkiHash);
2172
2173 /* this CA matches but exceptions for CAs have constraints */
2174 if (SecCertificateGetPermittedSubtrees(ca)) {
2175 /* Constrained CAs have to have a Distinguished Name permitted subtree with an Organization attribute */
2176 CFArrayForEach(SecCertificateGetPermittedSubtrees(ca), ^(const void *value) {
2177 CFDataRef subtree = (CFDataRef)value;
2178 const DERItem general_name = { (unsigned char *)CFDataGetBytePtr(subtree), CFDataGetLength(subtree) };
2179 DERDecodedInfo general_name_content;
2180 if (DR_Success == DERDecodeItem(&general_name, &general_name_content)) {
2181 OSStatus status = SecCertificateParseGeneralNameContentProperty(general_name_content.tag,
2182 &general_name_content.content,
2183 NULL,
2184 is_subtree_dn_with_org);
2185 if (status == errSecSuccess) {
2186 result = true;
2187 }
2188 }
2189 });
2190 }
2191
2192 if (!result) {
2193 /* The Organization attribute(s) in the CA subject have to exactly match the Organization attribute(s) in the leaf */
2194 CFArrayRef leafOrgs = SecCertificateCopyOrganization(leaf);
2195 CFArrayRef caOrgs = SecCertificateCopyOrganization(ca);
2196 if (caOrgs && leafOrgs && CFEqualSafe(leafOrgs, caOrgs)) {
2197 result = true;
2198 }
2199 CFReleaseNull(leafOrgs);
2200 CFReleaseNull(caOrgs);
2201 }
2202
2203 if (result) {
2204 break;
2205 }
2206 }
2207
2208 return result;
2209 }
2210
2211 static bool is_ct_excepted(SecPVCRef pvc) {
2212 CFDictionaryRef ct_exceptions = _SecTrustStoreCopyCTExceptions(NULL, NULL);
2213 if (!ct_exceptions) {
2214 return false;
2215 }
2216
2217 __block bool result = false;
2218 CFArrayRef domainExceptions = CFDictionaryGetValue(ct_exceptions, kSecCTExceptionsDomainsKey);
2219 if (domainExceptions) {
2220 SecPolicyRef policy = SecPVCGetPolicy(pvc);
2221 CFStringRef hostname = CFDictionaryGetValue(policy->_options, kSecPolicyCheckSSLHostname);
2222 if (hostname) {
2223 CFArrayForEach(domainExceptions, ^(const void *value) {
2224 result = result || is_ct_excepted_domain(hostname, value);
2225 });
2226 }
2227 }
2228 if (result) {
2229 secinfo("policy", "domain-based CT exception applied");
2230 CFReleaseNull(ct_exceptions);
2231 return result;
2232 }
2233
2234 CFArrayRef keyExceptions = CFDictionaryGetValue(ct_exceptions, kSecCTExceptionsCAsKey);
2235 if (keyExceptions) {
2236 __block SecCertificatePathVCRef path = SecPathBuilderGetPath(pvc->builder);
2237 CFArrayForEach(keyExceptions, ^(const void *value) {
2238 result = result || has_ct_excepted_key(path, value);
2239 });
2240 }
2241
2242 if (result) {
2243 secinfo("policy" , "key-based CT exceptions applied");
2244 }
2245
2246 CFReleaseNull(ct_exceptions);
2247 return result;
2248 }
2249
2250 /* <rdar://45466778> some Apple servers not getting certs with embedded SCTs
2251 * <rdar://45545270> some Google apps have their own TLS stacks and aren't passing us TLS SCTs */
2252 static bool is_apple_ca(SecCertificatePathVCRef path) {
2253 /* subject:/CN=Apple IST CA 8 - G1/OU=Certification Authority/O=Apple Inc./C=US */
2254 /* issuer :/C=US/O=GeoTrust Inc./OU=(c) 2007 GeoTrust Inc. - For authorized use only/CN=GeoTrust Primary Certification Authority - G2 */
2255 static const uint8_t appleISTCA8G1_spkiSHA256[] = {
2256 0xe2, 0x4f, 0x8e, 0x8c, 0x21, 0x85, 0xda, 0x2f, 0x5e, 0x88, 0xd4, 0x57, 0x9e, 0x81, 0x7c, 0x47,
2257 0xbf, 0x6e, 0xaf, 0xbc, 0x85, 0x05, 0xf0, 0xf9, 0x60, 0xfd, 0x5a, 0x0d, 0xf4, 0x47, 0x3a, 0xd3
2258 };
2259
2260 /* subject:/CN=Apple IST CA 2 - G1/OU=Certification Authority/O=Apple Inc./C=US */
2261 /* issuer :/C=US/O=GeoTrust Inc./CN=GeoTrust Global CA */
2262 static const uint8_t appleISTCA2G1_spkiSHA256[] = {
2263 0xb5, 0xcf, 0x82, 0xd4, 0x7e, 0xf9, 0x82, 0x3f, 0x9a, 0xa7, 0x8f, 0x12, 0x31, 0x86, 0xc5, 0x2e,
2264 0x88, 0x79, 0xea, 0x84, 0xb0, 0xf8, 0x22, 0xc9, 0x1d, 0x83, 0xe0, 0x42, 0x79, 0xb7, 0x8f, 0xd5
2265 };
2266
2267 /* subject:/C=US/O=Google Trust Services/CN=Google Internet Authority G3 */
2268 /* issuer :/OU=GlobalSign Root CA - R2/O=GlobalSign/CN=GlobalSign */
2269 static const uint8_t googleIAG3_spkiSHA256[] = {
2270 0x7f, 0xc3, 0x67, 0x10, 0x56, 0x71, 0x43, 0x81, 0x31, 0x14, 0xe8, 0x52, 0x37, 0xb1, 0x22, 0x15,
2271 0x6b, 0x62, 0xb9, 0xd6, 0x50, 0x54, 0x3d, 0xa8, 0x63, 0xad, 0x2e, 0x6a, 0xe5, 0x7f, 0x9f, 0xbf
2272 };
2273
2274 bool result = false;
2275 for (CFIndex certIX = 1; certIX < SecCertificatePathVCGetCount(path); certIX++) {
2276 SecCertificateRef ca = SecCertificatePathVCGetCertificateAtIndex(path, certIX);
2277
2278 CFDataRef caSPKIHash = SecCertificateCopySubjectPublicKeyInfoSHA256Digest(ca);
2279 const uint8_t *dp = CFDataGetBytePtr(caSPKIHash);
2280 if (dp && (!memcmp(appleISTCA8G1_spkiSHA256, dp, CC_SHA256_DIGEST_LENGTH) ||
2281 !memcmp(appleISTCA2G1_spkiSHA256, dp, CC_SHA256_DIGEST_LENGTH) ||
2282 !memcmp(googleIAG3_spkiSHA256, dp, CC_SHA256_DIGEST_LENGTH))) {
2283 result = true;
2284 }
2285 CFReleaseNull(caSPKIHash);
2286 if (result) {
2287 break;
2288 }
2289 }
2290 return result;
2291 }
2292
2293 static void SecPolicyCheckSystemTrustedCTRequired(SecPVCRef pvc) {
2294 SecCertificateSourceRef appleAnchorSource = NULL;
2295 SecOTAPKIRef otaref = SecOTAPKICopyCurrentOTAPKIRef();
2296 SecCertificatePathVCRef path = SecPathBuilderGetPath(pvc->builder);
2297 CFArrayRef trustedLogs = SecPathBuilderCopyTrustedLogs(pvc->builder);
2298
2299 /* Skip this check if we haven't done the CT checks yet */
2300 require_quiet(SecCertificatePathVCIsPathValidated(path), out);
2301
2302 /* We only enforce this check when all of the following are true:
2303 * 0. Kill Switch not enabled */
2304 require_quiet(!SecOTAPKIKillSwitchEnabled(otaref, kOTAPKIKillSwitchCT), out);
2305
2306 /* 1. Not a pinning policy */
2307 SecPolicyRef policy = SecPVCGetPolicy(pvc);
2308 require_quiet(CFEqualSafe(SecPolicyGetName(policy),kSecPolicyNameSSLServer), out);
2309
2310 /* 2. Device has checked in to MobileAsset for a current log list within the last 60 days.
2311 * Or the caller passed in the trusted log list. */
2312 require_quiet(SecOTAPKIAssetStalenessLessThanSeconds(otaref, kSecOTAPKIAssetStalenessDisable) || trustedLogs, out);
2313
2314 /* 3. Leaf issuance date is on or after 16 Oct 2018 at 00:00:00 AM UTC and not expired. */
2315 SecCertificateRef leaf = SecPVCGetCertificateAtIndex(pvc, 0);
2316 require_quiet(SecCertificateNotValidBefore(leaf) >= 561340800.0 &&
2317 SecCertificateIsValid(leaf, SecPVCGetVerifyTime(pvc)), out);
2318
2319 /* 4. Chain is anchored with root in the system anchor source but not the Apple anchor source
2320 * with certain excepted CAs and configurable included CAs. */
2321 CFIndex count = SecPVCGetCertificateCount(pvc);
2322 SecCertificateRef root = SecPVCGetCertificateAtIndex(pvc, count - 1);
2323 appleAnchorSource = SecMemoryCertificateSourceCreate(SecGetAppleTrustAnchors(false));
2324 require_quiet(SecPathBuilderIsAnchored(pvc->builder), out);
2325 require_quiet((SecCertificateSourceContains(kSecSystemAnchorSource, root) &&
2326 appleAnchorSource && !SecCertificateSourceContains(appleAnchorSource, root) &&
2327 !is_apple_ca(path)) ||
2328 is_configured_test_system_root(root), out);
2329
2330 if (!SecCertificatePathVCIsCT(path) && !is_ct_excepted(pvc)) {
2331 /* Set failure. By not using the Forced variant, we implicitly check that this
2332 * policy had this options set. */
2333 SecPVCSetResult(pvc, kSecPolicyCheckSystemTrustedCTRequired, 0, kCFBooleanFalse);
2334 }
2335
2336 out:
2337 CFReleaseNull(trustedLogs);
2338 CFReleaseNull(otaref);
2339 if (appleAnchorSource) {
2340 SecMemoryCertificateSourceDestroy(appleAnchorSource);
2341 }
2342 }
2343
2344 void SecPolicyServerInitialize(void) {
2345 gSecPolicyLeafCallbacks = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
2346 &kCFTypeDictionaryKeyCallBacks, NULL);
2347 gSecPolicyPathCallbacks = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
2348 &kCFTypeDictionaryKeyCallBacks, NULL);
2349
2350 #undef POLICYCHECKMACRO
2351 #define __PC_ADD_CHECK_(NAME)
2352 #define __PC_ADD_CHECK_L(NAME) CFDictionaryAddValue(gSecPolicyLeafCallbacks, kSecPolicyCheck##NAME, SecPolicyCheck##NAME);
2353 #define __PC_ADD_CHECK_A(NAME) CFDictionaryAddValue(gSecPolicyPathCallbacks, kSecPolicyCheck##NAME, SecPolicyCheck##NAME);
2354
2355 #define POLICYCHECKMACRO(NAME, TRUSTRESULT, SUBTYPE, LEAFCHECK, PATHCHECK, LEAFONLY, CSSMERR, OSSTATUS) \
2356 __PC_ADD_CHECK_##LEAFCHECK(NAME) \
2357 __PC_ADD_CHECK_##PATHCHECK(NAME)
2358 #include "../Security/SecPolicyChecks.list"
2359
2360 /* Some of these don't follow the naming conventions but are in the Pinning DB.
2361 * <rdar://34537018> fix policy check constant values */
2362 CFDictionaryAddValue(gSecPolicyLeafCallbacks, CFSTR("CheckLeafMarkerOid"), SecPolicyCheckLeafMarkerOid);
2363 CFDictionaryAddValue(gSecPolicyLeafCallbacks, CFSTR("CheckLeafMarkersProdAndQA"), SecPolicyCheckLeafMarkersProdAndQA);
2364 CFDictionaryAddValue(gSecPolicyPathCallbacks, CFSTR("CheckIntermediateMarkerOid"), SecPolicyCheckIntermediateMarkerOid);
2365 CFDictionaryAddValue(gSecPolicyPathCallbacks, CFSTR("CheckIntermediateCountry"), SecPolicyCheckIntermediateCountry);
2366 CFDictionaryAddValue(gSecPolicyPathCallbacks, CFSTR("CheckIntermediateOrganization"), SecPolicyCheckIntermediateOrganization);
2367 }
2368
2369 // MARK: -
2370 // MARK: SecPVCRef
2371 /********************************************************
2372 ****************** SecPVCRef Functions *****************
2373 ********************************************************/
2374
2375 void SecPVCInit(SecPVCRef pvc, SecPathBuilderRef builder, CFArrayRef policies) {
2376 secdebug("alloc", "pvc %p", pvc);
2377 // Weird logging policies crashes.
2378 //secdebug("policy", "%@", policies);
2379
2380 // Zero the pvc struct so only non-zero fields need to be explicitly set
2381 memset(pvc, 0, sizeof(struct OpaqueSecPVC));
2382 pvc->builder = builder;
2383 pvc->policies = policies;
2384 if (policies)
2385 CFRetain(policies);
2386 pvc->result = kSecTrustResultUnspecified;
2387
2388 CFMutableDictionaryRef certDetail = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
2389 &kCFTypeDictionaryKeyCallBacks,
2390 &kCFTypeDictionaryValueCallBacks);
2391 pvc->leafDetails = CFArrayCreate(kCFAllocatorDefault, (const void **)&certDetail,
2392 1, &kCFTypeArrayCallBacks);
2393 CFRelease(certDetail);
2394 }
2395
2396 void SecPVCDelete(SecPVCRef pvc) {
2397 secdebug("alloc", "delete pvc %p", pvc);
2398 CFReleaseNull(pvc->policies);
2399 CFReleaseNull(pvc->details);
2400 CFReleaseNull(pvc->leafDetails);
2401 }
2402
2403 void SecPVCSetPath(SecPVCRef pvc, SecCertificatePathVCRef path) {
2404 secdebug("policy", "%@", path);
2405 pvc->policyIX = 0;
2406 pvc->result = kSecTrustResultUnspecified;
2407 CFReleaseNull(pvc->details);
2408 }
2409
2410 void SecPVCComputeDetails(SecPVCRef pvc, SecCertificatePathVCRef path) {
2411 pvc->policyIX = 0;
2412
2413 /* Since we don't run the LeafChecks again, we need to preserve the
2414 * result the leaf had. */
2415 CFIndex ix, pathLength = SecCertificatePathVCGetCount(path);
2416 CFMutableArrayRef details = CFArrayCreateMutableCopy(kCFAllocatorDefault,
2417 pathLength, pvc->leafDetails);
2418 for (ix = 1; ix < pathLength; ++ix) {
2419 CFMutableDictionaryRef certDetail = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
2420 &kCFTypeDictionaryKeyCallBacks,
2421 &kCFTypeDictionaryValueCallBacks);
2422 CFArrayAppendValue(details, certDetail);
2423 CFRelease(certDetail);
2424 }
2425 CFRetainAssign(pvc->details, details);
2426 pvc->result = pvc->leafResult;
2427 CFReleaseSafe(details);
2428 }
2429
2430 SecPolicyRef SecPVCGetPolicy(SecPVCRef pvc) {
2431 return (SecPolicyRef)CFArrayGetValueAtIndex(pvc->policies, pvc->policyIX);
2432 }
2433
2434 static CFIndex SecPVCGetCertificateCount(SecPVCRef pvc) {
2435 return SecPathBuilderGetCertificateCount(pvc->builder);
2436 }
2437
2438 static SecCertificateRef SecPVCGetCertificateAtIndex(SecPVCRef pvc, CFIndex ix) {
2439 return SecPathBuilderGetCertificateAtIndex(pvc->builder, ix);
2440 }
2441
2442 static CFAbsoluteTime SecPVCGetVerifyTime(SecPVCRef pvc) {
2443 return SecPathBuilderGetVerifyTime(pvc->builder);
2444 }
2445
2446 static bool SecPVCIsExceptedError(SecPVCRef pvc, CFIndex ix, CFStringRef key, CFTypeRef value) {
2447 CFArrayRef exceptions = SecPathBuilderGetExceptions(pvc->builder);
2448 if (!exceptions) { return false; }
2449 CFIndex exceptionsCount = CFArrayGetCount(exceptions);
2450
2451 /* There are two types of exceptions:
2452 * 1. Those that are built from SecTrustCopyExceptions, which are particular to the
2453 * certs in the chain -- as indicated by the SHA1 digest in the exception dictionary.
2454 * 2. On macOS, those built from SecTrustSetOptions, which are generic excepted errors.
2455 */
2456 #if TARGET_OS_OSX
2457 CFDictionaryRef options = CFArrayGetValueAtIndex(exceptions, 0);
2458 /* Type 2 */
2459 if (exceptionsCount == 1 && (ix > 0 || !CFDictionaryContainsKey(options, kSecCertificateDetailSHA1Digest))) {
2460 /* SHA1Digest not allowed */
2461 if (CFDictionaryContainsKey(options, kSecCertificateDetailSHA1Digest)) { return false; }
2462 /* Key excepted */
2463 if (CFDictionaryContainsKey(options, key)) {
2464 /* Special case -- AnchorTrusted only for self-signed certs */
2465 if (CFEqual(kSecPolicyCheckAnchorTrusted, key)) {
2466 Boolean isSelfSigned = false;
2467 SecCertificateRef cert = SecPathBuilderGetCertificateAtIndex(pvc->builder, ix);
2468 if (!cert || (errSecSuccess != SecCertificateIsSelfSigned(cert, &isSelfSigned)) || !isSelfSigned) {
2469 return false;
2470 }
2471 }
2472 return true;
2473 } else if (CFEqual(key, kSecPolicyCheckTemporalValidity) && CFDictionaryContainsKey(options, kSecPolicyCheckValidRoot)) {
2474 /* Another special case - ValidRoot excepts Valid only for self-signed certs */
2475 Boolean isSelfSigned = false;
2476 SecCertificateRef cert = SecPathBuilderGetCertificateAtIndex(pvc->builder, ix);
2477 if (!cert || (errSecSuccess != SecCertificateIsSelfSigned(cert, &isSelfSigned)) || !isSelfSigned) {
2478 return false;
2479 }
2480 return true;
2481 }
2482 }
2483 #endif
2484
2485 /* Type 1 */
2486 if (ix >= exceptionsCount) { return false; }
2487 CFDictionaryRef exception = CFArrayGetValueAtIndex(exceptions, ix);
2488
2489 /* Compare the cert hash */
2490 if (!CFDictionaryContainsKey(exception, kSecCertificateDetailSHA1Digest)) { return false; }
2491 SecCertificateRef cert = SecPathBuilderGetCertificateAtIndex(pvc->builder, ix);
2492 if (!CFEqual(SecCertificateGetSHA1Digest(cert), CFDictionaryGetValue(exception, kSecCertificateDetailSHA1Digest))) {
2493 return false;
2494 }
2495
2496 /* Key Excepted */
2497 CFTypeRef exceptionValue = CFDictionaryGetValue(exception, key);
2498 if (exceptionValue && CFEqual(value, exceptionValue)) {
2499 /* Only change result if PVC is already ok */
2500 if (SecPVCIsOkResult(pvc)) {
2501 // Chains that pass due to exceptions get Proceed result.
2502 pvc->result = kSecTrustResultProceed;
2503 }
2504 return true;
2505 }
2506
2507 return false;
2508 }
2509
2510 static int32_t detailKeyToCssmErr(CFStringRef key) {
2511 int32_t result = 0;
2512
2513 if (CFEqual(key, kSecPolicyCheckSSLHostname)) {
2514 result = -2147408896; // CSSMERR_APPLETP_HOSTNAME_MISMATCH
2515 }
2516 else if (CFEqual(key, kSecPolicyCheckEmail)) {
2517 result = -2147408872; // CSSMERR_APPLETP_SMIME_EMAIL_ADDRS_NOT_FOUND
2518 }
2519 else if (CFEqual(key, kSecPolicyCheckTemporalValidity)) {
2520 result = -2147409654; // CSSMERR_TP_CERT_EXPIRED
2521 }
2522
2523 return result;
2524 }
2525
2526 static bool SecPVCMeetsConstraint(SecPVCRef pvc, SecCertificateRef certificate, CFDictionaryRef constraint);
2527
2528 static bool SecPVCIsAllowedError(SecPVCRef pvc, CFIndex ix, CFStringRef key) {
2529 bool result = false;
2530 SecCertificatePathVCRef path = SecPathBuilderGetPath(pvc->builder);
2531 CFArrayRef constraints = SecCertificatePathVCGetUsageConstraintsAtIndex(path, ix);
2532 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix);
2533 CFIndex constraintIX, constraintCount = CFArrayGetCount(constraints);
2534
2535 for (constraintIX = 0; constraintIX < constraintCount; constraintIX++) {
2536 CFDictionaryRef constraint = (CFDictionaryRef)CFArrayGetValueAtIndex(constraints, constraintIX);
2537 CFNumberRef allowedErrorNumber = NULL;
2538 if (!isDictionary(constraint)) {
2539 continue;
2540 }
2541 allowedErrorNumber = (CFNumberRef)CFDictionaryGetValue(constraint, kSecTrustSettingsAllowedError);
2542 int32_t allowedErrorValue = 0;
2543 if (!isNumber(allowedErrorNumber) || !CFNumberGetValue(allowedErrorNumber, kCFNumberSInt32Type, &allowedErrorValue)) {
2544 continue;
2545 }
2546
2547 if (SecPVCMeetsConstraint(pvc, cert, constraint)) {
2548 if (allowedErrorValue == detailKeyToCssmErr(key)) {
2549 result = true;
2550 break;
2551 }
2552 }
2553 }
2554 return result;
2555 }
2556
2557 static bool SecPVCKeyIsConstraintPolicyOption(SecPVCRef pvc, CFStringRef key) {
2558 CFIndex certIX, certCount = SecPVCGetCertificateCount(pvc);
2559 for (certIX = 0; certIX < certCount; certIX++) {
2560 SecCertificatePathVCRef path = SecPathBuilderGetPath(pvc->builder);
2561 CFArrayRef constraints = SecCertificatePathVCGetUsageConstraintsAtIndex(path, certIX);
2562 CFIndex constraintIX, constraintCount = CFArrayGetCount(constraints);
2563 for (constraintIX = 0; constraintIX < constraintCount; constraintIX++) {
2564 CFDictionaryRef constraint = (CFDictionaryRef)CFArrayGetValueAtIndex(constraints, constraintIX);
2565 if (!isDictionary(constraint)) {
2566 continue;
2567 }
2568
2569 CFDictionaryRef policyOptions = NULL;
2570 policyOptions = (CFDictionaryRef)CFDictionaryGetValue(constraint, kSecTrustSettingsPolicyOptions);
2571 if (policyOptions && isDictionary(policyOptions) &&
2572 CFDictionaryContainsKey(policyOptions, key)) {
2573 return true;
2574 }
2575 }
2576 }
2577 return false;
2578 }
2579
2580 static SecTrustResultType trust_result_for_key(CFStringRef key) {
2581 SecTrustResultType result = kSecTrustResultRecoverableTrustFailure;
2582 #undef POLICYCHECKMACRO
2583 #define __PC_TYPE_MEMBER_ false
2584 #define __PC_TYPE_MEMBER_R false
2585 #define __PC_TYPE_MEMBER_F true
2586 #define __PC_TYPE_MEMBER_D true
2587
2588 #define __TRUSTRESULT_ kSecTrustResultRecoverableTrustFailure
2589 #define __TRUSTRESULT_F kSecTrustResultFatalTrustFailure
2590 #define __TRUSTRESULT_D kSecTrustResultDeny
2591 #define __TRUSTRESULT_R kSecTrustResultRecoverableTrustFailure
2592
2593 #define POLICYCHECKMACRO(NAME, TRUSTRESULT, SUBTYPE, LEAFCHECK, PATHCHECK, LEAFONLY, CSSMERR, OSSTATUS) \
2594 if (__PC_TYPE_MEMBER_##TRUSTRESULT && CFEqual(key,CFSTR(#NAME))) { \
2595 result = __TRUSTRESULT_##TRUSTRESULT; \
2596 }
2597 #include "../Security/SecPolicyChecks.list"
2598 return result;
2599 }
2600
2601
2602 /* AUDIT[securityd](done):
2603 policy->_options is a caller provided dictionary, only its cf type has
2604 been checked.
2605 */
2606 bool SecPVCSetResultForced(SecPVCRef pvc,
2607 CFStringRef key, CFIndex ix, CFTypeRef result, bool force) {
2608
2609 secnotice("policy", "cert[%d]: %@ =(%s)[%s]> %@", (int) ix, key,
2610 (pvc->callbacks == gSecPolicyLeafCallbacks ? "leaf"
2611 : (pvc->callbacks == gSecPolicyPathCallbacks ? "path"
2612 : "custom")),
2613 (force ? "force" : ""), result);
2614
2615 /* If this is not something the current policy cares about ignore
2616 this error and return true so our caller continues evaluation. */
2617 if (!force) {
2618 /* Either the policy or the usage constraints have to have this key */
2619 SecPolicyRef policy = SecPVCGetPolicy(pvc);
2620 if (!(SecPVCKeyIsConstraintPolicyOption(pvc, key) ||
2621 (policy && CFDictionaryContainsKey(policy->_options, key)))) {
2622 return true;
2623 }
2624 }
2625
2626 /* Check to see if the SecTrustSettings for the certificate in question
2627 tell us to ignore this error. */
2628 if (SecPVCIsAllowedError(pvc, ix, key)) {
2629 secinfo("policy", "cert[%d]: skipped allowed error %@", (int) ix, key);
2630 return true;
2631 }
2632
2633 /* Check to see if exceptions tells us to ignore this error. */
2634 if (SecPVCIsExceptedError(pvc, ix, key, result)) {
2635 secinfo("policy", "cert[%d]: skipped exception error %@", (int) ix, key);
2636 return true;
2637 }
2638
2639 /* Avoid resetting deny or fatal to recoverable */
2640 SecTrustResultType trustResult = trust_result_for_key(key);
2641 if (SecPVCIsOkResult(pvc) || trustResult == kSecTrustResultFatalTrustFailure) {
2642 pvc->result = trustResult;
2643 } else if (trustResult == kSecTrustResultDeny &&
2644 pvc->result == kSecTrustResultRecoverableTrustFailure) {
2645 pvc->result = trustResult;
2646 }
2647
2648 if (!pvc->details)
2649 return false;
2650
2651 CFMutableDictionaryRef detail =
2652 (CFMutableDictionaryRef)CFArrayGetValueAtIndex(pvc->details, ix);
2653
2654 /* Perhaps detail should have an array of results per key? As it stands
2655 in the case of multiple policy failures the last failure stands. */
2656 CFDictionarySetValue(detail, key, result);
2657
2658 return true;
2659 }
2660
2661 bool SecPVCSetResult(SecPVCRef pvc,
2662 CFStringRef key, CFIndex ix, CFTypeRef result) {
2663 return SecPVCSetResultForced(pvc, key, ix, result, false);
2664 }
2665
2666 /* AUDIT[securityd](done):
2667 key(ok) is a caller provided.
2668 value(ok, unused) is a caller provided.
2669 */
2670 static void SecPVCValidateKey(const void *key, const void *value,
2671 void *context) {
2672 SecPVCRef pvc = (SecPVCRef)context;
2673
2674 /* If our caller doesn't want full details and we failed earlier there is
2675 no point in doing additional checks. */
2676 if (!SecPVCIsOkResult(pvc) && !pvc->details)
2677 return;
2678
2679 SecPolicyCheckFunction fcn = (SecPolicyCheckFunction)
2680 CFDictionaryGetValue(pvc->callbacks, key);
2681
2682 if (!fcn) {
2683 /* "Optional" policy checks. This may be a new key from the
2684 * pinning DB which is not implemented in this OS version. Log a
2685 * warning, and on debug builds fail evaluation, to encourage us
2686 * to ensure that checks are synchronized across the same build. */
2687 if (pvc->callbacks == gSecPolicyLeafCallbacks) {
2688 if (!CFDictionaryContainsKey(gSecPolicyPathCallbacks, key)) {
2689 secwarning("policy: unknown policy key %@, skipping", key);
2690 #if DEBUG
2691 pvc->result = kSecTrustResultOtherError;
2692 #endif
2693 }
2694 } else if (pvc->callbacks == gSecPolicyPathCallbacks) {
2695 if (!CFDictionaryContainsKey(gSecPolicyLeafCallbacks, key)) {
2696 secwarning("policy: unknown policy key %@, skipping", key);
2697 #if DEBUG
2698 pvc->result = kSecTrustResultOtherError;
2699 #endif
2700 }
2701 } else {
2702 /* Non standard validation phase, nothing is optional. */
2703 pvc->result = kSecTrustResultOtherError;
2704 }
2705 return;
2706 }
2707
2708 fcn(pvc, (CFStringRef)key);
2709 }
2710
2711 /* AUDIT[securityd](done):
2712 policy->_options is a caller provided dictionary, only its cf type has
2713 been checked.
2714 */
2715 SecTrustResultType SecPVCLeafChecks(SecPVCRef pvc) {
2716 /* We need to compute details for the leaf. */
2717 CFRetainAssign(pvc->details, pvc->leafDetails);
2718
2719 CFArrayRef policies = pvc->policies;
2720 CFIndex ix, count = CFArrayGetCount(policies);
2721 for (ix = 0; ix < count; ++ix) {
2722 SecPolicyRef policy = (SecPolicyRef)CFArrayGetValueAtIndex(policies, ix);
2723 pvc->policyIX = ix;
2724 /* Validate all keys for all policies. */
2725 pvc->callbacks = gSecPolicyLeafCallbacks;
2726 CFDictionaryApplyFunction(policy->_options, SecPVCValidateKey, pvc);
2727 }
2728
2729 pvc->leafResult = pvc->result;
2730 CFRetainAssign(pvc->leafDetails, pvc->details);
2731
2732 return pvc->result;
2733 }
2734
2735 bool SecPVCIsOkResult(SecPVCRef pvc) {
2736 if (pvc->result == kSecTrustResultRecoverableTrustFailure ||
2737 pvc->result == kSecTrustResultDeny ||
2738 pvc->result == kSecTrustResultFatalTrustFailure ||
2739 pvc->result == kSecTrustResultOtherError) {
2740 return false;
2741 }
2742 return true;
2743 }
2744
2745 bool SecPVCParentCertificateChecks(SecPVCRef pvc, CFIndex ix) {
2746 /* Check stuff common to intermediate and anchors. */
2747 CFAbsoluteTime verifyTime = SecPVCGetVerifyTime(pvc);
2748 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix);
2749 CFIndex anchor_ix = SecPVCGetCertificateCount(pvc) - 1;
2750 bool is_anchor = (ix == anchor_ix && SecPathBuilderIsAnchored(pvc->builder));
2751
2752 if (!SecCertificateIsValid(cert, verifyTime)) {
2753 /* Certificate has expired. */
2754 if (!SecPVCSetResult(pvc, kSecPolicyCheckTemporalValidity, ix, kCFBooleanFalse)) {
2755 goto errOut;
2756 }
2757 }
2758
2759 if (SecCertificateIsWeakKey(cert)) {
2760 /* Certificate uses weak key. */
2761 if (!SecPVCSetResult(pvc, kSecPolicyCheckWeakKeySize, ix, kCFBooleanFalse)) {
2762 goto errOut;
2763 }
2764 }
2765
2766 if (!SecPolicyCheckCertWeakSignature(cert, NULL)) {
2767 /* Certificate uses weak hash. */
2768 if (!SecPVCSetResult(pvc, kSecPolicyCheckWeakSignature, ix, kCFBooleanFalse)) {
2769 goto errOut;
2770 }
2771 }
2772
2773 if (is_anchor) {
2774 /* Perform anchor specific checks. */
2775 /* Don't think we have any of these. */
2776 } else {
2777 /* Perform intermediate specific checks. */
2778
2779 /* (k) Basic constraints only relevant for v3 and later. */
2780 if (SecCertificateVersion(cert) >= 3) {
2781 const SecCEBasicConstraints *bc =
2782 SecCertificateGetBasicConstraints(cert);
2783 if (!bc) {
2784 /* Basic constraints not present, illegal. */
2785 if (!SecPVCSetResultForced(pvc, kSecPolicyCheckBasicConstraints,
2786 ix, kCFBooleanFalse, true)) {
2787 goto errOut;
2788 }
2789 } else if (!bc->isCA) {
2790 /* Basic constraints not marked as isCA, illegal. */
2791 if (!SecPVCSetResultForced(pvc, kSecPolicyCheckBasicConstraintsCA,
2792 ix, kCFBooleanFalse, true)) {
2793 goto errOut;
2794 }
2795 }
2796 }
2797 /* For a v1 or v2 certificate in an intermediate slot (not a leaf and
2798 not an anchor), we additionally require that the certificate chain
2799 does not end in a v3 or later anchor. [rdar://32204517] */
2800 else if (ix > 0 && ix < anchor_ix) {
2801 SecCertificateRef anchor = SecPVCGetCertificateAtIndex(pvc, anchor_ix);
2802 if (SecCertificateVersion(anchor) >= 3) {
2803 if (!SecPVCSetResultForced(pvc, kSecPolicyCheckBasicConstraints,
2804 ix, kCFBooleanFalse, true)) {
2805 goto errOut;
2806 }
2807 }
2808 }
2809 /* (l) max_path_length is checked elsewhere. */
2810
2811 /* (n) If a key usage extension is present, verify that the keyCertSign bit is set. */
2812 SecKeyUsage keyUsage = SecCertificateGetKeyUsage(cert);
2813 if (keyUsage && !(keyUsage & kSecKeyUsageKeyCertSign)) {
2814 if (!SecPVCSetResultForced(pvc, kSecPolicyCheckKeyUsage,
2815 ix, kCFBooleanFalse, true)) {
2816 goto errOut;
2817 }
2818 }
2819 }
2820
2821 errOut:
2822 return SecPVCIsOkResult(pvc);
2823 }
2824
2825 static bool SecPVCBlackListedKeyChecks(SecPVCRef pvc, CFIndex ix) {
2826 /* Check stuff common to intermediate and anchors. */
2827
2828 SecOTAPKIRef otapkiRef = SecOTAPKICopyCurrentOTAPKIRef();
2829 if (NULL != otapkiRef)
2830 {
2831 CFSetRef blackListedKeys = SecOTAPKICopyBlackListSet(otapkiRef);
2832 CFRelease(otapkiRef);
2833 if (NULL != blackListedKeys)
2834 {
2835 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix);
2836 CFIndex count = SecPVCGetCertificateCount(pvc);
2837 bool is_last = (ix == count - 1);
2838 bool is_anchor = (is_last && SecPathBuilderIsAnchored(pvc->builder));
2839 if (!is_anchor) {
2840 /* Check for blacklisted intermediate issuer keys. */
2841 CFDataRef dgst = SecCertificateCopyPublicKeySHA1Digest(cert);
2842 if (dgst) {
2843 /* Check dgst against blacklist. */
2844 if (CFSetContainsValue(blackListedKeys, dgst)) {
2845 /* Check allow list for this blacklisted issuer key,
2846 which is the authority key of the issued cert at ix-1.
2847 */
2848 SecCertificatePathVCRef path = SecPathBuilderGetPath(pvc->builder);
2849 bool allowed = path && SecCertificatePathVCIsAllowlisted(path);
2850 if (!allowed) {
2851 SecPVCSetResultForced(pvc, kSecPolicyCheckBlackListedKey,
2852 ix, kCFBooleanFalse, true);
2853 }
2854 }
2855 CFRelease(dgst);
2856 }
2857 }
2858 CFRelease(blackListedKeys);
2859 return SecPVCIsOkResult(pvc);
2860 }
2861 }
2862 // Assume OK
2863 return true;
2864 }
2865
2866 static bool SecPVCGrayListedKeyChecks(SecPVCRef pvc, CFIndex ix)
2867 {
2868 /* Check stuff common to intermediate and anchors. */
2869 SecOTAPKIRef otapkiRef = SecOTAPKICopyCurrentOTAPKIRef();
2870 if (NULL != otapkiRef)
2871 {
2872 CFSetRef grayListKeys = SecOTAPKICopyGrayList(otapkiRef);
2873 CFRelease(otapkiRef);
2874 if (NULL != grayListKeys)
2875 {
2876 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix);
2877 CFIndex count = SecPVCGetCertificateCount(pvc);
2878 bool is_last = (ix == count - 1);
2879 bool is_anchor = (is_last && SecPathBuilderIsAnchored(pvc->builder));
2880 if (!is_anchor) {
2881 /* Check for gray listed intermediate issuer keys. */
2882 CFDataRef dgst = SecCertificateCopyPublicKeySHA1Digest(cert);
2883 if (dgst) {
2884 /* Check dgst against gray list. */
2885 if (CFSetContainsValue(grayListKeys, dgst)) {
2886 /* Check allow list for this graylisted issuer key,
2887 which is the authority key of the issued cert at ix-1.
2888 */
2889 SecCertificatePathVCRef path = SecPathBuilderGetPath(pvc->builder);
2890 bool allowed = path && SecCertificatePathVCIsAllowlisted(path);
2891 if (!allowed) {
2892 SecPVCSetResultForced(pvc, kSecPolicyCheckGrayListedKey,
2893 ix, kCFBooleanFalse, true);
2894 }
2895 }
2896 CFRelease(dgst);
2897 }
2898 }
2899 CFRelease(grayListKeys);
2900 return SecPVCIsOkResult(pvc);
2901 }
2902 }
2903 // Assume ok
2904 return true;
2905 }
2906
2907 static bool SecPVCContainsPolicy(SecPVCRef pvc, CFStringRef searchOid, CFStringRef searchName, CFIndex *policyIX) {
2908 if (!isString(searchName) && !isString(searchOid)) {
2909 return false;
2910 }
2911 CFArrayRef policies = pvc->policies;
2912 CFIndex ix, count = CFArrayGetCount(policies);
2913 for (ix = 0; ix < count; ++ix) {
2914 SecPolicyRef policy = (SecPolicyRef)CFArrayGetValueAtIndex(policies, ix);
2915 CFStringRef policyName = SecPolicyGetName(policy);
2916 CFStringRef policyOid = SecPolicyGetOidString(policy);
2917 /* Prefer a match of both name and OID */
2918 if (searchOid && searchName && policyOid && policyName) {
2919 if (CFEqual(searchOid, policyOid) &&
2920 CFEqual(searchName, policyName)) {
2921 if (policyIX) { *policyIX = ix; }
2922 return true;
2923 }
2924 /* <rdar://40617139> sslServer trust settings need to apply to evals using policyName pinning
2925 * but make sure we don't use this for SSL Client trust settings or policies. */
2926 if (CFEqual(searchOid, policyOid) &&
2927 CFEqual(searchName, kSecPolicyNameSSLServer) && !CFEqual(policyName, kSecPolicyNameSSLClient)) {
2928 if (policyIX) { *policyIX = ix; }
2929 return true;
2930 }
2931 }
2932 /* Next best is just OID. */
2933 if (!searchName && searchOid && policyOid) {
2934 if (CFEqual(searchOid, policyOid)) {
2935 if (policyIX) { *policyIX = ix; }
2936 return true;
2937 }
2938 }
2939 if (!searchOid && searchName && policyName) {
2940 if (CFEqual(searchName, policyName)) {
2941 if (policyIX) { *policyIX = ix; }
2942 return true;
2943 }
2944 }
2945 }
2946 return false;
2947 }
2948
2949 static bool SecPVCContainsString(SecPVCRef pvc, CFIndex policyIX, CFStringRef stringValue) {
2950 if (!isString(stringValue)) {
2951 return false;
2952 }
2953 bool result = false;
2954
2955 CFStringRef tmpStringValue = NULL;
2956 if (CFStringGetCharacterAtIndex(stringValue, CFStringGetLength(stringValue) -1) == (UniChar)0x0000) {
2957 tmpStringValue = CFStringCreateTruncatedCopy(stringValue, CFStringGetLength(stringValue) - 1);
2958 } else {
2959 tmpStringValue = CFStringCreateCopy(NULL, stringValue);
2960 }
2961 if (policyIX >= 0 && policyIX < CFArrayGetCount(pvc->policies)) {
2962 SecPolicyRef policy = (SecPolicyRef)CFArrayGetValueAtIndex(pvc->policies, policyIX);
2963 /* Have to look for all the possible locations of name string */
2964 CFStringRef policyString = NULL;
2965 policyString = CFDictionaryGetValue(policy->_options, kSecPolicyCheckSSLHostname);
2966 if (!policyString) {
2967 policyString = CFDictionaryGetValue(policy->_options, kSecPolicyCheckEmail);
2968 }
2969 if (policyString && (CFStringCompare(tmpStringValue, policyString, kCFCompareCaseInsensitive) == kCFCompareEqualTo)) {
2970 result = true;
2971 goto out;
2972 }
2973
2974 CFArrayRef policyStrings = NULL;
2975 policyStrings = CFDictionaryGetValue(policy->_options, kSecPolicyCheckEAPTrustedServerNames);
2976 if (policyStrings && CFArrayContainsValue(policyStrings,
2977 CFRangeMake(0, CFArrayGetCount(policyStrings)),
2978 tmpStringValue)) {
2979 result = true;
2980 goto out;
2981 }
2982 }
2983
2984 out:
2985 CFReleaseNull(tmpStringValue);
2986 return result;
2987 }
2988
2989
2990 static uint32_t ts_key_usage_for_kuNumber(CFNumberRef keyUsageNumber) {
2991 uint32_t ourTSKeyUsage = 0;
2992 uint32_t keyUsage = 0;
2993 if (keyUsageNumber &&
2994 CFNumberGetValue(keyUsageNumber, kCFNumberSInt32Type, &keyUsage)) {
2995 if (keyUsage & kSecKeyUsageDigitalSignature) {
2996 ourTSKeyUsage |= kSecTrustSettingsKeyUseSignature;
2997 }
2998 if (keyUsage & kSecKeyUsageDataEncipherment) {
2999 ourTSKeyUsage |= kSecTrustSettingsKeyUseEnDecryptData;
3000 }
3001 if (keyUsage & kSecKeyUsageKeyEncipherment) {
3002 ourTSKeyUsage |= kSecTrustSettingsKeyUseEnDecryptKey;
3003 }
3004 if (keyUsage & kSecKeyUsageKeyAgreement) {
3005 ourTSKeyUsage |= kSecTrustSettingsKeyUseKeyExchange;
3006 }
3007 if (keyUsage == kSecKeyUsageAll) {
3008 ourTSKeyUsage = kSecTrustSettingsKeyUseAny;
3009 }
3010 }
3011 return ourTSKeyUsage;
3012 }
3013
3014 static uint32_t ts_key_usage_for_policy(SecPolicyRef policy) {
3015 uint32_t ourTSKeyUsage = 0;
3016 CFTypeRef policyKeyUsageType = NULL;
3017
3018 policyKeyUsageType = (CFTypeRef)CFDictionaryGetValue(policy->_options, kSecPolicyCheckKeyUsage);
3019 if (isArray(policyKeyUsageType)) {
3020 CFIndex ix, count = CFArrayGetCount(policyKeyUsageType);
3021 for (ix = 0; ix < count; ix++) {
3022 CFNumberRef policyKeyUsageNumber = NULL;
3023 policyKeyUsageNumber = (CFNumberRef)CFArrayGetValueAtIndex(policyKeyUsageType, ix);
3024 ourTSKeyUsage |= ts_key_usage_for_kuNumber(policyKeyUsageNumber);
3025 }
3026 } else if (isNumber(policyKeyUsageType)) {
3027 ourTSKeyUsage |= ts_key_usage_for_kuNumber(policyKeyUsageType);
3028 }
3029
3030 return ourTSKeyUsage;
3031 }
3032
3033 static bool SecPVCContainsTrustSettingsKeyUsage(SecPVCRef pvc,
3034 SecCertificateRef certificate, CFIndex policyIX, CFNumberRef keyUsageNumber) {
3035 int64_t keyUsageValue = 0;
3036 uint32_t ourKeyUsage = 0;
3037
3038 if (!isNumber(keyUsageNumber) || !CFNumberGetValue(keyUsageNumber, kCFNumberSInt64Type, &keyUsageValue)) {
3039 return false;
3040 }
3041
3042 if (keyUsageValue == kSecTrustSettingsKeyUseAny) {
3043 return true;
3044 }
3045
3046 /* We're using the key for revocation if we have the OCSPSigner policy.
3047 * @@@ If we support CRLs, we'd need to check for that policy here too.
3048 */
3049 if (SecPVCContainsPolicy(pvc, kSecPolicyAppleOCSPSigner, NULL, NULL)) {
3050 ourKeyUsage |= kSecTrustSettingsKeyUseSignRevocation;
3051 }
3052
3053 /* We're using the key for verifying a cert if it's a root/intermediate
3054 * in the chain. If the cert isn't in the path yet, we're about to add it,
3055 * so it's a root/intermediate. If there is no path, this is the leaf.
3056 */
3057 CFIndex pathIndex = -1;
3058 SecCertificatePathVCRef path = SecPathBuilderGetPath(pvc->builder);
3059 if (path) {
3060 pathIndex = SecCertificatePathVCGetIndexOfCertificate(path, certificate);
3061 } else {
3062 pathIndex = 0;
3063 }
3064 if (pathIndex != 0) {
3065 ourKeyUsage |= kSecTrustSettingsKeyUseSignCert;
3066 }
3067
3068 /* The rest of the key usages may be specified by the policy(ies). */
3069 if (policyIX >= 0 && policyIX < CFArrayGetCount(pvc->policies)) {
3070 SecPolicyRef policy = (SecPolicyRef)CFArrayGetValueAtIndex(pvc->policies, policyIX);
3071 ourKeyUsage |= ts_key_usage_for_policy(policy);
3072 } else {
3073 /* Get key usage from ALL policies */
3074 CFIndex ix, count = CFArrayGetCount(pvc->policies);
3075 for (ix = 0; ix < count; ix++) {
3076 SecPolicyRef policy = (SecPolicyRef)CFArrayGetValueAtIndex(pvc->policies, ix);
3077 ourKeyUsage |= ts_key_usage_for_policy(policy);
3078 }
3079 }
3080
3081 if (ourKeyUsage == (uint32_t)(keyUsageValue & 0x00ffffffff)) {
3082 return true;
3083 }
3084
3085 return false;
3086 }
3087
3088 #if TARGET_OS_OSX
3089 #include <Security/SecTrustedApplicationPriv.h>
3090 #include <Security/SecTask.h>
3091 #include <Security/SecTaskPriv.h>
3092 #include <bsm/libbsm.h>
3093 #include <libproc.h>
3094
3095 extern OSStatus SecTaskValidateForRequirement(SecTaskRef task, CFStringRef requirement);
3096
3097 static bool SecPVCCallerIsApplication(CFDataRef clientAuditToken, CFTypeRef appRef) {
3098 bool result = false;
3099 audit_token_t auditToken = {};
3100 SecTaskRef task = NULL;
3101 SecRequirementRef requirement = NULL;
3102 CFStringRef stringRequirement = NULL;
3103
3104 require(appRef && clientAuditToken, out);
3105 require(CFGetTypeID(appRef) == SecTrustedApplicationGetTypeID(), out);
3106 require_noerr(SecTrustedApplicationCopyRequirement((SecTrustedApplicationRef)appRef, &requirement), out);
3107 require(requirement, out);
3108 require_noerr(SecRequirementsCopyString(requirement, kSecCSDefaultFlags, &stringRequirement), out);
3109 require(stringRequirement, out);
3110
3111 require(sizeof(auditToken) == CFDataGetLength(clientAuditToken), out);
3112 CFDataGetBytes(clientAuditToken, CFRangeMake(0, sizeof(auditToken)), (uint8_t *)&auditToken);
3113 require(task = SecTaskCreateWithAuditToken(NULL, auditToken), out);
3114
3115 if(errSecSuccess == SecTaskValidateForRequirement(task, stringRequirement)) {
3116 result = true;
3117 }
3118
3119 out:
3120 CFReleaseNull(task);
3121 CFReleaseNull(requirement);
3122 CFReleaseNull(stringRequirement);
3123 return result;
3124 }
3125 #endif
3126
3127 static bool SecPVCContainsTrustSettingsPolicyOption(SecPVCRef pvc, CFDictionaryRef options) {
3128 if (!isDictionary(options)) {
3129 return false;
3130 }
3131
3132 /* Push */
3133 CFDictionaryRef currentCallbacks = pvc->callbacks;
3134
3135 /* We need to run the leaf and path checks using these options. */
3136 pvc->callbacks = gSecPolicyLeafCallbacks;
3137 CFDictionaryApplyFunction(options, SecPVCValidateKey, pvc);
3138
3139 pvc->callbacks = gSecPolicyPathCallbacks;
3140 CFDictionaryApplyFunction(options, SecPVCValidateKey, pvc);
3141
3142 /* Pop */
3143 pvc->callbacks = currentCallbacks;
3144
3145 /* Our work here is done; no need to claim a match */
3146 return false;
3147 }
3148
3149 static bool SecPVCMeetsConstraint(SecPVCRef pvc, SecCertificateRef certificate, CFDictionaryRef constraint) {
3150 CFStringRef policyOid = NULL, policyString = NULL, policyName = NULL;
3151 CFNumberRef keyUsageNumber = NULL;
3152 CFTypeRef trustedApplicationData = NULL;
3153 CFDictionaryRef policyOptions = NULL;
3154
3155 bool policyMatch = false, policyStringMatch = false, applicationMatch = false ,
3156 keyUsageMatch = false, policyOptionMatch = false;
3157 bool result = false;
3158
3159 #if TARGET_OS_MAC && !TARGET_OS_IPHONE
3160 /* OS X returns a SecPolicyRef in the constraints. Convert to the oid string. */
3161 SecPolicyRef policy = NULL;
3162 policy = (SecPolicyRef)CFDictionaryGetValue(constraint, kSecTrustSettingsPolicy);
3163 policyOid = (policy) ? policy->_oid : NULL;
3164 #else
3165 policyOid = (CFStringRef)CFDictionaryGetValue(constraint, kSecTrustSettingsPolicy);
3166 #endif
3167 policyName = (CFStringRef)CFDictionaryGetValue(constraint, kSecTrustSettingsPolicyName);
3168 policyString = (CFStringRef)CFDictionaryGetValue(constraint, kSecTrustSettingsPolicyString);
3169 keyUsageNumber = (CFNumberRef)CFDictionaryGetValue(constraint, kSecTrustSettingsKeyUsage);
3170 policyOptions = (CFDictionaryRef)CFDictionaryGetValue(constraint, kSecTrustSettingsPolicyOptions);
3171
3172 CFIndex policyIX = -1;
3173 policyMatch = SecPVCContainsPolicy(pvc, policyOid, policyName, &policyIX);
3174 policyStringMatch = SecPVCContainsString(pvc, policyIX, policyString);
3175 keyUsageMatch = SecPVCContainsTrustSettingsKeyUsage(pvc, certificate, policyIX, keyUsageNumber);
3176 policyOptionMatch = SecPVCContainsTrustSettingsPolicyOption(pvc, policyOptions);
3177
3178 #if TARGET_OS_MAC && !TARGET_OS_IPHONE
3179 trustedApplicationData = CFDictionaryGetValue(constraint, kSecTrustSettingsApplication);
3180 CFDataRef clientAuditToken = SecPathBuilderCopyClientAuditToken(pvc->builder);
3181 applicationMatch = SecPVCCallerIsApplication(clientAuditToken, trustedApplicationData);
3182 CFReleaseNull(clientAuditToken);
3183 #else
3184 if(CFDictionaryContainsKey(constraint, kSecTrustSettingsApplication)) {
3185 secerror("kSecTrustSettingsApplication is not yet supported on this platform");
3186 }
3187 #endif
3188
3189 /* If we either didn't find the parameter in the dictionary or we got a match
3190 * against that parameter, for all possible parameters in the dictionary, then
3191 * this trust setting result applies to the output. */
3192 if (((!policyOid && !policyName) || policyMatch) &&
3193 (!policyString || policyStringMatch) &&
3194 (!trustedApplicationData || applicationMatch) &&
3195 (!keyUsageNumber || keyUsageMatch) &&
3196 (!policyOptions || policyOptionMatch)) {
3197 result = true;
3198 }
3199
3200 return result;
3201 }
3202
3203 SecTrustSettingsResult SecPVCGetTrustSettingsResult(SecPVCRef pvc, SecCertificateRef certificate, CFArrayRef constraints) {
3204 SecTrustSettingsResult result = kSecTrustSettingsResultInvalid;
3205 CFIndex constraintIX, constraintCount = CFArrayGetCount(constraints);
3206 for (constraintIX = 0; constraintIX < constraintCount; constraintIX++) {
3207 CFDictionaryRef constraint = (CFDictionaryRef)CFArrayGetValueAtIndex(constraints, constraintIX);
3208 if (!isDictionary(constraint)) {
3209 continue;
3210 }
3211
3212 CFNumberRef resultNumber = NULL;
3213 resultNumber = (CFNumberRef)CFDictionaryGetValue(constraint, kSecTrustSettingsResult);
3214 uint32_t resultValue = kSecTrustSettingsResultInvalid;
3215 if (!isNumber(resultNumber) || !CFNumberGetValue(resultNumber, kCFNumberSInt32Type, &resultValue)) {
3216 /* no SecTrustSettingsResult entry defaults to TrustRoot*/
3217 resultValue = kSecTrustSettingsResultTrustRoot;
3218 }
3219
3220 if (SecPVCMeetsConstraint(pvc, certificate, constraint)) {
3221 result = resultValue;
3222 break;
3223 }
3224 }
3225 return result;
3226 }
3227
3228 static void SecPVCCheckUsageConstraints(SecPVCRef pvc) {
3229 CFIndex certIX, certCount = SecPVCGetCertificateCount(pvc);
3230 for (certIX = 0; certIX < certCount; certIX++) {
3231 SecCertificatePathVCRef path = SecPathBuilderGetPath(pvc->builder);
3232 CFArrayRef constraints = SecCertificatePathVCGetUsageConstraintsAtIndex(path, certIX);
3233 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, certIX);
3234 SecTrustSettingsResult result = SecPVCGetTrustSettingsResult(pvc, cert, constraints);
3235
3236 /* Set the pvc trust result based on the usage constraints and anchor source. */
3237 if (result == kSecTrustSettingsResultDeny) {
3238 SecPVCSetResultForced(pvc, kSecPolicyCheckUsageConstraints, certIX, kCFBooleanFalse, true);
3239 } else if ((result == kSecTrustSettingsResultTrustRoot || result == kSecTrustSettingsResultTrustAsRoot ||
3240 result == kSecTrustSettingsResultInvalid) && SecPVCIsOkResult(pvc)) {
3241 /* If we already think the PVC is ok and this cert is from one of the user/
3242 * admin anchor sources, trustRoot, trustAsRoot, and Invalid (no constraints),
3243 * all mean we should use the special "Proceed" trust result. */
3244 #if TARGET_OS_IPHONE
3245 if (SecPathBuilderIsAnchorSource(pvc->builder, kSecUserAnchorSource) &&
3246 SecCertificateSourceContains(kSecUserAnchorSource, cert)) {
3247 #else
3248 if (SecPathBuilderIsAnchorSource(pvc->builder, kSecLegacyAnchorSource) &&
3249 SecCertificateSourceContains(kSecLegacyAnchorSource, cert)) {
3250 #endif
3251 pvc->result = kSecTrustResultProceed;
3252 }
3253 }
3254 }
3255 }
3256
3257 static const UInt8 kTestDateConstraintsRoot[kSecPolicySHA256Size] = {
3258 0x51,0xA0,0xF3,0x1F,0xC0,0x1D,0xEC,0x87,0x32,0xB6,0xFD,0x13,0x6A,0x43,0x4D,0x6C,
3259 0x87,0xCD,0x62,0xE0,0x38,0xB4,0xFB,0xD6,0x40,0xB0,0xFD,0x62,0x4D,0x1F,0xCF,0x6D
3260 };
3261 static const UInt8 kWS_CA1_G2[kSecPolicySHA256Size] = {
3262 0xD4,0x87,0xA5,0x6F,0x83,0xB0,0x74,0x82,0xE8,0x5E,0x96,0x33,0x94,0xC1,0xEC,0xC2,
3263 0xC9,0xE5,0x1D,0x09,0x03,0xEE,0x94,0x6B,0x02,0xC3,0x01,0x58,0x1E,0xD9,0x9E,0x16
3264 };
3265 static const UInt8 kWS_CA1_NEW[kSecPolicySHA256Size] = {
3266 0x4B,0x22,0xD5,0xA6,0xAE,0xC9,0x9F,0x3C,0xDB,0x79,0xAA,0x5E,0xC0,0x68,0x38,0x47,
3267 0x9C,0xD5,0xEC,0xBA,0x71,0x64,0xF7,0xF2,0x2D,0xC1,0xD6,0x5F,0x63,0xD8,0x57,0x08
3268 };
3269 static const UInt8 kWS_CA2_NEW[kSecPolicySHA256Size] = {
3270 0xD6,0xF0,0x34,0xBD,0x94,0xAA,0x23,0x3F,0x02,0x97,0xEC,0xA4,0x24,0x5B,0x28,0x39,
3271 0x73,0xE4,0x47,0xAA,0x59,0x0F,0x31,0x0C,0x77,0xF4,0x8F,0xDF,0x83,0x11,0x22,0x54
3272 };
3273 static const UInt8 kWS_ECC[kSecPolicySHA256Size] = {
3274 0x8B,0x45,0xDA,0x1C,0x06,0xF7,0x91,0xEB,0x0C,0xAB,0xF2,0x6B,0xE5,0x88,0xF5,0xFB,
3275 0x23,0x16,0x5C,0x2E,0x61,0x4B,0xF8,0x85,0x56,0x2D,0x0D,0xCE,0x50,0xB2,0x9B,0x02
3276 };
3277 static const UInt8 kSC_SFSCA[kSecPolicySHA256Size] = {
3278 0xC7,0x66,0xA9,0xBE,0xF2,0xD4,0x07,0x1C,0x86,0x3A,0x31,0xAA,0x49,0x20,0xE8,0x13,
3279 0xB2,0xD1,0x98,0x60,0x8C,0xB7,0xB7,0xCF,0xE2,0x11,0x43,0xB8,0x36,0xDF,0x09,0xEA
3280 };
3281 static const UInt8 kSC_SHA2[kSecPolicySHA256Size] = {
3282 0xE1,0x78,0x90,0xEE,0x09,0xA3,0xFB,0xF4,0xF4,0x8B,0x9C,0x41,0x4A,0x17,0xD6,0x37,
3283 0xB7,0xA5,0x06,0x47,0xE9,0xBC,0x75,0x23,0x22,0x72,0x7F,0xCC,0x17,0x42,0xA9,0x11
3284 };
3285 static const UInt8 kSC_G2[kSecPolicySHA256Size] = {
3286 0xC7,0xBA,0x65,0x67,0xDE,0x93,0xA7,0x98,0xAE,0x1F,0xAA,0x79,0x1E,0x71,0x2D,0x37,
3287 0x8F,0xAE,0x1F,0x93,0xC4,0x39,0x7F,0xEA,0x44,0x1B,0xB7,0xCB,0xE6,0xFD,0x59,0x95
3288 };
3289
3290 static void SecPVCCheckIssuerDateConstraints(SecPVCRef pvc) {
3291 static CFSetRef sConstrainedRoots = NULL;
3292 static dispatch_once_t _t;
3293 dispatch_once(&_t, ^{
3294 const UInt8 *v_hashes[] = {
3295 kWS_CA1_G2, kWS_CA1_NEW, kWS_CA2_NEW, kWS_ECC,
3296 kSC_SFSCA, kSC_SHA2, kSC_G2, kTestDateConstraintsRoot
3297 };
3298 CFMutableSetRef set = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks);
3299 CFIndex ix, count = sizeof(v_hashes)/sizeof(*v_hashes);
3300 for (ix=0; ix<count; ix++) {
3301 CFDataRef hash = CFDataCreateWithBytesNoCopy(NULL, v_hashes[ix],
3302 kSecPolicySHA256Size, kCFAllocatorNull);
3303 if (hash) {
3304 CFSetAddValue(set, hash);
3305 CFRelease(hash);
3306 }
3307 }
3308 sConstrainedRoots = set;
3309 });
3310
3311 bool shouldDeny = false;
3312 CFIndex certIX, certCount = SecPVCGetCertificateCount(pvc);
3313 for (certIX = certCount - 1; certIX >= 0 && !shouldDeny; certIX--) {
3314 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, certIX);
3315 CFDataRef sha256 = SecCertificateCopySHA256Digest(cert);
3316 if (sha256 && CFSetContainsValue(sConstrainedRoots, sha256)) {
3317 /* matched a constrained root; check notBefore dates on all its children. */
3318 CFIndex childIX = certIX;
3319 while (--childIX >= 0) {
3320 SecCertificateRef child = SecPVCGetCertificateAtIndex(pvc, childIX);
3321 /* 1 Dec 2016 00:00:00 GMT */
3322 if (child && (CFAbsoluteTime)502243200.0 <= SecCertificateNotValidBefore(child)) {
3323 SecPVCSetResultForced(pvc, kSecPolicyCheckBlackListedKey, certIX, kCFBooleanFalse, true);
3324 shouldDeny = true;
3325 break;
3326 }
3327 }
3328 }
3329 CFReleaseNull(sha256);
3330 }
3331 }
3332
3333 static bool SecPVCIsSSLServerAuthenticationPolicy(SecPVCRef pvc) {
3334 if (!pvc || !pvc->policies) {
3335 return false;
3336 }
3337 SecPolicyRef policy = (SecPolicyRef)CFArrayGetValueAtIndex(pvc->policies, 0);
3338 if (!policy) {
3339 return false;
3340 }
3341 CFStringRef policyName = SecPolicyGetName(policy);
3342 if (CFEqualSafe(policyName, kSecPolicyNameSSLServer)) {
3343 return true;
3344 }
3345 CFDictionaryRef options = policy->_options;
3346 if (options && CFDictionaryGetValue(options, kSecPolicyCheckSSLHostname)) {
3347 return true;
3348 }
3349 return false;
3350 }
3351
3352 /* ASSUMPTIONS:
3353 1. SecPVCCheckRequireCTConstraints must be called after SecPolicyCheckCT,
3354 so earliest issuance time has already been obtained from SCTs.
3355 2. If the issuance time value is 0 (i.e. 2001-01-01) or earlier, we
3356 assume it was not set, and thus we did not have CT info.
3357 */
3358 static void SecPVCCheckRequireCTConstraints(SecPVCRef pvc) {
3359 SecCertificatePathVCRef path = (pvc) ? SecPathBuilderGetPath(pvc->builder) : NULL;
3360 if (!path) {
3361 return;
3362 }
3363 /* If we are evaluating for a SSL server authentication policy, make sure
3364 SCT issuance time is prior to the earliest not-after date constraint.
3365 Note that CT will already be required if there is a not-after date
3366 constraint present (set in SecRVCProcessValidDateConstraints).
3367 */
3368 if (SecPVCIsSSLServerAuthenticationPolicy(pvc)) {
3369 CFIndex ix, certCount = SecCertificatePathVCGetCount(path);
3370 SecCertificateRef certificate = SecPathBuilderGetCertificateAtIndex(pvc->builder, 0);
3371 CFAbsoluteTime earliestNotAfter = 31556908800.0; /* default: 3001-01-01 00:00:00-0000 */
3372 CFAbsoluteTime issuanceTime = SecCertificatePathVCIssuanceTime(path);
3373 if (issuanceTime <= 0) {
3374 /* if not set (or prior to 2001-01-01), use leaf's not-before time. */
3375 issuanceTime = SecCertificateNotValidBefore(certificate);
3376 }
3377 for (ix = 0; ix < certCount; ix++) {
3378 SecRVCRef rvc = SecCertificatePathVCGetRVCAtIndex(path, ix);
3379 if (!rvc || !rvc->valid_info || !rvc->valid_info->hasDateConstraints || !rvc->valid_info->notAfterDate) {
3380 continue;
3381 }
3382 /* Found CA certificate with a not-after date constraint. */
3383 CFAbsoluteTime caNotAfter = CFDateGetAbsoluteTime(rvc->valid_info->notAfterDate);
3384 if (caNotAfter < earliestNotAfter) {
3385 earliestNotAfter = caNotAfter;
3386 }
3387 if (issuanceTime > earliestNotAfter) {
3388 /* Issuance time violates the not-after date constraint. */
3389 secnotice("rvc", "certificate issuance time (%f) is later than allowed value (%f)",
3390 issuanceTime, earliestNotAfter);
3391 SecRVCSetValidDeterminedErrorResult(rvc);
3392 break;
3393 }
3394 }
3395 }
3396 /* If path is CT validated, nothing further to do here. */
3397 if (SecCertificatePathVCIsCT(path)) {
3398 return;
3399 }
3400
3401 /* Path is not CT validated, so check if CT was required. */
3402 SecPathCTPolicy ctp = SecCertificatePathVCRequiresCT(path);
3403 if (ctp <= kSecPathCTNotRequired || !SecPVCIsSSLServerAuthenticationPolicy(pvc)) {
3404 return;
3405 }
3406
3407 /* We need to have a recent log list or the CT check may have failed due to the list being out of date.
3408 * Also, honor the CT kill switch. */
3409 SecOTAPKIRef otaref = SecOTAPKICopyCurrentOTAPKIRef();
3410 if (!SecOTAPKIKillSwitchEnabled(otaref, kOTAPKIKillSwitchCT) &&
3411 SecOTAPKIAssetStalenessLessThanSeconds(otaref, kSecOTAPKIAssetStalenessDisable)) {
3412 /* CT was required. Error is always set on leaf certificate. */
3413 SecPVCSetResultForced(pvc, kSecPolicyCheckCTRequired,
3414 0, kCFBooleanFalse, true);
3415 if (ctp != kSecPathCTRequiredOverridable) {
3416 /* Normally kSecPolicyCheckCTRequired is recoverable,
3417 so need to manually change trust result here. */
3418 pvc->result = kSecTrustResultFatalTrustFailure;
3419 }
3420 }
3421 CFReleaseNull(otaref);
3422 }
3423
3424 /* AUDIT[securityd](done):
3425 policy->_options is a caller provided dictionary, only its cf type has
3426 been checked.
3427 */
3428 void SecPVCPathChecks(SecPVCRef pvc) {
3429 secdebug("policy", "begin path: %@", SecPathBuilderGetPath(pvc->builder));
3430 SecCertificatePathVCRef path = SecPathBuilderGetPath(pvc->builder);
3431 /* This needs to be initialized before we call any function that might call
3432 SecPVCSetResultForced(). */
3433 pvc->policyIX = 0;
3434 SecPolicyCheckIdLinkage(pvc, kSecPolicyCheckIdLinkage);
3435 if (SecPVCIsOkResult(pvc) || pvc->details) {
3436 SecPolicyCheckBasicCertificateProcessing(pvc,
3437 kSecPolicyCheckBasicCertificateProcessing);
3438 }
3439
3440 CFArrayRef policies = pvc->policies;
3441 CFIndex count = CFArrayGetCount(policies);
3442 for (; pvc->policyIX < count; ++pvc->policyIX) {
3443 /* Validate all keys for all policies. */
3444 pvc->callbacks = gSecPolicyPathCallbacks;
3445 SecPolicyRef policy = SecPVCGetPolicy(pvc);
3446 CFDictionaryApplyFunction(policy->_options, SecPVCValidateKey, pvc);
3447 if (!SecPVCIsOkResult(pvc) && !pvc->details)
3448 return;
3449 }
3450
3451 // Reset
3452 pvc->policyIX = 0;
3453
3454 /* Check whether the TrustSettings say to deny a cert in the path. */
3455 SecPVCCheckUsageConstraints(pvc);
3456
3457 /* Check for Blocklisted certs */
3458 SecPVCCheckIssuerDateConstraints(pvc);
3459 CFIndex ix;
3460 count = SecCertificatePathVCGetCount(path);
3461 for (ix = 1; ix < count; ix++) {
3462 SecPVCGrayListedKeyChecks(pvc, ix);
3463 SecPVCBlackListedKeyChecks(pvc, ix);
3464 }
3465
3466 /* Path-based check tests. */
3467 if (!SecCertificatePathVCIsPathValidated(path)) {
3468 bool ev_check_ok = false;
3469 if (SecCertificatePathVCIsOptionallyEV(path)) {
3470 SecTrustResultType pre_ev_check_result = pvc->result;
3471 SecPolicyCheckEV(pvc, kSecPolicyCheckExtendedValidation);
3472 ev_check_ok = SecPVCIsOkResult(pvc);
3473 /* If ev checking failed, we still want to accept this chain
3474 as a non EV one, if it was valid as such. */
3475 pvc->result = pre_ev_check_result;
3476 }
3477
3478 /* Check for CT */
3479 /* This call will set the value of pvc->is_ct, but won't change the result (pvc->result) */
3480 SecPolicyCheckCT(pvc);
3481
3482 /* Certs are only EV if they are also CT verified (when the Kill Switch isn't enabled and against a recent log list) */
3483 SecOTAPKIRef otaref = SecOTAPKICopyCurrentOTAPKIRef();
3484 if (ev_check_ok && (SecCertificatePathVCIsCT(path) || SecOTAPKIKillSwitchEnabled(otaref, kOTAPKIKillSwitchCT) ||
3485 !SecOTAPKIAssetStalenessLessThanSeconds(otaref, kSecOTAPKIAssetStalenessDisable))) {
3486 SecCertificatePathVCSetIsEV(path, true);
3487 }
3488 CFReleaseNull(otaref);
3489 }
3490
3491 /* Say that we did the expensive path checks (that we want to skip on the second call) */
3492 SecCertificatePathVCSetPathValidated(SecPathBuilderGetPath(pvc->builder));
3493
3494 /* Check that this path meets CT constraints. */
3495 SecPVCCheckRequireCTConstraints(pvc);
3496 SecPolicyCheckSystemTrustedCTRequired(pvc);
3497
3498 /* Check that this path meets known-intermediate constraints. */
3499 SecPathBuilderCheckKnownIntermediateConstraints(pvc->builder);
3500
3501 secdebug("policy", "end %strusted path: %@",
3502 (SecPVCIsOkResult(pvc) ? "" : "not "), SecPathBuilderGetPath(pvc->builder));
3503
3504 return;
3505 }
3506
3507 void SecPVCPathCheckRevocationResponsesReceived(SecPVCRef pvc) {
3508 #if TARGET_OS_WATCH
3509 /* Since we don't currently allow networking on watchOS,
3510 * don't enforce the revocation-required check here. (32728029) */
3511 bool required = false;
3512 #else
3513 bool required = true;
3514 #endif
3515 SecCertificatePathVCRef path = SecPathBuilderGetPath(pvc->builder);
3516 CFIndex ix, certCount = SecCertificatePathVCGetCount(path);
3517 for (ix = 0; ix < certCount; ix++) {
3518 SecRVCRef rvc = SecCertificatePathVCGetRVCAtIndex(path, ix);
3519 /* Do we have a valid revocation response? */
3520 if (SecRVCGetEarliestNextUpdate(rvc) == NULL_TIME) {
3521 /* No valid revocation response.
3522 * Do we require revocation (for that cert per the
3523 * SecCertificateVCRef, or per the pvc)? */
3524 if (required && (SecCertificatePathVCIsRevocationRequiredForCertificateAtIndex(path, ix) ||
3525 ((ix == 0) && pvc->require_revocation_response))) {
3526 SecPVCSetResultForced(pvc, kSecPolicyCheckRevocationResponseRequired,
3527 ix, kCFBooleanFalse, true);
3528 }
3529 /* Do we have a definitive Valid revocation result for this cert? */
3530 if (SecRVCHasDefinitiveValidInfo(rvc) && SecRVCHasRevokedValidInfo(rvc)) {
3531 SecRVCSetValidDeterminedErrorResult(rvc);
3532 }
3533 }
3534 }
3535 }