refactor sshkey_from_blob_internal()
authordjm <djm@openbsd.org>
Fri, 28 Oct 2022 00:41:52 +0000 (00:41 +0000)
committerdjm <djm@openbsd.org>
Fri, 28 Oct 2022 00:41:52 +0000 (00:41 +0000)
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 2dba1ed..233b6fc 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: ssh-dss.c,v 1.44 2022/10/28 00:41:17 djm Exp $ */
+/* $OpenBSD: ssh-dss.c,v 1.45 2022/10/28 00:41:52 djm Exp $ */
 /*
  * Copyright (c) 2000 Markus Friedl.  All rights reserved.
  *
@@ -96,7 +96,7 @@ ssh_dss_equal(const struct sshkey *a, const struct sshkey *b)
 
 static int
 ssh_dss_serialize_public(const struct sshkey *key, struct sshbuf *b,
-    const char *typename, enum sshkey_serialize_rep opts)
+    enum sshkey_serialize_rep opts)
 {
        int r;
        const BIGNUM *dsa_p, *dsa_q, *dsa_g, *dsa_pub_key;
@@ -108,8 +108,7 @@ ssh_dss_serialize_public(const struct sshkey *key, struct sshbuf *b,
        if (dsa_p == NULL || dsa_q == NULL ||
            dsa_g == NULL || dsa_pub_key == NULL)
                return SSH_ERR_INTERNAL_ERROR;
-       if ((r = sshbuf_put_cstring(b, typename)) != 0 ||
-           (r = sshbuf_put_bignum2(b, dsa_p)) != 0 ||
+       if ((r = sshbuf_put_bignum2(b, dsa_p)) != 0 ||
            (r = sshbuf_put_bignum2(b, dsa_q)) != 0 ||
            (r = sshbuf_put_bignum2(b, dsa_g)) != 0 ||
            (r = sshbuf_put_bignum2(b, dsa_pub_key)) != 0)
@@ -173,6 +172,43 @@ ssh_dss_copy_public(const struct sshkey *from, struct sshkey *to)
        return r;
 }
 
+static int
+ssh_dss_deserialize_public(const char *ktype, struct sshbuf *b,
+    struct sshkey *key)
+{
+       int ret = SSH_ERR_INTERNAL_ERROR;
+       BIGNUM *dsa_p = NULL, *dsa_q = NULL, *dsa_g = NULL, *dsa_pub_key = NULL;
+
+       if (sshbuf_get_bignum2(b, &dsa_p) != 0 ||
+           sshbuf_get_bignum2(b, &dsa_q) != 0 ||
+           sshbuf_get_bignum2(b, &dsa_g) != 0 ||
+           sshbuf_get_bignum2(b, &dsa_pub_key) != 0) {
+               ret = SSH_ERR_INVALID_FORMAT;
+               goto out;
+       }
+       if (!DSA_set0_pqg(key->dsa, dsa_p, dsa_q, dsa_g)) {
+               ret = SSH_ERR_LIBCRYPTO_ERROR;
+               goto out;
+       }
+       dsa_p = dsa_q = dsa_g = NULL; /* transferred */
+       if (!DSA_set0_key(key->dsa, dsa_pub_key, NULL)) {
+               ret = SSH_ERR_LIBCRYPTO_ERROR;
+               goto out;
+       }
+       dsa_pub_key = NULL; /* transferred */
+#ifdef DEBUG_PK
+       DSA_print_fp(stderr, key->dsa, 8);
+#endif
+       /* success */
+       ret = 0;
+ out:
+       BN_clear_free(dsa_p);
+       BN_clear_free(dsa_q);
+       BN_clear_free(dsa_g);
+       BN_clear_free(dsa_pub_key);
+       return ret;
+}
+
 int
 ssh_dss_sign(const struct sshkey *key, u_char **sigp, size_t *lenp,
     const u_char *data, size_t datalen, u_int compat)
@@ -336,6 +372,7 @@ static const struct sshkey_impl_funcs sshkey_dss_funcs = {
        /* .cleanup = */        ssh_dss_cleanup,
        /* .equal = */          ssh_dss_equal,
        /* .ssh_serialize_public = */ ssh_dss_serialize_public,
+       /* .ssh_deserialize_public = */ ssh_dss_deserialize_public,
        /* .generate = */       ssh_dss_generate,
        /* .copy_public = */    ssh_dss_copy_public,
 };
