Home | History | Annotate | Line # | Download | only in dist
      1 /*	$NetBSD: ssh-pkcs11.c,v 1.31 2026/04/08 18:58:41 christos Exp $	*/
      2 /* $OpenBSD: ssh-pkcs11.c,v 1.78 2026/03/03 09:57:25 dtucker Exp $ */
      3 
      4 /*
      5  * Copyright (c) 2010 Markus Friedl.  All rights reserved.
      6  * Copyright (c) 2014 Pedro Martelletto. All rights reserved.
      7  *
      8  * Permission to use, copy, modify, and distribute this software for any
      9  * purpose with or without fee is hereby granted, provided that the above
     10  * copyright notice and this permission notice appear in all copies.
     11  *
     12  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
     13  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
     14  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
     15  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     16  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
     17  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
     18  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     19  */
     20 #include "includes.h"
     21 __RCSID("$NetBSD: ssh-pkcs11.c,v 1.31 2026/04/08 18:58:41 christos Exp $");
     22 
     23 #include <sys/types.h>
     24 #include <sys/queue.h>
     25 #include <sys/time.h>
     26 #include <stdarg.h>
     27 #include <stdio.h>
     28 
     29 #include <string.h>
     30 #include <dlfcn.h>
     31 
     32 #ifdef WITH_OPENSSL
     33 #include <openssl/bn.h>
     34 #include <openssl/ecdsa.h>
     35 #include <openssl/x509.h>
     36 #include <openssl/err.h>
     37 #endif
     38 
     39 #define CRYPTOKI_COMPAT
     40 #include "pkcs11.h"
     41 
     42 #define SSHKEY_INTERNAL
     43 #include "sshkey.h"
     44 
     45 #include "log.h"
     46 #include "misc.h"
     47 #include "sshbuf.h"
     48 #include "ssh-pkcs11.h"
     49 #include "digest.h"
     50 #include "xmalloc.h"
     51 #include "crypto_api.h"
     52 
     53 struct pkcs11_slotinfo {
     54 	CK_TOKEN_INFO		token;
     55 	CK_SESSION_HANDLE	session;
     56 	int			logged_in;
     57 };
     58 
     59 struct pkcs11_provider {
     60 	char			*name;
     61 	void			*handle;
     62 	CK_FUNCTION_LIST	*function_list;
     63 	CK_INFO			info;
     64 	CK_ULONG		nslots;
     65 	CK_SLOT_ID		*slotlist;
     66 	struct pkcs11_slotinfo	*slotinfo;
     67 	int			valid;
     68 	int			refcount;
     69 	TAILQ_ENTRY(pkcs11_provider) next;
     70 };
     71 
     72 TAILQ_HEAD(, pkcs11_provider) pkcs11_providers;
     73 
     74 struct pkcs11_key {
     75 	struct sshbuf		*keyblob;
     76 	struct pkcs11_provider	*provider;
     77 	CK_ULONG		slotidx;
     78 	char			*keyid;
     79 	int			keyid_len;
     80 	TAILQ_ENTRY(pkcs11_key)	next;
     81 };
     82 
     83 TAILQ_HEAD(, pkcs11_key) pkcs11_keys; /* XXX a tree would be better */
     84 
     85 int pkcs11_interactive = 0;
     86 
     87 #ifdef WITH_OPENSSL
     88 static void
     89 ossl_error(const char *msg)
     90 {
     91 	unsigned long    e;
     92 
     93 	error_f("%s", msg);
     94 	while ((e = ERR_get_error()) != 0)
     95 		error_f("libcrypto error: %s", ERR_error_string(e, NULL));
     96 }
     97 #endif
     98 
     99 /*
    100  * finalize a provider shared library, it's no longer usable.
    101  * however, there might still be keys referencing this provider,
    102  * so the actual freeing of memory is handled by pkcs11_provider_unref().
    103  * this is called when a provider gets unregistered.
    104  */
    105 static void
    106 pkcs11_provider_finalize(struct pkcs11_provider *p)
    107 {
    108 	CK_RV rv;
    109 	CK_ULONG i;
    110 
    111 	debug_f("provider \"%s\" refcount %d valid %d",
    112 	    p->name, p->refcount, p->valid);
    113 	if (!p->valid)
    114 		return;
    115 	for (i = 0; i < p->nslots; i++) {
    116 		if (p->slotinfo[i].session &&
    117 		    (rv = p->function_list->C_CloseSession(
    118 		    p->slotinfo[i].session)) != CKR_OK)
    119 			error("C_CloseSession failed: %lu", rv);
    120 	}
    121 	if ((rv = p->function_list->C_Finalize(NULL)) != CKR_OK)
    122 		error("C_Finalize failed: %lu", rv);
    123 	p->valid = 0;
    124 	p->function_list = NULL;
    125 #ifdef HAVE_DLOPEN
    126 	dlclose(p->handle);
    127 #endif
    128 }
    129 
    130 /*
    131  * remove a reference to the provider.
    132  * called when a key gets destroyed or when the provider is unregistered.
    133  */
    134 static void
    135 pkcs11_provider_unref(struct pkcs11_provider *p)
    136 {
    137 	debug_f("provider \"%s\" refcount %d", p->name, p->refcount);
    138 	if (--p->refcount <= 0) {
    139 		if (p->valid)
    140 			error_f("provider \"%s\" still valid", p->name);
    141 		free(p->name);
    142 		free(p->slotlist);
    143 		free(p->slotinfo);
    144 		free(p);
    145 	}
    146 }
    147 
    148 /* lookup provider by name */
    149 static struct pkcs11_provider *
    150 pkcs11_provider_lookup(char *provider_id)
    151 {
    152 	struct pkcs11_provider *p;
    153 
    154 	TAILQ_FOREACH(p, &pkcs11_providers, next) {
    155 		debug("check provider \"%s\"", p->name);
    156 		if (!strcmp(provider_id, p->name))
    157 			return (p);
    158 	}
    159 	return (NULL);
    160 }
    161 
    162 /* unregister provider by name */
    163 int
    164 pkcs11_del_provider(char *provider_id)
    165 {
    166 	struct pkcs11_provider *p;
    167 
    168 	if ((p = pkcs11_provider_lookup(provider_id)) != NULL) {
    169 		TAILQ_REMOVE(&pkcs11_providers, p, next);
    170 		pkcs11_provider_finalize(p);
    171 		pkcs11_provider_unref(p);
    172 		return (0);
    173 	}
    174 	return (-1);
    175 }
    176 
    177 #ifdef HAVE_DLOPEN
    178 
    179 /* release a wrapped object */
    180 static void
    181 pkcs11_k11_free(struct pkcs11_key *k11)
    182 {
    183 	if (k11 == NULL)
    184 		return;
    185 	if (k11->provider)
    186 		pkcs11_provider_unref(k11->provider);
    187 	free(k11->keyid);
    188 	sshbuf_free(k11->keyblob);
    189 	free(k11);
    190 }
    191 
    192 /* find a single 'obj' for given attributes */
    193 static int
    194 pkcs11_find(struct pkcs11_provider *p, CK_ULONG slotidx, CK_ATTRIBUTE *attr,
    195     CK_ULONG nattr, CK_OBJECT_HANDLE *obj)
    196 {
    197 	CK_FUNCTION_LIST	*f;
    198 	CK_SESSION_HANDLE	session;
    199 	CK_ULONG		nfound = 0;
    200 	CK_RV			rv;
    201 	int			ret = -1;
    202 
    203 	f = p->function_list;
    204 	session = p->slotinfo[slotidx].session;
    205 	if ((rv = f->C_FindObjectsInit(session, attr, nattr)) != CKR_OK) {
    206 		error("C_FindObjectsInit failed (nattr %lu): %lu", nattr, rv);
    207 		return (-1);
    208 	}
    209 	if ((rv = f->C_FindObjects(session, obj, 1, &nfound)) != CKR_OK ||
    210 	    nfound != 1) {
    211 		debug("C_FindObjects failed (nfound %lu nattr %lu): %lu",
    212 		    nfound, nattr, rv);
    213 	} else
    214 		ret = 0;
    215 	if ((rv = f->C_FindObjectsFinal(session)) != CKR_OK)
    216 		error("C_FindObjectsFinal failed: %lu", rv);
    217 	return (ret);
    218 }
    219 
    220 static int
    221 pkcs11_login_slot(struct pkcs11_provider *provider, struct pkcs11_slotinfo *si,
    222     CK_USER_TYPE type)
    223 {
    224 	char			*pin = NULL, prompt[1024];
    225 	CK_RV			 rv;
    226 
    227 	if (provider == NULL || si == NULL || !provider->valid) {
    228 		error("no pkcs11 (valid) provider found");
    229 		return (-1);
    230 	}
    231 
    232 	if (!pkcs11_interactive) {
    233 		error("need pin entry%s",
    234 		    (si->token.flags & CKF_PROTECTED_AUTHENTICATION_PATH) ?
    235 		    " on reader keypad" : "");
    236 		return (-1);
    237 	}
    238 	if (si->token.flags & CKF_PROTECTED_AUTHENTICATION_PATH)
    239 		verbose("Deferring PIN entry to reader keypad.");
    240 	else {
    241 		snprintf(prompt, sizeof(prompt), "Enter PIN for '%s': ",
    242 		    si->token.label);
    243 		if ((pin = read_passphrase(prompt, RP_ALLOW_EOF)) == NULL) {
    244 			debug_f("no pin specified");
    245 			return (-1);	/* bail out */
    246 		}
    247 	}
    248 	rv = provider->function_list->C_Login(si->session, type, (u_char *)pin,
    249 	    (pin != NULL) ? strlen(pin) : 0);
    250 	if (pin != NULL)
    251 		freezero(pin, strlen(pin));
    252 
    253 	switch (rv) {
    254 	case CKR_OK:
    255 	case CKR_USER_ALREADY_LOGGED_IN:
    256 		/* success */
    257 		break;
    258 	case CKR_PIN_LEN_RANGE:
    259 		error("PKCS#11 login failed: PIN length out of range");
    260 		return -1;
    261 	case CKR_PIN_INCORRECT:
    262 		error("PKCS#11 login failed: PIN incorrect");
    263 		return -1;
    264 	case CKR_PIN_LOCKED:
    265 		error("PKCS#11 login failed: PIN locked");
    266 		return -1;
    267 	default:
    268 		error("PKCS#11 login failed: error %lu", rv);
    269 		return -1;
    270 	}
    271 	si->logged_in = 1;
    272 	return (0);
    273 }
    274 
    275 static int
    276 pkcs11_login(struct pkcs11_key *k11, CK_USER_TYPE type)
    277 {
    278 	if (k11 == NULL || k11->provider == NULL || !k11->provider->valid) {
    279 		error("no pkcs11 (valid) provider found");
    280 		return (-1);
    281 	}
    282 
    283 	return pkcs11_login_slot(k11->provider,
    284 	    &k11->provider->slotinfo[k11->slotidx], type);
    285 }
    286 
    287 
    288 static int
    289 pkcs11_check_obj_bool_attrib(struct pkcs11_key *k11, CK_OBJECT_HANDLE obj,
    290     CK_ATTRIBUTE_TYPE type, int *val)
    291 {
    292 	struct pkcs11_slotinfo	*si;
    293 	CK_FUNCTION_LIST	*f;
    294 	CK_BBOOL		flag = 0;
    295 	CK_ATTRIBUTE		attr;
    296 	CK_RV			 rv;
    297 
    298 	*val = 0;
    299 
    300 	if (!k11->provider || !k11->provider->valid) {
    301 		error("no pkcs11 (valid) provider found");
    302 		return (-1);
    303 	}
    304 
    305 	f = k11->provider->function_list;
    306 	si = &k11->provider->slotinfo[k11->slotidx];
    307 
    308 	attr.type = type;
    309 	attr.pValue = &flag;
    310 	attr.ulValueLen = sizeof(flag);
    311 
    312 	rv = f->C_GetAttributeValue(si->session, obj, &attr, 1);
    313 	if (rv != CKR_OK) {
    314 		error("C_GetAttributeValue failed: %lu", rv);
    315 		return (-1);
    316 	}
    317 	*val = flag != 0;
    318 	debug_f("provider \"%s\" slot %lu object %lu: attrib %lu = %d",
    319 	    k11->provider->name, k11->slotidx, obj, type, *val);
    320 	return (0);
    321 }
    322 
    323 static int
    324 pkcs11_get_key(struct pkcs11_key *k11, CK_MECHANISM_TYPE mech_type)
    325 {
    326 	struct pkcs11_slotinfo	*si;
    327 	CK_FUNCTION_LIST	*f;
    328 	CK_OBJECT_HANDLE	 obj;
    329 	CK_RV			 rv;
    330 	CK_OBJECT_CLASS		 private_key_class;
    331 	CK_BBOOL		 true_val;
    332 	CK_MECHANISM		 mech;
    333 	CK_ATTRIBUTE		 key_filter[3];
    334 	int			 always_auth = 0;
    335 	int			 did_login = 0;
    336 
    337 	if (!k11->provider || !k11->provider->valid) {
    338 		error("no pkcs11 (valid) provider found");
    339 		return (-1);
    340 	}
    341 
    342 	f = k11->provider->function_list;
    343 	si = &k11->provider->slotinfo[k11->slotidx];
    344 
    345 	if ((si->token.flags & CKF_LOGIN_REQUIRED) && !si->logged_in) {
    346 		if (pkcs11_login(k11, CKU_USER) < 0) {
    347 			error("login failed");
    348 			return (-1);
    349 		}
    350 		did_login = 1;
    351 	}
    352 
    353 	memset(&key_filter, 0, sizeof(key_filter));
    354 	private_key_class = CKO_PRIVATE_KEY;
    355 	key_filter[0].type = CKA_CLASS;
    356 	key_filter[0].pValue = &private_key_class;
    357 	key_filter[0].ulValueLen = sizeof(private_key_class);
    358 
    359 	key_filter[1].type = CKA_ID;
    360 	key_filter[1].pValue = k11->keyid;
    361 	key_filter[1].ulValueLen = k11->keyid_len;
    362 
    363 	true_val = CK_TRUE;
    364 	key_filter[2].type = CKA_SIGN;
    365 	key_filter[2].pValue = &true_val;
    366 	key_filter[2].ulValueLen = sizeof(true_val);
    367 
    368 	/* try to find object w/CKA_SIGN first, retry w/o */
    369 	if (pkcs11_find(k11->provider, k11->slotidx, key_filter, 3, &obj) < 0 &&
    370 	    pkcs11_find(k11->provider, k11->slotidx, key_filter, 2, &obj) < 0) {
    371 		error("cannot find private key");
    372 		return (-1);
    373 	}
    374 
    375 	memset(&mech, 0, sizeof(mech));
    376 	mech.mechanism = mech_type;
    377 	mech.pParameter = NULL_PTR;
    378 	mech.ulParameterLen = 0;
    379 
    380 	if ((rv = f->C_SignInit(si->session, &mech, obj)) != CKR_OK) {
    381 		error("C_SignInit failed: %lu", rv);
    382 		return (-1);
    383 	}
    384 
    385 	pkcs11_check_obj_bool_attrib(k11, obj, CKA_ALWAYS_AUTHENTICATE,
    386 	    &always_auth); /* ignore errors here */
    387 	if (always_auth && !did_login) {
    388 		debug_f("always-auth key");
    389 		if (pkcs11_login(k11, CKU_CONTEXT_SPECIFIC) < 0) {
    390 			error("login failed for always-auth key");
    391 			return (-1);
    392 		}
    393 	}
    394 
    395 	return (0);
    396 }
    397 
    398 /* record the key information later use lookup by keyblob */
    399 static int
    400 pkcs11_record_key(struct pkcs11_provider *provider, CK_ULONG slotidx,
    401     CK_ATTRIBUTE *keyid_attrib, struct sshkey *key)
    402 {
    403 	struct sshbuf *keyblob;
    404 	struct pkcs11_key *k11;
    405 	int r;
    406 	char *hex;
    407 
    408 	hex = tohex(keyid_attrib->pValue, keyid_attrib->ulValueLen);
    409 	debug_f("%s key: provider %s slot %lu keyid %s",
    410 	    sshkey_type(key), provider->name, (u_long)slotidx, hex);
    411 	free(hex);
    412 
    413 	if ((keyblob = sshbuf_new()) == NULL)
    414 		fatal_f("sshbuf_new failed");
    415 	if ((r = sshkey_putb(key, keyblob)) != 0)
    416 		fatal_fr(r, "sshkey_putb");
    417 
    418 	/* Check if we've already recorded this key in a different slot */
    419 	TAILQ_FOREACH(k11, &pkcs11_keys, next) {
    420 		if (sshbuf_equals(k11->keyblob, keyblob) == 0) {
    421 			hex = tohex(k11->keyid, k11->keyid_len);
    422 			debug_f("Already seen this key at "
    423 			    "provider %s slot %lu keyid %s",
    424 			    k11->provider->name, k11->slotidx, hex);
    425 			free(hex);
    426 			sshbuf_free(keyblob);
    427 			return -1;
    428 		}
    429 	}
    430 
    431 	k11 = xcalloc(1, sizeof(*k11));
    432 	k11->provider = provider;
    433 	k11->keyblob = keyblob;
    434 	provider->refcount++;	/* provider referenced by RSA key */
    435 	k11->slotidx = slotidx;
    436 	/* identify key object on smartcard */
    437 	k11->keyid_len = keyid_attrib->ulValueLen;
    438 	if (k11->keyid_len > 0) {
    439 		k11->keyid = xmalloc(k11->keyid_len);
    440 		memcpy(k11->keyid, keyid_attrib->pValue, k11->keyid_len);
    441 	}
    442 	TAILQ_INSERT_TAIL(&pkcs11_keys, k11, next);
    443 
    444 	return 0;
    445 }
    446 
    447 /* retrieve the key information by keyblob */
    448 static struct pkcs11_key *
    449 pkcs11_lookup_key(struct sshkey *key)
    450 {
    451 	struct pkcs11_key *k11, *found = NULL;
    452 	struct sshbuf *keyblob;
    453 	int r;
    454 
    455 	if ((keyblob = sshbuf_new()) == NULL)
    456 		fatal_f("sshbuf_new failed");
    457 	if ((r = sshkey_putb(key, keyblob)) != 0)
    458 		fatal_fr(r, "sshkey_putb");
    459 	TAILQ_FOREACH(k11, &pkcs11_keys, next) {
    460 		if (sshbuf_equals(k11->keyblob, keyblob) == 0) {
    461 			found = k11;
    462 			break;
    463 		}
    464 	}
    465 	sshbuf_free(keyblob);
    466 	return found;
    467 }
    468 
    469 #ifdef WITH_OPENSSL
    470 /*
    471  * See:
    472  * https://datatracker.ietf.org/doc/html/rfc8017#section-9.2
    473  */
    474 
    475 /*
    476  * id-sha1 OBJECT IDENTIFIER ::= { iso(1) identified-organization(3)
    477  *	oiw(14) secsig(3) algorithms(2) 26 }
    478  */
    479 static const u_char id_sha1[] = {
    480 	0x30, 0x21, /* type Sequence, length 0x21 (33) */
    481 	0x30, 0x09, /* type Sequence, length 0x09 */
    482 	0x06, 0x05, /* type OID, length 0x05 */
    483 	0x2b, 0x0e, 0x03, 0x02, 0x1a, /* id-sha1 OID */
    484 	0x05, 0x00, /* NULL */
    485 	0x04, 0x14  /* Octet string, length 0x14 (20), followed by sha1 hash */
    486 };
    487 
    488 /*
    489  * id-sha256 OBJECT IDENTIFIER ::= { joint-iso-itu-t(2) country(16) us(840)
    490  *      organization(1) gov(101) csor(3) nistAlgorithm(4) hashAlgs(2)
    491  *      id-sha256(1) }
    492  */
    493 static const u_char id_sha256[] = {
    494 	0x30, 0x31, /* type Sequence, length 0x31 (49) */
    495 	0x30, 0x0d, /* type Sequence, length 0x0d (13) */
    496 	0x06, 0x09, /* type OID, length 0x09 */
    497 	0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, /* id-sha256 */
    498 	0x05, 0x00, /* NULL */
    499 	0x04, 0x20  /* Octet string, length 0x20 (32), followed by sha256 hash */
    500 };
    501 
    502 /*
    503  * id-sha512 OBJECT IDENTIFIER ::= { joint-iso-itu-t(2) country(16) us(840)
    504  *      organization(1) gov(101) csor(3) nistAlgorithm(4) hashAlgs(2)
    505  *      id-sha256(3) }
    506  */
    507 static const u_char id_sha512[] = {
    508 	0x30, 0x51, /* type Sequence, length 0x51 (81) */
    509 	0x30, 0x0d, /* type Sequence, length 0x0d (13) */
    510 	0x06, 0x09, /* type OID, length 0x09 */
    511 	0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, /* id-sha512 */
    512 	0x05, 0x00, /* NULL */
    513 	0x04, 0x40  /* Octet string, length 0x40 (64), followed by sha512 hash */
    514 };
    515 
    516 static int
    517 rsa_hash_alg_oid(int hash_alg, const u_char **oidp, size_t *oidlenp)
    518 {
    519 	switch (hash_alg) {
    520 	case SSH_DIGEST_SHA1:
    521 		*oidp = id_sha1;
    522 		*oidlenp = sizeof(id_sha1);
    523 		break;
    524 	case SSH_DIGEST_SHA256:
    525 		*oidp = id_sha256;
    526 		*oidlenp = sizeof(id_sha256);
    527 		break;
    528 	case SSH_DIGEST_SHA512:
    529 		*oidp = id_sha512;
    530 		*oidlenp = sizeof(id_sha512);
    531 		break;
    532 	default:
    533 		return SSH_ERR_INVALID_ARGUMENT;
    534 	}
    535 	return 0;
    536 }
    537 
    538 static int
    539 pkcs11_sign_rsa(struct sshkey *key,
    540     u_char **sigp, size_t *lenp,
    541     const u_char *data, size_t datalen,
    542     const char *alg, const char *sk_provider,
    543     const char *sk_pin, u_int compat)
    544 {
    545 	struct pkcs11_key	*k11;
    546 	struct pkcs11_slotinfo	*si;
    547 	CK_FUNCTION_LIST	*f;
    548 	CK_ULONG		slen = 0;
    549 	CK_RV			rv;
    550 	int			hashalg, r, diff, siglen, ret = -1;
    551 	u_char			*oid_dgst = NULL, *sig = NULL;
    552 	size_t			dgst_len, oid_len, oid_dgst_len = 0;
    553 	const u_char		*oid;
    554 
    555 	if (sigp != NULL)
    556 		*sigp = NULL;
    557 	if (lenp != NULL)
    558 		*lenp = 0;
    559 
    560 	if ((k11 = pkcs11_lookup_key(key)) == NULL) {
    561 		error_f("no key found");
    562 		return SSH_ERR_KEY_NOT_FOUND;
    563 	}
    564 
    565 	debug3_f("sign with alg \"%s\" using provider %s slotidx %lu",
    566 	    alg == NULL ? "" : alg, k11->provider->name, (u_long)k11->slotidx);
    567 
    568 	if (pkcs11_get_key(k11, CKM_RSA_PKCS) == -1) {
    569 		error("pkcs11_get_key failed");
    570 		return SSH_ERR_AGENT_FAILURE;
    571 	}
    572 
    573 	f = k11->provider->function_list;
    574 	si = &k11->provider->slotinfo[k11->slotidx];
    575 
    576 	if ((siglen = EVP_PKEY_size(key->pkey)) <= 0)
    577 		return SSH_ERR_INVALID_ARGUMENT;
    578 	sig = xmalloc(siglen);
    579 	slen = (CK_ULONG)siglen;
    580 
    581 	/* Determine hash algorithm and OID for signature */
    582 	if (alg == NULL || *alg == '\0')
    583 		hashalg = SSH_DIGEST_SHA1;
    584 	else if ((hashalg = ssh_rsa_hash_id_from_keyname(alg)) == -1)
    585 		fatal_f("couldn't determine RSA hash alg \"%s\"", alg);
    586 	if ((r = rsa_hash_alg_oid(hashalg, &oid, &oid_len)) != 0)
    587 		fatal_fr(r, "rsa_hash_alg_oid failed");
    588 	if ((dgst_len = ssh_digest_bytes(hashalg)) == 0)
    589 		fatal_f("bad hash alg %d", hashalg);
    590 
    591 	/* Prepare { oid || digest } */
    592 	oid_dgst_len = oid_len + dgst_len;
    593 	oid_dgst = xcalloc(1, oid_dgst_len);
    594 	memcpy(oid_dgst, oid, oid_len);
    595 	if ((r = ssh_digest_memory(hashalg, data, datalen,
    596 	    oid_dgst + oid_len, dgst_len)) == -1)
    597 		fatal_fr(r, "hash failed");
    598 
    599 	/* XXX handle CKR_BUFFER_TOO_SMALL */
    600 	if ((rv = f->C_Sign(si->session, (CK_BYTE *)oid_dgst,
    601 	    oid_dgst_len, sig, &slen)) != CKR_OK) {
    602 		error("C_Sign failed: %lu", rv);
    603 		goto done;
    604 	}
    605 
    606 	if (slen < (CK_ULONG)siglen) {
    607 		diff = siglen - slen;
    608 		debug3_f("repack %lu < %d (diff %d)",
    609 		    (u_long)slen, siglen, diff);
    610 		memmove(sig + diff, sig, slen);
    611 		explicit_bzero(sig, diff);
    612 	} else if (slen > (size_t)siglen)
    613 		fatal_f("bad C_Sign length");
    614 
    615 	if ((ret = ssh_rsa_encode_store_sig(hashalg, sig, siglen,
    616 	    sigp, lenp)) != 0)
    617 		fatal_fr(ret, "couldn't store signature");
    618 
    619 	/* success */
    620 	ret = 0;
    621  done:
    622 	freezero(oid_dgst, oid_dgst_len);
    623 	free(sig);
    624 	return ret;
    625 }
    626 
    627 static int
    628 pkcs11_sign_ecdsa(struct sshkey *key,
    629     u_char **sigp, size_t *lenp,
    630     const u_char *data, size_t datalen,
    631     const char *alg, const char *sk_provider,
    632     const char *sk_pin, u_int compat)
    633 {
    634 	struct pkcs11_key	*k11;
    635 	struct pkcs11_slotinfo	*si;
    636 	CK_FUNCTION_LIST	*f;
    637 	CK_ULONG		slen = 0, bnlen;
    638 	CK_RV			rv;
    639 	BIGNUM			*sig_r = NULL, *sig_s = NULL;
    640 	u_char			*sig = NULL, *dgst = NULL;
    641 	size_t			dgst_len = 0;
    642 	int			hashalg, ret = -1, r, siglen;
    643 
    644 	if (sigp != NULL)
    645 		*sigp = NULL;
    646 	if (lenp != NULL)
    647 		*lenp = 0;
    648 
    649 	if ((k11 = pkcs11_lookup_key(key)) == NULL) {
    650 		error_f("no key found");
    651 		return SSH_ERR_KEY_NOT_FOUND;
    652 	}
    653 
    654 	if (pkcs11_get_key(k11, CKM_ECDSA) == -1) {
    655 		error("pkcs11_get_key failed");
    656 		return SSH_ERR_AGENT_FAILURE;
    657 	}
    658 
    659 	debug3_f("sign using provider %s slotidx %lu",
    660 	    k11->provider->name, (u_long)k11->slotidx);
    661 
    662 	f = k11->provider->function_list;
    663 	si = &k11->provider->slotinfo[k11->slotidx];
    664 
    665 	/* Prepare digest to be signed */
    666 	if ((hashalg = sshkey_ec_nid_to_hash_alg(key->ecdsa_nid)) == -1)
    667 		fatal_f("couldn't determine ECDSA hash alg");
    668 	if ((dgst_len = ssh_digest_bytes(hashalg)) == 0)
    669 		fatal_f("bad hash alg %d", hashalg);
    670 	dgst = xcalloc(1, dgst_len);
    671 	if ((r = ssh_digest_memory(hashalg, data, datalen,
    672 	    dgst, dgst_len)) == -1)
    673 		fatal_fr(r, "hash failed");
    674 
    675 	if ((siglen = EVP_PKEY_size(key->pkey)) <= 0)
    676 		return SSH_ERR_INVALID_ARGUMENT;
    677 	sig = xmalloc(siglen);
    678 	slen = (CK_ULONG)siglen;
    679 
    680 	/* XXX handle CKR_BUFFER_TOO_SMALL */
    681 	rv = f->C_Sign(si->session, __UNCONST(dgst), dgst_len, sig, &slen);
    682 	if (rv != CKR_OK) {
    683 		error("C_Sign failed: %lu", rv);
    684 		goto done;
    685 	}
    686 	if (slen < 64 || slen > 132 || slen % 2) {
    687 		error_f("bad signature length: %lu", (u_long)slen);
    688 		goto done;
    689 	}
    690 	bnlen = slen/2;
    691 	if ((sig_r = BN_bin2bn(sig, bnlen, NULL)) == NULL ||
    692 	    (sig_s = BN_bin2bn(sig+bnlen, bnlen, NULL)) == NULL) {
    693 		ossl_error("BN_bin2bn failed");
    694 		goto done;
    695 	}
    696 
    697 	if ((ret = ssh_ecdsa_encode_store_sig(key, sig_r, sig_s,
    698 	    sigp, lenp)) != 0)
    699 		fatal_fr(ret, "couldn't store signature");
    700 
    701 	/* success */
    702 	ret = 0;
    703  done:
    704 	freezero(dgst, dgst_len);
    705 	BN_free(sig_r);
    706 	BN_free(sig_s);
    707 	free(sig);
    708 	return ret;
    709 }
    710 #endif /* WITH_OPENSSL */
    711 
    712 static int
    713 pkcs11_sign_ed25519(struct sshkey *key,
    714     u_char **sigp, size_t *lenp,
    715     const u_char *data, size_t datalen,
    716     const char *alg, const char *sk_provider,
    717     const char *sk_pin, u_int compat)
    718 {
    719 	struct pkcs11_key	*k11;
    720 	struct pkcs11_slotinfo	*si;
    721 	CK_FUNCTION_LIST	*f;
    722 	CK_ULONG		slen = 0;
    723 	CK_RV			rv;
    724 	u_char			*sig = NULL;
    725 	CK_BYTE			*xdata = NULL;
    726 	int			ret = -1;
    727 
    728 	if (sigp != NULL)
    729 		*sigp = NULL;
    730 	if (lenp != NULL)
    731 		*lenp = 0;
    732 
    733 	if ((k11 = pkcs11_lookup_key(key)) == NULL) {
    734 		error_f("no key found");
    735 		return SSH_ERR_KEY_NOT_FOUND;
    736 	}
    737 
    738 	if (pkcs11_get_key(k11, CKM_EDDSA) == -1) {
    739 		error("pkcs11_get_key failed");
    740 		return SSH_ERR_AGENT_FAILURE;
    741 	}
    742 
    743 	debug3_f("sign using provider %s slotidx %lu",
    744 	    k11->provider->name, (u_long)k11->slotidx);
    745 
    746 	f = k11->provider->function_list;
    747 	si = &k11->provider->slotinfo[k11->slotidx];
    748 
    749 	xdata = xmalloc(datalen);
    750 	memcpy(xdata, data, datalen);
    751 	sig = xmalloc(crypto_sign_ed25519_BYTES);
    752 	slen = crypto_sign_ed25519_BYTES;
    753 
    754 	rv = f->C_Sign(si->session, xdata, datalen, sig, &slen);
    755 	if (rv != CKR_OK) {
    756 		error("C_Sign failed: %lu", rv);
    757 		goto done;
    758 	}
    759 	if (slen != crypto_sign_ed25519_BYTES) {
    760 		error_f("bad signature length: %lu", (u_long)slen);
    761 		goto done;
    762 	}
    763 	if ((ret = ssh_ed25519_encode_store_sig(sig, slen, sigp, lenp)) != 0)
    764 		fatal_fr(ret, "couldn't store signature");
    765 
    766 	/* success */
    767 	ret = 0;
    768  done:
    769 	if (xdata != NULL)
    770 		freezero(xdata, datalen);
    771 	free(sig);
    772 	return ret;
    773 }
    774 
    775 /* remove trailing spaces */
    776 static char *
    777 rmspace(u_char *buf, size_t len)
    778 {
    779 	size_t i;
    780 
    781 	if (len == 0)
    782 		return buf;
    783 	for (i = len - 1; i > 0; i--)
    784 		if (buf[i] == ' ')
    785 			buf[i] = '\0';
    786 		else
    787 			break;
    788 	return buf;
    789 }
    790 /* Used to printf fixed-width, space-padded, unterminated strings using %.*s */
    791 #define RMSPACE(s) (int)sizeof(s), rmspace(s, sizeof(s))
    792 
    793 /*
    794  * open a pkcs11 session and login if required.
    795  * if pin == NULL we delay login until key use
    796  */
    797 static int
    798 pkcs11_open_session(struct pkcs11_provider *p, CK_ULONG slotidx, char *pin,
    799     CK_ULONG user)
    800 {
    801 	struct pkcs11_slotinfo	*si;
    802 	CK_FUNCTION_LIST	*f;
    803 	CK_RV			rv;
    804 	CK_SESSION_HANDLE	session;
    805 	int			login_required, ret;
    806 
    807 	f = p->function_list;
    808 	si = &p->slotinfo[slotidx];
    809 
    810 	login_required = si->token.flags & CKF_LOGIN_REQUIRED;
    811 
    812 	/* fail early before opening session */
    813 	if (login_required && !pkcs11_interactive &&
    814 	    (pin == NULL || strlen(pin) == 0)) {
    815 		error("pin required");
    816 		return (-SSH_PKCS11_ERR_PIN_REQUIRED);
    817 	}
    818 	if ((rv = f->C_OpenSession(p->slotlist[slotidx], CKF_RW_SESSION|
    819 	    CKF_SERIAL_SESSION, NULL, NULL, &session)) != CKR_OK) {
    820 		error("C_OpenSession failed: %lu", rv);
    821 		return (-1);
    822 	}
    823 	if (login_required && pin != NULL && strlen(pin) != 0) {
    824 		rv = f->C_Login(session, user, (u_char *)pin, strlen(pin));
    825 		if (rv != CKR_OK && rv != CKR_USER_ALREADY_LOGGED_IN) {
    826 			error("C_Login failed: %lu", rv);
    827 			ret = (rv == CKR_PIN_LOCKED) ?
    828 			    -SSH_PKCS11_ERR_PIN_LOCKED :
    829 			    -SSH_PKCS11_ERR_LOGIN_FAIL;
    830 			if ((rv = f->C_CloseSession(session)) != CKR_OK)
    831 				error("C_CloseSession failed: %lu", rv);
    832 			return (ret);
    833 		}
    834 		si->logged_in = 1;
    835 	}
    836 	si->session = session;
    837 	return (0);
    838 }
    839 
    840 static int
    841 pkcs11_key_included(struct sshkey ***keysp, int *nkeys, struct sshkey *key)
    842 {
    843 	int i;
    844 
    845 	for (i = 0; i < *nkeys; i++)
    846 		if (sshkey_equal(key, (*keysp)[i]))
    847 			return (1);
    848 	return (0);
    849 }
    850 
    851 #ifdef WITH_OPENSSL
    852 static struct sshkey *
    853 pkcs11_fetch_ecdsa_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx,
    854     CK_OBJECT_HANDLE *obj)
    855 {
    856 	CK_ATTRIBUTE		 key_attr[3];
    857 	CK_SESSION_HANDLE	 session;
    858 	CK_FUNCTION_LIST	*f = NULL;
    859 	CK_RV			 rv;
    860 	ASN1_OCTET_STRING	*octet = NULL;
    861 	EC_KEY			*ec = NULL;
    862 	EC_GROUP		*group = NULL;
    863 	struct sshkey		*key = NULL;
    864 	const unsigned char	*attrp = NULL;
    865 	int			 success = -1, r, i, nid;
    866 
    867 	memset(&key_attr, 0, sizeof(key_attr));
    868 	key_attr[0].type = CKA_ID;
    869 	key_attr[1].type = CKA_EC_POINT;
    870 	key_attr[2].type = CKA_EC_PARAMS;
    871 
    872 	session = p->slotinfo[slotidx].session;
    873 	f = p->function_list;
    874 
    875 	/* figure out size of the attributes */
    876 	rv = f->C_GetAttributeValue(session, *obj, key_attr, 3);
    877 	if (rv != CKR_OK) {
    878 		error("C_GetAttributeValue failed: %lu", rv);
    879 		return (NULL);
    880 	}
    881 
    882 	/*
    883 	 * Allow CKA_ID (always first attribute) to be empty, but
    884 	 * ensure that none of the others are zero length.
    885 	 * XXX assumes CKA_ID is always first.
    886 	 */
    887 	if (key_attr[1].ulValueLen == 0 ||
    888 	    key_attr[2].ulValueLen == 0) {
    889 		error("invalid attribute length");
    890 		return (NULL);
    891 	}
    892 
    893 	/* allocate buffers for attributes */
    894 	for (i = 0; i < 3; i++)
    895 		if (key_attr[i].ulValueLen > 0)
    896 			key_attr[i].pValue = xcalloc(1, key_attr[i].ulValueLen);
    897 
    898 	/* retrieve ID, public point and curve parameters of EC key */
    899 	rv = f->C_GetAttributeValue(session, *obj, key_attr, 3);
    900 	if (rv != CKR_OK) {
    901 		error("C_GetAttributeValue failed: %lu", rv);
    902 		goto fail;
    903 	}
    904 
    905 	ec = EC_KEY_new();
    906 	if (ec == NULL) {
    907 		error("EC_KEY_new failed");
    908 		goto fail;
    909 	}
    910 
    911 	attrp = key_attr[2].pValue;
    912 	group = d2i_ECPKParameters(NULL, &attrp, key_attr[2].ulValueLen);
    913 	if (group == NULL) {
    914 		ossl_error("d2i_ECPKParameters failed");
    915 		goto fail;
    916 	}
    917 
    918 	if (EC_KEY_set_group(ec, group) == 0) {
    919 		ossl_error("EC_KEY_set_group failed");
    920 		goto fail;
    921 	}
    922 
    923 	if (key_attr[1].ulValueLen <= 2) {
    924 		error("CKA_EC_POINT too small");
    925 		goto fail;
    926 	}
    927 
    928 	attrp = key_attr[1].pValue;
    929 	octet = d2i_ASN1_OCTET_STRING(NULL, &attrp, key_attr[1].ulValueLen);
    930 	if (octet == NULL) {
    931 		ossl_error("d2i_ASN1_OCTET_STRING failed");
    932 		goto fail;
    933 	}
    934 	attrp = ASN1_STRING_get0_data(octet);
    935 	if (o2i_ECPublicKey(&ec, &attrp, ASN1_STRING_length(octet)) == NULL) {
    936 		ossl_error("o2i_ECPublicKey failed");
    937 		goto fail;
    938 	}
    939 	if ((r = sshkey_ec_validate_public(EC_KEY_get0_group(ec),
    940 	    EC_KEY_get0_public_key(ec))) != 0) {
    941 		error_fr(r, "invalid EC key");
    942 		goto fail;
    943 	}
    944 
    945 	nid = sshkey_ecdsa_key_to_nid(ec);
    946 	if (nid < 0) {
    947 		error("couldn't get curve nid");
    948 		goto fail;
    949 	}
    950 
    951 	key = sshkey_new(KEY_UNSPEC);
    952 	if (key == NULL) {
    953 		error("sshkey_new failed");
    954 		goto fail;
    955 	}
    956 
    957 	EVP_PKEY_free(key->pkey);
    958 	if ((key->pkey = EVP_PKEY_new()) == NULL)
    959 		fatal("EVP_PKEY_new failed");
    960 	if (EVP_PKEY_set1_EC_KEY(key->pkey, ec) != 1)
    961 		fatal("EVP_PKEY_set1_EC_KEY failed");
    962 	key->ecdsa_nid = nid;
    963 	key->type = KEY_ECDSA;
    964 	key->flags |= SSHKEY_FLAG_EXT;
    965 	if (pkcs11_record_key(p, slotidx, &key_attr[0], key))
    966 		goto fail;
    967 	/* success */
    968 	success = 0;
    969 fail:
    970 	if (success != 0) {
    971 		sshkey_free(key);
    972 		key = NULL;
    973 	}
    974 	for (i = 0; i < 3; i++)
    975 		free(key_attr[i].pValue);
    976 	if (ec)
    977 		EC_KEY_free(ec);
    978 	if (group)
    979 		EC_GROUP_free(group);
    980 	if (octet)
    981 		ASN1_OCTET_STRING_free(octet);
    982 
    983 	return (key);
    984 }
    985 
    986 static struct sshkey *
    987 pkcs11_fetch_rsa_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx,
    988     CK_OBJECT_HANDLE *obj)
    989 {
    990 	CK_ATTRIBUTE		 key_attr[3];
    991 	CK_SESSION_HANDLE	 session;
    992 	CK_FUNCTION_LIST	*f = NULL;
    993 	CK_RV			 rv;
    994 	RSA			*rsa = NULL;
    995 	BIGNUM			*rsa_n, *rsa_e;
    996 	struct sshkey		*key = NULL;
    997 	int			 i, success = -1;
    998 
    999 	memset(&key_attr, 0, sizeof(key_attr));
   1000 	key_attr[0].type = CKA_ID;
   1001 	key_attr[1].type = CKA_MODULUS;
   1002 	key_attr[2].type = CKA_PUBLIC_EXPONENT;
   1003 
   1004 	session = p->slotinfo[slotidx].session;
   1005 	f = p->function_list;
   1006 
   1007 	/* figure out size of the attributes */
   1008 	rv = f->C_GetAttributeValue(session, *obj, key_attr, 3);
   1009 	if (rv != CKR_OK) {
   1010 		error("C_GetAttributeValue failed: %lu", rv);
   1011 		return (NULL);
   1012 	}
   1013 
   1014 	/*
   1015 	 * Allow CKA_ID (always first attribute) to be empty, but
   1016 	 * ensure that none of the others are zero length.
   1017 	 * XXX assumes CKA_ID is always first.
   1018 	 */
   1019 	if (key_attr[1].ulValueLen == 0 ||
   1020 	    key_attr[2].ulValueLen == 0) {
   1021 		error("invalid attribute length");
   1022 		return (NULL);
   1023 	}
   1024 
   1025 	/* allocate buffers for attributes */
   1026 	for (i = 0; i < 3; i++)
   1027 		if (key_attr[i].ulValueLen > 0)
   1028 			key_attr[i].pValue = xcalloc(1, key_attr[i].ulValueLen);
   1029 
   1030 	/* retrieve ID, modulus and public exponent of RSA key */
   1031 	rv = f->C_GetAttributeValue(session, *obj, key_attr, 3);
   1032 	if (rv != CKR_OK) {
   1033 		error("C_GetAttributeValue failed: %lu", rv);
   1034 		goto fail;
   1035 	}
   1036 
   1037 	rsa = RSA_new();
   1038 	if (rsa == NULL) {
   1039 		error("RSA_new failed");
   1040 		goto fail;
   1041 	}
   1042 
   1043 	rsa_n = BN_bin2bn(key_attr[1].pValue, key_attr[1].ulValueLen, NULL);
   1044 	rsa_e = BN_bin2bn(key_attr[2].pValue, key_attr[2].ulValueLen, NULL);
   1045 	if (rsa_n == NULL || rsa_e == NULL) {
   1046 		error("BN_bin2bn failed");
   1047 		goto fail;
   1048 	}
   1049 	if (!RSA_set0_key(rsa, rsa_n, rsa_e, NULL))
   1050 		fatal_f("set key");
   1051 	rsa_n = rsa_e = NULL; /* transferred */
   1052 
   1053 	key = sshkey_new(KEY_UNSPEC);
   1054 	if (key == NULL) {
   1055 		error("sshkey_new failed");
   1056 		goto fail;
   1057 	}
   1058 
   1059 	EVP_PKEY_free(key->pkey);
   1060 	if ((key->pkey = EVP_PKEY_new()) == NULL)
   1061 		fatal("EVP_PKEY_new failed");
   1062 	if (EVP_PKEY_set1_RSA(key->pkey, rsa) != 1)
   1063 		fatal("EVP_PKEY_set1_RSA failed");
   1064 	key->type = KEY_RSA;
   1065 	key->flags |= SSHKEY_FLAG_EXT;
   1066 	if (EVP_PKEY_bits(key->pkey) < SSH_RSA_MINIMUM_MODULUS_SIZE) {
   1067 		error_f("RSA key too small %d < minimum %d",
   1068 		    EVP_PKEY_bits(key->pkey), SSH_RSA_MINIMUM_MODULUS_SIZE);
   1069 		goto fail;
   1070 	}
   1071 	if (pkcs11_record_key(p, slotidx, &key_attr[0], key))
   1072 		goto fail;
   1073 	/* success */
   1074 	success = 0;
   1075 fail:
   1076 	for (i = 0; i < 3; i++)
   1077 		free(key_attr[i].pValue);
   1078 	RSA_free(rsa);
   1079 	if (success != 0) {
   1080 		sshkey_free(key);
   1081 		key = NULL;
   1082 	}
   1083 	return key;
   1084 }
   1085 #endif /* WITH_OPENSSL */
   1086 
   1087 static struct sshkey *
   1088 pkcs11_fetch_ed25519_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx,
   1089     CK_OBJECT_HANDLE *obj)
   1090 {
   1091 	CK_ATTRIBUTE		 key_attr[3];
   1092 	CK_SESSION_HANDLE	 session;
   1093 	CK_FUNCTION_LIST	*f = NULL;
   1094 	CK_RV			 rv;
   1095 	struct sshkey		*key = NULL;
   1096 	const unsigned char	*d = NULL;
   1097 	size_t			len;
   1098 	char			*hex = NULL;
   1099 	int			 success = -1, i;
   1100 	/* https://docs.oasis-open.org/pkcs11/pkcs11-curr/v3.0/os/pkcs11-curr-v3.0-os.html#_Toc30061180 */
   1101 	const u_char		 id1[14] = {
   1102 		0x13, 0x0c, 0x65, 0x64, 0x77, 0x61, 0x72, 0x64,
   1103 		0x73, 0x32, 0x35, 0x35, 0x31, 0x39,
   1104 	}; /* PrintableString { "edwards25519" } */
   1105 	const u_char		 id2[5] = {
   1106 		0x06, 0x03, 0x2b, 0x65, 0x70,
   1107 	}; /* OBJECT_IDENTIFIER { 1.3.101.112 } */
   1108 
   1109 	memset(&key_attr, 0, sizeof(key_attr));
   1110 	key_attr[0].type = CKA_ID;
   1111 	key_attr[1].type = CKA_EC_POINT; /* XXX or CKA_VALUE ? */
   1112 	key_attr[2].type = CKA_EC_PARAMS;
   1113 
   1114 	session = p->slotinfo[slotidx].session;
   1115 	f = p->function_list;
   1116 
   1117 	/* figure out size of the attributes */
   1118 	rv = f->C_GetAttributeValue(session, *obj, key_attr, 3);
   1119 	if (rv != CKR_OK) {
   1120 		error("C_GetAttributeValue failed: %lu", rv);
   1121 		return (NULL);
   1122 	}
   1123 
   1124 	/*
   1125 	 * Allow CKA_ID (always first attribute) to be empty, but
   1126 	 * ensure that none of the others are zero length.
   1127 	 * XXX assumes CKA_ID is always first.
   1128 	 */
   1129 	if (key_attr[1].ulValueLen == 0 ||
   1130 	    key_attr[2].ulValueLen == 0) {
   1131 		error("invalid attribute length");
   1132 		return (NULL);
   1133 	}
   1134 
   1135 	/* allocate buffers for attributes */
   1136 	for (i = 0; i < 3; i++) {
   1137 		if (key_attr[i].ulValueLen > 0)
   1138 			key_attr[i].pValue = xcalloc(1, key_attr[i].ulValueLen);
   1139 	}
   1140 
   1141 	/* retrieve ID, public point and curve parameters of EC key */
   1142 	rv = f->C_GetAttributeValue(session, *obj, key_attr, 3);
   1143 	if (rv != CKR_OK) {
   1144 		error("C_GetAttributeValue failed: %lu", rv);
   1145 		goto fail;
   1146 	}
   1147 
   1148 	/* Expect one of the supported identifiers in CKA_EC_PARAMS */
   1149 	d = (u_char *)key_attr[2].pValue;
   1150 	len = key_attr[2].ulValueLen;
   1151 	if ((len != sizeof(id1) || memcmp(d, id1, sizeof(id1)) != 0) &&
   1152 	    (len != sizeof(id2) || memcmp(d, id2, sizeof(id2)) != 0)) {
   1153 		hex = tohex(d, len);
   1154 		logit_f("unsupported CKA_EC_PARAMS: %s (len %zu)", hex, len);
   1155 		goto fail;
   1156 	}
   1157 
   1158 	/*
   1159 	 * Expect either a raw 32 byte pubkey or an OCTET STRING with
   1160 	 * a 32 byte pubkey in CKA_VALUE
   1161 	 */
   1162 	d = (u_char *)key_attr[1].pValue;
   1163 	len = key_attr[1].ulValueLen;
   1164 	if (len == ED25519_PK_SZ + 2 && d[0] == 0x04 && d[1] == ED25519_PK_SZ) {
   1165 		d += 2;
   1166 		len -= 2;
   1167 	}
   1168 	if (len != ED25519_PK_SZ) {
   1169 		hex = tohex(key_attr[1].pValue, key_attr[1].ulValueLen);
   1170 		logit_f("CKA_EC_POINT invalid octet str: %s (len %lu)",
   1171 		    hex, (u_long)key_attr[1].ulValueLen);
   1172 		goto fail;
   1173 	}
   1174 
   1175 	if ((key = sshkey_new(KEY_UNSPEC)) == NULL)
   1176 		fatal_f("sshkey_new failed");
   1177 	key->ed25519_pk = xmalloc(ED25519_PK_SZ);
   1178 	memcpy(key->ed25519_pk, d, ED25519_PK_SZ);
   1179 	key->type = KEY_ED25519;
   1180 	key->flags |= SSHKEY_FLAG_EXT;
   1181 	if (pkcs11_record_key(p, slotidx, &key_attr[0], key))
   1182 		goto fail;
   1183 	/* success */
   1184 	success = 0;
   1185  fail:
   1186 	if (success != 0) {
   1187 		sshkey_free(key);
   1188 		key = NULL;
   1189 	}
   1190 	free(hex);
   1191 	for (i = 0; i < 3; i++)
   1192 		free(key_attr[i].pValue);
   1193 	return key;
   1194 }
   1195 
   1196 #ifdef WITH_OPENSSL
   1197 static int
   1198 pkcs11_fetch_x509_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx,
   1199     CK_OBJECT_HANDLE *obj, struct sshkey **keyp, char **labelp)
   1200 {
   1201 	CK_ATTRIBUTE		 cert_attr[3];
   1202 	CK_SESSION_HANDLE	 session;
   1203 	CK_FUNCTION_LIST	*f = NULL;
   1204 	CK_RV			 rv;
   1205 	X509			*x509 = NULL;
   1206 	X509_NAME		*x509_name = NULL;
   1207 	EVP_PKEY		*evp;
   1208 	RSA			*rsa = NULL;
   1209 	EC_KEY			*ec = NULL;
   1210 	struct sshkey		*key = NULL;
   1211 	int			 r, i, nid, success = -1;
   1212 	const u_char		*cp;
   1213 	char			*subject = NULL;
   1214 	size_t			len;
   1215 
   1216 	*keyp = NULL;
   1217 	*labelp = NULL;
   1218 
   1219 	memset(&cert_attr, 0, sizeof(cert_attr));
   1220 	cert_attr[0].type = CKA_ID;
   1221 	cert_attr[1].type = CKA_SUBJECT;
   1222 	cert_attr[2].type = CKA_VALUE;
   1223 
   1224 	session = p->slotinfo[slotidx].session;
   1225 	f = p->function_list;
   1226 
   1227 	/* figure out size of the attributes */
   1228 	rv = f->C_GetAttributeValue(session, *obj, cert_attr, 3);
   1229 	if (rv != CKR_OK) {
   1230 		error("C_GetAttributeValue failed: %lu", rv);
   1231 		return -1;
   1232 	}
   1233 
   1234 	/*
   1235 	 * Allow CKA_ID (always first attribute) to be empty, but
   1236 	 * ensure that none of the others are zero length.
   1237 	 * XXX assumes CKA_ID is always first.
   1238 	 */
   1239 	if (cert_attr[1].ulValueLen == 0 ||
   1240 	    cert_attr[2].ulValueLen == 0) {
   1241 		error("invalid attribute length");
   1242 		return -1;
   1243 	}
   1244 
   1245 	/* allocate buffers for attributes */
   1246 	for (i = 0; i < 3; i++)
   1247 		if (cert_attr[i].ulValueLen > 0)
   1248 			cert_attr[i].pValue = xcalloc(1, cert_attr[i].ulValueLen);
   1249 
   1250 	/* retrieve ID, subject and value of certificate */
   1251 	rv = f->C_GetAttributeValue(session, *obj, cert_attr, 3);
   1252 	if (rv != CKR_OK) {
   1253 		error("C_GetAttributeValue failed: %lu", rv);
   1254 		goto out;
   1255 	}
   1256 
   1257 	/* Decode DER-encoded cert subject */
   1258 	cp = cert_attr[1].pValue;
   1259 	if ((x509_name = d2i_X509_NAME(NULL, &cp,
   1260 	    cert_attr[1].ulValueLen)) == NULL ||
   1261 	    (subject = X509_NAME_oneline(x509_name, NULL, 0)) == NULL)
   1262 		subject = xstrdup("invalid subject");
   1263 	X509_NAME_free(x509_name);
   1264 
   1265 	cp = cert_attr[2].pValue;
   1266 	if ((x509 = d2i_X509(NULL, &cp, cert_attr[2].ulValueLen)) == NULL) {
   1267 		error("d2i_x509 failed");
   1268 		goto out;
   1269 	}
   1270 
   1271 	if ((evp = X509_get_pubkey(x509)) == NULL) {
   1272 		error("X509_get_pubkey failed");
   1273 		goto out;
   1274 	}
   1275 
   1276 	if (EVP_PKEY_base_id(evp) == EVP_PKEY_RSA) {
   1277 		if (EVP_PKEY_get0_RSA(evp) == NULL) {
   1278 			error("invalid x509; no rsa key");
   1279 			goto out;
   1280 		}
   1281 		if ((rsa = RSAPublicKey_dup(EVP_PKEY_get0_RSA(evp))) == NULL) {
   1282 			error("RSAPublicKey_dup failed");
   1283 			goto out;
   1284 		}
   1285 
   1286 		key = sshkey_new(KEY_UNSPEC);
   1287 		if (key == NULL) {
   1288 			error("sshkey_new failed");
   1289 			goto out;
   1290 		}
   1291 
   1292 		EVP_PKEY_free(key->pkey);
   1293 		if ((key->pkey = EVP_PKEY_new()) == NULL)
   1294 			fatal("EVP_PKEY_new failed");
   1295 		if (EVP_PKEY_set1_RSA(key->pkey, rsa) != 1)
   1296 			fatal("EVP_PKEY_set1_RSA failed");
   1297 		key->type = KEY_RSA;
   1298 		key->flags |= SSHKEY_FLAG_EXT;
   1299 		if (EVP_PKEY_bits(key->pkey) < SSH_RSA_MINIMUM_MODULUS_SIZE) {
   1300 			error_f("RSA key too small %d < minimum %d",
   1301 			    EVP_PKEY_bits(key->pkey),
   1302 			    SSH_RSA_MINIMUM_MODULUS_SIZE);
   1303 			goto out;
   1304 		}
   1305 		if (pkcs11_record_key(p, slotidx, &cert_attr[0], key))
   1306 			goto out;
   1307 		/* success */
   1308 		success = 0;
   1309 	} else if (EVP_PKEY_base_id(evp) == EVP_PKEY_EC) {
   1310 		if (EVP_PKEY_get0_EC_KEY(evp) == NULL) {
   1311 			error("invalid x509; no ec key");
   1312 			goto out;
   1313 		}
   1314 		if ((ec = EC_KEY_dup(EVP_PKEY_get0_EC_KEY(evp))) == NULL) {
   1315 			error("EC_KEY_dup failed");
   1316 			goto out;
   1317 		}
   1318 		if ((r = sshkey_ec_validate_public(EC_KEY_get0_group(ec),
   1319 		    EC_KEY_get0_public_key(ec))) != 0) {
   1320 			error_fr(r, "invalid EC key");
   1321 			goto out;
   1322 		}
   1323 		nid = sshkey_ecdsa_key_to_nid(ec);
   1324 		if (nid < 0) {
   1325 			error("couldn't get curve nid");
   1326 			goto out;
   1327 		}
   1328 
   1329 		key = sshkey_new(KEY_UNSPEC);
   1330 		if (key == NULL) {
   1331 			error("sshkey_new failed");
   1332 			goto out;
   1333 		}
   1334 
   1335 		EVP_PKEY_free(key->pkey);
   1336 		if ((key->pkey = EVP_PKEY_new()) == NULL)
   1337 			fatal("EVP_PKEY_new failed");
   1338 		if (EVP_PKEY_set1_EC_KEY(key->pkey, ec) != 1)
   1339 			fatal("EVP_PKEY_set1_EC_KEY failed");
   1340 		key->ecdsa_nid = nid;
   1341 		key->type = KEY_ECDSA;
   1342 		key->flags |= SSHKEY_FLAG_EXT;
   1343 		if (pkcs11_record_key(p, slotidx, &cert_attr[0], key))
   1344 			goto out;
   1345 		/* success */
   1346 		success = 0;
   1347 	} else if (EVP_PKEY_base_id(evp) == EVP_PKEY_ED25519) {
   1348 		if ((key = sshkey_new(KEY_UNSPEC)) == NULL ||
   1349 		    (key->ed25519_pk = calloc(1, ED25519_PK_SZ)) == NULL)
   1350 			fatal_f("allocation failed");
   1351 		len = ED25519_PK_SZ;
   1352 		if (!EVP_PKEY_get_raw_public_key(evp, key->ed25519_pk, &len)) {
   1353 			ossl_error("EVP_PKEY_get_raw_public_key failed");
   1354 			goto out;
   1355 		}
   1356 		if (len != ED25519_PK_SZ) {
   1357 			error_f("incorrect returned public key "
   1358 			    "length for ed25519");
   1359 			goto out;
   1360 		}
   1361 		key->type = KEY_ED25519;
   1362 		key->flags |= SSHKEY_FLAG_EXT;
   1363 		if (pkcs11_record_key(p, slotidx, &cert_attr[0], key))
   1364 			goto out;
   1365 		/* success */
   1366 		success = 0;
   1367 	} else {
   1368 		error("unknown certificate key type");
   1369 		goto out;
   1370 	}
   1371  out:
   1372 	for (i = 0; i < 3; i++)
   1373 		free(cert_attr[i].pValue);
   1374 	X509_free(x509);
   1375 	RSA_free(rsa);
   1376 	EC_KEY_free(ec);
   1377 	if (success != 0 || key == NULL) {
   1378 		sshkey_free(key);
   1379 		free(subject);
   1380 		return -1;
   1381 	}
   1382 	/* success */
   1383 	*keyp = key;
   1384 	*labelp = subject;
   1385 	return 0;
   1386 }
   1387 #endif /* WITH_OPENSSL */
   1388 
   1389 static void
   1390 note_key(struct pkcs11_provider *p, CK_ULONG slotidx, const char *context,
   1391     struct sshkey *key)
   1392 {
   1393 	char *fp;
   1394 
   1395 	if ((fp = sshkey_fingerprint(key, SSH_FP_HASH_DEFAULT,
   1396 	    SSH_FP_DEFAULT)) == NULL) {
   1397 		error_f("sshkey_fingerprint failed");
   1398 		return;
   1399 	}
   1400 	debug2("%s: provider %s slot %lu: %s %s", context, p->name,
   1401 	    (u_long)slotidx, sshkey_type(key), fp);
   1402 	free(fp);
   1403 }
   1404 
   1405 #ifdef WITH_OPENSSL /* libcrypto needed for certificate parsing */
   1406 /*
   1407  * lookup certificates for token in slot identified by slotidx,
   1408  * add 'wrapped' public keys to the 'keysp' array and increment nkeys.
   1409  * keysp points to an (possibly empty) array with *nkeys keys.
   1410  */
   1411 static int
   1412 pkcs11_fetch_certs(struct pkcs11_provider *p, CK_ULONG slotidx,
   1413     struct sshkey ***keysp, char ***labelsp, int *nkeys)
   1414 {
   1415 	struct sshkey		*key = NULL;
   1416 	CK_OBJECT_CLASS		 key_class;
   1417 	CK_ATTRIBUTE		 key_attr[1];
   1418 	CK_SESSION_HANDLE	 session;
   1419 	CK_FUNCTION_LIST	*f = NULL;
   1420 	CK_RV			 rv;
   1421 	CK_OBJECT_HANDLE	 obj;
   1422 	CK_ULONG		 n = 0;
   1423 	int			 ret = -1;
   1424 	char			*label;
   1425 
   1426 	memset(&key_attr, 0, sizeof(key_attr));
   1427 	memset(&obj, 0, sizeof(obj));
   1428 
   1429 	key_class = CKO_CERTIFICATE;
   1430 	key_attr[0].type = CKA_CLASS;
   1431 	key_attr[0].pValue = &key_class;
   1432 	key_attr[0].ulValueLen = sizeof(key_class);
   1433 
   1434 	session = p->slotinfo[slotidx].session;
   1435 	f = p->function_list;
   1436 
   1437 	rv = f->C_FindObjectsInit(session, key_attr, 1);
   1438 	if (rv != CKR_OK) {
   1439 		error("C_FindObjectsInit failed: %lu", rv);
   1440 		goto fail;
   1441 	}
   1442 
   1443 	while (1) {
   1444 		CK_CERTIFICATE_TYPE	ck_cert_type;
   1445 
   1446 		rv = f->C_FindObjects(session, &obj, 1, &n);
   1447 		if (rv != CKR_OK) {
   1448 			error("C_FindObjects failed: %lu", rv);
   1449 			goto fail;
   1450 		}
   1451 		if (n == 0)
   1452 			break;
   1453 
   1454 		memset(&ck_cert_type, 0, sizeof(ck_cert_type));
   1455 		memset(&key_attr, 0, sizeof(key_attr));
   1456 		key_attr[0].type = CKA_CERTIFICATE_TYPE;
   1457 		key_attr[0].pValue = &ck_cert_type;
   1458 		key_attr[0].ulValueLen = sizeof(ck_cert_type);
   1459 
   1460 		rv = f->C_GetAttributeValue(session, obj, key_attr, 1);
   1461 		if (rv != CKR_OK) {
   1462 			error("C_GetAttributeValue failed: %lu", rv);
   1463 			goto fail;
   1464 		}
   1465 
   1466 		key = NULL;
   1467 		label = NULL;
   1468 		switch (ck_cert_type) {
   1469 		case CKC_X_509:
   1470 			if (pkcs11_fetch_x509_pubkey(p, slotidx, &obj,
   1471 			    &key, &label) != 0) {
   1472 				debug_f("failed to fetch key");
   1473 				continue;
   1474 			}
   1475 			break;
   1476 		default:
   1477 			error("skipping unsupported certificate type %lu",
   1478 			    ck_cert_type);
   1479 			continue;
   1480 		}
   1481 		note_key(p, slotidx, __func__, key);
   1482 		if (pkcs11_key_included(keysp, nkeys, key)) {
   1483 			debug2_f("key already included");
   1484 			sshkey_free(key);
   1485 		} else {
   1486 			/* expand key array and add key */
   1487 			*keysp = xrecallocarray(*keysp, *nkeys,
   1488 			    *nkeys + 1, sizeof(struct sshkey *));
   1489 			(*keysp)[*nkeys] = key;
   1490 			if (labelsp != NULL) {
   1491 				*labelsp = xrecallocarray(*labelsp, *nkeys,
   1492 				    *nkeys + 1, sizeof(char *));
   1493 				(*labelsp)[*nkeys] = xstrdup((char *)label);
   1494 			}
   1495 			*nkeys = *nkeys + 1;
   1496 			debug("have %d keys", *nkeys);
   1497 		}
   1498 	}
   1499 
   1500 	ret = 0;
   1501 fail:
   1502 	rv = f->C_FindObjectsFinal(session);
   1503 	if (rv != CKR_OK) {
   1504 		error("C_FindObjectsFinal failed: %lu", rv);
   1505 		ret = -1;
   1506 	}
   1507 
   1508 	return (ret);
   1509 }
   1510 #endif /* WITH_OPENSSL */
   1511 
   1512 /*
   1513  * lookup public keys for token in slot identified by slotidx,
   1514  * add 'wrapped' public keys to the 'keysp' array and increment nkeys.
   1515  * keysp points to an (possibly empty) array with *nkeys keys.
   1516  */
   1517 static int
   1518 pkcs11_fetch_keys(struct pkcs11_provider *p, CK_ULONG slotidx,
   1519     struct sshkey ***keysp, char ***labelsp, int *nkeys)
   1520 {
   1521 	struct sshkey		*key = NULL;
   1522 	CK_OBJECT_CLASS		 key_class;
   1523 	CK_ATTRIBUTE		 key_attr[2];
   1524 	CK_SESSION_HANDLE	 session;
   1525 	CK_FUNCTION_LIST	*f = NULL;
   1526 	CK_RV			 rv;
   1527 	CK_OBJECT_HANDLE	 obj;
   1528 	CK_ULONG		 n = 0;
   1529 	int			 ret = -1;
   1530 
   1531 	memset(&key_attr, 0, sizeof(key_attr));
   1532 	memset(&obj, 0, sizeof(obj));
   1533 
   1534 	key_class = CKO_PUBLIC_KEY;
   1535 	key_attr[0].type = CKA_CLASS;
   1536 	key_attr[0].pValue = &key_class;
   1537 	key_attr[0].ulValueLen = sizeof(key_class);
   1538 
   1539 	session = p->slotinfo[slotidx].session;
   1540 	f = p->function_list;
   1541 
   1542 	rv = f->C_FindObjectsInit(session, key_attr, 1);
   1543 	if (rv != CKR_OK) {
   1544 		error("C_FindObjectsInit failed: %lu", rv);
   1545 		goto fail;
   1546 	}
   1547 
   1548 	while (1) {
   1549 		CK_KEY_TYPE	ck_key_type;
   1550 		CK_UTF8CHAR	label[256];
   1551 
   1552 		rv = f->C_FindObjects(session, &obj, 1, &n);
   1553 		if (rv != CKR_OK) {
   1554 			error("C_FindObjects failed: %lu", rv);
   1555 			goto fail;
   1556 		}
   1557 		if (n == 0)
   1558 			break;
   1559 
   1560 		memset(&ck_key_type, 0, sizeof(ck_key_type));
   1561 		memset(&key_attr, 0, sizeof(key_attr));
   1562 		key_attr[0].type = CKA_KEY_TYPE;
   1563 		key_attr[0].pValue = &ck_key_type;
   1564 		key_attr[0].ulValueLen = sizeof(ck_key_type);
   1565 		key_attr[1].type = CKA_LABEL;
   1566 		key_attr[1].pValue = &label;
   1567 		key_attr[1].ulValueLen = sizeof(label) - 1;
   1568 
   1569 		rv = f->C_GetAttributeValue(session, obj, key_attr, 2);
   1570 		if (rv != CKR_OK) {
   1571 			error("C_GetAttributeValue failed: %lu", rv);
   1572 			goto fail;
   1573 		}
   1574 
   1575 		label[key_attr[1].ulValueLen] = '\0';
   1576 
   1577 		switch (ck_key_type) {
   1578 #ifdef WITH_OPENSSL
   1579 		case CKK_RSA:
   1580 			key = pkcs11_fetch_rsa_pubkey(p, slotidx, &obj);
   1581 			break;
   1582 		case CKK_ECDSA:
   1583 			key = pkcs11_fetch_ecdsa_pubkey(p, slotidx, &obj);
   1584 			break;
   1585 #endif /* WITH_OPENSSL */
   1586 		case CKK_EC_EDWARDS:
   1587 			key = pkcs11_fetch_ed25519_pubkey(p, slotidx, &obj);
   1588 			break;
   1589 		default:
   1590 			/* XXX print key type? */
   1591 			key = NULL;
   1592 			error("skipping unsupported key type 0x%lx",
   1593 			    (u_long)ck_key_type);
   1594 		}
   1595 
   1596 		if (key == NULL) {
   1597 			debug_f("failed to fetch key");
   1598 			continue;
   1599 		}
   1600 		note_key(p, slotidx, __func__, key);
   1601 		if (pkcs11_key_included(keysp, nkeys, key)) {
   1602 			debug2_f("key already included");
   1603 			sshkey_free(key);
   1604 		} else {
   1605 			/* expand key array and add key */
   1606 			*keysp = xrecallocarray(*keysp, *nkeys,
   1607 			    *nkeys + 1, sizeof(struct sshkey *));
   1608 			(*keysp)[*nkeys] = key;
   1609 			if (labelsp != NULL) {
   1610 				*labelsp = xrecallocarray(*labelsp, *nkeys,
   1611 				    *nkeys + 1, sizeof(char *));
   1612 				(*labelsp)[*nkeys] = xstrdup((char *)label);
   1613 			}
   1614 			*nkeys = *nkeys + 1;
   1615 			debug("have %d keys", *nkeys);
   1616 		}
   1617 	}
   1618 
   1619 	ret = 0;
   1620 fail:
   1621 	rv = f->C_FindObjectsFinal(session);
   1622 	if (rv != CKR_OK) {
   1623 		error("C_FindObjectsFinal failed: %lu", rv);
   1624 		ret = -1;
   1625 	}
   1626 
   1627 	return (ret);
   1628 }
   1629 
   1630 #ifdef WITH_PKCS11_KEYGEN
   1631 #define FILL_ATTR(attr, idx, typ, val, len) \
   1632 	{ (attr[idx]).type=(typ); (attr[idx]).pValue=(val); (attr[idx]).ulValueLen=len; idx++; }
   1633 
   1634 static struct sshkey *
   1635 pkcs11_rsa_generate_private_key(struct pkcs11_provider *p, CK_ULONG slotidx,
   1636     char *label, CK_ULONG bits, CK_BYTE keyid, uint32_t *err)
   1637 {
   1638 	struct pkcs11_slotinfo	*si;
   1639 	char			*plabel = label ? label : "";
   1640 	int			 npub = 0, npriv = 0;
   1641 	CK_RV			 rv;
   1642 	CK_FUNCTION_LIST	*f;
   1643 	CK_SESSION_HANDLE	 session;
   1644 	CK_BBOOL		 true_val = CK_TRUE, false_val = CK_FALSE;
   1645 	CK_OBJECT_HANDLE	 pubKey, privKey;
   1646 	CK_ATTRIBUTE		 tpub[16], tpriv[16];
   1647 	CK_MECHANISM		 mech = {
   1648 	    CKM_RSA_PKCS_KEY_PAIR_GEN, NULL_PTR, 0
   1649 	};
   1650 	CK_BYTE			 pubExponent[] = {
   1651 	    0x01, 0x00, 0x01 /* RSA_F4 in bytes */
   1652 	};
   1653 
   1654 	*err = 0;
   1655 
   1656 	FILL_ATTR(tpub, npub, CKA_TOKEN, &true_val, sizeof(true_val));
   1657 	FILL_ATTR(tpub, npub, CKA_LABEL, plabel, strlen(plabel));
   1658 	FILL_ATTR(tpub, npub, CKA_ENCRYPT, &false_val, sizeof(false_val));
   1659 	FILL_ATTR(tpub, npub, CKA_VERIFY, &true_val, sizeof(true_val));
   1660 	FILL_ATTR(tpub, npub, CKA_VERIFY_RECOVER, &false_val,
   1661 	    sizeof(false_val));
   1662 	FILL_ATTR(tpub, npub, CKA_WRAP, &false_val, sizeof(false_val));
   1663 	FILL_ATTR(tpub, npub, CKA_DERIVE, &false_val, sizeof(false_val));
   1664 	FILL_ATTR(tpub, npub, CKA_MODULUS_BITS, &bits, sizeof(bits));
   1665 	FILL_ATTR(tpub, npub, CKA_PUBLIC_EXPONENT, pubExponent,
   1666 	    sizeof(pubExponent));
   1667 	FILL_ATTR(tpub, npub, CKA_ID, &keyid, sizeof(keyid));
   1668 
   1669 	FILL_ATTR(tpriv, npriv, CKA_TOKEN,  &true_val, sizeof(true_val));
   1670 	FILL_ATTR(tpriv, npriv, CKA_LABEL,  plabel, strlen(plabel));
   1671 	FILL_ATTR(tpriv, npriv, CKA_PRIVATE,  &true_val, sizeof(true_val));
   1672 	FILL_ATTR(tpriv, npriv, CKA_SENSITIVE,  &true_val, sizeof(true_val));
   1673 	FILL_ATTR(tpriv, npriv, CKA_DECRYPT,  &false_val, sizeof(false_val));
   1674 	FILL_ATTR(tpriv, npriv, CKA_SIGN,  &true_val, sizeof(true_val));
   1675 	FILL_ATTR(tpriv, npriv, CKA_SIGN_RECOVER,  &false_val,
   1676 	    sizeof(false_val));
   1677 	FILL_ATTR(tpriv, npriv, CKA_UNWRAP,  &false_val, sizeof(false_val));
   1678 	FILL_ATTR(tpriv, npriv, CKA_DERIVE,  &false_val, sizeof(false_val));
   1679 	FILL_ATTR(tpriv, npriv, CKA_ID, &keyid, sizeof(keyid));
   1680 
   1681 	f = p->function_list;
   1682 	si = &p->slotinfo[slotidx];
   1683 	session = si->session;
   1684 
   1685 	if ((rv = f->C_GenerateKeyPair(session, &mech, tpub, npub, tpriv, npriv,
   1686 	    &pubKey, &privKey)) != CKR_OK) {
   1687 		error_f("key generation failed: error 0x%lx", rv);
   1688 		*err = rv;
   1689 		return NULL;
   1690 	}
   1691 
   1692 	return pkcs11_fetch_rsa_pubkey(p, slotidx, &pubKey);
   1693 }
   1694 
   1695 static int
   1696 h2i(char c)
   1697 {
   1698 	if (c >= '0' && c <= '9')
   1699 		return c - '0';
   1700 	else if (c >= 'a' && c <= 'f')
   1701 		return c - 'a' + 10;
   1702 	else if (c >= 'A' && c <= 'F')
   1703 		return c - 'A' + 10;
   1704 	else
   1705 		return -1;
   1706 }
   1707 
   1708 static int
   1709 pkcs11_decode_hex(const char *hex, unsigned char **dest, size_t *rlen)
   1710 {
   1711 	size_t	i, len;
   1712 
   1713 	if (dest)
   1714 		*dest = NULL;
   1715 	if (rlen)
   1716 		*rlen = 0;
   1717 
   1718 	if ((len = strlen(hex)) % 2)
   1719 		return -1;
   1720 	len /= 2;
   1721 
   1722 	*dest = xmalloc(len);
   1723 
   1724 	for (i = 0; i < len; i++) {
   1725 		int hi, lo;
   1726 
   1727 		hi = h2i(hex[2 * i]);
   1728 		lo = h2i(hex[(2 * i) + 1]);
   1729 		if (hi == -1 || lo == -1)
   1730 			return -1;
   1731 		(*dest)[i] = (hi << 4) | lo;
   1732 	}
   1733 
   1734 	if (rlen)
   1735 		*rlen = len;
   1736 
   1737 	return 0;
   1738 }
   1739 
   1740 static struct ec_curve_info {
   1741 	const char	*name;
   1742 	const char	*oid;
   1743 	const char	*oid_encoded;
   1744 	size_t		 size;
   1745 } ec_curve_infos[] = {
   1746 	{"prime256v1",	"1.2.840.10045.3.1.7",	"06082A8648CE3D030107", 256},
   1747 	{"secp384r1",	"1.3.132.0.34",		"06052B81040022",	384},
   1748 	{"secp521r1",	"1.3.132.0.35",		"06052B81040023",	521},
   1749 	{NULL,		NULL,			NULL,			0},
   1750 };
   1751 
   1752 static struct sshkey *
   1753 pkcs11_ecdsa_generate_private_key(struct pkcs11_provider *p, CK_ULONG slotidx,
   1754     char *label, CK_ULONG bits, CK_BYTE keyid, uint32_t *err)
   1755 {
   1756 	struct pkcs11_slotinfo	*si;
   1757 	char			*plabel = label ? label : "";
   1758 	int			 i;
   1759 	size_t			 ecparams_size;
   1760 	unsigned char		*ecparams = NULL;
   1761 	int			 npub = 0, npriv = 0;
   1762 	CK_RV			 rv;
   1763 	CK_FUNCTION_LIST	*f;
   1764 	CK_SESSION_HANDLE	 session;
   1765 	CK_BBOOL		 true_val = CK_TRUE, false_val = CK_FALSE;
   1766 	CK_OBJECT_HANDLE	 pubKey, privKey;
   1767 	CK_MECHANISM		 mech = {
   1768 	    CKM_EC_KEY_PAIR_GEN, NULL_PTR, 0
   1769 	};
   1770 	CK_ATTRIBUTE		 tpub[16], tpriv[16];
   1771 
   1772 	*err = 0;
   1773 
   1774 	for (i = 0; ec_curve_infos[i].name; i++) {
   1775 		if (ec_curve_infos[i].size == bits)
   1776 			break;
   1777 	}
   1778 	if (!ec_curve_infos[i].name) {
   1779 		error_f("invalid key size %lu", bits);
   1780 		return NULL;
   1781 	}
   1782 	if (pkcs11_decode_hex(ec_curve_infos[i].oid_encoded, &ecparams,
   1783 	    &ecparams_size) == -1) {
   1784 		error_f("invalid oid");
   1785 		return NULL;
   1786 	}
   1787 
   1788 	FILL_ATTR(tpub, npub, CKA_TOKEN, &true_val, sizeof(true_val));
   1789 	FILL_ATTR(tpub, npub, CKA_LABEL, plabel, strlen(plabel));
   1790 	FILL_ATTR(tpub, npub, CKA_ENCRYPT, &false_val, sizeof(false_val));
   1791 	FILL_ATTR(tpub, npub, CKA_VERIFY, &true_val, sizeof(true_val));
   1792 	FILL_ATTR(tpub, npub, CKA_VERIFY_RECOVER, &false_val,
   1793 	    sizeof(false_val));
   1794 	FILL_ATTR(tpub, npub, CKA_WRAP, &false_val, sizeof(false_val));
   1795 	FILL_ATTR(tpub, npub, CKA_DERIVE, &false_val, sizeof(false_val));
   1796 	FILL_ATTR(tpub, npub, CKA_EC_PARAMS, ecparams, ecparams_size);
   1797 	FILL_ATTR(tpub, npub, CKA_ID, &keyid, sizeof(keyid));
   1798 
   1799 	FILL_ATTR(tpriv, npriv, CKA_TOKEN, &true_val, sizeof(true_val));
   1800 	FILL_ATTR(tpriv, npriv, CKA_LABEL, plabel, strlen(plabel));
   1801 	FILL_ATTR(tpriv, npriv, CKA_PRIVATE, &true_val, sizeof(true_val));
   1802 	FILL_ATTR(tpriv, npriv, CKA_SENSITIVE, &true_val, sizeof(true_val));
   1803 	FILL_ATTR(tpriv, npriv, CKA_DECRYPT, &false_val, sizeof(false_val));
   1804 	FILL_ATTR(tpriv, npriv, CKA_SIGN, &true_val, sizeof(true_val));
   1805 	FILL_ATTR(tpriv, npriv, CKA_SIGN_RECOVER, &false_val,
   1806 	    sizeof(false_val));
   1807 	FILL_ATTR(tpriv, npriv, CKA_UNWRAP, &false_val, sizeof(false_val));
   1808 	FILL_ATTR(tpriv, npriv, CKA_DERIVE, &false_val, sizeof(false_val));
   1809 	FILL_ATTR(tpriv, npriv, CKA_ID, &keyid, sizeof(keyid));
   1810 
   1811 	f = p->function_list;
   1812 	si = &p->slotinfo[slotidx];
   1813 	session = si->session;
   1814 
   1815 	if ((rv = f->C_GenerateKeyPair(session, &mech, tpub, npub, tpriv, npriv,
   1816 	    &pubKey, &privKey)) != CKR_OK) {
   1817 		error_f("key generation failed: error 0x%lx", rv);
   1818 		*err = rv;
   1819 		return NULL;
   1820 	}
   1821 
   1822 	return pkcs11_fetch_ecdsa_pubkey(p, slotidx, &pubKey);
   1823 }
   1824 #endif /* WITH_PKCS11_KEYGEN */
   1825 
   1826 /*
   1827  * register a new provider, fails if provider already exists. if
   1828  * keyp is provided, fetch keys.
   1829  */
   1830 static int
   1831 pkcs11_register_provider(char *provider_id, char *pin,
   1832     struct sshkey ***keyp, char ***labelsp,
   1833     struct pkcs11_provider **providerp, CK_ULONG user)
   1834 {
   1835 	int nkeys, need_finalize = 0;
   1836 	int ret = -1;
   1837 	struct pkcs11_provider *p = NULL;
   1838 	void *handle = NULL;
   1839 	CK_RV (*getfunctionlist)(CK_FUNCTION_LIST **);
   1840 	CK_RV rv;
   1841 	CK_FUNCTION_LIST *f = NULL;
   1842 	CK_TOKEN_INFO *token;
   1843 	CK_ULONG i;
   1844 
   1845 	if (providerp == NULL)
   1846 		goto fail;
   1847 	*providerp = NULL;
   1848 
   1849 	if (keyp != NULL)
   1850 		*keyp = NULL;
   1851 	if (labelsp != NULL)
   1852 		*labelsp = NULL;
   1853 
   1854 	if (pkcs11_provider_lookup(provider_id) != NULL) {
   1855 		debug_f("provider already registered: %s", provider_id);
   1856 		goto fail;
   1857 	}
   1858 	if (lib_contains_symbol(provider_id, "C_GetFunctionList") != 0) {
   1859 		error("provider %s is not a PKCS11 library", provider_id);
   1860 		goto fail;
   1861 	}
   1862 	/* open shared pkcs11-library */
   1863 	if ((handle = dlopen(provider_id, RTLD_NOW)) == NULL) {
   1864 		error("dlopen %s failed: %s", provider_id, dlerror());
   1865 		goto fail;
   1866 	}
   1867 	if ((getfunctionlist = dlsym(handle, "C_GetFunctionList")) == NULL)
   1868 		fatal("dlsym(C_GetFunctionList) failed: %s", dlerror());
   1869 	p = xcalloc(1, sizeof(*p));
   1870 	p->name = xstrdup(provider_id);
   1871 	p->handle = handle;
   1872 	/* set up the pkcs11 callbacks */
   1873 	if ((rv = (*getfunctionlist)(&f)) != CKR_OK) {
   1874 		error("C_GetFunctionList for provider %s failed: %lu",
   1875 		    provider_id, rv);
   1876 		goto fail;
   1877 	}
   1878 	p->function_list = f;
   1879 	if ((rv = f->C_Initialize(NULL)) != CKR_OK) {
   1880 		error("C_Initialize for provider %s failed: %lu",
   1881 		    provider_id, rv);
   1882 		goto fail;
   1883 	}
   1884 	need_finalize = 1;
   1885 	if ((rv = f->C_GetInfo(&p->info)) != CKR_OK) {
   1886 		error("C_GetInfo for provider %s failed: %lu",
   1887 		    provider_id, rv);
   1888 		goto fail;
   1889 	}
   1890 	debug("provider %s: manufacturerID <%.*s> cryptokiVersion %d.%d"
   1891 	    " libraryDescription <%.*s> libraryVersion %d.%d",
   1892 	    provider_id,
   1893 	    RMSPACE(p->info.manufacturerID),
   1894 	    p->info.cryptokiVersion.major,
   1895 	    p->info.cryptokiVersion.minor,
   1896 	    RMSPACE(p->info.libraryDescription),
   1897 	    p->info.libraryVersion.major,
   1898 	    p->info.libraryVersion.minor);
   1899 	if ((rv = f->C_GetSlotList(CK_TRUE, NULL, &p->nslots)) != CKR_OK) {
   1900 		error("C_GetSlotList failed: %lu", rv);
   1901 		goto fail;
   1902 	}
   1903 	if (p->nslots == 0) {
   1904 		debug_f("provider %s returned no slots", provider_id);
   1905 		ret = -SSH_PKCS11_ERR_NO_SLOTS;
   1906 		goto fail;
   1907 	}
   1908 	p->slotlist = xcalloc(p->nslots, sizeof(CK_SLOT_ID));
   1909 	if ((rv = f->C_GetSlotList(CK_TRUE, p->slotlist, &p->nslots))
   1910 	    != CKR_OK) {
   1911 		error("C_GetSlotList for provider %s failed: %lu",
   1912 		    provider_id, rv);
   1913 		goto fail;
   1914 	}
   1915 	p->slotinfo = xcalloc(p->nslots, sizeof(struct pkcs11_slotinfo));
   1916 	p->valid = 1;
   1917 	nkeys = 0;
   1918 	for (i = 0; i < p->nslots; i++) {
   1919 		token = &p->slotinfo[i].token;
   1920 		if ((rv = f->C_GetTokenInfo(p->slotlist[i], token))
   1921 		    != CKR_OK) {
   1922 			error("C_GetTokenInfo for provider %s slot %lu "
   1923 			    "failed: %lu", provider_id, (u_long)i, rv);
   1924 			continue;
   1925 		}
   1926 		if ((token->flags & CKF_TOKEN_INITIALIZED) == 0) {
   1927 			debug2_f("ignoring uninitialised token in "
   1928 			    "provider %s slot %lu", provider_id, (u_long)i);
   1929 			continue;
   1930 		}
   1931 		debug("provider %s slot %lu: label <%.*s> "
   1932 		    "manufacturerID <%.*s> model <%.*s> serial <%.*s> "
   1933 		    "flags 0x%lx",
   1934 		    provider_id, (unsigned long)i,
   1935 		    RMSPACE(token->label), RMSPACE(token->manufacturerID),
   1936 		    RMSPACE(token->model), RMSPACE(token->serialNumber),
   1937 		    token->flags);
   1938 		/*
   1939 		 * open session, login with pin and retrieve public
   1940 		 * keys (if keyp is provided)
   1941 		 */
   1942 		if ((ret = pkcs11_open_session(p, i, pin, user)) != 0 ||
   1943 		    keyp == NULL)
   1944 			continue;
   1945 		pkcs11_fetch_keys(p, i, keyp, labelsp, &nkeys);
   1946 #ifdef WITH_OPENSSL
   1947 		pkcs11_fetch_certs(p, i, keyp, labelsp, &nkeys);
   1948 #endif
   1949 		if (nkeys == 0 && !p->slotinfo[i].logged_in &&
   1950 		    pkcs11_interactive) {
   1951 			/*
   1952 			 * Some tokens require login before they will
   1953 			 * expose keys.
   1954 			 */
   1955 			if (pkcs11_login_slot(p, &p->slotinfo[i],
   1956 			    CKU_USER) < 0) {
   1957 				error("login failed");
   1958 				continue;
   1959 			}
   1960 			pkcs11_fetch_keys(p, i, keyp, labelsp, &nkeys);
   1961 #ifdef WITH_OPENSSL
   1962 			pkcs11_fetch_certs(p, i, keyp, labelsp, &nkeys);
   1963 #endif
   1964 		}
   1965 	}
   1966 
   1967 	/* now owned by caller */
   1968 	*providerp = p;
   1969 
   1970 	TAILQ_INSERT_TAIL(&pkcs11_providers, p, next);
   1971 	p->refcount++;	/* add to provider list */
   1972 
   1973 	return (nkeys);
   1974 fail:
   1975 	if (need_finalize && (rv = f->C_Finalize(NULL)) != CKR_OK)
   1976 		error("C_Finalize for provider %s failed: %lu",
   1977 		    provider_id, rv);
   1978 	if (p) {
   1979 		free(p->name);
   1980 		free(p->slotlist);
   1981 		free(p->slotinfo);
   1982 		free(p);
   1983 	}
   1984 	if (handle)
   1985 		dlclose(handle);
   1986 	if (ret > 0)
   1987 		ret = -1;
   1988 	return (ret);
   1989 }
   1990 
   1991 int
   1992 pkcs11_init(int interactive)
   1993 {
   1994 	debug3_f("called, interactive = %d", interactive);
   1995 
   1996 	pkcs11_interactive = interactive;
   1997 	TAILQ_INIT(&pkcs11_providers);
   1998 	TAILQ_INIT(&pkcs11_keys);
   1999 	return (0);
   2000 }
   2001 
   2002 /* unregister all providers, keys might still point to the providers */
   2003 void
   2004 pkcs11_terminate(void)
   2005 {
   2006 	struct pkcs11_provider *p;
   2007 	struct pkcs11_key *k11;
   2008 
   2009 	debug3_f("called");
   2010 
   2011 	while ((k11 = TAILQ_FIRST(&pkcs11_keys)) != NULL) {
   2012 		TAILQ_REMOVE(&pkcs11_keys, k11, next);
   2013 		pkcs11_k11_free(k11);
   2014 	}
   2015 	while ((p = TAILQ_FIRST(&pkcs11_providers)) != NULL) {
   2016 		TAILQ_REMOVE(&pkcs11_providers, p, next);
   2017 		pkcs11_provider_finalize(p);
   2018 		pkcs11_provider_unref(p);
   2019 	}
   2020 }
   2021 
   2022 /*
   2023  * register a new provider and get number of keys hold by the token,
   2024  * fails if provider already exists
   2025  */
   2026 int
   2027 pkcs11_add_provider(char *provider_id, char *pin, struct sshkey ***keyp,
   2028     char ***labelsp)
   2029 {
   2030 	struct pkcs11_provider *p = NULL;
   2031 	int nkeys;
   2032 
   2033 	nkeys = pkcs11_register_provider(provider_id, pin, keyp, labelsp,
   2034 	    &p, CKU_USER);
   2035 
   2036 	/* no keys found or some other error, de-register provider */
   2037 	if (nkeys <= 0 && p != NULL) {
   2038 		TAILQ_REMOVE(&pkcs11_providers, p, next);
   2039 		pkcs11_provider_finalize(p);
   2040 		pkcs11_provider_unref(p);
   2041 	}
   2042 	if (nkeys == 0)
   2043 		debug_f("provider %s returned no keys", provider_id);
   2044 
   2045 	return (nkeys);
   2046 }
   2047 
   2048 int
   2049 pkcs11_sign(struct sshkey *key,
   2050     u_char **sigp, size_t *lenp,
   2051     const u_char *data, size_t datalen,
   2052     const char *alg, const char *sk_provider,
   2053     const char *sk_pin, u_int compat)
   2054 {
   2055 	switch (key->type) {
   2056 #ifdef WITH_OPENSSL
   2057 	case KEY_RSA:
   2058 	case KEY_RSA_CERT:
   2059 		return pkcs11_sign_rsa(key, sigp, lenp, data, datalen,
   2060 		    alg, sk_provider, sk_pin, compat);
   2061 	case KEY_ECDSA:
   2062 	case KEY_ECDSA_CERT:
   2063 		return pkcs11_sign_ecdsa(key, sigp, lenp, data, datalen,
   2064 		    alg, sk_provider, sk_pin, compat);
   2065 #endif /* WITH_OPENSSL */
   2066 	case KEY_ED25519:
   2067 	case KEY_ED25519_CERT:
   2068 		return pkcs11_sign_ed25519(key, sigp, lenp, data, datalen,
   2069 		    alg, sk_provider, sk_pin, compat);
   2070 	default:
   2071 		return SSH_ERR_KEY_TYPE_UNKNOWN;
   2072 	}
   2073 }
   2074 
   2075 void
   2076 pkcs11_key_free(struct sshkey *key)
   2077 {
   2078 	/* never called */
   2079 }
   2080 
   2081 #ifdef WITH_PKCS11_KEYGEN
   2082 struct sshkey *
   2083 pkcs11_gakp(char *provider_id, char *pin, unsigned int slotidx, char *label,
   2084     unsigned int type, unsigned int bits, unsigned char keyid, uint32_t *err)
   2085 {
   2086 	struct pkcs11_provider	*p = NULL;
   2087 	struct pkcs11_slotinfo	*si;
   2088 	CK_FUNCTION_LIST	*f;
   2089 	CK_SESSION_HANDLE	 session;
   2090 	struct sshkey		*k = NULL;
   2091 	int			 ret = -1, reset_pin = 0, reset_provider = 0;
   2092 	CK_RV			 rv;
   2093 
   2094 	*err = 0;
   2095 
   2096 	if ((p = pkcs11_provider_lookup(provider_id)) != NULL)
   2097 		debug_f("provider \"%s\" available", provider_id);
   2098 	else if ((ret = pkcs11_register_provider(provider_id, pin, NULL, NULL,
   2099 	    &p, CKU_SO)) < 0) {
   2100 		debug_f("could not register provider %s", provider_id);
   2101 		goto out;
   2102 	} else
   2103 		reset_provider = 1;
   2104 
   2105 	f = p->function_list;
   2106 	si = &p->slotinfo[slotidx];
   2107 	session = si->session;
   2108 
   2109 	if ((rv = f->C_SetOperationState(session , pin, strlen(pin),
   2110 	    CK_INVALID_HANDLE, CK_INVALID_HANDLE)) != CKR_OK) {
   2111 		debug_f("could not supply SO pin: %lu", rv);
   2112 		reset_pin = 0;
   2113 	} else
   2114 		reset_pin = 1;
   2115 
   2116 	switch (type) {
   2117 	case KEY_RSA:
   2118 		if ((k = pkcs11_rsa_generate_private_key(p, slotidx, label,
   2119 		    bits, keyid, err)) == NULL) {
   2120 			debug_f("failed to generate RSA key");
   2121 			goto out;
   2122 		}
   2123 		break;
   2124 	case KEY_ECDSA:
   2125 		if ((k = pkcs11_ecdsa_generate_private_key(p, slotidx, label,
   2126 		    bits, keyid, err)) == NULL) {
   2127 			debug_f("failed to generate ECDSA key");
   2128 			goto out;
   2129 		}
   2130 		break;
   2131 	default:
   2132 		*err = SSH_PKCS11_ERR_GENERIC;
   2133 		debug_f("unknown type %d", type);
   2134 		goto out;
   2135 	}
   2136 
   2137 out:
   2138 	if (reset_pin)
   2139 		f->C_SetOperationState(session , NULL, 0, CK_INVALID_HANDLE,
   2140 		    CK_INVALID_HANDLE);
   2141 
   2142 	if (reset_provider)
   2143 		pkcs11_del_provider(provider_id);
   2144 
   2145 	return (k);
   2146 }
   2147 
   2148 struct sshkey *
   2149 pkcs11_destroy_keypair(char *provider_id, char *pin, unsigned long slotidx,
   2150     unsigned char keyid, uint32_t *err)
   2151 {
   2152 	struct pkcs11_provider	*p = NULL;
   2153 	struct pkcs11_slotinfo	*si;
   2154 	struct sshkey		*k = NULL;
   2155 	int			 reset_pin = 0, reset_provider = 0;
   2156 	CK_ULONG		 nattrs;
   2157 	CK_FUNCTION_LIST	*f;
   2158 	CK_SESSION_HANDLE	 session;
   2159 	CK_ATTRIBUTE		 attrs[16];
   2160 	CK_OBJECT_CLASS		 key_class;
   2161 	CK_KEY_TYPE		 key_type;
   2162 	CK_OBJECT_HANDLE	 obj = CK_INVALID_HANDLE;
   2163 	CK_RV			 rv;
   2164 
   2165 	*err = 0;
   2166 
   2167 	if ((p = pkcs11_provider_lookup(provider_id)) != NULL) {
   2168 		debug_f("using provider \"%s\"", provider_id);
   2169 	} else if (pkcs11_register_provider(provider_id, pin, NULL, NULL, &p,
   2170 	    CKU_SO) < 0) {
   2171 		debug_f("could not register provider %s",
   2172 		    provider_id);
   2173 		goto out;
   2174 	} else
   2175 		reset_provider = 1;
   2176 
   2177 	f = p->function_list;
   2178 	si = &p->slotinfo[slotidx];
   2179 	session = si->session;
   2180 
   2181 	if ((rv = f->C_SetOperationState(session , pin, strlen(pin),
   2182 	    CK_INVALID_HANDLE, CK_INVALID_HANDLE)) != CKR_OK) {
   2183 		debug_f("could not supply SO pin: %lu", rv);
   2184 		reset_pin = 0;
   2185 	} else
   2186 		reset_pin = 1;
   2187 
   2188 	/* private key */
   2189 	nattrs = 0;
   2190 	key_class = CKO_PRIVATE_KEY;
   2191 	FILL_ATTR(attrs, nattrs, CKA_CLASS, &key_class, sizeof(key_class));
   2192 	FILL_ATTR(attrs, nattrs, CKA_ID, &keyid, sizeof(keyid));
   2193 
   2194 	if (pkcs11_find(p, slotidx, attrs, nattrs, &obj) == 0 &&
   2195 	    obj != CK_INVALID_HANDLE) {
   2196 		if ((rv = f->C_DestroyObject(session, obj)) != CKR_OK) {
   2197 			debug_f("could not destroy private key 0x%hhx",
   2198 			    keyid);
   2199 			*err = rv;
   2200 			goto out;
   2201 		}
   2202 	}
   2203 
   2204 	/* public key */
   2205 	nattrs = 0;
   2206 	key_class = CKO_PUBLIC_KEY;
   2207 	FILL_ATTR(attrs, nattrs, CKA_CLASS, &key_class, sizeof(key_class));
   2208 	FILL_ATTR(attrs, nattrs, CKA_ID, &keyid, sizeof(keyid));
   2209 
   2210 	if (pkcs11_find(p, slotidx, attrs, nattrs, &obj) == 0 &&
   2211 	    obj != CK_INVALID_HANDLE) {
   2212 
   2213 		/* get key type */
   2214 		nattrs = 0;
   2215 		FILL_ATTR(attrs, nattrs, CKA_KEY_TYPE, &key_type,
   2216 		    sizeof(key_type));
   2217 		rv = f->C_GetAttributeValue(session, obj, attrs, nattrs);
   2218 		if (rv != CKR_OK) {
   2219 			debug_f("could not get key type of public key 0x%hhx",
   2220 			    keyid);
   2221 			*err = rv;
   2222 			key_type = -1;
   2223 		}
   2224 		switch (key_type) {
   2225 		case CKK_RSA:
   2226 			k = pkcs11_fetch_rsa_pubkey(p, slotidx, &obj);
   2227 			break;
   2228 		case CKK_ECDSA:
   2229 			k = pkcs11_fetch_ecdsa_pubkey(p, slotidx, &obj);
   2230 			break;
   2231 		case CKK_EC_EDWARDS:
   2232 			k = pkcs11_fetch_ed25519_pubkey(p, slotidx, &obj);
   2233 			break;
   2234 		default:
   2235 			debug_f("unsupported key type %lu", (u_long)key_type);
   2236 			break;
   2237 		}
   2238 
   2239 		if ((rv = f->C_DestroyObject(session, obj)) != CKR_OK) {
   2240 			debug_f("could not destroy public key 0x%hhx", keyid);
   2241 			*err = rv;
   2242 			goto out;
   2243 		}
   2244 	}
   2245 
   2246 out:
   2247 	if (reset_pin)
   2248 		f->C_SetOperationState(session , NULL, 0, CK_INVALID_HANDLE,
   2249 		    CK_INVALID_HANDLE);
   2250 
   2251 	if (reset_provider)
   2252 		pkcs11_del_provider(provider_id);
   2253 
   2254 	return (k);
   2255 }
   2256 #endif /* WITH_PKCS11_KEYGEN */
   2257 #else
   2258 int
   2259 pkcs11_add_provider(char *provider_id, char *pin, struct sshkey ***keyp,
   2260     char ***labelsp)
   2261 {
   2262 	error("dlopen() not supported");
   2263 	return (-1);
   2264 }
   2265 #endif /* HAVE_DLOPEN */
   2266