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