2 * Copyright (c) 2007-2008 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/SecIdentityPriv.h>
30 #include <Security/SecPolicy.h>
31 #include <Security/SecTrust.h>
32 #include <Security/SecInternal.h>
34 #include <AssertMacros.h>
36 #include "p12import.h"
37 #include "SecImportExport.h"
39 CFStringRef kSecImportExportPassphrase
= CFSTR("passphrase");
40 CFStringRef kSecImportItemLabel
= CFSTR("label");
41 CFStringRef kSecImportItemKeyID
= CFSTR("keyid");
42 CFStringRef kSecImportItemTrust
= CFSTR("trust");
43 CFStringRef kSecImportItemCertChain
= CFSTR("chain");
44 CFStringRef kSecImportItemIdentity
= CFSTR("identity");
47 static void collect_certs(const void *key
, const void *value
, void *context
)
49 if (!CFDictionaryContainsKey(value
, CFSTR("key"))) {
50 CFDataRef cert_bytes
= CFDictionaryGetValue(value
, CFSTR("cert"));
53 SecCertificateRef cert
=
54 SecCertificateCreateWithData(kCFAllocatorDefault
, cert_bytes
);
57 CFMutableArrayRef cert_array
= (CFMutableArrayRef
)context
;
58 CFArrayAppendValue(cert_array
, cert
);
64 CFMutableArrayRef identities
;
66 } build_trust_chains_context
;
68 static void build_trust_chains(const void *key
, const void *value
,
71 CFMutableDictionaryRef identity_dict
= CFDictionaryCreateMutable(kCFAllocatorDefault
,
72 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
73 SecKeyRef private_key
= NULL
;
74 SecCertificateRef cert
= NULL
;
75 SecIdentityRef identity
= NULL
;
76 SecPolicyRef policy
= NULL
;
77 CFMutableArrayRef cert_chain
= NULL
, eval_chain
= NULL
;
78 SecTrustRef trust
= NULL
;
79 build_trust_chains_context
* a_build_trust_chains_context
= (build_trust_chains_context
*)context
;
81 CFDataRef key_bytes
= CFDictionaryGetValue(value
, CFSTR("key"));
82 require(key_bytes
, out
);
83 CFDataRef cert_bytes
= CFDictionaryGetValue(value
, CFSTR("cert"));
84 require(cert_bytes
, out
);
86 /* p12import only passes up rsa keys */
87 require (private_key
= SecKeyCreateRSAPrivateKey(kCFAllocatorDefault
,
88 CFDataGetBytePtr(key_bytes
), CFDataGetLength(key_bytes
),
89 kSecKeyEncodingPkcs1
), out
);
90 require(cert
= SecCertificateCreateWithData(kCFAllocatorDefault
, cert_bytes
), out
);
91 require(identity
= SecIdentityCreate(kCFAllocatorDefault
, cert
, private_key
), out
);
92 CFDictionarySetValue(identity_dict
, kSecImportItemIdentity
, identity
);
94 eval_chain
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
95 require(eval_chain
, out
);
96 CFArrayAppendValue(eval_chain
, cert
);
97 CFRange all_certs
= { 0, CFArrayGetCount(a_build_trust_chains_context
->certs
) };
98 CFArrayAppendArray(eval_chain
, a_build_trust_chains_context
->certs
, all_certs
);
99 require(policy
= SecPolicyCreateBasicX509(), out
);
100 SecTrustResultType result
;
101 SecTrustCreateWithCertificates(eval_chain
, policy
, &trust
);
103 SecTrustEvaluate(trust
, &result
);
104 CFDictionarySetValue(identity_dict
, kSecImportItemTrust
, trust
);
106 require(cert_chain
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
), out
);
107 CFIndex cert_chain_length
= SecTrustGetCertificateCount(trust
);
109 for (i
= 0; i
< cert_chain_length
; i
++)
110 CFArrayAppendValue(cert_chain
, SecTrustGetCertificateAtIndex(trust
, i
));
111 CFDictionarySetValue(identity_dict
, kSecImportItemCertChain
, cert_chain
);
113 CFArrayAppendValue(a_build_trust_chains_context
->identities
, identity_dict
);
115 CFReleaseSafe(identity_dict
);
116 CFReleaseSafe(identity
);
117 CFReleaseSafe(private_key
);
119 CFReleaseSafe(policy
);
120 CFReleaseSafe(cert_chain
);
121 CFReleaseSafe(eval_chain
);
122 CFReleaseSafe(trust
);
125 OSStatus
SecPKCS12Import(CFDataRef pkcs12_data
, CFDictionaryRef options
, CFArrayRef
*items
)
127 pkcs12_context context
= {};
128 SecAsn1CoderCreate(&context
.coder
);
130 context
.passphrase
= CFDictionaryGetValue(options
, kSecImportExportPassphrase
);
131 context
.items
= CFDictionaryCreateMutable(kCFAllocatorDefault
,
132 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
133 int status
= p12decode(&context
, pkcs12_data
);
135 CFMutableArrayRef certs
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
136 CFDictionaryApplyFunction(context
.items
, collect_certs
, certs
);
138 CFMutableArrayRef identities
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
139 build_trust_chains_context a_build_trust_chains_context
= { identities
, certs
};
140 CFDictionaryApplyFunction(context
.items
, build_trust_chains
, &a_build_trust_chains_context
);
141 CFReleaseSafe(certs
);
143 /* ignoring certs that weren't picked up as part of the certchain for found keys */
148 CFReleaseSafe(context
.items
);
149 SecAsn1CoderRelease(context
.coder
);
152 case p12_noErr
: return noErr
;
153 case p12_passwordErr
: return errSecAuthFailed
;
154 case p12_decodeErr
: return errSecDecode
;
155 default: return errSecInternal
;