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:
- Export the primary private part
- Export the subkeys' private parts
- Delete all private parts
- 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:
- 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 - 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 typekey 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:
- Using your yubikey with openpgp (yubico support)
- Smartcards
- What is the Authenticate capability used for
- Why use subkeys?
- OpenPGP - The almost perfect key pair
- Anatomy of GPG key