summaryrefslogtreecommitdiff
path: root/content/posts/2018/2018-09-04-setting-up-pgp-with-a-yubikey.md
blob: 36e0ef6e19acbd8fc60fd0814ad4840e8645fef8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
---
title: Setting up PGP with a Yubikey
date: 2018-09-04
tags:
- GPG
- PGP
- Security
- YubiKey
---

I've recently started a job where I am required to have above-average security
practices in place on my machine. I already had some standard security in
place, such as full disk encryption and PGP encrypted email, but I thought that
this would be a good time to up my game. To accomplish this, I purchased a
Yubikey to act as my physical security token. Additionally, I have a USB device
which is also encrypted to hold backups of the keys.

In this blogpost, I will detail how I set up my security policies in the hopes
it will be able to help out other people looking to improve their security, and
to get feedback to improve my set up as well.

{{< admonition title="note" >}}
I am using the Yubikey 4. If you're using another version, some steps may
differ.
{{< / admonition >}}

## Installing required software

You'll need some software to set all of this up. Depending on your
distribution, some of it might already be installed. Everything not installed
yet should be installed with your distribution's package manager.

For encrypting the disk and the USB key, you will need `cryptsetup`. To
generate and use the PGP keys, you will need `gpg`, at least version 2.0.12. To
interface with the Yubikey itself, you'll need `pcsc-lite`, and start the
service as well. It may be necessary to restart the `gpg-agent` after
installing `pcsc-lite`, which you can do by simply killing the existing
`gpg-agent` process. It restarts itself when needed.

To securely remove the temporary data we need, you should make sure you have
`secure-delete` available on your system as well.

## Personalizing the Yubikey

The Yubikey can be personalized. Some of this personalization is completely
optional, such as setting personal information. However, setting new PIN codes
is strongly advised, as the default values are publicly known.

### PIN codes

The PIN codes are short combinations of numbers, letters and symbols to grant
permission to write to or retrieve data from the Yubikey. The default value for
the user PIN is `123456`. The admin PIN is `12345678` by default. These should
be changed, as they're publicly known and allow the usage of your private keys.
To change these, use the `gpg` program and enter admin mode:

```txt
gpg --card-edit

gpg/card> admin
Admin commands are allowed
```

You'll notice it immediately says that admin commands are now allowed to be
used. The admin PIN (`12345678`) will be asked whenever an admin command is
executed. It will then be stored for this session, so you won't have to enter
it right away. To update the PIN values, run the following commands:

```txt
gpg/card> passwd
gpg/card> 3
```

This will change the admin PIN first. This PIN is required for managing the
keys and user PIN on the Yubikey. To set the user PIN, pick `1` instead of `3`:

```txt
gpg/card> 1
```

Once this is done, you can quit the `passwd` submenu using `q`:

```txt
gpg/card> q
```

You may have noticed we skipped the reset code. Resetting the device will wipe
existing keys, so it's not a serious risk to keep this at the default. The
private keys will be backed up to an encrypted USB drive, so we can always
retrieve them and put them back on the Yubikey if ever needed.

### Personal information

The personal information is optional, but could be used by a friendly person to
find out who a found Yubikey belongs to. They can contact the owner, and send
the key back. You can set as many of the personally identifying fields as you
want. If you're interested in setting this information, plug in your Yubikey
and edit the card information with `gpg`:

```txt
gpg --card-edit
```

Once you're back in the GPG shell, you can update your personal information.
There are 5 attributes that you can set in this way:

- `name`, which is your real name;
- `lang`, which is your preferred contact language;
- `sex`, which is your real sex;
- `url`, which indicates a location to retrieve your public key from;
- `login`, which indicates your email address.

Each of these attributes can be updated by running the command in the GPG
shell. For instance, to update your real name, run the following:

```txt
gpg/card> name
```

You do not need to explicitly save once you're done. You can run `quit` to quit
the GPG shell and return to your regular shell.

## Creating PGP keys

To create the PGP keys, we'll create a temporary directory which will function
as our working directory to store the keys in. This way you can't accidentally
break existing keys if you have them, and ensure that the private keys don't
accidentally linger on in your filesystem.

### Preparing a clean environment

To create such a temporary directory, we'll use `mktemp`, and store the result
in an environment variable so we can easily re-use it:

```sh
export GNUPGHOME="$(mktemp -d)"
```

Now you can switch to that directory using `cd "$GNUPGHOME"`. Additionally,
`$GNUPGHOME` is also the directory `gpg` uses as its working directory, if it
is set. This means you can use a temporary custom configuration for `gpg` as
well, without it affecting your normal setup. The following configuration is
recommended to set in `$GNUPGHOME/gpg.conf` before starting:

```conf
use-agent
charset utf-8
no-comments
keyid-format 0xlong
list-options show-uid-validity
verify-options show-uid-validity
with-fingerprint
```

