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