From ac12767ff3b8fabd033770015cdb029b12ec24e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20P=C3=A9gouri=C3=A9-Gonnard?= Date: Tue, 1 Jun 2021 12:06:57 +0200 Subject: [PATCH] Fix non-constant-time comparison in mbedtls_ecp_gen_privkey MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Calling mbedtls_mpi_cmp_int reveals the number of leading zero limbs to an adversary who is capable of very fine-grained timing measurements. This is very little information, but could be practical with secp521r1 (1/512 chance of the leading limb being 0) if the adversary can measure the precise timing of a large number of signature operations. Signed-off-by: Manuel Pégourié-Gonnard --- ChangeLog.d/ecdsa-random-leading-zeros.txt | 7 +++++++ library/ecp.c | 23 ++++++++++++++++------ 2 files changed, 24 insertions(+), 6 deletions(-) create mode 100644 ChangeLog.d/ecdsa-random-leading-zeros.txt diff --git a/ChangeLog.d/ecdsa-random-leading-zeros.txt b/ChangeLog.d/ecdsa-random-leading-zeros.txt new file mode 100644 index 0000000000..793b37156e --- /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.16.4. diff --git a/library/ecp.c b/library/ecp.c index 2168981afb..9db6988838 100644 --- a/library/ecp.c +++ b/library/ecp.c @@ -3059,6 +3059,11 @@ int mbedtls_ecp_gen_privkey( const mbedtls_ecp_group *grp, { int ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA; size_t n_size; +#if defined(ECP_SHORTWEIERSTRASS) + mbedtls_mpi one; + + mbedtls_mpi_init( &one ); +#endif ECP_VALIDATE_RET( grp != NULL ); ECP_VALIDATE_RET( d != NULL ); @@ -3099,7 +3104,10 @@ int mbedtls_ecp_gen_privkey( const mbedtls_ecp_group *grp, { /* SEC1 3.2.1: Generate d such that 1 <= n < N */ int count = 0; - unsigned cmp = 0; + unsigned lt_lower = 1, lt_upper = 0; + + MBEDTLS_MPI_CHK( mbedtls_mpi_grow( &one, grp->N.n ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &one, 1 ) ); /* * Match the procedure given in RFC 6979 (deterministic ECDSA): @@ -3123,19 +3131,22 @@ int mbedtls_ecp_gen_privkey( const mbedtls_ecp_group *grp, * such as secp224k1 are actually very close to the worst case. */ if( ++count > 30 ) - return( MBEDTLS_ERR_ECP_RANDOM_FAILED ); - - ret = mbedtls_mpi_lt_mpi_ct( d, &grp->N, &cmp ); - if( ret != 0 ) { + ret = MBEDTLS_ERR_ECP_RANDOM_FAILED; goto cleanup; } + + MBEDTLS_MPI_CHK( mbedtls_mpi_lt_mpi_ct( d, &grp->N, <_upper ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_lt_mpi_ct( d, &one, <_lower ) ); } - while( mbedtls_mpi_cmp_int( d, 1 ) < 0 || cmp != 1 ); + while( lt_lower != 0 || lt_upper == 0 ); } #endif /* ECP_SHORTWEIERSTRASS */ cleanup: +#if defined(ECP_SHORTWEIERSTRASS) + mbedtls_mpi_free( &one ); +#endif return( ret ); }