From a5fa07958eff9657bcf7cead98f7244264707b38 Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Fri, 9 Mar 2018 10:42:23 +0000 Subject: [PATCH 1/6] Verify the result of RSA private key operations If RSA-CRT is used for signing, and if an attacker can cause a glitch in one of the two computations modulo P or Q, the difference between the faulty and the correct signature (which is not secret) will be divisible by P or Q, but not by both, allowing to recover the private key by taking the GCD with the public RSA modulus N. This is known as the Bellcore Glitch Attack. Verifying the RSA signature before handing it out is a countermeasure against it. --- library/rsa.c | 124 +++++++++++++++++++++++++++++++++++++------------- 1 file changed, 93 insertions(+), 31 deletions(-) diff --git a/library/rsa.c b/library/rsa.c index 6526978e2..c9f7ba91b 100644 --- a/library/rsa.c +++ b/library/rsa.c @@ -773,16 +773,38 @@ int mbedtls_rsa_private( mbedtls_rsa_context *ctx, { int ret; size_t olen; - mbedtls_mpi T, T1, T2; + + /* Temporary holding the result */ + mbedtls_mpi T; + + /* Temporaries holding P-1, Q-1 and the + * exponent blinding factor, respectively. */ mbedtls_mpi P1, Q1, R; -#if defined(MBEDTLS_RSA_NO_CRT) - mbedtls_mpi D_blind; - mbedtls_mpi *D = &ctx->D; -#else + +#if !defined(MBEDTLS_RSA_NO_CRT) + /* Temporaries holding the results mod p resp. mod q. */ + mbedtls_mpi TP, TQ; + + /* Temporaries holding the blinded exponents for + * the mod p resp. mod q computation (if used). */ mbedtls_mpi DP_blind, DQ_blind; + + /* Pointers to actual exponents to be used - either the unblinded + * or the blinded ones, depending on the presence of a PRNG. */ mbedtls_mpi *DP = &ctx->DP; mbedtls_mpi *DQ = &ctx->DQ; -#endif +#else + /* Temporary holding the blinded exponent (if used). */ + mbedtls_mpi D_blind; + + /* Pointer to actual exponent to be used - either the unblinded + * or the blinded one, depending on the presence of a PRNG. */ + mbedtls_mpi *D = &ctx->D; +#endif /* MBEDTLS_RSA_NO_CRT */ + + /* Temporaries holding the initial input and the double + * checked result; should be the same in the end. */ + mbedtls_mpi I, C; if( rsa_check_context( ctx, 1 /* private key checks */, f_rng != NULL /* blinding y/n */ ) != 0 ) @@ -790,8 +812,17 @@ int mbedtls_rsa_private( mbedtls_rsa_context *ctx, return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); } - mbedtls_mpi_init( &T ); mbedtls_mpi_init( &T1 ); mbedtls_mpi_init( &T2 ); - mbedtls_mpi_init( &P1 ); mbedtls_mpi_init( &Q1 ); mbedtls_mpi_init( &R ); +#if defined(MBEDTLS_THREADING_C) + if( ( ret = mbedtls_mutex_lock( &ctx->mutex ) ) != 0 ) + return( ret ); +#endif + + /* MPI Initialization */ + mbedtls_mpi_init( &T ); + + mbedtls_mpi_init( &P1 ); + mbedtls_mpi_init( &Q1 ); + mbedtls_mpi_init( &R ); if( f_rng != NULL ) { @@ -803,12 +834,15 @@ int mbedtls_rsa_private( mbedtls_rsa_context *ctx, #endif } - -#if defined(MBEDTLS_THREADING_C) - if( ( ret = mbedtls_mutex_lock( &ctx->mutex ) ) != 0 ) - return( ret ); +#if !defined(MBEDTLS_RSA_NO_CRT) + mbedtls_mpi_init( &TP ); mbedtls_mpi_init( &TQ ); #endif + mbedtls_mpi_init( &I ); + mbedtls_mpi_init( &C ); + + /* End of MPI initialization */ + MBEDTLS_MPI_CHK( mbedtls_mpi_read_binary( &T, input, ctx->len ) ); if( mbedtls_mpi_cmp_mpi( &T, &ctx->N ) >= 0 ) { @@ -816,6 +850,8 @@ int mbedtls_rsa_private( mbedtls_rsa_context *ctx, goto cleanup; } + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &I, &T ) ); + if( f_rng != NULL ) { /* @@ -874,24 +910,25 @@ int mbedtls_rsa_private( mbedtls_rsa_context *ctx, /* * Faster decryption using the CRT * - * T1 = input ^ dP mod P - * T2 = input ^ dQ mod Q + * TP = input ^ dP mod P + * TQ = input ^ dQ mod Q */ - MBEDTLS_MPI_CHK( mbedtls_mpi_exp_mod( &T1, &T, DP, &ctx->P, &ctx->RP ) ); - MBEDTLS_MPI_CHK( mbedtls_mpi_exp_mod( &T2, &T, DQ, &ctx->Q, &ctx->RQ ) ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_exp_mod( &TP, &T, DP, &ctx->P, &ctx->RP ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_exp_mod( &TQ, &T, DQ, &ctx->Q, &ctx->RQ ) ); /* - * T = (T1 - T2) * (Q^-1 mod P) mod P + * T = (TP - TQ) * (Q^-1 mod P) mod P */ - MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &T, &T1, &T2 ) ); - MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &T1, &T, &ctx->QP ) ); - MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &T, &T1, &ctx->P ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &T, &TP, &TQ ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &TP, &T, &ctx->QP ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &T, &TP, &ctx->P ) ); /* - * T = T2 + T * Q + * T = TQ + T * Q */ - MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &T1, &T, &ctx->Q ) ); - MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &T, &T2, &T1 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &TP, &T, &ctx->Q ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &T, &TQ, &TP ) ); #endif /* MBEDTLS_RSA_NO_CRT */ if( f_rng != NULL ) @@ -904,6 +941,15 @@ int mbedtls_rsa_private( mbedtls_rsa_context *ctx, MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &T, &T, &ctx->N ) ); } + /* Verify the result to prevent glitching attacks. */ + MBEDTLS_MPI_CHK( mbedtls_mpi_exp_mod( &C, &T, &ctx->E, + &ctx->N, &ctx->RN ) ); + if( mbedtls_mpi_cmp_mpi( &C, &I ) != 0 ) + { + ret = MBEDTLS_ERR_RSA_VERIFY_FAILED; + goto cleanup; + } + olen = ctx->len; MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( &T, output, olen ) ); @@ -913,8 +959,9 @@ cleanup: return( MBEDTLS_ERR_THREADING_MUTEX_ERROR ); #endif - mbedtls_mpi_free( &T ); mbedtls_mpi_free( &T1 ); mbedtls_mpi_free( &T2 ); - mbedtls_mpi_free( &P1 ); mbedtls_mpi_free( &Q1 ); mbedtls_mpi_free( &R ); + mbedtls_mpi_free( &P1 ); + mbedtls_mpi_free( &Q1 ); + mbedtls_mpi_free( &R ); if( f_rng != NULL ) { @@ -926,6 +973,15 @@ cleanup: #endif } + mbedtls_mpi_free( &T ); + +#if !defined(MBEDTLS_RSA_NO_CRT) + mbedtls_mpi_free( &TP ); mbedtls_mpi_free( &TQ ); +#endif + + mbedtls_mpi_free( &C ); + mbedtls_mpi_free( &I ); + if( ret != 0 ) return( MBEDTLS_ERR_RSA_PRIVATE_FAILED + ret ); @@ -2222,7 +2278,8 @@ int mbedtls_rsa_self_test( int verbose ) if( verbose != 0 ) mbedtls_printf( "failed\n" ); - return( 1 ); + ret = 1; + goto cleanup; } if( verbose != 0 ) @@ -2237,7 +2294,8 @@ int mbedtls_rsa_self_test( int verbose ) if( verbose != 0 ) mbedtls_printf( "failed\n" ); - return( 1 ); + ret = 1; + goto cleanup; } if( verbose != 0 ) @@ -2250,7 +2308,8 @@ int mbedtls_rsa_self_test( int verbose ) if( verbose != 0 ) mbedtls_printf( "failed\n" ); - return( 1 ); + ret = 1; + goto cleanup; } if( memcmp( rsa_decrypted, rsa_plaintext, len ) != 0 ) @@ -2258,7 +2317,8 @@ int mbedtls_rsa_self_test( int verbose ) if( verbose != 0 ) mbedtls_printf( "failed\n" ); - return( 1 ); + ret = 1; + goto cleanup; } if( verbose != 0 ) @@ -2283,7 +2343,8 @@ int mbedtls_rsa_self_test( int verbose ) if( verbose != 0 ) mbedtls_printf( "failed\n" ); - return( 1 ); + ret = 1; + goto cleanup; } if( verbose != 0 ) @@ -2296,7 +2357,8 @@ int mbedtls_rsa_self_test( int verbose ) if( verbose != 0 ) mbedtls_printf( "failed\n" ); - return( 1 ); + ret = 1; + goto cleanup; } if( verbose != 0 ) From 69d45cce5d643edbac11469818c5840762263a4f Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Fri, 9 Mar 2018 10:46:23 +0000 Subject: [PATCH 2/6] Add a run with RSA_NO_CRT to all.sh --- tests/scripts/all.sh | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/tests/scripts/all.sh b/tests/scripts/all.sh index d5fc12d0a..e60530fd7 100755 --- a/tests/scripts/all.sh +++ b/tests/scripts/all.sh @@ -530,6 +530,22 @@ make test msg "test: !MBEDTLS_SSL_RENEGOTIATION - ssl-opt.sh (ASan build)" # ~ 6 min if_build_succeeded tests/ssl-opt.sh +msg "build: Default + RSA_NO_CRT (ASan build)" # ~ 6 min +cleanup +cp "$CONFIG_H" "$CONFIG_BAK" +scripts/config.pl set MBEDTLS_RSA_NO_CRT +CC=gcc cmake -D CMAKE_BUILD_TYPE:String=Asan . +make + +msg "test: RSA_NO_CRT - main suites (inc. selftests) (ASan build)" # ~ 50s +make test + +msg "test: RSA_NO_CRT - RSA-related part of ssl-opt.sh (ASan build)" # ~ 5s +tests/ssl-opt.sh -f RSA + +msg "test: RSA_NO_CRT - RSA-related part of compat.sh (ASan build)" # ~ 3 min +tests/compat.sh -t RSA + msg "build: cmake, full config, clang, C99" # ~ 50s cleanup cp "$CONFIG_H" "$CONFIG_BAK" From 70e66395b53a7bacc01128766209c3b52763fcb6 Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Fri, 9 Mar 2018 10:46:43 +0000 Subject: [PATCH 3/6] Adapt ChangeLog --- ChangeLog | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ChangeLog b/ChangeLog index 51ad7273e..998a56704 100644 --- a/ChangeLog +++ b/ChangeLog @@ -13,6 +13,8 @@ Default behavior changes Applied Sciences). Security + * Verify results of RSA private key operations to defend + against Bellcore glitch attack. * Fix implementation of the truncated HMAC extension. The previous implementation allowed an offline 2^80 brute force attack on the HMAC key of a single, uninterrupted connection (with no From e856e84de3990ea3f6da009b05cbf0270e80724d Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Fri, 9 Mar 2018 10:47:01 +0000 Subject: [PATCH 4/6] Don't enable RSA_NO_CRT in `config.pl full` --- scripts/config.pl | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/scripts/config.pl b/scripts/config.pl index 76ca4709c..5bf27859a 100755 --- a/scripts/config.pl +++ b/scripts/config.pl @@ -17,7 +17,7 @@ # # Full usage description provided below. # -# Things that shouldn't be enabled with "full". +# The following options are disabled instead of enabled with "full". # # MBEDTLS_TEST_NULL_ENTROPY # MBEDTLS_DEPRECATED_REMOVED @@ -30,6 +30,7 @@ # MBEDTLS_NO_PLATFORM_ENTROPY # MBEDTLS_REMOVE_ARC4_CIPHERSUITES # MBEDTLS_SSL_HW_RECORD_ACCEL +# MBEDTLS_RSA_NO_CRT # MBEDTLS_X509_ALLOW_EXTENSIONS_NON_V3 # MBEDTLS_X509_ALLOW_UNSUPPORTED_CRITICAL_EXTENSION # - this could be enabled if the respective tests were adapted @@ -86,6 +87,7 @@ MBEDTLS_ECP_DP_M383_ENABLED MBEDTLS_ECP_DP_M511_ENABLED MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES MBEDTLS_NO_PLATFORM_ENTROPY +MBEDTLS_RSA_NO_CRT MBEDTLS_REMOVE_ARC4_CIPHERSUITES MBEDTLS_SSL_HW_RECORD_ACCEL MBEDTLS_X509_ALLOW_EXTENSIONS_NON_V3 From 26f1f6061deabc15400835d278763cadb39aad71 Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Fri, 9 Mar 2018 10:47:30 +0000 Subject: [PATCH 5/6] Improve documentation on the use of blinding in RSA --- include/mbedtls/rsa.h | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/include/mbedtls/rsa.h b/include/mbedtls/rsa.h index fb2f77f94..5548f3c12 100644 --- a/include/mbedtls/rsa.h +++ b/include/mbedtls/rsa.h @@ -518,6 +518,18 @@ int mbedtls_rsa_public( mbedtls_rsa_context *ctx, * * \note The input and output buffers must be large * enough. For example, 128 Bytes if RSA-1024 is used. + * + * \note Blinding is used if and only if a PRNG is provided. + * + * \note If blinding is used, both the base of exponentation + * and the exponent are blinded, providing protection + * against some side-channel attacks. + * + * \warning It is deprecated and a security risk to not provide + * a PRNG here and thereby prevent the use of blinding. + * Future versions of the library may enforce the presence + * of a PRNG. + * */ int mbedtls_rsa_private( mbedtls_rsa_context *ctx, int (*f_rng)(void *, unsigned char *, size_t), From 930ec7dfe50686edb330fcc6a6e5b9569a61935e Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Fri, 9 Mar 2018 10:48:00 +0000 Subject: [PATCH 6/6] Minor fixes --- include/mbedtls/config.h | 3 ++- library/bignum.c | 2 +- tests/suites/test_suite_pk.function | 12 ++++++++---- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/include/mbedtls/config.h b/include/mbedtls/config.h index 1c98558eb..c7ba1743b 100644 --- a/include/mbedtls/config.h +++ b/include/mbedtls/config.h @@ -1049,7 +1049,8 @@ /** * \def MBEDTLS_RSA_NO_CRT * - * Do not use the Chinese Remainder Theorem for the RSA private operation. + * Do not use the Chinese Remainder Theorem + * for the RSA private operation. * * Uncomment this macro to disable the use of CRT in RSA. * diff --git a/library/bignum.c b/library/bignum.c index d27c130bc..9f13da442 100644 --- a/library/bignum.c +++ b/library/bignum.c @@ -1623,7 +1623,7 @@ int mbedtls_mpi_exp_mod( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi mbedtls_mpi RR, T, W[ 2 << MBEDTLS_MPI_WINDOW_SIZE ], Apos; int neg; - if( mbedtls_mpi_cmp_int( N, 0 ) < 0 || ( N->p[0] & 1 ) == 0 ) + if( mbedtls_mpi_cmp_int( N, 0 ) <= 0 || ( N->p[0] & 1 ) == 0 ) return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA ); if( mbedtls_mpi_cmp_int( E, 0 ) < 0 ) diff --git a/tests/suites/test_suite_pk.function b/tests/suites/test_suite_pk.function index 2180f5c8e..318272700 100644 --- a/tests/suites/test_suite_pk.function +++ b/tests/suites/test_suite_pk.function @@ -43,15 +43,18 @@ int mbedtls_rsa_decrypt_func( void *ctx, int mode, size_t *olen, const unsigned char *input, unsigned char *output, size_t output_max_len ) { - return( mbedtls_rsa_pkcs1_decrypt( (mbedtls_rsa_context *) ctx, NULL, NULL, mode, olen, - input, output, output_max_len ) ); + return( mbedtls_rsa_pkcs1_decrypt( (mbedtls_rsa_context *) ctx, + rnd_std_rand, NULL, mode, olen, + input, output, output_max_len ) ); } int mbedtls_rsa_sign_func( void *ctx, int (*f_rng)(void *, unsigned char *, size_t), void *p_rng, int mode, mbedtls_md_type_t md_alg, unsigned int hashlen, const unsigned char *hash, unsigned char *sig ) { - return( mbedtls_rsa_pkcs1_sign( (mbedtls_rsa_context *) ctx, f_rng, p_rng, mode, + ((void) f_rng); + ((void) p_rng); + return( mbedtls_rsa_pkcs1_sign( (mbedtls_rsa_context *) ctx, rnd_std_rand, NULL, mode, md_alg, hashlen, hash, sig ) ); } size_t mbedtls_rsa_key_len_func( void *ctx ) @@ -105,7 +108,8 @@ void mbedtls_pk_check_pair( char *pub_file, char *prv_file, int ret ) if( mbedtls_pk_get_type( &prv ) == MBEDTLS_PK_RSA ) { TEST_ASSERT( mbedtls_pk_setup_rsa_alt( &alt, mbedtls_pk_rsa( prv ), - mbedtls_rsa_decrypt_func, mbedtls_rsa_sign_func, mbedtls_rsa_key_len_func ) == 0 ); + mbedtls_rsa_decrypt_func, mbedtls_rsa_sign_func, + mbedtls_rsa_key_len_func ) == 0 ); TEST_ASSERT( mbedtls_pk_check_pair( &pub, &alt ) == ret ); } #endif