GPG and yubikey - Serenity through madness
Mar 26, 2019 • 2118 words • 11 min read

A year or so ago I got myself a yubikey. So far I had only been using it to improve the process of logging in to most of my 2FA-protected accounts and I loved it.

But a yubikey can improve more aspects of your digital identity and one of the ways it can help you do that is by allowing you to store GPG keys on it.

GPG is a very versatile piece of software which implements the OpenPGP standard. Feel free to read what this is, but the tl;dr version is that you can use it (among other things) to sign and encrypt emails, commits, files using public key cryptography, i.e. you encrypt something with someone's public key and they can decrypt it with their private key, because magic maths.

The problem is that GPG is one of these things that even if you know what you want to do, it's not obvious how to do it unless you have already done it. Its user interface is not exactly user friendly and both it and its man pages can be a bit daunting especially if you're not very familiar with the terminology.

So in this post I will attempt to explain some of the things that I found extremely confusing, both for my sake and for anyone else who will venture this way.

Table of contents

Key pairs, subkeys and capabilities. Wat?

Key pairs

Let's start with the simple ones first: As I said earlier GPG is using public key cryptography.

This means that when you generate a key, you actually generate a key pair. The pair consists of a private part and a public part. The public part is shared with everyone, the private part must be kept private. Duh.

Because I'm lazy I will continue referring to the key pair as "key" throughout the rest of the post.

Subkeys: The most confusing bit

GPG allows the creation of subkeys which are to be used for everyday tasks whereas the primary key is used for important operations

