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