From e05e53c482865d16287b8df5408e4f6fec9accb6 Mon Sep 17 00:00:00 2001
From: Adam Langley <agl@chromium.org>
Date: Tue, 23 Apr 2013 14:36:06 -0400
Subject: [PATCH 08/11] small_prime_generation.

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.
---
 crypto/bn/bn.h       |  2 ++
 crypto/bn/bn_err.c   |  2 ++
 crypto/bn/bn_prime.c | 71 ++++++++++++++++++++++++++++++++++++++++++++--------
 crypto/bn/bntest.c   | 28 +++++++++++++++++++++
 4 files changed, 93 insertions(+), 10 deletions(-)

diff --git a/crypto/bn/bn.h b/crypto/bn/bn.h
index af5e9b9..7c23c01 100644
--- a/crypto/bn/bn.h
+++ b/crypto/bn/bn.h
@@ -831,6 +831,7 @@ void ERR_load_BN_strings(void);
 #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
@@ -859,6 +860,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
diff --git a/crypto/bn/bn_err.c b/crypto/bn/bn_err.c
index 2704417..18a28ec 100644
--- a/crypto/bn/bn_err.c
+++ b/crypto/bn/bn_err.c
@@ -88,6 +88,7 @@ static ERR_STRING_DATA BN_str_functs[]=
 {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"},
@@ -119,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"},
diff --git a/crypto/bn/bn_prime.c b/crypto/bn/bn_prime.c
index 7b25979..339dbec 100644
--- a/crypto/bn/bn_prime.c
+++ b/crypto/bn/bn_prime.c
@@ -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,27 +391,65 @@ 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)
 		{
-		/* check that rnd is not a prime and also
-		 * that gcd(rnd-1,primes) == 1 (except for 2) */
-		if (((mods[i]+delta)%primes[i]) <= 1)
+		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++)
 			{
-			delta+=2;
-			if (delta > maxdelta) goto again;
-			goto loop;
+			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) */
+			if (((mods[i]+delta)%primes[i]) <= 1)
+				{
+				delta+=2;
+				if (delta > maxdelta) goto 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);
 	}
diff --git a/crypto/bn/bntest.c b/crypto/bn/bntest.c
index 7771e92..d22c2d4 100644
--- a/crypto/bn/bntest.c
+++ b/crypto/bn/bntest.c
@@ -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;
-- 
1.8.2.1

