YubiKey-5 Guide

Don’t let your PGP or SSH keys be copied from your computer. Protect your keys in an OpenPGP Card.

You may want to review the typographical conventions used on this site.

Introduction

Test that your computer can interact with the YubiKey.

ykman info
Device type: YubiKey 5 NFC
Serial number: xxxxxxxx
Firmware version: 5.7.1
...

Make note of the YubiKey’s serial number. This guide includes the device’s serial number, in a string like yubikey-xxxxxxxx, as part of credential identifiers to simplify using multiple YubiKeys.

FIDO/FIDO2/Passkey

You can display basic FIDO configuration information with the command:

ykman fido info

The stored FIDO2/Passkey credentials can be listed with the command:

ykman fido credentials list

Reset FIDO

You can delete all FIDO credentials and restore factory settings with the command:

ykman fido reset

Configure FIDO

Increase the minimum PIN length from four to six.

ykman fido access set-min-length 6

Change the FIDO PIN from the default 123456.

ykman fido access change-pin

Always require user verification.

ykman fido config toggle-always-uv

Generate a resident FIDO authenticator key for use with SSH. Resident keys store key handle information on the authenticator that simplify using the authenticator on multiple computers.

The default OpenSSH application string is only ssh:, and must always begin with ssh:. This tutorial sets the application string to include the YubiKey owner’s name and the YubiKey’s serial number.

ssh-keygen -t ed25519-sk \
    -O resident \
    -O verify-required \
    -O application=ssh:john.doe+yubikey-xxxxxxxx@example.com

The FIDO configuration information should now look something like this:

ykman fido info
AAGUID:                       xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
PIN:                          8 attempt(s) remaining
Minimum PIN length:           6
Always Require UV:            On
Credential storage remaining: 99

OpenPGP

You can display basic OpenPGP configuration information with the command:

ykman openpgp info

More detailed OpenPGP configuration information can be displayed using GnuPG:

gpg --card-status

Reset OpenPGP

You can delete all OpenPGP keys and data and restore factory settings with the command:

ykman openpgp reset

The output from the reset shows that the default reset code is not set, the default admin PIN is 12345678, and the default user PIN is 123456.

Configure OpenPGP

Start a GnuPG session to configure the OpenPGP application; enable required admin commands.

gpg --card-edit
gpg/card> admin
Admin commands are allowed

Enable Key Derived Function (KDF) support. KDF can only be enabled right after reset, before changing any PINs or generating any keys. Use list to verify the KDF setting before proceeding.

gpg/card> kdf-setup

gpg/card> list
...
KDF setting ......: on
...

Change the user PIN, admin PIN, and reset code.

gpg/card> passwd

Every PGP signature generation should require entering the user PIN. The forcesig command toggles the current setting, so verify the setting is correct with list after toggling.

gpg/card> forcesig

gpg/card> list
...
Signature PIN ....: forced
...

Set the YubiKey owner’s surname/last and given/first names.

gpg/card> name
Cardholder's surname: Doe
Cardholder's given name: John

Set the YubiKey owner’s preferred language as an ISO 639 two-letter language code.

gpg/card> lang
Language preferences: en

By default, the YubiKey OpenPGP application generates RSA 2048 keys. We want to change key generation to use either RSA 4096 or Curve 25519. The following example configures Curve 25519. Use list to verify the settings.

gpg/card> key-attr

Changing card key attribute for: Signature key
Please select what kind of key you want:
   (1) RSA
   (2) ECC
Your selection? 2
Please select which elliptic curve you want:
   (1) Curve 25519 *default*
   (4) NIST P-384
   (6) Brainpool P-256
Your selection? 1
The card will now be re-configured to generate a key of type: ed25519

Changing card key attribute for: Encryption key
Please select what kind of key you want:
   (1) RSA
   (2) ECC
Your selection? 2
Please select which elliptic curve you want:
   (1) Curve 25519 *default*
   (4) NIST P-384
   (6) Brainpool P-256
Your selection? 1
The card will now be re-configured to generate a key of type: cv25519

