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