refactor sshkey_private_deserialize
authordjm <djm@openbsd.org>
Fri, 28 Oct 2022 00:44:44 +0000 (00:44 +0000)
committerdjm <djm@openbsd.org>
Fri, 28 Oct 2022 00:44:44 +0000 (00:44 +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 85641e4..de80458 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: ssh-dss.c,v 1.47 2022/10/28 00:44:17 djm Exp $ */
+/* $OpenBSD: ssh-dss.c,v 1.48 2022/10/28 00:44:44 djm Exp $ */
 /*
  * Copyright (c) 2000 Markus Friedl.  All rights reserved.
  *
@@ -227,6 +227,27 @@ ssh_dss_deserialize_public(const char *ktype, struct sshbuf *b,
        return ret;
 }
 
+static int
+ssh_dss_deserialize_private(const char *ktype, struct sshbuf *b,
+    struct sshkey *key)
+{
+       int r;
+       BIGNUM *dsa_priv_key = NULL;
+
+       if (!sshkey_is_cert(key)) {
+               if ((r = ssh_dss_deserialize_public(ktype, b, key)) != 0)
+                       return r;
+       }
+
+       if ((r = sshbuf_get_bignum2(b, &dsa_priv_key)) != 0)
+               return r;
+       if (!DSA_set0_key(key->dsa, NULL, dsa_priv_key)) {
+               BN_clear_free(dsa_priv_key);
+               return SSH_ERR_LIBCRYPTO_ERROR;
+       }
+       return 0;
+}
+
 static int
 ssh_dss_sign(struct sshkey *key,
     u_char **sigp, size_t *lenp,
@@ -395,6 +416,7 @@ static const struct sshkey_impl_funcs sshkey_dss_funcs = {
        /* .ssh_serialize_public = */ ssh_dss_serialize_public,
        /* .ssh_deserialize_public = */ ssh_dss_deserialize_public,
        /* .ssh_serialize_private = */ ssh_dss_serialize_private,
+       /* .ssh_deserialize_private = */ ssh_dss_deserialize_private,
        /* .generate = */       ssh_dss_generate,
        /* .copy_public = */    ssh_dss_copy_public,
        /* .sign = */           ssh_dss_sign,
index fc53dba..04b02e0 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: ssh-ecdsa-sk.c,v 1.16 2022/10/28 00:44:17 djm Exp $ */
+/* $OpenBSD: ssh-ecdsa-sk.c,v 1.17 2022/10/28 00:44:44 djm Exp $ */
 /*
  * Copyright (c) 2000 Markus Friedl.  All rights reserved.
  * Copyright (c) 2010 Damien Miller.  All rights reserved.
@@ -119,6 +119,23 @@ ssh_ecdsa_sk_deserialize_public(const char *ktype, struct sshbuf *b,
        return 0;
 }
 
+static int
+ssh_ecdsa_sk_deserialize_private(const char *ktype, struct sshbuf *b,
+    struct sshkey *key)
+{
+       int r;
+
+       if (!sshkey_is_cert(key)) {
+               if ((r = sshkey_ecdsa_funcs.deserialize_public(ktype,
+                   b, key)) != 0)
+                       return r;
+       }
+       if ((r = sshkey_private_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.
@@ -387,6 +404,7 @@ static const struct sshkey_impl_funcs sshkey_ecdsa_sk_funcs = {
        /* .ssh_serialize_public = */ ssh_ecdsa_sk_serialize_public,
        /* .ssh_deserialize_public = */ ssh_ecdsa_sk_deserialize_public,
        /* .ssh_serialize_private = */ ssh_ecdsa_sk_serialize_private,
+       /* .ssh_deserialize_private = */ ssh_ecdsa_sk_deserialize_private,
        /* .generate = */       NULL,
        /* .copy_public = */    ssh_ecdsa_sk_copy_public,
        /* .sign = */           NULL,
index 8c08b23..5677396 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: ssh-ecdsa.c,v 1.24 2022/10/28 00:44:17 djm Exp $ */
+/* $OpenBSD: ssh-ecdsa.c,v 1.25 2022/10/28 00:44:44 djm Exp $ */
 /*
  * Copyright (c) 2000 Markus Friedl.  All rights reserved.
  * Copyright (c) 2010 Damien Miller.  All rights reserved.
@@ -149,50 +149,69 @@ static int
 ssh_ecdsa_deserialize_public(const char *ktype, struct sshbuf *b,
     struct sshkey *key)
 {
-       int ret = SSH_ERR_INTERNAL_ERROR;
+       int r;
        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;
+       if ((key->ecdsa_nid = sshkey_ecdsa_nid_from_name(ktype)) == -1)
+               return SSH_ERR_INVALID_ARGUMENT;
+       if ((r = sshbuf_get_cstring(b, &curve, NULL)) != 0)
                goto out;
-       }
        if (key->ecdsa_nid != sshkey_curve_name_to_nid(curve)) {
-               ret = SSH_ERR_EC_CURVE_MISMATCH;
+               r = SSH_ERR_EC_CURVE_MISMATCH;
                goto out;
        }
        EC_KEY_free(key->ecdsa);
+       key->ecdsa = NULL;
        if ((key->ecdsa = EC_KEY_new_by_curve_name(key->ecdsa_nid)) == NULL) {
-               ret = SSH_ERR_EC_CURVE_INVALID;
+               r = SSH_ERR_LIBCRYPTO_ERROR;
                goto out;
        }
-       if ((q = EC_POINT_new(EC_KEY_get0_group(key->ecdsa))) == NULL) {
-               ret = SSH_ERR_ALLOC_FAIL;
+       if ((r = sshbuf_get_eckey(b, key->ecdsa)) != 0)
                goto out;
-       }
-       if (sshbuf_get_ec(b, q, EC_KEY_get0_group(key->ecdsa)) != 0) {
-               ret = SSH_ERR_INVALID_FORMAT;
+       if (sshkey_ec_validate_public(EC_KEY_get0_group(key->ecdsa),
+           EC_KEY_get0_public_key(key->ecdsa)) != 0) {
+               r = SSH_ERR_KEY_INVALID_EC_VALUE;
                goto out;
        }
-       if (sshkey_ec_validate_public(EC_KEY_get0_group(key->ecdsa), q) != 0) {
-               ret = SSH_ERR_KEY_INVALID_EC_VALUE;
-               goto out;
+       /* success */
+       r = 0;
+#ifdef DEBUG_PK
+       sshkey_dump_ec_point(EC_KEY_get0_group(key->ecdsa),
+           EC_KEY_get0_public_key(key->ecdsa));
+#endif
+ out:
+       free(curve);
+       if (r != 0) {
+               EC_KEY_free(key->ecdsa);
+               key->ecdsa = NULL;
        }
-       if (EC_KEY_set_public_key(key->ecdsa, q) != 1) {
-               /* XXX assume it is a allocation error */
-               ret = SSH_ERR_ALLOC_FAIL;
+       return r;
+}
+
+static int
+ssh_ecdsa_deserialize_private(const char *ktype, struct sshbuf *b,
+    struct sshkey *key)
+{
+       int r;
+       BIGNUM *exponent = NULL;
+
+       if (!sshkey_is_cert(key)) {
+               if ((r = ssh_ecdsa_deserialize_public(ktype, b, key)) != 0)
+                       return r;
+       }
+       if ((r = sshbuf_get_bignum2(b, &exponent)) != 0)
+               goto out;
+       if (EC_KEY_set_private_key(key->ecdsa, exponent) != 1) {
+               r = SSH_ERR_LIBCRYPTO_ERROR;
                goto out;
        }
-#ifdef DEBUG_PK
-       sshkey_dump_ec_point(EC_KEY_get0_group(key->ecdsa), q);
-#endif
+       if ((r = sshkey_ec_validate_private(key->ecdsa)) != 0)
+               goto out;
        /* success */
-       ret = 0;
+       r = 0;
  out:
-       free(curve);
-       EC_POINT_free(q);
-       return ret;
+       BN_clear_free(exponent);
+       return r;
 }
 
 /* ARGSUSED */
@@ -359,6 +378,7 @@ const struct sshkey_impl_funcs sshkey_ecdsa_funcs = {
        /* .ssh_serialize_public = */ ssh_ecdsa_serialize_public,
        /* .ssh_deserialize_public = */ ssh_ecdsa_deserialize_public,
        /* .ssh_serialize_private = */ ssh_ecdsa_serialize_private,
+       /* .ssh_deserialize_private = */ ssh_ecdsa_deserialize_private,
        /* .generate = */       ssh_ecdsa_generate,
        /* .copy_public = */    ssh_ecdsa_copy_public,
        /* .sign = */           ssh_ecdsa_sign,
index b849c11..e0eb8dd 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: ssh-ed25519-sk.c,v 1.14 2022/10/28 00:44:17 djm Exp $ */
+/* $OpenBSD: ssh-ed25519-sk.c,v 1.15 2022/10/28 00:44:44 djm Exp $ */
 /*
  * Copyright (c) 2019 Markus Friedl.  All rights reserved.
  *
@@ -106,6 +106,19 @@ ssh_ed25519_sk_deserialize_public(const char *ktype, struct sshbuf *b,
        return 0;
 }
 
+static int
+ssh_ed25519_sk_deserialize_private(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_private_deserialize_sk(b, key)) != 0)
+               return r;
+       return 0;
+}
+
 static int
 ssh_ed25519_sk_verify(const struct sshkey *key,
     const u_char *sig, size_t siglen,
@@ -241,6 +254,7 @@ static const struct sshkey_impl_funcs sshkey_ed25519_sk_funcs = {
        /* .ssh_serialize_public = */ ssh_ed25519_sk_serialize_public,
        /* .ssh_deserialize_public = */ ssh_ed25519_sk_deserialize_public,
        /* .ssh_serialize_private = */ ssh_ed25519_sk_serialize_private,
+       /* .ssh_deserialize_private = */ ssh_ed25519_sk_deserialize_private,
        /* .generate = */       NULL,
        /* .copy_public = */    ssh_ed25519_sk_copy_public,
        /* .sign = */           NULL,
index 7eba617..06c6a04 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: ssh-ed25519.c,v 1.18 2022/10/28 00:44:17 djm Exp $ */
+/* $OpenBSD: ssh-ed25519.c,v 1.19 2022/10/28 00:44:44 djm Exp $ */
 /*
  * Copyright (c) 2013 Markus Friedl <markus@openbsd.org>
  *
@@ -114,6 +114,31 @@ ssh_ed25519_deserialize_public(const char *ktype, struct sshbuf *b,
        return 0;
 }
 
+static int
+ssh_ed25519_deserialize_private(const char *ktype, struct sshbuf *b,
+    struct sshkey *key)
+{
+       int r;
+       size_t sklen = 0;
+       u_char *ed25519_sk = NULL;
+
+       if ((r = ssh_ed25519_deserialize_public(NULL, b, key)) != 0)
+               goto out;
+       if ((r = sshbuf_get_string(b, &ed25519_sk, &sklen)) != 0)
+               goto out;
+       if (sklen != ED25519_SK_SZ) {
+               r = SSH_ERR_INVALID_FORMAT;
+               goto out;
+       }
+       key->ed25519_sk = ed25519_sk;
+       ed25519_sk = NULL; /* transferred */
+       /* success */
+       r = 0;
+ out:
+       freezero(ed25519_sk, sklen);
+       return r;
+}
+
 static int
 ssh_ed25519_sign(struct sshkey *key,
     u_char **sigp, size_t *lenp,
@@ -253,6 +278,7 @@ const struct sshkey_impl_funcs sshkey_ed25519_funcs = {
        /* .ssh_serialize_public = */ ssh_ed25519_serialize_public,
        /* .ssh_deserialize_public = */ ssh_ed25519_deserialize_public,
        /* .ssh_serialize_private = */ ssh_ed25519_serialize_private,
+       /* .ssh_deserialize_private = */ ssh_ed25519_deserialize_private,
        /* .generate = */       ssh_ed25519_generate,
        /* .copy_public = */    ssh_ed25519_copy_public,
        /* .sign = */           ssh_ed25519_sign,
index cbb8600..31c9add 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: ssh-rsa.c,v 1.76 2022/10/28 00:44:17 djm Exp $ */
+/* $OpenBSD: ssh-rsa.c,v 1.77 2022/10/28 00:44:44 djm Exp $ */
 /*
  * Copyright (c) 2000, 2003 Markus Friedl <markus@openbsd.org>
  *
@@ -226,6 +226,60 @@ ssh_rsa_deserialize_public(const char *ktype, struct sshbuf *b,
        return ret;
 }
 
+static int
+ssh_rsa_deserialize_private(const char *ktype, struct sshbuf *b,
+    struct sshkey *key)
+{
+       int r;
+       BIGNUM *rsa_n = NULL, *rsa_e = NULL, *rsa_d = NULL;
+       BIGNUM *rsa_iqmp = NULL, *rsa_p = NULL, *rsa_q = NULL;
+
+       /* Note: can't reuse ssh_rsa_deserialize_public: e, n vs. n, e */
+       if (!sshkey_is_cert(key)) {
+               if ((r = sshbuf_get_bignum2(b, &rsa_n)) != 0 ||
+                   (r = sshbuf_get_bignum2(b, &rsa_e)) != 0)
+                       goto out;
+               if (!RSA_set0_key(key->rsa, rsa_n, rsa_e, NULL)) {
+                       r = SSH_ERR_LIBCRYPTO_ERROR;
+                       goto out;
+               }
+               rsa_n = rsa_e = NULL; /* transferred */
+       }
+       if ((r = sshbuf_get_bignum2(b, &rsa_d)) != 0 ||
+           (r = sshbuf_get_bignum2(b, &rsa_iqmp)) != 0 ||
+           (r = sshbuf_get_bignum2(b, &rsa_p)) != 0 ||
+           (r = sshbuf_get_bignum2(b, &rsa_q)) != 0)
+               goto out;
+       if (!RSA_set0_key(key->rsa, NULL, NULL, rsa_d)) {
+               r = SSH_ERR_LIBCRYPTO_ERROR;
+               goto out;
+       }
+       rsa_d = NULL; /* transferred */
+       if (!RSA_set0_factors(key->rsa, rsa_p, rsa_q)) {
+               r = SSH_ERR_LIBCRYPTO_ERROR;
+               goto out;
+       }
+       rsa_p = rsa_q = NULL; /* transferred */
+       if ((r = sshkey_check_rsa_length(key, 0)) != 0)
+               goto out;
+       if ((r = ssh_rsa_complete_crt_parameters(key, rsa_iqmp)) != 0)
+               goto out;
+       if (RSA_blinding_on(key->rsa, NULL) != 1) {
+               r = SSH_ERR_LIBCRYPTO_ERROR;
+               goto out;
+       }
+       /* success */
+       r = 0;
+ out:
+       BN_clear_free(rsa_n);
+       BN_clear_free(rsa_e);
+       BN_clear_free(rsa_d);
+       BN_clear_free(rsa_p);
+       BN_clear_free(rsa_q);
+       BN_clear_free(rsa_iqmp);
+       return r;
+}
+
 static const char *
 rsa_hash_alg_ident(int hash_alg)
 {
@@ -645,6 +699,7 @@ static const struct sshkey_impl_funcs sshkey_rsa_funcs = {
        /* .ssh_serialize_public = */ ssh_rsa_serialize_public,
        /* .ssh_deserialize_public = */ ssh_rsa_deserialize_public,
        /* .ssh_serialize_private = */ ssh_rsa_serialize_private,
+       /* .ssh_deserialize_private = */ ssh_rsa_deserialize_private,
        /* .generate = */       ssh_rsa_generate,
        /* .copy_public = */    ssh_rsa_copy_public,
        /* .sign = */           ssh_rsa_sign,
index 2bd2988..5601b33 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: ssh-xmss.c,v 1.13 2022/10/28 00:44:17 djm Exp $*/
+/* $OpenBSD: ssh-xmss.c,v 1.14 2022/10/28 00:44:44 djm Exp $*/
 /*
  * Copyright (c) 2017 Stefan-Lukas Gazdag.
  * Copyright (c) 2017 Markus Friedl.
@@ -155,6 +155,43 @@ ssh_xmss_deserialize_public(const char *ktype, struct sshbuf *b,
        return ret;
 }
 
+static int
+ssh_xmss_deserialize_private(const char *ktype, struct sshbuf *b,
+    struct sshkey *key)
+{
+       int r;
+       char *xmss_name = NULL;
+       size_t pklen = 0, sklen = 0;
+       u_char *xmss_pk = NULL, *xmss_sk = NULL;
+
+       /* Note: can't reuse ssh_xmss_deserialize_public because of sk order */
+       if ((r = sshbuf_get_cstring(b, &xmss_name, NULL)) != 0 ||
+           (r = sshbuf_get_string(b, &xmss_pk, &pklen)) != 0 ||
+           (r = sshbuf_get_string(b, &xmss_sk, &sklen)) != 0)
+               goto out;
+       if (!sshkey_is_cert(key) &&
+           (r = sshkey_xmss_init(key, xmss_name)) != 0)
+               goto out;
+       if (pklen != sshkey_xmss_pklen(key) ||
+           sklen != sshkey_xmss_sklen(key)) {
+               r = SSH_ERR_INVALID_FORMAT;
+               goto out;
+       }
+       key->xmss_pk = xmss_pk;
+       key->xmss_sk = xmss_sk;
+       xmss_pk = xmss_sk = NULL;
+       /* optional internal state */
+       if ((r = sshkey_xmss_deserialize_state_opt(key, b)) != 0)
+               goto out;
+       /* success */
+       r = 0;
+ out:
+       free(xmss_name);
+       freezero(xmss_pk, pklen);
+       freezero(xmss_sk, sklen);
+       return r;
+}
+
 static int
 ssh_xmss_sign(struct sshkey *key,
     u_char **sigp, size_t *lenp,
@@ -314,6 +351,7 @@ static const struct sshkey_impl_funcs sshkey_xmss_funcs = {
        /* .ssh_serialize_public = */ ssh_xmss_serialize_public,
        /* .ssh_deserialize_public = */ ssh_xmss_deserialize_public,
        /* .ssh_serialize_private = */ ssh_xmss_serialize_private,
+       /* .ssh_deserialize_private = */ ssh_xmss_deserialize_private,
        /* .generate = */       sshkey_xmss_generate_private_key,
        /* .copy_public = */    ssh_xmss_copy_public,
        /* .sign = */           ssh_xmss_sign,
index 0644d59..c61b4e2 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: sshkey.c,v 1.132 2022/10/28 00:44:17 djm Exp $ */
+/* $OpenBSD: sshkey.c,v 1.133 2022/10/28 00:44:44 djm Exp $ */
 /*
  * Copyright (c) 2000, 2001 Markus Friedl.  All rights reserved.
  * Copyright (c) 2008 Alexander von Gernler.  All rights reserved.
@@ -2430,24 +2430,33 @@ sshkey_private_serialize(struct sshkey *key, struct sshbuf *b)
            SSHKEY_SERIALIZE_DEFAULT);
 }
 
+/* Shared deserialization of FIDO private key components */
+int
+sshkey_private_deserialize_sk(struct sshbuf *buf, struct sshkey *k)
+{
+       int r;
+
+       if ((k->sk_key_handle = sshbuf_new()) == NULL ||
+           (k->sk_reserved = sshbuf_new()) == NULL)
+               return SSH_ERR_ALLOC_FAIL;
+       if ((r = sshbuf_get_cstring(buf, &k->sk_application, NULL)) != 0 ||
+           (r = sshbuf_get_u8(buf, &k->sk_flags)) != 0 ||
+           (r = sshbuf_get_stringb(buf, k->sk_key_handle)) != 0 ||
+           (r = sshbuf_get_stringb(buf, k->sk_reserved)) != 0)
+               return r;
+
+       return 0;
+}
+
 int
 sshkey_private_deserialize(struct sshbuf *buf, struct sshkey **kp)
 {
-       char *tname = NULL, *curve = NULL, *xmss_name = NULL;
+       const struct sshkey_impl *impl;
+       char *tname = NULL;
        char *expect_sk_application = NULL;
+       u_char *expect_ed25519_pk = NULL;
        struct sshkey *k = NULL;
-       size_t pklen = 0, sklen = 0;
        int type, r = SSH_ERR_INTERNAL_ERROR;
-       u_char *ed25519_pk = NULL, *ed25519_sk = NULL;
-       u_char *expect_ed25519_pk = NULL;
-       u_char *xmss_pk = NULL, *xmss_sk = NULL;
-#ifdef WITH_OPENSSL
-       BIGNUM *exponent = NULL;
-       BIGNUM *rsa_n = NULL, *rsa_e = NULL, *rsa_d = NULL;
-       BIGNUM *rsa_iqmp = NULL, *rsa_p = NULL, *rsa_q = NULL;
-       BIGNUM *dsa_p = NULL, *dsa_q = NULL, *dsa_g = NULL;
-       BIGNUM *dsa_pub_key = NULL, *dsa_priv_key = NULL;
-#endif /* WITH_OPENSSL */
 
        if (kp != NULL)
                *kp = NULL;
@@ -2480,225 +2489,21 @@ sshkey_private_deserialize(struct sshbuf *buf, struct sshkey **kp)
                expect_ed25519_pk = k->ed25519_pk;
                k->sk_application = NULL;
                k->ed25519_pk = NULL;
+               /* XXX xmss too or refactor */
        } else {
                if ((k = sshkey_new(type)) == NULL) {
                        r = SSH_ERR_ALLOC_FAIL;
                        goto out;
                }
        }
-       switch (type) {
-#ifdef WITH_OPENSSL
-       case KEY_DSA:
-               if ((r = sshbuf_get_bignum2(buf, &dsa_p)) != 0 ||
-                   (r = sshbuf_get_bignum2(buf, &dsa_q)) != 0 ||
-                   (r = sshbuf_get_bignum2(buf, &dsa_g)) != 0 ||
-                   (r = sshbuf_get_bignum2(buf, &dsa_pub_key)) != 0)
-                       goto out;
-               if (!DSA_set0_pqg(k->dsa, dsa_p, dsa_q, dsa_g)) {
-                       r = SSH_ERR_LIBCRYPTO_ERROR;
-                       goto out;
-               }
-               dsa_p = dsa_q = dsa_g = NULL; /* transferred */
-               if (!DSA_set0_key(k->dsa, dsa_pub_key, NULL)) {
-                       r = SSH_ERR_LIBCRYPTO_ERROR;
-                       goto out;
-               }
-               dsa_pub_key = NULL; /* transferred */
-               /* FALLTHROUGH */
-       case KEY_DSA_CERT:
-               if ((r = sshbuf_get_bignum2(buf, &dsa_priv_key)) != 0)
-                       goto out;
-               if (!DSA_set0_key(k->dsa, NULL, dsa_priv_key)) {
-                       r = SSH_ERR_LIBCRYPTO_ERROR;
-                       goto out;
-               }
-               dsa_priv_key = NULL; /* transferred */
-               break;
-       case KEY_ECDSA:
-               if ((k->ecdsa_nid = sshkey_ecdsa_nid_from_name(tname)) == -1) {
-                       r = SSH_ERR_INVALID_ARGUMENT;
-                       goto out;
-               }
-               if ((r = sshbuf_get_cstring(buf, &curve, NULL)) != 0)
-                       goto out;
-               if (k->ecdsa_nid != sshkey_curve_name_to_nid(curve)) {
-                       r = SSH_ERR_EC_CURVE_MISMATCH;
-                       goto out;
-               }
-               k->ecdsa = EC_KEY_new_by_curve_name(k->ecdsa_nid);
-               if (k->ecdsa  == NULL) {
-                       r = SSH_ERR_LIBCRYPTO_ERROR;
-                       goto out;
-               }
-               if ((r = sshbuf_get_eckey(buf, k->ecdsa)) != 0)
-                       goto out;
-               /* FALLTHROUGH */
-       case KEY_ECDSA_CERT:
-               if ((r = sshbuf_get_bignum2(buf, &exponent)) != 0)
-                       goto out;
-               if (EC_KEY_set_private_key(k->ecdsa, exponent) != 1) {
-                       r = SSH_ERR_LIBCRYPTO_ERROR;
-                       goto out;
-               }
-               if ((r = sshkey_ec_validate_public(EC_KEY_get0_group(k->ecdsa),
-                   EC_KEY_get0_public_key(k->ecdsa))) != 0 ||
-                   (r = sshkey_ec_validate_private(k->ecdsa)) != 0)
-                       goto out;
-               break;
-       case KEY_ECDSA_SK:
-               if ((k->ecdsa_nid = sshkey_ecdsa_nid_from_name(tname)) == -1) {
-                       r = SSH_ERR_INVALID_ARGUMENT;
-                       goto out;
-               }
-               if ((r = sshbuf_get_cstring(buf, &curve, NULL)) != 0)
-                       goto out;
-               if (k->ecdsa_nid != sshkey_curve_name_to_nid(curve)) {
-                       r = SSH_ERR_EC_CURVE_MISMATCH;
-                       goto out;
-               }
-               if ((k->sk_key_handle = sshbuf_new()) == NULL ||
-                   (k->sk_reserved = sshbuf_new()) == NULL) {
-                       r = SSH_ERR_ALLOC_FAIL;
-                       goto out;
-               }
-               k->ecdsa = EC_KEY_new_by_curve_name(k->ecdsa_nid);
-               if (k->ecdsa  == NULL) {
-                       r = SSH_ERR_LIBCRYPTO_ERROR;
-                       goto out;
-               }
-               if ((r = sshbuf_get_eckey(buf, k->ecdsa)) != 0 ||
-                   (r = sshbuf_get_cstring(buf, &k->sk_application,
-                   NULL)) != 0 ||
-                   (r = sshbuf_get_u8(buf, &k->sk_flags)) != 0 ||
-                   (r = sshbuf_get_stringb(buf, k->sk_key_handle)) != 0 ||
-                   (r = sshbuf_get_stringb(buf, k->sk_reserved)) != 0)
-                       goto out;
-               if ((r = sshkey_ec_validate_public(EC_KEY_get0_group(k->ecdsa),
-                   EC_KEY_get0_public_key(k->ecdsa))) != 0)
-                       goto out;
-               break;
-       case KEY_ECDSA_SK_CERT:
-               if ((k->sk_key_handle = sshbuf_new()) == NULL ||
-                   (k->sk_reserved = sshbuf_new()) == NULL) {
-                       r = SSH_ERR_ALLOC_FAIL;
-                       goto out;
-               }
-               if ((r = sshbuf_get_cstring(buf, &k->sk_application,
-                   NULL)) != 0 ||
-                   (r = sshbuf_get_u8(buf, &k->sk_flags)) != 0 ||
-                   (r = sshbuf_get_stringb(buf, k->sk_key_handle)) != 0 ||
-                   (r = sshbuf_get_stringb(buf, k->sk_reserved)) != 0)
-                       goto out;
-               if ((r = sshkey_ec_validate_public(EC_KEY_get0_group(k->ecdsa),
-                   EC_KEY_get0_public_key(k->ecdsa))) != 0)
-                       goto out;
-               break;
-       case KEY_RSA:
-               if ((r = sshbuf_get_bignum2(buf, &rsa_n)) != 0 ||
-                   (r = sshbuf_get_bignum2(buf, &rsa_e)) != 0)
-                       goto out;
-               if (!RSA_set0_key(k->rsa, rsa_n, rsa_e, NULL)) {
-                       r = SSH_ERR_LIBCRYPTO_ERROR;
-                       goto out;
-               }
-               rsa_n = rsa_e = NULL; /* transferred */
-               /* FALLTHROUGH */
-       case KEY_RSA_CERT:
-               if ((r = sshbuf_get_bignum2(buf, &rsa_d)) != 0 ||
-                   (r = sshbuf_get_bignum2(buf, &rsa_iqmp)) != 0 ||
-                   (r = sshbuf_get_bignum2(buf, &rsa_p)) != 0 ||
-                   (r = sshbuf_get_bignum2(buf, &rsa_q)) != 0)
-                       goto out;
-               if (!RSA_set0_key(k->rsa, NULL, NULL, rsa_d)) {
-                       r = SSH_ERR_LIBCRYPTO_ERROR;
-                       goto out;
-               }
-               rsa_d = NULL; /* transferred */
-               if (!RSA_set0_factors(k->rsa, rsa_p, rsa_q)) {
-                       r = SSH_ERR_LIBCRYPTO_ERROR;
-                       goto out;
-               }
-               rsa_p = rsa_q = NULL; /* transferred */
-               if ((r = sshkey_check_rsa_length(k, 0)) != 0)
-                       goto out;
-               if ((r = ssh_rsa_complete_crt_parameters(k, rsa_iqmp)) != 0)
-                       goto out;
-               break;
-#endif /* WITH_OPENSSL */
-       case KEY_ED25519:
-       case KEY_ED25519_CERT:
-               if ((r = sshbuf_get_string(buf, &ed25519_pk, &pklen)) != 0 ||
-                   (r = sshbuf_get_string(buf, &ed25519_sk, &sklen)) != 0)
-                       goto out;
-               if (pklen != ED25519_PK_SZ || sklen != ED25519_SK_SZ) {
-                       r = SSH_ERR_INVALID_FORMAT;
-                       goto out;
-               }
-               k->ed25519_pk = ed25519_pk;
-               k->ed25519_sk = ed25519_sk;
-               ed25519_pk = ed25519_sk = NULL; /* transferred */
-               break;
-       case KEY_ED25519_SK:
-       case KEY_ED25519_SK_CERT:
-               if ((r = sshbuf_get_string(buf, &ed25519_pk, &pklen)) != 0)
-                       goto out;
-               if (pklen != ED25519_PK_SZ) {
-                       r = SSH_ERR_INVALID_FORMAT;
-                       goto out;
-               }
-               if ((k->sk_key_handle = sshbuf_new()) == NULL ||
-                   (k->sk_reserved = sshbuf_new()) == NULL) {
-                       r = SSH_ERR_ALLOC_FAIL;
-                       goto out;
-               }
-               if ((r = sshbuf_get_cstring(buf, &k->sk_application,
-                   NULL)) != 0 ||
-                   (r = sshbuf_get_u8(buf, &k->sk_flags)) != 0 ||
-                   (r = sshbuf_get_stringb(buf, k->sk_key_handle)) != 0 ||
-                   (r = sshbuf_get_stringb(buf, k->sk_reserved)) != 0)
-                       goto out;
-               k->ed25519_pk = ed25519_pk;
-               ed25519_pk = NULL; /* transferred */
-               break;
-#ifdef WITH_XMSS
-       case KEY_XMSS:
-       case KEY_XMSS_CERT:
-               if ((r = sshbuf_get_cstring(buf, &xmss_name, NULL)) != 0 ||
-                   (r = sshbuf_get_string(buf, &xmss_pk, &pklen)) != 0 ||
-                   (r = sshbuf_get_string(buf, &xmss_sk, &sklen)) != 0)
-                       goto out;
-               if (type == KEY_XMSS &&
-                   (r = sshkey_xmss_init(k, xmss_name)) != 0)
-                       goto out;
-               if (pklen != sshkey_xmss_pklen(k) ||
-                   sklen != sshkey_xmss_sklen(k)) {
-                       r = SSH_ERR_INVALID_FORMAT;
-                       goto out;
-               }
-               k->xmss_pk = xmss_pk;
-               k->xmss_sk = xmss_sk;
-               xmss_pk = xmss_sk = NULL;
-               /* optional internal state */
-               if ((r = sshkey_xmss_deserialize_state_opt(k, buf)) != 0)
-                       goto out;
-               break;
-#endif /* WITH_XMSS */
-       default:
-               r = SSH_ERR_KEY_TYPE_UNKNOWN;
+       if ((impl = sshkey_impl_from_type(type)) == NULL) {
+               r = SSH_ERR_INTERNAL_ERROR;
                goto out;
        }
-#ifdef WITH_OPENSSL
-       /* enable blinding */
-       switch (k->type) {
-       case KEY_RSA:
-       case KEY_RSA_CERT:
-               if (RSA_blinding_on(k->rsa, NULL) != 1) {
-                       r = SSH_ERR_LIBCRYPTO_ERROR;
-                       goto out;
-               }
-               break;
-       }
-#endif /* WITH_OPENSSL */
+       if ((r = impl->funcs->deserialize_private(tname, buf, k)) != 0)
+               goto out;
+
+       /* XXX xmss too or refactor */
        if ((expect_sk_application != NULL && (k->sk_application == NULL ||
            strcmp(expect_sk_application, k->sk_application) != 0)) ||
            (expect_ed25519_pk != NULL && (k->ed25519_pk == NULL ||
@@ -2714,27 +2519,7 @@ sshkey_private_deserialize(struct sshbuf *buf, struct sshkey **kp)
        }
  out:
        free(tname);
-       free(curve);
-#ifdef WITH_OPENSSL
-       BN_clear_free(exponent);
-       BN_clear_free(dsa_p);
-       BN_clear_free(dsa_q);
-       BN_clear_free(dsa_g);
-       BN_clear_free(dsa_pub_key);
-       BN_clear_free(dsa_priv_key);
-       BN_clear_free(rsa_n);
-       BN_clear_free(rsa_e);
-       BN_clear_free(rsa_d);
-       BN_clear_free(rsa_p);
-       BN_clear_free(rsa_q);
-       BN_clear_free(rsa_iqmp);
-#endif /* WITH_OPENSSL */
        sshkey_free(k);
-       freezero(ed25519_pk, pklen);
-       freezero(ed25519_sk, sklen);
-       free(xmss_name);
-       freezero(xmss_pk, pklen);
-       freezero(xmss_sk, sklen);
        free(expect_sk_application);
        free(expect_ed25519_pk);
        return r;
index ea37713..e90a1ee 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: sshkey.h,v 1.60 2022/10/28 00:44:17 djm Exp $ */
+/* $OpenBSD: sshkey.h,v 1.61 2022/10/28 00:44:44 djm Exp $ */
 
 /*
  * Copyright (c) 2000, 2001 Markus Friedl.  All rights reserved.
@@ -169,6 +169,8 @@ struct sshkey_impl_funcs {
            struct sshkey *);
        int (*serialize_private)(const struct sshkey *, struct sshbuf *,
            enum sshkey_serialize_rep);
+       int (*deserialize_private)(const char *, struct sshbuf *,
+           struct sshkey *);
        int (*generate)(struct sshkey *, int);  /* optional */
        int (*copy_public)(const struct sshkey *, struct sshkey *);
        int (*sign)(struct sshkey *, u_char **, size_t *,
@@ -322,6 +324,7 @@ int sshkey_copy_public_sk(const struct sshkey *from, struct sshkey *to);
 int    sshkey_deserialize_sk(struct sshbuf *b, struct sshkey *key);
 int    sshkey_serialize_private_sk(const struct sshkey *key,
     struct sshbuf *buf);
+int    sshkey_private_deserialize_sk(struct sshbuf *buf, struct sshkey *k);
 #ifdef WITH_OPENSSL
 int    check_rsa_length(const RSA *rsa); /* XXX remove */
 #endif