From: djm Date: Fri, 28 Oct 2022 00:44:44 +0000 (+0000) Subject: refactor sshkey_private_deserialize X-Git-Url: http://artulab.com/gitweb/?a=commitdiff_plain;h=a2c931d988e31395022f1322d85edf6de1b6b1db;p=openbsd refactor sshkey_private_deserialize feedback/ok markus@ --- diff --git a/usr.bin/ssh/ssh-dss.c b/usr.bin/ssh/ssh-dss.c index 85641e47c9a..de804585861 100644 --- a/usr.bin/ssh/ssh-dss.c +++ b/usr.bin/ssh/ssh-dss.c @@ -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, diff --git a/usr.bin/ssh/ssh-ecdsa-sk.c b/usr.bin/ssh/ssh-ecdsa-sk.c index fc53dba54e2..04b02e08dc4 100644 --- a/usr.bin/ssh/ssh-ecdsa-sk.c +++ b/usr.bin/ssh/ssh-ecdsa-sk.c @@ -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, diff --git a/usr.bin/ssh/ssh-ecdsa.c b/usr.bin/ssh/ssh-ecdsa.c index 8c08b232bc0..5677396feb1 100644 --- a/usr.bin/ssh/ssh-ecdsa.c +++ b/usr.bin/ssh/ssh-ecdsa.c @@ -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, diff --git a/usr.bin/ssh/ssh-ed25519-sk.c b/usr.bin/ssh/ssh-ed25519-sk.c index b849c11f877..e0eb8ddcc64 100644 --- a/usr.bin/ssh/ssh-ed25519-sk.c +++ b/usr.bin/ssh/ssh-ed25519-sk.c @@ -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, diff --git a/usr.bin/ssh/ssh-ed25519.c b/usr.bin/ssh/ssh-ed25519.c index 7eba61710db..06c6a04dc1a 100644 --- a/usr.bin/ssh/ssh-ed25519.c +++ b/usr.bin/ssh/ssh-ed25519.c @@ -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 * @@ -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, diff --git a/usr.bin/ssh/ssh-rsa.c b/usr.bin/ssh/ssh-rsa.c index cbb86001aef..31c9add11ac 100644 --- a/usr.bin/ssh/ssh-rsa.c +++ b/usr.bin/ssh/ssh-rsa.c @@ -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 * @@ -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, diff --git a/usr.bin/ssh/ssh-xmss.c b/usr.bin/ssh/ssh-xmss.c index 2bd29882003..5601b338fd9 100644 --- a/usr.bin/ssh/ssh-xmss.c +++ b/usr.bin/ssh/ssh-xmss.c @@ -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, diff --git a/usr.bin/ssh/sshkey.c b/usr.bin/ssh/sshkey.c index 0644d593a41..c61b4e2fb55 100644 --- a/usr.bin/ssh/sshkey.c +++ b/usr.bin/ssh/sshkey.c @@ -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; diff --git a/usr.bin/ssh/sshkey.h b/usr.bin/ssh/sshkey.h index ea3771393f7..e90a1eec8cb 100644 --- a/usr.bin/ssh/sshkey.h +++ b/usr.bin/ssh/sshkey.h @@ -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