]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_keychain/lib/SecImportExport.c
Security-59754.80.3.tar.gz
[apple/security.git] / OSX / libsecurity_keychain / lib / SecImportExport.c
1 /*
2 * Copyright (c) 2007-2014 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 #include <Security/SecBase.h>
25 #include <Security/SecBasePriv.h>
26 #include <Security/SecItem.h>
27 #include <Security/SecCertificate.h>
28 #include <Security/SecCertificatePriv.h>
29 #include <Security/SecIdentity.h>
30 #include <Security/SecIdentityPriv.h>
31 #include <Security/SecPolicy.h>
32 #include <Security/SecTrust.h>
33 #include <Security/SecKeyPriv.h>
34 #include <Security/SecInternal.h>
35
36 //#include <AssertMacros.h>
37 #include <CommonCrypto/CommonDigest.h>
38
39 //#include "p12import.h"
40 #include <Security/SecImportExportPriv.h>
41
42 #include <CoreFoundation/CFPriv.h>
43
44 const CFStringRef __nonnull kSecImportExportPassphrase = CFSTR("passphrase");
45 const CFStringRef __nonnull kSecImportExportKeychain = CFSTR("keychain");
46 const CFStringRef __nonnull kSecImportExportAccess = CFSTR("access");
47
48 const CFStringRef __nonnull kSecImportItemLabel = CFSTR("label");
49 const CFStringRef __nonnull kSecImportItemKeyID = CFSTR("keyid");
50 const CFStringRef __nonnull kSecImportItemTrust = CFSTR("trust");
51 const CFStringRef __nonnull kSecImportItemCertChain = CFSTR("chain");
52 const CFStringRef __nonnull kSecImportItemIdentity = CFSTR("identity");
53
54 #if 0
55 static void collect_certs(const void *key, const void *value, void *context)
56 {
57 if (!CFDictionaryContainsKey(value, CFSTR("key"))) {
58 CFDataRef cert_bytes = CFDictionaryGetValue(value, CFSTR("cert"));
59 if (!cert_bytes)
60 return;
61 SecCertificateRef cert =
62 SecCertificateCreateWithData(kCFAllocatorDefault, cert_bytes);
63 if (!cert)
64 return;
65 CFMutableArrayRef cert_array = (CFMutableArrayRef)context;
66 CFArrayAppendValue(cert_array, cert);
67 CFRelease(cert);
68 }
69 }
70
71 typedef struct {
72 CFMutableArrayRef identities;
73 CFArrayRef certs;
74 } build_trust_chains_context;
75
76 static void build_trust_chains(const void *key, const void *value,
77 void *context)
78 {
79 CFMutableDictionaryRef identity_dict = CFDictionaryCreateMutable(kCFAllocatorDefault,
80 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
81 SecKeyRef private_key = NULL;
82 SecCertificateRef cert = NULL;
83 SecIdentityRef identity = NULL;
84 SecPolicyRef policy = NULL;
85 CFMutableArrayRef cert_chain = NULL, eval_chain = NULL;
86 SecTrustRef trust = NULL;
87 build_trust_chains_context * a_build_trust_chains_context = (build_trust_chains_context*)context;
88
89 CFDataRef key_bytes = CFDictionaryGetValue(value, CFSTR("key"));
90 if(!key_bytes) goto out; //require(key_bytes, out);
91 CFDataRef cert_bytes = CFDictionaryGetValue(value, CFSTR("cert"));
92 if(!cert_bytes) goto out; //require(cert_bytes, out);
93
94 /* p12import only passes up rsa keys */
95 //FIXME: needs SecKeyCreateRSAPrivateKey implementation
96 //#if 0
97 // private_key = SecKeyCreateRSAPrivateKey(kCFAllocatorDefault,
98 // CFDataGetBytePtr(key_bytes), CFDataGetLength(key_bytes),
99 // kSecKeyEncodingPkcs1);
100 //#endif
101 if(!private_key) goto out; //require(private_key, out);
102 cert = SecCertificateCreateWithData(kCFAllocatorDefault, cert_bytes);
103 if(!cert) goto out; //require(cert, out);
104 identity = SecIdentityCreate(kCFAllocatorDefault, cert, private_key);
105 if(!identity) goto out; //require(identity, out);
106 CFDictionarySetValue(identity_dict, kSecImportItemIdentity, identity);
107
108 eval_chain = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
109 if(!eval_chain) goto out; //require(eval_chain, out);
110 CFArrayAppendValue(eval_chain, cert);
111 CFRange all_certs = { 0, CFArrayGetCount(a_build_trust_chains_context->certs) };
112 CFArrayAppendArray(eval_chain, a_build_trust_chains_context->certs, all_certs);
113 policy = SecPolicyCreateBasicX509();
114 if(!policy) goto out; //require(policy, out);
115 SecTrustResultType result;
116 SecTrustCreateWithCertificates(eval_chain, policy, &trust);
117 if(!trust) goto out; //require(trust, out);
118 SecTrustEvaluate(trust, &result);
119 CFDictionarySetValue(identity_dict, kSecImportItemTrust, trust);
120
121 cert_chain = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
122 if(!cert_chain) goto out; //require(cert_chain, out);
123 CFIndex cert_chain_length = SecTrustGetCertificateCount(trust);
124 int i;
125 for (i = 0; i < cert_chain_length; i++)
126 CFArrayAppendValue(cert_chain, SecTrustGetCertificateAtIndex(trust, i));
127 CFDictionarySetValue(identity_dict, kSecImportItemCertChain, cert_chain);
128
129 CFArrayAppendValue(a_build_trust_chains_context->identities, identity_dict);
130 out:
131 CFReleaseSafe(identity_dict);
132 CFReleaseSafe(identity);
133 CFReleaseSafe(private_key);
134 CFReleaseSafe(cert);
135 CFReleaseSafe(policy);
136 CFReleaseSafe(cert_chain);
137 CFReleaseSafe(eval_chain);
138 CFReleaseSafe(trust);
139 }
140 #endif // if 0
141
142 OSStatus SecPKCS12Import(CFDataRef pkcs12_data, CFDictionaryRef options, CFArrayRef *items)
143 {
144 if (_CFMZEnabled()) {
145 return SecPKCS12Import_ios(pkcs12_data, options, items);
146 }
147 // SecPKCS12Import is implemented on Mac OS X in terms of the existing
148 // SecKeychainItemImport API, which supports importing items into a
149 // specified keychain with initial access control settings for keys.
150 //
151 OSStatus status = errSecSuccess;
152 SecExternalFormat inputFormat = kSecFormatPKCS12;
153 SecExternalItemType itemType = kSecItemTypeAggregate;
154 SecItemImportExportFlags flags = 0; /* don't know if it's PEM armoured */
155 SecKeyImportExportParameters keyParams; /* filled in below... */
156 SecKeychainRef importKeychain = NULL;
157 SecAccessRef importAccess = NULL;
158 CFStringRef importPassword = NULL;
159 CFArrayRef tmpItems = NULL; /* items returned by SecKeychainItemImport */
160 CFMutableArrayRef certs = NULL; /* certificates imported by this function */
161 CFMutableArrayRef identities = NULL; /* items returned by this function */
162
163 if (options) {
164 importKeychain = (SecKeychainRef) CFDictionaryGetValue(options, kSecImportExportKeychain);
165 if (importKeychain)
166 CFRetain(importKeychain);
167 importAccess = (SecAccessRef) CFDictionaryGetValue(options, kSecImportExportAccess);
168 if (importAccess)
169 CFRetain(importAccess);
170 importPassword = (CFStringRef) CFDictionaryGetValue(options, kSecImportExportPassphrase);
171 if (importPassword)
172 CFRetain(importPassword);
173 }
174
175 if (!importKeychain) {
176 // SecKeychainItemImport requires a keychain, so use default
177 status = SecKeychainCopyDefault(&importKeychain);
178 }
179
180 memset(&keyParams, 0, sizeof(SecKeyImportExportParameters));
181 keyParams.version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION;
182 keyParams.passphrase = importPassword;
183 keyParams.accessRef = importAccess;
184
185 status = SecKeychainItemImport(pkcs12_data,
186 NULL, /* no filename */
187 &inputFormat,
188 &itemType,
189 flags,
190 &keyParams,
191 importKeychain,
192 &tmpItems);
193
194 // build an array of all non-identity certificates which were imported
195 if (!status) {
196 certs = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
197 CFIndex i, count = CFArrayGetCount(tmpItems);
198 for (i=0; i<count; i++) {
199 CFTypeRef anItem = (CFTypeRef)CFArrayGetValueAtIndex(tmpItems, i);
200 CFTypeID itemID = CFGetTypeID(anItem);
201 if (itemID == SecCertificateGetTypeID()) {
202 CFArrayAppendValue(certs, anItem);
203 }
204 }
205 }
206
207 // now build the output items (array of dictionaries)
208 if (!status) {
209 identities = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
210 CFIndex i, count = CFArrayGetCount(tmpItems);
211 for (i=0; i<count; i++) {
212 CFTypeRef anItem = (CFTypeRef)CFArrayGetValueAtIndex(tmpItems, i);
213 CFTypeID itemID = CFGetTypeID(anItem);
214 if (itemID == SecIdentityGetTypeID()) {
215 CFMutableDictionaryRef itemDict;
216 itemDict = CFDictionaryCreateMutable(kCFAllocatorDefault,
217 0,
218 &kCFTypeDictionaryKeyCallBacks,
219 &kCFTypeDictionaryValueCallBacks);
220
221 SecCertificateRef itemCert = NULL;
222 status = SecIdentityCopyCertificate((SecIdentityRef)anItem, &itemCert);
223
224 // label
225 if (!status) {
226 CFStringRef label = SecCertificateCopySubjectSummary(itemCert);
227 if (label) {
228 CFDictionaryAddValue(itemDict, kSecImportItemLabel, label);
229 CFRelease(label);
230 }
231 }
232
233 // key ID
234 if (!status) {
235 CFDataRef digest = SecCertificateCopyPublicKeySHA1Digest(itemCert);
236 if (digest) {
237 CFDictionaryAddValue(itemDict, kSecImportItemKeyID, digest);
238 CFRelease(digest);
239 }
240 }
241
242 // trust
243 SecTrustRef trust = NULL;
244 SecPolicyRef policy = SecPolicyCreateBasicX509();
245 CFMutableArrayRef certArray = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
246 CFArrayAppendValue(certArray, itemCert);
247 if (certs) {
248 CFArrayAppendArray(certArray, certs, CFRangeMake(0, CFArrayGetCount(certs)));
249 }
250 status = SecTrustCreateWithCertificates(certArray, policy, &trust);
251 if (policy) {
252 CFRelease(policy);
253 }
254 if (trust) {
255 CFDictionaryAddValue(itemDict, kSecImportItemTrust, trust);
256 CFRelease(trust);
257 }
258
259 // certificate chain
260 if (certArray) {
261 CFDictionaryAddValue(itemDict, kSecImportItemCertChain, certArray);
262 CFRelease(certArray);
263 }
264
265 // identity
266 CFDictionaryAddValue(itemDict, kSecImportItemIdentity, anItem);
267
268 if (itemCert)
269 CFRelease(itemCert);
270 CFArrayAppendValue(identities, itemDict);
271 CFRelease(itemDict);
272 }
273 }
274 }
275
276 if (items)
277 *items = identities;
278 else if (identities)
279 CFRelease(identities);
280
281 if (certs)
282 CFRelease(certs);
283 if (tmpItems)
284 CFRelease(tmpItems);
285 if (importKeychain)
286 CFRelease(importKeychain);
287 if (importAccess)
288 CFRelease(importAccess);
289 if (importPassword)
290 CFRelease(importPassword);
291
292 return status;
293
294 //FIXME: needs SecAsn1Coder implementation
295 #if 0
296 pkcs12_context context = {};
297 SecAsn1CoderCreate(&context.coder);
298 if (options)
299 context.passphrase = CFDictionaryGetValue(options, kSecImportExportPassphrase);
300 context.items = CFDictionaryCreateMutable(kCFAllocatorDefault,
301 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
302 int status = p12decode(&context, pkcs12_data);
303 if (!status) {
304 CFMutableArrayRef certs = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
305 CFDictionaryApplyFunction(context.items, collect_certs, certs);
306
307 CFMutableArrayRef identities = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
308 build_trust_chains_context a_build_trust_chains_context = { identities, certs };
309 CFDictionaryApplyFunction(context.items, build_trust_chains, &a_build_trust_chains_context);
310 CFReleaseSafe(certs);
311
312 /* ignoring certs that weren't picked up as part of the certchain for found keys */
313
314 *items = identities;
315 }
316
317 CFReleaseSafe(context.items);
318 SecAsn1CoderRelease(context.coder);
319
320 switch (status) {
321 case p12_noErr: return errSecSuccess;
322 case p12_passwordErr: return errSecAuthFailed;
323 case p12_decodeErr: return errSecDecode;
324 default: return errSecInternal;
325 };
326 return errSecSuccess;
327 #endif
328 }
329