YubiKey-5 Guide

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

Required Software

In order to follow this guide, you will need YubiKey Manager, GNU Privacy Guard (GnuPG), and OpenSSH client and key management tools.

NixOS

On NixOS, the following settings are recommended somewhere in your configuration.

{
  programs.gnupg.agent = {
    enable = true;
    enableSSHSupport = true;
    enableBrowserSocket = true;
  };

  programs.gnupg.dirmngr = {
    enable = true;
  };

  programs.yubikey-touch-detector = {
    enable = true;
  };

  environment.systemPackages = with pkgs; [
    gnupg
    openssh
    yubikey-manager
    yubioath-flutter
  ];
}

Debian

On Debian-based Linux systems, install the following packages.

apt install gnupg openssh-client yubikey-manager yubioath-desktop

Ensure that your ~/.gnupg/gpg-agent.conf enables ssh-agent 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

YubiKey Configuration

If you have multiple YubiKeys, follow the instructions in this section for each YubiKey.

Connect the YubiKey to your computer and collect some device information.

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 YubiKey’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.

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 guide sets the application string to include the YubiKey owner’s name and the YubiKey’s serial number, which is useful when working with multiple YubiKeys or when creating multiple FIDO SSH keys on one YubiKey.

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

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 on a new or reset device, 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 to 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. Including the YubiKey’s serial number in the USER-ID simplifies configuring multiple YubiKeys in code signing, file encryption, and SSH authentication.

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

