OpenPGP Keys on a YubiKey
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.
Threat Model
PGP or SSH keys stored in files on your computer are susceptible to theft. Maybe a browser exploit allows an attacker to upload a copy of your private keys to their web server. Maybe you left your terminal unlocked and unattended for a few minutes, and someone copied your private keys to a USB drive or across the network.
Storing your private keys in an OpenPGP Card, instead of in files on your computer, prevents the theft of your private keys without physically stealing your OpenPGP Card.
Buy a YubiKey
Yubico’s YubiKey is one of the best OpenPGP Cards on the market. The YubiKey also provides Smart Card (PIV), Universal 2nd Factor (U2F), FIDO2, and One-Time-Password (OTP) features in the same device. However, this tutorial focuses on the OpenPGP features of the YubiKey.
You can buy a YubiKey 5 for about $45 from the Yubico store or from Amazon.
Install the Required Linux Software
Install the required GnuPG, Smart Card, and YubiKey packages.
apt-get install pcscd opensc
apt-get install pinentry-curses pinentry-gtk2 pinentry-qt
apt-get install gnupg gpg gpg-agent dirmngr scdaemon
apt-get install yubikey-manager
Configure scdaemon
~/.gnupg/scdaemon.conf
# Power down smartcards after the specified number of seconds of inactivity.
# The user will need to enter the PIN again after the next power up.
card-timeout 900 # 15 minutes.
# Disable the integrated support for CCID compliant readers.
# This allows using pcsc (instead of conflicting with it).
disable-ccid
Generate an Offline Key Pair
Before generating a new OpenPGP key pair, you should harden your GnuPG configuration so that the hardened settings are used when generating new keys and subkeys.
Your offline key pair must be on a normally-offline, and preferably encrypted, storage device in order to guard against theft while still allowing you to recover from a lost or stolen YubiKey. A bootable encrypted Linux on USB is a great place to generate and store your offline key pair. If your offline key storage is bootable, install and configure the same software as above.
In the following example session, some of the lengthy or repetitive output has been trimmed in the interest of length and clarity.
Generate a new master key that is only capable of certifying other keys.
gpg --expert --full-gen-key
Please select what kind of key you want:
(8) RSA (set your own capabilities)
Your selection? 8
Possible actions for a RSA key: Sign Certify Encrypt Authenticate
Current allowed actions: Sign Certify Encrypt
(S) Toggle the sign capability
(E) Toggle the encrypt capability
(A) Toggle the authenticate capability
(Q) Finished
Your selection? S
Your selection? E
Possible actions for a RSA key: Sign Certify Encrypt Authenticate
Current allowed actions: Certify
Your selection? Q
RSA keys may be between 1024 and 4096 bits long.
What keysize do you want? (2048) 4096
Please specify how long the key should be valid.
Key is valid for? (0) 2y
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@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
Edit your new key and add several single-purpose subkeys.
gpg --expert --edit-key XXXXXXXXXXXXXXXX
Add a signature-only RSA subkey.
gpg> addkey
Please select what kind of key you want:
(4) RSA (sign only)
Your selection? 4
RSA keys may be between 1024 and 4096 bits long.
What keysize do you want? (2048) 4096
Please specify how long the key should be valid.
Key is valid for? (0) 2y
Is this correct? (y/N) y
Really create? (y/N) y
Add an encryption-only RSA subkey.
gpg> addkey
Please select what kind of key you want:
(6) RSA (encrypt only)
Your selection? 6
RSA keys may be between 1024 and 4096 bits long.
What keysize do you want? (2048) 4096
Please specify how long the key should be valid.
Key is valid for? (0) 2y
Is this correct? (y/N) y
Really create? (y/N) y
Add an authentication-only RSA subkey.
gpg> addkey
Please select what kind of key you want:
(8) RSA (set your own capabilities)
Your selection? 8
Possible actions for a RSA key: Sign Encrypt Authenticate
Current allowed actions: Sign Encrypt
(S) Toggle the sign capability
(E) Toggle the encrypt capability
(A) Toggle the authenticate capability
(Q) Finished
Your selection? S
Your selection? E
Your selection? A
Possible actions for a RSA key: Sign Encrypt Authenticate
Current allowed actions: Authenticate
Your selection? Q
RSA keys may be between 1024 and 4096 bits long.
What keysize do you want? (2048) 4096
Please specify how long the key should be valid.
Key is valid for? (0) 2y
Is this correct? (y/N) y
Really create? (y/N) y
Save your changes and exit the key editing session.
gpg> save
Copy Subkeys into the YubiKey
Backup your keys and subkeys before loading the subkeys into the YubiKey. This is required because loading the subkeys into the YubiKey actually removes the subkeys from the keyring files and moves them to the YubiKey. These backup files preserve an offline copy of keys and subkeys.
gpg --armor --output XXXXXXXXXXXXXXXX_public.asc --export XXXXXXXXXXXXXXXX
gpg --armor --output XXXXXXXXXXXXXXXX_secret.asc --export-secret-keys XXXXXXXXXXXXXXXX
Copy the public-key-only XXXXXXXXXXXXXXXX_public.asc
to your regular online computer.
Edit your key to move subkeys from your keyring to the YubiKey.
gpg --edit-key XXXXXXXXXXXXXXXX
Transfer your signature-only subkey to the YubiKey’s signature key slot.
gpg> key 1
gpg> keytocard
Please select where to store the key:
(1) Signature key
(3) Authentication key
Your selection? 1
gpg> key 1
Transfer your encryption-only subkey to the YubiKey’s encryption key slot.
gpg> key 2
gpg> keytocard
Please select where to store the key:
(2) Encryption key
Your selection? 2
gpg> key 2
Transfer your authentication-only subkey to the YubiKey’s authentication key slot.
gpg> key 3
gpg> keytocard
Please select where to store the key:
(3) Authentication key
Your selection? 3
gpg> key 3
Save your changes and exit the key editing session.
gpg> save
Unplug the YubiKey, delete the card-migrated keys, and re-import your backed up private keys.
gpg --delete-secret-and-public-key XXXXXXXXXXXXXXXX
gpg --import XXXXXXXXXXXXXXXX_secret.asc
At this point you should shutdown, offline, and safely store your offline keys.
Go to your regular online computer and import the public key and subkeys. Then plug in the YubiKey and check the YubiKey’s card status to connect that YubiKey to the matching public key and subkeys.
gpg --import XXXXXXXXXXXXXXXX_public.asc
gpg --card-status
Harden YubiKey OpenPGP Settings
The three-letter parameters are short for (sig)nature, (dec)ryption, and (aut)hentication.
ykman openpgp set-touch sig On
ykman openpgp set-touch enc On
ykman openpgp set-touch aut On
Check the current settings with the following command.
ykman openpgp info
Change the YubiKey PINs
Connect your YubiKey to your computer and edit the OpenPGP card settings.
gpg --card-edit
Whenever you have a gpg/card>
prompt,
help
shows the currently available commands
and list
shows the current OpenPGP card settings.
Several of the commands used in this session are not available
until after the admin
command is run.
You can run help
before and after running the admin
command
to see the general differences in the available commands.
gpg/card> admin
Admin commands are allowed
The YubiKey’s default user PIN is 123456
,
the default admin PIN is 12345678
,
and the default reset PIN is unset.
You need to change these PINs.
gpg/card> passwd
1 - change PIN
2 - unblock PIN
3 - change Admin PIN
4 - set the Reset Code
Q - quit
Your selection? 1
Your selection? 3
Your selection? 4
Your selection? Q
I want every signature generation to require entering my 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
While you are editing the OpenPGP card, you can also set your name, sex, preferred language, and other settings.
gpg/card> name
Cardholder's surname: Doe
Cardholder's given name: John
gpg/card> sex
Sex ((M)ale, (F)emale or space): M
gpg/card> lang
Language preferences: en
Quit the session once you are done editing the OpenPGP card settings.
gpg/card> quit
Upload Your Public Key to the Keyservers
At this point, you should have an encrypted offline backup of your keys and subkeys, a copy of your private subkeys loaded into your YubiKey, your public key and subkeys on your computer and linked to your YubiKey, and your YubiKey settings personalized and hardened.
You are now ready to upload your public key and subkeys 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
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 ~/.ssh/authorized_keys
on the appropriate systems and register the public key
with SSH-based services like GitHub or GitLab.
ssh-add -L
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.
ssh-rsa ... cardno:XXXXXXXXXXXX
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
Fetch your public key from the keyservers. Then plug in the YubiKey and check the YubiKey’s card status to connect that YubiKey to the matching public key and subkeys.
gpg --recv-keys XXXXXXXXXXXXXXXX
gpg --card-status