Index | Thread | Search

From:
Damien Miller <djm@mindrot.org>
Subject:
openssh: refactor PKCS#11 and add support for Ed25519
To:
tech@openbsd.org
Date:
Thu, 12 Jun 2025 13:49:46 +1000

Download raw body.

Thread
  • Damien Miller:

    openssh: refactor PKCS#11 and add support for Ed25519

Hi,

This refactor's OpenSSH's PKCS#11 code to remove its use of libcrypto
methods (RSA_set_method / EC_KEY_set_method) in favour of supporting
these keys in a way similar to how we hook in support for FIDO keys.

On top of the refactor, it adds support for Ed25519 keys held in
PKCS#11 tokens. Yubikeys with recent firmware and softhsm2 are known
to work at least.

FWIW I used this sequence of commands to generate a Ed25519 key on
my Yubikey:

    ykman piv keys generate -a ED25519 --pin-policy=ONCE \
        --touch-policy=CACHED 83 yubikey-piv-ed25519.pub
    ykman piv certificates generate -s "djm usbc" -d 35600 \
        83 yubikey-piv-ed25519.pub

It will prompt your for your management key, so have that at hand.

After generation, I can load the key into the agent with:

    ssh-add -s /usr/local/lib/libykcs11.so.1.1

You'll need the yubico-piv-tool and yubikey-manager ports installed
for this.

-d

diff --git a/Makefile.inc b/Makefile.inc
index adf3c25..21b27d5 100644
--- a/Makefile.inc
+++ b/Makefile.inc
@@ -123,13 +123,12 @@ SRCS_PROT+=	monitor_fdpass.c
 SRCS_PROT+=	nchan.c
 SRCS_PROT+=	ttymodes.c
 
-.if (${OPENSSL:L} == "yes")
 SRCS_PKCS11+=		ssh-pkcs11.c
 SRCS_PKCS11_CLIENT+=	ssh-pkcs11-client.c
+
+.if (${OPENSSL:L} == "yes")
 SRCS_MODULI+=		moduli.c
 .else
-SRCS_PKCS11+=
-SRCS_PKCS11_CLIENT+=
 SRCS_MODULI+=
 .endif
 
diff --git a/ssh-add/Makefile b/ssh-add/Makefile
index 69b50f6..80bdf7b 100644
--- a/ssh-add/Makefile
+++ b/ssh-add/Makefile
@@ -5,7 +5,7 @@
 SRCS=	ssh-add.c
 SRCS+=	authfd.c cleanup.c fatal.c readpass.c utf8.c hostfile.c hmac.c
 SRCS+=	${SRCS_BASE} ${SRCS_KEY} ${SRCS_KEYP} ${SRCS_KRL} ${SRCS_UTL}
-SRCS+=	${SRCS_SK_CLIENT}
+SRCS+=	${SRCS_SK_CLIENT} ${SRCS_PKCS11_CLIENT}
 
 PROG=	ssh-add
 
diff --git a/ssh-ecdsa.c b/ssh-ecdsa.c
index aa59b33..e9da78d 100644
--- a/ssh-ecdsa.c
+++ b/ssh-ecdsa.c
@@ -318,8 +318,7 @@ ssh_ecdsa_sign(struct sshkey *key,
 	const BIGNUM *sig_r, *sig_s;
 	int hash_alg;
 	size_t slen = 0;
-	struct sshbuf *b = NULL, *bb = NULL;
-	int len = 0, ret = SSH_ERR_INTERNAL_ERROR;
+	int ret = SSH_ERR_INTERNAL_ERROR;
 
 	if (lenp != NULL)
 		*lenp = 0;
@@ -342,11 +341,37 @@ ssh_ecdsa_sign(struct sshkey *key,
 		ret = SSH_ERR_LIBCRYPTO_ERROR;
 		goto out;
 	}
-	if ((bb = sshbuf_new()) == NULL || (b = sshbuf_new()) == NULL) {
-		ret = SSH_ERR_ALLOC_FAIL;
-		goto out;
-	}
 	ECDSA_SIG_get0(esig, &sig_r, &sig_s);
+
+	if ((ret = ssh_ecdsa_encode_store_sig(key, sig_r, sig_s,
+	    sigp, lenp)) != 0)
+		goto out;
+	/* success */
+	ret = 0;
+ out:
+	freezero(sigb, slen);
+	ECDSA_SIG_free(esig);
+	return ret;
+}
+
+int
+ssh_ecdsa_encode_store_sig(const struct sshkey *key,
+    const BIGNUM *sig_r, const BIGNUM *sig_s,
+    u_char **sigp, size_t *lenp)
+{
+	struct sshbuf *b = NULL, *bb = NULL;
+	int ret;
+	size_t len;
+
+	if (lenp != NULL)
+		*lenp = 0;
+	if (sigp != NULL)
+		*sigp = NULL;
+
+	if ((bb = sshbuf_new()) == NULL || (b = sshbuf_new()) == NULL) {
+		ret = SSH_ERR_ALLOC_FAIL;
+		goto out;
+	}
 	if ((ret = sshbuf_put_bignum2(bb, sig_r)) != 0 ||
 	    (ret = sshbuf_put_bignum2(bb, sig_s)) != 0)
 		goto out;
@@ -365,10 +390,8 @@ ssh_ecdsa_sign(struct sshkey *key,
 		*lenp = len;
 	ret = 0;
  out:
-	freezero(sigb, slen);
 	sshbuf_free(b);
 	sshbuf_free(bb);
-	ECDSA_SIG_free(esig);
 	return ret;
 }
 
diff --git a/ssh-ed25519.c b/ssh-ed25519.c
index 06c6a04..561d657 100644
--- a/ssh-ed25519.c
+++ b/ssh-ed25519.c
@@ -146,10 +146,9 @@ ssh_ed25519_sign(struct sshkey *key,
     const char *alg, const char *sk_provider, const char *sk_pin, u_int compat)
 {
 	u_char *sig = NULL;
-	size_t slen = 0, len;
+	size_t slen = 0;
 	unsigned long long smlen;
 	int r, ret;
-	struct sshbuf *b = NULL;
 
 	if (lenp != NULL)
 		*lenp = 0;
@@ -170,13 +169,40 @@ ssh_ed25519_sign(struct sshkey *key,
 		r = SSH_ERR_INVALID_ARGUMENT; /* XXX better error? */
 		goto out;
 	}
+	if ((r = ssh_ed25519_encode_store_sig(sig, smlen - datalen,
+	    sigp, lenp)) != 0)
+		goto out;
+
+	/* success */
+	r = 0;
+ out:
+	freezero(sig, slen);
+	return r;
+}
+
+int
+ssh_ed25519_encode_store_sig(const u_char *sig, size_t slen,
+    u_char **sigp, size_t *lenp)
+{
+	struct sshbuf *b = NULL;
+	int r = -1;
+	size_t len;
+
+	if (lenp != NULL)
+		*lenp = 0;
+	if (sigp != NULL)
+		*sigp = NULL;
+
+	if (slen != crypto_sign_ed25519_BYTES)
+		return SSH_ERR_INVALID_ARGUMENT;
+
 	/* encode signature */
 	if ((b = sshbuf_new()) == NULL) {
 		r = SSH_ERR_ALLOC_FAIL;
 		goto out;
 	}
 	if ((r = sshbuf_put_cstring(b, "ssh-ed25519")) != 0 ||
-	    (r = sshbuf_put_string(b, sig, smlen - datalen)) != 0)
+	    (r = sshbuf_put_string(b, sig, slen)) != 0)
 		goto out;
 	len = sshbuf_len(b);
 	if (sigp != NULL) {
@@ -192,9 +218,6 @@ ssh_ed25519_sign(struct sshkey *key,
 	r = 0;
  out:
 	sshbuf_free(b);
-	if (sig != NULL)
-		freezero(sig, slen);
-
 	return r;
 }
 
diff --git a/ssh-keyscan/Makefile b/ssh-keyscan/Makefile
index 49981aa..0542a07 100644
--- a/ssh-keyscan/Makefile
+++ b/ssh-keyscan/Makefile
@@ -5,7 +5,7 @@
 SRCS=	ssh-keyscan.c
 SRCS+=	atomicio.c cleanup.c compat.c hostfile.c ssh_api.c dns.c fatal.c
 SRCS+=	${SRCS_BASE} ${SRCS_KEX} ${SRCS_KEXC} ${SRCS_KEXS} ${SRCS_KEY} \
-	${SRCS_PKT} ${SRCS_UTL} ${SRCS_SK_CLIENT}
+	${SRCS_PKT} ${SRCS_UTL} ${SRCS_SK_CLIENT} ${SRCS_PKCS11_CLIENT}
 PROG=	ssh-keyscan
 
 BINDIR=	/usr/bin
diff --git a/ssh-keysign/Makefile b/ssh-keysign/Makefile
index 90ef21b..4712dd4 100644
--- a/ssh-keysign/Makefile
+++ b/ssh-keysign/Makefile
@@ -6,7 +6,7 @@ SRCS=	ssh-keysign.c readconf.c compat.c
 SRCS+=	cleanup.c fatal.c
 SRCS+=	uidswap.c utf8.c
 SRCS+=	${SRCS_BASE} ${SRCS_KEY} ${SRCS_KEYP} ${SRCS_KRL} ${SRCS_PKT} \
-	${SRCS_UTL} ${SRCS_SK_CLIENT}
+	${SRCS_UTL} ${SRCS_SK_CLIENT} ${SRCS_PKCS11_CLIENT}
 PROG=	ssh-keysign
 BINOWN=	root
 BINMODE=4555
diff --git a/ssh-pkcs11-client.c b/ssh-pkcs11-client.c
index 205139f..eca1504 100644
--- a/ssh-pkcs11-client.c
+++ b/ssh-pkcs11-client.c
@@ -44,17 +44,14 @@
 
 /*
  * Maintain a list of ssh-pkcs11-helper subprocesses. These may be looked up
- * by provider path or their unique EC/RSA METHOD pointers.
+ * by provider path or their unique keyblobs.
  */
 struct helper {
 	char *path;
 	pid_t pid;
 	int fd;
-	RSA_METHOD *rsa_meth;
-	EC_KEY_METHOD *ec_meth;
-	int (*rsa_finish)(RSA *rsa);
-	void (*ec_finish)(EC_KEY *key);
-	size_t nrsa, nec; /* number of active keys of each type */
+	size_t nkeyblobs;
+	struct sshbuf **keyblobs; /* XXX use a tree or something faster */
 };
 static struct helper **helpers;
 static size_t nhelpers;
@@ -75,56 +72,75 @@ helper_by_provider(const char *path)
 }
 
 static struct helper *
-helper_by_rsa(const RSA *rsa)
+helper_by_key(const struct sshkey *key)
 {
-	size_t i;
-	const RSA_METHOD *meth;
+	size_t i, j;
+	struct sshbuf *keyblob = NULL;
+	int r;
+
+	if ((keyblob = sshbuf_new()) == NULL)
+		fatal_f("sshbuf_new failed");
+	if ((r = sshkey_putb(key, keyblob)) != 0)
+		fatal_fr(r, "serialise key");
 
-	if ((meth = RSA_get_method(rsa)) == NULL)
-		return NULL;
 	for (i = 0; i < nhelpers; i++) {
-		if (helpers[i] != NULL && helpers[i]->rsa_meth == meth)
-			return helpers[i];
+		if (helpers[i] == NULL)
+			continue;
+		for (j = 0; j < helpers[i]->nkeyblobs; j++) {
+			if (sshbuf_equals(keyblob,
+			    helpers[i]->keyblobs[j]) == 0) {
+				sshbuf_free(keyblob);
+				return helpers[i];
+			}
+		}
 	}
+	sshbuf_free(keyblob);
 	return NULL;
 
 }
 
-static struct helper *
-helper_by_ec(const EC_KEY *ec)
+static void
+helper_add_key(struct helper *helper, struct sshkey *key)
 {
-	size_t i;
-	const EC_KEY_METHOD *meth;
-
-	if ((meth = EC_KEY_get_method(ec)) == NULL)
-		return NULL;
-	for (i = 0; i < nhelpers; i++) {
-		if (helpers[i] != NULL && helpers[i]->ec_meth == meth)
-			return helpers[i];
-	}
-	return NULL;
+	int r;
 
+	helper->keyblobs = xrecallocarray(helper->keyblobs, helper->nkeyblobs,
+	    helper->nkeyblobs + 1, sizeof(*helper->keyblobs));
+	if ((helper->keyblobs[helper->nkeyblobs] = sshbuf_new()) == NULL)
+		fatal_f("sshbuf_new failed");
+	if ((r = sshkey_putb(key, helper->keyblobs[helper->nkeyblobs])) != 0)
+		fatal_fr(r, "shkey_putb failed");
+	helper->nkeyblobs++;
+	debug3_f("added %s key for provider %s, now has %zu keys",
+	    sshkey_type(key), helper->path, helper->nkeyblobs);
 }
 
 static void
-helper_free(struct helper *helper)
+helper_terminate(struct helper *helper)
 {
 	size_t i;
 	int found = 0;
 
 	if (helper == NULL)
 		return;
-	if (helper->path == NULL || helper->ec_meth == NULL ||
-	    helper->rsa_meth == NULL)
+	if (helper->path == NULL)
 		fatal_f("inconsistent helper");
-	debug3_f("free helper for provider %s", helper->path);
+
+	debug3_f("terminating helper for %s; remaining %zu keys",
+	    helper->path, helper->nkeyblobs);
+
+	close(helper->fd);
+	/* XXX waitpid() */
+	helper->fd = -1;
+	helper->pid = -1;
+
+	/* repack helpers */
 	for (i = 0; i < nhelpers; i++) {
 		if (helpers[i] == helper) {
 			if (found)
 				fatal_f("helper recorded more than once");
 			found = 1;
-		}
-		else if (found)
+		} else if (found)
 			helpers[i - 1] = helpers[i];
 	}
 	if (found) {
@@ -132,37 +148,12 @@ helper_free(struct helper *helper)
 		    nhelpers - 1, sizeof(*helpers));
 		nhelpers--;
 	}
+	for (i = 0; i < helper->nkeyblobs; i++)
+		sshbuf_free(helper->keyblobs[i]);
 	free(helper->path);
-	EC_KEY_METHOD_free(helper->ec_meth);
-	RSA_meth_free(helper->rsa_meth);
 	free(helper);
 }
 
-static void
-helper_terminate(struct helper *helper)
-{
-	if (helper == NULL) {
-		return;
-	} else if (helper->fd == -1) {
-		debug3_f("already terminated");
-	} else {
-		debug3_f("terminating helper for %s; "
-		    "remaining %zu RSA %zu ECDSA",
-		    helper->path, helper->nrsa, helper->nec);
-		close(helper->fd);
-		/* XXX waitpid() */
-		helper->fd = -1;
-		helper->pid = -1;
-	}
-	/*
-	 * Don't delete the helper entry until there are no remaining keys
-	 * that reference it. Otherwise, any signing operation would call
-	 * a free'd METHOD pointer and that would be bad.
-	 */
-	if (helper->nrsa == 0 && helper->nec == 0)
-		helper_free(helper);
-}
-
 static void
 send_msg(int fd, struct sshbuf *m)
 {
@@ -232,196 +223,61 @@ pkcs11_terminate(void)
 		helper_terminate(helpers[i]);
 }
 
-static int
-rsa_encrypt(int flen, const u_char *from, u_char *to, RSA *rsa, int padding)
+int
+pkcs11_sign(struct sshkey *key,
+    u_char **sigp, size_t *lenp,
+    const u_char *data, size_t datalen,
+    const char *alg, const char *sk_provider,
+    const char *sk_pin, u_int compat)
 {
-	struct sshkey *key = NULL;
 	struct sshbuf *msg = NULL;
-	u_char *blob = NULL, *signature = NULL;
-	size_t blen, slen = 0;
-	int r, ret = -1;
 	struct helper *helper;
+	int status, r;
+	u_char *signature = NULL;
+	size_t signature_len = 0;
+	int ret = SSH_ERR_INTERNAL_ERROR;
 
-	if ((helper = helper_by_rsa(rsa)) == NULL || helper->fd == -1)
-		fatal_f("no helper for PKCS11 key");
-	debug3_f("signing with PKCS11 provider %s", helper->path);
-	if (padding != RSA_PKCS1_PADDING)
-		goto fail;
-	if ((key = sshkey_new(KEY_UNSPEC)) == NULL) {
-		error_f("sshkey_new failed");
-		goto fail;
-	}
-	if ((key->pkey = EVP_PKEY_new()) == NULL ||
-	   EVP_PKEY_set1_RSA(key->pkey, rsa) != 1) {
-		error_f("pkey setup failed");
-		goto fail;
-	}
+	if (sigp != NULL)
+		*sigp = NULL;
+	if (lenp != NULL)
+		*lenp = 0;
+
+	if ((helper = helper_by_key(key)) == NULL || helper->fd == -1)
+		fatal_f("no helper for %s key", sshkey_type(key));
 
-	key->type = KEY_RSA;
-	if ((r = sshkey_to_blob(key, &blob, &blen)) != 0) {
-		error_fr(r, "encode key");
-		goto fail;
-	}
 	if ((msg = sshbuf_new()) == NULL)
-		fatal_f("sshbuf_new failed");
+		return SSH_ERR_ALLOC_FAIL;
 	if ((r = sshbuf_put_u8(msg, SSH2_AGENTC_SIGN_REQUEST)) != 0 ||
-	    (r = sshbuf_put_string(msg, blob, blen)) != 0 ||
-	    (r = sshbuf_put_string(msg, from, flen)) != 0 ||
-	    (r = sshbuf_put_u32(msg, 0)) != 0)
+	    (r = sshkey_puts_plain(key, msg)) != 0 ||
+	    (r = sshbuf_put_string(msg, data, datalen)) != 0 ||
+	    (r = sshbuf_put_cstring(msg, alg == NULL ? "" : alg)) != 0 ||
+	    (r = sshbuf_put_u32(msg, compat)) != 0)
 		fatal_fr(r, "compose");
 	send_msg(helper->fd, msg);
 	sshbuf_reset(msg);
 
