Enforce a minimum DH modulus size of 512 bits
authorBernd Edlinger <bernd.edlinger@hotmail.de>
Mon, 22 Jul 2019 20:50:19 +0000 (22:50 +0200)
committerBernd Edlinger <bernd.edlinger@hotmail.de>
Wed, 24 Jul 2019 12:44:08 +0000 (14:44 +0200)
[extended tests]

Reviewed-by: Paul Dale <paul.dale@oracle.com>
(Merged from https://github.com/openssl/openssl/pull/9437)

CHANGES
crypto/dh/dh_err.c
crypto/dh/dh_gen.c
crypto/dh/dh_key.c
crypto/dh/dh_locl.h
crypto/err/openssl.txt
doc/man1/dhparam.pod
include/openssl/dherr.h
test/dhtest.c

diff --git a/CHANGES b/CHANGES
index 3507e35..acaa099 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -9,6 +9,9 @@
 
  Changes between 1.1.1 and 3.0.0 [xx XXX xxxx]
 
+  *) Enforce a minimum DH modulus size of 512 bits.
+     [Bernd Edlinger]
+
   *) Changed DH parameters to generate the order q subgroup instead of 2q.
      Previously generated DH parameters are still accepted by DH_check
      but DH_generate_key works around that by clearing bit 0 of the
index cbde260..69f1452 100644 (file)
@@ -41,6 +41,7 @@ static const ERR_STRING_DATA DH_str_reasons[] = {
     {ERR_PACK(ERR_LIB_DH, 0, DH_R_KEYS_NOT_SET), "keys not set"},
     {ERR_PACK(ERR_LIB_DH, 0, DH_R_MISSING_PUBKEY), "missing pubkey"},
     {ERR_PACK(ERR_LIB_DH, 0, DH_R_MODULUS_TOO_LARGE), "modulus too large"},
+    {ERR_PACK(ERR_LIB_DH, 0, DH_R_MODULUS_TOO_SMALL), "modulus too small"},
     {ERR_PACK(ERR_LIB_DH, 0, DH_R_NOT_SUITABLE_GENERATOR),
     "not suitable generator"},
     {ERR_PACK(ERR_LIB_DH, 0, DH_R_NO_PARAMETERS_SET), "no parameters set"},
index 6e98b59..76d6ad0 100644 (file)
@@ -61,6 +61,16 @@ static int dh_builtin_genparams(DH *ret, int prime_len, int generator,
     int g, ok = -1;
     BN_CTX *ctx = NULL;
 
+    if (prime_len > OPENSSL_DH_MAX_MODULUS_BITS) {
+        DHerr(DH_F_DH_BUILTIN_GENPARAMS, DH_R_MODULUS_TOO_LARGE);
+        return 0;
+    }
+
+    if (prime_len < DH_MIN_MODULUS_BITS) {
+        DHerr(DH_F_DH_BUILTIN_GENPARAMS, DH_R_MODULUS_TOO_SMALL);
+        return 0;
+    }
+
     ctx = BN_CTX_new();
     if (ctx == NULL)
         goto err;
index 0d6b04d..8731cc2 100644 (file)
@@ -87,6 +87,11 @@ static int generate_key(DH *dh)
         return 0;
     }
 
+    if (BN_num_bits(dh->p) < DH_MIN_MODULUS_BITS) {
+        DHerr(DH_F_GENERATE_KEY, DH_R_MODULUS_TOO_SMALL);
+        return 0;
+    }
+
     ctx = BN_CTX_new();
     if (ctx == NULL)
         goto err;
@@ -181,6 +186,11 @@ static int compute_key(unsigned char *key, const BIGNUM *pub_key, DH *dh)
         goto err;
     }
 
+    if (BN_num_bits(dh->p) < DH_MIN_MODULUS_BITS) {
+        DHerr(DH_F_COMPUTE_KEY, DH_R_MODULUS_TOO_SMALL);
+        return 0;
+    }
+
     ctx = BN_CTX_new();
     if (ctx == NULL)
         goto err;
index f0247b8..a9041e9 100644 (file)
@@ -10,6 +10,8 @@
 #include <openssl/dh.h>
 #include "internal/refcount.h"
 
