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
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
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
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
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
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
223 kc_rsa_init(RSA *rsa)
224 {
225     return 1;
226 }
227 
228 static int
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
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
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
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
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
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
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
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