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