From 69ff30e86a1c4b97b38b8cb303a1ddb821ff524a Mon Sep 17 00:00:00 2001 From: Chris van Marle Date: Tue, 11 Oct 2022 22:13:32 +0200 Subject: [PATCH] MRTD TLV parsing (and select) --- lib/nfc/helpers/iso7816.c | 34 +++++++++++- lib/nfc/helpers/iso7816.h | 17 +++--- test_iso7816_helpers.c | 109 +++++++++++++++++++++++++++++++------- 3 files changed, 130 insertions(+), 30 deletions(-) diff --git a/lib/nfc/helpers/iso7816.c b/lib/nfc/helpers/iso7816.c index 2cbff0809..1759a67f9 100644 --- a/lib/nfc/helpers/iso7816.c +++ b/lib/nfc/helpers/iso7816.c @@ -13,15 +13,22 @@ TlvInfo iso7816_tlv_parse(const uint8_t* data) { // 11111 10000001 00000001 - 11111 11111111 01111111 => 128 - 16383 (3 byte) tlv.tag = *(data++); + tlv.ber.constructed = ((tlv.tag & 0x20) != 0); + tlv.ber.class = (tlv.tag >> 6) & 0x03; if ((tlv.tag & 0x1f) == 0x1f) { // BER-TLV, multi byte tag - tlv.tag = *(data++); + tlv.tag <<= 8; + tlv.tag |= *(data++); + tlv.ber.tag = tlv.tag & 0x7f; if(tlv.tag & 0x80) { // BER-TLV, 3 byte tag tlv.tag &= ~0x80; tlv.tag <<= 7; tlv.tag |= *(data++) & 0x7f; + tlv.ber.tag = tlv.tag & 0x3fff; } + } else { + tlv.ber.tag = tlv.tag & 0x1f; } //TODO: check for invalid 'indefinite length' @@ -49,3 +56,28 @@ TlvInfo iso7816_tlv_parse(const uint8_t* data) { return tlv; } + +TlvInfo iso7816_tlv_select(const uint8_t* data, size_t length, const uint16_t tags[], size_t num_tags) { + TlvInfo tlv; + size_t offset = 0; + + if(num_tags == 0) { + return (TlvInfo){.tag = 0x0000}; + } + + while(offset < length) { + tlv = iso7816_tlv_parse(data + offset); + + if(tlv.tag == tags[0]) { + if(num_tags == 1) { + return tlv; + } else { + return iso7816_tlv_select(tlv.value, tlv.length, tags+1, num_tags - 1); + } + } + + offset = tlv.next - data; // TODO: use some length value of TlvInfo instead of this monstrosity + } + + return (TlvInfo){.tag = 0x0000}; +} diff --git a/lib/nfc/helpers/iso7816.h b/lib/nfc/helpers/iso7816.h index 883da0d33..10d28d11b 100644 --- a/lib/nfc/helpers/iso7816.h +++ b/lib/nfc/helpers/iso7816.h @@ -11,17 +11,12 @@ #define BER_CLASS_PRIVATE 0x3 typedef struct { - union { + uint16_t tag; // TODO: use define/typedef for this data format? + struct { uint16_t tag; - struct { - // LSB - uint8_t tag : 5; - uint8_t constructed : 1; - uint8_t class : 2; - // MSB - } ber; - //TODO: currently only works for 1-byte tags - }; + uint8_t constructed : 1; + uint8_t class : 2; + } ber; size_t length; const uint8_t* value; @@ -31,3 +26,5 @@ typedef struct { // ISO7816-5 §5.2 // Simple-TLV and BER-TLV parsing TlvInfo iso7816_tlv_parse(const uint8_t* data); + +TlvInfo iso7816_tlv_select(const uint8_t* data, size_t length, const uint16_t tags[], size_t num_tags); diff --git a/test_iso7816_helpers.c b/test_iso7816_helpers.c index e617f4713..292fefbf4 100644 --- a/test_iso7816_helpers.c +++ b/test_iso7816_helpers.c @@ -6,19 +6,31 @@ #define COLOR_GREEN "\033[0;32m" #define COLOR_RESET "\033[0;0m" +//TODO: do something with ISO7816-4 Table 9 — Interindustry data objects for tag allocation authority +//0x06 Object identifier (encoding specified in ISO/IEC 8825-1, see examples in annex A) +//0x41 Country code (encoding specified in ISO 3166-1 [1] ) and optional national data +//0x42 Issuer identification number (encoding and registration specified in ISO/IEC 7812-1 [3] ) and optional issuer data +//0x4F Application identifier (AID, encoding specified in 8.2.1.2) + void print_hex(const uint8_t* data, size_t length) { for(size_t i=0; i