2 * Copyright (c) 2008-2016 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 * SecPolicyLeafCallbacks.c - Callbacks for SecPolicy for verifying leafs
28 #include <AssertMacros.h>
29 #include <CoreFoundation/CFDictionary.h>
30 #include <Security/SecPolicyInternal.h>
31 #include <Security/SecCertificateInternal.h>
32 #include <utilities/SecCFWrappers.h>
35 #include <libDER/oidsPriv.h>
38 * MARK: SecPolicyCheckCert Functions
39 * All SecPolicyCheckCert* return false if the cert fails the check and true if it succeeds.
42 typedef bool (*SecPolicyCheckCertFunction
)(SecCertificateRef cert
, CFTypeRef pvcValue
);
44 /* This one is different from SecPolicyCheckCriticalExtensions because
45 that one is an empty stub. The CriticalExtensions check is done in
46 SecPolicyCheckBasicCertificateProcessing. */
47 static bool SecPolicyCheckCertCriticalExtensions(SecCertificateRef cert
, CFTypeRef __unused pvcValue
) {
48 if (SecCertificateHasUnknownCriticalExtension(cert
)) {
49 /* Certificate contains one or more unknown critical extensions. */
55 static bool keyusage_allows(SecKeyUsage keyUsage
, CFTypeRef xku
) {
56 if (!xku
|| CFGetTypeID(xku
) != CFNumberGetTypeID())
60 CFNumberGetValue((CFNumberRef
)xku
, kCFNumberSInt32Type
, &dku
);
61 SecKeyUsage ku
= (SecKeyUsage
)dku
;
62 return (keyUsage
& ku
) == ku
;
65 bool SecPolicyCheckCertKeyUsage(SecCertificateRef cert
, CFTypeRef pvcValue
) {
66 SecKeyUsage keyUsage
= SecCertificateGetKeyUsage(cert
);
68 CFTypeRef xku
= pvcValue
;
70 CFIndex ix
, count
= CFArrayGetCount(xku
);
71 for (ix
= 0; ix
< count
; ++ix
) {
72 CFTypeRef ku
= CFArrayGetValueAtIndex(xku
, ix
);
73 if (keyusage_allows(keyUsage
, ku
)) {
79 match
= keyusage_allows(keyUsage
, xku
);
84 static bool extendedkeyusage_allows(CFArrayRef extendedKeyUsage
,
88 if (extendedKeyUsage
) {
89 CFRange all
= { 0, CFArrayGetCount(extendedKeyUsage
) };
90 return CFArrayContainsValue(extendedKeyUsage
, all
, xeku
);
92 /* Certificate has no extended key usage, only a match if the policy
93 contains a 0 length CFDataRef. */
94 return CFDataGetLength((CFDataRef
)xeku
) == 0;
98 static bool isExtendedKeyUsageAllowed(CFArrayRef extendedKeyUsage
,
103 if(CFGetTypeID(xeku
) == CFDataGetTypeID()) {
104 return extendedkeyusage_allows(extendedKeyUsage
, xeku
);
105 } else if (CFGetTypeID(xeku
) == CFStringGetTypeID()) {
106 CFDataRef eku
= SecCertificateCreateOidDataFromString(NULL
, xeku
);
108 bool result
= extendedkeyusage_allows(extendedKeyUsage
, eku
);
116 bool SecPolicyCheckCertExtendedKeyUsage(SecCertificateRef cert
, CFTypeRef pvcValue
) {
117 CFArrayRef certExtendedKeyUsage
= SecCertificateCopyExtendedKeyUsage(cert
);
119 CFTypeRef xeku
= pvcValue
;
121 CFIndex ix
, count
= CFArrayGetCount(xeku
);
122 for (ix
= 0; ix
< count
; ix
++) {
123 CFTypeRef eku
= CFArrayGetValueAtIndex(xeku
, ix
);
124 if (isExtendedKeyUsageAllowed(certExtendedKeyUsage
, eku
)) {
130 match
= isExtendedKeyUsageAllowed(certExtendedKeyUsage
, xeku
);
132 CFReleaseSafe(certExtendedKeyUsage
);
136 static bool SecPolicyCheckCertNonEmptySubject(SecCertificateRef cert
, CFTypeRef pvcValue
) {
137 /* If the certificate has a subject, or
138 if it doesn't, and it's the leaf and not self signed,
139 and also has a critical subjectAltName extension it's valid. */
140 if (!SecCertificateHasSubject(cert
)) {
141 Boolean isSelfSigned
= true;
142 SecCertificateIsSelfSigned(cert
, &isSelfSigned
);
144 if (!SecCertificateHasCriticalSubjectAltName(cert
)) {
145 /* Leaf certificate with empty subject does not have
146 a critical subject alt name extension. */
150 /* CA certificate has empty subject. */
158 /* This one is different from SecPolicyCheckQualifiedCertStatements because
159 both are empty stubs. */
160 static bool SecPolicyCheckCertQualifiedCertStatements(SecCertificateRef __unused cert
,
161 CFTypeRef __unused pvcValue
) {
166 /* We have a wildcard reference identifier that looks like "*." followed by 2 or
167 more labels. Use CFNetwork's function for determining if those labels comprise
168 a top-level domain. We need to dlopen since CFNetwork is a client of ours. */
169 typedef bool (*CFNIsTLD_f
)(CFStringRef domain
);
170 static bool SecDNSIsTLD(CFStringRef reference
) {
171 bool result
= false; /* fail open for allocation and symbol lookup failures */
172 static CFNIsTLD_f CFNIsDomainTopLevelFunctionPtr
= NULL
;
173 static dispatch_once_t onceToken
;
174 CFStringRef presentedDomain
= NULL
;
176 dispatch_once(&onceToken
, ^{
177 void *framework
= dlopen("/System/Library/Frameworks/CFNetwork.framework/CFNetwork", RTLD_LAZY
);
179 CFNIsDomainTopLevelFunctionPtr
= dlsym(framework
, "_CFHostIsDomainTopLevel");
183 require_quiet(CFNIsDomainTopLevelFunctionPtr
, out
);
184 CFIndex referenceLen
= CFStringGetLength(reference
);
186 /* reference identifier is too short, we should fail it */
187 require_action_quiet(referenceLen
> 2, out
, result
= true);
189 require_quiet(presentedDomain
= CFStringCreateWithSubstring(NULL
, reference
,
190 CFRangeMake(2, referenceLen
- 2)),
192 result
= CFNIsDomainTopLevelFunctionPtr(presentedDomain
);
195 CFReleaseNull(presentedDomain
);
200 /* Compare hostname, to a server name obtained from the server's cert
201 Obtained from the SubjectAltName or the CommonName entry in the Subject.
202 Limited wildcard checking is performed here as outlined in RFC 6125
205 We adhere to the (SHOULD NOT) guidance in rules 1 and 2, and we choose
206 never to accept partial-label wildcards even though they are allowed by
209 We use the language from RFC 6125, particularly the following definitions:
211 presented identifier: An identifier that is presented by a server to
212 a client within a PKIX certificate when the client attempts to
213 establish secure communication with the server; the certificate
214 can include one or more presented identifiers of different types,
215 and if the server hosts more than one domain then the certificate
216 might present distinct identifiers for each domain.
218 reference identifier: An identifier, constructed from a source
219 domain and optionally an application service type, used by the
220 client for matching purposes when examining presented identifiers.
223 static bool SecDNSMatch(CFStringRef reference
, CFStringRef presented
) {
224 CFArrayRef referenceLabels
= NULL
, presentedLabels
= NULL
;
227 /* A trailing '.' in the reference identifier is allowed as a mechanism
228 to force TLS renegotiation. Strip it before parsing labels. */
229 CFIndex referenceLen
= CFStringGetLength(reference
);
230 require_quiet(referenceLen
> 0, noMatch
);
231 if ('.' == CFStringGetCharacterAtIndex(reference
, referenceLen
- 1)) {
232 CFStringRef truncatedReference
= CFStringCreateWithSubstring(NULL
, reference
,
233 CFRangeMake(0, referenceLen
- 1));
234 referenceLabels
= CFStringCreateArrayBySeparatingStrings(NULL
, truncatedReference
, CFSTR("."));
235 CFReleaseNull(truncatedReference
);
236 require_quiet(referenceLabels
, noMatch
);
238 require_quiet(referenceLabels
= CFStringCreateArrayBySeparatingStrings(NULL
, reference
, CFSTR(".")),
242 require_quiet(presentedLabels
= CFStringCreateArrayBySeparatingStrings(NULL
, presented
, CFSTR(".")),
245 /* Reference Identifier and Presented Identifier must have the same number of labels
246 because a wildcard in the presented identifier can only match a single label in the
247 reference identifier. */
248 require_quiet(CFArrayGetCount(referenceLabels
) == CFArrayGetCount(presentedLabels
), noMatch
);
250 CFIndex ix
, count
= CFArrayGetCount(referenceLabels
);
251 for (ix
= count
- 1; ix
>= 0; ix
--) {
252 CFStringRef rlabel
= NULL
, plabel
= NULL
;
253 require_quiet(rlabel
= CFArrayGetValueAtIndex(referenceLabels
, ix
), noMatch
);
254 require_quiet(plabel
= CFArrayGetValueAtIndex(presentedLabels
, ix
), noMatch
);
255 if (CFEqual(plabel
, CFSTR("*"))) {
256 /* must only occur in left-most label */
257 require_quiet(ix
== 0, noMatch
);
259 /* must not occur before single-label TLD */
260 require_quiet(count
> 2 && ix
!= count
- 2, noMatch
);
262 // <rdar://26563617>, check removed due to <rdar://26552669>
263 /* must not occur before a multi-label gTLD */
264 require_quiet(!SecDNSIsTLD(presented
), noMatch
);
267 /* partial-label wildcards are disallowed */
268 CFRange partialRange
= CFStringFind(plabel
, CFSTR("*"), 0);
269 require_quiet(partialRange
.location
== kCFNotFound
&& partialRange
.length
== 0 ,
272 /* not a wildcard, so labels must match exactly */
273 require_quiet(CFStringCompare(rlabel
, plabel
, kCFCompareCaseInsensitive
) == kCFCompareEqualTo
, noMatch
);
280 CFReleaseNull(referenceLabels
);
281 CFReleaseNull(presentedLabels
);
285 bool SecPolicyCheckCertSSLHostname(SecCertificateRef cert
, CFTypeRef pvcValue
) {
286 /* @@@ Consider what to do if the caller passes in no hostname. Should
287 we then still fail if the leaf has no dnsNames or IPAddresses at all? */
288 CFStringRef hostName
= pvcValue
;
289 if (!isString(hostName
)) {
290 /* @@@ We can't return an error here and making the evaluation fail
291 won't help much either. */
295 bool dnsMatch
= false;
296 CFArrayRef dnsNames
= SecCertificateCopyDNSNames(cert
);
298 CFIndex ix
, count
= CFArrayGetCount(dnsNames
);
299 for (ix
= 0; ix
< count
; ++ix
) {
300 CFStringRef dns
= (CFStringRef
)CFArrayGetValueAtIndex(dnsNames
, ix
);
301 if (SecDNSMatch(hostName
, dns
)) {
310 /* Maybe hostname is an IPv4 or IPv6 address, let's compare against
311 the values returned by SecCertificateCopyIPAddresses() instead. */
312 CFArrayRef ipAddresses
= SecCertificateCopyIPAddresses(cert
);
314 CFIndex ix
, count
= CFArrayGetCount(ipAddresses
);
315 for (ix
= 0; ix
< count
; ++ix
) {
316 CFStringRef ipAddress
= (CFStringRef
)CFArrayGetValueAtIndex(ipAddresses
, ix
);
317 if (!CFStringCompare(hostName
, ipAddress
, kCFCompareCaseInsensitive
)) {
322 CFRelease(ipAddresses
);
329 bool SecPolicyCheckCertEmail(SecCertificateRef cert
, CFTypeRef pvcValue
) {
330 CFStringRef email
= pvcValue
;
332 if (!isString(email
)) {
333 /* We can't return an error here and making the evaluation fail
334 won't help much either. */
338 CFArrayRef addrs
= SecCertificateCopyRFC822Names(cert
);
340 CFIndex ix
, count
= CFArrayGetCount(addrs
);
341 for (ix
= 0; ix
< count
; ++ix
) {
342 CFStringRef addr
= (CFStringRef
)CFArrayGetValueAtIndex(addrs
, ix
);
343 if (!CFStringCompare(email
, addr
, kCFCompareCaseInsensitive
)) {
354 static bool SecPolicyCheckCertValidLeaf(SecCertificateRef cert
, CFTypeRef pvcValue
) {
355 CFAbsoluteTime verifyTime
= CFDateGetAbsoluteTime(pvcValue
);
356 if (!SecCertificateIsValid(cert
, verifyTime
)) {
357 /* Leaf certificate has expired. */
363 bool SecPolicyCheckCertSubjectCommonNamePrefix(SecCertificateRef cert
, CFTypeRef pvcValue
) {
364 CFStringRef prefix
= pvcValue
;
366 if (!isString(prefix
)) {
367 /* @@@ We can't return an error here and making the evaluation fail
368 won't help much either. */
371 CFArrayRef commonNames
= SecCertificateCopyCommonNames(cert
);
372 if (!commonNames
|| CFArrayGetCount(commonNames
) != 1 ||
373 !CFStringHasPrefix(CFArrayGetValueAtIndex(commonNames
, 0), prefix
)) {
374 /* Common Name prefix mismatch. */
377 CFReleaseSafe(commonNames
);
381 bool SecPolicyCheckCertSubjectCommonName(SecCertificateRef cert
, CFTypeRef pvcValue
) {
382 CFStringRef common_name
= pvcValue
;
384 if (!isString(common_name
)) {
385 /* @@@ We can't return an error here and making the evaluation fail
386 won't help much either. */
389 CFArrayRef commonNames
= SecCertificateCopyCommonNames(cert
);
390 if (!commonNames
|| CFArrayGetCount(commonNames
) != 1 ||
391 !CFEqual(common_name
, CFArrayGetValueAtIndex(commonNames
, 0))) {
392 /* Common Name mismatch. */
395 CFReleaseSafe(commonNames
);
399 bool SecPolicyCheckCertSubjectCommonNameTEST(SecCertificateRef cert
, CFTypeRef pvcValue
) {
400 CFStringRef common_name
= pvcValue
;
402 if (!isString(common_name
)) {
403 /* @@@ We can't return an error here and making the evaluation fail
404 won't help much either. */
407 CFArrayRef commonNames
= SecCertificateCopyCommonNames(cert
);
408 if (!commonNames
|| CFArrayGetCount(commonNames
) != 1) {
409 CFStringRef cert_common_name
= CFArrayGetValueAtIndex(commonNames
, 0);
410 CFStringRef test_common_name
= common_name
?
411 CFStringCreateWithFormat(kCFAllocatorDefault
,
412 NULL
, CFSTR("TEST %@ TEST"), common_name
) :
414 if (!CFEqual(common_name
, cert_common_name
) &&
415 (!test_common_name
|| !CFEqual(test_common_name
, cert_common_name
)))
416 /* Common Name mismatch. */
418 CFReleaseSafe(test_common_name
);
420 CFReleaseSafe(commonNames
);
424 bool SecPolicyCheckCertNotValidBefore(SecCertificateRef cert
, CFTypeRef pvcValue
) {
425 CFDateRef date
= pvcValue
;
427 /* @@@ We can't return an error here and making the evaluation fail
428 won't help much either. */
431 CFAbsoluteTime at
= CFDateGetAbsoluteTime(date
);
432 if (SecCertificateNotValidBefore(cert
) <= at
) {
433 /* Leaf certificate has not valid before that is too old. */
439 bool SecPolicyCheckCertSubjectOrganization(SecCertificateRef cert
, CFTypeRef pvcValue
) {
440 CFStringRef org
= pvcValue
;
442 if (!isString(org
)) {
443 /* @@@ We can't return an error here and making the evaluation fail
444 won't help much either. */
447 CFArrayRef organization
= SecCertificateCopyOrganization(cert
);
448 if (!organization
|| CFArrayGetCount(organization
) != 1 ||
449 !CFEqual(org
, CFArrayGetValueAtIndex(organization
, 0))) {
450 /* Leaf Subject Organization mismatch. */
453 CFReleaseSafe(organization
);
457 bool SecPolicyCheckCertSubjectOrganizationalUnit(SecCertificateRef cert
, CFTypeRef pvcValue
) {
458 CFStringRef orgUnit
= pvcValue
;
460 if (!isString(orgUnit
)) {
461 /* @@@ We can't return an error here and making the evaluation fail
462 won't help much either. */
465 CFArrayRef organizationalUnit
= SecCertificateCopyOrganizationalUnit(cert
);
466 if (!organizationalUnit
|| CFArrayGetCount(organizationalUnit
) != 1 ||
467 !CFEqual(orgUnit
, CFArrayGetValueAtIndex(organizationalUnit
, 0))) {
468 /* Leaf Subject Organizational Unit mismatch. */
471 CFReleaseSafe(organizationalUnit
);
475 bool SecPolicyCheckCertEAPTrustedServerNames(SecCertificateRef cert
, CFTypeRef pvcValue
) {
476 CFArrayRef trustedServerNames
= pvcValue
;
477 /* No names specified means we accept any name. */
478 if (!trustedServerNames
)
480 if (!isArray(trustedServerNames
)) {
481 /* @@@ We can't return an error here and making the evaluation fail
482 won't help much either. */
486 CFIndex tsnCount
= CFArrayGetCount(trustedServerNames
);
487 bool dnsMatch
= false;
488 CFArrayRef dnsNames
= SecCertificateCopyDNSNames(cert
);
490 CFIndex ix
, count
= CFArrayGetCount(dnsNames
);
491 // @@@ This is O(N^2) unfortunately we can't do better easily unless
492 // we don't do wildcard matching. */
493 for (ix
= 0; !dnsMatch
&& ix
< count
; ++ix
) {
494 CFStringRef dns
= (CFStringRef
)CFArrayGetValueAtIndex(dnsNames
, ix
);
496 for (tix
= 0; tix
< tsnCount
; ++tix
) {
497 CFStringRef serverName
=
498 (CFStringRef
)CFArrayGetValueAtIndex(trustedServerNames
, tix
);
499 if (!isString(serverName
)) {
500 /* @@@ We can't return an error here and making the
501 evaluation fail won't help much either. */
502 CFReleaseSafe(dnsNames
);
505 /* we purposefully reverse the arguments here such that dns names
506 from the cert are matched against a server name list, where
507 the server names list can contain wildcards and the dns name
508 cannot. References: http://support.microsoft.com/kb/941123
509 It's easy to find occurrences where people tried to use
510 wildcard certificates and were told that those don't work
512 if (SecDNSMatch(dns
, serverName
)) {
524 bool SecPolicyCheckCertLeafMarkerOid(SecCertificateRef cert
, CFTypeRef pvcValue
) {
525 if (pvcValue
&& SecCertificateHasMarkerExtension(cert
, pvcValue
)) {
532 bool SecPolicyCheckCertLeafMarkerOidWithoutValueCheck(SecCertificateRef cert
,
533 CFTypeRef pvcValue
) {
534 if (CFGetTypeID(pvcValue
) == CFArrayGetTypeID()) {
535 CFIndex ix
, length
= CFArrayGetCount(pvcValue
);
536 for (ix
= 0; ix
< length
; ix
++)
537 if (SecPolicyCheckCertLeafMarkerOidWithoutValueCheck(cert
,
538 CFArrayGetValueAtIndex((CFArrayRef
)pvcValue
, ix
))) {
541 } else if (CFGetTypeID(pvcValue
) == CFDataGetTypeID() ||
542 CFGetTypeID(pvcValue
) == CFStringGetTypeID()) {
543 return (NULL
!= SecCertificateGetExtensionValue(cert
, pvcValue
));
548 static CFSetRef
copyCertificatePolicies(SecCertificateRef cert
) {
549 CFMutableSetRef policies
= NULL
;
550 policies
= CFSetCreateMutable(NULL
, 0, &kCFTypeSetCallBacks
);
551 if (!policies
) return NULL
;
553 const SecCECertificatePolicies
*cp
= SecCertificateGetCertificatePolicies(cert
);
554 size_t policy_ix
, policy_count
= cp
? cp
->numPolicies
: 0;
555 for (policy_ix
= 0; policy_ix
< policy_count
; ++policy_ix
) {
556 CFDataRef oidData
= NULL
;
557 DERItem
*policyOID
= &cp
->policies
[policy_ix
].policyIdentifier
;
558 oidData
= CFDataCreate(kCFAllocatorDefault
, policyOID
->data
, policyOID
->length
);
559 CFSetAddValue(policies
, oidData
);
560 CFReleaseSafe(oidData
);
565 static bool checkPolicyOidData(SecCertificateRef cert
, CFDataRef oid
) {
566 CFSetRef policies
= copyCertificatePolicies(cert
);
568 if (policies
&& CFSetContainsValue(policies
, oid
)) {
571 CFReleaseSafe(policies
);
575 /* This one is different from SecPolicyCheckCertificatePolicyOid because
576 that one checks the whole chain. (And uses policy_set_t...) */
577 static bool SecPolicyCheckCertCertificatePolicyOid(SecCertificateRef cert
, CFTypeRef pvcValue
) {
578 CFTypeRef value
= pvcValue
;
581 if (CFGetTypeID(value
) == CFDataGetTypeID())
583 result
= checkPolicyOidData(cert
, value
);
584 } else if (CFGetTypeID(value
) == CFStringGetTypeID()) {
585 CFDataRef dataOid
= SecCertificateCreateOidDataFromString(NULL
, value
);
587 result
= checkPolicyOidData(cert
, dataOid
);
594 static bool SecPolicyCheckCertWeak(SecCertificateRef cert
, CFTypeRef __unused pvcValue
) {
595 if (cert
&& SecCertificateIsWeakKey(cert
)) {
596 /* Leaf certificate has a weak key. */
602 static bool SecPolicyCheckCertKeySize(SecCertificateRef cert
, CFTypeRef pvcValue
) {
603 CFDictionaryRef keySizes
= pvcValue
;
604 if (!SecCertificateIsAtLeastMinKeySize(cert
, keySizes
)) {
610 static CFStringRef
convertSignatureHashAlgorithm(SecSignatureHashAlgorithm algorithmEnum
) {
611 const void *digests
[] = { kSecSignatureDigestAlgorithmUnknown
,
612 kSecSignatureDigestAlgorithmMD2
,
613 kSecSignatureDigestAlgorithmMD4
,
614 kSecSignatureDigestAlgorithmMD5
,
615 kSecSignatureDigestAlgorithmSHA1
,
616 kSecSignatureDigestAlgorithmSHA224
,
617 kSecSignatureDigestAlgorithmSHA256
,
618 kSecSignatureDigestAlgorithmSHA384
,
619 kSecSignatureDigestAlgorithmSHA512
,
621 return digests
[algorithmEnum
];
624 bool SecPolicyCheckCertSignatureHashAlgorithms(SecCertificateRef cert
, CFTypeRef pvcValue
) {
625 CFSetRef disallowedHashAlgorithms
= pvcValue
;
626 CFStringRef certAlg
= convertSignatureHashAlgorithm(SecCertificateGetSignatureHashAlgorithm(cert
));
627 if (CFSetContainsValue(disallowedHashAlgorithms
, certAlg
)) {
634 * MARK: SecLeafPVC functions
636 static CFDictionaryRef
SecLeafPVCCopyCallbacks(void) {
637 CFMutableDictionaryRef leafCallbacks
= NULL
;
638 leafCallbacks
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0,
639 &kCFTypeDictionaryKeyCallBacks
, NULL
);
640 CFDictionaryAddValue(leafCallbacks
,
641 kSecPolicyCheckCriticalExtensions
,
642 SecPolicyCheckCertCriticalExtensions
);
643 CFDictionaryAddValue(leafCallbacks
,
644 kSecPolicyCheckKeyUsage
,
645 SecPolicyCheckCertKeyUsage
);
646 CFDictionaryAddValue(leafCallbacks
,
647 kSecPolicyCheckExtendedKeyUsage
,
648 SecPolicyCheckCertExtendedKeyUsage
);
649 CFDictionaryAddValue(leafCallbacks
,
650 kSecPolicyCheckNonEmptySubject
,
651 SecPolicyCheckCertNonEmptySubject
);
652 CFDictionaryAddValue(leafCallbacks
,
653 kSecPolicyCheckQualifiedCertStatements
,
654 SecPolicyCheckCertQualifiedCertStatements
);
655 CFDictionaryAddValue(leafCallbacks
,
656 kSecPolicyCheckSSLHostname
,
657 SecPolicyCheckCertSSLHostname
);
658 CFDictionaryAddValue(leafCallbacks
,
659 kSecPolicyCheckEmail
,
660 SecPolicyCheckCertEmail
);
661 CFDictionaryAddValue(leafCallbacks
,
662 kSecPolicyCheckValidLeaf
,
663 SecPolicyCheckCertValidLeaf
);
664 CFDictionaryAddValue(leafCallbacks
,
665 kSecPolicyCheckSubjectCommonNamePrefix
,
666 SecPolicyCheckCertSubjectCommonNamePrefix
);
667 CFDictionaryAddValue(leafCallbacks
,
668 kSecPolicyCheckSubjectCommonName
,
669 SecPolicyCheckCertSubjectCommonName
);
670 CFDictionaryAddValue(leafCallbacks
,
671 kSecPolicyCheckNotValidBefore
,
672 SecPolicyCheckCertNotValidBefore
);
673 CFDictionaryAddValue(leafCallbacks
,
674 kSecPolicyCheckSubjectOrganization
,
675 SecPolicyCheckCertSubjectOrganization
);
676 CFDictionaryAddValue(leafCallbacks
,
677 kSecPolicyCheckSubjectOrganizationalUnit
,
678 SecPolicyCheckCertSubjectOrganizationalUnit
);
679 CFDictionaryAddValue(leafCallbacks
,
680 kSecPolicyCheckEAPTrustedServerNames
,
681 SecPolicyCheckCertEAPTrustedServerNames
);
682 CFDictionaryAddValue(leafCallbacks
,
683 kSecPolicyCheckSubjectCommonNameTEST
,
684 SecPolicyCheckCertSubjectCommonNameTEST
);
685 CFDictionaryAddValue(leafCallbacks
,
686 kSecPolicyCheckLeafMarkerOid
,
687 SecPolicyCheckCertLeafMarkerOid
);
688 CFDictionaryAddValue(leafCallbacks
,
689 kSecPolicyCheckLeafMarkerOidWithoutValueCheck
,
690 SecPolicyCheckCertLeafMarkerOidWithoutValueCheck
);
691 CFDictionaryAddValue(leafCallbacks
,
692 kSecPolicyCheckCertificatePolicy
,
693 SecPolicyCheckCertCertificatePolicyOid
);
694 CFDictionaryAddValue(leafCallbacks
,
695 kSecPolicyCheckWeakLeaf
,
696 SecPolicyCheckCertWeak
);
697 CFDictionaryAddValue(leafCallbacks
,
698 kSecPolicyCheckKeySize
,
699 SecPolicyCheckCertKeySize
);
700 CFDictionaryAddValue(leafCallbacks
,
701 kSecPolicyCheckSignatureHashAlgorithms
,
702 SecPolicyCheckCertSignatureHashAlgorithms
);
704 return leafCallbacks
;
707 void SecLeafPVCInit(SecLeafPVCRef pvc
, SecCertificateRef leaf
, CFArrayRef policies
,
708 CFAbsoluteTime verifyTime
) {
709 secdebug("alloc", "%p", pvc
);
710 // Weird logging policies crashes.
711 //secdebug("policy", "%@", policies);
712 pvc
->leaf
= CFRetainSafe(leaf
);
713 pvc
->policies
= CFRetainSafe(policies
);
714 pvc
->verifyTime
= verifyTime
;
715 pvc
->callbacks
= SecLeafPVCCopyCallbacks();
719 CFMutableDictionaryRef certDetail
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeDictionaryKeyCallBacks
,
720 &kCFTypeDictionaryValueCallBacks
);
721 pvc
->details
= CFArrayCreate(kCFAllocatorDefault
, (const void **)&certDetail
, 1,
722 &kCFTypeArrayCallBacks
);
723 CFRelease(certDetail
);
727 void SecLeafPVCDelete(SecLeafPVCRef pvc
) {
728 secdebug("alloc", "%p", pvc
);
729 CFReleaseNull(pvc
->policies
);
730 CFReleaseNull(pvc
->details
);
731 CFReleaseNull(pvc
->callbacks
);
732 CFReleaseNull(pvc
->leaf
);
735 static bool SecLeafPVCSetResultForced(SecLeafPVCRef pvc
,
736 CFStringRef key
, CFIndex ix
, CFTypeRef result
, bool force
) {
738 secdebug("policy", "cert[%d]: %@ =(%s)[%s]> %@", (int) ix
, key
, "leaf",
739 (force
? "force" : ""), result
);
741 /* If this is not something the current policy cares about ignore
742 this error and return true so our caller continues evaluation. */
744 /* @@@ The right long term fix might be to check if none of the passed
745 in policies contain this key, since not all checks are run for all
747 SecPolicyRef policy
= (SecPolicyRef
)CFArrayGetValueAtIndex(pvc
->policies
, pvc
->policyIX
);
748 if (policy
&& !CFDictionaryContainsKey(policy
->_options
, key
))
752 /* @@@ Check to see if the SecTrustSettings for the certificate in question
753 tell us to ignore this error. */
758 CFMutableDictionaryRef detail
=
759 (CFMutableDictionaryRef
)CFArrayGetValueAtIndex(pvc
->details
, ix
);
761 /* Perhaps detail should have an array of results per key? As it stands
762 in the case of multiple policy failures the last failure stands. */
763 CFDictionarySetValue(detail
, key
, result
);
768 static bool SecLeafPVCSetResult(SecLeafPVCRef pvc
,
769 CFStringRef key
, CFIndex ix
, CFTypeRef result
) {
770 return SecLeafPVCSetResultForced(pvc
, key
, ix
, result
, false);
773 static void SecLeafPVCValidateKey(const void *key
, const void *value
,
775 SecLeafPVCRef pvc
= (SecLeafPVCRef
)context
;
777 /* If our caller doesn't want full details and we failed earlier there is
778 no point in doing additional checks. */
779 if (!pvc
->result
&& !pvc
->details
)
782 SecPolicyCheckCertFunction fcn
= (SecPolicyCheckCertFunction
) CFDictionaryGetValue(pvc
->callbacks
, key
);
788 /* kSecPolicyCheckValidLeaf is special */
789 if (CFEqual(key
, kSecPolicyCheckValidLeaf
)) {
790 CFDateRef verifyDate
= CFDateCreate(NULL
, pvc
->verifyTime
);
791 if(!fcn(pvc
->leaf
, verifyDate
)) {
792 SecLeafPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
);
794 CFReleaseSafe(verifyDate
);
796 /* get pvcValue from current policy */
797 SecPolicyRef policy
= (SecPolicyRef
)CFArrayGetValueAtIndex(pvc
->policies
, pvc
->policyIX
);
802 CFTypeRef pvcValue
= (CFTypeRef
)CFDictionaryGetValue(policy
->_options
, key
);
803 if(!fcn(pvc
->leaf
, pvcValue
)) {
804 SecLeafPVCSetResult(pvc
, key
, 0, kCFBooleanFalse
);
809 bool SecLeafPVCLeafChecks(SecLeafPVCRef pvc
) {
811 CFArrayRef policies
= pvc
->policies
;
812 CFIndex ix
, count
= CFArrayGetCount(policies
);
813 for (ix
= 0; ix
< count
; ++ix
) {
814 SecPolicyRef policy
= (SecPolicyRef
)CFArrayGetValueAtIndex(policies
, ix
);
816 /* Validate all keys for all policies. */
817 CFDictionaryApplyFunction(policy
->_options
, SecLeafPVCValidateKey
, pvc
);
818 if (!pvc
->result
&& !pvc
->details
)