xref: /freebsd/crypto/heimdal/lib/hx509/ks_keychain.c (revision 6a068746777241722b2b32c5d0bc443a2a64d80b)
1c19800e8SDoug Rabson /*
2*ae771770SStanislav Sedov  * Copyright (c) 2007 Kungliga Tekniska Högskolan
3c19800e8SDoug Rabson  * (Royal Institute of Technology, Stockholm, Sweden).
4c19800e8SDoug Rabson  * All rights reserved.
5c19800e8SDoug Rabson  *
6c19800e8SDoug Rabson  * Redistribution and use in source and binary forms, with or without
7c19800e8SDoug Rabson  * modification, are permitted provided that the following conditions
8c19800e8SDoug Rabson  * are met:
9c19800e8SDoug Rabson  *
10c19800e8SDoug Rabson  * 1. Redistributions of source code must retain the above copyright
11c19800e8SDoug Rabson  *    notice, this list of conditions and the following disclaimer.
12c19800e8SDoug Rabson  *
13c19800e8SDoug Rabson  * 2. Redistributions in binary form must reproduce the above copyright
14c19800e8SDoug Rabson  *    notice, this list of conditions and the following disclaimer in the
15c19800e8SDoug Rabson  *    documentation and/or other materials provided with the distribution.
16c19800e8SDoug Rabson  *
17c19800e8SDoug Rabson  * 3. Neither the name of the Institute nor the names of its contributors
18c19800e8SDoug Rabson  *    may be used to endorse or promote products derived from this software
19c19800e8SDoug Rabson  *    without specific prior written permission.
20c19800e8SDoug Rabson  *
21c19800e8SDoug Rabson  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22c19800e8SDoug Rabson  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23c19800e8SDoug Rabson  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24c19800e8SDoug Rabson  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25c19800e8SDoug Rabson  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26c19800e8SDoug Rabson  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27c19800e8SDoug Rabson  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28c19800e8SDoug Rabson  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29c19800e8SDoug Rabson  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30c19800e8SDoug Rabson  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31c19800e8SDoug Rabson  * SUCH DAMAGE.
32c19800e8SDoug Rabson  */
33c19800e8SDoug Rabson 
34c19800e8SDoug Rabson #include "hx_locl.h"
35c19800e8SDoug Rabson 
36c19800e8SDoug Rabson #ifdef HAVE_FRAMEWORK_SECURITY
37c19800e8SDoug Rabson 
38c19800e8SDoug Rabson #include <Security/Security.h>
39c19800e8SDoug Rabson 
40c19800e8SDoug Rabson /* Missing function decls in pre Leopard */
41c19800e8SDoug Rabson #ifdef NEED_SECKEYGETCSPHANDLE_PROTO
42c19800e8SDoug Rabson OSStatus SecKeyGetCSPHandle(SecKeyRef, CSSM_CSP_HANDLE *);
43c19800e8SDoug Rabson OSStatus SecKeyGetCredentials(SecKeyRef, CSSM_ACL_AUTHORIZATION_TAG,
44c19800e8SDoug Rabson 			      int, const CSSM_ACCESS_CREDENTIALS **);
45c19800e8SDoug Rabson #define kSecCredentialTypeDefault 0
46*ae771770SStanislav Sedov #define CSSM_SIZE uint32_t
47c19800e8SDoug Rabson #endif
48c19800e8SDoug Rabson 
49c19800e8SDoug Rabson 
50c19800e8SDoug Rabson static int
getAttribute(SecKeychainItemRef itemRef,SecItemAttr item,SecKeychainAttributeList ** attrs)51c19800e8SDoug Rabson getAttribute(SecKeychainItemRef itemRef, SecItemAttr item,
52c19800e8SDoug Rabson 	     SecKeychainAttributeList **attrs)
53c19800e8SDoug Rabson {
54c19800e8SDoug Rabson     SecKeychainAttributeInfo attrInfo;
55c19800e8SDoug Rabson     UInt32 attrFormat = 0;
56c19800e8SDoug Rabson     OSStatus ret;
57c19800e8SDoug Rabson 
58c19800e8SDoug Rabson     *attrs = NULL;
59c19800e8SDoug Rabson 
60c19800e8SDoug Rabson     attrInfo.count = 1;
61c19800e8SDoug Rabson     attrInfo.tag = &item;
62c19800e8SDoug Rabson     attrInfo.format = &attrFormat;
63c19800e8SDoug Rabson 
64c19800e8SDoug Rabson     ret = SecKeychainItemCopyAttributesAndData(itemRef, &attrInfo, NULL,
65c19800e8SDoug Rabson 					       attrs, NULL, NULL);
66c19800e8SDoug Rabson     if (ret)
67c19800e8SDoug Rabson 	return EINVAL;
68c19800e8SDoug Rabson     return 0;
69c19800e8SDoug Rabson }
70c19800e8SDoug Rabson 
71c19800e8SDoug Rabson 
72c19800e8SDoug Rabson /*
73c19800e8SDoug Rabson  *
74c19800e8SDoug Rabson  */
75c19800e8SDoug Rabson 
76c19800e8SDoug Rabson struct kc_rsa {
77c19800e8SDoug Rabson     SecKeychainItemRef item;
78c19800e8SDoug Rabson     size_t keysize;
79c19800e8SDoug Rabson };
80c19800e8SDoug Rabson 
81c19800e8SDoug Rabson 
82c19800e8SDoug Rabson static int
kc_rsa_public_encrypt(int flen,const unsigned char * from,unsigned char * to,RSA * rsa,int padding)83c19800e8SDoug Rabson kc_rsa_public_encrypt(int flen,
84c19800e8SDoug Rabson 		      const unsigned char *from,
85c19800e8SDoug Rabson 		      unsigned char *to,
86c19800e8SDoug Rabson 		      RSA *rsa,
87c19800e8SDoug Rabson 		      int padding)
88c19800e8SDoug Rabson {
89c19800e8SDoug Rabson     return -1;
90c19800e8SDoug Rabson }
91c19800e8SDoug Rabson 
92c19800e8SDoug Rabson static int
kc_rsa_public_decrypt(int flen,const unsigned char * from,unsigned char * to,RSA * rsa,int padding)93c19800e8SDoug Rabson kc_rsa_public_decrypt(int flen,
94c19800e8SDoug Rabson 		      const unsigned char *from,
95c19800e8SDoug Rabson 		      unsigned char *to,
96c19800e8SDoug Rabson 		      RSA *rsa,
97c19800e8SDoug Rabson 		      int padding)
98c19800e8SDoug Rabson {
99c19800e8SDoug Rabson     return -1;
100c19800e8SDoug Rabson }
101c19800e8SDoug Rabson 
102c19800e8SDoug Rabson 
103c19800e8SDoug Rabson static int
kc_rsa_private_encrypt(int flen,const unsigned char * from,unsigned char * to,RSA * rsa,int padding)104c19800e8SDoug Rabson kc_rsa_private_encrypt(int flen,
105c19800e8SDoug Rabson 		       const unsigned char *from,
106c19800e8SDoug Rabson 		       unsigned char *to,
107c19800e8SDoug Rabson 		       RSA *rsa,
108c19800e8SDoug Rabson 		       int padding)
109c19800e8SDoug Rabson {
110c19800e8SDoug Rabson     struct kc_rsa *kc = RSA_get_app_data(rsa);
111c19800e8SDoug Rabson 
112c19800e8SDoug Rabson     CSSM_RETURN cret;
113c19800e8SDoug Rabson     OSStatus ret;
114c19800e8SDoug Rabson     const CSSM_ACCESS_CREDENTIALS *creds;
115c19800e8SDoug Rabson     SecKeyRef privKeyRef = (SecKeyRef)kc->item;
116c19800e8SDoug Rabson     CSSM_CSP_HANDLE cspHandle;
117c19800e8SDoug Rabson     const CSSM_KEY *cssmKey;
118c19800e8SDoug Rabson     CSSM_CC_HANDLE sigHandle = 0;
119c19800e8SDoug Rabson     CSSM_DATA sig, in;
120c19800e8SDoug Rabson     int fret = 0;
121c19800e8SDoug Rabson 
122*ae771770SStanislav Sedov     if (padding != RSA_PKCS1_PADDING)
123*ae771770SStanislav Sedov 	return -1;
124c19800e8SDoug Rabson 
125c19800e8SDoug Rabson     cret = SecKeyGetCSSMKey(privKeyRef, &cssmKey);
126c19800e8SDoug Rabson     if(cret) abort();
127c19800e8SDoug Rabson 
128c19800e8SDoug Rabson     cret = SecKeyGetCSPHandle(privKeyRef, &cspHandle);
129c19800e8SDoug Rabson     if(cret) abort();
130c19800e8SDoug Rabson 
131c19800e8SDoug Rabson     ret = SecKeyGetCredentials(privKeyRef, CSSM_ACL_AUTHORIZATION_SIGN,
132c19800e8SDoug Rabson 			       kSecCredentialTypeDefault, &creds);
133c19800e8SDoug Rabson     if(ret) abort();
134c19800e8SDoug Rabson 
135c19800e8SDoug Rabson     ret = CSSM_CSP_CreateSignatureContext(cspHandle, CSSM_ALGID_RSA,
136c19800e8SDoug Rabson 					  creds, cssmKey, &sigHandle);
137c19800e8SDoug Rabson     if(ret) abort();
138c19800e8SDoug Rabson 
139c19800e8SDoug Rabson     in.Data = (uint8 *)from;
140c19800e8SDoug Rabson     in.Length = flen;
141c19800e8SDoug Rabson 
142c19800e8SDoug Rabson     sig.Data = (uint8 *)to;
143c19800e8SDoug Rabson     sig.Length = kc->keysize;
144c19800e8SDoug Rabson 
145c19800e8SDoug Rabson     cret = CSSM_SignData(sigHandle, &in, 1, CSSM_ALGID_NONE, &sig);
146c19800e8SDoug Rabson     if(cret) {
147c19800e8SDoug Rabson 	/* cssmErrorString(cret); */
148c19800e8SDoug Rabson 	fret = -1;
149c19800e8SDoug Rabson     } else
150c19800e8SDoug Rabson 	fret = sig.Length;
151c19800e8SDoug Rabson 
152c19800e8SDoug Rabson     if(sigHandle)
153c19800e8SDoug Rabson 	CSSM_DeleteContext(sigHandle);
154c19800e8SDoug Rabson 
155c19800e8SDoug Rabson     return fret;
156c19800e8SDoug Rabson }
157c19800e8SDoug Rabson 
158c19800e8SDoug Rabson static int
kc_rsa_private_decrypt(int flen,const unsigned char * from,unsigned char * to,RSA * rsa,int padding)159c19800e8SDoug Rabson kc_rsa_private_decrypt(int flen, const unsigned char *from, unsigned char *to,
160c19800e8SDoug Rabson 		       RSA * rsa, int padding)
161c19800e8SDoug Rabson {
162*ae771770SStanislav Sedov     struct kc_rsa *kc = RSA_get_app_data(rsa);
163*ae771770SStanislav Sedov 
164*ae771770SStanislav Sedov     CSSM_RETURN cret;
165*ae771770SStanislav Sedov     OSStatus ret;
166*ae771770SStanislav Sedov     const CSSM_ACCESS_CREDENTIALS *creds;
167*ae771770SStanislav Sedov     SecKeyRef privKeyRef = (SecKeyRef)kc->item;
168*ae771770SStanislav Sedov     CSSM_CSP_HANDLE cspHandle;
169*ae771770SStanislav Sedov     const CSSM_KEY *cssmKey;
170*ae771770SStanislav Sedov     CSSM_CC_HANDLE handle = 0;
171*ae771770SStanislav Sedov     CSSM_DATA out, in, rem;
172*ae771770SStanislav Sedov     int fret = 0;
173*ae771770SStanislav Sedov     CSSM_SIZE outlen = 0;
174*ae771770SStanislav Sedov     char remdata[1024];
175*ae771770SStanislav Sedov 
176*ae771770SStanislav Sedov     if (padding != RSA_PKCS1_PADDING)
177c19800e8SDoug Rabson 	return -1;
178*ae771770SStanislav Sedov 
179*ae771770SStanislav Sedov     cret = SecKeyGetCSSMKey(privKeyRef, &cssmKey);
180*ae771770SStanislav Sedov     if(cret) abort();
181*ae771770SStanislav Sedov 
182*ae771770SStanislav Sedov     cret = SecKeyGetCSPHandle(privKeyRef, &cspHandle);
183*ae771770SStanislav Sedov     if(cret) abort();
184*ae771770SStanislav Sedov 
185*ae771770SStanislav Sedov     ret = SecKeyGetCredentials(privKeyRef, CSSM_ACL_AUTHORIZATION_DECRYPT,
186*ae771770SStanislav Sedov 			       kSecCredentialTypeDefault, &creds);
187*ae771770SStanislav Sedov     if(ret) abort();
188*ae771770SStanislav Sedov 
189*ae771770SStanislav Sedov 
190*ae771770SStanislav Sedov     ret = CSSM_CSP_CreateAsymmetricContext (cspHandle,
191*ae771770SStanislav Sedov 					    CSSM_ALGID_RSA,
192*ae771770SStanislav Sedov 					    creds,
193*ae771770SStanislav Sedov 					    cssmKey,
194*ae771770SStanislav Sedov 					    CSSM_PADDING_PKCS1,
195*ae771770SStanislav Sedov 					    &handle);
196*ae771770SStanislav Sedov     if(ret) abort();
197*ae771770SStanislav Sedov 
198*ae771770SStanislav Sedov     in.Data = (uint8 *)from;
199*ae771770SStanislav Sedov     in.Length = flen;
200*ae771770SStanislav Sedov 
201*ae771770SStanislav Sedov     out.Data = (uint8 *)to;
202*ae771770SStanislav Sedov     out.Length = kc->keysize;
203*ae771770SStanislav Sedov 
204*ae771770SStanislav Sedov     rem.Data = (uint8 *)remdata;
205*ae771770SStanislav Sedov     rem.Length = sizeof(remdata);
206*ae771770SStanislav Sedov 
207*ae771770SStanislav Sedov     cret = CSSM_DecryptData(handle, &in, 1, &out, 1, &outlen, &rem);
208*ae771770SStanislav Sedov     if(cret) {
209*ae771770SStanislav Sedov 	/* cssmErrorString(cret); */
210*ae771770SStanislav Sedov 	fret = -1;
211*ae771770SStanislav Sedov     } else
212*ae771770SStanislav Sedov 	fret = out.Length;
213*ae771770SStanislav Sedov 
214*ae771770SStanislav Sedov     if(handle)
215*ae771770SStanislav Sedov 	CSSM_DeleteContext(handle);
216*ae771770SStanislav Sedov 
217*ae771770SStanislav Sedov     return fret;
218c19800e8SDoug Rabson }
219c19800e8SDoug Rabson 
220c19800e8SDoug Rabson static int
kc_rsa_init(RSA * rsa)221c19800e8SDoug Rabson kc_rsa_init(RSA *rsa)
222c19800e8SDoug Rabson {
223c19800e8SDoug Rabson     return 1;
224c19800e8SDoug Rabson }
225c19800e8SDoug Rabson 
226c19800e8SDoug Rabson static int
kc_rsa_finish(RSA * rsa)227c19800e8SDoug Rabson kc_rsa_finish(RSA *rsa)
228c19800e8SDoug Rabson {
229c19800e8SDoug Rabson     struct kc_rsa *kc_rsa = RSA_get_app_data(rsa);
230c19800e8SDoug Rabson     CFRelease(kc_rsa->item);
231c19800e8SDoug Rabson     memset(kc_rsa, 0, sizeof(*kc_rsa));
232c19800e8SDoug Rabson     free(kc_rsa);
233c19800e8SDoug Rabson     return 1;
234c19800e8SDoug Rabson }
235c19800e8SDoug Rabson 
236c19800e8SDoug Rabson static const RSA_METHOD kc_rsa_pkcs1_method = {
237c19800e8SDoug Rabson     "hx509 Keychain PKCS#1 RSA",
238c19800e8SDoug Rabson     kc_rsa_public_encrypt,
239c19800e8SDoug Rabson     kc_rsa_public_decrypt,
240c19800e8SDoug Rabson     kc_rsa_private_encrypt,
241c19800e8SDoug Rabson     kc_rsa_private_decrypt,
242c19800e8SDoug Rabson     NULL,
243c19800e8SDoug Rabson     NULL,
244c19800e8SDoug Rabson     kc_rsa_init,
245c19800e8SDoug Rabson     kc_rsa_finish,
246c19800e8SDoug Rabson     0,
247c19800e8SDoug Rabson     NULL,
248c19800e8SDoug Rabson     NULL,
249c19800e8SDoug Rabson     NULL
250c19800e8SDoug Rabson };
251c19800e8SDoug Rabson 
252c19800e8SDoug Rabson static int
set_private_key(hx509_context context,SecKeychainItemRef itemRef,hx509_cert cert)253c19800e8SDoug Rabson set_private_key(hx509_context context,
254c19800e8SDoug Rabson 		SecKeychainItemRef itemRef,
255c19800e8SDoug Rabson 		hx509_cert cert)
256c19800e8SDoug Rabson {
257c19800e8SDoug Rabson     struct kc_rsa *kc;
258c19800e8SDoug Rabson     hx509_private_key key;
259c19800e8SDoug Rabson     RSA *rsa;
260c19800e8SDoug Rabson     int ret;
261c19800e8SDoug Rabson 
262*ae771770SStanislav Sedov     ret = hx509_private_key_init(&key, NULL, NULL);
263c19800e8SDoug Rabson     if (ret)
264c19800e8SDoug Rabson 	return ret;
265c19800e8SDoug Rabson 
266c19800e8SDoug Rabson     kc = calloc(1, sizeof(*kc));
267c19800e8SDoug Rabson     if (kc == NULL)
268c19800e8SDoug Rabson 	_hx509_abort("out of memory");
269c19800e8SDoug Rabson 
270c19800e8SDoug Rabson     kc->item = itemRef;
271c19800e8SDoug Rabson 
272c19800e8SDoug Rabson     rsa = RSA_new();
273c19800e8SDoug Rabson     if (rsa == NULL)
274c19800e8SDoug Rabson 	_hx509_abort("out of memory");
275c19800e8SDoug Rabson 
276c19800e8SDoug Rabson     /* Argh, fake modulus since OpenSSL API is on crack */
277c19800e8SDoug Rabson     {
278c19800e8SDoug Rabson 	SecKeychainAttributeList *attrs = NULL;
279c19800e8SDoug Rabson 	uint32_t size;
280c19800e8SDoug Rabson 	void *data;
281c19800e8SDoug Rabson 
282c19800e8SDoug Rabson 	rsa->n = BN_new();
283c19800e8SDoug Rabson 	if (rsa->n == NULL) abort();
284c19800e8SDoug Rabson 
285c19800e8SDoug Rabson 	ret = getAttribute(itemRef, kSecKeyKeySizeInBits, &attrs);
286c19800e8SDoug Rabson 	if (ret) abort();
287c19800e8SDoug Rabson 
288c19800e8SDoug Rabson 	size = *(uint32_t *)attrs->attr[0].data;
289c19800e8SDoug Rabson 	SecKeychainItemFreeAttributesAndData(attrs, NULL);
290c19800e8SDoug Rabson 
291c19800e8SDoug Rabson 	kc->keysize = (size + 7) / 8;
292c19800e8SDoug Rabson 
293c19800e8SDoug Rabson 	data = malloc(kc->keysize);
294c19800e8SDoug Rabson 	memset(data, 0xe0, kc->keysize);
295c19800e8SDoug Rabson 	BN_bin2bn(data, kc->keysize, rsa->n);
296c19800e8SDoug Rabson 	free(data);
297c19800e8SDoug Rabson     }
298c19800e8SDoug Rabson     rsa->e = NULL;
299c19800e8SDoug Rabson 
300c19800e8SDoug Rabson     RSA_set_method(rsa, &kc_rsa_pkcs1_method);
301c19800e8SDoug Rabson     ret = RSA_set_app_data(rsa, kc);
302c19800e8SDoug Rabson     if (ret != 1)
303c19800e8SDoug Rabson 	_hx509_abort("RSA_set_app_data");
304c19800e8SDoug Rabson 
305*ae771770SStanislav Sedov     hx509_private_key_assign_rsa(key, rsa);
306c19800e8SDoug Rabson     _hx509_cert_assign_key(cert, key);
307c19800e8SDoug Rabson 
308c19800e8SDoug Rabson     return 0;
309c19800e8SDoug Rabson }
310c19800e8SDoug Rabson 
311c19800e8SDoug Rabson /*
312c19800e8SDoug Rabson  *
313c19800e8SDoug Rabson  */
314c19800e8SDoug Rabson 
315c19800e8SDoug Rabson struct ks_keychain {
316c19800e8SDoug Rabson     int anchors;
317c19800e8SDoug Rabson     SecKeychainRef keychain;
318c19800e8SDoug Rabson };
319c19800e8SDoug Rabson 
320c19800e8SDoug Rabson static int
keychain_init(hx509_context context,hx509_certs certs,void ** data,int flags,const char * residue,hx509_lock lock)321c19800e8SDoug Rabson keychain_init(hx509_context context,
322c19800e8SDoug Rabson 	      hx509_certs certs, void **data, int flags,
323c19800e8SDoug Rabson 	      const char *residue, hx509_lock lock)
324c19800e8SDoug Rabson {
325c19800e8SDoug Rabson     struct ks_keychain *ctx;
326c19800e8SDoug Rabson 
327c19800e8SDoug Rabson     ctx = calloc(1, sizeof(*ctx));
328c19800e8SDoug Rabson     if (ctx == NULL) {
329c19800e8SDoug Rabson 	hx509_clear_error_string(context);
330c19800e8SDoug Rabson 	return ENOMEM;
331c19800e8SDoug Rabson     }
332c19800e8SDoug Rabson 
333c19800e8SDoug Rabson     if (residue) {
334c19800e8SDoug Rabson 	if (strcasecmp(residue, "system-anchors") == 0) {
335c19800e8SDoug Rabson 	    ctx->anchors = 1;
336c19800e8SDoug Rabson 	} else if (strncasecmp(residue, "FILE:", 5) == 0) {
337c19800e8SDoug Rabson 	    OSStatus ret;
338c19800e8SDoug Rabson 
339c19800e8SDoug Rabson 	    ret = SecKeychainOpen(residue + 5, &ctx->keychain);
340c19800e8SDoug Rabson 	    if (ret != noErr) {
341c19800e8SDoug Rabson 		hx509_set_error_string(context, 0, ENOENT,
342c19800e8SDoug Rabson 				       "Failed to open %s", residue);
343c19800e8SDoug Rabson 		return ENOENT;
344c19800e8SDoug Rabson 	    }
345c19800e8SDoug Rabson 	} else {
346c19800e8SDoug Rabson 	    hx509_set_error_string(context, 0, ENOENT,
347c19800e8SDoug Rabson 				   "Unknown subtype %s", residue);
348c19800e8SDoug Rabson 	    return ENOENT;
349c19800e8SDoug Rabson 	}
350c19800e8SDoug Rabson     }
351c19800e8SDoug Rabson 
352c19800e8SDoug Rabson     *data = ctx;
353c19800e8SDoug Rabson     return 0;
354c19800e8SDoug Rabson }
355c19800e8SDoug Rabson 
356c19800e8SDoug Rabson /*
357c19800e8SDoug Rabson  *
358c19800e8SDoug Rabson  */
359c19800e8SDoug Rabson 
360c19800e8SDoug Rabson static int
keychain_free(hx509_certs certs,void * data)361c19800e8SDoug Rabson keychain_free(hx509_certs certs, void *data)
362c19800e8SDoug Rabson {
363c19800e8SDoug Rabson     struct ks_keychain *ctx = data;
364c19800e8SDoug Rabson     if (ctx->keychain)
365c19800e8SDoug Rabson 	CFRelease(ctx->keychain);
366c19800e8SDoug Rabson     memset(ctx, 0, sizeof(*ctx));
367c19800e8SDoug Rabson     free(ctx);
368c19800e8SDoug Rabson     return 0;
369c19800e8SDoug Rabson }
370c19800e8SDoug Rabson 
371c19800e8SDoug Rabson /*
372c19800e8SDoug Rabson  *
373c19800e8SDoug Rabson  */
374c19800e8SDoug Rabson 
375c19800e8SDoug Rabson struct iter {
376c19800e8SDoug Rabson     hx509_certs certs;
377c19800e8SDoug Rabson     void *cursor;
378c19800e8SDoug Rabson     SecKeychainSearchRef searchRef;
379c19800e8SDoug Rabson };
380c19800e8SDoug Rabson 
381c19800e8SDoug Rabson static int
keychain_iter_start(hx509_context context,hx509_certs certs,void * data,void ** cursor)382c19800e8SDoug Rabson keychain_iter_start(hx509_context context,
383c19800e8SDoug Rabson 		    hx509_certs certs, void *data, void **cursor)
384c19800e8SDoug Rabson {
385c19800e8SDoug Rabson     struct ks_keychain *ctx = data;
386c19800e8SDoug Rabson     struct iter *iter;
387c19800e8SDoug Rabson 
388c19800e8SDoug Rabson     iter = calloc(1, sizeof(*iter));
389c19800e8SDoug Rabson     if (iter == NULL) {
390c19800e8SDoug Rabson 	hx509_set_error_string(context, 0, ENOMEM, "out of memory");
391c19800e8SDoug Rabson 	return ENOMEM;
392c19800e8SDoug Rabson     }
393c19800e8SDoug Rabson 
394c19800e8SDoug Rabson     if (ctx->anchors) {
395c19800e8SDoug Rabson         CFArrayRef anchors;
396c19800e8SDoug Rabson 	int ret;
397c19800e8SDoug Rabson 	int i;
398c19800e8SDoug Rabson 
399c19800e8SDoug Rabson 	ret = hx509_certs_init(context, "MEMORY:ks-file-create",
400c19800e8SDoug Rabson 			       0, NULL, &iter->certs);
401c19800e8SDoug Rabson 	if (ret) {
402c19800e8SDoug Rabson 	    free(iter);
403c19800e8SDoug Rabson 	    return ret;
404c19800e8SDoug Rabson 	}
405c19800e8SDoug Rabson 
406c19800e8SDoug Rabson 	ret = SecTrustCopyAnchorCertificates(&anchors);
407c19800e8SDoug Rabson 	if (ret != 0) {
408c19800e8SDoug Rabson 	    hx509_certs_free(&iter->certs);
409c19800e8SDoug Rabson 	    free(iter);
410c19800e8SDoug Rabson 	    hx509_set_error_string(context, 0, ENOMEM,
411c19800e8SDoug Rabson 				   "Can't get trust anchors from Keychain");
412c19800e8SDoug Rabson 	    return ENOMEM;
413c19800e8SDoug Rabson 	}
414c19800e8SDoug Rabson 	for (i = 0; i < CFArrayGetCount(anchors); i++) {
415c19800e8SDoug Rabson 	    SecCertificateRef cr;
416c19800e8SDoug Rabson 	    hx509_cert cert;
417c19800e8SDoug Rabson 	    CSSM_DATA cssm;
418c19800e8SDoug Rabson 
419c19800e8SDoug Rabson 	    cr = (SecCertificateRef)CFArrayGetValueAtIndex(anchors, i);
420c19800e8SDoug Rabson 
421c19800e8SDoug Rabson 	    SecCertificateGetData(cr, &cssm);
422c19800e8SDoug Rabson 
423c19800e8SDoug Rabson 	    ret = hx509_cert_init_data(context, cssm.Data, cssm.Length, &cert);
424c19800e8SDoug Rabson 	    if (ret)
425c19800e8SDoug Rabson 		continue;
426c19800e8SDoug Rabson 
427c19800e8SDoug Rabson 	    ret = hx509_certs_add(context, iter->certs, cert);
428c19800e8SDoug Rabson 	    hx509_cert_free(cert);
429c19800e8SDoug Rabson 	}
430c19800e8SDoug Rabson 	CFRelease(anchors);
431c19800e8SDoug Rabson     }
432c19800e8SDoug Rabson 
433c19800e8SDoug Rabson     if (iter->certs) {
434c19800e8SDoug Rabson 	int ret;
435c19800e8SDoug Rabson 	ret = hx509_certs_start_seq(context, iter->certs, &iter->cursor);
436c19800e8SDoug Rabson 	if (ret) {
437c19800e8SDoug Rabson 	    hx509_certs_free(&iter->certs);
438c19800e8SDoug Rabson 	    free(iter);
439c19800e8SDoug Rabson 	    return ret;
440c19800e8SDoug Rabson 	}
441c19800e8SDoug Rabson     } else {
442c19800e8SDoug Rabson 	OSStatus ret;
443c19800e8SDoug Rabson 
444c19800e8SDoug Rabson 	ret = SecKeychainSearchCreateFromAttributes(ctx->keychain,
445c19800e8SDoug Rabson 						    kSecCertificateItemClass,
446c19800e8SDoug Rabson 						    NULL,
447c19800e8SDoug Rabson 						    &iter->searchRef);
448c19800e8SDoug Rabson 	if (ret) {
449c19800e8SDoug Rabson 	    free(iter);
450c19800e8SDoug Rabson 	    hx509_set_error_string(context, 0, ret,
451c19800e8SDoug Rabson 				   "Failed to start search for attributes");
452c19800e8SDoug Rabson 	    return ENOMEM;
453c19800e8SDoug Rabson 	}
454c19800e8SDoug Rabson     }
455c19800e8SDoug Rabson 
456c19800e8SDoug Rabson     *cursor = iter;
457c19800e8SDoug Rabson     return 0;
458c19800e8SDoug Rabson }
459c19800e8SDoug Rabson 
460c19800e8SDoug Rabson /*
461c19800e8SDoug Rabson  *
462c19800e8SDoug Rabson  */
463c19800e8SDoug Rabson 
464c19800e8SDoug Rabson static int
keychain_iter(hx509_context context,hx509_certs certs,void * data,void * cursor,hx509_cert * cert)465c19800e8SDoug Rabson keychain_iter(hx509_context context,
466c19800e8SDoug Rabson 	      hx509_certs certs, void *data, void *cursor, hx509_cert *cert)
467c19800e8SDoug Rabson {
468c19800e8SDoug Rabson     SecKeychainAttributeList *attrs = NULL;
469c19800e8SDoug Rabson     SecKeychainAttributeInfo attrInfo;
470c19800e8SDoug Rabson     UInt32 attrFormat[1] = { 0 };
471c19800e8SDoug Rabson     SecKeychainItemRef itemRef;
472c19800e8SDoug Rabson     SecItemAttr item[1];
473c19800e8SDoug Rabson     struct iter *iter = cursor;
474c19800e8SDoug Rabson     OSStatus ret;
475c19800e8SDoug Rabson     UInt32 len;
476c19800e8SDoug Rabson     void *ptr = NULL;
477c19800e8SDoug Rabson 
478c19800e8SDoug Rabson     if (iter->certs)
479c19800e8SDoug Rabson 	return hx509_certs_next_cert(context, iter->certs, iter->cursor, cert);
480c19800e8SDoug Rabson 
481c19800e8SDoug Rabson     *cert = NULL;
482c19800e8SDoug Rabson 
483c19800e8SDoug Rabson     ret = SecKeychainSearchCopyNext(iter->searchRef, &itemRef);
484c19800e8SDoug Rabson     if (ret == errSecItemNotFound)
485c19800e8SDoug Rabson 	return 0;
486c19800e8SDoug Rabson     else if (ret != 0)
487c19800e8SDoug Rabson 	return EINVAL;
488c19800e8SDoug Rabson 
489c19800e8SDoug Rabson     /*
490c19800e8SDoug Rabson      * Pick out certificate and matching "keyid"
491c19800e8SDoug Rabson      */
492c19800e8SDoug Rabson 
493c19800e8SDoug Rabson     item[0] = kSecPublicKeyHashItemAttr;
494c19800e8SDoug Rabson 
495c19800e8SDoug Rabson     attrInfo.count = 1;
496c19800e8SDoug Rabson     attrInfo.tag = item;
497c19800e8SDoug Rabson     attrInfo.format = attrFormat;
498c19800e8SDoug Rabson 
499c19800e8SDoug Rabson     ret = SecKeychainItemCopyAttributesAndData(itemRef, &attrInfo, NULL,
500c19800e8SDoug Rabson 					       &attrs, &len, &ptr);
501c19800e8SDoug Rabson     if (ret)
502c19800e8SDoug Rabson 	return EINVAL;
503c19800e8SDoug Rabson 
504c19800e8SDoug Rabson     ret = hx509_cert_init_data(context, ptr, len, cert);
505c19800e8SDoug Rabson     if (ret)
506c19800e8SDoug Rabson 	goto out;
507c19800e8SDoug Rabson 
508c19800e8SDoug Rabson     /*
509c19800e8SDoug Rabson      * Find related private key if there is one by looking at
510c19800e8SDoug Rabson      * kSecPublicKeyHashItemAttr == kSecKeyLabel
511c19800e8SDoug Rabson      */
512c19800e8SDoug Rabson     {
513c19800e8SDoug Rabson 	SecKeychainSearchRef search;
514c19800e8SDoug Rabson 	SecKeychainAttribute attrKeyid;
515c19800e8SDoug Rabson 	SecKeychainAttributeList attrList;
516c19800e8SDoug Rabson 
517c19800e8SDoug Rabson 	attrKeyid.tag = kSecKeyLabel;
518c19800e8SDoug Rabson 	attrKeyid.length = attrs->attr[0].length;
519c19800e8SDoug Rabson 	attrKeyid.data = attrs->attr[0].data;
520c19800e8SDoug Rabson 
521c19800e8SDoug Rabson 	attrList.count = 1;
522c19800e8SDoug Rabson 	attrList.attr = &attrKeyid;
523c19800e8SDoug Rabson 
524c19800e8SDoug Rabson 	ret = SecKeychainSearchCreateFromAttributes(NULL,
525c19800e8SDoug Rabson 						    CSSM_DL_DB_RECORD_PRIVATE_KEY,
526c19800e8SDoug Rabson 						    &attrList,
527c19800e8SDoug Rabson 						    &search);
528c19800e8SDoug Rabson 	if (ret) {
529c19800e8SDoug Rabson 	    ret = 0;
530c19800e8SDoug Rabson 	    goto out;
531c19800e8SDoug Rabson 	}
532c19800e8SDoug Rabson 
533c19800e8SDoug Rabson 	ret = SecKeychainSearchCopyNext(search, &itemRef);
534c19800e8SDoug Rabson 	CFRelease(search);
535c19800e8SDoug Rabson 	if (ret == errSecItemNotFound) {
536c19800e8SDoug Rabson 	    ret = 0;
537c19800e8SDoug Rabson 	    goto out;
538c19800e8SDoug Rabson 	} else if (ret) {
539c19800e8SDoug Rabson 	    ret = EINVAL;
540c19800e8SDoug Rabson 	    goto out;
541c19800e8SDoug Rabson 	}
542c19800e8SDoug Rabson 	set_private_key(context, itemRef, *cert);
543c19800e8SDoug Rabson     }
544c19800e8SDoug Rabson 
545c19800e8SDoug Rabson out:
546c19800e8SDoug Rabson     SecKeychainItemFreeAttributesAndData(attrs, ptr);
547c19800e8SDoug Rabson 
548c19800e8SDoug Rabson     return ret;
549c19800e8SDoug Rabson }
550c19800e8SDoug Rabson 
551c19800e8SDoug Rabson /*
552c19800e8SDoug Rabson  *
553c19800e8SDoug Rabson  */
554c19800e8SDoug Rabson 
555c19800e8SDoug Rabson static int
keychain_iter_end(hx509_context context,hx509_certs certs,void * data,void * cursor)556c19800e8SDoug Rabson keychain_iter_end(hx509_context context,
557c19800e8SDoug Rabson 		  hx509_certs certs,
558c19800e8SDoug Rabson 		  void *data,
559c19800e8SDoug Rabson 		  void *cursor)
560c19800e8SDoug Rabson {
561c19800e8SDoug Rabson     struct iter *iter = cursor;
562c19800e8SDoug Rabson 
563c19800e8SDoug Rabson     if (iter->certs) {
564*ae771770SStanislav Sedov 	hx509_certs_end_seq(context, iter->certs, iter->cursor);
565c19800e8SDoug Rabson 	hx509_certs_free(&iter->certs);
566c19800e8SDoug Rabson     } else {
567c19800e8SDoug Rabson 	CFRelease(iter->searchRef);
568c19800e8SDoug Rabson     }
569c19800e8SDoug Rabson 
570c19800e8SDoug Rabson     memset(iter, 0, sizeof(*iter));
571c19800e8SDoug Rabson     free(iter);
572c19800e8SDoug Rabson     return 0;
573c19800e8SDoug Rabson }
574c19800e8SDoug Rabson 
575c19800e8SDoug Rabson /*
576c19800e8SDoug Rabson  *
577c19800e8SDoug Rabson  */
578c19800e8SDoug Rabson 
579c19800e8SDoug Rabson struct hx509_keyset_ops keyset_keychain = {
580c19800e8SDoug Rabson     "KEYCHAIN",
581c19800e8SDoug Rabson     0,
582c19800e8SDoug Rabson     keychain_init,
583c19800e8SDoug Rabson     NULL,
584c19800e8SDoug Rabson     keychain_free,
585c19800e8SDoug Rabson     NULL,
586c19800e8SDoug Rabson     NULL,
587c19800e8SDoug Rabson     keychain_iter_start,
588c19800e8SDoug Rabson     keychain_iter,
589c19800e8SDoug Rabson     keychain_iter_end
590c19800e8SDoug Rabson };
591c19800e8SDoug Rabson 
592c19800e8SDoug Rabson #endif /* HAVE_FRAMEWORK_SECURITY */
593c19800e8SDoug Rabson 
594c19800e8SDoug Rabson /*
595c19800e8SDoug Rabson  *
596c19800e8SDoug Rabson  */
597c19800e8SDoug Rabson 
598c19800e8SDoug Rabson void
_hx509_ks_keychain_register(hx509_context context)599c19800e8SDoug Rabson _hx509_ks_keychain_register(hx509_context context)
600c19800e8SDoug Rabson {
601c19800e8SDoug Rabson #ifdef HAVE_FRAMEWORK_SECURITY
602c19800e8SDoug Rabson     _hx509_ks_register(context, &keyset_keychain);
603c19800e8SDoug Rabson #endif
604c19800e8SDoug Rabson }
605