From 67cb49d045f04973ddba0f92fe8a8ad483c7da89 Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Thu, 9 Jun 2016 18:57:56 +0000 Subject: [PATCH] Fix BN_mod_word bug. On systems where we do not have BN_ULLONG (notably Win64), BN_mod_word() can return incorrect results if the supplied modulus is too big. (Imported from upstream's e82fd1b4574c8908b2c3bb68e1237f057a981820 and e4c4b2766bb97b34ea3479252276ab7c66311809.) Change-Id: Icee8a7c5c67a8ee14c276097f43a7c491e68c2f9 Reviewed-on: https://boringssl-review.googlesource.com/8233 Reviewed-by: Adam Langley --- crypto/bn/bn_test.cc | 6 ++++++ crypto/bn/div.c | 14 ++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/crypto/bn/bn_test.cc b/crypto/bn/bn_test.cc index fe8cfd05..d909ee28 100644 --- a/crypto/bn/bn_test.cc +++ b/crypto/bn/bn_test.cc @@ -850,11 +850,17 @@ static bool test_div_word(FILE *fp) { return false; } BN_ULONG s = b->d[0]; + BN_ULONG rmod = BN_mod_word(b.get(), s); BN_ULONG r = BN_div_word(b.get(), s); if (r == (BN_ULONG)-1) { return false; } + if (rmod != r) { + fprintf(stderr, "Mod (word) test failed!\n"); + return false; + } + if (fp != NULL) { BN_print_fp(fp, a.get()); puts_fp(fp, " / "); diff --git a/crypto/bn/div.c b/crypto/bn/div.c index 6f672914..e824458b 100644 --- a/crypto/bn/div.c +++ b/crypto/bn/div.c @@ -644,6 +644,20 @@ BN_ULONG BN_mod_word(const BIGNUM *a, BN_ULONG w) { return (BN_ULONG) -1; } +#ifndef BN_ULLONG + /* If |w| is too long and we don't have |BN_ULLONG| then we need to fall back + * to using |BN_div_word|. */ + if (w > ((BN_ULONG)1 << BN_BITS4)) { + BIGNUM *tmp = BN_dup(a); + if (tmp == NULL) { + return (BN_ULONG)-1; + } + ret = BN_div_word(tmp, w); + BN_free(tmp); + return ret; + } +#endif + w &= BN_MASK2; for (i = a->top - 1; i >= 0; i--) { #ifndef BN_ULLONG