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