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