Changing card key attribute for: Authentication key
Please select what kind of key you want:
   (1) RSA
   (2) ECC
Your selection? 2
Please select which elliptic curve you want:
   (1) Curve 25519 *default*
   (4) NIST P-384
   (6) Brainpool P-256
Your selection? 1
The card will now be re-configured to generate a key of type: ed25519

gpg/card> list
...
Key attributes ...: ed25519 cv25519 ed25519
...

Generate OpenPGP keys on the YubiKey using the configured key attributes. The following example declines making an off-card backup (so private key material never leaves the YubiKey), sets the key lifetime to never expire, and configures the USER-ID for the keys to include the YubiKey’s serial number.

gpg/card> generate

Make off-card backup of encryption key? (Y/n) n

Please specify how long the key should be valid.
         0 = key does not expire
      <n>  = key expires in n days
      <n>w = key expires in n weeks
      <n>m = key expires in n months
      <n>y = key expires in n years
Key is valid for? (0)
Key does not expire at all
Is this correct? (y/N) y

GnuPG needs to construct a user ID to identify your key.

Real name: John Doe
Email address: john.doe+yubikey-xxxxxxxx@example.com
Comment:
You selected this USER-ID:
    "John Doe <john.doe+yubikey-xxxxxxxx@example.com>"

Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? O

Require touch confirmation for all OpenPGP keys (1 = Sign, 2 = Decrypt, 3 = Auth). Use list to verify the settings.

gpg/card> uif 1 on

gpg/card> uif 2 on

gpg/card> uif 3 on

gpg/card> list
...
UIF setting ......: Sign=on Decrypt=on Auth=on
...

Quit the GnuPG card-edit session.

gpg/card> quit

Set the number of allowed PIN retries to something slightly more forgiving than the default three. Eight attempts is reasonable and matches the FIDO application for consistency.

ykman openpgp access set-retries 8 8 8

Verify the OpenPGP settings with the following commands:

ykman openpgp info
OpenPGP version:            3.4
Application version:        5.7.1
PIN tries remaining:        8
Reset code tries remaining: 8
Admin PIN tries remaining:  8
Require PIN for signature:  Always
KDF enabled:                True
Signature key:
  Fingerprint:  xxxx xxxx xxxx xxxx xxxx  xxxx xxxx xxxx xxxx xxxx
  Touch policy: On

Decryption key:
  Fingerprint:  xxxx xxxx xxxx xxxx xxxx  xxxx xxxx xxxx xxxx xxxx
  Touch policy: On

Authentication key:
  Fingerprint:  xxxx xxxx xxxx xxxx xxxx  xxxx xxxx xxxx xxxx xxxx
  Touch policy: On
gpg --card-status
Reader ...........: Yubico YubiKey FIDO CCID 00 00
Application ID ...: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Application type .: OpenPGP
Version ..........: 3.4
Manufacturer .....: Yubico
Serial number ....: xxxxxxxx
Name of cardholder: John Doe
Language prefs ...: en
Salutation .......:
URL of public key : [not set]
Login data .......: [not set]
Signature PIN ....: forced
Key attributes ...: ed25519 cv25519 ed25519
Max. PIN lengths .: 127 127 127
PIN retry counter : 8 8 8
Signature counter : 4
KDF setting ......: on
UIF setting ......: Sign=on Decrypt=on Auth=on
Signature key ....: xxxx xxxx xxxx xxxx xxxx  xxxx xxxx xxxx xxxx xxxx
      created ....: YYYY-MM-DD hh:mm:ss
Encryption key....: xxxx xxxx xxxx xxxx xxxx  xxxx xxxx xxxx xxxx xxxx
      created ....: YYYY-MM-DD hh:mm:ss
Authentication key: xxxx xxxx xxxx xxxx xxxx  xxxx xxxx xxxx xxxx xxxx
      created ....: YYYY-MM-DD hh:mm:ss
General key info..: pub  ed25519/xxxxxxxxxxxxxxxx YYYY-MM-DD John Doe <john.doe+yubikey-xxxxxxxx@example.com>
sec>  ed25519/xxxxxxxxxxxxxxxx  created: YYYY-MM-DD  expires: never
                                card-no: xxxx xxxxxxxx
