]> git.saurik.com Git - apple/security.git/blob - OSX/sec/securityd/SecPolicyServer.c
Security-57337.20.44.tar.gz
[apple/security.git] / OSX / sec / securityd / SecPolicyServer.c
1 /*
2 * Copyright (c) 2008-2015 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 <utilities/SecIOFormat.h>
32 #include <securityd/asynchttp.h>
33 #include <securityd/policytree.h>
34 #include <securityd/nameconstraints.h>
35 #include <CoreFoundation/CFTimeZone.h>
36 #include <wctype.h>
37 #include <libDER/oidsPriv.h>
38 #include <CoreFoundation/CFNumber.h>
39 #include <Security/SecCertificateInternal.h>
40 #include <AssertMacros.h>
41 #include <utilities/debugging.h>
42 #include <security_asn1/SecAsn1Coder.h>
43 #include <security_asn1/ocspTemplates.h>
44 #include <security_asn1/oidsalg.h>
45 #include <security_asn1/oidsocsp.h>
46 #include <CommonCrypto/CommonDigest.h>
47 #include <Security/SecFramework.h>
48 #include <Security/SecPolicyInternal.h>
49 #include <Security/SecTrustPriv.h>
50 #include <Security/SecInternal.h>
51 #include <Security/SecKeyPriv.h>
52 #include <CFNetwork/CFHTTPMessage.h>
53 #include <CFNetwork/CFHTTPStream.h>
54 #include <SystemConfiguration/SCDynamicStoreCopySpecific.h>
55 #include <asl.h>
56 #include <securityd/SecOCSPRequest.h>
57 #include <securityd/SecOCSPResponse.h>
58 #include <securityd/asynchttp.h>
59 #include <securityd/SecTrustServer.h>
60 #include <securityd/SecOCSPCache.h>
61 #include <utilities/array_size.h>
62 #include <utilities/SecCFWrappers.h>
63 #include <utilities/SecAppleAnchorPriv.h>
64 #include "OTATrustUtilities.h"
65
66 #define ocspdErrorLog(args...) asl_log(NULL, NULL, ASL_LEVEL_ERR, ## args)
67
68 /* Set this to 1 to dump the ocsp responses received in DER form in /tmp. */
69 #ifndef DUMP_OCSPRESPONSES
70 #define DUMP_OCSPRESPONSES 0
71 #endif
72
73 #if DUMP_OCSPRESPONSES
74
75 #include <unistd.h>
76 #include <fcntl.h>
77
78 static void secdumpdata(CFDataRef data, const char *name) {
79 int fd = open(name, O_CREAT | O_WRONLY | O_TRUNC, 0666);
80 write(fd, CFDataGetBytePtr(data), CFDataGetLength(data));
81 close(fd);
82 }
83
84 #endif
85
86
87 /********************************************************
88 ****************** SecPolicy object ********************
89 ********************************************************/
90
91 static CFMutableDictionaryRef gSecPolicyLeafCallbacks = NULL;
92 static CFMutableDictionaryRef gSecPolicyPathCallbacks = NULL;
93
94 static CFArrayRef SecPolicyAnchorDigestsForEVPolicy(const DERItem *policyOID)
95 {
96 CFArrayRef result = NULL;
97 SecOTAPKIRef otapkiRef = SecOTAPKICopyCurrentOTAPKIRef();
98 if (NULL == otapkiRef)
99 {
100 return result;
101 }
102
103 CFDictionaryRef evToPolicyAnchorDigest = SecOTAPKICopyEVPolicyToAnchorMapping(otapkiRef);
104 CFRelease(otapkiRef);
105
106 if (NULL == evToPolicyAnchorDigest)
107 {
108 return result;
109 }
110
111 CFArrayRef roots = NULL;
112 CFStringRef oid = SecDERItemCopyOIDDecimalRepresentation(kCFAllocatorDefault, policyOID);
113 if (oid && evToPolicyAnchorDigest)
114 {
115 result = (CFArrayRef)CFDictionaryGetValue(evToPolicyAnchorDigest, oid);
116 if (roots && CFGetTypeID(result) != CFArrayGetTypeID())
117 {
118 ocspdErrorLog("EVRoot.plist has non array value");
119 result = NULL;
120 }
121 CFRelease(oid);
122 }
123 CFReleaseSafe(evToPolicyAnchorDigest);
124 return result;
125 }
126
127
128 static bool SecPolicyIsEVPolicy(const DERItem *policyOID) {
129 return SecPolicyAnchorDigestsForEVPolicy(policyOID);
130 }
131
132 static bool SecPolicyRootCACertificateIsEV(SecCertificateRef certificate,
133 policy_set_t valid_policies) {
134 /* Ensure that this certificate is a valid anchor for one of the
135 certificate policy oids specified in the leaf. */
136 CFDataRef digest = SecCertificateGetSHA1Digest(certificate);
137 policy_set_t ix;
138 bool good_ev_anchor = false;
139 for (ix = valid_policies; ix; ix = ix->oid_next) {
140 CFArrayRef digests = SecPolicyAnchorDigestsForEVPolicy(&ix->oid);
141 if (digests && CFArrayContainsValue(digests,
142 CFRangeMake(0, CFArrayGetCount(digests)), digest)) {
143 secdebug("ev", "found anchor for policy oid");
144 good_ev_anchor = true;
145 break;
146 }
147 }
148 require_quiet(good_ev_anchor, notEV);
149
150 CFAbsoluteTime october2006 = 178761600;
151 if (SecCertificateVersion(certificate) >= 3
152 && SecCertificateNotValidBefore(certificate) >= october2006) {
153 const SecCEBasicConstraints *bc = SecCertificateGetBasicConstraints(certificate);
154 require_quiet(bc && bc->isCA == true, notEV);
155 SecKeyUsage ku = SecCertificateGetKeyUsage(certificate);
156 require_quiet((ku & (kSecKeyUsageKeyCertSign | kSecKeyUsageCRLSign))
157 == (kSecKeyUsageKeyCertSign | kSecKeyUsageCRLSign), notEV);
158 }
159
160 CFAbsoluteTime jan2011 = 315532800;
161 if (SecCertificateNotValidBefore(certificate) < jan2011) {
162 /* At least MD5, SHA-1 with RSA 2048 or ECC NIST P-256. */
163 } else {
164 /* At least SHA-1, SHA-256, SHA-384 or SHA-512 with RSA 2048 or
165 ECC NIST P-256. */
166 }
167
168 return true;
169 notEV:
170 return false;
171 }
172
173 static bool SecPolicySubordinateCACertificateCouldBeEV(SecCertificateRef certificate) {
174 const SecCECertificatePolicies *cp;
175 cp = SecCertificateGetCertificatePolicies(certificate);
176 require_quiet(cp && cp->numPolicies > 0, notEV);
177 /* SecCertificateGetCRLDistributionPoints() is a noop right now */
178 #if 0
179 CFArrayRef cdp = SecCertificateGetCRLDistributionPoints(certificate);
180 require_quiet(cdp && CFArrayGetCount(cdp) > 0, notEV);
181 #endif
182 const SecCEBasicConstraints *bc = SecCertificateGetBasicConstraints(certificate);
183 require_quiet(bc && bc->isCA == true, notEV);
184 SecKeyUsage ku = SecCertificateGetKeyUsage(certificate);
185 require_quiet((ku & (kSecKeyUsageKeyCertSign | kSecKeyUsageCRLSign))
186 == (kSecKeyUsageKeyCertSign | kSecKeyUsageCRLSign), notEV);
187 CFAbsoluteTime jan2011 = 315532800;
188 if (SecCertificateNotValidBefore(certificate) < jan2011) {
189 /* At least SHA-1 with RSA 1024 or ECC NIST P-256. */
190 } else {
191 /* At least SHA-1, SHA-256, SHA-284 or SHA-512 with RSA 2028 or
192 ECC NIST P-256. */
193 }
194
195 return true;
196 notEV:
197 return false;
198 }
199
200 bool SecPolicySubscriberCertificateCouldBeEV(SecCertificateRef certificate) {
201 /* 3. Subscriber Certificate. */
202
203 /* (a) certificate Policies */
204 const SecCECertificatePolicies *cp;
205 cp = SecCertificateGetCertificatePolicies(certificate);
206 require_quiet(cp && cp->numPolicies > 0, notEV);
207 /* Now find at least one policy in here that has a qualifierID of id-qt 2
208 and a policyQualifier that is a URI to the CPS and an EV policy OID. */
209 uint32_t ix = 0;
210 bool found_ev_anchor_for_leaf_policy = false;
211 for (ix = 0; ix < cp->numPolicies; ++ix) {
212 if (SecPolicyIsEVPolicy(&cp->policies[ix].policyIdentifier)) {
213 found_ev_anchor_for_leaf_policy = true;
214 }
215 }
216 require_quiet(found_ev_anchor_for_leaf_policy, notEV);
217
218 /* SecCertificateGetCRLDistributionPoints() is a noop right now */
219 #if 0
220 /* (b) cRLDistributionPoint
221 (c) authorityInformationAccess */
222 CFArrayRef cdp = SecCertificateGetCRLDistributionPoints(certificate);
223 if (cdp) {
224 require_quiet(CFArrayGetCount(cdp) > 0, notEV);
225 } else {
226 CFArrayRef or = SecCertificateGetOCSPResponders(certificate);
227 require_quiet(or && CFArrayGetCount(or) > 0, notEV);
228 //CFArrayRef ci = SecCertificateGetCAIssuers(certificate);
229 }
230 #endif
231
232 /* (d) basicConstraints
233 If present, the cA field MUST be set false. */
234 const SecCEBasicConstraints *bc = SecCertificateGetBasicConstraints(certificate);
235 if (bc) {
236 require_quiet(bc->isCA == false, notEV);
237 }
238
239 /* (e) keyUsage. */
240 SecKeyUsage ku = SecCertificateGetKeyUsage(certificate);
241 if (ku) {
242 require_quiet((ku & (kSecKeyUsageKeyCertSign | kSecKeyUsageCRLSign)) == 0, notEV);
243 }
244
245 #if 0
246 /* The EV Cert Spec errata specifies this, though this is a check for SSL
247 not specifically EV. */
248
249 /* (e) extKeyUsage
250
251 Either the value id-kp-serverAuth [RFC5280] or id-kp-clientAuth [RFC5280] or both values MUST be present. Other values SHOULD NOT be present. */
252 SecCertificateCopyExtendedKeyUsage(certificate);
253 #endif
254
255 CFAbsoluteTime jan2011 = 315532800;
256 if (SecCertificateNotValidAfter(certificate) < jan2011) {
257 /* At least SHA-1 with RSA 1024 or ECC NIST P-256. */
258 } else {
259 /* At least SHA-1, SHA-256, SHA-284 or SHA-512 with RSA 2028 or
260 ECC NIST P-256. */
261 }
262
263 return true;
264 notEV:
265 return false;
266 }
267
268 /********************************************************
269 **************** SecPolicy Callbacks *******************
270 ********************************************************/
271 static void SecPolicyCheckCriticalExtensions(SecPVCRef pvc,
272 CFStringRef key) {
273 }
274
275 static void SecPolicyCheckIdLinkage(SecPVCRef pvc,
276 CFStringRef key) {
277 CFIndex ix, count = SecPVCGetCertificateCount(pvc);
278 CFDataRef parentSubjectKeyID = NULL;
279 for (ix = count - 1; ix >= 0; --ix) {
280 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix);
281 /* If the previous certificate in the chain had a SubjectKeyID,
282 make sure it matches the current certificates AuthorityKeyID. */
283 if (parentSubjectKeyID) {
284 /* @@@ According to RFC 2459 neither AuthorityKeyID nor
285 SubjectKeyID can be critical. Currenty we don't check
286 for this. */
287 CFDataRef authorityKeyID = SecCertificateGetAuthorityKeyID(cert);
288 if (authorityKeyID) {
289 if (!CFEqual(parentSubjectKeyID, authorityKeyID)) {
290 /* AuthorityKeyID doesn't match issuers SubjectKeyID. */
291 if (!SecPVCSetResult(pvc, key, ix, kCFBooleanFalse))
292 return;
293 }
294 }
295 }
296
297 parentSubjectKeyID = SecCertificateGetSubjectKeyID(cert);
298 }
299 }
300
301 static bool keyusage_allows(SecKeyUsage keyUsage, CFTypeRef xku) {
302 if (!xku || CFGetTypeID(xku) != CFNumberGetTypeID())
303 return false;
304
305 SInt32 dku;
306 CFNumberGetValue((CFNumberRef)xku, kCFNumberSInt32Type, &dku);
307 SecKeyUsage ku = (SecKeyUsage)dku;
308 return (keyUsage & ku) == ku;
309 }
310
311 static void SecPolicyCheckKeyUsage(SecPVCRef pvc,
312 CFStringRef key) {
313 SecCertificateRef leaf = SecPVCGetCertificateAtIndex(pvc, 0);
314 SecKeyUsage keyUsage = SecCertificateGetKeyUsage(leaf);
315 bool match = false;
316 SecPolicyRef policy = SecPVCGetPolicy(pvc);
317 CFTypeRef xku = CFDictionaryGetValue(policy->_options, key);
318 if (isArray(xku)) {
319 CFIndex ix, count = CFArrayGetCount(xku);
320 for (ix = 0; ix < count; ++ix) {
321 CFTypeRef ku = CFArrayGetValueAtIndex(xku, ix);
322 if (keyusage_allows(keyUsage, ku)) {
323 match = true;
324 break;
325 }
326 }
327 } else {
328 match = keyusage_allows(keyUsage, xku);
329 }
330 if (!match) {
331 SecPVCSetResult(pvc, key, 0, kCFBooleanFalse);
332 }
333 }
334
335 static bool extendedkeyusage_allows(CFArrayRef extendedKeyUsage,
336 CFTypeRef xeku) {
337 if (!xeku || CFGetTypeID(xeku) != CFDataGetTypeID())
338 return false;
339 if (extendedKeyUsage) {
340 CFRange all = { 0, CFArrayGetCount(extendedKeyUsage) };
341 return CFArrayContainsValue(extendedKeyUsage, all, xeku);
342 } else {
343 /* Certificate has no extended key usage, only a match if the policy
344 contains a 0 length CFDataRef. */
345 return CFDataGetLength((CFDataRef)xeku) == 0;
346 }
347 }
348
349 /* AUDIT[securityd](done):
350 policy->_options is a caller provided dictionary, only its cf type has
351 been checked.
352 */
353 static void SecPolicyCheckExtendedKeyUsage(SecPVCRef pvc, CFStringRef key) {
354 SecCertificateRef leaf = SecPVCGetCertificateAtIndex(pvc, 0);
355 CFArrayRef leafExtendedKeyUsage = SecCertificateCopyExtendedKeyUsage(leaf);
356 bool match = false;
357 SecPolicyRef policy = SecPVCGetPolicy(pvc);
358 CFTypeRef xeku = CFDictionaryGetValue(policy->_options, key);
359 if (isArray(xeku)) {
360 CFIndex ix, count = CFArrayGetCount(xeku);
361 for (ix = 0; ix < count; ix++) {
362 CFTypeRef eku = CFArrayGetValueAtIndex(xeku, ix);
363 if (extendedkeyusage_allows(leafExtendedKeyUsage, eku)) {
364 match = true;
365 break;
366 }
367 }
368 } else {
369 match = extendedkeyusage_allows(leafExtendedKeyUsage, xeku);
370 }
371 CFReleaseSafe(leafExtendedKeyUsage);
372 if (!match) {
373 SecPVCSetResult(pvc, key, 0, kCFBooleanFalse);
374 }
375 }
376
377 #if 0
378 static void SecPolicyCheckBasicContraintsCommon(SecPVCRef pvc,
379 CFStringRef key, bool strict) {
380 CFIndex ix, count = SecPVCGetCertificateCount(pvc);
381 for (ix = 0; ix < count; ++ix) {
382 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix);
383 const SecCEBasicConstraints *bc =
384 SecCertificateGetBasicConstraints(cert);
385 if (bc) {
386 if (strict) {
387 if (ix == 0) {
388 /* Leaf certificate has basic constraints extension. */
389 if (!SecPVCSetResult(pvc, key, ix, kCFBooleanFalse))
390 return;
391 } else if (!bc->critical) {
392 /* Basic constraints extension is not marked critical. */
393 if (!SecPVCSetResult(pvc, key, ix, kCFBooleanFalse))
394 return;
395 }
396 }
397
398 if (ix > 0 || count == 1) {
399 if (!bc->isCA) {
400 /* Non leaf certificate marked as isCA false. */
401 if (!SecPVCSetResult(pvc, key, ix, kCFBooleanFalse))
402 return;
403 }
404
405 if (bc->pathLenConstraintPresent) {
406 if (bc->pathLenConstraint < (uint32_t)(ix - 1)) {
407 #if 0
408 /* @@@ If a self signed certificate is issued by
409 another cert that is trusted, then we are supposed
410 to treat the self signed cert itself as the anchor
411 for path length purposes. */
412 CFIndex ssix = SecCertificatePathSelfSignedIndex(path);
413 if (ssix >= 0 && ix >= ssix) {
414 /* It's ok if the pathLenConstraint isn't met for
415 certificates signing a self signed cert in the
416 chain. */
417 } else
418 #endif
419 {
420 /* Path Length Constraint Exceeded. */
421 if (!SecPVCSetResult(pvc, key, ix,
422 kCFBooleanFalse))
423 return;
424 }
425 }
426 }
427 }
428 } else if (strict && ix > 0) {
429 /* In strict mode all CA certificates *MUST* have a critical
430 basic constraints extension and the leaf certificate
431 *MUST NOT* have a basic constraints extension. */
432 /* CA certificate is missing basicConstraints extension. */
433 if (!SecPVCSetResult(pvc, key, ix, kCFBooleanFalse))
434 return;
435 }
436 }
437 }
438 #endif
439
440 static void SecPolicyCheckBasicContraints(SecPVCRef pvc,
441 CFStringRef key) {
442 //SecPolicyCheckBasicContraintsCommon(pvc, key, false);
443 }
444
445 static void SecPolicyCheckNonEmptySubject(SecPVCRef pvc,
446 CFStringRef key) {
447 CFIndex ix, count = SecPVCGetCertificateCount(pvc);
448 for (ix = 0; ix < count; ++ix) {
449 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix);
450 /* If the certificate has a subject, or
451 if it doesn't, and it's the leaf and not self signed,
452 and also has a critical subjectAltName extension it's valid. */
453 if (!SecCertificateHasSubject(cert)) {
454 if (ix == 0 && count > 1) {
455 if (!SecCertificateHasCriticalSubjectAltName(cert)) {
456 /* Leaf certificate with empty subject does not have
457 a critical subject alt name extension. */
458 if (!SecPVCSetResult(pvc, key, ix, kCFBooleanFalse))
459 return;
460 }
461 } else {
462 /* CA certificate has empty subject. */
463 if (!SecPVCSetResult(pvc, key, ix, kCFBooleanFalse))
464 return;
465 }
466 }
467 }
468 }
469
470 static void SecPolicyCheckQualifiedCertStatements(SecPVCRef pvc,
471 CFStringRef key) {
472 }
473
474 /* Compare hostname suffix to domain name.
475 This function does not process wildcards, and allows hostname to match
476 any subdomain level of the provided domain.
477
478 To match, the last domain length chars of hostname must equal domain,
479 and the character immediately preceding domain in hostname (if any)
480 must be a dot. This means that domain 'bar.com' will match hostname
481 values 'host.bar.com' or 'host.sub.bar.com', but not 'host.foobar.com'.
482
483 Characters in each string are converted to lowercase for the comparison.
484 Trailing '.' characters in both names will be ignored.
485
486 Returns true on match, else false.
487 */
488 static bool SecDomainSuffixMatch(CFStringRef hostname, CFStringRef domain) {
489 CFStringInlineBuffer hbuf, dbuf;
490 UniChar hch, dch;
491 CFIndex hix, dix,
492 hlength = CFStringGetLength(hostname),
493 dlength = CFStringGetLength(domain);
494 CFRange hrange = { 0, hlength }, drange = { 0, dlength };
495 CFStringInitInlineBuffer(hostname, &hbuf, hrange);
496 CFStringInitInlineBuffer(domain, &dbuf, drange);
497
498 if((hlength == 0) || (dlength == 0)) {
499 /* trivial case with at least one empty name */
500 return (hlength == dlength) ? true : false;
501 }
502
503 /* trim off trailing dots */
504 hch = CFStringGetCharacterFromInlineBuffer(&hbuf, hlength-1);
505 dch = CFStringGetCharacterFromInlineBuffer(&dbuf, dlength-1);
506 if(hch == '.') {
507 hrange.length = --hlength;
508 }
509 if(dch == '.') {
510 drange.length = --dlength;
511 }
512
513 /* trim off leading dot in suffix, if present */
514 dch = CFStringGetCharacterFromInlineBuffer(&dbuf, 0);
515 if((dlength > 0) && (dch == '.')) {
516 drange.location++;
517 drange.length = --dlength;
518 }
519
520 if(hlength < dlength) {
521 return false;
522 }
523
524 /* perform case-insensitive comparison of domain suffix */
525 for (hix = (hlength-dlength),
526 dix = drange.location; dix < drange.length; dix++) {
527 hch = CFStringGetCharacterFromInlineBuffer(&hbuf, hix);
528 dch = CFStringGetCharacterFromInlineBuffer(&dbuf, dix);
529 if (towlower(hch) != towlower(dch)) {
530 return false;
531 }
532 }
533
534 /* require a dot prior to domain suffix, unless hostname == domain */
535 if(hlength > dlength) {
536 hch = CFStringGetCharacterFromInlineBuffer(&hbuf, (hlength-(dlength+1)));
537 if(hch != '.') {
538 return false;
539 }
540 }
541
542 return true;
543 }
544
545 /* Compare hostname, to a server name obtained from the server's cert
546 Obtained from the SubjectAltName or the CommonName entry in the Subject.
547 Limited wildcard checking is performed here as outlined in
548
549 RFC 2818 Section 3.1. Server Identity
550
551 [...] Names may contain the wildcard
552 character * which is considered to match any single domain name
553 component or component fragment. E.g., *.a.com matches foo.a.com but
554 not bar.foo.a.com. f*.com matches foo.com but not bar.com.
555 [...]
556
557 Trailing '.' characters in the hostname will be ignored.
558
559 Returns true on match, else false.
560
561 RFC6125:
562 */
563 bool SecDNSMatch(CFStringRef hostname, CFStringRef servername) {
564 CFStringInlineBuffer hbuf, sbuf;
565 CFIndex hix, six, tix,
566 hlength = CFStringGetLength(hostname),
567 slength = CFStringGetLength(servername);
568 CFRange hrange = { 0, hlength }, srange = { 0, slength };
569 CFStringInitInlineBuffer(hostname, &hbuf, hrange);
570 CFStringInitInlineBuffer(servername, &sbuf, srange);
571 bool prevLabel=false;
572
573 for (hix = six = 0; six < slength; ++six) {
574 UniChar tch, hch, sch = CFStringGetCharacterFromInlineBuffer(&sbuf, six);
575 if (sch == '*') {
576 if (prevLabel) {
577 /* RFC6125: No wildcard after a Previous Label */
578 /* INVALID: Means we have something like foo.*.<public_suffix> */
579 return false;
580 }
581
582 if (six + 1 >= slength) {
583 /* Trailing '*' in servername, match until end of hostname or
584 trailing '.'. */
585 do {
586 if (hix >= hlength) {
587 /* If we reach the end of the hostname we have a
588 match. */
589 return true;
590 }
591 hch = CFStringGetCharacterFromInlineBuffer(&hbuf, hix++);
592 } while (hch != '.');
593 /* We reached the end of servername and found a '.' in
594 hostname. Return true if hostname has a single
595 trailing '.' return false if there is anything after it. */
596 return hix == hlength;
597 }
598
599 /* Grab the character after the '*'. */
600 sch = CFStringGetCharacterFromInlineBuffer(&sbuf, ++six);
601 if (sch != '.') {
602 /* We have something of the form '*foo.com'. Or '**.com'
603 We don't deal with that yet, since it might require
604 backtracking. Also RFC 2818 doesn't seem to require it. */
605 return false;
606 }
607
608 /* We're looking at the '.' after the '*' in something of the
609 form 'foo*.com' or '*.com'. Match until next '.' in hostname. */
610 if (prevLabel==false) { /* RFC6125: Check if *.<tld> */
611 tix=six+1;
612 do { /* Loop to end of servername */
613 if (tix > slength)
614 return false; /* Means we have something like *.com */
615 tch = CFStringGetCharacterFromInlineBuffer(&sbuf, tix++);
616 } while (tch != '.');
617 if (tix > slength)
618 return false; /* In case we have *.com. */
619 }
620
621 do {
622 /* Since we're not at the end of servername yet (that case
623 was handled above), running out of chars in hostname
624 means we don't have a match. */
625 if (hix >= hlength)
626 return false;
627 hch = CFStringGetCharacterFromInlineBuffer(&hbuf, hix++);
628 } while (hch != '.');
629 } else {
630 /* We're looking at a non wildcard character in the servername.
631 If we reached the end of hostname, it's not a match. */
632 if (hix >= hlength)
633 return false;
634
635 /* Otherwise make sure the hostname matches the character in the
636 servername, case insensitively. */
637 hch = CFStringGetCharacterFromInlineBuffer(&hbuf, hix++);
638 if (towlower(hch) != towlower(sch))
639 return false;
640 if (sch == '.')
641 prevLabel=true; /* Set if a confirmed previous component */
642 }
643 }
644
645 if (hix < hlength) {
646 /* We reached the end of servername but we have one or more characters
647 left to compare against in the hostname. */
648 if (hix + 1 == hlength &&
649 CFStringGetCharacterFromInlineBuffer(&hbuf, hix) == '.') {
650 /* Hostname has a single trailing '.', we're ok with that. */
651 return true;
652 }
653 /* Anything else is not a match. */
654 return false;
655 }
656
657 return true;
658 }
659
660 #define kSecPolicySHA1Size 20
661 static const UInt8 kAppleCorpCASHA1[kSecPolicySHA1Size] = {
662 0xA1, 0x71, 0xDC, 0xDE, 0xE0, 0x8B, 0x1B, 0xAE, 0x30, 0xA1,
663 0xAE, 0x6C, 0xC6, 0xD4, 0x03, 0x3B, 0xFD, 0xEF, 0x91, 0xCE
664 };
665
666 /* Check whether hostname is in a particular set of allowed domains.
667 Returns true if OK, false if not allowed.
668 */
669 static bool SecPolicyCheckDomain(SecPVCRef pvc, CFStringRef hostname)
670 {
671 CFIndex count = SecPVCGetCertificateCount(pvc);
672 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, count - 1);
673 CFDataRef anchorSHA1 = SecCertificateGetSHA1Digest(cert);
674
675 /* is this chain anchored by kAppleCorpCASHA1? */
676 CFDataRef corpSHA1 = CFDataCreateWithBytesNoCopy(NULL,
677 kAppleCorpCASHA1, kSecPolicySHA1Size, kCFAllocatorNull);
678 bool isCorpSHA1 = (corpSHA1 && CFEqual(anchorSHA1, corpSHA1));
679 CFReleaseSafe(corpSHA1);
680 if (isCorpSHA1) {
681 /* limit hostname to specified domains */
682 const CFStringRef dnlist[] = {
683 CFSTR("apple.com"),
684 CFSTR("icloud.com"),
685 };
686 unsigned int idx, dncount=2;
687 for (idx = 0; idx < dncount; idx++) {
688 if (SecDomainSuffixMatch(hostname, dnlist[idx])) {
689 return true;
690 }
691 }
692 return false;
693 }
694 /* %%% other CA pinning checks TBA */
695
696 return true;
697 }
698
699 /* AUDIT[securityd](done):
700 policy->_options is a caller provided dictionary, only its cf type has
701 been checked.
702 */
703 static void SecPolicyCheckSSLHostname(SecPVCRef pvc,
704 CFStringRef key) {
705 /* @@@ Consider what to do if the caller passes in no hostname. Should
706 we then still fail if the leaf has no dnsNames or IPAddresses at all? */
707 SecPolicyRef policy = SecPVCGetPolicy(pvc);
708 CFStringRef hostName = (CFStringRef)
709 CFDictionaryGetValue(policy->_options, key);
710 if (!isString(hostName)) {
711 /* @@@ We can't return an error here and making the evaluation fail
712 won't help much either. */
713 return;
714 }
715
716 SecCertificateRef leaf = SecPVCGetCertificateAtIndex(pvc, 0);
717 bool dnsMatch = false;
718 CFArrayRef dnsNames = SecCertificateCopyDNSNames(leaf);
719 if (dnsNames) {
720 CFIndex ix, count = CFArrayGetCount(dnsNames);
721 for (ix = 0; ix < count; ++ix) {
722 CFStringRef dns = (CFStringRef)CFArrayGetValueAtIndex(dnsNames, ix);
723 if (SecDNSMatch(hostName, dns)) {
724 dnsMatch = true;
725 break;
726 }
727 }
728 CFRelease(dnsNames);
729 }
730
731 if (!dnsMatch) {
732 /* Maybe hostname is an IPv4 or IPv6 address, let's compare against
733 the values returned by SecCertificateCopyIPAddresses() instead. */
734 CFArrayRef ipAddresses = SecCertificateCopyIPAddresses(leaf);
735 if (ipAddresses) {
736 CFIndex ix, count = CFArrayGetCount(ipAddresses);
737 for (ix = 0; ix < count; ++ix) {
738 CFStringRef ipAddress = (CFStringRef)CFArrayGetValueAtIndex(ipAddresses, ix);
739 if (!CFStringCompare(hostName, ipAddress, kCFCompareCaseInsensitive)) {
740 dnsMatch = true;
741 break;
742 }
743 }
744 CFRelease(ipAddresses);
745 }
746 }
747
748 if (!dnsMatch) {
749 /* Hostname mismatch or no hostnames found in certificate. */
750 SecPVCSetResult(pvc, key, 0, kCFBooleanFalse);
751 }
752 else if (!SecPolicyCheckDomain(pvc, hostName)) {
753 /* Hostname match, but domain not allowed for this CA */
754 SecPVCSetResult(pvc, key, 0, kCFBooleanFalse);
755 }
756
757 if ((dnsMatch || pvc->details)
758 && SecPolicySubscriberCertificateCouldBeEV(leaf)) {
759 secdebug("policy", "enabling optionally_ev");
760 pvc->optionally_ev = true;
761 /* optionally_ev => check_revocation, so we don't enable revocation
762 checking here, since we don't want it on for non EV ssl certs. */
763 #if 0
764 /* Check revocation status if the certificate asks for it (and we
765 support it) currently we only support ocsp. */
766 CFArrayRef ocspResponders = SecCertificateGetOCSPResponders(leaf);
767 if (ocspResponders) {
768 SecPVCSetCheckRevocation(pvc);
769 }
770 #endif
771 }
772 }
773
774 /* AUDIT[securityd](done):
775 policy->_options is a caller provided dictionary, only its cf type has
776 been checked.
777 */
778 static void SecPolicyCheckEmail(SecPVCRef pvc, CFStringRef key) {
779 SecPolicyRef policy = SecPVCGetPolicy(pvc);
780 CFStringRef email = (CFStringRef)CFDictionaryGetValue(policy->_options, key);
781 bool match = false;
782 if (!isString(email)) {
783 /* We can't return an error here and making the evaluation fail
784 won't help much either. */
785 return;
786 }
787
788 SecCertificateRef leaf = SecPVCGetCertificateAtIndex(pvc, 0);
789 CFArrayRef addrs = SecCertificateCopyRFC822Names(leaf);
790 if (addrs) {
791 CFIndex ix, count = CFArrayGetCount(addrs);
792 for (ix = 0; ix < count; ++ix) {
793 CFStringRef addr = (CFStringRef)CFArrayGetValueAtIndex(addrs, ix);
794 if (!CFStringCompare(email, addr, kCFCompareCaseInsensitive)) {
795 match = true;
796 break;
797 }
798 }
799 CFRelease(addrs);
800 }
801
802 if (!match) {
803 /* Hostname mismatch or no hostnames found in certificate. */
804 SecPVCSetResult(pvc, key, 0, kCFBooleanFalse);
805 }
806 }
807
808 static void SecPolicyCheckValidIntermediates(SecPVCRef pvc,
809 CFStringRef key) {
810 CFIndex ix, count = SecPVCGetCertificateCount(pvc);
811 CFAbsoluteTime verifyTime = SecPVCGetVerifyTime(pvc);
812 for (ix = 1; ix < count - 1; ++ix) {
813 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix);
814 if (!SecCertificateIsValid(cert, verifyTime)) {
815 /* Intermediate certificate has expired. */
816 if (!SecPVCSetResult(pvc, key, ix, kCFBooleanFalse))
817 return;
818 }
819 }
820 }
821
822 static void SecPolicyCheckValidLeaf(SecPVCRef pvc,
823 CFStringRef key) {
824 CFAbsoluteTime verifyTime = SecPVCGetVerifyTime(pvc);
825 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, 0);
826 if (!SecCertificateIsValid(cert, verifyTime)) {
827 /* Leaf certificate has expired. */
828 if (!SecPVCSetResult(pvc, key, 0, kCFBooleanFalse))
829 return;
830 }
831 }
832
833 static void SecPolicyCheckValidRoot(SecPVCRef pvc,
834 CFStringRef key) {
835 CFIndex ix, count = SecPVCGetCertificateCount(pvc);
836 CFAbsoluteTime verifyTime = SecPVCGetVerifyTime(pvc);
837 ix = count - 1;
838 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix);
839 if (!SecCertificateIsValid(cert, verifyTime)) {
840 /* Root certificate has expired. */
841 if (!SecPVCSetResult(pvc, key, ix, kCFBooleanFalse))
842 return;
843 }
844 }
845
846 /* AUDIT[securityd](done):
847 policy->_options is a caller provided dictionary, only its cf type has
848 been checked.
849 */
850 static void SecPolicyCheckIssuerCommonName(SecPVCRef pvc,
851 CFStringRef key) {
852 CFIndex count = SecPVCGetCertificateCount(pvc);
853 if (count < 2) {
854 /* Can't check intermediates common name if there is no intermediate. */
855 SecPVCSetResult(pvc, key, 0, kCFBooleanFalse);
856 return;
857 }
858
859 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, 1);
860 SecPolicyRef policy = SecPVCGetPolicy(pvc);
861 CFStringRef commonName =
862 (CFStringRef)CFDictionaryGetValue(policy->_options, key);
863 if (!isString(commonName)) {
864 /* @@@ We can't return an error here and making the evaluation fail
865 won't help much either. */
866 return;
867 }
868 CFArrayRef commonNames = SecCertificateCopyCommonNames(cert);
869 if (!commonNames || CFArrayGetCount(commonNames) != 1 ||
870 !CFEqual(commonName, CFArrayGetValueAtIndex(commonNames, 0))) {
871 /* Common Name mismatch. */
872 SecPVCSetResult(pvc, key, 0, kCFBooleanFalse);
873 }
874 CFReleaseSafe(commonNames);
875 }
876
877 /* AUDIT[securityd](done):
878 policy->_options is a caller provided dictionary, only its cf type has
879 been checked.
880 */
881 static void SecPolicyCheckSubjectCommonName(SecPVCRef pvc,
882 CFStringRef key) {
883 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, 0);
884 SecPolicyRef policy = SecPVCGetPolicy(pvc);
885 CFStringRef common_name = (CFStringRef)CFDictionaryGetValue(policy->_options,
886 key);
887 if (!isString(common_name)) {
888 /* @@@ We can't return an error here and making the evaluation fail
889 won't help much either. */
890 return;
891 }
892 CFArrayRef commonNames = SecCertificateCopyCommonNames(cert);
893 if (!commonNames || CFArrayGetCount(commonNames) != 1 ||
894 !CFEqual(common_name, CFArrayGetValueAtIndex(commonNames, 0))) {
895 /* Common Name mismatch. */
896 SecPVCSetResult(pvc, key, 0, kCFBooleanFalse);
897 }
898 CFReleaseSafe(commonNames);
899 }
900
901 /* AUDIT[securityd](done):
902 policy->_options is a caller provided dictionary, only its cf type has
903 been checked.
904 */
905 static void SecPolicyCheckSubjectCommonNamePrefix(SecPVCRef pvc,
906 CFStringRef key) {
907 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, 0);
908 SecPolicyRef policy = SecPVCGetPolicy(pvc);
909 CFStringRef prefix = (CFStringRef)CFDictionaryGetValue(policy->_options,
910 key);
911 if (!isString(prefix)) {
912 /* @@@ We can't return an error here and making the evaluation fail
913 won't help much either. */
914 return;
915 }
916 CFArrayRef commonNames = SecCertificateCopyCommonNames(cert);
917 if (!commonNames || CFArrayGetCount(commonNames) != 1 ||
918 !CFStringHasPrefix(CFArrayGetValueAtIndex(commonNames, 0), prefix)) {
919 /* Common Name prefix mismatch. */
920 SecPVCSetResult(pvc, key, 0, kCFBooleanFalse);
921 }
922 CFReleaseSafe(commonNames);
923 }
924
925 /* AUDIT[securityd](done):
926 policy->_options is a caller provided dictionary, only its cf type has
927 been checked.
928 */
929 static void SecPolicyCheckSubjectCommonNameTEST(SecPVCRef pvc,
930 CFStringRef key) {
931 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, 0);
932 SecPolicyRef policy = SecPVCGetPolicy(pvc);
933 CFStringRef common_name = (CFStringRef)CFDictionaryGetValue(policy->_options,
934 key);
935 if (!isString(common_name)) {
936 /* @@@ We can't return an error here and making the evaluation fail
937 won't help much either. */
938 return;
939 }
940 CFArrayRef commonNames = SecCertificateCopyCommonNames(cert);
941 if (!commonNames || CFArrayGetCount(commonNames) != 1) {
942 CFStringRef cert_common_name = CFArrayGetValueAtIndex(commonNames, 0);
943 CFStringRef test_common_name = common_name ?
944 CFStringCreateWithFormat(kCFAllocatorDefault,
945 NULL, CFSTR("TEST %@ TEST"), common_name) :
946 NULL;
947 if (!CFEqual(common_name, cert_common_name) &&
948 (!test_common_name || !CFEqual(test_common_name, cert_common_name)))
949 /* Common Name mismatch. */
950 SecPVCSetResult(pvc, key, 0, kCFBooleanFalse);
951 CFReleaseSafe(test_common_name);
952 }
953 CFReleaseSafe(commonNames);
954 }
955
956 /* AUDIT[securityd](done):
957 policy->_options is a caller provided dictionary, only its cf type has
958 been checked.
959 */
960 static void SecPolicyCheckNotValidBefore(SecPVCRef pvc,
961 CFStringRef key) {
962 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, 0);
963 SecPolicyRef policy = SecPVCGetPolicy(pvc);
964 CFDateRef date = (CFDateRef)CFDictionaryGetValue(policy->_options, key);
965 if (!isDate(date)) {
966 /* @@@ We can't return an error here and making the evaluation fail
967 won't help much either. */
968 return;
969 }
970 CFAbsoluteTime at = CFDateGetAbsoluteTime(date);
971 if (SecCertificateNotValidBefore(cert) <= at) {
972 /* Leaf certificate has not valid before that is too old. */
973 if (!SecPVCSetResult(pvc, key, 0, kCFBooleanFalse))
974 return;
975 }
976 }
977
978 /* AUDIT[securityd](done):
979 policy->_options is a caller provided dictionary, only its cf type has
980 been checked.
981 */
982 static void SecPolicyCheckChainLength(SecPVCRef pvc,
983 CFStringRef key) {
984 CFIndex count = SecPVCGetCertificateCount(pvc);
985 SecPolicyRef policy = SecPVCGetPolicy(pvc);
986 CFNumberRef chainLength =
987 (CFNumberRef)CFDictionaryGetValue(policy->_options, key);
988 CFIndex value;
989 if (!chainLength || CFGetTypeID(chainLength) != CFNumberGetTypeID() ||
990 !CFNumberGetValue(chainLength, kCFNumberCFIndexType, &value)) {
991 /* @@@ We can't return an error here and making the evaluation fail
992 won't help much either. */
993 return;
994 }
995 if (value != count) {
996 /* Chain length doesn't match policy requirement. */
997 if (!SecPVCSetResult(pvc, key, 0, kCFBooleanFalse))
998 return;
999 }
1000 }
1001
1002 /* AUDIT[securityd](done):
1003 policy->_options is a caller provided dictionary, only its cf type has
1004 been checked.
1005 */
1006 static void SecPolicyCheckAnchorSHA1(SecPVCRef pvc,
1007 CFStringRef key) {
1008 CFIndex count = SecPVCGetCertificateCount(pvc);
1009 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, count - 1);
1010 SecPolicyRef policy = SecPVCGetPolicy(pvc);
1011 CFTypeRef value = CFDictionaryGetValue(policy->_options, key);
1012 CFDataRef anchorSHA1 = SecCertificateGetSHA1Digest(cert);
1013
1014 bool foundMatch = false;
1015
1016 if (isData(value))
1017 foundMatch = CFEqual(anchorSHA1, value);
1018 else if (isArray(value))
1019 foundMatch = CFArrayContainsValue((CFArrayRef) value, CFRangeMake(0, CFArrayGetCount((CFArrayRef) value)), anchorSHA1);
1020 else {
1021 /* @@@ We only support Data and Array but we can't return an error here so.
1022 we let the evaluation fail (not much help) and assert in debug. */
1023 assert(false);
1024 }
1025
1026 if (!foundMatch)
1027 if (!SecPVCSetResult(pvc, kSecPolicyCheckAnchorSHA1, 0, kCFBooleanFalse))
1028 return;
1029
1030 return;
1031 }
1032
1033 /*
1034 Check the SHA256 of SPKI of the first intermediate CA certificate in the path
1035 policy->_options is a caller provided dictionary, only its cf type has
1036 been checked.
1037 */
1038 static void SecPolicyCheckIntermediateSPKISHA256(SecPVCRef pvc,
1039 CFStringRef key) {
1040 SecPolicyRef policy = SecPVCGetPolicy(pvc);
1041 CFTypeRef value = CFDictionaryGetValue(policy->_options, key);
1042 SecCertificateRef cert = NULL;
1043 CFDataRef digest = NULL;
1044 bool foundMatch = false;
1045
1046 if (SecPVCGetCertificateCount(pvc) < 2) {
1047 SecPVCSetResult(pvc, kSecPolicyCheckIntermediateSPKISHA256, 0, kCFBooleanFalse);
1048 return;
1049 }
1050
1051 cert = SecPVCGetCertificateAtIndex(pvc, 1);
1052 digest = SecCertificateCopySubjectPublicKeyInfoSHA256Digest(cert);
1053
1054 if (isData(value))
1055 foundMatch = CFEqual(digest, value);
1056 else if (isArray(value))
1057 foundMatch = CFArrayContainsValue((CFArrayRef) value, CFRangeMake(0, CFArrayGetCount((CFArrayRef) value)), digest);
1058 else {
1059 /* @@@ We only support Data and Array but we can't return an error here so.
1060 we let the evaluation fail (not much help) and assert in debug. */
1061 assert(false);
1062 }
1063
1064 CFReleaseNull(digest);
1065
1066 if (!foundMatch) {
1067 SecPVCSetResult(pvc, kSecPolicyCheckIntermediateSPKISHA256, 0, kCFBooleanFalse);
1068 }
1069 }
1070
1071 /*
1072 policy->_options is a caller provided dictionary, only its cf type has
1073 been checked.
1074 */
1075 static void SecPolicyCheckAnchorApple(SecPVCRef pvc,
1076 CFStringRef key) {
1077 CFIndex count = SecPVCGetCertificateCount(pvc);
1078 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, count - 1);
1079 SecPolicyRef policy = SecPVCGetPolicy(pvc);
1080 CFTypeRef value = CFDictionaryGetValue(policy->_options, key);
1081 SecAppleTrustAnchorFlags flags = 0;
1082
1083 if (isDictionary(value)) {
1084 if (CFDictionaryGetValue(value, kSecPolicyAppleAnchorIncludeTestRoots))
1085 flags |= kSecAppleTrustAnchorFlagsIncludeTestAnchors;
1086 }
1087
1088 bool foundMatch = SecIsAppleTrustAnchor(cert, flags);
1089
1090 if (!foundMatch)
1091 if (!SecPVCSetResult(pvc, kSecPolicyCheckAnchorApple, 0, kCFBooleanFalse))
1092 return;
1093
1094 return;
1095 }
1096
1097
1098 /* AUDIT[securityd](done):
1099 policy->_options is a caller provided dictionary, only its cf type has
1100 been checked.
1101 */
1102 static void SecPolicyCheckSubjectOrganization(SecPVCRef pvc,
1103 CFStringRef key) {
1104 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, 0);
1105 SecPolicyRef policy = SecPVCGetPolicy(pvc);
1106 CFStringRef org = (CFStringRef)CFDictionaryGetValue(policy->_options,
1107 key);
1108 if (!isString(org)) {
1109 /* @@@ We can't return an error here and making the evaluation fail
1110 won't help much either. */
1111 return;
1112 }
1113 CFArrayRef organization = SecCertificateCopyOrganization(cert);
1114 if (!organization || CFArrayGetCount(organization) != 1 ||
1115 !CFEqual(org, CFArrayGetValueAtIndex(organization, 0))) {
1116 /* Leaf Subject Organization mismatch. */
1117 SecPVCSetResult(pvc, key, 0, kCFBooleanFalse);
1118 }
1119 CFReleaseSafe(organization);
1120 }
1121
1122 static void SecPolicyCheckSubjectOrganizationalUnit(SecPVCRef pvc,
1123 CFStringRef key) {
1124 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, 0);
1125 SecPolicyRef policy = SecPVCGetPolicy(pvc);
1126 CFStringRef orgUnit = (CFStringRef)CFDictionaryGetValue(policy->_options,
1127 key);
1128 if (!isString(orgUnit)) {
1129 /* @@@ We can't return an error here and making the evaluation fail
1130 won't help much either. */
1131 return;
1132 }
1133 CFArrayRef organizationalUnit = SecCertificateCopyOrganizationalUnit(cert);
1134 if (!organizationalUnit || CFArrayGetCount(organizationalUnit) != 1 ||
1135 !CFEqual(orgUnit, CFArrayGetValueAtIndex(organizationalUnit, 0))) {
1136 /* Leaf Subject Organizational Unit mismatch. */
1137 SecPVCSetResult(pvc, key, 0, kCFBooleanFalse);
1138 }
1139 CFReleaseSafe(organizationalUnit);
1140 }
1141
1142 /* AUDIT[securityd](done):
1143 policy->_options is a caller provided dictionary, only its cf type has
1144 been checked.
1145 */
1146 static void SecPolicyCheckEAPTrustedServerNames(SecPVCRef pvc,
1147 CFStringRef key) {
1148 SecPolicyRef policy = SecPVCGetPolicy(pvc);
1149 CFArrayRef trustedServerNames = (CFArrayRef)
1150 CFDictionaryGetValue(policy->_options, key);
1151 /* No names specified means we accept any name. */
1152 if (!trustedServerNames)
1153 return;
1154 if (!isArray(trustedServerNames)) {
1155 /* @@@ We can't return an error here and making the evaluation fail
1156 won't help much either. */
1157 return;
1158 }
1159
1160 CFIndex tsnCount = CFArrayGetCount(trustedServerNames);
1161 SecCertificateRef leaf = SecPVCGetCertificateAtIndex(pvc, 0);
1162 bool dnsMatch = false;
1163 CFArrayRef dnsNames = SecCertificateCopyDNSNames(leaf);
1164 if (dnsNames) {
1165 CFIndex ix, count = CFArrayGetCount(dnsNames);
1166 // @@@ This is O(N^2) unfortunately we can't do better easily unless
1167 // we don't do wildcard matching. */
1168 for (ix = 0; !dnsMatch && ix < count; ++ix) {
1169 CFStringRef dns = (CFStringRef)CFArrayGetValueAtIndex(dnsNames, ix);
1170 CFIndex tix;
1171 for (tix = 0; tix < tsnCount; ++tix) {
1172 CFStringRef serverName =
1173 (CFStringRef)CFArrayGetValueAtIndex(trustedServerNames, tix);
1174 if (!isString(serverName)) {
1175 /* @@@ We can't return an error here and making the
1176 evaluation fail won't help much either. */
1177 CFReleaseSafe(dnsNames);
1178 return;
1179 }
1180 /* we purposefully reverse the arguments here such that dns names
1181 from the cert are matched against a server name list, where
1182 the server names list can contain wildcards and the dns name
1183 cannot. References: http://support.microsoft.com/kb/941123
1184 It's easy to find occurrences where people tried to use
1185 wildcard certificates and were told that those don't work
1186 in this context. */
1187 if (SecDNSMatch(dns, serverName)) {
1188 dnsMatch = true;
1189 break;
1190 }
1191 }
1192 }
1193 CFRelease(dnsNames);
1194 }
1195
1196 if (!dnsMatch) {
1197 /* Hostname mismatch or no hostnames found in certificate. */
1198 SecPVCSetResult(pvc, key, 0, kCFBooleanFalse);
1199 }
1200 }
1201
1202 static const unsigned char UTN_USERFirst_Hardware_Serial[][16] = {
1203 { 0xd8, 0xf3, 0x5f, 0x4e, 0xb7, 0x87, 0x2b, 0x2d, 0xab, 0x06, 0x92, 0xe3, 0x15, 0x38, 0x2f, 0xb0 },
1204 { 0x92, 0x39, 0xd5, 0x34, 0x8f, 0x40, 0xd1, 0x69, 0x5a, 0x74, 0x54, 0x70, 0xe1, 0xf2, 0x3f, 0x43 },
1205 { 0xb0, 0xb7, 0x13, 0x3e, 0xd0, 0x96, 0xf9, 0xb5, 0x6f, 0xae, 0x91, 0xc8, 0x74, 0xbd, 0x3a, 0xc0 },
1206 { 0xe9, 0x02, 0x8b, 0x95, 0x78, 0xe4, 0x15, 0xdc, 0x1a, 0x71, 0x0a, 0x2b, 0x88, 0x15, 0x44, 0x47 },
1207 { 0x39, 0x2a, 0x43, 0x4f, 0x0e, 0x07, 0xdf, 0x1f, 0x8a, 0xa3, 0x05, 0xde, 0x34, 0xe0, 0xc2, 0x29 },
1208 { 0x3e, 0x75, 0xce, 0xd4, 0x6b, 0x69, 0x30, 0x21, 0x21, 0x88, 0x30, 0xae, 0x86, 0xa8, 0x2a, 0x71 },
1209 { 0xd7, 0x55, 0x8f, 0xda, 0xf5, 0xf1, 0x10, 0x5b, 0xb2, 0x13, 0x28, 0x2b, 0x70, 0x77, 0x29, 0xa3 },
1210 { 0x04, 0x7e, 0xcb, 0xe9, 0xfc, 0xa5, 0x5f, 0x7b, 0xd0, 0x9e, 0xae, 0x36, 0xe1, 0x0c, 0xae, 0x1e },
1211 { 0xf5, 0xc8, 0x6a, 0xf3, 0x61, 0x62, 0xf1, 0x3a, 0x64, 0xf5, 0x4f, 0x6d, 0xc9, 0x58, 0x7c, 0x06 } };
1212
1213 static const unsigned char UTN_USERFirst_Hardware_Normalized_Issuer[] = {
1214 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55,
1215 0x53, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x02,
1216 0x55, 0x54, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x07, 0x13,
1217 0x0e, 0x53, 0x41, 0x4c, 0x54, 0x20, 0x4c, 0x41, 0x4b, 0x45, 0x20, 0x43,
1218 0x49, 0x54, 0x59, 0x31, 0x1e, 0x30, 0x1c, 0x06, 0x03, 0x55, 0x04, 0x0a,
1219 0x13, 0x15, 0x54, 0x48, 0x45, 0x20, 0x55, 0x53, 0x45, 0x52, 0x54, 0x52,
1220 0x55, 0x53, 0x54, 0x20, 0x4e, 0x45, 0x54, 0x57, 0x4f, 0x52, 0x4b, 0x31,
1221 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x18, 0x48, 0x54,
1222 0x54, 0x50, 0x3a, 0x2f, 0x2f, 0x57, 0x57, 0x57, 0x2e, 0x55, 0x53, 0x45,
1223 0x52, 0x54, 0x52, 0x55, 0x53, 0x54, 0x2e, 0x43, 0x4f, 0x4d, 0x31, 0x1f,
1224 0x30, 0x1d, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x16, 0x55, 0x54, 0x4e,
1225 0x2d, 0x55, 0x53, 0x45, 0x52, 0x46, 0x49, 0x52, 0x53, 0x54, 0x2d, 0x48,
1226 0x41, 0x52, 0x44, 0x57, 0x41, 0x52, 0x45
1227 };
1228 static const unsigned int UTN_USERFirst_Hardware_Normalized_Issuer_len = 151;
1229
1230
1231 static void SecPolicyCheckBlackListedLeaf(SecPVCRef pvc,
1232 CFStringRef key) {
1233 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, 0);
1234 CFDataRef issuer = cert ? SecCertificateGetNormalizedIssuerContent(cert) : NULL;
1235
1236 if (issuer && (CFDataGetLength(issuer) == (CFIndex)UTN_USERFirst_Hardware_Normalized_Issuer_len) &&
1237 (0 == memcmp(UTN_USERFirst_Hardware_Normalized_Issuer, CFDataGetBytePtr(issuer),
1238 UTN_USERFirst_Hardware_Normalized_Issuer_len)))
1239 {
1240 #if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE))
1241 CFDataRef serial = SecCertificateCopySerialNumber(cert, NULL);
1242 #else
1243 CFDataRef serial = SecCertificateCopySerialNumber(cert);
1244 #endif
1245
1246 if (serial) {
1247 CFIndex serial_length = CFDataGetLength(serial);
1248 const uint8_t *serial_ptr = CFDataGetBytePtr(serial);
1249
1250 while ((serial_length > 0) && (*serial_ptr == 0)) {
1251 serial_ptr++;
1252 serial_length--;
1253 }
1254
1255 if (serial_length == (CFIndex)sizeof(*UTN_USERFirst_Hardware_Serial)) {
1256 unsigned int i;
1257 for (i = 0; i < array_size(UTN_USERFirst_Hardware_Serial); i++)
1258 {
1259 if (0 == memcmp(UTN_USERFirst_Hardware_Serial[i],
1260 serial_ptr, sizeof(*UTN_USERFirst_Hardware_Serial)))
1261 {
1262 SecPVCSetResult(pvc, key, 0, kCFBooleanFalse);
1263 CFReleaseSafe(serial);
1264 return;
1265 }
1266 }
1267 }
1268 CFRelease(serial);
1269 }
1270 }
1271
1272 SecOTAPKIRef otapkiRef = SecOTAPKICopyCurrentOTAPKIRef();
1273 if (NULL != otapkiRef)
1274 {
1275 CFSetRef blackListedKeys = SecOTAPKICopyBlackListSet(otapkiRef);
1276 CFRelease(otapkiRef);
1277 if (NULL != blackListedKeys)
1278 {
1279 /* Check for blacklisted intermediates keys. */
1280 CFDataRef dgst = SecCertificateCopyPublicKeySHA1Digest(cert);
1281 if (dgst)
1282 {
1283 /* Check dgst against blacklist. */
1284 if (CFSetContainsValue(blackListedKeys, dgst))
1285 {
1286 SecPVCSetResult(pvc, key, 0, kCFBooleanFalse);
1287 }
1288 CFRelease(dgst);
1289 }
1290 CFRelease(blackListedKeys);
1291 }
1292 }
1293 }
1294
1295 static void SecPolicyCheckGrayListedLeaf(SecPVCRef pvc, CFStringRef key)
1296 {
1297 SecOTAPKIRef otapkiRef = SecOTAPKICopyCurrentOTAPKIRef();
1298 if (NULL != otapkiRef)
1299 {
1300 CFSetRef grayListedKeys = SecOTAPKICopyGrayList(otapkiRef);
1301 CFRelease(otapkiRef);
1302 if (NULL != grayListedKeys)
1303 {
1304 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, 0);
1305
1306 CFDataRef dgst = SecCertificateCopyPublicKeySHA1Digest(cert);
1307 if (dgst)
1308 {
1309 /* Check dgst against gray. */
1310 if (CFSetContainsValue(grayListedKeys, dgst))
1311 {
1312 SecPVCSetResult(pvc, key, 0, kCFBooleanFalse);
1313 }
1314 CFRelease(dgst);
1315 }
1316 CFRelease(grayListedKeys);
1317 }
1318 }
1319 }
1320
1321 static void SecPolicyCheckLeafMarkerOid(SecPVCRef pvc, CFStringRef key)
1322 {
1323 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, 0);
1324 SecPolicyRef policy = SecPVCGetPolicy(pvc);
1325 CFTypeRef value = CFDictionaryGetValue(policy->_options, key);
1326
1327 if (value && SecCertificateHasMarkerExtension(cert, value))
1328 return;
1329
1330 SecPVCSetResult(pvc, key, 0, kCFBooleanFalse);
1331 }
1332
1333 static void SecPolicyCheckIntermediateMarkerOid(SecPVCRef pvc, CFStringRef key)
1334 {
1335 CFIndex ix, count = SecPVCGetCertificateCount(pvc);
1336 SecPolicyRef policy = SecPVCGetPolicy(pvc);
1337 CFTypeRef value = CFDictionaryGetValue(policy->_options, key);
1338
1339 for (ix = 1; ix < count - 1; ix++) {
1340 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix);
1341 if (SecCertificateHasMarkerExtension(cert, value))
1342 return;
1343 }
1344 SecPVCSetResult(pvc, key, 0, kCFBooleanFalse);
1345 }
1346
1347 /* Returns true if path is on the allow list, false otherwise */
1348 static bool SecPVCCheckCertificateAllowList(SecPVCRef pvc)
1349 {
1350 bool result = false;
1351 CFIndex ix = 0, count = SecPVCGetCertificateCount(pvc);
1352 CFStringRef authKey = NULL;
1353 SecOTAPKIRef otapkiRef = NULL;
1354
1355 //get authKeyID from the last chain in the cert
1356 if (count < 1) {
1357 return result;
1358 }
1359 SecCertificateRef lastCert = SecPVCGetCertificateAtIndex(pvc, count - 1);
1360 CFDataRef authKeyID = SecCertificateGetAuthorityKeyID(lastCert);
1361 if (NULL == authKeyID) {
1362 return result;
1363 }
1364 authKey = CFDataCopyHexString(authKeyID);
1365
1366 //if allowList && key is in allowList, this would have chained up to a now-removed anchor
1367 otapkiRef = SecOTAPKICopyCurrentOTAPKIRef();
1368 if (NULL == otapkiRef) {
1369 goto errout;
1370 }
1371 CFDictionaryRef allowList = SecOTAPKICopyAllowList(otapkiRef);
1372 if (NULL == allowList) {
1373 goto errout;
1374 }
1375
1376 CFArrayRef allowedCerts = CFDictionaryGetValue(allowList, authKey);
1377 if (!allowedCerts || !CFArrayGetCount(allowedCerts)) {
1378 goto errout;
1379 }
1380
1381 //search sorted array for the SHA256 hash of a cert in the chain
1382 CFRange range = CFRangeMake(0, CFArrayGetCount(allowedCerts));
1383 for (ix = 0; ix < count; ix++) {
1384 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix);
1385 if (!cert) {
1386 goto errout;
1387 }
1388
1389 CFDataRef certHash = SecCertificateCopySHA256Digest(cert);
1390 if (!certHash) {
1391 goto errout;
1392 }
1393
1394 CFIndex position = CFArrayBSearchValues(allowedCerts, range, certHash,
1395 (CFComparatorFunction)CFDataCompare, NULL);
1396 if (position < CFArrayGetCount(allowedCerts)) {
1397 CFDataRef possibleMatch = CFArrayGetValueAtIndex(allowedCerts, position);
1398 if (!CFDataCompare(certHash, possibleMatch)) {
1399 //this cert is in the allowlist
1400 result = true;
1401 }
1402 }
1403
1404 CFRelease(certHash);
1405 }
1406
1407 errout:
1408 CFRelease(authKey);
1409 CFReleaseNull(otapkiRef);
1410 CFReleaseNull(allowList);
1411 return result;
1412 }
1413
1414
1415 /****************************************************************************
1416 *********************** New rfc5280 Chain Validation ***********************
1417 ****************************************************************************/
1418
1419 #if 0
1420 typedef struct cert_path *cert_path_t;
1421 struct cert_path {
1422 int length;
1423 };
1424
1425 typedef struct x500_name *x500_name_t;
1426 struct x500_name {
1427 };
1428
1429 typedef struct algorithm_id *algorithm_id_t;
1430 struct algorithm_id {
1431 oid_t algorithm_oid;
1432 der_t parameters;
1433 };
1434
1435 typedef struct trust_anchor *trust_anchor_t;
1436 struct trust_anchor {
1437 x500_name_t issuer_name;
1438 algorithm_id_t public_key_algorithm; /* includes optional params */
1439 SecKeyRef public_key;
1440 };
1441
1442 typedef struct certificate_policy *certificate_policy_t;
1443 struct certificate_policy {
1444 policy_qualifier_t qualifiers;
1445 oid_t oid;
1446 SLIST_ENTRY(certificate_policy) policies;
1447 };
1448
1449 typedef struct policy_mapping *policy_mapping_t;
1450 struct policy_mapping {
1451 SLIST_ENTRY(policy_mapping) mappings;
1452 oid_t issuer_domain_policy;
1453 oid_t subject_domain_policy;
1454 };
1455
1456 typedef struct root_name *root_name_t;
1457 struct root_name {
1458 };
1459 #endif
1460
1461 struct policy_tree_add_ctx {
1462 oid_t p_oid;
1463 policy_qualifier_t p_q;
1464 };
1465
1466 /* 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}. */
1467 static bool policy_tree_add_if_match(policy_tree_t node, void *ctx) {
1468 struct policy_tree_add_ctx *info = (struct policy_tree_add_ctx *)ctx;
1469 policy_set_t policy_set;
1470 for (policy_set = node->expected_policy_set;
1471 policy_set;
1472 policy_set = policy_set->oid_next) {
1473 if (oid_equal(policy_set->oid, info->p_oid)) {
1474 policy_tree_add_child(node, &info->p_oid, info->p_q);
1475 return true;
1476 }
1477 }
1478 return false;
1479 }
1480
1481 /* 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}. */
1482 static bool policy_tree_add_if_any(policy_tree_t node, void *ctx) {
1483 struct policy_tree_add_ctx *info = (struct policy_tree_add_ctx *)ctx;
1484 if (oid_equal(node->valid_policy, oidAnyPolicy)) {
1485 policy_tree_add_child(node, &info->p_oid, info->p_q);
1486 return true;
1487 }
1488 return false;
1489 }
1490
1491 /* Return true iff node has a child with a valid_policy equal to oid. */
1492 static bool policy_tree_has_child_with_oid(policy_tree_t node,
1493 const oid_t *oid) {
1494 policy_tree_t child;
1495 for (child = node->children; child; child = child->siblings) {
1496 if (oid_equal(child->valid_policy, (*oid))) {
1497 return true;
1498 }
1499 }
1500 return false;
1501 }
1502
1503 /* 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. */
1504 static bool policy_tree_add_expected(policy_tree_t node, void *ctx) {
1505 policy_qualifier_t p_q = (policy_qualifier_t)ctx;
1506 policy_set_t policy_set;
1507 bool added_node = false;
1508 for (policy_set = node->expected_policy_set;
1509 policy_set;
1510 policy_set = policy_set->oid_next) {
1511 if (!policy_tree_has_child_with_oid(node, &policy_set->oid)) {
1512 policy_tree_add_child(node, &policy_set->oid, p_q);
1513 added_node = true;
1514 }
1515 }
1516 return added_node;
1517 }
1518
1519 #if 0
1520 /* 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. */
1521 static bool policy_tree_map(policy_tree_t node, void *ctx) {
1522 /* Can't map oidAnyPolicy. */
1523 if (oid_equal(node->valid_policy, oidAnyPolicy))
1524 return false;
1525
1526 const SecCEPolicyMappings *pm = (const SecCEPolicyMappings *)ctx;
1527 uint32_t mapping_ix, mapping_count = pm->numMappings;
1528 policy_set_t policy_set = NULL;
1529 /* First count how many mappings match this nodes valid_policy. */
1530 for (mapping_ix = 0; mapping_ix < mapping_count; ++mapping_ix) {
1531 const SecCEPolicyMapping *mapping = &pm->mappings[mapping_ix];
1532 if (oid_equal(node->valid_policy, mapping->issuerDomainPolicy)) {
1533 policy_set_t p_node = (policy_set_t)malloc(sizeof(*policy_set));
1534 p_node->oid = mapping->subjectDomainPolicy;
1535 p_node->oid_next = policy_set ? policy_set : NULL;
1536 policy_set = p_node;
1537 }
1538 }
1539 if (policy_set) {
1540 policy_tree_set_expected_policy(node, policy_set);
1541 return true;
1542 }
1543 return false;
1544 }
1545 #endif
1546
1547 #define POLICY_MAPPING 0
1548 #define POLICY_SUBTREES 1
1549
1550 /* rfc5280 basic cert processing. */
1551 static void SecPolicyCheckBasicCertificateProcessing(SecPVCRef pvc,
1552 CFStringRef key) {
1553 /* Inputs */
1554 //cert_path_t path;
1555 CFIndex count = SecPVCGetCertificateCount(pvc);
1556 /* 64 bits cast: worst case here is we truncate the number of cert, and the validation may fail */
1557 assert((unsigned long)count<=UINT32_MAX); /* Debug check. Correct as long as CFIndex is long */
1558 uint32_t n = (uint32_t)count;
1559 bool is_anchored = SecPVCIsAnchored(pvc);
1560 if (is_anchored) {
1561 /* If the anchor is trusted we don't procces the last cert in the
1562 chain (root). */
1563 n--;
1564 } else {
1565 /* trust may be restored for a path with an untrusted root that matches the allow list */
1566 if (!SecPVCCheckCertificateAllowList(pvc)) {
1567 /* Add a detail for the root not being trusted. */
1568 if (SecPVCSetResultForced(pvc, kSecPolicyCheckAnchorTrusted,
1569 n - 1, kCFBooleanFalse, true))
1570 return;
1571 }
1572 }
1573
1574 CFAbsoluteTime verify_time = SecPVCGetVerifyTime(pvc);
1575 //policy_set_t user_initial_policy_set = NULL;
1576 //trust_anchor_t anchor;
1577 bool initial_policy_mapping_inhibit = false;
1578 bool initial_explicit_policy = false;
1579 bool initial_any_policy_inhibit = false;
1580
1581 /* Initialization */
1582 pvc->valid_policy_tree = policy_tree_create(&oidAnyPolicy, NULL);
1583 #if POLICY_SUBTREES
1584 CFMutableArrayRef permitted_subtrees = NULL;
1585 CFMutableArrayRef excluded_subtrees = NULL;
1586 permitted_subtrees = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
1587 excluded_subtrees = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
1588 assert(permitted_subtrees != NULL);
1589 assert(excluded_subtrees != NULL);
1590 #endif
1591 uint32_t explicit_policy = initial_explicit_policy ? 0 : n + 1;
1592 uint32_t inhibit_any_policy = initial_any_policy_inhibit ? 0 : n + 1;
1593 uint32_t policy_mapping = initial_policy_mapping_inhibit ? 0 : n + 1;
1594
1595 #if 0
1596 /* Path builder ensures we only get cert chains with proper issuer
1597 chaining with valid signatures along the way. */
1598 algorithm_id_t working_public_key_algorithm = anchor->public_key_algorithm;
1599 SecKeyRef working_public_key = anchor->public_key;
1600 x500_name_t working_issuer_name = anchor->issuer_name;
1601 #endif
1602 uint32_t i, max_path_length = n;
1603 SecCertificateRef cert = NULL;
1604 for (i = 1; i <= n; ++i) {
1605 /* Process Cert */
1606 cert = SecPVCGetCertificateAtIndex(pvc, n - i);
1607 bool is_self_issued = SecPVCIsCertificateAtIndexSelfSigned(pvc, n - i);
1608
1609 /* (a) Verify the basic certificate information. */
1610 /* @@@ Ensure that cert was signed with working_public_key_algorithm
1611 using the working_public_key and the working_public_key_parameters. */
1612 #if 1
1613 /* Already done by chain builder. */
1614 if (!SecCertificateIsValid(cert, verify_time)) {
1615 CFStringRef fail_key = i == n ? kSecPolicyCheckValidLeaf : kSecPolicyCheckValidIntermediates;
1616 if (!SecPVCSetResult(pvc, fail_key, n - i, kCFBooleanFalse))
1617 return;
1618 }
1619 #endif
1620 #if 0
1621 /* Check revocation status if the certificate asks for it. */
1622 CFArrayRef ocspResponders = SecCertificateGetOCSPResponders(cert);
1623 if (ocspResponders) {
1624 SecPVCSetCheckRevocation(pvc);
1625 }
1626 #endif
1627 /* @@@ cert.issuer == working_issuer_name. */
1628
1629 #if POLICY_SUBTREES
1630 /* (b) (c) */
1631 if (!is_self_issued || i == n) {
1632 bool found = false;
1633 /* Verify certificate Subject Name and SubjectAltNames are not within any of the excluded_subtrees */
1634 if(excluded_subtrees && CFArrayGetCount(excluded_subtrees)) {
1635 if ((errSecSuccess != SecNameContraintsMatchSubtrees(cert, excluded_subtrees, &found, false)) || found) {
1636 if(!SecPVCSetResultForced(pvc, key, n - i, kCFBooleanFalse, true)) return;
1637 }
1638 }
1639 /* Verify certificate Subject Name and SubjectAltNames are within the permitted_subtrees */
1640 if(permitted_subtrees && CFArrayGetCount(permitted_subtrees)) {
1641 if ((errSecSuccess != SecNameContraintsMatchSubtrees(cert, permitted_subtrees, &found, true)) || !found) {
1642 if(!SecPVCSetResultForced(pvc, key, n - i, kCFBooleanFalse, true)) return;
1643 }
1644 }
1645 }
1646 #endif
1647 /* (d) */
1648 if (pvc->valid_policy_tree) {
1649 const SecCECertificatePolicies *cp =
1650 SecCertificateGetCertificatePolicies(cert);
1651 size_t policy_ix, policy_count = cp ? cp->numPolicies : 0;
1652 for (policy_ix = 0; policy_ix < policy_count; ++policy_ix) {
1653 const SecCEPolicyInformation *policy = &cp->policies[policy_ix];
1654 oid_t p_oid = policy->policyIdentifier;
1655 policy_qualifier_t p_q = &policy->policyQualifiers;
1656 struct policy_tree_add_ctx ctx = { p_oid, p_q };
1657 if (!oid_equal(p_oid, oidAnyPolicy)) {
1658 if (!policy_tree_walk_depth(pvc->valid_policy_tree, i - 1,
1659 policy_tree_add_if_match, &ctx)) {
1660 policy_tree_walk_depth(pvc->valid_policy_tree, i - 1,
1661 policy_tree_add_if_any, &ctx);
1662 }
1663 }
1664 }
1665 /* The certificate policies extension includes the policy
1666 anyPolicy with the qualifier set AP-Q and either
1667 (a) inhibit_anyPolicy is greater than 0 or
1668 (b) i < n and the certificate is self-issued. */
1669 if (inhibit_any_policy > 0 || (i < n && is_self_issued)) {
1670 for (policy_ix = 0; policy_ix < policy_count; ++policy_ix) {
1671 const SecCEPolicyInformation *policy = &cp->policies[policy_ix];
1672 oid_t p_oid = policy->policyIdentifier;
1673 policy_qualifier_t p_q = &policy->policyQualifiers;
1674 if (oid_equal(p_oid, oidAnyPolicy)) {
1675 policy_tree_walk_depth(pvc->valid_policy_tree, i - 1,
1676 policy_tree_add_expected, (void *)p_q);
1677 }
1678 }
1679 }
1680 policy_tree_prune_childless(&pvc->valid_policy_tree, i - 1);
1681 /* (e) */
1682 if (!cp) {
1683 if (pvc->valid_policy_tree)
1684 policy_tree_prune(&pvc->valid_policy_tree);
1685 }
1686 }
1687 /* (f) Verify that either explicit_policy is greater than 0 or the
1688 valid_policy_tree is not equal to NULL. */
1689 if (!pvc->valid_policy_tree && explicit_policy == 0) {
1690 /* valid_policy_tree is empty and explicit policy is 0, illegal. */
1691 if (!SecPVCSetResultForced(pvc, key /* @@@ Need custom key */, n - i, kCFBooleanFalse, true))
1692 return;
1693 }
1694 /* If Last Cert in Path */
1695 if (i == n)
1696 break;
1697
1698 /* Prepare for Next Cert */
1699 #if POLICY_MAPPING
1700 /* (a) verify that anyPolicy does not appear as an
1701 issuerDomainPolicy or a subjectDomainPolicy */
1702 CFDictionaryRef pm = SecCertificateGetPolicyMappings(cert);
1703 if (pm) {
1704 uint32_t mapping_ix, mapping_count = pm->numMappings;
1705 for (mapping_ix = 0; mapping_ix < mapping_count; ++mapping_ix) {
1706 const SecCEPolicyMapping *mapping = &pm->mappings[mapping_ix];
1707 if (oid_equal(mapping->issuerDomainPolicy, oidAnyPolicy)
1708 || oid_equal(mapping->subjectDomainPolicy, oidAnyPolicy)) {
1709 /* Policy mapping uses anyPolicy, illegal. */
1710 if (!SecPVCSetResultForced(pvc, key /* @@@ Need custom key */, n - i, kCFBooleanFalse))
1711 return;
1712 }
1713 }
1714 /* (b) */
1715 /* (1) If the policy_mapping variable is greater than 0 */
1716 if (policy_mapping > 0) {
1717 if (!policy_tree_walk_depth(pvc->valid_policy_tree, i,
1718 policy_tree_map, (void *)pm)) {
1719 /* 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:
1720
1721 (i) set the valid_policy to ID-P;
1722
1723 (ii) set the qualifier_set to the qualifier set of the
1724 policy anyPolicy in the certificate policies
1725 extension of certificate i; and
1726 (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. */
1727 }
1728 } else {
1729 #if 0
1730 /* (i) delete each node of depth i in the valid_policy_tree
1731 where ID-P is the valid_policy. */
1732 struct policy_tree_map_ctx ctx = { idp_oid, sdp_oid };
1733 policy_tree_walk_depth(pvc->valid_policy_tree, i,
1734 policy_tree_delete_if_match, &ctx);
1735 #endif
1736 /* (ii) If there is a node in the valid_policy_tree of depth
1737 i-1 or less without any child nodes, delete that
1738 node. Repeat this step until there are no nodes of
1739 depth i-1 or less without children. */
1740 policy_tree_prune_childless(&pvc->valid_policy_tree, i - 1);
1741 }
1742 }
1743 #endif /* POLICY_MAPPING */
1744 /* (c)(d)(e)(f) */
1745 //working_issuer_name = SecCertificateGetNormalizedSubjectContent(cert);
1746 //working_public_key = SecCertificateCopyPublicKey(cert);
1747 //working_public_key_parameters = SecCertificateCopyPublicKeyParameters(cert);
1748 //working_public_key_algorithm = SecCertificateCopyPublicKeyAlgorithm(cert);
1749 #if POLICY_SUBTREES
1750 /* (g) If a name constraints extension is included in the certificate, modify the permitted_subtrees and excluded_subtrees state variables.
1751 */
1752 CFArrayRef permitted_subtrees_in_cert = SecCertificateGetPermittedSubtrees(cert);
1753 if (permitted_subtrees_in_cert) {
1754 SecNameConstraintsIntersectSubtrees(permitted_subtrees, permitted_subtrees_in_cert);
1755 }
1756
1757 // could do something smart here to avoid inserting the exact same constraint
1758 CFArrayRef excluded_subtrees_in_cert = SecCertificateGetExcludedSubtrees(cert);
1759 if (excluded_subtrees_in_cert) {
1760 CFIndex num_trees = CFArrayGetCount(excluded_subtrees_in_cert);
1761 CFRange range = { 0, num_trees };
1762 CFArrayAppendArray(excluded_subtrees, excluded_subtrees_in_cert, range);
1763 }
1764 #endif
1765 /* (h) */
1766 if (!is_self_issued) {
1767 if (explicit_policy)
1768 explicit_policy--;
1769 if (policy_mapping)
1770 policy_mapping--;
1771 if (inhibit_any_policy)
1772 inhibit_any_policy--;
1773 }
1774 /* (i) */
1775 const SecCEPolicyConstraints *pc =
1776 SecCertificateGetPolicyConstraints(cert);
1777 if (pc) {
1778 if (pc->requireExplicitPolicyPresent
1779 && pc->requireExplicitPolicy < explicit_policy) {
1780 explicit_policy = pc->requireExplicitPolicy;
1781 }
1782 if (pc->inhibitPolicyMappingPresent
1783 && pc->inhibitPolicyMapping < policy_mapping) {
1784 policy_mapping = pc->inhibitPolicyMapping;
1785 }
1786 }
1787 /* (j) */
1788 uint32_t iap = SecCertificateGetInhibitAnyPolicySkipCerts(cert);
1789 if (iap < inhibit_any_policy) {
1790 inhibit_any_policy = iap;
1791 }
1792 /* (k) */
1793 const SecCEBasicConstraints *bc =
1794 SecCertificateGetBasicConstraints(cert);
1795 #if 0 /* Checked in chain builder pre signature verify already. */
1796 if (!bc || !bc->isCA) {
1797 /* Basic constraints not present or not marked as isCA, illegal. */
1798 if (!SecPVCSetResult(pvc, kSecPolicyCheckBasicContraints,
1799 n - i, kCFBooleanFalse))
1800 return;
1801 }
1802 #endif
1803 /* (l) */
1804 if (!is_self_issued) {
1805 if (max_path_length > 0) {
1806 max_path_length--;
1807 } else {
1808 /* max_path_len exceeded, illegal. */
1809 if (!SecPVCSetResult(pvc, kSecPolicyCheckBasicContraints,
1810 n - i, kCFBooleanFalse))
1811 return;
1812 }
1813 }
1814 /* (m) */
1815 if (bc && bc->pathLenConstraintPresent
1816 && bc->pathLenConstraint < max_path_length) {
1817 max_path_length = bc->pathLenConstraint;
1818 }
1819 #if 0 /* Checked in chain builder pre signature verify already. */
1820 /* (n) If a key usage extension is present, verify that the keyCertSign bit is set. */
1821 SecKeyUsage keyUsage = SecCertificateGetKeyUsage(cert);
1822 if (keyUsage && !(keyUsage & kSecKeyUsageKeyCertSign)) {
1823 if (!SecPVCSetResultForced(pvc, kSecPolicyCheckKeyUsage,
1824 n - i, kCFBooleanFalse, true))
1825 return;
1826 }
1827 #endif
1828 /* (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. */
1829 if (SecCertificateHasUnknownCriticalExtension(cert)) {
1830 /* Certificate contains one or more unknown critical extensions. */
1831 if (!SecPVCSetResult(pvc, kSecPolicyCheckCriticalExtensions,
1832 n - i, kCFBooleanFalse))
1833 return;
1834 }
1835 } /* end loop over certs in path */
1836 /* Wrap up */
1837 cert = SecPVCGetCertificateAtIndex(pvc, 0);
1838 /* (a) */
1839 if (explicit_policy)
1840 explicit_policy--;
1841 /* (b) */
1842 const SecCEPolicyConstraints *pc = SecCertificateGetPolicyConstraints(cert);
1843 if (pc) {
1844 if (pc->requireExplicitPolicyPresent
1845 && pc->requireExplicitPolicy == 0) {
1846 explicit_policy = 0;
1847 }
1848 }
1849 /* (c) */
1850 //working_public_key = SecCertificateCopyPublicKey(cert);
1851 /* (d) */
1852 /* 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
1853 working_public_key_algorithm are different, set the working_public_key_parameters to null. */
1854 //working_public_key_parameters = SecCertificateCopyPublicKeyParameters(cert);
1855 /* (e) */
1856 //working_public_key_algorithm = SecCertificateCopyPublicKeyAlgorithm(cert);
1857 /* (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. */
1858 if (SecCertificateHasUnknownCriticalExtension(cert)) {
1859 /* Certificate contains one or more unknown critical extensions. */
1860 if (!SecPVCSetResult(pvc, kSecPolicyCheckCriticalExtensions,
1861 0, kCFBooleanFalse))
1862 return;
1863 }
1864 /* (g) Calculate the intersection of the valid_policy_tree and the user-initial-policy-set, as follows */
1865
1866 if (pvc->valid_policy_tree) {
1867 #if !defined(NDEBUG)
1868 policy_tree_dump(pvc->valid_policy_tree);
1869 #endif
1870 /* (g3c4) */
1871 //policy_tree_prune_childless(&pvc->valid_policy_tree, n - 1);
1872 }
1873
1874 /* If either (1) the value of explicit_policy variable is greater than
1875 zero or (2) the valid_policy_tree is not NULL, then path processing
1876 has succeeded. */
1877 if (!pvc->valid_policy_tree && explicit_policy == 0) {
1878 /* valid_policy_tree is empty and explicit policy is 0, illegal. */
1879 if (!SecPVCSetResultForced(pvc, key /* @@@ Need custom key */, 0, kCFBooleanFalse, true))
1880 return;
1881 }
1882
1883 CFReleaseNull(permitted_subtrees);
1884 CFReleaseNull(excluded_subtrees);
1885 }
1886
1887 static policy_set_t policies_for_cert(SecCertificateRef cert) {
1888 policy_set_t policies = NULL;
1889 const SecCECertificatePolicies *cp =
1890 SecCertificateGetCertificatePolicies(cert);
1891 size_t policy_ix, policy_count = cp ? cp->numPolicies : 0;
1892 for (policy_ix = 0; policy_ix < policy_count; ++policy_ix) {
1893 policy_set_add(&policies, &cp->policies[policy_ix].policyIdentifier);
1894 }
1895 return policies;
1896 }
1897
1898 static void SecPolicyCheckEV(SecPVCRef pvc,
1899 CFStringRef key) {
1900 CFIndex ix, count = SecPVCGetCertificateCount(pvc);
1901 policy_set_t valid_policies = NULL;
1902
1903 for (ix = 0; ix < count; ++ix) {
1904 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix);
1905 policy_set_t policies = policies_for_cert(cert);
1906 if (ix == 0) {
1907 /* Subscriber */
1908 /* anyPolicy in the leaf isn't allowed for EV, so only init
1909 valid_policies if we have real policies. */
1910 if (!policy_set_contains(policies, &oidAnyPolicy)) {
1911 valid_policies = policies;
1912 policies = NULL;
1913 }
1914 } else if (ix < count - 1) {
1915 /* Subordinate CA */
1916 if (!SecPolicySubordinateCACertificateCouldBeEV(cert)) {
1917 secdebug("ev", "subordinate certificate is not ev");
1918 if (SecPVCSetResultForced(pvc, key,
1919 ix, kCFBooleanFalse, true)) {
1920 policy_set_free(valid_policies);
1921 policy_set_free(policies);
1922 return;
1923 }
1924 }
1925 policy_set_intersect(&valid_policies, policies);
1926 } else {
1927 /* Root CA */
1928 if (!SecPolicyRootCACertificateIsEV(cert, valid_policies)) {
1929 secdebug("ev", "anchor certificate is not ev");
1930 if (SecPVCSetResultForced(pvc, key,
1931 ix, kCFBooleanFalse, true)) {
1932 policy_set_free(valid_policies);
1933 policy_set_free(policies);
1934 return;
1935 }
1936 }
1937 }
1938 policy_set_free(policies);
1939 if (!valid_policies) {
1940 secdebug("ev", "valid_policies set is empty: chain not ev");
1941 /* If we ever get into a state where no policies are valid anymore
1942 this can't be an ev chain. */
1943 if (SecPVCSetResultForced(pvc, key,
1944 ix, kCFBooleanFalse, true)) {
1945 return;
1946 }
1947 }
1948 }
1949
1950 policy_set_free(valid_policies);
1951
1952 /* (a) EV Subscriber Certificates Each EV Certificate issued by the CA to a
1953 Subscriber MUST contain an OID defined by the CA in the certificate’s
1954 certificatePolicies extension that: (i) indicates which CA policy statement relates
1955 to that certificate, (ii) asserts the CA’s adherence to and compliance with these
1956 Guidelines, and (iii), by pre-agreement with the Application Software Vendor,
1957 marks the certificate as being an EV Certificate.
1958 (b) EV Subordinate CA Certificates
1959 (1) Certificates issued to Subordinate CAs that are not controlled by the issuing
1960 CA MUST contain one or more OIDs defined by the issuing CA that
1961 explicitly identify the EV Policies that are implemented by the Subordinate
1962 CA;
1963 (2) Certificates issued to Subordinate CAs that are controlled by the Root CA
1964 MAY contain the special anyPolicy OID (2.5.29.32.0).
1965 (c) Root CA Certificates Root CA Certificates SHOULD NOT contain the
1966 certificatePolicies or extendedKeyUsage extensions.
1967 */
1968 }
1969
1970
1971 /*
1972 * MARK: Certificate Transparency support
1973 */
1974
1975 /***
1976
1977 struct {
1978 Version sct_version; // 1 byte
1979 LogID id; // 32 bytes
1980 uint64 timestamp; // 8 bytes
1981 CtExtensions extensions; // 2 bytes len field, + n bytes data
1982 digitally-signed struct { // 1 byte hash alg, 1 byte sig alg, n bytes signature
1983 Version sct_version;
1984 SignatureType signature_type = certificate_timestamp;
1985 uint64 timestamp;
1986 LogEntryType entry_type;
1987 select(entry_type) {
1988 case x509_entry: ASN.1Cert;
1989 case precert_entry: PreCert;
1990 } signed_entry;
1991 CtExtensions extensions;
1992 };
1993 } SignedCertificateTimestamp;
1994
1995 ***/
1996
1997 #include <Security/SecureTransportPriv.h>
1998
1999 static const
2000 SecAsn1Oid *oidForSigAlg(SSL_HashAlgorithm hash, SSL_SignatureAlgorithm alg)
2001 {
2002 switch(alg) {
2003 case SSL_SignatureAlgorithmRSA:
2004 switch (hash) {
2005 case SSL_HashAlgorithmSHA1:
2006 return &CSSMOID_SHA1WithRSA;
2007 case SSL_HashAlgorithmSHA256:
2008 return &CSSMOID_SHA256WithRSA;
2009 case SSL_HashAlgorithmSHA384:
2010 return &CSSMOID_SHA384WithRSA;
2011 default:
2012 break;
2013 }
2014 case SSL_SignatureAlgorithmECDSA:
2015 switch (hash) {
2016 case SSL_HashAlgorithmSHA1:
2017 return &CSSMOID_ECDSA_WithSHA1;
2018 case SSL_HashAlgorithmSHA256:
2019 return &CSSMOID_ECDSA_WithSHA256;
2020 case SSL_HashAlgorithmSHA384:
2021 return &CSSMOID_ECDSA_WithSHA384;
2022 default:
2023 break;
2024 }
2025 default:
2026 break;
2027 }
2028
2029 return NULL;
2030 }
2031
2032
2033 static size_t SSLDecodeUint16(const uint8_t *p)
2034 {
2035 return (p[0]<<8 | p[1]);
2036 }
2037
2038 static uint8_t *SSLEncodeUint16(uint8_t *p, size_t len)
2039 {
2040 p[0] = (len >> 8)&0xff;
2041 p[1] = (len & 0xff);
2042 return p+2;
2043 }
2044
2045 static uint8_t *SSLEncodeUint24(uint8_t *p, size_t len)
2046 {
2047 p[0] = (len >> 16)&0xff;
2048 p[1] = (len >> 8)&0xff;
2049 p[2] = (len & 0xff);
2050 return p+3;
2051 }
2052
2053
2054 static
2055 uint64_t SSLDecodeUint64(const uint8_t *p)
2056 {
2057 uint64_t u = 0;
2058 for(int i=0; i<8; i++) {
2059 u=(u<<8)|p[0];
2060 p++;
2061 }
2062 return u;
2063 }
2064
2065 #include <libDER/DER_CertCrl.h>
2066 #include <libDER/DER_Encode.h>
2067 #include <libDER/asn1Types.h>
2068
2069
2070 static CFDataRef copy_x509_entry_from_chain(SecPVCRef pvc)
2071 {
2072 SecCertificateRef leafCert = SecPVCGetCertificateAtIndex(pvc, 0);
2073
2074 CFMutableDataRef data = CFDataCreateMutable(kCFAllocatorDefault, 3+SecCertificateGetLength(leafCert));
2075
2076 CFDataSetLength(data, 3+SecCertificateGetLength(leafCert));
2077
2078 uint8_t *q = CFDataGetMutableBytePtr(data);
2079 q = SSLEncodeUint24(q, SecCertificateGetLength(leafCert));
2080 memcpy(q, SecCertificateGetBytePtr(leafCert), SecCertificateGetLength(leafCert));
2081
2082 return data;
2083 }
2084
2085
2086 static CFDataRef copy_precert_entry_from_chain(SecPVCRef pvc)
2087 {
2088 SecCertificateRef leafCert = NULL;
2089 SecCertificateRef issuer = NULL;
2090 CFDataRef issuerKeyHash = NULL;
2091 CFDataRef tbs_precert = NULL;
2092 CFMutableDataRef data= NULL;
2093
2094 require_quiet(SecPVCGetCertificateCount(pvc)>=2, out); //we need the issuer key for precerts.
2095 leafCert = SecPVCGetCertificateAtIndex(pvc, 0);
2096 issuer = SecPVCGetCertificateAtIndex(pvc, 1);
2097
2098 require(leafCert, out);
2099 require(issuer, out); // Those two would likely indicate an internal error, since we already checked the chain length above.
2100 issuerKeyHash = SecCertificateCopySubjectPublicKeyInfoSHA256Digest(issuer);
2101 tbs_precert = SecCertificateCopyPrecertTBS(leafCert);
2102
2103 require(issuerKeyHash, out);
2104 require(tbs_precert, out);
2105 data = CFDataCreateMutable(kCFAllocatorDefault, CFDataGetLength(issuerKeyHash) + 3 + CFDataGetLength(tbs_precert));
2106 CFDataSetLength(data, CFDataGetLength(issuerKeyHash) + 3 + CFDataGetLength(tbs_precert));
2107
2108 uint8_t *q = CFDataGetMutableBytePtr(data);
2109 memcpy(q, CFDataGetBytePtr(issuerKeyHash), CFDataGetLength(issuerKeyHash)); q += CFDataGetLength(issuerKeyHash); // issuer key hash
2110 q = SSLEncodeUint24(q, CFDataGetLength(tbs_precert));
2111 memcpy(q, CFDataGetBytePtr(tbs_precert), CFDataGetLength(tbs_precert));
2112
2113 out:
2114 CFReleaseSafe(issuerKeyHash);
2115 CFReleaseSafe(tbs_precert);
2116 return data;
2117 }
2118
2119 /* If the 'sct' is valid, return the operator ID of the log that signed this sct.
2120
2121 The SCT is valid if:
2122 - It decodes properly.
2123 - Its timestamp is less than 'verifyTime'.
2124 - It is signed by a log in 'trustedLogs'.
2125 - The signing log expiryTime (if any) is less than 'verifyTime' (entry_type==0) or 'issuanceTime' (entry_type==1).
2126
2127 If the SCT is valid, the returned CFStringRef is the identifier for the log operator. That value is not retained.
2128 If the SCT is valid, '*validLogAtVerifyTime' is set to true if the log is not expired at 'verifyTime'
2129
2130 If the SCT is not valid this function return NULL.
2131 */
2132 static CFStringRef get_valid_sct_operator(CFDataRef sct, int entry_type, CFDataRef entry, CFAbsoluteTime verifyTime, CFAbsoluteTime issuanceTime, CFArrayRef trustedLogs, bool *validLogAtVerifyTime)
2133 {
2134 uint8_t version;
2135 const uint8_t *logID;
2136 const uint8_t *timestampData;
2137 uint64_t timestamp;
2138 size_t extensionsLen;
2139 const uint8_t *extensionsData;
2140 uint8_t hashAlg;
2141 uint8_t sigAlg;
2142 size_t signatureLen;
2143 const uint8_t *signatureData;
2144 CFStringRef result = NULL;
2145 SecKeyRef pubKey = NULL;
2146 uint8_t *signed_data = NULL;
2147 const SecAsn1Oid *oid = NULL;
2148 SecAsn1AlgId algId;
2149
2150 const uint8_t *p = CFDataGetBytePtr(sct);
2151 size_t len = CFDataGetLength(sct);
2152 uint64_t vt =(uint64_t)( verifyTime + kCFAbsoluteTimeIntervalSince1970) * 1000;
2153
2154 require(len>=43, out);
2155
2156 version = p[0]; p++; len--;
2157 logID = p; p+=32; len-=32;
2158 timestampData = p; p+=8; len-=8;
2159 extensionsLen = SSLDecodeUint16(p); p+=2; len-=2;
2160
2161 require(len>=extensionsLen, out);
2162 extensionsData = p; p+=extensionsLen; len-=extensionsLen;
2163
2164 require(len>=4, out);
2165 hashAlg=p[0]; p++; len--;
2166 sigAlg=p[0]; p++; len--;
2167 signatureLen = SSLDecodeUint16(p); p+=2; len-=2;
2168 require(len==signatureLen, out); /* We do not tolerate any extra data after the signature */
2169 signatureData = p;
2170
2171 /* verify version: only v1(0) is supported */
2172 if(version!=0) {
2173 secerror("SCT version unsupported: %d\n", version);
2174 goto out;
2175 }
2176
2177 /* verify timestamp not in the future */
2178 timestamp = SSLDecodeUint64(timestampData);
2179 if(timestamp > vt) {
2180 secerror("SCT is in the future: %llu > %llu\n", timestamp, vt);
2181 goto out;
2182 }
2183
2184 uint8_t *q;
2185
2186 /* signed entry */
2187 size_t signed_data_len = 12 + CFDataGetLength(entry) + 2 + extensionsLen ;
2188 signed_data = malloc(signed_data_len);
2189 require(signed_data, out);
2190 q = signed_data;
2191 *q++ = version;
2192 *q++ = 0; // certificate_timestamp
2193 memcpy(q, timestampData, 8); q+=8;
2194 q = SSLEncodeUint16(q, entry_type); // logentry type: 0=cert 1=precert
2195 memcpy(q, CFDataGetBytePtr(entry), CFDataGetLength(entry)); q += CFDataGetLength(entry);
2196 q = SSLEncodeUint16(q, extensionsLen);
2197 memcpy(q, extensionsData, extensionsLen);
2198
2199 CFDataRef logIDData = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, logID, 32, NULL);
2200
2201 CFDictionaryRef logData = CFArrayGetValueMatching(trustedLogs, ^bool(const void *dict) {
2202 const void *key_data;
2203 if(!isDictionary(dict)) return false;
2204 if(!CFDictionaryGetValueIfPresent(dict, CFSTR("key"), &key_data)) return false;
2205 if(!isData(key_data)) return false;
2206 CFDataRef valueID = SecSHA256DigestCreateFromData(kCFAllocatorDefault, (CFDataRef)key_data);
2207 bool result = (bool)(CFDataCompare(logIDData, valueID)==kCFCompareEqualTo);
2208 CFReleaseSafe(valueID);
2209 return result;
2210 });
2211 require(logData, out);
2212
2213 /* If an expiry date is specified, and is a valid CFDate, then we check it against issuanceTime or verifyTime */
2214 const void *expiry_date;
2215 if(CFDictionaryGetValueIfPresent(logData, CFSTR("expiry"), &expiry_date) && isDate(expiry_date)) {
2216 CFAbsoluteTime expiryTime = CFDateGetAbsoluteTime(expiry_date);
2217 if(entry_type == 1) {/* pre-cert: check the validity of the log at issuanceTime */
2218 require(issuanceTime<=expiryTime, out);
2219 } else {
2220 require(verifyTime<=expiryTime, out);
2221 }
2222 *validLogAtVerifyTime = (verifyTime<=expiryTime);
2223 } else {
2224 *validLogAtVerifyTime = true;
2225 }
2226
2227 CFDataRef logKeyData = CFDictionaryGetValue(logData, CFSTR("key"));
2228 require(logKeyData, out); // This failing would be an internal logic error
2229 pubKey = SecKeyCreateFromSubjectPublicKeyInfoData(kCFAllocatorDefault, logKeyData);
2230 require(pubKey, out);
2231
2232 oid = oidForSigAlg(hashAlg, sigAlg);
2233 require(oid, out);
2234
2235 algId.algorithm = *oid;
2236 algId.parameters.Data = NULL;
2237 algId.parameters.Length = 0;
2238
2239 if(SecKeyDigestAndVerify(pubKey, &algId, signed_data, signed_data_len, signatureData, signatureLen)==0) {
2240 result = CFDictionaryGetValue(logData, CFSTR("operator"));
2241 } else {
2242 secerror("SCT signature failed (log=%@)\n", logData);
2243 }
2244
2245 out:
2246 CFReleaseSafe(pubKey);
2247 free(signed_data);
2248 return result;
2249 }
2250
2251 static CFArrayRef copy_ocsp_scts(SecPVCRef pvc)
2252 {
2253 CFMutableArrayRef SCTs = NULL;
2254 SecCertificateRef leafCert = NULL;
2255 SecCertificateRef issuer = NULL;
2256 CFArrayRef ocspResponsesData = NULL;
2257 SecOCSPRequestRef ocspRequest = NULL;
2258
2259 ocspResponsesData = SecPathBuilderCopyOCSPResponses(pvc->builder);
2260 require_quiet(ocspResponsesData, out);
2261
2262 require_quiet(SecPVCGetCertificateCount(pvc)>=2, out); //we need the issuer key for precerts.
2263 leafCert = SecPVCGetCertificateAtIndex(pvc, 0);
2264 issuer = SecPVCGetCertificateAtIndex(pvc, 1);
2265
2266 require(leafCert, out);
2267 require(issuer, out); // not quiet: Those two would likely indicate an internal error, since we already checked the chain length above.
2268 ocspRequest = SecOCSPRequestCreate(leafCert, issuer);
2269
2270 SCTs = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
2271 require(SCTs, out);
2272
2273 CFArrayForEach(ocspResponsesData, ^(const void *value) {
2274 /* TODO: Should the builder already have the appropriate SecOCSPResponseRef ? */
2275 SecOCSPResponseRef ocspResponse = SecOCSPResponseCreate(value);
2276 if(ocspResponse && SecOCSPGetResponseStatus(ocspResponse)==kSecOCSPSuccess) {
2277 SecOCSPSingleResponseRef ocspSingleResponse = SecOCSPResponseCopySingleResponse(ocspResponse, ocspRequest);
2278 if(ocspSingleResponse) {
2279 CFArrayRef singleResponseSCTs = SecOCSPSingleResponseCopySCTs(ocspSingleResponse);
2280 if(singleResponseSCTs) {
2281 CFArrayAppendArray(SCTs, singleResponseSCTs, CFRangeMake(0, CFArrayGetCount(singleResponseSCTs)));
2282 CFRelease(singleResponseSCTs);
2283 }
2284 SecOCSPSingleResponseDestroy(ocspSingleResponse);
2285 }
2286 SecOCSPResponseFinalize(ocspResponse);
2287 }
2288 });
2289
2290 if(CFArrayGetCount(SCTs)==0) {
2291 CFReleaseNull(SCTs);
2292 }
2293
2294 out:
2295 CFReleaseSafe(ocspResponsesData);
2296 if(ocspRequest)
2297 SecOCSPRequestFinalize(ocspRequest);
2298
2299 return SCTs;
2300 }
2301
2302 static void SecPolicyCheckCT(SecPVCRef pvc, CFStringRef key)
2303 {
2304 SecCertificateRef leafCert = SecPVCGetCertificateAtIndex(pvc, 0);
2305 CFArrayRef embeddedScts = SecCertificateCopySignedCertificateTimestamps(leafCert);
2306 CFArrayRef builderScts = SecPathBuilderCopySignedCertificateTimestamps(pvc->builder);
2307 CFArrayRef trustedLogs = SecPathBuilderCopyTrustedLogs(pvc->builder);
2308 CFArrayRef ocspScts = copy_ocsp_scts(pvc);
2309 CFDataRef precertEntry = copy_precert_entry_from_chain(pvc);
2310 CFDataRef x509Entry = copy_x509_entry_from_chain(pvc);
2311
2312 // This eventually contain the list of operators who validated the SCT.
2313 CFMutableSetRef operatorsValidatingEmbeddedScts = CFSetCreateMutable(kCFAllocatorDefault, 0, &kCFTypeSetCallBacks);
2314 CFMutableSetRef operatorsValidatingExternalScts = CFSetCreateMutable(kCFAllocatorDefault, 0, &kCFTypeSetCallBacks);
2315
2316 __block bool atLeastOneValidAtVerifyTime = false;
2317 __block int lifetime; // in Months
2318
2319 require(operatorsValidatingEmbeddedScts, out);
2320 require(operatorsValidatingExternalScts, out);
2321
2322 if(trustedLogs) { // Don't bother trying to validate SCTs if we don't have any trusted logs.
2323 if(embeddedScts) {
2324 CFArrayForEach(embeddedScts, ^(const void *value){
2325 bool validLogAtVerifyTime = false;
2326 CFStringRef operator = get_valid_sct_operator(value, 1, precertEntry, pvc->verifyTime, SecCertificateNotValidBefore(leafCert), trustedLogs, &validLogAtVerifyTime);
2327 if(operator) CFSetAddValue(operatorsValidatingEmbeddedScts, operator);
2328 if(validLogAtVerifyTime) atLeastOneValidAtVerifyTime = true;
2329 });
2330 }
2331
2332 if(builderScts) {
2333 CFArrayForEach(builderScts, ^(const void *value){
2334 bool validLogAtVerifyTime = false;
2335 CFStringRef operator = get_valid_sct_operator(value, 0, x509Entry, pvc->verifyTime, SecCertificateNotValidBefore(leafCert), trustedLogs, &validLogAtVerifyTime);
2336 if(operator) CFSetAddValue(operatorsValidatingExternalScts, operator);
2337 if(validLogAtVerifyTime) atLeastOneValidAtVerifyTime = true;
2338 });
2339 }
2340
2341 if(ocspScts) {
2342 CFArrayForEach(ocspScts, ^(const void *value){
2343 bool validLogAtVerifyTime = false;
2344 CFStringRef operator = get_valid_sct_operator(value, 0, x509Entry, pvc->verifyTime, SecCertificateNotValidBefore(leafCert), trustedLogs, &validLogAtVerifyTime);
2345 if(operator) CFSetAddValue(operatorsValidatingExternalScts, operator);
2346 if(validLogAtVerifyTime) atLeastOneValidAtVerifyTime = true;
2347 });
2348 }
2349 }
2350
2351 /* We now have 2 sets of operators that validated those SCTS, count them and make a final decision.
2352 Current Policy:
2353 is_ct = (A1 OR A2) AND B.
2354
2355 A1: 2+ to 5+ SCTs from the cert from independent logs valid at issuance time
2356 (operatorsValidatingEmbeddedScts)
2357 A2: 2+ SCTs from external sources (OCSP stapled response and TLS extension)
2358 from independent logs valid at verify time. (operatorsValidatingExternalScts)
2359 B: All least one SCTs from a log valid at verify time.
2360
2361 Policy is based on: https://docs.google.com/viewer?a=v&pid=sites&srcid=ZGVmYXVsdGRvbWFpbnxjZXJ0aWZpY2F0ZXRyYW5zcGFyZW5jeXxneDo0ODhjNGRlOTIyMzYwNTcz
2362 with one difference: we consider SCTs from OCSP and TLS extensions as a whole.
2363 It sounds like this is what Google will eventually do, per:
2364 https://groups.google.com/forum/?fromgroups#!topic/certificate-transparency/VdXuzA3TLWY
2365
2366 */
2367
2368 SecCFCalendarDoWithZuluCalendar(^(CFCalendarRef zuluCalendar) {
2369 int _lifetime;
2370 CFCalendarGetComponentDifference(zuluCalendar,
2371 SecCertificateNotValidBefore(leafCert),
2372 SecCertificateNotValidAfter(leafCert),
2373 0, "M", &_lifetime);
2374 lifetime = _lifetime;
2375 });
2376
2377 CFIndex requiredEmbeddedSctsCount;
2378
2379 if (lifetime < 15) {
2380 requiredEmbeddedSctsCount = 2;
2381 } else if (lifetime <= 27) {
2382 requiredEmbeddedSctsCount = 3;
2383 } else if (lifetime <= 39) {
2384 requiredEmbeddedSctsCount = 4;
2385 } else {
2386 requiredEmbeddedSctsCount = 5;
2387 }
2388
2389 pvc->is_ct = ((CFSetGetCount(operatorsValidatingEmbeddedScts) >= requiredEmbeddedSctsCount) ||
2390 (CFSetGetCount(operatorsValidatingExternalScts) >= 2)
2391 ) && atLeastOneValidAtVerifyTime;
2392
2393 out:
2394
2395 CFReleaseSafe(operatorsValidatingEmbeddedScts);
2396 CFReleaseSafe(operatorsValidatingExternalScts);
2397 CFReleaseSafe(builderScts);
2398 CFReleaseSafe(embeddedScts);
2399 CFReleaseSafe(ocspScts);
2400 CFReleaseSafe(precertEntry);
2401 CFReleaseSafe(trustedLogs);
2402 CFReleaseSafe(x509Entry);
2403 }
2404
2405 static void SecPolicyCheckCertificatePolicyOid(SecPVCRef pvc, CFStringRef key)
2406 {
2407 CFIndex ix, count = SecPVCGetCertificateCount(pvc);
2408 SecPolicyRef policy = SecPVCGetPolicy(pvc);
2409 CFTypeRef value = CFDictionaryGetValue(policy->_options, key);
2410 DERItem key_value;
2411 key_value.data = NULL;
2412 key_value.length = 0;
2413
2414 if (CFGetTypeID(value) == CFDataGetTypeID())
2415 {
2416 CFDataRef key_data = (CFDataRef)value;
2417 key_value.data = (DERByte *)CFDataGetBytePtr(key_data);
2418 key_value.length = (DERSize)CFDataGetLength(key_data);
2419
2420 for (ix = 0; ix < count; ix++) {
2421 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix);
2422 policy_set_t policies = policies_for_cert(cert);
2423
2424 if (policy_set_contains(policies, &key_value)) {
2425 return;
2426 }
2427 }
2428 SecPVCSetResult(pvc, key, 0, kCFBooleanFalse);
2429 }
2430 }
2431
2432
2433 static void SecPolicyCheckRevocation(SecPVCRef pvc,
2434 CFStringRef key) {
2435 SecPVCSetCheckRevocation(pvc);
2436 }
2437
2438 static void SecPolicyCheckRevocationResponseRequired(SecPVCRef pvc,
2439 CFStringRef key) {
2440 SecPVCSetCheckRevocationResponseRequired(pvc);
2441 }
2442
2443 static void SecPolicyCheckNoNetworkAccess(SecPVCRef pvc,
2444 CFStringRef key) {
2445 SecPathBuilderSetCanAccessNetwork(pvc->builder, false);
2446 }
2447
2448 // MARK: -
2449 // MARK: SecRVCRef
2450 /********************************************************
2451 ****************** SecRVCRef Functions *****************
2452 ********************************************************/
2453
2454 const CFAbsoluteTime kSecDefaultOCSPResponseTTL = 24.0 * 60.0 * 60.0;
2455
2456 /* Revocation verification context. */
2457 struct OpaqueSecRVC {
2458 /* Will contain the response data. */
2459 asynchttp_t http;
2460
2461 /* Pointer to the pvc for this revocation check. */
2462 SecPVCRef pvc;
2463
2464 /* The ocsp request we send to each responder. */
2465 SecOCSPRequestRef ocspRequest;
2466
2467 /* The freshest response we received so far, from stapling or cache or responder. */
2468 SecOCSPResponseRef ocspResponse;
2469
2470 /* The best validated candidate single response we received so far, from stapling or cache or responder. */
2471 SecOCSPSingleResponseRef ocspSingleResponse;
2472
2473 /* Index of cert in pvc that this RVC is for 0 = leaf, etc. */
2474 CFIndex certIX;
2475
2476 /* Index in array returned by SecCertificateGetOCSPResponders() for current
2477 responder. */
2478 CFIndex responderIX;
2479
2480 /* URL of current responder. */
2481 CFURLRef responder;
2482
2483 /* Date until which this revocation status is valid. */
2484 CFAbsoluteTime nextUpdate;
2485
2486 bool done;
2487 };
2488 typedef struct OpaqueSecRVC *SecRVCRef;
2489
2490 static void SecRVCDelete(SecRVCRef rvc) {
2491 secdebug("alloc", "%p", rvc);
2492 asynchttp_free(&rvc->http);
2493 SecOCSPRequestFinalize(rvc->ocspRequest);
2494 if (rvc->ocspResponse) {
2495 SecOCSPResponseFinalize(rvc->ocspResponse);
2496 rvc->ocspResponse = NULL;
2497 if (rvc->ocspSingleResponse) {
2498 SecOCSPSingleResponseDestroy(rvc->ocspSingleResponse);
2499 rvc->ocspSingleResponse = NULL;
2500 }
2501 }
2502 }
2503
2504 /* Return the next responder we should contact for this rvc or NULL if we
2505 exhausted them all. */
2506 static CFURLRef SecRVCGetNextResponder(SecRVCRef rvc) {
2507 SecCertificateRef cert = SecPVCGetCertificateAtIndex(rvc->pvc, rvc->certIX);
2508 CFArrayRef ocspResponders = SecCertificateGetOCSPResponders(cert);
2509 if (ocspResponders) {
2510 CFIndex responderCount = CFArrayGetCount(ocspResponders);
2511 while (rvc->responderIX < responderCount) {
2512 CFURLRef responder = CFArrayGetValueAtIndex(ocspResponders, rvc->responderIX);
2513 rvc->responderIX++;
2514 CFStringRef scheme = CFURLCopyScheme(responder);
2515 if (scheme) {
2516 /* We only support http and https responders currently. */
2517 bool valid_responder = (CFEqual(CFSTR("http"), scheme) ||
2518 CFEqual(CFSTR("https"), scheme));
2519 CFRelease(scheme);
2520 if (valid_responder)
2521 return responder;
2522 }
2523 }
2524 }
2525 return NULL;
2526 }
2527
2528 /* Fire off an async http request for this certs revocation status, return
2529 false if request was queued, true if we're done. */
2530 static bool SecRVCFetchNext(SecRVCRef rvc) {
2531 while ((rvc->responder = SecRVCGetNextResponder(rvc))) {
2532 CFDataRef request = SecOCSPRequestGetDER(rvc->ocspRequest);
2533 if (!request)
2534 goto errOut;
2535
2536 secdebug("ocsp", "Sending http ocsp request for cert %ld", rvc->certIX);
2537 if (!asyncHttpPost(rvc->responder, request, &rvc->http)) {
2538 /* Async request was posted, wait for reply. */
2539 return false;
2540 }
2541 }
2542
2543 errOut:
2544 rvc->done = true;
2545 return true;
2546 }
2547
2548 /* Process a verified ocsp response for a given cert. Return true if the
2549 certificate status was obtained. */
2550 static bool SecOCSPSingleResponseProcess(SecOCSPSingleResponseRef this,
2551 SecRVCRef rvc) {
2552 bool processed;
2553 switch (this->certStatus) {
2554 case CS_Good:
2555 secdebug("ocsp", "CS_Good for cert %" PRIdCFIndex, rvc->certIX);
2556 /* @@@ Mark cert as valid until a given date (nextUpdate if we have one)
2557 in the info dictionary. */
2558 //cert.revokeCheckGood(true);
2559 rvc->nextUpdate = this->nextUpdate == NULL_TIME ? this->thisUpdate + kSecDefaultOCSPResponseTTL : this->nextUpdate;
2560 processed = true;
2561 break;
2562 case CS_Revoked:
2563 secdebug("ocsp", "CS_Revoked for cert %" PRIdCFIndex, rvc->certIX);
2564 /* @@@ Mark cert as revoked (with reason) at revocation date in
2565 the info dictionary, or perhaps we should use a different key per
2566 reason? That way a client using exceptions can ignore some but
2567 not all reasons. */
2568 SInt32 reason = this->crlReason;
2569 CFNumberRef cfreason = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &reason);
2570 SecPVCSetResultForced(rvc->pvc, kSecPolicyCheckRevocation, rvc->certIX,
2571 cfreason, true);
2572 if (rvc->pvc && rvc->pvc->info) {
2573 /* make the revocation reason available in the trust result */
2574 CFDictionarySetValue(rvc->pvc->info, kSecTrustRevocationReason, cfreason);
2575 }
2576 CFRelease(cfreason);
2577 processed = true;
2578 break;
2579 case CS_Unknown:
2580 /* not an error, no per-cert status, nothing here */
2581 secdebug("ocsp", "CS_Unknown for cert %" PRIdCFIndex, rvc->certIX);
2582 processed = false;
2583 break;
2584 default:
2585 secdebug("ocsp", "BAD certStatus (%d) for cert %" PRIdCFIndex,
2586 (int)this->certStatus, rvc->certIX);
2587 processed = false;
2588 break;
2589 }
2590
2591 return processed;
2592 }
2593
2594 static void SecRVCUpdatePVC(SecRVCRef rvc) {
2595 if (rvc->ocspSingleResponse) {
2596 SecOCSPSingleResponseProcess(rvc->ocspSingleResponse, rvc);
2597 }
2598 if (rvc->ocspResponse) {
2599 rvc->nextUpdate = SecOCSPResponseGetExpirationTime(rvc->ocspResponse);
2600 }
2601 }
2602
2603 static bool SecOCSPResponseVerify(SecOCSPResponseRef ocspResponse, SecRVCRef rvc, CFAbsoluteTime verifyTime) {
2604 bool trusted;
2605 SecCertificatePathRef issuer = SecCertificatePathCopyFromParent(rvc->pvc->path, rvc->certIX + 1);
2606 SecCertificatePathRef signer = SecOCSPResponseCopySigner(ocspResponse, issuer);
2607 CFRelease(issuer);
2608
2609 if (signer) {
2610 if (signer == issuer) {
2611 /* We already know we trust issuer since it's the path we are
2612 trying to verify minus the leaf. */
2613 secdebug("ocsp", "ocsp responder: %@ response signed by issuer",
2614 rvc->responder);
2615 trusted = true;
2616 } else {
2617 secdebug("ocsp",
2618 "ocsp responder: %@ response signed by cert issued by issuer",
2619 rvc->responder);
2620 /* @@@ Now check that we trust signer. */
2621 const void *ocspSigner = SecPolicyCreateOCSPSigner();
2622 CFArrayRef policies = CFArrayCreate(kCFAllocatorDefault,
2623 &ocspSigner, 1, &kCFTypeArrayCallBacks);
2624 CFRelease(ocspSigner);
2625 struct OpaqueSecPVC ospvc;
2626 SecPVCInit(&ospvc, rvc->pvc->builder, policies, verifyTime);
2627 CFRelease(policies);
2628 SecPVCSetPath(&ospvc, signer, NULL);
2629 SecPVCLeafChecks(&ospvc);
2630 if (ospvc.result) {
2631 bool completed = SecPVCPathChecks(&ospvc);
2632 /* If completed is false we are waiting for a callback, this
2633 shouldn't happen since we aren't asking for details, no
2634 revocation checking is done. */
2635 if (!completed) {
2636 ocspdErrorLog("SecPVCPathChecks unexpectedly started "
2637 "background job!");
2638 /* @@@ assert() or abort here perhaps? */
2639 }
2640 }
2641 if (ospvc.result) {
2642 secdebug("ocsp", "response satisfies ocspSigner policy (%@)",
2643 rvc->responder);
2644 trusted = true;
2645 } else {
2646 /* @@@ We don't trust the cert so don't use this response. */
2647 ocspdErrorLog("ocsp response signed by certificate which "
2648 "does not satisfy ocspSigner policy");
2649 trusted = false;
2650 }
2651 SecPVCDelete(&ospvc);
2652 }
2653
2654 CFRelease(signer);
2655 } else {
2656 /* @@@ No signer found for this ocsp response, discard it. */
2657 secdebug("ocsp", "ocsp responder: %@ no signer found for response",
2658 rvc->responder);
2659 trusted = false;
2660 }
2661
2662 #if DUMP_OCSPRESPONSES
2663 char buf[40];
2664 snprintf(buf, 40, "/tmp/ocspresponse%ld%s.der",
2665 rvc->certIX, (trusted ? "t" : "u"));
2666 secdumpdata(ocspResponse->data, buf);
2667 #endif
2668
2669 return trusted;
2670 }
2671
2672 static void SecRVCConsumeOCSPResponse(SecRVCRef rvc, SecOCSPResponseRef ocspResponse /*CF_CONSUMED*/, CFTimeInterval maxAge, bool updateCache) {
2673 SecOCSPSingleResponseRef sr = NULL;
2674 require_quiet(ocspResponse, errOut);
2675 SecOCSPResponseStatus orStatus = SecOCSPGetResponseStatus(ocspResponse);
2676 require_action_quiet(orStatus == kSecOCSPSuccess, errOut,
2677 secdebug("ocsp", "responder: %@ returned status: %d", rvc->responder, orStatus));
2678 require_action_quiet(sr = SecOCSPResponseCopySingleResponse(ocspResponse, rvc->ocspRequest), errOut,
2679 secdebug("ocsp", "ocsp responder: %@ did not include status of requested cert", rvc->responder));
2680 // Check if this response is fresher than any (cached) response we might still have in the rvc.
2681 require_quiet(!rvc->ocspSingleResponse || rvc->ocspSingleResponse->thisUpdate < sr->thisUpdate, errOut);
2682
2683 CFAbsoluteTime verifyTime = CFAbsoluteTimeGetCurrent();
2684 /* TODO: If the responder doesn't have the ocsp-nocheck extension we should
2685 check whether the leaf was revoked (we are already checking the rest of
2686 the chain). */
2687 /* Check the OCSP response signature and verify the response. */
2688 require_quiet(SecOCSPResponseVerify(ocspResponse, rvc,
2689 sr->certStatus == CS_Revoked ? SecOCSPResponseProducedAt(ocspResponse) : verifyTime), errOut);
2690
2691 // If we get here, we have a properly signed ocsp response
2692 // but we haven't checked dates yet.
2693
2694 bool sr_valid = SecOCSPSingleResponseCalculateValidity(sr, kSecDefaultOCSPResponseTTL, verifyTime);
2695 if (sr->certStatus == CS_Good) {
2696 // Side effect of SecOCSPResponseCalculateValidity sets ocspResponse->expireTime
2697 require_quiet(sr_valid && SecOCSPResponseCalculateValidity(ocspResponse, maxAge, kSecDefaultOCSPResponseTTL, verifyTime), errOut);
2698 } else if (sr->certStatus == CS_Revoked) {
2699 // Expire revoked responses when the subject certificate itself expires.
2700 ocspResponse->expireTime = SecCertificateNotValidAfter(SecPVCGetCertificateAtIndex(rvc->pvc, rvc->certIX));
2701 }
2702
2703 // Ok we like the new response, let's toss the old one.
2704 if (updateCache)
2705 SecOCSPCacheReplaceResponse(rvc->ocspResponse, ocspResponse, rvc->responder, verifyTime);
2706
2707 if (rvc->ocspResponse) SecOCSPResponseFinalize(rvc->ocspResponse);
2708 rvc->ocspResponse = ocspResponse;
2709 ocspResponse = NULL;
2710
2711 if (rvc->ocspSingleResponse) SecOCSPSingleResponseDestroy(rvc->ocspSingleResponse);
2712 rvc->ocspSingleResponse = sr;
2713 sr = NULL;
2714
2715 rvc->done = sr_valid;
2716
2717 errOut:
2718 if (sr) SecOCSPSingleResponseDestroy(sr);
2719 if (ocspResponse) SecOCSPResponseFinalize(ocspResponse);
2720 }
2721
2722 /* Callback from async http code after an ocsp response has been received. */
2723 static void SecOCSPFetchCompleted(asynchttp_t *http, CFTimeInterval maxAge) {
2724 SecRVCRef rvc = (SecRVCRef)http->info;
2725 SecPVCRef pvc = rvc->pvc;
2726 SecOCSPResponseRef ocspResponse = NULL;
2727 if (http->response) {
2728 CFDataRef data = CFHTTPMessageCopyBody(http->response);
2729 if (data) {
2730 /* Parse the returned data as if it's an ocspResponse. */
2731 ocspResponse = SecOCSPResponseCreate(data);
2732 CFRelease(data);
2733 }
2734 }
2735
2736 SecRVCConsumeOCSPResponse(rvc, ocspResponse, maxAge, true);
2737 // TODO: maybe we should set the cache-control: false in the http header and try again if the response is stale
2738
2739 if (!rvc->done) {
2740 /* Clear the data for the next response. */
2741 asynchttp_free(http);
2742 SecRVCFetchNext(rvc);
2743 }
2744
2745 if (rvc->done) {
2746 SecRVCUpdatePVC(rvc);
2747 SecRVCDelete(rvc);
2748 if (!--pvc->asyncJobCount) {
2749 SecPathBuilderStep(pvc->builder);
2750 }
2751 }
2752 }
2753
2754 static void SecRVCInit(SecRVCRef rvc, SecPVCRef pvc, CFIndex certIX) {
2755 secdebug("alloc", "%p", rvc);
2756 rvc->pvc = pvc;
2757 rvc->certIX = certIX;
2758 rvc->http.queue = SecPathBuilderGetQueue(pvc->builder);
2759 rvc->http.token = SecPathBuilderCopyClientAuditToken(pvc->builder);
2760 rvc->http.completed = SecOCSPFetchCompleted;
2761 rvc->http.info = rvc;
2762 rvc->ocspRequest = NULL;
2763 rvc->responderIX = 0;
2764 rvc->responder = NULL;
2765 rvc->nextUpdate = NULL_TIME;
2766 rvc->ocspResponse = NULL;
2767 rvc->ocspSingleResponse = NULL;
2768 rvc->done = false;
2769 }
2770
2771
2772 static bool SecPVCCheckRevocation(SecPVCRef pvc) {
2773 secdebug("ocsp", "checking revocation");
2774 CFIndex certIX, certCount = SecPVCGetCertificateCount(pvc);
2775 bool completed = true;
2776 if (certCount <= 1) {
2777 /* Can't verify without an issuer; we're done */
2778 return completed;
2779 }
2780 if (!SecPVCIsAnchored(pvc)) {
2781 /* We can't check revocation for chains without a trusted anchor. */
2782 return completed;
2783 }
2784 certCount--;
2785
2786 #if 0
2787 /* TODO: Implement getting this value from the client.
2788 Optional responder passed in though policy. */
2789 CFURLRef localResponder = NULL;
2790 /* Generate a nonce in outgoing request if true. */
2791 bool genNonce = false;
2792 /* Require a nonce in response if true. */
2793 bool requireRespNonce = false;
2794 bool cacheReadDisable = false;
2795 bool cacheWriteDisable = false;
2796 #endif
2797
2798 if (pvc->rvcs) {
2799 /* We have done revocation checking already, we're done. */
2800 secdebug("ocsp", "Not rechecking revocation");
2801 return completed;
2802 }
2803
2804 /* Setup things so we check revocation status of all certs except the
2805 anchor. */
2806 pvc->rvcs = calloc(sizeof(struct OpaqueSecRVC), certCount);
2807
2808 #if 0
2809 /* Lookup cached revocation data for each certificate. */
2810 for (certIX = 0; certIX < certCount; ++certIX) {
2811 SecCertificateRef cert = SecPVCGetCertificateAtIndex(rvc->pvc, rvc->certIX);
2812 CFArrayRef ocspResponders = SecCertificateGetOCSPResponders(cert);
2813 if (ocspResponders) {
2814 /* First look though passed in ocsp responses. */
2815 //SecPVCGetOCSPResponseForCertificateAtIndex(pvc, ix, singleResponse);
2816
2817 /* Then look though shared cache (we don't care which responder
2818 something came from here). */
2819 CFDataRef ocspResponse = SecOCSPCacheCopyMatching(SecCertIDRef certID, NULL);
2820
2821 /* Now let's parse the response. */
2822 if (decodeOCSPResponse(ocspResp)) {
2823 secdebug("ocsp", "response ok: %@", ocspResp);
2824 } else {
2825 secdebug("ocsp", "response bad: %@", ocspResp);
2826 /* ocsp response not ok. */
2827 if (!SecPVCSetResultForced(pvc, key, ix, kCFBooleanFalse, true))
2828 return completed;
2829 }
2830 CFReleaseSafe(ocspResp);
2831 } else {
2832 /* Check if certificate has any crl distributionPoints. */
2833 CFArrayRef distributionPoints = SecCertificateGetCRLDistributionPoints(cert);
2834 if (distributionPoints) {
2835 /* Look for a cached CRL and potentially delta CRL for this certificate. */
2836 }
2837 }
2838 }
2839 #endif
2840
2841 /* Note that if we are multi threaded and a job completes after it
2842 is started but before we return from this function, we don't want
2843 a callback to decrement asyncJobCount to zero before we finish issuing
2844 all the jobs. To avoid this we pretend we issued certCount async jobs,
2845 and decrement pvc->asyncJobCount for each cert that we don't start a
2846 background fetch for. */
2847 pvc->asyncJobCount = (unsigned int) certCount;
2848
2849 /* Loop though certificates again and issue an ocsp fetch if the
2850 revocation status checking isn't done yet. */
2851 for (certIX = 0; certIX < certCount; ++certIX) {
2852 secdebug("ocsp", "checking revocation for cert: %ld", certIX);
2853 SecRVCRef rvc = &((SecRVCRef)pvc->rvcs)[certIX];
2854 SecRVCInit(rvc, pvc, certIX);
2855 if (rvc->done)
2856 continue;
2857
2858 SecCertificateRef cert = SecPVCGetCertificateAtIndex(rvc->pvc,
2859 rvc->certIX);
2860 /* The certIX + 1 is ok here since certCount is always at least 1
2861 less than the actual number of certs. */
2862 SecCertificateRef issuer = SecPVCGetCertificateAtIndex(rvc->pvc,
2863 rvc->certIX + 1);
2864
2865 rvc->ocspRequest = SecOCSPRequestCreate(cert, issuer);
2866
2867 /* Get stapled OCSP responses */
2868 CFArrayRef ocspResponsesData = SecPathBuilderCopyOCSPResponses(pvc->builder);
2869
2870 /* If we have any OCSP stapled responses, check those first */
2871 if(ocspResponsesData) {
2872 secdebug("ocsp", "Checking stapled responses for cert %ld", certIX);
2873 CFArrayForEach(ocspResponsesData, ^(const void *value) {
2874 /* TODO: Should the builder already have the appropriate SecOCSPResponseRef ? */
2875 SecOCSPResponseRef ocspResponse = SecOCSPResponseCreate(value);
2876 SecRVCConsumeOCSPResponse(rvc, ocspResponse, NULL_TIME, false);
2877 });
2878 CFRelease(ocspResponsesData);
2879 }
2880
2881 /* Then check the cached response */
2882 secdebug("ocsp", "Checking cached responses for cert %ld", certIX);
2883 SecRVCConsumeOCSPResponse(rvc, SecOCSPCacheCopyMatching(rvc->ocspRequest, NULL), NULL_TIME, false);
2884
2885 /* Unless we successfully checked the revocation status of this cert
2886 based on the cache or stapled responses, attempt to fire off an async http request
2887 for this cert's revocation status. */
2888 bool fetch_done = true;
2889 if (rvc->done || !SecPathBuilderCanAccessNetwork(pvc->builder) ||
2890 (fetch_done = SecRVCFetchNext(rvc))) {
2891 /* We got a cache hit or we aren't allowed to access the network,
2892 or the async http post failed. */
2893 SecRVCUpdatePVC(rvc);
2894 SecRVCDelete(rvc);
2895 /* We didn't really start a background job for this cert. */
2896 pvc->asyncJobCount--;
2897 } else if (!fetch_done) {
2898 /* We started at least one background fetch. */
2899 completed = false;
2900 }
2901 }
2902
2903 /* Return false if we started any background jobs. */
2904 /* We can't just return !pvc->asyncJobCount here, since if we started any
2905 jobs the completion callback will be called eventually and it will call
2906 SecPathBuilderStep(). If for some reason everything completed before we
2907 get here we still want the outer SecPathBuilderStep() to terminate so we
2908 keep track of whether we started any jobs and return false if so. */
2909 return completed;
2910 }
2911
2912
2913 void SecPolicyServerInitalize(void) {
2914 gSecPolicyLeafCallbacks = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
2915 &kCFTypeDictionaryKeyCallBacks, NULL);
2916 gSecPolicyPathCallbacks = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
2917 &kCFTypeDictionaryKeyCallBacks, NULL);
2918
2919 CFDictionaryAddValue(gSecPolicyPathCallbacks,
2920 kSecPolicyCheckBasicCertificateProcessing,
2921 SecPolicyCheckBasicCertificateProcessing);
2922 CFDictionaryAddValue(gSecPolicyPathCallbacks,
2923 kSecPolicyCheckCriticalExtensions,
2924 SecPolicyCheckCriticalExtensions);
2925 CFDictionaryAddValue(gSecPolicyPathCallbacks,
2926 kSecPolicyCheckIdLinkage,
2927 SecPolicyCheckIdLinkage);
2928 CFDictionaryAddValue(gSecPolicyLeafCallbacks,
2929 kSecPolicyCheckKeyUsage,
2930 SecPolicyCheckKeyUsage);
2931 CFDictionaryAddValue(gSecPolicyLeafCallbacks,
2932 kSecPolicyCheckExtendedKeyUsage,
2933 SecPolicyCheckExtendedKeyUsage);
2934 CFDictionaryAddValue(gSecPolicyLeafCallbacks,
2935 kSecPolicyCheckBasicContraints,
2936 SecPolicyCheckBasicContraints);
2937 CFDictionaryAddValue(gSecPolicyLeafCallbacks,
2938 kSecPolicyCheckNonEmptySubject,
2939 SecPolicyCheckNonEmptySubject);
2940 CFDictionaryAddValue(gSecPolicyLeafCallbacks,
2941 kSecPolicyCheckQualifiedCertStatements,
2942 SecPolicyCheckQualifiedCertStatements);
2943 CFDictionaryAddValue(gSecPolicyLeafCallbacks,
2944 kSecPolicyCheckSSLHostname,
2945 SecPolicyCheckSSLHostname);
2946 CFDictionaryAddValue(gSecPolicyLeafCallbacks,
2947 kSecPolicyCheckEmail,
2948 SecPolicyCheckEmail);
2949 CFDictionaryAddValue(gSecPolicyPathCallbacks,
2950 kSecPolicyCheckValidIntermediates,
2951 SecPolicyCheckValidIntermediates);
2952 CFDictionaryAddValue(gSecPolicyLeafCallbacks,
2953 kSecPolicyCheckValidLeaf,
2954 SecPolicyCheckValidLeaf);
2955 CFDictionaryAddValue(gSecPolicyPathCallbacks,
2956 kSecPolicyCheckValidRoot,
2957 SecPolicyCheckValidRoot);
2958 CFDictionaryAddValue(gSecPolicyPathCallbacks,
2959 kSecPolicyCheckIssuerCommonName,
2960 SecPolicyCheckIssuerCommonName);
2961 CFDictionaryAddValue(gSecPolicyLeafCallbacks,
2962 kSecPolicyCheckSubjectCommonNamePrefix,
2963 SecPolicyCheckSubjectCommonNamePrefix);
2964 CFDictionaryAddValue(gSecPolicyLeafCallbacks,
2965 kSecPolicyCheckSubjectCommonName,
2966 SecPolicyCheckSubjectCommonName);
2967 CFDictionaryAddValue(gSecPolicyLeafCallbacks,
2968 kSecPolicyCheckNotValidBefore,
2969 SecPolicyCheckNotValidBefore);
2970 CFDictionaryAddValue(gSecPolicyPathCallbacks,
2971 kSecPolicyCheckChainLength,
2972 SecPolicyCheckChainLength);
2973 CFDictionaryAddValue(gSecPolicyPathCallbacks,
2974 kSecPolicyCheckAnchorSHA1,
2975 SecPolicyCheckAnchorSHA1);
2976 CFDictionaryAddValue(gSecPolicyPathCallbacks,
2977 kSecPolicyCheckIntermediateSPKISHA256,
2978 SecPolicyCheckIntermediateSPKISHA256);
2979 CFDictionaryAddValue(gSecPolicyPathCallbacks,
2980 kSecPolicyCheckAnchorApple,
2981 SecPolicyCheckAnchorApple);
2982 CFDictionaryAddValue(gSecPolicyLeafCallbacks,
2983 kSecPolicyCheckSubjectOrganization,
2984 SecPolicyCheckSubjectOrganization);
2985 CFDictionaryAddValue(gSecPolicyLeafCallbacks,
2986 kSecPolicyCheckSubjectOrganizationalUnit,
2987 SecPolicyCheckSubjectOrganizationalUnit);
2988 CFDictionaryAddValue(gSecPolicyLeafCallbacks,
2989 kSecPolicyCheckEAPTrustedServerNames,
2990 SecPolicyCheckEAPTrustedServerNames);
2991 CFDictionaryAddValue(gSecPolicyLeafCallbacks,
2992 kSecPolicyCheckSubjectCommonNameTEST,
2993 SecPolicyCheckSubjectCommonNameTEST);
2994 CFDictionaryAddValue(gSecPolicyLeafCallbacks,
2995 kSecPolicyCheckRevocation,
2996 SecPolicyCheckRevocation);
2997 CFDictionaryAddValue(gSecPolicyLeafCallbacks,
2998 kSecPolicyCheckRevocationResponseRequired,
2999 SecPolicyCheckRevocationResponseRequired);
3000 CFDictionaryAddValue(gSecPolicyLeafCallbacks,
3001 kSecPolicyCheckNoNetworkAccess,
3002 SecPolicyCheckNoNetworkAccess);
3003 CFDictionaryAddValue(gSecPolicyLeafCallbacks,
3004 kSecPolicyCheckBlackListedLeaf,
3005 SecPolicyCheckBlackListedLeaf);
3006 CFDictionaryAddValue(gSecPolicyLeafCallbacks,
3007 kSecPolicyCheckGrayListedLeaf,
3008 SecPolicyCheckGrayListedLeaf);
3009 CFDictionaryAddValue(gSecPolicyLeafCallbacks,
3010 kSecPolicyCheckLeafMarkerOid,
3011 SecPolicyCheckLeafMarkerOid);
3012 CFDictionaryAddValue(gSecPolicyPathCallbacks,
3013 kSecPolicyCheckIntermediateMarkerOid,
3014 SecPolicyCheckIntermediateMarkerOid);
3015 CFDictionaryAddValue(gSecPolicyLeafCallbacks,
3016 kSecPolicyCheckCertificatePolicy,
3017 SecPolicyCheckCertificatePolicyOid);
3018 }
3019
3020 /* AUDIT[securityd](done):
3021 array (ok) is a caller provided array, only its cf type has
3022 been checked.
3023 The options (ok) field ends up in policy->_options unchecked, so every access
3024 of policy->_options needs to be validated.
3025 */
3026 static SecPolicyRef SecPolicyCreateWithArray(CFArrayRef array) {
3027 SecPolicyRef policy = NULL;
3028 require_quiet(array && CFArrayGetCount(array) == 2, errOut);
3029 CFStringRef oid = (CFStringRef)CFArrayGetValueAtIndex(array, 0);
3030 require_quiet(isString(oid), errOut);
3031 CFDictionaryRef options = (CFDictionaryRef)CFArrayGetValueAtIndex(array, 1);
3032 require_quiet(isDictionary(options), errOut);
3033 policy = SecPolicyCreate(oid, options);
3034 errOut:
3035 return policy;
3036 }
3037
3038 /* AUDIT[securityd](done):
3039 value (ok) is an element in a caller provided array.
3040 */
3041 static void deserializePolicy(const void *value, void *context) {
3042 CFArrayRef policyArray = (CFArrayRef)value;
3043 if (isArray(policyArray)) {
3044 CFTypeRef deserializedPolicy = SecPolicyCreateWithArray(policyArray);
3045 if (deserializedPolicy) {
3046 CFArrayAppendValue((CFMutableArrayRef)context, deserializedPolicy);
3047 CFRelease(deserializedPolicy);
3048 }
3049 }
3050 }
3051
3052 /* AUDIT[securityd](done):
3053 serializedPolicies (ok) is a caller provided array, only its cf type has
3054 been checked.
3055 */
3056 CFArrayRef SecPolicyArrayDeserialize(CFArrayRef serializedPolicies) {
3057 CFMutableArrayRef result = NULL;
3058 require_quiet(isArray(serializedPolicies), errOut);
3059 CFIndex count = CFArrayGetCount(serializedPolicies);
3060 result = CFArrayCreateMutable(kCFAllocatorDefault, count, &kCFTypeArrayCallBacks);
3061 CFRange all_policies = { 0, count };
3062 CFArrayApplyFunction(serializedPolicies, all_policies, deserializePolicy, result);
3063 errOut:
3064 return result;
3065 }
3066
3067 // MARK: -
3068 // MARK: SecPVCRef
3069 /********************************************************
3070 ****************** SecPVCRef Functions *****************
3071 ********************************************************/
3072
3073 void SecPVCInit(SecPVCRef pvc, SecPathBuilderRef builder, CFArrayRef policies,
3074 CFAbsoluteTime verifyTime) {
3075 secdebug("alloc", "%p", pvc);
3076 // Weird logging policies crashes.
3077 //secdebug("policy", "%@", policies);
3078 pvc->builder = builder;
3079 pvc->policies = policies;
3080 if (policies)
3081 CFRetain(policies);
3082 pvc->verifyTime = verifyTime;
3083 pvc->path = NULL;
3084 pvc->details = NULL;
3085 pvc->info = NULL;
3086 pvc->valid_policy_tree = NULL;
3087 pvc->callbacks = NULL;
3088 pvc->policyIX = 0;
3089 pvc->rvcs = NULL;
3090 pvc->asyncJobCount = 0;
3091 pvc->check_revocation = false;
3092 pvc->response_required = false;
3093 pvc->optionally_ev = false;
3094 pvc->is_ev = false;
3095 pvc->result = true;
3096 }
3097
3098 static void SecPVCDeleteRVCs(SecPVCRef pvc) {
3099 secdebug("alloc", "%p", pvc);
3100 if (pvc->rvcs) {
3101 free(pvc->rvcs);
3102 pvc->rvcs = NULL;
3103 }
3104 }
3105
3106 void SecPVCDelete(SecPVCRef pvc) {
3107 secdebug("alloc", "%p", pvc);
3108 CFReleaseNull(pvc->policies);
3109 CFReleaseNull(pvc->details);
3110 CFReleaseNull(pvc->info);
3111 if (pvc->valid_policy_tree) {
3112 policy_tree_prune(&pvc->valid_policy_tree);
3113 }
3114 SecPVCDeleteRVCs(pvc);
3115 }
3116
3117 void SecPVCSetPath(SecPVCRef pvc, SecCertificatePathRef path,
3118 CF_CONSUMED CFArrayRef details) {
3119 secdebug("policy", "%@", path);
3120 if (pvc->path != path) {
3121 /* Changing path makes us clear the Revocation Verification Contexts */
3122 SecPVCDeleteRVCs(pvc);
3123 pvc->path = path;
3124 }
3125 pvc->details = details;
3126 CFReleaseNull(pvc->info);
3127 if (pvc->valid_policy_tree) {
3128 policy_tree_prune(&pvc->valid_policy_tree);
3129 }
3130 pvc->policyIX = 0;
3131 pvc->result = true;
3132 }
3133
3134 SecPolicyRef SecPVCGetPolicy(SecPVCRef pvc) {
3135 return (SecPolicyRef)CFArrayGetValueAtIndex(pvc->policies, pvc->policyIX);
3136 }
3137
3138 CFIndex SecPVCGetCertificateCount(SecPVCRef pvc) {
3139 return SecCertificatePathGetCount(pvc->path);
3140 }
3141
3142 SecCertificateRef SecPVCGetCertificateAtIndex(SecPVCRef pvc, CFIndex ix) {
3143 return SecCertificatePathGetCertificateAtIndex(pvc->path, ix);
3144 }
3145
3146 bool SecPVCIsCertificateAtIndexSelfSigned(SecPVCRef pvc, CFIndex ix) {
3147 return SecCertificatePathSelfSignedIndex(pvc->path) == ix;
3148 }
3149
3150 void SecPVCSetCheckRevocation(SecPVCRef pvc) {
3151 pvc->check_revocation = true;
3152 secdebug("ocsp", "deferred revocation checking enabled");
3153 }
3154
3155 void SecPVCSetCheckRevocationResponseRequired(SecPVCRef pvc) {
3156 pvc->response_required = true;
3157 secdebug("ocsp", "revocation response required");
3158 }
3159
3160 bool SecPVCIsAnchored(SecPVCRef pvc) {
3161 return SecCertificatePathIsAnchored(pvc->path);
3162 }
3163
3164 CFAbsoluteTime SecPVCGetVerifyTime(SecPVCRef pvc) {
3165 return pvc->verifyTime;
3166 }
3167
3168 /* AUDIT[securityd](done):
3169 policy->_options is a caller provided dictionary, only its cf type has
3170 been checked.
3171 */
3172 bool SecPVCSetResultForced(SecPVCRef pvc,
3173 CFStringRef key, CFIndex ix, CFTypeRef result, bool force) {
3174
3175 secdebug("policy", "cert[%d]: %@ =(%s)[%s]> %@", (int) ix, key,
3176 (pvc->callbacks == gSecPolicyLeafCallbacks ? "leaf"
3177 : (pvc->callbacks == gSecPolicyPathCallbacks ? "path"
3178 : "custom")),
3179 (force ? "force" : ""), result);
3180
3181 /* If this is not something the current policy cares about ignore
3182 this error and return true so our caller continues evaluation. */
3183 if (!force) {
3184 /* @@@ The right long term fix might be to check if none of the passed
3185 in policies contain this key, since not all checks are run for all
3186 policies. */
3187 SecPolicyRef policy = SecPVCGetPolicy(pvc);
3188 if (policy && !CFDictionaryContainsKey(policy->_options, key))
3189 return true;
3190 }
3191
3192 /* @@@ Check to see if the SecTrustSettings for the certificate in question
3193 tell us to ignore this error. */
3194 pvc->result = false;
3195 if (!pvc->details)
3196 return false;
3197
3198 CFMutableDictionaryRef detail =
3199 (CFMutableDictionaryRef)CFArrayGetValueAtIndex(pvc->details, ix);
3200
3201 /* Perhaps detail should have an array of results per key? As it stands
3202 in the case of multiple policy failures the last failure stands. */
3203 CFDictionarySetValue(detail, key, result);
3204
3205 return true;
3206 }
3207
3208 bool SecPVCSetResult(SecPVCRef pvc,
3209 CFStringRef key, CFIndex ix, CFTypeRef result) {
3210 return SecPVCSetResultForced(pvc, key, ix, result, false);
3211 }
3212
3213 /* AUDIT[securityd](done):
3214 key(ok) is a caller provided.
3215 value(ok, unused) is a caller provided.
3216 */
3217 static void SecPVCValidateKey(const void *key, const void *value,
3218 void *context) {
3219 SecPVCRef pvc = (SecPVCRef)context;
3220
3221 /* If our caller doesn't want full details and we failed earlier there is
3222 no point in doing additional checks. */
3223 if (!pvc->result && !pvc->details)
3224 return;
3225
3226 SecPolicyCheckFunction fcn = (SecPolicyCheckFunction)
3227 CFDictionaryGetValue(pvc->callbacks, key);
3228
3229 if (!fcn) {
3230 #if 0
3231 /* Why not to have optional policy checks rant:
3232 Not all keys are in all dictionaries anymore, so why not make checks
3233 optional? This way a client can ask for something and the server will
3234 do a best effort based on the supported flags. It works since they are
3235 synchronized now, but we need some debug checking here for now. */
3236 pvc->result = false;
3237 #endif
3238 if (pvc->callbacks == gSecPolicyLeafCallbacks) {
3239 if (!CFDictionaryContainsKey(gSecPolicyPathCallbacks, key)) {
3240 pvc->result = false;
3241 }
3242 } else if (pvc->callbacks == gSecPolicyPathCallbacks) {
3243 if (!CFDictionaryContainsKey(gSecPolicyLeafCallbacks, key)) {
3244 pvc->result = false;
3245 }
3246 } else {
3247 /* Non standard validation phase, nothing is optional. */
3248 pvc->result = false;
3249 }
3250 return;
3251 }
3252
3253 fcn(pvc, (CFStringRef)key);
3254 }
3255
3256 /* AUDIT[securityd](done):
3257 policy->_options is a caller provided dictionary, only its cf type has
3258 been checked.
3259 */
3260 bool SecPVCLeafChecks(SecPVCRef pvc) {
3261 pvc->result = true;
3262 CFArrayRef policies = pvc->policies;
3263 CFIndex ix, count = CFArrayGetCount(policies);
3264 for (ix = 0; ix < count; ++ix) {
3265 SecPolicyRef policy = (SecPolicyRef)CFArrayGetValueAtIndex(policies, ix);
3266 pvc->policyIX = ix;
3267 /* Validate all keys for all policies. */
3268 pvc->callbacks = gSecPolicyLeafCallbacks;
3269 CFDictionaryApplyFunction(policy->_options, SecPVCValidateKey, pvc);
3270 if (!pvc->result && !pvc->details)
3271 return pvc->result;
3272 }
3273
3274 return pvc->result;
3275 }
3276
3277 bool SecPVCParentCertificateChecks(SecPVCRef pvc, CFIndex ix) {
3278 /* Check stuff common to intermediate and anchors. */
3279 CFAbsoluteTime verifyTime = SecPVCGetVerifyTime(pvc);
3280 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix);
3281 bool is_anchor = (ix == SecPVCGetCertificateCount(pvc) - 1
3282 && SecPVCIsAnchored(pvc));
3283 if (!SecCertificateIsValid(cert, verifyTime)) {
3284 /* Certificate has expired. */
3285 if (!SecPVCSetResult(pvc, is_anchor ? kSecPolicyCheckValidRoot
3286 : kSecPolicyCheckValidIntermediates, ix, kCFBooleanFalse))
3287 goto errOut;
3288 }
3289
3290 if (is_anchor) {
3291 /* Perform anchor specific checks. */
3292 /* Don't think we have any of these. */
3293 } else {
3294 /* Perform intermediate specific checks. */
3295
3296 /* (k) */
3297 const SecCEBasicConstraints *bc =
3298 SecCertificateGetBasicConstraints(cert);
3299 if (!bc || !bc->isCA) {
3300 /* Basic constraints not present or not marked as isCA, illegal. */
3301 if (!SecPVCSetResultForced(pvc, kSecPolicyCheckBasicContraints,
3302 ix, kCFBooleanFalse, true))
3303 goto errOut;
3304 }
3305 /* Consider adding (l) max_path_length checking here. */
3306
3307 /* (n) If a key usage extension is present, verify that the keyCertSign bit is set. */
3308 SecKeyUsage keyUsage = SecCertificateGetKeyUsage(cert);
3309 if (keyUsage && !(keyUsage & kSecKeyUsageKeyCertSign)) {
3310 if (!SecPVCSetResultForced(pvc, kSecPolicyCheckKeyUsage,
3311 ix, kCFBooleanFalse, true))
3312 goto errOut;
3313 }
3314 }
3315
3316 errOut:
3317 return pvc->result;
3318 }
3319
3320 bool SecPVCBlackListedKeyChecks(SecPVCRef pvc, CFIndex ix) {
3321 /* Check stuff common to intermediate and anchors. */
3322
3323 SecOTAPKIRef otapkiRef = SecOTAPKICopyCurrentOTAPKIRef();
3324 if (NULL != otapkiRef)
3325 {
3326 CFSetRef blackListedKeys = SecOTAPKICopyBlackListSet(otapkiRef);
3327 CFRelease(otapkiRef);
3328 if (NULL != blackListedKeys)
3329 {
3330 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix);
3331 bool is_anchor = (ix == SecPVCGetCertificateCount(pvc) - 1
3332 && SecPVCIsAnchored(pvc));
3333 if (!is_anchor) {
3334 /* Check for blacklisted intermediates keys. */
3335 CFDataRef dgst = SecCertificateCopyPublicKeySHA1Digest(cert);
3336 if (dgst) {
3337 /* Check dgst against blacklist. */
3338 if (CFSetContainsValue(blackListedKeys, dgst)) {
3339 SecPVCSetResultForced(pvc, kSecPolicyCheckBlackListedKey,
3340 ix, kCFBooleanFalse, true);
3341 }
3342 CFRelease(dgst);
3343 }
3344 }
3345 CFRelease(blackListedKeys);
3346 return pvc->result;
3347 }
3348 }
3349 // Assume OK
3350 return true;
3351 }
3352
3353 bool SecPVCGrayListedKeyChecks(SecPVCRef pvc, CFIndex ix)
3354 {
3355 /* Check stuff common to intermediate and anchors. */
3356 SecOTAPKIRef otapkiRef = SecOTAPKICopyCurrentOTAPKIRef();
3357 if (NULL != otapkiRef)
3358 {
3359 CFSetRef grayListKeys = SecOTAPKICopyGrayList(otapkiRef);
3360 CFRelease(otapkiRef);
3361 if (NULL != grayListKeys)
3362 {
3363 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix);
3364 bool is_anchor = (ix == SecPVCGetCertificateCount(pvc) - 1
3365 && SecPVCIsAnchored(pvc));
3366 if (!is_anchor) {
3367 /* Check for gray listed intermediates keys. */
3368 CFDataRef dgst = SecCertificateCopyPublicKeySHA1Digest(cert);
3369 if (dgst) {
3370 /* Check dgst against gray list. */
3371 if (CFSetContainsValue(grayListKeys, dgst)) {
3372 SecPVCSetResultForced(pvc, kSecPolicyCheckGrayListedKey,
3373 ix, kCFBooleanFalse, true);
3374 }
3375 CFRelease(dgst);
3376 }
3377 }
3378 CFRelease(grayListKeys);
3379 return pvc->result;
3380 }
3381 }
3382 // Assume ok
3383 return true;
3384 }
3385
3386 /* AUDIT[securityd](done):
3387 policy->_options is a caller provided dictionary, only its cf type has
3388 been checked.
3389 */
3390 bool SecPVCPathChecks(SecPVCRef pvc) {
3391 secdebug("policy", "begin path: %@", pvc->path);
3392 bool completed = true;
3393 /* This needs to be initialized before we call any function that might call
3394 SecPVCSetResultForced(). */
3395 pvc->policyIX = 0;
3396 SecPolicyCheckIdLinkage(pvc, kSecPolicyCheckIdLinkage);
3397 if (pvc->result || pvc->details) {
3398 SecPolicyCheckBasicCertificateProcessing(pvc,
3399 kSecPolicyCheckBasicCertificateProcessing);
3400 }
3401
3402 CFArrayRef policies = pvc->policies;
3403 CFIndex count = CFArrayGetCount(policies);
3404 for (; pvc->policyIX < count; ++pvc->policyIX) {
3405 /* Validate all keys for all policies. */
3406 pvc->callbacks = gSecPolicyPathCallbacks;
3407 SecPolicyRef policy = SecPVCGetPolicy(pvc);
3408 CFDictionaryApplyFunction(policy->_options, SecPVCValidateKey, pvc);
3409 if (!pvc->result && !pvc->details)
3410 return completed;
3411 }
3412
3413 /* Check the things we can't check statically for the certificate path. */
3414 /* Critical Extensions, chainLength. */
3415
3416 /* Policy tests. */
3417 pvc->is_ev = false;
3418 if ((pvc->result || pvc->details) && pvc->optionally_ev) {
3419 bool pre_ev_check_result = pvc->result;
3420 SecPolicyCheckEV(pvc, kSecPolicyCheckExtendedValidation);
3421 pvc->is_ev = pvc->result;
3422 /* If ev checking failed, we still want to accept this chain
3423 as a non EV one, if it was valid as such. */
3424 pvc->result = pre_ev_check_result;
3425 }
3426 /* Check revocation only if the chain is valid so far. Then only check
3427 revocation if the client asked for it explicitly or is_ev is
3428 true. */
3429 if (pvc->result && (pvc->is_ev || pvc->check_revocation)) {
3430 completed = SecPVCCheckRevocation(pvc);
3431 }
3432
3433 /* Check for CT */
3434 if (pvc->result || pvc->details) {
3435 /* This call will set the value of pvc->is_ct, but won't change the result (pvc->result) */
3436 SecPolicyCheckCT(pvc, kSecPolicyCheckCertificateTransparency);
3437 }
3438
3439
3440 //errOut:
3441 secdebug("policy", "end %strusted completed: %d path: %@",
3442 (pvc->result ? "" : "not "), completed, pvc->path);
3443 return completed;
3444 }
3445
3446 /* This function returns 0 to indicate revocation checking was not completed
3447 for this certificate chain, otherwise return to date at which the first
3448 piece of revocation checking info we used expires. */
3449 CFAbsoluteTime SecPVCGetEarliestNextUpdate(SecPVCRef pvc) {
3450 CFIndex certIX, certCount = SecPVCGetCertificateCount(pvc);
3451 CFAbsoluteTime enu = 0;
3452 if (certCount <= 1 || !pvc->rvcs) {
3453 return enu;
3454 }
3455 certCount--;
3456
3457 for (certIX = 0; certIX < certCount; ++certIX) {
3458 SecRVCRef rvc = &((SecRVCRef)pvc->rvcs)[certIX];
3459 if (rvc->nextUpdate == 0) {
3460 if (certIX > 0) {
3461 /* We allow for CA certs to not be revocation checked if they
3462 have no ocspResponders to check against, but the leaf
3463 must be checked in order for us to claim we did revocation
3464 checking. */
3465 SecCertificateRef cert =
3466 SecPVCGetCertificateAtIndex(rvc->pvc, rvc->certIX);
3467 CFArrayRef ocspResponders = SecCertificateGetOCSPResponders(cert);
3468 if (!ocspResponders || CFArrayGetCount(ocspResponders) == 0) {
3469 /* We can't check this cert so we don't consider it a soft
3470 failure that we didn't. Ideally we should support crl
3471 checking and remove this workaround, since that more
3472 strict. */
3473 continue;
3474 }
3475 }
3476 secdebug("ocsp", "revocation checking soft failure for cert: %ld",
3477 certIX);
3478 enu = rvc->nextUpdate;
3479 break;
3480 }
3481 if (enu == 0 || rvc->nextUpdate < enu) {
3482 enu = rvc->nextUpdate;
3483 }
3484 #if 0
3485 /* Perhaps we don't want to do this since some policies might
3486 ignore the certificate expiration but still use revocation
3487 checking. */
3488
3489 /* Earliest certificate expiration date. */
3490 SecCertificateRef cert = SecPVCGetCertificateAtIndex(rvc->pvc, rvc->certIX);
3491 CFAbsoluteTime nva = SecCertificateNotValidAfter(cert);
3492 if (nva && (enu == 0 || nva < enu)
3493 enu = nva;
3494 #endif
3495 }
3496
3497 secdebug("ocsp", "revocation valid until: %lg", enu);
3498 return enu;
3499 }