Skip to content

Fix DER TLV length parse when reading certificate size#102

Open
parmi93 wants to merge 2 commits into
STMicroelectronics:dev/1.2.0from
parmi93:fix_cert_parse
Open

Fix DER TLV length parse when reading certificate size#102
parmi93 wants to merge 2 commits into
STMicroelectronics:dev/1.2.0from
parmi93:fix_cert_parse

Conversation

@parmi93

@parmi93 parmi93 commented Jul 4, 2026

Copy link
Copy Markdown
Contributor

Summary

stse_get_device_certificate_size() read a fixed 2-byte length at offset 2 and added a hard-coded 4. That only works for the DER long-form-with-2-length-bytes encoding, and it did no validation of the zone content, any two bytes were blindly used as a length.

This MR properly decodes the X.509 DER TLV header and now detects and rejects invalid or corrupted certificates instead of returning a wrong size: non-SEQUENCE tag (empty/unprovisioned zone), forbidden indefinite length (0x80), non-minimal or zero length, and sizes too large for the 16-bit output. These fail early with STSE_CERT_UNEXPECTED_SEQUENCE / STSE_CERT_INVALID_CERTIFICATE.

What changed

  • Read the first 4 bytes (tag + up to 3 length bytes) instead of only the 2 length bytes at offset 2.
  • Decode the length according to DER rules:
    • verify the tag is SEQUENCE (0x30);
    • reject the indefinite length (0x80), not allowed in DER;
    • handle short form and 1-/2-byte long form to obtain the Value length;
    • add the Tag+Length field size to return the full certificate size.
  • Harden against malformed input:
    • enforce minimal DER length encoding;
    • reject empty / zero-length certificates;
    • reject length fields longer than 2 bytes (> 65535, beyond PLAT_UI16);
    • guard the final addition against 16-bit overflow.
  • Add <stdint.h> (UINT16_MAX) and certificate/stse_certificate_types.h (TAG_SEQUENCE) includes.

Why

The previous code returned a wrong size for any certificate not encoded with a 2-byte long-form length, and did no validation of the DER header, a malformed or unexpected zone content could produce a bogus size used by callers to allocate/read the certificate.

Impact

No API change. Return values are unchanged on success; malformed certificates now fail early with STSE_CERT_UNEXPECTED_SEQUENCE / STSE_CERT_INVALID_CERTIFICATE instead of returning an incorrect size.

Question (curiosity, not blocking)

ret is declared volatile stse_ReturnCode_t here (and in a few other API functions). Out of curiosity, is this an intentional fault-injection / glitch-attack countermeasure (forcing the compiler not to optimize away or cache the return-code checks, so a skipped comparison is harder to induce), or is there another reason? Worth documenting the rationale if so, since it's easy to mistake for dead-code and "clean up".

parmi93 added 2 commits July 4, 2026 16:39
stse_get_device_certificate_size previously assumed the certificate length
was always encoded in a fixed 2-byte field at offset 2, which only holds
for the DER long-form-with-2-length-bytes case. Certificates using the
short form or a 1-byte long form were sized incorrectly.

Read the first 4 bytes (tag + up to 3 length bytes) and decode the length
according to the X.509 DER TLV encoding:
 - verify the tag is SEQUENCE (0x30)
 - reject the indefinite length (0x80), which is not allowed in DER
 - handle short form and 1/2-byte long form, computing the value length
 - add the tag+length field size to obtain the full certificate size

Also validate against malformed encodings: enforce the minimal DER length
encoding, reject empty/zero-length certificates, reject length fields
longer than 2 bytes (> 65535 bytes), and guard the final addition against
16-bit overflow.

Add <stdint.h> (UINT16_MAX) and stse_certificate_types.h (TAG_SEQUENCE)
includes.
…enticate

stse_device_authenticate duplicated the inline 2-byte certificate size
computation, which suffered from the same incorrect DER length handling
just fixed in stse_get_device_certificate_size. Call that function
instead so authentication benefits from the correct DER TLV parsing and
the malformed-certificate validation.

Remove the now-unused certificate_size_ui8 buffer and the
STSE_CERTIFICATE_SIZE_OFFSET_BYTES / STSE_CERTIFICATE_SIZE_LENGTH macros.
@parmi93

parmi93 commented Jul 4, 2026

Copy link
Copy Markdown
Contributor Author

Update - additional commit

stse_device_authenticate() previously duplicated the same inline 2-byte certificate size computation, affected by the identical DER length bug fixed above. It now calls stse_get_device_certificate_size() instead, so the authentication path benefits from the corrected DER TLV parsing and the malformed-certificate validation.

Also removes the now-unused certificate_size_ui8 buffer and the STSE_CERTIFICATE_SIZE_OFFSET_BYTES / STSE_CERTIFICATE_SIZE_LENGTH macros.

Note

While this makes the size computation safer than before (the returned size is now validated and bounded), the underlying VLA issue remains, certificate_size is still used to declare a variable-length array (PLAT_UI8 certificate[certificate_size];) on the stack. Even with the size validated, an attacker-controlled length up to 65535 bytes can still blow the stack, so this should be addressed separately (e.g. a fixed-size buffer or a hard cap on the accepted certificate size).

@parmi93 parmi93 changed the title [fix][api] parse DER TLV length when reading device certificate size Fix DER TLV length parse when reading certificate size Jul 4, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant