Add BN_rand_range_ex and use internally.

There are many cases where we need |BN_rand_range| but with a minimum
value other than 0. |BN_rand_range_ex| provides that.

Change-Id: I564326c9206bf4e20a37414bdbce16a951c148ce
Reviewed-on: https://boringssl-review.googlesource.com/8921
Reviewed-by: David Benjamin <davidben@google.com>
Commit-Queue: David Benjamin <davidben@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
diff --git a/crypto/bn/cmp.c b/crypto/bn/cmp.c
index 121c894..9cf33b4 100644
--- a/crypto/bn/cmp.c
+++ b/crypto/bn/cmp.c
@@ -185,6 +185,17 @@
   }
 }
 
+int BN_cmp_word(const BIGNUM *a, BN_ULONG b) {
+  BIGNUM b_bn;
+  BN_init(&b_bn);
+
+  b_bn.d = &b;
+  b_bn.top = b > 0;
+  b_bn.dmax = 1;
+  b_bn.flags = BN_FLG_STATIC_DATA;
+  return BN_cmp(a, &b_bn);
+}
+
 int BN_is_zero(const BIGNUM *bn) {
   return bn->top == 0;
 }
diff --git a/crypto/bn/random.c b/crypto/bn/random.c
index 8333430..fb76f1d 100644
--- a/crypto/bn/random.c
+++ b/crypto/bn/random.c
@@ -181,16 +181,17 @@
   return BN_rand(rnd, bits, top, bottom);
 }
 
