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