From 0e17eb05f88b0171b17fada3b3c41987dc29769b Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Wed, 3 May 2017 18:32:21 +0200 Subject: [PATCH 1/2] More length checks in RSA PKCS1v15 verify Tighten ASN.1 parsing of RSA PKCS#1 v1.5 signatures, to avoid a potential Bleichenbacher-style attack. --- ChangeLog | 6 ++++++ library/rsa.c | 13 +++++++++---- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/ChangeLog b/ChangeLog index 13de8672c..6673e829e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,11 @@ mbed TLS ChangeLog (Sorted per branch, date) += mbed TLS 2.x.x branch released xxxx-xx-xx + +Security + * Tighten ASN.1 parsing of RSA PKCS#1 v1.5 signatures, to avoid a + potential Bleichenbacher-style attack. + = mbed TLS 2.4.2 branch released 2017-03-08 Security diff --git a/library/rsa.c b/library/rsa.c index 40ef2a948..4d4a00ba3 100644 --- a/library/rsa.c +++ b/library/rsa.c @@ -1337,7 +1337,7 @@ int mbedtls_rsa_rsassa_pkcs1_v15_verify( mbedtls_rsa_context *ctx, { int ret; size_t len, siglen, asn1_len; - unsigned char *p, *end; + unsigned char *p, *p0, *end; mbedtls_md_type_t msg_md_alg; const mbedtls_md_info_t *md_info; mbedtls_asn1_buf oid; @@ -1391,23 +1391,27 @@ int mbedtls_rsa_rsassa_pkcs1_v15_verify( mbedtls_rsa_context *ctx, /* * Parse the ASN.1 structure inside the PKCS#1 v1.5 structure */ + p0 = p; if( ( ret = mbedtls_asn1_get_tag( &p, end, &asn1_len, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) return( MBEDTLS_ERR_RSA_VERIFY_FAILED ); - if( asn1_len + 2 != len ) + if( p != p0 + 2 || asn1_len + 2 != len ) return( MBEDTLS_ERR_RSA_VERIFY_FAILED ); if( ( ret = mbedtls_asn1_get_tag( &p, end, &asn1_len, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) return( MBEDTLS_ERR_RSA_VERIFY_FAILED ); - if( asn1_len + 6 + hashlen != len ) + if( p != p0 + 4 || asn1_len + 6 + hashlen != len ) return( MBEDTLS_ERR_RSA_VERIFY_FAILED ); if( ( ret = mbedtls_asn1_get_tag( &p, end, &oid.len, MBEDTLS_ASN1_OID ) ) != 0 ) return( MBEDTLS_ERR_RSA_VERIFY_FAILED ); + if( p != p0 + 6 ) + return( MBEDTLS_ERR_RSA_VERIFY_FAILED ); + oid.p = p; p += oid.len; @@ -1423,10 +1427,11 @@ int mbedtls_rsa_rsassa_pkcs1_v15_verify( mbedtls_rsa_context *ctx, if( ( ret = mbedtls_asn1_get_tag( &p, end, &asn1_len, MBEDTLS_ASN1_NULL ) ) != 0 ) return( MBEDTLS_ERR_RSA_VERIFY_FAILED ); + p0 = p; if( ( ret = mbedtls_asn1_get_tag( &p, end, &asn1_len, MBEDTLS_ASN1_OCTET_STRING ) ) != 0 ) return( MBEDTLS_ERR_RSA_VERIFY_FAILED ); - if( asn1_len != hashlen ) + if( p != p0 + 2 || asn1_len != hashlen ) return( MBEDTLS_ERR_RSA_VERIFY_FAILED ); if( memcmp( p, hash, hashlen ) != 0 ) From e7e7650480e84c6fc09a1d353eea2a8b90d85777 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Thu, 4 May 2017 12:48:39 +0200 Subject: [PATCH 2/2] More length checks in RSA PKCS1v15 verify Added one check that I'd missed, and made the style more uniform. --- library/rsa.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/library/rsa.c b/library/rsa.c index 4d4a00ba3..e97d280eb 100644 --- a/library/rsa.c +++ b/library/rsa.c @@ -1389,27 +1389,28 @@ int mbedtls_rsa_rsassa_pkcs1_v15_verify( mbedtls_rsa_context *ctx, end = p + len; /* - * Parse the ASN.1 structure inside the PKCS#1 v1.5 structure + * Parse the ASN.1 structure inside the PKCS#1 v1.5 structure. + * Insist on 2-byte length tags, to protect against variants of + * Bleichenbacher's forgery attack against lax PKCS#1v1.5 verification. */ p0 = p; if( ( ret = mbedtls_asn1_get_tag( &p, end, &asn1_len, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) return( MBEDTLS_ERR_RSA_VERIFY_FAILED ); - if( p != p0 + 2 || asn1_len + 2 != len ) return( MBEDTLS_ERR_RSA_VERIFY_FAILED ); + p0 = p; if( ( ret = mbedtls_asn1_get_tag( &p, end, &asn1_len, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) return( MBEDTLS_ERR_RSA_VERIFY_FAILED ); - - if( p != p0 + 4 || asn1_len + 6 + hashlen != len ) + if( p != p0 + 2 || asn1_len + 6 + hashlen != len ) return( MBEDTLS_ERR_RSA_VERIFY_FAILED ); + p0 = p; if( ( ret = mbedtls_asn1_get_tag( &p, end, &oid.len, MBEDTLS_ASN1_OID ) ) != 0 ) return( MBEDTLS_ERR_RSA_VERIFY_FAILED ); - - if( p != p0 + 6 ) + if( p != p0 + 2 ) return( MBEDTLS_ERR_RSA_VERIFY_FAILED ); oid.p = p; @@ -1424,13 +1425,15 @@ int mbedtls_rsa_rsassa_pkcs1_v15_verify( mbedtls_rsa_context *ctx, /* * assume the algorithm parameters must be NULL */ + p0 = p; if( ( ret = mbedtls_asn1_get_tag( &p, end, &asn1_len, MBEDTLS_ASN1_NULL ) ) != 0 ) return( MBEDTLS_ERR_RSA_VERIFY_FAILED ); + if( p != p0 + 2 ) + return( MBEDTLS_ERR_RSA_VERIFY_FAILED ); p0 = p; if( ( ret = mbedtls_asn1_get_tag( &p, end, &asn1_len, MBEDTLS_ASN1_OCTET_STRING ) ) != 0 ) return( MBEDTLS_ERR_RSA_VERIFY_FAILED ); - if( p != p0 + 2 || asn1_len != hashlen ) return( MBEDTLS_ERR_RSA_VERIFY_FAILED );