diff --git a/include/mbedtls/ecdsa.h b/include/mbedtls/ecdsa.h
index ad5118814..6e4bc6c04 100644
--- a/include/mbedtls/ecdsa.h
+++ b/include/mbedtls/ecdsa.h
@@ -215,6 +215,51 @@ 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 5c3038048..6a5413205 100644
--- a/library/ecdsa.c
+++ b/library/ecdsa.c
@@ -254,6 +254,8 @@ static int ecdsa_sign_restartable( 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,
mbedtls_ecdsa_restart_ctx *rs_ctx )
{
int ret, key_tries, sign_tries;
@@ -323,7 +325,9 @@ static int ecdsa_sign_restartable( mbedtls_ecp_group *grp,
mul:
#endif
MBEDTLS_MPI_CHK( mbedtls_ecp_mul_restartable( grp, &R, pk, &grp->G,
- f_rng, p_rng, ECDSA_RS_ECP ) );
+ f_rng_blind,
+ p_rng_blind,
+ ECDSA_RS_ECP ) );
MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( pr, &R.X, &grp->N ) );
}
while( mbedtls_mpi_cmp_int( pr, 0 ) == 0 );
@@ -349,7 +353,8 @@ modn:
* Generate a random value to blind inv_mod in next step,
* avoiding a potential timing leak.
*/
- MBEDTLS_MPI_CHK( mbedtls_ecp_gen_privkey( grp, &t, f_rng, p_rng ) );
+ MBEDTLS_MPI_CHK( mbedtls_ecp_gen_privkey( grp, &t, f_rng_blind,
+ p_rng_blind ) );
/*
* Step 6: compute s = (e + r * d) / k = t (e + rd) / (kt) mod n
@@ -406,8 +411,9 @@ int mbedtls_ecdsa_sign( mbedtls_ecp_group *grp, mbedtls_mpi *r, mbedtls_mpi *s,
ECDSA_VALIDATE_RET( f_rng != NULL );
ECDSA_VALIDATE_RET( buf != NULL || blen == 0 );
+ /* Use the same RNG for both blinding and ephemeral key generation */
return( ecdsa_sign_restartable( grp, r, s, d, buf, blen,
- f_rng, p_rng, NULL ) );
+ f_rng, p_rng, f_rng, p_rng, NULL ) );
}
#endif /* !MBEDTLS_ECDSA_SIGN_ALT */
@@ -419,6 +425,8 @@ static int ecdsa_sign_det_restartable( 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,
mbedtls_ecdsa_restart_ctx *rs_ctx )
{
int ret;
@@ -465,8 +473,22 @@ sign:
ret = mbedtls_ecdsa_sign( grp, r, s, d, buf, blen,
mbedtls_hmac_drbg_random, p_rng );
#else
- ret = ecdsa_sign_restartable( grp, r, s, d, buf, blen,
- mbedtls_hmac_drbg_random, p_rng, rs_ctx );
+ if( f_rng_blind != NULL )
+ ret = ecdsa_sign_restartable( grp, r, s, d, buf, blen,
+ mbedtls_hmac_drbg_random, p_rng,
+ f_rng_blind, p_rng_blind, rs_ctx );
+ 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. 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_restartable( grp, r, s, d, buf, blen,
+ mbedtls_hmac_drbg_random, p_rng,
+ mbedtls_hmac_drbg_random, p_rng, rs_ctx );
#endif /* MBEDTLS_ECDSA_SIGN_ALT */
cleanup:
@@ -479,11 +501,12 @@ cleanup:
}
/*
- * Deterministic signature wrapper
+ * 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 )
+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 )
{
ECDSA_VALIDATE_RET( grp != NULL );
ECDSA_VALIDATE_RET( r != NULL );
@@ -491,7 +514,27 @@ int mbedtls_ecdsa_sign_det( mbedtls_ecp_group *grp, mbedtls_mpi *r, mbedtls_mpi
ECDSA_VALIDATE_RET( d != NULL );
ECDSA_VALIDATE_RET( buf != NULL || blen == 0 );
- return( ecdsa_sign_det_restartable( grp, r, s, d, buf, blen, md_alg, NULL ) );
+ return( ecdsa_sign_det_restartable( grp, r, s, d, buf, blen, md_alg,
+ NULL, 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 )
+{
+ ECDSA_VALIDATE_RET( grp != NULL );
+ ECDSA_VALIDATE_RET( r != NULL );
+ ECDSA_VALIDATE_RET( s != NULL );
+ ECDSA_VALIDATE_RET( d != NULL );
+ ECDSA_VALIDATE_RET( buf != NULL || blen == 0 );
+ ECDSA_VALIDATE_RET( f_rng_blind != NULL );
+
+ return( ecdsa_sign_det_restartable( grp, r, s, d, buf, blen, md_alg,
+ f_rng_blind, p_rng_blind, NULL ) );
}
#endif /* MBEDTLS_ECDSA_DETERMINISTIC */
@@ -670,11 +713,9 @@ int mbedtls_ecdsa_write_signature_restartable( mbedtls_ecdsa_context *ctx,
mbedtls_mpi_init( &s );
#if defined(MBEDTLS_ECDSA_DETERMINISTIC)
- (void) f_rng;
- (void) p_rng;
-
MBEDTLS_MPI_CHK( ecdsa_sign_det_restartable( &ctx->grp, &r, &s, &ctx->d,
- hash, hlen, md_alg, rs_ctx ) );
+ hash, hlen, md_alg, f_rng,
+ p_rng, rs_ctx ) );
#else
(void) md_alg;
@@ -682,8 +723,10 @@ int mbedtls_ecdsa_write_signature_restartable( mbedtls_ecdsa_context *ctx,
MBEDTLS_MPI_CHK( mbedtls_ecdsa_sign( &ctx->grp, &r, &s, &ctx->d,
hash, hlen, f_rng, p_rng ) );
#else
+ /* Use the same RNG for both blinding and ephemeral key generation */
MBEDTLS_MPI_CHK( ecdsa_sign_restartable( &ctx->grp, &r, &s, &ctx->d,
- hash, hlen, f_rng, p_rng, rs_ctx ) );
+ hash, hlen, f_rng, p_rng, f_rng,
+ p_rng, rs_ctx ) );
#endif /* MBEDTLS_ECDSA_SIGN_ALT */
#endif /* MBEDTLS_ECDSA_DETERMINISTIC */