ssb>  ed25519/xxxxxxxxxxxxxxxx  created: YYYY-MM-DD  expires: never
                                card-no: xxxx xxxxxxxx
ssb>  cv25519/xxxxxxxxxxxxxxxx  created: YYYY-MM-DD  expires: never
                                card-no: xxxx xxxxxxxx

Upload Your Public Key to the Keyservers

To make your OpenPGP public key easy to find, you can upload your public key to the keyservers.

gpg --send-keys XXXXXXXXXXXXXXXX

If you are using the keys.openpgp.org keyserver, you need to verify each email address by which your public key should be searchable. Execute the following command, copy the returned URL into your web browser, and follow the instructions at that URL.

gpg --export XXXXXXXXXXXXXXXX | curl -T - https://keys.openpgp.org/

Information about the design and privacy of keys.openpgp.org is available at the following links.

OpenSSH Support

FIDO2 in OpenSSH

OpenSSH version 8.3 added native support for FIDO2 authenticator keys.

GnuPG in OpenSSH

Ensure that your ~/.gnupg/gpg-agent.conf enables ssh-agent support.

# Enable OpenSSH Agent (ssh-agent) protocol support.
enable-ssh-support

Ensure that your ~/.profile tells ssh to use gpg-agent instead of ssh-agent.

if [ -z "$SSH_AUTH_SOCK" ]; then
    export SSH_AUTH_SOCK="$(gpgconf --list-dirs agent-ssh-socket)"
fi

Kill any running ssh-agent and gpg-agent processes for your user so that the new gpg-agent settings can take effect.

killall -u ${USER} ssh-agent gpg-agent

Log out and log in to set the session environment variables required for ssh to use gpg-agent instead of ssh-agent. Then check that gpg can still see your YubiKey, which has the side-effect of ensuring that gpg-agent is running.

gpg --card-status

At this point, ssh should be able to use the authentication key slot on the YubiKey as an SSH authentication key.

The following command retrieves the SSH-formatted public key from the YubiKey. Place the retrieved public key into the OpenSSH authorized_keys file on the appropriate systems and register the public key with SSH-based services like GitHub or GitLab.

ssh-add -L
ssh-ed25519 ... cardno:XXXXXXXXXX

If multiple public keys are listed, the authentication Key on the YubiKey is the one that ends with a card number comment that contains the serial number of that YubiKey.

Harden OpenSSH

Now that you have a YubiKey that can be used for SSH public key authentication, you should harden your OpenSSH configuration to disable SSH password authentication.

Using the YubiKey on a New Computer

FIDO2

To configure a new system with the FIDO2 OpenSSH key:

cd ~/.ssh
ssh-keygen -K
Enter PIN for authenticator:
You may need to touch your authenticator to authorize key download.
Enter passphrase for "id_ed25519_sk_rk_john.doe+yubikey-xxxxxxxx@example.com" (empty for no passphrase):
Enter same passphrase again:
Saved ED25519-SK key ssh:john.doe+yubikey-xxxxxxxx@example.com to id_ed25519_sk_rk_john.doe+yubikey-xxxxxxxx@example.com

Since the private key never leaves the YubiKey, must be unlocked with a PIN, and every use requires touch authorization, using an empty password on the OpenSSH key handle is acceptable.

The above command downloads the resident key handle from the YubiKey and creates two files:

You can specify which YubiKey to use by specifying the key handle with ssh -i, or you can create symbolic links from the default key handle files to the desired YubiKey files.

cd ~/.ssh
ln -s id_ed25519_sk_rk_john.doe+yubikey-xxxxxxxx@example.com id_ed25519_sk
ln -s id_ed25519_sk_rk_john.doe+yubikey-xxxxxxxx@example.com.pub id_ed25519_sk.pub

OpenPGP

To configure a new system with the OpenPGP key, fetch your public key from the keyservers, plug in the YubiKey, and check the card status to connect that YubiKey to the matching public key.

gpg --recv-keys XXXXXXXXXXXXXXXX
gpg --card-status