check for reasonable public DH values
authormarkus <markus@openbsd.org>
Wed, 12 Apr 2000 07:03:05 +0000 (07:03 +0000)
committermarkus <markus@openbsd.org>
Wed, 12 Apr 2000 07:03:05 +0000 (07:03 +0000)
usr.bin/ssh/kex.c
usr.bin/ssh/kex.h
usr.bin/ssh/sshconnect.c
usr.bin/ssh/sshd.c

index cc2543a..2308c93 100644 (file)
@@ -28,7 +28,7 @@
  */
 
 #include "includes.h"
-RCSID("$Id: kex.c,v 1.2 2000/04/12 06:37:02 markus Exp $");
+RCSID("$Id: kex.c,v 1.3 2000/04/12 07:03:05 markus Exp $");
 
 #include "ssh.h"
 #include "ssh2.h"
@@ -74,8 +74,36 @@ kex_init(char *myproposal[PROPOSAL_MAX])
 
 /* diffie-hellman-group1-sha1 */
 
+int
+dh_pub_is_valid(DH *dh, BIGNUM *dh_pub)
+{
+       int i;
+       int n = BN_num_bits(dh_pub);
+       int bits_set = 0;
+
+       /* we only accept g==2 */
+       if (!BN_is_word(dh->g, 2)) {
+               log("invalid DH base != 2");
+               return 0;
+       }
+       if (dh_pub->neg) {
+               log("invalid public DH value: negativ");
+               return 0;
+       }
+       for (i = 0; i <= n; i++)
+               if (BN_is_bit_set(dh_pub, i))
+                       bits_set++;
+       debug("bits set: %d/%d", bits_set, BN_num_bits(dh->p));
+
+       /* if g==2 and bits_set==1 then computing log_g(dh_pub) is trivial */
+       if (bits_set > 1 && (BN_cmp(dh_pub, dh->p) == -1))
+               return 1;
+       log("invalid public DH value (%d/%d)", bits_set, BN_num_bits(dh->p));
+       return 0;
+}
+
 DH *
-new_dh_group1()
+dh_new_group1()
 {
        static char *group1 =
            "FFFFFFFF" "FFFFFFFF" "C90FDAA2" "2168C234" "C4C6628B" "80DC1CD1"
@@ -85,19 +113,23 @@ new_dh_group1()
            "EE386BFB" "5A899FA5" "AE9F2411" "7C4B1FE6" "49286651" "ECE65381"
            "FFFFFFFF" "FFFFFFFF";
        DH *dh;
-       int ret;
+       int ret, tries = 0;
        dh = DH_new();
        if(dh == NULL)
                fatal("DH_new");
-       ret = BN_hex2bn(&dh->p,group1);
+       ret = BN_hex2bn(&dh->p, group1);
        if(ret<0)
                fatal("BN_hex2bn");
        dh->g = BN_new();
        if(dh->g == NULL)
                fatal("DH_new g");
-       BN_set_word(dh->g,2);
-       if (DH_generate_key(dh) == 0)
-               fatal("DH_generate_key");
+       BN_set_word(dh->g, 2);
+       do {
+               if (DH_generate_key(dh) == 0)
+                       fatal("DH_generate_key");
+               if (tries++ > 10)
+                       fatal("dh_new_group1: too many bad keys: giving up");
+       } while (!dh_pub_is_valid(dh, dh->pub_key));
        return dh;
 }
 
index f9e7999..5395ebc 100644 (file)
@@ -91,7 +91,8 @@ struct Kex {
 };
 
 Buffer *kex_init(char *myproposal[PROPOSAL_MAX]);
-DH     *new_dh_group1();
+int    dh_pub_is_valid(DH *dh, BIGNUM *dh_pub);
+DH     *dh_new_group1();
 Kex    *kex_choose_conf(char *cprop[PROPOSAL_MAX], char *sprop[PROPOSAL_MAX], int server);
 int    kex_derive_keys(Kex *k, unsigned char *hash, BIGNUM *shared_secret);
 void   bignum_print(BIGNUM *b);
index 3391c33..e8b4f16 100644 (file)
@@ -10,7 +10,7 @@
  */
 
 #include "includes.h"
-RCSID("$OpenBSD: sshconnect.c,v 1.62 2000/04/12 06:36:48 markus Exp $");
+RCSID("$OpenBSD: sshconnect.c,v 1.63 2000/04/12 07:03:06 markus Exp $");
 
 #include <ssl/bn.h>
 #include "xmalloc.h"
@@ -1393,7 +1393,7 @@ ssh_kex2(char *host, struct sockaddr *hostaddr)
        debug("Sending SSH2_MSG_KEXDH_INIT.");
 
        /* generate and send 'e', client DH public key */
-       dh = new_dh_group1();
+       dh = dh_new_group1();
        packet_start(SSH2_MSG_KEXDH_INIT);
        packet_put_bignum2(dh->pub_key);
        packet_send();
@@ -1440,6 +1440,9 @@ ssh_kex2(char *host, struct sockaddr *hostaddr)
        /* signed H */
        signature = packet_get_string(&slen);
 
+       if (!dh_pub_is_valid(dh, dh_server_pub))
+               packet_disconnect("bad server public DH value");
+
        klen = DH_size(dh);
        kbuf = xmalloc(klen);
        kout = DH_compute_key(kbuf, dh_server_pub, dh);
index 7d8963f..088da20 100644 (file)
@@ -14,7 +14,7 @@
  */
 
 #include "includes.h"
-RCSID("$OpenBSD: sshd.c,v 1.100 2000/04/12 06:37:02 markus Exp $");
+RCSID("$OpenBSD: sshd.c,v 1.101 2000/04/12 07:03:06 markus Exp $");
 
 #include "xmalloc.h"
 #include "rsa.h"
@@ -1166,7 +1166,7 @@ do_ssh2_kex()
 #endif
 
        /* generate DH key */
-       dh = new_dh_group1();                   /* XXX depends on 'kex' */
+       dh = dh_new_group1();                   /* XXX depends on 'kex' */
 
 #ifdef DEBUG_KEXDH
        fprintf(stderr, "\np= ");
@@ -1177,6 +1177,8 @@ do_ssh2_kex()
        bignum_print(dh->pub_key);
        fprintf(stderr, "\n");
 #endif
+       if (!dh_pub_is_valid(dh, dh_client_pub))
+               packet_disconnect("bad client public DH value");
 
        klen = DH_size(dh);
        kbuf = xmalloc(klen);