begin big refactor of sshkey
authordjm <djm@openbsd.org>
Fri, 28 Oct 2022 00:35:40 +0000 (00:35 +0000)
committerdjm <djm@openbsd.org>
Fri, 28 Oct 2022 00:35:40 +0000 (00:35 +0000)
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@

usr.bin/ssh/ssh-dss.c
usr.bin/ssh/ssh-ecdsa-sk.c
usr.bin/ssh/ssh-ecdsa.c
usr.bin/ssh/ssh-ed25519-sk.c
usr.bin/ssh/ssh-ed25519.c
usr.bin/ssh/ssh-rsa.c
usr.bin/ssh/ssh-xmss.c
usr.bin/ssh/sshkey.c
usr.bin/ssh/sshkey.h

index c54bfd3..104222e 100644 (file)
@@ -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.
  *
 #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)
@@ -196,3 +222,33 @@ 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@openssh.com",
+       /* .shortname = */      "DSA-CERT",
+       /* .sigalg = */         NULL,
+       /* .type = */           KEY_DSA_CERT,
+       /* .nid = */            0,
+       /* .cert = */           1,
+       /* .sigonly = */        0,
+       /* .keybits = */        0,
+       /* .funcs = */          &sshkey_dss_funcs,
+};
index 68a6fc7..c48e089 100644 (file)
@@ -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.
 #define SSHKEY_INTERNAL
 #include "sshkey.h"
 
+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.
@@ -302,3 +312,45 @@ ssh_ecdsa_sk_verify(const struct sshkey *key,
        free(ktype);
        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@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@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@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,
+};
index d9d7e07..661f9c2 100644 (file)
@@ -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.
 #define SSHKEY_INTERNAL
 #include "sshkey.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;
+       case NID_secp521r1:
+               return 521;
+       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,
@@ -190,3 +212,81 @@ ssh_ecdsa_verify(const struct sshkey *key,
        free(ktype);
        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@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@openssh.com",
+       /* .shortname = */      "ECDSA-CERT",
+       /* .sigalg = */         NULL,
+       /* .type = */           KEY_ECDSA_CERT,
+       /* .nid = */            NID_secp384r1,
+       /* .cert = */           1,
+       /* .sigonly = */        0,
+       /* .keybits = */        0,
+       /* .funcs = */          &sshkey_ecdsa_funcs,
+};
+
+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@openssh.com",
+       /* .shortname = */      "ECDSA-CERT",
+       /* .sigalg = */         NULL,
+       /* .type = */           KEY_ECDSA_CERT,
+       /* .nid = */            NID_secp521r1,
+       /* .cert = */           1,
+       /* .sigonly = */        0,
+       /* .keybits = */        0,
+       /* .funcs = */          &sshkey_ecdsa_funcs,
+};
index 8d8ddaa..ce0631a 100644 (file)
@@ -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.
  *
 #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,
@@ -159,3 +171,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@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@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,
+};
index 24f52e1..fdc08d1 100644 (file)
@@ -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@openbsd.org>
  *
 #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)
