X-Git-Url: https://asedeno.scripts.mit.edu/gitweb/?a=blobdiff_plain;f=ssh.c;h=e59afc266868e51ddf06f0e44a75c4c85e05d7f3;hb=d0da9737469c38b64b668606eef3e9af92ed3848;hp=a6fba8b87af423f91a6985c9213f9e0f2a299e0a;hpb=56d5dc7eecf52bb1fcb164be161f419dd15c3284;p=PuTTY.git diff --git a/ssh.c b/ssh.c index a6fba8b8..e59afc26 100644 --- 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; @@ -4337,6 +4325,37 @@ static int do_ssh2_transport(Ssh ssh, unsigned char *in, int inlen, s->first_kex = 1; + { + 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; /* @@ -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; } } @@ -7379,14 +7412,17 @@ static void ssh_size(void *handle, int width, int height) */ static const struct telnet_special *ssh_get_specials(void *handle) { - static const struct telnet_special ignore_special[] = { + static const struct telnet_special ssh1_ignore_special[] = { + {"IGNORE message", TS_NOP} + }; + static const struct telnet_special ssh2_transport_specials[] = { {"IGNORE message", TS_NOP}, {"Repeat key exchange", TS_REKEY}, }; static const struct telnet_special ssh2_session_specials[] = { {NULL, TS_SEP}, {"Break", TS_BRK}, - /* These are the signal names defined by draft-ietf-secsh-connect-19. + /* These are the signal names defined by draft-ietf-secsh-connect-23. * They include all the ISO C signals, but are a subset of the POSIX * required signals. */ {"SIGINT (Interrupt)", TS_SIGINT}, @@ -7404,7 +7440,8 @@ static const struct telnet_special *ssh_get_specials(void *handle) static const struct telnet_special specials_end[] = { {NULL, TS_EXITMENU} }; - static struct telnet_special ssh_specials[lenof(ignore_special) + + /* XXX review this length for any changes: */ + static struct telnet_special ssh_specials[lenof(ssh2_transport_specials) + lenof(ssh2_session_specials) + lenof(specials_end)]; Ssh ssh = (Ssh) handle; @@ -7421,9 +7458,9 @@ static const struct telnet_special *ssh_get_specials(void *handle) * won't cope with it, since we wouldn't bother sending it if * asked anyway. */ if (!(ssh->remote_bugs & BUG_CHOKES_ON_SSH1_IGNORE)) - ADD_SPECIALS(ignore_special); + ADD_SPECIALS(ssh1_ignore_special); } else if (ssh->version == 2) { - ADD_SPECIALS(ignore_special); + ADD_SPECIALS(ssh2_transport_specials); if (ssh->mainchan) ADD_SPECIALS(ssh2_session_specials); } /* else we're not ready yet */