Introduce the Bugs control panel, for overriding PuTTY's server
authorsimon <simon@cda61777-01e9-0310-a592-d414129be87e>
Sun, 8 Sep 2002 13:28:38 +0000 (13:28 +0000)
committersimon <simon@cda61777-01e9-0310-a592-d414129be87e>
Sun, 8 Sep 2002 13:28:38 +0000 (13:28 +0000)
version number checks to determine the presence or absence of server
bugs.

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

doc/config.but
putty.h
settings.c
ssh.c
winctrls.c
windlg.c
winstuff.h

index f032ccf..4a855e0 100644 (file)
@@ -1,4 +1,4 @@
-\versionid $Id: config.but,v 1.36 2002/09/08 13:25:58 jacob Exp $
+\versionid $Id: config.but,v 1.37 2002/09/08 13:28:38 simon Exp $
 
 \C{config} Configuring PuTTY
 
 
 \C{config} Configuring PuTTY
 
@@ -1356,6 +1356,10 @@ server.
 Keepalives are only supported in Telnet and SSH; the Rlogin and Raw
 protocols offer no way of implementing them.
 
 Keepalives are only supported in Telnet and SSH; the Rlogin and Raw
 protocols offer no way of implementing them.
 
+Note that if you are using SSH1 and the server has a bug that makes
+it unable to deal with SSH1 ignore messages (see
+\k{config-ssh-bug-ignore1}), enabling keepalives will have no effect.
+
 \S{config-nodelay} \q{Disable Nagle's algorithm}
 
 \cfg{winhelp-topic}{connection.nodelay}
 \S{config-nodelay} \q{Disable Nagle's algorithm}
 
 \cfg{winhelp-topic}{connection.nodelay}
@@ -1662,20 +1666,6 @@ If you select \q{1 only} or \q{2 only} here, PuTTY will only connect
 if the server you connect to offers the SSH protocol version you
 have specified.
 
 if the server you connect to offers the SSH protocol version you
 have specified.
 
-\S{config-ssh-macbug} \q{Imitate SSH 2 MAC bug}
-
-\cfg{winhelp-topic}{ssh.buggymac}
-
-This option \e{should} now be unnecessary. It existed in order to
-work around a bug in early versions (2.3.0 and below) of the SSH
-server software from \cw{ssh.com}. The symptom of this problem would
-be that PuTTY would die unexpectedly at the beginning of the
-session, saying \q{Incorrect MAC received on packet}.
-
-Current versions of PuTTY attempt to detect these faulty servers and
-enable the bug compatibility automatically, so you should never need
-to use this option any more.
-
 \S{config-ssh-encryption} Encryption algorithm selection
 
 \cfg{winhelp-topic}{ssh.ciphers}
 \S{config-ssh-encryption} Encryption algorithm selection
 
 \cfg{winhelp-topic}{ssh.ciphers}
@@ -1870,6 +1860,146 @@ SSH server machine can connect to the forwarded port.) Note that
 this feature is only available in the SSH 2 protocol, and not all
 SSH 2 servers support it (OpenSSH 3.0 does not, for example).
 
 this feature is only available in the SSH 2 protocol, and not all
 SSH 2 servers support it (OpenSSH 3.0 does not, for example).
 
+\H{config-ssh-bugs} The Bugs panel
+
+Not all SSH servers work properly. Various existing servers have
+bugs in them, which can make it impossible for a client to talk to
+them unless it knows about the bug and works around it.
+
+Since most servers announce their software version number at the
+beginning of the SSH connection, PuTTY will attempt to detect which
+bugs it can expect to see in the server and automatically enable
+workarounds. However, sometimes it will make mistakes; if the server
+has been deliberately configured to conceal its version number, or
+if the server is a version which PuTTY's bug database does not know
+about, then PuTTY will not know what bugs to expect.
+
+The Bugs panel allows you to manually configure the bugs PuTTY
+expects to see in the server. Each bug can be configured in three
+states:
+
+\b \q{Off}: PuTTY will assume the server does not have the bug.
+
+\b \q{On}: PuTTY will assume the server \e{does} have the bug.
+
+\b \q{Auto}: PuTTY will use the server's version number announcement
+to try to guess whether or not the server has the bug.
+
+\S{config-ssh-bug-ignore1} \q{Chokes on SSH1 ignore messages}
+
+\cfg{winhelp-topic}{ssh.bugs.ignore1}
+
+An ignore message (SSH_MSG_IGNORE) is a message in the SSH protocol
+which can be sent from the client to the server, or from the server
+to the client, at any time. Either side is required to ignore the
+message whenever it receives it. PuTTY uses ignore messages to hide
+the password packet in SSH1, so that a listener cannot tell the
+length of the user's password; it also uses ignore messages for
+connection keepalives (see \k{config-keepalive}).
+
+If this bug is detected, PuTTY will stop using ignore messages. This
+means that keepalives will stop working, and PuTTY will have to fall
+back to a secondary defence against SSH1 password-length
+eavesdropping. See \k{config-ssh-bug-plainpw1}. If this bug is
+enabled when talking to a correct server, the session will succeed,
+but keepalives will not work and the session might be more
+vulnerable to eavesdroppers than it could be.
+
+This is an SSH1-specific bug. No known SSH2 server fails to deal
+with SSH2 ignore messages.
+
+\S{config-ssh-bug-plainpw1} \q{Refuses all SSH1 password camouflage}
+
+\cfg{winhelp-topic}{ssh.bugs.plainpw1}
+
+When talking to an SSH1 server which cannot deal with ignore
+messages (see \k{config-ssh-bug-ignore1}), PuTTY will attempt to
+disguise the length of the user's password by sending additional
+padding \e{within} the password packet. This is technically a
+violation of the SSH1 specification, and so PuTTY will only do it
+when it cannot use standards-compliant ignore messages as
+camouflage. In this sense, for a server to refuse to accept a padded
+password packet is not really a bug, but it does make life
+inconvenient if the server can also not handle ignore messages.
+
+If this \q{bug} is detected, PuTTY will have no choice but to send
+the user's password with no form of camouflage, so that an
+eavesdropping user will be easily able to find out the exact length
+of the password. If this bug is enabled when talking to a correct
+server, the session will succeed, but will be more vulnerable to
+eavesdroppers than it could be.
+
+This is an SSH1-specific bug. SSH2 is secure against this type of
+attack.
+
+\S{config-ssh-bug-rsa1} \q{Chokes on SSH1 RSA authentication}
+
+\cfg{winhelp-topic}{ssh.bugs.rsa1}
+
+Some SSH1 servers cannot deal with RSA authentication messages at
+all. If Pageant is running and contains any SSH1 keys, PuTTY will
+normally automatically try RSA authentication before falling back to
+passwords, so these servers will crash when they see the RSA attempt.
+
+If this bug is detected, PuTTY will go straight to password
+authentication. If this bug is enabled when talking to a correct
+server, the session will succeed, but of course RSA authentication
+will be impossible.
+
+This is an SSH1-specific bug.
+
+\S{config-ssh-bug-hmac2} \q{Miscomputes SSH2 HMAC keys}
+
+\cfg{winhelp-topic}{ssh.bugs.hmac2}
+
+Versions 2.3.0 and below of the SSH server software from
+\cw{ssh.com} compute the keys for their HMAC message authentication
+codes incorrectly. A typical symptom of this problem is that PuTTY
+dies unexpectedly at the beginning of the session, saying
+\q{Incorrect MAC received on packet}.
+
+If this bug is detected, PuTTY will compute its HMAC keys in the
+same way as the buggy server, so that communication will still be
+possible. If this bug is enabled when talking to a correct server,
+communication will fail.
+
+This is an SSH2-specific bug.
+
+\S{config-ssh-bug-derivekey2} \q{Miscomputes SSH2 encryption keys}
+
+\cfg{winhelp-topic}{ssh.bugs.derivekey2}
+
+Versions below 2.1.0 of the SSH server software from \cw{ssh.com}
+compute the keys for the session encryption incorrectly. This
+problem can cause various error messages, such as \q{Incoming packet
+was garbled on decryption}, or possibly even \q{Out of memory}.
+
+If this bug is detected, PuTTY will compute its encryption keys in
+the same way as the buggy server, so that communication will still
+be possible. If this bug is enabled when talking to a correct
+server, communication will fail.
+
+This is an SSH2-specific bug.
+
+\S{config-ssh-bug-ssh} \q{Requires padding on SSH2 RSA signatures}
+
+\cfg{winhelp-topic}{ssh.bugs.rsapad2}
+
+Versions below 3.3 of OpenSSH require SSH2 RSA signatures to be
+padded with zero bytes to the same length as the RSA key modulus.
+The SSH2 draft specification says that an unpadded signature MUST be
+accepted, so this is a bug. A typical symptom of this problem is
+that PuTTY mysteriously fails RSA authentication once in every few
+hundred attempts, and falls back to passwords.
+
+If this bug is detected, PuTTY will pad its signatures in the way
+OpenSSH expects. If this bug is enabled when talking to a correct
+server, it is likely that no damage will be done, since correct
+servers usually still accept padded signatures because they're used
+to talking to OpenSSH.
+
+This is an SSH2-specific bug.
+
 \H{config-file} Storing configuration in a file
 
 PuTTY does not currently support storing its configuration in a file
 \H{config-file} Storing configuration in a file
 
 PuTTY does not currently support storing its configuration in a file
diff --git a/putty.h b/putty.h
index 9994b85..e98bd7d 100644 (file)
--- a/putty.h
+++ b/putty.h
@@ -368,6 +368,11 @@ typedef struct {
     int lport_acceptall; /* accept conns from hosts other than localhost */
     int rport_acceptall; /* same for remote forwarded ports (SSH2 only) */
     char portfwd[1024]; /* [LR]localport\thost:port\000[LR]localport\thost:port\000\000 */
     int lport_acceptall; /* accept conns from hosts other than localhost */
     int rport_acceptall; /* same for remote forwarded ports (SSH2 only) */
     char portfwd[1024]; /* [LR]localport\thost:port\000[LR]localport\thost:port\000\000 */
+    /* SSH bug compatibility modes */
+    enum {
+       BUG_AUTO, BUG_OFF, BUG_ON
+    } sshbug_ignore1, sshbug_plainpw1, sshbug_rsa1,
+       sshbug_hmac2, sshbug_derivekey2, sshbug_rsapad2;
 } Config;
 
 /*
 } Config;
 
 /*
index febd950..faed9e5 100644 (file)
@@ -189,7 +189,6 @@ void save_settings(char *section, int do_host, Config * cfg)
     write_setting_i(sesskey, "AuthTIS", cfg->try_tis_auth);
     write_setting_i(sesskey, "AuthKI", cfg->try_ki_auth);
     write_setting_i(sesskey, "SshProt", cfg->sshprot);
     write_setting_i(sesskey, "AuthTIS", cfg->try_tis_auth);
     write_setting_i(sesskey, "AuthKI", cfg->try_ki_auth);
     write_setting_i(sesskey, "SshProt", cfg->sshprot);
-    write_setting_i(sesskey, "BuggyMAC", cfg->buggymac);
     write_setting_i(sesskey, "SSH2DES", cfg->ssh2_des_cbc);
     write_setting_s(sesskey, "PublicKeyFile", cfg->keyfile);
     write_setting_s(sesskey, "RemoteCommand", cfg->remote_cmd);
     write_setting_i(sesskey, "SSH2DES", cfg->ssh2_des_cbc);
     write_setting_s(sesskey, "PublicKeyFile", cfg->keyfile);
     write_setting_s(sesskey, "RemoteCommand", cfg->remote_cmd);
@@ -304,7 +303,12 @@ void save_settings(char *section, int do_host, Config * cfg)
        *p = '\0';
        write_setting_s(sesskey, "PortForwardings", buf);
     }
        *p = '\0';
        write_setting_s(sesskey, "PortForwardings", buf);
     }
-
+    write_setting_i(sesskey, "BugIgnore1", cfg->sshbug_ignore1);
+    write_setting_i(sesskey, "BugPlainPW1", cfg->sshbug_plainpw1);
+    write_setting_i(sesskey, "BugRSA1", cfg->sshbug_rsa1);
+    write_setting_i(sesskey, "BugHMAC2", cfg->sshbug_hmac2);
+    write_setting_i(sesskey, "BugDeriveKey2", cfg->sshbug_derivekey2);
+    write_setting_i(sesskey, "BugRSAPad2", cfg->sshbug_rsapad2);
     close_settings_w(sesskey);
 }
 
     close_settings_w(sesskey);
 }
 
@@ -400,7 +404,6 @@ void load_settings(char *section, int do_host, Config * cfg)
     gprefs(sesskey, "Cipher", "\0",
           ciphernames, CIPHER_MAX, cfg->ssh_cipherlist);
     gppi(sesskey, "SshProt", 1, &cfg->sshprot);
     gprefs(sesskey, "Cipher", "\0",
           ciphernames, CIPHER_MAX, cfg->ssh_cipherlist);
     gppi(sesskey, "SshProt", 1, &cfg->sshprot);
-    gppi(sesskey, "BuggyMAC", 0, &cfg->buggymac);
     gppi(sesskey, "SSH2DES", 0, &cfg->ssh2_des_cbc);
     gppi(sesskey, "AuthTIS", 0, &cfg->try_tis_auth);
     gppi(sesskey, "AuthKI", 1, &cfg->try_ki_auth);
     gppi(sesskey, "SSH2DES", 0, &cfg->ssh2_des_cbc);
     gppi(sesskey, "AuthTIS", 0, &cfg->try_tis_auth);
     gppi(sesskey, "AuthKI", 1, &cfg->try_ki_auth);
@@ -566,6 +569,20 @@ void load_settings(char *section, int do_host, Config * cfg)
        }
        *q = '\0';
     }
        }
        *q = '\0';
     }
+    gppi(sesskey, "BugIgnore1", BUG_AUTO, &cfg->sshbug_ignore1);
+    gppi(sesskey, "BugPlainPW1", BUG_AUTO, &cfg->sshbug_plainpw1);
+    gppi(sesskey, "BugRSA1", BUG_AUTO, &cfg->sshbug_rsa1);
+    {
+       int i;
+       gppi(sesskey, "BugHMAC2", BUG_AUTO, &cfg->sshbug_hmac2);
+       if (cfg->sshbug_hmac2 == BUG_AUTO) {
+           gppi(sesskey, "BuggyMAC", 0, &i);
+           if (i == 1)
+               cfg->sshbug_hmac2 = BUG_ON;
+       }
+    }
+    gppi(sesskey, "BugDeriveKey2", BUG_AUTO, &cfg->sshbug_derivekey2);
+    gppi(sesskey, "BugRSAPad2", BUG_AUTO, &cfg->sshbug_rsapad2);
 
     close_settings_r(sesskey);
 }
 
     close_settings_r(sesskey);
 }
diff --git a/ssh.c b/ssh.c
index d998d08..58b6b42 100644 (file)
--- a/ssh.c
+++ b/ssh.c
@@ -1660,9 +1660,11 @@ static void ssh_detect_bugs(char *vstring)
 
     ssh_remote_bugs = 0;
 
 
     ssh_remote_bugs = 0;
 
-    if (!strcmp(imp, "1.2.18") || !strcmp(imp, "1.2.19") ||
-       !strcmp(imp, "1.2.20") || !strcmp(imp, "1.2.21") ||
-       !strcmp(imp, "1.2.22") || !strcmp(imp, "Cisco-1.25")) {
+    if (cfg.sshbug_ignore1 == BUG_ON ||
+       (cfg.sshbug_ignore1 == BUG_AUTO &&
+        (!strcmp(imp, "1.2.18") || !strcmp(imp, "1.2.19") ||
+         !strcmp(imp, "1.2.20") || !strcmp(imp, "1.2.21") ||
+         !strcmp(imp, "1.2.22") || !strcmp(imp, "Cisco-1.25")))) {
        /*
         * These versions don't support SSH1_MSG_IGNORE, so we have
         * to use a different defence against password length
        /*
         * These versions don't support SSH1_MSG_IGNORE, so we have
         * to use a different defence against password length
@@ -1672,7 +1674,9 @@ static void ssh_detect_bugs(char *vstring)
        logevent("We believe remote version has SSH1 ignore bug");
     }
 
        logevent("We believe remote version has SSH1 ignore bug");
     }
 
-    if (!strcmp(imp, "Cisco-1.25")) {
+    if (cfg.sshbug_plainpw1 == BUG_ON ||
+       (cfg.sshbug_plainpw1 == BUG_AUTO &&
+        (!strcmp(imp, "Cisco-1.25")))) {
        /*
         * These versions need a plain password sent; they can't
         * handle having a null and a random length of data after
        /*
         * These versions need a plain password sent; they can't
         * handle having a null and a random length of data after
@@ -1682,7 +1686,9 @@ static void ssh_detect_bugs(char *vstring)
        logevent("We believe remote version needs a plain SSH1 password");
     }
 
        logevent("We believe remote version needs a plain SSH1 password");
     }
 
-    if (!strcmp(imp, "Cisco-1.25")) {
+    if (cfg.sshbug_rsa1 == BUG_ON ||
+       (cfg.sshbug_rsa1 == BUG_AUTO &&
+        (!strcmp(imp, "Cisco-1.25")))) {
        /*
         * These versions apparently have no clue whatever about
         * RSA authentication and will panic and die if they see
        /*
         * These versions apparently have no clue whatever about
         * RSA authentication and will panic and die if they see
@@ -1692,9 +1698,11 @@ static void ssh_detect_bugs(char *vstring)
        logevent("We believe remote version can't handle RSA authentication");
     }
 
        logevent("We believe remote version can't handle RSA authentication");
     }
 
-    if (!strncmp(imp, "2.1.0", 5) || !strncmp(imp, "2.0.", 4) ||
-       !strncmp(imp, "2.2.0", 5) || !strncmp(imp, "2.3.0", 5) ||
-       !strncmp(imp, "2.1 ", 4)) {
+    if (cfg.sshbug_hmac2 == BUG_ON ||
+       (cfg.sshbug_hmac2 == BUG_AUTO &&
+        (!strncmp(imp, "2.1.0", 5) || !strncmp(imp, "2.0.", 4) ||
+         !strncmp(imp, "2.2.0", 5) || !strncmp(imp, "2.3.0", 5) ||
+         !strncmp(imp, "2.1 ", 4)))) {
        /*
         * These versions have the HMAC bug.
         */
        /*
         * These versions have the HMAC bug.
         */
@@ -1702,7 +1710,9 @@ static void ssh_detect_bugs(char *vstring)
        logevent("We believe remote version has SSH2 HMAC bug");
     }
 
        logevent("We believe remote version has SSH2 HMAC bug");
     }
 
