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

Fix rekeying when using a certified host key.

In a rekey, we expect to see the same host key again, which we enforce
by comparing its cache string, which we happened to have handy. But
certified host keys don't have cache strings, so this no longer works
reliably - the 'assert(s->keystr)' fails.

(This is what I get for making a zillion short-lived test connections
and not leaving any of them running for more than 2 minutes!)

Instead, we now keep the official public blob of the host key from the
first key exchange, and compare that to the public blob of the one in
the rekey.
This commit is contained in:
Simon Tatham 2022-04-29 22:44:40 +01:00
parent 1dfa0f538b
commit 958304897d
3 changed files with 12 additions and 9 deletions

View File

@ -952,8 +952,8 @@ void ssh2kex_coroutine(struct ssh2_transport_state *s, bool *aborted)
* Save this host key, to check against the one presented in
* subsequent rekeys.
*/
s->hostkey_str = s->keystr;
s->keystr = NULL;
strbuf_clear(s->hostkeyblob);
ssh_key_public_blob(s->hkey, BinarySink_UPCAST(s->hostkeyblob));
} else if (s->cross_certifying) {
assert(s->hkey);
assert(ssh_key_alg(s->hkey) == s->cross_certifying);
@ -969,8 +969,8 @@ void ssh2kex_coroutine(struct ssh2_transport_state *s, bool *aborted)
* Don't forget to store the new key as the one we'll be
* re-checking in future normal rekeys.
*/
s->hostkey_str = s->keystr;
s->keystr = NULL;
strbuf_clear(s->hostkeyblob);
ssh_key_public_blob(s->hkey, BinarySink_UPCAST(s->hostkeyblob));
} else {
/*
* In a rekey, we never present an interactive host key
@ -978,8 +978,12 @@ void ssh2kex_coroutine(struct ssh2_transport_state *s, bool *aborted)
* enforce that the key we're seeing this time is identical to
* the one we saw before.
*/
assert(s->keystr); /* filled in by prior key exchange */
if (strcmp(s->hostkey_str, s->keystr)) {
strbuf *thisblob = strbuf_new();
ssh_key_public_blob(s->hkey, BinarySink_UPCAST(thisblob));
bool match = ptrlen_eq_ptrlen(ptrlen_from_strbuf(thisblob),
ptrlen_from_strbuf(s->hostkeyblob));
strbuf_free(thisblob);
if (!match) {
#ifndef FUZZING
ssh_sw_abort(s->ppl.ssh,
"Host key was different in repeat key exchange");

View File

@ -212,7 +212,6 @@ static void ssh2_transport_free(PacketProtocolLayer *ppl)
sfree(s->client_greeting);
sfree(s->server_greeting);
sfree(s->keystr);
sfree(s->hostkey_str);
strbuf_free(s->hostkeyblob);
{
host_ca *hca;

View File

@ -140,7 +140,6 @@ struct ssh2_transport_state {
const ssh_kex *kex_alg;
const ssh_keyalg *hostkey_alg;
char *hostkey_str; /* string representation, for easy checking in rekeys */
unsigned char session_id[MAX_HASH_LEN];
int session_id_len;
int dh_min_size, dh_max_size;
@ -188,7 +187,8 @@ struct ssh2_transport_state {
int kex_init_value, kex_reply_value;
transport_direction in, out, *cstrans, *sctrans;
ptrlen hostkeydata, sigdata;
strbuf *hostkeyblob;
strbuf *hostkeyblob; /* used in server to construct host key to
* send to client; in client to check in rekeys */
char *keystr;
ssh_key *hkey; /* actual host key */
unsigned hkflags; /* signing flags, used in server */