Diffie-Hellman group exchange in SSH2. Currently #ifdeffed out
authorsimon <simon@cda61777-01e9-0310-a592-d414129be87e>
Thu, 1 Mar 2001 17:55:40 +0000 (17:55 +0000)
committersimon <simon@cda61777-01e9-0310-a592-d414129be87e>
Thu, 1 Mar 2001 17:55:40 +0000 (17:55 +0000)
(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
ssh.h
sshdh.c

diff --git a/ssh.c b/ssh.c
index a6433db..a7f6f88 100644 (file)
--- a/ssh.c
+++ b/ssh.c
 #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 <stdio.h>
 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 6584029..555fe61 100644 (file)
--- 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 35e6690..18749ec 100644 (file)
--- 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) {