Vulnerability: The rsa_verify_hash_ex function in rsa_verify_hash.c in LibTomCrypt, as used in OP-TEE before 2.2.0, does not validate that the message length is equal to the ASN.1 encoded data length, which makes it easier for remote attackers to forge RSA signatures or public certificates by leveraging a Bleichenbacher signature forgery attack.
Vulnerability ID: CVE-2016-6129
CWE: CWE-20
Severity score: 2.9
Project: https://github.com/libtom/libtomcrypt
Published: 2017-02-13
File: src/pk/rsa/rsa_verify_hash.c
Commit message: rsa_verify_hash: fix possible bleichenbacher signature attack
Commit author: Steffen Jaeckel

Vulnerable version (before fix):
 int rsa_verify_hash_ex(const unsigned char *sig,      unsigned long siglen,   } else {     /* PKCS #1 v1.5 decode it */     unsigned char *out;     unsigned long outlen, loid[16];     int           decoded;     ltc_asn1_list digestinfo[2], siginfo[2];  int rsa_verify_hash_ex(const unsigned char *sig,      unsigned long siglen,        goto bail_2;     }      /* test OID */     if ((digestinfo[0].size == hash_descriptor[hash_idx].OIDlen) &&         (XMEMCMP(digestinfo[0].data, hash_descriptor[hash_idx].OID, sizeof(unsigned long) * hash_descriptor[hash_idx].OIDlen) == 0) &&         (siginfo[1].size == hashlen) &&         (XMEMCMP(siginfo[1].data, hash, hashlen) == 0)) {

Fixed version (after fix):
 int rsa_verify_hash_ex(const unsigned char *sig,      unsigned long siglen,   } else {     /* PKCS #1 v1.5 decode it */     unsigned char *out;     unsigned long outlen, loid[16], reallen;     int           decoded;     ltc_asn1_list digestinfo[2], siginfo[2];  int rsa_verify_hash_ex(const unsigned char *sig,      unsigned long siglen,        goto bail_2;     }      if ((err = der_length_sequence(siginfo, 2, &reallen)) != CRYPT_OK) {        XFREE(out);        goto bail_2;     }      /* test OID */     if ((reallen == outlen) &&         (digestinfo[0].size == hash_descriptor[hash_idx].OIDlen) &&         (XMEMCMP(digestinfo[0].data, hash_descriptor[hash_idx].OID, sizeof(unsigned long) * hash_descriptor[hash_idx].OIDlen) == 0) &&         (siginfo[1].size == hashlen) &&         (XMEMCMP(siginfo[1].data, hash, hashlen) == 0)) {

Patch:
patch: @@ -103,7 +103,7 @@ int rsa_verify_hash_ex(const unsigned char *sig,      unsigned long siglen,
   } else {
     /* PKCS #1 v1.5 decode it */
     unsigned char *out;
-    unsigned long outlen, loid[16];
+    unsigned long outlen, loid[16], reallen;
     int           decoded;
     ltc_asn1_list digestinfo[2], siginfo[2];
 
@@ -145,8 +145,14 @@ int rsa_verify_hash_ex(const unsigned char *sig,      unsigned long siglen,
        goto bail_2;
     }
 
+    if ((err = der_length_sequence(siginfo, 2, &reallen)) != CRYPT_OK) {
+       XFREE(out);
+       goto bail_2;
+    }
+
     /* test OID */
-    if ((digestinfo[0].size == hash_descriptor[hash_idx].OIDlen) &&
+    if ((reallen == outlen) &&
+        (digestinfo[0].size == hash_descriptor[hash_idx].OIDlen) &&
         (XMEMCMP(digestinfo[0].data, hash_descriptor[hash_idx].OID, sizeof(unsigned long) * hash_descriptor[hash_idx].OIDlen) == 0) &&
         (siginfo[1].size == hashlen) &&
         (XMEMCMP(siginfo[1].data, hash, hashlen) == 0)) {
path: src/pk/rsa/rsa_verify_hash.c