Skip to content

feat(emv): add nfc_emv_aip_decode — EMV Application Interchange Profile (tag 82) field decode#70

Merged
xunholy merged 1 commit into
mainfrom
feat/emv-aip-decode
Jun 20, 2026
Merged

feat(emv): add nfc_emv_aip_decode — EMV Application Interchange Profile (tag 82) field decode#70
xunholy merged 1 commit into
mainfrom
feat/emv-aip-decode

Conversation

@xunholy

@xunholy xunholy commented Jun 20, 2026

Copy link
Copy Markdown
Owner

What

Adds nfc_emv_aip_decode, extending the nfc_emv_* decode family (Track-2 / DOL / AFL / CVM-List) to the Application Interchange Profile (tag 82) — the 2-byte bitfield the BER-TLV walker named but never decoded.

The AIP is the single most security-relevant field on an EMV card dump: it advertises the card's offline data-authentication method (SDA / DDA / CDA), plus cardholder verification, issuer authentication, and terminal risk management.

Decode

Byte 1's seven defined bits per EMV 4.3 Book 3, Annex C1:

bit mask meaning
7 0x40 SDA supported
6 0x20 DDA supported
5 0x10 Cardholder verification supported
4 0x08 Terminal risk management to be performed
3 0x04 Issuer authentication supported
2 0x02 On-device cardholder verification (EMV 4.3+)
1 0x01 CDA supported

An offline_data_authentication headline picks the strongest method present (CDA > DDA > SDA), flagging SDA-only cards as replayable/clone-prone and no-offline-auth cards as online-only.

No confidently-wrong output

Byte 1 bit 8 and the whole of byte 2 are RFU in the contact profile (contactless kernels repurpose byte 2), so they're surfaced raw with a note, never guessed. Gated structurally to exactly 2 bytes. Accepts the 2-byte AIP value directly or a full EMV BER-TLV blob (tag 82 auto-extracted). Offline transform, transmits nothing → Low risk.

Verification

The decode is a direct mask of the published EMV bit table, so the per-bit vectors are authoritative. Tests cover: each byte-1 bit in isolation; realistic combined values (7C00 offline-DDA card, 1800 online-only, 0500 CDA); the CDA>DDA>SDA headline precedence; RFU notes; and the 2-byte structural gate.

  • gofmt / go vet clean
  • golangci-lint run ./...0 issues
  • go test -race ./internal/emv/ ./internal/risk/ ./internal/tools/ → all ok
  • registry-size (676→677), risk-consistency, gated-set tests green

Wired

internal/emv/{aip.go,aip_test.go}, internal/tools/emv_aip.go, risk.go (Low), registry_size_test.go (count + comment), gap-analysis EMV row.

…le (tag 82) field decode

The nfc_emv_* family already cracks the structured EMV fields the BER-TLV
walker surfaces raw — Track-2 (tag 57), DOL lists, AFL (tag 94), CVM List
(tag 8E). The Application Interchange Profile (tag 82) was named by the
tag dictionary but its 2-byte bitfield was never decoded, even though it is
the single most security-relevant field on an EMV card dump: it advertises
which offline data-authentication method the card supports (SDA / DDA / CDA),
plus cardholder verification, issuer authentication and terminal risk
management.

nfc_emv_aip_decode cracks it. Byte 1's seven defined bits are decoded per
EMV 4.3 Book 3, Annex C1 (SDA 0x40, DDA 0x20, cardholder verification 0x10,
terminal risk management 0x08, issuer authentication 0x04, on-device CVM
0x02 [EMV 4.3+], CDA 0x01). An offline_data_authentication headline picks
the strongest method present (CDA > DDA > SDA), flagging SDA-only cards as
replayable/clone-prone and no-offline-auth cards as online-only — the
takeaway an analyst actually wants.

No confidently-wrong output: byte 1 bit 8 and the whole of byte 2 are RFU
in the EMV Book 3 contact profile (contactless kernels repurpose byte 2),
so they are surfaced raw with a note rather than guessed. Gated structurally
to exactly 2 bytes. Accepts either the 2-byte AIP value directly or a full
EMV BER-TLV blob (tag 82 extracted automatically). Offline transform —
reads bytes, transmits nothing — so it is Low risk like the rest of the
EMV decode family.

Verification: the decode is a direct mask of the published EMV bit table,
so the single-bit vectors (each byte-1 bit in isolation) are authoritative;
plus realistic combined values (7C00 offline-DDA card, 1800 online-only,
0500 CDA), the CDA>DDA>SDA headline precedence, and RFU-note + 2-byte-gate
rejection paths. gofmt / go vet / golangci-lint (0 issues) /
go test -race (emv, risk, tools) all green.

Wired: internal/emv/{aip.go,aip_test.go}, internal/tools/emv_aip.go,
risk.go classification (Low, consistency test green), registry_size_test.go
676 -> 677 (count + comment), and the gap-analysis EMV row.
@xunholy xunholy merged commit 3b673cf into main Jun 20, 2026
10 of 11 checks passed
@xunholy xunholy deleted the feat/emv-aip-decode branch June 20, 2026 02:31
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