Commit 96a4c31b authored by Adam Langley's avatar Adam Langley Committed by Ben Laurie
Browse files

Ensure that, when generating small primes, the result is actually of the

requested size. Fixes OpenSSL #2701.

This change does not address the cases of generating safe primes, or
where the |add| parameter is non-NULL.

Conflicts:
	crypto/bn/bn.h
	crypto/bn/bn_err.c
parent 2b0180c3
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -826,6 +826,8 @@ void ERR_load_BN_strings(void);
#define BN_F_BN_EXP					 123
#define BN_F_BN_EXPAND2					 108
#define BN_F_BN_EXPAND_INTERNAL				 120
#define BN_F_BN_GENERATE_DSA_NONCE			 140
#define BN_F_BN_GENERATE_PRIME_EX			 141
#define BN_F_BN_GF2M_MOD				 131
#define BN_F_BN_GF2M_MOD_EXP				 132
#define BN_F_BN_GF2M_MOD_MUL				 133
@@ -854,6 +856,7 @@ void ERR_load_BN_strings(void);
#define BN_R_ARG2_LT_ARG3				 100
#define BN_R_BAD_RECIPROCAL				 101
#define BN_R_BIGNUM_TOO_LONG				 114
#define BN_R_BITS_TOO_SMALL				 118
#define BN_R_CALLED_WITH_EVEN_MODULUS			 102
#define BN_R_DIV_BY_ZERO				 103
#define BN_R_ENCODING_ERROR				 104
+3 −0
Original line number Diff line number Diff line
@@ -87,6 +87,8 @@ static ERR_STRING_DATA BN_str_functs[]=
{ERR_FUNC(BN_F_BN_EXP),	"BN_exp"},
{ERR_FUNC(BN_F_BN_EXPAND2),	"bn_expand2"},
{ERR_FUNC(BN_F_BN_EXPAND_INTERNAL),	"BN_EXPAND_INTERNAL"},
{ERR_FUNC(BN_F_BN_GENERATE_DSA_NONCE),	"BN_generate_dsa_nonce"},
{ERR_FUNC(BN_F_BN_GENERATE_PRIME_EX),	"BN_generate_prime_ex"},
{ERR_FUNC(BN_F_BN_GF2M_MOD),	"BN_GF2m_mod"},
{ERR_FUNC(BN_F_BN_GF2M_MOD_EXP),	"BN_GF2m_mod_exp"},
{ERR_FUNC(BN_F_BN_GF2M_MOD_MUL),	"BN_GF2m_mod_mul"},
@@ -118,6 +120,7 @@ static ERR_STRING_DATA BN_str_reasons[]=
{ERR_REASON(BN_R_ARG2_LT_ARG3)           ,"arg2 lt arg3"},
{ERR_REASON(BN_R_BAD_RECIPROCAL)         ,"bad reciprocal"},
{ERR_REASON(BN_R_BIGNUM_TOO_LONG)        ,"bignum too long"},
{ERR_REASON(BN_R_BITS_TOO_SMALL)         ,"bits too small"},
{ERR_REASON(BN_R_CALLED_WITH_EVEN_MODULUS),"called with even modulus"},
{ERR_REASON(BN_R_DIV_BY_ZERO)            ,"div by zero"},
{ERR_REASON(BN_R_ENCODING_ERROR)         ,"encoding error"},
+61 −10
Original line number Diff line number Diff line
@@ -165,6 +165,19 @@ int BN_generate_prime_ex(BIGNUM *ret, int bits, int safe,
	BN_CTX *ctx;
	int checks = BN_prime_checks_for_size(bits);

	if (bits < 2)
		{
		/* There are no prime numbers this small. */
		BNerr(BN_F_BN_GENERATE_PRIME_EX, BN_R_BITS_TOO_SMALL);
		return 0;
		}
	else if (bits == 2 && safe)
		{
		/* The smallest safe prime (7) is three bits. */
		BNerr(BN_F_BN_GENERATE_PRIME_EX, BN_R_BITS_TOO_SMALL);
		return 0;
		}

	ctx=BN_CTX_new();
	if (ctx == NULL) goto err;
	BN_CTX_start(ctx);
@@ -378,16 +391,51 @@ static int probable_prime(BIGNUM *rnd, int bits)
	{
	int i;
	prime_t mods[NUMPRIMES];
	BN_ULONG delta,maxdelta;
	BN_ULONG delta;
	BN_ULONG maxdelta = BN_MASK2 - primes[NUMPRIMES-1];
	char is_single_word = bits <= BN_BITS2;

again:
	if (!BN_rand(rnd,bits,1,1)) return(0);
	/* we now have a random number 'rand' to test. */
	/* we now have a random number 'rnd' to test. */
	for (i=1; i<NUMPRIMES; i++)
		mods[i]=(prime_t)BN_mod_word(rnd,(BN_ULONG)primes[i]);
	maxdelta=BN_MASK2 - primes[NUMPRIMES-1];
	/* If bits is so small that it fits into a single word then we
	 * 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;
		if (size_limit < maxdelta)
			maxdelta = size_limit;
		}
	delta=0;
	loop: for (i=1; i<NUMPRIMES; i++)
	loop:
	if (is_single_word)
		{
		BN_ULONG rnd_word = BN_get_word(rnd);

		/* In the case that the candidate prime is a single word then
		 * we check that:
		 *   1) It's greater than primes[i] because we shouldn't reject
		 *      3 as being a prime number because it's a multiple of
		 *      three.
		 *   2) That it's not a multiple of a known prime. We don't
		 *      check that rnd-1 is also coprime to all the known
		 *      primes because there aren't many small primes where
		 *      that's true. */
		for (i=1; i<NUMPRIMES && primes[i]<rnd_word; i++)
			{
			if ((mods[i]+delta)%primes[i] == 0)
				{
				delta+=2;
				if (delta > maxdelta) goto again;
				goto loop;
				}
			}
		}
	else
		{
		for (i=1; i<NUMPRIMES; i++)
			{
			/* check that rnd is not a prime and also
			 * that gcd(rnd-1,primes) == 1 (except for 2) */
@@ -398,7 +446,10 @@ again:
				goto loop;
				}
			}
		}
	if (!BN_add_word(rnd,delta)) return(0);
	if (BN_num_bits(rnd) != bits)
		goto again;
	bn_check_top(rnd);
	return(1);
	}
