1178825Sdfr/*
2178825Sdfr * Copyright (c) 2007 Kungliga Tekniska H�gskolan
3178825Sdfr * (Royal Institute of Technology, Stockholm, Sweden).
4178825Sdfr * All rights reserved.
5178825Sdfr *
6178825Sdfr * Redistribution and use in source and binary forms, with or without
7178825Sdfr * modification, are permitted provided that the following conditions
8178825Sdfr * are met:
9178825Sdfr *
10178825Sdfr * 1. Redistributions of source code must retain the above copyright
11178825Sdfr *    notice, this list of conditions and the following disclaimer.
12178825Sdfr *
13178825Sdfr * 2. Redistributions in binary form must reproduce the above copyright
14178825Sdfr *    notice, this list of conditions and the following disclaimer in the
15178825Sdfr *    documentation and/or other materials provided with the distribution.
16178825Sdfr *
17178825Sdfr * 3. Neither the name of the Institute nor the names of its contributors
18178825Sdfr *    may be used to endorse or promote products derived from this software
19178825Sdfr *    without specific prior written permission.
20178825Sdfr *
21178825Sdfr * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22178825Sdfr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23178825Sdfr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24178825Sdfr * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25178825Sdfr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26178825Sdfr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27178825Sdfr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28178825Sdfr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29178825Sdfr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30178825Sdfr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31178825Sdfr * SUCH DAMAGE.
32178825Sdfr */
33178825Sdfr
34178825Sdfr#include "hx_locl.h"
35178825SdfrRCSID("$Id: ks_keychain.c 22084 2007-11-16 20:12:30Z lha $");
36178825Sdfr
37178825Sdfr#ifdef HAVE_FRAMEWORK_SECURITY
38178825Sdfr
39178825Sdfr#include <Security/Security.h>
40178825Sdfr
41178825Sdfr/* Missing function decls in pre Leopard */
42178825Sdfr#ifdef NEED_SECKEYGETCSPHANDLE_PROTO
43178825SdfrOSStatus SecKeyGetCSPHandle(SecKeyRef, CSSM_CSP_HANDLE *);
44178825SdfrOSStatus SecKeyGetCredentials(SecKeyRef, CSSM_ACL_AUTHORIZATION_TAG,
45178825Sdfr			      int, const CSSM_ACCESS_CREDENTIALS **);
46178825Sdfr#define kSecCredentialTypeDefault 0
47178825Sdfr#endif
48178825Sdfr
49178825Sdfr
50178825Sdfrstatic int
51178825SdfrgetAttribute(SecKeychainItemRef itemRef, SecItemAttr item,
52178825Sdfr	     SecKeychainAttributeList **attrs)
53178825Sdfr{
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;
63178825Sdfr
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
104178825Sdfrkc_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
122178825Sdfr
123178825Sdfr    cret = SecKeyGetCSSMKey(privKeyRef, &cssmKey);
124178825Sdfr    if(cret) abort();
125178825Sdfr
126178825Sdfr    cret = SecKeyGetCSPHandle(privKeyRef, &cspHandle);
127178825Sdfr    if(cret) abort();
128178825Sdfr
129178825Sdfr    ret = SecKeyGetCredentials(privKeyRef, CSSM_ACL_AUTHORIZATION_SIGN,
130178825Sdfr			       kSecCredentialTypeDefault, &creds);
131178825Sdfr    if(ret) abort();
132178825Sdfr
133178825Sdfr    ret = CSSM_CSP_CreateSignatureContext(cspHandle, CSSM_ALGID_RSA,
134178825Sdfr					  creds, cssmKey, &sigHandle);
135178825Sdfr    if(ret) abort();
136178825Sdfr
137178825Sdfr    in.Data = (uint8 *)from;
138178825Sdfr    in.Length = flen;
139178825Sdfr
140178825Sdfr    sig.Data = (uint8 *)to;
141178825Sdfr    sig.Length = kc->keysize;
142178825Sdfr
143178825Sdfr    cret = CSSM_SignData(sigHandle, &in, 1, CSSM_ALGID_NONE, &sig);
144178825Sdfr    if(cret) {
145178825Sdfr	/* cssmErrorString(cret); */
146178825Sdfr	fret = -1;
147178825Sdfr    } else
148178825Sdfr	fret = sig.Length;
149178825Sdfr
150178825Sdfr    if(sigHandle)
151178825Sdfr	CSSM_DeleteContext(sigHandle);
152178825Sdfr
153178825Sdfr    return fret;
154178825Sdfr}
155178825Sdfr
156178825Sdfrstatic int
157178825Sdfrkc_rsa_private_decrypt(int flen, const unsigned char *from, unsigned char *to,
158178825Sdfr		       RSA * rsa, int padding)
159178825Sdfr{
160178825Sdfr    return -1;
161178825Sdfr}
162178825Sdfr
163178825Sdfrstatic int
164178825Sdfrkc_rsa_init(RSA *rsa)
165178825Sdfr{
166178825Sdfr    return 1;
167178825Sdfr}
168178825Sdfr
169178825Sdfrstatic int
170178825Sdfrkc_rsa_finish(RSA *rsa)
171178825Sdfr{
172178825Sdfr    struct kc_rsa *kc_rsa = RSA_get_app_data(rsa);
173178825Sdfr    CFRelease(kc_rsa->item);
174178825Sdfr    memset(kc_rsa, 0, sizeof(*kc_rsa));
175178825Sdfr    free(kc_rsa);
176178825Sdfr    return 1;
177178825Sdfr}
178178825Sdfr
179178825Sdfrstatic const RSA_METHOD kc_rsa_pkcs1_method = {
180178825Sdfr    "hx509 Keychain PKCS#1 RSA",
181178825Sdfr    kc_rsa_public_encrypt,
182178825Sdfr    kc_rsa_public_decrypt,
183178825Sdfr    kc_rsa_private_encrypt,
184178825Sdfr    kc_rsa_private_decrypt,
185178825Sdfr    NULL,
186178825Sdfr    NULL,
187178825Sdfr    kc_rsa_init,
188178825Sdfr    kc_rsa_finish,
189178825Sdfr    0,
190178825Sdfr    NULL,
191178825Sdfr    NULL,
192178825Sdfr    NULL
193178825Sdfr};
194178825Sdfr
195178825Sdfrstatic int
196178825Sdfrset_private_key(hx509_context context,
197178825Sdfr		SecKeychainItemRef itemRef,
198178825Sdfr		hx509_cert cert)
199178825Sdfr{
200178825Sdfr    struct kc_rsa *kc;
201178825Sdfr    hx509_private_key key;
202178825Sdfr    RSA *rsa;
203178825Sdfr    int ret;
204178825Sdfr
205178825Sdfr    ret = _hx509_private_key_init(&key, NULL, NULL);
206178825Sdfr    if (ret)
207178825Sdfr	return ret;
208178825Sdfr
209178825Sdfr    kc = calloc(1, sizeof(*kc));
210178825Sdfr    if (kc == NULL)
211178825Sdfr	_hx509_abort("out of memory");
212178825Sdfr
213178825Sdfr    kc->item = itemRef;
214178825Sdfr
215178825Sdfr    rsa = RSA_new();
216178825Sdfr    if (rsa == NULL)
217178825Sdfr	_hx509_abort("out of memory");
218178825Sdfr
219178825Sdfr    /* Argh, fake modulus since OpenSSL API is on crack */
220178825Sdfr    {
221178825Sdfr	SecKeychainAttributeList *attrs = NULL;
222178825Sdfr	uint32_t size;
223178825Sdfr	void *data;
224178825Sdfr
225178825Sdfr	rsa->n = BN_new();
226178825Sdfr	if (rsa->n == NULL) abort();
227178825Sdfr
228178825Sdfr	ret = getAttribute(itemRef, kSecKeyKeySizeInBits, &attrs);
229178825Sdfr	if (ret) abort();
230178825Sdfr
231178825Sdfr	size = *(uint32_t *)attrs->attr[0].data;
232178825Sdfr	SecKeychainItemFreeAttributesAndData(attrs, NULL);
233178825Sdfr
234178825Sdfr	kc->keysize = (size + 7) / 8;
235178825Sdfr
236178825Sdfr	data = malloc(kc->keysize);
237178825Sdfr	memset(data, 0xe0, kc->keysize);
238178825Sdfr	BN_bin2bn(data, kc->keysize, rsa->n);
239178825Sdfr	free(data);
240178825Sdfr    }
241178825Sdfr    rsa->e = NULL;
242178825Sdfr
243178825Sdfr    RSA_set_method(rsa, &kc_rsa_pkcs1_method);
244178825Sdfr    ret = RSA_set_app_data(rsa, kc);
245178825Sdfr    if (ret != 1)
246178825Sdfr	_hx509_abort("RSA_set_app_data");
247178825Sdfr
248178825Sdfr    _hx509_private_key_assign_rsa(key, rsa);
249178825Sdfr    _hx509_cert_assign_key(cert, key);
250178825Sdfr
251178825Sdfr    return 0;
252178825Sdfr}
253178825Sdfr
254178825Sdfr/*
255178825Sdfr *
256178825Sdfr */
257178825Sdfr
258178825Sdfrstruct ks_keychain {
259178825Sdfr    int anchors;
260178825Sdfr    SecKeychainRef keychain;
261178825Sdfr};
262178825Sdfr
263178825Sdfrstatic int
264178825Sdfrkeychain_init(hx509_context context,
265178825Sdfr	      hx509_certs certs, void **data, int flags,
266178825Sdfr	      const char *residue, hx509_lock lock)
267178825Sdfr{
268178825Sdfr    struct ks_keychain *ctx;
269178825Sdfr
270178825Sdfr    ctx = calloc(1, sizeof(*ctx));
271178825Sdfr    if (ctx == NULL) {
272178825Sdfr	hx509_clear_error_string(context);
273178825Sdfr	return ENOMEM;
274178825Sdfr    }
275178825Sdfr
276178825Sdfr    if (residue) {
277178825Sdfr	if (strcasecmp(residue, "system-anchors") == 0) {
278178825Sdfr	    ctx->anchors = 1;
279178825Sdfr	} else if (strncasecmp(residue, "FILE:", 5) == 0) {
280178825Sdfr	    OSStatus ret;
281178825Sdfr
282178825Sdfr	    ret = SecKeychainOpen(residue + 5, &ctx->keychain);
283178825Sdfr	    if (ret != noErr) {
284178825Sdfr		hx509_set_error_string(context, 0, ENOENT,
285178825Sdfr				       "Failed to open %s", residue);
286178825Sdfr		return ENOENT;
287178825Sdfr	    }
288178825Sdfr	} else {
289178825Sdfr	    hx509_set_error_string(context, 0, ENOENT,
290178825Sdfr				   "Unknown subtype %s", residue);
291178825Sdfr	    return ENOENT;
292178825Sdfr	}
293178825Sdfr    }
294178825Sdfr
295178825Sdfr    *data = ctx;
296178825Sdfr    return 0;
297178825Sdfr}
298178825Sdfr
299178825Sdfr/*
300178825Sdfr *
301178825Sdfr */
302178825Sdfr
303178825Sdfrstatic int
304178825Sdfrkeychain_free(hx509_certs certs, void *data)
305178825Sdfr{
306178825Sdfr    struct ks_keychain *ctx = data;
307178825Sdfr    if (ctx->keychain)
308178825Sdfr	CFRelease(ctx->keychain);
309178825Sdfr    memset(ctx, 0, sizeof(*ctx));
310178825Sdfr    free(ctx);
311178825Sdfr    return 0;
312178825Sdfr}
313178825Sdfr
314178825Sdfr/*
315178825Sdfr *
316178825Sdfr */
317178825Sdfr
318178825Sdfrstruct iter {
319178825Sdfr    hx509_certs certs;
320178825Sdfr    void *cursor;
321178825Sdfr    SecKeychainSearchRef searchRef;
322178825Sdfr};
323178825Sdfr
324178825Sdfrstatic int
325178825Sdfrkeychain_iter_start(hx509_context context,
326178825Sdfr		    hx509_certs certs, void *data, void **cursor)
327178825Sdfr{
328178825Sdfr    struct ks_keychain *ctx = data;
329178825Sdfr    struct iter *iter;
330178825Sdfr
331178825Sdfr    iter = calloc(1, sizeof(*iter));
332178825Sdfr    if (iter == NULL) {
333178825Sdfr	hx509_set_error_string(context, 0, ENOMEM, "out of memory");
334178825Sdfr	return ENOMEM;
335178825Sdfr    }
336178825Sdfr
337178825Sdfr    if (ctx->anchors) {
338178825Sdfr        CFArrayRef anchors;
339178825Sdfr	int ret;
340178825Sdfr	int i;
341178825Sdfr
342178825Sdfr	ret = hx509_certs_init(context, "MEMORY:ks-file-create",
343178825Sdfr			       0, NULL, &iter->certs);
344178825Sdfr	if (ret) {
345178825Sdfr	    free(iter);
346178825Sdfr	    return ret;
347178825Sdfr	}
348178825Sdfr
349178825Sdfr	ret = SecTrustCopyAnchorCertificates(&anchors);
350178825Sdfr	if (ret != 0) {
351178825Sdfr	    hx509_certs_free(&iter->certs);
352178825Sdfr	    free(iter);
353178825Sdfr	    hx509_set_error_string(context, 0, ENOMEM,
354178825Sdfr				   "Can't get trust anchors from Keychain");
355178825Sdfr	    return ENOMEM;
356178825Sdfr	}
357178825Sdfr	for (i = 0; i < CFArrayGetCount(anchors); i++) {
358178825Sdfr	    SecCertificateRef cr;
359178825Sdfr	    hx509_cert cert;
360178825Sdfr	    CSSM_DATA cssm;
361178825Sdfr
362178825Sdfr	    cr = (SecCertificateRef)CFArrayGetValueAtIndex(anchors, i);
363178825Sdfr
364178825Sdfr	    SecCertificateGetData(cr, &cssm);
365178825Sdfr
366178825Sdfr	    ret = hx509_cert_init_data(context, cssm.Data, cssm.Length, &cert);
367178825Sdfr	    if (ret)
368178825Sdfr		continue;
369178825Sdfr
370178825Sdfr	    ret = hx509_certs_add(context, iter->certs, cert);
371178825Sdfr	    hx509_cert_free(cert);
372178825Sdfr	}
373178825Sdfr	CFRelease(anchors);
374178825Sdfr    }
375178825Sdfr
376178825Sdfr    if (iter->certs) {
377178825Sdfr	int ret;
378178825Sdfr	ret = hx509_certs_start_seq(context, iter->certs, &iter->cursor);
379178825Sdfr	if (ret) {
380178825Sdfr	    hx509_certs_free(&iter->certs);
381178825Sdfr	    free(iter);
382178825Sdfr	    return ret;
383178825Sdfr	}
384178825Sdfr    } else {
385178825Sdfr	OSStatus ret;
386178825Sdfr
387178825Sdfr	ret = SecKeychainSearchCreateFromAttributes(ctx->keychain,
388178825Sdfr						    kSecCertificateItemClass,
389178825Sdfr						    NULL,
390178825Sdfr						    &iter->searchRef);
391178825Sdfr	if (ret) {
392178825Sdfr	    free(iter);
393178825Sdfr	    hx509_set_error_string(context, 0, ret,
394178825Sdfr				   "Failed to start search for attributes");
395178825Sdfr	    return ENOMEM;
396178825Sdfr	}
397178825Sdfr    }
398178825Sdfr
399178825Sdfr    *cursor = iter;
400178825Sdfr    return 0;
401178825Sdfr}
402178825Sdfr
403178825Sdfr/*
404178825Sdfr *
405178825Sdfr */
406178825Sdfr
407178825Sdfrstatic int
408178825Sdfrkeychain_iter(hx509_context context,
409178825Sdfr	      hx509_certs certs, void *data, void *cursor, hx509_cert *cert)
410178825Sdfr{
411178825Sdfr    SecKeychainAttributeList *attrs = NULL;
412178825Sdfr    SecKeychainAttributeInfo attrInfo;
413178825Sdfr    UInt32 attrFormat[1] = { 0 };
414178825Sdfr    SecKeychainItemRef itemRef;
415178825Sdfr    SecItemAttr item[1];
416178825Sdfr    struct iter *iter = cursor;
417178825Sdfr    OSStatus ret;
418178825Sdfr    UInt32 len;
419178825Sdfr    void *ptr = NULL;
420178825Sdfr
421178825Sdfr    if (iter->certs)
422178825Sdfr	return hx509_certs_next_cert(context, iter->certs, iter->cursor, cert);
423178825Sdfr
424178825Sdfr    *cert = NULL;
425178825Sdfr
426178825Sdfr    ret = SecKeychainSearchCopyNext(iter->searchRef, &itemRef);
427178825Sdfr    if (ret == errSecItemNotFound)
428178825Sdfr	return 0;
429178825Sdfr    else if (ret != 0)
430178825Sdfr	return EINVAL;
431178825Sdfr
432178825Sdfr    /*
433178825Sdfr     * Pick out certificate and matching "keyid"
434178825Sdfr     */
435178825Sdfr
436178825Sdfr    item[0] = kSecPublicKeyHashItemAttr;
437178825Sdfr
438178825Sdfr    attrInfo.count = 1;
439178825Sdfr    attrInfo.tag = item;
440178825Sdfr    attrInfo.format = attrFormat;
441178825Sdfr
442178825Sdfr    ret = SecKeychainItemCopyAttributesAndData(itemRef, &attrInfo, NULL,
443178825Sdfr					       &attrs, &len, &ptr);
444178825Sdfr    if (ret)
445178825Sdfr	return EINVAL;
446178825Sdfr
447178825Sdfr    ret = hx509_cert_init_data(context, ptr, len, cert);
448178825Sdfr    if (ret)
449178825Sdfr	goto out;
450178825Sdfr
451178825Sdfr    /*
452178825Sdfr     * Find related private key if there is one by looking at
453178825Sdfr     * kSecPublicKeyHashItemAttr == kSecKeyLabel
454178825Sdfr     */
455178825Sdfr    {
456178825Sdfr	SecKeychainSearchRef search;
457178825Sdfr	SecKeychainAttribute attrKeyid;
458178825Sdfr	SecKeychainAttributeList attrList;
459178825Sdfr
460178825Sdfr	attrKeyid.tag = kSecKeyLabel;
461178825Sdfr	attrKeyid.length = attrs->attr[0].length;
462178825Sdfr	attrKeyid.data = attrs->attr[0].data;
463178825Sdfr
464178825Sdfr	attrList.count = 1;
465178825Sdfr	attrList.attr = &attrKeyid;
466178825Sdfr
467178825Sdfr	ret = SecKeychainSearchCreateFromAttributes(NULL,
468178825Sdfr						    CSSM_DL_DB_RECORD_PRIVATE_KEY,
469178825Sdfr						    &attrList,
470178825Sdfr						    &search);
471178825Sdfr	if (ret) {
472178825Sdfr	    ret = 0;
473178825Sdfr	    goto out;
474178825Sdfr	}
475178825Sdfr
476178825Sdfr	ret = SecKeychainSearchCopyNext(search, &itemRef);
477178825Sdfr	CFRelease(search);
478178825Sdfr	if (ret == errSecItemNotFound) {
479178825Sdfr	    ret = 0;
480178825Sdfr	    goto out;
481178825Sdfr	} else if (ret) {
482178825Sdfr	    ret = EINVAL;
483178825Sdfr	    goto out;
484178825Sdfr	}
485178825Sdfr	set_private_key(context, itemRef, *cert);
486178825Sdfr    }
487178825Sdfr
488178825Sdfrout:
489178825Sdfr    SecKeychainItemFreeAttributesAndData(attrs, ptr);
490178825Sdfr
491178825Sdfr    return ret;
492178825Sdfr}
493178825Sdfr
494178825Sdfr/*
495178825Sdfr *
496178825Sdfr */
497178825Sdfr
498178825Sdfrstatic int
499178825Sdfrkeychain_iter_end(hx509_context context,
500178825Sdfr		  hx509_certs certs,
501178825Sdfr		  void *data,
502178825Sdfr		  void *cursor)
503178825Sdfr{
504178825Sdfr    struct iter *iter = cursor;
505178825Sdfr
506178825Sdfr    if (iter->certs) {
507178825Sdfr	int ret;
508178825Sdfr	ret = hx509_certs_end_seq(context, iter->certs, iter->cursor);
509178825Sdfr	hx509_certs_free(&iter->certs);
510178825Sdfr    } else {
511178825Sdfr	CFRelease(iter->searchRef);
512178825Sdfr    }
513178825Sdfr
514178825Sdfr    memset(iter, 0, sizeof(*iter));
515178825Sdfr    free(iter);
516178825Sdfr    return 0;
517178825Sdfr}
518178825Sdfr
519178825Sdfr/*
520178825Sdfr *
521178825Sdfr */
522178825Sdfr
523178825Sdfrstruct hx509_keyset_ops keyset_keychain = {
524178825Sdfr    "KEYCHAIN",
525178825Sdfr    0,
526178825Sdfr    keychain_init,
527178825Sdfr    NULL,
528178825Sdfr    keychain_free,
529178825Sdfr    NULL,
530178825Sdfr    NULL,
531178825Sdfr    keychain_iter_start,
532178825Sdfr    keychain_iter,
533178825Sdfr    keychain_iter_end
534178825Sdfr};
535178825Sdfr
536178825Sdfr#endif /* HAVE_FRAMEWORK_SECURITY */
537178825Sdfr
538178825Sdfr/*
539178825Sdfr *
540178825Sdfr */
541178825Sdfr
542178825Sdfrvoid
543178825Sdfr_hx509_ks_keychain_register(hx509_context context)
544178825Sdfr{
545178825Sdfr#ifdef HAVE_FRAMEWORK_SECURITY
546178825Sdfr    _hx509_ks_register(context, &keyset_keychain);
547178825Sdfr#endif
548178825Sdfr}
549