index f3692b0..5f26395 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: ssh-ecdsa-sk.c,v 1.13 2022/10/28 00:41:17 djm Exp $ */
+/* $OpenBSD: ssh-ecdsa-sk.c,v 1.14 2022/10/28 00:41:52 djm Exp $ */
 /*
  * Copyright (c) 2000 Markus Friedl.  All rights reserved.
  * Copyright (c) 2010 Damien Miller.  All rights reserved.
@@ -65,12 +65,11 @@ ssh_ecdsa_sk_equal(const struct sshkey *a, const struct sshkey *b)
 
 static int
 ssh_ecdsa_sk_serialize_public(const struct sshkey *key, struct sshbuf *b,
-    const char *typename, enum sshkey_serialize_rep opts)
+    enum sshkey_serialize_rep opts)
 {
        int r;
 
-       if ((r = sshkey_ecdsa_funcs.serialize_public(key, b,
-           typename, opts)) != 0)
+       if ((r = sshkey_ecdsa_funcs.serialize_public(key, b, opts)) != 0)
                return r;
        if ((r = sshkey_serialize_sk(key, b)) != 0)
                return r;
@@ -90,6 +89,19 @@ ssh_ecdsa_sk_copy_public(const struct sshkey *from, struct sshkey *to)
        return 0;
 }
 
+static int
+ssh_ecdsa_sk_deserialize_public(const char *ktype, struct sshbuf *b,
+    struct sshkey *key)
+{
+       int r;
+
+       if ((r = sshkey_ecdsa_funcs.deserialize_public(ktype, b, key)) != 0)
+               return r;
+       if ((r = sshkey_deserialize_sk(b, key)) != 0)
+               return r;
+       return 0;
+}
+
 /*
  * Check FIDO/W3C webauthn signatures clientData field against the expected
  * format and prepare a hash of it for use in signature verification.
@@ -356,6 +368,7 @@ static const struct sshkey_impl_funcs sshkey_ecdsa_sk_funcs = {
        /* .cleanup = */        ssh_ecdsa_sk_cleanup,
        /* .equal = */          ssh_ecdsa_sk_equal,
        /* .ssh_serialize_public = */ ssh_ecdsa_sk_serialize_public,
+       /* .ssh_deserialize_public = */ ssh_ecdsa_sk_deserialize_public,
        /* .generate = */       NULL,
        /* .copy_public = */    ssh_ecdsa_sk_copy_public,
 };