You can have primary keys and subkeys. Best practices dictate that you use your primary key for important operations (creating and revoking subkeys, signing other people's keys, etc) and your subkeys for every day use (e.g. encrypting and decrypting things).

Here is where things get hairy and what was the single most confusing thing for me:

All the information about your subkeys are stored together with your primary key. The result of this, and the second most confusing thing, is that you don't really have a public keys for your subkeys. Or rather, you have, but they always come bundled as part of your primary key's public part.

Here's an example of how to add a subkey and how it affects your public key:


Important:

When you --edit-key your changes are not persisted until you give the save command.

Capabilities

Capabilities are flags that can be enabled or disabled on the subkeys to determine which actions they can and cannot do. When I was creating the subkey in the screencast above, after I issued the command addkey I got this menu:

gpg> addkey
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? 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

So as you can see a subkey can do any or all of the actions listed above and by typing S/E/A you toggle the corresponding flag on and off.

There is one extra capability which is mandatory for the primary key and can only be had by the primary key. This is denoted by the letter 'C' for Certify and it is what allows the primary key to do the important operations that I mentioned earlier, such as creating and revoking keys etc.

Putting it all together: Decrypting the gpg -K output

When you run gpg -K (or its long form gpg --list-secret-keys) you see something like this:

$ gpg -K
/home/sakis/.gnupg/pubring.kbx
------------------------------
sec   rsa3072 2019-03-23 [SC]
      720F0BB73AD59959046117EC8B95F161351E9EEA
uid           [ultimate] sakis <[email protected]>
ssb   rsa3072 2019-03-23 [E]
ssb   rsa3072 2019-03-23 [A]

Let's break it down:

sec   rsa3072 2019-03-23 [SC]

sec means that this is a reference to the secret part of your primary key
rsa3072 2019-03-23 shows what type of key it is (RSA), its size (3072) and when it was created (2019-03-23)
[SC] shows the capabilities of the key. This is the primary key which by default has the Sign and Certify capabilities enabled.

      720F0BB73AD59959046117EC8B95F161351E9EEA

This is the fingerprint of your key which stays the same throughout its lifetime and can be used to uniquely identify your key both locally, for various operations, and online.

uid           [ultimate] sakis <[email protected]>

uid stands for "user id". You can add and remove uids as necessary.
[ultimate] The level of trust you have for this key. You can find more information about the trust model here: https://security.stackexchange.com/a/41209/82804
sakis <[email protected]> This is the name and the email you typed when you created the key. The full format is firstname lastname (comment) <[email protected]>

ssb   rsa3072 2019-03-23 [E]
ssb   rsa3072 2019-03-23 [A]

These follow the same format as the first line with the only difference being the ssb in the beginning which indicates that these refer to the secret part of your subkeys.

Bonus: list the public parts with gpg -k

If you only want to get information about the public parts of your keys you can use gpg -k (lower case) or its long form gpg --list-keys where you get a similar output:

$ gpg -k
pub   rsa3072 2019-03-23 [SC]
      720F0BB73AD59959046117EC8B95F161351E9EEA
uid           [ultimate] sakis <[email protected]>
sub   rsa3072 2019-03-23 [E]
sub   rsa3072 2019-03-23 [A]

Notice the difference where sec is now pub and ssb is now sub.

Isn't the difference obvious? Isn't GPG fun?

Putting keys on the yubikey

GPG has support for smartcards where you can store your private keys, providing increased security against malware and physical theft. The idea is that once your private keys are on the smartcard they cannot be retrieved.

Before we take such a drastic step, it's wise to sort out what we want to move and what we want to backup.

Preparation

As I have already mentioned, the primary key is used to do important operations. If someone was to get their hands on it they could impersonate you. It's important therefore to secure its private key.

The subkeys on the other hand are more ephemeral and not as dangerous and are the ones that we will be using for everyday operations.

The sequence of actions is:

  1. Export the primary private part
  2. Export the subkeys' private parts
  3. Delete all private parts
  4. Import only the subkeys' private parts

It's up to you to decide how to store your primary private key. I would suggest multiple trusted places at least one of which out of your house.

Moving the subkeys

Now let's put our subkeys onto the yubikey. The yubikey has 3 slots, one for each of the 3 operations that the subkeys can perform: Signing, Encryption, Authentication.

Assuming you have 3 subkeys, one for each operation and an empty yubikey plugged in, the process looks like this:

(For anyone paying close attention, yes, I had to create a new key with a length of 2048 bits because I'm using an older yubikey that only supports keys up to 2048 bits. The new ones support keys up to 4096 bits)

A couple of the things that are not visible or you can miss in the asciinema screencast:

  1. The first time you run keytocard will ask you for both your GPG passphrase and for the admin pin of the yubikey (which defaults to 12345678). The next 2 times it will only ask you for your GPG passphrase
  2. Key selection works like the capabilities toggling above. Every time you type key X you select that particular key which is indicated by a * . If you want to deselect a key you just type key X again. Intuitive, I know.

The chevron (>) and the hash (#)

Now if you run gpg -K again you will notice that instead of ssb it now showsssb> and instead of sec it shows sec#. This is how GPG indicates that the secret keys of your subkeys and your primary key are missing.

If you run gpg --card-status with your yubikey connected you will see something similar to this:

$ gpg --card-status

Reader ...........: 1050:0116:X:0
Application ID ...: D27600012401020000060XXXXXXX0000
Version ..........: 2.0
Manufacturer .....: Yubico
Serial number ....: 0XXXXXXX
Name of cardholder: [not set]
Language prefs ...: [not set]
Sex ..............: unspecified
URL of public key : [not set]
Login data .......: [not set]
Signature PIN ....: forced
Key attributes ...: rsa2048 rsa2048 rsa2048
Max. PIN lengths .: 127 127 127
PIN retry counter : 3 3 3
Signature counter : 0
Signature key ....: D57D 87A8 C6F8 E2B2 F7C5  5742 371F F549 634A B054
      created ....: 2019-03-26 21:22:04
Encryption key....: 096A B151 B612 2AAF C234  562F EC18 F0AB 19AE 4340
      created ....: 2019-03-26 21:19:26
Authentication key: DE81 04CE EAFF 7C84 8A37  622B 97B9 2CBB B2E1 4799
      created ....: 2019-03-26 21:22:27
General key info..: sub  rsa2048/371FF549634AB054 2019-03-26 sakis <[email protected]>
sec#  rsa2048/2E6E41D5BA7F82FB  created: 2019-03-26  expires: never
ssb>  rsa2048/EC18F0AB19AE4340  created: 2019-03-26  expires: never
                                card-no: 0006 0XXXXXXX
ssb>  rsa2048/371FF549634AB054  created: 2019-03-26  expires: never
                                card-no: 0006 0XXXXXXX
ssb>  rsa2048/97B92CBBB2E14799  created: 2019-03-26  expires: never
                                card-no: 0006 0XXXXXXX

Notice the card-no: section at the bottom. The 0XXXXXXX is the serial number of your yubikey and is also printed on your device. Notice the chevrons after the ssb and the hash after the sec that indicate that your keys are not present.

Questions

A few of the questions I had after finishing this process for the first time:

Which fingerprint/public key do I upload to a keyserver?

As I mentioned in the beginning, the fingerprint remains the same no matter what you do. The public key changes as you create more subkeys, so once you have finished your setup, run gpg --armor --export <KEY_ID> > your_name.pub and upload this to a key server (e.g. https://keyserver.ubuntu.com)

And what if I lose my yubikey? How can I create a backup of it?

Once you have transferred your keys to your yubikey, you have no secret keys stored on your machine. To create a new yubikey you need to import your secret subkeys and run the keytocard steps again.

Can I add more emails/names and if so, does it change the public key?

Yes you can add more emails/names (uids in the GPG slang) to your key and yes it changes the public key.

To add a new uid you will need to import your primary private key because this is an Important Operation™. Once you do that you need to gpg --expert --edit-key <KEY_ID> and then type adduid and follow the wizard there. Remember to save your changes in the end.


Use the comments below to ask more questions because undoubtedly I have missed things.

Resources

In addition to the links in the text, these are some more sites that helped me understand what's going on:


/notes-to-self/ /GPG/ /yubikey/ /security/