diff --git a/ChangeLog.d/ecdsa-random-leading-zeros.txt b/ChangeLog.d/ecdsa-random-leading-zeros.txt new file mode 100644 index 000000000..cbc674bd4 --- /dev/null +++ b/ChangeLog.d/ecdsa-random-leading-zeros.txt @@ -0,0 +1,7 @@ +Security +* Fix a potential side channel vulnerability in ECDSA ephemeral key generation. + An adversary who is capable of very precise timing measurements could + learn partial information about the leading bits of the nonce used for the + signature, allowing the recovery of the private key after observing a + large number of signature operations. This completes a partial fix in + Mbed TLS 2.20.0. diff --git a/library/bignum.c b/library/bignum.c index 3acc4b9b4..2c3645689 100644 --- a/library/bignum.c +++ b/library/bignum.c @@ -2466,9 +2466,10 @@ int mbedtls_mpi_random( mbedtls_mpi *X, { int ret = MBEDTLS_ERR_MPI_BAD_INPUT_DATA; int count; - unsigned cmp = 0; + unsigned lt_lower = 1, lt_upper = 0; size_t n_bits = mbedtls_mpi_bitlen( N ); size_t n_bytes = ( n_bits + 7 ) / 8; + mbedtls_mpi lower_bound; if( min < 0 ) return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA ); @@ -2494,10 +2495,14 @@ int mbedtls_mpi_random( mbedtls_mpi *X, */ count = ( n_bytes > 4 ? 30 : 250 ); + mbedtls_mpi_init( &lower_bound ); + /* Ensure that target MPI has exactly the same number of limbs * as the upper bound, even if the upper bound has leading zeros. * This is necessary for the mbedtls_mpi_lt_mpi_ct() check. */ MBEDTLS_MPI_CHK( mbedtls_mpi_resize_clear( X, N->n ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_grow( &lower_bound, N->n ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &lower_bound, min ) ); /* * Match the procedure given in RFC 6979 ยง3.3 (deterministic ECDSA) @@ -2518,11 +2523,13 @@ int mbedtls_mpi_random( mbedtls_mpi *X, goto cleanup; } - MBEDTLS_MPI_CHK( mbedtls_mpi_lt_mpi_ct( X, N, &cmp ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_lt_mpi_ct( X, &lower_bound, <_lower ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_lt_mpi_ct( X, N, <_upper ) ); } - while( mbedtls_mpi_cmp_int( X, min ) < 0 || cmp != 1 ); + while( lt_lower != 0 || lt_upper == 0 ); cleanup: + mbedtls_mpi_free( &lower_bound ); return( ret ); }