Require BN_mod_exp_mont* inputs be reduced.
If the caller asked for the base to be treated as secret, we should provide that. Allowing unbounded inputs is not compatible with being constant-time. Additionally, this aligns with the guidance here: https://github.com/HACS-workshop/spectre-mitigations/blob/master/crypto_guidelines.md#1-do-not-conditionally-choose-between-constant-and-non-constant-time Update-Note: BN_mod_exp_mont_consttime and BN_mod_exp_mont now require inputs be fully reduced. I believe current callers tolerate this. Additionally, due to a quirk of how certain operations were ordered, using (publicly) zero exponent tolerated a NULL BN_CTX while other exponents required non-NULL BN_CTX. Non-NULL BN_CTX is now required uniformly. This is unlikely to cause problems. Any call site where the exponent is always zero should just be replaced with BN_value_one(). Change-Id: I7c941953ea05f36dc2754facb9f4cf83a6789c61 Reviewed-on: https://boringssl-review.googlesource.com/27665 Commit-Queue: David Benjamin <davidben@google.com> CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org> Reviewed-by: Steven Valdez <svaldez@google.com>
This commit is contained in:
parent
52a68a9b43
commit
a63d0ad40d
@ -763,6 +763,9 @@ static void TestModExp(BIGNUMFileTest *t, BN_CTX *ctx) {
|
||||
ASSERT_TRUE(BN_mod_exp(ret.get(), a.get(), e.get(), m.get(), ctx));
|
||||
EXPECT_BIGNUMS_EQUAL("A ^ E (mod M)", mod_exp.get(), ret.get());
|
||||
|
||||
// The other implementations require reduced inputs.
|
||||
ASSERT_TRUE(BN_nnmod(a.get(), a.get(), m.get(), ctx));
|
||||
|
||||
if (BN_is_odd(m.get())) {
|
||||
ASSERT_TRUE(
|
||||
BN_mod_exp_mont(ret.get(), a.get(), e.get(), m.get(), ctx, NULL));
|
||||
@ -780,7 +783,6 @@ static void TestModExp(BIGNUMFileTest *t, BN_CTX *ctx) {
|
||||
bssl::UniquePtr<BN_MONT_CTX> mont(
|
||||
BN_MONT_CTX_new_for_modulus(m.get(), ctx));
|
||||
ASSERT_TRUE(mont.get());
|
||||
ASSERT_TRUE(BN_nnmod(a.get(), a.get(), m.get(), ctx));
|
||||
std::unique_ptr<BN_ULONG[]> r_words(new BN_ULONG[m_width]),
|
||||
a_words(new BN_ULONG[m_width]);
|
||||
ASSERT_TRUE(bn_copy_words(a_words.get(), m_width, a.get()));
|
||||
@ -1564,21 +1566,16 @@ TEST_F(BNTest, ExpModZero) {
|
||||
ASSERT_TRUE(BN_rand(a.get(), 1024, BN_RAND_TOP_ONE, BN_RAND_BOTTOM_ANY));
|
||||
BN_zero(zero.get());
|
||||
|
||||
ASSERT_TRUE(
|
||||
BN_mod_exp(r.get(), a.get(), zero.get(), BN_value_one(), nullptr));
|
||||
EXPECT_TRUE(BN_is_zero(r.get()));
|
||||
|
||||
ASSERT_TRUE(BN_mod_exp_mont(r.get(), a.get(), zero.get(), BN_value_one(),
|
||||
nullptr, nullptr));
|
||||
EXPECT_TRUE(BN_is_zero(r.get()));
|
||||
|
||||
ASSERT_TRUE(BN_mod_exp_mont_consttime(r.get(), a.get(), zero.get(),
|
||||
BN_value_one(), nullptr, nullptr));
|
||||
ASSERT_TRUE(BN_mod_exp(r.get(), a.get(), zero.get(), BN_value_one(), ctx()));
|
||||
EXPECT_TRUE(BN_is_zero(r.get()));
|
||||
|
||||
ASSERT_TRUE(BN_mod_exp_mont_word(r.get(), 42, zero.get(), BN_value_one(),
|
||||
nullptr, nullptr));
|
||||
ctx(), nullptr));
|
||||
EXPECT_TRUE(BN_is_zero(r.get()));
|
||||
|
||||
// The other modular exponentiation functions, |BN_mod_exp_mont| and
|
||||
// |BN_mod_exp_mont_consttime|, require fully-reduced inputs, so 1**0 mod 1 is
|
||||
// not a valid call.
|
||||
}
|
||||
|
||||
TEST_F(BNTest, SmallPrime) {
|
||||
|
@ -586,6 +586,13 @@ err:
|
||||
|
||||
int BN_mod_exp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, const BIGNUM *m,
|
||||
BN_CTX *ctx) {
|
||||
if (a->neg || BN_ucmp(a, m) >= 0) {
|
||||
if (!BN_nnmod(r, a, m, ctx)) {
|
||||
return 0;
|
||||
}
|
||||
a = r;
|
||||
}
|
||||
|
||||
if (BN_is_odd(m)) {
|
||||
return BN_mod_exp_mont(r, a, p, m, ctx, NULL);
|
||||
}
|
||||
@ -599,6 +606,11 @@ int BN_mod_exp_mont(BIGNUM *rr, const BIGNUM *a, const BIGNUM *p,
|
||||
OPENSSL_PUT_ERROR(BN, BN_R_CALLED_WITH_EVEN_MODULUS);
|
||||
return 0;
|
||||
}
|
||||
if (a->neg || BN_ucmp(a, m) >= 0) {
|
||||
OPENSSL_PUT_ERROR(BN, BN_R_INPUT_NOT_REDUCED);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bits = BN_num_bits(p);
|
||||
if (bits == 0) {
|
||||
// x**0 mod 1 is still zero.
|
||||
@ -630,22 +642,12 @@ int BN_mod_exp_mont(BIGNUM *rr, const BIGNUM *a, const BIGNUM *p,
|
||||
mont = new_mont;
|
||||
}
|
||||
|
||||
const BIGNUM *aa;
|
||||
if (a->neg || BN_ucmp(a, m) >= 0) {
|
||||
if (!BN_nnmod(val[0], a, m, ctx)) {
|
||||
goto err;
|
||||
}
|
||||
aa = val[0];
|
||||
} else {
|
||||
aa = a;
|
||||
}
|
||||
|
||||
// We exponentiate by looking at sliding windows of the exponent and
|
||||
// precomputing powers of |aa|. Windows may be shifted so they always end on a
|
||||
// set bit, so only precompute odd powers. We compute val[i] = aa^(2*i + 1)
|
||||
// precomputing powers of |a|. Windows may be shifted so they always end on a
|
||||
// set bit, so only precompute odd powers. We compute val[i] = a^(2*i + 1)
|
||||
// for i = 0 to 2^(window-1), all in Montgomery form.
|
||||
int window = BN_window_bits_for_exponent_size(bits);
|
||||
if (!BN_to_montgomery(val[0], aa, mont, ctx)) {
|
||||
if (!BN_to_montgomery(val[0], a, mont, ctx)) {
|
||||
goto err;
|
||||
}
|
||||
if (window > 1) {
|
||||
@ -966,12 +968,15 @@ int BN_mod_exp_mont_consttime(BIGNUM *rr, const BIGNUM *a, const BIGNUM *p,
|
||||
int powerbufLen = 0;
|
||||
unsigned char *powerbuf = NULL;
|
||||
BIGNUM tmp, am;
|
||||
BIGNUM *new_a = NULL;
|
||||
|
||||
if (!BN_is_odd(m)) {
|
||||
OPENSSL_PUT_ERROR(BN, BN_R_CALLED_WITH_EVEN_MODULUS);
|
||||
return 0;
|
||||
}
|
||||
if (a->neg || BN_ucmp(a, m) >= 0) {
|
||||
OPENSSL_PUT_ERROR(BN, BN_R_INPUT_NOT_REDUCED);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Use all bits stored in |p|, rather than |BN_num_bits|, so we do not leak
|
||||
// whether the top bits are zero.
|
||||
@ -999,15 +1004,6 @@ int BN_mod_exp_mont_consttime(BIGNUM *rr, const BIGNUM *a, const BIGNUM *p,
|
||||
// implementation assumes it can use |top| to size R.
|
||||
int top = mont->N.width;
|
||||
|
||||
if (a->neg || BN_ucmp(a, m) >= 0) {
|
||||
new_a = BN_new();
|
||||
if (new_a == NULL ||
|
||||
!BN_nnmod(new_a, a, m, ctx)) {
|
||||
goto err;
|
||||
}
|
||||
a = new_a;
|
||||
}
|
||||
|
||||
#ifdef RSAZ_ENABLED
|
||||
// If the size of the operands allow it, perform the optimized
|
||||
// RSAZ exponentiation. For further information see
|
||||
@ -1268,7 +1264,6 @@ int BN_mod_exp_mont_consttime(BIGNUM *rr, const BIGNUM *a, const BIGNUM *p,
|
||||
|
||||
err:
|
||||
BN_MONT_CTX_free(new_mont);
|
||||
BN_clear_free(new_a);
|
||||
OPENSSL_free(powerbufFree);
|
||||
return (ret);
|
||||
}
|
||||
@ -1281,6 +1276,11 @@ int BN_mod_exp_mont_word(BIGNUM *rr, BN_ULONG a, const BIGNUM *p,
|
||||
|
||||
int ret = 0;
|
||||
|
||||
// BN_mod_exp_mont requires reduced inputs.
|
||||
if (bn_minimal_width(m) == 1) {
|
||||
a %= m->d[0];
|
||||
}
|
||||
|
||||
if (!BN_set_word(&a_bignum, a)) {
|
||||
OPENSSL_PUT_ERROR(BN, ERR_R_INTERNAL_ERROR);
|
||||
goto err;
|
||||
|
@ -109,6 +109,8 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *buf, size_t len) {
|
||||
bssl::UniquePtr<BN_MONT_CTX> mont(
|
||||
BN_MONT_CTX_new_for_modulus(modulus.get(), ctx.get()));
|
||||
CHECK(mont);
|
||||
// |BN_mod_exp_mont| and |BN_mod_exp_mont_consttime| require reduced inputs.
|
||||
CHECK(BN_nnmod(base.get(), base.get(), modulus.get(), ctx.get()));
|
||||
CHECK(BN_mod_exp_mont(result.get(), base.get(), power.get(), modulus.get(),
|
||||
ctx.get(), mont.get()));
|
||||
CHECK(BN_cmp(result.get(), expected.get()) == 0);
|
||||
|
@ -874,10 +874,14 @@ OPENSSL_EXPORT int BN_exp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
|
||||
OPENSSL_EXPORT int BN_mod_exp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
|
||||
const BIGNUM *m, BN_CTX *ctx);
|
||||
|
||||
// BN_mod_exp_mont behaves like |BN_mod_exp| but treats |a| as secret and
|
||||
// requires 0 <= |a| < |m|.
|
||||
OPENSSL_EXPORT int BN_mod_exp_mont(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
|
||||
const BIGNUM *m, BN_CTX *ctx,
|
||||
const BN_MONT_CTX *mont);
|
||||
|
||||
// BN_mod_exp_mont_consttime behaves like |BN_mod_exp| but treats |a|, |p|, and
|
||||
// |m| as secret and requires 0 <= |a| < |m|.
|
||||
OPENSSL_EXPORT int BN_mod_exp_mont_consttime(BIGNUM *rr, const BIGNUM *a,
|
||||
const BIGNUM *p, const BIGNUM *m,
|
||||
BN_CTX *ctx,
|
||||
|
Loading…
Reference in New Issue
Block a user