2 * Copyright (c) 2007-2010 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 * SecPolicy.c - Implementation of various X.509 certificate trust policies
28 #include <Security/SecPolicyInternal.h>
29 #include <Security/SecPolicyPriv.h>
30 #include <AssertMacros.h>
32 #include <security_utilities/debugging.h>
33 #include <Security/SecInternal.h>
34 #include <CoreFoundation/CFNumber.h>
35 #include <CoreFoundation/CFRuntime.h>
36 #include <CoreFoundation/CFString.h>
37 #include <CoreFoundation/CFTimeZone.h>
38 #include <Security/SecCertificateInternal.h>
39 #include <libDER/oids.h>
41 /********************************************************
42 **************** SecPolicy Constants *******************
43 ********************************************************/
45 #pragma mark SecPolicy Constants
47 /********************************************************
48 ************** Unverified Leaf Checks ******************
49 ********************************************************/
50 CFStringRef kSecPolicyCheckSSLHostname
= CFSTR("SSLHostname");
52 CFStringRef kSecPolicyCheckEmail
= CFSTR("email");
54 /* Checks that the issuer of the leaf has exactly one Common Name and that it
55 matches the specified string. */
56 CFStringRef kSecPolicyCheckIssuerCommonName
= CFSTR("IssuerCommonName");
58 /* Checks that the leaf has exactly one Common Name and that it
59 matches the specified string. */
60 CFStringRef kSecPolicyCheckSubjectCommonName
= CFSTR("SubjectCommonName");
62 /* Checks that the leaf has exactly one Common Name and that it has the
63 specified string as a prefix. */
64 CFStringRef kSecPolicyCheckSubjectCommonNamePrefix
= CFSTR("SubjectCommonNamePrefix");
66 /* Checks that the leaf has exactly one Common Name and that it
67 matches the specified "<string>" or "TEST <string> TEST". */
68 CFStringRef kSecPolicyCheckSubjectCommonNameTEST
= CFSTR("SubjectCommonNameTEST");
70 /* Checks that the leaf has exactly one Organzation and that it
71 matches the specified string. */
72 CFStringRef kSecPolicyCheckSubjectOrganization
= CFSTR("SubjectOrganization");
74 /* Check that the leaf is not valid before the specified date (or verifyDate
75 if none is provided?). */
76 CFStringRef kSecPolicyCheckNotValidBefore
= CFSTR("NotValidBefore");
78 CFStringRef kSecPolicyCheckEAPTrustedServerNames
= CFSTR("EAPTrustedServerNames");
81 /* Check for basic constraints on leaf to be valid. (rfc5280 check) */
82 CFStringRef kSecPolicyCheckLeafBasicConstraints
= CFSTR("LeafBasicContraints");
85 /********************************************************
86 *********** Unverified Intermediate Checks *************
87 ********************************************************/
88 CFStringRef kSecPolicyCheckKeyUsage
= CFSTR("KeyUsage"); /* (rfc5280 check) */
89 CFStringRef kSecPolicyCheckExtendedKeyUsage
= CFSTR("ExtendedKeyUsage"); /* (rfc5280 check) */
90 CFStringRef kSecPolicyCheckBasicContraints
= CFSTR("BasicContraints"); /* (rfc5280 check) */
91 CFStringRef kSecPolicyCheckQualifiedCertStatements
=
92 CFSTR("QualifiedCertStatements"); /* (rfc5280 check) */
94 /********************************************************
95 ************** Unverified Anchor Checks ****************
96 ********************************************************/
97 CFStringRef kSecPolicyCheckAnchorSHA1
= CFSTR("AnchorSHA1");
99 /* Fake key for isAnchored check. */
100 CFStringRef kSecPolicyCheckAnchorTrusted
= CFSTR("AnchorTrusted");
102 /********************************************************
103 *********** Unverified Certificate Checks **************
104 ********************************************************/
105 /* Unverified Certificate Checks (any of the above) */
106 CFStringRef kSecPolicyCheckNonEmptySubject
= CFSTR("NonEmptySubject");
107 CFStringRef kSecPolicyCheckIdLinkage
= CFSTR("IdLinkage"); /* (rfc5280 check) */
109 CFStringRef kSecPolicyCheckValidityStarted
= CFSTR("ValidStarted");
110 CFStringRef kSecPolicyCheckValidityExpired
= CFSTR("ValidExpired");
112 CFStringRef kSecPolicyCheckValidIntermediates
= CFSTR("ValidIntermediates");
113 CFStringRef kSecPolicyCheckValidLeaf
= CFSTR("ValidLeaf");
114 CFStringRef kSecPolicyCheckValidRoot
= CFSTR("ValidRoot");
118 /********************************************************
119 **************** Verified Path Checks ******************
120 ********************************************************/
121 /* (rfc5280 check) Ideally we should dynamically track all the extensions
122 we processed for each certificate and fail this test if any critical
123 extensions remain. */
124 CFStringRef kSecPolicyCheckCriticalExtensions
= CFSTR("CriticalExtensions");
126 /* Check that the certificate chain length matches the specificed CFNumberRef
128 CFStringRef kSecPolicyCheckChainLength
= CFSTR("ChainLength");
130 /* (rfc5280 check) */
131 CFStringRef kSecPolicyCheckBasicCertificateProcessing
=
132 CFSTR("BasicCertificateProcessing");
134 /********************************************************
135 ******************* Feature toggles ********************
136 ********************************************************/
138 /* Check revocation if specified. */
139 CFStringRef kSecPolicyCheckExtendedValidation
= CFSTR("ExtendedValidation");
140 CFStringRef kSecPolicyCheckRevocation
= CFSTR("Revocation");
142 /* If present and true, we never go out to the network for anything
143 (OCSP, CRL or CA Issuer checking) but just used cached data instead. */
144 CFStringRef kSecPolicyCheckNoNetworkAccess
= CFSTR("NoNetworkAccess");
146 /* Hack to quickly blacklist certain certs. */
147 CFStringRef kSecPolicyCheckBlackListedLeaf
= CFSTR("BlackListedLeaf");
148 CFStringRef kSecPolicyCheckBlackListedKey
= CFSTR("BlackListedKey");
150 CFStringRef kSecPolicyCheckLeafMarkerOid
= CFSTR("CheckLeafMarkerOid");
151 CFStringRef kSecPolicyCheckIntermediateMarkerOid
= CFSTR("CheckIntermediateMarkerOid");
154 static CFStringRef kSecPolicyOIDBasicX509
= CFSTR("basicX509");
155 static CFStringRef kSecPolicyOIDSSLServer
= CFSTR("sslServer");
156 static CFStringRef kSecPolicyOIDSSLClient
= CFSTR("sslClient");
157 static CFStringRef kSecPolicyOIDiPhoneActivation
= CFSTR("iPhoneActivation");
158 static CFStringRef kSecPolicyOIDiPhoneDeviceCertificate
=
159 CFSTR("iPhoneDeviceCertificate");
160 static CFStringRef kSecPolicyOIDFactoryDeviceCertificate
=
161 CFSTR("FactoryDeviceCertificate");
162 static CFStringRef kSecPolicyOIDiAP
= CFSTR("iAP");
163 static CFStringRef kSecPolicyOIDiTunesStoreURLBag
= CFSTR("iTunesStoreURLBag");
164 static CFStringRef kSecPolicyEAPServer
= CFSTR("eapServer");
165 static CFStringRef kSecPolicyEAPClient
= CFSTR("eapClient");
166 static CFStringRef kSecPolicyOIDIPSecServer
= CFSTR("ipsecServer");
167 static CFStringRef kSecPolicyOIDIPSecClient
= CFSTR("ipsecClient");
168 static CFStringRef kSecPolicyOIDiPhoneApplicationSigning
=
169 CFSTR("iPhoneApplicationSigning");
170 static CFStringRef kSecPolicyOIDiPhoneProfileApplicationSigning
=
171 CFSTR("iPhoneProfileApplicationSigning");
172 static CFStringRef kSecPolicyOIDiPhoneProvisioningProfileSigning
=
173 CFSTR("iPhoneProvisioningProfileSigning");
174 static CFStringRef kSecPolicyOIDRevocation
= CFSTR("revocation");
175 static CFStringRef kSecPolicyOIDOCSPSigner
= CFSTR("OCSPSigner");
176 static CFStringRef kSecPolicyOIDSMIME
= CFSTR("SMIME");
177 static CFStringRef kSecPolicyOIDCodeSigning
= CFSTR("CodeSigning");
178 static CFStringRef kSecPolicyOIDLockdownPairing
= CFSTR("LockdownPairing");
179 static CFStringRef kSecPolicyOIDURLBag
= CFSTR("URLBag");
180 static CFStringRef kSecPolicyOIDOTATasking
= CFSTR("OTATasking");
181 static CFStringRef kSecPolicyOIDMobileAsset
= CFSTR("MobileAsset");
182 static CFStringRef kSecPolicyOIDAppleIDAuthority
= CFSTR("AppleIDAuthority");
184 /* Policies will now change to multiple categories of checks.
186 IDEA Store partial valid policy tree in each chain? Result tree pruning might make this not feasible unless you can pretend to prune the tree without actually deleting nodes and somehow still have shable nodes with parent chains (this assumes that chains will be built as cached things from the root down), and we can build something equivalent to rfc5280 in a tree of certs. So we need to maintain a cache of leaf->chain with this certificate as any_ca_cert->tree. Revocation status caching can be done in this cache as well, so maybe the cache should be in sqlite3, or at least written there before exit and querying of the cache could be done first on the in core (possibly CF or custom tree like structure) and secondarly on the sqlite3 backed store. We should choose the lowest memory footprint solution in my mind, while choosing a sqlite3 cache size that gives us a resonable io usage pattern.
187 NOTE no certificate can be an intermediate unless it is X.509V3 and it has a basicConstraints extension with isCA set to true. This can be used to classify certs for caching purposes.
189 kSecPolicySLCheck Static Subscriber Certificate Checks
190 kSecPolicySICheck Static Subsidiary CA Checks
191 kSecPolicySACheck Static Anchor Checks
193 kSecPolicyDLCheck Dynamic Subscriber Certificate Checks
194 kSecPolicyDICheck Dynamic Subsidiary CA Checks
195 kSecPolicyDACheck Dynamic Anchor Checks ? not yet needed other than to
196 possibly exclude in a exception template (but those should still be per
197 certificate --- i.o.w. exceptions (or a database backed multiple role/user
198 trust store of some sort) and policies are 2 different things and this
199 text is about policies.
201 All static checks are only allowed to consider the certificate in isolation,
202 just given the position in the chain or the cert (leaf, intermidate, root).
203 dynamic checks can make determinations about the chain as a whole.
205 Static Subscriber Certificate Checks will be done up front before the
206 chainbuilder is even instantiated. If they fail and details aren't required
207 by the client (if no exceptions were present for this certificate) we could
208 short circuit fail the evaluation.
209 IDEA: These checks can dynamically add new checks...[needs work]
210 ALTERNATIVE: A policy can have one or more sub-policies. Each sub-policy will be evaluated only after the parent policy succeeds. Subpolicies can be either required (making the parent policy fail) or optional making the parent policy succeed, but allowing the chainbuilder to continue building chains after an optional subpolicy failure in search of a chain for which the subpolicy also succeeded. Subpolicies can be dynamically added to the policy evaluation context tree (a tree with a node for every node in the certificate path. This tree however is from the leaf up stored in the SecCertificatePathRef objects themselves possibly - requiring a separate shared subtree of nodes for the underlying certificate state tree.) by a parent policy at any stage, since the subpolicy evaluation only starts after
211 will have a key in the info (or even details and make info client side generated from info to indicate the success or failure of optional subpolicies) tree the value of which is an
212 equivalent subtree from that level down. So SSL has EV as a subpolicy, but
213 EV dynamically enables the ocsp or crl or dcrl or any combination thereof subpolicies.
215 Static Subsidiary CA Checks will be used by the chain-builder to choose the
216 best parents to evaluate first. This feature is currently already implemented
217 but with a hardcoded is_valid(verifyTime) check. Instead we will evaluate all
218 Static Subsidiary CA Checks. The results of these checks for purposes of
219 generating details could be cached in the SecCertificatePathRefs themselves, or we can short circuit fail and recalc details on demand later.
221 Static Anchor Checks can do things like populate the chainbuilder level context value of the initial_valid_policy_tree with a particular anchors list of ev policies it represents or modify inputs to the policy itself.
223 Dynamic Subscriber Certificate Checks These can do things like check for EV policy conformance based on the valid_policy_tree at the end of the certificate evaluation, or based on things like the pathlen, etc. in the chain validation context.
225 Dynamic Subsidiary CA Checks might not be needed to have custom
226 implementations, since they are all done as part of the rfc5280 checks now.
227 This assumes that checks like issuer common name includes 'foo' are
228 implmented as Static Subscriber Certificate Checks instead.
230 Dynamic Anchor Checks might include EV type checks or chain validation context seeding as well, allthough we might be able to do them as static checks to seed the chain validation context instead.
233 Questions/Notes: Do we need to dynamically add new policies? If policy static checks fail and policy is optional we don't even run policy dynamic checks nor do we compute subpolicy values. So if the static check of the leaf for EV fails we skip the rest of the EV style checks and instead don't run the revocation subpolicy of the ev policy.
235 If an optional subpolicy s_p has a required subpolicy r_s_p. Then success of s_p will cause the entire chain evaluation to fail if r_s_p fails.
237 All policies static revocation checks are run at the appropriate phase in the evaluation. static leaf checks are done before chainbuilding even starts. static intermediate checks are done in the chainbuilder for each cadidate parent certificate. If all policies pass we check the signatures. We reject the whole chain if that step fails. Otherwise we add the path to builder->candidatePaths. If the top level policy or a required subpolicy or a required subpolicy of a successful subpolicy fails we stick the chain at the end of the expiredPaths, if one of the optional subpolicies fail, we stick the chain at the start of expiredPaths so it's considered first after all real candidatePaths have been processed.
239 Static revocation policy checks could check the passed in ocspresponses or even the local cache, though the latter is probably best left for the dynamic phase.
241 The same rules that apply above to the adding paths to candidatePaths v/s expiredPaths apply to dynamicpolicy checks, except that we don't remember failures anymore, we reject them.
243 We need to remember the best successful chain we find, where best is defined by: satisfies as many optional policies as possible.
245 Chain building ends when either we find a chain that matches all optional and required policies, or we run out of chains to build. Another case is if we run out of candiate paths but we already have a chain that matches at least the top level and required subpolicies. In that case we don't even consider any expiredPaths. Example: we find a valid SSL chain (top level policy), but no partial chain we constructed satisfied the static checks of the ev subpolicy, or the required revocation sub-subpolicy of the ev policy.
247 In order for this to work well with exceptions on subpolicies, we'd need to move the validation of exceptions to the server, something we'd do anyway if we had full on truststore. In this case exceptions would be live in the failure callback for a trust check.
249 Example sectrust operation in psuedocode:
253 new builder(verifyTime
, certificates
, anchors
, anchorsOnly
, policies
);
254 chain
= builder
.subscriber_only_chain
;
255 foreach (policy in policies
{kSecPolicySLCheck
}) {
256 foreach(check in policy
)
257 SecPolicyRunCheck(builder
, chain
, check
, details
);
258 foreach (subpolicy in policy
) {
259 check_policy(builder
, chain
, subpolicy
, details
{subpolicy
.name
})
261 propagate_subpolicy_results(builder
, chain
, details
);
263 while (chain
= builder
.next
) {
264 for (depth
= 0; p_d
= policies
.at_depth(depth
),
265 d_p_d
= dynamic_policies
.at_depth(depth
), p_d
|| d_p_d
; ++depth
)
267 /* Modify SecPathBuilderIsPartial() to
268 run builder_check(buildier, policies, kSecPolicySICheck) instead
269 of SecCertificateIsValid. Also rename considerExpired to
272 foreach (policy in p_d
) {
273 check_policy(builder
, chain
, policy
, kSecPolicySICheck
, depth
);
275 /* Recalculate since the static checks might have added new dynamic
277 d_p_d
= dynamic_policies
.at_depth(depth
);
278 foreach (policy in d_p_d
) {
279 check_policy(builder
, chain
, policy
, kSecPolicySICheck
, depth
);
281 if (chain
.is_anchored
) {
282 foreach (policy in p_d
) {
283 check_policy(builder
, chain
, policy
, kSecPolicySACheck
, depth
);
285 foreach (policy in d_p_d
) {
286 check_policy(builder
, chain
, policy
, kSecPolicySACheck
, depth
);
288 foreach (policy in p_d
) {
289 check_policy(builder
, chain
, policy
, kSecPolicyDACheck
, depth
);
291 foreach (policy in d_p_d
) {
292 check_policy(builder
, chain
, policy
, kSecPolicyDACheck
, depth
);
295 foreach (policy in policies
) {
296 check_policy(builder
, chain
, policy
, kSecPolicySACheck
, depth
);
297 check_policy(builder
, chain
, policy
, kSecPolicyDACheck
, depth
);
299 foreach (policy in policies
{kSecPolicySDCheck
}) {
304 check_policy(builder
, chain
, policy
, check_class
, details
, depth
) {
306 foreach(check in policy
{check_class
}) {
307 SecPolicyRunCheck(builder
, chain
, check
, details
);
311 foreach (subpolicy in policy
) {
312 if (!check_policy(builder
, chain
, subpolicy
, check_class
,
313 details
{subpolicy
.name
}) && subpolicy
.is_required
, depth
)
317 propagate_subpolicy_results(builder
, chain
, details
);
324 #define kSecPolicySHA1Size 20
325 static const UInt8 kAppleCASHA1
[kSecPolicySHA1Size
] = {
326 0x61, 0x1E, 0x5B, 0x66, 0x2C, 0x59, 0x3A, 0x08, 0xFF, 0x58,
327 0xD1, 0x4A, 0xE2, 0x24, 0x52, 0xD1, 0x98, 0xDF, 0x6C, 0x60
330 static const UInt8 kITMSCASHA1
[kSecPolicySHA1Size
] = {
331 0x1D, 0x33, 0x42, 0x46, 0x8B, 0x10, 0xBD, 0xE6, 0x45, 0xCE,
332 0x44, 0x6E, 0xBB, 0xE8, 0xF5, 0x03, 0x5D, 0xF8, 0x32, 0x22
335 static const UInt8 kFactoryDeviceCASHA1
[kSecPolicySHA1Size
] = {
336 0xef, 0x68, 0x73, 0x17, 0xa4, 0xf8, 0xf9, 0x4b, 0x7b, 0x21,
337 0xe2, 0x2f, 0x09, 0x8f, 0xfd, 0x6a, 0xae, 0xc0, 0x0d, 0x63
341 #pragma mark SecPolicy
342 /********************************************************
343 ****************** SecPolicy object ********************
344 ********************************************************/
346 /* CFRuntime regsitration data. */
347 static pthread_once_t kSecPolicyRegisterClass
= PTHREAD_ONCE_INIT
;
348 static CFTypeID kSecPolicyTypeID
= _kCFRuntimeNotATypeID
;
350 static void SecPolicyDestroy(CFTypeRef cf
) {
351 SecPolicyRef policy
= (SecPolicyRef
) cf
;
352 CFRelease(policy
->_oid
);
353 CFRelease(policy
->_options
);
356 static Boolean
SecPolicyEqual(CFTypeRef cf1
, CFTypeRef cf2
) {
357 SecPolicyRef policy1
= (SecPolicyRef
) cf1
;
358 SecPolicyRef policy2
= (SecPolicyRef
) cf2
;
359 return CFEqual(policy1
->_oid
, policy2
->_oid
) &&
360 CFEqual(policy1
->_options
, policy2
->_options
);
363 static CFHashCode
SecPolicyHash(CFTypeRef cf
) {
364 SecPolicyRef policy
= (SecPolicyRef
) cf
;
366 return CFHash(policy
->_oid
) + CFHash(policy
->_options
);
369 static CFStringRef
SecPolicyDescribe(CFTypeRef cf
) {
370 SecPolicyRef policy
= (SecPolicyRef
) cf
;
371 CFMutableStringRef desc
= CFStringCreateMutable(kCFAllocatorDefault
, 0);
372 CFStringRef typeStr
= CFCopyTypeIDDescription(CFGetTypeID(cf
));
373 CFStringAppendFormat(desc
, NULL
,
374 CFSTR("<%@ %@: oid: %@ options %@"), typeStr
,
375 policy
->_oid
, policy
->_options
);
377 CFStringAppend(desc
, CFSTR(" >"));
382 static void SecPolicyRegisterClass(void) {
383 static const CFRuntimeClass kSecPolicyClass
= {
385 "SecPolicy", /* class name */
388 SecPolicyDestroy
, /* dealloc */
389 SecPolicyEqual
, /* equal */
390 SecPolicyHash
, /* hash */
391 NULL
, /* copyFormattingDesc */
392 SecPolicyDescribe
/* copyDebugDesc */
395 kSecPolicyTypeID
= _CFRuntimeRegisterClass(&kSecPolicyClass
);
398 /* SecPolicy API functions. */
399 CFTypeID
SecPolicyGetTypeID(void) {
400 pthread_once(&kSecPolicyRegisterClass
, SecPolicyRegisterClass
);
401 return kSecPolicyTypeID
;
404 /* AUDIT[securityd](done):
405 oid (ok) is a caller providied string, only it's cf type has been checked.
406 options is a caller provided dictionary, only its cf type has
409 SecPolicyRef
SecPolicyCreate(CFStringRef oid
, CFDictionaryRef options
) {
410 SecPolicyRef result
= NULL
;
412 require(oid
, errOut
);
413 require(options
, errOut
);
415 (SecPolicyRef
)_CFRuntimeCreateInstance(kCFAllocatorDefault
,
416 SecPolicyGetTypeID(),
417 sizeof(struct __SecPolicy
) - sizeof(CFRuntimeBase
), 0), errOut
);
422 result
->_options
= options
;
428 static CFArrayRef
SecPolicyCopyArray(SecPolicyRef policy
) {
429 const void *values
[] = { policy
->_oid
, policy
->_options
};
430 return CFArrayCreate(kCFAllocatorDefault
, values
, 2, &kCFTypeArrayCallBacks
);
433 static void serializePolicy(const void *value
, void *context
) {
434 CFTypeRef serializedPolicy
= SecPolicyCopyArray((SecPolicyRef
)value
);
435 CFArrayAppendValue((CFMutableArrayRef
)context
, serializedPolicy
);
436 CFRelease(serializedPolicy
);
439 CFArrayRef
SecPolicyArraySerialize(CFArrayRef policies
) {
440 CFMutableArrayRef result
= NULL
;
441 require_quiet(policies
&& CFGetTypeID(policies
) == CFArrayGetTypeID(), errOut
);
442 CFIndex count
= CFArrayGetCount(policies
);
443 result
= CFArrayCreateMutable(kCFAllocatorDefault
, count
, &kCFTypeArrayCallBacks
);
444 CFRange all_policies
= { 0, count
};
445 CFArrayApplyFunction(policies
, all_policies
, serializePolicy
, result
);
450 static void add_element(CFMutableDictionaryRef options
, CFStringRef key
,
452 CFTypeRef old_value
= CFDictionaryGetValue(options
, key
);
454 CFMutableArrayRef array
;
455 if (CFGetTypeID(old_value
) == CFArrayGetTypeID()) {
456 array
= (CFMutableArrayRef
)old_value
;
458 array
= CFArrayCreateMutable(kCFAllocatorDefault
, 0,
459 &kCFTypeArrayCallBacks
);
460 CFArrayAppendValue(array
, old_value
);
461 CFDictionarySetValue(options
, key
, array
);
464 CFArrayAppendValue(array
, value
);
466 CFDictionaryAddValue(options
, key
, value
);
470 static void add_eku(CFMutableDictionaryRef options
, const DERItem
*ekuOid
) {
471 CFDataRef eku
= CFDataCreate(kCFAllocatorDefault
,
472 ekuOid
? ekuOid
->data
: NULL
,
473 ekuOid
? ekuOid
->length
: 0);
475 add_element(options
, kSecPolicyCheckExtendedKeyUsage
, eku
);
480 static void add_ku(CFMutableDictionaryRef options
, SecKeyUsage keyUsage
) {
481 SInt32 dku
= keyUsage
;
482 CFNumberRef ku
= CFNumberCreate(kCFAllocatorDefault
, kCFNumberSInt32Type
,
485 add_element(options
, kSecPolicyCheckKeyUsage
, ku
);
490 static void add_oid(CFMutableDictionaryRef options
, CFStringRef policy_key
, const DERItem
*oid
) {
491 CFDataRef oid_data
= CFDataCreate(kCFAllocatorDefault
,
492 oid
? oid
->data
: NULL
,
493 oid
? oid
->length
: 0);
495 add_element(options
, policy_key
, oid_data
);
501 // Routines for adding dictionary entries for policies.
504 // X.509, but missing validity requirements.
505 static void SecPolicyAddBasicCertOptions(CFMutableDictionaryRef options
)
507 //CFDictionaryAddValue(options, kSecPolicyCheckBasicCertificateProcessing, kCFBooleanTrue);
508 CFDictionaryAddValue(options
, kSecPolicyCheckCriticalExtensions
, kCFBooleanTrue
);
509 CFDictionaryAddValue(options
, kSecPolicyCheckIdLinkage
, kCFBooleanTrue
);
510 CFDictionaryAddValue(options
, kSecPolicyCheckBasicContraints
, kCFBooleanTrue
);
511 CFDictionaryAddValue(options
, kSecPolicyCheckNonEmptySubject
, kCFBooleanTrue
);
512 CFDictionaryAddValue(options
, kSecPolicyCheckQualifiedCertStatements
, kCFBooleanTrue
);
515 static void SecPolicyAddBasicX509Options(CFMutableDictionaryRef options
)
517 SecPolicyAddBasicCertOptions(options
);
518 CFDictionaryAddValue(options
, kSecPolicyCheckValidIntermediates
, kCFBooleanTrue
);
519 CFDictionaryAddValue(options
, kSecPolicyCheckValidLeaf
, kCFBooleanTrue
);
520 CFDictionaryAddValue(options
, kSecPolicyCheckValidRoot
, kCFBooleanTrue
);
523 static bool SecPolicyAddChainLengthOptions(CFMutableDictionaryRef options
, CFIndex length
)
526 CFNumberRef lengthAsCF
= NULL
;
528 require(lengthAsCF
= CFNumberCreate(kCFAllocatorDefault
,
529 kCFNumberCFIndexType
, &length
), errOut
);
530 CFDictionaryAddValue(options
, kSecPolicyCheckChainLength
, lengthAsCF
);
535 CFReleaseSafe(lengthAsCF
);
539 static bool SecPolicyAddAnchorSHA1Options(CFMutableDictionaryRef options
,
540 const UInt8 anchorSha1
[kSecPolicySHA1Size
])
542 bool success
= false;
543 CFDataRef anchorData
= NULL
;
545 require(anchorData
= CFDataCreate(kCFAllocatorDefault
, anchorSha1
, kSecPolicySHA1Size
), errOut
);
546 CFDictionaryAddValue(options
, kSecPolicyCheckAnchorSHA1
, anchorData
);
551 CFReleaseSafe(anchorData
);
555 static bool SecPolicyAddAppleAnchorOptions(CFMutableDictionaryRef options
)
557 return SecPolicyAddAnchorSHA1Options(options
, kAppleCASHA1
);
562 // Policy Creation Functions
564 SecPolicyRef
SecPolicyCreateBasicX509(void) {
565 CFMutableDictionaryRef options
= NULL
;
566 SecPolicyRef result
= NULL
;
568 require(options
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0,
569 &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
), errOut
);
571 SecPolicyAddBasicX509Options(options
);
573 require(result
= SecPolicyCreate(kSecPolicyOIDBasicX509
, options
), errOut
);
576 CFReleaseSafe(options
);
580 SecPolicyRef
SecPolicyCreateSSL(Boolean server
, CFStringRef hostname
) {
581 CFMutableDictionaryRef options
= NULL
;
582 SecPolicyRef result
= NULL
;
584 require(options
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0,
585 &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
), errOut
);
587 SecPolicyAddBasicX509Options(options
);
590 CFDictionaryAddValue(options
, kSecPolicyCheckKeyUsage
,
595 CFDictionaryAddValue(options
, kSecPolicyCheckSSLHostname
, hostname
);
597 CFDictionaryAddValue(options
, kSecPolicyCheckBlackListedLeaf
,
600 /* If server and EKU ext present then EKU ext should contain one of
601 CSSMOID_ServerAuth or CSSMOID_ExtendedKeyUsageAny or
602 CSSMOID_NetscapeSGC or CSSMOID_MicrosoftSGC.
603 else if !server and EKU ext present then EKU ext should contain one of
604 CSSMOID_ClientAuth or CSSMOID_ExtendedKeyUsageAny. */
606 /* We always allow certification that specify oidAnyExtendedKeyUsage. */
607 add_eku(options
, NULL
); /* eku extension is optional */
608 add_eku(options
, &oidAnyExtendedKeyUsage
);
610 add_eku(options
, &oidExtendedKeyUsageServerAuth
);
611 add_eku(options
, &oidExtendedKeyUsageMicrosoftSGC
);
612 add_eku(options
, &oidExtendedKeyUsageNetscapeSGC
);
614 add_eku(options
, &oidExtendedKeyUsageClientAuth
);
617 require(result
= SecPolicyCreate(
618 server
? kSecPolicyOIDSSLServer
: kSecPolicyOIDSSLClient
,
622 CFReleaseSafe(options
);
626 SecPolicyRef
SecPolicyCreateiPhoneActivation(void) {
627 CFMutableDictionaryRef options
= NULL
;
628 SecPolicyRef result
= NULL
;
630 require(options
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0,
631 &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
), errOut
);
633 SecPolicyAddBasicCertOptions(options
);
636 CFDictionaryAddValue(options
, kSecPolicyCheckKeyUsage
,
638 CFDictionaryAddValue(options
, kSecPolicyCheckExtendedKeyUsage
,
642 /* Basic X.509 policy with the additional requirements that the chain
643 length is 3, it's anchored at the AppleCA and the leaf certificate
644 has issuer "Apple iPhone Certification Authority" and
645 subject "Apple iPhone Activation" for the common name. */
646 CFDictionaryAddValue(options
, kSecPolicyCheckIssuerCommonName
,
647 CFSTR("Apple iPhone Certification Authority"));
648 CFDictionaryAddValue(options
, kSecPolicyCheckSubjectCommonName
,
649 CFSTR("Apple iPhone Activation"));
651 require(SecPolicyAddChainLengthOptions(options
, 3), errOut
);
652 require(SecPolicyAddAppleAnchorOptions(options
), errOut
);
654 require(result
= SecPolicyCreate(kSecPolicyOIDiPhoneActivation
, options
),
658 CFReleaseSafe(options
);
662 SecPolicyRef
SecPolicyCreateiPhoneDeviceCertificate(void) {
663 CFMutableDictionaryRef options
= NULL
;
664 SecPolicyRef result
= NULL
;
666 require(options
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0,
667 &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
), errOut
);
669 SecPolicyAddBasicCertOptions(options
);
672 CFDictionaryAddValue(options
, kSecPolicyCheckKeyUsage
,
674 CFDictionaryAddValue(options
, kSecPolicyCheckExtendedKeyUsage
,
678 /* Basic X.509 policy with the additional requirements that the chain
679 length is 4, it's anchored at the AppleCA and the first intermediate
680 has the subject "Apple iPhone Device CA". */
681 CFDictionaryAddValue(options
, kSecPolicyCheckIssuerCommonName
,
682 CFSTR("Apple iPhone Device CA"));
684 require(SecPolicyAddChainLengthOptions(options
, 4), errOut
);
685 require(SecPolicyAddAppleAnchorOptions(options
), errOut
);
687 require(result
= SecPolicyCreate(kSecPolicyOIDiPhoneDeviceCertificate
, options
),
691 CFReleaseSafe(options
);
695 SecPolicyRef
SecPolicyCreateFactoryDeviceCertificate(void) {
696 CFMutableDictionaryRef options
= NULL
;
697 SecPolicyRef result
= NULL
;
699 require(options
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0,
700 &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
), errOut
);
702 SecPolicyAddBasicCertOptions(options
);
705 CFDictionaryAddValue(options
, kSecPolicyCheckKeyUsage
,
707 CFDictionaryAddValue(options
, kSecPolicyCheckExtendedKeyUsage
,
711 /* Basic X.509 policy with the additional requirements that the chain
712 is anchored at the factory device certificate issuer. */
713 require(SecPolicyAddAnchorSHA1Options(options
, kFactoryDeviceCASHA1
), errOut
);
715 require(result
= SecPolicyCreate(kSecPolicyOIDFactoryDeviceCertificate
, options
),
719 CFReleaseSafe(options
);
723 SecPolicyRef
SecPolicyCreateiAP(void) {
724 CFMutableDictionaryRef options
= NULL
;
725 SecPolicyRef result
= NULL
;
726 CFTimeZoneRef tz
= NULL
;
727 CFDateRef date
= NULL
;
729 require(options
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0,
730 &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
), errOut
);
732 SecPolicyAddBasicCertOptions(options
);
734 CFDictionaryAddValue(options
, kSecPolicyCheckSubjectCommonNamePrefix
,
737 CFGregorianDate gd
= {
745 require(tz
= CFTimeZoneCreateWithTimeIntervalFromGMT(NULL
, 0), errOut
);
746 CFAbsoluteTime at
= CFGregorianDateGetAbsoluteTime(gd
, tz
);
747 require(date
= CFDateCreate(kCFAllocatorDefault
, at
), errOut
);
748 CFDictionaryAddValue(options
, kSecPolicyCheckNotValidBefore
, date
);
750 require(result
= SecPolicyCreate(kSecPolicyOIDiAP
, options
),
756 CFReleaseSafe(options
);
760 SecPolicyRef
SecPolicyCreateiTunesStoreURLBag(void) {
761 CFMutableDictionaryRef options
= NULL
;
762 SecPolicyRef result
= NULL
;
765 require(options
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0,
766 &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
), errOut
);
768 SecPolicyAddBasicCertOptions(options
);
770 CFDictionaryAddValue(options
, kSecPolicyCheckSubjectOrganization
,
771 CFSTR("Apple Inc."));
772 CFDictionaryAddValue(options
, kSecPolicyCheckSubjectCommonName
,
773 CFSTR("iTunes Store URL Bag"));
775 require(SecPolicyAddChainLengthOptions(options
, 2), errOut
);
776 require(SecPolicyAddAnchorSHA1Options(options
, kITMSCASHA1
), errOut
);
778 require(result
= SecPolicyCreate(kSecPolicyOIDiTunesStoreURLBag
, options
), errOut
);
781 CFReleaseSafe(options
);
785 SecPolicyRef
SecPolicyCreateEAP(Boolean server
, CFArrayRef trustedServerNames
) {
786 CFMutableDictionaryRef options
= NULL
;
787 SecPolicyRef result
= NULL
;
789 require(options
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0,
790 &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
), errOut
);
792 SecPolicyAddBasicX509Options(options
);
795 CFDictionaryAddValue(options
, kSecPolicyCheckKeyUsage
,
797 CFDictionaryAddValue(options
, kSecPolicyCheckExtendedKeyUsage
,
801 /* Since EAP is used to setup the network we don't want evaluation
802 using this policy to access the network. */
803 CFDictionaryAddValue(options
, kSecPolicyCheckNoNetworkAccess
,
805 if (trustedServerNames
) {
806 CFDictionaryAddValue(options
, kSecPolicyCheckEAPTrustedServerNames
, trustedServerNames
);
809 require(result
= SecPolicyCreate(
810 server
? kSecPolicyEAPServer
: kSecPolicyEAPClient
,
814 CFReleaseSafe(options
);
818 SecPolicyRef
SecPolicyCreateIPSec(Boolean server
, CFStringRef hostname
) {
819 CFMutableDictionaryRef options
= NULL
;
820 SecPolicyRef result
= NULL
;
822 require(options
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0,
823 &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
), errOut
);
825 SecPolicyAddBasicX509Options(options
);
828 CFDictionaryAddValue(options
, kSecPolicyCheckSSLHostname
, hostname
);
831 /* Require oidExtendedKeyUsageIPSec if Extended Keyusage Extention is
833 /* Per <rdar://problem/6843827> Cisco VPN Certificate compatibility issue.
834 We don't check the EKU for IPSec certs for now. If we do add eku
835 checking back in the future, we should probably also accept the
837 ipsecEndSystem 1.3.6.1.5.5.7.3.5
839 ipsecTunnel 1.3.6.1.5.5.7.3.6
840 ipsecUser 1.3.6.1.5.5.7.3.7
842 //add_eku(options, NULL); /* eku extension is optional */
843 //add_eku(options, &oidAnyExtendedKeyUsage);
844 //add_eku(options, &oidExtendedKeyUsageIPSec);
846 require(result
= SecPolicyCreate(
847 server
? kSecPolicyOIDIPSecServer
: kSecPolicyOIDIPSecClient
,
851 CFReleaseSafe(options
);
855 SecPolicyRef
SecPolicyCreateiPhoneApplicationSigning(void) {
856 CFMutableDictionaryRef options
= NULL
;
857 SecPolicyRef result
= NULL
;
859 require(options
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0,
860 &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
), errOut
);
862 SecPolicyAddBasicCertOptions(options
);
864 /* Basic X.509 policy with the additional requirements that the chain
865 length is 3, it's anchored at the AppleCA and the leaf certificate
866 has issuer "Apple iPhone Certification Authority" and
867 subject "Apple iPhone OS Application Signing" for the common name. */
868 CFDictionaryAddValue(options
, kSecPolicyCheckIssuerCommonName
,
869 CFSTR("Apple iPhone Certification Authority"));
870 CFDictionaryAddValue(options
, kSecPolicyCheckSubjectCommonNameTEST
,
871 CFSTR("Apple iPhone OS Application Signing"));
873 require(SecPolicyAddChainLengthOptions(options
, 3), errOut
);
874 require(SecPolicyAddAppleAnchorOptions(options
), errOut
);
876 add_eku(options
, NULL
); /* eku extension is optional */
877 add_eku(options
, &oidAnyExtendedKeyUsage
);
878 add_eku(options
, &oidExtendedKeyUsageCodeSigning
);
880 require(result
= SecPolicyCreate(kSecPolicyOIDiPhoneApplicationSigning
, options
),
883 /* 1.2.840.113635.100.6.1.3, non-critical: DER:05:00 - application signing */
886 CFReleaseSafe(options
);
890 SecPolicyRef
SecPolicyCreateiPhoneProfileApplicationSigning(void) {
891 CFMutableDictionaryRef options
= NULL
;
892 SecPolicyRef result
= NULL
;
894 require(options
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0,
895 &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
), errOut
);
896 CFDictionaryAddValue(options
, kSecPolicyCheckRevocation
, kCFBooleanFalse
);
897 CFDictionaryAddValue(options
, kSecPolicyCheckValidLeaf
, kCFBooleanFalse
);
899 require(result
= SecPolicyCreate(kSecPolicyOIDiPhoneProfileApplicationSigning
,
903 CFReleaseSafe(options
);
907 SecPolicyRef
SecPolicyCreateiPhoneProvisioningProfileSigning(void) {
908 CFMutableDictionaryRef options
= NULL
;
909 SecPolicyRef result
= NULL
;
911 require(options
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0,
912 &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
), errOut
);
914 SecPolicyAddBasicCertOptions(options
);
916 /* Basic X.509 policy with the additional requirements that the chain
917 length is 3, it's anchored at the AppleCA and the leaf certificate
918 has issuer "Apple iPhone Certification Authority" and
919 subject "Apple iPhone OS Provisioning Profile Signing" for the common name. */
920 CFDictionaryAddValue(options
, kSecPolicyCheckIssuerCommonName
,
921 CFSTR("Apple iPhone Certification Authority"));
922 CFDictionaryAddValue(options
, kSecPolicyCheckSubjectCommonNameTEST
,
923 CFSTR("Apple iPhone OS Provisioning Profile Signing"));
925 require(SecPolicyAddChainLengthOptions(options
, 3), errOut
);
926 require(SecPolicyAddAppleAnchorOptions(options
), errOut
);
928 require(result
= SecPolicyCreate(kSecPolicyOIDiPhoneProvisioningProfileSigning
, options
),
931 /* 1.2.840.113635.100.6.2.2.1, non-critical: DER:05:00 - provisioning profile */
934 CFReleaseSafe(options
);
938 SecPolicyRef
SecPolicyCreateOCSPSigner(void) {
939 CFMutableDictionaryRef options
= NULL
;
940 SecPolicyRef result
= NULL
;
942 require(options
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0,
943 &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
), errOut
);
945 SecPolicyAddBasicX509Options(options
);
947 /* Require id-kp-OCSPSigning extendedKeyUsage to be present, not optional. */
948 add_eku(options
, &oidExtendedKeyUsageOCSPSigning
);
950 require(result
= SecPolicyCreate(kSecPolicyOIDOCSPSigner
, options
), errOut
);
953 CFReleaseSafe(options
);
957 SecPolicyRef
SecPolicyCreateRevocation(void) {
958 CFMutableDictionaryRef options
= NULL
;
959 SecPolicyRef result
= NULL
;
961 require(options
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0,
962 &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
), errOut
);
963 /* false = ocsp, true = crl, string/url value = crl distribution point,
964 array = list of multiple values for example false, true, url1, url2
965 check ocsp, crl, and url1 and url2 for certs which have no extensions.
967 CFDictionaryAddValue(options
, kSecPolicyCheckRevocation
, kCFBooleanFalse
);
969 require(result
= SecPolicyCreate(kSecPolicyOIDRevocation
, options
), errOut
);
972 CFReleaseSafe(options
);
976 SecPolicyRef
SecPolicyCreateSMIME(CFIndex smimeUsage
, CFStringRef email
) {
977 CFMutableDictionaryRef options
= NULL
;
978 SecPolicyRef result
= NULL
;
980 require(options
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0,
981 &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
), errOut
);
983 SecPolicyAddBasicX509Options(options
);
985 /* We call add_ku for each combination of bits we are willing to allow. */
986 if (smimeUsage
& kSecSignSMIMEUsage
) {
987 add_ku(options
, kSecKeyUsageUnspecified
);
988 add_ku(options
, kSecKeyUsageDigitalSignature
);
989 add_ku(options
, kSecKeyUsageNonRepudiation
);
991 if (smimeUsage
& kSecKeyEncryptSMIMEUsage
) {
992 add_ku(options
, kSecKeyUsageKeyEncipherment
);
994 if (smimeUsage
& kSecDataEncryptSMIMEUsage
) {
995 add_ku(options
, kSecKeyUsageDataEncipherment
);
997 if (smimeUsage
& kSecKeyExchangeDecryptSMIMEUsage
) {
998 add_ku(options
, kSecKeyUsageKeyAgreement
| kSecKeyUsageDecipherOnly
);
1000 if (smimeUsage
& kSecKeyExchangeEncryptSMIMEUsage
) {
1001 add_ku(options
, kSecKeyUsageKeyAgreement
| kSecKeyUsageEncipherOnly
);
1003 if (smimeUsage
& kSecKeyExchangeBothSMIMEUsage
) {
1004 add_ku(options
, kSecKeyUsageKeyAgreement
| kSecKeyUsageEncipherOnly
| kSecKeyUsageDecipherOnly
);
1008 CFDictionaryAddValue(options
, kSecPolicyCheckEmail
, email
);
1011 /* To be a valid SMIME certifcate we have to have an eku extension.
1012 * We only accept emailProtection (and not any) to make this policy
1013 * effective for selection in Mail. */
1014 add_eku(options
, &oidExtendedKeyUsageEmailProtection
);
1016 require(result
= SecPolicyCreate(kSecPolicyOIDSMIME
, options
), errOut
);
1019 CFReleaseSafe(options
);
1023 SecPolicyRef
SecPolicyCreateCodeSigning(void) {
1024 CFMutableDictionaryRef options
= NULL
;
1025 SecPolicyRef result
= NULL
;
1027 require(options
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0,
1028 &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
), errOut
);
1030 SecPolicyAddBasicX509Options(options
);
1032 /* If the keuusage extension is present we accept it having either of
1034 add_ku(options
, kSecKeyUsageDigitalSignature
);
1035 add_ku(options
, kSecKeyUsageNonRepudiation
);
1037 /* We require a extended key usage extension and we accept any or
1038 codesigning ekus. */
1039 /* TODO: Do we want to accept the apple codesigning oid as well or is
1040 that a separate policy? */
1041 add_eku(options
, &oidAnyExtendedKeyUsage
);
1042 add_eku(options
, &oidExtendedKeyUsageCodeSigning
);
1044 require(result
= SecPolicyCreate(kSecPolicyOIDCodeSigning
, options
),
1048 CFReleaseSafe(options
);
1052 /* Explicitly leave out empty subject/subjectaltname check */
1053 SecPolicyRef
SecPolicyCreateLockdownPairing(void) {
1054 CFMutableDictionaryRef options
= NULL
;
1055 SecPolicyRef result
= NULL
;
1057 require(options
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0,
1058 &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
), errOut
);
1059 //CFDictionaryAddValue(options, kSecPolicyCheckBasicCertificateProcessing,
1061 CFDictionaryAddValue(options
, kSecPolicyCheckCriticalExtensions
,
1063 CFDictionaryAddValue(options
, kSecPolicyCheckIdLinkage
,
1065 CFDictionaryAddValue(options
, kSecPolicyCheckBasicContraints
,
1067 CFDictionaryAddValue(options
, kSecPolicyCheckQualifiedCertStatements
,
1070 require(result
= SecPolicyCreate(kSecPolicyOIDLockdownPairing
, options
), errOut
);
1073 CFReleaseSafe(options
);
1077 SecPolicyRef
SecPolicyCreateURLBag(void) {
1078 CFMutableDictionaryRef options
= NULL
;
1079 SecPolicyRef result
= NULL
;
1081 require(options
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0,
1082 &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
), errOut
);
1084 SecPolicyAddBasicCertOptions(options
);
1086 add_eku(options
, &oidExtendedKeyUsageCodeSigning
);
1088 require(result
= SecPolicyCreate(kSecPolicyOIDURLBag
, options
), errOut
);
1091 CFReleaseSafe(options
);
1095 static bool SecPolicyAddAppleCertificationAuthorityOptions(CFMutableDictionaryRef options
, bool honorValidity
)
1097 bool success
= false;
1100 SecPolicyAddBasicX509Options(options
);
1102 SecPolicyAddBasicCertOptions(options
);
1105 CFDictionaryAddValue(options
, kSecPolicyCheckKeyUsage
,
1107 CFDictionaryAddValue(options
, kSecPolicyCheckExtendedKeyUsage
,
1111 /* Basic X.509 policy with the additional requirements that the chain
1112 length is 3, it's anchored at the AppleCA and the leaf certificate
1113 has issuer "Apple iPhone Certification Authority". */
1114 CFDictionaryAddValue(options
, kSecPolicyCheckIssuerCommonName
,
1115 CFSTR("Apple iPhone Certification Authority"));
1117 require(SecPolicyAddChainLengthOptions(options
, 3), errOut
);
1118 require(SecPolicyAddAppleAnchorOptions(options
), errOut
);
1126 static SecPolicyRef
SecPolicyCreateAppleCertificationAuthorityPolicy(CFStringRef policyOID
, CFStringRef leafName
, bool honorValidity
)
1128 CFMutableDictionaryRef options
= NULL
;
1129 SecPolicyRef result
= NULL
;
1131 require(options
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0,
1132 &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
), errOut
);
1134 require(SecPolicyAddAppleCertificationAuthorityOptions(options
, honorValidity
), errOut
);
1136 CFDictionaryAddValue(options
, kSecPolicyCheckSubjectCommonName
, leafName
);
1138 require(result
= SecPolicyCreate(policyOID
, options
),
1142 CFReleaseSafe(options
);
1147 SecPolicyRef
SecPolicyCreateOTATasking(void)
1149 return SecPolicyCreateAppleCertificationAuthorityPolicy(kSecPolicyOIDOTATasking
, CFSTR("OTA Task Signing"), true);
1152 SecPolicyRef
SecPolicyCreateMobileAsset(void)
1154 return SecPolicyCreateAppleCertificationAuthorityPolicy(kSecPolicyOIDMobileAsset
, CFSTR("Asset Manifest Signing"), false);
1157 SecPolicyRef
SecPolicyCreateAppleIDAuthorityPolicy(void)
1159 SecPolicyRef result
= NULL
;
1160 CFMutableDictionaryRef options
= NULL
;
1161 require(options
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0,
1162 &kCFTypeDictionaryKeyCallBacks
,
1163 &kCFTypeDictionaryValueCallBacks
), out
);
1165 //Leaf appears to be a SSL only cert, so policy should expand on that policy
1166 SecPolicyAddBasicX509Options(options
);
1168 // Apple CA anchored
1169 require(SecPolicyAddAppleAnchorOptions(options
), out
);
1171 // with the addition of the existence check of an extension with "Apple ID Sharing Certificate" oid (1.2.840.113635.100.4.7)
1172 // NOTE: this obviously intended to have gone into Extended Key Usage, but evidence of existing certs proves the contrary.
1173 add_oid(options
, kSecPolicyCheckLeafMarkerOid
, &oidAppleExtendedKeyUsageAppleID
);
1175 // and validate that intermediate has extension with CSSMOID_APPLE_EXTENSION_AAI_INTERMEDIATE oid (1.2.840.113635.100.6.2.3) and goes back to the Apple Root CA.
1176 add_oid(options
, kSecPolicyCheckIntermediateMarkerOid
, &oidAppleIntmMarkerAppleID
);
1177 add_oid(options
, kSecPolicyCheckIntermediateMarkerOid
, &oidAppleIntmMarkerAppleID2
);
1179 require(result
= SecPolicyCreate(kSecPolicyOIDAppleIDAuthority
, options
), out
);
1182 CFReleaseSafe(options
);