1
0
mirror of https://git.tartarus.org/simon/putty.git synced 2025-01-09 17:38:00 +00:00

New SSH bug flag, for 'can't handle SSH2_MSG_IGNORE'. Another user

today reported an SSH2_MSG_UNIMPLEMENTED from a Cisco router which
looks as if it was triggered by SSH2_MSG_IGNORE, so I'm
experimentally putting this flag in. Currently must be manually
enabled, though if it turns out to solve the user's problem then
I'll probably add at least one version string...

[Edited commit message: actually, I also committed in error a piece
of experimental code as part of this checkin. Serve me right for not
running 'svn diff' first.]

[originally from svn r8926]
This commit is contained in:
Simon Tatham 2010-04-23 18:32:15 +00:00
parent 97ca111e29
commit d5aa23c116
7 changed files with 82 additions and 12 deletions

View File

@ -2284,6 +2284,9 @@ void setup_config_box(struct controlbox *b, int midsession,
ctrl_droplist(s, "Chokes on SSH-1 RSA authentication", 'r', 20,
HELPCTX(ssh_bugs_rsa1),
sshbug_handler, I(offsetof(Config,sshbug_rsa1)));
ctrl_droplist(s, "Chokes on SSH-2 ignore messages", '2', 20,
HELPCTX(ssh_bugs_ignore2),
sshbug_handler, I(offsetof(Config,sshbug_ignore2)));
ctrl_droplist(s, "Miscomputes SSH-2 HMAC keys", 'm', 20,
HELPCTX(ssh_bugs_hmac2),
sshbug_handler, I(offsetof(Config,sshbug_hmac2)));

View File

@ -2948,9 +2948,6 @@ 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 SSH-1-specific bug. No known SSH-2 server fails to deal
with SSH-2 ignore messages.
\S{config-ssh-bug-plainpw1} \q{Refuses all SSH-1 \i{password camouflage}}
\cfg{winhelp-topic}{ssh.bugs.plainpw1}
@ -2992,6 +2989,23 @@ will be impossible.
This is an SSH-1-specific bug.
\S{config-ssh-bug-ignore2} \q{Chokes on SSH-2 \i{ignore message}s}
\cfg{winhelp-topic}{ssh.bugs.ignore2}
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 in SSH-2
to confuse the encrypted data stream and make it harder to
cryptanalyse. It also uses ignore messages for connection
\i{keepalives} (see \k{config-keepalive}).
If it believes the server to have this bug, PuTTY will stop using
ignore messages. 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 less cryptographically secure than it could be.
\S{config-ssh-bug-hmac2} \q{Miscomputes SSH-2 HMAC keys}
\cfg{winhelp-topic}{ssh.bugs.hmac2}

View File

@ -592,7 +592,8 @@ struct config_tag {
/* SSH bug compatibility modes */
int sshbug_ignore1, sshbug_plainpw1, sshbug_rsa1,
sshbug_hmac2, sshbug_derivekey2, sshbug_rsapad2,
sshbug_pksessid2, sshbug_rekey2, sshbug_maxpkt2;
sshbug_pksessid2, sshbug_rekey2, sshbug_maxpkt2,
sshbug_ignore2;
/*
* ssh_simple means that we promise never to open any channel other
* than the main one, which means it can safely use a very large
@ -825,6 +826,7 @@ void term_free(Terminal *);
void term_size(Terminal *, int, int, int);
void term_paint(Terminal *, Context, int, int, int, int, int);
void term_scroll(Terminal *, int, int);
void term_scroll_to_selection(Terminal *, int);
void term_pwron(Terminal *, int);
void term_clrsb(Terminal *);
void term_mouse(Terminal *, Mouse_Button, Mouse_Button, Mouse_Action,

View File

@ -477,6 +477,7 @@ void save_open_settings(void *sesskey, Config *cfg)
write_setting_i(sesskey, "BugIgnore1", 2-cfg->sshbug_ignore1);
write_setting_i(sesskey, "BugPlainPW1", 2-cfg->sshbug_plainpw1);
write_setting_i(sesskey, "BugRSA1", 2-cfg->sshbug_rsa1);
write_setting_i(sesskey, "BugIgnore2", 2-cfg->sshbug_ignore2);
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);
@ -817,6 +818,7 @@ void load_open_settings(void *sesskey, Config *cfg)
gppi(sesskey, "BugIgnore1", 0, &i); cfg->sshbug_ignore1 = 2-i;
gppi(sesskey, "BugPlainPW1", 0, &i); cfg->sshbug_plainpw1 = 2-i;
gppi(sesskey, "BugRSA1", 0, &i); cfg->sshbug_rsa1 = 2-i;
gppi(sesskey, "BugIgnore2", 0, &i); cfg->sshbug_ignore2 = 2-i;
{
int i;
gppi(sesskey, "BugHMAC2", 0, &i); cfg->sshbug_hmac2 = 2-i;

36
ssh.c
View File

@ -194,6 +194,7 @@ static const char *const ssh2_disconnect_reasons[] = {
#define BUG_SSH2_REKEY 64
#define BUG_SSH2_PK_SESSIONID 128
#define BUG_SSH2_MAXPKT 256
#define BUG_CHOKES_ON_SSH2_IGNORE 512
/*
* Codes for terminal modes.
@ -2011,7 +2012,8 @@ static void ssh2_pkt_defer_noqueue(Ssh ssh, struct Packet *pkt, int noignore)
{
int len;
if (ssh->cscipher != NULL && (ssh->cscipher->flags & SSH_CIPHER_IS_CBC) &&
ssh->deferred_len == 0 && !noignore) {
ssh->deferred_len == 0 && !noignore &&
!(ssh->remote_bugs & BUG_CHOKES_ON_SSH2_IGNORE)) {
/*
* Interpose an SSH_MSG_IGNORE to ensure that user data don't
* get encrypted with a known IV.
@ -2141,7 +2143,8 @@ static void ssh2_pkt_send_with_padding(Ssh ssh, struct Packet *pkt,
* unavailable, we don't do this trick at all, because we
* gain nothing by it.)
*/
if (ssh->cscipher) {
if (ssh->cscipher &&
!(ssh->remote_bugs & BUG_CHOKES_ON_SSH2_IGNORE)) {
int stringlen, i;
stringlen = (256 - ssh->deferred_len);
@ -2508,6 +2511,15 @@ static void ssh_detect_bugs(Ssh ssh, char *vstring)
ssh->remote_bugs |= BUG_SSH2_MAXPKT;
logevent("We believe remote version ignores SSH-2 maximum packet size");
}
if (ssh->cfg.sshbug_ignore2 == FORCE_ON) {
/*
* Servers that don't support SSH2_MSG_IGNORE. Currently,
* none detected automatically.
*/
ssh->remote_bugs |= BUG_CHOKES_ON_SSH2_IGNORE;
logevent("We believe remote version has SSH-2 ignore bug");
}
}
/*
@ -9426,8 +9438,10 @@ static const struct telnet_special *ssh_get_specials(void *handle)
static const struct telnet_special ssh1_ignore_special[] = {
{"IGNORE message", TS_NOP}
};
static const struct telnet_special ssh2_transport_specials[] = {
static const struct telnet_special ssh2_ignore_special[] = {
{"IGNORE message", TS_NOP},
};
static const struct telnet_special ssh2_rekey_special[] = {
{"Repeat key exchange", TS_REKEY},
};
static const struct telnet_special ssh2_session_specials[] = {
@ -9452,7 +9466,8 @@ static const struct telnet_special *ssh_get_specials(void *handle)
{NULL, TS_EXITMENU}
};
/* XXX review this length for any changes: */
static struct telnet_special ssh_specials[lenof(ssh2_transport_specials) +
static struct telnet_special ssh_specials[lenof(ssh2_ignore_special) +
lenof(ssh2_rekey_special) +
lenof(ssh2_session_specials) +
lenof(specials_end)];
Ssh ssh = (Ssh) handle;
@ -9471,7 +9486,10 @@ static const struct telnet_special *ssh_get_specials(void *handle)
if (!(ssh->remote_bugs & BUG_CHOKES_ON_SSH1_IGNORE))
ADD_SPECIALS(ssh1_ignore_special);
} else if (ssh->version == 2) {
ADD_SPECIALS(ssh2_transport_specials);
if (!(ssh->remote_bugs & BUG_CHOKES_ON_SSH2_IGNORE))
ADD_SPECIALS(ssh2_ignore_special);
if (!(ssh->remote_bugs & BUG_SSH2_REKEY))
ADD_SPECIALS(ssh2_rekey_special);
if (ssh->mainchan)
ADD_SPECIALS(ssh2_session_specials);
} /* else we're not ready yet */
@ -9521,9 +9539,11 @@ static void ssh_special(void *handle, Telnet_Special code)
if (!(ssh->remote_bugs & BUG_CHOKES_ON_SSH1_IGNORE))
send_packet(ssh, SSH1_MSG_IGNORE, PKT_STR, "", PKT_END);
} else {
pktout = ssh2_pkt_init(SSH2_MSG_IGNORE);
ssh2_pkt_addstring_start(pktout);
ssh2_pkt_send_noqueue(ssh, pktout);
if (!(ssh->remote_bugs & BUG_CHOKES_ON_SSH2_IGNORE)) {
pktout = ssh2_pkt_init(SSH2_MSG_IGNORE);
ssh2_pkt_addstring_start(pktout);
ssh2_pkt_send_noqueue(ssh, pktout);
}
}
} else if (code == TS_REKEY) {
if (!ssh->kex_in_progress && ssh->version == 2) {

View File

@ -5136,6 +5136,31 @@ void term_scroll(Terminal *term, int rel, int where)
term_update(term);
}
/*
* Scroll the scrollback to centre it on the beginning or end of the
* current selection, if any.
*/
void term_scroll_to_selection(Terminal *term, int which_end)
{
pos target;
int y;
int sbtop = -sblines(term);
if (term->selstate != SELECTED)
return;
if (which_end)
target = term->selend;
else
target = term->selstart;
y = target.y - term->rows/2;
if (y < sbtop)
y = sbtop;
else if (y > 0)
y = 0;
term_scroll(term, -1, y);
}
/*
* Helper routine for clipme(): growing buffer.
*/

View File

@ -3811,6 +3811,10 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam,
SendMessage(hwnd, WM_VSCROLL, SB_LINEDOWN, 0);
return 0;
}
if ((wParam == VK_PRIOR || wParam == VK_NEXT) && shift_state == 3) {
term_scroll_to_selection(term, (wParam == VK_PRIOR ? 0 : 1));
return 0;
}
if (wParam == VK_INSERT && shift_state == 1) {
request_paste(NULL);
return 0;