-    if (!strncmp(imp, "2.0.", 4)) {
+    if (cfg.sshbug_derivekey2 == BUG_ON ||
+       (cfg.sshbug_derivekey2 == BUG_AUTO &&
+        (!strncmp(imp, "2.0.", 4)))) {
        /*
         * These versions have the key-derivation bug (failing to
         * include the literal shared secret in the hashes that
        /*
         * These versions have the key-derivation bug (failing to
         * include the literal shared secret in the hashes that
@@ -1712,8 +1722,10 @@ static void ssh_detect_bugs(char *vstring)
        logevent("We believe remote version has SSH2 key-derivation bug");
     }
 
        logevent("We believe remote version has SSH2 key-derivation bug");
     }
 
-    if ((!strncmp(imp, "OpenSSH_2.", 10) && imp[10]>='5' && imp[10]<='9') ||
-       (!strncmp(imp, "OpenSSH_3.", 10) && imp[10]>='0' && imp[10]<='2')) {
+    if (cfg.sshbug_rsapad2 == BUG_ON ||
+       (cfg.sshbug_rsapad2 == BUG_AUTO &&
+        ((!strncmp(imp, "OpenSSH_2.", 10) && imp[10]>='5' && imp[10]<='9') ||
+         (!strncmp(imp, "OpenSSH_3.", 10) && imp[10]>='0' && imp[10]<='2')))){
        /*
         * These versions have the SSH2 RSA padding bug.
         */
        /*
         * These versions have the SSH2 RSA padding bug.
         */
@@ -5787,7 +5799,8 @@ static void ssh_special(Telnet_Special code)
        if (ssh_state == SSH_STATE_CLOSED
            || ssh_state == SSH_STATE_PREPACKET) return;
        if (ssh_version == 1) {
        if (ssh_state == SSH_STATE_CLOSED
            || ssh_state == SSH_STATE_PREPACKET) return;
        if (ssh_version == 1) {
-           send_packet(SSH1_MSG_IGNORE, PKT_STR, "", PKT_END);
+           if (!(ssh_remote_bugs & BUG_CHOKES_ON_SSH1_IGNORE))
+               send_packet(SSH1_MSG_IGNORE, PKT_STR, "", PKT_END);
        } else {
            ssh2_pkt_init(SSH2_MSG_IGNORE);
            ssh2_pkt_addstring_start();
        } else {
            ssh2_pkt_init(SSH2_MSG_IGNORE);
            ssh2_pkt_addstring_start();
index df0edce..f44a0be 100644 (file)
@@ -448,6 +448,40 @@ void staticpassedit(struct ctlpos *cp, char *stext,
 }
 
 /*
 }
 
 /*
+ * A drop-down list box on the right hand side, with a static to
+ * its left.
+ */
+void staticddl(struct ctlpos *cp, char *stext,
+              int sid, int lid, int percentlist)
+{
+    const int height = (COMBOHEIGHT > STATICHEIGHT ?
+                       COMBOHEIGHT : STATICHEIGHT);
+    RECT r;
+    int lwid, rwid, rpos;
+
+    rpos =
+       GAPBETWEEN + (100 - percentlist) * (cp->width + GAPBETWEEN) / 100;
+    lwid = rpos - 2 * GAPBETWEEN;
+    rwid = cp->width + GAPBETWEEN - rpos;
+
+    r.left = GAPBETWEEN;
+    r.top = cp->ypos + (height - STATICHEIGHT) / 2;
+    r.right = lwid;
+    r.bottom = STATICHEIGHT;
+    doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0, stext, sid);
+
+    r.left = rpos;
+    r.top = cp->ypos + (height - EDITHEIGHT) / 2;
+    r.right = rwid;
+    r.bottom = COMBOHEIGHT*4;
+    doctl(cp, r, "COMBOBOX",
+         WS_CHILD | WS_VISIBLE | WS_TABSTOP |
+         CBS_DROPDOWNLIST | CBS_HASSTRINGS, WS_EX_CLIENTEDGE, "", lid);
+
+    cp->ypos += height + GAPBETWEEN;
+}
+
+/*
  * A big multiline edit control with a static labelling it.
  */
 void bigeditctrl(struct ctlpos *cp, char *stext,
  * A big multiline edit control with a static labelling it.
  */
 void bigeditctrl(struct ctlpos *cp, char *stext,
index 474a054..76d4804 100644 (file)
--- a/windlg.c
+++ b/windlg.c
@@ -509,7 +509,6 @@ enum { IDCX_ABOUT =
     IDC_CIPHERLIST,
     IDC_CIPHERUP,
     IDC_CIPHERDN,
     IDC_CIPHERLIST,
     IDC_CIPHERUP,
     IDC_CIPHERDN,
-    IDC_BUGGYMAC,
     IDC_SSH2DES,
     IDC_SSHPROTSTATIC,
     IDC_SSHPROT1ONLY,
     IDC_SSH2DES,
     IDC_SSHPROTSTATIC,
     IDC_SSHPROT1ONLY,
@@ -534,6 +533,23 @@ enum { IDCX_ABOUT =
     IDC_AUTHKI,
     sshauthpanelend,
 
     IDC_AUTHKI,
     sshauthpanelend,
 
+    sshbugspanelstart,
+    IDC_TITLE_SSHBUGS,
+    IDC_BOX_SSHBUGS1,
+    IDC_BUGS_IGNORE1,
+    IDC_BUGD_IGNORE1,
+    IDC_BUGS_PLAINPW1,
+    IDC_BUGD_PLAINPW1,
+    IDC_BUGS_RSA1,
+    IDC_BUGD_RSA1,
+    IDC_BUGS_HMAC2,
+    IDC_BUGD_HMAC2,
+    IDC_BUGS_DERIVEKEY2,
+    IDC_BUGD_DERIVEKEY2,
+    IDC_BUGS_RSAPAD2,
+    IDC_BUGD_RSAPAD2,
+    sshbugspanelend,
+
     selectionpanelstart,
     IDC_TITLE_SELECTION,
     IDC_BOX_SELECTION1,
     selectionpanelstart,
     IDC_TITLE_SELECTION,
     IDC_BOX_SELECTION1,
@@ -889,8 +905,6 @@ char *help_context_cmd(int id)
       case IDC_CIPHERDN:
       case IDC_SSH2DES:
         return "JI(`',`ssh.ciphers')";
       case IDC_CIPHERDN:
       case IDC_SSH2DES:
         return "JI(`',`ssh.ciphers')";
-      case IDC_BUGGYMAC:
-        return "JI(`',`ssh.buggymac')";
       case IDC_SSHPROTSTATIC:
       case IDC_SSHPROT1ONLY:
       case IDC_SSHPROT1:
       case IDC_SSHPROTSTATIC:
       case IDC_SSHPROT1ONLY:
       case IDC_SSHPROT1:
@@ -985,6 +999,25 @@ char *help_context_cmd(int id)
       case IDC_RPORT_ALL:
         return "JI(`',`ssh.tunnels.portfwd.localhost')";
 
       case IDC_RPORT_ALL:
         return "JI(`',`ssh.tunnels.portfwd.localhost')";
 
+      case IDC_BUGS_IGNORE1:
+      case IDC_BUGD_IGNORE1:
+       return "JI(`',`ssh.bugs.ignore1')";
+      case IDC_BUGS_PLAINPW1:
+      case IDC_BUGD_PLAINPW1:
+       return "JI(`',`ssh.bugs.plainpw1')";
+      case IDC_BUGS_RSA1:
+      case IDC_BUGD_RSA1:
+       return "JI(`',`ssh.bugs.rsa1')";
+      case IDC_BUGS_HMAC2:
+      case IDC_BUGD_HMAC2:
+       return "JI(`',`ssh.bugs.hmac2')";
+      case IDC_BUGS_DERIVEKEY2:
+      case IDC_BUGD_DERIVEKEY2:
+       return "JI(`',`ssh.bugs.derivekey2')";
+      case IDC_BUGS_RSAPAD2:
+      case IDC_BUGD_RSAPAD2:
+       return "JI(`',`ssh.bugs.rsapad2')";
+
       default:
         return NULL;
     }
       default:
         return NULL;
     }
@@ -1149,7 +1182,6 @@ static void init_dlg_ctrls(HWND hwnd, int keepsess)
     SetDlgItemText(hwnd, IDC_LOGEDIT, cfg.username);
     CheckDlgButton(hwnd, IDC_NOPTY, cfg.nopty);
     CheckDlgButton(hwnd, IDC_COMPRESS, cfg.compression);
     SetDlgItemText(hwnd, IDC_LOGEDIT, cfg.username);
     CheckDlgButton(hwnd, IDC_NOPTY, cfg.nopty);
     CheckDlgButton(hwnd, IDC_COMPRESS, cfg.compression);
-    CheckDlgButton(hwnd, IDC_BUGGYMAC, cfg.buggymac);
     CheckDlgButton(hwnd, IDC_SSH2DES, cfg.ssh2_des_cbc);
     CheckDlgButton(hwnd, IDC_AGENTFWD, cfg.agentfwd);
     CheckDlgButton(hwnd, IDC_CHANGEUSER, cfg.change_username);
     CheckDlgButton(hwnd, IDC_SSH2DES, cfg.ssh2_des_cbc);
     CheckDlgButton(hwnd, IDC_AGENTFWD, cfg.agentfwd);
     CheckDlgButton(hwnd, IDC_CHANGEUSER, cfg.change_username);
@@ -1288,6 +1320,50 @@ static void init_dlg_ctrls(HWND hwnd, int keepsess)
     SetDlgItemText(hwnd, IDC_PROXYPASSEDIT, cfg.proxy_password);
     CheckRadioButton(hwnd, IDC_PROXYSOCKSVER5, IDC_PROXYSOCKSVER4,
                     cfg.proxy_socks_version == 4 ? IDC_PROXYSOCKSVER4 : IDC_PROXYSOCKSVER5);
     SetDlgItemText(hwnd, IDC_PROXYPASSEDIT, cfg.proxy_password);
     CheckRadioButton(hwnd, IDC_PROXYSOCKSVER5, IDC_PROXYSOCKSVER4,
                     cfg.proxy_socks_version == 4 ? IDC_PROXYSOCKSVER4 : IDC_PROXYSOCKSVER5);
+
+    /* SSH bugs config */
+    SendDlgItemMessage(hwnd, IDC_BUGD_IGNORE1, CB_RESETCONTENT, 0, 0);
+    SendDlgItemMessage(hwnd, IDC_BUGD_IGNORE1, CB_ADDSTRING, 0, (LPARAM)"Auto");
+    SendDlgItemMessage(hwnd, IDC_BUGD_IGNORE1, CB_ADDSTRING, 0, (LPARAM)"Off");
+    SendDlgItemMessage(hwnd, IDC_BUGD_IGNORE1, CB_ADDSTRING, 0, (LPARAM)"On");
+    SendDlgItemMessage(hwnd, IDC_BUGD_IGNORE1, CB_SETCURSEL,
+                      cfg.sshbug_ignore1 == BUG_ON ? 2 :
+                      cfg.sshbug_ignore1 == BUG_OFF ? 1 : 0, 0);
+    SendDlgItemMessage(hwnd, IDC_BUGD_PLAINPW1, CB_RESETCONTENT, 0, 0);
+    SendDlgItemMessage(hwnd, IDC_BUGD_PLAINPW1, CB_ADDSTRING, 0, (LPARAM)"Auto");
+    SendDlgItemMessage(hwnd, IDC_BUGD_PLAINPW1, CB_ADDSTRING, 0, (LPARAM)"Off");
+    SendDlgItemMessage(hwnd, IDC_BUGD_PLAINPW1, CB_ADDSTRING, 0, (LPARAM)"On");
+    SendDlgItemMessage(hwnd, IDC_BUGD_PLAINPW1, CB_SETCURSEL,
+                      cfg.sshbug_plainpw1 == BUG_ON ? 2 :
+                      cfg.sshbug_plainpw1 == BUG_OFF ? 1 : 0, 0);
+    SendDlgItemMessage(hwnd, IDC_BUGD_RSA1, CB_RESETCONTENT, 0, 0);
+    SendDlgItemMessage(hwnd, IDC_BUGD_RSA1, CB_ADDSTRING, 0, (LPARAM)"Auto");
+    SendDlgItemMessage(hwnd, IDC_BUGD_RSA1, CB_ADDSTRING, 0, (LPARAM)"Off");
+    SendDlgItemMessage(hwnd, IDC_BUGD_RSA1, CB_ADDSTRING, 0, (LPARAM)"On");
+    SendDlgItemMessage(hwnd, IDC_BUGD_RSA1, CB_SETCURSEL,
+                      cfg.sshbug_rsa1 == BUG_ON ? 2 :
+                      cfg.sshbug_rsa1 == BUG_OFF ? 1 : 0, 0);
+    SendDlgItemMessage(hwnd, IDC_BUGD_HMAC2, CB_RESETCONTENT, 0, 0);
+    SendDlgItemMessage(hwnd, IDC_BUGD_HMAC2, CB_ADDSTRING, 0, (LPARAM)"Auto");
+    SendDlgItemMessage(hwnd, IDC_BUGD_HMAC2, CB_ADDSTRING, 0, (LPARAM)"Off");
+    SendDlgItemMessage(hwnd, IDC_BUGD_HMAC2, CB_ADDSTRING, 0, (LPARAM)"On");
+    SendDlgItemMessage(hwnd, IDC_BUGD_HMAC2, CB_SETCURSEL,
+                      cfg.sshbug_hmac2 == BUG_ON ? 2 :
+                      cfg.sshbug_hmac2 == BUG_OFF ? 1 : 0, 0);
+    SendDlgItemMessage(hwnd, IDC_BUGD_DERIVEKEY2, CB_RESETCONTENT, 0, 0);
+    SendDlgItemMessage(hwnd, IDC_BUGD_DERIVEKEY2, CB_ADDSTRING, 0, (LPARAM)"Auto");
+    SendDlgItemMessage(hwnd, IDC_BUGD_DERIVEKEY2, CB_ADDSTRING, 0, (LPARAM)"Off");
+    SendDlgItemMessage(hwnd, IDC_BUGD_DERIVEKEY2, CB_ADDSTRING, 0, (LPARAM)"On");
+    SendDlgItemMessage(hwnd, IDC_BUGD_DERIVEKEY2, CB_SETCURSEL,
+                      cfg.sshbug_derivekey2 == BUG_ON ? 2 :
+                      cfg.sshbug_derivekey2 == BUG_OFF ? 1 : 0, 0);
+    SendDlgItemMessage(hwnd, IDC_BUGD_RSAPAD2, CB_RESETCONTENT, 0, 0);
+    SendDlgItemMessage(hwnd, IDC_BUGD_RSAPAD2, CB_ADDSTRING, 0, (LPARAM)"Auto");
+    SendDlgItemMessage(hwnd, IDC_BUGD_RSAPAD2, CB_ADDSTRING, 0, (LPARAM)"Off");
+    SendDlgItemMessage(hwnd, IDC_BUGD_RSAPAD2, CB_ADDSTRING, 0, (LPARAM)"On");
+    SendDlgItemMessage(hwnd, IDC_BUGD_RSAPAD2, CB_SETCURSEL,
+                      cfg.sshbug_rsapad2 == BUG_ON ? 2 :
+                      cfg.sshbug_rsapad2 == BUG_OFF ? 1 : 0, 0);
 }
 
 struct treeview_faff {
 }
 
 struct treeview_faff {
@@ -1833,8 +1909,6 @@ static void create_controls(HWND hwnd, int dlgtype, int panel)
                      "1 on&ly", IDC_SSHPROT1ONLY,
                      "&1", IDC_SSHPROT1, "&2", IDC_SSHPROT2,
                      "2 o&nly", IDC_SSHPROT2ONLY, NULL);
                      "1 on&ly", IDC_SSHPROT1ONLY,
                      "&1", IDC_SSHPROT1, "&2", IDC_SSHPROT2,
                      "2 o&nly", IDC_SSHPROT2ONLY, NULL);
-           checkbox(&cp, "&Imitate SSH 2 MAC bug in commercial <= v2.3.x",
-                    IDC_BUGGYMAC);
            endbox(&cp);
            beginbox(&cp, "Encryption options", IDC_BOX_SSH3);
            prefslist(&cipherlist, &cp, "Encryption cipher &selection policy:",
            endbox(&cp);
            beginbox(&cp, "Encryption options", IDC_BOX_SSH3);
            prefslist(&cipherlist, &cp, "Encryption cipher &selection policy:",
@@ -1872,6 +1946,31 @@ static void create_controls(HWND hwnd, int dlgtype, int panel)
        }
     }
 
        }
     }
 
+    if (panel == sshbugspanelstart) {
+       /* The SSH bugs panel. Accelerators used: [acgoh] isrmep */
+       struct ctlpos cp;
+       ctlposinit(&cp, hwnd, 80, 3, 13);
+       if (dlgtype == 0) {
+           bartitle(&cp, "Workarounds for SSH server bugs",
+                    IDC_TITLE_SSHBUGS);
+           beginbox(&cp, "Detection of known bugs in SSH servers",
+                    IDC_BOX_SSHBUGS1);
+           staticddl(&cp, "Chokes on SSH1 &ignore messages",
+                     IDC_BUGS_IGNORE1, IDC_BUGD_IGNORE1, 20);
+           staticddl(&cp, "Refuses all SSH1 pa&ssword camouflage",
+                     IDC_BUGS_PLAINPW1, IDC_BUGD_PLAINPW1, 20);
+           staticddl(&cp, "Chokes on SSH1 &RSA authentication",
+                     IDC_BUGS_RSA1, IDC_BUGD_RSA1, 20);
+           staticddl(&cp, "Miscomputes SSH2 H&MAC keys",
+                     IDC_BUGS_HMAC2, IDC_BUGD_HMAC2, 20);
+           staticddl(&cp, "Miscomputes SSH2 &encryption keys",
+                     IDC_BUGS_DERIVEKEY2, IDC_BUGD_DERIVEKEY2, 20);
+           staticddl(&cp, "Requires &padding on SSH2 RSA signatures",
+                     IDC_BUGS_RSAPAD2, IDC_BUGD_RSAPAD2, 20);
+           endbox(&cp);
+       }
+    }
+
     if (panel == tunnelspanelstart) {
        /* The Tunnels panel. Accelerators used: [acgoh] deilmrstxp */
        struct ctlpos cp;
     if (panel == tunnelspanelstart) {
        /* The Tunnels panel. Accelerators used: [acgoh] deilmrstxp */
        struct ctlpos cp;
@@ -2048,6 +2147,7 @@ static int GenericMainDlgProc(HWND hwnd, UINT msg,
                /* XXX make it closed by default? */
                treeview_insert(&tvfaff, 2, "Auth");
                treeview_insert(&tvfaff, 2, "Tunnels");
                /* XXX make it closed by default? */
                treeview_insert(&tvfaff, 2, "Auth");
                treeview_insert(&tvfaff, 2, "Tunnels");
+               treeview_insert(&tvfaff, 2, "Bugs");
            }
        }
 
            }
        }
 
