Skip to content

Commit c7cde03

Browse files
authored
Merge pull request #276 from dgreen-arm/dev/dgreen-arm/iotcrypt-616-fix-ecdsa-rng
Fix deterministic ECDSA RNG misuse
2 parents c04305f + 5e843fa commit c7cde03

File tree

5 files changed

+221
-40
lines changed

5 files changed

+221
-40
lines changed

include/mbedtls/config.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -441,6 +441,16 @@
441441
* dependencies on them, and considering stronger message digests
442442
* and ciphers instead.
443443
*
444+
* \warning If both MBEDTLS_ECDSA_SIGN_ALT and MBEDTLS_ECDSA_DETERMINISTIC are
445+
* enabled, then the deterministic ECDH signature functions pass the
446+
* the static HMAC-DRBG as RNG to mbedtls_ecdsa_sign(). Therefore
447+
* alternative implementations should use the RNG only for generating
448+
* the ephemeral key and nothing else. If this is not possible, then
449+
* MBEDTLS_ECDSA_DETERMINISTIC should be disabled and an alternative
450+
* implementation should be provided for mbedtls_ecdsa_sign_det_ext()
451+
* (and for mbedtls_ecdsa_sign_det() too if backward compatibility is
452+
* desirable).
453+
*
444454
*/
445455
//#define MBEDTLS_MD2_PROCESS_ALT
446456
//#define MBEDTLS_MD4_PROCESS_ALT

include/mbedtls/ecdsa.h

Lines changed: 70 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,12 @@ int mbedtls_ecdsa_sign( mbedtls_ecp_group *grp, mbedtls_mpi *r, mbedtls_mpi *s,
176176
int (*f_rng)(void *, unsigned char *, size_t), void *p_rng );
177177

