Use A YubiKey For PGP Signing, Encryption, And Authentication

As you know, based on a few of the tutorials that I’ve published recently, I have a YubiKey that I’ve been learning how to take full advantage of. In previous tutorials I demonstrated how to implement U2F in your web application, but most YubiKey devices do so much more than just U2F authentication. For example, the YubiKey NEO and YubiKey 5 have support for U2F, FIDO2, OpenPGP, OTP, and a bunch of other crazy technologies.

In this tutorial, we’re going to explore using the YubiKey as a smart card for storing our PGP signing, encryption, and authentication subkeys.

Before we get too invested in this tutorial, I want to point out that I’m using a Mac. While a Mac is not a requirement, if you’re using Windows, the steps will likely be different. If you’re using Linux, you can probably follow along with little to no problems. Also note that you should be making and maintaining a backup of everything we do in case you end up wiping out your keys. Finally, note that I am not an expert with PGP. I’ve followed several guides and made plenty of mistakes which I’m hoping to clear up in this tutorial. If you think something should be changed to make it better, let me know your thoughts in the comments.

Generating a Primary PGP Key with Signing, Encryption, and Authentication Subkeys

Before we can start using the YubiKey for any PGP related task we need to create our primary key and related subkeys. There are technically two ways to do this:

Generate the keys directly on the YubiKey device. Generate the keys locally and then import (move) them onto the YubiKey device.

Which route you choose is totally up to you, but hear me out on why I think the second approach is the better approach. Once your secret key is on the YubiKey device it cannot be exported from the device. If you lose your YubiKey then having a backup likely won’t happen. If you create your keys locally, you can create a backup of your keys before moving them onto the device. However, once you move your keys onto the device, you’re in the same scenario as the first option. This is why making a backup first is a critical first step.

Knowing what you know now, we need to create our keys. We’re going to do this locally. I’m using MacGPG, also known as GPG Suite or GPG Tools for Mac. However, you could easily use Homebrew to install gnupg which would be more comparable to what you’d find on Linux.

If you’re using MacGPG, choose to create a new key.

When creating a new key, make sure to provide your name as well as the email that you wish to associate your key with. While a password is optional, I strongly advise you to create a strong password. For added security, increase the key length to 4096 and give it an expiration.

If you’re not using MacGPG, you can create your new key by executing the following:

gpg --full-generate-key

The above command should present you with a few questions similar to what is found in MacGPG. Answer them the same as what I had mentioned previously.

At this time you should have a primary key created with signing and encryption abilities, unless you specified differently. The primary key will allow you to create subkeys and revoke subkeys which is what we want because if our YubiKey ever became lost or stolen we could just invalidate the subkeys without an issue.

If you’re using MacGPG, view the details of your key and choose SubKeys.

The YubiKey can store a signing key, an encryption key, and an authentication key. You can store your primary key on the YubiKey, but I would advise against that. Remember, anything you move onto your YubiKey only exists on the YubiKey, unless you made a back up. Even if you made a backup, remember your primary key is like a master key. The primary key should be stored offline in a safe place and probably not in your pocket.

Even though MacGPG can add new subkeys, you may consider using strictly the command line instead. From what I’ve found MacGPG won’t create authentication subkeys, only signing and encryption.

From the command line, you can execute the following:

gpg --list-keys

The above command will give us a list of all the keys stored in our keychain. We’re running it because we want to know the ID of our primary key. With the ID of our primary key, we can edit it to make subkeys.

With the ID in hand, we can run something like the following:

gpg --expert --edit-key 7727544

We’re passing the --expert flag because without it we won’t be able to create an authentication subkey.

When editing your key, you’re going to want to enter the following:

addkey

After entering the above command, you’ll be given a menu that looks something like this:

Please select what kind of key you want: (3) DSA (sign only) (4) RSA (sign only) (5) Elgamal (encrypt only) (6) RSA (encrypt only) (7) DSA (set your own capabilities) (8) RSA (set your own capabilities) (10) ECC (sign only) (11) ECC (set your own capabilities) (12) ECC (encrypt only) (13) Existing key Your selection?

For the first two subkeys, we can choose option 4 and option 6. You’ll need to run the addkey command twice so you can add each subkey separately. To create your authentication key you’ll need to choose option 8 and then manually select the features of the key.

When creating each of your subkeys, make sure to choose an expiration time as well as a subkey length of 4096. At the main screen of your key editing, type save to save any changes that you’ve made.

At this point in time you have a primary key with hopefully three subkeys associated to it where each subkey offers different functionality. Now we can focus on importing these subkeys onto the YubiKey device and configuring the device itself.

Securing the YubiKey with a PIN and Two-Step Touch Authentication

Before we start importing our keys, we should probably configure the device so it is no longer using the factory defaults. By default, the smart card PIN is 123456 and the Admin PIN is 12345678. Doesn’t do us a whole lot of good if we are working with PGP and a thief knows your PIN.

Insert your YubiKey via the USB port on your computer and enter the following command:

gpg --card-status

If compatible, you’ll see information about your YubiKey and a lot of that information should be empty. Now we want to start editing our card by entering the following command:

gpg --edit-card

While in edit mode, we can do numerous things such as add owner information and basic meta data. What we’re particularly interested in is changing the PIN data. From the command line, execute the following:

admin passwd

The first command will switch into administrative mode. You’ll likely have to enter your Admin PIN to continue. After entering administrative mode we’re choosing to change our password or PIN data. First change the Admin PIN then change the standard PIN. On recent YubiKey devices you can have a PIN that is up to 127 bytes. At first I thought that since it was a PIN it had to be numeric, but in reality you can use any characters as if it were a passphrase.

Your PIN will be used instead of your primary key password when using your YubiKey for PGP.

After setting your new PIN information, we should probably enable two-step authentication on our device. Two-step will require us to enter our PIN as well as push the button on the YubiKey which will prevent rogue processes from trying to use our keys without our knowledge.

To enable the touch button, we’ll need to have the YubiKey Manager application installed. With the application installed and our YubiKey attached to our computer, we can enter something like the following:

ykman openpgp touch sig on ykman openpgp touch aut on ykman openpgp touch enc on

If the ykman application is not in your PATH, it can be found at /Applications/YubiKey Manager.app/Contents/MacOS/ykman on a Mac. The location will differ on Linux and Windows. However, in the above three commands, notice that I am enabling touch for each of the possible OpenPGP subkey slots. You can choose do do all three, or just one, it is up to you. If you don’t want the two-step authentication enabled, feel free to skip it.

At this point in time we should be ready to import our subkey data.

Importing PGP Keys into the YubiKey Smart Card Device

It is very important that you create a backup of your keys as of right now. When I say backup, I mean export your secret keys for the primary key as well as your subkeys and not just the public key. To do this, you can enter the following:

gpg --export-secret-keys --armor 7727544 > secret.asc

Back that secret key up because when you do the import step you’re going to lose access to the secret key. You’re going to be left with a stub of your key which will prevent you from restoring it without the exported secret key.

What comes next is what was probably some of the most confusing parts for me.

Execute the following to start editing your key again:

gpg --edit-key 7727544

If you really wanted to move your primary key to the YubiKey, you could execute the following commands:

toggle keytocard

Based on everything I read, you probably don’t want to store the primary key on the YubiKey because that is your master key. It is up to you, but feel free to skip the above step. Instead, we need to transfer each of our subkeys over.

To transfer each of our subkeys over, we need to toggle on the subkey in question. Take the following for example:

sec rsa4096/XXXXXXXXX created: 2017-03-07 expires: 2025-03-07 usage: SC trust: ultimate validity: ultimate ssb rsa4096/XXXXXXXXX created: 2017-03-07 expires: never usage: E ssb rsa4096/XXXXXXXXX created: 2019-01-15 expires: never usage: A ssb rsa4096/XXXXXXXXX created: 2019-01-15 expires: never usage: S

Each of the subkeys is not toggled on. I know this because the ssb does not have an asterisk symbol attached. Now let’s say we want to transfer over our encryption subkey. We can enter the following:

key 1 keytocard

The key 1 command will activate the first item in the list and the keytocard will transfer it over. To transfer the next, we need to enter the following:

key 1 key 2 keytocard

We need to first deactivate the first subkey and then activate the second. We’re not really deactivating them, we’re just deselecting or selecting them. Finally, we can transfer the final key over by executing the following:

key 2 key 3 keytocard

When you’re back at the main screen you can type save to save your changes. After saving you’ll be left with a stub of your subkeys on your local computer and the actual keys on your YubiKey device.

Some things to note:

The primary key is still on the local computer and can be used to create new subkeys on the local computer or revoke subkeys on the local computer or the YubiKey device.

The subkey stubs cannot be used without the YubiKey inserted.

The primary key will have the original passphrase chosen while the subkeys on the YubiKey will use the PIN instead.

If you try to use your YubiKey for PGP operations on a different computer, you will first need to have the public key imported. After importing the public key you can run the following:

gpg --card-status

The above command will get the stub information, at which point you can start doing PGP oriented activities. At no point is your secret key information leaving the YubiKey device.

Conclusion

You just saw how to generate PGP primary keys and subkeys and then transfer them onto your YubiKey device which supports OpenPGP. I’ve read quite a few of the guides out there, even the one from Yubico and there were always things to be desired. I’m hoping that I was able to clear things up based on my own trial and error.

For example, when I was learning, I had a tough time grasping how to generate an authentication subkey or how to correctly select subkeys for transfer.

In terms of why you might want to use a YubiKey for managing your PGP information, you might want to do this as a portable, yet secure mechanism that can be used without exposing your secret keys on every computer that you use.

Like I mentioned before, I’m not a pro at this, so if you have better ways to accomplish anything I demonstrated, let me know in the comments. We’re all learning here!

Nic Raboy Nic Raboy is an advocate of modern web and mobile development technologies. He has experience in Java, JavaScript, Golang and a variety of frameworks such as Angular, NativeScript, and Apache Cordova. Nic writes about his development experiences related to making web and mobile development easier to understand.