If you have a `gpg-agent` running, it is recommended to stop it before
continuing with `killall gpg-agent`.

### Creating the master key

For our master key, we'll go for a 4096 bytes RSA key. 2048 would be plenty as
well, if you want the generation to be a tad quicker. `gpg` will ask you a
couple questions to establish your identity, which is required for a PGP key.
You can add more identities later, in case you're using multiple email
addresses, for instance.

Start the key generation process with `gpg`:

```txt
gpg --full-generate-key
```

When asked what kind of key you want, choose `4` (RSA (sign only)). Next is the
key size, which should be `4096`.

The key's expiration is optional, though highly recommended. It will be more
effort to maintain the keys, as you'll occasionally need the private master
keys to extend the validity, but you can also guarantee that your keys won't
stay valid in case you ever lose them. If you don't want to bother with
refreshing your keys from time to time, just press enter here to continue.

When prompted on whether the data is correct, doublecheck whether the data is
really correct, and then enter `y` and press enter to accept the current
values. `gpg` will continue with your identity information, which you should
fill out with your real information. The comment field can be left empty, this
is an optional field to add a comment to your identity, such as "School", or
"Work keys". `gpg` will ask your confirmation one final time. Enter an `o`
(it's not case sensitive) and press enter again. The final step before it will
generate a key is to enter a passphrase. This is technically optional, but
highly recommended. If anyone ever gets their hands on your private master key,
they will need the passphrase in order to use it. Adding one is yet another
layer against malicious use of your key.

Once you've chosen a passphrase, it will generate they key and output some
information about the key. Verify whether this information is correct one more
time, and if it is, you can continue to the next step. If it is not, redo the
whole PGP section of this post.

Take note of the line starting with `pub`. It shows that the key is an
`rsa4096` key, followed by a `/`, and then the key ID. You'll need this key ID
throughout the rest of this post. For convenience, you can store this ID in
a variable, and just refer to the variable when you need it's value again:

```sh
export KEYID=0x27F53A16486878C7
```

This post will use the `$KEYID` variable from now on, to make it easier to
follow.

### Creating a revocation certificate

The revocation certificate can be used to invalidate your newly created key.
You should store it seperately from the private master key, preferably printed
on a sheet of paper. If you want to be able to easily read it back in, consider
printing it as a QR code.

To create the certificate, run the following:

```txt
gpg --gen-revoke $KEYID > $GNUPGHOME/revoke.txt
```

This will prompt you to specify a reason, for which you'll want to use `1`.
This way you can easily revoke the key's validity if you ever lose it. If you
want to revoke your keys in the future for any other reason, you can always
generate a new revocation certificate for that specific purpose. You don't have
to supply an additional description, so just hit enter. A revocation
certificate will be written to `$GNUPGHOME/revoke.txt`.

### Creating the subkeys

Now that you have your master key and the ability to revoke it in case anything
goes wrong in the future, it's time to create a couple of subkeys which can be
stored on the Yubikey, and used in your daily life. We'll create seperate keys
for _encryption_, _signing_ and _authentication_, and store each of them in
their own dedicated slot on the Yubikey.

To add subkeys to your master key, enter a GPG shell to edit your existing
key with `gpg --expert --edit-key $KEYID`. The `--expert` is required to show
all the options we're going to need. Once the GPG shell has started, run
`addkey` to add a new key.

Just like with the master key, a number of questions will be asked. Expiration
for subkeys is generally not advised, as the subkeys will be considered invalid
whenever the master key has expired. The key sizes for the subkeys can be left
at 2048 as well, which is also the maximum size for keys for the older Yubikey
models. The key type is different for all 3 subkeys.

You will want to select type `4` (RSA (sign only)) for your signing key, type
`6` (RSA (encrypt only)) for the encryption key, and type `8` (RSA (set your
own capabilities)) for the authentication key. With the final key, it will ask
you what capabilities you want to enable. The only capability you want it to
have is *Authentication*.

Once you've created the subkeys, you can check `gpg --list-secret-keys` to look
at your newly created keys. You should have 1 `sec` key, which is the master
key, and 3 `ssb` keys, which are the subkeys. One line should end with `[S]`,
one with `[E]` and one with `[A]`. These denote the capabilities of the
subkeys, _Sign_, _Encrypt_ and _Authenticate_, respectively.

### Export the keys

Now that you have your keys generated, you should export them, allowing you to
easily import them in another environment in case you ever need to generate
more keys, invalidate some keys, or extend the validity of the keys in case you
set an expiry date. This can be done with the following commands:

```txt
gpg --armor --export-secret-keys $KEYID > masterkey.asc
gpg --armor --export-secret-subkeys $KEYID > subkeys.asc
```

## Creating a backup USB

For the backup of the private keys, I'm using an encrypted USB device. You can
also opt to print the keys to paper, and retype them if you ever need them. Or
print a QR code that you can scan. But for convenience sake, I went with a USB
device. I encrypted it, and stored it in a safe and sealed location, so it's
easy to detect unwanted attempted access.

### Encrypting the USB

For the encryption, I went with full device encryption using LUKS. You will
need the `cryptsetup` utility to apply the encryption, and to unlock the drive.
You can find out the device name from `dmesg` or `lsblk`. Once you know it,
encrypt the drive with the `luksFormat` subcommand.

{{< admonition title="warning" >}}
Using the wrong name for the device can irrecoverably destroy data from another
drive!
{{< / admonition >}}

```txt
cryptsetup luksFormat /dev/sdb
```

It will prompt you whether you want to continue, and ask twice for a passphrase
to ensure it is correct. Make sure you don't forget the passphrase, or you'll
lose access to your backup keys.

Once it has been encrypted, unlock the device.

```txt
cryptsetup luksOpen /dev/sdb crypt
```

This will open the device as `/dev/mapper/crypt`. Format it with your favourite
filesystem. I used `ext4`.

```txt
mkfs.ext4 /dev/mapper/crypt
```

Once it has been formatted, you can mount it as a regular device.

```txt
mount /dev/mapper/crypt /mnt/usb
```

### Copying the keys

Copying the keys is as straightforward as copying other files. You can use
`$GNUPGHOME` to target the source directory.

```txt
cp -arv "$GNUPGHOME"/* /mnt/usb/.
```

Once the files are copied, you can unmount the drive, lock it and unplug the
USB.

```txt
sync
umount /mnt/usb
cryptsetup luksClose crypt
```

Store the USB in a safe location, because these private keys can give someone
full control of your identity.

## Storing the private keys on the Yubikey

The Yubikey has key slots for encryption, signing and authentication.  These
need to be set individually, which can be done using `gpg`. First, you need to
select a key using the `key` command, then store it on the card using
`keytocard` and select a slot to store it in, then finally deselect the key by
using the `key` command again.

```txt
gpg --edit-key $KEYID

gpg> key 1
gpg> keytocard
Your selection? 1
gpg> key 1

gpg> key 2
gpg> keytocard
Your selection? 2
gpg> key 2

gpg> key 3
gpg> keytocard
Your selection? 3

gpg> save
```

You can verify whether the keys are available on the Yubikey now using `gpg
--card-status`. It will show the key fingerprints for the `Signature key`,
`Encryption key` and `Authentication key`.

### Sharing your public key

You can share your public keys in many ways. Mine is hosted [on my own
site](/pubkey.txt), for instance. There are also [public
keyservers](https://sks-keyservers.net/) on which you can upload your keys.
`gpg` has the `--send-keys` and `--recv-keys` switches to interact with these
public keyservers. For ease of use, I would recommend uploading them to a public
keyserver, so that other people can easily import it. For instance, my key can
be imported using `gpg`:

```txt
gpg --recv-keys 0x7A6AC285E2D98827
```

## Clean up

The keys are on the Yubikey, and you probably do not want to leave traces on
your local system of these new keys, so you should clean up the `$GNUPGHOME`
directory. There's a utility for securely removing a directory with all its
contents, called `secure-delete`, which provides the `srm` program. You can use
it just like the regular `rm` on the temporary directory.

```txt
srm -r "$GNUPGHOME"
```

You can also `unset` the `$GNUPGHOME` variable at this point, so `gpg` will use
it's default configuration again.

```txt
unset GNUPGHOME
```

## Configure GPG

Finally, you have your keys on the Yubikey and the traces that might have been
left on your device are wiped clean. Now you should configure `gpg` for regular
use as well, however, this is completely optional. All this configuration does
is ensure you have good defaults for the current day and age.

```conf
auto-key-locate keyserver
keyserver hkps://hkps.pool.sks-keyservers.net
keyserver-options no-honor-keyserver-url
personal-cipher-preferences AES256 AES192 AES CAST5
personal-digest-preferences SHA512 SHA384 SHA256 SHA224
default-preference-list SHA512 SHA384 SHA256 SHA224 AES256 AES192 AES CAST5
ZLIB BZIP2 ZIP Uncompressed
cert-digest-algo SHA512
s2k-cipher-algo AES256
s2k-digest-algo SHA512
charset utf-8
fixed-list-mode
no-comments
no-emit-version
keyid-format 0xlong
list-options show-uid-validity
verify-options show-uid-validity
with-fingerprint
use-agent
require-cross-certification
```

## Conclusion

You now have PGP keys available on your Yubikey. These keys are only available
to your system if the Yubikey is inserted, and the user PIN is given. You can
use these keys for authentication, signing and encrypting/decrypting messages.
In a future post, I'll detail how to set up a number of services to use these
keys as well.