ISO/IEC 7816-4 Annex D: BER-TLV Encoding in Smart Cards

BER-TLV Encoding in Smart Cards

ISO 7816 Part 4: Interindustry Commands for Interchange

ISO 7816 part 4, section..1 2 3 4 5 6 7 8 9 annex.. A B C D E F

BER-TLV encoding in smart cards

Nearly everything structured that a card returns — file control information, capability data, secure messaging fields, application data — is encoded as BER-TLV: a tag saying what this is, a length saying how big it is, and a value. Getting comfortable with the encoding pays for itself immediately, because a parser that handles it properly handles most of the card’s output.

The tag field

The first byte of a tag carries three pieces of information in its bits:

  • Bits b8 and b7 give the class: universal, application, context-specific, or private. Smart-card data objects are overwhelmingly application or context-specific.
  • Bit b6 says whether the object is constructed (its value is itself a sequence of TLV objects) or primitive (its value is raw data). This bit is what makes BER-TLV a tree rather than a list, and ignoring it is the classic parser bug.
  • Bits b5 to b1 carry the tag number. If all five are set, the tag continues into further bytes, each using its high bit to indicate whether another follows.

The length field

  • A single byte with its high bit clear encodes a length from 0 to 127 directly.
  • A single byte with its high bit set does not encode the length — its low bits give the number of subsequent bytes that do. So a leading byte indicating one following byte covers lengths up to 255, two following bytes up to 65535, and so on.

That distinction is where most hand-written parsers fail. A length byte of 81 does not mean 129; it means “the next byte is the length”.

The value field

For a primitive object the value is data to be interpreted according to the tag. For a constructed object the value is a concatenation of further TLV objects, parsed recursively.

Where you will meet it

  • File control information returned by SELECT, where the FCP and FMD templates are constructed objects containing primitive descriptors.
  • Data objects fetched and stored with GET DATA and PUT DATA.
  • Secure messaging fields, which are TLV objects wrapping the protected parts of an APDU.
  • Control reference templates identifying a key and an algorithm for a security operation.

Note that the historical bytes in the ATR use a different, condensed encoding rather than full BER-TLV, because space there is scarce. A BER-TLV parser will not read them.

Writing a parser that survives contact with real cards

  • Handle multi-byte tags and long-form lengths from the start. They will appear eventually, and retrofitting them means revisiting every call site.
  • Recurse on the constructed bit, not on a list of known tags. A parser that only descends into templates it recognises will silently flatten unfamiliar structures.
  • Bound everything. A declared length longer than the remaining buffer is the obvious attack and the obvious corruption symptom. Reject it rather than reading past the end.
  • Skip unknown tags rather than failing. Cards add data objects over time; a parser that aborts on anything it does not recognise will break on the next card revision.
  • Preserve raw bytes alongside parsed values. Signature and MAC verification operate on the encoded form, and re-encoding a parsed structure rarely reproduces the original byte-for-byte.
  • Illustrative example. A constructed template containing two primitive objects parses as: read the template’s tag, read its length, then parse the value as a sequence of TLVs until that length is consumed — not until the buffer ends. Bounding by the parent’s length is what keeps sibling structures from being swallowed.

Authoritative source

The encoding rules themselves are specified in ISO/IEC 8825-1, published jointly with ITU-T as Recommendation X.690. For how those rules are applied to card data objects, refer to ISO/IEC 7816-4:2020, published by ISO. This page is Ambimat’s own explanation and does not reproduce or replace either standard.