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/oidsPriv.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 static void collect_certs(const void *key
, const void *value
, void *context
)
51 if (!CFDictionaryContainsKey(value
, CFSTR("key"))) {
52 CFDataRef cert_bytes
= CFDictionaryGetValue(value
, CFSTR("cert"));
55 SecCertificateRef cert
=
56 SecCertificateCreateWithData(kCFAllocatorDefault
, cert_bytes
);
59 CFMutableArrayRef cert_array
= (CFMutableArrayRef
)context
;
60 CFArrayAppendValue(cert_array
, cert
);
66 CFMutableArrayRef identities
;
68 } build_trust_chains_context
;
70 static void build_trust_chains(const void *key
, const void *value
,
73 CFMutableDictionaryRef identity_dict
= CFDictionaryCreateMutable(kCFAllocatorDefault
,
74 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
75 SecKeyRef private_key
= NULL
;
76 SecCertificateRef cert
= NULL
;
77 SecIdentityRef identity
= NULL
;
78 SecPolicyRef policy
= NULL
;
79 CFMutableArrayRef cert_chain
= NULL
, eval_chain
= NULL
;
80 SecTrustRef trust
= NULL
;
81 build_trust_chains_context
* a_build_trust_chains_context
= (build_trust_chains_context
*)context
;
83 CFDataRef key_bytes
= CFDictionaryGetValue(value
, CFSTR("key"));
84 require(key_bytes
, out
);
85 CFDataRef cert_bytes
= CFDictionaryGetValue(value
, CFSTR("cert"));
86 require(cert_bytes
, out
);
87 CFDataRef algoid_bytes
= CFDictionaryGetValue(value
, CFSTR("algid"));
90 DERItem algorithm
= { (DERByte
*)CFDataGetBytePtr(algoid_bytes
), CFDataGetLength(algoid_bytes
) };
91 if (DEROidCompare(&oidEcPubKey
, &algorithm
)) {
92 require (private_key
= SecKeyCreateECPrivateKey(kCFAllocatorDefault
,
93 CFDataGetBytePtr(key_bytes
), CFDataGetLength(key_bytes
),
94 kSecKeyEncodingPkcs1
), out
);
95 } else if (DEROidCompare(&oidRsa
, &algorithm
)) {
96 require (private_key
= SecKeyCreateRSAPrivateKey(kCFAllocatorDefault
,
97 CFDataGetBytePtr(key_bytes
), CFDataGetLength(key_bytes
),
98 kSecKeyEncodingPkcs1
), out
);
103 require(cert
= SecCertificateCreateWithData(kCFAllocatorDefault
, cert_bytes
), out
);
104 require(identity
= SecIdentityCreate(kCFAllocatorDefault
, cert
, private_key
), out
);
105 CFDictionarySetValue(identity_dict
, kSecImportItemIdentity
, identity
);
107 eval_chain
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
108 require(eval_chain
, out
);
109 CFArrayAppendValue(eval_chain
, cert
);
110 CFRange all_certs
= { 0, CFArrayGetCount(a_build_trust_chains_context
->certs
) };
111 CFArrayAppendArray(eval_chain
, a_build_trust_chains_context
->certs
, all_certs
);
112 require(policy
= SecPolicyCreateBasicX509(), out
);
113 SecTrustResultType result
;
114 SecTrustCreateWithCertificates(eval_chain
, policy
, &trust
);
116 SecTrustEvaluate(trust
, &result
);
117 CFDictionarySetValue(identity_dict
, kSecImportItemTrust
, trust
);
119 require(cert_chain
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
), out
);
120 CFIndex cert_chain_length
= SecTrustGetCertificateCount(trust
);
122 for (i
= 0; i
< cert_chain_length
; i
++)
123 CFArrayAppendValue(cert_chain
, SecTrustGetCertificateAtIndex(trust
, i
));
124 CFDictionarySetValue(identity_dict
, kSecImportItemCertChain
, cert_chain
);
126 CFArrayAppendValue(a_build_trust_chains_context
->identities
, identity_dict
);
128 CFReleaseSafe(identity_dict
);
129 CFReleaseSafe(identity
);
130 CFReleaseSafe(private_key
);
132 CFReleaseSafe(policy
);
133 CFReleaseSafe(cert_chain
);
134 CFReleaseSafe(eval_chain
);
135 CFReleaseSafe(trust
);
138 OSStatus
SecPKCS12Import(CFDataRef pkcs12_data
, CFDictionaryRef options
, CFArrayRef
*items
)
140 pkcs12_context context
= {};
141 SecAsn1CoderCreate(&context
.coder
);
143 context
.passphrase
= CFDictionaryGetValue(options
, kSecImportExportPassphrase
);
144 context
.items
= CFDictionaryCreateMutable(kCFAllocatorDefault
,
145 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
146 int status
= p12decode(&context
, pkcs12_data
);
148 CFMutableArrayRef certs
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
149 CFDictionaryApplyFunction(context
.items
, collect_certs
, certs
);
151 CFMutableArrayRef identities
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
152 build_trust_chains_context a_build_trust_chains_context
= { identities
, certs
};
153 CFDictionaryApplyFunction(context
.items
, build_trust_chains
, &a_build_trust_chains_context
);
154 CFReleaseSafe(certs
);
156 /* ignoring certs that weren't picked up as part of the certchain for found keys */
161 CFReleaseSafe(context
.items
);
162 SecAsn1CoderRelease(context
.coder
);
165 case p12_noErr
: return errSecSuccess
;
166 case p12_passwordErr
: return errSecAuthFailed
;
167 case p12_decodeErr
: return errSecDecode
;
168 default: return errSecInternal
;
170 return errSecSuccess
;