2021-12-26
Inspired by Filippo Valsorda’s blogpost Touch-to-operate Password-store with Yubikey 4 I recently got an Yubikey myself, trying to build a similar setup. While I’d have preferred getting a solokeyV2/Nitrokey3 these seem to be still in production and not yet available. So for now I will test the YubiKey 5 NFC.
When I run the same commands as Filippo, I get:
$ ykman mode FIDO+CCID
WARNING: The use of this command is deprecated and will be removed!
Replace with: ykman config mode FIDO+CCID
Set mode of YubiKey to FIDO+CCID? [y/N]:
And indeed the newer version works without the warning. However, me being curious by nature, I’d like to see which of the USB modes listed on the ArchLinux wiki page 1 are currently enabled:
$ ykman config mode -h
Usage: ykman config mode [OPTIONS] MODE
Manage connection modes (USB Interfaces).
This command is generaly used with YubiKeys prior to the 5 series. Use "ykman config usb" for more granular
control on YubiKey 5 and later.
Get the current connection mode of the YubiKey, or set it to MODE.
MODE can be a string, such as "OTP+FIDO+CCID", or a shortened form: "o+f+c". It can also be a mode number.
Examples:
Set the OTP and FIDO mode:
$ ykman config mode OTP+FIDO
Set the CCID only mode and use touch to eject the smart card:
$ ykman config mode CCID --touch-eject
Options:
--touch-eject When set, the button toggles the state of the smartcard between ejected and inserted
(CCID mode only).
--autoeject-timeout SECONDS When set, the smartcard will automatically eject after the given time. Implies
--touch-eject (CCID mode only).
--chalresp-timeout SECONDS Sets the timeout when waiting for touch for challenge response.
-f, --force Confirm the action without prompting.
-h, --help Show this message and exit.
Hm, this is maximally unhelpful. It says “Get the current connection
mode” but doesn’t tell me how. A quick glance into the source code 2 shows that this feature seemes to
have been (re)moved. This starts out to be a promising journey… While
back then (tm) config mode
changed the USB mode (FIDO, CCID
or HID), we can now change the actual “applications” that are hidden
behind these USB modes, as listed in the ArchLinux wiki page linked
above.
We now have ykman config usb
(and, they don’t tell you
that, ykman config nfc
for NFC enabled keys…):
$ ykman config usb -l
OTP
FIDO U2F
FIDO2
OATH
PIV
OpenPGP
YubiHSM Auth
(The output for nfc
is the same, by default.)
So let’s disable all modes we don’t need using the new syntax:
$ for mode in OTP OATH HSMAUTH; do
ykman config usb --force --disable "$mode";
ykman config nfc --force --disable "$mode";
done
I disabled OTP based on my understanding that this requires the YubiKey key validation server 3, which goes strongly against my sense of security and secrecy.
I also disable OATH since I won’t store the credentials directly on
the YubiKey but using pass(1)
, but encrypted using the
YubiKey.
Further, I have no use (yet) for HSM authentication.
I leave FIDO/FIDO2 enabled. PIV and OPENPGP smartcard functionality shall stay enabled as well, although we will use OPENPGP mode only for now:
$ gpg --card-edit
[... snip ...]
gpg/card> admin
Admin commands are allowed
gpg/card> passwd
1 - change PIN
2 - unblock PIN
3 - change Admin PIN
4 - set the Reset Code
Q - quit
Your selection?
Change the PIN, Admin PIN (default each “12345678”) and optionally
set a Reset Code. I also set the key-attr
to use ECC
instead of RSA.
Now enabling touch-to-operate:
$ ykman openpgp touch
Usage: ykman openpgp [OPTIONS] COMMAND [ARGS]...
Try 'ykman openpgp -h' for help.
Error: No such command 'touch'.
Hm, so apparently one can set the policy per signing/encryption/authentication or attestation key:
$ for key in SIG ENC AUT ATT; do
ykman openpgp keys set-touch "$key" Fixed;
done
Error: No YubiKey found with the given interface(s)
Error: No YubiKey found with the given interface(s)
Error: No YubiKey found with the given interface(s)
Error: No YubiKey found with the given interface(s)
Uhm. So I went thinking to the bathroom and tried again, and – behold – now the command worked. Except:
Enter Admin PIN:
WARNING: This touch policy cannot be changed without deleting the corresponding key slot!
Set touch policy of signature key to fixed? [y/N]: y^M^M
Okay, so sometimes, when the tool fails/errors, it doesn’t properly reset the terminal settings, so you might need to run
$ stty icrnl
in order for the enter key (carriage return / ^M
) to be
translated to LF that the linux console expects. Anyhow, you can check
whether everything worked using:
$ ykman openpgp info
OpenPGP version: 3.4
Application version: 5.4.3
PIN tries remaining: 3
Reset code tries remaining: 3
Admin PIN tries remaining: 3
Touch policies
Signature key On (fixed)
Encryption key On (fixed)
Authentication key On (fixed)
Attestation key On (fixed)
You can now generate the keys:
$ gpg --card-edit
gpg/card> generate
as described in the original blog post.
You can now use the list
subcommand to list the
available keys:
gpg/card> list
[... snip ...]
Manufacturer .....: Yubico
[... snip ...]
Key attributes ...: ed25519 cv25519 ed25519
[... snip ...]
Signature key ....: 1234 1234 1234 1234 1234 1234 0123 4567 89AB CDEF
created ....: 1970-01-01 00:00:00
Encryption key....: 1234 1234 1234 1234 1234 1234 ABCD EF01 2345 6789
created ....: 1970-01-01 00:00:00
Authentication key: 1234 1234 1234 1234 1234 1234 9876 5432 10FE DCBA
created ....: 1970-01-01 00:00:00
General key info..:
pub ed25519/0123456789ABCDEF 1990-01-01 John Doe (pass PGP key) <john.doe@example.com>
sec> ed25519/0123456789ABCDEF created: 1990-01-01 expires: never
card-no: 0000 00000000
ssb> ed25519/ABCDEF0123456789 created: 1990-01-01 expires: never
card-no: 0000 00000000
ssb> cv25519/9876543210FEDCBA created: 1990-01-01 expires: never
card-no: 0000 00000000
While the 0123456789ABCDEF is the main secret key also used for signatures, the ABCDEF0123456789 is the secret subkey used for encryption and 9876543210FEDCBA the key for authentication.
In order to use pass(1)
we will now run:
$ pass init ABCDEF0123456789
$ pass insert passtestpassword
Enter password for passtestpassword: foobar
Retype password for passtestpassword: foobar
$ pass show passtestpassword
<touch yubikey>
foobar
It works!
We can now export the public key for import in OpenKeychain on Android:
gpg --export --armor 0123456789ABCDEF > pubkey.armor
Send it over to your Android phone and import the key. Then, in the “Keys” menu, open the 3-dot menu, select “Manage my keys” and “Use Security Token”. Hold your security token to your NFC enabled phone (or connect it via USB) and it will now pair the previously imported public key with the private key stored on the Yubikey.
You can now either create a new local repository for storing credentials or use git to synchronize your computers passwords with your Androids.
You can use pass-otp
to generate and store OTPs.
However, if migrating from another application, this might have stored
the TOTP secret as a text key and not as a OTP URI. In that case,
unfortunately the best way forward seems to be to re-enroll using the
new password manager application.
Ideally, we could remove the need for GPG in pass(1)
.
This is worked on with passage 4 which combines pass with
age 5. Using the Rust implementation of
age, rage, and the linked age-plugin-yubikey, the age key can be stored
on the YubiKey as well and thus used for encryption.
Similarly, the Solokey V2 doesn’t support PGP at all, but instead provides only a PKCS PIV smartcard interface instead of an OpenPGP backed on. This can be used for encrypting the password credentials as well, and since YubiKeys also provide such an interface, this would work for both types of keys.
On the desktop side, the former design is already feasable, for
Android this is highly WIP 6. I’m looking forward to
phasing out the GPG encryption key for encrypting my passwords in favor
of age, although this is a separate key anyway, whiches only purpose is
the use for pass(1)
.
Since I need GPG for work, this would then free up my YubiKey to store that GPG key on it instead, or, I’d simply encrypt the GPG key using the age/PKCS from the YubiKey and store it as a separate passwordstore credential.
https://wiki.archlinux.org/title/YubiKey#USB_connection_modes↩︎
https://github.com/Yubico/yubikey-manager/blob/main/ykman/cli/config.py#L514↩︎
https://wiki.archlinux.org/title/YubiKey#Yubico_OTP↩︎
https://github.com/FiloSottile/passage↩︎
https://github.com/FiloSottile/age↩︎
https://github.com/android-password-store/Android-Password-Store/issues/1486↩︎