index b2b0320..709870e 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: ssh-ecdsa.c,v 1.21 2022/10/28 00:41:17 djm Exp $ */
+/* $OpenBSD: ssh-ecdsa.c,v 1.22 2022/10/28 00:41:52 djm Exp $ */
 /*
  * Copyright (c) 2000 Markus Friedl.  All rights reserved.
  * Copyright (c) 2010 Damien Miller.  All rights reserved.
@@ -85,14 +85,13 @@ ssh_ecdsa_equal(const struct sshkey *a, const struct sshkey *b)
 
 static int
 ssh_ecdsa_serialize_public(const struct sshkey *key, struct sshbuf *b,
-    const char *typename, enum sshkey_serialize_rep opts)
+    enum sshkey_serialize_rep opts)
 {
        int r;
 
        if (key->ecdsa == NULL)
                return SSH_ERR_INVALID_ARGUMENT;
-       if ((r = sshbuf_put_cstring(b, typename)) != 0 ||
-           (r = sshbuf_put_cstring(b,
+       if ((r = sshbuf_put_cstring(b,
            sshkey_curve_nid_to_name(key->ecdsa_nid))) != 0 ||
            (r = sshbuf_put_eckey(b, key->ecdsa)) != 0)
                return r;
@@ -130,6 +129,56 @@ ssh_ecdsa_copy_public(const struct sshkey *from, struct sshkey *to)
        return 0;
 }
 
+static int
+ssh_ecdsa_deserialize_public(const char *ktype, struct sshbuf *b,
+    struct sshkey *key)
+{
+       int ret = SSH_ERR_INTERNAL_ERROR;
+       char *curve = NULL;
+       EC_POINT *q = NULL;
+
+       key->ecdsa_nid = sshkey_ecdsa_nid_from_name(ktype);
+       if (sshbuf_get_cstring(b, &curve, NULL) != 0) {
+               ret = SSH_ERR_INVALID_FORMAT;
+               goto out;
+       }
+       if (key->ecdsa_nid != sshkey_curve_name_to_nid(curve)) {
+               ret = SSH_ERR_EC_CURVE_MISMATCH;
+               goto out;
+       }
+       EC_KEY_free(key->ecdsa);
+       if ((key->ecdsa = EC_KEY_new_by_curve_name(key->ecdsa_nid)) == NULL) {
+               ret = SSH_ERR_EC_CURVE_INVALID;
+               goto out;
+       }
+       if ((q = EC_POINT_new(EC_KEY_get0_group(key->ecdsa))) == NULL) {
+               ret = SSH_ERR_ALLOC_FAIL;
+               goto out;
+       }
+       if (sshbuf_get_ec(b, q, EC_KEY_get0_group(key->ecdsa)) != 0) {
+               ret = SSH_ERR_INVALID_FORMAT;
+               goto out;
+       }
+       if (sshkey_ec_validate_public(EC_KEY_get0_group(key->ecdsa), q) != 0) {
+               ret = SSH_ERR_KEY_INVALID_EC_VALUE;
+               goto out;
+       }
+       if (EC_KEY_set_public_key(key->ecdsa, q) != 1) {
+               /* XXX assume it is a allocation error */
+               ret = SSH_ERR_ALLOC_FAIL;
+               goto out;
+       }
+#ifdef DEBUG_PK
+       sshkey_dump_ec_point(EC_KEY_get0_group(key->ecdsa), q);
+#endif
+       /* success */
+       ret = 0;
+ out:
+       free(curve);
+       EC_POINT_free(q);
+       return ret;
+}
+
 /* ARGSUSED */
 int
 ssh_ecdsa_sign(const struct sshkey *key, u_char **sigp, size_t *lenp,
@@ -289,6 +338,7 @@ const struct sshkey_impl_funcs sshkey_ecdsa_funcs = {
        /* .cleanup = */        ssh_ecdsa_cleanup,
        /* .equal = */          ssh_ecdsa_equal,
        /* .ssh_serialize_public = */ ssh_ecdsa_serialize_public,
+       /* .ssh_deserialize_public = */ ssh_ecdsa_deserialize_public,
        /* .generate = */       ssh_ecdsa_generate,
        /* .copy_public = */    ssh_ecdsa_copy_public,
 };
index 99676d9..777d033 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: ssh-ed25519-sk.c,v 1.11 2022/10/28 00:41:17 djm Exp $ */
+/* $OpenBSD: ssh-ed25519-sk.c,v 1.12 2022/10/28 00:41:52 djm Exp $ */
 /*
  * Copyright (c) 2019 Markus Friedl.  All rights reserved.
  *
@@ -55,12 +55,11 @@ ssh_ed25519_sk_equal(const struct sshkey *a, const struct sshkey *b)
 
 static int
 ssh_ed25519_sk_serialize_public(const struct sshkey *key, struct sshbuf *b,
-    const char *typename, enum sshkey_serialize_rep opts)
+    enum sshkey_serialize_rep opts)
 {
        int r;
 
-       if ((r = sshkey_ed25519_funcs.serialize_public(key, b,
-           typename, opts)) != 0)
+       if ((r = sshkey_ed25519_funcs.serialize_public(key, b, opts)) != 0)
                return r;
        if ((r = sshkey_serialize_sk(key, b)) != 0)
                return r;
@@ -80,6 +79,19 @@ ssh_ed25519_sk_copy_public(const struct sshkey *from, struct sshkey *to)
        return 0;
 }
 
+static int
+ssh_ed25519_sk_deserialize_public(const char *ktype, struct sshbuf *b,
+    struct sshkey *key)
+{
+       int r;
+
+       if ((r = sshkey_ed25519_funcs.deserialize_public(ktype, b, key)) != 0)
+               return r;
+       if ((r = sshkey_deserialize_sk(b, key)) != 0)
+               return r;
+       return 0;
+}
+
 int
 ssh_ed25519_sk_verify(const struct sshkey *key,
     const u_char *signature, size_t signaturelen,
@@ -213,6 +225,7 @@ static const struct sshkey_impl_funcs sshkey_ed25519_sk_funcs = {
        /* .cleanup = */        ssh_ed25519_sk_cleanup,
        /* .equal = */          ssh_ed25519_sk_equal,
        /* .ssh_serialize_public = */ ssh_ed25519_sk_serialize_public,
+       /* .ssh_deserialize_public = */ ssh_ed25519_sk_deserialize_public,
        /* .generate = */       NULL,
        /* .copy_public = */    ssh_ed25519_sk_copy_public,
 };
