From a1deb6cdbbe6afaab74ecb08fcb62db5739267be Mon Sep 17 00:00:00 2001 From: "djm@openbsd.org" Date: Fri, 28 Oct 2022 00:41:52 +0000 Subject: [PATCH] upstream: refactor sshkey_from_blob_internal() feedback/ok markus@ OpenBSD-Commit-ID: 1f46c0cbb8060ee9666a02749594ad6658c8e283 --- ssh-dss.c | 45 ++++++++- ssh-ecdsa-sk.c | 21 +++- ssh-ecdsa.c | 58 ++++++++++- ssh-ed25519-sk.c | 21 +++- ssh-ed25519.c | 26 ++++- ssh-rsa.c | 58 ++++++++++- ssh-xmss.c | 40 +++++++- sshkey.c | 258 +++++------------------------------------------ sshkey.h | 10 +- 9 files changed, 273 insertions(+), 264 deletions(-) diff --git a/ssh-dss.c b/ssh-dss.c index 16a8b25e5..baf3cfb1b 100644 --- a/ssh-dss.c +++ b/ssh-dss.c @@ -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. * @@ -104,7 +104,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; @@ -116,8 +116,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) @@ -181,6 +180,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) @@ -344,6 +380,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, }; diff --git a/ssh-ecdsa-sk.c b/ssh-ecdsa-sk.c index 2a67df8a4..cb8bcef1e 100644 --- a/ssh-ecdsa-sk.c +++ b/ssh-ecdsa-sk.c @@ -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. @@ -83,12 +83,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; @@ -108,6 +107,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. @@ -374,6 +386,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, }; diff --git a/ssh-ecdsa.c b/ssh-ecdsa.c index 271285c9f..e584cb792 100644 --- a/ssh-ecdsa.c +++ b/ssh-ecdsa.c @@ -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. @@ -93,14 +93,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; @@ -138,6 +137,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, @@ -297,6 +346,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, }; diff --git a/ssh-ed25519-sk.c b/ssh-ed25519-sk.c index b04d06905..eba835d91 100644 --- a/ssh-ed25519-sk.c +++ b/ssh-ed25519-sk.c @@ -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. * @@ -57,12 +57,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; @@ -82,6 +81,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, @@ -215,6 +227,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, }; diff --git a/ssh-ed25519.c b/ssh-ed25519.c index 1b37760d0..1556641df 100644 --- a/ssh-ed25519.c +++ b/ssh-ed25519.c @@ -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 * @@ -53,14 +53,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; @@ -87,6 +86,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) @@ -221,6 +238,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, }; diff --git a/ssh-rsa.c b/ssh-rsa.c index 10585387e..cbea0d299 100644 --- a/ssh-rsa.c +++ b/ssh-rsa.c @@ -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 * @@ -39,6 +39,26 @@ 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) { @@ -88,7 +108,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; @@ -96,8 +116,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; @@ -158,6 +177,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) { @@ -572,6 +621,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, }; diff --git a/ssh-xmss.c b/ssh-xmss.c index ef0fed167..039436b43 100644 --- a/ssh-xmss.c +++ b/ssh-xmss.c @@ -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. @@ -65,15 +65,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) @@ -107,6 +106,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) @@ -261,6 +292,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, }; diff --git a/sshkey.c b/sshkey.c index 93debae36..69b993b0b 100644 --- a/sshkey.c +++ b/sshkey.c @@ -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. @@ -734,7 +734,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 @@ -1833,21 +1835,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; } @@ -1856,18 +1848,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; -#if defined(WITH_OPENSSL) - BIGNUM *rsa_n = NULL, *rsa_e = NULL; - BIGNUM *dsa_p = NULL, *dsa_q = NULL, *dsa_g = NULL, *dsa_pub_key = NULL; -# if defined(OPENSSL_HAS_ECC) - EC_POINT *q = NULL; -# endif /* OPENSSL_HAS_ECC */ -#endif /* WITH_OPENSSL */ + const struct sshkey_impl *impl; #ifdef DEBUG_PK /* XXX */ sshbuf_dump(b, stderr); @@ -1888,203 +1872,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; -# ifdef OPENSSL_HAS_ECC - 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 /* OPENSSL_HAS_ECC */ -#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 (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: + 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; + } + } + 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) @@ -2102,21 +1906,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); -#if defined(WITH_OPENSSL) - 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); -# if defined(OPENSSL_HAS_ECC) - EC_POINT_free(q); -# endif /* OPENSSL_HAS_ECC */ -#endif /* WITH_OPENSSL */ return ret; } diff --git a/sshkey.h b/sshkey.h index abf92149e..5d9e9df3a 100644 --- a/sshkey.h +++ b/sshkey.h @@ -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. @@ -170,7 +170,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 *); }; @@ -315,6 +317,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,