diff mbox series

[4/4] hw/usb/u2f-passthru: Implement FIDO U2FHID keep-alive

Message ID 20240625145350.65978-5-dbouman03@gmail.com (mailing list archive)
State New
Headers show
Series hw/usb/u2f-passthru: U2F keepalive fixes | expand

Commit Message

David Bouman June 25, 2024, 2:53 p.m. UTC
FIDO U2FHID features a keep-alive response command (code 0xbb). A
keep-alive response signifies that the request is being processed
and the transaction should not be closed yet.

u2f-passthru does not recognize this command, and hence closes the
transaction prematurely upon receiving it. This prevents some U2F
security keys from being passed through correctly (Yubikey 4/5).

Fix this by recognizing the keep-alive response and, if received,
by keeping the transaction alive regardless of the resp_bcnt limit.

Signed-off-by: David Bouman <dbouman03@gmail.com>
Fixes: 299976b050bf (hw/usb: Add U2F key passthru mode)
Resolves: https://gitlab.com/qemu-project/qemu/-/issues/2293
---
 hw/usb/u2f-passthru.c | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)
diff mbox series

Patch

diff --git a/hw/usb/u2f-passthru.c b/hw/usb/u2f-passthru.c
index d0fb7b377c..c1e4db3467 100644
--- a/hw/usb/u2f-passthru.c
+++ b/hw/usb/u2f-passthru.c
@@ -296,10 +296,14 @@  static void u2f_passthru_recv_from_host(U2FPassthruState *key,
         return;
     }
 
+    bool keepalive = false;
     if (packet_is_init(packet)) {
         transaction->resp_bcnt = packet_init_get_bcnt(packet);
         transaction->resp_size = PACKET_INIT_DATA_SIZE;
 
+        if (packet->init.cmd == U2FHID_CMD_KEEPALIVE)
+            keepalive = true;
+
         if (packet->cid == BROADCAST_CID) {
             /* Nonce checking for legitimate response */
             if (memcmp(transaction->nonce, packet->init.data, NONCE_SIZE)
@@ -312,7 +316,7 @@  static void u2f_passthru_recv_from_host(U2FPassthruState *key,
     }
 
     /* Transaction end check */
-    if (transaction->resp_size >= transaction->resp_bcnt) {
+    if (!keepalive && transaction->resp_size >= transaction->resp_bcnt) {
         u2f_transaction_close(key, cid);
     }
     u2f_send_to_guest(&key->base, raw_packet);