From fec3f85fad35866d89bc2b1878018ee57899a908 Mon Sep 17 00:00:00 2001 From: Stuart Longland Date: Sun, 23 Jul 2023 20:34:41 +1000 Subject: [PATCH] CcidTransceiver: Poke device again if we get zero-sized packet. --- .../securitytoken/usb/CcidTransceiver.java | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/securitytoken/usb/CcidTransceiver.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/securitytoken/usb/CcidTransceiver.java index d14c102f3..188fcfce5 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/securitytoken/usb/CcidTransceiver.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/securitytoken/usb/CcidTransceiver.java @@ -275,7 +275,20 @@ public class CcidTransceiver { } private CcidDataBlock receiveDataBlockImmediate(byte expectedSequenceNumber) throws UsbTransportException { - int readBytes = usbConnection.bulkTransfer(usbBulkIn, inputBuffer, inputBuffer.length, DEVICE_COMMUNICATE_TIMEOUT_MILLIS); + /* + * Some USB CCID devices (notably NitroKey 3) may time-out and need a subsequent poke to + * carry on communications. No particular reason why the number 3 was chosen. If we get a + * zero-sized reply (or a time-out), we try again. Clamped retries prevent an infinite loop + * if things really turn sour. + */ + int attempts = 3; + Timber.d("Receive data block immediate seq=%d", expectedSequenceNumber); + int readBytes; + do { + readBytes = usbConnection.bulkTransfer(usbBulkIn, inputBuffer, inputBuffer.length, DEVICE_COMMUNICATE_TIMEOUT_MILLIS); + Timber.d("Received " + readBytes + " bytes: " + toHexString(inputBuffer)); + } while ((readBytes <= 0) && (attempts-- > 0)); + if (readBytes < CCID_HEADER_LENGTH) { throw new UsbTransportException("USB-CCID error - failed to receive CCID header"); }