From 96a4c31be3344cb08994a9d460c0ebd55939cc5b Mon Sep 17 00:00:00 2001 From: Adam Langley Date: Tue, 23 Apr 2013 14:36:06 -0400 Subject: [PATCH] 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 --- crypto/bn/bn.h | 3 ++ crypto/bn/bn_err.c | 3 ++ crypto/bn/bn_prime.c | 71 +++++++++++++++++++++++++++++++++++++------- crypto/bn/bntest.c | 28 +++++++++++++++++ 4 files changed, 95 insertions(+), 10 deletions(-) diff --git a/crypto/bn/bn.h b/crypto/bn/bn.h index 0e5e554937..d7397cae8b 100644 --- a/crypto/bn/bn.h +++ b/crypto/bn/bn.h @@ -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 diff --git a/crypto/bn/bn_err.c b/crypto/bn/bn_err.c index cfe2eb94a0..cdc15e62f0 100644 --- a/crypto/bn/bn_err.c +++ b/crypto/bn/bn_err.c @@ -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"}, diff --git a/crypto/bn/bn_prime.c b/crypto/bn/bn_prime.c index 7b25979dd1..339dbec570 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 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 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 7771e92023..d22c2d43d6 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; -- 2.34.1