[EAtT] Secure your GPG keys with a Yubikey 4

If you've followed my article One GPG key pair (to rule them all), you have a GPG primary key with subkeys for encryption, signing, and authentication. The private key for the primary key is safely stored offline, but what about the private keys for the subkeys? In order to actually use the subkeys to sign, encrypt, and authenticate, the private keys need to be available. But if they are stored on your local computer they are subject to compromise by intruders, malware, theft of the computer, etc. The solution to this problem, being able to use your keys while still keeping them secure, is found in a specially-designed piece of hardware called a smartcard. In this article, I'll show you how to secure your private keys by transferring them to a smartcard called a Yubikey.

Smart(card) key storage

Smartcards are specialized cryptography devices that hold and allow the use of cryptographic keys. Once written to key slots on a smartcard, private keys can no longer be read or accessed directly. Instead, when a smartcard user performs cryptographic operations like signing and encrypting, the user application (GPG in this case) passes the request to the smartcard. The smartcard authenticates the request - for example, by requiring that a PIN be entered. If authentication is successful, the card performs the requested task itself using its own processor and the private keys stored on its chip. The smartcard then passes the output of the operation back to the requesting user application.

Through this mechanism the smartcard allows the use of the private keys, without providing the user or any applications direct access to the keys themselves. All cryptographic operations are performed on the smartcard, so key data is never held in the system memory or disk storage of the host. Even if the host computer were to be root-level compromised, the keys would remain safe. The only private key files stored on the computer are stub keys that simply tell GPG information about the smartcard where the actual keys are stored. Those stub keys on their own hold no secret information and cannot be used to perform cryptographic operations absent the smartcard.

The use of a smartcard provides an additional factor of security for your GPG keys. With a standard GPG keyring, anyone might use a GPG key if they have a copy of the key file and know the key's passphrase. Key files may be copied or exfiltrated, and are protected only by filesystem-level permissions.

With the smartcard solution, any user who wants to make use of the GPG keys must have not only the authentication PIN for the card, but physical possession of the card itself. Further, the smartcard is designed in such a way as to make it impossible (as far as we know) to copy or clone the contents to a duplicate card. For additional security, many smartcards also have a built-in kill switch: enter the wrong PIN three times, and the smartcard locks itself and/or wipes its key stores. This countermeasure makes brute force attacks against a smartcard impossible, and with a sufficiently long and randomized PIN the chance of correctly guessing the code in three or less tries is astronomically slim.

The Yubikey 4

Yubico is the manufacturer of USB-enabled smartcards called Yubikeys. Traditional smartcards resemble a credit card or ID card, and must be inserted into a specialized reader slot built in to the host computer, or a standalone reader connected to the computer via USB. Built-in smart card readers are uncommon except in business-class laptops (and even then, only on certain models). The USB readers are cumbersome to carry around and awkward to employ if you're not using a traditional workspace (i.e., a desk in an office). Traditional smartcards and the required hardware to program them also tend to be quite expensive, ranging into the hundreds of dollars in cost to get started.

In contrast, Yubikeys resemble a thin USB flash drive in form. When inserted into a standard USB port of a host computer, a Yubikey presents itself as a smartcard reader with a smartcard inserted. Yubikeys are extremely portable - you can keep one on your regular keyring in your pocket. They also draw their power from the USB port they are inserted into, so no battery or external power source is required. And they are relatively cheap, at around US$40.

The Yubikey 4 is the current model from Yubico. It sports some impressive features including multiple operation modes, a touch sensor, and three key slots that can support up to 4096-bit RSA keys - one each for signing, encryption, and authentication.

Make a backup

Before you begin, be sure that you have a backup copy of the private keys for your GPG subkeys. When you transfer your keys to a Yubikey it is a move operation - not a copy. The private keys will be deleted from your private keyring and replaced with stub keys. Once copied to the Yubikey, there is no way to extract or recover your private keys.

To make a backup of your subkeys, use the command:

$ gpg --export-secret-subkeys -a -o <backupfile.asc>

System requirements

To use your Yubikey with GPG and gpg-agent you will need to install the GPG smartcard support package scdaemon:

$ sudo apt install scdaemon

You may also want to install the Yubikey personalization tool in order to modify your Yubikey's settings:

$ sudo apt install yubikey-personalization

Setting up the Yubikey 4

Before you move your keys to your Yubikey, you should first configure the card. To do so, insert your Yubikey into a USB slot. To verify that GPG can see and use your card, issue the command:

$ gpg --card-status

GPG will print a summary of the card's settings, which should be the defaults. You'll now modify your key to set information fields and PINs. Issue the command:

$ gpg --edit-card

At the prompt, issue the admin command:

gpg/card> admin
Admin commands are allowed

If you use the help command, you will see all of the available options you may configure:

gpg/card> help
quit           quit this menu
admin          show admin commands
help           show this help
list           list all available data
name           change card holder's name
url            change URL to retrieve key
fetch          fetch the key specified in the card URL
login          change the login name
lang           change the language preferences
sex            change card holder's sex
cafpr          change a CA fingerprint
forcesig       toggle the signature force PIN flag
generate       generate new keys
passwd         menu to change or unblock the PIN
verify         verify the PIN and list all data
unblock        unblock the PIN using a Reset Code
factory-reset  destroy all keys and data

The first thing you should do is change your PINs, by using the passwd command:

gpg/card> passwd 
1 - change PIN
2 - unblock PIN
3 - change Admin PIN
4 - set the Reset Code
Q - quit

At a minimum, you will want to change the admin PIN (option 3, default: '12345678') and the user PIN (option 1, default: '123456'). You may also choose to set a reset code (option 4, no default). The reset code (also called the PIN unlock code or 'PUC') is a special admin PIN that can only be used to unblock the user PIN. This option is usually only implemented in corporate environments where Yubikeys are being issued to many users. For personal use, the reset code has limited application. If you do not set the reset code, the admin PIN is used instead to unblock the user PIN.

The user and admin pins are not limited to 6 and 8 digits respectively, and you should feel free to use a longer PIN - particularly for the admin PIN which you should rarely need to use. Record these PINs in your password manager to prevent loss. If the user PIN is incorrectly entered three times, the PIN will become 'blocked' (disabled). Even if correctly entered afterward, the PIN will no longer work until it is unblocked using the reset code (with the unblock command) or with the admin PIN (using the passwd command, option 2). If either the admin PIN or the reset code are entered incorrectly three times the Yubikey will reset to factory defaults, wiping any installed keys.

Other settings you may want to change are url (the URL for the key owner's public key, used by fetch) and login (the key owner's login name). You can also set other informational fields such as the key owner's full name, sex, and preferred language (name, sex, and lang, respectively).

When you're done setting up the Yubikey, issue the quit command:

gpg/card> quit

Transferring your keys

Now you'll transfer your private keys to key slots on your Yubikey, using the GPG --edit-key option:

$ gpg -K

sec#  rsa4096/0x7CD6ACA4C84DA8B3 2017-10-29 [C] [expires: 2020-10-29]
      Key fingerprint = 4C64 592C 9611 E531 1A81  8824 7CD6 ACA4 C84D A8B3
uid                   [ultimate] Rick Demo <rick@demo.com>
ssb   rsa4096/0x582CBC299B4C2718 2017-10-29 [S] [expires: 2018-10-29]
ssb   rsa4096/0x7C97F91B5079A317 2017-10-29 [E] [expires: 2018-10-29]
ssb   rsa4096/0x88C4DD5D965ABA57 2017-10-29 [A] [expires: 2018-10-29]

$ gpg --edit-key rick@demo.com

sec# rsa4096/0x7CD6ACA4C84DA8B3
     created: 2017-10-29  expires: 2020-10-28  usage: C
     trust: ultimate      validity: ultimate
ssb  rsa4096/0x582CBC299B4C2718
     created: 2017-10-29  expires: 2018-10-29  usage: S
ssb  rsa4096/0x7C97F91B5079A317
     created: 2017-10-29  expires: 2018-10-29  usage: E
ssb  rsa4096/0x88C4DD5D965ABA57
     created: 2017-10-29  expires: 2018-10-29  usage: A
[ultimate] (1). Rick Demo <rick@demo.com>

Select your first subkey (in this example, the signing key) by using the key command:

gpg> key 1

The subkey will be denoted with a * to show that it is selected:

sec# rsa4096/0x7CD6ACA4C84DA8B3
     created: 2017-10-29  expires: 2020-10-28  usage: C
     trust: ultimate      validity: ultimate
ssb* rsa4096/0x582CBC299B4C2718
     created: 2017-10-29  expires: 2018-10-29  usage: S
ssb  rsa4096/0x7C97F91B5079A317
     created: 2017-10-29  expires: 2018-10-29  usage: E
