xref: /freebsd/crypto/heimdal/lib/hx509/ks_p11.c (revision aca5021d5f7dcab1e11692923266373e35322d9a)
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 }
1191