From d21041f7f8846b16ff6d72ed696d6190627e19b4 Mon Sep 17 00:00:00 2001 From: Ben Harris Date: Fri, 29 May 2015 22:40:50 +0100 Subject: [PATCH] Add have_ssh_host_key() and use it to influence algorithm selection. The general plan is that if PuTTY knows a host key for a server, it should preferentially ask for the same type of key so that there's some chance of actually getting the same key again. This should mean that when a server (or PuTTY) adds a new host key type, PuTTY doesn't gratuitously switch to that key type and then warn the user about an unrecognised key. --- putty.h | 5 +++++ ssh.c | 13 ++++++++++++- unix/uxstore.c | 10 ++++++++++ windows/winstore.c | 10 ++++++++++ 4 files changed, 37 insertions(+), 1 deletion(-) diff --git a/putty.h b/putty.h index 22ec67b7..9d4aa739 100644 --- a/putty.h +++ b/putty.h @@ -1197,6 +1197,11 @@ void pgp_fingerprints(void); int verify_ssh_host_key(void *frontend, char *host, int port, const char *keytype, char *keystr, char *fingerprint, void (*callback)(void *ctx, int result), void *ctx); +/* + * have_ssh_host_key() just returns true if a key of that type is + * already chached and false otherwise. + */ +int have_ssh_host_key(const char *host, int port, const char *keytype); /* * askalg has the same set of return values as verify_ssh_host_key. */ diff --git a/ssh.c b/ssh.c index 9cf64a16..c48eff70 100644 --- a/ssh.c +++ b/ssh.c @@ -6350,9 +6350,20 @@ static void do_ssh2_transport(Ssh ssh, const void *vin, int inlen, if (!s->got_session_id) { /* * In the first key exchange, we list all the algorithms - * we're prepared to cope with. + * we're prepared to cope with, but prefer those algorithms + * for which we have a host key for this host. */ n = 0; + for (i = 0; i < lenof(hostkey_algs); i++) { + if (have_ssh_host_key(ssh->savedhost, ssh->savedport, + hostkey_algs[i]->keytype)) { + assert(n < MAXKEXLIST); + s->kexlists[KEXLIST_HOSTKEY][n].name = + hostkey_algs[i]->name; + s->kexlists[KEXLIST_HOSTKEY][n].u.hostkey = hostkey_algs[i]; + n++; + } + } for (i = 0; i < lenof(hostkey_algs); i++) { assert(n < MAXKEXLIST); s->kexlists[KEXLIST_HOSTKEY][n].name = hostkey_algs[i]->name; diff --git a/unix/uxstore.c b/unix/uxstore.c index d97185e1..411953ac 100644 --- a/unix/uxstore.c +++ b/unix/uxstore.c @@ -589,6 +589,16 @@ int verify_host_key(const char *hostname, int port, return ret; } +int have_ssh_host_key(const char *hostname, int port, + const char *keytype) +{ + /* + * If we have a host key, verify_host_key will return 0 or 2. + * If we don't have one, it'll return 1. + */ + return verify_host_key(hostname, port, keytype, "") != 1; +} + void store_host_key(const char *hostname, int port, const char *keytype, const char *key) { diff --git a/windows/winstore.c b/windows/winstore.c index b1058832..c45b9b04 100644 --- a/windows/winstore.c +++ b/windows/winstore.c @@ -454,6 +454,16 @@ int verify_host_key(const char *hostname, int port, return 0; /* key matched OK in registry */ } +int have_ssh_host_key(const char *hostname, int port, + const char *keytype) +{ + /* + * If we have a host key, verify_host_key will return 0 or 2. + * If we don't have one, it'll return 1. + */ + return verify_host_key(hostname, port, keytype, "") != 1; +} + void store_host_key(const char *hostname, int port, const char *keytype, const char *key) { -- 2.45.2