+28 −0
Original line number Diff line number Diff line
@@ -120,6 +120,7 @@ int test_gf2m_mod_sqrt(BIO *bp,BN_CTX *ctx);
int test_gf2m_mod_solve_quad(BIO *bp,BN_CTX *ctx);
int test_kron(BIO *bp,BN_CTX *ctx);
int test_sqrt(BIO *bp,BN_CTX *ctx);
int test_small_prime(BIO *bp,BN_CTX *ctx);
int rand_neg(void);
static int results=0;

@@ -264,6 +265,11 @@ int main(int argc, char *argv[])
	message(out,"BN_mod_sqrt");
	if (!test_sqrt(out,ctx)) goto err;
	(void)BIO_flush(out);

	message(out,"Small prime generation");
	if (!test_small_prime(out,ctx)) goto err;
	(void)BIO_flush(out);

#ifndef OPENSSL_NO_EC2M
	message(out,"BN_GF2m_add");
	if (!test_gf2m_add(out)) goto err;
@@ -1895,6 +1901,28 @@ int test_sqrt(BIO *bp, BN_CTX *ctx)
	return ret;
	}

int test_small_prime(BIO *bp,BN_CTX *ctx)
	{
	static const int bits = 10;
	int ret = 0;
	BIGNUM r;

	BN_init(&r);
	if (!BN_generate_prime_ex(&r, bits, 0, NULL, NULL, NULL))
		goto err;
	if (BN_num_bits(&r) != bits)
		{
		BIO_printf(bp, "Expected %d bit prime, got %d bit number\n", bits, BN_num_bits(&r));
		goto err;
		}

	ret = 1;

err:
	BN_clear(&r);
	return ret;
	}

int test_lshift(BIO *bp,BN_CTX *ctx,BIGNUM *a_)
	{
	BIGNUM *a,*b,*c,*d;