From a92dd380e9adcd09e9c43fa44466b5fb2e323c3b Mon Sep 17 00:00:00 2001 From: simon Date: Thu, 1 Mar 2001 17:55:40 +0000 Subject: [PATCH] Diffie-Hellman group exchange in SSH2. Currently #ifdeffed out (change the sense of #ifdef DO_DIFFIE_HELLMAN_GEX in ssh.c) because it's _far_ too slow. Will be re-enabled once the bignum routines work a bit faster (or rather a _lot_ faster). git-svn-id: svn://svn.tartarus.org/sgt/putty@962 cda61777-01e9-0310-a592-d414129be87e --- ssh.c | 88 ++++++++++++++++++++++++++++++++++++++++++++++++++++------------- ssh.h | 1 + sshdh.c | 13 ++++++++++ 3 files changed, 85 insertions(+), 17 deletions(-) diff --git a/ssh.c b/ssh.c index a6433db5..a7f6f882 100644 --- a/ssh.c +++ b/ssh.c @@ -87,6 +87,10 @@ #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_GROUP 31 /* 0x1f */ +#define SSH2_MSG_KEX_DH_GEX_INIT 32 /* 0x20 */ +#define SSH2_MSG_KEX_DH_GEX_REPLY 33 /* 0x21 */ #define SSH2_MSG_USERAUTH_REQUEST 50 /* 0x32 */ #define SSH2_MSG_USERAUTH_FAILURE 51 /* 0x33 */ #define SSH2_MSG_USERAUTH_SUCCESS 52 /* 0x34 */ @@ -180,7 +184,12 @@ extern void x11_invent_auth(char *, int, char *, int); const static struct ssh_cipher *ciphers[] = { &ssh_blowfish_ssh2, &ssh_3des_ssh2 }; extern const struct ssh_kex ssh_diffiehellman; -const static struct ssh_kex *kex_algs[] = { &ssh_diffiehellman }; +extern const struct ssh_kex ssh_diffiehellman_gex; +const static struct ssh_kex *kex_algs[] = { +#ifdef DO_DIFFIE_HELLMAN_GEX + &ssh_diffiehellman_gex, +#endif + &ssh_diffiehellman }; extern const struct ssh_signkey ssh_dss; const static struct ssh_signkey *hostkey_algs[] = { &ssh_dss }; @@ -806,8 +815,8 @@ static int ssh_versioncmp(char *a, char *b) { /* - * Utility routine for putting an SSH-protocol `string' into a SHA - * state. + * Utility routines for putting an SSH-protocol `string' and + * `uint32' into a SHA state. */ #include static void sha_string(SHA_State *s, void *str, int len) { @@ -817,6 +826,12 @@ static void sha_string(SHA_State *s, void *str, int len) { SHA_Bytes(s, str, len); } +static void sha_uint32(SHA_State *s, unsigned i) { + unsigned char intblk[4]; + PUT_32BIT(intblk, i); + SHA_Bytes(s, intblk, 4); +} + /* * SSH2 packet construction functions. */ @@ -2157,9 +2172,10 @@ static void ssh2_mkkey(Bignum K, char *H, char *sessid, char chr, char *keyspace */ static int do_ssh2_transport(unsigned char *in, int inlen, int ispkt) { - static int i, len; + static int i, len, nbits; static char *str; - static Bignum e, f, K; + static Bignum p, g, e, f, K; + static int kex_init_value, kex_reply_value; static const struct ssh_mac **maclist; static int nmacs; static const struct ssh_cipher *cscipher_tobe = NULL; @@ -2366,27 +2382,60 @@ static int do_ssh2_transport(unsigned char *in, int inlen, int ispkt) } /* - * Currently we only support Diffie-Hellman and DSS, so let's - * bomb out if those aren't selected. + * If we're doing Diffie-Hellman group exchange, start by + * requesting a group. */ - if (kex != &ssh_diffiehellman || hostkey != &ssh_dss) { - bombout(("internal fault: chaos in SSH 2 transport layer")); - crReturn(0); + if (kex == &ssh_diffiehellman_gex) { + int csbits, scbits; + + logevent("Doing Diffie-Hellman group exchange"); + /* + * Work out number of bits. We start with the maximum key + * length of either cipher... + */ + csbits = cscipher_tobe->keylen; + scbits = sccipher_tobe->keylen; + nbits = (csbits > scbits ? csbits : scbits); + /* The keys only have 160-bit entropy, since they're based on + * a SHA-1 hash. So cap the key size at 160 bits. */ + if (nbits > 160) nbits = 160; + /* + * ... and then work out how big a DH group we will need to + * allow that much data. + */ + nbits = 512 << ((nbits-1) / 64); + ssh2_pkt_init(SSH2_MSG_KEX_DH_GEX_REQUEST); + ssh2_pkt_adduint32(nbits); + ssh2_pkt_send(); + + crWaitUntil(ispkt); + if (pktin.type != SSH2_MSG_KEX_DH_GEX_GROUP) { + bombout(("expected key exchange group packet from server")); + crReturn(0); + } + p = ssh2_pkt_getmp(); + g = ssh2_pkt_getmp(); + dh_setup_group(p, g); + kex_init_value = SSH2_MSG_KEX_DH_GEX_INIT; + kex_reply_value = SSH2_MSG_KEX_DH_GEX_REPLY; + } else { + dh_setup_group1(); + kex_init_value = SSH2_MSG_KEXDH_INIT; + kex_reply_value = SSH2_MSG_KEXDH_REPLY; } + logevent("Doing Diffie-Hellman key exchange"); /* - * Now we begin the fun. Generate and send e for Diffie-Hellman. + * Now generate and send e for Diffie-Hellman. */ - dh_setup_group1(); - e = dh_create_e(); - ssh2_pkt_init(SSH2_MSG_KEXDH_INIT); + ssh2_pkt_init(kex_init_value); ssh2_pkt_addmp(e); ssh2_pkt_send(); crWaitUntil(ispkt); - if (pktin.type != SSH2_MSG_KEXDH_REPLY) { - bombout(("expected key exchange packet from server")); + if (pktin.type != kex_reply_value) { + bombout(("expected key exchange reply packet from server")); crReturn(0); } ssh2_pkt_getstring(&hostkeydata, &hostkeylen); @@ -2396,6 +2445,11 @@ static int do_ssh2_transport(unsigned char *in, int inlen, int ispkt) K = dh_find_K(f); sha_string(&exhash, hostkeydata, hostkeylen); + if (kex == &ssh_diffiehellman_gex) { + sha_uint32(&exhash, nbits); + sha_mpint(&exhash, p); + sha_mpint(&exhash, g); + } sha_mpint(&exhash, e); sha_mpint(&exhash, f); sha_mpint(&exhash, K); @@ -2433,7 +2487,7 @@ static int do_ssh2_transport(unsigned char *in, int inlen, int ispkt) fingerprint = hostkey->fingerprint(hkey); verify_ssh_host_key(savedhost, savedport, hostkey->keytype, keystr, fingerprint); - if (first_kex) { /* don't bother logging this in rekeys */ + if (first_kex) { /* don't bother logging this in rekeys */ logevent("Host key fingerprint is:"); logevent(fingerprint); } diff --git a/ssh.h b/ssh.h index 65840293..555fe61c 100644 --- a/ssh.h +++ b/ssh.h @@ -187,6 +187,7 @@ int bignum_cmp(Bignum a, Bignum b); char *bignum_decimal(Bignum x); void dh_setup_group1(void); +void dh_setup_group(Bignum pval, Bignum gval); void dh_cleanup(void); Bignum dh_create_e(void); Bignum dh_find_K(Bignum f); diff --git a/sshdh.c b/sshdh.c index 35e66907..18749ecc 100644 --- a/sshdh.c +++ b/sshdh.c @@ -4,6 +4,10 @@ struct ssh_kex ssh_diffiehellman = { "diffie-hellman-group1-sha1" }; +struct ssh_kex ssh_diffiehellman_gex = { + "diffie-hellman-group-exchange-sha1" +}; + /* * The prime p used in the key exchange. */ @@ -50,6 +54,15 @@ void dh_setup_group1(void) { } /* + * Initialise DH for an alternative group. + */ +void dh_setup_group(Bignum pval, Bignum gval) { + p = copybn(pval); + g = copybn(gval); + dh_init(); +} + +/* * Clean up. */ void dh_cleanup(void) { -- 2.11.0