+#define DH_MIN_MODULUS_BITS     512
+
 struct dh_st {
     /*
      * This first argument is used to pick up errors when a DH is passed
index d88e989..ede1c57 100644 (file)
@@ -2276,6 +2276,7 @@ DH_R_KDF_PARAMETER_ERROR:112:kdf parameter error
 DH_R_KEYS_NOT_SET:108:keys not set
 DH_R_MISSING_PUBKEY:125:missing pubkey
 DH_R_MODULUS_TOO_LARGE:103:modulus too large
+DH_R_MODULUS_TOO_SMALL:126:modulus too small
 DH_R_NOT_SUITABLE_GENERATOR:120:not suitable generator
 DH_R_NO_PARAMETERS_SET:107:no parameters set
 DH_R_NO_PRIVATE_VALUE:100:no private value
index dd871b3..c51bbaa 100644 (file)
@@ -103,8 +103,9 @@ This can be used with a subsequent B<-rand> flag.
 This option specifies that a parameter set should be generated of size
 I<numbits>. It must be the last option. If this option is present then
 the input file is ignored and parameters are generated instead. If
-this option is not present but a generator (B<-2> or B<-5>) is
+this option is not present but a generator (B<-2>, B<-3> or B<-5>) is
 present, parameters are generated with a default length of 2048 bits.
+The minimim length is 512 bits. The maximum length is 10000 bits.
 
 =item B<-noout>
 
index 1e3451b..13bd036 100644 (file)
@@ -80,6 +80,7 @@ int ERR_load_DH_strings(void);
 #  define DH_R_KEYS_NOT_SET                                108
 #  define DH_R_MISSING_PUBKEY                              125
 #  define DH_R_MODULUS_TOO_LARGE                           103
+#  define DH_R_MODULUS_TOO_SMALL                           126
 #  define DH_R_NOT_SUITABLE_GENERATOR                      120
 #  define DH_R_NO_PARAMETERS_SET                           107
 #  define DH_R_NO_PRIVATE_VALUE                            100
index f80d5b3..662a4f3 100644 (file)
@@ -103,25 +103,12 @@ static int dh_test(void)
         || !TEST_ptr_eq(DH_get0_priv_key(dh), priv_key2))
         goto err3;
 
-    /* now generate a key pair ... */
-    if (!DH_generate_key(dh))
+    /* now generate a key pair (expect failure since modulus is too small) */
+    if (!TEST_false(DH_generate_key(dh)))
         goto err3;
 
-    /* ... and check whether the private key was reused: */
-
-    /* test it with the combined getter for pub_key and priv_key */
-    DH_get0_key(dh, &pub_key2, &priv_key2);
-    if (!TEST_ptr(pub_key2)
-        || !TEST_ptr_eq(priv_key2, priv_key))
-        goto err3;
-
-    /* test it the simple getters for pub_key and priv_key */
-    if (!TEST_ptr_eq(DH_get0_pub_key(dh), pub_key2)
-        || !TEST_ptr_eq(DH_get0_priv_key(dh), priv_key2))
-        goto err3;
-
-    /* check whether the public key was calculated correctly */
-    TEST_uint_eq(BN_get_word(pub_key2), 3331L);
+    /* We'll have a stale error on the queue from the above test so clear it */
+    ERR_clear_error();
 
     /*
      * II) key generation
@@ -132,7 +119,7 @@ static int dh_test(void)
         goto err3;
     BN_GENCB_set(_cb, &cb, NULL);
     if (!TEST_ptr(a = DH_new())
-            || !TEST_true(DH_generate_parameters_ex(a, 64,
+            || !TEST_true(DH_generate_parameters_ex(a, 512,
                                                     DH_GENERATOR_5, _cb)))
         goto err3;
 
@@ -192,7 +179,7 @@ static int dh_test(void)
             || !TEST_true((cout = DH_compute_key(cbuf, apub_key, c)) != -1))
         goto err3;
 
-    if (!TEST_true(aout >= 4)
+    if (!TEST_true(aout >= 20)
             || !TEST_mem_eq(abuf, aout, bbuf, bout)
             || !TEST_mem_eq(abuf, aout, cbuf, cout))
         goto err3;