Skip to content

onlykey-agent fails after another app uses the OnlyKey #88

@haplo

Description

@haplo

On Linux, onlykey-agent intermittently fails to open the OnlyKey's HID interface with a OSError: open failed error. It then works fine on the next invocation.

The issue can be reliably reproduced when the OnlyKey was just used by another application (e.g. KeePassXC HMAC-SHA1 challenge-response) or after a previous onlykey-agent run was interrupted with CTRL-C.

Environment

Arch Linux, hidapi with the cython backend resolving to libusb (libhidapi-libusb).

$ B=/home/fidel/.local/share/uv/tools/onlykey-agent/lib/python3.13/site-packages
$ ldd "$B/hid.cpython-313-x86_64-linux-gnu.so"    | grep -i usb
# uses libusb
libusb-1-150b88da.0.so.0.1.0 => /home/fidel/.local/share/uv/tools/onlykey-agent/lib/python3.13/site-packages/hidapi.libs/libusb-1-150b88da.0.so.0.1.0 (0x00007efee2c00000)
$ ldd "$B/hidraw.cpython-313-x86_64-linux-gnu.so" | grep -i usb
# no libusb

Symptoms

# Do one of these things:
# 1. Open a KeepassXC DB using Onlykey for HMAC
# 2. Run `onlykey-agent` but abort with CTRL-C when seeing the button challenge.
#    Then complete the challenge in OnlyKey and try onlykey-agent again.

$ onlykey-agent <identity> -- ssh <server>
ERROR  failed to connect  [client.py]
Traceback (most recent call last):
  File ".../onlykey/client.py", line ..., in _connect
    self._hid.open_path(self.path)
  File "hid.pyx", line 158, in hid.device.open_path
OSError: open failed

Re-running the exact same command immediately afterward succeeds. Notably, waiting any amount of time does not help, only running the command a second time does.

The problem: libusb-backed hidapi

On my setup, hid.enumerate() returned libusb-style paths and zeroed usage pages:

path=b'1-3:1.2' usage_page=0x0 interface_number=2 ...

The hidraw backend reports:

path=b'/dev/hidraw14' usage_page=0xf1d0 interface_number=2 ...

Running udevadm monitor --udev --subsystem-match=hidraw when using the libusb-backed hidapi shows how the device id increments every time (0026, 0027, 0028...) as libusb detaches/reattaches the kernel driver:

UDEV  [6514.362533] remove   /devices/pci0000:00/0000:00:02.1/0000:05:00.0/0000:06:0c.0/0000:13:00.0/usb1/1-3/1-3:1.0/0003:1D50:60FC.0026/hidraw/hidraw12 (hidraw)
UDEV  [6514.478417] add      /devices/pci0000:00/0000:00:02.1/0000:05:00.0/0000:06:0c.0/0000:13:00.0/usb1/1-3/1-3:1.0/0003:1D50:60FC.0027/hidraw/hidraw12 (hidraw)
UDEV  [6515.641427] remove   /devices/pci0000:00/0000:00:02.1/0000:05:00.0/0000:06:0c.0/0000:13:00.0/usb1/1-3/1-3:1.0/0003:1D50:60FC.0027/hidraw/hidraw12 (hidraw)
UDEV  [6515.980519] add      /devices/pci0000:00/0000:00:02.1/0000:05:00.0/0000:06:0c.0/0000:13:00.0/usb1/1-3/1-3:1.0/0003:1D50:60FC.0028/hidraw/hidraw12 (hidraw)
UDEV  [6516.220419] remove   /devices/pci0000:00/0000:00:02.1/0000:05:00.0/0000:06:0c.0/0000:13:00.0/usb1/1-3/1-3:1.0/0003:1D50:60FC.0028/hidraw/hidraw12 (hidraw)
UDEV  [6516.565550] add      /devices/pci0000:00/0000:00:02.1/0000:05:00.0/0000:06:0c.0/0000:13:00.0/usb1/1-3/1-3:1.0/0003:1D50:60FC.0029/hidraw/hidraw12 (hidraw)

Fix

Prefer the hidraw backend on Linux, with a fallback to the current hid one. The change is minimal in onlykey/client.py. I will submit a PR with this fix.

The hidraw module exposes the same API, so no other code changes should be needed.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions