]> git.saurik.com Git - apple/security.git/blob - OSX/sec/securityd/SecPolicyServer.c
Security-57337.50.23.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 if (CFDictionaryGetValue(value, kSecPolicyAppleAnchorAllowTestRootsOnProduction))
1087 flags |= kSecAppleTrustAnchorFlagsAllowNonProduction;
1088 }
1089
1090 bool foundMatch = SecIsAppleTrustAnchor(cert, flags);
1091
1092 if (!foundMatch)
1093 if (!SecPVCSetResult(pvc, kSecPolicyCheckAnchorApple, 0, kCFBooleanFalse))
1094 return;
1095
1096 return;
1097 }
1098
1099
1100 /* AUDIT[securityd](done):
1101 policy->_options is a caller provided dictionary, only its cf type has
1102 been checked.
1103 */
1104 static void SecPolicyCheckSubjectOrganization(SecPVCRef pvc,
1105 CFStringRef key) {
1106 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, 0);
1107 SecPolicyRef policy = SecPVCGetPolicy(pvc);
1108 CFStringRef org = (CFStringRef)CFDictionaryGetValue(policy->_options,
1109 key);
1110 if (!isString(org)) {
1111 /* @@@ We can't return an error here and making the evaluation fail
1112 won't help much either. */
1113 return;
1114 }
1115 CFArrayRef organization = SecCertificateCopyOrganization(cert);
1116 if (!organization || CFArrayGetCount(organization) != 1 ||
1117 !CFEqual(org, CFArrayGetValueAtIndex(organization, 0))) {
1118 /* Leaf Subject Organization mismatch. */
1119 SecPVCSetResult(pvc, key, 0, kCFBooleanFalse);
1120 }
1121 CFReleaseSafe(organization);
1122 }
1123
1124 static void SecPolicyCheckSubjectOrganizationalUnit(SecPVCRef pvc,
1125 CFStringRef key) {
1126 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, 0);
1127 SecPolicyRef policy = SecPVCGetPolicy(pvc);
1128 CFStringRef orgUnit = (CFStringRef)CFDictionaryGetValue(policy->_options,
1129 key);
1130 if (!isString(orgUnit)) {
1131 /* @@@ We can't return an error here and making the evaluation fail
1132 won't help much either. */
1133 return;
1134 }
1135 CFArrayRef organizationalUnit = SecCertificateCopyOrganizationalUnit(cert);
1136 if (!organizationalUnit || CFArrayGetCount(organizationalUnit) != 1 ||
1137 !CFEqual(orgUnit, CFArrayGetValueAtIndex(organizationalUnit, 0))) {
1138 /* Leaf Subject Organizational Unit mismatch. */
1139 SecPVCSetResult(pvc, key, 0, kCFBooleanFalse);
1140 }
1141 CFReleaseSafe(organizationalUnit);
1142 }
1143
1144 /* AUDIT[securityd](done):
1145 policy->_options is a caller provided dictionary, only its cf type has
1146 been checked.
1147 */
1148 static void SecPolicyCheckEAPTrustedServerNames(SecPVCRef pvc,
1149 CFStringRef key) {
1150 SecPolicyRef policy = SecPVCGetPolicy(pvc);
1151 CFArrayRef trustedServerNames = (CFArrayRef)
1152 CFDictionaryGetValue(policy->_options, key);
1153 /* No names specified means we accept any name. */
1154 if (!trustedServerNames)
1155 return;
1156 if (!isArray(trustedServerNames)) {
1157 /* @@@ We can't return an error here and making the evaluation fail
1158 won't help much either. */
1159 return;
1160 }
1161
1162 CFIndex tsnCount = CFArrayGetCount(trustedServerNames);
1163 SecCertificateRef leaf = SecPVCGetCertificateAtIndex(pvc, 0);
1164 bool dnsMatch = false;
1165 CFArrayRef dnsNames = SecCertificateCopyDNSNames(leaf);
1166 if (dnsNames) {
1167 CFIndex ix, count = CFArrayGetCount(dnsNames);
1168 // @@@ This is O(N^2) unfortunately we can't do better easily unless
1169 // we don't do wildcard matching. */
1170 for (ix = 0; !dnsMatch && ix < count; ++ix) {
1171 CFStringRef dns = (CFStringRef)CFArrayGetValueAtIndex(dnsNames, ix);
1172 CFIndex tix;
1173 for (tix = 0; tix < tsnCount; ++tix) {
1174 CFStringRef serverName =
1175 (CFStringRef)CFArrayGetValueAtIndex(trustedServerNames, tix);
1176 if (!isString(serverName)) {
1177 /* @@@ We can't return an error here and making the
1178 evaluation fail won't help much either. */
1179 CFReleaseSafe(dnsNames);
1180 return;
1181 }
1182 /* we purposefully reverse the arguments here such that dns names
1183 from the cert are matched against a server name list, where
1184 the server names list can contain wildcards and the dns name
1185 cannot. References: http://support.microsoft.com/kb/941123
1186 It's easy to find occurrences where people tried to use
1187 wildcard certificates and were told that those don't work
1188 in this context. */
1189 if (SecDNSMatch(dns, serverName)) {
1190 dnsMatch = true;
1191 break;
1192 }
1193 }
1194 }
1195 CFRelease(dnsNames);
1196 }
1197
1198 if (!dnsMatch) {
1199 /* Hostname mismatch or no hostnames found in certificate. */
1200 SecPVCSetResult(pvc, key, 0, kCFBooleanFalse);
1201 }
1202 }
1203
1204 static const unsigned char UTN_USERFirst_Hardware_Serial[][16] = {
1205 { 0xd8, 0xf3, 0x5f, 0x4e, 0xb7, 0x87, 0x2b, 0x2d, 0xab, 0x06, 0x92, 0xe3, 0x15, 0x38, 0x2f, 0xb0 },
1206 { 0x92, 0x39, 0xd5, 0x34, 0x8f, 0x40, 0xd1, 0x69, 0x5a, 0x74, 0x54, 0x70, 0xe1, 0xf2, 0x3f, 0x43 },
1207 { 0xb0, 0xb7, 0x13, 0x3e, 0xd0, 0x96, 0xf9, 0xb5, 0x6f, 0xae, 0x91, 0xc8, 0x74, 0xbd, 0x3a, 0xc0 },
1208 { 0xe9, 0x02, 0x8b, 0x95, 0x78, 0xe4, 0x15, 0xdc, 0x1a, 0x71, 0x0a, 0x2b, 0x88, 0x15, 0x44, 0x47 },
1209 { 0x39, 0x2a, 0x43, 0x4f, 0x0e, 0x07, 0xdf, 0x1f, 0x8a, 0xa3, 0x05, 0xde, 0x34, 0xe0, 0xc2, 0x29 },
1210 { 0x3e, 0x75, 0xce, 0xd4, 0x6b, 0x69, 0x30, 0x21, 0x21, 0x88, 0x30, 0xae, 0x86, 0xa8, 0x2a, 0x71 },
1211 { 0xd7, 0x55, 0x8f, 0xda, 0xf5, 0xf1, 0x10, 0x5b, 0xb2, 0x13, 0x28, 0x2b, 0x70, 0x77, 0x29, 0xa3 },
1212 { 0x04, 0x7e, 0xcb, 0xe9, 0xfc, 0xa5, 0x5f, 0x7b, 0xd0, 0x9e, 0xae, 0x36, 0xe1, 0x0c, 0xae, 0x1e },
1213 { 0xf5, 0xc8, 0x6a, 0xf3, 0x61, 0x62, 0xf1, 0x3a, 0x64, 0xf5, 0x4f, 0x6d, 0xc9, 0x58, 0x7c, 0x06 } };
1214
1215 static const unsigned char UTN_USERFirst_Hardware_Normalized_Issuer[] = {
1216 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55,
1217 0x53, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x02,
1218 0x55, 0x54, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x07, 0x13,
1219 0x0e, 0x53, 0x41, 0x4c, 0x54, 0x20, 0x4c, 0x41, 0x4b, 0x45, 0x20, 0x43,
1220 0x49, 0x54, 0x59, 0x31, 0x1e, 0x30, 0x1c, 0x06, 0x03, 0x55, 0x04, 0x0a,
1221 0x13, 0x15, 0x54, 0x48, 0x45, 0x20, 0x55, 0x53, 0x45, 0x52, 0x54, 0x52,
1222 0x55, 0x53, 0x54, 0x20, 0x4e, 0x45, 0x54, 0x57, 0x4f, 0x52, 0x4b, 0x31,
1223 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x18, 0x48, 0x54,
1224 0x54, 0x50, 0x3a, 0x2f, 0x2f, 0x57, 0x57, 0x57, 0x2e, 0x55, 0x53, 0x45,
1225 0x52, 0x54, 0x52, 0x55, 0x53, 0x54, 0x2e, 0x43, 0x4f, 0x4d, 0x31, 0x1f,
1226 0x30, 0x1d, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x16, 0x55, 0x54, 0x4e,
1227 0x2d, 0x55, 0x53, 0x45, 0x52, 0x46, 0x49, 0x52, 0x53, 0x54, 0x2d, 0x48,
1228 0x41, 0x52, 0x44, 0x57, 0x41, 0x52, 0x45
1229 };
1230 static const unsigned int UTN_USERFirst_Hardware_Normalized_Issuer_len = 151;
1231
1232
1233 static void SecPolicyCheckBlackListedLeaf(SecPVCRef pvc,
1234 CFStringRef key) {
1235 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, 0);
1236 CFDataRef issuer = cert ? SecCertificateGetNormalizedIssuerContent(cert) : NULL;
1237
1238 if (issuer && (CFDataGetLength(issuer) == (CFIndex)UTN_USERFirst_Hardware_Normalized_Issuer_len) &&
1239 (0 == memcmp(UTN_USERFirst_Hardware_Normalized_Issuer, CFDataGetBytePtr(issuer),
1240 UTN_USERFirst_Hardware_Normalized_Issuer_len)))
1241 {
1242 #if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE))
1243 CFDataRef serial = SecCertificateCopySerialNumber(cert, NULL);
1244 #else
1245 CFDataRef serial = SecCertificateCopySerialNumber(cert);
1246 #endif
1247
1248 if (serial) {
1249 CFIndex serial_length = CFDataGetLength(serial);
1250 const uint8_t *serial_ptr = CFDataGetBytePtr(serial);
1251
1252 while ((serial_length > 0) && (*serial_ptr == 0)) {
1253 serial_ptr++;
1254 serial_length--;
1255 }
1256
1257 if (serial_length == (CFIndex)sizeof(*UTN_USERFirst_Hardware_Serial)) {
1258 unsigned int i;
1259 for (i = 0; i < array_size(UTN_USERFirst_Hardware_Serial); i++)
1260 {
1261 if (0 == memcmp(UTN_USERFirst_Hardware_Serial[i],
1262 serial_ptr, sizeof(*UTN_USERFirst_Hardware_Serial)))
1263 {
1264 SecPVCSetResult(pvc, key, 0, kCFBooleanFalse);
1265 CFReleaseSafe(serial);
1266 return;
1267 }
1268 }
1269 }
1270 CFRelease(serial);
1271 }
1272 }
1273
1274 SecOTAPKIRef otapkiRef = SecOTAPKICopyCurrentOTAPKIRef();
1275 if (NULL != otapkiRef)
1276 {
1277 CFSetRef blackListedKeys = SecOTAPKICopyBlackListSet(otapkiRef);
1278 CFRelease(otapkiRef);
1279 if (NULL != blackListedKeys)
1280 {
1281 /* Check for blacklisted intermediates keys. */
1282 CFDataRef dgst = SecCertificateCopyPublicKeySHA1Digest(cert);
1283 if (dgst)
1284 {
1285 /* Check dgst against blacklist. */
1286 if (CFSetContainsValue(blackListedKeys, dgst))
1287 {
1288 SecPVCSetResult(pvc, key, 0, kCFBooleanFalse);
1289 }
1290 CFRelease(dgst);
1291 }
1292 CFRelease(blackListedKeys);
1293 }
1294 }
1295 }
1296
1297 static void SecPolicyCheckGrayListedLeaf(SecPVCRef pvc, CFStringRef key)
1298 {
1299 SecOTAPKIRef otapkiRef = SecOTAPKICopyCurrentOTAPKIRef();
1300 if (NULL != otapkiRef)
1301 {
1302 CFSetRef grayListedKeys = SecOTAPKICopyGrayList(otapkiRef);
1303 CFRelease(otapkiRef);
1304 if (NULL != grayListedKeys)
1305 {
1306 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, 0);
1307
1308 CFDataRef dgst = SecCertificateCopyPublicKeySHA1Digest(cert);
1309 if (dgst)
1310 {
1311 /* Check dgst against gray. */
1312 if (CFSetContainsValue(grayListedKeys, dgst))
1313 {
1314 SecPVCSetResult(pvc, key, 0, kCFBooleanFalse);
1315 }
1316 CFRelease(dgst);
1317 }
1318 CFRelease(grayListedKeys);
1319 }
1320 }
1321 }
1322
1323 static void SecPolicyCheckLeafMarkerOid(SecPVCRef pvc, CFStringRef key)
1324 {
1325 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, 0);
1326 SecPolicyRef policy = SecPVCGetPolicy(pvc);
1327 CFTypeRef value = CFDictionaryGetValue(policy->_options, key);
1328
1329 if (value && SecCertificateHasMarkerExtension(cert, value))
1330 return;
1331
1332 SecPVCSetResult(pvc, key, 0, kCFBooleanFalse);
1333 }
1334
1335 static void SecPolicyCheckIntermediateMarkerOid(SecPVCRef pvc, CFStringRef key)
1336 {
1337 CFIndex ix, count = SecPVCGetCertificateCount(pvc);
1338 SecPolicyRef policy = SecPVCGetPolicy(pvc);
1339 CFTypeRef value = CFDictionaryGetValue(policy->_options, key);
1340
1341 for (ix = 1; ix < count - 1; ix++) {
1342 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix);
1343 if (SecCertificateHasMarkerExtension(cert, value))
1344 return;
1345 }
1346 SecPVCSetResult(pvc, key, 0, kCFBooleanFalse);
1347 }
1348
1349 /* Returns true if path is on the allow list, false otherwise */
1350 static bool SecPVCCheckCertificateAllowList(SecPVCRef pvc)
1351 {
1352 bool result = false;
1353 CFIndex ix = 0, count = SecPVCGetCertificateCount(pvc);
1354 CFStringRef authKey = NULL;
1355 SecOTAPKIRef otapkiRef = NULL;
1356
1357 //get authKeyID from the last chain in the cert
1358 if (count < 1) {
1359 return result;
1360 }
1361 SecCertificateRef lastCert = SecPVCGetCertificateAtIndex(pvc, count - 1);
1362 CFDataRef authKeyID = SecCertificateGetAuthorityKeyID(lastCert);
1363 if (NULL == authKeyID) {
1364 return result;
1365 }
1366 authKey = CFDataCopyHexString(authKeyID);
1367
1368 //if allowList && key is in allowList, this would have chained up to a now-removed anchor
1369 otapkiRef = SecOTAPKICopyCurrentOTAPKIRef();
1370 if (NULL == otapkiRef) {
1371 goto errout;
1372 }
1373 CFDictionaryRef allowList = SecOTAPKICopyAllowList(otapkiRef);
1374 if (NULL == allowList) {
1375 goto errout;
1376 }
1377
1378 CFArrayRef allowedCerts = CFDictionaryGetValue(allowList, authKey);
1379 if (!allowedCerts || !CFArrayGetCount(allowedCerts)) {
1380 goto errout;
1381 }
1382
1383 //search sorted array for the SHA256 hash of a cert in the chain
1384 CFRange range = CFRangeMake(0, CFArrayGetCount(allowedCerts));
1385 for (ix = 0; ix < count; ix++) {
1386 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix);
1387 if (!cert) {
1388 goto errout;
1389 }
1390
1391 CFDataRef certHash = SecCertificateCopySHA256Digest(cert);
1392 if (!certHash) {
1393 goto errout;
1394 }
1395
1396 CFIndex position = CFArrayBSearchValues(allowedCerts, range, certHash,
1397 (CFComparatorFunction)CFDataCompare, NULL);
1398 if (position < CFArrayGetCount(allowedCerts)) {
1399 CFDataRef possibleMatch = CFArrayGetValueAtIndex(allowedCerts, position);
1400 if (!CFDataCompare(certHash, possibleMatch)) {
1401 //this cert is in the allowlist
1402 result = true;
1403 }
1404 }
1405
1406 CFRelease(certHash);
1407 }
1408
1409 errout:
1410 CFRelease(authKey);
1411 CFReleaseNull(otapkiRef);
1412 CFReleaseNull(allowList);
1413 return result;
1414 }
1415
1416
1417 /****************************************************************************
1418 *********************** New rfc5280 Chain Validation ***********************
1419 ****************************************************************************/
1420
1421 #if 0
1422 typedef struct cert_path *cert_path_t;
1423 struct cert_path {
1424 int length;
1425 };
1426
1427 typedef struct x500_name *x500_name_t;
1428 struct x500_name {
1429 };
1430
1431 typedef struct algorithm_id *algorithm_id_t;
1432 struct algorithm_id {
1433 oid_t algorithm_oid;
1434 der_t parameters;
1435 };
1436
1437 typedef struct trust_anchor *trust_anchor_t;
1438 struct trust_anchor {
1439 x500_name_t issuer_name;
1440 algorithm_id_t public_key_algorithm; /* includes optional params */
1441 SecKeyRef public_key;
1442 };
1443
1444 typedef struct certificate_policy *certificate_policy_t;
1445 struct certificate_policy {
1446 policy_qualifier_t qualifiers;
1447 oid_t oid;
1448 SLIST_ENTRY(certificate_policy) policies;
1449 };
1450
1451 typedef struct policy_mapping *policy_mapping_t;
1452 struct policy_mapping {
1453 SLIST_ENTRY(policy_mapping) mappings;
1454 oid_t issuer_domain_policy;
1455 oid_t subject_domain_policy;
1456 };
1457
1458 typedef struct root_name *root_name_t;
1459 struct root_name {
1460 };
1461 #endif
1462
1463 struct policy_tree_add_ctx {
1464 oid_t p_oid;
1465 policy_qualifier_t p_q;
1466 };
1467
1468 /* 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}. */
1469 static bool policy_tree_add_if_match(policy_tree_t node, void *ctx) {
1470 struct policy_tree_add_ctx *info = (struct policy_tree_add_ctx *)ctx;
1471 policy_set_t policy_set;
1472 for (policy_set = node->expected_policy_set;
1473 policy_set;
1474 policy_set = policy_set->oid_next) {
1475 if (oid_equal(policy_set->oid, info->p_oid)) {
1476 policy_tree_add_child(node, &info->p_oid, info->p_q);
1477 return true;
1478 }
1479 }
1480 return false;
1481 }
1482
1483 /* 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}. */
1484 static bool policy_tree_add_if_any(policy_tree_t node, void *ctx) {
1485 struct policy_tree_add_ctx *info = (struct policy_tree_add_ctx *)ctx;
1486 if (oid_equal(node->valid_policy, oidAnyPolicy)) {
1487 policy_tree_add_child(node, &info->p_oid, info->p_q);
1488 return true;
1489 }
1490 return false;
1491 }
1492
1493 /* Return true iff node has a child with a valid_policy equal to oid. */
1494 static bool policy_tree_has_child_with_oid(policy_tree_t node,
1495 const oid_t *oid) {
1496 policy_tree_t child;
1497 for (child = node->children; child; child = child->siblings) {
1498 if (oid_equal(child->valid_policy, (*oid))) {
1499 return true;
1500 }
1501 }
1502 return false;
1503 }
1504
1505 /* 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. */
1506 static bool policy_tree_add_expected(policy_tree_t node, void *ctx) {
1507 policy_qualifier_t p_q = (policy_qualifier_t)ctx;
1508 policy_set_t policy_set;
1509 bool added_node = false;
1510 for (policy_set = node->expected_policy_set;
1511 policy_set;
1512 policy_set = policy_set->oid_next) {
1513 if (!policy_tree_has_child_with_oid(node, &policy_set->oid)) {
1514 policy_tree_add_child(node, &policy_set->oid, p_q);
1515 added_node = true;
1516 }
1517 }
1518 return added_node;
1519 }
1520
1521 #if 0
1522 /* 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. */
1523 static bool policy_tree_map(policy_tree_t node, void *ctx) {
1524 /* Can't map oidAnyPolicy. */
1525 if (oid_equal(node->valid_policy, oidAnyPolicy))
1526 return false;
1527
1528 const SecCEPolicyMappings *pm = (const SecCEPolicyMappings *)ctx;
1529 uint32_t mapping_ix, mapping_count = pm->numMappings;
1530 policy_set_t policy_set = NULL;
1531 /* First count how many mappings match this nodes valid_policy. */
1532 for (mapping_ix = 0; mapping_ix < mapping_count; ++mapping_ix) {
1533 const SecCEPolicyMapping *mapping = &pm->mappings[mapping_ix];
1534 if (oid_equal(node->valid_policy, mapping->issuerDomainPolicy)) {
1535 policy_set_t p_node = (policy_set_t)malloc(sizeof(*policy_set));
1536 p_node->oid = mapping->subjectDomainPolicy;
1537 p_node->oid_next = policy_set ? policy_set : NULL;
1538 policy_set = p_node;
1539 }
1540 }
1541 if (policy_set) {
1542 policy_tree_set_expected_policy(node, policy_set);
1543 return true;
1544 }
1545 return false;
1546 }
1547 #endif
1548
1549 #define POLICY_MAPPING 0
1550 #define POLICY_SUBTREES 1
1551
1552 /* rfc5280 basic cert processing. */
1553 static void SecPolicyCheckBasicCertificateProcessing(SecPVCRef pvc,
1554 CFStringRef key) {
1555 /* Inputs */
1556 //cert_path_t path;
1557 CFIndex count = SecPVCGetCertificateCount(pvc);
1558 /* 64 bits cast: worst case here is we truncate the number of cert, and the validation may fail */
1559 assert((unsigned long)count<=UINT32_MAX); /* Debug check. Correct as long as CFIndex is long */
1560 uint32_t n = (uint32_t)count;
1561 bool is_anchored = SecPVCIsAnchored(pvc);
1562 if (is_anchored) {
1563 /* If the anchor is trusted we don't procces the last cert in the
1564 chain (root). */
1565 n--;
1566 } else {
1567 /* trust may be restored for a path with an untrusted root that matches the allow list */
1568 if (!SecPVCCheckCertificateAllowList(pvc)) {
1569 /* Add a detail for the root not being trusted. */
1570 if (SecPVCSetResultForced(pvc, kSecPolicyCheckAnchorTrusted,
1571 n - 1, kCFBooleanFalse, true))
1572 return;
1573 }
1574 }
1575
1576 CFAbsoluteTime verify_time = SecPVCGetVerifyTime(pvc);
1577 //policy_set_t user_initial_policy_set = NULL;
1578 //trust_anchor_t anchor;
1579 bool initial_policy_mapping_inhibit = false;
1580 bool initial_explicit_policy = false;
1581 bool initial_any_policy_inhibit = false;
1582
1583 /* Initialization */
1584 pvc->valid_policy_tree = policy_tree_create(&oidAnyPolicy, NULL);
1585 #if POLICY_SUBTREES
1586 CFMutableArrayRef permitted_subtrees = NULL;
1587 CFMutableArrayRef excluded_subtrees = NULL;
1588 permitted_subtrees = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
1589 excluded_subtrees = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
1590 assert(permitted_subtrees != NULL);
1591 assert(excluded_subtrees != NULL);
1592 #endif
1593 uint32_t explicit_policy = initial_explicit_policy ? 0 : n + 1;
1594 uint32_t inhibit_any_policy = initial_any_policy_inhibit ? 0 : n + 1;
1595 uint32_t policy_mapping = initial_policy_mapping_inhibit ? 0 : n + 1;
1596
1597 #if 0
1598 /* Path builder ensures we only get cert chains with proper issuer
1599 chaining with valid signatures along the way. */
1600 algorithm_id_t working_public_key_algorithm = anchor->public_key_algorithm;
1601 SecKeyRef working_public_key = anchor->public_key;
1602 x500_name_t working_issuer_name = anchor->issuer_name;
1603 #endif
1604 uint32_t i, max_path_length = n;
1605 SecCertificateRef cert = NULL;
1606 for (i = 1; i <= n; ++i) {
1607 /* Process Cert */
1608 cert = SecPVCGetCertificateAtIndex(pvc, n - i);
1609 bool is_self_issued = SecPVCIsCertificateAtIndexSelfSigned(pvc, n - i);
1610
1611 /* (a) Verify the basic certificate information. */
1612 /* @@@ Ensure that cert was signed with working_public_key_algorithm
1613 using the working_public_key and the working_public_key_parameters. */
1614 #if 1
1615 /* Already done by chain builder. */
1616 if (!SecCertificateIsValid(cert, verify_time)) {
1617 CFStringRef fail_key = i == n ? kSecPolicyCheckValidLeaf : kSecPolicyCheckValidIntermediates;
1618 if (!SecPVCSetResult(pvc, fail_key, n - i, kCFBooleanFalse))
1619 return;
1620 }
1621 if (SecCertificateIsWeak(cert)) {
1622 CFStringRef fail_key = i == n ? kSecPolicyCheckWeakLeaf : kSecPolicyCheckWeakIntermediates;
1623 if (!SecPVCSetResult(pvc, fail_key, n - i, kCFBooleanFalse))
1624 return;
1625 }
1626 #endif
1627 #if 0
1628 /* Check revocation status if the certificate asks for it. */
1629 CFArrayRef ocspResponders = SecCertificateGetOCSPResponders(cert);
1630 if (ocspResponders) {
1631 SecPVCSetCheckRevocation(pvc);
1632 }
1633 #endif
1634 /* @@@ cert.issuer == working_issuer_name. */
1635
1636 #if POLICY_SUBTREES
1637 /* (b) (c) */
1638 if (!is_self_issued || i == n) {
1639 bool found = false;
1640 /* Verify certificate Subject Name and SubjectAltNames are not within any of the excluded_subtrees */
1641 if(excluded_subtrees && CFArrayGetCount(excluded_subtrees)) {
1642 if ((errSecSuccess != SecNameContraintsMatchSubtrees(cert, excluded_subtrees, &found, false)) || found) {
1643 if(!SecPVCSetResultForced(pvc, key, n - i, kCFBooleanFalse, true)) return;
1644 }
1645 }
1646 /* Verify certificate Subject Name and SubjectAltNames are within the permitted_subtrees */
1647 if(permitted_subtrees && CFArrayGetCount(permitted_subtrees)) {
1648 if ((errSecSuccess != SecNameContraintsMatchSubtrees(cert, permitted_subtrees, &found, true)) || !found) {
1649 if(!SecPVCSetResultForced(pvc, key, n - i, kCFBooleanFalse, true)) return;
1650 }
1651 }
1652 }
1653 #endif
1654 /* (d) */
1655 if (pvc->valid_policy_tree) {
1656 const SecCECertificatePolicies *cp =
1657 SecCertificateGetCertificatePolicies(cert);
1658 size_t policy_ix, policy_count = cp ? cp->numPolicies : 0;
1659 for (policy_ix = 0; policy_ix < policy_count; ++policy_ix) {
1660 const SecCEPolicyInformation *policy = &cp->policies[policy_ix];
1661 oid_t p_oid = policy->policyIdentifier;
1662 policy_qualifier_t p_q = &policy->policyQualifiers;
1663 struct policy_tree_add_ctx ctx = { p_oid, p_q };
1664 if (!oid_equal(p_oid, oidAnyPolicy)) {
1665 if (!policy_tree_walk_depth(pvc->valid_policy_tree, i - 1,
1666 policy_tree_add_if_match, &ctx)) {
1667 policy_tree_walk_depth(pvc->valid_policy_tree, i - 1,
1668 policy_tree_add_if_any, &ctx);
1669 }
1670 }
1671 }
1672 /* The certificate policies extension includes the policy
1673 anyPolicy with the qualifier set AP-Q and either
1674 (a) inhibit_anyPolicy is greater than 0 or
1675 (b) i < n and the certificate is self-issued. */
1676 if (inhibit_any_policy > 0 || (i < n && is_self_issued)) {
1677 for (policy_ix = 0; policy_ix < policy_count; ++policy_ix) {
1678 const SecCEPolicyInformation *policy = &cp->policies[policy_ix];
1679 oid_t p_oid = policy->policyIdentifier;
1680 policy_qualifier_t p_q = &policy->policyQualifiers;
1681 if (oid_equal(p_oid, oidAnyPolicy)) {
1682 policy_tree_walk_depth(pvc->valid_policy_tree, i - 1,
1683 policy_tree_add_expected, (void *)p_q);
1684 }
1685 }
1686 }
1687 policy_tree_prune_childless(&pvc->valid_policy_tree, i - 1);
1688 /* (e) */
1689 if (!cp) {
1690 if (pvc->valid_policy_tree)
1691 policy_tree_prune(&pvc->valid_policy_tree);
1692 }
1693 }
1694 /* (f) Verify that either explicit_policy is greater than 0 or the
1695 valid_policy_tree is not equal to NULL. */
1696 if (!pvc->valid_policy_tree && explicit_policy == 0) {
1697 /* valid_policy_tree is empty and explicit policy is 0, illegal. */
1698 if (!SecPVCSetResultForced(pvc, key /* @@@ Need custom key */, n - i, kCFBooleanFalse, true))
1699 return;
1700 }
1701 /* If Last Cert in Path */
1702 if (i == n)
1703 break;
1704
1705 /* Prepare for Next Cert */
1706 #if POLICY_MAPPING
1707 /* (a) verify that anyPolicy does not appear as an
1708 issuerDomainPolicy or a subjectDomainPolicy */
1709 CFDictionaryRef pm = SecCertificateGetPolicyMappings(cert);
1710 if (pm) {
1711 uint32_t mapping_ix, mapping_count = pm->numMappings;
1712 for (mapping_ix = 0; mapping_ix < mapping_count; ++mapping_ix) {
1713 const SecCEPolicyMapping *mapping = &pm->mappings[mapping_ix];
1714 if (oid_equal(mapping->issuerDomainPolicy, oidAnyPolicy)
1715 || oid_equal(mapping->subjectDomainPolicy, oidAnyPolicy)) {
1716 /* Policy mapping uses anyPolicy, illegal. */
1717 if (!SecPVCSetResultForced(pvc, key /* @@@ Need custom key */, n - i, kCFBooleanFalse))
1718 return;
1719 }
1720 }
1721 /* (b) */
1722 /* (1) If the policy_mapping variable is greater than 0 */
1723 if (policy_mapping > 0) {
1724 if (!policy_tree_walk_depth(pvc->valid_policy_tree, i,
1725 policy_tree_map, (void *)pm)) {
1726 /* 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:
1727
1728 (i) set the valid_policy to ID-P;
1729
1730 (ii) set the qualifier_set to the qualifier set of the
1731 policy anyPolicy in the certificate policies
1732 extension of certificate i; and
1733 (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. */
1734 }
1735 } else {
1736 #if 0
1737 /* (i) delete each node of depth i in the valid_policy_tree
1738 where ID-P is the valid_policy. */
1739 struct policy_tree_map_ctx ctx = { idp_oid, sdp_oid };
1740 policy_tree_walk_depth(pvc->valid_policy_tree, i,
1741 policy_tree_delete_if_match, &ctx);
1742 #endif
1743 /* (ii) If there is a node in the valid_policy_tree of depth
1744 i-1 or less without any child nodes, delete that
1745 node. Repeat this step until there are no nodes of
1746 depth i-1 or less without children. */
1747 policy_tree_prune_childless(&pvc->valid_policy_tree, i - 1);
1748 }
1749 }
1750 #endif /* POLICY_MAPPING */
1751 /* (c)(d)(e)(f) */
1752 //working_issuer_name = SecCertificateGetNormalizedSubjectContent(cert);
1753 //working_public_key = SecCertificateCopyPublicKey(cert);
1754 //working_public_key_parameters = SecCertificateCopyPublicKeyParameters(cert);
1755 //working_public_key_algorithm = SecCertificateCopyPublicKeyAlgorithm(cert);
1756 #if POLICY_SUBTREES
1757 /* (g) If a name constraints extension is included in the certificate, modify the permitted_subtrees and excluded_subtrees state variables.
1758 */
1759 CFArrayRef permitted_subtrees_in_cert = SecCertificateGetPermittedSubtrees(cert);
1760 if (permitted_subtrees_in_cert) {
1761 SecNameConstraintsIntersectSubtrees(permitted_subtrees, permitted_subtrees_in_cert);
1762 }
1763
1764 // could do something smart here to avoid inserting the exact same constraint
1765 CFArrayRef excluded_subtrees_in_cert = SecCertificateGetExcludedSubtrees(cert);
1766 if (excluded_subtrees_in_cert) {
1767 CFIndex num_trees = CFArrayGetCount(excluded_subtrees_in_cert);
1768 CFRange range = { 0, num_trees };
1769 CFArrayAppendArray(excluded_subtrees, excluded_subtrees_in_cert, range);
1770 }
1771 #endif
1772 /* (h) */
1773 if (!is_self_issued) {
1774 if (explicit_policy)
1775 explicit_policy--;
1776 if (policy_mapping)
1777 policy_mapping--;
1778 if (inhibit_any_policy)
1779 inhibit_any_policy--;
1780 }
1781 /* (i) */
1782 const SecCEPolicyConstraints *pc =
1783 SecCertificateGetPolicyConstraints(cert);
1784 if (pc) {
1785 if (pc->requireExplicitPolicyPresent
1786 && pc->requireExplicitPolicy < explicit_policy) {
1787 explicit_policy = pc->requireExplicitPolicy;
1788 }
1789 if (pc->inhibitPolicyMappingPresent
1790 && pc->inhibitPolicyMapping < policy_mapping) {
1791 policy_mapping = pc->inhibitPolicyMapping;
1792 }
1793 }
1794 /* (j) */
1795 uint32_t iap = SecCertificateGetInhibitAnyPolicySkipCerts(cert);
1796 if (iap < inhibit_any_policy) {
1797 inhibit_any_policy = iap;
1798 }
1799 /* (k) */
1800 const SecCEBasicConstraints *bc =
1801 SecCertificateGetBasicConstraints(cert);
1802 #if 0 /* Checked in chain builder pre signature verify already. */
1803 if (!bc || !bc->isCA) {
1804 /* Basic constraints not present or not marked as isCA, illegal. */
1805 if (!SecPVCSetResult(pvc, kSecPolicyCheckBasicContraints,
1806 n - i, kCFBooleanFalse))
1807 return;
1808 }
1809 #endif
1810 /* (l) */
1811 if (!is_self_issued) {
1812 if (max_path_length > 0) {
1813 max_path_length--;
1814 } else {
1815 /* max_path_len exceeded, illegal. */
1816 if (!SecPVCSetResult(pvc, kSecPolicyCheckBasicContraints,
1817 n - i, kCFBooleanFalse))
1818 return;
1819 }
1820 }
1821 /* (m) */
1822 if (bc && bc->pathLenConstraintPresent
1823 && bc->pathLenConstraint < max_path_length) {
1824 max_path_length = bc->pathLenConstraint;
1825 }
1826 #if 0 /* Checked in chain builder pre signature verify already. */
1827 /* (n) If a key usage extension is present, verify that the keyCertSign bit is set. */
1828 SecKeyUsage keyUsage = SecCertificateGetKeyUsage(cert);
1829 if (keyUsage && !(keyUsage & kSecKeyUsageKeyCertSign)) {
1830 if (!SecPVCSetResultForced(pvc, kSecPolicyCheckKeyUsage,
1831 n - i, kCFBooleanFalse, true))
1832 return;
1833 }
1834 #endif
1835 /* (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. */
1836 if (SecCertificateHasUnknownCriticalExtension(cert)) {
1837 /* Certificate contains one or more unknown critical extensions. */
1838 if (!SecPVCSetResult(pvc, kSecPolicyCheckCriticalExtensions,
1839 n - i, kCFBooleanFalse))
1840 return;
1841 }
1842 } /* end loop over certs in path */
1843 /* Wrap up */
1844 cert = SecPVCGetCertificateAtIndex(pvc, 0);
1845 /* (a) */
1846 if (explicit_policy)
1847 explicit_policy--;
1848 /* (b) */
1849 const SecCEPolicyConstraints *pc = SecCertificateGetPolicyConstraints(cert);
1850 if (pc) {
1851 if (pc->requireExplicitPolicyPresent
1852 && pc->requireExplicitPolicy == 0) {
1853 explicit_policy = 0;
1854 }
1855 }
1856 /* (c) */
1857 //working_public_key = SecCertificateCopyPublicKey(cert);
1858 /* (d) */
1859 /* 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
1860 working_public_key_algorithm are different, set the working_public_key_parameters to null. */
1861 //working_public_key_parameters = SecCertificateCopyPublicKeyParameters(cert);
1862 /* (e) */
1863 //working_public_key_algorithm = SecCertificateCopyPublicKeyAlgorithm(cert);
1864 /* (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. */
1865 if (SecCertificateHasUnknownCriticalExtension(cert)) {
1866 /* Certificate contains one or more unknown critical extensions. */
1867 if (!SecPVCSetResult(pvc, kSecPolicyCheckCriticalExtensions,
1868 0, kCFBooleanFalse))
1869 return;
1870 }
1871 /* (g) Calculate the intersection of the valid_policy_tree and the user-initial-policy-set, as follows */
1872
1873 if (pvc->valid_policy_tree) {
1874 #if !defined(NDEBUG)
1875 policy_tree_dump(pvc->valid_policy_tree);
1876 #endif
1877 /* (g3c4) */
1878 //policy_tree_prune_childless(&pvc->valid_policy_tree, n - 1);
1879 }
1880
1881 /* If either (1) the value of explicit_policy variable is greater than
1882 zero or (2) the valid_policy_tree is not NULL, then path processing
1883 has succeeded. */
1884 if (!pvc->valid_policy_tree && explicit_policy == 0) {
1885 /* valid_policy_tree is empty and explicit policy is 0, illegal. */
1886 if (!SecPVCSetResultForced(pvc, key /* @@@ Need custom key */, 0, kCFBooleanFalse, true))
1887 return;
1888 }
1889
1890 CFReleaseNull(permitted_subtrees);
1891 CFReleaseNull(excluded_subtrees);
1892 }
1893
1894 static policy_set_t policies_for_cert(SecCertificateRef cert) {
1895 policy_set_t policies = NULL;
1896 const SecCECertificatePolicies *cp =
1897 SecCertificateGetCertificatePolicies(cert);
1898 size_t policy_ix, policy_count = cp ? cp->numPolicies : 0;
1899 for (policy_ix = 0; policy_ix < policy_count; ++policy_ix) {
1900 policy_set_add(&policies, &cp->policies[policy_ix].policyIdentifier);
1901 }
1902 return policies;
1903 }
1904
1905 static void SecPolicyCheckEV(SecPVCRef pvc,
1906 CFStringRef key) {
1907 CFIndex ix, count = SecPVCGetCertificateCount(pvc);
1908 policy_set_t valid_policies = NULL;
1909
1910 for (ix = 0; ix < count; ++ix) {
1911 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix);
1912 policy_set_t policies = policies_for_cert(cert);
1913 if (ix == 0) {
1914 /* Subscriber */
1915 /* anyPolicy in the leaf isn't allowed for EV, so only init
1916 valid_policies if we have real policies. */
1917 if (!policy_set_contains(policies, &oidAnyPolicy)) {
1918 valid_policies = policies;
1919 policies = NULL;
1920 }
1921 } else if (ix < count - 1) {
1922 /* Subordinate CA */
1923 if (!SecPolicySubordinateCACertificateCouldBeEV(cert)) {
1924 secdebug("ev", "subordinate certificate is not ev");
1925 if (SecPVCSetResultForced(pvc, key,
1926 ix, kCFBooleanFalse, true)) {
1927 policy_set_free(valid_policies);
1928 policy_set_free(policies);
1929 return;
1930 }
1931 }
1932 policy_set_intersect(&valid_policies, policies);
1933 } else {
1934 /* Root CA */
1935 if (!SecPolicyRootCACertificateIsEV(cert, valid_policies)) {
1936 secdebug("ev", "anchor certificate is not ev");
1937 if (SecPVCSetResultForced(pvc, key,
1938 ix, kCFBooleanFalse, true)) {
1939 policy_set_free(valid_policies);
1940 policy_set_free(policies);
1941 return;
1942 }
1943 }
1944 }
1945 policy_set_free(policies);
1946 if (!valid_policies) {
1947 secdebug("ev", "valid_policies set is empty: chain not ev");
1948 /* If we ever get into a state where no policies are valid anymore
1949 this can't be an ev chain. */
1950 if (SecPVCSetResultForced(pvc, key,
1951 ix, kCFBooleanFalse, true)) {
1952 return;
1953 }
1954 }
1955 }
1956
1957 policy_set_free(valid_policies);
1958
1959 /* (a) EV Subscriber Certificates Each EV Certificate issued by the CA to a
1960 Subscriber MUST contain an OID defined by the CA in the certificate’s
1961 certificatePolicies extension that: (i) indicates which CA policy statement relates
1962 to that certificate, (ii) asserts the CA’s adherence to and compliance with these
1963 Guidelines, and (iii), by pre-agreement with the Application Software Vendor,
1964 marks the certificate as being an EV Certificate.
1965 (b) EV Subordinate CA Certificates
1966 (1) Certificates issued to Subordinate CAs that are not controlled by the issuing
1967 CA MUST contain one or more OIDs defined by the issuing CA that
1968 explicitly identify the EV Policies that are implemented by the Subordinate
1969 CA;
1970 (2) Certificates issued to Subordinate CAs that are controlled by the Root CA
1971 MAY contain the special anyPolicy OID (2.5.29.32.0).
1972 (c) Root CA Certificates Root CA Certificates SHOULD NOT contain the
1973 certificatePolicies or extendedKeyUsage extensions.
1974 */
1975 }
1976
1977
1978 /*
1979 * MARK: Certificate Transparency support
1980 */
1981
1982 /***
1983
1984 struct {
1985 Version sct_version; // 1 byte
1986 LogID id; // 32 bytes
1987 uint64 timestamp; // 8 bytes
1988 CtExtensions extensions; // 2 bytes len field, + n bytes data
1989 digitally-signed struct { // 1 byte hash alg, 1 byte sig alg, n bytes signature
1990 Version sct_version;
1991 SignatureType signature_type = certificate_timestamp;
1992 uint64 timestamp;
1993 LogEntryType entry_type;
1994 select(entry_type) {
1995 case x509_entry: ASN.1Cert;
1996 case precert_entry: PreCert;
1997 } signed_entry;
1998 CtExtensions extensions;
1999 };
2000 } SignedCertificateTimestamp;
2001
2002 ***/
2003
2004 #include <Security/SecureTransportPriv.h>
2005
2006 static const
2007 SecAsn1Oid *oidForSigAlg(SSL_HashAlgorithm hash, SSL_SignatureAlgorithm alg)
2008 {
2009 switch(alg) {
2010 case SSL_SignatureAlgorithmRSA:
2011 switch (hash) {
2012 case SSL_HashAlgorithmSHA1:
2013 return &CSSMOID_SHA1WithRSA;
2014 case SSL_HashAlgorithmSHA256:
2015 return &CSSMOID_SHA256WithRSA;
2016 case SSL_HashAlgorithmSHA384:
2017 return &CSSMOID_SHA384WithRSA;
2018 default:
2019 break;
2020 }
2021 case SSL_SignatureAlgorithmECDSA:
2022 switch (hash) {
2023 case SSL_HashAlgorithmSHA1:
2024 return &CSSMOID_ECDSA_WithSHA1;
2025 case SSL_HashAlgorithmSHA256:
2026 return &CSSMOID_ECDSA_WithSHA256;
2027 case SSL_HashAlgorithmSHA384:
2028 return &CSSMOID_ECDSA_WithSHA384;
2029 default:
2030 break;
2031 }
2032 default:
2033 break;
2034 }
2035
2036 return NULL;
2037 }
2038
2039
2040 static size_t SSLDecodeUint16(const uint8_t *p)
2041 {
2042 return (p[0]<<8 | p[1]);
2043 }
2044
2045 static uint8_t *SSLEncodeUint16(uint8_t *p, size_t len)
2046 {
2047 p[0] = (len >> 8)&0xff;
2048 p[1] = (len & 0xff);
2049 return p+2;
2050 }
2051
2052 static uint8_t *SSLEncodeUint24(uint8_t *p, size_t len)
2053 {
2054 p[0] = (len >> 16)&0xff;
2055 p[1] = (len >> 8)&0xff;
2056 p[2] = (len & 0xff);
2057 return p+3;
2058 }
2059
2060
2061 static
2062 uint64_t SSLDecodeUint64(const uint8_t *p)
2063 {
2064 uint64_t u = 0;
2065 for(int i=0; i<8; i++) {
2066 u=(u<<8)|p[0];
2067 p++;
2068 }
2069 return u;
2070 }
2071
2072 #include <libDER/DER_CertCrl.h>
2073 #include <libDER/DER_Encode.h>
2074 #include <libDER/asn1Types.h>
2075
2076
2077 static CFDataRef copy_x509_entry_from_chain(SecPVCRef pvc)
2078 {
2079 SecCertificateRef leafCert = SecPVCGetCertificateAtIndex(pvc, 0);
2080
2081 CFMutableDataRef data = CFDataCreateMutable(kCFAllocatorDefault, 3+SecCertificateGetLength(leafCert));
2082
2083 CFDataSetLength(data, 3+SecCertificateGetLength(leafCert));
2084
2085 uint8_t *q = CFDataGetMutableBytePtr(data);
2086 q = SSLEncodeUint24(q, SecCertificateGetLength(leafCert));
2087 memcpy(q, SecCertificateGetBytePtr(leafCert), SecCertificateGetLength(leafCert));
2088
2089 return data;
2090 }
2091
2092
2093 static CFDataRef copy_precert_entry_from_chain(SecPVCRef pvc)
2094 {
2095 SecCertificateRef leafCert = NULL;
2096 SecCertificateRef issuer = NULL;
2097 CFDataRef issuerKeyHash = NULL;
2098 CFDataRef tbs_precert = NULL;
2099 CFMutableDataRef data= NULL;
2100
2101 require_quiet(SecPVCGetCertificateCount(pvc)>=2, out); //we need the issuer key for precerts.
2102 leafCert = SecPVCGetCertificateAtIndex(pvc, 0);
2103 issuer = SecPVCGetCertificateAtIndex(pvc, 1);
2104
2105 require(leafCert, out);
2106 require(issuer, out); // Those two would likely indicate an internal error, since we already checked the chain length above.
2107 issuerKeyHash = SecCertificateCopySubjectPublicKeyInfoSHA256Digest(issuer);
2108 tbs_precert = SecCertificateCopyPrecertTBS(leafCert);
2109
2110 require(issuerKeyHash, out);
2111 require(tbs_precert, out);
2112 data = CFDataCreateMutable(kCFAllocatorDefault, CFDataGetLength(issuerKeyHash) + 3 + CFDataGetLength(tbs_precert));
2113 CFDataSetLength(data, CFDataGetLength(issuerKeyHash) + 3 + CFDataGetLength(tbs_precert));
2114
2115 uint8_t *q = CFDataGetMutableBytePtr(data);
2116 memcpy(q, CFDataGetBytePtr(issuerKeyHash), CFDataGetLength(issuerKeyHash)); q += CFDataGetLength(issuerKeyHash); // issuer key hash
2117 q = SSLEncodeUint24(q, CFDataGetLength(tbs_precert));
2118 memcpy(q, CFDataGetBytePtr(tbs_precert), CFDataGetLength(tbs_precert));
2119
2120 out:
2121 CFReleaseSafe(issuerKeyHash);
2122 CFReleaseSafe(tbs_precert);
2123 return data;
2124 }
2125
2126 /* If the 'sct' is valid, return the operator ID of the log that signed this sct.
2127
2128 The SCT is valid if:
2129 - It decodes properly.
2130 - Its timestamp is less than 'verifyTime'.
2131 - It is signed by a log in 'trustedLogs'.
2132 - The signing log expiryTime (if any) is less than 'verifyTime' (entry_type==0) or 'issuanceTime' (entry_type==1).
2133
2134 If the SCT is valid, the returned CFStringRef is the identifier for the log operator. That value is not retained.
2135 If the SCT is valid, '*validLogAtVerifyTime' is set to true if the log is not expired at 'verifyTime'
2136
2137 If the SCT is not valid this function return NULL.
2138 */
2139 static CFStringRef get_valid_sct_operator(CFDataRef sct, int entry_type, CFDataRef entry, CFAbsoluteTime verifyTime, CFAbsoluteTime issuanceTime, CFArrayRef trustedLogs, bool *validLogAtVerifyTime)
2140 {
2141 uint8_t version;
2142 const uint8_t *logID;
2143 const uint8_t *timestampData;
2144 uint64_t timestamp;
2145 size_t extensionsLen;
2146 const uint8_t *extensionsData;
2147 uint8_t hashAlg;
2148 uint8_t sigAlg;
2149 size_t signatureLen;
2150 const uint8_t *signatureData;
2151 CFStringRef result = NULL;
2152 SecKeyRef pubKey = NULL;
2153 uint8_t *signed_data = NULL;
2154 const SecAsn1Oid *oid = NULL;
2155 SecAsn1AlgId algId;
2156
2157 const uint8_t *p = CFDataGetBytePtr(sct);
2158 size_t len = CFDataGetLength(sct);
2159 uint64_t vt =(uint64_t)( verifyTime + kCFAbsoluteTimeIntervalSince1970) * 1000;
2160
2161 require(len>=43, out);
2162
2163 version = p[0]; p++; len--;
2164 logID = p; p+=32; len-=32;
2165 timestampData = p; p+=8; len-=8;
2166 extensionsLen = SSLDecodeUint16(p); p+=2; len-=2;
2167
2168 require(len>=extensionsLen, out);
2169 extensionsData = p; p+=extensionsLen; len-=extensionsLen;
2170
2171 require(len>=4, out);
2172 hashAlg=p[0]; p++; len--;
2173 sigAlg=p[0]; p++; len--;
2174 signatureLen = SSLDecodeUint16(p); p+=2; len-=2;
2175 require(len==signatureLen, out); /* We do not tolerate any extra data after the signature */
2176 signatureData = p;
2177
2178 /* verify version: only v1(0) is supported */
2179 if(version!=0) {
2180 secerror("SCT version unsupported: %d\n", version);
2181 goto out;
2182 }
2183
2184 /* verify timestamp not in the future */
2185 timestamp = SSLDecodeUint64(timestampData);
2186 if(timestamp > vt) {
2187 secerror("SCT is in the future: %llu > %llu\n", timestamp, vt);
2188 goto out;
2189 }
2190
2191 uint8_t *q;
2192
2193 /* signed entry */
2194 size_t signed_data_len = 12 + CFDataGetLength(entry) + 2 + extensionsLen ;
2195 signed_data = malloc(signed_data_len);
2196 require(signed_data, out);
2197 q = signed_data;
2198 *q++ = version;
2199 *q++ = 0; // certificate_timestamp
2200 memcpy(q, timestampData, 8); q+=8;
2201 q = SSLEncodeUint16(q, entry_type); // logentry type: 0=cert 1=precert
2202 memcpy(q, CFDataGetBytePtr(entry), CFDataGetLength(entry)); q += CFDataGetLength(entry);
2203 q = SSLEncodeUint16(q, extensionsLen);
2204 memcpy(q, extensionsData, extensionsLen);
2205
2206 CFDataRef logIDData = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, logID, 32, kCFAllocatorNull);
2207
2208 CFDictionaryRef logData = CFArrayGetValueMatching(trustedLogs, ^bool(const void *dict) {
2209 const void *key_data;
2210 if(!isDictionary(dict)) return false;
2211 if(!CFDictionaryGetValueIfPresent(dict, CFSTR("key"), &key_data)) return false;
2212 if(!isData(key_data)) return false;
2213 CFDataRef valueID = SecSHA256DigestCreateFromData(kCFAllocatorDefault, (CFDataRef)key_data);
2214 bool result = (bool)(CFDataCompare(logIDData, valueID)==kCFCompareEqualTo);
2215 CFReleaseSafe(valueID);
2216 return result;
2217 });
2218 CFReleaseSafe(logIDData);
2219 require(logData, out);
2220
2221 /* If an expiry date is specified, and is a valid CFDate, then we check it against issuanceTime or verifyTime */
2222 const void *expiry_date;
2223 if(CFDictionaryGetValueIfPresent(logData, CFSTR("expiry"), &expiry_date) && isDate(expiry_date)) {
2224 CFAbsoluteTime expiryTime = CFDateGetAbsoluteTime(expiry_date);
2225 if(entry_type == 1) {/* pre-cert: check the validity of the log at issuanceTime */
2226 require(issuanceTime<=expiryTime, out);
2227 } else {
2228 require(verifyTime<=expiryTime, out);
2229 }
2230 *validLogAtVerifyTime = (verifyTime<=expiryTime);
2231 } else {
2232 *validLogAtVerifyTime = true;
2233 }
2234
2235 CFDataRef logKeyData = CFDictionaryGetValue(logData, CFSTR("key"));
2236 require(logKeyData, out); // This failing would be an internal logic error
2237 pubKey = SecKeyCreateFromSubjectPublicKeyInfoData(kCFAllocatorDefault, logKeyData);
2238 require(pubKey, out);
2239
2240 oid = oidForSigAlg(hashAlg, sigAlg);
2241 require(oid, out);
2242
2243 algId.algorithm = *oid;
2244 algId.parameters.Data = NULL;
2245 algId.parameters.Length = 0;
2246
2247 if(SecKeyDigestAndVerify(pubKey, &algId, signed_data, signed_data_len, signatureData, signatureLen)==0) {
2248 result = CFDictionaryGetValue(logData, CFSTR("operator"));
2249 } else {
2250 secerror("SCT signature failed (log=%@)\n", logData);
2251 }
2252
2253 out:
2254 CFReleaseSafe(pubKey);
2255 free(signed_data);
2256 return result;
2257 }
2258
2259 static CFArrayRef copy_ocsp_scts(SecPVCRef pvc)
2260 {
2261 CFMutableArrayRef SCTs = NULL;
2262 SecCertificateRef leafCert = NULL;
2263 SecCertificateRef issuer = NULL;
2264 CFArrayRef ocspResponsesData = NULL;
2265 SecOCSPRequestRef ocspRequest = NULL;
2266
2267 ocspResponsesData = SecPathBuilderCopyOCSPResponses(pvc->builder);
2268 require_quiet(ocspResponsesData, out);
2269
2270 require_quiet(SecPVCGetCertificateCount(pvc)>=2, out); //we need the issuer key for precerts.
2271 leafCert = SecPVCGetCertificateAtIndex(pvc, 0);
2272 issuer = SecPVCGetCertificateAtIndex(pvc, 1);
2273
2274 require(leafCert, out);
2275 require(issuer, out); // not quiet: Those two would likely indicate an internal error, since we already checked the chain length above.
2276 ocspRequest = SecOCSPRequestCreate(leafCert, issuer);
2277
2278 SCTs = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
2279 require(SCTs, out);
2280
2281 CFArrayForEach(ocspResponsesData, ^(const void *value) {
2282 /* TODO: Should the builder already have the appropriate SecOCSPResponseRef ? */
2283 SecOCSPResponseRef ocspResponse = SecOCSPResponseCreate(value);
2284 if(ocspResponse && SecOCSPGetResponseStatus(ocspResponse)==kSecOCSPSuccess) {
2285 SecOCSPSingleResponseRef ocspSingleResponse = SecOCSPResponseCopySingleResponse(ocspResponse, ocspRequest);
2286 if(ocspSingleResponse) {
2287 CFArrayRef singleResponseSCTs = SecOCSPSingleResponseCopySCTs(ocspSingleResponse);
2288 if(singleResponseSCTs) {
2289 CFArrayAppendArray(SCTs, singleResponseSCTs, CFRangeMake(0, CFArrayGetCount(singleResponseSCTs)));
2290 CFRelease(singleResponseSCTs);
2291 }
2292 SecOCSPSingleResponseDestroy(ocspSingleResponse);
2293 }
2294 }
2295 if(ocspResponse) SecOCSPResponseFinalize(ocspResponse);
2296 });
2297
2298 if(CFArrayGetCount(SCTs)==0) {
2299 CFReleaseNull(SCTs);
2300 }
2301
2302 out:
2303 CFReleaseSafe(ocspResponsesData);
2304 if(ocspRequest)
2305 SecOCSPRequestFinalize(ocspRequest);
2306
2307 return SCTs;
2308 }
2309
2310 static void SecPolicyCheckCT(SecPVCRef pvc, CFStringRef key)
2311 {
2312 SecCertificateRef leafCert = SecPVCGetCertificateAtIndex(pvc, 0);
2313 CFArrayRef embeddedScts = SecCertificateCopySignedCertificateTimestamps(leafCert);
2314 CFArrayRef builderScts = SecPathBuilderCopySignedCertificateTimestamps(pvc->builder);
2315 CFArrayRef trustedLogs = SecPathBuilderCopyTrustedLogs(pvc->builder);
2316 CFArrayRef ocspScts = copy_ocsp_scts(pvc);
2317 CFDataRef precertEntry = copy_precert_entry_from_chain(pvc);
2318 CFDataRef x509Entry = copy_x509_entry_from_chain(pvc);
2319
2320 // This eventually contain the list of operators who validated the SCT.
2321 CFMutableSetRef operatorsValidatingEmbeddedScts = CFSetCreateMutable(kCFAllocatorDefault, 0, &kCFTypeSetCallBacks);
2322 CFMutableSetRef operatorsValidatingExternalScts = CFSetCreateMutable(kCFAllocatorDefault, 0, &kCFTypeSetCallBacks);
2323
2324 __block bool atLeastOneValidAtVerifyTime = false;
2325 __block int lifetime; // in Months
2326
2327 require(operatorsValidatingEmbeddedScts, out);
2328 require(operatorsValidatingExternalScts, out);
2329
2330 if(trustedLogs) { // Don't bother trying to validate SCTs if we don't have any trusted logs.
2331 if(embeddedScts && precertEntry) { // Don't bother if we could not get the precert.
2332 CFArrayForEach(embeddedScts, ^(const void *value){
2333 bool validLogAtVerifyTime = false;
2334 CFStringRef operator = get_valid_sct_operator(value, 1, precertEntry, pvc->verifyTime, SecCertificateNotValidBefore(leafCert), trustedLogs, &validLogAtVerifyTime);
2335 if(operator) CFSetAddValue(operatorsValidatingEmbeddedScts, operator);
2336 if(validLogAtVerifyTime) atLeastOneValidAtVerifyTime = true;
2337 });
2338 }
2339
2340 if(builderScts && x509Entry) { // Don't bother if we could not get the cert.
2341 CFArrayForEach(builderScts, ^(const void *value){
2342 bool validLogAtVerifyTime = false;
2343 CFStringRef operator = get_valid_sct_operator(value, 0, x509Entry, pvc->verifyTime, SecCertificateNotValidBefore(leafCert), trustedLogs, &validLogAtVerifyTime);
2344 if(operator) CFSetAddValue(operatorsValidatingExternalScts, operator);
2345 if(validLogAtVerifyTime) atLeastOneValidAtVerifyTime = true;
2346 });
2347 }
2348
2349 if(ocspScts && x509Entry) {
2350 CFArrayForEach(ocspScts, ^(const void *value){
2351 bool validLogAtVerifyTime = false;
2352 CFStringRef operator = get_valid_sct_operator(value, 0, x509Entry, pvc->verifyTime, SecCertificateNotValidBefore(leafCert), trustedLogs, &validLogAtVerifyTime);
2353 if(operator) CFSetAddValue(operatorsValidatingExternalScts, operator);
2354 if(validLogAtVerifyTime) atLeastOneValidAtVerifyTime = true;
2355 });
2356 }
2357 }
2358
2359 /* We now have 2 sets of operators that validated those SCTS, count them and make a final decision.
2360 Current Policy:
2361 is_ct = (A1 OR A2) AND B.
2362
2363 A1: 2+ to 5+ SCTs from the cert from independent logs valid at issuance time
2364 (operatorsValidatingEmbeddedScts)
2365 A2: 2+ SCTs from external sources (OCSP stapled response and TLS extension)
2366 from independent logs valid at verify time. (operatorsValidatingExternalScts)
2367 B: All least one SCTs from a log valid at verify time.
2368
2369 Policy is based on: https://docs.google.com/viewer?a=v&pid=sites&srcid=ZGVmYXVsdGRvbWFpbnxjZXJ0aWZpY2F0ZXRyYW5zcGFyZW5jeXxneDo0ODhjNGRlOTIyMzYwNTcz
2370 with one difference: we consider SCTs from OCSP and TLS extensions as a whole.
2371 It sounds like this is what Google will eventually do, per:
2372 https://groups.google.com/forum/?fromgroups#!topic/certificate-transparency/VdXuzA3TLWY
2373
2374 */
2375
2376 SecCFCalendarDoWithZuluCalendar(^(CFCalendarRef zuluCalendar) {
2377 int _lifetime;
2378 CFCalendarGetComponentDifference(zuluCalendar,
2379 SecCertificateNotValidBefore(leafCert),
2380 SecCertificateNotValidAfter(leafCert),
2381 0, "M", &_lifetime);
2382 lifetime = _lifetime;
2383 });
2384
2385 CFIndex requiredEmbeddedSctsCount;
2386
2387 if (lifetime < 15) {
2388 requiredEmbeddedSctsCount = 2;
2389 } else if (lifetime <= 27) {
2390 requiredEmbeddedSctsCount = 3;
2391 } else if (lifetime <= 39) {
2392 requiredEmbeddedSctsCount = 4;
2393 } else {
2394 requiredEmbeddedSctsCount = 5;
2395 }
2396
2397 pvc->is_ct = ((CFSetGetCount(operatorsValidatingEmbeddedScts) >= requiredEmbeddedSctsCount) ||
2398 (CFSetGetCount(operatorsValidatingExternalScts) >= 2)
2399 ) && atLeastOneValidAtVerifyTime;
2400
2401 out:
2402
2403 CFReleaseSafe(operatorsValidatingEmbeddedScts);
2404 CFReleaseSafe(operatorsValidatingExternalScts);
2405 CFReleaseSafe(builderScts);
2406 CFReleaseSafe(embeddedScts);
2407 CFReleaseSafe(ocspScts);
2408 CFReleaseSafe(precertEntry);
2409 CFReleaseSafe(trustedLogs);
2410 CFReleaseSafe(x509Entry);
2411 }
2412
2413 static void SecPolicyCheckCertificatePolicyOid(SecPVCRef pvc, CFStringRef key)
2414 {
2415 CFIndex ix, count = SecPVCGetCertificateCount(pvc);
2416 SecPolicyRef policy = SecPVCGetPolicy(pvc);
2417 CFTypeRef value = CFDictionaryGetValue(policy->_options, key);
2418 DERItem key_value;
2419 key_value.data = NULL;
2420 key_value.length = 0;
2421
2422 if (CFGetTypeID(value) == CFDataGetTypeID())
2423 {
2424 CFDataRef key_data = (CFDataRef)value;
2425 key_value.data = (DERByte *)CFDataGetBytePtr(key_data);
2426 key_value.length = (DERSize)CFDataGetLength(key_data);
2427
2428 for (ix = 0; ix < count; ix++) {
2429 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix);
2430 policy_set_t policies = policies_for_cert(cert);
2431
2432 if (policy_set_contains(policies, &key_value)) {
2433 return;
2434 }
2435 }
2436 SecPVCSetResult(pvc, key, 0, kCFBooleanFalse);
2437 }
2438 }
2439
2440
2441 static void SecPolicyCheckRevocation(SecPVCRef pvc,
2442 CFStringRef key) {
2443 SecPVCSetCheckRevocation(pvc);
2444 }
2445
2446 static void SecPolicyCheckRevocationResponseRequired(SecPVCRef pvc,
2447 CFStringRef key) {
2448 SecPVCSetCheckRevocationResponseRequired(pvc);
2449 }
2450
2451 static void SecPolicyCheckNoNetworkAccess(SecPVCRef pvc,
2452 CFStringRef key) {
2453 SecPathBuilderSetCanAccessNetwork(pvc->builder, false);
2454 }
2455
2456 static void SecPolicyCheckWeakIntermediates(SecPVCRef pvc,
2457 CFStringRef key) {
2458 CFIndex ix, count = SecPVCGetCertificateCount(pvc);
2459 for (ix = 1; ix < count - 1; ++ix) {
2460 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix);
2461 if (cert && SecCertificateIsWeak(cert)) {
2462 /* Intermediate certificate has a weak key. */
2463 if (!SecPVCSetResult(pvc, key, ix, kCFBooleanFalse))
2464 return;
2465 }
2466 }
2467 }
2468
2469 static void SecPolicyCheckWeakLeaf(SecPVCRef pvc,
2470 CFStringRef key) {
2471 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, 0);
2472 if (cert && SecCertificateIsWeak(cert)) {
2473 /* Leaf certificate has a weak key. */
2474 if (!SecPVCSetResult(pvc, key, 0, kCFBooleanFalse))
2475 return;
2476 }
2477 }
2478
2479 static void SecPolicyCheckWeakRoot(SecPVCRef pvc,
2480 CFStringRef key) {
2481 CFIndex ix, count = SecPVCGetCertificateCount(pvc);
2482 ix = count - 1;
2483 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix);
2484 if (cert && SecCertificateIsWeak(cert)) {
2485 /* Root certificate has a weak key. */
2486 if (!SecPVCSetResult(pvc, key, ix, kCFBooleanFalse))
2487 return;
2488 }
2489 }
2490
2491 // MARK: -
2492 // MARK: SecRVCRef
2493 /********************************************************
2494 ****************** SecRVCRef Functions *****************
2495 ********************************************************/
2496
2497 const CFAbsoluteTime kSecDefaultOCSPResponseTTL = 24.0 * 60.0 * 60.0;
2498
2499 /* Revocation verification context. */
2500 struct OpaqueSecRVC {
2501 /* Will contain the response data. */
2502 asynchttp_t http;
2503
2504 /* Pointer to the pvc for this revocation check. */
2505 SecPVCRef pvc;
2506
2507 /* The ocsp request we send to each responder. */
2508 SecOCSPRequestRef ocspRequest;
2509
2510 /* The freshest response we received so far, from stapling or cache or responder. */
2511 SecOCSPResponseRef ocspResponse;
2512
2513 /* The best validated candidate single response we received so far, from stapling or cache or responder. */
2514 SecOCSPSingleResponseRef ocspSingleResponse;
2515
2516 /* Index of cert in pvc that this RVC is for 0 = leaf, etc. */
2517 CFIndex certIX;
2518
2519 /* Index in array returned by SecCertificateGetOCSPResponders() for current
2520 responder. */
2521 CFIndex responderIX;
2522
2523 /* URL of current responder. */
2524 CFURLRef responder;
2525
2526 /* Date until which this revocation status is valid. */
2527 CFAbsoluteTime nextUpdate;
2528
2529 bool done;
2530 };
2531 typedef struct OpaqueSecRVC *SecRVCRef;
2532
2533 static void SecRVCDelete(SecRVCRef rvc) {
2534 secdebug("alloc", "%p", rvc);
2535 asynchttp_free(&rvc->http);
2536 SecOCSPRequestFinalize(rvc->ocspRequest);
2537 if (rvc->ocspResponse) {
2538 SecOCSPResponseFinalize(rvc->ocspResponse);
2539 rvc->ocspResponse = NULL;
2540 if (rvc->ocspSingleResponse) {
2541 SecOCSPSingleResponseDestroy(rvc->ocspSingleResponse);
2542 rvc->ocspSingleResponse = NULL;
2543 }
2544 }
2545 }
2546
2547 /* Return the next responder we should contact for this rvc or NULL if we
2548 exhausted them all. */
2549 static CFURLRef SecRVCGetNextResponder(SecRVCRef rvc) {
2550 SecCertificateRef cert = SecPVCGetCertificateAtIndex(rvc->pvc, rvc->certIX);
2551 CFArrayRef ocspResponders = SecCertificateGetOCSPResponders(cert);
2552 if (ocspResponders) {
2553 CFIndex responderCount = CFArrayGetCount(ocspResponders);
2554 while (rvc->responderIX < responderCount) {
2555 CFURLRef responder = CFArrayGetValueAtIndex(ocspResponders, rvc->responderIX);
2556 rvc->responderIX++;
2557 CFStringRef scheme = CFURLCopyScheme(responder);
2558 if (scheme) {
2559 /* We only support http and https responders currently. */
2560 bool valid_responder = (CFEqual(CFSTR("http"), scheme) ||
2561 CFEqual(CFSTR("https"), scheme));
2562 CFRelease(scheme);
2563 if (valid_responder)
2564 return responder;
2565 }
2566 }
2567 }
2568 return NULL;
2569 }
2570
2571 /* Fire off an async http request for this certs revocation status, return
2572 false if request was queued, true if we're done. */
2573 static bool SecRVCFetchNext(SecRVCRef rvc) {
2574 while ((rvc->responder = SecRVCGetNextResponder(rvc))) {
2575 CFDataRef request = SecOCSPRequestGetDER(rvc->ocspRequest);
2576 if (!request)
2577 goto errOut;
2578
2579 secdebug("ocsp", "Sending http ocsp request for cert %ld", rvc->certIX);
2580 if (!asyncHttpPost(rvc->responder, request, &rvc->http)) {
2581 /* Async request was posted, wait for reply. */
2582 return false;
2583 }
2584 }
2585
2586 errOut:
2587 rvc->done = true;
2588 return true;
2589 }
2590
2591 /* Process a verified ocsp response for a given cert. Return true if the
2592 certificate status was obtained. */
2593 static bool SecOCSPSingleResponseProcess(SecOCSPSingleResponseRef this,
2594 SecRVCRef rvc) {
2595 bool processed;
2596 switch (this->certStatus) {
2597 case CS_Good:
2598 secdebug("ocsp", "CS_Good for cert %" PRIdCFIndex, rvc->certIX);
2599 /* @@@ Mark cert as valid until a given date (nextUpdate if we have one)
2600 in the info dictionary. */
2601 //cert.revokeCheckGood(true);
2602 rvc->nextUpdate = this->nextUpdate == NULL_TIME ? this->thisUpdate + kSecDefaultOCSPResponseTTL : this->nextUpdate;
2603 processed = true;
2604 break;
2605 case CS_Revoked:
2606 secdebug("ocsp", "CS_Revoked for cert %" PRIdCFIndex, rvc->certIX);
2607 /* @@@ Mark cert as revoked (with reason) at revocation date in
2608 the info dictionary, or perhaps we should use a different key per
2609 reason? That way a client using exceptions can ignore some but
2610 not all reasons. */
2611 SInt32 reason = this->crlReason;
2612 CFNumberRef cfreason = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &reason);
2613 SecPVCSetResultForced(rvc->pvc, kSecPolicyCheckRevocation, rvc->certIX,
2614 cfreason, true);
2615 if (rvc->pvc && rvc->pvc->info) {
2616 /* make the revocation reason available in the trust result */
2617 CFDictionarySetValue(rvc->pvc->info, kSecTrustRevocationReason, cfreason);
2618 }
2619 CFRelease(cfreason);
2620 processed = true;
2621 break;
2622 case CS_Unknown:
2623 /* not an error, no per-cert status, nothing here */
2624 secdebug("ocsp", "CS_Unknown for cert %" PRIdCFIndex, rvc->certIX);
2625 processed = false;
2626 break;
2627 default:
2628 secdebug("ocsp", "BAD certStatus (%d) for cert %" PRIdCFIndex,
2629 (int)this->certStatus, rvc->certIX);
2630 processed = false;
2631 break;
2632 }
2633
2634 return processed;
2635 }
2636
2637 static void SecRVCUpdatePVC(SecRVCRef rvc) {
2638 if (rvc->ocspSingleResponse) {
2639 SecOCSPSingleResponseProcess(rvc->ocspSingleResponse, rvc);
2640 }
2641 if (rvc->ocspResponse) {
2642 rvc->nextUpdate = SecOCSPResponseGetExpirationTime(rvc->ocspResponse);
2643 }
2644 }
2645
2646 static bool SecOCSPResponseVerify(SecOCSPResponseRef ocspResponse, SecRVCRef rvc, CFAbsoluteTime verifyTime) {
2647 bool trusted;
2648 SecCertificatePathRef issuer = SecCertificatePathCopyFromParent(rvc->pvc->path, rvc->certIX + 1);
2649 SecCertificatePathRef signer = SecOCSPResponseCopySigner(ocspResponse, issuer);
2650 CFRelease(issuer);
2651
2652 if (signer) {
2653 if (signer == issuer) {
2654 /* We already know we trust issuer since it's the path we are
2655 trying to verify minus the leaf. */
2656 secdebug("ocsp", "ocsp responder: %@ response signed by issuer",
2657 rvc->responder);
2658 trusted = true;
2659 } else {
2660 secdebug("ocsp",
2661 "ocsp responder: %@ response signed by cert issued by issuer",
2662 rvc->responder);
2663 /* @@@ Now check that we trust signer. */
2664 const void *ocspSigner = SecPolicyCreateOCSPSigner();
2665 CFArrayRef policies = CFArrayCreate(kCFAllocatorDefault,
2666 &ocspSigner, 1, &kCFTypeArrayCallBacks);
2667 CFRelease(ocspSigner);
2668 struct OpaqueSecPVC ospvc;
2669 SecPVCInit(&ospvc, rvc->pvc->builder, policies, verifyTime);
2670 CFRelease(policies);
2671 SecPVCSetPath(&ospvc, signer, NULL);
2672 SecPVCLeafChecks(&ospvc);
2673 if (ospvc.result) {
2674 bool completed = SecPVCPathChecks(&ospvc);
2675 /* If completed is false we are waiting for a callback, this
2676 shouldn't happen since we aren't asking for details, no
2677 revocation checking is done. */
2678 if (!completed) {
2679 ocspdErrorLog("SecPVCPathChecks unexpectedly started "
2680 "background job!");
2681 /* @@@ assert() or abort here perhaps? */
2682 }
2683 }
2684 if (ospvc.result) {
2685 secdebug("ocsp", "response satisfies ocspSigner policy (%@)",
2686 rvc->responder);
2687 trusted = true;
2688 } else {
2689 /* @@@ We don't trust the cert so don't use this response. */
2690 ocspdErrorLog("ocsp response signed by certificate which "
2691 "does not satisfy ocspSigner policy");
2692 trusted = false;
2693 }
2694 SecPVCDelete(&ospvc);
2695 }
2696
2697 CFRelease(signer);
2698 } else {
2699 /* @@@ No signer found for this ocsp response, discard it. */
2700 secdebug("ocsp", "ocsp responder: %@ no signer found for response",
2701 rvc->responder);
2702 trusted = false;
2703 }
2704
2705 #if DUMP_OCSPRESPONSES
2706 char buf[40];
2707 snprintf(buf, 40, "/tmp/ocspresponse%ld%s.der",
2708 rvc->certIX, (trusted ? "t" : "u"));
2709 secdumpdata(ocspResponse->data, buf);
2710 #endif
2711
2712 return trusted;
2713 }
2714
2715 static void SecRVCConsumeOCSPResponse(SecRVCRef rvc, SecOCSPResponseRef ocspResponse /*CF_CONSUMED*/, CFTimeInterval maxAge, bool updateCache) {
2716 SecOCSPSingleResponseRef sr = NULL;
2717 require_quiet(ocspResponse, errOut);
2718 SecOCSPResponseStatus orStatus = SecOCSPGetResponseStatus(ocspResponse);
2719 require_action_quiet(orStatus == kSecOCSPSuccess, errOut,
2720 secdebug("ocsp", "responder: %@ returned status: %d", rvc->responder, orStatus));
2721 require_action_quiet(sr = SecOCSPResponseCopySingleResponse(ocspResponse, rvc->ocspRequest), errOut,
2722 secdebug("ocsp", "ocsp responder: %@ did not include status of requested cert", rvc->responder));
2723 // Check if this response is fresher than any (cached) response we might still have in the rvc.
2724 require_quiet(!rvc->ocspSingleResponse || rvc->ocspSingleResponse->thisUpdate < sr->thisUpdate, errOut);
2725
2726 CFAbsoluteTime verifyTime = CFAbsoluteTimeGetCurrent();
2727 /* TODO: If the responder doesn't have the ocsp-nocheck extension we should
2728 check whether the leaf was revoked (we are already checking the rest of
2729 the chain). */
2730 /* Check the OCSP response signature and verify the response. */
2731 require_quiet(SecOCSPResponseVerify(ocspResponse, rvc,
2732 sr->certStatus == CS_Revoked ? SecOCSPResponseProducedAt(ocspResponse) : verifyTime), errOut);
2733
2734 // If we get here, we have a properly signed ocsp response
2735 // but we haven't checked dates yet.
2736
2737 bool sr_valid = SecOCSPSingleResponseCalculateValidity(sr, kSecDefaultOCSPResponseTTL, verifyTime);
2738 if (sr->certStatus == CS_Good) {
2739 // Side effect of SecOCSPResponseCalculateValidity sets ocspResponse->expireTime
2740 require_quiet(sr_valid && SecOCSPResponseCalculateValidity(ocspResponse, maxAge, kSecDefaultOCSPResponseTTL, verifyTime), errOut);
2741 } else if (sr->certStatus == CS_Revoked) {
2742 // Expire revoked responses when the subject certificate itself expires.
2743 ocspResponse->expireTime = SecCertificateNotValidAfter(SecPVCGetCertificateAtIndex(rvc->pvc, rvc->certIX));
2744 }
2745
2746 // Ok we like the new response, let's toss the old one.
2747 if (updateCache)
2748 SecOCSPCacheReplaceResponse(rvc->ocspResponse, ocspResponse, rvc->responder, verifyTime);
2749
2750 if (rvc->ocspResponse) SecOCSPResponseFinalize(rvc->ocspResponse);
2751 rvc->ocspResponse = ocspResponse;
2752 ocspResponse = NULL;
2753
2754 if (rvc->ocspSingleResponse) SecOCSPSingleResponseDestroy(rvc->ocspSingleResponse);
2755 rvc->ocspSingleResponse = sr;
2756 sr = NULL;
2757
2758 rvc->done = sr_valid;
2759
2760 errOut:
2761 if (sr) SecOCSPSingleResponseDestroy(sr);
2762 if (ocspResponse) SecOCSPResponseFinalize(ocspResponse);
2763 }
2764
2765 /* Callback from async http code after an ocsp response has been received. */
2766 static void SecOCSPFetchCompleted(asynchttp_t *http, CFTimeInterval maxAge) {
2767 SecRVCRef rvc = (SecRVCRef)http->info;
2768 SecPVCRef pvc = rvc->pvc;
2769 SecOCSPResponseRef ocspResponse = NULL;
2770 if (http->response) {
2771 CFDataRef data = CFHTTPMessageCopyBody(http->response);
2772 if (data) {
2773 /* Parse the returned data as if it's an ocspResponse. */
2774 ocspResponse = SecOCSPResponseCreate(data);
2775 CFRelease(data);
2776 }
2777 }
2778
2779 SecRVCConsumeOCSPResponse(rvc, ocspResponse, maxAge, true);
2780 // TODO: maybe we should set the cache-control: false in the http header and try again if the response is stale
2781
2782 if (!rvc->done) {
2783 /* Clear the data for the next response. */
2784 asynchttp_free(http);
2785 SecRVCFetchNext(rvc);
2786 }
2787
2788 if (rvc->done) {
2789 SecRVCUpdatePVC(rvc);
2790 SecRVCDelete(rvc);
2791 if (!--pvc->asyncJobCount) {
2792 SecPathBuilderStep(pvc->builder);
2793 }
2794 }
2795 }
2796
2797 static void SecRVCInit(SecRVCRef rvc, SecPVCRef pvc, CFIndex certIX) {
2798 secdebug("alloc", "%p", rvc);
2799 rvc->pvc = pvc;
2800 rvc->certIX = certIX;
2801 rvc->http.queue = SecPathBuilderGetQueue(pvc->builder);
2802 rvc->http.token = SecPathBuilderCopyClientAuditToken(pvc->builder);
2803 rvc->http.completed = SecOCSPFetchCompleted;
2804 rvc->http.info = rvc;
2805 rvc->ocspRequest = NULL;
2806 rvc->responderIX = 0;
2807 rvc->responder = NULL;
2808 rvc->nextUpdate = NULL_TIME;
2809 rvc->ocspResponse = NULL;
2810 rvc->ocspSingleResponse = NULL;
2811 rvc->done = false;
2812 }
2813
2814
2815 static bool SecPVCCheckRevocation(SecPVCRef pvc) {
2816 secdebug("ocsp", "checking revocation");
2817 CFIndex certIX, certCount = SecPVCGetCertificateCount(pvc);
2818 bool completed = true;
2819 if (certCount <= 1) {
2820 /* Can't verify without an issuer; we're done */
2821 return completed;
2822 }
2823 if (!SecPVCIsAnchored(pvc)) {
2824 /* We can't check revocation for chains without a trusted anchor. */
2825 return completed;
2826 }
2827 certCount--;
2828
2829 #if 0
2830 /* TODO: Implement getting this value from the client.
2831 Optional responder passed in though policy. */
2832 CFURLRef localResponder = NULL;
2833 /* Generate a nonce in outgoing request if true. */
2834 bool genNonce = false;
2835 /* Require a nonce in response if true. */
2836 bool requireRespNonce = false;
2837 bool cacheReadDisable = false;
2838 bool cacheWriteDisable = false;
2839 #endif
2840
2841 if (pvc->rvcs) {
2842 /* We have done revocation checking already, we're done. */
2843 secdebug("ocsp", "Not rechecking revocation");
2844 return completed;
2845 }
2846
2847 /* Setup things so we check revocation status of all certs except the
2848 anchor. */
2849 pvc->rvcs = calloc(sizeof(struct OpaqueSecRVC), certCount);
2850
2851 #if 0
2852 /* Lookup cached revocation data for each certificate. */
2853 for (certIX = 0; certIX < certCount; ++certIX) {
2854 SecCertificateRef cert = SecPVCGetCertificateAtIndex(rvc->pvc, rvc->certIX);
2855 CFArrayRef ocspResponders = SecCertificateGetOCSPResponders(cert);
2856 if (ocspResponders) {
2857 /* First look though passed in ocsp responses. */
2858 //SecPVCGetOCSPResponseForCertificateAtIndex(pvc, ix, singleResponse);
2859
2860 /* Then look though shared cache (we don't care which responder
2861 something came from here). */
2862 CFDataRef ocspResponse = SecOCSPCacheCopyMatching(SecCertIDRef certID, NULL);
2863
2864 /* Now let's parse the response. */
2865 if (decodeOCSPResponse(ocspResp)) {
2866 secdebug("ocsp", "response ok: %@", ocspResp);
2867 } else {
2868 secdebug("ocsp", "response bad: %@", ocspResp);
2869 /* ocsp response not ok. */
2870 if (!SecPVCSetResultForced(pvc, key, ix, kCFBooleanFalse, true))
2871 return completed;
2872 }
2873 CFReleaseSafe(ocspResp);
2874 } else {
2875 /* Check if certificate has any crl distributionPoints. */
2876 CFArrayRef distributionPoints = SecCertificateGetCRLDistributionPoints(cert);
2877 if (distributionPoints) {
2878 /* Look for a cached CRL and potentially delta CRL for this certificate. */
2879 }
2880 }
2881 }
2882 #endif
2883
2884 /* Note that if we are multi threaded and a job completes after it
2885 is started but before we return from this function, we don't want
2886 a callback to decrement asyncJobCount to zero before we finish issuing
2887 all the jobs. To avoid this we pretend we issued certCount async jobs,
2888 and decrement pvc->asyncJobCount for each cert that we don't start a
2889 background fetch for. */
2890 pvc->asyncJobCount = (unsigned int) certCount;
2891
2892 /* Loop though certificates again and issue an ocsp fetch if the
2893 revocation status checking isn't done yet. */
2894 for (certIX = 0; certIX < certCount; ++certIX) {
2895 secdebug("ocsp", "checking revocation for cert: %ld", certIX);
2896 SecRVCRef rvc = &((SecRVCRef)pvc->rvcs)[certIX];
2897 SecRVCInit(rvc, pvc, certIX);
2898 if (rvc->done)
2899 continue;
2900
2901 SecCertificateRef cert = SecPVCGetCertificateAtIndex(rvc->pvc,
2902 rvc->certIX);
2903 /* The certIX + 1 is ok here since certCount is always at least 1
2904 less than the actual number of certs. */
2905 SecCertificateRef issuer = SecPVCGetCertificateAtIndex(rvc->pvc,
2906 rvc->certIX + 1);
2907
2908 rvc->ocspRequest = SecOCSPRequestCreate(cert, issuer);
2909
2910 /* Get stapled OCSP responses */
2911 CFArrayRef ocspResponsesData = SecPathBuilderCopyOCSPResponses(pvc->builder);
2912
2913 /* If we have any OCSP stapled responses, check those first */
2914 if(ocspResponsesData) {
2915 secdebug("ocsp", "Checking stapled responses for cert %ld", certIX);
2916 CFArrayForEach(ocspResponsesData, ^(const void *value) {
2917 /* TODO: Should the builder already have the appropriate SecOCSPResponseRef ? */
2918 SecOCSPResponseRef ocspResponse = SecOCSPResponseCreate(value);
2919 SecRVCConsumeOCSPResponse(rvc, ocspResponse, NULL_TIME, false);
2920 });
2921 CFRelease(ocspResponsesData);
2922 }
2923
2924 /* Then check the cached response */
2925 secdebug("ocsp", "Checking cached responses for cert %ld", certIX);
2926 SecRVCConsumeOCSPResponse(rvc, SecOCSPCacheCopyMatching(rvc->ocspRequest, NULL), NULL_TIME, false);
2927
2928 /* If the cert is EV or if revocation checking was explicitly enabled, attempt to fire off an
2929 async http request for this cert's revocation status, unless we already successfully checked
2930 the revocation status of this cert based on the cache or stapled responses, */
2931 bool allow_fetch = SecPathBuilderCanAccessNetwork(pvc->builder) && (pvc->is_ev || pvc->check_revocation);
2932 bool fetch_done = true;
2933 if (rvc->done || !allow_fetch ||
2934 (fetch_done = SecRVCFetchNext(rvc))) {
2935 /* We got a cache hit or we aren't allowed to access the network,
2936 or the async http post failed. */
2937 SecRVCUpdatePVC(rvc);
2938 SecRVCDelete(rvc);
2939 /* We didn't really start a background job for this cert. */
2940 pvc->asyncJobCount--;
2941 } else if (!fetch_done) {
2942 /* We started at least one background fetch. */
2943 completed = false;
2944 }
2945 }
2946
2947 /* Return false if we started any background jobs. */
2948 /* We can't just return !pvc->asyncJobCount here, since if we started any
2949 jobs the completion callback will be called eventually and it will call
2950 SecPathBuilderStep(). If for some reason everything completed before we
2951 get here we still want the outer SecPathBuilderStep() to terminate so we
2952 keep track of whether we started any jobs and return false if so. */
2953 return completed;
2954 }
2955
2956
2957 void SecPolicyServerInitalize(void) {
2958 gSecPolicyLeafCallbacks = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
2959 &kCFTypeDictionaryKeyCallBacks, NULL);
2960 gSecPolicyPathCallbacks = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
2961 &kCFTypeDictionaryKeyCallBacks, NULL);
2962
2963 CFDictionaryAddValue(gSecPolicyPathCallbacks,
2964 kSecPolicyCheckBasicCertificateProcessing,
2965 SecPolicyCheckBasicCertificateProcessing);
2966 CFDictionaryAddValue(gSecPolicyPathCallbacks,
2967 kSecPolicyCheckCriticalExtensions,
2968 SecPolicyCheckCriticalExtensions);
2969 CFDictionaryAddValue(gSecPolicyPathCallbacks,
2970 kSecPolicyCheckIdLinkage,
2971 SecPolicyCheckIdLinkage);
2972 CFDictionaryAddValue(gSecPolicyLeafCallbacks,
2973 kSecPolicyCheckKeyUsage,
2974 SecPolicyCheckKeyUsage);
2975 CFDictionaryAddValue(gSecPolicyLeafCallbacks,
2976 kSecPolicyCheckExtendedKeyUsage,
2977 SecPolicyCheckExtendedKeyUsage);
2978 CFDictionaryAddValue(gSecPolicyLeafCallbacks,
2979 kSecPolicyCheckBasicContraints,
2980 SecPolicyCheckBasicContraints);
2981 CFDictionaryAddValue(gSecPolicyLeafCallbacks,
2982 kSecPolicyCheckNonEmptySubject,
2983 SecPolicyCheckNonEmptySubject);
2984 CFDictionaryAddValue(gSecPolicyLeafCallbacks,
2985 kSecPolicyCheckQualifiedCertStatements,
2986 SecPolicyCheckQualifiedCertStatements);
2987 CFDictionaryAddValue(gSecPolicyLeafCallbacks,
2988 kSecPolicyCheckSSLHostname,
2989 SecPolicyCheckSSLHostname);
2990 CFDictionaryAddValue(gSecPolicyLeafCallbacks,
2991 kSecPolicyCheckEmail,
2992 SecPolicyCheckEmail);
2993 CFDictionaryAddValue(gSecPolicyPathCallbacks,
2994 kSecPolicyCheckValidIntermediates,
2995 SecPolicyCheckValidIntermediates);
2996 CFDictionaryAddValue(gSecPolicyLeafCallbacks,
2997 kSecPolicyCheckValidLeaf,
2998 SecPolicyCheckValidLeaf);
2999 CFDictionaryAddValue(gSecPolicyPathCallbacks,
3000 kSecPolicyCheckValidRoot,
3001 SecPolicyCheckValidRoot);
3002 CFDictionaryAddValue(gSecPolicyPathCallbacks,
3003 kSecPolicyCheckIssuerCommonName,
3004 SecPolicyCheckIssuerCommonName);
3005 CFDictionaryAddValue(gSecPolicyLeafCallbacks,
3006 kSecPolicyCheckSubjectCommonNamePrefix,
3007 SecPolicyCheckSubjectCommonNamePrefix);
3008 CFDictionaryAddValue(gSecPolicyLeafCallbacks,
3009 kSecPolicyCheckSubjectCommonName,
3010 SecPolicyCheckSubjectCommonName);
3011 CFDictionaryAddValue(gSecPolicyLeafCallbacks,
3012 kSecPolicyCheckNotValidBefore,
3013 SecPolicyCheckNotValidBefore);
3014 CFDictionaryAddValue(gSecPolicyPathCallbacks,
3015 kSecPolicyCheckChainLength,
3016 SecPolicyCheckChainLength);
3017 CFDictionaryAddValue(gSecPolicyPathCallbacks,
3018 kSecPolicyCheckAnchorSHA1,
3019 SecPolicyCheckAnchorSHA1);
3020 CFDictionaryAddValue(gSecPolicyPathCallbacks,
3021 kSecPolicyCheckIntermediateSPKISHA256,
3022 SecPolicyCheckIntermediateSPKISHA256);
3023 CFDictionaryAddValue(gSecPolicyPathCallbacks,
3024 kSecPolicyCheckAnchorApple,
3025 SecPolicyCheckAnchorApple);
3026 CFDictionaryAddValue(gSecPolicyLeafCallbacks,
3027 kSecPolicyCheckSubjectOrganization,
3028 SecPolicyCheckSubjectOrganization);
3029 CFDictionaryAddValue(gSecPolicyLeafCallbacks,
3030 kSecPolicyCheckSubjectOrganizationalUnit,
3031 SecPolicyCheckSubjectOrganizationalUnit);
3032 CFDictionaryAddValue(gSecPolicyLeafCallbacks,
3033 kSecPolicyCheckEAPTrustedServerNames,
3034 SecPolicyCheckEAPTrustedServerNames);
3035 CFDictionaryAddValue(gSecPolicyLeafCallbacks,
3036 kSecPolicyCheckSubjectCommonNameTEST,
3037 SecPolicyCheckSubjectCommonNameTEST);
3038 CFDictionaryAddValue(gSecPolicyLeafCallbacks,
3039 kSecPolicyCheckRevocation,
3040 SecPolicyCheckRevocation);
3041 CFDictionaryAddValue(gSecPolicyLeafCallbacks,
3042 kSecPolicyCheckRevocationResponseRequired,
3043 SecPolicyCheckRevocationResponseRequired);
3044 CFDictionaryAddValue(gSecPolicyLeafCallbacks,
3045 kSecPolicyCheckNoNetworkAccess,
3046 SecPolicyCheckNoNetworkAccess);
3047 CFDictionaryAddValue(gSecPolicyLeafCallbacks,
3048 kSecPolicyCheckBlackListedLeaf,
3049 SecPolicyCheckBlackListedLeaf);
3050 CFDictionaryAddValue(gSecPolicyLeafCallbacks,
3051 kSecPolicyCheckGrayListedLeaf,
3052 SecPolicyCheckGrayListedLeaf);
3053 CFDictionaryAddValue(gSecPolicyLeafCallbacks,
3054 kSecPolicyCheckLeafMarkerOid,
3055 SecPolicyCheckLeafMarkerOid);
3056 CFDictionaryAddValue(gSecPolicyPathCallbacks,
3057 kSecPolicyCheckIntermediateMarkerOid,
3058 SecPolicyCheckIntermediateMarkerOid);
3059 CFDictionaryAddValue(gSecPolicyLeafCallbacks,
3060 kSecPolicyCheckCertificatePolicy,
3061 SecPolicyCheckCertificatePolicyOid);
3062 CFDictionaryAddValue(gSecPolicyPathCallbacks,
3063 kSecPolicyCheckWeakIntermediates,
3064 SecPolicyCheckWeakIntermediates);
3065 CFDictionaryAddValue(gSecPolicyLeafCallbacks,
3066 kSecPolicyCheckWeakLeaf,
3067 SecPolicyCheckWeakLeaf);
3068 CFDictionaryAddValue(gSecPolicyPathCallbacks,
3069 kSecPolicyCheckWeakRoot,
3070 SecPolicyCheckWeakRoot);
3071 }
3072
3073 /* AUDIT[securityd](done):
3074 array (ok) is a caller provided array, only its cf type has
3075 been checked.
3076 The options (ok) field ends up in policy->_options unchecked, so every access
3077 of policy->_options needs to be validated.
3078 */
3079 static SecPolicyRef SecPolicyCreateWithArray(CFArrayRef array) {
3080 SecPolicyRef policy = NULL;
3081 require_quiet(array && CFArrayGetCount(array) == 2, errOut);
3082 CFStringRef oid = (CFStringRef)CFArrayGetValueAtIndex(array, 0);
3083 require_quiet(isString(oid), errOut);
3084 CFDictionaryRef options = (CFDictionaryRef)CFArrayGetValueAtIndex(array, 1);
3085 require_quiet(isDictionary(options), errOut);
3086 policy = SecPolicyCreate(oid, options);
3087 errOut:
3088 return policy;
3089 }
3090
3091 /* AUDIT[securityd](done):
3092 value (ok) is an element in a caller provided array.
3093 */
3094 static void deserializePolicy(const void *value, void *context) {
3095 CFArrayRef policyArray = (CFArrayRef)value;
3096 if (isArray(policyArray)) {
3097 CFTypeRef deserializedPolicy = SecPolicyCreateWithArray(policyArray);
3098 if (deserializedPolicy) {
3099 CFArrayAppendValue((CFMutableArrayRef)context, deserializedPolicy);
3100 CFRelease(deserializedPolicy);
3101 }
3102 }
3103 }
3104
3105 /* AUDIT[securityd](done):
3106 serializedPolicies (ok) is a caller provided array, only its cf type has
3107 been checked.
3108 */
3109 CFArrayRef SecPolicyArrayDeserialize(CFArrayRef serializedPolicies) {
3110 CFMutableArrayRef result = NULL;
3111 require_quiet(isArray(serializedPolicies), errOut);
3112 CFIndex count = CFArrayGetCount(serializedPolicies);
3113 result = CFArrayCreateMutable(kCFAllocatorDefault, count, &kCFTypeArrayCallBacks);
3114 CFRange all_policies = { 0, count };
3115 CFArrayApplyFunction(serializedPolicies, all_policies, deserializePolicy, result);
3116 errOut:
3117 return result;
3118 }
3119
3120 // MARK: -
3121 // MARK: SecPVCRef
3122 /********************************************************
3123 ****************** SecPVCRef Functions *****************
3124 ********************************************************/
3125
3126 void SecPVCInit(SecPVCRef pvc, SecPathBuilderRef builder, CFArrayRef policies,
3127 CFAbsoluteTime verifyTime) {
3128 secdebug("alloc", "%p", pvc);
3129 // Weird logging policies crashes.
3130 //secdebug("policy", "%@", policies);
3131 pvc->builder = builder;
3132 pvc->policies = policies;
3133 if (policies)
3134 CFRetain(policies);
3135 pvc->verifyTime = verifyTime;
3136 pvc->path = NULL;
3137 pvc->details = NULL;
3138 pvc->info = NULL;
3139 pvc->valid_policy_tree = NULL;
3140 pvc->callbacks = NULL;
3141 pvc->policyIX = 0;
3142 pvc->rvcs = NULL;
3143 pvc->asyncJobCount = 0;
3144 pvc->check_revocation = false;
3145 pvc->response_required = false;
3146 pvc->optionally_ev = false;
3147 pvc->is_ev = false;
3148 pvc->result = true;
3149 }
3150
3151 static void SecPVCDeleteRVCs(SecPVCRef pvc) {
3152 secdebug("alloc", "%p", pvc);
3153 if (pvc->rvcs) {
3154 free(pvc->rvcs);
3155 pvc->rvcs = NULL;
3156 }
3157 }
3158
3159 void SecPVCDelete(SecPVCRef pvc) {
3160 secdebug("alloc", "%p", pvc);
3161 CFReleaseNull(pvc->policies);
3162 CFReleaseNull(pvc->details);
3163 CFReleaseNull(pvc->info);
3164 if (pvc->valid_policy_tree) {
3165 policy_tree_prune(&pvc->valid_policy_tree);
3166 }
3167 SecPVCDeleteRVCs(pvc);
3168 }
3169
3170 void SecPVCSetPath(SecPVCRef pvc, SecCertificatePathRef path,
3171 CF_CONSUMED CFArrayRef details) {
3172 secdebug("policy", "%@", path);
3173 if (pvc->path != path) {
3174 /* Changing path makes us clear the Revocation Verification Contexts */
3175 SecPVCDeleteRVCs(pvc);
3176 pvc->path = path;
3177 }
3178 pvc->details = details;
3179 CFReleaseNull(pvc->info);
3180 if (pvc->valid_policy_tree) {
3181 policy_tree_prune(&pvc->valid_policy_tree);
3182 }
3183 pvc->policyIX = 0;
3184 pvc->result = true;
3185 }
3186
3187 SecPolicyRef SecPVCGetPolicy(SecPVCRef pvc) {
3188 return (SecPolicyRef)CFArrayGetValueAtIndex(pvc->policies, pvc->policyIX);
3189 }
3190
3191 CFIndex SecPVCGetCertificateCount(SecPVCRef pvc) {
3192 return SecCertificatePathGetCount(pvc->path);
3193 }
3194
3195 SecCertificateRef SecPVCGetCertificateAtIndex(SecPVCRef pvc, CFIndex ix) {
3196 return SecCertificatePathGetCertificateAtIndex(pvc->path, ix);
3197 }
3198
3199 bool SecPVCIsCertificateAtIndexSelfSigned(SecPVCRef pvc, CFIndex ix) {
3200 return SecCertificatePathSelfSignedIndex(pvc->path) == ix;
3201 }
3202
3203 void SecPVCSetCheckRevocation(SecPVCRef pvc) {
3204 pvc->check_revocation = true;
3205 secdebug("ocsp", "deferred revocation checking enabled");
3206 }
3207
3208 void SecPVCSetCheckRevocationResponseRequired(SecPVCRef pvc) {
3209 pvc->response_required = true;
3210 secdebug("ocsp", "revocation response required");
3211 }
3212
3213 bool SecPVCIsAnchored(SecPVCRef pvc) {
3214 return SecCertificatePathIsAnchored(pvc->path);
3215 }
3216
3217 CFAbsoluteTime SecPVCGetVerifyTime(SecPVCRef pvc) {
3218 return pvc->verifyTime;
3219 }
3220
3221 /* AUDIT[securityd](done):
3222 policy->_options is a caller provided dictionary, only its cf type has
3223 been checked.
3224 */
3225 bool SecPVCSetResultForced(SecPVCRef pvc,
3226 CFStringRef key, CFIndex ix, CFTypeRef result, bool force) {
3227
3228 secdebug("policy", "cert[%d]: %@ =(%s)[%s]> %@", (int) ix, key,
3229 (pvc->callbacks == gSecPolicyLeafCallbacks ? "leaf"
3230 : (pvc->callbacks == gSecPolicyPathCallbacks ? "path"
3231 : "custom")),
3232 (force ? "force" : ""), result);
3233
3234 /* If this is not something the current policy cares about ignore
3235 this error and return true so our caller continues evaluation. */
3236 if (!force) {
3237 /* @@@ The right long term fix might be to check if none of the passed
3238 in policies contain this key, since not all checks are run for all
3239 policies. */
3240 SecPolicyRef policy = SecPVCGetPolicy(pvc);
3241 if (policy && !CFDictionaryContainsKey(policy->_options, key))
3242 return true;
3243 }
3244
3245 /* @@@ Check to see if the SecTrustSettings for the certificate in question
3246 tell us to ignore this error. */
3247 pvc->result = false;
3248 if (!pvc->details)
3249 return false;
3250
3251 CFMutableDictionaryRef detail =
3252 (CFMutableDictionaryRef)CFArrayGetValueAtIndex(pvc->details, ix);
3253
3254 /* Perhaps detail should have an array of results per key? As it stands
3255 in the case of multiple policy failures the last failure stands. */
3256 CFDictionarySetValue(detail, key, result);
3257
3258 return true;
3259 }
3260
3261 bool SecPVCSetResult(SecPVCRef pvc,
3262 CFStringRef key, CFIndex ix, CFTypeRef result) {
3263 return SecPVCSetResultForced(pvc, key, ix, result, false);
3264 }
3265
3266 /* AUDIT[securityd](done):
3267 key(ok) is a caller provided.
3268 value(ok, unused) is a caller provided.
3269 */
3270 static void SecPVCValidateKey(const void *key, const void *value,
3271 void *context) {
3272 SecPVCRef pvc = (SecPVCRef)context;
3273
3274 /* If our caller doesn't want full details and we failed earlier there is
3275 no point in doing additional checks. */
3276 if (!pvc->result && !pvc->details)
3277 return;
3278
3279 SecPolicyCheckFunction fcn = (SecPolicyCheckFunction)
3280 CFDictionaryGetValue(pvc->callbacks, key);
3281
3282 if (!fcn) {
3283 #if 0
3284 /* Why not to have optional policy checks rant:
3285 Not all keys are in all dictionaries anymore, so why not make checks
3286 optional? This way a client can ask for something and the server will
3287 do a best effort based on the supported flags. It works since they are
3288 synchronized now, but we need some debug checking here for now. */
3289 pvc->result = false;
3290 #endif
3291 if (pvc->callbacks == gSecPolicyLeafCallbacks) {
3292 if (!CFDictionaryContainsKey(gSecPolicyPathCallbacks, key)) {
3293 pvc->result = false;
3294 }
3295 } else if (pvc->callbacks == gSecPolicyPathCallbacks) {
3296 if (!CFDictionaryContainsKey(gSecPolicyLeafCallbacks, key)) {
3297 pvc->result = false;
3298 }
3299 } else {
3300 /* Non standard validation phase, nothing is optional. */
3301 pvc->result = false;
3302 }
3303 return;
3304 }
3305
3306 fcn(pvc, (CFStringRef)key);
3307 }
3308
3309 /* AUDIT[securityd](done):
3310 policy->_options is a caller provided dictionary, only its cf type has
3311 been checked.
3312 */
3313 bool SecPVCLeafChecks(SecPVCRef pvc) {
3314 pvc->result = true;
3315 CFArrayRef policies = pvc->policies;
3316 CFIndex ix, count = CFArrayGetCount(policies);
3317 for (ix = 0; ix < count; ++ix) {
3318 SecPolicyRef policy = (SecPolicyRef)CFArrayGetValueAtIndex(policies, ix);
3319 pvc->policyIX = ix;
3320 /* Validate all keys for all policies. */
3321 pvc->callbacks = gSecPolicyLeafCallbacks;
3322 CFDictionaryApplyFunction(policy->_options, SecPVCValidateKey, pvc);
3323 if (!pvc->result && !pvc->details)
3324 return pvc->result;
3325 }
3326
3327 return pvc->result;
3328 }
3329
3330 bool SecPVCParentCertificateChecks(SecPVCRef pvc, CFIndex ix) {
3331 /* Check stuff common to intermediate and anchors. */
3332 CFAbsoluteTime verifyTime = SecPVCGetVerifyTime(pvc);
3333 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix);
3334 bool is_anchor = (ix == SecPVCGetCertificateCount(pvc) - 1
3335 && SecPVCIsAnchored(pvc));
3336 if (!SecCertificateIsValid(cert, verifyTime)) {
3337 /* Certificate has expired. */
3338 if (!SecPVCSetResult(pvc, is_anchor ? kSecPolicyCheckValidRoot
3339 : kSecPolicyCheckValidIntermediates, ix, kCFBooleanFalse))
3340 goto errOut;
3341 }
3342
3343 if (SecCertificateIsWeak(cert)) {
3344 /* Certificate uses weak key. */
3345 if (!SecPVCSetResult(pvc, is_anchor ? kSecPolicyCheckWeakRoot
3346 : kSecPolicyCheckWeakIntermediates, ix, kCFBooleanFalse))
3347 goto errOut;
3348 }
3349
3350 if (is_anchor) {
3351 /* Perform anchor specific checks. */
3352 /* Don't think we have any of these. */
3353 } else {
3354 /* Perform intermediate specific checks. */
3355
3356 /* (k) */
3357 const SecCEBasicConstraints *bc =
3358 SecCertificateGetBasicConstraints(cert);
3359 if (!bc || !bc->isCA) {
3360 /* Basic constraints not present or not marked as isCA, illegal. */
3361 if (!SecPVCSetResultForced(pvc, kSecPolicyCheckBasicContraints,
3362 ix, kCFBooleanFalse, true))
3363 goto errOut;
3364 }
3365 /* Consider adding (l) max_path_length checking here. */
3366
3367 /* (n) If a key usage extension is present, verify that the keyCertSign bit is set. */
3368 SecKeyUsage keyUsage = SecCertificateGetKeyUsage(cert);
3369 if (keyUsage && !(keyUsage & kSecKeyUsageKeyCertSign)) {
3370 if (!SecPVCSetResultForced(pvc, kSecPolicyCheckKeyUsage,
3371 ix, kCFBooleanFalse, true))
3372 goto errOut;
3373 }
3374 }
3375
3376 errOut:
3377 return pvc->result;
3378 }
3379
3380 bool SecPVCBlackListedKeyChecks(SecPVCRef pvc, CFIndex ix) {
3381 /* Check stuff common to intermediate and anchors. */
3382
3383 SecOTAPKIRef otapkiRef = SecOTAPKICopyCurrentOTAPKIRef();
3384 if (NULL != otapkiRef)
3385 {
3386 CFSetRef blackListedKeys = SecOTAPKICopyBlackListSet(otapkiRef);
3387 CFRelease(otapkiRef);
3388 if (NULL != blackListedKeys)
3389 {
3390 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix);
3391 bool is_anchor = (ix == SecPVCGetCertificateCount(pvc) - 1
3392 && SecPVCIsAnchored(pvc));
3393 if (!is_anchor) {
3394 /* Check for blacklisted intermediates keys. */
3395 CFDataRef dgst = SecCertificateCopyPublicKeySHA1Digest(cert);
3396 if (dgst) {
3397 /* Check dgst against blacklist. */
3398 if (CFSetContainsValue(blackListedKeys, dgst)) {
3399 SecPVCSetResultForced(pvc, kSecPolicyCheckBlackListedKey,
3400 ix, kCFBooleanFalse, true);
3401 }
3402 CFRelease(dgst);
3403 }
3404 }
3405 CFRelease(blackListedKeys);
3406 return pvc->result;
3407 }
3408 }
3409 // Assume OK
3410 return true;
3411 }
3412
3413 bool SecPVCGrayListedKeyChecks(SecPVCRef pvc, CFIndex ix)
3414 {
3415 /* Check stuff common to intermediate and anchors. */
3416 SecOTAPKIRef otapkiRef = SecOTAPKICopyCurrentOTAPKIRef();
3417 if (NULL != otapkiRef)
3418 {
3419 CFSetRef grayListKeys = SecOTAPKICopyGrayList(otapkiRef);
3420 CFRelease(otapkiRef);
3421 if (NULL != grayListKeys)
3422 {
3423 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix);
3424 bool is_anchor = (ix == SecPVCGetCertificateCount(pvc) - 1
3425 && SecPVCIsAnchored(pvc));
3426 if (!is_anchor) {
3427 /* Check for gray listed intermediates keys. */
3428 CFDataRef dgst = SecCertificateCopyPublicKeySHA1Digest(cert);
3429 if (dgst) {
3430 /* Check dgst against gray list. */
3431 if (CFSetContainsValue(grayListKeys, dgst)) {
3432 SecPVCSetResultForced(pvc, kSecPolicyCheckGrayListedKey,
3433 ix, kCFBooleanFalse, true);
3434 }
3435 CFRelease(dgst);
3436 }
3437 }
3438 CFRelease(grayListKeys);
3439 return pvc->result;
3440 }
3441 }
3442 // Assume ok
3443 return true;
3444 }
3445
3446 /* AUDIT[securityd](done):
3447 policy->_options is a caller provided dictionary, only its cf type has
3448 been checked.
3449 */
3450 bool SecPVCPathChecks(SecPVCRef pvc) {
3451 secdebug("policy", "begin path: %@", pvc->path);
3452 bool completed = true;
3453 /* This needs to be initialized before we call any function that might call
3454 SecPVCSetResultForced(). */
3455 pvc->policyIX = 0;
3456 SecPolicyCheckIdLinkage(pvc, kSecPolicyCheckIdLinkage);
3457 if (pvc->result || pvc->details) {
3458 SecPolicyCheckBasicCertificateProcessing(pvc,
3459 kSecPolicyCheckBasicCertificateProcessing);
3460 }
3461
3462 CFArrayRef policies = pvc->policies;
3463 CFIndex count = CFArrayGetCount(policies);
3464 for (; pvc->policyIX < count; ++pvc->policyIX) {
3465 /* Validate all keys for all policies. */
3466 pvc->callbacks = gSecPolicyPathCallbacks;
3467 SecPolicyRef policy = SecPVCGetPolicy(pvc);
3468 CFDictionaryApplyFunction(policy->_options, SecPVCValidateKey, pvc);
3469 if (!pvc->result && !pvc->details)
3470 return completed;
3471 }
3472
3473 /* Check the things we can't check statically for the certificate path. */
3474 /* Critical Extensions, chainLength. */
3475
3476 /* Policy tests. */
3477 pvc->is_ev = false;
3478 if ((pvc->result || pvc->details) && pvc->optionally_ev) {
3479 bool pre_ev_check_result = pvc->result;
3480 SecPolicyCheckEV(pvc, kSecPolicyCheckExtendedValidation);
3481 pvc->is_ev = pvc->result;
3482 /* If ev checking failed, we still want to accept this chain
3483 as a non EV one, if it was valid as such. */
3484 pvc->result = pre_ev_check_result;
3485 }
3486 /* Check revocation only if the chain is valid so far. The revocation will
3487 only fetch OCSP response over the network if the client asked for revocation
3488 check explicitly or is_ev is true. */
3489 if (pvc->result) {
3490 completed = SecPVCCheckRevocation(pvc);
3491 }
3492
3493 /* Check for CT */
3494 if (pvc->result || pvc->details) {
3495 /* This call will set the value of pvc->is_ct, but won't change the result (pvc->result) */
3496 SecPolicyCheckCT(pvc, kSecPolicyCheckCertificateTransparency);
3497 }
3498
3499
3500 //errOut:
3501 secdebug("policy", "end %strusted completed: %d path: %@",
3502 (pvc->result ? "" : "not "), completed, pvc->path);
3503 return completed;
3504 }
3505
3506 /* This function returns 0 to indicate revocation checking was not completed
3507 for this certificate chain, otherwise return to date at which the first
3508 piece of revocation checking info we used expires. */
3509 CFAbsoluteTime SecPVCGetEarliestNextUpdate(SecPVCRef pvc) {
3510 CFIndex certIX, certCount = SecPVCGetCertificateCount(pvc);
3511 CFAbsoluteTime enu = 0;
3512 if (certCount <= 1 || !pvc->rvcs) {
3513 return enu;
3514 }
3515 certCount--;
3516
3517 for (certIX = 0; certIX < certCount; ++certIX) {
3518 SecRVCRef rvc = &((SecRVCRef)pvc->rvcs)[certIX];
3519 if (rvc->nextUpdate == 0) {
3520 if (certIX > 0) {
3521 /* We allow for CA certs to not be revocation checked if they
3522 have no ocspResponders to check against, but the leaf
3523 must be checked in order for us to claim we did revocation
3524 checking. */
3525 SecCertificateRef cert =
3526 SecPVCGetCertificateAtIndex(rvc->pvc, rvc->certIX);
3527 CFArrayRef ocspResponders = SecCertificateGetOCSPResponders(cert);
3528 if (!ocspResponders || CFArrayGetCount(ocspResponders) == 0) {
3529 /* We can't check this cert so we don't consider it a soft
3530 failure that we didn't. Ideally we should support crl
3531 checking and remove this workaround, since that more
3532 strict. */
3533 continue;
3534 }
3535 }
3536 secdebug("ocsp", "revocation checking soft failure for cert: %ld",
3537 certIX);
3538 enu = rvc->nextUpdate;
3539 break;
3540 }
3541 if (enu == 0 || rvc->nextUpdate < enu) {
3542 enu = rvc->nextUpdate;
3543 }
3544 #if 0
3545 /* Perhaps we don't want to do this since some policies might
3546 ignore the certificate expiration but still use revocation
3547 checking. */
3548
3549 /* Earliest certificate expiration date. */
3550 SecCertificateRef cert = SecPVCGetCertificateAtIndex(rvc->pvc, rvc->certIX);
3551 CFAbsoluteTime nva = SecCertificateNotValidAfter(cert);
3552 if (nva && (enu == 0 || nva < enu)
3553 enu = nva;
3554 #endif
3555 }
3556
3557 secdebug("ocsp", "revocation valid until: %lg", enu);
3558 return enu;
3559 }