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