]> asedeno.scripts.mit.edu Git - PuTTY.git/commitdiff
Support RFC 4419.
authorSimon Tatham <anakin@pobox.com>
Sat, 25 Apr 2015 09:46:53 +0000 (10:46 +0100)
committerSimon Tatham <anakin@pobox.com>
Sat, 20 Jun 2015 08:31:55 +0000 (09:31 +0100)
PuTTY now uses the updated version of Diffie-Hellman group exchange,
except for a few old OpenSSH versions which Darren Tucker reports only
support the old version.

FIXME: this needs further work because the Bugs config panel has now
overflowed.

(cherry picked from commit 62a1bce7cb3ecb98feb57c7f1fd5d55845ce1533)

config.c
doc/config.but
putty.h
settings.c
ssh.c
ssh.h
windows/winhelp.h

index c2acd6287a83558c7147da29229d6605a76d4f9b..395f9c81a46a293754f9ba9970b894337b85a06b 100644 (file)
--- a/config.c
+++ b/config.c
@@ -2603,6 +2603,9 @@ void setup_config_box(struct controlbox *b, int midsession,
            ctrl_droplist(s, "Ignores SSH-2 maximum packet size", 'x', 20,
                          HELPCTX(ssh_bugs_maxpkt2),
                          sshbug_handler, I(CONF_sshbug_maxpkt2));
+           ctrl_droplist(s, "Only supports pre-RFC4419 SSH-2 DH GEX", 'd', 20,
+                         HELPCTX(ssh_bugs_oldgex2),
+                         sshbug_handler, I(CONF_sshbug_oldgex2));
            ctrl_droplist(s, "Replies to requests on closed channels", 'q', 20,
                          HELPCTX(ssh_bugs_chanreq),
                          sshbug_handler, I(CONF_sshbug_chanreq));
index 0f8175f2bcec550dc44e43e8172d8cee2a8d47b9..1d81460fd436d1b2700dfa89ed4bfe14dcd25417 100644 (file)
@@ -3386,6 +3386,23 @@ reply to a request after it thinks the channel has entirely closed,
 and terminate with an error along the lines of \q{Received
 \cw{SSH2_MSG_CHANNEL_FAILURE} for nonexistent channel 256}.
 
+\S{config-ssh-bug-oldgex2} \q{Only supports pre-RFC4419 SSH-2 DH GEX}
+
+\cfg{winhelp-topic}{ssh.bugs.oldgex2}
+
+The SSH key exchange method that uses Diffie-Hellman group exchange
+was redesigned after its original release, to use a slightly more
+sophisticated setup message. Almost all SSH implementations switched
+over to the new version. (PuTTY was one of the last.) A few old
+servers still only support the old one.
+
+If this bug is detected, and the client and server negotiate
+Diffie-Hellman group exchange, then PuTTY will send the old message
+now known as \cw{SSH2_MSG_KEX_DH_GEX_REQUEST_OLD} in place of the new
+\cw{SSH2_MSG_KEX_DH_GEX_REQUEST}.
+
+This is an SSH-2-specific bug.
+
 \H{config-serial} The Serial panel
 
 The \i{Serial} panel allows you to configure options that only apply
diff --git a/putty.h b/putty.h
index 5e0439609bfcd3db653b7b8bc7b9c537ea83f33a..e030df79eed425349a6c318d76843c19051f3535 100644 (file)
--- a/putty.h
+++ b/putty.h
@@ -837,6 +837,7 @@ void cleanup_exit(int);
     X(INT, NONE, sshbug_rekey2) \
     X(INT, NONE, sshbug_maxpkt2) \
     X(INT, NONE, sshbug_ignore2) \
+    X(INT, NONE, sshbug_oldgex2) \
     X(INT, NONE, sshbug_winadj) \
     X(INT, NONE, sshbug_chanreq) \
     /*                                                                \
index a7a887851ed3e3baae0c8e44c4f80fd27f78f5db..02d7506b121aeb25d3b7b2fd8dab3581544ffbe0 100644 (file)
@@ -630,6 +630,7 @@ void save_open_settings(void *sesskey, Conf *conf)
     write_setting_i(sesskey, "BugPKSessID2", 2-conf_get_int(conf, CONF_sshbug_pksessid2));
     write_setting_i(sesskey, "BugRekey2", 2-conf_get_int(conf, CONF_sshbug_rekey2));
     write_setting_i(sesskey, "BugMaxPkt2", 2-conf_get_int(conf, CONF_sshbug_maxpkt2));
+    write_setting_i(sesskey, "BugOldGex2", 2-conf_get_int(conf, CONF_sshbug_oldgex2));
     write_setting_i(sesskey, "BugWinadj", 2-conf_get_int(conf, CONF_sshbug_winadj));
     write_setting_i(sesskey, "BugChanReq", 2-conf_get_int(conf, CONF_sshbug_chanreq));
     write_setting_i(sesskey, "StampUtmp", conf_get_int(conf, CONF_stamp_utmp));
@@ -977,6 +978,7 @@ void load_open_settings(void *sesskey, Conf *conf)
     i = gppi_raw(sesskey, "BugPKSessID2", 0); conf_set_int(conf, CONF_sshbug_pksessid2, 2-i);
     i = gppi_raw(sesskey, "BugRekey2", 0); conf_set_int(conf, CONF_sshbug_rekey2, 2-i);
     i = gppi_raw(sesskey, "BugMaxPkt2", 0); conf_set_int(conf, CONF_sshbug_maxpkt2, 2-i);
+    i = gppi_raw(sesskey, "BugOldGex2", 0); conf_set_int(conf, CONF_sshbug_oldgex2, 2-i);
     i = gppi_raw(sesskey, "BugWinadj", 0); conf_set_int(conf, CONF_sshbug_winadj, 2-i);
     i = gppi_raw(sesskey, "BugChanReq", 0); conf_set_int(conf, CONF_sshbug_chanreq, 2-i);
     conf_set_int(conf, CONF_ssh_simple, FALSE);
diff --git a/ssh.c b/ssh.c
index 13b67b6b3a1092b27b0f96c25c3a8e746ec80106..735bc17460063034ff20d2f2d9e6ac7eeec519a8 100644 (file)
--- a/ssh.c
+++ b/ssh.c
@@ -76,6 +76,10 @@ static const char *const ssh2_disconnect_reasons[] = {
 #define BUG_CHOKES_ON_SSH2_IGNORE               512
 #define BUG_CHOKES_ON_WINADJ                   1024
 #define BUG_SENDS_LATE_REQUEST_REPLY           2048
+#define BUG_SSH2_OLDGEX                        4096
+
+#define DH_MIN_SIZE 1024
+#define DH_MAX_SIZE 8192
 
 /*
  * Codes for terminal modes.
@@ -247,6 +251,7 @@ static char *ssh2_pkt_type(Pkt_KCtx pkt_kctx, Pkt_ACtx pkt_actx, int type)
     translate(SSH2_MSG_NEWKEYS);
     translatek(SSH2_MSG_KEXDH_INIT, SSH2_PKTCTX_DHGROUP);
     translatek(SSH2_MSG_KEXDH_REPLY, SSH2_PKTCTX_DHGROUP);
+    translatek(SSH2_MSG_KEX_DH_GEX_REQUEST_OLD, SSH2_PKTCTX_DHGEX);
     translatek(SSH2_MSG_KEX_DH_GEX_REQUEST, SSH2_PKTCTX_DHGEX);
     translatek(SSH2_MSG_KEX_DH_GEX_GROUP, SSH2_PKTCTX_DHGEX);
     translatek(SSH2_MSG_KEX_DH_GEX_INIT, SSH2_PKTCTX_DHGEX);
@@ -2805,6 +2810,17 @@ static void ssh_detect_bugs(Ssh ssh, char *vstring)
        logevent("We believe remote version has SSH-2 ignore bug");
     }
 
+    if (conf_get_int(ssh->conf, CONF_sshbug_oldgex2) == FORCE_ON ||
+       (conf_get_int(ssh->conf, CONF_sshbug_oldgex2) == AUTO &&
+        (wc_match("OpenSSH_2.[235]*", imp)))) {
+       /*
+        * These versions only support the original (pre-RFC4419)
+        * SSH-2 GEX request.
+        */
+       ssh->remote_bugs |= BUG_SSH2_OLDGEX;
+       logevent("We believe remote version has outdated SSH-2 GEX");
+    }
+
     if (conf_get_int(ssh->conf, CONF_sshbug_winadj) == FORCE_ON) {
        /*
         * Servers that don't support our winadj request for one
@@ -6595,8 +6611,19 @@ static void do_ssh2_transport(Ssh ssh, void *vin, int inlen,
              * much data.
              */
             s->pbits = 512 << ((s->nbits - 1) / 64);
-            s->pktout = ssh2_pkt_init(SSH2_MSG_KEX_DH_GEX_REQUEST);
-            ssh2_pkt_adduint32(s->pktout, s->pbits);
+            if (s->pbits < DH_MIN_SIZE)
+                s->pbits = DH_MIN_SIZE;
+            if (s->pbits > DH_MAX_SIZE)
+                s->pbits = DH_MAX_SIZE;
+            if ((ssh->remote_bugs & BUG_SSH2_OLDGEX)) {
+                s->pktout = ssh2_pkt_init(SSH2_MSG_KEX_DH_GEX_REQUEST_OLD);
+                ssh2_pkt_adduint32(s->pktout, s->pbits);
+            } else {
+                s->pktout = ssh2_pkt_init(SSH2_MSG_KEX_DH_GEX_REQUEST);
+                ssh2_pkt_adduint32(s->pktout, DH_MIN_SIZE);
+                ssh2_pkt_adduint32(s->pktout, s->pbits);
+                ssh2_pkt_adduint32(s->pktout, DH_MAX_SIZE);
+            }
             ssh2_pkt_send_noqueue(ssh, s->pktout);
 
             crWaitUntilV(pktin);
@@ -6664,7 +6691,11 @@ static void do_ssh2_transport(Ssh ssh, void *vin, int inlen,
 
         hash_string(ssh->kex->hash, ssh->exhash, s->hostkeydata, s->hostkeylen);
         if (!ssh->kex->pdata) {
+            if (!(ssh->remote_bugs & BUG_SSH2_OLDGEX))
+                hash_uint32(ssh->kex->hash, ssh->exhash, DH_MIN_SIZE);
             hash_uint32(ssh->kex->hash, ssh->exhash, s->pbits);
+            if (!(ssh->remote_bugs & BUG_SSH2_OLDGEX))
+                hash_uint32(ssh->kex->hash, ssh->exhash, DH_MAX_SIZE);
             hash_mpint(ssh->kex->hash, ssh->exhash, s->p);
             hash_mpint(ssh->kex->hash, ssh->exhash, s->g);
         }
diff --git a/ssh.h b/ssh.h
index 52500ac887d33c0aed63ba9fe2a060dfd25d2d05..e50fbca349ec08237851940ed306ef8b8c5d146d 100644 (file)
--- a/ssh.h
+++ b/ssh.h
@@ -720,7 +720,8 @@ void platform_ssh_share_cleanup(const char *name);
 #define SSH2_MSG_NEWKEYS                          21   /* 0x15 */
 #define SSH2_MSG_KEXDH_INIT                       30   /* 0x1e */
 #define SSH2_MSG_KEXDH_REPLY                      31   /* 0x1f */
-#define SSH2_MSG_KEX_DH_GEX_REQUEST               30   /* 0x1e */
+#define SSH2_MSG_KEX_DH_GEX_REQUEST_OLD           30   /* 0x1e */
+#define SSH2_MSG_KEX_DH_GEX_REQUEST               34   /* 0x1e */
 #define SSH2_MSG_KEX_DH_GEX_GROUP                 31   /* 0x1f */
 #define SSH2_MSG_KEX_DH_GEX_INIT                  32   /* 0x20 */
 #define SSH2_MSG_KEX_DH_GEX_REPLY                 33   /* 0x21 */
index fc10a8f4d5b895d1f762d61a3ad95f897f6ed6c0..9b21c92c17f131242bc6c95bf4fc6249bfb2a581 100644 (file)
 #define WINHELP_CTX_ssh_bugs_maxpkt2 "ssh.bugs.maxpkt2:config-ssh-bug-maxpkt2"
 #define WINHELP_CTX_ssh_bugs_winadj "ssh.bugs.winadj:config-ssh-bug-winadj"
 #define WINHELP_CTX_ssh_bugs_chanreq "ssh.bugs.winadj:config-ssh-bug-chanreq"
+#define WINHELP_CTX_ssh_bugs_oldgex2 "ssh.bugs.oldgex2:config-ssh-bug-oldgex2"
 #define WINHELP_CTX_serial_line "serial.line:config-serial-line"
 #define WINHELP_CTX_serial_speed "serial.speed:config-serial-speed"
 #define WINHELP_CTX_serial_databits "serial.databits:config-serial-databits"