]> git.saurik.com Git - apple/security.git/blob - OSX/sec/securityd/SecPolicyServer.c
Security-57740.31.2.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 for the authority key of the
1190 certificate at certix, false otherwise.
1191 */
1192 static bool SecPVCCheckCertificateAllowList(SecPVCRef pvc, CFIndex certix)
1193 {
1194 bool result = false;
1195 CFIndex ix = 0, count = SecPVCGetCertificateCount(pvc);
1196 CFStringRef authKey = NULL;
1197 CFArrayRef allowedCerts = NULL;
1198 SecOTAPKIRef otapkiRef = NULL;
1199
1200 if (certix < 0 || certix >= count) {
1201 return result;
1202 }
1203
1204 //get authKeyID from the specified cert in the chain
1205 SecCertificateRef issuedCert = SecPVCGetCertificateAtIndex(pvc, certix);
1206 CFDataRef authKeyID = SecCertificateGetAuthorityKeyID(issuedCert);
1207 if (NULL == authKeyID) {
1208 return result;
1209 }
1210 authKey = CFDataCopyHexString(authKeyID);
1211 if (NULL == authKey) {
1212 goto errout;
1213 }
1214
1215 otapkiRef = SecOTAPKICopyCurrentOTAPKIRef();
1216 if (NULL == otapkiRef) {
1217 goto errout;
1218 }
1219
1220 allowedCerts = SecOTAPKICopyAllowListForAuthKeyID(otapkiRef, authKey);
1221 if (NULL == allowedCerts || !CFArrayGetCount(allowedCerts)) {
1222 goto errout;
1223 }
1224
1225 //search sorted array for the SHA256 hash of a cert in the chain
1226 CFRange range = CFRangeMake(0, CFArrayGetCount(allowedCerts));
1227 for (ix = 0; ix <= certix; ix++) {
1228 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix);
1229 if (!cert) {
1230 goto errout;
1231 }
1232
1233 CFDataRef certHash = SecCertificateCopySHA256Digest(cert);
1234 if (!certHash) {
1235 goto errout;
1236 }
1237
1238 CFIndex position = CFArrayBSearchValues(allowedCerts, range, certHash,
1239 (CFComparatorFunction)CFDataCompare, NULL);
1240 if (position < CFArrayGetCount(allowedCerts)) {
1241 CFDataRef possibleMatch = CFArrayGetValueAtIndex(allowedCerts, position);
1242 if (!CFDataCompare(certHash, possibleMatch)) {
1243 //this cert is in the allowlist
1244 result = true;
1245 }
1246 }
1247
1248 CFRelease(certHash);
1249 }
1250
1251 errout:
1252 CFReleaseNull(authKey);
1253 CFReleaseNull(otapkiRef);
1254 CFReleaseNull(allowedCerts);
1255 return result;
1256 }
1257
1258 #define DCMP(_idx_) memcmp(data+(8*_idx_), digest, 8)
1259
1260 /* Returns true if leaf is on the CT whitelist */
1261 static bool SecPVCCheckCTWhiteListedLeaf(SecPVCRef pvc)
1262 {
1263 SecOTAPKIRef otapkiRef = NULL;
1264 CFDataRef whiteList = NULL;
1265 SecCertificateRef cert = NULL;
1266 CFDataRef dgst = NULL;
1267 bool result = false;
1268 const uint8_t *digest = NULL;
1269 const uint8_t *data = NULL;
1270 require(otapkiRef = SecOTAPKICopyCurrentOTAPKIRef(), out);
1271 require(whiteList = SecOTAPKICopyCTWhiteList(otapkiRef), out);
1272 require(cert = SecPVCGetCertificateAtIndex(pvc, 0), out);
1273 require(dgst = SecCertificateCopySHA256Digest(cert), out);
1274
1275 digest = CFDataGetBytePtr(dgst);
1276 data = CFDataGetBytePtr(whiteList);
1277 CFIndex l = 0;
1278 CFIndex h = CFDataGetLength(whiteList)/8-1;
1279
1280 if(DCMP(l)==0 || DCMP(h)==0) {
1281 result = true;
1282 goto out;
1283 }
1284
1285 if(DCMP(l)>0 || DCMP(h)<0) {
1286 goto out;
1287 }
1288
1289 while((h-l)>1) {
1290 CFIndex i = (h+l)/
1291 2;
1292 int s = DCMP(i);
1293 if(s == 0) {
1294 result = true;
1295 goto out;
1296 } else if(s < 0) {
1297 l = i;
1298 } else {
1299 h = i;
1300 }
1301 }
1302
1303 out:
1304 CFReleaseSafe(dgst);
1305 CFReleaseSafe(whiteList);
1306 CFReleaseSafe(otapkiRef);
1307 return result;
1308 }
1309
1310 /****************************************************************************
1311 *********************** New rfc5280 Chain Validation ***********************
1312 ****************************************************************************/
1313
1314 #if 0
1315 typedef struct cert_path *cert_path_t;
1316 struct cert_path {
1317 int length;
1318 };
1319
1320 typedef struct x500_name *x500_name_t;
1321 struct x500_name {
1322 };
1323
1324 typedef struct algorithm_id *algorithm_id_t;
1325 struct algorithm_id {
1326 oid_t algorithm_oid;
1327 der_t parameters;
1328 };
1329
1330 typedef struct trust_anchor *trust_anchor_t;
1331 struct trust_anchor {
1332 x500_name_t issuer_name;
1333 algorithm_id_t public_key_algorithm; /* includes optional params */
1334 SecKeyRef public_key;
1335 };
1336
1337 typedef struct certificate_policy *certificate_policy_t;
1338 struct certificate_policy {
1339 policy_qualifier_t qualifiers;
1340 oid_t oid;
1341 SLIST_ENTRY(certificate_policy) policies;
1342 };
1343
1344 typedef struct policy_mapping *policy_mapping_t;
1345 struct policy_mapping {
1346 SLIST_ENTRY(policy_mapping) mappings;
1347 oid_t issuer_domain_policy;
1348 oid_t subject_domain_policy;
1349 };
1350
1351 typedef struct root_name *root_name_t;
1352 struct root_name {
1353 };
1354 #endif
1355
1356 struct policy_tree_add_ctx {
1357 oid_t p_oid;
1358 policy_qualifier_t p_q;
1359 };
1360
1361 /* 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}. */
1362 static bool policy_tree_add_if_match(policy_tree_t node, void *ctx) {
1363 struct policy_tree_add_ctx *info = (struct policy_tree_add_ctx *)ctx;
1364 policy_set_t policy_set;
1365 for (policy_set = node->expected_policy_set;
1366 policy_set;
1367 policy_set = policy_set->oid_next) {
1368 if (oid_equal(policy_set->oid, info->p_oid)) {
1369 policy_tree_add_child(node, &info->p_oid, info->p_q);
1370 return true;
1371 }
1372 }
1373 return false;
1374 }
1375
1376 /* 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}. */
1377 static bool policy_tree_add_if_any(policy_tree_t node, void *ctx) {
1378 struct policy_tree_add_ctx *info = (struct policy_tree_add_ctx *)ctx;
1379 if (oid_equal(node->valid_policy, oidAnyPolicy)) {
1380 policy_tree_add_child(node, &info->p_oid, info->p_q);
1381 return true;
1382 }
1383 return false;
1384 }
1385
1386 /* Return true iff node has a child with a valid_policy equal to oid. */
1387 static bool policy_tree_has_child_with_oid(policy_tree_t node,
1388 const oid_t *oid) {
1389 policy_tree_t child;
1390 for (child = node->children; child; child = child->siblings) {
1391 if (oid_equal(child->valid_policy, (*oid))) {
1392 return true;
1393 }
1394 }
1395 return false;
1396 }
1397
1398 /* 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. */
1399 static bool policy_tree_add_expected(policy_tree_t node, void *ctx) {
1400 policy_qualifier_t p_q = (policy_qualifier_t)ctx;
1401 policy_set_t policy_set;
1402 bool added_node = false;
1403 for (policy_set = node->expected_policy_set;
1404 policy_set;
1405 policy_set = policy_set->oid_next) {
1406 if (!policy_tree_has_child_with_oid(node, &policy_set->oid)) {
1407 policy_tree_add_child(node, &policy_set->oid, p_q);
1408 added_node = true;
1409 }
1410 }
1411 return added_node;
1412 }
1413
1414 #if 0
1415 /* 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. */
1416 static bool policy_tree_map(policy_tree_t node, void *ctx) {
1417 /* Can't map oidAnyPolicy. */
1418 if (oid_equal(node->valid_policy, oidAnyPolicy))
1419 return false;
1420
1421 const SecCEPolicyMappings *pm = (const SecCEPolicyMappings *)ctx;
1422 uint32_t mapping_ix, mapping_count = pm->numMappings;
1423 policy_set_t policy_set = NULL;
1424 /* First count how many mappings match this nodes valid_policy. */
1425 for (mapping_ix = 0; mapping_ix < mapping_count; ++mapping_ix) {
1426 const SecCEPolicyMapping *mapping = &pm->mappings[mapping_ix];
1427 if (oid_equal(node->valid_policy, mapping->issuerDomainPolicy)) {
1428 policy_set_t p_node = (policy_set_t)malloc(sizeof(*policy_set));
1429 p_node->oid = mapping->subjectDomainPolicy;
1430 p_node->oid_next = policy_set ? policy_set : NULL;
1431 policy_set = p_node;
1432 }
1433 }
1434 if (policy_set) {
1435 policy_tree_set_expected_policy(node, policy_set);
1436 return true;
1437 }
1438 return false;
1439 }
1440 #endif
1441
1442 #define POLICY_MAPPING 0
1443 #define POLICY_SUBTREES 1
1444
1445 /* rfc5280 basic cert processing. */
1446 static void SecPolicyCheckBasicCertificateProcessing(SecPVCRef pvc,
1447 CFStringRef key) {
1448 /* Inputs */
1449 //cert_path_t path;
1450 CFIndex count = SecPVCGetCertificateCount(pvc);
1451 /* 64 bits cast: worst case here is we truncate the number of cert, and the validation may fail */
1452 assert((unsigned long)count<=UINT32_MAX); /* Debug check. Correct as long as CFIndex is long */
1453 uint32_t n = (uint32_t)count;
1454 bool is_anchored = SecPVCIsAnchored(pvc);
1455 if (is_anchored) {
1456 /* If the anchor is trusted we don't process the last cert in the
1457 chain (root). */
1458 n--;
1459 } else {
1460 /* trust may be restored for a path with an untrusted root that matches the allow list */
1461 pvc->is_allowlisted = SecPVCCheckCertificateAllowList(pvc, n - 1);
1462 if (!pvc->is_allowlisted) {
1463 /* Add a detail for the root not being trusted. */
1464 if (SecPVCSetResultForced(pvc, kSecPolicyCheckAnchorTrusted,
1465 n - 1, kCFBooleanFalse, true))
1466 return;
1467 }
1468 }
1469
1470 CFAbsoluteTime verify_time = SecPVCGetVerifyTime(pvc);
1471 //policy_set_t user_initial_policy_set = NULL;
1472 //trust_anchor_t anchor;
1473 bool initial_policy_mapping_inhibit = false;
1474 bool initial_explicit_policy = false;
1475 bool initial_any_policy_inhibit = false;
1476
1477 /* Initialization */
1478 pvc->valid_policy_tree = policy_tree_create(&oidAnyPolicy, NULL);
1479 #if POLICY_SUBTREES
1480 CFMutableArrayRef permitted_subtrees = NULL;
1481 CFMutableArrayRef excluded_subtrees = NULL;
1482 permitted_subtrees = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
1483 excluded_subtrees = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
1484 require_action_quiet(permitted_subtrees != NULL, errOut,
1485 SecPVCSetResultForced(pvc, key, 0, kCFBooleanFalse, true));
1486 require_action_quiet(excluded_subtrees != NULL, errOut,
1487 SecPVCSetResultForced(pvc, key, 0, kCFBooleanFalse, true));
1488 #endif
1489 uint32_t explicit_policy = initial_explicit_policy ? 0 : n + 1;
1490 uint32_t inhibit_any_policy = initial_any_policy_inhibit ? 0 : n + 1;
1491 uint32_t policy_mapping = initial_policy_mapping_inhibit ? 0 : n + 1;
1492
1493 #if 0
1494 /* Path builder ensures we only get cert chains with proper issuer
1495 chaining with valid signatures along the way. */
1496 algorithm_id_t working_public_key_algorithm = anchor->public_key_algorithm;
1497 SecKeyRef working_public_key = anchor->public_key;
1498 x500_name_t working_issuer_name = anchor->issuer_name;
1499 #endif
1500 uint32_t i, max_path_length = n;
1501 SecCertificateRef cert = NULL;
1502 for (i = 1; i <= n; ++i) {
1503 /* Process Cert */
1504 cert = SecPVCGetCertificateAtIndex(pvc, n - i);
1505 bool is_self_issued = SecPVCIsCertificateAtIndexSelfSigned(pvc, n - i);
1506
1507 /* (a) Verify the basic certificate information. */
1508 /* @@@ Ensure that cert was signed with working_public_key_algorithm
1509 using the working_public_key and the working_public_key_parameters. */
1510 #if 1
1511 /* Already done by chain builder. */
1512 if (!SecCertificateIsValid(cert, verify_time)) {
1513 CFStringRef fail_key = i == n ? kSecPolicyCheckValidLeaf : kSecPolicyCheckValidIntermediates;
1514 if (!SecPVCSetResult(pvc, fail_key, n - i, kCFBooleanFalse)) {
1515 goto errOut;
1516 }
1517 }
1518 if (SecCertificateIsWeakKey(cert)) {
1519 CFStringRef fail_key = i == n ? kSecPolicyCheckWeakLeaf : kSecPolicyCheckWeakIntermediates;
1520 if (!SecPVCSetResult(pvc, fail_key, n - i, kCFBooleanFalse)) {
1521 goto errOut;
1522 }
1523 }
1524 #endif
1525 /* @@@ cert.issuer == working_issuer_name. */
1526
1527 #if POLICY_SUBTREES
1528 /* (b) (c) */
1529 if (!is_self_issued || i == n) {
1530 bool found = false;
1531 /* Verify certificate Subject Name and SubjectAltNames are not within any of the excluded_subtrees */
1532 if(excluded_subtrees && CFArrayGetCount(excluded_subtrees)) {
1533 if ((errSecSuccess != SecNameContraintsMatchSubtrees(cert, excluded_subtrees, &found, false)) || found) {
1534 secnotice("policy", "name in excluded subtrees");
1535 if(!SecPVCSetResultForced(pvc, key, n - i, kCFBooleanFalse, true)) { goto errOut; }
1536 }
1537 }
1538 /* Verify certificate Subject Name and SubjectAltNames are within the permitted_subtrees */
1539 if(permitted_subtrees && CFArrayGetCount(permitted_subtrees)) {
1540 if ((errSecSuccess != SecNameContraintsMatchSubtrees(cert, permitted_subtrees, &found, true)) || !found) {
1541 secnotice("policy", "name not in permitted subtrees");
1542 if(!SecPVCSetResultForced(pvc, key, n - i, kCFBooleanFalse, true)) { goto errOut; }
1543 }
1544 }
1545 }
1546 #endif
1547 /* (d) */
1548 if (pvc->valid_policy_tree) {
1549 const SecCECertificatePolicies *cp =
1550 SecCertificateGetCertificatePolicies(cert);
1551 size_t policy_ix, policy_count = cp ? cp->numPolicies : 0;
1552 for (policy_ix = 0; policy_ix < policy_count; ++policy_ix) {
1553 const SecCEPolicyInformation *policy = &cp->policies[policy_ix];
1554 oid_t p_oid = policy->policyIdentifier;
1555 policy_qualifier_t p_q = &policy->policyQualifiers;
1556 struct policy_tree_add_ctx ctx = { p_oid, p_q };
1557 if (!oid_equal(p_oid, oidAnyPolicy)) {
1558 if (!policy_tree_walk_depth(pvc->valid_policy_tree, i - 1,
1559 policy_tree_add_if_match, &ctx)) {
1560 policy_tree_walk_depth(pvc->valid_policy_tree, i - 1,
1561 policy_tree_add_if_any, &ctx);
1562 }
1563 }
1564 }
1565 /* The certificate policies extension includes the policy
1566 anyPolicy with the qualifier set AP-Q and either
1567 (a) inhibit_anyPolicy is greater than 0 or
1568 (b) i < n and the certificate is self-issued. */
1569 if (inhibit_any_policy > 0 || (i < n && is_self_issued)) {
1570 for (policy_ix = 0; policy_ix < policy_count; ++policy_ix) {
1571 const SecCEPolicyInformation *policy = &cp->policies[policy_ix];
1572 oid_t p_oid = policy->policyIdentifier;
1573 policy_qualifier_t p_q = &policy->policyQualifiers;
1574 if (oid_equal(p_oid, oidAnyPolicy)) {
1575 policy_tree_walk_depth(pvc->valid_policy_tree, i - 1,
1576 policy_tree_add_expected, (void *)p_q);
1577 }
1578 }
1579 }
1580 policy_tree_prune_childless(&pvc->valid_policy_tree, i - 1);
1581 /* (e) */
1582 if (!cp) {
1583 if (pvc->valid_policy_tree)
1584 policy_tree_prune(&pvc->valid_policy_tree);
1585 }
1586 }
1587 /* (f) Verify that either explicit_policy is greater than 0 or the
1588 valid_policy_tree is not equal to NULL. */
1589 if (!pvc->valid_policy_tree && explicit_policy == 0) {
1590 /* valid_policy_tree is empty and explicit policy is 0, illegal. */
1591 secnotice("policy", "policy tree failure");
1592 if (!SecPVCSetResultForced(pvc, key /* @@@ Need custom key */, n - i, kCFBooleanFalse, true)) {
1593 goto errOut;
1594 }
1595 }
1596 /* If Last Cert in Path */
1597 if (i == n)
1598 break;
1599
1600 /* Prepare for Next Cert */
1601 #if POLICY_MAPPING
1602 /* (a) verify that anyPolicy does not appear as an
1603 issuerDomainPolicy or a subjectDomainPolicy */
1604 CFDictionaryRef pm = SecCertificateGetPolicyMappings(cert);
1605 if (pm) {
1606 uint32_t mapping_ix, mapping_count = pm->numMappings;
1607 for (mapping_ix = 0; mapping_ix < mapping_count; ++mapping_ix) {
1608 const SecCEPolicyMapping *mapping = &pm->mappings[mapping_ix];
1609 if (oid_equal(mapping->issuerDomainPolicy, oidAnyPolicy)
1610 || oid_equal(mapping->subjectDomainPolicy, oidAnyPolicy)) {
1611 /* Policy mapping uses anyPolicy, illegal. */
1612 if (!SecPVCSetResultForced(pvc, key /* @@@ Need custom key */, n - i, kCFBooleanFalse)) {
1613 goto errOut;
1614 }
1615 }
1616 }
1617 /* (b) */
1618 /* (1) If the policy_mapping variable is greater than 0 */
1619 if (policy_mapping > 0) {
1620 if (!policy_tree_walk_depth(pvc->valid_policy_tree, i,
1621 policy_tree_map, (void *)pm)) {
1622 /* 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:
1623
1624 (i) set the valid_policy to ID-P;
1625
1626 (ii) set the qualifier_set to the qualifier set of the
1627 policy anyPolicy in the certificate policies
1628 extension of certificate i; and
1629 (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. */
1630 }
1631 } else {
1632 #if 0
1633 /* (i) delete each node of depth i in the valid_policy_tree
1634 where ID-P is the valid_policy. */
1635 struct policy_tree_map_ctx ctx = { idp_oid, sdp_oid };
1636 policy_tree_walk_depth(pvc->valid_policy_tree, i,
1637 policy_tree_delete_if_match, &ctx);
1638 #endif
1639 /* (ii) If there is a node in the valid_policy_tree of depth
1640 i-1 or less without any child nodes, delete that
1641 node. Repeat this step until there are no nodes of
1642 depth i-1 or less without children. */
1643 policy_tree_prune_childless(&pvc->valid_policy_tree, i - 1);
1644 }
1645 }
1646 #endif /* POLICY_MAPPING */
1647 /* (c)(d)(e)(f) */
1648 //working_issuer_name = SecCertificateGetNormalizedSubjectContent(cert);
1649 //working_public_key = SecCertificateCopyPublicKey(cert);
1650 //working_public_key_parameters = SecCertificateCopyPublicKeyParameters(cert);
1651 //working_public_key_algorithm = SecCertificateCopyPublicKeyAlgorithm(cert);
1652 #if POLICY_SUBTREES
1653 /* (g) If a name constraints extension is included in the certificate, modify the permitted_subtrees and excluded_subtrees state variables.
1654 */
1655 CFArrayRef permitted_subtrees_in_cert = SecCertificateGetPermittedSubtrees(cert);
1656 if (permitted_subtrees_in_cert) {
1657 SecNameConstraintsIntersectSubtrees(permitted_subtrees, permitted_subtrees_in_cert);
1658 }
1659
1660 // could do something smart here to avoid inserting the exact same constraint
1661 CFArrayRef excluded_subtrees_in_cert = SecCertificateGetExcludedSubtrees(cert);
1662 if (excluded_subtrees_in_cert) {
1663 CFIndex num_trees = CFArrayGetCount(excluded_subtrees_in_cert);
1664 CFRange range = { 0, num_trees };
1665 CFArrayAppendArray(excluded_subtrees, excluded_subtrees_in_cert, range);
1666 }
1667 #endif
1668 /* (h) */
1669 if (!is_self_issued) {
1670 if (explicit_policy)
1671 explicit_policy--;
1672 if (policy_mapping)
1673 policy_mapping--;
1674 if (inhibit_any_policy)
1675 inhibit_any_policy--;
1676 }
1677 /* (i) */
1678 const SecCEPolicyConstraints *pc =
1679 SecCertificateGetPolicyConstraints(cert);
1680 if (pc) {
1681 if (pc->requireExplicitPolicyPresent
1682 && pc->requireExplicitPolicy < explicit_policy) {
1683 explicit_policy = pc->requireExplicitPolicy;
1684 }
1685 if (pc->inhibitPolicyMappingPresent
1686 && pc->inhibitPolicyMapping < policy_mapping) {
1687 policy_mapping = pc->inhibitPolicyMapping;
1688 }
1689 }
1690 /* (j) */
1691 uint32_t iap = SecCertificateGetInhibitAnyPolicySkipCerts(cert);
1692 if (iap < inhibit_any_policy) {
1693 inhibit_any_policy = iap;
1694 }
1695 /* (k) */
1696 const SecCEBasicConstraints *bc =
1697 SecCertificateGetBasicConstraints(cert);
1698 #if 0 /* Checked in chain builder pre signature verify already. */
1699 if (!bc || !bc->isCA) {
1700 /* Basic constraints not present or not marked as isCA, illegal. */
1701 if (!SecPVCSetResult(pvc, kSecPolicyCheckBasicConstraints,
1702 n - i, kCFBooleanFalse)) {
1703 goto errOut;
1704 }
1705 }
1706 #endif
1707 /* (l) */
1708 if (!is_self_issued) {
1709 if (max_path_length > 0) {
1710 max_path_length--;
1711 } else {
1712 /* max_path_len exceeded, illegal. */
1713 if (!SecPVCSetResult(pvc, kSecPolicyCheckBasicConstraints,
1714 n - i, kCFBooleanFalse)) {
1715 goto errOut;
1716 }
1717 }
1718 }
1719 /* (m) */
1720 if (bc && bc->pathLenConstraintPresent
1721 && bc->pathLenConstraint < max_path_length) {
1722 max_path_length = bc->pathLenConstraint;
1723 }
1724 #if 0 /* Checked in chain builder pre signature verify already. */
1725 /* (n) If a key usage extension is present, verify that the keyCertSign bit is set. */
1726 SecKeyUsage keyUsage = SecCertificateGetKeyUsage(cert);
1727 if (keyUsage && !(keyUsage & kSecKeyUsageKeyCertSign)) {
1728 if (!SecPVCSetResultForced(pvc, kSecPolicyCheckKeyUsage,
1729 n - i, kCFBooleanFalse, true)) {
1730 goto errOut;
1731 }
1732 }
1733 #endif
1734 /* (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. */
1735 if (SecCertificateHasUnknownCriticalExtension(cert)) {
1736 /* Certificate contains one or more unknown critical extensions. */
1737 if (!SecPVCSetResult(pvc, kSecPolicyCheckCriticalExtensions,
1738 n - i, kCFBooleanFalse)) {
1739 goto errOut;
1740 }
1741 }
1742 } /* end loop over certs in path */
1743 /* Wrap up */
1744 cert = SecPVCGetCertificateAtIndex(pvc, 0);
1745 /* (a) */
1746 if (explicit_policy)
1747 explicit_policy--;
1748 /* (b) */
1749 const SecCEPolicyConstraints *pc = SecCertificateGetPolicyConstraints(cert);
1750 if (pc) {
1751 if (pc->requireExplicitPolicyPresent
1752 && pc->requireExplicitPolicy == 0) {
1753 explicit_policy = 0;
1754 }
1755 }
1756 /* (c) */
1757 //working_public_key = SecCertificateCopyPublicKey(cert);
1758 /* (d) */
1759 /* 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
1760 working_public_key_algorithm are different, set the working_public_key_parameters to null. */
1761 //working_public_key_parameters = SecCertificateCopyPublicKeyParameters(cert);
1762 /* (e) */
1763 //working_public_key_algorithm = SecCertificateCopyPublicKeyAlgorithm(cert);
1764 /* (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. */
1765 if (SecCertificateHasUnknownCriticalExtension(cert)) {
1766 /* Certificate contains one or more unknown critical extensions. */
1767 if (!SecPVCSetResult(pvc, kSecPolicyCheckCriticalExtensions,
1768 0, kCFBooleanFalse)) {
1769 goto errOut;
1770 }
1771 }
1772 /* (g) Calculate the intersection of the valid_policy_tree and the user-initial-policy-set, as follows */
1773
1774 if (pvc->valid_policy_tree) {
1775 #if !defined(NDEBUG)
1776 policy_tree_dump(pvc->valid_policy_tree);
1777 #endif
1778 /* (g3c4) */
1779 //policy_tree_prune_childless(&pvc->valid_policy_tree, n - 1);
1780 }
1781
1782 /* If either (1) the value of explicit_policy variable is greater than
1783 zero or (2) the valid_policy_tree is not NULL, then path processing
1784 has succeeded. */
1785 if (!pvc->valid_policy_tree && explicit_policy == 0) {
1786 /* valid_policy_tree is empty and explicit policy is 0, illegal. */
1787 secnotice("policy", "policy tree failure");
1788 if (!SecPVCSetResultForced(pvc, key /* @@@ Need custom key */, 0, kCFBooleanFalse, true)) {
1789 goto errOut;
1790 }
1791 }
1792
1793 errOut:
1794 CFReleaseNull(permitted_subtrees);
1795 CFReleaseNull(excluded_subtrees);
1796 }
1797
1798 static policy_set_t policies_for_cert(SecCertificateRef cert) {
1799 policy_set_t policies = NULL;
1800 const SecCECertificatePolicies *cp =
1801 SecCertificateGetCertificatePolicies(cert);
1802 size_t policy_ix, policy_count = cp ? cp->numPolicies : 0;
1803 for (policy_ix = 0; policy_ix < policy_count; ++policy_ix) {
1804 policy_set_add(&policies, &cp->policies[policy_ix].policyIdentifier);
1805 }
1806 return policies;
1807 }
1808
1809 static void SecPolicyCheckEV(SecPVCRef pvc,
1810 CFStringRef key) {
1811 CFIndex ix, count = SecPVCGetCertificateCount(pvc);
1812 policy_set_t valid_policies = NULL;
1813
1814 /* 6.1.7. Key Usage Purposes */
1815 if (count) {
1816 CFAbsoluteTime jul2016 = 489024000;
1817 SecCertificateRef leaf = SecPVCGetCertificateAtIndex(pvc, 0);
1818 if (SecCertificateNotValidBefore(leaf) > jul2016 && count < 3) {
1819 /* Root CAs may not sign subscriber certificates after 30 June 2016. */
1820 if (SecPVCSetResultForced(pvc, key,
1821 0, kCFBooleanFalse, true)) {
1822 return;
1823 }
1824 }
1825 }
1826
1827 for (ix = 0; ix < count; ++ix) {
1828 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix);
1829 policy_set_t policies = policies_for_cert(cert);
1830 if (ix == 0) {
1831 /* Subscriber */
1832 /* anyPolicy in the leaf isn't allowed for EV, so only init
1833 valid_policies if we have real policies. */
1834 if (!policy_set_contains(policies, &oidAnyPolicy)) {
1835 valid_policies = policies;
1836 policies = NULL;
1837 }
1838 } else if (ix < count - 1) {
1839 /* Subordinate CA */
1840 if (!SecPolicySubordinateCACertificateCouldBeEV(cert)) {
1841 secnotice("ev", "subordinate certificate is not ev");
1842 if (SecPVCSetResultForced(pvc, key,
1843 ix, kCFBooleanFalse, true)) {
1844 policy_set_free(valid_policies);
1845 policy_set_free(policies);
1846 return;
1847 }
1848 }
1849 policy_set_intersect(&valid_policies, policies);
1850 } else {
1851 /* Root CA */
1852 if (!SecPolicyRootCACertificateIsEV(cert, valid_policies)) {
1853 secnotice("ev", "anchor certificate is not ev");
1854 if (SecPVCSetResultForced(pvc, key,
1855 ix, kCFBooleanFalse, true)) {
1856 policy_set_free(valid_policies);
1857 policy_set_free(policies);
1858 return;
1859 }
1860 }
1861 }
1862 policy_set_free(policies);
1863 if (!valid_policies) {
1864 secnotice("ev", "valid_policies set is empty: chain not ev");
1865 /* If we ever get into a state where no policies are valid anymore
1866 this can't be an ev chain. */
1867 if (SecPVCSetResultForced(pvc, key,
1868 ix, kCFBooleanFalse, true)) {
1869 return;
1870 }
1871 }
1872 }
1873
1874 policy_set_free(valid_policies);
1875
1876 /* (a) EV Subscriber Certificates Each EV Certificate issued by the CA to a
1877 Subscriber MUST contain an OID defined by the CA in the certificate’s
1878 certificatePolicies extension that: (i) indicates which CA policy statement relates
1879 to that certificate, (ii) asserts the CA’s adherence to and compliance with these
1880 Guidelines, and (iii), by pre-agreement with the Application Software Vendor,
1881 marks the certificate as being an EV Certificate.
1882 (b) EV Subordinate CA Certificates
1883 (1) Certificates issued to Subordinate CAs that are not controlled by the issuing
1884 CA MUST contain one or more OIDs defined by the issuing CA that
1885 explicitly identify the EV Policies that are implemented by the Subordinate
1886 CA;
1887 (2) Certificates issued to Subordinate CAs that are controlled by the Root CA
1888 MAY contain the special anyPolicy OID (2.5.29.32.0).
1889 (c) Root CA Certificates Root CA Certificates SHOULD NOT contain the
1890 certificatePolicies or extendedKeyUsage extensions.
1891 */
1892 }
1893
1894
1895 /*
1896 * MARK: Certificate Transparency support
1897 */
1898
1899 /***
1900
1901 struct {
1902 Version sct_version; // 1 byte
1903 LogID id; // 32 bytes
1904 uint64 timestamp; // 8 bytes
1905 CtExtensions extensions; // 2 bytes len field, + n bytes data
1906 digitally-signed struct { // 1 byte hash alg, 1 byte sig alg, n bytes signature
1907 Version sct_version;
1908 SignatureType signature_type = certificate_timestamp;
1909 uint64 timestamp;
1910 LogEntryType entry_type;
1911 select(entry_type) {
1912 case x509_entry: ASN.1Cert;
1913 case precert_entry: PreCert;
1914 } signed_entry;
1915 CtExtensions extensions;
1916 };
1917 } SignedCertificateTimestamp;
1918
1919 ***/
1920
1921 #include <Security/SecureTransportPriv.h>
1922
1923 static const
1924 SecAsn1Oid *oidForSigAlg(SSL_HashAlgorithm hash, SSL_SignatureAlgorithm alg)
1925 {
1926 switch(alg) {
1927 case SSL_SignatureAlgorithmRSA:
1928 switch (hash) {
1929 case SSL_HashAlgorithmSHA1:
1930 return &CSSMOID_SHA1WithRSA;
1931 case SSL_HashAlgorithmSHA256:
1932 return &CSSMOID_SHA256WithRSA;
1933 case SSL_HashAlgorithmSHA384:
1934 return &CSSMOID_SHA384WithRSA;
1935 default:
1936 break;
1937 }
1938 case SSL_SignatureAlgorithmECDSA:
1939 switch (hash) {
1940 case SSL_HashAlgorithmSHA1:
1941 return &CSSMOID_ECDSA_WithSHA1;
1942 case SSL_HashAlgorithmSHA256:
1943 return &CSSMOID_ECDSA_WithSHA256;
1944 case SSL_HashAlgorithmSHA384:
1945 return &CSSMOID_ECDSA_WithSHA384;
1946 default:
1947 break;
1948 }
1949 default:
1950 break;
1951 }
1952
1953 return NULL;
1954 }
1955
1956
1957 static size_t SSLDecodeUint16(const uint8_t *p)
1958 {
1959 return (p[0]<<8 | p[1]);
1960 }
1961
1962 static uint8_t *SSLEncodeUint16(uint8_t *p, size_t len)
1963 {
1964 p[0] = (len >> 8)&0xff;
1965 p[1] = (len & 0xff);
1966 return p+2;
1967 }
1968
1969 static uint8_t *SSLEncodeUint24(uint8_t *p, size_t len)
1970 {
1971 p[0] = (len >> 16)&0xff;
1972 p[1] = (len >> 8)&0xff;
1973 p[2] = (len & 0xff);
1974 return p+3;
1975 }
1976
1977
1978 static
1979 uint64_t SSLDecodeUint64(const uint8_t *p)
1980 {
1981 uint64_t u = 0;
1982 for(int i=0; i<8; i++) {
1983 u=(u<<8)|p[0];
1984 p++;
1985 }
1986 return u;
1987 }
1988
1989 #include <libDER/DER_CertCrl.h>
1990 #include <libDER/DER_Encode.h>
1991 #include <libDER/asn1Types.h>
1992
1993
1994 static CFDataRef copy_x509_entry_from_chain(SecPVCRef pvc)
1995 {
1996 SecCertificateRef leafCert = SecPVCGetCertificateAtIndex(pvc, 0);
1997
1998 CFMutableDataRef data = CFDataCreateMutable(kCFAllocatorDefault, 3+SecCertificateGetLength(leafCert));
1999
2000 CFDataSetLength(data, 3+SecCertificateGetLength(leafCert));
2001
2002 uint8_t *q = CFDataGetMutableBytePtr(data);
2003 q = SSLEncodeUint24(q, SecCertificateGetLength(leafCert));
2004 memcpy(q, SecCertificateGetBytePtr(leafCert), SecCertificateGetLength(leafCert));
2005
2006 return data;
2007 }
2008
2009
2010 static CFDataRef copy_precert_entry_from_chain(SecPVCRef pvc)
2011 {
2012 SecCertificateRef leafCert = NULL;
2013 SecCertificateRef issuer = NULL;
2014 CFDataRef issuerKeyHash = NULL;
2015 CFDataRef tbs_precert = NULL;
2016 CFMutableDataRef data= NULL;
2017
2018 require_quiet(SecPVCGetCertificateCount(pvc)>=2, out); //we need the issuer key for precerts.
2019 leafCert = SecPVCGetCertificateAtIndex(pvc, 0);
2020 issuer = SecPVCGetCertificateAtIndex(pvc, 1);
2021
2022 require(leafCert, out);
2023 require(issuer, out); // Those two would likely indicate an internal error, since we already checked the chain length above.
2024 issuerKeyHash = SecCertificateCopySubjectPublicKeyInfoSHA256Digest(issuer);
2025 tbs_precert = SecCertificateCopyPrecertTBS(leafCert);
2026
2027 require(issuerKeyHash, out);
2028 require(tbs_precert, out);
2029 data = CFDataCreateMutable(kCFAllocatorDefault, CFDataGetLength(issuerKeyHash) + 3 + CFDataGetLength(tbs_precert));
2030 CFDataSetLength(data, CFDataGetLength(issuerKeyHash) + 3 + CFDataGetLength(tbs_precert));
2031
2032 uint8_t *q = CFDataGetMutableBytePtr(data);
2033 memcpy(q, CFDataGetBytePtr(issuerKeyHash), CFDataGetLength(issuerKeyHash)); q += CFDataGetLength(issuerKeyHash); // issuer key hash
2034 q = SSLEncodeUint24(q, CFDataGetLength(tbs_precert));
2035 memcpy(q, CFDataGetBytePtr(tbs_precert), CFDataGetLength(tbs_precert));
2036
2037 out:
2038 CFReleaseSafe(issuerKeyHash);
2039 CFReleaseSafe(tbs_precert);
2040 return data;
2041 }
2042
2043 static
2044 CFAbsoluteTime TimestampToCFAbsoluteTime(uint64_t ts)
2045 {
2046 return (ts / 1000) - kCFAbsoluteTimeIntervalSince1970;
2047 }
2048
2049 static
2050 uint64_t TimestampFromCFAbsoluteTime(CFAbsoluteTime at)
2051 {
2052 return (uint64_t)(at + kCFAbsoluteTimeIntervalSince1970) * 1000;
2053 }
2054
2055
2056
2057
2058 /*
2059 If the 'sct' is valid, add it to the validatingLogs dictionary.
2060
2061 Inputs:
2062 - validatingLogs: mutable dictionary to which to add the log that validate this SCT.
2063 - sct: the SCT date
2064 - entry_type: 0 for x509 cert, 1 for precert.
2065 - entry: the cert or precert data.
2066 - vt: verification time timestamp (as used in SCTs: ms since 1970 Epoch)
2067 - trustedLog: Dictionary contain the Trusted Logs.
2068
2069 The SCT is valid if:
2070 - It decodes properly.
2071 - Its timestamp is less than 'verifyTime'.
2072 - It is signed by a log in 'trustedLogs'.
2073 - If entry_type = 0, the log must be currently qualified.
2074 - If entry_type = 1, the log may be expired.
2075
2076 If the SCT is valid, it's added to the validatinLogs dictionary using the log dictionary as the key, and the timestamp as value.
2077 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.
2078
2079 */
2080
2081
2082 static CFDictionaryRef getSCTValidatingLog(CFDataRef sct, int entry_type, CFDataRef entry, uint64_t vt, CFArrayRef trustedLogs, CFAbsoluteTime *sct_at)
2083 {
2084 uint8_t version;
2085 const uint8_t *logID;
2086 const uint8_t *timestampData;
2087 uint64_t timestamp;
2088 size_t extensionsLen;
2089 const uint8_t *extensionsData;
2090 uint8_t hashAlg;
2091 uint8_t sigAlg;
2092 size_t signatureLen;
2093 const uint8_t *signatureData;
2094 SecKeyRef pubKey = NULL;
2095 uint8_t *signed_data = NULL;
2096 const SecAsn1Oid *oid = NULL;
2097 SecAsn1AlgId algId;
2098 CFDataRef logIDData = NULL;
2099 CFDictionaryRef result = 0;
2100
2101 const uint8_t *p = CFDataGetBytePtr(sct);
2102 size_t len = CFDataGetLength(sct);
2103
2104 require(len>=43, out);
2105
2106 version = p[0]; p++; len--;
2107 logID = p; p+=32; len-=32;
2108 timestampData = p; p+=8; len-=8;
2109 extensionsLen = SSLDecodeUint16(p); p+=2; len-=2;
2110
2111 require(len>=extensionsLen, out);
2112 extensionsData = p; p+=extensionsLen; len-=extensionsLen;
2113
2114 require(len>=4, out);
2115 hashAlg=p[0]; p++; len--;
2116 sigAlg=p[0]; p++; len--;
2117 signatureLen = SSLDecodeUint16(p); p+=2; len-=2;
2118 require(len==signatureLen, out); /* We do not tolerate any extra data after the signature */
2119 signatureData = p;
2120
2121 /* verify version: only v1(0) is supported */
2122 if(version!=0) {
2123 secerror("SCT version unsupported: %d\n", version);
2124 goto out;
2125 }
2126
2127 /* verify timestamp not in the future */
2128 timestamp = SSLDecodeUint64(timestampData);
2129 if(timestamp > vt) {
2130 secerror("SCT is in the future: %llu > %llu\n", timestamp, vt);
2131 goto out;
2132 }
2133
2134 uint8_t *q;
2135
2136 /* signed entry */
2137 size_t signed_data_len = 12 + CFDataGetLength(entry) + 2 + extensionsLen ;
2138 signed_data = malloc(signed_data_len);
2139 require(signed_data, out);
2140 q = signed_data;
2141 *q++ = version;
2142 *q++ = 0; // certificate_timestamp
2143 memcpy(q, timestampData, 8); q+=8;
2144 q = SSLEncodeUint16(q, entry_type); // logentry type: 0=cert 1=precert
2145 memcpy(q, CFDataGetBytePtr(entry), CFDataGetLength(entry)); q += CFDataGetLength(entry);
2146 q = SSLEncodeUint16(q, extensionsLen);
2147 memcpy(q, extensionsData, extensionsLen);
2148
2149 logIDData = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, logID, 32, kCFAllocatorNull);
2150
2151 CFDictionaryRef logData = CFArrayGetValueMatching(trustedLogs, ^bool(const void *dict) {
2152 const void *key_data;
2153 if(!isDictionary(dict)) return false;
2154 if(!CFDictionaryGetValueIfPresent(dict, CFSTR("key"), &key_data)) return false;
2155 if(!isData(key_data)) return false;
2156 CFDataRef valueID = SecSHA256DigestCreateFromData(kCFAllocatorDefault, (CFDataRef)key_data);
2157 bool result = (bool)(CFDataCompare(logIDData, valueID)==kCFCompareEqualTo);
2158 CFReleaseSafe(valueID);
2159 return result;
2160 });
2161 require(logData, out);
2162
2163 if(entry_type==0) {
2164 // For external SCTs, only keep SCTs from currently valid logs.
2165 require(!CFDictionaryContainsKey(logData, CFSTR("expiry")), out);
2166 }
2167
2168 CFDataRef logKeyData = CFDictionaryGetValue(logData, CFSTR("key"));
2169 require(logKeyData, out); // This failing would be an internal logic error
2170 pubKey = SecKeyCreateFromSubjectPublicKeyInfoData(kCFAllocatorDefault, logKeyData);
2171 require(pubKey, out);
2172
2173 oid = oidForSigAlg(hashAlg, sigAlg);
2174 require(oid, out);
2175
2176 algId.algorithm = *oid;
2177 algId.parameters.Data = NULL;
2178 algId.parameters.Length = 0;
2179
2180 if(SecKeyDigestAndVerify(pubKey, &algId, signed_data, signed_data_len, signatureData, signatureLen)==0) {
2181 *sct_at = TimestampToCFAbsoluteTime(timestamp);
2182 result = logData;
2183 } else {
2184 secerror("SCT signature failed (log=%@)\n", logData);
2185 }
2186
2187 out:
2188 CFReleaseSafe(logIDData);
2189 CFReleaseSafe(pubKey);
2190 free(signed_data);
2191 return result;
2192 }
2193
2194
2195 static void addValidatingLog(CFMutableDictionaryRef validatingLogs, CFDictionaryRef log, CFAbsoluteTime sct_at)
2196 {
2197 CFDateRef validated_time = CFDictionaryGetValue(validatingLogs, log);
2198
2199 if(validated_time==NULL || (sct_at < CFDateGetAbsoluteTime(validated_time))) {
2200 CFDateRef sct_time = CFDateCreate(kCFAllocatorDefault, sct_at);
2201 CFDictionarySetValue(validatingLogs, log, sct_time);
2202 CFReleaseSafe(sct_time);
2203 }
2204 }
2205
2206 static CFArrayRef copy_ocsp_scts(SecPVCRef pvc)
2207 {
2208 CFMutableArrayRef SCTs = NULL;
2209 SecCertificateRef leafCert = NULL;
2210 SecCertificateRef issuer = NULL;
2211 CFArrayRef ocspResponsesData = NULL;
2212 SecOCSPRequestRef ocspRequest = NULL;
2213
2214 ocspResponsesData = SecPathBuilderCopyOCSPResponses(pvc->builder);
2215 require_quiet(ocspResponsesData, out);
2216
2217 require_quiet(SecPVCGetCertificateCount(pvc)>=2, out); //we need the issuer key for precerts.
2218 leafCert = SecPVCGetCertificateAtIndex(pvc, 0);
2219 issuer = SecPVCGetCertificateAtIndex(pvc, 1);
2220
2221 require(leafCert, out);
2222 require(issuer, out); // not quiet: Those two would likely indicate an internal error, since we already checked the chain length above.
2223 ocspRequest = SecOCSPRequestCreate(leafCert, issuer);
2224
2225 SCTs = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
2226 require(SCTs, out);
2227
2228 CFArrayForEach(ocspResponsesData, ^(const void *value) {
2229 /* TODO: Should the builder already have the appropriate SecOCSPResponseRef ? */
2230 SecOCSPResponseRef ocspResponse = SecOCSPResponseCreate(value);
2231 if(ocspResponse && SecOCSPGetResponseStatus(ocspResponse)==kSecOCSPSuccess) {
2232 SecOCSPSingleResponseRef ocspSingleResponse = SecOCSPResponseCopySingleResponse(ocspResponse, ocspRequest);
2233 if(ocspSingleResponse) {
2234 CFArrayRef singleResponseSCTs = SecOCSPSingleResponseCopySCTs(ocspSingleResponse);
2235 if(singleResponseSCTs) {
2236 CFArrayAppendArray(SCTs, singleResponseSCTs, CFRangeMake(0, CFArrayGetCount(singleResponseSCTs)));
2237 CFRelease(singleResponseSCTs);
2238 }
2239 SecOCSPSingleResponseDestroy(ocspSingleResponse);
2240 }
2241 }
2242 if(ocspResponse) SecOCSPResponseFinalize(ocspResponse);
2243 });
2244
2245 if(CFArrayGetCount(SCTs)==0) {
2246 CFReleaseNull(SCTs);
2247 }
2248
2249 out:
2250 CFReleaseSafe(ocspResponsesData);
2251 if(ocspRequest)
2252 SecOCSPRequestFinalize(ocspRequest);
2253
2254 return SCTs;
2255 }
2256
2257 static void SecPolicyCheckCT(SecPVCRef pvc, CFStringRef key)
2258 {
2259 SecCertificateRef leafCert = SecPVCGetCertificateAtIndex(pvc, 0);
2260 CFArrayRef embeddedScts = SecCertificateCopySignedCertificateTimestamps(leafCert);
2261 CFArrayRef builderScts = SecPathBuilderCopySignedCertificateTimestamps(pvc->builder);
2262 CFArrayRef trustedLogs = SecPathBuilderCopyTrustedLogs(pvc->builder);
2263 CFArrayRef ocspScts = copy_ocsp_scts(pvc);
2264 CFDataRef precertEntry = copy_precert_entry_from_chain(pvc);
2265 CFDataRef x509Entry = copy_x509_entry_from_chain(pvc);
2266
2267 // This eventually contain list of logs who validated the SCT.
2268 CFMutableDictionaryRef currentLogsValidatingScts = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
2269 CFMutableDictionaryRef logsValidatingEmbeddedScts = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
2270
2271 uint64_t vt = TimestampFromCFAbsoluteTime(pvc->verifyTime);
2272
2273 __block bool at_least_one_currently_valid_external = 0;
2274 __block bool at_least_one_currently_valid_embedded = 0;
2275
2276 require(logsValidatingEmbeddedScts, out);
2277 require(currentLogsValidatingScts, out);
2278
2279 if(trustedLogs) { // Don't bother trying to validate SCTs if we don't have any trusted logs.
2280 if(embeddedScts && precertEntry) { // Don't bother if we could not get the precert.
2281 CFArrayForEach(embeddedScts, ^(const void *value){
2282 CFAbsoluteTime sct_at;
2283 CFDictionaryRef log = getSCTValidatingLog(value, 1, precertEntry, vt, trustedLogs, &sct_at);
2284 if(log) {
2285 addValidatingLog(logsValidatingEmbeddedScts, log, sct_at);
2286 if(!CFDictionaryContainsKey(log, CFSTR("expiry"))) {
2287 addValidatingLog(currentLogsValidatingScts, log, sct_at);
2288 at_least_one_currently_valid_embedded = true;
2289 }
2290 }
2291 });
2292 }
2293
2294 if(builderScts && x509Entry) { // Don't bother if we could not get the cert.
2295 CFArrayForEach(builderScts, ^(const void *value){
2296 CFAbsoluteTime sct_at;
2297 CFDictionaryRef log = getSCTValidatingLog(value, 0, x509Entry, vt, trustedLogs, &sct_at);
2298 if(log) {
2299 addValidatingLog(currentLogsValidatingScts, log, sct_at);
2300 at_least_one_currently_valid_external = true;
2301 }
2302 });
2303 }
2304
2305 if(ocspScts && x509Entry) {
2306 CFArrayForEach(ocspScts, ^(const void *value){
2307 CFAbsoluteTime sct_at;
2308 CFDictionaryRef log = getSCTValidatingLog(value, 0, x509Entry, vt, trustedLogs, &sct_at);
2309 if(log) {
2310 addValidatingLog(currentLogsValidatingScts, log, sct_at);
2311 at_least_one_currently_valid_external = true;
2312 }
2313 });
2314 }
2315 }
2316
2317
2318 /* We now have 2 sets of logs that validated those SCTS, count them and make a final decision.
2319
2320 Current Policy:
2321 is_ct = (A1 AND A2) OR (B1 AND B2).
2322
2323 A1: embedded SCTs from 2+ to 5+ logs valid at issuance time
2324 A2: At least one embedded SCT from a currently valid log.
2325
2326 B1: SCTs from 2 currently valid logs (from any source)
2327 B2: At least 1 external SCT from a currently valid log.
2328
2329 */
2330
2331 pvc->is_ct = false;
2332
2333 if(at_least_one_currently_valid_external && CFDictionaryGetCount(currentLogsValidatingScts)>=2) {
2334 pvc->is_ct = true;
2335 } else if(at_least_one_currently_valid_embedded) {
2336 __block CFAbsoluteTime issuanceTime = pvc->verifyTime;
2337 __block int lifetime; // in Months
2338 __block unsigned once_or_current_qualified_embedded = 0;
2339
2340 /* Calculate issuance time base on timestamp of SCTs from current logs */
2341 CFDictionaryForEach(currentLogsValidatingScts, ^(const void *key, const void *value) {
2342 CFDictionaryRef log = key;
2343 if(!CFDictionaryContainsKey(log, CFSTR("expiry"))) {
2344 // Log is still qualified
2345 CFDateRef ts = (CFDateRef) value;
2346 CFAbsoluteTime timestamp = CFDateGetAbsoluteTime(ts);
2347 if(timestamp < issuanceTime) {
2348 issuanceTime = timestamp;
2349 }
2350 }
2351 });
2352
2353 /* Count Logs */
2354 CFDictionaryForEach(logsValidatingEmbeddedScts, ^(const void *key, const void *value) {
2355 CFDictionaryRef log = key;
2356 CFDateRef ts = value;
2357 CFDateRef expiry = CFDictionaryGetValue(log, CFSTR("expiry"));
2358 if(expiry == NULL || CFDateCompare(ts, expiry, NULL) == kCFCompareLessThan) {
2359 once_or_current_qualified_embedded++;
2360 }
2361 });
2362
2363 SecCFCalendarDoWithZuluCalendar(^(CFCalendarRef zuluCalendar) {
2364 int _lifetime;
2365 CFCalendarGetComponentDifference(zuluCalendar,
2366 SecCertificateNotValidBefore(leafCert),
2367 SecCertificateNotValidAfter(leafCert),
2368 0, "M", &_lifetime);
2369 lifetime = _lifetime;
2370 });
2371
2372 unsigned requiredEmbeddedSctsCount;
2373
2374 if (lifetime < 15) {
2375 requiredEmbeddedSctsCount = 2;
2376 } else if (lifetime <= 27) {
2377 requiredEmbeddedSctsCount = 3;
2378 } else if (lifetime <= 39) {
2379 requiredEmbeddedSctsCount = 4;
2380 } else {
2381 requiredEmbeddedSctsCount = 5;
2382 }
2383
2384 if(once_or_current_qualified_embedded >= requiredEmbeddedSctsCount){
2385 pvc->is_ct = true;
2386 }
2387 }
2388
2389 out:
2390 CFReleaseSafe(logsValidatingEmbeddedScts);
2391 CFReleaseSafe(currentLogsValidatingScts);
2392 CFReleaseSafe(builderScts);
2393 CFReleaseSafe(embeddedScts);
2394 CFReleaseSafe(ocspScts);
2395 CFReleaseSafe(precertEntry);
2396 CFReleaseSafe(trustedLogs);
2397 CFReleaseSafe(x509Entry);
2398 }
2399
2400 static bool checkPolicyOidData(SecPVCRef pvc, CFDataRef oid) {
2401 CFIndex ix, count = SecPVCGetCertificateCount(pvc);
2402 DERItem key_value;
2403 key_value.data = (DERByte *)CFDataGetBytePtr(oid);
2404 key_value.length = (DERSize)CFDataGetLength(oid);
2405
2406 for (ix = 0; ix < count; ix++) {
2407 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix);
2408 policy_set_t policies = policies_for_cert(cert);
2409
2410 if (policy_set_contains(policies, &key_value)) {
2411 return true;
2412 }
2413 }
2414 return false;
2415 }
2416
2417 static void SecPolicyCheckCertificatePolicyOid(SecPVCRef pvc, CFStringRef key)
2418 {
2419 SecPolicyRef policy = SecPVCGetPolicy(pvc);
2420 CFTypeRef value = CFDictionaryGetValue(policy->_options, key);
2421 bool result = false;
2422
2423 if (CFGetTypeID(value) == CFDataGetTypeID())
2424 {
2425 result = checkPolicyOidData(pvc, value);
2426 } else if (CFGetTypeID(value) == CFStringGetTypeID()) {
2427 CFDataRef dataOid = SecCertificateCreateOidDataFromString(NULL, value);
2428 if (dataOid) {
2429 result = checkPolicyOidData(pvc, dataOid);
2430 CFRelease(dataOid);
2431 }
2432 }
2433 if(!result) {
2434 SecPVCSetResult(pvc, key, 0, kCFBooleanFalse);
2435 }
2436 }
2437
2438
2439 static void SecPolicyCheckRevocation(SecPVCRef pvc,
2440 CFStringRef key) {
2441 SecPolicyRef policy = SecPVCGetPolicy(pvc);
2442 CFTypeRef value = CFDictionaryGetValue(policy->_options, key);
2443 if (isString(value)) {
2444 SecPVCSetCheckRevocation(pvc, value);
2445 }
2446 }
2447
2448 static void SecPolicyCheckRevocationResponseRequired(SecPVCRef pvc,
2449 CFStringRef key) {
2450 SecPVCSetCheckRevocationResponseRequired(pvc);
2451 }
2452
2453 static void SecPolicyCheckNoNetworkAccess(SecPVCRef pvc,
2454 CFStringRef key) {
2455 SecPolicyRef policy = SecPVCGetPolicy(pvc);
2456 CFTypeRef value = CFDictionaryGetValue(policy->_options, key);
2457 if (value == kCFBooleanTrue) {
2458 SecPathBuilderSetCanAccessNetwork(pvc->builder, false);
2459 } else {
2460 SecPathBuilderSetCanAccessNetwork(pvc->builder, true);
2461 }
2462 }
2463
2464 static void SecPolicyCheckWeakIntermediates(SecPVCRef pvc,
2465 CFStringRef key) {
2466 CFIndex ix, count = SecPVCGetCertificateCount(pvc);
2467 for (ix = 1; ix < count - 1; ++ix) {
2468 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix);
2469 if (cert && SecCertificateIsWeakKey(cert)) {
2470 /* Intermediate certificate has a weak key. */
2471 if (!SecPVCSetResult(pvc, key, ix, kCFBooleanFalse))
2472 return;
2473 }
2474 }
2475 }
2476
2477 static void SecPolicyCheckWeakLeaf(SecPVCRef pvc,
2478 CFStringRef key) {
2479 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, 0);
2480 if (cert && SecCertificateIsWeakKey(cert)) {
2481 /* Leaf certificate has a weak key. */
2482 if (!SecPVCSetResult(pvc, key, 0, kCFBooleanFalse))
2483 return;
2484 }
2485 }
2486
2487 static void SecPolicyCheckWeakRoot(SecPVCRef pvc,
2488 CFStringRef key) {
2489 CFIndex ix, count = SecPVCGetCertificateCount(pvc);
2490 ix = count - 1;
2491 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix);
2492 if (cert && SecCertificateIsWeakKey(cert)) {
2493 /* Root certificate has a weak key. */
2494 if (!SecPVCSetResult(pvc, key, ix, kCFBooleanFalse))
2495 return;
2496 }
2497 }
2498
2499 static void SecPolicyCheckKeySize(SecPVCRef pvc, CFStringRef key) {
2500 CFIndex ix, count = SecPVCGetCertificateCount(pvc);
2501 SecPolicyRef policy = SecPVCGetPolicy(pvc);
2502 CFDictionaryRef keySizes = CFDictionaryGetValue(policy->_options, key);
2503 for (ix = 0; ix < count; ++ix) {
2504 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix);
2505 if (!SecCertificateIsAtLeastMinKeySize(cert, keySizes)) {
2506 if (!SecPVCSetResult(pvc, key, ix, kCFBooleanFalse))
2507 return;
2508 }
2509 }
2510 }
2511
2512 static void SecPolicyCheckSignatureHashAlgorithms(SecPVCRef pvc,
2513 CFStringRef key) {
2514 CFIndex ix, count = SecPVCGetCertificateCount(pvc);
2515 SecPolicyRef policy = SecPVCGetPolicy(pvc);
2516 CFSetRef disallowedHashAlgorithms = CFDictionaryGetValue(policy->_options, key);
2517 for (ix = 0; ix < count; ++ix) {
2518 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix);
2519 if (!SecPolicyCheckCertSignatureHashAlgorithms(cert, disallowedHashAlgorithms)) {
2520 if (!SecPVCSetResult(pvc, key, ix, kCFBooleanFalse))
2521 return;
2522 }
2523 }
2524 }
2525
2526 #define ENABLE_CRLS (TARGET_OS_MAC && !TARGET_OS_IPHONE)
2527
2528 // MARK: -
2529 // MARK: SecRVCRef
2530 /********************************************************
2531 ****************** SecRVCRef Functions *****************
2532 ********************************************************/
2533 typedef struct OpaqueSecORVC *SecORVCRef;
2534 #if ENABLE_CRLS
2535 typedef struct OpaqueSecCRVC *SecCRVCRef;
2536 #endif
2537
2538 /* Revocation verification context. */
2539 struct OpaqueSecRVC {
2540 /* Pointer to the pvc for this revocation check */
2541 SecPVCRef pvc;
2542
2543 /* Index of cert in pvc that this RVC is for 0 = leaf, etc. */
2544 CFIndex certIX;
2545
2546 /* The OCSP Revocation verification context */
2547 SecORVCRef orvc;
2548
2549 #if ENABLE_CRLS
2550 SecCRVCRef crvc;
2551 #endif
2552
2553 bool done;
2554 };
2555 typedef struct OpaqueSecRVC *SecRVCRef;
2556
2557 // MARK: SecORVCRef
2558 /********************************************************
2559 ****************** OCSP RVC Functions ******************
2560 ********************************************************/
2561 const CFAbsoluteTime kSecDefaultOCSPResponseTTL = 24.0 * 60.0 * 60.0;
2562 #define OCSP_RESPONSE_TIMEOUT (3 * NSEC_PER_SEC)
2563
2564 /* OCSP Revocation verification context. */
2565 struct OpaqueSecORVC {
2566 /* Will contain the response data. */
2567 asynchttp_t http;
2568
2569 /* Pointer to the pvc for this revocation check. */
2570 SecPVCRef pvc;
2571
2572 /* Pointer to the generic rvc for this revocation check */
2573 SecRVCRef rvc;
2574
2575 /* The ocsp request we send to each responder. */
2576 SecOCSPRequestRef ocspRequest;
2577
2578 /* The freshest response we received so far, from stapling or cache or responder. */
2579 SecOCSPResponseRef ocspResponse;
2580
2581 /* The best validated candidate single response we received so far, from stapling or cache or responder. */
2582 SecOCSPSingleResponseRef ocspSingleResponse;
2583
2584 /* Index of cert in pvc that this RVC is for 0 = leaf, etc. */
2585 CFIndex certIX;
2586
2587 /* Index in array returned by SecCertificateGetOCSPResponders() for current
2588 responder. */
2589 CFIndex responderIX;
2590
2591 /* URL of current responder. */
2592 CFURLRef responder;
2593
2594 /* Date until which this revocation status is valid. */
2595 CFAbsoluteTime nextUpdate;
2596
2597 bool done;
2598 };
2599
2600 static void SecORVCFinish(SecORVCRef orvc) {
2601 secdebug("alloc", "%p", orvc);
2602 asynchttp_free(&orvc->http);
2603 if (orvc->ocspRequest) {
2604 SecOCSPRequestFinalize(orvc->ocspRequest);
2605 orvc->ocspRequest = NULL;
2606 }
2607 if (orvc->ocspResponse) {
2608 SecOCSPResponseFinalize(orvc->ocspResponse);
2609 orvc->ocspResponse = NULL;
2610 if (orvc->ocspSingleResponse) {
2611 SecOCSPSingleResponseDestroy(orvc->ocspSingleResponse);
2612 orvc->ocspSingleResponse = NULL;
2613 }
2614 }
2615 }
2616
2617 #define MAX_OCSP_RESPONDERS 3
2618 #define OCSP_REQUEST_THRESHOLD 10
2619
2620 /* Return the next responder we should contact for this rvc or NULL if we
2621 exhausted them all. */
2622 static CFURLRef SecORVCGetNextResponder(SecORVCRef rvc) {
2623 SecCertificateRef cert = SecPVCGetCertificateAtIndex(rvc->pvc, rvc->certIX);
2624 CFArrayRef ocspResponders = SecCertificateGetOCSPResponders(cert);
2625 if (ocspResponders) {
2626 CFIndex responderCount = CFArrayGetCount(ocspResponders);
2627 if (responderCount >= OCSP_REQUEST_THRESHOLD) {
2628 secnotice("rvc", "too many ocsp responders (%ld)", (long)responderCount);
2629 return NULL;
2630 }
2631 while (rvc->responderIX < responderCount && rvc->responderIX < MAX_OCSP_RESPONDERS) {
2632 CFURLRef responder = CFArrayGetValueAtIndex(ocspResponders, rvc->responderIX);
2633 rvc->responderIX++;
2634 CFStringRef scheme = CFURLCopyScheme(responder);
2635 if (scheme) {
2636 /* We only support http and https responders currently. */
2637 bool valid_responder = (CFEqual(CFSTR("http"), scheme) ||
2638 CFEqual(CFSTR("https"), scheme));
2639 CFRelease(scheme);
2640 if (valid_responder)
2641 return responder;
2642 }
2643 }
2644 }
2645 return NULL;
2646 }
2647
2648 /* Fire off an async http request for this certs revocation status, return
2649 false if request was queued, true if we're done. */
2650 static bool SecORVCFetchNext(SecORVCRef rvc) {
2651 while ((rvc->responder = SecORVCGetNextResponder(rvc))) {
2652 CFDataRef request = SecOCSPRequestGetDER(rvc->ocspRequest);
2653 if (!request)
2654 goto errOut;
2655
2656 secinfo("rvc", "Sending http ocsp request for cert %ld", rvc->certIX);
2657 if (!asyncHttpPost(rvc->responder, request, OCSP_RESPONSE_TIMEOUT, &rvc->http)) {
2658 /* Async request was posted, wait for reply. */
2659 return false;
2660 }
2661 }
2662
2663 errOut:
2664 rvc->done = true;
2665 return true;
2666 }
2667
2668 /* Process a verified ocsp response for a given cert. Return true if the
2669 certificate status was obtained. */
2670 static bool SecOCSPSingleResponseProcess(SecOCSPSingleResponseRef this,
2671 SecORVCRef rvc) {
2672 bool processed;
2673 switch (this->certStatus) {
2674 case CS_Good:
2675 secdebug("ocsp", "CS_Good for cert %" PRIdCFIndex, rvc->certIX);
2676 /* @@@ Mark cert as valid until a given date (nextUpdate if we have one)
2677 in the info dictionary. */
2678 //cert.revokeCheckGood(true);
2679 rvc->nextUpdate = this->nextUpdate == NULL_TIME ? this->thisUpdate + kSecDefaultOCSPResponseTTL : this->nextUpdate;
2680 processed = true;
2681 break;
2682 case CS_Revoked:
2683 secdebug("ocsp", "CS_Revoked for cert %" PRIdCFIndex, rvc->certIX);
2684 /* @@@ Mark cert as revoked (with reason) at revocation date in
2685 the info dictionary, or perhaps we should use a different key per
2686 reason? That way a client using exceptions can ignore some but
2687 not all reasons. */
2688 SInt32 reason = this->crlReason;
2689 CFNumberRef cfreason = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &reason);
2690 SecPVCSetResultForced(rvc->pvc, kSecPolicyCheckRevocation, rvc->certIX,
2691 cfreason, true);
2692 if (rvc->pvc && rvc->pvc->info) {
2693 /* make the revocation reason available in the trust result */
2694 CFDictionarySetValue(rvc->pvc->info, kSecTrustRevocationReason, cfreason);
2695 }
2696 CFRelease(cfreason);
2697 processed = true;
2698 break;
2699 case CS_Unknown:
2700 /* not an error, no per-cert status, nothing here */
2701 secdebug("ocsp", "CS_Unknown for cert %" PRIdCFIndex, rvc->certIX);
2702 processed = false;
2703 break;
2704 default:
2705 secnotice("ocsp", "BAD certStatus (%d) for cert %" PRIdCFIndex,
2706 (int)this->certStatus, rvc->certIX);
2707 processed = false;
2708 break;
2709 }
2710
2711 return processed;
2712 }
2713
2714 static void SecORVCUpdatePVC(SecORVCRef rvc) {
2715 if (rvc->ocspSingleResponse) {
2716 SecOCSPSingleResponseProcess(rvc->ocspSingleResponse, rvc);
2717 }
2718 if (rvc->ocspResponse) {
2719 rvc->nextUpdate = SecOCSPResponseGetExpirationTime(rvc->ocspResponse);
2720 }
2721 }
2722
2723 typedef void (^SecOCSPEvaluationCompleted)(SecTrustResultType tr);
2724
2725 static void
2726 SecOCSPEvaluateCompleted(const void *userData,
2727 SecCertificatePathRef chain, CFArrayRef details, CFDictionaryRef info,
2728 SecTrustResultType result) {
2729 SecOCSPEvaluationCompleted evaluated = (SecOCSPEvaluationCompleted)userData;
2730 evaluated(result);
2731 Block_release(evaluated);
2732
2733 }
2734
2735 static bool SecOCSPResponseEvaluateSigner(SecORVCRef rvc, CFArrayRef signers, CFArrayRef issuers, CFAbsoluteTime verifyTime) {
2736 __block bool evaluated = false;
2737 bool trusted = false;
2738 if (!signers || !issuers) {
2739 return trusted;
2740 }
2741
2742 /* Verify the signer chain against the OCSPSigner policy, using the issuer chain as anchors. */
2743 const void *ocspSigner = SecPolicyCreateOCSPSigner();
2744 CFArrayRef policies = CFArrayCreate(kCFAllocatorDefault,
2745 &ocspSigner, 1, &kCFTypeArrayCallBacks);
2746 CFRelease(ocspSigner);
2747
2748 SecOCSPEvaluationCompleted completed = Block_copy(^(SecTrustResultType result) {
2749 if (result == kSecTrustResultProceed || result == kSecTrustResultUnspecified) {
2750 evaluated = true;
2751 }
2752 });
2753
2754 CFDataRef clientAuditToken = SecPathBuilderCopyClientAuditToken(rvc->pvc->builder);
2755 SecPathBuilderRef oBuilder = SecPathBuilderCreate(clientAuditToken,
2756 signers, issuers, true, false,
2757 policies, NULL, NULL, NULL,
2758 verifyTime, NULL,
2759 SecOCSPEvaluateCompleted, completed);
2760 /* Build the chain(s), evaluate them, call the completed block, free the block and builder */
2761 SecPathBuilderStep(oBuilder);
2762 CFReleaseNull(clientAuditToken);
2763 CFReleaseNull(policies);
2764
2765 /* verify the public key of the issuer signed the OCSP signer */
2766 if (evaluated) {
2767 SecCertificateRef issuer = NULL, signer = NULL;
2768 SecKeyRef issuerPubKey = NULL;
2769
2770 issuer = (SecCertificateRef)CFArrayGetValueAtIndex(issuers, 0);
2771 signer = (SecCertificateRef)CFArrayGetValueAtIndex(signers, 0);
2772
2773 if (issuer) {
2774 #if TARGET_OS_IPHONE
2775 issuerPubKey = SecCertificateCopyPublicKey(issuer);
2776 #else
2777 issuerPubKey = SecCertificateCopyPublicKey_ios(issuer);
2778 #endif
2779 }
2780 if (signer && issuerPubKey && (errSecSuccess == SecCertificateIsSignedBy(signer, issuerPubKey))) {
2781 trusted = true;
2782 } else {
2783 secnotice("ocsp", "ocsp signer cert not signed by issuer");
2784 }
2785 CFReleaseNull(issuerPubKey);
2786 }
2787
2788 return trusted;
2789 }
2790
2791 static bool SecOCSPResponseVerify(SecOCSPResponseRef ocspResponse, SecORVCRef rvc, CFAbsoluteTime verifyTime) {
2792 bool trusted;
2793 SecCertificatePathRef issuers = SecCertificatePathCopyFromParent(rvc->pvc->path, rvc->certIX + 1);
2794 SecCertificateRef issuer = issuers ? CFRetainSafe(SecCertificatePathGetCertificateAtIndex(issuers, 0)) : NULL;
2795 CFArrayRef signers = SecOCSPResponseCopySigners(ocspResponse);
2796 SecCertificateRef signer = SecOCSPResponseCopySigner(ocspResponse, issuer);
2797
2798 if (signer && signers) {
2799 if (issuer && CFEqual(signer, issuer)) {
2800 /* We already know we trust issuer since it's the issuer of the
2801 * cert we are verifying. */
2802 secinfo("ocsp", "ocsp responder: %@ response signed by issuer",
2803 rvc->responder);
2804 trusted = true;
2805 } else {
2806 secinfo("ocsp", "ocsp responder: %@ response signed by cert issued by issuer",
2807 rvc->responder);
2808 CFMutableArrayRef signerCerts = NULL;
2809 CFArrayRef issuerCerts = NULL;
2810
2811 /* Ensure the signer cert is the 0th cert for trust evaluation */
2812 signerCerts = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
2813 CFArrayAppendValue(signerCerts, signer);
2814 CFArrayAppendArray(signerCerts, signers, CFRangeMake(0, CFArrayGetCount(signers)));
2815
2816 if (issuers) {
2817 issuerCerts = SecCertificatePathCopyCertificates(issuers, NULL);
2818 }
2819
2820 if (SecOCSPResponseEvaluateSigner(rvc, signerCerts, issuerCerts, verifyTime)) {
2821 secdebug("ocsp", "response satisfies ocspSigner policy (%@)",
2822 rvc->responder);
2823 trusted = true;
2824 } else {
2825 /* @@@ We don't trust the cert so don't use this response. */
2826 secnotice("ocsp", "ocsp response signed by certificate which "
2827 "does not satisfy ocspSigner policy");
2828 trusted = false;
2829 }
2830 CFReleaseNull(signerCerts);
2831 CFReleaseNull(issuerCerts);
2832 }
2833 } else {
2834 /* @@@ No signer found for this ocsp response, discard it. */
2835 secnotice("ocsp", "ocsp responder: %@ no signer found for response",
2836 rvc->responder);
2837 trusted = false;
2838 }
2839
2840 #if DUMP_OCSPRESPONSES
2841 char buf[40];
2842 snprintf(buf, 40, "/tmp/ocspresponse%ld%s.der",
2843 rvc->certIX, (trusted ? "t" : "u"));
2844 secdumpdata(ocspResponse->data, buf);
2845 #endif
2846 CFReleaseNull(issuers);
2847 CFReleaseNull(issuer);
2848 CFReleaseNull(signers);
2849 CFReleaseNull(signer);
2850 return trusted;
2851 }
2852
2853 static void SecORVCConsumeOCSPResponse(SecORVCRef rvc, SecOCSPResponseRef ocspResponse /*CF_CONSUMED*/, CFTimeInterval maxAge, bool updateCache) {
2854 SecOCSPSingleResponseRef sr = NULL;
2855 require_quiet(ocspResponse, errOut);
2856 SecOCSPResponseStatus orStatus = SecOCSPGetResponseStatus(ocspResponse);
2857 require_action_quiet(orStatus == kSecOCSPSuccess, errOut,
2858 secnotice("ocsp", "responder: %@ returned status: %d", rvc->responder, orStatus));
2859 require_action_quiet(sr = SecOCSPResponseCopySingleResponse(ocspResponse, rvc->ocspRequest), errOut,
2860 secnotice("ocsp", "ocsp responder: %@ did not include status of requested cert", rvc->responder));
2861 // Check if this response is fresher than any (cached) response we might still have in the rvc.
2862 require_quiet(!rvc->ocspSingleResponse || rvc->ocspSingleResponse->thisUpdate < sr->thisUpdate, errOut);
2863
2864 CFAbsoluteTime verifyTime = CFAbsoluteTimeGetCurrent();
2865 /* TODO: If the responder doesn't have the ocsp-nocheck extension we should
2866 check whether the leaf was revoked (we are already checking the rest of
2867 the chain). */
2868 /* Check the OCSP response signature and verify the response. */
2869 require_quiet(SecOCSPResponseVerify(ocspResponse, rvc,
2870 sr->certStatus == CS_Revoked ? SecOCSPResponseProducedAt(ocspResponse) : verifyTime), errOut);
2871
2872 // If we get here, we have a properly signed ocsp response
2873 // but we haven't checked dates yet.
2874
2875 bool sr_valid = SecOCSPSingleResponseCalculateValidity(sr, kSecDefaultOCSPResponseTTL, verifyTime);
2876 if (sr->certStatus == CS_Good) {
2877 // Side effect of SecOCSPResponseCalculateValidity sets ocspResponse->expireTime
2878 require_quiet(sr_valid && SecOCSPResponseCalculateValidity(ocspResponse, maxAge, kSecDefaultOCSPResponseTTL, verifyTime), errOut);
2879 } else if (sr->certStatus == CS_Revoked) {
2880 // Expire revoked responses when the subject certificate itself expires.
2881 ocspResponse->expireTime = SecCertificateNotValidAfter(SecPVCGetCertificateAtIndex(rvc->pvc, rvc->certIX));
2882 }
2883
2884 // Ok we like the new response, let's toss the old one.
2885 if (updateCache)
2886 SecOCSPCacheReplaceResponse(rvc->ocspResponse, ocspResponse, rvc->responder, verifyTime);
2887
2888 if (rvc->ocspResponse) SecOCSPResponseFinalize(rvc->ocspResponse);
2889 rvc->ocspResponse = ocspResponse;
2890 ocspResponse = NULL;
2891
2892 if (rvc->ocspSingleResponse) SecOCSPSingleResponseDestroy(rvc->ocspSingleResponse);
2893 rvc->ocspSingleResponse = sr;
2894 sr = NULL;
2895
2896 rvc->done = sr_valid;
2897
2898 errOut:
2899 if (sr) SecOCSPSingleResponseDestroy(sr);
2900 if (ocspResponse) SecOCSPResponseFinalize(ocspResponse);
2901 }
2902
2903 /* Callback from async http code after an ocsp response has been received. */
2904 static void SecOCSPFetchCompleted(asynchttp_t *http, CFTimeInterval maxAge) {
2905 SecORVCRef rvc = (SecORVCRef)http->info;
2906 SecPVCRef pvc = rvc->pvc;
2907 SecOCSPResponseRef ocspResponse = NULL;
2908 if (http->response) {
2909 CFDataRef data = CFHTTPMessageCopyBody(http->response);
2910 if (data) {
2911 /* Parse the returned data as if it's an ocspResponse. */
2912 ocspResponse = SecOCSPResponseCreate(data);
2913 CFRelease(data);
2914 }
2915 }
2916
2917 SecORVCConsumeOCSPResponse(rvc, ocspResponse, maxAge, true);
2918 // TODO: maybe we should set the cache-control: false in the http header and try again if the response is stale
2919
2920 if (!rvc->done) {
2921 /* Clear the data for the next response. */
2922 asynchttp_free(http);
2923 SecORVCFetchNext(rvc);
2924 }
2925
2926 if (rvc->done) {
2927 secdebug("rvc", "got OCSP response for cert: %ld", rvc->certIX);
2928 SecORVCUpdatePVC(rvc);
2929 SecORVCFinish(rvc);
2930 if (!--pvc->asyncJobCount) {
2931 secdebug("rvc", "done with all async jobs");
2932 SecPathBuilderStep(pvc->builder);
2933 }
2934 }
2935 }
2936
2937 static SecORVCRef SecORVCCreate(SecRVCRef rvc, SecPVCRef pvc, CFIndex certIX) {
2938 SecORVCRef orvc = NULL;
2939 orvc = malloc(sizeof(struct OpaqueSecORVC));
2940 if (orvc) {
2941 memset(orvc, 0, sizeof(struct OpaqueSecORVC));
2942 orvc->pvc = pvc;
2943 orvc->rvc = rvc;
2944 orvc->certIX = certIX;
2945 orvc->http.queue = SecPathBuilderGetQueue(pvc->builder);
2946 orvc->http.token = SecPathBuilderCopyClientAuditToken(pvc->builder);
2947 orvc->http.completed = SecOCSPFetchCompleted;
2948 orvc->http.info = orvc;
2949 orvc->ocspRequest = NULL;
2950 orvc->responderIX = 0;
2951 orvc->responder = NULL;
2952 orvc->nextUpdate = NULL_TIME;
2953 orvc->ocspResponse = NULL;
2954 orvc->ocspSingleResponse = NULL;
2955 orvc->done = false;
2956
2957 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, certIX);
2958 /* The certIX + 1 is ok here since certCount is always at least 1
2959 less than the actual number of certs in SecPVCCheckRevocation. */
2960 SecCertificateRef issuer = SecPVCGetCertificateAtIndex(pvc, certIX + 1);
2961 orvc->ocspRequest = SecOCSPRequestCreate(cert, issuer);
2962 }
2963 return orvc;
2964 }
2965
2966 static void SecORVCProcessStapledResponses(SecORVCRef rvc) {
2967 /* Get stapled OCSP responses */
2968 CFArrayRef ocspResponsesData = SecPathBuilderCopyOCSPResponses(rvc->pvc->builder);
2969
2970 if(ocspResponsesData) {
2971 secdebug("rvc", "Checking stapled responses for cert %ld", rvc->certIX);
2972 CFArrayForEach(ocspResponsesData, ^(const void *value) {
2973 SecOCSPResponseRef ocspResponse = SecOCSPResponseCreate(value);
2974 SecORVCConsumeOCSPResponse(rvc, ocspResponse, NULL_TIME, false);
2975 });
2976 CFRelease(ocspResponsesData);
2977 }
2978 }
2979
2980 // MARK: SecCRVCRef
2981 /********************************************************
2982 ******************* CRL RVC Functions ******************
2983 ********************************************************/
2984 #if ENABLE_CRLS
2985 #include <../trustd/SecTrustOSXEntryPoints.h>
2986 OSStatus errSecCertificateRevoked = -67820;
2987 #define kSecDefaultCRLTTL kSecDefaultOCSPResponseTTL
2988
2989 /* CRL Revocation verification context. */
2990 struct OpaqueSecCRVC {
2991 /* Response data from ocspd. Yes, ocspd does CRLs, but not OCSP... */
2992 async_ocspd_t async_ocspd;
2993
2994 /* Pointer to the pvc for this revocation check. */
2995 SecPVCRef pvc;
2996
2997 /* Pointer to the generic rvc for this revocation check */
2998 SecRVCRef rvc;
2999
3000 /* The current CRL status from ocspd. */
3001 OSStatus status;
3002
3003 /* Index of cert in pvc that this RVC is for 0 = leaf, etc. */
3004 CFIndex certIX;
3005
3006 /* Index in array returned by SecCertificateGetCRLDistributionPoints() for
3007 current distribution point. */
3008 CFIndex distributionPointIX;
3009
3010 /* URL of current distribution point. */
3011 CFURLRef distributionPoint;
3012
3013 /* Date until which this revocation status is valid. */
3014 CFAbsoluteTime nextUpdate;
3015
3016 bool done;
3017 };
3018
3019 static void SecCRVCFinish(SecCRVCRef crvc) {
3020 // nothing yet
3021 }
3022
3023 #define MAX_CRL_DPS 3
3024 #define CRL_REQUEST_THRESHOLD 10
3025
3026 static CFURLRef SecCRVCGetNextDistributionPoint(SecCRVCRef rvc) {
3027 SecCertificateRef cert = SecPVCGetCertificateAtIndex(rvc->pvc, rvc->certIX);
3028 CFArrayRef crlDPs = SecCertificateGetCRLDistributionPoints(cert);
3029 if (crlDPs) {
3030 CFIndex crlDPCount = CFArrayGetCount(crlDPs);
3031 if (crlDPCount >= CRL_REQUEST_THRESHOLD) {
3032 secnotice("rvc", "too many CRL DP entries (%ld)", (long)crlDPCount);
3033 return NULL;
3034 }
3035 while (rvc->distributionPointIX < crlDPCount && rvc->distributionPointIX < MAX_CRL_DPS) {
3036 CFURLRef distributionPoint = CFArrayGetValueAtIndex(crlDPs, rvc->distributionPointIX);
3037 rvc->distributionPointIX++;
3038 CFStringRef scheme = CFURLCopyScheme(distributionPoint);
3039 if (scheme) {
3040 /* We only support http and https responders currently. */
3041 bool valid_DP = (CFEqual(CFSTR("http"), scheme) ||
3042 CFEqual(CFSTR("https"), scheme) ||
3043 CFEqual(CFSTR("ldap"), scheme));
3044 CFRelease(scheme);
3045 if (valid_DP)
3046 return distributionPoint;
3047 }
3048 }
3049 }
3050 return NULL;
3051 }
3052
3053 static void SecCRVCGetCRLStatus(SecCRVCRef rvc) {
3054 SecCertificateRef cert = SecPVCGetCertificateAtIndex(rvc->pvc, rvc->certIX);
3055 SecCertificatePathRef path = rvc->pvc->path;
3056 CFArrayRef serializedCertPath = SecCertificatePathCreateSerialized(path, NULL);
3057 secdebug("rvc", "searching CRL cache for cert: %ld", rvc->certIX);
3058 rvc->status = SecTrustLegacyCRLStatus(cert, serializedCertPath, rvc->distributionPoint);
3059 CFReleaseNull(serializedCertPath);
3060 /* we got a response indicating that the CRL was checked */
3061 if (rvc->status == errSecSuccess || rvc->status == errSecCertificateRevoked) {
3062 rvc->done = true;
3063 /* ocspd doesn't give us the nextUpdate time, so set to default */
3064 rvc->nextUpdate = SecPVCGetVerifyTime(rvc->pvc) + kSecDefaultCRLTTL;
3065 }
3066 }
3067
3068 static void SecCRVCCheckRevocationCache(SecCRVCRef rvc) {
3069 while ((rvc->distributionPoint = SecCRVCGetNextDistributionPoint(rvc))) {
3070 SecCRVCGetCRLStatus(rvc);
3071 if (rvc->status == errSecCertificateRevoked) {
3072 return;
3073 }
3074 }
3075 }
3076
3077 /* Fire off an async http request for this certs revocation status, return
3078 false if request was queued, true if we're done. */
3079 static bool SecCRVCFetchNext(SecCRVCRef rvc) {
3080 while ((rvc->distributionPoint = SecCRVCGetNextDistributionPoint(rvc))) {
3081 SecCertificateRef cert = SecPVCGetCertificateAtIndex(rvc->pvc, rvc->certIX);
3082 SecCertificatePathRef path = rvc->pvc->path;
3083 CFArrayRef serializedCertPath = SecCertificatePathCreateSerialized(path, NULL);
3084 secinfo("rvc", "fetching CRL for cert: %ld", rvc->certIX);
3085 if (!SecTrustLegacyCRLFetch(&rvc->async_ocspd, rvc->distributionPoint,
3086 CFAbsoluteTimeGetCurrent(), cert, serializedCertPath)) {
3087 CFDataRef clientAuditToken = NULL;
3088 SecTaskRef task = NULL;
3089 audit_token_t auditToken = {};
3090 clientAuditToken = SecPathBuilderCopyClientAuditToken(rvc->pvc->builder);
3091 require(clientAuditToken, out);
3092 require(sizeof(auditToken) == CFDataGetLength(clientAuditToken), out);
3093 CFDataGetBytes(clientAuditToken, CFRangeMake(0, sizeof(auditToken)), (uint8_t *)&auditToken);
3094 require(task = SecTaskCreateWithAuditToken(NULL, auditToken), out);
3095 secnotice("rvc", "asynchronously fetching CRL (%@) for client (%@)",
3096 rvc->distributionPoint, task);
3097
3098 out:
3099 CFReleaseNull(clientAuditToken);
3100 CFReleaseNull(task);
3101 /* Async request was posted, wait for reply. */
3102 return false;
3103 }
3104 }
3105 rvc->done = true;
3106 return true;
3107 }
3108
3109 static void SecCRVCUpdatePVC(SecCRVCRef rvc) {
3110 if (rvc->status == errSecCertificateRevoked) {
3111 secdebug("rvc", "CRL revoked cert %" PRIdCFIndex, rvc->certIX);
3112 SInt32 reason = 0; // unspecified, since ocspd didn't tell us
3113 CFNumberRef cfreason = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &reason);
3114 SecPVCSetResultForced(rvc->pvc, kSecPolicyCheckRevocation, rvc->certIX,
3115 cfreason, true);
3116 if (rvc->pvc && rvc->pvc->info) {
3117 /* make the revocation reason available in the trust result */
3118 CFDictionarySetValue(rvc->pvc->info, kSecTrustRevocationReason, cfreason);
3119 }
3120 CFReleaseNull(cfreason);
3121 }
3122 }
3123
3124 static void SecCRVCFetchCompleted(async_ocspd_t *ocspd) {
3125 SecCRVCRef rvc = ocspd->info;
3126 SecPVCRef pvc = rvc->pvc;
3127 /* we got a response indicating that the CRL was checked */
3128 if (ocspd->response == errSecSuccess || ocspd->response == errSecCertificateRevoked) {
3129 rvc->status = ocspd->response;
3130 rvc->done = true;
3131 /* ocspd doesn't give us the nextUpdate time, so set to default */
3132 rvc->nextUpdate = SecPVCGetVerifyTime(rvc->pvc) + kSecDefaultCRLTTL;
3133 secdebug("rvc", "got CRL response for cert: %ld", rvc->certIX);
3134 SecCRVCUpdatePVC(rvc);
3135 SecCRVCFinish(rvc);
3136 if (!--pvc->asyncJobCount) {
3137 secdebug("rvc", "done with all async jobs");
3138 SecPathBuilderStep(pvc->builder);
3139 }
3140 } else {
3141 if(SecCRVCFetchNext(rvc)) {
3142 if (!--pvc->asyncJobCount) {
3143 secdebug("rvc", "done with all async jobs");
3144 SecPathBuilderStep(pvc->builder);
3145 }
3146 }
3147 }
3148 }
3149
3150 static SecCRVCRef SecCRVCCreate(SecRVCRef rvc, SecPVCRef pvc, CFIndex certIX) {
3151 SecCRVCRef crvc = NULL;
3152 crvc = malloc(sizeof(struct OpaqueSecCRVC));
3153 if (crvc) {
3154 memset(crvc, 0, sizeof(struct OpaqueSecCRVC));
3155 crvc->pvc = pvc;
3156 crvc->rvc = rvc;
3157 crvc->certIX = certIX;
3158 crvc->status = errSecInternal;
3159 crvc->distributionPointIX = 0;
3160 crvc->distributionPoint = NULL;
3161 crvc->nextUpdate = NULL_TIME;
3162 crvc->async_ocspd.queue = SecPathBuilderGetQueue(pvc->builder);
3163 crvc->async_ocspd.completed = SecCRVCFetchCompleted;
3164 crvc->async_ocspd.response = errSecInternal;
3165 crvc->async_ocspd.info = crvc;
3166 crvc->done = false;
3167 }
3168 return crvc;
3169 }
3170
3171 static bool SecRVCShouldCheckCRL(SecRVCRef rvc) {
3172 if (rvc->pvc->check_revocation &&
3173 CFEqual(kSecPolicyCheckRevocationCRL, rvc->pvc->check_revocation)) {
3174 /* Our client insists on CRLs */
3175 secinfo("rvc", "client told us to check CRL");
3176 return true;
3177 }
3178 SecCertificateRef cert = SecPVCGetCertificateAtIndex(rvc->pvc, rvc->certIX);
3179 CFArrayRef ocspResponders = SecCertificateGetOCSPResponders(cert);
3180 if ((!ocspResponders || CFArrayGetCount(ocspResponders) == 0) &&
3181 (rvc->pvc->check_revocation && !CFEqual(kSecPolicyCheckRevocationOCSP, rvc->pvc->check_revocation))) {
3182 /* The cert doesn't have OCSP responders and the client didn't specifically ask for OCSP.
3183 * This logic will skip the CRL cache check if the client didn't ask for revocation checking */
3184 secinfo("rvc", "client told us to check revocation and CRL is only option for cert: %ld", rvc->certIX);
3185 return true;
3186 }
3187 return false;
3188 }
3189 #endif /* ENABLE_CRLS */
3190
3191 static void SecRVCFinish(SecRVCRef rvc) {
3192 if (rvc->orvc) {
3193 SecORVCFinish(rvc->orvc);
3194 }
3195 #if ENABLE_CRLS
3196 if (rvc->crvc) {
3197 SecCRVCFinish(rvc->crvc);
3198 }
3199 #endif
3200 }
3201
3202 static void SecRVCDelete(SecRVCRef rvc) {
3203 if (rvc->orvc) {
3204 SecORVCFinish(rvc->orvc);
3205 free(rvc->orvc);
3206 }
3207 #if ENABLE_CRLS
3208 if (rvc->crvc) {
3209 SecCRVCFinish(rvc->crvc);
3210 free(rvc->crvc);
3211 }
3212 #endif
3213 }
3214
3215 static void SecRVCInit(SecRVCRef rvc, SecPVCRef pvc, CFIndex certIX) {
3216 secdebug("alloc", "%p", rvc);
3217 rvc->pvc = pvc;
3218 rvc->certIX = certIX;
3219 rvc->orvc = SecORVCCreate(rvc, pvc, certIX);
3220 #if ENABLE_CRLS
3221 rvc->crvc = SecCRVCCreate(rvc, pvc, certIX);
3222 #endif
3223 rvc->done = false;
3224 }
3225
3226 static void SecRVCUpdatePVC(SecRVCRef rvc) {
3227 SecORVCUpdatePVC(rvc->orvc);
3228 #if ENABLE_CRLS
3229 SecCRVCUpdatePVC(rvc->crvc);
3230 #endif
3231 }
3232
3233 #if ENABLE_CRLS
3234 static bool SecRVCShouldCheckOCSP(SecRVCRef rvc) {
3235 if (!rvc->pvc->check_revocation
3236 || !CFEqual(rvc->pvc->check_revocation, kSecPolicyCheckRevocationCRL)) {
3237 return true;
3238 }
3239 return false;
3240 }
3241 #else
3242 static bool SecRVCShouldCheckOCSP(SecRVCRef rvc) {
3243 return true;
3244 }
3245 #endif
3246
3247 static void SecRVCCheckRevocationCaches(SecRVCRef rvc) {
3248 /* Don't check OCSP cache if CRLs enabled and policy requested CRL only */
3249 if (SecRVCShouldCheckOCSP(rvc)) {
3250 secdebug("ocsp", "Checking cached responses for cert %ld", rvc->certIX);
3251 SecORVCConsumeOCSPResponse(rvc->orvc,
3252 SecOCSPCacheCopyMatching(rvc->orvc->ocspRequest, NULL),
3253 NULL_TIME, false);
3254 }
3255 #if ENABLE_CRLS
3256 /* Don't check CRL cache if policy requested OCSP only */
3257 if (SecRVCShouldCheckCRL(rvc)) {
3258 SecCRVCCheckRevocationCache(rvc->crvc);
3259 }
3260 #endif
3261 }
3262
3263 static bool SecRVCFetchNext(SecRVCRef rvc) {
3264 bool OCSP_fetch_finished = true;
3265 /* Don't send OCSP request only if CRLs enabled and policy requested CRL only */
3266 if (SecRVCShouldCheckOCSP(rvc)) {
3267 OCSP_fetch_finished &= SecORVCFetchNext(rvc->orvc);
3268 }
3269 if (OCSP_fetch_finished) {
3270 /* we didn't start an OCSP background job for this cert */
3271 rvc->pvc->asyncJobCount--;
3272 }
3273
3274 #if ENABLE_CRLS
3275 bool CRL_fetch_finished = true;
3276 /* Don't check CRL cache if policy requested OCSP only */
3277 if (SecRVCShouldCheckCRL(rvc)) {
3278 /* reset the distributionPointIX because we already iterated through the CRLDPs
3279 * in SecCRVCCheckRevocationCache */
3280 rvc->crvc->distributionPointIX = 0;
3281 CRL_fetch_finished &= SecCRVCFetchNext(rvc->crvc);
3282 }
3283 if (CRL_fetch_finished) {
3284 /* we didn't start a CRL background job for this cert */
3285 rvc->pvc->asyncJobCount--;
3286 }
3287 OCSP_fetch_finished &= CRL_fetch_finished;
3288 #endif
3289
3290 return OCSP_fetch_finished;
3291 }
3292
3293 static bool SecPVCCheckRevocation(SecPVCRef pvc) {
3294 secdebug("rvc", "checking revocation");
3295 CFIndex certIX, certCount = SecPVCGetCertificateCount(pvc);
3296 bool completed = true;
3297 if (certCount <= 1) {
3298 /* Can't verify without an issuer; we're done */
3299 return completed;
3300 }
3301
3302 /*
3303 * Don't need to call SecPVCIsAnchored; having an issuer is sufficient here.
3304 * We can't check revocation for the final cert in the chain.
3305 */
3306 certCount--;
3307
3308 if (pvc->rvcs) {
3309 /* We have done revocation checking already, we're done. */
3310 secdebug("rvc", "Not rechecking revocation");
3311 return completed;
3312 }
3313
3314 /* Setup things so we check revocation status of all certs except the
3315 anchor. */
3316 pvc->rvcs = calloc(sizeof(struct OpaqueSecRVC), certCount);
3317
3318 /* Note that if we are multi threaded and a job completes after it
3319 is started but before we return from this function, we don't want
3320 a callback to decrement asyncJobCount to zero before we finish issuing
3321 all the jobs. To avoid this we pretend we issued certCount async jobs,
3322 and decrement pvc->asyncJobCount for each cert that we don't start a
3323 background fetch for. */
3324 #if !ENABLE_CRLS
3325 pvc->asyncJobCount = (unsigned int) certCount;
3326 #else
3327 /* If we enable CRLS, we may end up with two async jobs per cert: one
3328 * for OCSP and one for fetching the CRL */
3329 pvc->asyncJobCount = 2 * (unsigned int)certCount;
3330 #endif
3331 secdebug("rvc", "set asyncJobCount to %d", pvc->asyncJobCount);
3332
3333 /* Loop though certificates again and issue an ocsp fetch if the
3334 revocation status checking isn't done yet. */
3335 for (certIX = 0; certIX < certCount; ++certIX) {
3336 secdebug("rvc", "checking revocation for cert: %ld", certIX);
3337 SecRVCRef rvc = &((SecRVCRef)pvc->rvcs)[certIX];
3338 SecRVCInit(rvc, pvc, certIX);
3339 if (rvc->done){
3340 continue;
3341 }
3342 /* Ignore stapled OCSP responses only if CRLs are enabled and the
3343 * policy specifically requested CRLs only. */
3344 if (SecRVCShouldCheckOCSP(rvc)) {
3345 /* If we have any OCSP stapled responses, check those first */
3346 SecORVCProcessStapledResponses(rvc->orvc);
3347 }
3348
3349 #if TARGET_OS_BRIDGE
3350 /* The bridge has no writeable storage and no network. Nothing else we can
3351 * do here. */
3352 rvc->done = true;
3353 return completed;
3354 #endif
3355
3356 /* Then check the caches for revocation results. */
3357 SecRVCCheckRevocationCaches(rvc);
3358
3359 /* The check is done if we found cached responses from either method. */
3360 if (rvc->orvc->done
3361 #if ENABLE_CRLS
3362 || rvc->orvc->done
3363 #endif
3364 ) {
3365 secdebug("rvc", "found cached response for cert: %ld", certIX);
3366 rvc->done = true;
3367 }
3368
3369 /* If the cert is EV or if revocation checking was explicitly enabled, attempt to fire off an
3370 async http request for this cert's revocation status, unless we already successfully checked
3371 the revocation status of this cert based on the cache or stapled responses, */
3372 bool allow_fetch = SecPathBuilderCanAccessNetwork(pvc->builder) && (pvc->is_ev || pvc->check_revocation);
3373 bool fetch_done = true;
3374 if (rvc->done || !allow_fetch) {
3375 /* We got a cache hit or we aren't allowed to access the network */
3376 SecRVCUpdatePVC(rvc);
3377 SecRVCFinish(rvc);
3378 /* We didn't really start any background jobs for this cert. */
3379 pvc->asyncJobCount--;
3380 #if ENABLE_CRLS
3381 pvc->asyncJobCount--;
3382 #endif
3383 secdebug("rvc", "not fetching and job count is %d for cert %ld", pvc->asyncJobCount, certIX);
3384 } else {
3385 fetch_done = SecRVCFetchNext(rvc);
3386 }
3387 if (!fetch_done) {
3388 /* We started at least one background fetch. */
3389 secdebug("rvc", "waiting on background fetch for cert %ld", certIX);
3390 completed = false;
3391 }
3392 }
3393
3394 /* Return false if we started any background jobs. */
3395 /* We can't just return !pvc->asyncJobCount here, since if we started any
3396 jobs the completion callback will be called eventually and it will call
3397 SecPathBuilderStep(). If for some reason everything completed before we
3398 get here we still want the outer SecPathBuilderStep() to terminate so we
3399 keep track of whether we started any jobs and return false if so. */
3400 return completed;
3401 }
3402
3403 static CFAbsoluteTime SecRVCGetEarliestNextUpdate(SecRVCRef rvc) {
3404 CFAbsoluteTime enu = NULL_TIME;
3405 enu = rvc->orvc->nextUpdate;
3406 #if ENABLE_CRLS
3407 CFAbsoluteTime crlNextUpdate = rvc->crvc->nextUpdate;
3408 if (enu == NULL_TIME ||
3409 ((crlNextUpdate > NULL_TIME) && (enu > crlNextUpdate))) {
3410 /* We didn't check OCSP or CRL next update time was sooner */
3411 enu = crlNextUpdate;
3412 }
3413 #endif
3414 return enu;
3415 }
3416
3417
3418 void SecPolicyServerInitalize(void) {
3419 gSecPolicyLeafCallbacks = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
3420 &kCFTypeDictionaryKeyCallBacks, NULL);
3421 gSecPolicyPathCallbacks = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
3422 &kCFTypeDictionaryKeyCallBacks, NULL);
3423
3424 CFDictionaryAddValue(gSecPolicyPathCallbacks,
3425 kSecPolicyCheckBasicCertificateProcessing,
3426 SecPolicyCheckBasicCertificateProcessing);
3427 CFDictionaryAddValue(gSecPolicyPathCallbacks,
3428 kSecPolicyCheckCriticalExtensions,
3429 SecPolicyCheckCriticalExtensions);
3430 CFDictionaryAddValue(gSecPolicyPathCallbacks,
3431 kSecPolicyCheckIdLinkage,
3432 SecPolicyCheckIdLinkage);
3433 CFDictionaryAddValue(gSecPolicyLeafCallbacks,
3434 kSecPolicyCheckKeyUsage,
3435 SecPolicyCheckKeyUsage);
3436 CFDictionaryAddValue(gSecPolicyLeafCallbacks,
3437 kSecPolicyCheckExtendedKeyUsage,
3438 SecPolicyCheckExtendedKeyUsage);
3439 CFDictionaryAddValue(gSecPolicyLeafCallbacks,
3440 kSecPolicyCheckBasicConstraints,
3441 SecPolicyCheckBasicConstraints);
3442 CFDictionaryAddValue(gSecPolicyLeafCallbacks,
3443 kSecPolicyCheckNonEmptySubject,
3444 SecPolicyCheckNonEmptySubject);
3445 CFDictionaryAddValue(gSecPolicyLeafCallbacks,
3446 kSecPolicyCheckQualifiedCertStatements,
3447 SecPolicyCheckQualifiedCertStatements);
3448 CFDictionaryAddValue(gSecPolicyLeafCallbacks,
3449 kSecPolicyCheckSSLHostname,
3450 SecPolicyCheckSSLHostname);
3451 CFDictionaryAddValue(gSecPolicyLeafCallbacks,
3452 kSecPolicyCheckEmail,
3453 SecPolicyCheckEmail);
3454 CFDictionaryAddValue(gSecPolicyPathCallbacks,
3455 kSecPolicyCheckValidIntermediates,
3456 SecPolicyCheckValidIntermediates);
3457 CFDictionaryAddValue(gSecPolicyLeafCallbacks,
3458 kSecPolicyCheckValidLeaf,
3459 SecPolicyCheckValidLeaf);
3460 CFDictionaryAddValue(gSecPolicyPathCallbacks,
3461 kSecPolicyCheckValidRoot,
3462 SecPolicyCheckValidRoot);
3463 CFDictionaryAddValue(gSecPolicyPathCallbacks,
3464 kSecPolicyCheckIssuerCommonName,
3465 SecPolicyCheckIssuerCommonName);
3466 CFDictionaryAddValue(gSecPolicyLeafCallbacks,
3467 kSecPolicyCheckSubjectCommonNamePrefix,
3468 SecPolicyCheckSubjectCommonNamePrefix);
3469 CFDictionaryAddValue(gSecPolicyLeafCallbacks,
3470 kSecPolicyCheckSubjectCommonName,
3471 SecPolicyCheckSubjectCommonName);
3472 CFDictionaryAddValue(gSecPolicyLeafCallbacks,
3473 kSecPolicyCheckNotValidBefore,
3474 SecPolicyCheckNotValidBefore);
3475 CFDictionaryAddValue(gSecPolicyPathCallbacks,
3476 kSecPolicyCheckChainLength,
3477 SecPolicyCheckChainLength);
3478 CFDictionaryAddValue(gSecPolicyPathCallbacks,
3479 kSecPolicyCheckAnchorSHA1,
3480 SecPolicyCheckAnchorSHA1);
3481 CFDictionaryAddValue(gSecPolicyPathCallbacks,
3482 kSecPolicyCheckAnchorSHA256,
3483 SecPolicyCheckAnchorSHA256);
3484 CFDictionaryAddValue(gSecPolicyPathCallbacks,
3485 kSecPolicyCheckAnchorApple,
3486 SecPolicyCheckAnchorApple);
3487 CFDictionaryAddValue(gSecPolicyLeafCallbacks,
3488 kSecPolicyCheckSubjectOrganization,
3489 SecPolicyCheckSubjectOrganization);
3490 CFDictionaryAddValue(gSecPolicyLeafCallbacks,
3491 kSecPolicyCheckSubjectOrganizationalUnit,
3492 SecPolicyCheckSubjectOrganizationalUnit);
3493 CFDictionaryAddValue(gSecPolicyLeafCallbacks,
3494 kSecPolicyCheckEAPTrustedServerNames,
3495 SecPolicyCheckEAPTrustedServerNames);
3496 CFDictionaryAddValue(gSecPolicyLeafCallbacks,
3497 kSecPolicyCheckSubjectCommonNameTEST,
3498 SecPolicyCheckSubjectCommonNameTEST);
3499 CFDictionaryAddValue(gSecPolicyLeafCallbacks,
3500 kSecPolicyCheckRevocation,
3501 SecPolicyCheckRevocation);
3502 CFDictionaryAddValue(gSecPolicyLeafCallbacks,
3503 kSecPolicyCheckRevocationResponseRequired,
3504 SecPolicyCheckRevocationResponseRequired);
3505 CFDictionaryAddValue(gSecPolicyLeafCallbacks,
3506 kSecPolicyCheckNoNetworkAccess,
3507 SecPolicyCheckNoNetworkAccess);
3508 CFDictionaryAddValue(gSecPolicyLeafCallbacks,
3509 kSecPolicyCheckBlackListedLeaf,
3510 SecPolicyCheckBlackListedLeaf);
3511 CFDictionaryAddValue(gSecPolicyLeafCallbacks,
3512 kSecPolicyCheckGrayListedLeaf,
3513 SecPolicyCheckGrayListedLeaf);
3514 CFDictionaryAddValue(gSecPolicyLeafCallbacks,
3515 kSecPolicyCheckLeafMarkerOid,
3516 SecPolicyCheckLeafMarkerOid);
3517 CFDictionaryAddValue(gSecPolicyLeafCallbacks,
3518 kSecPolicyCheckLeafMarkerOidWithoutValueCheck,
3519 SecPolicyCheckLeafMarkerOidWithoutValueCheck);
3520 CFDictionaryAddValue(gSecPolicyPathCallbacks,
3521 kSecPolicyCheckIntermediateSPKISHA256,
3522 SecPolicyCheckIntermediateSPKISHA256);
3523 CFDictionaryAddValue(gSecPolicyPathCallbacks,
3524 kSecPolicyCheckIntermediateEKU,
3525 SecPolicyCheckIntermediateEKU);
3526 CFDictionaryAddValue(gSecPolicyPathCallbacks,
3527 kSecPolicyCheckIntermediateMarkerOid,
3528 SecPolicyCheckIntermediateMarkerOid);
3529 CFDictionaryAddValue(gSecPolicyLeafCallbacks,
3530 kSecPolicyCheckCertificatePolicy,
3531 SecPolicyCheckCertificatePolicyOid);
3532 CFDictionaryAddValue(gSecPolicyPathCallbacks,
3533 kSecPolicyCheckWeakIntermediates,
3534 SecPolicyCheckWeakIntermediates);
3535 CFDictionaryAddValue(gSecPolicyLeafCallbacks,
3536 kSecPolicyCheckWeakLeaf,
3537 SecPolicyCheckWeakLeaf);
3538 CFDictionaryAddValue(gSecPolicyPathCallbacks,
3539 kSecPolicyCheckWeakRoot,
3540 SecPolicyCheckWeakRoot);
3541 CFDictionaryAddValue(gSecPolicyPathCallbacks,
3542 kSecPolicyCheckKeySize,
3543 SecPolicyCheckKeySize);
3544 CFDictionaryAddValue(gSecPolicyPathCallbacks,
3545 kSecPolicyCheckSignatureHashAlgorithms,
3546 SecPolicyCheckSignatureHashAlgorithms);
3547 }
3548
3549 // MARK: -
3550 // MARK: SecPVCRef
3551 /********************************************************
3552 ****************** SecPVCRef Functions *****************
3553 ********************************************************/
3554
3555 void SecPVCInit(SecPVCRef pvc, SecPathBuilderRef builder, CFArrayRef policies,
3556 CFAbsoluteTime verifyTime) {
3557 secdebug("alloc", "%p", pvc);
3558 // Weird logging policies crashes.
3559 //secdebug("policy", "%@", policies);
3560
3561 // Zero the pvc struct so only non-zero fields need to be explicitly set
3562 memset(pvc, 0, sizeof(struct OpaqueSecPVC));
3563 pvc->builder = builder;
3564 pvc->policies = policies;
3565 if (policies)
3566 CFRetain(policies);
3567 pvc->verifyTime = verifyTime;
3568 pvc->result = true;
3569 }
3570
3571 static void SecPVCDeleteRVCs(SecPVCRef pvc) {
3572 secdebug("alloc", "%p", pvc);
3573 if (pvc->rvcs) {
3574 CFIndex certIX, certCount = SecPVCGetCertificateCount(pvc) - 1;
3575 for (certIX = 0; certIX < certCount; ++certIX) {
3576 SecRVCRef rvc = &((SecRVCRef)pvc->rvcs)[certIX];
3577 SecRVCDelete(rvc);
3578 }
3579 free(pvc->rvcs);
3580 pvc->rvcs = NULL;
3581 }
3582 }
3583
3584 void SecPVCDelete(SecPVCRef pvc) {
3585 secdebug("alloc", "%p", pvc);
3586 CFReleaseNull(pvc->policies);
3587 CFReleaseNull(pvc->details);
3588 CFReleaseNull(pvc->info);
3589 if (pvc->valid_policy_tree) {
3590 policy_tree_prune(&pvc->valid_policy_tree);
3591 }
3592 SecPVCDeleteRVCs(pvc);
3593 CFReleaseNull(pvc->path);
3594 }
3595
3596 void SecPVCSetPath(SecPVCRef pvc, SecCertificatePathRef path,
3597 CF_CONSUMED CFArrayRef details) {
3598 secdebug("policy", "%@", path);
3599 bool samePath = ((!path && !pvc->path) || (path && pvc->path && CFEqual(path, pvc->path)));
3600 if (!samePath) {
3601 /* Changing path makes us clear the Revocation Verification Contexts */
3602 SecPVCDeleteRVCs(pvc);
3603 CFReleaseSafe(pvc->path);
3604 pvc->path = CFRetainSafe(path);
3605 }
3606 pvc->details = details;
3607 CFReleaseNull(pvc->info);
3608 if (pvc->valid_policy_tree) {
3609 policy_tree_prune(&pvc->valid_policy_tree);
3610 }
3611 pvc->policyIX = 0;
3612
3613 /* Since we don't run the LeafChecks again, we need to preserve the
3614 * result the leaf had. */
3615 pvc->result = (details) ? (CFDictionaryGetCount(CFArrayGetValueAtIndex(details, 0)) == 0)
3616 : true;
3617 }
3618
3619 SecPolicyRef SecPVCGetPolicy(SecPVCRef pvc) {
3620 return (SecPolicyRef)CFArrayGetValueAtIndex(pvc->policies, pvc->policyIX);
3621 }
3622
3623 CFIndex SecPVCGetCertificateCount(SecPVCRef pvc) {
3624 return SecCertificatePathGetCount(pvc->path);
3625 }
3626
3627 SecCertificateRef SecPVCGetCertificateAtIndex(SecPVCRef pvc, CFIndex ix) {
3628 return SecCertificatePathGetCertificateAtIndex(pvc->path, ix);
3629 }
3630
3631 bool SecPVCIsCertificateAtIndexSelfSigned(SecPVCRef pvc, CFIndex ix) {
3632 return SecCertificatePathSelfSignedIndex(pvc->path) == ix;
3633 }
3634
3635 void SecPVCSetCheckRevocation(SecPVCRef pvc, CFStringRef method) {
3636 pvc->check_revocation = method;
3637 secdebug("rvc", "deferred revocation checking enabled using %@ method", method);
3638 }
3639
3640 void SecPVCSetCheckRevocationResponseRequired(SecPVCRef pvc) {
3641 pvc->response_required = true;
3642 secdebug("rvc", "revocation response required");
3643 }
3644
3645 bool SecPVCIsAnchored(SecPVCRef pvc) {
3646 return SecCertificatePathIsAnchored(pvc->path);
3647 }
3648
3649 CFAbsoluteTime SecPVCGetVerifyTime(SecPVCRef pvc) {
3650 return pvc->verifyTime;
3651 }
3652
3653 static int32_t detailKeyToCssmErr(CFStringRef key) {
3654 int32_t result = 0;
3655
3656 if (CFEqual(key, kSecPolicyCheckSSLHostname)) {
3657 result = -2147408896; // CSSMERR_APPLETP_HOSTNAME_MISMATCH
3658 }
3659 else if (CFEqual(key, kSecPolicyCheckEmail)) {
3660 result = -2147408872; // CSSMERR_APPLETP_SMIME_EMAIL_ADDRS_NOT_FOUND
3661 }
3662 else if (CFEqual(key, kSecPolicyCheckValidLeaf) ||
3663 CFEqual(key, kSecPolicyCheckValidIntermediates) ||
3664 CFEqual(key, kSecPolicyCheckValidRoot)) {
3665 result = -2147409654; // CSSMERR_TP_CERT_EXPIRED
3666 }
3667
3668 return result;
3669 }
3670
3671 static bool SecPVCMeetsConstraint(SecPVCRef pvc, SecCertificateRef certificate, CFDictionaryRef constraint);
3672
3673 static bool SecPVCIsAllowedError(SecPVCRef pvc, CFIndex ix, CFStringRef key) {
3674 bool result = false;
3675 CFArrayRef constraints = SecCertificatePathGetUsageConstraintsAtIndex(pvc->path, ix);
3676 SecCertificateRef cert = SecCertificatePathGetCertificateAtIndex(pvc->path, ix);
3677 CFIndex constraintIX, constraintCount = CFArrayGetCount(constraints);
3678
3679 for (constraintIX = 0; constraintIX < constraintCount; constraintIX++) {
3680 CFDictionaryRef constraint = (CFDictionaryRef)CFArrayGetValueAtIndex(constraints, constraintIX);
3681 CFNumberRef allowedErrorNumber = NULL;
3682 if (!isDictionary(constraint)) {
3683 continue;
3684 }
3685 allowedErrorNumber = (CFNumberRef)CFDictionaryGetValue(constraint, kSecTrustSettingsAllowedError);
3686 int32_t allowedErrorValue = 0;
3687 if (!isNumber(allowedErrorNumber) || !CFNumberGetValue(allowedErrorNumber, kCFNumberSInt32Type, &allowedErrorValue)) {
3688 continue;
3689 }
3690
3691 if (SecPVCMeetsConstraint(pvc, cert, constraint)) {
3692 if (allowedErrorValue == detailKeyToCssmErr(key)) {
3693 result = true;
3694 break;
3695 }
3696 }
3697 }
3698 return result;
3699 }
3700
3701 /* AUDIT[securityd](done):
3702 policy->_options is a caller provided dictionary, only its cf type has
3703 been checked.
3704 */
3705 bool SecPVCSetResultForced(SecPVCRef pvc,
3706 CFStringRef key, CFIndex ix, CFTypeRef result, bool force) {
3707
3708 secnotice("policy", "cert[%d]: %@ =(%s)[%s]> %@", (int) ix, key,
3709 (pvc->callbacks == gSecPolicyLeafCallbacks ? "leaf"
3710 : (pvc->callbacks == gSecPolicyPathCallbacks ? "path"
3711 : "custom")),
3712 (force ? "force" : ""), result);
3713
3714 /* If this is not something the current policy cares about ignore
3715 this error and return true so our caller continues evaluation. */
3716 if (!force) {
3717 /* @@@ The right long term fix might be to check if none of the passed
3718 in policies contain this key, since not all checks are run for all
3719 policies. */
3720 SecPolicyRef policy = SecPVCGetPolicy(pvc);
3721 if (policy && !CFDictionaryContainsKey(policy->_options, key))
3722 return true;
3723 }
3724
3725 /* Check to see if the SecTrustSettings for the certificate in question
3726 tell us to ignore this error. */
3727 if (SecPVCIsAllowedError(pvc, ix, key)) {
3728 secinfo("policy", "cert[%d]: skipped allowed error %@", (int) ix, key);
3729 return true;
3730 }
3731
3732 pvc->result = false;
3733 if (!pvc->details)
3734 return false;
3735
3736 CFMutableDictionaryRef detail =
3737 (CFMutableDictionaryRef)CFArrayGetValueAtIndex(pvc->details, ix);
3738
3739 /* Perhaps detail should have an array of results per key? As it stands
3740 in the case of multiple policy failures the last failure stands. */
3741 CFDictionarySetValue(detail, key, result);
3742
3743 return true;
3744 }
3745
3746 bool SecPVCSetResult(SecPVCRef pvc,
3747 CFStringRef key, CFIndex ix, CFTypeRef result) {
3748 return SecPVCSetResultForced(pvc, key, ix, result, false);
3749 }
3750
3751 /* AUDIT[securityd](done):
3752 key(ok) is a caller provided.
3753 value(ok, unused) is a caller provided.
3754 */
3755 static void SecPVCValidateKey(const void *key, const void *value,
3756 void *context) {
3757 SecPVCRef pvc = (SecPVCRef)context;
3758
3759 /* If our caller doesn't want full details and we failed earlier there is
3760 no point in doing additional checks. */
3761 if (!pvc->result && !pvc->details)
3762 return;
3763
3764 SecPolicyCheckFunction fcn = (SecPolicyCheckFunction)
3765 CFDictionaryGetValue(pvc->callbacks, key);
3766
3767 if (!fcn) {
3768 #if 0
3769 /* Why not to have optional policy checks rant:
3770 Not all keys are in all dictionaries anymore, so why not make checks
3771 optional? This way a client can ask for something and the server will
3772 do a best effort based on the supported flags. It works since they are
3773 synchronized now, but we need some debug checking here for now. */
3774 pvc->result = false;
3775 #endif
3776 if (pvc->callbacks == gSecPolicyLeafCallbacks) {
3777 if (!CFDictionaryContainsKey(gSecPolicyPathCallbacks, key)) {
3778 pvc->result = false;
3779 }
3780 } else if (pvc->callbacks == gSecPolicyPathCallbacks) {
3781 if (!CFDictionaryContainsKey(gSecPolicyLeafCallbacks, key)) {
3782 pvc->result = false;
3783 }
3784 } else {
3785 /* Non standard validation phase, nothing is optional. */
3786 pvc->result = false;
3787 }
3788 return;
3789 }
3790
3791 fcn(pvc, (CFStringRef)key);
3792 }
3793
3794 /* AUDIT[securityd](done):
3795 policy->_options is a caller provided dictionary, only its cf type has
3796 been checked.
3797 */
3798 bool SecPVCLeafChecks(SecPVCRef pvc) {
3799 pvc->result = true;
3800 CFArrayRef policies = pvc->policies;
3801 CFIndex ix, count = CFArrayGetCount(policies);
3802 for (ix = 0; ix < count; ++ix) {
3803 SecPolicyRef policy = (SecPolicyRef)CFArrayGetValueAtIndex(policies, ix);
3804 pvc->policyIX = ix;
3805 /* Validate all keys for all policies. */
3806 pvc->callbacks = gSecPolicyLeafCallbacks;
3807 CFDictionaryApplyFunction(policy->_options, SecPVCValidateKey, pvc);
3808 if (!pvc->result && !pvc->details)
3809 return pvc->result;
3810 }
3811
3812 return pvc->result;
3813 }
3814
3815 bool SecPVCParentCertificateChecks(SecPVCRef pvc, CFIndex ix) {
3816 /* Check stuff common to intermediate and anchors. */
3817 CFAbsoluteTime verifyTime = SecPVCGetVerifyTime(pvc);
3818 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix);
3819 bool is_anchor = (ix == SecPVCGetCertificateCount(pvc) - 1
3820 && SecPVCIsAnchored(pvc));
3821 if (!SecCertificateIsValid(cert, verifyTime)) {
3822 /* Certificate has expired. */
3823 if (!SecPVCSetResult(pvc, is_anchor ? kSecPolicyCheckValidRoot
3824 : kSecPolicyCheckValidIntermediates, ix, kCFBooleanFalse))
3825 goto errOut;
3826 }
3827
3828 if (SecCertificateIsWeakKey(cert)) {
3829 /* Certificate uses weak key. */
3830 if (!SecPVCSetResult(pvc, is_anchor ? kSecPolicyCheckWeakRoot
3831 : kSecPolicyCheckWeakIntermediates, ix, kCFBooleanFalse))
3832 goto errOut;
3833 }
3834
3835 if (is_anchor) {
3836 /* Perform anchor specific checks. */
3837 /* Don't think we have any of these. */
3838 } else {
3839 /* Perform intermediate specific checks. */
3840
3841 /* (k) Basic constraints only relevant for v3 and later. */
3842 if (SecCertificateVersion(cert) >= 3) {
3843 const SecCEBasicConstraints *bc =
3844 SecCertificateGetBasicConstraints(cert);
3845 if (!bc || !bc->isCA) {
3846 /* Basic constraints not present or not marked as isCA, illegal. */
3847 if (!SecPVCSetResultForced(pvc, kSecPolicyCheckBasicConstraints,
3848 ix, kCFBooleanFalse, true))
3849 goto errOut;
3850 }
3851 }
3852 /* (l) max_path_length is checked elsewhere. */
3853
3854 /* (n) If a key usage extension is present, verify that the keyCertSign bit is set. */
3855 SecKeyUsage keyUsage = SecCertificateGetKeyUsage(cert);
3856 if (keyUsage && !(keyUsage & kSecKeyUsageKeyCertSign)) {
3857 if (!SecPVCSetResultForced(pvc, kSecPolicyCheckKeyUsage,
3858 ix, kCFBooleanFalse, true))
3859 goto errOut;
3860 }
3861 }
3862
3863 errOut:
3864 return pvc->result;
3865 }
3866
3867 bool SecPVCBlackListedKeyChecks(SecPVCRef pvc, CFIndex ix) {
3868 /* Check stuff common to intermediate and anchors. */
3869
3870 SecOTAPKIRef otapkiRef = SecOTAPKICopyCurrentOTAPKIRef();
3871 if (NULL != otapkiRef)
3872 {
3873 CFSetRef blackListedKeys = SecOTAPKICopyBlackListSet(otapkiRef);
3874 CFRelease(otapkiRef);
3875 if (NULL != blackListedKeys)
3876 {
3877 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix);
3878 CFIndex count = SecPVCGetCertificateCount(pvc);
3879 bool is_last = (ix == count - 1);
3880 bool is_anchor = (is_last && SecPVCIsAnchored(pvc));
3881 if (!is_anchor) {
3882 /* Check for blacklisted intermediate issuer keys. */
3883 CFDataRef dgst = SecCertificateCopyPublicKeySHA1Digest(cert);
3884 if (dgst) {
3885 /* Check dgst against blacklist. */
3886 if (CFSetContainsValue(blackListedKeys, dgst)) {
3887 /* Check allow list for this blacklisted issuer key,
3888 which is the authority key of the issued cert at ix-1.
3889 If ix is the last cert, the root is missing, so we
3890 also check our own authority key in that case.
3891 */
3892 bool allowed = ((ix && SecPVCCheckCertificateAllowList(pvc, ix - 1)) ||
3893 (is_last && SecPVCCheckCertificateAllowList(pvc, ix)));
3894 if (!allowed) {
3895 SecPVCSetResultForced(pvc, kSecPolicyCheckBlackListedKey,
3896 ix, kCFBooleanFalse, true);
3897 }
3898 pvc->is_allowlisted = allowed;
3899 }
3900 CFRelease(dgst);
3901 }
3902 }
3903 CFRelease(blackListedKeys);
3904 return pvc->result;
3905 }
3906 }
3907 // Assume OK
3908 return true;
3909 }
3910
3911 bool SecPVCGrayListedKeyChecks(SecPVCRef pvc, CFIndex ix)
3912 {
3913 /* Check stuff common to intermediate and anchors. */
3914 SecOTAPKIRef otapkiRef = SecOTAPKICopyCurrentOTAPKIRef();
3915 if (NULL != otapkiRef)
3916 {
3917 CFSetRef grayListKeys = SecOTAPKICopyGrayList(otapkiRef);
3918 CFRelease(otapkiRef);
3919 if (NULL != grayListKeys)
3920 {
3921 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix);
3922 CFIndex count = SecPVCGetCertificateCount(pvc);
3923 bool is_last = (ix == count - 1);
3924 bool is_anchor = (is_last && SecPVCIsAnchored(pvc));
3925 if (!is_anchor) {
3926 /* Check for gray listed intermediate issuer keys. */
3927 CFDataRef dgst = SecCertificateCopyPublicKeySHA1Digest(cert);
3928 if (dgst) {
3929 /* Check dgst against gray list. */
3930 if (CFSetContainsValue(grayListKeys, dgst)) {
3931 /* Check allow list for this graylisted issuer key,
3932 which is the authority key of the issued cert at ix-1.
3933 If ix is the last cert, the root is missing, so we
3934 also check our own authority key in that case.
3935 */
3936 bool allowed = ((ix && SecPVCCheckCertificateAllowList(pvc, ix - 1)) ||
3937 (is_last && SecPVCCheckCertificateAllowList(pvc, ix)));
3938 if (!allowed) {
3939 SecPVCSetResultForced(pvc, kSecPolicyCheckGrayListedKey,
3940 ix, kCFBooleanFalse, true);
3941 }
3942 pvc->is_allowlisted = allowed;
3943 }
3944 CFRelease(dgst);
3945 }
3946 }
3947 CFRelease(grayListKeys);
3948 return pvc->result;
3949 }
3950 }
3951 // Assume ok
3952 return true;
3953 }
3954
3955 static bool SecPVCContainsPolicy(SecPVCRef pvc, CFStringRef searchOid, CFStringRef searchName, CFIndex *policyIX) {
3956 if (!isString(searchName) && !isString(searchOid)) {
3957 return false;
3958 }
3959 CFArrayRef policies = pvc->policies;
3960 CFIndex ix, count = CFArrayGetCount(policies);
3961 for (ix = 0; ix < count; ++ix) {
3962 SecPolicyRef policy = (SecPolicyRef)CFArrayGetValueAtIndex(policies, ix);
3963 CFStringRef policyName = SecPolicyGetName(policy);
3964 CFStringRef policyOid = SecPolicyGetOidString(policy);
3965 /* Prefer a match of both name and OID */
3966 if (searchOid && searchName && policyOid && policyName) {
3967 if (CFEqual(searchOid, policyOid) &&
3968 CFEqual(searchName, policyName)) {
3969 if (policyIX) { *policyIX = ix; }
3970 return true;
3971 }
3972 }
3973 /* Next best is just OID. */
3974 if (!searchName && searchOid && policyOid) {
3975 if (CFEqual(searchOid, policyOid)) {
3976 if (policyIX) { *policyIX = ix; }
3977 return true;
3978 }
3979 }
3980 if (!searchOid && searchName && policyName) {
3981 if (CFEqual(searchName, policyName)) {
3982 if (policyIX) { *policyIX = ix; }
3983 return true;
3984 }
3985 }
3986 }
3987 return false;
3988 }
3989
3990 static bool SecPVCContainsString(SecPVCRef pvc, CFIndex policyIX, CFStringRef stringValue) {
3991 if (!isString(stringValue)) {
3992 return false;
3993 }
3994 bool result = false;
3995
3996 CFStringRef tmpStringValue = NULL;
3997 if (CFStringGetCharacterAtIndex(stringValue, CFStringGetLength(stringValue) -1) == (UniChar)0x0000) {
3998 tmpStringValue = CFStringCreateTruncatedCopy(stringValue, CFStringGetLength(stringValue) - 1);
3999 } else {
4000 tmpStringValue = CFStringCreateCopy(NULL, stringValue);
4001 }
4002 if (policyIX >= 0 && policyIX < CFArrayGetCount(pvc->policies)) {
4003 SecPolicyRef policy = (SecPolicyRef)CFArrayGetValueAtIndex(pvc->policies, policyIX);
4004 /* Have to look for all the possible locations of name string */
4005 CFStringRef policyString = NULL;
4006 policyString = CFDictionaryGetValue(policy->_options, kSecPolicyCheckSSLHostname);
4007 if (!policyString) {
4008 policyString = CFDictionaryGetValue(policy->_options, kSecPolicyCheckEmail);
4009 }
4010 if (policyString && (CFStringCompare(tmpStringValue, policyString, kCFCompareCaseInsensitive) == kCFCompareEqualTo)) {
4011 result = true;
4012 goto out;
4013 }
4014
4015 CFArrayRef policyStrings = NULL;
4016 policyStrings = CFDictionaryGetValue(policy->_options, kSecPolicyCheckEAPTrustedServerNames);
4017 if (policyStrings && CFArrayContainsValue(policyStrings,
4018 CFRangeMake(0, CFArrayGetCount(policyStrings)),
4019 tmpStringValue)) {
4020 result = true;
4021 goto out;
4022 }
4023 }
4024
4025 out:
4026 CFReleaseNull(tmpStringValue);
4027 return result;
4028 }
4029
4030
4031 static uint32_t ts_key_usage_for_kuNumber(CFNumberRef keyUsageNumber) {
4032 uint32_t ourTSKeyUsage = 0;
4033 uint32_t keyUsage = 0;
4034 if (keyUsageNumber &&
4035 CFNumberGetValue(keyUsageNumber, kCFNumberSInt32Type, &keyUsage)) {
4036 if (keyUsage & kSecKeyUsageDigitalSignature) {
4037 ourTSKeyUsage |= kSecTrustSettingsKeyUseSignature;
4038 }
4039 if (keyUsage & kSecKeyUsageDataEncipherment) {
4040 ourTSKeyUsage |= kSecTrustSettingsKeyUseEnDecryptData;
4041 }
4042 if (keyUsage & kSecKeyUsageKeyEncipherment) {
4043 ourTSKeyUsage |= kSecTrustSettingsKeyUseEnDecryptKey;
4044 }
4045 if (keyUsage & kSecKeyUsageKeyAgreement) {
4046 ourTSKeyUsage |= kSecTrustSettingsKeyUseKeyExchange;
4047 }
4048 if (keyUsage == kSecKeyUsageAll) {
4049 ourTSKeyUsage = kSecTrustSettingsKeyUseAny;
4050 }
4051 }
4052 return ourTSKeyUsage;
4053 }
4054
4055 static uint32_t ts_key_usage_for_policy(SecPolicyRef policy) {
4056 uint32_t ourTSKeyUsage = 0;
4057 CFTypeRef policyKeyUsageType = NULL;
4058
4059 policyKeyUsageType = (CFTypeRef)CFDictionaryGetValue(policy->_options, kSecPolicyCheckKeyUsage);
4060 if (isArray(policyKeyUsageType)) {
4061 CFIndex ix, count = CFArrayGetCount(policyKeyUsageType);
4062 for (ix = 0; ix < count; ix++) {
4063 CFNumberRef policyKeyUsageNumber = NULL;
4064 policyKeyUsageNumber = (CFNumberRef)CFArrayGetValueAtIndex(policyKeyUsageType, ix);
4065 ourTSKeyUsage |= ts_key_usage_for_kuNumber(policyKeyUsageNumber);
4066 }
4067 } else if (isNumber(policyKeyUsageType)) {
4068 ourTSKeyUsage |= ts_key_usage_for_kuNumber(policyKeyUsageType);
4069 }
4070
4071 return ourTSKeyUsage;
4072 }
4073
4074 static bool SecPVCContainsTrustSettingsKeyUsage(SecPVCRef pvc,
4075 SecCertificateRef certificate, CFIndex policyIX, CFNumberRef keyUsageNumber) {
4076 int64_t keyUsageValue = 0;
4077 uint32_t ourKeyUsage = 0;
4078
4079 if (!isNumber(keyUsageNumber) || !CFNumberGetValue(keyUsageNumber, kCFNumberSInt64Type, &keyUsageValue)) {
4080 return false;
4081 }
4082
4083 if (keyUsageValue == kSecTrustSettingsKeyUseAny) {
4084 return true;
4085 }
4086
4087 /* We're using the key for revocation if we have the OCSPSigner policy.
4088 * @@@ If we support CRLs, we'd need to check for that policy here too.
4089 */
4090 if (SecPVCContainsPolicy(pvc, kSecPolicyAppleOCSPSigner, NULL, NULL)) {
4091 ourKeyUsage |= kSecTrustSettingsKeyUseSignRevocation;
4092 }
4093
4094 /* We're using the key for verifying a cert if it's a root/intermediate
4095 * in the chain. If the cert isn't in the path yet, we're about to add it,
4096 * so it's a root/intermediate. If there is no path, this is the leaf.
4097 */
4098 CFIndex pathIndex = -1;
4099 if (pvc->path) {
4100 pathIndex = SecCertificatePathGetIndexOfCertificate(pvc->path, certificate);
4101 } else {
4102 pathIndex = 0;
4103 }
4104 if (pathIndex != 0) {
4105 ourKeyUsage |= kSecTrustSettingsKeyUseSignCert;
4106 }
4107
4108 /* The rest of the key usages may be specified by the policy(ies). */
4109 if (policyIX >= 0 && policyIX < CFArrayGetCount(pvc->policies)) {
4110 SecPolicyRef policy = (SecPolicyRef)CFArrayGetValueAtIndex(pvc->policies, policyIX);
4111 ourKeyUsage |= ts_key_usage_for_policy(policy);
4112 } else {
4113 /* Get key usage from ALL policies */
4114 CFIndex ix, count = CFArrayGetCount(pvc->policies);
4115 for (ix = 0; ix < count; ix++) {
4116 SecPolicyRef policy = (SecPolicyRef)CFArrayGetValueAtIndex(pvc->policies, ix);
4117 ourKeyUsage |= ts_key_usage_for_policy(policy);
4118 }
4119 }
4120
4121 if (ourKeyUsage == (uint32_t)(keyUsageValue & 0x00ffffffff)) {
4122 return true;
4123 }
4124
4125 return false;
4126 }
4127
4128 #if TARGET_OS_MAC && !TARGET_OS_IPHONE
4129 /* We need to declare the SecTrustedApplicationRef type for those binaries
4130 * that don't include the OS X Security Framework headers. */
4131 typedef struct CF_BRIDGED_TYPE(id) OpaqueSecTrustedApplicationRef *SecTrustedApplicationRef;
4132
4133 #include <Security/SecTrustedApplicationPriv.h>
4134 #include <bsm/libbsm.h>
4135 #include <libproc.h>
4136
4137 static bool SecPVCCallerIsApplication(CFDataRef clientAuditToken, CFTypeRef appRef) {
4138 bool result = false;
4139 audit_token_t auditToken = {};
4140 char path[MAXPATHLEN];
4141
4142 require(appRef && clientAuditToken, out);
4143 require(CFGetTypeID(appRef) == SecTrustedApplicationGetTypeID(), out);
4144
4145 require(sizeof(auditToken) == CFDataGetLength(clientAuditToken), out);
4146 CFDataGetBytes(clientAuditToken, CFRangeMake(0, sizeof(auditToken)), (uint8_t *)&auditToken);
4147 require(proc_pidpath(audit_token_to_pid(auditToken), path, sizeof(path)) > 0, out);
4148
4149 if(errSecSuccess == SecTrustedApplicationValidateWithPath((SecTrustedApplicationRef)appRef, path)) {
4150 result = true;
4151 }
4152
4153 out:
4154 return result;
4155 }
4156 #endif
4157
4158 static bool SecPVCMeetsConstraint(SecPVCRef pvc, SecCertificateRef certificate, CFDictionaryRef constraint) {
4159 CFStringRef policyOid = NULL, policyString = NULL, policyName = NULL;
4160 CFNumberRef keyUsageNumber = NULL;
4161 CFTypeRef trustedApplicationData = NULL;
4162
4163 bool policyMatch = false, policyStringMatch = false, applicationMatch = false , keyUsageMatch = false;
4164 bool result = false;
4165
4166 #if TARGET_OS_MAC && !TARGET_OS_IPHONE
4167 /* OS X returns a SecPolicyRef in the constraints. Convert to the oid string. */
4168 SecPolicyRef policy = NULL;
4169 policy = (SecPolicyRef)CFDictionaryGetValue(constraint, kSecTrustSettingsPolicy);
4170 policyOid = (policy) ? policy->_oid : NULL;
4171 #else
4172 policyOid = (CFStringRef)CFDictionaryGetValue(constraint, kSecTrustSettingsPolicy);
4173 #endif
4174 policyName = (CFStringRef)CFDictionaryGetValue(constraint, kSecTrustSettingsPolicyName);
4175 policyString = (CFStringRef)CFDictionaryGetValue(constraint, kSecTrustSettingsPolicyString);
4176 keyUsageNumber = (CFNumberRef)CFDictionaryGetValue(constraint, kSecTrustSettingsKeyUsage);
4177
4178 CFIndex policyIX = -1;
4179 policyMatch = SecPVCContainsPolicy(pvc, policyOid, policyName, &policyIX);
4180 policyStringMatch = SecPVCContainsString(pvc, policyIX, policyString);
4181 keyUsageMatch = SecPVCContainsTrustSettingsKeyUsage(pvc, certificate, policyIX, keyUsageNumber);
4182
4183 #if TARGET_OS_MAC && !TARGET_OS_IPHONE
4184 trustedApplicationData = CFDictionaryGetValue(constraint, kSecTrustSettingsApplication);
4185 CFDataRef clientAuditToken = SecPathBuilderCopyClientAuditToken(pvc->builder);
4186 applicationMatch = SecPVCCallerIsApplication(clientAuditToken, trustedApplicationData);
4187 CFReleaseNull(clientAuditToken);
4188 #else
4189 if(CFDictionaryContainsKey(constraint, kSecTrustSettingsApplication)) {
4190 secerror("kSecTrustSettingsApplication is not yet supported on this platform");
4191 }
4192 #endif
4193
4194 /* If we either didn't find the parameter in the dictionary or we got a match
4195 * against that parameter, for all possible parameters in the dictionary, then
4196 * this trust setting result applies to the output. */
4197 if (((!policyOid && !policyName) || policyMatch) &&
4198 (!policyString || policyStringMatch) &&
4199 (!trustedApplicationData || applicationMatch) &&
4200 (!keyUsageNumber || keyUsageMatch)) {
4201 result = true;
4202 }
4203
4204 return result;
4205 }
4206
4207 SecTrustSettingsResult SecPVCGetTrustSettingsResult(SecPVCRef pvc, SecCertificateRef certificate, CFArrayRef constraints) {
4208 SecTrustSettingsResult result = kSecTrustSettingsResultInvalid;
4209 CFIndex constraintIX, constraintCount = CFArrayGetCount(constraints);
4210 for (constraintIX = 0; constraintIX < constraintCount; constraintIX++) {
4211 CFDictionaryRef constraint = (CFDictionaryRef)CFArrayGetValueAtIndex(constraints, constraintIX);
4212 if (!isDictionary(constraint)) {
4213 continue;
4214 }
4215
4216 CFNumberRef resultNumber = NULL;
4217 resultNumber = (CFNumberRef)CFDictionaryGetValue(constraint, kSecTrustSettingsResult);
4218 uint32_t resultValue = kSecTrustSettingsResultInvalid;
4219 if (!isNumber(resultNumber) || !CFNumberGetValue(resultNumber, kCFNumberSInt32Type, &resultValue)) {
4220 /* no SecTrustSettingsResult entry defaults to TrustRoot*/
4221 resultValue = kSecTrustSettingsResultTrustRoot;
4222 }
4223
4224 if (SecPVCMeetsConstraint(pvc, certificate, constraint)) {
4225 result = resultValue;
4226 break;
4227 }
4228 }
4229 return result;
4230 }
4231
4232 bool SecPVCCheckUsageConstraints(SecPVCRef pvc) {
4233 bool shouldDeny = false;
4234 CFIndex certIX, certCount = SecCertificatePathGetCount(pvc->path);
4235 for (certIX = 0; certIX < certCount; certIX++) {
4236 CFArrayRef constraints = SecCertificatePathGetUsageConstraintsAtIndex(pvc->path, certIX);
4237 SecCertificateRef cert = SecCertificatePathGetCertificateAtIndex(pvc->path, certIX);
4238 SecTrustSettingsResult result = SecPVCGetTrustSettingsResult(pvc, cert, constraints);
4239
4240 if (result == kSecTrustSettingsResultDeny) {
4241 SecPVCSetResultForced(pvc, kSecPolicyCheckUsageConstraints, certIX, kCFBooleanFalse, true);
4242 shouldDeny = true;
4243 }
4244 }
4245 return shouldDeny;
4246 }
4247
4248 #define kSecPolicySHA256Size 32
4249 static const UInt8 kTestDateConstraintsRoot[kSecPolicySHA256Size] = {
4250 0x51,0xA0,0xF3,0x1F,0xC0,0x1D,0xEC,0x87,0x32,0xB6,0xFD,0x13,0x6A,0x43,0x4D,0x6C,
4251 0x87,0xCD,0x62,0xE0,0x38,0xB4,0xFB,0xD6,0x40,0xB0,0xFD,0x62,0x4D,0x1F,0xCF,0x6D
4252 };
4253 static const UInt8 kWS_CA1_G2[kSecPolicySHA256Size] = {
4254 0xD4,0x87,0xA5,0x6F,0x83,0xB0,0x74,0x82,0xE8,0x5E,0x96,0x33,0x94,0xC1,0xEC,0xC2,
4255 0xC9,0xE5,0x1D,0x09,0x03,0xEE,0x94,0x6B,0x02,0xC3,0x01,0x58,0x1E,0xD9,0x9E,0x16
4256 };
4257 static const UInt8 kWS_CA1_NEW[kSecPolicySHA256Size] = {
4258 0x4B,0x22,0xD5,0xA6,0xAE,0xC9,0x9F,0x3C,0xDB,0x79,0xAA,0x5E,0xC0,0x68,0x38,0x47,
4259 0x9C,0xD5,0xEC,0xBA,0x71,0x64,0xF7,0xF2,0x2D,0xC1,0xD6,0x5F,0x63,0xD8,0x57,0x08
4260 };
4261 static const UInt8 kWS_CA2_NEW[kSecPolicySHA256Size] = {
4262 0xD6,0xF0,0x34,0xBD,0x94,0xAA,0x23,0x3F,0x02,0x97,0xEC,0xA4,0x24,0x5B,0x28,0x39,
4263 0x73,0xE4,0x47,0xAA,0x59,0x0F,0x31,0x0C,0x77,0xF4,0x8F,0xDF,0x83,0x11,0x22,0x54
4264 };
4265 static const UInt8 kWS_ECC[kSecPolicySHA256Size] = {
4266 0x8B,0x45,0xDA,0x1C,0x06,0xF7,0x91,0xEB,0x0C,0xAB,0xF2,0x6B,0xE5,0x88,0xF5,0xFB,
4267 0x23,0x16,0x5C,0x2E,0x61,0x4B,0xF8,0x85,0x56,0x2D,0x0D,0xCE,0x50,0xB2,0x9B,0x02
4268 };
4269 static const UInt8 kSC_SFSCA[kSecPolicySHA256Size] = {
4270 0xC7,0x66,0xA9,0xBE,0xF2,0xD4,0x07,0x1C,0x86,0x3A,0x31,0xAA,0x49,0x20,0xE8,0x13,
4271 0xB2,0xD1,0x98,0x60,0x8C,0xB7,0xB7,0xCF,0xE2,0x11,0x43,0xB8,0x36,0xDF,0x09,0xEA
4272 };
4273 static const UInt8 kSC_SHA2[kSecPolicySHA256Size] = {
4274 0xE1,0x78,0x90,0xEE,0x09,0xA3,0xFB,0xF4,0xF4,0x8B,0x9C,0x41,0x4A,0x17,0xD6,0x37,
4275 0xB7,0xA5,0x06,0x47,0xE9,0xBC,0x75,0x23,0x22,0x72,0x7F,0xCC,0x17,0x42,0xA9,0x11
4276 };
4277 static const UInt8 kSC_G2[kSecPolicySHA256Size] = {
4278 0xC7,0xBA,0x65,0x67,0xDE,0x93,0xA7,0x98,0xAE,0x1F,0xAA,0x79,0x1E,0x71,0x2D,0x37,
4279 0x8F,0xAE,0x1F,0x93,0xC4,0x39,0x7F,0xEA,0x44,0x1B,0xB7,0xCB,0xE6,0xFD,0x59,0x95
4280 };
4281
4282 bool SecPVCCheckIssuerDateConstraints(SecPVCRef pvc) {
4283 static CFSetRef sConstrainedRoots = NULL;
4284 static dispatch_once_t _t;
4285 dispatch_once(&_t, ^{
4286 const UInt8 *v_hashes[] = {
4287 kWS_CA1_G2, kWS_CA1_NEW, kWS_CA2_NEW, kWS_ECC,
4288 kSC_SFSCA, kSC_SHA2, kSC_G2, kTestDateConstraintsRoot
4289 };
4290 CFMutableSetRef set = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks);
4291 CFIndex ix, count = sizeof(v_hashes)/sizeof(*v_hashes);
4292 for (ix=0; ix<count; ix++) {
4293 CFDataRef hash = CFDataCreateWithBytesNoCopy(NULL, v_hashes[ix],
4294 kSecPolicySHA256Size, kCFAllocatorNull);
4295 if (hash) {
4296 CFSetAddValue(set, hash);
4297 CFRelease(hash);
4298 }
4299 }
4300 sConstrainedRoots = set;
4301 });
4302
4303 bool shouldDeny = false;
4304 CFIndex certIX, certCount = SecCertificatePathGetCount(pvc->path);
4305 for (certIX = certCount - 1; certIX >= 0 && !shouldDeny; certIX--) {
4306 SecCertificateRef cert = SecCertificatePathGetCertificateAtIndex(pvc->path, certIX);
4307 CFDataRef sha256 = SecCertificateCopySHA256Digest(cert);
4308 if (sha256 && CFSetContainsValue(sConstrainedRoots, sha256)) {
4309 /* matched a constrained root; check notBefore dates on all its children. */
4310 CFIndex childIX = certIX;
4311 while (--childIX >= 0) {
4312 SecCertificateRef child = SecCertificatePathGetCertificateAtIndex(pvc->path, childIX);
4313 /* 1 Dec 2016 00:00:00 GMT */
4314 if (child && (CFAbsoluteTime)502243200.0 <= SecCertificateNotValidBefore(child)) {
4315 SecPVCSetResultForced(pvc, kSecPolicyCheckBlackListedKey, certIX, kCFBooleanFalse, true);
4316 shouldDeny = true;
4317 break;
4318 }
4319 }
4320 }
4321 CFReleaseNull(sha256);
4322 }
4323 return shouldDeny;
4324 }
4325
4326 /* AUDIT[securityd](done):
4327 policy->_options is a caller provided dictionary, only its cf type has
4328 been checked.
4329 */
4330 bool SecPVCPathChecks(SecPVCRef pvc) {
4331 secdebug("policy", "begin path: %@", pvc->path);
4332 bool completed = true;
4333 /* This needs to be initialized before we call any function that might call
4334 SecPVCSetResultForced(). */
4335 pvc->policyIX = 0;
4336 SecPolicyCheckIdLinkage(pvc, kSecPolicyCheckIdLinkage);
4337 if (pvc->result || pvc->details) {
4338 SecPolicyCheckBasicCertificateProcessing(pvc,
4339 kSecPolicyCheckBasicCertificateProcessing);
4340 }
4341
4342 CFArrayRef policies = pvc->policies;
4343 CFIndex count = CFArrayGetCount(policies);
4344 for (; pvc->policyIX < count; ++pvc->policyIX) {
4345 /* Validate all keys for all policies. */
4346 pvc->callbacks = gSecPolicyPathCallbacks;
4347 SecPolicyRef policy = SecPVCGetPolicy(pvc);
4348 CFDictionaryApplyFunction(policy->_options, SecPVCValidateKey, pvc);
4349 if (!pvc->result && !pvc->details)
4350 return completed;
4351 }
4352
4353 /* Check whether the TrustSettings say to deny a cert in the path. */
4354 (void)SecPVCCheckUsageConstraints(pvc);
4355
4356 /* Check for issuer date constraints. */
4357 (void)SecPVCCheckIssuerDateConstraints(pvc);
4358
4359 /* Check the things we can't check statically for the certificate path. */
4360 /* Critical Extensions, chainLength. */
4361
4362 /* Policy tests. */
4363 pvc->is_ev = false;
4364 if ((pvc->result || pvc->details) && pvc->optionally_ev) {
4365 bool pre_ev_check_result = pvc->result;
4366 SecPolicyCheckEV(pvc, kSecPolicyCheckExtendedValidation);
4367 pvc->is_ev = pvc->result;
4368 /* If ev checking failed, we still want to accept this chain
4369 as a non EV one, if it was valid as such. */
4370 pvc->result = pre_ev_check_result;
4371 }
4372
4373 /* Check revocation always, since we don't want a lesser recoverable result
4374 * to prevent the check from occurring. */
4375 completed = SecPVCCheckRevocation(pvc);
4376
4377 /* Check for CT */
4378 if (pvc->result || pvc->details) {
4379 /* This call will set the value of pvc->is_ct, but won't change the result (pvc->result) */
4380 SecPolicyCheckCT(pvc, kSecPolicyCheckCertificateTransparency);
4381 }
4382
4383 if (pvc->is_ev && !pvc->is_ct) {
4384 pvc->is_ct_whitelisted = SecPVCCheckCTWhiteListedLeaf(pvc);
4385 } else {
4386 pvc->is_ct_whitelisted = false;
4387 }
4388
4389 //errOut:
4390 secdebug("policy", "end %strusted completed: %d path: %@",
4391 (pvc->result ? "" : "not "), completed, pvc->path);
4392 return completed;
4393 }
4394
4395 /* This function returns 0 to indicate revocation checking was not completed
4396 for this certificate chain, otherwise return to date at which the first
4397 piece of revocation checking info we used expires. */
4398 CFAbsoluteTime SecPVCGetEarliestNextUpdate(SecPVCRef pvc) {
4399 CFIndex certIX, certCount = SecPVCGetCertificateCount(pvc);
4400 CFAbsoluteTime enu = NULL_TIME;
4401 if (certCount <= 1 || !pvc->rvcs) {
4402 return enu;
4403 }
4404 certCount--;
4405
4406 for (certIX = 0; certIX < certCount; ++certIX) {
4407 SecRVCRef rvc = &((SecRVCRef)pvc->rvcs)[certIX];
4408 CFAbsoluteTime thisCertNextUpdate = SecRVCGetEarliestNextUpdate(rvc);
4409 if (thisCertNextUpdate == 0) {
4410 if (certIX > 0) {
4411 /* We allow for CA certs to not be revocation checked if they
4412 have no ocspResponders nor CRLDPs to check against, but the leaf
4413 must be checked in order for us to claim we did revocation
4414 checking. */
4415 SecCertificateRef cert =
4416 SecPVCGetCertificateAtIndex(rvc->pvc, rvc->certIX);
4417 CFArrayRef ocspResponders = NULL;
4418 ocspResponders = SecCertificateGetOCSPResponders(cert);
4419 #if ENABLE_CRLS
4420 CFArrayRef crlDPs = NULL;
4421 crlDPs = SecCertificateGetCRLDistributionPoints(cert);
4422 #endif
4423 if ((!ocspResponders || CFArrayGetCount(ocspResponders) == 0)
4424 #if ENABLE_CRLS
4425 && (!crlDPs || CFArrayGetCount(crlDPs) == 0)
4426 #endif
4427 ) {
4428 /* We can't check this cert so we don't consider it a soft
4429 failure that we didn't. Ideally we should support crl
4430 checking and remove this workaround, since that more
4431 strict. */
4432 continue;
4433 }
4434 }
4435 secdebug("rvc", "revocation checking soft failure for cert: %ld",
4436 certIX);
4437 enu = thisCertNextUpdate;
4438 break;
4439 }
4440 if (enu == 0 || thisCertNextUpdate < enu) {
4441 enu = thisCertNextUpdate;
4442 }
4443 }
4444
4445 secdebug("rvc", "revocation valid until: %lg", enu);
4446 return enu;
4447 }