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