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