1/*	$NetBSD: ks_p11.c,v 1.1.1.1 2011/04/13 18:15:11 elric Exp $	*/
2
3/*
4 * Copyright (c) 2004 - 2008 Kungliga Tekniska Högskolan
5 * (Royal Institute of Technology, Stockholm, Sweden).
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 *
12 * 1. Redistributions of source code must retain the above copyright
13 *    notice, this list of conditions and the following disclaimer.
14 *
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 *
19 * 3. Neither the name of the Institute nor the names of its contributors
20 *    may be used to endorse or promote products derived from this software
21 *    without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 */
35
36#include "hx_locl.h"
37#ifdef HAVE_DLFCN_H
38#include <dlfcn.h>
39#endif
40
41#ifdef HAVE_DLOPEN
42
43#include "pkcs11.h"
44
45struct p11_slot {
46    int flags;
47#define P11_SESSION		1
48#define P11_SESSION_IN_USE	2
49#define P11_LOGIN_REQ		4
50#define P11_LOGIN_DONE		8
51#define P11_TOKEN_PRESENT	16
52    CK_SESSION_HANDLE session;
53    CK_SLOT_ID id;
54    CK_BBOOL token;
55    char *name;
56    hx509_certs certs;
57    char *pin;
58    struct {
59	CK_MECHANISM_TYPE_PTR list;
60	CK_ULONG num;
61	CK_MECHANISM_INFO_PTR *infos;
62    } mechs;
63};
64
65struct p11_module {
66    void *dl_handle;
67    CK_FUNCTION_LIST_PTR funcs;
68    CK_ULONG num_slots;
69    unsigned int ref;
70    struct p11_slot *slot;
71};
72
73#define P11FUNC(module,f,args) (*(module)->funcs->C_##f)args
74
75static int p11_get_session(hx509_context,
76			   struct p11_module *,
77			   struct p11_slot *,
78			   hx509_lock,
79			   CK_SESSION_HANDLE *);
80static int p11_put_session(struct p11_module *,
81			   struct p11_slot *,
82			   CK_SESSION_HANDLE);
83static void p11_release_module(struct p11_module *);
84
85static int p11_list_keys(hx509_context,
86			 struct p11_module *,
87			 struct p11_slot *,
88			 CK_SESSION_HANDLE,
89			 hx509_lock,
90			 hx509_certs *);
91
92/*
93 *
94 */
95
96struct p11_rsa {
97    struct p11_module *p;
98    struct p11_slot *slot;
99    CK_OBJECT_HANDLE private_key;
100    CK_OBJECT_HANDLE public_key;
101};
102
103static int
104p11_rsa_public_encrypt(int flen,
105		       const unsigned char *from,
106		       unsigned char *to,
107		       RSA *rsa,
108		       int padding)
109{
110    return -1;
111}
112
113static int
114p11_rsa_public_decrypt(int flen,
115		       const unsigned char *from,
116		       unsigned char *to,
117		       RSA *rsa,
118		       int padding)
119{
120    return -1;
121}
122
123
124static int
125p11_rsa_private_encrypt(int flen,
126			const unsigned char *from,
127			unsigned char *to,
128			RSA *rsa,
129			int padding)
130{
131    struct p11_rsa *p11rsa = RSA_get_app_data(rsa);
132    CK_OBJECT_HANDLE key = p11rsa->private_key;
133    CK_SESSION_HANDLE session;
134    CK_MECHANISM mechanism;
135    CK_ULONG ck_sigsize;
136    int ret;
137
138    if (padding != RSA_PKCS1_PADDING)
139	return -1;
140
141    memset(&mechanism, 0, sizeof(mechanism));
142    mechanism.mechanism = CKM_RSA_PKCS;
143
144    ck_sigsize = RSA_size(rsa);
145
146    ret = p11_get_session(NULL, p11rsa->p, p11rsa->slot, NULL, &session);
147    if (ret)
148	return -1;
149
150    ret = P11FUNC(p11rsa->p, SignInit, (session, &mechanism, key));
151    if (ret != CKR_OK) {
152	p11_put_session(p11rsa->p, p11rsa->slot, session);
153	return -1;
154    }
155
156    ret = P11FUNC(p11rsa->p, Sign,
157		  (session, (CK_BYTE *)from, flen, to, &ck_sigsize));
158    p11_put_session(p11rsa->p, p11rsa->slot, session);
159    if (ret != CKR_OK)
160	return -1;
161
162    return ck_sigsize;
163}
164
165static int
166p11_rsa_private_decrypt(int flen, const unsigned char *from, unsigned char *to,
167			RSA * rsa, int padding)
168{
169    struct p11_rsa *p11rsa = RSA_get_app_data(rsa);
170    CK_OBJECT_HANDLE key = p11rsa->private_key;
171    CK_SESSION_HANDLE session;
172    CK_MECHANISM mechanism;
173    CK_ULONG ck_sigsize;
174    int ret;
175
176    if (padding != RSA_PKCS1_PADDING)
177	return -1;
178
179    memset(&mechanism, 0, sizeof(mechanism));
180    mechanism.mechanism = CKM_RSA_PKCS;
181
182    ck_sigsize = RSA_size(rsa);
183
184    ret = p11_get_session(NULL, p11rsa->p, p11rsa->slot, NULL, &session);
185    if (ret)
186	return -1;
187
188    ret = P11FUNC(p11rsa->p, DecryptInit, (session, &mechanism, key));
189    if (ret != CKR_OK) {
190	p11_put_session(p11rsa->p, p11rsa->slot, session);
191	return -1;
192    }
193
194    ret = P11FUNC(p11rsa->p, Decrypt,
195		  (session, (CK_BYTE *)from, flen, to, &ck_sigsize));
196    p11_put_session(p11rsa->p, p11rsa->slot, session);
197    if (ret != CKR_OK)
198	return -1;
199
200    return ck_sigsize;
201}
202
203static int
204p11_rsa_init(RSA *rsa)
205{
206    return 1;
207}
208
209static int
210p11_rsa_finish(RSA *rsa)
211{
212    struct p11_rsa *p11rsa = RSA_get_app_data(rsa);
213    p11_release_module(p11rsa->p);
214    free(p11rsa);
215    return 1;
216}
217
218static const RSA_METHOD p11_rsa_pkcs1_method = {
219    "hx509 PKCS11 PKCS#1 RSA",
220    p11_rsa_public_encrypt,
221    p11_rsa_public_decrypt,
222    p11_rsa_private_encrypt,
223    p11_rsa_private_decrypt,
224    NULL,
225    NULL,
226    p11_rsa_init,
227    p11_rsa_finish,
228    0,
229    NULL,
230    NULL,
231    NULL
232};
233
234/*
235 *
236 */
237
238static int
239p11_mech_info(hx509_context context,
240	      struct p11_module *p,
241	      struct p11_slot *slot,
242	      int num)
243{
244    CK_ULONG i;
245    int ret;
246
247    ret = P11FUNC(p, GetMechanismList, (slot->id, NULL_PTR, &i));
248    if (ret) {
249	hx509_set_error_string(context, 0, HX509_PKCS11_NO_MECH,
250			       "Failed to get mech list count for slot %d",
251			       num);
252	return HX509_PKCS11_NO_MECH;
253    }
254    if (i == 0) {
255	hx509_set_error_string(context, 0, HX509_PKCS11_NO_MECH,
256			       "no mech supported for slot %d", num);
257	return HX509_PKCS11_NO_MECH;
258    }
259    slot->mechs.list = calloc(i, sizeof(slot->mechs.list[0]));
260    if (slot->mechs.list == NULL) {
261	hx509_set_error_string(context, 0, ENOMEM,
262			       "out of memory");
263	return ENOMEM;
264    }
265    slot->mechs.num = i;
266    ret = P11FUNC(p, GetMechanismList, (slot->id, slot->mechs.list, &i));
267    if (ret) {
268	hx509_set_error_string(context, 0, HX509_PKCS11_NO_MECH,
269			       "Failed to get mech list for slot %d",
270			       num);
271	return HX509_PKCS11_NO_MECH;
272    }
273    assert(i == slot->mechs.num);
274
275    slot->mechs.infos = calloc(i, sizeof(*slot->mechs.infos));
276    if (slot->mechs.list == NULL) {
277	hx509_set_error_string(context, 0, ENOMEM,
278			       "out of memory");
279	return ENOMEM;
280    }
281
282    for (i = 0; i < slot->mechs.num; i++) {
283	slot->mechs.infos[i] = calloc(1, sizeof(*(slot->mechs.infos[0])));
284	if (slot->mechs.infos[i] == NULL) {
285	    hx509_set_error_string(context, 0, ENOMEM,
286				   "out of memory");
287	    return ENOMEM;
288	}
289	ret = P11FUNC(p, GetMechanismInfo, (slot->id, slot->mechs.list[i],
290					    slot->mechs.infos[i]));
291	if (ret) {
292	    hx509_set_error_string(context, 0, HX509_PKCS11_NO_MECH,
293				   "Failed to get mech info for slot %d",
294				   num);
295	    return HX509_PKCS11_NO_MECH;
296	}
297    }
298
299    return 0;
300}
301
302static int
303p11_init_slot(hx509_context context,
304	      struct p11_module *p,
305	      hx509_lock lock,
306	      CK_SLOT_ID id,
307	      int num,
308	      struct p11_slot *slot)
309{
310    CK_SESSION_HANDLE session;
311    CK_SLOT_INFO slot_info;
312    CK_TOKEN_INFO token_info;
313    size_t i;
314    int ret;
315
316    slot->certs = NULL;
317    slot->id = id;
318
319    ret = P11FUNC(p, GetSlotInfo, (slot->id, &slot_info));
320    if (ret) {
321	hx509_set_error_string(context, 0, HX509_PKCS11_TOKEN_CONFUSED,
322			       "Failed to init PKCS11 slot %d",
323			       num);
324	return HX509_PKCS11_TOKEN_CONFUSED;
325    }
326
327    for (i = sizeof(slot_info.slotDescription) - 1; i > 0; i--) {
328	char c = slot_info.slotDescription[i];
329	if (c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\0')
330	    continue;
331	i++;
332	break;
333    }
334
335    asprintf(&slot->name, "%.*s",
336	     (int)i, slot_info.slotDescription);
337
338    if ((slot_info.flags & CKF_TOKEN_PRESENT) == 0)
339	return 0;
340
341    ret = P11FUNC(p, GetTokenInfo, (slot->id, &token_info));
342    if (ret) {
343	hx509_set_error_string(context, 0, HX509_PKCS11_NO_TOKEN,
344			       "Failed to init PKCS11 slot %d "
345			       "with error 0x08x",
346			       num, ret);
347	return HX509_PKCS11_NO_TOKEN;
348    }
349    slot->flags |= P11_TOKEN_PRESENT;
350
351    if (token_info.flags & CKF_LOGIN_REQUIRED)
352	slot->flags |= P11_LOGIN_REQ;
353
354    ret = p11_get_session(context, p, slot, lock, &session);
355    if (ret)
356	return ret;
357
358    ret = p11_mech_info(context, p, slot, num);
359    if (ret)
360	goto out;
361
362    ret = p11_list_keys(context, p, slot, session, lock, &slot->certs);
363 out:
364    p11_put_session(p, slot, session);
365
366    return ret;
367}
368
369static int
370p11_get_session(hx509_context context,
371		struct p11_module *p,
372		struct p11_slot *slot,
373		hx509_lock lock,
374		CK_SESSION_HANDLE *psession)
375{
376    CK_RV ret;
377
378    if (slot->flags & P11_SESSION_IN_USE)
379	_hx509_abort("slot already in session");
380
381    if (slot->flags & P11_SESSION) {
382	slot->flags |= P11_SESSION_IN_USE;
383	*psession = slot->session;
384	return 0;
385    }
386
387    ret = P11FUNC(p, OpenSession, (slot->id,
388				   CKF_SERIAL_SESSION,
389				   NULL,
390				   NULL,
391				   &slot->session));
392    if (ret != CKR_OK) {
393	if (context)
394	    hx509_set_error_string(context, 0, HX509_PKCS11_OPEN_SESSION,
395				   "Failed to OpenSession for slot id %d "
396				   "with error: 0x%08x",
397				   (int)slot->id, ret);
398	return HX509_PKCS11_OPEN_SESSION;
399    }
400
401    slot->flags |= P11_SESSION;
402
403    /*
404     * If we have have to login, and haven't tried before and have a
405     * prompter or known to work pin code.
406     *
407     * This code is very conversative and only uses the prompter in
408     * the hx509_lock, the reason is that it's bad to try many
409     * passwords on a pkcs11 token, it might lock up and have to be
410     * unlocked by a administrator.
411     *
412     * XXX try harder to not use pin several times on the same card.
413     */
414
415    if (   (slot->flags & P11_LOGIN_REQ)
416	&& (slot->flags & P11_LOGIN_DONE) == 0
417	&& (lock || slot->pin))
418    {
419	hx509_prompt prompt;
420	char pin[20];
421	char *str;
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	    return HX509_PKCS11_LOGIN;
457	} else
458	    slot->flags |= P11_LOGIN_DONE;
459
460	if (slot->pin == NULL) {
461	    slot->pin = strdup(pin);
462	    if (slot->pin == NULL) {
463		if (context)
464		    hx509_set_error_string(context, 0, ENOMEM,
465					   "out of memory");
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, ret2, 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    ret2 = P11FUNC(p, FindObjectsFinal, (session));
560    if (ret2 != CKR_OK) {
561	return ret2;
562    }
563
564    return ret;
565}
566
567static BIGNUM *
568getattr_bn(struct p11_module *p,
569	   struct p11_slot *slot,
570	   CK_SESSION_HANDLE session,
571	   CK_OBJECT_HANDLE object,
572	   unsigned int type)
573{
574    CK_ATTRIBUTE query;
575    BIGNUM *bn;
576    int ret;
577
578    query.type = type;
579    query.pValue = NULL;
580    query.ulValueLen = 0;
581
582    ret = P11FUNC(p, GetAttributeValue,
583		  (session, object, &query, 1));
584    if (ret != CKR_OK)
585	return NULL;
586
587    query.pValue = malloc(query.ulValueLen);
588
589    ret = P11FUNC(p, GetAttributeValue,
590		  (session, object, &query, 1));
591    if (ret != CKR_OK) {
592	free(query.pValue);
593	return NULL;
594    }
595    bn = BN_bin2bn(query.pValue, query.ulValueLen, NULL);
596    free(query.pValue);
597
598    return bn;
599}
600
601static int
602collect_private_key(hx509_context context,
603		    struct p11_module *p, struct p11_slot *slot,
604		    CK_SESSION_HANDLE session,
605		    CK_OBJECT_HANDLE object,
606		    void *ptr, CK_ATTRIBUTE *query, int num_query)
607{
608    struct hx509_collector *collector = ptr;
609    hx509_private_key key;
610    heim_octet_string localKeyId;
611    int ret;
612    RSA *rsa;
613    struct p11_rsa *p11rsa;
614
615    localKeyId.data = query[0].pValue;
616    localKeyId.length = query[0].ulValueLen;
617
618    ret = hx509_private_key_init(&key, NULL, NULL);
619    if (ret)
620	return ret;
621
622    rsa = RSA_new();
623    if (rsa == NULL)
624	_hx509_abort("out of memory");
625
626    /*
627     * The exponent and modulus should always be present according to
628     * the pkcs11 specification, but some smartcards leaves it out,
629     * let ignore any failure to fetch it.
630     */
631    rsa->n = getattr_bn(p, slot, session, object, CKA_MODULUS);
632    rsa->e = getattr_bn(p, slot, session, object, CKA_PUBLIC_EXPONENT);
633
634    p11rsa = calloc(1, sizeof(*p11rsa));
635    if (p11rsa == NULL)
636	_hx509_abort("out of memory");
637
638    p11rsa->p = p;
639    p11rsa->slot = slot;
640    p11rsa->private_key = object;
641
642    if (p->ref == 0)
643	_hx509_abort("pkcs11 ref == 0 on alloc");
644    p->ref++;
645    if (p->ref == UINT_MAX)
646	_hx509_abort("pkcs11 ref == UINT_MAX on alloc");
647
648    RSA_set_method(rsa, &p11_rsa_pkcs1_method);
649    ret = RSA_set_app_data(rsa, p11rsa);
650    if (ret != 1)
651	_hx509_abort("RSA_set_app_data");
652
653    hx509_private_key_assign_rsa(key, rsa);
654
655    ret = _hx509_collector_private_key_add(context,
656					   collector,
657					   hx509_signature_rsa(),
658					   key,
659					   NULL,
660					   &localKeyId);
661
662    if (ret) {
663	hx509_private_key_free(&key);
664	return ret;
665    }
666    return 0;
667}
668
669static void
670p11_cert_release(hx509_cert cert, void *ctx)
671{
672    struct p11_module *p = ctx;
673    p11_release_module(p);
674}
675
676
677static int
678collect_cert(hx509_context context,
679	     struct p11_module *p, struct p11_slot *slot,
680	     CK_SESSION_HANDLE session,
681	     CK_OBJECT_HANDLE object,
682	     void *ptr, CK_ATTRIBUTE *query, int num_query)
683{
684    struct hx509_collector *collector = ptr;
685    hx509_cert cert;
686    int ret;
687
688    if ((CK_LONG)query[0].ulValueLen == -1 ||
689	(CK_LONG)query[1].ulValueLen == -1)
690    {
691	return 0;
692    }
693
694    ret = hx509_cert_init_data(context, query[1].pValue,
695			       query[1].ulValueLen, &cert);
696    if (ret)
697	return ret;
698
699    if (p->ref == 0)
700	_hx509_abort("pkcs11 ref == 0 on alloc");
701    p->ref++;
702    if (p->ref == UINT_MAX)
703	_hx509_abort("pkcs11 ref to high");
704
705    _hx509_cert_set_release(cert, p11_cert_release, p);
706
707    {
708	heim_octet_string data;
709
710	data.data = query[0].pValue;
711	data.length = query[0].ulValueLen;
712
713	_hx509_set_cert_attribute(context,
714				  cert,
715				  &asn1_oid_id_pkcs_9_at_localKeyId,
716				  &data);
717    }
718
719    if ((CK_LONG)query[2].ulValueLen != -1) {
720	char *str;
721
722	asprintf(&str, "%.*s",
723		 (int)query[2].ulValueLen, (char *)query[2].pValue);
724	if (str) {
725	    hx509_cert_set_friendly_name(cert, str);
726	    free(str);
727	}
728    }
729
730    ret = _hx509_collector_certs_add(context, collector, cert);
731    hx509_cert_free(cert);
732
733    return ret;
734}
735
736
737static int
738p11_list_keys(hx509_context context,
739	      struct p11_module *p,
740	      struct p11_slot *slot,
741	      CK_SESSION_HANDLE session,
742	      hx509_lock lock,
743	      hx509_certs *certs)
744{
745    struct hx509_collector *collector;
746    CK_OBJECT_CLASS key_class;
747    CK_ATTRIBUTE search_data[] = {
748	{CKA_CLASS, NULL, 0},
749    };
750    CK_ATTRIBUTE query_data[3] = {
751	{CKA_ID, NULL, 0},
752	{CKA_VALUE, NULL, 0},
753	{CKA_LABEL, NULL, 0}
754    };
755    int ret;
756
757    search_data[0].pValue = &key_class;
758    search_data[0].ulValueLen = sizeof(key_class);
759
760    if (lock == NULL)
761	lock = _hx509_empty_lock;
762
763    ret = _hx509_collector_alloc(context, lock, &collector);
764    if (ret)
765	return ret;
766
767    key_class = CKO_PRIVATE_KEY;
768    ret = iterate_entries(context, p, slot, session,
769			  search_data, 1,
770			  query_data, 1,
771			  collect_private_key, collector);
772    if (ret)
773	goto out;
774
775    key_class = CKO_CERTIFICATE;
776    ret = iterate_entries(context, p, slot, session,
777			  search_data, 1,
778			  query_data, 3,
779			  collect_cert, collector);
780    if (ret)
781	goto out;
782
783    ret = _hx509_collector_collect_certs(context, collector, &slot->certs);
784
785out:
786    _hx509_collector_free(collector);
787
788    return ret;
789}
790
791
792static int
793p11_init(hx509_context context,
794	 hx509_certs certs, void **data, int flags,
795	 const char *residue, hx509_lock lock)
796{
797    CK_C_GetFunctionList getFuncs;
798    struct p11_module *p;
799    char *list, *str;
800    int ret;
801
802    *data = NULL;
803
804    list = strdup(residue);
805    if (list == NULL)
806	return ENOMEM;
807
808    p = calloc(1, sizeof(*p));
809    if (p == NULL) {
810	free(list);
811	return ENOMEM;
812    }
813
814    p->ref = 1;
815
816    str = strchr(list, ',');
817    if (str)
818	*str++ = '\0';
819    while (str) {
820	char *strnext;
821	strnext = strchr(str, ',');
822	if (strnext)
823	    *strnext++ = '\0';
824#if 0
825	if (strncasecmp(str, "slot=", 5) == 0)
826	    p->selected_slot = atoi(str + 5);
827#endif
828	str = strnext;
829    }
830
831    p->dl_handle = dlopen(list, RTLD_NOW);
832    free(list);
833    if (p->dl_handle == NULL) {
834	ret = HX509_PKCS11_LOAD;
835	hx509_set_error_string(context, 0, ret,
836			       "Failed to open %s: %s", list, dlerror());
837	goto out;
838    }
839
840    getFuncs = (CK_C_GetFunctionList) dlsym(p->dl_handle, "C_GetFunctionList");
841    if (getFuncs == NULL) {
842	ret = HX509_PKCS11_LOAD;
843	hx509_set_error_string(context, 0, ret,
844			       "C_GetFunctionList missing in %s: %s",
845			       list, dlerror());
846	goto out;
847    }
848
849    ret = (*getFuncs)(&p->funcs);
850    if (ret) {
851	ret = HX509_PKCS11_LOAD;
852	hx509_set_error_string(context, 0, ret,
853			       "C_GetFunctionList failed in %s", list);
854	goto out;
855    }
856
857    ret = P11FUNC(p, Initialize, (NULL_PTR));
858    if (ret != CKR_OK) {
859	ret = HX509_PKCS11_TOKEN_CONFUSED;
860	hx509_set_error_string(context, 0, ret,
861			       "Failed initialize the PKCS11 module");
862	goto out;
863    }
864
865    ret = P11FUNC(p, GetSlotList, (FALSE, NULL, &p->num_slots));
866    if (ret) {
867	ret = HX509_PKCS11_TOKEN_CONFUSED;
868	hx509_set_error_string(context, 0, ret,
869			       "Failed to get number of PKCS11 slots");
870	goto out;
871    }
872
873   if (p->num_slots == 0) {
874	ret = HX509_PKCS11_NO_SLOT;
875	hx509_set_error_string(context, 0, ret,
876			       "Selected PKCS11 module have no slots");
877	goto out;
878   }
879
880
881    {
882	CK_SLOT_ID_PTR slot_ids;
883	int i, num_tokens = 0;
884
885	slot_ids = malloc(p->num_slots * sizeof(*slot_ids));
886	if (slot_ids == NULL) {
887	    hx509_clear_error_string(context);
888	    ret = ENOMEM;
889	    goto out;
890	}
891
892	ret = P11FUNC(p, GetSlotList, (FALSE, slot_ids, &p->num_slots));
893	if (ret) {
894	    free(slot_ids);
895	    hx509_set_error_string(context, 0, HX509_PKCS11_TOKEN_CONFUSED,
896				   "Failed getting slot-list from "
897				   "PKCS11 module");
898	    ret = HX509_PKCS11_TOKEN_CONFUSED;
899	    goto out;
900	}
901
902	p->slot = calloc(p->num_slots, sizeof(p->slot[0]));
903	if (p->slot == NULL) {
904	    free(slot_ids);
905	    hx509_set_error_string(context, 0, ENOMEM,
906				   "Failed to get memory for slot-list");
907	    ret = ENOMEM;
908	    goto out;
909	}
910
911	for (i = 0; i < p->num_slots; i++) {
912	    ret = p11_init_slot(context, p, lock, slot_ids[i], i, &p->slot[i]);
913	    if (ret)
914		break;
915	    if (p->slot[i].flags & P11_TOKEN_PRESENT)
916		num_tokens++;
917	}
918	free(slot_ids);
919	if (ret)
920	    goto out;
921	if (num_tokens == 0) {
922	    ret = HX509_PKCS11_NO_TOKEN;
923	    goto out;
924	}
925    }
926
927    *data = p;
928
929    return 0;
930 out:
931    p11_release_module(p);
932    return ret;
933}
934
935static void
936p11_release_module(struct p11_module *p)
937{
938    int i;
939
940    if (p->ref == 0)
941	_hx509_abort("pkcs11 ref to low");
942    if (--p->ref > 0)
943	return;
944
945    for (i = 0; i < p->num_slots; i++) {
946	if (p->slot[i].flags & P11_SESSION_IN_USE)
947	    _hx509_abort("pkcs11 module release while session in use");
948	if (p->slot[i].flags & P11_SESSION) {
949	    P11FUNC(p, CloseSession, (p->slot[i].session));
950	}
951
952	if (p->slot[i].name)
953	    free(p->slot[i].name);
954	if (p->slot[i].pin) {
955	    memset(p->slot[i].pin, 0, strlen(p->slot[i].pin));
956	    free(p->slot[i].pin);
957	}
958	if (p->slot[i].mechs.num) {
959	    free(p->slot[i].mechs.list);
960
961	    if (p->slot[i].mechs.infos) {
962		int j;
963
964		for (j = 0 ; j < p->slot[i].mechs.num ; j++)
965		    free(p->slot[i].mechs.infos[j]);
966		free(p->slot[i].mechs.infos);
967	    }
968	}
969    }
970    free(p->slot);
971
972    if (p->funcs)
973	P11FUNC(p, Finalize, (NULL));
974
975    if (p->dl_handle)
976	dlclose(p->dl_handle);
977
978    memset(p, 0, sizeof(*p));
979    free(p);
980}
981
982static int
983p11_free(hx509_certs certs, void *data)
984{
985    struct p11_module *p = data;
986    int i;
987
988    for (i = 0; i < p->num_slots; i++) {
989	if (p->slot[i].certs)
990	    hx509_certs_free(&p->slot[i].certs);
991    }
992    p11_release_module(p);
993    return 0;
994}
995
996struct p11_cursor {
997    hx509_certs certs;
998    void *cursor;
999};
1000
1001static int
1002p11_iter_start(hx509_context context,
1003	       hx509_certs certs, void *data, void **cursor)
1004{
1005    struct p11_module *p = data;
1006    struct p11_cursor *c;
1007    int ret, 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
1042static int
1043p11_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
1050static int
1051p11_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 }
1063static 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
1100static int
1101p11_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    int 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
1168static 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
1184void
1185_hx509_ks_pkcs11_register(hx509_context context)
1186{
1187#ifdef HAVE_DLOPEN
1188    _hx509_ks_register(context, &keyset_pkcs11);
1189#endif
1190}
1191