]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_keychain/Security/SecImportExport.c
Security-57336.1.9.tar.gz
[apple/security.git] / OSX / libsecurity_keychain / Security / 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/SecRSAKey.h>
28 #include <Security/SecCertificate.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 "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 SecKeyRef itemKey = NULL;
231 status = SecCertificateCopyPublicKey(itemCert, &itemKey);
232 if (!status) {
233 const CSSM_KEY *cssmKey;
234 status = SecKeyGetCSSMKey(itemKey, &cssmKey);
235 if (!status) {
236 unsigned char hash[CC_SHA1_DIGEST_LENGTH];
237 CC_SHA1(cssmKey->KeyData.Data, (CC_LONG)cssmKey->KeyData.Length, &hash[0]);
238 CFDataRef digest = CFDataCreate(NULL, (const UInt8 *)hash, CC_SHA1_DIGEST_LENGTH);
239 if (digest) {
240 CFDictionaryAddValue(itemDict, kSecImportItemKeyID, digest);
241 CFRelease(digest);
242 }
243 }
244 CFRelease(itemKey);
245 }
246 }
247
248 // trust
249 SecTrustRef trust = NULL;
250 SecPolicyRef policy = SecPolicyCreateBasicX509();
251 CFMutableArrayRef certArray = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
252 CFArrayAppendValue(certArray, itemCert);
253 if (certs) {
254 CFArrayAppendArray(certArray, certs, CFRangeMake(0, CFArrayGetCount(certs)));
255 }
256 status = SecTrustCreateWithCertificates(certArray, policy, &trust);
257 if (policy) {
258 CFRelease(policy);
259 }
260 if (trust) {
261 CFDictionaryAddValue(itemDict, kSecImportItemTrust, trust);
262 CFRelease(trust);
263 }
264
265 // certificate chain
266 if (certArray) {
267 CFDictionaryAddValue(itemDict, kSecImportItemCertChain, certArray);
268 CFRelease(certArray);
269 }
270
271 // identity
272 CFDictionaryAddValue(itemDict, kSecImportItemIdentity, anItem);
273
274 if (itemCert)
275 CFRelease(itemCert);
276 CFArrayAppendValue(identities, itemDict);
277 CFRelease(itemDict);
278 }
279 }
280 }
281
282 if (items)
283 *items = identities;
284 else if (identities)
285 CFRelease(identities);
286
287 if (certs)
288 CFRelease(certs);
289 if (tmpItems)
290 CFRelease(tmpItems);
291 if (importKeychain)
292 CFRelease(importKeychain);
293 if (importAccess)
294 CFRelease(importAccess);
295 if (importPassword)
296 CFRelease(importPassword);
297
298 return status;
299
300 //FIXME: needs SecAsn1Coder implementation
301 #if 0
302 pkcs12_context context = {};
303 SecAsn1CoderCreate(&context.coder);
304 if (options)
305 context.passphrase = CFDictionaryGetValue(options, kSecImportExportPassphrase);
306 context.items = CFDictionaryCreateMutable(kCFAllocatorDefault,
307 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
308 int status = p12decode(&context, pkcs12_data);
309 if (!status) {
310 CFMutableArrayRef certs = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
311 CFDictionaryApplyFunction(context.items, collect_certs, certs);
312
313 CFMutableArrayRef identities = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
314 build_trust_chains_context a_build_trust_chains_context = { identities, certs };
315 CFDictionaryApplyFunction(context.items, build_trust_chains, &a_build_trust_chains_context);
316 CFReleaseSafe(certs);
317
318 /* ignoring certs that weren't picked up as part of the certchain for found keys */
319
320 *items = identities;
321 }
322
323 CFReleaseSafe(context.items);
324 SecAsn1CoderRelease(context.coder);
325
326 switch (status) {
327 case p12_noErr: return errSecSuccess;
328 case p12_passwordErr: return errSecAuthFailed;
329 case p12_decodeErr: return errSecDecode;
330 default: return errSecInternal;
331 };
332 return errSecSuccess;
333 #endif
334 }
335