@@ -155,3 +164,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@openssh.com",
+       /* .shortname = */      "ED25519-CERT",
+       /* .sigalg = */         NULL,
+       /* .type = */           KEY_ED25519_CERT,
+       /* .nid = */            0,
+       /* .cert = */           1,
+       /* .sigonly = */        0,
+       /* .keybits = */        256,
+       /* .funcs = */          &sshkey_ed25519_funcs,
+};
index 1176b34..6aa3f75 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: ssh-rsa.c,v 1.68 2018/09/13 02:08:33 djm Exp $ */
+/* $OpenBSD: ssh-rsa.c,v 1.69 2022/10/28 00:35:40 djm Exp $ */
 /*
  * Copyright (c) 2000, 2003 Markus Friedl <markus@openbsd.org>
  *
 
 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)
 {
@@ -439,3 +465,83 @@ 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@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@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@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,
+};
index ef64502..5309ba8 100644 (file)
@@ -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.
 
 #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)
@@ -181,3 +195,33 @@ 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@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@openssh.com",
+       /* .shortname = */      "XMSS-CERT",
+       /* .sigalg = */         NULL,
+       /* .type = */           KEY_XMSS_CERT,
+       /* .nid = */            0,
+       /* .cert = */           1,
+       /* .sigonly = */        0,
+       /* .keybits = */        256,
+       /* .funcs = */          &sshkey_xmss_funcs,
+};
index da671b8..f959deb 100644 (file)
@@ -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.
@@ -87,97 +87,118 @@ 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@openssh.com", "ED25519-CERT", NULL,
-           KEY_ED25519_CERT, 0, 1, 0 },
-       { "sk-ssh-ed25519@openssh.com", "ED25519-SK", NULL,
-           KEY_ED25519_SK, 0, 0, 0 },
-       { "sk-ssh-ed25519-cert-v01@openssh.com", "ED25519-SK-CERT", NULL,
-           KEY_ED25519_SK_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
+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;
+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;
+extern const struct sshkey_impl sshkey_ecdsa_nistp521_impl;
+extern const struct sshkey_impl sshkey_ecdsa_nistp521_cert_impl;
+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
-       { "ssh-xmss@openssh.com", "XMSS", NULL, KEY_XMSS, 0, 0, 0 },
-       { "ssh-xmss-cert-v01@openssh.com", "XMSS-CERT", NULL,
-           KEY_XMSS_CERT, 0, 1, 0 },
-#endif /* 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,
+       &sshkey_ed25519_sk_impl,
+       &sshkey_ed25519_sk_cert_impl,
 #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 },
-       { "ecdsa-sha2-nistp256", "ECDSA", NULL,
-           KEY_ECDSA, NID_X9_62_prime256v1, 0, 0 },
-       { "ecdsa-sha2-nistp384", "ECDSA", NULL,
-           KEY_ECDSA, NID_secp384r1, 0, 0 },
-       { "ecdsa-sha2-nistp521", "ECDSA", NULL,
-           KEY_ECDSA, NID_secp521r1, 0, 0 },
-       { "sk-ecdsa-sha2-nistp256@openssh.com", "ECDSA-SK", NULL,
-           KEY_ECDSA_SK, NID_X9_62_prime256v1, 0, 0 },
-       { "webauthn-sk-ecdsa-sha2-nistp256@openssh.com", "ECDSA-SK", NULL,
-           KEY_ECDSA_SK, NID_X9_62_prime256v1, 0, 1 },
-       { "ssh-rsa-cert-v01@openssh.com", "RSA-CERT", NULL,
-           KEY_RSA_CERT, 0, 1, 0 },
-       { "rsa-sha2-256-cert-v01@openssh.com", "RSA-CERT",
-           "rsa-sha2-256", KEY_RSA_CERT, 0, 1, 1 },
-       { "rsa-sha2-512-cert-v01@openssh.com", "RSA-CERT",
-           "rsa-sha2-512", KEY_RSA_CERT, 0, 1, 1 },
-       { "ssh-dss-cert-v01@openssh.com", "DSA-CERT", NULL,
-           KEY_DSA_CERT, 0, 1, 0 },
-       { "ecdsa-sha2-nistp256-cert-v01@openssh.com", "ECDSA-CERT", NULL,
-           KEY_ECDSA_CERT, NID_X9_62_prime256v1, 1, 0 },
-       { "ecdsa-sha2-nistp384-cert-v01@openssh.com", "ECDSA-CERT", NULL,
-           KEY_ECDSA_CERT, NID_secp384r1, 1, 0 },
-       { "ecdsa-sha2-nistp521-cert-v01@openssh.com", "ECDSA-CERT", NULL,
-           KEY_ECDSA_CERT, NID_secp521r1, 1, 0 },
-       { "sk-ecdsa-sha2-nistp256-cert-v01@openssh.com", "ECDSA-SK-CERT", NULL,
-           KEY_ECDSA_SK_CERT, NID_X9_62_prime256v1, 1, 0 },
+       &sshkey_ecdsa_nistp256_impl,
+       &sshkey_ecdsa_nistp256_cert_impl,
+       &sshkey_ecdsa_nistp384_impl,
+       &sshkey_ecdsa_nistp384_cert_impl,
+       &sshkey_ecdsa_nistp521_impl,
+       &sshkey_ecdsa_nistp521_cert_impl,
+       &sshkey_ecdsa_sk_impl,
+       &sshkey_ecdsa_sk_cert_impl,
+       &sshkey_ecdsa_sk_webauthn_impl,
+       &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 *
@@ -196,13 +217,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;
 }
@@ -223,13 +246,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;
 }
@@ -261,25 +285,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;
@@ -289,8 +314,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;
@@ -306,12 +331,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);
@@ -325,56 +353,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
@@ -544,63 +540,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);
@@ -614,64 +570,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;
-       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 /* 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);
@@ -1284,16 +1189,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;
@@ -2685,17 +2592,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;
 }
index 850ce33..748cd41 100644 (file)
@@ -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.
@@ -158,6 +158,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 *,