@@ -2133,6 +2233,8 @@ static int GenericMainDlgProc(HWND hwnd, UINT msg,
                create_controls(hwnd, dlgtype, sshpanelstart);
            if (!strcmp(buffer, "Auth"))
                create_controls(hwnd, dlgtype, sshauthpanelstart);
                create_controls(hwnd, dlgtype, sshpanelstart);
            if (!strcmp(buffer, "Auth"))
                create_controls(hwnd, dlgtype, sshauthpanelstart);
+           if (!strcmp(buffer, "Bugs"))
+               create_controls(hwnd, dlgtype, sshbugspanelstart);
            if (!strcmp(buffer, "Selection"))
                create_controls(hwnd, dlgtype, selectionpanelstart);
            if (!strcmp(buffer, "Colours"))
            if (!strcmp(buffer, "Selection"))
                create_controls(hwnd, dlgtype, selectionpanelstart);
            if (!strcmp(buffer, "Colours"))
@@ -3063,12 +3165,6 @@ static int GenericMainDlgProc(HWND hwnd, UINT msg,
                        cfg.compression =
                        IsDlgButtonChecked(hwnd, IDC_COMPRESS);
                break;
                        cfg.compression =
                        IsDlgButtonChecked(hwnd, IDC_COMPRESS);
                break;
-             case IDC_BUGGYMAC:
-               if (HIWORD(wParam) == BN_CLICKED ||
-                   HIWORD(wParam) == BN_DOUBLECLICKED)
-                       cfg.buggymac =
-                       IsDlgButtonChecked(hwnd, IDC_BUGGYMAC);
-               break;
              case IDC_SSH2DES:
                if (HIWORD(wParam) == BN_CLICKED ||
                    HIWORD(wParam) == BN_DOUBLECLICKED)
              case IDC_SSH2DES:
                if (HIWORD(wParam) == BN_CLICKED ||
                    HIWORD(wParam) == BN_DOUBLECLICKED)
@@ -3441,6 +3537,54 @@ static int GenericMainDlgProc(HWND hwnd, UINT msg,
                  disaster2:;
                }
                break;
                  disaster2:;
                }
                break;
+             case IDC_BUGD_IGNORE1:
+               if (HIWORD(wParam) == CBN_SELCHANGE) {
+                   int index = SendDlgItemMessage(hwnd, IDC_BUGD_IGNORE1,
+                                                  CB_GETCURSEL, 0, 0);
+                   cfg.sshbug_ignore1 = (index == 0 ? BUG_AUTO :
+                                         index == 1 ? BUG_OFF : BUG_ON);
+               }
+               break;
+             case IDC_BUGD_PLAINPW1:
+               if (HIWORD(wParam) == CBN_SELCHANGE) {
+                   int index = SendDlgItemMessage(hwnd, IDC_BUGD_PLAINPW1,
+                                                  CB_GETCURSEL, 0, 0);
+                   cfg.sshbug_plainpw1 = (index == 0 ? BUG_AUTO :
+                                          index == 1 ? BUG_OFF : BUG_ON);
+               }
+               break;
+             case IDC_BUGD_RSA1:
+               if (HIWORD(wParam) == CBN_SELCHANGE) {
+                   int index = SendDlgItemMessage(hwnd, IDC_BUGD_RSA1,
+                                                  CB_GETCURSEL, 0, 0);
+                   cfg.sshbug_rsa1 = (index == 0 ? BUG_AUTO :
+                                      index == 1 ? BUG_OFF : BUG_ON);
+               }
+               break;
+             case IDC_BUGD_HMAC2:
+               if (HIWORD(wParam) == CBN_SELCHANGE) {
+                   int index = SendDlgItemMessage(hwnd, IDC_BUGD_HMAC2,
+                                                  CB_GETCURSEL, 0, 0);
+                   cfg.sshbug_hmac2 = (index == 0 ? BUG_AUTO :
+                                       index == 1 ? BUG_OFF : BUG_ON);
+               }
+               break;
+             case IDC_BUGD_DERIVEKEY2:
+               if (HIWORD(wParam) == CBN_SELCHANGE) {
+                   int index = SendDlgItemMessage(hwnd, IDC_BUGD_DERIVEKEY2,
+                                                  CB_GETCURSEL, 0, 0);
+                   cfg.sshbug_derivekey2 = (index == 0 ? BUG_AUTO :
+                                            index == 1 ? BUG_OFF : BUG_ON);
+               }
+               break;
+             case IDC_BUGD_RSAPAD2:
+               if (HIWORD(wParam) == CBN_SELCHANGE) {
+                   int index = SendDlgItemMessage(hwnd, IDC_BUGD_RSAPAD2,
+                                                  CB_GETCURSEL, 0, 0);
+                   cfg.sshbug_rsapad2 = (index == 0 ? BUG_AUTO :
+                                         index == 1 ? BUG_OFF : BUG_ON);
+               }
+               break;
            }
        return 0;
       case WM_HELP:
            }
        return 0;
       case WM_HELP:
index a2e4821..6f080b3 100644 (file)
@@ -64,6 +64,8 @@ void static2btn(struct ctlpos *cp, char *stext, int sid,
                char *btext1, int bid1, char *btext2, int bid2);
 void staticedit(struct ctlpos *cp, char *stext,
                int sid, int eid, int percentedit);
                char *btext1, int bid1, char *btext2, int bid2);
 void staticedit(struct ctlpos *cp, char *stext,
                int sid, int eid, int percentedit);
+void staticddl(struct ctlpos *cp, char *stext,
+              int sid, int lid, int percentlist);
 void combobox(struct ctlpos *cp, char *text, int staticid, int listid);
 void staticpassedit(struct ctlpos *cp, char *stext,
                    int sid, int eid, int percentedit);
 void combobox(struct ctlpos *cp, char *text, int staticid, int listid);
 void staticpassedit(struct ctlpos *cp, char *stext,
                    int sid, int eid, int percentedit);