2 * Copyright (c) 2008-2014 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");
120 CFReleaseSafe(evToPolicyAnchorDigest
);
125 static bool SecPolicyIsEVPolicy(const DERItem
*policyOID
) {
126 return SecPolicyAnchorDigestsForEVPolicy(policyOID
);
129 static bool SecPolicyRootCACertificateIsEV(SecCertificateRef certificate
,
130 policy_set_t valid_policies
) {
131 /* Ensure that this certificate is a valid anchor for one of the
132 certificate policy oids specified in the leaf. */
133 CFDataRef digest
= SecCertificateGetSHA1Digest(certificate
);
135 bool good_ev_anchor
= false;
136 for (ix
= valid_policies
; ix
; ix
= ix
->oid_next
) {
137 CFArrayRef digests
= SecPolicyAnchorDigestsForEVPolicy(&ix
->oid
);
138 if (digests
&& CFArrayContainsValue(digests
,
139 CFRangeMake(0, CFArrayGetCount(digests
)), digest
)) {
140 secdebug("ev", "found anchor for policy oid");
141 good_ev_anchor
= true;
145 require_quiet(good_ev_anchor
, notEV
);
147 CFAbsoluteTime october2006
= 178761600;
148 if (SecCertificateVersion(certificate
) >= 3
149 && SecCertificateNotValidBefore(certificate
) >= october2006
) {
150 const SecCEBasicConstraints
*bc
= SecCertificateGetBasicConstraints(certificate
);
151 require_quiet(bc
&& bc
->isCA
== true, notEV
);
152 SecKeyUsage ku
= SecCertificateGetKeyUsage(certificate
);
153 require_quiet((ku
& (kSecKeyUsageKeyCertSign
| kSecKeyUsageCRLSign
))
154 == (kSecKeyUsageKeyCertSign
| kSecKeyUsageCRLSign
), notEV
);
157 CFAbsoluteTime jan2011
= 315532800;
158 if (SecCertificateNotValidBefore(certificate
) < jan2011
) {
159 /* At least MD5, SHA-1 with RSA 2048 or ECC NIST P-256. */
161 /* At least SHA-1, SHA-256, SHA-384 or SHA-512 with RSA 2048 or
170 static bool SecPolicySubordinateCACertificateCouldBeEV(SecCertificateRef certificate
) {
171 const SecCECertificatePolicies
*cp
;
172 cp
= SecCertificateGetCertificatePolicies(certificate
);
173 require_quiet(cp
&& cp
->numPolicies
> 0, notEV
);
174 /* SecCertificateGetCRLDistributionPoints() is a noop right now */
176 CFArrayRef cdp
= SecCertificateGetCRLDistributionPoints(certificate
);
177 require_quiet(cdp
&& CFArrayGetCount(cdp
) > 0, notEV
);
179 const SecCEBasicConstraints
*bc
= SecCertificateGetBasicConstraints(certificate
);
180 require_quiet(bc
&& bc
->isCA
== true, notEV
);
181 SecKeyUsage ku
= SecCertificateGetKeyUsage(certificate
);
182 require_quiet((ku
& (kSecKeyUsageKeyCertSign
| kSecKeyUsageCRLSign
))
183 == (kSecKeyUsageKeyCertSign
| kSecKeyUsageCRLSign
), notEV
);
184 CFAbsoluteTime jan2011
= 315532800;
185 if (SecCertificateNotValidBefore(certificate
) < jan2011
) {
186 /* At least SHA-1 with RSA 1024 or ECC NIST P-256. */
188 /* At least SHA-1, SHA-256, SHA-284 or SHA-512 with RSA 2028 or
197 bool SecPolicySubscriberCertificateCouldBeEV(SecCertificateRef certificate
) {
198 /* 3. Subscriber Certificate. */
200 /* (a) certificate Policies */
201 const SecCECertificatePolicies
*cp
;
202 cp
= SecCertificateGetCertificatePolicies(certificate
);
203 require_quiet(cp
&& cp
->numPolicies
> 0, notEV
);
204 /* Now find at least one policy in here that has a qualifierID of id-qt 2
205 and a policyQualifier that is a URI to the CPS and an EV policy OID. */
207 bool found_ev_anchor_for_leaf_policy
= false;
208 for (ix
= 0; ix
< cp
->numPolicies
; ++ix
) {
209 if (SecPolicyIsEVPolicy(&cp
->policies
[ix
].policyIdentifier
)) {
210 found_ev_anchor_for_leaf_policy
= true;
213 require_quiet(found_ev_anchor_for_leaf_policy
, notEV
);
215 /* SecCertificateGetCRLDistributionPoints() is a noop right now */
217 /* (b) cRLDistributionPoint
218 (c) authorityInformationAccess */
219 CFArrayRef cdp
= SecCertificateGetCRLDistributionPoints(certificate
);
221 require_quiet(CFArrayGetCount(cdp
) > 0, notEV
);
223 CFArrayRef
or = SecCertificateGetOCSPResponders(certificate
);
224 require_quiet(or && CFArrayGetCount(or) > 0, notEV
);
225 //CFArrayRef ci = SecCertificateGetCAIssuers(certificate);
229 /* (d) basicConstraints
230 If present, the cA field MUST be set false. */
231 const SecCEBasicConstraints
*bc
= SecCertificateGetBasicConstraints(certificate
);
233 require_quiet(bc
->isCA
== false, notEV
);
237 SecKeyUsage ku
= SecCertificateGetKeyUsage(certificate
);
239 require_quiet((ku
& (kSecKeyUsageKeyCertSign
| kSecKeyUsageCRLSign
)) == 0, notEV
);
243 /* The EV Cert Spec errata specifies this, though this is a check for SSL
244 not specifically EV. */
248 Either the value id-kp-serverAuth [RFC5280] or id-kp-clientAuth [RFC5280] or both values MUST be present. Other values SHOULD NOT be present. */
249 SecCertificateCopyExtendedKeyUsage(certificate
);
252 CFAbsoluteTime jan2011
= 315532800;
253 if (SecCertificateNotValidAfter(certificate
) < jan2011
) {
254 /* At least SHA-1 with RSA 1024 or ECC NIST P-256. */
256 /* At least SHA-1, SHA-256, SHA-284 or SHA-512 with RSA 2028 or
265 /********************************************************
266 **************** SecPolicy Callbacks *******************
267 ********************************************************/
268 static void SecPolicyCheckCriticalExtensions(SecPVCRef pvc
,
272 static void SecPolicyCheckIdLinkage(SecPVCRef pvc
,
274 CFIndex ix
, count
= SecPVCGetCertificateCount(pvc
);
275 CFDataRef parentSubjectKeyID
= NULL
;
276 for (ix
= count
- 1; ix
>= 0; --ix
) {
277 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, ix
);
278 /* If the previous certificate in the chain had a SubjectKeyID,
279 make sure it matches the current certificates AuthorityKeyID. */
280 if (parentSubjectKeyID
) {
281 /* @@@ According to RFC 2459 neither AuthorityKeyID nor
282 SubjectKeyID can be critical. Currenty we don't check
284 CFDataRef authorityKeyID
= SecCertificateGetAuthorityKeyID(cert
);
285 if (authorityKeyID
) {
286 if (!CFEqual(parentSubjectKeyID
, authorityKeyID
)) {
287 /* AuthorityKeyID doesn't match issuers SubjectKeyID. */
288 if (!SecPVCSetResult(pvc
, key
, ix
, kCFBooleanFalse
))
294 parentSubjectKeyID
= SecCertificateGetSubjectKeyID(cert
);
298 static bool keyusage_allows(SecKeyUsage keyUsage
, CFTypeRef xku
) {
299 if (!xku
|| CFGetTypeID(xku
) != CFNumberGetTypeID())
303 CFNumberGetValue((CFNumberRef
)xku
, kCFNumberSInt32Type
, &dku
);
304 SecKeyUsage ku
= (SecKeyUsage
)dku
;
305 return (keyUsage
& ku
) == ku
;
308 static void SecPolicyCheckKeyUsage(SecPVCRef pvc
,
310 SecCertificateRef leaf
= SecPVCGetCertificateAtIndex(pvc
, 0);
311 SecKeyUsage keyUsage
= SecCertificateGetKeyUsage(leaf
);
313 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
314 CFTypeRef xku
= CFDictionaryGetValue(policy
->_options
, key
);
316 CFIndex ix
, count
= CFArrayGetCount(xku
);
317 for (ix
= 0; ix
< count
; ++ix
) {
318 CFTypeRef ku
= CFArrayGetValueAtIndex(xku
, ix
);
319 if (keyusage_allows(keyUsage
, ku
)) {
325 match
= keyusage_allows(keyUsage
, xku
);
328 SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
);
332 static bool extendedkeyusage_allows(CFArrayRef extendedKeyUsage
,
334 if (!xeku
|| CFGetTypeID(xeku
) != CFDataGetTypeID())
336 if (extendedKeyUsage
) {
337 CFRange all
= { 0, CFArrayGetCount(extendedKeyUsage
) };
338 return CFArrayContainsValue(extendedKeyUsage
, all
, xeku
);
340 /* Certificate has no extended key usage, only a match if the policy
341 contains a 0 length CFDataRef. */
342 return CFDataGetLength((CFDataRef
)xeku
) == 0;
346 /* AUDIT[securityd](done):
347 policy->_options is a caller provided dictionary, only its cf type has
350 static void SecPolicyCheckExtendedKeyUsage(SecPVCRef pvc
, CFStringRef key
) {
351 SecCertificateRef leaf
= SecPVCGetCertificateAtIndex(pvc
, 0);
352 CFArrayRef leafExtendedKeyUsage
= SecCertificateCopyExtendedKeyUsage(leaf
);
354 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
355 CFTypeRef xeku
= CFDictionaryGetValue(policy
->_options
, key
);
357 CFIndex ix
, count
= CFArrayGetCount(xeku
);
358 for (ix
= 0; ix
< count
; ix
++) {
359 CFTypeRef eku
= CFArrayGetValueAtIndex(xeku
, ix
);
360 if (extendedkeyusage_allows(leafExtendedKeyUsage
, eku
)) {
366 match
= extendedkeyusage_allows(leafExtendedKeyUsage
, xeku
);
368 CFReleaseSafe(leafExtendedKeyUsage
);
370 SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
);
375 static void SecPolicyCheckBasicContraintsCommon(SecPVCRef pvc
,
376 CFStringRef key
, bool strict
) {
377 CFIndex ix
, count
= SecPVCGetCertificateCount(pvc
);
378 for (ix
= 0; ix
< count
; ++ix
) {
379 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, ix
);
380 const SecCEBasicConstraints
*bc
=
381 SecCertificateGetBasicConstraints(cert
);
385 /* Leaf certificate has basic constraints extension. */
386 if (!SecPVCSetResult(pvc
, key
, ix
, kCFBooleanFalse
))
388 } else if (!bc
->critical
) {
389 /* Basic constraints extension is not marked critical. */
390 if (!SecPVCSetResult(pvc
, key
, ix
, kCFBooleanFalse
))
395 if (ix
> 0 || count
== 1) {
397 /* Non leaf certificate marked as isCA false. */
398 if (!SecPVCSetResult(pvc
, key
, ix
, kCFBooleanFalse
))
402 if (bc
->pathLenConstraintPresent
) {
403 if (bc
->pathLenConstraint
< (uint32_t)(ix
- 1)) {
405 /* @@@ If a self signed certificate is issued by
406 another cert that is trusted, then we are supposed
407 to treat the self signed cert itself as the anchor
408 for path length purposes. */
409 CFIndex ssix
= SecCertificatePathSelfSignedIndex(path
);
410 if (ssix
>= 0 && ix
>= ssix
) {
411 /* It's ok if the pathLenConstraint isn't met for
412 certificates signing a self signed cert in the
417 /* Path Length Constraint Exceeded. */
418 if (!SecPVCSetResult(pvc
, key
, ix
,
425 } else if (strict
&& ix
> 0) {
426 /* In strict mode all CA certificates *MUST* have a critical
427 basic constraints extension and the leaf certificate
428 *MUST NOT* have a basic constraints extension. */
429 /* CA certificate is missing basicConstraints extension. */
430 if (!SecPVCSetResult(pvc
, key
, ix
, kCFBooleanFalse
))
437 static void SecPolicyCheckBasicContraints(SecPVCRef pvc
,
439 //SecPolicyCheckBasicContraintsCommon(pvc, key, false);
442 static void SecPolicyCheckNonEmptySubject(SecPVCRef pvc
,
444 CFIndex ix
, count
= SecPVCGetCertificateCount(pvc
);
445 for (ix
= 0; ix
< count
; ++ix
) {
446 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, ix
);
447 /* If the certificate has a subject, or
448 if it doesn't, and it's the leaf and not self signed,
449 and also has a critical subjectAltName extension it's valid. */
450 if (!SecCertificateHasSubject(cert
)) {
451 if (ix
== 0 && count
> 1) {
452 if (!SecCertificateHasCriticalSubjectAltName(cert
)) {
453 /* Leaf certificate with empty subject does not have
454 a critical subject alt name extension. */
455 if (!SecPVCSetResult(pvc
, key
, ix
, kCFBooleanFalse
))
459 /* CA certificate has empty subject. */
460 if (!SecPVCSetResult(pvc
, key
, ix
, kCFBooleanFalse
))
467 static void SecPolicyCheckQualifiedCertStatements(SecPVCRef pvc
,
471 /* Compare hostname suffix to domain name.
472 This function does not process wildcards, and allows hostname to match
473 any subdomain level of the provided domain.
475 To match, the last domain length chars of hostname must equal domain,
476 and the character immediately preceding domain in hostname (if any)
477 must be a dot. This means that domain 'bar.com' will match hostname
478 values 'host.bar.com' or 'host.sub.bar.com', but not 'host.foobar.com'.
480 Characters in each string are converted to lowercase for the comparison.
481 Trailing '.' characters in both names will be ignored.
483 Returns true on match, else false.
485 static bool SecDomainSuffixMatch(CFStringRef hostname
, CFStringRef domain
) {
486 CFStringInlineBuffer hbuf
, dbuf
;
489 hlength
= CFStringGetLength(hostname
),
490 dlength
= CFStringGetLength(domain
);
491 CFRange hrange
= { 0, hlength
}, drange
= { 0, dlength
};
492 CFStringInitInlineBuffer(hostname
, &hbuf
, hrange
);
493 CFStringInitInlineBuffer(domain
, &dbuf
, drange
);
495 if((hlength
== 0) || (dlength
== 0)) {
496 /* trivial case with at least one empty name */
497 return (hlength
== dlength
) ? true : false;
500 /* trim off trailing dots */
501 hch
= CFStringGetCharacterFromInlineBuffer(&hbuf
, hlength
-1);
502 dch
= CFStringGetCharacterFromInlineBuffer(&dbuf
, dlength
-1);
504 hrange
.length
= --hlength
;
507 drange
.length
= --dlength
;
510 /* trim off leading dot in suffix, if present */
511 dch
= CFStringGetCharacterFromInlineBuffer(&dbuf
, 0);
512 if((dlength
> 0) && (dch
== '.')) {
514 drange
.length
= --dlength
;
517 if(hlength
< dlength
) {
521 /* perform case-insensitive comparison of domain suffix */
522 for (hix
= (hlength
-dlength
),
523 dix
= drange
.location
; dix
< drange
.length
; dix
++) {
524 hch
= CFStringGetCharacterFromInlineBuffer(&hbuf
, hix
);
525 dch
= CFStringGetCharacterFromInlineBuffer(&dbuf
, dix
);
526 if (towlower(hch
) != towlower(dch
)) {
531 /* require a dot prior to domain suffix, unless hostname == domain */
532 if(hlength
> dlength
) {
533 hch
= CFStringGetCharacterFromInlineBuffer(&hbuf
, (hlength
-(dlength
+1)));
542 /* Compare hostname, to a server name obtained from the server's cert
543 Obtained from the SubjectAltName or the CommonName entry in the Subject.
544 Limited wildcard checking is performed here as outlined in
546 RFC 2818 Section 3.1. Server Identity
548 [...] Names may contain the wildcard
549 character * which is considered to match any single domain name
550 component or component fragment. E.g., *.a.com matches foo.a.com but
551 not bar.foo.a.com. f*.com matches foo.com but not bar.com.
554 Trailing '.' characters in the hostname will be ignored.
556 Returns true on match, else false.
558 static bool SecDNSMatch(CFStringRef hostname
, CFStringRef servername
) {
559 CFStringInlineBuffer hbuf
, sbuf
;
561 hlength
= CFStringGetLength(hostname
),
562 slength
= CFStringGetLength(servername
);
563 CFRange hrange
= { 0, hlength
}, srange
= { 0, slength
};
564 CFStringInitInlineBuffer(hostname
, &hbuf
, hrange
);
565 CFStringInitInlineBuffer(servername
, &sbuf
, srange
);
567 for (hix
= six
= 0; six
< slength
; ++six
) {
568 UniChar hch
, sch
= CFStringGetCharacterFromInlineBuffer(&sbuf
, six
);
570 if (six
+ 1 >= slength
) {
571 /* Trailing '*' in servername, match until end of hostname or
574 if (hix
>= hlength
) {
575 /* If we reach the end of the hostname we have a
579 hch
= CFStringGetCharacterFromInlineBuffer(&hbuf
, hix
++);
580 } while (hch
!= '.');
581 /* We reached the end of servername and found a '.' in
582 hostname. Return true if hostname has a single
583 trailing '.' return false if there is anything after it. */
584 return hix
== hlength
;
587 /* Grab the character after the '*'. */
588 sch
= CFStringGetCharacterFromInlineBuffer(&sbuf
, ++six
);
590 /* We have something of the form '*foo.com'. Or '**.com'
591 We don't deal with that yet, since it might require
592 backtracking. Also RFC 2818 doesn't seem to require it. */
596 /* We're looking at the '.' after the '*' in something of the
597 form 'foo*.com' or '*.com'. Match until next '.' in hostname. */
599 /* Since we're not at the end of servername yet (that case
600 was handled above), running out of chars in hostname
601 means we don't have a match. */
604 hch
= CFStringGetCharacterFromInlineBuffer(&hbuf
, hix
++);
605 } while (hch
!= '.');
607 /* We're looking at a non wildcard character in the servername.
608 If we reached the end of hostname it's not a match. */
612 /* Otherwise make sure the hostname matches the character in the
613 servername, case insensitively. */
614 hch
= CFStringGetCharacterFromInlineBuffer(&hbuf
, hix
++);
615 if (towlower(hch
) != towlower(sch
))
621 /* We reached the end of servername but we have one or more characters
622 left to compare against in the hostname. */
623 if (hix
+ 1 == hlength
&&
624 CFStringGetCharacterFromInlineBuffer(&hbuf
, hix
) == '.') {
625 /* Hostname has a single trailing '.', we're ok with that. */
628 /* Anything else is not a match. */
635 #define kSecPolicySHA1Size 20
636 static const UInt8 kAppleCorpCASHA1
[kSecPolicySHA1Size
] = {
637 0xA1, 0x71, 0xDC, 0xDE, 0xE0, 0x8B, 0x1B, 0xAE, 0x30, 0xA1,
638 0xAE, 0x6C, 0xC6, 0xD4, 0x03, 0x3B, 0xFD, 0xEF, 0x91, 0xCE
641 /* Check whether hostname is in a particular set of allowed domains.
642 Returns true if OK, false if not allowed.
644 static bool SecPolicyCheckDomain(SecPVCRef pvc
, CFStringRef hostname
)
646 CFIndex count
= SecPVCGetCertificateCount(pvc
);
647 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, count
- 1);
648 CFDataRef anchorSHA1
= SecCertificateGetSHA1Digest(cert
);
650 /* is this chain anchored by kAppleCorpCASHA1? */
651 CFDataRef corpSHA1
= CFDataCreateWithBytesNoCopy(NULL
,
652 kAppleCorpCASHA1
, kSecPolicySHA1Size
, kCFAllocatorNull
);
653 bool isCorpSHA1
= (corpSHA1
&& CFEqual(anchorSHA1
, corpSHA1
));
654 CFReleaseSafe(corpSHA1
);
656 /* limit hostname to specified domains */
657 const CFStringRef dnlist
[] = {
661 unsigned int idx
, dncount
=2;
662 for (idx
= 0; idx
< dncount
; idx
++) {
663 if (SecDomainSuffixMatch(hostname
, dnlist
[idx
])) {
669 /* %%% other CA pinning checks TBA */
674 /* AUDIT[securityd](done):
675 policy->_options is a caller provided dictionary, only its cf type has
678 static void SecPolicyCheckSSLHostname(SecPVCRef pvc
,
680 /* @@@ Consider what to do if the caller passes in no hostname. Should
681 we then still fail if the leaf has no dnsNames or IPAddresses at all? */
682 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
683 CFStringRef hostName
= (CFStringRef
)
684 CFDictionaryGetValue(policy
->_options
, key
);
685 if (!isString(hostName
)) {
686 /* @@@ We can't return an error here and making the evaluation fail
687 won't help much either. */
691 SecCertificateRef leaf
= SecPVCGetCertificateAtIndex(pvc
, 0);
692 bool dnsMatch
= false;
693 CFArrayRef dnsNames
= SecCertificateCopyDNSNames(leaf
);
695 CFIndex ix
, count
= CFArrayGetCount(dnsNames
);
696 for (ix
= 0; ix
< count
; ++ix
) {
697 CFStringRef dns
= (CFStringRef
)CFArrayGetValueAtIndex(dnsNames
, ix
);
698 if (SecDNSMatch(hostName
, dns
)) {
707 /* Maybe hostname is an IPv4 or IPv6 address, let's compare against
708 the values returned by SecCertificateCopyIPAddresses() instead. */
709 CFArrayRef ipAddresses
= SecCertificateCopyIPAddresses(leaf
);
711 CFIndex ix
, count
= CFArrayGetCount(ipAddresses
);
712 for (ix
= 0; ix
< count
; ++ix
) {
713 CFStringRef ipAddress
= (CFStringRef
)CFArrayGetValueAtIndex(ipAddresses
, ix
);
714 if (!CFStringCompare(hostName
, ipAddress
, kCFCompareCaseInsensitive
)) {
719 CFRelease(ipAddresses
);
724 /* Hostname mismatch or no hostnames found in certificate. */
725 SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
);
727 else if (!SecPolicyCheckDomain(pvc
, hostName
)) {
728 /* Hostname match, but domain not allowed for this CA */
729 SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
);
732 if ((dnsMatch
|| pvc
->details
)
733 && SecPolicySubscriberCertificateCouldBeEV(leaf
)) {
734 secdebug("policy", "enabling optionally_ev");
735 pvc
->optionally_ev
= true;
736 /* optionally_ev => check_revocation, so we don't enable revocation
737 checking here, since we don't want it on for non EV ssl certs. */
739 /* Check revocation status if the certificate asks for it (and we
740 support it) currently we only support ocsp. */
741 CFArrayRef ocspResponders
= SecCertificateGetOCSPResponders(leaf
);
742 if (ocspResponders
) {
743 SecPVCSetCheckRevocation(pvc
);
749 /* AUDIT[securityd](done):
750 policy->_options is a caller provided dictionary, only its cf type has
753 static void SecPolicyCheckEmail(SecPVCRef pvc
, CFStringRef key
) {
754 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
755 CFStringRef email
= (CFStringRef
)CFDictionaryGetValue(policy
->_options
, key
);
757 if (!isString(email
)) {
758 /* We can't return an error here and making the evaluation fail
759 won't help much either. */
763 SecCertificateRef leaf
= SecPVCGetCertificateAtIndex(pvc
, 0);
764 CFArrayRef addrs
= SecCertificateCopyRFC822Names(leaf
);
766 CFIndex ix
, count
= CFArrayGetCount(addrs
);
767 for (ix
= 0; ix
< count
; ++ix
) {
768 CFStringRef addr
= (CFStringRef
)CFArrayGetValueAtIndex(addrs
, ix
);
769 if (!CFStringCompare(email
, addr
, kCFCompareCaseInsensitive
)) {
778 /* Hostname mismatch or no hostnames found in certificate. */
779 SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
);
783 static void SecPolicyCheckValidIntermediates(SecPVCRef pvc
,
785 CFIndex ix
, count
= SecPVCGetCertificateCount(pvc
);
786 CFAbsoluteTime verifyTime
= SecPVCGetVerifyTime(pvc
);
787 for (ix
= 1; ix
< count
- 1; ++ix
) {
788 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, ix
);
789 if (!SecCertificateIsValid(cert
, verifyTime
)) {
790 /* Intermediate certificate has expired. */
791 if (!SecPVCSetResult(pvc
, key
, ix
, kCFBooleanFalse
))
797 static void SecPolicyCheckValidLeaf(SecPVCRef pvc
,
799 CFAbsoluteTime verifyTime
= SecPVCGetVerifyTime(pvc
);
800 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, 0);
801 if (!SecCertificateIsValid(cert
, verifyTime
)) {
802 /* Leaf certificate has expired. */
803 if (!SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
))
808 static void SecPolicyCheckValidRoot(SecPVCRef pvc
,
810 CFIndex ix
, count
= SecPVCGetCertificateCount(pvc
);
811 CFAbsoluteTime verifyTime
= SecPVCGetVerifyTime(pvc
);
813 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, ix
);
814 if (!SecCertificateIsValid(cert
, verifyTime
)) {
815 /* Root certificate has expired. */
816 if (!SecPVCSetResult(pvc
, key
, ix
, kCFBooleanFalse
))
821 /* AUDIT[securityd](done):
822 policy->_options is a caller provided dictionary, only its cf type has
825 static void SecPolicyCheckIssuerCommonName(SecPVCRef pvc
,
827 CFIndex count
= SecPVCGetCertificateCount(pvc
);
829 /* Can't check intermediates common name if there is no intermediate. */
830 SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
);
834 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, 1);
835 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
836 CFStringRef commonName
=
837 (CFStringRef
)CFDictionaryGetValue(policy
->_options
, key
);
838 if (!isString(commonName
)) {
839 /* @@@ We can't return an error here and making the evaluation fail
840 won't help much either. */
843 CFArrayRef commonNames
= SecCertificateCopyCommonNames(cert
);
844 if (!commonNames
|| CFArrayGetCount(commonNames
) != 1 ||
845 !CFEqual(commonName
, CFArrayGetValueAtIndex(commonNames
, 0))) {
846 /* Common Name mismatch. */
847 SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
);
849 CFReleaseSafe(commonNames
);
852 /* AUDIT[securityd](done):
853 policy->_options is a caller provided dictionary, only its cf type has
856 static void SecPolicyCheckSubjectCommonName(SecPVCRef pvc
,
858 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, 0);
859 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
860 CFStringRef common_name
= (CFStringRef
)CFDictionaryGetValue(policy
->_options
,
862 if (!isString(common_name
)) {
863 /* @@@ We can't return an error here and making the evaluation fail
864 won't help much either. */
867 CFArrayRef commonNames
= SecCertificateCopyCommonNames(cert
);
868 if (!commonNames
|| CFArrayGetCount(commonNames
) != 1 ||
869 !CFEqual(common_name
, CFArrayGetValueAtIndex(commonNames
, 0))) {
870 /* Common Name mismatch. */
871 SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
);
873 CFReleaseSafe(commonNames
);
876 /* AUDIT[securityd](done):
877 policy->_options is a caller provided dictionary, only its cf type has
880 static void SecPolicyCheckSubjectCommonNamePrefix(SecPVCRef pvc
,
882 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, 0);
883 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
884 CFStringRef prefix
= (CFStringRef
)CFDictionaryGetValue(policy
->_options
,
886 if (!isString(prefix
)) {
887 /* @@@ We can't return an error here and making the evaluation fail
888 won't help much either. */
891 CFArrayRef commonNames
= SecCertificateCopyCommonNames(cert
);
892 if (!commonNames
|| CFArrayGetCount(commonNames
) != 1 ||
893 !CFStringHasPrefix(CFArrayGetValueAtIndex(commonNames
, 0), prefix
)) {
894 /* Common Name prefix mismatch. */
895 SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
);
897 CFReleaseSafe(commonNames
);
900 /* AUDIT[securityd](done):
901 policy->_options is a caller provided dictionary, only its cf type has
904 static void SecPolicyCheckSubjectCommonNameTEST(SecPVCRef pvc
,
906 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, 0);
907 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
908 CFStringRef common_name
= (CFStringRef
)CFDictionaryGetValue(policy
->_options
,
910 if (!isString(common_name
)) {
911 /* @@@ We can't return an error here and making the evaluation fail
912 won't help much either. */
915 CFArrayRef commonNames
= SecCertificateCopyCommonNames(cert
);
916 if (!commonNames
|| CFArrayGetCount(commonNames
) != 1) {
917 CFStringRef cert_common_name
= CFArrayGetValueAtIndex(commonNames
, 0);
918 CFStringRef test_common_name
= common_name
?
919 CFStringCreateWithFormat(kCFAllocatorDefault
,
920 NULL
, CFSTR("TEST %@ TEST"), common_name
) :
922 if (!CFEqual(common_name
, cert_common_name
) &&
923 (!test_common_name
|| !CFEqual(test_common_name
, cert_common_name
)))
924 /* Common Name mismatch. */
925 SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
);
926 CFReleaseSafe(test_common_name
);
928 CFReleaseSafe(commonNames
);
931 /* AUDIT[securityd](done):
932 policy->_options is a caller provided dictionary, only its cf type has
935 static void SecPolicyCheckNotValidBefore(SecPVCRef pvc
,
937 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, 0);
938 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
939 CFDateRef date
= (CFDateRef
)CFDictionaryGetValue(policy
->_options
, key
);
941 /* @@@ We can't return an error here and making the evaluation fail
942 won't help much either. */
945 CFAbsoluteTime at
= CFDateGetAbsoluteTime(date
);
946 if (SecCertificateNotValidBefore(cert
) <= at
) {
947 /* Leaf certificate has not valid before that is too old. */
948 if (!SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
))
953 /* AUDIT[securityd](done):
954 policy->_options is a caller provided dictionary, only its cf type has
957 static void SecPolicyCheckChainLength(SecPVCRef pvc
,
959 CFIndex count
= SecPVCGetCertificateCount(pvc
);
960 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
961 CFNumberRef chainLength
=
962 (CFNumberRef
)CFDictionaryGetValue(policy
->_options
, key
);
964 if (!chainLength
|| CFGetTypeID(chainLength
) != CFNumberGetTypeID() ||
965 !CFNumberGetValue(chainLength
, kCFNumberCFIndexType
, &value
)) {
966 /* @@@ We can't return an error here and making the evaluation fail
967 won't help much either. */
970 if (value
!= count
) {
971 /* Chain length doesn't match policy requirement. */
972 if (!SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
))
977 /* AUDIT[securityd](done):
978 policy->_options is a caller provided dictionary, only its cf type has
981 static void SecPolicyCheckAnchorSHA1(SecPVCRef pvc
,
983 CFIndex count
= SecPVCGetCertificateCount(pvc
);
984 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, count
- 1);
985 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
986 CFTypeRef value
= CFDictionaryGetValue(policy
->_options
, key
);
987 CFDataRef anchorSHA1
= SecCertificateGetSHA1Digest(cert
);
989 bool foundMatch
= false;
992 foundMatch
= CFEqual(anchorSHA1
, value
);
993 else if (isArray(value
))
994 foundMatch
= CFArrayContainsValue((CFArrayRef
) value
, CFRangeMake(0, CFArrayGetCount((CFArrayRef
) value
)), anchorSHA1
);
996 /* @@@ We only support Data and Array but we can't return an error here so.
997 we let the evaluation fail (not much help) and assert in debug. */
1002 if (!SecPVCSetResult(pvc
, kSecPolicyCheckAnchorSHA1
, 0, kCFBooleanFalse
))
1008 /* AUDIT[securityd](done):
1009 policy->_options is a caller provided dictionary, only its cf type has
1012 static void SecPolicyCheckSubjectOrganization(SecPVCRef pvc
,
1014 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, 0);
1015 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
1016 CFStringRef org
= (CFStringRef
)CFDictionaryGetValue(policy
->_options
,
1018 if (!isString(org
)) {
1019 /* @@@ We can't return an error here and making the evaluation fail
1020 won't help much either. */
1023 CFArrayRef organization
= SecCertificateCopyOrganization(cert
);
1024 if (!organization
|| CFArrayGetCount(organization
) != 1 ||
1025 !CFEqual(org
, CFArrayGetValueAtIndex(organization
, 0))) {
1026 /* Leaf Subject Organization mismatch. */
1027 SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
);
1029 CFReleaseSafe(organization
);
1032 static void SecPolicyCheckSubjectOrganizationalUnit(SecPVCRef pvc
,
1034 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, 0);
1035 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
1036 CFStringRef orgUnit
= (CFStringRef
)CFDictionaryGetValue(policy
->_options
,
1038 if (!isString(orgUnit
)) {
1039 /* @@@ We can't return an error here and making the evaluation fail
1040 won't help much either. */
1043 CFArrayRef organizationalUnit
= SecCertificateCopyOrganizationalUnit(cert
);
1044 if (!organizationalUnit
|| CFArrayGetCount(organizationalUnit
) != 1 ||
1045 !CFEqual(orgUnit
, CFArrayGetValueAtIndex(organizationalUnit
, 0))) {
1046 /* Leaf Subject Organizational Unit mismatch. */
1047 SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
);
1049 CFReleaseSafe(organizationalUnit
);
1052 /* AUDIT[securityd](done):
1053 policy->_options is a caller provided dictionary, only its cf type has
1056 static void SecPolicyCheckEAPTrustedServerNames(SecPVCRef pvc
,
1058 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
1059 CFArrayRef trustedServerNames
= (CFArrayRef
)
1060 CFDictionaryGetValue(policy
->_options
, key
);
1061 /* No names specified means we accept any name. */
1062 if (!trustedServerNames
)
1064 if (!isArray(trustedServerNames
)) {
1065 /* @@@ We can't return an error here and making the evaluation fail
1066 won't help much either. */
1070 CFIndex tsnCount
= CFArrayGetCount(trustedServerNames
);
1071 SecCertificateRef leaf
= SecPVCGetCertificateAtIndex(pvc
, 0);
1072 bool dnsMatch
= false;
1073 CFArrayRef dnsNames
= SecCertificateCopyDNSNames(leaf
);
1075 CFIndex ix
, count
= CFArrayGetCount(dnsNames
);
1076 // @@@ This is O(N^2) unfortunately we can't do better easily unless
1077 // we don't do wildcard matching. */
1078 for (ix
= 0; !dnsMatch
&& ix
< count
; ++ix
) {
1079 CFStringRef dns
= (CFStringRef
)CFArrayGetValueAtIndex(dnsNames
, ix
);
1081 for (tix
= 0; tix
< tsnCount
; ++tix
) {
1082 CFStringRef serverName
=
1083 (CFStringRef
)CFArrayGetValueAtIndex(trustedServerNames
, tix
);
1084 if (!isString(serverName
)) {
1085 /* @@@ We can't return an error here and making the
1086 evaluation fail won't help much either. */
1087 CFReleaseSafe(dnsNames
);
1090 /* we purposefully reverse the arguments here such that dns names
1091 from the cert are matched against a server name list, where
1092 the server names list can contain wildcards and the dns name
1093 cannot. References: http://support.microsoft.com/kb/941123
1094 It's easy to find occurrences where people tried to use
1095 wildcard certificates and were told that those don't work
1097 if (SecDNSMatch(dns
, serverName
)) {
1103 CFRelease(dnsNames
);
1107 /* Hostname mismatch or no hostnames found in certificate. */
1108 SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
);
1112 static const unsigned char UTN_USERFirst_Hardware_Serial
[][16] = {
1113 { 0xd8, 0xf3, 0x5f, 0x4e, 0xb7, 0x87, 0x2b, 0x2d, 0xab, 0x06, 0x92, 0xe3, 0x15, 0x38, 0x2f, 0xb0 },
1114 { 0x92, 0x39, 0xd5, 0x34, 0x8f, 0x40, 0xd1, 0x69, 0x5a, 0x74, 0x54, 0x70, 0xe1, 0xf2, 0x3f, 0x43 },
1115 { 0xb0, 0xb7, 0x13, 0x3e, 0xd0, 0x96, 0xf9, 0xb5, 0x6f, 0xae, 0x91, 0xc8, 0x74, 0xbd, 0x3a, 0xc0 },
1116 { 0xe9, 0x02, 0x8b, 0x95, 0x78, 0xe4, 0x15, 0xdc, 0x1a, 0x71, 0x0a, 0x2b, 0x88, 0x15, 0x44, 0x47 },
1117 { 0x39, 0x2a, 0x43, 0x4f, 0x0e, 0x07, 0xdf, 0x1f, 0x8a, 0xa3, 0x05, 0xde, 0x34, 0xe0, 0xc2, 0x29 },
1118 { 0x3e, 0x75, 0xce, 0xd4, 0x6b, 0x69, 0x30, 0x21, 0x21, 0x88, 0x30, 0xae, 0x86, 0xa8, 0x2a, 0x71 },
1119 { 0xd7, 0x55, 0x8f, 0xda, 0xf5, 0xf1, 0x10, 0x5b, 0xb2, 0x13, 0x28, 0x2b, 0x70, 0x77, 0x29, 0xa3 },
1120 { 0x04, 0x7e, 0xcb, 0xe9, 0xfc, 0xa5, 0x5f, 0x7b, 0xd0, 0x9e, 0xae, 0x36, 0xe1, 0x0c, 0xae, 0x1e },
1121 { 0xf5, 0xc8, 0x6a, 0xf3, 0x61, 0x62, 0xf1, 0x3a, 0x64, 0xf5, 0x4f, 0x6d, 0xc9, 0x58, 0x7c, 0x06 } };
1123 static const unsigned char UTN_USERFirst_Hardware_Normalized_Issuer
[] = {
1124 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55,
1125 0x53, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x02,
1126 0x55, 0x54, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x07, 0x13,
1127 0x0e, 0x53, 0x41, 0x4c, 0x54, 0x20, 0x4c, 0x41, 0x4b, 0x45, 0x20, 0x43,
1128 0x49, 0x54, 0x59, 0x31, 0x1e, 0x30, 0x1c, 0x06, 0x03, 0x55, 0x04, 0x0a,
1129 0x13, 0x15, 0x54, 0x48, 0x45, 0x20, 0x55, 0x53, 0x45, 0x52, 0x54, 0x52,
1130 0x55, 0x53, 0x54, 0x20, 0x4e, 0x45, 0x54, 0x57, 0x4f, 0x52, 0x4b, 0x31,
1131 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x18, 0x48, 0x54,
1132 0x54, 0x50, 0x3a, 0x2f, 0x2f, 0x57, 0x57, 0x57, 0x2e, 0x55, 0x53, 0x45,
1133 0x52, 0x54, 0x52, 0x55, 0x53, 0x54, 0x2e, 0x43, 0x4f, 0x4d, 0x31, 0x1f,
1134 0x30, 0x1d, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x16, 0x55, 0x54, 0x4e,
1135 0x2d, 0x55, 0x53, 0x45, 0x52, 0x46, 0x49, 0x52, 0x53, 0x54, 0x2d, 0x48,
1136 0x41, 0x52, 0x44, 0x57, 0x41, 0x52, 0x45
1138 static const unsigned int UTN_USERFirst_Hardware_Normalized_Issuer_len
= 151;
1141 static void SecPolicyCheckBlackListedLeaf(SecPVCRef pvc
,
1143 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, 0);
1144 CFDataRef issuer
= cert
? SecCertificateGetNormalizedIssuerContent(cert
) : NULL
;
1146 if (issuer
&& (CFDataGetLength(issuer
) == (CFIndex
)UTN_USERFirst_Hardware_Normalized_Issuer_len
) &&
1147 (0 == memcmp(UTN_USERFirst_Hardware_Normalized_Issuer
, CFDataGetBytePtr(issuer
),
1148 UTN_USERFirst_Hardware_Normalized_Issuer_len
)))
1150 CFDataRef serial
= SecCertificateCopySerialNumber(cert
);
1152 CFIndex serial_length
= CFDataGetLength(serial
);
1153 const uint8_t *serial_ptr
= CFDataGetBytePtr(serial
);
1155 while ((serial_length
> 0) && (*serial_ptr
== 0)) {
1160 if (serial_length
== (CFIndex
)sizeof(*UTN_USERFirst_Hardware_Serial
)) {
1162 for (i
= 0; i
< array_size(UTN_USERFirst_Hardware_Serial
); i
++)
1164 if (0 == memcmp(UTN_USERFirst_Hardware_Serial
[i
],
1165 serial_ptr
, sizeof(*UTN_USERFirst_Hardware_Serial
)))
1167 SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
);
1168 CFReleaseSafe(serial
);
1177 SecOTAPKIRef otapkiRef
= SecOTAPKICopyCurrentOTAPKIRef();
1178 if (NULL
!= otapkiRef
)
1180 CFSetRef blackListedKeys
= SecOTAPKICopyBlackListSet(otapkiRef
);
1181 CFRelease(otapkiRef
);
1182 if (NULL
!= blackListedKeys
)
1184 /* Check for blacklisted intermediates keys. */
1185 CFDataRef dgst
= SecCertificateCopyPublicKeySHA1Digest(cert
);
1188 /* Check dgst against blacklist. */
1189 if (CFSetContainsValue(blackListedKeys
, dgst
))
1191 SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
);
1195 CFRelease(blackListedKeys
);
1200 static void SecPolicyCheckGrayListedLeaf(SecPVCRef pvc
, CFStringRef key
)
1202 SecOTAPKIRef otapkiRef
= SecOTAPKICopyCurrentOTAPKIRef();
1203 if (NULL
!= otapkiRef
)
1205 CFSetRef grayListedKeys
= SecOTAPKICopyGrayList(otapkiRef
);
1206 CFRelease(otapkiRef
);
1207 if (NULL
!= grayListedKeys
)
1209 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, 0);
1211 CFDataRef dgst
= SecCertificateCopyPublicKeySHA1Digest(cert
);
1214 /* Check dgst against gray. */
1215 if (CFSetContainsValue(grayListedKeys
, dgst
))
1217 SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
);
1221 CFRelease(grayListedKeys
);
1226 static void SecPolicyCheckLeafMarkerOid(SecPVCRef pvc
, CFStringRef key
)
1228 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, 0);
1229 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
1230 CFTypeRef value
= CFDictionaryGetValue(policy
->_options
, key
);
1232 if (value
&& SecCertificateHasMarkerExtension(cert
, value
))
1235 SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
);
1238 static void SecPolicyCheckIntermediateMarkerOid(SecPVCRef pvc
, CFStringRef key
)
1240 CFIndex ix
, count
= SecPVCGetCertificateCount(pvc
);
1241 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
1242 CFTypeRef value
= CFDictionaryGetValue(policy
->_options
, key
);
1244 for (ix
= 1; ix
< count
- 1; ix
++) {
1245 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, ix
);
1246 if (SecCertificateHasMarkerExtension(cert
, value
))
1249 SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
);
1254 /****************************************************************************
1255 *********************** New rfc5280 Chain Validation ***********************
1256 ****************************************************************************/
1259 typedef struct cert_path
*cert_path_t
;
1264 typedef struct x500_name
*x500_name_t
;
1268 typedef struct algorithm_id
*algorithm_id_t
;
1269 struct algorithm_id
{
1270 oid_t algorithm_oid
;
1274 typedef struct trust_anchor
*trust_anchor_t
;
1275 struct trust_anchor
{
1276 x500_name_t issuer_name
;
1277 algorithm_id_t public_key_algorithm
; /* includes optional params */
1278 SecKeyRef public_key
;
1281 typedef struct certificate_policy
*certificate_policy_t
;
1282 struct certificate_policy
{
1283 policy_qualifier_t qualifiers
;
1285 SLIST_ENTRY(certificate_policy
) policies
;
1288 typedef struct policy_mapping
*policy_mapping_t
;
1289 struct policy_mapping
{
1290 SLIST_ENTRY(policy_mapping
) mappings
;
1291 oid_t issuer_domain_policy
;
1292 oid_t subject_domain_policy
;
1295 typedef struct root_name
*root_name_t
;
1300 struct policy_tree_add_ctx
{
1302 policy_qualifier_t p_q
;
1305 /* 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}. */
1306 static bool policy_tree_add_if_match(policy_tree_t node
, void *ctx
) {
1307 struct policy_tree_add_ctx
*info
= (struct policy_tree_add_ctx
*)ctx
;
1308 policy_set_t policy_set
;
1309 for (policy_set
= node
->expected_policy_set
;
1311 policy_set
= policy_set
->oid_next
) {
1312 if (oid_equal(policy_set
->oid
, info
->p_oid
)) {
1313 policy_tree_add_child(node
, &info
->p_oid
, info
->p_q
);
1320 /* 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}. */
1321 static bool policy_tree_add_if_any(policy_tree_t node
, void *ctx
) {
1322 struct policy_tree_add_ctx
*info
= (struct policy_tree_add_ctx
*)ctx
;
1323 if (oid_equal(node
->valid_policy
, oidAnyPolicy
)) {
1324 policy_tree_add_child(node
, &info
->p_oid
, info
->p_q
);
1330 /* Return true iff node has a child with a valid_policy equal to oid. */
1331 static bool policy_tree_has_child_with_oid(policy_tree_t node
,
1333 policy_tree_t child
;
1334 for (child
= node
->children
; child
; child
= child
->siblings
) {
1335 if (oid_equal(child
->valid_policy
, (*oid
))) {
1342 /* 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. */
1343 static bool policy_tree_add_expected(policy_tree_t node
, void *ctx
) {
1344 policy_qualifier_t p_q
= (policy_qualifier_t
)ctx
;
1345 policy_set_t policy_set
;
1346 bool added_node
= false;
1347 for (policy_set
= node
->expected_policy_set
;
1349 policy_set
= policy_set
->oid_next
) {
1350 if (!policy_tree_has_child_with_oid(node
, &policy_set
->oid
)) {
1351 policy_tree_add_child(node
, &policy_set
->oid
, p_q
);
1359 /* 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. */
1360 static bool policy_tree_map(policy_tree_t node
, void *ctx
) {
1361 /* Can't map oidAnyPolicy. */
1362 if (oid_equal(node
->valid_policy
, oidAnyPolicy
))
1365 const SecCEPolicyMappings
*pm
= (const SecCEPolicyMappings
*)ctx
;
1366 uint32_t mapping_ix
, mapping_count
= pm
->numMappings
;
1367 policy_set_t policy_set
= NULL
;
1368 /* First count how many mappings match this nodes valid_policy. */
1369 for (mapping_ix
= 0; mapping_ix
< mapping_count
; ++mapping_ix
) {
1370 const SecCEPolicyMapping
*mapping
= &pm
->mappings
[mapping_ix
];
1371 if (oid_equal(node
->valid_policy
, mapping
->issuerDomainPolicy
)) {
1372 policy_set_t p_node
= (policy_set_t
)malloc(sizeof(*policy_set
));
1373 p_node
->oid
= mapping
->subjectDomainPolicy
;
1374 p_node
->oid_next
= policy_set
? policy_set
: NULL
;
1375 policy_set
= p_node
;
1379 policy_tree_set_expected_policy(node
, policy_set
);
1386 #define POLICY_MAPPING 0
1387 #define POLICY_SUBTREES 0
1389 /* rfc5280 basic cert processing. */
1390 static void SecPolicyCheckBasicCertificateProcessing(SecPVCRef pvc
,
1394 CFIndex count
= SecPVCGetCertificateCount(pvc
);
1395 /* 64 bits cast: worst case here is we truncate the number of cert, and the validation may fail */
1396 assert((unsigned long)count
<=UINT32_MAX
); /* Debug check. Correct as long as CFIndex is long */
1397 uint32_t n
= (uint32_t)count
;
1398 bool is_anchored
= SecPVCIsAnchored(pvc
);
1400 /* If the anchor is trusted we don't procces the last cert in the
1404 /* Add a detail for the root not being trusted. */
1405 if (SecPVCSetResultForced(pvc
, kSecPolicyCheckAnchorTrusted
,
1406 n
- 1, kCFBooleanFalse
, true))
1410 CFAbsoluteTime verify_time
= SecPVCGetVerifyTime(pvc
);
1411 //policy_set_t user_initial_policy_set = NULL;
1412 //trust_anchor_t anchor;
1413 bool initial_policy_mapping_inhibit
= false;
1414 bool initial_explicit_policy
= false;
1415 bool initial_any_policy_inhibit
= false;
1417 root_name_t initial_permitted_subtrees
= NULL
;
1418 root_name_t initial_excluded_subtrees
= NULL
;
1421 /* Initialization */
1422 pvc
->valid_policy_tree
= policy_tree_create(&oidAnyPolicy
, NULL
);
1424 root_name_t permitted_subtrees
= initial_permitted_subtrees
;
1425 root_name_t excluded_subtrees
= initial_excluded_subtrees
;
1427 uint32_t explicit_policy
= initial_explicit_policy
? 0 : n
+ 1;
1428 uint32_t inhibit_any_policy
= initial_any_policy_inhibit
? 0 : n
+ 1;
1429 uint32_t policy_mapping
= initial_policy_mapping_inhibit
? 0 : n
+ 1;
1432 /* Path builder ensures we only get cert chains with proper issuer
1433 chaining with valid signatures along the way. */
1434 algorithm_id_t working_public_key_algorithm
= anchor
->public_key_algorithm
;
1435 SecKeyRef working_public_key
= anchor
->public_key
;
1436 x500_name_t working_issuer_name
= anchor
->issuer_name
;
1438 uint32_t i
, max_path_length
= n
;
1439 SecCertificateRef cert
= NULL
;
1440 for (i
= 1; i
<= n
; ++i
) {
1442 cert
= SecPVCGetCertificateAtIndex(pvc
, n
- i
);
1443 bool is_self_issued
= SecPVCIsCertificateAtIndexSelfSigned(pvc
, n
- i
);
1445 /* (a) Verify the basic certificate information. */
1446 /* @@@ Ensure that cert was signed with working_public_key_algorithm
1447 using the working_public_key and the working_public_key_parameters. */
1449 /* Already done by chain builder. */
1450 if (!SecCertificateIsValid(cert
, verify_time
)) {
1451 CFStringRef fail_key
= i
== n
? kSecPolicyCheckValidLeaf
: kSecPolicyCheckValidIntermediates
;
1452 if (!SecPVCSetResult(pvc
, fail_key
, n
- i
, kCFBooleanFalse
))
1457 /* Check revocation status if the certificate asks for it. */
1458 CFArrayRef ocspResponders
= SecCertificateGetOCSPResponders(cert
);
1459 if (ocspResponders
) {
1460 SecPVCSetCheckRevocation(pvc
);
1463 /* @@@ cert.issuer == working_issuer_name. */
1467 if (!is_self_issued
|| i
== n
) {
1468 /* 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. */
1469 /* 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. */
1473 if (pvc
->valid_policy_tree
) {
1474 const SecCECertificatePolicies
*cp
=
1475 SecCertificateGetCertificatePolicies(cert
);
1476 size_t policy_ix
, policy_count
= cp
? cp
->numPolicies
: 0;
1477 for (policy_ix
= 0; policy_ix
< policy_count
; ++policy_ix
) {
1478 const SecCEPolicyInformation
*policy
= &cp
->policies
[policy_ix
];
1479 oid_t p_oid
= policy
->policyIdentifier
;
1480 policy_qualifier_t p_q
= &policy
->policyQualifiers
;
1481 struct policy_tree_add_ctx ctx
= { p_oid
, p_q
};
1482 if (!oid_equal(p_oid
, oidAnyPolicy
)) {
1483 if (!policy_tree_walk_depth(pvc
->valid_policy_tree
, i
- 1,
1484 policy_tree_add_if_match
, &ctx
)) {
1485 policy_tree_walk_depth(pvc
->valid_policy_tree
, i
- 1,
1486 policy_tree_add_if_any
, &ctx
);
1490 /* The certificate policies extension includes the policy
1491 anyPolicy with the qualifier set AP-Q and either
1492 (a) inhibit_anyPolicy is greater than 0 or
1493 (b) i < n and the certificate is self-issued. */
1494 if (inhibit_any_policy
> 0 || (i
< n
&& is_self_issued
)) {
1495 for (policy_ix
= 0; policy_ix
< policy_count
; ++policy_ix
) {
1496 const SecCEPolicyInformation
*policy
= &cp
->policies
[policy_ix
];
1497 oid_t p_oid
= policy
->policyIdentifier
;
1498 policy_qualifier_t p_q
= &policy
->policyQualifiers
;
1499 if (oid_equal(p_oid
, oidAnyPolicy
)) {
1500 policy_tree_walk_depth(pvc
->valid_policy_tree
, i
- 1,
1501 policy_tree_add_expected
, (void *)p_q
);
1505 policy_tree_prune_childless(&pvc
->valid_policy_tree
, i
- 1);
1508 if (pvc
->valid_policy_tree
)
1509 policy_tree_prune(&pvc
->valid_policy_tree
);
1512 /* (f) Verify that either explicit_policy is greater than 0 or the
1513 valid_policy_tree is not equal to NULL. */
1514 if (!pvc
->valid_policy_tree
&& explicit_policy
== 0) {
1515 /* valid_policy_tree is empty and explicit policy is 0, illegal. */
1516 if (!SecPVCSetResultForced(pvc
, key
/* @@@ Need custom key */, n
- i
, kCFBooleanFalse
, true))
1519 /* If Last Cert in Path */
1523 /* Prepare for Next Cert */
1525 /* (a) verify that anyPolicy does not appear as an
1526 issuerDomainPolicy or a subjectDomainPolicy */
1527 CFDictionaryRef pm
= SecCertificateGetPolicyMappings(cert
);
1529 uint32_t mapping_ix
, mapping_count
= pm
->numMappings
;
1530 for (mapping_ix
= 0; mapping_ix
< mapping_count
; ++mapping_ix
) {
1531 const SecCEPolicyMapping
*mapping
= &pm
->mappings
[mapping_ix
];
1532 if (oid_equal(mapping
->issuerDomainPolicy
, oidAnyPolicy
)
1533 || oid_equal(mapping
->subjectDomainPolicy
, oidAnyPolicy
)) {
1534 /* Policy mapping uses anyPolicy, illegal. */
1535 if (!SecPVCSetResultForced(pvc
, key
/* @@@ Need custom key */, n
- i
, kCFBooleanFalse
))
1540 /* (1) If the policy_mapping variable is greater than 0 */
1541 if (policy_mapping
> 0) {
1542 if (!policy_tree_walk_depth(pvc
->valid_policy_tree
, i
,
1543 policy_tree_map
, (void *)pm
)) {
1544 /* 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:
1546 (i) set the valid_policy to ID-P;
1548 (ii) set the qualifier_set to the qualifier set of the
1549 policy anyPolicy in the certificate policies
1550 extension of certificate i; and
1551 (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. */
1555 /* (i) delete each node of depth i in the valid_policy_tree
1556 where ID-P is the valid_policy. */
1557 struct policy_tree_map_ctx ctx
= { idp_oid
, sdp_oid
};
1558 policy_tree_walk_depth(pvc
->valid_policy_tree
, i
,
1559 policy_tree_delete_if_match
, &ctx
);
1561 /* (ii) If there is a node in the valid_policy_tree of depth
1562 i-1 or less without any child nodes, delete that
1563 node. Repeat this step until there are no nodes of
1564 depth i-1 or less without children. */
1565 policy_tree_prune_childless(&pvc
->valid_policy_tree
, i
- 1);
1568 #endif /* POLICY_MAPPING */
1570 //working_issuer_name = SecCertificateGetNormalizedSubjectContent(cert);
1571 //working_public_key = SecCertificateCopyPublicKey(cert);
1572 //working_public_key_parameters = SecCertificateCopyPublicKeyParameters(cert);
1573 //working_public_key_algorithm = SecCertificateCopyPublicKeyAlgorithm(cert);
1575 /* (g) If a name constraints extension is included in the certificate, modify the permitted_subtrees and excluded_subtrees state variables as follows:
1577 /* @@@ handle name constraints. */
1580 if (!is_self_issued
) {
1581 if (explicit_policy
)
1585 if (inhibit_any_policy
)
1586 inhibit_any_policy
--;
1589 const SecCEPolicyConstraints
*pc
=
1590 SecCertificateGetPolicyConstraints(cert
);
1592 if (pc
->requireExplicitPolicyPresent
1593 && pc
->requireExplicitPolicy
< explicit_policy
) {
1594 explicit_policy
= pc
->requireExplicitPolicy
;
1596 if (pc
->inhibitPolicyMappingPresent
1597 && pc
->inhibitPolicyMapping
< policy_mapping
) {
1598 policy_mapping
= pc
->inhibitPolicyMapping
;
1602 uint32_t iap
= SecCertificateGetInhibitAnyPolicySkipCerts(cert
);
1603 if (iap
< inhibit_any_policy
) {
1604 inhibit_any_policy
= iap
;
1607 const SecCEBasicConstraints
*bc
=
1608 SecCertificateGetBasicConstraints(cert
);
1609 #if 0 /* Checked in chain builder pre signature verify already. */
1610 if (!bc
|| !bc
->isCA
) {
1611 /* Basic constraints not present or not marked as isCA, illegal. */
1612 if (!SecPVCSetResult(pvc
, kSecPolicyCheckBasicContraints
,
1613 n
- i
, kCFBooleanFalse
))
1618 if (!is_self_issued
) {
1619 if (max_path_length
> 0) {
1622 /* max_path_len exceeded, illegal. */
1623 if (!SecPVCSetResult(pvc
, kSecPolicyCheckBasicContraints
,
1624 n
- i
, kCFBooleanFalse
))
1629 if (bc
&& bc
->pathLenConstraintPresent
1630 && bc
->pathLenConstraint
< max_path_length
) {
1631 max_path_length
= bc
->pathLenConstraint
;
1633 #if 0 /* Checked in chain builder pre signature verify already. */
1634 /* (n) If a key usage extension is present, verify that the keyCertSign bit is set. */
1635 SecKeyUsage keyUsage
= SecCertificateGetKeyUsage(cert
);
1636 if (keyUsage
&& !(keyUsage
& kSecKeyUsageKeyCertSign
)) {
1637 if (!SecPVCSetResultForced(pvc
, kSecPolicyCheckKeyUsage
,
1638 n
- i
, kCFBooleanFalse
, true))
1642 /* (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. */
1643 if (SecCertificateHasUnknownCriticalExtension(cert
)) {
1644 /* Certificate contains one or more unknown critical extensions. */
1645 if (!SecPVCSetResult(pvc
, kSecPolicyCheckCriticalExtensions
,
1646 n
- i
, kCFBooleanFalse
))
1651 cert
= SecPVCGetCertificateAtIndex(pvc
, 0);
1653 if (explicit_policy
)
1656 const SecCEPolicyConstraints
*pc
= SecCertificateGetPolicyConstraints(cert
);
1658 if (pc
->requireExplicitPolicyPresent
1659 && pc
->requireExplicitPolicy
== 0) {
1660 explicit_policy
= 0;
1664 //working_public_key = SecCertificateCopyPublicKey(cert);
1666 /* 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
1667 working_public_key_algorithm are different, set the working_public_key_parameters to null. */
1668 //working_public_key_parameters = SecCertificateCopyPublicKeyParameters(cert);
1670 //working_public_key_algorithm = SecCertificateCopyPublicKeyAlgorithm(cert);
1671 /* (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. */
1672 if (SecCertificateHasUnknownCriticalExtension(cert
)) {
1673 /* Certificate contains one or more unknown critical extensions. */
1674 if (!SecPVCSetResult(pvc
, kSecPolicyCheckCriticalExtensions
,
1675 0, kCFBooleanFalse
))
1678 /* (g) Calculate the intersection of the valid_policy_tree and the user-initial-policy-set, as follows */
1680 if (pvc
->valid_policy_tree
) {
1681 #if !defined(NDEBUG)
1682 policy_tree_dump(pvc
->valid_policy_tree
);
1685 //policy_tree_prune_childless(&pvc->valid_policy_tree, n - 1);
1688 /* If either (1) the value of explicit_policy variable is greater than
1689 zero or (2) the valid_policy_tree is not NULL, then path processing
1691 if (!pvc
->valid_policy_tree
&& explicit_policy
== 0) {
1692 /* valid_policy_tree is empty and explicit policy is 0, illegal. */
1693 if (!SecPVCSetResultForced(pvc
, key
/* @@@ Need custom key */, 0, kCFBooleanFalse
, true))
1698 static policy_set_t
policies_for_cert(SecCertificateRef cert
) {
1699 policy_set_t policies
= NULL
;
1700 const SecCECertificatePolicies
*cp
=
1701 SecCertificateGetCertificatePolicies(cert
);
1702 size_t policy_ix
, policy_count
= cp
? cp
->numPolicies
: 0;
1703 for (policy_ix
= 0; policy_ix
< policy_count
; ++policy_ix
) {
1704 policy_set_add(&policies
, &cp
->policies
[policy_ix
].policyIdentifier
);
1709 static void SecPolicyCheckEV(SecPVCRef pvc
,
1711 CFIndex ix
, count
= SecPVCGetCertificateCount(pvc
);
1712 policy_set_t valid_policies
= NULL
;
1714 for (ix
= 0; ix
< count
; ++ix
) {
1715 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, ix
);
1716 policy_set_t policies
= policies_for_cert(cert
);
1719 /* anyPolicy in the leaf isn't allowed for EV, so only init
1720 valid_policies if we have real policies. */
1721 if (!policy_set_contains(policies
, &oidAnyPolicy
)) {
1722 valid_policies
= policies
;
1725 } else if (ix
< count
- 1) {
1726 /* Subordinate CA */
1727 if (!SecPolicySubordinateCACertificateCouldBeEV(cert
)) {
1728 secdebug("ev", "subordinate certificate is not ev");
1729 if (SecPVCSetResultForced(pvc
, key
,
1730 ix
, kCFBooleanFalse
, true)) {
1731 policy_set_free(valid_policies
);
1732 policy_set_free(policies
);
1736 policy_set_intersect(&valid_policies
, policies
);
1739 if (!SecPolicyRootCACertificateIsEV(cert
, valid_policies
)) {
1740 secdebug("ev", "anchor certificate is not ev");
1741 if (SecPVCSetResultForced(pvc
, key
,
1742 ix
, kCFBooleanFalse
, true)) {
1743 policy_set_free(valid_policies
);
1744 policy_set_free(policies
);
1749 policy_set_free(policies
);
1750 if (!valid_policies
) {
1751 secdebug("ev", "valid_policies set is empty: chain not ev");
1752 /* If we ever get into a state where no policies are valid anymore
1753 this can't be an ev chain. */
1754 if (SecPVCSetResultForced(pvc
, key
,
1755 ix
, kCFBooleanFalse
, true)) {
1761 policy_set_free(valid_policies
);
1763 /* (a) EV Subscriber Certificates Each EV Certificate issued by the CA to a
1764 Subscriber MUST contain an OID defined by the CA in the certificate’s
1765 certificatePolicies extension that: (i) indicates which CA policy statement relates
1766 to that certificate, (ii) asserts the CA’s adherence to and compliance with these
1767 Guidelines, and (iii), by pre-agreement with the Application Software Vendor,
1768 marks the certificate as being an EV Certificate.
1769 (b) EV Subordinate CA Certificates
1770 (1) Certificates issued to Subordinate CAs that are not controlled by the issuing
1771 CA MUST contain one or more OIDs defined by the issuing CA that
1772 explicitly identify the EV Policies that are implemented by the Subordinate
1774 (2) Certificates issued to Subordinate CAs that are controlled by the Root CA
1775 MAY contain the special anyPolicy OID (2.5.29.32.0).
1776 (c) Root CA Certificates Root CA Certificates SHOULD NOT contain the
1777 certificatePolicies or extendedKeyUsage extensions.
1782 static void SecPolicyCheckCertificatePolicyOid(SecPVCRef pvc
, CFStringRef key
)
1784 CFIndex ix
, count
= SecPVCGetCertificateCount(pvc
);
1785 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
1786 CFTypeRef value
= CFDictionaryGetValue(policy
->_options
, key
);
1788 key_value
.data
= NULL
;
1789 key_value
.length
= 0;
1791 if (CFGetTypeID(value
) == CFDataGetTypeID())
1793 CFDataRef key_data
= (CFDataRef
)value
;
1794 key_value
.data
= (DERByte
*)CFDataGetBytePtr(key_data
);
1795 key_value
.length
= (DERSize
)CFDataGetLength(key_data
);
1797 for (ix
= 0; ix
< count
; ix
++) {
1798 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, ix
);
1799 policy_set_t policies
= policies_for_cert(cert
);
1801 if (policy_set_contains(policies
, &key_value
)) {
1805 SecPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
);
1810 static void SecPolicyCheckRevocation(SecPVCRef pvc
,
1812 SecPVCSetCheckRevocation(pvc
);
1815 static void SecPolicyCheckNoNetworkAccess(SecPVCRef pvc
,
1817 SecPathBuilderSetCanAccessNetwork(pvc
->builder
, false);
1822 /********************************************************
1823 ****************** SecRVCRef Functions *****************
1824 ********************************************************/
1826 /* Revocation verification context. */
1827 struct OpaqueSecRVC
{
1828 /* Will contain the response data. */
1831 /* Pointer to the pvc for this revocation check. */
1834 /* The ocsp request we send to each responder. */
1835 SecOCSPRequestRef ocspRequest
;
1837 /* Index of cert in pvc that this RVC is for 0 = leaf, etc. */
1840 /* Index in array returned by SecCertificateGetOCSPResponders() for current
1842 CFIndex responderIX
;
1844 /* URL of current responder. */
1847 /* Date until which this revocation status is valid. */
1848 CFAbsoluteTime nextUpdate
;
1852 typedef struct OpaqueSecRVC
*SecRVCRef
;
1854 static void SecRVCDelete(SecRVCRef rvc
) {
1855 secdebug("alloc", "%p", rvc
);
1856 asynchttp_free(&rvc
->http
);
1857 SecOCSPRequestFinalize(rvc
->ocspRequest
);
1860 /* Return the next responder we should contact for this rvc or NULL if we
1861 exhausted them all. */
1862 static CFURLRef
SecRVCGetNextResponder(SecRVCRef rvc
) {
1863 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(rvc
->pvc
, rvc
->certIX
);
1864 CFArrayRef ocspResponders
= SecCertificateGetOCSPResponders(cert
);
1865 if (ocspResponders
) {
1866 CFIndex responderCount
= CFArrayGetCount(ocspResponders
);
1867 while (rvc
->responderIX
< responderCount
) {
1868 CFURLRef responder
= CFArrayGetValueAtIndex(ocspResponders
, rvc
->responderIX
);
1870 CFStringRef scheme
= CFURLCopyScheme(responder
);
1872 /* We only support http and https responders currently. */
1873 bool valid_responder
= (CFEqual(CFSTR("http"), scheme
) ||
1874 CFEqual(CFSTR("https"), scheme
));
1876 if (valid_responder
)
1884 /* Fire off an async http request for this certs revocation status, return
1885 false if request was queued, true if we're done. */
1886 static bool SecRVCFetchNext(SecRVCRef rvc
) {
1887 while ((rvc
->responder
= SecRVCGetNextResponder(rvc
))) {
1888 CFDataRef request
= SecOCSPRequestGetDER(rvc
->ocspRequest
);
1892 if (!asyncHttpPost(rvc
->responder
, request
, &rvc
->http
)) {
1893 /* Async request was posted, wait for reply. */
1903 /* Proccess a verified ocsp response for a given cert. Return true if the
1904 certificate status was obtained. */
1905 static bool SecOCSPSingleResponseProccess(SecOCSPSingleResponseRef
this,
1908 switch (this->certStatus
) {
1910 secdebug("ocsp", "CS_Good for cert %" PRIdCFIndex
, rvc
->certIX
);
1911 /* @@@ Mark cert as valid until a given date (nextUpdate if we have one)
1912 in the info dictionary. */
1913 //cert.revokeCheckGood(true);
1914 rvc
->nextUpdate
= this->nextUpdate
;
1918 secdebug("ocsp", "CS_Revoked for cert %" PRIdCFIndex
, rvc
->certIX
);
1919 /* @@@ Mark cert as revoked (with reason) at revocation date in
1920 the info dictionary, or perhaps we should use a different key per
1921 reason? That way a client using exceptions can ignore some but
1923 SInt32 reason
= this->crlReason
;
1924 CFNumberRef cfreason
= CFNumberCreate(kCFAllocatorDefault
, kCFNumberSInt32Type
, &reason
);
1925 SecPVCSetResultForced(rvc
->pvc
, kSecPolicyCheckRevocation
, rvc
->certIX
,
1927 CFRelease(cfreason
);
1931 /* not an error, no per-cert status, nothing here */
1932 secdebug("ocsp", "CS_Unknown for cert %" PRIdCFIndex
, rvc
->certIX
);
1936 secdebug("ocsp", "BAD certStatus (%d) for cert %" PRIdCFIndex
,
1937 (int)this->certStatus
, rvc
->certIX
);
1945 static bool SecOCSPResponseVerify(SecOCSPResponseRef ocspResponse
, SecRVCRef rvc
) {
1947 SecCertificatePathRef issuer
= SecCertificatePathCopyFromParent(rvc
->pvc
->path
, rvc
->certIX
+ 1);
1948 SecCertificatePathRef signer
= SecOCSPResponseCopySigner(ocspResponse
, issuer
);
1952 if (signer
== issuer
) {
1953 /* We already know we trust issuer since it's the path we are
1954 trying to verify minus the leaf. */
1955 secdebug("ocsp", "ocsp responder: %@ response signed by issuer",
1960 "ocsp responder: %@ response signed by cert issued by issuer",
1962 /* @@@ Now check that we trust signer. */
1963 const void *ocspSigner
= SecPolicyCreateOCSPSigner();
1964 CFArrayRef policies
= CFArrayCreate(kCFAllocatorDefault
,
1965 &ocspSigner
, 1, &kCFTypeArrayCallBacks
);
1966 CFRelease(ocspSigner
);
1967 CFAbsoluteTime verifyTime
= SecOCSPResponseVerifyTime(ocspResponse
);
1968 struct OpaqueSecPVC ospvc
;
1969 SecPVCInit(&ospvc
, rvc
->pvc
->builder
, policies
, verifyTime
);
1970 CFRelease(policies
);
1971 SecPVCSetPath(&ospvc
, signer
, NULL
);
1972 SecPVCLeafChecks(&ospvc
);
1974 bool completed
= SecPVCPathChecks(&ospvc
);
1975 /* If completed is false we are waiting for a callback, this
1976 shouldn't happen since we aren't asking for details, no
1977 revocation checking is done. */
1979 ocspdErrorLog("SecPVCPathChecks unexpectedly started "
1981 /* @@@ assert() or abort here perhaps? */
1985 secdebug("ocsp", "response satisfies ocspSigner policy (%@)",
1989 /* @@@ We don't trust the cert so don't use this response. */
1990 ocspdErrorLog("ocsp response signed by certificate which "
1991 "does not satisfy ocspSigner policy");
1994 SecPVCDelete(&ospvc
);
1999 /* @@@ No signer found for this ocsp response, discard it. */
2000 secdebug("ocsp", "ocsp responder: %@ no signer found for response",
2005 #if DUMP_OCSPRESPONSES
2007 snprintf(buf
, 40, "/tmp/ocspresponse%ld%s.der",
2008 rvc
->certIX
, (trusted
? "t" : "u"));
2009 secdumpdata(ocspResponse
->data
, buf
);
2015 /* Callback from async http code after an ocsp response has been received. */
2016 static void SecOCSPFetchCompleted(asynchttp_t
*http
, CFTimeInterval maxAge
) {
2017 SecRVCRef rvc
= (SecRVCRef
)http
->info
;
2018 SecPVCRef pvc
= rvc
->pvc
;
2019 SecOCSPResponseRef ocspResponse
= NULL
;
2020 if (http
->response
) {
2021 CFDataRef data
= CFHTTPMessageCopyBody(http
->response
);
2023 /* Parse the returned data as if it's an ocspResponse. */
2024 ocspResponse
= SecOCSPResponseCreate(data
, maxAge
);
2030 SecOCSPResponseStatus orStatus
= SecOCSPGetResponseStatus(ocspResponse
);
2031 if (orStatus
== kSecOCSPSuccess
) {
2032 SecOCSPSingleResponseRef sr
=
2033 SecOCSPResponseCopySingleResponse(ocspResponse
, rvc
->ocspRequest
);
2035 /* The ocsp response didn't have a singleResponse for the cert
2036 we are looking for, let's try the next responder. */
2038 "ocsp responder: %@ did not include status of requested cert",
2041 /* We got a singleResponse for the cert we are interested in,
2042 let's proccess it. */
2043 /* @@@ If the responder doesn't have the ocsp-nocheck extension
2044 we should check whether the leaf was revoked (we are
2045 already checking the rest of the chain). */
2046 /* Check the OCSP response signature and verify the
2048 if (SecOCSPResponseVerify(ocspResponse
, rvc
)) {
2049 secdebug("ocsp","responder: %@ sent proper response",
2052 if (SecOCSPSingleResponseProccess(sr
, rvc
)) {
2053 if (rvc
->nextUpdate
== 0) {
2055 SecOCSPResponseGetExpirationTime(ocspResponse
);
2057 /* If the singleResponse had meaningful information, we
2058 cache the response. */
2059 SecOCSPCacheAddResponse(ocspResponse
, rvc
->responder
);
2063 SecOCSPSingleResponseDestroy(sr
);
2066 /* ocsp response not ok. Let's try next responder. */
2067 secdebug("ocsp", "responder: %@ returned status: %d",
2068 rvc
->responder
, orStatus
);
2070 if (!SecPVCSetResultForced(pvc
, kSecPolicyCheckRevocation
,
2071 rvc
->certIX
, kCFBooleanFalse
, true))
2075 SecOCSPResponseFinalize(ocspResponse
);
2079 /* Clear the data for the next response. */
2080 asynchttp_free(http
);
2081 SecRVCFetchNext(rvc
);
2086 if (!--pvc
->asyncJobCount
) {
2087 SecPathBuilderStep(pvc
->builder
);
2092 static void SecRVCInit(SecRVCRef rvc
, SecPVCRef pvc
, CFIndex certIX
) {
2093 secdebug("alloc", "%p", rvc
);
2095 rvc
->certIX
= certIX
;
2096 rvc
->http
.queue
= SecPathBuilderGetQueue(pvc
->builder
);
2097 rvc
->http
.completed
= SecOCSPFetchCompleted
;
2098 rvc
->http
.info
= rvc
;
2099 rvc
->ocspRequest
= NULL
;
2100 rvc
->responderIX
= 0;
2101 rvc
->responder
= NULL
;
2102 rvc
->nextUpdate
= 0;
2107 static bool SecPVCCheckRevocation(SecPVCRef pvc
) {
2108 secdebug("ocsp", "checking revocation");
2109 CFIndex certIX
, certCount
= SecPVCGetCertificateCount(pvc
);
2110 bool completed
= true;
2111 if (certCount
<= 1) {
2112 /* Can't verify without an issuer; we're done */
2115 if (!SecPVCIsAnchored(pvc
)) {
2116 /* We can't check revocation for chains without a trusted anchor. */
2122 /* @@@ Implement getting this value from the client.
2123 Optional responder passed in though policy. */
2124 CFURLRef localResponder
= NULL
;
2125 /* Generate a nonce in outgoing request if true. */
2126 bool genNonce
= false;
2127 /* Require a nonce in response if true. */
2128 bool requireRespNonce
= false;
2129 bool cacheReadDisable
= false;
2130 bool cacheWriteDisable
= false;
2134 /* We have done revocation checking already, we're done. */
2135 secdebug("ocsp", "Not rechecking revocation");
2139 /* Setup things so we check revocation status of all certs except the
2141 pvc
->rvcs
= calloc(sizeof(struct OpaqueSecRVC
), certCount
);
2144 /* Lookup cached revocation data for each certificate. */
2145 for (certIX
= 0; certIX
< certCount
; ++certIX
) {
2146 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(rvc
->pvc
, rvc
->certIX
);
2147 CFArrayRef ocspResponders
= SecCertificateGetOCSPResponders(cert
);
2148 if (ocspResponders
) {
2149 /* First look though passed in ocsp responses. */
2150 //SecPVCGetOCSPResponseForCertificateAtIndex(pvc, ix, singleResponse);
2152 /* Then look though shared cache (we don't care which responder
2153 something came from here). */
2154 CFDataRef ocspResponse
= SecOCSPCacheCopyMatching(SecCertIDRef certID
, NULL
);
2156 /* Now let's parse the response. */
2157 if (decodeOCSPResponse(ocspResp
)) {
2158 secdebug("ocsp", "response ok: %@", ocspResp
);
2160 secdebug("ocsp", "response bad: %@", ocspResp
);
2161 /* ocsp response not ok. */
2162 if (!SecPVCSetResultForced(pvc
, key
, ix
, kCFBooleanFalse
, true))
2165 CFReleaseSafe(ocspResp
);
2167 /* Check if certificate has any crl distributionPoints. */
2168 CFArrayRef distributionPoints
= SecCertificateGetCRLDistributionPoints(cert
);
2169 if (distributionPoints
) {
2170 /* Look for a cached CRL and potentially delta CRL for this certificate. */
2176 /* Note that if we are multi threaded and a job completes after it
2177 is started but before we return from this function, we don't want
2178 a callback to decrement asyncJobCount to zero before we finish issuing
2179 all the jobs. To avoid this we pretend we issued certCount async jobs,
2180 and decrement pvc->asyncJobCount for each cert that we don't start a
2181 background fetch for. */
2182 pvc
->asyncJobCount
= (unsigned int) certCount
;
2184 /* Loop though certificates again and issue an ocsp fetch if the
2185 revocation status checking isn't done yet. */
2186 for (certIX
= 0; certIX
< certCount
; ++certIX
) {
2187 secdebug("ocsp", "checking revocation for cert: %ld", certIX
);
2188 SecRVCRef rvc
= &((SecRVCRef
)pvc
->rvcs
)[certIX
];
2189 SecRVCInit(rvc
, pvc
, certIX
);
2193 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(rvc
->pvc
,
2195 /* The certIX + 1 is ok here since certCount is always at least 1
2196 less than the actual number of certs. */
2197 SecCertificateRef issuer
= SecPVCGetCertificateAtIndex(rvc
->pvc
,
2200 rvc
->ocspRequest
= SecOCSPRequestCreate(cert
, issuer
);
2201 SecOCSPResponseRef ocspResponse
;
2202 ocspResponse
= SecOCSPCacheCopyMatching(rvc
->ocspRequest
, NULL
);
2204 SecOCSPSingleResponseRef sr
=
2205 SecOCSPResponseCopySingleResponse(ocspResponse
, rvc
->ocspRequest
);
2207 /* The cached ocsp response didn't have a singleResponse for
2208 the cert we are looking for, it's shouldn't be in the cache. */
2209 secdebug("ocsp", "cached ocsp response did not include status"
2210 " of requested cert");
2212 /* We got a singleResponse for the cert we are interested in,
2213 let's proccess it. */
2215 /* @@@ If the responder doesn't have the ocsp-nocheck extension
2216 we should check whether the leaf was revoked (we are
2217 already checking the rest of the chain). */
2218 /* Recheck the OCSP response signature and verify the
2220 if (SecOCSPResponseVerify(ocspResponse
, rvc
)) {
2221 secdebug("ocsp","cached response still has valid signature");
2223 if (SecOCSPSingleResponseProccess(sr
, rvc
)) {
2224 CFAbsoluteTime expTime
=
2225 SecOCSPResponseGetExpirationTime(ocspResponse
);
2226 if (rvc
->nextUpdate
== 0 || expTime
< rvc
->nextUpdate
)
2227 rvc
->nextUpdate
= expTime
;
2231 SecOCSPSingleResponseDestroy(sr
);
2233 SecOCSPResponseFinalize(ocspResponse
);
2236 /* Unless we succefully checked the revocation status of this cert
2237 based on the cache, Attempt to fire off an async http request
2238 for this certs revocation status. */
2239 bool fetch_done
= true;
2240 if (rvc
->done
|| !SecPathBuilderCanAccessNetwork(pvc
->builder
) ||
2241 (fetch_done
= SecRVCFetchNext(rvc
))) {
2242 /* We got a cache hit or we aren't allowed to access the network,
2243 or the async http post failed. */
2245 /* We didn't really start a background job for this cert. */
2246 pvc
->asyncJobCount
--;
2247 } else if (!fetch_done
) {
2248 /* We started at least one background fetch. */
2253 /* Return false if we started any background jobs. */
2254 /* We can't just return !pvc->asyncJobCount here, since if we started any
2255 jobs the completion callback will be called eventually and it will call
2256 SecPathBuilderStep(). If for some reason everything completed before we
2257 get here we still want the outer SecPathBuilderStep() to terminate so we
2258 keep track of whether we started any jobs and return false if so. */
2263 void SecPolicyServerInitalize(void) {
2264 gSecPolicyLeafCallbacks
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0,
2265 &kCFTypeDictionaryKeyCallBacks
, NULL
);
2266 gSecPolicyPathCallbacks
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0,
2267 &kCFTypeDictionaryKeyCallBacks
, NULL
);
2268 CFDictionaryAddValue(gSecPolicyPathCallbacks
,
2269 kSecPolicyCheckBasicCertificateProcessing
,
2270 SecPolicyCheckBasicCertificateProcessing
);
2271 CFDictionaryAddValue(gSecPolicyPathCallbacks
,
2272 kSecPolicyCheckCriticalExtensions
, SecPolicyCheckCriticalExtensions
);
2273 CFDictionaryAddValue(gSecPolicyPathCallbacks
,
2274 kSecPolicyCheckIdLinkage
, SecPolicyCheckIdLinkage
);
2275 CFDictionaryAddValue(gSecPolicyLeafCallbacks
,
2276 kSecPolicyCheckKeyUsage
, SecPolicyCheckKeyUsage
);
2277 CFDictionaryAddValue(gSecPolicyLeafCallbacks
,
2278 kSecPolicyCheckExtendedKeyUsage
, SecPolicyCheckExtendedKeyUsage
);
2279 CFDictionaryAddValue(gSecPolicyLeafCallbacks
,
2280 kSecPolicyCheckBasicContraints
, SecPolicyCheckBasicContraints
);
2281 CFDictionaryAddValue(gSecPolicyLeafCallbacks
,
2282 kSecPolicyCheckNonEmptySubject
, SecPolicyCheckNonEmptySubject
);
2283 CFDictionaryAddValue(gSecPolicyLeafCallbacks
,
2284 kSecPolicyCheckQualifiedCertStatements
,
2285 SecPolicyCheckQualifiedCertStatements
);
2286 CFDictionaryAddValue(gSecPolicyLeafCallbacks
,
2287 kSecPolicyCheckSSLHostname
, SecPolicyCheckSSLHostname
);
2288 CFDictionaryAddValue(gSecPolicyLeafCallbacks
,
2289 kSecPolicyCheckEmail
, SecPolicyCheckEmail
);
2290 CFDictionaryAddValue(gSecPolicyPathCallbacks
,
2291 kSecPolicyCheckValidIntermediates
, SecPolicyCheckValidIntermediates
);
2292 CFDictionaryAddValue(gSecPolicyLeafCallbacks
,
2293 kSecPolicyCheckValidLeaf
, SecPolicyCheckValidLeaf
);
2294 CFDictionaryAddValue(gSecPolicyPathCallbacks
,
2295 kSecPolicyCheckValidRoot
, SecPolicyCheckValidRoot
);
2296 CFDictionaryAddValue(gSecPolicyPathCallbacks
,
2297 kSecPolicyCheckIssuerCommonName
, SecPolicyCheckIssuerCommonName
);
2298 CFDictionaryAddValue(gSecPolicyLeafCallbacks
,
2299 kSecPolicyCheckSubjectCommonNamePrefix
,
2300 SecPolicyCheckSubjectCommonNamePrefix
);
2301 CFDictionaryAddValue(gSecPolicyLeafCallbacks
,
2302 kSecPolicyCheckSubjectCommonName
,
2303 SecPolicyCheckSubjectCommonName
);
2304 CFDictionaryAddValue(gSecPolicyLeafCallbacks
,
2305 kSecPolicyCheckNotValidBefore
,
2306 SecPolicyCheckNotValidBefore
);
2307 CFDictionaryAddValue(gSecPolicyPathCallbacks
,
2308 kSecPolicyCheckChainLength
, SecPolicyCheckChainLength
);
2309 CFDictionaryAddValue(gSecPolicyPathCallbacks
,
2310 kSecPolicyCheckAnchorSHA1
, SecPolicyCheckAnchorSHA1
);
2311 CFDictionaryAddValue(gSecPolicyLeafCallbacks
,
2312 kSecPolicyCheckSubjectOrganization
,
2313 SecPolicyCheckSubjectOrganization
);
2314 CFDictionaryAddValue(gSecPolicyLeafCallbacks
,
2315 kSecPolicyCheckSubjectOrganizationalUnit
,
2316 SecPolicyCheckSubjectOrganizationalUnit
);
2317 CFDictionaryAddValue(gSecPolicyLeafCallbacks
,
2318 kSecPolicyCheckEAPTrustedServerNames
,
2319 SecPolicyCheckEAPTrustedServerNames
);
2320 CFDictionaryAddValue(gSecPolicyLeafCallbacks
,
2321 kSecPolicyCheckSubjectCommonNameTEST
,
2322 SecPolicyCheckSubjectCommonNameTEST
);
2323 CFDictionaryAddValue(gSecPolicyLeafCallbacks
,
2324 kSecPolicyCheckRevocation
,
2325 SecPolicyCheckRevocation
);
2326 CFDictionaryAddValue(gSecPolicyLeafCallbacks
,
2327 kSecPolicyCheckNoNetworkAccess
,
2328 SecPolicyCheckNoNetworkAccess
);
2329 CFDictionaryAddValue(gSecPolicyLeafCallbacks
,
2330 kSecPolicyCheckBlackListedLeaf
,
2331 SecPolicyCheckBlackListedLeaf
);
2332 CFDictionaryAddValue(gSecPolicyLeafCallbacks
,
2333 kSecPolicyCheckGrayListedLeaf
,
2334 SecPolicyCheckGrayListedLeaf
);
2335 CFDictionaryAddValue(gSecPolicyLeafCallbacks
,
2336 kSecPolicyCheckLeafMarkerOid
,
2337 SecPolicyCheckLeafMarkerOid
);
2338 CFDictionaryAddValue(gSecPolicyPathCallbacks
,
2339 kSecPolicyCheckIntermediateMarkerOid
,
2340 SecPolicyCheckIntermediateMarkerOid
);
2341 CFDictionaryAddValue(gSecPolicyLeafCallbacks
,
2342 kSecPolicyCheckCertificatePolicy
,
2343 SecPolicyCheckCertificatePolicyOid
);
2346 /* AUDIT[securityd](done):
2347 array (ok) is a caller provided array, only its cf type has
2349 The options (ok) field ends up in policy->_options unchecked, so every access
2350 of policy->_options needs to be validated.
2352 static SecPolicyRef
SecPolicyCreateWithArray(CFArrayRef array
) {
2353 SecPolicyRef policy
= NULL
;
2354 require_quiet(array
&& CFArrayGetCount(array
) == 2, errOut
);
2355 CFStringRef oid
= (CFStringRef
)CFArrayGetValueAtIndex(array
, 0);
2356 require_quiet(isString(oid
), errOut
);
2357 CFDictionaryRef options
= (CFDictionaryRef
)CFArrayGetValueAtIndex(array
, 1);
2358 require_quiet(isDictionary(options
), errOut
);
2359 policy
= SecPolicyCreate(oid
, options
);
2364 /* AUDIT[securityd](done):
2365 value (ok) is an element in a caller provided array.
2367 static void deserializePolicy(const void *value
, void *context
) {
2368 CFArrayRef policyArray
= (CFArrayRef
)value
;
2369 if (isArray(policyArray
)) {
2370 CFTypeRef deserializedPolicy
= SecPolicyCreateWithArray(policyArray
);
2371 if (deserializedPolicy
) {
2372 CFArrayAppendValue((CFMutableArrayRef
)context
, deserializedPolicy
);
2373 CFRelease(deserializedPolicy
);
2378 /* AUDIT[securityd](done):
2379 serializedPolicies (ok) is a caller provided array, only its cf type has
2382 CFArrayRef
SecPolicyArrayDeserialize(CFArrayRef serializedPolicies
) {
2383 CFMutableArrayRef result
= NULL
;
2384 require_quiet(isArray(serializedPolicies
), errOut
);
2385 CFIndex count
= CFArrayGetCount(serializedPolicies
);
2386 result
= CFArrayCreateMutable(kCFAllocatorDefault
, count
, &kCFTypeArrayCallBacks
);
2387 CFRange all_policies
= { 0, count
};
2388 CFArrayApplyFunction(serializedPolicies
, all_policies
, deserializePolicy
, result
);
2395 /********************************************************
2396 ****************** SecPVCRef Functions *****************
2397 ********************************************************/
2399 void SecPVCInit(SecPVCRef pvc
, SecPathBuilderRef builder
, CFArrayRef policies
,
2400 CFAbsoluteTime verifyTime
) {
2401 secdebug("alloc", "%p", pvc
);
2402 // Weird logging policies crashes.
2403 //secdebug("policy", "%@", policies);
2404 pvc
->builder
= builder
;
2405 pvc
->policies
= policies
;
2408 pvc
->verifyTime
= verifyTime
;
2410 pvc
->details
= NULL
;
2412 pvc
->valid_policy_tree
= NULL
;
2413 pvc
->callbacks
= NULL
;
2416 pvc
->asyncJobCount
= 0;
2417 pvc
->check_revocation
= false;
2418 pvc
->optionally_ev
= false;
2423 static void SecPVCDeleteRVCs(SecPVCRef pvc
) {
2424 secdebug("alloc", "%p", pvc
);
2431 void SecPVCDelete(SecPVCRef pvc
) {
2432 secdebug("alloc", "%p", pvc
);
2433 CFReleaseNull(pvc
->policies
);
2434 CFReleaseNull(pvc
->details
);
2435 CFReleaseNull(pvc
->info
);
2436 if (pvc
->valid_policy_tree
) {
2437 policy_tree_prune(&pvc
->valid_policy_tree
);
2439 SecPVCDeleteRVCs(pvc
);
2442 void SecPVCSetPath(SecPVCRef pvc
, SecCertificatePathRef path
,
2443 CF_CONSUMED CFArrayRef details
) {
2444 secdebug("policy", "%@", path
);
2445 if (pvc
->path
!= path
) {
2446 /* Changing path makes us clear the Revocation Verification Contexts */
2447 SecPVCDeleteRVCs(pvc
);
2450 pvc
->details
= details
;
2451 CFReleaseNull(pvc
->info
);
2452 if (pvc
->valid_policy_tree
) {
2453 policy_tree_prune(&pvc
->valid_policy_tree
);
2459 SecPolicyRef
SecPVCGetPolicy(SecPVCRef pvc
) {
2460 return (SecPolicyRef
)CFArrayGetValueAtIndex(pvc
->policies
, pvc
->policyIX
);
2463 CFIndex
SecPVCGetCertificateCount(SecPVCRef pvc
) {
2464 return SecCertificatePathGetCount(pvc
->path
);
2467 SecCertificateRef
SecPVCGetCertificateAtIndex(SecPVCRef pvc
, CFIndex ix
) {
2468 return SecCertificatePathGetCertificateAtIndex(pvc
->path
, ix
);
2471 bool SecPVCIsCertificateAtIndexSelfSigned(SecPVCRef pvc
, CFIndex ix
) {
2472 return SecCertificatePathSelfSignedIndex(pvc
->path
) == ix
;
2475 void SecPVCSetCheckRevocation(SecPVCRef pvc
) {
2476 pvc
->check_revocation
= true;
2477 secdebug("ocsp", "deferred revocation checking enabled");
2480 bool SecPVCIsAnchored(SecPVCRef pvc
) {
2481 return SecCertificatePathIsAnchored(pvc
->path
);
2484 CFAbsoluteTime
SecPVCGetVerifyTime(SecPVCRef pvc
) {
2485 return pvc
->verifyTime
;
2488 /* AUDIT[securityd](done):
2489 policy->_options is a caller provided dictionary, only its cf type has
2492 bool SecPVCSetResultForced(SecPVCRef pvc
,
2493 CFStringRef key
, CFIndex ix
, CFTypeRef result
, bool force
) {
2495 secdebug("policy", "cert[%d]: %@ =(%s)[%s]> %@", (int) ix
, key
,
2496 (pvc
->callbacks
== gSecPolicyLeafCallbacks
? "leaf"
2497 : (pvc
->callbacks
== gSecPolicyPathCallbacks
? "path"
2499 (force
? "force" : ""), result
);
2501 /* If this is not something the current policy cares about ignore
2502 this error and return true so our caller continues evaluation. */
2504 /* @@@ The right long term fix might be to check if none of the passed
2505 in policies contain this key, since not all checks are run for all
2507 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
2508 if (policy
&& !CFDictionaryContainsKey(policy
->_options
, key
))
2512 /* @@@ Check to see if the SecTrustSettings for the certificate in question
2513 tell us to ignore this error. */
2514 pvc
->result
= false;
2518 CFMutableDictionaryRef detail
=
2519 (CFMutableDictionaryRef
)CFArrayGetValueAtIndex(pvc
->details
, ix
);
2521 /* Perhaps detail should have an array of results per key? As it stands
2522 in the case of multiple policy failures the last failure stands. */
2523 CFDictionarySetValue(detail
, key
, result
);
2528 bool SecPVCSetResult(SecPVCRef pvc
,
2529 CFStringRef key
, CFIndex ix
, CFTypeRef result
) {
2530 return SecPVCSetResultForced(pvc
, key
, ix
, result
, false);
2533 /* AUDIT[securityd](done):
2534 key(ok) is a caller provided.
2535 value(ok, unused) is a caller provided.
2537 static void SecPVCValidateKey(const void *key
, const void *value
,
2539 SecPVCRef pvc
= (SecPVCRef
)context
;
2541 /* If our caller doesn't want full details and we failed earlier there is
2542 no point in doing additional checks. */
2543 if (!pvc
->result
&& !pvc
->details
)
2546 SecPolicyCheckFunction fcn
= (SecPolicyCheckFunction
)
2547 CFDictionaryGetValue(pvc
->callbacks
, key
);
2551 /* Why not to have optional policy checks rant:
2552 Not all keys are in all dictionaries anymore, so why not make checks
2553 optional? This way a client can ask for something and the server will
2554 do a best effort based on the supported flags. It works since they are
2555 synchronized now, but we need some debug checking here for now. */
2556 pvc
->result
= false;
2558 if (pvc
->callbacks
== gSecPolicyLeafCallbacks
) {
2559 if (!CFDictionaryContainsKey(gSecPolicyPathCallbacks
, key
)) {
2560 pvc
->result
= false;
2562 } else if (pvc
->callbacks
== gSecPolicyPathCallbacks
) {
2563 if (!CFDictionaryContainsKey(gSecPolicyLeafCallbacks
, key
)) {
2564 pvc
->result
= false;
2567 /* Non standard valdation phase, nothing is optional. */
2568 pvc
->result
= false;
2573 fcn(pvc
, (CFStringRef
)key
);
2576 /* AUDIT[securityd](done):
2577 policy->_options is a caller provided dictionary, only its cf type has
2580 bool SecPVCLeafChecks(SecPVCRef pvc
) {
2582 CFArrayRef policies
= pvc
->policies
;
2583 CFIndex ix
, count
= CFArrayGetCount(policies
);
2584 for (ix
= 0; ix
< count
; ++ix
) {
2585 SecPolicyRef policy
= (SecPolicyRef
)CFArrayGetValueAtIndex(policies
, ix
);
2587 /* Validate all keys for all policies. */
2588 pvc
->callbacks
= gSecPolicyLeafCallbacks
;
2589 CFDictionaryApplyFunction(policy
->_options
, SecPVCValidateKey
, pvc
);
2590 if (!pvc
->result
&& !pvc
->details
)
2597 bool SecPVCParentCertificateChecks(SecPVCRef pvc
, CFIndex ix
) {
2598 /* Check stuff common to intermediate and anchors. */
2599 CFAbsoluteTime verifyTime
= SecPVCGetVerifyTime(pvc
);
2600 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, ix
);
2601 bool is_anchor
= (ix
== SecPVCGetCertificateCount(pvc
) - 1
2602 && SecPVCIsAnchored(pvc
));
2603 if (!SecCertificateIsValid(cert
, verifyTime
)) {
2604 /* Certificate has expired. */
2605 if (!SecPVCSetResult(pvc
, is_anchor
? kSecPolicyCheckValidRoot
2606 : kSecPolicyCheckValidIntermediates
, ix
, kCFBooleanFalse
))
2611 /* Perform anchor specific checks. */
2612 /* Don't think we have any of these. */
2614 /* Perform intermediate specific checks. */
2617 const SecCEBasicConstraints
*bc
=
2618 SecCertificateGetBasicConstraints(cert
);
2619 if (!bc
|| !bc
->isCA
) {
2620 /* Basic constraints not present or not marked as isCA, illegal. */
2621 if (!SecPVCSetResultForced(pvc
, kSecPolicyCheckBasicContraints
,
2622 ix
, kCFBooleanFalse
, true))
2625 /* Consider adding (l) max_path_length checking here. */
2627 /* (n) If a key usage extension is present, verify that the keyCertSign bit is set. */
2628 SecKeyUsage keyUsage
= SecCertificateGetKeyUsage(cert
);
2629 if (keyUsage
&& !(keyUsage
& kSecKeyUsageKeyCertSign
)) {
2630 if (!SecPVCSetResultForced(pvc
, kSecPolicyCheckKeyUsage
,
2631 ix
, kCFBooleanFalse
, true))
2640 bool SecPVCBlackListedKeyChecks(SecPVCRef pvc
, CFIndex ix
) {
2641 /* Check stuff common to intermediate and anchors. */
2643 SecOTAPKIRef otapkiRef
= SecOTAPKICopyCurrentOTAPKIRef();
2644 if (NULL
!= otapkiRef
)
2646 CFSetRef blackListedKeys
= SecOTAPKICopyBlackListSet(otapkiRef
);
2647 CFRelease(otapkiRef
);
2648 if (NULL
!= blackListedKeys
)
2650 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, ix
);
2651 bool is_anchor
= (ix
== SecPVCGetCertificateCount(pvc
) - 1
2652 && SecPVCIsAnchored(pvc
));
2654 /* Check for blacklisted intermediates keys. */
2655 CFDataRef dgst
= SecCertificateCopyPublicKeySHA1Digest(cert
);
2657 /* Check dgst against blacklist. */
2658 if (CFSetContainsValue(blackListedKeys
, dgst
)) {
2659 SecPVCSetResultForced(pvc
, kSecPolicyCheckBlackListedKey
,
2660 ix
, kCFBooleanFalse
, true);
2665 CFRelease(blackListedKeys
);
2673 bool SecPVCGrayListedKeyChecks(SecPVCRef pvc
, CFIndex ix
)
2675 /* Check stuff common to intermediate and anchors. */
2676 SecOTAPKIRef otapkiRef
= SecOTAPKICopyCurrentOTAPKIRef();
2677 if (NULL
!= otapkiRef
)
2679 CFSetRef grayListKeys
= SecOTAPKICopyGrayList(otapkiRef
);
2680 CFRelease(otapkiRef
);
2681 if (NULL
!= grayListKeys
)
2683 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(pvc
, ix
);
2684 bool is_anchor
= (ix
== SecPVCGetCertificateCount(pvc
) - 1
2685 && SecPVCIsAnchored(pvc
));
2687 /* Check for gray listed intermediates keys. */
2688 CFDataRef dgst
= SecCertificateCopyPublicKeySHA1Digest(cert
);
2690 /* Check dgst against gray list. */
2691 if (CFSetContainsValue(grayListKeys
, dgst
)) {
2692 SecPVCSetResultForced(pvc
, kSecPolicyCheckGrayListedKey
,
2693 ix
, kCFBooleanFalse
, true);
2698 CFRelease(grayListKeys
);
2706 /* AUDIT[securityd](done):
2707 policy->_options is a caller provided dictionary, only its cf type has
2710 bool SecPVCPathChecks(SecPVCRef pvc
) {
2711 secdebug("policy", "begin path: %@", pvc
->path
);
2712 bool completed
= true;
2713 /* This needs to be initialized before we call any function that might call
2714 SecPVCSetResultForced(). */
2716 SecPolicyCheckIdLinkage(pvc
, kSecPolicyCheckIdLinkage
);
2717 if (pvc
->result
|| pvc
->details
) {
2718 SecPolicyCheckBasicCertificateProcessing(pvc
,
2719 kSecPolicyCheckBasicCertificateProcessing
);
2722 CFArrayRef policies
= pvc
->policies
;
2723 CFIndex count
= CFArrayGetCount(policies
);
2724 for (; pvc
->policyIX
< count
; ++pvc
->policyIX
) {
2725 /* Validate all keys for all policies. */
2726 pvc
->callbacks
= gSecPolicyPathCallbacks
;
2727 SecPolicyRef policy
= SecPVCGetPolicy(pvc
);
2728 CFDictionaryApplyFunction(policy
->_options
, SecPVCValidateKey
, pvc
);
2729 if (!pvc
->result
&& !pvc
->details
)
2733 /* Check the things we can't check statically for the certificate path. */
2734 /* Critical Extensions, chainLength. */
2738 if ((pvc
->result
|| pvc
->details
) && pvc
->optionally_ev
) {
2739 bool pre_ev_check_result
= pvc
->result
;
2740 SecPolicyCheckEV(pvc
, kSecPolicyCheckExtendedValidation
);
2741 pvc
->is_ev
= pvc
->result
;
2742 /* If ev checking failed, we still want to accept this chain
2743 as a non EV one, if it was valid as such. */
2744 pvc
->result
= pre_ev_check_result
;
2746 /* Check revocation only if the chain is valid so far. Then only check
2747 revocation if the client asked for it explicitly or is_ev is
2749 if (pvc
->result
&& (pvc
->is_ev
|| pvc
->check_revocation
)) {
2750 completed
= SecPVCCheckRevocation(pvc
);
2754 secdebug("policy", "end %strusted completed: %d path: %@",
2755 (pvc
->result
? "" : "not "), completed
, pvc
->path
);
2759 /* This function returns 0 to indicate revocation checking was not completed
2760 for this certificate chain, otherwise return to date at which the first
2761 piece of revocation checking info we used expires. */
2762 CFAbsoluteTime
SecPVCGetEarliestNextUpdate(SecPVCRef pvc
) {
2763 CFIndex certIX
, certCount
= SecPVCGetCertificateCount(pvc
);
2764 CFAbsoluteTime enu
= 0;
2765 if (certCount
<= 1 || !pvc
->rvcs
) {
2770 for (certIX
= 0; certIX
< certCount
; ++certIX
) {
2771 SecRVCRef rvc
= &((SecRVCRef
)pvc
->rvcs
)[certIX
];
2772 if (rvc
->nextUpdate
== 0) {
2774 /* We allow for CA certs to not be revocation checked if they
2775 have no ocspResponders to check against, but the leaf
2776 must be checked in order for us to claim we did revocation
2778 SecCertificateRef cert
=
2779 SecPVCGetCertificateAtIndex(rvc
->pvc
, rvc
->certIX
);
2780 CFArrayRef ocspResponders
= SecCertificateGetOCSPResponders(cert
);
2781 if (!ocspResponders
|| CFArrayGetCount(ocspResponders
) == 0) {
2782 /* We can't check this cert so we don't consider it a soft
2783 failure that we didn't. Ideally we should support crl
2784 checking and remove this workaround, since that more
2789 secdebug("ocsp", "revocation checking soft failure for cert: %ld",
2791 enu
= rvc
->nextUpdate
;
2794 if (enu
== 0 || rvc
->nextUpdate
< enu
) {
2795 enu
= rvc
->nextUpdate
;
2798 /* Perhaps we don't want to do this since some policies might
2799 ignore the certificate experation but still use revocation
2802 /* Earliest certificate expiration date. */
2803 SecCertificateRef cert
= SecPVCGetCertificateAtIndex(rvc
->pvc
, rvc
->certIX
);
2804 CFAbsoluteTime nva
= SecCertificateNotValidAfter(cert
);
2805 if (nva
&& (enu
== 0 || nva
< enu
)
2810 secdebug("ocsp", "revocation valid until: %lg", enu
);