1178825Sdfr/*
2233294Sstas * Copyright (c) 2007 Kungliga Tekniska H��gskolan
3233294Sstas * (Royal Institute of Technology, Stockholm, Sweden).
4233294Sstas * All rights reserved.
5178825Sdfr *
6233294Sstas * Redistribution and use in source and binary forms, with or without
7233294Sstas * modification, are permitted provided that the following conditions
8233294Sstas * are met:
9178825Sdfr *
10233294Sstas * 1. Redistributions of source code must retain the above copyright
11233294Sstas *    notice, this list of conditions and the following disclaimer.
12178825Sdfr *
13233294Sstas * 2. Redistributions in binary form must reproduce the above copyright
14233294Sstas *    notice, this list of conditions and the following disclaimer in the
15233294Sstas *    documentation and/or other materials provided with the distribution.
16178825Sdfr *
17233294Sstas * 3. Neither the name of the Institute nor the names of its contributors
18233294Sstas *    may be used to endorse or promote products derived from this software
19233294Sstas *    without specific prior written permission.
20178825Sdfr *
21233294Sstas * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22233294Sstas * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23233294Sstas * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24233294Sstas * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25233294Sstas * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26233294Sstas * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27233294Sstas * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28233294Sstas * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29233294Sstas * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30233294Sstas * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31233294Sstas * SUCH DAMAGE.
32178825Sdfr */
33178825Sdfr
34178825Sdfr#include "hx_locl.h"
35178825Sdfr
36178825Sdfr#ifdef HAVE_FRAMEWORK_SECURITY
37178825Sdfr
38178825Sdfr#include <Security/Security.h>
39178825Sdfr
40178825Sdfr/* Missing function decls in pre Leopard */
41178825Sdfr#ifdef NEED_SECKEYGETCSPHANDLE_PROTO
42178825SdfrOSStatus SecKeyGetCSPHandle(SecKeyRef, CSSM_CSP_HANDLE *);
43178825SdfrOSStatus SecKeyGetCredentials(SecKeyRef, CSSM_ACL_AUTHORIZATION_TAG,
44178825Sdfr			      int, const CSSM_ACCESS_CREDENTIALS **);
45178825Sdfr#define kSecCredentialTypeDefault 0
46233294Sstas#define CSSM_SIZE uint32_t
47178825Sdfr#endif
48178825Sdfr
49178825Sdfr
50178825Sdfrstatic int
51178825SdfrgetAttribute(SecKeychainItemRef itemRef, SecItemAttr item,
52178825Sdfr	     SecKeychainAttributeList **attrs)
53233294Sstas{
54178825Sdfr    SecKeychainAttributeInfo attrInfo;
55178825Sdfr    UInt32 attrFormat = 0;
56178825Sdfr    OSStatus ret;
57178825Sdfr
58178825Sdfr    *attrs = NULL;
59178825Sdfr
60178825Sdfr    attrInfo.count = 1;
61178825Sdfr    attrInfo.tag = &item;
62178825Sdfr    attrInfo.format = &attrFormat;
63233294Sstas
64178825Sdfr    ret = SecKeychainItemCopyAttributesAndData(itemRef, &attrInfo, NULL,
65178825Sdfr					       attrs, NULL, NULL);
66178825Sdfr    if (ret)
67178825Sdfr	return EINVAL;
68178825Sdfr    return 0;
69178825Sdfr}
70178825Sdfr
71178825Sdfr
72178825Sdfr/*
73178825Sdfr *
74178825Sdfr */
75178825Sdfr
76178825Sdfrstruct kc_rsa {
77178825Sdfr    SecKeychainItemRef item;
78178825Sdfr    size_t keysize;
79178825Sdfr};
80178825Sdfr
81178825Sdfr
82178825Sdfrstatic int
83178825Sdfrkc_rsa_public_encrypt(int flen,
84178825Sdfr		      const unsigned char *from,
85178825Sdfr		      unsigned char *to,
86178825Sdfr		      RSA *rsa,
87178825Sdfr		      int padding)
88178825Sdfr{
89178825Sdfr    return -1;
90178825Sdfr}
91178825Sdfr
92178825Sdfrstatic int
93178825Sdfrkc_rsa_public_decrypt(int flen,
94178825Sdfr		      const unsigned char *from,
95178825Sdfr		      unsigned char *to,
96178825Sdfr		      RSA *rsa,
97178825Sdfr		      int padding)
98178825Sdfr{
99178825Sdfr    return -1;
100178825Sdfr}
101178825Sdfr
102178825Sdfr
103178825Sdfrstatic int
104233294Sstaskc_rsa_private_encrypt(int flen,
105178825Sdfr		       const unsigned char *from,
106178825Sdfr		       unsigned char *to,
107178825Sdfr		       RSA *rsa,
108178825Sdfr		       int padding)
109178825Sdfr{
110178825Sdfr    struct kc_rsa *kc = RSA_get_app_data(rsa);
111178825Sdfr
112178825Sdfr    CSSM_RETURN cret;
113178825Sdfr    OSStatus ret;
114178825Sdfr    const CSSM_ACCESS_CREDENTIALS *creds;
115178825Sdfr    SecKeyRef privKeyRef = (SecKeyRef)kc->item;
116178825Sdfr    CSSM_CSP_HANDLE cspHandle;
117178825Sdfr    const CSSM_KEY *cssmKey;
118178825Sdfr    CSSM_CC_HANDLE sigHandle = 0;
119178825Sdfr    CSSM_DATA sig, in;
120178825Sdfr    int fret = 0;
121178825Sdfr
122233294Sstas    if (padding != RSA_PKCS1_PADDING)
123233294Sstas	return -1;
124178825Sdfr
125178825Sdfr    cret = SecKeyGetCSSMKey(privKeyRef, &cssmKey);
126178825Sdfr    if(cret) abort();
127178825Sdfr
128178825Sdfr    cret = SecKeyGetCSPHandle(privKeyRef, &cspHandle);
129178825Sdfr    if(cret) abort();
130178825Sdfr
131178825Sdfr    ret = SecKeyGetCredentials(privKeyRef, CSSM_ACL_AUTHORIZATION_SIGN,
132178825Sdfr			       kSecCredentialTypeDefault, &creds);
133178825Sdfr    if(ret) abort();
134178825Sdfr
135178825Sdfr    ret = CSSM_CSP_CreateSignatureContext(cspHandle, CSSM_ALGID_RSA,
136178825Sdfr					  creds, cssmKey, &sigHandle);
137178825Sdfr    if(ret) abort();
138178825Sdfr
139178825Sdfr    in.Data = (uint8 *)from;
140178825Sdfr    in.Length = flen;
141233294Sstas
142178825Sdfr    sig.Data = (uint8 *)to;
143178825Sdfr    sig.Length = kc->keysize;
144233294Sstas
145178825Sdfr    cret = CSSM_SignData(sigHandle, &in, 1, CSSM_ALGID_NONE, &sig);
146178825Sdfr    if(cret) {
147178825Sdfr	/* cssmErrorString(cret); */
148178825Sdfr	fret = -1;
149178825Sdfr    } else
150178825Sdfr	fret = sig.Length;
151178825Sdfr
152178825Sdfr    if(sigHandle)
153178825Sdfr	CSSM_DeleteContext(sigHandle);
154178825Sdfr
155178825Sdfr    return fret;
156178825Sdfr}
157178825Sdfr
158178825Sdfrstatic int
159178825Sdfrkc_rsa_private_decrypt(int flen, const unsigned char *from, unsigned char *to,
160178825Sdfr		       RSA * rsa, int padding)
161178825Sdfr{
162233294Sstas    struct kc_rsa *kc = RSA_get_app_data(rsa);
163233294Sstas
164233294Sstas    CSSM_RETURN cret;
165233294Sstas    OSStatus ret;
166233294Sstas    const CSSM_ACCESS_CREDENTIALS *creds;
167233294Sstas    SecKeyRef privKeyRef = (SecKeyRef)kc->item;
168233294Sstas    CSSM_CSP_HANDLE cspHandle;
169233294Sstas    const CSSM_KEY *cssmKey;
170233294Sstas    CSSM_CC_HANDLE handle = 0;
171233294Sstas    CSSM_DATA out, in, rem;
172233294Sstas    int fret = 0;
173233294Sstas    CSSM_SIZE outlen = 0;
174233294Sstas    char remdata[1024];
175233294Sstas
176233294Sstas    if (padding != RSA_PKCS1_PADDING)
177233294Sstas	return -1;
178233294Sstas
179233294Sstas    cret = SecKeyGetCSSMKey(privKeyRef, &cssmKey);
180233294Sstas    if(cret) abort();
181233294Sstas
182233294Sstas    cret = SecKeyGetCSPHandle(privKeyRef, &cspHandle);
183233294Sstas    if(cret) abort();
184233294Sstas
185233294Sstas    ret = SecKeyGetCredentials(privKeyRef, CSSM_ACL_AUTHORIZATION_DECRYPT,
186233294Sstas			       kSecCredentialTypeDefault, &creds);
187233294Sstas    if(ret) abort();
188233294Sstas
189233294Sstas
190233294Sstas    ret = CSSM_CSP_CreateAsymmetricContext (cspHandle,
191233294Sstas					    CSSM_ALGID_RSA,
192233294Sstas					    creds,
193233294Sstas					    cssmKey,
194233294Sstas					    CSSM_PADDING_PKCS1,
195233294Sstas					    &handle);
196233294Sstas    if(ret) abort();
197233294Sstas
198233294Sstas    in.Data = (uint8 *)from;
199233294Sstas    in.Length = flen;
200233294Sstas
201233294Sstas    out.Data = (uint8 *)to;
202233294Sstas    out.Length = kc->keysize;
203233294Sstas
204233294Sstas    rem.Data = (uint8 *)remdata;
205233294Sstas    rem.Length = sizeof(remdata);
206233294Sstas
207233294Sstas    cret = CSSM_DecryptData(handle, &in, 1, &out, 1, &outlen, &rem);
208233294Sstas    if(cret) {
209233294Sstas	/* cssmErrorString(cret); */
210233294Sstas	fret = -1;
211233294Sstas    } else
212233294Sstas	fret = out.Length;
213233294Sstas
214233294Sstas    if(handle)
215233294Sstas	CSSM_DeleteContext(handle);
216233294Sstas
217233294Sstas    return fret;
218178825Sdfr}
219178825Sdfr
220233294Sstasstatic int
221178825Sdfrkc_rsa_init(RSA *rsa)
222178825Sdfr{
223178825Sdfr    return 1;
224178825Sdfr}
225178825Sdfr
226178825Sdfrstatic int
227178825Sdfrkc_rsa_finish(RSA *rsa)
228178825Sdfr{
229178825Sdfr    struct kc_rsa *kc_rsa = RSA_get_app_data(rsa);
230178825Sdfr    CFRelease(kc_rsa->item);
231178825Sdfr    memset(kc_rsa, 0, sizeof(*kc_rsa));
232178825Sdfr    free(kc_rsa);
233178825Sdfr    return 1;
234178825Sdfr}
235178825Sdfr
236178825Sdfrstatic const RSA_METHOD kc_rsa_pkcs1_method = {
237178825Sdfr    "hx509 Keychain PKCS#1 RSA",
238178825Sdfr    kc_rsa_public_encrypt,
239178825Sdfr    kc_rsa_public_decrypt,
240178825Sdfr    kc_rsa_private_encrypt,
241178825Sdfr    kc_rsa_private_decrypt,
242178825Sdfr    NULL,
243178825Sdfr    NULL,
244178825Sdfr    kc_rsa_init,
245178825Sdfr    kc_rsa_finish,
246178825Sdfr    0,
247178825Sdfr    NULL,
248178825Sdfr    NULL,
249178825Sdfr    NULL
250178825Sdfr};
251178825Sdfr
252178825Sdfrstatic int
253178825Sdfrset_private_key(hx509_context context,
254178825Sdfr		SecKeychainItemRef itemRef,
255178825Sdfr		hx509_cert cert)
256178825Sdfr{
257178825Sdfr    struct kc_rsa *kc;
258178825Sdfr    hx509_private_key key;
259178825Sdfr    RSA *rsa;
260178825Sdfr    int ret;
261178825Sdfr
262233294Sstas    ret = hx509_private_key_init(&key, NULL, NULL);
263178825Sdfr    if (ret)
264178825Sdfr	return ret;
265178825Sdfr
266178825Sdfr    kc = calloc(1, sizeof(*kc));
267178825Sdfr    if (kc == NULL)
268178825Sdfr	_hx509_abort("out of memory");
269178825Sdfr
270178825Sdfr    kc->item = itemRef;
271178825Sdfr
272178825Sdfr    rsa = RSA_new();
273178825Sdfr    if (rsa == NULL)
274178825Sdfr	_hx509_abort("out of memory");
275178825Sdfr
276178825Sdfr    /* Argh, fake modulus since OpenSSL API is on crack */
277178825Sdfr    {
278178825Sdfr	SecKeychainAttributeList *attrs = NULL;
279178825Sdfr	uint32_t size;
280178825Sdfr	void *data;
281178825Sdfr
282178825Sdfr	rsa->n = BN_new();
283178825Sdfr	if (rsa->n == NULL) abort();
284178825Sdfr
285178825Sdfr	ret = getAttribute(itemRef, kSecKeyKeySizeInBits, &attrs);
286178825Sdfr	if (ret) abort();
287178825Sdfr
288178825Sdfr	size = *(uint32_t *)attrs->attr[0].data;
289178825Sdfr	SecKeychainItemFreeAttributesAndData(attrs, NULL);
290178825Sdfr
291178825Sdfr	kc->keysize = (size + 7) / 8;
292178825Sdfr
293178825Sdfr	data = malloc(kc->keysize);
294178825Sdfr	memset(data, 0xe0, kc->keysize);
295178825Sdfr	BN_bin2bn(data, kc->keysize, rsa->n);
296178825Sdfr	free(data);
297178825Sdfr    }
298178825Sdfr    rsa->e = NULL;
299178825Sdfr
300178825Sdfr    RSA_set_method(rsa, &kc_rsa_pkcs1_method);
301178825Sdfr    ret = RSA_set_app_data(rsa, kc);
302178825Sdfr    if (ret != 1)
303178825Sdfr	_hx509_abort("RSA_set_app_data");
304178825Sdfr
305233294Sstas    hx509_private_key_assign_rsa(key, rsa);
306178825Sdfr    _hx509_cert_assign_key(cert, key);
307178825Sdfr
308178825Sdfr    return 0;
309178825Sdfr}
310178825Sdfr
311178825Sdfr/*
312178825Sdfr *
313178825Sdfr */
314178825Sdfr
315178825Sdfrstruct ks_keychain {
316178825Sdfr    int anchors;
317178825Sdfr    SecKeychainRef keychain;
318178825Sdfr};
319178825Sdfr
320178825Sdfrstatic int
321178825Sdfrkeychain_init(hx509_context context,
322178825Sdfr	      hx509_certs certs, void **data, int flags,
323178825Sdfr	      const char *residue, hx509_lock lock)
324178825Sdfr{
325178825Sdfr    struct ks_keychain *ctx;
326178825Sdfr
327178825Sdfr    ctx = calloc(1, sizeof(*ctx));
328178825Sdfr    if (ctx == NULL) {
329178825Sdfr	hx509_clear_error_string(context);
330178825Sdfr	return ENOMEM;
331178825Sdfr    }
332178825Sdfr
333178825Sdfr    if (residue) {
334178825Sdfr	if (strcasecmp(residue, "system-anchors") == 0) {
335178825Sdfr	    ctx->anchors = 1;
336178825Sdfr	} else if (strncasecmp(residue, "FILE:", 5) == 0) {
337178825Sdfr	    OSStatus ret;
338178825Sdfr
339178825Sdfr	    ret = SecKeychainOpen(residue + 5, &ctx->keychain);
340178825Sdfr	    if (ret != noErr) {
341233294Sstas		hx509_set_error_string(context, 0, ENOENT,
342178825Sdfr				       "Failed to open %s", residue);
343178825Sdfr		return ENOENT;
344178825Sdfr	    }
345178825Sdfr	} else {
346233294Sstas	    hx509_set_error_string(context, 0, ENOENT,
347178825Sdfr				   "Unknown subtype %s", residue);
348178825Sdfr	    return ENOENT;
349178825Sdfr	}
350178825Sdfr    }
351178825Sdfr
352178825Sdfr    *data = ctx;
353178825Sdfr    return 0;
354178825Sdfr}
355178825Sdfr
356178825Sdfr/*
357178825Sdfr *
358178825Sdfr */
359178825Sdfr
360178825Sdfrstatic int
361178825Sdfrkeychain_free(hx509_certs certs, void *data)
362178825Sdfr{
363178825Sdfr    struct ks_keychain *ctx = data;
364178825Sdfr    if (ctx->keychain)
365178825Sdfr	CFRelease(ctx->keychain);
366178825Sdfr    memset(ctx, 0, sizeof(*ctx));
367178825Sdfr    free(ctx);
368178825Sdfr    return 0;
369178825Sdfr}
370178825Sdfr
371178825Sdfr/*
372178825Sdfr *
373178825Sdfr */
374178825Sdfr
375178825Sdfrstruct iter {
376178825Sdfr    hx509_certs certs;
377178825Sdfr    void *cursor;
378178825Sdfr    SecKeychainSearchRef searchRef;
379178825Sdfr};
380178825Sdfr
381233294Sstasstatic int
382178825Sdfrkeychain_iter_start(hx509_context context,
383178825Sdfr		    hx509_certs certs, void *data, void **cursor)
384178825Sdfr{
385178825Sdfr    struct ks_keychain *ctx = data;
386178825Sdfr    struct iter *iter;
387178825Sdfr
388178825Sdfr    iter = calloc(1, sizeof(*iter));
389178825Sdfr    if (iter == NULL) {
390178825Sdfr	hx509_set_error_string(context, 0, ENOMEM, "out of memory");
391178825Sdfr	return ENOMEM;
392178825Sdfr    }
393178825Sdfr
394178825Sdfr    if (ctx->anchors) {
395178825Sdfr        CFArrayRef anchors;
396178825Sdfr	int ret;
397178825Sdfr	int i;
398178825Sdfr
399233294Sstas	ret = hx509_certs_init(context, "MEMORY:ks-file-create",
400178825Sdfr			       0, NULL, &iter->certs);
401178825Sdfr	if (ret) {
402178825Sdfr	    free(iter);
403178825Sdfr	    return ret;
404178825Sdfr	}
405178825Sdfr
406178825Sdfr	ret = SecTrustCopyAnchorCertificates(&anchors);
407178825Sdfr	if (ret != 0) {
408178825Sdfr	    hx509_certs_free(&iter->certs);
409178825Sdfr	    free(iter);
410233294Sstas	    hx509_set_error_string(context, 0, ENOMEM,
411178825Sdfr				   "Can't get trust anchors from Keychain");
412178825Sdfr	    return ENOMEM;
413178825Sdfr	}
414178825Sdfr	for (i = 0; i < CFArrayGetCount(anchors); i++) {
415233294Sstas	    SecCertificateRef cr;
416178825Sdfr	    hx509_cert cert;
417178825Sdfr	    CSSM_DATA cssm;
418178825Sdfr
419178825Sdfr	    cr = (SecCertificateRef)CFArrayGetValueAtIndex(anchors, i);
420178825Sdfr
421178825Sdfr	    SecCertificateGetData(cr, &cssm);
422178825Sdfr
423178825Sdfr	    ret = hx509_cert_init_data(context, cssm.Data, cssm.Length, &cert);
424178825Sdfr	    if (ret)
425178825Sdfr		continue;
426178825Sdfr
427178825Sdfr	    ret = hx509_certs_add(context, iter->certs, cert);
428178825Sdfr	    hx509_cert_free(cert);
429178825Sdfr	}
430178825Sdfr	CFRelease(anchors);
431178825Sdfr    }
432178825Sdfr
433178825Sdfr    if (iter->certs) {
434178825Sdfr	int ret;
435178825Sdfr	ret = hx509_certs_start_seq(context, iter->certs, &iter->cursor);
436178825Sdfr	if (ret) {
437178825Sdfr	    hx509_certs_free(&iter->certs);
438178825Sdfr	    free(iter);
439178825Sdfr	    return ret;
440178825Sdfr	}
441178825Sdfr    } else {
442178825Sdfr	OSStatus ret;
443178825Sdfr
444178825Sdfr	ret = SecKeychainSearchCreateFromAttributes(ctx->keychain,
445178825Sdfr						    kSecCertificateItemClass,
446178825Sdfr						    NULL,
447178825Sdfr						    &iter->searchRef);
448178825Sdfr	if (ret) {
449178825Sdfr	    free(iter);
450233294Sstas	    hx509_set_error_string(context, 0, ret,
451178825Sdfr				   "Failed to start search for attributes");
452178825Sdfr	    return ENOMEM;
453178825Sdfr	}
454178825Sdfr    }
455178825Sdfr
456178825Sdfr    *cursor = iter;
457178825Sdfr    return 0;
458178825Sdfr}
459178825Sdfr
460178825Sdfr/*
461178825Sdfr *
462178825Sdfr */
463178825Sdfr
464178825Sdfrstatic int
465178825Sdfrkeychain_iter(hx509_context context,
466178825Sdfr	      hx509_certs certs, void *data, void *cursor, hx509_cert *cert)
467178825Sdfr{
468178825Sdfr    SecKeychainAttributeList *attrs = NULL;
469178825Sdfr    SecKeychainAttributeInfo attrInfo;
470178825Sdfr    UInt32 attrFormat[1] = { 0 };
471178825Sdfr    SecKeychainItemRef itemRef;
472178825Sdfr    SecItemAttr item[1];
473178825Sdfr    struct iter *iter = cursor;
474178825Sdfr    OSStatus ret;
475178825Sdfr    UInt32 len;
476178825Sdfr    void *ptr = NULL;
477178825Sdfr
478178825Sdfr    if (iter->certs)
479178825Sdfr	return hx509_certs_next_cert(context, iter->certs, iter->cursor, cert);
480178825Sdfr
481178825Sdfr    *cert = NULL;
482178825Sdfr
483178825Sdfr    ret = SecKeychainSearchCopyNext(iter->searchRef, &itemRef);
484178825Sdfr    if (ret == errSecItemNotFound)
485178825Sdfr	return 0;
486178825Sdfr    else if (ret != 0)
487178825Sdfr	return EINVAL;
488233294Sstas
489178825Sdfr    /*
490178825Sdfr     * Pick out certificate and matching "keyid"
491178825Sdfr     */
492178825Sdfr
493178825Sdfr    item[0] = kSecPublicKeyHashItemAttr;
494178825Sdfr
495178825Sdfr    attrInfo.count = 1;
496178825Sdfr    attrInfo.tag = item;
497178825Sdfr    attrInfo.format = attrFormat;
498233294Sstas
499178825Sdfr    ret = SecKeychainItemCopyAttributesAndData(itemRef, &attrInfo, NULL,
500178825Sdfr					       &attrs, &len, &ptr);
501178825Sdfr    if (ret)
502178825Sdfr	return EINVAL;
503178825Sdfr
504178825Sdfr    ret = hx509_cert_init_data(context, ptr, len, cert);
505178825Sdfr    if (ret)
506178825Sdfr	goto out;
507178825Sdfr
508233294Sstas    /*
509178825Sdfr     * Find related private key if there is one by looking at
510178825Sdfr     * kSecPublicKeyHashItemAttr == kSecKeyLabel
511178825Sdfr     */
512178825Sdfr    {
513178825Sdfr	SecKeychainSearchRef search;
514178825Sdfr	SecKeychainAttribute attrKeyid;
515178825Sdfr	SecKeychainAttributeList attrList;
516178825Sdfr
517178825Sdfr	attrKeyid.tag = kSecKeyLabel;
518178825Sdfr	attrKeyid.length = attrs->attr[0].length;
519178825Sdfr	attrKeyid.data = attrs->attr[0].data;
520233294Sstas
521178825Sdfr	attrList.count = 1;
522178825Sdfr	attrList.attr = &attrKeyid;
523178825Sdfr
524178825Sdfr	ret = SecKeychainSearchCreateFromAttributes(NULL,
525178825Sdfr						    CSSM_DL_DB_RECORD_PRIVATE_KEY,
526178825Sdfr						    &attrList,
527178825Sdfr						    &search);
528178825Sdfr	if (ret) {
529178825Sdfr	    ret = 0;
530178825Sdfr	    goto out;
531178825Sdfr	}
532178825Sdfr
533178825Sdfr	ret = SecKeychainSearchCopyNext(search, &itemRef);
534178825Sdfr	CFRelease(search);
535178825Sdfr	if (ret == errSecItemNotFound) {
536178825Sdfr	    ret = 0;
537178825Sdfr	    goto out;
538178825Sdfr	} else if (ret) {
539178825Sdfr	    ret = EINVAL;
540178825Sdfr	    goto out;
541178825Sdfr	}
542178825Sdfr	set_private_key(context, itemRef, *cert);
543178825Sdfr    }
544178825Sdfr
545178825Sdfrout:
546178825Sdfr    SecKeychainItemFreeAttributesAndData(attrs, ptr);
547178825Sdfr
548178825Sdfr    return ret;
549178825Sdfr}
550178825Sdfr
551178825Sdfr/*
552178825Sdfr *
553178825Sdfr */
554178825Sdfr
555178825Sdfrstatic int
556178825Sdfrkeychain_iter_end(hx509_context context,
557178825Sdfr		  hx509_certs certs,
558178825Sdfr		  void *data,
559178825Sdfr		  void *cursor)
560178825Sdfr{
561178825Sdfr    struct iter *iter = cursor;
562178825Sdfr
563178825Sdfr    if (iter->certs) {
564233294Sstas	hx509_certs_end_seq(context, iter->certs, iter->cursor);
565178825Sdfr	hx509_certs_free(&iter->certs);
566178825Sdfr    } else {
567178825Sdfr	CFRelease(iter->searchRef);
568178825Sdfr    }
569178825Sdfr
570178825Sdfr    memset(iter, 0, sizeof(*iter));
571178825Sdfr    free(iter);
572178825Sdfr    return 0;
573178825Sdfr}
574178825Sdfr
575178825Sdfr/*
576178825Sdfr *
577178825Sdfr */
578178825Sdfr
579178825Sdfrstruct hx509_keyset_ops keyset_keychain = {
580178825Sdfr    "KEYCHAIN",
581178825Sdfr    0,
582178825Sdfr    keychain_init,
583178825Sdfr    NULL,
584178825Sdfr    keychain_free,
585178825Sdfr    NULL,
586178825Sdfr    NULL,
587178825Sdfr    keychain_iter_start,
588178825Sdfr    keychain_iter,
589178825Sdfr    keychain_iter_end
590178825Sdfr};
591178825Sdfr
592178825Sdfr#endif /* HAVE_FRAMEWORK_SECURITY */
593178825Sdfr
594178825Sdfr/*
595178825Sdfr *
596178825Sdfr */
597178825Sdfr
598178825Sdfrvoid
599178825Sdfr_hx509_ks_keychain_register(hx509_context context)
600178825Sdfr{
601178825Sdfr#ifdef HAVE_FRAMEWORK_SECURITY
602178825Sdfr    _hx509_ks_register(context, &keyset_keychain);
603178825Sdfr#endif
604178825Sdfr}
605