index db1dc96..d0dcea0 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: ssh-ed25519.c,v 1.15 2022/10/28 00:41:17 djm Exp $ */
+/* $OpenBSD: ssh-ed25519.c,v 1.16 2022/10/28 00:41:52 djm Exp $ */
 /*
  * Copyright (c) 2013 Markus Friedl <markus@openbsd.org>
  *
@@ -50,14 +50,13 @@ ssh_ed25519_equal(const struct sshkey *a, const struct sshkey *b)
 
 static int
 ssh_ed25519_serialize_public(const struct sshkey *key, struct sshbuf *b,
-    const char *typename, enum sshkey_serialize_rep opts)
+    enum sshkey_serialize_rep opts)
 {
        int r;
 
        if (key->ed25519_pk == NULL)
                return SSH_ERR_INVALID_ARGUMENT;
-       if ((r = sshbuf_put_cstring(b, typename)) != 0 ||
-           (r = sshbuf_put_string(b, key->ed25519_pk, ED25519_PK_SZ)) != 0)
+       if ((r = sshbuf_put_string(b, key->ed25519_pk, ED25519_PK_SZ)) != 0)
                return r;
 
        return 0;
@@ -84,6 +83,24 @@ ssh_ed25519_copy_public(const struct sshkey *from, struct sshkey *to)
        return 0;
 }
 
+static int
+ssh_ed25519_deserialize_public(const char *ktype, struct sshbuf *b,
+    struct sshkey *key)
+{
+       u_char *pk = NULL;
+       size_t len = 0;
+       int r;
+
+       if ((r = sshbuf_get_string(b, &pk, &len)) != 0)
+               return r;
+       if (len != ED25519_PK_SZ) {
+               freezero(pk, len);
+               return SSH_ERR_INVALID_FORMAT;
+       }
+       key->ed25519_pk = pk;
+       return 0;
+}
+
 int
 ssh_ed25519_sign(const struct sshkey *key, u_char **sigp, size_t *lenp,
     const u_char *data, size_t datalen, u_int compat)
@@ -218,6 +235,7 @@ const struct sshkey_impl_funcs sshkey_ed25519_funcs = {
        /* .cleanup = */        ssh_ed25519_cleanup,
        /* .equal = */          ssh_ed25519_equal,
        /* .ssh_serialize_public = */ ssh_ed25519_serialize_public,
+       /* .ssh_deserialize_public = */ ssh_ed25519_deserialize_public,
        /* .generate = */       ssh_ed25519_generate,
        /* .copy_public = */    ssh_ed25519_copy_public,
 };
