1/*	$NetBSD: ssh-pkcs11.c,v 1.26 2023/10/25 20:19:57 christos Exp $	*/
2/* $OpenBSD: ssh-pkcs11.c,v 1.59 2023/07/27 22:26:49 djm Exp $ */
3
4/*
5 * Copyright (c) 2010 Markus Friedl.  All rights reserved.
6 * Copyright (c) 2014 Pedro Martelletto. All rights reserved.
7 *
8 * Permission to use, copy, modify, and distribute this software for any
9 * purpose with or without fee is hereby granted, provided that the above
10 * copyright notice and this permission notice appear in all copies.
11 *
12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19 */
20#include "includes.h"
21__RCSID("$NetBSD: ssh-pkcs11.c,v 1.26 2023/10/25 20:19:57 christos Exp $");
22
23#include <sys/types.h>
24#include <sys/queue.h>
25#include <sys/time.h>
26#include <stdarg.h>
27#include <stdio.h>
28
29#include <ctype.h>
30#include <string.h>
31#include <dlfcn.h>
32
33#include <openssl/ecdsa.h>
34#include <openssl/x509.h>
35#include <openssl/err.h>
36
37#define CRYPTOKI_COMPAT
38#include "pkcs11.h"
39
40#include "log.h"
41#include "misc.h"
42#include "sshkey.h"
43#include "ssh-pkcs11.h"
44#include "digest.h"
45#include "xmalloc.h"
46
47struct pkcs11_slotinfo {
48	CK_TOKEN_INFO		token;
49	CK_SESSION_HANDLE	session;
50	int			logged_in;
51};
52
53struct pkcs11_provider {
54	char			*name;
55	void			*handle;
56	CK_FUNCTION_LIST	*function_list;
57	CK_INFO			info;
58	CK_ULONG		nslots;
59	CK_SLOT_ID		*slotlist;
60	struct pkcs11_slotinfo	*slotinfo;
61	int			valid;
62	int			refcount;
63	TAILQ_ENTRY(pkcs11_provider) next;
64};
65
66TAILQ_HEAD(, pkcs11_provider) pkcs11_providers;
67
68struct pkcs11_key {
69	struct pkcs11_provider	*provider;
70	CK_ULONG		slotidx;
71	char			*keyid;
72	int			keyid_len;
73};
74
75int pkcs11_interactive = 0;
76
77#ifdef HAVE_DLOPEN
78static void
79ossl_error(const char *msg)
80{
81	unsigned long    e;
82
83	error_f("%s", msg);
84	while ((e = ERR_get_error()) != 0)
85		error_f("libcrypto error: %s", ERR_error_string(e, NULL));
86}
87#endif
88
89int
90pkcs11_init(int interactive)
91{
92	pkcs11_interactive = interactive;
93	TAILQ_INIT(&pkcs11_providers);
94	return (0);
95}
96
97/*
98 * finalize a provider shared library, it's no longer usable.
99 * however, there might still be keys referencing this provider,
100 * so the actual freeing of memory is handled by pkcs11_provider_unref().
101 * this is called when a provider gets unregistered.
102 */
103static void
104pkcs11_provider_finalize(struct pkcs11_provider *p)
105{
106	CK_RV rv;
107	CK_ULONG i;
108
109	debug_f("provider \"%s\" refcount %d valid %d",
110	    p->name, p->refcount, p->valid);
111	if (!p->valid)
112		return;
113	for (i = 0; i < p->nslots; i++) {
114		if (p->slotinfo[i].session &&
115		    (rv = p->function_list->C_CloseSession(
116		    p->slotinfo[i].session)) != CKR_OK)
117			error("C_CloseSession failed: %lu", rv);
118	}
119	if ((rv = p->function_list->C_Finalize(NULL)) != CKR_OK)
120		error("C_Finalize failed: %lu", rv);
121	p->valid = 0;
122	p->function_list = NULL;
123#ifdef HAVE_DLOPEN
124	dlclose(p->handle);
125#endif
126}
127
128/*
129 * remove a reference to the provider.
130 * called when a key gets destroyed or when the provider is unregistered.
131 */
132static void
133pkcs11_provider_unref(struct pkcs11_provider *p)
134{
135	debug_f("provider \"%s\" refcount %d", p->name, p->refcount);
136	if (--p->refcount <= 0) {
137		if (p->valid)
138			error_f("provider \"%s\" still valid", p->name);
139		free(p->name);
140		free(p->slotlist);
141		free(p->slotinfo);
142		free(p);
143	}
144}
145
146/* unregister all providers, keys might still point to the providers */
147void
148pkcs11_terminate(void)
149{
150	struct pkcs11_provider *p;
151
152	while ((p = TAILQ_FIRST(&pkcs11_providers)) != NULL) {
153		TAILQ_REMOVE(&pkcs11_providers, p, next);
154		pkcs11_provider_finalize(p);
155		pkcs11_provider_unref(p);
156	}
157}
158
159/* lookup provider by name */
160static struct pkcs11_provider *
161pkcs11_provider_lookup(char *provider_id)
162{
163	struct pkcs11_provider *p;
164
165	TAILQ_FOREACH(p, &pkcs11_providers, next) {
166		debug("check provider \"%s\"", p->name);
167		if (!strcmp(provider_id, p->name))
168			return (p);
169	}
170	return (NULL);
171}
172
173/* unregister provider by name */
174int
175pkcs11_del_provider(char *provider_id)
176{
177	struct pkcs11_provider *p;
178
179	if ((p = pkcs11_provider_lookup(provider_id)) != NULL) {
180		TAILQ_REMOVE(&pkcs11_providers, p, next);
181		pkcs11_provider_finalize(p);
182		pkcs11_provider_unref(p);
183		return (0);
184	}
185	return (-1);
186}
187
188#ifdef HAVE_DLOPEN
189static RSA_METHOD *rsa_method;
190static int rsa_idx = 0;
191static EC_KEY_METHOD *ec_key_method;
192static int ec_key_idx = 0;
193
194/* release a wrapped object */
195static void
196pkcs11_k11_free(void *parent, void *ptr, CRYPTO_EX_DATA *ad, int idx,
197    long argl, void *argp)
198{
199	struct pkcs11_key	*k11 = ptr;
200
201	debug_f("parent %p ptr %p idx %d", parent, ptr, idx);
202	if (k11 == NULL)
203		return;
204	if (k11->provider)
205		pkcs11_provider_unref(k11->provider);
206	free(k11->keyid);
207	free(k11);
208}
209
210/* find a single 'obj' for given attributes */
211static int
212pkcs11_find(struct pkcs11_provider *p, CK_ULONG slotidx, CK_ATTRIBUTE *attr,
213    CK_ULONG nattr, CK_OBJECT_HANDLE *obj)
214{
215	CK_FUNCTION_LIST	*f;
216	CK_SESSION_HANDLE	session;
217	CK_ULONG		nfound = 0;
218	CK_RV			rv;
219	int			ret = -1;
220
221	f = p->function_list;
222	session = p->slotinfo[slotidx].session;
223	if ((rv = f->C_FindObjectsInit(session, attr, nattr)) != CKR_OK) {
224		error("C_FindObjectsInit failed (nattr %lu): %lu", nattr, rv);
225		return (-1);
226	}
227	if ((rv = f->C_FindObjects(session, obj, 1, &nfound)) != CKR_OK ||
228	    nfound != 1) {
229		debug("C_FindObjects failed (nfound %lu nattr %lu): %lu",
230		    nfound, nattr, rv);
231	} else
232		ret = 0;
233	if ((rv = f->C_FindObjectsFinal(session)) != CKR_OK)
234		error("C_FindObjectsFinal failed: %lu", rv);
235	return (ret);
236}
237
238static int
239pkcs11_login_slot(struct pkcs11_provider *provider, struct pkcs11_slotinfo *si,
240    CK_USER_TYPE type)
241{
242	char			*pin = NULL, prompt[1024];
243	CK_RV			 rv;
244
245	if (provider == NULL || si == NULL || !provider->valid) {
246		error("no pkcs11 (valid) provider found");
247		return (-1);
248	}
249
250	if (!pkcs11_interactive) {
251		error("need pin entry%s",
252		    (si->token.flags & CKF_PROTECTED_AUTHENTICATION_PATH) ?
253		    " on reader keypad" : "");
254		return (-1);
255	}
256	if (si->token.flags & CKF_PROTECTED_AUTHENTICATION_PATH)
257		verbose("Deferring PIN entry to reader keypad.");
258	else {
259		snprintf(prompt, sizeof(prompt), "Enter PIN for '%s': ",
260		    si->token.label);
261		if ((pin = read_passphrase(prompt, RP_ALLOW_EOF)) == NULL) {
262			debug_f("no pin specified");
263			return (-1);	/* bail out */
264		}
265	}
266	rv = provider->function_list->C_Login(si->session, type, (u_char *)pin,
267	    (pin != NULL) ? strlen(pin) : 0);
268	if (pin != NULL)
269		freezero(pin, strlen(pin));
270
271	switch (rv) {
272	case CKR_OK:
273	case CKR_USER_ALREADY_LOGGED_IN:
274		/* success */
275		break;
276	case CKR_PIN_LEN_RANGE:
277		error("PKCS#11 login failed: PIN length out of range");
278		return -1;
279	case CKR_PIN_INCORRECT:
280		error("PKCS#11 login failed: PIN incorrect");
281		return -1;
282	case CKR_PIN_LOCKED:
283		error("PKCS#11 login failed: PIN locked");
284		return -1;
285	default:
286		error("PKCS#11 login failed: error %lu", rv);
287		return -1;
288	}
289	si->logged_in = 1;
290	return (0);
291}
292
293static int
294pkcs11_login(struct pkcs11_key *k11, CK_USER_TYPE type)
295{
296	if (k11 == NULL || k11->provider == NULL || !k11->provider->valid) {
297		error("no pkcs11 (valid) provider found");
298		return (-1);
299	}
300
301	return pkcs11_login_slot(k11->provider,
302	    &k11->provider->slotinfo[k11->slotidx], type);
303}
304
305
306static int
307pkcs11_check_obj_bool_attrib(struct pkcs11_key *k11, CK_OBJECT_HANDLE obj,
308    CK_ATTRIBUTE_TYPE type, int *val)
309{
310	struct pkcs11_slotinfo	*si;
311	CK_FUNCTION_LIST	*f;
312	CK_BBOOL		flag = 0;
313	CK_ATTRIBUTE		attr;
314	CK_RV			 rv;
315
316	*val = 0;
317
318	if (!k11->provider || !k11->provider->valid) {
319		error("no pkcs11 (valid) provider found");
320		return (-1);
321	}
322
323	f = k11->provider->function_list;
324	si = &k11->provider->slotinfo[k11->slotidx];
325
326	attr.type = type;
327	attr.pValue = &flag;
328	attr.ulValueLen = sizeof(flag);
329
330	rv = f->C_GetAttributeValue(si->session, obj, &attr, 1);
331	if (rv != CKR_OK) {
332		error("C_GetAttributeValue failed: %lu", rv);
333		return (-1);
334	}
335	*val = flag != 0;
336	debug_f("provider \"%s\" slot %lu object %lu: attrib %lu = %d",
337	    k11->provider->name, k11->slotidx, obj, type, *val);
338	return (0);
339}
340
341static int
342pkcs11_get_key(struct pkcs11_key *k11, CK_MECHANISM_TYPE mech_type)
343{
344	struct pkcs11_slotinfo	*si;
345	CK_FUNCTION_LIST	*f;
346	CK_OBJECT_HANDLE	 obj;
347	CK_RV			 rv;
348	CK_OBJECT_CLASS		 private_key_class;
349	CK_BBOOL		 true_val;
350	CK_MECHANISM		 mech;
351	CK_ATTRIBUTE		 key_filter[3];
352	int			 always_auth = 0;
353	int			 did_login = 0;
354
355	if (!k11->provider || !k11->provider->valid) {
356		error("no pkcs11 (valid) provider found");
357		return (-1);
358	}
359
360	f = k11->provider->function_list;
361	si = &k11->provider->slotinfo[k11->slotidx];
362
363	if ((si->token.flags & CKF_LOGIN_REQUIRED) && !si->logged_in) {
364		if (pkcs11_login(k11, CKU_USER) < 0) {
365			error("login failed");
366			return (-1);
367		}
368		did_login = 1;
369	}
370
371	memset(&key_filter, 0, sizeof(key_filter));
372	private_key_class = CKO_PRIVATE_KEY;
373	key_filter[0].type = CKA_CLASS;
374	key_filter[0].pValue = &private_key_class;
375	key_filter[0].ulValueLen = sizeof(private_key_class);
376
377	key_filter[1].type = CKA_ID;
378	key_filter[1].pValue = k11->keyid;
379	key_filter[1].ulValueLen = k11->keyid_len;
380
381	true_val = CK_TRUE;
382	key_filter[2].type = CKA_SIGN;
383	key_filter[2].pValue = &true_val;
384	key_filter[2].ulValueLen = sizeof(true_val);
385
386	/* try to find object w/CKA_SIGN first, retry w/o */
387	if (pkcs11_find(k11->provider, k11->slotidx, key_filter, 3, &obj) < 0 &&
388	    pkcs11_find(k11->provider, k11->slotidx, key_filter, 2, &obj) < 0) {
389		error("cannot find private key");
390		return (-1);
391	}
392
393	memset(&mech, 0, sizeof(mech));
394	mech.mechanism = mech_type;
395	mech.pParameter = NULL_PTR;
396	mech.ulParameterLen = 0;
397
398	if ((rv = f->C_SignInit(si->session, &mech, obj)) != CKR_OK) {
399		error("C_SignInit failed: %lu", rv);
400		return (-1);
401	}
402
403	pkcs11_check_obj_bool_attrib(k11, obj, CKA_ALWAYS_AUTHENTICATE,
404	    &always_auth); /* ignore errors here */
405	if (always_auth && !did_login) {
406		debug_f("always-auth key");
407		if (pkcs11_login(k11, CKU_CONTEXT_SPECIFIC) < 0) {
408			error("login failed for always-auth key");
409			return (-1);
410		}
411	}
412
413	return (0);
414}
415
416/* openssl callback doing the actual signing operation */
417static int
418pkcs11_rsa_private_encrypt(int flen, const u_char *from, u_char *to, RSA *rsa,
419    int padding)
420{
421	struct pkcs11_key	*k11;
422	struct pkcs11_slotinfo	*si;
423	CK_FUNCTION_LIST	*f;
424	CK_ULONG		tlen = 0;
425	CK_RV			rv;
426	int			rval = -1;
427
428	if ((k11 = RSA_get_ex_data(rsa, rsa_idx)) == NULL) {
429		error("RSA_get_ex_data failed");
430		return (-1);
431	}
432
433	if (pkcs11_get_key(k11, CKM_RSA_PKCS) == -1) {
434		error("pkcs11_get_key failed");
435		return (-1);
436	}
437
438	f = k11->provider->function_list;
439	si = &k11->provider->slotinfo[k11->slotidx];
440	tlen = RSA_size(rsa);
441
442	/* XXX handle CKR_BUFFER_TOO_SMALL */
443	rv = f->C_Sign(si->session, __UNCONST(from), flen, to, &tlen);
444	if (rv == CKR_OK)
445		rval = tlen;
446	else
447		error("C_Sign failed: %lu", rv);
448
449	return (rval);
450}
451
452static int
453pkcs11_rsa_private_decrypt(int flen, const u_char *from, u_char *to, RSA *rsa,
454    int padding)
455{
456	return (-1);
457}
458
459static int
460pkcs11_rsa_start_wrapper(void)
461{
462	if (rsa_method != NULL)
463		return (0);
464	rsa_method = RSA_meth_dup(RSA_get_default_method());
465	if (rsa_method == NULL)
466		return (-1);
467	rsa_idx = RSA_get_ex_new_index(0, __UNCONST("ssh-pkcs11-rsa"),
468	    NULL, NULL, pkcs11_k11_free);
469	if (rsa_idx == -1)
470		return (-1);
471	if (!RSA_meth_set1_name(rsa_method, "pkcs11") ||
472	    !RSA_meth_set_priv_enc(rsa_method, pkcs11_rsa_private_encrypt) ||
473	    !RSA_meth_set_priv_dec(rsa_method, pkcs11_rsa_private_decrypt)) {
474		error_f("setup pkcs11 method failed");
475		return (-1);
476	}
477	return (0);
478}
479
480/* redirect private key operations for rsa key to pkcs11 token */
481static int
482pkcs11_rsa_wrap(struct pkcs11_provider *provider, CK_ULONG slotidx,
483    CK_ATTRIBUTE *keyid_attrib, RSA *rsa)
484{
485	struct pkcs11_key	*k11;
486
487	if (pkcs11_rsa_start_wrapper() == -1)
488		return (-1);
489
490	k11 = xcalloc(1, sizeof(*k11));
491	k11->provider = provider;
492	provider->refcount++;	/* provider referenced by RSA key */
493	k11->slotidx = slotidx;
494	/* identify key object on smartcard */
495	k11->keyid_len = keyid_attrib->ulValueLen;
496	if (k11->keyid_len > 0) {
497		k11->keyid = xmalloc(k11->keyid_len);
498		memcpy(k11->keyid, keyid_attrib->pValue, k11->keyid_len);
499	}
500
501	RSA_set_method(rsa, rsa_method);
502	RSA_set_ex_data(rsa, rsa_idx, k11);
503	return (0);
504}
505
506/* openssl callback doing the actual signing operation */
507static ECDSA_SIG *
508ecdsa_do_sign(const unsigned char *dgst, int dgst_len, const BIGNUM *inv,
509    const BIGNUM *rp, EC_KEY *ec)
510{
511	struct pkcs11_key	*k11;
512	struct pkcs11_slotinfo	*si;
513	CK_FUNCTION_LIST	*f;
514	CK_ULONG		siglen = 0, bnlen;
515	CK_RV			rv;
516	ECDSA_SIG		*ret = NULL;
517	u_char			*sig;
518	BIGNUM			*r = NULL, *s = NULL;
519
520	if ((k11 = EC_KEY_get_ex_data(ec, ec_key_idx)) == NULL) {
521		ossl_error("EC_KEY_get_ex_data failed for ec");
522		return (NULL);
523	}
524
525	if (pkcs11_get_key(k11, CKM_ECDSA) == -1) {
526		error("pkcs11_get_key failed");
527		return (NULL);
528	}
529
530	f = k11->provider->function_list;
531	si = &k11->provider->slotinfo[k11->slotidx];
532
533	siglen = ECDSA_size(ec);
534	sig = xmalloc(siglen);
535
536	/* XXX handle CKR_BUFFER_TOO_SMALL */
537	rv = f->C_Sign(si->session, __UNCONST(dgst), dgst_len, sig, &siglen);
538	if (rv != CKR_OK) {
539		error("C_Sign failed: %lu", rv);
540		goto done;
541	}
542	if (siglen < 64 || siglen > 132 || siglen % 2) {
543		error_f("bad signature length: %lu", (u_long)siglen);
544		goto done;
545	}
546	bnlen = siglen/2;
547	if ((ret = ECDSA_SIG_new()) == NULL) {
548		error("ECDSA_SIG_new failed");
549		goto done;
550	}
551	if ((r = BN_bin2bn(sig, bnlen, NULL)) == NULL ||
552	    (s = BN_bin2bn(sig+bnlen, bnlen, NULL)) == NULL) {
553		ossl_error("BN_bin2bn failed");
554		ECDSA_SIG_free(ret);
555		ret = NULL;
556		goto done;
557	}
558	if (!ECDSA_SIG_set0(ret, r, s)) {
559		error_f("ECDSA_SIG_set0 failed");
560		ECDSA_SIG_free(ret);
561		ret = NULL;
562		goto done;
563	}
564	r = s = NULL; /* now owned by ret */
565	/* success */
566 done:
567	BN_free(r);
568	BN_free(s);
569	free(sig);
570
571	return (ret);
572}
573
574static int
575pkcs11_ecdsa_start_wrapper(void)
576{
577	int (*orig_sign)(int, const unsigned char *, int, unsigned char *,
578	    unsigned int *, const BIGNUM *, const BIGNUM *, EC_KEY *) = NULL;
579
580	if (ec_key_method != NULL)
581		return (0);
582	ec_key_idx = EC_KEY_get_ex_new_index(0, __UNCONST("ssh-pkcs11-ecdsa"),
583	    NULL, NULL, pkcs11_k11_free);
584	if (ec_key_idx == -1)
585		return (-1);
586	ec_key_method = EC_KEY_METHOD_new(EC_KEY_OpenSSL());
587	if (ec_key_method == NULL)
588		return (-1);
589	EC_KEY_METHOD_get_sign(ec_key_method, &orig_sign, NULL, NULL);
590	EC_KEY_METHOD_set_sign(ec_key_method, orig_sign, NULL, ecdsa_do_sign);
591	return (0);
592}
593
594static int
595pkcs11_ecdsa_wrap(struct pkcs11_provider *provider, CK_ULONG slotidx,
596    CK_ATTRIBUTE *keyid_attrib, EC_KEY *ec)
597{
598	struct pkcs11_key	*k11;
599
600	if (pkcs11_ecdsa_start_wrapper() == -1)
601		return (-1);
602
603	k11 = xcalloc(1, sizeof(*k11));
604	k11->provider = provider;
605	provider->refcount++;	/* provider referenced by ECDSA key */
606	k11->slotidx = slotidx;
607	/* identify key object on smartcard */
608	k11->keyid_len = keyid_attrib->ulValueLen;
609	if (k11->keyid_len > 0) {
610		k11->keyid = xmalloc(k11->keyid_len);
611		memcpy(k11->keyid, keyid_attrib->pValue, k11->keyid_len);
612	}
613	EC_KEY_set_method(ec, ec_key_method);
614	EC_KEY_set_ex_data(ec, ec_key_idx, k11);
615
616	return (0);
617}
618
619/* remove trailing spaces */
620static char *
621rmspace(u_char *buf, size_t len)
622{
623	size_t i;
624
625	if (len == 0)
626		return buf;
627	for (i = len - 1; i > 0; i--)
628		if (buf[i] == ' ')
629			buf[i] = '\0';
630		else
631			break;
632	return buf;
633}
634/* Used to printf fixed-width, space-padded, unterminated strings using %.*s */
635#define RMSPACE(s) (int)sizeof(s), rmspace(s, sizeof(s))
636
637/*
638 * open a pkcs11 session and login if required.
639 * if pin == NULL we delay login until key use
640 */
641static int
642pkcs11_open_session(struct pkcs11_provider *p, CK_ULONG slotidx, char *pin,
643    CK_ULONG user)
644{
645	struct pkcs11_slotinfo	*si;
646	CK_FUNCTION_LIST	*f;
647	CK_RV			rv;
648	CK_SESSION_HANDLE	session;
649	int			login_required, ret;
650
651	f = p->function_list;
652	si = &p->slotinfo[slotidx];
653
654	login_required = si->token.flags & CKF_LOGIN_REQUIRED;
655
656	/* fail early before opening session */
657	if (login_required && !pkcs11_interactive &&
658	    (pin == NULL || strlen(pin) == 0)) {
659		error("pin required");
660		return (-SSH_PKCS11_ERR_PIN_REQUIRED);
661	}
662	if ((rv = f->C_OpenSession(p->slotlist[slotidx], CKF_RW_SESSION|
663	    CKF_SERIAL_SESSION, NULL, NULL, &session)) != CKR_OK) {
664		error("C_OpenSession failed: %lu", rv);
665		return (-1);
666	}
667	if (login_required && pin != NULL && strlen(pin) != 0) {
668		rv = f->C_Login(session, user, (u_char *)pin, strlen(pin));
669		if (rv != CKR_OK && rv != CKR_USER_ALREADY_LOGGED_IN) {
670			error("C_Login failed: %lu", rv);
671			ret = (rv == CKR_PIN_LOCKED) ?
672			    -SSH_PKCS11_ERR_PIN_LOCKED :
673			    -SSH_PKCS11_ERR_LOGIN_FAIL;
674			if ((rv = f->C_CloseSession(session)) != CKR_OK)
675				error("C_CloseSession failed: %lu", rv);
676			return (ret);
677		}
678		si->logged_in = 1;
679	}
680	si->session = session;
681	return (0);
682}
683
684static int
685pkcs11_key_included(struct sshkey ***keysp, int *nkeys, struct sshkey *key)
686{
687	int i;
688
689	for (i = 0; i < *nkeys; i++)
690		if (sshkey_equal(key, (*keysp)[i]))
691			return (1);
692	return (0);
693}
694
695static struct sshkey *
696pkcs11_fetch_ecdsa_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx,
697    CK_OBJECT_HANDLE *obj)
698{
699	CK_ATTRIBUTE		 key_attr[3];
700	CK_SESSION_HANDLE	 session;
701	CK_FUNCTION_LIST	*f = NULL;
702	CK_RV			 rv;
703	ASN1_OCTET_STRING	*octet = NULL;
704	EC_KEY			*ec = NULL;
705	EC_GROUP		*group = NULL;
706	struct sshkey		*key = NULL;
707	const unsigned char	*attrp = NULL;
708	int			 i;
709	int			 nid;
710
711	memset(&key_attr, 0, sizeof(key_attr));
712	key_attr[0].type = CKA_ID;
713	key_attr[1].type = CKA_EC_POINT;
714	key_attr[2].type = CKA_EC_PARAMS;
715
716	session = p->slotinfo[slotidx].session;
717	f = p->function_list;
718
719	/* figure out size of the attributes */
720	rv = f->C_GetAttributeValue(session, *obj, key_attr, 3);
721	if (rv != CKR_OK) {
722		error("C_GetAttributeValue failed: %lu", rv);
723		return (NULL);
724	}
725
726	/*
727	 * Allow CKA_ID (always first attribute) to be empty, but
728	 * ensure that none of the others are zero length.
729	 * XXX assumes CKA_ID is always first.
730	 */
731	if (key_attr[1].ulValueLen == 0 ||
732	    key_attr[2].ulValueLen == 0) {
733		error("invalid attribute length");
734		return (NULL);
735	}
736
737	/* allocate buffers for attributes */
738	for (i = 0; i < 3; i++)
739		if (key_attr[i].ulValueLen > 0)
740			key_attr[i].pValue = xcalloc(1, key_attr[i].ulValueLen);
741
742	/* retrieve ID, public point and curve parameters of EC key */
743	rv = f->C_GetAttributeValue(session, *obj, key_attr, 3);
744	if (rv != CKR_OK) {
745		error("C_GetAttributeValue failed: %lu", rv);
746		goto fail;
747	}
748
749	ec = EC_KEY_new();
750	if (ec == NULL) {
751		error("EC_KEY_new failed");
752		goto fail;
753	}
754
755	attrp = key_attr[2].pValue;
756	group = d2i_ECPKParameters(NULL, &attrp, key_attr[2].ulValueLen);
757	if (group == NULL) {
758		ossl_error("d2i_ECPKParameters failed");
759		goto fail;
760	}
761
762	if (EC_KEY_set_group(ec, group) == 0) {
763		ossl_error("EC_KEY_set_group failed");
764		goto fail;
765	}
766
767	if (key_attr[1].ulValueLen <= 2) {
768		error("CKA_EC_POINT too small");
769		goto fail;
770	}
771
772	attrp = key_attr[1].pValue;
773	octet = d2i_ASN1_OCTET_STRING(NULL, &attrp, key_attr[1].ulValueLen);
774	if (octet == NULL) {
775		ossl_error("d2i_ASN1_OCTET_STRING failed");
776		goto fail;
777	}
778	attrp = octet->data;
779	if (o2i_ECPublicKey(&ec, &attrp, octet->length) == NULL) {
780		ossl_error("o2i_ECPublicKey failed");
781		goto fail;
782	}
783
784	nid = sshkey_ecdsa_key_to_nid(ec);
785	if (nid < 0) {
786		error("couldn't get curve nid");
787		goto fail;
788	}
789
790	if (pkcs11_ecdsa_wrap(p, slotidx, &key_attr[0], ec))
791		goto fail;
792
793	key = sshkey_new(KEY_UNSPEC);
794	if (key == NULL) {
795		error("sshkey_new failed");
796		goto fail;
797	}
798
799	key->ecdsa = ec;
800	key->ecdsa_nid = nid;
801	key->type = KEY_ECDSA;
802	key->flags |= SSHKEY_FLAG_EXT;
803	ec = NULL;	/* now owned by key */
804
805fail:
806	for (i = 0; i < 3; i++)
807		free(key_attr[i].pValue);
808	if (ec)
809		EC_KEY_free(ec);
810	if (group)
811		EC_GROUP_free(group);
812	if (octet)
813		ASN1_OCTET_STRING_free(octet);
814
815	return (key);
816}
817
818static struct sshkey *
819pkcs11_fetch_rsa_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx,
820    CK_OBJECT_HANDLE *obj)
821{
822	CK_ATTRIBUTE		 key_attr[3];
823	CK_SESSION_HANDLE	 session;
824	CK_FUNCTION_LIST	*f = NULL;
825	CK_RV			 rv;
826	RSA			*rsa = NULL;
827	BIGNUM			*rsa_n, *rsa_e;
828	struct sshkey		*key = NULL;
829	int			 i;
830
831	memset(&key_attr, 0, sizeof(key_attr));
832	key_attr[0].type = CKA_ID;
833	key_attr[1].type = CKA_MODULUS;
834	key_attr[2].type = CKA_PUBLIC_EXPONENT;
835
836	session = p->slotinfo[slotidx].session;
837	f = p->function_list;
838
839	/* figure out size of the attributes */
840	rv = f->C_GetAttributeValue(session, *obj, key_attr, 3);
841	if (rv != CKR_OK) {
842		error("C_GetAttributeValue failed: %lu", rv);
843		return (NULL);
844	}
845
846	/*
847	 * Allow CKA_ID (always first attribute) to be empty, but
848	 * ensure that none of the others are zero length.
849	 * XXX assumes CKA_ID is always first.
850	 */
851	if (key_attr[1].ulValueLen == 0 ||
852	    key_attr[2].ulValueLen == 0) {
853		error("invalid attribute length");
854		return (NULL);
855	}
856
857	/* allocate buffers for attributes */
858	for (i = 0; i < 3; i++)
859		if (key_attr[i].ulValueLen > 0)
860			key_attr[i].pValue = xcalloc(1, key_attr[i].ulValueLen);
861
862	/* retrieve ID, modulus and public exponent of RSA key */
863	rv = f->C_GetAttributeValue(session, *obj, key_attr, 3);
864	if (rv != CKR_OK) {
865		error("C_GetAttributeValue failed: %lu", rv);
866		goto fail;
867	}
868
869	rsa = RSA_new();
870	if (rsa == NULL) {
871		error("RSA_new failed");
872		goto fail;
873	}
874
875	rsa_n = BN_bin2bn(key_attr[1].pValue, key_attr[1].ulValueLen, NULL);
876	rsa_e = BN_bin2bn(key_attr[2].pValue, key_attr[2].ulValueLen, NULL);
877	if (rsa_n == NULL || rsa_e == NULL) {
878		error("BN_bin2bn failed");
879		goto fail;
880	}
881	if (!RSA_set0_key(rsa, rsa_n, rsa_e, NULL))
882		fatal_f("set key");
883	rsa_n = rsa_e = NULL; /* transferred */
884
885	if (pkcs11_rsa_wrap(p, slotidx, &key_attr[0], rsa))
886		goto fail;
887
888	key = sshkey_new(KEY_UNSPEC);
889	if (key == NULL) {
890		error("sshkey_new failed");
891		goto fail;
892	}
893
894	key->rsa = rsa;
895	key->type = KEY_RSA;
896	key->flags |= SSHKEY_FLAG_EXT;
897	rsa = NULL;	/* now owned by key */
898
899fail:
900	for (i = 0; i < 3; i++)
901		free(key_attr[i].pValue);
902	RSA_free(rsa);
903
904	return (key);
905}
906
907static int
908pkcs11_fetch_x509_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx,
909    CK_OBJECT_HANDLE *obj, struct sshkey **keyp, char **labelp)
910{
911	CK_ATTRIBUTE		 cert_attr[3];
912	CK_SESSION_HANDLE	 session;
913	CK_FUNCTION_LIST	*f = NULL;
914	CK_RV			 rv;
915	X509			*x509 = NULL;
916	X509_NAME		*x509_name = NULL;
917	EVP_PKEY		*evp;
918	RSA			*rsa = NULL;
919	EC_KEY			*ec = NULL;
920	struct sshkey		*key = NULL;
921	int			 i;
922	int			 nid;
923	const u_char		*cp;
924	char			*subject = NULL;
925
926	*keyp = NULL;
927	*labelp = NULL;
928
929	memset(&cert_attr, 0, sizeof(cert_attr));
930	cert_attr[0].type = CKA_ID;
931	cert_attr[1].type = CKA_SUBJECT;
932	cert_attr[2].type = CKA_VALUE;
933
934	session = p->slotinfo[slotidx].session;
935	f = p->function_list;
936
937	/* figure out size of the attributes */
938	rv = f->C_GetAttributeValue(session, *obj, cert_attr, 3);
939	if (rv != CKR_OK) {
940		error("C_GetAttributeValue failed: %lu", rv);
941		return -1;
942	}
943
944	/*
945	 * Allow CKA_ID (always first attribute) to be empty, but
946	 * ensure that none of the others are zero length.
947	 * XXX assumes CKA_ID is always first.
948	 */
949	if (cert_attr[1].ulValueLen == 0 ||
950	    cert_attr[2].ulValueLen == 0) {
951		error("invalid attribute length");
952		return -1;
953	}
954
955	/* allocate buffers for attributes */
956	for (i = 0; i < 3; i++)
957		if (cert_attr[i].ulValueLen > 0)
958			cert_attr[i].pValue = xcalloc(1, cert_attr[i].ulValueLen);
959
960	/* retrieve ID, subject and value of certificate */
961	rv = f->C_GetAttributeValue(session, *obj, cert_attr, 3);
962	if (rv != CKR_OK) {
963		error("C_GetAttributeValue failed: %lu", rv);
964		goto out;
965	}
966
967	/* Decode DER-encoded cert subject */
968	cp = cert_attr[1].pValue;
969	if ((x509_name = d2i_X509_NAME(NULL, &cp,
970	    cert_attr[1].ulValueLen)) == NULL ||
971	    (subject = X509_NAME_oneline(x509_name, NULL, 0)) == NULL)
972		subject = xstrdup("invalid subject");
973	X509_NAME_free(x509_name);
974
975	cp = cert_attr[2].pValue;
976	if ((x509 = d2i_X509(NULL, &cp, cert_attr[2].ulValueLen)) == NULL) {
977		error("d2i_x509 failed");
978		goto out;
979	}
980
981	if ((evp = X509_get_pubkey(x509)) == NULL) {
982		error("X509_get_pubkey failed");
983		goto out;
984	}
985
986	if (EVP_PKEY_base_id(evp) == EVP_PKEY_RSA) {
987		if (EVP_PKEY_get0_RSA(evp) == NULL) {
988			error("invalid x509; no rsa key");
989			goto out;
990		}
991		if ((rsa = RSAPublicKey_dup(EVP_PKEY_get0_RSA(evp))) == NULL) {
992			error("RSAPublicKey_dup failed");
993			goto out;
994		}
995
996		if (pkcs11_rsa_wrap(p, slotidx, &cert_attr[0], rsa))
997			goto out;
998
999		key = sshkey_new(KEY_UNSPEC);
1000		if (key == NULL) {
1001			error("sshkey_new failed");
1002			goto out;
1003		}
1004
1005		key->rsa = rsa;
1006		key->type = KEY_RSA;
1007		key->flags |= SSHKEY_FLAG_EXT;
1008		rsa = NULL;	/* now owned by key */
1009	} else if (EVP_PKEY_base_id(evp) == EVP_PKEY_EC) {
1010		if (EVP_PKEY_get0_EC_KEY(evp) == NULL) {
1011			error("invalid x509; no ec key");
1012			goto out;
1013		}
1014		if ((ec = EC_KEY_dup(EVP_PKEY_get0_EC_KEY(evp))) == NULL) {
1015			error("EC_KEY_dup failed");
1016			goto out;
1017		}
1018
1019		nid = sshkey_ecdsa_key_to_nid(ec);
1020		if (nid < 0) {
1021			error("couldn't get curve nid");
1022			goto out;
1023		}
1024
1025		if (pkcs11_ecdsa_wrap(p, slotidx, &cert_attr[0], ec))
1026			goto out;
1027
1028		key = sshkey_new(KEY_UNSPEC);
1029		if (key == NULL) {
1030			error("sshkey_new failed");
1031			goto out;
1032		}
1033
1034		key->ecdsa = ec;
1035		key->ecdsa_nid = nid;
1036		key->type = KEY_ECDSA;
1037		key->flags |= SSHKEY_FLAG_EXT;
1038		ec = NULL;	/* now owned by key */
1039	} else {
1040		error("unknown certificate key type");
1041		goto out;
1042	}
1043 out:
1044	for (i = 0; i < 3; i++)
1045		free(cert_attr[i].pValue);
1046	X509_free(x509);
1047	RSA_free(rsa);
1048	EC_KEY_free(ec);
1049	if (key == NULL) {
1050		free(subject);
1051		return -1;
1052	}
1053	/* success */
1054	*keyp = key;
1055	*labelp = subject;
1056	return 0;
1057}
1058
1059#if 0
1060static int
1061have_rsa_key(const RSA *rsa)
1062{
1063	const BIGNUM *rsa_n, *rsa_e;
1064
1065	RSA_get0_key(rsa, &rsa_n, &rsa_e, NULL);
1066	return rsa_n != NULL && rsa_e != NULL;
1067}
1068#endif
1069
1070static void
1071note_key(struct pkcs11_provider *p, CK_ULONG slotidx, const char *context,
1072    struct sshkey *key)
1073{
1074	char *fp;
1075
1076	if ((fp = sshkey_fingerprint(key, SSH_FP_HASH_DEFAULT,
1077	    SSH_FP_DEFAULT)) == NULL) {
1078		error_f("sshkey_fingerprint failed");
1079		return;
1080	}
1081	debug2("%s: provider %s slot %lu: %s %s", context, p->name,
1082	    (u_long)slotidx, sshkey_type(key), fp);
1083	free(fp);
1084}
1085
1086/*
1087 * lookup certificates for token in slot identified by slotidx,
1088 * add 'wrapped' public keys to the 'keysp' array and increment nkeys.
1089 * keysp points to an (possibly empty) array with *nkeys keys.
1090 */
1091static int
1092pkcs11_fetch_certs(struct pkcs11_provider *p, CK_ULONG slotidx,
1093    struct sshkey ***keysp, char ***labelsp, int *nkeys)
1094{
1095	struct sshkey		*key = NULL;
1096	CK_OBJECT_CLASS		 key_class;
1097	CK_ATTRIBUTE		 key_attr[1];
1098	CK_SESSION_HANDLE	 session;
1099	CK_FUNCTION_LIST	*f = NULL;
1100	CK_RV			 rv;
1101	CK_OBJECT_HANDLE	 obj;
1102	CK_ULONG		 n = 0;
1103	int			 ret = -1;
1104	char			*label;
1105
1106	memset(&key_attr, 0, sizeof(key_attr));
1107	memset(&obj, 0, sizeof(obj));
1108
1109	key_class = CKO_CERTIFICATE;
1110	key_attr[0].type = CKA_CLASS;
1111	key_attr[0].pValue = &key_class;
1112	key_attr[0].ulValueLen = sizeof(key_class);
1113
1114	session = p->slotinfo[slotidx].session;
1115	f = p->function_list;
1116
1117	rv = f->C_FindObjectsInit(session, key_attr, 1);
1118	if (rv != CKR_OK) {
1119		error("C_FindObjectsInit failed: %lu", rv);
1120		goto fail;
1121	}
1122
1123	while (1) {
1124		CK_CERTIFICATE_TYPE	ck_cert_type;
1125
1126		rv = f->C_FindObjects(session, &obj, 1, &n);
1127		if (rv != CKR_OK) {
1128			error("C_FindObjects failed: %lu", rv);
1129			goto fail;
1130		}
1131		if (n == 0)
1132			break;
1133
1134		memset(&ck_cert_type, 0, sizeof(ck_cert_type));
1135		memset(&key_attr, 0, sizeof(key_attr));
1136		key_attr[0].type = CKA_CERTIFICATE_TYPE;
1137		key_attr[0].pValue = &ck_cert_type;
1138		key_attr[0].ulValueLen = sizeof(ck_cert_type);
1139
1140		rv = f->C_GetAttributeValue(session, obj, key_attr, 1);
1141		if (rv != CKR_OK) {
1142			error("C_GetAttributeValue failed: %lu", rv);
1143			goto fail;
1144		}
1145
1146		key = NULL;
1147		label = NULL;
1148		switch (ck_cert_type) {
1149		case CKC_X_509:
1150			if (pkcs11_fetch_x509_pubkey(p, slotidx, &obj,
1151			    &key, &label) != 0) {
1152				error("failed to fetch key");
1153				continue;
1154			}
1155			break;
1156		default:
1157			error("skipping unsupported certificate type %lu",
1158			    ck_cert_type);
1159			continue;
1160		}
1161		note_key(p, slotidx, __func__, key);
1162		if (pkcs11_key_included(keysp, nkeys, key)) {
1163			debug2_f("key already included");;
1164			sshkey_free(key);
1165		} else {
1166			/* expand key array and add key */
1167			*keysp = xrecallocarray(*keysp, *nkeys,
1168			    *nkeys + 1, sizeof(struct sshkey *));
1169			(*keysp)[*nkeys] = key;
1170			if (labelsp != NULL) {
1171				*labelsp = xrecallocarray(*labelsp, *nkeys,
1172				    *nkeys + 1, sizeof(char *));
1173				(*labelsp)[*nkeys] = xstrdup((char *)label);
1174			}
1175			*nkeys = *nkeys + 1;
1176			debug("have %d keys", *nkeys);
1177		}
1178	}
1179
1180	ret = 0;
1181fail:
1182	rv = f->C_FindObjectsFinal(session);
1183	if (rv != CKR_OK) {
1184		error("C_FindObjectsFinal failed: %lu", rv);
1185		ret = -1;
1186	}
1187
1188	return (ret);
1189}
1190
1191/*
1192 * lookup public keys for token in slot identified by slotidx,
1193 * add 'wrapped' public keys to the 'keysp' array and increment nkeys.
1194 * keysp points to an (possibly empty) array with *nkeys keys.
1195 */
1196static int
1197pkcs11_fetch_keys(struct pkcs11_provider *p, CK_ULONG slotidx,
1198    struct sshkey ***keysp, char ***labelsp, int *nkeys)
1199{
1200	struct sshkey		*key = NULL;
1201	CK_OBJECT_CLASS		 key_class;
1202	CK_ATTRIBUTE		 key_attr[2];
1203	CK_SESSION_HANDLE	 session;
1204	CK_FUNCTION_LIST	*f = NULL;
1205	CK_RV			 rv;
1206	CK_OBJECT_HANDLE	 obj;
1207	CK_ULONG		 n = 0;
1208	int			 ret = -1;
1209
1210	memset(&key_attr, 0, sizeof(key_attr));
1211	memset(&obj, 0, sizeof(obj));
1212
1213	key_class = CKO_PUBLIC_KEY;
1214	key_attr[0].type = CKA_CLASS;
1215	key_attr[0].pValue = &key_class;
1216	key_attr[0].ulValueLen = sizeof(key_class);
1217
1218	session = p->slotinfo[slotidx].session;
1219	f = p->function_list;
1220
1221	rv = f->C_FindObjectsInit(session, key_attr, 1);
1222	if (rv != CKR_OK) {
1223		error("C_FindObjectsInit failed: %lu", rv);
1224		goto fail;
1225	}
1226
1227	while (1) {
1228		CK_KEY_TYPE	ck_key_type;
1229		CK_UTF8CHAR	label[256];
1230
1231		rv = f->C_FindObjects(session, &obj, 1, &n);
1232		if (rv != CKR_OK) {
1233			error("C_FindObjects failed: %lu", rv);
1234			goto fail;
1235		}
1236		if (n == 0)
1237			break;
1238
1239		memset(&ck_key_type, 0, sizeof(ck_key_type));
1240		memset(&key_attr, 0, sizeof(key_attr));
1241		key_attr[0].type = CKA_KEY_TYPE;
1242		key_attr[0].pValue = &ck_key_type;
1243		key_attr[0].ulValueLen = sizeof(ck_key_type);
1244		key_attr[1].type = CKA_LABEL;
1245		key_attr[1].pValue = &label;
1246		key_attr[1].ulValueLen = sizeof(label) - 1;
1247
1248		rv = f->C_GetAttributeValue(session, obj, key_attr, 2);
1249		if (rv != CKR_OK) {
1250			error("C_GetAttributeValue failed: %lu", rv);
1251			goto fail;
1252		}
1253
1254		label[key_attr[1].ulValueLen] = '\0';
1255
1256		switch (ck_key_type) {
1257		case CKK_RSA:
1258			key = pkcs11_fetch_rsa_pubkey(p, slotidx, &obj);
1259			break;
1260		case CKK_ECDSA:
1261			key = pkcs11_fetch_ecdsa_pubkey(p, slotidx, &obj);
1262			break;
1263		default:
1264			/* XXX print key type? */
1265			key = NULL;
1266			error("skipping unsupported key type");
1267		}
1268
1269		if (key == NULL) {
1270			error("failed to fetch key");
1271			continue;
1272		}
1273		note_key(p, slotidx, __func__, key);
1274		if (pkcs11_key_included(keysp, nkeys, key)) {
1275			debug2_f("key already included");;
1276			sshkey_free(key);
1277		} else {
1278			/* expand key array and add key */
1279			*keysp = xrecallocarray(*keysp, *nkeys,
1280			    *nkeys + 1, sizeof(struct sshkey *));
1281			(*keysp)[*nkeys] = key;
1282			if (labelsp != NULL) {
1283				*labelsp = xrecallocarray(*labelsp, *nkeys,
1284				    *nkeys + 1, sizeof(char *));
1285				(*labelsp)[*nkeys] = xstrdup((char *)label);
1286			}
1287			*nkeys = *nkeys + 1;
1288			debug("have %d keys", *nkeys);
1289		}
1290	}
1291
1292	ret = 0;
1293fail:
1294	rv = f->C_FindObjectsFinal(session);
1295	if (rv != CKR_OK) {
1296		error("C_FindObjectsFinal failed: %lu", rv);
1297		ret = -1;
1298	}
1299
1300	return (ret);
1301}
1302
1303#ifdef WITH_PKCS11_KEYGEN
1304#define FILL_ATTR(attr, idx, typ, val, len) \
1305	{ (attr[idx]).type=(typ); (attr[idx]).pValue=(val); (attr[idx]).ulValueLen=len; idx++; }
1306
1307static struct sshkey *
1308pkcs11_rsa_generate_private_key(struct pkcs11_provider *p, CK_ULONG slotidx,
1309    char *label, CK_ULONG bits, CK_BYTE keyid, u_int32_t *err)
1310{
1311	struct pkcs11_slotinfo	*si;
1312	char			*plabel = label ? label : "";
1313	int			 npub = 0, npriv = 0;
1314	CK_RV			 rv;
1315	CK_FUNCTION_LIST	*f;
1316	CK_SESSION_HANDLE	 session;
1317	CK_BBOOL		 true_val = CK_TRUE, false_val = CK_FALSE;
1318	CK_OBJECT_HANDLE	 pubKey, privKey;
1319	CK_ATTRIBUTE		 tpub[16], tpriv[16];
1320	CK_MECHANISM		 mech = {
1321	    CKM_RSA_PKCS_KEY_PAIR_GEN, NULL_PTR, 0
1322	};
1323	CK_BYTE			 pubExponent[] = {
1324	    0x01, 0x00, 0x01 /* RSA_F4 in bytes */
1325	};
1326
1327	*err = 0;
1328
1329	FILL_ATTR(tpub, npub, CKA_TOKEN, &true_val, sizeof(true_val));
1330	FILL_ATTR(tpub, npub, CKA_LABEL, plabel, strlen(plabel));
1331	FILL_ATTR(tpub, npub, CKA_ENCRYPT, &false_val, sizeof(false_val));
1332	FILL_ATTR(tpub, npub, CKA_VERIFY, &true_val, sizeof(true_val));
1333	FILL_ATTR(tpub, npub, CKA_VERIFY_RECOVER, &false_val,
1334	    sizeof(false_val));
1335	FILL_ATTR(tpub, npub, CKA_WRAP, &false_val, sizeof(false_val));
1336	FILL_ATTR(tpub, npub, CKA_DERIVE, &false_val, sizeof(false_val));
1337	FILL_ATTR(tpub, npub, CKA_MODULUS_BITS, &bits, sizeof(bits));
1338	FILL_ATTR(tpub, npub, CKA_PUBLIC_EXPONENT, pubExponent,
1339	    sizeof(pubExponent));
1340	FILL_ATTR(tpub, npub, CKA_ID, &keyid, sizeof(keyid));
1341
1342	FILL_ATTR(tpriv, npriv, CKA_TOKEN,  &true_val, sizeof(true_val));
1343	FILL_ATTR(tpriv, npriv, CKA_LABEL,  plabel, strlen(plabel));
1344	FILL_ATTR(tpriv, npriv, CKA_PRIVATE,  &true_val, sizeof(true_val));
1345	FILL_ATTR(tpriv, npriv, CKA_SENSITIVE,  &true_val, sizeof(true_val));
1346	FILL_ATTR(tpriv, npriv, CKA_DECRYPT,  &false_val, sizeof(false_val));
1347	FILL_ATTR(tpriv, npriv, CKA_SIGN,  &true_val, sizeof(true_val));
1348	FILL_ATTR(tpriv, npriv, CKA_SIGN_RECOVER,  &false_val,
1349	    sizeof(false_val));
1350	FILL_ATTR(tpriv, npriv, CKA_UNWRAP,  &false_val, sizeof(false_val));
1351	FILL_ATTR(tpriv, npriv, CKA_DERIVE,  &false_val, sizeof(false_val));
1352	FILL_ATTR(tpriv, npriv, CKA_ID, &keyid, sizeof(keyid));
1353
1354	f = p->function_list;
1355	si = &p->slotinfo[slotidx];
1356	session = si->session;
1357
1358	if ((rv = f->C_GenerateKeyPair(session, &mech, tpub, npub, tpriv, npriv,
1359	    &pubKey, &privKey)) != CKR_OK) {
1360		error_f("key generation failed: error 0x%lx", rv);
1361		*err = rv;
1362		return NULL;
1363	}
1364
1365	return pkcs11_fetch_rsa_pubkey(p, slotidx, &pubKey);
1366}
1367
1368static int
1369pkcs11_decode_hex(const char *hex, unsigned char **dest, size_t *rlen)
1370{
1371	size_t	i, len;
1372	char	ptr[3];
1373
1374	if (dest)
1375		*dest = NULL;
1376	if (rlen)
1377		*rlen = 0;
1378
1379	if ((len = strlen(hex)) % 2)
1380		return -1;
1381	len /= 2;
1382
1383	*dest = xmalloc(len);
1384
1385	ptr[2] = '\0';
1386	for (i = 0; i < len; i++) {
1387		ptr[0] = hex[2 * i];
1388		ptr[1] = hex[(2 * i) + 1];
1389		if (!isxdigit(ptr[0]) || !isxdigit(ptr[1]))
1390			return -1;
1391		(*dest)[i] = (unsigned char)strtoul(ptr, NULL, 16);
1392	}
1393
1394	if (rlen)
1395		*rlen = len;
1396
1397	return 0;
1398}
1399
1400static struct ec_curve_info {
1401	const char	*name;
1402	const char	*oid;
1403	const char	*oid_encoded;
1404	size_t		 size;
1405} ec_curve_infos[] = {
1406	{"prime256v1",	"1.2.840.10045.3.1.7",	"06082A8648CE3D030107", 256},
1407	{"secp384r1",	"1.3.132.0.34",		"06052B81040022",	384},
1408	{"secp521r1",	"1.3.132.0.35",		"06052B81040023",	521},
1409	{NULL,		NULL,			NULL,			0},
1410};
1411
1412static struct sshkey *
1413pkcs11_ecdsa_generate_private_key(struct pkcs11_provider *p, CK_ULONG slotidx,
1414    char *label, CK_ULONG bits, CK_BYTE keyid, u_int32_t *err)
1415{
1416	struct pkcs11_slotinfo	*si;
1417	char			*plabel = label ? label : "";
1418	int			 i;
1419	size_t			 ecparams_size;
1420	unsigned char		*ecparams = NULL;
1421	int			 npub = 0, npriv = 0;
1422	CK_RV			 rv;
1423	CK_FUNCTION_LIST	*f;
1424	CK_SESSION_HANDLE	 session;
1425	CK_BBOOL		 true_val = CK_TRUE, false_val = CK_FALSE;
1426	CK_OBJECT_HANDLE	 pubKey, privKey;
1427	CK_MECHANISM		 mech = {
1428	    CKM_EC_KEY_PAIR_GEN, NULL_PTR, 0
1429	};
1430	CK_ATTRIBUTE		 tpub[16], tpriv[16];
1431
1432	*err = 0;
1433
1434	for (i = 0; ec_curve_infos[i].name; i++) {
1435		if (ec_curve_infos[i].size == bits)
1436			break;
1437	}
1438	if (!ec_curve_infos[i].name) {
1439		error_f("invalid key size %lu", bits);
1440		return NULL;
1441	}
1442	if (pkcs11_decode_hex(ec_curve_infos[i].oid_encoded, &ecparams,
1443	    &ecparams_size) == -1) {
1444		error_f("invalid oid");
1445		return NULL;
1446	}
1447
1448	FILL_ATTR(tpub, npub, CKA_TOKEN, &true_val, sizeof(true_val));
1449	FILL_ATTR(tpub, npub, CKA_LABEL, plabel, strlen(plabel));
1450	FILL_ATTR(tpub, npub, CKA_ENCRYPT, &false_val, sizeof(false_val));
1451	FILL_ATTR(tpub, npub, CKA_VERIFY, &true_val, sizeof(true_val));
1452	FILL_ATTR(tpub, npub, CKA_VERIFY_RECOVER, &false_val,
1453	    sizeof(false_val));
1454	FILL_ATTR(tpub, npub, CKA_WRAP, &false_val, sizeof(false_val));
1455	FILL_ATTR(tpub, npub, CKA_DERIVE, &false_val, sizeof(false_val));
1456	FILL_ATTR(tpub, npub, CKA_EC_PARAMS, ecparams, ecparams_size);
1457	FILL_ATTR(tpub, npub, CKA_ID, &keyid, sizeof(keyid));
1458
1459	FILL_ATTR(tpriv, npriv, CKA_TOKEN, &true_val, sizeof(true_val));
1460	FILL_ATTR(tpriv, npriv, CKA_LABEL, plabel, strlen(plabel));
1461	FILL_ATTR(tpriv, npriv, CKA_PRIVATE, &true_val, sizeof(true_val));
1462	FILL_ATTR(tpriv, npriv, CKA_SENSITIVE, &true_val, sizeof(true_val));
1463	FILL_ATTR(tpriv, npriv, CKA_DECRYPT, &false_val, sizeof(false_val));
1464	FILL_ATTR(tpriv, npriv, CKA_SIGN, &true_val, sizeof(true_val));
1465	FILL_ATTR(tpriv, npriv, CKA_SIGN_RECOVER, &false_val,
1466	    sizeof(false_val));
1467	FILL_ATTR(tpriv, npriv, CKA_UNWRAP, &false_val, sizeof(false_val));
1468	FILL_ATTR(tpriv, npriv, CKA_DERIVE, &false_val, sizeof(false_val));
1469	FILL_ATTR(tpriv, npriv, CKA_ID, &keyid, sizeof(keyid));
1470
1471	f = p->function_list;
1472	si = &p->slotinfo[slotidx];
1473	session = si->session;
1474
1475	if ((rv = f->C_GenerateKeyPair(session, &mech, tpub, npub, tpriv, npriv,
1476	    &pubKey, &privKey)) != CKR_OK) {
1477		error_f("key generation failed: error 0x%lx", rv);
1478		*err = rv;
1479		return NULL;
1480	}
1481
1482	return pkcs11_fetch_ecdsa_pubkey(p, slotidx, &pubKey);
1483}
1484#endif /* WITH_PKCS11_KEYGEN */
1485
1486/*
1487 * register a new provider, fails if provider already exists. if
1488 * keyp is provided, fetch keys.
1489 */
1490static int
1491pkcs11_register_provider(char *provider_id, char *pin,
1492    struct sshkey ***keyp, char ***labelsp,
1493    struct pkcs11_provider **providerp, CK_ULONG user)
1494{
1495	int nkeys, need_finalize = 0;
1496	int ret = -1;
1497	struct pkcs11_provider *p = NULL;
1498	void *handle = NULL;
1499	CK_RV (*getfunctionlist)(CK_FUNCTION_LIST **);
1500	CK_RV rv;
1501	CK_FUNCTION_LIST *f = NULL;
1502	CK_TOKEN_INFO *token;
1503	CK_ULONG i;
1504
1505	if (providerp == NULL)
1506		goto fail;
1507	*providerp = NULL;
1508
1509	if (keyp != NULL)
1510		*keyp = NULL;
1511	if (labelsp != NULL)
1512		*labelsp = NULL;
1513
1514	if (pkcs11_provider_lookup(provider_id) != NULL) {
1515		debug_f("provider already registered: %s", provider_id);
1516		goto fail;
1517	}
1518	if (lib_contains_symbol(provider_id, "C_GetFunctionList") != 0) {
1519		error("provider %s is not a PKCS11 library", provider_id);
1520		goto fail;
1521	}
1522	/* open shared pkcs11-library */
1523	if ((handle = dlopen(provider_id, RTLD_NOW)) == NULL) {
1524		error("dlopen %s failed: %s", provider_id, dlerror());
1525		goto fail;
1526	}
1527	if ((getfunctionlist = dlsym(handle, "C_GetFunctionList")) == NULL)
1528		fatal("dlsym(C_GetFunctionList) failed: %s", dlerror());
1529	p = xcalloc(1, sizeof(*p));
1530	p->name = xstrdup(provider_id);
1531	p->handle = handle;
1532	/* setup the pkcs11 callbacks */
1533	if ((rv = (*getfunctionlist)(&f)) != CKR_OK) {
1534		error("C_GetFunctionList for provider %s failed: %lu",
1535		    provider_id, rv);
1536		goto fail;
1537	}
1538	p->function_list = f;
1539	if ((rv = f->C_Initialize(NULL)) != CKR_OK) {
1540		error("C_Initialize for provider %s failed: %lu",
1541		    provider_id, rv);
1542		goto fail;
1543	}
1544	need_finalize = 1;
1545	if ((rv = f->C_GetInfo(&p->info)) != CKR_OK) {
1546		error("C_GetInfo for provider %s failed: %lu",
1547		    provider_id, rv);
1548		goto fail;
1549	}
1550	debug("provider %s: manufacturerID <%.*s> cryptokiVersion %d.%d"
1551	    " libraryDescription <%.*s> libraryVersion %d.%d",
1552	    provider_id,
1553	    RMSPACE(p->info.manufacturerID),
1554	    p->info.cryptokiVersion.major,
1555	    p->info.cryptokiVersion.minor,
1556	    RMSPACE(p->info.libraryDescription),
1557	    p->info.libraryVersion.major,
1558	    p->info.libraryVersion.minor);
1559	if ((rv = f->C_GetSlotList(CK_TRUE, NULL, &p->nslots)) != CKR_OK) {
1560		error("C_GetSlotList failed: %lu", rv);
1561		goto fail;
1562	}
1563	if (p->nslots == 0) {
1564		debug_f("provider %s returned no slots", provider_id);
1565		ret = -SSH_PKCS11_ERR_NO_SLOTS;
1566		goto fail;
1567	}
1568	p->slotlist = xcalloc(p->nslots, sizeof(CK_SLOT_ID));
1569	if ((rv = f->C_GetSlotList(CK_TRUE, p->slotlist, &p->nslots))
1570	    != CKR_OK) {
1571		error("C_GetSlotList for provider %s failed: %lu",
1572		    provider_id, rv);
1573		goto fail;
1574	}
1575	p->slotinfo = xcalloc(p->nslots, sizeof(struct pkcs11_slotinfo));
1576	p->valid = 1;
1577	nkeys = 0;
1578	for (i = 0; i < p->nslots; i++) {
1579		token = &p->slotinfo[i].token;
1580		if ((rv = f->C_GetTokenInfo(p->slotlist[i], token))
1581		    != CKR_OK) {
1582			error("C_GetTokenInfo for provider %s slot %lu "
1583			    "failed: %lu", provider_id, (u_long)i, rv);
1584			continue;
1585		}
1586		if ((token->flags & CKF_TOKEN_INITIALIZED) == 0) {
1587			debug2_f("ignoring uninitialised token in "
1588			    "provider %s slot %lu", provider_id, (u_long)i);
1589			continue;
1590		}
1591		debug("provider %s slot %lu: label <%.*s> "
1592		    "manufacturerID <%.*s> model <%.*s> serial <%.*s> "
1593		    "flags 0x%lx",
1594		    provider_id, (unsigned long)i,
1595		    RMSPACE(token->label), RMSPACE(token->manufacturerID),
1596		    RMSPACE(token->model), RMSPACE(token->serialNumber),
1597		    token->flags);
1598		/*
1599		 * open session, login with pin and retrieve public
1600		 * keys (if keyp is provided)
1601		 */
1602		if ((ret = pkcs11_open_session(p, i, pin, user)) != 0 ||
1603		    keyp == NULL)
1604			continue;
1605		pkcs11_fetch_keys(p, i, keyp, labelsp, &nkeys);
1606		pkcs11_fetch_certs(p, i, keyp, labelsp, &nkeys);
1607		if (nkeys == 0 && !p->slotinfo[i].logged_in &&
1608		    pkcs11_interactive) {
1609			/*
1610			 * Some tokens require login before they will
1611			 * expose keys.
1612			 */
1613			if (pkcs11_login_slot(p, &p->slotinfo[i],
1614			    CKU_USER) < 0) {
1615				error("login failed");
1616				continue;
1617			}
1618			pkcs11_fetch_keys(p, i, keyp, labelsp, &nkeys);
1619			pkcs11_fetch_certs(p, i, keyp, labelsp, &nkeys);
1620		}
1621	}
1622
1623	/* now owned by caller */
1624	*providerp = p;
1625
1626	TAILQ_INSERT_TAIL(&pkcs11_providers, p, next);
1627	p->refcount++;	/* add to provider list */
1628
1629	return (nkeys);
1630fail:
1631	if (need_finalize && (rv = f->C_Finalize(NULL)) != CKR_OK)
1632		error("C_Finalize for provider %s failed: %lu",
1633		    provider_id, rv);
1634	if (p) {
1635		free(p->name);
1636		free(p->slotlist);
1637		free(p->slotinfo);
1638		free(p);
1639	}
1640	if (handle)
1641		dlclose(handle);
1642	if (ret > 0)
1643		ret = -1;
1644	return (ret);
1645}
1646
1647/*
1648 * register a new provider and get number of keys hold by the token,
1649 * fails if provider already exists
1650 */
1651int
1652pkcs11_add_provider(char *provider_id, char *pin, struct sshkey ***keyp,
1653    char ***labelsp)
1654{
1655	struct pkcs11_provider *p = NULL;
1656	int nkeys;
1657
1658	nkeys = pkcs11_register_provider(provider_id, pin, keyp, labelsp,
1659	    &p, CKU_USER);
1660
1661	/* no keys found or some other error, de-register provider */
1662	if (nkeys <= 0 && p != NULL) {
1663		TAILQ_REMOVE(&pkcs11_providers, p, next);
1664		pkcs11_provider_finalize(p);
1665		pkcs11_provider_unref(p);
1666	}
1667	if (nkeys == 0)
1668		debug_f("provider %s returned no keys", provider_id);
1669
1670	return (nkeys);
1671}
1672
1673#ifdef WITH_PKCS11_KEYGEN
1674struct sshkey *
1675pkcs11_gakp(char *provider_id, char *pin, unsigned int slotidx, char *label,
1676    unsigned int type, unsigned int bits, unsigned char keyid, u_int32_t *err)
1677{
1678	struct pkcs11_provider	*p = NULL;
1679	struct pkcs11_slotinfo	*si;
1680	CK_FUNCTION_LIST	*f;
1681	CK_SESSION_HANDLE	 session;
1682	struct sshkey		*k = NULL;
1683	int			 ret = -1, reset_pin = 0, reset_provider = 0;
1684	CK_RV			 rv;
1685
1686	*err = 0;
1687
1688	if ((p = pkcs11_provider_lookup(provider_id)) != NULL)
1689		debug_f("provider \"%s\" available", provider_id);
1690	else if ((ret = pkcs11_register_provider(provider_id, pin, NULL, NULL,
1691	    &p, CKU_SO)) < 0) {
1692		debug_f("could not register provider %s", provider_id);
1693		goto out;
1694	} else
1695		reset_provider = 1;
1696
1697	f = p->function_list;
1698	si = &p->slotinfo[slotidx];
1699	session = si->session;
1700
1701	if ((rv = f->C_SetOperationState(session , pin, strlen(pin),
1702	    CK_INVALID_HANDLE, CK_INVALID_HANDLE)) != CKR_OK) {
1703		debug_f("could not supply SO pin: %lu", rv);
1704		reset_pin = 0;
1705	} else
1706		reset_pin = 1;
1707
1708	switch (type) {
1709	case KEY_RSA:
1710		if ((k = pkcs11_rsa_generate_private_key(p, slotidx, label,
1711		    bits, keyid, err)) == NULL) {
1712			debug_f("failed to generate RSA key");
1713			goto out;
1714		}
1715		break;
1716	case KEY_ECDSA:
1717		if ((k = pkcs11_ecdsa_generate_private_key(p, slotidx, label,
1718		    bits, keyid, err)) == NULL) {
1719			debug_f("failed to generate ECDSA key");
1720			goto out;
1721		}
1722		break;
1723	default:
1724		*err = SSH_PKCS11_ERR_GENERIC;
1725		debug_f("unknown type %d", type);
1726		goto out;
1727	}
1728
1729out:
1730	if (reset_pin)
1731		f->C_SetOperationState(session , NULL, 0, CK_INVALID_HANDLE,
1732		    CK_INVALID_HANDLE);
1733
1734	if (reset_provider)
1735		pkcs11_del_provider(provider_id);
1736
1737	return (k);
1738}
1739
1740struct sshkey *
1741pkcs11_destroy_keypair(char *provider_id, char *pin, unsigned long slotidx,
1742    unsigned char keyid, u_int32_t *err)
1743{
1744	struct pkcs11_provider	*p = NULL;
1745	struct pkcs11_slotinfo	*si;
1746	struct sshkey		*k = NULL;
1747	int			 reset_pin = 0, reset_provider = 0;
1748	CK_ULONG		 nattrs;
1749	CK_FUNCTION_LIST	*f;
1750	CK_SESSION_HANDLE	 session;
1751	CK_ATTRIBUTE		 attrs[16];
1752	CK_OBJECT_CLASS		 key_class;
1753	CK_KEY_TYPE		 key_type;
1754	CK_OBJECT_HANDLE	 obj = CK_INVALID_HANDLE;
1755	CK_RV			 rv;
1756
1757	*err = 0;
1758
1759	if ((p = pkcs11_provider_lookup(provider_id)) != NULL) {
1760		debug_f("using provider \"%s\"", provider_id);
1761	} else if (pkcs11_register_provider(provider_id, pin, NULL, NULL, &p,
1762	    CKU_SO) < 0) {
1763		debug_f("could not register provider %s",
1764		    provider_id);
1765		goto out;
1766	} else
1767		reset_provider = 1;
1768
1769	f = p->function_list;
1770	si = &p->slotinfo[slotidx];
1771	session = si->session;
1772
1773	if ((rv = f->C_SetOperationState(session , pin, strlen(pin),
1774	    CK_INVALID_HANDLE, CK_INVALID_HANDLE)) != CKR_OK) {
1775		debug_f("could not supply SO pin: %lu", rv);
1776		reset_pin = 0;
1777	} else
1778		reset_pin = 1;
1779
1780	/* private key */
1781	nattrs = 0;
1782	key_class = CKO_PRIVATE_KEY;
1783	FILL_ATTR(attrs, nattrs, CKA_CLASS, &key_class, sizeof(key_class));
1784	FILL_ATTR(attrs, nattrs, CKA_ID, &keyid, sizeof(keyid));
1785
1786	if (pkcs11_find(p, slotidx, attrs, nattrs, &obj) == 0 &&
1787	    obj != CK_INVALID_HANDLE) {
1788		if ((rv = f->C_DestroyObject(session, obj)) != CKR_OK) {
1789			debug_f("could not destroy private key 0x%hhx",
1790			    keyid);
1791			*err = rv;
1792			goto out;
1793		}
1794	}
1795
1796	/* public key */
1797	nattrs = 0;
1798	key_class = CKO_PUBLIC_KEY;
1799	FILL_ATTR(attrs, nattrs, CKA_CLASS, &key_class, sizeof(key_class));
1800	FILL_ATTR(attrs, nattrs, CKA_ID, &keyid, sizeof(keyid));
1801
1802	if (pkcs11_find(p, slotidx, attrs, nattrs, &obj) == 0 &&
1803	    obj != CK_INVALID_HANDLE) {
1804
1805		/* get key type */
1806		nattrs = 0;
1807		FILL_ATTR(attrs, nattrs, CKA_KEY_TYPE, &key_type,
1808		    sizeof(key_type));
1809		rv = f->C_GetAttributeValue(session, obj, attrs, nattrs);
1810		if (rv != CKR_OK) {
1811			debug_f("could not get key type of public key 0x%hhx",
1812			    keyid);
1813			*err = rv;
1814			key_type = -1;
1815		}
1816		if (key_type == CKK_RSA)
1817			k = pkcs11_fetch_rsa_pubkey(p, slotidx, &obj);
1818		else if (key_type == CKK_ECDSA)
1819			k = pkcs11_fetch_ecdsa_pubkey(p, slotidx, &obj);
1820
1821		if ((rv = f->C_DestroyObject(session, obj)) != CKR_OK) {
1822			debug_f("could not destroy public key 0x%hhx", keyid);
1823			*err = rv;
1824			goto out;
1825		}
1826	}
1827
1828out:
1829	if (reset_pin)
1830		f->C_SetOperationState(session , NULL, 0, CK_INVALID_HANDLE,
1831		    CK_INVALID_HANDLE);
1832
1833	if (reset_provider)
1834		pkcs11_del_provider(provider_id);
1835
1836	return (k);
1837}
1838#endif /* WITH_PKCS11_KEYGEN */
1839#else
1840int
1841pkcs11_add_provider(char *provider_id, char *pin, struct sshkey ***keyp,
1842    char ***labelsp)
1843{
1844	error("dlopen() not supported");
1845	return (-1);
1846}
1847#endif /* HAVE_DLOPEN */
1848