diff --git a/ChangeLog b/ChangeLog index 8449329b0..944d695b7 100644 --- a/ChangeLog +++ b/ChangeLog @@ -8,6 +8,8 @@ Security https://arxiv.org/abs/1702.08719v2. Found and fix proposed by Michael Schwarz, Samuel Weiser, Daniel Gruss, Clémentine Maurice and Stefan Mangard. + * Tighten ASN.1 parsing of RSA PKCS#1 v1.5 signatures, to avoid a + potential Bleichenbacher-style attack. Bugfix * Fix insufficient support for signature-hash-algorithm extension, diff --git a/library/rsa.c b/library/rsa.c index 1cdf0d66a..999c8b92d 100644 --- a/library/rsa.c +++ b/library/rsa.c @@ -1472,7 +1472,7 @@ int rsa_rsassa_pkcs1_v15_verify( rsa_context *ctx, { int ret; size_t len, siglen, asn1_len; - unsigned char *p, *end; + unsigned char *p, *p0, *end; unsigned char buf[POLARSSL_MPI_MAX_SIZE]; md_type_t msg_md_alg; const md_info_t *md_info; @@ -1523,24 +1523,30 @@ int rsa_rsassa_pkcs1_v15_verify( 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 = asn1_get_tag( &p, end, &asn1_len, ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 ) return( POLARSSL_ERR_RSA_VERIFY_FAILED ); - - if( asn1_len + 2 != len ) + if( p != p0 + 2 || asn1_len + 2 != len ) return( POLARSSL_ERR_RSA_VERIFY_FAILED ); + p0 = p; if( ( ret = asn1_get_tag( &p, end, &asn1_len, ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 ) return( POLARSSL_ERR_RSA_VERIFY_FAILED ); - - if( asn1_len + 6 + hashlen != len ) + if( p != p0 + 2 || asn1_len + 6 + hashlen != len ) return( POLARSSL_ERR_RSA_VERIFY_FAILED ); + p0 = p; if( ( ret = asn1_get_tag( &p, end, &oid.len, ASN1_OID ) ) != 0 ) return( POLARSSL_ERR_RSA_VERIFY_FAILED ); + if( p != p0 + 2 ) + return( POLARSSL_ERR_RSA_VERIFY_FAILED ); oid.p = p; p += oid.len; @@ -1554,13 +1560,16 @@ int rsa_rsassa_pkcs1_v15_verify( rsa_context *ctx, /* * assume the algorithm parameters must be NULL */ + p0 = p; if( ( ret = asn1_get_tag( &p, end, &asn1_len, ASN1_NULL ) ) != 0 ) return( POLARSSL_ERR_RSA_VERIFY_FAILED ); - - if( ( ret = asn1_get_tag( &p, end, &asn1_len, ASN1_OCTET_STRING ) ) != 0 ) + if( p != p0 + 2 ) return( POLARSSL_ERR_RSA_VERIFY_FAILED ); - if( asn1_len != hashlen ) + p0 = p; + if( ( ret = asn1_get_tag( &p, end, &asn1_len, ASN1_OCTET_STRING ) ) != 0 ) + return( POLARSSL_ERR_RSA_VERIFY_FAILED ); + if( p != p0 + 2 || asn1_len != hashlen ) return( POLARSSL_ERR_RSA_VERIFY_FAILED ); if( memcmp( p, hash, hashlen ) != 0 )