Fix sign bit in BN_div if numerator and quotient alias. See also f8fc0e35e0b1813af15887d42e17b7d5537bb86c from upstream, though our BN_divs have diverged slightly. Change-Id: I49fa4f0a5c730d34e6f41f724f1afe3685470712 Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/48426 Reviewed-by: Adam Langley <agl@google.com>
diff --git a/crypto/fipsmodule/bn/bn_test.cc b/crypto/fipsmodule/bn/bn_test.cc index 9791437..1b42d9c 100644 --- a/crypto/fipsmodule/bn/bn_test.cc +++ b/crypto/fipsmodule/bn/bn_test.cc
@@ -556,6 +556,19 @@ EXPECT_BIGNUMS_EQUAL("A / B", quotient.get(), ret.get()); EXPECT_BIGNUMS_EQUAL("A % B", remainder.get(), ret2.get()); + ASSERT_TRUE(BN_copy(ret.get(), a.get())); + ASSERT_TRUE(BN_copy(ret2.get(), b.get())); + ASSERT_TRUE(BN_div(ret.get(), ret2.get(), ret.get(), ret2.get(), ctx)); + EXPECT_BIGNUMS_EQUAL("A / B (in-place)", quotient.get(), ret.get()); + EXPECT_BIGNUMS_EQUAL("A % B (in-place)", remainder.get(), ret2.get()); + + ASSERT_TRUE(BN_copy(ret2.get(), a.get())); + ASSERT_TRUE(BN_copy(ret.get(), b.get())); + ASSERT_TRUE(BN_div(ret.get(), ret2.get(), ret2.get(), ret.get(), ctx)); + EXPECT_BIGNUMS_EQUAL("A / B (in-place, swapped)", quotient.get(), ret.get()); + EXPECT_BIGNUMS_EQUAL("A % B (in-place, swapped)", remainder.get(), + ret2.get()); + ASSERT_TRUE(BN_mul(ret.get(), quotient.get(), b.get(), ctx)); ASSERT_TRUE(BN_add(ret.get(), ret.get(), remainder.get())); EXPECT_BIGNUMS_EQUAL("Quotient * B + Remainder", a.get(), ret.get());
diff --git a/crypto/fipsmodule/bn/div.c b/crypto/fipsmodule/bn/div.c index 333c770..6ee6dbd 100644 --- a/crypto/fipsmodule/bn/div.c +++ b/crypto/fipsmodule/bn/div.c
@@ -285,8 +285,10 @@ // pointer to the 'top' of snum wnump = &(snum->d[num_n - 1]); - // Setup to 'res' - res->neg = (numerator->neg ^ divisor->neg); + // Setup |res|. |numerator| and |res| may alias, so we save |numerator->neg| + // for later. + const int numerator_neg = numerator->neg; + res->neg = (numerator_neg ^ divisor->neg); if (!bn_wexpand(res, loop + 1)) { goto err; } @@ -379,14 +381,11 @@ bn_set_minimal_width(snum); if (rem != NULL) { - // Keep a copy of the neg flag in numerator because if |rem| == |numerator| - // |BN_rshift| will overwrite it. - int neg = numerator->neg; if (!BN_rshift(rem, snum, norm_shift)) { goto err; } if (!BN_is_zero(rem)) { - rem->neg = neg; + rem->neg = numerator_neg; } }