]> git.saurik.com Git - apple/security.git/blob - sec/securityd/SecPolicyServer.c
976ad214428f974678fe73db9b52454948815553
[apple/security.git] / sec / securityd / SecPolicyServer.c
1 /*
2 * Copyright (c) 2008-2011 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
32 #include <securityd/asynchttp.h>
33 #include <securityd/policytree.h>
34 #include <pthread.h>
35 #include <CoreFoundation/CFTimeZone.h>
36 #include <wctype.h>
37 #include <libDER/oids.h>
38 #include <CoreFoundation/CFNumber.h>
39 #include <Security/SecCertificateInternal.h>
40 #include <AssertMacros.h>
41 #include <security_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 <CFNetwork/CFHTTPMessage.h>
52 #include <CFNetwork/CFHTTPStream.h>
53 #include <SystemConfiguration/SCDynamicStoreCopySpecific.h>
54 #include <asl.h>
55 #include <securityd/SecOCSPRequest.h>
56 #include <securityd/SecOCSPResponse.h>
57 #include <securityd/asynchttp.h>
58 #include <securityd/SecTrustServer.h>
59 #include <securityd/SecOCSPCache.h>
60
61 #define ocspdErrorLog(args...) asl_log(NULL, NULL, ASL_LEVEL_ERR, ## args)
62
63 /* Set this to 1 to dump the ocsp responses received in DER form in /tmp. */
64 #ifndef DUMP_OCSPRESPONSES
65 #define DUMP_OCSPRESPONSES 0
66 #endif
67
68 #if DUMP_OCSPRESPONSES
69
70 #include <unistd.h>
71 #include <fcntl.h>
72
73 static void secdumpdata(CFDataRef data, const char *name) {
74 int fd = open(name, O_CREAT | O_WRONLY | O_TRUNC, 0666);
75 write(fd, CFDataGetBytePtr(data), CFDataGetLength(data));
76 close(fd);
77 }
78
79 #endif
80
81 /********************************************************
82 ****************** SecPolicy object ********************
83 ********************************************************/
84
85 static CFMutableDictionaryRef gSecPolicyLeafCallbacks = NULL;
86 static CFMutableDictionaryRef gSecPolicyPathCallbacks = NULL;
87 static CFSetRef gBlackListedKeys = NULL;
88
89 static pthread_once_t gSecEVPolicyToAnchorDigestsOnce = PTHREAD_ONCE_INIT;
90 static CFDictionaryRef gSecEVPolicyToAnchorDigests = NULL;
91
92 /* Helper functions. */
93
94 static bool isArray(CFTypeRef cfType) {
95 return cfType && CFGetTypeID(cfType) == CFArrayGetTypeID();
96 }
97
98 static bool isData(CFTypeRef cfType) {
99 return cfType && CFGetTypeID(cfType) == CFDataGetTypeID();
100 }
101
102 static bool isDate(CFTypeRef cfType) {
103 return cfType && CFGetTypeID(cfType) == CFDateGetTypeID();
104 }
105
106 static bool isDictionary(CFTypeRef cfType) {
107 return cfType && CFGetTypeID(cfType) == CFDictionaryGetTypeID();
108 }
109
110 static bool isString(CFTypeRef cfType) {
111 return cfType && CFGetTypeID(cfType) == CFStringGetTypeID();
112 }
113
114 static void SecEVPolicyToAnchorDigestsInit(void) {
115 CFDataRef xmlData = SecFrameworkCopyResourceContents(
116 CFSTR("EVRoots"), CFSTR("plist"), NULL);
117 CFPropertyListRef evroots = NULL;
118 if (xmlData) {
119 evroots = CFPropertyListCreateFromXMLData(
120 kCFAllocatorDefault, xmlData, kCFPropertyListImmutable, NULL);
121 CFRelease(xmlData);
122 }
123 if (evroots) {
124 if (CFGetTypeID(evroots) == CFDictionaryGetTypeID()) {
125 /* @@@ Ensure that each dictionary key is a dotted list of digits,
126 each value is an NSArrayRef and each element in the array is a
127 20 byte digest. */
128 gSecEVPolicyToAnchorDigests = (CFDictionaryRef)evroots;
129 } else {
130 secwarning("EVRoot.plist is wrong type.");
131 CFRelease(evroots);
132 }
133 }
134 }
135
136 static CFArrayRef SecPolicyAnchorDigestsForEVPolicy(const DERItem *policyOID) {
137 pthread_once(&gSecEVPolicyToAnchorDigestsOnce,
138 SecEVPolicyToAnchorDigestsInit);
139 CFArrayRef roots = NULL;
140 CFStringRef oid = SecDERItemCopyOIDDecimalRepresentation(
141 kCFAllocatorDefault, policyOID);
142 if (oid) {
143 roots = (CFArrayRef)CFDictionaryGetValue(gSecEVPolicyToAnchorDigests,
144 oid);
145 if (roots && CFGetTypeID(roots) != CFArrayGetTypeID()) {
146 ocspdErrorLog("EVRoot.plist has non array value");
147 roots = NULL;
148 }
149 CFRelease(oid);
150 }
151 return roots;
152 }
153
154
155 static bool SecPolicyIsEVPolicy(const DERItem *policyOID) {
156 return SecPolicyAnchorDigestsForEVPolicy(policyOID);
157 }
158
159 static bool SecPolicyRootCACertificateIsEV(SecCertificateRef certificate,
160 policy_set_t valid_policies) {
161 /* Ensure that this certificate is a valid anchor for one of the
162 certificate policy oids specified in the leaf. */
163 CFDataRef digest = SecCertificateGetSHA1Digest(certificate);
164 policy_set_t ix;
165 bool good_ev_anchor = false;
166 for (ix = valid_policies; ix; ix = ix->oid_next) {
167 CFArrayRef digests = SecPolicyAnchorDigestsForEVPolicy(&ix->oid);
168 if (digests && CFArrayContainsValue(digests,
169 CFRangeMake(0, CFArrayGetCount(digests)), digest)) {
170 secdebug("ev", "found anchor for policy oid");
171 good_ev_anchor = true;
172 break;
173 }
174 }
175 require_quiet(good_ev_anchor, notEV);
176
177 CFAbsoluteTime october2006 = 178761600;
178 if (SecCertificateVersion(certificate) >= 3
179 && SecCertificateNotValidBefore(certificate) >= october2006) {
180 const SecCEBasicConstraints *bc = SecCertificateGetBasicConstraints(certificate);
181 require_quiet(bc && bc->isCA == true, notEV);
182 SecKeyUsage ku = SecCertificateGetKeyUsage(certificate);
183 require_quiet((ku & (kSecKeyUsageKeyCertSign | kSecKeyUsageCRLSign))
184 == (kSecKeyUsageKeyCertSign | kSecKeyUsageCRLSign), notEV);
185 }
186
187 CFAbsoluteTime jan2011 = 315532800;
188 if (SecCertificateNotValidBefore(certificate) < jan2011) {
189 /* At least MD5, SHA-1 with RSA 2048 or ECC NIST P-256. */
190 } else {
191 /* At least SHA-1, SHA-256, SHA-384 or SHA-512 with RSA 2048 or
192 ECC NIST P-256. */
193 }
194
195 return true;
196 notEV:
197 return false;
198 }
199
200 static bool SecPolicySubordinateCACertificateCouldBeEV(SecCertificateRef certificate) {
201 const SecCECertificatePolicies *cp;
202 cp = SecCertificateGetCertificatePolicies(certificate);
203 require_quiet(cp && cp->numPolicies > 0, notEV);
204 /* SecCertificateGetCRLDistributionPoints() is a noop right now */
205 #if 0
206 CFArrayRef cdp = SecCertificateGetCRLDistributionPoints(certificate);
207 require_quiet(cdp && CFArrayGetCount(cdp) > 0, notEV);
208 #endif
209 const SecCEBasicConstraints *bc = SecCertificateGetBasicConstraints(certificate);
210 require_quiet(bc && bc->isCA == true, notEV);
211 SecKeyUsage ku = SecCertificateGetKeyUsage(certificate);
212 require_quiet((ku & (kSecKeyUsageKeyCertSign | kSecKeyUsageCRLSign))
213 == (kSecKeyUsageKeyCertSign | kSecKeyUsageCRLSign), notEV);
214 CFAbsoluteTime jan2011 = 315532800;
215 if (SecCertificateNotValidBefore(certificate) < jan2011) {
216 /* At least SHA-1 with RSA 1024 or ECC NIST P-256. */
217 } else {
218 /* At least SHA-1, SHA-256, SHA-284 or SHA-512 with RSA 2028 or
219 ECC NIST P-256. */
220 }
221
222 return true;
223 notEV:
224 return false;
225 }
226
227 bool SecPolicySubscriberCertificateCouldBeEV(SecCertificateRef certificate) {
228 /* 3. Subscriber Certificate. */
229
230 /* (a) certificate Policies */
231 const SecCECertificatePolicies *cp;
232 cp = SecCertificateGetCertificatePolicies(certificate);
233 require_quiet(cp && cp->numPolicies > 0, notEV);
234 /* Now find at least one policy in here that has a qualifierID of id-qt 2
235 and a policyQualifier that is a URI to the CPS and an EV policy OID. */
236 uint32_t ix = 0;
237 bool found_ev_anchor_for_leaf_policy = false;
238 for (ix = 0; ix < cp->numPolicies; ++ix) {
239 if (SecPolicyIsEVPolicy(&cp->policies[ix].policyIdentifier)) {
240 found_ev_anchor_for_leaf_policy = true;
241 }
242 }
243 require_quiet(found_ev_anchor_for_leaf_policy, notEV);
244
245 /* SecCertificateGetCRLDistributionPoints() is a noop right now */
246 #if 0
247 /* (b) cRLDistributionPoint
248 (c) authorityInformationAccess */
249 CFArrayRef cdp = SecCertificateGetCRLDistributionPoints(certificate);
250 if (cdp) {
251 require_quiet(CFArrayGetCount(cdp) > 0, notEV);
252 } else {
253 CFArrayRef or = SecCertificateGetOCSPResponders(certificate);
254 require_quiet(or && CFArrayGetCount(or) > 0, notEV);
255 //CFArrayRef ci = SecCertificateGetCAIssuers(certificate);
256 }
257 #endif
258
259 /* (d) basicConstraints
260 If present, the cA field MUST be set false. */
261 const SecCEBasicConstraints *bc = SecCertificateGetBasicConstraints(certificate);
262 if (bc) {
263 require_quiet(bc->isCA == false, notEV);
264 }
265
266 /* (e) keyUsage. */
267 SecKeyUsage ku = SecCertificateGetKeyUsage(certificate);
268 if (ku) {
269 require_quiet((ku & (kSecKeyUsageKeyCertSign | kSecKeyUsageCRLSign)) == 0, notEV);
270 }
271
272 #if 0
273 /* The EV Cert Spec errata specifies this, though this is a check for SSL
274 not specifically EV. */
275
276 /* (e) extKeyUsage
277
278 Either the value id-kp-serverAuth [RFC5280] or id-kp-clientAuth [RFC5280] or both values MUST be present. Other values SHOULD NOT be present. */
279 SecCertificateCopyExtendedKeyUsage(certificate);
280 #endif
281
282 CFAbsoluteTime jan2011 = 315532800;
283 if (SecCertificateNotValidAfter(certificate) < jan2011) {
284 /* At least SHA-1 with RSA 1024 or ECC NIST P-256. */
285 } else {
286 /* At least SHA-1, SHA-256, SHA-284 or SHA-512 with RSA 2028 or
287 ECC NIST P-256. */
288 }
289
290 return true;
291 notEV:
292 return false;
293 }
294
295 /********************************************************
296 **************** SecPolicy Callbacks *******************
297 ********************************************************/
298 static void SecPolicyCheckCriticalExtensions(SecPVCRef pvc,
299 CFStringRef key) {
300 }
301
302 static void SecPolicyCheckIdLinkage(SecPVCRef pvc,
303 CFStringRef key) {
304 CFIndex ix, count = SecPVCGetCertificateCount(pvc);
305 CFDataRef parentSubjectKeyID = NULL;
306 for (ix = count - 1; ix >= 0; --ix) {
307 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix);
308 /* If the previous certificate in the chain had a SubjectKeyID,
309 make sure it matches the current certificates AuthorityKeyID. */
310 if (parentSubjectKeyID) {
311 /* @@@ According to RFC 2459 neither AuthorityKeyID nor
312 SubjectKeyID can be critical. Currenty we don't check
313 for this. */
314 CFDataRef authorityKeyID = SecCertificateGetAuthorityKeyID(cert);
315 if (authorityKeyID) {
316 if (!CFEqual(parentSubjectKeyID, authorityKeyID)) {
317 /* AuthorityKeyID doesn't match issuers SubjectKeyID. */
318 if (!SecPVCSetResult(pvc, key, ix, kCFBooleanFalse))
319 return;
320 }
321 }
322 }
323
324 parentSubjectKeyID = SecCertificateGetSubjectKeyID(cert);
325 }
326 }
327
328 static bool keyusage_allows(SecKeyUsage keyUsage, CFTypeRef xku) {
329 if (!xku || CFGetTypeID(xku) != CFNumberGetTypeID())
330 return false;
331
332 SInt32 dku;
333 CFNumberGetValue((CFNumberRef)xku, kCFNumberSInt32Type, &dku);
334 SecKeyUsage ku = (SecKeyUsage)dku;
335 return (keyUsage & ku) == ku;
336 }
337
338 static void SecPolicyCheckKeyUsage(SecPVCRef pvc,
339 CFStringRef key) {
340 SecCertificateRef leaf = SecPVCGetCertificateAtIndex(pvc, 0);
341 SecKeyUsage keyUsage = SecCertificateGetKeyUsage(leaf);
342 bool match = false;
343 SecPolicyRef policy = SecPVCGetPolicy(pvc);
344 CFTypeRef xku = CFDictionaryGetValue(policy->_options, key);
345 if (isArray(xku)) {
346 CFIndex ix, count = CFArrayGetCount(xku);
347 for (ix = 0; ix < count; ++ix) {
348 CFTypeRef ku = CFArrayGetValueAtIndex(xku, ix);
349 if (keyusage_allows(keyUsage, ku)) {
350 match = true;
351 break;
352 }
353 }
354 } else {
355 match = keyusage_allows(keyUsage, xku);
356 }
357 if (!match) {
358 SecPVCSetResult(pvc, key, 0, kCFBooleanFalse);
359 }
360 }
361
362 static bool extendedkeyusage_allows(CFArrayRef extendedKeyUsage,
363 CFTypeRef xeku) {
364 if (!xeku || CFGetTypeID(xeku) != CFDataGetTypeID())
365 return false;
366 if (extendedKeyUsage) {
367 CFRange all = { 0, CFArrayGetCount(extendedKeyUsage) };
368 return CFArrayContainsValue(extendedKeyUsage, all, xeku);
369 } else {
370 /* Certificate has no extended key usage, only a match if the policy
371 contains a 0 length CFDataRef. */
372 return CFDataGetLength((CFDataRef)xeku) == 0;
373 }
374 }
375
376 /* AUDIT[securityd](done):
377 policy->_options is a caller provided dictionary, only its cf type has
378 been checked.
379 */
380 static void SecPolicyCheckExtendedKeyUsage(SecPVCRef pvc, CFStringRef key) {
381 SecCertificateRef leaf = SecPVCGetCertificateAtIndex(pvc, 0);
382 CFArrayRef leafExtendedKeyUsage = SecCertificateCopyExtendedKeyUsage(leaf);
383 bool match = false;
384 SecPolicyRef policy = SecPVCGetPolicy(pvc);
385 CFTypeRef xeku = CFDictionaryGetValue(policy->_options, key);
386 if (isArray(xeku)) {
387 CFIndex ix, count = CFArrayGetCount(xeku);
388 for (ix = 0; ix < count; ix++) {
389 CFTypeRef eku = CFArrayGetValueAtIndex(xeku, ix);
390 if (extendedkeyusage_allows(leafExtendedKeyUsage, eku)) {
391 match = true;
392 break;
393 }
394 }
395 } else {
396 match = extendedkeyusage_allows(leafExtendedKeyUsage, xeku);
397 }
398 CFReleaseSafe(leafExtendedKeyUsage);
399 if (!match) {
400 SecPVCSetResult(pvc, key, 0, kCFBooleanFalse);
401 }
402 }
403
404 #if 0
405 static void SecPolicyCheckBasicContraintsCommon(SecPVCRef pvc,
406 CFStringRef key, bool strict) {
407 CFIndex ix, count = SecPVCGetCertificateCount(pvc);
408 for (ix = 0; ix < count; ++ix) {
409 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix);
410 const SecCEBasicConstraints *bc =
411 SecCertificateGetBasicConstraints(cert);
412 if (bc) {
413 if (strict) {
414 if (ix == 0) {
415 /* Leaf certificate has basic constraints extension. */
416 if (!SecPVCSetResult(pvc, key, ix, kCFBooleanFalse))
417 return;
418 } else if (!bc->critical) {
419 /* Basic constraints extension is not marked critical. */
420 if (!SecPVCSetResult(pvc, key, ix, kCFBooleanFalse))
421 return;
422 }
423 }
424
425 if (ix > 0 || count == 1) {
426 if (!bc->isCA) {
427 /* Non leaf certificate marked as isCA false. */
428 if (!SecPVCSetResult(pvc, key, ix, kCFBooleanFalse))
429 return;
430 }
431
432 if (bc->pathLenConstraintPresent) {
433 if (bc->pathLenConstraint < (uint32_t)(ix - 1)) {
434 #if 0
435 /* @@@ If a self signed certificate is issued by
436 another cert that is trusted, then we are supposed
437 to treat the self signed cert itself as the anchor
438 for path length purposes. */
439 CFIndex ssix = SecCertificatePathSelfSignedIndex(path);
440 if (ssix >= 0 && ix >= ssix) {
441 /* It's ok if the pathLenConstraint isn't met for
442 certificates signing a self signed cert in the
443 chain. */
444 } else
445 #endif
446 {
447 /* Path Length Constraint Exceeded. */
448 if (!SecPVCSetResult(pvc, key, ix,
449 kCFBooleanFalse))
450 return;
451 }
452 }
453 }
454 }
455 } else if (strict && ix > 0) {
456 /* In strict mode all CA certificates *MUST* have a critical
457 basic constraints extension and the leaf certificate
458 *MUST NOT* have a basic constraints extension. */
459 /* CA certificate is missing basicConstraints extension. */
460 if (!SecPVCSetResult(pvc, key, ix, kCFBooleanFalse))
461 return;
462 }
463 }
464 }
465 #endif
466
467 static void SecPolicyCheckBasicContraints(SecPVCRef pvc,
468 CFStringRef key) {
469 //SecPolicyCheckBasicContraintsCommon(pvc, key, false);
470 }
471
472 static void SecPolicyCheckNonEmptySubject(SecPVCRef pvc,
473 CFStringRef key) {
474 CFIndex ix, count = SecPVCGetCertificateCount(pvc);
475 for (ix = 0; ix < count; ++ix) {
476 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix);
477 /* If the certificate has a subject, or
478 if it doesn't, and it's the leaf and not self signed,
479 and also has a critical subjectAltName extension it's valid. */
480 if (!SecCertificateHasSubject(cert)) {
481 if (ix == 0 && count > 1) {
482 if (!SecCertificateHasCriticalSubjectAltName(cert)) {
483 /* Leaf certificate with empty subject does not have
484 a critical subject alt name extension. */
485 if (!SecPVCSetResult(pvc, key, ix, kCFBooleanFalse))
486 return;
487 }
488 } else {
489 /* CA certificate has empty subject. */
490 if (!SecPVCSetResult(pvc, key, ix, kCFBooleanFalse))
491 return;
492 }
493 }
494 }
495 }
496
497 static void SecPolicyCheckQualifiedCertStatements(SecPVCRef pvc,
498 CFStringRef key) {
499 }
500
501 /* Compare hostname, to a server name obtained from the server's cert
502 Obtained from the SubjectAltName or the CommonName entry in the Subject.
503 Limited wildcard checking is performed here as outlined in
504
505 RFC 2818 Section 3.1. Server Identity
506
507 [...] Names may contain the wildcard
508 character * which is considered to match any single domain name
509 component or component fragment. E.g., *.a.com matches foo.a.com but
510 not bar.foo.a.com. f*.com matches foo.com but not bar.com.
511 [...]
512
513 Trailing '.' characters in the hostname will be ignored.
514
515 Returns true on match, else false.
516 */
517 static bool SecDNSMatch(CFStringRef hostname, CFStringRef servername) {
518 CFStringInlineBuffer hbuf, sbuf;
519 CFIndex hix, six,
520 hlength = CFStringGetLength(hostname),
521 slength = CFStringGetLength(servername);
522 CFRange hrange = { 0, hlength }, srange = { 0, slength };
523 CFStringInitInlineBuffer(hostname, &hbuf, hrange);
524 CFStringInitInlineBuffer(servername, &sbuf, srange);
525
526 for (hix = six = 0; six < slength; ++six) {
527 UniChar hch, sch = CFStringGetCharacterFromInlineBuffer(&sbuf, six);
528 if (sch == '*') {
529 if (six + 1 >= slength) {
530 /* Trailing '*' in servername, match until end of hostname or
531 trailing '.'. */
532 do {
533 if (hix >= hlength) {
534 /* If we reach the end of the hostname we have a
535 match. */
536 return true;
537 }
538 hch = CFStringGetCharacterFromInlineBuffer(&hbuf, hix++);
539 } while (hch != '.');
540 /* We reached the end of servername and found a '.' in
541 hostname. Return true if hostname has a single
542 trailing '.' return false if there is anything after it. */
543 return hix == hlength;
544 }
545
546 /* Grab the character after the '*'. */
547 sch = CFStringGetCharacterFromInlineBuffer(&sbuf, ++six);
548 if (sch != '.') {
549 /* We have something of the form '*foo.com'. Or '**.com'
550 We don't deal with that yet, since it might require
551 backtracking. Also RFC 2818 doesn't seem to require it. */
552 return false;
553 }
554
555 /* We're looking at the '.' after the '*' in something of the
556 form 'foo*.com' or '*.com'. Match until next '.' in hostname. */
557 do {
558 /* Since we're not at the end of servername yet (that case
559 was handeled above), running out of chars in hostname
560 means we don't have a match. */
561 if (hix >= hlength)
562 return false;
563 hch = CFStringGetCharacterFromInlineBuffer(&hbuf, hix++);
564 } while (hch != '.');
565 } else {
566 /* We're looking at a non wildcard character in the servername.
567 If we reached the end of hostname it's not a match. */
568 if (hix >= hlength)
569 return false;
570
571 /* Otherwise make sure the hostname matches the character in the
572 servername, case insensitively. */
573 hch = CFStringGetCharacterFromInlineBuffer(&hbuf, hix++);
574 if (towlower(hch) != towlower(sch))
575 return false;
576 }
577 }
578
579 if (hix < hlength) {
580 /* We reached the end of servername but we have one or more characters
581 left to compare against in the hostname. */
582 if (hix + 1 == hlength &&
583 CFStringGetCharacterFromInlineBuffer(&hbuf, hix) == '.') {
584 /* Hostname has a single trailing '.', we're ok with that. */
585 return true;
586 }
587 /* Anything else is not a match. */
588 return false;
589 }
590
591 return true;
592 }
593
594 /* AUDIT[securityd](done):
595 policy->_options is a caller provided dictionary, only its cf type has
596 been checked.
597 */
598 static void SecPolicyCheckSSLHostname(SecPVCRef pvc,
599 CFStringRef key) {
600 /* @@@ Consider what to do if the caller passes in no hostname. Should
601 we then still fail if the leaf has no dnsNames or IPAddresses at all? */
602 SecPolicyRef policy = SecPVCGetPolicy(pvc);
603 CFStringRef hostName = (CFStringRef)
604 CFDictionaryGetValue(policy->_options, key);
605 if (!isString(hostName)) {
606 /* @@@ We can't return an error here and making the evaluation fail
607 won't help much either. */
608 return;
609 }
610
611 SecCertificateRef leaf = SecPVCGetCertificateAtIndex(pvc, 0);
612 bool dnsMatch = false;
613 CFArrayRef dnsNames = SecCertificateCopyDNSNames(leaf);
614 if (dnsNames) {
615 CFIndex ix, count = CFArrayGetCount(dnsNames);
616 for (ix = 0; ix < count; ++ix) {
617 CFStringRef dns = (CFStringRef)CFArrayGetValueAtIndex(dnsNames, ix);
618 if (SecDNSMatch(hostName, dns)) {
619 dnsMatch = true;
620 break;
621 }
622 }
623 CFRelease(dnsNames);
624 }
625
626 if (!dnsMatch) {
627 /* Maybe hostname is an IPv4 or IPv6 address, let's compare against
628 the values returned by SecCertificateCopyIPAddresses() instead. */
629 CFArrayRef ipAddresses = SecCertificateCopyIPAddresses(leaf);
630 if (ipAddresses) {
631 CFIndex ix, count = CFArrayGetCount(ipAddresses);
632 for (ix = 0; ix < count; ++ix) {
633 CFStringRef ipAddress = (CFStringRef)CFArrayGetValueAtIndex(ipAddresses, ix);
634 if (!CFStringCompare(hostName, ipAddress, kCFCompareCaseInsensitive)) {
635 dnsMatch = true;
636 break;
637 }
638 }
639 CFRelease(ipAddresses);
640 }
641 }
642
643 if (!dnsMatch) {
644 /* Hostname mismatch or no hostnames found in certificate. */
645 SecPVCSetResult(pvc, key, 0, kCFBooleanFalse);
646 }
647 if ((dnsMatch || pvc->details)
648 && SecPolicySubscriberCertificateCouldBeEV(leaf)) {
649 secdebug("policy", "enabling optionally_ev");
650 pvc->optionally_ev = true;
651 /* optionally_ev => check_revocation, so we don't enable revocation
652 checking here, since we don't want it on for non EV ssl certs. */
653 #if 0
654 /* Check revocation status if the certificate asks for it (and we
655 support it) currently we only support ocsp. */
656 CFArrayRef ocspResponders = SecCertificateGetOCSPResponders(leaf);
657 if (ocspResponders) {
658 SecPVCSetCheckRevocation(pvc);
659 }
660 #endif
661 }
662 }
663
664 /* AUDIT[securityd](done):
665 policy->_options is a caller provided dictionary, only its cf type has
666 been checked.
667 */
668 static void SecPolicyCheckEmail(SecPVCRef pvc, CFStringRef key) {
669 SecPolicyRef policy = SecPVCGetPolicy(pvc);
670 CFStringRef email = (CFStringRef)CFDictionaryGetValue(policy->_options, key);
671 bool match = false;
672 if (!isString(email)) {
673 /* We can't return an error here and making the evaluation fail
674 won't help much either. */
675 return;
676 }
677
678 SecCertificateRef leaf = SecPVCGetCertificateAtIndex(pvc, 0);
679 CFArrayRef addrs = SecCertificateCopyRFC822Names(leaf);
680 if (addrs) {
681 CFIndex ix, count = CFArrayGetCount(addrs);
682 for (ix = 0; ix < count; ++ix) {
683 CFStringRef addr = (CFStringRef)CFArrayGetValueAtIndex(addrs, ix);
684 if (!CFStringCompare(email, addr, kCFCompareCaseInsensitive)) {
685 match = true;
686 break;
687 }
688 }
689 CFRelease(addrs);
690 }
691
692 if (!match) {
693 /* Hostname mismatch or no hostnames found in certificate. */
694 SecPVCSetResult(pvc, key, 0, kCFBooleanFalse);
695 }
696 }
697
698 static void SecPolicyCheckValidIntermediates(SecPVCRef pvc,
699 CFStringRef key) {
700 CFIndex ix, count = SecPVCGetCertificateCount(pvc);
701 CFAbsoluteTime verifyTime = SecPVCGetVerifyTime(pvc);
702 for (ix = 1; ix < count - 1; ++ix) {
703 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix);
704 if (!SecCertificateIsValid(cert, verifyTime)) {
705 /* Intermediate certificate has expired. */
706 if (!SecPVCSetResult(pvc, key, ix, kCFBooleanFalse))
707 return;
708 }
709 }
710 }
711
712 static void SecPolicyCheckValidLeaf(SecPVCRef pvc,
713 CFStringRef key) {
714 CFAbsoluteTime verifyTime = SecPVCGetVerifyTime(pvc);
715 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, 0);
716 if (!SecCertificateIsValid(cert, verifyTime)) {
717 /* Leaf certificate has expired. */
718 if (!SecPVCSetResult(pvc, key, 0, kCFBooleanFalse))
719 return;
720 }
721 }
722
723 static void SecPolicyCheckValidRoot(SecPVCRef pvc,
724 CFStringRef key) {
725 CFIndex ix, count = SecPVCGetCertificateCount(pvc);
726 CFAbsoluteTime verifyTime = SecPVCGetVerifyTime(pvc);
727 ix = count - 1;
728 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix);
729 if (!SecCertificateIsValid(cert, verifyTime)) {
730 /* Root certificate has expired. */
731 if (!SecPVCSetResult(pvc, key, ix, kCFBooleanFalse))
732 return;
733 }
734 }
735
736 /* AUDIT[securityd](done):
737 policy->_options is a caller provided dictionary, only its cf type has
738 been checked.
739 */
740 static void SecPolicyCheckIssuerCommonName(SecPVCRef pvc,
741 CFStringRef key) {
742 CFIndex count = SecPVCGetCertificateCount(pvc);
743 if (count < 2) {
744 /* Can't check intermediates common name if there is no intermediate. */
745 SecPVCSetResult(pvc, key, 0, kCFBooleanFalse);
746 return;
747 }
748
749 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, 1);
750 SecPolicyRef policy = SecPVCGetPolicy(pvc);
751 CFStringRef commonName =
752 (CFStringRef)CFDictionaryGetValue(policy->_options, key);
753 if (!isString(commonName)) {
754 /* @@@ We can't return an error here and making the evaluation fail
755 won't help much either. */
756 return;
757 }
758 CFArrayRef commonNames = SecCertificateCopyCommonNames(cert);
759 if (!commonNames || CFArrayGetCount(commonNames) != 1 ||
760 !CFEqual(commonName, CFArrayGetValueAtIndex(commonNames, 0))) {
761 /* Common Name mismatch. */
762 SecPVCSetResult(pvc, key, 0, kCFBooleanFalse);
763 }
764 CFReleaseSafe(commonNames);
765 }
766
767 /* AUDIT[securityd](done):
768 policy->_options is a caller provided dictionary, only its cf type has
769 been checked.
770 */
771 static void SecPolicyCheckSubjectCommonName(SecPVCRef pvc,
772 CFStringRef key) {
773 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, 0);
774 SecPolicyRef policy = SecPVCGetPolicy(pvc);
775 CFStringRef common_name = (CFStringRef)CFDictionaryGetValue(policy->_options,
776 key);
777 if (!isString(common_name)) {
778 /* @@@ We can't return an error here and making the evaluation fail
779 won't help much either. */
780 return;
781 }
782 CFArrayRef commonNames = SecCertificateCopyCommonNames(cert);
783 if (!commonNames || CFArrayGetCount(commonNames) != 1 ||
784 !CFEqual(common_name, CFArrayGetValueAtIndex(commonNames, 0))) {
785 /* Common Name mismatch. */
786 SecPVCSetResult(pvc, key, 0, kCFBooleanFalse);
787 }
788 CFReleaseSafe(commonNames);
789 }
790
791 /* AUDIT[securityd](done):
792 policy->_options is a caller provided dictionary, only its cf type has
793 been checked.
794 */
795 static void SecPolicyCheckSubjectCommonNamePrefix(SecPVCRef pvc,
796 CFStringRef key) {
797 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, 0);
798 SecPolicyRef policy = SecPVCGetPolicy(pvc);
799 CFStringRef prefix = (CFStringRef)CFDictionaryGetValue(policy->_options,
800 key);
801 if (!isString(prefix)) {
802 /* @@@ We can't return an error here and making the evaluation fail
803 won't help much either. */
804 return;
805 }
806 CFArrayRef commonNames = SecCertificateCopyCommonNames(cert);
807 if (!commonNames || CFArrayGetCount(commonNames) != 1 ||
808 !CFStringHasPrefix(CFArrayGetValueAtIndex(commonNames, 0), prefix)) {
809 /* Common Name prefix mismatch. */
810 SecPVCSetResult(pvc, key, 0, kCFBooleanFalse);
811 }
812 CFReleaseSafe(commonNames);
813 }
814
815 /* AUDIT[securityd](done):
816 policy->_options is a caller provided dictionary, only its cf type has
817 been checked.
818 */
819 static void SecPolicyCheckSubjectCommonNameTEST(SecPVCRef pvc,
820 CFStringRef key) {
821 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, 0);
822 SecPolicyRef policy = SecPVCGetPolicy(pvc);
823 CFStringRef common_name = (CFStringRef)CFDictionaryGetValue(policy->_options,
824 key);
825 if (!isString(common_name)) {
826 /* @@@ We can't return an error here and making the evaluation fail
827 won't help much either. */
828 return;
829 }
830 CFArrayRef commonNames = SecCertificateCopyCommonNames(cert);
831 if (!commonNames || CFArrayGetCount(commonNames) != 1) {
832 CFStringRef cert_common_name = CFArrayGetValueAtIndex(commonNames, 0);
833 CFStringRef test_common_name = common_name ?
834 CFStringCreateWithFormat(kCFAllocatorDefault,
835 NULL, CFSTR("TEST %@ TEST"), common_name) :
836 NULL;
837 if (!CFEqual(common_name, cert_common_name) &&
838 (!test_common_name || !CFEqual(test_common_name, cert_common_name)))
839 /* Common Name mismatch. */
840 SecPVCSetResult(pvc, key, 0, kCFBooleanFalse);
841 CFReleaseSafe(test_common_name);
842 }
843 CFReleaseSafe(commonNames);
844 }
845
846 /* AUDIT[securityd](done):
847 policy->_options is a caller provided dictionary, only its cf type has
848 been checked.
849 */
850 static void SecPolicyCheckNotValidBefore(SecPVCRef pvc,
851 CFStringRef key) {
852 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, 0);
853 SecPolicyRef policy = SecPVCGetPolicy(pvc);
854 CFDateRef date = (CFDateRef)CFDictionaryGetValue(policy->_options, key);
855 if (!isDate(date)) {
856 /* @@@ We can't return an error here and making the evaluation fail
857 won't help much either. */
858 return;
859 }
860 CFAbsoluteTime at = CFDateGetAbsoluteTime(date);
861 if (SecCertificateNotValidBefore(cert) <= at) {
862 /* Leaf certificate has not valid before that is too old. */
863 if (!SecPVCSetResult(pvc, key, 0, kCFBooleanFalse))
864 return;
865 }
866 }
867
868 /* AUDIT[securityd](done):
869 policy->_options is a caller provided dictionary, only its cf type has
870 been checked.
871 */
872 static void SecPolicyCheckChainLength(SecPVCRef pvc,
873 CFStringRef key) {
874 CFIndex count = SecPVCGetCertificateCount(pvc);
875 SecPolicyRef policy = SecPVCGetPolicy(pvc);
876 CFNumberRef chainLength =
877 (CFNumberRef)CFDictionaryGetValue(policy->_options, key);
878 CFIndex value;
879 if (!chainLength || CFGetTypeID(chainLength) != CFNumberGetTypeID() ||
880 !CFNumberGetValue(chainLength, kCFNumberCFIndexType, &value)) {
881 /* @@@ We can't return an error here and making the evaluation fail
882 won't help much either. */
883 return;
884 }
885 if (value != count) {
886 /* Chain length doesn't match policy requirement. */
887 if (!SecPVCSetResult(pvc, key, 0, kCFBooleanFalse))
888 return;
889 }
890 }
891
892 /* AUDIT[securityd](done):
893 policy->_options is a caller provided dictionary, only its cf type has
894 been checked.
895 */
896 static void SecPolicyCheckAnchorSHA1(SecPVCRef pvc,
897 CFStringRef key) {
898 CFIndex count = SecPVCGetCertificateCount(pvc);
899 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, count - 1);
900 SecPolicyRef policy = SecPVCGetPolicy(pvc);
901 CFDataRef sha1Digest =
902 (CFDataRef)CFDictionaryGetValue(policy->_options, key);
903 if (!isData(sha1Digest)) {
904 /* @@@ We can't return an error here and making the evaluation fail
905 won't help much either. */
906 return;
907 }
908 CFDataRef anchorSHA1 = SecCertificateGetSHA1Digest(cert);
909 if (!CFEqual(anchorSHA1, sha1Digest)) {
910 /* Certificate chain is not issued by required anchor. */
911 if (!SecPVCSetResult(pvc, kSecPolicyCheckAnchorSHA1, 0, kCFBooleanFalse))
912 return;
913 }
914 }
915
916 /* AUDIT[securityd](done):
917 policy->_options is a caller provided dictionary, only its cf type has
918 been checked.
919 */
920 static void SecPolicyCheckSubjectOrganization(SecPVCRef pvc,
921 CFStringRef key) {
922 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, 0);
923 SecPolicyRef policy = SecPVCGetPolicy(pvc);
924 CFStringRef org = (CFStringRef)CFDictionaryGetValue(policy->_options,
925 key);
926 if (!isString(org)) {
927 /* @@@ We can't return an error here and making the evaluation fail
928 won't help much either. */
929 return;
930 }
931 CFArrayRef organization = SecCertificateCopyOrganization(cert);
932 if (!organization || CFArrayGetCount(organization) != 1 ||
933 !CFEqual(org, CFArrayGetValueAtIndex(organization, 0))) {
934 /* Leaf Subject Organization mismatch. */
935 SecPVCSetResult(pvc, key, 0, kCFBooleanFalse);
936 }
937 CFReleaseSafe(organization);
938 }
939
940 /* AUDIT[securityd](done):
941 policy->_options is a caller provided dictionary, only its cf type has
942 been checked.
943 */
944 static void SecPolicyCheckEAPTrustedServerNames(SecPVCRef pvc,
945 CFStringRef key) {
946 SecPolicyRef policy = SecPVCGetPolicy(pvc);
947 CFArrayRef trustedServerNames = (CFArrayRef)
948 CFDictionaryGetValue(policy->_options, key);
949 /* No names specified means we accept any name. */
950 if (!trustedServerNames)
951 return;
952 if (!isArray(trustedServerNames)) {
953 /* @@@ We can't return an error here and making the evaluation fail
954 won't help much either. */
955 return;
956 }
957
958 CFIndex tsnCount = CFArrayGetCount(trustedServerNames);
959 SecCertificateRef leaf = SecPVCGetCertificateAtIndex(pvc, 0);
960 bool dnsMatch = false;
961 CFArrayRef dnsNames = SecCertificateCopyDNSNames(leaf);
962 if (dnsNames) {
963 CFIndex ix, count = CFArrayGetCount(dnsNames);
964 // @@@ This is O(N^2) unfortunately we can't do better easily unless
965 // we don't do wildcard matching. */
966 for (ix = 0; !dnsMatch && ix < count; ++ix) {
967 CFStringRef dns = (CFStringRef)CFArrayGetValueAtIndex(dnsNames, ix);
968 CFIndex tix;
969 for (tix = 0; tix < tsnCount; ++tix) {
970 CFStringRef serverName =
971 (CFStringRef)CFArrayGetValueAtIndex(trustedServerNames, tix);
972 if (!isString(serverName)) {
973 /* @@@ We can't return an error here and making the
974 evaluation fail won't help much either. */
975 return;
976 }
977 /* we purposefully reverse the arguments here such that dns names
978 from the cert are matched against a server name list, where
979 the server names list can contain wildcards and the dns name
980 cannot. References: http://support.microsoft.com/kb/941123
981 It's easy to find occurrences where people tried to use
982 wildcard certificates and were told that those don't work
983 in this context. */
984 if (SecDNSMatch(dns, serverName)) {
985 dnsMatch = true;
986 break;
987 }
988 }
989 }
990 CFRelease(dnsNames);
991 }
992
993 if (!dnsMatch) {
994 /* Hostname mismatch or no hostnames found in certificate. */
995 SecPVCSetResult(pvc, key, 0, kCFBooleanFalse);
996 }
997 }
998
999 static const unsigned char const UTN_USERFirst_Hardware_Serial[][16] = {
1000 { 0xd8, 0xf3, 0x5f, 0x4e, 0xb7, 0x87, 0x2b, 0x2d, 0xab, 0x06, 0x92, 0xe3, 0x15, 0x38, 0x2f, 0xb0 },
1001 { 0x92, 0x39, 0xd5, 0x34, 0x8f, 0x40, 0xd1, 0x69, 0x5a, 0x74, 0x54, 0x70, 0xe1, 0xf2, 0x3f, 0x43 },
1002 { 0xb0, 0xb7, 0x13, 0x3e, 0xd0, 0x96, 0xf9, 0xb5, 0x6f, 0xae, 0x91, 0xc8, 0x74, 0xbd, 0x3a, 0xc0 },
1003 { 0xe9, 0x02, 0x8b, 0x95, 0x78, 0xe4, 0x15, 0xdc, 0x1a, 0x71, 0x0a, 0x2b, 0x88, 0x15, 0x44, 0x47 },
1004 { 0x39, 0x2a, 0x43, 0x4f, 0x0e, 0x07, 0xdf, 0x1f, 0x8a, 0xa3, 0x05, 0xde, 0x34, 0xe0, 0xc2, 0x29 },
1005 { 0x3e, 0x75, 0xce, 0xd4, 0x6b, 0x69, 0x30, 0x21, 0x21, 0x88, 0x30, 0xae, 0x86, 0xa8, 0x2a, 0x71 },
1006 { 0xd7, 0x55, 0x8f, 0xda, 0xf5, 0xf1, 0x10, 0x5b, 0xb2, 0x13, 0x28, 0x2b, 0x70, 0x77, 0x29, 0xa3 },
1007 { 0x04, 0x7e, 0xcb, 0xe9, 0xfc, 0xa5, 0x5f, 0x7b, 0xd0, 0x9e, 0xae, 0x36, 0xe1, 0x0c, 0xae, 0x1e },
1008 { 0xf5, 0xc8, 0x6a, 0xf3, 0x61, 0x62, 0xf1, 0x3a, 0x64, 0xf5, 0x4f, 0x6d, 0xc9, 0x58, 0x7c, 0x06 } };
1009
1010 static const unsigned char UTN_USERFirst_Hardware_Normalized_Issuer[] = {
1011 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55,
1012 0x53, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x02,
1013 0x55, 0x54, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x07, 0x13,
1014 0x0e, 0x53, 0x41, 0x4c, 0x54, 0x20, 0x4c, 0x41, 0x4b, 0x45, 0x20, 0x43,
1015 0x49, 0x54, 0x59, 0x31, 0x1e, 0x30, 0x1c, 0x06, 0x03, 0x55, 0x04, 0x0a,
1016 0x13, 0x15, 0x54, 0x48, 0x45, 0x20, 0x55, 0x53, 0x45, 0x52, 0x54, 0x52,
1017 0x55, 0x53, 0x54, 0x20, 0x4e, 0x45, 0x54, 0x57, 0x4f, 0x52, 0x4b, 0x31,
1018 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x18, 0x48, 0x54,
1019 0x54, 0x50, 0x3a, 0x2f, 0x2f, 0x57, 0x57, 0x57, 0x2e, 0x55, 0x53, 0x45,
1020 0x52, 0x54, 0x52, 0x55, 0x53, 0x54, 0x2e, 0x43, 0x4f, 0x4d, 0x31, 0x1f,
1021 0x30, 0x1d, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x16, 0x55, 0x54, 0x4e,
1022 0x2d, 0x55, 0x53, 0x45, 0x52, 0x46, 0x49, 0x52, 0x53, 0x54, 0x2d, 0x48,
1023 0x41, 0x52, 0x44, 0x57, 0x41, 0x52, 0x45
1024 };
1025 static const unsigned int UTN_USERFirst_Hardware_Normalized_Issuer_len = 151;
1026
1027
1028 static void SecPolicyCheckBlackListedLeaf(SecPVCRef pvc,
1029 CFStringRef key) {
1030 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, 0);
1031 CFDataRef issuer = cert ? SecCertificateGetNormalizedIssuerContent(cert) : NULL;
1032
1033 if (issuer && (CFDataGetLength(issuer) == (CFIndex)UTN_USERFirst_Hardware_Normalized_Issuer_len) &&
1034 (0 == memcmp(UTN_USERFirst_Hardware_Normalized_Issuer, CFDataGetBytePtr(issuer),
1035 UTN_USERFirst_Hardware_Normalized_Issuer_len)))
1036 {
1037 CFDataRef serial = SecCertificateCopySerialNumber(cert);
1038 if (serial) {
1039 CFIndex serial_length = CFDataGetLength(serial);
1040 const uint8_t *serial_ptr = CFDataGetBytePtr(serial);
1041
1042 while ((serial_length > 0) && (*serial_ptr == 0)) {
1043 serial_ptr++;
1044 serial_length--;
1045 }
1046
1047 if (serial_length == (CFIndex)sizeof(*UTN_USERFirst_Hardware_Serial)) {
1048 unsigned int i;
1049 for (i = 0; i < sizeof(UTN_USERFirst_Hardware_Serial)/sizeof(*UTN_USERFirst_Hardware_Serial); i++)
1050 {
1051 if (0 == memcmp(UTN_USERFirst_Hardware_Serial[i],
1052 serial_ptr, sizeof(*UTN_USERFirst_Hardware_Serial)))
1053 {
1054 SecPVCSetResult(pvc, key, 0, kCFBooleanFalse);
1055 return;
1056 }
1057 }
1058 }
1059 CFRelease(serial);
1060 }
1061 }
1062 }
1063
1064 static void SecPolicyCheckLeafMarkerOid(SecPVCRef pvc, CFStringRef key)
1065 {
1066 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, 0);
1067 SecPolicyRef policy = SecPVCGetPolicy(pvc);
1068 CFTypeRef value = CFDictionaryGetValue(policy->_options, key);
1069
1070 if (value && SecCertificateHasMarkerExtension(cert, value))
1071 return;
1072
1073 SecPVCSetResult(pvc, key, 0, kCFBooleanFalse);
1074 }
1075
1076 static void SecPolicyCheckIntermediateMarkerOid(SecPVCRef pvc, CFStringRef key)
1077 {
1078 CFIndex ix, count = SecPVCGetCertificateCount(pvc);
1079 SecPolicyRef policy = SecPVCGetPolicy(pvc);
1080 CFTypeRef value = CFDictionaryGetValue(policy->_options, key);
1081
1082 for (ix = 1; ix < count - 1; ix++) {
1083 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix);
1084 if (SecCertificateHasMarkerExtension(cert, value))
1085 return;
1086 }
1087 SecPVCSetResult(pvc, key, 0, kCFBooleanFalse);
1088 }
1089
1090 /****************************************************************************
1091 *********************** New rfc5280 Chain Validation ***********************
1092 ****************************************************************************/
1093
1094 #if 0
1095 typedef struct cert_path *cert_path_t;
1096 struct cert_path {
1097 int length;
1098 };
1099
1100 typedef struct x500_name *x500_name_t;
1101 struct x500_name {
1102 };
1103
1104 typedef struct algorithm_id *algorithm_id_t;
1105 struct algorithm_id {
1106 oid_t algorithm_oid;
1107 der_t parameters;
1108 };
1109
1110 typedef struct trust_anchor *trust_anchor_t;
1111 struct trust_anchor {
1112 x500_name_t issuer_name;
1113 algorithm_id_t public_key_algorithm; /* includes optional params */
1114 SecKeyRef public_key;
1115 };
1116
1117 typedef struct certificate_policy *certificate_policy_t;
1118 struct certificate_policy {
1119 policy_qualifier_t qualifiers;
1120 oid_t oid;
1121 SLIST_ENTRY(certificate_policy) policies;
1122 };
1123
1124 typedef struct policy_mapping *policy_mapping_t;
1125 struct policy_mapping {
1126 SLIST_ENTRY(policy_mapping) mappings;
1127 oid_t issuer_domain_policy;
1128 oid_t subject_domain_policy;
1129 };
1130
1131 typedef struct root_name *root_name_t;
1132 struct root_name {
1133 };
1134 #endif
1135
1136 struct policy_tree_add_ctx {
1137 oid_t p_oid;
1138 policy_qualifier_t p_q;
1139 };
1140
1141 /* 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}. */
1142 static bool policy_tree_add_if_match(policy_tree_t node, void *ctx) {
1143 struct policy_tree_add_ctx *info = (struct policy_tree_add_ctx *)ctx;
1144 policy_set_t policy_set;
1145 for (policy_set = node->expected_policy_set;
1146 policy_set;
1147 policy_set = policy_set->oid_next) {
1148 if (oid_equal(policy_set->oid, info->p_oid)) {
1149 policy_tree_add_child(node, &info->p_oid, info->p_q);
1150 return true;
1151 }
1152 }
1153 return false;
1154 }
1155
1156 /* 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}. */
1157 static bool policy_tree_add_if_any(policy_tree_t node, void *ctx) {
1158 struct policy_tree_add_ctx *info = (struct policy_tree_add_ctx *)ctx;
1159 if (oid_equal(node->valid_policy, oidAnyPolicy)) {
1160 policy_tree_add_child(node, &info->p_oid, info->p_q);
1161 return true;
1162 }
1163 return false;
1164 }
1165
1166 /* Return true iff node has a child with a valid_policy equal to oid. */
1167 static bool policy_tree_has_child_with_oid(policy_tree_t node,
1168 const oid_t *oid) {
1169 policy_tree_t child = node->children;
1170 for (child = node->children; child; child = child->siblings) {
1171 if (oid_equal(child->valid_policy, (*oid))) {
1172 return true;
1173 }
1174 }
1175 return false;
1176 }
1177
1178 /* 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. */
1179 static bool policy_tree_add_expected(policy_tree_t node, void *ctx) {
1180 policy_qualifier_t p_q = (policy_qualifier_t)ctx;
1181 policy_set_t policy_set;
1182 bool added_node = false;
1183 for (policy_set = node->expected_policy_set;
1184 policy_set;
1185 policy_set = policy_set->oid_next) {
1186 if (!policy_tree_has_child_with_oid(node, &policy_set->oid)) {
1187 policy_tree_add_child(node, &policy_set->oid, p_q);
1188 added_node = true;
1189 }
1190 }
1191 return added_node;
1192 }
1193
1194 #if 0
1195 /* 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. */
1196 static bool policy_tree_map(policy_tree_t node, void *ctx) {
1197 /* Can't map oidAnyPolicy. */
1198 if (oid_equal(node->valid_policy, oidAnyPolicy))
1199 return false;
1200
1201 const SecCEPolicyMappings *pm = (const SecCEPolicyMappings *)ctx;
1202 uint32_t mapping_ix, mapping_count = pm->numMappings;
1203 policy_set_t policy_set = NULL;
1204 /* First count how many mappings match this nodes valid_policy. */
1205 for (mapping_ix = 0; mapping_ix < mapping_count; ++mapping_ix) {
1206 const SecCEPolicyMapping *mapping = &pm->mappings[mapping_ix];
1207 if (oid_equal(node->valid_policy, mapping->issuerDomainPolicy)) {
1208 policy_set_t p_node = (policy_set_t)malloc(sizeof(*policy_set));
1209 p_node->oid = mapping->subjectDomainPolicy;
1210 p_node->oid_next = policy_set ? policy_set : NULL;
1211 policy_set = p_node;
1212 }
1213 }
1214 if (policy_set) {
1215 policy_tree_set_expected_policy(node, policy_set);
1216 return true;
1217 }
1218 return false;
1219 }
1220 #endif
1221
1222 #define POLICY_MAPPING 0
1223 #define POLICY_SUBTREES 0
1224
1225 /* rfc5280 basic cert processing. */
1226 static void SecPolicyCheckBasicCertificateProcessing(SecPVCRef pvc,
1227 CFStringRef key) {
1228 /* Inputs */
1229 //cert_path_t path;
1230 CFIndex count = SecPVCGetCertificateCount(pvc);
1231 /* 64 bits cast: worst case here is we truncate the number of cert, and the validation may fail */
1232 assert((unsigned long)count<=UINT32_MAX); /* Debug check. Correct as long as CFIndex is long */
1233 uint32_t n = (uint32_t)count;
1234 bool is_anchored = SecPVCIsAnchored(pvc);
1235 if (is_anchored) {
1236 /* If the anchor is trusted we don't procces the last cert in the
1237 chain (root). */
1238 n--;
1239 } else {
1240 /* Add a detail for the root not being trusted. */
1241 if (SecPVCSetResultForced(pvc, kSecPolicyCheckAnchorTrusted,
1242 n - 1, kCFBooleanFalse, true))
1243 return;
1244 }
1245
1246 CFAbsoluteTime verify_time = SecPVCGetVerifyTime(pvc);
1247 //policy_set_t user_initial_policy_set = NULL;
1248 //trust_anchor_t anchor;
1249 bool initial_policy_mapping_inhibit = false;
1250 bool initial_explicit_policy = false;
1251 bool initial_any_policy_inhibit = false;
1252 #if POLICY_SUBTREES
1253 root_name_t initial_permitted_subtrees = NULL;
1254 root_name_t initial_excluded_subtrees = NULL;
1255 #endif
1256
1257 /* Initialization */
1258 pvc->valid_policy_tree = policy_tree_create(&oidAnyPolicy, NULL);
1259 #if POLICY_SUBTREES
1260 root_name_t permitted_subtrees = initial_permitted_subtrees;
1261 root_name_t excluded_subtrees = initial_excluded_subtrees;
1262 #endif
1263 uint32_t explicit_policy = initial_explicit_policy ? 0 : n + 1;
1264 uint32_t inhibit_any_policy = initial_any_policy_inhibit ? 0 : n + 1;
1265 uint32_t policy_mapping = initial_policy_mapping_inhibit ? 0 : n + 1;
1266
1267 #if 0
1268 /* Path builder ensures we only get cert chains with proper issuer
1269 chaining with valid signatures along the way. */
1270 algorithm_id_t working_public_key_algorithm = anchor->public_key_algorithm;
1271 SecKeyRef working_public_key = anchor->public_key;
1272 x500_name_t working_issuer_name = anchor->issuer_name;
1273 #endif
1274 uint32_t i, max_path_length = n;
1275 SecCertificateRef cert = NULL;
1276 for (i = 1; i <= n; ++i) {
1277 /* Process Cert */
1278 cert = SecPVCGetCertificateAtIndex(pvc, n - i);
1279 bool is_self_issued = SecPVCIsCertificateAtIndexSelfSigned(pvc, n - i);
1280
1281 /* (a) Verify the basic certificate information. */
1282 /* @@@ Ensure that cert was signed with working_public_key_algorithm
1283 using the working_public_key and the working_public_key_parameters. */
1284 #if 1
1285 /* Already done by chain builder. */
1286 if (!SecCertificateIsValid(cert, verify_time)) {
1287 CFStringRef fail_key = i == n ? kSecPolicyCheckValidLeaf : kSecPolicyCheckValidIntermediates;
1288 if (!SecPVCSetResult(pvc, fail_key, n - i, kCFBooleanFalse))
1289 return;
1290 }
1291 #endif
1292 #if 0
1293 /* Check revocation status if the certificate asks for it. */
1294 CFArrayRef ocspResponders = SecCertificateGetOCSPResponders(cert);
1295 if (ocspResponders) {
1296 SecPVCSetCheckRevocation(pvc);
1297 }
1298 #endif
1299 /* @@@ cert.issuer == working_issuer_name. */
1300
1301 #if POLICY_SUBTREES
1302 /* (b) (c) */
1303 if (!is_self_issued || i == n) {
1304 /* Verify that the subject name is within one of the permitted_subtrees for X.500 distinguished names, and verify that each of the alternative names in the subjectAltName extension (critical or non-critical) is within one of the permitted_subtrees for that name type. */
1305 /* Verify that the subject name is not within any of the excluded_subtrees for X.500 distinguished names, and verify that each of the alternative names in the subjectAltName extension (critical or non-critical) is not within any of the excluded_subtrees for that name type. */
1306 }
1307 #endif
1308 /* (d) */
1309 if (pvc->valid_policy_tree) {
1310 const SecCECertificatePolicies *cp =
1311 SecCertificateGetCertificatePolicies(cert);
1312 size_t policy_ix, policy_count = cp ? cp->numPolicies : 0;
1313 for (policy_ix = 0; policy_ix < policy_count; ++policy_ix) {
1314 const SecCEPolicyInformation *policy = &cp->policies[policy_ix];
1315 oid_t p_oid = policy->policyIdentifier;
1316 policy_qualifier_t p_q = &policy->policyQualifiers;
1317 struct policy_tree_add_ctx ctx = { p_oid, p_q };
1318 if (!oid_equal(p_oid, oidAnyPolicy)) {
1319 if (!policy_tree_walk_depth(pvc->valid_policy_tree, i - 1,
1320 policy_tree_add_if_match, &ctx)) {
1321 policy_tree_walk_depth(pvc->valid_policy_tree, i - 1,
1322 policy_tree_add_if_any, &ctx);
1323 }
1324 }
1325 }
1326 /* The certificate policies extension includes the policy
1327 anyPolicy with the qualifier set AP-Q and either
1328 (a) inhibit_anyPolicy is greater than 0 or
1329 (b) i < n and the certificate is self-issued. */
1330 if (inhibit_any_policy > 0 || (i < n && is_self_issued)) {
1331 for (policy_ix = 0; policy_ix < policy_count; ++policy_ix) {
1332 const SecCEPolicyInformation *policy = &cp->policies[policy_ix];
1333 oid_t p_oid = policy->policyIdentifier;
1334 policy_qualifier_t p_q = &policy->policyQualifiers;
1335 if (oid_equal(p_oid, oidAnyPolicy)) {
1336 policy_tree_walk_depth(pvc->valid_policy_tree, i - 1,
1337 policy_tree_add_expected, (void *)p_q);
1338 }
1339 }
1340 }
1341 policy_tree_prune_childless(&pvc->valid_policy_tree, i - 1);
1342 /* (e) */
1343 if (!cp) {
1344 if (pvc->valid_policy_tree)
1345 policy_tree_prune(&pvc->valid_policy_tree);
1346 }
1347 }
1348 /* (f) Verify that either explicit_policy is greater than 0 or the
1349 valid_policy_tree is not equal to NULL. */
1350 if (!pvc->valid_policy_tree && explicit_policy == 0) {
1351 /* valid_policy_tree is empty and explicit policy is 0, illegal. */
1352 if (!SecPVCSetResultForced(pvc, key /* @@@ Need custom key */, n - i, kCFBooleanFalse, true))
1353 return;
1354 }
1355 /* If Last Cert in Path */
1356 if (i == n)
1357 break;
1358
1359 /* Prepare for Next Cert */
1360 #if POLICY_MAPPING
1361 /* (a) verify that anyPolicy does not appear as an
1362 issuerDomainPolicy or a subjectDomainPolicy */
1363 CFDictionaryRef pm = SecCertificateGetPolicyMappings(cert);
1364 if (pm) {
1365 uint32_t mapping_ix, mapping_count = pm->numMappings;
1366 for (mapping_ix = 0; mapping_ix < mapping_count; ++mapping_ix) {
1367 const SecCEPolicyMapping *mapping = &pm->mappings[mapping_ix];
1368 if (oid_equal(mapping->issuerDomainPolicy, oidAnyPolicy)
1369 || oid_equal(mapping->subjectDomainPolicy, oidAnyPolicy)) {
1370 /* Policy mapping uses anyPolicy, illegal. */
1371 if (!SecPVCSetResultForced(pvc, key /* @@@ Need custom key */, n - i, kCFBooleanFalse))
1372 return;
1373 }
1374 }
1375 /* (b) */
1376 /* (1) If the policy_mapping variable is greater than 0 */
1377 if (policy_mapping > 0) {
1378 if (!policy_tree_walk_depth(pvc->valid_policy_tree, i,
1379 policy_tree_map, (void *)pm)) {
1380 /* 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:
1381
1382 (i) set the valid_policy to ID-P;
1383
1384 (ii) set the qualifier_set to the qualifier set of the
1385 policy anyPolicy in the certificate policies
1386 extension of certificate i; and
1387 (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. */
1388 }
1389 } else {
1390 #if 0
1391 /* (i) delete each node of depth i in the valid_policy_tree
1392 where ID-P is the valid_policy. */
1393 struct policy_tree_map_ctx ctx = { idp_oid, sdp_oid };
1394 policy_tree_walk_depth(pvc->valid_policy_tree, i,
1395 policy_tree_delete_if_match, &ctx);
1396 #endif
1397 /* (ii) If there is a node in the valid_policy_tree of depth
1398 i-1 or less without any child nodes, delete that
1399 node. Repeat this step until there are no nodes of
1400 depth i-1 or less without children. */
1401 policy_tree_prune_childless(&pvc->valid_policy_tree, i - 1);
1402 }
1403 }
1404 #endif /* POLICY_MAPPING */
1405 /* (c)(d)(e)(f) */
1406 //working_issuer_name = SecCertificateGetNormalizedSubjectContent(cert);
1407 //working_public_key = SecCertificateCopyPublicKey(cert);
1408 //working_public_key_parameters = SecCertificateCopyPublicKeyParameters(cert);
1409 //working_public_key_algorithm = SecCertificateCopyPublicKeyAlgorithm(cert);
1410 #if POLICY_SUBTREES
1411 /* (g) If a name constraints extension is included in the certificate, modify the permitted_subtrees and excluded_subtrees state variables as follows:
1412 */
1413 /* @@@ handle name constraints. */
1414 #endif
1415 /* (h) */
1416 if (!is_self_issued) {
1417 if (explicit_policy)
1418 explicit_policy--;
1419 if (policy_mapping)
1420 policy_mapping--;
1421 if (inhibit_any_policy)
1422 inhibit_any_policy--;
1423 }
1424 /* (i) */
1425 const SecCEPolicyConstraints *pc =
1426 SecCertificateGetPolicyConstraints(cert);
1427 if (pc) {
1428 if (pc->requireExplicitPolicyPresent
1429 && pc->requireExplicitPolicy < explicit_policy) {
1430 explicit_policy = pc->requireExplicitPolicy;
1431 }
1432 if (pc->inhibitPolicyMappingPresent
1433 && pc->inhibitPolicyMapping < policy_mapping) {
1434 policy_mapping = pc->inhibitPolicyMapping;
1435 }
1436 }
1437 /* (j) */
1438 uint32_t iap = SecCertificateGetInhibitAnyPolicySkipCerts(cert);
1439 if (iap < inhibit_any_policy) {
1440 inhibit_any_policy = iap;
1441 }
1442 /* (k) */
1443 const SecCEBasicConstraints *bc =
1444 SecCertificateGetBasicConstraints(cert);
1445 #if 0 /* Checked in chain builder pre signature verify already. */
1446 if (!bc || !bc->isCA) {
1447 /* Basic constraints not present or not marked as isCA, illegal. */
1448 if (!SecPVCSetResult(pvc, kSecPolicyCheckBasicContraints,
1449 n - i, kCFBooleanFalse))
1450 return;
1451 }
1452 #endif
1453 /* (l) */
1454 if (!is_self_issued) {
1455 if (max_path_length > 0) {
1456 max_path_length--;
1457 } else {
1458 /* max_path_len exceeded, illegal. */
1459 if (!SecPVCSetResult(pvc, kSecPolicyCheckBasicContraints,
1460 n - i, kCFBooleanFalse))
1461 return;
1462 }
1463 }
1464 /* (m) */
1465 if (bc && bc->pathLenConstraintPresent
1466 && bc->pathLenConstraint < max_path_length) {
1467 max_path_length = bc->pathLenConstraint;
1468 }
1469 #if 0 /* Checked in chain builder pre signature verify already. */
1470 /* (n) If a key usage extension is present, verify that the keyCertSign bit is set. */
1471 SecKeyUsage keyUsage = SecCertificateGetKeyUsage(cert);
1472 if (keyUsage && !(keyUsage & kSecKeyUsageKeyCertSign)) {
1473 if (!SecPVCSetResultForced(pvc, kSecPolicyCheckKeyUsage,
1474 n - i, kCFBooleanFalse, true))
1475 return;
1476 }
1477 #endif
1478 /* (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. */
1479 if (SecCertificateHasUnknownCriticalExtension(cert)) {
1480 /* Certificate contains one or more unknown critical extensions. */
1481 if (!SecPVCSetResult(pvc, kSecPolicyCheckCriticalExtensions,
1482 n - i, kCFBooleanFalse))
1483 return;
1484 }
1485 }
1486 /* Wrap up */
1487 cert = SecPVCGetCertificateAtIndex(pvc, 0);
1488 /* (a) */
1489 if (explicit_policy)
1490 explicit_policy--;
1491 /* (b) */
1492 const SecCEPolicyConstraints *pc = SecCertificateGetPolicyConstraints(cert);
1493 if (pc) {
1494 if (pc->requireExplicitPolicyPresent
1495 && pc->requireExplicitPolicy == 0) {
1496 explicit_policy = 0;
1497 }
1498 }
1499 /* (c) */
1500 //working_public_key = SecCertificateCopyPublicKey(cert);
1501 /* (d) */
1502 /* 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
1503 working_public_key_algorithm are different, set the working_public_key_parameters to null. */
1504 //working_public_key_parameters = SecCertificateCopyPublicKeyParameters(cert);
1505 /* (e) */
1506 //working_public_key_algorithm = SecCertificateCopyPublicKeyAlgorithm(cert);
1507 /* (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. */
1508 if (SecCertificateHasUnknownCriticalExtension(cert)) {
1509 /* Certificate contains one or more unknown critical extensions. */
1510 if (!SecPVCSetResult(pvc, kSecPolicyCheckCriticalExtensions,
1511 0, kCFBooleanFalse))
1512 return;
1513 }
1514 /* (g) Calculate the intersection of the valid_policy_tree and the user-initial-policy-set, as follows */
1515
1516 if (pvc->valid_policy_tree) {
1517 #if !defined(NDEBUG)
1518 policy_tree_dump(pvc->valid_policy_tree);
1519 #endif
1520 /* (g3c4) */
1521 //policy_tree_prune_childless(&pvc->valid_policy_tree, n - 1);
1522 }
1523
1524 /* If either (1) the value of explicit_policy variable is greater than
1525 zero or (2) the valid_policy_tree is not NULL, then path processing
1526 has succeeded. */
1527 if (!pvc->valid_policy_tree && explicit_policy == 0) {
1528 /* valid_policy_tree is empty and explicit policy is 0, illegal. */
1529 if (!SecPVCSetResultForced(pvc, key /* @@@ Need custom key */, 0, kCFBooleanFalse, true))
1530 return;
1531 }
1532 }
1533
1534 static policy_set_t policies_for_cert(SecCertificateRef cert) {
1535 policy_set_t policies = NULL;
1536 const SecCECertificatePolicies *cp =
1537 SecCertificateGetCertificatePolicies(cert);
1538 size_t policy_ix, policy_count = cp ? cp->numPolicies : 0;
1539 for (policy_ix = 0; policy_ix < policy_count; ++policy_ix) {
1540 policy_set_add(&policies, &cp->policies[policy_ix].policyIdentifier);
1541 }
1542 return policies;
1543 }
1544
1545 static void SecPolicyCheckEV(SecPVCRef pvc,
1546 CFStringRef key) {
1547 CFIndex ix, count = SecPVCGetCertificateCount(pvc);
1548 policy_set_t valid_policies = NULL;
1549
1550 for (ix = 0; ix < count; ++ix) {
1551 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix);
1552 policy_set_t policies = policies_for_cert(cert);
1553 if (ix == 0) {
1554 /* Subscriber */
1555 /* anyPolicy in the leaf isn't allowed for EV, so only init
1556 valid_policies if we have real policies. */
1557 if (!policy_set_contains(policies, &oidAnyPolicy)) {
1558 valid_policies = policies;
1559 policies = NULL;
1560 }
1561 } else if (ix < count - 1) {
1562 /* Subordinate CA */
1563 if (!SecPolicySubordinateCACertificateCouldBeEV(cert)) {
1564 secdebug("ev", "subordinate certificate is not ev");
1565 if (SecPVCSetResultForced(pvc, key,
1566 ix, kCFBooleanFalse, true)) {
1567 policy_set_free(valid_policies);
1568 policy_set_free(policies);
1569 return;
1570 }
1571 }
1572 policy_set_intersect(&valid_policies, policies);
1573 } else {
1574 /* Root CA */
1575 if (!SecPolicyRootCACertificateIsEV(cert, valid_policies)) {
1576 secdebug("ev", "anchor certificate is not ev");
1577 if (SecPVCSetResultForced(pvc, key,
1578 ix, kCFBooleanFalse, true)) {
1579 policy_set_free(valid_policies);
1580 policy_set_free(policies);
1581 return;
1582 }
1583 }
1584 }
1585 policy_set_free(policies);
1586 if (!valid_policies) {
1587 secdebug("ev", "valid_policies set is empty: chain not ev");
1588 /* If we ever get into a state where no policies are valid anymore
1589 this can't be an ev chain. */
1590 if (SecPVCSetResultForced(pvc, key,
1591 ix, kCFBooleanFalse, true)) {
1592 return;
1593 }
1594 }
1595 }
1596
1597 policy_set_free(valid_policies);
1598
1599 /* (a) EV Subscriber Certificates Each EV Certificate issued by the CA to a
1600 Subscriber MUST contain an OID defined by the CA in the certificate’s
1601 certificatePolicies extension that: (i) indicates which CA policy statement relates
1602 to that certificate, (ii) asserts the CA’s adherence to and compliance with these
1603 Guidelines, and (iii), by pre-agreement with the Application Software Vendor,
1604 marks the certificate as being an EV Certificate.
1605 (b) EV Subordinate CA Certificates
1606 (1) Certificates issued to Subordinate CAs that are not controlled by the issuing
1607 CA MUST contain one or more OIDs defined by the issuing CA that
1608 explicitly identify the EV Policies that are implemented by the Subordinate
1609 CA;
1610 (2) Certificates issued to Subordinate CAs that are controlled by the Root CA
1611 MAY contain the special anyPolicy OID (2.5.29.32.0).
1612 (c) Root CA Certificates Root CA Certificates SHOULD NOT contain the
1613 certificatePolicies or extendedKeyUsage extensions.
1614 */
1615 }
1616
1617 static void SecPolicyCheckRevocation(SecPVCRef pvc,
1618 CFStringRef key) {
1619 SecPVCSetCheckRevocation(pvc);
1620 }
1621
1622 static void SecPolicyCheckNoNetworkAccess(SecPVCRef pvc,
1623 CFStringRef key) {
1624 SecPathBuilderSetCanAccessNetwork(pvc->builder, false);
1625 }
1626
1627 #pragma mark -
1628 #pragma mark SecRVCRef
1629 /********************************************************
1630 ****************** SecRVCRef Functions *****************
1631 ********************************************************/
1632
1633 /* Revocation verification context. */
1634 struct OpaqueSecRVC {
1635 /* Will contain the response data. */
1636 asynchttp_t http;
1637
1638 /* Pointer to the pvc for this revocation check. */
1639 SecPVCRef pvc;
1640
1641 /* The ocsp request we send to each responder. */
1642 SecOCSPRequestRef ocspRequest;
1643
1644 /* Index of cert in pvc that this RVC is for 0 = leaf, etc. */
1645 CFIndex certIX;
1646
1647 /* Index in array returned by SecCertificateGetOCSPResponders() for current
1648 responder. */
1649 CFIndex responderIX;
1650
1651 /* URL of current responder. */
1652 CFURLRef responder;
1653
1654 /* Date until which this revocation status is valid. */
1655 CFAbsoluteTime nextUpdate;
1656
1657 bool done;
1658 };
1659 typedef struct OpaqueSecRVC *SecRVCRef;
1660
1661 static void SecRVCDelete(SecRVCRef rvc) {
1662 secdebug("alloc", "%p", rvc);
1663 asynchttp_free(&rvc->http);
1664 SecOCSPRequestFinalize(rvc->ocspRequest);
1665 }
1666
1667 /* Return the next responder we should contact for this rvc or NULL if we
1668 exhausted them all. */
1669 static CFURLRef SecRVCGetNextResponder(SecRVCRef rvc) {
1670 SecCertificateRef cert = SecPVCGetCertificateAtIndex(rvc->pvc, rvc->certIX);
1671 CFArrayRef ocspResponders = SecCertificateGetOCSPResponders(cert);
1672 if (ocspResponders) {
1673 CFIndex responderCount = CFArrayGetCount(ocspResponders);
1674 while (rvc->responderIX < responderCount) {
1675 CFURLRef responder = CFArrayGetValueAtIndex(ocspResponders, rvc->responderIX);
1676 rvc->responderIX++;
1677 CFStringRef scheme = CFURLCopyScheme(responder);
1678 if (scheme) {
1679 /* We only support http and https responders currently. */
1680 bool valid_responder = (CFEqual(CFSTR("http"), scheme) ||
1681 CFEqual(CFSTR("https"), scheme));
1682 CFRelease(scheme);
1683 if (valid_responder)
1684 return responder;
1685 }
1686 }
1687 }
1688 return NULL;
1689 }
1690
1691 /* Fire off an async http request for this certs revocation status, return
1692 false if request was queued, true if we're done. */
1693 static bool SecRVCFetchNext(SecRVCRef rvc) {
1694 while ((rvc->responder = SecRVCGetNextResponder(rvc))) {
1695 CFDataRef request = SecOCSPRequestGetDER(rvc->ocspRequest);
1696 if (!request)
1697 goto errOut;
1698
1699 if (!asyncHttpPost(rvc->responder, request, &rvc->http)) {
1700 /* Async request was posted, wait for reply. */
1701 return false;
1702 }
1703 }
1704
1705 errOut:
1706 rvc->done = true;
1707 return true;
1708 }
1709
1710 /* Proccess a verified ocsp response for a given cert. Return true if the
1711 certificate status was obtained. */
1712 static bool SecOCSPSingleResponseProccess(SecOCSPSingleResponseRef this,
1713 SecRVCRef rvc) {
1714 bool proccessed;
1715 switch (this->certStatus) {
1716 case CS_Good:
1717 secdebug("ocsp", "CS_Good for cert %u", rvc->certIX);
1718 /* @@@ Mark cert as valid until a given date (nextUpdate if we have one)
1719 in the info dictionary. */
1720 //cert.revokeCheckGood(true);
1721 rvc->nextUpdate = this->nextUpdate;
1722 proccessed = true;
1723 break;
1724 case CS_Revoked:
1725 secdebug("ocsp", "CS_Revoked for cert %u", rvc->certIX);
1726 /* @@@ Mark cert as revoked (with reason) at revocation date in
1727 the info dictionary, or perhaps we should use a different key per
1728 reason? That way a client using exceptions can ignore some but
1729 not all reasons. */
1730 SInt32 reason = this->crlReason;
1731 CFNumberRef cfreason = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &reason);
1732 SecPVCSetResultForced(rvc->pvc, kSecPolicyCheckRevocation, rvc->certIX,
1733 cfreason, true);
1734 CFRelease(cfreason);
1735 proccessed = true;
1736 break;
1737 case CS_Unknown:
1738 /* not an error, no per-cert status, nothing here */
1739 secdebug("ocsp", "CS_Unknown for cert %u", rvc->certIX);
1740 proccessed = false;
1741 break;
1742 default:
1743 secdebug("ocsp", "BAD certStatus (%d) for cert %u",
1744 (int)this->certStatus, rvc->certIX);
1745 proccessed = false;
1746 break;
1747 }
1748
1749 return proccessed;
1750 }
1751
1752 static bool SecOCSPResponseVerify(SecOCSPResponseRef ocspResponse, SecRVCRef rvc) {
1753 bool trusted;
1754 SecCertificatePathRef issuer = SecCertificatePathCopyFromParent(rvc->pvc->path, rvc->certIX + 1);
1755 SecCertificatePathRef signer = SecOCSPResponseCopySigner(ocspResponse, issuer);
1756 CFRelease(issuer);
1757
1758 if (signer) {
1759 if (signer == issuer) {
1760 /* We already know we trust issuer since it's the path we are
1761 trying to verify minus the leaf. */
1762 secdebug("ocsp", "ocsp responder: %@ response signed by issuer",
1763 rvc->responder);
1764 trusted = true;
1765 } else {
1766 secdebug("ocsp",
1767 "ocsp responder: %@ response signed by cert issued by issuer",
1768 rvc->responder);
1769 /* @@@ Now check that we trust signer. */
1770 const void *ocspSigner = SecPolicyCreateOCSPSigner();
1771 CFArrayRef policies = CFArrayCreate(kCFAllocatorDefault,
1772 &ocspSigner, 1, &kCFTypeArrayCallBacks);
1773 CFRelease(ocspSigner);
1774 CFAbsoluteTime verifyTime = SecOCSPResponseVerifyTime(ocspResponse);
1775 struct OpaqueSecPVC ospvc;
1776 SecPVCInit(&ospvc, rvc->pvc->builder, policies, verifyTime);
1777 CFRelease(policies);
1778 SecPVCSetPath(&ospvc, signer, NULL);
1779 SecPVCLeafChecks(&ospvc);
1780 if (ospvc.result) {
1781 bool completed = SecPVCPathChecks(&ospvc);
1782 /* If completed is false we are waiting for a callback, this
1783 shouldn't happen since we aren't asking for details, no
1784 revocation checking is done. */
1785 if (!completed) {
1786 ocspdErrorLog("SecPVCPathChecks unexpectedly started "
1787 "background job!");
1788 /* @@@ assert() or abort here perhaps? */
1789 }
1790 }
1791 if (ospvc.result) {
1792 secdebug("ocsp", "response satisfies ocspSigner policy",
1793 rvc->responder);
1794 trusted = true;
1795 } else {
1796 /* @@@ We don't trust the cert so don't use this response. */
1797 ocspdErrorLog("ocsp response signed by certificate which "
1798 "does not satisfy ocspSigner policy");
1799 trusted = false;
1800 }
1801 SecPVCDelete(&ospvc);
1802 }
1803
1804 CFRelease(signer);
1805 } else {
1806 /* @@@ No signer found for this ocsp response, discard it. */
1807 secdebug("ocsp", "ocsp responder: %@ no signer found for response",
1808 rvc->responder);
1809 trusted = false;
1810 }
1811
1812 #if DUMP_OCSPRESPONSES
1813 char buf[40];
1814 snprintf(buf, 40, "/tmp/ocspresponse%ld%s.der",
1815 rvc->certIX, (trusted ? "t" : "u"));
1816 secdumpdata(ocspResponse->data, buf);
1817 #endif
1818
1819 return trusted;
1820 }
1821
1822 /* Callback from async http code after an ocsp response has been received. */
1823 static void SecOCSPFetchCompleted(asynchttp_t *http, CFTimeInterval maxAge) {
1824 SecRVCRef rvc = (SecRVCRef)http->info;
1825 SecPVCRef pvc = rvc->pvc;
1826 SecOCSPResponseRef ocspResponse = NULL;
1827 if (http->response) {
1828 CFDataRef data = CFHTTPMessageCopyBody(http->response);
1829 if (data) {
1830 /* Parse the returned data as if it's an ocspResponse. */
1831 ocspResponse = SecOCSPResponseCreate(data, maxAge);
1832 CFRelease(data);
1833 }
1834 }
1835
1836 if (ocspResponse) {
1837 SecOCSPResponseStatus orStatus = SecOCSPGetResponseStatus(ocspResponse);
1838 if (orStatus == kSecOCSPSuccess) {
1839 SecOCSPSingleResponseRef sr =
1840 SecOCSPResponseCopySingleResponse(ocspResponse, rvc->ocspRequest);
1841 if (!sr) {
1842 /* The ocsp response didn't have a singleResponse for the cert
1843 we are looking for, let's try the next responder. */
1844 secdebug("ocsp",
1845 "ocsp responder: %@ did not include status of requested cert",
1846 rvc->responder);
1847 } else {
1848 /* We got a singleResponse for the cert we are interested in,
1849 let's proccess it. */
1850 /* @@@ If the responder doesn't have the ocsp-nocheck extension
1851 we should check whether the leaf was revoked (we are
1852 already checking the rest of the chain). */
1853 /* Check the OCSP response signature and verify the
1854 response. */
1855 if (SecOCSPResponseVerify(ocspResponse, rvc)) {
1856 secdebug("ocsp","responder: %@ sent proper response",
1857 rvc->responder);
1858
1859 if (SecOCSPSingleResponseProccess(sr, rvc)) {
1860 if (rvc->nextUpdate == 0) {
1861 rvc->nextUpdate =
1862 SecOCSPResponseGetExpirationTime(ocspResponse);
1863 }
1864 /* If the singleResponse had meaningful information, we
1865 cache the response. */
1866 SecOCSPCacheAddResponse(ocspResponse, rvc->responder);
1867 rvc->done = true;
1868 }
1869 }
1870 SecOCSPSingleResponseDestroy(sr);
1871 }
1872 } else {
1873 /* ocsp response not ok. Let's try next responder. */
1874 secdebug("ocsp", "responder: %@ returned status: %d",
1875 rvc->responder, orStatus);
1876 #if 0
1877 if (!SecPVCSetResultForced(pvc, kSecPolicyCheckRevocation,
1878 rvc->certIX, kCFBooleanFalse, true))
1879 return;
1880 #endif
1881 }
1882 SecOCSPResponseFinalize(ocspResponse);
1883 }
1884
1885 if (!rvc->done) {
1886 /* Clear the data for the next response. */
1887 asynchttp_free(http);
1888 SecRVCFetchNext(rvc);
1889 }
1890
1891 if (rvc->done) {
1892 SecRVCDelete(rvc);
1893 if (!--pvc->asyncJobCount) {
1894 SecPathBuilderStep(pvc->builder);
1895 }
1896 }
1897 }
1898
1899 static void SecRVCInit(SecRVCRef rvc, SecPVCRef pvc, CFIndex certIX) {
1900 secdebug("alloc", "%p", rvc);
1901 rvc->pvc = pvc;
1902 rvc->certIX = certIX;
1903 rvc->http.completed = SecOCSPFetchCompleted;
1904 rvc->http.info = rvc;
1905 rvc->ocspRequest = NULL;
1906 rvc->responderIX = 0;
1907 rvc->responder = NULL;
1908 rvc->nextUpdate = 0;
1909 rvc->done = false;
1910 }
1911
1912
1913 static bool SecPVCCheckRevocation(SecPVCRef pvc) {
1914 secdebug("ocsp", "checking revocation");
1915 CFIndex certIX, certCount = SecPVCGetCertificateCount(pvc);
1916 bool completed = true;
1917 if (certCount <= 1) {
1918 /* Can't verify without an issuer; we're done */
1919 return completed;
1920 }
1921 if (!SecPVCIsAnchored(pvc)) {
1922 /* We can't check revocation for chains without a trusted anchor. */
1923 return completed;
1924 }
1925 certCount--;
1926
1927 #if 0
1928 /* @@@ Implement getting this value from the client.
1929 Optional responder passed in though policy. */
1930 CFURLRef localResponder = NULL;
1931 /* Generate a nonce in outgoing request if true. */
1932 bool genNonce = false;
1933 /* Require a nonce in response if true. */
1934 bool requireRespNonce = false;
1935 bool cacheReadDisable = false;
1936 bool cacheWriteDisable = false;
1937 #endif
1938
1939 if (pvc->rvcs) {
1940 /* We have done revocation checking already, we're done. */
1941 secdebug("ocsp", "Not rechecking revocation");
1942 return completed;
1943 }
1944
1945 /* Setup things so we check revocation status of all certs except the
1946 anchor. */
1947 pvc->rvcs = calloc(sizeof(struct OpaqueSecRVC), certCount);
1948
1949 #if 0
1950 /* Lookup cached revocation data for each certificate. */
1951 for (certIX = 0; certIX < certCount; ++certIX) {
1952 SecCertificateRef cert = SecPVCGetCertificateAtIndex(rvc->pvc, rvc->certIX);
1953 CFArrayRef ocspResponders = SecCertificateGetOCSPResponders(cert);
1954 if (ocspResponders) {
1955 /* First look though passed in ocsp responses. */
1956 //SecPVCGetOCSPResponseForCertificateAtIndex(pvc, ix, singleResponse);
1957
1958 /* Then look though shared cache (we don't care which responder
1959 something came from here). */
1960 CFDataRef ocspResponse = SecOCSPCacheCopyMatching(SecCertIDRef certID, NULL);
1961
1962 /* Now let's parse the response. */
1963 if (decodeOCSPResponse(ocspResp)) {
1964 secdebug("ocsp", "response ok: %@", ocspResp);
1965 } else {
1966 secdebug("ocsp", "response bad: %@", ocspResp);
1967 /* ocsp response not ok. */
1968 if (!SecPVCSetResultForced(pvc, key, ix, kCFBooleanFalse, true))
1969 return completed;
1970 }
1971 CFReleaseSafe(ocspResp);
1972 } else {
1973 /* Check if certificate has any crl distributionPoints. */
1974 CFArrayRef distributionPoints = SecCertificateGetCRLDistributionPoints(cert);
1975 if (distributionPoints) {
1976 /* Look for a cached CRL and potentially delta CRL for this certificate. */
1977 }
1978 }
1979 }
1980 #endif
1981
1982 /* Note that if we are multi threaded and a job completes after it
1983 is started but before we return from this function, we don't want
1984 a callback to decrement asyncJobCount to zero before we finish issuing
1985 all the jobs. To avoid this we pretend we issued certCount async jobs,
1986 and decrement pvc->asyncJobCount for each cert that we don't start a
1987 background fetch for. */
1988 pvc->asyncJobCount = certCount;
1989
1990 /* Loop though certificates again and issue an ocsp fetch if the
1991 revocation status checking isn't done yet. */
1992 for (certIX = 0; certIX < certCount; ++certIX) {
1993 secdebug("ocsp", "checking revocation for cert: %ld", certIX);
1994 SecRVCRef rvc = &((SecRVCRef)pvc->rvcs)[certIX];
1995 SecRVCInit(rvc, pvc, certIX);
1996 if (rvc->done)
1997 continue;
1998
1999 SecCertificateRef cert = SecPVCGetCertificateAtIndex(rvc->pvc,
2000 rvc->certIX);
2001 /* The certIX + 1 is ok here since certCount is always at least 1
2002 less than the actual number of certs. */
2003 SecCertificateRef issuer = SecPVCGetCertificateAtIndex(rvc->pvc,
2004 rvc->certIX + 1);
2005
2006 rvc->ocspRequest = SecOCSPRequestCreate(cert, issuer);
2007 SecOCSPResponseRef ocspResponse;
2008 ocspResponse = SecOCSPCacheCopyMatching(rvc->ocspRequest, NULL);
2009 if (ocspResponse) {
2010 SecOCSPSingleResponseRef sr =
2011 SecOCSPResponseCopySingleResponse(ocspResponse, rvc->ocspRequest);
2012 if (!sr) {
2013 /* The cached ocsp response didn't have a singleResponse for
2014 the cert we are looking for, it's shouldn't be in the cache. */
2015 secdebug("ocsp", "cached ocsp response did not include status"
2016 " of requested cert");
2017 } else {
2018 /* We got a singleResponse for the cert we are interested in,
2019 let's proccess it. */
2020
2021 /* @@@ If the responder doesn't have the ocsp-nocheck extension
2022 we should check whether the leaf was revoked (we are
2023 already checking the rest of the chain). */
2024 /* Recheck the OCSP response signature and verify the
2025 response. */
2026 if (SecOCSPResponseVerify(ocspResponse, rvc)) {
2027 secdebug("ocsp","cached response still has valid signature");
2028
2029 if (SecOCSPSingleResponseProccess(sr, rvc)) {
2030 CFAbsoluteTime expTime =
2031 SecOCSPResponseGetExpirationTime(ocspResponse);
2032 if (rvc->nextUpdate == 0 || expTime < rvc->nextUpdate)
2033 rvc->nextUpdate = expTime;
2034 rvc->done = true;
2035 }
2036 }
2037 SecOCSPSingleResponseDestroy(sr);
2038 }
2039 SecOCSPResponseFinalize(ocspResponse);
2040 }
2041
2042 /* Unless we succefully checked the revocation status of this cert
2043 based on the cache, Attempt to fire off an async http request
2044 for this certs revocation status. */
2045 bool fetch_done = true;
2046 if (rvc->done || !SecPathBuilderCanAccessNetwork(pvc->builder) ||
2047 (fetch_done = SecRVCFetchNext(rvc))) {
2048 /* We got a cache hit or we aren't allowed to acces the network,
2049 or the async http post failed. */
2050 SecRVCDelete(rvc);
2051 /* We didn't really start a background job for this cert. */
2052 pvc->asyncJobCount--;
2053 } else if (!fetch_done) {
2054 /* We started at least one background fetch. */
2055 completed = false;
2056 }
2057 }
2058
2059 /* Return false if we started any background jobs. */
2060 /* We can't just return !pvc->asyncJobCount here, since if we started any
2061 jobs the completion callback will be called eventually and it will call
2062 SecPathBuilderStep(). If for some reason everything completed before we
2063 get here we still want the outer SecPathBuilderStep() to terminate so we
2064 keep track of whether we started any jobs and return false if so. */
2065 return completed;
2066 }
2067
2068 void SecPolicyServerInitalize(void) {
2069 gSecPolicyLeafCallbacks = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
2070 &kCFTypeDictionaryKeyCallBacks, NULL);
2071 gSecPolicyPathCallbacks = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
2072 &kCFTypeDictionaryKeyCallBacks, NULL);
2073 CFDictionaryAddValue(gSecPolicyPathCallbacks,
2074 kSecPolicyCheckBasicCertificateProcessing,
2075 SecPolicyCheckBasicCertificateProcessing);
2076 CFDictionaryAddValue(gSecPolicyPathCallbacks,
2077 kSecPolicyCheckCriticalExtensions, SecPolicyCheckCriticalExtensions);
2078 CFDictionaryAddValue(gSecPolicyPathCallbacks,
2079 kSecPolicyCheckIdLinkage, SecPolicyCheckIdLinkage);
2080 CFDictionaryAddValue(gSecPolicyLeafCallbacks,
2081 kSecPolicyCheckKeyUsage, SecPolicyCheckKeyUsage);
2082 CFDictionaryAddValue(gSecPolicyLeafCallbacks,
2083 kSecPolicyCheckExtendedKeyUsage, SecPolicyCheckExtendedKeyUsage);
2084 CFDictionaryAddValue(gSecPolicyLeafCallbacks,
2085 kSecPolicyCheckBasicContraints, SecPolicyCheckBasicContraints);
2086 CFDictionaryAddValue(gSecPolicyLeafCallbacks,
2087 kSecPolicyCheckNonEmptySubject, SecPolicyCheckNonEmptySubject);
2088 CFDictionaryAddValue(gSecPolicyLeafCallbacks,
2089 kSecPolicyCheckQualifiedCertStatements,
2090 SecPolicyCheckQualifiedCertStatements);
2091 CFDictionaryAddValue(gSecPolicyLeafCallbacks,
2092 kSecPolicyCheckSSLHostname, SecPolicyCheckSSLHostname);
2093 CFDictionaryAddValue(gSecPolicyLeafCallbacks,
2094 kSecPolicyCheckEmail, SecPolicyCheckEmail);
2095 CFDictionaryAddValue(gSecPolicyPathCallbacks,
2096 kSecPolicyCheckValidIntermediates, SecPolicyCheckValidIntermediates);
2097 CFDictionaryAddValue(gSecPolicyLeafCallbacks,
2098 kSecPolicyCheckValidLeaf, SecPolicyCheckValidLeaf);
2099 CFDictionaryAddValue(gSecPolicyPathCallbacks,
2100 kSecPolicyCheckValidRoot, SecPolicyCheckValidRoot);
2101 CFDictionaryAddValue(gSecPolicyPathCallbacks,
2102 kSecPolicyCheckIssuerCommonName, SecPolicyCheckIssuerCommonName);
2103 CFDictionaryAddValue(gSecPolicyLeafCallbacks,
2104 kSecPolicyCheckSubjectCommonNamePrefix,
2105 SecPolicyCheckSubjectCommonNamePrefix);
2106 CFDictionaryAddValue(gSecPolicyLeafCallbacks,
2107 kSecPolicyCheckSubjectCommonName,
2108 SecPolicyCheckSubjectCommonName);
2109 CFDictionaryAddValue(gSecPolicyLeafCallbacks,
2110 kSecPolicyCheckNotValidBefore,
2111 SecPolicyCheckNotValidBefore);
2112 CFDictionaryAddValue(gSecPolicyPathCallbacks,
2113 kSecPolicyCheckChainLength, SecPolicyCheckChainLength);
2114 CFDictionaryAddValue(gSecPolicyPathCallbacks,
2115 kSecPolicyCheckAnchorSHA1, SecPolicyCheckAnchorSHA1);
2116 CFDictionaryAddValue(gSecPolicyLeafCallbacks,
2117 kSecPolicyCheckSubjectOrganization,
2118 SecPolicyCheckSubjectOrganization);
2119 CFDictionaryAddValue(gSecPolicyLeafCallbacks,
2120 kSecPolicyCheckEAPTrustedServerNames,
2121 SecPolicyCheckEAPTrustedServerNames);
2122 CFDictionaryAddValue(gSecPolicyLeafCallbacks,
2123 kSecPolicyCheckSubjectCommonNameTEST,
2124 SecPolicyCheckSubjectCommonNameTEST);
2125 CFDictionaryAddValue(gSecPolicyLeafCallbacks,
2126 kSecPolicyCheckRevocation,
2127 SecPolicyCheckRevocation);
2128 CFDictionaryAddValue(gSecPolicyLeafCallbacks,
2129 kSecPolicyCheckNoNetworkAccess,
2130 SecPolicyCheckNoNetworkAccess);
2131 CFDictionaryAddValue(gSecPolicyLeafCallbacks,
2132 kSecPolicyCheckBlackListedLeaf,
2133 SecPolicyCheckBlackListedLeaf);
2134 CFDictionaryAddValue(gSecPolicyLeafCallbacks,
2135 kSecPolicyCheckLeafMarkerOid,
2136 SecPolicyCheckLeafMarkerOid);
2137 CFDictionaryAddValue(gSecPolicyPathCallbacks,
2138 kSecPolicyCheckIntermediateMarkerOid,
2139 SecPolicyCheckIntermediateMarkerOid);
2140
2141 /* Initialize gBlackListedKeys. */
2142 const uint8_t blacklisted_keys[][CC_SHA1_DIGEST_LENGTH] = {
2143 /* DigiNotar Root CA by DigiNotar Root CA (is also cross certified by entrust) */
2144 { 0x88, 0x68, 0xBF, 0xE0, 0x8E, 0x35, 0xC4, 0x3B, 0x38, 0x6B, 0x62, 0xF7, 0x28, 0x3B, 0x84, 0x81, 0xC8, 0x0C, 0xD7, 0x4D },
2145 /* DigiNotar Services 1024 CA.cer by Entrust.net Secure Server Certification Authority (revoked) */
2146 { 0xFE, 0xDC, 0x94, 0x49, 0x0C, 0x6F, 0xEF, 0x5C, 0x7F, 0xC6, 0xF1, 0x12, 0x99, 0x4F, 0x16, 0x49, 0xAD, 0xFB, 0x82, 0x65 },
2147 /* DigiNotar Cyber CA issued by GTE CyberTrust Global Root. (no yet revoked) */
2148 { 0xAB, 0xF9, 0x68, 0xDF, 0xCF, 0x4A, 0x37, 0xD7, 0x7B, 0x45, 0x8C, 0x5F, 0x72, 0xDE, 0x40, 0x44, 0xC3, 0x65, 0xBB, 0xC2 },
2149 /* DigiNotar PKIoverheid CA Overheid en Bedrijven */
2150 { 0x4C, 0x08, 0xC9, 0x8D, 0x76, 0xF1, 0x98, 0xC7, 0x3E, 0xDF, 0x3C, 0xD7, 0x2F, 0x75, 0x0D, 0xB1, 0x76, 0x79, 0x97, 0xCC },
2151 /* DigiNotar PKIoverheid CA Organisatie - G2 */
2152 { 0xBC, 0x5D, 0x94, 0x3B, 0xD9, 0xAB, 0x7B, 0x03, 0x25, 0x73, 0x61, 0xC2, 0xDB, 0x2D, 0xEE, 0xFC, 0xAB, 0x8F, 0x65, 0xA1 },
2153 /* Digisign Server ID - (Enrich) cross-certified by Entrust.net Certification Authority (2048), serial 1276011370 */
2154 { 0xa1, 0x3f, 0xd3, 0x7c, 0x04, 0x5b, 0xb4, 0xa3, 0x11, 0x2b,
2155 0xd8, 0x9b, 0x1a, 0x07, 0xe9, 0x04, 0xb2, 0xd2, 0x6e, 0x26 },
2156 /* Digisign Server ID - (Enrich) cross-certified by GTE CyberTrust Global Root, serial 120001705 */
2157 { 0xc6, 0x16, 0x93, 0x4e, 0x16, 0x17, 0xec, 0x16, 0xae, 0x8c,
2158 0x94, 0x76, 0xf3, 0x86, 0x6d, 0xc5, 0x74, 0x6e, 0x84, 0x77 },
2159 };
2160 #define NUM_BLACKLISTED_KEYS (sizeof(blacklisted_keys) / sizeof(*blacklisted_keys))
2161
2162 const void *keys[NUM_BLACKLISTED_KEYS];
2163 size_t ix;
2164 for (ix = 0; ix < NUM_BLACKLISTED_KEYS; ++ix) {
2165 keys[ix] = CFDataCreateWithBytesNoCopy(0, blacklisted_keys[ix], CC_SHA1_DIGEST_LENGTH, kCFAllocatorNull);
2166 }
2167 gBlackListedKeys = CFSetCreate(0, keys, NUM_BLACKLISTED_KEYS, &kCFTypeSetCallBacks);
2168 CFSetApplyFunction(gBlackListedKeys, (CFSetApplierFunction)CFRelease, 0);
2169 }
2170
2171 /* AUDIT[securityd](done):
2172 array (ok) is a caller provided array, only its cf type has
2173 been checked.
2174 The options (ok) field ends up in policy->_options unchecked, so every access
2175 of policy->_options needs to be validated.
2176 */
2177 static SecPolicyRef SecPolicyCreateWithArray(CFArrayRef array) {
2178 SecPolicyRef policy = NULL;
2179 require_quiet(array && CFArrayGetCount(array) == 2, errOut);
2180 CFStringRef oid = (CFStringRef)CFArrayGetValueAtIndex(array, 0);
2181 require_quiet(isString(oid), errOut);
2182 CFDictionaryRef options = (CFDictionaryRef)CFArrayGetValueAtIndex(array, 1);
2183 require_quiet(isDictionary(options), errOut);
2184 policy = SecPolicyCreate(oid, options);
2185 errOut:
2186 return policy;
2187 }
2188
2189 /* AUDIT[securityd](done):
2190 value (ok) is an element in a caller provided array.
2191 */
2192 static void deserializePolicy(const void *value, void *context) {
2193 CFArrayRef policyArray = (CFArrayRef)value;
2194 if (isArray(policyArray)) {
2195 CFTypeRef deserializedPolicy = SecPolicyCreateWithArray(policyArray);
2196 if (deserializedPolicy) {
2197 CFArrayAppendValue((CFMutableArrayRef)context, deserializedPolicy);
2198 CFRelease(deserializedPolicy);
2199 }
2200 }
2201 }
2202
2203 /* AUDIT[securityd](done):
2204 serializedPolicies (ok) is a caller provided array, only its cf type has
2205 been checked.
2206 */
2207 CFArrayRef SecPolicyArrayDeserialize(CFArrayRef serializedPolicies) {
2208 CFMutableArrayRef result = NULL;
2209 require_quiet(isArray(serializedPolicies), errOut);
2210 CFIndex count = CFArrayGetCount(serializedPolicies);
2211 result = CFArrayCreateMutable(kCFAllocatorDefault, count, &kCFTypeArrayCallBacks);
2212 CFRange all_policies = { 0, count };
2213 CFArrayApplyFunction(serializedPolicies, all_policies, deserializePolicy, result);
2214 errOut:
2215 return result;
2216 }
2217
2218 #pragma mark -
2219 #pragma mark SecPVCRef
2220 /********************************************************
2221 ****************** SecPVCRef Functions *****************
2222 ********************************************************/
2223
2224 void SecPVCInit(SecPVCRef pvc, SecPathBuilderRef builder, CFArrayRef policies,
2225 CFAbsoluteTime verifyTime) {
2226 secdebug("alloc", "%p", pvc);
2227 // Weird logging policies crashes.
2228 //secdebug("policy", "%@", policies);
2229 pvc->builder = builder;
2230 pvc->policies = policies;
2231 if (policies)
2232 CFRetain(policies);
2233 pvc->verifyTime = verifyTime;
2234 pvc->path = NULL;
2235 pvc->details = NULL;
2236 pvc->info = NULL;
2237 pvc->valid_policy_tree = NULL;
2238 pvc->callbacks = NULL;
2239 pvc->policyIX = 0;
2240 pvc->rvcs = NULL;
2241 pvc->asyncJobCount = 0;
2242 pvc->check_revocation = false;
2243 pvc->optionally_ev = false;
2244 pvc->is_ev = false;
2245 pvc->result = true;
2246 }
2247
2248 static void SecPVCDeleteRVCs(SecPVCRef pvc) {
2249 secdebug("alloc", "%p", pvc);
2250 if (pvc->rvcs) {
2251 free(pvc->rvcs);
2252 pvc->rvcs = NULL;
2253 }
2254 }
2255
2256 void SecPVCDelete(SecPVCRef pvc) {
2257 secdebug("alloc", "%p", pvc);
2258 CFReleaseNull(pvc->policies);
2259 CFReleaseNull(pvc->details);
2260 CFReleaseNull(pvc->info);
2261 if (pvc->valid_policy_tree) {
2262 policy_tree_prune(&pvc->valid_policy_tree);
2263 }
2264 SecPVCDeleteRVCs(pvc);
2265 }
2266
2267 void SecPVCSetPath(SecPVCRef pvc, SecCertificatePathRef path,
2268 CFArrayRef details) {
2269 secdebug("policy", "%@", path);
2270 if (pvc->path != path) {
2271 /* Changing path makes us clear the Revocation Verification Contexts */
2272 SecPVCDeleteRVCs(pvc);
2273 pvc->path = path;
2274 }
2275 pvc->details = details;
2276 CFReleaseNull(pvc->info);
2277 if (pvc->valid_policy_tree) {
2278 policy_tree_prune(&pvc->valid_policy_tree);
2279 }
2280 pvc->policyIX = 0;
2281 pvc->result = true;
2282 }
2283
2284 SecPolicyRef SecPVCGetPolicy(SecPVCRef pvc) {
2285 return (SecPolicyRef)CFArrayGetValueAtIndex(pvc->policies, pvc->policyIX);
2286 }
2287
2288 CFIndex SecPVCGetCertificateCount(SecPVCRef pvc) {
2289 return SecCertificatePathGetCount(pvc->path);
2290 }
2291
2292 SecCertificateRef SecPVCGetCertificateAtIndex(SecPVCRef pvc, CFIndex ix) {
2293 return SecCertificatePathGetCertificateAtIndex(pvc->path, ix);
2294 }
2295
2296 bool SecPVCIsCertificateAtIndexSelfSigned(SecPVCRef pvc, CFIndex ix) {
2297 return SecCertificatePathSelfSignedIndex(pvc->path) == ix;
2298 }
2299
2300 void SecPVCSetCheckRevocation(SecPVCRef pvc) {
2301 pvc->check_revocation = true;
2302 secdebug("ocsp", "deferred revocation checking enabled");
2303 }
2304
2305 bool SecPVCIsAnchored(SecPVCRef pvc) {
2306 return SecCertificatePathIsAnchored(pvc->path);
2307 }
2308
2309 CFAbsoluteTime SecPVCGetVerifyTime(SecPVCRef pvc) {
2310 return pvc->verifyTime;
2311 }
2312
2313 /* AUDIT[securityd](done):
2314 policy->_options is a caller provided dictionary, only its cf type has
2315 been checked.
2316 */
2317 bool SecPVCSetResultForced(SecPVCRef pvc,
2318 CFStringRef key, CFIndex ix, CFTypeRef result, bool force) {
2319
2320 secdebug("policy", "cert[%d]: %@ =(%s)[%s]> %@", ix, key,
2321 (pvc->callbacks == gSecPolicyLeafCallbacks ? "leaf"
2322 : (pvc->callbacks == gSecPolicyPathCallbacks ? "path"
2323 : "custom")),
2324 (force ? "force" : ""), result);
2325
2326 /* If this is not something the current policy cares about ignore
2327 this error and return true so our caller continues evaluation. */
2328 if (!force) {
2329 /* @@@ The right long term fix might be to check if none of the passed
2330 in policies contain this key, since not all checks are run for all
2331 policies. */
2332 SecPolicyRef policy = SecPVCGetPolicy(pvc);
2333 if (policy && !CFDictionaryContainsKey(policy->_options, key))
2334 return true;
2335 }
2336
2337 /* @@@ Check to see if the SecTrustSettings for the certificate in question
2338 tell us to ignore this error. */
2339 pvc->result = false;
2340 if (!pvc->details)
2341 return false;
2342
2343 CFMutableDictionaryRef detail =
2344 (CFMutableDictionaryRef)CFArrayGetValueAtIndex(pvc->details, ix);
2345
2346 /* Perhaps detail should have an array of results per key? As it stands
2347 in the case of multiple policy failures the last failure stands. */
2348 CFDictionarySetValue(detail, key, result);
2349
2350 return true;
2351 }
2352
2353 bool SecPVCSetResult(SecPVCRef pvc,
2354 CFStringRef key, CFIndex ix, CFTypeRef result) {
2355 return SecPVCSetResultForced(pvc, key, ix, result, false);
2356 }
2357
2358 /* AUDIT[securityd](done):
2359 key(ok) is a caller provided.
2360 value(ok, unused) is a caller provided.
2361 */
2362 static void SecPVCValidateKey(const void *key, const void *value,
2363 void *context) {
2364 SecPVCRef pvc = (SecPVCRef)context;
2365
2366 /* If our caller doesn't want full details and we failed earlier there is
2367 no point in doing additional checks. */
2368 if (!pvc->result && !pvc->details)
2369 return;
2370
2371 SecPolicyCheckFunction fcn = (SecPolicyCheckFunction)
2372 CFDictionaryGetValue(pvc->callbacks, key);
2373
2374 if (!fcn) {
2375 #if 0
2376 /* Why not to have optional policy checks rant:
2377 Not all keys are in all dictionaries anymore, so why not make checks
2378 optional? This way a client can ask for something and the server will
2379 do a best effort based on the supported flags. It works since they are
2380 synchronized now, but we need some debug checking here for now. */
2381 pvc->result = false;
2382 #endif
2383 if (pvc->callbacks == gSecPolicyLeafCallbacks) {
2384 if (!CFDictionaryContainsKey(gSecPolicyPathCallbacks, key)) {
2385 pvc->result = false;
2386 }
2387 } else if (pvc->callbacks == gSecPolicyPathCallbacks) {
2388 if (!CFDictionaryContainsKey(gSecPolicyLeafCallbacks, key)) {
2389 pvc->result = false;
2390 }
2391 } else {
2392 /* Non standard valdation phase, nothing is optional. */
2393 pvc->result = false;
2394 }
2395 return;
2396 }
2397
2398 fcn(pvc, (CFStringRef)key);
2399 }
2400
2401 /* AUDIT[securityd](done):
2402 policy->_options is a caller provided dictionary, only its cf type has
2403 been checked.
2404 */
2405 bool SecPVCLeafChecks(SecPVCRef pvc) {
2406 pvc->result = true;
2407 CFArrayRef policies = pvc->policies;
2408 CFIndex ix, count = CFArrayGetCount(policies);
2409 for (ix = 0; ix < count; ++ix) {
2410 SecPolicyRef policy = (SecPolicyRef)CFArrayGetValueAtIndex(policies, ix);
2411 pvc->policyIX = ix;
2412 /* Validate all keys for all policies. */
2413 pvc->callbacks = gSecPolicyLeafCallbacks;
2414 CFDictionaryApplyFunction(policy->_options, SecPVCValidateKey, pvc);
2415 if (!pvc->result && !pvc->details)
2416 return pvc->result;
2417 }
2418
2419 return pvc->result;
2420 }
2421
2422 bool SecPVCParentCertificateChecks(SecPVCRef pvc, CFIndex ix) {
2423 /* Check stuff common to intermediate and anchors. */
2424 CFAbsoluteTime verifyTime = SecPVCGetVerifyTime(pvc);
2425 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix);
2426 bool is_anchor = (ix == SecPVCGetCertificateCount(pvc) - 1
2427 && SecPVCIsAnchored(pvc));
2428 if (!SecCertificateIsValid(cert, verifyTime)) {
2429 /* Certificate has expired. */
2430 if (!SecPVCSetResult(pvc, is_anchor ? kSecPolicyCheckValidRoot
2431 : kSecPolicyCheckValidIntermediates, ix, kCFBooleanFalse))
2432 goto errOut;
2433 }
2434
2435 if (is_anchor) {
2436 /* Perform anchor specific checks. */
2437 /* Don't think we have any of these. */
2438 } else {
2439 /* Perform intermediate specific checks. */
2440
2441 /* (k) */
2442 const SecCEBasicConstraints *bc =
2443 SecCertificateGetBasicConstraints(cert);
2444 if (!bc || !bc->isCA) {
2445 /* Basic constraints not present or not marked as isCA, illegal. */
2446 if (!SecPVCSetResultForced(pvc, kSecPolicyCheckBasicContraints,
2447 ix, kCFBooleanFalse, true))
2448 goto errOut;
2449 }
2450 /* Consider adding (l) max_path_length checking here. */
2451
2452 /* (n) If a key usage extension is present, verify that the keyCertSign bit is set. */
2453 SecKeyUsage keyUsage = SecCertificateGetKeyUsage(cert);
2454 if (keyUsage && !(keyUsage & kSecKeyUsageKeyCertSign)) {
2455 if (!SecPVCSetResultForced(pvc, kSecPolicyCheckKeyUsage,
2456 ix, kCFBooleanFalse, true))
2457 goto errOut;
2458 }
2459 }
2460
2461 errOut:
2462 return pvc->result;
2463 }
2464
2465 bool SecPVCBlackListedKeyChecks(SecPVCRef pvc, CFIndex ix) {
2466 /* Check stuff common to intermediate and anchors. */
2467 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix);
2468 bool is_anchor = (ix == SecPVCGetCertificateCount(pvc) - 1
2469 && SecPVCIsAnchored(pvc));
2470 if (!is_anchor) {
2471 /* Check for blacklisted intermediates keys. */
2472 CFDataRef dgst = SecCertificateCopyPublicKeySHA1Digest(cert);
2473 if (dgst) {
2474 /* Check dgst against blacklist. */
2475 if (CFSetContainsValue(gBlackListedKeys, dgst)) {
2476 SecPVCSetResultForced(pvc, kSecPolicyCheckBlackListedKey,
2477 ix, kCFBooleanFalse, true);
2478 }
2479 CFRelease(dgst);
2480 }
2481 }
2482
2483 return pvc->result;
2484 }
2485
2486 /* AUDIT[securityd](done):
2487 policy->_options is a caller provided dictionary, only its cf type has
2488 been checked.
2489 */
2490 bool SecPVCPathChecks(SecPVCRef pvc) {
2491 secdebug("policy", "begin path: %@", pvc->path);
2492 bool completed = true;
2493 /* This needs to be initialized before we call any function that might call
2494 SecPVCSetResultForced(). */
2495 pvc->policyIX = 0;
2496 SecPolicyCheckIdLinkage(pvc, kSecPolicyCheckIdLinkage);
2497 if (pvc->result || pvc->details) {
2498 SecPolicyCheckBasicCertificateProcessing(pvc,
2499 kSecPolicyCheckBasicCertificateProcessing);
2500 }
2501
2502 CFArrayRef policies = pvc->policies;
2503 CFIndex count = CFArrayGetCount(policies);
2504 for (; pvc->policyIX < count; ++pvc->policyIX) {
2505 /* Validate all keys for all policies. */
2506 pvc->callbacks = gSecPolicyPathCallbacks;
2507 SecPolicyRef policy = SecPVCGetPolicy(pvc);
2508 CFDictionaryApplyFunction(policy->_options, SecPVCValidateKey, pvc);
2509 if (!pvc->result && !pvc->details)
2510 return completed;
2511 }
2512
2513 /* Check the things we can't check statically for the certificate path. */
2514 /* Critical Extensions, chainLength. */
2515
2516 /* Policy tests. */
2517 pvc->is_ev = false;
2518 if ((pvc->result || pvc->details) && pvc->optionally_ev) {
2519 bool pre_ev_check_result = pvc->result;
2520 SecPolicyCheckEV(pvc, kSecPolicyCheckExtendedValidation);
2521 pvc->is_ev = pvc->result;
2522 /* If ev checking failed, we still want to accept this chain
2523 as a non EV one, if it was valid as such. */
2524 pvc->result = pre_ev_check_result;
2525 }
2526 /* Check revocation only if the chain is valid so far. Then only check
2527 revocation if the client asked for it explicitly or is_ev is
2528 true. */
2529 if (pvc->result && (pvc->is_ev || pvc->check_revocation)) {
2530 completed = SecPVCCheckRevocation(pvc);
2531 }
2532
2533 //errOut:
2534 secdebug("policy", "end %strusted completed: %d path: %@",
2535 (pvc->result ? "" : "not "), completed, pvc->path);
2536 return completed;
2537 }
2538
2539 /* This function returns 0 to indicate revocation checking was not completed
2540 for this certificate chain, otherwise return to date at which the first
2541 piece of revocation checking info we used expires. */
2542 CFAbsoluteTime SecPVCGetEarliestNextUpdate(SecPVCRef pvc) {
2543 CFIndex certIX, certCount = SecPVCGetCertificateCount(pvc);
2544 CFAbsoluteTime enu = 0;
2545 if (certCount <= 1 || !pvc->rvcs) {
2546 return enu;
2547 }
2548 certCount--;
2549
2550 for (certIX = 0; certIX < certCount; ++certIX) {
2551 SecRVCRef rvc = &((SecRVCRef)pvc->rvcs)[certIX];
2552 if (rvc->nextUpdate == 0) {
2553 if (certIX > 0) {
2554 /* We allow for CA certs to not be revocation checked if they
2555 have no ocspResponders to check against, but the leaf
2556 must be checked in order for us to claim we did revocation
2557 checking. */
2558 SecCertificateRef cert =
2559 SecPVCGetCertificateAtIndex(rvc->pvc, rvc->certIX);
2560 CFArrayRef ocspResponders = SecCertificateGetOCSPResponders(cert);
2561 if (!ocspResponders || CFArrayGetCount(ocspResponders) == 0) {
2562 /* We can't check this cert so we don't consider it a soft
2563 failure that we didn't. Ideally we should support crl
2564 checking and remove this workaround, since that more
2565 strict. */
2566 continue;
2567 }
2568 }
2569 secdebug("ocsp", "revocation checking soft failure for cert: %ld",
2570 certIX);
2571 enu = rvc->nextUpdate;
2572 break;
2573 }
2574 if (enu == 0 || rvc->nextUpdate < enu) {
2575 enu = rvc->nextUpdate;
2576 }
2577 #if 0
2578 /* Perhaps we don't want to do this since some policies might
2579 ignore the certificate experation but still use revocation
2580 checking. */
2581
2582 /* Earliest certificate expiration date. */
2583 SecCertificateRef cert = SecPVCGetCertificateAtIndex(rvc->pvc, rvc->certIX);
2584 CFAbsoluteTime nva = SecCertificateNotValidAfter(cert);
2585 if (nva && (enu == 0 || nva < enu)
2586 enu = nva;
2587 #endif
2588 }
2589
2590 secdebug("ocsp", "revocation valid until: %lg", enu);
2591 return enu;
2592 }