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