]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - crypto/heimdal/lib/hx509/ks_keychain.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.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 RCSID("$Id: ks_keychain.c 22084 2007-11-16 20:12:30Z lha $");
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,
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
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,
158                        RSA * rsa, int padding)
159 {
160     return -1;
161 }
162
163 static int 
164 kc_rsa_init(RSA *rsa)
165 {
166     return 1;
167 }
168
169 static int
170 kc_rsa_finish(RSA *rsa)
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,
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,
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)
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,
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,
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,
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)
544 {
545 #ifdef HAVE_FRAMEWORK_SECURITY
546     _hx509_ks_register(context, &keyset_keychain);
547 #endif
548 }