OpenSSH key management with YubiKey PIV and FIDO2

As my SSH keys for both work and private infrastructure are quite valuable to me I like to have those as secure as fairly possible. The YubiKey provides two features that help in managing my OpenSSH private and public keys.

With the PIV feature the key can generate and store OpenSSH private keys. The FIDO2 feature however stores public keys - think of them as identities. Without FIDO2 the public key is generated on each device and hence you don’t have a portable key-pair. The OpenSSH 8.6+ agent is capable of loading identities from a smart card out-of-the-box, otherwise the individually generated public keys are used by the agent to load the private key from the smart card.

Configure a backup key - This does not get old

As these hardware tokens are unique by design it is pretty easy to lock yourself out of everything should you loose the key in any way. I can’t stress on this fact enough. Therefore I always have a second key ready for registration to services or generating private keys which is always kept somewhere safe.

Pre-requisites

You’ll need two packages from the official Fedora repositories: pam_yubico and yubikey-manager.

sudo dnf install -y pam_yubico yubikey-manager

Setup PIV and FIDO2

Change the PIN, PUK and Management Key of the PIV module of your key. Default PIN is 123456 and PUK is 12345678.

$ ykman piv access change-pin
Enter the current PIN: 123456
Enter the new PIN: ********
Repeat for confirmation: ********
New PIN set.

$ ykman piv access change-puk
Enter the current PUK: 12345678
Enter the new PUK: ********
Repeat for confirmation: ********
New PUK set.

$ ykman piv access change-management-key --generate --protect
Enter the current management key [blank to use default key]:
Enter PIN: ********

Set a PIN to the FIDO2 module.

$ ykman fido access change-pin
Enter the current PIN: 123456
Enter the new PIN: ********
Repeat for confirmation: ********
New PIN set.

Generate a private key

Generate a private key (e.g. ED25519) with touch and pin requirement in the 9a slot:

$ ykman piv keys generate --algorithm ED25519 --pin-policy ONCE --touch-policy ALWAYS 9a public.pem
Enter PIN: ********

The slot 9a is for “PIV Authentication”.

Create a self-signed certificate for that key. The only use for the X.509 certificate is to satisfy PIV/PKCS #11 lib. It is needed to extract the public key from the smart card.

$ ykman piv certificates generate --subject "CN=OpenSSH" --hash-algorithm SHA384 9a pubkey.pem
Enter PIN: ********
Touch your YubiKey…

Generate a resident public key

Use OpenSSH ssh-keygen to generate a public key you can later use in authorized_keys files on remote systems. The following generates such a key directly on the YubiKey in a FIDO2 slot, making it portable.

ssh-keygen -t ed25519-sk -O resident -O application=ssh:fedora -O verify-required

The resident option instructs ssh-keygen to store the key handle on the YubiKey, making it easier to use the key across multiple systems as ssh-add can load the and use the SSH keys from the YubiKey directly. The application option assigns a designated name for the this specific private-public-key-pair and is useful if working with different SSH identities. The verify-required option is mandatory for resident keys and adds requirement to enter a pin on key usage.

If the key is generated with a touch requirement only omit the verify-required option. If you don’t want to use FIDO2 slots omit the resident and application options and make sure to backup generated public keys.

Caching OpenSSH connections

In OpenSSH default configuration you’ll be prompted to touch your key every time you connect to a machine. To let your OpenSSH client cache connections even after you close the terminal session and thus don’t need to touch the key again add the following option to your ~/.ssh/config:

Host *
    ControlMaster auto
    ControlPath ~/.ssh/S.%r@%h:%p
    ControlPersist 5m

This will persist a session for 5 more minutes after you stop using it.

Introspection

Get information on the PIV slot 9a:

$ ykman piv info
PIV version: 5.4.3
PIN tries remaining: 3/3
Management key algorithm: TDES
CHUID:	REDACTED
CCC: 	No data available.
Slot 9a:
	Algorithm:	RSA2048
	Subject DN:	CN=SSH key
	Issuer DN:	CN=SSH key
	Serial: REDACTED
	Fingerprint: REDACTED
	Not before:	2022-01-01 20:00:00
	Not after:	2023-01-01 20:00:00

List stored FIDO2 public keys with:

$ ykman fido credentials list
ssh:fedora 0000000000000000000000000000000000000000000000000000000000000000 openssh

Any thoughts of your own?

Feel free to raise a discussion with me on Mastodon or drop me an email.

Licenses

The text of this post is licensed under the Attribution 4.0 International License (CC BY 4.0). You may Share or Adapt given the appropriate Credit.

Any source code in this post is licensed under the MIT license.