index f13a082..e979541 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: ssh-rsa.c,v 1.73 2022/10/28 00:41:17 djm Exp $ */
+/* $OpenBSD: ssh-rsa.c,v 1.74 2022/10/28 00:41:52 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 *);
 
+int
+sshkey_check_rsa_length(const struct sshkey *k, int min_size)
+{
+#ifdef WITH_OPENSSL
+       const BIGNUM *rsa_n;
+       int nbits;
+
+       if (k == NULL || k->rsa == NULL ||
+           (k->type != KEY_RSA && k->type != KEY_RSA_CERT))
+               return 0;
+       RSA_get0_key(k->rsa, &rsa_n, NULL, NULL);
+       nbits = BN_num_bits(rsa_n);
+       if (nbits < SSH_RSA_MINIMUM_MODULUS_SIZE ||
+           (min_size > 0 && nbits < min_size))
+               return SSH_ERR_KEY_LENGTH;
+#endif /* WITH_OPENSSL */
+       return 0;
+}
+
+
 static u_int
 ssh_rsa_size(const struct sshkey *key)
 {
@@ -81,7 +101,7 @@ ssh_rsa_equal(const struct sshkey *a, const struct sshkey *b)
 
 static int
 ssh_rsa_serialize_public(const struct sshkey *key, struct sshbuf *b,
-    const char *typename, enum sshkey_serialize_rep opts)
+    enum sshkey_serialize_rep opts)
 {
        int r;
        const BIGNUM *rsa_n, *rsa_e;
@@ -89,8 +109,7 @@ ssh_rsa_serialize_public(const struct sshkey *key, struct sshbuf *b,
        if (key->rsa == NULL)
                return SSH_ERR_INVALID_ARGUMENT;
        RSA_get0_key(key->rsa, &rsa_n, &rsa_e, NULL);
-       if ((r = sshbuf_put_cstring(b, typename)) != 0 ||
-           (r = sshbuf_put_bignum2(b, rsa_e)) != 0 ||
+       if ((r = sshbuf_put_bignum2(b, rsa_e)) != 0 ||
            (r = sshbuf_put_bignum2(b, rsa_n)) != 0)
                return r;
 
@@ -151,6 +170,36 @@ ssh_rsa_copy_public(const struct sshkey *from, struct sshkey *to)
        return r;
 }
 
+static int
+ssh_rsa_deserialize_public(const char *ktype, struct sshbuf *b,
+    struct sshkey *key)
+{
+       int ret = SSH_ERR_INTERNAL_ERROR;
+       BIGNUM *rsa_n = NULL, *rsa_e = NULL;
+
+       if (sshbuf_get_bignum2(b, &rsa_e) != 0 ||
+           sshbuf_get_bignum2(b, &rsa_n) != 0) {
+               ret = SSH_ERR_INVALID_FORMAT;
+               goto out;
+       }
+       if (!RSA_set0_key(key->rsa, rsa_n, rsa_e, NULL)) {
+               ret = SSH_ERR_LIBCRYPTO_ERROR;
+               goto out;
+       }
+       rsa_n = rsa_e = NULL; /* transferred */
+       if ((ret = sshkey_check_rsa_length(key, 0)) != 0)
+               goto out;
+#ifdef DEBUG_PK
+       RSA_print_fp(stderr, key->rsa, 8);
+#endif
+       /* success */
+       ret = 0;
+ out:
+       BN_clear_free(rsa_n);
+       BN_clear_free(rsa_e);
+       return ret;
+}
+
 static const char *
 rsa_hash_alg_ident(int hash_alg)
 {
@@ -565,6 +614,7 @@ static const struct sshkey_impl_funcs sshkey_rsa_funcs = {
        /* .cleanup = */        ssh_rsa_cleanup,
        /* .equal = */          ssh_rsa_equal,
        /* .ssh_serialize_public = */ ssh_rsa_serialize_public,
+       /* .ssh_deserialize_public = */ ssh_rsa_deserialize_public,
        /* .generate = */       ssh_rsa_generate,
        /* .copy_public = */    ssh_rsa_copy_public,
 };
index 7a3bec7..18fee08 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: ssh-xmss.c,v 1.10 2022/10/28 00:41:17 djm Exp $*/
+/* $OpenBSD: ssh-xmss.c,v 1.11 2022/10/28 00:41:52 djm Exp $*/
 /*
  * Copyright (c) 2017 Stefan-Lukas Gazdag.
  * Copyright (c) 2017 Markus Friedl.
@@ -62,15 +62,14 @@ ssh_xmss_equal(const struct sshkey *a, const struct sshkey *b)
 
 static int
 ssh_xmss_serialize_public(const struct sshkey *key, struct sshbuf *b,
-    const char *typename, enum sshkey_serialize_rep opts)
+    enum sshkey_serialize_rep opts)
 {
        int r;
 
        if (key->xmss_name == NULL || key->xmss_pk == NULL ||
            sshkey_xmss_pklen(key) == 0)
                return SSH_ERR_INVALID_ARGUMENT;
-       if ((r = sshbuf_put_cstring(b, typename)) != 0 ||
-           (r = sshbuf_put_cstring(b, key->xmss_name)) != 0 ||
+       if ((r = sshbuf_put_cstring(b, key->xmss_name)) != 0 ||
            (r = sshbuf_put_string(b, key->xmss_pk,
            sshkey_xmss_pklen(key))) != 0 ||
            (r = sshkey_xmss_serialize_pk_info(key, b, opts)) != 0)
@@ -104,6 +103,38 @@ ssh_xmss_copy_public(const struct sshkey *from, struct sshkey *to)
        return 0;
 }
 
+static int
+ssh_xmss_deserialize_public(const char *ktype, struct sshbuf *b,
+    struct sshkey *key)
+{
+       size_t len = 0;
+       char *xmss_name = NULL;
+       u_char *pk = NULL;
+       int ret = SSH_ERR_INTERNAL_ERROR;
+
+       if ((ret = sshbuf_get_cstring(b, &xmss_name, NULL)) != 0)
+               goto out;
+       if ((ret = sshkey_xmss_init(key, xmss_name)) != 0)
+               goto out;
+       if ((ret = sshbuf_get_string(b, &pk, &len)) != 0)
+               goto out;
+       if (len == 0 || len != sshkey_xmss_pklen(key)) {
+               ret = SSH_ERR_INVALID_FORMAT;
+               goto out;
+       }
+       key->xmss_pk = pk;
+       pk = NULL;
+       if (!sshkey_is_cert(key) &&
+           (ret = sshkey_xmss_deserialize_pk_info(key, b)) != 0)
+               goto out;
+       /* success */
+       ret = 0;
+ out:
+       free(xmss_name);
+       freezero(pk, len);
+       return ret;
+}
+
 int
 ssh_xmss_sign(const struct sshkey *key, u_char **sigp, size_t *lenp,
     const u_char *data, size_t datalen, u_int compat)
@@ -258,6 +289,7 @@ static const struct sshkey_impl_funcs sshkey_xmss_funcs = {
        /* .cleanup = */        ssh_xmss_cleanup,
        /* .equal = */          ssh_xmss_equal,
        /* .ssh_serialize_public = */ ssh_xmss_serialize_public,
+       /* .ssh_deserialize_public = */ ssh_xmss_deserialize_public,
        /* .generate = */       sshkey_xmss_generate_private_key,
        /* .copy_public = */    ssh_xmss_copy_public,
 };
index 7a6daeb..bc5e258 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: sshkey.c,v 1.128 2022/10/28 00:41:17 djm Exp $ */
+/* $OpenBSD: sshkey.c,v 1.129 2022/10/28 00:41:52 djm Exp $ */
 /*
  * Copyright (c) 2000, 2001 Markus Friedl.  All rights reserved.
  * Copyright (c) 2008 Alexander von Gernler.  All rights reserved.
@@ -704,7 +704,9 @@ to_blob_buf(const struct sshkey *key, struct sshbuf *b, int force_plain,
                return SSH_ERR_KEY_TYPE_UNKNOWN;
 
        typename = sshkey_ssh_name_from_type_nid(type, key->ecdsa_nid);
-       return impl->funcs->serialize_public(key, b, typename, opts);
+       if ((ret = sshbuf_put_cstring(b, typename)) != 0)
+               return ret;
+       return impl->funcs->serialize_public(key, b, opts);
 }
 
 int
@@ -1800,21 +1802,11 @@ cert_parse(struct sshbuf *b, struct sshkey *key, struct sshbuf *certbuf)
 }
 
 int
-sshkey_check_rsa_length(const struct sshkey *k, int min_size)
+sshkey_deserialize_sk(struct sshbuf *b, struct sshkey *key)
 {
-#ifdef WITH_OPENSSL
-       const BIGNUM *rsa_n;
-       int nbits;
-
-       if (k == NULL || k->rsa == NULL ||
-           (k->type != KEY_RSA && k->type != KEY_RSA_CERT))
-               return 0;
-       RSA_get0_key(k->rsa, &rsa_n, NULL, NULL);
-       nbits = BN_num_bits(rsa_n);
-       if (nbits < SSH_RSA_MINIMUM_MODULUS_SIZE ||
-           (min_size > 0 && nbits < min_size))
-               return SSH_ERR_KEY_LENGTH;
-#endif /* WITH_OPENSSL */
+       /* Parse additional security-key application string */
+       if (sshbuf_get_cstring(b, &key->sk_application, NULL) != 0)
+               return SSH_ERR_INVALID_FORMAT;
        return 0;
 }
 
@@ -1823,16 +1815,10 @@ sshkey_from_blob_internal(struct sshbuf *b, struct sshkey **keyp,
     int allow_cert)
 {
        int type, ret = SSH_ERR_INTERNAL_ERROR;
-       char *ktype = NULL, *curve = NULL, *xmss_name = NULL;
+       char *ktype = NULL;
        struct sshkey *key = NULL;
-       size_t len;
-       u_char *pk = NULL;
        struct sshbuf *copy;
-#ifdef WITH_OPENSSL
-       EC_POINT *q = NULL;
-       BIGNUM *rsa_n = NULL, *rsa_e = NULL;
-       BIGNUM *dsa_p = NULL, *dsa_q = NULL, *dsa_g = NULL, *dsa_pub_key = NULL;
-#endif /* WITH_OPENSSL */
+       const struct sshkey_impl *impl;
 
 #ifdef DEBUG_PK /* XXX */
        sshbuf_dump(b, stderr);
@@ -1853,201 +1839,23 @@ sshkey_from_blob_internal(struct sshbuf *b, struct sshkey **keyp,
                ret = SSH_ERR_KEY_CERT_INVALID_SIGN_KEY;
                goto out;
        }
-       switch (type) {
-#ifdef WITH_OPENSSL
-       case KEY_RSA_CERT:
-               /* Skip nonce */
-               if (sshbuf_get_string_direct(b, NULL, NULL) != 0) {
-                       ret = SSH_ERR_INVALID_FORMAT;
-                       goto out;
-               }
-               /* FALLTHROUGH */
-       case KEY_RSA:
-               if ((key = sshkey_new(type)) == NULL) {
-                       ret = SSH_ERR_ALLOC_FAIL;
-                       goto out;
-               }
-               if (sshbuf_get_bignum2(b, &rsa_e) != 0 ||
-                   sshbuf_get_bignum2(b, &rsa_n) != 0) {
-                       ret = SSH_ERR_INVALID_FORMAT;
-                       goto out;
-               }
-               if (!RSA_set0_key(key->rsa, rsa_n, rsa_e, NULL)) {
-                       ret = SSH_ERR_LIBCRYPTO_ERROR;
-                       goto out;
-               }
-               rsa_n = rsa_e = NULL; /* transferred */
-               if ((ret = sshkey_check_rsa_length(key, 0)) != 0)
-                       goto out;
-#ifdef DEBUG_PK
-               RSA_print_fp(stderr, key->rsa, 8);
-#endif
-               break;
-       case KEY_DSA_CERT:
-               /* Skip nonce */
-               if (sshbuf_get_string_direct(b, NULL, NULL) != 0) {
-                       ret = SSH_ERR_INVALID_FORMAT;
-                       goto out;
-               }
-               /* FALLTHROUGH */
-       case KEY_DSA:
-               if ((key = sshkey_new(type)) == NULL) {
-                       ret = SSH_ERR_ALLOC_FAIL;
-                       goto out;
-               }
-               if (sshbuf_get_bignum2(b, &dsa_p) != 0 ||
-                   sshbuf_get_bignum2(b, &dsa_q) != 0 ||
-                   sshbuf_get_bignum2(b, &dsa_g) != 0 ||
-                   sshbuf_get_bignum2(b, &dsa_pub_key) != 0) {
-                       ret = SSH_ERR_INVALID_FORMAT;
-                       goto out;
-               }
-               if (!DSA_set0_pqg(key->dsa, dsa_p, dsa_q, dsa_g)) {
-                       ret = SSH_ERR_LIBCRYPTO_ERROR;
-                       goto out;
-               }
-               dsa_p = dsa_q = dsa_g = NULL; /* transferred */
-               if (!DSA_set0_key(key->dsa, dsa_pub_key, NULL)) {
-                       ret = SSH_ERR_LIBCRYPTO_ERROR;
-                       goto out;
-               }
-               dsa_pub_key = NULL; /* transferred */
-#ifdef DEBUG_PK
-               DSA_print_fp(stderr, key->dsa, 8);
-#endif
-               break;
-       case KEY_ECDSA_CERT:
-       case KEY_ECDSA_SK_CERT:
-               /* Skip nonce */
-               if (sshbuf_get_string_direct(b, NULL, NULL) != 0) {
-                       ret = SSH_ERR_INVALID_FORMAT;
-                       goto out;
-               }
-               /* FALLTHROUGH */
-       case KEY_ECDSA:
-       case KEY_ECDSA_SK:
-               if ((key = sshkey_new(type)) == NULL) {
-                       ret = SSH_ERR_ALLOC_FAIL;
-                       goto out;
-               }
-               key->ecdsa_nid = sshkey_ecdsa_nid_from_name(ktype);
-               if (sshbuf_get_cstring(b, &curve, NULL) != 0) {
-                       ret = SSH_ERR_INVALID_FORMAT;
-                       goto out;
-               }
-               if (key->ecdsa_nid != sshkey_curve_name_to_nid(curve)) {
-                       ret = SSH_ERR_EC_CURVE_MISMATCH;
-                       goto out;
-               }
-               EC_KEY_free(key->ecdsa);
-               if ((key->ecdsa = EC_KEY_new_by_curve_name(key->ecdsa_nid))
-                   == NULL) {
-                       ret = SSH_ERR_EC_CURVE_INVALID;
-                       goto out;
-               }
-               if ((q = EC_POINT_new(EC_KEY_get0_group(key->ecdsa))) == NULL) {
-                       ret = SSH_ERR_ALLOC_FAIL;
-                       goto out;
-               }
-               if (sshbuf_get_ec(b, q, EC_KEY_get0_group(key->ecdsa)) != 0) {
-                       ret = SSH_ERR_INVALID_FORMAT;
-                       goto out;
-               }
-               if (sshkey_ec_validate_public(EC_KEY_get0_group(key->ecdsa),
-                   q) != 0) {
-                       ret = SSH_ERR_KEY_INVALID_EC_VALUE;
-                       goto out;
-               }
-               if (EC_KEY_set_public_key(key->ecdsa, q) != 1) {
-                       /* XXX assume it is a allocation error */
-                       ret = SSH_ERR_ALLOC_FAIL;
-                       goto out;
-               }
-#ifdef DEBUG_PK
-               sshkey_dump_ec_point(EC_KEY_get0_group(key->ecdsa), q);
-#endif
-               if (type == KEY_ECDSA_SK || type == KEY_ECDSA_SK_CERT) {
-                       /* Parse additional security-key application string */
-                       if (sshbuf_get_cstring(b, &key->sk_application,
-                           NULL) != 0) {
-                               ret = SSH_ERR_INVALID_FORMAT;
-                               goto out;
-                       }
-#ifdef DEBUG_PK
-                       fprintf(stderr, "App: %s\n", key->sk_application);
-#endif
-               }
-               break;
-#endif /* WITH_OPENSSL */
-       case KEY_ED25519_CERT:
-       case KEY_ED25519_SK_CERT:
-               /* Skip nonce */
-               if (sshbuf_get_string_direct(b, NULL, NULL) != 0) {
-                       ret = SSH_ERR_INVALID_FORMAT;
-                       goto out;
-               }
-               /* FALLTHROUGH */
-       case KEY_ED25519:
-       case KEY_ED25519_SK:
-               if ((ret = sshbuf_get_string(b, &pk, &len)) != 0)
-                       goto out;
-               if (len != ED25519_PK_SZ) {
-                       ret = SSH_ERR_INVALID_FORMAT;
-                       goto out;
-               }
-               if ((key = sshkey_new(type)) == NULL) {
-                       ret = SSH_ERR_ALLOC_FAIL;
-                       goto out;
-               }
-               if (type == KEY_ED25519_SK || type == KEY_ED25519_SK_CERT) {
-                       /* Parse additional security-key application string */
-                       if (sshbuf_get_cstring(b, &key->sk_application,
-                           NULL) != 0) {
-                               ret = SSH_ERR_INVALID_FORMAT;
-                               goto out;
-                       }
-#ifdef DEBUG_PK
-                       fprintf(stderr, "App: %s\n", key->sk_application);
-#endif
-               }
-               key->ed25519_pk = pk;
-               pk = NULL;
-               break;
-#ifdef WITH_XMSS
-       case KEY_XMSS_CERT:
-               /* Skip nonce */
+       if ((impl = sshkey_impl_from_type(type)) == NULL) {
+               ret = SSH_ERR_KEY_TYPE_UNKNOWN;
+               goto out;
+       }
+       if ((key = sshkey_new(type)) == NULL) {
+               ret = SSH_ERR_ALLOC_FAIL;
+               goto out;
+       }
+       if (sshkey_type_is_cert(type)) {
+               /* Skip nonce that preceeds all certificates */
                if (sshbuf_get_string_direct(b, NULL, NULL) != 0) {
                        ret = SSH_ERR_INVALID_FORMAT;
                        goto out;
                }
-               /* FALLTHROUGH */
-       case KEY_XMSS:
-               if ((ret = sshbuf_get_cstring(b, &xmss_name, NULL)) != 0)
-                       goto out;
-               if ((key = sshkey_new(type)) == NULL) {
-                       ret = SSH_ERR_ALLOC_FAIL;
-                       goto out;
-               }
-               if ((ret = sshkey_xmss_init(key, xmss_name)) != 0)
-                       goto out;
-               if ((ret = sshbuf_get_string(b, &pk, &len)) != 0)
-                       goto out;
-               if (len == 0 || len != sshkey_xmss_pklen(key)) {
-                       ret = SSH_ERR_INVALID_FORMAT;
-                       goto out;
-               }
-               key->xmss_pk = pk;
-               pk = NULL;
-               if (type != KEY_XMSS_CERT &&
-                   (ret = sshkey_xmss_deserialize_pk_info(key, b)) != 0)
-                       goto out;
-               break;
-#endif /* WITH_XMSS */
-       case KEY_UNSPEC:
-       default:
-               ret = SSH_ERR_KEY_TYPE_UNKNOWN;
-               goto out;
        }
+       if ((ret = impl->funcs->deserialize_public(ktype, b, key)) != 0)
+               goto out;
 
        /* Parse certificate potion */
        if (sshkey_is_cert(key) && (ret = cert_parse(b, key, copy)) != 0)
@@ -2065,19 +1873,7 @@ sshkey_from_blob_internal(struct sshbuf *b, struct sshkey **keyp,
  out:
        sshbuf_free(copy);
        sshkey_free(key);
-       free(xmss_name);
        free(ktype);
-       free(curve);
-       free(pk);
-#ifdef WITH_OPENSSL
-       EC_POINT_free(q);
-       BN_clear_free(rsa_n);
-       BN_clear_free(rsa_e);
-       BN_clear_free(dsa_p);
-       BN_clear_free(dsa_q);
-       BN_clear_free(dsa_g);
-       BN_clear_free(dsa_pub_key);
-#endif /* WITH_OPENSSL */
        return ret;
 }
 
index 899614d..9feefc1 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: sshkey.h,v 1.57 2022/10/28 00:41:17 djm Exp $ */
+/* $OpenBSD: sshkey.h,v 1.58 2022/10/28 00:41:52 djm Exp $ */
 
 /*
  * Copyright (c) 2000, 2001 Markus Friedl.  All rights reserved.
@@ -164,7 +164,9 @@ struct sshkey_impl_funcs {
        void (*cleanup)(struct sshkey *);       /* optional */
        int (*equal)(const struct sshkey *, const struct sshkey *);
        int (*serialize_public)(const struct sshkey *, struct sshbuf *,
-           const char *, enum sshkey_serialize_rep);
+           enum sshkey_serialize_rep);
+       int (*deserialize_public)(const char *, struct sshbuf *,
+           struct sshkey *);
        int (*generate)(struct sshkey *, int);  /* optional */
        int (*copy_public)(const struct sshkey *, struct sshkey *);
 };
@@ -309,6 +311,10 @@ int        sshkey_sk_fields_equal(const struct sshkey *a, const struct sshkey *b);
 void   sshkey_sk_cleanup(struct sshkey *k);
 int    sshkey_serialize_sk(const struct sshkey *key, struct sshbuf *b);
 int    sshkey_copy_public_sk(const struct sshkey *from, struct sshkey *to);
+int    sshkey_deserialize_sk(struct sshbuf *b, struct sshkey *key);
+#ifdef WITH_OPENSSL
+int    check_rsa_length(const RSA *rsa); /* XXX remove */
+#endif
 
 int ssh_rsa_sign(const struct sshkey *key,
     u_char **sigp, size_t *lenp, const u_char *data, size_t datalen,