Skip to content

Heap OOB read in TPM2_ASN_RsaUnpadPkcsv15 #515

@jming912

Description

@jming912

Summary

TPM2_ASN_RsaUnpadPkcsv15 in src/tpm2_asn.c reads one byte past the end of
the input buffer when the PKCS#1 v1.5 padding consists entirely of 0xFF
bytes after the 0x00 0x01 header and contains no 0x00 separator. The
minimum input that triggers the read is 3 bytes: 00 01 FF.

Affected code

wolfTPM src/tpm2_asn.c, function TPM2_ASN_RsaUnpadPkcsv15 (lines 369-391
at commit adb15eecfed32b3fdb48e0fe1aa2a826808a59ae, master HEAD as of
2026-05-27):

if (sig[idx++] == 0x00 && sig[idx++] == 0x01) {
    while (idx < *sigSz) {
        if (sig[idx] != 0xFF)
            break;
        idx++;
    }
    if (sig[idx++] == 0x00) {   /* <-- OOB read when loop exited with idx == *sigSz */

The while loop has two exit conditions:

  1. it encounters a non-0xFF byte, in which case idx < *sigSz, or
  2. it runs off the end, in which case idx == *sigSz.

The subsequent sig[idx++] == 0x00 check does not distinguish between these
cases and dereferences sig[*sigSz] in case (2).

Reproducer

Standalone PoC, function body copied verbatim from tpm2_asn.c:369-391,
built with gcc 13.3 on Ubuntu 24.04 using -fsanitize=address,undefined:

uint8_t* buf = malloc(3);
buf[0] = 0x00; buf[1] = 0x01; buf[2] = 0xFF;
uint8_t* sig = buf;
int sigSz = 3;
TPM2_ASN_RsaUnpadPkcsv15(&sig, &sigSz);

ASan output:

==481294==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x502000000013
READ of size 1 at 0x502000000013 thread T0
    #0 in TPM2_ASN_RsaUnpadPkcsv15  src/tpm2_asn.c:384
    #1 in main                      poc.c:56

0x502000000013 is located 0 bytes after 3-byte region [0x502000000010,0x502000000013)
allocated by thread T0 here:
    #0 in malloc
    #1 in main                      poc.c:46

SUMMARY: AddressSanitizer: heap-buffer-overflow in TPM2_ASN_RsaUnpadPkcsv15

(Full log and the single-file PoC are available on request — happy to attach
them to this advisory.)

Impact

The function is a WOLFTPM_API export and is reachable from application
code that verifies signed payloads, e.g.
examples/endorsement/verify_ek_cert.c:287. The read is 1 byte, so the
direct impact is bounded:

  • Information disclosure of one heap byte adjacent to the signature buffer
    (or, depending on the allocator and heap layout, a crash via the ASan
    redzone / a guard page).
  • If the byte happens to equal 0x00, the function returns success (rc = 0)
    with *sigSz set to one less than the original allocation length, which
    may cause the caller to consume one byte of uninitialised / adjacent
    memory as legitimate signed content.

Exploitability depends on whether attacker-controlled buffers can reach this
function in a deployment. The existing OSS-Fuzz harness
(fuzz_asn_cert.c) does not call this function, which is likely why ASan
has not flagged it in CI to date.

Suggested fix

--- a/src/tpm2_asn.c
+++ b/src/tpm2_asn.c
@@ -381,7 +381,7 @@ int TPM2_ASN_RsaUnpadPkcsv15(uint8_t** pSig, int* sigSz)
             idx++;
         }
-        if (sig[idx++] == 0x00) {
+        if (idx < *sigSz && sig[idx++] == 0x00) {
             rc = 0;
             *pSig = &sig[idx];

Equivalently, the while loop guard can be tightened to idx < *sigSz - 1
so that the byte-after-padding check is always in bounds.

How it was found

Static review of tpm2_asn.c, followed by a standalone reproducer compiled
with ASan to confirm. I'm not aware of any in-the-wild exploitation; this is
a routine code-audit finding.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions