]> CyberLeo.Net >> Repos - FreeBSD/releng/10.2.git/blob - crypto/heimdal/lib/hx509/ks_p11.c
- Copy stable/10@285827 to releng/10.2 in preparation for 10.2-RC1
[FreeBSD/releng/10.2.git] / crypto / heimdal / lib / hx509 / ks_p11.c
1 /*
2  * Copyright (c) 2004 - 2008 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 #ifdef HAVE_DLFCN_H
36 #include <dlfcn.h>
37 #endif
38
39 #ifdef HAVE_DLOPEN
40
41 #include "pkcs11.h"
42
43 struct p11_slot {
44     int flags;
45 #define P11_SESSION             1
46 #define P11_SESSION_IN_USE      2
47 #define P11_LOGIN_REQ           4
48 #define P11_LOGIN_DONE          8
49 #define P11_TOKEN_PRESENT       16
50     CK_SESSION_HANDLE session;
51     CK_SLOT_ID id;
52     CK_BBOOL token;
53     char *name;
54     hx509_certs certs;
55     char *pin;
56     struct {
57         CK_MECHANISM_TYPE_PTR list;
58         CK_ULONG num;
59         CK_MECHANISM_INFO_PTR *infos;
60     } mechs;
61 };
62
63 struct p11_module {
64     void *dl_handle;
65     CK_FUNCTION_LIST_PTR funcs;
66     CK_ULONG num_slots;
67     unsigned int ref;
68     struct p11_slot *slot;
69 };
70
71 #define P11FUNC(module,f,args) (*(module)->funcs->C_##f)args
72
73 static int p11_get_session(hx509_context,
74                            struct p11_module *,
75                            struct p11_slot *,
76                            hx509_lock,
77                            CK_SESSION_HANDLE *);
78 static int p11_put_session(struct p11_module *,
79                            struct p11_slot *,
80                            CK_SESSION_HANDLE);
81 static void p11_release_module(struct p11_module *);
82
83 static int p11_list_keys(hx509_context,
84                          struct p11_module *,
85                          struct p11_slot *,
86                          CK_SESSION_HANDLE,
87                          hx509_lock,
88                          hx509_certs *);
89
90 /*
91  *
92  */
93
94 struct p11_rsa {
95     struct p11_module *p;
96     struct p11_slot *slot;
97     CK_OBJECT_HANDLE private_key;
98     CK_OBJECT_HANDLE public_key;
99 };
100
101 static int
102 p11_rsa_public_encrypt(int flen,
103                        const unsigned char *from,
104                        unsigned char *to,
105                        RSA *rsa,
106                        int padding)
107 {
108     return -1;
109 }
110
111 static int
112 p11_rsa_public_decrypt(int flen,
113                        const unsigned char *from,
114                        unsigned char *to,
115                        RSA *rsa,
116                        int padding)
117 {
118     return -1;
119 }
120
121
122 static int
123 p11_rsa_private_encrypt(int flen,
124                         const unsigned char *from,
125                         unsigned char *to,
126                         RSA *rsa,
127                         int padding)
128 {
129     struct p11_rsa *p11rsa = RSA_get_app_data(rsa);
130     CK_OBJECT_HANDLE key = p11rsa->private_key;
131     CK_SESSION_HANDLE session;
132     CK_MECHANISM mechanism;
133     CK_ULONG ck_sigsize;
134     int ret;
135
136     if (padding != RSA_PKCS1_PADDING)
137         return -1;
138
139     memset(&mechanism, 0, sizeof(mechanism));
140     mechanism.mechanism = CKM_RSA_PKCS;
141
142     ck_sigsize = RSA_size(rsa);
143
144     ret = p11_get_session(NULL, p11rsa->p, p11rsa->slot, NULL, &session);
145     if (ret)
146         return -1;
147
148     ret = P11FUNC(p11rsa->p, SignInit, (session, &mechanism, key));
149     if (ret != CKR_OK) {
150         p11_put_session(p11rsa->p, p11rsa->slot, session);
151         return -1;
152     }
153
154     ret = P11FUNC(p11rsa->p, Sign,
155                   (session, (CK_BYTE *)(intptr_t)from, flen, to, &ck_sigsize));
156     p11_put_session(p11rsa->p, p11rsa->slot, session);
157     if (ret != CKR_OK)
158         return -1;
159
160     return ck_sigsize;
161 }
162
163 static int
164 p11_rsa_private_decrypt(int flen, const unsigned char *from, unsigned char *to,
165                         RSA * rsa, int padding)
166 {
167     struct p11_rsa *p11rsa = RSA_get_app_data(rsa);
168     CK_OBJECT_HANDLE key = p11rsa->private_key;
169     CK_SESSION_HANDLE session;
170     CK_MECHANISM mechanism;
171     CK_ULONG ck_sigsize;
172     int ret;
173
174     if (padding != RSA_PKCS1_PADDING)
175         return -1;
176
177     memset(&mechanism, 0, sizeof(mechanism));
178     mechanism.mechanism = CKM_RSA_PKCS;
179
180     ck_sigsize = RSA_size(rsa);
181
182     ret = p11_get_session(NULL, p11rsa->p, p11rsa->slot, NULL, &session);
183     if (ret)
184         return -1;
185
186     ret = P11FUNC(p11rsa->p, DecryptInit, (session, &mechanism, key));
187     if (ret != CKR_OK) {
188         p11_put_session(p11rsa->p, p11rsa->slot, session);
189         return -1;
190     }
191
192     ret = P11FUNC(p11rsa->p, Decrypt,
193                   (session, (CK_BYTE *)(intptr_t)from, flen, to, &ck_sigsize));
194     p11_put_session(p11rsa->p, p11rsa->slot, session);
195     if (ret != CKR_OK)
196         return -1;
197
198     return ck_sigsize;
199 }
200
201 static int
202 p11_rsa_init(RSA *rsa)
203 {
204     return 1;
205 }
206
207 static int
208 p11_rsa_finish(RSA *rsa)
209 {
210     struct p11_rsa *p11rsa = RSA_get_app_data(rsa);
211     p11_release_module(p11rsa->p);
212     free(p11rsa);
213     return 1;
214 }
215
216 static const RSA_METHOD p11_rsa_pkcs1_method = {
217     "hx509 PKCS11 PKCS#1 RSA",
218     p11_rsa_public_encrypt,
219     p11_rsa_public_decrypt,
220     p11_rsa_private_encrypt,
221     p11_rsa_private_decrypt,
222     NULL,
223     NULL,
224     p11_rsa_init,
225     p11_rsa_finish,
226     0,
227     NULL,
228     NULL,
229     NULL
230 };
231
232 /*
233  *
234  */
235
236 static int
237 p11_mech_info(hx509_context context,
238               struct p11_module *p,
239               struct p11_slot *slot,
240               int num)
241 {
242     CK_ULONG i;
243     int ret;
244
245     ret = P11FUNC(p, GetMechanismList, (slot->id, NULL_PTR, &i));
246     if (ret) {
247         hx509_set_error_string(context, 0, HX509_PKCS11_NO_MECH,
248                                "Failed to get mech list count for slot %d",
249                                num);
250         return HX509_PKCS11_NO_MECH;
251     }
252     if (i == 0) {
253         hx509_set_error_string(context, 0, HX509_PKCS11_NO_MECH,
254                                "no mech supported for slot %d", num);
255         return HX509_PKCS11_NO_MECH;
256     }
257     slot->mechs.list = calloc(i, sizeof(slot->mechs.list[0]));
258     if (slot->mechs.list == NULL) {
259         hx509_set_error_string(context, 0, ENOMEM,
260                                "out of memory");
261         return ENOMEM;
262     }
263     slot->mechs.num = i;
264     ret = P11FUNC(p, GetMechanismList, (slot->id, slot->mechs.list, &i));
265     if (ret) {
266         hx509_set_error_string(context, 0, HX509_PKCS11_NO_MECH,
267                                "Failed to get mech list for slot %d",
268                                num);
269         return HX509_PKCS11_NO_MECH;
270     }
271     assert(i == slot->mechs.num);
272
273     slot->mechs.infos = calloc(i, sizeof(*slot->mechs.infos));
274     if (slot->mechs.list == NULL) {
275         hx509_set_error_string(context, 0, ENOMEM,
276                                "out of memory");
277         return ENOMEM;
278     }
279
280     for (i = 0; i < slot->mechs.num; i++) {
281         slot->mechs.infos[i] = calloc(1, sizeof(*(slot->mechs.infos[0])));
282         if (slot->mechs.infos[i] == NULL) {
283             hx509_set_error_string(context, 0, ENOMEM,
284                                    "out of memory");
285             return ENOMEM;
286         }
287         ret = P11FUNC(p, GetMechanismInfo, (slot->id, slot->mechs.list[i],
288                                             slot->mechs.infos[i]));
289         if (ret) {
290             hx509_set_error_string(context, 0, HX509_PKCS11_NO_MECH,
291                                    "Failed to get mech info for slot %d",
292                                    num);
293             return HX509_PKCS11_NO_MECH;
294         }
295     }
296
297     return 0;
298 }
299
300 static int
301 p11_init_slot(hx509_context context,
302               struct p11_module *p,
303               hx509_lock lock,
304               CK_SLOT_ID id,
305               int num,
306               struct p11_slot *slot)
307 {
308     CK_SESSION_HANDLE session;
309     CK_SLOT_INFO slot_info;
310     CK_TOKEN_INFO token_info;
311     size_t i;
312     int ret;
313
314     slot->certs = NULL;
315     slot->id = id;
316
317     ret = P11FUNC(p, GetSlotInfo, (slot->id, &slot_info));
318     if (ret) {
319         hx509_set_error_string(context, 0, HX509_PKCS11_TOKEN_CONFUSED,
320                                "Failed to init PKCS11 slot %d",
321                                num);
322         return HX509_PKCS11_TOKEN_CONFUSED;
323     }
324
325     for (i = sizeof(slot_info.slotDescription) - 1; i > 0; i--) {
326         char c = slot_info.slotDescription[i];
327         if (c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\0')
328             continue;
329         i++;
330         break;
331     }
332
333     asprintf(&slot->name, "%.*s",
334              (int)i, slot_info.slotDescription);
335
336     if ((slot_info.flags & CKF_TOKEN_PRESENT) == 0)
337         return 0;
338
339     ret = P11FUNC(p, GetTokenInfo, (slot->id, &token_info));
340     if (ret) {
341         hx509_set_error_string(context, 0, HX509_PKCS11_NO_TOKEN,
342                                "Failed to init PKCS11 slot %d "
343                                "with error 0x08x",
344                                num, ret);
345         return HX509_PKCS11_NO_TOKEN;
346     }
347     slot->flags |= P11_TOKEN_PRESENT;
348
349     if (token_info.flags & CKF_LOGIN_REQUIRED)
350         slot->flags |= P11_LOGIN_REQ;
351
352     ret = p11_get_session(context, p, slot, lock, &session);
353     if (ret)
354         return ret;
355
356     ret = p11_mech_info(context, p, slot, num);
357     if (ret)
358         goto out;
359
360     ret = p11_list_keys(context, p, slot, session, lock, &slot->certs);
361  out:
362     p11_put_session(p, slot, session);
363
364     return ret;
365 }
366
367 static int
368 p11_get_session(hx509_context context,
369                 struct p11_module *p,
370                 struct p11_slot *slot,
371                 hx509_lock lock,
372                 CK_SESSION_HANDLE *psession)
373 {
374     CK_RV ret;
375
376     if (slot->flags & P11_SESSION_IN_USE)
377         _hx509_abort("slot already in session");
378
379     if (slot->flags & P11_SESSION) {
380         slot->flags |= P11_SESSION_IN_USE;
381         *psession = slot->session;
382         return 0;
383     }
384
385     ret = P11FUNC(p, OpenSession, (slot->id,
386                                    CKF_SERIAL_SESSION,
387                                    NULL,
388                                    NULL,
389                                    &slot->session));
390     if (ret != CKR_OK) {
391         if (context)
392             hx509_set_error_string(context, 0, HX509_PKCS11_OPEN_SESSION,
393                                    "Failed to OpenSession for slot id %d "
394                                    "with error: 0x%08x",
395                                    (int)slot->id, ret);
396         return HX509_PKCS11_OPEN_SESSION;
397     }
398
399     slot->flags |= P11_SESSION;
400
401     /*
402      * If we have have to login, and haven't tried before and have a
403      * prompter or known to work pin code.
404      *
405      * This code is very conversative and only uses the prompter in
406      * the hx509_lock, the reason is that it's bad to try many
407      * passwords on a pkcs11 token, it might lock up and have to be
408      * unlocked by a administrator.
409      *
410      * XXX try harder to not use pin several times on the same card.
411      */
412
413     if (   (slot->flags & P11_LOGIN_REQ)
414         && (slot->flags & P11_LOGIN_DONE) == 0
415         && (lock || slot->pin))
416     {
417         hx509_prompt prompt;
418         char pin[20];
419         char *str;
420
421         if (slot->pin == NULL) {
422
423             memset(&prompt, 0, sizeof(prompt));
424
425             asprintf(&str, "PIN code for %s: ", slot->name);
426             prompt.prompt = str;
427             prompt.type = HX509_PROMPT_TYPE_PASSWORD;
428             prompt.reply.data = pin;
429             prompt.reply.length = sizeof(pin);
430
431             ret = hx509_lock_prompt(lock, &prompt);
432             if (ret) {
433                 free(str);
434                 if (context)
435                     hx509_set_error_string(context, 0, ret,
436                                            "Failed to get pin code for slot "
437                                            "id %d with error: %d",
438                                            (int)slot->id, ret);
439                 return ret;
440             }
441             free(str);
442         } else {
443             strlcpy(pin, slot->pin, sizeof(pin));
444         }
445
446         ret = P11FUNC(p, Login, (slot->session, CKU_USER,
447                                  (unsigned char*)pin, strlen(pin)));
448         if (ret != CKR_OK) {
449             if (context)
450                 hx509_set_error_string(context, 0, HX509_PKCS11_LOGIN,
451                                        "Failed to login on slot id %d "
452                                        "with error: 0x%08x",
453                                        (int)slot->id, ret);
454             return HX509_PKCS11_LOGIN;
455         } else
456             slot->flags |= P11_LOGIN_DONE;
457
458         if (slot->pin == NULL) {
459             slot->pin = strdup(pin);
460             if (slot->pin == NULL) {
461                 if (context)
462                     hx509_set_error_string(context, 0, ENOMEM,
463                                            "out of memory");
464                 return ENOMEM;
465             }
466         }
467     } else
468         slot->flags |= P11_LOGIN_DONE;
469
470     slot->flags |= P11_SESSION_IN_USE;
471
472     *psession = slot->session;
473
474     return 0;
475 }
476
477 static int
478 p11_put_session(struct p11_module *p,
479                 struct p11_slot *slot,
480                 CK_SESSION_HANDLE session)
481 {
482     if ((slot->flags & P11_SESSION_IN_USE) == 0)
483         _hx509_abort("slot not in session");
484     slot->flags &= ~P11_SESSION_IN_USE;
485
486     return 0;
487 }
488
489 static int
490 iterate_entries(hx509_context context,
491                 struct p11_module *p, struct p11_slot *slot,
492                 CK_SESSION_HANDLE session,
493                 CK_ATTRIBUTE *search_data, int num_search_data,
494                 CK_ATTRIBUTE *query, int num_query,
495                 int (*func)(hx509_context,
496                             struct p11_module *, struct p11_slot *,
497                             CK_SESSION_HANDLE session,
498                             CK_OBJECT_HANDLE object,
499                             void *, CK_ATTRIBUTE *, int), void *ptr)
500 {
501     CK_OBJECT_HANDLE object;
502     CK_ULONG object_count;
503     int ret, ret2, i;
504
505     ret = P11FUNC(p, FindObjectsInit, (session, search_data, num_search_data));
506     if (ret != CKR_OK) {
507         return -1;
508     }
509     while (1) {
510         ret = P11FUNC(p, FindObjects, (session, &object, 1, &object_count));
511         if (ret != CKR_OK) {
512             return -1;
513         }
514         if (object_count == 0)
515             break;
516
517         for (i = 0; i < num_query; i++)
518             query[i].pValue = NULL;
519
520         ret = P11FUNC(p, GetAttributeValue,
521                       (session, object, query, num_query));
522         if (ret != CKR_OK) {
523             return -1;
524         }
525         for (i = 0; i < num_query; i++) {
526             query[i].pValue = malloc(query[i].ulValueLen);
527             if (query[i].pValue == NULL) {
528                 ret = ENOMEM;
529                 goto out;
530             }
531         }
532         ret = P11FUNC(p, GetAttributeValue,
533                       (session, object, query, num_query));
534         if (ret != CKR_OK) {
535             ret = -1;
536             goto out;
537         }
538
539         ret = (*func)(context, p, slot, session, object, ptr, query, num_query);
540         if (ret)
541             goto out;
542
543         for (i = 0; i < num_query; i++) {
544             if (query[i].pValue)
545                 free(query[i].pValue);
546             query[i].pValue = NULL;
547         }
548     }
549  out:
550
551     for (i = 0; i < num_query; i++) {
552         if (query[i].pValue)
553             free(query[i].pValue);
554         query[i].pValue = NULL;
555     }
556
557     ret2 = P11FUNC(p, FindObjectsFinal, (session));
558     if (ret2 != CKR_OK) {
559         return ret2;
560     }
561
562     return ret;
563 }
564
565 static BIGNUM *
566 getattr_bn(struct p11_module *p,
567            struct p11_slot *slot,
568            CK_SESSION_HANDLE session,
569            CK_OBJECT_HANDLE object,
570            unsigned int type)
571 {
572     CK_ATTRIBUTE query;
573     BIGNUM *bn;
574     int ret;
575
576     query.type = type;
577     query.pValue = NULL;
578     query.ulValueLen = 0;
579
580     ret = P11FUNC(p, GetAttributeValue,
581                   (session, object, &query, 1));
582     if (ret != CKR_OK)
583         return NULL;
584
585     query.pValue = malloc(query.ulValueLen);
586
587     ret = P11FUNC(p, GetAttributeValue,
588                   (session, object, &query, 1));
589     if (ret != CKR_OK) {
590         free(query.pValue);
591         return NULL;
592     }
593     bn = BN_bin2bn(query.pValue, query.ulValueLen, NULL);
594     free(query.pValue);
595
596     return bn;
597 }
598
599 static int
600 collect_private_key(hx509_context context,
601                     struct p11_module *p, struct p11_slot *slot,
602                     CK_SESSION_HANDLE session,
603                     CK_OBJECT_HANDLE object,
604                     void *ptr, CK_ATTRIBUTE *query, int num_query)
605 {
606     struct hx509_collector *collector = ptr;
607     hx509_private_key key;
608     heim_octet_string localKeyId;
609     int ret;
610     RSA *rsa;
611     struct p11_rsa *p11rsa;
612
613     localKeyId.data = query[0].pValue;
614     localKeyId.length = query[0].ulValueLen;
615
616     ret = hx509_private_key_init(&key, NULL, NULL);
617     if (ret)
618         return ret;
619
620     rsa = RSA_new();
621     if (rsa == NULL)
622         _hx509_abort("out of memory");
623
624     /*
625      * The exponent and modulus should always be present according to
626      * the pkcs11 specification, but some smartcards leaves it out,
627      * let ignore any failure to fetch it.
628      */
629     rsa->n = getattr_bn(p, slot, session, object, CKA_MODULUS);
630     rsa->e = getattr_bn(p, slot, session, object, CKA_PUBLIC_EXPONENT);
631
632     p11rsa = calloc(1, sizeof(*p11rsa));
633     if (p11rsa == NULL)
634         _hx509_abort("out of memory");
635
636     p11rsa->p = p;
637     p11rsa->slot = slot;
638     p11rsa->private_key = object;
639
640     if (p->ref == 0)
641         _hx509_abort("pkcs11 ref == 0 on alloc");
642     p->ref++;
643     if (p->ref == UINT_MAX)
644         _hx509_abort("pkcs11 ref == UINT_MAX on alloc");
645
646     RSA_set_method(rsa, &p11_rsa_pkcs1_method);
647     ret = RSA_set_app_data(rsa, p11rsa);
648     if (ret != 1)
649         _hx509_abort("RSA_set_app_data");
650
651     hx509_private_key_assign_rsa(key, rsa);
652
653     ret = _hx509_collector_private_key_add(context,
654                                            collector,
655                                            hx509_signature_rsa(),
656                                            key,
657                                            NULL,
658                                            &localKeyId);
659
660     if (ret) {
661         hx509_private_key_free(&key);
662         return ret;
663     }
664     return 0;
665 }
666
667 static void
668 p11_cert_release(hx509_cert cert, void *ctx)
669 {
670     struct p11_module *p = ctx;
671     p11_release_module(p);
672 }
673
674
675 static int
676 collect_cert(hx509_context context,
677              struct p11_module *p, struct p11_slot *slot,
678              CK_SESSION_HANDLE session,
679              CK_OBJECT_HANDLE object,
680              void *ptr, CK_ATTRIBUTE *query, int num_query)
681 {
682     struct hx509_collector *collector = ptr;
683     hx509_cert cert;
684     int ret;
685
686     if ((CK_LONG)query[0].ulValueLen == -1 ||
687         (CK_LONG)query[1].ulValueLen == -1)
688     {
689         return 0;
690     }
691
692     ret = hx509_cert_init_data(context, query[1].pValue,
693                                query[1].ulValueLen, &cert);
694     if (ret)
695         return ret;
696
697     if (p->ref == 0)
698         _hx509_abort("pkcs11 ref == 0 on alloc");
699     p->ref++;
700     if (p->ref == UINT_MAX)
701         _hx509_abort("pkcs11 ref to high");
702
703     _hx509_cert_set_release(cert, p11_cert_release, p);
704
705     {
706         heim_octet_string data;
707
708         data.data = query[0].pValue;
709         data.length = query[0].ulValueLen;
710
711         _hx509_set_cert_attribute(context,
712                                   cert,
713                                   &asn1_oid_id_pkcs_9_at_localKeyId,
714                                   &data);
715     }
716
717     if ((CK_LONG)query[2].ulValueLen != -1) {
718         char *str;
719
720         asprintf(&str, "%.*s",
721                  (int)query[2].ulValueLen, (char *)query[2].pValue);
722         if (str) {
723             hx509_cert_set_friendly_name(cert, str);
724             free(str);
725         }
726     }
727
728     ret = _hx509_collector_certs_add(context, collector, cert);
729     hx509_cert_free(cert);
730
731     return ret;
732 }
733
734
735 static int
736 p11_list_keys(hx509_context context,
737               struct p11_module *p,
738               struct p11_slot *slot,
739               CK_SESSION_HANDLE session,
740               hx509_lock lock,
741               hx509_certs *certs)
742 {
743     struct hx509_collector *collector;
744     CK_OBJECT_CLASS key_class;
745     CK_ATTRIBUTE search_data[] = {
746         {CKA_CLASS, NULL, 0},
747     };
748     CK_ATTRIBUTE query_data[3] = {
749         {CKA_ID, NULL, 0},
750         {CKA_VALUE, NULL, 0},
751         {CKA_LABEL, NULL, 0}
752     };
753     int ret;
754
755     search_data[0].pValue = &key_class;
756     search_data[0].ulValueLen = sizeof(key_class);
757
758     if (lock == NULL)
759         lock = _hx509_empty_lock;
760
761     ret = _hx509_collector_alloc(context, lock, &collector);
762     if (ret)
763         return ret;
764
765     key_class = CKO_PRIVATE_KEY;
766     ret = iterate_entries(context, p, slot, session,
767                           search_data, 1,
768                           query_data, 1,
769                           collect_private_key, collector);
770     if (ret)
771         goto out;
772
773     key_class = CKO_CERTIFICATE;
774     ret = iterate_entries(context, p, slot, session,
775                           search_data, 1,
776                           query_data, 3,
777                           collect_cert, collector);
778     if (ret)
779         goto out;
780
781     ret = _hx509_collector_collect_certs(context, collector, &slot->certs);
782
783 out:
784     _hx509_collector_free(collector);
785
786     return ret;
787 }
788
789
790 static int
791 p11_init(hx509_context context,
792          hx509_certs certs, void **data, int flags,
793          const char *residue, hx509_lock lock)
794 {
795     CK_C_GetFunctionList getFuncs;
796     struct p11_module *p;
797     char *list, *str;
798     int ret;
799
800     *data = NULL;
801
802     list = strdup(residue);
803     if (list == NULL)
804         return ENOMEM;
805
806     p = calloc(1, sizeof(*p));
807     if (p == NULL) {
808         free(list);
809         return ENOMEM;
810     }
811
812     p->ref = 1;
813
814     str = strchr(list, ',');
815     if (str)
816         *str++ = '\0';
817     while (str) {
818         char *strnext;
819         strnext = strchr(str, ',');
820         if (strnext)
821             *strnext++ = '\0';
822 #if 0
823         if (strncasecmp(str, "slot=", 5) == 0)
824             p->selected_slot = atoi(str + 5);
825 #endif
826         str = strnext;
827     }
828
829     p->dl_handle = dlopen(list, RTLD_NOW);
830     free(list);
831     if (p->dl_handle == NULL) {
832         ret = HX509_PKCS11_LOAD;
833         hx509_set_error_string(context, 0, ret,
834                                "Failed to open %s: %s", list, dlerror());
835         goto out;
836     }
837
838     getFuncs = (CK_C_GetFunctionList) dlsym(p->dl_handle, "C_GetFunctionList");
839     if (getFuncs == NULL) {
840         ret = HX509_PKCS11_LOAD;
841         hx509_set_error_string(context, 0, ret,
842                                "C_GetFunctionList missing in %s: %s",
843                                list, dlerror());
844         goto out;
845     }
846
847     ret = (*getFuncs)(&p->funcs);
848     if (ret) {
849         ret = HX509_PKCS11_LOAD;
850         hx509_set_error_string(context, 0, ret,
851                                "C_GetFunctionList failed in %s", list);
852         goto out;
853     }
854
855     ret = P11FUNC(p, Initialize, (NULL_PTR));
856     if (ret != CKR_OK) {
857         ret = HX509_PKCS11_TOKEN_CONFUSED;
858         hx509_set_error_string(context, 0, ret,
859                                "Failed initialize the PKCS11 module");
860         goto out;
861     }
862
863     ret = P11FUNC(p, GetSlotList, (FALSE, NULL, &p->num_slots));
864     if (ret) {
865         ret = HX509_PKCS11_TOKEN_CONFUSED;
866         hx509_set_error_string(context, 0, ret,
867                                "Failed to get number of PKCS11 slots");
868         goto out;
869     }
870
871    if (p->num_slots == 0) {
872         ret = HX509_PKCS11_NO_SLOT;
873         hx509_set_error_string(context, 0, ret,
874                                "Selected PKCS11 module have no slots");
875         goto out;
876    }
877
878
879     {
880         CK_SLOT_ID_PTR slot_ids;
881         int num_tokens = 0;
882         size_t i;
883
884         slot_ids = malloc(p->num_slots * sizeof(*slot_ids));
885         if (slot_ids == NULL) {
886             hx509_clear_error_string(context);
887             ret = ENOMEM;
888             goto out;
889         }
890
891         ret = P11FUNC(p, GetSlotList, (FALSE, slot_ids, &p->num_slots));
892         if (ret) {
893             free(slot_ids);
894             hx509_set_error_string(context, 0, HX509_PKCS11_TOKEN_CONFUSED,
895                                    "Failed getting slot-list from "
896                                    "PKCS11 module");
897             ret = HX509_PKCS11_TOKEN_CONFUSED;
898             goto out;
899         }
900
901         p->slot = calloc(p->num_slots, sizeof(p->slot[0]));
902         if (p->slot == NULL) {
903             free(slot_ids);
904             hx509_set_error_string(context, 0, ENOMEM,
905                                    "Failed to get memory for slot-list");
906             ret = ENOMEM;
907             goto out;
908         }
909
910         for (i = 0; i < p->num_slots; i++) {
911             ret = p11_init_slot(context, p, lock, slot_ids[i], i, &p->slot[i]);
912             if (ret)
913                 break;
914             if (p->slot[i].flags & P11_TOKEN_PRESENT)
915                 num_tokens++;
916         }
917         free(slot_ids);
918         if (ret)
919             goto out;
920         if (num_tokens == 0) {
921             ret = HX509_PKCS11_NO_TOKEN;
922             goto out;
923         }
924     }
925
926     *data = p;
927
928     return 0;
929  out:
930     p11_release_module(p);
931     return ret;
932 }
933
934 static void
935 p11_release_module(struct p11_module *p)
936 {
937     size_t i;
938
939     if (p->ref == 0)
940         _hx509_abort("pkcs11 ref to low");
941     if (--p->ref > 0)
942         return;
943
944     for (i = 0; i < p->num_slots; i++) {
945         if (p->slot[i].flags & P11_SESSION_IN_USE)
946             _hx509_abort("pkcs11 module release while session in use");
947         if (p->slot[i].flags & P11_SESSION) {
948             P11FUNC(p, CloseSession, (p->slot[i].session));
949         }
950
951         if (p->slot[i].name)
952             free(p->slot[i].name);
953         if (p->slot[i].pin) {
954             memset(p->slot[i].pin, 0, strlen(p->slot[i].pin));
955             free(p->slot[i].pin);
956         }
957         if (p->slot[i].mechs.num) {
958             free(p->slot[i].mechs.list);
959
960             if (p->slot[i].mechs.infos) {
961                 size_t j;
962
963                 for (j = 0 ; j < p->slot[i].mechs.num ; j++)
964                     free(p->slot[i].mechs.infos[j]);
965                 free(p->slot[i].mechs.infos);
966             }
967         }
968     }
969     free(p->slot);
970
971     if (p->funcs)
972         P11FUNC(p, Finalize, (NULL));
973
974     if (p->dl_handle)
975         dlclose(p->dl_handle);
976
977     memset(p, 0, sizeof(*p));
978     free(p);
979 }
980
981 static int
982 p11_free(hx509_certs certs, void *data)
983 {
984     struct p11_module *p = data;
985     size_t i;
986
987     for (i = 0; i < p->num_slots; i++) {
988         if (p->slot[i].certs)
989             hx509_certs_free(&p->slot[i].certs);
990     }
991     p11_release_module(p);
992     return 0;
993 }
994
995 struct p11_cursor {
996     hx509_certs certs;
997     void *cursor;
998 };
999
1000 static int
1001 p11_iter_start(hx509_context context,
1002                hx509_certs certs, void *data, void **cursor)
1003 {
1004     struct p11_module *p = data;
1005     struct p11_cursor *c;
1006     int ret;
1007     size_t i;
1008
1009     c = malloc(sizeof(*c));
1010     if (c == NULL) {
1011         hx509_clear_error_string(context);
1012         return ENOMEM;
1013     }
1014     ret = hx509_certs_init(context, "MEMORY:pkcs11-iter", 0, NULL, &c->certs);
1015     if (ret) {
1016         free(c);
1017         return ret;
1018     }
1019
1020     for (i = 0 ; i < p->num_slots; i++) {
1021         if (p->slot[i].certs == NULL)
1022             continue;
1023         ret = hx509_certs_merge(context, c->certs, p->slot[i].certs);
1024         if (ret) {
1025             hx509_certs_free(&c->certs);
1026             free(c);
1027             return ret;
1028         }
1029     }
1030
1031     ret = hx509_certs_start_seq(context, c->certs, &c->cursor);
1032     if (ret) {
1033         hx509_certs_free(&c->certs);
1034         free(c);
1035         return 0;
1036     }
1037     *cursor = c;
1038
1039     return 0;
1040 }
1041
1042 static int
1043 p11_iter(hx509_context context,
1044          hx509_certs certs, void *data, void *cursor, hx509_cert *cert)
1045 {
1046     struct p11_cursor *c = cursor;
1047     return hx509_certs_next_cert(context, c->certs, c->cursor, cert);
1048 }
1049
1050 static int
1051 p11_iter_end(hx509_context context,
1052              hx509_certs certs, void *data, void *cursor)
1053 {
1054     struct p11_cursor *c = cursor;
1055     int ret;
1056     ret = hx509_certs_end_seq(context, c->certs, c->cursor);
1057     hx509_certs_free(&c->certs);
1058     free(c);
1059     return ret;
1060 }
1061
1062 #define MECHFLAG(x) { "unknown-flag-" #x, x }
1063 static struct units mechflags[] = {
1064         MECHFLAG(0x80000000),
1065         MECHFLAG(0x40000000),
1066         MECHFLAG(0x20000000),
1067         MECHFLAG(0x10000000),
1068         MECHFLAG(0x08000000),
1069         MECHFLAG(0x04000000),
1070         {"ec-compress",         0x2000000 },
1071         {"ec-uncompress",       0x1000000 },
1072         {"ec-namedcurve",       0x0800000 },
1073         {"ec-ecparameters",     0x0400000 },
1074         {"ec-f-2m",             0x0200000 },
1075         {"ec-f-p",              0x0100000 },
1076         {"derive",              0x0080000 },
1077         {"unwrap",              0x0040000 },
1078         {"wrap",                0x0020000 },
1079         {"genereate-key-pair",  0x0010000 },
1080         {"generate",            0x0008000 },
1081         {"verify-recover",      0x0004000 },
1082         {"verify",              0x0002000 },
1083         {"sign-recover",        0x0001000 },
1084         {"sign",                0x0000800 },
1085         {"digest",              0x0000400 },
1086         {"decrypt",             0x0000200 },
1087         {"encrypt",             0x0000100 },
1088         MECHFLAG(0x00080),
1089         MECHFLAG(0x00040),
1090         MECHFLAG(0x00020),
1091         MECHFLAG(0x00010),
1092         MECHFLAG(0x00008),
1093         MECHFLAG(0x00004),
1094         MECHFLAG(0x00002),
1095         {"hw",                  0x0000001 },
1096         { NULL,                 0x0000000 }
1097 };
1098 #undef MECHFLAG
1099
1100 static int
1101 p11_printinfo(hx509_context context,
1102               hx509_certs certs,
1103               void *data,
1104               int (*func)(void *, const char *),
1105               void *ctx)
1106 {
1107     struct p11_module *p = data;
1108     size_t i, j;
1109
1110     _hx509_pi_printf(func, ctx, "pkcs11 driver with %d slot%s",
1111                      p->num_slots, p->num_slots > 1 ? "s" : "");
1112
1113     for (i = 0; i < p->num_slots; i++) {
1114         struct p11_slot *s = &p->slot[i];
1115
1116         _hx509_pi_printf(func, ctx, "slot %d: id: %d name: %s flags: %08x",
1117                          i, (int)s->id, s->name, s->flags);
1118
1119         _hx509_pi_printf(func, ctx, "number of supported mechanisms: %lu",
1120                          (unsigned long)s->mechs.num);
1121         for (j = 0; j < s->mechs.num; j++) {
1122             const char *mechname = "unknown";
1123             char flags[256], unknownname[40];
1124 #define MECHNAME(s,n) case s: mechname = n; break
1125             switch(s->mechs.list[j]) {
1126                 MECHNAME(CKM_RSA_PKCS_KEY_PAIR_GEN, "rsa-pkcs-key-pair-gen");
1127                 MECHNAME(CKM_RSA_PKCS, "rsa-pkcs");
1128                 MECHNAME(CKM_RSA_X_509, "rsa-x-509");
1129                 MECHNAME(CKM_MD5_RSA_PKCS, "md5-rsa-pkcs");
1130                 MECHNAME(CKM_SHA1_RSA_PKCS, "sha1-rsa-pkcs");
1131                 MECHNAME(CKM_SHA256_RSA_PKCS, "sha256-rsa-pkcs");
1132                 MECHNAME(CKM_SHA384_RSA_PKCS, "sha384-rsa-pkcs");
1133                 MECHNAME(CKM_SHA512_RSA_PKCS, "sha512-rsa-pkcs");
1134                 MECHNAME(CKM_RIPEMD160_RSA_PKCS, "ripemd160-rsa-pkcs");
1135                 MECHNAME(CKM_RSA_PKCS_OAEP, "rsa-pkcs-oaep");
1136                 MECHNAME(CKM_SHA512_HMAC, "sha512-hmac");
1137                 MECHNAME(CKM_SHA512, "sha512");
1138                 MECHNAME(CKM_SHA384_HMAC, "sha384-hmac");
1139                 MECHNAME(CKM_SHA384, "sha384");
1140                 MECHNAME(CKM_SHA256_HMAC, "sha256-hmac");
1141                 MECHNAME(CKM_SHA256, "sha256");
1142                 MECHNAME(CKM_SHA_1, "sha1");
1143                 MECHNAME(CKM_MD5, "md5");
1144                 MECHNAME(CKM_RIPEMD160, "ripemd-160");
1145                 MECHNAME(CKM_DES_ECB, "des-ecb");
1146                 MECHNAME(CKM_DES_CBC, "des-cbc");
1147                 MECHNAME(CKM_AES_ECB, "aes-ecb");
1148                 MECHNAME(CKM_AES_CBC, "aes-cbc");
1149                 MECHNAME(CKM_DH_PKCS_PARAMETER_GEN, "dh-pkcs-parameter-gen");
1150             default:
1151                 snprintf(unknownname, sizeof(unknownname),
1152                          "unknown-mech-%lu",
1153                          (unsigned long)s->mechs.list[j]);
1154                 mechname = unknownname;
1155                 break;
1156             }
1157 #undef MECHNAME
1158             unparse_flags(s->mechs.infos[j]->flags, mechflags,
1159                           flags, sizeof(flags));
1160
1161             _hx509_pi_printf(func, ctx, "  %s: %s", mechname, flags);
1162         }
1163     }
1164
1165     return 0;
1166 }
1167
1168 static struct hx509_keyset_ops keyset_pkcs11 = {
1169     "PKCS11",
1170     0,
1171     p11_init,
1172     NULL,
1173     p11_free,
1174     NULL,
1175     NULL,
1176     p11_iter_start,
1177     p11_iter,
1178     p11_iter_end,
1179     p11_printinfo
1180 };
1181
1182 #endif /* HAVE_DLOPEN */
1183
1184 void
1185 _hx509_ks_pkcs11_register(hx509_context context)
1186 {
1187 #ifdef HAVE_DLOPEN
1188     _hx509_ks_register(context, &keyset_pkcs11);
1189 #endif
1190 }