You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
207 lines
7.0 KiB
207 lines
7.0 KiB
diff --color -ru a/clientloop.c b/clientloop.c |
|
--- a/clientloop.c 2022-06-29 16:35:06.677597259 +0200 |
|
+++ b/clientloop.c 2022-06-29 16:40:29.737926205 +0200 |
|
@@ -116,6 +116,9 @@ |
|
#include "ssh-gss.h" |
|
#endif |
|
|
|
+/* Permitted RSA signature algorithms for UpdateHostkeys proofs */ |
|
+#define HOSTKEY_PROOF_RSA_ALGS "rsa-sha2-512,rsa-sha2-256" |
|
+ |
|
/* import options */ |
|
extern Options options; |
|
|
|
@@ -2110,8 +2113,10 @@ |
|
struct hostkeys_update_ctx *ctx = (struct hostkeys_update_ctx *)_ctx; |
|
size_t i, ndone; |
|
struct sshbuf *signdata; |
|
- int r, kexsigtype, use_kexsigtype; |
|
+ int r, plaintype; |
|
const u_char *sig; |
|
+ const char *rsa_kexalg = NULL; |
|
+ char *alg = NULL; |
|
size_t siglen; |
|
|
|
if (ctx->nnew == 0) |
|
@@ -2122,9 +2127,9 @@ |
|
hostkeys_update_ctx_free(ctx); |
|
return; |
|
} |
|
- kexsigtype = sshkey_type_plain( |
|
- sshkey_type_from_name(ssh->kex->hostkey_alg)); |
|
- |
|
+ if (sshkey_type_plain(sshkey_type_from_name( |
|
+ ssh->kex->hostkey_alg)) == KEY_RSA) |
|
+ rsa_kexalg = ssh->kex->hostkey_alg; |
|
if ((signdata = sshbuf_new()) == NULL) |
|
fatal_f("sshbuf_new failed"); |
|
/* |
|
@@ -2135,6 +2140,7 @@ |
|
for (ndone = i = 0; i < ctx->nkeys; i++) { |
|
if (ctx->keys_match[i]) |
|
continue; |
|
+ plaintype = sshkey_type_plain(ctx->keys[i]->type); |
|
/* Prepare data to be signed: session ID, unique string, key */ |
|
sshbuf_reset(signdata); |
|
if ( (r = sshbuf_put_cstring(signdata, |
|
@@ -2148,19 +2154,33 @@ |
|
error_fr(r, "parse sig"); |
|
goto out; |
|
} |
|
+ if ((r = sshkey_get_sigtype(sig, siglen, &alg)) != 0) { |
|
+ error_fr(r, "server gave unintelligible signature " |
|
+ "for %s key %zu", sshkey_type(ctx->keys[i]), i); |
|
+ goto out; |
|
+ } |
|
/* |
|
- * For RSA keys, prefer to use the signature type negotiated |
|
- * during KEX to the default (SHA1). |
|
+ * Special case for RSA keys: if a RSA hostkey was negotiated, |
|
+ * then use its signature type for verification of RSA hostkey |
|
+ * proofs. Otherwise, accept only RSA-SHA256/512 signatures. |
|
*/ |
|
- use_kexsigtype = kexsigtype == KEY_RSA && |
|
- sshkey_type_plain(ctx->keys[i]->type) == KEY_RSA; |
|
- debug3_f("verify %s key %zu using %s sigalg", |
|
- sshkey_type(ctx->keys[i]), i, |
|
- use_kexsigtype ? ssh->kex->hostkey_alg : "default"); |
|
+ if (plaintype == KEY_RSA && rsa_kexalg == NULL && |
|
+ match_pattern_list(alg, HOSTKEY_PROOF_RSA_ALGS, 0) != 1) { |
|
+ debug_f("server used untrusted RSA signature algorithm " |
|
+ "%s for key %zu, disregarding", alg, i); |
|
+ free(alg); |
|
+ /* zap the key from the list */ |
|
+ sshkey_free(ctx->keys[i]); |
|
+ ctx->keys[i] = NULL; |
|
+ ndone++; |
|
+ continue; |
|
+ } |
|
+ debug3_f("verify %s key %zu using sigalg %s", |
|
+ sshkey_type(ctx->keys[i]), i, alg); |
|
+ free(alg); |
|
if ((r = sshkey_verify(ctx->keys[i], sig, siglen, |
|
sshbuf_ptr(signdata), sshbuf_len(signdata), |
|
- use_kexsigtype ? ssh->kex->hostkey_alg : NULL, 0, |
|
- NULL)) != 0) { |
|
+ plaintype == KEY_RSA ? rsa_kexalg : NULL, 0, NULL)) != 0) { |
|
error_fr(r, "server gave bad signature for %s key %zu", |
|
sshkey_type(ctx->keys[i]), i); |
|
goto out; |
|
diff --git a/hostfile.c b/hostfile.c |
|
index a035b381..bd49e3ac 100644 |
|
--- a/hostfile.c |
|
+++ b/hostfile.c |
|
@@ -642,7 +642,7 @@ hostfile_replace_entries(const char *filename, const char *host, const char *ip, |
|
/* Re-add the requested keys */ |
|
want = HKF_MATCH_HOST | (ip == NULL ? 0 : HKF_MATCH_IP); |
|
for (i = 0; i < nkeys; i++) { |
|
- if ((want & ctx.match_keys[i]) == want) |
|
+ if (keys[i] == NULL || (want & ctx.match_keys[i]) == want) |
|
continue; |
|
if ((fp = sshkey_fingerprint(keys[i], hash_alg, |
|
SSH_FP_DEFAULT)) == NULL) { |
|
diff --color -ru a/kex.c b/kex.c |
|
--- a/kex.c 2022-06-29 16:35:06.775599179 +0200 |
|
+++ b/kex.c 2022-06-29 16:42:00.839710940 +0200 |
|
@@ -959,6 +959,18 @@ |
|
return (1); |
|
} |
|
|
|
+/* returns non-zero if proposal contains any algorithm from algs */ |
|
+static int |
|
+has_any_alg(const char *proposal, const char *algs) |
|
+{ |
|
+ char *cp; |
|
+ |
|
+ if ((cp = match_list(proposal, algs, NULL)) == NULL) |
|
+ return 0; |
|
+ free(cp); |
|
+ return 1; |
|
+} |
|
+ |
|
static int |
|
kex_choose_conf(struct ssh *ssh) |
|
{ |
|
@@ -994,6 +1006,16 @@ |
|
free(ext); |
|
} |
|
|
|
+ /* Check whether client supports rsa-sha2 algorithms */ |
|
+ if (kex->server && (kex->flags & KEX_INITIAL)) { |
|
+ if (has_any_alg(peer[PROPOSAL_SERVER_HOST_KEY_ALGS], |
|
+ "rsa-sha2-256,rsa-sha2-256-cert-v01@openssh.com")) |
|
+ kex->flags |= KEX_RSA_SHA2_256_SUPPORTED; |
|
+ if (has_any_alg(peer[PROPOSAL_SERVER_HOST_KEY_ALGS], |
|
+ "rsa-sha2-512,rsa-sha2-512-cert-v01@openssh.com")) |
|
+ kex->flags |= KEX_RSA_SHA2_512_SUPPORTED; |
|
+ } |
|
+ |
|
/* Algorithm Negotiation */ |
|
if ((r = choose_kex(kex, cprop[PROPOSAL_KEX_ALGS], |
|
sprop[PROPOSAL_KEX_ALGS])) != 0) { |
|
diff --color -ru a/kex.h b/kex.h |
|
--- a/kex.h 2022-06-29 16:35:06.766599003 +0200 |
|
+++ b/kex.h 2022-06-29 16:42:24.199168567 +0200 |
|
@@ -116,6 +116,8 @@ |
|
|
|
#define KEX_INIT_SENT 0x0001 |
|
#define KEX_INITIAL 0x0002 |
|
+#define KEX_RSA_SHA2_256_SUPPORTED 0x0008 /* only set in server for now */ |
|
+#define KEX_RSA_SHA2_512_SUPPORTED 0x0010 /* only set in server for now */ |
|
|
|
struct sshenc { |
|
char *name; |
|
diff --color -ru a/serverloop.c b/serverloop.c |
|
--- a/serverloop.c 2021-08-20 06:03:49.000000000 +0200 |
|
+++ b/serverloop.c 2022-06-29 16:45:05.902336428 +0200 |
|
@@ -684,16 +684,18 @@ |
|
struct sshbuf *resp = NULL; |
|
struct sshbuf *sigbuf = NULL; |
|
struct sshkey *key = NULL, *key_pub = NULL, *key_prv = NULL; |
|
- int r, ndx, kexsigtype, use_kexsigtype, success = 0; |
|
+ int r, ndx, success = 0; |
|
const u_char *blob; |
|
+ const char *sigalg, *kex_rsa_sigalg = NULL; |
|
u_char *sig = 0; |
|
size_t blen, slen; |
|
|
|
if ((resp = sshbuf_new()) == NULL || (sigbuf = sshbuf_new()) == NULL) |
|
fatal_f("sshbuf_new"); |
|
|
|
- kexsigtype = sshkey_type_plain( |
|
- sshkey_type_from_name(ssh->kex->hostkey_alg)); |
|
+ if (sshkey_type_plain(sshkey_type_from_name( |
|
+ ssh->kex->hostkey_alg)) == KEY_RSA) |
|
+ kex_rsa_sigalg = ssh->kex->hostkey_alg; |
|
while (ssh_packet_remaining(ssh) > 0) { |
|
sshkey_free(key); |
|
key = NULL; |
|
@@ -726,16 +728,24 @@ |
|
* For RSA keys, prefer to use the signature type negotiated |
|
* during KEX to the default (SHA1). |
|
*/ |
|
- use_kexsigtype = kexsigtype == KEY_RSA && |
|
- sshkey_type_plain(key->type) == KEY_RSA; |
|
+ sigalg = NULL; |
|
+ if (sshkey_type_plain(key->type) == KEY_RSA) { |
|
+ if (kex_rsa_sigalg != NULL) |
|
+ sigalg = kex_rsa_sigalg; |
|
+ else if (ssh->kex->flags & KEX_RSA_SHA2_512_SUPPORTED) |
|
+ sigalg = "rsa-sha2-512"; |
|
+ else if (ssh->kex->flags & KEX_RSA_SHA2_256_SUPPORTED) |
|
+ sigalg = "rsa-sha2-256"; |
|
+ } |
|
+ debug3_f("sign %s key (index %d) using sigalg %s", |
|
+ sshkey_type(key), ndx, sigalg == NULL ? "default" : sigalg); |
|
if ((r = sshbuf_put_cstring(sigbuf, |
|
"hostkeys-prove-00@openssh.com")) != 0 || |
|
(r = sshbuf_put_stringb(sigbuf, |
|
ssh->kex->session_id)) != 0 || |
|
(r = sshkey_puts(key, sigbuf)) != 0 || |
|
(r = ssh->kex->sign(ssh, key_prv, key_pub, &sig, &slen, |
|
- sshbuf_ptr(sigbuf), sshbuf_len(sigbuf), |
|
- use_kexsigtype ? ssh->kex->hostkey_alg : NULL)) != 0 || |
|
+ sshbuf_ptr(sigbuf), sshbuf_len(sigbuf), sigalg)) != 0 || |
|
(r = sshbuf_put_string(resp, sig, slen)) != 0) { |
|
error_fr(r, "assemble signature"); |
|
goto out;
|
|
|