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
getAttribute(SecKeychainItemRef itemRef,SecItemAttr item,SecKeychainAttributeList ** attrs)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
kc_rsa_public_encrypt(int flen,const unsigned char * from,unsigned char * to,RSA * rsa,int padding)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
kc_rsa_public_decrypt(int flen,const unsigned char * from,unsigned char * to,RSA * rsa,int padding)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
kc_rsa_private_encrypt(int flen,const unsigned char * from,unsigned char * to,RSA * rsa,int padding)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
kc_rsa_private_decrypt(int flen,const unsigned char * from,unsigned char * to,RSA * rsa,int padding)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
kc_rsa_init(RSA * rsa)221 kc_rsa_init(RSA *rsa)
222 {
223 return 1;
224 }
225
226 static int
kc_rsa_finish(RSA * rsa)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
set_private_key(hx509_context context,SecKeychainItemRef itemRef,hx509_cert cert)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
keychain_init(hx509_context context,hx509_certs certs,void ** data,int flags,const char * residue,hx509_lock lock)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
keychain_free(hx509_certs certs,void * data)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
keychain_iter_start(hx509_context context,hx509_certs certs,void * data,void ** cursor)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
keychain_iter(hx509_context context,hx509_certs certs,void * data,void * cursor,hx509_cert * cert)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
keychain_iter_end(hx509_context context,hx509_certs certs,void * data,void * cursor)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
_hx509_ks_keychain_register(hx509_context context)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