ssb  rsa4096/0x88C4DD5D965ABA57
     created: 2017-10-29  expires: 2018-10-29  usage: A
[ultimate] (1). Rick Demo <rick@demo.com>

Now use the keytocard command to transfer the private key. GPG will ask you for the key slot where the key should be installed. This is a signing key, so we'll take option 1:

gpg> keytocard
Please select where to store the key:
(1) Signature key
(3) Authentication key
Your selection? 1

You'll be prompted for the private key passphrase and the admin PIN. After the key is installed, de-select key 1:

gpg> key 1

sec# rsa4096/0x7CD6ACA4C84DA8B3
     created: 2017-10-29  expires: 2020-10-28  usage: C
     trust: ultimate      validity: ultimate
ssb  rsa4096/0x582CBC299B4C2718
     created: 2017-10-29  expires: 2018-10-29  usage: S
ssb  rsa4096/0x7C97F91B5079A317
     created: 2017-10-29  expires: 2018-10-29  usage: E
ssb  rsa4096/0x88C4DD5D965ABA57
     created: 2017-10-29  expires: 2018-10-29  usage: A
[ultimate] (1). Rick Demo <rick@demo.com>

Now repeat this process for key 2 and key 3, assigning them to the Encryption Key (2) and Authentication Key (3) slots, respectively. When you are done, use the save command to exit:

gpg> save

If you do gpg --card-status now, you should see that the keys have been installed on the card. If you do gpg -K you will see that the subkeys are now denoted with a > to show that they are located on a smartcard:

$ gpg -K
sec#  rsa4096/0x7CD6ACA4C84DA8B3 2017-10-29 [C] [expires: 2020-10-29]
      Key fingerprint = 4C64 592C 9611 E531 1A81  8824 7CD6 ACA4 C84D A8B3
uid                   [ultimate] Rick Demo <rick@demo.com>
ssb>  rsa4096/0x582CBC299B4C2718 2017-10-29 [S] [expires: 2018-10-29]
ssb>  rsa4096/0x7C97F91B5079A317 2017-10-29 [E] [expires: 2018-10-29]
ssb>  rsa4096/0x88C4DD5D965ABA57 2017-10-29 [A] [expires: 2018-10-29]

Using GPG with your Yubikey

Using GPG with your Yubikey is almost the same as when your keys were stored locally on your computer, except that instead of being prompted for your key passphrase you will now be prompted for your user PIN. If you are running gpg-agent the PIN will be cached in the same way that your passphrase was cached. If you attempt to use GPG for an operation that requires your keys and your Yubikey is not inserted into the computer at the time, pinentry will prompt you to insert your Yubikey.

Staying in touch with your Yubikey

The Yubikey provides additional protection for your GPG keys by requiring the presence of a physical token (the Yubikey) as well as the knowledge of the user PIN. However, if you run gpg-agent the default settings are to cache the PIN for some period of time after it is entered once. This is convenient, but it also means that your key is subject to unauthorized use if someone were to gain remote access to your computer. If you want to add an additional layer of security, you can require that the Yubikey be touched each time it is used to sign, encrypt, or authenticate, in order to authorize use of the private key. If touch authorization is enabled and you perform a task requiring one of your private keys, you will be prompted to insert the Yubikey (if it is not already inserted), and prompted to enter the PIN (if it has not already been entered and cached by gpg-agent). Then the Yubikey will blink, prompting you to touch its button before the key operation will be performed. If you don't touch the button within 15 seconds, the operation is cancelled.

This feature provides two key benefits:

  1. It gives you a third factor of authentication - your key is only usable to the person sitting in front of the computer, even if the Yubikey is inserted and the PIN is cached.
  2. It gives you a visual indication that your key is being accessed - by you, or by some other user or process.

To enable touch authorization, use the yubitouch.sh bash script by Alessio Di Mauro.

./yubitouch.sh sig on
./yubitouch.sh dec on
./yubitouch.sh aut on

You will be prompted for the Yubikey's admin PIN for each command. If you want to disable touch authorization, use the same command with the off option. You may also use fix instead of on. This will turn on touch authorization and prevent it from being disabled without resetting the Yubikey to factory defaults.

If you use GPG keys on your Yubikey for batch operations, scripts, etc., enabling touch authorization may present a problem for you. Touch authorization requires a touch each time a key is accessed to perform an operation. If your authentication key is on your Yubikey and you run a script that uses SSH to execute a command on 100 servers, you'll be prompted to touch your Yubikey 100 times - not just once when the script is first run.

