upstream: refactor sshkey_from_blob_internal()

feedback/ok markus@

OpenBSD-Commit-ID: 1f46c0cbb8060ee9666a02749594ad6658c8e283
This commit is contained in:
djm@openbsd.org 2022-10-28 00:41:52 +00:00 committed by Damien Miller
parent 7d00799c93
commit a1deb6cdbb
No known key found for this signature in database
9 changed files with 273 additions and 264 deletions

View 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.
*
@ -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,
};

View 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.
@ -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,
};

View 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.
@ -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,
};

View 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.
*
@ -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,
};

View 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>
*
@ -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,
};

View 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>
*
@ -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,
};

View 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.
@ -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,
};

258
sshkey.c
View 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.
@ -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;
}

View 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.
@ -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,