diff --git a/config.c b/config.c index db83adb4..16808bcb 100644 --- a/config.c +++ b/config.c @@ -2486,6 +2486,10 @@ void setup_config_box(struct controlbox *b, bool midsession, HELPCTX(ssh_hklist), hklist_handler, P(NULL)); c->listbox.height = 5; + + ctrl_checkbox(s, "Prefer algorithms for which a host key is known", + 'p', HELPCTX(ssh_hk_known), conf_checkbox_handler, + I(CONF_ssh_prefer_known_hostkeys)); } /* diff --git a/doc/config.but b/doc/config.but index ee179668..8cc96d0a 100644 --- a/doc/config.but +++ b/doc/config.but @@ -2544,6 +2544,27 @@ If the first key type PuTTY finds is below the \q{warn below here} line, you will see a warning box when you make the connection, similar to that for cipher selection (see \k{config-ssh-encryption}). +\S{config-ssh-prefer-known-hostkeys} Preferring known host keys + +By default, PuTTY will adjust the preference order for host key +algorithms so that any host keys it already knows are moved to the top +of the list. + +This prevents you from having to check and confirm a new host key for +a server you already had one for (e.g. because the server has +generated an alternative key of a type higher in PuTTY's preference +order, or because you changed the preference order itself). + +However, on the other hand, it can leak information to a listener in +the network about \e{whether} you already know a host key for this +server. + +For this reason, this policy is configurable. By turning this checkbox +off, you can reset PuTTY to always use the exact order of host key +algorithms configured in the preference list described in +\k{config-ssh-hostkey-order}, so that a listener will find out nothing +about what keys you had stored. + \S{config-ssh-kex-manual-hostkeys} \ii{Manually configuring host keys} In some situations, if PuTTY's automated host key management is not diff --git a/putty.h b/putty.h index 33835582..12e9dd5e 100644 --- a/putty.h +++ b/putty.h @@ -1256,6 +1256,7 @@ NORETURN void cleanup_exit(int); X(BOOL, NONE, compression) \ X(INT, INT, ssh_kexlist) \ X(INT, INT, ssh_hklist) \ + X(BOOL, NONE, ssh_prefer_known_hostkeys) \ X(INT, NONE, ssh_rekey_time) /* in minutes */ \ X(STR, NONE, ssh_rekey_data) /* string encoding e.g. "100K", "2M", "1G" */ \ X(BOOL, NONE, tryagent) \ diff --git a/settings.c b/settings.c index 7bf7e4d2..11bb5798 100644 --- a/settings.c +++ b/settings.c @@ -598,6 +598,7 @@ void save_open_settings(settings_w *sesskey, Conf *conf) wprefs(sesskey, "Cipher", ciphernames, CIPHER_MAX, conf, CONF_ssh_cipherlist); wprefs(sesskey, "KEX", kexnames, KEX_MAX, conf, CONF_ssh_kexlist); wprefs(sesskey, "HostKey", hknames, HK_MAX, conf, CONF_ssh_hklist); + write_setting_b(sesskey, "PreferKnownHostKeys", conf_get_bool(conf, CONF_ssh_prefer_known_hostkeys)); write_setting_i(sesskey, "RekeyTime", conf_get_int(conf, CONF_ssh_rekey_time)); #ifndef NO_GSSAPI write_setting_i(sesskey, "GssapiRekey", conf_get_int(conf, CONF_gssapirekey)); @@ -994,6 +995,7 @@ void load_open_settings(settings_r *sesskey, Conf *conf) } gprefs(sesskey, "HostKey", "ed25519,ecdsa,rsa,dsa,WARN", hknames, HK_MAX, conf, CONF_ssh_hklist); + gppb(sesskey, "PreferKnownHostKeys", true, conf, CONF_ssh_prefer_known_hostkeys); gppi(sesskey, "RekeyTime", 60, conf, CONF_ssh_rekey_time); #ifndef NO_GSSAPI gppi(sesskey, "GssapiRekey", GSS_DEF_REKEY_MINS, conf, CONF_gssapirekey); diff --git a/ssh2transport.c b/ssh2transport.c index 88f1f6d4..7ca1d3d8 100644 --- a/ssh2transport.c +++ b/ssh2transport.c @@ -571,9 +571,10 @@ static void ssh2_write_kexinit_lists( } } else if (first_time) { /* - * In the first key exchange, we list all the algorithms - * we're prepared to cope with, but prefer those algorithms - * for which we have a host key for this host. + * In the first key exchange, we list all the algorithms we're + * prepared to cope with, but (if configured to) we prefer + * those algorithms for which we have a host key for this + * host. * * If the host key algorithm is below the warning * threshold, we warn even if we did already have a key @@ -589,7 +590,8 @@ static void ssh2_write_kexinit_lists( for (j = 0; j < lenof(ssh2_hostkey_algs); j++) { if (ssh2_hostkey_algs[j].id != preferred_hk[i]) continue; - if (have_ssh_host_key(hk_host, hk_port, + if (conf_get_bool(conf, CONF_ssh_prefer_known_hostkeys) && + have_ssh_host_key(hk_host, hk_port, ssh2_hostkey_algs[j].alg->cache_id)) { alg = ssh2_kexinit_addalg(kexlists[KEXLIST_HOSTKEY], ssh2_hostkey_algs[j].alg->ssh_id); diff --git a/windows/winhelp.h b/windows/winhelp.h index 823a2429..452f8f49 100644 --- a/windows/winhelp.h +++ b/windows/winhelp.h @@ -102,6 +102,7 @@ #define WINHELP_CTX_ssh_share "config-ssh-sharing" #define WINHELP_CTX_ssh_kexlist "config-ssh-kex-order" #define WINHELP_CTX_ssh_hklist "config-ssh-hostkey-order" +#define WINHELP_CTX_ssh_hk_known "config-ssh-prefer-known-hostkeys" #define WINHELP_CTX_ssh_gssapi_kex_delegation "config-ssh-kex-gssapi-delegation" #define WINHELP_CTX_ssh_kex_repeat "config-ssh-kex-rekey" #define WINHELP_CTX_ssh_kex_manual_hostkeys "config-ssh-kex-manual-hostkeys"