178178
#if defined(MBEDTLS_ECDSA_DETERMINISTIC)
179+
#if ! defined(MBEDTLS_DEPRECATED_REMOVED)
180+
#if defined(MBEDTLS_DEPRECATED_WARNING)
181+
#define MBEDTLS_DEPRECATED __attribute__((deprecated))
182+
#else
183+
#define MBEDTLS_DEPRECATED
184+
#endif
179185
/**
180186
* \brief This function computes the ECDSA signature of a
181187
* previously-hashed message, deterministic version.
@@ -190,6 +196,19 @@ int mbedtls_ecdsa_sign( mbedtls_ecp_group *grp, mbedtls_mpi *r, mbedtls_mpi *s,
190196
* (SECG): SEC1 Elliptic Curve Cryptography</em>, section
191197
* 4.1.3, step 5.
192198
*
199+
* \warning Since the output of the internal RNG is always the same for
200+
* the same key and message, this limits the efficiency of
201+
* blinding and leaks information through side channels. For
202+
* secure behavior use mbedtls_ecdsa_sign_det_ext() instead.
203+
*
204+
* (Optimally the blinding is a random value that is different
205+
* on every execution. In this case the blinding is still
206+
* random from the attackers perspective, but is the same on
207+
* each execution. This means that this blinding does not
208+
* prevent attackers from recovering secrets by combining
209+
* several measurement traces, but may prevent some attacks
210+
* that exploit relationships between secret data.)
211+
*
193212
* \see ecp.h
194213
*
195214
* \param grp The context for the elliptic curve to use.
@@ -214,7 +233,55 @@ int mbedtls_ecdsa_sign( mbedtls_ecp_group *grp, mbedtls_mpi *r, mbedtls_mpi *s,
214233
int mbedtls_ecdsa_sign_det( mbedtls_ecp_group *grp, mbedtls_mpi *r,
215234
mbedtls_mpi *s, const mbedtls_mpi *d,
216235
const unsigned char *buf, size_t blen,
217-
mbedtls_md_type_t md_alg );
236+
mbedtls_md_type_t md_alg ) MBEDTLS_DEPRECATED;
237+
#undef MBEDTLS_DEPRECATED
238+
#endif /* MBEDTLS_DEPRECATED_REMOVED */
239+
240+
/**
241+
* \brief This function computes the ECDSA signature of a
242+
* previously-hashed message, deterministic version.
243+
*
244+
* For more information, see <em>RFC-6979: Deterministic
245+
* Usage of the Digital Signature Algorithm (DSA) and Elliptic
246+
* Curve Digital Signature Algorithm (ECDSA)</em>.
247+
*
248+
* \note If the bitlength of the message hash is larger than the
249+
* bitlength of the group order, then the hash is truncated as
250+
* defined in <em>Standards for Efficient Cryptography Group
251+
* (SECG): SEC1 Elliptic Curve Cryptography</em>, section
252+
* 4.1.3, step 5.
253+
*
254+
* \see ecp.h
255+
*
256+
* \param grp The context for the elliptic curve to use.
257+
* This must be initialized and have group parameters
258+
* set, for example through mbedtls_ecp_group_load().
259+
* \param r The MPI context in which to store the first part
260+
* the signature. This must be initialized.
261+
* \param s The MPI context in which to store the second part
262+
* the signature. This must be initialized.
263+
* \param d The private signing key. This must be initialized
264+
* and setup, for example through mbedtls_ecp_gen_privkey().
265+
* \param buf The hashed content to be signed. This must be a readable
266+
* buffer of length \p blen Bytes. It may be \c NULL if
267+
* \p blen is zero.
268+
* \param blen The length of \p buf in Bytes.
269+
* \param md_alg The hash algorithm used to hash the original data.
270+
* \param f_rng_blind The RNG function used for blinding. This must not be
271+
* \c NULL.
272+
* \param p_rng_blind The RNG context to be passed to \p f_rng. This may be
273+
* \c NULL if \p f_rng doesn't need a context parameter.
274+
*
275+
* \return \c 0 on success.
276+
* \return An \c MBEDTLS_ERR_ECP_XXX or \c MBEDTLS_MPI_XXX
277+
* error code on failure.
278+
*/
279+
int mbedtls_ecdsa_sign_det_ext( mbedtls_ecp_group *grp, mbedtls_mpi *r,
280+
mbedtls_mpi *s, const mbedtls_mpi *d,
281+
const unsigned char *buf, size_t blen,
282+
mbedtls_md_type_t md_alg,
283+
int (*f_rng_blind)(void *, unsigned char *, size_t),
284+
void *p_rng_blind );
218285
#endif /* MBEDTLS_ECDSA_DETERMINISTIC */
219286

220287
/**
@@ -293,7 +360,8 @@ int mbedtls_ecdsa_verify( mbedtls_ecp_group *grp,
293360
* the signature written. Must not be \c NULL.
294361
* \param f_rng The RNG function. This must not be \c NULL if
295362
* #MBEDTLS_ECDSA_DETERMINISTIC is unset. Otherwise,
296-
* it is unused and may be set to \c NULL.
363+
* it is used only for blinding and may be set to \c NULL, but
364+
* doing so is DEPRECATED.
297365
* \param p_rng The RNG context to be passed to \p f_rng. This may be
298366
* \c NULL if \p f_rng is \c NULL or doesn't use a context.
299367
*

library/ecdsa.c

Lines changed: 108 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,8 @@ static int ecdsa_sign_restartable( mbedtls_ecp_group *grp,
254254
mbedtls_mpi *r, mbedtls_mpi *s,
255255
const mbedtls_mpi *d, const unsigned char *buf, size_t blen,
256256
int (*f_rng)(void *, unsigned char *, size_t), void *p_rng,
257+
int (*f_rng_blind)(void *, unsigned char *, size_t),
258+
void *p_rng_blind,
257259
mbedtls_ecdsa_restart_ctx *rs_ctx )
258260
{
259261
int ret, key_tries, sign_tries;
@@ -323,7 +325,9 @@ static int ecdsa_sign_restartable( mbedtls_ecp_group *grp,
323325
mul:
324326
#endif
325327
MBEDTLS_MPI_CHK( mbedtls_ecp_mul_restartable( grp, &R, pk, &grp->G,
326-
f_rng, p_rng, ECDSA_RS_ECP ) );
328+
f_rng_blind,
329+
p_rng_blind,
330+
ECDSA_RS_ECP ) );
327331
MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( pr, &R.X, &grp->N ) );
328332
}
329333
while( mbedtls_mpi_cmp_int( pr, 0 ) == 0 );
@@ -349,7 +353,8 @@ static int ecdsa_sign_restartable( mbedtls_ecp_group *grp,
349353
* Generate a random value to blind inv_mod in next step,
350354
* avoiding a potential timing leak.
351355
*/
352-
MBEDTLS_MPI_CHK( mbedtls_ecp_gen_privkey( grp, &t, f_rng, p_rng ) );
356+
MBEDTLS_MPI_CHK( mbedtls_ecp_gen_privkey( grp, &t, f_rng_blind,
357+
p_rng_blind ) );
353358

