From: Matt Caswell Date: Fri, 13 Mar 2015 12:48:57 +0000 (+0000) Subject: Fix probable_prime over large shift X-Git-Tag: OpenSSL_1_1_0-pre1~1520 X-Git-Url: https://git.openssl.org/gitweb/?p=openssl.git;a=commitdiff_plain;h=e4676e900f165f5272991443225813002300b09b;ds=sidebyside Fix probable_prime over large shift In the probable_prime() function we behave slightly different if the number of bits we are interested in is <= BN_BITS2 (the num of bits in a BN_ULONG). As part of the calculation we work out a size_limit as follows: size_limit = (((BN_ULONG)1) << bits) - BN_get_word(rnd) - 1; There is a problem though if bits == BN_BITS2. Shifting by that much causes undefined behaviour. I did some tests. On my system BN_BITS2 == 64. So I set bits to 64 and calculated the result of: (((BN_ULONG)1) << bits) I was expecting to get the result 0. I actually got 1! Strangely this... (((BN_ULONG)0) << BN_BITS2) ...does equal 0! This means that, on my system at least, size_limit will be off by 1 when bits == BN_BITS2. This commit fixes the behaviour so that we always get consistent results. Reviewed-by: Andy Polyakov --- diff --git a/crypto/bn/bn_prime.c b/crypto/bn/bn_prime.c index b12295e84e..2a7822ef1d 100644 --- a/crypto/bn/bn_prime.c +++ b/crypto/bn/bn_prime.c @@ -518,7 +518,17 @@ static int probable_prime(BIGNUM *rnd, int bits) * additionally don't want to exceed that many bits. */ if (is_single_word) { - BN_ULONG size_limit = (((BN_ULONG)1) << bits) - BN_get_word(rnd) - 1; + BN_ULONG size_limit; + + if (bits == BN_BITS2) { + /* + * Shifting by this much has undefined behaviour so we do it a + * different way + */ + size_limit = ~((BN_ULONG)0) - BN_get_word(rnd); + } else { + size_limit = (((BN_ULONG)1) << bits) - BN_get_word(rnd) - 1; + } if (size_limit < maxdelta) maxdelta = size_limit; }