1
0
mirror of https://git.tartarus.org/simon/putty.git synced 2025-01-25 01:02:24 +00:00

Remove fatal-error reporting from scan_kexinits.

This will allow it to be called in a second circumstance where we're
trying to find out whether something _would_ have worked, so that we
never want to terminate the connection.
This commit is contained in:
Simon Tatham 2023-12-10 15:09:50 +00:00
parent 0b00e4ce26
commit fdc891d170

View File

@ -1005,13 +1005,27 @@ static bool kexinit_keyword_found(ptrlen list, ptrlen keyword)
return false; return false;
} }
static bool ssh2_scan_kexinits( typedef struct ScanKexinitsResult {
bool success;
/* only if success is false */
enum {
SKR_INCOMPLETE,
SKR_UNKNOWN_ID,
SKR_NO_AGREEMENT,
} error;
const char *kind; /* what kind of thing did we fail to sort out? */
ptrlen desc; /* and what was it? or what was the available list? */
} ScanKexinitsResult;
static ScanKexinitsResult ssh2_scan_kexinits(
ptrlen client_kexinit, ptrlen server_kexinit, bool we_are_server, ptrlen client_kexinit, ptrlen server_kexinit, bool we_are_server,
struct kexinit_algorithm_list kexlists[NKEXLIST], struct kexinit_algorithm_list kexlists[NKEXLIST],
const ssh_kex **kex_alg, const ssh_keyalg **hostkey_alg, const ssh_kex **kex_alg, const ssh_keyalg **hostkey_alg,
transport_direction *cs, transport_direction *sc, transport_direction *cs, transport_direction *sc,
bool *warn_kex, bool *warn_hk, bool *warn_cscipher, bool *warn_sccipher, bool *warn_kex, bool *warn_hk, bool *warn_cscipher, bool *warn_sccipher,
Ssh *ssh, bool *ignore_guess_cs_packet, bool *ignore_guess_sc_packet, bool *ignore_guess_cs_packet, bool *ignore_guess_sc_packet,
struct server_hostkeys *server_hostkeys, unsigned *hkflags, struct server_hostkeys *server_hostkeys, unsigned *hkflags,
bool *can_send_ext_info, bool first_time, bool *strict_kex) bool *can_send_ext_info, bool first_time, bool *strict_kex)
{ {
@ -1040,11 +1054,10 @@ static bool ssh2_scan_kexinits(
clists[i] = get_string(client); clists[i] = get_string(client);
slists[i] = get_string(server); slists[i] = get_string(server);
if (get_err(client) || get_err(server)) { if (get_err(client) || get_err(server)) {
/* Report a better error than the spurious "Couldn't ScanKexinitsResult skr = {
* agree" that we'd generate if we pressed on regardless .success = false, .error = SKR_INCOMPLETE,
* and treated the empty get_string() result as genuine */ };
ssh_proto_error(ssh, "KEXINIT packet was incomplete"); return skr;
return false;
} }
for (cfirst = true, clist = clists[i]; for (cfirst = true, clist = clists[i];
@ -1092,10 +1105,11 @@ static bool ssh2_scan_kexinits(
* produce a reasonably useful message instead of an * produce a reasonably useful message instead of an
* assertion failure. * assertion failure.
*/ */
ssh_sw_abort(ssh, "Selected %s \"%.*s\" does not correspond to " ScanKexinitsResult skr = {
"any supported algorithm", .success = false, .error = SKR_UNKNOWN_ID,
kexlist_descr[i], PTRLEN_PRINTF(found)); .kind = kexlist_descr[i], .desc = found,
return false; };
return skr;
} }
/* /*
@ -1150,9 +1164,11 @@ static bool ssh2_scan_kexinits(
/* /*
* Otherwise, any match failure _is_ a fatal error. * Otherwise, any match failure _is_ a fatal error.
*/ */
ssh_sw_abort(ssh, "Couldn't agree a %s (available: %.*s)", ScanKexinitsResult skr = {
kexlist_descr[i], PTRLEN_PRINTF(slists[i])); .success = false, .error = SKR_UNKNOWN_ID,
return false; .kind = kexlist_descr[i], .desc = slists[i],
};
return skr;
} }
switch (i) { switch (i) {
@ -1248,7 +1264,33 @@ static bool ssh2_scan_kexinits(
} }
} }
return true; ScanKexinitsResult skr = { .success = true };
return skr;
}
static void ssh2_report_scan_kexinits_error(Ssh *ssh, ScanKexinitsResult skr)
{
assert(!skr.success);
switch (skr.error) {
case SKR_INCOMPLETE:
/* Report a better error than the spurious "Couldn't
* agree" that we'd generate if we pressed on regardless
* and treated the empty get_string() result as genuine */
ssh_proto_error(ssh, "KEXINIT packet was incomplete");
break;
case SKR_UNKNOWN_ID:
ssh_sw_abort(ssh, "Selected %s \"%.*s\" does not correspond to "
"any supported algorithm",
skr.kind, PTRLEN_PRINTF(skr.desc));
break;
case SKR_NO_AGREEMENT:
ssh_sw_abort(ssh, "Couldn't agree a %s (available: %.*s)",
skr.kind, PTRLEN_PRINTF(skr.desc));
break;
default:
unreachable("bad ScanKexinitsResult");
}
} }
static inline bool delay_outgoing_kexinit(struct ssh2_transport_state *s) static inline bool delay_outgoing_kexinit(struct ssh2_transport_state *s)
@ -1529,16 +1571,19 @@ static void ssh2_transport_process_queue(PacketProtocolLayer *ppl)
{ {
struct server_hostkeys hks = { NULL, 0, 0 }; struct server_hostkeys hks = { NULL, 0, 0 };
if (!ssh2_scan_kexinits( ScanKexinitsResult skr = ssh2_scan_kexinits(
ptrlen_from_strbuf(s->client_kexinit), ptrlen_from_strbuf(s->client_kexinit),
ptrlen_from_strbuf(s->server_kexinit), s->ssc != NULL, ptrlen_from_strbuf(s->server_kexinit), s->ssc != NULL,
s->kexlists, &s->kex_alg, &s->hostkey_alg, s->cstrans, s->kexlists, &s->kex_alg, &s->hostkey_alg, s->cstrans,
s->sctrans, &s->warn_kex, &s->warn_hk, &s->warn_cscipher, s->sctrans, &s->warn_kex, &s->warn_hk, &s->warn_cscipher,
&s->warn_sccipher, s->ppl.ssh, NULL, &s->ignorepkt, &hks, &s->warn_sccipher, NULL, &s->ignorepkt, &hks,
&s->hkflags, &s->can_send_ext_info, !s->got_session_id, &s->hkflags, &s->can_send_ext_info, !s->got_session_id,
&s->strict_kex)) { &s->strict_kex);
if (!skr.success) {
sfree(hks.indices); sfree(hks.indices);
return; /* false means a fatal error function was called */ ssh2_report_scan_kexinits_error(s->ppl.ssh, skr);
return; /* we just called a fatal error function */
} }
/* /*