[openssh-commits] [openssh] 01/11: upstream: begin big refactor of sshkey

git+noreply at mindrot.org git+noreply at mindrot.org
Fri Oct 28 12:47:26 AEDT 2022


This is an automated email from the git hooks/post-receive script.

djm pushed a commit to branch master
in repository openssh.

commit 25de1c01a8b9a2c8ab9b1da22444a03e89c982de
Author: djm at openbsd.org <djm at openbsd.org>
Date:   Fri Oct 28 00:35:40 2022 +0000

    upstream: begin big refactor of sshkey
    
    Move keytype data and some of the type-specific code (allocation,
    cleanup, etc) out into each key type's implementation. Subsequent
    commits will move more, with the goal of having each key-*.c file
    owning as much of its keytype's implementation as possible.
    
    lots of feedback + ok markus@
    
    OpenBSD-Commit-ID: 0f2b4334f73914344e9e5b3d33522d41762a57ec
---
 ssh-dss.c        |  58 +++++++-
 ssh-ecdsa-sk.c   |  54 ++++++-
 ssh-ecdsa.c      | 106 +++++++++++++-
 ssh-ed25519-sk.c |  44 +++++-
 ssh-ed25519.c    |  41 +++++-
 ssh-rsa.c        | 108 +++++++++++++-
 ssh-xmss.c       |  46 +++++-
 sshkey.c         | 439 ++++++++++++++++++++++---------------------------------
 sshkey.h         |  20 ++-
 9 files changed, 642 insertions(+), 274 deletions(-)

diff --git a/ssh-dss.c b/ssh-dss.c
index fddc29cc..2206bbe6 100644
--- a/ssh-dss.c
+++ b/ssh-dss.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ssh-dss.c,v 1.39 2020/02/26 13:40:09 jsg Exp $ */
+/* $OpenBSD: ssh-dss.c,v 1.40 2022/10/28 00:35:40 djm Exp $ */
 /*
  * Copyright (c) 2000 Markus Friedl.  All rights reserved.
  *
@@ -48,6 +48,32 @@
 #define INTBLOB_LEN	20
 #define SIGBLOB_LEN	(2*INTBLOB_LEN)
 
+static u_int
+ssh_dss_size(const struct sshkey *key)
+{
+	const BIGNUM *dsa_p;
+
+	if (key->dsa == NULL)
+		return 0;
+	DSA_get0_pqg(key->dsa, &dsa_p, NULL, NULL);
+	return BN_num_bits(dsa_p);
+}
+
+static int
+ssh_dss_alloc(struct sshkey *k)
+{
+	if ((k->dsa = DSA_new()) == NULL)
+		return SSH_ERR_ALLOC_FAIL;
+	return 0;
+}
+
+static void
+ssh_dss_cleanup(struct sshkey *k)
+{
+	DSA_free(k->dsa);
+	k->dsa = NULL;
+}
+
 int
 ssh_dss_sign(const struct sshkey *key, u_char **sigp, size_t *lenp,
     const u_char *data, size_t datalen, u_int compat)
@@ -204,4 +230,34 @@ ssh_dss_verify(const struct sshkey *key,
 		freezero(sigblob, len);
 	return ret;
 }
+
+static const struct sshkey_impl_funcs sshkey_dss_funcs = {
+	/* .size = */		ssh_dss_size,
+	/* .alloc = */		ssh_dss_alloc,
+	/* .cleanup = */	ssh_dss_cleanup,
+};
+
+const struct sshkey_impl sshkey_dss_impl = {
+	/* .name = */		"ssh-dss",
+	/* .shortname = */	"DSA",
+	/* .sigalg = */		NULL,
+	/* .type = */		KEY_DSA,
+	/* .nid = */		0,
+	/* .cert = */		0,
+	/* .sigonly = */	0,
+	/* .keybits = */	0,
+	/* .funcs = */		&sshkey_dss_funcs,
+};
+
+const struct sshkey_impl sshkey_dsa_cert_impl = {
+	/* .name = */		"ssh-dss-cert-v01 at openssh.com",
+	/* .shortname = */	"DSA-CERT",
+	/* .sigalg = */		NULL,
+	/* .type = */		KEY_DSA_CERT,
+	/* .nid = */		0,
+	/* .cert = */		1,
+	/* .sigonly = */	0,
+	/* .keybits = */	0,
+	/* .funcs = */		&sshkey_dss_funcs,
+};
 #endif /* WITH_OPENSSL */
diff --git a/ssh-ecdsa-sk.c b/ssh-ecdsa-sk.c
index c6927ecb..2f0984f4 100644
--- a/ssh-ecdsa-sk.c
+++ b/ssh-ecdsa-sk.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ssh-ecdsa-sk.c,v 1.8 2020/06/22 23:44:27 djm Exp $ */
+/* $OpenBSD: ssh-ecdsa-sk.c,v 1.9 2022/10/28 00:35:40 djm Exp $ */
 /*
  * Copyright (c) 2000 Markus Friedl.  All rights reserved.
  * Copyright (c) 2010 Damien Miller.  All rights reserved.
@@ -61,6 +61,16 @@ ssh_ecdsa_sk_verify(const struct sshkey *key,
 }
 #else /* OPENSSL_HAS_ECC */
 