354359
/*
355360
* 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,
406411
ECDSA_VALIDATE_RET( f_rng != NULL );
407412
ECDSA_VALIDATE_RET( buf != NULL || blen == 0 );
408413

414+
/* Use the same RNG for both blinding and ephemeral key generation */
409415
return( ecdsa_sign_restartable( grp, r, s, d, buf, blen,
410-
f_rng, p_rng, NULL ) );
416+
f_rng, p_rng, f_rng, p_rng, NULL ) );
411417
}
412418
#endif /* !MBEDTLS_ECDSA_SIGN_ALT */
413419

@@ -419,6 +425,8 @@ static int ecdsa_sign_det_restartable( mbedtls_ecp_group *grp,
419425
mbedtls_mpi *r, mbedtls_mpi *s,
420426
const mbedtls_mpi *d, const unsigned char *buf, size_t blen,
421427
mbedtls_md_type_t md_alg,
428+
int (*f_rng_blind)(void *, unsigned char *, size_t),
429+
void *p_rng_blind,
422430
mbedtls_ecdsa_restart_ctx *rs_ctx )
423431
{
424432
int ret;
@@ -465,8 +473,69 @@ static int ecdsa_sign_det_restartable( mbedtls_ecp_group *grp,
465473
ret = mbedtls_ecdsa_sign( grp, r, s, d, buf, blen,
466474
mbedtls_hmac_drbg_random, p_rng );
467475
#else
468-
ret = ecdsa_sign_restartable( grp, r, s, d, buf, blen,
469-
mbedtls_hmac_drbg_random, p_rng, rs_ctx );
476+
if( f_rng_blind != NULL )
477+
ret = ecdsa_sign_restartable( grp, r, s, d, buf, blen,
478+
mbedtls_hmac_drbg_random, p_rng,
479+
f_rng_blind, p_rng_blind, rs_ctx );
480+
else
481+
{
482+
mbedtls_hmac_drbg_context *p_rng_blind_det;
483+
484+
#if !defined(MBEDTLS_ECP_RESTARTABLE)
485+
/*
486+
* To avoid reusing rng_ctx and risking incorrect behavior we seed a
487+
* second HMAC-DRBG with the same seed. We also apply a label to avoid
488+
* reusing the bits of the ephemeral key for blinding and eliminate the
489+
* risk that they leak this way.
490+
*/
491+
const char* blind_label = "BLINDING CONTEXT";
492+
mbedtls_hmac_drbg_context rng_ctx_blind;
493+
494+
mbedtls_hmac_drbg_init( &rng_ctx_blind );
495+
p_rng_blind_det = &rng_ctx_blind;
496+
mbedtls_hmac_drbg_seed_buf( p_rng_blind_det, md_info,
497+
data, 2 * grp_len );
498+
ret = mbedtls_hmac_drbg_update_ret( p_rng_blind_det,
499+
(const unsigned char*) blind_label,
500+
strlen( blind_label ) );
501+
if( ret != 0 )
502+
{
503+
mbedtls_hmac_drbg_free( &rng_ctx_blind );
504+
goto cleanup;
505+
}
506+
#else
507+
/*
508+
* In the case of restartable computations we would either need to store
509+
* the second RNG in the restart context too or set it up at every
510+
* restart. The first option would penalize the correct application of
511+
* the function and the second would defeat the purpose of the
512+
* restartable feature.
513+
*
514+
* Therefore in this case we reuse the original RNG. This comes with the
515+
* price that the resulting signature might not be a valid deterministic
516+
* ECDSA signature with a very low probability (same magnitude as
517+
* successfully guessing the private key). However even then it is still
518+
* a valid ECDSA signature.
519+
*/
520+
p_rng_blind_det = p_rng;
521+
#endif /* MBEDTLS_ECP_RESTARTABLE */
522+
523+
/*
524+
* Since the output of the RNGs is always the same for the same key and
525+
* message, this limits the efficiency of blinding and leaks information
526+
* through side channels. After mbedtls_ecdsa_sign_det() is removed NULL
527+
* won't be a valid value for f_rng_blind anymore. Therefore it should
528+
* be checked by the caller and this branch and check can be removed.
529+
*/
530+
ret = ecdsa_sign_restartable( grp, r, s, d, buf, blen,
531+
mbedtls_hmac_drbg_random, p_rng,
532+
mbedtls_hmac_drbg_random, p_rng_blind_det,
533+
rs_ctx );
534+
535+
#if !defined(MBEDTLS_ECP_RESTARTABLE)
536+
mbedtls_hmac_drbg_free( &rng_ctx_blind );
537+
#endif
538+
}
470539
#endif /* MBEDTLS_ECDSA_SIGN_ALT */
471540

472541
cleanup:
@@ -479,19 +548,43 @@ static int ecdsa_sign_det_restartable( mbedtls_ecp_group *grp,
479548
}
480549

481550
/*
482-
* Deterministic signature wrapper
551+
* Deterministic signature wrappers
483552
*/
484-
int mbedtls_ecdsa_sign_det( mbedtls_ecp_group *grp, mbedtls_mpi *r, mbedtls_mpi *s,
485-
const mbedtls_mpi *d, const unsigned char *buf, size_t blen,
486-
mbedtls_md_type_t md_alg )
553+
554+
#if !defined(MBEDTLS_DEPRECATED_REMOVED)
555+
int mbedtls_ecdsa_sign_det( mbedtls_ecp_group *grp, mbedtls_mpi *r,
556+
mbedtls_mpi *s, const mbedtls_mpi *d,
557+
const unsigned char *buf, size_t blen,
558+
mbedtls_md_type_t md_alg )
559+
{
560+
ECDSA_VALIDATE_RET( grp != NULL );
561+
ECDSA_VALIDATE_RET( r != NULL );
562+
ECDSA_VALIDATE_RET( s != NULL );
563+
ECDSA_VALIDATE_RET( d != NULL );
564+
ECDSA_VALIDATE_RET( buf != NULL || blen == 0 );
565+
566+
return( ecdsa_sign_det_restartable( grp, r, s, d, buf, blen, md_alg,
567+
NULL, NULL, NULL ) );
568+
}
569+
#endif /* MBEDTLS_DEPRECATED_REMOVED */
570+
571+
int mbedtls_ecdsa_sign_det_ext( mbedtls_ecp_group *grp, mbedtls_mpi *r,
572+
mbedtls_mpi *s, const mbedtls_mpi *d,
573+
const unsigned char *buf, size_t blen,
574+
mbedtls_md_type_t md_alg,
575+
int (*f_rng_blind)(void *, unsigned char *,
576+
size_t),
577+
void *p_rng_blind )
487578
{
488579
ECDSA_VALIDATE_RET( grp != NULL );
489580
ECDSA_VALIDATE_RET( r != NULL );
490581
ECDSA_VALIDATE_RET( s != NULL );
491582
ECDSA_VALIDATE_RET( d != NULL );
492583
ECDSA_VALIDATE_RET( buf != NULL || blen == 0 );
584+
ECDSA_VALIDATE_RET( f_rng_blind != NULL );
493585

494-
return( ecdsa_sign_det_restartable( grp, r, s, d, buf, blen, md_alg, NULL ) );
586+
return( ecdsa_sign_det_restartable( grp, r, s, d, buf, blen, md_alg,
587+
f_rng_blind, p_rng_blind, NULL ) );
495588
}
496589
#endif /* MBEDTLS_ECDSA_DETERMINISTIC */
497590

@@ -670,20 +763,20 @@ int mbedtls_ecdsa_write_signature_restartable( mbedtls_ecdsa_context *ctx,
670763
mbedtls_mpi_init( &s );
671764

672765
#if defined(MBEDTLS_ECDSA_DETERMINISTIC)
673-
(void) f_rng;
674-
(void) p_rng;
675-
676766
MBEDTLS_MPI_CHK( ecdsa_sign_det_restartable( &ctx->grp, &r, &s, &ctx->d,
677-
hash, hlen, md_alg, rs_ctx ) );
767+
hash, hlen, md_alg, f_rng,
768+
p_rng, rs_ctx ) );
678769
#else
679770
(void) md_alg;
680771

681772
#if defined(MBEDTLS_ECDSA_SIGN_ALT)
682773
MBEDTLS_MPI_CHK( mbedtls_ecdsa_sign( &ctx->grp, &r, &s, &ctx->d,
683774
hash, hlen, f_rng, p_rng ) );
684775
#else
776+
/* Use the same RNG for both blinding and ephemeral key generation */
685777
MBEDTLS_MPI_CHK( ecdsa_sign_restartable( &ctx->grp, &r, &s, &ctx->d,
686-
hash, hlen, f_rng, p_rng, rs_ctx ) );
778+
hash, hlen, f_rng, p_rng, f_rng,
779+
p_rng, rs_ctx ) );
687780
#endif /* MBEDTLS_ECDSA_SIGN_ALT */
688781
#endif /* MBEDTLS_ECDSA_DETERMINISTIC */
689782

