Fix DER TLV length parse when reading certificate size#102
Conversation
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.
Update - additional commit
Also removes the now-unused Note While this makes the size computation safer than before (the returned size is now validated and bounded), the underlying VLA issue remains, |
Summary
stse_get_device_certificate_size()read a fixed 2-byte length at offset 2 and added a hard-coded4. 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-
SEQUENCEtag (empty/unprovisioned zone), forbidden indefinite length (0x80), non-minimal or zero length, and sizes too large for the 16-bit output. These fail early withSTSE_CERT_UNEXPECTED_SEQUENCE/STSE_CERT_INVALID_CERTIFICATE.What changed
SEQUENCE(0x30);0x80), not allowed in DER;PLAT_UI16);<stdint.h>(UINT16_MAX) andcertificate/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_CERTIFICATEinstead of returning an incorrect size.Question (curiosity, not blocking)
retis declaredvolatile stse_ReturnCode_there (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".