+static void
+ssh_ecdsa_sk_cleanup(struct sshkey *k)
+{
+	free(k->sk_application);
+	sshbuf_free(k->sk_key_handle);
+	sshbuf_free(k->sk_reserved);
+	EC_KEY_free(k->ecdsa);
+	k->ecdsa = NULL;
+}
+
 /*
  * Check FIDO/W3C webauthn signatures clientData field against the expected
  * format and prepare a hash of it for use in signature verification.
@@ -321,4 +331,46 @@ ssh_ecdsa_sk_verify(const struct sshkey *key,
 	return ret;
 }
 
+static const struct sshkey_impl_funcs sshkey_ecdsa_sk_funcs = {
+	/* .size = */		NULL,
+	/* .alloc = */		NULL,
+	/* .cleanup = */	ssh_ecdsa_sk_cleanup,
+};
+
+const struct sshkey_impl sshkey_ecdsa_sk_impl = {
+	/* .name = */		"sk-ecdsa-sha2-nistp256 at openssh.com",
+	/* .shortname = */	"ECDSA-SK",
+	/* .sigalg = */		NULL,
+	/* .type = */		KEY_ECDSA_SK,
+	/* .nid = */		NID_X9_62_prime256v1,
+	/* .cert = */		0,
+	/* .sigonly = */	0,
+	/* .keybits = */	256,
+	/* .funcs = */		&sshkey_ecdsa_sk_funcs,
+};
+
+const struct sshkey_impl sshkey_ecdsa_sk_cert_impl = {
+	/* .name = */		"sk-ecdsa-sha2-nistp256-cert-v01 at openssh.com",
+	/* .shortname = */	"ECDSA-SK-CERT",
+	/* .sigalg = */		NULL,
+	/* .type = */		KEY_ECDSA_SK_CERT,
+	/* .nid = */		NID_X9_62_prime256v1,
+	/* .cert = */		1,
+	/* .sigonly = */	0,
+	/* .keybits = */	256,
+	/* .funcs = */		&sshkey_ecdsa_sk_funcs,
+};
+
+const struct sshkey_impl sshkey_ecdsa_sk_webauthn_impl = {
+	/* .name = */		"webauthn-sk-ecdsa-sha2-nistp256 at openssh.com",
+	/* .shortname = */	"ECDSA-SK",
+	/* .sigalg = */		NULL,
+	/* .type = */		KEY_ECDSA_SK,
+	/* .nid = */		NID_X9_62_prime256v1,
+	/* .cert = */		0,
+	/* .sigonly = */	1,
+	/* .keybits = */	256,
+	/* .funcs = */		&sshkey_ecdsa_sk_funcs,
+};
+
 #endif /* OPENSSL_HAS_ECC */
diff --git a/ssh-ecdsa.c b/ssh-ecdsa.c
index 599c7199..e207e43f 100644
--- a/ssh-ecdsa.c
+++ b/ssh-ecdsa.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ssh-ecdsa.c,v 1.16 2019/01/21 09:54:11 djm Exp $ */
+/* $OpenBSD: ssh-ecdsa.c,v 1.17 2022/10/28 00:35:40 djm Exp $ */
 /*
  * Copyright (c) 2000 Markus Friedl.  All rights reserved.
  * Copyright (c) 2010 Damien Miller.  All rights reserved.
@@ -45,6 +45,30 @@
 
 #include "openbsd-compat/openssl-compat.h"
 
+static u_int
+ssh_ecdsa_size(const struct sshkey *key)
+{
+	switch (key->ecdsa_nid) {
+	case NID_X9_62_prime256v1:
+		return 256;
+	case NID_secp384r1:
+		return 384;
+#ifdef OPENSSL_HAS_NISTP521
+	case NID_secp521r1:
+		return 521;
+#endif
+	default:
+		return 0;
+	}
+}
+
+static void
+ssh_ecdsa_cleanup(struct sshkey *k)
+{
+	EC_KEY_free(k->ecdsa);
+	k->ecdsa = NULL;
+}
+
 /* ARGSUSED */
 int
 ssh_ecdsa_sign(const struct sshkey *key, u_char **sigp, size_t *lenp,
@@ -197,4 +221,84 @@ ssh_ecdsa_verify(const struct sshkey *key,
 	return ret;
 }
 
+static const struct sshkey_impl_funcs sshkey_ecdsa_funcs = {
+	/* .size = */		ssh_ecdsa_size,
+	/* .alloc = */		NULL,
+	/* .cleanup = */	ssh_ecdsa_cleanup,
+};
+
+const struct sshkey_impl sshkey_ecdsa_nistp256_impl = {
+	/* .name = */		"ecdsa-sha2-nistp256",
+	/* .shortname = */	"ECDSA",
+	/* .sigalg = */		NULL,
+	/* .type = */		KEY_ECDSA,
+	/* .nid = */		NID_X9_62_prime256v1,
+	/* .cert = */		0,
+	/* .sigonly = */	0,
+	/* .keybits = */	0,
+	/* .funcs = */		&sshkey_ecdsa_funcs,
+};
+
+const struct sshkey_impl sshkey_ecdsa_nistp256_cert_impl = {
+	/* .name = */		"ecdsa-sha2-nistp256-cert-v01 at openssh.com",
+	/* .shortname = */	"ECDSA-CERT",
+	/* .sigalg = */		NULL,
+	/* .type = */		KEY_ECDSA_CERT,
+	/* .nid = */		NID_X9_62_prime256v1,
+	/* .cert = */		1,
+	/* .sigonly = */	0,
+	/* .keybits = */	0,
+	/* .funcs = */		&sshkey_ecdsa_funcs,
+};
+
+const struct sshkey_impl sshkey_ecdsa_nistp384_impl = {
+	/* .name = */		"ecdsa-sha2-nistp384",
+	/* .shortname = */	"ECDSA",
+	/* .sigalg = */		NULL,
+	/* .type = */		KEY_ECDSA,
+	/* .nid = */		NID_secp384r1,
+	/* .cert = */		0,
+	/* .sigonly = */	0,
+	/* .keybits = */	0,
+	/* .funcs = */		&sshkey_ecdsa_funcs,
+};
+
+const struct sshkey_impl sshkey_ecdsa_nistp384_cert_impl = {
+	/* .name = */		"ecdsa-sha2-nistp384-cert-v01 at openssh.com",
+	/* .shortname = */	"ECDSA-CERT",
+	/* .sigalg = */		NULL,
+	/* .type = */		KEY_ECDSA_CERT,
+	/* .nid = */		NID_secp384r1,
+	/* .cert = */		1,
+	/* .sigonly = */	0,
+	/* .keybits = */	0,
+	/* .funcs = */		&sshkey_ecdsa_funcs,
+};
+
+#ifdef OPENSSL_HAS_NISTP521
+const struct sshkey_impl sshkey_ecdsa_nistp521_impl = {
+	/* .name = */		"ecdsa-sha2-nistp521",
+	/* .shortname = */	"ECDSA",
+	/* .sigalg = */		NULL,
+	/* .type = */		KEY_ECDSA,
+	/* .nid = */		NID_secp521r1,
+	/* .cert = */		0,
+	/* .sigonly = */	0,
+	/* .keybits = */	0,
+	/* .funcs = */		&sshkey_ecdsa_funcs,
+};
+
+const struct sshkey_impl sshkey_ecdsa_nistp521_cert_impl = {
+	/* .name = */		"ecdsa-sha2-nistp521-cert-v01 at openssh.com",
+	/* .shortname = */	"ECDSA-CERT",
+	/* .sigalg = */		NULL,
+	/* .type = */		KEY_ECDSA_CERT,
+	/* .nid = */		NID_secp521r1,
+	/* .cert = */		1,
+	/* .sigonly = */	0,
+	/* .keybits = */	0,
+	/* .funcs = */		&sshkey_ecdsa_funcs,
+};
+#endif
+
 #endif /* WITH_OPENSSL && OPENSSL_HAS_ECC */
diff --git a/ssh-ed25519-sk.c b/ssh-ed25519-sk.c
index 4393ca66..1c21d4bf 100644
--- a/ssh-ed25519-sk.c
+++ b/ssh-ed25519-sk.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ssh-ed25519-sk.c,v 1.6 2020/10/18 11:32:02 djm Exp $ */
+/* $OpenBSD: ssh-ed25519-sk.c,v 1.7 2022/10/28 00:35:40 djm Exp $ */
 /*
  * Copyright (c) 2019 Markus Friedl.  All rights reserved.
  *
@@ -35,6 +35,18 @@
 #include "ssh.h"
 #include "digest.h"
 
+static void
+ssh_ed25519_sk_cleanup(struct sshkey *k)
+{
+	free(k->sk_application);
+	sshbuf_free(k->sk_key_handle);
+	sshbuf_free(k->sk_reserved);
+	freezero(k->ed25519_pk, ED25519_PK_SZ);
+	freezero(k->ed25519_sk, ED25519_SK_SZ);
+	k->ed25519_pk = NULL;
+	k->ed25519_sk = NULL;
+}
+
 int
 ssh_ed25519_sk_verify(const struct sshkey *key,
     const u_char *signature, size_t signaturelen,
@@ -161,3 +173,33 @@ ssh_ed25519_sk_verify(const struct sshkey *key,
 	free(ktype);
 	return r;
 }
+
+static const struct sshkey_impl_funcs sshkey_ed25519_sk_funcs = {
+	/* .size = */		NULL,
+	/* .alloc = */		NULL,
+	/* .cleanup = */	ssh_ed25519_sk_cleanup,
+};
+
+const struct sshkey_impl sshkey_ed25519_sk_impl = {
+	/* .name = */		"sk-ssh-ed25519 at openssh.com",
+	/* .shortname = */	"ED25519-SK",
+	/* .sigalg = */		NULL,
+	/* .type = */		KEY_ED25519_SK,
+	/* .nid = */		0,
+	/* .cert = */		0,
+	/* .sigonly = */	0,
+	/* .keybits = */	256,
+	/* .funcs = */		&sshkey_ed25519_sk_funcs,
+};
+
+const struct sshkey_impl sshkey_ed25519_sk_cert_impl = {
+	/* .name = */		"sk-ssh-ed25519-cert-v01 at openssh.com",
+	/* .shortname = */	"ED25519-SK-CERT",
+	/* .sigalg = */		NULL,
+	/* .type = */		KEY_ED25519_SK_CERT,
+	/* .nid = */		0,
+	/* .cert = */		1,
+	/* .sigonly = */	0,
+	/* .keybits = */	256,
+	/* .funcs = */		&sshkey_ed25519_sk_funcs,
+};
diff --git a/ssh-ed25519.c b/ssh-ed25519.c
index 4861628c..abd983df 100644
--- a/ssh-ed25519.c
+++ b/ssh-ed25519.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ssh-ed25519.c,v 1.10 2022/08/26 08:12:56 djm Exp $ */
+/* $OpenBSD: ssh-ed25519.c,v 1.11 2022/10/28 00:35:40 djm Exp $ */
 /*
  * Copyright (c) 2013 Markus Friedl <markus at openbsd.org>
  *
@@ -32,6 +32,15 @@
 #include "ssherr.h"
 #include "ssh.h"
 
+static void
+ssh_ed25519_cleanup(struct sshkey *k)
+{
+	freezero(k->ed25519_pk, ED25519_PK_SZ);
+	freezero(k->ed25519_sk, ED25519_SK_SZ);
+	k->ed25519_pk = NULL;
+	k->ed25519_sk = NULL;
+}
+
 int
 ssh_ed25519_sign(const struct sshkey *key, u_char **sigp, size_t *lenp,
     const u_char *data, size_t datalen, u_int compat)
@@ -158,3 +167,33 @@ ssh_ed25519_verify(const struct sshkey *key,
 	free(ktype);
 	return r;
 }
+
+static const struct sshkey_impl_funcs sshkey_ed25519_funcs = {
+	/* .size = */		NULL,
+	/* .alloc = */		NULL,
+	/* .cleanup = */	ssh_ed25519_cleanup,
+};
+
+const struct sshkey_impl sshkey_ed25519_impl = {
+	/* .name = */		"ssh-ed25519",
+	/* .shortname = */	"ED25519",
+	/* .sigalg = */		NULL,
+	/* .type = */		KEY_ED25519,
+	/* .nid = */		0,
+	/* .cert = */		0,
+	/* .sigonly = */	0,
+	/* .keybits = */	256,
+	/* .funcs = */		&sshkey_ed25519_funcs,
+};
+
+const struct sshkey_impl sshkey_ed25519_cert_impl = {
+	/* .name = */		"ssh-ed25519-cert-v01 at openssh.com",
+	/* .shortname = */	"ED25519-CERT",
+	/* .sigalg = */		NULL,
+	/* .type = */		KEY_ED25519_CERT,
+	/* .nid = */		0,
+	/* .cert = */		1,
+	/* .sigonly = */	0,
+	/* .keybits = */	256,
+	/* .funcs = */		&sshkey_ed25519_funcs,
+};
diff --git a/ssh-rsa.c b/ssh-rsa.c
index 9b14f9a9..e7225e82 100644
--- a/ssh-rsa.c
+++ b/ssh-rsa.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ssh-rsa.c,v 1.67 2018/07/03 11:39:54 djm Exp $ */
+/* $OpenBSD: ssh-rsa.c,v 1.69 2022/10/28 00:35:40 djm Exp $ */
 /*
  * Copyright (c) 2000, 2003 Markus Friedl <markus at openbsd.org>
  *
@@ -39,6 +39,32 @@
 
 static int openssh_RSA_verify(int, u_char *, size_t, u_char *, size_t, RSA *);
 
+static u_int
+ssh_rsa_size(const struct sshkey *key)
+{
+	const BIGNUM *rsa_n;
+
+	if (key->rsa == NULL)
+		return 0;
+	RSA_get0_key(key->rsa, &rsa_n, NULL, NULL);
+	return BN_num_bits(rsa_n);
+}
+
+static int
+ssh_rsa_alloc(struct sshkey *k)
+{
+	if ((k->rsa = RSA_new()) == NULL)
+		return SSH_ERR_ALLOC_FAIL;
+	return 0;
+}
+
+static void
+ssh_rsa_cleanup(struct sshkey *k)
+{
+	RSA_free(k->rsa);
+	k->rsa = NULL;
+}
+
 static const char *
 rsa_hash_alg_ident(int hash_alg)
 {
@@ -446,4 +472,84 @@ done:
 	freezero(decrypted, rsasize);
 	return ret;
 }
+
+static const struct sshkey_impl_funcs sshkey_rsa_funcs = {
+	/* .size = */		ssh_rsa_size,
+	/* .alloc = */		ssh_rsa_alloc,
+	/* .cleanup = */	ssh_rsa_cleanup,
+};
+
+const struct sshkey_impl sshkey_rsa_impl = {
+	/* .name = */		"ssh-rsa",
+	/* .shortname = */	"RSA",
+	/* .sigalg = */		NULL,
+	/* .type = */		KEY_RSA,
+	/* .nid = */		0,
+	/* .cert = */		0,
+	/* .sigonly = */	0,
+	/* .keybits = */	0,
+	/* .funcs = */		&sshkey_rsa_funcs,
+};
+
+const struct sshkey_impl sshkey_rsa_cert_impl = {
+	/* .name = */		"ssh-rsa-cert-v01 at openssh.com",
+	/* .shortname = */	"RSA-CERT",
+	/* .sigalg = */		NULL,
+	/* .type = */		KEY_RSA_CERT,
+	/* .nid = */		0,
+	/* .cert = */		1,
+	/* .sigonly = */	0,
+	/* .keybits = */	0,
+	/* .funcs = */		&sshkey_rsa_funcs,
+};
+
+/* SHA2 signature algorithms */
+
+const struct sshkey_impl sshkey_rsa_sha256_impl = {
+	/* .name = */		"rsa-sha2-256",
+	/* .shortname = */	"RSA",
+	/* .sigalg = */		NULL,
+	/* .type = */		KEY_RSA,
+	/* .nid = */		0,
+	/* .cert = */		0,
+	/* .sigonly = */	1,
+	/* .keybits = */	0,
+	/* .funcs = */		&sshkey_rsa_funcs,
+};
+
+const struct sshkey_impl sshkey_rsa_sha512_impl = {
+	/* .name = */		"rsa-sha2-512",
+	/* .shortname = */	"RSA",
+	/* .sigalg = */		NULL,
+	/* .type = */		KEY_RSA,
+	/* .nid = */		0,
+	/* .cert = */		0,
+	/* .sigonly = */	1,
+	/* .keybits = */	0,
+	/* .funcs = */		&sshkey_rsa_funcs,
+};
+
+const struct sshkey_impl sshkey_rsa_sha256_cert_impl = {
+	/* .name = */		"rsa-sha2-256-cert-v01 at openssh.com",
+	/* .shortname = */	"RSA-CERT",
+	/* .sigalg = */		"rsa-sha2-256",
+	/* .type = */		KEY_RSA_CERT,
+	/* .nid = */		0,
+	/* .cert = */		1,
+	/* .sigonly = */	1,
+	/* .keybits = */	0,
+	/* .funcs = */		&sshkey_rsa_funcs,
+};
+
+const struct sshkey_impl sshkey_rsa_sha512_cert_impl = {
+	/* .name = */		"rsa-sha2-512-cert-v01 at openssh.com",
+	/* .shortname = */	"RSA-CERT",
+	/* .sigalg = */		"rsa-sha2-512",
+	/* .type = */		KEY_RSA_CERT,
+	/* .nid = */		0,
+	/* .cert = */		1,
+	/* .sigonly = */	1,
+	/* .keybits = */	0,
+	/* .funcs = */		&sshkey_rsa_funcs,
+};
 #endif /* WITH_OPENSSL */
diff --git a/ssh-xmss.c b/ssh-xmss.c
index 41ede296..2ac9ee05 100644
--- a/ssh-xmss.c
+++ b/ssh-xmss.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ssh-xmss.c,v 1.5 2022/04/20 15:59:18 millert Exp $*/
+/* $OpenBSD: ssh-xmss.c,v 1.6 2022/10/28 00:35:40 djm Exp $*/
 /*
  * Copyright (c) 2017 Stefan-Lukas Gazdag.
  * Copyright (c) 2017 Markus Friedl.
@@ -37,6 +37,20 @@
 
 #include "xmss_fast.h"
 
+static void
+ssh_xmss_cleanup(struct sshkey *k)
+{
+	freezero(k->xmss_pk, sshkey_xmss_pklen(k));
+	freezero(k->xmss_sk, sshkey_xmss_sklen(k));
+	sshkey_xmss_free_state(k);
+	free(k->xmss_name);
+	free(k->xmss_filename);
+	k->xmss_pk = NULL;
+	k->xmss_sk = NULL;
+	k->xmss_name = NULL;
+	k->xmss_filename = NULL;
+}
+
 int
 ssh_xmss_sign(const struct sshkey *key, u_char **sigp, size_t *lenp,
     const u_char *data, size_t datalen, u_int compat)
@@ -184,4 +198,34 @@ ssh_xmss_verify(const struct sshkey *key,
 	free(ktype);
 	return r;
 }
+
+static const struct sshkey_impl_funcs sshkey_xmss_funcs = {
+	/* .size = */		NULL,
+	/* .alloc = */		NULL,
+	/* .cleanup = */	ssh_xmss_cleanup,
+};
+
+const struct sshkey_impl sshkey_xmss_impl = {
+	/* .name = */		"ssh-xmss at openssh.com",
+	/* .shortname = */	"XMSS",
+	/* .sigalg = */		NULL,
+	/* .type = */		KEY_XMSS,
+	/* .nid = */		0,
+	/* .cert = */		0,
+	/* .sigonly = */	0,
+	/* .keybits = */	256,
+	/* .funcs = */		&sshkey_xmss_funcs,
+};
+
+const struct sshkey_impl sshkey_xmss_cert_impl = {
+	/* .name = */		"ssh-xmss-cert-v01 at openssh.com",
+	/* .shortname = */	"XMSS-CERT",
+	/* .sigalg = */		NULL,
+	/* .type = */		KEY_XMSS_CERT,
+	/* .nid = */		0,
+	/* .cert = */		1,
+	/* .sigonly = */	0,
+	/* .keybits = */	256,
+	/* .funcs = */		&sshkey_xmss_funcs,
+};
 #endif /* WITH_XMSS */
