Add a preference list for SSH-2 key exchange algorithms, on a new "Kex" panel
authorjacob <jacob@cda61777-01e9-0310-a592-d414129be87e>
Thu, 23 Dec 2004 02:24:07 +0000 (02:24 +0000)
committerjacob <jacob@cda61777-01e9-0310-a592-d414129be87e>
Thu, 23 Dec 2004 02:24:07 +0000 (02:24 +0000)
(which will gain more content anon).

Retire BUG_SSH2_DH_GEX and add a backwards-compatibility wart, since we never
did find a way of automatically detecting this alleged server bug, and in any
case there was only ever one report (<3D91F3B5.7030309@inwind.it>, FWIW).

Also generalise askcipher() to a new askalg() (thus touching all the
front-ends).

I've made some attempt to document what SSH key exchange is and why you care,
but it could use some review for clarity (and outright lies).

git-svn-id: svn://svn.tartarus.org/sgt/putty@5022 cda61777-01e9-0310-a592-d414129be87e

config.c
doc/config.but
mac/mac.c
putty.h
settings.c
ssh.c
unix/gtkdlg.c
unix/uxcons.c
windows/wincons.c
windows/windlg.c
windows/winhelp.h

index 08ad490..51d0f73 100644 (file)
--- a/config.c
+++ b/config.c
@@ -124,6 +124,48 @@ static void cipherlist_handler(union control *ctrl, void *dlg,
     }
 }
 
