Correct deterministic ECDSA behavior

We were still reusing the internal HMAC-DRBG of the deterministic ECDSA
for blinding. This meant that with cryptographically low likelyhood the
result was not the same signature as the one the deterministic ECDSA
algorithm has to produce (however it is still a valid ECDSA signature).

To correct this we seed a second HMAC-DRBG with the same seed to restore
correct behavior. We also apply a label to avoid reusing the bits of the
ephemeral key for a different purpose and reduce the chance that they
leak.

This workaround can't be implemented in the restartable case without
penalising the case where external RNG is available or completely
defeating the purpose of the restartable feature, therefore in this case
the small chance of incorrect behavior remains.
This commit is contained in:
Janos Follath 2019-01-07 17:27:56 +00:00
parent ba66faf167
commit 7b774483bf

View File

@ -195,12 +195,16 @@ static int ecdsa_sign_det_internal( mbedtls_ecp_group *grp, mbedtls_mpi *r,
size_t grp_len = ( grp->nbits + 7 ) / 8;
const mbedtls_md_info_t *md_info;
mbedtls_mpi h;
/* Variables for deterministic blinding fallback */
const char* blind_label = "BLINDING CONTEXT";
mbedtls_hmac_drbg_context rng_ctx_blind;
if( ( md_info = mbedtls_md_info_from_type( md_alg ) ) == NULL )
return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA );
mbedtls_mpi_init( &h );
mbedtls_hmac_drbg_init( &rng_ctx );
mbedtls_hmac_drbg_init( &rng_ctx_blind );
/* Use private key and message hash (reduced) to initialize HMAC_DRBG */
MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( d, data, grp_len ) );
@ -213,18 +217,38 @@ static int ecdsa_sign_det_internal( mbedtls_ecp_group *grp, mbedtls_mpi *r,
mbedtls_hmac_drbg_random, &rng_ctx,
f_rng_blind, p_rng_blind );
else
{
/*
* Use the same RNG for both blinding and ephemeral key generation.
* Since the RNG output is always the same for the same key and message,
* this limits the efficiency of blinding and leaks information through
* side channels.
* To avoid reusing rng_ctx and risking incorrect behavior we seed a
* second HMAC-DRBG with the same seed. We also apply a label to avoid
* reusing the bits of the ephemeral key for blinding and eliminate the
* risk that they leak this way.
*/
mbedtls_hmac_drbg_seed_buf( &rng_ctx_blind, md_info,
data, 2 * grp_len );
ret = mbedtls_hmac_drbg_update_ret( &rng_ctx_blind,
(const unsigned char*) blind_label,
strlen( blind_label ) );
if( ret != 0 )
goto cleanup;
/*
* Since the output of the RNGs is always the same for the same key and
* message, this limits the efficiency of blinding and leaks information
* through side channels. After mbedtls_ecdsa_sign_det() is removed NULL
* won't be a valid value for f_rng_blind anymore. Therefore it should
* be checked by the caller and this branch and check can be removed.
*/
ret = ecdsa_sign_internal( grp, r, s, d, buf, blen,
mbedtls_hmac_drbg_random, &rng_ctx,
mbedtls_hmac_drbg_random, &rng_ctx );
mbedtls_hmac_drbg_random, &rng_ctx_blind );
}
cleanup:
mbedtls_hmac_drbg_free( &rng_ctx );
mbedtls_hmac_drbg_free( &rng_ctx_blind );
mbedtls_mpi_free( &h );
return( ret );