xref: /openbsd/usr.bin/ssh/ssh-pkcs11.c (revision 479c151d)
1*479c151dSjsg /* $OpenBSD: ssh-pkcs11.c,v 1.64 2024/09/20 02:00:46 jsg Exp $ */
241503fafSmarkus /*
341503fafSmarkus  * Copyright (c) 2010 Markus Friedl.  All rights reserved.
421f43f82Sdjm  * Copyright (c) 2014 Pedro Martelletto. All rights reserved.
541503fafSmarkus  *
641503fafSmarkus  * Permission to use, copy, modify, and distribute this software for any
741503fafSmarkus  * purpose with or without fee is hereby granted, provided that the above
841503fafSmarkus  * copyright notice and this permission notice appear in all copies.
941503fafSmarkus  *
1041503fafSmarkus  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1141503fafSmarkus  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1241503fafSmarkus  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1341503fafSmarkus  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1441503fafSmarkus  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1541503fafSmarkus  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1641503fafSmarkus  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1741503fafSmarkus  */
1841503fafSmarkus 
1941503fafSmarkus #include <sys/types.h>
2041503fafSmarkus #include <sys/queue.h>
2141503fafSmarkus #include <stdarg.h>
2241503fafSmarkus #include <stdio.h>
2341503fafSmarkus 
2421f43f82Sdjm #include <ctype.h>
2541503fafSmarkus #include <string.h>
2641503fafSmarkus #include <dlfcn.h>
2741503fafSmarkus 
2821f43f82Sdjm #include <openssl/ecdsa.h>
2912770bd2Smarkus #include <openssl/x509.h>
3021f43f82Sdjm #include <openssl/err.h>
3112770bd2Smarkus 
3241503fafSmarkus #define CRYPTOKI_COMPAT
3341503fafSmarkus #include "pkcs11.h"
3441503fafSmarkus 
3541503fafSmarkus #include "log.h"
3641503fafSmarkus #include "misc.h"
372aa7d220Sdjm #include "sshkey.h"
3841503fafSmarkus #include "ssh-pkcs11.h"
39d176a5c8Sdjm #include "digest.h"
4041503fafSmarkus #include "xmalloc.h"
4141503fafSmarkus 
4241503fafSmarkus struct pkcs11_slotinfo {
4341503fafSmarkus 	CK_TOKEN_INFO		token;
4441503fafSmarkus 	CK_SESSION_HANDLE	session;
4541503fafSmarkus 	int			logged_in;
4641503fafSmarkus };
4741503fafSmarkus 
4841503fafSmarkus struct pkcs11_provider {
4941503fafSmarkus 	char			*name;
5041503fafSmarkus 	void			*handle;
5141503fafSmarkus 	CK_FUNCTION_LIST	*function_list;
5241503fafSmarkus 	CK_INFO			info;
5341503fafSmarkus 	CK_ULONG		nslots;
5441503fafSmarkus 	CK_SLOT_ID		*slotlist;
5541503fafSmarkus 	struct pkcs11_slotinfo	*slotinfo;
5641503fafSmarkus 	int			valid;
5741503fafSmarkus 	int			refcount;
5841503fafSmarkus 	TAILQ_ENTRY(pkcs11_provider) next;
5941503fafSmarkus };
6041503fafSmarkus 
6141503fafSmarkus TAILQ_HEAD(, pkcs11_provider) pkcs11_providers;
6241503fafSmarkus 
6341503fafSmarkus struct pkcs11_key {
6441503fafSmarkus 	struct pkcs11_provider	*provider;
6541503fafSmarkus 	CK_ULONG		slotidx;
6641503fafSmarkus 	char			*keyid;
6741503fafSmarkus 	int			keyid_len;
6841503fafSmarkus };
6941503fafSmarkus 
7041503fafSmarkus int pkcs11_interactive = 0;
7141503fafSmarkus 
7221f43f82Sdjm #ifdef HAVE_DLOPEN
7321f43f82Sdjm static void
ossl_error(const char * msg)7421f43f82Sdjm ossl_error(const char *msg)
7521f43f82Sdjm {
7621f43f82Sdjm 	unsigned long    e;
7721f43f82Sdjm 
7848e6b99dSdjm 	error_f("%s", msg);
7921f43f82Sdjm 	while ((e = ERR_get_error()) != 0)
8048e6b99dSdjm 		error_f("libcrypto error: %s", ERR_error_string(e, NULL));
8121f43f82Sdjm }
8221f43f82Sdjm #endif
8321f43f82Sdjm 
8441503fafSmarkus int
pkcs11_init(int interactive)8541503fafSmarkus pkcs11_init(int interactive)
8641503fafSmarkus {
8741503fafSmarkus 	pkcs11_interactive = interactive;
8841503fafSmarkus 	TAILQ_INIT(&pkcs11_providers);
8941503fafSmarkus 	return (0);
9041503fafSmarkus }
9141503fafSmarkus 
9241503fafSmarkus /*
9321f43f82Sdjm  * finalize a provider shared library, it's no longer usable.
9441503fafSmarkus  * however, there might still be keys referencing this provider,
9521f43f82Sdjm  * so the actual freeing of memory is handled by pkcs11_provider_unref().
9641503fafSmarkus  * this is called when a provider gets unregistered.
9741503fafSmarkus  */
9841503fafSmarkus static void
pkcs11_provider_finalize(struct pkcs11_provider * p)9941503fafSmarkus pkcs11_provider_finalize(struct pkcs11_provider *p)
10041503fafSmarkus {
10141503fafSmarkus 	CK_RV rv;
10241503fafSmarkus 	CK_ULONG i;
10341503fafSmarkus 
104efa52ff8Sdjm 	debug_f("provider \"%s\" refcount %d valid %d",
105efa52ff8Sdjm 	    p->name, p->refcount, p->valid);
10641503fafSmarkus 	if (!p->valid)
10741503fafSmarkus 		return;
10841503fafSmarkus 	for (i = 0; i < p->nslots; i++) {
10941503fafSmarkus 		if (p->slotinfo[i].session &&
11041503fafSmarkus 		    (rv = p->function_list->C_CloseSession(
11141503fafSmarkus 		    p->slotinfo[i].session)) != CKR_OK)
11241503fafSmarkus 			error("C_CloseSession failed: %lu", rv);
11341503fafSmarkus 	}
11441503fafSmarkus 	if ((rv = p->function_list->C_Finalize(NULL)) != CKR_OK)
11541503fafSmarkus 		error("C_Finalize failed: %lu", rv);
11641503fafSmarkus 	p->valid = 0;
11741503fafSmarkus 	p->function_list = NULL;
118cd71c241Sderaadt #ifdef HAVE_DLOPEN
11941503fafSmarkus 	dlclose(p->handle);
120cd71c241Sderaadt #endif
12141503fafSmarkus }
12241503fafSmarkus 
12341503fafSmarkus /*
12441503fafSmarkus  * remove a reference to the provider.
12541503fafSmarkus  * called when a key gets destroyed or when the provider is unregistered.
12641503fafSmarkus  */
12741503fafSmarkus static void
pkcs11_provider_unref(struct pkcs11_provider * p)12841503fafSmarkus pkcs11_provider_unref(struct pkcs11_provider *p)
12941503fafSmarkus {
130efa52ff8Sdjm 	debug_f("provider \"%s\" refcount %d", p->name, p->refcount);
13141503fafSmarkus 	if (--p->refcount <= 0) {
13241503fafSmarkus 		if (p->valid)
133efa52ff8Sdjm 			error_f("provider \"%s\" still valid", p->name);
13421f43f82Sdjm 		free(p->name);
1350d40fefdSdjm 		free(p->slotlist);
1360d40fefdSdjm 		free(p->slotinfo);
1370d40fefdSdjm 		free(p);
13841503fafSmarkus 	}
13941503fafSmarkus }
14041503fafSmarkus 
14141503fafSmarkus /* unregister all providers, keys might still point to the providers */
14241503fafSmarkus void
pkcs11_terminate(void)14341503fafSmarkus pkcs11_terminate(void)
14441503fafSmarkus {
14541503fafSmarkus 	struct pkcs11_provider *p;
14641503fafSmarkus 
14741503fafSmarkus 	while ((p = TAILQ_FIRST(&pkcs11_providers)) != NULL) {
14841503fafSmarkus 		TAILQ_REMOVE(&pkcs11_providers, p, next);
14941503fafSmarkus 		pkcs11_provider_finalize(p);
15041503fafSmarkus 		pkcs11_provider_unref(p);
15141503fafSmarkus 	}
15241503fafSmarkus }
15341503fafSmarkus 
15441503fafSmarkus /* lookup provider by name */
15541503fafSmarkus static struct pkcs11_provider *
pkcs11_provider_lookup(char * provider_id)15641503fafSmarkus pkcs11_provider_lookup(char *provider_id)
15741503fafSmarkus {
15841503fafSmarkus 	struct pkcs11_provider *p;
15941503fafSmarkus 
16041503fafSmarkus 	TAILQ_FOREACH(p, &pkcs11_providers, next) {
161efa52ff8Sdjm 		debug("check provider \"%s\"", p->name);
16241503fafSmarkus 		if (!strcmp(provider_id, p->name))
16341503fafSmarkus 			return (p);
16441503fafSmarkus 	}
16541503fafSmarkus 	return (NULL);
16641503fafSmarkus }
16741503fafSmarkus 
16841503fafSmarkus /* unregister provider by name */
16941503fafSmarkus int
pkcs11_del_provider(char * provider_id)17041503fafSmarkus pkcs11_del_provider(char *provider_id)
17141503fafSmarkus {
17241503fafSmarkus 	struct pkcs11_provider *p;
17341503fafSmarkus 
17441503fafSmarkus 	if ((p = pkcs11_provider_lookup(provider_id)) != NULL) {
17541503fafSmarkus 		TAILQ_REMOVE(&pkcs11_providers, p, next);
17641503fafSmarkus 		pkcs11_provider_finalize(p);
17741503fafSmarkus 		pkcs11_provider_unref(p);
17841503fafSmarkus 		return (0);
17941503fafSmarkus 	}
18041503fafSmarkus 	return (-1);
18141503fafSmarkus }
18241503fafSmarkus 
18321f43f82Sdjm #ifdef HAVE_DLOPEN
184dec222b5Sdjm static RSA_METHOD *rsa_method;
185dec222b5Sdjm static int rsa_idx = 0;
186dec222b5Sdjm static EC_KEY_METHOD *ec_key_method;
187dec222b5Sdjm static int ec_key_idx = 0;
188dec222b5Sdjm 
1891ab0eecfSdjm /* release a wrapped object */
1901ab0eecfSdjm static void
pkcs11_k11_free(void * parent,void * ptr,CRYPTO_EX_DATA * ad,int idx,long argl,void * argp)1911ab0eecfSdjm pkcs11_k11_free(void *parent, void *ptr, CRYPTO_EX_DATA *ad, int idx,
1921ab0eecfSdjm     long argl, void *argp)
19341503fafSmarkus {
1941ab0eecfSdjm 	struct pkcs11_key	*k11 = ptr;
19541503fafSmarkus 
19648e6b99dSdjm 	debug_f("parent %p ptr %p idx %d", parent, ptr, idx);
1971ab0eecfSdjm 	if (k11 == NULL)
1981ab0eecfSdjm 		return;
19941503fafSmarkus 	if (k11->provider)
20041503fafSmarkus 		pkcs11_provider_unref(k11->provider);
2010d40fefdSdjm 	free(k11->keyid);
2020d40fefdSdjm 	free(k11);
20341503fafSmarkus }
20441503fafSmarkus 
2052f7c3d34Smarkus /* find a single 'obj' for given attributes */
2062f7c3d34Smarkus static int
pkcs11_find(struct pkcs11_provider * p,CK_ULONG slotidx,CK_ATTRIBUTE * attr,CK_ULONG nattr,CK_OBJECT_HANDLE * obj)2072f7c3d34Smarkus pkcs11_find(struct pkcs11_provider *p, CK_ULONG slotidx, CK_ATTRIBUTE *attr,
2082f7c3d34Smarkus     CK_ULONG nattr, CK_OBJECT_HANDLE *obj)
2092f7c3d34Smarkus {
2102f7c3d34Smarkus 	CK_FUNCTION_LIST	*f;
2112f7c3d34Smarkus 	CK_SESSION_HANDLE	session;
2122f7c3d34Smarkus 	CK_ULONG		nfound = 0;
2132f7c3d34Smarkus 	CK_RV			rv;
2142f7c3d34Smarkus 	int			ret = -1;
2152f7c3d34Smarkus 
2162f7c3d34Smarkus 	f = p->function_list;
2172f7c3d34Smarkus 	session = p->slotinfo[slotidx].session;
2182f7c3d34Smarkus 	if ((rv = f->C_FindObjectsInit(session, attr, nattr)) != CKR_OK) {
2192f7c3d34Smarkus 		error("C_FindObjectsInit failed (nattr %lu): %lu", nattr, rv);
2202f7c3d34Smarkus 		return (-1);
2212f7c3d34Smarkus 	}
2222f7c3d34Smarkus 	if ((rv = f->C_FindObjects(session, obj, 1, &nfound)) != CKR_OK ||
2232f7c3d34Smarkus 	    nfound != 1) {
2242f7c3d34Smarkus 		debug("C_FindObjects failed (nfound %lu nattr %lu): %lu",
2252f7c3d34Smarkus 		    nfound, nattr, rv);
2262f7c3d34Smarkus 	} else
2272f7c3d34Smarkus 		ret = 0;
2282f7c3d34Smarkus 	if ((rv = f->C_FindObjectsFinal(session)) != CKR_OK)
2292f7c3d34Smarkus 		error("C_FindObjectsFinal failed: %lu", rv);
2302f7c3d34Smarkus 	return (ret);
2312f7c3d34Smarkus }
2322f7c3d34Smarkus 
23341503fafSmarkus static int
pkcs11_login_slot(struct pkcs11_provider * provider,struct pkcs11_slotinfo * si,CK_USER_TYPE type)234f69acb9aSdjm pkcs11_login_slot(struct pkcs11_provider *provider, struct pkcs11_slotinfo *si,
235f69acb9aSdjm     CK_USER_TYPE type)
2365a0bd427Sdjm {
2375a0bd427Sdjm 	char			*pin = NULL, prompt[1024];
2385a0bd427Sdjm 	CK_RV			 rv;
2395a0bd427Sdjm 
240f69acb9aSdjm 	if (provider == NULL || si == NULL || !provider->valid) {
2415a0bd427Sdjm 		error("no pkcs11 (valid) provider found");
2425a0bd427Sdjm 		return (-1);
2435a0bd427Sdjm 	}
2445a0bd427Sdjm 
2455a0bd427Sdjm 	if (!pkcs11_interactive) {
2465a0bd427Sdjm 		error("need pin entry%s",
2475a0bd427Sdjm 		    (si->token.flags & CKF_PROTECTED_AUTHENTICATION_PATH) ?
2485a0bd427Sdjm 		    " on reader keypad" : "");
2495a0bd427Sdjm 		return (-1);
2505a0bd427Sdjm 	}
2515a0bd427Sdjm 	if (si->token.flags & CKF_PROTECTED_AUTHENTICATION_PATH)
2525a0bd427Sdjm 		verbose("Deferring PIN entry to reader keypad.");
2535a0bd427Sdjm 	else {
2545a0bd427Sdjm 		snprintf(prompt, sizeof(prompt), "Enter PIN for '%s': ",
2555a0bd427Sdjm 		    si->token.label);
2565a0bd427Sdjm 		if ((pin = read_passphrase(prompt, RP_ALLOW_EOF)) == NULL) {
25748e6b99dSdjm 			debug_f("no pin specified");
2585a0bd427Sdjm 			return (-1);	/* bail out */
2595a0bd427Sdjm 		}
2605a0bd427Sdjm 	}
261f69acb9aSdjm 	rv = provider->function_list->C_Login(si->session, type, (u_char *)pin,
2625a0bd427Sdjm 	    (pin != NULL) ? strlen(pin) : 0);
2635a0bd427Sdjm 	if (pin != NULL)
2645a0bd427Sdjm 		freezero(pin, strlen(pin));
2651a9276bcSdjm 
2661a9276bcSdjm 	switch (rv) {
2671a9276bcSdjm 	case CKR_OK:
2681a9276bcSdjm 	case CKR_USER_ALREADY_LOGGED_IN:
2691a9276bcSdjm 		/* success */
2701a9276bcSdjm 		break;
2711a9276bcSdjm 	case CKR_PIN_LEN_RANGE:
2721a9276bcSdjm 		error("PKCS#11 login failed: PIN length out of range");
2731a9276bcSdjm 		return -1;
2741a9276bcSdjm 	case CKR_PIN_INCORRECT:
2751a9276bcSdjm 		error("PKCS#11 login failed: PIN incorrect");
2761a9276bcSdjm 		return -1;
2771a9276bcSdjm 	case CKR_PIN_LOCKED:
2781a9276bcSdjm 		error("PKCS#11 login failed: PIN locked");
2791a9276bcSdjm 		return -1;
2801a9276bcSdjm 	default:
2811a9276bcSdjm 		error("PKCS#11 login failed: error %lu", rv);
2821a9276bcSdjm 		return -1;
2835a0bd427Sdjm 	}
2845a0bd427Sdjm 	si->logged_in = 1;
2855a0bd427Sdjm 	return (0);
2865a0bd427Sdjm }
2875a0bd427Sdjm 
2885a0bd427Sdjm static int
pkcs11_login(struct pkcs11_key * k11,CK_USER_TYPE type)289f69acb9aSdjm pkcs11_login(struct pkcs11_key *k11, CK_USER_TYPE type)
290f69acb9aSdjm {
291f69acb9aSdjm 	if (k11 == NULL || k11->provider == NULL || !k11->provider->valid) {
292f69acb9aSdjm 		error("no pkcs11 (valid) provider found");
293f69acb9aSdjm 		return (-1);
294f69acb9aSdjm 	}
295f69acb9aSdjm 
296f69acb9aSdjm 	return pkcs11_login_slot(k11->provider,
297f69acb9aSdjm 	    &k11->provider->slotinfo[k11->slotidx], type);
298f69acb9aSdjm }
299f69acb9aSdjm 
300f69acb9aSdjm 
301f69acb9aSdjm static int
pkcs11_check_obj_bool_attrib(struct pkcs11_key * k11,CK_OBJECT_HANDLE obj,CK_ATTRIBUTE_TYPE type,int * val)3025a0bd427Sdjm pkcs11_check_obj_bool_attrib(struct pkcs11_key *k11, CK_OBJECT_HANDLE obj,
3035a0bd427Sdjm     CK_ATTRIBUTE_TYPE type, int *val)
3045a0bd427Sdjm {
3055a0bd427Sdjm 	struct pkcs11_slotinfo	*si;
3065a0bd427Sdjm 	CK_FUNCTION_LIST	*f;
3075a0bd427Sdjm 	CK_BBOOL		flag = 0;
3085a0bd427Sdjm 	CK_ATTRIBUTE		attr;
3095a0bd427Sdjm 	CK_RV			 rv;
3105a0bd427Sdjm 
3115a0bd427Sdjm 	*val = 0;
3125a0bd427Sdjm 
3135a0bd427Sdjm 	if (!k11->provider || !k11->provider->valid) {
3145a0bd427Sdjm 		error("no pkcs11 (valid) provider found");
3155a0bd427Sdjm 		return (-1);
3165a0bd427Sdjm 	}
3175a0bd427Sdjm 
3185a0bd427Sdjm 	f = k11->provider->function_list;
3195a0bd427Sdjm 	si = &k11->provider->slotinfo[k11->slotidx];
3205a0bd427Sdjm 
3215a0bd427Sdjm 	attr.type = type;
3225a0bd427Sdjm 	attr.pValue = &flag;
3235a0bd427Sdjm 	attr.ulValueLen = sizeof(flag);
3245a0bd427Sdjm 
3255a0bd427Sdjm 	rv = f->C_GetAttributeValue(si->session, obj, &attr, 1);
3265a0bd427Sdjm 	if (rv != CKR_OK) {
3275a0bd427Sdjm 		error("C_GetAttributeValue failed: %lu", rv);
3285a0bd427Sdjm 		return (-1);
3295a0bd427Sdjm 	}
3305a0bd427Sdjm 	*val = flag != 0;
331efa52ff8Sdjm 	debug_f("provider \"%s\" slot %lu object %lu: attrib %lu = %d",
332efa52ff8Sdjm 	    k11->provider->name, k11->slotidx, obj, type, *val);
3335a0bd427Sdjm 	return (0);
3345a0bd427Sdjm }
3355a0bd427Sdjm 
3365a0bd427Sdjm static int
pkcs11_get_key(struct pkcs11_key * k11,CK_MECHANISM_TYPE mech_type)33721f43f82Sdjm pkcs11_get_key(struct pkcs11_key *k11, CK_MECHANISM_TYPE mech_type)
33841503fafSmarkus {
33941503fafSmarkus 	struct pkcs11_slotinfo	*si;
34041503fafSmarkus 	CK_FUNCTION_LIST	*f;
34141503fafSmarkus 	CK_OBJECT_HANDLE	 obj;
34241503fafSmarkus 	CK_RV			 rv;
34321f43f82Sdjm 	CK_OBJECT_CLASS		 private_key_class;
34421f43f82Sdjm 	CK_BBOOL		 true_val;
34521f43f82Sdjm 	CK_MECHANISM		 mech;
34621f43f82Sdjm 	CK_ATTRIBUTE		 key_filter[3];
3475a0bd427Sdjm 	int			 always_auth = 0;
3485a0bd427Sdjm 	int			 did_login = 0;
34941503fafSmarkus 
35041503fafSmarkus 	if (!k11->provider || !k11->provider->valid) {
35121f43f82Sdjm 		error("no pkcs11 (valid) provider found");
35241503fafSmarkus 		return (-1);
35341503fafSmarkus 	}
35421f43f82Sdjm 
35541503fafSmarkus 	f = k11->provider->function_list;
35641503fafSmarkus 	si = &k11->provider->slotinfo[k11->slotidx];
35721f43f82Sdjm 
35841503fafSmarkus 	if ((si->token.flags & CKF_LOGIN_REQUIRED) && !si->logged_in) {
3595a0bd427Sdjm 		if (pkcs11_login(k11, CKU_USER) < 0) {
3605a0bd427Sdjm 			error("login failed");
36141503fafSmarkus 			return (-1);
36241503fafSmarkus 		}
3635a0bd427Sdjm 		did_login = 1;
36441503fafSmarkus 	}
36521f43f82Sdjm 
36621f43f82Sdjm 	memset(&key_filter, 0, sizeof(key_filter));
36721f43f82Sdjm 	private_key_class = CKO_PRIVATE_KEY;
36821f43f82Sdjm 	key_filter[0].type = CKA_CLASS;
36921f43f82Sdjm 	key_filter[0].pValue = &private_key_class;
37021f43f82Sdjm 	key_filter[0].ulValueLen = sizeof(private_key_class);
37121f43f82Sdjm 
37221f43f82Sdjm 	key_filter[1].type = CKA_ID;
37341503fafSmarkus 	key_filter[1].pValue = k11->keyid;
37441503fafSmarkus 	key_filter[1].ulValueLen = k11->keyid_len;
37521f43f82Sdjm 
37621f43f82Sdjm 	true_val = CK_TRUE;
37721f43f82Sdjm 	key_filter[2].type = CKA_SIGN;
37821f43f82Sdjm 	key_filter[2].pValue = &true_val;
37921f43f82Sdjm 	key_filter[2].ulValueLen = sizeof(true_val);
38021f43f82Sdjm 
3812f7c3d34Smarkus 	/* try to find object w/CKA_SIGN first, retry w/o */
3822f7c3d34Smarkus 	if (pkcs11_find(k11->provider, k11->slotidx, key_filter, 3, &obj) < 0 &&
3832f7c3d34Smarkus 	    pkcs11_find(k11->provider, k11->slotidx, key_filter, 2, &obj) < 0) {
3842f7c3d34Smarkus 		error("cannot find private key");
38521f43f82Sdjm 		return (-1);
38621f43f82Sdjm 	}
38721f43f82Sdjm 
38821f43f82Sdjm 	memset(&mech, 0, sizeof(mech));
38921f43f82Sdjm 	mech.mechanism = mech_type;
39021f43f82Sdjm 	mech.pParameter = NULL_PTR;
39121f43f82Sdjm 	mech.ulParameterLen = 0;
39221f43f82Sdjm 
39321f43f82Sdjm 	if ((rv = f->C_SignInit(si->session, &mech, obj)) != CKR_OK) {
39441503fafSmarkus 		error("C_SignInit failed: %lu", rv);
39521f43f82Sdjm 		return (-1);
39621f43f82Sdjm 	}
39721f43f82Sdjm 
3985a0bd427Sdjm 	pkcs11_check_obj_bool_attrib(k11, obj, CKA_ALWAYS_AUTHENTICATE,
3995a0bd427Sdjm 	    &always_auth); /* ignore errors here */
4005a0bd427Sdjm 	if (always_auth && !did_login) {
40148e6b99dSdjm 		debug_f("always-auth key");
4025a0bd427Sdjm 		if (pkcs11_login(k11, CKU_CONTEXT_SPECIFIC) < 0) {
4035a0bd427Sdjm 			error("login failed for always-auth key");
4045a0bd427Sdjm 			return (-1);
4055a0bd427Sdjm 		}
4065a0bd427Sdjm 	}
4075a0bd427Sdjm 
40821f43f82Sdjm 	return (0);
40921f43f82Sdjm }
41021f43f82Sdjm 
41121f43f82Sdjm /* openssl callback doing the actual signing operation */
41221f43f82Sdjm static int
pkcs11_rsa_private_encrypt(int flen,const u_char * from,u_char * to,RSA * rsa,int padding)41321f43f82Sdjm pkcs11_rsa_private_encrypt(int flen, const u_char *from, u_char *to, RSA *rsa,
41421f43f82Sdjm     int padding)
41521f43f82Sdjm {
41621f43f82Sdjm 	struct pkcs11_key	*k11;
41721f43f82Sdjm 	struct pkcs11_slotinfo	*si;
41821f43f82Sdjm 	CK_FUNCTION_LIST	*f;
41921f43f82Sdjm 	CK_ULONG		tlen = 0;
42021f43f82Sdjm 	CK_RV			rv;
42121f43f82Sdjm 	int			rval = -1;
42221f43f82Sdjm 
423dec222b5Sdjm 	if ((k11 = RSA_get_ex_data(rsa, rsa_idx)) == NULL) {
424efa52ff8Sdjm 		error("RSA_get_ex_data failed");
42521f43f82Sdjm 		return (-1);
42621f43f82Sdjm 	}
42721f43f82Sdjm 
42821f43f82Sdjm 	if (pkcs11_get_key(k11, CKM_RSA_PKCS) == -1) {
42921f43f82Sdjm 		error("pkcs11_get_key failed");
43021f43f82Sdjm 		return (-1);
43121f43f82Sdjm 	}
43221f43f82Sdjm 
43321f43f82Sdjm 	f = k11->provider->function_list;
43421f43f82Sdjm 	si = &k11->provider->slotinfo[k11->slotidx];
43541503fafSmarkus 	tlen = RSA_size(rsa);
43621f43f82Sdjm 
43721f43f82Sdjm 	/* XXX handle CKR_BUFFER_TOO_SMALL */
43841503fafSmarkus 	rv = f->C_Sign(si->session, (CK_BYTE *)from, flen, to, &tlen);
43941503fafSmarkus 	if (rv == CKR_OK)
44041503fafSmarkus 		rval = tlen;
44141503fafSmarkus 	else
44241503fafSmarkus 		error("C_Sign failed: %lu", rv);
44321f43f82Sdjm 
44441503fafSmarkus 	return (rval);
44541503fafSmarkus }
44641503fafSmarkus 
44741503fafSmarkus static int
pkcs11_rsa_private_decrypt(int flen,const u_char * from,u_char * to,RSA * rsa,int padding)44841503fafSmarkus pkcs11_rsa_private_decrypt(int flen, const u_char *from, u_char *to, RSA *rsa,
44941503fafSmarkus     int padding)
45041503fafSmarkus {
45141503fafSmarkus 	return (-1);
45241503fafSmarkus }
45341503fafSmarkus 
454de64df3dSdjm static int
pkcs11_rsa_start_wrapper(void)455de64df3dSdjm pkcs11_rsa_start_wrapper(void)
456de64df3dSdjm {
457de64df3dSdjm 	if (rsa_method != NULL)
458de64df3dSdjm 		return (0);
459de64df3dSdjm 	rsa_method = RSA_meth_dup(RSA_get_default_method());
460de64df3dSdjm 	if (rsa_method == NULL)
461de64df3dSdjm 		return (-1);
4621ab0eecfSdjm 	rsa_idx = RSA_get_ex_new_index(0, "ssh-pkcs11-rsa",
4631ab0eecfSdjm 	    NULL, NULL, pkcs11_k11_free);
4641ab0eecfSdjm 	if (rsa_idx == -1)
4651ab0eecfSdjm 		return (-1);
466de64df3dSdjm 	if (!RSA_meth_set1_name(rsa_method, "pkcs11") ||
467de64df3dSdjm 	    !RSA_meth_set_priv_enc(rsa_method, pkcs11_rsa_private_encrypt) ||
4681ab0eecfSdjm 	    !RSA_meth_set_priv_dec(rsa_method, pkcs11_rsa_private_decrypt)) {
46948e6b99dSdjm 		error_f("setup pkcs11 method failed");
470de64df3dSdjm 		return (-1);
471de64df3dSdjm 	}
472de64df3dSdjm 	return (0);
473de64df3dSdjm }
474de64df3dSdjm 
47541503fafSmarkus /* redirect private key operations for rsa key to pkcs11 token */
47641503fafSmarkus static int
pkcs11_rsa_wrap(struct pkcs11_provider * provider,CK_ULONG slotidx,CK_ATTRIBUTE * keyid_attrib,RSA * rsa)47741503fafSmarkus pkcs11_rsa_wrap(struct pkcs11_provider *provider, CK_ULONG slotidx,
47841503fafSmarkus     CK_ATTRIBUTE *keyid_attrib, RSA *rsa)
47941503fafSmarkus {
48041503fafSmarkus 	struct pkcs11_key	*k11;
481de64df3dSdjm 
482de64df3dSdjm 	if (pkcs11_rsa_start_wrapper() == -1)
483de64df3dSdjm 		return (-1);
48441503fafSmarkus 
48541503fafSmarkus 	k11 = xcalloc(1, sizeof(*k11));
48641503fafSmarkus 	k11->provider = provider;
48741503fafSmarkus 	provider->refcount++;	/* provider referenced by RSA key */
48841503fafSmarkus 	k11->slotidx = slotidx;
48941503fafSmarkus 	/* identify key object on smartcard */
49041503fafSmarkus 	k11->keyid_len = keyid_attrib->ulValueLen;
49114fcadb6Sdjm 	if (k11->keyid_len > 0) {
49241503fafSmarkus 		k11->keyid = xmalloc(k11->keyid_len);
49341503fafSmarkus 		memcpy(k11->keyid, keyid_attrib->pValue, k11->keyid_len);
49414fcadb6Sdjm 	}
495de64df3dSdjm 
4965411e769Sdjm 	if (RSA_set_method(rsa, rsa_method) != 1)
4975411e769Sdjm 		fatal_f("RSA_set_method failed");
4985411e769Sdjm 	if (RSA_set_ex_data(rsa, rsa_idx, k11) != 1)
4995411e769Sdjm 		fatal_f("RSA_set_ex_data failed");
50041503fafSmarkus 	return (0);
50141503fafSmarkus }
50241503fafSmarkus 
50321f43f82Sdjm /* openssl callback doing the actual signing operation */
50421f43f82Sdjm static ECDSA_SIG *
ecdsa_do_sign(const unsigned char * dgst,int dgst_len,const BIGNUM * inv,const BIGNUM * rp,EC_KEY * ec)50521f43f82Sdjm ecdsa_do_sign(const unsigned char *dgst, int dgst_len, const BIGNUM *inv,
50621f43f82Sdjm     const BIGNUM *rp, EC_KEY *ec)
50721f43f82Sdjm {
50821f43f82Sdjm 	struct pkcs11_key	*k11;
50921f43f82Sdjm 	struct pkcs11_slotinfo	*si;
51021f43f82Sdjm 	CK_FUNCTION_LIST	*f;
51121f43f82Sdjm 	CK_ULONG		siglen = 0, bnlen;
51221f43f82Sdjm 	CK_RV			rv;
51321f43f82Sdjm 	ECDSA_SIG		*ret = NULL;
51421f43f82Sdjm 	u_char			*sig;
5152d94b486Sdjm 	BIGNUM			*r = NULL, *s = NULL;
51621f43f82Sdjm 
517dec222b5Sdjm 	if ((k11 = EC_KEY_get_ex_data(ec, ec_key_idx)) == NULL) {
51847f132e2Stb 		ossl_error("EC_KEY_get_ex_data failed for ec");
51921f43f82Sdjm 		return (NULL);
52021f43f82Sdjm 	}
52121f43f82Sdjm 
52221f43f82Sdjm 	if (pkcs11_get_key(k11, CKM_ECDSA) == -1) {
52321f43f82Sdjm 		error("pkcs11_get_key failed");
52421f43f82Sdjm 		return (NULL);
52521f43f82Sdjm 	}
52621f43f82Sdjm 
52721f43f82Sdjm 	f = k11->provider->function_list;
52821f43f82Sdjm 	si = &k11->provider->slotinfo[k11->slotidx];
52921f43f82Sdjm 
53021f43f82Sdjm 	siglen = ECDSA_size(ec);
53121f43f82Sdjm 	sig = xmalloc(siglen);
53221f43f82Sdjm 
53321f43f82Sdjm 	/* XXX handle CKR_BUFFER_TOO_SMALL */
53421f43f82Sdjm 	rv = f->C_Sign(si->session, (CK_BYTE *)dgst, dgst_len, sig, &siglen);
53521f43f82Sdjm 	if (rv != CKR_OK) {
53621f43f82Sdjm 		error("C_Sign failed: %lu", rv);
53721f43f82Sdjm 		goto done;
53821f43f82Sdjm 	}
53921f43f82Sdjm 	if (siglen < 64 || siglen > 132 || siglen % 2) {
54047f132e2Stb 		error_f("bad signature length: %lu", (u_long)siglen);
54121f43f82Sdjm 		goto done;
54221f43f82Sdjm 	}
54321f43f82Sdjm 	bnlen = siglen/2;
54421f43f82Sdjm 	if ((ret = ECDSA_SIG_new()) == NULL) {
54521f43f82Sdjm 		error("ECDSA_SIG_new failed");
54621f43f82Sdjm 		goto done;
54721f43f82Sdjm 	}
5482d94b486Sdjm 	if ((r = BN_bin2bn(sig, bnlen, NULL)) == NULL ||
5492d94b486Sdjm 	    (s = BN_bin2bn(sig+bnlen, bnlen, NULL)) == NULL) {
55047f132e2Stb 		ossl_error("BN_bin2bn failed");
55121f43f82Sdjm 		ECDSA_SIG_free(ret);
55221f43f82Sdjm 		ret = NULL;
55321f43f82Sdjm 		goto done;
55421f43f82Sdjm 	}
5552d94b486Sdjm 	if (!ECDSA_SIG_set0(ret, r, s)) {
55648e6b99dSdjm 		error_f("ECDSA_SIG_set0 failed");
5572d94b486Sdjm 		ECDSA_SIG_free(ret);
5582d94b486Sdjm 		ret = NULL;
5592d94b486Sdjm 		goto done;
5602d94b486Sdjm 	}
5612d94b486Sdjm 	r = s = NULL; /* now owned by ret */
5622d94b486Sdjm 	/* success */
56321f43f82Sdjm  done:
5642d94b486Sdjm 	BN_free(r);
5652d94b486Sdjm 	BN_free(s);
56621f43f82Sdjm 	free(sig);
56721f43f82Sdjm 
56821f43f82Sdjm 	return (ret);
56921f43f82Sdjm }
57021f43f82Sdjm 
57121f43f82Sdjm static int
pkcs11_ecdsa_start_wrapper(void)57221f43f82Sdjm pkcs11_ecdsa_start_wrapper(void)
57321f43f82Sdjm {
57421f43f82Sdjm 	int (*orig_sign)(int, const unsigned char *, int, unsigned char *,
57521f43f82Sdjm 	    unsigned int *, const BIGNUM *, const BIGNUM *, EC_KEY *) = NULL;
57621f43f82Sdjm 
57721f43f82Sdjm 	if (ec_key_method != NULL)
57821f43f82Sdjm 		return (0);
579d4d5784cSdjm 	ec_key_idx = EC_KEY_get_ex_new_index(0, "ssh-pkcs11-ecdsa",
580d4d5784cSdjm 	    NULL, NULL, pkcs11_k11_free);
581d4d5784cSdjm 	if (ec_key_idx == -1)
582d4d5784cSdjm 		return (-1);
58321f43f82Sdjm 	ec_key_method = EC_KEY_METHOD_new(EC_KEY_OpenSSL());
58421f43f82Sdjm 	if (ec_key_method == NULL)
58521f43f82Sdjm 		return (-1);
58621f43f82Sdjm 	EC_KEY_METHOD_get_sign(ec_key_method, &orig_sign, NULL, NULL);
58721f43f82Sdjm 	EC_KEY_METHOD_set_sign(ec_key_method, orig_sign, NULL, ecdsa_do_sign);
58821f43f82Sdjm 	return (0);
58921f43f82Sdjm }
59021f43f82Sdjm 
59121f43f82Sdjm static int
pkcs11_ecdsa_wrap(struct pkcs11_provider * provider,CK_ULONG slotidx,CK_ATTRIBUTE * keyid_attrib,EC_KEY * ec)59221f43f82Sdjm pkcs11_ecdsa_wrap(struct pkcs11_provider *provider, CK_ULONG slotidx,
59321f43f82Sdjm     CK_ATTRIBUTE *keyid_attrib, EC_KEY *ec)
59421f43f82Sdjm {
59521f43f82Sdjm 	struct pkcs11_key	*k11;
59621f43f82Sdjm 
59721f43f82Sdjm 	if (pkcs11_ecdsa_start_wrapper() == -1)
59821f43f82Sdjm 		return (-1);
59921f43f82Sdjm 
60021f43f82Sdjm 	k11 = xcalloc(1, sizeof(*k11));
60121f43f82Sdjm 	k11->provider = provider;
60221f43f82Sdjm 	provider->refcount++;	/* provider referenced by ECDSA key */
60321f43f82Sdjm 	k11->slotidx = slotidx;
60421f43f82Sdjm 	/* identify key object on smartcard */
60521f43f82Sdjm 	k11->keyid_len = keyid_attrib->ulValueLen;
606a9f89e4dSdjm 	if (k11->keyid_len > 0) {
60721f43f82Sdjm 		k11->keyid = xmalloc(k11->keyid_len);
60821f43f82Sdjm 		memcpy(k11->keyid, keyid_attrib->pValue, k11->keyid_len);
609a9f89e4dSdjm 	}
6105411e769Sdjm 	if (EC_KEY_set_method(ec, ec_key_method) != 1)
6115411e769Sdjm 		fatal_f("EC_KEY_set_method failed");
6125411e769Sdjm 	if (EC_KEY_set_ex_data(ec, ec_key_idx, k11) != 1)
6135411e769Sdjm 		fatal_f("EC_KEY_set_ex_data failed");
61421f43f82Sdjm 
61521f43f82Sdjm 	return (0);
61621f43f82Sdjm }
61721f43f82Sdjm 
61841503fafSmarkus /* remove trailing spaces */
6192c6bff6fSdjm static char *
rmspace(u_char * buf,size_t len)6202d917344Sdjm rmspace(u_char *buf, size_t len)
62141503fafSmarkus {
62241503fafSmarkus 	size_t i;
62341503fafSmarkus 
6242c6bff6fSdjm 	if (len == 0)
6252c6bff6fSdjm 		return buf;
62641503fafSmarkus 	for (i = len - 1; i > 0; i--)
6272c6bff6fSdjm 		if (buf[i] == ' ')
62841503fafSmarkus 			buf[i] = '\0';
62941503fafSmarkus 		else
63041503fafSmarkus 			break;
6312c6bff6fSdjm 	return buf;
63241503fafSmarkus }
6332c6bff6fSdjm /* Used to printf fixed-width, space-padded, unterminated strings using %.*s */
6342c6bff6fSdjm #define RMSPACE(s) (int)sizeof(s), rmspace(s, sizeof(s))
63541503fafSmarkus 
63641503fafSmarkus /*
63741503fafSmarkus  * open a pkcs11 session and login if required.
63841503fafSmarkus  * if pin == NULL we delay login until key use
63941503fafSmarkus  */
64041503fafSmarkus static int
pkcs11_open_session(struct pkcs11_provider * p,CK_ULONG slotidx,char * pin,CK_ULONG user)64121f43f82Sdjm pkcs11_open_session(struct pkcs11_provider *p, CK_ULONG slotidx, char *pin,
64221f43f82Sdjm     CK_ULONG user)
64341503fafSmarkus {
64407a271d3Sdjm 	struct pkcs11_slotinfo	*si;
64541503fafSmarkus 	CK_FUNCTION_LIST	*f;
64607a271d3Sdjm 	CK_RV			rv;
64741503fafSmarkus 	CK_SESSION_HANDLE	session;
648c386cd63Sdjm 	int			login_required, ret;
64941503fafSmarkus 
65041503fafSmarkus 	f = p->function_list;
65107a271d3Sdjm 	si = &p->slotinfo[slotidx];
65207a271d3Sdjm 
65307a271d3Sdjm 	login_required = si->token.flags & CKF_LOGIN_REQUIRED;
65407a271d3Sdjm 
65507a271d3Sdjm 	/* fail early before opening session */
656c386cd63Sdjm 	if (login_required && !pkcs11_interactive &&
65743b779d4Sdjm 	    (pin == NULL || strlen(pin) == 0)) {
65841503fafSmarkus 		error("pin required");
65921f43f82Sdjm 		return (-SSH_PKCS11_ERR_PIN_REQUIRED);
66041503fafSmarkus 	}
66141503fafSmarkus 	if ((rv = f->C_OpenSession(p->slotlist[slotidx], CKF_RW_SESSION|
66207a271d3Sdjm 	    CKF_SERIAL_SESSION, NULL, NULL, &session)) != CKR_OK) {
66341503fafSmarkus 		error("C_OpenSession failed: %lu", rv);
66441503fafSmarkus 		return (-1);
66541503fafSmarkus 	}
666c386cd63Sdjm 	if (login_required && pin != NULL && strlen(pin) != 0) {
667c386cd63Sdjm 		rv = f->C_Login(session, user, (u_char *)pin, strlen(pin));
6684cfc4a70Sdjm 		if (rv != CKR_OK && rv != CKR_USER_ALREADY_LOGGED_IN) {
66941503fafSmarkus 			error("C_Login failed: %lu", rv);
67021f43f82Sdjm 			ret = (rv == CKR_PIN_LOCKED) ?
67121f43f82Sdjm 			    -SSH_PKCS11_ERR_PIN_LOCKED :
67221f43f82Sdjm 			    -SSH_PKCS11_ERR_LOGIN_FAIL;
67341503fafSmarkus 			if ((rv = f->C_CloseSession(session)) != CKR_OK)
67441503fafSmarkus 				error("C_CloseSession failed: %lu", rv);
67521f43f82Sdjm 			return (ret);
67641503fafSmarkus 		}
67707a271d3Sdjm 		si->logged_in = 1;
67841503fafSmarkus 	}
67907a271d3Sdjm 	si->session = session;
68041503fafSmarkus 	return (0);
68141503fafSmarkus }
68241503fafSmarkus 
68312770bd2Smarkus static int
pkcs11_key_included(struct sshkey *** keysp,int * nkeys,struct sshkey * key)6842aa7d220Sdjm pkcs11_key_included(struct sshkey ***keysp, int *nkeys, struct sshkey *key)
68512770bd2Smarkus {
68612770bd2Smarkus 	int i;
68712770bd2Smarkus 
68812770bd2Smarkus 	for (i = 0; i < *nkeys; i++)
6892aa7d220Sdjm 		if (sshkey_equal(key, (*keysp)[i]))
69012770bd2Smarkus 			return (1);
69112770bd2Smarkus 	return (0);
69212770bd2Smarkus }
69312770bd2Smarkus 
69421f43f82Sdjm static struct sshkey *
pkcs11_fetch_ecdsa_pubkey(struct pkcs11_provider * p,CK_ULONG slotidx,CK_OBJECT_HANDLE * obj)69521f43f82Sdjm pkcs11_fetch_ecdsa_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx,
69621f43f82Sdjm     CK_OBJECT_HANDLE *obj)
69721f43f82Sdjm {
69821f43f82Sdjm 	CK_ATTRIBUTE		 key_attr[3];
69921f43f82Sdjm 	CK_SESSION_HANDLE	 session;
70021f43f82Sdjm 	CK_FUNCTION_LIST	*f = NULL;
70121f43f82Sdjm 	CK_RV			 rv;
70260996112Sdjm 	ASN1_OCTET_STRING	*octet = NULL;
70321f43f82Sdjm 	EC_KEY			*ec = NULL;
70421f43f82Sdjm 	EC_GROUP		*group = NULL;
70521f43f82Sdjm 	struct sshkey		*key = NULL;
70621f43f82Sdjm 	const unsigned char	*attrp = NULL;
70721f43f82Sdjm 	int			 i;
70821f43f82Sdjm 	int			 nid;
70921f43f82Sdjm 
71021f43f82Sdjm 	memset(&key_attr, 0, sizeof(key_attr));
71121f43f82Sdjm 	key_attr[0].type = CKA_ID;
71221f43f82Sdjm 	key_attr[1].type = CKA_EC_POINT;
71321f43f82Sdjm 	key_attr[2].type = CKA_EC_PARAMS;
71421f43f82Sdjm 
71521f43f82Sdjm 	session = p->slotinfo[slotidx].session;
71621f43f82Sdjm 	f = p->function_list;
71721f43f82Sdjm 
71821f43f82Sdjm 	/* figure out size of the attributes */
71921f43f82Sdjm 	rv = f->C_GetAttributeValue(session, *obj, key_attr, 3);
72021f43f82Sdjm 	if (rv != CKR_OK) {
72121f43f82Sdjm 		error("C_GetAttributeValue failed: %lu", rv);
72221f43f82Sdjm 		return (NULL);
72321f43f82Sdjm 	}
72421f43f82Sdjm 
72521f43f82Sdjm 	/*
72621f43f82Sdjm 	 * Allow CKA_ID (always first attribute) to be empty, but
72721f43f82Sdjm 	 * ensure that none of the others are zero length.
72821f43f82Sdjm 	 * XXX assumes CKA_ID is always first.
72921f43f82Sdjm 	 */
73021f43f82Sdjm 	if (key_attr[1].ulValueLen == 0 ||
73121f43f82Sdjm 	    key_attr[2].ulValueLen == 0) {
73221f43f82Sdjm 		error("invalid attribute length");
73321f43f82Sdjm 		return (NULL);
73421f43f82Sdjm 	}
73521f43f82Sdjm 
73621f43f82Sdjm 	/* allocate buffers for attributes */
73721f43f82Sdjm 	for (i = 0; i < 3; i++)
73821f43f82Sdjm 		if (key_attr[i].ulValueLen > 0)
73921f43f82Sdjm 			key_attr[i].pValue = xcalloc(1, key_attr[i].ulValueLen);
74021f43f82Sdjm 
74121f43f82Sdjm 	/* retrieve ID, public point and curve parameters of EC key */
74221f43f82Sdjm 	rv = f->C_GetAttributeValue(session, *obj, key_attr, 3);
74321f43f82Sdjm 	if (rv != CKR_OK) {
74421f43f82Sdjm 		error("C_GetAttributeValue failed: %lu", rv);
74521f43f82Sdjm 		goto fail;
74621f43f82Sdjm 	}
74721f43f82Sdjm 
74821f43f82Sdjm 	ec = EC_KEY_new();
74921f43f82Sdjm 	if (ec == NULL) {
75021f43f82Sdjm 		error("EC_KEY_new failed");
75121f43f82Sdjm 		goto fail;
75221f43f82Sdjm 	}
75321f43f82Sdjm 
75421f43f82Sdjm 	attrp = key_attr[2].pValue;
75521f43f82Sdjm 	group = d2i_ECPKParameters(NULL, &attrp, key_attr[2].ulValueLen);
75621f43f82Sdjm 	if (group == NULL) {
75721f43f82Sdjm 		ossl_error("d2i_ECPKParameters failed");
75821f43f82Sdjm 		goto fail;
75921f43f82Sdjm 	}
76021f43f82Sdjm 
76121f43f82Sdjm 	if (EC_KEY_set_group(ec, group) == 0) {
76221f43f82Sdjm 		ossl_error("EC_KEY_set_group failed");
76321f43f82Sdjm 		goto fail;
76421f43f82Sdjm 	}
76521f43f82Sdjm 
76621f43f82Sdjm 	if (key_attr[1].ulValueLen <= 2) {
76721f43f82Sdjm 		error("CKA_EC_POINT too small");
76821f43f82Sdjm 		goto fail;
76921f43f82Sdjm 	}
77021f43f82Sdjm 
77160996112Sdjm 	attrp = key_attr[1].pValue;
77260996112Sdjm 	octet = d2i_ASN1_OCTET_STRING(NULL, &attrp, key_attr[1].ulValueLen);
77360996112Sdjm 	if (octet == NULL) {
77460996112Sdjm 		ossl_error("d2i_ASN1_OCTET_STRING failed");
77521f43f82Sdjm 		goto fail;
77621f43f82Sdjm 	}
77760996112Sdjm 	attrp = octet->data;
77860996112Sdjm 	if (o2i_ECPublicKey(&ec, &attrp, octet->length) == NULL) {
77960996112Sdjm 		ossl_error("o2i_ECPublicKey failed");
78060996112Sdjm 		goto fail;
78121f43f82Sdjm 	}
78221f43f82Sdjm 
78321f43f82Sdjm 	nid = sshkey_ecdsa_key_to_nid(ec);
78421f43f82Sdjm 	if (nid < 0) {
78521f43f82Sdjm 		error("couldn't get curve nid");
78621f43f82Sdjm 		goto fail;
78721f43f82Sdjm 	}
78821f43f82Sdjm 
78921f43f82Sdjm 	if (pkcs11_ecdsa_wrap(p, slotidx, &key_attr[0], ec))
79021f43f82Sdjm 		goto fail;
79121f43f82Sdjm 
79221f43f82Sdjm 	key = sshkey_new(KEY_UNSPEC);
79321f43f82Sdjm 	if (key == NULL) {
79421f43f82Sdjm 		error("sshkey_new failed");
79521f43f82Sdjm 		goto fail;
79621f43f82Sdjm 	}
79721f43f82Sdjm 
7985411e769Sdjm 	EVP_PKEY_free(key->pkey);
7995411e769Sdjm 	if ((key->pkey = EVP_PKEY_new()) == NULL)
8005411e769Sdjm 		fatal("EVP_PKEY_new failed");
8015411e769Sdjm 	if (EVP_PKEY_set1_EC_KEY(key->pkey, ec) != 1)
8025411e769Sdjm 		fatal("EVP_PKEY_set1_EC_KEY failed");
80321f43f82Sdjm 	key->ecdsa_nid = nid;
80421f43f82Sdjm 	key->type = KEY_ECDSA;
80521f43f82Sdjm 	key->flags |= SSHKEY_FLAG_EXT;
80621f43f82Sdjm 
80721f43f82Sdjm fail:
80821f43f82Sdjm 	for (i = 0; i < 3; i++)
80921f43f82Sdjm 		free(key_attr[i].pValue);
81021f43f82Sdjm 	if (ec)
81121f43f82Sdjm 		EC_KEY_free(ec);
81221f43f82Sdjm 	if (group)
81321f43f82Sdjm 		EC_GROUP_free(group);
81460996112Sdjm 	if (octet)
81560996112Sdjm 		ASN1_OCTET_STRING_free(octet);
81621f43f82Sdjm 
81721f43f82Sdjm 	return (key);
81821f43f82Sdjm }
81921f43f82Sdjm 
82021f43f82Sdjm static struct sshkey *
pkcs11_fetch_rsa_pubkey(struct pkcs11_provider * p,CK_ULONG slotidx,CK_OBJECT_HANDLE * obj)82121f43f82Sdjm pkcs11_fetch_rsa_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx,
82221f43f82Sdjm     CK_OBJECT_HANDLE *obj)
82321f43f82Sdjm {
82421f43f82Sdjm 	CK_ATTRIBUTE		 key_attr[3];
82521f43f82Sdjm 	CK_SESSION_HANDLE	 session;
82621f43f82Sdjm 	CK_FUNCTION_LIST	*f = NULL;
82721f43f82Sdjm 	CK_RV			 rv;
82821f43f82Sdjm 	RSA			*rsa = NULL;
82921f43f82Sdjm 	BIGNUM			*rsa_n, *rsa_e;
83021f43f82Sdjm 	struct sshkey		*key = NULL;
83121f43f82Sdjm 	int			 i;
83221f43f82Sdjm 
83321f43f82Sdjm 	memset(&key_attr, 0, sizeof(key_attr));
83421f43f82Sdjm 	key_attr[0].type = CKA_ID;
83521f43f82Sdjm 	key_attr[1].type = CKA_MODULUS;
83621f43f82Sdjm 	key_attr[2].type = CKA_PUBLIC_EXPONENT;
83721f43f82Sdjm 
83821f43f82Sdjm 	session = p->slotinfo[slotidx].session;
83921f43f82Sdjm 	f = p->function_list;
84021f43f82Sdjm 
84121f43f82Sdjm 	/* figure out size of the attributes */
84221f43f82Sdjm 	rv = f->C_GetAttributeValue(session, *obj, key_attr, 3);
84321f43f82Sdjm 	if (rv != CKR_OK) {
84421f43f82Sdjm 		error("C_GetAttributeValue failed: %lu", rv);
84521f43f82Sdjm 		return (NULL);
84621f43f82Sdjm 	}
84721f43f82Sdjm 
84821f43f82Sdjm 	/*
84921f43f82Sdjm 	 * Allow CKA_ID (always first attribute) to be empty, but
85021f43f82Sdjm 	 * ensure that none of the others are zero length.
85121f43f82Sdjm 	 * XXX assumes CKA_ID is always first.
85221f43f82Sdjm 	 */
85321f43f82Sdjm 	if (key_attr[1].ulValueLen == 0 ||
85421f43f82Sdjm 	    key_attr[2].ulValueLen == 0) {
85521f43f82Sdjm 		error("invalid attribute length");
85621f43f82Sdjm 		return (NULL);
85721f43f82Sdjm 	}
85821f43f82Sdjm 
85921f43f82Sdjm 	/* allocate buffers for attributes */
86021f43f82Sdjm 	for (i = 0; i < 3; i++)
86121f43f82Sdjm 		if (key_attr[i].ulValueLen > 0)
86221f43f82Sdjm 			key_attr[i].pValue = xcalloc(1, key_attr[i].ulValueLen);
86321f43f82Sdjm 
86421f43f82Sdjm 	/* retrieve ID, modulus and public exponent of RSA key */
86521f43f82Sdjm 	rv = f->C_GetAttributeValue(session, *obj, key_attr, 3);
86621f43f82Sdjm 	if (rv != CKR_OK) {
86721f43f82Sdjm 		error("C_GetAttributeValue failed: %lu", rv);
86821f43f82Sdjm 		goto fail;
86921f43f82Sdjm 	}
87021f43f82Sdjm 
87121f43f82Sdjm 	rsa = RSA_new();
87221f43f82Sdjm 	if (rsa == NULL) {
87321f43f82Sdjm 		error("RSA_new failed");
87421f43f82Sdjm 		goto fail;
87521f43f82Sdjm 	}
87621f43f82Sdjm 
87721f43f82Sdjm 	rsa_n = BN_bin2bn(key_attr[1].pValue, key_attr[1].ulValueLen, NULL);
87821f43f82Sdjm 	rsa_e = BN_bin2bn(key_attr[2].pValue, key_attr[2].ulValueLen, NULL);
87921f43f82Sdjm 	if (rsa_n == NULL || rsa_e == NULL) {
88021f43f82Sdjm 		error("BN_bin2bn failed");
88121f43f82Sdjm 		goto fail;
88221f43f82Sdjm 	}
88321f43f82Sdjm 	if (!RSA_set0_key(rsa, rsa_n, rsa_e, NULL))
88448e6b99dSdjm 		fatal_f("set key");
88521f43f82Sdjm 	rsa_n = rsa_e = NULL; /* transferred */
88621f43f82Sdjm 
88721f43f82Sdjm 	if (pkcs11_rsa_wrap(p, slotidx, &key_attr[0], rsa))
88821f43f82Sdjm 		goto fail;
88921f43f82Sdjm 
89021f43f82Sdjm 	key = sshkey_new(KEY_UNSPEC);
89121f43f82Sdjm 	if (key == NULL) {
89221f43f82Sdjm 		error("sshkey_new failed");
89321f43f82Sdjm 		goto fail;
89421f43f82Sdjm 	}
89521f43f82Sdjm 
8965411e769Sdjm 	EVP_PKEY_free(key->pkey);
8975411e769Sdjm 	if ((key->pkey = EVP_PKEY_new()) == NULL)
8985411e769Sdjm 		fatal("EVP_PKEY_new failed");
8995411e769Sdjm 	if (EVP_PKEY_set1_RSA(key->pkey, rsa) != 1)
9005411e769Sdjm 		fatal("EVP_PKEY_set1_RSA failed");
90121f43f82Sdjm 	key->type = KEY_RSA;
90221f43f82Sdjm 	key->flags |= SSHKEY_FLAG_EXT;
90321f43f82Sdjm 
90421f43f82Sdjm fail:
90521f43f82Sdjm 	for (i = 0; i < 3; i++)
90621f43f82Sdjm 		free(key_attr[i].pValue);
90721f43f82Sdjm 	RSA_free(rsa);
90821f43f82Sdjm 
90921f43f82Sdjm 	return (key);
91021f43f82Sdjm }
91121f43f82Sdjm 
91244e54ccbSdjm static int
pkcs11_fetch_x509_pubkey(struct pkcs11_provider * p,CK_ULONG slotidx,CK_OBJECT_HANDLE * obj,struct sshkey ** keyp,char ** labelp)91321f43f82Sdjm pkcs11_fetch_x509_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx,
91444e54ccbSdjm     CK_OBJECT_HANDLE *obj, struct sshkey **keyp, char **labelp)
91521f43f82Sdjm {
91621f43f82Sdjm 	CK_ATTRIBUTE		 cert_attr[3];
91721f43f82Sdjm 	CK_SESSION_HANDLE	 session;
91821f43f82Sdjm 	CK_FUNCTION_LIST	*f = NULL;
91921f43f82Sdjm 	CK_RV			 rv;
92021f43f82Sdjm 	X509			*x509 = NULL;
92144e54ccbSdjm 	X509_NAME		*x509_name = NULL;
92221f43f82Sdjm 	EVP_PKEY		*evp;
92321f43f82Sdjm 	RSA			*rsa = NULL;
92421f43f82Sdjm 	EC_KEY			*ec = NULL;
92521f43f82Sdjm 	struct sshkey		*key = NULL;
92621f43f82Sdjm 	int			 i;
92721f43f82Sdjm 	int			 nid;
92821f43f82Sdjm 	const u_char		*cp;
92944e54ccbSdjm 	char			*subject = NULL;
93044e54ccbSdjm 
93144e54ccbSdjm 	*keyp = NULL;
93244e54ccbSdjm 	*labelp = NULL;
93321f43f82Sdjm 
93421f43f82Sdjm 	memset(&cert_attr, 0, sizeof(cert_attr));
93521f43f82Sdjm 	cert_attr[0].type = CKA_ID;
93621f43f82Sdjm 	cert_attr[1].type = CKA_SUBJECT;
93721f43f82Sdjm 	cert_attr[2].type = CKA_VALUE;
93821f43f82Sdjm 
93921f43f82Sdjm 	session = p->slotinfo[slotidx].session;
94021f43f82Sdjm 	f = p->function_list;
94121f43f82Sdjm 
94221f43f82Sdjm 	/* figure out size of the attributes */
94321f43f82Sdjm 	rv = f->C_GetAttributeValue(session, *obj, cert_attr, 3);
94421f43f82Sdjm 	if (rv != CKR_OK) {
94521f43f82Sdjm 		error("C_GetAttributeValue failed: %lu", rv);
94644e54ccbSdjm 		return -1;
94721f43f82Sdjm 	}
94821f43f82Sdjm 
94921f43f82Sdjm 	/*
95021f43f82Sdjm 	 * Allow CKA_ID (always first attribute) to be empty, but
95121f43f82Sdjm 	 * ensure that none of the others are zero length.
95221f43f82Sdjm 	 * XXX assumes CKA_ID is always first.
95321f43f82Sdjm 	 */
95421f43f82Sdjm 	if (cert_attr[1].ulValueLen == 0 ||
95521f43f82Sdjm 	    cert_attr[2].ulValueLen == 0) {
95621f43f82Sdjm 		error("invalid attribute length");
95744e54ccbSdjm 		return -1;
95821f43f82Sdjm 	}
95921f43f82Sdjm 
96021f43f82Sdjm 	/* allocate buffers for attributes */
96121f43f82Sdjm 	for (i = 0; i < 3; i++)
96221f43f82Sdjm 		if (cert_attr[i].ulValueLen > 0)
96321f43f82Sdjm 			cert_attr[i].pValue = xcalloc(1, cert_attr[i].ulValueLen);
96421f43f82Sdjm 
96521f43f82Sdjm 	/* retrieve ID, subject and value of certificate */
96621f43f82Sdjm 	rv = f->C_GetAttributeValue(session, *obj, cert_attr, 3);
96721f43f82Sdjm 	if (rv != CKR_OK) {
96821f43f82Sdjm 		error("C_GetAttributeValue failed: %lu", rv);
96944e54ccbSdjm 		goto out;
97021f43f82Sdjm 	}
97121f43f82Sdjm 
97244e54ccbSdjm 	/* Decode DER-encoded cert subject */
973384b8b21Sdjm 	cp = cert_attr[1].pValue;
97444e54ccbSdjm 	if ((x509_name = d2i_X509_NAME(NULL, &cp,
97544e54ccbSdjm 	    cert_attr[1].ulValueLen)) == NULL ||
97644e54ccbSdjm 	    (subject = X509_NAME_oneline(x509_name, NULL, 0)) == NULL)
97744e54ccbSdjm 		subject = xstrdup("invalid subject");
97844e54ccbSdjm 	X509_NAME_free(x509_name);
97921f43f82Sdjm 
98021f43f82Sdjm 	cp = cert_attr[2].pValue;
98144e54ccbSdjm 	if ((x509 = d2i_X509(NULL, &cp, cert_attr[2].ulValueLen)) == NULL) {
98221f43f82Sdjm 		error("d2i_x509 failed");
98344e54ccbSdjm 		goto out;
98421f43f82Sdjm 	}
98521f43f82Sdjm 
98644e54ccbSdjm 	if ((evp = X509_get_pubkey(x509)) == NULL) {
98721f43f82Sdjm 		error("X509_get_pubkey failed");
98844e54ccbSdjm 		goto out;
98921f43f82Sdjm 	}
99021f43f82Sdjm 
99121f43f82Sdjm 	if (EVP_PKEY_base_id(evp) == EVP_PKEY_RSA) {
99221f43f82Sdjm 		if (EVP_PKEY_get0_RSA(evp) == NULL) {
99321f43f82Sdjm 			error("invalid x509; no rsa key");
99444e54ccbSdjm 			goto out;
99521f43f82Sdjm 		}
99621f43f82Sdjm 		if ((rsa = RSAPublicKey_dup(EVP_PKEY_get0_RSA(evp))) == NULL) {
99721f43f82Sdjm 			error("RSAPublicKey_dup failed");
99844e54ccbSdjm 			goto out;
99921f43f82Sdjm 		}
100021f43f82Sdjm 
100121f43f82Sdjm 		if (pkcs11_rsa_wrap(p, slotidx, &cert_attr[0], rsa))
100244e54ccbSdjm 			goto out;
100321f43f82Sdjm 
100421f43f82Sdjm 		key = sshkey_new(KEY_UNSPEC);
100521f43f82Sdjm 		if (key == NULL) {
100621f43f82Sdjm 			error("sshkey_new failed");
100744e54ccbSdjm 			goto out;
100821f43f82Sdjm 		}
100921f43f82Sdjm 
10105411e769Sdjm 		EVP_PKEY_free(key->pkey);
10115411e769Sdjm 		if ((key->pkey = EVP_PKEY_new()) == NULL)
10125411e769Sdjm 			fatal("EVP_PKEY_new failed");
10135411e769Sdjm 		if (EVP_PKEY_set1_RSA(key->pkey, rsa) != 1)
10145411e769Sdjm 			fatal("EVP_PKEY_set1_RSA failed");
101521f43f82Sdjm 		key->type = KEY_RSA;
101621f43f82Sdjm 		key->flags |= SSHKEY_FLAG_EXT;
101721f43f82Sdjm 	} else if (EVP_PKEY_base_id(evp) == EVP_PKEY_EC) {
1018ac22b3d0Sdjm 		if (EVP_PKEY_get0_EC_KEY(evp) == NULL) {
101921f43f82Sdjm 			error("invalid x509; no ec key");
102044e54ccbSdjm 			goto out;
102121f43f82Sdjm 		}
1022ac22b3d0Sdjm 		if ((ec = EC_KEY_dup(EVP_PKEY_get0_EC_KEY(evp))) == NULL) {
102321f43f82Sdjm 			error("EC_KEY_dup failed");
102444e54ccbSdjm 			goto out;
102521f43f82Sdjm 		}
102621f43f82Sdjm 
102721f43f82Sdjm 		nid = sshkey_ecdsa_key_to_nid(ec);
102821f43f82Sdjm 		if (nid < 0) {
102921f43f82Sdjm 			error("couldn't get curve nid");
103044e54ccbSdjm 			goto out;
103121f43f82Sdjm 		}
103221f43f82Sdjm 
103321f43f82Sdjm 		if (pkcs11_ecdsa_wrap(p, slotidx, &cert_attr[0], ec))
103444e54ccbSdjm 			goto out;
103521f43f82Sdjm 
103621f43f82Sdjm 		key = sshkey_new(KEY_UNSPEC);
103721f43f82Sdjm 		if (key == NULL) {
103821f43f82Sdjm 			error("sshkey_new failed");
103944e54ccbSdjm 			goto out;
104021f43f82Sdjm 		}
104121f43f82Sdjm 
10425411e769Sdjm 		EVP_PKEY_free(key->pkey);
10435411e769Sdjm 		if ((key->pkey = EVP_PKEY_new()) == NULL)
10445411e769Sdjm 			fatal("EVP_PKEY_new failed");
10455411e769Sdjm 		if (EVP_PKEY_set1_EC_KEY(key->pkey, ec) != 1)
10465411e769Sdjm 			fatal("EVP_PKEY_set1_EC_KEY failed");
104721f43f82Sdjm 		key->ecdsa_nid = nid;
104821f43f82Sdjm 		key->type = KEY_ECDSA;
104921f43f82Sdjm 		key->flags |= SSHKEY_FLAG_EXT;
105044e54ccbSdjm 	} else {
105121f43f82Sdjm 		error("unknown certificate key type");
105244e54ccbSdjm 		goto out;
105344e54ccbSdjm 	}
105444e54ccbSdjm  out:
105521f43f82Sdjm 	for (i = 0; i < 3; i++)
105621f43f82Sdjm 		free(cert_attr[i].pValue);
105721f43f82Sdjm 	X509_free(x509);
105821f43f82Sdjm 	RSA_free(rsa);
105921f43f82Sdjm 	EC_KEY_free(ec);
106044e54ccbSdjm 	if (key == NULL) {
106144e54ccbSdjm 		free(subject);
106244e54ccbSdjm 		return -1;
106344e54ccbSdjm 	}
106444e54ccbSdjm 	/* success */
106544e54ccbSdjm 	*keyp = key;
106644e54ccbSdjm 	*labelp = subject;
106744e54ccbSdjm 	return 0;
106821f43f82Sdjm }
106921f43f82Sdjm 
107021f43f82Sdjm #if 0
107112770bd2Smarkus static int
10727c94020aSdjm have_rsa_key(const RSA *rsa)
10737c94020aSdjm {
10747c94020aSdjm 	const BIGNUM *rsa_n, *rsa_e;
10757c94020aSdjm 
10767c94020aSdjm 	RSA_get0_key(rsa, &rsa_n, &rsa_e, NULL);
10777c94020aSdjm 	return rsa_n != NULL && rsa_e != NULL;
10787c94020aSdjm }
107921f43f82Sdjm #endif
10807c94020aSdjm 
1081d176a5c8Sdjm static void
note_key(struct pkcs11_provider * p,CK_ULONG slotidx,const char * context,struct sshkey * key)1082d176a5c8Sdjm note_key(struct pkcs11_provider *p, CK_ULONG slotidx, const char *context,
1083d176a5c8Sdjm     struct sshkey *key)
1084d176a5c8Sdjm {
1085d176a5c8Sdjm 	char *fp;
1086d176a5c8Sdjm 
1087d176a5c8Sdjm 	if ((fp = sshkey_fingerprint(key, SSH_FP_HASH_DEFAULT,
1088d176a5c8Sdjm 	    SSH_FP_DEFAULT)) == NULL) {
1089d176a5c8Sdjm 		error_f("sshkey_fingerprint failed");
1090d176a5c8Sdjm 		return;
1091d176a5c8Sdjm 	}
1092d176a5c8Sdjm 	debug2("%s: provider %s slot %lu: %s %s", context, p->name,
1093d176a5c8Sdjm 	    (u_long)slotidx, sshkey_type(key), fp);
1094d176a5c8Sdjm 	free(fp);
1095d176a5c8Sdjm }
1096d176a5c8Sdjm 
109721f43f82Sdjm /*
109821f43f82Sdjm  * lookup certificates for token in slot identified by slotidx,
109921f43f82Sdjm  * add 'wrapped' public keys to the 'keysp' array and increment nkeys.
110021f43f82Sdjm  * keysp points to an (possibly empty) array with *nkeys keys.
110121f43f82Sdjm  */
11027c94020aSdjm static int
pkcs11_fetch_certs(struct pkcs11_provider * p,CK_ULONG slotidx,struct sshkey *** keysp,char *** labelsp,int * nkeys)110321f43f82Sdjm pkcs11_fetch_certs(struct pkcs11_provider *p, CK_ULONG slotidx,
110444e54ccbSdjm     struct sshkey ***keysp, char ***labelsp, int *nkeys)
110541503fafSmarkus {
110621f43f82Sdjm 	struct sshkey		*key = NULL;
110721f43f82Sdjm 	CK_OBJECT_CLASS		 key_class;
110821f43f82Sdjm 	CK_ATTRIBUTE		 key_attr[1];
110921f43f82Sdjm 	CK_SESSION_HANDLE	 session;
111021f43f82Sdjm 	CK_FUNCTION_LIST	*f = NULL;
111141503fafSmarkus 	CK_RV			 rv;
111241503fafSmarkus 	CK_OBJECT_HANDLE	 obj;
111321f43f82Sdjm 	CK_ULONG		 n = 0;
111421f43f82Sdjm 	int			 ret = -1;
111544e54ccbSdjm 	char			*label;
111641503fafSmarkus 
111721f43f82Sdjm 	memset(&key_attr, 0, sizeof(key_attr));
111821f43f82Sdjm 	memset(&obj, 0, sizeof(obj));
111921f43f82Sdjm 
112021f43f82Sdjm 	key_class = CKO_CERTIFICATE;
112121f43f82Sdjm 	key_attr[0].type = CKA_CLASS;
112221f43f82Sdjm 	key_attr[0].pValue = &key_class;
112321f43f82Sdjm 	key_attr[0].ulValueLen = sizeof(key_class);
112421f43f82Sdjm 
112541503fafSmarkus 	session = p->slotinfo[slotidx].session;
112621f43f82Sdjm 	f = p->function_list;
112721f43f82Sdjm 
112821f43f82Sdjm 	rv = f->C_FindObjectsInit(session, key_attr, 1);
112921f43f82Sdjm 	if (rv != CKR_OK) {
113041503fafSmarkus 		error("C_FindObjectsInit failed: %lu", rv);
113121f43f82Sdjm 		goto fail;
113241503fafSmarkus 	}
113321f43f82Sdjm 
113441503fafSmarkus 	while (1) {
113521f43f82Sdjm 		CK_CERTIFICATE_TYPE	ck_cert_type;
113621f43f82Sdjm 
113721f43f82Sdjm 		rv = f->C_FindObjects(session, &obj, 1, &n);
113821f43f82Sdjm 		if (rv != CKR_OK) {
113921f43f82Sdjm 			error("C_FindObjects failed: %lu", rv);
114021f43f82Sdjm 			goto fail;
114141503fafSmarkus 		}
114221f43f82Sdjm 		if (n == 0)
114341503fafSmarkus 			break;
114421f43f82Sdjm 
114521f43f82Sdjm 		memset(&ck_cert_type, 0, sizeof(ck_cert_type));
114621f43f82Sdjm 		memset(&key_attr, 0, sizeof(key_attr));
114721f43f82Sdjm 		key_attr[0].type = CKA_CERTIFICATE_TYPE;
114821f43f82Sdjm 		key_attr[0].pValue = &ck_cert_type;
114921f43f82Sdjm 		key_attr[0].ulValueLen = sizeof(ck_cert_type);
115021f43f82Sdjm 
115121f43f82Sdjm 		rv = f->C_GetAttributeValue(session, obj, key_attr, 1);
115221f43f82Sdjm 		if (rv != CKR_OK) {
115341503fafSmarkus 			error("C_GetAttributeValue failed: %lu", rv);
115421f43f82Sdjm 			goto fail;
115571eb7f6dSdjm 		}
115671eb7f6dSdjm 
115744e54ccbSdjm 		key = NULL;
115844e54ccbSdjm 		label = NULL;
115921f43f82Sdjm 		switch (ck_cert_type) {
116021f43f82Sdjm 		case CKC_X_509:
116144e54ccbSdjm 			if (pkcs11_fetch_x509_pubkey(p, slotidx, &obj,
116244e54ccbSdjm 			    &key, &label) != 0) {
116344e54ccbSdjm 				error("failed to fetch key");
116444e54ccbSdjm 				continue;
116544e54ccbSdjm 			}
116621f43f82Sdjm 			break;
116721f43f82Sdjm 		default:
116844e54ccbSdjm 			error("skipping unsupported certificate type %lu",
116944e54ccbSdjm 			    ck_cert_type);
117021f43f82Sdjm 			continue;
11717c94020aSdjm 		}
1172d176a5c8Sdjm 		note_key(p, slotidx, __func__, key);
117312770bd2Smarkus 		if (pkcs11_key_included(keysp, nkeys, key)) {
1174*479c151dSjsg 			debug2_f("key already included");
11752aa7d220Sdjm 			sshkey_free(key);
117612770bd2Smarkus 		} else {
117741503fafSmarkus 			/* expand key array and add key */
1178eaf8e3f6Sderaadt 			*keysp = xrecallocarray(*keysp, *nkeys,
1179eaf8e3f6Sderaadt 			    *nkeys + 1, sizeof(struct sshkey *));
118041503fafSmarkus 			(*keysp)[*nkeys] = key;
118144e54ccbSdjm 			if (labelsp != NULL) {
118244e54ccbSdjm 				*labelsp = xrecallocarray(*labelsp, *nkeys,
118344e54ccbSdjm 				    *nkeys + 1, sizeof(char *));
118444e54ccbSdjm 				(*labelsp)[*nkeys] = xstrdup((char *)label);
118544e54ccbSdjm 			}
118641503fafSmarkus 			*nkeys = *nkeys + 1;
118741503fafSmarkus 			debug("have %d keys", *nkeys);
118841503fafSmarkus 		}
118941503fafSmarkus 	}
119041503fafSmarkus 
119121f43f82Sdjm 	ret = 0;
119221f43f82Sdjm fail:
119321f43f82Sdjm 	rv = f->C_FindObjectsFinal(session);
119421f43f82Sdjm 	if (rv != CKR_OK) {
119521f43f82Sdjm 		error("C_FindObjectsFinal failed: %lu", rv);
119621f43f82Sdjm 		ret = -1;
119721f43f82Sdjm 	}
119821f43f82Sdjm 
119921f43f82Sdjm 	return (ret);
120021f43f82Sdjm }
120121f43f82Sdjm 
120221f43f82Sdjm /*
120321f43f82Sdjm  * lookup public keys for token in slot identified by slotidx,
120421f43f82Sdjm  * add 'wrapped' public keys to the 'keysp' array and increment nkeys.
120521f43f82Sdjm  * keysp points to an (possibly empty) array with *nkeys keys.
120621f43f82Sdjm  */
120721f43f82Sdjm static int
pkcs11_fetch_keys(struct pkcs11_provider * p,CK_ULONG slotidx,struct sshkey *** keysp,char *** labelsp,int * nkeys)120821f43f82Sdjm pkcs11_fetch_keys(struct pkcs11_provider *p, CK_ULONG slotidx,
120944e54ccbSdjm     struct sshkey ***keysp, char ***labelsp, int *nkeys)
121021f43f82Sdjm {
121121f43f82Sdjm 	struct sshkey		*key = NULL;
121221f43f82Sdjm 	CK_OBJECT_CLASS		 key_class;
121344e54ccbSdjm 	CK_ATTRIBUTE		 key_attr[2];
121421f43f82Sdjm 	CK_SESSION_HANDLE	 session;
121521f43f82Sdjm 	CK_FUNCTION_LIST	*f = NULL;
121621f43f82Sdjm 	CK_RV			 rv;
121721f43f82Sdjm 	CK_OBJECT_HANDLE	 obj;
121821f43f82Sdjm 	CK_ULONG		 n = 0;
121921f43f82Sdjm 	int			 ret = -1;
122021f43f82Sdjm 
122121f43f82Sdjm 	memset(&key_attr, 0, sizeof(key_attr));
122221f43f82Sdjm 	memset(&obj, 0, sizeof(obj));
122321f43f82Sdjm 
122421f43f82Sdjm 	key_class = CKO_PUBLIC_KEY;
122521f43f82Sdjm 	key_attr[0].type = CKA_CLASS;
122621f43f82Sdjm 	key_attr[0].pValue = &key_class;
122721f43f82Sdjm 	key_attr[0].ulValueLen = sizeof(key_class);
122821f43f82Sdjm 
122921f43f82Sdjm 	session = p->slotinfo[slotidx].session;
123021f43f82Sdjm 	f = p->function_list;
123121f43f82Sdjm 
123221f43f82Sdjm 	rv = f->C_FindObjectsInit(session, key_attr, 1);
123321f43f82Sdjm 	if (rv != CKR_OK) {
123421f43f82Sdjm 		error("C_FindObjectsInit failed: %lu", rv);
123521f43f82Sdjm 		goto fail;
123621f43f82Sdjm 	}
123721f43f82Sdjm 
123821f43f82Sdjm 	while (1) {
123921f43f82Sdjm 		CK_KEY_TYPE	ck_key_type;
124044e54ccbSdjm 		CK_UTF8CHAR	label[256];
124121f43f82Sdjm 
124221f43f82Sdjm 		rv = f->C_FindObjects(session, &obj, 1, &n);
124321f43f82Sdjm 		if (rv != CKR_OK) {
124421f43f82Sdjm 			error("C_FindObjects failed: %lu", rv);
124521f43f82Sdjm 			goto fail;
124621f43f82Sdjm 		}
124721f43f82Sdjm 		if (n == 0)
124821f43f82Sdjm 			break;
124921f43f82Sdjm 
125021f43f82Sdjm 		memset(&ck_key_type, 0, sizeof(ck_key_type));
125121f43f82Sdjm 		memset(&key_attr, 0, sizeof(key_attr));
125221f43f82Sdjm 		key_attr[0].type = CKA_KEY_TYPE;
125321f43f82Sdjm 		key_attr[0].pValue = &ck_key_type;
125421f43f82Sdjm 		key_attr[0].ulValueLen = sizeof(ck_key_type);
125544e54ccbSdjm 		key_attr[1].type = CKA_LABEL;
125644e54ccbSdjm 		key_attr[1].pValue = &label;
125744e54ccbSdjm 		key_attr[1].ulValueLen = sizeof(label) - 1;
125821f43f82Sdjm 
125944e54ccbSdjm 		rv = f->C_GetAttributeValue(session, obj, key_attr, 2);
126021f43f82Sdjm 		if (rv != CKR_OK) {
126121f43f82Sdjm 			error("C_GetAttributeValue failed: %lu", rv);
126221f43f82Sdjm 			goto fail;
126321f43f82Sdjm 		}
126421f43f82Sdjm 
126544e54ccbSdjm 		label[key_attr[1].ulValueLen] = '\0';
126644e54ccbSdjm 
126721f43f82Sdjm 		switch (ck_key_type) {
126821f43f82Sdjm 		case CKK_RSA:
126921f43f82Sdjm 			key = pkcs11_fetch_rsa_pubkey(p, slotidx, &obj);
127021f43f82Sdjm 			break;
127121f43f82Sdjm 		case CKK_ECDSA:
127221f43f82Sdjm 			key = pkcs11_fetch_ecdsa_pubkey(p, slotidx, &obj);
127321f43f82Sdjm 			break;
127421f43f82Sdjm 		default:
127521f43f82Sdjm 			/* XXX print key type? */
12767b1c2372Smarkus 			key = NULL;
127721f43f82Sdjm 			error("skipping unsupported key type");
127821f43f82Sdjm 		}
127921f43f82Sdjm 
128021f43f82Sdjm 		if (key == NULL) {
128121f43f82Sdjm 			error("failed to fetch key");
128221f43f82Sdjm 			continue;
128321f43f82Sdjm 		}
1284d176a5c8Sdjm 		note_key(p, slotidx, __func__, key);
128521f43f82Sdjm 		if (pkcs11_key_included(keysp, nkeys, key)) {
1286*479c151dSjsg 			debug2_f("key already included");
128721f43f82Sdjm 			sshkey_free(key);
128821f43f82Sdjm 		} else {
128921f43f82Sdjm 			/* expand key array and add key */
129021f43f82Sdjm 			*keysp = xrecallocarray(*keysp, *nkeys,
129121f43f82Sdjm 			    *nkeys + 1, sizeof(struct sshkey *));
129221f43f82Sdjm 			(*keysp)[*nkeys] = key;
129344e54ccbSdjm 			if (labelsp != NULL) {
129444e54ccbSdjm 				*labelsp = xrecallocarray(*labelsp, *nkeys,
129544e54ccbSdjm 				    *nkeys + 1, sizeof(char *));
129644e54ccbSdjm 				(*labelsp)[*nkeys] = xstrdup((char *)label);
129744e54ccbSdjm 			}
129821f43f82Sdjm 			*nkeys = *nkeys + 1;
129921f43f82Sdjm 			debug("have %d keys", *nkeys);
130021f43f82Sdjm 		}
130121f43f82Sdjm 	}
130221f43f82Sdjm 
130321f43f82Sdjm 	ret = 0;
130421f43f82Sdjm fail:
130521f43f82Sdjm 	rv = f->C_FindObjectsFinal(session);
130621f43f82Sdjm 	if (rv != CKR_OK) {
130721f43f82Sdjm 		error("C_FindObjectsFinal failed: %lu", rv);
130821f43f82Sdjm 		ret = -1;
130921f43f82Sdjm 	}
131021f43f82Sdjm 
131121f43f82Sdjm 	return (ret);
131221f43f82Sdjm }
131321f43f82Sdjm 
131421f43f82Sdjm #ifdef WITH_PKCS11_KEYGEN
131521f43f82Sdjm #define FILL_ATTR(attr, idx, typ, val, len) \
131621f43f82Sdjm 	{ (attr[idx]).type=(typ); (attr[idx]).pValue=(val); (attr[idx]).ulValueLen=len; idx++; }
131721f43f82Sdjm 
131821f43f82Sdjm static struct sshkey *
pkcs11_rsa_generate_private_key(struct pkcs11_provider * p,CK_ULONG slotidx,char * label,CK_ULONG bits,CK_BYTE keyid,u_int32_t * err)131921f43f82Sdjm pkcs11_rsa_generate_private_key(struct pkcs11_provider *p, CK_ULONG slotidx,
132021f43f82Sdjm     char *label, CK_ULONG bits, CK_BYTE keyid, u_int32_t *err)
132121f43f82Sdjm {
132221f43f82Sdjm 	struct pkcs11_slotinfo	*si;
132321f43f82Sdjm 	char			*plabel = label ? label : "";
132421f43f82Sdjm 	int			 npub = 0, npriv = 0;
132521f43f82Sdjm 	CK_RV			 rv;
132621f43f82Sdjm 	CK_FUNCTION_LIST	*f;
132721f43f82Sdjm 	CK_SESSION_HANDLE	 session;
132821f43f82Sdjm 	CK_BBOOL		 true_val = CK_TRUE, false_val = CK_FALSE;
132921f43f82Sdjm 	CK_OBJECT_HANDLE	 pubKey, privKey;
133021f43f82Sdjm 	CK_ATTRIBUTE		 tpub[16], tpriv[16];
133121f43f82Sdjm 	CK_MECHANISM		 mech = {
133221f43f82Sdjm 	    CKM_RSA_PKCS_KEY_PAIR_GEN, NULL_PTR, 0
133321f43f82Sdjm 	};
133421f43f82Sdjm 	CK_BYTE			 pubExponent[] = {
133521f43f82Sdjm 	    0x01, 0x00, 0x01 /* RSA_F4 in bytes */
133621f43f82Sdjm 	};
133721f43f82Sdjm 
133821f43f82Sdjm 	*err = 0;
133921f43f82Sdjm 
134021f43f82Sdjm 	FILL_ATTR(tpub, npub, CKA_TOKEN, &true_val, sizeof(true_val));
134121f43f82Sdjm 	FILL_ATTR(tpub, npub, CKA_LABEL, plabel, strlen(plabel));
134221f43f82Sdjm 	FILL_ATTR(tpub, npub, CKA_ENCRYPT, &false_val, sizeof(false_val));
134321f43f82Sdjm 	FILL_ATTR(tpub, npub, CKA_VERIFY, &true_val, sizeof(true_val));
134421f43f82Sdjm 	FILL_ATTR(tpub, npub, CKA_VERIFY_RECOVER, &false_val,
134521f43f82Sdjm 	    sizeof(false_val));
134621f43f82Sdjm 	FILL_ATTR(tpub, npub, CKA_WRAP, &false_val, sizeof(false_val));
134721f43f82Sdjm 	FILL_ATTR(tpub, npub, CKA_DERIVE, &false_val, sizeof(false_val));
134821f43f82Sdjm 	FILL_ATTR(tpub, npub, CKA_MODULUS_BITS, &bits, sizeof(bits));
134921f43f82Sdjm 	FILL_ATTR(tpub, npub, CKA_PUBLIC_EXPONENT, pubExponent,
135021f43f82Sdjm 	    sizeof(pubExponent));
135121f43f82Sdjm 	FILL_ATTR(tpub, npub, CKA_ID, &keyid, sizeof(keyid));
135221f43f82Sdjm 
135321f43f82Sdjm 	FILL_ATTR(tpriv, npriv, CKA_TOKEN,  &true_val, sizeof(true_val));
135421f43f82Sdjm 	FILL_ATTR(tpriv, npriv, CKA_LABEL,  plabel, strlen(plabel));
135521f43f82Sdjm 	FILL_ATTR(tpriv, npriv, CKA_PRIVATE,  &true_val, sizeof(true_val));
135621f43f82Sdjm 	FILL_ATTR(tpriv, npriv, CKA_SENSITIVE,  &true_val, sizeof(true_val));
135721f43f82Sdjm 	FILL_ATTR(tpriv, npriv, CKA_DECRYPT,  &false_val, sizeof(false_val));
135821f43f82Sdjm 	FILL_ATTR(tpriv, npriv, CKA_SIGN,  &true_val, sizeof(true_val));
135921f43f82Sdjm 	FILL_ATTR(tpriv, npriv, CKA_SIGN_RECOVER,  &false_val,
136021f43f82Sdjm 	    sizeof(false_val));
136121f43f82Sdjm 	FILL_ATTR(tpriv, npriv, CKA_UNWRAP,  &false_val, sizeof(false_val));
136221f43f82Sdjm 	FILL_ATTR(tpriv, npriv, CKA_DERIVE,  &false_val, sizeof(false_val));
136321f43f82Sdjm 	FILL_ATTR(tpriv, npriv, CKA_ID, &keyid, sizeof(keyid));
136421f43f82Sdjm 
136521f43f82Sdjm 	f = p->function_list;
136621f43f82Sdjm 	si = &p->slotinfo[slotidx];
136721f43f82Sdjm 	session = si->session;
136821f43f82Sdjm 
136921f43f82Sdjm 	if ((rv = f->C_GenerateKeyPair(session, &mech, tpub, npub, tpriv, npriv,
137021f43f82Sdjm 	    &pubKey, &privKey)) != CKR_OK) {
137148e6b99dSdjm 		error_f("key generation failed: error 0x%lx", rv);
137221f43f82Sdjm 		*err = rv;
137321f43f82Sdjm 		return NULL;
137421f43f82Sdjm 	}
137521f43f82Sdjm 
137621f43f82Sdjm 	return pkcs11_fetch_rsa_pubkey(p, slotidx, &pubKey);
137721f43f82Sdjm }
137821f43f82Sdjm 
137921f43f82Sdjm static int
h2i(char c)1380da716d80Sderaadt h2i(char c)
1381da716d80Sderaadt {
1382da716d80Sderaadt 	if (c >= '0' && c <= '9')
1383354c843bSderaadt 		return c - '0';
1384da716d80Sderaadt 	else if (c >= 'a' && c <= 'f')
1385354c843bSderaadt 		return c - 'a' + 10;
1386da716d80Sderaadt 	else if (c >= 'A' && c <= 'F')
1387354c843bSderaadt 		return c - 'A' + 10;
1388da716d80Sderaadt 	else
1389da716d80Sderaadt 		return -1;
1390da716d80Sderaadt }
1391da716d80Sderaadt 
1392da716d80Sderaadt static int
pkcs11_decode_hex(const char * hex,unsigned char ** dest,size_t * rlen)139321f43f82Sdjm pkcs11_decode_hex(const char *hex, unsigned char **dest, size_t *rlen)
139421f43f82Sdjm {
139521f43f82Sdjm 	size_t	i, len;
139621f43f82Sdjm 
139721f43f82Sdjm 	if (dest)
139821f43f82Sdjm 		*dest = NULL;
139921f43f82Sdjm 	if (rlen)
140021f43f82Sdjm 		*rlen = 0;
140121f43f82Sdjm 
140221f43f82Sdjm 	if ((len = strlen(hex)) % 2)
140321f43f82Sdjm 		return -1;
140421f43f82Sdjm 	len /= 2;
140521f43f82Sdjm 
140621f43f82Sdjm 	*dest = xmalloc(len);
140721f43f82Sdjm 
140821f43f82Sdjm 	for (i = 0; i < len; i++) {
1409da716d80Sderaadt 		int hi, low;
1410da716d80Sderaadt 
1411da716d80Sderaadt 		hi = h2i(hex[2 * i]);
1412da716d80Sderaadt 		lo = h2i(hex[(2 * i) + 1]);
1413da716d80Sderaadt 		if (hi == -1 || lo == -1)
141421f43f82Sdjm 			return -1;
1415da716d80Sderaadt 		(*dest)[i] = (hi << 4) | lo;
141621f43f82Sdjm 	}
141721f43f82Sdjm 
141821f43f82Sdjm 	if (rlen)
141921f43f82Sdjm 		*rlen = len;
142021f43f82Sdjm 
142121f43f82Sdjm 	return 0;
142221f43f82Sdjm }
142321f43f82Sdjm 
142421f43f82Sdjm static struct ec_curve_info {
142521f43f82Sdjm 	const char	*name;
142621f43f82Sdjm 	const char	*oid;
142721f43f82Sdjm 	const char	*oid_encoded;
142821f43f82Sdjm 	size_t		 size;
142921f43f82Sdjm } ec_curve_infos[] = {
143021f43f82Sdjm 	{"prime256v1",	"1.2.840.10045.3.1.7",	"06082A8648CE3D030107", 256},
143121f43f82Sdjm 	{"secp384r1",	"1.3.132.0.34",		"06052B81040022",	384},
143221f43f82Sdjm 	{"secp521r1",	"1.3.132.0.35",		"06052B81040023",	521},
143321f43f82Sdjm 	{NULL,		NULL,			NULL,			0},
143421f43f82Sdjm };
143521f43f82Sdjm 
143621f43f82Sdjm static struct sshkey *
pkcs11_ecdsa_generate_private_key(struct pkcs11_provider * p,CK_ULONG slotidx,char * label,CK_ULONG bits,CK_BYTE keyid,u_int32_t * err)143721f43f82Sdjm pkcs11_ecdsa_generate_private_key(struct pkcs11_provider *p, CK_ULONG slotidx,
143821f43f82Sdjm     char *label, CK_ULONG bits, CK_BYTE keyid, u_int32_t *err)
143921f43f82Sdjm {
144021f43f82Sdjm 	struct pkcs11_slotinfo	*si;
144121f43f82Sdjm 	char			*plabel = label ? label : "";
144221f43f82Sdjm 	int			 i;
144321f43f82Sdjm 	size_t			 ecparams_size;
144421f43f82Sdjm 	unsigned char		*ecparams = NULL;
144521f43f82Sdjm 	int			 npub = 0, npriv = 0;
144621f43f82Sdjm 	CK_RV			 rv;
144721f43f82Sdjm 	CK_FUNCTION_LIST	*f;
144821f43f82Sdjm 	CK_SESSION_HANDLE	 session;
144921f43f82Sdjm 	CK_BBOOL		 true_val = CK_TRUE, false_val = CK_FALSE;
145021f43f82Sdjm 	CK_OBJECT_HANDLE	 pubKey, privKey;
145121f43f82Sdjm 	CK_MECHANISM		 mech = {
145221f43f82Sdjm 	    CKM_EC_KEY_PAIR_GEN, NULL_PTR, 0
145321f43f82Sdjm 	};
145421f43f82Sdjm 	CK_ATTRIBUTE		 tpub[16], tpriv[16];
145521f43f82Sdjm 
145621f43f82Sdjm 	*err = 0;
145721f43f82Sdjm 
145821f43f82Sdjm 	for (i = 0; ec_curve_infos[i].name; i++) {
145921f43f82Sdjm 		if (ec_curve_infos[i].size == bits)
146021f43f82Sdjm 			break;
146121f43f82Sdjm 	}
146221f43f82Sdjm 	if (!ec_curve_infos[i].name) {
146348e6b99dSdjm 		error_f("invalid key size %lu", bits);
146421f43f82Sdjm 		return NULL;
146521f43f82Sdjm 	}
146621f43f82Sdjm 	if (pkcs11_decode_hex(ec_curve_infos[i].oid_encoded, &ecparams,
146721f43f82Sdjm 	    &ecparams_size) == -1) {
146848e6b99dSdjm 		error_f("invalid oid");
146921f43f82Sdjm 		return NULL;
147021f43f82Sdjm 	}
147121f43f82Sdjm 
147221f43f82Sdjm 	FILL_ATTR(tpub, npub, CKA_TOKEN, &true_val, sizeof(true_val));
147321f43f82Sdjm 	FILL_ATTR(tpub, npub, CKA_LABEL, plabel, strlen(plabel));
147421f43f82Sdjm 	FILL_ATTR(tpub, npub, CKA_ENCRYPT, &false_val, sizeof(false_val));
147521f43f82Sdjm 	FILL_ATTR(tpub, npub, CKA_VERIFY, &true_val, sizeof(true_val));
147621f43f82Sdjm 	FILL_ATTR(tpub, npub, CKA_VERIFY_RECOVER, &false_val,
147721f43f82Sdjm 	    sizeof(false_val));
147821f43f82Sdjm 	FILL_ATTR(tpub, npub, CKA_WRAP, &false_val, sizeof(false_val));
147921f43f82Sdjm 	FILL_ATTR(tpub, npub, CKA_DERIVE, &false_val, sizeof(false_val));
148021f43f82Sdjm 	FILL_ATTR(tpub, npub, CKA_EC_PARAMS, ecparams, ecparams_size);
148121f43f82Sdjm 	FILL_ATTR(tpub, npub, CKA_ID, &keyid, sizeof(keyid));
148221f43f82Sdjm 
148321f43f82Sdjm 	FILL_ATTR(tpriv, npriv, CKA_TOKEN, &true_val, sizeof(true_val));
148421f43f82Sdjm 	FILL_ATTR(tpriv, npriv, CKA_LABEL, plabel, strlen(plabel));
148521f43f82Sdjm 	FILL_ATTR(tpriv, npriv, CKA_PRIVATE, &true_val, sizeof(true_val));
148621f43f82Sdjm 	FILL_ATTR(tpriv, npriv, CKA_SENSITIVE, &true_val, sizeof(true_val));
148721f43f82Sdjm 	FILL_ATTR(tpriv, npriv, CKA_DECRYPT, &false_val, sizeof(false_val));
148821f43f82Sdjm 	FILL_ATTR(tpriv, npriv, CKA_SIGN, &true_val, sizeof(true_val));
148921f43f82Sdjm 	FILL_ATTR(tpriv, npriv, CKA_SIGN_RECOVER, &false_val,
149021f43f82Sdjm 	    sizeof(false_val));
149121f43f82Sdjm 	FILL_ATTR(tpriv, npriv, CKA_UNWRAP, &false_val, sizeof(false_val));
149221f43f82Sdjm 	FILL_ATTR(tpriv, npriv, CKA_DERIVE, &false_val, sizeof(false_val));
149321f43f82Sdjm 	FILL_ATTR(tpriv, npriv, CKA_ID, &keyid, sizeof(keyid));
149421f43f82Sdjm 
149521f43f82Sdjm 	f = p->function_list;
149621f43f82Sdjm 	si = &p->slotinfo[slotidx];
149721f43f82Sdjm 	session = si->session;
149821f43f82Sdjm 
149921f43f82Sdjm 	if ((rv = f->C_GenerateKeyPair(session, &mech, tpub, npub, tpriv, npriv,
150021f43f82Sdjm 	    &pubKey, &privKey)) != CKR_OK) {
150148e6b99dSdjm 		error_f("key generation failed: error 0x%lx", rv);
150221f43f82Sdjm 		*err = rv;
150321f43f82Sdjm 		return NULL;
150421f43f82Sdjm 	}
150521f43f82Sdjm 
150621f43f82Sdjm 	return pkcs11_fetch_ecdsa_pubkey(p, slotidx, &pubKey);
150721f43f82Sdjm }
150821f43f82Sdjm #endif /* WITH_PKCS11_KEYGEN */
150921f43f82Sdjm 
151021f43f82Sdjm /*
151121f43f82Sdjm  * register a new provider, fails if provider already exists. if
151221f43f82Sdjm  * keyp is provided, fetch keys.
151321f43f82Sdjm  */
151421f43f82Sdjm static int
pkcs11_register_provider(char * provider_id,char * pin,struct sshkey *** keyp,char *** labelsp,struct pkcs11_provider ** providerp,CK_ULONG user)151544e54ccbSdjm pkcs11_register_provider(char *provider_id, char *pin,
151644e54ccbSdjm     struct sshkey ***keyp, char ***labelsp,
151721f43f82Sdjm     struct pkcs11_provider **providerp, CK_ULONG user)
151841503fafSmarkus {
151941503fafSmarkus 	int nkeys, need_finalize = 0;
152021f43f82Sdjm 	int ret = -1;
152141503fafSmarkus 	struct pkcs11_provider *p = NULL;
152241503fafSmarkus 	void *handle = NULL;
152341503fafSmarkus 	CK_RV (*getfunctionlist)(CK_FUNCTION_LIST **);
152441503fafSmarkus 	CK_RV rv;
152541503fafSmarkus 	CK_FUNCTION_LIST *f = NULL;
152641503fafSmarkus 	CK_TOKEN_INFO *token;
152741503fafSmarkus 	CK_ULONG i;
152841503fafSmarkus 
152921f43f82Sdjm 	if (providerp == NULL)
153021f43f82Sdjm 		goto fail;
153121f43f82Sdjm 	*providerp = NULL;
153221f43f82Sdjm 
153321f43f82Sdjm 	if (keyp != NULL)
153441503fafSmarkus 		*keyp = NULL;
153544e54ccbSdjm 	if (labelsp != NULL)
153644e54ccbSdjm 		*labelsp = NULL;
153721f43f82Sdjm 
153841503fafSmarkus 	if (pkcs11_provider_lookup(provider_id) != NULL) {
153948e6b99dSdjm 		debug_f("provider already registered: %s", provider_id);
154041503fafSmarkus 		goto fail;
154141503fafSmarkus 	}
1542f8f5a6b0Sdjm 	if (lib_contains_symbol(provider_id, "C_GetFunctionList") != 0) {
1543f8f5a6b0Sdjm 		error("provider %s is not a PKCS11 library", provider_id);
1544f8f5a6b0Sdjm 		goto fail;
1545f8f5a6b0Sdjm 	}
154621f43f82Sdjm 	/* open shared pkcs11-library */
154741503fafSmarkus 	if ((handle = dlopen(provider_id, RTLD_NOW)) == NULL) {
154841503fafSmarkus 		error("dlopen %s failed: %s", provider_id, dlerror());
154941503fafSmarkus 		goto fail;
155041503fafSmarkus 	}
1551f03a4faaSdjm 	if ((getfunctionlist = dlsym(handle, "C_GetFunctionList")) == NULL)
1552f03a4faaSdjm 		fatal("dlsym(C_GetFunctionList) failed: %s", dlerror());
155341503fafSmarkus 	p = xcalloc(1, sizeof(*p));
155441503fafSmarkus 	p->name = xstrdup(provider_id);
155541503fafSmarkus 	p->handle = handle;
155641503fafSmarkus 	/* setup the pkcs11 callbacks */
155741503fafSmarkus 	if ((rv = (*getfunctionlist)(&f)) != CKR_OK) {
15583c54a32fSdjm 		error("C_GetFunctionList for provider %s failed: %lu",
15593c54a32fSdjm 		    provider_id, rv);
156041503fafSmarkus 		goto fail;
156141503fafSmarkus 	}
156241503fafSmarkus 	p->function_list = f;
156341503fafSmarkus 	if ((rv = f->C_Initialize(NULL)) != CKR_OK) {
15643c54a32fSdjm 		error("C_Initialize for provider %s failed: %lu",
15653c54a32fSdjm 		    provider_id, rv);
156641503fafSmarkus 		goto fail;
156741503fafSmarkus 	}
156841503fafSmarkus 	need_finalize = 1;
156941503fafSmarkus 	if ((rv = f->C_GetInfo(&p->info)) != CKR_OK) {
15703c54a32fSdjm 		error("C_GetInfo for provider %s failed: %lu",
15713c54a32fSdjm 		    provider_id, rv);
157241503fafSmarkus 		goto fail;
157341503fafSmarkus 	}
15742c6bff6fSdjm 	debug("provider %s: manufacturerID <%.*s> cryptokiVersion %d.%d"
15752c6bff6fSdjm 	    " libraryDescription <%.*s> libraryVersion %d.%d",
15763c54a32fSdjm 	    provider_id,
15772c6bff6fSdjm 	    RMSPACE(p->info.manufacturerID),
157841503fafSmarkus 	    p->info.cryptokiVersion.major,
157941503fafSmarkus 	    p->info.cryptokiVersion.minor,
15802c6bff6fSdjm 	    RMSPACE(p->info.libraryDescription),
158141503fafSmarkus 	    p->info.libraryVersion.major,
158241503fafSmarkus 	    p->info.libraryVersion.minor);
158341503fafSmarkus 	if ((rv = f->C_GetSlotList(CK_TRUE, NULL, &p->nslots)) != CKR_OK) {
158441503fafSmarkus 		error("C_GetSlotList failed: %lu", rv);
158541503fafSmarkus 		goto fail;
158641503fafSmarkus 	}
158741503fafSmarkus 	if (p->nslots == 0) {
158848e6b99dSdjm 		debug_f("provider %s returned no slots", provider_id);
158921f43f82Sdjm 		ret = -SSH_PKCS11_ERR_NO_SLOTS;
159041503fafSmarkus 		goto fail;
159141503fafSmarkus 	}
159241503fafSmarkus 	p->slotlist = xcalloc(p->nslots, sizeof(CK_SLOT_ID));
159341503fafSmarkus 	if ((rv = f->C_GetSlotList(CK_TRUE, p->slotlist, &p->nslots))
159441503fafSmarkus 	    != CKR_OK) {
15953c54a32fSdjm 		error("C_GetSlotList for provider %s failed: %lu",
15963c54a32fSdjm 		    provider_id, rv);
159741503fafSmarkus 		goto fail;
159841503fafSmarkus 	}
159941503fafSmarkus 	p->slotinfo = xcalloc(p->nslots, sizeof(struct pkcs11_slotinfo));
160041503fafSmarkus 	p->valid = 1;
160141503fafSmarkus 	nkeys = 0;
160241503fafSmarkus 	for (i = 0; i < p->nslots; i++) {
160341503fafSmarkus 		token = &p->slotinfo[i].token;
160441503fafSmarkus 		if ((rv = f->C_GetTokenInfo(p->slotlist[i], token))
160541503fafSmarkus 		    != CKR_OK) {
16063c54a32fSdjm 			error("C_GetTokenInfo for provider %s slot %lu "
160748e6b99dSdjm 			    "failed: %lu", provider_id, (u_long)i, rv);
160841503fafSmarkus 			continue;
160941503fafSmarkus 		}
1610eea3c97aSdjm 		if ((token->flags & CKF_TOKEN_INITIALIZED) == 0) {
161148e6b99dSdjm 			debug2_f("ignoring uninitialised token in "
161248e6b99dSdjm 			    "provider %s slot %lu", provider_id, (u_long)i);
1613eea3c97aSdjm 			continue;
1614eea3c97aSdjm 		}
16152c6bff6fSdjm 		debug("provider %s slot %lu: label <%.*s> "
16162c6bff6fSdjm 		    "manufacturerID <%.*s> model <%.*s> serial <%.*s> "
16172c6bff6fSdjm 		    "flags 0x%lx",
16183c54a32fSdjm 		    provider_id, (unsigned long)i,
16192c6bff6fSdjm 		    RMSPACE(token->label), RMSPACE(token->manufacturerID),
16202c6bff6fSdjm 		    RMSPACE(token->model), RMSPACE(token->serialNumber),
16212c6bff6fSdjm 		    token->flags);
162221f43f82Sdjm 		/*
162321f43f82Sdjm 		 * open session, login with pin and retrieve public
162421f43f82Sdjm 		 * keys (if keyp is provided)
162521f43f82Sdjm 		 */
1626f69acb9aSdjm 		if ((ret = pkcs11_open_session(p, i, pin, user)) != 0 ||
1627f69acb9aSdjm 		    keyp == NULL)
162821f43f82Sdjm 			continue;
162944e54ccbSdjm 		pkcs11_fetch_keys(p, i, keyp, labelsp, &nkeys);
163044e54ccbSdjm 		pkcs11_fetch_certs(p, i, keyp, labelsp, &nkeys);
1631f69acb9aSdjm 		if (nkeys == 0 && !p->slotinfo[i].logged_in &&
1632f69acb9aSdjm 		    pkcs11_interactive) {
1633f69acb9aSdjm 			/*
1634f69acb9aSdjm 			 * Some tokens require login before they will
1635f69acb9aSdjm 			 * expose keys.
1636f69acb9aSdjm 			 */
1637f69acb9aSdjm 			if (pkcs11_login_slot(p, &p->slotinfo[i],
1638f69acb9aSdjm 			    CKU_USER) < 0) {
1639f69acb9aSdjm 				error("login failed");
1640f69acb9aSdjm 				continue;
1641f69acb9aSdjm 			}
164244e54ccbSdjm 			pkcs11_fetch_keys(p, i, keyp, labelsp, &nkeys);
164344e54ccbSdjm 			pkcs11_fetch_certs(p, i, keyp, labelsp, &nkeys);
164441503fafSmarkus 		}
164521f43f82Sdjm 	}
164621f43f82Sdjm 
164721f43f82Sdjm 	/* now owned by caller */
164821f43f82Sdjm 	*providerp = p;
164921f43f82Sdjm 
165041503fafSmarkus 	TAILQ_INSERT_TAIL(&pkcs11_providers, p, next);
165141503fafSmarkus 	p->refcount++;	/* add to provider list */
165221f43f82Sdjm 
165341503fafSmarkus 	return (nkeys);
165441503fafSmarkus fail:
165541503fafSmarkus 	if (need_finalize && (rv = f->C_Finalize(NULL)) != CKR_OK)
16563c54a32fSdjm 		error("C_Finalize for provider %s failed: %lu",
16573c54a32fSdjm 		    provider_id, rv);
165841503fafSmarkus 	if (p) {
165921f43f82Sdjm 		free(p->name);
16600d40fefdSdjm 		free(p->slotlist);
16610d40fefdSdjm 		free(p->slotinfo);
16620d40fefdSdjm 		free(p);
166341503fafSmarkus 	}
166441503fafSmarkus 	if (handle)
166541503fafSmarkus 		dlclose(handle);
1666816fc154Smarkus 	if (ret > 0)
1667816fc154Smarkus 		ret = -1;
166821f43f82Sdjm 	return (ret);
166941503fafSmarkus }
167021f43f82Sdjm 
167121f43f82Sdjm /*
167221f43f82Sdjm  * register a new provider and get number of keys hold by the token,
167321f43f82Sdjm  * fails if provider already exists
167421f43f82Sdjm  */
167521f43f82Sdjm int
pkcs11_add_provider(char * provider_id,char * pin,struct sshkey *** keyp,char *** labelsp)167644e54ccbSdjm pkcs11_add_provider(char *provider_id, char *pin, struct sshkey ***keyp,
167744e54ccbSdjm     char ***labelsp)
167821f43f82Sdjm {
167921f43f82Sdjm 	struct pkcs11_provider *p = NULL;
168021f43f82Sdjm 	int nkeys;
168121f43f82Sdjm 
168244e54ccbSdjm 	nkeys = pkcs11_register_provider(provider_id, pin, keyp, labelsp,
168344e54ccbSdjm 	    &p, CKU_USER);
168421f43f82Sdjm 
168521f43f82Sdjm 	/* no keys found or some other error, de-register provider */
168621f43f82Sdjm 	if (nkeys <= 0 && p != NULL) {
168721f43f82Sdjm 		TAILQ_REMOVE(&pkcs11_providers, p, next);
168821f43f82Sdjm 		pkcs11_provider_finalize(p);
168921f43f82Sdjm 		pkcs11_provider_unref(p);
169021f43f82Sdjm 	}
169121f43f82Sdjm 	if (nkeys == 0)
169248e6b99dSdjm 		debug_f("provider %s returned no keys", provider_id);
169321f43f82Sdjm 
169421f43f82Sdjm 	return (nkeys);
169521f43f82Sdjm }
169621f43f82Sdjm 
169721f43f82Sdjm #ifdef WITH_PKCS11_KEYGEN
169821f43f82Sdjm struct sshkey *
pkcs11_gakp(char * provider_id,char * pin,unsigned int slotidx,char * label,unsigned int type,unsigned int bits,unsigned char keyid,u_int32_t * err)169921f43f82Sdjm pkcs11_gakp(char *provider_id, char *pin, unsigned int slotidx, char *label,
170021f43f82Sdjm     unsigned int type, unsigned int bits, unsigned char keyid, u_int32_t *err)
170121f43f82Sdjm {
170221f43f82Sdjm 	struct pkcs11_provider	*p = NULL;
170321f43f82Sdjm 	struct pkcs11_slotinfo	*si;
170421f43f82Sdjm 	CK_FUNCTION_LIST	*f;
170521f43f82Sdjm 	CK_SESSION_HANDLE	 session;
170621f43f82Sdjm 	struct sshkey		*k = NULL;
170721f43f82Sdjm 	int			 ret = -1, reset_pin = 0, reset_provider = 0;
170821f43f82Sdjm 	CK_RV			 rv;
170921f43f82Sdjm 
171021f43f82Sdjm 	*err = 0;
171121f43f82Sdjm 
171221f43f82Sdjm 	if ((p = pkcs11_provider_lookup(provider_id)) != NULL)
171348e6b99dSdjm 		debug_f("provider \"%s\" available", provider_id);
171444e54ccbSdjm 	else if ((ret = pkcs11_register_provider(provider_id, pin, NULL, NULL,
171544e54ccbSdjm 	    &p, CKU_SO)) < 0) {
171648e6b99dSdjm 		debug_f("could not register provider %s", provider_id);
171721f43f82Sdjm 		goto out;
171821f43f82Sdjm 	} else
171921f43f82Sdjm 		reset_provider = 1;
172021f43f82Sdjm 
172121f43f82Sdjm 	f = p->function_list;
172221f43f82Sdjm 	si = &p->slotinfo[slotidx];
172321f43f82Sdjm 	session = si->session;
172421f43f82Sdjm 
172521f43f82Sdjm 	if ((rv = f->C_SetOperationState(session , pin, strlen(pin),
172621f43f82Sdjm 	    CK_INVALID_HANDLE, CK_INVALID_HANDLE)) != CKR_OK) {
172748e6b99dSdjm 		debug_f("could not supply SO pin: %lu", rv);
172821f43f82Sdjm 		reset_pin = 0;
172921f43f82Sdjm 	} else
173021f43f82Sdjm 		reset_pin = 1;
173121f43f82Sdjm 
173221f43f82Sdjm 	switch (type) {
173321f43f82Sdjm 	case KEY_RSA:
173421f43f82Sdjm 		if ((k = pkcs11_rsa_generate_private_key(p, slotidx, label,
173521f43f82Sdjm 		    bits, keyid, err)) == NULL) {
173648e6b99dSdjm 			debug_f("failed to generate RSA key");
173721f43f82Sdjm 			goto out;
173821f43f82Sdjm 		}
173921f43f82Sdjm 		break;
174021f43f82Sdjm 	case KEY_ECDSA:
174121f43f82Sdjm 		if ((k = pkcs11_ecdsa_generate_private_key(p, slotidx, label,
174221f43f82Sdjm 		    bits, keyid, err)) == NULL) {
174348e6b99dSdjm 			debug_f("failed to generate ECDSA key");
174421f43f82Sdjm 			goto out;
174521f43f82Sdjm 		}
174621f43f82Sdjm 		break;
174721f43f82Sdjm 	default:
174821f43f82Sdjm 		*err = SSH_PKCS11_ERR_GENERIC;
174948e6b99dSdjm 		debug_f("unknown type %d", type);
175021f43f82Sdjm 		goto out;
175121f43f82Sdjm 	}
175221f43f82Sdjm 
175321f43f82Sdjm out:
175421f43f82Sdjm 	if (reset_pin)
175521f43f82Sdjm 		f->C_SetOperationState(session , NULL, 0, CK_INVALID_HANDLE,
175621f43f82Sdjm 		    CK_INVALID_HANDLE);
175721f43f82Sdjm 
175821f43f82Sdjm 	if (reset_provider)
175921f43f82Sdjm 		pkcs11_del_provider(provider_id);
176021f43f82Sdjm 
176121f43f82Sdjm 	return (k);
176221f43f82Sdjm }
176321f43f82Sdjm 
176421f43f82Sdjm struct sshkey *
pkcs11_destroy_keypair(char * provider_id,char * pin,unsigned long slotidx,unsigned char keyid,u_int32_t * err)176521f43f82Sdjm pkcs11_destroy_keypair(char *provider_id, char *pin, unsigned long slotidx,
176621f43f82Sdjm     unsigned char keyid, u_int32_t *err)
176721f43f82Sdjm {
176821f43f82Sdjm 	struct pkcs11_provider	*p = NULL;
176921f43f82Sdjm 	struct pkcs11_slotinfo	*si;
177021f43f82Sdjm 	struct sshkey		*k = NULL;
177121f43f82Sdjm 	int			 reset_pin = 0, reset_provider = 0;
177221f43f82Sdjm 	CK_ULONG		 nattrs;
177321f43f82Sdjm 	CK_FUNCTION_LIST	*f;
177421f43f82Sdjm 	CK_SESSION_HANDLE	 session;
177521f43f82Sdjm 	CK_ATTRIBUTE		 attrs[16];
177621f43f82Sdjm 	CK_OBJECT_CLASS		 key_class;
177721f43f82Sdjm 	CK_KEY_TYPE		 key_type;
177821f43f82Sdjm 	CK_OBJECT_HANDLE	 obj = CK_INVALID_HANDLE;
177921f43f82Sdjm 	CK_RV			 rv;
178021f43f82Sdjm 
178121f43f82Sdjm 	*err = 0;
178221f43f82Sdjm 
178321f43f82Sdjm 	if ((p = pkcs11_provider_lookup(provider_id)) != NULL) {
178448e6b99dSdjm 		debug_f("using provider \"%s\"", provider_id);
178544e54ccbSdjm 	} else if (pkcs11_register_provider(provider_id, pin, NULL, NULL, &p,
178621f43f82Sdjm 	    CKU_SO) < 0) {
178748e6b99dSdjm 		debug_f("could not register provider %s",
178821f43f82Sdjm 		    provider_id);
178921f43f82Sdjm 		goto out;
179021f43f82Sdjm 	} else
179121f43f82Sdjm 		reset_provider = 1;
179221f43f82Sdjm 
179321f43f82Sdjm 	f = p->function_list;
179421f43f82Sdjm 	si = &p->slotinfo[slotidx];
179521f43f82Sdjm 	session = si->session;
179621f43f82Sdjm 
179721f43f82Sdjm 	if ((rv = f->C_SetOperationState(session , pin, strlen(pin),
179821f43f82Sdjm 	    CK_INVALID_HANDLE, CK_INVALID_HANDLE)) != CKR_OK) {
179948e6b99dSdjm 		debug_f("could not supply SO pin: %lu", rv);
180021f43f82Sdjm 		reset_pin = 0;
180121f43f82Sdjm 	} else
180221f43f82Sdjm 		reset_pin = 1;
180321f43f82Sdjm 
180421f43f82Sdjm 	/* private key */
180521f43f82Sdjm 	nattrs = 0;
180621f43f82Sdjm 	key_class = CKO_PRIVATE_KEY;
180721f43f82Sdjm 	FILL_ATTR(attrs, nattrs, CKA_CLASS, &key_class, sizeof(key_class));
180821f43f82Sdjm 	FILL_ATTR(attrs, nattrs, CKA_ID, &keyid, sizeof(keyid));
180921f43f82Sdjm 
181021f43f82Sdjm 	if (pkcs11_find(p, slotidx, attrs, nattrs, &obj) == 0 &&
181121f43f82Sdjm 	    obj != CK_INVALID_HANDLE) {
181221f43f82Sdjm 		if ((rv = f->C_DestroyObject(session, obj)) != CKR_OK) {
181348e6b99dSdjm 			debug_f("could not destroy private key 0x%hhx",
181448e6b99dSdjm 			    keyid);
181521f43f82Sdjm 			*err = rv;
181621f43f82Sdjm 			goto out;
181721f43f82Sdjm 		}
181821f43f82Sdjm 	}
181921f43f82Sdjm 
182021f43f82Sdjm 	/* public key */
182121f43f82Sdjm 	nattrs = 0;
182221f43f82Sdjm 	key_class = CKO_PUBLIC_KEY;
182321f43f82Sdjm 	FILL_ATTR(attrs, nattrs, CKA_CLASS, &key_class, sizeof(key_class));
182421f43f82Sdjm 	FILL_ATTR(attrs, nattrs, CKA_ID, &keyid, sizeof(keyid));
182521f43f82Sdjm 
182621f43f82Sdjm 	if (pkcs11_find(p, slotidx, attrs, nattrs, &obj) == 0 &&
182721f43f82Sdjm 	    obj != CK_INVALID_HANDLE) {
182821f43f82Sdjm 
182921f43f82Sdjm 		/* get key type */
183021f43f82Sdjm 		nattrs = 0;
183121f43f82Sdjm 		FILL_ATTR(attrs, nattrs, CKA_KEY_TYPE, &key_type,
183221f43f82Sdjm 		    sizeof(key_type));
183321f43f82Sdjm 		rv = f->C_GetAttributeValue(session, obj, attrs, nattrs);
183421f43f82Sdjm 		if (rv != CKR_OK) {
183548e6b99dSdjm 			debug_f("could not get key type of public key 0x%hhx",
183648e6b99dSdjm 			    keyid);
183721f43f82Sdjm 			*err = rv;
183821f43f82Sdjm 			key_type = -1;
183921f43f82Sdjm 		}
184021f43f82Sdjm 		if (key_type == CKK_RSA)
184121f43f82Sdjm 			k = pkcs11_fetch_rsa_pubkey(p, slotidx, &obj);
184221f43f82Sdjm 		else if (key_type == CKK_ECDSA)
184321f43f82Sdjm 			k = pkcs11_fetch_ecdsa_pubkey(p, slotidx, &obj);
184421f43f82Sdjm 
184521f43f82Sdjm 		if ((rv = f->C_DestroyObject(session, obj)) != CKR_OK) {
184648e6b99dSdjm 			debug_f("could not destroy public key 0x%hhx", keyid);
184721f43f82Sdjm 			*err = rv;
184821f43f82Sdjm 			goto out;
184921f43f82Sdjm 		}
185021f43f82Sdjm 	}
185121f43f82Sdjm 
185221f43f82Sdjm out:
185321f43f82Sdjm 	if (reset_pin)
185421f43f82Sdjm 		f->C_SetOperationState(session , NULL, 0, CK_INVALID_HANDLE,
185521f43f82Sdjm 		    CK_INVALID_HANDLE);
185621f43f82Sdjm 
185721f43f82Sdjm 	if (reset_provider)
185821f43f82Sdjm 		pkcs11_del_provider(provider_id);
185921f43f82Sdjm 
186021f43f82Sdjm 	return (k);
186121f43f82Sdjm }
186221f43f82Sdjm #endif /* WITH_PKCS11_KEYGEN */
18634ad56734Smarkus #else
18644ad56734Smarkus int
pkcs11_add_provider(char * provider_id,char * pin,struct sshkey *** keyp,char *** labelsp)1865860701bfSdjm pkcs11_add_provider(char *provider_id, char *pin, struct sshkey ***keyp,
1866860701bfSdjm     char ***labelsp)
18674ad56734Smarkus {
18684ad56734Smarkus 	error("dlopen() not supported");
18694ad56734Smarkus 	return (-1);
18704ad56734Smarkus }
187121f43f82Sdjm #endif /* HAVE_DLOPEN */
1872