2 * Copyright (c) 2008-2012 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>
31 #include <utilities/SecIOFormat.h>
32 #include <securityd/asynchttp.h>
33 #include <securityd/policytree.h>
34 #include <CoreFoundation/CFTimeZone.h>
36 #include <libDER/oids.h>
37 #include <CoreFoundation/CFNumber.h>
38 #include <Security/SecCertificateInternal.h>
39 #include <AssertMacros.h>
40 #include <utilities/debugging.h>
41 #include <security_asn1/SecAsn1Coder.h>
42 #include <security_asn1/ocspTemplates.h>
43 #include <security_asn1/oidsalg.h>
44 #include <security_asn1/oidsocsp.h>
45 #include <CommonCrypto/CommonDigest.h>
46 #include <Security/SecFramework.h>
47 #include <Security/SecPolicyInternal.h>
48 #include <Security/SecTrustPriv.h>
49 #include <Security/SecInternal.h>
50 #include <CFNetwork/CFHTTPMessage.h>
51 #include <CFNetwork/CFHTTPStream.h>
52 #include <SystemConfiguration/SCDynamicStoreCopySpecific.h>
54 #include <securityd/SecOCSPRequest.h>
55 #include <securityd/SecOCSPResponse.h>
56 #include <securityd/asynchttp.h>
57 #include <securityd/SecTrustServer.h>
58 #include <securityd/SecOCSPCache.h>
59 #include <utilities/array_size.h>
60 #include <utilities/SecCFWrappers.h>
61 #include "OTATrustUtilities.h"
63 #define ocspdErrorLog(args...) asl_log(NULL, NULL, ASL_LEVEL_ERR, ## args)
65 /* Set this to 1 to dump the ocsp responses received in DER form in /tmp. */
66 #ifndef DUMP_OCSPRESPONSES
67 #define DUMP_OCSPRESPONSES 0
70 #if DUMP_OCSPRESPONSES
75 static void secdumpdata(CFDataRef data
, const char *name
) {
76 int fd
= open(name
, O_CREAT
| O_WRONLY
| O_TRUNC
, 0666);
77 write(fd
, CFDataGetBytePtr(data
), CFDataGetLength(data
));
84 /********************************************************
85 ****************** SecPolicy object ********************
86 ********************************************************/
88 static CFMutableDictionaryRef gSecPolicyLeafCallbacks
= NULL
;
89 static CFMutableDictionaryRef gSecPolicyPathCallbacks
= NULL
;
91 static CFArrayRef
SecPolicyAnchorDigestsForEVPolicy(const DERItem
*policyOID
)
93 CFArrayRef result
= NULL
;
94 SecOTAPKIRef otapkiRef
= SecOTAPKICopyCurrentOTAPKIRef();
95 if (NULL
== otapkiRef
)
100 CFDictionaryRef evToPolicyAnchorDigest
= SecOTAPKICopyEVPolicyToAnchorMapping(otapkiRef
);
101 CFRelease(otapkiRef
);
103 if (NULL
== evToPolicyAnchorDigest
)
108 CFArrayRef roots
= NULL
;
109 CFStringRef oid
= SecDERItemCopyOIDDecimalRepresentation(kCFAllocatorDefault
, policyOID
);
110 if (oid
&& evToPolicyAnchorDigest
)
112 result
= (CFArrayRef
)CFDictionaryGetValue(evToPolicyAnchorDigest
, oid
);
113 if (roots
&& CFGetTypeID(result
) != CFArrayGetTypeID())
115 ocspdErrorLog("EVRoot.plist has non array value");
124 static bool SecPolicyIsEVPolicy(const DERItem
*policyOID
) {
125 return SecPolicyAnchorDigestsForEVPolicy(policyOID
);
128 static bool SecPolicyRootCACertificateIsEV(SecCertificateRef certificate
,
129 policy_set_t valid_policies
) {
130 /* Ensure that this certificate is a valid anchor for one of the
131 certificate policy oids specified in the leaf. */
132 CFDataRef digest
= SecCertificateGetSHA1Digest(certificate
);
134 bool good_ev_anchor
= false;
135 for (ix
= valid_policies
; ix
; ix
= ix
->oid_next
) {
136 CFArrayRef digests
= SecPolicyAnchorDigestsForEVPolicy(&ix
->oid
);
137 if (digests
&& CFArrayContainsValue(digests
,
138 CFRangeMake(0, CFArrayGetCount(digests
)), digest
)) {
139 secdebug("ev", "found anchor for policy oid");
140 good_ev_anchor
= true;
144 require_quiet(good_ev_anchor
, notEV
);
146 CFAbsoluteTime october2006
= 178761600;
147 if (SecCertificateVersion(certificate
) >= 3
148 && SecCertificateNotValidBefore(certificate
) >= october2006
) {
149 const SecCEBasicConstraints
*bc
= SecCertificateGetBasicConstraints(certificate
);
150 require_quiet(bc
&& bc
->isCA
== true, notEV
);
151 SecKeyUsage ku
= SecCertificateGetKeyUsage(certificate
);
152 require_quiet((ku
& (kSecKeyUsageKeyCertSign
| kSecKeyUsageCRLSign
))
153 == (kSecKeyUsageKeyCertSign
| kSecKeyUsageCRLSign
), notEV
);
156 CFAbsoluteTime jan2011
= 315532800;
157 if (SecCertificateNotValidBefore(certificate
) < jan2011
) {
158 /* At least MD5, SHA-1 with RSA 2048 or ECC NIST P-256. */
160 /* At least SHA-1, SHA-256, SHA-384 or SHA-512 with RSA 2048 or
169 static bool SecPolicySubordinateCACertificateCouldBeEV(SecCertificateRef certificate
) {
170 const SecCECertificatePolicies
*cp
;
171 cp
= SecCertificateGetCertificatePolicies(certificate
);
172 require_quiet(cp
&& cp
->numPolicies
> 0, notEV
);
173 /* SecCertificateGetCRLDistributionPoints() is a noop right now */
175 CFArrayRef cdp
= SecCertificateGetCRLDistributionPoints(certificate
);
176 require_quiet(cdp
&& CFArrayGetCount(cdp
) > 0, notEV
);
178 const SecCEBasicConstraints
*bc
= SecCertificateGetBasicConstraints(certificate
);
179 require_quiet(bc
&& bc
->isCA
== true, notEV
);
180 SecKeyUsage ku
= SecCertificateGetKeyUsage(certificate
);
181 require_quiet((ku
& (kSecKeyUsageKeyCertSign
| kSecKeyUsageCRLSign
))
182 == (kSecKeyUsageKeyCertSign
| kSecKeyUsageCRLSign
), notEV
);
183 CFAbsoluteTime jan2011
= 315532800;
184 if (SecCertificateNotValidBefore(certificate
) < jan2011
) {
185 /* At least SHA-1 with RSA 1024 or ECC NIST P-256. */
187 /* At least SHA-1, SHA-256, SHA-284 or SHA-512 with RSA 2028 or
196 bool SecPolicySubscriberCertificateCouldBeEV(SecCertificateRef certificate
) {
197 /* 3. Subscriber Certificate. */
199 /* (a) certificate Policies */
200 const SecCECertificatePolicies
*cp
;
201 cp
= SecCertificateGetCertificatePolicies(certificate
);
202 require_quiet(cp
&& cp
->numPolicies
> 0, notEV
);
203 /* Now find at least one policy in here that has a qualifierID of id-qt 2
204 and a policyQualifier that is a URI to the CPS and an EV policy OID. */
206 bool found_ev_anchor_for_leaf_policy
= false;
207 for (ix
= 0; ix
< cp
->numPolicies
; ++ix
) {
208 if (SecPolicyIsEVPolicy(&cp
->policies
[ix
].policyIdentifier
)) {
209 found_ev_anchor_for_leaf_policy
= true;
212 require_quiet(found_ev_anchor_for_leaf_policy
, notEV
);
214 /* SecCertificateGetCRLDistributionPoints() is a noop right now */
216 /* (b) cRLDistributionPoint
217 (c) authorityInformationAccess */
218 CFArrayRef cdp
= SecCertificateGetCRLDistributionPoints(certificate
);
220 require_quiet(CFArrayGetCount(cdp
) > 0, notEV
);
222 CFArrayRef
or = SecCertificateGetOCSPResponders(certificate
);
223 require_quiet(or && CFArrayGetCount(or) > 0, notEV
);
224 //CFArrayRef ci = SecCertificateGetCAIssuers(certificate);
228 /* (d) basicConstraints
229 If present, the cA field MUST be set false. */
230 const SecCEBasicConstraints
*bc
= SecCertificateGetBasicConstraints(certificate
);
232 require_quiet(bc
->isCA
== false, notEV
);
236 SecKeyUsage ku
= SecCertificateGetKeyUsage(certificate
);
238 require_quiet((ku
& (kSecKeyUsageKeyCertSign
| kSecKeyUsageCRLSign
)) == 0, notEV
);
242 /* The EV Cert Spec errata specifies this, though this is a check for SSL
243 not specifically EV. */
247 Either the value id-kp-serverAuth [RFC5280] or id-kp-clientAuth [RFC5280] or both values MUST be present. Other values SHOULD NOT be present. */
248 SecCertificateCopyExtendedKeyUsage(certificate
);
251 CFAbsoluteTime jan2011
= 315532800;
252 if (SecCertificateNotValidAfter(certificate
) < jan2011
) {
253 /* At least SHA-1 with RSA 1024 or ECC NIST P-256. */
255 /* At least SHA-1, SHA-256, SHA-284 or SHA-512 with RSA 2028 or
264 /********************************************************
265 **************** SecPolicy Callbacks *******************
266 ********************************************************/
267 static void SecPolicyCheckCriticalExtensions(SecPVCRef pvc
,
271 static void SecPolicyCheckIdLinkage(SecPVCRef pvc
,
273 CFIndex ix
, count
= SecPVCGetCertificateCount(pvc
);
274 CFDataRef parentSubjectKeyID
= NULL
;
275 for (ix
= count
- 1; ix
>= 0; --ix
) {
276 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, ix
);
277 /* If the previous certificate in the chain had a SubjectKeyID,
278 make sure it matches the current certificates AuthorityKeyID. */
279 if (parentSubjectKeyID
) {
280 /* @@@ According to RFC 2459 neither AuthorityKeyID nor
281 SubjectKeyID can be critical. Currenty we don't check
283 CFDataRef authorityKeyID
= SecCertificateGetAuthorityKeyID(cert
);
284 if (authorityKeyID
) {
285 if (!CFEqual(parentSubjectKeyID
, authorityKeyID
)) {
286 /* AuthorityKeyID doesn't match issuers SubjectKeyID. */
287 if (!SecPVCSetResult(pvc
, key
, ix
, kCFBooleanFalse
))
293 parentSubjectKeyID
= SecCertificateGetSubjectKeyID(cert
);
297 static bool keyusage_allows(SecKeyUsage keyUsage
, CFTypeRef xku
) {
298 if (!xku
|| CFGetTypeID(xku
) != CFNumberGetTypeID())
302 CFNumberGetValue((CFNumberRef
)xku
, kCFNumberSInt32Type
, &dku
);
303 SecKeyUsage ku
= (SecKeyUsage
)dku
;
304 return (keyUsage
& ku
) == ku
;
307 static void SecPolicyCheckKeyUsage(SecPVCRef pvc
,
309 SecCertificateRef leaf
= SecPVCGetCertificateAtIndex(pvc
, 0);
310 SecKeyUsage keyUsage
= SecCertificateGetKeyUsage(leaf
);
312 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
313 CFTypeRef xku
= CFDictionaryGetValue(policy
->_options
, key
);
315 CFIndex ix
, count
= CFArrayGetCount(xku
);
316 for (ix
= 0; ix
< count
; ++ix
) {
317 CFTypeRef ku
= CFArrayGetValueAtIndex(xku
, ix
);
318 if (keyusage_allows(keyUsage
, ku
)) {
324 match
= keyusage_allows(keyUsage
, xku
);
327 SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
);
331 static bool extendedkeyusage_allows(CFArrayRef extendedKeyUsage
,
333 if (!xeku
|| CFGetTypeID(xeku
) != CFDataGetTypeID())
335 if (extendedKeyUsage
) {
336 CFRange all
= { 0, CFArrayGetCount(extendedKeyUsage
) };
337 return CFArrayContainsValue(extendedKeyUsage
, all
, xeku
);
339 /* Certificate has no extended key usage, only a match if the policy
340 contains a 0 length CFDataRef. */
341 return CFDataGetLength((CFDataRef
)xeku
) == 0;
345 /* AUDIT[securityd](done):
346 policy->_options is a caller provided dictionary, only its cf type has
349 static void SecPolicyCheckExtendedKeyUsage(SecPVCRef pvc
, CFStringRef key
) {
350 SecCertificateRef leaf
= SecPVCGetCertificateAtIndex(pvc
, 0);
351 CFArrayRef leafExtendedKeyUsage
= SecCertificateCopyExtendedKeyUsage(leaf
);
353 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
354 CFTypeRef xeku
= CFDictionaryGetValue(policy
->_options
, key
);
356 CFIndex ix
, count
= CFArrayGetCount(xeku
);
357 for (ix
= 0; ix
< count
; ix
++) {
358 CFTypeRef eku
= CFArrayGetValueAtIndex(xeku
, ix
);
359 if (extendedkeyusage_allows(leafExtendedKeyUsage
, eku
)) {
365 match
= extendedkeyusage_allows(leafExtendedKeyUsage
, xeku
);
367 CFReleaseSafe(leafExtendedKeyUsage
);
369 SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
);
374 static void SecPolicyCheckBasicContraintsCommon(SecPVCRef pvc
,
375 CFStringRef key
, bool strict
) {
376 CFIndex ix
, count
= SecPVCGetCertificateCount(pvc
);
377 for (ix
= 0; ix
< count
; ++ix
) {
378 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, ix
);
379 const SecCEBasicConstraints
*bc
=
380 SecCertificateGetBasicConstraints(cert
);
384 /* Leaf certificate has basic constraints extension. */
385 if (!SecPVCSetResult(pvc
, key
, ix
, kCFBooleanFalse
))
387 } else if (!bc
->critical
) {
388 /* Basic constraints extension is not marked critical. */
389 if (!SecPVCSetResult(pvc
, key
, ix
, kCFBooleanFalse
))
394 if (ix
> 0 || count
== 1) {
396 /* Non leaf certificate marked as isCA false. */
397 if (!SecPVCSetResult(pvc
, key
, ix
, kCFBooleanFalse
))
401 if (bc
->pathLenConstraintPresent
) {
402 if (bc
->pathLenConstraint
< (uint32_t)(ix
- 1)) {
404 /* @@@ If a self signed certificate is issued by
405 another cert that is trusted, then we are supposed
406 to treat the self signed cert itself as the anchor
407 for path length purposes. */
408 CFIndex ssix
= SecCertificatePathSelfSignedIndex(path
);
409 if (ssix
>= 0 && ix
>= ssix
) {
410 /* It's ok if the pathLenConstraint isn't met for
411 certificates signing a self signed cert in the
416 /* Path Length Constraint Exceeded. */
417 if (!SecPVCSetResult(pvc
, key
, ix
,
424 } else if (strict
&& ix
> 0) {
425 /* In strict mode all CA certificates *MUST* have a critical
426 basic constraints extension and the leaf certificate
427 *MUST NOT* have a basic constraints extension. */
428 /* CA certificate is missing basicConstraints extension. */
429 if (!SecPVCSetResult(pvc
, key
, ix
, kCFBooleanFalse
))
436 static void SecPolicyCheckBasicContraints(SecPVCRef pvc
,
438 //SecPolicyCheckBasicContraintsCommon(pvc, key, false);
441 static void SecPolicyCheckNonEmptySubject(SecPVCRef pvc
,
443 CFIndex ix
, count
= SecPVCGetCertificateCount(pvc
);
444 for (ix
= 0; ix
< count
; ++ix
) {
445 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, ix
);
446 /* If the certificate has a subject, or
447 if it doesn't, and it's the leaf and not self signed,
448 and also has a critical subjectAltName extension it's valid. */
449 if (!SecCertificateHasSubject(cert
)) {
450 if (ix
== 0 && count
> 1) {
451 if (!SecCertificateHasCriticalSubjectAltName(cert
)) {
452 /* Leaf certificate with empty subject does not have
453 a critical subject alt name extension. */
454 if (!SecPVCSetResult(pvc
, key
, ix
, kCFBooleanFalse
))
458 /* CA certificate has empty subject. */
459 if (!SecPVCSetResult(pvc
, key
, ix
, kCFBooleanFalse
))
466 static void SecPolicyCheckQualifiedCertStatements(SecPVCRef pvc
,
470 /* Compare hostname, to a server name obtained from the server's cert
471 Obtained from the SubjectAltName or the CommonName entry in the Subject.
472 Limited wildcard checking is performed here as outlined in
474 RFC 2818 Section 3.1. Server Identity
476 [...] Names may contain the wildcard
477 character * which is considered to match any single domain name
478 component or component fragment. E.g., *.a.com matches foo.a.com but
479 not bar.foo.a.com. f*.com matches foo.com but not bar.com.
482 Trailing '.' characters in the hostname will be ignored.
484 Returns true on match, else false.
486 static bool SecDNSMatch(CFStringRef hostname
, CFStringRef servername
) {
487 CFStringInlineBuffer hbuf
, sbuf
;
489 hlength
= CFStringGetLength(hostname
),
490 slength
= CFStringGetLength(servername
);
491 CFRange hrange
= { 0, hlength
}, srange
= { 0, slength
};
492 CFStringInitInlineBuffer(hostname
, &hbuf
, hrange
);
493 CFStringInitInlineBuffer(servername
, &sbuf
, srange
);
495 for (hix
= six
= 0; six
< slength
; ++six
) {
496 UniChar hch
, sch
= CFStringGetCharacterFromInlineBuffer(&sbuf
, six
);
498 if (six
+ 1 >= slength
) {
499 /* Trailing '*' in servername, match until end of hostname or
502 if (hix
>= hlength
) {
503 /* If we reach the end of the hostname we have a
507 hch
= CFStringGetCharacterFromInlineBuffer(&hbuf
, hix
++);
508 } while (hch
!= '.');
509 /* We reached the end of servername and found a '.' in
510 hostname. Return true if hostname has a single
511 trailing '.' return false if there is anything after it. */
512 return hix
== hlength
;
515 /* Grab the character after the '*'. */
516 sch
= CFStringGetCharacterFromInlineBuffer(&sbuf
, ++six
);
518 /* We have something of the form '*foo.com'. Or '**.com'
519 We don't deal with that yet, since it might require
520 backtracking. Also RFC 2818 doesn't seem to require it. */
524 /* We're looking at the '.' after the '*' in something of the
525 form 'foo*.com' or '*.com'. Match until next '.' in hostname. */
527 /* Since we're not at the end of servername yet (that case
528 was handeled above), running out of chars in hostname
529 means we don't have a match. */
532 hch
= CFStringGetCharacterFromInlineBuffer(&hbuf
, hix
++);
533 } while (hch
!= '.');
535 /* We're looking at a non wildcard character in the servername.
536 If we reached the end of hostname it's not a match. */
540 /* Otherwise make sure the hostname matches the character in the
541 servername, case insensitively. */
542 hch
= CFStringGetCharacterFromInlineBuffer(&hbuf
, hix
++);
543 if (towlower(hch
) != towlower(sch
))
549 /* We reached the end of servername but we have one or more characters
550 left to compare against in the hostname. */
551 if (hix
+ 1 == hlength
&&
552 CFStringGetCharacterFromInlineBuffer(&hbuf
, hix
) == '.') {
553 /* Hostname has a single trailing '.', we're ok with that. */
556 /* Anything else is not a match. */
563 /* AUDIT[securityd](done):
564 policy->_options is a caller provided dictionary, only its cf type has
567 static void SecPolicyCheckSSLHostname(SecPVCRef pvc
,
569 /* @@@ Consider what to do if the caller passes in no hostname. Should
570 we then still fail if the leaf has no dnsNames or IPAddresses at all? */
571 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
572 CFStringRef hostName
= (CFStringRef
)
573 CFDictionaryGetValue(policy
->_options
, key
);
574 if (!isString(hostName
)) {
575 /* @@@ We can't return an error here and making the evaluation fail
576 won't help much either. */
580 SecCertificateRef leaf
= SecPVCGetCertificateAtIndex(pvc
, 0);
581 bool dnsMatch
= false;
582 CFArrayRef dnsNames
= SecCertificateCopyDNSNames(leaf
);
584 CFIndex ix
, count
= CFArrayGetCount(dnsNames
);
585 for (ix
= 0; ix
< count
; ++ix
) {
586 CFStringRef dns
= (CFStringRef
)CFArrayGetValueAtIndex(dnsNames
, ix
);
587 if (SecDNSMatch(hostName
, dns
)) {
596 /* Maybe hostname is an IPv4 or IPv6 address, let's compare against
597 the values returned by SecCertificateCopyIPAddresses() instead. */
598 CFArrayRef ipAddresses
= SecCertificateCopyIPAddresses(leaf
);
600 CFIndex ix
, count
= CFArrayGetCount(ipAddresses
);
601 for (ix
= 0; ix
< count
; ++ix
) {
602 CFStringRef ipAddress
= (CFStringRef
)CFArrayGetValueAtIndex(ipAddresses
, ix
);
603 if (!CFStringCompare(hostName
, ipAddress
, kCFCompareCaseInsensitive
)) {
608 CFRelease(ipAddresses
);
613 /* Hostname mismatch or no hostnames found in certificate. */
614 SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
);
616 if ((dnsMatch
|| pvc
->details
)
617 && SecPolicySubscriberCertificateCouldBeEV(leaf
)) {
618 secdebug("policy", "enabling optionally_ev");
619 pvc
->optionally_ev
= true;
620 /* optionally_ev => check_revocation, so we don't enable revocation
621 checking here, since we don't want it on for non EV ssl certs. */
623 /* Check revocation status if the certificate asks for it (and we
624 support it) currently we only support ocsp. */
625 CFArrayRef ocspResponders
= SecCertificateGetOCSPResponders(leaf
);
626 if (ocspResponders
) {
627 SecPVCSetCheckRevocation(pvc
);
633 /* AUDIT[securityd](done):
634 policy->_options is a caller provided dictionary, only its cf type has
637 static void SecPolicyCheckEmail(SecPVCRef pvc
, CFStringRef key
) {
638 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
639 CFStringRef email
= (CFStringRef
)CFDictionaryGetValue(policy
->_options
, key
);
641 if (!isString(email
)) {
642 /* We can't return an error here and making the evaluation fail
643 won't help much either. */
647 SecCertificateRef leaf
= SecPVCGetCertificateAtIndex(pvc
, 0);
648 CFArrayRef addrs
= SecCertificateCopyRFC822Names(leaf
);
650 CFIndex ix
, count
= CFArrayGetCount(addrs
);
651 for (ix
= 0; ix
< count
; ++ix
) {
652 CFStringRef addr
= (CFStringRef
)CFArrayGetValueAtIndex(addrs
, ix
);
653 if (!CFStringCompare(email
, addr
, kCFCompareCaseInsensitive
)) {
662 /* Hostname mismatch or no hostnames found in certificate. */
663 SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
);
667 static void SecPolicyCheckValidIntermediates(SecPVCRef pvc
,
669 CFIndex ix
, count
= SecPVCGetCertificateCount(pvc
);
670 CFAbsoluteTime verifyTime
= SecPVCGetVerifyTime(pvc
);
671 for (ix
= 1; ix
< count
- 1; ++ix
) {
672 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, ix
);
673 if (!SecCertificateIsValid(cert
, verifyTime
)) {
674 /* Intermediate certificate has expired. */
675 if (!SecPVCSetResult(pvc
, key
, ix
, kCFBooleanFalse
))
681 static void SecPolicyCheckValidLeaf(SecPVCRef pvc
,
683 CFAbsoluteTime verifyTime
= SecPVCGetVerifyTime(pvc
);
684 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, 0);
685 if (!SecCertificateIsValid(cert
, verifyTime
)) {
686 /* Leaf certificate has expired. */
687 if (!SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
))
692 static void SecPolicyCheckValidRoot(SecPVCRef pvc
,
694 CFIndex ix
, count
= SecPVCGetCertificateCount(pvc
);
695 CFAbsoluteTime verifyTime
= SecPVCGetVerifyTime(pvc
);
697 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, ix
);
698 if (!SecCertificateIsValid(cert
, verifyTime
)) {
699 /* Root certificate has expired. */
700 if (!SecPVCSetResult(pvc
, key
, ix
, kCFBooleanFalse
))
705 /* AUDIT[securityd](done):
706 policy->_options is a caller provided dictionary, only its cf type has
709 static void SecPolicyCheckIssuerCommonName(SecPVCRef pvc
,
711 CFIndex count
= SecPVCGetCertificateCount(pvc
);
713 /* Can't check intermediates common name if there is no intermediate. */
714 SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
);
718 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, 1);
719 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
720 CFStringRef commonName
=
721 (CFStringRef
)CFDictionaryGetValue(policy
->_options
, key
);
722 if (!isString(commonName
)) {
723 /* @@@ We can't return an error here and making the evaluation fail
724 won't help much either. */
727 CFArrayRef commonNames
= SecCertificateCopyCommonNames(cert
);
728 if (!commonNames
|| CFArrayGetCount(commonNames
) != 1 ||
729 !CFEqual(commonName
, CFArrayGetValueAtIndex(commonNames
, 0))) {
730 /* Common Name mismatch. */
731 SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
);
733 CFReleaseSafe(commonNames
);
736 /* AUDIT[securityd](done):
737 policy->_options is a caller provided dictionary, only its cf type has
740 static void SecPolicyCheckSubjectCommonName(SecPVCRef pvc
,
742 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, 0);
743 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
744 CFStringRef common_name
= (CFStringRef
)CFDictionaryGetValue(policy
->_options
,
746 if (!isString(common_name
)) {
747 /* @@@ We can't return an error here and making the evaluation fail
748 won't help much either. */
751 CFArrayRef commonNames
= SecCertificateCopyCommonNames(cert
);
752 if (!commonNames
|| CFArrayGetCount(commonNames
) != 1 ||
753 !CFEqual(common_name
, CFArrayGetValueAtIndex(commonNames
, 0))) {
754 /* Common Name mismatch. */
755 SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
);
757 CFReleaseSafe(commonNames
);
760 /* AUDIT[securityd](done):
761 policy->_options is a caller provided dictionary, only its cf type has
764 static void SecPolicyCheckSubjectCommonNamePrefix(SecPVCRef pvc
,
766 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, 0);
767 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
768 CFStringRef prefix
= (CFStringRef
)CFDictionaryGetValue(policy
->_options
,
770 if (!isString(prefix
)) {
771 /* @@@ We can't return an error here and making the evaluation fail
772 won't help much either. */
775 CFArrayRef commonNames
= SecCertificateCopyCommonNames(cert
);
776 if (!commonNames
|| CFArrayGetCount(commonNames
) != 1 ||
777 !CFStringHasPrefix(CFArrayGetValueAtIndex(commonNames
, 0), prefix
)) {
778 /* Common Name prefix mismatch. */
779 SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
);
781 CFReleaseSafe(commonNames
);
784 /* AUDIT[securityd](done):
785 policy->_options is a caller provided dictionary, only its cf type has
788 static void SecPolicyCheckSubjectCommonNameTEST(SecPVCRef pvc
,
790 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, 0);
791 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
792 CFStringRef common_name
= (CFStringRef
)CFDictionaryGetValue(policy
->_options
,
794 if (!isString(common_name
)) {
795 /* @@@ We can't return an error here and making the evaluation fail
796 won't help much either. */
799 CFArrayRef commonNames
= SecCertificateCopyCommonNames(cert
);
800 if (!commonNames
|| CFArrayGetCount(commonNames
) != 1) {
801 CFStringRef cert_common_name
= CFArrayGetValueAtIndex(commonNames
, 0);
802 CFStringRef test_common_name
= common_name
?
803 CFStringCreateWithFormat(kCFAllocatorDefault
,
804 NULL
, CFSTR("TEST %@ TEST"), common_name
) :
806 if (!CFEqual(common_name
, cert_common_name
) &&
807 (!test_common_name
|| !CFEqual(test_common_name
, cert_common_name
)))
808 /* Common Name mismatch. */
809 SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
);
810 CFReleaseSafe(test_common_name
);
812 CFReleaseSafe(commonNames
);
815 /* AUDIT[securityd](done):
816 policy->_options is a caller provided dictionary, only its cf type has
819 static void SecPolicyCheckNotValidBefore(SecPVCRef pvc
,
821 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, 0);
822 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
823 CFDateRef date
= (CFDateRef
)CFDictionaryGetValue(policy
->_options
, key
);
825 /* @@@ We can't return an error here and making the evaluation fail
826 won't help much either. */
829 CFAbsoluteTime at
= CFDateGetAbsoluteTime(date
);
830 if (SecCertificateNotValidBefore(cert
) <= at
) {
831 /* Leaf certificate has not valid before that is too old. */
832 if (!SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
))
837 /* AUDIT[securityd](done):
838 policy->_options is a caller provided dictionary, only its cf type has
841 static void SecPolicyCheckChainLength(SecPVCRef pvc
,
843 CFIndex count
= SecPVCGetCertificateCount(pvc
);
844 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
845 CFNumberRef chainLength
=
846 (CFNumberRef
)CFDictionaryGetValue(policy
->_options
, key
);
848 if (!chainLength
|| CFGetTypeID(chainLength
) != CFNumberGetTypeID() ||
849 !CFNumberGetValue(chainLength
, kCFNumberCFIndexType
, &value
)) {
850 /* @@@ We can't return an error here and making the evaluation fail
851 won't help much either. */
854 if (value
!= count
) {
855 /* Chain length doesn't match policy requirement. */
856 if (!SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
))
861 /* AUDIT[securityd](done):
862 policy->_options is a caller provided dictionary, only its cf type has
865 static void SecPolicyCheckAnchorSHA1(SecPVCRef pvc
,
867 CFIndex count
= SecPVCGetCertificateCount(pvc
);
868 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, count
- 1);
869 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
870 CFTypeRef value
= CFDictionaryGetValue(policy
->_options
, key
);
871 CFDataRef anchorSHA1
= SecCertificateGetSHA1Digest(cert
);
873 bool foundMatch
= false;
876 foundMatch
= CFEqual(anchorSHA1
, value
);
877 else if (isArray(value
))
878 foundMatch
= CFArrayContainsValue((CFArrayRef
) value
, CFRangeMake(0, CFArrayGetCount((CFArrayRef
) value
)), anchorSHA1
);
880 /* @@@ We only support Data and Array but we can't return an error here so.
881 we let the evaluation fail (not much help) and assert in debug. */
886 if (!SecPVCSetResult(pvc
, kSecPolicyCheckAnchorSHA1
, 0, kCFBooleanFalse
))
892 /* AUDIT[securityd](done):
893 policy->_options is a caller provided dictionary, only its cf type has
896 static void SecPolicyCheckSubjectOrganization(SecPVCRef pvc
,
898 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, 0);
899 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
900 CFStringRef org
= (CFStringRef
)CFDictionaryGetValue(policy
->_options
,
902 if (!isString(org
)) {
903 /* @@@ We can't return an error here and making the evaluation fail
904 won't help much either. */
907 CFArrayRef organization
= SecCertificateCopyOrganization(cert
);
908 if (!organization
|| CFArrayGetCount(organization
) != 1 ||
909 !CFEqual(org
, CFArrayGetValueAtIndex(organization
, 0))) {
910 /* Leaf Subject Organization mismatch. */
911 SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
);
913 CFReleaseSafe(organization
);
916 static void SecPolicyCheckSubjectOrganizationalUnit(SecPVCRef pvc
,
918 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, 0);
919 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
920 CFStringRef orgUnit
= (CFStringRef
)CFDictionaryGetValue(policy
->_options
,
922 if (!isString(orgUnit
)) {
923 /* @@@ We can't return an error here and making the evaluation fail
924 won't help much either. */
927 CFArrayRef organizationalUnit
= SecCertificateCopyOrganizationalUnit(cert
);
928 if (!organizationalUnit
|| CFArrayGetCount(organizationalUnit
) != 1 ||
929 !CFEqual(orgUnit
, CFArrayGetValueAtIndex(organizationalUnit
, 0))) {
930 /* Leaf Subject Organizational Unit mismatch. */
931 SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
);
933 CFReleaseSafe(organizationalUnit
);
936 /* AUDIT[securityd](done):
937 policy->_options is a caller provided dictionary, only its cf type has
940 static void SecPolicyCheckEAPTrustedServerNames(SecPVCRef pvc
,
942 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
943 CFArrayRef trustedServerNames
= (CFArrayRef
)
944 CFDictionaryGetValue(policy
->_options
, key
);
945 /* No names specified means we accept any name. */
946 if (!trustedServerNames
)
948 if (!isArray(trustedServerNames
)) {
949 /* @@@ We can't return an error here and making the evaluation fail
950 won't help much either. */
954 CFIndex tsnCount
= CFArrayGetCount(trustedServerNames
);
955 SecCertificateRef leaf
= SecPVCGetCertificateAtIndex(pvc
, 0);
956 bool dnsMatch
= false;
957 CFArrayRef dnsNames
= SecCertificateCopyDNSNames(leaf
);
959 CFIndex ix
, count
= CFArrayGetCount(dnsNames
);
960 // @@@ This is O(N^2) unfortunately we can't do better easily unless
961 // we don't do wildcard matching. */
962 for (ix
= 0; !dnsMatch
&& ix
< count
; ++ix
) {
963 CFStringRef dns
= (CFStringRef
)CFArrayGetValueAtIndex(dnsNames
, ix
);
965 for (tix
= 0; tix
< tsnCount
; ++tix
) {
966 CFStringRef serverName
=
967 (CFStringRef
)CFArrayGetValueAtIndex(trustedServerNames
, tix
);
968 if (!isString(serverName
)) {
969 /* @@@ We can't return an error here and making the
970 evaluation fail won't help much either. */
971 CFReleaseSafe(dnsNames
);
974 /* we purposefully reverse the arguments here such that dns names
975 from the cert are matched against a server name list, where
976 the server names list can contain wildcards and the dns name
977 cannot. References: http://support.microsoft.com/kb/941123
978 It's easy to find occurrences where people tried to use
979 wildcard certificates and were told that those don't work
981 if (SecDNSMatch(dns
, serverName
)) {
991 /* Hostname mismatch or no hostnames found in certificate. */
992 SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
);
996 static const unsigned char UTN_USERFirst_Hardware_Serial
[][16] = {
997 { 0xd8, 0xf3, 0x5f, 0x4e, 0xb7, 0x87, 0x2b, 0x2d, 0xab, 0x06, 0x92, 0xe3, 0x15, 0x38, 0x2f, 0xb0 },
998 { 0x92, 0x39, 0xd5, 0x34, 0x8f, 0x40, 0xd1, 0x69, 0x5a, 0x74, 0x54, 0x70, 0xe1, 0xf2, 0x3f, 0x43 },
999 { 0xb0, 0xb7, 0x13, 0x3e, 0xd0, 0x96, 0xf9, 0xb5, 0x6f, 0xae, 0x91, 0xc8, 0x74, 0xbd, 0x3a, 0xc0 },
1000 { 0xe9, 0x02, 0x8b, 0x95, 0x78, 0xe4, 0x15, 0xdc, 0x1a, 0x71, 0x0a, 0x2b, 0x88, 0x15, 0x44, 0x47 },
1001 { 0x39, 0x2a, 0x43, 0x4f, 0x0e, 0x07, 0xdf, 0x1f, 0x8a, 0xa3, 0x05, 0xde, 0x34, 0xe0, 0xc2, 0x29 },
1002 { 0x3e, 0x75, 0xce, 0xd4, 0x6b, 0x69, 0x30, 0x21, 0x21, 0x88, 0x30, 0xae, 0x86, 0xa8, 0x2a, 0x71 },
1003 { 0xd7, 0x55, 0x8f, 0xda, 0xf5, 0xf1, 0x10, 0x5b, 0xb2, 0x13, 0x28, 0x2b, 0x70, 0x77, 0x29, 0xa3 },
1004 { 0x04, 0x7e, 0xcb, 0xe9, 0xfc, 0xa5, 0x5f, 0x7b, 0xd0, 0x9e, 0xae, 0x36, 0xe1, 0x0c, 0xae, 0x1e },
1005 { 0xf5, 0xc8, 0x6a, 0xf3, 0x61, 0x62, 0xf1, 0x3a, 0x64, 0xf5, 0x4f, 0x6d, 0xc9, 0x58, 0x7c, 0x06 } };
1007 static const unsigned char UTN_USERFirst_Hardware_Normalized_Issuer
[] = {
1008 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55,
1009 0x53, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x02,
1010 0x55, 0x54, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x07, 0x13,
1011 0x0e, 0x53, 0x41, 0x4c, 0x54, 0x20, 0x4c, 0x41, 0x4b, 0x45, 0x20, 0x43,
1012 0x49, 0x54, 0x59, 0x31, 0x1e, 0x30, 0x1c, 0x06, 0x03, 0x55, 0x04, 0x0a,
1013 0x13, 0x15, 0x54, 0x48, 0x45, 0x20, 0x55, 0x53, 0x45, 0x52, 0x54, 0x52,
1014 0x55, 0x53, 0x54, 0x20, 0x4e, 0x45, 0x54, 0x57, 0x4f, 0x52, 0x4b, 0x31,
1015 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x18, 0x48, 0x54,
1016 0x54, 0x50, 0x3a, 0x2f, 0x2f, 0x57, 0x57, 0x57, 0x2e, 0x55, 0x53, 0x45,
1017 0x52, 0x54, 0x52, 0x55, 0x53, 0x54, 0x2e, 0x43, 0x4f, 0x4d, 0x31, 0x1f,
1018 0x30, 0x1d, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x16, 0x55, 0x54, 0x4e,
1019 0x2d, 0x55, 0x53, 0x45, 0x52, 0x46, 0x49, 0x52, 0x53, 0x54, 0x2d, 0x48,
1020 0x41, 0x52, 0x44, 0x57, 0x41, 0x52, 0x45
1022 static const unsigned int UTN_USERFirst_Hardware_Normalized_Issuer_len
= 151;
1025 static void SecPolicyCheckBlackListedLeaf(SecPVCRef pvc
,
1027 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, 0);
1028 CFDataRef issuer
= cert
? SecCertificateGetNormalizedIssuerContent(cert
) : NULL
;
1030 if (issuer
&& (CFDataGetLength(issuer
) == (CFIndex
)UTN_USERFirst_Hardware_Normalized_Issuer_len
) &&
1031 (0 == memcmp(UTN_USERFirst_Hardware_Normalized_Issuer
, CFDataGetBytePtr(issuer
),
1032 UTN_USERFirst_Hardware_Normalized_Issuer_len
)))
1034 CFDataRef serial
= SecCertificateCopySerialNumber(cert
);
1036 CFIndex serial_length
= CFDataGetLength(serial
);
1037 const uint8_t *serial_ptr
= CFDataGetBytePtr(serial
);
1039 while ((serial_length
> 0) && (*serial_ptr
== 0)) {
1044 if (serial_length
== (CFIndex
)sizeof(*UTN_USERFirst_Hardware_Serial
)) {
1046 for (i
= 0; i
< array_size(UTN_USERFirst_Hardware_Serial
); i
++)
1048 if (0 == memcmp(UTN_USERFirst_Hardware_Serial
[i
],
1049 serial_ptr
, sizeof(*UTN_USERFirst_Hardware_Serial
)))
1051 SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
);
1052 CFReleaseSafe(serial
);
1061 SecOTAPKIRef otapkiRef
= SecOTAPKICopyCurrentOTAPKIRef();
1062 if (NULL
!= otapkiRef
)
1064 CFSetRef blackListedKeys
= SecOTAPKICopyBlackListSet(otapkiRef
);
1065 CFRelease(otapkiRef
);
1066 if (NULL
!= blackListedKeys
)
1068 /* Check for blacklisted intermediates keys. */
1069 CFDataRef dgst
= SecCertificateCopyPublicKeySHA1Digest(cert
);
1072 /* Check dgst against blacklist. */
1073 if (CFSetContainsValue(blackListedKeys
, dgst
))
1075 SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
);
1079 CFRelease(blackListedKeys
);
1084 static void SecPolicyCheckGrayListedLeaf(SecPVCRef pvc
, CFStringRef key
)
1086 SecOTAPKIRef otapkiRef
= SecOTAPKICopyCurrentOTAPKIRef();
1087 if (NULL
!= otapkiRef
)
1089 CFSetRef grayListedKeys
= SecOTAPKICopyGrayList(otapkiRef
);
1090 CFRelease(otapkiRef
);
1091 if (NULL
!= grayListedKeys
)
1093 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, 0);
1095 CFDataRef dgst
= SecCertificateCopyPublicKeySHA1Digest(cert
);
1098 /* Check dgst against gray. */
1099 if (CFSetContainsValue(grayListedKeys
, dgst
))
1101 SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
);
1105 CFRelease(grayListedKeys
);
1110 static void SecPolicyCheckLeafMarkerOid(SecPVCRef pvc
, CFStringRef key
)
1112 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, 0);
1113 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
1114 CFTypeRef value
= CFDictionaryGetValue(policy
->_options
, key
);
1116 if (value
&& SecCertificateHasMarkerExtension(cert
, value
))
1119 SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
);
1122 static void SecPolicyCheckIntermediateMarkerOid(SecPVCRef pvc
, CFStringRef key
)
1124 CFIndex ix
, count
= SecPVCGetCertificateCount(pvc
);
1125 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
1126 CFTypeRef value
= CFDictionaryGetValue(policy
->_options
, key
);
1128 for (ix
= 1; ix
< count
- 1; ix
++) {
1129 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, ix
);
1130 if (SecCertificateHasMarkerExtension(cert
, value
))
1133 SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
);
1138 /****************************************************************************
1139 *********************** New rfc5280 Chain Validation ***********************
1140 ****************************************************************************/
1143 typedef struct cert_path
*cert_path_t
;
1148 typedef struct x500_name
*x500_name_t
;
1152 typedef struct algorithm_id
*algorithm_id_t
;
1153 struct algorithm_id
{
1154 oid_t algorithm_oid
;
1158 typedef struct trust_anchor
*trust_anchor_t
;
1159 struct trust_anchor
{
1160 x500_name_t issuer_name
;
1161 algorithm_id_t public_key_algorithm
; /* includes optional params */
1162 SecKeyRef public_key
;
1165 typedef struct certificate_policy
*certificate_policy_t
;
1166 struct certificate_policy
{
1167 policy_qualifier_t qualifiers
;
1169 SLIST_ENTRY(certificate_policy
) policies
;
1172 typedef struct policy_mapping
*policy_mapping_t
;
1173 struct policy_mapping
{
1174 SLIST_ENTRY(policy_mapping
) mappings
;
1175 oid_t issuer_domain_policy
;
1176 oid_t subject_domain_policy
;
1179 typedef struct root_name
*root_name_t
;
1184 struct policy_tree_add_ctx
{
1186 policy_qualifier_t p_q
;
1189 /* 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}. */
1190 static bool policy_tree_add_if_match(policy_tree_t node
, void *ctx
) {
1191 struct policy_tree_add_ctx
*info
= (struct policy_tree_add_ctx
*)ctx
;
1192 policy_set_t policy_set
;
1193 for (policy_set
= node
->expected_policy_set
;
1195 policy_set
= policy_set
->oid_next
) {
1196 if (oid_equal(policy_set
->oid
, info
->p_oid
)) {
1197 policy_tree_add_child(node
, &info
->p_oid
, info
->p_q
);
1204 /* 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}. */
1205 static bool policy_tree_add_if_any(policy_tree_t node
, void *ctx
) {
1206 struct policy_tree_add_ctx
*info
= (struct policy_tree_add_ctx
*)ctx
;
1207 if (oid_equal(node
->valid_policy
, oidAnyPolicy
)) {
1208 policy_tree_add_child(node
, &info
->p_oid
, info
->p_q
);
1214 /* Return true iff node has a child with a valid_policy equal to oid. */
1215 static bool policy_tree_has_child_with_oid(policy_tree_t node
,
1217 policy_tree_t child
;
1218 for (child
= node
->children
; child
; child
= child
->siblings
) {
1219 if (oid_equal(child
->valid_policy
, (*oid
))) {
1226 /* 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. */
1227 static bool policy_tree_add_expected(policy_tree_t node
, void *ctx
) {
1228 policy_qualifier_t p_q
= (policy_qualifier_t
)ctx
;
1229 policy_set_t policy_set
;
1230 bool added_node
= false;
1231 for (policy_set
= node
->expected_policy_set
;
1233 policy_set
= policy_set
->oid_next
) {
1234 if (!policy_tree_has_child_with_oid(node
, &policy_set
->oid
)) {
1235 policy_tree_add_child(node
, &policy_set
->oid
, p_q
);
1243 /* 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. */
1244 static bool policy_tree_map(policy_tree_t node
, void *ctx
) {
1245 /* Can't map oidAnyPolicy. */
1246 if (oid_equal(node
->valid_policy
, oidAnyPolicy
))
1249 const SecCEPolicyMappings
*pm
= (const SecCEPolicyMappings
*)ctx
;
1250 uint32_t mapping_ix
, mapping_count
= pm
->numMappings
;
1251 policy_set_t policy_set
= NULL
;
1252 /* First count how many mappings match this nodes valid_policy. */
1253 for (mapping_ix
= 0; mapping_ix
< mapping_count
; ++mapping_ix
) {
1254 const SecCEPolicyMapping
*mapping
= &pm
->mappings
[mapping_ix
];
1255 if (oid_equal(node
->valid_policy
, mapping
->issuerDomainPolicy
)) {
1256 policy_set_t p_node
= (policy_set_t
)malloc(sizeof(*policy_set
));
1257 p_node
->oid
= mapping
->subjectDomainPolicy
;
1258 p_node
->oid_next
= policy_set
? policy_set
: NULL
;
1259 policy_set
= p_node
;
1263 policy_tree_set_expected_policy(node
, policy_set
);
1270 #define POLICY_MAPPING 0
1271 #define POLICY_SUBTREES 0
1273 /* rfc5280 basic cert processing. */
1274 static void SecPolicyCheckBasicCertificateProcessing(SecPVCRef pvc
,
1278 CFIndex count
= SecPVCGetCertificateCount(pvc
);
1279 /* 64 bits cast: worst case here is we truncate the number of cert, and the validation may fail */
1280 assert((unsigned long)count
<=UINT32_MAX
); /* Debug check. Correct as long as CFIndex is long */
1281 uint32_t n
= (uint32_t)count
;
1282 bool is_anchored
= SecPVCIsAnchored(pvc
);
1284 /* If the anchor is trusted we don't procces the last cert in the
1288 /* Add a detail for the root not being trusted. */
1289 if (SecPVCSetResultForced(pvc
, kSecPolicyCheckAnchorTrusted
,
1290 n
- 1, kCFBooleanFalse
, true))
1294 CFAbsoluteTime verify_time
= SecPVCGetVerifyTime(pvc
);
1295 //policy_set_t user_initial_policy_set = NULL;
1296 //trust_anchor_t anchor;
1297 bool initial_policy_mapping_inhibit
= false;
1298 bool initial_explicit_policy
= false;
1299 bool initial_any_policy_inhibit
= false;
1301 root_name_t initial_permitted_subtrees
= NULL
;
1302 root_name_t initial_excluded_subtrees
= NULL
;
1305 /* Initialization */
1306 pvc
->valid_policy_tree
= policy_tree_create(&oidAnyPolicy
, NULL
);
1308 root_name_t permitted_subtrees
= initial_permitted_subtrees
;
1309 root_name_t excluded_subtrees
= initial_excluded_subtrees
;
1311 uint32_t explicit_policy
= initial_explicit_policy
? 0 : n
+ 1;
1312 uint32_t inhibit_any_policy
= initial_any_policy_inhibit
? 0 : n
+ 1;
1313 uint32_t policy_mapping
= initial_policy_mapping_inhibit
? 0 : n
+ 1;
1316 /* Path builder ensures we only get cert chains with proper issuer
1317 chaining with valid signatures along the way. */
1318 algorithm_id_t working_public_key_algorithm
= anchor
->public_key_algorithm
;
1319 SecKeyRef working_public_key
= anchor
->public_key
;
1320 x500_name_t working_issuer_name
= anchor
->issuer_name
;
1322 uint32_t i
, max_path_length
= n
;
1323 SecCertificateRef cert
= NULL
;
1324 for (i
= 1; i
<= n
; ++i
) {
1326 cert
= SecPVCGetCertificateAtIndex(pvc
, n
- i
);
1327 bool is_self_issued
= SecPVCIsCertificateAtIndexSelfSigned(pvc
, n
- i
);
1329 /* (a) Verify the basic certificate information. */
1330 /* @@@ Ensure that cert was signed with working_public_key_algorithm
1331 using the working_public_key and the working_public_key_parameters. */
1333 /* Already done by chain builder. */
1334 if (!SecCertificateIsValid(cert
, verify_time
)) {
1335 CFStringRef fail_key
= i
== n
? kSecPolicyCheckValidLeaf
: kSecPolicyCheckValidIntermediates
;
1336 if (!SecPVCSetResult(pvc
, fail_key
, n
- i
, kCFBooleanFalse
))
1341 /* Check revocation status if the certificate asks for it. */
1342 CFArrayRef ocspResponders
= SecCertificateGetOCSPResponders(cert
);
1343 if (ocspResponders
) {
1344 SecPVCSetCheckRevocation(pvc
);
1347 /* @@@ cert.issuer == working_issuer_name. */
1351 if (!is_self_issued
|| i
== n
) {
1352 /* 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. */
1353 /* 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. */
1357 if (pvc
->valid_policy_tree
) {
1358 const SecCECertificatePolicies
*cp
=
1359 SecCertificateGetCertificatePolicies(cert
);
1360 size_t policy_ix
, policy_count
= cp
? cp
->numPolicies
: 0;
1361 for (policy_ix
= 0; policy_ix
< policy_count
; ++policy_ix
) {
1362 const SecCEPolicyInformation
*policy
= &cp
->policies
[policy_ix
];
1363 oid_t p_oid
= policy
->policyIdentifier
;
1364 policy_qualifier_t p_q
= &policy
->policyQualifiers
;
1365 struct policy_tree_add_ctx ctx
= { p_oid
, p_q
};
1366 if (!oid_equal(p_oid
, oidAnyPolicy
)) {
1367 if (!policy_tree_walk_depth(pvc
->valid_policy_tree
, i
- 1,
1368 policy_tree_add_if_match
, &ctx
)) {
1369 policy_tree_walk_depth(pvc
->valid_policy_tree
, i
- 1,
1370 policy_tree_add_if_any
, &ctx
);
1374 /* The certificate policies extension includes the policy
1375 anyPolicy with the qualifier set AP-Q and either
1376 (a) inhibit_anyPolicy is greater than 0 or
1377 (b) i < n and the certificate is self-issued. */
1378 if (inhibit_any_policy
> 0 || (i
< n
&& is_self_issued
)) {
1379 for (policy_ix
= 0; policy_ix
< policy_count
; ++policy_ix
) {
1380 const SecCEPolicyInformation
*policy
= &cp
->policies
[policy_ix
];
1381 oid_t p_oid
= policy
->policyIdentifier
;
1382 policy_qualifier_t p_q
= &policy
->policyQualifiers
;
1383 if (oid_equal(p_oid
, oidAnyPolicy
)) {
1384 policy_tree_walk_depth(pvc
->valid_policy_tree
, i
- 1,
1385 policy_tree_add_expected
, (void *)p_q
);
1389 policy_tree_prune_childless(&pvc
->valid_policy_tree
, i
- 1);
1392 if (pvc
->valid_policy_tree
)
1393 policy_tree_prune(&pvc
->valid_policy_tree
);
1396 /* (f) Verify that either explicit_policy is greater than 0 or the
1397 valid_policy_tree is not equal to NULL. */
1398 if (!pvc
->valid_policy_tree
&& explicit_policy
== 0) {
1399 /* valid_policy_tree is empty and explicit policy is 0, illegal. */
1400 if (!SecPVCSetResultForced(pvc
, key
/* @@@ Need custom key */, n
- i
, kCFBooleanFalse
, true))
1403 /* If Last Cert in Path */
1407 /* Prepare for Next Cert */
1409 /* (a) verify that anyPolicy does not appear as an
1410 issuerDomainPolicy or a subjectDomainPolicy */
1411 CFDictionaryRef pm
= SecCertificateGetPolicyMappings(cert
);
1413 uint32_t mapping_ix
, mapping_count
= pm
->numMappings
;
1414 for (mapping_ix
= 0; mapping_ix
< mapping_count
; ++mapping_ix
) {
1415 const SecCEPolicyMapping
*mapping
= &pm
->mappings
[mapping_ix
];
1416 if (oid_equal(mapping
->issuerDomainPolicy
, oidAnyPolicy
)
1417 || oid_equal(mapping
->subjectDomainPolicy
, oidAnyPolicy
)) {
1418 /* Policy mapping uses anyPolicy, illegal. */
1419 if (!SecPVCSetResultForced(pvc
, key
/* @@@ Need custom key */, n
- i
, kCFBooleanFalse
))
1424 /* (1) If the policy_mapping variable is greater than 0 */
1425 if (policy_mapping
> 0) {
1426 if (!policy_tree_walk_depth(pvc
->valid_policy_tree
, i
,
1427 policy_tree_map
, (void *)pm
)) {
1428 /* 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:
1430 (i) set the valid_policy to ID-P;
1432 (ii) set the qualifier_set to the qualifier set of the
1433 policy anyPolicy in the certificate policies
1434 extension of certificate i; and
1435 (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. */
1439 /* (i) delete each node of depth i in the valid_policy_tree
1440 where ID-P is the valid_policy. */
1441 struct policy_tree_map_ctx ctx
= { idp_oid
, sdp_oid
};
1442 policy_tree_walk_depth(pvc
->valid_policy_tree
, i
,
1443 policy_tree_delete_if_match
, &ctx
);
1445 /* (ii) If there is a node in the valid_policy_tree of depth
1446 i-1 or less without any child nodes, delete that
1447 node. Repeat this step until there are no nodes of
1448 depth i-1 or less without children. */
1449 policy_tree_prune_childless(&pvc
->valid_policy_tree
, i
- 1);
1452 #endif /* POLICY_MAPPING */
1454 //working_issuer_name = SecCertificateGetNormalizedSubjectContent(cert);
1455 //working_public_key = SecCertificateCopyPublicKey(cert);
1456 //working_public_key_parameters = SecCertificateCopyPublicKeyParameters(cert);
1457 //working_public_key_algorithm = SecCertificateCopyPublicKeyAlgorithm(cert);
1459 /* (g) If a name constraints extension is included in the certificate, modify the permitted_subtrees and excluded_subtrees state variables as follows:
1461 /* @@@ handle name constraints. */
1464 if (!is_self_issued
) {
1465 if (explicit_policy
)
1469 if (inhibit_any_policy
)
1470 inhibit_any_policy
--;
1473 const SecCEPolicyConstraints
*pc
=
1474 SecCertificateGetPolicyConstraints(cert
);
1476 if (pc
->requireExplicitPolicyPresent
1477 && pc
->requireExplicitPolicy
< explicit_policy
) {
1478 explicit_policy
= pc
->requireExplicitPolicy
;
1480 if (pc
->inhibitPolicyMappingPresent
1481 && pc
->inhibitPolicyMapping
< policy_mapping
) {
1482 policy_mapping
= pc
->inhibitPolicyMapping
;
1486 uint32_t iap
= SecCertificateGetInhibitAnyPolicySkipCerts(cert
);
1487 if (iap
< inhibit_any_policy
) {
1488 inhibit_any_policy
= iap
;
1491 const SecCEBasicConstraints
*bc
=
1492 SecCertificateGetBasicConstraints(cert
);
1493 #if 0 /* Checked in chain builder pre signature verify already. */
1494 if (!bc
|| !bc
->isCA
) {
1495 /* Basic constraints not present or not marked as isCA, illegal. */
1496 if (!SecPVCSetResult(pvc
, kSecPolicyCheckBasicContraints
,
1497 n
- i
, kCFBooleanFalse
))
1502 if (!is_self_issued
) {
1503 if (max_path_length
> 0) {
1506 /* max_path_len exceeded, illegal. */
1507 if (!SecPVCSetResult(pvc
, kSecPolicyCheckBasicContraints
,
1508 n
- i
, kCFBooleanFalse
))
1513 if (bc
&& bc
->pathLenConstraintPresent
1514 && bc
->pathLenConstraint
< max_path_length
) {
1515 max_path_length
= bc
->pathLenConstraint
;
1517 #if 0 /* Checked in chain builder pre signature verify already. */
1518 /* (n) If a key usage extension is present, verify that the keyCertSign bit is set. */
1519 SecKeyUsage keyUsage
= SecCertificateGetKeyUsage(cert
);
1520 if (keyUsage
&& !(keyUsage
& kSecKeyUsageKeyCertSign
)) {
1521 if (!SecPVCSetResultForced(pvc
, kSecPolicyCheckKeyUsage
,
1522 n
- i
, kCFBooleanFalse
, true))
1526 /* (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. */
1527 if (SecCertificateHasUnknownCriticalExtension(cert
)) {
1528 /* Certificate contains one or more unknown critical extensions. */
1529 if (!SecPVCSetResult(pvc
, kSecPolicyCheckCriticalExtensions
,
1530 n
- i
, kCFBooleanFalse
))
1535 cert
= SecPVCGetCertificateAtIndex(pvc
, 0);
1537 if (explicit_policy
)
1540 const SecCEPolicyConstraints
*pc
= SecCertificateGetPolicyConstraints(cert
);
1542 if (pc
->requireExplicitPolicyPresent
1543 && pc
->requireExplicitPolicy
== 0) {
1544 explicit_policy
= 0;
1548 //working_public_key = SecCertificateCopyPublicKey(cert);
1550 /* 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
1551 working_public_key_algorithm are different, set the working_public_key_parameters to null. */
1552 //working_public_key_parameters = SecCertificateCopyPublicKeyParameters(cert);
1554 //working_public_key_algorithm = SecCertificateCopyPublicKeyAlgorithm(cert);
1555 /* (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. */
1556 if (SecCertificateHasUnknownCriticalExtension(cert
)) {
1557 /* Certificate contains one or more unknown critical extensions. */
1558 if (!SecPVCSetResult(pvc
, kSecPolicyCheckCriticalExtensions
,
1559 0, kCFBooleanFalse
))
1562 /* (g) Calculate the intersection of the valid_policy_tree and the user-initial-policy-set, as follows */
1564 if (pvc
->valid_policy_tree
) {
1565 #if !defined(NDEBUG)
1566 policy_tree_dump(pvc
->valid_policy_tree
);
1569 //policy_tree_prune_childless(&pvc->valid_policy_tree, n - 1);
1572 /* If either (1) the value of explicit_policy variable is greater than
1573 zero or (2) the valid_policy_tree is not NULL, then path processing
1575 if (!pvc
->valid_policy_tree
&& explicit_policy
== 0) {
1576 /* valid_policy_tree is empty and explicit policy is 0, illegal. */
1577 if (!SecPVCSetResultForced(pvc
, key
/* @@@ Need custom key */, 0, kCFBooleanFalse
, true))
1582 static policy_set_t
policies_for_cert(SecCertificateRef cert
) {
1583 policy_set_t policies
= NULL
;
1584 const SecCECertificatePolicies
*cp
=
1585 SecCertificateGetCertificatePolicies(cert
);
1586 size_t policy_ix
, policy_count
= cp
? cp
->numPolicies
: 0;
1587 for (policy_ix
= 0; policy_ix
< policy_count
; ++policy_ix
) {
1588 policy_set_add(&policies
, &cp
->policies
[policy_ix
].policyIdentifier
);
1593 static void SecPolicyCheckEV(SecPVCRef pvc
,
1595 CFIndex ix
, count
= SecPVCGetCertificateCount(pvc
);
1596 policy_set_t valid_policies
= NULL
;
1598 for (ix
= 0; ix
< count
; ++ix
) {
1599 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, ix
);
1600 policy_set_t policies
= policies_for_cert(cert
);
1603 /* anyPolicy in the leaf isn't allowed for EV, so only init
1604 valid_policies if we have real policies. */
1605 if (!policy_set_contains(policies
, &oidAnyPolicy
)) {
1606 valid_policies
= policies
;
1609 } else if (ix
< count
- 1) {
1610 /* Subordinate CA */
1611 if (!SecPolicySubordinateCACertificateCouldBeEV(cert
)) {
1612 secdebug("ev", "subordinate certificate is not ev");
1613 if (SecPVCSetResultForced(pvc
, key
,
1614 ix
, kCFBooleanFalse
, true)) {
1615 policy_set_free(valid_policies
);
1616 policy_set_free(policies
);
1620 policy_set_intersect(&valid_policies
, policies
);
1623 if (!SecPolicyRootCACertificateIsEV(cert
, valid_policies
)) {
1624 secdebug("ev", "anchor certificate is not ev");
1625 if (SecPVCSetResultForced(pvc
, key
,
1626 ix
, kCFBooleanFalse
, true)) {
1627 policy_set_free(valid_policies
);
1628 policy_set_free(policies
);
1633 policy_set_free(policies
);
1634 if (!valid_policies
) {
1635 secdebug("ev", "valid_policies set is empty: chain not ev");
1636 /* If we ever get into a state where no policies are valid anymore
1637 this can't be an ev chain. */
1638 if (SecPVCSetResultForced(pvc
, key
,
1639 ix
, kCFBooleanFalse
, true)) {
1645 policy_set_free(valid_policies
);
1647 /* (a) EV Subscriber Certificates Each EV Certificate issued by the CA to a
1648 Subscriber MUST contain an OID defined by the CA in the certificate’s
1649 certificatePolicies extension that: (i) indicates which CA policy statement relates
1650 to that certificate, (ii) asserts the CA’s adherence to and compliance with these
1651 Guidelines, and (iii), by pre-agreement with the Application Software Vendor,
1652 marks the certificate as being an EV Certificate.
1653 (b) EV Subordinate CA Certificates
1654 (1) Certificates issued to Subordinate CAs that are not controlled by the issuing
1655 CA MUST contain one or more OIDs defined by the issuing CA that
1656 explicitly identify the EV Policies that are implemented by the Subordinate
1658 (2) Certificates issued to Subordinate CAs that are controlled by the Root CA
1659 MAY contain the special anyPolicy OID (2.5.29.32.0).
1660 (c) Root CA Certificates Root CA Certificates SHOULD NOT contain the
1661 certificatePolicies or extendedKeyUsage extensions.
1666 static void SecPolicyCheckCertificatePolicyOid(SecPVCRef pvc
, CFStringRef key
)
1668 CFIndex ix
, count
= SecPVCGetCertificateCount(pvc
);
1669 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
1670 CFTypeRef value
= CFDictionaryGetValue(policy
->_options
, key
);
1672 key_value
.data
= NULL
;
1673 key_value
.length
= 0;
1675 if (CFGetTypeID(value
) == CFDataGetTypeID())
1677 CFDataRef key_data
= (CFDataRef
)value
;
1678 key_value
.data
= (DERByte
*)CFDataGetBytePtr(key_data
);
1679 key_value
.length
= (DERSize
)CFDataGetLength(key_data
);
1681 for (ix
= 0; ix
< count
; ix
++) {
1682 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, ix
);
1683 policy_set_t policies
= policies_for_cert(cert
);
1685 if (policy_set_contains(policies
, &key_value
)) {
1689 SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
);
1694 static void SecPolicyCheckRevocation(SecPVCRef pvc
,
1696 SecPVCSetCheckRevocation(pvc
);
1699 static void SecPolicyCheckNoNetworkAccess(SecPVCRef pvc
,
1701 SecPathBuilderSetCanAccessNetwork(pvc
->builder
, false);
1706 /********************************************************
1707 ****************** SecRVCRef Functions *****************
1708 ********************************************************/
1710 /* Revocation verification context. */
1711 struct OpaqueSecRVC
{
1712 /* Will contain the response data. */
1715 /* Pointer to the pvc for this revocation check. */
1718 /* The ocsp request we send to each responder. */
1719 SecOCSPRequestRef ocspRequest
;
1721 /* Index of cert in pvc that this RVC is for 0 = leaf, etc. */
1724 /* Index in array returned by SecCertificateGetOCSPResponders() for current
1726 CFIndex responderIX
;
1728 /* URL of current responder. */
1731 /* Date until which this revocation status is valid. */
1732 CFAbsoluteTime nextUpdate
;
1736 typedef struct OpaqueSecRVC
*SecRVCRef
;
1738 static void SecRVCDelete(SecRVCRef rvc
) {
1739 secdebug("alloc", "%p", rvc
);
1740 asynchttp_free(&rvc
->http
);
1741 SecOCSPRequestFinalize(rvc
->ocspRequest
);
1744 /* Return the next responder we should contact for this rvc or NULL if we
1745 exhausted them all. */
1746 static CFURLRef
SecRVCGetNextResponder(SecRVCRef rvc
) {
1747 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(rvc
->pvc
, rvc
->certIX
);
1748 CFArrayRef ocspResponders
= SecCertificateGetOCSPResponders(cert
);
1749 if (ocspResponders
) {
1750 CFIndex responderCount
= CFArrayGetCount(ocspResponders
);
1751 while (rvc
->responderIX
< responderCount
) {
1752 CFURLRef responder
= CFArrayGetValueAtIndex(ocspResponders
, rvc
->responderIX
);
1754 CFStringRef scheme
= CFURLCopyScheme(responder
);
1756 /* We only support http and https responders currently. */
1757 bool valid_responder
= (CFEqual(CFSTR("http"), scheme
) ||
1758 CFEqual(CFSTR("https"), scheme
));
1760 if (valid_responder
)
1768 /* Fire off an async http request for this certs revocation status, return
1769 false if request was queued, true if we're done. */
1770 static bool SecRVCFetchNext(SecRVCRef rvc
) {
1771 while ((rvc
->responder
= SecRVCGetNextResponder(rvc
))) {
1772 CFDataRef request
= SecOCSPRequestGetDER(rvc
->ocspRequest
);
1776 if (!asyncHttpPost(rvc
->responder
, request
, &rvc
->http
)) {
1777 /* Async request was posted, wait for reply. */
1787 /* Proccess a verified ocsp response for a given cert. Return true if the
1788 certificate status was obtained. */
1789 static bool SecOCSPSingleResponseProccess(SecOCSPSingleResponseRef
this,
1792 switch (this->certStatus
) {
1794 secdebug("ocsp", "CS_Good for cert %" PRIdCFIndex
, rvc
->certIX
);
1795 /* @@@ Mark cert as valid until a given date (nextUpdate if we have one)
1796 in the info dictionary. */
1797 //cert.revokeCheckGood(true);
1798 rvc
->nextUpdate
= this->nextUpdate
;
1802 secdebug("ocsp", "CS_Revoked for cert %" PRIdCFIndex
, rvc
->certIX
);
1803 /* @@@ Mark cert as revoked (with reason) at revocation date in
1804 the info dictionary, or perhaps we should use a different key per
1805 reason? That way a client using exceptions can ignore some but
1807 SInt32 reason
= this->crlReason
;
1808 CFNumberRef cfreason
= CFNumberCreate(kCFAllocatorDefault
, kCFNumberSInt32Type
, &reason
);
1809 SecPVCSetResultForced(rvc
->pvc
, kSecPolicyCheckRevocation
, rvc
->certIX
,
1811 CFRelease(cfreason
);
1815 /* not an error, no per-cert status, nothing here */
1816 secdebug("ocsp", "CS_Unknown for cert %" PRIdCFIndex
, rvc
->certIX
);
1820 secdebug("ocsp", "BAD certStatus (%d) for cert %" PRIdCFIndex
,
1821 (int)this->certStatus
, rvc
->certIX
);
1829 static bool SecOCSPResponseVerify(SecOCSPResponseRef ocspResponse
, SecRVCRef rvc
) {
1831 SecCertificatePathRef issuer
= SecCertificatePathCopyFromParent(rvc
->pvc
->path
, rvc
->certIX
+ 1);
1832 SecCertificatePathRef signer
= SecOCSPResponseCopySigner(ocspResponse
, issuer
);
1836 if (signer
== issuer
) {
1837 /* We already know we trust issuer since it's the path we are
1838 trying to verify minus the leaf. */
1839 secdebug("ocsp", "ocsp responder: %@ response signed by issuer",
1844 "ocsp responder: %@ response signed by cert issued by issuer",
1846 /* @@@ Now check that we trust signer. */
1847 const void *ocspSigner
= SecPolicyCreateOCSPSigner();
1848 CFArrayRef policies
= CFArrayCreate(kCFAllocatorDefault
,
1849 &ocspSigner
, 1, &kCFTypeArrayCallBacks
);
1850 CFRelease(ocspSigner
);
1851 CFAbsoluteTime verifyTime
= SecOCSPResponseVerifyTime(ocspResponse
);
1852 struct OpaqueSecPVC ospvc
;
1853 SecPVCInit(&ospvc
, rvc
->pvc
->builder
, policies
, verifyTime
);
1854 CFRelease(policies
);
1855 SecPVCSetPath(&ospvc
, signer
, NULL
);
1856 SecPVCLeafChecks(&ospvc
);
1858 bool completed
= SecPVCPathChecks(&ospvc
);
1859 /* If completed is false we are waiting for a callback, this
1860 shouldn't happen since we aren't asking for details, no
1861 revocation checking is done. */
1863 ocspdErrorLog("SecPVCPathChecks unexpectedly started "
1865 /* @@@ assert() or abort here perhaps? */
1869 secdebug("ocsp", "response satisfies ocspSigner policy (%@)",
1873 /* @@@ We don't trust the cert so don't use this response. */
1874 ocspdErrorLog("ocsp response signed by certificate which "
1875 "does not satisfy ocspSigner policy");
1878 SecPVCDelete(&ospvc
);
1883 /* @@@ No signer found for this ocsp response, discard it. */
1884 secdebug("ocsp", "ocsp responder: %@ no signer found for response",
1889 #if DUMP_OCSPRESPONSES
1891 snprintf(buf
, 40, "/tmp/ocspresponse%ld%s.der",
1892 rvc
->certIX
, (trusted
? "t" : "u"));
1893 secdumpdata(ocspResponse
->data
, buf
);
1899 /* Callback from async http code after an ocsp response has been received. */
1900 static void SecOCSPFetchCompleted(asynchttp_t
*http
, CFTimeInterval maxAge
) {
1901 SecRVCRef rvc
= (SecRVCRef
)http
->info
;
1902 SecPVCRef pvc
= rvc
->pvc
;
1903 SecOCSPResponseRef ocspResponse
= NULL
;
1904 if (http
->response
) {
1905 CFDataRef data
= CFHTTPMessageCopyBody(http
->response
);
1907 /* Parse the returned data as if it's an ocspResponse. */
1908 ocspResponse
= SecOCSPResponseCreate(data
, maxAge
);
1914 SecOCSPResponseStatus orStatus
= SecOCSPGetResponseStatus(ocspResponse
);
1915 if (orStatus
== kSecOCSPSuccess
) {
1916 SecOCSPSingleResponseRef sr
=
1917 SecOCSPResponseCopySingleResponse(ocspResponse
, rvc
->ocspRequest
);
1919 /* The ocsp response didn't have a singleResponse for the cert
1920 we are looking for, let's try the next responder. */
1922 "ocsp responder: %@ did not include status of requested cert",
1925 /* We got a singleResponse for the cert we are interested in,
1926 let's proccess it. */
1927 /* @@@ If the responder doesn't have the ocsp-nocheck extension
1928 we should check whether the leaf was revoked (we are
1929 already checking the rest of the chain). */
1930 /* Check the OCSP response signature and verify the
1932 if (SecOCSPResponseVerify(ocspResponse
, rvc
)) {
1933 secdebug("ocsp","responder: %@ sent proper response",
1936 if (SecOCSPSingleResponseProccess(sr
, rvc
)) {
1937 if (rvc
->nextUpdate
== 0) {
1939 SecOCSPResponseGetExpirationTime(ocspResponse
);
1941 /* If the singleResponse had meaningful information, we
1942 cache the response. */
1943 SecOCSPCacheAddResponse(ocspResponse
, rvc
->responder
);
1947 SecOCSPSingleResponseDestroy(sr
);
1950 /* ocsp response not ok. Let's try next responder. */
1951 secdebug("ocsp", "responder: %@ returned status: %d",
1952 rvc
->responder
, orStatus
);
1954 if (!SecPVCSetResultForced(pvc
, kSecPolicyCheckRevocation
,
1955 rvc
->certIX
, kCFBooleanFalse
, true))
1959 SecOCSPResponseFinalize(ocspResponse
);
1963 /* Clear the data for the next response. */
1964 asynchttp_free(http
);
1965 SecRVCFetchNext(rvc
);
1970 if (!--pvc
->asyncJobCount
) {
1971 SecPathBuilderStep(pvc
->builder
);
1976 static void SecRVCInit(SecRVCRef rvc
, SecPVCRef pvc
, CFIndex certIX
) {
1977 secdebug("alloc", "%p", rvc
);
1979 rvc
->certIX
= certIX
;
1980 rvc
->http
.queue
= SecPathBuilderGetQueue(pvc
->builder
);
1981 rvc
->http
.completed
= SecOCSPFetchCompleted
;
1982 rvc
->http
.info
= rvc
;
1983 rvc
->ocspRequest
= NULL
;
1984 rvc
->responderIX
= 0;
1985 rvc
->responder
= NULL
;
1986 rvc
->nextUpdate
= 0;
1991 static bool SecPVCCheckRevocation(SecPVCRef pvc
) {
1992 secdebug("ocsp", "checking revocation");
1993 CFIndex certIX
, certCount
= SecPVCGetCertificateCount(pvc
);
1994 bool completed
= true;
1995 if (certCount
<= 1) {
1996 /* Can't verify without an issuer; we're done */
1999 if (!SecPVCIsAnchored(pvc
)) {
2000 /* We can't check revocation for chains without a trusted anchor. */
2006 /* @@@ Implement getting this value from the client.
2007 Optional responder passed in though policy. */
2008 CFURLRef localResponder
= NULL
;
2009 /* Generate a nonce in outgoing request if true. */
2010 bool genNonce
= false;
2011 /* Require a nonce in response if true. */
2012 bool requireRespNonce
= false;
2013 bool cacheReadDisable
= false;
2014 bool cacheWriteDisable
= false;
2018 /* We have done revocation checking already, we're done. */
2019 secdebug("ocsp", "Not rechecking revocation");
2023 /* Setup things so we check revocation status of all certs except the
2025 pvc
->rvcs
= calloc(sizeof(struct OpaqueSecRVC
), certCount
);
2028 /* Lookup cached revocation data for each certificate. */
2029 for (certIX
= 0; certIX
< certCount
; ++certIX
) {
2030 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(rvc
->pvc
, rvc
->certIX
);
2031 CFArrayRef ocspResponders
= SecCertificateGetOCSPResponders(cert
);
2032 if (ocspResponders
) {
2033 /* First look though passed in ocsp responses. */
2034 //SecPVCGetOCSPResponseForCertificateAtIndex(pvc, ix, singleResponse);
2036 /* Then look though shared cache (we don't care which responder
2037 something came from here). */
2038 CFDataRef ocspResponse
= SecOCSPCacheCopyMatching(SecCertIDRef certID
, NULL
);
2040 /* Now let's parse the response. */
2041 if (decodeOCSPResponse(ocspResp
)) {
2042 secdebug("ocsp", "response ok: %@", ocspResp
);
2044 secdebug("ocsp", "response bad: %@", ocspResp
);
2045 /* ocsp response not ok. */
2046 if (!SecPVCSetResultForced(pvc
, key
, ix
, kCFBooleanFalse
, true))
2049 CFReleaseSafe(ocspResp
);
2051 /* Check if certificate has any crl distributionPoints. */
2052 CFArrayRef distributionPoints
= SecCertificateGetCRLDistributionPoints(cert
);
2053 if (distributionPoints
) {
2054 /* Look for a cached CRL and potentially delta CRL for this certificate. */
2060 /* Note that if we are multi threaded and a job completes after it
2061 is started but before we return from this function, we don't want
2062 a callback to decrement asyncJobCount to zero before we finish issuing
2063 all the jobs. To avoid this we pretend we issued certCount async jobs,
2064 and decrement pvc->asyncJobCount for each cert that we don't start a
2065 background fetch for. */
2066 pvc
->asyncJobCount
= (unsigned int) certCount
;
2068 /* Loop though certificates again and issue an ocsp fetch if the
2069 revocation status checking isn't done yet. */
2070 for (certIX
= 0; certIX
< certCount
; ++certIX
) {
2071 secdebug("ocsp", "checking revocation for cert: %ld", certIX
);
2072 SecRVCRef rvc
= &((SecRVCRef
)pvc
->rvcs
)[certIX
];
2073 SecRVCInit(rvc
, pvc
, certIX
);
2077 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(rvc
->pvc
,
2079 /* The certIX + 1 is ok here since certCount is always at least 1
2080 less than the actual number of certs. */
2081 SecCertificateRef issuer
= SecPVCGetCertificateAtIndex(rvc
->pvc
,
2084 rvc
->ocspRequest
= SecOCSPRequestCreate(cert
, issuer
);
2085 SecOCSPResponseRef ocspResponse
;
2086 ocspResponse
= SecOCSPCacheCopyMatching(rvc
->ocspRequest
, NULL
);
2088 SecOCSPSingleResponseRef sr
=
2089 SecOCSPResponseCopySingleResponse(ocspResponse
, rvc
->ocspRequest
);
2091 /* The cached ocsp response didn't have a singleResponse for
2092 the cert we are looking for, it's shouldn't be in the cache. */
2093 secdebug("ocsp", "cached ocsp response did not include status"
2094 " of requested cert");
2096 /* We got a singleResponse for the cert we are interested in,
2097 let's proccess it. */
2099 /* @@@ If the responder doesn't have the ocsp-nocheck extension
2100 we should check whether the leaf was revoked (we are
2101 already checking the rest of the chain). */
2102 /* Recheck the OCSP response signature and verify the
2104 if (SecOCSPResponseVerify(ocspResponse
, rvc
)) {
2105 secdebug("ocsp","cached response still has valid signature");
2107 if (SecOCSPSingleResponseProccess(sr
, rvc
)) {
2108 CFAbsoluteTime expTime
=
2109 SecOCSPResponseGetExpirationTime(ocspResponse
);
2110 if (rvc
->nextUpdate
== 0 || expTime
< rvc
->nextUpdate
)
2111 rvc
->nextUpdate
= expTime
;
2115 SecOCSPSingleResponseDestroy(sr
);
2117 SecOCSPResponseFinalize(ocspResponse
);
2120 /* Unless we succefully checked the revocation status of this cert
2121 based on the cache, Attempt to fire off an async http request
2122 for this certs revocation status. */
2123 bool fetch_done
= true;
2124 if (rvc
->done
|| !SecPathBuilderCanAccessNetwork(pvc
->builder
) ||
2125 (fetch_done
= SecRVCFetchNext(rvc
))) {
2126 /* We got a cache hit or we aren't allowed to access the network,
2127 or the async http post failed. */
2129 /* We didn't really start a background job for this cert. */
2130 pvc
->asyncJobCount
--;
2131 } else if (!fetch_done
) {
2132 /* We started at least one background fetch. */
2137 /* Return false if we started any background jobs. */
2138 /* We can't just return !pvc->asyncJobCount here, since if we started any
2139 jobs the completion callback will be called eventually and it will call
2140 SecPathBuilderStep(). If for some reason everything completed before we
2141 get here we still want the outer SecPathBuilderStep() to terminate so we
2142 keep track of whether we started any jobs and return false if so. */
2147 void SecPolicyServerInitalize(void) {
2148 gSecPolicyLeafCallbacks
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0,
2149 &kCFTypeDictionaryKeyCallBacks
, NULL
);
2150 gSecPolicyPathCallbacks
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0,
2151 &kCFTypeDictionaryKeyCallBacks
, NULL
);
2152 CFDictionaryAddValue(gSecPolicyPathCallbacks
,
2153 kSecPolicyCheckBasicCertificateProcessing
,
2154 SecPolicyCheckBasicCertificateProcessing
);
2155 CFDictionaryAddValue(gSecPolicyPathCallbacks
,
2156 kSecPolicyCheckCriticalExtensions
, SecPolicyCheckCriticalExtensions
);
2157 CFDictionaryAddValue(gSecPolicyPathCallbacks
,
2158 kSecPolicyCheckIdLinkage
, SecPolicyCheckIdLinkage
);
2159 CFDictionaryAddValue(gSecPolicyLeafCallbacks
,
2160 kSecPolicyCheckKeyUsage
, SecPolicyCheckKeyUsage
);
2161 CFDictionaryAddValue(gSecPolicyLeafCallbacks
,
2162 kSecPolicyCheckExtendedKeyUsage
, SecPolicyCheckExtendedKeyUsage
);
2163 CFDictionaryAddValue(gSecPolicyLeafCallbacks
,
2164 kSecPolicyCheckBasicContraints
, SecPolicyCheckBasicContraints
);
2165 CFDictionaryAddValue(gSecPolicyLeafCallbacks
,
2166 kSecPolicyCheckNonEmptySubject
, SecPolicyCheckNonEmptySubject
);
2167 CFDictionaryAddValue(gSecPolicyLeafCallbacks
,
2168 kSecPolicyCheckQualifiedCertStatements
,
2169 SecPolicyCheckQualifiedCertStatements
);
2170 CFDictionaryAddValue(gSecPolicyLeafCallbacks
,
2171 kSecPolicyCheckSSLHostname
, SecPolicyCheckSSLHostname
);
2172 CFDictionaryAddValue(gSecPolicyLeafCallbacks
,
2173 kSecPolicyCheckEmail
, SecPolicyCheckEmail
);
2174 CFDictionaryAddValue(gSecPolicyPathCallbacks
,
2175 kSecPolicyCheckValidIntermediates
, SecPolicyCheckValidIntermediates
);
2176 CFDictionaryAddValue(gSecPolicyLeafCallbacks
,
2177 kSecPolicyCheckValidLeaf
, SecPolicyCheckValidLeaf
);
2178 CFDictionaryAddValue(gSecPolicyPathCallbacks
,
2179 kSecPolicyCheckValidRoot
, SecPolicyCheckValidRoot
);
2180 CFDictionaryAddValue(gSecPolicyPathCallbacks
,
2181 kSecPolicyCheckIssuerCommonName
, SecPolicyCheckIssuerCommonName
);
2182 CFDictionaryAddValue(gSecPolicyLeafCallbacks
,
2183 kSecPolicyCheckSubjectCommonNamePrefix
,
2184 SecPolicyCheckSubjectCommonNamePrefix
);
2185 CFDictionaryAddValue(gSecPolicyLeafCallbacks
,
2186 kSecPolicyCheckSubjectCommonName
,
2187 SecPolicyCheckSubjectCommonName
);
2188 CFDictionaryAddValue(gSecPolicyLeafCallbacks
,
2189 kSecPolicyCheckNotValidBefore
,
2190 SecPolicyCheckNotValidBefore
);
2191 CFDictionaryAddValue(gSecPolicyPathCallbacks
,
2192 kSecPolicyCheckChainLength
, SecPolicyCheckChainLength
);
2193 CFDictionaryAddValue(gSecPolicyPathCallbacks
,
2194 kSecPolicyCheckAnchorSHA1
, SecPolicyCheckAnchorSHA1
);
2195 CFDictionaryAddValue(gSecPolicyLeafCallbacks
,
2196 kSecPolicyCheckSubjectOrganization
,
2197 SecPolicyCheckSubjectOrganization
);
2198 CFDictionaryAddValue(gSecPolicyLeafCallbacks
,
2199 kSecPolicyCheckSubjectOrganizationalUnit
,
2200 SecPolicyCheckSubjectOrganizationalUnit
);
2201 CFDictionaryAddValue(gSecPolicyLeafCallbacks
,
2202 kSecPolicyCheckEAPTrustedServerNames
,
2203 SecPolicyCheckEAPTrustedServerNames
);
2204 CFDictionaryAddValue(gSecPolicyLeafCallbacks
,
2205 kSecPolicyCheckSubjectCommonNameTEST
,
2206 SecPolicyCheckSubjectCommonNameTEST
);
2207 CFDictionaryAddValue(gSecPolicyLeafCallbacks
,
2208 kSecPolicyCheckRevocation
,
2209 SecPolicyCheckRevocation
);
2210 CFDictionaryAddValue(gSecPolicyLeafCallbacks
,
2211 kSecPolicyCheckNoNetworkAccess
,
2212 SecPolicyCheckNoNetworkAccess
);
2213 CFDictionaryAddValue(gSecPolicyLeafCallbacks
,
2214 kSecPolicyCheckBlackListedLeaf
,
2215 SecPolicyCheckBlackListedLeaf
);
2216 CFDictionaryAddValue(gSecPolicyLeafCallbacks
,
2217 kSecPolicyCheckGrayListedLeaf
,
2218 SecPolicyCheckGrayListedLeaf
);
2219 CFDictionaryAddValue(gSecPolicyLeafCallbacks
,
2220 kSecPolicyCheckLeafMarkerOid
,
2221 SecPolicyCheckLeafMarkerOid
);
2222 CFDictionaryAddValue(gSecPolicyPathCallbacks
,
2223 kSecPolicyCheckIntermediateMarkerOid
,
2224 SecPolicyCheckIntermediateMarkerOid
);
2225 CFDictionaryAddValue(gSecPolicyLeafCallbacks
,
2226 kSecPolicyCheckCertificatePolicy
,
2227 SecPolicyCheckCertificatePolicyOid
);
2230 /* AUDIT[securityd](done):
2231 array (ok) is a caller provided array, only its cf type has
2233 The options (ok) field ends up in policy->_options unchecked, so every access
2234 of policy->_options needs to be validated.
2236 static SecPolicyRef
SecPolicyCreateWithArray(CFArrayRef array
) {
2237 SecPolicyRef policy
= NULL
;
2238 require_quiet(array
&& CFArrayGetCount(array
) == 2, errOut
);
2239 CFStringRef oid
= (CFStringRef
)CFArrayGetValueAtIndex(array
, 0);
2240 require_quiet(isString(oid
), errOut
);
2241 CFDictionaryRef options
= (CFDictionaryRef
)CFArrayGetValueAtIndex(array
, 1);
2242 require_quiet(isDictionary(options
), errOut
);
2243 policy
= SecPolicyCreate(oid
, options
);
2248 /* AUDIT[securityd](done):
2249 value (ok) is an element in a caller provided array.
2251 static void deserializePolicy(const void *value
, void *context
) {
2252 CFArrayRef policyArray
= (CFArrayRef
)value
;
2253 if (isArray(policyArray
)) {
2254 CFTypeRef deserializedPolicy
= SecPolicyCreateWithArray(policyArray
);
2255 if (deserializedPolicy
) {
2256 CFArrayAppendValue((CFMutableArrayRef
)context
, deserializedPolicy
);
2257 CFRelease(deserializedPolicy
);
2262 /* AUDIT[securityd](done):
2263 serializedPolicies (ok) is a caller provided array, only its cf type has
2266 CFArrayRef
SecPolicyArrayDeserialize(CFArrayRef serializedPolicies
) {
2267 CFMutableArrayRef result
= NULL
;
2268 require_quiet(isArray(serializedPolicies
), errOut
);
2269 CFIndex count
= CFArrayGetCount(serializedPolicies
);
2270 result
= CFArrayCreateMutable(kCFAllocatorDefault
, count
, &kCFTypeArrayCallBacks
);
2271 CFRange all_policies
= { 0, count
};
2272 CFArrayApplyFunction(serializedPolicies
, all_policies
, deserializePolicy
, result
);
2279 /********************************************************
2280 ****************** SecPVCRef Functions *****************
2281 ********************************************************/
2283 void SecPVCInit(SecPVCRef pvc
, SecPathBuilderRef builder
, CFArrayRef policies
,
2284 CFAbsoluteTime verifyTime
) {
2285 secdebug("alloc", "%p", pvc
);
2286 // Weird logging policies crashes.
2287 //secdebug("policy", "%@", policies);
2288 pvc
->builder
= builder
;
2289 pvc
->policies
= policies
;
2292 pvc
->verifyTime
= verifyTime
;
2294 pvc
->details
= NULL
;
2296 pvc
->valid_policy_tree
= NULL
;
2297 pvc
->callbacks
= NULL
;
2300 pvc
->asyncJobCount
= 0;
2301 pvc
->check_revocation
= false;
2302 pvc
->optionally_ev
= false;
2307 static void SecPVCDeleteRVCs(SecPVCRef pvc
) {
2308 secdebug("alloc", "%p", pvc
);
2315 void SecPVCDelete(SecPVCRef pvc
) {
2316 secdebug("alloc", "%p", pvc
);
2317 CFReleaseNull(pvc
->policies
);
2318 CFReleaseNull(pvc
->details
);
2319 CFReleaseNull(pvc
->info
);
2320 if (pvc
->valid_policy_tree
) {
2321 policy_tree_prune(&pvc
->valid_policy_tree
);
2323 SecPVCDeleteRVCs(pvc
);
2326 void SecPVCSetPath(SecPVCRef pvc
, SecCertificatePathRef path
,
2327 CFArrayRef details
) {
2328 secdebug("policy", "%@", path
);
2329 if (pvc
->path
!= path
) {
2330 /* Changing path makes us clear the Revocation Verification Contexts */
2331 SecPVCDeleteRVCs(pvc
);
2334 pvc
->details
= details
;
2335 CFReleaseNull(pvc
->info
);
2336 if (pvc
->valid_policy_tree
) {
2337 policy_tree_prune(&pvc
->valid_policy_tree
);
2343 SecPolicyRef
SecPVCGetPolicy(SecPVCRef pvc
) {
2344 return (SecPolicyRef
)CFArrayGetValueAtIndex(pvc
->policies
, pvc
->policyIX
);
2347 CFIndex
SecPVCGetCertificateCount(SecPVCRef pvc
) {
2348 return SecCertificatePathGetCount(pvc
->path
);
2351 SecCertificateRef
SecPVCGetCertificateAtIndex(SecPVCRef pvc
, CFIndex ix
) {
2352 return SecCertificatePathGetCertificateAtIndex(pvc
->path
, ix
);
2355 bool SecPVCIsCertificateAtIndexSelfSigned(SecPVCRef pvc
, CFIndex ix
) {
2356 return SecCertificatePathSelfSignedIndex(pvc
->path
) == ix
;
2359 void SecPVCSetCheckRevocation(SecPVCRef pvc
) {
2360 pvc
->check_revocation
= true;
2361 secdebug("ocsp", "deferred revocation checking enabled");
2364 bool SecPVCIsAnchored(SecPVCRef pvc
) {
2365 return SecCertificatePathIsAnchored(pvc
->path
);
2368 CFAbsoluteTime
SecPVCGetVerifyTime(SecPVCRef pvc
) {
2369 return pvc
->verifyTime
;
2372 /* AUDIT[securityd](done):
2373 policy->_options is a caller provided dictionary, only its cf type has
2376 bool SecPVCSetResultForced(SecPVCRef pvc
,
2377 CFStringRef key
, CFIndex ix
, CFTypeRef result
, bool force
) {
2379 secdebug("policy", "cert[%d]: %@ =(%s)[%s]> %@", (int) ix
, key
,
2380 (pvc
->callbacks
== gSecPolicyLeafCallbacks
? "leaf"
2381 : (pvc
->callbacks
== gSecPolicyPathCallbacks
? "path"
2383 (force
? "force" : ""), result
);
2385 /* If this is not something the current policy cares about ignore
2386 this error and return true so our caller continues evaluation. */
2388 /* @@@ The right long term fix might be to check if none of the passed
2389 in policies contain this key, since not all checks are run for all
2391 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
2392 if (policy
&& !CFDictionaryContainsKey(policy
->_options
, key
))
2396 /* @@@ Check to see if the SecTrustSettings for the certificate in question
2397 tell us to ignore this error. */
2398 pvc
->result
= false;
2402 CFMutableDictionaryRef detail
=
2403 (CFMutableDictionaryRef
)CFArrayGetValueAtIndex(pvc
->details
, ix
);
2405 /* Perhaps detail should have an array of results per key? As it stands
2406 in the case of multiple policy failures the last failure stands. */
2407 CFDictionarySetValue(detail
, key
, result
);
2412 bool SecPVCSetResult(SecPVCRef pvc
,
2413 CFStringRef key
, CFIndex ix
, CFTypeRef result
) {
2414 return SecPVCSetResultForced(pvc
, key
, ix
, result
, false);
2417 /* AUDIT[securityd](done):
2418 key(ok) is a caller provided.
2419 value(ok, unused) is a caller provided.
2421 static void SecPVCValidateKey(const void *key
, const void *value
,
2423 SecPVCRef pvc
= (SecPVCRef
)context
;
2425 /* If our caller doesn't want full details and we failed earlier there is
2426 no point in doing additional checks. */
2427 if (!pvc
->result
&& !pvc
->details
)
2430 SecPolicyCheckFunction fcn
= (SecPolicyCheckFunction
)
2431 CFDictionaryGetValue(pvc
->callbacks
, key
);
2435 /* Why not to have optional policy checks rant:
2436 Not all keys are in all dictionaries anymore, so why not make checks
2437 optional? This way a client can ask for something and the server will
2438 do a best effort based on the supported flags. It works since they are
2439 synchronized now, but we need some debug checking here for now. */
2440 pvc
->result
= false;
2442 if (pvc
->callbacks
== gSecPolicyLeafCallbacks
) {
2443 if (!CFDictionaryContainsKey(gSecPolicyPathCallbacks
, key
)) {
2444 pvc
->result
= false;
2446 } else if (pvc
->callbacks
== gSecPolicyPathCallbacks
) {
2447 if (!CFDictionaryContainsKey(gSecPolicyLeafCallbacks
, key
)) {
2448 pvc
->result
= false;
2451 /* Non standard valdation phase, nothing is optional. */
2452 pvc
->result
= false;
2457 fcn(pvc
, (CFStringRef
)key
);
2460 /* AUDIT[securityd](done):
2461 policy->_options is a caller provided dictionary, only its cf type has
2464 bool SecPVCLeafChecks(SecPVCRef pvc
) {
2466 CFArrayRef policies
= pvc
->policies
;
2467 CFIndex ix
, count
= CFArrayGetCount(policies
);
2468 for (ix
= 0; ix
< count
; ++ix
) {
2469 SecPolicyRef policy
= (SecPolicyRef
)CFArrayGetValueAtIndex(policies
, ix
);
2471 /* Validate all keys for all policies. */
2472 pvc
->callbacks
= gSecPolicyLeafCallbacks
;
2473 CFDictionaryApplyFunction(policy
->_options
, SecPVCValidateKey
, pvc
);
2474 if (!pvc
->result
&& !pvc
->details
)
2481 bool SecPVCParentCertificateChecks(SecPVCRef pvc
, CFIndex ix
) {
2482 /* Check stuff common to intermediate and anchors. */
2483 CFAbsoluteTime verifyTime
= SecPVCGetVerifyTime(pvc
);
2484 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, ix
);
2485 bool is_anchor
= (ix
== SecPVCGetCertificateCount(pvc
) - 1
2486 && SecPVCIsAnchored(pvc
));
2487 if (!SecCertificateIsValid(cert
, verifyTime
)) {
2488 /* Certificate has expired. */
2489 if (!SecPVCSetResult(pvc
, is_anchor
? kSecPolicyCheckValidRoot
2490 : kSecPolicyCheckValidIntermediates
, ix
, kCFBooleanFalse
))
2495 /* Perform anchor specific checks. */
2496 /* Don't think we have any of these. */
2498 /* Perform intermediate specific checks. */
2501 const SecCEBasicConstraints
*bc
=
2502 SecCertificateGetBasicConstraints(cert
);
2503 if (!bc
|| !bc
->isCA
) {
2504 /* Basic constraints not present or not marked as isCA, illegal. */
2505 if (!SecPVCSetResultForced(pvc
, kSecPolicyCheckBasicContraints
,
2506 ix
, kCFBooleanFalse
, true))
2509 /* Consider adding (l) max_path_length checking here. */
2511 /* (n) If a key usage extension is present, verify that the keyCertSign bit is set. */
2512 SecKeyUsage keyUsage
= SecCertificateGetKeyUsage(cert
);
2513 if (keyUsage
&& !(keyUsage
& kSecKeyUsageKeyCertSign
)) {
2514 if (!SecPVCSetResultForced(pvc
, kSecPolicyCheckKeyUsage
,
2515 ix
, kCFBooleanFalse
, true))
2524 bool SecPVCBlackListedKeyChecks(SecPVCRef pvc
, CFIndex ix
) {
2525 /* Check stuff common to intermediate and anchors. */
2527 SecOTAPKIRef otapkiRef
= SecOTAPKICopyCurrentOTAPKIRef();
2528 if (NULL
!= otapkiRef
)
2530 CFSetRef blackListedKeys
= SecOTAPKICopyBlackListSet(otapkiRef
);
2531 CFRelease(otapkiRef
);
2532 if (NULL
!= blackListedKeys
)
2534 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, ix
);
2535 bool is_anchor
= (ix
== SecPVCGetCertificateCount(pvc
) - 1
2536 && SecPVCIsAnchored(pvc
));
2538 /* Check for blacklisted intermediates keys. */
2539 CFDataRef dgst
= SecCertificateCopyPublicKeySHA1Digest(cert
);
2541 /* Check dgst against blacklist. */
2542 if (CFSetContainsValue(blackListedKeys
, dgst
)) {
2543 SecPVCSetResultForced(pvc
, kSecPolicyCheckBlackListedKey
,
2544 ix
, kCFBooleanFalse
, true);
2549 CFRelease(blackListedKeys
);
2557 bool SecPVCGrayListedKeyChecks(SecPVCRef pvc
, CFIndex ix
)
2559 /* Check stuff common to intermediate and anchors. */
2560 SecOTAPKIRef otapkiRef
= SecOTAPKICopyCurrentOTAPKIRef();
2561 if (NULL
!= otapkiRef
)
2563 CFSetRef grayListKeys
= SecOTAPKICopyGrayList(otapkiRef
);
2564 CFRelease(otapkiRef
);
2565 if (NULL
!= grayListKeys
)
2567 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, ix
);
2568 bool is_anchor
= (ix
== SecPVCGetCertificateCount(pvc
) - 1
2569 && SecPVCIsAnchored(pvc
));
2571 /* Check for gray listed intermediates keys. */
2572 CFDataRef dgst
= SecCertificateCopyPublicKeySHA1Digest(cert
);
2574 /* Check dgst against gray list. */
2575 if (CFSetContainsValue(grayListKeys
, dgst
)) {
2576 SecPVCSetResultForced(pvc
, kSecPolicyCheckGrayListedKey
,
2577 ix
, kCFBooleanFalse
, true);
2582 CFRelease(grayListKeys
);
2590 /* AUDIT[securityd](done):
2591 policy->_options is a caller provided dictionary, only its cf type has
2594 bool SecPVCPathChecks(SecPVCRef pvc
) {
2595 secdebug("policy", "begin path: %@", pvc
->path
);
2596 bool completed
= true;
2597 /* This needs to be initialized before we call any function that might call
2598 SecPVCSetResultForced(). */
2600 SecPolicyCheckIdLinkage(pvc
, kSecPolicyCheckIdLinkage
);
2601 if (pvc
->result
|| pvc
->details
) {
2602 SecPolicyCheckBasicCertificateProcessing(pvc
,
2603 kSecPolicyCheckBasicCertificateProcessing
);
2606 CFArrayRef policies
= pvc
->policies
;
2607 CFIndex count
= CFArrayGetCount(policies
);
2608 for (; pvc
->policyIX
< count
; ++pvc
->policyIX
) {
2609 /* Validate all keys for all policies. */
2610 pvc
->callbacks
= gSecPolicyPathCallbacks
;
2611 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
2612 CFDictionaryApplyFunction(policy
->_options
, SecPVCValidateKey
, pvc
);
2613 if (!pvc
->result
&& !pvc
->details
)
2617 /* Check the things we can't check statically for the certificate path. */
2618 /* Critical Extensions, chainLength. */
2622 if ((pvc
->result
|| pvc
->details
) && pvc
->optionally_ev
) {
2623 bool pre_ev_check_result
= pvc
->result
;
2624 SecPolicyCheckEV(pvc
, kSecPolicyCheckExtendedValidation
);
2625 pvc
->is_ev
= pvc
->result
;
2626 /* If ev checking failed, we still want to accept this chain
2627 as a non EV one, if it was valid as such. */
2628 pvc
->result
= pre_ev_check_result
;
2630 /* Check revocation only if the chain is valid so far. Then only check
2631 revocation if the client asked for it explicitly or is_ev is
2633 if (pvc
->result
&& (pvc
->is_ev
|| pvc
->check_revocation
)) {
2634 completed
= SecPVCCheckRevocation(pvc
);
2638 secdebug("policy", "end %strusted completed: %d path: %@",
2639 (pvc
->result
? "" : "not "), completed
, pvc
->path
);
2643 /* This function returns 0 to indicate revocation checking was not completed
2644 for this certificate chain, otherwise return to date at which the first
2645 piece of revocation checking info we used expires. */
2646 CFAbsoluteTime
SecPVCGetEarliestNextUpdate(SecPVCRef pvc
) {
2647 CFIndex certIX
, certCount
= SecPVCGetCertificateCount(pvc
);
2648 CFAbsoluteTime enu
= 0;
2649 if (certCount
<= 1 || !pvc
->rvcs
) {
2654 for (certIX
= 0; certIX
< certCount
; ++certIX
) {
2655 SecRVCRef rvc
= &((SecRVCRef
)pvc
->rvcs
)[certIX
];
2656 if (rvc
->nextUpdate
== 0) {
2658 /* We allow for CA certs to not be revocation checked if they
2659 have no ocspResponders to check against, but the leaf
2660 must be checked in order for us to claim we did revocation
2662 SecCertificateRef cert
=
2663 SecPVCGetCertificateAtIndex(rvc
->pvc
, rvc
->certIX
);
2664 CFArrayRef ocspResponders
= SecCertificateGetOCSPResponders(cert
);
2665 if (!ocspResponders
|| CFArrayGetCount(ocspResponders
) == 0) {
2666 /* We can't check this cert so we don't consider it a soft
2667 failure that we didn't. Ideally we should support crl
2668 checking and remove this workaround, since that more
2673 secdebug("ocsp", "revocation checking soft failure for cert: %ld",
2675 enu
= rvc
->nextUpdate
;
2678 if (enu
== 0 || rvc
->nextUpdate
< enu
) {
2679 enu
= rvc
->nextUpdate
;
2682 /* Perhaps we don't want to do this since some policies might
2683 ignore the certificate experation but still use revocation
2686 /* Earliest certificate expiration date. */
2687 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(rvc
->pvc
, rvc
->certIX
);
2688 CFAbsoluteTime nva
= SecCertificateNotValidAfter(cert
);
2689 if (nva
&& (enu
== 0 || nva
< enu
)
2694 secdebug("ocsp", "revocation valid until: %lg", enu
);