Yubikey is too touchy

The Yubikey 4 has an integrated button used for various functions in different modes. Its default function is to generate one-time password ('OTP') codes for two-factor authentication. This is a useful feature - unless you aren't using it. In which case it becomes an annoying button that you accidentally touch all the time, causing the key to spit out a long string of digits into whatever application you're working in at the time. This is particularly true of the Yubikey Nano, which is a tiny device that barely protrudes from a USB port and whose entire visible surface is a touch interface.

If you aren't using the Yubikey to generate OTP codes for websites or applications, you can disable that feature to prevent the device from spewing text into your editor or IRC client at the most inappropriate moment possible. To do this, you'll use the ykpersonalize command to set the device's USB mode:

$ ykpersonalize -m1

Will set the device to CCID-only mode, turning off OTP and U2F functionality. The available modes are:

0 OTP device only.
1 CCID device only.
2 OTP/CCID composite device.
3 U2F device only.
4 OTP/U2F composite device.
5 U2F/CCID composite device.
6 OTP/U2F/CCID composite device.

If you change your Yubikey to a non-OTP mode with ykpersonalize you will not be able to change the mode again using the same tool (ykpersonalize only works in OTP mode). If you decide later to re-enable OTP mode, you will need to use the ykman tool. At this time ykman is not packaged in the Debian repos, and will have to be installed from source or via the pip utility (pip install yubikey-manager). The ykman utility is still in beta and is not very well documented at this time.

You may also enable 'eject' functionality. This feature will allow you to 'eject' the smartcard when the Yubikey is touched, making it appear to be removed even though the Yubikey is still inserted in the USB port. Touching the button again will 're-insert' the smartcard. This feature can be convenient if you like to leave your Yubikey installed most of the time (as is often the case with the Yubikey Nano) but only want it to be available for use when you specifically 'insert' it. When you are done, you immediately 'eject' it to keep your keys from being available unnecessarily.

In order to enable the 'eject' flag, add 80 to the mode value (e.g., 81 for CCID only, plus eject).

Do not enable 'eject' if you are also using touch authorization for signing, decryption, or authentication. The two features are mutually incompatible.

Using multiple Yubikeys

There are a couple of scenarios where you might use multiple Yubikeys that hold the same private keys, and each scenario is handled differently.

The 'backup' Yubikey

You might have one Yubikey that is your primary daily key. You keep it on a lanyard or on your keyring, and you carry it around with you. You might also have a backup Yubikey on which you installed the same keys. You might keep that backup in a safe or locked drawer, and only use it if your primary key becomes lost or destroyed.

When you move your private keys from your local disk to a Yubikey, GPG replaces the private key files with 'stub' keys that contain information about where the real keys are stored. In particular, the stubs contain the unique serial number of the Yubikey to which the key was moved with keytocard. If you lose your primary Yubikey and insert your backup, you'll have to re-create the stubs in order for GPG to find your private keys on the new Yubikey (which has a different serial number than the primary). Luckily, that's pretty easy to do.

Just delete the private subkeys from your keyring, and then relearn them from the new Yubikey:

$ gpg --delete-secret-subkeys rick@demo.com
$ gpg --card-status

Multiple Yubikeys: same keys, different computers

People often use the Yubikey Nano as a "permanent" smartcard, leaving it installed in their computer all the time. If you have multiple desktops or laptops you can have a dedicated Yubikey for each. The setup process just needs to be performed for each Yubikey on each computer, using a local keyring that contains the private subkeys (remember that installing the keys on the smartcard is a 'move' operation, not a 'copy' - you can't setup two Yubikeys with the same keys from the same GPG instance). On each computer, start with a copy of your .gnupg directory that contains your private subkeys, and perform the keytocard operations on each machine. This will create stub keys on each computer that point to its dedicated Yubikey.

If you use sync software to keep your GPG keyrings in the same state, be sure to only sync your public keyring. If you sync the private keyring, you'll end up with the same stub keys on every machine and only one will have a card with the correct serial number. For example, if you use Syncthing you might add a line to the .stignore file in the root of your home directory that reads /.gnupg/private-keys-v1.d. This will prevent Syncthing from synchronizing your stub key files.

Keys and cards demystified

I hope that this article has removed some of the mystery around GPG and smartcards, and shown how easy it is to provide a whole new level of security for your GPG keys. As always, if you have comments, questions, or corrections, feel free to send me an email. Thanks for reading.