ks_p11.c revision 267654
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"
35RCSID("$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
44struct 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
64struct 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
74static int p11_get_session(hx509_context,
75			   struct p11_module *,
76			   struct p11_slot *,
77			   hx509_lock,
78			   CK_SESSION_HANDLE *);
79static int p11_put_session(struct p11_module *,
80			   struct p11_slot *,
81			   CK_SESSION_HANDLE);
82static void p11_release_module(struct p11_module *);
83
84static 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
95struct 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
102static int
103p11_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
112static int
113p11_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
123static int
124p11_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
164static int
165p11_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
202static int
203p11_rsa_init(RSA *rsa)
204{
205    return 1;
206}
207
208static int
209p11_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
217static 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
237static int
238p11_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
301static int
302p11_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
367static int
368p11_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
479static int
480p11_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
491static int
492iterate_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
568static BIGNUM *
569getattr_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
602static int
603collect_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
668static void
669p11_cert_release(hx509_cert cert, void *ctx)
670{
671    struct p11_module *p = ctx;
672    p11_release_module(p);
673}
674
675
676static int
677collect_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
734static int
735p11_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
782out:
783    _hx509_collector_free(collector);
784
785    return ret;
786}
787
788
789static int
790p11_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
932static void
933p11_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
983static int
984p11_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
997struct p11_cursor {
998    hx509_certs certs;
999    void *cursor;
1000};
1001
1002static int
1003p11_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
1043static int
1044p11_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
1051static int
1052p11_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 }
1064static 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
1101static int
1102p11_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
1170static 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
1186void
1187_hx509_ks_pkcs11_register(hx509_context context)
1188{
1189#ifdef HAVE_DLOPEN
1190    _hx509_ks_register(context, &keyset_pkcs11);
1191#endif
1192}
1193