Merge remote-tracking branch 'restricted/IOTSSL-1366/development-restricted' into development-restricted

* restricted/IOTSSL-1366/development-restricted:
  More length checks in RSA PKCS1v15 verify
  More length checks in RSA PKCS1v15 verify
diff --git a/ChangeLog b/ChangeLog
index 243bd6b..bbfec95 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -8,6 +8,8 @@
      option if needed.
    * Fixed offset in FALLBACK_SCSV parsing that caused TLS server to fail to
      detect it sometimes. Reported by Hugo Leisink. #810
+   * Tighten ASN.1 parsing of RSA PKCS#1 v1.5 signatures, to avoid a
+     potential Bleichenbacher-style attack.
 
 Bugfix
    * Remove invalid use of size zero arrays in ECJPAKE test suite.
diff --git a/library/rsa.c b/library/rsa.c
index 122bc13..e965bf5 100644
--- a/library/rsa.c
+++ b/library/rsa.c
@@ -1467,7 +1467,7 @@
 {
     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;
@@ -1519,24 +1519,29 @@
     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( asn1_len + 2 != len )
+    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( 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 + 2 )
+        return( MBEDTLS_ERR_RSA_VERIFY_FAILED );
 
     oid.p = p;
     p += oid.len;
@@ -1550,13 +1555,16 @@
     /*
      * 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( ( ret = mbedtls_asn1_get_tag( &p, end, &asn1_len, MBEDTLS_ASN1_OCTET_STRING ) ) != 0 )
+    if( p != p0 + 2 )
         return( MBEDTLS_ERR_RSA_VERIFY_FAILED );
 
-    if( asn1_len != hashlen )
+    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 );
 
     if( memcmp( p, hash, hashlen ) != 0 )