YubiKey, Void Linux and GPG
Context
The Yubikey 4 is an HSM that can be used to store GPG keys, among other things.
After following Lars Wirzenius’ tutorial in an air-gapped Tails live session, we had 3 subkeys in our Yubikey, which then we tested in the same live session with simple commands like:
$ echo "Secret Message" > test.txt
$ gpg --encrypt -r user@example.com test.txt
... here we enter our YK pin, test.txt.gpg is created.
$ gpg --decrypt --output test.output.txt test.txt.gpg
$ diff test.txt test.output.txt
Signing also worked properly, and after removing the Yubikey decryption was not possible: a pinentry popup asked us to insert the card, and then enter the PIN.
After that, we imported our public key in our main Void Linux system, connected our
Yubikey and ran gpg2 --card-status
to generate the private key stubs that tell GPG to
look for private keys in the Yubikey, instead of the keyring.
Problem
Interacting with the card is possible only as root.
$ gpg2 --card-status
gpg: selecting openpgp failed: No such device
gpg: OpenPGP card not available: No such device
# gpg2 --card-status
Reader ...........: 1050:0407:X:0
Application ID ...: D2760001240102000087596366710000
Version ..........: 2.1
Manufacturer .....: Yubico
Serial number ....: [redacted]
Name of cardholder: Cristian Ojeda Flores
... and so on.
Solution
Install the following packages from the repo:
gnupg2-scdaemon
libu2f-host
From the following pinentry packages, install those you need:
pinentry
: for CUI/CLI programs, like gpg2 and [maybe] mutt.pinentry-emacs
: for GNU/Linux/Emacs OS users. Haven’t tried it myself, though.pinentry-gtk
: required for pinentry in Thunderbird with the Enigmail plugin.pinentry-qt
: Qt programs, but haven’t used it myself.
Copy /usr/lib/udev/rules.d/70-u2f.rules to /etc/udev/rules.d/70-u2f.rules (if there’s no /etc/udev/rules.d/ then create it).
Change the following in /etc/udev/rules.d/70-u2f.rules:
# Yubico YubiKey
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1050", ATTRS{idProduct}=="0113|0114|0115|0116|0120|0200|0402|0403|0406|0407|0410", MODE="0660", GROUP="plugdev"
To:
# Yubico YubiKey
ATTRS{idVendor}=="1050", ATTRS{idProduct}=="0113|0114|0115|0116|0120|0200|0402|0403|0406|0407|0410", MODE="0660", GROUP="plugdev"
Create the plugdev group if needed (friendly reminder: check /etc/groups). Add your user to it.
# groupadd plugdev
# usermod -a -G plugdev YOUR_USER
Finally, you may also want to install ykpers
, which contains the ykpersonalize
command to make additional changes in the Yubikey (change operation modes, etc.). I don’t
use it.
Relog or reboot.
How it works?
The root user can access the device, so we know it’s not an issue of missing drivers or any other similar fuckery. What’s not so obvious however, is the message that GPG gives us:
$ gpg2 --card-status
gpg: selecting openpgp failed: No such device
gpg: OpenPGP card not available: No such device
However, trying to use ykpersonalize
uncovers the real issue:
$ ykpersonalize
USB error: access denied
The access error as normal user (but not as root) has to do with udev rules. As usual, there’s info on the ArchWiki: udev - ArchWiki.
Now, at some point I read about installing libu2f-host
, but I don’t remember where
(maybe it came preinstalled?). The important part is, that it contains a very useful
udev rule written for us.
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1050", ATTRS{idProduct}=="0113|0114|0115|0116|0120|0200|0402|0403|0406|0407|0410", MODE="0660", GROUP="plugdev"
1050 is the vendor id for Yubico, and 0407 is the product id of our YubiKey 4, so this rule should give any member of the plugdev group r+w access to the card.
We can verify the vendor and product id of USB devices by running lsusb
:
$ lsusb | grep -i yubikey
Bus 005 Device 012: ID 1050:0407 Yubico.com Yubikey 4 OTP+U2F+CCID
But, there’s something odd: the rule matches only the HID raw subsystem, and we got an USB error.
We found a related issue on GitHub: libu2f-host udev rule not triggering. And just as
it says, removing the KERNEL and SUBSYSTEM attributes causes the rule to match USB
devices too. We can check that by simply running ls
:
ls -la /dev/bus/usb/005/012
crw-rw---- 1 root plugdev 189, 524 Apr 30 17:38 /dev/bus/usb/005/012