diff --git a/ssh-dss.c b/ssh-dss.c index 15d6cea39..e955fdd5e 100644 --- a/ssh-dss.c +++ b/ssh-dss.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh-dss.c,v 1.41 2022/10/28 00:36:31 djm Exp $ */ +/* $OpenBSD: ssh-dss.c,v 1.42 2022/10/28 00:37:24 djm Exp $ */ /* * Copyright (c) 2000 Markus Friedl. All rights reserved. * @@ -102,6 +102,30 @@ ssh_dss_equal(const struct sshkey *a, const struct sshkey *b) return 1; } +static int +ssh_dss_serialize_public(const struct sshkey *key, struct sshbuf *b, + const char *typename, enum sshkey_serialize_rep opts) +{ + int r; + const BIGNUM *dsa_p, *dsa_q, *dsa_g, *dsa_pub_key; + + if (key->dsa == NULL) + return SSH_ERR_INVALID_ARGUMENT; + DSA_get0_pqg(key->dsa, &dsa_p, &dsa_q, &dsa_g); + DSA_get0_key(key->dsa, &dsa_pub_key, NULL); + 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 || + (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) + return r; + + return 0; +} + int ssh_dss_sign(const struct sshkey *key, u_char **sigp, size_t *lenp, const u_char *data, size_t datalen, u_int compat) @@ -264,6 +288,7 @@ static const struct sshkey_impl_funcs sshkey_dss_funcs = { /* .alloc = */ ssh_dss_alloc, /* .cleanup = */ ssh_dss_cleanup, /* .equal = */ ssh_dss_equal, + /* .ssh_serialize_public = */ ssh_dss_serialize_public, }; const struct sshkey_impl sshkey_dss_impl = { diff --git a/ssh-ecdsa-sk.c b/ssh-ecdsa-sk.c index 77a577671..228e1b093 100644 --- a/ssh-ecdsa-sk.c +++ b/ssh-ecdsa-sk.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh-ecdsa-sk.c,v 1.10 2022/10/28 00:36:31 djm Exp $ */ +/* $OpenBSD: ssh-ecdsa-sk.c,v 1.11 2022/10/28 00:37:24 djm Exp $ */ /* * Copyright (c) 2000 Markus Friedl. All rights reserved. * Copyright (c) 2010 Damien Miller. All rights reserved. @@ -81,6 +81,21 @@ ssh_ecdsa_sk_equal(const struct sshkey *a, const struct sshkey *b) return 1; } +static int +ssh_ecdsa_sk_serialize_public(const struct sshkey *key, struct sshbuf *b, + const char *typename, enum sshkey_serialize_rep opts) +{ + int r; + + if ((r = sshkey_ecdsa_funcs.serialize_public(key, b, + typename, opts)) != 0) + return r; + if ((r = sshkey_serialize_sk(key, b)) != 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. @@ -346,6 +361,7 @@ static const struct sshkey_impl_funcs sshkey_ecdsa_sk_funcs = { /* .alloc = */ NULL, /* .cleanup = */ ssh_ecdsa_sk_cleanup, /* .equal = */ ssh_ecdsa_sk_equal, + /* .ssh_serialize_public = */ ssh_ecdsa_sk_serialize_public, }; const struct sshkey_impl sshkey_ecdsa_sk_impl = { diff --git a/ssh-ecdsa.c b/ssh-ecdsa.c index 85fa15c49..24f66bdc0 100644 --- a/ssh-ecdsa.c +++ b/ssh-ecdsa.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh-ecdsa.c,v 1.18 2022/10/28 00:36:31 djm Exp $ */ +/* $OpenBSD: ssh-ecdsa.c,v 1.19 2022/10/28 00:37:24 djm Exp $ */ /* * Copyright (c) 2000 Markus Friedl. All rights reserved. * Copyright (c) 2010 Damien Miller. All rights reserved. @@ -87,9 +87,27 @@ ssh_ecdsa_equal(const struct sshkey *a, const struct sshkey *b) return 0; if (EC_POINT_cmp(grp_a, pub_a, pub_b, NULL) != 0) return 0; + return 1; } +static int +ssh_ecdsa_serialize_public(const struct sshkey *key, struct sshbuf *b, + const char *typename, 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, + sshkey_curve_nid_to_name(key->ecdsa_nid))) != 0 || + (r = sshbuf_put_eckey(b, key->ecdsa)) != 0) + return r; + + return 0; +} + /* ARGSUSED */ int ssh_ecdsa_sign(const struct sshkey *key, u_char **sigp, size_t *lenp, @@ -248,6 +266,7 @@ const struct sshkey_impl_funcs sshkey_ecdsa_funcs = { /* .alloc = */ NULL, /* .cleanup = */ ssh_ecdsa_cleanup, /* .equal = */ ssh_ecdsa_equal, + /* .ssh_serialize_public = */ ssh_ecdsa_serialize_public, }; const struct sshkey_impl sshkey_ecdsa_nistp256_impl = { diff --git a/ssh-ed25519-sk.c b/ssh-ed25519-sk.c index 4c0fc7075..b95227c0f 100644 --- a/ssh-ed25519-sk.c +++ b/ssh-ed25519-sk.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh-ed25519-sk.c,v 1.8 2022/10/28 00:36:31 djm Exp $ */ +/* $OpenBSD: ssh-ed25519-sk.c,v 1.9 2022/10/28 00:37:24 djm Exp $ */ /* * Copyright (c) 2019 Markus Friedl. All rights reserved. * @@ -55,6 +55,21 @@ ssh_ed25519_sk_equal(const struct sshkey *a, const struct sshkey *b) return 1; } +static int +ssh_ed25519_sk_serialize_public(const struct sshkey *key, struct sshbuf *b, + const char *typename, enum sshkey_serialize_rep opts) +{ + int r; + + if ((r = sshkey_ed25519_funcs.serialize_public(key, b, + typename, opts)) != 0) + return r; + if ((r = sshkey_serialize_sk(key, b)) != 0) + return r; + + return 0; +} + int ssh_ed25519_sk_verify(const struct sshkey *key, const u_char *signature, size_t signaturelen, @@ -187,6 +202,7 @@ static const struct sshkey_impl_funcs sshkey_ed25519_sk_funcs = { /* .alloc = */ NULL, /* .cleanup = */ ssh_ed25519_sk_cleanup, /* .equal = */ ssh_ed25519_sk_equal, + /* .ssh_serialize_public = */ ssh_ed25519_sk_serialize_public, }; const struct sshkey_impl sshkey_ed25519_sk_impl = { diff --git a/ssh-ed25519.c b/ssh-ed25519.c index 712cc4022..72c850000 100644 --- a/ssh-ed25519.c +++ b/ssh-ed25519.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh-ed25519.c,v 1.12 2022/10/28 00:36:31 djm Exp $ */ +/* $OpenBSD: ssh-ed25519.c,v 1.13 2022/10/28 00:37:24 djm Exp $ */ /* * Copyright (c) 2013 Markus Friedl * @@ -51,6 +51,21 @@ ssh_ed25519_equal(const struct sshkey *a, const struct sshkey *b) return 1; } +static int +ssh_ed25519_serialize_public(const struct sshkey *key, struct sshbuf *b, + const char *typename, 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) + return r; + + 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) @@ -184,6 +199,7 @@ const struct sshkey_impl_funcs sshkey_ed25519_funcs = { /* .alloc = */ NULL, /* .cleanup = */ ssh_ed25519_cleanup, /* .equal = */ ssh_ed25519_equal, + /* .ssh_serialize_public = */ ssh_ed25519_serialize_public, }; const struct sshkey_impl sshkey_ed25519_impl = { diff --git a/ssh-rsa.c b/ssh-rsa.c index 345d9a8d0..4ece09f7b 100644 --- a/ssh-rsa.c +++ b/ssh-rsa.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh-rsa.c,v 1.70 2022/10/28 00:36:31 djm Exp $ */ +/* $OpenBSD: ssh-rsa.c,v 1.71 2022/10/28 00:37:24 djm Exp $ */ /* * Copyright (c) 2000, 2003 Markus Friedl * @@ -86,6 +86,24 @@ ssh_rsa_equal(const struct sshkey *a, const struct sshkey *b) return 1; } +static int +ssh_rsa_serialize_public(const struct sshkey *key, struct sshbuf *b, + const char *typename, enum sshkey_serialize_rep opts) +{ + int r; + const BIGNUM *rsa_n, *rsa_e; + + 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 || + (r = sshbuf_put_bignum2(b, rsa_n)) != 0) + return r; + + return 0; +} + static const char * rsa_hash_alg_ident(int hash_alg) { @@ -499,6 +517,7 @@ static const struct sshkey_impl_funcs sshkey_rsa_funcs = { /* .alloc = */ ssh_rsa_alloc, /* .cleanup = */ ssh_rsa_cleanup, /* .equal = */ ssh_rsa_equal, + /* .ssh_serialize_public = */ ssh_rsa_serialize_public, }; const struct sshkey_impl sshkey_rsa_impl = { diff --git a/ssh-xmss.c b/ssh-xmss.c index 2bc319797..7031baf9d 100644 --- a/ssh-xmss.c +++ b/ssh-xmss.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh-xmss.c,v 1.7 2022/10/28 00:36:31 djm Exp $*/ +/* $OpenBSD: ssh-xmss.c,v 1.8 2022/10/28 00:37:24 djm Exp $*/ /* * Copyright (c) 2017 Stefan-Lukas Gazdag. * Copyright (c) 2017 Markus Friedl. @@ -63,6 +63,25 @@ ssh_xmss_equal(const struct sshkey *a, const struct sshkey *b) return 1; } +static int +ssh_xmss_serialize_public(const struct sshkey *key, struct sshbuf *b, + const char *typename, 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 || + (r = sshbuf_put_string(b, key->xmss_pk, + sshkey_xmss_pklen(key))) != 0 || + (r = sshkey_xmss_serialize_pk_info(key, b, opts)) != 0) + return r; + + return 0; +} + int ssh_xmss_sign(const struct sshkey *key, u_char **sigp, size_t *lenp, const u_char *data, size_t datalen, u_int compat) @@ -216,6 +235,7 @@ static const struct sshkey_impl_funcs sshkey_xmss_funcs = { /* .alloc = */ NULL, /* .cleanup = */ ssh_xmss_cleanup, /* .equal = */ ssh_xmss_equal, + /* .ssh_serialize_public = */ ssh_xmss_serialize_public, }; const struct sshkey_impl sshkey_xmss_impl = { diff --git a/sshkey.c b/sshkey.c index 76bab4f99..b4130f2a7 100644 --- a/sshkey.c +++ b/sshkey.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sshkey.c,v 1.124 2022/10/28 00:36:31 djm Exp $ */ +/* $OpenBSD: sshkey.c,v 1.125 2022/10/28 00:37:24 djm Exp $ */ /* * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. * Copyright (c) 2008 Alexander von Gernler. All rights reserved. @@ -679,116 +679,47 @@ sshkey_equal(const struct sshkey *a, const struct sshkey *b) return sshkey_equal_public(a, b); } + +/* Serialise common FIDO key parts */ +int +sshkey_serialize_sk(const struct sshkey *key, struct sshbuf *b) +{ + int r; + + if ((r = sshbuf_put_cstring(b, key->sk_application)) != 0) + return r; + + return 0; +} + static int to_blob_buf(const struct sshkey *key, struct sshbuf *b, int force_plain, enum sshkey_serialize_rep opts) { int type, ret = SSH_ERR_INTERNAL_ERROR; const char *typename; -#ifdef WITH_OPENSSL - const BIGNUM *rsa_n, *rsa_e, *dsa_p, *dsa_q, *dsa_g, *dsa_pub_key; -#endif /* WITH_OPENSSL */ + const struct sshkey_impl *impl; if (key == NULL) return SSH_ERR_INVALID_ARGUMENT; - if (sshkey_is_cert(key)) { + type = force_plain ? sshkey_type_plain(key->type) : key->type; + + if (sshkey_type_is_cert(type)) { if (key->cert == NULL) return SSH_ERR_EXPECTED_CERT; if (sshbuf_len(key->cert->certblob) == 0) return SSH_ERR_KEY_LACKS_CERTBLOB; - } - type = force_plain ? sshkey_type_plain(key->type) : key->type; - typename = sshkey_ssh_name_from_type_nid(type, key->ecdsa_nid); - - switch (type) { -#ifdef WITH_OPENSSL - case KEY_DSA_CERT: - case KEY_ECDSA_CERT: - case KEY_ECDSA_SK_CERT: - case KEY_RSA_CERT: -#endif /* WITH_OPENSSL */ - case KEY_ED25519_CERT: - case KEY_ED25519_SK_CERT: -#ifdef WITH_XMSS - case KEY_XMSS_CERT: -#endif /* WITH_XMSS */ /* Use the existing blob */ - /* XXX modified flag? */ if ((ret = sshbuf_putb(b, key->cert->certblob)) != 0) return ret; - break; -#ifdef WITH_OPENSSL - case KEY_DSA: - if (key->dsa == NULL) - return SSH_ERR_INVALID_ARGUMENT; - DSA_get0_pqg(key->dsa, &dsa_p, &dsa_q, &dsa_g); - DSA_get0_key(key->dsa, &dsa_pub_key, NULL); - if ((ret = sshbuf_put_cstring(b, typename)) != 0 || - (ret = sshbuf_put_bignum2(b, dsa_p)) != 0 || - (ret = sshbuf_put_bignum2(b, dsa_q)) != 0 || - (ret = sshbuf_put_bignum2(b, dsa_g)) != 0 || - (ret = sshbuf_put_bignum2(b, dsa_pub_key)) != 0) - return ret; - break; -# ifdef OPENSSL_HAS_ECC - case KEY_ECDSA: - case KEY_ECDSA_SK: - if (key->ecdsa == NULL) - return SSH_ERR_INVALID_ARGUMENT; - if ((ret = sshbuf_put_cstring(b, typename)) != 0 || - (ret = sshbuf_put_cstring(b, - sshkey_curve_nid_to_name(key->ecdsa_nid))) != 0 || - (ret = sshbuf_put_eckey(b, key->ecdsa)) != 0) - return ret; - if (type == KEY_ECDSA_SK) { - if ((ret = sshbuf_put_cstring(b, - key->sk_application)) != 0) - return ret; - } - break; -# endif - case KEY_RSA: - if (key->rsa == NULL) - return SSH_ERR_INVALID_ARGUMENT; - RSA_get0_key(key->rsa, &rsa_n, &rsa_e, NULL); - if ((ret = sshbuf_put_cstring(b, typename)) != 0 || - (ret = sshbuf_put_bignum2(b, rsa_e)) != 0 || - (ret = sshbuf_put_bignum2(b, rsa_n)) != 0) - return ret; - break; -#endif /* WITH_OPENSSL */ - case KEY_ED25519: - case KEY_ED25519_SK: - if (key->ed25519_pk == NULL) - return SSH_ERR_INVALID_ARGUMENT; - if ((ret = sshbuf_put_cstring(b, typename)) != 0 || - (ret = sshbuf_put_string(b, - key->ed25519_pk, ED25519_PK_SZ)) != 0) - return ret; - if (type == KEY_ED25519_SK) { - if ((ret = sshbuf_put_cstring(b, - key->sk_application)) != 0) - return ret; - } - break; -#ifdef WITH_XMSS - case KEY_XMSS: - if (key->xmss_name == NULL || key->xmss_pk == NULL || - sshkey_xmss_pklen(key) == 0) - return SSH_ERR_INVALID_ARGUMENT; - if ((ret = sshbuf_put_cstring(b, typename)) != 0 || - (ret = sshbuf_put_cstring(b, key->xmss_name)) != 0 || - (ret = sshbuf_put_string(b, - key->xmss_pk, sshkey_xmss_pklen(key))) != 0 || - (ret = sshkey_xmss_serialize_pk_info(key, b, opts)) != 0) - return ret; - break; -#endif /* WITH_XMSS */ - default: - return SSH_ERR_KEY_TYPE_UNKNOWN; + return 0; } - return 0; + if ((impl = sshkey_impl_from_type(type)) == NULL) + 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); } int diff --git a/sshkey.h b/sshkey.h index b94e332e4..03d82aedf 100644 --- a/sshkey.h +++ b/sshkey.h @@ -1,4 +1,4 @@ -/* $OpenBSD: sshkey.h,v 1.54 2022/10/28 00:36:31 djm Exp $ */ +/* $OpenBSD: sshkey.h,v 1.55 2022/10/28 00:37:24 djm Exp $ */ /* * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. @@ -169,6 +169,8 @@ struct sshkey_impl_funcs { int (*alloc)(struct sshkey *); /* optional */ 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); }; struct sshkey_impl { @@ -309,6 +311,7 @@ void sshkey_sig_details_free(struct sshkey_sig_details *); #ifdef SSHKEY_INTERNAL 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 ssh_rsa_sign(const struct sshkey *key, u_char **sigp, size_t *lenp, const u_char *data, size_t datalen,