library/psa_crypto.c

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3271,9 +3271,11 @@ static psa_status_t psa_ecdsa_sign( mbedtls_ecp_keypair *ecp,
32713271
psa_algorithm_t hash_alg = PSA_ALG_SIGN_GET_HASH( alg );
32723272
const mbedtls_md_info_t *md_info = mbedtls_md_info_from_psa( hash_alg );
32733273
mbedtls_md_type_t md_alg = mbedtls_md_get_type( md_info );
3274-
MBEDTLS_MPI_CHK( mbedtls_ecdsa_sign_det( &ecp->grp, &r, &s, &ecp->d,
3275-
hash, hash_length,
3276-
md_alg ) );
3274+
MBEDTLS_MPI_CHK( mbedtls_ecdsa_sign_det_ext( &ecp->grp, &r, &s,
3275+
&ecp->d, hash,
3276+
hash_length, md_alg,
3277+
mbedtls_ctr_drbg_random,
3278+
&global_data.ctr_drbg ) );
32773279
}
32783280
else
32793281
#endif /* MBEDTLS_ECDSA_DETERMINISTIC */

tests/suites/test_suite_ecdsa.function

Lines changed: 28 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -55,25 +55,30 @@ void ecdsa_invalid_param( )
5555

5656
#if defined(MBEDTLS_ECDSA_DETERMINISTIC)
5757
TEST_INVALID_PARAM_RET( MBEDTLS_ERR_ECP_BAD_INPUT_DATA,
58-
mbedtls_ecdsa_sign_det( NULL, &m, &m, &m,
59-
buf, sizeof( buf ),
60-
valid_md ) );
61-
TEST_INVALID_PARAM_RET( MBEDTLS_ERR_ECP_BAD_INPUT_DATA,
62-
mbedtls_ecdsa_sign_det( &grp, NULL, &m, &m,
63-
buf, sizeof( buf ),
64-
valid_md ) );
65-
TEST_INVALID_PARAM_RET( MBEDTLS_ERR_ECP_BAD_INPUT_DATA,
66-
mbedtls_ecdsa_sign_det( &grp, &m, NULL, &m,
67-
buf, sizeof( buf ),
68-
valid_md ) );
69-
TEST_INVALID_PARAM_RET( MBEDTLS_ERR_ECP_BAD_INPUT_DATA,
70-
mbedtls_ecdsa_sign_det( &grp, &m, &m, NULL,
71-
buf, sizeof( buf ),
72-
valid_md ) );
73-
TEST_INVALID_PARAM_RET( MBEDTLS_ERR_ECP_BAD_INPUT_DATA,
74-
mbedtls_ecdsa_sign_det( &grp, &m, &m, &m,
75-
NULL, sizeof( buf ),
76-
valid_md ) );
58+
mbedtls_ecdsa_sign_det_ext( NULL, &m, &m, &m,
59+
buf, sizeof( buf ),
60+
valid_md,
61+
rnd_std_rand, NULL ) );
62+
TEST_INVALID_PARAM_RET( MBEDTLS_ERR_ECP_BAD_INPUT_DATA,
63+
mbedtls_ecdsa_sign_det_ext( &grp, NULL, &m, &m,
64+
buf, sizeof( buf ),
65+
valid_md,
66+
rnd_std_rand, NULL ) );
67+
TEST_INVALID_PARAM_RET( MBEDTLS_ERR_ECP_BAD_INPUT_DATA,
68+
mbedtls_ecdsa_sign_det_ext( &grp, &m, NULL, &m,
69+
buf, sizeof( buf ),
70+
valid_md,
71+
rnd_std_rand, NULL ) );
72+
TEST_INVALID_PARAM_RET( MBEDTLS_ERR_ECP_BAD_INPUT_DATA,
73+
mbedtls_ecdsa_sign_det_ext( &grp, &m, &m, NULL,
74+
buf, sizeof( buf ),
75+
valid_md,
76+
rnd_std_rand, NULL ) );
77+
TEST_INVALID_PARAM_RET( MBEDTLS_ERR_ECP_BAD_INPUT_DATA,
78+
mbedtls_ecdsa_sign_det_ext( &grp, &m, &m, &m,
79+
NULL, sizeof( buf ),
80+
valid_md,
81+
rnd_std_rand, NULL ) );
7782
#endif /* MBEDTLS_ECDSA_DETERMINISTIC */
7883

7984
TEST_INVALID_PARAM_RET( MBEDTLS_ERR_ECP_BAD_INPUT_DATA,
@@ -325,7 +330,10 @@ void ecdsa_det_test_vectors( int id, char * d_str, int md_alg, char * msg,
325330
TEST_ASSERT( mbedtls_md( md_info, (const unsigned char *) msg,
326331
strlen( msg ), hash ) == 0 );
327332

328-
TEST_ASSERT( mbedtls_ecdsa_sign_det( &grp, &r, &s, &d, hash, hlen, md_alg ) == 0 );
333+
TEST_ASSERT(
334+
mbedtls_ecdsa_sign_det_ext( &grp, &r, &s, &d, hash, hlen,
335+
md_alg, rnd_std_rand, NULL )
336+
== 0 );
329337

330338
TEST_ASSERT( mbedtls_mpi_cmp_mpi( &r, &r_check ) == 0 );
331339
TEST_ASSERT( mbedtls_mpi_cmp_mpi( &s, &s_check ) == 0 );

0 commit comments

Comments
 (0)