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.
This commit is contained in:
parent
61bb3ddfab
commit
27ae9ed774
@ -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 */
|
||||
|
@ -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"},
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user