Linux setup¶
The dongle needs no kernel driver. What the host needs:
| Component | Needed for | Package (Debian/Ubuntu) |
|---|---|---|
libfido2 |
FIDO2 command-line tools (fido2-token); browsers bring their own FIDO stack |
libfido2-1, fido2-tools |
pcscd + libccid |
The OpenPGP card (CCID smart-card reader) | pcscd, libccid |
gnupg, scdaemon |
gpg signing, decryption, SSH agent | gnupg, scdaemon |
| udev rules | Access without root; keep ModemManager away | see below |
| libccid patch | libccid does not know cafe:4001 yet |
see below |
On NixOS one module does all of it. On other distributions follow the manual steps.
NixOS¶
{
inputs.nixtropic.url = "github:jjacke13/nixtropic";
# configuration.nix
imports = [ inputs.nixtropic.nixosModules.tropic ];
services.tropic.enable = true;
services.tropic.users = [ "your-username" ]; # adds you to the `tropic` group
}
The module installs the udev rules for all three USB identities, enables pcscd
with a patched libccid, and creates the tropic group. services.tropic.enableCcid
= false skips pcscd if you only use FIDO2. Then continue with
GnuPG configuration.
Other distributions¶
sudo apt install -y pcscd libccid pcsc-tools libfido2-1 fido2-tools gnupg scdaemon opensc
udev rules¶
sudo groupadd -f tropic
sudo usermod -aG tropic "$USER" # log out and back in afterwards
sudo tee /etc/udev/rules.d/70-nixtropic.rules >/dev/null <<'EOF'
# Stock firmware (USB serial bridge)
SUBSYSTEM=="tty", ATTRS{idVendor}=="0483", ATTRS{idProduct}=="5740", GROUP="tropic", MODE="0660", SYMLINK+="tropic01", ENV{ID_MM_DEVICE_IGNORE}="1", TAG+="uaccess"
SUBSYSTEM=="usb", ATTRS{idVendor}=="0483", ATTRS{idProduct}=="5740", GROUP="tropic", MODE="0660", ENV{ID_MM_DEVICE_IGNORE}="1", TAG+="uaccess"
# nixtropic: no GROUP on the usb node, pcscd may run as its own user and needs it
SUBSYSTEM=="usb", ATTRS{idVendor}=="cafe", ATTRS{idProduct}=="4001", MODE="0660", ENV{ID_MM_DEVICE_IGNORE}="1", TAG+="uaccess"
SUBSYSTEM=="hidraw", ATTRS{idVendor}=="cafe", ATTRS{idProduct}=="4001", GROUP="tropic", MODE="0660", TAG+="uaccess"
# STM32 DFU bootloader
SUBSYSTEM=="usb", ATTRS{idVendor}=="0483", ATTRS{idProduct}=="df11", GROUP="tropic", MODE="0660", ENV{ID_MM_DEVICE_IGNORE}="1", TAG+="uaccess"
EOF
sudo udevadm control --reload-rules && sudo udevadm trigger
ID_MM_DEVICE_IGNORE stops ModemManager from probing the serial port. The hidraw
rule lets browsers open the FIDO interface even where the security-device tag is
missing.
The libccid patch¶
libccid drives only readers on its built-in VID:PID list, and nixtropic still uses
TinyUSB's demonstration ID cafe:4001 (a registered ID is on the
backlog). Without the patch pcscd sees the device, refuses to drive
it, and gpg --card-status says No such device.
INFO=/usr/lib/pcsc/drivers/ifd-ccid.bundle/Contents/Info.plist
sudo cp "$INFO" "$INFO.bak"
sudo awk '
/<key>ifdVendorID<\/key>/ { stage="vid"; print; next }
/<key>ifdProductID<\/key>/ { stage="pid"; print; next }
/<key>ifdFriendlyName<\/key>/ { stage="name"; print; next }
/<\/array>/ {
if (stage == "vid") print "\t\t<string>0xCAFE</string>"
if (stage == "pid") print "\t\t<string>0x4001</string>"
if (stage == "name") print "\t\t<string>nixtropic CCID Reader</string>"
stage = ""; print; next
}
{ print }
' "$INFO.bak" | sudo tee "$INFO" >/dev/null
grep -q 0xCAFE "$INFO" && sudo systemctl restart pcscd
A libccid package update reverts the patch; run the block again afterwards.
GnuPG¶
These settings apply to every distribution, NixOS included.
disable-ccid
pcsc-shared
enable-ssh-support
gpgconf --kill scdaemon
gpg-connect-agent updatestartuptty /bye
gpg --card-status
Why both scdaemon options:
disable-ccidmakesscdaemonusepcscdinstead of its own USB driver. With the built-in driver,scdaemonclaims the CCID interface directly; when the browser then uses the FIDO interface of the same device, the claim can hang until the dongle is replugged. Throughpcscdthe two interfaces stay independent.pcsc-sharedopens the reader in shared mode, so a restartedscdaemonor a second program can attach without restartingpcscd.
YubiKey users
With disable-ccid + pcsc-shared, a YubiKey also goes through pcscd and may
ask for its PIN more often. If that bothers you, comment the two lines out while
the nixtropic dongle is not in use.
After a replug¶
scdaemon keeps a handle to the old USB device. After every flash, reboot or replug:
gpgconf --kill scdaemon # host-side handle only, the card loses nothing
gpg --card-status
If it still says No such device, restart pcscd (sudo systemctl restart pcscd)
and then unplug and replug the dongle: pcscd attaches a reader only on a USB
plug event.
SSH¶
With enable-ssh-support, gpg-agent serves the card's authentication key:
export SSH_AUTH_SOCK="$(gpgconf --list-dirs agent-ssh-socket)"
ssh-add -L # the public key to put in authorized_keys
FIDO2 troubleshooting¶
Work down the list:
- Enumerated?
lsusb | grep cafe:4001 - Seen by libfido2?
fido2-token -L - Answers GetInfo?
fido2-token -I /dev/hidrawN - Browser access?
ls -l /dev/hidrawNshould show a+(ACL for your user);udevadm info /dev/hidrawN | grep TAGSshould includeuaccess. - Browser logs:
about:webauthnin Firefox,chrome://device-login Chromium.
More WebAuthn detail: WebAuthn notes.
Windows and macOS¶
Windows has its own page: Windows (OpenPGP card works; FIDO2 with a PIN needs v0.3.1). On macOS, FIDO2 works with v0.3.2 in a Chromium browser (registration and login, PIN set, no driver install); the OpenPGP card is untested there.