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