diff --git a/ChangeLog b/ChangeLog index d3636f00a..8be2cdde8 100644 --- a/ChangeLog +++ b/ChangeLog @@ -2,6 +2,11 @@ mbed TLS ChangeLog (Sorted per branch, date) = mbed TLS 2.1.0 released 2015-09-04 +Security + * Add countermeasure against Lenstra's RSA-CRT attack for PKCS#1 v1.5 + signatures. (Found by Florian Weimer, Red Hat.) + https://securityblog.redhat.com/2015/09/02/factoring-rsa-keys-with-tls-perfect-forward-secrecy/ + Features * Added support for yotta as a build system. * Primary open source license changed to Apache 2.0 license. diff --git a/library/rsa.c b/library/rsa.c index f4ab6b2a6..3883d0921 100644 --- a/library/rsa.c +++ b/library/rsa.c @@ -51,6 +51,8 @@ #else #include #define mbedtls_printf printf +#define mbedtls_calloc calloc +#define mbedtls_free free #endif /* @@ -1005,6 +1007,11 @@ int mbedtls_rsa_rsassa_pkcs1_v15_sign( mbedtls_rsa_context *ctx, size_t nb_pad, olen, oid_size = 0; unsigned char *p = sig; const char *oid = NULL; + unsigned char *sig_try = NULL, *verif = NULL; + size_t i; + unsigned char diff; + volatile unsigned char diff_no_optimize; + int ret; if( mode == MBEDTLS_RSA_PRIVATE && ctx->padding != MBEDTLS_RSA_PKCS_V15 ) return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); @@ -1067,9 +1074,39 @@ int mbedtls_rsa_rsassa_pkcs1_v15_sign( mbedtls_rsa_context *ctx, memcpy( p, hash, hashlen ); } - return( ( mode == MBEDTLS_RSA_PUBLIC ) - ? mbedtls_rsa_public( ctx, sig, sig ) - : mbedtls_rsa_private( ctx, f_rng, p_rng, sig, sig ) ); + if( mode == MBEDTLS_RSA_PUBLIC ) + return( mbedtls_rsa_public( ctx, sig, sig ) ); + + /* + * In order to prevent Lenstra's attack, make the signature in a + * temporary buffer and check it before returning it. + */ + sig_try = mbedtls_calloc( 1, ctx->len ); + verif = mbedtls_calloc( 1, ctx->len ); + if( sig_try == NULL || verif == NULL ) + return( MBEDTLS_ERR_MPI_ALLOC_FAILED ); + + MBEDTLS_MPI_CHK( mbedtls_rsa_private( ctx, f_rng, p_rng, sig, sig_try ) ); + MBEDTLS_MPI_CHK( mbedtls_rsa_public( ctx, sig_try, verif ) ); + + /* Compare in constant time just in case */ + for( diff = 0, i = 0; i < ctx->len; i++ ) + diff |= verif[i] ^ sig[i]; + diff_no_optimize = diff; + + if( diff_no_optimize != 0 ) + { + ret = MBEDTLS_ERR_RSA_PRIVATE_FAILED; + goto cleanup; + } + + memcpy( sig, sig_try, ctx->len ); + +cleanup: + mbedtls_free( sig_try ); + mbedtls_free( verif ); + + return( ret ); } #endif /* MBEDTLS_PKCS1_V15 */