Conversation
CCID 1.10 §6.2.1 lets RDR_to_PC_DataBlock signal that the response APDU is split across multiple frames via the bChainParameter byte at offset 9 of the header. UsbSmartCardConnection.sendAndReceive() previously read the first frame, silently truncated via Math.min(received, dwLength), and returned. For YubiKeys the response always fits in one frame so the bug never surfaced. For contactless USB CCID readers (HID OMNIKEY 5022-CL etc.) reading anything bigger than ~500 B — e.g. a PIV CHUID or facial image — the response came back mid-byte. Fix: parse bChainParameter into a per-connection field; if it's 0x01 (first) or 0x03 (middle), pull each subsequent chunk via a follow-up PC_to_RDR_XfrBlock with wLevelParameter = 0x0010 (CCID §6.1.4) and an empty data field until the reader reports 0x00 (complete) or 0x02 (last). Concatenate the chunks before returning. Adds testChainedResponse exercising a three-frame chained response.
Cap a reassembled chained response at the largest response APDU ISO 7816-4 can express, reject an empty continuation chunk rather than looping on it, and extract responseIsChained() so the two continuation states are named in one place. Adds five cases: two-frame chain, last-without-first, unchained, empty continuation chunk, and both sides of the length cap.
The default USB filter matches the Yubico vendor id, so no test could reach a third-party smart card reader and the chaining paths in UsbSmartCardConnection had no hardware coverage. CcidReaderFilter widens it to any device exposing a CCID interface; YubiKeys are still admitted unchanged. ExternalCcidReaderTests echoes payloads up to 2048 bytes off a YubiKey in the reader's field and compares byte for byte, since a reader that drops a chunk still answers SW 9000. It fails rather than skips when the reader is absent, so it cannot report green untested.
Read dwFeatures and dwMaxCCIDMessageLength from the reader's CCID class descriptor. A reader offering only the TPDU exchange level expects the host to frame T=1 blocks itself, which this class does not do, so it is now refused at open instead of being sent APDU-level XfrBlocks.
The host never split a command APDU exceeding the reader's dwMaxCCIDMessageLength, so the OMNIKEY 5022-CL (520 bytes) dropped the overflow and the card echoed stale buffer under SW 9000. Split it across XfrBlock messages chained via wLevelParameter and require an acknowledgement for each non-final chunk.
Heading stays "Next version" until the release version is decided.
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.
Reads the CCID class descriptor to discover the reader's buffer limit, reassembles multi-frame responses via bChainParameter (CCID 1.10 §6.2.1), and splits command APDUs that exceed dwMaxCCIDMessageLength across frames using wLevelParameter chaining; TPDU-only readers are detected and rejected with a clear error.
Fixes silent data corruption on contactless readers such as the HID OMNIKEY 5022-CL, where large responses were split across frames (returning truncated data) and large command APDUs overflowed the reader's 520-byte buffer (corrupting the card's view of the command from byte 495 onward).
Unit tests cover all bChainParameter values, empty-chunk rejection, the reassembly cap, and frame-boundary cases;
ExternalCcidReaderTestsround-trips payloads up to 2048 bytes through an OMNIKEY 5022-CL with a YubiKey 5 NFC in its field;SmokeDeviceTests(29 tests, YubiKey direct-attached) confirmed no regression on the normal USB path.