Conversation
sidcha
force-pushed
the
trs_dev
branch
3 times, most recently
from
July 14, 2026 17:30
dcdb1a3 to
e6e5c66
Compare
TRS tunnels raw smart-card APDUs from the CP, through a PD acting as a transparent pipe, to a card in the reader (OSDP CMD_XWR/REPLY_XRD, capability SMART_CARD_SUPPORT). The control panel drives the card directly, so a compromised reader cannot forge a credential. The CP runs the session as a library-driven state machine: it negotiates transparent mode, streams the app's APDUs, and tears the session down on osdp_cp_trs_stop(). Apps submit OSDP_CMD_XWR commands and receive card responses as OSDP_EVENT_TRS events. The PD answers each APDU either synchronously, in the command callback, or deferred: it ACKs "working" and delivers the response on a later poll once a slow card responds. Deferral keeps a shared multi-drop bus non-blocking, so each PD's session makes progress independently. A Card Present reply is accepted with or without the trailing status byte -- the spec marks it optional (v2.2 section 7.26.8) and readers like the HID RPK40 omit it; the status then reports as unspecified. Gated behind OPT_BUILD_OSDP_TRS (default off); wired into both build systems and covered by a CP<->PD APDU round-trip unit test. Fixes: #22 Co-developed-by: Aaron Tulino (Aaronjamt) <git@aaronjamt.com> Signed-off-by: Siddharth Chandrasekaran <sidcha.dev@gmail.com>
Table 36 marks the mode-config byte optional: in its absence 0x00 is used. The PD decoder demanded both mode and config, NAK-ing a 3-byte Mode-Set that a foreign ACU may legitimately send. Related-to: #22 Signed-off-by: Siddharth Chandrasekaran <sidcha.dev@gmail.com>
The RPK40 NAKs a CARD_SCAN it does not implement with MSG_CHK, which the CP's corrupted-frame heuristic answered with up to eight blind retransmissions before tearing the card session down. Replaying card traffic can have card-side effects (PIN retry counters, transaction state), so CMD_XWR is exempt from the resend heuristic entirely; and since a reader may pick any NAK code it fancies for an unimplemented card command, every NAK to an app-owned card command is a soft failure -- one failed command, session intact -- unless the code says the link itself is broken (SEQ_NUM, SC_UNSUP, SC_COND). The test runs on a plaintext link, as in the field trace: the mock channel rewrites the reader's reply into a NAK(MSG_CHK) at the same sequence number, which is also why the mock gained a no-SCBK device setup -- rewriting a secured reply would desync the MAC chain, which a real quirky reader never does. Related-to: #22 Signed-off-by: Siddharth Chandrasekaran <sidcha.dev@gmail.com>
A reader left in transparent mode -- failed teardown, CP restart -- keeps answering polls with XRD replies. The CP treated those as unknown responses and cycled the PD offline for the full retry penalty, taking a healthy link down over a stale reader mode. Swallow the reply with a warning instead: it is well-formed, it just has no session to route to. The payload is dropped, no event reaches the app, and the link stays up. Related-to: #22 Signed-off-by: Siddharth Chandrasekaran <sidcha.dev@gmail.com>
The 64-byte APDU carrier could not hold what the headline use case moves: PIV certificate reads chain GET RESPONSE chunks up to the short-APDU maximum of 258 bytes (255 data + SW1SW2). Raise the default to 258 behind an #ifndef so constrained builds can dial it back down -- osdp_cmd/osdp_event embed a buffer of this size, so the override is also the memory knob. The usable size is further bound by the negotiated packet size; a C-APDU that cannot fit it is now rejected at submit time instead of failing mid-band. Full-size chunks additionally need -DOSDP_PACKET_BUF_SIZE=512 (default 256). Chunking inside the library would be wrong here: TRS is a transparent tunnel and ISO 7816-4 has its own chaining. Related-to: #22 Signed-off-by: Siddharth Chandrasekaran <sidcha.dev@gmail.com>
The card (emu-card.c, libosdp-free) speaks just enough ISO 7816-4 to model the headline workflow: SELECT of the PIV AID, GET DATA of a 1.2KB certificate-sized object, and 61xx/GET RESPONSE chaining. The scenarios drive it through a real CP<->PD session over the mock channel, modeled on the reader behaviour reported in issue #22: a full chained certificate read, a session that must ride out a busy spell, a permanently-busy reader costing one soft-failed command, and a card leaving the field mid-band with no card-not-present courtesy from the reader. Related-to: #22 Signed-off-by: Siddharth Chandrasekaran <sidcha.dev@gmail.com>
The channel-hook frame parsers assumed the leading mark byte from build options, but its presence also varies by direction and RX mode; detect it from the frame instead. Also add test-pd-zc.c to the lean build's test sources -- the zero-copy unit-test binary never linked there. Related-to: #22 Signed-off-by: Siddharth Chandrasekaran <sidcha.dev@gmail.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
TRS tunnels raw smart-card APDUs from the CP, through a PD acting as a transparent pipe, to a card in the reader (OSDP CMD_XWR/REPLY_XRD, capability SMART_CARD_SUPPORT). The control panel drives the card directly, so a compromised reader cannot forge a credential.
The CP runs the session as a library-driven state machine: it negotiates transparent mode, streams the app's APDUs, and tears the session down on osdp_cp_trs_stop(). Apps submit OSDP_CMD_XWR commands and receive card responses as OSDP_EVENT_TRS events.
The PD answers each APDU either synchronously, in the command callback, or deferred: it ACKs "working" and delivers the response on a later poll once a slow card responds. Deferral keeps a shared multi-drop bus non-blocking, so each PD's session makes progress independently.
Gated behind OPT_BUILD_OSDP_TRS (default off); wired into both build systems and covered by a CP<->PD APDU round-trip unit test.
Co-developed-by: Aaron Tulino (Aaronjamt) git@aaronjamt.com