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