1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
// SPDX-FileCopyrightText: 2026 Jannik Schürg
//
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
use ;
/// A raw APDU-level transport. The implementor handles framing, the
/// NFC layer, USB HID (e.g. ACR1252U), or any other physical channel.
///
/// # Implementing this trait
///
/// ## Connection ownership
///
/// The implementor owns the live reader/card connection and is
/// responsible for establishing it before the first call and tearing
/// it down after the last. [`Session`](crate::Session) borrows the
/// transport mutably for each operation but never opens, closes, or
/// resets it. If the card is removed mid-session, surface the
/// reader's error through [`Self::Error`]; the session is then no
/// longer usable and the caller must drop it.
///
/// The library tracks the *logical* application/EF selection state
/// (NDEF AID, current EF) on the [`Session`](crate::Session) itself,
/// not on the transport. Implementors should not cache or replay
/// `SELECT` APDUs; just forward bytes.
///
/// ## APDU format
///
/// Only ISO 7816-4 *short-form* APDUs are emitted (NT4H2421Gx §8.4):
///
/// - `apdu` is at most `5 + 255 + 1 = 261` bytes (header, 1-byte
/// `Lc`, body, 1-byte `Le`); never extended-length.
/// - All four ISO cases occur. `Le` is included whenever a response
/// is expected (`Le = 0x00` meaning "up to 256 bytes"); case-3
/// commands (e.g. `ISOUpdateBinary`) carry no `Le` byte.
/// - Each call corresponds to exactly one APDU exchange. Multi-frame
/// protocol flows (`ADDITIONAL_FRAME`/`AF` chaining for
/// `ReadData`, `WriteData`, `GetVersion`, the two-leg
/// `AuthenticateEV2*` handshake) are driven by the library across
/// multiple `transmit` calls; the transport must not coalesce or
/// split frames.
///
/// ## Returning a [`Response`]
///
/// `data` must contain the response body **without** the trailing
/// SW1/SW2; those go in the dedicated fields. An empty body is
/// represented by an empty `Self::Data`. Any status word — including
/// non-`9000` codes such as `91AF` (`ADDITIONAL_FRAME`) or `91AE`
/// (`AUTHENTICATION_ERROR`) — must be passed through unchanged: the
/// library parses status words itself and relies on seeing them. Do
/// not translate tag-side errors into `Self::Error`; reserve
/// `Self::Error` for transport/IO failures (reader disconnect,
/// timeout, malformed framing).
///
/// ## `get_uid`
///
/// Must return the UID seen by the reader during ISO/IEC 14443-3
/// anti-collision, as a 4- or 7-byte slice. This is *not* necessarily
/// the tag's permanent UID: a tag in random-ID mode returns a
/// freshly-randomised 4-byte single-size UID (leading byte `0x08`)
/// here, and the permanent UID is only available via the
/// authenticated `GetCardUID` command
/// ([`AuthenticatedSession::get_uid`](crate::AuthenticatedSession::get_uid)).
/// PC/SC readers typically expose this via the `FF CA 00 00 00`
/// pseudo-APDU; see [`ntag424-pcsc`] for a reference implementation.
///
/// ## Concurrency
///
/// The library calls `transmit` and `get_uid` strictly sequentially
/// on a single transport, and both methods take `&mut self`, so
/// implementations need not be `Sync` or re-entrant. A `&mut`
/// transport is threaded through every authenticated operation and
/// command-counter advance, so concurrent use against the same tag
/// would desynchronise the secure channel.
///
/// [`ntag424-pcsc`]: https://crates.io/crates/ntag424-pcsc
/// A response to an APDU command, containing the data and the status words.
///
/// `data` carries the response body only; SW1/SW2 are reported
/// separately in [`Self::sw1`] and [`Self::sw2`].