Skip to content

Commit a2caae2

Browse files
committed
Parse RSA CRT parameters from PKCS1 private keys
Currently they are ignored in the serialized key and then regenerated from P/Q/D. But that exposes key loading to a side channel attack on the modular inversion and GCD bignum functions when QP is computed. [And probably similar issues for DP/DQ during the division step but no attack there has been published yet.] Backport of ARMmbed/mbed-crypto#352
1 parent e860574 commit a2caae2

File tree

2 files changed

+40
-5
lines changed

2 files changed

+40
-5
lines changed

mbedtls-sys/vendor/library/pkparse.c

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -768,14 +768,40 @@ static int pk_parse_key_pkcs1_der( mbedtls_rsa_context *rsa,
768768
goto cleanup;
769769
p += len;
770770

771-
/* Complete the RSA private key */
772-
if( ( ret = mbedtls_rsa_complete( rsa ) ) != 0 )
773-
goto cleanup;
771+
#if !defined(MBEDTLS_RSA_NO_CRT)
772+
/*
773+
* The RSA CRT parameters DP, DQ and QP are nominally redundant, in
774+
* that they can be easily recomputed from D, P and Q. However by
775+
* parsing them from the PKCS1 structure it is possible to avoid
776+
* recalculating them which both reduces the overhead of loading
777+
* RSA private keys into memory and also avoids side channels which
778+
* can arise when computing those values, since all of D, P, and Q
779+
* are secret. See https://eprint.iacr.org/2020/055 for a
780+
* description of one such attack.
781+
*/
782+
783+
/* Import DP */
784+
if( ( ret = mbedtls_asn1_get_mpi( &p, end, &rsa->DP ) ) != 0)
785+
goto cleanup;
786+
787+
/* Import DQ */
788+
if( ( ret = mbedtls_asn1_get_mpi( &p, end, &rsa->DQ ) ) != 0)
789+
goto cleanup;
790+
791+
/* Import QP */
792+
if( ( ret = mbedtls_asn1_get_mpi( &p, end, &rsa->QP ) ) != 0)
793+
goto cleanup;
774794

775-
/* Check optional parameters */
795+
#else
796+
/* Verify existance of the CRT params */
776797
if( ( ret = mbedtls_asn1_get_mpi( &p, end, &T ) ) != 0 ||
777798
( ret = mbedtls_asn1_get_mpi( &p, end, &T ) ) != 0 ||
778799
( ret = mbedtls_asn1_get_mpi( &p, end, &T ) ) != 0 )
800+
goto cleanup;
801+
#endif
802+
803+
/* Complete the RSA private key */
804+
if( ( ret = mbedtls_rsa_complete( rsa ) ) != 0 )
779805
goto cleanup;
780806

781807
if( p != end )

mbedtls-sys/vendor/library/rsa.c

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,9 @@ int mbedtls_rsa_complete( mbedtls_rsa_context *ctx )
249249
{
250250
int ret = 0;
251251
int have_N, have_P, have_Q, have_D, have_E;
252+
#if !defined(MBEDTLS_RSA_NO_CRT)
253+
int have_DP, have_DQ, have_QP;
254+
#endif
252255
int n_missing, pq_missing, d_missing, is_pub, is_priv;
253256

254257
RSA_VALIDATE_RET( ctx != NULL );
@@ -259,6 +262,12 @@ int mbedtls_rsa_complete( mbedtls_rsa_context *ctx )
259262
have_D = ( mbedtls_mpi_cmp_int( &ctx->D, 0 ) != 0 );
260263
have_E = ( mbedtls_mpi_cmp_int( &ctx->E, 0 ) != 0 );
261264

265+
#if !defined(MBEDTLS_RSA_NO_CRT)
266+
have_DP = ( mbedtls_mpi_cmp_int( &ctx->DP, 0 ) != 0 );
267+
have_DQ = ( mbedtls_mpi_cmp_int( &ctx->DQ, 0 ) != 0 );
268+
have_QP = ( mbedtls_mpi_cmp_int( &ctx->QP, 0 ) != 0 );
269+
#endif
270+
262271
/*
263272
* Check whether provided parameters are enough
264273
* to deduce all others. The following incomplete
@@ -324,7 +333,7 @@ int mbedtls_rsa_complete( mbedtls_rsa_context *ctx )
324333
*/
325334

326335
#if !defined(MBEDTLS_RSA_NO_CRT)
327-
if( is_priv )
336+
if( is_priv && ! ( have_DP && have_DQ && have_QP ) )
328337
{
329338
ret = mbedtls_rsa_deduce_crt( &ctx->P, &ctx->Q, &ctx->D,
330339
&ctx->DP, &ctx->DQ, &ctx->QP );

0 commit comments

Comments
 (0)