Set the User Interaction Flags (UIF) to require touch confirmation for all OpenPGP subkeys (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 ....: SSSS SSSS SSSS SSSS SSSS  SSSS SSSS SSSS SSSS SSSS
      created ....: YYYY-MM-DD hh:mm:ss
Encryption key....: EEEE EEEE EEEE EEEE EEEE  EEEE EEEE EEEE EEEE EEEE
      created ....: YYYY-MM-DD hh:mm:ss
Authentication key: AAAA AAAA AAAA AAAA AAAA  AAAA AAAA AAAA AAAA AAAA
      created ....: YYYY-MM-DD hh:mm:ss
General key info..: pub  ed25519/0xSSSSSSSSSSSSSSSS YYYY-MM-DD John Doe <john.doe+yubikey-xxxxxxxx@example.com>
sec>  ed25519/0xSSSSSSSSSSSSSSSS  created: YYYY-MM-DD  expires: never
                                  card-no: xxxx xxxxxxxx
ssb>  ed25519/0xEEEEEEEEEEEEEEEE  created: YYYY-MM-DD  expires: never
                                  card-no: xxxx xxxxxxxx
ssb>  cv25519/0xAAAAAAAAAAAAAAAA  created: YYYY-MM-DD  expires: never
                                  card-no: xxxx xxxxxxxx

If you need to add additional user identities (such as an email address without the YubiKey’s serial number) to the OpenPGP key, specify the fingerprint of the key to edit.

gpg --edit-key 0xSSSSSSSSSSSSSSSS

Add the new user identity to the key.

gpg> adduid

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

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

Select the new user identity and set the trust level.

gpg> uid 2

gpg> trust
...
  1 = I don't know or won't say
  2 = I do NOT trust
  3 = I trust marginally
  4 = I trust fully
  5 = I trust ultimately
  m = back to the main menu

Your decision? 5

Save your changes to the key.

gpg> save

Upload Your Public Key to Key Servers

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

gpg --send-keys 0xSSSSSSSSSSSSSSSS

If you are using the keys.openpgp.org key server, 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 0xSSSSSSSSSSSSSSSS | curl -T - https://keys.openpgp.org/

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

Using YubiKeys From New Computers

Now that you have the FIDO and OpenPGP applications configured on at least one YubiKey, it is time to configure each of your computers for any of your YubiKeys that you might use from that computer.

Ensure that the required software from the beginning of this guide is installed on each new computer.

FIDO From New Computers

To configure a new computer with the FIDO OpenSSH key, connect the YubiKey and download the resident key handle.

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" (empty for no passphrase):
Enter same passphrase again:
Saved ED25519-SK key ssh:john.doe+yubikey-xxxxxxxx to id_ed25519_sk_rk_john.doe+yubikey-xxxxxxxx

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:

The application string (specified when creating the key) is automatically included in the file names. When using multiple YubiKeys prepared this way, each YubiKey will have have its own pair of 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 id_ed25519_sk
ln -s id_ed25519_sk_rk_john.doe+yubikey-xxxxxxxx.pub id_ed25519_sk.pub

OpenPGP From New Computers

To configure a new computer with the OpenPGP key, connect the YubiKey, fetch the public key from the key servers, and check the card status to connect that YubiKey to the matching public key.

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

Using YubiKeys With Remote Services

Now that you have the FIDO and OpenPGP applications configured on at least one YubiKey, and you have at least one computer configured to work with those YubiKeys, it is time to configure remote services to use your YubiKeys for authentication and signing.

Yubico maintains a Works with YubiKey catalog where you can search for websites and services that are verified to work with YubiKeys.

Website Authentication

Each YubiKey-5 device can store up to 100 FIDO2 Passkeys and supports an unlimited number of unique FIDO Universal 2nd Factor (U2F) registrations.

For each of your online accounts, check the Works with YubiKey catalog. However, even if a website isn’t verified in that catalog, check the Two-Factor Authentication (2FA) settings in your account to see if the website supports either FIDO2 Passkeys or FIDO Universal 2nd Factor (U2F) tokens.

Register all of your YubiKeys with each supported website.

I recommend naming each registered Passkey or U2F token in your account like this:

yubikey-xxxxxxxx

That way, you can easily match each physical YubiKey to the corresponding authentication entry in each online account. If a YubiKey is ever lost/stolen/reset/destroyed, you know exactly which Passkey or U2F token to remove from each of your accounts.

SSH Authentication

FIDO in SSH

OpenSSH version 8.3 added native support for FIDO2 authenticator keys.

When you prepared to use FIDO from new computers, the resulting ~/.ssh/id_ed25519_sk_rk_john.doe+yubikey-xxxxxxxx.pub files each contain the OpenSSH public key for one YubiKey. Place the retrieved public keys into the OpenSSH authorized_keys files on remote systems and add the public keys to your accounts at SSH-based services like GitHub or GitLab.

cat ~/.ssh/id_ed25519_sk_rk_john.doe+yubikey-xxxxxxxx.pub
sk-ssh-ed25519@openssh.com ... ssh:john.doe+yubikey-xxxxxxxx

In GitHub and GitLab, I recommend naming the FIDO SSH keys like this:

fido:john.doe+yubikey-xxxxxxxx

This distinguishes between FIDO and OpenPGP SSH keys in your account if you are using both types.

OpenPGP in SSH

The following command uses the ssh-agent support that you enabled in gpg-agent to retrieve the OpenSSH-formatted form of the OpenPGP authentication public key from the currently connected YubiKey. Connect each of your YubiKeys, one at a time, and place the retrieved public keys into the OpenSSH authorized_keys files on remote systems and add the public keys to your accounts at 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.

In GitHub and GitLab, I recommend naming the OpenPGP SSH keys like this:

openpgp:john.doe+yubikey-xxxxxxxx

This distinguishes between FIDO and OpenPGP SSH keys in your account if you are using both types.

Harden OpenSSH

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

Git Commit Signing

OpenPGP in Git

Get the OpenPGP public key fingerprint for the currently connected YubiKey.

gpg --card-status
...
General key info..: pub  ed25519/0xSSSSSSSSSSSSSSSS ...
...

Export the corresponding ASCII armored OpenPGP public key and subkeys.

gpg --export --armor 0xSSSSSSSSSSSSSSSS
-----BEGIN PGP PUBLIC KEY BLOCK-----
...
-----END PGP PUBLIC KEY BLOCK-----

Add that OpenPGP public key block to your GitHub or GitLab accounts.

In both GitHub and GitLab, all identities in the public key are extracted and displayed.