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