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