diff --git a/PAYMENT_RECIPES.md b/PAYMENT_RECIPES.md index 1e2157c1..21b9d6e3 100644 --- a/PAYMENT_RECIPES.md +++ b/PAYMENT_RECIPES.md @@ -118,7 +118,7 @@ Operations: - `EMV Generate ARPC` - `EMV Build ARPC Data` - `EMV Parse ARPC Data` -- `Parse EMV TLV` +- `EMV Parse TLV` Use this when: - you want to assemble or inspect ARQC/ARPC preimage data by named field @@ -130,7 +130,7 @@ Input: - `EMV Build ARQC Data` / `EMV Build ARPC Data`: all fields supplied via args; ignores the input field — use as the first step in a chained recipe - `EMV Parse ARQC Data` / `EMV Parse ARPC Data`: flat hex preimage - `EMV Generate ARQC` / `EMV Verify ARQC` / `EMV Generate ARPC`: preassembled EMV data as hex -- `Parse EMV TLV`: BER-TLV encoded hex (DE 55, ICC response, GPO response) +- `EMV Parse TLV`: BER-TLV encoded hex (DE 55, ICC response, GPO response) Important assumptions: - CDOL1 structure is network-agnostic: the same 10-field 33-byte layout applies across Visa, Mastercard, Amex, Discover, and JCB @@ -457,7 +457,7 @@ Release guidance: `Publish` = safe with normal guardrails; `Publish with guardra | `EMV Generate ARPC` | Vendor-aligned | AWS `VerifyAuthRequestCryptogram` issuer flow | Publish with guardrails | | `EMV Build ARPC Data` | Verified | EMV Book 2 §8.2 (Method 1); Mastercard M/Chip (Method 2) | Publish | | `EMV Parse ARPC Data` | Verified | EMV Book 2 §8.2 (Method 1); Mastercard M/Chip (Method 2) | Publish | -| `Parse EMV TLV` | Verified | ISO 8825-1 BER-TLV; EMV Books 1–4; EMVCo contactless Book C | Publish | +| `EMV Parse TLV` | Verified | ISO 8825-1 BER-TLV; EMV Books 1–4; EMVCo contactless Book C | Publish | | `Card Validation Data Generate` | Vendor-aligned | AWS `GenerateCardValidationData` | Publish with guardrails | | `Card Validation Data Verify` | Vendor-aligned | AWS `VerifyCardValidationData` | Publish with guardrails | | `PIN IBM 3624 Offset Generate` | Vendor-aligned | AWS IBM 3624 PIN verification object | Publish with guardrails | diff --git a/src/core/config/Categories.json b/src/core/config/Categories.json index f3878677..10436ef5 100644 --- a/src/core/config/Categories.json +++ b/src/core/config/Categories.json @@ -599,7 +599,7 @@ "EMV Generate ARQC", "EMV Parse ARPC Data", "EMV Parse ARQC Data", - "Parse EMV TLV", + "EMV Parse TLV", "EMV Generate MAC", "EMV Generate MAC (PIN Change)", "EMV Verify ARQC", diff --git a/src/core/lib/EmvTlvDictionary.mjs b/src/core/lib/EmvTlvDictionary.mjs index ed03a6c7..de689317 100644 --- a/src/core/lib/EmvTlvDictionary.mjs +++ b/src/core/lib/EmvTlvDictionary.mjs @@ -4,7 +4,7 @@ * * EMV tag dictionary covering EMV Books 1-4, EMVCo contactless, Nexo, and * common acquirer/terminal tags. Each entry carries metadata used by the - * Parse EMV TLV operation. + * EMV Parse TLV operation. * * Sources: EMV Book 1 §A; EMV Book 3 §A; Nexo FAST 3.x; ISO 8583 DE 55 common tags. */ diff --git a/src/core/operations/ParseEMVTLV.mjs b/src/core/operations/ParseEMVTLV.mjs index bf5b5447..3038737b 100644 --- a/src/core/operations/ParseEMVTLV.mjs +++ b/src/core/operations/ParseEMVTLV.mjs @@ -7,7 +7,7 @@ import Operation from "../Operation.mjs"; import { parseEmvTlv, EMV_TAG_DICTIONARY } from "../lib/EmvTlv.mjs"; /** - * Parse EMV TLV operation. + * EMV Parse TLV operation. */ class ParseEMVTLV extends Operation { @@ -15,7 +15,7 @@ class ParseEMVTLV extends Operation { constructor() { super(); - this.name = "Parse EMV TLV"; + this.name = "EMV Parse TLV"; this.module = "Payment"; this.description = "Parse hex-encoded BER-TLV data (e.g., DE 55 field, ICC response, terminal data, ARQC preimage in TLV form) and annotate each tag using the built-in EMV tag dictionary.

Input: hex-encoded BER-TLV data.
Output: JSON tree. Each record includes the tag hex value, name from the EMV tag dictionary, source (ICC / Terminal / Host / Both), value format, length, value in hex, and — for constructed tags — a children array with the recursively parsed inner TLVs.

Tag dictionary: covers EMV Books 1–4, EMVCo contactless Book C, and common Nexo/acquirer tags (~90 entries). Unknown tags are decoded structurally but marked with name Unknown.

Constructed tags: tags with the constructed bit set (e.g., 70, 77, 6F, A5, BF0C) are recursively parsed into child arrays.

Note: indefinite-length BER encoding is not supported; this covers the definite short- and long-form lengths used by all standard EMV cards."; this.inlineHelp = "Input: hex-encoded BER-TLV (DE 55, ICC response, GPO reply, etc.). Outputs annotated JSON with EMV tag names and nested children."; diff --git a/tests/operations/tests/Payment.mjs b/tests/operations/tests/Payment.mjs index 119a24f3..a95d350a 100644 --- a/tests/operations/tests/Payment.mjs +++ b/tests/operations/tests/Payment.mjs @@ -1539,7 +1539,7 @@ TestRegister.addTests([ // ── Parse EMV TLV ───────────────────────────────────────────────────────── { - name: "Parse EMV TLV: GPO Format 2 (constructed 77 > AIP + AFL)", + name: "EMV Parse TLV: GPO Format 2 (constructed 77 > AIP + AFL)", input: "770A82025900940408010401", expectedOutput: JSON.stringify([ { @@ -1552,35 +1552,35 @@ TestRegister.addTests([ ], }, ], null, 4), - recipeConfig: [{ op: "Parse EMV TLV", args: [false] }] + recipeConfig: [{ op: "EMV Parse TLV", args: [false] }] }, { - name: "Parse EMV TLV: primitive tags (ARQC / CID / ATC)", + name: "EMV Parse TLV: primitive tags (ARQC / CID / ATC)", input: "9F2608A1B2C3D4E5F607089F2701809F360200 01", expectedOutput: JSON.stringify([ { tag: "9F26", name: "Application Cryptogram (ARQC/TC/AAC)", constructed: false, class: "Application", source: "ICC", format: "b", length: 8, valueHex: "A1B2C3D4E5F60708" }, { tag: "9F27", name: "Cryptogram Information Data (CID)", constructed: false, class: "Application", source: "ICC", format: "b", length: 1, valueHex: "80" }, { tag: "9F36", name: "Application Transaction Counter (ATC)", constructed: false, class: "Application", source: "ICC", format: "b", length: 2, valueHex: "0001" }, ], null, 4), - recipeConfig: [{ op: "Parse EMV TLV", args: [false] }] + recipeConfig: [{ op: "EMV Parse TLV", args: [false] }] }, { - name: "Parse EMV TLV: unknown tag decoded structurally", + name: "EMV Parse TLV: unknown tag decoded structurally", input: "FF0203AABBCC", expectedMatch: /"name":\s*"Unknown"/, - recipeConfig: [{ op: "Parse EMV TLV", args: [false] }] + recipeConfig: [{ op: "EMV Parse TLV", args: [false] }] }, { - name: "Parse EMV TLV: dictionary mode returns tag index", + name: "EMV Parse TLV: dictionary mode returns tag index", input: "", expectedMatch: /"9F26":/, - recipeConfig: [{ op: "Parse EMV TLV", args: [true] }] + recipeConfig: [{ op: "EMV Parse TLV", args: [true] }] }, { - name: "Parse EMV TLV: bad hex throws", + name: "EMV Parse TLV: bad hex throws", input: "GG", expectedOutput: "Input is not valid hex (odd length or non-hex chars).", - recipeConfig: [{ op: "Parse EMV TLV", args: [false] }] + recipeConfig: [{ op: "EMV Parse TLV", args: [false] }] }, // ── EMV Build Script Data ─────────────────────────────────────────────────