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