]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - crypto/heimdal/lib/hx509/ks_keychain.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / crypto / heimdal / lib / hx509 / ks_keychain.c
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 }