1178825Sdfr/*
2178825Sdfr * Copyright (c) 2004 - 2006 Kungliga Tekniska H�gskolan
3178825Sdfr * (Royal Institute of Technology, Stockholm, Sweden).
4178825Sdfr * All rights reserved.
5178825Sdfr *
6178825Sdfr * Redistribution and use in source and binary forms, with or without
7178825Sdfr * modification, are permitted provided that the following conditions
8178825Sdfr * are met:
9178825Sdfr *
10178825Sdfr * 1. Redistributions of source code must retain the above copyright
11178825Sdfr *    notice, this list of conditions and the following disclaimer.
12178825Sdfr *
13178825Sdfr * 2. Redistributions in binary form must reproduce the above copyright
14178825Sdfr *    notice, this list of conditions and the following disclaimer in the
15178825Sdfr *    documentation and/or other materials provided with the distribution.
16178825Sdfr *
17178825Sdfr * 3. Neither the name of the Institute nor the names of its contributors
18178825Sdfr *    may be used to endorse or promote products derived from this software
19178825Sdfr *    without specific prior written permission.
20178825Sdfr *
21178825Sdfr * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22178825Sdfr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23178825Sdfr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24178825Sdfr * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25178825Sdfr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26178825Sdfr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27178825Sdfr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28178825Sdfr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29178825Sdfr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30178825Sdfr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31178825Sdfr * SUCH DAMAGE.
32178825Sdfr */
33178825Sdfr
34178825Sdfr#include "hx_locl.h"
35178825SdfrRCSID("$Id: ks_p11.c 22071 2007-11-14 20:04:50Z lha $");
36178825Sdfr#ifdef HAVE_DLFCN_H
37178825Sdfr#include <dlfcn.h>
38178825Sdfr#endif
39178825Sdfr
40178825Sdfr#ifdef HAVE_DLOPEN
41178825Sdfr
42178825Sdfr#include "pkcs11.h"
43178825Sdfr
44178825Sdfrstruct p11_slot {
45178825Sdfr    int flags;
46178825Sdfr#define P11_SESSION		1
47178825Sdfr#define P11_SESSION_IN_USE	2
48178825Sdfr#define P11_LOGIN_REQ		4
49178825Sdfr#define P11_LOGIN_DONE		8
50178825Sdfr#define P11_TOKEN_PRESENT	16
51178825Sdfr    CK_SESSION_HANDLE session;
52178825Sdfr    CK_SLOT_ID id;
53178825Sdfr    CK_BBOOL token;
54178825Sdfr    char *name;
55178825Sdfr    hx509_certs certs;
56178825Sdfr    char *pin;
57178825Sdfr    struct {
58178825Sdfr	CK_MECHANISM_TYPE_PTR list;
59178825Sdfr	CK_ULONG num;
60178825Sdfr	CK_MECHANISM_INFO_PTR *infos;
61178825Sdfr    } mechs;
62178825Sdfr};
63178825Sdfr
64178825Sdfrstruct p11_module {
65178825Sdfr    void *dl_handle;
66178825Sdfr    CK_FUNCTION_LIST_PTR funcs;
67178825Sdfr    CK_ULONG num_slots;
68178825Sdfr    unsigned int refcount;
69178825Sdfr    struct p11_slot *slot;
70178825Sdfr};
71178825Sdfr
72178825Sdfr#define P11FUNC(module,f,args) (*(module)->funcs->C_##f)args
73178825Sdfr
74178825Sdfrstatic int p11_get_session(hx509_context,
75178825Sdfr			   struct p11_module *,
76178825Sdfr			   struct p11_slot *,
77178825Sdfr			   hx509_lock,
78178825Sdfr			   CK_SESSION_HANDLE *);
79178825Sdfrstatic int p11_put_session(struct p11_module *,
80178825Sdfr			   struct p11_slot *,
81178825Sdfr			   CK_SESSION_HANDLE);
82178825Sdfrstatic void p11_release_module(struct p11_module *);
83178825Sdfr
84178825Sdfrstatic int p11_list_keys(hx509_context,
85178825Sdfr			 struct p11_module *,
86178825Sdfr			 struct p11_slot *,
87178825Sdfr			 CK_SESSION_HANDLE,
88178825Sdfr			 hx509_lock,
89178825Sdfr			 hx509_certs *);
90178825Sdfr
91178825Sdfr/*
92178825Sdfr *
93178825Sdfr */
94178825Sdfr
95178825Sdfrstruct p11_rsa {
96178825Sdfr    struct p11_module *p;
97178825Sdfr    struct p11_slot *slot;
98178825Sdfr    CK_OBJECT_HANDLE private_key;
99178825Sdfr    CK_OBJECT_HANDLE public_key;
100178825Sdfr};
101178825Sdfr
102178825Sdfrstatic int
103178825Sdfrp11_rsa_public_encrypt(int flen,
104178825Sdfr		       const unsigned char *from,
105178825Sdfr		       unsigned char *to,
106178825Sdfr		       RSA *rsa,
107178825Sdfr		       int padding)
108178825Sdfr{
109178825Sdfr    return -1;
110178825Sdfr}
111178825Sdfr
112178825Sdfrstatic int
113178825Sdfrp11_rsa_public_decrypt(int flen,
114178825Sdfr		       const unsigned char *from,
115178825Sdfr		       unsigned char *to,
116178825Sdfr		       RSA *rsa,
117178825Sdfr		       int padding)
118178825Sdfr{
119178825Sdfr    return -1;
120178825Sdfr}
121178825Sdfr
122178825Sdfr
123178825Sdfrstatic int
124178825Sdfrp11_rsa_private_encrypt(int flen,
125178825Sdfr			const unsigned char *from,
126178825Sdfr			unsigned char *to,
127178825Sdfr			RSA *rsa,
128178825Sdfr			int padding)
129178825Sdfr{
130178825Sdfr    struct p11_rsa *p11rsa = RSA_get_app_data(rsa);
131178825Sdfr    CK_OBJECT_HANDLE key = p11rsa->private_key;
132178825Sdfr    CK_SESSION_HANDLE session;
133178825Sdfr    CK_MECHANISM mechanism;
134178825Sdfr    CK_ULONG ck_sigsize;
135178825Sdfr    int ret;
136178825Sdfr
137178825Sdfr    if (padding != RSA_PKCS1_PADDING)
138178825Sdfr	return -1;
139178825Sdfr
140178825Sdfr    memset(&mechanism, 0, sizeof(mechanism));
141178825Sdfr    mechanism.mechanism = CKM_RSA_PKCS;
142178825Sdfr
143178825Sdfr    ck_sigsize = RSA_size(rsa);
144178825Sdfr
145178825Sdfr    ret = p11_get_session(NULL, p11rsa->p, p11rsa->slot, NULL, &session);
146178825Sdfr    if (ret)
147178825Sdfr	return -1;
148178825Sdfr
149178825Sdfr    ret = P11FUNC(p11rsa->p, SignInit, (session, &mechanism, key));
150178825Sdfr    if (ret != CKR_OK) {
151178825Sdfr	p11_put_session(p11rsa->p, p11rsa->slot, session);
152178825Sdfr	return -1;
153178825Sdfr    }
154178825Sdfr
155178825Sdfr    ret = P11FUNC(p11rsa->p, Sign,
156178825Sdfr		  (session, (CK_BYTE *)from, flen, to, &ck_sigsize));
157178825Sdfr    p11_put_session(p11rsa->p, p11rsa->slot, session);
158178825Sdfr    if (ret != CKR_OK)
159178825Sdfr	return -1;
160178825Sdfr
161178825Sdfr    return ck_sigsize;
162178825Sdfr}
163178825Sdfr
164178825Sdfrstatic int
165178825Sdfrp11_rsa_private_decrypt(int flen, const unsigned char *from, unsigned char *to,
166178825Sdfr			RSA * rsa, int padding)
167178825Sdfr{
168178825Sdfr    struct p11_rsa *p11rsa = RSA_get_app_data(rsa);
169178825Sdfr    CK_OBJECT_HANDLE key = p11rsa->private_key;
170178825Sdfr    CK_SESSION_HANDLE session;
171178825Sdfr    CK_MECHANISM mechanism;
172178825Sdfr    CK_ULONG ck_sigsize;
173178825Sdfr    int ret;
174178825Sdfr
175178825Sdfr    if (padding != RSA_PKCS1_PADDING)
176178825Sdfr	return -1;
177178825Sdfr
178178825Sdfr    memset(&mechanism, 0, sizeof(mechanism));
179178825Sdfr    mechanism.mechanism = CKM_RSA_PKCS;
180178825Sdfr
181178825Sdfr    ck_sigsize = RSA_size(rsa);
182178825Sdfr
183178825Sdfr    ret = p11_get_session(NULL, p11rsa->p, p11rsa->slot, NULL, &session);
184178825Sdfr    if (ret)
185178825Sdfr	return -1;
186178825Sdfr
187178825Sdfr    ret = P11FUNC(p11rsa->p, DecryptInit, (session, &mechanism, key));
188178825Sdfr    if (ret != CKR_OK) {
189178825Sdfr	p11_put_session(p11rsa->p, p11rsa->slot, session);
190178825Sdfr	return -1;
191178825Sdfr    }
192178825Sdfr
193178825Sdfr    ret = P11FUNC(p11rsa->p, Decrypt,
194178825Sdfr		  (session, (CK_BYTE *)from, flen, to, &ck_sigsize));
195178825Sdfr    p11_put_session(p11rsa->p, p11rsa->slot, session);
196178825Sdfr    if (ret != CKR_OK)
197178825Sdfr	return -1;
198178825Sdfr
199178825Sdfr    return ck_sigsize;
200178825Sdfr}
201178825Sdfr
202178825Sdfrstatic int
203178825Sdfrp11_rsa_init(RSA *rsa)
204178825Sdfr{
205178825Sdfr    return 1;
206178825Sdfr}
207178825Sdfr
208178825Sdfrstatic int
209178825Sdfrp11_rsa_finish(RSA *rsa)
210178825Sdfr{
211178825Sdfr    struct p11_rsa *p11rsa = RSA_get_app_data(rsa);
212178825Sdfr    p11_release_module(p11rsa->p);
213178825Sdfr    free(p11rsa);
214178825Sdfr    return 1;
215178825Sdfr}
216178825Sdfr
217178825Sdfrstatic const RSA_METHOD p11_rsa_pkcs1_method = {
218178825Sdfr    "hx509 PKCS11 PKCS#1 RSA",
219178825Sdfr    p11_rsa_public_encrypt,
220178825Sdfr    p11_rsa_public_decrypt,
221178825Sdfr    p11_rsa_private_encrypt,
222178825Sdfr    p11_rsa_private_decrypt,
223178825Sdfr    NULL,
224178825Sdfr    NULL,
225178825Sdfr    p11_rsa_init,
226178825Sdfr    p11_rsa_finish,
227178825Sdfr    0,
228178825Sdfr    NULL,
229178825Sdfr    NULL,
230178825Sdfr    NULL
231178825Sdfr};
232178825Sdfr
233178825Sdfr/*
234178825Sdfr *
235178825Sdfr */
236178825Sdfr
237178825Sdfrstatic int
238178825Sdfrp11_mech_info(hx509_context context,
239178825Sdfr	      struct p11_module *p,
240178825Sdfr	      struct p11_slot *slot,
241178825Sdfr	      int num)
242178825Sdfr{
243178825Sdfr    CK_ULONG i;
244178825Sdfr    int ret;
245178825Sdfr
246178825Sdfr    ret = P11FUNC(p, GetMechanismList, (slot->id, NULL_PTR, &i));
247178825Sdfr    if (ret) {
248178825Sdfr	hx509_set_error_string(context, 0, HX509_PKCS11_NO_MECH,
249178825Sdfr			       "Failed to get mech list count for slot %d",
250178825Sdfr			       num);
251178825Sdfr	return HX509_PKCS11_NO_MECH;
252178825Sdfr    }
253178825Sdfr    if (i == 0) {
254178825Sdfr	hx509_set_error_string(context, 0, HX509_PKCS11_NO_MECH,
255178825Sdfr			       "no mech supported for slot %d", num);
256178825Sdfr	return HX509_PKCS11_NO_MECH;
257178825Sdfr    }
258178825Sdfr    slot->mechs.list = calloc(i, sizeof(slot->mechs.list[0]));
259178825Sdfr    if (slot->mechs.list == NULL) {
260178825Sdfr	hx509_set_error_string(context, 0, ENOMEM,
261178825Sdfr			       "out of memory");
262178825Sdfr	return ENOMEM;
263178825Sdfr    }
264178825Sdfr    slot->mechs.num = i;
265178825Sdfr    ret = P11FUNC(p, GetMechanismList, (slot->id, slot->mechs.list, &i));
266178825Sdfr    if (ret) {
267178825Sdfr	hx509_set_error_string(context, 0, HX509_PKCS11_NO_MECH,
268178825Sdfr			       "Failed to get mech list for slot %d",
269178825Sdfr			       num);
270178825Sdfr	return HX509_PKCS11_NO_MECH;
271178825Sdfr    }
272178825Sdfr    assert(i == slot->mechs.num);
273178825Sdfr
274178825Sdfr    slot->mechs.infos = calloc(i, sizeof(*slot->mechs.infos));
275178825Sdfr    if (slot->mechs.list == NULL) {
276178825Sdfr	hx509_set_error_string(context, 0, ENOMEM,
277178825Sdfr			       "out of memory");
278178825Sdfr	return ENOMEM;
279178825Sdfr    }
280178825Sdfr
281178825Sdfr    for (i = 0; i < slot->mechs.num; i++) {
282178825Sdfr	slot->mechs.infos[i] = calloc(1, sizeof(*(slot->mechs.infos[0])));
283178825Sdfr	if (slot->mechs.infos[i] == NULL) {
284178825Sdfr	    hx509_set_error_string(context, 0, ENOMEM,
285178825Sdfr				   "out of memory");
286178825Sdfr	    return ENOMEM;
287178825Sdfr	}
288178825Sdfr	ret = P11FUNC(p, GetMechanismInfo, (slot->id, slot->mechs.list[i],
289178825Sdfr					    slot->mechs.infos[i]));
290178825Sdfr	if (ret) {
291178825Sdfr	    hx509_set_error_string(context, 0, HX509_PKCS11_NO_MECH,
292178825Sdfr				   "Failed to get mech info for slot %d",
293178825Sdfr				   num);
294178825Sdfr	    return HX509_PKCS11_NO_MECH;
295178825Sdfr	}
296178825Sdfr    }
297178825Sdfr
298178825Sdfr    return 0;
299178825Sdfr}
300178825Sdfr
301178825Sdfrstatic int
302178825Sdfrp11_init_slot(hx509_context context,
303178825Sdfr	      struct p11_module *p,
304178825Sdfr	      hx509_lock lock,
305178825Sdfr	      CK_SLOT_ID id,
306178825Sdfr	      int num,
307178825Sdfr	      struct p11_slot *slot)
308178825Sdfr{
309178825Sdfr    CK_SESSION_HANDLE session;
310178825Sdfr    CK_SLOT_INFO slot_info;
311178825Sdfr    CK_TOKEN_INFO token_info;
312178825Sdfr    int ret, i;
313178825Sdfr
314178825Sdfr    slot->certs = NULL;
315178825Sdfr    slot->id = id;
316178825Sdfr
317178825Sdfr    ret = P11FUNC(p, GetSlotInfo, (slot->id, &slot_info));
318178825Sdfr    if (ret) {
319178825Sdfr	hx509_set_error_string(context, 0, HX509_PKCS11_TOKEN_CONFUSED,
320178825Sdfr			       "Failed to init PKCS11 slot %d",
321178825Sdfr			       num);
322178825Sdfr	return HX509_PKCS11_TOKEN_CONFUSED;
323178825Sdfr    }
324178825Sdfr
325178825Sdfr    for (i = sizeof(slot_info.slotDescription) - 1; i > 0; i--) {
326178825Sdfr	char c = slot_info.slotDescription[i];
327178825Sdfr	if (c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\0')
328178825Sdfr	    continue;
329178825Sdfr	i++;
330178825Sdfr	break;
331178825Sdfr    }
332178825Sdfr
333178825Sdfr    asprintf(&slot->name, "%.*s",
334178825Sdfr	     i, slot_info.slotDescription);
335178825Sdfr
336178825Sdfr    if ((slot_info.flags & CKF_TOKEN_PRESENT) == 0)
337178825Sdfr	return 0;
338178825Sdfr
339178825Sdfr    ret = P11FUNC(p, GetTokenInfo, (slot->id, &token_info));
340178825Sdfr    if (ret) {
341178825Sdfr	hx509_set_error_string(context, 0, HX509_PKCS11_NO_TOKEN,
342178825Sdfr			       "Failed to init PKCS11 slot %d "
343178825Sdfr			       "with error 0x08x",
344178825Sdfr			       num, ret);
345178825Sdfr	return HX509_PKCS11_NO_TOKEN;
346178825Sdfr    }
347178825Sdfr    slot->flags |= P11_TOKEN_PRESENT;
348178825Sdfr
349178825Sdfr    if (token_info.flags & CKF_LOGIN_REQUIRED)
350178825Sdfr	slot->flags |= P11_LOGIN_REQ;
351178825Sdfr
352178825Sdfr    ret = p11_get_session(context, p, slot, lock, &session);
353178825Sdfr    if (ret)
354178825Sdfr	return ret;
355178825Sdfr
356178825Sdfr    ret = p11_mech_info(context, p, slot, num);
357178825Sdfr    if (ret)
358178825Sdfr	goto out;
359178825Sdfr
360178825Sdfr    ret = p11_list_keys(context, p, slot, session, lock, &slot->certs);
361178825Sdfr out:
362178825Sdfr    p11_put_session(p, slot, session);
363178825Sdfr
364178825Sdfr    return ret;
365178825Sdfr}
366178825Sdfr
367178825Sdfrstatic int
368178825Sdfrp11_get_session(hx509_context context,
369178825Sdfr		struct p11_module *p,
370178825Sdfr		struct p11_slot *slot,
371178825Sdfr		hx509_lock lock,
372178825Sdfr		CK_SESSION_HANDLE *psession)
373178825Sdfr{
374178825Sdfr    CK_RV ret;
375178825Sdfr
376178825Sdfr    if (slot->flags & P11_SESSION_IN_USE)
377178825Sdfr	_hx509_abort("slot already in session");
378178825Sdfr
379178825Sdfr    if (slot->flags & P11_SESSION) {
380178825Sdfr	slot->flags |= P11_SESSION_IN_USE;
381178825Sdfr	*psession = slot->session;
382178825Sdfr	return 0;
383178825Sdfr    }
384178825Sdfr
385178825Sdfr    ret = P11FUNC(p, OpenSession, (slot->id,
386178825Sdfr				   CKF_SERIAL_SESSION,
387178825Sdfr				   NULL,
388178825Sdfr				   NULL,
389178825Sdfr				   &slot->session));
390178825Sdfr    if (ret != CKR_OK) {
391178825Sdfr	if (context)
392178825Sdfr	    hx509_set_error_string(context, 0, HX509_PKCS11_OPEN_SESSION,
393178825Sdfr				   "Failed to OpenSession for slot id %d "
394178825Sdfr				   "with error: 0x%08x",
395178825Sdfr				   (int)slot->id, ret);
396178825Sdfr	return HX509_PKCS11_OPEN_SESSION;
397178825Sdfr    }
398178825Sdfr
399178825Sdfr    slot->flags |= P11_SESSION;
400178825Sdfr
401178825Sdfr    /*
402178825Sdfr     * If we have have to login, and haven't tried before and have a
403178825Sdfr     * prompter or known to work pin code.
404178825Sdfr     *
405178825Sdfr     * This code is very conversative and only uses the prompter in
406178825Sdfr     * the hx509_lock, the reason is that it's bad to try many
407178825Sdfr     * passwords on a pkcs11 token, it might lock up and have to be
408178825Sdfr     * unlocked by a administrator.
409178825Sdfr     *
410178825Sdfr     * XXX try harder to not use pin several times on the same card.
411178825Sdfr     */
412178825Sdfr
413178825Sdfr    if (   (slot->flags & P11_LOGIN_REQ)
414178825Sdfr	&& (slot->flags & P11_LOGIN_DONE) == 0
415178825Sdfr	&& (lock || slot->pin))
416178825Sdfr    {
417178825Sdfr	hx509_prompt prompt;
418178825Sdfr	char pin[20];
419178825Sdfr	char *str;
420178825Sdfr
421178825Sdfr	slot->flags |= P11_LOGIN_DONE;
422178825Sdfr
423178825Sdfr	if (slot->pin == NULL) {
424178825Sdfr
425178825Sdfr	    memset(&prompt, 0, sizeof(prompt));
426178825Sdfr
427178825Sdfr	    asprintf(&str, "PIN code for %s: ", slot->name);
428178825Sdfr	    prompt.prompt = str;
429178825Sdfr	    prompt.type = HX509_PROMPT_TYPE_PASSWORD;
430178825Sdfr	    prompt.reply.data = pin;
431178825Sdfr	    prompt.reply.length = sizeof(pin);
432178825Sdfr
433178825Sdfr	    ret = hx509_lock_prompt(lock, &prompt);
434178825Sdfr	    if (ret) {
435178825Sdfr		free(str);
436178825Sdfr		if (context)
437178825Sdfr		    hx509_set_error_string(context, 0, ret,
438178825Sdfr					   "Failed to get pin code for slot "
439178825Sdfr					   "id %d with error: %d",
440178825Sdfr					   (int)slot->id, ret);
441178825Sdfr		return ret;
442178825Sdfr	    }
443178825Sdfr	    free(str);
444178825Sdfr	} else {
445178825Sdfr	    strlcpy(pin, slot->pin, sizeof(pin));
446178825Sdfr	}
447178825Sdfr
448178825Sdfr	ret = P11FUNC(p, Login, (slot->session, CKU_USER,
449178825Sdfr				 (unsigned char*)pin, strlen(pin)));
450178825Sdfr	if (ret != CKR_OK) {
451178825Sdfr	    if (context)
452178825Sdfr		hx509_set_error_string(context, 0, HX509_PKCS11_LOGIN,
453178825Sdfr				       "Failed to login on slot id %d "
454178825Sdfr				       "with error: 0x%08x",
455178825Sdfr				       (int)slot->id, ret);
456178825Sdfr	    p11_put_session(p, slot, slot->session);
457178825Sdfr	    return HX509_PKCS11_LOGIN;
458178825Sdfr	}
459178825Sdfr	if (slot->pin == NULL) {
460178825Sdfr	    slot->pin = strdup(pin);
461178825Sdfr	    if (slot->pin == NULL) {
462178825Sdfr		if (context)
463178825Sdfr		    hx509_set_error_string(context, 0, ENOMEM,
464178825Sdfr					   "out of memory");
465178825Sdfr		p11_put_session(p, slot, slot->session);
466178825Sdfr		return ENOMEM;
467178825Sdfr	    }
468178825Sdfr	}
469178825Sdfr    } else
470178825Sdfr	slot->flags |= P11_LOGIN_DONE;
471178825Sdfr
472178825Sdfr    slot->flags |= P11_SESSION_IN_USE;
473178825Sdfr
474178825Sdfr    *psession = slot->session;
475178825Sdfr
476178825Sdfr    return 0;
477178825Sdfr}
478178825Sdfr
479178825Sdfrstatic int
480178825Sdfrp11_put_session(struct p11_module *p,
481178825Sdfr		struct p11_slot *slot,
482178825Sdfr		CK_SESSION_HANDLE session)
483178825Sdfr{
484178825Sdfr    if ((slot->flags & P11_SESSION_IN_USE) == 0)
485178825Sdfr	_hx509_abort("slot not in session");
486178825Sdfr    slot->flags &= ~P11_SESSION_IN_USE;
487178825Sdfr
488178825Sdfr    return 0;
489178825Sdfr}
490178825Sdfr
491178825Sdfrstatic int
492178825Sdfriterate_entries(hx509_context context,
493178825Sdfr		struct p11_module *p, struct p11_slot *slot,
494178825Sdfr		CK_SESSION_HANDLE session,
495178825Sdfr		CK_ATTRIBUTE *search_data, int num_search_data,
496178825Sdfr		CK_ATTRIBUTE *query, int num_query,
497178825Sdfr		int (*func)(hx509_context,
498178825Sdfr			    struct p11_module *, struct p11_slot *,
499178825Sdfr			    CK_SESSION_HANDLE session,
500178825Sdfr			    CK_OBJECT_HANDLE object,
501178825Sdfr			    void *, CK_ATTRIBUTE *, int), void *ptr)
502178825Sdfr{
503178825Sdfr    CK_OBJECT_HANDLE object;
504178825Sdfr    CK_ULONG object_count;
505178825Sdfr    int ret, i;
506178825Sdfr
507178825Sdfr    ret = P11FUNC(p, FindObjectsInit, (session, search_data, num_search_data));
508178825Sdfr    if (ret != CKR_OK) {
509178825Sdfr	return -1;
510178825Sdfr    }
511178825Sdfr    while (1) {
512178825Sdfr	ret = P11FUNC(p, FindObjects, (session, &object, 1, &object_count));
513178825Sdfr	if (ret != CKR_OK) {
514178825Sdfr	    return -1;
515178825Sdfr	}
516178825Sdfr	if (object_count == 0)
517178825Sdfr	    break;
518178825Sdfr
519178825Sdfr	for (i = 0; i < num_query; i++)
520178825Sdfr	    query[i].pValue = NULL;
521178825Sdfr
522178825Sdfr	ret = P11FUNC(p, GetAttributeValue,
523178825Sdfr		      (session, object, query, num_query));
524178825Sdfr	if (ret != CKR_OK) {
525178825Sdfr	    return -1;
526178825Sdfr	}
527178825Sdfr	for (i = 0; i < num_query; i++) {
528178825Sdfr	    query[i].pValue = malloc(query[i].ulValueLen);
529178825Sdfr	    if (query[i].pValue == NULL) {
530178825Sdfr		ret = ENOMEM;
531178825Sdfr		goto out;
532178825Sdfr	    }
533178825Sdfr	}
534178825Sdfr	ret = P11FUNC(p, GetAttributeValue,
535178825Sdfr		      (session, object, query, num_query));
536178825Sdfr	if (ret != CKR_OK) {
537178825Sdfr	    ret = -1;
538178825Sdfr	    goto out;
539178825Sdfr	}
540178825Sdfr
541178825Sdfr	ret = (*func)(context, p, slot, session, object, ptr, query, num_query);
542178825Sdfr	if (ret)
543178825Sdfr	    goto out;
544178825Sdfr
545178825Sdfr	for (i = 0; i < num_query; i++) {
546178825Sdfr	    if (query[i].pValue)
547178825Sdfr		free(query[i].pValue);
548178825Sdfr	    query[i].pValue = NULL;
549178825Sdfr	}
550178825Sdfr    }
551178825Sdfr out:
552178825Sdfr
553178825Sdfr    for (i = 0; i < num_query; i++) {
554178825Sdfr	if (query[i].pValue)
555178825Sdfr	    free(query[i].pValue);
556178825Sdfr	query[i].pValue = NULL;
557178825Sdfr    }
558178825Sdfr
559178825Sdfr    ret = P11FUNC(p, FindObjectsFinal, (session));
560178825Sdfr    if (ret != CKR_OK) {
561178825Sdfr	return -2;
562178825Sdfr    }
563178825Sdfr
564178825Sdfr
565178825Sdfr    return 0;
566178825Sdfr}
567178825Sdfr
568178825Sdfrstatic BIGNUM *
569178825Sdfrgetattr_bn(struct p11_module *p,
570178825Sdfr	   struct p11_slot *slot,
571178825Sdfr	   CK_SESSION_HANDLE session,
572178825Sdfr	   CK_OBJECT_HANDLE object,
573178825Sdfr	   unsigned int type)
574178825Sdfr{
575178825Sdfr    CK_ATTRIBUTE query;
576178825Sdfr    BIGNUM *bn;
577178825Sdfr    int ret;
578178825Sdfr
579178825Sdfr    query.type = type;
580178825Sdfr    query.pValue = NULL;
581178825Sdfr    query.ulValueLen = 0;
582178825Sdfr
583178825Sdfr    ret = P11FUNC(p, GetAttributeValue,
584178825Sdfr		  (session, object, &query, 1));
585178825Sdfr    if (ret != CKR_OK)
586178825Sdfr	return NULL;
587178825Sdfr
588178825Sdfr    query.pValue = malloc(query.ulValueLen);
589178825Sdfr
590178825Sdfr    ret = P11FUNC(p, GetAttributeValue,
591178825Sdfr		  (session, object, &query, 1));
592178825Sdfr    if (ret != CKR_OK) {
593178825Sdfr	free(query.pValue);
594178825Sdfr	return NULL;
595178825Sdfr    }
596178825Sdfr    bn = BN_bin2bn(query.pValue, query.ulValueLen, NULL);
597178825Sdfr    free(query.pValue);
598178825Sdfr
599178825Sdfr    return bn;
600178825Sdfr}
601178825Sdfr
602178825Sdfrstatic int
603178825Sdfrcollect_private_key(hx509_context context,
604178825Sdfr		    struct p11_module *p, struct p11_slot *slot,
605178825Sdfr		    CK_SESSION_HANDLE session,
606178825Sdfr		    CK_OBJECT_HANDLE object,
607178825Sdfr		    void *ptr, CK_ATTRIBUTE *query, int num_query)
608178825Sdfr{
609178825Sdfr    struct hx509_collector *collector = ptr;
610178825Sdfr    hx509_private_key key;
611178825Sdfr    heim_octet_string localKeyId;
612178825Sdfr    int ret;
613178825Sdfr    RSA *rsa;
614178825Sdfr    struct p11_rsa *p11rsa;
615178825Sdfr
616178825Sdfr    localKeyId.data = query[0].pValue;
617178825Sdfr    localKeyId.length = query[0].ulValueLen;
618178825Sdfr
619178825Sdfr    ret = _hx509_private_key_init(&key, NULL, NULL);
620178825Sdfr    if (ret)
621178825Sdfr	return ret;
622178825Sdfr
623178825Sdfr    rsa = RSA_new();
624178825Sdfr    if (rsa == NULL)
625178825Sdfr	_hx509_abort("out of memory");
626178825Sdfr
627178825Sdfr    /*
628178825Sdfr     * The exponent and modulus should always be present according to
629178825Sdfr     * the pkcs11 specification, but some smartcards leaves it out,
630178825Sdfr     * let ignore any failure to fetch it.
631178825Sdfr     */
632178825Sdfr    rsa->n = getattr_bn(p, slot, session, object, CKA_MODULUS);
633178825Sdfr    rsa->e = getattr_bn(p, slot, session, object, CKA_PUBLIC_EXPONENT);
634178825Sdfr
635178825Sdfr    p11rsa = calloc(1, sizeof(*p11rsa));
636178825Sdfr    if (p11rsa == NULL)
637178825Sdfr	_hx509_abort("out of memory");
638178825Sdfr
639178825Sdfr    p11rsa->p = p;
640178825Sdfr    p11rsa->slot = slot;
641178825Sdfr    p11rsa->private_key = object;
642178825Sdfr
643178825Sdfr    p->refcount++;
644178825Sdfr    if (p->refcount == 0)
645178825Sdfr	_hx509_abort("pkcs11 refcount to high");
646178825Sdfr
647178825Sdfr    RSA_set_method(rsa, &p11_rsa_pkcs1_method);
648178825Sdfr    ret = RSA_set_app_data(rsa, p11rsa);
649178825Sdfr    if (ret != 1)
650178825Sdfr	_hx509_abort("RSA_set_app_data");
651178825Sdfr
652178825Sdfr    _hx509_private_key_assign_rsa(key, rsa);
653178825Sdfr
654178825Sdfr    ret = _hx509_collector_private_key_add(context,
655178825Sdfr					   collector,
656178825Sdfr					   hx509_signature_rsa(),
657178825Sdfr					   key,
658178825Sdfr					   NULL,
659178825Sdfr					   &localKeyId);
660178825Sdfr
661178825Sdfr    if (ret) {
662178825Sdfr	_hx509_private_key_free(&key);
663178825Sdfr	return ret;
664178825Sdfr    }
665178825Sdfr    return 0;
666178825Sdfr}
667178825Sdfr
668178825Sdfrstatic void
669178825Sdfrp11_cert_release(hx509_cert cert, void *ctx)
670178825Sdfr{
671178825Sdfr    struct p11_module *p = ctx;
672178825Sdfr    p11_release_module(p);
673178825Sdfr}
674178825Sdfr
675178825Sdfr
676178825Sdfrstatic int
677178825Sdfrcollect_cert(hx509_context context,
678178825Sdfr	     struct p11_module *p, struct p11_slot *slot,
679178825Sdfr	     CK_SESSION_HANDLE session,
680178825Sdfr	     CK_OBJECT_HANDLE object,
681178825Sdfr	     void *ptr, CK_ATTRIBUTE *query, int num_query)
682178825Sdfr{
683178825Sdfr    struct hx509_collector *collector = ptr;
684178825Sdfr    hx509_cert cert;
685178825Sdfr    int ret;
686178825Sdfr
687178825Sdfr    if ((CK_LONG)query[0].ulValueLen == -1 ||
688178825Sdfr	(CK_LONG)query[1].ulValueLen == -1)
689178825Sdfr    {
690178825Sdfr	return 0;
691178825Sdfr    }
692178825Sdfr
693178825Sdfr    ret = hx509_cert_init_data(context, query[1].pValue,
694178825Sdfr			       query[1].ulValueLen, &cert);
695178825Sdfr    if (ret)
696178825Sdfr	return ret;
697178825Sdfr
698178825Sdfr    p->refcount++;
699178825Sdfr    if (p->refcount == 0)
700178825Sdfr	_hx509_abort("pkcs11 refcount to high");
701178825Sdfr
702178825Sdfr    _hx509_cert_set_release(cert, p11_cert_release, p);
703178825Sdfr
704178825Sdfr    {
705178825Sdfr	heim_octet_string data;
706178825Sdfr
707178825Sdfr	data.data = query[0].pValue;
708178825Sdfr	data.length = query[0].ulValueLen;
709178825Sdfr
710178825Sdfr	_hx509_set_cert_attribute(context,
711178825Sdfr				  cert,
712178825Sdfr				  oid_id_pkcs_9_at_localKeyId(),
713178825Sdfr				  &data);
714178825Sdfr    }
715178825Sdfr
716178825Sdfr    if ((CK_LONG)query[2].ulValueLen != -1) {
717178825Sdfr	char *str;
718178825Sdfr
719178825Sdfr	asprintf(&str, "%.*s",
720178825Sdfr		 (int)query[2].ulValueLen, (char *)query[2].pValue);
721178825Sdfr	if (str) {
722178825Sdfr	    hx509_cert_set_friendly_name(cert, str);
723178825Sdfr	    free(str);
724178825Sdfr	}
725178825Sdfr    }
726178825Sdfr
727178825Sdfr    ret = _hx509_collector_certs_add(context, collector, cert);
728178825Sdfr    hx509_cert_free(cert);
729178825Sdfr
730178825Sdfr    return ret;
731178825Sdfr}
732178825Sdfr
733178825Sdfr
734178825Sdfrstatic int
735178825Sdfrp11_list_keys(hx509_context context,
736178825Sdfr	      struct p11_module *p,
737178825Sdfr	      struct p11_slot *slot,
738178825Sdfr	      CK_SESSION_HANDLE session,
739178825Sdfr	      hx509_lock lock,
740178825Sdfr	      hx509_certs *certs)
741178825Sdfr{
742178825Sdfr    struct hx509_collector *collector;
743178825Sdfr    CK_OBJECT_CLASS key_class;
744178825Sdfr    CK_ATTRIBUTE search_data[] = {
745178825Sdfr	{CKA_CLASS, NULL, 0},
746178825Sdfr    };
747178825Sdfr    CK_ATTRIBUTE query_data[3] = {
748178825Sdfr	{CKA_ID, NULL, 0},
749178825Sdfr	{CKA_VALUE, NULL, 0},
750178825Sdfr	{CKA_LABEL, NULL, 0}
751178825Sdfr    };
752178825Sdfr    int ret;
753178825Sdfr
754178825Sdfr    search_data[0].pValue = &key_class;
755178825Sdfr    search_data[0].ulValueLen = sizeof(key_class);
756178825Sdfr
757178825Sdfr    if (lock == NULL)
758178825Sdfr	lock = _hx509_empty_lock;
759178825Sdfr
760178825Sdfr    ret = _hx509_collector_alloc(context, lock, &collector);
761178825Sdfr    if (ret)
762178825Sdfr	return ret;
763178825Sdfr
764178825Sdfr    key_class = CKO_PRIVATE_KEY;
765178825Sdfr    ret = iterate_entries(context, p, slot, session,
766178825Sdfr			  search_data, 1,
767178825Sdfr			  query_data, 1,
768178825Sdfr			  collect_private_key, collector);
769178825Sdfr    if (ret)
770178825Sdfr	goto out;
771178825Sdfr
772178825Sdfr    key_class = CKO_CERTIFICATE;
773178825Sdfr    ret = iterate_entries(context, p, slot, session,
774178825Sdfr			  search_data, 1,
775178825Sdfr			  query_data, 3,
776178825Sdfr			  collect_cert, collector);
777178825Sdfr    if (ret)
778178825Sdfr	goto out;
779178825Sdfr
780178825Sdfr    ret = _hx509_collector_collect_certs(context, collector, &slot->certs);
781178825Sdfr
782178825Sdfrout:
783178825Sdfr    _hx509_collector_free(collector);
784178825Sdfr
785178825Sdfr    return ret;
786178825Sdfr}
787178825Sdfr
788178825Sdfr
789178825Sdfrstatic int
790178825Sdfrp11_init(hx509_context context,
791178825Sdfr	 hx509_certs certs, void **data, int flags,
792178825Sdfr	 const char *residue, hx509_lock lock)
793178825Sdfr{
794178825Sdfr    CK_C_GetFunctionList getFuncs;
795178825Sdfr    struct p11_module *p;
796178825Sdfr    char *list, *str;
797178825Sdfr    int ret;
798178825Sdfr
799178825Sdfr    *data = NULL;
800178825Sdfr
801178825Sdfr    list = strdup(residue);
802178825Sdfr    if (list == NULL)
803178825Sdfr	return ENOMEM;
804178825Sdfr
805178825Sdfr    p = calloc(1, sizeof(*p));
806178825Sdfr    if (p == NULL) {
807178825Sdfr	free(list);
808178825Sdfr	return ENOMEM;
809178825Sdfr    }
810178825Sdfr
811178825Sdfr    p->refcount = 1;
812178825Sdfr
813178825Sdfr    str = strchr(list, ',');
814178825Sdfr    if (str)
815178825Sdfr	*str++ = '\0';
816178825Sdfr    while (str) {
817178825Sdfr	char *strnext;
818178825Sdfr	strnext = strchr(str, ',');
819178825Sdfr	if (strnext)
820178825Sdfr	    *strnext++ = '\0';
821178825Sdfr#if 0
822178825Sdfr	if (strncasecmp(str, "slot=", 5) == 0)
823178825Sdfr	    p->selected_slot = atoi(str + 5);
824178825Sdfr#endif
825178825Sdfr	str = strnext;
826178825Sdfr    }
827178825Sdfr
828178825Sdfr    p->dl_handle = dlopen(list, RTLD_NOW);
829178825Sdfr    free(list);
830178825Sdfr    if (p->dl_handle == NULL) {
831178825Sdfr	ret = HX509_PKCS11_LOAD;
832178825Sdfr	hx509_set_error_string(context, 0, ret,
833178825Sdfr			       "Failed to open %s: %s", list, dlerror());
834178825Sdfr	goto out;
835178825Sdfr    }
836178825Sdfr
837178825Sdfr    getFuncs = dlsym(p->dl_handle, "C_GetFunctionList");
838178825Sdfr    if (getFuncs == NULL) {
839178825Sdfr	ret = HX509_PKCS11_LOAD;
840178825Sdfr	hx509_set_error_string(context, 0, ret,
841178825Sdfr			       "C_GetFunctionList missing in %s: %s",
842178825Sdfr			       list, dlerror());
843178825Sdfr	goto out;
844178825Sdfr    }
845178825Sdfr
846178825Sdfr    ret = (*getFuncs)(&p->funcs);
847178825Sdfr    if (ret) {
848178825Sdfr	ret = HX509_PKCS11_LOAD;
849178825Sdfr	hx509_set_error_string(context, 0, ret,
850178825Sdfr			       "C_GetFunctionList failed in %s", list);
851178825Sdfr	goto out;
852178825Sdfr    }
853178825Sdfr
854178825Sdfr    ret = P11FUNC(p, Initialize, (NULL_PTR));
855178825Sdfr    if (ret != CKR_OK) {
856178825Sdfr	ret = HX509_PKCS11_TOKEN_CONFUSED;
857178825Sdfr	hx509_set_error_string(context, 0, ret,
858178825Sdfr			       "Failed initialize the PKCS11 module");
859178825Sdfr	goto out;
860178825Sdfr    }
861178825Sdfr
862178825Sdfr    ret = P11FUNC(p, GetSlotList, (FALSE, NULL, &p->num_slots));
863178825Sdfr    if (ret) {
864178825Sdfr	ret = HX509_PKCS11_TOKEN_CONFUSED;
865178825Sdfr	hx509_set_error_string(context, 0, ret,
866178825Sdfr			       "Failed to get number of PKCS11 slots");
867178825Sdfr	goto out;
868178825Sdfr    }
869178825Sdfr
870178825Sdfr   if (p->num_slots == 0) {
871178825Sdfr	ret = HX509_PKCS11_NO_SLOT;
872178825Sdfr	hx509_set_error_string(context, 0, ret,
873178825Sdfr			       "Selected PKCS11 module have no slots");
874178825Sdfr	goto out;
875178825Sdfr   }
876178825Sdfr
877178825Sdfr
878178825Sdfr    {
879178825Sdfr	CK_SLOT_ID_PTR slot_ids;
880178825Sdfr	int i, num_tokens = 0;
881178825Sdfr
882178825Sdfr	slot_ids = malloc(p->num_slots * sizeof(*slot_ids));
883178825Sdfr	if (slot_ids == NULL) {
884178825Sdfr	    hx509_clear_error_string(context);
885178825Sdfr	    ret = ENOMEM;
886178825Sdfr	    goto out;
887178825Sdfr	}
888178825Sdfr
889178825Sdfr	ret = P11FUNC(p, GetSlotList, (FALSE, slot_ids, &p->num_slots));
890178825Sdfr	if (ret) {
891178825Sdfr	    free(slot_ids);
892178825Sdfr	    hx509_set_error_string(context, 0, HX509_PKCS11_TOKEN_CONFUSED,
893178825Sdfr				   "Failed getting slot-list from "
894178825Sdfr				   "PKCS11 module");
895178825Sdfr	    ret = HX509_PKCS11_TOKEN_CONFUSED;
896178825Sdfr	    goto out;
897178825Sdfr	}
898178825Sdfr
899178825Sdfr	p->slot = calloc(p->num_slots, sizeof(p->slot[0]));
900178825Sdfr	if (p->slot == NULL) {
901178825Sdfr	    free(slot_ids);
902178825Sdfr	    hx509_set_error_string(context, 0, ENOMEM,
903178825Sdfr				   "Failed to get memory for slot-list");
904178825Sdfr	    ret = ENOMEM;
905178825Sdfr	    goto out;
906178825Sdfr	}
907178825Sdfr
908178825Sdfr	for (i = 0; i < p->num_slots; i++) {
909178825Sdfr	    ret = p11_init_slot(context, p, lock, slot_ids[i], i, &p->slot[i]);
910178825Sdfr	    if (ret)
911178825Sdfr		break;
912178825Sdfr	    if (p->slot[i].flags & P11_TOKEN_PRESENT)
913178825Sdfr		num_tokens++;
914178825Sdfr	}
915178825Sdfr	free(slot_ids);
916178825Sdfr	if (ret)
917178825Sdfr	    goto out;
918178825Sdfr	if (num_tokens == 0) {
919178825Sdfr	    ret = HX509_PKCS11_NO_TOKEN;
920178825Sdfr	    goto out;
921178825Sdfr	}
922178825Sdfr    }
923178825Sdfr
924178825Sdfr    *data = p;
925178825Sdfr
926178825Sdfr    return 0;
927178825Sdfr out:
928178825Sdfr    p11_release_module(p);
929178825Sdfr    return ret;
930178825Sdfr}
931178825Sdfr
932178825Sdfrstatic void
933178825Sdfrp11_release_module(struct p11_module *p)
934178825Sdfr{
935178825Sdfr    int i;
936178825Sdfr
937178825Sdfr    if (p->refcount == 0)
938178825Sdfr	_hx509_abort("pkcs11 refcount to low");
939178825Sdfr    if (--p->refcount > 0)
940178825Sdfr	return;
941178825Sdfr
942178825Sdfr    for (i = 0; i < p->num_slots; i++) {
943178825Sdfr	if (p->slot[i].flags & P11_SESSION_IN_USE)
944178825Sdfr	    _hx509_abort("pkcs11 module release while session in use");
945178825Sdfr	if (p->slot[i].flags & P11_SESSION) {
946178825Sdfr	    int ret;
947178825Sdfr
948178825Sdfr	    ret = P11FUNC(p, CloseSession, (p->slot[i].session));
949178825Sdfr	    if (ret != CKR_OK)
950178825Sdfr		;
951178825Sdfr	}
952178825Sdfr
953178825Sdfr	if (p->slot[i].name)
954178825Sdfr	    free(p->slot[i].name);
955178825Sdfr	if (p->slot[i].pin) {
956178825Sdfr	    memset(p->slot[i].pin, 0, strlen(p->slot[i].pin));
957178825Sdfr	    free(p->slot[i].pin);
958178825Sdfr	}
959178825Sdfr	if (p->slot[i].mechs.num) {
960178825Sdfr	    free(p->slot[i].mechs.list);
961178825Sdfr
962178825Sdfr	    if (p->slot[i].mechs.infos) {
963178825Sdfr		int j;
964178825Sdfr
965178825Sdfr		for (j = 0 ; j < p->slot[i].mechs.num ; j++)
966178825Sdfr		    free(p->slot[i].mechs.infos[j]);
967178825Sdfr		free(p->slot[i].mechs.infos);
968178825Sdfr	    }
969178825Sdfr	}
970178825Sdfr    }
971178825Sdfr    free(p->slot);
972178825Sdfr
973178825Sdfr    if (p->funcs)
974178825Sdfr	P11FUNC(p, Finalize, (NULL));
975178825Sdfr
976178825Sdfr    if (p->dl_handle)
977178825Sdfr	dlclose(p->dl_handle);
978178825Sdfr
979178825Sdfr    memset(p, 0, sizeof(*p));
980178825Sdfr    free(p);
981178825Sdfr}
982178825Sdfr
983178825Sdfrstatic int
984178825Sdfrp11_free(hx509_certs certs, void *data)
985178825Sdfr{
986178825Sdfr    struct p11_module *p = data;
987178825Sdfr    int i;
988178825Sdfr
989178825Sdfr    for (i = 0; i < p->num_slots; i++) {
990178825Sdfr	if (p->slot[i].certs)
991178825Sdfr	    hx509_certs_free(&p->slot[i].certs);
992178825Sdfr    }
993178825Sdfr    p11_release_module(p);
994178825Sdfr    return 0;
995178825Sdfr}
996178825Sdfr
997178825Sdfrstruct p11_cursor {
998178825Sdfr    hx509_certs certs;
999178825Sdfr    void *cursor;
1000178825Sdfr};
1001178825Sdfr
1002178825Sdfrstatic int
1003178825Sdfrp11_iter_start(hx509_context context,
1004178825Sdfr	       hx509_certs certs, void *data, void **cursor)
1005178825Sdfr{
1006178825Sdfr    struct p11_module *p = data;
1007178825Sdfr    struct p11_cursor *c;
1008178825Sdfr    int ret, i;
1009178825Sdfr
1010178825Sdfr    c = malloc(sizeof(*c));
1011178825Sdfr    if (c == NULL) {
1012178825Sdfr	hx509_clear_error_string(context);
1013178825Sdfr	return ENOMEM;
1014178825Sdfr    }
1015178825Sdfr    ret = hx509_certs_init(context, "MEMORY:pkcs11-iter", 0, NULL, &c->certs);
1016178825Sdfr    if (ret) {
1017178825Sdfr	free(c);
1018178825Sdfr	return ret;
1019178825Sdfr    }
1020178825Sdfr
1021178825Sdfr    for (i = 0 ; i < p->num_slots; i++) {
1022178825Sdfr	if (p->slot[i].certs == NULL)
1023178825Sdfr	    continue;
1024178825Sdfr	ret = hx509_certs_merge(context, c->certs, p->slot[i].certs);
1025178825Sdfr	if (ret) {
1026178825Sdfr	    hx509_certs_free(&c->certs);
1027178825Sdfr	    free(c);
1028178825Sdfr	    return ret;
1029178825Sdfr	}
1030178825Sdfr    }
1031178825Sdfr
1032178825Sdfr    ret = hx509_certs_start_seq(context, c->certs, &c->cursor);
1033178825Sdfr    if (ret) {
1034178825Sdfr	hx509_certs_free(&c->certs);
1035178825Sdfr	free(c);
1036178825Sdfr	return 0;
1037178825Sdfr    }
1038178825Sdfr    *cursor = c;
1039178825Sdfr
1040178825Sdfr    return 0;
1041178825Sdfr}
1042178825Sdfr
1043178825Sdfrstatic int
1044178825Sdfrp11_iter(hx509_context context,
1045178825Sdfr	 hx509_certs certs, void *data, void *cursor, hx509_cert *cert)
1046178825Sdfr{
1047178825Sdfr    struct p11_cursor *c = cursor;
1048178825Sdfr    return hx509_certs_next_cert(context, c->certs, c->cursor, cert);
1049178825Sdfr}
1050178825Sdfr
1051178825Sdfrstatic int
1052178825Sdfrp11_iter_end(hx509_context context,
1053178825Sdfr	     hx509_certs certs, void *data, void *cursor)
1054178825Sdfr{
1055178825Sdfr    struct p11_cursor *c = cursor;
1056178825Sdfr    int ret;
1057178825Sdfr    ret = hx509_certs_end_seq(context, c->certs, c->cursor);
1058178825Sdfr    hx509_certs_free(&c->certs);
1059178825Sdfr    free(c);
1060178825Sdfr    return ret;
1061178825Sdfr}
1062178825Sdfr
1063178825Sdfr#define MECHFLAG(x) { "unknown-flag-" #x, x }
1064178825Sdfrstatic struct units mechflags[] = {
1065178825Sdfr	MECHFLAG(0x80000000),
1066178825Sdfr	MECHFLAG(0x40000000),
1067178825Sdfr	MECHFLAG(0x20000000),
1068178825Sdfr	MECHFLAG(0x10000000),
1069178825Sdfr	MECHFLAG(0x08000000),
1070178825Sdfr	MECHFLAG(0x04000000),
1071178825Sdfr	{"ec-compress",		0x2000000 },
1072178825Sdfr	{"ec-uncompress",	0x1000000 },
1073178825Sdfr	{"ec-namedcurve",	0x0800000 },
1074178825Sdfr	{"ec-ecparameters",	0x0400000 },
1075178825Sdfr	{"ec-f-2m",		0x0200000 },
1076178825Sdfr	{"ec-f-p",		0x0100000 },
1077178825Sdfr	{"derive",		0x0080000 },
1078178825Sdfr	{"unwrap",		0x0040000 },
1079178825Sdfr	{"wrap",		0x0020000 },
1080178825Sdfr	{"genereate-key-pair",	0x0010000 },
1081178825Sdfr	{"generate",		0x0008000 },
1082178825Sdfr	{"verify-recover",	0x0004000 },
1083178825Sdfr	{"verify",		0x0002000 },
1084178825Sdfr	{"sign-recover",	0x0001000 },
1085178825Sdfr	{"sign",		0x0000800 },
1086178825Sdfr	{"digest",		0x0000400 },
1087178825Sdfr	{"decrypt",		0x0000200 },
1088178825Sdfr	{"encrypt",		0x0000100 },
1089178825Sdfr	MECHFLAG(0x00080),
1090178825Sdfr	MECHFLAG(0x00040),
1091178825Sdfr	MECHFLAG(0x00020),
1092178825Sdfr	MECHFLAG(0x00010),
1093178825Sdfr	MECHFLAG(0x00008),
1094178825Sdfr	MECHFLAG(0x00004),
1095178825Sdfr	MECHFLAG(0x00002),
1096178825Sdfr	{"hw",			0x0000001 },
1097178825Sdfr	{ NULL,			0x0000000 }
1098178825Sdfr};
1099178825Sdfr#undef MECHFLAG
1100178825Sdfr
1101178825Sdfrstatic int
1102178825Sdfrp11_printinfo(hx509_context context,
1103178825Sdfr	      hx509_certs certs,
1104178825Sdfr	      void *data,
1105178825Sdfr	      int (*func)(void *, const char *),
1106178825Sdfr	      void *ctx)
1107178825Sdfr{
1108178825Sdfr    struct p11_module *p = data;
1109178825Sdfr    int i, j;
1110178825Sdfr
1111178825Sdfr    _hx509_pi_printf(func, ctx, "pkcs11 driver with %d slot%s",
1112178825Sdfr		     p->num_slots, p->num_slots > 1 ? "s" : "");
1113178825Sdfr
1114178825Sdfr    for (i = 0; i < p->num_slots; i++) {
1115178825Sdfr	struct p11_slot *s = &p->slot[i];
1116178825Sdfr
1117178825Sdfr	_hx509_pi_printf(func, ctx, "slot %d: id: %d name: %s flags: %08x",
1118178825Sdfr			 i, (int)s->id, s->name, s->flags);
1119178825Sdfr
1120178825Sdfr	_hx509_pi_printf(func, ctx, "number of supported mechanisms: %lu",
1121178825Sdfr			 (unsigned long)s->mechs.num);
1122178825Sdfr	for (j = 0; j < s->mechs.num; j++) {
1123178825Sdfr	    const char *mechname = "unknown";
1124178825Sdfr	    char flags[256], unknownname[40];
1125178825Sdfr#define MECHNAME(s,n) case s: mechname = n; break
1126178825Sdfr	    switch(s->mechs.list[j]) {
1127178825Sdfr		MECHNAME(CKM_RSA_PKCS_KEY_PAIR_GEN, "rsa-pkcs-key-pair-gen");
1128178825Sdfr		MECHNAME(CKM_RSA_PKCS, "rsa-pkcs");
1129178825Sdfr		MECHNAME(CKM_RSA_X_509, "rsa-x-509");
1130178825Sdfr		MECHNAME(CKM_MD5_RSA_PKCS, "md5-rsa-pkcs");
1131178825Sdfr		MECHNAME(CKM_SHA1_RSA_PKCS, "sha1-rsa-pkcs");
1132178825Sdfr		MECHNAME(CKM_SHA256_RSA_PKCS, "sha256-rsa-pkcs");
1133178825Sdfr		MECHNAME(CKM_SHA384_RSA_PKCS, "sha384-rsa-pkcs");
1134178825Sdfr		MECHNAME(CKM_SHA512_RSA_PKCS, "sha512-rsa-pkcs");
1135178825Sdfr		MECHNAME(CKM_RIPEMD160_RSA_PKCS, "ripemd160-rsa-pkcs");
1136178825Sdfr		MECHNAME(CKM_RSA_PKCS_OAEP, "rsa-pkcs-oaep");
1137178825Sdfr		MECHNAME(CKM_SHA512_HMAC, "sha512-hmac");
1138178825Sdfr		MECHNAME(CKM_SHA512, "sha512");
1139178825Sdfr		MECHNAME(CKM_SHA384_HMAC, "sha384-hmac");
1140178825Sdfr		MECHNAME(CKM_SHA384, "sha384");
1141178825Sdfr		MECHNAME(CKM_SHA256_HMAC, "sha256-hmac");
1142178825Sdfr		MECHNAME(CKM_SHA256, "sha256");
1143178825Sdfr		MECHNAME(CKM_SHA_1, "sha1");
1144178825Sdfr		MECHNAME(CKM_MD5, "md5");
1145178825Sdfr		MECHNAME(CKM_MD2, "md2");
1146178825Sdfr		MECHNAME(CKM_RIPEMD160, "ripemd-160");
1147178825Sdfr		MECHNAME(CKM_DES_ECB, "des-ecb");
1148178825Sdfr		MECHNAME(CKM_DES_CBC, "des-cbc");
1149178825Sdfr		MECHNAME(CKM_AES_ECB, "aes-ecb");
1150178825Sdfr		MECHNAME(CKM_AES_CBC, "aes-cbc");
1151178825Sdfr		MECHNAME(CKM_DH_PKCS_PARAMETER_GEN, "dh-pkcs-parameter-gen");
1152178825Sdfr	    default:
1153178825Sdfr		snprintf(unknownname, sizeof(unknownname),
1154178825Sdfr			 "unknown-mech-%lu",
1155178825Sdfr			 (unsigned long)s->mechs.list[j]);
1156178825Sdfr		mechname = unknownname;
1157178825Sdfr		break;
1158178825Sdfr	    }
1159178825Sdfr#undef MECHNAME
1160178825Sdfr	    unparse_flags(s->mechs.infos[j]->flags, mechflags,
1161178825Sdfr			  flags, sizeof(flags));
1162178825Sdfr
1163178825Sdfr	    _hx509_pi_printf(func, ctx, "  %s: %s", mechname, flags);
1164178825Sdfr	}
1165178825Sdfr    }
1166178825Sdfr
1167178825Sdfr    return 0;
1168178825Sdfr}
1169178825Sdfr
1170178825Sdfrstatic struct hx509_keyset_ops keyset_pkcs11 = {
1171178825Sdfr    "PKCS11",
1172178825Sdfr    0,
1173178825Sdfr    p11_init,
1174178825Sdfr    NULL,
1175178825Sdfr    p11_free,
1176178825Sdfr    NULL,
1177178825Sdfr    NULL,
1178178825Sdfr    p11_iter_start,
1179178825Sdfr    p11_iter,
1180178825Sdfr    p11_iter_end,
1181178825Sdfr    p11_printinfo
1182178825Sdfr};
1183178825Sdfr
1184178825Sdfr#endif /* HAVE_DLOPEN */
1185178825Sdfr
1186178825Sdfrvoid
1187178825Sdfr_hx509_ks_pkcs11_register(hx509_context context)
1188178825Sdfr{
1189178825Sdfr#ifdef HAVE_DLOPEN
1190178825Sdfr    _hx509_ks_register(context, &keyset_pkcs11);
1191178825Sdfr#endif
1192178825Sdfr}
1193