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