2 * Copyright (c) 2008-2011 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
25 * SecPolicyServer.c - Trust policies dealing with certificate revocation.
28 #include <securityd/SecPolicyServer.h>
29 #include <Security/SecPolicyInternal.h>
30 #include <Security/SecPolicyPriv.h>
32 #include <securityd/asynchttp.h>
33 #include <securityd/policytree.h>
35 #include <CoreFoundation/CFTimeZone.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>
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>
61 #define ocspdErrorLog(args...) asl_log(NULL, NULL, ASL_LEVEL_ERR, ## args)
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
68 #if DUMP_OCSPRESPONSES
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
));
81 /********************************************************
82 ****************** SecPolicy object ********************
83 ********************************************************/
85 static CFMutableDictionaryRef gSecPolicyLeafCallbacks
= NULL
;
86 static CFMutableDictionaryRef gSecPolicyPathCallbacks
= NULL
;
87 static CFSetRef gBlackListedKeys
= NULL
;
89 static pthread_once_t gSecEVPolicyToAnchorDigestsOnce
= PTHREAD_ONCE_INIT
;
90 static CFDictionaryRef gSecEVPolicyToAnchorDigests
= NULL
;
92 /* Helper functions. */
94 static bool isArray(CFTypeRef cfType
) {
95 return cfType
&& CFGetTypeID(cfType
) == CFArrayGetTypeID();
98 static bool isData(CFTypeRef cfType
) {
99 return cfType
&& CFGetTypeID(cfType
) == CFDataGetTypeID();
102 static bool isDate(CFTypeRef cfType
) {
103 return cfType
&& CFGetTypeID(cfType
) == CFDateGetTypeID();
106 static bool isDictionary(CFTypeRef cfType
) {
107 return cfType
&& CFGetTypeID(cfType
) == CFDictionaryGetTypeID();
110 static bool isString(CFTypeRef cfType
) {
111 return cfType
&& CFGetTypeID(cfType
) == CFStringGetTypeID();
114 static void SecEVPolicyToAnchorDigestsInit(void) {
115 CFDataRef xmlData
= SecFrameworkCopyResourceContents(
116 CFSTR("EVRoots"), CFSTR("plist"), NULL
);
117 CFPropertyListRef evroots
= NULL
;
119 evroots
= CFPropertyListCreateFromXMLData(
120 kCFAllocatorDefault
, xmlData
, kCFPropertyListImmutable
, NULL
);
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
128 gSecEVPolicyToAnchorDigests
= (CFDictionaryRef
)evroots
;
130 secwarning("EVRoot.plist is wrong type.");
136 static CFArrayRef
SecPolicyAnchorDigestsForEVPolicy(const DERItem
*policyOID
) {
137 pthread_once(&gSecEVPolicyToAnchorDigestsOnce
,
138 SecEVPolicyToAnchorDigestsInit
);
139 CFArrayRef roots
= NULL
;
140 CFStringRef oid
= SecDERItemCopyOIDDecimalRepresentation(
141 kCFAllocatorDefault
, policyOID
);
143 roots
= (CFArrayRef
)CFDictionaryGetValue(gSecEVPolicyToAnchorDigests
,
145 if (roots
&& CFGetTypeID(roots
) != CFArrayGetTypeID()) {
146 ocspdErrorLog("EVRoot.plist has non array value");
155 static bool SecPolicyIsEVPolicy(const DERItem
*policyOID
) {
156 return SecPolicyAnchorDigestsForEVPolicy(policyOID
);
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
);
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;
175 require_quiet(good_ev_anchor
, notEV
);
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
);
187 CFAbsoluteTime jan2011
= 315532800;
188 if (SecCertificateNotValidBefore(certificate
) < jan2011
) {
189 /* At least MD5, SHA-1 with RSA 2048 or ECC NIST P-256. */
191 /* At least SHA-1, SHA-256, SHA-384 or SHA-512 with RSA 2048 or
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 */
206 CFArrayRef cdp
= SecCertificateGetCRLDistributionPoints(certificate
);
207 require_quiet(cdp
&& CFArrayGetCount(cdp
) > 0, notEV
);
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. */
218 /* At least SHA-1, SHA-256, SHA-284 or SHA-512 with RSA 2028 or
227 bool SecPolicySubscriberCertificateCouldBeEV(SecCertificateRef certificate
) {
228 /* 3. Subscriber Certificate. */
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. */
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;
243 require_quiet(found_ev_anchor_for_leaf_policy
, notEV
);
245 /* SecCertificateGetCRLDistributionPoints() is a noop right now */
247 /* (b) cRLDistributionPoint
248 (c) authorityInformationAccess */
249 CFArrayRef cdp
= SecCertificateGetCRLDistributionPoints(certificate
);
251 require_quiet(CFArrayGetCount(cdp
) > 0, notEV
);
253 CFArrayRef
or = SecCertificateGetOCSPResponders(certificate
);
254 require_quiet(or && CFArrayGetCount(or) > 0, notEV
);
255 //CFArrayRef ci = SecCertificateGetCAIssuers(certificate);
259 /* (d) basicConstraints
260 If present, the cA field MUST be set false. */
261 const SecCEBasicConstraints
*bc
= SecCertificateGetBasicConstraints(certificate
);
263 require_quiet(bc
->isCA
== false, notEV
);
267 SecKeyUsage ku
= SecCertificateGetKeyUsage(certificate
);
269 require_quiet((ku
& (kSecKeyUsageKeyCertSign
| kSecKeyUsageCRLSign
)) == 0, notEV
);
273 /* The EV Cert Spec errata specifies this, though this is a check for SSL
274 not specifically EV. */
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
);
282 CFAbsoluteTime jan2011
= 315532800;
283 if (SecCertificateNotValidAfter(certificate
) < jan2011
) {
284 /* At least SHA-1 with RSA 1024 or ECC NIST P-256. */
286 /* At least SHA-1, SHA-256, SHA-284 or SHA-512 with RSA 2028 or
295 /********************************************************
296 **************** SecPolicy Callbacks *******************
297 ********************************************************/
298 static void SecPolicyCheckCriticalExtensions(SecPVCRef pvc
,
302 static void SecPolicyCheckIdLinkage(SecPVCRef pvc
,
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
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
))
324 parentSubjectKeyID
= SecCertificateGetSubjectKeyID(cert
);
328 static bool keyusage_allows(SecKeyUsage keyUsage
, CFTypeRef xku
) {
329 if (!xku
|| CFGetTypeID(xku
) != CFNumberGetTypeID())
333 CFNumberGetValue((CFNumberRef
)xku
, kCFNumberSInt32Type
, &dku
);
334 SecKeyUsage ku
= (SecKeyUsage
)dku
;
335 return (keyUsage
& ku
) == ku
;
338 static void SecPolicyCheckKeyUsage(SecPVCRef pvc
,
340 SecCertificateRef leaf
= SecPVCGetCertificateAtIndex(pvc
, 0);
341 SecKeyUsage keyUsage
= SecCertificateGetKeyUsage(leaf
);
343 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
344 CFTypeRef xku
= CFDictionaryGetValue(policy
->_options
, key
);
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
)) {
355 match
= keyusage_allows(keyUsage
, xku
);
358 SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
);
362 static bool extendedkeyusage_allows(CFArrayRef extendedKeyUsage
,
364 if (!xeku
|| CFGetTypeID(xeku
) != CFDataGetTypeID())
366 if (extendedKeyUsage
) {
367 CFRange all
= { 0, CFArrayGetCount(extendedKeyUsage
) };
368 return CFArrayContainsValue(extendedKeyUsage
, all
, xeku
);
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;
376 /* AUDIT[securityd](done):
377 policy->_options is a caller provided dictionary, only its cf type has
380 static void SecPolicyCheckExtendedKeyUsage(SecPVCRef pvc
, CFStringRef key
) {
381 SecCertificateRef leaf
= SecPVCGetCertificateAtIndex(pvc
, 0);
382 CFArrayRef leafExtendedKeyUsage
= SecCertificateCopyExtendedKeyUsage(leaf
);
384 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
385 CFTypeRef xeku
= CFDictionaryGetValue(policy
->_options
, key
);
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
)) {
396 match
= extendedkeyusage_allows(leafExtendedKeyUsage
, xeku
);
398 CFReleaseSafe(leafExtendedKeyUsage
);
400 SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
);
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
);
415 /* Leaf certificate has basic constraints extension. */
416 if (!SecPVCSetResult(pvc
, key
, ix
, kCFBooleanFalse
))
418 } else if (!bc
->critical
) {
419 /* Basic constraints extension is not marked critical. */
420 if (!SecPVCSetResult(pvc
, key
, ix
, kCFBooleanFalse
))
425 if (ix
> 0 || count
== 1) {
427 /* Non leaf certificate marked as isCA false. */
428 if (!SecPVCSetResult(pvc
, key
, ix
, kCFBooleanFalse
))
432 if (bc
->pathLenConstraintPresent
) {
433 if (bc
->pathLenConstraint
< (uint32_t)(ix
- 1)) {
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
447 /* Path Length Constraint Exceeded. */
448 if (!SecPVCSetResult(pvc
, key
, ix
,
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
))
467 static void SecPolicyCheckBasicContraints(SecPVCRef pvc
,
469 //SecPolicyCheckBasicContraintsCommon(pvc, key, false);
472 static void SecPolicyCheckNonEmptySubject(SecPVCRef pvc
,
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
))
489 /* CA certificate has empty subject. */
490 if (!SecPVCSetResult(pvc
, key
, ix
, kCFBooleanFalse
))
497 static void SecPolicyCheckQualifiedCertStatements(SecPVCRef pvc
,
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
505 RFC 2818 Section 3.1. Server Identity
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.
513 Trailing '.' characters in the hostname will be ignored.
515 Returns true on match, else false.
517 static bool SecDNSMatch(CFStringRef hostname
, CFStringRef servername
) {
518 CFStringInlineBuffer hbuf
, sbuf
;
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
);
526 for (hix
= six
= 0; six
< slength
; ++six
) {
527 UniChar hch
, sch
= CFStringGetCharacterFromInlineBuffer(&sbuf
, six
);
529 if (six
+ 1 >= slength
) {
530 /* Trailing '*' in servername, match until end of hostname or
533 if (hix
>= hlength
) {
534 /* If we reach the end of the hostname we have a
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
;
546 /* Grab the character after the '*'. */
547 sch
= CFStringGetCharacterFromInlineBuffer(&sbuf
, ++six
);
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. */
555 /* We're looking at the '.' after the '*' in something of the
556 form 'foo*.com' or '*.com'. Match until next '.' in hostname. */
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. */
563 hch
= CFStringGetCharacterFromInlineBuffer(&hbuf
, hix
++);
564 } while (hch
!= '.');
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. */
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
))
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. */
587 /* Anything else is not a match. */
594 /* AUDIT[securityd](done):
595 policy->_options is a caller provided dictionary, only its cf type has
598 static void SecPolicyCheckSSLHostname(SecPVCRef pvc
,
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. */
611 SecCertificateRef leaf
= SecPVCGetCertificateAtIndex(pvc
, 0);
612 bool dnsMatch
= false;
613 CFArrayRef dnsNames
= SecCertificateCopyDNSNames(leaf
);
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
)) {
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
);
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
)) {
639 CFRelease(ipAddresses
);
644 /* Hostname mismatch or no hostnames found in certificate. */
645 SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
);
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. */
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
);
664 /* AUDIT[securityd](done):
665 policy->_options is a caller provided dictionary, only its cf type has
668 static void SecPolicyCheckEmail(SecPVCRef pvc
, CFStringRef key
) {
669 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
670 CFStringRef email
= (CFStringRef
)CFDictionaryGetValue(policy
->_options
, key
);
672 if (!isString(email
)) {
673 /* We can't return an error here and making the evaluation fail
674 won't help much either. */
678 SecCertificateRef leaf
= SecPVCGetCertificateAtIndex(pvc
, 0);
679 CFArrayRef addrs
= SecCertificateCopyRFC822Names(leaf
);
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
)) {
693 /* Hostname mismatch or no hostnames found in certificate. */
694 SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
);
698 static void SecPolicyCheckValidIntermediates(SecPVCRef pvc
,
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
))
712 static void SecPolicyCheckValidLeaf(SecPVCRef pvc
,
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
))
723 static void SecPolicyCheckValidRoot(SecPVCRef pvc
,
725 CFIndex ix
, count
= SecPVCGetCertificateCount(pvc
);
726 CFAbsoluteTime verifyTime
= SecPVCGetVerifyTime(pvc
);
728 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, ix
);
729 if (!SecCertificateIsValid(cert
, verifyTime
)) {
730 /* Root certificate has expired. */
731 if (!SecPVCSetResult(pvc
, key
, ix
, kCFBooleanFalse
))
736 /* AUDIT[securityd](done):
737 policy->_options is a caller provided dictionary, only its cf type has
740 static void SecPolicyCheckIssuerCommonName(SecPVCRef pvc
,
742 CFIndex count
= SecPVCGetCertificateCount(pvc
);
744 /* Can't check intermediates common name if there is no intermediate. */
745 SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
);
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. */
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
);
764 CFReleaseSafe(commonNames
);
767 /* AUDIT[securityd](done):
768 policy->_options is a caller provided dictionary, only its cf type has
771 static void SecPolicyCheckSubjectCommonName(SecPVCRef pvc
,
773 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, 0);
774 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
775 CFStringRef common_name
= (CFStringRef
)CFDictionaryGetValue(policy
->_options
,
777 if (!isString(common_name
)) {
778 /* @@@ We can't return an error here and making the evaluation fail
779 won't help much either. */
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
);
788 CFReleaseSafe(commonNames
);
791 /* AUDIT[securityd](done):
792 policy->_options is a caller provided dictionary, only its cf type has
795 static void SecPolicyCheckSubjectCommonNamePrefix(SecPVCRef pvc
,
797 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, 0);
798 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
799 CFStringRef prefix
= (CFStringRef
)CFDictionaryGetValue(policy
->_options
,
801 if (!isString(prefix
)) {
802 /* @@@ We can't return an error here and making the evaluation fail
803 won't help much either. */
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
);
812 CFReleaseSafe(commonNames
);
815 /* AUDIT[securityd](done):
816 policy->_options is a caller provided dictionary, only its cf type has
819 static void SecPolicyCheckSubjectCommonNameTEST(SecPVCRef pvc
,
821 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, 0);
822 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
823 CFStringRef common_name
= (CFStringRef
)CFDictionaryGetValue(policy
->_options
,
825 if (!isString(common_name
)) {
826 /* @@@ We can't return an error here and making the evaluation fail
827 won't help much either. */
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
) :
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
);
843 CFReleaseSafe(commonNames
);
846 /* AUDIT[securityd](done):
847 policy->_options is a caller provided dictionary, only its cf type has
850 static void SecPolicyCheckNotValidBefore(SecPVCRef pvc
,
852 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, 0);
853 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
854 CFDateRef date
= (CFDateRef
)CFDictionaryGetValue(policy
->_options
, key
);
856 /* @@@ We can't return an error here and making the evaluation fail
857 won't help much either. */
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
))
868 /* AUDIT[securityd](done):
869 policy->_options is a caller provided dictionary, only its cf type has
872 static void SecPolicyCheckChainLength(SecPVCRef pvc
,
874 CFIndex count
= SecPVCGetCertificateCount(pvc
);
875 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
876 CFNumberRef chainLength
=
877 (CFNumberRef
)CFDictionaryGetValue(policy
->_options
, key
);
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. */
885 if (value
!= count
) {
886 /* Chain length doesn't match policy requirement. */
887 if (!SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
))
892 /* AUDIT[securityd](done):
893 policy->_options is a caller provided dictionary, only its cf type has
896 static void SecPolicyCheckAnchorSHA1(SecPVCRef pvc
,
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. */
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
))
916 /* AUDIT[securityd](done):
917 policy->_options is a caller provided dictionary, only its cf type has
920 static void SecPolicyCheckSubjectOrganization(SecPVCRef pvc
,
922 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, 0);
923 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
924 CFStringRef org
= (CFStringRef
)CFDictionaryGetValue(policy
->_options
,
926 if (!isString(org
)) {
927 /* @@@ We can't return an error here and making the evaluation fail
928 won't help much either. */
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
);
937 CFReleaseSafe(organization
);
940 /* AUDIT[securityd](done):
941 policy->_options is a caller provided dictionary, only its cf type has
944 static void SecPolicyCheckEAPTrustedServerNames(SecPVCRef pvc
,
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
)
952 if (!isArray(trustedServerNames
)) {
953 /* @@@ We can't return an error here and making the evaluation fail
954 won't help much either. */
958 CFIndex tsnCount
= CFArrayGetCount(trustedServerNames
);
959 SecCertificateRef leaf
= SecPVCGetCertificateAtIndex(pvc
, 0);
960 bool dnsMatch
= false;
961 CFArrayRef dnsNames
= SecCertificateCopyDNSNames(leaf
);
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
);
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. */
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
984 if (SecDNSMatch(dns
, serverName
)) {
994 /* Hostname mismatch or no hostnames found in certificate. */
995 SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
);
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 } };
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
1025 static const unsigned int UTN_USERFirst_Hardware_Normalized_Issuer_len
= 151;
1028 static void SecPolicyCheckBlackListedLeaf(SecPVCRef pvc
,
1030 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, 0);
1031 CFDataRef issuer
= cert
? SecCertificateGetNormalizedIssuerContent(cert
) : NULL
;
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
)))
1037 CFDataRef serial
= SecCertificateCopySerialNumber(cert
);
1039 CFIndex serial_length
= CFDataGetLength(serial
);
1040 const uint8_t *serial_ptr
= CFDataGetBytePtr(serial
);
1042 while ((serial_length
> 0) && (*serial_ptr
== 0)) {
1047 if (serial_length
== (CFIndex
)sizeof(*UTN_USERFirst_Hardware_Serial
)) {
1049 for (i
= 0; i
< sizeof(UTN_USERFirst_Hardware_Serial
)/sizeof(*UTN_USERFirst_Hardware_Serial
); i
++)
1051 if (0 == memcmp(UTN_USERFirst_Hardware_Serial
[i
],
1052 serial_ptr
, sizeof(*UTN_USERFirst_Hardware_Serial
)))
1054 SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
);
1064 static void SecPolicyCheckLeafMarkerOid(SecPVCRef pvc
, CFStringRef key
)
1066 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, 0);
1067 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
1068 CFTypeRef value
= CFDictionaryGetValue(policy
->_options
, key
);
1070 if (value
&& SecCertificateHasMarkerExtension(cert
, value
))
1073 SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
);
1076 static void SecPolicyCheckIntermediateMarkerOid(SecPVCRef pvc
, CFStringRef key
)
1078 CFIndex ix
, count
= SecPVCGetCertificateCount(pvc
);
1079 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
1080 CFTypeRef value
= CFDictionaryGetValue(policy
->_options
, key
);
1082 for (ix
= 1; ix
< count
- 1; ix
++) {
1083 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, ix
);
1084 if (SecCertificateHasMarkerExtension(cert
, value
))
1087 SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
);
1090 /****************************************************************************
1091 *********************** New rfc5280 Chain Validation ***********************
1092 ****************************************************************************/
1095 typedef struct cert_path
*cert_path_t
;
1100 typedef struct x500_name
*x500_name_t
;
1104 typedef struct algorithm_id
*algorithm_id_t
;
1105 struct algorithm_id
{
1106 oid_t algorithm_oid
;
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
;
1117 typedef struct certificate_policy
*certificate_policy_t
;
1118 struct certificate_policy
{
1119 policy_qualifier_t qualifiers
;
1121 SLIST_ENTRY(certificate_policy
) policies
;
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
;
1131 typedef struct root_name
*root_name_t
;
1136 struct policy_tree_add_ctx
{
1138 policy_qualifier_t p_q
;
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
;
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
);
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
);
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
,
1169 policy_tree_t child
= node
->children
;
1170 for (child
= node
->children
; child
; child
= child
->siblings
) {
1171 if (oid_equal(child
->valid_policy
, (*oid
))) {
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
;
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
);
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
))
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
;
1215 policy_tree_set_expected_policy(node
, policy_set
);
1222 #define POLICY_MAPPING 0
1223 #define POLICY_SUBTREES 0
1225 /* rfc5280 basic cert processing. */
1226 static void SecPolicyCheckBasicCertificateProcessing(SecPVCRef pvc
,
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
);
1236 /* If the anchor is trusted we don't procces the last cert in the
1240 /* Add a detail for the root not being trusted. */
1241 if (SecPVCSetResultForced(pvc
, kSecPolicyCheckAnchorTrusted
,
1242 n
- 1, kCFBooleanFalse
, true))
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;
1253 root_name_t initial_permitted_subtrees
= NULL
;
1254 root_name_t initial_excluded_subtrees
= NULL
;
1257 /* Initialization */
1258 pvc
->valid_policy_tree
= policy_tree_create(&oidAnyPolicy
, NULL
);
1260 root_name_t permitted_subtrees
= initial_permitted_subtrees
;
1261 root_name_t excluded_subtrees
= initial_excluded_subtrees
;
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;
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
;
1274 uint32_t i
, max_path_length
= n
;
1275 SecCertificateRef cert
= NULL
;
1276 for (i
= 1; i
<= n
; ++i
) {
1278 cert
= SecPVCGetCertificateAtIndex(pvc
, n
- i
);
1279 bool is_self_issued
= SecPVCIsCertificateAtIndexSelfSigned(pvc
, n
- i
);
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. */
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
))
1293 /* Check revocation status if the certificate asks for it. */
1294 CFArrayRef ocspResponders
= SecCertificateGetOCSPResponders(cert
);
1295 if (ocspResponders
) {
1296 SecPVCSetCheckRevocation(pvc
);
1299 /* @@@ cert.issuer == working_issuer_name. */
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. */
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
);
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
);
1341 policy_tree_prune_childless(&pvc
->valid_policy_tree
, i
- 1);
1344 if (pvc
->valid_policy_tree
)
1345 policy_tree_prune(&pvc
->valid_policy_tree
);
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))
1355 /* If Last Cert in Path */
1359 /* Prepare for Next Cert */
1361 /* (a) verify that anyPolicy does not appear as an
1362 issuerDomainPolicy or a subjectDomainPolicy */
1363 CFDictionaryRef pm
= SecCertificateGetPolicyMappings(cert
);
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
))
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:
1382 (i) set the valid_policy to ID-P;
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. */
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
);
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);
1404 #endif /* POLICY_MAPPING */
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);
1411 /* (g) If a name constraints extension is included in the certificate, modify the permitted_subtrees and excluded_subtrees state variables as follows:
1413 /* @@@ handle name constraints. */
1416 if (!is_self_issued
) {
1417 if (explicit_policy
)
1421 if (inhibit_any_policy
)
1422 inhibit_any_policy
--;
1425 const SecCEPolicyConstraints
*pc
=
1426 SecCertificateGetPolicyConstraints(cert
);
1428 if (pc
->requireExplicitPolicyPresent
1429 && pc
->requireExplicitPolicy
< explicit_policy
) {
1430 explicit_policy
= pc
->requireExplicitPolicy
;
1432 if (pc
->inhibitPolicyMappingPresent
1433 && pc
->inhibitPolicyMapping
< policy_mapping
) {
1434 policy_mapping
= pc
->inhibitPolicyMapping
;
1438 uint32_t iap
= SecCertificateGetInhibitAnyPolicySkipCerts(cert
);
1439 if (iap
< inhibit_any_policy
) {
1440 inhibit_any_policy
= iap
;
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
))
1454 if (!is_self_issued
) {
1455 if (max_path_length
> 0) {
1458 /* max_path_len exceeded, illegal. */
1459 if (!SecPVCSetResult(pvc
, kSecPolicyCheckBasicContraints
,
1460 n
- i
, kCFBooleanFalse
))
1465 if (bc
&& bc
->pathLenConstraintPresent
1466 && bc
->pathLenConstraint
< max_path_length
) {
1467 max_path_length
= bc
->pathLenConstraint
;
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))
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
))
1487 cert
= SecPVCGetCertificateAtIndex(pvc
, 0);
1489 if (explicit_policy
)
1492 const SecCEPolicyConstraints
*pc
= SecCertificateGetPolicyConstraints(cert
);
1494 if (pc
->requireExplicitPolicyPresent
1495 && pc
->requireExplicitPolicy
== 0) {
1496 explicit_policy
= 0;
1500 //working_public_key = SecCertificateCopyPublicKey(cert);
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);
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
))
1514 /* (g) Calculate the intersection of the valid_policy_tree and the user-initial-policy-set, as follows */
1516 if (pvc
->valid_policy_tree
) {
1517 #if !defined(NDEBUG)
1518 policy_tree_dump(pvc
->valid_policy_tree
);
1521 //policy_tree_prune_childless(&pvc->valid_policy_tree, n - 1);
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
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))
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
);
1545 static void SecPolicyCheckEV(SecPVCRef pvc
,
1547 CFIndex ix
, count
= SecPVCGetCertificateCount(pvc
);
1548 policy_set_t valid_policies
= NULL
;
1550 for (ix
= 0; ix
< count
; ++ix
) {
1551 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, ix
);
1552 policy_set_t policies
= policies_for_cert(cert
);
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
;
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
);
1572 policy_set_intersect(&valid_policies
, policies
);
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
);
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)) {
1597 policy_set_free(valid_policies
);
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
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.
1617 static void SecPolicyCheckRevocation(SecPVCRef pvc
,
1619 SecPVCSetCheckRevocation(pvc
);
1622 static void SecPolicyCheckNoNetworkAccess(SecPVCRef pvc
,
1624 SecPathBuilderSetCanAccessNetwork(pvc
->builder
, false);
1628 #pragma mark SecRVCRef
1629 /********************************************************
1630 ****************** SecRVCRef Functions *****************
1631 ********************************************************/
1633 /* Revocation verification context. */
1634 struct OpaqueSecRVC
{
1635 /* Will contain the response data. */
1638 /* Pointer to the pvc for this revocation check. */
1641 /* The ocsp request we send to each responder. */
1642 SecOCSPRequestRef ocspRequest
;
1644 /* Index of cert in pvc that this RVC is for 0 = leaf, etc. */
1647 /* Index in array returned by SecCertificateGetOCSPResponders() for current
1649 CFIndex responderIX
;
1651 /* URL of current responder. */
1654 /* Date until which this revocation status is valid. */
1655 CFAbsoluteTime nextUpdate
;
1659 typedef struct OpaqueSecRVC
*SecRVCRef
;
1661 static void SecRVCDelete(SecRVCRef rvc
) {
1662 secdebug("alloc", "%p", rvc
);
1663 asynchttp_free(&rvc
->http
);
1664 SecOCSPRequestFinalize(rvc
->ocspRequest
);
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
);
1677 CFStringRef scheme
= CFURLCopyScheme(responder
);
1679 /* We only support http and https responders currently. */
1680 bool valid_responder
= (CFEqual(CFSTR("http"), scheme
) ||
1681 CFEqual(CFSTR("https"), scheme
));
1683 if (valid_responder
)
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
);
1699 if (!asyncHttpPost(rvc
->responder
, request
, &rvc
->http
)) {
1700 /* Async request was posted, wait for reply. */
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,
1715 switch (this->certStatus
) {
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
;
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
1730 SInt32 reason
= this->crlReason
;
1731 CFNumberRef cfreason
= CFNumberCreate(kCFAllocatorDefault
, kCFNumberSInt32Type
, &reason
);
1732 SecPVCSetResultForced(rvc
->pvc
, kSecPolicyCheckRevocation
, rvc
->certIX
,
1734 CFRelease(cfreason
);
1738 /* not an error, no per-cert status, nothing here */
1739 secdebug("ocsp", "CS_Unknown for cert %u", rvc
->certIX
);
1743 secdebug("ocsp", "BAD certStatus (%d) for cert %u",
1744 (int)this->certStatus
, rvc
->certIX
);
1752 static bool SecOCSPResponseVerify(SecOCSPResponseRef ocspResponse
, SecRVCRef rvc
) {
1754 SecCertificatePathRef issuer
= SecCertificatePathCopyFromParent(rvc
->pvc
->path
, rvc
->certIX
+ 1);
1755 SecCertificatePathRef signer
= SecOCSPResponseCopySigner(ocspResponse
, issuer
);
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",
1767 "ocsp responder: %@ response signed by cert issued by issuer",
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
);
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. */
1786 ocspdErrorLog("SecPVCPathChecks unexpectedly started "
1788 /* @@@ assert() or abort here perhaps? */
1792 secdebug("ocsp", "response satisfies ocspSigner policy",
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");
1801 SecPVCDelete(&ospvc
);
1806 /* @@@ No signer found for this ocsp response, discard it. */
1807 secdebug("ocsp", "ocsp responder: %@ no signer found for response",
1812 #if DUMP_OCSPRESPONSES
1814 snprintf(buf
, 40, "/tmp/ocspresponse%ld%s.der",
1815 rvc
->certIX
, (trusted
? "t" : "u"));
1816 secdumpdata(ocspResponse
->data
, buf
);
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
);
1830 /* Parse the returned data as if it's an ocspResponse. */
1831 ocspResponse
= SecOCSPResponseCreate(data
, maxAge
);
1837 SecOCSPResponseStatus orStatus
= SecOCSPGetResponseStatus(ocspResponse
);
1838 if (orStatus
== kSecOCSPSuccess
) {
1839 SecOCSPSingleResponseRef sr
=
1840 SecOCSPResponseCopySingleResponse(ocspResponse
, rvc
->ocspRequest
);
1842 /* The ocsp response didn't have a singleResponse for the cert
1843 we are looking for, let's try the next responder. */
1845 "ocsp responder: %@ did not include status of requested cert",
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
1855 if (SecOCSPResponseVerify(ocspResponse
, rvc
)) {
1856 secdebug("ocsp","responder: %@ sent proper response",
1859 if (SecOCSPSingleResponseProccess(sr
, rvc
)) {
1860 if (rvc
->nextUpdate
== 0) {
1862 SecOCSPResponseGetExpirationTime(ocspResponse
);
1864 /* If the singleResponse had meaningful information, we
1865 cache the response. */
1866 SecOCSPCacheAddResponse(ocspResponse
, rvc
->responder
);
1870 SecOCSPSingleResponseDestroy(sr
);
1873 /* ocsp response not ok. Let's try next responder. */
1874 secdebug("ocsp", "responder: %@ returned status: %d",
1875 rvc
->responder
, orStatus
);
1877 if (!SecPVCSetResultForced(pvc
, kSecPolicyCheckRevocation
,
1878 rvc
->certIX
, kCFBooleanFalse
, true))
1882 SecOCSPResponseFinalize(ocspResponse
);
1886 /* Clear the data for the next response. */
1887 asynchttp_free(http
);
1888 SecRVCFetchNext(rvc
);
1893 if (!--pvc
->asyncJobCount
) {
1894 SecPathBuilderStep(pvc
->builder
);
1899 static void SecRVCInit(SecRVCRef rvc
, SecPVCRef pvc
, CFIndex certIX
) {
1900 secdebug("alloc", "%p", rvc
);
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;
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 */
1921 if (!SecPVCIsAnchored(pvc
)) {
1922 /* We can't check revocation for chains without a trusted anchor. */
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;
1940 /* We have done revocation checking already, we're done. */
1941 secdebug("ocsp", "Not rechecking revocation");
1945 /* Setup things so we check revocation status of all certs except the
1947 pvc
->rvcs
= calloc(sizeof(struct OpaqueSecRVC
), certCount
);
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);
1958 /* Then look though shared cache (we don't care which responder
1959 something came from here). */
1960 CFDataRef ocspResponse
= SecOCSPCacheCopyMatching(SecCertIDRef certID
, NULL
);
1962 /* Now let's parse the response. */
1963 if (decodeOCSPResponse(ocspResp
)) {
1964 secdebug("ocsp", "response ok: %@", ocspResp
);
1966 secdebug("ocsp", "response bad: %@", ocspResp
);
1967 /* ocsp response not ok. */
1968 if (!SecPVCSetResultForced(pvc
, key
, ix
, kCFBooleanFalse
, true))
1971 CFReleaseSafe(ocspResp
);
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. */
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
;
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
);
1999 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(rvc
->pvc
,
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
,
2006 rvc
->ocspRequest
= SecOCSPRequestCreate(cert
, issuer
);
2007 SecOCSPResponseRef ocspResponse
;
2008 ocspResponse
= SecOCSPCacheCopyMatching(rvc
->ocspRequest
, NULL
);
2010 SecOCSPSingleResponseRef sr
=
2011 SecOCSPResponseCopySingleResponse(ocspResponse
, rvc
->ocspRequest
);
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");
2018 /* We got a singleResponse for the cert we are interested in,
2019 let's proccess it. */
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
2026 if (SecOCSPResponseVerify(ocspResponse
, rvc
)) {
2027 secdebug("ocsp","cached response still has valid signature");
2029 if (SecOCSPSingleResponseProccess(sr
, rvc
)) {
2030 CFAbsoluteTime expTime
=
2031 SecOCSPResponseGetExpirationTime(ocspResponse
);
2032 if (rvc
->nextUpdate
== 0 || expTime
< rvc
->nextUpdate
)
2033 rvc
->nextUpdate
= expTime
;
2037 SecOCSPSingleResponseDestroy(sr
);
2039 SecOCSPResponseFinalize(ocspResponse
);
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. */
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. */
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. */
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
);
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 },
2160 #define NUM_BLACKLISTED_KEYS (sizeof(blacklisted_keys) / sizeof(*blacklisted_keys))
2162 const void *keys
[NUM_BLACKLISTED_KEYS
];
2164 for (ix
= 0; ix
< NUM_BLACKLISTED_KEYS
; ++ix
) {
2165 keys
[ix
] = CFDataCreateWithBytesNoCopy(0, blacklisted_keys
[ix
], CC_SHA1_DIGEST_LENGTH
, kCFAllocatorNull
);
2167 gBlackListedKeys
= CFSetCreate(0, keys
, NUM_BLACKLISTED_KEYS
, &kCFTypeSetCallBacks
);
2168 CFSetApplyFunction(gBlackListedKeys
, (CFSetApplierFunction
)CFRelease
, 0);
2171 /* AUDIT[securityd](done):
2172 array (ok) is a caller provided array, only its cf type has
2174 The options (ok) field ends up in policy->_options unchecked, so every access
2175 of policy->_options needs to be validated.
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
);
2189 /* AUDIT[securityd](done):
2190 value (ok) is an element in a caller provided array.
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
);
2203 /* AUDIT[securityd](done):
2204 serializedPolicies (ok) is a caller provided array, only its cf type has
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
);
2219 #pragma mark SecPVCRef
2220 /********************************************************
2221 ****************** SecPVCRef Functions *****************
2222 ********************************************************/
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
;
2233 pvc
->verifyTime
= verifyTime
;
2235 pvc
->details
= NULL
;
2237 pvc
->valid_policy_tree
= NULL
;
2238 pvc
->callbacks
= NULL
;
2241 pvc
->asyncJobCount
= 0;
2242 pvc
->check_revocation
= false;
2243 pvc
->optionally_ev
= false;
2248 static void SecPVCDeleteRVCs(SecPVCRef pvc
) {
2249 secdebug("alloc", "%p", pvc
);
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
);
2264 SecPVCDeleteRVCs(pvc
);
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
);
2275 pvc
->details
= details
;
2276 CFReleaseNull(pvc
->info
);
2277 if (pvc
->valid_policy_tree
) {
2278 policy_tree_prune(&pvc
->valid_policy_tree
);
2284 SecPolicyRef
SecPVCGetPolicy(SecPVCRef pvc
) {
2285 return (SecPolicyRef
)CFArrayGetValueAtIndex(pvc
->policies
, pvc
->policyIX
);
2288 CFIndex
SecPVCGetCertificateCount(SecPVCRef pvc
) {
2289 return SecCertificatePathGetCount(pvc
->path
);
2292 SecCertificateRef
SecPVCGetCertificateAtIndex(SecPVCRef pvc
, CFIndex ix
) {
2293 return SecCertificatePathGetCertificateAtIndex(pvc
->path
, ix
);
2296 bool SecPVCIsCertificateAtIndexSelfSigned(SecPVCRef pvc
, CFIndex ix
) {
2297 return SecCertificatePathSelfSignedIndex(pvc
->path
) == ix
;
2300 void SecPVCSetCheckRevocation(SecPVCRef pvc
) {
2301 pvc
->check_revocation
= true;
2302 secdebug("ocsp", "deferred revocation checking enabled");
2305 bool SecPVCIsAnchored(SecPVCRef pvc
) {
2306 return SecCertificatePathIsAnchored(pvc
->path
);
2309 CFAbsoluteTime
SecPVCGetVerifyTime(SecPVCRef pvc
) {
2310 return pvc
->verifyTime
;
2313 /* AUDIT[securityd](done):
2314 policy->_options is a caller provided dictionary, only its cf type has
2317 bool SecPVCSetResultForced(SecPVCRef pvc
,
2318 CFStringRef key
, CFIndex ix
, CFTypeRef result
, bool force
) {
2320 secdebug("policy", "cert[%d]: %@ =(%s)[%s]> %@", ix
, key
,
2321 (pvc
->callbacks
== gSecPolicyLeafCallbacks
? "leaf"
2322 : (pvc
->callbacks
== gSecPolicyPathCallbacks
? "path"
2324 (force
? "force" : ""), result
);
2326 /* If this is not something the current policy cares about ignore
2327 this error and return true so our caller continues evaluation. */
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
2332 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
2333 if (policy
&& !CFDictionaryContainsKey(policy
->_options
, key
))
2337 /* @@@ Check to see if the SecTrustSettings for the certificate in question
2338 tell us to ignore this error. */
2339 pvc
->result
= false;
2343 CFMutableDictionaryRef detail
=
2344 (CFMutableDictionaryRef
)CFArrayGetValueAtIndex(pvc
->details
, ix
);
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
);
2353 bool SecPVCSetResult(SecPVCRef pvc
,
2354 CFStringRef key
, CFIndex ix
, CFTypeRef result
) {
2355 return SecPVCSetResultForced(pvc
, key
, ix
, result
, false);
2358 /* AUDIT[securityd](done):
2359 key(ok) is a caller provided.
2360 value(ok, unused) is a caller provided.
2362 static void SecPVCValidateKey(const void *key
, const void *value
,
2364 SecPVCRef pvc
= (SecPVCRef
)context
;
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
)
2371 SecPolicyCheckFunction fcn
= (SecPolicyCheckFunction
)
2372 CFDictionaryGetValue(pvc
->callbacks
, key
);
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;
2383 if (pvc
->callbacks
== gSecPolicyLeafCallbacks
) {
2384 if (!CFDictionaryContainsKey(gSecPolicyPathCallbacks
, key
)) {
2385 pvc
->result
= false;
2387 } else if (pvc
->callbacks
== gSecPolicyPathCallbacks
) {
2388 if (!CFDictionaryContainsKey(gSecPolicyLeafCallbacks
, key
)) {
2389 pvc
->result
= false;
2392 /* Non standard valdation phase, nothing is optional. */
2393 pvc
->result
= false;
2398 fcn(pvc
, (CFStringRef
)key
);
2401 /* AUDIT[securityd](done):
2402 policy->_options is a caller provided dictionary, only its cf type has
2405 bool SecPVCLeafChecks(SecPVCRef pvc
) {
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
);
2412 /* Validate all keys for all policies. */
2413 pvc
->callbacks
= gSecPolicyLeafCallbacks
;
2414 CFDictionaryApplyFunction(policy
->_options
, SecPVCValidateKey
, pvc
);
2415 if (!pvc
->result
&& !pvc
->details
)
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
))
2436 /* Perform anchor specific checks. */
2437 /* Don't think we have any of these. */
2439 /* Perform intermediate specific checks. */
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))
2450 /* Consider adding (l) max_path_length checking here. */
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))
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
));
2471 /* Check for blacklisted intermediates keys. */
2472 CFDataRef dgst
= SecCertificateCopyPublicKeySHA1Digest(cert
);
2474 /* Check dgst against blacklist. */
2475 if (CFSetContainsValue(gBlackListedKeys
, dgst
)) {
2476 SecPVCSetResultForced(pvc
, kSecPolicyCheckBlackListedKey
,
2477 ix
, kCFBooleanFalse
, true);
2486 /* AUDIT[securityd](done):
2487 policy->_options is a caller provided dictionary, only its cf type has
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(). */
2496 SecPolicyCheckIdLinkage(pvc
, kSecPolicyCheckIdLinkage
);
2497 if (pvc
->result
|| pvc
->details
) {
2498 SecPolicyCheckBasicCertificateProcessing(pvc
,
2499 kSecPolicyCheckBasicCertificateProcessing
);
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
)
2513 /* Check the things we can't check statically for the certificate path. */
2514 /* Critical Extensions, chainLength. */
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
;
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
2529 if (pvc
->result
&& (pvc
->is_ev
|| pvc
->check_revocation
)) {
2530 completed
= SecPVCCheckRevocation(pvc
);
2534 secdebug("policy", "end %strusted completed: %d path: %@",
2535 (pvc
->result
? "" : "not "), completed
, pvc
->path
);
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
) {
2550 for (certIX
= 0; certIX
< certCount
; ++certIX
) {
2551 SecRVCRef rvc
= &((SecRVCRef
)pvc
->rvcs
)[certIX
];
2552 if (rvc
->nextUpdate
== 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
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
2569 secdebug("ocsp", "revocation checking soft failure for cert: %ld",
2571 enu
= rvc
->nextUpdate
;
2574 if (enu
== 0 || rvc
->nextUpdate
< enu
) {
2575 enu
= rvc
->nextUpdate
;
2578 /* Perhaps we don't want to do this since some policies might
2579 ignore the certificate experation but still use revocation
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
)
2590 secdebug("ocsp", "revocation valid until: %lg", enu
);