Patch from Guillaume Rousse to update the Windows situation
[heimdal.git] / lib / hx509 / ks_keychain.c
blob01d0c55d1c6da71b513c8bae08f58ffa6bee3935
1 /*
2 * Copyright (c) 2007 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
4 * All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the Institute nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
34 #include "hx_locl.h"
36 #ifdef HAVE_FRAMEWORK_SECURITY
38 #include <Security/Security.h>
40 /* Missing function decls in pre Leopard */
41 #ifdef NEED_SECKEYGETCSPHANDLE_PROTO
42 OSStatus SecKeyGetCSPHandle(SecKeyRef, CSSM_CSP_HANDLE *);
43 OSStatus SecKeyGetCredentials(SecKeyRef, CSSM_ACL_AUTHORIZATION_TAG,
44 int, const CSSM_ACCESS_CREDENTIALS **);
45 #define kSecCredentialTypeDefault 0
46 #endif
49 static int
50 getAttribute(SecKeychainItemRef itemRef, SecItemAttr item,
51 SecKeychainAttributeList **attrs)
53 SecKeychainAttributeInfo attrInfo;
54 UInt32 attrFormat = 0;
55 OSStatus ret;
57 *attrs = NULL;
59 attrInfo.count = 1;
60 attrInfo.tag = &item;
61 attrInfo.format = &attrFormat;
63 ret = SecKeychainItemCopyAttributesAndData(itemRef, &attrInfo, NULL,
64 attrs, NULL, NULL);
65 if (ret)
66 return EINVAL;
67 return 0;
75 struct kc_rsa {
76 SecKeychainItemRef item;
77 size_t keysize;
81 static int
82 kc_rsa_public_encrypt(int flen,
83 const unsigned char *from,
84 unsigned char *to,
85 RSA *rsa,
86 int padding)
88 return -1;
91 static int
92 kc_rsa_public_decrypt(int flen,
93 const unsigned char *from,
94 unsigned char *to,
95 RSA *rsa,
96 int padding)
98 return -1;
102 static int
103 kc_rsa_private_encrypt(int flen,
104 const unsigned char *from,
105 unsigned char *to,
106 RSA *rsa,
107 int padding)
109 struct kc_rsa *kc = RSA_get_app_data(rsa);
111 CSSM_RETURN cret;
112 OSStatus ret;
113 const CSSM_ACCESS_CREDENTIALS *creds;
114 SecKeyRef privKeyRef = (SecKeyRef)kc->item;
115 CSSM_CSP_HANDLE cspHandle;
116 const CSSM_KEY *cssmKey;
117 CSSM_CC_HANDLE sigHandle = 0;
118 CSSM_DATA sig, in;
119 int fret = 0;
121 if (padding != RSA_PKCS1_PADDING)
122 return -1;
124 cret = SecKeyGetCSSMKey(privKeyRef, &cssmKey);
125 if(cret) abort();
127 cret = SecKeyGetCSPHandle(privKeyRef, &cspHandle);
128 if(cret) abort();
130 ret = SecKeyGetCredentials(privKeyRef, CSSM_ACL_AUTHORIZATION_SIGN,
131 kSecCredentialTypeDefault, &creds);
132 if(ret) abort();
134 ret = CSSM_CSP_CreateSignatureContext(cspHandle, CSSM_ALGID_RSA,
135 creds, cssmKey, &sigHandle);
136 if(ret) abort();
138 in.Data = (uint8 *)from;
139 in.Length = flen;
141 sig.Data = (uint8 *)to;
142 sig.Length = kc->keysize;
144 cret = CSSM_SignData(sigHandle, &in, 1, CSSM_ALGID_NONE, &sig);
145 if(cret) {
146 /* cssmErrorString(cret); */
147 fret = -1;
148 } else
149 fret = sig.Length;
151 if(sigHandle)
152 CSSM_DeleteContext(sigHandle);
154 return fret;
157 static int
158 kc_rsa_private_decrypt(int flen, const unsigned char *from, unsigned char *to,
159 RSA * rsa, int padding)
161 struct kc_rsa *kc = RSA_get_app_data(rsa);
163 CSSM_RETURN cret;
164 OSStatus ret;
165 const CSSM_ACCESS_CREDENTIALS *creds;
166 SecKeyRef privKeyRef = (SecKeyRef)kc->item;
167 CSSM_CSP_HANDLE cspHandle;
168 const CSSM_KEY *cssmKey;
169 CSSM_CC_HANDLE handle = 0;
170 CSSM_DATA out, in, rem;
171 int fret = 0;
172 CSSM_SIZE outlen = 0;
173 char remdata[1024];
175 if (padding != RSA_PKCS1_PADDING)
176 return -1;
178 cret = SecKeyGetCSSMKey(privKeyRef, &cssmKey);
179 if(cret) abort();
181 cret = SecKeyGetCSPHandle(privKeyRef, &cspHandle);
182 if(cret) abort();
184 ret = SecKeyGetCredentials(privKeyRef, CSSM_ACL_AUTHORIZATION_DECRYPT,
185 kSecCredentialTypeDefault, &creds);
186 if(ret) abort();
189 ret = CSSM_CSP_CreateAsymmetricContext (cspHandle,
190 CSSM_ALGID_RSA,
191 creds,
192 cssmKey,
193 CSSM_PADDING_PKCS1,
194 &handle);
195 if(ret) abort();
197 in.Data = (uint8 *)from;
198 in.Length = flen;
200 out.Data = (uint8 *)to;
201 out.Length = kc->keysize;
203 rem.Data = (uint8 *)remdata;
204 rem.Length = sizeof(remdata);
206 cret = CSSM_DecryptData(handle, &in, 1, &out, 1, &outlen, &rem);
207 if(cret) {
208 /* cssmErrorString(cret); */
209 fret = -1;
210 } else
211 fret = out.Length;
213 if(handle)
214 CSSM_DeleteContext(handle);
216 return fret;
219 static int
220 kc_rsa_init(RSA *rsa)
222 return 1;
225 static int
226 kc_rsa_finish(RSA *rsa)
228 struct kc_rsa *kc_rsa = RSA_get_app_data(rsa);
229 CFRelease(kc_rsa->item);
230 memset(kc_rsa, 0, sizeof(*kc_rsa));
231 free(kc_rsa);
232 return 1;
235 static const RSA_METHOD kc_rsa_pkcs1_method = {
236 "hx509 Keychain PKCS#1 RSA",
237 kc_rsa_public_encrypt,
238 kc_rsa_public_decrypt,
239 kc_rsa_private_encrypt,
240 kc_rsa_private_decrypt,
241 NULL,
242 NULL,
243 kc_rsa_init,
244 kc_rsa_finish,
246 NULL,
247 NULL,
248 NULL
251 static int
252 set_private_key(hx509_context context,
253 SecKeychainItemRef itemRef,
254 hx509_cert cert)
256 struct kc_rsa *kc;
257 hx509_private_key key;
258 RSA *rsa;
259 int ret;
261 ret = _hx509_private_key_init(&key, NULL, NULL);
262 if (ret)
263 return ret;
265 kc = calloc(1, sizeof(*kc));
266 if (kc == NULL)
267 _hx509_abort("out of memory");
269 kc->item = itemRef;
271 rsa = RSA_new();
272 if (rsa == NULL)
273 _hx509_abort("out of memory");
275 /* Argh, fake modulus since OpenSSL API is on crack */
277 SecKeychainAttributeList *attrs = NULL;
278 uint32_t size;
279 void *data;
281 rsa->n = BN_new();
282 if (rsa->n == NULL) abort();
284 ret = getAttribute(itemRef, kSecKeyKeySizeInBits, &attrs);
285 if (ret) abort();
287 size = *(uint32_t *)attrs->attr[0].data;
288 SecKeychainItemFreeAttributesAndData(attrs, NULL);
290 kc->keysize = (size + 7) / 8;
292 data = malloc(kc->keysize);
293 memset(data, 0xe0, kc->keysize);
294 BN_bin2bn(data, kc->keysize, rsa->n);
295 free(data);
297 rsa->e = NULL;
299 RSA_set_method(rsa, &kc_rsa_pkcs1_method);
300 ret = RSA_set_app_data(rsa, kc);
301 if (ret != 1)
302 _hx509_abort("RSA_set_app_data");
304 _hx509_private_key_assign_rsa(key, rsa);
305 _hx509_cert_assign_key(cert, key);
307 return 0;
314 struct ks_keychain {
315 int anchors;
316 SecKeychainRef keychain;
319 static int
320 keychain_init(hx509_context context,
321 hx509_certs certs, void **data, int flags,
322 const char *residue, hx509_lock lock)
324 struct ks_keychain *ctx;
326 ctx = calloc(1, sizeof(*ctx));
327 if (ctx == NULL) {
328 hx509_clear_error_string(context);
329 return ENOMEM;
332 if (residue) {
333 if (strcasecmp(residue, "system-anchors") == 0) {
334 ctx->anchors = 1;
335 } else if (strncasecmp(residue, "FILE:", 5) == 0) {
336 OSStatus ret;
338 ret = SecKeychainOpen(residue + 5, &ctx->keychain);
339 if (ret != noErr) {
340 hx509_set_error_string(context, 0, ENOENT,
341 "Failed to open %s", residue);
342 return ENOENT;
344 } else {
345 hx509_set_error_string(context, 0, ENOENT,
346 "Unknown subtype %s", residue);
347 return ENOENT;
351 *data = ctx;
352 return 0;
359 static int
360 keychain_free(hx509_certs certs, void *data)
362 struct ks_keychain *ctx = data;
363 if (ctx->keychain)
364 CFRelease(ctx->keychain);
365 memset(ctx, 0, sizeof(*ctx));
366 free(ctx);
367 return 0;
374 struct iter {
375 hx509_certs certs;
376 void *cursor;
377 SecKeychainSearchRef searchRef;
380 static int
381 keychain_iter_start(hx509_context context,
382 hx509_certs certs, void *data, void **cursor)
384 struct ks_keychain *ctx = data;
385 struct iter *iter;
387 iter = calloc(1, sizeof(*iter));
388 if (iter == NULL) {
389 hx509_set_error_string(context, 0, ENOMEM, "out of memory");
390 return ENOMEM;
393 if (ctx->anchors) {
394 CFArrayRef anchors;
395 int ret;
396 int i;
398 ret = hx509_certs_init(context, "MEMORY:ks-file-create",
399 0, NULL, &iter->certs);
400 if (ret) {
401 free(iter);
402 return ret;
405 ret = SecTrustCopyAnchorCertificates(&anchors);
406 if (ret != 0) {
407 hx509_certs_free(&iter->certs);
408 free(iter);
409 hx509_set_error_string(context, 0, ENOMEM,
410 "Can't get trust anchors from Keychain");
411 return ENOMEM;
413 for (i = 0; i < CFArrayGetCount(anchors); i++) {
414 SecCertificateRef cr;
415 hx509_cert cert;
416 CSSM_DATA cssm;
418 cr = (SecCertificateRef)CFArrayGetValueAtIndex(anchors, i);
420 SecCertificateGetData(cr, &cssm);
422 ret = hx509_cert_init_data(context, cssm.Data, cssm.Length, &cert);
423 if (ret)
424 continue;
426 ret = hx509_certs_add(context, iter->certs, cert);
427 hx509_cert_free(cert);
429 CFRelease(anchors);
432 if (iter->certs) {
433 int ret;
434 ret = hx509_certs_start_seq(context, iter->certs, &iter->cursor);
435 if (ret) {
436 hx509_certs_free(&iter->certs);
437 free(iter);
438 return ret;
440 } else {
441 OSStatus ret;
443 ret = SecKeychainSearchCreateFromAttributes(ctx->keychain,
444 kSecCertificateItemClass,
445 NULL,
446 &iter->searchRef);
447 if (ret) {
448 free(iter);
449 hx509_set_error_string(context, 0, ret,
450 "Failed to start search for attributes");
451 return ENOMEM;
455 *cursor = iter;
456 return 0;
463 static int
464 keychain_iter(hx509_context context,
465 hx509_certs certs, void *data, void *cursor, hx509_cert *cert)
467 SecKeychainAttributeList *attrs = NULL;
468 SecKeychainAttributeInfo attrInfo;
469 UInt32 attrFormat[1] = { 0 };
470 SecKeychainItemRef itemRef;
471 SecItemAttr item[1];
472 struct iter *iter = cursor;
473 OSStatus ret;
474 UInt32 len;
475 void *ptr = NULL;
477 if (iter->certs)
478 return hx509_certs_next_cert(context, iter->certs, iter->cursor, cert);
480 *cert = NULL;
482 ret = SecKeychainSearchCopyNext(iter->searchRef, &itemRef);
483 if (ret == errSecItemNotFound)
484 return 0;
485 else if (ret != 0)
486 return EINVAL;
489 * Pick out certificate and matching "keyid"
492 item[0] = kSecPublicKeyHashItemAttr;
494 attrInfo.count = 1;
495 attrInfo.tag = item;
496 attrInfo.format = attrFormat;
498 ret = SecKeychainItemCopyAttributesAndData(itemRef, &attrInfo, NULL,
499 &attrs, &len, &ptr);
500 if (ret)
501 return EINVAL;
503 ret = hx509_cert_init_data(context, ptr, len, cert);
504 if (ret)
505 goto out;
508 * Find related private key if there is one by looking at
509 * kSecPublicKeyHashItemAttr == kSecKeyLabel
512 SecKeychainSearchRef search;
513 SecKeychainAttribute attrKeyid;
514 SecKeychainAttributeList attrList;
516 attrKeyid.tag = kSecKeyLabel;
517 attrKeyid.length = attrs->attr[0].length;
518 attrKeyid.data = attrs->attr[0].data;
520 attrList.count = 1;
521 attrList.attr = &attrKeyid;
523 ret = SecKeychainSearchCreateFromAttributes(NULL,
524 CSSM_DL_DB_RECORD_PRIVATE_KEY,
525 &attrList,
526 &search);
527 if (ret) {
528 ret = 0;
529 goto out;
532 ret = SecKeychainSearchCopyNext(search, &itemRef);
533 CFRelease(search);
534 if (ret == errSecItemNotFound) {
535 ret = 0;
536 goto out;
537 } else if (ret) {
538 ret = EINVAL;
539 goto out;
541 set_private_key(context, itemRef, *cert);
544 out:
545 SecKeychainItemFreeAttributesAndData(attrs, ptr);
547 return ret;
554 static int
555 keychain_iter_end(hx509_context context,
556 hx509_certs certs,
557 void *data,
558 void *cursor)
560 struct iter *iter = cursor;
562 if (iter->certs) {
563 hx509_certs_end_seq(context, iter->certs, iter->cursor);
564 hx509_certs_free(&iter->certs);
565 } else {
566 CFRelease(iter->searchRef);
569 memset(iter, 0, sizeof(*iter));
570 free(iter);
571 return 0;
578 struct hx509_keyset_ops keyset_keychain = {
579 "KEYCHAIN",
581 keychain_init,
582 NULL,
583 keychain_free,
584 NULL,
585 NULL,
586 keychain_iter_start,
587 keychain_iter,
588 keychain_iter_end
591 #endif /* HAVE_FRAMEWORK_SECURITY */
597 void
598 _hx509_ks_keychain_register(hx509_context context)
600 #ifdef HAVE_FRAMEWORK_SECURITY
601 _hx509_ks_register(context, &keyset_keychain);
602 #endif