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