]> git.saurik.com Git - apple/security.git/blob - OSX/sec/securityd/SecPolicyServer.c
b53cd556f59b5f54c0a48ba29307c9181888c9b9
[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. Not a pinning policy */
2304 SecPolicyRef policy = SecPVCGetPolicy(pvc);
2305 require_quiet(CFEqualSafe(SecPolicyGetName(policy),kSecPolicyNameSSLServer), out);
2306
2307 /* 1. Device has checked in to MobileAsset for a current log list within the last 60 days.
2308 * Or the caller passed in the trusted log list. */
2309 require_quiet(SecOTAPKIAssetStalenessLessThanSeconds(otaref, kSecOTAPKIAssetStalenessDisable) || trustedLogs, out);
2310
2311 /* 2. Leaf issuance date is on or after 16 Oct 2018 at 00:00:00 AM UTC and not expired. */
2312 SecCertificateRef leaf = SecPVCGetCertificateAtIndex(pvc, 0);
2313 require_quiet(SecCertificateNotValidBefore(leaf) >= 561340800.0 &&
2314 SecCertificateIsValid(leaf, SecPVCGetVerifyTime(pvc)), out);
2315
2316 /* 3. Chain is anchored with root in the system anchor source but not the Apple anchor source */
2317 CFIndex count = SecPVCGetCertificateCount(pvc);
2318 SecCertificateRef root = SecPVCGetCertificateAtIndex(pvc, count - 1);
2319 appleAnchorSource = SecMemoryCertificateSourceCreate(SecGetAppleTrustAnchors(false));
2320 require_quiet(SecPathBuilderIsAnchored(pvc->builder), out);
2321 require_quiet((SecCertificateSourceContains(kSecSystemAnchorSource, root) &&
2322 appleAnchorSource && !SecCertificateSourceContains(appleAnchorSource, root) &&
2323 !is_apple_ca(path)) ||
2324 is_configured_test_system_root(root), out);
2325
2326 if (!SecCertificatePathVCIsCT(path) && !is_ct_excepted(pvc)) {
2327 /* Set failure. By not using the Forced variant, we implicitly check that this
2328 * policy had this options set. */
2329 SecPVCSetResult(pvc, kSecPolicyCheckSystemTrustedCTRequired, 0, kCFBooleanFalse);
2330 }
2331
2332 out:
2333 CFReleaseNull(trustedLogs);
2334 CFReleaseNull(otaref);
2335 if (appleAnchorSource) {
2336 SecMemoryCertificateSourceDestroy(appleAnchorSource);
2337 }
2338 }
2339
2340 void SecPolicyServerInitialize(void) {
2341 gSecPolicyLeafCallbacks = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
2342 &kCFTypeDictionaryKeyCallBacks, NULL);
2343 gSecPolicyPathCallbacks = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
2344 &kCFTypeDictionaryKeyCallBacks, NULL);
2345
2346 #undef POLICYCHECKMACRO
2347 #define __PC_ADD_CHECK_(NAME)
2348 #define __PC_ADD_CHECK_L(NAME) CFDictionaryAddValue(gSecPolicyLeafCallbacks, kSecPolicyCheck##NAME, SecPolicyCheck##NAME);
2349 #define __PC_ADD_CHECK_A(NAME) CFDictionaryAddValue(gSecPolicyPathCallbacks, kSecPolicyCheck##NAME, SecPolicyCheck##NAME);
2350
2351 #define POLICYCHECKMACRO(NAME, TRUSTRESULT, SUBTYPE, LEAFCHECK, PATHCHECK, LEAFONLY, CSSMERR, OSSTATUS) \
2352 __PC_ADD_CHECK_##LEAFCHECK(NAME) \
2353 __PC_ADD_CHECK_##PATHCHECK(NAME)
2354 #include "../Security/SecPolicyChecks.list"
2355
2356 /* Some of these don't follow the naming conventions but are in the Pinning DB.
2357 * <rdar://34537018> fix policy check constant values */
2358 CFDictionaryAddValue(gSecPolicyLeafCallbacks, CFSTR("CheckLeafMarkerOid"), SecPolicyCheckLeafMarkerOid);
2359 CFDictionaryAddValue(gSecPolicyLeafCallbacks, CFSTR("CheckLeafMarkersProdAndQA"), SecPolicyCheckLeafMarkersProdAndQA);
2360 CFDictionaryAddValue(gSecPolicyPathCallbacks, CFSTR("CheckIntermediateMarkerOid"), SecPolicyCheckIntermediateMarkerOid);
2361 CFDictionaryAddValue(gSecPolicyPathCallbacks, CFSTR("CheckIntermediateCountry"), SecPolicyCheckIntermediateCountry);
2362 CFDictionaryAddValue(gSecPolicyPathCallbacks, CFSTR("CheckIntermediateOrganization"), SecPolicyCheckIntermediateOrganization);
2363 }
2364
2365 // MARK: -
2366 // MARK: SecPVCRef
2367 /********************************************************
2368 ****************** SecPVCRef Functions *****************
2369 ********************************************************/
2370
2371 void SecPVCInit(SecPVCRef pvc, SecPathBuilderRef builder, CFArrayRef policies) {
2372 secdebug("alloc", "pvc %p", pvc);
2373 // Weird logging policies crashes.
2374 //secdebug("policy", "%@", policies);
2375
2376 // Zero the pvc struct so only non-zero fields need to be explicitly set
2377 memset(pvc, 0, sizeof(struct OpaqueSecPVC));
2378 pvc->builder = builder;
2379 pvc->policies = policies;
2380 if (policies)
2381 CFRetain(policies);
2382 pvc->result = kSecTrustResultUnspecified;
2383
2384 CFMutableDictionaryRef certDetail = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
2385 &kCFTypeDictionaryKeyCallBacks,
2386 &kCFTypeDictionaryValueCallBacks);
2387 pvc->leafDetails = CFArrayCreate(kCFAllocatorDefault, (const void **)&certDetail,
2388 1, &kCFTypeArrayCallBacks);
2389 CFRelease(certDetail);
2390 }
2391
2392 void SecPVCDelete(SecPVCRef pvc) {
2393 secdebug("alloc", "delete pvc %p", pvc);
2394 CFReleaseNull(pvc->policies);
2395 CFReleaseNull(pvc->details);
2396 CFReleaseNull(pvc->leafDetails);
2397 }
2398
2399 void SecPVCSetPath(SecPVCRef pvc, SecCertificatePathVCRef path) {
2400 secdebug("policy", "%@", path);
2401 pvc->policyIX = 0;
2402 pvc->result = kSecTrustResultUnspecified;
2403 CFReleaseNull(pvc->details);
2404 }
2405
2406 void SecPVCComputeDetails(SecPVCRef pvc, SecCertificatePathVCRef path) {
2407 pvc->policyIX = 0;
2408
2409 /* Since we don't run the LeafChecks again, we need to preserve the
2410 * result the leaf had. */
2411 CFIndex ix, pathLength = SecCertificatePathVCGetCount(path);
2412 CFMutableArrayRef details = CFArrayCreateMutableCopy(kCFAllocatorDefault,
2413 pathLength, pvc->leafDetails);
2414 for (ix = 1; ix < pathLength; ++ix) {
2415 CFMutableDictionaryRef certDetail = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
2416 &kCFTypeDictionaryKeyCallBacks,
2417 &kCFTypeDictionaryValueCallBacks);
2418 CFArrayAppendValue(details, certDetail);
2419 CFRelease(certDetail);
2420 }
2421 CFRetainAssign(pvc->details, details);
2422 pvc->result = pvc->leafResult;
2423 CFReleaseSafe(details);
2424 }
2425
2426 SecPolicyRef SecPVCGetPolicy(SecPVCRef pvc) {
2427 return (SecPolicyRef)CFArrayGetValueAtIndex(pvc->policies, pvc->policyIX);
2428 }
2429
2430 static CFIndex SecPVCGetCertificateCount(SecPVCRef pvc) {
2431 return SecPathBuilderGetCertificateCount(pvc->builder);
2432 }
2433
2434 static SecCertificateRef SecPVCGetCertificateAtIndex(SecPVCRef pvc, CFIndex ix) {
2435 return SecPathBuilderGetCertificateAtIndex(pvc->builder, ix);
2436 }
2437
2438 static CFAbsoluteTime SecPVCGetVerifyTime(SecPVCRef pvc) {
2439 return SecPathBuilderGetVerifyTime(pvc->builder);
2440 }
2441
2442 static bool SecPVCIsExceptedError(SecPVCRef pvc, CFIndex ix, CFStringRef key, CFTypeRef value) {
2443 CFArrayRef exceptions = SecPathBuilderGetExceptions(pvc->builder);
2444 if (!exceptions) { return false; }
2445 CFIndex exceptionsCount = CFArrayGetCount(exceptions);
2446
2447 /* There are two types of exceptions:
2448 * 1. Those that are built from SecTrustCopyExceptions, which are particular to the
2449 * certs in the chain -- as indicated by the SHA1 digest in the exception dictionary.
2450 * 2. On macOS, those built from SecTrustSetOptions, which are generic excepted errors.
2451 */
2452 #if TARGET_OS_OSX
2453 CFDictionaryRef options = CFArrayGetValueAtIndex(exceptions, 0);
2454 /* Type 2 */
2455 if (exceptionsCount == 1 && (ix > 0 || !CFDictionaryContainsKey(options, kSecCertificateDetailSHA1Digest))) {
2456 /* SHA1Digest not allowed */
2457 if (CFDictionaryContainsKey(options, kSecCertificateDetailSHA1Digest)) { return false; }
2458 /* Key excepted */
2459 if (CFDictionaryContainsKey(options, key)) {
2460 /* Special case -- AnchorTrusted only for self-signed certs */
2461 if (CFEqual(kSecPolicyCheckAnchorTrusted, key)) {
2462 Boolean isSelfSigned = false;
2463 SecCertificateRef cert = SecPathBuilderGetCertificateAtIndex(pvc->builder, ix);
2464 if (!cert || (errSecSuccess != SecCertificateIsSelfSigned(cert, &isSelfSigned)) || !isSelfSigned) {
2465 return false;
2466 }
2467 }
2468 return true;
2469 } else if (CFEqual(key, kSecPolicyCheckTemporalValidity) && CFDictionaryContainsKey(options, kSecPolicyCheckValidRoot)) {
2470 /* Another special case - ValidRoot excepts Valid only for self-signed certs */
2471 Boolean isSelfSigned = false;
2472 SecCertificateRef cert = SecPathBuilderGetCertificateAtIndex(pvc->builder, ix);
2473 if (!cert || (errSecSuccess != SecCertificateIsSelfSigned(cert, &isSelfSigned)) || !isSelfSigned) {
2474 return false;
2475 }
2476 return true;
2477 }
2478 }
2479 #endif
2480
2481 /* Type 1 */
2482 if (ix >= exceptionsCount) { return false; }
2483 CFDictionaryRef exception = CFArrayGetValueAtIndex(exceptions, ix);
2484
2485 /* Compare the cert hash */
2486 if (!CFDictionaryContainsKey(exception, kSecCertificateDetailSHA1Digest)) { return false; }
2487 SecCertificateRef cert = SecPathBuilderGetCertificateAtIndex(pvc->builder, ix);
2488 if (!CFEqual(SecCertificateGetSHA1Digest(cert), CFDictionaryGetValue(exception, kSecCertificateDetailSHA1Digest))) {
2489 return false;
2490 }
2491
2492 /* Key Excepted */
2493 CFTypeRef exceptionValue = CFDictionaryGetValue(exception, key);
2494 if (exceptionValue && CFEqual(value, exceptionValue)) {
2495 /* Only change result if PVC is already ok */
2496 if (SecPVCIsOkResult(pvc)) {
2497 // Chains that pass due to exceptions get Proceed result.
2498 pvc->result = kSecTrustResultProceed;
2499 }
2500 return true;
2501 }
2502
2503 return false;
2504 }
2505
2506 static int32_t detailKeyToCssmErr(CFStringRef key) {
2507 int32_t result = 0;
2508
2509 if (CFEqual(key, kSecPolicyCheckSSLHostname)) {
2510 result = -2147408896; // CSSMERR_APPLETP_HOSTNAME_MISMATCH
2511 }
2512 else if (CFEqual(key, kSecPolicyCheckEmail)) {
2513 result = -2147408872; // CSSMERR_APPLETP_SMIME_EMAIL_ADDRS_NOT_FOUND
2514 }
2515 else if (CFEqual(key, kSecPolicyCheckTemporalValidity)) {
2516 result = -2147409654; // CSSMERR_TP_CERT_EXPIRED
2517 }
2518
2519 return result;
2520 }
2521
2522 static bool SecPVCMeetsConstraint(SecPVCRef pvc, SecCertificateRef certificate, CFDictionaryRef constraint);
2523
2524 static bool SecPVCIsAllowedError(SecPVCRef pvc, CFIndex ix, CFStringRef key) {
2525 bool result = false;
2526 SecCertificatePathVCRef path = SecPathBuilderGetPath(pvc->builder);
2527 CFArrayRef constraints = SecCertificatePathVCGetUsageConstraintsAtIndex(path, ix);
2528 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix);
2529 CFIndex constraintIX, constraintCount = CFArrayGetCount(constraints);
2530
2531 for (constraintIX = 0; constraintIX < constraintCount; constraintIX++) {
2532 CFDictionaryRef constraint = (CFDictionaryRef)CFArrayGetValueAtIndex(constraints, constraintIX);
2533 CFNumberRef allowedErrorNumber = NULL;
2534 if (!isDictionary(constraint)) {
2535 continue;
2536 }
2537 allowedErrorNumber = (CFNumberRef)CFDictionaryGetValue(constraint, kSecTrustSettingsAllowedError);
2538 int32_t allowedErrorValue = 0;
2539 if (!isNumber(allowedErrorNumber) || !CFNumberGetValue(allowedErrorNumber, kCFNumberSInt32Type, &allowedErrorValue)) {
2540 continue;
2541 }
2542
2543 if (SecPVCMeetsConstraint(pvc, cert, constraint)) {
2544 if (allowedErrorValue == detailKeyToCssmErr(key)) {
2545 result = true;
2546 break;
2547 }
2548 }
2549 }
2550 return result;
2551 }
2552
2553 static bool SecPVCKeyIsConstraintPolicyOption(SecPVCRef pvc, CFStringRef key) {
2554 CFIndex certIX, certCount = SecPVCGetCertificateCount(pvc);
2555 for (certIX = 0; certIX < certCount; certIX++) {
2556 SecCertificatePathVCRef path = SecPathBuilderGetPath(pvc->builder);
2557 CFArrayRef constraints = SecCertificatePathVCGetUsageConstraintsAtIndex(path, certIX);
2558 CFIndex constraintIX, constraintCount = CFArrayGetCount(constraints);
2559 for (constraintIX = 0; constraintIX < constraintCount; constraintIX++) {
2560 CFDictionaryRef constraint = (CFDictionaryRef)CFArrayGetValueAtIndex(constraints, constraintIX);
2561 if (!isDictionary(constraint)) {
2562 continue;
2563 }
2564
2565 CFDictionaryRef policyOptions = NULL;
2566 policyOptions = (CFDictionaryRef)CFDictionaryGetValue(constraint, kSecTrustSettingsPolicyOptions);
2567 if (policyOptions && isDictionary(policyOptions) &&
2568 CFDictionaryContainsKey(policyOptions, key)) {
2569 return true;
2570 }
2571 }
2572 }
2573 return false;
2574 }
2575
2576 static SecTrustResultType trust_result_for_key(CFStringRef key) {
2577 SecTrustResultType result = kSecTrustResultRecoverableTrustFailure;
2578 #undef POLICYCHECKMACRO
2579 #define __PC_TYPE_MEMBER_ false
2580 #define __PC_TYPE_MEMBER_R false
2581 #define __PC_TYPE_MEMBER_F true
2582 #define __PC_TYPE_MEMBER_D true
2583
2584 #define __TRUSTRESULT_ kSecTrustResultRecoverableTrustFailure
2585 #define __TRUSTRESULT_F kSecTrustResultFatalTrustFailure
2586 #define __TRUSTRESULT_D kSecTrustResultDeny
2587 #define __TRUSTRESULT_R kSecTrustResultRecoverableTrustFailure
2588
2589 #define POLICYCHECKMACRO(NAME, TRUSTRESULT, SUBTYPE, LEAFCHECK, PATHCHECK, LEAFONLY, CSSMERR, OSSTATUS) \
2590 if (__PC_TYPE_MEMBER_##TRUSTRESULT && CFEqual(key,CFSTR(#NAME))) { \
2591 result = __TRUSTRESULT_##TRUSTRESULT; \
2592 }
2593 #include "../Security/SecPolicyChecks.list"
2594 return result;
2595 }
2596
2597
2598 /* AUDIT[securityd](done):
2599 policy->_options is a caller provided dictionary, only its cf type has
2600 been checked.
2601 */
2602 bool SecPVCSetResultForced(SecPVCRef pvc,
2603 CFStringRef key, CFIndex ix, CFTypeRef result, bool force) {
2604
2605 secnotice("policy", "cert[%d]: %@ =(%s)[%s]> %@", (int) ix, key,
2606 (pvc->callbacks == gSecPolicyLeafCallbacks ? "leaf"
2607 : (pvc->callbacks == gSecPolicyPathCallbacks ? "path"
2608 : "custom")),
2609 (force ? "force" : ""), result);
2610
2611 /* If this is not something the current policy cares about ignore
2612 this error and return true so our caller continues evaluation. */
2613 if (!force) {
2614 /* Either the policy or the usage constraints have to have this key */
2615 SecPolicyRef policy = SecPVCGetPolicy(pvc);
2616 if (!(SecPVCKeyIsConstraintPolicyOption(pvc, key) ||
2617 (policy && CFDictionaryContainsKey(policy->_options, key)))) {
2618 return true;
2619 }
2620 }
2621
2622 /* Check to see if the SecTrustSettings for the certificate in question
2623 tell us to ignore this error. */
2624 if (SecPVCIsAllowedError(pvc, ix, key)) {
2625 secinfo("policy", "cert[%d]: skipped allowed error %@", (int) ix, key);
2626 return true;
2627 }
2628
2629 /* Check to see if exceptions tells us to ignore this error. */
2630 if (SecPVCIsExceptedError(pvc, ix, key, result)) {
2631 secinfo("policy", "cert[%d]: skipped exception error %@", (int) ix, key);
2632 return true;
2633 }
2634
2635 /* Avoid resetting deny or fatal to recoverable */
2636 SecTrustResultType trustResult = trust_result_for_key(key);
2637 if (SecPVCIsOkResult(pvc) || trustResult == kSecTrustResultFatalTrustFailure) {
2638 pvc->result = trustResult;
2639 } else if (trustResult == kSecTrustResultDeny &&
2640 pvc->result == kSecTrustResultRecoverableTrustFailure) {
2641 pvc->result = trustResult;
2642 }
2643
2644 if (!pvc->details)
2645 return false;
2646
2647 CFMutableDictionaryRef detail =
2648 (CFMutableDictionaryRef)CFArrayGetValueAtIndex(pvc->details, ix);
2649
2650 /* Perhaps detail should have an array of results per key? As it stands
2651 in the case of multiple policy failures the last failure stands. */
2652 CFDictionarySetValue(detail, key, result);
2653
2654 return true;
2655 }
2656
2657 bool SecPVCSetResult(SecPVCRef pvc,
2658 CFStringRef key, CFIndex ix, CFTypeRef result) {
2659 return SecPVCSetResultForced(pvc, key, ix, result, false);
2660 }
2661
2662 /* AUDIT[securityd](done):
2663 key(ok) is a caller provided.
2664 value(ok, unused) is a caller provided.
2665 */
2666 static void SecPVCValidateKey(const void *key, const void *value,
2667 void *context) {
2668 SecPVCRef pvc = (SecPVCRef)context;
2669
2670 /* If our caller doesn't want full details and we failed earlier there is
2671 no point in doing additional checks. */
2672 if (!SecPVCIsOkResult(pvc) && !pvc->details)
2673 return;
2674
2675 SecPolicyCheckFunction fcn = (SecPolicyCheckFunction)
2676 CFDictionaryGetValue(pvc->callbacks, key);
2677
2678 if (!fcn) {
2679 /* "Optional" policy checks. This may be a new key from the
2680 * pinning DB which is not implemented in this OS version. Log a
2681 * warning, and on debug builds fail evaluation, to encourage us
2682 * to ensure that checks are synchronized across the same build. */
2683 if (pvc->callbacks == gSecPolicyLeafCallbacks) {
2684 if (!CFDictionaryContainsKey(gSecPolicyPathCallbacks, key)) {
2685 secwarning("policy: unknown policy key %@, skipping", key);
2686 #if DEBUG
2687 pvc->result = kSecTrustResultOtherError;
2688 #endif
2689 }
2690 } else if (pvc->callbacks == gSecPolicyPathCallbacks) {
2691 if (!CFDictionaryContainsKey(gSecPolicyLeafCallbacks, key)) {
2692 secwarning("policy: unknown policy key %@, skipping", key);
2693 #if DEBUG
2694 pvc->result = kSecTrustResultOtherError;
2695 #endif
2696 }
2697 } else {
2698 /* Non standard validation phase, nothing is optional. */
2699 pvc->result = kSecTrustResultOtherError;
2700 }
2701 return;
2702 }
2703
2704 fcn(pvc, (CFStringRef)key);
2705 }
2706
2707 /* AUDIT[securityd](done):
2708 policy->_options is a caller provided dictionary, only its cf type has
2709 been checked.
2710 */
2711 SecTrustResultType SecPVCLeafChecks(SecPVCRef pvc) {
2712 /* We need to compute details for the leaf. */
2713 CFRetainAssign(pvc->details, pvc->leafDetails);
2714
2715 CFArrayRef policies = pvc->policies;
2716 CFIndex ix, count = CFArrayGetCount(policies);
2717 for (ix = 0; ix < count; ++ix) {
2718 SecPolicyRef policy = (SecPolicyRef)CFArrayGetValueAtIndex(policies, ix);
2719 pvc->policyIX = ix;
2720 /* Validate all keys for all policies. */
2721 pvc->callbacks = gSecPolicyLeafCallbacks;
2722 CFDictionaryApplyFunction(policy->_options, SecPVCValidateKey, pvc);
2723 }
2724
2725 pvc->leafResult = pvc->result;
2726 CFRetainAssign(pvc->leafDetails, pvc->details);
2727
2728 return pvc->result;
2729 }
2730
2731 bool SecPVCIsOkResult(SecPVCRef pvc) {
2732 if (pvc->result == kSecTrustResultRecoverableTrustFailure ||
2733 pvc->result == kSecTrustResultDeny ||
2734 pvc->result == kSecTrustResultFatalTrustFailure ||
2735 pvc->result == kSecTrustResultOtherError) {
2736 return false;
2737 }
2738 return true;
2739 }
2740
2741 bool SecPVCParentCertificateChecks(SecPVCRef pvc, CFIndex ix) {
2742 /* Check stuff common to intermediate and anchors. */
2743 CFAbsoluteTime verifyTime = SecPVCGetVerifyTime(pvc);
2744 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix);
2745 CFIndex anchor_ix = SecPVCGetCertificateCount(pvc) - 1;
2746 bool is_anchor = (ix == anchor_ix && SecPathBuilderIsAnchored(pvc->builder));
2747
2748 if (!SecCertificateIsValid(cert, verifyTime)) {
2749 /* Certificate has expired. */
2750 if (!SecPVCSetResult(pvc, kSecPolicyCheckTemporalValidity, ix, kCFBooleanFalse)) {
2751 goto errOut;
2752 }
2753 }
2754
2755 if (SecCertificateIsWeakKey(cert)) {
2756 /* Certificate uses weak key. */
2757 if (!SecPVCSetResult(pvc, kSecPolicyCheckWeakKeySize, ix, kCFBooleanFalse)) {
2758 goto errOut;
2759 }
2760 }
2761
2762 if (!SecPolicyCheckCertWeakSignature(cert, NULL)) {
2763 /* Certificate uses weak hash. */
2764 if (!SecPVCSetResult(pvc, kSecPolicyCheckWeakSignature, ix, kCFBooleanFalse)) {
2765 goto errOut;
2766 }
2767 }
2768
2769 if (is_anchor) {
2770 /* Perform anchor specific checks. */
2771 /* Don't think we have any of these. */
2772 } else {
2773 /* Perform intermediate specific checks. */
2774
2775 /* (k) Basic constraints only relevant for v3 and later. */
2776 if (SecCertificateVersion(cert) >= 3) {
2777 const SecCEBasicConstraints *bc =
2778 SecCertificateGetBasicConstraints(cert);
2779 if (!bc) {
2780 /* Basic constraints not present, illegal. */
2781 if (!SecPVCSetResultForced(pvc, kSecPolicyCheckBasicConstraints,
2782 ix, kCFBooleanFalse, true)) {
2783 goto errOut;
2784 }
2785 } else if (!bc->isCA) {
2786 /* Basic constraints not marked as isCA, illegal. */
2787 if (!SecPVCSetResultForced(pvc, kSecPolicyCheckBasicConstraintsCA,
2788 ix, kCFBooleanFalse, true)) {
2789 goto errOut;
2790 }
2791 }
2792 }
2793 /* For a v1 or v2 certificate in an intermediate slot (not a leaf and
2794 not an anchor), we additionally require that the certificate chain
2795 does not end in a v3 or later anchor. [rdar://32204517] */
2796 else if (ix > 0 && ix < anchor_ix) {
2797 SecCertificateRef anchor = SecPVCGetCertificateAtIndex(pvc, anchor_ix);
2798 if (SecCertificateVersion(anchor) >= 3) {
2799 if (!SecPVCSetResultForced(pvc, kSecPolicyCheckBasicConstraints,
2800 ix, kCFBooleanFalse, true)) {
2801 goto errOut;
2802 }
2803 }
2804 }
2805 /* (l) max_path_length is checked elsewhere. */
2806
2807 /* (n) If a key usage extension is present, verify that the keyCertSign bit is set. */
2808 SecKeyUsage keyUsage = SecCertificateGetKeyUsage(cert);
2809 if (keyUsage && !(keyUsage & kSecKeyUsageKeyCertSign)) {
2810 if (!SecPVCSetResultForced(pvc, kSecPolicyCheckKeyUsage,
2811 ix, kCFBooleanFalse, true)) {
2812 goto errOut;
2813 }
2814 }
2815 }
2816
2817 errOut:
2818 return SecPVCIsOkResult(pvc);
2819 }
2820
2821 static bool SecPVCBlackListedKeyChecks(SecPVCRef pvc, CFIndex ix) {
2822 /* Check stuff common to intermediate and anchors. */
2823
2824 SecOTAPKIRef otapkiRef = SecOTAPKICopyCurrentOTAPKIRef();
2825 if (NULL != otapkiRef)
2826 {
2827 CFSetRef blackListedKeys = SecOTAPKICopyBlackListSet(otapkiRef);
2828 CFRelease(otapkiRef);
2829 if (NULL != blackListedKeys)
2830 {
2831 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix);
2832 CFIndex count = SecPVCGetCertificateCount(pvc);
2833 bool is_last = (ix == count - 1);
2834 bool is_anchor = (is_last && SecPathBuilderIsAnchored(pvc->builder));
2835 if (!is_anchor) {
2836 /* Check for blacklisted intermediate issuer keys. */
2837 CFDataRef dgst = SecCertificateCopyPublicKeySHA1Digest(cert);
2838 if (dgst) {
2839 /* Check dgst against blacklist. */
2840 if (CFSetContainsValue(blackListedKeys, dgst)) {
2841 /* Check allow list for this blacklisted issuer key,
2842 which is the authority key of the issued cert at ix-1.
2843 */
2844 SecCertificatePathVCRef path = SecPathBuilderGetPath(pvc->builder);
2845 bool allowed = path && SecCertificatePathVCIsAllowlisted(path);
2846 if (!allowed) {
2847 SecPVCSetResultForced(pvc, kSecPolicyCheckBlackListedKey,
2848 ix, kCFBooleanFalse, true);
2849 }
2850 }
2851 CFRelease(dgst);
2852 }
2853 }
2854 CFRelease(blackListedKeys);
2855 return SecPVCIsOkResult(pvc);
2856 }
2857 }
2858 // Assume OK
2859 return true;
2860 }
2861
2862 static bool SecPVCGrayListedKeyChecks(SecPVCRef pvc, CFIndex ix)
2863 {
2864 /* Check stuff common to intermediate and anchors. */
2865 SecOTAPKIRef otapkiRef = SecOTAPKICopyCurrentOTAPKIRef();
2866 if (NULL != otapkiRef)
2867 {
2868 CFSetRef grayListKeys = SecOTAPKICopyGrayList(otapkiRef);
2869 CFRelease(otapkiRef);
2870 if (NULL != grayListKeys)
2871 {
2872 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix);
2873 CFIndex count = SecPVCGetCertificateCount(pvc);
2874 bool is_last = (ix == count - 1);
2875 bool is_anchor = (is_last && SecPathBuilderIsAnchored(pvc->builder));
2876 if (!is_anchor) {
2877 /* Check for gray listed intermediate issuer keys. */
2878 CFDataRef dgst = SecCertificateCopyPublicKeySHA1Digest(cert);
2879 if (dgst) {
2880 /* Check dgst against gray list. */
2881 if (CFSetContainsValue(grayListKeys, dgst)) {
2882 /* Check allow list for this graylisted issuer key,
2883 which is the authority key of the issued cert at ix-1.
2884 */
2885 SecCertificatePathVCRef path = SecPathBuilderGetPath(pvc->builder);
2886 bool allowed = path && SecCertificatePathVCIsAllowlisted(path);
2887 if (!allowed) {
2888 SecPVCSetResultForced(pvc, kSecPolicyCheckGrayListedKey,
2889 ix, kCFBooleanFalse, true);
2890 }
2891 }
2892 CFRelease(dgst);
2893 }
2894 }
2895 CFRelease(grayListKeys);
2896 return SecPVCIsOkResult(pvc);
2897 }
2898 }
2899 // Assume ok
2900 return true;
2901 }
2902
2903 static bool SecPVCContainsPolicy(SecPVCRef pvc, CFStringRef searchOid, CFStringRef searchName, CFIndex *policyIX) {
2904 if (!isString(searchName) && !isString(searchOid)) {
2905 return false;
2906 }
2907 CFArrayRef policies = pvc->policies;
2908 CFIndex ix, count = CFArrayGetCount(policies);
2909 for (ix = 0; ix < count; ++ix) {
2910 SecPolicyRef policy = (SecPolicyRef)CFArrayGetValueAtIndex(policies, ix);
2911 CFStringRef policyName = SecPolicyGetName(policy);
2912 CFStringRef policyOid = SecPolicyGetOidString(policy);
2913 /* Prefer a match of both name and OID */
2914 if (searchOid && searchName && policyOid && policyName) {
2915 if (CFEqual(searchOid, policyOid) &&
2916 CFEqual(searchName, policyName)) {
2917 if (policyIX) { *policyIX = ix; }
2918 return true;
2919 }
2920 /* <rdar://40617139> sslServer trust settings need to apply to evals using policyName pinning
2921 * but make sure we don't use this for SSL Client trust settings or policies. */
2922 if (CFEqual(searchOid, policyOid) &&
2923 CFEqual(searchName, kSecPolicyNameSSLServer) && !CFEqual(policyName, kSecPolicyNameSSLClient)) {
2924 if (policyIX) { *policyIX = ix; }
2925 return true;
2926 }
2927 }
2928 /* Next best is just OID. */
2929 if (!searchName && searchOid && policyOid) {
2930 if (CFEqual(searchOid, policyOid)) {
2931 if (policyIX) { *policyIX = ix; }
2932 return true;
2933 }
2934 }
2935 if (!searchOid && searchName && policyName) {
2936 if (CFEqual(searchName, policyName)) {
2937 if (policyIX) { *policyIX = ix; }
2938 return true;
2939 }
2940 }
2941 }
2942 return false;
2943 }
2944
2945 static bool SecPVCContainsString(SecPVCRef pvc, CFIndex policyIX, CFStringRef stringValue) {
2946 if (!isString(stringValue)) {
2947 return false;
2948 }
2949 bool result = false;
2950
2951 CFStringRef tmpStringValue = NULL;
2952 if (CFStringGetCharacterAtIndex(stringValue, CFStringGetLength(stringValue) -1) == (UniChar)0x0000) {
2953 tmpStringValue = CFStringCreateTruncatedCopy(stringValue, CFStringGetLength(stringValue) - 1);
2954 } else {
2955 tmpStringValue = CFStringCreateCopy(NULL, stringValue);
2956 }
2957 if (policyIX >= 0 && policyIX < CFArrayGetCount(pvc->policies)) {
2958 SecPolicyRef policy = (SecPolicyRef)CFArrayGetValueAtIndex(pvc->policies, policyIX);
2959 /* Have to look for all the possible locations of name string */
2960 CFStringRef policyString = NULL;
2961 policyString = CFDictionaryGetValue(policy->_options, kSecPolicyCheckSSLHostname);
2962 if (!policyString) {
2963 policyString = CFDictionaryGetValue(policy->_options, kSecPolicyCheckEmail);
2964 }
2965 if (policyString && (CFStringCompare(tmpStringValue, policyString, kCFCompareCaseInsensitive) == kCFCompareEqualTo)) {
2966 result = true;
2967 goto out;
2968 }
2969
2970 CFArrayRef policyStrings = NULL;
2971 policyStrings = CFDictionaryGetValue(policy->_options, kSecPolicyCheckEAPTrustedServerNames);
2972 if (policyStrings && CFArrayContainsValue(policyStrings,
2973 CFRangeMake(0, CFArrayGetCount(policyStrings)),
2974 tmpStringValue)) {
2975 result = true;
2976 goto out;
2977 }
2978 }
2979
2980 out:
2981 CFReleaseNull(tmpStringValue);
2982 return result;
2983 }
2984
2985
2986 static uint32_t ts_key_usage_for_kuNumber(CFNumberRef keyUsageNumber) {
2987 uint32_t ourTSKeyUsage = 0;
2988 uint32_t keyUsage = 0;
2989 if (keyUsageNumber &&
2990 CFNumberGetValue(keyUsageNumber, kCFNumberSInt32Type, &keyUsage)) {
2991 if (keyUsage & kSecKeyUsageDigitalSignature) {
2992 ourTSKeyUsage |= kSecTrustSettingsKeyUseSignature;
2993 }
2994 if (keyUsage & kSecKeyUsageDataEncipherment) {
2995 ourTSKeyUsage |= kSecTrustSettingsKeyUseEnDecryptData;
2996 }
2997 if (keyUsage & kSecKeyUsageKeyEncipherment) {
2998 ourTSKeyUsage |= kSecTrustSettingsKeyUseEnDecryptKey;
2999 }
3000 if (keyUsage & kSecKeyUsageKeyAgreement) {
3001 ourTSKeyUsage |= kSecTrustSettingsKeyUseKeyExchange;
3002 }
3003 if (keyUsage == kSecKeyUsageAll) {
3004 ourTSKeyUsage = kSecTrustSettingsKeyUseAny;
3005 }
3006 }
3007 return ourTSKeyUsage;
3008 }
3009
3010 static uint32_t ts_key_usage_for_policy(SecPolicyRef policy) {
3011 uint32_t ourTSKeyUsage = 0;
3012 CFTypeRef policyKeyUsageType = NULL;
3013
3014 policyKeyUsageType = (CFTypeRef)CFDictionaryGetValue(policy->_options, kSecPolicyCheckKeyUsage);
3015 if (isArray(policyKeyUsageType)) {
3016 CFIndex ix, count = CFArrayGetCount(policyKeyUsageType);
3017 for (ix = 0; ix < count; ix++) {
3018 CFNumberRef policyKeyUsageNumber = NULL;
3019 policyKeyUsageNumber = (CFNumberRef)CFArrayGetValueAtIndex(policyKeyUsageType, ix);
3020 ourTSKeyUsage |= ts_key_usage_for_kuNumber(policyKeyUsageNumber);
3021 }
3022 } else if (isNumber(policyKeyUsageType)) {
3023 ourTSKeyUsage |= ts_key_usage_for_kuNumber(policyKeyUsageType);
3024 }
3025
3026 return ourTSKeyUsage;
3027 }
3028
3029 static bool SecPVCContainsTrustSettingsKeyUsage(SecPVCRef pvc,
3030 SecCertificateRef certificate, CFIndex policyIX, CFNumberRef keyUsageNumber) {
3031 int64_t keyUsageValue = 0;
3032 uint32_t ourKeyUsage = 0;
3033
3034 if (!isNumber(keyUsageNumber) || !CFNumberGetValue(keyUsageNumber, kCFNumberSInt64Type, &keyUsageValue)) {
3035 return false;
3036 }
3037
3038 if (keyUsageValue == kSecTrustSettingsKeyUseAny) {
3039 return true;
3040 }
3041
3042 /* We're using the key for revocation if we have the OCSPSigner policy.
3043 * @@@ If we support CRLs, we'd need to check for that policy here too.
3044 */
3045 if (SecPVCContainsPolicy(pvc, kSecPolicyAppleOCSPSigner, NULL, NULL)) {
3046 ourKeyUsage |= kSecTrustSettingsKeyUseSignRevocation;
3047 }
3048
3049 /* We're using the key for verifying a cert if it's a root/intermediate
3050 * in the chain. If the cert isn't in the path yet, we're about to add it,
3051 * so it's a root/intermediate. If there is no path, this is the leaf.
3052 */
3053 CFIndex pathIndex = -1;
3054 SecCertificatePathVCRef path = SecPathBuilderGetPath(pvc->builder);
3055 if (path) {
3056 pathIndex = SecCertificatePathVCGetIndexOfCertificate(path, certificate);
3057 } else {
3058 pathIndex = 0;
3059 }
3060 if (pathIndex != 0) {
3061 ourKeyUsage |= kSecTrustSettingsKeyUseSignCert;
3062 }
3063
3064 /* The rest of the key usages may be specified by the policy(ies). */
3065 if (policyIX >= 0 && policyIX < CFArrayGetCount(pvc->policies)) {
3066 SecPolicyRef policy = (SecPolicyRef)CFArrayGetValueAtIndex(pvc->policies, policyIX);
3067 ourKeyUsage |= ts_key_usage_for_policy(policy);
3068 } else {
3069 /* Get key usage from ALL policies */
3070 CFIndex ix, count = CFArrayGetCount(pvc->policies);
3071 for (ix = 0; ix < count; ix++) {
3072 SecPolicyRef policy = (SecPolicyRef)CFArrayGetValueAtIndex(pvc->policies, ix);
3073 ourKeyUsage |= ts_key_usage_for_policy(policy);
3074 }
3075 }
3076
3077 if (ourKeyUsage == (uint32_t)(keyUsageValue & 0x00ffffffff)) {
3078 return true;
3079 }
3080
3081 return false;
3082 }
3083
3084 #if TARGET_OS_OSX
3085 #include <Security/SecTrustedApplicationPriv.h>
3086 #include <Security/SecTask.h>
3087 #include <Security/SecTaskPriv.h>
3088 #include <bsm/libbsm.h>
3089 #include <libproc.h>
3090
3091 extern OSStatus SecTaskValidateForRequirement(SecTaskRef task, CFStringRef requirement);
3092
3093 static bool SecPVCCallerIsApplication(CFDataRef clientAuditToken, CFTypeRef appRef) {
3094 bool result = false;
3095 audit_token_t auditToken = {};
3096 SecTaskRef task = NULL;
3097 SecRequirementRef requirement = NULL;
3098 CFStringRef stringRequirement = NULL;
3099
3100 require(appRef && clientAuditToken, out);
3101 require(CFGetTypeID(appRef) == SecTrustedApplicationGetTypeID(), out);
3102 require_noerr(SecTrustedApplicationCopyRequirement((SecTrustedApplicationRef)appRef, &requirement), out);
3103 require(requirement, out);
3104 require_noerr(SecRequirementsCopyString(requirement, kSecCSDefaultFlags, &stringRequirement), out);
3105 require(stringRequirement, out);
3106
3107 require(sizeof(auditToken) == CFDataGetLength(clientAuditToken), out);
3108 CFDataGetBytes(clientAuditToken, CFRangeMake(0, sizeof(auditToken)), (uint8_t *)&auditToken);
3109 require(task = SecTaskCreateWithAuditToken(NULL, auditToken), out);
3110
3111 if(errSecSuccess == SecTaskValidateForRequirement(task, stringRequirement)) {
3112 result = true;
3113 }
3114
3115 out:
3116 CFReleaseNull(task);
3117 CFReleaseNull(requirement);
3118 CFReleaseNull(stringRequirement);
3119 return result;
3120 }
3121 #endif
3122
3123 static bool SecPVCContainsTrustSettingsPolicyOption(SecPVCRef pvc, CFDictionaryRef options) {
3124 if (!isDictionary(options)) {
3125 return false;
3126 }
3127
3128 /* Push */
3129 CFDictionaryRef currentCallbacks = pvc->callbacks;
3130
3131 /* We need to run the leaf and path checks using these options. */
3132 pvc->callbacks = gSecPolicyLeafCallbacks;
3133 CFDictionaryApplyFunction(options, SecPVCValidateKey, pvc);
3134
3135 pvc->callbacks = gSecPolicyPathCallbacks;
3136 CFDictionaryApplyFunction(options, SecPVCValidateKey, pvc);
3137
3138 /* Pop */
3139 pvc->callbacks = currentCallbacks;
3140
3141 /* Our work here is done; no need to claim a match */
3142 return false;
3143 }
3144
3145 static bool SecPVCMeetsConstraint(SecPVCRef pvc, SecCertificateRef certificate, CFDictionaryRef constraint) {
3146 CFStringRef policyOid = NULL, policyString = NULL, policyName = NULL;
3147 CFNumberRef keyUsageNumber = NULL;
3148 CFTypeRef trustedApplicationData = NULL;
3149 CFDictionaryRef policyOptions = NULL;
3150
3151 bool policyMatch = false, policyStringMatch = false, applicationMatch = false ,
3152 keyUsageMatch = false, policyOptionMatch = false;
3153 bool result = false;
3154
3155 #if TARGET_OS_MAC && !TARGET_OS_IPHONE
3156 /* OS X returns a SecPolicyRef in the constraints. Convert to the oid string. */
3157 SecPolicyRef policy = NULL;
3158 policy = (SecPolicyRef)CFDictionaryGetValue(constraint, kSecTrustSettingsPolicy);
3159 policyOid = (policy) ? policy->_oid : NULL;
3160 #else
3161 policyOid = (CFStringRef)CFDictionaryGetValue(constraint, kSecTrustSettingsPolicy);
3162 #endif
3163 policyName = (CFStringRef)CFDictionaryGetValue(constraint, kSecTrustSettingsPolicyName);
3164 policyString = (CFStringRef)CFDictionaryGetValue(constraint, kSecTrustSettingsPolicyString);
3165 keyUsageNumber = (CFNumberRef)CFDictionaryGetValue(constraint, kSecTrustSettingsKeyUsage);
3166 policyOptions = (CFDictionaryRef)CFDictionaryGetValue(constraint, kSecTrustSettingsPolicyOptions);
3167
3168 CFIndex policyIX = -1;
3169 policyMatch = SecPVCContainsPolicy(pvc, policyOid, policyName, &policyIX);
3170 policyStringMatch = SecPVCContainsString(pvc, policyIX, policyString);
3171 keyUsageMatch = SecPVCContainsTrustSettingsKeyUsage(pvc, certificate, policyIX, keyUsageNumber);
3172 policyOptionMatch = SecPVCContainsTrustSettingsPolicyOption(pvc, policyOptions);
3173
3174 #if TARGET_OS_MAC && !TARGET_OS_IPHONE
3175 trustedApplicationData = CFDictionaryGetValue(constraint, kSecTrustSettingsApplication);
3176 CFDataRef clientAuditToken = SecPathBuilderCopyClientAuditToken(pvc->builder);
3177 applicationMatch = SecPVCCallerIsApplication(clientAuditToken, trustedApplicationData);
3178 CFReleaseNull(clientAuditToken);
3179 #else
3180 if(CFDictionaryContainsKey(constraint, kSecTrustSettingsApplication)) {
3181 secerror("kSecTrustSettingsApplication is not yet supported on this platform");
3182 }
3183 #endif
3184
3185 /* If we either didn't find the parameter in the dictionary or we got a match
3186 * against that parameter, for all possible parameters in the dictionary, then
3187 * this trust setting result applies to the output. */
3188 if (((!policyOid && !policyName) || policyMatch) &&
3189 (!policyString || policyStringMatch) &&
3190 (!trustedApplicationData || applicationMatch) &&
3191 (!keyUsageNumber || keyUsageMatch) &&
3192 (!policyOptions || policyOptionMatch)) {
3193 result = true;
3194 }
3195
3196 return result;
3197 }
3198
3199 SecTrustSettingsResult SecPVCGetTrustSettingsResult(SecPVCRef pvc, SecCertificateRef certificate, CFArrayRef constraints) {
3200 SecTrustSettingsResult result = kSecTrustSettingsResultInvalid;
3201 CFIndex constraintIX, constraintCount = CFArrayGetCount(constraints);
3202 for (constraintIX = 0; constraintIX < constraintCount; constraintIX++) {
3203 CFDictionaryRef constraint = (CFDictionaryRef)CFArrayGetValueAtIndex(constraints, constraintIX);
3204 if (!isDictionary(constraint)) {
3205 continue;
3206 }
3207
3208 CFNumberRef resultNumber = NULL;
3209 resultNumber = (CFNumberRef)CFDictionaryGetValue(constraint, kSecTrustSettingsResult);
3210 uint32_t resultValue = kSecTrustSettingsResultInvalid;
3211 if (!isNumber(resultNumber) || !CFNumberGetValue(resultNumber, kCFNumberSInt32Type, &resultValue)) {
3212 /* no SecTrustSettingsResult entry defaults to TrustRoot*/
3213 resultValue = kSecTrustSettingsResultTrustRoot;
3214 }
3215
3216 if (SecPVCMeetsConstraint(pvc, certificate, constraint)) {
3217 result = resultValue;
3218 break;
3219 }
3220 }
3221 return result;
3222 }
3223
3224 static void SecPVCCheckUsageConstraints(SecPVCRef pvc) {
3225 CFIndex certIX, certCount = SecPVCGetCertificateCount(pvc);
3226 for (certIX = 0; certIX < certCount; certIX++) {
3227 SecCertificatePathVCRef path = SecPathBuilderGetPath(pvc->builder);
3228 CFArrayRef constraints = SecCertificatePathVCGetUsageConstraintsAtIndex(path, certIX);
3229 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, certIX);
3230 SecTrustSettingsResult result = SecPVCGetTrustSettingsResult(pvc, cert, constraints);
3231
3232 /* Set the pvc trust result based on the usage constraints and anchor source. */
3233 if (result == kSecTrustSettingsResultDeny) {
3234 SecPVCSetResultForced(pvc, kSecPolicyCheckUsageConstraints, certIX, kCFBooleanFalse, true);
3235 } else if ((result == kSecTrustSettingsResultTrustRoot || result == kSecTrustSettingsResultTrustAsRoot ||
3236 result == kSecTrustSettingsResultInvalid) && SecPVCIsOkResult(pvc)) {
3237 /* If we already think the PVC is ok and this cert is from one of the user/
3238 * admin anchor sources, trustRoot, trustAsRoot, and Invalid (no constraints),
3239 * all mean we should use the special "Proceed" trust result. */
3240 #if TARGET_OS_IPHONE
3241 if (SecPathBuilderIsAnchorSource(pvc->builder, kSecUserAnchorSource) &&
3242 SecCertificateSourceContains(kSecUserAnchorSource, cert)) {
3243 #else
3244 if (SecPathBuilderIsAnchorSource(pvc->builder, kSecLegacyAnchorSource) &&
3245 SecCertificateSourceContains(kSecLegacyAnchorSource, cert)) {
3246 #endif
3247 pvc->result = kSecTrustResultProceed;
3248 }
3249 }
3250 }
3251 }
3252
3253 static const UInt8 kTestDateConstraintsRoot[kSecPolicySHA256Size] = {
3254 0x51,0xA0,0xF3,0x1F,0xC0,0x1D,0xEC,0x87,0x32,0xB6,0xFD,0x13,0x6A,0x43,0x4D,0x6C,
3255 0x87,0xCD,0x62,0xE0,0x38,0xB4,0xFB,0xD6,0x40,0xB0,0xFD,0x62,0x4D,0x1F,0xCF,0x6D
3256 };
3257 static const UInt8 kWS_CA1_G2[kSecPolicySHA256Size] = {
3258 0xD4,0x87,0xA5,0x6F,0x83,0xB0,0x74,0x82,0xE8,0x5E,0x96,0x33,0x94,0xC1,0xEC,0xC2,
3259 0xC9,0xE5,0x1D,0x09,0x03,0xEE,0x94,0x6B,0x02,0xC3,0x01,0x58,0x1E,0xD9,0x9E,0x16
3260 };
3261 static const UInt8 kWS_CA1_NEW[kSecPolicySHA256Size] = {
3262 0x4B,0x22,0xD5,0xA6,0xAE,0xC9,0x9F,0x3C,0xDB,0x79,0xAA,0x5E,0xC0,0x68,0x38,0x47,
3263 0x9C,0xD5,0xEC,0xBA,0x71,0x64,0xF7,0xF2,0x2D,0xC1,0xD6,0x5F,0x63,0xD8,0x57,0x08
3264 };
3265 static const UInt8 kWS_CA2_NEW[kSecPolicySHA256Size] = {
3266 0xD6,0xF0,0x34,0xBD,0x94,0xAA,0x23,0x3F,0x02,0x97,0xEC,0xA4,0x24,0x5B,0x28,0x39,
3267 0x73,0xE4,0x47,0xAA,0x59,0x0F,0x31,0x0C,0x77,0xF4,0x8F,0xDF,0x83,0x11,0x22,0x54
3268 };
3269 static const UInt8 kWS_ECC[kSecPolicySHA256Size] = {
3270 0x8B,0x45,0xDA,0x1C,0x06,0xF7,0x91,0xEB,0x0C,0xAB,0xF2,0x6B,0xE5,0x88,0xF5,0xFB,
3271 0x23,0x16,0x5C,0x2E,0x61,0x4B,0xF8,0x85,0x56,0x2D,0x0D,0xCE,0x50,0xB2,0x9B,0x02
3272 };
3273 static const UInt8 kSC_SFSCA[kSecPolicySHA256Size] = {
3274 0xC7,0x66,0xA9,0xBE,0xF2,0xD4,0x07,0x1C,0x86,0x3A,0x31,0xAA,0x49,0x20,0xE8,0x13,
3275 0xB2,0xD1,0x98,0x60,0x8C,0xB7,0xB7,0xCF,0xE2,0x11,0x43,0xB8,0x36,0xDF,0x09,0xEA
3276 };
3277 static const UInt8 kSC_SHA2[kSecPolicySHA256Size] = {
3278 0xE1,0x78,0x90,0xEE,0x09,0xA3,0xFB,0xF4,0xF4,0x8B,0x9C,0x41,0x4A,0x17,0xD6,0x37,
3279 0xB7,0xA5,0x06,0x47,0xE9,0xBC,0x75,0x23,0x22,0x72,0x7F,0xCC,0x17,0x42,0xA9,0x11
3280 };
3281 static const UInt8 kSC_G2[kSecPolicySHA256Size] = {
3282 0xC7,0xBA,0x65,0x67,0xDE,0x93,0xA7,0x98,0xAE,0x1F,0xAA,0x79,0x1E,0x71,0x2D,0x37,
3283 0x8F,0xAE,0x1F,0x93,0xC4,0x39,0x7F,0xEA,0x44,0x1B,0xB7,0xCB,0xE6,0xFD,0x59,0x95
3284 };
3285
3286 static void SecPVCCheckIssuerDateConstraints(SecPVCRef pvc) {
3287 static CFSetRef sConstrainedRoots = NULL;
3288 static dispatch_once_t _t;
3289 dispatch_once(&_t, ^{
3290 const UInt8 *v_hashes[] = {
3291 kWS_CA1_G2, kWS_CA1_NEW, kWS_CA2_NEW, kWS_ECC,
3292 kSC_SFSCA, kSC_SHA2, kSC_G2, kTestDateConstraintsRoot
3293 };
3294 CFMutableSetRef set = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks);
3295 CFIndex ix, count = sizeof(v_hashes)/sizeof(*v_hashes);
3296 for (ix=0; ix<count; ix++) {
3297 CFDataRef hash = CFDataCreateWithBytesNoCopy(NULL, v_hashes[ix],
3298 kSecPolicySHA256Size, kCFAllocatorNull);
3299 if (hash) {
3300 CFSetAddValue(set, hash);
3301 CFRelease(hash);
3302 }
3303 }
3304 sConstrainedRoots = set;
3305 });
3306
3307 bool shouldDeny = false;
3308 CFIndex certIX, certCount = SecPVCGetCertificateCount(pvc);
3309 for (certIX = certCount - 1; certIX >= 0 && !shouldDeny; certIX--) {
3310 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, certIX);
3311 CFDataRef sha256 = SecCertificateCopySHA256Digest(cert);
3312 if (sha256 && CFSetContainsValue(sConstrainedRoots, sha256)) {
3313 /* matched a constrained root; check notBefore dates on all its children. */
3314 CFIndex childIX = certIX;
3315 while (--childIX >= 0) {
3316 SecCertificateRef child = SecPVCGetCertificateAtIndex(pvc, childIX);
3317 /* 1 Dec 2016 00:00:00 GMT */
3318 if (child && (CFAbsoluteTime)502243200.0 <= SecCertificateNotValidBefore(child)) {
3319 SecPVCSetResultForced(pvc, kSecPolicyCheckBlackListedKey, certIX, kCFBooleanFalse, true);
3320 shouldDeny = true;
3321 break;
3322 }
3323 }
3324 }
3325 CFReleaseNull(sha256);
3326 }
3327 }
3328
3329 static bool SecPVCIsSSLServerAuthenticationPolicy(SecPVCRef pvc) {
3330 if (!pvc || !pvc->policies) {
3331 return false;
3332 }
3333 SecPolicyRef policy = (SecPolicyRef)CFArrayGetValueAtIndex(pvc->policies, 0);
3334 if (!policy) {
3335 return false;
3336 }
3337 CFStringRef policyName = SecPolicyGetName(policy);
3338 if (CFEqualSafe(policyName, kSecPolicyNameSSLServer)) {
3339 return true;
3340 }
3341 CFDictionaryRef options = policy->_options;
3342 if (options && CFDictionaryGetValue(options, kSecPolicyCheckSSLHostname)) {
3343 return true;
3344 }
3345 return false;
3346 }
3347
3348 /* ASSUMPTIONS:
3349 1. SecPVCCheckRequireCTConstraints must be called after SecPolicyCheckCT,
3350 so earliest issuance time has already been obtained from SCTs.
3351 2. If the issuance time value is 0 (i.e. 2001-01-01) or earlier, we
3352 assume it was not set, and thus we did not have CT info.
3353 */
3354 static void SecPVCCheckRequireCTConstraints(SecPVCRef pvc) {
3355 SecCertificatePathVCRef path = (pvc) ? SecPathBuilderGetPath(pvc->builder) : NULL;
3356 if (!path) {
3357 return;
3358 }
3359 /* If we are evaluating for a SSL server authentication policy, make sure
3360 SCT issuance time is prior to the earliest not-after date constraint.
3361 Note that CT will already be required if there is a not-after date
3362 constraint present (set in SecRVCProcessValidDateConstraints).
3363 */
3364 if (SecPVCIsSSLServerAuthenticationPolicy(pvc)) {
3365 CFIndex ix, certCount = SecCertificatePathVCGetCount(path);
3366 SecCertificateRef certificate = SecPathBuilderGetCertificateAtIndex(pvc->builder, 0);
3367 CFAbsoluteTime earliestNotAfter = 31556908800.0; /* default: 3001-01-01 00:00:00-0000 */
3368 CFAbsoluteTime issuanceTime = SecCertificatePathVCIssuanceTime(path);
3369 if (issuanceTime <= 0) {
3370 /* if not set (or prior to 2001-01-01), use leaf's not-before time. */
3371 issuanceTime = SecCertificateNotValidBefore(certificate);
3372 }
3373 for (ix = 0; ix < certCount; ix++) {
3374 SecRVCRef rvc = SecCertificatePathVCGetRVCAtIndex(path, ix);
3375 if (!rvc || !rvc->valid_info || !rvc->valid_info->hasDateConstraints || !rvc->valid_info->notAfterDate) {
3376 continue;
3377 }
3378 /* Found CA certificate with a not-after date constraint. */
3379 CFAbsoluteTime caNotAfter = CFDateGetAbsoluteTime(rvc->valid_info->notAfterDate);
3380 if (caNotAfter < earliestNotAfter) {
3381 earliestNotAfter = caNotAfter;
3382 }
3383 if (issuanceTime > earliestNotAfter) {
3384 /* Issuance time violates the not-after date constraint. */
3385 secnotice("rvc", "certificate issuance time (%f) is later than allowed value (%f)",
3386 issuanceTime, earliestNotAfter);
3387 SecRVCSetValidDeterminedErrorResult(rvc);
3388 break;
3389 }
3390 }
3391 }
3392 /* If path is CT validated, nothing further to do here. */
3393 if (SecCertificatePathVCIsCT(path)) {
3394 return;
3395 }
3396
3397 /* Path is not CT validated, so check if CT was required. */
3398 SecPathCTPolicy ctp = SecCertificatePathVCRequiresCT(path);
3399 if (ctp <= kSecPathCTNotRequired || !SecPVCIsSSLServerAuthenticationPolicy(pvc)) {
3400 return;
3401 }
3402 /* CT was required. Error is always set on leaf certificate. */
3403 SecPVCSetResultForced(pvc, kSecPolicyCheckCTRequired,
3404 0, kCFBooleanFalse, true);
3405 if (ctp != kSecPathCTRequiredOverridable) {
3406 /* Normally kSecPolicyCheckCTRequired is recoverable,
3407 so need to manually change trust result here. */
3408 pvc->result = kSecTrustResultFatalTrustFailure;
3409 }
3410 }
3411
3412 /* AUDIT[securityd](done):
3413 policy->_options is a caller provided dictionary, only its cf type has
3414 been checked.
3415 */
3416 void SecPVCPathChecks(SecPVCRef pvc) {
3417 secdebug("policy", "begin path: %@", SecPathBuilderGetPath(pvc->builder));
3418 SecCertificatePathVCRef path = SecPathBuilderGetPath(pvc->builder);
3419 /* This needs to be initialized before we call any function that might call
3420 SecPVCSetResultForced(). */
3421 pvc->policyIX = 0;
3422 SecPolicyCheckIdLinkage(pvc, kSecPolicyCheckIdLinkage);
3423 if (SecPVCIsOkResult(pvc) || pvc->details) {
3424 SecPolicyCheckBasicCertificateProcessing(pvc,
3425 kSecPolicyCheckBasicCertificateProcessing);
3426 }
3427
3428 CFArrayRef policies = pvc->policies;
3429 CFIndex count = CFArrayGetCount(policies);
3430 for (; pvc->policyIX < count; ++pvc->policyIX) {
3431 /* Validate all keys for all policies. */
3432 pvc->callbacks = gSecPolicyPathCallbacks;
3433 SecPolicyRef policy = SecPVCGetPolicy(pvc);
3434 CFDictionaryApplyFunction(policy->_options, SecPVCValidateKey, pvc);
3435 if (!SecPVCIsOkResult(pvc) && !pvc->details)
3436 return;
3437 }
3438
3439 // Reset
3440 pvc->policyIX = 0;
3441
3442 /* Check whether the TrustSettings say to deny a cert in the path. */
3443 SecPVCCheckUsageConstraints(pvc);
3444
3445 /* Check for Blocklisted certs */
3446 SecPVCCheckIssuerDateConstraints(pvc);
3447 CFIndex ix;
3448 count = SecCertificatePathVCGetCount(path);
3449 for (ix = 1; ix < count; ix++) {
3450 SecPVCGrayListedKeyChecks(pvc, ix);
3451 SecPVCBlackListedKeyChecks(pvc, ix);
3452 }
3453
3454 /* Path-based check tests. */
3455 if (!SecCertificatePathVCIsPathValidated(path)) {
3456 bool ev_check_ok = false;
3457 if (SecCertificatePathVCIsOptionallyEV(path)) {
3458 SecTrustResultType pre_ev_check_result = pvc->result;
3459 SecPolicyCheckEV(pvc, kSecPolicyCheckExtendedValidation);
3460 ev_check_ok = SecPVCIsOkResult(pvc);
3461 /* If ev checking failed, we still want to accept this chain
3462 as a non EV one, if it was valid as such. */
3463 pvc->result = pre_ev_check_result;
3464 }
3465
3466 /* Check for CT */
3467 /* This call will set the value of pvc->is_ct, but won't change the result (pvc->result) */
3468 SecPolicyCheckCT(pvc);
3469
3470 /* Certs are only EV if they are also CT verified */
3471 if (ev_check_ok && SecCertificatePathVCIsCT(path)) {
3472 SecCertificatePathVCSetIsEV(path, true);
3473 }
3474 }
3475
3476 /* Say that we did the expensive path checks (that we want to skip on the second call) */
3477 SecCertificatePathVCSetPathValidated(SecPathBuilderGetPath(pvc->builder));
3478
3479 /* Check that this path meets CT constraints. */
3480 SecPVCCheckRequireCTConstraints(pvc);
3481 SecPolicyCheckSystemTrustedCTRequired(pvc);
3482
3483 /* Check that this path meets known-intermediate constraints. */
3484 SecPathBuilderCheckKnownIntermediateConstraints(pvc->builder);
3485
3486 secdebug("policy", "end %strusted path: %@",
3487 (SecPVCIsOkResult(pvc) ? "" : "not "), SecPathBuilderGetPath(pvc->builder));
3488
3489 return;
3490 }
3491
3492 void SecPVCPathCheckRevocationResponsesReceived(SecPVCRef pvc) {
3493 #if TARGET_OS_WATCH
3494 /* Since we don't currently allow networking on watchOS,
3495 * don't enforce the revocation-required check here. (32728029) */
3496 bool required = false;
3497 #else
3498 bool required = true;
3499 #endif
3500 SecCertificatePathVCRef path = SecPathBuilderGetPath(pvc->builder);
3501 CFIndex ix, certCount = SecCertificatePathVCGetCount(path);
3502 for (ix = 0; ix < certCount; ix++) {
3503 SecRVCRef rvc = SecCertificatePathVCGetRVCAtIndex(path, ix);
3504 /* Do we have a valid revocation response? */
3505 if (SecRVCGetEarliestNextUpdate(rvc) == NULL_TIME) {
3506 /* No valid revocation response.
3507 * Do we require revocation (for that cert per the
3508 * SecCertificateVCRef, or per the pvc)? */
3509 if (required && (SecCertificatePathVCIsRevocationRequiredForCertificateAtIndex(path, ix) ||
3510 ((ix == 0) && pvc->require_revocation_response))) {
3511 SecPVCSetResultForced(pvc, kSecPolicyCheckRevocationResponseRequired,
3512 ix, kCFBooleanFalse, true);
3513 }
3514 /* Do we have a definitive Valid revocation result for this cert? */
3515 if (SecRVCHasDefinitiveValidInfo(rvc) && SecRVCHasRevokedValidInfo(rvc)) {
3516 SecRVCSetValidDeterminedErrorResult(rvc);
3517 }
3518 }
3519 }
3520 }