1178825Sdfr/*
2233294Sstas * Copyright (c) 2004 - 2008 Kungliga Tekniska H��gskolan
3233294Sstas * (Royal Institute of Technology, Stockholm, Sweden).
4233294Sstas * All rights reserved.
5178825Sdfr *
6233294Sstas * Redistribution and use in source and binary forms, with or without
7233294Sstas * modification, are permitted provided that the following conditions
8233294Sstas * are met:
9178825Sdfr *
10233294Sstas * 1. Redistributions of source code must retain the above copyright
11233294Sstas *    notice, this list of conditions and the following disclaimer.
12178825Sdfr *
13233294Sstas * 2. Redistributions in binary form must reproduce the above copyright
14233294Sstas *    notice, this list of conditions and the following disclaimer in the
15233294Sstas *    documentation and/or other materials provided with the distribution.
16178825Sdfr *
17233294Sstas * 3. Neither the name of the Institute nor the names of its contributors
18233294Sstas *    may be used to endorse or promote products derived from this software
19233294Sstas *    without specific prior written permission.
20178825Sdfr *
21233294Sstas * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22233294Sstas * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23233294Sstas * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24233294Sstas * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25233294Sstas * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26233294Sstas * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27233294Sstas * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28233294Sstas * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29233294Sstas * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30233294Sstas * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31233294Sstas * SUCH DAMAGE.
32178825Sdfr */
33178825Sdfr
34178825Sdfr#include "hx_locl.h"
35178825Sdfr#ifdef HAVE_DLFCN_H
36178825Sdfr#include <dlfcn.h>
37178825Sdfr#endif
38178825Sdfr
39178825Sdfr#ifdef HAVE_DLOPEN
40178825Sdfr
41178825Sdfr#include "pkcs11.h"
42178825Sdfr
43178825Sdfrstruct p11_slot {
44178825Sdfr    int flags;
45178825Sdfr#define P11_SESSION		1
46178825Sdfr#define P11_SESSION_IN_USE	2
47178825Sdfr#define P11_LOGIN_REQ		4
48178825Sdfr#define P11_LOGIN_DONE		8
49178825Sdfr#define P11_TOKEN_PRESENT	16
50178825Sdfr    CK_SESSION_HANDLE session;
51178825Sdfr    CK_SLOT_ID id;
52178825Sdfr    CK_BBOOL token;
53178825Sdfr    char *name;
54178825Sdfr    hx509_certs certs;
55178825Sdfr    char *pin;
56178825Sdfr    struct {
57178825Sdfr	CK_MECHANISM_TYPE_PTR list;
58178825Sdfr	CK_ULONG num;
59178825Sdfr	CK_MECHANISM_INFO_PTR *infos;
60178825Sdfr    } mechs;
61178825Sdfr};
62178825Sdfr
63178825Sdfrstruct p11_module {
64178825Sdfr    void *dl_handle;
65178825Sdfr    CK_FUNCTION_LIST_PTR funcs;
66178825Sdfr    CK_ULONG num_slots;
67233294Sstas    unsigned int ref;
68178825Sdfr    struct p11_slot *slot;
69178825Sdfr};
70178825Sdfr
71178825Sdfr#define P11FUNC(module,f,args) (*(module)->funcs->C_##f)args
72178825Sdfr
73178825Sdfrstatic int p11_get_session(hx509_context,
74178825Sdfr			   struct p11_module *,
75178825Sdfr			   struct p11_slot *,
76178825Sdfr			   hx509_lock,
77178825Sdfr			   CK_SESSION_HANDLE *);
78178825Sdfrstatic int p11_put_session(struct p11_module *,
79178825Sdfr			   struct p11_slot *,
80178825Sdfr			   CK_SESSION_HANDLE);
81178825Sdfrstatic void p11_release_module(struct p11_module *);
82178825Sdfr
83178825Sdfrstatic int p11_list_keys(hx509_context,
84178825Sdfr			 struct p11_module *,
85233294Sstas			 struct p11_slot *,
86178825Sdfr			 CK_SESSION_HANDLE,
87178825Sdfr			 hx509_lock,
88178825Sdfr			 hx509_certs *);
89178825Sdfr
90178825Sdfr/*
91178825Sdfr *
92178825Sdfr */
93178825Sdfr
94178825Sdfrstruct p11_rsa {
95178825Sdfr    struct p11_module *p;
96178825Sdfr    struct p11_slot *slot;
97178825Sdfr    CK_OBJECT_HANDLE private_key;
98178825Sdfr    CK_OBJECT_HANDLE public_key;
99178825Sdfr};
100178825Sdfr
101178825Sdfrstatic int
102178825Sdfrp11_rsa_public_encrypt(int flen,
103178825Sdfr		       const unsigned char *from,
104178825Sdfr		       unsigned char *to,
105178825Sdfr		       RSA *rsa,
106178825Sdfr		       int padding)
107178825Sdfr{
108178825Sdfr    return -1;
109178825Sdfr}
110178825Sdfr
111178825Sdfrstatic int
112178825Sdfrp11_rsa_public_decrypt(int flen,
113178825Sdfr		       const unsigned char *from,
114178825Sdfr		       unsigned char *to,
115178825Sdfr		       RSA *rsa,
116178825Sdfr		       int padding)
117178825Sdfr{
118178825Sdfr    return -1;
119178825Sdfr}
120178825Sdfr
121178825Sdfr
122178825Sdfrstatic int
123233294Sstasp11_rsa_private_encrypt(int flen,
124178825Sdfr			const unsigned char *from,
125178825Sdfr			unsigned char *to,
126178825Sdfr			RSA *rsa,
127178825Sdfr			int padding)
128178825Sdfr{
129178825Sdfr    struct p11_rsa *p11rsa = RSA_get_app_data(rsa);
130178825Sdfr    CK_OBJECT_HANDLE key = p11rsa->private_key;
131178825Sdfr    CK_SESSION_HANDLE session;
132178825Sdfr    CK_MECHANISM mechanism;
133178825Sdfr    CK_ULONG ck_sigsize;
134178825Sdfr    int ret;
135178825Sdfr
136178825Sdfr    if (padding != RSA_PKCS1_PADDING)
137178825Sdfr	return -1;
138178825Sdfr
139178825Sdfr    memset(&mechanism, 0, sizeof(mechanism));
140178825Sdfr    mechanism.mechanism = CKM_RSA_PKCS;
141178825Sdfr
142178825Sdfr    ck_sigsize = RSA_size(rsa);
143178825Sdfr
144178825Sdfr    ret = p11_get_session(NULL, p11rsa->p, p11rsa->slot, NULL, &session);
145178825Sdfr    if (ret)
146178825Sdfr	return -1;
147178825Sdfr
148178825Sdfr    ret = P11FUNC(p11rsa->p, SignInit, (session, &mechanism, key));
149178825Sdfr    if (ret != CKR_OK) {
150178825Sdfr	p11_put_session(p11rsa->p, p11rsa->slot, session);
151178825Sdfr	return -1;
152178825Sdfr    }
153178825Sdfr
154233294Sstas    ret = P11FUNC(p11rsa->p, Sign,
155233294Sstas		  (session, (CK_BYTE *)(intptr_t)from, flen, to, &ck_sigsize));
156178825Sdfr    p11_put_session(p11rsa->p, p11rsa->slot, session);
157178825Sdfr    if (ret != CKR_OK)
158178825Sdfr	return -1;
159178825Sdfr
160178825Sdfr    return ck_sigsize;
161178825Sdfr}
162178825Sdfr
163178825Sdfrstatic int
164178825Sdfrp11_rsa_private_decrypt(int flen, const unsigned char *from, unsigned char *to,
165178825Sdfr			RSA * rsa, int padding)
166178825Sdfr{
167178825Sdfr    struct p11_rsa *p11rsa = RSA_get_app_data(rsa);
168178825Sdfr    CK_OBJECT_HANDLE key = p11rsa->private_key;
169178825Sdfr    CK_SESSION_HANDLE session;
170178825Sdfr    CK_MECHANISM mechanism;
171178825Sdfr    CK_ULONG ck_sigsize;
172178825Sdfr    int ret;
173178825Sdfr
174178825Sdfr    if (padding != RSA_PKCS1_PADDING)
175178825Sdfr	return -1;
176178825Sdfr
177178825Sdfr    memset(&mechanism, 0, sizeof(mechanism));
178178825Sdfr    mechanism.mechanism = CKM_RSA_PKCS;
179178825Sdfr
180178825Sdfr    ck_sigsize = RSA_size(rsa);
181178825Sdfr
182178825Sdfr    ret = p11_get_session(NULL, p11rsa->p, p11rsa->slot, NULL, &session);
183178825Sdfr    if (ret)
184178825Sdfr	return -1;
185178825Sdfr
186178825Sdfr    ret = P11FUNC(p11rsa->p, DecryptInit, (session, &mechanism, key));
187178825Sdfr    if (ret != CKR_OK) {
188178825Sdfr	p11_put_session(p11rsa->p, p11rsa->slot, session);
189178825Sdfr	return -1;
190178825Sdfr    }
191178825Sdfr
192233294Sstas    ret = P11FUNC(p11rsa->p, Decrypt,
193233294Sstas		  (session, (CK_BYTE *)(intptr_t)from, flen, to, &ck_sigsize));
194178825Sdfr    p11_put_session(p11rsa->p, p11rsa->slot, session);
195178825Sdfr    if (ret != CKR_OK)
196178825Sdfr	return -1;
197178825Sdfr
198178825Sdfr    return ck_sigsize;
199178825Sdfr}
200178825Sdfr
201233294Sstasstatic int
202178825Sdfrp11_rsa_init(RSA *rsa)
203178825Sdfr{
204178825Sdfr    return 1;
205178825Sdfr}
206178825Sdfr
207178825Sdfrstatic int
208178825Sdfrp11_rsa_finish(RSA *rsa)
209178825Sdfr{
210178825Sdfr    struct p11_rsa *p11rsa = RSA_get_app_data(rsa);
211178825Sdfr    p11_release_module(p11rsa->p);
212178825Sdfr    free(p11rsa);
213178825Sdfr    return 1;
214178825Sdfr}
215178825Sdfr
216178825Sdfrstatic const RSA_METHOD p11_rsa_pkcs1_method = {
217178825Sdfr    "hx509 PKCS11 PKCS#1 RSA",
218178825Sdfr    p11_rsa_public_encrypt,
219178825Sdfr    p11_rsa_public_decrypt,
220178825Sdfr    p11_rsa_private_encrypt,
221178825Sdfr    p11_rsa_private_decrypt,
222178825Sdfr    NULL,
223178825Sdfr    NULL,
224178825Sdfr    p11_rsa_init,
225178825Sdfr    p11_rsa_finish,
226178825Sdfr    0,
227178825Sdfr    NULL,
228178825Sdfr    NULL,
229178825Sdfr    NULL
230178825Sdfr};
231178825Sdfr
232178825Sdfr/*
233178825Sdfr *
234178825Sdfr */
235178825Sdfr
236178825Sdfrstatic int
237178825Sdfrp11_mech_info(hx509_context context,
238178825Sdfr	      struct p11_module *p,
239178825Sdfr	      struct p11_slot *slot,
240178825Sdfr	      int num)
241178825Sdfr{
242178825Sdfr    CK_ULONG i;
243178825Sdfr    int ret;
244178825Sdfr
245178825Sdfr    ret = P11FUNC(p, GetMechanismList, (slot->id, NULL_PTR, &i));
246178825Sdfr    if (ret) {
247178825Sdfr	hx509_set_error_string(context, 0, HX509_PKCS11_NO_MECH,
248178825Sdfr			       "Failed to get mech list count for slot %d",
249178825Sdfr			       num);
250178825Sdfr	return HX509_PKCS11_NO_MECH;
251178825Sdfr    }
252178825Sdfr    if (i == 0) {
253178825Sdfr	hx509_set_error_string(context, 0, HX509_PKCS11_NO_MECH,
254178825Sdfr			       "no mech supported for slot %d", num);
255178825Sdfr	return HX509_PKCS11_NO_MECH;
256178825Sdfr    }
257178825Sdfr    slot->mechs.list = calloc(i, sizeof(slot->mechs.list[0]));
258178825Sdfr    if (slot->mechs.list == NULL) {
259178825Sdfr	hx509_set_error_string(context, 0, ENOMEM,
260178825Sdfr			       "out of memory");
261178825Sdfr	return ENOMEM;
262178825Sdfr    }
263178825Sdfr    slot->mechs.num = i;
264178825Sdfr    ret = P11FUNC(p, GetMechanismList, (slot->id, slot->mechs.list, &i));
265178825Sdfr    if (ret) {
266178825Sdfr	hx509_set_error_string(context, 0, HX509_PKCS11_NO_MECH,
267178825Sdfr			       "Failed to get mech list for slot %d",
268178825Sdfr			       num);
269178825Sdfr	return HX509_PKCS11_NO_MECH;
270178825Sdfr    }
271178825Sdfr    assert(i == slot->mechs.num);
272178825Sdfr
273178825Sdfr    slot->mechs.infos = calloc(i, sizeof(*slot->mechs.infos));
274178825Sdfr    if (slot->mechs.list == NULL) {
275178825Sdfr	hx509_set_error_string(context, 0, ENOMEM,
276178825Sdfr			       "out of memory");
277178825Sdfr	return ENOMEM;
278178825Sdfr    }
279178825Sdfr
280178825Sdfr    for (i = 0; i < slot->mechs.num; i++) {
281178825Sdfr	slot->mechs.infos[i] = calloc(1, sizeof(*(slot->mechs.infos[0])));
282178825Sdfr	if (slot->mechs.infos[i] == NULL) {
283178825Sdfr	    hx509_set_error_string(context, 0, ENOMEM,
284178825Sdfr				   "out of memory");
285178825Sdfr	    return ENOMEM;
286178825Sdfr	}
287178825Sdfr	ret = P11FUNC(p, GetMechanismInfo, (slot->id, slot->mechs.list[i],
288178825Sdfr					    slot->mechs.infos[i]));
289178825Sdfr	if (ret) {
290178825Sdfr	    hx509_set_error_string(context, 0, HX509_PKCS11_NO_MECH,
291178825Sdfr				   "Failed to get mech info for slot %d",
292178825Sdfr				   num);
293178825Sdfr	    return HX509_PKCS11_NO_MECH;
294178825Sdfr	}
295178825Sdfr    }
296178825Sdfr
297178825Sdfr    return 0;
298178825Sdfr}
299178825Sdfr
300178825Sdfrstatic int
301233294Sstasp11_init_slot(hx509_context context,
302178825Sdfr	      struct p11_module *p,
303178825Sdfr	      hx509_lock lock,
304178825Sdfr	      CK_SLOT_ID id,
305178825Sdfr	      int num,
306178825Sdfr	      struct p11_slot *slot)
307178825Sdfr{
308178825Sdfr    CK_SESSION_HANDLE session;
309178825Sdfr    CK_SLOT_INFO slot_info;
310178825Sdfr    CK_TOKEN_INFO token_info;
311233294Sstas    size_t i;
312233294Sstas    int ret;
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",
334233294Sstas	     (int)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");
378233294Sstas
379178825Sdfr    if (slot->flags & P11_SESSION) {
380178825Sdfr	slot->flags |= P11_SESSION_IN_USE;
381178825Sdfr	*psession = slot->session;
382178825Sdfr	return 0;
383178825Sdfr    }
384178825Sdfr
385233294Sstas    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    }
398233294Sstas
399178825Sdfr    slot->flags |= P11_SESSION;
400233294Sstas
401233294Sstas    /*
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	if (slot->pin == NULL) {
422178825Sdfr
423178825Sdfr	    memset(&prompt, 0, sizeof(prompt));
424178825Sdfr
425178825Sdfr	    asprintf(&str, "PIN code for %s: ", slot->name);
426178825Sdfr	    prompt.prompt = str;
427178825Sdfr	    prompt.type = HX509_PROMPT_TYPE_PASSWORD;
428178825Sdfr	    prompt.reply.data = pin;
429178825Sdfr	    prompt.reply.length = sizeof(pin);
430233294Sstas
431178825Sdfr	    ret = hx509_lock_prompt(lock, &prompt);
432178825Sdfr	    if (ret) {
433178825Sdfr		free(str);
434178825Sdfr		if (context)
435178825Sdfr		    hx509_set_error_string(context, 0, ret,
436178825Sdfr					   "Failed to get pin code for slot "
437178825Sdfr					   "id %d with error: %d",
438178825Sdfr					   (int)slot->id, ret);
439178825Sdfr		return ret;
440178825Sdfr	    }
441178825Sdfr	    free(str);
442178825Sdfr	} else {
443178825Sdfr	    strlcpy(pin, slot->pin, sizeof(pin));
444178825Sdfr	}
445178825Sdfr
446178825Sdfr	ret = P11FUNC(p, Login, (slot->session, CKU_USER,
447178825Sdfr				 (unsigned char*)pin, strlen(pin)));
448178825Sdfr	if (ret != CKR_OK) {
449178825Sdfr	    if (context)
450178825Sdfr		hx509_set_error_string(context, 0, HX509_PKCS11_LOGIN,
451178825Sdfr				       "Failed to login on slot id %d "
452178825Sdfr				       "with error: 0x%08x",
453178825Sdfr				       (int)slot->id, ret);
454178825Sdfr	    return HX509_PKCS11_LOGIN;
455233294Sstas	} else
456233294Sstas	    slot->flags |= P11_LOGIN_DONE;
457233294Sstas
458178825Sdfr	if (slot->pin == NULL) {
459178825Sdfr	    slot->pin = strdup(pin);
460178825Sdfr	    if (slot->pin == NULL) {
461178825Sdfr		if (context)
462178825Sdfr		    hx509_set_error_string(context, 0, ENOMEM,
463178825Sdfr					   "out of memory");
464178825Sdfr		return ENOMEM;
465178825Sdfr	    }
466178825Sdfr	}
467178825Sdfr    } else
468178825Sdfr	slot->flags |= P11_LOGIN_DONE;
469178825Sdfr
470178825Sdfr    slot->flags |= P11_SESSION_IN_USE;
471178825Sdfr
472178825Sdfr    *psession = slot->session;
473178825Sdfr
474178825Sdfr    return 0;
475178825Sdfr}
476178825Sdfr
477178825Sdfrstatic int
478178825Sdfrp11_put_session(struct p11_module *p,
479233294Sstas		struct p11_slot *slot,
480178825Sdfr		CK_SESSION_HANDLE session)
481178825Sdfr{
482178825Sdfr    if ((slot->flags & P11_SESSION_IN_USE) == 0)
483178825Sdfr	_hx509_abort("slot not in session");
484178825Sdfr    slot->flags &= ~P11_SESSION_IN_USE;
485178825Sdfr
486178825Sdfr    return 0;
487178825Sdfr}
488178825Sdfr
489178825Sdfrstatic int
490178825Sdfriterate_entries(hx509_context context,
491178825Sdfr		struct p11_module *p, struct p11_slot *slot,
492178825Sdfr		CK_SESSION_HANDLE session,
493178825Sdfr		CK_ATTRIBUTE *search_data, int num_search_data,
494178825Sdfr		CK_ATTRIBUTE *query, int num_query,
495178825Sdfr		int (*func)(hx509_context,
496178825Sdfr			    struct p11_module *, struct p11_slot *,
497178825Sdfr			    CK_SESSION_HANDLE session,
498178825Sdfr			    CK_OBJECT_HANDLE object,
499178825Sdfr			    void *, CK_ATTRIBUTE *, int), void *ptr)
500178825Sdfr{
501178825Sdfr    CK_OBJECT_HANDLE object;
502178825Sdfr    CK_ULONG object_count;
503233294Sstas    int ret, ret2, i;
504178825Sdfr
505178825Sdfr    ret = P11FUNC(p, FindObjectsInit, (session, search_data, num_search_data));
506178825Sdfr    if (ret != CKR_OK) {
507178825Sdfr	return -1;
508178825Sdfr    }
509178825Sdfr    while (1) {
510178825Sdfr	ret = P11FUNC(p, FindObjects, (session, &object, 1, &object_count));
511178825Sdfr	if (ret != CKR_OK) {
512178825Sdfr	    return -1;
513178825Sdfr	}
514178825Sdfr	if (object_count == 0)
515178825Sdfr	    break;
516233294Sstas
517178825Sdfr	for (i = 0; i < num_query; i++)
518178825Sdfr	    query[i].pValue = NULL;
519178825Sdfr
520233294Sstas	ret = P11FUNC(p, GetAttributeValue,
521178825Sdfr		      (session, object, query, num_query));
522178825Sdfr	if (ret != CKR_OK) {
523178825Sdfr	    return -1;
524178825Sdfr	}
525178825Sdfr	for (i = 0; i < num_query; i++) {
526178825Sdfr	    query[i].pValue = malloc(query[i].ulValueLen);
527178825Sdfr	    if (query[i].pValue == NULL) {
528178825Sdfr		ret = ENOMEM;
529178825Sdfr		goto out;
530178825Sdfr	    }
531178825Sdfr	}
532178825Sdfr	ret = P11FUNC(p, GetAttributeValue,
533178825Sdfr		      (session, object, query, num_query));
534178825Sdfr	if (ret != CKR_OK) {
535178825Sdfr	    ret = -1;
536178825Sdfr	    goto out;
537178825Sdfr	}
538233294Sstas
539178825Sdfr	ret = (*func)(context, p, slot, session, object, ptr, query, num_query);
540178825Sdfr	if (ret)
541178825Sdfr	    goto out;
542178825Sdfr
543178825Sdfr	for (i = 0; i < num_query; i++) {
544178825Sdfr	    if (query[i].pValue)
545178825Sdfr		free(query[i].pValue);
546178825Sdfr	    query[i].pValue = NULL;
547178825Sdfr	}
548178825Sdfr    }
549178825Sdfr out:
550178825Sdfr
551178825Sdfr    for (i = 0; i < num_query; i++) {
552178825Sdfr	if (query[i].pValue)
553178825Sdfr	    free(query[i].pValue);
554178825Sdfr	query[i].pValue = NULL;
555178825Sdfr    }
556178825Sdfr
557233294Sstas    ret2 = P11FUNC(p, FindObjectsFinal, (session));
558233294Sstas    if (ret2 != CKR_OK) {
559233294Sstas	return ret2;
560178825Sdfr    }
561178825Sdfr
562233294Sstas    return ret;
563233294Sstas}
564178825Sdfr
565178825Sdfrstatic BIGNUM *
566178825Sdfrgetattr_bn(struct p11_module *p,
567178825Sdfr	   struct p11_slot *slot,
568178825Sdfr	   CK_SESSION_HANDLE session,
569233294Sstas	   CK_OBJECT_HANDLE object,
570178825Sdfr	   unsigned int type)
571178825Sdfr{
572178825Sdfr    CK_ATTRIBUTE query;
573178825Sdfr    BIGNUM *bn;
574178825Sdfr    int ret;
575178825Sdfr
576178825Sdfr    query.type = type;
577178825Sdfr    query.pValue = NULL;
578178825Sdfr    query.ulValueLen = 0;
579178825Sdfr
580233294Sstas    ret = P11FUNC(p, GetAttributeValue,
581178825Sdfr		  (session, object, &query, 1));
582178825Sdfr    if (ret != CKR_OK)
583178825Sdfr	return NULL;
584178825Sdfr
585178825Sdfr    query.pValue = malloc(query.ulValueLen);
586178825Sdfr
587233294Sstas    ret = P11FUNC(p, GetAttributeValue,
588178825Sdfr		  (session, object, &query, 1));
589178825Sdfr    if (ret != CKR_OK) {
590178825Sdfr	free(query.pValue);
591178825Sdfr	return NULL;
592178825Sdfr    }
593178825Sdfr    bn = BN_bin2bn(query.pValue, query.ulValueLen, NULL);
594178825Sdfr    free(query.pValue);
595178825Sdfr
596178825Sdfr    return bn;
597178825Sdfr}
598178825Sdfr
599178825Sdfrstatic int
600178825Sdfrcollect_private_key(hx509_context context,
601178825Sdfr		    struct p11_module *p, struct p11_slot *slot,
602178825Sdfr		    CK_SESSION_HANDLE session,
603178825Sdfr		    CK_OBJECT_HANDLE object,
604178825Sdfr		    void *ptr, CK_ATTRIBUTE *query, int num_query)
605178825Sdfr{
606178825Sdfr    struct hx509_collector *collector = ptr;
607178825Sdfr    hx509_private_key key;
608178825Sdfr    heim_octet_string localKeyId;
609178825Sdfr    int ret;
610178825Sdfr    RSA *rsa;
611178825Sdfr    struct p11_rsa *p11rsa;
612178825Sdfr
613178825Sdfr    localKeyId.data = query[0].pValue;
614178825Sdfr    localKeyId.length = query[0].ulValueLen;
615178825Sdfr
616233294Sstas    ret = hx509_private_key_init(&key, NULL, NULL);
617178825Sdfr    if (ret)
618178825Sdfr	return ret;
619178825Sdfr
620178825Sdfr    rsa = RSA_new();
621178825Sdfr    if (rsa == NULL)
622178825Sdfr	_hx509_abort("out of memory");
623178825Sdfr
624233294Sstas    /*
625178825Sdfr     * The exponent and modulus should always be present according to
626178825Sdfr     * the pkcs11 specification, but some smartcards leaves it out,
627178825Sdfr     * let ignore any failure to fetch it.
628178825Sdfr     */
629178825Sdfr    rsa->n = getattr_bn(p, slot, session, object, CKA_MODULUS);
630178825Sdfr    rsa->e = getattr_bn(p, slot, session, object, CKA_PUBLIC_EXPONENT);
631178825Sdfr
632178825Sdfr    p11rsa = calloc(1, sizeof(*p11rsa));
633178825Sdfr    if (p11rsa == NULL)
634178825Sdfr	_hx509_abort("out of memory");
635178825Sdfr
636178825Sdfr    p11rsa->p = p;
637178825Sdfr    p11rsa->slot = slot;
638178825Sdfr    p11rsa->private_key = object;
639178825Sdfr
640233294Sstas    if (p->ref == 0)
641233294Sstas	_hx509_abort("pkcs11 ref == 0 on alloc");
642233294Sstas    p->ref++;
643233294Sstas    if (p->ref == UINT_MAX)
644233294Sstas	_hx509_abort("pkcs11 ref == UINT_MAX on alloc");
645233294Sstas
646178825Sdfr    RSA_set_method(rsa, &p11_rsa_pkcs1_method);
647178825Sdfr    ret = RSA_set_app_data(rsa, p11rsa);
648178825Sdfr    if (ret != 1)
649178825Sdfr	_hx509_abort("RSA_set_app_data");
650178825Sdfr
651233294Sstas    hx509_private_key_assign_rsa(key, rsa);
652178825Sdfr
653178825Sdfr    ret = _hx509_collector_private_key_add(context,
654178825Sdfr					   collector,
655178825Sdfr					   hx509_signature_rsa(),
656178825Sdfr					   key,
657178825Sdfr					   NULL,
658178825Sdfr					   &localKeyId);
659178825Sdfr
660178825Sdfr    if (ret) {
661233294Sstas	hx509_private_key_free(&key);
662178825Sdfr	return ret;
663178825Sdfr    }
664178825Sdfr    return 0;
665178825Sdfr}
666178825Sdfr
667178825Sdfrstatic void
668178825Sdfrp11_cert_release(hx509_cert cert, void *ctx)
669178825Sdfr{
670178825Sdfr    struct p11_module *p = ctx;
671178825Sdfr    p11_release_module(p);
672178825Sdfr}
673178825Sdfr
674178825Sdfr
675178825Sdfrstatic int
676233294Sstascollect_cert(hx509_context context,
677178825Sdfr	     struct p11_module *p, struct p11_slot *slot,
678178825Sdfr	     CK_SESSION_HANDLE session,
679178825Sdfr	     CK_OBJECT_HANDLE object,
680178825Sdfr	     void *ptr, CK_ATTRIBUTE *query, int num_query)
681178825Sdfr{
682178825Sdfr    struct hx509_collector *collector = ptr;
683178825Sdfr    hx509_cert cert;
684178825Sdfr    int ret;
685178825Sdfr
686178825Sdfr    if ((CK_LONG)query[0].ulValueLen == -1 ||
687233294Sstas	(CK_LONG)query[1].ulValueLen == -1)
688178825Sdfr    {
689178825Sdfr	return 0;
690178825Sdfr    }
691178825Sdfr
692233294Sstas    ret = hx509_cert_init_data(context, query[1].pValue,
693178825Sdfr			       query[1].ulValueLen, &cert);
694178825Sdfr    if (ret)
695178825Sdfr	return ret;
696178825Sdfr
697233294Sstas    if (p->ref == 0)
698233294Sstas	_hx509_abort("pkcs11 ref == 0 on alloc");
699233294Sstas    p->ref++;
700233294Sstas    if (p->ref == UINT_MAX)
701233294Sstas	_hx509_abort("pkcs11 ref to high");
702178825Sdfr
703178825Sdfr    _hx509_cert_set_release(cert, p11_cert_release, p);
704178825Sdfr
705178825Sdfr    {
706178825Sdfr	heim_octet_string data;
707233294Sstas
708178825Sdfr	data.data = query[0].pValue;
709178825Sdfr	data.length = query[0].ulValueLen;
710233294Sstas
711178825Sdfr	_hx509_set_cert_attribute(context,
712178825Sdfr				  cert,
713233294Sstas				  &asn1_oid_id_pkcs_9_at_localKeyId,
714178825Sdfr				  &data);
715178825Sdfr    }
716178825Sdfr
717178825Sdfr    if ((CK_LONG)query[2].ulValueLen != -1) {
718178825Sdfr	char *str;
719178825Sdfr
720178825Sdfr	asprintf(&str, "%.*s",
721178825Sdfr		 (int)query[2].ulValueLen, (char *)query[2].pValue);
722178825Sdfr	if (str) {
723178825Sdfr	    hx509_cert_set_friendly_name(cert, str);
724178825Sdfr	    free(str);
725178825Sdfr	}
726178825Sdfr    }
727178825Sdfr
728178825Sdfr    ret = _hx509_collector_certs_add(context, collector, cert);
729178825Sdfr    hx509_cert_free(cert);
730178825Sdfr
731178825Sdfr    return ret;
732178825Sdfr}
733178825Sdfr
734178825Sdfr
735178825Sdfrstatic int
736178825Sdfrp11_list_keys(hx509_context context,
737178825Sdfr	      struct p11_module *p,
738233294Sstas	      struct p11_slot *slot,
739178825Sdfr	      CK_SESSION_HANDLE session,
740178825Sdfr	      hx509_lock lock,
741178825Sdfr	      hx509_certs *certs)
742178825Sdfr{
743178825Sdfr    struct hx509_collector *collector;
744178825Sdfr    CK_OBJECT_CLASS key_class;
745178825Sdfr    CK_ATTRIBUTE search_data[] = {
746178825Sdfr	{CKA_CLASS, NULL, 0},
747178825Sdfr    };
748178825Sdfr    CK_ATTRIBUTE query_data[3] = {
749178825Sdfr	{CKA_ID, NULL, 0},
750178825Sdfr	{CKA_VALUE, NULL, 0},
751178825Sdfr	{CKA_LABEL, NULL, 0}
752178825Sdfr    };
753178825Sdfr    int ret;
754178825Sdfr
755178825Sdfr    search_data[0].pValue = &key_class;
756178825Sdfr    search_data[0].ulValueLen = sizeof(key_class);
757178825Sdfr
758178825Sdfr    if (lock == NULL)
759178825Sdfr	lock = _hx509_empty_lock;
760178825Sdfr
761178825Sdfr    ret = _hx509_collector_alloc(context, lock, &collector);
762178825Sdfr    if (ret)
763178825Sdfr	return ret;
764178825Sdfr
765178825Sdfr    key_class = CKO_PRIVATE_KEY;
766178825Sdfr    ret = iterate_entries(context, p, slot, session,
767178825Sdfr			  search_data, 1,
768178825Sdfr			  query_data, 1,
769178825Sdfr			  collect_private_key, collector);
770178825Sdfr    if (ret)
771178825Sdfr	goto out;
772178825Sdfr
773178825Sdfr    key_class = CKO_CERTIFICATE;
774178825Sdfr    ret = iterate_entries(context, p, slot, session,
775178825Sdfr			  search_data, 1,
776178825Sdfr			  query_data, 3,
777178825Sdfr			  collect_cert, collector);
778178825Sdfr    if (ret)
779178825Sdfr	goto out;
780178825Sdfr
781178825Sdfr    ret = _hx509_collector_collect_certs(context, collector, &slot->certs);
782178825Sdfr
783178825Sdfrout:
784178825Sdfr    _hx509_collector_free(collector);
785178825Sdfr
786178825Sdfr    return ret;
787178825Sdfr}
788178825Sdfr
789178825Sdfr
790178825Sdfrstatic int
791178825Sdfrp11_init(hx509_context context,
792233294Sstas	 hx509_certs certs, void **data, int flags,
793178825Sdfr	 const char *residue, hx509_lock lock)
794178825Sdfr{
795178825Sdfr    CK_C_GetFunctionList getFuncs;
796178825Sdfr    struct p11_module *p;
797178825Sdfr    char *list, *str;
798178825Sdfr    int ret;
799178825Sdfr
800178825Sdfr    *data = NULL;
801178825Sdfr
802178825Sdfr    list = strdup(residue);
803178825Sdfr    if (list == NULL)
804178825Sdfr	return ENOMEM;
805178825Sdfr
806178825Sdfr    p = calloc(1, sizeof(*p));
807178825Sdfr    if (p == NULL) {
808178825Sdfr	free(list);
809178825Sdfr	return ENOMEM;
810178825Sdfr    }
811178825Sdfr
812233294Sstas    p->ref = 1;
813178825Sdfr
814178825Sdfr    str = strchr(list, ',');
815178825Sdfr    if (str)
816178825Sdfr	*str++ = '\0';
817178825Sdfr    while (str) {
818178825Sdfr	char *strnext;
819178825Sdfr	strnext = strchr(str, ',');
820178825Sdfr	if (strnext)
821178825Sdfr	    *strnext++ = '\0';
822178825Sdfr#if 0
823178825Sdfr	if (strncasecmp(str, "slot=", 5) == 0)
824178825Sdfr	    p->selected_slot = atoi(str + 5);
825178825Sdfr#endif
826178825Sdfr	str = strnext;
827178825Sdfr    }
828178825Sdfr
829178825Sdfr    p->dl_handle = dlopen(list, RTLD_NOW);
830178825Sdfr    free(list);
831178825Sdfr    if (p->dl_handle == NULL) {
832178825Sdfr	ret = HX509_PKCS11_LOAD;
833178825Sdfr	hx509_set_error_string(context, 0, ret,
834178825Sdfr			       "Failed to open %s: %s", list, dlerror());
835178825Sdfr	goto out;
836178825Sdfr    }
837178825Sdfr
838233294Sstas    getFuncs = (CK_C_GetFunctionList) dlsym(p->dl_handle, "C_GetFunctionList");
839178825Sdfr    if (getFuncs == NULL) {
840178825Sdfr	ret = HX509_PKCS11_LOAD;
841178825Sdfr	hx509_set_error_string(context, 0, ret,
842233294Sstas			       "C_GetFunctionList missing in %s: %s",
843178825Sdfr			       list, dlerror());
844178825Sdfr	goto out;
845178825Sdfr    }
846178825Sdfr
847178825Sdfr    ret = (*getFuncs)(&p->funcs);
848178825Sdfr    if (ret) {
849178825Sdfr	ret = HX509_PKCS11_LOAD;
850178825Sdfr	hx509_set_error_string(context, 0, ret,
851178825Sdfr			       "C_GetFunctionList failed in %s", list);
852178825Sdfr	goto out;
853178825Sdfr    }
854178825Sdfr
855178825Sdfr    ret = P11FUNC(p, Initialize, (NULL_PTR));
856178825Sdfr    if (ret != CKR_OK) {
857178825Sdfr	ret = HX509_PKCS11_TOKEN_CONFUSED;
858178825Sdfr	hx509_set_error_string(context, 0, ret,
859178825Sdfr			       "Failed initialize the PKCS11 module");
860178825Sdfr	goto out;
861178825Sdfr    }
862178825Sdfr
863178825Sdfr    ret = P11FUNC(p, GetSlotList, (FALSE, NULL, &p->num_slots));
864178825Sdfr    if (ret) {
865178825Sdfr	ret = HX509_PKCS11_TOKEN_CONFUSED;
866178825Sdfr	hx509_set_error_string(context, 0, ret,
867178825Sdfr			       "Failed to get number of PKCS11 slots");
868178825Sdfr	goto out;
869178825Sdfr    }
870178825Sdfr
871178825Sdfr   if (p->num_slots == 0) {
872178825Sdfr	ret = HX509_PKCS11_NO_SLOT;
873178825Sdfr	hx509_set_error_string(context, 0, ret,
874178825Sdfr			       "Selected PKCS11 module have no slots");
875178825Sdfr	goto out;
876178825Sdfr   }
877178825Sdfr
878178825Sdfr
879178825Sdfr    {
880178825Sdfr	CK_SLOT_ID_PTR slot_ids;
881233294Sstas	int num_tokens = 0;
882233294Sstas	size_t i;
883178825Sdfr
884178825Sdfr	slot_ids = malloc(p->num_slots * sizeof(*slot_ids));
885178825Sdfr	if (slot_ids == NULL) {
886178825Sdfr	    hx509_clear_error_string(context);
887178825Sdfr	    ret = ENOMEM;
888178825Sdfr	    goto out;
889178825Sdfr	}
890178825Sdfr
891178825Sdfr	ret = P11FUNC(p, GetSlotList, (FALSE, slot_ids, &p->num_slots));
892178825Sdfr	if (ret) {
893178825Sdfr	    free(slot_ids);
894178825Sdfr	    hx509_set_error_string(context, 0, HX509_PKCS11_TOKEN_CONFUSED,
895178825Sdfr				   "Failed getting slot-list from "
896178825Sdfr				   "PKCS11 module");
897178825Sdfr	    ret = HX509_PKCS11_TOKEN_CONFUSED;
898178825Sdfr	    goto out;
899178825Sdfr	}
900178825Sdfr
901178825Sdfr	p->slot = calloc(p->num_slots, sizeof(p->slot[0]));
902178825Sdfr	if (p->slot == NULL) {
903178825Sdfr	    free(slot_ids);
904178825Sdfr	    hx509_set_error_string(context, 0, ENOMEM,
905178825Sdfr				   "Failed to get memory for slot-list");
906178825Sdfr	    ret = ENOMEM;
907178825Sdfr	    goto out;
908178825Sdfr	}
909233294Sstas
910178825Sdfr	for (i = 0; i < p->num_slots; i++) {
911178825Sdfr	    ret = p11_init_slot(context, p, lock, slot_ids[i], i, &p->slot[i]);
912178825Sdfr	    if (ret)
913178825Sdfr		break;
914178825Sdfr	    if (p->slot[i].flags & P11_TOKEN_PRESENT)
915178825Sdfr		num_tokens++;
916178825Sdfr	}
917178825Sdfr	free(slot_ids);
918178825Sdfr	if (ret)
919178825Sdfr	    goto out;
920178825Sdfr	if (num_tokens == 0) {
921178825Sdfr	    ret = HX509_PKCS11_NO_TOKEN;
922178825Sdfr	    goto out;
923178825Sdfr	}
924178825Sdfr    }
925178825Sdfr
926178825Sdfr    *data = p;
927178825Sdfr
928178825Sdfr    return 0;
929233294Sstas out:
930178825Sdfr    p11_release_module(p);
931178825Sdfr    return ret;
932178825Sdfr}
933178825Sdfr
934178825Sdfrstatic void
935178825Sdfrp11_release_module(struct p11_module *p)
936178825Sdfr{
937233294Sstas    size_t i;
938178825Sdfr
939233294Sstas    if (p->ref == 0)
940233294Sstas	_hx509_abort("pkcs11 ref to low");
941233294Sstas    if (--p->ref > 0)
942178825Sdfr	return;
943178825Sdfr
944178825Sdfr    for (i = 0; i < p->num_slots; i++) {
945178825Sdfr	if (p->slot[i].flags & P11_SESSION_IN_USE)
946178825Sdfr	    _hx509_abort("pkcs11 module release while session in use");
947178825Sdfr	if (p->slot[i].flags & P11_SESSION) {
948233294Sstas	    P11FUNC(p, CloseSession, (p->slot[i].session));
949178825Sdfr	}
950178825Sdfr
951178825Sdfr	if (p->slot[i].name)
952178825Sdfr	    free(p->slot[i].name);
953178825Sdfr	if (p->slot[i].pin) {
954178825Sdfr	    memset(p->slot[i].pin, 0, strlen(p->slot[i].pin));
955178825Sdfr	    free(p->slot[i].pin);
956178825Sdfr	}
957178825Sdfr	if (p->slot[i].mechs.num) {
958178825Sdfr	    free(p->slot[i].mechs.list);
959178825Sdfr
960178825Sdfr	    if (p->slot[i].mechs.infos) {
961233294Sstas		size_t j;
962178825Sdfr
963178825Sdfr		for (j = 0 ; j < p->slot[i].mechs.num ; j++)
964178825Sdfr		    free(p->slot[i].mechs.infos[j]);
965178825Sdfr		free(p->slot[i].mechs.infos);
966178825Sdfr	    }
967178825Sdfr	}
968178825Sdfr    }
969178825Sdfr    free(p->slot);
970178825Sdfr
971178825Sdfr    if (p->funcs)
972178825Sdfr	P11FUNC(p, Finalize, (NULL));
973178825Sdfr
974178825Sdfr    if (p->dl_handle)
975178825Sdfr	dlclose(p->dl_handle);
976178825Sdfr
977178825Sdfr    memset(p, 0, sizeof(*p));
978178825Sdfr    free(p);
979178825Sdfr}
980178825Sdfr
981178825Sdfrstatic int
982178825Sdfrp11_free(hx509_certs certs, void *data)
983178825Sdfr{
984178825Sdfr    struct p11_module *p = data;
985233294Sstas    size_t i;
986178825Sdfr
987178825Sdfr    for (i = 0; i < p->num_slots; i++) {
988178825Sdfr	if (p->slot[i].certs)
989178825Sdfr	    hx509_certs_free(&p->slot[i].certs);
990178825Sdfr    }
991178825Sdfr    p11_release_module(p);
992178825Sdfr    return 0;
993178825Sdfr}
994178825Sdfr
995178825Sdfrstruct p11_cursor {
996178825Sdfr    hx509_certs certs;
997178825Sdfr    void *cursor;
998178825Sdfr};
999178825Sdfr
1000233294Sstasstatic int
1001178825Sdfrp11_iter_start(hx509_context context,
1002178825Sdfr	       hx509_certs certs, void *data, void **cursor)
1003178825Sdfr{
1004178825Sdfr    struct p11_module *p = data;
1005178825Sdfr    struct p11_cursor *c;
1006233294Sstas    int ret;
1007233294Sstas    size_t i;
1008178825Sdfr
1009178825Sdfr    c = malloc(sizeof(*c));
1010178825Sdfr    if (c == NULL) {
1011178825Sdfr	hx509_clear_error_string(context);
1012178825Sdfr	return ENOMEM;
1013178825Sdfr    }
1014178825Sdfr    ret = hx509_certs_init(context, "MEMORY:pkcs11-iter", 0, NULL, &c->certs);
1015178825Sdfr    if (ret) {
1016178825Sdfr	free(c);
1017178825Sdfr	return ret;
1018178825Sdfr    }
1019178825Sdfr
1020178825Sdfr    for (i = 0 ; i < p->num_slots; i++) {
1021178825Sdfr	if (p->slot[i].certs == NULL)
1022178825Sdfr	    continue;
1023178825Sdfr	ret = hx509_certs_merge(context, c->certs, p->slot[i].certs);
1024178825Sdfr	if (ret) {
1025178825Sdfr	    hx509_certs_free(&c->certs);
1026178825Sdfr	    free(c);
1027178825Sdfr	    return ret;
1028178825Sdfr	}
1029178825Sdfr    }
1030178825Sdfr
1031178825Sdfr    ret = hx509_certs_start_seq(context, c->certs, &c->cursor);
1032178825Sdfr    if (ret) {
1033178825Sdfr	hx509_certs_free(&c->certs);
1034178825Sdfr	free(c);
1035178825Sdfr	return 0;
1036178825Sdfr    }
1037178825Sdfr    *cursor = c;
1038178825Sdfr
1039178825Sdfr    return 0;
1040178825Sdfr}
1041178825Sdfr
1042178825Sdfrstatic int
1043178825Sdfrp11_iter(hx509_context context,
1044178825Sdfr	 hx509_certs certs, void *data, void *cursor, hx509_cert *cert)
1045178825Sdfr{
1046178825Sdfr    struct p11_cursor *c = cursor;
1047178825Sdfr    return hx509_certs_next_cert(context, c->certs, c->cursor, cert);
1048178825Sdfr}
1049178825Sdfr
1050178825Sdfrstatic int
1051178825Sdfrp11_iter_end(hx509_context context,
1052178825Sdfr	     hx509_certs certs, void *data, void *cursor)
1053178825Sdfr{
1054178825Sdfr    struct p11_cursor *c = cursor;
1055178825Sdfr    int ret;
1056178825Sdfr    ret = hx509_certs_end_seq(context, c->certs, c->cursor);
1057178825Sdfr    hx509_certs_free(&c->certs);
1058178825Sdfr    free(c);
1059178825Sdfr    return ret;
1060178825Sdfr}
1061178825Sdfr
1062178825Sdfr#define MECHFLAG(x) { "unknown-flag-" #x, x }
1063178825Sdfrstatic struct units mechflags[] = {
1064178825Sdfr	MECHFLAG(0x80000000),
1065178825Sdfr	MECHFLAG(0x40000000),
1066178825Sdfr	MECHFLAG(0x20000000),
1067178825Sdfr	MECHFLAG(0x10000000),
1068178825Sdfr	MECHFLAG(0x08000000),
1069178825Sdfr	MECHFLAG(0x04000000),
1070178825Sdfr	{"ec-compress",		0x2000000 },
1071178825Sdfr	{"ec-uncompress",	0x1000000 },
1072178825Sdfr	{"ec-namedcurve",	0x0800000 },
1073178825Sdfr	{"ec-ecparameters",	0x0400000 },
1074178825Sdfr	{"ec-f-2m",		0x0200000 },
1075178825Sdfr	{"ec-f-p",		0x0100000 },
1076178825Sdfr	{"derive",		0x0080000 },
1077178825Sdfr	{"unwrap",		0x0040000 },
1078178825Sdfr	{"wrap",		0x0020000 },
1079178825Sdfr	{"genereate-key-pair",	0x0010000 },
1080178825Sdfr	{"generate",		0x0008000 },
1081178825Sdfr	{"verify-recover",	0x0004000 },
1082178825Sdfr	{"verify",		0x0002000 },
1083178825Sdfr	{"sign-recover",	0x0001000 },
1084178825Sdfr	{"sign",		0x0000800 },
1085178825Sdfr	{"digest",		0x0000400 },
1086178825Sdfr	{"decrypt",		0x0000200 },
1087178825Sdfr	{"encrypt",		0x0000100 },
1088178825Sdfr	MECHFLAG(0x00080),
1089178825Sdfr	MECHFLAG(0x00040),
1090178825Sdfr	MECHFLAG(0x00020),
1091178825Sdfr	MECHFLAG(0x00010),
1092178825Sdfr	MECHFLAG(0x00008),
1093178825Sdfr	MECHFLAG(0x00004),
1094178825Sdfr	MECHFLAG(0x00002),
1095178825Sdfr	{"hw",			0x0000001 },
1096178825Sdfr	{ NULL,			0x0000000 }
1097178825Sdfr};
1098178825Sdfr#undef MECHFLAG
1099178825Sdfr
1100178825Sdfrstatic int
1101233294Sstasp11_printinfo(hx509_context context,
1102233294Sstas	      hx509_certs certs,
1103178825Sdfr	      void *data,
1104178825Sdfr	      int (*func)(void *, const char *),
1105178825Sdfr	      void *ctx)
1106178825Sdfr{
1107178825Sdfr    struct p11_module *p = data;
1108233294Sstas    size_t i, j;
1109233294Sstas
1110233294Sstas    _hx509_pi_printf(func, ctx, "pkcs11 driver with %d slot%s",
1111178825Sdfr		     p->num_slots, p->num_slots > 1 ? "s" : "");
1112178825Sdfr
1113178825Sdfr    for (i = 0; i < p->num_slots; i++) {
1114178825Sdfr	struct p11_slot *s = &p->slot[i];
1115178825Sdfr
1116178825Sdfr	_hx509_pi_printf(func, ctx, "slot %d: id: %d name: %s flags: %08x",
1117178825Sdfr			 i, (int)s->id, s->name, s->flags);
1118178825Sdfr
1119233294Sstas	_hx509_pi_printf(func, ctx, "number of supported mechanisms: %lu",
1120178825Sdfr			 (unsigned long)s->mechs.num);
1121178825Sdfr	for (j = 0; j < s->mechs.num; j++) {
1122178825Sdfr	    const char *mechname = "unknown";
1123178825Sdfr	    char flags[256], unknownname[40];
1124178825Sdfr#define MECHNAME(s,n) case s: mechname = n; break
1125178825Sdfr	    switch(s->mechs.list[j]) {
1126178825Sdfr		MECHNAME(CKM_RSA_PKCS_KEY_PAIR_GEN, "rsa-pkcs-key-pair-gen");
1127178825Sdfr		MECHNAME(CKM_RSA_PKCS, "rsa-pkcs");
1128178825Sdfr		MECHNAME(CKM_RSA_X_509, "rsa-x-509");
1129178825Sdfr		MECHNAME(CKM_MD5_RSA_PKCS, "md5-rsa-pkcs");
1130178825Sdfr		MECHNAME(CKM_SHA1_RSA_PKCS, "sha1-rsa-pkcs");
1131178825Sdfr		MECHNAME(CKM_SHA256_RSA_PKCS, "sha256-rsa-pkcs");
1132178825Sdfr		MECHNAME(CKM_SHA384_RSA_PKCS, "sha384-rsa-pkcs");
1133178825Sdfr		MECHNAME(CKM_SHA512_RSA_PKCS, "sha512-rsa-pkcs");
1134178825Sdfr		MECHNAME(CKM_RIPEMD160_RSA_PKCS, "ripemd160-rsa-pkcs");
1135178825Sdfr		MECHNAME(CKM_RSA_PKCS_OAEP, "rsa-pkcs-oaep");
1136178825Sdfr		MECHNAME(CKM_SHA512_HMAC, "sha512-hmac");
1137178825Sdfr		MECHNAME(CKM_SHA512, "sha512");
1138178825Sdfr		MECHNAME(CKM_SHA384_HMAC, "sha384-hmac");
1139178825Sdfr		MECHNAME(CKM_SHA384, "sha384");
1140178825Sdfr		MECHNAME(CKM_SHA256_HMAC, "sha256-hmac");
1141178825Sdfr		MECHNAME(CKM_SHA256, "sha256");
1142178825Sdfr		MECHNAME(CKM_SHA_1, "sha1");
1143178825Sdfr		MECHNAME(CKM_MD5, "md5");
1144178825Sdfr		MECHNAME(CKM_RIPEMD160, "ripemd-160");
1145178825Sdfr		MECHNAME(CKM_DES_ECB, "des-ecb");
1146178825Sdfr		MECHNAME(CKM_DES_CBC, "des-cbc");
1147178825Sdfr		MECHNAME(CKM_AES_ECB, "aes-ecb");
1148178825Sdfr		MECHNAME(CKM_AES_CBC, "aes-cbc");
1149178825Sdfr		MECHNAME(CKM_DH_PKCS_PARAMETER_GEN, "dh-pkcs-parameter-gen");
1150178825Sdfr	    default:
1151178825Sdfr		snprintf(unknownname, sizeof(unknownname),
1152233294Sstas			 "unknown-mech-%lu",
1153178825Sdfr			 (unsigned long)s->mechs.list[j]);
1154178825Sdfr		mechname = unknownname;
1155178825Sdfr		break;
1156178825Sdfr	    }
1157178825Sdfr#undef MECHNAME
1158233294Sstas	    unparse_flags(s->mechs.infos[j]->flags, mechflags,
1159178825Sdfr			  flags, sizeof(flags));
1160178825Sdfr
1161178825Sdfr	    _hx509_pi_printf(func, ctx, "  %s: %s", mechname, flags);
1162178825Sdfr	}
1163178825Sdfr    }
1164178825Sdfr
1165178825Sdfr    return 0;
1166178825Sdfr}
1167178825Sdfr
1168178825Sdfrstatic struct hx509_keyset_ops keyset_pkcs11 = {
1169178825Sdfr    "PKCS11",
1170178825Sdfr    0,
1171178825Sdfr    p11_init,
1172178825Sdfr    NULL,
1173178825Sdfr    p11_free,
1174178825Sdfr    NULL,
1175178825Sdfr    NULL,
1176178825Sdfr    p11_iter_start,
1177178825Sdfr    p11_iter,
1178178825Sdfr    p11_iter_end,
1179178825Sdfr    p11_printinfo
1180178825Sdfr};
1181178825Sdfr
1182178825Sdfr#endif /* HAVE_DLOPEN */
1183178825Sdfr
1184178825Sdfrvoid
1185178825Sdfr_hx509_ks_pkcs11_register(hx509_context context)
1186178825Sdfr{
1187178825Sdfr#ifdef HAVE_DLOPEN
1188178825Sdfr    _hx509_ks_register(context, &keyset_pkcs11);
1189178825Sdfr#endif
1190178825Sdfr}
1191