+static void kexlist_handler(union control *ctrl, void *dlg,
+                           void *data, int event)
+{
+    Config *cfg = (Config *)data;
+    if (event == EVENT_REFRESH) {
+       int i;
+
+       static const struct { char *s; int k; } kexes[] = {
+           { "Diffie-Hellman group 1",         KEX_DHGROUP1 },
+           { "Diffie-Hellman group 14",        KEX_DHGROUP14 },
+           { "Diffie-Hellman group exchange",  KEX_DHGEX },
+           { "-- warn below here --",          KEX_WARN }
+       };
+
+       /* Set up the "kex preference" box. */
+       /* (kexlist assumed to contain all algorithms) */
+       dlg_update_start(ctrl, dlg);
+       dlg_listbox_clear(ctrl, dlg);
+       for (i = 0; i < KEX_MAX; i++) {
+           int k = cfg->ssh_kexlist[i];
+           int j;
+           char *kstr = NULL;
+           for (j = 0; j < (sizeof kexes) / (sizeof kexes[0]); j++) {
+               if (kexes[j].k == k) {
+                   kstr = kexes[j].s;
+                   break;
+               }
+           }
+           dlg_listbox_addwithid(ctrl, dlg, kstr, k);
+       }
+       dlg_update_done(ctrl, dlg);
+
+    } else if (event == EVENT_VALCHANGE) {
+       int i;
+
+       /* Update array to match the list box. */
+       for (i=0; i < KEX_MAX; i++)
+           cfg->ssh_kexlist[i] = dlg_listbox_getid(ctrl, dlg, i);
+
+    }
+}
+
 static void printerbox_handler(union control *ctrl, void *dlg,
                               void *data, int event)
 {
@@ -1526,6 +1568,25 @@ void setup_config_box(struct controlbox *b, struct sesslist *sesslist,
                      I(offsetof(Config,ssh2_des_cbc)));
 
        /*
+        * The Connection/SSH/Kex panel.
+        */
+       ctrl_settitle(b, "Connection/SSH/Kex",
+                     "Options controlling SSH key exchange");
+
+       s = ctrl_getset(b, "Connection/SSH/Kex", "main", 
+                       "Key exchange algorithm options");
+       c = ctrl_draglist(s, "Algorithm selection policy", 's',
+                         HELPCTX(ssh_kexlist),
+                         kexlist_handler, P(NULL));
+       c->listbox.height = 5;
+
+#if 0
+       s = ctrl_getset(b, "Connection/SSH/Kex", "repeat",
+                       "Options controlling key re-exchange");
+       /* FIXME: at least time and data size */
+#endif
+
+       /*
         * The Connection/SSH/Auth panel.
         */
        ctrl_settitle(b, "Connection/SSH/Auth",
@@ -1659,9 +1720,6 @@ void setup_config_box(struct controlbox *b, struct sesslist *sesslist,
        ctrl_droplist(s, "Requires padding on SSH2 RSA signatures", 'p', 20,
                      HELPCTX(ssh_bugs_rsapad2),
                      sshbug_handler, I(offsetof(Config,sshbug_rsapad2)));
-       ctrl_droplist(s, "Chokes on Diffie-Hellman group exchange", 'd', 20,
-                     HELPCTX(ssh_bugs_dhgex2),
-                     sshbug_handler, I(offsetof(Config,sshbug_dhgex2)));
        ctrl_droplist(s, "Misuses the session ID in PK auth", 'n', 20,
                      HELPCTX(ssh_bugs_pksessid2),
                      sshbug_handler, I(offsetof(Config,sshbug_pksessid2)));
index 07c3528..badb0d9 100644 (file)
@@ -2098,6 +2098,77 @@ these servers if you enable the \q{Enable legacy use of single-DES in
 SSH 2} option; by default this is disabled and PuTTY will stick to
 recommended ciphers.
 
+\H{config-ssh-kex} The Kex panel
+
+\# FIXME: This whole section is draft. Feel free to revise.
+
+The Kex panel (short for \q{key exchange}) allows you to configure
+options related to SSH-2 key exchange.
+
+Key exchange occurs at the start of an SSH connection (and
+occasionally thereafter); it establishes a shared secret that is used
+as the basis for all of SSH's security features. It is therefore very
+important for the security of the connection that the key exchange is
+secure.
+
+Key exchange is a cryptographically intensive process; if either the
+client or the server is a relatively slow machine, the slower methods
+may take several tens of seconds to complete.
+
+If connection startup is too slow, or the connection hangs
+periodically, you may want to try changing these settings.
+
+If you don't understand what any of this means, it's safe to leave
+these settings alone.
+
+This entire panel is only relevant to SSH protocol version 2; none of
+these settings affect SSH-1 at all.
+
+\S{config-ssh-kex-order} Key exchange algorithm selection
+
+\cfg{winhelp-topic}{ssh.kex.order}
+
+PuTTY supports a variety of SSH-2 key exchange methods, and allows you
+to choose which one you prefer to use; configuration is similar to
+cipher selection (see \k{config-ssh-encryption}).
+
+PuTTY currently supports the following varieties of Diffie-Hellman key
+exchange:
+
+\b \q{Group 14}: a well-known 2048-bit group.
+
+\b \q{Group 1}: a well-known 1024-bit group. This is less secure
+\#{FIXME better words} than group 14, but may be faster with slow
+client or server machines, and may be the only method supported by
+older server software.
+
+\b \q{Group exchange}: with this method, instead of using a fixed
+group, PuTTY requests that the server suggest a group to use for key
+exchange; the server can avoid groups known to be weak, and possibly
+invent new ones over time, without any changes required to PuTTY's
+configuration. We recommend use of this method, if possible.
+
+If the first algorithm 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}).
+
+\# [Repeat key exchange bumph when config is added:] If the session
+key negotiated at connection startup is used too much or for too long,
+it may become feasible to mount attacks against the SSH connection.
+Therefore, the SSH protocol specifies that a new key exchange should
+take place every so often.
+
+\# While this renegotiation is taking place, no data can pass through
+the SSH connection, so it may appear to \q{freeze}. (The occurrence of
+repeat key exchange is noted in the Event Log; see
+\k{using-eventlog}.) Usually the same algorithm is used as at the
+start of the connection, with a similar overhead.
+
+\# [When options are added to frob how often this happens, we should
+hardcode the values recommended by the drafts -- 1 hour, 1GB -- in
+this documentation, in case PuTTY's defaults are obscured by Default
+Settings etc. Assuming we think they're good advice, that is.]
+
 \H{config-ssh-auth} The Auth panel
 
 The Auth panel allows you to configure authentication options for
@@ -2455,23 +2526,6 @@ to talking to OpenSSH.
 
 This is an SSH2-specific bug.
 
-\S{config-ssh-bug-dhgex} \q{Chokes on Diffie-Hellman group exchange}
-
-\cfg{winhelp-topic}{ssh.bugs.dhgex2}
-
-We have anecdotal evidence that some SSH servers claim to be able to
-perform Diffie-Hellman group exchange, but fail to actually do so
-when PuTTY tries to. If your SSH2 sessions spontaneously close
-immediately after opening the PuTTY window, it might be worth
-enabling the workaround for this bug to see if it helps.
-
-We have no hard evidence that any specific version of specific
-server software reliably demonstrates this bug. Therefore, PuTTY
-will never \e{assume} a server has this bug; if you want the
-workaround, you need to enable it manually.
-
-This is an SSH2-specific bug.
-
 \S{config-ssh-bug-pksessid2} \q{Misuses the session ID in PK auth}
 
 \cfg{winhelp-topic}{ssh.bugs.pksessid2}
index 4f7c2fc..8dde3e1 100644 (file)
--- a/mac/mac.c
+++ b/mac/mac.c
@@ -1,4 +1,4 @@
-/* $Id: mac.c,v 1.59 2003/05/10 12:27:38 ben Exp $ */
+/* $Id$ */
 /*
  * Copyright (c) 1999, 2003 Ben Harris
  * All rights reserved.
@@ -704,7 +704,7 @@ void verify_ssh_host_key(void *frontend, char *host, int port, char *keytype,
     }
 }
 
-void askcipher(void *frontend, char *ciphername, int cs)
+void askalg(void *frontend, const char *algtype, const char *algname)
 {
 
 }
diff --git a/putty.h b/putty.h
index b6aace7..5ffd73c 100644 (file)
--- a/putty.h
+++ b/putty.h
@@ -234,6 +234,17 @@ enum {
 
 enum {
     /*
+     * SSH-2 key exchange algorithms
+     */
+    KEX_WARN,
+    KEX_DHGROUP1,
+    KEX_DHGROUP14,
+    KEX_DHGEX,
+    KEX_MAX
+};
+
+enum {
+    /*
      * SSH ciphers (both SSH1 and SSH2)
      */
     CIPHER_WARN,                      /* pseudo 'cipher' */
@@ -388,6 +399,7 @@ struct config_tag {
                                        * but never for loading/saving */
     int nopty;
     int compression;
+    int ssh_kexlist[KEX_MAX];
     int agentfwd;
     int change_username;              /* allow username switching in SSH2 */
     int ssh_cipherlist[CIPHER_MAX];
@@ -514,7 +526,7 @@ struct config_tag {
     /* SSH bug compatibility modes */
     int sshbug_ignore1, sshbug_plainpw1, sshbug_rsa1,
        sshbug_hmac2, sshbug_derivekey2, sshbug_rsapad2,
-       sshbug_dhgex2, sshbug_pksessid2;
+       sshbug_pksessid2;
     /* Options for pterm. Should split out into platform-dependent part. */
     int stamp_utmp;
     int login_shell;
@@ -862,7 +874,7 @@ int wc_unescape(char *output, const char *wildcard);
 void logevent(void *frontend, const char *);
 void verify_ssh_host_key(void *frontend, char *host, int port, char *keytype,
                         char *keystr, char *fingerprint);
-void askcipher(void *frontend, char *ciphername, int cs);
+void askalg(void *frontend, const char *algtype, const char *algname);
 int askappend(void *frontend, Filename filename);
 
 /*
index 4377bfe..711ef88 100644 (file)
@@ -12,6 +12,7 @@
  */
 struct keyval { char *s; int v; };
 
+/* The cipher order given here is the default order. */
 static const struct keyval ciphernames[] = {
     { "aes",       CIPHER_AES },
     { "blowfish",   CIPHER_BLOWFISH },
@@ -20,6 +21,13 @@ static const struct keyval ciphernames[] = {
     { "des",       CIPHER_DES }
 };
 
+static const struct keyval kexnames[] = {
+    { "dh-gex-sha1",       KEX_DHGEX },
+    { "dh-group14-sha1",    KEX_DHGROUP14 },
+    { "dh-group1-sha1",            KEX_DHGROUP1 },
+    { "WARN",              KEX_WARN }
+};
+
 static void gpps(void *handle, const char *name, const char *def,
                 char *val, int len)
 {
@@ -227,6 +235,7 @@ void save_open_settings(void *sesskey, int do_host, Config *cfg)
     write_setting_i(sesskey, "ChangeUsername", cfg->change_username);
     wprefs(sesskey, "Cipher", ciphernames, CIPHER_MAX,
           cfg->ssh_cipherlist);
+    wprefs(sesskey, "KEX", kexnames, KEX_MAX, cfg->ssh_kexlist);
     write_setting_i(sesskey, "AuthTIS", cfg->try_tis_auth);
     write_setting_i(sesskey, "AuthKI", cfg->try_ki_auth);
     write_setting_i(sesskey, "SshNoShell", cfg->ssh_no_shell);
@@ -358,7 +367,6 @@ void save_open_settings(void *sesskey, int do_host, Config *cfg)
     write_setting_i(sesskey, "BugHMAC2", 2-cfg->sshbug_hmac2);
     write_setting_i(sesskey, "BugDeriveKey2", 2-cfg->sshbug_derivekey2);
     write_setting_i(sesskey, "BugRSAPad2", 2-cfg->sshbug_rsapad2);
-    write_setting_i(sesskey, "BugDHGEx2", 2-cfg->sshbug_dhgex2);
     write_setting_i(sesskey, "BugPKSessID2", 2-cfg->sshbug_pksessid2);
     write_setting_i(sesskey, "StampUtmp", cfg->stamp_utmp);
     write_setting_i(sesskey, "LoginShell", cfg->login_shell);
@@ -492,6 +500,20 @@ void load_open_settings(void *sesskey, int do_host, Config *cfg)
     gppi(sesskey, "ChangeUsername", 0, &cfg->change_username);
     gprefs(sesskey, "Cipher", "\0",
           ciphernames, CIPHER_MAX, cfg->ssh_cipherlist);
+    {
+       /* Backward-compatibility: we used to have an option to
+        * disable gex under the "bugs" panel after one report of
+        * a server which offered it then choked, but we never got
+        * a server version string or any other reports. */
+       char *default_kexes;
+       gppi(sesskey, "BugDHGEx2", 0, &i); i = 2-i;
+       if (i == FORCE_ON)
+           default_kexes = "dh-group14-sha1,dh-group1-sha1,WARN,dh-gex-sha1";
+       else
+           default_kexes = "dh-gex-sha1,dh-group14-sha1,dh-group1-sha1,WARN";
+       gprefs(sesskey, "KEX", default_kexes,
+              kexnames, KEX_MAX, cfg->ssh_kexlist);
+    }
     gppi(sesskey, "SshProt", 2, &cfg->sshprot);
     gppi(sesskey, "SSH2DES", 0, &cfg->ssh2_des_cbc);
     gppi(sesskey, "AuthTIS", 0, &cfg->try_tis_auth);
@@ -667,7 +689,6 @@ void load_open_settings(void *sesskey, int do_host, Config *cfg)
     }
     gppi(sesskey, "BugDeriveKey2", 0, &i); cfg->sshbug_derivekey2 = 2-i;
     gppi(sesskey, "BugRSAPad2", 0, &i); cfg->sshbug_rsapad2 = 2-i;
-    gppi(sesskey, "BugDHGEx2", 0, &i); cfg->sshbug_dhgex2 = 2-i;
     gppi(sesskey, "BugPKSessID2", 0, &i); cfg->sshbug_pksessid2 = 2-i;
     gppi(sesskey, "StampUtmp", 1, &cfg->stamp_utmp);
     gppi(sesskey, "LoginShell", 1, &cfg->login_shell);
diff --git a/ssh.c b/ssh.c
index a6fba8b..126e6ff 100644 (file)
--- a/ssh.c
+++ b/ssh.c
@@ -162,7 +162,7 @@ static const char *const ssh2_disconnect_reasons[] = {
 #define BUG_CHOKES_ON_RSA                        8
 #define BUG_SSH2_RSA_PADDING                    16
 #define BUG_SSH2_DERIVEKEY                       32
-#define BUG_SSH2_DH_GEX                          64
+/* 64 was BUG_SSH2_DH_GEX, now spare */
 #define BUG_SSH2_PK_SESSIONID                   128
 
 #define translate(x) if (type == x) return #x
@@ -360,12 +360,6 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen,
 #define SSH_MAX_BACKLOG 32768
 #define OUR_V2_WINSIZE 16384
 
-const static struct ssh_kex *kex_algs[] = {
-    &ssh_diffiehellman_gex,
-    &ssh_diffiehellman_group14,
-    &ssh_diffiehellman_group1,
-};
-
 const static struct ssh_signkey *hostkey_algs[] = { &ssh_rsa, &ssh_dss };
 
 static void *nullmac_make_context(void)
@@ -2058,14 +2052,6 @@ static void ssh_detect_bugs(Ssh ssh, char *vstring)
        ssh->remote_bugs |= BUG_SSH2_PK_SESSIONID;
        logevent("We believe remote version has SSH2 public-key-session-ID bug");
     }
-
-    if (ssh->cfg.sshbug_dhgex2 == FORCE_ON) {
-       /*
-        * User specified the SSH2 DH GEX bug.
-        */
-       ssh->remote_bugs |= BUG_SSH2_DH_GEX;
-       logevent("We believe remote version has SSH2 DH group exchange bug");
-    }
 }
 
 /*
@@ -2761,7 +2747,7 @@ static int do_ssh1_login(Ssh ssh, unsigned char *in, int inlen,
 
        /* Warn about chosen cipher if necessary. */
        if (warn)
-           askcipher(ssh->frontend, cipher_string, 0);
+           askalg(ssh->frontend, "cipher", cipher_string);
     }
 
     switch (s->cipher_type) {
@@ -4321,6 +4307,8 @@ static int do_ssh2_transport(Ssh ssh, unsigned char *in, int inlen,
        int hostkeylen, siglen;
        void *hkey;                    /* actual host key */
        unsigned char exchange_hash[20];
+       int n_preferred_kex;
+       const struct ssh_kex *preferred_kex[KEX_MAX];
        int n_preferred_ciphers;
        const struct ssh2_ciphers *preferred_ciphers[CIPHER_MAX];
        const struct ssh_compress *preferred_comp;
@@ -4340,6 +4328,37 @@ static int do_ssh2_transport(Ssh ssh, unsigned char *in, int inlen,
     {
        int i;
        /*
+        * Set up the preferred key exchange. (NULL => warn below here)
+        */
+       s->n_preferred_kex = 0;
+       for (i = 0; i < KEX_MAX; i++) {
+           switch (ssh->cfg.ssh_kexlist[i]) {
+             case KEX_DHGEX:
+               s->preferred_kex[s->n_preferred_kex++] =
+                   &ssh_diffiehellman_gex;
+               break;
+             case KEX_DHGROUP14:
+               s->preferred_kex[s->n_preferred_kex++] =
+                   &ssh_diffiehellman_group14;
+               break;
+             case KEX_DHGROUP1:
+               s->preferred_kex[s->n_preferred_kex++] =
+                   &ssh_diffiehellman_group1;
+               break;
+             case CIPHER_WARN:
+               /* Flag for later. Don't bother if it's the last in
+                * the list. */
+               if (i < KEX_MAX - 1) {
+                   s->preferred_kex[s->n_preferred_kex++] = NULL;
+               }
+               break;
+           }
+       }
+    }
+
+    {
+       int i;
+       /*
         * Set up the preferred ciphers. (NULL => warn below here)
         */
        s->n_preferred_ciphers = 0;
@@ -4388,7 +4407,7 @@ static int do_ssh2_transport(Ssh ssh, unsigned char *in, int inlen,
 
   begin_key_exchange:
     {
-       int i, j, cipherstr_started;
+       int i, j, commalist_started;
 
        /*
         * Enable queueing of outgoing auth- or connection-layer
@@ -4409,13 +4428,14 @@ static int do_ssh2_transport(Ssh ssh, unsigned char *in, int inlen,
            ssh2_pkt_addbyte(s->pktout, (unsigned char) random_byte());
        /* List key exchange algorithms. */
        ssh2_pkt_addstring_start(s->pktout);
-       for (i = 0; i < lenof(kex_algs); i++) {
-           if (kex_algs[i] == &ssh_diffiehellman_gex &&
-               (ssh->remote_bugs & BUG_SSH2_DH_GEX))
-               continue;
-           ssh2_pkt_addstring_str(s->pktout, kex_algs[i]->name);
-           if (i < lenof(kex_algs) - 1)
+       commalist_started = 0;
+       for (i = 0; i < s->n_preferred_kex; i++) {
+           const struct ssh_kex *k = s->preferred_kex[i];
+           if (!k) continue;          /* warning flag */
+           if (commalist_started)
                ssh2_pkt_addstring_str(s->pktout, ",");
+           ssh2_pkt_addstring_str(s->pktout, s->preferred_kex[i]->name);
+           commalist_started = 1;
        }
        /* List server host key algorithms. */
        ssh2_pkt_addstring_start(s->pktout);
@@ -4426,28 +4446,28 @@ static int do_ssh2_transport(Ssh ssh, unsigned char *in, int inlen,
        }
        /* List client->server encryption algorithms. */
        ssh2_pkt_addstring_start(s->pktout);
-       cipherstr_started = 0;
+       commalist_started = 0;
        for (i = 0; i < s->n_preferred_ciphers; i++) {
            const struct ssh2_ciphers *c = s->preferred_ciphers[i];
            if (!c) continue;          /* warning flag */
            for (j = 0; j < c->nciphers; j++) {
-               if (cipherstr_started)
+               if (commalist_started)
                    ssh2_pkt_addstring_str(s->pktout, ",");
                ssh2_pkt_addstring_str(s->pktout, c->list[j]->name);
-               cipherstr_started = 1;
+               commalist_started = 1;
            }
        }
        /* List server->client encryption algorithms. */
        ssh2_pkt_addstring_start(s->pktout);
-       cipherstr_started = 0;
+       commalist_started = 0;
        for (i = 0; i < s->n_preferred_ciphers; i++) {
            const struct ssh2_ciphers *c = s->preferred_ciphers[i];
            if (!c) continue; /* warning flag */
            for (j = 0; j < c->nciphers; j++) {
-               if (cipherstr_started)
+               if (commalist_started)
                    ssh2_pkt_addstring_str(s->pktout, ",");
                ssh2_pkt_addstring_str(s->pktout, c->list[j]->name);
-               cipherstr_started = 1;
+               commalist_started = 1;
            }
        }
        /* List client->server MAC algorithms. */
@@ -4528,15 +4548,26 @@ static int do_ssh2_transport(Ssh ssh, unsigned char *in, int inlen,
        s->sccomp_tobe = NULL;
        pktin->savedpos += 16;          /* skip garbage cookie */
        ssh_pkt_getstring(pktin, &str, &len);    /* key exchange algorithms */
-       for (i = 0; i < lenof(kex_algs); i++) {
-           if (kex_algs[i] == &ssh_diffiehellman_gex &&
-               (ssh->remote_bugs & BUG_SSH2_DH_GEX))
-               continue;
-           if (in_commasep_string(kex_algs[i]->name, str, len)) {
-               ssh->kex = kex_algs[i];
+       s->warn = 0;
+       for (i = 0; i < s->n_preferred_kex; i++) {
+           const struct ssh_kex *k = s->preferred_kex[i];
+           if (!k) {
+               s->warn = 1;
+           } else if (in_commasep_string(k->name, str, len)) {
+               ssh->kex = k;
+           }
+           if (ssh->kex) {
+               if (s->warn)
+                   askalg(ssh->frontend, "key-exchange algorithm",
+                          ssh->kex->name);
                break;
            }
        }
+       if (!ssh->kex) {
+           bombout(("Couldn't agree a key exchange algorithm (available: %s)",
+                    str ? str : "(null)"));
+           crStop(0);
+       }
        ssh_pkt_getstring(pktin, &str, &len);    /* host key algorithms */
        for (i = 0; i < lenof(hostkey_algs); i++) {
            if (in_commasep_string(hostkey_algs[i]->name, str, len)) {
@@ -4560,7 +4591,8 @@ static int do_ssh2_transport(Ssh ssh, unsigned char *in, int inlen,
            }
            if (s->cscipher_tobe) {
                if (s->warn)
-                   askcipher(ssh->frontend, s->cscipher_tobe->name, 1);
+                   askalg(ssh->frontend, "client-to-server cipher",
+                          s->cscipher_tobe->name);
                break;
            }
        }
@@ -4586,7 +4618,8 @@ static int do_ssh2_transport(Ssh ssh, unsigned char *in, int inlen,
            }
            if (s->sccipher_tobe) {
                if (s->warn)
-                   askcipher(ssh->frontend, s->sccipher_tobe->name, 2);
+                   askalg(ssh->frontend, "server-to-client cipher",
+                          s->sccipher_tobe->name);
                break;
            }
        }
index 2a2b3ab..6b5659c 100644 (file)
@@ -2351,22 +2351,19 @@ void verify_ssh_host_key(void *frontend, char *host, int port, char *keytype,
 }
 
 /*
- * Ask whether the selected cipher is acceptable (since it was
+ * Ask whether the selected algorithm is acceptable (since it was
  * below the configured 'warn' threshold).
- * cs: 0 = both ways, 1 = client->server, 2 = server->client
  */
-void askcipher(void *frontend, char *ciphername, int cs)
+void askalg(void *frontend, const char *algtype, const char *algname)
 {
     static const char msg[] =
-       "The first %scipher supported by the server is "
+       "The first %s supported by the server is "
        "%s, which is below the configured warning threshold.\n"
        "Continue with connection?";
     char *text;
     int ret;
 
-    text = dupprintf(msg, (cs == 0) ? "" :
-                     (cs == 1) ? "client-to-server " : "server-to-client ",
-                     ciphername);
+    text = dupprintf(msg, algtype, algname);
     ret = messagebox(GTK_WIDGET(get_window(frontend)),
                     "PuTTY Security Alert", text,
                     string_width("Continue with connection?"),
index a8effe9..b5bf840 100644 (file)
@@ -143,18 +143,17 @@ void verify_ssh_host_key(void *frontend, char *host, int port, char *keytype,
 }
 
 /*
- * Ask whether the selected cipher is acceptable (since it was
+ * Ask whether the selected algorithm is acceptable (since it was
  * below the configured 'warn' threshold).
- * cs: 0 = both ways, 1 = client->server, 2 = server->client
  */
-void askcipher(void *frontend, char *ciphername, int cs)
+void askalg(void *frontend, const char *algtype, const char *algname)
 {
     static const char msg[] =
-       "The first %scipher supported by the server is\n"
+       "The first %s supported by the server is\n"
        "%s, which is below the configured warning threshold.\n"
        "Continue with connection? (y/n) ";
     static const char msg_batch[] =
-       "The first %scipher supported by the server is\n"
+       "The first %s supported by the server is\n"
        "%s, which is below the configured warning threshold.\n"
        "Connection abandoned.\n";
     static const char abandoned[] = "Connection abandoned.\n";
@@ -162,17 +161,11 @@ void askcipher(void *frontend, char *ciphername, int cs)
     char line[32];
 
     if (console_batch_mode) {
-       fprintf(stderr, msg_batch,
-               (cs == 0) ? "" :
-               (cs == 1) ? "client-to-server " : "server-to-client ",
-               ciphername);
+       fprintf(stderr, msg_batch, algtype, algname);
        cleanup_exit(1);
     }
 
-    fprintf(stderr, msg,
-           (cs == 0) ? "" :
-           (cs == 1) ? "client-to-server " : "server-to-client ",
-           ciphername);
+    fprintf(stderr, msg, algtype, algname);
     fflush(stderr);
 
     {
index 347f99f..38b46fa 100644 (file)
@@ -147,21 +147,20 @@ void update_specials_menu(void *frontend)
 }
 
 /*
- * Ask whether the selected cipher is acceptable (since it was
+ * Ask whether the selected algorithm is acceptable (since it was
  * below the configured 'warn' threshold).
- * cs: 0 = both ways, 1 = client->server, 2 = server->client
  */
-void askcipher(void *frontend, char *ciphername, int cs)
+void askalg(void *frontend, const char *algtype, const char *algname)
 {
     HANDLE hin;
     DWORD savemode, i;
 
     static const char msg[] =
-       "The first %scipher supported by the server is\n"
+       "The first %s supported by the server is\n"
        "%s, which is below the configured warning threshold.\n"
        "Continue with connection? (y/n) ";
     static const char msg_batch[] =
-       "The first %scipher supported by the server is\n"
+       "The first %s supported by the server is\n"
        "%s, which is below the configured warning threshold.\n"
        "Connection abandoned.\n";
     static const char abandoned[] = "Connection abandoned.\n";
@@ -169,17 +168,11 @@ void askcipher(void *frontend, char *ciphername, int cs)
     char line[32];
 
     if (console_batch_mode) {
-       fprintf(stderr, msg_batch,
-               (cs == 0) ? "" :
-               (cs == 1) ? "client-to-server " : "server-to-client ",
-               ciphername);
+       fprintf(stderr, msg_batch, algtype, algname);
        cleanup_exit(1);
     }
 
-    fprintf(stderr, msg,
-           (cs == 0) ? "" :
-           (cs == 1) ? "client-to-server " : "server-to-client ",
-           ciphername);
+    fprintf(stderr, msg, algtype, algname);
     fflush(stderr);
 
     hin = GetStdHandle(STD_INPUT_HANDLE);
index 272196d..65018b1 100644 (file)
@@ -777,24 +777,21 @@ void verify_ssh_host_key(void *frontend, char *host, int port, char *keytype,
 }
 
 /*
- * Ask whether the selected cipher is acceptable (since it was
+ * Ask whether the selected algorithm is acceptable (since it was
  * below the configured 'warn' threshold).
- * cs: 0 = both ways, 1 = client->server, 2 = server->client
  */
-void askcipher(void *frontend, char *ciphername, int cs)
+void askalg(void *frontend, const char *algtype, const char *algname)
 {
     static const char mbtitle[] = "%s Security Alert";
     static const char msg[] =
-       "The first %.35scipher supported by the server\n"
+       "The first %s supported by the server\n"
        "is %.64s, which is below the configured\n"
        "warning threshold.\n"
        "Do you want to continue with this connection?\n";
     char *message, *title;
     int mbret;
 
-    message = dupprintf(msg, ((cs == 0) ? "" :
-                             (cs == 1) ? "client-to-server " :
-                             "server-to-client "), ciphername);
+    message = dupprintf(msg, algtype, algname);
     title = dupprintf(mbtitle, appname);
     mbret = MessageBox(NULL, message, title,
                       MB_ICONWARNING | MB_YESNO);
index 88338d3..63f25ad 100644 (file)
@@ -86,6 +86,7 @@
 #define WINHELP_CTX_ssh_protocol "ssh.protocol"
 #define WINHELP_CTX_ssh_command "ssh.command"
 #define WINHELP_CTX_ssh_compress "ssh.compress"
+#define WINHELP_CTX_ssh_kexlist "ssh.kex.order"
 #define WINHELP_CTX_ssh_auth_privkey "ssh.auth.privkey"
 #define WINHELP_CTX_ssh_auth_agentfwd "ssh.auth.agentfwd"
 #define WINHELP_CTX_ssh_auth_changeuser "ssh.auth.changeuser"
 #define WINHELP_CTX_ssh_bugs_hmac2 "ssh.bugs.hmac2"
 #define WINHELP_CTX_ssh_bugs_derivekey2 "ssh.bugs.derivekey2"
 #define WINHELP_CTX_ssh_bugs_rsapad2 "ssh.bugs.rsapad2"
-#define WINHELP_CTX_ssh_bugs_dhgex2 "ssh.bugs.dhgex2"
 #define WINHELP_CTX_ssh_bugs_pksessid2 "ssh.bugs.pksessid2"