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/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"
36 //#include <AssertMacros.h>
37 #include <CommonCrypto/CommonDigest.h>
39 //#include "p12import.h"
40 #include <Security/SecImportExport.h>
42 const CFStringRef __nonnull kSecImportExportPassphrase
= CFSTR("passphrase");
43 const CFStringRef __nonnull kSecImportExportKeychain
= CFSTR("keychain");
44 const CFStringRef __nonnull kSecImportExportAccess
= CFSTR("access");
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");
53 static void collect_certs(const void *key
, const void *value
, void *context
)
55 if (!CFDictionaryContainsKey(value
, CFSTR("key"))) {
56 CFDataRef cert_bytes
= CFDictionaryGetValue(value
, CFSTR("cert"));
59 SecCertificateRef cert
=
60 SecCertificateCreateWithData(kCFAllocatorDefault
, cert_bytes
);
63 CFMutableArrayRef cert_array
= (CFMutableArrayRef
)context
;
64 CFArrayAppendValue(cert_array
, cert
);
70 CFMutableArrayRef identities
;
72 } build_trust_chains_context
;
74 static void build_trust_chains(const void *key
, const void *value
,
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
;
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);
92 /* p12import only passes up rsa keys */
93 //FIXME: needs SecKeyCreateRSAPrivateKey implementation
95 // private_key = SecKeyCreateRSAPrivateKey(kCFAllocatorDefault,
96 // CFDataGetBytePtr(key_bytes), CFDataGetLength(key_bytes),
97 // kSecKeyEncodingPkcs1);
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
);
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
);
119 cert_chain
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
120 if(!cert_chain
) goto out
; //require(cert_chain, out);
121 CFIndex cert_chain_length
= SecTrustGetCertificateCount(trust
);
123 for (i
= 0; i
< cert_chain_length
; i
++)
124 CFArrayAppendValue(cert_chain
, SecTrustGetCertificateAtIndex(trust
, i
));
125 CFDictionarySetValue(identity_dict
, kSecImportItemCertChain
, cert_chain
);
127 CFArrayAppendValue(a_build_trust_chains_context
->identities
, identity_dict
);
129 CFReleaseSafe(identity_dict
);
130 CFReleaseSafe(identity
);
131 CFReleaseSafe(private_key
);
133 CFReleaseSafe(policy
);
134 CFReleaseSafe(cert_chain
);
135 CFReleaseSafe(eval_chain
);
136 CFReleaseSafe(trust
);
140 OSStatus
SecPKCS12Import(CFDataRef pkcs12_data
, CFDictionaryRef options
, CFArrayRef
*items
)
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.
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 */
159 importKeychain
= (SecKeychainRef
) CFDictionaryGetValue(options
, kSecImportExportKeychain
);
161 CFRetain(importKeychain
);
162 importAccess
= (SecAccessRef
) CFDictionaryGetValue(options
, kSecImportExportAccess
);
164 CFRetain(importAccess
);
165 importPassword
= (CFStringRef
) CFDictionaryGetValue(options
, kSecImportExportPassphrase
);
167 CFRetain(importPassword
);
170 if (!importKeychain
) {
171 // SecKeychainItemImport requires a keychain, so use default
172 status
= SecKeychainCopyDefault(&importKeychain
);
175 memset(&keyParams
, 0, sizeof(SecKeyImportExportParameters
));
176 keyParams
.version
= SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION
;
177 keyParams
.passphrase
= importPassword
;
178 keyParams
.accessRef
= importAccess
;
180 status
= SecKeychainItemImport(pkcs12_data
,
181 NULL
, /* no filename */
189 // build an array of all non-identity certificates which were imported
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
);
202 // now build the output items (array of dictionaries)
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
,
213 &kCFTypeDictionaryKeyCallBacks
,
214 &kCFTypeDictionaryValueCallBacks
);
216 SecCertificateRef itemCert
= NULL
;
217 status
= SecIdentityCopyCertificate((SecIdentityRef
)anItem
, &itemCert
);
221 CFStringRef label
= SecCertificateCopySubjectSummary(itemCert
);
223 CFDictionaryAddValue(itemDict
, kSecImportItemLabel
, label
);
230 SecKeyRef itemKey
= NULL
;
231 status
= SecCertificateCopyPublicKey(itemCert
, &itemKey
);
233 const CSSM_KEY
*cssmKey
;
234 status
= SecKeyGetCSSMKey(itemKey
, &cssmKey
);
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
);
240 CFDictionaryAddValue(itemDict
, kSecImportItemKeyID
, digest
);
249 SecTrustRef trust
= NULL
;
250 SecPolicyRef policy
= SecPolicyCreateBasicX509();
251 CFMutableArrayRef certArray
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
252 CFArrayAppendValue(certArray
, itemCert
);
254 CFArrayAppendArray(certArray
, certs
, CFRangeMake(0, CFArrayGetCount(certs
)));
256 status
= SecTrustCreateWithCertificates(certArray
, policy
, &trust
);
261 CFDictionaryAddValue(itemDict
, kSecImportItemTrust
, trust
);
267 CFDictionaryAddValue(itemDict
, kSecImportItemCertChain
, certArray
);
268 CFRelease(certArray
);
272 CFDictionaryAddValue(itemDict
, kSecImportItemIdentity
, anItem
);
276 CFArrayAppendValue(identities
, itemDict
);
285 CFRelease(identities
);
292 CFRelease(importKeychain
);
294 CFRelease(importAccess
);
296 CFRelease(importPassword
);
300 //FIXME: needs SecAsn1Coder implementation
302 pkcs12_context context
= {};
303 SecAsn1CoderCreate(&context
.coder
);
305 context
.passphrase
= CFDictionaryGetValue(options
, kSecImportExportPassphrase
);
306 context
.items
= CFDictionaryCreateMutable(kCFAllocatorDefault
,
307 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
308 int status
= p12decode(&context
, pkcs12_data
);
310 CFMutableArrayRef certs
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
311 CFDictionaryApplyFunction(context
.items
, collect_certs
, certs
);
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
);
318 /* ignoring certs that weren't picked up as part of the certchain for found keys */
323 CFReleaseSafe(context
.items
);
324 SecAsn1CoderRelease(context
.coder
);
327 case p12_noErr
: return errSecSuccess
;
328 case p12_passwordErr
: return errSecAuthFailed
;
329 case p12_decodeErr
: return errSecDecode
;
330 default: return errSecInternal
;
332 return errSecSuccess
;