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