No empty .Rs/.Re
[netbsd-mini2440.git] / crypto / dist / heimdal / lib / hx509 / ks_keychain.c
blob9908367cf6873f5d15c5d56fe6b0f8a8bb6af0d4
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"
35 __RCSID("$Heimdal: ks_keychain.c 22084 2007-11-16 20:12:30Z lha $"
36 "$NetBSD$");
38 #ifdef HAVE_FRAMEWORK_SECURITY
40 #include <Security/Security.h>
42 /* Missing function decls in pre Leopard */
43 #ifdef NEED_SECKEYGETCSPHANDLE_PROTO
44 OSStatus SecKeyGetCSPHandle(SecKeyRef, CSSM_CSP_HANDLE *);
45 OSStatus SecKeyGetCredentials(SecKeyRef, CSSM_ACL_AUTHORIZATION_TAG,
46 int, const CSSM_ACCESS_CREDENTIALS **);
47 #define kSecCredentialTypeDefault 0
48 #endif
51 static int
52 getAttribute(SecKeychainItemRef itemRef, SecItemAttr item,
53 SecKeychainAttributeList **attrs)
55 SecKeychainAttributeInfo attrInfo;
56 UInt32 attrFormat = 0;
57 OSStatus ret;
59 *attrs = NULL;
61 attrInfo.count = 1;
62 attrInfo.tag = &item;
63 attrInfo.format = &attrFormat;
65 ret = SecKeychainItemCopyAttributesAndData(itemRef, &attrInfo, NULL,
66 attrs, NULL, NULL);
67 if (ret)
68 return EINVAL;
69 return 0;
77 struct kc_rsa {
78 SecKeychainItemRef item;
79 size_t keysize;
83 static int
84 kc_rsa_public_encrypt(int flen,
85 const unsigned char *from,
86 unsigned char *to,
87 RSA *rsa,
88 int padding)
90 return -1;
93 static int
94 kc_rsa_public_decrypt(int flen,
95 const unsigned char *from,
96 unsigned char *to,
97 RSA *rsa,
98 int padding)
100 return -1;
104 static int
105 kc_rsa_private_encrypt(int flen,
106 const unsigned char *from,
107 unsigned char *to,
108 RSA *rsa,
109 int padding)
111 struct kc_rsa *kc = RSA_get_app_data(rsa);
113 CSSM_RETURN cret;
114 OSStatus ret;
115 const CSSM_ACCESS_CREDENTIALS *creds;
116 SecKeyRef privKeyRef = (SecKeyRef)kc->item;
117 CSSM_CSP_HANDLE cspHandle;
118 const CSSM_KEY *cssmKey;
119 CSSM_CC_HANDLE sigHandle = 0;
120 CSSM_DATA sig, in;
121 int fret = 0;
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 return -1;
164 static int
165 kc_rsa_init(RSA *rsa)
167 return 1;
170 static int
171 kc_rsa_finish(RSA *rsa)
173 struct kc_rsa *kc_rsa = RSA_get_app_data(rsa);
174 CFRelease(kc_rsa->item);
175 memset(kc_rsa, 0, sizeof(*kc_rsa));
176 free(kc_rsa);
177 return 1;
180 static const RSA_METHOD kc_rsa_pkcs1_method = {
181 "hx509 Keychain PKCS#1 RSA",
182 kc_rsa_public_encrypt,
183 kc_rsa_public_decrypt,
184 kc_rsa_private_encrypt,
185 kc_rsa_private_decrypt,
186 NULL,
187 NULL,
188 kc_rsa_init,
189 kc_rsa_finish,
191 NULL,
192 NULL,
193 NULL
196 static int
197 set_private_key(hx509_context context,
198 SecKeychainItemRef itemRef,
199 hx509_cert cert)
201 struct kc_rsa *kc;
202 hx509_private_key key;
203 RSA *rsa;
204 int ret;
206 ret = _hx509_private_key_init(&key, NULL, NULL);
207 if (ret)
208 return ret;
210 kc = calloc(1, sizeof(*kc));
211 if (kc == NULL)
212 _hx509_abort("out of memory");
214 kc->item = itemRef;
216 rsa = RSA_new();
217 if (rsa == NULL)
218 _hx509_abort("out of memory");
220 /* Argh, fake modulus since OpenSSL API is on crack */
222 SecKeychainAttributeList *attrs = NULL;
223 uint32_t size;
224 void *data;
226 rsa->n = BN_new();
227 if (rsa->n == NULL) abort();
229 ret = getAttribute(itemRef, kSecKeyKeySizeInBits, &attrs);
230 if (ret) abort();
232 size = *(uint32_t *)attrs->attr[0].data;
233 SecKeychainItemFreeAttributesAndData(attrs, NULL);
235 kc->keysize = (size + 7) / 8;
237 data = malloc(kc->keysize);
238 memset(data, 0xe0, kc->keysize);
239 BN_bin2bn(data, kc->keysize, rsa->n);
240 free(data);
242 rsa->e = NULL;
244 RSA_set_method(rsa, &kc_rsa_pkcs1_method);
245 ret = RSA_set_app_data(rsa, kc);
246 if (ret != 1)
247 _hx509_abort("RSA_set_app_data");
249 _hx509_private_key_assign_rsa(key, rsa);
250 _hx509_cert_assign_key(cert, key);
252 return 0;
259 struct ks_keychain {
260 int anchors;
261 SecKeychainRef keychain;
264 static int
265 keychain_init(hx509_context context,
266 hx509_certs certs, void **data, int flags,
267 const char *residue, hx509_lock lock)
269 struct ks_keychain *ctx;
271 ctx = calloc(1, sizeof(*ctx));
272 if (ctx == NULL) {
273 hx509_clear_error_string(context);
274 return ENOMEM;
277 if (residue) {
278 if (strcasecmp(residue, "system-anchors") == 0) {
279 ctx->anchors = 1;
280 } else if (strncasecmp(residue, "FILE:", 5) == 0) {
281 OSStatus ret;
283 ret = SecKeychainOpen(residue + 5, &ctx->keychain);
284 if (ret != noErr) {
285 hx509_set_error_string(context, 0, ENOENT,
286 "Failed to open %s", residue);
287 return ENOENT;
289 } else {
290 hx509_set_error_string(context, 0, ENOENT,
291 "Unknown subtype %s", residue);
292 return ENOENT;
296 *data = ctx;
297 return 0;
304 static int
305 keychain_free(hx509_certs certs, void *data)
307 struct ks_keychain *ctx = data;
308 if (ctx->keychain)
309 CFRelease(ctx->keychain);
310 memset(ctx, 0, sizeof(*ctx));
311 free(ctx);
312 return 0;
319 struct iter {
320 hx509_certs certs;
321 void *cursor;
322 SecKeychainSearchRef searchRef;
325 static int
326 keychain_iter_start(hx509_context context,
327 hx509_certs certs, void *data, void **cursor)
329 struct ks_keychain *ctx = data;
330 struct iter *iter;
332 iter = calloc(1, sizeof(*iter));
333 if (iter == NULL) {
334 hx509_set_error_string(context, 0, ENOMEM, "out of memory");
335 return ENOMEM;
338 if (ctx->anchors) {
339 CFArrayRef anchors;
340 int ret;
341 int i;
343 ret = hx509_certs_init(context, "MEMORY:ks-file-create",
344 0, NULL, &iter->certs);
345 if (ret) {
346 free(iter);
347 return ret;
350 ret = SecTrustCopyAnchorCertificates(&anchors);
351 if (ret != 0) {
352 hx509_certs_free(&iter->certs);
353 free(iter);
354 hx509_set_error_string(context, 0, ENOMEM,
355 "Can't get trust anchors from Keychain");
356 return ENOMEM;
358 for (i = 0; i < CFArrayGetCount(anchors); i++) {
359 SecCertificateRef cr;
360 hx509_cert cert;
361 CSSM_DATA cssm;
363 cr = (SecCertificateRef)CFArrayGetValueAtIndex(anchors, i);
365 SecCertificateGetData(cr, &cssm);
367 ret = hx509_cert_init_data(context, cssm.Data, cssm.Length, &cert);
368 if (ret)
369 continue;
371 ret = hx509_certs_add(context, iter->certs, cert);
372 hx509_cert_free(cert);
374 CFRelease(anchors);
377 if (iter->certs) {
378 int ret;
379 ret = hx509_certs_start_seq(context, iter->certs, &iter->cursor);
380 if (ret) {
381 hx509_certs_free(&iter->certs);
382 free(iter);
383 return ret;
385 } else {
386 OSStatus ret;
388 ret = SecKeychainSearchCreateFromAttributes(ctx->keychain,
389 kSecCertificateItemClass,
390 NULL,
391 &iter->searchRef);
392 if (ret) {
393 free(iter);
394 hx509_set_error_string(context, 0, ret,
395 "Failed to start search for attributes");
396 return ENOMEM;
400 *cursor = iter;
401 return 0;
408 static int
409 keychain_iter(hx509_context context,
410 hx509_certs certs, void *data, void *cursor, hx509_cert *cert)
412 SecKeychainAttributeList *attrs = NULL;
413 SecKeychainAttributeInfo attrInfo;
414 UInt32 attrFormat[1] = { 0 };
415 SecKeychainItemRef itemRef;
416 SecItemAttr item[1];
417 struct iter *iter = cursor;
418 OSStatus ret;
419 UInt32 len;
420 void *ptr = NULL;
422 if (iter->certs)
423 return hx509_certs_next_cert(context, iter->certs, iter->cursor, cert);
425 *cert = NULL;
427 ret = SecKeychainSearchCopyNext(iter->searchRef, &itemRef);
428 if (ret == errSecItemNotFound)
429 return 0;
430 else if (ret != 0)
431 return EINVAL;
434 * Pick out certificate and matching "keyid"
437 item[0] = kSecPublicKeyHashItemAttr;
439 attrInfo.count = 1;
440 attrInfo.tag = item;
441 attrInfo.format = attrFormat;
443 ret = SecKeychainItemCopyAttributesAndData(itemRef, &attrInfo, NULL,
444 &attrs, &len, &ptr);
445 if (ret)
446 return EINVAL;
448 ret = hx509_cert_init_data(context, ptr, len, cert);
449 if (ret)
450 goto out;
453 * Find related private key if there is one by looking at
454 * kSecPublicKeyHashItemAttr == kSecKeyLabel
457 SecKeychainSearchRef search;
458 SecKeychainAttribute attrKeyid;
459 SecKeychainAttributeList attrList;
461 attrKeyid.tag = kSecKeyLabel;
462 attrKeyid.length = attrs->attr[0].length;
463 attrKeyid.data = attrs->attr[0].data;
465 attrList.count = 1;
466 attrList.attr = &attrKeyid;
468 ret = SecKeychainSearchCreateFromAttributes(NULL,
469 CSSM_DL_DB_RECORD_PRIVATE_KEY,
470 &attrList,
471 &search);
472 if (ret) {
473 ret = 0;
474 goto out;
477 ret = SecKeychainSearchCopyNext(search, &itemRef);
478 CFRelease(search);
479 if (ret == errSecItemNotFound) {
480 ret = 0;
481 goto out;
482 } else if (ret) {
483 ret = EINVAL;
484 goto out;
486 set_private_key(context, itemRef, *cert);
489 out:
490 SecKeychainItemFreeAttributesAndData(attrs, ptr);
492 return ret;
499 static int
500 keychain_iter_end(hx509_context context,
501 hx509_certs certs,
502 void *data,
503 void *cursor)
505 struct iter *iter = cursor;
507 if (iter->certs) {
508 int ret;
509 ret = hx509_certs_end_seq(context, iter->certs, iter->cursor);
510 hx509_certs_free(&iter->certs);
511 } else {
512 CFRelease(iter->searchRef);
515 memset(iter, 0, sizeof(*iter));
516 free(iter);
517 return 0;
524 struct hx509_keyset_ops keyset_keychain = {
525 "KEYCHAIN",
527 keychain_init,
528 NULL,
529 keychain_free,
530 NULL,
531 NULL,
532 keychain_iter_start,
533 keychain_iter,
534 keychain_iter_end
537 #endif /* HAVE_FRAMEWORK_SECURITY */
543 void
544 _hx509_ks_keychain_register(hx509_context context)
546 #ifdef HAVE_FRAMEWORK_SECURITY
547 _hx509_ks_register(context, &keyset_keychain);
548 #endif