2 * Copyright (c) 2007-2014 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@
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>
36 //#include <AssertMacros.h>
37 #include <CommonCrypto/CommonDigest.h>
39 //#include "p12import.h"
40 #include <Security/SecImportExportPriv.h>
42 #include <CoreFoundation/CFPriv.h>
44 const CFStringRef __nonnull kSecImportExportPassphrase
= CFSTR("passphrase");
45 const CFStringRef __nonnull kSecImportExportKeychain
= CFSTR("keychain");
46 const CFStringRef __nonnull kSecImportExportAccess
= CFSTR("access");
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");
55 static void collect_certs(const void *key
, const void *value
, void *context
)
57 if (!CFDictionaryContainsKey(value
, CFSTR("key"))) {
58 CFDataRef cert_bytes
= CFDictionaryGetValue(value
, CFSTR("cert"));
61 SecCertificateRef cert
=
62 SecCertificateCreateWithData(kCFAllocatorDefault
, cert_bytes
);
65 CFMutableArrayRef cert_array
= (CFMutableArrayRef
)context
;
66 CFArrayAppendValue(cert_array
, cert
);
72 CFMutableArrayRef identities
;
74 } build_trust_chains_context
;
76 static void build_trust_chains(const void *key
, const void *value
,
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
;
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);
94 /* p12import only passes up rsa keys */
95 //FIXME: needs SecKeyCreateRSAPrivateKey implementation
97 // private_key = SecKeyCreateRSAPrivateKey(kCFAllocatorDefault,
98 // CFDataGetBytePtr(key_bytes), CFDataGetLength(key_bytes),
99 // kSecKeyEncodingPkcs1);
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
);
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
);
121 cert_chain
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
122 if(!cert_chain
) goto out
; //require(cert_chain, out);
123 CFIndex cert_chain_length
= SecTrustGetCertificateCount(trust
);
125 for (i
= 0; i
< cert_chain_length
; i
++)
126 CFArrayAppendValue(cert_chain
, SecTrustGetCertificateAtIndex(trust
, i
));
127 CFDictionarySetValue(identity_dict
, kSecImportItemCertChain
, cert_chain
);
129 CFArrayAppendValue(a_build_trust_chains_context
->identities
, identity_dict
);
131 CFReleaseSafe(identity_dict
);
132 CFReleaseSafe(identity
);
133 CFReleaseSafe(private_key
);
135 CFReleaseSafe(policy
);
136 CFReleaseSafe(cert_chain
);
137 CFReleaseSafe(eval_chain
);
138 CFReleaseSafe(trust
);
142 OSStatus
SecPKCS12Import(CFDataRef pkcs12_data
, CFDictionaryRef options
, CFArrayRef
*items
)
144 if (_CFMZEnabled()) {
145 return SecPKCS12Import_ios(pkcs12_data
, options
, items
);
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.
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 */
164 importKeychain
= (SecKeychainRef
) CFDictionaryGetValue(options
, kSecImportExportKeychain
);
166 CFRetain(importKeychain
);
167 importAccess
= (SecAccessRef
) CFDictionaryGetValue(options
, kSecImportExportAccess
);
169 CFRetain(importAccess
);
170 importPassword
= (CFStringRef
) CFDictionaryGetValue(options
, kSecImportExportPassphrase
);
172 CFRetain(importPassword
);
175 if (!importKeychain
) {
176 // SecKeychainItemImport requires a keychain, so use default
177 status
= SecKeychainCopyDefault(&importKeychain
);
180 memset(&keyParams
, 0, sizeof(SecKeyImportExportParameters
));
181 keyParams
.version
= SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION
;
182 keyParams
.passphrase
= importPassword
;
183 keyParams
.accessRef
= importAccess
;
185 status
= SecKeychainItemImport(pkcs12_data
,
186 NULL
, /* no filename */
194 // build an array of all non-identity certificates which were imported
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
);
207 // now build the output items (array of dictionaries)
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
,
218 &kCFTypeDictionaryKeyCallBacks
,
219 &kCFTypeDictionaryValueCallBacks
);
221 SecCertificateRef itemCert
= NULL
;
222 status
= SecIdentityCopyCertificate((SecIdentityRef
)anItem
, &itemCert
);
226 CFStringRef label
= SecCertificateCopySubjectSummary(itemCert
);
228 CFDictionaryAddValue(itemDict
, kSecImportItemLabel
, label
);
235 CFDataRef digest
= SecCertificateCopyPublicKeySHA1Digest(itemCert
);
237 CFDictionaryAddValue(itemDict
, kSecImportItemKeyID
, digest
);
243 SecTrustRef trust
= NULL
;
244 SecPolicyRef policy
= SecPolicyCreateBasicX509();
245 CFMutableArrayRef certArray
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
246 CFArrayAppendValue(certArray
, itemCert
);
248 CFArrayAppendArray(certArray
, certs
, CFRangeMake(0, CFArrayGetCount(certs
)));
250 status
= SecTrustCreateWithCertificates(certArray
, policy
, &trust
);
255 CFDictionaryAddValue(itemDict
, kSecImportItemTrust
, trust
);
261 CFDictionaryAddValue(itemDict
, kSecImportItemCertChain
, certArray
);
262 CFRelease(certArray
);
266 CFDictionaryAddValue(itemDict
, kSecImportItemIdentity
, anItem
);
270 CFArrayAppendValue(identities
, itemDict
);
279 CFRelease(identities
);
286 CFRelease(importKeychain
);
288 CFRelease(importAccess
);
290 CFRelease(importPassword
);
294 //FIXME: needs SecAsn1Coder implementation
296 pkcs12_context context
= {};
297 SecAsn1CoderCreate(&context
.coder
);
299 context
.passphrase
= CFDictionaryGetValue(options
, kSecImportExportPassphrase
);
300 context
.items
= CFDictionaryCreateMutable(kCFAllocatorDefault
,
301 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
302 int status
= p12decode(&context
, pkcs12_data
);
304 CFMutableArrayRef certs
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
305 CFDictionaryApplyFunction(context
.items
, collect_certs
, certs
);
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
);
312 /* ignoring certs that weren't picked up as part of the certchain for found keys */
317 CFReleaseSafe(context
.items
);
318 SecAsn1CoderRelease(context
.coder
);
321 case p12_noErr
: return errSecSuccess
;
322 case p12_passwordErr
: return errSecAuthFailed
;
323 case p12_decodeErr
: return errSecDecode
;
324 default: return errSecInternal
;
326 return errSecSuccess
;