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