]> git.saurik.com Git - apple/security.git/blob - OSX/sec/securityd/SecPolicyServer.c
Security-57740.60.18.tar.gz
[apple/security.git] / OSX / sec / securityd / SecPolicyServer.c
1 /*
2 * Copyright (c) 2008-2016 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 - Trust policies dealing with certificate revocation.
26 */
27
28 #include <securityd/SecPolicyServer.h>
29 #include <Security/SecPolicyInternal.h>
30 #include <Security/SecPolicyPriv.h>
31 #include <Security/SecTask.h>
32 #include <utilities/SecIOFormat.h>
33 #include <securityd/asynchttp.h>
34 #include <securityd/policytree.h>
35 #include <securityd/nameconstraints.h>
36 #include <CoreFoundation/CFTimeZone.h>
37 #include <wctype.h>
38 #include <libDER/oidsPriv.h>
39 #include <CoreFoundation/CFNumber.h>
40 #include <Security/SecCertificateInternal.h>
41 #include <AssertMacros.h>
42 #include <utilities/debugging.h>
43 #include <utilities/SecInternalReleasePriv.h>
44 #include <security_asn1/SecAsn1Coder.h>
45 #include <security_asn1/ocspTemplates.h>
46 #include <security_asn1/oidsalg.h>
47 #include <security_asn1/oidsocsp.h>
48 #include <CommonCrypto/CommonDigest.h>
49 #include <Security/SecFramework.h>
50 #include <Security/SecPolicyInternal.h>
51 #include <Security/SecTrustPriv.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/SecOCSPRequest.h>
61 #include <securityd/SecOCSPResponse.h>
62 #include <securityd/asynchttp.h>
63 #include <securityd/SecTrustServer.h>
64 #include <securityd/SecOCSPCache.h>
65 #include <securityd/SecRevocationDb.h>
66 #include <securityd/SecTrustLoggingServer.h>
67 #include <utilities/array_size.h>
68 #include <utilities/SecCFWrappers.h>
69 #include <utilities/SecAppleAnchorPriv.h>
70 #include "OTATrustUtilities.h"
71 #include "personalization.h"
72 #include <sys/codesign.h>
73
74 #if !TARGET_OS_IPHONE
75 #include <Security/SecTaskPriv.h>
76 #endif
77
78 /* Set this to 1 to dump the ocsp responses received in DER form in /tmp. */
79 #ifndef DUMP_OCSPRESPONSES
80 #define DUMP_OCSPRESPONSES 0
81 #endif
82
83 #if DUMP_OCSPRESPONSES
84
85 #include <unistd.h>
86 #include <fcntl.h>
87
88 static void secdumpdata(CFDataRef data, const char *name) {
89 int fd = open(name, O_CREAT | O_WRONLY | O_TRUNC, 0666);
90 write(fd, CFDataGetBytePtr(data), CFDataGetLength(data));
91 close(fd);
92 }
93
94 #endif
95
96
97 /********************************************************
98 ****************** SecPolicy object ********************
99 ********************************************************/
100
101 static CFMutableDictionaryRef gSecPolicyLeafCallbacks = NULL;
102 static CFMutableDictionaryRef gSecPolicyPathCallbacks = NULL;
103
104 static CFArrayRef SecPolicyAnchorDigestsForEVPolicy(const DERItem *policyOID)
105 {
106 CFArrayRef result = NULL;
107 SecOTAPKIRef otapkiRef = SecOTAPKICopyCurrentOTAPKIRef();
108 if (NULL == otapkiRef)
109 {
110 return result;
111 }
112
113 CFDictionaryRef evToPolicyAnchorDigest = SecOTAPKICopyEVPolicyToAnchorMapping(otapkiRef);
114 CFRelease(otapkiRef);
115
116 if (NULL == evToPolicyAnchorDigest)
117 {
118 return result;
119 }
120
121 CFArrayRef roots = NULL;
122 CFStringRef oid = SecDERItemCopyOIDDecimalRepresentation(kCFAllocatorDefault, policyOID);
123 if (oid && evToPolicyAnchorDigest)
124 {
125 result = (CFArrayRef)CFDictionaryGetValue(evToPolicyAnchorDigest, oid);
126 if (roots && CFGetTypeID(result) != CFArrayGetTypeID())
127 {
128 secerror("EVRoot.plist has non array value");
129 result = NULL;
130 }
131 CFRelease(oid);
132 }
133 CFReleaseSafe(evToPolicyAnchorDigest);
134 return result;
135 }
136
137
138 static bool SecPolicyIsEVPolicy(const DERItem *policyOID) {
139 return SecPolicyAnchorDigestsForEVPolicy(policyOID);
140 }
141
142 static bool SecPolicyRootCACertificateIsEV(SecCertificateRef certificate,
143 policy_set_t valid_policies) {
144 CFDictionaryRef keySizes = NULL;
145 CFNumberRef rsaSize = NULL, ecSize = NULL;
146 bool isEV = false;
147 /* Ensure that this certificate is a valid anchor for one of the
148 certificate policy oids specified in the leaf. */
149 CFDataRef digest = SecCertificateGetSHA1Digest(certificate);
150 policy_set_t ix;
151 bool good_ev_anchor = false;
152 for (ix = valid_policies; ix; ix = ix->oid_next) {
153 CFArrayRef digests = SecPolicyAnchorDigestsForEVPolicy(&ix->oid);
154 if (digests && CFArrayContainsValue(digests,
155 CFRangeMake(0, CFArrayGetCount(digests)), digest)) {
156 secdebug("ev", "found anchor for policy oid");
157 good_ev_anchor = true;
158 break;
159 }
160 }
161 require_action_quiet(good_ev_anchor, notEV, secnotice("ev", "anchor not in plist"));
162
163 CFAbsoluteTime october2006 = 178761600;
164 if (SecCertificateNotValidBefore(certificate) >= october2006) {
165 require_action_quiet(SecCertificateVersion(certificate) >= 3, notEV,
166 secnotice("ev", "Anchor issued after October 2006 and is not v3"));
167 }
168 if (SecCertificateVersion(certificate) >= 3
169 && SecCertificateNotValidBefore(certificate) >= october2006) {
170 const SecCEBasicConstraints *bc = SecCertificateGetBasicConstraints(certificate);
171 require_action_quiet(bc && bc->isCA == true, notEV,
172 secnotice("ev", "Anchor has invalid basic constraints"));
173 SecKeyUsage ku = SecCertificateGetKeyUsage(certificate);
174 require_action_quiet((ku & (kSecKeyUsageKeyCertSign | kSecKeyUsageCRLSign))
175 == (kSecKeyUsageKeyCertSign | kSecKeyUsageCRLSign), notEV,
176 secnotice("ev", "Anchor has invalid key usage %u", ku));
177 }
178
179 /* At least RSA 2048 or ECC NIST P-256. */
180 require_quiet(rsaSize = CFNumberCreateWithCFIndex(NULL, 2048), notEV);
181 require_quiet(ecSize = CFNumberCreateWithCFIndex(NULL, 256), notEV);
182 const void *keys[] = { kSecAttrKeyTypeRSA, kSecAttrKeyTypeEC };
183 const void *values[] = { rsaSize, ecSize };
184 require_quiet(keySizes = CFDictionaryCreate(NULL, keys, values, 2,
185 &kCFTypeDictionaryKeyCallBacks,
186 &kCFTypeDictionaryValueCallBacks), notEV);
187 require_action_quiet(SecCertificateIsAtLeastMinKeySize(certificate, keySizes), notEV,
188 secnotice("ev", "Anchor's public key is too weak for EV"));
189
190 isEV = true;
191
192 notEV:
193 CFReleaseNull(rsaSize);
194 CFReleaseNull(ecSize);
195 CFReleaseNull(keySizes);
196 return isEV;
197 }
198
199 static bool SecPolicySubordinateCACertificateCouldBeEV(SecCertificateRef certificate) {
200 CFMutableDictionaryRef keySizes = NULL;
201 CFNumberRef rsaSize = NULL, ecSize = NULL;
202 bool isEV = false;
203
204 const SecCECertificatePolicies *cp;
205 cp = SecCertificateGetCertificatePolicies(certificate);
206 require_action_quiet(cp && cp->numPolicies > 0, notEV,
207 secnotice("ev", "SubCA missing certificate policies"));
208 CFArrayRef cdp = SecCertificateGetCRLDistributionPoints(certificate);
209 require_action_quiet(cdp && CFArrayGetCount(cdp) > 0, notEV,
210 secnotice("ev", "SubCA missing CRLDP"));
211 const SecCEBasicConstraints *bc = SecCertificateGetBasicConstraints(certificate);
212 require_action_quiet(bc && bc->isCA == true, notEV,
213 secnotice("ev", "SubCA has invalid basic constraints"));
214 SecKeyUsage ku = SecCertificateGetKeyUsage(certificate);
215 require_action_quiet((ku & (kSecKeyUsageKeyCertSign | kSecKeyUsageCRLSign))
216 == (kSecKeyUsageKeyCertSign | kSecKeyUsageCRLSign), notEV,
217 secnotice("ev", "SubCA has invalid key usage %u", ku));
218
219 /* 6.1.5 Key Sizes */
220 CFAbsoluteTime jan2011 = 315532800;
221 CFAbsoluteTime jan2014 = 410227200;
222 require_quiet(ecSize = CFNumberCreateWithCFIndex(NULL, 256), notEV);
223 require_quiet(keySizes = CFDictionaryCreateMutable(NULL, 2, &kCFTypeDictionaryKeyCallBacks,
224 &kCFTypeDictionaryValueCallBacks), notEV);
225 CFDictionaryAddValue(keySizes, kSecAttrKeyTypeEC, ecSize);
226 if (SecCertificateNotValidBefore(certificate) < jan2011 ||
227 SecCertificateNotValidAfter(certificate) < jan2014) {
228 /* At least RSA 1024 or ECC NIST P-256. */
229 require_quiet(rsaSize = CFNumberCreateWithCFIndex(NULL, 1024), notEV);
230 CFDictionaryAddValue(keySizes, kSecAttrKeyTypeRSA, rsaSize);
231 require_action_quiet(SecCertificateIsAtLeastMinKeySize(certificate, keySizes), notEV,
232 secnotice("ev", "SubCA's public key is too small for issuance before 2011 or expiration before 2014"));
233 } else {
234 /* At least RSA 2028 or ECC NIST P-256. */
235 require_quiet(rsaSize = CFNumberCreateWithCFIndex(NULL, 2048), notEV);
236 CFDictionaryAddValue(keySizes, kSecAttrKeyTypeRSA, rsaSize);
237 require_action_quiet(SecCertificateIsAtLeastMinKeySize(certificate, keySizes), notEV,
238 secnotice("ev", "SubCA's public key is too small for issuance after 2010 or expiration after 2013"));
239 }
240
241 /* 7.1.3 Algorithm Object Identifiers */
242 CFAbsoluteTime jan2016 = 473299200;
243 if (SecCertificateNotValidBefore(certificate) > jan2016) {
244 /* SHA-2 only */
245 require_action_quiet(SecCertificateGetSignatureHashAlgorithm(certificate) > kSecSignatureHashAlgorithmSHA1,
246 notEV, secnotice("ev", "SubCA was issued with SHA-1 after 2015"));
247 }
248
249 isEV = true;
250
251 notEV:
252 CFReleaseNull(rsaSize);
253 CFReleaseNull(ecSize);
254 CFReleaseNull(keySizes);
255 return isEV;
256 }
257
258 bool SecPolicySubscriberCertificateCouldBeEV(SecCertificateRef certificate) {
259 CFMutableDictionaryRef keySizes = NULL;
260 CFNumberRef rsaSize = NULL, ecSize = NULL;
261 bool isEV = false;
262
263 /* 3. Subscriber Certificate. */
264
265 /* (a) certificate Policies */
266 const SecCECertificatePolicies *cp;
267 cp = SecCertificateGetCertificatePolicies(certificate);
268 require_quiet(cp && cp->numPolicies > 0, notEV);
269 /* Now find at least one policy in here that has a qualifierID of id-qt 2
270 and a policyQualifier that is a URI to the CPS and an EV policy OID. */
271 uint32_t ix = 0;
272 bool found_ev_anchor_for_leaf_policy = false;
273 for (ix = 0; ix < cp->numPolicies; ++ix) {
274 if (SecPolicyIsEVPolicy(&cp->policies[ix].policyIdentifier)) {
275 found_ev_anchor_for_leaf_policy = true;
276 }
277 }
278 require_quiet(found_ev_anchor_for_leaf_policy, notEV);
279
280 /* (b) cRLDistributionPoint
281 (c) authorityInformationAccess
282 BRv1.3.4: MUST be present with OCSP Responder unless stapled response.
283 */
284
285 /* (d) basicConstraints
286 If present, the cA field MUST be set false. */
287 const SecCEBasicConstraints *bc = SecCertificateGetBasicConstraints(certificate);
288 if (bc) {
289 require_action_quiet(bc->isCA == false, notEV,
290 secnotice("ev", "Leaf has invalid basic constraints"));
291 }
292
293 /* (e) keyUsage. */
294 SecKeyUsage ku = SecCertificateGetKeyUsage(certificate);
295 if (ku) {
296 require_action_quiet((ku & (kSecKeyUsageKeyCertSign | kSecKeyUsageCRLSign)) == 0, notEV,
297 secnotice("ev", "Leaf has invalid key usage %u", ku));
298 }
299
300 #if 0
301 /* The EV Cert Spec errata specifies this, though this is a check for SSL
302 not specifically EV. */
303
304 /* (e) extKeyUsage
305
306 Either the value id-kp-serverAuth [RFC5280] or id-kp-clientAuth [RFC5280] or both values MUST be present. Other values SHOULD NOT be present. */
307 SecCertificateCopyExtendedKeyUsage(certificate);
308 #endif
309
310 /* 6.1.5 Key Sizes */
311 CFAbsoluteTime jan2014 = 410227200;
312 require_quiet(ecSize = CFNumberCreateWithCFIndex(NULL, 256), notEV);
313 require_quiet(keySizes = CFDictionaryCreateMutable(NULL, 2, &kCFTypeDictionaryKeyCallBacks,
314 &kCFTypeDictionaryValueCallBacks), notEV);
315 CFDictionaryAddValue(keySizes, kSecAttrKeyTypeEC, ecSize);
316 if (SecCertificateNotValidBefore(certificate) < jan2014) {
317 /* At least RSA 1024 or ECC NIST P-256. */
318 require_quiet(rsaSize = CFNumberCreateWithCFIndex(NULL, 1024), notEV);
319 CFDictionaryAddValue(keySizes, kSecAttrKeyTypeRSA, rsaSize);
320 require_action_quiet(SecCertificateIsAtLeastMinKeySize(certificate, keySizes), notEV,
321 secnotice("ev", "Leaf's public key is too small for issuance before 2014"));
322 } else {
323 /* At least RSA 2028 or ECC NIST P-256. */
324 require_quiet(rsaSize = CFNumberCreateWithCFIndex(NULL, 2048), notEV);
325 CFDictionaryAddValue(keySizes, kSecAttrKeyTypeRSA, rsaSize);
326 require_action_quiet(SecCertificateIsAtLeastMinKeySize(certificate, keySizes), notEV,
327 secnotice("ev", "Leaf's public key is too small for issuance after 2013"));
328 }
329
330 /* 6.3.2 Validity Periods */
331 CFAbsoluteTime jul2016 = 489024000;
332 CFAbsoluteTime notAfter = SecCertificateNotValidAfter(certificate);
333 CFAbsoluteTime notBefore = SecCertificateNotValidBefore(certificate);
334 if (SecCertificateNotValidBefore(certificate) < jul2016) {
335 /* Validity Period no greater than 60 months.
336 60 months is no more than 5 years and 2 leap days. */
337 CFAbsoluteTime maxPeriod = 60*60*24*(365*5+2);
338 require_action_quiet(notAfter - notBefore <= maxPeriod, notEV,
339 secnotice("ev", "Leaf's validity period is more than 60 months"));
340 } else {
341 /* Validity Period no greater than 39 months.
342 39 months is no more than 3 years, 2 31-day months,
343 1 30-day month, and 1 leap day */
344 CFAbsoluteTime maxPeriod = 60*60*24*(365*3+2*31+30+1);
345 require_action_quiet(notAfter - notBefore <= maxPeriod, notEV,
346 secnotice("ev", "Leaf has validity period longer than 39 months and issued after 30 June 2016"));
347 }
348
349 /* 7.1.3 Algorithm Object Identifiers */
350 CFAbsoluteTime jan2016 = 473299200;
351 if (SecCertificateNotValidBefore(certificate) > jan2016) {
352 /* SHA-2 only */
353 require_action_quiet(SecCertificateGetSignatureHashAlgorithm(certificate) > kSecSignatureHashAlgorithmSHA1,
354 notEV, secnotice("ev", "Leaf was issued with SHA-1 after 2015"));
355 }
356
357 isEV = true;
358
359 notEV:
360 CFReleaseNull(rsaSize);
361 CFReleaseNull(ecSize);
362 CFReleaseNull(keySizes);
363 return isEV;
364 }
365
366 /********************************************************
367 **************** SecPolicy Callbacks *******************
368 ********************************************************/
369 static void SecPolicyCheckCriticalExtensions(SecPVCRef pvc,
370 CFStringRef key) {
371 }
372
373 static void SecPolicyCheckIdLinkage(SecPVCRef pvc,
374 CFStringRef key) {
375 CFIndex ix, count = SecPVCGetCertificateCount(pvc);
376 CFDataRef parentSubjectKeyID = NULL;
377 for (ix = count - 1; ix >= 0; --ix) {
378 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix);
379 /* If the previous certificate in the chain had a SubjectKeyID,
380 make sure it matches the current certificates AuthorityKeyID. */
381 if (parentSubjectKeyID) {
382 /* @@@ According to RFC 2459 neither AuthorityKeyID nor
383 SubjectKeyID can be critical. Currenty we don't check
384 for this. */
385 CFDataRef authorityKeyID = SecCertificateGetAuthorityKeyID(cert);
386 if (authorityKeyID) {
387 if (!CFEqual(parentSubjectKeyID, authorityKeyID)) {
388 /* AuthorityKeyID doesn't match issuers SubjectKeyID. */
389 if (!SecPVCSetResult(pvc, key, ix, kCFBooleanFalse))
390 return;
391 }
392 }
393 }
394
395 parentSubjectKeyID = SecCertificateGetSubjectKeyID(cert);
396 }
397 }
398
399 static void SecPolicyCheckKeyUsage(SecPVCRef pvc,
400 CFStringRef key) {
401 SecCertificateRef leaf = SecPVCGetCertificateAtIndex(pvc, 0);
402 SecPolicyRef policy = SecPVCGetPolicy(pvc);
403 CFTypeRef xku = CFDictionaryGetValue(policy->_options, key);
404 if (!SecPolicyCheckCertKeyUsage(leaf, xku)) {
405 SecPVCSetResult(pvc, key, 0, kCFBooleanFalse);
406 }
407 }
408
409 /* AUDIT[securityd](done):
410 policy->_options is a caller provided dictionary, only its cf type has
411 been checked.
412 */
413 static void SecPolicyCheckExtendedKeyUsage(SecPVCRef pvc, CFStringRef key) {
414 SecCertificateRef leaf = SecPVCGetCertificateAtIndex(pvc, 0);
415 SecPolicyRef policy = SecPVCGetPolicy(pvc);
416 CFTypeRef xeku = CFDictionaryGetValue(policy->_options, key);
417 if (!SecPolicyCheckCertExtendedKeyUsage(leaf, xeku)){
418 SecPVCSetResult(pvc, key, 0, kCFBooleanFalse);
419 }
420 }
421
422 #if 0
423 static void SecPolicyCheckBasicContraintsCommon(SecPVCRef pvc,
424 CFStringRef key, bool strict) {
425 CFIndex ix, count = SecPVCGetCertificateCount(pvc);
426 for (ix = 0; ix < count; ++ix) {
427 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix);
428 const SecCEBasicConstraints *bc =
429 SecCertificateGetBasicConstraints(cert);
430 if (bc) {
431 if (strict) {
432 if (ix == 0) {
433 /* Leaf certificate has basic constraints extension. */
434 if (!SecPVCSetResult(pvc, key, ix, kCFBooleanFalse))
435 return;
436 } else if (!bc->critical) {
437 /* Basic constraints extension is not marked critical. */
438 if (!SecPVCSetResult(pvc, key, ix, kCFBooleanFalse))
439 return;
440 }
441 }
442
443 if (ix > 0 || count == 1) {
444 if (!bc->isCA) {
445 /* Non leaf certificate marked as isCA false. */
446 if (!SecPVCSetResult(pvc, key, ix, kCFBooleanFalse))
447 return;
448 }
449
450 if (bc->pathLenConstraintPresent) {
451 if (bc->pathLenConstraint < (uint32_t)(ix - 1)) {
452 #if 0
453 /* @@@ If a self signed certificate is issued by
454 another cert that is trusted, then we are supposed
455 to treat the self signed cert itself as the anchor
456 for path length purposes. */
457 CFIndex ssix = SecCertificatePathSelfSignedIndex(path);
458 if (ssix >= 0 && ix >= ssix) {
459 /* It's ok if the pathLenConstraint isn't met for
460 certificates signing a self signed cert in the
461 chain. */
462 } else
463 #endif
464 {
465 /* Path Length Constraint Exceeded. */
466 if (!SecPVCSetResult(pvc, key, ix,
467 kCFBooleanFalse))
468 return;
469 }
470 }
471 }
472 }
473 } else if (strict && ix > 0) {
474 /* In strict mode all CA certificates *MUST* have a critical
475 basic constraints extension and the leaf certificate
476 *MUST NOT* have a basic constraints extension. */
477 /* CA certificate is missing basicConstraints extension. */
478 if (!SecPVCSetResult(pvc, key, ix, kCFBooleanFalse))
479 return;
480 }
481 }
482 }
483 #endif
484
485 static void SecPolicyCheckBasicConstraints(SecPVCRef pvc,
486 CFStringRef key) {
487 //SecPolicyCheckBasicContraintsCommon(pvc, key, false);
488 }
489
490 static void SecPolicyCheckNonEmptySubject(SecPVCRef pvc,
491 CFStringRef key) {
492 CFIndex ix, count = SecPVCGetCertificateCount(pvc);
493 for (ix = 0; ix < count; ++ix) {
494 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix);
495 /* If the certificate has a subject, or
496 if it doesn't, and it's the leaf and not self signed,
497 and also has a critical subjectAltName extension it's valid. */
498 if (!SecCertificateHasSubject(cert)) {
499 if (ix == 0 && count > 1) {
500 if (!SecCertificateHasCriticalSubjectAltName(cert)) {
501 /* Leaf certificate with empty subject does not have
502 a critical subject alt name extension. */
503 if (!SecPVCSetResult(pvc, key, ix, kCFBooleanFalse))
504 return;
505 }
506 } else {
507 /* CA certificate has empty subject. */
508 if (!SecPVCSetResult(pvc, key, ix, kCFBooleanFalse))
509 return;
510 }
511 }
512 }
513 }
514
515 static void SecPolicyCheckQualifiedCertStatements(SecPVCRef pvc,
516 CFStringRef key) {
517 }
518
519 /* Compare hostname suffix to domain name.
520 This function does not process wildcards, and allows hostname to match
521 any subdomain level of the provided domain.
522
523 To match, the last domain length chars of hostname must equal domain,
524 and the character immediately preceding domain in hostname (if any)
525 must be a dot. This means that domain 'bar.com' will match hostname
526 values 'host.bar.com' or 'host.sub.bar.com', but not 'host.foobar.com'.
527
528 Characters in each string are converted to lowercase for the comparison.
529 Trailing '.' characters in both names will be ignored.
530
531 Returns true on match, else false.
532 */
533 static bool SecDomainSuffixMatch(CFStringRef hostname, CFStringRef domain) {
534 CFStringInlineBuffer hbuf = {}, dbuf = {};
535 UniChar hch, dch;
536 CFIndex hix, dix,
537 hlength = CFStringGetLength(hostname),
538 dlength = CFStringGetLength(domain);
539 CFRange hrange = { 0, hlength }, drange = { 0, dlength };
540 CFStringInitInlineBuffer(hostname, &hbuf, hrange);
541 CFStringInitInlineBuffer(domain, &dbuf, drange);
542
543 if((hlength == 0) || (dlength == 0)) {
544 /* trivial case with at least one empty name */
545 return (hlength == dlength) ? true : false;
546 }
547
548 /* trim off trailing dots */
549 hch = CFStringGetCharacterFromInlineBuffer(&hbuf, hlength-1);
550 dch = CFStringGetCharacterFromInlineBuffer(&dbuf, dlength-1);
551 if(hch == '.') {
552 hrange.length = --hlength;
553 }
554 if(dch == '.') {
555 drange.length = --dlength;
556 }
557
558 /* trim off leading dot in suffix, if present */
559 dch = CFStringGetCharacterFromInlineBuffer(&dbuf, 0);
560 if((dlength > 0) && (dch == '.')) {
561 drange.location++;
562 drange.length = --dlength;
563 }
564
565 if(hlength < dlength) {
566 return false;
567 }
568
569 /* perform case-insensitive comparison of domain suffix */
570 for (hix = (hlength-dlength),
571 dix = drange.location; dix < drange.length; dix++) {
572 hch = CFStringGetCharacterFromInlineBuffer(&hbuf, hix);
573 dch = CFStringGetCharacterFromInlineBuffer(&dbuf, dix);
574 if (towlower(hch) != towlower(dch)) {
575 return false;
576 }
577 }
578
579 /* require a dot prior to domain suffix, unless hostname == domain */
580 if(hlength > dlength) {
581 hch = CFStringGetCharacterFromInlineBuffer(&hbuf, (hlength-(dlength+1)));
582 if(hch != '.') {
583 return false;
584 }
585 }
586
587 return true;
588 }
589
590 #define kSecPolicySHA1Size 20
591 static const UInt8 kAppleCorpCASHA1[kSecPolicySHA1Size] = {
592 0xA1, 0x71, 0xDC, 0xDE, 0xE0, 0x8B, 0x1B, 0xAE, 0x30, 0xA1,
593 0xAE, 0x6C, 0xC6, 0xD4, 0x03, 0x3B, 0xFD, 0xEF, 0x91, 0xCE
594 };
595
596 /* Check whether hostname is in a particular set of allowed domains.
597 Returns true if OK, false if not allowed.
598 */
599 static bool SecPolicyCheckDomain(SecPVCRef pvc, CFStringRef hostname)
600 {
601 CFIndex count = SecPVCGetCertificateCount(pvc);
602 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, count - 1);
603 CFDataRef anchorSHA1 = SecCertificateGetSHA1Digest(cert);
604
605 /* is this chain anchored by kAppleCorpCASHA1? */
606 CFDataRef corpSHA1 = CFDataCreateWithBytesNoCopy(NULL,
607 kAppleCorpCASHA1, kSecPolicySHA1Size, kCFAllocatorNull);
608 bool isCorpSHA1 = (corpSHA1 && CFEqual(anchorSHA1, corpSHA1));
609 CFReleaseSafe(corpSHA1);
610 if (isCorpSHA1) {
611 /* limit hostname to specified domains */
612 const CFStringRef dnlist[] = {
613 CFSTR("apple.com"),
614 CFSTR("icloud.com"),
615 };
616 unsigned int idx, dncount=2;
617 for (idx = 0; idx < dncount; idx++) {
618 if (SecDomainSuffixMatch(hostname, dnlist[idx])) {
619 return true;
620 }
621 }
622 return false;
623 }
624 /* %%% other CA pinning checks TBA */
625
626 return true;
627 }
628
629 /* AUDIT[securityd](done):
630 policy->_options is a caller provided dictionary, only its cf type has
631 been checked.
632 */
633 static void SecPolicyCheckSSLHostname(SecPVCRef pvc,
634 CFStringRef key) {
635 /* @@@ Consider what to do if the caller passes in no hostname. Should
636 we then still fail if the leaf has no dnsNames or IPAddresses at all? */
637 SecPolicyRef policy = SecPVCGetPolicy(pvc);
638 CFStringRef hostName = (CFStringRef)
639 CFDictionaryGetValue(policy->_options, key);
640 if (!isString(hostName)) {
641 /* @@@ We can't return an error here and making the evaluation fail
642 won't help much either. */
643 return;
644 }
645
646 SecCertificateRef leaf = SecPVCGetCertificateAtIndex(pvc, 0);
647 bool dnsMatch = SecPolicyCheckCertSSLHostname(leaf, hostName);
648
649 if (!dnsMatch) {
650 /* Hostname mismatch or no hostnames found in certificate. */
651 SecPVCSetResult(pvc, key, 0, kCFBooleanFalse);
652 }
653 else if (!SecPolicyCheckDomain(pvc, hostName)) {
654 /* Hostname match, but domain not allowed for this CA */
655 SecPVCSetResult(pvc, key, 0, kCFBooleanFalse);
656 }
657
658 if ((dnsMatch || pvc->details)
659 && SecPolicySubscriberCertificateCouldBeEV(leaf)) {
660 secdebug("policy", "enabling optionally_ev");
661 pvc->optionally_ev = true;
662 }
663
664 }
665
666 /* AUDIT[securityd](done):
667 policy->_options is a caller provided dictionary, only its cf type has
668 been checked.
669 */
670 static void SecPolicyCheckEmail(SecPVCRef pvc, CFStringRef key) {
671 SecPolicyRef policy = SecPVCGetPolicy(pvc);
672 CFStringRef email = (CFStringRef)CFDictionaryGetValue(policy->_options, key);
673 if (!isString(email)) {
674 /* We can't return an error here and making the evaluation fail
675 won't help much either. */
676 return;
677 }
678
679 SecCertificateRef leaf = SecPVCGetCertificateAtIndex(pvc, 0);
680
681 if (!SecPolicyCheckCertEmail(leaf, email)) {
682 /* Hostname mismatch or no hostnames found in certificate. */
683 SecPVCSetResult(pvc, key, 0, kCFBooleanFalse);
684 }
685 }
686
687 static void SecPolicyCheckValidIntermediates(SecPVCRef pvc,
688 CFStringRef key) {
689 CFIndex ix, count = SecPVCGetCertificateCount(pvc);
690 CFAbsoluteTime verifyTime = SecPVCGetVerifyTime(pvc);
691 for (ix = 1; ix < count - 1; ++ix) {
692 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix);
693 if (!SecCertificateIsValid(cert, verifyTime)) {
694 /* Intermediate certificate has expired. */
695 if (!SecPVCSetResult(pvc, key, ix, kCFBooleanFalse))
696 return;
697 }
698 }
699 }
700
701 static void SecPolicyCheckValidLeaf(SecPVCRef pvc,
702 CFStringRef key) {
703 CFAbsoluteTime verifyTime = SecPVCGetVerifyTime(pvc);
704 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, 0);
705 if (!SecCertificateIsValid(cert, verifyTime)) {
706 /* Leaf certificate has expired. */
707 if (!SecPVCSetResult(pvc, key, 0, kCFBooleanFalse))
708 return;
709 }
710 }
711
712 static void SecPolicyCheckValidRoot(SecPVCRef pvc,
713 CFStringRef key) {
714 CFIndex ix, count = SecPVCGetCertificateCount(pvc);
715 CFAbsoluteTime verifyTime = SecPVCGetVerifyTime(pvc);
716 ix = count - 1;
717 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix);
718 if (!SecCertificateIsValid(cert, verifyTime)) {
719 /* Root certificate has expired. */
720 if (!SecPVCSetResult(pvc, key, ix, kCFBooleanFalse))
721 return;
722 }
723 }
724
725 /* AUDIT[securityd](done):
726 policy->_options is a caller provided dictionary, only its cf type has
727 been checked.
728 */
729 static void SecPolicyCheckIssuerCommonName(SecPVCRef pvc,
730 CFStringRef key) {
731 CFIndex count = SecPVCGetCertificateCount(pvc);
732 if (count < 2) {
733 /* Can't check intermediates common name if there is no intermediate. */
734 SecPVCSetResult(pvc, key, 0, kCFBooleanFalse);
735 return;
736 }
737
738 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, 1);
739 SecPolicyRef policy = SecPVCGetPolicy(pvc);
740 CFStringRef commonName =
741 (CFStringRef)CFDictionaryGetValue(policy->_options, key);
742 if (!isString(commonName)) {
743 /* @@@ We can't return an error here and making the evaluation fail
744 won't help much either. */
745 return;
746 }
747 if (!SecPolicyCheckCertSubjectCommonName(cert, commonName)) {
748 SecPVCSetResult(pvc, key, 0, kCFBooleanFalse);
749 }
750 }
751
752 /* AUDIT[securityd](done):
753 policy->_options is a caller provided dictionary, only its cf type has
754 been checked.
755 */
756 static void SecPolicyCheckSubjectCommonName(SecPVCRef pvc,
757 CFStringRef key) {
758 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, 0);
759 SecPolicyRef policy = SecPVCGetPolicy(pvc);
760 CFStringRef common_name = (CFStringRef)CFDictionaryGetValue(policy->_options,
761 key);
762 if (!isString(common_name)) {
763 /* @@@ We can't return an error here and making the evaluation fail
764 won't help much either. */
765 return;
766 }
767 if (!SecPolicyCheckCertSubjectCommonName(cert, common_name)) {
768 SecPVCSetResult(pvc, key, 0, kCFBooleanFalse);
769 }
770 }
771
772 /* AUDIT[securityd](done):
773 policy->_options is a caller provided dictionary, only its cf type has
774 been checked.
775 */
776 static void SecPolicyCheckSubjectCommonNamePrefix(SecPVCRef pvc,
777 CFStringRef key) {
778 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, 0);
779 SecPolicyRef policy = SecPVCGetPolicy(pvc);
780 CFStringRef prefix = (CFStringRef)CFDictionaryGetValue(policy->_options,
781 key);
782 if (!isString(prefix)) {
783 /* @@@ We can't return an error here and making the evaluation fail
784 won't help much either. */
785 return;
786 }
787 if (!SecPolicyCheckCertSubjectCommonNamePrefix(cert, prefix)) {
788 SecPVCSetResult(pvc, key, 0, kCFBooleanFalse);
789 }
790 }
791
792 /* AUDIT[securityd](done):
793 policy->_options is a caller provided dictionary, only its cf type has
794 been checked.
795 */
796 static void SecPolicyCheckSubjectCommonNameTEST(SecPVCRef pvc,
797 CFStringRef key) {
798 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, 0);
799 SecPolicyRef policy = SecPVCGetPolicy(pvc);
800 CFStringRef common_name = (CFStringRef)CFDictionaryGetValue(policy->_options,
801 key);
802 if (!isString(common_name)) {
803 /* @@@ We can't return an error here and making the evaluation fail
804 won't help much either. */
805 return;
806 }
807 if (!SecPolicyCheckCertSubjectCommonNameTEST(cert, common_name)) {
808 SecPVCSetResult(pvc, key, 0, kCFBooleanFalse);
809 }
810 }
811
812 /* AUDIT[securityd](done):
813 policy->_options is a caller provided dictionary, only its cf type has
814 been checked.
815 */
816 static void SecPolicyCheckNotValidBefore(SecPVCRef pvc,
817 CFStringRef key) {
818 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, 0);
819 SecPolicyRef policy = SecPVCGetPolicy(pvc);
820 CFDateRef date = (CFDateRef)CFDictionaryGetValue(policy->_options, key);
821 if (!isDate(date)) {
822 /* @@@ We can't return an error here and making the evaluation fail
823 won't help much either. */
824 return;
825 }
826 if (!SecPolicyCheckCertNotValidBefore(cert, date)) {
827 if (!SecPVCSetResult(pvc, key, 0, kCFBooleanFalse))
828 return;
829 }
830 }
831
832 /* AUDIT[securityd](done):
833 policy->_options is a caller provided dictionary, only its cf type has
834 been checked.
835 */
836 static void SecPolicyCheckChainLength(SecPVCRef pvc,
837 CFStringRef key) {
838 CFIndex count = SecPVCGetCertificateCount(pvc);
839 SecPolicyRef policy = SecPVCGetPolicy(pvc);
840 CFNumberRef chainLength =
841 (CFNumberRef)CFDictionaryGetValue(policy->_options, key);
842 CFIndex value;
843 if (!chainLength || CFGetTypeID(chainLength) != CFNumberGetTypeID() ||
844 !CFNumberGetValue(chainLength, kCFNumberCFIndexType, &value)) {
845 /* @@@ We can't return an error here and making the evaluation fail
846 won't help much either. */
847 return;
848 }
849 if (value != count) {
850 /* Chain length doesn't match policy requirement. */
851 if (!SecPVCSetResult(pvc, key, 0, kCFBooleanFalse))
852 return;
853 }
854 }
855
856 static bool isDigestInPolicy(SecPVCRef pvc, CFStringRef key, CFDataRef digest) {
857 SecPolicyRef policy = SecPVCGetPolicy(pvc);
858 CFTypeRef value = CFDictionaryGetValue(policy->_options, key);
859
860 bool foundMatch = false;
861 if (isData(value))
862 foundMatch = CFEqual(digest, value);
863 else if (isArray(value))
864 foundMatch = CFArrayContainsValue((CFArrayRef) value, CFRangeMake(0, CFArrayGetCount((CFArrayRef) value)), digest);
865 else {
866 /* @@@ We only support Data and Array but we can't return an error here so.
867 we let the evaluation fail (not much help) and assert in debug. */
868 assert(false);
869 }
870
871 return foundMatch;
872 }
873
874 static void SecPolicyCheckAnchorSHA256(SecPVCRef pvc, CFStringRef key) {
875 CFIndex count = SecPVCGetCertificateCount(pvc);
876 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, count - 1);
877 CFDataRef anchorSHA256 = NULL;
878 anchorSHA256 = SecCertificateCopySHA256Digest(cert);
879
880 if (!isDigestInPolicy(pvc, key, anchorSHA256)) {
881 SecPVCSetResult(pvc, kSecPolicyCheckAnchorSHA256, count-1, kCFBooleanFalse);
882 }
883
884 CFReleaseNull(anchorSHA256);
885 return;
886 }
887
888
889 /* AUDIT[securityd](done):
890 policy->_options is a caller provided dictionary, only its cf type has
891 been checked.
892 */
893 static void SecPolicyCheckAnchorSHA1(SecPVCRef pvc,
894 CFStringRef key) {
895 CFIndex count = SecPVCGetCertificateCount(pvc);
896 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, count - 1);
897 CFDataRef anchorSHA1 = SecCertificateGetSHA1Digest(cert);
898
899 if (!isDigestInPolicy(pvc, key, anchorSHA1))
900 if (!SecPVCSetResult(pvc, kSecPolicyCheckAnchorSHA1, count-1, kCFBooleanFalse))
901 return;
902
903 return;
904 }
905
906 /*
907 Check the SHA256 of SPKI of the first intermediate CA certificate in the path
908 policy->_options is a caller provided dictionary, only its cf type has
909 been checked.
910 */
911 static void SecPolicyCheckIntermediateSPKISHA256(SecPVCRef pvc,
912 CFStringRef key) {
913 SecCertificateRef cert = NULL;
914 CFDataRef digest = NULL;
915
916 if (SecPVCGetCertificateCount(pvc) < 2) {
917 SecPVCSetResult(pvc, kSecPolicyCheckIntermediateSPKISHA256, 0, kCFBooleanFalse);
918 return;
919 }
920
921 cert = SecPVCGetCertificateAtIndex(pvc, 1);
922 digest = SecCertificateCopySubjectPublicKeyInfoSHA256Digest(cert);
923
924 if (!isDigestInPolicy(pvc, key, digest)) {
925 SecPVCSetResult(pvc, kSecPolicyCheckIntermediateSPKISHA256, 1, kCFBooleanFalse);
926 }
927 CFReleaseNull(digest);
928 }
929
930 /*
931 policy->_options is a caller provided dictionary, only its cf type has
932 been checked.
933 */
934 static void SecPolicyCheckAnchorApple(SecPVCRef pvc,
935 CFStringRef key) {
936 CFIndex count = SecPVCGetCertificateCount(pvc);
937 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, count - 1);
938 SecPolicyRef policy = SecPVCGetPolicy(pvc);
939 CFTypeRef value = CFDictionaryGetValue(policy->_options, key);
940 SecAppleTrustAnchorFlags flags = 0;
941
942 if (isDictionary(value)) {
943 if (CFDictionaryGetValue(value, kSecPolicyAppleAnchorIncludeTestRoots)) {
944 flags |= kSecAppleTrustAnchorFlagsIncludeTestAnchors;
945 }
946 }
947
948 bool foundMatch = SecIsAppleTrustAnchor(cert, flags);
949
950 if (!foundMatch)
951 if (!SecPVCSetResult(pvc, kSecPolicyCheckAnchorApple, 0, kCFBooleanFalse))
952 return;
953
954 return;
955 }
956
957
958 /* AUDIT[securityd](done):
959 policy->_options is a caller provided dictionary, only its cf type has
960 been checked.
961 */
962 static void SecPolicyCheckSubjectOrganization(SecPVCRef pvc,
963 CFStringRef key) {
964 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, 0);
965 SecPolicyRef policy = SecPVCGetPolicy(pvc);
966 CFStringRef org = (CFStringRef)CFDictionaryGetValue(policy->_options,
967 key);
968 if (!isString(org)) {
969 /* @@@ We can't return an error here and making the evaluation fail
970 won't help much either. */
971 return;
972 }
973 if (!SecPolicyCheckCertSubjectOrganization(cert, org)) {
974 /* Leaf Subject Organization mismatch. */
975 SecPVCSetResult(pvc, key, 0, kCFBooleanFalse);
976 }
977 }
978
979 static void SecPolicyCheckSubjectOrganizationalUnit(SecPVCRef pvc,
980 CFStringRef key) {
981 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, 0);
982 SecPolicyRef policy = SecPVCGetPolicy(pvc);
983 CFStringRef orgUnit = (CFStringRef)CFDictionaryGetValue(policy->_options,
984 key);
985 if (!isString(orgUnit)) {
986 /* @@@ We can't return an error here and making the evaluation fail
987 won't help much either. */
988 return;
989 }
990 if (!SecPolicyCheckCertSubjectOrganizationalUnit(cert, orgUnit)) {
991 /* Leaf Subject Organization mismatch. */
992 SecPVCSetResult(pvc, key, 0, kCFBooleanFalse);
993 }
994 }
995
996 /* AUDIT[securityd](done):
997 policy->_options is a caller provided dictionary, only its cf type has
998 been checked.
999 */
1000 static void SecPolicyCheckEAPTrustedServerNames(SecPVCRef pvc,
1001 CFStringRef key) {
1002 SecPolicyRef policy = SecPVCGetPolicy(pvc);
1003 CFArrayRef trustedServerNames = (CFArrayRef)
1004 CFDictionaryGetValue(policy->_options, key);
1005 /* No names specified means we accept any name. */
1006 if (!trustedServerNames)
1007 return;
1008 if (!isArray(trustedServerNames)) {
1009 /* @@@ We can't return an error here and making the evaluation fail
1010 won't help much either. */
1011 return;
1012 }
1013
1014 SecCertificateRef leaf = SecPVCGetCertificateAtIndex(pvc, 0);
1015 if (!SecPolicyCheckCertEAPTrustedServerNames(leaf, trustedServerNames)) {
1016 /* Hostname mismatch or no hostnames found in certificate. */
1017 SecPVCSetResult(pvc, key, 0, kCFBooleanFalse);
1018 }
1019 }
1020
1021 static const unsigned char UTN_USERFirst_Hardware_Serial[][16] = {
1022 { 0xd8, 0xf3, 0x5f, 0x4e, 0xb7, 0x87, 0x2b, 0x2d, 0xab, 0x06, 0x92, 0xe3, 0x15, 0x38, 0x2f, 0xb0 },
1023 { 0x92, 0x39, 0xd5, 0x34, 0x8f, 0x40, 0xd1, 0x69, 0x5a, 0x74, 0x54, 0x70, 0xe1, 0xf2, 0x3f, 0x43 },
1024 { 0xb0, 0xb7, 0x13, 0x3e, 0xd0, 0x96, 0xf9, 0xb5, 0x6f, 0xae, 0x91, 0xc8, 0x74, 0xbd, 0x3a, 0xc0 },
1025 { 0xe9, 0x02, 0x8b, 0x95, 0x78, 0xe4, 0x15, 0xdc, 0x1a, 0x71, 0x0a, 0x2b, 0x88, 0x15, 0x44, 0x47 },
1026 { 0x39, 0x2a, 0x43, 0x4f, 0x0e, 0x07, 0xdf, 0x1f, 0x8a, 0xa3, 0x05, 0xde, 0x34, 0xe0, 0xc2, 0x29 },
1027 { 0x3e, 0x75, 0xce, 0xd4, 0x6b, 0x69, 0x30, 0x21, 0x21, 0x88, 0x30, 0xae, 0x86, 0xa8, 0x2a, 0x71 },
1028 { 0xd7, 0x55, 0x8f, 0xda, 0xf5, 0xf1, 0x10, 0x5b, 0xb2, 0x13, 0x28, 0x2b, 0x70, 0x77, 0x29, 0xa3 },
1029 { 0x04, 0x7e, 0xcb, 0xe9, 0xfc, 0xa5, 0x5f, 0x7b, 0xd0, 0x9e, 0xae, 0x36, 0xe1, 0x0c, 0xae, 0x1e },
1030 { 0xf5, 0xc8, 0x6a, 0xf3, 0x61, 0x62, 0xf1, 0x3a, 0x64, 0xf5, 0x4f, 0x6d, 0xc9, 0x58, 0x7c, 0x06 } };
1031
1032 static const unsigned char UTN_USERFirst_Hardware_Normalized_Issuer[] = {
1033 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55,
1034 0x53, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x02,
1035 0x55, 0x54, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x07, 0x13,
1036 0x0e, 0x53, 0x41, 0x4c, 0x54, 0x20, 0x4c, 0x41, 0x4b, 0x45, 0x20, 0x43,
1037 0x49, 0x54, 0x59, 0x31, 0x1e, 0x30, 0x1c, 0x06, 0x03, 0x55, 0x04, 0x0a,
1038 0x13, 0x15, 0x54, 0x48, 0x45, 0x20, 0x55, 0x53, 0x45, 0x52, 0x54, 0x52,
1039 0x55, 0x53, 0x54, 0x20, 0x4e, 0x45, 0x54, 0x57, 0x4f, 0x52, 0x4b, 0x31,
1040 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x18, 0x48, 0x54,
1041 0x54, 0x50, 0x3a, 0x2f, 0x2f, 0x57, 0x57, 0x57, 0x2e, 0x55, 0x53, 0x45,
1042 0x52, 0x54, 0x52, 0x55, 0x53, 0x54, 0x2e, 0x43, 0x4f, 0x4d, 0x31, 0x1f,
1043 0x30, 0x1d, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x16, 0x55, 0x54, 0x4e,
1044 0x2d, 0x55, 0x53, 0x45, 0x52, 0x46, 0x49, 0x52, 0x53, 0x54, 0x2d, 0x48,
1045 0x41, 0x52, 0x44, 0x57, 0x41, 0x52, 0x45
1046 };
1047 static const unsigned int UTN_USERFirst_Hardware_Normalized_Issuer_len = 151;
1048
1049
1050 static void SecPolicyCheckBlackListedLeaf(SecPVCRef pvc,
1051 CFStringRef key) {
1052 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, 0);
1053 CFDataRef issuer = cert ? SecCertificateGetNormalizedIssuerContent(cert) : NULL;
1054
1055 if (issuer && (CFDataGetLength(issuer) == (CFIndex)UTN_USERFirst_Hardware_Normalized_Issuer_len) &&
1056 (0 == memcmp(UTN_USERFirst_Hardware_Normalized_Issuer, CFDataGetBytePtr(issuer),
1057 UTN_USERFirst_Hardware_Normalized_Issuer_len)))
1058 {
1059 #if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE))
1060 CFDataRef serial = SecCertificateCopySerialNumber(cert, NULL);
1061 #else
1062 CFDataRef serial = SecCertificateCopySerialNumber(cert);
1063 #endif
1064
1065 if (serial) {
1066 CFIndex serial_length = CFDataGetLength(serial);
1067 const uint8_t *serial_ptr = CFDataGetBytePtr(serial);
1068
1069 while ((serial_length > 0) && (*serial_ptr == 0)) {
1070 serial_ptr++;
1071 serial_length--;
1072 }
1073
1074 if (serial_length == (CFIndex)sizeof(*UTN_USERFirst_Hardware_Serial)) {
1075 unsigned int i;
1076 for (i = 0; i < array_size(UTN_USERFirst_Hardware_Serial); i++)
1077 {
1078 if (0 == memcmp(UTN_USERFirst_Hardware_Serial[i],
1079 serial_ptr, sizeof(*UTN_USERFirst_Hardware_Serial)))
1080 {
1081 SecPVCSetResult(pvc, key, 0, kCFBooleanFalse);
1082 CFReleaseSafe(serial);
1083 return;
1084 }
1085 }
1086 }
1087 CFRelease(serial);
1088 }
1089 }
1090
1091 SecOTAPKIRef otapkiRef = SecOTAPKICopyCurrentOTAPKIRef();
1092 if (NULL != otapkiRef)
1093 {
1094 CFSetRef blackListedKeys = SecOTAPKICopyBlackListSet(otapkiRef);
1095 CFRelease(otapkiRef);
1096 if (NULL != blackListedKeys)
1097 {
1098 /* Check for blacklisted intermediates keys. */
1099 CFDataRef dgst = SecCertificateCopyPublicKeySHA1Digest(cert);
1100 if (dgst)
1101 {
1102 /* Check dgst against blacklist. */
1103 if (CFSetContainsValue(blackListedKeys, dgst))
1104 {
1105 SecPVCSetResult(pvc, key, 0, kCFBooleanFalse);
1106 }
1107 CFRelease(dgst);
1108 }
1109 CFRelease(blackListedKeys);
1110 }
1111 }
1112 }
1113
1114 static void SecPolicyCheckGrayListedLeaf(SecPVCRef pvc, CFStringRef key)
1115 {
1116 SecOTAPKIRef otapkiRef = SecOTAPKICopyCurrentOTAPKIRef();
1117 if (NULL != otapkiRef)
1118 {
1119 CFSetRef grayListedKeys = SecOTAPKICopyGrayList(otapkiRef);
1120 CFRelease(otapkiRef);
1121 if (NULL != grayListedKeys)
1122 {
1123 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, 0);
1124
1125 CFDataRef dgst = SecCertificateCopyPublicKeySHA1Digest(cert);
1126 if (dgst)
1127 {
1128 /* Check dgst against gray. */
1129 if (CFSetContainsValue(grayListedKeys, dgst))
1130 {
1131 SecPVCSetResult(pvc, key, 0, kCFBooleanFalse);
1132 }
1133 CFRelease(dgst);
1134 }
1135 CFRelease(grayListedKeys);
1136 }
1137 }
1138 }
1139
1140 static void SecPolicyCheckLeafMarkerOid(SecPVCRef pvc, CFStringRef key)
1141 {
1142 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, 0);
1143 SecPolicyRef policy = SecPVCGetPolicy(pvc);
1144 CFTypeRef value = CFDictionaryGetValue(policy->_options, key);
1145
1146 if (!SecPolicyCheckCertLeafMarkerOid(cert, value)) {
1147 SecPVCSetResult(pvc, key, 0, kCFBooleanFalse);
1148 }
1149 }
1150
1151 static void SecPolicyCheckLeafMarkerOidWithoutValueCheck(SecPVCRef pvc, CFStringRef key)
1152 {
1153 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, 0);
1154 SecPolicyRef policy = SecPVCGetPolicy(pvc);
1155 CFTypeRef value = CFDictionaryGetValue(policy->_options, key);
1156
1157 if (!SecPolicyCheckCertLeafMarkerOidWithoutValueCheck(cert, value)) {
1158 SecPVCSetResult(pvc, key, 0, kCFBooleanFalse);
1159 }
1160 }
1161
1162 /*
1163 * The value is a dictionary. The dictionary contains keys indicating
1164 * whether the value is for Prod or QA. The values are the same as
1165 * in the options dictionary for SecPolicyCheckLeafMarkerOid.
1166 */
1167 static void SecPolicyCheckLeafMarkersProdAndQA(SecPVCRef pvc, CFStringRef key)
1168 {
1169 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, 0);
1170 SecPolicyRef policy = SecPVCGetPolicy(pvc);
1171 CFDictionaryRef value = CFDictionaryGetValue(policy->_options, key);
1172 CFTypeRef prodValue = CFDictionaryGetValue(value, kSecPolicyLeafMarkerProd);
1173
1174 if (!SecPolicyCheckCertLeafMarkerOid(cert, prodValue)) {
1175 bool result = false;
1176 if (!result) {
1177 SecPVCSetResult(pvc, key, 0, kCFBooleanFalse);
1178 }
1179 }
1180 }
1181
1182 static void SecPolicyCheckIntermediateMarkerOid(SecPVCRef pvc, CFStringRef key)
1183 {
1184 CFIndex ix, count = SecPVCGetCertificateCount(pvc);
1185 SecPolicyRef policy = SecPVCGetPolicy(pvc);
1186 CFTypeRef value = CFDictionaryGetValue(policy->_options, key);
1187
1188 for (ix = 1; ix < count - 1; ix++) {
1189 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix);
1190 if (SecCertificateHasMarkerExtension(cert, value))
1191 return;
1192 }
1193 SecPVCSetResult(pvc, key, 0, kCFBooleanFalse);
1194 }
1195
1196 static void SecPolicyCheckIntermediateEKU(SecPVCRef pvc, CFStringRef key)
1197 {
1198 CFIndex ix, count = SecPVCGetCertificateCount(pvc);
1199 SecPolicyRef policy = SecPVCGetPolicy(pvc);
1200 CFTypeRef peku = CFDictionaryGetValue(policy->_options, key);
1201
1202 for (ix = 1; ix < count - 1; ix++) {
1203 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix);
1204 if (!SecPolicyCheckCertExtendedKeyUsage(cert, peku)) {
1205 SecPVCSetResult(pvc, key, ix, kCFBooleanFalse);
1206 }
1207 }
1208 }
1209
1210 static void SecPolicyCheckIntermediateOrganization(SecPVCRef pvc, CFStringRef key)
1211 {
1212 CFIndex ix, count = SecPVCGetCertificateCount(pvc);
1213 SecPolicyRef policy = SecPVCGetPolicy(pvc);
1214 CFTypeRef organization = CFDictionaryGetValue(policy->_options, key);
1215
1216 for (ix = 1; ix < count - 1; ix++) {
1217 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix);
1218 if (!SecPolicyCheckCertSubjectOrganization(cert, organization)) {
1219 SecPVCSetResult(pvc, key, ix, kCFBooleanFalse);
1220 }
1221 }
1222 }
1223
1224 static void SecPolicyCheckIntermediateCountry(SecPVCRef pvc, CFStringRef key)
1225 {
1226 CFIndex ix, count = SecPVCGetCertificateCount(pvc);
1227 SecPolicyRef policy = SecPVCGetPolicy(pvc);
1228 CFTypeRef country = CFDictionaryGetValue(policy->_options, key);
1229
1230 for (ix = 1; ix < count - 1; ix++) {
1231 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix);
1232 if (!SecPolicyCheckCertSubjectCountry(cert, country)) {
1233 SecPVCSetResult(pvc, key, ix, kCFBooleanFalse);
1234 }
1235 }
1236 }
1237
1238 /* Returns true if path is on the allow list for the authority key of the
1239 certificate at certix, false otherwise.
1240 */
1241 static bool SecPVCCheckCertificateAllowList(SecPVCRef pvc, CFIndex certix)
1242 {
1243 bool result = false;
1244 CFIndex ix = 0, count = SecPVCGetCertificateCount(pvc);
1245 CFStringRef authKey = NULL;
1246 CFArrayRef allowedCerts = NULL;
1247 SecOTAPKIRef otapkiRef = NULL;
1248
1249 if (certix < 0 || certix >= count) {
1250 return result;
1251 }
1252
1253 //get authKeyID from the specified cert in the chain
1254 SecCertificateRef issuedCert = SecPVCGetCertificateAtIndex(pvc, certix);
1255 CFDataRef authKeyID = SecCertificateGetAuthorityKeyID(issuedCert);
1256 if (NULL == authKeyID) {
1257 return result;
1258 }
1259 authKey = CFDataCopyHexString(authKeyID);
1260 if (NULL == authKey) {
1261 goto errout;
1262 }
1263
1264 otapkiRef = SecOTAPKICopyCurrentOTAPKIRef();
1265 if (NULL == otapkiRef) {
1266 goto errout;
1267 }
1268
1269 allowedCerts = SecOTAPKICopyAllowListForAuthKeyID(otapkiRef, authKey);
1270 if (NULL == allowedCerts || !CFArrayGetCount(allowedCerts)) {
1271 goto errout;
1272 }
1273
1274 //search sorted array for the SHA256 hash of a cert in the chain
1275 CFRange range = CFRangeMake(0, CFArrayGetCount(allowedCerts));
1276 for (ix = 0; ix <= certix; ix++) {
1277 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix);
1278 if (!cert) {
1279 goto errout;
1280 }
1281
1282 CFDataRef certHash = SecCertificateCopySHA256Digest(cert);
1283 if (!certHash) {
1284 goto errout;
1285 }
1286
1287 CFIndex position = CFArrayBSearchValues(allowedCerts, range, certHash,
1288 (CFComparatorFunction)CFDataCompare, NULL);
1289 if (position < CFArrayGetCount(allowedCerts)) {
1290 CFDataRef possibleMatch = CFArrayGetValueAtIndex(allowedCerts, position);
1291 if (!CFDataCompare(certHash, possibleMatch)) {
1292 //this cert is in the allowlist
1293 result = true;
1294 }
1295 }
1296
1297 CFRelease(certHash);
1298 }
1299
1300 errout:
1301 CFReleaseNull(authKey);
1302 CFReleaseNull(otapkiRef);
1303 CFReleaseNull(allowedCerts);
1304 return result;
1305 }
1306
1307 #define DCMP(_idx_) memcmp(data+(8*_idx_), digest, 8)
1308
1309 /* Returns true if leaf is on the CT whitelist */
1310 static bool SecPVCCheckCTWhiteListedLeaf(SecPVCRef pvc)
1311 {
1312 SecOTAPKIRef otapkiRef = NULL;
1313 CFDataRef whiteList = NULL;
1314 SecCertificateRef cert = NULL;
1315 CFDataRef dgst = NULL;
1316 bool result = false;
1317 const uint8_t *digest = NULL;
1318 const uint8_t *data = NULL;
1319 require(otapkiRef = SecOTAPKICopyCurrentOTAPKIRef(), out);
1320 require(whiteList = SecOTAPKICopyCTWhiteList(otapkiRef), out);
1321 require(cert = SecPVCGetCertificateAtIndex(pvc, 0), out);
1322 require(dgst = SecCertificateCopySHA256Digest(cert), out);
1323
1324 digest = CFDataGetBytePtr(dgst);
1325 data = CFDataGetBytePtr(whiteList);
1326 CFIndex l = 0;
1327 CFIndex h = CFDataGetLength(whiteList)/8-1;
1328
1329 if(DCMP(l)==0 || DCMP(h)==0) {
1330 result = true;
1331 goto out;
1332 }
1333
1334 if(DCMP(l)>0 || DCMP(h)<0) {
1335 goto out;
1336 }
1337
1338 while((h-l)>1) {
1339 CFIndex i = (h+l)/
1340 2;
1341 int s = DCMP(i);
1342 if(s == 0) {
1343 result = true;
1344 goto out;
1345 } else if(s < 0) {
1346 l = i;
1347 } else {
1348 h = i;
1349 }
1350 }
1351
1352 out:
1353 CFReleaseSafe(dgst);
1354 CFReleaseSafe(whiteList);
1355 CFReleaseSafe(otapkiRef);
1356 return result;
1357 }
1358
1359 /****************************************************************************
1360 *********************** New rfc5280 Chain Validation ***********************
1361 ****************************************************************************/
1362
1363 #define POLICY_MAPPING 1
1364 #define POLICY_SUBTREES 1
1365
1366 struct policy_tree_add_ctx {
1367 oid_t p_oid;
1368 policy_qualifier_t p_q;
1369 };
1370
1371 /* For each node of depth i-1 in the valid_policy_tree where P-OID is in the expected_policy_set, create a child node as follows: set the valid_policy to P-OID, set the qualifier_set to P-Q, and set the expected_policy_set to {P-OID}. */
1372 static bool policy_tree_add_if_match(policy_tree_t node, void *ctx) {
1373 struct policy_tree_add_ctx *info = (struct policy_tree_add_ctx *)ctx;
1374 policy_set_t policy_set;
1375 for (policy_set = node->expected_policy_set;
1376 policy_set;
1377 policy_set = policy_set->oid_next) {
1378 if (oid_equal(policy_set->oid, info->p_oid)) {
1379 policy_tree_add_child(node, &info->p_oid, info->p_q);
1380 return true;
1381 }
1382 }
1383 return false;
1384 }
1385
1386 /* If the valid_policy_tree includes a node of depth i-1 with the valid_policy anyPolicy, generate a child node with the following values: set the valid_policy to P-OID, set the qualifier_set to P-Q, and set the expected_policy_set to {P-OID}. */
1387 static bool policy_tree_add_if_any(policy_tree_t node, void *ctx) {
1388 struct policy_tree_add_ctx *info = (struct policy_tree_add_ctx *)ctx;
1389 if (oid_equal(node->valid_policy, oidAnyPolicy)) {
1390 policy_tree_add_child(node, &info->p_oid, info->p_q);
1391 return true;
1392 }
1393 return false;
1394 }
1395
1396 /* Return true iff node has a child with a valid_policy equal to oid. */
1397 static bool policy_tree_has_child_with_oid(policy_tree_t node,
1398 const oid_t *oid) {
1399 policy_tree_t child;
1400 for (child = node->children; child; child = child->siblings) {
1401 if (oid_equal(child->valid_policy, (*oid))) {
1402 return true;
1403 }
1404 }
1405 return false;
1406 }
1407
1408 /* For each node in the valid_policy_tree of depth i-1, for each value in the expected_policy_set (including anyPolicy) that does not appear in a child node, create a child node with the following values: set the valid_policy to the value from the expected_policy_set in the parent node, set the qualifier_set to AP-Q, and set the expected_policy_set to the value in the valid_policy from this node. */
1409 static bool policy_tree_add_expected(policy_tree_t node, void *ctx) {
1410 policy_qualifier_t p_q = (policy_qualifier_t)ctx;
1411 policy_set_t policy_set;
1412 bool added_node = false;
1413 for (policy_set = node->expected_policy_set;
1414 policy_set;
1415 policy_set = policy_set->oid_next) {
1416 if (!policy_tree_has_child_with_oid(node, &policy_set->oid)) {
1417 policy_tree_add_child(node, &policy_set->oid, p_q);
1418 added_node = true;
1419 }
1420 }
1421 return added_node;
1422 }
1423
1424 #if POLICY_MAPPING
1425 /* For each node where ID-P is the valid_policy, set expected_policy_set to the set of subjectDomainPolicy values that are specified as equivalent to ID-P by the policy mappings extension. */
1426 static bool policy_tree_map_if_match(policy_tree_t node, void *ctx) {
1427 /* Can't map oidAnyPolicy. */
1428 if (oid_equal(node->valid_policy, oidAnyPolicy))
1429 return false;
1430
1431 const SecCEPolicyMappings *pm = (const SecCEPolicyMappings *)ctx;
1432 size_t mapping_ix, mapping_count = pm->numMappings;
1433 policy_set_t policy_set = NULL;
1434 /* Generate the policy_set of sdps for matching idp */
1435 for (mapping_ix = 0; mapping_ix < mapping_count; ++mapping_ix) {
1436 const SecCEPolicyMapping *mapping = &pm->mappings[mapping_ix];
1437 if (oid_equal(node->valid_policy, mapping->issuerDomainPolicy)) {
1438 policy_set_t p_node = (policy_set_t)malloc(sizeof(*policy_set));
1439 p_node->oid = mapping->subjectDomainPolicy;
1440 p_node->oid_next = policy_set ? policy_set : NULL;
1441 policy_set = p_node;
1442 }
1443 }
1444 if (policy_set) {
1445 policy_tree_set_expected_policy(node, policy_set);
1446 return true;
1447 }
1448 return false;
1449 }
1450
1451 /* If no node of depth i in the valid_policy_tree has a valid_policy of ID-P but there is a node of depth i with a valid_policy of anyPolicy, then generate a child node of the node of depth i-1 that has a valid_policy of anyPolicy as follows:
1452 (i) set the valid_policy to ID-P;
1453 (ii) set the qualifier_set to the qualifier set of the policy anyPolicy in the certificate policies extension of certificate i; and
1454 (iii) set the expected_policy_set to the set of subjectDomainPolicy values that are specified as equivalent to ID-P by the policy mappings extension. */
1455 static bool policy_tree_map_if_any(policy_tree_t node, void *ctx) {
1456 if (!oid_equal(node->valid_policy, oidAnyPolicy)) {
1457 return false;
1458 }
1459
1460 const SecCEPolicyMappings *pm = (const SecCEPolicyMappings *)ctx;
1461 size_t mapping_ix, mapping_count = pm->numMappings;
1462 CFMutableDictionaryRef mappings = NULL;
1463 CFDataRef idp = NULL;
1464 CFDataRef sdp = NULL;
1465 require_quiet(mappings = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks,
1466 &kCFTypeDictionaryValueCallBacks),
1467 errOut);
1468 /* First we need to walk the mappings to generate the dictionary idp->sdps */
1469 for (mapping_ix = 0; mapping_ix < mapping_count; mapping_ix++) {
1470 oid_t issuerDomainPolicy = pm->mappings[mapping_ix].issuerDomainPolicy;
1471 oid_t subjectDomainPolicy = pm->mappings[mapping_ix].subjectDomainPolicy;
1472 idp = CFDataCreateWithBytesNoCopy(NULL, issuerDomainPolicy.data, issuerDomainPolicy.length, kCFAllocatorNull);
1473 sdp = CFDataCreateWithBytesNoCopy(NULL, subjectDomainPolicy.data, subjectDomainPolicy.length, kCFAllocatorNull);
1474 CFMutableArrayRef sdps = (CFMutableArrayRef)CFDictionaryGetValue(mappings, idp);
1475 if (sdps) {
1476 CFArrayAppendValue(sdps, sdp);
1477 } else {
1478 require_quiet(sdps = CFArrayCreateMutable(kCFAllocatorDefault, 0,
1479 &kCFTypeArrayCallBacks), errOut);
1480 CFArrayAppendValue(sdps, sdp);
1481 CFDictionarySetValue(mappings, idp, sdps);
1482 CFRelease(sdps);
1483 }
1484 CFReleaseNull(idp);
1485 CFReleaseNull(sdp);
1486 }
1487
1488 /* Now we use the dictionary to generate the new nodes */
1489 CFDictionaryForEach(mappings, ^(const void *key, const void *value) {
1490 CFDataRef idp = key;
1491 CFArrayRef sdps = value;
1492
1493 /* (i) set the valid_policy to ID-P; */
1494 oid_t p_oid;
1495 p_oid.data = (uint8_t *)CFDataGetBytePtr(idp);
1496 p_oid.length = CFDataGetLength(idp);
1497
1498 /* (ii) set the qualifier_set to the qualifier set of the policy anyPolicy in the certificate policies extension of certificate i */
1499 policy_qualifier_t p_q = node->qualifier_set;
1500
1501 /* (iii) set the expected_policy_set to the set of subjectDomainPolicy values that are specified as equivalent to ID-P by the policy mappings extension. */
1502 __block policy_set_t p_expected = NULL;
1503 CFArrayForEach(sdps, ^(const void *value) {
1504 policy_set_t p_node = (policy_set_t)malloc(sizeof(*p_expected));
1505 p_node->oid.data = (void *)CFDataGetBytePtr(value);
1506 p_node->oid.length = CFDataGetLength(value);
1507 p_node->oid_next = p_expected ? p_expected : NULL;
1508 p_expected = p_node;
1509 });
1510
1511 policy_tree_add_sibling(node, &p_oid, p_q, p_expected);
1512 });
1513 CFReleaseNull(mappings);
1514 return true;
1515
1516 errOut:
1517 CFReleaseNull(mappings);
1518 CFReleaseNull(idp);
1519 CFReleaseNull(sdp);
1520 return false;
1521 }
1522
1523 static bool policy_tree_map_delete_if_match(policy_tree_t node, void *ctx) {
1524 /* Can't map oidAnyPolicy. */
1525 if (oid_equal(node->valid_policy, oidAnyPolicy))
1526 return false;
1527
1528 const SecCEPolicyMappings *pm = (const SecCEPolicyMappings *)ctx;
1529 size_t mapping_ix, mapping_count = pm->numMappings;
1530 /* If this node matches any of the idps, delete it. */
1531 for (mapping_ix = 0; mapping_ix < mapping_count; ++mapping_ix) {
1532 const SecCEPolicyMapping *mapping = &pm->mappings[mapping_ix];
1533 if (oid_equal(node->valid_policy, mapping->issuerDomainPolicy)) {
1534 policy_tree_remove_node(&node);
1535 break;
1536 }
1537 }
1538 return true;
1539 }
1540 #endif /* POLICY_MAPPINGS */
1541
1542 /* rfc5280 basic cert processing. */
1543 static void SecPolicyCheckBasicCertificateProcessing(SecPVCRef pvc,
1544 CFStringRef key) {
1545 /* Inputs */
1546 //cert_path_t path;
1547 CFIndex count = SecPVCGetCertificateCount(pvc);
1548 /* 64 bits cast: worst case here is we truncate the number of cert, and the validation may fail */
1549 assert((unsigned long)count<=UINT32_MAX); /* Debug check. Correct as long as CFIndex is long */
1550 uint32_t n = (uint32_t)count;
1551 bool is_anchored = SecPVCIsAnchored(pvc);
1552 if (is_anchored) {
1553 /* If the anchor is trusted we don't process the last cert in the
1554 chain (root). */
1555 n--;
1556 } else {
1557 /* trust may be restored for a path with an untrusted root that matches the allow list */
1558 pvc->is_allowlisted = SecPVCCheckCertificateAllowList(pvc, n - 1);
1559 if (!pvc->is_allowlisted) {
1560 /* Add a detail for the root not being trusted. */
1561 if (!SecPVCSetResultForced(pvc, kSecPolicyCheckAnchorTrusted,
1562 n - 1, kCFBooleanFalse, true))
1563 return;
1564 }
1565 }
1566
1567 CFAbsoluteTime verify_time = SecPVCGetVerifyTime(pvc);
1568 //policy_set_t user_initial_policy_set = NULL;
1569 //trust_anchor_t anchor;
1570 bool initial_policy_mapping_inhibit = false;
1571 bool initial_explicit_policy = false;
1572 bool initial_any_policy_inhibit = false;
1573
1574 /* Initialization */
1575 pvc->valid_policy_tree = policy_tree_create(&oidAnyPolicy, NULL);
1576 #if POLICY_SUBTREES
1577 CFMutableArrayRef permitted_subtrees = NULL;
1578 CFMutableArrayRef excluded_subtrees = NULL;
1579 permitted_subtrees = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
1580 excluded_subtrees = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
1581 require_action_quiet(permitted_subtrees != NULL, errOut,
1582 SecPVCSetResultForced(pvc, key, 0, kCFBooleanFalse, true));
1583 require_action_quiet(excluded_subtrees != NULL, errOut,
1584 SecPVCSetResultForced(pvc, key, 0, kCFBooleanFalse, true));
1585 #endif
1586 uint32_t explicit_policy = initial_explicit_policy ? 0 : n + 1;
1587 uint32_t inhibit_any_policy = initial_any_policy_inhibit ? 0 : n + 1;
1588 uint32_t policy_mapping = initial_policy_mapping_inhibit ? 0 : n + 1;
1589
1590 #if 0
1591 /* Path builder ensures we only get cert chains with proper issuer
1592 chaining with valid signatures along the way. */
1593 algorithm_id_t working_public_key_algorithm = anchor->public_key_algorithm;
1594 SecKeyRef working_public_key = anchor->public_key;
1595 x500_name_t working_issuer_name = anchor->issuer_name;
1596 #endif
1597 uint32_t i, max_path_length = n;
1598 SecCertificateRef cert = NULL;
1599 for (i = 1; i <= n; ++i) {
1600 /* Process Cert */
1601 cert = SecPVCGetCertificateAtIndex(pvc, n - i);
1602 bool is_self_issued = SecPVCIsCertificateAtIndexSelfIssued(pvc, n - i);
1603
1604 /* (a) Verify the basic certificate information. */
1605 /* @@@ Ensure that cert was signed with working_public_key_algorithm
1606 using the working_public_key and the working_public_key_parameters. */
1607 #if 1
1608 /* Already done by chain builder. */
1609 if (!SecCertificateIsValid(cert, verify_time)) {
1610 CFStringRef fail_key = i == n ? kSecPolicyCheckValidLeaf : kSecPolicyCheckValidIntermediates;
1611 if (!SecPVCSetResult(pvc, fail_key, n - i, kCFBooleanFalse)) {
1612 goto errOut;
1613 }
1614 }
1615 if (SecCertificateIsWeakKey(cert)) {
1616 CFStringRef fail_key = i == n ? kSecPolicyCheckWeakLeaf : kSecPolicyCheckWeakIntermediates;
1617 if (!SecPVCSetResult(pvc, fail_key, n - i, kCFBooleanFalse)) {
1618 goto errOut;
1619 }
1620 }
1621 #endif
1622 /* @@@ cert.issuer == working_issuer_name. */
1623
1624 #if POLICY_SUBTREES
1625 /* (b) (c) */
1626 if (!is_self_issued || i == n) {
1627 bool found = false;
1628 /* Verify certificate Subject Name and SubjectAltNames are not within any of the excluded_subtrees */
1629 if(excluded_subtrees && CFArrayGetCount(excluded_subtrees)) {
1630 if ((errSecSuccess != SecNameContraintsMatchSubtrees(cert, excluded_subtrees, &found, false)) || found) {
1631 secnotice("policy", "name in excluded subtrees");
1632 if(!SecPVCSetResultForced(pvc, key, n - i, kCFBooleanFalse, true)) { goto errOut; }
1633 }
1634 }
1635 /* Verify certificate Subject Name and SubjectAltNames are within the permitted_subtrees */
1636 if(permitted_subtrees && CFArrayGetCount(permitted_subtrees)) {
1637 if ((errSecSuccess != SecNameContraintsMatchSubtrees(cert, permitted_subtrees, &found, true)) || !found) {
1638 secnotice("policy", "name not in permitted subtrees");
1639 if(!SecPVCSetResultForced(pvc, key, n - i, kCFBooleanFalse, true)) { goto errOut; }
1640 }
1641 }
1642 }
1643 #endif
1644 /* (d) */
1645 if (pvc->valid_policy_tree) {
1646 const SecCECertificatePolicies *cp =
1647 SecCertificateGetCertificatePolicies(cert);
1648 size_t policy_ix, policy_count = cp ? cp->numPolicies : 0;
1649 for (policy_ix = 0; policy_ix < policy_count; ++policy_ix) {
1650 const SecCEPolicyInformation *policy = &cp->policies[policy_ix];
1651 oid_t p_oid = policy->policyIdentifier;
1652 policy_qualifier_t p_q = &policy->policyQualifiers;
1653 struct policy_tree_add_ctx ctx = { p_oid, p_q };
1654 if (!oid_equal(p_oid, oidAnyPolicy)) {
1655 if (!policy_tree_walk_depth(pvc->valid_policy_tree, i - 1,
1656 policy_tree_add_if_match, &ctx)) {
1657 policy_tree_walk_depth(pvc->valid_policy_tree, i - 1,
1658 policy_tree_add_if_any, &ctx);
1659 }
1660 }
1661 }
1662 /* The certificate policies extension includes the policy
1663 anyPolicy with the qualifier set AP-Q and either
1664 (a) inhibit_anyPolicy is greater than 0 or
1665 (b) i < n and the certificate is self-issued. */
1666 if (inhibit_any_policy > 0 || (i < n && is_self_issued)) {
1667 for (policy_ix = 0; policy_ix < policy_count; ++policy_ix) {
1668 const SecCEPolicyInformation *policy = &cp->policies[policy_ix];
1669 oid_t p_oid = policy->policyIdentifier;
1670 policy_qualifier_t p_q = &policy->policyQualifiers;
1671 if (oid_equal(p_oid, oidAnyPolicy)) {
1672 policy_tree_walk_depth(pvc->valid_policy_tree, i - 1,
1673 policy_tree_add_expected, (void *)p_q);
1674 }
1675 }
1676 }
1677 policy_tree_prune_childless(&pvc->valid_policy_tree, i - 1);
1678 /* (e) */
1679 if (!cp) {
1680 if (pvc->valid_policy_tree)
1681 policy_tree_prune(&pvc->valid_policy_tree);
1682 }
1683 }
1684 /* (f) Verify that either explicit_policy is greater than 0 or the
1685 valid_policy_tree is not equal to NULL. */
1686 if (!pvc->valid_policy_tree && explicit_policy == 0) {
1687 /* valid_policy_tree is empty and explicit policy is 0, illegal. */
1688 secnotice("policy", "policy tree failure");
1689 if (!SecPVCSetResultForced(pvc, key /* @@@ Need custom key */, n - i, kCFBooleanFalse, true)) {
1690 goto errOut;
1691 }
1692 }
1693 /* If Last Cert in Path */
1694 if (i == n)
1695 break;
1696
1697 /* Prepare for Next Cert */
1698 #if POLICY_MAPPING
1699 /* (a) verify that anyPolicy does not appear as an
1700 issuerDomainPolicy or a subjectDomainPolicy */
1701 const SecCEPolicyMappings *pm = SecCertificateGetPolicyMappings(cert);
1702 if (pm && pm->present) {
1703 size_t mapping_ix, mapping_count = pm->numMappings;
1704 for (mapping_ix = 0; mapping_ix < mapping_count; ++mapping_ix) {
1705 const SecCEPolicyMapping *mapping = &pm->mappings[mapping_ix];
1706 if (oid_equal(mapping->issuerDomainPolicy, oidAnyPolicy)
1707 || oid_equal(mapping->subjectDomainPolicy, oidAnyPolicy)) {
1708 /* Policy mapping uses anyPolicy, illegal. */
1709 if (!SecPVCSetResultForced(pvc, key /* @@@ Need custom key */, n - i, kCFBooleanFalse, true)) {
1710 goto errOut;
1711 }
1712 }
1713 }
1714
1715 /* (b) */
1716 /* (1) If the policy_mapping variable is greater than 0 */
1717 if (policy_mapping > 0 && pvc->valid_policy_tree) {
1718 if (!policy_tree_walk_depth(pvc->valid_policy_tree, i,
1719 policy_tree_map_if_match, (void *)pm)) {
1720 /* If no node of depth i in the valid_policy_tree has a valid_policy of ID-P but there is a node of depth i with a valid_policy of anyPolicy, then generate a child node of the node of depth i-1. */
1721 policy_tree_walk_depth(pvc->valid_policy_tree, i, policy_tree_map_if_any, (void *)pm);
1722 }
1723 } else if (pvc->valid_policy_tree) {
1724 /* (i) delete each node of depth i in the valid_policy_tree
1725 where ID-P is the valid_policy. */
1726 policy_tree_walk_depth(pvc->valid_policy_tree, i,
1727 policy_tree_map_delete_if_match, (void *)pm);
1728 /* (ii) If there is a node in the valid_policy_tree of depth
1729 i-1 or less without any child nodes, delete that
1730 node. Repeat this step until there are no nodes of
1731 depth i-1 or less without children. */
1732 policy_tree_prune_childless(&pvc->valid_policy_tree, i - 1);
1733 }
1734 }
1735 #endif /* POLICY_MAPPING */
1736 /* (c)(d)(e)(f) */
1737 //working_issuer_name = SecCertificateGetNormalizedSubjectContent(cert);
1738 //working_public_key = SecCertificateCopyPublicKey(cert);
1739 //working_public_key_parameters = SecCertificateCopyPublicKeyParameters(cert);
1740 //working_public_key_algorithm = SecCertificateCopyPublicKeyAlgorithm(cert);
1741 #if POLICY_SUBTREES
1742 /* (g) If a name constraints extension is included in the certificate, modify the permitted_subtrees and excluded_subtrees state variables.
1743 */
1744 CFArrayRef permitted_subtrees_in_cert = SecCertificateGetPermittedSubtrees(cert);
1745 if (permitted_subtrees_in_cert) {
1746 SecNameConstraintsIntersectSubtrees(permitted_subtrees, permitted_subtrees_in_cert);
1747 }
1748
1749 // could do something smart here to avoid inserting the exact same constraint
1750 CFArrayRef excluded_subtrees_in_cert = SecCertificateGetExcludedSubtrees(cert);
1751 if (excluded_subtrees_in_cert) {
1752 CFIndex num_trees = CFArrayGetCount(excluded_subtrees_in_cert);
1753 CFRange range = { 0, num_trees };
1754 CFArrayAppendArray(excluded_subtrees, excluded_subtrees_in_cert, range);
1755 }
1756 #endif
1757 /* (h) */
1758 if (!is_self_issued) {
1759 if (explicit_policy)
1760 explicit_policy--;
1761 if (policy_mapping)
1762 policy_mapping--;
1763 if (inhibit_any_policy)
1764 inhibit_any_policy--;
1765 }
1766 /* (i) */
1767 const SecCEPolicyConstraints *pc =
1768 SecCertificateGetPolicyConstraints(cert);
1769 if (pc) {
1770 if (pc->requireExplicitPolicyPresent
1771 && pc->requireExplicitPolicy < explicit_policy) {
1772 explicit_policy = pc->requireExplicitPolicy;
1773 }
1774 if (pc->inhibitPolicyMappingPresent
1775 && pc->inhibitPolicyMapping < policy_mapping) {
1776 policy_mapping = pc->inhibitPolicyMapping;
1777 }
1778 }
1779 /* (j) */
1780 const SecCEInhibitAnyPolicy *iap = SecCertificateGetInhibitAnyPolicySkipCerts(cert);
1781 if (iap && iap->skipCerts < inhibit_any_policy) {
1782 inhibit_any_policy = iap->skipCerts;
1783 }
1784 /* (k) */
1785 const SecCEBasicConstraints *bc =
1786 SecCertificateGetBasicConstraints(cert);
1787 #if 0 /* Checked in chain builder pre signature verify already. */
1788 if (!bc || !bc->isCA) {
1789 /* Basic constraints not present or not marked as isCA, illegal. */
1790 if (!SecPVCSetResult(pvc, kSecPolicyCheckBasicConstraints,
1791 n - i, kCFBooleanFalse)) {
1792 goto errOut;
1793 }
1794 }
1795 #endif
1796 /* (l) */
1797 if (!is_self_issued) {
1798 if (max_path_length > 0) {
1799 max_path_length--;
1800 } else {
1801 /* max_path_len exceeded, illegal. */
1802 if (!SecPVCSetResult(pvc, kSecPolicyCheckBasicConstraints,
1803 n - i, kCFBooleanFalse)) {
1804 goto errOut;
1805 }
1806 }
1807 }
1808 /* (m) */
1809 if (bc && bc->pathLenConstraintPresent
1810 && bc->pathLenConstraint < max_path_length) {
1811 max_path_length = bc->pathLenConstraint;
1812 }
1813 #if 0 /* Checked in chain builder pre signature verify already. */
1814 /* (n) If a key usage extension is present, verify that the keyCertSign bit is set. */
1815 SecKeyUsage keyUsage = SecCertificateGetKeyUsage(cert);
1816 if (keyUsage && !(keyUsage & kSecKeyUsageKeyCertSign)) {
1817 if (!SecPVCSetResultForced(pvc, kSecPolicyCheckKeyUsage,
1818 n - i, kCFBooleanFalse, true)) {
1819 goto errOut;
1820 }
1821 }
1822 #endif
1823 /* (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. */
1824 if (SecCertificateHasUnknownCriticalExtension(cert)) {
1825 /* Certificate contains one or more unknown critical extensions. */
1826 if (!SecPVCSetResult(pvc, kSecPolicyCheckCriticalExtensions,
1827 n - i, kCFBooleanFalse)) {
1828 goto errOut;
1829 }
1830 }
1831 } /* end loop over certs in path */
1832 /* Wrap up */
1833 cert = SecPVCGetCertificateAtIndex(pvc, 0);
1834 /* (a) */
1835 if (explicit_policy)
1836 explicit_policy--;
1837 /* (b) */
1838 const SecCEPolicyConstraints *pc = SecCertificateGetPolicyConstraints(cert);
1839 if (pc) {
1840 if (pc->requireExplicitPolicyPresent
1841 && pc->requireExplicitPolicy == 0) {
1842 explicit_policy = 0;
1843 }
1844 }
1845 /* (c) */
1846 //working_public_key = SecCertificateCopyPublicKey(cert);
1847 /* (d) */
1848 /* 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
1849 working_public_key_algorithm are different, set the working_public_key_parameters to null. */
1850 //working_public_key_parameters = SecCertificateCopyPublicKeyParameters(cert);
1851 /* (e) */
1852 //working_public_key_algorithm = SecCertificateCopyPublicKeyAlgorithm(cert);
1853 /* (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. */
1854 if (SecCertificateHasUnknownCriticalExtension(cert)) {
1855 /* Certificate contains one or more unknown critical extensions. */
1856 if (!SecPVCSetResult(pvc, kSecPolicyCheckCriticalExtensions,
1857 0, kCFBooleanFalse)) {
1858 goto errOut;
1859 }
1860 }
1861 /* (g) Calculate the intersection of the valid_policy_tree and the user-initial-policy-set, as follows */
1862
1863 if (pvc->valid_policy_tree) {
1864 #if !defined(NDEBUG)
1865 policy_tree_dump(pvc->valid_policy_tree);
1866 #endif
1867 /* (g3c4) */
1868 //policy_tree_prune_childless(&pvc->valid_policy_tree, n - 1);
1869 }
1870
1871 /* If either (1) the value of explicit_policy variable is greater than
1872 zero or (2) the valid_policy_tree is not NULL, then path processing
1873 has succeeded. */
1874 if (!pvc->valid_policy_tree && explicit_policy == 0) {
1875 /* valid_policy_tree is empty and explicit policy is 0, illegal. */
1876 secnotice("policy", "policy tree failure");
1877 if (!SecPVCSetResultForced(pvc, key /* @@@ Need custom key */, 0, kCFBooleanFalse, true)) {
1878 goto errOut;
1879 }
1880 }
1881
1882 errOut:
1883 CFReleaseNull(permitted_subtrees);
1884 CFReleaseNull(excluded_subtrees);
1885 }
1886
1887 static policy_set_t policies_for_cert(SecCertificateRef cert) {
1888 policy_set_t policies = NULL;
1889 const SecCECertificatePolicies *cp =
1890 SecCertificateGetCertificatePolicies(cert);
1891 size_t policy_ix, policy_count = cp ? cp->numPolicies : 0;
1892 for (policy_ix = 0; policy_ix < policy_count; ++policy_ix) {
1893 policy_set_add(&policies, &cp->policies[policy_ix].policyIdentifier);
1894 }
1895 return policies;
1896 }
1897
1898 static void SecPolicyCheckEV(SecPVCRef pvc,
1899 CFStringRef key) {
1900 CFIndex ix, count = SecPVCGetCertificateCount(pvc);
1901 policy_set_t valid_policies = NULL;
1902
1903 /* 6.1.7. Key Usage Purposes */
1904 if (count) {
1905 CFAbsoluteTime jul2016 = 489024000;
1906 SecCertificateRef leaf = SecPVCGetCertificateAtIndex(pvc, 0);
1907 if (SecCertificateNotValidBefore(leaf) > jul2016 && count < 3) {
1908 /* Root CAs may not sign subscriber certificates after 30 June 2016. */
1909 if (SecPVCSetResultForced(pvc, key,
1910 0, kCFBooleanFalse, true)) {
1911 return;
1912 }
1913 }
1914 }
1915
1916 for (ix = 0; ix < count; ++ix) {
1917 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix);
1918 policy_set_t policies = policies_for_cert(cert);
1919 if (ix == 0) {
1920 /* Subscriber */
1921 /* anyPolicy in the leaf isn't allowed for EV, so only init
1922 valid_policies if we have real policies. */
1923 if (!policy_set_contains(policies, &oidAnyPolicy)) {
1924 valid_policies = policies;
1925 policies = NULL;
1926 }
1927 } else if (ix < count - 1) {
1928 /* Subordinate CA */
1929 if (!SecPolicySubordinateCACertificateCouldBeEV(cert)) {
1930 secnotice("ev", "subordinate certificate is not ev");
1931 if (SecPVCSetResultForced(pvc, key,
1932 ix, kCFBooleanFalse, true)) {
1933 policy_set_free(valid_policies);
1934 policy_set_free(policies);
1935 return;
1936 }
1937 }
1938 policy_set_intersect(&valid_policies, policies);
1939 } else {
1940 /* Root CA */
1941 if (!SecPolicyRootCACertificateIsEV(cert, valid_policies)) {
1942 secnotice("ev", "anchor certificate is not ev");
1943 if (SecPVCSetResultForced(pvc, key,
1944 ix, kCFBooleanFalse, true)) {
1945 policy_set_free(valid_policies);
1946 policy_set_free(policies);
1947 return;
1948 }
1949 }
1950 }
1951 policy_set_free(policies);
1952 if (!valid_policies) {
1953 secnotice("ev", "valid_policies set is empty: chain not ev");
1954 /* If we ever get into a state where no policies are valid anymore
1955 this can't be an ev chain. */
1956 if (SecPVCSetResultForced(pvc, key,
1957 ix, kCFBooleanFalse, true)) {
1958 return;
1959 }
1960 }
1961 }
1962
1963 policy_set_free(valid_policies);
1964
1965 /* (a) EV Subscriber Certificates Each EV Certificate issued by the CA to a
1966 Subscriber MUST contain an OID defined by the CA in the certificate’s
1967 certificatePolicies extension that: (i) indicates which CA policy statement relates
1968 to that certificate, (ii) asserts the CA’s adherence to and compliance with these
1969 Guidelines, and (iii), by pre-agreement with the Application Software Vendor,
1970 marks the certificate as being an EV Certificate.
1971 (b) EV Subordinate CA Certificates
1972 (1) Certificates issued to Subordinate CAs that are not controlled by the issuing
1973 CA MUST contain one or more OIDs defined by the issuing CA that
1974 explicitly identify the EV Policies that are implemented by the Subordinate
1975 CA;
1976 (2) Certificates issued to Subordinate CAs that are controlled by the Root CA
1977 MAY contain the special anyPolicy OID (2.5.29.32.0).
1978 (c) Root CA Certificates Root CA Certificates SHOULD NOT contain the
1979 certificatePolicies or extendedKeyUsage extensions.
1980 */
1981 }
1982
1983
1984 /*
1985 * MARK: Certificate Transparency support
1986 */
1987
1988 /***
1989
1990 struct {
1991 Version sct_version; // 1 byte
1992 LogID id; // 32 bytes
1993 uint64 timestamp; // 8 bytes
1994 CtExtensions extensions; // 2 bytes len field, + n bytes data
1995 digitally-signed struct { // 1 byte hash alg, 1 byte sig alg, n bytes signature
1996 Version sct_version;
1997 SignatureType signature_type = certificate_timestamp;
1998 uint64 timestamp;
1999 LogEntryType entry_type;
2000 select(entry_type) {
2001 case x509_entry: ASN.1Cert;
2002 case precert_entry: PreCert;
2003 } signed_entry;
2004 CtExtensions extensions;
2005 };
2006 } SignedCertificateTimestamp;
2007
2008 ***/
2009
2010 #include <Security/SecureTransportPriv.h>
2011
2012 static const
2013 SecAsn1Oid *oidForSigAlg(SSL_HashAlgorithm hash, SSL_SignatureAlgorithm alg)
2014 {
2015 switch(alg) {
2016 case SSL_SignatureAlgorithmRSA:
2017 switch (hash) {
2018 case SSL_HashAlgorithmSHA1:
2019 return &CSSMOID_SHA1WithRSA;
2020 case SSL_HashAlgorithmSHA256:
2021 return &CSSMOID_SHA256WithRSA;
2022 case SSL_HashAlgorithmSHA384:
2023 return &CSSMOID_SHA384WithRSA;
2024 default:
2025 break;
2026 }
2027 case SSL_SignatureAlgorithmECDSA:
2028 switch (hash) {
2029 case SSL_HashAlgorithmSHA1:
2030 return &CSSMOID_ECDSA_WithSHA1;
2031 case SSL_HashAlgorithmSHA256:
2032 return &CSSMOID_ECDSA_WithSHA256;
2033 case SSL_HashAlgorithmSHA384:
2034 return &CSSMOID_ECDSA_WithSHA384;
2035 default:
2036 break;
2037 }
2038 default:
2039 break;
2040 }
2041
2042 return NULL;
2043 }
2044
2045
2046 static size_t SSLDecodeUint16(const uint8_t *p)
2047 {
2048 return (p[0]<<8 | p[1]);
2049 }
2050
2051 static uint8_t *SSLEncodeUint16(uint8_t *p, size_t len)
2052 {
2053 p[0] = (len >> 8)&0xff;
2054 p[1] = (len & 0xff);
2055 return p+2;
2056 }
2057
2058 static uint8_t *SSLEncodeUint24(uint8_t *p, size_t len)
2059 {
2060 p[0] = (len >> 16)&0xff;
2061 p[1] = (len >> 8)&0xff;
2062 p[2] = (len & 0xff);
2063 return p+3;
2064 }
2065
2066
2067 static
2068 uint64_t SSLDecodeUint64(const uint8_t *p)
2069 {
2070 uint64_t u = 0;
2071 for(int i=0; i<8; i++) {
2072 u=(u<<8)|p[0];
2073 p++;
2074 }
2075 return u;
2076 }
2077
2078 #include <libDER/DER_CertCrl.h>
2079 #include <libDER/DER_Encode.h>
2080 #include <libDER/asn1Types.h>
2081
2082
2083 static CFDataRef copy_x509_entry_from_chain(SecPVCRef pvc)
2084 {
2085 SecCertificateRef leafCert = SecPVCGetCertificateAtIndex(pvc, 0);
2086
2087 CFMutableDataRef data = CFDataCreateMutable(kCFAllocatorDefault, 3+SecCertificateGetLength(leafCert));
2088
2089 CFDataSetLength(data, 3+SecCertificateGetLength(leafCert));
2090
2091 uint8_t *q = CFDataGetMutableBytePtr(data);
2092 q = SSLEncodeUint24(q, SecCertificateGetLength(leafCert));
2093 memcpy(q, SecCertificateGetBytePtr(leafCert), SecCertificateGetLength(leafCert));
2094
2095 return data;
2096 }
2097
2098
2099 static CFDataRef copy_precert_entry_from_chain(SecPVCRef pvc)
2100 {
2101 SecCertificateRef leafCert = NULL;
2102 SecCertificateRef issuer = NULL;
2103 CFDataRef issuerKeyHash = NULL;
2104 CFDataRef tbs_precert = NULL;
2105 CFMutableDataRef data= NULL;
2106
2107 require_quiet(SecPVCGetCertificateCount(pvc)>=2, out); //we need the issuer key for precerts.
2108 leafCert = SecPVCGetCertificateAtIndex(pvc, 0);
2109 issuer = SecPVCGetCertificateAtIndex(pvc, 1);
2110
2111 require(leafCert, out);
2112 require(issuer, out); // Those two would likely indicate an internal error, since we already checked the chain length above.
2113 issuerKeyHash = SecCertificateCopySubjectPublicKeyInfoSHA256Digest(issuer);
2114 tbs_precert = SecCertificateCopyPrecertTBS(leafCert);
2115
2116 require(issuerKeyHash, out);
2117 require(tbs_precert, out);
2118 data = CFDataCreateMutable(kCFAllocatorDefault, CFDataGetLength(issuerKeyHash) + 3 + CFDataGetLength(tbs_precert));
2119 CFDataSetLength(data, CFDataGetLength(issuerKeyHash) + 3 + CFDataGetLength(tbs_precert));
2120
2121 uint8_t *q = CFDataGetMutableBytePtr(data);
2122 memcpy(q, CFDataGetBytePtr(issuerKeyHash), CFDataGetLength(issuerKeyHash)); q += CFDataGetLength(issuerKeyHash); // issuer key hash
2123 q = SSLEncodeUint24(q, CFDataGetLength(tbs_precert));
2124 memcpy(q, CFDataGetBytePtr(tbs_precert), CFDataGetLength(tbs_precert));
2125
2126 out:
2127 CFReleaseSafe(issuerKeyHash);
2128 CFReleaseSafe(tbs_precert);
2129 return data;
2130 }
2131
2132 static
2133 CFAbsoluteTime TimestampToCFAbsoluteTime(uint64_t ts)
2134 {
2135 return (ts / 1000) - kCFAbsoluteTimeIntervalSince1970;
2136 }
2137
2138 static
2139 uint64_t TimestampFromCFAbsoluteTime(CFAbsoluteTime at)
2140 {
2141 return (uint64_t)(at + kCFAbsoluteTimeIntervalSince1970) * 1000;
2142 }
2143
2144
2145
2146
2147 /*
2148 If the 'sct' is valid, add it to the validatingLogs dictionary.
2149
2150 Inputs:
2151 - validatingLogs: mutable dictionary to which to add the log that validate this SCT.
2152 - sct: the SCT date
2153 - entry_type: 0 for x509 cert, 1 for precert.
2154 - entry: the cert or precert data.
2155 - vt: verification time timestamp (as used in SCTs: ms since 1970 Epoch)
2156 - trustedLog: Dictionary contain the Trusted Logs.
2157
2158 The SCT is valid if:
2159 - It decodes properly.
2160 - Its timestamp is less than 'verifyTime'.
2161 - It is signed by a log in 'trustedLogs'.
2162 - If entry_type = 0, the log must be currently qualified.
2163 - If entry_type = 1, the log may be expired.
2164
2165 If the SCT is valid, it's added to the validatinLogs dictionary using the log dictionary as the key, and the timestamp as value.
2166 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.
2167
2168 */
2169
2170
2171 static CFDictionaryRef getSCTValidatingLog(CFDataRef sct, int entry_type, CFDataRef entry, uint64_t vt, CFArrayRef trustedLogs, CFAbsoluteTime *sct_at)
2172 {
2173 uint8_t version;
2174 const uint8_t *logID;
2175 const uint8_t *timestampData;
2176 uint64_t timestamp;
2177 size_t extensionsLen;
2178 const uint8_t *extensionsData;
2179 uint8_t hashAlg;
2180 uint8_t sigAlg;
2181 size_t signatureLen;
2182 const uint8_t *signatureData;
2183 SecKeyRef pubKey = NULL;
2184 uint8_t *signed_data = NULL;
2185 const SecAsn1Oid *oid = NULL;
2186 SecAsn1AlgId algId;
2187 CFDataRef logIDData = NULL;
2188 CFDictionaryRef result = 0;
2189
2190 const uint8_t *p = CFDataGetBytePtr(sct);
2191 size_t len = CFDataGetLength(sct);
2192
2193 require(len>=43, out);
2194
2195 version = p[0]; p++; len--;
2196 logID = p; p+=32; len-=32;
2197 timestampData = p; p+=8; len-=8;
2198 extensionsLen = SSLDecodeUint16(p); p+=2; len-=2;
2199
2200 require(len>=extensionsLen, out);
2201 extensionsData = p; p+=extensionsLen; len-=extensionsLen;
2202
2203 require(len>=4, out);
2204 hashAlg=p[0]; p++; len--;
2205 sigAlg=p[0]; p++; len--;
2206 signatureLen = SSLDecodeUint16(p); p+=2; len-=2;
2207 require(len==signatureLen, out); /* We do not tolerate any extra data after the signature */
2208 signatureData = p;
2209
2210 /* verify version: only v1(0) is supported */
2211 if(version!=0) {
2212 secerror("SCT version unsupported: %d\n", version);
2213 goto out;
2214 }
2215
2216 /* verify timestamp not in the future */
2217 timestamp = SSLDecodeUint64(timestampData);
2218 if(timestamp > vt) {
2219 secerror("SCT is in the future: %llu > %llu\n", timestamp, vt);
2220 goto out;
2221 }
2222
2223 uint8_t *q;
2224
2225 /* signed entry */
2226 size_t signed_data_len = 12 + CFDataGetLength(entry) + 2 + extensionsLen ;
2227 signed_data = malloc(signed_data_len);
2228 require(signed_data, out);
2229 q = signed_data;
2230 *q++ = version;
2231 *q++ = 0; // certificate_timestamp
2232 memcpy(q, timestampData, 8); q+=8;
2233 q = SSLEncodeUint16(q, entry_type); // logentry type: 0=cert 1=precert
2234 memcpy(q, CFDataGetBytePtr(entry), CFDataGetLength(entry)); q += CFDataGetLength(entry);
2235 q = SSLEncodeUint16(q, extensionsLen);
2236 memcpy(q, extensionsData, extensionsLen);
2237
2238 logIDData = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, logID, 32, kCFAllocatorNull);
2239
2240 CFDictionaryRef logData = CFArrayGetValueMatching(trustedLogs, ^bool(const void *dict) {
2241 const void *key_data;
2242 if(!isDictionary(dict)) return false;
2243 if(!CFDictionaryGetValueIfPresent(dict, CFSTR("key"), &key_data)) return false;
2244 if(!isData(key_data)) return false;
2245 CFDataRef valueID = SecSHA256DigestCreateFromData(kCFAllocatorDefault, (CFDataRef)key_data);
2246 bool result = (bool)(CFDataCompare(logIDData, valueID)==kCFCompareEqualTo);
2247 CFReleaseSafe(valueID);
2248 return result;
2249 });
2250 require(logData, out);
2251
2252 if(entry_type==0) {
2253 // For external SCTs, only keep SCTs from currently valid logs.
2254 require(!CFDictionaryContainsKey(logData, CFSTR("expiry")), out);
2255 }
2256
2257 CFDataRef logKeyData = CFDictionaryGetValue(logData, CFSTR("key"));
2258 require(logKeyData, out); // This failing would be an internal logic error
2259 pubKey = SecKeyCreateFromSubjectPublicKeyInfoData(kCFAllocatorDefault, logKeyData);
2260 require(pubKey, out);
2261
2262 oid = oidForSigAlg(hashAlg, sigAlg);
2263 require(oid, out);
2264
2265 algId.algorithm = *oid;
2266 algId.parameters.Data = NULL;
2267 algId.parameters.Length = 0;
2268
2269 if(SecKeyDigestAndVerify(pubKey, &algId, signed_data, signed_data_len, signatureData, signatureLen)==0) {
2270 *sct_at = TimestampToCFAbsoluteTime(timestamp);
2271 result = logData;
2272 } else {
2273 secerror("SCT signature failed (log=%@)\n", logData);
2274 }
2275
2276 out:
2277 CFReleaseSafe(logIDData);
2278 CFReleaseSafe(pubKey);
2279 free(signed_data);
2280 return result;
2281 }
2282
2283
2284 static void addValidatingLog(CFMutableDictionaryRef validatingLogs, CFDictionaryRef log, CFAbsoluteTime sct_at)
2285 {
2286 CFDateRef validated_time = CFDictionaryGetValue(validatingLogs, log);
2287
2288 if(validated_time==NULL || (sct_at < CFDateGetAbsoluteTime(validated_time))) {
2289 CFDateRef sct_time = CFDateCreate(kCFAllocatorDefault, sct_at);
2290 CFDictionarySetValue(validatingLogs, log, sct_time);
2291 CFReleaseSafe(sct_time);
2292 }
2293 }
2294
2295 static CFArrayRef copy_ocsp_scts(SecPVCRef pvc)
2296 {
2297 CFMutableArrayRef SCTs = NULL;
2298 SecCertificateRef leafCert = NULL;
2299 SecCertificateRef issuer = NULL;
2300 CFArrayRef ocspResponsesData = NULL;
2301 SecOCSPRequestRef ocspRequest = NULL;
2302
2303 ocspResponsesData = SecPathBuilderCopyOCSPResponses(pvc->builder);
2304 require_quiet(ocspResponsesData, out);
2305
2306 require_quiet(SecPVCGetCertificateCount(pvc)>=2, out); //we need the issuer key for precerts.
2307 leafCert = SecPVCGetCertificateAtIndex(pvc, 0);
2308 issuer = SecPVCGetCertificateAtIndex(pvc, 1);
2309
2310 require(leafCert, out);
2311 require(issuer, out); // not quiet: Those two would likely indicate an internal error, since we already checked the chain length above.
2312 ocspRequest = SecOCSPRequestCreate(leafCert, issuer);
2313
2314 SCTs = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
2315 require(SCTs, out);
2316
2317 CFArrayForEach(ocspResponsesData, ^(const void *value) {
2318 /* TODO: Should the builder already have the appropriate SecOCSPResponseRef ? */
2319 SecOCSPResponseRef ocspResponse = SecOCSPResponseCreate(value);
2320 if(ocspResponse && SecOCSPGetResponseStatus(ocspResponse)==kSecOCSPSuccess) {
2321 SecOCSPSingleResponseRef ocspSingleResponse = SecOCSPResponseCopySingleResponse(ocspResponse, ocspRequest);
2322 if(ocspSingleResponse) {
2323 CFArrayRef singleResponseSCTs = SecOCSPSingleResponseCopySCTs(ocspSingleResponse);
2324 if(singleResponseSCTs) {
2325 CFArrayAppendArray(SCTs, singleResponseSCTs, CFRangeMake(0, CFArrayGetCount(singleResponseSCTs)));
2326 CFRelease(singleResponseSCTs);
2327 }
2328 SecOCSPSingleResponseDestroy(ocspSingleResponse);
2329 }
2330 }
2331 if(ocspResponse) SecOCSPResponseFinalize(ocspResponse);
2332 });
2333
2334 if(CFArrayGetCount(SCTs)==0) {
2335 CFReleaseNull(SCTs);
2336 }
2337
2338 out:
2339 CFReleaseSafe(ocspResponsesData);
2340 if(ocspRequest)
2341 SecOCSPRequestFinalize(ocspRequest);
2342
2343 return SCTs;
2344 }
2345
2346 static void SecPolicyCheckCT(SecPVCRef pvc, CFStringRef key)
2347 {
2348 SecCertificateRef leafCert = SecPVCGetCertificateAtIndex(pvc, 0);
2349 CFArrayRef embeddedScts = SecCertificateCopySignedCertificateTimestamps(leafCert);
2350 CFArrayRef builderScts = SecPathBuilderCopySignedCertificateTimestamps(pvc->builder);
2351 CFArrayRef trustedLogs = SecPathBuilderCopyTrustedLogs(pvc->builder);
2352 CFArrayRef ocspScts = copy_ocsp_scts(pvc);
2353 CFDataRef precertEntry = copy_precert_entry_from_chain(pvc);
2354 CFDataRef x509Entry = copy_x509_entry_from_chain(pvc);
2355
2356 // This eventually contain list of logs who validated the SCT.
2357 CFMutableDictionaryRef currentLogsValidatingScts = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
2358 CFMutableDictionaryRef logsValidatingEmbeddedScts = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
2359
2360 uint64_t vt = TimestampFromCFAbsoluteTime(pvc->verifyTime);
2361
2362 __block bool at_least_one_currently_valid_external = 0;
2363 __block bool at_least_one_currently_valid_embedded = 0;
2364
2365 require(logsValidatingEmbeddedScts, out);
2366 require(currentLogsValidatingScts, out);
2367
2368 if(trustedLogs) { // Don't bother trying to validate SCTs if we don't have any trusted logs.
2369 if(embeddedScts && precertEntry) { // Don't bother if we could not get the precert.
2370 CFArrayForEach(embeddedScts, ^(const void *value){
2371 CFAbsoluteTime sct_at;
2372 CFDictionaryRef log = getSCTValidatingLog(value, 1, precertEntry, vt, trustedLogs, &sct_at);
2373 if(log) {
2374 addValidatingLog(logsValidatingEmbeddedScts, log, sct_at);
2375 if(!CFDictionaryContainsKey(log, CFSTR("expiry"))) {
2376 addValidatingLog(currentLogsValidatingScts, log, sct_at);
2377 at_least_one_currently_valid_embedded = true;
2378 }
2379 }
2380 });
2381 }
2382
2383 if(builderScts && x509Entry) { // Don't bother if we could not get the cert.
2384 CFArrayForEach(builderScts, ^(const void *value){
2385 CFAbsoluteTime sct_at;
2386 CFDictionaryRef log = getSCTValidatingLog(value, 0, x509Entry, vt, trustedLogs, &sct_at);
2387 if(log) {
2388 addValidatingLog(currentLogsValidatingScts, log, sct_at);
2389 at_least_one_currently_valid_external = true;
2390 }
2391 });
2392 }
2393
2394 if(ocspScts && x509Entry) {
2395 CFArrayForEach(ocspScts, ^(const void *value){
2396 CFAbsoluteTime sct_at;
2397 CFDictionaryRef log = getSCTValidatingLog(value, 0, x509Entry, vt, trustedLogs, &sct_at);
2398 if(log) {
2399 addValidatingLog(currentLogsValidatingScts, log, sct_at);
2400 at_least_one_currently_valid_external = true;
2401 }
2402 });
2403 }
2404 }
2405
2406
2407 /* We now have 2 sets of logs that validated those SCTS, count them and make a final decision.
2408
2409 Current Policy:
2410 is_ct = (A1 AND A2) OR (B1 AND B2).
2411
2412 A1: embedded SCTs from 2+ to 5+ logs valid at issuance time
2413 A2: At least one embedded SCT from a currently valid log.
2414
2415 B1: SCTs from 2 currently valid logs (from any source)
2416 B2: At least 1 external SCT from a currently valid log.
2417
2418 */
2419
2420 pvc->is_ct = false;
2421
2422 if(at_least_one_currently_valid_external && CFDictionaryGetCount(currentLogsValidatingScts)>=2) {
2423 pvc->is_ct = true;
2424 } else if(at_least_one_currently_valid_embedded) {
2425 __block CFAbsoluteTime issuanceTime = pvc->verifyTime;
2426 __block int lifetime; // in Months
2427 __block unsigned once_or_current_qualified_embedded = 0;
2428
2429 /* Calculate issuance time base on timestamp of SCTs from current logs */
2430 CFDictionaryForEach(currentLogsValidatingScts, ^(const void *key, const void *value) {
2431 CFDictionaryRef log = key;
2432 if(!CFDictionaryContainsKey(log, CFSTR("expiry"))) {
2433 // Log is still qualified
2434 CFDateRef ts = (CFDateRef) value;
2435 CFAbsoluteTime timestamp = CFDateGetAbsoluteTime(ts);
2436 if(timestamp < issuanceTime) {
2437 issuanceTime = timestamp;
2438 }
2439 }
2440 });
2441
2442 /* Count Logs */
2443 CFDictionaryForEach(logsValidatingEmbeddedScts, ^(const void *key, const void *value) {
2444 CFDictionaryRef log = key;
2445 CFDateRef ts = value;
2446 CFDateRef expiry = CFDictionaryGetValue(log, CFSTR("expiry"));
2447 if(expiry == NULL || CFDateCompare(ts, expiry, NULL) == kCFCompareLessThan) {
2448 once_or_current_qualified_embedded++;
2449 }
2450 });
2451
2452 SecCFCalendarDoWithZuluCalendar(^(CFCalendarRef zuluCalendar) {
2453 int _lifetime;
2454 CFCalendarGetComponentDifference(zuluCalendar,
2455 SecCertificateNotValidBefore(leafCert),
2456 SecCertificateNotValidAfter(leafCert),
2457 0, "M", &_lifetime);
2458 lifetime = _lifetime;
2459 });
2460
2461 unsigned requiredEmbeddedSctsCount;
2462
2463 if (lifetime < 15) {
2464 requiredEmbeddedSctsCount = 2;
2465 } else if (lifetime <= 27) {
2466 requiredEmbeddedSctsCount = 3;
2467 } else if (lifetime <= 39) {
2468 requiredEmbeddedSctsCount = 4;
2469 } else {
2470 requiredEmbeddedSctsCount = 5;
2471 }
2472
2473 if(once_or_current_qualified_embedded >= requiredEmbeddedSctsCount){
2474 pvc->is_ct = true;
2475 }
2476 }
2477
2478 out:
2479 CFReleaseSafe(logsValidatingEmbeddedScts);
2480 CFReleaseSafe(currentLogsValidatingScts);
2481 CFReleaseSafe(builderScts);
2482 CFReleaseSafe(embeddedScts);
2483 CFReleaseSafe(ocspScts);
2484 CFReleaseSafe(precertEntry);
2485 CFReleaseSafe(trustedLogs);
2486 CFReleaseSafe(x509Entry);
2487 }
2488
2489 static bool checkPolicyOidData(SecPVCRef pvc, CFDataRef oid) {
2490 CFIndex ix, count = SecPVCGetCertificateCount(pvc);
2491 DERItem key_value;
2492 key_value.data = (DERByte *)CFDataGetBytePtr(oid);
2493 key_value.length = (DERSize)CFDataGetLength(oid);
2494
2495 for (ix = 0; ix < count; ix++) {
2496 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix);
2497 policy_set_t policies = policies_for_cert(cert);
2498
2499 if (policy_set_contains(policies, &key_value)) {
2500 return true;
2501 }
2502 }
2503 return false;
2504 }
2505
2506 static void SecPolicyCheckCertificatePolicyOid(SecPVCRef pvc, CFStringRef key)
2507 {
2508 SecPolicyRef policy = SecPVCGetPolicy(pvc);
2509 CFTypeRef value = CFDictionaryGetValue(policy->_options, key);
2510 bool result = false;
2511
2512 if (CFGetTypeID(value) == CFDataGetTypeID())
2513 {
2514 result = checkPolicyOidData(pvc, value);
2515 } else if (CFGetTypeID(value) == CFStringGetTypeID()) {
2516 CFDataRef dataOid = SecCertificateCreateOidDataFromString(NULL, value);
2517 if (dataOid) {
2518 result = checkPolicyOidData(pvc, dataOid);
2519 CFRelease(dataOid);
2520 }
2521 }
2522 if(!result) {
2523 SecPVCSetResult(pvc, key, 0, kCFBooleanFalse);
2524 }
2525 }
2526
2527
2528 static void SecPolicyCheckRevocation(SecPVCRef pvc,
2529 CFStringRef key) {
2530 SecPolicyRef policy = SecPVCGetPolicy(pvc);
2531 CFTypeRef value = CFDictionaryGetValue(policy->_options, key);
2532 if (isString(value)) {
2533 SecPVCSetCheckRevocation(pvc, value);
2534 }
2535 }
2536
2537 static void SecPolicyCheckRevocationResponseRequired(SecPVCRef pvc,
2538 CFStringRef key) {
2539 SecPVCSetCheckRevocationResponseRequired(pvc);
2540 }
2541
2542 static void SecPolicyCheckRevocationOnline(SecPVCRef pvc, CFStringRef key) {
2543 SecPVCSetCheckRevocationOnline(pvc);
2544 }
2545
2546 static void SecPolicyCheckNoNetworkAccess(SecPVCRef pvc,
2547 CFStringRef key) {
2548 SecPolicyRef policy = SecPVCGetPolicy(pvc);
2549 CFTypeRef value = CFDictionaryGetValue(policy->_options, key);
2550 if (value == kCFBooleanTrue) {
2551 SecPathBuilderSetCanAccessNetwork(pvc->builder, false);
2552 } else {
2553 SecPathBuilderSetCanAccessNetwork(pvc->builder, true);
2554 }
2555 }
2556
2557 static void SecPolicyCheckWeakIntermediates(SecPVCRef pvc,
2558 CFStringRef key) {
2559 CFIndex ix, count = SecPVCGetCertificateCount(pvc);
2560 for (ix = 1; ix < count - 1; ++ix) {
2561 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix);
2562 if (cert && SecCertificateIsWeakKey(cert)) {
2563 /* Intermediate certificate has a weak key. */
2564 if (!SecPVCSetResult(pvc, key, ix, kCFBooleanFalse))
2565 return;
2566 }
2567 }
2568 }
2569
2570 static void SecPolicyCheckWeakLeaf(SecPVCRef pvc,
2571 CFStringRef key) {
2572 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, 0);
2573 if (cert && SecCertificateIsWeakKey(cert)) {
2574 /* Leaf certificate has a weak key. */
2575 if (!SecPVCSetResult(pvc, key, 0, kCFBooleanFalse))
2576 return;
2577 }
2578 }
2579
2580 static void SecPolicyCheckWeakRoot(SecPVCRef pvc,
2581 CFStringRef key) {
2582 CFIndex ix, count = SecPVCGetCertificateCount(pvc);
2583 ix = count - 1;
2584 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix);
2585 if (cert && SecCertificateIsWeakKey(cert)) {
2586 /* Root certificate has a weak key. */
2587 if (!SecPVCSetResult(pvc, key, ix, kCFBooleanFalse))
2588 return;
2589 }
2590 }
2591
2592 static void SecPolicyCheckKeySize(SecPVCRef pvc, CFStringRef key) {
2593 CFIndex ix, count = SecPVCGetCertificateCount(pvc);
2594 SecPolicyRef policy = SecPVCGetPolicy(pvc);
2595 CFDictionaryRef keySizes = CFDictionaryGetValue(policy->_options, key);
2596 for (ix = 0; ix < count; ++ix) {
2597 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix);
2598 if (!SecCertificateIsAtLeastMinKeySize(cert, keySizes)) {
2599 if (!SecPVCSetResult(pvc, key, ix, kCFBooleanFalse))
2600 return;
2601 }
2602 }
2603 }
2604
2605 static void SecPolicyCheckSignatureHashAlgorithms(SecPVCRef pvc,
2606 CFStringRef key) {
2607 CFIndex ix, count = SecPVCGetCertificateCount(pvc);
2608 SecPolicyRef policy = SecPVCGetPolicy(pvc);
2609 CFSetRef disallowedHashAlgorithms = CFDictionaryGetValue(policy->_options, key);
2610 for (ix = 0; ix < count; ++ix) {
2611 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix);
2612 if (!SecPolicyCheckCertSignatureHashAlgorithms(cert, disallowedHashAlgorithms)) {
2613 if (!SecPVCSetResult(pvc, key, ix, kCFBooleanFalse))
2614 return;
2615 }
2616 }
2617 }
2618
2619 static bool leaf_is_on_weak_hash_whitelist(SecPVCRef pvc) {
2620 SecCertificateRef leaf = SecPVCGetCertificateAtIndex(pvc, 0);
2621 require_quiet(leaf, out);
2622
2623 /* Leaf certificates that expire before Jan 3 2017 can get a pass.
2624 * They must be updated before this goes live. */
2625 if (SecCertificateNotValidAfter(leaf) < 505200000.0) {
2626 return true;
2627 }
2628
2629 /* And now a few special snowflakes */
2630
2631 /* subject:/C=UK/O=Vodafone Group/CN=Vodafone (Corporate Domain 2009) */
2632 /* issuer :/C=IE/O=Baltimore/OU=CyberTrust/CN=Baltimore CyberTrust Root */
2633 /* Not After : Dec 19 17:25:36 2019 GMT */
2634 static const uint8_t vodafone[] = {
2635 0xC5, 0x0E, 0x88, 0xE5, 0x20, 0xA8, 0x10, 0x41, 0x1D, 0x63,
2636 0x4C, 0xB8, 0xF9, 0xCC, 0x93, 0x9B, 0xFD, 0x76, 0x93, 0x99
2637 };
2638
2639 CFIndex intermediate_ix = SecPVCGetCertificateCount(pvc) - 2;
2640 require_quiet(intermediate_ix > 0, out);
2641 SecCertificateRef intermediate = SecPVCGetCertificateAtIndex(pvc, intermediate_ix);
2642 CFDataRef fingerprint = SecCertificateGetSHA1Digest(intermediate);
2643 require_quiet(fingerprint, out);
2644 const unsigned int len = 20;
2645 const uint8_t *dp = CFDataGetBytePtr(fingerprint);
2646 if (dp && (!memcmp(vodafone, dp, len))) {
2647 return true;
2648 }
2649
2650 out:
2651 return false;
2652 }
2653
2654 static bool SecPVCKeyIsConstraintPolicyOption(SecPVCRef pvc, CFStringRef key);
2655
2656 static void SecPolicyCheckSystemTrustedWeakHash(SecPVCRef pvc,
2657 CFStringRef key) {
2658 CFIndex ix, count = SecPVCGetCertificateCount(pvc);
2659 #if !NO_SERVER
2660 CFDataRef clientAuditToken = NULL;
2661 SecTaskRef task = NULL;
2662 #endif
2663 CFStringRef signingIdentifier = NULL;
2664
2665 /* Only for Safari and WebKit. */
2666 #if NO_SERVER
2667 require_quiet(signingIdentifier = CFRetainSafe(CFBundleGetIdentifier(CFBundleGetMainBundle())), out);
2668 #else
2669 require_quiet(clientAuditToken = SecPathBuilderCopyClientAuditToken(pvc->builder), out);
2670 audit_token_t auditToken = {};
2671 require(sizeof(auditToken) == CFDataGetLength(clientAuditToken), out);
2672 CFDataGetBytes(clientAuditToken, CFRangeMake(0, sizeof(auditToken)), (uint8_t *)&auditToken);
2673 require_quiet(task = SecTaskCreateWithAuditToken(NULL, auditToken), out);
2674 require_quiet(signingIdentifier = SecTaskCopySigningIdentifier(task, NULL), out);
2675 #endif
2676 require_quiet(CFStringHasPrefix(signingIdentifier, CFSTR("com.apple.Safari")) ||
2677 CFStringHasPrefix(signingIdentifier, CFSTR("com.apple.mobilesafari")) ||
2678 CFStringHasPrefix(signingIdentifier, CFSTR("com.apple.WebKit.Networking")) ||
2679 /* Or one of our test apps */
2680 CFStringHasPrefix(signingIdentifier, CFSTR("com.apple.security.SecurityTests")) ||
2681 CFStringHasPrefix(signingIdentifier, CFSTR("com.apple.security.SecurityDevTests")), out);
2682
2683 Boolean keyInPolicy = false;
2684 CFArrayRef policies = pvc->policies;
2685 CFIndex policyIX, policyCount = CFArrayGetCount(policies);
2686 for (policyIX = 0; policyIX < policyCount; ++policyIX) {
2687 SecPolicyRef policy = (SecPolicyRef)CFArrayGetValueAtIndex(policies, policyIX);
2688 if (policy && CFDictionaryContainsKey(policy->_options, key)) {
2689 keyInPolicy = true;
2690 }
2691 }
2692
2693 /* We only enforce this check when *both* of the following are true:
2694 * 1. One of the certs in the path has this usage constraint, and
2695 * 2. One of the policies in the PVC has this key
2696 * (As compared to normal policy options which require only one to be true..) */
2697 require_quiet(SecPVCKeyIsConstraintPolicyOption(pvc, key) &&
2698 keyInPolicy, out);
2699
2700 /* Ignore the anchor if it's trusted */
2701 if (SecCertificatePathIsAnchored(pvc->path)) {
2702 count--;
2703 }
2704 for (ix = 0; ix < count; ++ix) {
2705 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix);
2706 if (SecCertificateIsWeakHash(cert)) {
2707 if (!leaf_is_on_weak_hash_whitelist(pvc)) {
2708 if (!SecPVCSetResult(pvc, key, ix, kCFBooleanFalse)) {
2709 goto out;
2710 }
2711 }
2712 }
2713 }
2714 out:
2715 #if !NO_SERVER
2716 CFReleaseNull(clientAuditToken);
2717 CFReleaseNull(task);
2718 #endif
2719 CFReleaseNull(signingIdentifier);
2720 return;
2721 }
2722
2723 #define ENABLE_CRLS (TARGET_OS_MAC && !TARGET_OS_IPHONE)
2724
2725 // MARK: -
2726 // MARK: SecRVCRef
2727 /********************************************************
2728 ****************** SecRVCRef Functions *****************
2729 ********************************************************/
2730 typedef struct OpaqueSecORVC *SecORVCRef;
2731 #if ENABLE_CRLS
2732 typedef struct OpaqueSecCRVC *SecCRVCRef;
2733 #endif
2734
2735 /* Revocation verification context. */
2736 struct OpaqueSecRVC {
2737 /* Pointer to the pvc for this revocation check */
2738 SecPVCRef pvc;
2739
2740 /* Index of cert in pvc that this RVC is for 0 = leaf, etc. */
2741 CFIndex certIX;
2742
2743 /* The OCSP Revocation verification context */
2744 SecORVCRef orvc;
2745
2746 #if ENABLE_CRLS
2747 SecCRVCRef crvc;
2748 #endif
2749
2750 /* Valid database info for this revocation check */
2751 SecValidInfoRef valid_info;
2752
2753 bool done;
2754 };
2755 typedef struct OpaqueSecRVC *SecRVCRef;
2756
2757 // MARK: SecORVCRef
2758 /********************************************************
2759 ****************** OCSP RVC Functions ******************
2760 ********************************************************/
2761 const CFAbsoluteTime kSecDefaultOCSPResponseTTL = 24.0 * 60.0 * 60.0;
2762 const CFAbsoluteTime kSecOCSPResponseOnlineTTL = 5.0 * 60.0;
2763 #define OCSP_RESPONSE_TIMEOUT (3 * NSEC_PER_SEC)
2764
2765 /* OCSP Revocation verification context. */
2766 struct OpaqueSecORVC {
2767 /* Will contain the response data. */
2768 asynchttp_t http;
2769
2770 /* Pointer to the pvc for this revocation check. */
2771 SecPVCRef pvc;
2772
2773 /* Pointer to the generic rvc for this revocation check */
2774 SecRVCRef rvc;
2775
2776 /* The ocsp request we send to each responder. */
2777 SecOCSPRequestRef ocspRequest;
2778
2779 /* The freshest response we received so far, from stapling or cache or responder. */
2780 SecOCSPResponseRef ocspResponse;
2781
2782 /* The best validated candidate single response we received so far, from stapling or cache or responder. */
2783 SecOCSPSingleResponseRef ocspSingleResponse;
2784
2785 /* Index of cert in pvc that this RVC is for 0 = leaf, etc. */
2786 CFIndex certIX;
2787
2788 /* Index in array returned by SecCertificateGetOCSPResponders() for current
2789 responder. */
2790 CFIndex responderIX;
2791
2792 /* URL of current responder. */
2793 CFURLRef responder;
2794
2795 /* Date until which this revocation status is valid. */
2796 CFAbsoluteTime nextUpdate;
2797
2798 bool done;
2799 };
2800
2801 static void SecORVCFinish(SecORVCRef orvc) {
2802 secdebug("alloc", "%p", orvc);
2803 asynchttp_free(&orvc->http);
2804 if (orvc->ocspRequest) {
2805 SecOCSPRequestFinalize(orvc->ocspRequest);
2806 orvc->ocspRequest = NULL;
2807 }
2808 if (orvc->ocspResponse) {
2809 SecOCSPResponseFinalize(orvc->ocspResponse);
2810 orvc->ocspResponse = NULL;
2811 if (orvc->ocspSingleResponse) {
2812 SecOCSPSingleResponseDestroy(orvc->ocspSingleResponse);
2813 orvc->ocspSingleResponse = NULL;
2814 }
2815 }
2816 }
2817
2818 #define MAX_OCSP_RESPONDERS 3
2819 #define OCSP_REQUEST_THRESHOLD 10
2820
2821 /* Return the next responder we should contact for this rvc or NULL if we
2822 exhausted them all. */
2823 static CFURLRef SecORVCGetNextResponder(SecORVCRef rvc) {
2824 SecCertificateRef cert = SecPVCGetCertificateAtIndex(rvc->pvc, rvc->certIX);
2825 CFArrayRef ocspResponders = SecCertificateGetOCSPResponders(cert);
2826 if (ocspResponders) {
2827 CFIndex responderCount = CFArrayGetCount(ocspResponders);
2828 if (responderCount >= OCSP_REQUEST_THRESHOLD) {
2829 secnotice("rvc", "too many ocsp responders (%ld)", (long)responderCount);
2830 return NULL;
2831 }
2832 while (rvc->responderIX < responderCount && rvc->responderIX < MAX_OCSP_RESPONDERS) {
2833 CFURLRef responder = CFArrayGetValueAtIndex(ocspResponders, rvc->responderIX);
2834 rvc->responderIX++;
2835 CFStringRef scheme = CFURLCopyScheme(responder);
2836 if (scheme) {
2837 /* We only support http and https responders currently. */
2838 bool valid_responder = (CFEqual(CFSTR("http"), scheme) ||
2839 CFEqual(CFSTR("https"), scheme));
2840 CFRelease(scheme);
2841 if (valid_responder)
2842 return responder;
2843 }
2844 }
2845 }
2846 return NULL;
2847 }
2848
2849 /* Fire off an async http request for this certs revocation status, return
2850 false if request was queued, true if we're done. */
2851 static bool SecORVCFetchNext(SecORVCRef rvc) {
2852 while ((rvc->responder = SecORVCGetNextResponder(rvc))) {
2853 CFDataRef request = SecOCSPRequestGetDER(rvc->ocspRequest);
2854 if (!request)
2855 goto errOut;
2856
2857 secinfo("rvc", "Sending http ocsp request for cert %ld", rvc->certIX);
2858 if (!asyncHttpPost(rvc->responder, request, OCSP_RESPONSE_TIMEOUT, &rvc->http)) {
2859 /* Async request was posted, wait for reply. */
2860 return false;
2861 }
2862 }
2863
2864 errOut:
2865 rvc->done = true;
2866 return true;
2867 }
2868
2869 /* Process a verified ocsp response for a given cert. Return true if the
2870 certificate status was obtained. */
2871 static bool SecOCSPSingleResponseProcess(SecOCSPSingleResponseRef this,
2872 SecORVCRef rvc) {
2873 bool processed;
2874 switch (this->certStatus) {
2875 case CS_Good:
2876 secdebug("ocsp", "CS_Good for cert %" PRIdCFIndex, rvc->certIX);
2877 /* @@@ Mark cert as valid until a given date (nextUpdate if we have one)
2878 in the info dictionary. */
2879 //cert.revokeCheckGood(true);
2880 rvc->nextUpdate = this->nextUpdate == NULL_TIME ? this->thisUpdate + kSecDefaultOCSPResponseTTL : this->nextUpdate;
2881 processed = true;
2882 break;
2883 case CS_Revoked:
2884 secdebug("ocsp", "CS_Revoked for cert %" PRIdCFIndex, rvc->certIX);
2885 /* @@@ Mark cert as revoked (with reason) at revocation date in
2886 the info dictionary, or perhaps we should use a different key per
2887 reason? That way a client using exceptions can ignore some but
2888 not all reasons. */
2889 SInt32 reason = this->crlReason;
2890 CFNumberRef cfreason = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &reason);
2891 SecPVCSetResultForced(rvc->pvc, kSecPolicyCheckRevocation, rvc->certIX,
2892 cfreason, true);
2893 if (rvc->pvc && rvc->pvc->info) {
2894 /* make the revocation reason available in the trust result */
2895 CFDictionarySetValue(rvc->pvc->info, kSecTrustRevocationReason, cfreason);
2896 }
2897 CFRelease(cfreason);
2898 processed = true;
2899 break;
2900 case CS_Unknown:
2901 /* not an error, no per-cert status, nothing here */
2902 secdebug("ocsp", "CS_Unknown for cert %" PRIdCFIndex, rvc->certIX);
2903 processed = false;
2904 break;
2905 default:
2906 secnotice("ocsp", "BAD certStatus (%d) for cert %" PRIdCFIndex,
2907 (int)this->certStatus, rvc->certIX);
2908 processed = false;
2909 break;
2910 }
2911
2912 return processed;
2913 }
2914
2915 static void SecORVCUpdatePVC(SecORVCRef rvc) {
2916 if (rvc->ocspSingleResponse) {
2917 SecOCSPSingleResponseProcess(rvc->ocspSingleResponse, rvc);
2918 }
2919 if (rvc->ocspResponse) {
2920 rvc->nextUpdate = SecOCSPResponseGetExpirationTime(rvc->ocspResponse);
2921 }
2922 }
2923
2924 typedef void (^SecOCSPEvaluationCompleted)(SecTrustResultType tr);
2925
2926 static void
2927 SecOCSPEvaluateCompleted(const void *userData,
2928 SecCertificatePathRef chain, CFArrayRef details, CFDictionaryRef info,
2929 SecTrustResultType result) {
2930 SecOCSPEvaluationCompleted evaluated = (SecOCSPEvaluationCompleted)userData;
2931 evaluated(result);
2932 Block_release(evaluated);
2933
2934 }
2935
2936 static bool SecOCSPResponseEvaluateSigner(SecORVCRef rvc, CFArrayRef signers, CFArrayRef issuers, CFAbsoluteTime verifyTime) {
2937 __block bool evaluated = false;
2938 bool trusted = false;
2939 if (!signers || !issuers) {
2940 return trusted;
2941 }
2942
2943 /* Verify the signer chain against the OCSPSigner policy, using the issuer chain as anchors. */
2944 const void *ocspSigner = SecPolicyCreateOCSPSigner();
2945 CFArrayRef policies = CFArrayCreate(kCFAllocatorDefault,
2946 &ocspSigner, 1, &kCFTypeArrayCallBacks);
2947 CFRelease(ocspSigner);
2948
2949 SecOCSPEvaluationCompleted completed = Block_copy(^(SecTrustResultType result) {
2950 if (result == kSecTrustResultProceed || result == kSecTrustResultUnspecified) {
2951 evaluated = true;
2952 }
2953 });
2954
2955 CFDataRef clientAuditToken = SecPathBuilderCopyClientAuditToken(rvc->pvc->builder);
2956 SecPathBuilderRef oBuilder = SecPathBuilderCreate(clientAuditToken,
2957 signers, issuers, true, false,
2958 policies, NULL, NULL, NULL,
2959 verifyTime, NULL,
2960 SecOCSPEvaluateCompleted, completed);
2961 /* Build the chain(s), evaluate them, call the completed block, free the block and builder */
2962 SecPathBuilderStep(oBuilder);
2963 CFReleaseNull(clientAuditToken);
2964 CFReleaseNull(policies);
2965
2966 /* verify the public key of the issuer signed the OCSP signer */
2967 if (evaluated) {
2968 SecCertificateRef issuer = NULL, signer = NULL;
2969 SecKeyRef issuerPubKey = NULL;
2970
2971 issuer = (SecCertificateRef)CFArrayGetValueAtIndex(issuers, 0);
2972 signer = (SecCertificateRef)CFArrayGetValueAtIndex(signers, 0);
2973
2974 if (issuer) {
2975 #if TARGET_OS_IPHONE
2976 issuerPubKey = SecCertificateCopyPublicKey(issuer);
2977 #else
2978 issuerPubKey = SecCertificateCopyPublicKey_ios(issuer);
2979 #endif
2980 }
2981 if (signer && issuerPubKey && (errSecSuccess == SecCertificateIsSignedBy(signer, issuerPubKey))) {
2982 trusted = true;
2983 } else {
2984 secnotice("ocsp", "ocsp signer cert not signed by issuer");
2985 }
2986 CFReleaseNull(issuerPubKey);
2987 }
2988
2989 return trusted;
2990 }
2991
2992 static bool SecOCSPResponseVerify(SecOCSPResponseRef ocspResponse, SecORVCRef rvc, CFAbsoluteTime verifyTime) {
2993 bool trusted;
2994 SecCertificatePathRef issuers = SecCertificatePathCopyFromParent(rvc->pvc->path, rvc->certIX + 1);
2995 SecCertificateRef issuer = issuers ? CFRetainSafe(SecCertificatePathGetCertificateAtIndex(issuers, 0)) : NULL;
2996 CFArrayRef signers = SecOCSPResponseCopySigners(ocspResponse);
2997 SecCertificateRef signer = SecOCSPResponseCopySigner(ocspResponse, issuer);
2998
2999 if (signer && signers) {
3000 if (issuer && CFEqual(signer, issuer)) {
3001 /* We already know we trust issuer since it's the issuer of the
3002 * cert we are verifying. */
3003 secinfo("ocsp", "ocsp responder: %@ response signed by issuer",
3004 rvc->responder);
3005 trusted = true;
3006 } else {
3007 secinfo("ocsp", "ocsp responder: %@ response signed by cert issued by issuer",
3008 rvc->responder);
3009 CFMutableArrayRef signerCerts = NULL;
3010 CFArrayRef issuerCerts = NULL;
3011
3012 /* Ensure the signer cert is the 0th cert for trust evaluation */
3013 signerCerts = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
3014 CFArrayAppendValue(signerCerts, signer);
3015 CFArrayAppendArray(signerCerts, signers, CFRangeMake(0, CFArrayGetCount(signers)));
3016
3017 if (issuers) {
3018 issuerCerts = SecCertificatePathCopyCertificates(issuers, NULL);
3019 }
3020
3021 if (SecOCSPResponseEvaluateSigner(rvc, signerCerts, issuerCerts, verifyTime)) {
3022 secdebug("ocsp", "response satisfies ocspSigner policy (%@)",
3023 rvc->responder);
3024 trusted = true;
3025 } else {
3026 /* @@@ We don't trust the cert so don't use this response. */
3027 secnotice("ocsp", "ocsp response signed by certificate which "
3028 "does not satisfy ocspSigner policy");
3029 trusted = false;
3030 }
3031 CFReleaseNull(signerCerts);
3032 CFReleaseNull(issuerCerts);
3033 }
3034 } else {
3035 /* @@@ No signer found for this ocsp response, discard it. */
3036 secnotice("ocsp", "ocsp responder: %@ no signer found for response",
3037 rvc->responder);
3038 trusted = false;
3039 }
3040
3041 #if DUMP_OCSPRESPONSES
3042 char buf[40];
3043 snprintf(buf, 40, "/tmp/ocspresponse%ld%s.der",
3044 rvc->certIX, (trusted ? "t" : "u"));
3045 secdumpdata(ocspResponse->data, buf);
3046 #endif
3047 CFReleaseNull(issuers);
3048 CFReleaseNull(issuer);
3049 CFReleaseNull(signers);
3050 CFReleaseNull(signer);
3051 return trusted;
3052 }
3053
3054 static void SecORVCConsumeOCSPResponse(SecORVCRef rvc, SecOCSPResponseRef ocspResponse /*CF_CONSUMED*/, CFTimeInterval maxAge, bool updateCache) {
3055 SecOCSPSingleResponseRef sr = NULL;
3056 require_quiet(ocspResponse, errOut);
3057 SecOCSPResponseStatus orStatus = SecOCSPGetResponseStatus(ocspResponse);
3058 require_action_quiet(orStatus == kSecOCSPSuccess, errOut,
3059 secnotice("ocsp", "responder: %@ returned status: %d", rvc->responder, orStatus));
3060 require_action_quiet(sr = SecOCSPResponseCopySingleResponse(ocspResponse, rvc->ocspRequest), errOut,
3061 secnotice("ocsp", "ocsp responder: %@ did not include status of requested cert", rvc->responder));
3062 // Check if this response is fresher than any (cached) response we might still have in the rvc.
3063 require_quiet(!rvc->ocspSingleResponse || rvc->ocspSingleResponse->thisUpdate < sr->thisUpdate, errOut);
3064
3065 CFAbsoluteTime verifyTime = CFAbsoluteTimeGetCurrent();
3066 /* TODO: If the responder doesn't have the ocsp-nocheck extension we should
3067 check whether the leaf was revoked (we are already checking the rest of
3068 the chain). */
3069 /* Check the OCSP response signature and verify the response. */
3070 require_quiet(SecOCSPResponseVerify(ocspResponse, rvc,
3071 sr->certStatus == CS_Revoked ? SecOCSPResponseProducedAt(ocspResponse) : verifyTime), errOut);
3072
3073 // If we get here, we have a properly signed ocsp response
3074 // but we haven't checked dates yet.
3075
3076 bool sr_valid = SecOCSPSingleResponseCalculateValidity(sr, kSecDefaultOCSPResponseTTL, verifyTime);
3077 if (sr->certStatus == CS_Good) {
3078 // Side effect of SecOCSPResponseCalculateValidity sets ocspResponse->expireTime
3079 require_quiet(sr_valid && SecOCSPResponseCalculateValidity(ocspResponse, maxAge, kSecDefaultOCSPResponseTTL, verifyTime), errOut);
3080 } else if (sr->certStatus == CS_Revoked) {
3081 // Expire revoked responses when the subject certificate itself expires.
3082 ocspResponse->expireTime = SecCertificateNotValidAfter(SecPVCGetCertificateAtIndex(rvc->pvc, rvc->certIX));
3083 }
3084
3085 // Ok we like the new response, let's toss the old one.
3086 if (updateCache)
3087 SecOCSPCacheReplaceResponse(rvc->ocspResponse, ocspResponse, rvc->responder, verifyTime);
3088
3089 if (rvc->ocspResponse) SecOCSPResponseFinalize(rvc->ocspResponse);
3090 rvc->ocspResponse = ocspResponse;
3091 ocspResponse = NULL;
3092
3093 if (rvc->ocspSingleResponse) SecOCSPSingleResponseDestroy(rvc->ocspSingleResponse);
3094 rvc->ocspSingleResponse = sr;
3095 sr = NULL;
3096
3097 rvc->done = sr_valid;
3098
3099 errOut:
3100 if (sr) SecOCSPSingleResponseDestroy(sr);
3101 if (ocspResponse) SecOCSPResponseFinalize(ocspResponse);
3102 }
3103
3104 /* Callback from async http code after an ocsp response has been received. */
3105 static void SecOCSPFetchCompleted(asynchttp_t *http, CFTimeInterval maxAge) {
3106 SecORVCRef rvc = (SecORVCRef)http->info;
3107 SecPVCRef pvc = rvc->pvc;
3108 SecOCSPResponseRef ocspResponse = NULL;
3109 if (http->response) {
3110 CFDataRef data = CFHTTPMessageCopyBody(http->response);
3111 if (data) {
3112 /* Parse the returned data as if it's an ocspResponse. */
3113 ocspResponse = SecOCSPResponseCreate(data);
3114 CFRelease(data);
3115 }
3116 }
3117
3118 SecORVCConsumeOCSPResponse(rvc, ocspResponse, maxAge, true);
3119 // TODO: maybe we should set the cache-control: false in the http header and try again if the response is stale
3120
3121 if (!rvc->done) {
3122 /* Clear the data for the next response. */
3123 asynchttp_free(http);
3124 SecORVCFetchNext(rvc);
3125 }
3126
3127 if (rvc->done) {
3128 secdebug("rvc", "got OCSP response for cert: %ld", rvc->certIX);
3129 SecORVCUpdatePVC(rvc);
3130 SecORVCFinish(rvc);
3131 if (!--pvc->asyncJobCount) {
3132 secdebug("rvc", "done with all async jobs");
3133 SecPathBuilderStep(pvc->builder);
3134 }
3135 }
3136 }
3137
3138 static SecORVCRef SecORVCCreate(SecRVCRef rvc, SecPVCRef pvc, CFIndex certIX) {
3139 SecORVCRef orvc = NULL;
3140 orvc = malloc(sizeof(struct OpaqueSecORVC));
3141 if (orvc) {
3142 memset(orvc, 0, sizeof(struct OpaqueSecORVC));
3143 orvc->pvc = pvc;
3144 orvc->rvc = rvc;
3145 orvc->certIX = certIX;
3146 orvc->http.queue = SecPathBuilderGetQueue(pvc->builder);
3147 orvc->http.token = SecPathBuilderCopyClientAuditToken(pvc->builder);
3148 orvc->http.completed = SecOCSPFetchCompleted;
3149 orvc->http.info = orvc;
3150 orvc->ocspRequest = NULL;
3151 orvc->responderIX = 0;
3152 orvc->responder = NULL;
3153 orvc->nextUpdate = NULL_TIME;
3154 orvc->ocspResponse = NULL;
3155 orvc->ocspSingleResponse = NULL;
3156 orvc->done = false;
3157
3158 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, certIX);
3159 CFIndex count = SecPVCGetCertificateCount(pvc);
3160 if (certIX + 1 < count) {
3161 SecCertificateRef issuer = SecPVCGetCertificateAtIndex(pvc, certIX + 1);
3162 orvc->ocspRequest = SecOCSPRequestCreate(cert, issuer);
3163 }
3164 }
3165 return orvc;
3166 }
3167
3168 static void SecORVCProcessStapledResponses(SecORVCRef rvc) {
3169 /* Get stapled OCSP responses */
3170 CFArrayRef ocspResponsesData = SecPathBuilderCopyOCSPResponses(rvc->pvc->builder);
3171
3172 if(ocspResponsesData) {
3173 secdebug("rvc", "Checking stapled responses for cert %ld", rvc->certIX);
3174 CFArrayForEach(ocspResponsesData, ^(const void *value) {
3175 SecOCSPResponseRef ocspResponse = SecOCSPResponseCreate(value);
3176 SecORVCConsumeOCSPResponse(rvc, ocspResponse, NULL_TIME, false);
3177 });
3178 CFRelease(ocspResponsesData);
3179 }
3180 }
3181
3182 // MARK: SecCRVCRef
3183 /********************************************************
3184 ******************* CRL RVC Functions ******************
3185 ********************************************************/
3186 #if ENABLE_CRLS
3187 #include <../trustd/SecTrustOSXEntryPoints.h>
3188 #define kSecDefaultCRLTTL kSecDefaultOCSPResponseTTL
3189
3190 /* CRL Revocation verification context. */
3191 struct OpaqueSecCRVC {
3192 /* Response data from ocspd. Yes, ocspd does CRLs, but not OCSP... */
3193 async_ocspd_t async_ocspd;
3194
3195 /* Pointer to the pvc for this revocation check. */
3196 SecPVCRef pvc;
3197
3198 /* Pointer to the generic rvc for this revocation check */
3199 SecRVCRef rvc;
3200
3201 /* The current CRL status from ocspd. */
3202 OSStatus status;
3203
3204 /* Index of cert in pvc that this RVC is for 0 = leaf, etc. */
3205 CFIndex certIX;
3206
3207 /* Index in array returned by SecCertificateGetCRLDistributionPoints() for
3208 current distribution point. */
3209 CFIndex distributionPointIX;
3210
3211 /* URL of current distribution point. */
3212 CFURLRef distributionPoint;
3213
3214 /* Date until which this revocation status is valid. */
3215 CFAbsoluteTime nextUpdate;
3216
3217 bool done;
3218 };
3219
3220 static void SecCRVCFinish(SecCRVCRef crvc) {
3221 // nothing yet
3222 }
3223
3224 #define MAX_CRL_DPS 3
3225 #define CRL_REQUEST_THRESHOLD 10
3226
3227 static CFURLRef SecCRVCGetNextDistributionPoint(SecCRVCRef rvc) {
3228 SecCertificateRef cert = SecPVCGetCertificateAtIndex(rvc->pvc, rvc->certIX);
3229 CFArrayRef crlDPs = SecCertificateGetCRLDistributionPoints(cert);
3230 if (crlDPs) {
3231 CFIndex crlDPCount = CFArrayGetCount(crlDPs);
3232 if (crlDPCount >= CRL_REQUEST_THRESHOLD) {
3233 secnotice("rvc", "too many CRL DP entries (%ld)", (long)crlDPCount);
3234 return NULL;
3235 }
3236 while (rvc->distributionPointIX < crlDPCount && rvc->distributionPointIX < MAX_CRL_DPS) {
3237 CFURLRef distributionPoint = CFArrayGetValueAtIndex(crlDPs, rvc->distributionPointIX);
3238 rvc->distributionPointIX++;
3239 CFStringRef scheme = CFURLCopyScheme(distributionPoint);
3240 if (scheme) {
3241 /* We only support http and https responders currently. */
3242 bool valid_DP = (CFEqual(CFSTR("http"), scheme) ||
3243 CFEqual(CFSTR("https"), scheme) ||
3244 CFEqual(CFSTR("ldap"), scheme));
3245 CFRelease(scheme);
3246 if (valid_DP)
3247 return distributionPoint;
3248 }
3249 }
3250 }
3251 return NULL;
3252 }
3253
3254 static void SecCRVCGetCRLStatus(SecCRVCRef rvc) {
3255 SecCertificateRef cert = SecPVCGetCertificateAtIndex(rvc->pvc, rvc->certIX);
3256 SecCertificatePathRef path = rvc->pvc->path;
3257 CFArrayRef serializedCertPath = SecCertificatePathCreateSerialized(path, NULL);
3258 secdebug("rvc", "searching CRL cache for cert: %ld", rvc->certIX);
3259 rvc->status = SecTrustLegacyCRLStatus(cert, serializedCertPath, rvc->distributionPoint);
3260 CFReleaseNull(serializedCertPath);
3261 /* we got a response indicating that the CRL was checked */
3262 if (rvc->status == errSecSuccess || rvc->status == errSecCertificateRevoked) {
3263 rvc->done = true;
3264 /* ocspd doesn't give us the nextUpdate time, so set to default */
3265 rvc->nextUpdate = SecPVCGetVerifyTime(rvc->pvc) + kSecDefaultCRLTTL;
3266 }
3267 }
3268
3269 static void SecCRVCCheckRevocationCache(SecCRVCRef rvc) {
3270 while ((rvc->distributionPoint = SecCRVCGetNextDistributionPoint(rvc))) {
3271 SecCRVCGetCRLStatus(rvc);
3272 if (rvc->status == errSecCertificateRevoked) {
3273 return;
3274 }
3275 }
3276 }
3277
3278 /* Fire off an async http request for this certs revocation status, return
3279 false if request was queued, true if we're done. */
3280 static bool SecCRVCFetchNext(SecCRVCRef rvc) {
3281 while ((rvc->distributionPoint = SecCRVCGetNextDistributionPoint(rvc))) {
3282 SecCertificateRef cert = SecPVCGetCertificateAtIndex(rvc->pvc, rvc->certIX);
3283 SecCertificatePathRef path = rvc->pvc->path;
3284 CFArrayRef serializedCertPath = SecCertificatePathCreateSerialized(path, NULL);
3285 secinfo("rvc", "fetching CRL for cert: %ld", rvc->certIX);
3286 if (!SecTrustLegacyCRLFetch(&rvc->async_ocspd, rvc->distributionPoint,
3287 CFAbsoluteTimeGetCurrent(), cert, serializedCertPath)) {
3288 CFDataRef clientAuditToken = NULL;
3289 SecTaskRef task = NULL;
3290 audit_token_t auditToken = {};
3291 clientAuditToken = SecPathBuilderCopyClientAuditToken(rvc->pvc->builder);
3292 require(clientAuditToken, out);
3293 require(sizeof(auditToken) == CFDataGetLength(clientAuditToken), out);
3294 CFDataGetBytes(clientAuditToken, CFRangeMake(0, sizeof(auditToken)), (uint8_t *)&auditToken);
3295 require(task = SecTaskCreateWithAuditToken(NULL, auditToken), out);
3296 secnotice("rvc", "asynchronously fetching CRL (%@) for client (%@)",
3297 rvc->distributionPoint, task);
3298
3299 out:
3300 CFReleaseNull(clientAuditToken);
3301 CFReleaseNull(task);
3302 /* Async request was posted, wait for reply. */
3303 return false;
3304 }
3305 }
3306 rvc->done = true;
3307 return true;
3308 }
3309
3310 static void SecCRVCUpdatePVC(SecCRVCRef rvc) {
3311 if (rvc->status == errSecCertificateRevoked) {
3312 secdebug("rvc", "CRL revoked cert %" PRIdCFIndex, rvc->certIX);
3313 SInt32 reason = 0; // unspecified, since ocspd didn't tell us
3314 CFNumberRef cfreason = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &reason);
3315 SecPVCSetResultForced(rvc->pvc, kSecPolicyCheckRevocation, rvc->certIX,
3316 cfreason, true);
3317 if (rvc->pvc && rvc->pvc->info) {
3318 /* make the revocation reason available in the trust result */
3319 CFDictionarySetValue(rvc->pvc->info, kSecTrustRevocationReason, cfreason);
3320 }
3321 CFReleaseNull(cfreason);
3322 }
3323 }
3324
3325 static void SecCRVCFetchCompleted(async_ocspd_t *ocspd) {
3326 SecCRVCRef rvc = ocspd->info;
3327 SecPVCRef pvc = rvc->pvc;
3328 /* we got a response indicating that the CRL was checked */
3329 if (ocspd->response == errSecSuccess || ocspd->response == errSecCertificateRevoked) {
3330 rvc->status = ocspd->response;
3331 rvc->done = true;
3332 /* ocspd doesn't give us the nextUpdate time, so set to default */
3333 rvc->nextUpdate = SecPVCGetVerifyTime(rvc->pvc) + kSecDefaultCRLTTL;
3334 secdebug("rvc", "got CRL response for cert: %ld", rvc->certIX);
3335 SecCRVCUpdatePVC(rvc);
3336 SecCRVCFinish(rvc);
3337 if (!--pvc->asyncJobCount) {
3338 secdebug("rvc", "done with all async jobs");
3339 SecPathBuilderStep(pvc->builder);
3340 }
3341 } else {
3342 if(SecCRVCFetchNext(rvc)) {
3343 if (!--pvc->asyncJobCount) {
3344 secdebug("rvc", "done with all async jobs");
3345 SecPathBuilderStep(pvc->builder);
3346 }
3347 }
3348 }
3349 }
3350
3351 static SecCRVCRef SecCRVCCreate(SecRVCRef rvc, SecPVCRef pvc, CFIndex certIX) {
3352 SecCRVCRef crvc = NULL;
3353 crvc = malloc(sizeof(struct OpaqueSecCRVC));
3354 if (crvc) {
3355 memset(crvc, 0, sizeof(struct OpaqueSecCRVC));
3356 crvc->pvc = pvc;
3357 crvc->rvc = rvc;
3358 crvc->certIX = certIX;
3359 crvc->status = errSecInternal;
3360 crvc->distributionPointIX = 0;
3361 crvc->distributionPoint = NULL;
3362 crvc->nextUpdate = NULL_TIME;
3363 crvc->async_ocspd.queue = SecPathBuilderGetQueue(pvc->builder);
3364 crvc->async_ocspd.completed = SecCRVCFetchCompleted;
3365 crvc->async_ocspd.response = errSecInternal;
3366 crvc->async_ocspd.info = crvc;
3367 crvc->done = false;
3368 }
3369 return crvc;
3370 }
3371
3372 static bool SecRVCShouldCheckCRL(SecRVCRef rvc) {
3373 if (rvc->pvc->check_revocation &&
3374 CFEqual(kSecPolicyCheckRevocationCRL, rvc->pvc->check_revocation)) {
3375 /* Our client insists on CRLs */
3376 secinfo("rvc", "client told us to check CRL");
3377 return true;
3378 }
3379 SecCertificateRef cert = SecPVCGetCertificateAtIndex(rvc->pvc, rvc->certIX);
3380 CFArrayRef ocspResponders = SecCertificateGetOCSPResponders(cert);
3381 if ((!ocspResponders || CFArrayGetCount(ocspResponders) == 0) &&
3382 (rvc->pvc->check_revocation && !CFEqual(kSecPolicyCheckRevocationOCSP, rvc->pvc->check_revocation))) {
3383 /* The cert doesn't have OCSP responders and the client didn't specifically ask for OCSP.
3384 * This logic will skip the CRL cache check if the client didn't ask for revocation checking */
3385 secinfo("rvc", "client told us to check revocation and CRL is only option for cert: %ld", rvc->certIX);
3386 return true;
3387 }
3388 return false;
3389 }
3390 #endif /* ENABLE_CRLS */
3391
3392 static void SecRVCFinish(SecRVCRef rvc) {
3393 if (rvc->orvc) {
3394 SecORVCFinish(rvc->orvc);
3395 }
3396 #if ENABLE_CRLS
3397 if (rvc->crvc) {
3398 SecCRVCFinish(rvc->crvc);
3399 }
3400 #endif
3401 }
3402
3403 static void SecRVCDelete(SecRVCRef rvc) {
3404 if (rvc->orvc) {
3405 SecORVCFinish(rvc->orvc);
3406 free(rvc->orvc);
3407 }
3408 #if ENABLE_CRLS
3409 if (rvc->crvc) {
3410 SecCRVCFinish(rvc->crvc);
3411 free(rvc->crvc);
3412 }
3413 #endif
3414 if (rvc->valid_info) {
3415 SecValidInfoRelease(rvc->valid_info);
3416 }
3417 }
3418
3419 static void SecRVCInit(SecRVCRef rvc, SecPVCRef pvc, CFIndex certIX) {
3420 secdebug("alloc", "%p", rvc);
3421 rvc->pvc = pvc;
3422 rvc->certIX = certIX;
3423 rvc->orvc = SecORVCCreate(rvc, pvc, certIX);
3424 #if ENABLE_CRLS
3425 rvc->crvc = SecCRVCCreate(rvc, pvc, certIX);
3426 #endif
3427 rvc->done = false;
3428 }
3429
3430 static void SecRVCUpdatePVC(SecRVCRef rvc) {
3431 SecORVCUpdatePVC(rvc->orvc);
3432 #if ENABLE_CRLS
3433 SecCRVCUpdatePVC(rvc->crvc);
3434 #endif
3435 }
3436
3437 #if ENABLE_CRLS
3438 static bool SecRVCShouldCheckOCSP(SecRVCRef rvc) {
3439 if (!rvc->pvc->check_revocation
3440 || !CFEqual(rvc->pvc->check_revocation, kSecPolicyCheckRevocationCRL)) {
3441 return true;
3442 }
3443 return false;
3444 }
3445 #else
3446 static bool SecRVCShouldCheckOCSP(SecRVCRef rvc) {
3447 return true;
3448 }
3449 #endif
3450
3451 static void SecRVCProcessValidInfoResults(SecRVCRef rvc) {
3452 if (!rvc || !rvc->valid_info || !rvc->pvc) {
3453 return;
3454 }
3455 /* Handle definitive revocations.
3456 */
3457 bool valid = rvc->valid_info->valid;
3458 SecValidInfoFormat format = rvc->valid_info->format;
3459 if (!valid && (format == kSecValidInfoFormatSerial || format == kSecValidInfoFormatSHA256)) {
3460 secdebug("validupdate", "rvc: revoked cert %" PRIdCFIndex, rvc->certIX);
3461 SInt32 reason = 0; // unspecified, since the Valid db doesn't tell us
3462 CFNumberRef cfreason = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &reason);
3463 SecPVCSetResultForced(rvc->pvc, kSecPolicyCheckRevocation, rvc->certIX,
3464 cfreason, true);
3465 if (rvc->pvc->info) {
3466 /* make the revocation reason available in the trust result */
3467 CFDictionarySetValue(rvc->pvc->info, kSecTrustRevocationReason, cfreason);
3468 }
3469 CFReleaseNull(cfreason);
3470
3471 rvc->done = true;
3472 return;
3473 }
3474
3475 /* Handle non-definitive information.
3476 We set rvc->done = true above ONLY if the result was definitive;
3477 otherwise we require a revocation check for SSL usage.
3478 */
3479 if (format == kSecValidInfoFormatNto1) {
3480 /* matched the filter */
3481 CFIndex count = SecPVCGetCertificateCount(rvc->pvc);
3482 CFIndex issuerIX = rvc->certIX + 1;
3483 if (issuerIX >= count) {
3484 /* cannot perform a revocation check on the last cert in the
3485 chain, since we don't have its issuer. */
3486 return;
3487 }
3488 SecPolicyRef policy = SecPVCGetPolicy(rvc->pvc);
3489 CFStringRef policyName = (policy) ? SecPolicyGetName(policy) : NULL;
3490 if (policyName && CFEqual(CFSTR("sslServer"), policyName)) {
3491 /* perform revocation check for SSL policy;
3492 require for leaf if an OCSP responder is present. */
3493 if (0 == rvc->certIX) {
3494 SecCertificateRef cert = SecPVCGetCertificateAtIndex(rvc->pvc, rvc->certIX);
3495 CFArrayRef resps = (cert) ? SecCertificateGetOCSPResponders(cert) : NULL;
3496 CFIndex rcount = (resps) ? CFArrayGetCount(resps) : 0;
3497 if (rcount > 0) {
3498 rvc->pvc->response_required = true;
3499 }
3500 }
3501 rvc->pvc->check_revocation = kSecPolicyCheckRevocationAny;
3502 }
3503 }
3504
3505 }
3506
3507 static bool SecRVCCheckValidInfoDatabase(SecRVCRef rvc) {
3508 /* If the valid database is enabled... */
3509 #if (__MAC_OS_X_VERSION_MIN_REQUIRED >= 101300 || __IPHONE_OS_VERSION_MIN_REQUIRED >= 110000)
3510 /* Make sure revocation db info is up-to-date,
3511 if we are allowed to access the network */
3512 #if !TARGET_OS_BRIDGE
3513 SecPathBuilderRef builder = rvc->pvc->builder;
3514 if (SecPathBuilderCanAccessNetwork(builder)) {
3515 SecRevocationDbCheckNextUpdate();
3516 }
3517 #endif
3518 /* Check whether we have valid db info for this cert,
3519 given the cert and its issuer */
3520 SecValidInfoRef info = NULL;
3521 CFIndex count = SecPVCGetCertificateCount(rvc->pvc);
3522 if (count) {
3523 SecCertificateRef cert = NULL;
3524 SecCertificateRef issuer = NULL;
3525 CFIndex issuerIX = rvc->certIX + 1;
3526 if (count > issuerIX) {
3527 issuer = SecPVCGetCertificateAtIndex(rvc->pvc, issuerIX);
3528 } else if (count == issuerIX) {
3529 CFIndex rootIX = SecCertificatePathSelfSignedIndex(rvc->pvc->path);
3530 if (rootIX == rvc->certIX) {
3531 issuer = SecPVCGetCertificateAtIndex(rvc->pvc, rootIX);
3532 }
3533 }
3534 cert = SecPVCGetCertificateAtIndex(rvc->pvc, rvc->certIX);
3535 info = SecRevocationDbCopyMatching(cert, issuer);
3536 }
3537 if (info) {
3538 SecValidInfoRef old_info = rvc->valid_info;
3539 rvc->valid_info = info;
3540 if (old_info) {
3541 SecValidInfoRelease(old_info);
3542 }
3543 return true;
3544 }
3545 #endif
3546 return false;
3547 }
3548
3549 static void SecRVCCheckRevocationCaches(SecRVCRef rvc) {
3550 /* Don't check OCSP cache if CRLs enabled and policy requested CRL only */
3551 if (SecRVCShouldCheckOCSP(rvc)) {
3552 secdebug("ocsp", "Checking cached responses for cert %ld", rvc->certIX);
3553 SecOCSPResponseRef response = NULL;
3554 if (rvc->pvc->online_revocation) {
3555 CFAbsoluteTime now = CFAbsoluteTimeGetCurrent();
3556 response = SecOCSPCacheCopyMatchingWithMinInsertTime(rvc->orvc->ocspRequest, NULL, now - kSecOCSPResponseOnlineTTL);
3557 } else {
3558 response = SecOCSPCacheCopyMatching(rvc->orvc->ocspRequest, NULL);
3559 }
3560 SecORVCConsumeOCSPResponse(rvc->orvc,
3561 response,
3562 NULL_TIME, false);
3563 }
3564 #if ENABLE_CRLS
3565 /* Don't check CRL cache if policy requested OCSP only */
3566 if (SecRVCShouldCheckCRL(rvc)) {
3567 SecCRVCCheckRevocationCache(rvc->crvc);
3568 }
3569 #endif
3570 }
3571
3572 static bool SecRVCFetchNext(SecRVCRef rvc) {
3573 bool OCSP_fetch_finished = true;
3574 /* Don't send OCSP request only if CRLs enabled and policy requested CRL only */
3575 if (SecRVCShouldCheckOCSP(rvc)) {
3576 OCSP_fetch_finished &= SecORVCFetchNext(rvc->orvc);
3577 }
3578 if (OCSP_fetch_finished) {
3579 /* we didn't start an OCSP background job for this cert */
3580 rvc->pvc->asyncJobCount--;
3581 }
3582
3583 #if ENABLE_CRLS
3584 bool CRL_fetch_finished = true;
3585 /* Don't check CRL cache if policy requested OCSP only */
3586 if (SecRVCShouldCheckCRL(rvc)) {
3587 /* reset the distributionPointIX because we already iterated through the CRLDPs
3588 * in SecCRVCCheckRevocationCache */
3589 rvc->crvc->distributionPointIX = 0;
3590 CRL_fetch_finished &= SecCRVCFetchNext(rvc->crvc);
3591 }
3592 if (CRL_fetch_finished) {
3593 /* we didn't start a CRL background job for this cert */
3594 rvc->pvc->asyncJobCount--;
3595 }
3596 OCSP_fetch_finished &= CRL_fetch_finished;
3597 #endif
3598
3599 return OCSP_fetch_finished;
3600 }
3601
3602 static bool SecPVCCheckRevocation(SecPVCRef pvc) {
3603 secdebug("rvc", "checking revocation");
3604 CFIndex certIX, certCount = SecPVCGetCertificateCount(pvc);
3605 bool completed = true;
3606 if (certCount <= 1) {
3607 /* Can't verify without an issuer; we're done */
3608 return completed;
3609 }
3610
3611 /*
3612 * Don't need to call SecPVCIsAnchored; having an issuer is sufficient here.
3613 *
3614 * Note: we can't check revocation for the last certificate in the chain
3615 * via OCSP or CRL methods, since there isn't a separate issuer cert to
3616 * sign those responses. However, since a self-signed root has an implied
3617 * issuer of itself, we can check for it in the valid database.
3618 */
3619
3620 if (pvc->rvcs) {
3621 /* We have done revocation checking already, we're done. */
3622 secdebug("rvc", "Not rechecking revocation");
3623 return completed;
3624 }
3625
3626 /* Setup things so we check revocation status of all certs. */
3627 pvc->rvcs = calloc(sizeof(struct OpaqueSecRVC), certCount);
3628
3629 /* Note that if we are multi threaded and a job completes after it
3630 is started but before we return from this function, we don't want
3631 a callback to decrement asyncJobCount to zero before we finish issuing
3632 all the jobs. To avoid this we pretend we issued certCount-1 async jobs,
3633 and decrement pvc->asyncJobCount for each cert that we don't start a
3634 background fetch for. (We will never start an async job for the final
3635 cert in the chain.) */
3636 #if !ENABLE_CRLS
3637 pvc->asyncJobCount = (unsigned int)(certCount-1);
3638 #else
3639 /* If we enable CRLS, we may end up with two async jobs per cert: one
3640 * for OCSP and one for fetching the CRL */
3641 pvc->asyncJobCount = 2 * (unsigned int)(certCount-1);
3642 #endif
3643 secdebug("rvc", "set asyncJobCount to %d", pvc->asyncJobCount);
3644
3645 /* Loop though certificates again and issue an ocsp fetch if the
3646 * revocation status checking isn't done yet (and we have an issuer!) */
3647 for (certIX = 0; certIX < certCount; ++certIX) {
3648 secdebug("rvc", "checking revocation for cert: %ld", certIX);
3649 SecRVCRef rvc = &((SecRVCRef)pvc->rvcs)[certIX];
3650 SecRVCInit(rvc, pvc, certIX);
3651 if (rvc->done){
3652 continue;
3653 }
3654
3655 #if !TARGET_OS_BRIDGE
3656 /* Check valid database first (separate from OCSP response cache) */
3657 if (SecRVCCheckValidInfoDatabase(rvc)) {
3658 SecRVCProcessValidInfoResults(rvc);
3659 }
3660 #endif
3661 /* Any other revocation method requires an issuer certificate;
3662 * skip the last cert in the chain since it doesn't have one. */
3663 if (certIX+1 >= certCount) {
3664 continue;
3665 }
3666
3667 /* Ignore stapled OCSP responses only if CRLs are enabled and the
3668 * policy specifically requested CRLs only. */
3669 if (SecRVCShouldCheckOCSP(rvc)) {
3670 /* If we have any OCSP stapled responses, check those first */
3671 SecORVCProcessStapledResponses(rvc->orvc);
3672 }
3673
3674 #if TARGET_OS_BRIDGE
3675 /* The bridge has no writeable storage and no network. Nothing else we can
3676 * do here. */
3677 rvc->done = true;
3678 return completed;
3679 #endif
3680
3681 /* Then check the caches for revocation results. */
3682 SecRVCCheckRevocationCaches(rvc);
3683
3684 /* The check is done if we found cached responses from either method. */
3685 if (rvc->orvc->done
3686 #if ENABLE_CRLS
3687 || rvc->orvc->done
3688 #endif
3689 ) {
3690 secdebug("rvc", "found cached response for cert: %ld", certIX);
3691 rvc->done = true;
3692 }
3693
3694 /* If we got a cached response that is no longer valid (which can only be true for
3695 * revoked responses), let's try to get a fresher response even if no one asked.
3696 * This check resolves unrevocation events after the nextUpdate time. */
3697 bool old_cached_response = (!rvc->done && rvc->orvc->ocspResponse);
3698
3699 /* If the cert is EV or if revocation checking was explicitly enabled, attempt to fire off an
3700 async http request for this cert's revocation status, unless we already successfully checked
3701 the revocation status of this cert based on the cache or stapled responses. */
3702 bool allow_fetch = SecPathBuilderCanAccessNetwork(pvc->builder) &&
3703 (pvc->is_ev || pvc->check_revocation || old_cached_response);
3704 bool fetch_done = true;
3705 if (rvc->done || !allow_fetch) {
3706 /* We got a cache hit or we aren't allowed to access the network */
3707 SecRVCUpdatePVC(rvc);
3708 SecRVCFinish(rvc);
3709 /* We didn't really start any background jobs for this cert. */
3710 pvc->asyncJobCount--;
3711 #if ENABLE_CRLS
3712 pvc->asyncJobCount--;
3713 #endif
3714 secdebug("rvc", "not fetching and job count is %d for cert %ld", pvc->asyncJobCount, certIX);
3715 } else {
3716 fetch_done = SecRVCFetchNext(rvc);
3717 }
3718 if (!fetch_done) {
3719 /* We started at least one background fetch. */
3720 secdebug("rvc", "waiting on background fetch for cert %ld", certIX);
3721 completed = false;
3722 }
3723 }
3724
3725 /* Return false if we started any background jobs. */
3726 /* We can't just return !pvc->asyncJobCount here, since if we started any
3727 jobs the completion callback will be called eventually and it will call
3728 SecPathBuilderStep(). If for some reason everything completed before we
3729 get here we still want the outer SecPathBuilderStep() to terminate so we
3730 keep track of whether we started any jobs and return false if so. */
3731 return completed;
3732 }
3733
3734 static CFAbsoluteTime SecRVCGetEarliestNextUpdate(SecRVCRef rvc) {
3735 CFAbsoluteTime enu = NULL_TIME;
3736 enu = rvc->orvc->nextUpdate;
3737 #if ENABLE_CRLS
3738 CFAbsoluteTime crlNextUpdate = rvc->crvc->nextUpdate;
3739 if (enu == NULL_TIME ||
3740 ((crlNextUpdate > NULL_TIME) && (enu > crlNextUpdate))) {
3741 /* We didn't check OCSP or CRL next update time was sooner */
3742 enu = crlNextUpdate;
3743 }
3744 #endif
3745 return enu;
3746 }
3747
3748
3749 void SecPolicyServerInitalize(void) {
3750 gSecPolicyLeafCallbacks = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
3751 &kCFTypeDictionaryKeyCallBacks, NULL);
3752 gSecPolicyPathCallbacks = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
3753 &kCFTypeDictionaryKeyCallBacks, NULL);
3754
3755 CFDictionaryAddValue(gSecPolicyPathCallbacks,
3756 kSecPolicyCheckBasicCertificateProcessing,
3757 SecPolicyCheckBasicCertificateProcessing);
3758 CFDictionaryAddValue(gSecPolicyPathCallbacks,
3759 kSecPolicyCheckCriticalExtensions,
3760 SecPolicyCheckCriticalExtensions);
3761 CFDictionaryAddValue(gSecPolicyPathCallbacks,
3762 kSecPolicyCheckIdLinkage,
3763 SecPolicyCheckIdLinkage);
3764 CFDictionaryAddValue(gSecPolicyLeafCallbacks,
3765 kSecPolicyCheckKeyUsage,
3766 SecPolicyCheckKeyUsage);
3767 CFDictionaryAddValue(gSecPolicyLeafCallbacks,
3768 kSecPolicyCheckExtendedKeyUsage,
3769 SecPolicyCheckExtendedKeyUsage);
3770 CFDictionaryAddValue(gSecPolicyLeafCallbacks,
3771 kSecPolicyCheckBasicConstraints,
3772 SecPolicyCheckBasicConstraints);
3773 CFDictionaryAddValue(gSecPolicyLeafCallbacks,
3774 kSecPolicyCheckNonEmptySubject,
3775 SecPolicyCheckNonEmptySubject);
3776 CFDictionaryAddValue(gSecPolicyLeafCallbacks,
3777 kSecPolicyCheckQualifiedCertStatements,
3778 SecPolicyCheckQualifiedCertStatements);
3779 CFDictionaryAddValue(gSecPolicyLeafCallbacks,
3780 kSecPolicyCheckSSLHostname,
3781 SecPolicyCheckSSLHostname);
3782 CFDictionaryAddValue(gSecPolicyLeafCallbacks,
3783 kSecPolicyCheckEmail,
3784 SecPolicyCheckEmail);
3785 CFDictionaryAddValue(gSecPolicyPathCallbacks,
3786 kSecPolicyCheckValidIntermediates,
3787 SecPolicyCheckValidIntermediates);
3788 CFDictionaryAddValue(gSecPolicyLeafCallbacks,
3789 kSecPolicyCheckValidLeaf,
3790 SecPolicyCheckValidLeaf);
3791 CFDictionaryAddValue(gSecPolicyPathCallbacks,
3792 kSecPolicyCheckValidRoot,
3793 SecPolicyCheckValidRoot);
3794 CFDictionaryAddValue(gSecPolicyPathCallbacks,
3795 kSecPolicyCheckIssuerCommonName,
3796 SecPolicyCheckIssuerCommonName);
3797 CFDictionaryAddValue(gSecPolicyLeafCallbacks,
3798 kSecPolicyCheckSubjectCommonNamePrefix,
3799 SecPolicyCheckSubjectCommonNamePrefix);
3800 CFDictionaryAddValue(gSecPolicyLeafCallbacks,
3801 kSecPolicyCheckSubjectCommonName,
3802 SecPolicyCheckSubjectCommonName);
3803 CFDictionaryAddValue(gSecPolicyLeafCallbacks,
3804 kSecPolicyCheckNotValidBefore,
3805 SecPolicyCheckNotValidBefore);
3806 CFDictionaryAddValue(gSecPolicyPathCallbacks,
3807 kSecPolicyCheckChainLength,
3808 SecPolicyCheckChainLength);
3809 CFDictionaryAddValue(gSecPolicyPathCallbacks,
3810 kSecPolicyCheckAnchorSHA1,
3811 SecPolicyCheckAnchorSHA1);
3812 CFDictionaryAddValue(gSecPolicyPathCallbacks,
3813 kSecPolicyCheckAnchorSHA256,
3814 SecPolicyCheckAnchorSHA256);
3815 CFDictionaryAddValue(gSecPolicyPathCallbacks,
3816 kSecPolicyCheckAnchorApple,
3817 SecPolicyCheckAnchorApple);
3818 CFDictionaryAddValue(gSecPolicyLeafCallbacks,
3819 kSecPolicyCheckSubjectOrganization,
3820 SecPolicyCheckSubjectOrganization);
3821 CFDictionaryAddValue(gSecPolicyLeafCallbacks,
3822 kSecPolicyCheckSubjectOrganizationalUnit,
3823 SecPolicyCheckSubjectOrganizationalUnit);
3824 CFDictionaryAddValue(gSecPolicyLeafCallbacks,
3825 kSecPolicyCheckEAPTrustedServerNames,
3826 SecPolicyCheckEAPTrustedServerNames);
3827 CFDictionaryAddValue(gSecPolicyLeafCallbacks,
3828 kSecPolicyCheckSubjectCommonNameTEST,
3829 SecPolicyCheckSubjectCommonNameTEST);
3830 CFDictionaryAddValue(gSecPolicyLeafCallbacks,
3831 kSecPolicyCheckRevocation,
3832 SecPolicyCheckRevocation);
3833 CFDictionaryAddValue(gSecPolicyLeafCallbacks,
3834 kSecPolicyCheckRevocationResponseRequired,
3835 SecPolicyCheckRevocationResponseRequired);
3836 CFDictionaryAddValue(gSecPolicyLeafCallbacks,
3837 kSecPolicyCheckRevocationOnline,
3838 SecPolicyCheckRevocationOnline);
3839 CFDictionaryAddValue(gSecPolicyLeafCallbacks,
3840 kSecPolicyCheckNoNetworkAccess,
3841 SecPolicyCheckNoNetworkAccess);
3842 CFDictionaryAddValue(gSecPolicyLeafCallbacks,
3843 kSecPolicyCheckBlackListedLeaf,
3844 SecPolicyCheckBlackListedLeaf);
3845 CFDictionaryAddValue(gSecPolicyLeafCallbacks,
3846 kSecPolicyCheckGrayListedLeaf,
3847 SecPolicyCheckGrayListedLeaf);
3848 CFDictionaryAddValue(gSecPolicyLeafCallbacks,
3849 kSecPolicyCheckLeafMarkerOid,
3850 SecPolicyCheckLeafMarkerOid);
3851 CFDictionaryAddValue(gSecPolicyLeafCallbacks,
3852 kSecPolicyCheckLeafMarkerOidWithoutValueCheck,
3853 SecPolicyCheckLeafMarkerOidWithoutValueCheck);
3854 CFDictionaryAddValue(gSecPolicyLeafCallbacks,
3855 kSecPolicyCheckLeafMarkersProdAndQA,
3856 SecPolicyCheckLeafMarkersProdAndQA);
3857 CFDictionaryAddValue(gSecPolicyPathCallbacks,
3858 kSecPolicyCheckIntermediateSPKISHA256,
3859 SecPolicyCheckIntermediateSPKISHA256);
3860 CFDictionaryAddValue(gSecPolicyPathCallbacks,
3861 kSecPolicyCheckIntermediateEKU,
3862 SecPolicyCheckIntermediateEKU);
3863 CFDictionaryAddValue(gSecPolicyPathCallbacks,
3864 kSecPolicyCheckIntermediateMarkerOid,
3865 SecPolicyCheckIntermediateMarkerOid);
3866 CFDictionaryAddValue(gSecPolicyLeafCallbacks,
3867 kSecPolicyCheckCertificatePolicy,
3868 SecPolicyCheckCertificatePolicyOid);
3869 CFDictionaryAddValue(gSecPolicyPathCallbacks,
3870 kSecPolicyCheckWeakIntermediates,
3871 SecPolicyCheckWeakIntermediates);
3872 CFDictionaryAddValue(gSecPolicyLeafCallbacks,
3873 kSecPolicyCheckWeakLeaf,
3874 SecPolicyCheckWeakLeaf);
3875 CFDictionaryAddValue(gSecPolicyPathCallbacks,
3876 kSecPolicyCheckWeakRoot,
3877 SecPolicyCheckWeakRoot);
3878 CFDictionaryAddValue(gSecPolicyPathCallbacks,
3879 kSecPolicyCheckKeySize,
3880 SecPolicyCheckKeySize);
3881 CFDictionaryAddValue(gSecPolicyPathCallbacks,
3882 kSecPolicyCheckSignatureHashAlgorithms,
3883 SecPolicyCheckSignatureHashAlgorithms);
3884 CFDictionaryAddValue(gSecPolicyPathCallbacks,
3885 kSecPolicyCheckSystemTrustedWeakHash,
3886 SecPolicyCheckSystemTrustedWeakHash);
3887 CFDictionaryAddValue(gSecPolicyPathCallbacks,
3888 kSecPolicyCheckIntermediateOrganization,
3889 SecPolicyCheckIntermediateOrganization);
3890 CFDictionaryAddValue(gSecPolicyPathCallbacks,
3891 kSecPolicyCheckIntermediateCountry,
3892 SecPolicyCheckIntermediateCountry);
3893 }
3894
3895 // MARK: -
3896 // MARK: SecPVCRef
3897 /********************************************************
3898 ****************** SecPVCRef Functions *****************
3899 ********************************************************/
3900
3901 void SecPVCInit(SecPVCRef pvc, SecPathBuilderRef builder, CFArrayRef policies,
3902 CFAbsoluteTime verifyTime) {
3903 secdebug("alloc", "%p", pvc);
3904 // Weird logging policies crashes.
3905 //secdebug("policy", "%@", policies);
3906
3907 // Zero the pvc struct so only non-zero fields need to be explicitly set
3908 memset(pvc, 0, sizeof(struct OpaqueSecPVC));
3909 pvc->builder = builder;
3910 pvc->policies = policies;
3911 if (policies)
3912 CFRetain(policies);
3913 pvc->verifyTime = verifyTime;
3914 pvc->result = true;
3915 }
3916
3917 static void SecPVCDeleteRVCs(SecPVCRef pvc) {
3918 secdebug("alloc", "%p", pvc);
3919 if (pvc->rvcs) {
3920 CFIndex certIX, certCount = SecPVCGetCertificateCount(pvc);
3921 for (certIX = 0; certIX < certCount; ++certIX) {
3922 SecRVCRef rvc = &((SecRVCRef)pvc->rvcs)[certIX];
3923 SecRVCDelete(rvc);
3924 }
3925 free(pvc->rvcs);
3926 pvc->rvcs = NULL;
3927 }
3928 }
3929
3930 void SecPVCDelete(SecPVCRef pvc) {
3931 secdebug("alloc", "%p", pvc);
3932 CFReleaseNull(pvc->policies);
3933 CFReleaseNull(pvc->details);
3934 CFReleaseNull(pvc->info);
3935 if (pvc->valid_policy_tree) {
3936 policy_tree_prune(&pvc->valid_policy_tree);
3937 }
3938 SecPVCDeleteRVCs(pvc);
3939 CFReleaseNull(pvc->path);
3940 }
3941
3942 void SecPVCSetPath(SecPVCRef pvc, SecCertificatePathRef path,
3943 CF_CONSUMED CFArrayRef details) {
3944 secdebug("policy", "%@", path);
3945 bool samePath = ((!path && !pvc->path) || (path && pvc->path && CFEqual(path, pvc->path)));
3946 if (!samePath) {
3947 /* Changing path makes us clear the Revocation Verification Contexts */
3948 SecPVCDeleteRVCs(pvc);
3949 CFReleaseSafe(pvc->path);
3950 pvc->path = CFRetainSafe(path);
3951 }
3952 pvc->details = details;
3953 CFReleaseNull(pvc->info);
3954 if (pvc->valid_policy_tree) {
3955 policy_tree_prune(&pvc->valid_policy_tree);
3956 }
3957 pvc->policyIX = 0;
3958
3959 /* Since we don't run the LeafChecks again, we need to preserve the
3960 * result the leaf had. */
3961 pvc->result = (details) ? (CFDictionaryGetCount(CFArrayGetValueAtIndex(details, 0)) == 0)
3962 : true;
3963 }
3964
3965 SecPolicyRef SecPVCGetPolicy(SecPVCRef pvc) {
3966 return (SecPolicyRef)CFArrayGetValueAtIndex(pvc->policies, pvc->policyIX);
3967 }
3968
3969 CFIndex SecPVCGetCertificateCount(SecPVCRef pvc) {
3970 return SecCertificatePathGetCount(pvc->path);
3971 }
3972
3973 SecCertificateRef SecPVCGetCertificateAtIndex(SecPVCRef pvc, CFIndex ix) {
3974 return SecCertificatePathGetCertificateAtIndex(pvc->path, ix);
3975 }
3976
3977 bool SecPVCIsCertificateAtIndexSelfIssued(SecPVCRef pvc, CFIndex ix) {
3978 /* The SecCertificatePath only tells us the last self-issued cert.
3979 * The chain may have more than one self-issued cert, so we need to
3980 * do the comparison. */
3981 bool result = false;
3982 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix);
3983 CFDataRef issuer = SecCertificateCopyNormalizedIssuerSequence(cert);
3984 CFDataRef subject = SecCertificateCopyNormalizedSubjectSequence(cert);
3985 if (issuer && subject && CFEqual(issuer, subject)) {
3986 result = true;
3987 }
3988 CFReleaseNull(issuer);
3989 CFReleaseNull(subject);
3990 return result;
3991 }
3992
3993 void SecPVCSetCheckRevocation(SecPVCRef pvc, CFStringRef method) {
3994 pvc->check_revocation = method;
3995 secdebug("rvc", "deferred revocation checking enabled using %@ method", method);
3996 }
3997
3998 void SecPVCSetCheckRevocationResponseRequired(SecPVCRef pvc) {
3999 pvc->response_required = true;
4000 secdebug("rvc", "revocation response required");
4001 }
4002
4003 void SecPVCSetCheckRevocationOnline(SecPVCRef pvc) {
4004 pvc->online_revocation = true;
4005 secdebug("rvc", "revocation force online check");
4006 }
4007
4008 bool SecPVCIsAnchored(SecPVCRef pvc) {
4009 return SecCertificatePathIsAnchored(pvc->path);
4010 }
4011
4012 CFAbsoluteTime SecPVCGetVerifyTime(SecPVCRef pvc) {
4013 return pvc->verifyTime;
4014 }
4015
4016 static int32_t detailKeyToCssmErr(CFStringRef key) {
4017 int32_t result = 0;
4018
4019 if (CFEqual(key, kSecPolicyCheckSSLHostname)) {
4020 result = -2147408896; // CSSMERR_APPLETP_HOSTNAME_MISMATCH
4021 }
4022 else if (CFEqual(key, kSecPolicyCheckEmail)) {
4023 result = -2147408872; // CSSMERR_APPLETP_SMIME_EMAIL_ADDRS_NOT_FOUND
4024 }
4025 else if (CFEqual(key, kSecPolicyCheckValidLeaf) ||
4026 CFEqual(key, kSecPolicyCheckValidIntermediates) ||
4027 CFEqual(key, kSecPolicyCheckValidRoot)) {
4028 result = -2147409654; // CSSMERR_TP_CERT_EXPIRED
4029 }
4030
4031 return result;
4032 }
4033
4034 static bool SecPVCMeetsConstraint(SecPVCRef pvc, SecCertificateRef certificate, CFDictionaryRef constraint);
4035
4036 static bool SecPVCIsAllowedError(SecPVCRef pvc, CFIndex ix, CFStringRef key) {
4037 bool result = false;
4038 CFArrayRef constraints = SecCertificatePathGetUsageConstraintsAtIndex(pvc->path, ix);
4039 SecCertificateRef cert = SecCertificatePathGetCertificateAtIndex(pvc->path, ix);
4040 CFIndex constraintIX, constraintCount = CFArrayGetCount(constraints);
4041
4042 for (constraintIX = 0; constraintIX < constraintCount; constraintIX++) {
4043 CFDictionaryRef constraint = (CFDictionaryRef)CFArrayGetValueAtIndex(constraints, constraintIX);
4044 CFNumberRef allowedErrorNumber = NULL;
4045 if (!isDictionary(constraint)) {
4046 continue;
4047 }
4048 allowedErrorNumber = (CFNumberRef)CFDictionaryGetValue(constraint, kSecTrustSettingsAllowedError);
4049 int32_t allowedErrorValue = 0;
4050 if (!isNumber(allowedErrorNumber) || !CFNumberGetValue(allowedErrorNumber, kCFNumberSInt32Type, &allowedErrorValue)) {
4051 continue;
4052 }
4053
4054 if (SecPVCMeetsConstraint(pvc, cert, constraint)) {
4055 if (allowedErrorValue == detailKeyToCssmErr(key)) {
4056 result = true;
4057 break;
4058 }
4059 }
4060 }
4061 return result;
4062 }
4063
4064 static bool SecPVCKeyIsConstraintPolicyOption(SecPVCRef pvc, CFStringRef key) {
4065 CFIndex certIX, certCount = SecCertificatePathGetCount(pvc->path);
4066 for (certIX = 0; certIX < certCount; certIX++) {
4067 CFArrayRef constraints = SecCertificatePathGetUsageConstraintsAtIndex(pvc->path, certIX);
4068 CFIndex constraintIX, constraintCount = CFArrayGetCount(constraints);
4069 for (constraintIX = 0; constraintIX < constraintCount; constraintIX++) {
4070 CFDictionaryRef constraint = (CFDictionaryRef)CFArrayGetValueAtIndex(constraints, constraintIX);
4071 if (!isDictionary(constraint)) {
4072 continue;
4073 }
4074
4075 CFDictionaryRef policyOptions = NULL;
4076 policyOptions = (CFDictionaryRef)CFDictionaryGetValue(constraint, kSecTrustSettingsPolicyOptions);
4077 if (policyOptions && isDictionary(policyOptions) &&
4078 CFDictionaryContainsKey(policyOptions, key)) {
4079 return true;
4080 }
4081 }
4082 }
4083 return false;
4084 }
4085
4086 /* AUDIT[securityd](done):
4087 policy->_options is a caller provided dictionary, only its cf type has
4088 been checked.
4089 */
4090 bool SecPVCSetResultForced(SecPVCRef pvc,
4091 CFStringRef key, CFIndex ix, CFTypeRef result, bool force) {
4092
4093 secnotice("policy", "cert[%d]: %@ =(%s)[%s]> %@", (int) ix, key,
4094 (pvc->callbacks == gSecPolicyLeafCallbacks ? "leaf"
4095 : (pvc->callbacks == gSecPolicyPathCallbacks ? "path"
4096 : "custom")),
4097 (force ? "force" : ""), result);
4098
4099 /* If this is not something the current policy cares about ignore
4100 this error and return true so our caller continues evaluation. */
4101 if (!force) {
4102 /* Either the policy or the usage constraints have to have this key */
4103 SecPolicyRef policy = SecPVCGetPolicy(pvc);
4104 if (!(SecPVCKeyIsConstraintPolicyOption(pvc, key) ||
4105 (policy && CFDictionaryContainsKey(policy->_options, key)))) {
4106 return true;
4107 }
4108 }
4109
4110 /* Check to see if the SecTrustSettings for the certificate in question
4111 tell us to ignore this error. */
4112 if (SecPVCIsAllowedError(pvc, ix, key)) {
4113 secinfo("policy", "cert[%d]: skipped allowed error %@", (int) ix, key);
4114 return true;
4115 }
4116
4117 pvc->result = false;
4118 if (!pvc->details)
4119 return false;
4120
4121 CFMutableDictionaryRef detail =
4122 (CFMutableDictionaryRef)CFArrayGetValueAtIndex(pvc->details, ix);
4123
4124 /* Perhaps detail should have an array of results per key? As it stands
4125 in the case of multiple policy failures the last failure stands. */
4126 CFDictionarySetValue(detail, key, result);
4127
4128 return true;
4129 }
4130
4131 bool SecPVCSetResult(SecPVCRef pvc,
4132 CFStringRef key, CFIndex ix, CFTypeRef result) {
4133 return SecPVCSetResultForced(pvc, key, ix, result, false);
4134 }
4135
4136 /* AUDIT[securityd](done):
4137 key(ok) is a caller provided.
4138 value(ok, unused) is a caller provided.
4139 */
4140 static void SecPVCValidateKey(const void *key, const void *value,
4141 void *context) {
4142 SecPVCRef pvc = (SecPVCRef)context;
4143
4144 /* If our caller doesn't want full details and we failed earlier there is
4145 no point in doing additional checks. */
4146 if (!pvc->result && !pvc->details)
4147 return;
4148
4149 SecPolicyCheckFunction fcn = (SecPolicyCheckFunction)
4150 CFDictionaryGetValue(pvc->callbacks, key);
4151
4152 if (!fcn) {
4153 #if 0
4154 /* Why not to have optional policy checks rant:
4155 Not all keys are in all dictionaries anymore, so why not make checks
4156 optional? This way a client can ask for something and the server will
4157 do a best effort based on the supported flags. It works since they are
4158 synchronized now, but we need some debug checking here for now. */
4159 pvc->result = false;
4160 #endif
4161 if (pvc->callbacks == gSecPolicyLeafCallbacks) {
4162 if (!CFDictionaryContainsKey(gSecPolicyPathCallbacks, key)) {
4163 pvc->result = false;
4164 }
4165 } else if (pvc->callbacks == gSecPolicyPathCallbacks) {
4166 if (!CFDictionaryContainsKey(gSecPolicyLeafCallbacks, key)) {
4167 pvc->result = false;
4168 }
4169 } else {
4170 /* Non standard validation phase, nothing is optional. */
4171 pvc->result = false;
4172 }
4173 return;
4174 }
4175
4176 fcn(pvc, (CFStringRef)key);
4177 }
4178
4179 /* AUDIT[securityd](done):
4180 policy->_options is a caller provided dictionary, only its cf type has
4181 been checked.
4182 */
4183 bool SecPVCLeafChecks(SecPVCRef pvc) {
4184 pvc->result = true;
4185 CFArrayRef policies = pvc->policies;
4186 CFIndex ix, count = CFArrayGetCount(policies);
4187 for (ix = 0; ix < count; ++ix) {
4188 SecPolicyRef policy = (SecPolicyRef)CFArrayGetValueAtIndex(policies, ix);
4189 pvc->policyIX = ix;
4190 /* Validate all keys for all policies. */
4191 pvc->callbacks = gSecPolicyLeafCallbacks;
4192 CFDictionaryApplyFunction(policy->_options, SecPVCValidateKey, pvc);
4193 if (!pvc->result && !pvc->details)
4194 return pvc->result;
4195 }
4196
4197 return pvc->result;
4198 }
4199
4200 bool SecPVCParentCertificateChecks(SecPVCRef pvc, CFIndex ix) {
4201 /* Check stuff common to intermediate and anchors. */
4202 CFAbsoluteTime verifyTime = SecPVCGetVerifyTime(pvc);
4203 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix);
4204 bool is_anchor = (ix == SecPVCGetCertificateCount(pvc) - 1
4205 && SecPVCIsAnchored(pvc));
4206 if (!SecCertificateIsValid(cert, verifyTime)) {
4207 /* Certificate has expired. */
4208 if (!SecPVCSetResult(pvc, is_anchor ? kSecPolicyCheckValidRoot
4209 : kSecPolicyCheckValidIntermediates, ix, kCFBooleanFalse))
4210 goto errOut;
4211 }
4212
4213 if (SecCertificateIsWeakKey(cert)) {
4214 /* Certificate uses weak key. */
4215 if (!SecPVCSetResult(pvc, is_anchor ? kSecPolicyCheckWeakRoot
4216 : kSecPolicyCheckWeakIntermediates, ix, kCFBooleanFalse))
4217 goto errOut;
4218 }
4219
4220 if (is_anchor) {
4221 /* Perform anchor specific checks. */
4222 /* Don't think we have any of these. */
4223 } else {
4224 /* Perform intermediate specific checks. */
4225
4226 /* (k) Basic constraints only relevant for v3 and later. */
4227 if (SecCertificateVersion(cert) >= 3) {
4228 const SecCEBasicConstraints *bc =
4229 SecCertificateGetBasicConstraints(cert);
4230 if (!bc || !bc->isCA) {
4231 /* Basic constraints not present or not marked as isCA, illegal. */
4232 if (!SecPVCSetResultForced(pvc, kSecPolicyCheckBasicConstraints,
4233 ix, kCFBooleanFalse, true))
4234 goto errOut;
4235 }
4236 }
4237 /* (l) max_path_length is checked elsewhere. */
4238
4239 /* (n) If a key usage extension is present, verify that the keyCertSign bit is set. */
4240 SecKeyUsage keyUsage = SecCertificateGetKeyUsage(cert);
4241 if (keyUsage && !(keyUsage & kSecKeyUsageKeyCertSign)) {
4242 if (!SecPVCSetResultForced(pvc, kSecPolicyCheckKeyUsage,
4243 ix, kCFBooleanFalse, true))
4244 goto errOut;
4245 }
4246 }
4247
4248 errOut:
4249 return pvc->result;
4250 }
4251
4252 bool SecPVCBlackListedKeyChecks(SecPVCRef pvc, CFIndex ix) {
4253 /* Check stuff common to intermediate and anchors. */
4254
4255 SecOTAPKIRef otapkiRef = SecOTAPKICopyCurrentOTAPKIRef();
4256 if (NULL != otapkiRef)
4257 {
4258 CFSetRef blackListedKeys = SecOTAPKICopyBlackListSet(otapkiRef);
4259 CFRelease(otapkiRef);
4260 if (NULL != blackListedKeys)
4261 {
4262 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix);
4263 CFIndex count = SecPVCGetCertificateCount(pvc);
4264 bool is_last = (ix == count - 1);
4265 bool is_anchor = (is_last && SecPVCIsAnchored(pvc));
4266 if (!is_anchor) {
4267 /* Check for blacklisted intermediate issuer keys. */
4268 CFDataRef dgst = SecCertificateCopyPublicKeySHA1Digest(cert);
4269 if (dgst) {
4270 /* Check dgst against blacklist. */
4271 if (CFSetContainsValue(blackListedKeys, dgst)) {
4272 /* Check allow list for this blacklisted issuer key,
4273 which is the authority key of the issued cert at ix-1.
4274 If ix is the last cert, the root is missing, so we
4275 also check our own authority key in that case.
4276 */
4277 bool allowed = ((ix && SecPVCCheckCertificateAllowList(pvc, ix - 1)) ||
4278 (is_last && SecPVCCheckCertificateAllowList(pvc, ix)));
4279 if (!allowed) {
4280 SecPVCSetResultForced(pvc, kSecPolicyCheckBlackListedKey,
4281 ix, kCFBooleanFalse, true);
4282 }
4283 pvc->is_allowlisted = allowed;
4284 }
4285 CFRelease(dgst);
4286 }
4287 }
4288 CFRelease(blackListedKeys);
4289 return pvc->result;
4290 }
4291 }
4292 // Assume OK
4293 return true;
4294 }
4295
4296 bool SecPVCGrayListedKeyChecks(SecPVCRef pvc, CFIndex ix)
4297 {
4298 /* Check stuff common to intermediate and anchors. */
4299 SecOTAPKIRef otapkiRef = SecOTAPKICopyCurrentOTAPKIRef();
4300 if (NULL != otapkiRef)
4301 {
4302 CFSetRef grayListKeys = SecOTAPKICopyGrayList(otapkiRef);
4303 CFRelease(otapkiRef);
4304 if (NULL != grayListKeys)
4305 {
4306 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix);
4307 CFIndex count = SecPVCGetCertificateCount(pvc);
4308 bool is_last = (ix == count - 1);
4309 bool is_anchor = (is_last && SecPVCIsAnchored(pvc));
4310 if (!is_anchor) {
4311 /* Check for gray listed intermediate issuer keys. */
4312 CFDataRef dgst = SecCertificateCopyPublicKeySHA1Digest(cert);
4313 if (dgst) {
4314 /* Check dgst against gray list. */
4315 if (CFSetContainsValue(grayListKeys, dgst)) {
4316 /* Check allow list for this graylisted issuer key,
4317 which is the authority key of the issued cert at ix-1.
4318 If ix is the last cert, the root is missing, so we
4319 also check our own authority key in that case.
4320 */
4321 bool allowed = ((ix && SecPVCCheckCertificateAllowList(pvc, ix - 1)) ||
4322 (is_last && SecPVCCheckCertificateAllowList(pvc, ix)));
4323 if (!allowed) {
4324 SecPVCSetResultForced(pvc, kSecPolicyCheckGrayListedKey,
4325 ix, kCFBooleanFalse, true);
4326 }
4327 pvc->is_allowlisted = allowed;
4328 }
4329 CFRelease(dgst);
4330 }
4331 }
4332 CFRelease(grayListKeys);
4333 return pvc->result;
4334 }
4335 }
4336 // Assume ok
4337 return true;
4338 }
4339
4340 static bool SecPVCContainsPolicy(SecPVCRef pvc, CFStringRef searchOid, CFStringRef searchName, CFIndex *policyIX) {
4341 if (!isString(searchName) && !isString(searchOid)) {
4342 return false;
4343 }
4344 CFArrayRef policies = pvc->policies;
4345 CFIndex ix, count = CFArrayGetCount(policies);
4346 for (ix = 0; ix < count; ++ix) {
4347 SecPolicyRef policy = (SecPolicyRef)CFArrayGetValueAtIndex(policies, ix);
4348 CFStringRef policyName = SecPolicyGetName(policy);
4349 CFStringRef policyOid = SecPolicyGetOidString(policy);
4350 /* Prefer a match of both name and OID */
4351 if (searchOid && searchName && policyOid && policyName) {
4352 if (CFEqual(searchOid, policyOid) &&
4353 CFEqual(searchName, policyName)) {
4354 if (policyIX) { *policyIX = ix; }
4355 return true;
4356 }
4357 }
4358 /* Next best is just OID. */
4359 if (!searchName && searchOid && policyOid) {
4360 if (CFEqual(searchOid, policyOid)) {
4361 if (policyIX) { *policyIX = ix; }
4362 return true;
4363 }
4364 }
4365 if (!searchOid && searchName && policyName) {
4366 if (CFEqual(searchName, policyName)) {
4367 if (policyIX) { *policyIX = ix; }
4368 return true;
4369 }
4370 }
4371 }
4372 return false;
4373 }
4374
4375 static bool SecPVCContainsString(SecPVCRef pvc, CFIndex policyIX, CFStringRef stringValue) {
4376 if (!isString(stringValue)) {
4377 return false;
4378 }
4379 bool result = false;
4380
4381 CFStringRef tmpStringValue = NULL;
4382 if (CFStringGetCharacterAtIndex(stringValue, CFStringGetLength(stringValue) -1) == (UniChar)0x0000) {
4383 tmpStringValue = CFStringCreateTruncatedCopy(stringValue, CFStringGetLength(stringValue) - 1);
4384 } else {
4385 tmpStringValue = CFStringCreateCopy(NULL, stringValue);
4386 }
4387 if (policyIX >= 0 && policyIX < CFArrayGetCount(pvc->policies)) {
4388 SecPolicyRef policy = (SecPolicyRef)CFArrayGetValueAtIndex(pvc->policies, policyIX);
4389 /* Have to look for all the possible locations of name string */
4390 CFStringRef policyString = NULL;
4391 policyString = CFDictionaryGetValue(policy->_options, kSecPolicyCheckSSLHostname);
4392 if (!policyString) {
4393 policyString = CFDictionaryGetValue(policy->_options, kSecPolicyCheckEmail);
4394 }
4395 if (policyString && (CFStringCompare(tmpStringValue, policyString, kCFCompareCaseInsensitive) == kCFCompareEqualTo)) {
4396 result = true;
4397 goto out;
4398 }
4399
4400 CFArrayRef policyStrings = NULL;
4401 policyStrings = CFDictionaryGetValue(policy->_options, kSecPolicyCheckEAPTrustedServerNames);
4402 if (policyStrings && CFArrayContainsValue(policyStrings,
4403 CFRangeMake(0, CFArrayGetCount(policyStrings)),
4404 tmpStringValue)) {
4405 result = true;
4406 goto out;
4407 }
4408 }
4409
4410 out:
4411 CFReleaseNull(tmpStringValue);
4412 return result;
4413 }
4414
4415
4416 static uint32_t ts_key_usage_for_kuNumber(CFNumberRef keyUsageNumber) {
4417 uint32_t ourTSKeyUsage = 0;
4418 uint32_t keyUsage = 0;
4419 if (keyUsageNumber &&
4420 CFNumberGetValue(keyUsageNumber, kCFNumberSInt32Type, &keyUsage)) {
4421 if (keyUsage & kSecKeyUsageDigitalSignature) {
4422 ourTSKeyUsage |= kSecTrustSettingsKeyUseSignature;
4423 }
4424 if (keyUsage & kSecKeyUsageDataEncipherment) {
4425 ourTSKeyUsage |= kSecTrustSettingsKeyUseEnDecryptData;
4426 }
4427 if (keyUsage & kSecKeyUsageKeyEncipherment) {
4428 ourTSKeyUsage |= kSecTrustSettingsKeyUseEnDecryptKey;
4429 }
4430 if (keyUsage & kSecKeyUsageKeyAgreement) {
4431 ourTSKeyUsage |= kSecTrustSettingsKeyUseKeyExchange;
4432 }
4433 if (keyUsage == kSecKeyUsageAll) {
4434 ourTSKeyUsage = kSecTrustSettingsKeyUseAny;
4435 }
4436 }
4437 return ourTSKeyUsage;
4438 }
4439
4440 static uint32_t ts_key_usage_for_policy(SecPolicyRef policy) {
4441 uint32_t ourTSKeyUsage = 0;
4442 CFTypeRef policyKeyUsageType = NULL;
4443
4444 policyKeyUsageType = (CFTypeRef)CFDictionaryGetValue(policy->_options, kSecPolicyCheckKeyUsage);
4445 if (isArray(policyKeyUsageType)) {
4446 CFIndex ix, count = CFArrayGetCount(policyKeyUsageType);
4447 for (ix = 0; ix < count; ix++) {
4448 CFNumberRef policyKeyUsageNumber = NULL;
4449 policyKeyUsageNumber = (CFNumberRef)CFArrayGetValueAtIndex(policyKeyUsageType, ix);
4450 ourTSKeyUsage |= ts_key_usage_for_kuNumber(policyKeyUsageNumber);
4451 }
4452 } else if (isNumber(policyKeyUsageType)) {
4453 ourTSKeyUsage |= ts_key_usage_for_kuNumber(policyKeyUsageType);
4454 }
4455
4456 return ourTSKeyUsage;
4457 }
4458
4459 static bool SecPVCContainsTrustSettingsKeyUsage(SecPVCRef pvc,
4460 SecCertificateRef certificate, CFIndex policyIX, CFNumberRef keyUsageNumber) {
4461 int64_t keyUsageValue = 0;
4462 uint32_t ourKeyUsage = 0;
4463
4464 if (!isNumber(keyUsageNumber) || !CFNumberGetValue(keyUsageNumber, kCFNumberSInt64Type, &keyUsageValue)) {
4465 return false;
4466 }
4467
4468 if (keyUsageValue == kSecTrustSettingsKeyUseAny) {
4469 return true;
4470 }
4471
4472 /* We're using the key for revocation if we have the OCSPSigner policy.
4473 * @@@ If we support CRLs, we'd need to check for that policy here too.
4474 */
4475 if (SecPVCContainsPolicy(pvc, kSecPolicyAppleOCSPSigner, NULL, NULL)) {
4476 ourKeyUsage |= kSecTrustSettingsKeyUseSignRevocation;
4477 }
4478
4479 /* We're using the key for verifying a cert if it's a root/intermediate
4480 * in the chain. If the cert isn't in the path yet, we're about to add it,
4481 * so it's a root/intermediate. If there is no path, this is the leaf.
4482 */
4483 CFIndex pathIndex = -1;
4484 if (pvc->path) {
4485 pathIndex = SecCertificatePathGetIndexOfCertificate(pvc->path, certificate);
4486 } else {
4487 pathIndex = 0;
4488 }
4489 if (pathIndex != 0) {
4490 ourKeyUsage |= kSecTrustSettingsKeyUseSignCert;
4491 }
4492
4493 /* The rest of the key usages may be specified by the policy(ies). */
4494 if (policyIX >= 0 && policyIX < CFArrayGetCount(pvc->policies)) {
4495 SecPolicyRef policy = (SecPolicyRef)CFArrayGetValueAtIndex(pvc->policies, policyIX);
4496 ourKeyUsage |= ts_key_usage_for_policy(policy);
4497 } else {
4498 /* Get key usage from ALL policies */
4499 CFIndex ix, count = CFArrayGetCount(pvc->policies);
4500 for (ix = 0; ix < count; ix++) {
4501 SecPolicyRef policy = (SecPolicyRef)CFArrayGetValueAtIndex(pvc->policies, ix);
4502 ourKeyUsage |= ts_key_usage_for_policy(policy);
4503 }
4504 }
4505
4506 if (ourKeyUsage == (uint32_t)(keyUsageValue & 0x00ffffffff)) {
4507 return true;
4508 }
4509
4510 return false;
4511 }
4512
4513 #if TARGET_OS_MAC && !TARGET_OS_IPHONE
4514
4515 #include <Security/SecTrustedApplicationPriv.h>
4516 #include <bsm/libbsm.h>
4517 #include <libproc.h>
4518
4519 static bool SecPVCCallerIsApplication(CFDataRef clientAuditToken, CFTypeRef appRef) {
4520 bool result = false;
4521 audit_token_t auditToken = {};
4522 char path[MAXPATHLEN];
4523
4524 require(appRef && clientAuditToken, out);
4525 require(CFGetTypeID(appRef) == SecTrustedApplicationGetTypeID(), out);
4526
4527 require(sizeof(auditToken) == CFDataGetLength(clientAuditToken), out);
4528 CFDataGetBytes(clientAuditToken, CFRangeMake(0, sizeof(auditToken)), (uint8_t *)&auditToken);
4529 require(proc_pidpath(audit_token_to_pid(auditToken), path, sizeof(path)) > 0, out);
4530
4531 if(errSecSuccess == SecTrustedApplicationValidateWithPath((SecTrustedApplicationRef)appRef, path)) {
4532 result = true;
4533 }
4534
4535 out:
4536 return result;
4537 }
4538 #endif
4539
4540 static bool SecPVCContainsTrustSettingsPolicyOption(SecPVCRef pvc, CFDictionaryRef options) {
4541 if (!isDictionary(options)) {
4542 return false;
4543 }
4544
4545 /* Push */
4546 CFDictionaryRef currentCallbacks = pvc->callbacks;
4547
4548 /* We need to run the leaf and path checks using these options. */
4549 pvc->callbacks = gSecPolicyLeafCallbacks;
4550 CFDictionaryApplyFunction(options, SecPVCValidateKey, pvc);
4551
4552 pvc->callbacks = gSecPolicyPathCallbacks;
4553 CFDictionaryApplyFunction(options, SecPVCValidateKey, pvc);
4554
4555 /* Pop */
4556 pvc->callbacks = currentCallbacks;
4557
4558 /* Our work here is done; no need to claim a match */
4559 return false;
4560 }
4561
4562 static bool SecPVCMeetsConstraint(SecPVCRef pvc, SecCertificateRef certificate, CFDictionaryRef constraint) {
4563 CFStringRef policyOid = NULL, policyString = NULL, policyName = NULL;
4564 CFNumberRef keyUsageNumber = NULL;
4565 CFTypeRef trustedApplicationData = NULL;
4566 CFDictionaryRef policyOptions = NULL;
4567
4568 bool policyMatch = false, policyStringMatch = false, applicationMatch = false ,
4569 keyUsageMatch = false, policyOptionMatch = false;
4570 bool result = false;
4571
4572 #if TARGET_OS_MAC && !TARGET_OS_IPHONE
4573 /* OS X returns a SecPolicyRef in the constraints. Convert to the oid string. */
4574 SecPolicyRef policy = NULL;
4575 policy = (SecPolicyRef)CFDictionaryGetValue(constraint, kSecTrustSettingsPolicy);
4576 policyOid = (policy) ? policy->_oid : NULL;
4577 #else
4578 policyOid = (CFStringRef)CFDictionaryGetValue(constraint, kSecTrustSettingsPolicy);
4579 #endif
4580 policyName = (CFStringRef)CFDictionaryGetValue(constraint, kSecTrustSettingsPolicyName);
4581 policyString = (CFStringRef)CFDictionaryGetValue(constraint, kSecTrustSettingsPolicyString);
4582 keyUsageNumber = (CFNumberRef)CFDictionaryGetValue(constraint, kSecTrustSettingsKeyUsage);
4583 policyOptions = (CFDictionaryRef)CFDictionaryGetValue(constraint, kSecTrustSettingsPolicyOptions);
4584
4585 CFIndex policyIX = -1;
4586 policyMatch = SecPVCContainsPolicy(pvc, policyOid, policyName, &policyIX);
4587 policyStringMatch = SecPVCContainsString(pvc, policyIX, policyString);
4588 keyUsageMatch = SecPVCContainsTrustSettingsKeyUsage(pvc, certificate, policyIX, keyUsageNumber);
4589 policyOptionMatch = SecPVCContainsTrustSettingsPolicyOption(pvc, policyOptions);
4590
4591 #if TARGET_OS_MAC && !TARGET_OS_IPHONE
4592 trustedApplicationData = CFDictionaryGetValue(constraint, kSecTrustSettingsApplication);
4593 CFDataRef clientAuditToken = SecPathBuilderCopyClientAuditToken(pvc->builder);
4594 applicationMatch = SecPVCCallerIsApplication(clientAuditToken, trustedApplicationData);
4595 CFReleaseNull(clientAuditToken);
4596 #else
4597 if(CFDictionaryContainsKey(constraint, kSecTrustSettingsApplication)) {
4598 secerror("kSecTrustSettingsApplication is not yet supported on this platform");
4599 }
4600 #endif
4601
4602 /* If we either didn't find the parameter in the dictionary or we got a match
4603 * against that parameter, for all possible parameters in the dictionary, then
4604 * this trust setting result applies to the output. */
4605 if (((!policyOid && !policyName) || policyMatch) &&
4606 (!policyString || policyStringMatch) &&
4607 (!trustedApplicationData || applicationMatch) &&
4608 (!keyUsageNumber || keyUsageMatch) &&
4609 (!policyOptions || policyOptionMatch)) {
4610 result = true;
4611 }
4612
4613 return result;
4614 }
4615
4616 SecTrustSettingsResult SecPVCGetTrustSettingsResult(SecPVCRef pvc, SecCertificateRef certificate, CFArrayRef constraints) {
4617 SecTrustSettingsResult result = kSecTrustSettingsResultInvalid;
4618 CFIndex constraintIX, constraintCount = CFArrayGetCount(constraints);
4619 for (constraintIX = 0; constraintIX < constraintCount; constraintIX++) {
4620 CFDictionaryRef constraint = (CFDictionaryRef)CFArrayGetValueAtIndex(constraints, constraintIX);
4621 if (!isDictionary(constraint)) {
4622 continue;
4623 }
4624
4625 CFNumberRef resultNumber = NULL;
4626 resultNumber = (CFNumberRef)CFDictionaryGetValue(constraint, kSecTrustSettingsResult);
4627 uint32_t resultValue = kSecTrustSettingsResultInvalid;
4628 if (!isNumber(resultNumber) || !CFNumberGetValue(resultNumber, kCFNumberSInt32Type, &resultValue)) {
4629 /* no SecTrustSettingsResult entry defaults to TrustRoot*/
4630 resultValue = kSecTrustSettingsResultTrustRoot;
4631 }
4632
4633 if (SecPVCMeetsConstraint(pvc, certificate, constraint)) {
4634 result = resultValue;
4635 break;
4636 }
4637 }
4638 return result;
4639 }
4640
4641 bool SecPVCCheckUsageConstraints(SecPVCRef pvc) {
4642 bool shouldDeny = false;
4643 CFIndex certIX, certCount = SecCertificatePathGetCount(pvc->path);
4644 for (certIX = 0; certIX < certCount; certIX++) {
4645 CFArrayRef constraints = SecCertificatePathGetUsageConstraintsAtIndex(pvc->path, certIX);
4646 SecCertificateRef cert = SecCertificatePathGetCertificateAtIndex(pvc->path, certIX);
4647 SecTrustSettingsResult result = SecPVCGetTrustSettingsResult(pvc, cert, constraints);
4648
4649 if (result == kSecTrustSettingsResultDeny) {
4650 SecPVCSetResultForced(pvc, kSecPolicyCheckUsageConstraints, certIX, kCFBooleanFalse, true);
4651 shouldDeny = true;
4652 }
4653 }
4654 return shouldDeny;
4655 }
4656
4657 #define kSecPolicySHA256Size 32
4658 static const UInt8 kTestDateConstraintsRoot[kSecPolicySHA256Size] = {
4659 0x51,0xA0,0xF3,0x1F,0xC0,0x1D,0xEC,0x87,0x32,0xB6,0xFD,0x13,0x6A,0x43,0x4D,0x6C,
4660 0x87,0xCD,0x62,0xE0,0x38,0xB4,0xFB,0xD6,0x40,0xB0,0xFD,0x62,0x4D,0x1F,0xCF,0x6D
4661 };
4662 static const UInt8 kWS_CA1_G2[kSecPolicySHA256Size] = {
4663 0xD4,0x87,0xA5,0x6F,0x83,0xB0,0x74,0x82,0xE8,0x5E,0x96,0x33,0x94,0xC1,0xEC,0xC2,
4664 0xC9,0xE5,0x1D,0x09,0x03,0xEE,0x94,0x6B,0x02,0xC3,0x01,0x58,0x1E,0xD9,0x9E,0x16
4665 };
4666 static const UInt8 kWS_CA1_NEW[kSecPolicySHA256Size] = {
4667 0x4B,0x22,0xD5,0xA6,0xAE,0xC9,0x9F,0x3C,0xDB,0x79,0xAA,0x5E,0xC0,0x68,0x38,0x47,
4668 0x9C,0xD5,0xEC,0xBA,0x71,0x64,0xF7,0xF2,0x2D,0xC1,0xD6,0x5F,0x63,0xD8,0x57,0x08
4669 };
4670 static const UInt8 kWS_CA2_NEW[kSecPolicySHA256Size] = {
4671 0xD6,0xF0,0x34,0xBD,0x94,0xAA,0x23,0x3F,0x02,0x97,0xEC,0xA4,0x24,0x5B,0x28,0x39,
4672 0x73,0xE4,0x47,0xAA,0x59,0x0F,0x31,0x0C,0x77,0xF4,0x8F,0xDF,0x83,0x11,0x22,0x54
4673 };
4674 static const UInt8 kWS_ECC[kSecPolicySHA256Size] = {
4675 0x8B,0x45,0xDA,0x1C,0x06,0xF7,0x91,0xEB,0x0C,0xAB,0xF2,0x6B,0xE5,0x88,0xF5,0xFB,
4676 0x23,0x16,0x5C,0x2E,0x61,0x4B,0xF8,0x85,0x56,0x2D,0x0D,0xCE,0x50,0xB2,0x9B,0x02
4677 };
4678 static const UInt8 kSC_SFSCA[kSecPolicySHA256Size] = {
4679 0xC7,0x66,0xA9,0xBE,0xF2,0xD4,0x07,0x1C,0x86,0x3A,0x31,0xAA,0x49,0x20,0xE8,0x13,
4680 0xB2,0xD1,0x98,0x60,0x8C,0xB7,0xB7,0xCF,0xE2,0x11,0x43,0xB8,0x36,0xDF,0x09,0xEA
4681 };
4682 static const UInt8 kSC_SHA2[kSecPolicySHA256Size] = {
4683 0xE1,0x78,0x90,0xEE,0x09,0xA3,0xFB,0xF4,0xF4,0x8B,0x9C,0x41,0x4A,0x17,0xD6,0x37,
4684 0xB7,0xA5,0x06,0x47,0xE9,0xBC,0x75,0x23,0x22,0x72,0x7F,0xCC,0x17,0x42,0xA9,0x11
4685 };
4686 static const UInt8 kSC_G2[kSecPolicySHA256Size] = {
4687 0xC7,0xBA,0x65,0x67,0xDE,0x93,0xA7,0x98,0xAE,0x1F,0xAA,0x79,0x1E,0x71,0x2D,0x37,
4688 0x8F,0xAE,0x1F,0x93,0xC4,0x39,0x7F,0xEA,0x44,0x1B,0xB7,0xCB,0xE6,0xFD,0x59,0x95
4689 };
4690
4691 bool SecPVCCheckIssuerDateConstraints(SecPVCRef pvc) {
4692 static CFSetRef sConstrainedRoots = NULL;
4693 static dispatch_once_t _t;
4694 dispatch_once(&_t, ^{
4695 const UInt8 *v_hashes[] = {
4696 kWS_CA1_G2, kWS_CA1_NEW, kWS_CA2_NEW, kWS_ECC,
4697 kSC_SFSCA, kSC_SHA2, kSC_G2, kTestDateConstraintsRoot
4698 };
4699 CFMutableSetRef set = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks);
4700 CFIndex ix, count = sizeof(v_hashes)/sizeof(*v_hashes);
4701 for (ix=0; ix<count; ix++) {
4702 CFDataRef hash = CFDataCreateWithBytesNoCopy(NULL, v_hashes[ix],
4703 kSecPolicySHA256Size, kCFAllocatorNull);
4704 if (hash) {
4705 CFSetAddValue(set, hash);
4706 CFRelease(hash);
4707 }
4708 }
4709 sConstrainedRoots = set;
4710 });
4711
4712 bool shouldDeny = false;
4713 CFIndex certIX, certCount = SecCertificatePathGetCount(pvc->path);
4714 for (certIX = certCount - 1; certIX >= 0 && !shouldDeny; certIX--) {
4715 SecCertificateRef cert = SecCertificatePathGetCertificateAtIndex(pvc->path, certIX);
4716 CFDataRef sha256 = SecCertificateCopySHA256Digest(cert);
4717 if (sha256 && CFSetContainsValue(sConstrainedRoots, sha256)) {
4718 /* matched a constrained root; check notBefore dates on all its children. */
4719 CFIndex childIX = certIX;
4720 while (--childIX >= 0) {
4721 SecCertificateRef child = SecCertificatePathGetCertificateAtIndex(pvc->path, childIX);
4722 /* 1 Dec 2016 00:00:00 GMT */
4723 if (child && (CFAbsoluteTime)502243200.0 <= SecCertificateNotValidBefore(child)) {
4724 SecPVCSetResultForced(pvc, kSecPolicyCheckBlackListedKey, certIX, kCFBooleanFalse, true);
4725 shouldDeny = true;
4726 break;
4727 }
4728 }
4729 }
4730 CFReleaseNull(sha256);
4731 }
4732 return shouldDeny;
4733 }
4734
4735 /* AUDIT[securityd](done):
4736 policy->_options is a caller provided dictionary, only its cf type has
4737 been checked.
4738 */
4739 bool SecPVCPathChecks(SecPVCRef pvc) {
4740 secdebug("policy", "begin path: %@", pvc->path);
4741 bool completed = true;
4742 /* This needs to be initialized before we call any function that might call
4743 SecPVCSetResultForced(). */
4744 pvc->policyIX = 0;
4745 SecPolicyCheckIdLinkage(pvc, kSecPolicyCheckIdLinkage);
4746 if (pvc->result || pvc->details) {
4747 SecPolicyCheckBasicCertificateProcessing(pvc,
4748 kSecPolicyCheckBasicCertificateProcessing);
4749 }
4750
4751 CFArrayRef policies = pvc->policies;
4752 CFIndex count = CFArrayGetCount(policies);
4753 for (; pvc->policyIX < count; ++pvc->policyIX) {
4754 /* Validate all keys for all policies. */
4755 pvc->callbacks = gSecPolicyPathCallbacks;
4756 SecPolicyRef policy = SecPVCGetPolicy(pvc);
4757 CFDictionaryApplyFunction(policy->_options, SecPVCValidateKey, pvc);
4758 if (!pvc->result && !pvc->details)
4759 return completed;
4760 }
4761
4762 // Reset
4763 pvc->policyIX = 0;
4764
4765 /* Check whether the TrustSettings say to deny a cert in the path. */
4766 (void)SecPVCCheckUsageConstraints(pvc);
4767
4768 /* Check for issuer date constraints. */
4769 (void)SecPVCCheckIssuerDateConstraints(pvc);
4770
4771 /* Check the things we can't check statically for the certificate path. */
4772 /* Critical Extensions, chainLength. */
4773
4774 /* Policy tests. */
4775 pvc->is_ev = false;
4776 if ((pvc->result || pvc->details) && pvc->optionally_ev) {
4777 bool pre_ev_check_result = pvc->result;
4778 SecPolicyCheckEV(pvc, kSecPolicyCheckExtendedValidation);
4779 pvc->is_ev = pvc->result;
4780 /* If ev checking failed, we still want to accept this chain
4781 as a non EV one, if it was valid as such. */
4782 pvc->result = pre_ev_check_result;
4783 }
4784
4785 /* Check revocation always, since we don't want a lesser recoverable result
4786 * to prevent the check from occurring. */
4787 completed = SecPVCCheckRevocation(pvc);
4788
4789 /* Check for CT */
4790 if (pvc->result || pvc->details) {
4791 /* This call will set the value of pvc->is_ct, but won't change the result (pvc->result) */
4792 SecPolicyCheckCT(pvc, kSecPolicyCheckCertificateTransparency);
4793 }
4794
4795 if (pvc->is_ev && !pvc->is_ct) {
4796 pvc->is_ct_whitelisted = SecPVCCheckCTWhiteListedLeaf(pvc);
4797 } else {
4798 pvc->is_ct_whitelisted = false;
4799 }
4800
4801 //errOut:
4802 secdebug("policy", "end %strusted completed: %d path: %@",
4803 (pvc->result ? "" : "not "), completed, pvc->path);
4804 return completed;
4805 }
4806
4807 /* This function returns 0 to indicate revocation checking was not completed
4808 for this certificate chain, otherwise return to date at which the first
4809 piece of revocation checking info we used expires. */
4810 CFAbsoluteTime SecPVCGetEarliestNextUpdate(SecPVCRef pvc) {
4811 CFIndex certIX, certCount = SecPVCGetCertificateCount(pvc);
4812 CFAbsoluteTime enu = NULL_TIME;
4813 if (certCount <= 1 || !pvc->rvcs) {
4814 return enu;
4815 }
4816 certCount--;
4817
4818 for (certIX = 0; certIX < certCount; ++certIX) {
4819 SecRVCRef rvc = &((SecRVCRef)pvc->rvcs)[certIX];
4820 CFAbsoluteTime thisCertNextUpdate = SecRVCGetEarliestNextUpdate(rvc);
4821 if (thisCertNextUpdate == 0) {
4822 if (certIX > 0) {
4823 /* We allow for CA certs to not be revocation checked if they
4824 have no ocspResponders nor CRLDPs to check against, but the leaf
4825 must be checked in order for us to claim we did revocation
4826 checking. */
4827 SecCertificateRef cert =
4828 SecPVCGetCertificateAtIndex(rvc->pvc, rvc->certIX);
4829 CFArrayRef ocspResponders = NULL;
4830 ocspResponders = SecCertificateGetOCSPResponders(cert);
4831 #if ENABLE_CRLS
4832 CFArrayRef crlDPs = NULL;
4833 crlDPs = SecCertificateGetCRLDistributionPoints(cert);
4834 #endif
4835 if ((!ocspResponders || CFArrayGetCount(ocspResponders) == 0)
4836 #if ENABLE_CRLS
4837 && (!crlDPs || CFArrayGetCount(crlDPs) == 0)
4838 #endif
4839 ) {
4840 /* We can't check this cert so we don't consider it a soft
4841 failure that we didn't. Ideally we should support crl
4842 checking and remove this workaround, since that more
4843 strict. */
4844 continue;
4845 }
4846 }
4847 secdebug("rvc", "revocation checking soft failure for cert: %ld",
4848 certIX);
4849 enu = thisCertNextUpdate;
4850 break;
4851 }
4852 if (enu == 0 || thisCertNextUpdate < enu) {
4853 enu = thisCertNextUpdate;
4854 }
4855 }
4856
4857 secdebug("rvc", "revocation valid until: %lg", enu);
4858 return enu;
4859 }