-int BN_rand_range(BIGNUM *r, const BIGNUM *range) {
+int BN_rand_range_ex(BIGNUM *r, BN_ULONG min_inclusive,
+                     const BIGNUM *max_exclusive) {
   unsigned n;
   unsigned count = 100;
 
-  if (range->neg || BN_is_zero(range)) {
+  if (BN_cmp_word(max_exclusive, min_inclusive) <= 0) {
     OPENSSL_PUT_ERROR(BN, BN_R_INVALID_RANGE);
     return 0;
   }
 
-  n = BN_num_bits(range); /* n > 0 */
+  n = BN_num_bits(max_exclusive); /* n > 0 */
 
   /* BN_is_bit_set(range, n - 1) always holds */
   if (n == 1) {
@@ -204,7 +205,8 @@
       return 0;
     }
 
-    if (!BN_is_bit_set(range, n - 2) && !BN_is_bit_set(range, n - 3)) {
+    if (!BN_is_bit_set(max_exclusive, n - 2) &&
+        !BN_is_bit_set(max_exclusive, n - 3)) {
       /* range = 100..._2, so 3*range (= 11..._2) is exactly one bit longer
        * than range. This is a common scenario when generating a random value
        * modulo an RSA public modulus, e.g. for RSA base blinding. */
@@ -216,12 +218,12 @@
       /* If r < 3*range, use r := r MOD range (which is either r, r - range, or
        * r - 2*range). Otherwise, iterate again. Since 3*range = 11..._2, each
        * iteration succeeds with probability >= .75. */
-      if (BN_cmp(r, range) >= 0) {
-        if (!BN_sub(r, r, range)) {
+      if (BN_cmp(r, max_exclusive) >= 0) {
+        if (!BN_sub(r, r, max_exclusive)) {
           return 0;
         }
-        if (BN_cmp(r, range) >= 0) {
-          if (!BN_sub(r, r, range)) {
+        if (BN_cmp(r, max_exclusive) >= 0) {
+          if (!BN_sub(r, r, max_exclusive)) {
             return 0;
           }
         }
@@ -232,11 +234,16 @@
         return 0;
       }
     }
-  } while (BN_cmp(r, range) >= 0);
+  } while (BN_cmp_word(r, min_inclusive) < 0 ||
+           BN_cmp(r, max_exclusive) >= 0);
 
   return 1;
 }
 
+int BN_rand_range(BIGNUM *r, const BIGNUM *range) {
+  return BN_rand_range_ex(r, 0, range);
+}
+
 int BN_pseudo_rand_range(BIGNUM *r, const BIGNUM *range) {
   return BN_rand_range(r, range);
 }
diff --git a/crypto/dh/dh.c b/crypto/dh/dh.c
index 94eb364..eea1432 100644
--- a/crypto/dh/dh.c
+++ b/crypto/dh/dh.c
@@ -275,11 +275,9 @@
 
   if (generate_new_key) {
     if (dh->q) {
-      do {
-        if (!BN_rand_range(priv_key, dh->q)) {
-          goto err;
-        }
-      } while (BN_is_zero(priv_key) || BN_is_one(priv_key));
+      if (!BN_rand_range_ex(priv_key, 2, dh->q)) {
+        goto err;
+      }
     } else {
       /* secret exponent length */
       DH_check_standard_parameters(dh);
diff --git a/crypto/dsa/dsa.c b/crypto/dsa/dsa.c
index 5e1f81a..e1488af 100644
--- a/crypto/dsa/dsa.c
+++ b/crypto/dsa/dsa.c
@@ -425,11 +425,9 @@
     }
   }
 
-  do {
-    if (!BN_rand_range(priv_key, dsa->q)) {
-      goto err;
-    }
-  } while (BN_is_zero(priv_key));
+  if (!BN_rand_range_ex(priv_key, 1, dsa->q)) {
+    goto err;
+  }
 
   pub_key = dsa->pub_key;
   if (pub_key == NULL) {
@@ -818,11 +816,9 @@
   }
 
   /* Get random k */
-  do {
-    if (!BN_rand_range(&k, dsa->q)) {
-      goto err;
-    }
-  } while (BN_is_zero(&k));
+  if (!BN_rand_range_ex(&k, 1, dsa->q)) {
+    goto err;
+  }
 
   BN_set_flags(&k, BN_FLG_CONSTTIME);
 
diff --git a/crypto/ec/ec_key.c b/crypto/ec/ec_key.c
index dcacdfa..3e4456c 100644
--- a/crypto/ec/ec_key.c
+++ b/crypto/ec/ec_key.c
@@ -425,11 +425,9 @@
   }
 
   const BIGNUM *order = EC_GROUP_get0_order(eckey->group);
-  do {
-    if (!BN_rand_range(priv_key, order)) {
-      goto err;
-    }
-  } while (BN_is_zero(priv_key));
+  if (!BN_rand_range_ex(priv_key, 1, order)) {
+    goto err;
+  }
 
   if (eckey->pub_key == NULL) {
     pub_key = EC_POINT_new(eckey->group);
diff --git a/crypto/ecdsa/ecdsa.c b/crypto/ecdsa/ecdsa.c
index 6938325..a85c28a 100644
--- a/crypto/ecdsa/ecdsa.c
+++ b/crypto/ecdsa/ecdsa.c
@@ -263,20 +263,18 @@
     /* If possible, we'll include the private key and message digest in the k
      * generation. The |digest| argument is only empty if |ECDSA_sign_setup| is
      * being used. */
-    do {
-      int ok;
-
-      if (digest_len > 0) {
-        ok = BN_generate_dsa_nonce(k, order, EC_KEY_get0_private_key(eckey),
-                                   digest, digest_len, ctx);
-      } else {
-        ok = BN_rand_range(k, order);
-      }
-      if (!ok) {
-        OPENSSL_PUT_ERROR(ECDSA, ECDSA_R_RANDOM_NUMBER_GENERATION_FAILED);
-        goto err;
-      }
-    } while (BN_is_zero(k));
+    if (digest_len > 0) {
+      do {
+        if (!BN_generate_dsa_nonce(k, order, EC_KEY_get0_private_key(eckey),
+                                   digest, digest_len, ctx)) {
+          OPENSSL_PUT_ERROR(ECDSA, ECDSA_R_RANDOM_NUMBER_GENERATION_FAILED);
+          goto err;
+        }
+      } while (BN_is_zero(k));
+    } else if (!BN_rand_range_ex(k, 1, order)) {
+      OPENSSL_PUT_ERROR(ECDSA, ECDSA_R_RANDOM_NUMBER_GENERATION_FAILED);
+      goto err;
+    }
 
     /* We do not want timing information to leak the length of k,
      * so we compute G*k using an equivalent scalar of fixed
diff --git a/crypto/rsa/blinding.c b/crypto/rsa/blinding.c
index d9d90c2..71f2e6f 100644
--- a/crypto/rsa/blinding.c
+++ b/crypto/rsa/blinding.c
@@ -222,7 +222,7 @@
   int retry_counter = 32;
 
   do {
-    if (!BN_rand_range(b->A, &mont->N)) {
+    if (!BN_rand_range_ex(b->A, 1, &mont->N)) {
       OPENSSL_PUT_ERROR(RSA, ERR_R_INTERNAL_ERROR);
       return 0;
     }
diff --git a/include/openssl/bn.h b/include/openssl/bn.h
index a686696..51a63e6 100644
--- a/include/openssl/bn.h
+++ b/include/openssl/bn.h
@@ -436,6 +436,10 @@
  * less than, equal to or greater than |b|, respectively. */
 OPENSSL_EXPORT int BN_cmp(const BIGNUM *a, const BIGNUM *b);
 
+/* BN_cmp_word is like |BN_cmp| except it takes its second argument as a
+ * |BN_ULONG| instead of a |BIGNUM|. */
+int BN_cmp_word(const BIGNUM *a, BN_ULONG b);
+
 /* BN_ucmp returns a value less than, equal to or greater than zero if the
  * absolute value of |a| is less than, equal to or greater than the absolute
  * value of |b|, respectively. */
@@ -587,10 +591,16 @@
 /* BN_pseudo_rand is an alias for |BN_rand|. */
 OPENSSL_EXPORT int BN_pseudo_rand(BIGNUM *rnd, int bits, int top, int bottom);
 
-/* BN_rand_range sets |rnd| to a random value [0..range). It returns one on
- * success and zero otherwise. */
+/* BN_rand_range is equivalent to |BN_rand_range_ex| with |min_inclusive| set
+ * to zero and |max_exclusive| set to |range|. */
 OPENSSL_EXPORT int BN_rand_range(BIGNUM *rnd, const BIGNUM *range);
 
+/* BN_rand_range_ex sets |rnd| to a random value in
+ * [min_inclusive..max_exclusive). It returns one on success and zero
+ * otherwise. */
+OPENSSL_EXPORT int BN_rand_range_ex(BIGNUM *r, BN_ULONG min_inclusive,
+                                    const BIGNUM *max_exclusive);
+
 /* BN_pseudo_rand_range is an alias for BN_rand_range. */
 OPENSSL_EXPORT int BN_pseudo_rand_range(BIGNUM *rnd, const BIGNUM *range);
 
diff --git a/ssl/ssl_ecdh.c b/ssl/ssl_ecdh.c
index dd70bdb..47b6eab 100644
--- a/ssl/ssl_ecdh.c
+++ b/ssl/ssl_ecdh.c
@@ -59,12 +59,9 @@
   }
 
   /* Generate a private key. */
-  const BIGNUM *order = EC_GROUP_get0_order(group);
-  do {
-    if (!BN_rand_range(private_key, order)) {
-      goto err;
-    }
-  } while (BN_is_zero(private_key));
+  if (!BN_rand_range_ex(private_key, 1, EC_GROUP_get0_order(group))) {
+    goto err;
+  }
 
   /* Compute the corresponding public key and serialize it. */
   public_key = EC_POINT_new(group);