X-Git-Url: https://git.distorted.org.uk/~mdw/sgt/putty/blobdiff_plain/6c6d9ed9511ad9f76dcf9fcb3e184937bb1555f0..b624d1e699ea196984715dee5c878676b8ec79bf:/ssh.c diff --git a/ssh.c b/ssh.c index 88af2480..662d521f 100644 --- a/ssh.c +++ b/ssh.c @@ -163,6 +163,7 @@ static const char *const ssh2_disconnect_reasons[] = { #define BUG_SSH2_RSA_PADDING 16 #define BUG_SSH2_DERIVEKEY 32 #define BUG_SSH2_DH_GEX 64 +#define BUG_SSH2_PK_SESSIONID 128 #define translate(x) if (type == x) return #x #define translatec(x,ctx) if (type == x && (pkt_ctx & ctx)) return #x @@ -268,7 +269,26 @@ static char *ssh2_pkt_type(int pkt_ctx, int type) enum { PKT_END, PKT_INT, PKT_CHAR, PKT_DATA, PKT_STR, PKT_BIGNUM }; -/* Coroutine mechanics for the sillier bits of the code */ +/* + * Coroutine mechanics for the sillier bits of the code. If these + * macros look impenetrable to you, you might find it helpful to + * read + * + * http://www.chiark.greenend.org.uk/~sgtatham/coroutines.html + * + * which explains the theory behind these macros. + * + * In particular, if you are getting `case expression not constant' + * errors when building with MS Visual Studio, this is because MS's + * Edit and Continue debugging feature causes their compiler to + * violate ANSI C. To disable Edit and Continue debugging: + * + * - right-click ssh.c in the FileView + * - click Settings + * - select the C/C++ tab and the General category + * - under `Debug info:', select anything _other_ than `Program + * Database for Edit and Continue'. + */ #define crBegin(v) { int *crLine = &v; switch(v) { case 0:; #define crState(t) \ struct t *s; \ @@ -1166,8 +1186,18 @@ static void s_wrpkt_start(Ssh ssh, int type, int len) static int s_wrpkt_prepare(Ssh ssh) { - int pad, len, biglen, i; + int pad, biglen, i; unsigned long crc; +#ifdef __SC__ + /* + * XXX various versions of SC (including 8.8.4) screw up the + * register allocation in this function and use the same register + * (D6) for len and as a temporary, with predictable results. The + * following sledgehammer prevents this. + */ + volatile +#endif + int len; ssh->pktout.body[-1] = ssh->pktout.type; @@ -1771,7 +1801,7 @@ static void ssh_detect_bugs(Ssh ssh, char *vstring) if (ssh->cfg.sshbug_derivekey2 == FORCE_ON || (ssh->cfg.sshbug_derivekey2 == AUTO && - (wc_match("2.0.0*", imp) || wc_match("2.0.1[01]*", imp) ))) { + (wc_match("2.0.0*", imp) || wc_match("2.0.10*", imp) ))) { /* * These versions have the key-derivation bug (failing to * include the literal shared secret in the hashes that @@ -1792,6 +1822,17 @@ static void ssh_detect_bugs(Ssh ssh, char *vstring) logevent("We believe remote version has SSH2 RSA padding bug"); } + if (ssh->cfg.sshbug_pksessid2 == FORCE_ON || + (ssh->cfg.sshbug_pksessid2 == AUTO && + wc_match("OpenSSH_2.[0-2]*", imp))) { + /* + * These versions have the SSH2 session-ID bug in + * public-key authentication. + */ + 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. @@ -2181,7 +2222,13 @@ static int process_userpass_input(Ssh ssh, unsigned char *in, int inlen) return -1; break; default: - if (((c >= ' ' && c <= '~') || + /* + * This simplistic check for printability is disabled + * when we're doing password input, because some people + * have control characters in their passwords.o + */ + if ((!ssh->userpass_input_echo || + (c >= ' ' && c <= '~') || ((unsigned char) c >= 160)) && ssh->userpass_input_bufpos < ssh->userpass_input_buflen-1) { ssh->userpass_input_buffer[ssh->userpass_input_bufpos++] = c; @@ -4629,6 +4676,8 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt) ssh2_pkt_addstring_data(ssh, s->pkblob, s->pklen); s->siglen = ssh->pktout.length - 5 + 4 + 20; + if (ssh->remote_bugs & BUG_SSH2_PK_SESSIONID) + s->siglen -= 4; s->len = 1; /* message type */ s->len += 4 + s->pklen; /* key blob */ s->len += 4 + s->siglen; /* data to sign */ @@ -4644,8 +4693,10 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt) PUT_32BIT(s->q, s->siglen); s->q += 4; /* Now the data to be signed... */ - PUT_32BIT(s->q, 20); - s->q += 4; + if (!(ssh->remote_bugs & BUG_SSH2_PK_SESSIONID)) { + PUT_32BIT(s->q, 20); + s->q += 4; + } memcpy(s->q, ssh->v2_session_id, 20); s->q += 20; memcpy(s->q, ssh->pktout.data + 5, @@ -4894,6 +4945,7 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt) } else { unsigned char *pkblob, *sigblob, *sigdata; int pkblob_len, sigblob_len, sigdata_len; + int p; /* * We have loaded the private key and the server @@ -4919,11 +4971,19 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt) * outgoing packet. */ sigdata_len = ssh->pktout.length - 5 + 4 + 20; + if (ssh->remote_bugs & BUG_SSH2_PK_SESSIONID) + sigdata_len -= 4; sigdata = smalloc(sigdata_len); - PUT_32BIT(sigdata, 20); - memcpy(sigdata + 4, ssh->v2_session_id, 20); - memcpy(sigdata + 24, ssh->pktout.data + 5, + p = 0; + if (!(ssh->remote_bugs & BUG_SSH2_PK_SESSIONID)) { + PUT_32BIT(sigdata+p, 20); + p += 4; + } + memcpy(sigdata+p, ssh->v2_session_id, 20); p += 20; + memcpy(sigdata+p, ssh->pktout.data + 5, ssh->pktout.length - 5); + p += ssh->pktout.length - 5; + assert(p == sigdata_len); sigblob = key->alg->sign(key->data, (char *)sigdata, sigdata_len, &sigblob_len); ssh2_add_sigblob(ssh, pkblob, pkblob_len,