NFC WebAuthn: evaluate token2-fido-bridge as a PC/SC to USB-HID shim #2

Open
opened 2026-08-20 06:18:47 +00:00 by htayj · 0 comments
htayj commented 2026-08-20 06:18:47 +00:00 (Migrated from github.com)

Problem

Desktop Firefox cannot use an NFC-presented FIDO2 authenticator for WebAuthn.
USB works fine; tapping the same key on the contactless reader does nothing.

This is a Firefox limitation, not a local misconfiguration. Firefox's CTAP2
transport is USB-HID only:

  • libxul.so contains zero PC/SC symbols (SCardEstablishContext,
    winscard, pcsclite all absent)
  • its single hidraw reference sits next to the hidiocgrdescsize() Linux
    HID ioctl and the string Unable to find device

Chromium has the same limitation on Linux. NFC FIDO2 is effectively a mobile
feature, where the OS owns the NFC stack and brokers it to the browser.

Loading opensc-pkcs11.so under Settings > Privacy & Security > Security
Devices does not help. PKCS#11 and WebAuthn are separate code paths in
Firefox: PKCS#11 covers client certificates and S/MIME (and does work over
NFC), but navigator.credentials.get() never consults it.

Candidate solution

https://github.com/token2/token2-fido-bridge

Rather than patching the browser, it presents a virtual USB-HID FIDO
authenticator
through /dev/uhid, translates CTAP-HID frames into ISO 7816
APDUs, and relays them to the card over PC/SC. Firefox sees an ordinary USB
HID key and never knows NFC is involved.

Browser --USB-HID/CTAP--> /dev/uhid --> bridge --PC/SC--> smartcard

Vendor-neutral by design: it speaks standard CTAP2/ISO7816 and is documented
to work with any FIDO2 authenticator visible to PC/SC, not just Token2
hardware. C++, single ~250 KB binary, depends only on libpcsclite.

There is an earlier Python implementation of the same idea at
https://github.com/BryanJacobs/fido2-hid-bridge — larger footprint, but worth
comparing if the C++ one proves troublesome.

Prerequisites already satisfied on basedbox

Confirmed working as of system generation 14:

  • /dev/uhid present; CONFIG_UHID=m and uhid.ko loaded (kernel 7.1.8)
  • pcscd running via pcscd-service-type
  • Reader detected: Alcor Link AK9567 [Contactless Card Reader]
  • YubiKey 5C NFC with NFC transport enabled and FIDO2 enabled over NFC

Work required

  • Clone to ~/reference/external_src/ and review the source. It is a
    0.1.0 release, it runs as root for /dev/uhid, and it relays every CTAP
    exchange between browser and authenticator. That trust boundary deserves
    a read before it goes anywhere near a real credential.
  • Write a Guix package definition (cmake-build-system, pcsc-lite
    input). Not currently packaged in Guix; neither is the Python variant.
  • Translate the shipped systemd unit into a Shepherd service in
    config-k8-plus.scm.
  • Translate packaging/70-token2-fido-bridge.rules via
    udev-rules-service.
  • Test against Firefox 152 (non-Snap) under StumpWM. Upstream has only
    been tested on Ubuntu with Chromium and Snap Firefox, so this
    combination is unproven. The README's snap connect firefox:u2f-devices
    step does not apply here.

Not blocking

USB WebAuthn already works. This is a convenience improvement, so there is no
urgency and no reason to rush the security review.


Imported from GitHub issue/PR. Originally posted by htayj on 2026-08-20T06:18:47Z.

## Problem Desktop Firefox cannot use an NFC-presented FIDO2 authenticator for WebAuthn. USB works fine; tapping the same key on the contactless reader does nothing. This is a Firefox limitation, not a local misconfiguration. Firefox's CTAP2 transport is USB-HID only: - `libxul.so` contains zero PC/SC symbols (`SCardEstablishContext`, `winscard`, `pcsclite` all absent) - its single `hidraw` reference sits next to the `hidiocgrdescsize()` Linux HID ioctl and the string `Unable to find device` Chromium has the same limitation on Linux. NFC FIDO2 is effectively a mobile feature, where the OS owns the NFC stack and brokers it to the browser. Loading `opensc-pkcs11.so` under Settings > Privacy & Security > Security Devices does **not** help. PKCS#11 and WebAuthn are separate code paths in Firefox: PKCS#11 covers client certificates and S/MIME (and does work over NFC), but `navigator.credentials.get()` never consults it. ## Candidate solution https://github.com/token2/token2-fido-bridge Rather than patching the browser, it presents a **virtual USB-HID FIDO authenticator** through `/dev/uhid`, translates CTAP-HID frames into ISO 7816 APDUs, and relays them to the card over PC/SC. Firefox sees an ordinary USB HID key and never knows NFC is involved. Browser --USB-HID/CTAP--> /dev/uhid --> bridge --PC/SC--> smartcard Vendor-neutral by design: it speaks standard CTAP2/ISO7816 and is documented to work with any FIDO2 authenticator visible to PC/SC, not just Token2 hardware. C++, single ~250 KB binary, depends only on `libpcsclite`. There is an earlier Python implementation of the same idea at https://github.com/BryanJacobs/fido2-hid-bridge — larger footprint, but worth comparing if the C++ one proves troublesome. ## Prerequisites already satisfied on basedbox Confirmed working as of system generation 14: - `/dev/uhid` present; `CONFIG_UHID=m` and `uhid.ko` loaded (kernel 7.1.8) - `pcscd` running via `pcscd-service-type` - Reader detected: `Alcor Link AK9567 [Contactless Card Reader]` - YubiKey 5C NFC with NFC transport enabled and FIDO2 enabled over NFC ## Work required - [ ] Clone to `~/reference/external_src/` and review the source. It is a 0.1.0 release, it runs as root for `/dev/uhid`, and it relays every CTAP exchange between browser and authenticator. That trust boundary deserves a read before it goes anywhere near a real credential. - [ ] Write a Guix package definition (`cmake-build-system`, `pcsc-lite` input). Not currently packaged in Guix; neither is the Python variant. - [ ] Translate the shipped systemd unit into a Shepherd service in `config-k8-plus.scm`. - [ ] Translate `packaging/70-token2-fido-bridge.rules` via `udev-rules-service`. - [ ] Test against Firefox 152 (non-Snap) under StumpWM. Upstream has only been tested on Ubuntu with Chromium and Snap Firefox, so this combination is unproven. The README's `snap connect firefox:u2f-devices` step does not apply here. ## Not blocking USB WebAuthn already works. This is a convenience improvement, so there is no urgency and no reason to rush the security review. --- Imported from [GitHub issue/PR](https://github.com/htayj/src/issues/2). Originally posted by [htayj](https://github.com/htayj) on 2026-08-20T06:18:47Z.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
tay/src#2
No description provided.