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 "SecImportExport.h"
41 const CFStringRef kSecImportExportPassphrase
= CFSTR("passphrase");
42 const CFStringRef kSecImportItemLabel
= CFSTR("label");
43 const CFStringRef kSecImportItemKeyID
= CFSTR("keyid");
44 const CFStringRef kSecImportItemTrust
= CFSTR("trust");
45 const CFStringRef kSecImportItemCertChain
= CFSTR("chain");
46 const CFStringRef kSecImportItemIdentity
= CFSTR("identity");
49 CFMutableArrayRef certs
;
51 } collect_certs_context
;
54 static void collect_certs(const void *key
, const void *value
, void *context
)
56 if (!CFDictionaryContainsKey(value
, CFSTR("key"))) {
57 CFDataRef cert_bytes
= CFDictionaryGetValue(value
, CFSTR("cert"));
60 collect_certs_context
*a_collect_certs_context
= (collect_certs_context
*)context
;
61 SecCertificateRef cert
=
62 SecCertificateCreateWithData(kCFAllocatorDefault
, cert_bytes
);
64 *a_collect_certs_context
->status
= p12_decodeErr
;
67 CFMutableArrayRef cert_array
= a_collect_certs_context
->certs
;
68 CFArrayAppendValue(cert_array
, cert
);
74 CFMutableArrayRef identities
;
77 } build_trust_chains_context
;
79 static void build_trust_chains(const void *key
, const void *value
,
82 CFMutableDictionaryRef identity_dict
= CFDictionaryCreateMutable(kCFAllocatorDefault
,
83 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
84 SecKeyRef private_key
= NULL
;
85 SecCertificateRef cert
= NULL
;
86 SecIdentityRef identity
= NULL
;
87 SecPolicyRef policy
= NULL
;
88 CFMutableArrayRef cert_chain
= NULL
, eval_chain
= NULL
;
89 SecTrustRef trust
= NULL
;
90 build_trust_chains_context
* a_build_trust_chains_context
= (build_trust_chains_context
*)context
;
92 CFDataRef key_bytes
= CFDictionaryGetValue(value
, CFSTR("key"));
93 require(key_bytes
, out
);
94 CFDataRef cert_bytes
= CFDictionaryGetValue(value
, CFSTR("cert"));
95 require(cert_bytes
, out
);
96 CFDataRef algoid_bytes
= CFDictionaryGetValue(value
, CFSTR("algid"));
99 DERItem algorithm
= { (DERByte
*)CFDataGetBytePtr(algoid_bytes
), CFDataGetLength(algoid_bytes
) };
100 if (DEROidCompare(&oidEcPubKey
, &algorithm
)) {
101 require (private_key
= SecKeyCreateECPrivateKey(kCFAllocatorDefault
,
102 CFDataGetBytePtr(key_bytes
), CFDataGetLength(key_bytes
),
103 kSecKeyEncodingPkcs1
), out
);
104 } else if (DEROidCompare(&oidRsa
, &algorithm
)) {
105 require (private_key
= SecKeyCreateRSAPrivateKey(kCFAllocatorDefault
,
106 CFDataGetBytePtr(key_bytes
), CFDataGetLength(key_bytes
),
107 kSecKeyEncodingPkcs1
), out
);
109 *a_build_trust_chains_context
->status
= p12_decodeErr
;
113 require_action(cert
= SecCertificateCreateWithData(kCFAllocatorDefault
, cert_bytes
), out
,
114 *a_build_trust_chains_context
->status
= p12_decodeErr
);
115 require_action(identity
= SecIdentityCreate(kCFAllocatorDefault
, cert
, private_key
), out
,
116 *a_build_trust_chains_context
->status
= p12_decodeErr
);
117 CFDictionarySetValue(identity_dict
, kSecImportItemIdentity
, identity
);
119 eval_chain
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
120 require(eval_chain
, out
);
121 CFArrayAppendValue(eval_chain
, cert
);
122 CFRange all_certs
= { 0, CFArrayGetCount(a_build_trust_chains_context
->certs
) };
123 CFArrayAppendArray(eval_chain
, a_build_trust_chains_context
->certs
, all_certs
);
124 require(policy
= SecPolicyCreateBasicX509(), out
);
125 SecTrustResultType result
;
126 SecTrustCreateWithCertificates(eval_chain
, policy
, &trust
);
128 SecTrustEvaluate(trust
, &result
);
129 CFDictionarySetValue(identity_dict
, kSecImportItemTrust
, trust
);
131 require(cert_chain
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
), out
);
132 CFIndex cert_chain_length
= SecTrustGetCertificateCount(trust
);
134 for (i
= 0; i
< cert_chain_length
; i
++)
135 CFArrayAppendValue(cert_chain
, SecTrustGetCertificateAtIndex(trust
, i
));
136 CFDictionarySetValue(identity_dict
, kSecImportItemCertChain
, cert_chain
);
138 CFArrayAppendValue(a_build_trust_chains_context
->identities
, identity_dict
);
140 CFReleaseSafe(identity_dict
);
141 CFReleaseSafe(identity
);
142 CFReleaseSafe(private_key
);
144 CFReleaseSafe(policy
);
145 CFReleaseSafe(cert_chain
);
146 CFReleaseSafe(eval_chain
);
147 CFReleaseSafe(trust
);
150 OSStatus
SecPKCS12Import(CFDataRef pkcs12_data
, CFDictionaryRef options
, CFArrayRef
*items
)
152 pkcs12_context context
= {};
153 SecAsn1CoderCreate(&context
.coder
);
155 context
.passphrase
= CFDictionaryGetValue(options
, kSecImportExportPassphrase
);
156 context
.items
= CFDictionaryCreateMutable(kCFAllocatorDefault
,
157 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
158 p12_error status
= p12decode(&context
, pkcs12_data
);
160 CFMutableArrayRef certs
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
161 collect_certs_context a_collect_certs_context
= { certs
, &status
};
162 CFDictionaryApplyFunction(context
.items
, collect_certs
, &a_collect_certs_context
);
165 CFMutableArrayRef identities
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
166 build_trust_chains_context a_build_trust_chains_context
= { identities
, certs
, &status
};
167 CFDictionaryApplyFunction(context
.items
, build_trust_chains
, &a_build_trust_chains_context
);
168 CFReleaseSafe(certs
);
170 /* ignoring certs that weren't picked up as part of the certchain for found keys */
175 CFReleaseSafe(context
.items
);
176 SecAsn1CoderRelease(context
.coder
);
179 case p12_noErr
: return errSecSuccess
;
180 case p12_passwordErr
: return errSecAuthFailed
;
181 case p12_decodeErr
: return errSecDecode
;
182 default: return errSecInternal
;
184 return errSecSuccess
;