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);