2 * Copyright (c) 2007-2008,2012-2013 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/SecECKey.h>
29 #include <Security/SecCertificate.h>
30 #include <Security/SecIdentityPriv.h>
31 #include <Security/SecPolicy.h>
32 #include <Security/SecTrust.h>
33 #include <Security/SecInternal.h>
34 #include <libDER/oids.h>
36 #include <AssertMacros.h>
38 #include "p12import.h"
39 #include <Security/SecImportExportPriv.h>
42 const CFStringRef kSecImportExportPassphrase
= CFSTR("passphrase");
43 const CFStringRef kSecImportItemLabel
= CFSTR("label");
44 const CFStringRef kSecImportItemKeyID
= CFSTR("keyid");
45 const CFStringRef kSecImportItemTrust
= CFSTR("trust");
46 const CFStringRef kSecImportItemCertChain
= CFSTR("chain");
47 const CFStringRef kSecImportItemIdentity
= CFSTR("identity");
51 CFMutableArrayRef certs
;
53 } collect_certs_context
;
56 static void collect_certs(const void *key
, const void *value
, void *context
)
58 if (!CFDictionaryContainsKey(value
, CFSTR("key"))) {
59 CFDataRef cert_bytes
= CFDictionaryGetValue(value
, CFSTR("cert"));
62 collect_certs_context
*a_collect_certs_context
= (collect_certs_context
*)context
;
63 SecCertificateRef cert
=
64 SecCertificateCreateWithData(kCFAllocatorDefault
, cert_bytes
);
66 *a_collect_certs_context
->status
= p12_decodeErr
;
69 CFMutableArrayRef cert_array
= a_collect_certs_context
->certs
;
70 CFArrayAppendValue(cert_array
, cert
);
76 CFMutableArrayRef identities
;
79 } build_trust_chains_context
;
81 static void build_trust_chains(const void *key
, const void *value
,
84 CFMutableDictionaryRef identity_dict
= CFDictionaryCreateMutable(kCFAllocatorDefault
,
85 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
86 SecKeyRef private_key
= NULL
;
87 SecCertificateRef cert
= NULL
;
88 SecIdentityRef identity
= NULL
;
89 SecPolicyRef policy
= NULL
;
90 CFMutableArrayRef cert_chain
= NULL
, eval_chain
= NULL
;
91 SecTrustRef trust
= NULL
;
92 build_trust_chains_context
* a_build_trust_chains_context
= (build_trust_chains_context
*)context
;
94 CFDataRef key_bytes
= CFDictionaryGetValue(value
, CFSTR("key"));
95 require(key_bytes
, out
);
96 CFDataRef cert_bytes
= CFDictionaryGetValue(value
, CFSTR("cert"));
97 require(cert_bytes
, out
);
98 CFDataRef algoid_bytes
= CFDictionaryGetValue(value
, CFSTR("algid"));
101 DERItem algorithm
= { (DERByte
*)CFDataGetBytePtr(algoid_bytes
), CFDataGetLength(algoid_bytes
) };
102 if (DEROidCompare(&oidEcPubKey
, &algorithm
)) {
103 require (private_key
= SecKeyCreateECPrivateKey(kCFAllocatorDefault
,
104 CFDataGetBytePtr(key_bytes
), CFDataGetLength(key_bytes
),
105 kSecKeyEncodingPkcs1
), out
);
106 } else if (DEROidCompare(&oidRsa
, &algorithm
)) {
107 require (private_key
= SecKeyCreateRSAPrivateKey(kCFAllocatorDefault
,
108 CFDataGetBytePtr(key_bytes
), CFDataGetLength(key_bytes
),
109 kSecKeyEncodingPkcs1
), out
);
111 *a_build_trust_chains_context
->status
= p12_decodeErr
;
115 require_action(cert
= SecCertificateCreateWithData(kCFAllocatorDefault
, cert_bytes
), out
,
116 *a_build_trust_chains_context
->status
= p12_decodeErr
);
117 require_action(identity
= SecIdentityCreate(kCFAllocatorDefault
, cert
, private_key
), out
,
118 *a_build_trust_chains_context
->status
= p12_decodeErr
);
119 CFDictionarySetValue(identity_dict
, kSecImportItemIdentity
, identity
);
121 eval_chain
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
122 require(eval_chain
, out
);
123 CFArrayAppendValue(eval_chain
, cert
);
124 CFRange all_certs
= { 0, CFArrayGetCount(a_build_trust_chains_context
->certs
) };
125 CFArrayAppendArray(eval_chain
, a_build_trust_chains_context
->certs
, all_certs
);
126 require(policy
= SecPolicyCreateBasicX509(), out
);
127 SecTrustResultType result
;
128 SecTrustCreateWithCertificates(eval_chain
, policy
, &trust
);
130 SecTrustEvaluate(trust
, &result
);
131 CFDictionarySetValue(identity_dict
, kSecImportItemTrust
, trust
);
133 require(cert_chain
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
), out
);
134 CFIndex cert_chain_length
= SecTrustGetCertificateCount(trust
);
136 for (i
= 0; i
< cert_chain_length
; i
++)
137 CFArrayAppendValue(cert_chain
, SecTrustGetCertificateAtIndex(trust
, i
));
138 CFDictionarySetValue(identity_dict
, kSecImportItemCertChain
, cert_chain
);
140 CFArrayAppendValue(a_build_trust_chains_context
->identities
, identity_dict
);
142 CFReleaseSafe(identity_dict
);
143 CFReleaseSafe(identity
);
144 CFReleaseSafe(private_key
);
146 CFReleaseSafe(policy
);
147 CFReleaseSafe(cert_chain
);
148 CFReleaseSafe(eval_chain
);
149 CFReleaseSafe(trust
);
153 OSStatus
SecPKCS12Import_ios(CFDataRef pkcs12_data
, CFDictionaryRef options
, CFArrayRef
*items
)
155 OSStatus
SecPKCS12Import(CFDataRef pkcs12_data
, CFDictionaryRef options
, CFArrayRef
*items
)
158 pkcs12_context context
= {};
159 SecAsn1CoderCreate(&context
.coder
);
161 context
.passphrase
= CFDictionaryGetValue(options
, kSecImportExportPassphrase
);
162 context
.items
= CFDictionaryCreateMutable(kCFAllocatorDefault
,
163 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
164 p12_error status
= p12decode(&context
, pkcs12_data
);
166 CFMutableArrayRef certs
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
167 collect_certs_context a_collect_certs_context
= { certs
, &status
};
168 CFDictionaryApplyFunction(context
.items
, collect_certs
, &a_collect_certs_context
);
171 CFMutableArrayRef identities
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
172 build_trust_chains_context a_build_trust_chains_context
= { identities
, certs
, &status
};
173 CFDictionaryApplyFunction(context
.items
, build_trust_chains
, &a_build_trust_chains_context
);
174 CFReleaseSafe(certs
);
176 /* ignoring certs that weren't picked up as part of the certchain for found keys */
181 CFReleaseSafe(context
.items
);
182 SecAsn1CoderRelease(context
.coder
);
185 case p12_noErr
: return errSecSuccess
;
186 case p12_passwordErr
: return errSecAuthFailed
;
187 case p12_decodeErr
: return errSecDecode
;
188 default: return errSecInternal
;
190 return errSecSuccess
;