]> git.saurik.com Git - apple/security.git/blob - sec/Security/SecPolicy.c
Security-55163.44.tar.gz
[apple/security.git] / sec / Security / SecPolicy.c
1 /*
2 * Copyright (c) 2007-2010 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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
11 * file.
12 *
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.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 /*
25 * SecPolicy.c - Implementation of various X.509 certificate trust policies
26 */
27
28 #include <Security/SecPolicyInternal.h>
29 #include <Security/SecPolicyPriv.h>
30 #include <AssertMacros.h>
31 #include <pthread.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>
40
41 /********************************************************
42 **************** SecPolicy Constants *******************
43 ********************************************************/
44 #pragma mark -
45 #pragma mark SecPolicy Constants
46
47 /********************************************************
48 ************** Unverified Leaf Checks ******************
49 ********************************************************/
50 CFStringRef kSecPolicyCheckSSLHostname = CFSTR("SSLHostname");
51
52 CFStringRef kSecPolicyCheckEmail = CFSTR("email");
53
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");
57
58 /* Checks that the leaf has exactly one Common Name and that it
59 matches the specified string. */
60 CFStringRef kSecPolicyCheckSubjectCommonName = CFSTR("SubjectCommonName");
61
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");
65
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");
69
70 /* Checks that the leaf has exactly one Organzation and that it
71 matches the specified string. */
72 CFStringRef kSecPolicyCheckSubjectOrganization = CFSTR("SubjectOrganization");
73
74 /* Check that the leaf is not valid before the specified date (or verifyDate
75 if none is provided?). */
76 CFStringRef kSecPolicyCheckNotValidBefore = CFSTR("NotValidBefore");
77
78 CFStringRef kSecPolicyCheckEAPTrustedServerNames = CFSTR("EAPTrustedServerNames");
79
80 #if 0
81 /* Check for basic constraints on leaf to be valid. (rfc5280 check) */
82 CFStringRef kSecPolicyCheckLeafBasicConstraints = CFSTR("LeafBasicContraints");
83 #endif
84
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) */
93
94 /********************************************************
95 ************** Unverified Anchor Checks ****************
96 ********************************************************/
97 CFStringRef kSecPolicyCheckAnchorSHA1 = CFSTR("AnchorSHA1");
98
99 /* Fake key for isAnchored check. */
100 CFStringRef kSecPolicyCheckAnchorTrusted = CFSTR("AnchorTrusted");
101
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) */
108 #if 0
109 CFStringRef kSecPolicyCheckValidityStarted = CFSTR("ValidStarted");
110 CFStringRef kSecPolicyCheckValidityExpired = CFSTR("ValidExpired");
111 #else
112 CFStringRef kSecPolicyCheckValidIntermediates = CFSTR("ValidIntermediates");
113 CFStringRef kSecPolicyCheckValidLeaf = CFSTR("ValidLeaf");
114 CFStringRef kSecPolicyCheckValidRoot = CFSTR("ValidRoot");
115 #endif
116
117
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");
125
126 /* Check that the certificate chain length matches the specificed CFNumberRef
127 length. */
128 CFStringRef kSecPolicyCheckChainLength = CFSTR("ChainLength");
129
130 /* (rfc5280 check) */
131 CFStringRef kSecPolicyCheckBasicCertificateProcessing =
132 CFSTR("BasicCertificateProcessing");
133
134 /********************************************************
135 ******************* Feature toggles ********************
136 ********************************************************/
137
138 /* Check revocation if specified. */
139 CFStringRef kSecPolicyCheckExtendedValidation = CFSTR("ExtendedValidation");
140 CFStringRef kSecPolicyCheckRevocation = CFSTR("Revocation");
141
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");
145
146 /* Hack to quickly blacklist certain certs. */
147 CFStringRef kSecPolicyCheckBlackListedLeaf = CFSTR("BlackListedLeaf");
148 CFStringRef kSecPolicyCheckBlackListedKey = CFSTR("BlackListedKey");
149
150 CFStringRef kSecPolicyCheckLeafMarkerOid = CFSTR("CheckLeafMarkerOid");
151 CFStringRef kSecPolicyCheckIntermediateMarkerOid = CFSTR("CheckIntermediateMarkerOid");
152
153 /* Policy names. */
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");
183
184 /* Policies will now change to multiple categories of checks.
185
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.
188
189 kSecPolicySLCheck Static Subscriber Certificate Checks
190 kSecPolicySICheck Static Subsidiary CA Checks
191 kSecPolicySACheck Static Anchor Checks
192
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.
200
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.
204
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.
214
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.
220
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.
222
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.
224
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.
229
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.
231
232
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.
234
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.
236
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.
238
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.
240
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.
242
243 We need to remember the best successful chain we find, where best is defined by: satisfies as many optional policies as possible.
244
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.
246
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.
248
249 Example sectrust operation in psuedocode:
250 */
251 #if 0
252 {
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})
260 }
261 propagate_subpolicy_results(builder, chain, details);
262 }
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)
266 {
267 /* Modify SecPathBuilderIsPartial() to
268 run builder_check(buildier, policies, kSecPolicySICheck) instead
269 of SecCertificateIsValid. Also rename considerExpired to
270 considerSIFailures.
271 */
272 foreach (policy in p_d) {
273 check_policy(builder, chain, policy, kSecPolicySICheck, depth);
274 }
275 /* Recalculate since the static checks might have added new dynamic
276 policies. */
277 d_p_d = dynamic_policies.at_depth(depth);
278 foreach (policy in d_p_d) {
279 check_policy(builder, chain, policy, kSecPolicySICheck, depth);
280 }
281 if (chain.is_anchored) {
282 foreach (policy in p_d) {
283 check_policy(builder, chain, policy, kSecPolicySACheck, depth);
284 }
285 foreach (policy in d_p_d) {
286 check_policy(builder, chain, policy, kSecPolicySACheck, depth);
287 }
288 foreach (policy in p_d) {
289 check_policy(builder, chain, policy, kSecPolicyDACheck, depth);
290 }
291 foreach (policy in d_p_d) {
292 check_policy(builder, chain, policy, kSecPolicyDACheck, depth);
293 }
294 }
295 foreach (policy in policies) {
296 check_policy(builder, chain, policy, kSecPolicySACheck, depth);
297 check_policy(builder, chain, policy, kSecPolicyDACheck, depth);
298 }
299 foreach (policy in policies{kSecPolicySDCheck}) {
300 }
301 }
302 }
303
304 check_policy(builder, chain, policy, check_class, details, depth) {
305 if (depth == 0) {
306 foreach(check in policy{check_class}) {
307 SecPolicyRunCheck(builder, chain, check, details);
308 }
309 } else {
310 depth--;
311 foreach (subpolicy in policy) {
312 if (!check_policy(builder, chain, subpolicy, check_class,
313 details{subpolicy.name}) && subpolicy.is_required, depth)
314 secpvcsetresult()
315 }
316 }
317 propagate_subpolicy_results(builder, chain, details);
318 }
319
320 #endif
321
322
323
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
328 };
329
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
333 };
334
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
338 };
339
340 #pragma mark -
341 #pragma mark SecPolicy
342 /********************************************************
343 ****************** SecPolicy object ********************
344 ********************************************************/
345
346 /* CFRuntime regsitration data. */
347 static pthread_once_t kSecPolicyRegisterClass = PTHREAD_ONCE_INIT;
348 static CFTypeID kSecPolicyTypeID = _kCFRuntimeNotATypeID;
349
350 static void SecPolicyDestroy(CFTypeRef cf) {
351 SecPolicyRef policy = (SecPolicyRef) cf;
352 CFRelease(policy->_oid);
353 CFRelease(policy->_options);
354 }
355
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);
361 }
362
363 static CFHashCode SecPolicyHash(CFTypeRef cf) {
364 SecPolicyRef policy = (SecPolicyRef) cf;
365
366 return CFHash(policy->_oid) + CFHash(policy->_options);
367 }
368
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);
376 CFRelease(typeStr);
377 CFStringAppend(desc, CFSTR(" >"));
378
379 return desc;
380 }
381
382 static void SecPolicyRegisterClass(void) {
383 static const CFRuntimeClass kSecPolicyClass = {
384 0, /* version */
385 "SecPolicy", /* class name */
386 NULL, /* init */
387 NULL, /* copy */
388 SecPolicyDestroy, /* dealloc */
389 SecPolicyEqual, /* equal */
390 SecPolicyHash, /* hash */
391 NULL, /* copyFormattingDesc */
392 SecPolicyDescribe /* copyDebugDesc */
393 };
394
395 kSecPolicyTypeID = _CFRuntimeRegisterClass(&kSecPolicyClass);
396 }
397
398 /* SecPolicy API functions. */
399 CFTypeID SecPolicyGetTypeID(void) {
400 pthread_once(&kSecPolicyRegisterClass, SecPolicyRegisterClass);
401 return kSecPolicyTypeID;
402 }
403
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
407 been checked.
408 */
409 SecPolicyRef SecPolicyCreate(CFStringRef oid, CFDictionaryRef options) {
410 SecPolicyRef result = NULL;
411
412 require(oid, errOut);
413 require(options, errOut);
414 require(result =
415 (SecPolicyRef)_CFRuntimeCreateInstance(kCFAllocatorDefault,
416 SecPolicyGetTypeID(),
417 sizeof(struct __SecPolicy) - sizeof(CFRuntimeBase), 0), errOut);
418
419 CFRetain(oid);
420 result->_oid = oid;
421 CFRetain(options);
422 result->_options = options;
423
424 errOut:
425 return result;
426 }
427
428 static CFArrayRef SecPolicyCopyArray(SecPolicyRef policy) {
429 const void *values[] = { policy->_oid, policy->_options };
430 return CFArrayCreate(kCFAllocatorDefault, values, 2, &kCFTypeArrayCallBacks);
431 }
432
433 static void serializePolicy(const void *value, void *context) {
434 CFTypeRef serializedPolicy = SecPolicyCopyArray((SecPolicyRef)value);
435 CFArrayAppendValue((CFMutableArrayRef)context, serializedPolicy);
436 CFRelease(serializedPolicy);
437 }
438
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);
446 errOut:
447 return result;
448 }
449
450 static void add_element(CFMutableDictionaryRef options, CFStringRef key,
451 CFTypeRef value) {
452 CFTypeRef old_value = CFDictionaryGetValue(options, key);
453 if (old_value) {
454 CFMutableArrayRef array;
455 if (CFGetTypeID(old_value) == CFArrayGetTypeID()) {
456 array = (CFMutableArrayRef)old_value;
457 } else {
458 array = CFArrayCreateMutable(kCFAllocatorDefault, 0,
459 &kCFTypeArrayCallBacks);
460 CFArrayAppendValue(array, old_value);
461 CFDictionarySetValue(options, key, array);
462 CFRelease(array);
463 }
464 CFArrayAppendValue(array, value);
465 } else {
466 CFDictionaryAddValue(options, key, value);
467 }
468 }
469
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);
474 if (eku) {
475 add_element(options, kSecPolicyCheckExtendedKeyUsage, eku);
476 CFRelease(eku);
477 }
478 }
479
480 static void add_ku(CFMutableDictionaryRef options, SecKeyUsage keyUsage) {
481 SInt32 dku = keyUsage;
482 CFNumberRef ku = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type,
483 &dku);
484 if (ku) {
485 add_element(options, kSecPolicyCheckKeyUsage, ku);
486 CFRelease(ku);
487 }
488 }
489
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);
494 if (oid_data) {
495 add_element(options, policy_key, oid_data);
496 CFRelease(oid_data);
497 }
498 }
499
500 //
501 // Routines for adding dictionary entries for policies.
502 //
503
504 // X.509, but missing validity requirements.
505 static void SecPolicyAddBasicCertOptions(CFMutableDictionaryRef options)
506 {
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);
513 }
514
515 static void SecPolicyAddBasicX509Options(CFMutableDictionaryRef options)
516 {
517 SecPolicyAddBasicCertOptions(options);
518 CFDictionaryAddValue(options, kSecPolicyCheckValidIntermediates, kCFBooleanTrue);
519 CFDictionaryAddValue(options, kSecPolicyCheckValidLeaf, kCFBooleanTrue);
520 CFDictionaryAddValue(options, kSecPolicyCheckValidRoot, kCFBooleanTrue);
521 }
522
523 static bool SecPolicyAddChainLengthOptions(CFMutableDictionaryRef options, CFIndex length)
524 {
525 bool result = false;
526 CFNumberRef lengthAsCF = NULL;
527
528 require(lengthAsCF = CFNumberCreate(kCFAllocatorDefault,
529 kCFNumberCFIndexType, &length), errOut);
530 CFDictionaryAddValue(options, kSecPolicyCheckChainLength, lengthAsCF);
531
532 result = true;
533
534 errOut:
535 CFReleaseSafe(lengthAsCF);
536 return result;
537 }
538
539 static bool SecPolicyAddAnchorSHA1Options(CFMutableDictionaryRef options,
540 const UInt8 anchorSha1[kSecPolicySHA1Size])
541 {
542 bool success = false;
543 CFDataRef anchorData = NULL;
544
545 require(anchorData = CFDataCreate(kCFAllocatorDefault, anchorSha1, kSecPolicySHA1Size), errOut);
546 CFDictionaryAddValue(options, kSecPolicyCheckAnchorSHA1, anchorData);
547
548 success = true;
549
550 errOut:
551 CFReleaseSafe(anchorData);
552 return success;
553 }
554
555 static bool SecPolicyAddAppleAnchorOptions(CFMutableDictionaryRef options)
556 {
557 return SecPolicyAddAnchorSHA1Options(options, kAppleCASHA1);
558 }
559
560
561 //
562 // Policy Creation Functions
563 //
564 SecPolicyRef SecPolicyCreateBasicX509(void) {
565 CFMutableDictionaryRef options = NULL;
566 SecPolicyRef result = NULL;
567
568 require(options = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
569 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks), errOut);
570
571 SecPolicyAddBasicX509Options(options);
572
573 require(result = SecPolicyCreate(kSecPolicyOIDBasicX509, options), errOut);
574
575 errOut:
576 CFReleaseSafe(options);
577 return result;
578 }
579
580 SecPolicyRef SecPolicyCreateSSL(Boolean server, CFStringRef hostname) {
581 CFMutableDictionaryRef options = NULL;
582 SecPolicyRef result = NULL;
583
584 require(options = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
585 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks), errOut);
586
587 SecPolicyAddBasicX509Options(options);
588
589 #if 0
590 CFDictionaryAddValue(options, kSecPolicyCheckKeyUsage,
591 kCFBooleanTrue);
592 #endif
593
594 if (hostname) {
595 CFDictionaryAddValue(options, kSecPolicyCheckSSLHostname, hostname);
596 }
597 CFDictionaryAddValue(options, kSecPolicyCheckBlackListedLeaf,
598 kCFBooleanTrue);
599
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. */
605
606 /* We always allow certification that specify oidAnyExtendedKeyUsage. */
607 add_eku(options, NULL); /* eku extension is optional */
608 add_eku(options, &oidAnyExtendedKeyUsage);
609 if (server) {
610 add_eku(options, &oidExtendedKeyUsageServerAuth);
611 add_eku(options, &oidExtendedKeyUsageMicrosoftSGC);
612 add_eku(options, &oidExtendedKeyUsageNetscapeSGC);
613 } else {
614 add_eku(options, &oidExtendedKeyUsageClientAuth);
615 }
616
617 require(result = SecPolicyCreate(
618 server ? kSecPolicyOIDSSLServer : kSecPolicyOIDSSLClient,
619 options), errOut);
620
621 errOut:
622 CFReleaseSafe(options);
623 return result;
624 }
625
626 SecPolicyRef SecPolicyCreateiPhoneActivation(void) {
627 CFMutableDictionaryRef options = NULL;
628 SecPolicyRef result = NULL;
629
630 require(options = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
631 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks), errOut);
632
633 SecPolicyAddBasicCertOptions(options);
634
635 #if 0
636 CFDictionaryAddValue(options, kSecPolicyCheckKeyUsage,
637 kCFBooleanTrue);
638 CFDictionaryAddValue(options, kSecPolicyCheckExtendedKeyUsage,
639 kCFBooleanTrue);
640 #endif
641
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"));
650
651 require(SecPolicyAddChainLengthOptions(options, 3), errOut);
652 require(SecPolicyAddAppleAnchorOptions(options), errOut);
653
654 require(result = SecPolicyCreate(kSecPolicyOIDiPhoneActivation, options),
655 errOut);
656
657 errOut:
658 CFReleaseSafe(options);
659 return result;
660 }
661
662 SecPolicyRef SecPolicyCreateiPhoneDeviceCertificate(void) {
663 CFMutableDictionaryRef options = NULL;
664 SecPolicyRef result = NULL;
665
666 require(options = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
667 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks), errOut);
668
669 SecPolicyAddBasicCertOptions(options);
670
671 #if 0
672 CFDictionaryAddValue(options, kSecPolicyCheckKeyUsage,
673 kCFBooleanTrue);
674 CFDictionaryAddValue(options, kSecPolicyCheckExtendedKeyUsage,
675 kCFBooleanTrue);
676 #endif
677
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"));
683
684 require(SecPolicyAddChainLengthOptions(options, 4), errOut);
685 require(SecPolicyAddAppleAnchorOptions(options), errOut);
686
687 require(result = SecPolicyCreate(kSecPolicyOIDiPhoneDeviceCertificate, options),
688 errOut);
689
690 errOut:
691 CFReleaseSafe(options);
692 return result;
693 }
694
695 SecPolicyRef SecPolicyCreateFactoryDeviceCertificate(void) {
696 CFMutableDictionaryRef options = NULL;
697 SecPolicyRef result = NULL;
698
699 require(options = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
700 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks), errOut);
701
702 SecPolicyAddBasicCertOptions(options);
703
704 #if 0
705 CFDictionaryAddValue(options, kSecPolicyCheckKeyUsage,
706 kCFBooleanTrue);
707 CFDictionaryAddValue(options, kSecPolicyCheckExtendedKeyUsage,
708 kCFBooleanTrue);
709 #endif
710
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);
714
715 require(result = SecPolicyCreate(kSecPolicyOIDFactoryDeviceCertificate, options),
716 errOut);
717
718 errOut:
719 CFReleaseSafe(options);
720 return result;
721 }
722
723 SecPolicyRef SecPolicyCreateiAP(void) {
724 CFMutableDictionaryRef options = NULL;
725 SecPolicyRef result = NULL;
726 CFTimeZoneRef tz = NULL;
727 CFDateRef date = NULL;
728
729 require(options = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
730 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks), errOut);
731
732 SecPolicyAddBasicCertOptions(options);
733
734 CFDictionaryAddValue(options, kSecPolicyCheckSubjectCommonNamePrefix,
735 CFSTR("IPA_"));
736
737 CFGregorianDate gd = {
738 2006,
739 5,
740 31,
741 0,
742 0,
743 0.0
744 };
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);
749
750 require(result = SecPolicyCreate(kSecPolicyOIDiAP, options),
751 errOut);
752
753 errOut:
754 CFReleaseSafe(date);
755 CFReleaseSafe(tz);
756 CFReleaseSafe(options);
757 return result;
758 }
759
760 SecPolicyRef SecPolicyCreateiTunesStoreURLBag(void) {
761 CFMutableDictionaryRef options = NULL;
762 SecPolicyRef result = NULL;
763
764
765 require(options = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
766 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks), errOut);
767
768 SecPolicyAddBasicCertOptions(options);
769
770 CFDictionaryAddValue(options, kSecPolicyCheckSubjectOrganization,
771 CFSTR("Apple Inc."));
772 CFDictionaryAddValue(options, kSecPolicyCheckSubjectCommonName,
773 CFSTR("iTunes Store URL Bag"));
774
775 require(SecPolicyAddChainLengthOptions(options, 2), errOut);
776 require(SecPolicyAddAnchorSHA1Options(options, kITMSCASHA1), errOut);
777
778 require(result = SecPolicyCreate(kSecPolicyOIDiTunesStoreURLBag, options), errOut);
779
780 errOut:
781 CFReleaseSafe(options);
782 return result;
783 }
784
785 SecPolicyRef SecPolicyCreateEAP(Boolean server, CFArrayRef trustedServerNames) {
786 CFMutableDictionaryRef options = NULL;
787 SecPolicyRef result = NULL;
788
789 require(options = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
790 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks), errOut);
791
792 SecPolicyAddBasicX509Options(options);
793
794 #if 0
795 CFDictionaryAddValue(options, kSecPolicyCheckKeyUsage,
796 kCFBooleanTrue);
797 CFDictionaryAddValue(options, kSecPolicyCheckExtendedKeyUsage,
798 kCFBooleanTrue);
799 #endif
800
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,
804 kCFBooleanTrue);
805 if (trustedServerNames) {
806 CFDictionaryAddValue(options, kSecPolicyCheckEAPTrustedServerNames, trustedServerNames);
807 }
808
809 require(result = SecPolicyCreate(
810 server ? kSecPolicyEAPServer : kSecPolicyEAPClient,
811 options), errOut);
812
813 errOut:
814 CFReleaseSafe(options);
815 return result;
816 }
817
818 SecPolicyRef SecPolicyCreateIPSec(Boolean server, CFStringRef hostname) {
819 CFMutableDictionaryRef options = NULL;
820 SecPolicyRef result = NULL;
821
822 require(options = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
823 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks), errOut);
824
825 SecPolicyAddBasicX509Options(options);
826
827 if (hostname) {
828 CFDictionaryAddValue(options, kSecPolicyCheckSSLHostname, hostname);
829 }
830
831 /* Require oidExtendedKeyUsageIPSec if Extended Keyusage Extention is
832 present. */
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
836 following EKUs:
837 ipsecEndSystem 1.3.6.1.5.5.7.3.5
838 and possibly even
839 ipsecTunnel 1.3.6.1.5.5.7.3.6
840 ipsecUser 1.3.6.1.5.5.7.3.7
841 */
842 //add_eku(options, NULL); /* eku extension is optional */
843 //add_eku(options, &oidAnyExtendedKeyUsage);
844 //add_eku(options, &oidExtendedKeyUsageIPSec);
845
846 require(result = SecPolicyCreate(
847 server ? kSecPolicyOIDIPSecServer : kSecPolicyOIDIPSecClient,
848 options), errOut);
849
850 errOut:
851 CFReleaseSafe(options);
852 return result;
853 }
854
855 SecPolicyRef SecPolicyCreateiPhoneApplicationSigning(void) {
856 CFMutableDictionaryRef options = NULL;
857 SecPolicyRef result = NULL;
858
859 require(options = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
860 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks), errOut);
861
862 SecPolicyAddBasicCertOptions(options);
863
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"));
872
873 require(SecPolicyAddChainLengthOptions(options, 3), errOut);
874 require(SecPolicyAddAppleAnchorOptions(options), errOut);
875
876 add_eku(options, NULL); /* eku extension is optional */
877 add_eku(options, &oidAnyExtendedKeyUsage);
878 add_eku(options, &oidExtendedKeyUsageCodeSigning);
879
880 require(result = SecPolicyCreate(kSecPolicyOIDiPhoneApplicationSigning, options),
881 errOut);
882
883 /* 1.2.840.113635.100.6.1.3, non-critical: DER:05:00 - application signing */
884
885 errOut:
886 CFReleaseSafe(options);
887 return result;
888 }
889
890 SecPolicyRef SecPolicyCreateiPhoneProfileApplicationSigning(void) {
891 CFMutableDictionaryRef options = NULL;
892 SecPolicyRef result = NULL;
893
894 require(options = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
895 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks), errOut);
896 CFDictionaryAddValue(options, kSecPolicyCheckRevocation, kCFBooleanFalse);
897 CFDictionaryAddValue(options, kSecPolicyCheckValidLeaf, kCFBooleanFalse);
898
899 require(result = SecPolicyCreate(kSecPolicyOIDiPhoneProfileApplicationSigning,
900 options), errOut);
901
902 errOut:
903 CFReleaseSafe(options);
904 return result;
905 }
906
907 SecPolicyRef SecPolicyCreateiPhoneProvisioningProfileSigning(void) {
908 CFMutableDictionaryRef options = NULL;
909 SecPolicyRef result = NULL;
910
911 require(options = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
912 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks), errOut);
913
914 SecPolicyAddBasicCertOptions(options);
915
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"));
924
925 require(SecPolicyAddChainLengthOptions(options, 3), errOut);
926 require(SecPolicyAddAppleAnchorOptions(options), errOut);
927
928 require(result = SecPolicyCreate(kSecPolicyOIDiPhoneProvisioningProfileSigning, options),
929 errOut);
930
931 /* 1.2.840.113635.100.6.2.2.1, non-critical: DER:05:00 - provisioning profile */
932
933 errOut:
934 CFReleaseSafe(options);
935 return result;
936 }
937
938 SecPolicyRef SecPolicyCreateOCSPSigner(void) {
939 CFMutableDictionaryRef options = NULL;
940 SecPolicyRef result = NULL;
941
942 require(options = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
943 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks), errOut);
944
945 SecPolicyAddBasicX509Options(options);
946
947 /* Require id-kp-OCSPSigning extendedKeyUsage to be present, not optional. */
948 add_eku(options, &oidExtendedKeyUsageOCSPSigning);
949
950 require(result = SecPolicyCreate(kSecPolicyOIDOCSPSigner, options), errOut);
951
952 errOut:
953 CFReleaseSafe(options);
954 return result;
955 }
956
957 SecPolicyRef SecPolicyCreateRevocation(void) {
958 CFMutableDictionaryRef options = NULL;
959 SecPolicyRef result = NULL;
960
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.
966 */
967 CFDictionaryAddValue(options, kSecPolicyCheckRevocation, kCFBooleanFalse);
968
969 require(result = SecPolicyCreate(kSecPolicyOIDRevocation, options), errOut);
970
971 errOut:
972 CFReleaseSafe(options);
973 return result;
974 }
975
976 SecPolicyRef SecPolicyCreateSMIME(CFIndex smimeUsage, CFStringRef email) {
977 CFMutableDictionaryRef options = NULL;
978 SecPolicyRef result = NULL;
979
980 require(options = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
981 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks), errOut);
982
983 SecPolicyAddBasicX509Options(options);
984
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);
990 }
991 if (smimeUsage & kSecKeyEncryptSMIMEUsage) {
992 add_ku(options, kSecKeyUsageKeyEncipherment);
993 }
994 if (smimeUsage & kSecDataEncryptSMIMEUsage) {
995 add_ku(options, kSecKeyUsageDataEncipherment);
996 }
997 if (smimeUsage & kSecKeyExchangeDecryptSMIMEUsage) {
998 add_ku(options, kSecKeyUsageKeyAgreement | kSecKeyUsageDecipherOnly);
999 }
1000 if (smimeUsage & kSecKeyExchangeEncryptSMIMEUsage) {
1001 add_ku(options, kSecKeyUsageKeyAgreement | kSecKeyUsageEncipherOnly);
1002 }
1003 if (smimeUsage & kSecKeyExchangeBothSMIMEUsage) {
1004 add_ku(options, kSecKeyUsageKeyAgreement | kSecKeyUsageEncipherOnly | kSecKeyUsageDecipherOnly);
1005 }
1006
1007 if (email) {
1008 CFDictionaryAddValue(options, kSecPolicyCheckEmail, email);
1009 }
1010
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);
1015
1016 require(result = SecPolicyCreate(kSecPolicyOIDSMIME, options), errOut);
1017
1018 errOut:
1019 CFReleaseSafe(options);
1020 return result;
1021 }
1022
1023 SecPolicyRef SecPolicyCreateCodeSigning(void) {
1024 CFMutableDictionaryRef options = NULL;
1025 SecPolicyRef result = NULL;
1026
1027 require(options = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
1028 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks), errOut);
1029
1030 SecPolicyAddBasicX509Options(options);
1031
1032 /* If the keuusage extension is present we accept it having either of
1033 these values. */
1034 add_ku(options, kSecKeyUsageDigitalSignature);
1035 add_ku(options, kSecKeyUsageNonRepudiation);
1036
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);
1043
1044 require(result = SecPolicyCreate(kSecPolicyOIDCodeSigning, options),
1045 errOut);
1046
1047 errOut:
1048 CFReleaseSafe(options);
1049 return result;
1050 }
1051
1052 /* Explicitly leave out empty subject/subjectaltname check */
1053 SecPolicyRef SecPolicyCreateLockdownPairing(void) {
1054 CFMutableDictionaryRef options = NULL;
1055 SecPolicyRef result = NULL;
1056
1057 require(options = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
1058 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks), errOut);
1059 //CFDictionaryAddValue(options, kSecPolicyCheckBasicCertificateProcessing,
1060 // kCFBooleanTrue);
1061 CFDictionaryAddValue(options, kSecPolicyCheckCriticalExtensions,
1062 kCFBooleanTrue);
1063 CFDictionaryAddValue(options, kSecPolicyCheckIdLinkage,
1064 kCFBooleanTrue);
1065 CFDictionaryAddValue(options, kSecPolicyCheckBasicContraints,
1066 kCFBooleanTrue);
1067 CFDictionaryAddValue(options, kSecPolicyCheckQualifiedCertStatements,
1068 kCFBooleanTrue);
1069
1070 require(result = SecPolicyCreate(kSecPolicyOIDLockdownPairing, options), errOut);
1071
1072 errOut:
1073 CFReleaseSafe(options);
1074 return result;
1075 }
1076
1077 SecPolicyRef SecPolicyCreateURLBag(void) {
1078 CFMutableDictionaryRef options = NULL;
1079 SecPolicyRef result = NULL;
1080
1081 require(options = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
1082 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks), errOut);
1083
1084 SecPolicyAddBasicCertOptions(options);
1085
1086 add_eku(options, &oidExtendedKeyUsageCodeSigning);
1087
1088 require(result = SecPolicyCreate(kSecPolicyOIDURLBag, options), errOut);
1089
1090 errOut:
1091 CFReleaseSafe(options);
1092 return result;
1093 }
1094
1095 static bool SecPolicyAddAppleCertificationAuthorityOptions(CFMutableDictionaryRef options, bool honorValidity)
1096 {
1097 bool success = false;
1098
1099 if (honorValidity)
1100 SecPolicyAddBasicX509Options(options);
1101 else
1102 SecPolicyAddBasicCertOptions(options);
1103
1104 #if 0
1105 CFDictionaryAddValue(options, kSecPolicyCheckKeyUsage,
1106 kCFBooleanTrue);
1107 CFDictionaryAddValue(options, kSecPolicyCheckExtendedKeyUsage,
1108 kCFBooleanTrue);
1109 #endif
1110
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"));
1116
1117 require(SecPolicyAddChainLengthOptions(options, 3), errOut);
1118 require(SecPolicyAddAppleAnchorOptions(options), errOut);
1119
1120 success = true;
1121
1122 errOut:
1123 return success;
1124 }
1125
1126 static SecPolicyRef SecPolicyCreateAppleCertificationAuthorityPolicy(CFStringRef policyOID, CFStringRef leafName, bool honorValidity)
1127 {
1128 CFMutableDictionaryRef options = NULL;
1129 SecPolicyRef result = NULL;
1130
1131 require(options = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
1132 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks), errOut);
1133
1134 require(SecPolicyAddAppleCertificationAuthorityOptions(options, honorValidity), errOut);
1135
1136 CFDictionaryAddValue(options, kSecPolicyCheckSubjectCommonName, leafName);
1137
1138 require(result = SecPolicyCreate(policyOID, options),
1139 errOut);
1140
1141 errOut:
1142 CFReleaseSafe(options);
1143 return result;
1144 }
1145
1146
1147 SecPolicyRef SecPolicyCreateOTATasking(void)
1148 {
1149 return SecPolicyCreateAppleCertificationAuthorityPolicy(kSecPolicyOIDOTATasking, CFSTR("OTA Task Signing"), true);
1150 }
1151
1152 SecPolicyRef SecPolicyCreateMobileAsset(void)
1153 {
1154 return SecPolicyCreateAppleCertificationAuthorityPolicy(kSecPolicyOIDMobileAsset, CFSTR("Asset Manifest Signing"), false);
1155 }
1156
1157 SecPolicyRef SecPolicyCreateAppleIDAuthorityPolicy(void)
1158 {
1159 SecPolicyRef result = NULL;
1160 CFMutableDictionaryRef options = NULL;
1161 require(options = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
1162 &kCFTypeDictionaryKeyCallBacks,
1163 &kCFTypeDictionaryValueCallBacks), out);
1164
1165 //Leaf appears to be a SSL only cert, so policy should expand on that policy
1166 SecPolicyAddBasicX509Options(options);
1167
1168 // Apple CA anchored
1169 require(SecPolicyAddAppleAnchorOptions(options), out);
1170
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);
1174
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);
1178
1179 require(result = SecPolicyCreate(kSecPolicyOIDAppleIDAuthority, options), out);
1180
1181 out:
1182 CFReleaseSafe(options);
1183 return result;
1184 }