From 72d555dd7c3f86142ef1f0aa2837d02ea51737e3 Mon Sep 17 00:00:00 2001 From: Janos Follath Date: Mon, 3 Sep 2018 14:45:23 +0100 Subject: [PATCH] Bignum: Fix prime validation vulnerability The input distribution to primality testing functions is completely different when used for generating primes and when for validating primes. The constants used in the library are geared towards the prime generation use case and are weak when used for validation. (Maliciously constructed composite numbers can pass the test with high probability) The mbedtls_mpi_is_prime() function is in the public API and although it is not documented, it is reasonable to assume that the primary use case is validating primes. The RSA module too uses it for validating key material. --- library/bignum.c | 42 ++++++++++++++++++++++++++++-------------- 1 file changed, 28 insertions(+), 14 deletions(-) diff --git a/library/bignum.c b/library/bignum.c index 09b0321b2..bf5e0df4a 100644 --- a/library/bignum.c +++ b/library/bignum.c @@ -2053,12 +2053,12 @@ cleanup: /* * Miller-Rabin pseudo-primality test (HAC 4.24) */ -static int mpi_miller_rabin( const mbedtls_mpi *X, +static int mpi_miller_rabin( const mbedtls_mpi *X, size_t rounds, int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) { int ret, count; - size_t i, j, k, n, s; + size_t i, j, k, s; mbedtls_mpi W, R, T, A, RR; mbedtls_mpi_init( &W ); mbedtls_mpi_init( &R ); mbedtls_mpi_init( &T ); mbedtls_mpi_init( &A ); @@ -2074,14 +2074,8 @@ static int mpi_miller_rabin( const mbedtls_mpi *X, MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &R, s ) ); i = mbedtls_mpi_bitlen( X ); - /* - * HAC, table 4.4 - */ - n = ( ( i >= 1300 ) ? 2 : ( i >= 850 ) ? 3 : - ( i >= 650 ) ? 4 : ( i >= 350 ) ? 8 : - ( i >= 250 ) ? 12 : ( i >= 150 ) ? 18 : 27 ); - for( i = 0; i < n; i++ ) + for( i = 0; i < rounds; i++ ) { /* * pick a random A, 1 < A < |X| - 1 @@ -2148,7 +2142,7 @@ cleanup: /* * Pseudo-primality test: small factors, then Miller-Rabin */ -int mbedtls_mpi_is_prime( const mbedtls_mpi *X, +int mpi_is_prime_internal( const mbedtls_mpi *X, int rounds, int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) { @@ -2174,7 +2168,17 @@ int mbedtls_mpi_is_prime( const mbedtls_mpi *X, return( ret ); } - return( mpi_miller_rabin( &XX, f_rng, p_rng ) ); + return( mpi_miller_rabin( &XX, rounds, f_rng, p_rng ) ); +} + +/* + * Pseudo-primality test, error probability 2^-80 + */ +int mbedtls_mpi_is_prime( const mbedtls_mpi *X, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + return mpi_is_prime_internal( X, 40, f_rng, p_rng ); } /* @@ -2186,6 +2190,7 @@ int mbedtls_mpi_gen_prime( mbedtls_mpi *X, size_t nbits, int dh_flag, { int ret; size_t k, n; + int rounds; mbedtls_mpi_uint r; mbedtls_mpi Y; @@ -2196,6 +2201,13 @@ int mbedtls_mpi_gen_prime( mbedtls_mpi *X, size_t nbits, int dh_flag, n = BITS_TO_LIMBS( nbits ); + /* + * 2^-80 error probability, number of rounds chosen per HAC, table 4.4 + */ + rounds = ( ( nbits >= 1300 ) ? 2 : ( nbits >= 850 ) ? 3 : + ( nbits >= 650 ) ? 4 : ( nbits >= 350 ) ? 8 : + ( nbits >= 250 ) ? 12 : ( nbits >= 150 ) ? 18 : 27 ); + MBEDTLS_MPI_CHK( mbedtls_mpi_fill_random( X, n * ciL, f_rng, p_rng ) ); k = mbedtls_mpi_bitlen( X ); @@ -2207,7 +2219,7 @@ int mbedtls_mpi_gen_prime( mbedtls_mpi *X, size_t nbits, int dh_flag, if( dh_flag == 0 ) { - while( ( ret = mbedtls_mpi_is_prime( X, f_rng, p_rng ) ) != 0 ) + while( ( ret = mpi_is_prime_internal( X, rounds, f_rng, p_rng ) ) != 0 ) { if( ret != MBEDTLS_ERR_MPI_NOT_ACCEPTABLE ) goto cleanup; @@ -2243,8 +2255,10 @@ int mbedtls_mpi_gen_prime( mbedtls_mpi *X, size_t nbits, int dh_flag, */ if( ( ret = mpi_check_small_factors( X ) ) == 0 && ( ret = mpi_check_small_factors( &Y ) ) == 0 && - ( ret = mpi_miller_rabin( X, f_rng, p_rng ) ) == 0 && - ( ret = mpi_miller_rabin( &Y, f_rng, p_rng ) ) == 0 ) + ( ret = mpi_miller_rabin( X, rounds, f_rng, p_rng ) ) + == 0 && + ( ret = mpi_miller_rabin( &Y, rounds, f_rng, p_rng ) ) + == 0 ) { break; }