From 2934c32da2198f6bfd1e10de6be9c00795d9b604 Mon Sep 17 00:00:00 2001 From: Janos Follath Date: Fri, 4 Jan 2019 14:32:30 +0000 Subject: [PATCH] Add a safer deterministic ECDSA function `mbedtls_ecdsa_sign_det` reuses the internal HMAC-DRBG instance to implement blinding. The advantage of this is that the algorithm is deterministic too, not just the resulting signature. The drawback is that the blinding is always the same for the same key and message. This diminishes the efficiency of blinding and leaks information about the private key. A function that takes external randomness fixes this weakness. --- include/mbedtls/ecdsa.h | 67 +++++++++++++++++++++++++++-- library/ecdsa.c | 93 ++++++++++++++++++++++++++++++++--------- 2 files changed, 138 insertions(+), 22 deletions(-) diff --git a/include/mbedtls/ecdsa.h b/include/mbedtls/ecdsa.h index ff6efbc3f..a213e91ec 100644 --- a/include/mbedtls/ecdsa.h +++ b/include/mbedtls/ecdsa.h @@ -101,6 +101,20 @@ int mbedtls_ecdsa_sign( mbedtls_ecp_group *grp, mbedtls_mpi *r, mbedtls_mpi *s, * Usage of the Digital Signature Algorithm (DSA) and Elliptic * Curve Digital Signature Algorithm (ECDSA). * + * + * \warning Since the output of the internal RNG is always the same for + * the same key and message, this limits the efficiency of + * blinding and leaks information through side channels. For + * secure behavior use mbedtls_ecdsa_sign_det_ext() instead. + * + * (Optimally the blinding is a random value that is different + * on every execution. In this case the blinding is still + * random from the attackers perspective, but is the same on + * each execution. This means that this blinding does not + * prevent attackers from recovering secrets by combining + * several measurement traces, but may prevent some attacks + * that exploit relationships between secret data.) + * * \param grp The ECP group. * \param r The first output integer. * \param s The second output integer. @@ -121,9 +135,56 @@ int mbedtls_ecdsa_sign( mbedtls_ecp_group *grp, mbedtls_mpi *r, mbedtls_mpi *s, * * \see ecp.h */ -int mbedtls_ecdsa_sign_det( mbedtls_ecp_group *grp, mbedtls_mpi *r, mbedtls_mpi *s, - const mbedtls_mpi *d, const unsigned char *buf, size_t blen, - mbedtls_md_type_t md_alg ); +int mbedtls_ecdsa_sign_det( mbedtls_ecp_group *grp, mbedtls_mpi *r, + mbedtls_mpi *s, const mbedtls_mpi *d, + const unsigned char *buf, size_t blen, + mbedtls_md_type_t md_alg ); +/** + * \brief This function computes the ECDSA signature of a + * previously-hashed message, deterministic version. + * + * For more information, see RFC-6979: Deterministic + * Usage of the Digital Signature Algorithm (DSA) and Elliptic + * Curve Digital Signature Algorithm (ECDSA). + * + * \note If the bitlength of the message hash is larger than the + * bitlength of the group order, then the hash is truncated as + * defined in Standards for Efficient Cryptography Group + * (SECG): SEC1 Elliptic Curve Cryptography, section + * 4.1.3, step 5. + * + * \see ecp.h + * + * \param grp The context for the elliptic curve to use. + * This must be initialized and have group parameters + * set, for example through mbedtls_ecp_group_load(). + * \param r The MPI context in which to store the first part + * the signature. This must be initialized. + * \param s The MPI context in which to store the second part + * the signature. This must be initialized. + * \param d The private signing key. This must be initialized + * and setup, for example through mbedtls_ecp_gen_privkey(). + * \param buf The hashed content to be signed. This must be a readable + * buffer of length \p blen Bytes. It may be \c NULL if + * \p blen is zero. + * \param blen The length of \p buf in Bytes. + * \param md_alg The hash algorithm used to hash the original data. + * \param f_rng_blind The RNG function used for blinding. This must not be + * \c NULL. + * \param p_rng_blind The RNG context to be passed to \p f_rng. This may be + * \c NULL if \p f_rng doesn't need a context parameter. + * + * \return \c 0 on success. + * \return An \c MBEDTLS_ERR_ECP_XXX or \c MBEDTLS_MPI_XXX + * error code on failure. + */ +int mbedtls_ecdsa_sign_det_ext( mbedtls_ecp_group *grp, mbedtls_mpi *r, + mbedtls_mpi *s, const mbedtls_mpi *d, + const unsigned char *buf, size_t blen, + mbedtls_md_type_t md_alg, + int (*f_rng_blind)(void *, unsigned char *, + size_t), + void *p_rng_blind ); #endif /* MBEDTLS_ECDSA_DETERMINISTIC */ /** diff --git a/library/ecdsa.c b/library/ecdsa.c index 17a88bdd2..b3e516179 100644 --- a/library/ecdsa.c +++ b/library/ecdsa.c @@ -70,9 +70,14 @@ cleanup: * Compute ECDSA signature of a hashed message (SEC1 4.1.3) * Obviously, compared to SEC1 4.1.3, we skip step 4 (hash message) */ -int mbedtls_ecdsa_sign( mbedtls_ecp_group *grp, mbedtls_mpi *r, mbedtls_mpi *s, - const mbedtls_mpi *d, const unsigned char *buf, size_t blen, - int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) +static int ecdsa_sign_internal( mbedtls_ecp_group *grp, mbedtls_mpi *r, + mbedtls_mpi *s, const mbedtls_mpi *d, + const unsigned char *buf, size_t blen, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + int (*f_rng_blind)(void *, unsigned char *, + size_t), + void *p_rng_blind ) { int ret, key_tries, sign_tries, blind_tries; mbedtls_ecp_point R; @@ -99,7 +104,10 @@ int mbedtls_ecdsa_sign( mbedtls_ecp_group *grp, mbedtls_mpi *r, mbedtls_mpi *s, key_tries = 0; do { - MBEDTLS_MPI_CHK( mbedtls_ecp_gen_keypair( grp, &k, &R, f_rng, p_rng ) ); + MBEDTLS_MPI_CHK( mbedtls_ecp_gen_privkey( grp, &k, f_rng, p_rng ) ); + + MBEDTLS_MPI_CHK( mbedtls_ecp_mul( grp, &R, &k, &grp->G, + f_rng_blind, p_rng_blind ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( r, &R.X, &grp->N ) ); if( key_tries++ > 10 ) @@ -123,7 +131,8 @@ int mbedtls_ecdsa_sign( mbedtls_ecp_group *grp, mbedtls_mpi *r, mbedtls_mpi *s, do { size_t n_size = ( grp->nbits + 7 ) / 8; - MBEDTLS_MPI_CHK( mbedtls_mpi_fill_random( &t, n_size, f_rng, p_rng ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_fill_random( &t, n_size, f_rng_blind, + p_rng_blind ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &t, 8 * n_size - grp->nbits ) ); /* See mbedtls_ecp_gen_keypair() */ @@ -158,15 +167,27 @@ cleanup: return( ret ); } + +int mbedtls_ecdsa_sign( mbedtls_ecp_group *grp, mbedtls_mpi *r, mbedtls_mpi *s, + const mbedtls_mpi *d, const unsigned char *buf, + size_t blen, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + /* Use the same RNG for both blinding and ephemeral key generation */ + return( ecdsa_sign_internal( grp, r, s, d, buf, blen, f_rng, p_rng, + f_rng, p_rng ) ); +} #endif /* MBEDTLS_ECDSA_SIGN_ALT */ #if defined(MBEDTLS_ECDSA_DETERMINISTIC) -/* - * Deterministic signature wrapper - */ -int mbedtls_ecdsa_sign_det( mbedtls_ecp_group *grp, mbedtls_mpi *r, mbedtls_mpi *s, - const mbedtls_mpi *d, const unsigned char *buf, size_t blen, - mbedtls_md_type_t md_alg ) +static int ecdsa_sign_det_internal( mbedtls_ecp_group *grp, mbedtls_mpi *r, + mbedtls_mpi *s, const mbedtls_mpi *d, + const unsigned char *buf, size_t blen, + mbedtls_md_type_t md_alg, + int (*f_rng_blind)(void *, unsigned char *, + size_t), + void *p_rng_blind ) { int ret; mbedtls_hmac_drbg_context rng_ctx; @@ -187,8 +208,20 @@ int mbedtls_ecdsa_sign_det( mbedtls_ecp_group *grp, mbedtls_mpi *r, mbedtls_mpi MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( &h, data + grp_len, grp_len ) ); mbedtls_hmac_drbg_seed_buf( &rng_ctx, md_info, data, 2 * grp_len ); - ret = mbedtls_ecdsa_sign( grp, r, s, d, buf, blen, - mbedtls_hmac_drbg_random, &rng_ctx ); + if( f_rng_blind != NULL ) + ret = ecdsa_sign_internal( grp, r, s, d, buf, blen, + 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. + */ + ret = ecdsa_sign_internal( grp, r, s, d, buf, blen, + mbedtls_hmac_drbg_random, &rng_ctx, + mbedtls_hmac_drbg_random, &rng_ctx ); cleanup: mbedtls_hmac_drbg_free( &rng_ctx ); @@ -196,6 +229,30 @@ cleanup: return( ret ); } + +/* + * Deterministic signature wrappers + */ +int mbedtls_ecdsa_sign_det( mbedtls_ecp_group *grp, mbedtls_mpi *r, + mbedtls_mpi *s, const mbedtls_mpi *d, + const unsigned char *buf, size_t blen, + mbedtls_md_type_t md_alg ) +{ + return( ecdsa_sign_det_internal( grp, r, s, d, buf, blen, md_alg, + NULL, NULL ) ); +} + +int mbedtls_ecdsa_sign_det_ext( mbedtls_ecp_group *grp, mbedtls_mpi *r, + mbedtls_mpi *s, const mbedtls_mpi *d, + const unsigned char *buf, size_t blen, + mbedtls_md_type_t md_alg, + int (*f_rng_blind)(void *, unsigned char *, + size_t), + void *p_rng_blind ) +{ + return( ecdsa_sign_det_internal( grp, r, s, d, buf, blen, md_alg, + f_rng_blind, p_rng_blind ) ); +} #endif /* MBEDTLS_ECDSA_DETERMINISTIC */ #if !defined(MBEDTLS_ECDSA_VERIFY_ALT) @@ -326,17 +383,15 @@ int mbedtls_ecdsa_write_signature( mbedtls_ecdsa_context *ctx, mbedtls_md_type_t mbedtls_mpi_init( &s ); #if defined(MBEDTLS_ECDSA_DETERMINISTIC) - (void) f_rng; - (void) p_rng; - - MBEDTLS_MPI_CHK( mbedtls_ecdsa_sign_det( &ctx->grp, &r, &s, &ctx->d, - hash, hlen, md_alg ) ); + MBEDTLS_MPI_CHK( ecdsa_sign_det_internal( &ctx->grp, &r, &s, &ctx->d, + hash, hlen, md_alg, + f_rng, p_rng ) ); #else (void) md_alg; MBEDTLS_MPI_CHK( mbedtls_ecdsa_sign( &ctx->grp, &r, &s, &ctx->d, hash, hlen, f_rng, p_rng ) ); -#endif +#endif /* MBEDTLS_ECDSA_DETERMINISTIC */ MBEDTLS_MPI_CHK( ecdsa_signature_to_asn1( &r, &s, sig, slen ) );