diff --git a/sshkey.c b/sshkey.c
index 77093235..1052108b 100644
--- a/sshkey.c
+++ b/sshkey.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: sshkey.c,v 1.122 2022/09/17 10:30:45 djm Exp $ */
+/* $OpenBSD: sshkey.c,v 1.123 2022/10/28 00:35:40 djm Exp $ */
 /*
  * Copyright (c) 2000, 2001 Markus Friedl.  All rights reserved.
  * Copyright (c) 2008 Alexander von Gernler.  All rights reserved.
@@ -94,111 +94,132 @@ static int sshkey_from_blob_internal(struct sshbuf *buf,
     struct sshkey **keyp, int allow_cert);
 
 /* Supported key types */
-struct keytype {
-	const char *name;
-	const char *shortname;
-	const char *sigalg;
-	int type;
-	int nid;
-	int cert;
-	int sigonly;
-};
-static const struct keytype keytypes[] = {
-	{ "ssh-ed25519", "ED25519", NULL, KEY_ED25519, 0, 0, 0 },
-	{ "ssh-ed25519-cert-v01 at openssh.com", "ED25519-CERT", NULL,
-	    KEY_ED25519_CERT, 0, 1, 0 },
+extern const struct sshkey_impl sshkey_ed25519_impl;
+extern const struct sshkey_impl sshkey_ed25519_cert_impl;
+extern const struct sshkey_impl sshkey_ed25519_sk_impl;
+extern const struct sshkey_impl sshkey_ed25519_sk_cert_impl;
+#ifdef WITH_OPENSSL
+# ifdef OPENSSL_HAS_ECC
+#  ifdef ENABLE_SK
+extern const struct sshkey_impl sshkey_ecdsa_sk_impl;
+extern const struct sshkey_impl sshkey_ecdsa_sk_cert_impl;
+extern const struct sshkey_impl sshkey_ecdsa_sk_webauthn_impl;
+#  endif /* ENABLE_SK */
+extern const struct sshkey_impl sshkey_ecdsa_nistp256_impl;
+extern const struct sshkey_impl sshkey_ecdsa_nistp256_cert_impl;
+extern const struct sshkey_impl sshkey_ecdsa_nistp384_impl;
+extern const struct sshkey_impl sshkey_ecdsa_nistp384_cert_impl;
+#  ifdef OPENSSL_HAS_NISTP521
+extern const struct sshkey_impl sshkey_ecdsa_nistp521_impl;
+extern const struct sshkey_impl sshkey_ecdsa_nistp521_cert_impl;
+#  endif /* OPENSSL_HAS_NISTP521 */
+# endif /* OPENSSL_HAS_ECC */
+extern const struct sshkey_impl sshkey_rsa_impl;
+extern const struct sshkey_impl sshkey_rsa_cert_impl;
+extern const struct sshkey_impl sshkey_rsa_sha256_impl;
+extern const struct sshkey_impl sshkey_rsa_sha256_cert_impl;
+extern const struct sshkey_impl sshkey_rsa_sha512_impl;
+extern const struct sshkey_impl sshkey_rsa_sha512_cert_impl;
+extern const struct sshkey_impl sshkey_dss_impl;
+extern const struct sshkey_impl sshkey_dsa_cert_impl;
+#endif /* WITH_OPENSSL */
+#ifdef WITH_XMSS
+extern const struct sshkey_impl sshkey_xmss_impl;
+extern const struct sshkey_impl sshkey_xmss_cert_impl;
+#endif
+
+const struct sshkey_impl * const keyimpls[] = {
+	&sshkey_ed25519_impl,
+	&sshkey_ed25519_cert_impl,
 #ifdef ENABLE_SK
-	{ "sk-ssh-ed25519 at openssh.com", "ED25519-SK", NULL,
-	    KEY_ED25519_SK, 0, 0, 0 },
-	{ "sk-ssh-ed25519-cert-v01 at openssh.com", "ED25519-SK-CERT", NULL,
-	    KEY_ED25519_SK_CERT, 0, 1, 0 },
+	&sshkey_ed25519_sk_impl,
+	&sshkey_ed25519_sk_cert_impl,
 #endif
-#ifdef WITH_XMSS
-	{ "ssh-xmss at openssh.com", "XMSS", NULL, KEY_XMSS, 0, 0, 0 },
-	{ "ssh-xmss-cert-v01 at openssh.com", "XMSS-CERT", NULL,
-	    KEY_XMSS_CERT, 0, 1, 0 },
-#endif /* WITH_XMSS */
 #ifdef WITH_OPENSSL
-	{ "ssh-rsa", "RSA", NULL, KEY_RSA, 0, 0, 0 },
-	{ "rsa-sha2-256", "RSA", NULL, KEY_RSA, 0, 0, 1 },
-	{ "rsa-sha2-512", "RSA", NULL, KEY_RSA, 0, 0, 1 },
-	{ "ssh-dss", "DSA", NULL, KEY_DSA, 0, 0, 0 },
 # ifdef OPENSSL_HAS_ECC
-	{ "ecdsa-sha2-nistp256", "ECDSA", NULL,
-	    KEY_ECDSA, NID_X9_62_prime256v1, 0, 0 },
-	{ "ecdsa-sha2-nistp384", "ECDSA", NULL,
-	    KEY_ECDSA, NID_secp384r1, 0, 0 },
+	&sshkey_ecdsa_nistp256_impl,
+	&sshkey_ecdsa_nistp256_cert_impl,
+	&sshkey_ecdsa_nistp384_impl,
+	&sshkey_ecdsa_nistp384_cert_impl,
 #  ifdef OPENSSL_HAS_NISTP521
-	{ "ecdsa-sha2-nistp521", "ECDSA", NULL,
-	    KEY_ECDSA, NID_secp521r1, 0, 0 },
+	&sshkey_ecdsa_nistp521_impl,
+	&sshkey_ecdsa_nistp521_cert_impl,
 #  endif /* OPENSSL_HAS_NISTP521 */
 #  ifdef ENABLE_SK
-	{ "sk-ecdsa-sha2-nistp256 at openssh.com", "ECDSA-SK", NULL,
-	    KEY_ECDSA_SK, NID_X9_62_prime256v1, 0, 0 },
-	{ "webauthn-sk-ecdsa-sha2-nistp256 at openssh.com", "ECDSA-SK", NULL,
-	    KEY_ECDSA_SK, NID_X9_62_prime256v1, 0, 1 },
-#  endif /* ENABLE_SK */
-# endif /* OPENSSL_HAS_ECC */
-	{ "ssh-rsa-cert-v01 at openssh.com", "RSA-CERT", NULL,
-	    KEY_RSA_CERT, 0, 1, 0 },
-	{ "rsa-sha2-256-cert-v01 at openssh.com", "RSA-CERT",
-	    "rsa-sha2-256", KEY_RSA_CERT, 0, 1, 1 },
-	{ "rsa-sha2-512-cert-v01 at openssh.com", "RSA-CERT",
-	    "rsa-sha2-512", KEY_RSA_CERT, 0, 1, 1 },
-	{ "ssh-dss-cert-v01 at openssh.com", "DSA-CERT", NULL,
-	    KEY_DSA_CERT, 0, 1, 0 },
-# ifdef OPENSSL_HAS_ECC
-	{ "ecdsa-sha2-nistp256-cert-v01 at openssh.com", "ECDSA-CERT", NULL,
-	    KEY_ECDSA_CERT, NID_X9_62_prime256v1, 1, 0 },
-	{ "ecdsa-sha2-nistp384-cert-v01 at openssh.com", "ECDSA-CERT", NULL,
-	    KEY_ECDSA_CERT, NID_secp384r1, 1, 0 },
-#  ifdef OPENSSL_HAS_NISTP521
-	{ "ecdsa-sha2-nistp521-cert-v01 at openssh.com", "ECDSA-CERT", NULL,
-	    KEY_ECDSA_CERT, NID_secp521r1, 1, 0 },
-#  endif /* OPENSSL_HAS_NISTP521 */
-#  ifdef ENABLE_SK
-	{ "sk-ecdsa-sha2-nistp256-cert-v01 at openssh.com", "ECDSA-SK-CERT", NULL,
-	    KEY_ECDSA_SK_CERT, NID_X9_62_prime256v1, 1, 0 },
+	&sshkey_ecdsa_sk_impl,
+	&sshkey_ecdsa_sk_cert_impl,
+	&sshkey_ecdsa_sk_webauthn_impl,
 #  endif /* ENABLE_SK */
 # endif /* OPENSSL_HAS_ECC */
+	&sshkey_dss_impl,
+	&sshkey_dsa_cert_impl,
+	&sshkey_rsa_impl,
+	&sshkey_rsa_cert_impl,
+	&sshkey_rsa_sha256_impl,
+	&sshkey_rsa_sha256_cert_impl,
+	&sshkey_rsa_sha512_impl,
+	&sshkey_rsa_sha512_cert_impl,
 #endif /* WITH_OPENSSL */
-	{ NULL, NULL, NULL, -1, -1, 0, 0 }
+#ifdef WITH_XMSS
+	&sshkey_xmss_impl,
+	&sshkey_xmss_cert_impl,
+#endif
+	NULL
 };
 
+static const struct sshkey_impl *
+sshkey_impl_from_type(int type)
+{
+	int i;
+
+	for (i = 0; keyimpls[i] != NULL; i++) {
+		if (keyimpls[i]->type == type)
+			return keyimpls[i];
+	}
+	return NULL;
+}
+
+static const struct sshkey_impl *
+sshkey_impl_from_type_nid(int type, int nid)
+{
+	int i;
+
+	for (i = 0; keyimpls[i] != NULL; i++) {
+		if (keyimpls[i]->type == type &&
+		    (keyimpls[i]->nid == 0 || keyimpls[i]->nid == nid))
+			return keyimpls[i];
+	}
+	return NULL;
+}
+
 const char *
 sshkey_type(const struct sshkey *k)
 {
-	const struct keytype *kt;
+	const struct sshkey_impl *impl;
 
-	for (kt = keytypes; kt->type != -1; kt++) {
-		if (kt->type == k->type)
-			return kt->shortname;
-	}
-	return "unknown";
+	if ((impl = sshkey_impl_from_type(k->type)) == NULL)
+		return "unknown";
+	return impl->shortname;
 }
 
 static const char *
 sshkey_ssh_name_from_type_nid(int type, int nid)
 {
-	const struct keytype *kt;
+	const struct sshkey_impl *impl;
 
-	for (kt = keytypes; kt->type != -1; kt++) {
-		if (kt->type == type && (kt->nid == 0 || kt->nid == nid))
-			return kt->name;
-	}
-	return "ssh-unknown";
+	if ((impl = sshkey_impl_from_type_nid(type, nid)) == NULL)
+		return "ssh-unknown";
+	return impl->name;
 }
 
 int
 sshkey_type_is_cert(int type)
 {
-	const struct keytype *kt;
+	const struct sshkey_impl *impl;
 
-	for (kt = keytypes; kt->type != -1; kt++) {
-		if (kt->type == type)
-			return kt->cert;
-	}
-	return 0;
+	if ((impl = sshkey_impl_from_type(type)) == NULL)
+		return 0;
+	return impl->cert;
 }
 
 const char *
@@ -217,13 +238,15 @@ sshkey_ssh_name_plain(const struct sshkey *k)
 int
 sshkey_type_from_name(const char *name)
 {
-	const struct keytype *kt;
+	int i;
+	const struct sshkey_impl *impl;
 
-	for (kt = keytypes; kt->type != -1; kt++) {
+	for (i = 0; keyimpls[i] != NULL; i++) {
+		impl = keyimpls[i];
 		/* Only allow shortname matches for plain key types */
-		if ((kt->name != NULL && strcmp(name, kt->name) == 0) ||
-		    (!kt->cert && strcasecmp(kt->shortname, name) == 0))
-			return kt->type;
+		if ((impl->name != NULL && strcmp(name, impl->name) == 0) ||
+		    (!impl->cert && strcasecmp(impl->shortname, name) == 0))
+			return impl->type;
 	}
 	return KEY_UNSPEC;
 }
@@ -244,13 +267,14 @@ key_type_is_ecdsa_variant(int type)
 int
 sshkey_ecdsa_nid_from_name(const char *name)
 {
-	const struct keytype *kt;
+	int i;
 
-	for (kt = keytypes; kt->type != -1; kt++) {
-		if (!key_type_is_ecdsa_variant(kt->type))
+	for (i = 0; keyimpls[i] != NULL; i++) {
+		if (!key_type_is_ecdsa_variant(keyimpls[i]->type))
 			continue;
-		if (kt->name != NULL && strcmp(name, kt->name) == 0)
-			return kt->nid;
+		if (keyimpls[i]->name != NULL &&
+		    strcmp(name, keyimpls[i]->name) == 0)
+			return keyimpls[i]->nid;
 	}
 	return -1;
 }
@@ -282,25 +306,26 @@ char *
 sshkey_alg_list(int certs_only, int plain_only, int include_sigonly, char sep)
 {
 	char *tmp, *ret = NULL;
-	size_t nlen, rlen = 0;
-	const struct keytype *kt;
+	size_t i, nlen, rlen = 0;
+	const struct sshkey_impl *impl;
 
-	for (kt = keytypes; kt->type != -1; kt++) {
-		if (kt->name == NULL)
+	for (i = 0; keyimpls[i] != NULL; i++) {
+		impl = keyimpls[i];
+		if (impl->name == NULL)
 			continue;
-		if (!include_sigonly && kt->sigonly)
+		if (!include_sigonly && impl->sigonly)
 			continue;
-		if ((certs_only && !kt->cert) || (plain_only && kt->cert))
+		if ((certs_only && !impl->cert) || (plain_only && impl->cert))
 			continue;
 		if (ret != NULL)
 			ret[rlen++] = sep;
-		nlen = strlen(kt->name);
+		nlen = strlen(impl->name);
 		if ((tmp = realloc(ret, rlen + nlen + 2)) == NULL) {
 			free(ret);
 			return NULL;
 		}
 		ret = tmp;
-		memcpy(ret + rlen, kt->name, nlen + 1);
+		memcpy(ret + rlen, impl->name, nlen + 1);
 		rlen += nlen;
 	}
 	return ret;
@@ -310,8 +335,8 @@ int
 sshkey_names_valid2(const char *names, int allow_wildcard)
 {
 	char *s, *cp, *p;
-	const struct keytype *kt;
-	int type;
+	const struct sshkey_impl *impl;
+	int i, type;
 
 	if (names == NULL || strcmp(names, "") == 0)
 		return 0;
@@ -327,12 +352,15 @@ sshkey_names_valid2(const char *names, int allow_wildcard)
 				 * If any has a positive or negative match then
 				 * the component is accepted.
 				 */
-				for (kt = keytypes; kt->type != -1; kt++) {
-					if (match_pattern_list(kt->name,
-					    p, 0) != 0)
+				impl = NULL;
+				for (i = 0; keyimpls[i] != NULL; i++) {
+					if (match_pattern_list(
+					    keyimpls[i]->name, p, 0) != 0) {
+						impl = keyimpls[i];
 						break;
+					}
 				}
-				if (kt->type != -1)
+				if (impl != NULL)
 					continue;
 			}
 			free(s);
@@ -346,56 +374,24 @@ sshkey_names_valid2(const char *names, int allow_wildcard)
 u_int
 sshkey_size(const struct sshkey *k)
 {
-#ifdef WITH_OPENSSL
-	const BIGNUM *rsa_n, *dsa_p;
-#endif /* WITH_OPENSSL */
+	const struct sshkey_impl *impl;
 
-	switch (k->type) {
-#ifdef WITH_OPENSSL
-	case KEY_RSA:
-	case KEY_RSA_CERT:
-		if (k->rsa == NULL)
-			return 0;
-		RSA_get0_key(k->rsa, &rsa_n, NULL, NULL);
-		return BN_num_bits(rsa_n);
-	case KEY_DSA:
-	case KEY_DSA_CERT:
-		if (k->dsa == NULL)
-			return 0;
-		DSA_get0_pqg(k->dsa, &dsa_p, NULL, NULL);
-		return BN_num_bits(dsa_p);
-	case KEY_ECDSA:
-	case KEY_ECDSA_CERT:
-	case KEY_ECDSA_SK:
-	case KEY_ECDSA_SK_CERT:
-		return sshkey_curve_nid_to_bits(k->ecdsa_nid);
-#endif /* WITH_OPENSSL */
-	case KEY_ED25519:
-	case KEY_ED25519_CERT:
-	case KEY_ED25519_SK:
-	case KEY_ED25519_SK_CERT:
-	case KEY_XMSS:
-	case KEY_XMSS_CERT:
-		return 256;	/* XXX */
-	}
-	return 0;
+	if ((impl = sshkey_impl_from_type_nid(k->type, k->ecdsa_nid)) == NULL)
+		return 0;
+	if (impl->funcs->size != NULL)
+		return impl->funcs->size(k);
+	return impl->keybits;
 }
 
 static int
 sshkey_type_is_valid_ca(int type)
 {
-	switch (type) {
-	case KEY_RSA:
-	case KEY_DSA:
-	case KEY_ECDSA:
-	case KEY_ECDSA_SK:
-	case KEY_ED25519:
-	case KEY_ED25519_SK:
-	case KEY_XMSS:
-		return 1;
-	default:
+	const struct sshkey_impl *impl;
+
+	if ((impl = sshkey_impl_from_type(type)) == NULL)
 		return 0;
-	}
+	/* All non-certificate types may act as CAs */
+	return !impl->cert;
 }
 
 int
@@ -573,63 +569,23 @@ struct sshkey *
 sshkey_new(int type)
 {
 	struct sshkey *k;
-#ifdef WITH_OPENSSL
-	RSA *rsa;
-	DSA *dsa;
-#endif /* WITH_OPENSSL */
+	const struct sshkey_impl *impl = NULL;
 
+	if (type != KEY_UNSPEC &&
+	    (impl = sshkey_impl_from_type(type)) == NULL)
+		return NULL;
+
+	/* All non-certificate types may act as CAs */
 	if ((k = calloc(1, sizeof(*k))) == NULL)
 		return NULL;
 	k->type = type;
-	k->ecdsa = NULL;
 	k->ecdsa_nid = -1;
-	k->dsa = NULL;
-	k->rsa = NULL;
-	k->cert = NULL;
-	k->ed25519_sk = NULL;
-	k->ed25519_pk = NULL;
-	k->xmss_sk = NULL;
-	k->xmss_pk = NULL;
-	switch (k->type) {
-#ifdef WITH_OPENSSL
-	case KEY_RSA:
-	case KEY_RSA_CERT:
-		if ((rsa = RSA_new()) == NULL) {
+	if (impl != NULL && impl->funcs->alloc != NULL) {
+		if (impl->funcs->alloc(k) != 0) {
 			free(k);
 			return NULL;
 		}
-		k->rsa = rsa;
-		break;
-	case KEY_DSA:
-	case KEY_DSA_CERT:
-		if ((dsa = DSA_new()) == NULL) {
-			free(k);
-			return NULL;
-		}
-		k->dsa = dsa;
-		break;
-	case KEY_ECDSA:
-	case KEY_ECDSA_CERT:
-	case KEY_ECDSA_SK:
-	case KEY_ECDSA_SK_CERT:
-		/* Cannot do anything until we know the group */
-		break;
-#endif /* WITH_OPENSSL */
-	case KEY_ED25519:
-	case KEY_ED25519_CERT:
-	case KEY_ED25519_SK:
-	case KEY_ED25519_SK_CERT:
-	case KEY_XMSS:
-	case KEY_XMSS_CERT:
-		/* no need to prealloc */
-		break;
-	case KEY_UNSPEC:
-		break;
-	default:
-		free(k);
-		return NULL;
 	}
-
 	if (sshkey_is_cert(k)) {
 		if ((k->cert = cert_new()) == NULL) {
 			sshkey_free(k);
@@ -643,66 +599,13 @@ sshkey_new(int type)
 void
 sshkey_free(struct sshkey *k)
 {
+	const struct sshkey_impl *impl;
+
 	if (k == NULL)
 		return;
-	switch (k->type) {
-#ifdef WITH_OPENSSL
-	case KEY_RSA:
-	case KEY_RSA_CERT:
-		RSA_free(k->rsa);
-		k->rsa = NULL;
-		break;
-	case KEY_DSA:
-	case KEY_DSA_CERT:
-		DSA_free(k->dsa);
-		k->dsa = NULL;
-		break;
-# ifdef OPENSSL_HAS_ECC
-	case KEY_ECDSA_SK:
-	case KEY_ECDSA_SK_CERT:
-		free(k->sk_application);
-		sshbuf_free(k->sk_key_handle);
-		sshbuf_free(k->sk_reserved);
-		/* FALLTHROUGH */
-	case KEY_ECDSA:
-	case KEY_ECDSA_CERT:
-		EC_KEY_free(k->ecdsa);
-		k->ecdsa = NULL;
-		break;
-# endif /* OPENSSL_HAS_ECC */
-#endif /* WITH_OPENSSL */
-	case KEY_ED25519_SK:
-	case KEY_ED25519_SK_CERT:
-		free(k->sk_application);
-		sshbuf_free(k->sk_key_handle);
-		sshbuf_free(k->sk_reserved);
-		/* FALLTHROUGH */
-	case KEY_ED25519:
-	case KEY_ED25519_CERT:
-		freezero(k->ed25519_pk, ED25519_PK_SZ);
-		k->ed25519_pk = NULL;
-		freezero(k->ed25519_sk, ED25519_SK_SZ);
-		k->ed25519_sk = NULL;
-		break;
-#ifdef WITH_XMSS
-	case KEY_XMSS:
-	case KEY_XMSS_CERT:
-		freezero(k->xmss_pk, sshkey_xmss_pklen(k));
-		k->xmss_pk = NULL;
-		freezero(k->xmss_sk, sshkey_xmss_sklen(k));
-		k->xmss_sk = NULL;
-		sshkey_xmss_free_state(k);
-		free(k->xmss_name);
-		k->xmss_name = NULL;
-		free(k->xmss_filename);
-		k->xmss_filename = NULL;
-		break;
-#endif /* WITH_XMSS */
-	case KEY_UNSPEC:
-		break;
-	default:
-		break;
-	}
+	if ((impl = sshkey_impl_from_type(k->type)) != NULL &&
+	    impl->funcs->cleanup != NULL)
+		impl->funcs->cleanup(k);
 	if (sshkey_is_cert(k))
 		cert_free(k->cert);
 	freezero(k->shielded_private, k->shielded_len);
@@ -1319,16 +1222,18 @@ sshkey_fingerprint(const struct sshkey *k, int dgst_alg,
 static int
 peek_type_nid(const char *s, size_t l, int *nid)
 {
-	const struct keytype *kt;
+	const struct sshkey_impl *impl;
+	int i;
 
-	for (kt = keytypes; kt->type != -1; kt++) {
-		if (kt->name == NULL || strlen(kt->name) != l)
+	for (i = 0; keyimpls[i] != NULL; i++) {
+		impl = keyimpls[i];
+		if (impl->name == NULL || strlen(impl->name) != l)
 			continue;
-		if (memcmp(s, kt->name, l) == 0) {
+		if (memcmp(s, impl->name, l) == 0) {
 			*nid = -1;
-			if (key_type_is_ecdsa_variant(kt->type))
-				*nid = kt->nid;
-			return kt->type;
+			if (key_type_is_ecdsa_variant(impl->type))
+				*nid = impl->nid;
+			return impl->type;
 		}
 	}
 	return KEY_UNSPEC;
@@ -2737,17 +2642,19 @@ sshkey_check_cert_sigtype(const struct sshkey *key, const char *allowed)
 const char *
 sshkey_sigalg_by_name(const char *name)
 {
-	const struct keytype *kt;
+	const struct sshkey_impl *impl;
+	int i;
 
-	for (kt = keytypes; kt->type != -1; kt++) {
-		if (strcmp(kt->name, name) != 0)
+	for (i = 0; keyimpls[i] != NULL; i++) {
+		impl = keyimpls[i];
+		if (strcmp(impl->name, name) != 0)
 			continue;
-		if (kt->sigalg != NULL)
-			return kt->sigalg;
-		if (!kt->cert)
-			return kt->name;
+		if (impl->sigalg != NULL)
+			return impl->sigalg;
+		if (!impl->cert)
+			return impl->name;
 		return sshkey_ssh_name_from_type_nid(
-		    sshkey_type_plain(kt->type), kt->nid);
+		    sshkey_type_plain(impl->type), impl->nid);
 	}
 	return NULL;
 }
diff --git a/sshkey.h b/sshkey.h
index be254e6b..3ec0e87b 100644
--- a/sshkey.h
+++ b/sshkey.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: sshkey.h,v 1.52 2022/09/17 10:30:45 djm Exp $ */
+/* $OpenBSD: sshkey.h,v 1.53 2022/10/28 00:35:40 djm Exp $ */
 
 /*
  * Copyright (c) 2000, 2001 Markus Friedl.  All rights reserved.
@@ -164,6 +164,24 @@ struct sshkey_sig_details {
 	uint8_t sk_flags;	/* U2F signature flags; see ssh-sk.h */
 };
 
+struct sshkey_impl_funcs {
+	u_int (*size)(const struct sshkey *);	/* optional */
+	int (*alloc)(struct sshkey *);		/* optional */
+	void (*cleanup)(struct sshkey *);	/* optional */
+};
+
+struct sshkey_impl {
+	const char *name;
+	const char *shortname;
+	const char *sigalg;
+	int type;
+	int nid;
+	int cert;
+	int sigonly;
+	int keybits;
+	const struct sshkey_impl_funcs *funcs;
+};
+
 struct sshkey	*sshkey_new(int);
 void		 sshkey_free(struct sshkey *);
 int		 sshkey_equal_public(const struct sshkey *,

-- 
To stop receiving notification emails like this one, please contact
djm at mindrot.org.


More information about the openssh-commits mailing list