diff --git a/crypto/bn/bn.h b/crypto/bn/bn.h index 99e0efa4..23fca81e 100644 --- a/crypto/bn/bn.h +++ b/crypto/bn/bn.h @@ -780,6 +780,7 @@ unsigned BN_num_bits_word(BN_ULONG l); #define BN_F_BN_CTX_new 120 #define BN_F_BN_mod_inverse_no_branch 121 #define BN_F_BN_generate_dsa_nonce 122 +#define BN_F_BN_generate_prime_ex 123 #define BN_R_NOT_A_SQUARE 100 #define BN_R_TOO_MANY_ITERATIONS 101 #define BN_R_INPUT_NOT_REDUCED 102 @@ -795,5 +796,6 @@ unsigned BN_num_bits_word(BN_ULONG l); #define BN_R_ARG2_LT_ARG3 112 #define BN_R_BIGNUM_TOO_LONG 113 #define BN_R_PRIVATE_KEY_TOO_LARGE 114 +#define BN_R_BITS_TOO_SMALL 115 #endif /* OPENSSL_HEADER_BN_H */ diff --git a/crypto/bn/bn_error.c b/crypto/bn/bn_error.c index 4319d880..679033b7 100644 --- a/crypto/bn/bn_error.c +++ b/crypto/bn/bn_error.c @@ -26,6 +26,7 @@ const ERR_STRING_DATA BN_error_string_data[] = { {ERR_PACK(ERR_LIB_BN, BN_F_BN_div_recp, 0), "BN_div_recp"}, {ERR_PACK(ERR_LIB_BN, BN_F_BN_exp, 0), "BN_exp"}, {ERR_PACK(ERR_LIB_BN, BN_F_BN_generate_dsa_nonce, 0), "BN_generate_dsa_nonce"}, + {ERR_PACK(ERR_LIB_BN, BN_F_BN_generate_prime_ex, 0), "BN_generate_prime_ex"}, {ERR_PACK(ERR_LIB_BN, BN_F_BN_mod_exp2_mont, 0), "BN_mod_exp2_mont"}, {ERR_PACK(ERR_LIB_BN, BN_F_BN_mod_exp_mont, 0), "BN_mod_exp_mont"}, {ERR_PACK(ERR_LIB_BN, BN_F_BN_mod_exp_mont_consttime, 0), "BN_mod_exp_mont_consttime"}, @@ -43,6 +44,7 @@ const ERR_STRING_DATA BN_error_string_data[] = { {ERR_PACK(ERR_LIB_BN, 0, BN_R_ARG2_LT_ARG3), "ARG2_LT_ARG3"}, {ERR_PACK(ERR_LIB_BN, 0, BN_R_BAD_RECIPROCAL), "BAD_RECIPROCAL"}, {ERR_PACK(ERR_LIB_BN, 0, BN_R_BIGNUM_TOO_LONG), "BIGNUM_TOO_LONG"}, + {ERR_PACK(ERR_LIB_BN, 0, BN_R_BITS_TOO_SMALL), "BITS_TOO_SMALL"}, {ERR_PACK(ERR_LIB_BN, 0, BN_R_CALLED_WITH_EVEN_MODULUS), "CALLED_WITH_EVEN_MODULUS"}, {ERR_PACK(ERR_LIB_BN, 0, BN_R_DIV_BY_ZERO), "DIV_BY_ZERO"}, {ERR_PACK(ERR_LIB_BN, 0, BN_R_EXPAND_ON_STATIC_BIGNUM_DATA), "EXPAND_ON_STATIC_BIGNUM_DATA"}, diff --git a/crypto/bn/bn_test.c b/crypto/bn/bn_test.c index 38637999..aa9cecc4 100644 --- a/crypto/bn/bn_test.c +++ b/crypto/bn/bn_test.c @@ -99,6 +99,7 @@ int test_mod_exp_mont_consttime(BIO *bp, BN_CTX *ctx); int test_exp(BIO *bp, BN_CTX *ctx); int test_mod_sqrt(BIO *bp, BN_CTX *ctx); static int test_exp_mod_zero(); +int test_small_prime(BIO *bp,BN_CTX *ctx); int test_mod_exp_mont5(BIO *bp, BN_CTX *ctx); #if 0 int test_gf2m_add(BIO *bp); @@ -263,6 +264,11 @@ int main(int argc, char *argv[]) { goto err; (void)BIO_flush(out); + message(out, "Small prime generation"); + if (!test_small_prime(out, ctx)) + goto err; + (void)BIO_flush(out); + BN_CTX_free(ctx); BIO_free(out); @@ -1261,3 +1267,25 @@ err: BN_free(r); 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_free(&r); + return ret; +} diff --git a/crypto/bn/prime.c b/crypto/bn/prime.c index 1b8221b0..7d9edad6 100644 --- a/crypto/bn/prime.c +++ b/crypto/bn/prime.c @@ -173,6 +173,16 @@ int BN_generate_prime_ex(BIGNUM *ret, int bits, int safe, const BIGNUM *add, BN_CTX *ctx; int checks = BN_prime_checks_for_size(bits); + if (bits < 2) { + /* There are no prime numbers this small. */ + OPENSSL_PUT_ERROR(BN, BN_generate_prime_ex, BN_R_BITS_TOO_SMALL); + return 0; + } else if (bits == 2 && safe) { + /* The smallest safe prime (7) is three bits. */ + OPENSSL_PUT_ERROR(BN, BN_generate_prime_ex, BN_R_BITS_TOO_SMALL); + return 0; + } + ctx = BN_CTX_new(); if (ctx == NULL) { goto err; @@ -436,39 +446,79 @@ static int witness(BIGNUM *w, const BIGNUM *a, const BIGNUM *a1, return 1; } +static BN_ULONG get_word(const BIGNUM *bn) { + if (bn->top == 1) { + return bn->d[0]; + } + return 0; +} + static int probable_prime(BIGNUM *rnd, int bits) { int i; uint16_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] = (uint16_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) - get_word(rnd) - 1; + if (size_limit < maxdelta) { + maxdelta = size_limit; + } + } delta = 0; loop: - 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; + if (is_single_word) { + BN_ULONG rnd_word = 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) */ + if (((mods[i] + delta) % primes[i]) <= 1) { + delta += 2; + if (delta > maxdelta) + goto again; + goto loop; } - goto loop; } } if (!BN_add_word(rnd, delta)) { return 0; } + if (BN_num_bits(rnd) != bits) { + goto again; + } return 1; }