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