-	if (recv_msg(helper->fd, msg) == SSH2_AGENT_SIGN_RESPONSE) {
-		if ((r = sshbuf_get_string(msg, &signature, &slen)) != 0)
-			fatal_fr(r, "parse");
-		if (slen <= (size_t)RSA_size(rsa)) {
-			memcpy(to, signature, slen);
-			ret = slen;
-		}
-		free(signature);
-	}
- fail:
-	free(blob);
-	sshkey_free(key);
-	sshbuf_free(msg);
-	return (ret);
-}
-
-static int
-rsa_finish(RSA *rsa)
-{
-	struct helper *helper;
-
-	if ((helper = helper_by_rsa(rsa)) == NULL)
-		fatal_f("no helper for PKCS11 key");
-	debug3_f("free PKCS11 RSA key for provider %s", helper->path);
-	if (helper->rsa_finish != NULL)
-		helper->rsa_finish(rsa);
-	if (helper->nrsa == 0)
-		fatal_f("RSA refcount error");
-	helper->nrsa--;
-	debug3_f("provider %s remaining keys: %zu RSA %zu ECDSA",
-	    helper->path, helper->nrsa, helper->nec);
-	if (helper->nrsa == 0 && helper->nec == 0)
-		helper_terminate(helper);
-	return 1;
-}
-
-static ECDSA_SIG *
-ecdsa_do_sign(const unsigned char *dgst, int dgst_len, const BIGNUM *inv,
-    const BIGNUM *rp, EC_KEY *ec)
-{
-	struct sshkey *key = NULL;
-	struct sshbuf *msg = NULL;
-	ECDSA_SIG *ret = NULL;
-	const u_char *cp;
-	u_char *blob = NULL, *signature = NULL;
-	size_t blen, slen = 0;
-	int r, nid;
-	struct helper *helper;
-
-	if ((helper = helper_by_ec(ec)) == NULL || helper->fd == -1)
-		fatal_f("no helper for PKCS11 key");
-	debug3_f("signing with PKCS11 provider %s", helper->path);
-
-	if ((key = sshkey_new(KEY_UNSPEC)) == NULL) {
-		error_f("sshkey_new failed");
-		goto fail;
-	}
-	if ((key->pkey = EVP_PKEY_new()) == NULL ||
-	    EVP_PKEY_set1_EC_KEY(key->pkey, ec) != 1) {
-		error("pkey setup failed");
-		goto fail;
-	}
-	if ((nid = sshkey_ecdsa_pkey_to_nid(key->pkey)) < 0) {
-		error("couldn't get curve nid");
+	if ((status = recv_msg(helper->fd, msg)) != SSH2_AGENT_SIGN_RESPONSE) {
+		/* XXX translate status to something useful */
+		debug_fr(r, "recv_msg");
+		ret = SSH_ERR_AGENT_FAILURE;
 		goto fail;
 	}
-	key->ecdsa_nid = nid;
-	key->type = KEY_ECDSA;
 
-	if ((r = sshkey_to_blob(key, &blob, &blen)) != 0) {
-		error_fr(r, "encode key");
-		goto fail;
-	}
-	if ((msg = sshbuf_new()) == NULL)
-		fatal_f("sshbuf_new failed");
-	if ((r = sshbuf_put_u8(msg, SSH2_AGENTC_SIGN_REQUEST)) != 0 ||
-	    (r = sshbuf_put_string(msg, blob, blen)) != 0 ||
-	    (r = sshbuf_put_string(msg, dgst, dgst_len)) != 0 ||
-	    (r = sshbuf_put_u32(msg, 0)) != 0)
-		fatal_fr(r, "compose");
-	send_msg(helper->fd, msg);
-	sshbuf_reset(msg);
+	if ((r = sshbuf_get_string(msg, &signature, &signature_len)) != 0)
+		fatal_fr(r, "parse");
 
-	if (recv_msg(helper->fd, msg) == SSH2_AGENT_SIGN_RESPONSE) {
-		if ((r = sshbuf_get_string(msg, &signature, &slen)) != 0)
-			fatal_fr(r, "parse");
-		cp = signature;
-		ret = d2i_ECDSA_SIG(NULL, &cp, slen);
-		free(signature);
+	/* success */
+	if (sigp != NULL) {
+		*sigp = signature;
+		signature = NULL;
 	}
+	if (lenp != NULL)
+		*lenp = signature_len;
+	ret = 0;
 
  fail:
-	free(blob);
-	sshkey_free(key);
 	sshbuf_free(msg);
-	return (ret);
-}
-
-static void
-ecdsa_do_finish(EC_KEY *ec)
-{
-	struct helper *helper;
-
-	if ((helper = helper_by_ec(ec)) == NULL)
-		fatal_f("no helper for PKCS11 key");
-	debug3_f("free PKCS11 ECDSA key for provider %s", helper->path);
-	if (helper->ec_finish != NULL)
-		helper->ec_finish(ec);
-	if (helper->nec == 0)
-		fatal_f("ECDSA refcount error");
-	helper->nec--;
-	debug3_f("provider %s remaining keys: %zu RSA %zu ECDSA",
-	    helper->path, helper->nrsa, helper->nec);
-	if (helper->nrsa == 0 && helper->nec == 0)
-		helper_terminate(helper);
-}
-
-/* redirect private key crypto operations to the ssh-pkcs11-helper */
-static void
-wrap_key(struct helper *helper, struct sshkey *k)
-{
-	RSA *rsa = NULL;
-	EC_KEY *ecdsa = NULL;
-
-	debug3_f("wrap %s for provider %s", sshkey_type(k), helper->path);
-	if (k->type == KEY_RSA) {
-		if ((rsa = EVP_PKEY_get1_RSA(k->pkey)) == NULL)
-			fatal_f("no RSA key");
-		if (RSA_set_method(rsa, helper->rsa_meth) != 1)
-			fatal_f("RSA_set_method failed");
-		if (helper->nrsa++ >= INT_MAX)
-			fatal_f("RSA refcount error");
-		if (EVP_PKEY_set1_RSA(k->pkey, rsa) != 1)
-			fatal_f("EVP_PKEY_set1_RSA failed");
-		RSA_free(rsa);
-	} else if (k->type == KEY_ECDSA) {
-		if ((ecdsa = EVP_PKEY_get1_EC_KEY(k->pkey)) == NULL)
-			fatal_f("no ECDSA key");
-		if (EC_KEY_set_method(ecdsa, helper->ec_meth) != 1)
-			fatal_f("EC_KEY_set_method failed");
-		if (helper->nec++ >= INT_MAX)
-			fatal_f("EC refcount error");
-		if (EVP_PKEY_set1_EC_KEY(k->pkey, ecdsa) != 1)
-			fatal_f("EVP_PKEY_set1_EC_KEY failed");
-		EC_KEY_free(ecdsa);
-	} else
-		fatal_f("unknown key type");
-	k->flags |= SSHKEY_FLAG_EXT;
-	debug3_f("provider %s remaining keys: %zu RSA %zu ECDSA",
-	    helper->path, helper->nrsa, helper->nec);
+	return ret;
 }
 
 /*
@@ -435,11 +291,13 @@ pkcs11_make_cert(const struct sshkey *priv,
 	struct helper *helper = NULL;
 	struct sshkey *ret;
 	int r;
-	RSA *rsa_priv = NULL, *rsa_cert = NULL;
-	EC_KEY *ec_priv = NULL, *ec_cert = NULL;
 
-	debug3_f("private key type %s cert type %s", sshkey_type(priv),
-	    sshkey_type(certpub));
+	if ((helper = helper_by_key(priv)) == NULL || helper->fd == -1)
+		fatal_f("no helper for %s key", sshkey_type(priv));
+
+	debug3_f("private key type %s cert type %s on provider %s",
+	    sshkey_type(priv), sshkey_type(certpub), helper->path);
+
 	*certprivp = NULL;
 	if (!sshkey_is_cert(certpub) || sshkey_is_cert(priv) ||
 	    !sshkey_equal_public(priv, certpub)) {
@@ -448,91 +306,24 @@ pkcs11_make_cert(const struct sshkey *priv,
 		return SSH_ERR_INVALID_ARGUMENT;
 	}
 	*certprivp = NULL;
-	if (priv->type == KEY_RSA) {
-		if ((rsa_priv = EVP_PKEY_get1_RSA(priv->pkey)) == NULL)
-			fatal_f("no RSA pkey");
-		if ((helper = helper_by_rsa(rsa_priv)) == NULL ||
-		    helper->fd == -1)
-			fatal_f("no helper for PKCS11 RSA key");
-		if ((r = sshkey_from_private(priv, &ret)) != 0)
-			fatal_fr(r, "copy key");
-		if ((rsa_cert = EVP_PKEY_get1_RSA(ret->pkey)) == NULL)
-			fatal_f("no RSA cert pkey");
-		if (RSA_set_method(rsa_cert, helper->rsa_meth) != 1)
-			fatal_f("RSA_set_method failed");
-		if (helper->nrsa++ >= INT_MAX)
-			fatal_f("RSA refcount error");
-		if (EVP_PKEY_set1_RSA(ret->pkey, rsa_cert) != 1)
-			fatal_f("EVP_PKEY_set1_RSA failed");
-		RSA_free(rsa_priv);
-		RSA_free(rsa_cert);
-	} else if (priv->type == KEY_ECDSA) {
-		if ((ec_priv = EVP_PKEY_get1_EC_KEY(priv->pkey)) == NULL)
-			fatal_f("no EC pkey");
-		if ((helper = helper_by_ec(ec_priv)) == NULL ||
-		    helper->fd == -1)
-			fatal_f("no helper for PKCS11 EC key");
-		if ((r = sshkey_from_private(priv, &ret)) != 0)
-			fatal_fr(r, "copy key");
-		if ((ec_cert = EVP_PKEY_get1_EC_KEY(ret->pkey)) == NULL)
-			fatal_f("no EC cert pkey");
-		if (EC_KEY_set_method(ec_cert, helper->ec_meth) != 1)
-			fatal_f("EC_KEY_set_method failed");
-		if (helper->nec++ >= INT_MAX)
-			fatal_f("EC refcount error");
-		if (EVP_PKEY_set1_EC_KEY(ret->pkey, ec_cert) != 1)
-			fatal_f("EVP_PKEY_set1_EC_KEY failed");
-		EC_KEY_free(ec_priv);
-		EC_KEY_free(ec_cert);
-	} else
-		fatal_f("unknown key type %s", sshkey_type(priv));
+	if ((r = sshkey_from_private(priv, &ret)) != 0)
+		fatal_fr(r, "copy key");
 
 	ret->flags |= SSHKEY_FLAG_EXT;
 	if ((r = sshkey_to_certified(ret)) != 0 ||
 	    (r = sshkey_cert_copy(certpub, ret)) != 0)
 		fatal_fr(r, "graft certificate");
-	debug3_f("provider %s remaining keys: %zu RSA %zu ECDSA",
-	    helper->path, helper->nrsa, helper->nec);
+
+	helper_add_key(helper, ret);
+
+	debug3_f("provider %s: %zu remaining keys",
+	    helper->path, helper->nkeyblobs);
+
 	/* success */
 	*certprivp = ret;
 	return 0;
 }
 
-static int
-pkcs11_start_helper_methods(struct helper *helper)
-{
-	int (*ec_init)(EC_KEY *key);
-	int (*ec_copy)(EC_KEY *dest, const EC_KEY *src);
-	int (*ec_set_group)(EC_KEY *key, const EC_GROUP *grp);
-	int (*ec_set_private)(EC_KEY *key, const BIGNUM *priv_key);
-	int (*ec_set_public)(EC_KEY *key, const EC_POINT *pub_key);
-	int (*ec_sign)(int, const unsigned char *, int, unsigned char *,
-	    unsigned int *, const BIGNUM *, const BIGNUM *, EC_KEY *) = NULL;
-	RSA_METHOD *rsa_meth;
-	EC_KEY_METHOD *ec_meth;
-
-	if ((ec_meth = EC_KEY_METHOD_new(EC_KEY_OpenSSL())) == NULL)
-		return -1;
-	EC_KEY_METHOD_get_sign(ec_meth, &ec_sign, NULL, NULL);
-	EC_KEY_METHOD_set_sign(ec_meth, ec_sign, NULL, ecdsa_do_sign);
-	EC_KEY_METHOD_get_init(ec_meth, &ec_init, &helper->ec_finish,
-	    &ec_copy, &ec_set_group, &ec_set_private, &ec_set_public);
-	EC_KEY_METHOD_set_init(ec_meth, ec_init, ecdsa_do_finish,
-	    ec_copy, ec_set_group, ec_set_private, ec_set_public);
-
-	if ((rsa_meth = RSA_meth_dup(RSA_get_default_method())) == NULL)
-		fatal_f("RSA_meth_dup failed");
-	helper->rsa_finish = RSA_meth_get_finish(rsa_meth);
-	if (!RSA_meth_set1_name(rsa_meth, "ssh-pkcs11-helper") ||
-	    !RSA_meth_set_priv_enc(rsa_meth, rsa_encrypt) ||
-	    !RSA_meth_set_finish(rsa_meth, rsa_finish))
-		fatal_f("failed to prepare method");
-
-	helper->ec_meth = ec_meth;
-	helper->rsa_meth = rsa_meth;
-	return 0;
-}
-
 static struct helper *
 pkcs11_start_helper(const char *path)
 {
@@ -549,17 +340,10 @@ pkcs11_start_helper(const char *path)
 		return NULL;
 	}
 	helper = xcalloc(1, sizeof(*helper));
-	if (pkcs11_start_helper_methods(helper) == -1) {
-		error_f("pkcs11_start_helper_methods failed");
-		goto fail;
-	}
 	if ((pid = fork()) == -1) {
 		error_f("fork: %s", strerror(errno));
- fail:
 		close(pair[0]);
 		close(pair[1]);
-		RSA_meth_free(helper->rsa_meth);
-		EC_KEY_METHOD_free(helper->ec_meth);
 		free(helper);
 		return NULL;
 	} else if (pid == 0) {
@@ -599,10 +383,8 @@ pkcs11_add_provider(char *name, char *pin, struct sshkey ***keysp,
 {
 	struct sshkey *k;
 	int r, type;
-	u_char *blob;
 	char *label;
-	size_t blen;
-	u_int nkeys, i;
+	u_int ret = -1, nkeys, i;
 	struct sshbuf *msg;
 	struct helper *helper;
 
@@ -610,6 +392,8 @@ pkcs11_add_provider(char *name, char *pin, struct sshkey ***keysp,
 	    (helper = pkcs11_start_helper(name)) == NULL)
 		return -1;
 
+	debug3_f("add %s", helper->path);
+
 	if ((msg = sshbuf_new()) == NULL)
 		fatal_f("sshbuf_new failed");
 	if ((r = sshbuf_put_u8(msg, SSH_AGENTC_ADD_SMARTCARD_KEY)) != 0 ||
@@ -620,35 +404,39 @@ pkcs11_add_provider(char *name, char *pin, struct sshkey ***keysp,
 	sshbuf_reset(msg);
 
 	type = recv_msg(helper->fd, msg);
+	debug3_f("response %d", type);
 	if (type == SSH2_AGENT_IDENTITIES_ANSWER) {
 		if ((r = sshbuf_get_u32(msg, &nkeys)) != 0)
 			fatal_fr(r, "parse nkeys");
+		debug3_f("helper return %u keys", nkeys);
 		*keysp = xcalloc(nkeys, sizeof(struct sshkey *));
 		if (labelsp)
 			*labelsp = xcalloc(nkeys, sizeof(char *));
 		for (i = 0; i < nkeys; i++) {
 			/* XXX clean up properly instead of fatal() */
-			if ((r = sshbuf_get_string(msg, &blob, &blen)) != 0 ||
+			if ((r = sshkey_froms(msg, &k)) != 0 ||
 			    (r = sshbuf_get_cstring(msg, &label, NULL)) != 0)
 				fatal_fr(r, "parse key");
-			if ((r = sshkey_from_blob(blob, blen, &k)) != 0)
-				fatal_fr(r, "decode key");
-			wrap_key(helper, k);
+			k->flags |= SSHKEY_FLAG_EXT;
+			helper_add_key(helper, k);
 			(*keysp)[i] = k;
 			if (labelsp)
 				(*labelsp)[i] = label;
 			else
 				free(label);
-			free(blob);
 		}
+		/* success */
+		ret = 0;
 	} else if (type == SSH2_AGENT_FAILURE) {
 		if ((r = sshbuf_get_u32(msg, &nkeys)) != 0)
-			nkeys = -1;
-	} else {
-		nkeys = -1;
+			error_fr(r, "failed to parse failure response");
+	}
+	if (ret != 0) {
+		debug_f("no keys; terminate helper");
+		helper_terminate(helper);
 	}
 	sshbuf_free(msg);
-	return (nkeys);
+	return ret == 0 ? nkeys : -1;
 }
 
 int
@@ -665,3 +453,39 @@ pkcs11_del_provider(char *name)
 		helper_terminate(helper);
 	return 0;
 }
+
+void
+pkcs11_key_free(struct sshkey *key)
+{
+	struct helper *helper;
+	struct sshbuf *keyblob = NULL;
+	size_t i;
+	int r, found = 0;
+
+	debug3_f("free %s key", sshkey_type(key));
+
+	if ((helper = helper_by_key(key)) == NULL || helper->fd == -1)
+		fatal_f("no helper for %s key", sshkey_type(key));
+	if ((keyblob = sshbuf_new()) == NULL)
+		fatal_f("sshbuf_new failed");
+	if ((r = sshkey_putb(key, keyblob)) != 0)
+		fatal_fr(r, "serialise key");
+
+	/* repack keys */
+	for (i = 0; i < helper->nkeyblobs; i++) {
+		if (sshbuf_equals(keyblob, helper->keyblobs[i]) == 0) {
+			if (found)
+				fatal_f("key recorded more than once");
+			found = 1;
+		} else if (found)
+			helper->keyblobs[i - 1] = helper->keyblobs[i];
+	}
+	if (found) {
+		helper->keyblobs = xrecallocarray(helper->keyblobs,
+		    helper->nkeyblobs, helper->nkeyblobs - 1,
+		    sizeof(*helper->keyblobs));
+		helper->nkeyblobs--;
+	}
+	if (helper->nkeyblobs == 0)
+		helper_terminate(helper);
+}
diff --git a/ssh-pkcs11-helper.c b/ssh-pkcs11-helper.c
index 3f79a00..8d8d34a 100644
--- a/ssh-pkcs11-helper.c
+++ b/ssh-pkcs11-helper.c
@@ -35,19 +35,9 @@
 #include "ssh-pkcs11.h"
 #include "ssherr.h"
 
-#ifdef WITH_OPENSSL
-#include <openssl/ec.h>
-#include <openssl/rsa.h>
-
 /* borrows code from sftp-server and ssh-agent */
 
-struct pkcs11_keyinfo {
-	struct sshkey	*key;
-	char		*providername, *label;
-	TAILQ_ENTRY(pkcs11_keyinfo) next;
-};
-
-TAILQ_HEAD(, pkcs11_keyinfo) pkcs11_keylist;
+static char *providername; /* Provider for this helper */
 
 #define MAX_MSG_LENGTH		10240 /*XXX*/
 
@@ -55,50 +45,6 @@ TAILQ_HEAD(, pkcs11_keyinfo) pkcs11_keylist;
 struct sshbuf *iqueue;
 struct sshbuf *oqueue;
 
-static void
-add_key(struct sshkey *k, char *name, char *label)
-{
-	struct pkcs11_keyinfo *ki;
-
-	ki = xcalloc(1, sizeof(*ki));
-	ki->providername = xstrdup(name);
-	ki->key = k;
-	ki->label = xstrdup(label);
-	TAILQ_INSERT_TAIL(&pkcs11_keylist, ki, next);
-}
-
-static void
-del_keys_by_name(char *name)
-{
-	struct pkcs11_keyinfo *ki, *nxt;
-
-	for (ki = TAILQ_FIRST(&pkcs11_keylist); ki; ki = nxt) {
-		nxt = TAILQ_NEXT(ki, next);
-		if (!strcmp(ki->providername, name)) {
-			TAILQ_REMOVE(&pkcs11_keylist, ki, next);
-			free(ki->providername);
-			free(ki->label);
-			sshkey_free(ki->key);
-			free(ki);
-		}
-	}
-}
-
-/* lookup matching 'private' key */
-static struct sshkey *
-lookup_key(struct sshkey *k)
-{
-	struct pkcs11_keyinfo *ki;
-
-	TAILQ_FOREACH(ki, &pkcs11_keylist, next) {
-		debug("check %s %s %s", sshkey_type(ki->key),
-		    ki->providername, ki->label);
-		if (sshkey_equal(k, ki->key))
-			return (ki->key);
-	}
-	return (NULL);
-}
-
 static void
 send_msg(struct sshbuf *m)
 {
@@ -111,34 +57,32 @@ send_msg(struct sshbuf *m)
 static void
 process_add(void)
 {
-	char *name, *pin;
+	char *pin;
 	struct sshkey **keys = NULL;
 	int r, i, nkeys;
-	u_char *blob;
-	size_t blen;
 	struct sshbuf *msg;
 	char **labels = NULL;
 
+	if (providername != NULL)
+		fatal_f("provider already set");
 	if ((msg = sshbuf_new()) == NULL)
 		fatal_f("sshbuf_new failed");
-	if ((r = sshbuf_get_cstring(iqueue, &name, NULL)) != 0 ||
+	if ((r = sshbuf_get_cstring(iqueue, &providername, NULL)) != 0 ||
 	    (r = sshbuf_get_cstring(iqueue, &pin, NULL)) != 0)
 		fatal_fr(r, "parse");
-	if ((nkeys = pkcs11_add_provider(name, pin, &keys, &labels)) > 0) {
+	debug3_f("add %s", providername);
+	if ((nkeys = pkcs11_add_provider(providername, pin,
+	    &keys, &labels)) > 0) {
 		if ((r = sshbuf_put_u8(msg,
 		    SSH2_AGENT_IDENTITIES_ANSWER)) != 0 ||
 		    (r = sshbuf_put_u32(msg, nkeys)) != 0)
 			fatal_fr(r, "compose");
 		for (i = 0; i < nkeys; i++) {
-			if ((r = sshkey_to_blob(keys[i], &blob, &blen)) != 0) {
-				debug_fr(r, "encode key");
-				continue;
-			}
-			if ((r = sshbuf_put_string(msg, blob, blen)) != 0 ||
+			if ((r = sshkey_puts(keys[i], msg)) != 0 ||
 			    (r = sshbuf_put_cstring(msg, labels[i])) != 0)
 				fatal_fr(r, "compose key");
-			free(blob);
-			add_key(keys[i], name, labels[i]);
+			debug3_f("%s: %s \"%s\"", providername,
+			    sshkey_type(keys[i]), labels[i]);
 			free(labels[i]);
 		}
 	} else if ((r = sshbuf_put_u8(msg, SSH_AGENT_FAILURE)) != 0 ||
@@ -147,29 +91,6 @@ process_add(void)
 	free(labels);
 	free(keys); /* keys themselves are transferred to pkcs11_keylist */
 	free(pin);
-	free(name);
-	send_msg(msg);
-	sshbuf_free(msg);
-}
-
-static void
-process_del(void)
-{
-	char *name, *pin;
-	struct sshbuf *msg;
-	int r;
-
-	if ((msg = sshbuf_new()) == NULL)
-		fatal_f("sshbuf_new failed");
-	if ((r = sshbuf_get_cstring(iqueue, &name, NULL)) != 0 ||
-	    (r = sshbuf_get_cstring(iqueue, &pin, NULL)) != 0)
-		fatal_fr(r, "parse");
-	del_keys_by_name(name);
-	if ((r = sshbuf_put_u8(msg, pkcs11_del_provider(name) == 0 ?
-	    SSH_AGENT_SUCCESS : SSH_AGENT_FAILURE)) != 0)
-		fatal_fr(r, "compose");
-	free(pin);
-	free(name);
 	send_msg(msg);
 	sshbuf_free(msg);
 }
@@ -177,57 +98,32 @@ process_del(void)
 static void
 process_sign(void)
 {
-	u_char *blob, *data, *signature = NULL;
-	size_t blen, dlen;
-	u_int slen = 0;
-	int len, r, ok = -1;
-	struct sshkey *key = NULL, *found;
+	const u_char *data;
+	u_char *signature = NULL;
+	size_t dlen, slen = 0;
+	u_int compat;
+	int r, ok = -1;
+	struct sshkey *key = NULL;
 	struct sshbuf *msg;
-	RSA *rsa = NULL;
-	EC_KEY *ecdsa = NULL;
+	char *alg = NULL;
 
-	/* XXX support SHA2 signature flags */
-	if ((r = sshbuf_get_string(iqueue, &blob, &blen)) != 0 ||
-	    (r = sshbuf_get_string(iqueue, &data, &dlen)) != 0 ||
-	    (r = sshbuf_get_u32(iqueue, NULL)) != 0)
+	if ((r = sshkey_froms(iqueue, &key)) != 0 ||
+	    (r = sshbuf_get_string_direct(iqueue, &data, &dlen)) != 0 ||
+	    (r = sshbuf_get_cstring(iqueue, &alg, NULL)) != 0 ||
+	    (r = sshbuf_get_u32(iqueue, &compat)) != 0)
 		fatal_fr(r, "parse");
 
-	if ((r = sshkey_from_blob(blob, blen, &key)) != 0)
-		fatal_fr(r, "decode key");
-	if ((found = lookup_key(key)) == NULL)
+	if (*alg == '\0') {
+		free(alg);
+		alg = NULL;
+	}
+
+	if ((r = pkcs11_sign(key, &signature, &slen, data, dlen,
+	    alg, NULL, NULL, compat)) != 0) {
+		error_fr(r, "sign %s", sshkey_type(key));
 		goto reply;
-
-	/* XXX use pkey API properly for signing */
-	switch (key->type) {
-	case KEY_RSA:
-		if ((rsa = EVP_PKEY_get1_RSA(found->pkey)) == NULL)
-			fatal_f("no RSA in pkey");
-		if ((len = RSA_size(rsa)) < 0)
-			fatal_f("bad RSA length");
-		signature = xmalloc(len);
-		if ((len = RSA_private_encrypt(dlen, data, signature,
-		    rsa, RSA_PKCS1_PADDING)) < 0) {
-			error_f("RSA_private_encrypt failed");
-			goto reply;
-		}
-		slen = (u_int)len;
-		break;
-	case KEY_ECDSA:
-		if ((ecdsa = EVP_PKEY_get1_EC_KEY(found->pkey)) == NULL)
-			fatal_f("no ECDSA in pkey");
-		if ((len = ECDSA_size(ecdsa)) < 0)
-			fatal_f("bad ECDSA length");
-		slen = (u_int)len;
-		signature = xmalloc(slen);
-		/* "The parameter type is ignored." */
-		if (!ECDSA_sign(-1, data, dlen, signature, &slen, ecdsa)) {
-			error_f("ECDSA_sign failed");
-			goto reply;
-		}
-		break;
-	default:
-		fatal_f("unsupported key type %d", key->type);
 	}
+
 	/* success */
 	ok = 0;
  reply:
@@ -242,10 +138,7 @@ process_sign(void)
 			fatal_fr(r, "compose failure response");
 	}
 	sshkey_free(key);
-	RSA_free(rsa);
-	EC_KEY_free(ecdsa);
-	free(data);
-	free(blob);
+	free(alg);
 	free(signature);
 	send_msg(msg);
 	sshbuf_free(msg);
@@ -281,10 +174,6 @@ process(void)
 		debug("process_add");
 		process_add();
 		break;
-	case SSH_AGENTC_REMOVE_SMARTCARD_KEY:
-		debug("process_del");
-		process_del();
-		break;
 	case SSH2_AGENTC_SIGN_REQUEST:
 		debug("process_sign");
 		process_sign();
@@ -316,7 +205,6 @@ cleanup_exit(int i)
 	_exit(i);
 }
 
-
 int
 main(int argc, char **argv)
 {
@@ -328,8 +216,6 @@ main(int argc, char **argv)
 	extern char *__progname;
 	struct pollfd pfd[2];
 
-	TAILQ_INIT(&pkcs11_keylist);
-
 	log_init(__progname, log_level, log_facility, log_stderr);
 
 	while ((ch = getopt(argc, argv, "v")) != -1) {
@@ -417,18 +303,3 @@ main(int argc, char **argv)
 			fatal_fr(r, "reserve");
 	}
 }
-
-#else /* WITH_OPENSSL */
-void
-cleanup_exit(int i)
-{
-	_exit(i);
-}
-
-int
-main(int argc, char **argv)
-{
-	fprintf(stderr, "PKCS#11 code is not enabled\n");
-	return 1;
-}
-#endif /* WITH_OPENSSL */
diff --git a/ssh-pkcs11.c b/ssh-pkcs11.c
index 0174255..6a2682a 100644
--- a/ssh-pkcs11.c
+++ b/ssh-pkcs11.c
@@ -25,19 +25,25 @@
 #include <string.h>
 #include <dlfcn.h>
 
+#ifdef WITH_OPENSSL
 #include <openssl/ecdsa.h>
 #include <openssl/x509.h>
 #include <openssl/err.h>
+#endif
 
 #define CRYPTOKI_COMPAT
 #include "pkcs11.h"
 
+#define SSHKEY_INTERNAL
+#include "sshkey.h"
+
 #include "log.h"
 #include "misc.h"
-#include "sshkey.h"
+#include "sshbuf.h"
 #include "ssh-pkcs11.h"
 #include "digest.h"
 #include "xmalloc.h"
+#include "crypto_api.h"
 
 struct pkcs11_slotinfo {
 	CK_TOKEN_INFO		token;
@@ -61,15 +67,19 @@ struct pkcs11_provider {
 TAILQ_HEAD(, pkcs11_provider) pkcs11_providers;
 
 struct pkcs11_key {
+	struct sshbuf		*keyblob;
 	struct pkcs11_provider	*provider;
 	CK_ULONG		slotidx;
 	char			*keyid;
 	int			keyid_len;
+	TAILQ_ENTRY(pkcs11_key)	next;
 };
 
+TAILQ_HEAD(, pkcs11_key) pkcs11_keys; /* XXX a tree would be better */
+
 int pkcs11_interactive = 0;
 
-#ifdef HAVE_DLOPEN
+#ifdef WITH_OPENSSL
 static void
 ossl_error(const char *msg)
 {
@@ -81,14 +91,6 @@ ossl_error(const char *msg)
 }
 #endif
 
-int
-pkcs11_init(int interactive)
-{
-	pkcs11_interactive = interactive;
-	TAILQ_INIT(&pkcs11_providers);
-	return (0);
-}
-
 /*
  * finalize a provider shared library, it's no longer usable.
  * however, there might still be keys referencing this provider,
@@ -138,19 +140,6 @@ pkcs11_provider_unref(struct pkcs11_provider *p)
 	}
 }
 
-/* unregister all providers, keys might still point to the providers */
-void
-pkcs11_terminate(void)
-{
-	struct pkcs11_provider *p;
-
-	while ((p = TAILQ_FIRST(&pkcs11_providers)) != NULL) {
-		TAILQ_REMOVE(&pkcs11_providers, p, next);
-		pkcs11_provider_finalize(p);
-		pkcs11_provider_unref(p);
-	}
-}
-
 /* lookup provider by name */
 static struct pkcs11_provider *
 pkcs11_provider_lookup(char *provider_id)
@@ -181,24 +170,17 @@ pkcs11_del_provider(char *provider_id)
 }
 
 #ifdef HAVE_DLOPEN
-static RSA_METHOD *rsa_method;
-static int rsa_idx = 0;
-static EC_KEY_METHOD *ec_key_method;
-static int ec_key_idx = 0;
 
 /* release a wrapped object */
 static void
-pkcs11_k11_free(void *parent, void *ptr, CRYPTO_EX_DATA *ad, int idx,
-    long argl, void *argp)
+pkcs11_k11_free(struct pkcs11_key *k11)
 {
-	struct pkcs11_key	*k11 = ptr;
-
-	debug_f("parent %p ptr %p idx %d", parent, ptr, idx);
 	if (k11 == NULL)
 		return;
 	if (k11->provider)
 		pkcs11_provider_unref(k11->provider);
 	free(k11->keyid);
+	sshbuf_free(k11->keyblob);
 	free(k11);
 }
 
@@ -408,82 +390,42 @@ pkcs11_get_key(struct pkcs11_key *k11, CK_MECHANISM_TYPE mech_type)
 	return (0);
 }
 
-/* openssl callback doing the actual signing operation */
+/* record the key information later use lookup by keyblob */
 static int
-pkcs11_rsa_private_encrypt(int flen, const u_char *from, u_char *to, RSA *rsa,
-    int padding)
+pkcs11_record_key(struct pkcs11_provider *provider, CK_ULONG slotidx,
+    CK_ATTRIBUTE *keyid_attrib, struct sshkey *key)
 {
-	struct pkcs11_key	*k11;
-	struct pkcs11_slotinfo	*si;
-	CK_FUNCTION_LIST	*f;
-	CK_ULONG		tlen = 0;
-	CK_RV			rv;
-	int			rval = -1;
-
-	if ((k11 = RSA_get_ex_data(rsa, rsa_idx)) == NULL) {
-		error("RSA_get_ex_data failed");
-		return (-1);
-	}
-
-	if (pkcs11_get_key(k11, CKM_RSA_PKCS) == -1) {
-		error("pkcs11_get_key failed");
-		return (-1);
+	struct sshbuf *keyblob;
+	struct pkcs11_key *k11;
+	int r;
+	char *hex;
+
+	hex = tohex(keyid_attrib->pValue, keyid_attrib->ulValueLen);
+	debug_f("%s key: provider %s slot %lu keyid %s",
+	    sshkey_type(key), provider->name, (u_long)slotidx, hex);
+	free(hex);
+
+	if ((keyblob = sshbuf_new()) == NULL)
+		fatal_f("sshbuf_new failed");
+	if ((r = sshkey_putb(key, keyblob)) != 0)
+		fatal_fr(r, "sshkey_putb");
+
+	/* Check if we've already recorded this key in a different slot */
+	TAILQ_FOREACH(k11, &pkcs11_keys, next) {
+		if (sshbuf_equals(k11->keyblob, keyblob) == 0) {
+			hex = tohex(k11->keyid, k11->keyid_len);
+			debug_f("Already seen this key at "
+			    "provider %s slot %lu keyid %s",
+			    k11->provider->name, k11->slotidx, hex);
+			free(hex);
+			sshbuf_free(keyblob);
+			return -1;
+		}
 	}
 
-	f = k11->provider->function_list;
-	si = &k11->provider->slotinfo[k11->slotidx];
-	tlen = RSA_size(rsa);
-
-	/* XXX handle CKR_BUFFER_TOO_SMALL */
-	rv = f->C_Sign(si->session, (CK_BYTE *)from, flen, to, &tlen);
-	if (rv == CKR_OK)
-		rval = tlen;
-	else
-		error("C_Sign failed: %lu", rv);
-
-	return (rval);
-}
-
-static int
-pkcs11_rsa_private_decrypt(int flen, const u_char *from, u_char *to, RSA *rsa,
-    int padding)
-{
-	return (-1);
-}
-
-static int
-pkcs11_rsa_start_wrapper(void)
-{
-	if (rsa_method != NULL)
-		return (0);
-	rsa_method = RSA_meth_dup(RSA_get_default_method());
-	if (rsa_method == NULL)
-		return (-1);
-	rsa_idx = RSA_get_ex_new_index(0, "ssh-pkcs11-rsa",
-	    NULL, NULL, pkcs11_k11_free);
-	if (rsa_idx == -1)
-		return (-1);
-	if (!RSA_meth_set1_name(rsa_method, "pkcs11") ||
-	    !RSA_meth_set_priv_enc(rsa_method, pkcs11_rsa_private_encrypt) ||
-	    !RSA_meth_set_priv_dec(rsa_method, pkcs11_rsa_private_decrypt)) {
-		error_f("setup pkcs11 method failed");
-		return (-1);
-	}
-	return (0);
-}
-
-/* redirect private key operations for rsa key to pkcs11 token */
-static int
-pkcs11_rsa_wrap(struct pkcs11_provider *provider, CK_ULONG slotidx,
-    CK_ATTRIBUTE *keyid_attrib, RSA *rsa)
-{
-	struct pkcs11_key	*k11;
-
-	if (pkcs11_rsa_start_wrapper() == -1)
-		return (-1);
-
 	k11 = xcalloc(1, sizeof(*k11));
 	k11->provider = provider;
+	k11->keyblob = keyblob;
 	provider->refcount++;	/* provider referenced by RSA key */
 	k11->slotidx = slotidx;
 	/* identify key object on smartcard */
@@ -492,127 +434,340 @@ pkcs11_rsa_wrap(struct pkcs11_provider *provider, CK_ULONG slotidx,
 		k11->keyid = xmalloc(k11->keyid_len);
 		memcpy(k11->keyid, keyid_attrib->pValue, k11->keyid_len);
 	}
+	TAILQ_INSERT_TAIL(&pkcs11_keys, k11, next);
 
-	if (RSA_set_method(rsa, rsa_method) != 1)
-		fatal_f("RSA_set_method failed");
-	if (RSA_set_ex_data(rsa, rsa_idx, k11) != 1)
-		fatal_f("RSA_set_ex_data failed");
-	return (0);
+	return 0;
 }
 
-/* openssl callback doing the actual signing operation */
-static ECDSA_SIG *
-ecdsa_do_sign(const unsigned char *dgst, int dgst_len, const BIGNUM *inv,
-    const BIGNUM *rp, EC_KEY *ec)
+/* retrieve the key information by keyblob */
+static struct pkcs11_key *
+pkcs11_lookup_key(struct sshkey *key)
+{
+	struct pkcs11_key *k11, *found = NULL;
+	struct sshbuf *keyblob;
+	int r;
+
+	if ((keyblob = sshbuf_new()) == NULL)
+		fatal_f("sshbuf_new failed");
+	if ((r = sshkey_putb(key, keyblob)) != 0)
+		fatal_fr(r, "sshkey_putb");
+	TAILQ_FOREACH(k11, &pkcs11_keys, next) {
+		if (sshbuf_equals(k11->keyblob, keyblob) == 0) {
+			found = k11;
+			break;
+		}
+	}
+	sshbuf_free(keyblob);
+	return found;
+}
+
+#ifdef WITH_OPENSSL
+/*
+ * See:
+ * http://www.rsasecurity.com/rsalabs/pkcs/pkcs-1/
+ * ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1.asn
+ */
+
+/*
+ * id-sha1 OBJECT IDENTIFIER ::= { iso(1) identified-organization(3)
+ *	oiw(14) secsig(3) algorithms(2) 26 }
+ */
+static const u_char id_sha1[] = {
+	0x30, 0x21, /* type Sequence, length 0x21 (33) */
+	0x30, 0x09, /* type Sequence, length 0x09 */
+	0x06, 0x05, /* type OID, length 0x05 */
+	0x2b, 0x0e, 0x03, 0x02, 0x1a, /* id-sha1 OID */
+	0x05, 0x00, /* NULL */
+	0x04, 0x14  /* Octet string, length 0x14 (20), followed by sha1 hash */
+};
+
+/*
+ * See http://csrc.nist.gov/groups/ST/crypto_apps_infra/csor/algorithms.html
+ * id-sha256 OBJECT IDENTIFIER ::= { joint-iso-itu-t(2) country(16) us(840)
+ *      organization(1) gov(101) csor(3) nistAlgorithm(4) hashAlgs(2)
+ *      id-sha256(1) }
+ */
+static const u_char id_sha256[] = {
+	0x30, 0x31, /* type Sequence, length 0x31 (49) */
+	0x30, 0x0d, /* type Sequence, length 0x0d (13) */
+	0x06, 0x09, /* type OID, length 0x09 */
+	0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, /* id-sha256 */
+	0x05, 0x00, /* NULL */
+	0x04, 0x20  /* Octet string, length 0x20 (32), followed by sha256 hash */
+};
+
+/*
+ * See http://csrc.nist.gov/groups/ST/crypto_apps_infra/csor/algorithms.html
+ * id-sha512 OBJECT IDENTIFIER ::= { joint-iso-itu-t(2) country(16) us(840)
+ *      organization(1) gov(101) csor(3) nistAlgorithm(4) hashAlgs(2)
+ *      id-sha256(3) }
+ */
+static const u_char id_sha512[] = {
+	0x30, 0x51, /* type Sequence, length 0x51 (81) */
+	0x30, 0x0d, /* type Sequence, length 0x0d (13) */
+	0x06, 0x09, /* type OID, length 0x09 */
+	0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, /* id-sha512 */
+	0x05, 0x00, /* NULL */
+	0x04, 0x40  /* Octet string, length 0x40 (64), followed by sha512 hash */
+};
+
+static int
+rsa_hash_alg_oid(int hash_alg, const u_char **oidp, size_t *oidlenp)
+{
+	switch (hash_alg) {
+	case SSH_DIGEST_SHA1:
+		*oidp = id_sha1;
+		*oidlenp = sizeof(id_sha1);
+		break;
+	case SSH_DIGEST_SHA256:
+		*oidp = id_sha256;
+		*oidlenp = sizeof(id_sha256);
+		break;
+	case SSH_DIGEST_SHA512:
+		*oidp = id_sha512;
+		*oidlenp = sizeof(id_sha512);
+		break;
+	default:
+		return SSH_ERR_INVALID_ARGUMENT;
+	}
+	return 0;
+}
+
+static int
+pkcs11_sign_rsa(struct sshkey *key,
+    u_char **sigp, size_t *lenp,
+    const u_char *data, size_t datalen,
+    const char *alg, const char *sk_provider,
+    const char *sk_pin, u_int compat)
 {
 	struct pkcs11_key	*k11;
 	struct pkcs11_slotinfo	*si;
 	CK_FUNCTION_LIST	*f;
-	CK_ULONG		siglen = 0, bnlen;
+	CK_ULONG		slen = 0;
 	CK_RV			rv;
-	ECDSA_SIG		*ret = NULL;
-	u_char			*sig;
-	BIGNUM			*r = NULL, *s = NULL;
+	int			hashalg, r, diff, siglen, ret = -1;
+	u_char			*oid_dgst = NULL, *sig = NULL;
+	size_t			dgst_len, oid_len, oid_dgst_len = 0;
+	const u_char		*oid;
+
+	if (sigp != NULL)
+		*sigp = 0;
+	if (lenp != NULL)
+		*lenp = 0;
+
+	if ((k11 = pkcs11_lookup_key(key)) == NULL) {
+		error_f("no key found");
+		return SSH_ERR_KEY_NOT_FOUND;
+	}
+
+	debug3_f("sign with alg \"%s\" using provider %s slotidx %lu",
+	    alg == NULL ? "" : alg, k11->provider->name, (u_long)k11->slotidx);
+
+	if (pkcs11_get_key(k11, CKM_RSA_PKCS) == -1) {
+		error("pkcs11_get_key failed");
+		return SSH_ERR_AGENT_FAILURE;
+	}
+
+	f = k11->provider->function_list;
+	si = &k11->provider->slotinfo[k11->slotidx];
+
+	if ((siglen = EVP_PKEY_size(key->pkey)) <= 0)
+		return SSH_ERR_INVALID_ARGUMENT;
+	sig = xmalloc(siglen);
+	slen = (CK_ULONG)siglen;
+
+	/* Determine hash algorithm and OID for signature */
+	if (alg == NULL || *alg == '\0')
+		hashalg = SSH_DIGEST_SHA1;
+	else if ((hashalg = ssh_rsa_hash_id_from_keyname(alg)) == -1)
+		fatal_f("couldn't determine RSA hash alg \"%s\"", alg);
+	if ((r = rsa_hash_alg_oid(hashalg, &oid, &oid_len)) != 0)
+		fatal_fr(r, "rsa_hash_alg_oid failed");
+	if ((dgst_len = ssh_digest_bytes(hashalg)) == 0)
+		fatal_f("bad hash alg %d", hashalg);
+
+	/* Prepare { oid || digest } */
+	oid_dgst_len = oid_len + dgst_len;
+	oid_dgst = xcalloc(1, oid_dgst_len);
+	memcpy(oid_dgst, oid, oid_len);
+	if ((r = ssh_digest_memory(hashalg, data, datalen,
+	    oid_dgst + oid_len, dgst_len)) == -1)
+		fatal_fr(r, "hash failed");
+
+	/* XXX handle CKR_BUFFER_TOO_SMALL */
+	if ((rv = f->C_Sign(si->session, (CK_BYTE *)oid_dgst,
+	    oid_dgst_len, sig, &slen)) != CKR_OK) {
+		error("C_Sign failed: %lu", rv);
+		goto done;
+	}
+
+	if (slen < (CK_ULONG)siglen) {
+		diff = siglen - slen;
+		debug3_f("repack %lu < %d (diff %d)",
+		    (u_long)slen, siglen, diff);
+		memmove(sig + diff, sig, slen);
+		explicit_bzero(sig, diff);
+	} else if (slen > (size_t)siglen)
+		fatal_f("bad C_Sign length");
+
+	if ((ret = ssh_rsa_encode_store_sig(hashalg, sig, siglen,
+	    sigp, lenp)) != 0)
+		fatal_fr(ret, "couldn't store signature");
+
+	/* success */
+	ret = 0;
+ done:
+	freezero(oid_dgst, oid_dgst_len);
+	free(sig);
+	return ret;
+}
+
+static int
+pkcs11_sign_ecdsa(struct sshkey *key,
+    u_char **sigp, size_t *lenp,
+    const u_char *data, size_t datalen,
+    const char *alg, const char *sk_provider,
+    const char *sk_pin, u_int compat)
+{
+	struct pkcs11_key	*k11;
+	struct pkcs11_slotinfo	*si;
+	CK_FUNCTION_LIST	*f;
+	CK_ULONG		slen = 0, bnlen;
+	CK_RV			rv;
+	BIGNUM			*sig_r = NULL, *sig_s = NULL;
+	u_char			*sig = NULL, *dgst = NULL;
+	size_t			dgst_len = 0;
+	int			hashalg, ret = -1, r, siglen;
+
+	if (sigp != NULL)
+		*sigp = 0;
+	if (lenp != NULL)
+		*lenp = 0;
 
-	if ((k11 = EC_KEY_get_ex_data(ec, ec_key_idx)) == NULL) {
-		ossl_error("EC_KEY_get_ex_data failed for ec");
-		return (NULL);
+	if ((k11 = pkcs11_lookup_key(key)) == NULL) {
+		error_f("no key found");
+		return SSH_ERR_KEY_NOT_FOUND;
 	}
 
 	if (pkcs11_get_key(k11, CKM_ECDSA) == -1) {
 		error("pkcs11_get_key failed");
-		return (NULL);
+		return SSH_ERR_AGENT_FAILURE;
 	}
 
+	debug3_f("sign using provider %s slotidx %lu",
+	    k11->provider->name, (u_long)k11->slotidx);
+
 	f = k11->provider->function_list;
 	si = &k11->provider->slotinfo[k11->slotidx];
 
-	siglen = ECDSA_size(ec);
+	/* Prepare digest to be signed */
+	if ((hashalg = sshkey_ec_nid_to_hash_alg(key->ecdsa_nid)) == -1)
+		fatal_f("couldn't determine ECDSA hash alg");
+	if ((dgst_len = ssh_digest_bytes(hashalg)) == 0)
+		fatal_f("bad hash alg %d", hashalg);
+	dgst = xcalloc(1, dgst_len);
+	if ((r = ssh_digest_memory(hashalg, data, datalen,
+	    dgst, dgst_len)) == -1)
+		fatal_fr(r, "hash failed");
+
+	if ((siglen = EVP_PKEY_size(key->pkey)) <= 0)
+		return SSH_ERR_INVALID_ARGUMENT;
 	sig = xmalloc(siglen);
+	slen = (CK_ULONG)siglen;
 
 	/* XXX handle CKR_BUFFER_TOO_SMALL */
-	rv = f->C_Sign(si->session, (CK_BYTE *)dgst, dgst_len, sig, &siglen);
+	rv = f->C_Sign(si->session, (CK_BYTE *)dgst, dgst_len, sig, &slen);
 	if (rv != CKR_OK) {
 		error("C_Sign failed: %lu", rv);
 		goto done;
 	}
-	if (siglen < 64 || siglen > 132 || siglen % 2) {
-		error_f("bad signature length: %lu", (u_long)siglen);
+	if (slen < 64 || slen > 132 || slen % 2) {
+		error_f("bad signature length: %lu", (u_long)slen);
 		goto done;
 	}
-	bnlen = siglen/2;
-	if ((ret = ECDSA_SIG_new()) == NULL) {
-		error("ECDSA_SIG_new failed");
-		goto done;
-	}
-	if ((r = BN_bin2bn(sig, bnlen, NULL)) == NULL ||
-	    (s = BN_bin2bn(sig+bnlen, bnlen, NULL)) == NULL) {
+	bnlen = slen/2;
+	if ((sig_r = BN_bin2bn(sig, bnlen, NULL)) == NULL ||
+	    (sig_s = BN_bin2bn(sig+bnlen, bnlen, NULL)) == NULL) {
 		ossl_error("BN_bin2bn failed");
-		ECDSA_SIG_free(ret);
-		ret = NULL;
 		goto done;
 	}
-	if (!ECDSA_SIG_set0(ret, r, s)) {
-		error_f("ECDSA_SIG_set0 failed");
-		ECDSA_SIG_free(ret);
-		ret = NULL;
-		goto done;
-	}
-	r = s = NULL; /* now owned by ret */
+
+	if ((ret = ssh_ecdsa_encode_store_sig(key, sig_r, sig_s,
+	    sigp, lenp)) != 0)
+		fatal_fr(ret, "couldn't store signature");
+
 	/* success */
+	ret = 0;
  done:
-	BN_free(r);
-	BN_free(s);
+	freezero(dgst, dgst_len);
+	BN_free(sig_r);
+	BN_free(sig_s);
 	free(sig);
-
-	return (ret);
-}
-
-static int
-pkcs11_ecdsa_start_wrapper(void)
-{
-	int (*orig_sign)(int, const unsigned char *, int, unsigned char *,
-	    unsigned int *, const BIGNUM *, const BIGNUM *, EC_KEY *) = NULL;
-
-	if (ec_key_method != NULL)
-		return (0);
-	ec_key_idx = EC_KEY_get_ex_new_index(0, "ssh-pkcs11-ecdsa",
-	    NULL, NULL, pkcs11_k11_free);
-	if (ec_key_idx == -1)
-		return (-1);
-	ec_key_method = EC_KEY_METHOD_new(EC_KEY_OpenSSL());
-	if (ec_key_method == NULL)
-		return (-1);
-	EC_KEY_METHOD_get_sign(ec_key_method, &orig_sign, NULL, NULL);
-	EC_KEY_METHOD_set_sign(ec_key_method, orig_sign, NULL, ecdsa_do_sign);
-	return (0);
+	return ret;
 }
+#endif /* WITH_OPENSSL */
 
 static int
-pkcs11_ecdsa_wrap(struct pkcs11_provider *provider, CK_ULONG slotidx,
-    CK_ATTRIBUTE *keyid_attrib, EC_KEY *ec)
+pkcs11_sign_ed25519(struct sshkey *key,
+    u_char **sigp, size_t *lenp,
+    const u_char *data, size_t datalen,
+    const char *alg, const char *sk_provider,
+    const char *sk_pin, u_int compat)
 {
 	struct pkcs11_key	*k11;
+	struct pkcs11_slotinfo	*si;
+	CK_FUNCTION_LIST	*f;
+	CK_ULONG		slen = 0;
+	CK_RV			rv;
+	u_char			*sig = NULL;
+	CK_BYTE			*xdata = NULL;
+	int			ret = -1;
 
-	if (pkcs11_ecdsa_start_wrapper() == -1)
-		return (-1);
-
-	k11 = xcalloc(1, sizeof(*k11));
-	k11->provider = provider;
-	provider->refcount++;	/* provider referenced by ECDSA key */
-	k11->slotidx = slotidx;
-	/* identify key object on smartcard */
-	k11->keyid_len = keyid_attrib->ulValueLen;
-	if (k11->keyid_len > 0) {
-		k11->keyid = xmalloc(k11->keyid_len);
-		memcpy(k11->keyid, keyid_attrib->pValue, k11->keyid_len);
+	if (sigp != NULL)
+		*sigp = 0;
+	if (lenp != NULL)
+		*lenp = 0;
+
+	if ((k11 = pkcs11_lookup_key(key)) == NULL) {
+		error_f("no key found");
+		return SSH_ERR_KEY_NOT_FOUND;
+	}
+
+	if (pkcs11_get_key(k11, CKM_EDDSA) == -1) {
+		error("pkcs11_get_key failed");
+		return SSH_ERR_AGENT_FAILURE;
+	}
+
+	debug3_f("sign using provider %s slotidx %lu",
+	    k11->provider->name, (u_long)k11->slotidx);
+
+	f = k11->provider->function_list;
+	si = &k11->provider->slotinfo[k11->slotidx];
+
+	xdata = xmalloc(datalen);
+	memcpy(xdata, data, datalen);
+	sig = xmalloc(crypto_sign_ed25519_BYTES);
+	slen = crypto_sign_ed25519_BYTES;
+
+	rv = f->C_Sign(si->session, xdata, datalen, sig, &slen);
+	if (rv != CKR_OK) {
+		error("C_Sign failed: %lu", rv);
+		goto done;
+	}
+	if (slen != crypto_sign_ed25519_BYTES) {
+		error_f("bad signature length: %lu", (u_long)slen);
+		goto done;
 	}
-	if (EC_KEY_set_method(ec, ec_key_method) != 1)
-		fatal_f("EC_KEY_set_method failed");
-	if (EC_KEY_set_ex_data(ec, ec_key_idx, k11) != 1)
-		fatal_f("EC_KEY_set_ex_data failed");
+	if ((ret = ssh_ed25519_encode_store_sig(sig, slen, sigp, lenp)) != 0)
+		fatal_fr(ret, "couldn't store signature");
 
-	return (0);
+	/* success */
+	ret = 0;
+ done:
+	if (xdata != NULL)
+		freezero(xdata, datalen);
+	free(sig);
+	return ret;
 }
 
 /* remove trailing spaces */
@@ -691,6 +846,7 @@ pkcs11_key_included(struct sshkey ***keysp, int *nkeys, struct sshkey *key)
 	return (0);
 }
 
+#ifdef WITH_OPENSSL
 static struct sshkey *
 pkcs11_fetch_ecdsa_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx,
     CK_OBJECT_HANDLE *obj)
@@ -704,8 +860,7 @@ pkcs11_fetch_ecdsa_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx,
 	EC_GROUP		*group = NULL;
 	struct sshkey		*key = NULL;
 	const unsigned char	*attrp = NULL;
-	int			 i;
-	int			 nid;
+	int			 success = -1, r, i, nid;
 
 	memset(&key_attr, 0, sizeof(key_attr));
 	key_attr[0].type = CKA_ID;
@@ -779,6 +934,11 @@ pkcs11_fetch_ecdsa_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx,
 		ossl_error("o2i_ECPublicKey failed");
 		goto fail;
 	}
+	if ((r = sshkey_ec_validate_public(EC_KEY_get0_group(ec),
+	    EC_KEY_get0_public_key(ec))) != 0) {
+		error_fr(r, "invalid EC key");
+		goto fail;
+	}
 
 	nid = sshkey_ecdsa_key_to_nid(ec);
 	if (nid < 0) {
@@ -786,9 +946,6 @@ pkcs11_fetch_ecdsa_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx,
 		goto fail;
 	}
 
-	if (pkcs11_ecdsa_wrap(p, slotidx, &key_attr[0], ec))
-		goto fail;
-
 	key = sshkey_new(KEY_UNSPEC);
 	if (key == NULL) {
 		error("sshkey_new failed");
@@ -803,8 +960,15 @@ pkcs11_fetch_ecdsa_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx,
 	key->ecdsa_nid = nid;
 	key->type = KEY_ECDSA;
 	key->flags |= SSHKEY_FLAG_EXT;
-
+	if (pkcs11_record_key(p, slotidx, &key_attr[0], key))
+		goto fail;
+	/* success */
+	success = 0;
 fail:
+	if (success != 0) {
+		sshkey_free(key);
+		key = NULL;
+	}
 	for (i = 0; i < 3; i++)
 		free(key_attr[i].pValue);
 	if (ec)
@@ -828,7 +992,7 @@ pkcs11_fetch_rsa_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx,
 	RSA			*rsa = NULL;
 	BIGNUM			*rsa_n, *rsa_e;
 	struct sshkey		*key = NULL;
-	int			 i;
+	int			 i, success = -1;
 
 	memset(&key_attr, 0, sizeof(key_attr));
 	key_attr[0].type = CKA_ID;
@@ -884,9 +1048,6 @@ pkcs11_fetch_rsa_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx,
 		fatal_f("set key");
 	rsa_n = rsa_e = NULL; /* transferred */
 
-	if (pkcs11_rsa_wrap(p, slotidx, &key_attr[0], rsa))
-		goto fail;
-
 	key = sshkey_new(KEY_UNSPEC);
 	if (key == NULL) {
 		error("sshkey_new failed");
@@ -900,15 +1061,136 @@ pkcs11_fetch_rsa_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx,
 		fatal("EVP_PKEY_set1_RSA failed");
 	key->type = KEY_RSA;
 	key->flags |= SSHKEY_FLAG_EXT;
-
+	if (EVP_PKEY_bits(key->pkey) < SSH_RSA_MINIMUM_MODULUS_SIZE) {
+		error_f("RSA key too small %d < minumum %d",
+		    EVP_PKEY_bits(key->pkey), SSH_RSA_MINIMUM_MODULUS_SIZE);
+		goto fail;
+	}
+	if (pkcs11_record_key(p, slotidx, &key_attr[0], key))
+		goto fail;
+	/* success */
+	success = 0;
 fail:
 	for (i = 0; i < 3; i++)
 		free(key_attr[i].pValue);
 	RSA_free(rsa);
+	if (success != 0) {
+		sshkey_free(key);
+		key = NULL;
+	}
+	return key;
+}
+#endif /* WITH_OPENSSL */
+
+static struct sshkey *
+pkcs11_fetch_ed25519_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx,
+    CK_OBJECT_HANDLE *obj)
+{
+	CK_ATTRIBUTE		 key_attr[3];
+	CK_SESSION_HANDLE	 session;
+	CK_FUNCTION_LIST	*f = NULL;
+	CK_RV			 rv;
+	struct sshkey		*key = NULL;
+	const unsigned char	*d = NULL;
+	size_t			len;
+	char			*hex = NULL;
+	int			 success = -1, i;
+	const u_char		 oid1[14] = {
+		0x13, 0x0c, 0x65, 0x64, 0x77, 0x61, 0x72, 0x64,
+		0x73, 0x32, 0x35, 0x35, 0x31, 0x39,
+	}; /* PrintableString { "edwards25519" } */
+	const u_char		 oid2[5] = {
+		0x06, 0x03, 0x2b, 0x65, 0x70,
+	}; /* OBJECT_IDENTIFIER { 1.3.101.112 } */
+
+	memset(&key_attr, 0, sizeof(key_attr));
+	key_attr[0].type = CKA_ID;
+	key_attr[1].type = CKA_EC_POINT; /* XXX or CKA_VALUE ? */
+	key_attr[2].type = CKA_EC_PARAMS;
+
+	session = p->slotinfo[slotidx].session;
+	f = p->function_list;
+
+	/* figure out size of the attributes */
+	rv = f->C_GetAttributeValue(session, *obj, key_attr, 3);
+	if (rv != CKR_OK) {
+		error("C_GetAttributeValue failed: %lu", rv);
+		return (NULL);
+	}
+
+	/*
+	 * Allow CKA_ID (always first attribute) to be empty, but
+	 * ensure that none of the others are zero length.
+	 * XXX assumes CKA_ID is always first.
+	 */
+	if (key_attr[1].ulValueLen == 0 ||
+	    key_attr[2].ulValueLen == 0) {
+		error("invalid attribute length");
+		return (NULL);
+	}
+
+	/* allocate buffers for attributes */
+	for (i = 0; i < 3; i++) {
+		if (key_attr[i].ulValueLen > 0)
+			key_attr[i].pValue = xcalloc(1, key_attr[i].ulValueLen);
+	}
+
+	/* retrieve ID, public point and curve parameters of EC key */
+	rv = f->C_GetAttributeValue(session, *obj, key_attr, 3);
+	if (rv != CKR_OK) {
+		error("C_GetAttributeValue failed: %lu", rv);
+		goto fail;
+	}
+
+	/* Expect one of the supported oids in CKA_EC_PARAMS */
+	d = (u_char *)key_attr[2].pValue;
+	len = key_attr[2].ulValueLen;
+	if ((len != sizeof(oid1) || memcmp(d, oid1, sizeof(oid1)) != 0) &&
+	    (len != sizeof(oid2) || memcmp(d, oid2, sizeof(oid2)) != 0)) {
+		hex = tohex(d, len);
+		logit_f("unsupported CKA_EC_PARAMS: %s (len %zu)", hex, len);
+		goto fail;
+	}
+
+	/*
+	 * Expect an either a raw 32 byte pubkey or an OCTET_STRING with
+	 * a 32 byte pubkey in CKA_VALUE
+	 */
+	d = (u_char *)key_attr[1].pValue;
+	len = key_attr[1].ulValueLen;
+	if (len != ED25519_PK_SZ + 2 && d[0] == 0x04 && d[1] == ED25519_PK_SZ) {
+		d += 2;
+		len -= 2;
+	}
+	if (len != ED25519_PK_SZ) {
+		hex = tohex(key_attr[1].pValue, key_attr[1].ulValueLen);
+		logit_f("CKA_EC_POINT invalid octet str: %s (len %lu)",
+		    hex, (u_long)key_attr[1].ulValueLen);
+		goto fail;
+	}
 
-	return (key);
+	if ((key = sshkey_new(KEY_UNSPEC)) == NULL)
+		fatal_f("sshkey_new failed");
+	key->ed25519_pk = xmalloc(ED25519_PK_SZ);
+	memcpy(key->ed25519_pk, d, ED25519_PK_SZ);
+	key->type = KEY_ED25519;
+	key->flags |= SSHKEY_FLAG_EXT;
+	if (pkcs11_record_key(p, slotidx, &key_attr[0], key))
+		goto fail;
+	/* success */
+	success = 0;
+ fail:
+	if (success != 0) {
+		sshkey_free(key);
+		key = NULL;
+	}
+	free(hex);
+	for (i = 0; i < 3; i++)
+		free(key_attr[i].pValue);
+	return key;
 }
 
+#ifdef WITH_OPENSSL
 static int
 pkcs11_fetch_x509_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx,
     CK_OBJECT_HANDLE *obj, struct sshkey **keyp, char **labelp)
@@ -923,10 +1205,10 @@ pkcs11_fetch_x509_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx,
 	RSA			*rsa = NULL;
 	EC_KEY			*ec = NULL;
 	struct sshkey		*key = NULL;
-	int			 i;
-	int			 nid;
+	int			 r, i, nid, success = -1;
 	const u_char		*cp;
 	char			*subject = NULL;
+	size_t			len;
 
 	*keyp = NULL;
 	*labelp = NULL;
@@ -998,9 +1280,6 @@ pkcs11_fetch_x509_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx,
 			goto out;
 		}
 
-		if (pkcs11_rsa_wrap(p, slotidx, &cert_attr[0], rsa))
-			goto out;
-
 		key = sshkey_new(KEY_UNSPEC);
 		if (key == NULL) {
 			error("sshkey_new failed");
@@ -1014,6 +1293,16 @@ pkcs11_fetch_x509_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx,
 			fatal("EVP_PKEY_set1_RSA failed");
 		key->type = KEY_RSA;
 		key->flags |= SSHKEY_FLAG_EXT;
+		if (EVP_PKEY_bits(key->pkey) < SSH_RSA_MINIMUM_MODULUS_SIZE) {
+			error_f("RSA key too small %d < minumum %d",
+			    EVP_PKEY_bits(key->pkey),
+			    SSH_RSA_MINIMUM_MODULUS_SIZE);
+			goto out;
+		}
+		if (pkcs11_record_key(p, slotidx, &cert_attr[0], key))
+			goto out;
+		/* success */
+		success = 0;
 	} else if (EVP_PKEY_base_id(evp) == EVP_PKEY_EC) {
 		if (EVP_PKEY_get0_EC_KEY(evp) == NULL) {
 			error("invalid x509; no ec key");
@@ -1023,16 +1312,17 @@ pkcs11_fetch_x509_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx,
 			error("EC_KEY_dup failed");
 			goto out;
 		}
-
+		if ((r = sshkey_ec_validate_public(EC_KEY_get0_group(ec),
+		    EC_KEY_get0_public_key(ec))) != 0) {
+			error_fr(r, "invalid EC key");
+			goto out;
+		}
 		nid = sshkey_ecdsa_key_to_nid(ec);
 		if (nid < 0) {
 			error("couldn't get curve nid");
 			goto out;
 		}
 
-		if (pkcs11_ecdsa_wrap(p, slotidx, &cert_attr[0], ec))
-			goto out;
-
 		key = sshkey_new(KEY_UNSPEC);
 		if (key == NULL) {
 			error("sshkey_new failed");
@@ -1047,6 +1337,30 @@ pkcs11_fetch_x509_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx,
 		key->ecdsa_nid = nid;
 		key->type = KEY_ECDSA;
 		key->flags |= SSHKEY_FLAG_EXT;
+		if (pkcs11_record_key(p, slotidx, &cert_attr[0], key))
+			goto out;
+		/* success */
+		success = 0;
+	} else if (EVP_PKEY_base_id(evp) == EVP_PKEY_ED25519) {
+		if ((key = sshkey_new(KEY_UNSPEC)) == NULL ||
+		    (key->ed25519_pk = calloc(1, ED25519_PK_SZ)) == NULL)
+			fatal_f("allocation failed");
+		len = ED25519_PK_SZ;
+		if (!EVP_PKEY_get_raw_public_key(evp, key->ed25519_pk, &len)) {
+			ossl_error("EVP_PKEY_get_raw_public_key failed");
+			goto out;
+		}
+		if (len != ED25519_PK_SZ) {
+			error_f("incorrect returned public key "
+			    "length for ed25519");
+			goto out;
+		}
+		key->type = KEY_ED25519;
+		key->flags |= SSHKEY_FLAG_EXT;
+		if (pkcs11_record_key(p, slotidx, &cert_attr[0], key))
+			goto out;
+		/* success */
+		success = 0;
 	} else {
 		error("unknown certificate key type");
 		goto out;
@@ -1057,7 +1371,8 @@ pkcs11_fetch_x509_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx,
 	X509_free(x509);
 	RSA_free(rsa);
 	EC_KEY_free(ec);
-	if (key == NULL) {
+	if (success != 0 || key == NULL) {
+		sshkey_free(key);
 		free(subject);
 		return -1;
 	}
@@ -1066,17 +1381,7 @@ pkcs11_fetch_x509_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx,
 	*labelp = subject;
 	return 0;
 }
-
-#if 0
-static int
-have_rsa_key(const RSA *rsa)
-{
-	const BIGNUM *rsa_n, *rsa_e;
-
-	RSA_get0_key(rsa, &rsa_n, &rsa_e, NULL);
-	return rsa_n != NULL && rsa_e != NULL;
-}
-#endif
+#endif /* WITH_OPENSSL */
 
 static void
 note_key(struct pkcs11_provider *p, CK_ULONG slotidx, const char *context,
@@ -1094,6 +1399,7 @@ note_key(struct pkcs11_provider *p, CK_ULONG slotidx, const char *context,
 	free(fp);
 }
 
+#ifdef WITH_OPENSSL /* libcrypto needed for certificate parsing */
 /*
  * lookup certificates for token in slot identified by slotidx,
  * add 'wrapped' public keys to the 'keysp' array and increment nkeys.
@@ -1198,6 +1504,7 @@ fail:
 
 	return (ret);
 }
+#endif /* WITH_OPENSSL */
 
 /*
  * lookup public keys for token in slot identified by slotidx,
@@ -1265,16 +1572,22 @@ pkcs11_fetch_keys(struct pkcs11_provider *p, CK_ULONG slotidx,
 		label[key_attr[1].ulValueLen] = '\0';
 
 		switch (ck_key_type) {
+#ifdef WITH_OPENSSL
 		case CKK_RSA:
 			key = pkcs11_fetch_rsa_pubkey(p, slotidx, &obj);
 			break;
 		case CKK_ECDSA:
 			key = pkcs11_fetch_ecdsa_pubkey(p, slotidx, &obj);
 			break;
+#endif /* WITH_OPENSSL */
+		case CKK_EC_EDWARDS:
+			key = pkcs11_fetch_ed25519_pubkey(p, slotidx, &obj);
+			break;
 		default:
 			/* XXX print key type? */
 			key = NULL;
-			error("skipping unsupported key type");
+			error("skipping unsupported key type 0x%lx",
+			    (u_long)ck_key_type);
 		}
 
 		if (key == NULL) {
@@ -1627,7 +1940,9 @@ pkcs11_register_provider(char *provider_id, char *pin,
 		    keyp == NULL)
 			continue;
 		pkcs11_fetch_keys(p, i, keyp, labelsp, &nkeys);
+#ifdef WITH_OPENSSL
 		pkcs11_fetch_certs(p, i, keyp, labelsp, &nkeys);
+#endif
 		if (nkeys == 0 && !p->slotinfo[i].logged_in &&
 		    pkcs11_interactive) {
 			/*
@@ -1640,7 +1955,9 @@ pkcs11_register_provider(char *provider_id, char *pin,
 				continue;
 			}
 			pkcs11_fetch_keys(p, i, keyp, labelsp, &nkeys);
+#ifdef WITH_OPENSSL
 			pkcs11_fetch_certs(p, i, keyp, labelsp, &nkeys);
+#endif
 		}
 	}
 
@@ -1668,6 +1985,35 @@ fail:
 	return (ret);
 }
 
+int
+pkcs11_init(int interactive)
+{
+	debug3_f("called, interactive = %d", interactive);
+
+	pkcs11_interactive = interactive;
+	TAILQ_INIT(&pkcs11_providers);
+	TAILQ_INIT(&pkcs11_keys);
+	return (0);
+}
+
+/* unregister all providers, keys might still point to the providers */
+void
+pkcs11_terminate(void)
+{
+	struct pkcs11_provider *p;
+	struct pkcs11_key *k11;
+
+	debug3_f("called");
+
+	while ((k11 = TAILQ_FIRST(&pkcs11_keys)) != NULL)
+		pkcs11_k11_free(k11);
+	while ((p = TAILQ_FIRST(&pkcs11_providers)) != NULL) {
+		TAILQ_REMOVE(&pkcs11_providers, p, next);
+		pkcs11_provider_finalize(p);
+		pkcs11_provider_unref(p);
+	}
+}
+
 /*
  * register a new provider and get number of keys hold by the token,
  * fails if provider already exists
@@ -1694,6 +2040,39 @@ pkcs11_add_provider(char *provider_id, char *pin, struct sshkey ***keyp,
 	return (nkeys);
 }
 
+int
+pkcs11_sign(struct sshkey *key,
+    u_char **sigp, size_t *lenp,
+    const u_char *data, size_t datalen,
+    const char *alg, const char *sk_provider,
+    const char *sk_pin, u_int compat)
+{
+	switch (key->type) {
+#ifdef WITH_OPENSSL
+	case KEY_RSA:
+	case KEY_RSA_CERT:
+		return pkcs11_sign_rsa(key, sigp, lenp, data, datalen,
+		    alg, sk_provider, sk_pin, compat);
+	case KEY_ECDSA:
+	case KEY_ECDSA_CERT:
+		return pkcs11_sign_ecdsa(key, sigp, lenp, data, datalen,
+		    alg, sk_provider, sk_pin, compat);
+#endif /* WITH_OPENSSL */
+	case KEY_ED25519:
+	case KEY_ED25519_CERT:
+		return pkcs11_sign_ed25519(key, sigp, lenp, data, datalen,
+		    alg, sk_provider, sk_pin, compat);
+	default:
+		return SSH_ERR_KEY_TYPE_UNKNOWN;
+	}
+}
+
+void
+pkcs11_key_free(struct sshkey *key)
+{
+	/* never called */
+}
+
 #ifdef WITH_PKCS11_KEYGEN
 struct sshkey *
 pkcs11_gakp(char *provider_id, char *pin, unsigned int slotidx, char *label,
@@ -1837,16 +2216,27 @@ pkcs11_destroy_keypair(char *provider_id, char *pin, unsigned long slotidx,
 			*err = rv;
 			key_type = -1;
 		}
-		if (key_type == CKK_RSA)
+		switch (key_type) {
+		case CKK_RSA:
 			k = pkcs11_fetch_rsa_pubkey(p, slotidx, &obj);
-		else if (key_type == CKK_ECDSA)
+			break;
+		case CKK_ECDSA:
 			k = pkcs11_fetch_ecdsa_pubkey(p, slotidx, &obj);
+			break;
+		case CKK_EC_EDWARDS:
+			k = pkcs11_fetch_ed25519_pubkey(p, slotidx, &obj);
+			break;
+		default:
+			debug_f("unsupported key type %lu", (u_long)key_type);
+			continue;
+		}
 
 		if ((rv = f->C_DestroyObject(session, obj)) != CKR_OK) {
 			debug_f("could not destroy public key 0x%hhx", keyid);
 			*err = rv;
 			goto out;
 		}
+		sshkey_free(k);
 	}
 
 out:
diff --git a/ssh-pkcs11.h b/ssh-pkcs11.h
index 5260223..2f05eba 100644
--- a/ssh-pkcs11.h
+++ b/ssh-pkcs11.h
@@ -22,10 +22,17 @@
 #define	SSH_PKCS11_ERR_PIN_REQUIRED		4
 #define	SSH_PKCS11_ERR_PIN_LOCKED		5
 
+struct sshkey;
+
 int	pkcs11_init(int);
 void	pkcs11_terminate(void);
 int	pkcs11_add_provider(char *, char *, struct sshkey ***, char ***);
 int	pkcs11_del_provider(char *);
+int	pkcs11_sign(struct sshkey *, u_char **, size_t *,
+	    const u_char *, size_t, const char *, const char *,
+	    const char *, u_int);
+void	pkcs11_key_free(struct sshkey *);
+
 #ifdef WITH_PKCS11_KEYGEN
 struct sshkey *
 	pkcs11_gakp(char *, char *, unsigned int, char *, unsigned int,
@@ -35,9 +42,6 @@ struct sshkey *
 	    u_int32_t *);
 #endif
 
-/* Only available in ssh-pkcs11-client.c so far */
+/* Only available in ssh-pkcs11-client.c */
 int pkcs11_make_cert(const struct sshkey *,
     const struct sshkey *, struct sshkey **);
-#if !defined(WITH_OPENSSL) && defined(ENABLE_PKCS11)
-#undef ENABLE_PKCS11
-#endif
diff --git a/ssh-rsa.c b/ssh-rsa.c
index 6492e60..bdccb43 100644
--- a/ssh-rsa.c
+++ b/ssh-rsa.c
@@ -302,8 +302,8 @@ ssh_rsa_deserialize_private(const char *ktype, struct sshbuf *b,
 	return r;
 }
 
-static const char *
-rsa_hash_alg_ident(int hash_alg)
+const char *
+ssh_rsa_hash_alg_ident(int hash_alg)
 {
 	switch (hash_alg) {
 	case SSH_DIGEST_SHA1:
@@ -337,8 +337,8 @@ rsa_hash_id_from_ident(const char *ident)
  * all the cases of rsa_hash_id_from_ident() but also the certificate key
  * types.
  */
-static int
-rsa_hash_id_from_keyname(const char *alg)
+int
+ssh_rsa_hash_id_from_keyname(const char *alg)
 {
 	int r;
 
@@ -403,7 +403,6 @@ ssh_rsa_sign(struct sshkey *key,
 	size_t diff, len = 0;
 	int slen = 0;
 	int hash_alg, ret = SSH_ERR_INTERNAL_ERROR;
-	struct sshbuf *b = NULL;
 
 	if (lenp != NULL)
 		*lenp = 0;
@@ -413,7 +412,7 @@ ssh_rsa_sign(struct sshkey *key,
 	if (alg == NULL || strlen(alg) == 0)
 		hash_alg = SSH_DIGEST_SHA1;
 	else
-		hash_alg = rsa_hash_id_from_keyname(alg);
+		hash_alg = ssh_rsa_hash_id_from_keyname(alg);
 
 	if (key == NULL || key->pkey == NULL || hash_alg == -1 ||
 	    sshkey_type_plain(key->type) != KEY_RSA)
@@ -435,16 +434,42 @@ ssh_rsa_sign(struct sshkey *key,
 		ret = SSH_ERR_INTERNAL_ERROR;
 		goto out;
 	}
+	if ((ret = ssh_rsa_encode_store_sig(hash_alg, sig, slen,
+	    sigp, lenp)) != 0)
+		goto out;
 
-	/* encode signature */
+	/* success */
+	ret = 0;
+ out:
+	freezero(sig, slen);
+	return ret;
+}
+
+int
+ssh_rsa_encode_store_sig(int hash_alg, const u_char *sig, size_t slen,
+    u_char **sigp, size_t *lenp)
+{
+	struct sshbuf *b = NULL;
+	int ret = SSH_ERR_INTERNAL_ERROR;
+	size_t len;
+
+	if (lenp != NULL)
+		*lenp = 0;
+	if (sigp != NULL)
+		*sigp = NULL;
+
+	/* Encode signature */
 	if ((b = sshbuf_new()) == NULL) {
 		ret = SSH_ERR_ALLOC_FAIL;
 		goto out;
 	}
-	if ((ret = sshbuf_put_cstring(b, rsa_hash_alg_ident(hash_alg))) != 0 ||
+	if ((ret = sshbuf_put_cstring(b,
+	    ssh_rsa_hash_alg_ident(hash_alg))) != 0 ||
 	    (ret = sshbuf_put_string(b, sig, slen)) != 0)
 		goto out;
 	len = sshbuf_len(b);
+
+	/* Store signature */
 	if (sigp != NULL) {
 		if ((*sigp = malloc(len)) == NULL) {
 			ret = SSH_ERR_ALLOC_FAIL;
@@ -456,7 +481,6 @@ ssh_rsa_sign(struct sshkey *key,
 		*lenp = len;
 	ret = 0;
  out:
-	freezero(sig, slen);
 	sshbuf_free(b);
 	return ret;
 }
@@ -495,7 +519,7 @@ ssh_rsa_verify(const struct sshkey *key,
 	 * legacy reasons, but otherwise the signature type should match.
 	 */
 	if (alg != NULL && strcmp(alg, "ssh-rsa-cert-v01@openssh.com") != 0) {
-		if ((want_alg = rsa_hash_id_from_keyname(alg)) == -1) {
+		if ((want_alg = ssh_rsa_hash_id_from_keyname(alg)) == -1) {
 			ret = SSH_ERR_INVALID_ARGUMENT;
 			goto out;
 		}
diff --git a/ssh-sk-helper.c b/ssh-sk-helper.c
index 41743ac..8008687 100644
--- a/ssh-sk-helper.c
+++ b/ssh-sk-helper.c
@@ -43,6 +43,7 @@
 #include "uidswap.h"
 #include "ssherr.h"
 #include "ssh-sk.h"
+#include "ssh-pkcs11.h"
 
 extern char *__progname;
 
@@ -84,6 +85,22 @@ null_empty(char **s)
 	*s = NULL;
 }
 
+/* stubs */
+int
+pkcs11_sign(struct sshkey *key,
+    u_char **sigp, size_t *lenp,
+    const u_char *data, size_t datalen,
+    const char *alg, const char *sk_provider,
+    const char *sk_pin, u_int compat)
+{
+	return SSH_ERR_INTERNAL_ERROR;
+}
+
+void
+pkcs11_key_free(struct sshkey *key)
+{
+}
+
 static struct sshbuf *
 process_sign(struct sshbuf *req)
 {
diff --git a/sshbuf-misc.c b/sshbuf-misc.c
index 5ef47b1..665505a 100644
--- a/sshbuf-misc.c
+++ b/sshbuf-misc.c
@@ -281,6 +281,20 @@ sshbuf_cmp(const struct sshbuf *b, size_t offset,
 	return 0;
 }
 
+int
+sshbuf_equals(const struct sshbuf *a, const struct sshbuf *b)
+{
+	if (sshbuf_ptr(a) == NULL || sshbuf_ptr(b) == NULL)
+		return SSH_ERR_INTERNAL_ERROR;
+	if (sshbuf_len(a) != sshbuf_len(b))
+		return SSH_ERR_MESSAGE_INCOMPLETE;
+	if (sshbuf_len(a) == 0)
+		return 0;
+	if (memcmp(sshbuf_ptr(a), sshbuf_ptr(b), sshbuf_len(a)) != 0)
+		return SSH_ERR_INVALID_FORMAT;
+	return 0;
+}
+
 int
 sshbuf_find(const struct sshbuf *b, size_t start_offset,
     const void *s, size_t len, size_t *offsetp)
diff --git a/sshbuf.h b/sshbuf.h
index 8338d06..b2e5c21 100644
--- a/sshbuf.h
+++ b/sshbuf.h
@@ -265,6 +265,15 @@ int	sshbuf_b64tod(struct sshbuf *buf, const char *b64);
 int	sshbuf_cmp(const struct sshbuf *b, size_t offset,
     const void *s, size_t len);
 
+/*
+ * Test whether two buffers have identical contents.
+ * SSH_ERR_MESSAGE_INCOMPLETE indicates the buffers had differing size.
+ * SSH_ERR_INVALID_FORMAT indicates the buffers were the same size but
+ * had differing contents.
+ * Returns 0 on successful compare (comparing two empty buffers returns 0).
+ */
+int sshbuf_equals(const struct sshbuf *a, const struct sshbuf *b);
+
 /*
  * Searches the buffer for the specified string. Returns 0 on success
  * and updates *offsetp with the offset of the first match, relative to
diff --git a/sshd/Makefile b/sshd/Makefile
index 6543436..d2d8d90 100644
--- a/sshd/Makefile
+++ b/sshd/Makefile
@@ -5,7 +5,7 @@
 SRCS=	sshd.c servconf.c sshpty.c srclimit.c groupaccess.c auth2-methods.c
 SRCS+=	dns.c fatal.c compat.c utf8.c authfd.c canohost.c kex-names.c
 SRCS+=	${SRCS_BASE} ${SRCS_KEY} ${SRCS_KEYP} ${SRCS_KRL} \
-	${SRCS_MAC} ${SRCS_UTL} ${SRCS_SK_CLIENT}
+	${SRCS_MAC} ${SRCS_UTL} ${SRCS_SK_CLIENT} ${SRCS_PKCS11_CLIENT}
 
 PROG=	sshd
 BINMODE=511
diff --git a/sshkey.c b/sshkey.c
index 50e1f56..681c201 100644
--- a/sshkey.c
+++ b/sshkey.c
@@ -55,6 +55,7 @@
 #include "sshkey.h"
 #include "match.h"
 #include "ssh-sk.h"
+#include "ssh-pkcs11.h"
 
 #ifdef WITH_XMSS
 #include "sshkey-xmss.h"
@@ -738,6 +739,8 @@ sshkey_free_contents(struct sshkey *k)
 
 	if (k == NULL)
 		return;
+	if ((k->flags & SSHKEY_FLAG_EXT) != 0)
+		pkcs11_key_free(k);
 	if ((impl = sshkey_impl_from_type(k->type)) != NULL &&
 	    impl->funcs->cleanup != NULL)
 		impl->funcs->cleanup(k);
@@ -860,22 +863,29 @@ sshkey_putb(const struct sshkey *key, struct sshbuf *b)
 	return to_blob_buf(key, b, 0, SSHKEY_SERIALIZE_DEFAULT);
 }
 
-int
-sshkey_puts_opts(const struct sshkey *key, struct sshbuf *b,
-    enum sshkey_serialize_rep opts)
+static int
+sshkey_puts_opts_internal(const struct sshkey *key, struct sshbuf *b,
+    enum sshkey_serialize_rep opts, int force_plain)
 {
 	struct sshbuf *tmp;
 	int r;
 
 	if ((tmp = sshbuf_new()) == NULL)
 		return SSH_ERR_ALLOC_FAIL;
-	r = to_blob_buf(key, tmp, 0, opts);
+	r = to_blob_buf(key, tmp, force_plain, opts);
 	if (r == 0)
 		r = sshbuf_put_stringb(b, tmp);
 	sshbuf_free(tmp);
 	return r;
 }
 
+int
+sshkey_puts_opts(const struct sshkey *key, struct sshbuf *b,
+    enum sshkey_serialize_rep opts)
+{
+	return sshkey_puts_opts_internal(key, b, opts, 0);
+}
+
 int
 sshkey_puts(const struct sshkey *key, struct sshbuf *b)
 {
@@ -888,6 +898,12 @@ sshkey_putb_plain(const struct sshkey *key, struct sshbuf *b)
 	return to_blob_buf(key, b, 1, SSHKEY_SERIALIZE_DEFAULT);
 }
 
+int
+sshkey_puts_plain(const struct sshkey *key, struct sshbuf *b)
+{
+	return sshkey_puts_opts_internal(key, b, SSHKEY_SERIALIZE_DEFAULT, 1);
+}
+
 static int
 to_blob(const struct sshkey *key, u_char **blobp, size_t *lenp, int force_plain,
     enum sshkey_serialize_rep opts)
@@ -2160,6 +2176,9 @@ sshkey_sign(struct sshkey *key,
 	if (sshkey_is_sk(key)) {
 		r = sshsk_sign(sk_provider, key, sigp, lenp, data,
 		    datalen, compat, sk_pin);
+	} else if ((key->flags & SSHKEY_FLAG_EXT) != 0) {
+		r = pkcs11_sign(key, sigp, lenp, data, datalen,
+		    alg, sk_provider, sk_pin, compat);
 	} else {
 		if (impl->funcs->sign == NULL)
 			r = SSH_ERR_SIGN_ALG_UNSUPPORTED;
diff --git a/sshkey.h b/sshkey.h
index d3f3962..8168cac 100644
--- a/sshkey.h
+++ b/sshkey.h
@@ -269,6 +269,7 @@ int	 sshkey_puts_opts(const struct sshkey *, struct sshbuf *,
     enum sshkey_serialize_rep);
 int	 sshkey_plain_to_blob(const struct sshkey *, u_char **, size_t *);
 int	 sshkey_putb_plain(const struct sshkey *, struct sshbuf *);
+int	 sshkey_puts_plain(const struct sshkey *, struct sshbuf *);
 
 int	 sshkey_sign(struct sshkey *, u_char **, size_t *,
     const u_char *, size_t, const char *, const char *, const char *, u_int);
@@ -334,7 +335,15 @@ int	sshkey_serialize_private_sk(const struct sshkey *key,
 int	sshkey_private_deserialize_sk(struct sshbuf *buf, struct sshkey *k);
 #ifdef WITH_OPENSSL
 int	check_rsa_length(const RSA *rsa); /* XXX remove */
+int	ssh_rsa_hash_id_from_keyname(const char *);
+const char *ssh_rsa_hash_alg_ident(int);
+int	ssh_rsa_encode_store_sig(int, const u_char *, size_t,
+	    u_char **, size_t *);
+int	ssh_ecdsa_encode_store_sig(const struct sshkey *,
+	    const BIGNUM *, const BIGNUM *, u_char **, size_t *);
 #endif
+int	ssh_ed25519_encode_store_sig(const u_char *, size_t,
+	    u_char **, size_t *);
 #endif
 
 #ifndef WITH_OPENSSL
diff --git a/pkcs11.h b/pkcs11.h
index b01d58f..09c0ca3 100644
--- a/pkcs11.h
+++ b/pkcs11.h
@@ -1,4 +1,3 @@
-/* $OpenBSD: pkcs11.h,v 1.3 2013/11/26 19:15:09 deraadt Exp $ */
 /* pkcs11.h
    Copyright 2006, 2007 g10 Code GmbH
    Copyright 2006 Andreas Jellinghaus
@@ -64,9 +63,9 @@ extern "C" {
    version of this file, please consider deleting the revision macro
    (you may use a macro with a different name to keep track of your
    versions).  */
-#define CRYPTOKI_VERSION_MAJOR		2
-#define CRYPTOKI_VERSION_MINOR		20
-#define CRYPTOKI_VERSION_REVISION	6
+#define CRYPTOKI_VERSION_MAJOR		3
+#define CRYPTOKI_VERSION_MINOR		0
+#define CRYPTOKI_VERSION_REVISION	0
 
 
 /* Compatibility interface is default, unless CRYPTOKI_GNU is
@@ -96,7 +95,6 @@ extern "C" {
 
 #endif
 
-
 #ifdef CRYPTOKI_COMPAT
   /* If we are in compatibility mode, switch all exposed names to the
      PKCS #11 variant.  There are corresponding #undefs below.  */
@@ -155,6 +153,8 @@ extern "C" {
 
 #define ck_mechanism_type_t CK_MECHANISM_TYPE
 
+#define ck_rsa_pkcs_mgf_type_t CK_RSA_PKCS_MGF_TYPE
+
 #define ck_mechanism _CK_MECHANISM
 #define parameter pParameter
 #define parameter_len ulParameterLen
@@ -166,7 +166,10 @@ extern "C" {
 #define ck_rv_t CK_RV
 #define ck_notify_t CK_NOTIFY
 
+#define ck_interface CK_INTERFACE
+
 #define ck_function_list _CK_FUNCTION_LIST
+#define ck_function_list_3_0 _CK_FUNCTION_LIST_3_0
 
 #define ck_createmutex_t CK_CREATEMUTEX
 #define ck_destroymutex_t CK_DESTROYMUTEX
@@ -183,7 +186,6 @@ extern "C" {
 #endif	/* CRYPTOKI_COMPAT */
 
 
-
 typedef unsigned long ck_flags_t;
 
 struct ck_version
@@ -205,7 +207,7 @@ struct ck_info
 
 typedef unsigned long ck_notification_t;
 
-#define CKN_SURRENDER	(0)
+#define CKN_SURRENDER	(0UL)
 
 
 typedef unsigned long ck_slot_id_t;
@@ -221,10 +223,10 @@ struct ck_slot_info
 };
 
 
-#define CKF_TOKEN_PRESENT	(1 << 0)
-#define CKF_REMOVABLE_DEVICE	(1 << 1)
-#define CKF_HW_SLOT		(1 << 2)
-#define CKF_ARRAY_ATTRIBUTE	(1 << 30)
+#define CKF_TOKEN_PRESENT	(1UL << 0)
+#define CKF_REMOVABLE_DEVICE	(1UL << 1)
+#define CKF_HW_SLOT		(1UL << 2)
+#define CKF_ARRAY_ATTRIBUTE	(1UL << 30)
 
 
 struct ck_token_info
@@ -250,48 +252,48 @@ struct ck_token_info
 };
 
 
-#define CKF_RNG					(1 << 0)
-#define CKF_WRITE_PROTECTED			(1 << 1)
-#define CKF_LOGIN_REQUIRED			(1 << 2)
-#define CKF_USER_PIN_INITIALIZED		(1 << 3)
-#define CKF_RESTORE_KEY_NOT_NEEDED		(1 << 5)
-#define CKF_CLOCK_ON_TOKEN			(1 << 6)
-#define CKF_PROTECTED_AUTHENTICATION_PATH	(1 << 8)
-#define CKF_DUAL_CRYPTO_OPERATIONS		(1 << 9)
-#define CKF_TOKEN_INITIALIZED			(1 << 10)
-#define CKF_SECONDARY_AUTHENTICATION		(1 << 11)
-#define CKF_USER_PIN_COUNT_LOW			(1 << 16)
-#define CKF_USER_PIN_FINAL_TRY			(1 << 17)
-#define CKF_USER_PIN_LOCKED			(1 << 18)
-#define CKF_USER_PIN_TO_BE_CHANGED		(1 << 19)
-#define CKF_SO_PIN_COUNT_LOW			(1 << 20)
-#define CKF_SO_PIN_FINAL_TRY			(1 << 21)
-#define CKF_SO_PIN_LOCKED			(1 << 22)
-#define CKF_SO_PIN_TO_BE_CHANGED		(1 << 23)
+#define CKF_RNG					(1UL << 0)
+#define CKF_WRITE_PROTECTED			(1UL << 1)
+#define CKF_LOGIN_REQUIRED			(1UL << 2)
+#define CKF_USER_PIN_INITIALIZED		(1UL << 3)
+#define CKF_RESTORE_KEY_NOT_NEEDED		(1UL << 5)
+#define CKF_CLOCK_ON_TOKEN			(1UL << 6)
+#define CKF_PROTECTED_AUTHENTICATION_PATH	(1UL << 8)
+#define CKF_DUAL_CRYPTO_OPERATIONS		(1UL << 9)
+#define CKF_TOKEN_INITIALIZED			(1UL << 10)
+#define CKF_SECONDARY_AUTHENTICATION		(1UL << 11)
+#define CKF_USER_PIN_COUNT_LOW			(1UL << 16)
+#define CKF_USER_PIN_FINAL_TRY			(1UL << 17)
+#define CKF_USER_PIN_LOCKED			(1UL << 18)
+#define CKF_USER_PIN_TO_BE_CHANGED		(1UL << 19)
+#define CKF_SO_PIN_COUNT_LOW			(1UL << 20)
+#define CKF_SO_PIN_FINAL_TRY			(1UL << 21)
+#define CKF_SO_PIN_LOCKED			(1UL << 22)
+#define CKF_SO_PIN_TO_BE_CHANGED		(1UL << 23)
 
 #define CK_UNAVAILABLE_INFORMATION	((unsigned long) -1)
-#define CK_EFFECTIVELY_INFINITE		(0)
+#define CK_EFFECTIVELY_INFINITE		(0UL)
 
 
 typedef unsigned long ck_session_handle_t;
 
-#define CK_INVALID_HANDLE	(0)
+#define CK_INVALID_HANDLE	(0UL)
 
 
 typedef unsigned long ck_user_type_t;
 
-#define CKU_SO			(0)
-#define CKU_USER		(1)
-#define CKU_CONTEXT_SPECIFIC	(2)
+#define CKU_SO			(0UL)
+#define CKU_USER		(1UL)
+#define CKU_CONTEXT_SPECIFIC	(2UL)
 
 
 typedef unsigned long ck_state_t;
 
-#define CKS_RO_PUBLIC_SESSION	(0)
-#define CKS_RO_USER_FUNCTIONS	(1)
-#define CKS_RW_PUBLIC_SESSION	(2)
-#define CKS_RW_USER_FUNCTIONS	(3)
-#define CKS_RW_SO_FUNCTIONS	(4)
+#define CKS_RO_PUBLIC_SESSION	(0UL)
+#define CKS_RO_USER_FUNCTIONS	(1UL)
+#define CKS_RW_PUBLIC_SESSION	(2UL)
+#define CKS_RW_USER_FUNCTIONS	(3UL)
+#define CKS_RW_SO_FUNCTIONS	(4UL)
 
 
 struct ck_session_info
@@ -302,8 +304,8 @@ struct ck_session_info
   unsigned long device_error;
 };
 
-#define CKF_RW_SESSION		(1 << 1)
-#define CKF_SERIAL_SESSION	(1 << 2)
+#define CKF_RW_SESSION		(1UL << 1)
+#define CKF_SERIAL_SESSION	(1UL << 2)
 
 
 typedef unsigned long ck_object_handle_t;
@@ -311,149 +313,194 @@ typedef unsigned long ck_object_handle_t;
 
 typedef unsigned long ck_object_class_t;
 
-#define CKO_DATA		(0)
-#define CKO_CERTIFICATE		(1)
-#define CKO_PUBLIC_KEY		(2)
-#define CKO_PRIVATE_KEY		(3)
-#define CKO_SECRET_KEY		(4)
-#define CKO_HW_FEATURE		(5)
-#define CKO_DOMAIN_PARAMETERS	(6)
-#define CKO_MECHANISM		(7)
-#define CKO_VENDOR_DEFINED	(1U << 31)
+#define CKO_DATA		(0UL)
+#define CKO_CERTIFICATE		(1UL)
+#define CKO_PUBLIC_KEY		(2UL)
+#define CKO_PRIVATE_KEY		(3UL)
+#define CKO_SECRET_KEY		(4UL)
+#define CKO_HW_FEATURE		(5UL)
+#define CKO_DOMAIN_PARAMETERS	(6UL)
+#define CKO_MECHANISM		(7UL)
+#define CKO_OTP_KEY		(8UL)
+#define CKO_PROFILE		(9UL)
+#define CKO_VENDOR_DEFINED	(1UL << 31)
 
+#define CKP_INVALID_ID                (0UL)
+#define CKP_BASELINE_PROVIDER         (1UL)
+#define CKP_EXTENDED_PROVIDER         (2UL)
+#define CKP_AUTHENTICATION_TOKEN      (3UL)
+#define CKP_PUBLIC_CERTIFICATES_TOKEN (4UL)
+#define CKP_VENDOR_DEFINED            (1UL << 31)
 
 typedef unsigned long ck_hw_feature_type_t;
 
-#define CKH_MONOTONIC_COUNTER	(1)
-#define CKH_CLOCK		(2)
-#define CKH_USER_INTERFACE	(3)
-#define CKH_VENDOR_DEFINED	(1U << 31)
+#define CKH_MONOTONIC_COUNTER	(1UL)
+#define CKH_CLOCK		(2UL)
+#define CKH_USER_INTERFACE	(3UL)
+#define CKH_VENDOR_DEFINED	(1UL << 31)
 
 
 typedef unsigned long ck_key_type_t;
 
-#define CKK_RSA			(0)
-#define CKK_DSA			(1)
-#define CKK_DH			(2)
-#define CKK_ECDSA		(3)
-#define CKK_EC			(3)
-#define CKK_X9_42_DH		(4)
-#define CKK_KEA			(5)
-#define CKK_GENERIC_SECRET	(0x10)
-#define CKK_RC2			(0x11)
-#define CKK_RC4			(0x12)
-#define CKK_DES			(0x13)
-#define CKK_DES2		(0x14)
-#define CKK_DES3		(0x15)
-#define CKK_CAST		(0x16)
-#define CKK_CAST3		(0x17)
-#define CKK_CAST128		(0x18)
-#define CKK_RC5			(0x19)
-#define CKK_IDEA		(0x1a)
-#define CKK_SKIPJACK		(0x1b)
-#define CKK_BATON		(0x1c)
-#define CKK_JUNIPER		(0x1d)
-#define CKK_CDMF		(0x1e)
-#define CKK_AES			(0x1f)
-#define CKK_BLOWFISH		(0x20)
-#define CKK_TWOFISH		(0x21)
-#define CKK_VENDOR_DEFINED	(1U << 31)
+#define CKK_RSA			(0UL)
+#define CKK_DSA			(1UL)
+#define CKK_DH			(2UL)
+#define CKK_ECDSA		(3UL)
+#define CKK_EC			(3UL)
+#define CKK_X9_42_DH		(4UL)
+#define CKK_KEA			(5UL)
+#define CKK_GENERIC_SECRET	(0x10UL)
+#define CKK_RC2			(0x11UL)
+#define CKK_RC4			(0x12UL)
+#define CKK_DES			(0x13UL)
+#define CKK_DES2		(0x14UL)
+#define CKK_DES3		(0x15UL)
+#define CKK_CAST		(0x16UL)
+#define CKK_CAST3		(0x17UL)
+#define CKK_CAST128		(0x18UL)
+#define CKK_RC5			(0x19UL)
+#define CKK_IDEA		(0x1aUL)
+#define CKK_SKIPJACK		(0x1bUL)
+#define CKK_BATON		(0x1cUL)
+#define CKK_JUNIPER		(0x1dUL)
+#define CKK_CDMF		(0x1eUL)
+#define CKK_AES			(0x1fUL)
+#define CKK_BLOWFISH		(0x20UL)
+#define CKK_TWOFISH		(0x21UL)
+#define CKK_GOSTR3410		(0x30UL)
+#define CKK_GOSTR3411		(0x31UL)
+#define CKK_GOST28147		(0x32UL)
+#define CKK_EC_EDWARDS		(0x40UL)
+#define CKK_EC_MONTGOMERY	(0x41UL)
+#define CKK_HKDF		(0x42UL)
+#define CKK_VENDOR_DEFINED	(1UL << 31)
+
+/*
+ * A mask for new GOST algorithms.
+ * For details visit https://tc26.ru/standarts/perevody/guidelines-the-pkcs-11-extensions-for-implementing-the-gost-r-34-10-2012-and-gost-r-34-11-2012-russian-standards-.html
+ */
+#define NSSCK_VENDOR_PKCS11_RU_TEAM     (CKK_VENDOR_DEFINED | 0x54321000)
+#define CK_VENDOR_PKCS11_RU_TEAM_TK26   NSSCK_VENDOR_PKCS11_RU_TEAM
+
+#define CKK_GOSTR3410_512	(CK_VENDOR_PKCS11_RU_TEAM_TK26 | 0x003)
 
 typedef unsigned long ck_certificate_type_t;
 
-#define CKC_X_509		(0)
-#define CKC_X_509_ATTR_CERT	(1)
-#define CKC_WTLS		(2)
-#define CKC_VENDOR_DEFINED	(1U << 31)
+#define CKC_X_509		(0UL)
+#define CKC_X_509_ATTR_CERT	(1UL)
+#define CKC_WTLS		(2UL)
+#define CKC_VENDOR_DEFINED	(1UL << 31)
 
 
 typedef unsigned long ck_attribute_type_t;
 
-#define CKA_CLASS			(0)
-#define CKA_TOKEN			(1)
-#define CKA_PRIVATE			(2)
-#define CKA_LABEL			(3)
-#define CKA_APPLICATION			(0x10)
-#define CKA_VALUE			(0x11)
-#define CKA_OBJECT_ID			(0x12)
-#define CKA_CERTIFICATE_TYPE		(0x80)
-#define CKA_ISSUER			(0x81)
-#define CKA_SERIAL_NUMBER		(0x82)
-#define CKA_AC_ISSUER			(0x83)
-#define CKA_OWNER			(0x84)
-#define CKA_ATTR_TYPES			(0x85)
-#define CKA_TRUSTED			(0x86)
-#define CKA_CERTIFICATE_CATEGORY	(0x87)
-#define CKA_JAVA_MIDP_SECURITY_DOMAIN	(0x88)
-#define CKA_URL				(0x89)
-#define CKA_HASH_OF_SUBJECT_PUBLIC_KEY	(0x8a)
-#define CKA_HASH_OF_ISSUER_PUBLIC_KEY	(0x8b)
-#define CKA_CHECK_VALUE			(0x90)
-#define CKA_KEY_TYPE			(0x100)
-#define CKA_SUBJECT			(0x101)
-#define CKA_ID				(0x102)
-#define CKA_SENSITIVE			(0x103)
-#define CKA_ENCRYPT			(0x104)
-#define CKA_DECRYPT			(0x105)
-#define CKA_WRAP			(0x106)
-#define CKA_UNWRAP			(0x107)
-#define CKA_SIGN			(0x108)
-#define CKA_SIGN_RECOVER		(0x109)
-#define CKA_VERIFY			(0x10a)
-#define CKA_VERIFY_RECOVER		(0x10b)
-#define CKA_DERIVE			(0x10c)
-#define CKA_START_DATE			(0x110)
-#define CKA_END_DATE			(0x111)
-#define CKA_MODULUS			(0x120)
-#define CKA_MODULUS_BITS		(0x121)
-#define CKA_PUBLIC_EXPONENT		(0x122)
-#define CKA_PRIVATE_EXPONENT		(0x123)
-#define CKA_PRIME_1			(0x124)
-#define CKA_PRIME_2			(0x125)
-#define CKA_EXPONENT_1			(0x126)
-#define CKA_EXPONENT_2			(0x127)
-#define CKA_COEFFICIENT			(0x128)
-#define CKA_PRIME			(0x130)
-#define CKA_SUBPRIME			(0x131)
-#define CKA_BASE			(0x132)
-#define CKA_PRIME_BITS			(0x133)
-#define CKA_SUB_PRIME_BITS		(0x134)
-#define CKA_VALUE_BITS			(0x160)
-#define CKA_VALUE_LEN			(0x161)
-#define CKA_EXTRACTABLE			(0x162)
-#define CKA_LOCAL			(0x163)
-#define CKA_NEVER_EXTRACTABLE		(0x164)
-#define CKA_ALWAYS_SENSITIVE		(0x165)
-#define CKA_KEY_GEN_MECHANISM		(0x166)
-#define CKA_MODIFIABLE			(0x170)
-#define CKA_ECDSA_PARAMS		(0x180)
-#define CKA_EC_PARAMS			(0x180)
-#define CKA_EC_POINT			(0x181)
-#define CKA_SECONDARY_AUTH		(0x200)
-#define CKA_AUTH_PIN_FLAGS		(0x201)
-#define CKA_ALWAYS_AUTHENTICATE		(0x202)
-#define CKA_WRAP_WITH_TRUSTED		(0x210)
-#define CKA_HW_FEATURE_TYPE		(0x300)
-#define CKA_RESET_ON_INIT		(0x301)
-#define CKA_HAS_RESET			(0x302)
-#define CKA_PIXEL_X			(0x400)
-#define CKA_PIXEL_Y			(0x401)
-#define CKA_RESOLUTION			(0x402)
-#define CKA_CHAR_ROWS			(0x403)
-#define CKA_CHAR_COLUMNS		(0x404)
-#define CKA_COLOR			(0x405)
-#define CKA_BITS_PER_PIXEL		(0x406)
-#define CKA_CHAR_SETS			(0x480)
-#define CKA_ENCODING_METHODS		(0x481)
-#define CKA_MIME_TYPES			(0x482)
-#define CKA_MECHANISM_TYPE		(0x500)
-#define CKA_REQUIRED_CMS_ATTRIBUTES	(0x501)
-#define CKA_DEFAULT_CMS_ATTRIBUTES	(0x502)
-#define CKA_SUPPORTED_CMS_ATTRIBUTES	(0x503)
-#define CKA_WRAP_TEMPLATE		(CKF_ARRAY_ATTRIBUTE | 0x211)
-#define CKA_UNWRAP_TEMPLATE		(CKF_ARRAY_ATTRIBUTE | 0x212)
-#define CKA_ALLOWED_MECHANISMS		(CKF_ARRAY_ATTRIBUTE | 0x600)
-#define CKA_VENDOR_DEFINED		(1U << 31)
+#define CKA_CLASS			(0UL)
+#define CKA_TOKEN			(1UL)
+#define CKA_PRIVATE			(2UL)
+#define CKA_LABEL			(3UL)
+#define CKA_UNIQUE_ID		(4UL)
+#define CKA_APPLICATION			(0x10UL)
+#define CKA_VALUE			(0x11UL)
+#define CKA_OBJECT_ID			(0x12UL)
+#define CKA_CERTIFICATE_TYPE		(0x80UL)
+#define CKA_ISSUER			(0x81UL)
+#define CKA_SERIAL_NUMBER		(0x82UL)
+#define CKA_AC_ISSUER			(0x83UL)
+#define CKA_OWNER			(0x84UL)
+#define CKA_ATTR_TYPES			(0x85UL)
+#define CKA_TRUSTED			(0x86UL)
+#define CKA_CERTIFICATE_CATEGORY	(0x87UL)
+#define CKA_JAVA_MIDP_SECURITY_DOMAIN	(0x88UL)
+#define CKA_URL				(0x89UL)
+#define CKA_HASH_OF_SUBJECT_PUBLIC_KEY	(0x8aUL)
+#define CKA_HASH_OF_ISSUER_PUBLIC_KEY	(0x8bUL)
+#define CKA_CHECK_VALUE			(0x90UL)
+#define CKA_KEY_TYPE			(0x100UL)
+#define CKA_SUBJECT			(0x101UL)
+#define CKA_ID				(0x102UL)
+#define CKA_SENSITIVE			(0x103UL)
+#define CKA_ENCRYPT			(0x104UL)
+#define CKA_DECRYPT			(0x105UL)
+#define CKA_WRAP			(0x106UL)
+#define CKA_UNWRAP			(0x107UL)
+#define CKA_SIGN			(0x108UL)
+#define CKA_SIGN_RECOVER		(0x109UL)
+#define CKA_VERIFY			(0x10aUL)
+#define CKA_VERIFY_RECOVER		(0x10bUL)
+#define CKA_DERIVE			(0x10cUL)
+#define CKA_START_DATE			(0x110UL)
+#define CKA_END_DATE			(0x111UL)
+#define CKA_MODULUS			(0x120UL)
+#define CKA_MODULUS_BITS		(0x121UL)
+#define CKA_PUBLIC_EXPONENT		(0x122UL)
+#define CKA_PRIVATE_EXPONENT		(0x123UL)
+#define CKA_PRIME_1			(0x124UL)
+#define CKA_PRIME_2			(0x125UL)
+#define CKA_EXPONENT_1			(0x126UL)
+#define CKA_EXPONENT_2			(0x127UL)
+#define CKA_COEFFICIENT			(0x128UL)
+#define CKA_PUBLIC_KEY_INFO		(0x129UL)
+#define CKA_PRIME			(0x130UL)
+#define CKA_SUBPRIME			(0x131UL)
+#define CKA_BASE			(0x132UL)
+#define CKA_PRIME_BITS			(0x133UL)
+#define CKA_SUB_PRIME_BITS		(0x134UL)
+#define CKA_VALUE_BITS			(0x160UL)
+#define CKA_VALUE_LEN			(0x161UL)
+#define CKA_EXTRACTABLE			(0x162UL)
+#define CKA_LOCAL			(0x163UL)
+#define CKA_NEVER_EXTRACTABLE		(0x164UL)
+#define CKA_ALWAYS_SENSITIVE		(0x165UL)
+#define CKA_KEY_GEN_MECHANISM		(0x166UL)
+#define CKA_MODIFIABLE			(0x170UL)
+#define CKA_COPYABLE			(0x171UL)
+#define CKA_DESTROYABLE			(0x172UL)
+#define CKA_ECDSA_PARAMS		(0x180UL)
+#define CKA_EC_PARAMS			(0x180UL)
+#define CKA_EC_POINT			(0x181UL)
+#define CKA_SECONDARY_AUTH		(0x200UL)
+#define CKA_AUTH_PIN_FLAGS		(0x201UL)
+#define CKA_ALWAYS_AUTHENTICATE		(0x202UL)
+#define CKA_WRAP_WITH_TRUSTED		(0x210UL)
+#define CKA_GOSTR3410_PARAMS		(0x250UL)
+#define CKA_GOSTR3411_PARAMS		(0x251UL)
+#define CKA_GOST28147_PARAMS		(0x252UL)
+#define CKA_HW_FEATURE_TYPE		(0x300UL)
+#define CKA_RESET_ON_INIT		(0x301UL)
+#define CKA_HAS_RESET			(0x302UL)
+#define CKA_PIXEL_X			(0x400UL)
+#define CKA_PIXEL_Y			(0x401UL)
+#define CKA_RESOLUTION			(0x402UL)
+#define CKA_CHAR_ROWS			(0x403UL)
+#define CKA_CHAR_COLUMNS		(0x404UL)
+#define CKA_COLOR			(0x405UL)
+#define CKA_BITS_PER_PIXEL		(0x406UL)
+#define CKA_CHAR_SETS			(0x480UL)
+#define CKA_ENCODING_METHODS		(0x481UL)
+#define CKA_MIME_TYPES			(0x482UL)
+#define CKA_MECHANISM_TYPE		(0x500UL)
+#define CKA_REQUIRED_CMS_ATTRIBUTES	(0x501UL)
+#define CKA_DEFAULT_CMS_ATTRIBUTES	(0x502UL)
+#define CKA_SUPPORTED_CMS_ATTRIBUTES	(0x503UL)
+#define CKA_WRAP_TEMPLATE		(CKF_ARRAY_ATTRIBUTE | 0x211UL)
+#define CKA_UNWRAP_TEMPLATE		(CKF_ARRAY_ATTRIBUTE | 0x212UL)
+#define CKA_OTP_FORMAT			(0x220UL)
+#define CKA_OTP_LENGTH			(0x221UL)
+#define CKA_OTP_TIME_INTERVAL		(0x222UL)
+#define CKA_OTP_USER_FRIENDLY_MODE	(0x223UL)
+#define CKA_OTP_CHALLENGE_REQUIREMENT	(0x224UL)
+#define CKA_OTP_TIME_REQUIREMENT	(0x225UL)
+#define CKA_OTP_COUNTER_REQUIREMENT	(0x226UL)
+#define CKA_OTP_PIN_REQUIREMENT		(0x227UL)
+#define CKA_OTP_USER_IDENTIFIER		(0x22AUL)
+#define CKA_OTP_SERVICE_IDENTIFIER	(0x22BUL)
+#define CKA_OTP_SERVICE_LOGO		(0x22CUL)
+#define CKA_OTP_SERVICE_LOGO_TYPE	(0x22DUL)
+#define CKA_OTP_COUNTER			(0x22EUL)
+#define CKA_OTP_TIME			(0x22FUL)
+#define CKA_ALLOWED_MECHANISMS		(CKF_ARRAY_ATTRIBUTE | 0x600UL)
+#define CKA_PROFILE_ID			(0x601UL)
+#define CKA_VENDOR_DEFINED		(1UL << 31)
 
 
 struct ck_attribute
@@ -474,206 +521,304 @@ struct ck_date
 
 typedef unsigned long ck_mechanism_type_t;
 
-#define CKM_RSA_PKCS_KEY_PAIR_GEN	(0)
-#define CKM_RSA_PKCS			(1)
-#define CKM_RSA_9796			(2)
-#define CKM_RSA_X_509			(3)
-#define CKM_MD2_RSA_PKCS		(4)
-#define CKM_MD5_RSA_PKCS		(5)
-#define CKM_SHA1_RSA_PKCS		(6)
-#define CKM_RIPEMD128_RSA_PKCS		(7)
-#define CKM_RIPEMD160_RSA_PKCS		(8)
-#define CKM_RSA_PKCS_OAEP		(9)
-#define CKM_RSA_X9_31_KEY_PAIR_GEN	(0xa)
-#define CKM_RSA_X9_31			(0xb)
-#define CKM_SHA1_RSA_X9_31		(0xc)
-#define CKM_RSA_PKCS_PSS		(0xd)
-#define CKM_SHA1_RSA_PKCS_PSS		(0xe)
-#define CKM_DSA_KEY_PAIR_GEN		(0x10)
-#define	CKM_DSA				(0x11)
-#define CKM_DSA_SHA1			(0x12)
-#define CKM_DH_PKCS_KEY_PAIR_GEN	(0x20)
-#define CKM_DH_PKCS_DERIVE		(0x21)
-#define	CKM_X9_42_DH_KEY_PAIR_GEN	(0x30)
-#define CKM_X9_42_DH_DERIVE		(0x31)
-#define CKM_X9_42_DH_HYBRID_DERIVE	(0x32)
-#define CKM_X9_42_MQV_DERIVE		(0x33)
-#define CKM_SHA256_RSA_PKCS		(0x40)
-#define CKM_SHA384_RSA_PKCS		(0x41)
-#define CKM_SHA512_RSA_PKCS		(0x42)
-#define CKM_SHA256_RSA_PKCS_PSS		(0x43)
-#define CKM_SHA384_RSA_PKCS_PSS		(0x44)
-#define CKM_SHA512_RSA_PKCS_PSS		(0x45)
-#define CKM_RC2_KEY_GEN			(0x100)
-#define CKM_RC2_ECB			(0x101)
-#define	CKM_RC2_CBC			(0x102)
-#define	CKM_RC2_MAC			(0x103)
-#define CKM_RC2_MAC_GENERAL		(0x104)
-#define CKM_RC2_CBC_PAD			(0x105)
-#define CKM_RC4_KEY_GEN			(0x110)
-#define CKM_RC4				(0x111)
-#define CKM_DES_KEY_GEN			(0x120)
-#define CKM_DES_ECB			(0x121)
-#define CKM_DES_CBC			(0x122)
-#define CKM_DES_MAC			(0x123)
-#define CKM_DES_MAC_GENERAL		(0x124)
-#define CKM_DES_CBC_PAD			(0x125)
-#define CKM_DES2_KEY_GEN		(0x130)
-#define CKM_DES3_KEY_GEN		(0x131)
-#define CKM_DES3_ECB			(0x132)
-#define CKM_DES3_CBC			(0x133)
-#define CKM_DES3_MAC			(0x134)
-#define CKM_DES3_MAC_GENERAL		(0x135)
-#define CKM_DES3_CBC_PAD		(0x136)
-#define CKM_CDMF_KEY_GEN		(0x140)
-#define CKM_CDMF_ECB			(0x141)
-#define CKM_CDMF_CBC			(0x142)
-#define CKM_CDMF_MAC			(0x143)
-#define CKM_CDMF_MAC_GENERAL		(0x144)
-#define CKM_CDMF_CBC_PAD		(0x145)
-#define CKM_MD2				(0x200)
-#define CKM_MD2_HMAC			(0x201)
-#define CKM_MD2_HMAC_GENERAL		(0x202)
-#define CKM_MD5				(0x210)
-#define CKM_MD5_HMAC			(0x211)
-#define CKM_MD5_HMAC_GENERAL		(0x212)
-#define CKM_SHA_1			(0x220)
-#define CKM_SHA_1_HMAC			(0x221)
-#define CKM_SHA_1_HMAC_GENERAL		(0x222)
-#define CKM_RIPEMD128			(0x230)
-#define CKM_RIPEMD128_HMAC		(0x231)
-#define CKM_RIPEMD128_HMAC_GENERAL	(0x232)
-#define CKM_RIPEMD160			(0x240)
-#define CKM_RIPEMD160_HMAC		(0x241)
-#define CKM_RIPEMD160_HMAC_GENERAL	(0x242)
-#define CKM_SHA256			(0x250)
-#define CKM_SHA256_HMAC			(0x251)
-#define CKM_SHA256_HMAC_GENERAL		(0x252)
-#define CKM_SHA384			(0x260)
-#define CKM_SHA384_HMAC			(0x261)
-#define CKM_SHA384_HMAC_GENERAL		(0x262)
-#define CKM_SHA512			(0x270)
-#define CKM_SHA512_HMAC			(0x271)
-#define CKM_SHA512_HMAC_GENERAL		(0x272)
-#define CKM_CAST_KEY_GEN		(0x300)
-#define CKM_CAST_ECB			(0x301)
-#define CKM_CAST_CBC			(0x302)
-#define CKM_CAST_MAC			(0x303)
-#define CKM_CAST_MAC_GENERAL		(0x304)
-#define CKM_CAST_CBC_PAD		(0x305)
-#define CKM_CAST3_KEY_GEN		(0x310)
-#define CKM_CAST3_ECB			(0x311)
-#define CKM_CAST3_CBC			(0x312)
-#define CKM_CAST3_MAC			(0x313)
-#define CKM_CAST3_MAC_GENERAL		(0x314)
-#define CKM_CAST3_CBC_PAD		(0x315)
-#define CKM_CAST5_KEY_GEN		(0x320)
-#define CKM_CAST128_KEY_GEN		(0x320)
-#define CKM_CAST5_ECB			(0x321)
-#define CKM_CAST128_ECB			(0x321)
-#define CKM_CAST5_CBC			(0x322)
-#define CKM_CAST128_CBC			(0x322)
-#define CKM_CAST5_MAC			(0x323)
-#define	CKM_CAST128_MAC			(0x323)
-#define CKM_CAST5_MAC_GENERAL		(0x324)
-#define CKM_CAST128_MAC_GENERAL		(0x324)
-#define CKM_CAST5_CBC_PAD		(0x325)
-#define CKM_CAST128_CBC_PAD		(0x325)
-#define CKM_RC5_KEY_GEN			(0x330)
-#define CKM_RC5_ECB			(0x331)
-#define CKM_RC5_CBC			(0x332)
-#define CKM_RC5_MAC			(0x333)
-#define CKM_RC5_MAC_GENERAL		(0x334)
-#define CKM_RC5_CBC_PAD			(0x335)
-#define CKM_IDEA_KEY_GEN		(0x340)
-#define CKM_IDEA_ECB			(0x341)
-#define	CKM_IDEA_CBC			(0x342)
-#define CKM_IDEA_MAC			(0x343)
-#define CKM_IDEA_MAC_GENERAL		(0x344)
-#define CKM_IDEA_CBC_PAD		(0x345)
-#define CKM_GENERIC_SECRET_KEY_GEN	(0x350)
-#define CKM_CONCATENATE_BASE_AND_KEY	(0x360)
-#define CKM_CONCATENATE_BASE_AND_DATA	(0x362)
-#define CKM_CONCATENATE_DATA_AND_BASE	(0x363)
-#define CKM_XOR_BASE_AND_DATA		(0x364)
-#define CKM_EXTRACT_KEY_FROM_KEY	(0x365)
-#define CKM_SSL3_PRE_MASTER_KEY_GEN	(0x370)
-#define CKM_SSL3_MASTER_KEY_DERIVE	(0x371)
-#define CKM_SSL3_KEY_AND_MAC_DERIVE	(0x372)
-#define CKM_SSL3_MASTER_KEY_DERIVE_DH	(0x373)
-#define CKM_TLS_PRE_MASTER_KEY_GEN	(0x374)
-#define CKM_TLS_MASTER_KEY_DERIVE	(0x375)
-#define CKM_TLS_KEY_AND_MAC_DERIVE	(0x376)
-#define CKM_TLS_MASTER_KEY_DERIVE_DH	(0x377)
-#define CKM_SSL3_MD5_MAC		(0x380)
-#define CKM_SSL3_SHA1_MAC		(0x381)
-#define CKM_MD5_KEY_DERIVATION		(0x390)
-#define CKM_MD2_KEY_DERIVATION		(0x391)
-#define CKM_SHA1_KEY_DERIVATION		(0x392)
-#define CKM_PBE_MD2_DES_CBC		(0x3a0)
-#define CKM_PBE_MD5_DES_CBC		(0x3a1)
-#define CKM_PBE_MD5_CAST_CBC		(0x3a2)
-#define CKM_PBE_MD5_CAST3_CBC		(0x3a3)
-#define CKM_PBE_MD5_CAST5_CBC		(0x3a4)
-#define CKM_PBE_MD5_CAST128_CBC		(0x3a4)
-#define CKM_PBE_SHA1_CAST5_CBC		(0x3a5)
-#define CKM_PBE_SHA1_CAST128_CBC	(0x3a5)
-#define CKM_PBE_SHA1_RC4_128		(0x3a6)
-#define CKM_PBE_SHA1_RC4_40		(0x3a7)
-#define CKM_PBE_SHA1_DES3_EDE_CBC	(0x3a8)
-#define CKM_PBE_SHA1_DES2_EDE_CBC	(0x3a9)
-#define CKM_PBE_SHA1_RC2_128_CBC	(0x3aa)
-#define CKM_PBE_SHA1_RC2_40_CBC		(0x3ab)
-#define CKM_PKCS5_PBKD2			(0x3b0)
-#define CKM_PBA_SHA1_WITH_SHA1_HMAC	(0x3c0)
-#define CKM_KEY_WRAP_LYNKS		(0x400)
-#define CKM_KEY_WRAP_SET_OAEP		(0x401)
-#define CKM_SKIPJACK_KEY_GEN		(0x1000)
-#define CKM_SKIPJACK_ECB64		(0x1001)
-#define CKM_SKIPJACK_CBC64		(0x1002)
-#define CKM_SKIPJACK_OFB64		(0x1003)
-#define CKM_SKIPJACK_CFB64		(0x1004)
-#define CKM_SKIPJACK_CFB32		(0x1005)
-#define CKM_SKIPJACK_CFB16		(0x1006)
-#define CKM_SKIPJACK_CFB8		(0x1007)
-#define CKM_SKIPJACK_WRAP		(0x1008)
-#define CKM_SKIPJACK_PRIVATE_WRAP	(0x1009)
-#define CKM_SKIPJACK_RELAYX		(0x100a)
-#define CKM_KEA_KEY_PAIR_GEN		(0x1010)
-#define CKM_KEA_KEY_DERIVE		(0x1011)
-#define CKM_FORTEZZA_TIMESTAMP		(0x1020)
-#define CKM_BATON_KEY_GEN		(0x1030)
-#define CKM_BATON_ECB128		(0x1031)
-#define CKM_BATON_ECB96			(0x1032)
-#define CKM_BATON_CBC128		(0x1033)
-#define CKM_BATON_COUNTER		(0x1034)
-#define CKM_BATON_SHUFFLE		(0x1035)
-#define CKM_BATON_WRAP			(0x1036)
-#define CKM_ECDSA_KEY_PAIR_GEN		(0x1040)
-#define CKM_EC_KEY_PAIR_GEN		(0x1040)
-#define CKM_ECDSA			(0x1041)
-#define CKM_ECDSA_SHA1			(0x1042)
-#define CKM_ECDH1_DERIVE		(0x1050)
-#define CKM_ECDH1_COFACTOR_DERIVE	(0x1051)
-#define CKM_ECMQV_DERIVE		(0x1052)
-#define CKM_JUNIPER_KEY_GEN		(0x1060)
-#define CKM_JUNIPER_ECB128		(0x1061)
-#define CKM_JUNIPER_CBC128		(0x1062)
-#define CKM_JUNIPER_COUNTER		(0x1063)
-#define CKM_JUNIPER_SHUFFLE		(0x1064)
-#define CKM_JUNIPER_WRAP		(0x1065)
-#define CKM_FASTHASH			(0x1070)
-#define CKM_AES_KEY_GEN			(0x1080)
-#define CKM_AES_ECB			(0x1081)
-#define CKM_AES_CBC			(0x1082)
-#define CKM_AES_MAC			(0x1083)
-#define CKM_AES_MAC_GENERAL		(0x1084)
-#define CKM_AES_CBC_PAD			(0x1085)
-#define CKM_DSA_PARAMETER_GEN		(0x2000)
-#define CKM_DH_PKCS_PARAMETER_GEN	(0x2001)
-#define CKM_X9_42_DH_PARAMETER_GEN	(0x2002)
-#define CKM_VENDOR_DEFINED		(1U << 31)
+#define CKM_RSA_PKCS_KEY_PAIR_GEN	(0UL)
+#define CKM_RSA_PKCS			(1UL)
+#define CKM_RSA_9796			(2UL)
+#define CKM_RSA_X_509			(3UL)
+#define CKM_MD2_RSA_PKCS		(4UL)
+#define CKM_MD5_RSA_PKCS		(5UL)
+#define CKM_SHA1_RSA_PKCS		(6UL)
+#define CKM_RIPEMD128_RSA_PKCS		(7UL)
+#define CKM_RIPEMD160_RSA_PKCS		(8UL)
+#define CKM_RSA_PKCS_OAEP		(9UL)
+#define CKM_RSA_X9_31_KEY_PAIR_GEN	(0xaUL)
+#define CKM_RSA_X9_31			(0xbUL)
+#define CKM_SHA1_RSA_X9_31		(0xcUL)
+#define CKM_RSA_PKCS_PSS		(0xdUL)
+#define CKM_SHA1_RSA_PKCS_PSS		(0xeUL)
+#define CKM_DSA_KEY_PAIR_GEN		(0x10UL)
+#define	CKM_DSA				(0x11UL)
+#define CKM_DSA_SHA1			(0x12UL)
+#define CKM_DSA_SHA224			(0x13UL)
+#define CKM_DSA_SHA256			(0x14UL)
+#define CKM_DSA_SHA384			(0x15UL)
+#define CKM_DSA_SHA512			(0x16UL)
+#define CKM_DH_PKCS_KEY_PAIR_GEN	(0x20UL)
+#define CKM_DH_PKCS_DERIVE		(0x21UL)
+#define	CKM_X9_42_DH_KEY_PAIR_GEN	(0x30UL)
+#define CKM_X9_42_DH_DERIVE		(0x31UL)
+#define CKM_X9_42_DH_HYBRID_DERIVE	(0x32UL)
+#define CKM_X9_42_MQV_DERIVE		(0x33UL)
+#define CKM_SHA256_RSA_PKCS		(0x40UL)
+#define CKM_SHA384_RSA_PKCS		(0x41UL)
+#define CKM_SHA512_RSA_PKCS		(0x42UL)
+#define CKM_SHA256_RSA_PKCS_PSS		(0x43UL)
+#define CKM_SHA384_RSA_PKCS_PSS		(0x44UL)
+#define CKM_SHA512_RSA_PKCS_PSS		(0x45UL)
+#define CKM_SHA224_RSA_PKCS		(0x46UL)
+#define CKM_SHA224_RSA_PKCS_PSS		(0x47UL)
+#define CKM_SHA3_256_RSA_PKCS		(0x60UL)
+#define CKM_SHA3_384_RSA_PKCS		(0x61UL)
+#define CKM_SHA3_512_RSA_PKCS		(0x62UL)
+#define CKM_SHA3_256_RSA_PKCS_PSS	(0x63UL)
+#define CKM_SHA3_384_RSA_PKCS_PSS	(0x64UL)
+#define CKM_SHA3_512_RSA_PKCS_PSS	(0x65UL)
+#define CKM_SHA3_224_RSA_PKCS		(0x66UL)
+#define CKM_SHA3_224_RSA_PKCS_PSS	(0x67UL)
+#define CKM_RC2_KEY_GEN			(0x100UL)
+#define CKM_RC2_ECB			(0x101UL)
+#define	CKM_RC2_CBC			(0x102UL)
+#define	CKM_RC2_MAC			(0x103UL)
+#define CKM_RC2_MAC_GENERAL		(0x104UL)
+#define CKM_RC2_CBC_PAD			(0x105UL)
+#define CKM_RC4_KEY_GEN			(0x110UL)
+#define CKM_RC4				(0x111UL)
+#define CKM_DES_KEY_GEN			(0x120UL)
+#define CKM_DES_ECB			(0x121UL)
+#define CKM_DES_CBC			(0x122UL)
+#define CKM_DES_MAC			(0x123UL)
+#define CKM_DES_MAC_GENERAL		(0x124UL)
+#define CKM_DES_CBC_PAD			(0x125UL)
+#define CKM_DES2_KEY_GEN		(0x130UL)
+#define CKM_DES3_KEY_GEN		(0x131UL)
+#define CKM_DES3_ECB			(0x132UL)
+#define CKM_DES3_CBC			(0x133UL)
+#define CKM_DES3_MAC			(0x134UL)
+#define CKM_DES3_MAC_GENERAL		(0x135UL)
+#define CKM_DES3_CBC_PAD		(0x136UL)
+#define CKM_DES3_CMAC_GENERAL		(0x137UL)
+#define CKM_DES3_CMAC			(0x138UL)
+#define CKM_CDMF_KEY_GEN		(0x140UL)
+#define CKM_CDMF_ECB			(0x141UL)
+#define CKM_CDMF_CBC			(0x142UL)
+#define CKM_CDMF_MAC			(0x143UL)
+#define CKM_CDMF_MAC_GENERAL		(0x144UL)
+#define CKM_CDMF_CBC_PAD		(0x145UL)
+#define CKM_MD2				(0x200UL)
+#define CKM_MD2_HMAC			(0x201UL)
+#define CKM_MD2_HMAC_GENERAL		(0x202UL)
+#define CKM_MD5				(0x210UL)
+#define CKM_MD5_HMAC			(0x211UL)
+#define CKM_MD5_HMAC_GENERAL		(0x212UL)
+#define CKM_SHA_1			(0x220UL)
+#define CKM_SHA_1_HMAC			(0x221UL)
+#define CKM_SHA_1_HMAC_GENERAL		(0x222UL)
+#define CKM_RIPEMD128			(0x230UL)
+#define CKM_RIPEMD128_HMAC		(0x231UL)
+#define CKM_RIPEMD128_HMAC_GENERAL	(0x232UL)
+#define CKM_RIPEMD160			(0x240UL)
+#define CKM_RIPEMD160_HMAC		(0x241UL)
+#define CKM_RIPEMD160_HMAC_GENERAL	(0x242UL)
+#define CKM_SHA256			(0x250UL)
+#define CKM_SHA256_HMAC			(0x251UL)
+#define CKM_SHA256_HMAC_GENERAL		(0x252UL)
+#define CKM_SHA224			(0x255UL)
+#define CKM_SHA224_HMAC			(0x256UL)
+#define CKM_SHA224_HMAC_GENERAL		(0x257UL)
+#define CKM_SHA384			(0x260UL)
+#define CKM_SHA384_HMAC			(0x261UL)
+#define CKM_SHA384_HMAC_GENERAL		(0x262UL)
+#define CKM_SHA512			(0x270UL)
+#define CKM_SHA512_HMAC			(0x271UL)
+#define CKM_SHA512_HMAC_GENERAL		(0x272UL)
+#define CKM_SHA3_256			(0x2B0UL)
+#define CKM_SHA3_256_HMAC		(0x2B1UL)
+#define CKM_SHA3_256_HMAC_GENERAL	(0x2B2UL)
+#define CKM_SHA3_256_KEY_GEN		(0x2B3UL)
+#define CKM_SHA3_224			(0x2B5UL)
+#define CKM_SHA3_224_HMAC		(0x2B6UL)
+#define CKM_SHA3_224_HMAC_GENERAL	(0x2B7UL)
+#define CKM_SHA3_224_KEY_GEN		(0x2B8UL)
+#define CKM_SHA3_384			(0x2C0UL)
+#define CKM_SHA3_384_HMAC		(0x2C1UL)
+#define CKM_SHA3_384_HMAC_GENERAL	(0x2C2UL)
+#define CKM_SHA3_384_KEY_GEN		(0x2C3UL)
+#define CKM_SHA3_512			(0x2D0UL)
+#define CKM_SHA3_512_HMAC		(0x2D1UL)
+#define CKM_SHA3_512_HMAC_GENERAL	(0x2D2UL)
+#define CKM_SHA3_512_KEY_GEN		(0x2D3UL)
+#define CKM_CAST_KEY_GEN		(0x300UL)
+#define CKM_CAST_ECB			(0x301UL)
+#define CKM_CAST_CBC			(0x302UL)
+#define CKM_CAST_MAC			(0x303UL)
+#define CKM_CAST_MAC_GENERAL		(0x304UL)
+#define CKM_CAST_CBC_PAD		(0x305UL)
+#define CKM_CAST3_KEY_GEN		(0x310UL)
+#define CKM_CAST3_ECB			(0x311UL)
+#define CKM_CAST3_CBC			(0x312UL)
+#define CKM_CAST3_MAC			(0x313UL)
+#define CKM_CAST3_MAC_GENERAL		(0x314UL)
+#define CKM_CAST3_CBC_PAD		(0x315UL)
+#define CKM_CAST5_KEY_GEN		(0x320UL)
+#define CKM_CAST128_KEY_GEN		(0x320UL)
+#define CKM_CAST5_ECB			(0x321UL)
+#define CKM_CAST128_ECB			(0x321UL)
+#define CKM_CAST5_CBC			(0x322UL)
+#define CKM_CAST128_CBC			(0x322UL)
+#define CKM_CAST5_MAC			(0x323UL)
+#define	CKM_CAST128_MAC			(0x323UL)
+#define CKM_CAST5_MAC_GENERAL		(0x324UL)
+#define CKM_CAST128_MAC_GENERAL		(0x324UL)
+#define CKM_CAST5_CBC_PAD		(0x325UL)
+#define CKM_CAST128_CBC_PAD		(0x325UL)
+#define CKM_RC5_KEY_GEN			(0x330UL)
+#define CKM_RC5_ECB			(0x331UL)
+#define CKM_RC5_CBC			(0x332UL)
+#define CKM_RC5_MAC			(0x333UL)
+#define CKM_RC5_MAC_GENERAL		(0x334UL)
+#define CKM_RC5_CBC_PAD			(0x335UL)
+#define CKM_IDEA_KEY_GEN		(0x340UL)
+#define CKM_IDEA_ECB			(0x341UL)
+#define	CKM_IDEA_CBC			(0x342UL)
+#define CKM_IDEA_MAC			(0x343UL)
+#define CKM_IDEA_MAC_GENERAL		(0x344UL)
+#define CKM_IDEA_CBC_PAD		(0x345UL)
+#define CKM_GENERIC_SECRET_KEY_GEN	(0x350UL)
+#define CKM_CONCATENATE_BASE_AND_KEY	(0x360UL)
+#define CKM_CONCATENATE_BASE_AND_DATA	(0x362UL)
+#define CKM_CONCATENATE_DATA_AND_BASE	(0x363UL)
+#define CKM_XOR_BASE_AND_DATA		(0x364UL)
+#define CKM_EXTRACT_KEY_FROM_KEY	(0x365UL)
+#define CKM_SSL3_PRE_MASTER_KEY_GEN	(0x370UL)
+#define CKM_SSL3_MASTER_KEY_DERIVE	(0x371UL)
+#define CKM_SSL3_KEY_AND_MAC_DERIVE	(0x372UL)
+#define CKM_SSL3_MASTER_KEY_DERIVE_DH	(0x373UL)
+#define CKM_TLS_PRE_MASTER_KEY_GEN	(0x374UL)
+#define CKM_TLS_MASTER_KEY_DERIVE	(0x375UL)
+#define CKM_TLS_KEY_AND_MAC_DERIVE	(0x376UL)
+#define CKM_TLS_MASTER_KEY_DERIVE_DH	(0x377UL)
+#define CKM_SSL3_MD5_MAC		(0x380UL)
+#define CKM_SSL3_SHA1_MAC		(0x381UL)
+#define CKM_MD5_KEY_DERIVATION		(0x390UL)
+#define CKM_MD2_KEY_DERIVATION		(0x391UL)
+#define CKM_SHA1_KEY_DERIVATION		(0x392UL)
+#define CKM_PBE_MD2_DES_CBC		(0x3a0UL)
+#define CKM_PBE_MD5_DES_CBC		(0x3a1UL)
+#define CKM_PBE_MD5_CAST_CBC		(0x3a2UL)
+#define CKM_PBE_MD5_CAST3_CBC		(0x3a3UL)
+#define CKM_PBE_MD5_CAST5_CBC		(0x3a4UL)
+#define CKM_PBE_MD5_CAST128_CBC		(0x3a4UL)
+#define CKM_PBE_SHA1_CAST5_CBC		(0x3a5UL)
+#define CKM_PBE_SHA1_CAST128_CBC	(0x3a5UL)
+#define CKM_PBE_SHA1_RC4_128		(0x3a6UL)
+#define CKM_PBE_SHA1_RC4_40		(0x3a7UL)
+#define CKM_PBE_SHA1_DES3_EDE_CBC	(0x3a8UL)
+#define CKM_PBE_SHA1_DES2_EDE_CBC	(0x3a9UL)
+#define CKM_PBE_SHA1_RC2_128_CBC	(0x3aaUL)
+#define CKM_PBE_SHA1_RC2_40_CBC		(0x3abUL)
+#define CKM_PKCS5_PBKD2			(0x3b0UL)
+#define CKM_PBA_SHA1_WITH_SHA1_HMAC	(0x3c0UL)
+#define CKM_KEY_WRAP_LYNKS		(0x400UL)
+#define CKM_KEY_WRAP_SET_OAEP		(0x401UL)
+#define CKM_SKIPJACK_KEY_GEN		(0x1000UL)
+#define CKM_SKIPJACK_ECB64		(0x1001UL)
+#define CKM_SKIPJACK_CBC64		(0x1002UL)
+#define CKM_SKIPJACK_OFB64		(0x1003UL)
+#define CKM_SKIPJACK_CFB64		(0x1004UL)
+#define CKM_SKIPJACK_CFB32		(0x1005UL)
+#define CKM_SKIPJACK_CFB16		(0x1006UL)
+#define CKM_SKIPJACK_CFB8		(0x1007UL)
+#define CKM_SKIPJACK_WRAP		(0x1008UL)
+#define CKM_SKIPJACK_PRIVATE_WRAP	(0x1009UL)
+#define CKM_SKIPJACK_RELAYX		(0x100aUL)
+#define CKM_KEA_KEY_PAIR_GEN		(0x1010UL)
+#define CKM_KEA_KEY_DERIVE		(0x1011UL)
+#define CKM_FORTEZZA_TIMESTAMP		(0x1020UL)
+#define CKM_BATON_KEY_GEN		(0x1030UL)
+#define CKM_BATON_ECB128		(0x1031UL)
+#define CKM_BATON_ECB96			(0x1032UL)
+#define CKM_BATON_CBC128		(0x1033UL)
+#define CKM_BATON_COUNTER		(0x1034UL)
+#define CKM_BATON_SHUFFLE		(0x1035UL)
+#define CKM_BATON_WRAP			(0x1036UL)
+#define CKM_ECDSA_KEY_PAIR_GEN		(0x1040UL)
+#define CKM_EC_KEY_PAIR_GEN		(0x1040UL)
+#define CKM_ECDSA			(0x1041UL)
+#define CKM_ECDSA_SHA1			(0x1042UL)
+#define CKM_ECDSA_SHA224		(0x1043UL)
+#define CKM_ECDSA_SHA256		(0x1044UL)
+#define CKM_ECDSA_SHA384		(0x1045UL)
+#define CKM_ECDSA_SHA512		(0x1046UL)
+#define CKM_ECDSA_SHA3_224		(0x1047UL)
+#define CKM_ECDSA_SHA3_256		(0x1048UL)
+#define CKM_ECDSA_SHA3_384		(0x1049UL)
+#define CKM_ECDSA_SHA3_512		(0x104AUL)
+#define CKM_ECDH1_DERIVE		(0x1050UL)
+#define CKM_ECDH1_COFACTOR_DERIVE	(0x1051UL)
+#define CKM_ECMQV_DERIVE		(0x1052UL)
+#define CKM_EC_EDWARDS_KEY_PAIR_GEN     (0x1055UL)
+#define CKM_EC_MONTGOMERY_KEY_PAIR_GEN  (0x1056UL)
+#define CKM_EDDSA			(0x1057UL)
+#define CKM_JUNIPER_KEY_GEN		(0x1060UL)
+#define CKM_JUNIPER_ECB128		(0x1061UL)
+#define CKM_JUNIPER_CBC128		(0x1062UL)
+#define CKM_JUNIPER_COUNTER		(0x1063UL)
+#define CKM_JUNIPER_SHUFFLE		(0x1064UL)
+#define CKM_JUNIPER_WRAP		(0x1065UL)
+#define CKM_FASTHASH			(0x1070UL)
+#define CKM_AES_KEY_GEN			(0x1080UL)
+#define CKM_AES_ECB			(0x1081UL)
+#define CKM_AES_CBC			(0x1082UL)
+#define CKM_AES_MAC			(0x1083UL)
+#define CKM_AES_MAC_GENERAL		(0x1084UL)
+#define CKM_AES_CBC_PAD			(0x1085UL)
+#define CKM_AES_CTR				(0x1086UL)
+#define CKM_AES_GCM				(0x1087UL)
+#define CKM_AES_CCM				(0x1088UL)
+#define CKM_AES_CTS				(0x1089UL)
+#define CKM_AES_CMAC			(0x108AUL)
+#define CKM_AES_CMAC_GENERAL		(0x108BUL)
+#define CKM_AES_XCBC_MAC		(0x108CUL)
+#define CKM_AES_XCBC_MAC_96		(0x108DUL)
+#define CKM_AES_GMAC			(0x108EUL)
+#define CKM_BLOWFISH_KEY_GEN    (0x1090UL)
+#define CKM_BLOWFISH_CBC        (0x1091UL)
+#define CKM_TWOFISH_KEY_GEN     (0x1092UL)
+#define CKM_TWOFISH_CBC         (0x1093UL)
+#define CKM_DES_ECB_ENCRYPT_DATA	(0x1100UL)
+#define CKM_DES_CBC_ENCRYPT_DATA	(0x1101UL)
+#define CKM_DES3_ECB_ENCRYPT_DATA	(0x1102UL)
+#define CKM_DES3_CBC_ENCRYPT_DATA	(0x1103UL)
+#define CKM_AES_ECB_ENCRYPT_DATA	(0x1104UL)
+#define CKM_AES_CBC_ENCRYPT_DATA	(0x1105UL)
+#define CKM_GOSTR3410_KEY_PAIR_GEN	(0x1200UL)
+#define CKM_GOSTR3410			(0x1201UL)
+#define CKM_GOSTR3410_WITH_GOSTR3411	(0x1202UL)
+#define CKM_GOSTR3410_KEY_WRAP  (0x1203UL)
+#define CKM_GOSTR3410_DERIVE    (0x1204UL)
+#define CKM_GOSTR3410_512_KEY_PAIR_GEN	(CK_VENDOR_PKCS11_RU_TEAM_TK26 | 0x005)
+#define CKM_GOSTR3410_512	(CK_VENDOR_PKCS11_RU_TEAM_TK26 | 0x006)
+#define CKM_GOSTR3410_12_DERIVE	(CK_VENDOR_PKCS11_RU_TEAM_TK26 | 0x007)
+#define CKM_GOSTR3410_WITH_GOSTR3411_12_256	(CK_VENDOR_PKCS11_RU_TEAM_TK26 | 0x008)
+#define CKM_GOSTR3410_WITH_GOSTR3411_12_512	(CK_VENDOR_PKCS11_RU_TEAM_TK26 | 0x009)
+#define CKM_GOSTR3411			(0x1210UL)
+#define CKM_GOSTR3411_HMAC      (0x1211UL)
+#define CKM_GOSTR3411_12_256	(CK_VENDOR_PKCS11_RU_TEAM_TK26 | 0x012)
+#define CKM_GOSTR3411_12_512	(CK_VENDOR_PKCS11_RU_TEAM_TK26 | 0x013)
+#define CKM_GOSTR3411_12_256_HMAC	(CK_VENDOR_PKCS11_RU_TEAM_TK26 | 0x014)
+#define CKM_GOSTR3411_12_512_HMAC	(CK_VENDOR_PKCS11_RU_TEAM_TK26 | 0x015)
+#define CKM_GOST28147_KEY_GEN   (0x1220UL)
+#define CKM_GOST28147_ECB       (0x1221UL)
+#define CKM_GOST28147           (0x1222UL)
+#define CKM_GOST28147_MAC       (0x1223UL)
+#define CKM_GOST28147_KEY_WRAP  (0x1224UL)
 
+#define CKM_DSA_PARAMETER_GEN		(0x2000UL)
+#define CKM_DH_PKCS_PARAMETER_GEN	(0x2001UL)
+#define CKM_X9_42_DH_PARAMETER_GEN	(0x2002UL)
+#define CKM_AES_OFB			(0x2104UL)
+#define CKM_AES_CFB64			(0x2105UL)
+#define CKM_AES_CFB8			(0x2106UL)
+#define CKM_AES_CFB128			(0x2107UL)
+#define CKM_AES_CFB1			(0x2108UL)
+#define CKM_AES_KEY_WRAP		(0x2109UL)
+#define CKM_AES_KEY_WRAP_PAD		(0x210AUL)
+#define CKM_XEDDSA			(0x4029UL)
+#define CKM_HKDF_DERIVE			(0x402AUL)
+#define CKM_HKDF_DATA			(0x402BUL)
+#define CKM_HKDF_KEY_GEN		(0x402CUL)
+
+#define CKM_VENDOR_DEFINED		(1UL << 31)
 
 struct ck_mechanism
 {
@@ -690,25 +835,143 @@ struct ck_mechanism_info
   ck_flags_t flags;
 };
 
-#define CKF_HW			(1 << 0)
-#define CKF_ENCRYPT		(1 << 8)
-#define CKF_DECRYPT		(1 << 9)
-#define CKF_DIGEST		(1 << 10)
-#define CKF_SIGN		(1 << 11)
-#define CKF_SIGN_RECOVER	(1 << 12)
-#define CKF_VERIFY		(1 << 13)
-#define CKF_VERIFY_RECOVER	(1 << 14)
-#define CKF_GENERATE		(1 << 15)
-#define CKF_GENERATE_KEY_PAIR	(1 << 16)
-#define CKF_WRAP		(1 << 17)
-#define CKF_UNWRAP		(1 << 18)
-#define CKF_DERIVE		(1 << 19)
-#define CKF_EXTENSION		(1U << 31)
+#define CKF_HW			(1UL << 0)
 
+#define CKF_MESSAGE_ENCRYPT	(1UL << 1)
+#define CKF_MESSAGE_DECRYPT	(1UL << 2)
+#define CKF_MESSAGE_SIGN	(1UL << 3)
+#define CKF_MESSAGE_VERIFY	(1UL << 4)
+#define CKF_MULTI_MESSAGE	(1UL << 5)
+#define CKF_FIND_OBJECTS	(1UL << 6)
+
+#define CKF_ENCRYPT		(1UL << 8)
+#define CKF_DECRYPT		(1UL << 9)
+#define CKF_DIGEST		(1UL << 10)
+#define CKF_SIGN		(1UL << 11)
+#define CKF_SIGN_RECOVER	(1UL << 12)
+#define CKF_VERIFY		(1UL << 13)
+#define CKF_VERIFY_RECOVER	(1UL << 14)
+#define CKF_GENERATE		(1UL << 15)
+#define CKF_GENERATE_KEY_PAIR	(1UL << 16)
+#define CKF_WRAP		(1UL << 17)
+#define CKF_UNWRAP		(1UL << 18)
+#define CKF_DERIVE		(1UL << 19)
+#define CKF_EXTENSION		(1UL << 31)
+
+#define CKF_EC_F_P			(1UL << 20)
+#define CKF_EC_F_2M			(1UL << 21)
+#define CKF_EC_ECPARAMETERS	(1UL << 22)
+#define CKF_EC_OID		(1UL << 23)
+#define CKF_EC_NAMEDCURVE	CKF_EC_OID
+#define CKF_EC_UNCOMPRESS	(1UL << 24)
+#define CKF_EC_COMPRESS		(1UL << 25)
+#define CKF_EC_CURVENAME	(1UL << 26)
 
 /* Flags for C_WaitForSlotEvent.  */
-#define CKF_DONT_BLOCK				(1)
+#define CKF_DONT_BLOCK				(1UL)
 
+/* Flags for Key derivation */
+#define CKD_NULL			(0x1UL)
+#define CKD_SHA1_KDF			(0x2UL)
+#define CKD_SHA224_KDF			(0x5UL)
+#define CKD_SHA256_KDF			(0x6UL)
+#define CKD_SHA384_KDF			(0x7UL)
+#define CKD_SHA512_KDF			(0x8UL)
+
+typedef struct CK_ECDH1_DERIVE_PARAMS {
+	unsigned long  kdf;
+	unsigned long  ulSharedDataLen;
+	unsigned char *  pSharedData;
+	unsigned long  ulPublicDataLen;
+	unsigned char *  pPublicData;
+} CK_ECDH1_DERIVE_PARAMS;
+
+typedef struct CK_ECMQV_DERIVE_PARAMS {
+	unsigned long kdf;
+	unsigned long ulSharedDataLen;
+	unsigned char * pSharedData;
+	unsigned long ulPublicDataLen;
+	unsigned char * pPublicData;
+	unsigned long ulPrivateDataLen;
+	CK_OBJECT_HANDLE hPrivateData;
+	unsigned long ulPublicDataLen2;
+	unsigned char * pPublicData2;
+	CK_OBJECT_HANDLE publicKey;
+} CK_ECMQV_DERIVE_PARAMS;
+
+typedef unsigned long ck_rsa_pkcs_mgf_type_t;
+typedef unsigned long CK_RSA_PKCS_OAEP_SOURCE_TYPE;
+
+typedef struct CK_RSA_PKCS_OAEP_PARAMS {
+	CK_MECHANISM_TYPE hashAlg;
+	CK_RSA_PKCS_MGF_TYPE mgf;
+	CK_RSA_PKCS_OAEP_SOURCE_TYPE source;
+	void *pSourceData;
+	unsigned long ulSourceDataLen;
+} CK_RSA_PKCS_OAEP_PARAMS;
+
+typedef struct CK_RSA_PKCS_PSS_PARAMS {
+	ck_mechanism_type_t hashAlg;
+	CK_RSA_PKCS_MGF_TYPE mgf;
+	unsigned long sLen;
+} CK_RSA_PKCS_PSS_PARAMS;
+
+#define CKG_MGF1_SHA1			(0x00000001UL)
+#define CKG_MGF1_SHA224		(0x00000005UL)
+#define CKG_MGF1_SHA256		(0x00000002UL)
+#define CKG_MGF1_SHA384		(0x00000003UL)
+#define CKG_MGF1_SHA512		(0x00000004UL)
+#define CKG_MGF1_SHA3_224	(0x00000006UL)
+#define CKG_MGF1_SHA3_256	(0x00000007UL)
+#define CKG_MGF1_SHA3_384	(0x00000008UL)
+#define CKG_MGF1_SHA3_512	(0x00000009UL)
+
+#define CKZ_DATA_SPECIFIED	(0x00000001UL)
+
+typedef struct CK_GCM_PARAMS {
+	void * pIv;
+	unsigned long ulIvLen;
+	unsigned long ulIvBits;
+	void * pAAD;
+	unsigned long ulAADLen;
+	unsigned long ulTagBits;
+} CK_GCM_PARAMS;
+
+typedef struct CK_CCM_PARAMS {
+	unsigned long ulDataLen;
+	unsigned char *pNonce;
+	unsigned long ulNonceLen;
+	unsigned char *pAAD;
+	unsigned long ulAADLen;
+	unsigned long ulMACLen;
+} CK_CCM_PARAMS;
+
+/* EDDSA */
+typedef struct CK_EDDSA_PARAMS {
+	unsigned char phFlag;
+	unsigned long ulContextDataLen;
+	unsigned char *pContextData;
+} CK_EDDSA_PARAMS;
+
+typedef CK_EDDSA_PARAMS *CK_EDDSA_PARAMS_PTR;
+
+/* XEDDSA */
+typedef struct CK_XEDDSA_PARAMS {
+	unsigned long hash;
+} CK_XEDDSA_PARAMS;
+
+typedef CK_XEDDSA_PARAMS *CK_XEDDSA_PARAMS_PTR;
+
+typedef struct CK_AES_CTR_PARAMS {
+    unsigned long ulCounterBits;
+    unsigned char cb[16];
+} CK_AES_CTR_PARAMS;
+
+typedef CK_AES_CTR_PARAMS *CK_AES_CTR_PARAMS_PTR;
+
+typedef unsigned long CK_MAC_GENERAL_PARAMS;
+
+typedef CK_MAC_GENERAL_PARAMS *CK_MAC_GENERAL_PARAMS_PTR;
 
 typedef unsigned long ck_rv_t;
 
@@ -716,8 +979,17 @@ typedef unsigned long ck_rv_t;
 typedef ck_rv_t (*ck_notify_t) (ck_session_handle_t session,
 				ck_notification_t event, void *application);
 
+struct ck_interface {
+  char * pInterfaceName;
+  void * pFunctionList;
+  ck_flags_t flags;
+};
+
+#define CKF_INTERFACE_FORK_SAFE	(0x00000001UL)
+
 /* Forward reference.  */
 struct ck_function_list;
+struct ck_function_list_3_0;
 
 #define _CK_DECLARE_FUNCTION(name, args)	\
 typedef ck_rv_t (*CK_ ## name) args;		\
@@ -774,7 +1046,7 @@ _CK_DECLARE_FUNCTION (C_SetOperationState,
 		       unsigned char *operation_state,
 		       unsigned long operation_state_len,
 		       ck_object_handle_t encryption_key,
-		       ck_object_handle_t authentiation_key));
+		       ck_object_handle_t authentication_key));
 _CK_DECLARE_FUNCTION (C_Login,
 		      (ck_session_handle_t session, ck_user_type_t user_type,
 		       unsigned char *pin, unsigned long pin_len));
@@ -999,6 +1271,147 @@ _CK_DECLARE_FUNCTION (C_GenerateRandom,
 _CK_DECLARE_FUNCTION (C_GetFunctionStatus, (ck_session_handle_t session));
 _CK_DECLARE_FUNCTION (C_CancelFunction, (ck_session_handle_t session));
 
+_CK_DECLARE_FUNCTION (C_GetInterfaceList,
+		      (struct ck_interface *interfaces_list,
+		       unsigned long *count));
+_CK_DECLARE_FUNCTION (C_GetInterface,
+		      (unsigned char *interface_name,
+		       struct ck_version *version,
+		       struct ck_interface **interface_ptr,
+		       ck_flags_t flags));
+
+_CK_DECLARE_FUNCTION (C_LoginUser,
+		      (ck_session_handle_t session,
+		       ck_user_type_t user_type,
+		       unsigned char *pin,
+		       unsigned long pin_len,
+		       unsigned char *username,
+		       unsigned long username_len));
+
+_CK_DECLARE_FUNCTION (C_SessionCancel,
+		      (ck_session_handle_t session,
+		       ck_flags_t flags));
+
+_CK_DECLARE_FUNCTION (C_MessageEncryptInit,
+		      (ck_session_handle_t session,
+		       struct ck_mechanism *mechanism,
+		       ck_object_handle_t key));
+_CK_DECLARE_FUNCTION (C_EncryptMessage,
+		      (ck_session_handle_t session,
+		       void *parameter,
+		       unsigned long parameter_len,
+		       unsigned char *associated_data,
+		       unsigned long associated_data_len,
+		       unsigned char *plaintext,
+		       unsigned long plaintext_len,
+		       unsigned char *ciphertext,
+		       unsigned long *ciphertext_len));
+_CK_DECLARE_FUNCTION (C_EncryptMessageBegin,
+		      (ck_session_handle_t session,
+		       void *parameter,
+		       unsigned long parameter_len,
+		       unsigned char *associated_data,
+		       unsigned long associated_data_len));
+_CK_DECLARE_FUNCTION (C_EncryptMessageNext,
+		      (ck_session_handle_t session,
+		       void *parameter,
+		       unsigned long parameter_len,
+		       unsigned char *plaintext_part,
+		       unsigned long plaintext_part_len,
+		       unsigned char *ciphertext_part,
+		       unsigned long *ciphertext_part_len,
+		       ck_flags_t flags));
+_CK_DECLARE_FUNCTION (C_MessageEncryptFinal,
+		      (ck_session_handle_t session));
+
+_CK_DECLARE_FUNCTION (C_MessageDecryptInit,
+		      (ck_session_handle_t session,
+		       struct ck_mechanism *mechanism,
+		       ck_object_handle_t key));
+_CK_DECLARE_FUNCTION (C_DecryptMessage,
+		      (ck_session_handle_t session,
+		       void *parameter,
+		       unsigned long parameter_len,
+		       unsigned char *associated_data,
+		       unsigned long associated_data_len,
+		       unsigned char *ciphertext,
+		       unsigned long ciphertext_len,
+		       unsigned char *plaintext,
+		       unsigned long *plaintext_len));
+_CK_DECLARE_FUNCTION (C_DecryptMessageBegin,
+		      (ck_session_handle_t session,
+		       void *parameter,
+		       unsigned long parameter_len,
+		       unsigned char *associated_data,
+		       unsigned long associated_data_len));
+_CK_DECLARE_FUNCTION (C_DecryptMessageNext,
+		      (ck_session_handle_t session,
+		       void *parameter,
+		       unsigned long parameter_len,
+		       unsigned char *ciphertext_part,
+		       unsigned long ciphertext_part_len,
+		       unsigned char *plaintext_part,
+		       unsigned long *plaintext_part_len,
+		       ck_flags_t flags));
+_CK_DECLARE_FUNCTION (C_MessageDecryptFinal,
+		      (ck_session_handle_t session));
+
+_CK_DECLARE_FUNCTION (C_MessageSignInit,
+		      (ck_session_handle_t session,
+		       struct ck_mechanism *mechanism,
+		       ck_object_handle_t key));
+_CK_DECLARE_FUNCTION (C_SignMessage,
+		      (ck_session_handle_t session,
+		       void *parameter,
+		       unsigned long parameter_len,
+		       unsigned char *data,
+		       unsigned long data_len,
+		       unsigned char *signature,
+		       unsigned long *signature_len));
+_CK_DECLARE_FUNCTION (C_SignMessageBegin,
+		      (ck_session_handle_t session,
+		       void *parameter,
+		       unsigned long parameter_len));
+_CK_DECLARE_FUNCTION (C_SignMessageNext,
+		      (ck_session_handle_t session,
+		       void *parameter,
+		       unsigned long parameter_len,
+		       unsigned char *data,
+		       unsigned long data_len,
+		       unsigned char *signature,
+		       unsigned long *signature_len));
+_CK_DECLARE_FUNCTION (C_MessageSignFinal,
+		      (ck_session_handle_t session));
+
+_CK_DECLARE_FUNCTION (C_MessageVerifyInit,
+		      (ck_session_handle_t session,
+		       struct ck_mechanism *mechanism,
+		       ck_object_handle_t key));
+_CK_DECLARE_FUNCTION (C_VerifyMessage,
+		      (ck_session_handle_t session,
+		       void *parameter,
+		       unsigned long parameter_len,
+		       unsigned char *data,
+		       unsigned long data_len,
+		       unsigned char *signature,
+		       unsigned long signature_len));
+_CK_DECLARE_FUNCTION (C_VerifyMessageBegin,
+		      (ck_session_handle_t session,
+		       void *parameter,
+		       unsigned long parameter_len));
+_CK_DECLARE_FUNCTION (C_VerifyMessageNext,
+		      (ck_session_handle_t session,
+		       void *parameter,
+		       unsigned long parameter_len,
+		       unsigned char *data,
+		       unsigned long data_len,
+		       unsigned char *signature,
+		       unsigned long signature_len));
+_CK_DECLARE_FUNCTION (C_MessageVerifyFinal,
+		      (ck_session_handle_t session));
+
+/* Flags in Message-based encryption/decryption API */
+#define CKF_END_OF_MESSAGE 	(0x00000001UL)
 
 struct ck_function_list
 {
@@ -1073,6 +1486,105 @@ struct ck_function_list
   CK_C_WaitForSlotEvent C_WaitForSlotEvent;
 };
 
+struct ck_function_list_3_0
+{
+  struct ck_version version;
+  CK_C_Initialize C_Initialize;
+  CK_C_Finalize C_Finalize;
+  CK_C_GetInfo C_GetInfo;
+  CK_C_GetFunctionList C_GetFunctionList;
+  CK_C_GetSlotList C_GetSlotList;
+  CK_C_GetSlotInfo C_GetSlotInfo;
+  CK_C_GetTokenInfo C_GetTokenInfo;
+  CK_C_GetMechanismList C_GetMechanismList;
+  CK_C_GetMechanismInfo C_GetMechanismInfo;
+  CK_C_InitToken C_InitToken;
+  CK_C_InitPIN C_InitPIN;
+  CK_C_SetPIN C_SetPIN;
+  CK_C_OpenSession C_OpenSession;
+  CK_C_CloseSession C_CloseSession;
+  CK_C_CloseAllSessions C_CloseAllSessions;
+  CK_C_GetSessionInfo C_GetSessionInfo;
+  CK_C_GetOperationState C_GetOperationState;
+  CK_C_SetOperationState C_SetOperationState;
+  CK_C_Login C_Login;
+  CK_C_Logout C_Logout;
+  CK_C_CreateObject C_CreateObject;
+  CK_C_CopyObject C_CopyObject;
+  CK_C_DestroyObject C_DestroyObject;
+  CK_C_GetObjectSize C_GetObjectSize;
+  CK_C_GetAttributeValue C_GetAttributeValue;
+  CK_C_SetAttributeValue C_SetAttributeValue;
+  CK_C_FindObjectsInit C_FindObjectsInit;
+  CK_C_FindObjects C_FindObjects;
+  CK_C_FindObjectsFinal C_FindObjectsFinal;
+  CK_C_EncryptInit C_EncryptInit;
+  CK_C_Encrypt C_Encrypt;
+  CK_C_EncryptUpdate C_EncryptUpdate;
+  CK_C_EncryptFinal C_EncryptFinal;
+  CK_C_DecryptInit C_DecryptInit;
+  CK_C_Decrypt C_Decrypt;
+  CK_C_DecryptUpdate C_DecryptUpdate;
+  CK_C_DecryptFinal C_DecryptFinal;
+  CK_C_DigestInit C_DigestInit;
+  CK_C_Digest C_Digest;
+  CK_C_DigestUpdate C_DigestUpdate;
+  CK_C_DigestKey C_DigestKey;
+  CK_C_DigestFinal C_DigestFinal;
+  CK_C_SignInit C_SignInit;
+  CK_C_Sign C_Sign;
+  CK_C_SignUpdate C_SignUpdate;
+  CK_C_SignFinal C_SignFinal;
+  CK_C_SignRecoverInit C_SignRecoverInit;
+  CK_C_SignRecover C_SignRecover;
+  CK_C_VerifyInit C_VerifyInit;
+  CK_C_Verify C_Verify;
+  CK_C_VerifyUpdate C_VerifyUpdate;
+  CK_C_VerifyFinal C_VerifyFinal;
+  CK_C_VerifyRecoverInit C_VerifyRecoverInit;
+  CK_C_VerifyRecover C_VerifyRecover;
+  CK_C_DigestEncryptUpdate C_DigestEncryptUpdate;
+  CK_C_DecryptDigestUpdate C_DecryptDigestUpdate;
+  CK_C_SignEncryptUpdate C_SignEncryptUpdate;
+  CK_C_DecryptVerifyUpdate C_DecryptVerifyUpdate;
+  CK_C_GenerateKey C_GenerateKey;
+  CK_C_GenerateKeyPair C_GenerateKeyPair;
+  CK_C_WrapKey C_WrapKey;
+  CK_C_UnwrapKey C_UnwrapKey;
+  CK_C_DeriveKey C_DeriveKey;
+  CK_C_SeedRandom C_SeedRandom;
+  CK_C_GenerateRandom C_GenerateRandom;
+  CK_C_GetFunctionStatus C_GetFunctionStatus;
+  CK_C_CancelFunction C_CancelFunction;
+  CK_C_WaitForSlotEvent C_WaitForSlotEvent;
+  /* PKCS #11 3.0 functions */
+  CK_C_GetInterfaceList C_GetInterfaceList;
+  CK_C_GetInterface C_GetInterface;
+  CK_C_LoginUser C_LoginUser;
+  CK_C_SessionCancel C_SessionCancel;
+  CK_C_MessageEncryptInit C_MessageEncryptInit;
+  CK_C_EncryptMessage C_EncryptMessage;
+  CK_C_EncryptMessageBegin C_EncryptMessageBegin;
+  CK_C_EncryptMessageNext C_EncryptMessageNext;
+  CK_C_MessageEncryptFinal C_MessageEncryptFinal;
+  CK_C_MessageDecryptInit C_MessageDecryptInit;
+  CK_C_DecryptMessage C_DecryptMessage;
+  CK_C_DecryptMessageBegin C_DecryptMessageBegin;
+  CK_C_DecryptMessageNext C_DecryptMessageNext;
+  CK_C_MessageDecryptFinal C_MessageDecryptFinal;
+  CK_C_MessageSignInit C_MessageSignInit;
+  CK_C_SignMessage C_SignMessage;
+  CK_C_SignMessageBegin C_SignMessageBegin;
+  CK_C_SignMessageNext C_SignMessageNext;
+  CK_C_MessageSignFinal C_MessageSignFinal;
+  CK_C_MessageVerifyInit C_MessageVerifyInit;
+  CK_C_VerifyMessage C_VerifyMessage;
+  CK_C_VerifyMessageBegin C_VerifyMessageBegin;
+  CK_C_VerifyMessageNext C_VerifyMessageNext;
+  CK_C_MessageVerifyFinal C_MessageVerifyFinal;
+};
+
+
 
 typedef ck_rv_t (*ck_createmutex_t) (void **mutex);
 typedef ck_rv_t (*ck_destroymutex_t) (void *mutex);
@@ -1091,96 +1603,97 @@ struct ck_c_initialize_args
 };
 
 
-#define CKF_LIBRARY_CANT_CREATE_OS_THREADS	(1 << 0)
-#define CKF_OS_LOCKING_OK			(1 << 1)
-
-#define CKR_OK					(0)
-#define CKR_CANCEL				(1)
-#define CKR_HOST_MEMORY				(2)
-#define CKR_SLOT_ID_INVALID			(3)
-#define CKR_GENERAL_ERROR			(5)
-#define CKR_FUNCTION_FAILED			(6)
-#define CKR_ARGUMENTS_BAD			(7)
-#define CKR_NO_EVENT				(8)
-#define CKR_NEED_TO_CREATE_THREADS		(9)
-#define CKR_CANT_LOCK				(0xa)
-#define CKR_ATTRIBUTE_READ_ONLY			(0x10)
-#define CKR_ATTRIBUTE_SENSITIVE			(0x11)
-#define CKR_ATTRIBUTE_TYPE_INVALID		(0x12)
-#define CKR_ATTRIBUTE_VALUE_INVALID		(0x13)
-#define CKR_DATA_INVALID			(0x20)
-#define CKR_DATA_LEN_RANGE			(0x21)
-#define CKR_DEVICE_ERROR			(0x30)
-#define CKR_DEVICE_MEMORY			(0x31)
-#define CKR_DEVICE_REMOVED			(0x32)
-#define CKR_ENCRYPTED_DATA_INVALID		(0x40)
-#define CKR_ENCRYPTED_DATA_LEN_RANGE		(0x41)
-#define CKR_FUNCTION_CANCELED			(0x50)
-#define CKR_FUNCTION_NOT_PARALLEL		(0x51)
-#define CKR_FUNCTION_NOT_SUPPORTED		(0x54)
-#define CKR_KEY_HANDLE_INVALID			(0x60)
-#define CKR_KEY_SIZE_RANGE			(0x62)
-#define CKR_KEY_TYPE_INCONSISTENT		(0x63)
-#define CKR_KEY_NOT_NEEDED			(0x64)
-#define CKR_KEY_CHANGED				(0x65)
-#define CKR_KEY_NEEDED				(0x66)
-#define CKR_KEY_INDIGESTIBLE			(0x67)
-#define CKR_KEY_FUNCTION_NOT_PERMITTED		(0x68)
-#define CKR_KEY_NOT_WRAPPABLE			(0x69)
-#define CKR_KEY_UNEXTRACTABLE			(0x6a)
-#define CKR_MECHANISM_INVALID			(0x70)
-#define CKR_MECHANISM_PARAM_INVALID		(0x71)
-#define CKR_OBJECT_HANDLE_INVALID		(0x82)
-#define CKR_OPERATION_ACTIVE			(0x90)
-#define CKR_OPERATION_NOT_INITIALIZED		(0x91)
-#define CKR_PIN_INCORRECT			(0xa0)
-#define CKR_PIN_INVALID				(0xa1)
-#define CKR_PIN_LEN_RANGE			(0xa2)
-#define CKR_PIN_EXPIRED				(0xa3)
-#define CKR_PIN_LOCKED				(0xa4)
-#define CKR_SESSION_CLOSED			(0xb0)
-#define CKR_SESSION_COUNT			(0xb1)
-#define CKR_SESSION_HANDLE_INVALID		(0xb3)
-#define CKR_SESSION_PARALLEL_NOT_SUPPORTED	(0xb4)
-#define CKR_SESSION_READ_ONLY			(0xb5)
-#define CKR_SESSION_EXISTS			(0xb6)
-#define CKR_SESSION_READ_ONLY_EXISTS		(0xb7)
-#define CKR_SESSION_READ_WRITE_SO_EXISTS	(0xb8)
-#define CKR_SIGNATURE_INVALID			(0xc0)
-#define CKR_SIGNATURE_LEN_RANGE			(0xc1)
-#define CKR_TEMPLATE_INCOMPLETE			(0xd0)
-#define CKR_TEMPLATE_INCONSISTENT		(0xd1)
-#define CKR_TOKEN_NOT_PRESENT			(0xe0)
-#define CKR_TOKEN_NOT_RECOGNIZED		(0xe1)
-#define CKR_TOKEN_WRITE_PROTECTED		(0xe2)
-#define	CKR_UNWRAPPING_KEY_HANDLE_INVALID	(0xf0)
-#define CKR_UNWRAPPING_KEY_SIZE_RANGE		(0xf1)
-#define CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT	(0xf2)
-#define CKR_USER_ALREADY_LOGGED_IN		(0x100)
-#define CKR_USER_NOT_LOGGED_IN			(0x101)
-#define CKR_USER_PIN_NOT_INITIALIZED		(0x102)
-#define CKR_USER_TYPE_INVALID			(0x103)
-#define CKR_USER_ANOTHER_ALREADY_LOGGED_IN	(0x104)
-#define CKR_USER_TOO_MANY_TYPES			(0x105)
-#define CKR_WRAPPED_KEY_INVALID			(0x110)
-#define CKR_WRAPPED_KEY_LEN_RANGE		(0x112)
-#define CKR_WRAPPING_KEY_HANDLE_INVALID		(0x113)
-#define CKR_WRAPPING_KEY_SIZE_RANGE		(0x114)
-#define CKR_WRAPPING_KEY_TYPE_INCONSISTENT	(0x115)
-#define CKR_RANDOM_SEED_NOT_SUPPORTED		(0x120)
-#define CKR_RANDOM_NO_RNG			(0x121)
-#define CKR_DOMAIN_PARAMS_INVALID		(0x130)
-#define CKR_BUFFER_TOO_SMALL			(0x150)
-#define CKR_SAVED_STATE_INVALID			(0x160)
-#define CKR_INFORMATION_SENSITIVE		(0x170)
-#define CKR_STATE_UNSAVEABLE			(0x180)
-#define CKR_CRYPTOKI_NOT_INITIALIZED		(0x190)
-#define CKR_CRYPTOKI_ALREADY_INITIALIZED	(0x191)
-#define CKR_MUTEX_BAD				(0x1a0)
-#define CKR_MUTEX_NOT_LOCKED			(0x1a1)
-#define CKR_FUNCTION_REJECTED			(0x200)
-#define CKR_VENDOR_DEFINED			(1U << 31)
+#define CKF_LIBRARY_CANT_CREATE_OS_THREADS	(1UL << 0)
+#define CKF_OS_LOCKING_OK			(1UL << 1)
 
+#define CKR_OK					(0UL)
+#define CKR_CANCEL				(1UL)
+#define CKR_HOST_MEMORY				(2UL)
+#define CKR_SLOT_ID_INVALID			(3UL)
+#define CKR_GENERAL_ERROR			(5UL)
+#define CKR_FUNCTION_FAILED			(6UL)
+#define CKR_ARGUMENTS_BAD			(7UL)
+#define CKR_NO_EVENT				(8UL)
+#define CKR_NEED_TO_CREATE_THREADS		(9UL)
+#define CKR_CANT_LOCK				(0xaUL)
+#define CKR_ATTRIBUTE_READ_ONLY			(0x10UL)
+#define CKR_ATTRIBUTE_SENSITIVE			(0x11UL)
+#define CKR_ATTRIBUTE_TYPE_INVALID		(0x12UL)
+#define CKR_ATTRIBUTE_VALUE_INVALID		(0x13UL)
+#define CKR_ACTION_PROHIBITED			(0x1BUL)
+#define CKR_DATA_INVALID			(0x20UL)
+#define CKR_DATA_LEN_RANGE			(0x21UL)
+#define CKR_DEVICE_ERROR			(0x30UL)
+#define CKR_DEVICE_MEMORY			(0x31UL)
+#define CKR_DEVICE_REMOVED			(0x32UL)
+#define CKR_ENCRYPTED_DATA_INVALID		(0x40UL)
+#define CKR_ENCRYPTED_DATA_LEN_RANGE		(0x41UL)
+#define CKR_FUNCTION_CANCELED			(0x50UL)
+#define CKR_FUNCTION_NOT_PARALLEL		(0x51UL)
+#define CKR_FUNCTION_NOT_SUPPORTED		(0x54UL)
+#define CKR_KEY_HANDLE_INVALID			(0x60UL)
+#define CKR_KEY_SIZE_RANGE			(0x62UL)
+#define CKR_KEY_TYPE_INCONSISTENT		(0x63UL)
+#define CKR_KEY_NOT_NEEDED			(0x64UL)
+#define CKR_KEY_CHANGED				(0x65UL)
+#define CKR_KEY_NEEDED				(0x66UL)
+#define CKR_KEY_INDIGESTIBLE			(0x67UL)
+#define CKR_KEY_FUNCTION_NOT_PERMITTED		(0x68UL)
+#define CKR_KEY_NOT_WRAPPABLE			(0x69UL)
+#define CKR_KEY_UNEXTRACTABLE			(0x6aUL)
+#define CKR_MECHANISM_INVALID			(0x70UL)
+#define CKR_MECHANISM_PARAM_INVALID		(0x71UL)
+#define CKR_OBJECT_HANDLE_INVALID		(0x82UL)
+#define CKR_OPERATION_ACTIVE			(0x90UL)
+#define CKR_OPERATION_NOT_INITIALIZED		(0x91UL)
+#define CKR_PIN_INCORRECT			(0xa0UL)
+#define CKR_PIN_INVALID				(0xa1UL)
+#define CKR_PIN_LEN_RANGE			(0xa2UL)
+#define CKR_PIN_EXPIRED				(0xa3UL)
+#define CKR_PIN_LOCKED				(0xa4UL)
+#define CKR_SESSION_CLOSED			(0xb0UL)
+#define CKR_SESSION_COUNT			(0xb1UL)
+#define CKR_SESSION_HANDLE_INVALID		(0xb3UL)
+#define CKR_SESSION_PARALLEL_NOT_SUPPORTED	(0xb4UL)
+#define CKR_SESSION_READ_ONLY			(0xb5UL)
+#define CKR_SESSION_EXISTS			(0xb6UL)
+#define CKR_SESSION_READ_ONLY_EXISTS		(0xb7UL)
+#define CKR_SESSION_READ_WRITE_SO_EXISTS	(0xb8UL)
+#define CKR_SIGNATURE_INVALID			(0xc0UL)
+#define CKR_SIGNATURE_LEN_RANGE			(0xc1UL)
+#define CKR_TEMPLATE_INCOMPLETE			(0xd0UL)
+#define CKR_TEMPLATE_INCONSISTENT		(0xd1UL)
+#define CKR_TOKEN_NOT_PRESENT			(0xe0UL)
+#define CKR_TOKEN_NOT_RECOGNIZED		(0xe1UL)
+#define CKR_TOKEN_WRITE_PROTECTED		(0xe2UL)
+#define	CKR_UNWRAPPING_KEY_HANDLE_INVALID	(0xf0UL)
+#define CKR_UNWRAPPING_KEY_SIZE_RANGE		(0xf1UL)
+#define CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT	(0xf2UL)
+#define CKR_USER_ALREADY_LOGGED_IN		(0x100UL)
+#define CKR_USER_NOT_LOGGED_IN			(0x101UL)
+#define CKR_USER_PIN_NOT_INITIALIZED		(0x102UL)
+#define CKR_USER_TYPE_INVALID			(0x103UL)
+#define CKR_USER_ANOTHER_ALREADY_LOGGED_IN	(0x104UL)
+#define CKR_USER_TOO_MANY_TYPES			(0x105UL)
+#define CKR_WRAPPED_KEY_INVALID			(0x110UL)
+#define CKR_WRAPPED_KEY_LEN_RANGE		(0x112UL)
+#define CKR_WRAPPING_KEY_HANDLE_INVALID		(0x113UL)
+#define CKR_WRAPPING_KEY_SIZE_RANGE		(0x114UL)
+#define CKR_WRAPPING_KEY_TYPE_INCONSISTENT	(0x115UL)
+#define CKR_RANDOM_SEED_NOT_SUPPORTED		(0x120UL)
+#define CKR_RANDOM_NO_RNG			(0x121UL)
+#define CKR_DOMAIN_PARAMS_INVALID		(0x130UL)
+#define CKR_CURVE_NOT_SUPPORTED          	(0x140UL)
+#define CKR_BUFFER_TOO_SMALL			(0x150UL)
+#define CKR_SAVED_STATE_INVALID			(0x160UL)
+#define CKR_INFORMATION_SENSITIVE		(0x170UL)
+#define CKR_STATE_UNSAVEABLE			(0x180UL)
+#define CKR_CRYPTOKI_NOT_INITIALIZED		(0x190UL)
+#define CKR_CRYPTOKI_ALREADY_INITIALIZED	(0x191UL)
+#define CKR_MUTEX_BAD				(0x1a0UL)
+#define CKR_MUTEX_NOT_LOCKED			(0x1a1UL)
+#define CKR_FUNCTION_REJECTED			(0x200UL)
+#define CKR_VENDOR_DEFINED			(1UL << 31)
 
 
 /* Compatibility layer.  */
@@ -1216,6 +1729,22 @@ typedef void **CK_VOID_PTR_PTR;
 #endif
 #endif
 
+typedef struct CK_HKDF_PARAMS {
+	CK_BBOOL bExtract;
+	CK_BBOOL bExpand;
+	CK_MECHANISM_TYPE prfHashMechanism;
+	CK_ULONG ulSaltType;
+	CK_BYTE_PTR pSalt;
+	CK_ULONG ulSaltLen;
+	CK_OBJECT_HANDLE hSaltKey;
+	CK_BYTE_PTR pInfo;
+	CK_ULONG ulInfoLen;
+} CK_HKDF_PARAMS;
+
+#define CKF_HKDF_SALT_NULL 0x00000001UL
+#define CKF_HKDF_SALT_DATA 0x00000002UL
+#define CKF_HKDF_SALT_KEY  0x00000004UL
+
 typedef struct ck_version CK_VERSION;
 typedef struct ck_version *CK_VERSION_PTR;
 
@@ -1247,16 +1776,26 @@ typedef struct ck_date *CK_DATE_PTR;
 
 typedef ck_mechanism_type_t *CK_MECHANISM_TYPE_PTR;
 
+typedef ck_rsa_pkcs_mgf_type_t *CK_RSA_PKCS_MGF_TYPE_PTR;
+
 typedef struct ck_mechanism CK_MECHANISM;
 typedef struct ck_mechanism *CK_MECHANISM_PTR;
 
 typedef struct ck_mechanism_info CK_MECHANISM_INFO;
 typedef struct ck_mechanism_info *CK_MECHANISM_INFO_PTR;
 
+typedef struct ck_interface CK_INTERFACE;
+typedef struct ck_interface *CK_INTERFACE_PTR;
+typedef struct ck_interface **CK_INTERFACE_PTR_PTR;
+
 typedef struct ck_function_list CK_FUNCTION_LIST;
 typedef struct ck_function_list *CK_FUNCTION_LIST_PTR;
 typedef struct ck_function_list **CK_FUNCTION_LIST_PTR_PTR;
 
+typedef struct ck_function_list_3_0 CK_FUNCTION_LIST_3_0;
+typedef struct ck_function_list_3_0 *CK_FUNCTION_LIST_3_0_PTR;
+typedef struct ck_function_list_3_0 **CK_FUNCTION_LIST_3_0_PTR_PTR;
+
 typedef struct ck_c_initialize_args CK_C_INITIALIZE_ARGS;
 typedef struct ck_c_initialize_args *CK_C_INITIALIZE_ARGS_PTR;
 
@@ -1317,6 +1856,8 @@ typedef struct ck_c_initialize_args *CK_C_INITIALIZE_ARGS_PTR;
 
 #undef ck_mechanism_type_t
 
+#undef ck_rsa_pkcs_mgf_type_t
+
 #undef ck_mechanism
 #undef parameter
 #undef parameter_len
@@ -1328,7 +1869,10 @@ typedef struct ck_c_initialize_args *CK_C_INITIALIZE_ARGS_PTR;
 #undef ck_rv_t
 #undef ck_notify_t
 
+#undef ck_interface
+
 #undef ck_function_list
+#undef ck_function_list_3_0
 
 #undef ck_createmutex_t
 #undef ck_destroymutex_t
@@ -1344,7 +1888,6 @@ typedef struct ck_c_initialize_args *CK_C_INITIALIZE_ARGS_PTR;
 
 #endif	/* CRYPTOKI_COMPAT */
 
-
 /* System dependencies.  */
 #if defined(_WIN32) || defined(CRYPTOKI_FORCE_WIN32)
 #pragma pack(pop, cryptoki)