# YubiKey GPG Setup

John Simpson `<jms1@jms1.net>` 2019-03-21

Last updated: 2019-07-28

# TL;DR

If you're already familiar with the concepts and just need quick checklists...

### New key pair

```
gpg --quick-generate-key --yes 'John Simpson <jms1@jms1.net>' rsa4096 cert,sign 1y
```

```
KEYID="full-fingerprint-of-new-key"
gpg --quick-add-uid $KEYID 'John Simpson <kg4zow@kg4zow.us>'
gpg --quick-add-uid $KEYID 'John Simpson <kg4zow@mac.com>'
gpg --quick-add-key $KEYID rsa4096 encr 1y
gpg --quick-add-key $KEYID rsa4096 sign 1y
gpg --quick-add-key $KEYID rsa4096 auth 1y
```

### Back up key pair

```
gpg -a --export $KEYID            > $KEYID.pub.asc
gpg -a --export-secret-key $KEYID > $KEYID.sec.asc
gpg --gen-revoke $KEYID           > $KEYID.rev.asc
```

Also create a [paperkey](http://www.jabberwocky.com/software/paperkey/) backup.

```
gpg --export-secret-key $KEYID | paperkey -o $KEYID.paperkey.txt
```

### Set new expire date

```
gpg --quick-set-expire $KEYID 1y '*'
```

The *expire* argument (shown here as "`1y`") can be used to specify an expiration date for the  key. Several formats are supported; commonly the ISO formats `YYYY-MM-DD` or `YYYYMMDDThhmmss` are used. To make the key expire in N seconds, N days, N weeks, N months, or N years use "`seconds=N`", "`Nd`", "`Nw`", "`Nm`", or "`Ny`" respectively. The values "`never`", "`none`", and "`0`" can also be used to signify "no expiration date".

The last argument can be one of the following:

- Nothing: the expiration date of the primary key is changed

- "`*`": all non-revoked and not-yet expired subkeys will be changed

- one or more subkey fingerprints: those specific subkeys will be changed, provided they have not been revoked

# Background information

For the sake of documentation, the commands below were run on macOS, using the last version of [GPG Suite](https://gpgtools.org/) before they started charging for the GPGMail plug-in. The `gpg` software version involved is...

```
$ gpg --version
gpg (GnuPG/MacGPG2) 2.2.8
libgcrypt 1.8.3
Copyright (C) 2018 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <https://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Home: /Users/jms1/.gnupg
Supported algorithms:
Pubkey: RSA, ELG, DSA, ECDH, ECDSA, EDDSA
Cipher: IDEA, 3DES, CAST5, BLOWFISH, AES, AES192, AES256, TWOFISH,
        CAMELLIA128, CAMELLIA192, CAMELLIA256
Hash: SHA1, RIPEMD160, SHA256, SHA384, SHA512, SHA224
Compression: Uncompressed, ZIP, ZLIB, BZIP2
```

My `~/.gnupg/gpg.config` file currently has the following non-comment lines:

```
$ grep -v ^# ~/.gnupg/gpg.conf | grep .
no-greeting
default-key BDC84CA878FD827A4C0BB361A7EC1FBAB3B50007
default-recipient-self
require-cross-certification
charset utf-8
auto-key-locate cert pka ldap keyserver
no-emit-version
keyid-format 		0xlong
keyserver           hkp://pgp.mit.edu
keyserver           hkp://pool.sks-keyservers.net
```

# Procedure

**For safety, this should all be done on a machine which is NOT connected to the internet**, and the backup files should be stored using encrypted storage.

I use [Tails](https://tails.boum.org/) with its [encrypted persistence](https://tails.boum.org/doc/first_steps/persistence/index.en.html) feature when managing my own personal keys. However, I'm running through the example below on the same laptop where I'm typing this document so I can copy/paste the output here, so I'm generating a dummy key pair which will never actually be used.

## Before you start

### Yubico Security Advisories

You should review the [Yubico Security Advisories](https://www.yubico.com/support/security-advisories/) list to be sure that there are no issues with the YubiKey device(s) you own.

For example, my original YubiKey Neo has version 1.0.8 of the OpenPGP applet, which is subject to [this vulnerability](https://developers.yubico.com/ykneo-openpgp/SecurityAdvisory%202015-04-14.html). Because the YubiKey devices' firmware is not upgradable, Yubico sent me a free replacement (which I ended up never actually using, because at the time the YubiKey 4 had just come out and I already had one of them.)

### YubiKeys and PGP Key Sizes

Earlier YubiKey devices either didn't support PGP at all, or only supported smaller key sizes. You should be aware of the maximum key size supported by your YubiKey device before generating a key pair, so you don't accidentally generate a key which your YubiKey can't use.

| Device                    | Max Key Size  | Notes
|:--------------------------|:-------------:|:------
| [Security Key series](https://www.yubico.com/products/security-key/) | - | Only supports U2F and (for current models) FIDO2.
| YubiKey Standard          | -             | Does not support PGP
| YubiKey Edge and Edge-n   | -             | Does not support PGP
| [YubiKey Neo](https://www.yubico.com/products/yubikey-hardware/yubikey%20neo/) | 2048 | Be sure you have firmware [version 1.10 or higher](https://developers.yubico.com/ykneo-openpgp/SecurityAdvisory%202015-04-14.html)
| [YubiKey 4 series](https://www.yubico.com/products/yubikey-hardware/compare-yubikey-4-neo/) | 4096
| [YubiKey 5 series](https://www.yubico.com/products/yubikey-5-overview/) | 4096

## Create a new GPG key pair

Note that it *is* possible to generate a key pair directly on the YubiKey, which means that the private keys never leave the YubiKey itself. If you do this, there is no way to back up the secret keys or load them onto another YubiKey device, which means if you ever lose that YubiKey, the secret key is gone forever.

### Generate the key pair

#### Quick version

This is what the "TL;DR" section at the top of the page is doing.

The "`--quick-xxx`" options require a current version of [OpenPGP](https://www.openpgp.org/). For most Linux distributions this will be pre-installed, or can be installed through normal package repositories (i.e. "`yum`", "`apt`", etc.)

To generate the primary key:

```
gpg --quick-generate-key --yes 'John Simpson <jms1@jms1.net>' rsa4096 cert,sign 1y
```

At the end of the process, it will show the key's full fingerprint. I normally save this in a shell variable so I don't have to type it over and over in the next few commands.

```
KEYID="full-fingerprint-of-new-key"
```

If the key will have multiple UserIDs on it, add the additional users.

```
gpg --quick-add-uid $KEYID 'John Simpson <kg4zow@kg4zow.us>'
gpg --quick-add-uid $KEYID 'John Simpson <kg4zow@mac.com>'
```

Then, generate encryption, signature, and authentication keys.

```
gpg --quick-add-key $KEYID rsa4096 encr 1y
gpg --quick-add-key $KEYID rsa4096 sign 1y
gpg --quick-add-key $KEYID rsa4096 auth 1y
```


#### Manual version

* The "`--gen-key`" option only generates 2048-bit keys. I prefer larger keys (and my YubiKey 5 supports keys up to 4096 bits), so I use the "`--full-gen-key`" option instead.

* You will also be asked for a passphrase. If you're running this command in a shell which doesn't have a graphic display, those prompts will appear as part of this process. I ran this on a macOS laptop, so I had a pop-up dialog which isn't shown.

```
$ gpg --full-gen-key
Please select what kind of key you want:
   (1) RSA and RSA (default)
   (2) DSA and Elgamal
   (3) DSA (sign only)
   (4) RSA (sign only)
Your selection? 1
RSA keys may be between 1024 and 4096 bits long.
What keysize do you want? (2048) 4096
Requested keysize is 4096 bits
Please specify how long the key should be valid.
         0 = key does not expire
      <n>  = key expires in n days
      <n>w = key expires in n weeks
      <n>m = key expires in n months
      <n>y = key expires in n years
Key is valid for? (0) 1y
Key expires at Fri Mar 20 11:11:03 2020 EDT
Is this correct? (y/N) y

GnuPG needs to construct a user ID to identify your key.

Real name: John Simpson
Email address: jms1@jms1.net
Comment: Dummy key for documentation
You selected this USER-ID:
    "John Simpson (Dummy key for documentation) <jms1@jms1.net>"

Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? o
We need to generate a lot of random bytes. It is a good idea to perform
some other action (type on the keyboard, move the mouse, utilize the
disks) during the prime generation; this gives the random number
generator a better chance to gain enough entropy.
We need to generate a lot of random bytes. It is a good idea to perform
some other action (type on the keyboard, move the mouse, utilize the
disks) during the prime generation; this gives the random number
generator a better chance to gain enough entropy.
gpg: key 0xC454C65F54870CFD marked as ultimately trusted
gpg: directory '/Users/jms1/.gnupg/openpgp-revocs.d' created
gpg: revocation certificate stored as '/Users/jms1/.gnupg/openpgp-revocs.d/8382A47933F921FCDE56159CC454C65F54870CFD.rev'
public and secret key created and signed.

pub   rsa4096/0xC454C65F54870CFD 2019-03-21 [SC] [expires: 2020-03-20]
      8382A47933F921FCDE56159CC454C65F54870CFD
uid                              John Simpson (Dummy key for documentation) <jms1@jms1.net>
sub   rsa4096/0xD9F571006ED93488 2019-03-21 [E] [expires: 2020-03-20]
```

### Revocation certificate

Depending on what version of `gpg` you're using, it may or may not automatically create a revocation certificate while creating the key. If so, you'll see a message like this in the "`gpg --full-gen-key`" command's output:

```
gpg: revocation certificate stored as '/Users/jms1/.gnupg/openpgp-revocs.d/8382A47933F921FCDE56159CC454C65F54870CFD.rev'
```

**If it DID create a revocation certificate**, copy it to where you plan to store the new key's backup files.

```
cp /Users/jms1/.gnupg/openpgp-revocs.d/8382A47933F921FCDE56159CC454C65F54870CFD.rev \
    /mnt/usb/newkey/
```

**If it did NOT create a revocation certificate**, you should create one.

```
$ gpg --gen-revoke 8382A47933F921FCDE56159CC454C65F54870CFD \
    > /mnt/usb/newkey/8382A47933F921FCDE56159CC454C65F54870CFD.rev
```

This file needs to be protected almost as securely as the secret key file itself. If somebody gets this file and distributes it (by uploading it to a public keyserver, for example), anybody else who gets the file will stop using or trusting this key pair entirely. It won't compromise the security of any messages, but it will force you to have to generate and distribute a new key pair.

### Add a second signing sub-key

Encryption keys are flagged for use for different purposes. For PGP/GPG, the different purposes are:

* **`C` = Certification** - This key is used to sign other keys, including its own sub-keys and other users' keys. This will only be present on the main key.

* **`E` = Encryption** - This key is used to encrypt messages. Other people will use this public key to encrypt message to you, and you will use this private key to decrypt those messages.

* **`S` = Signing** - This key is used to digitally sign messages. You will use this private key to create signatures, and other people will use this public key to verify those signatures.

* **`A` = Authentication** - This key is used for other types of authentication. Most people don't need the authentication functionality to begin with, so new keys are not generated with an authentication sub-key by default. However, we will be creating an authenticaion sub-key for use with SSH below.

A PGP/GPG key consists of a primary key and one or more sub-keys. For example, in the key pair we generated n the "Manually" section above...

```
$ gpg --list-keys 8382A47933F921FCDE56159CC454C65F54870CFD
pub   rsa4096/0xC454C65F54870CFD 2019-03-21 [SC] [expires: 2020-03-20]
      8382A47933F921FCDE56159CC454C65F54870CFD
uid                              John Simpson (Dummy key for documentation) <jms1@jms1.net>
sub   rsa4096/0xD9F571006ED93488 2019-03-21 [E] [expires: 2020-03-20]
```

... there are two keys:

* **`rsa4096/0xC454C65F54870CFD`** is the primary key, and is flagged as "`[SC]`" (signing and certification). This key is used for signing its own sub-keys, and for signing other people's public keys.

* **`rsa4096/0xD9F571006ED93488`** is a sub-key, flagged as "`[E]`" (encryption). Other people will use this public key to encrypt messages they send to you, and you will use this secret key to decrypt those messages.

We're going to add a second signing sub-key. This will allow us to copy that new sub-key's secret key to the YubiKey *instead of* copying the primary key's secret key, which means that:

* The primary key's secret key never needs to leave the offline secure storage where you will eventually store it.

* The YubiKey can be used to sign and de-crypt messages, but it cannot be used to add more sub-keys or to sign other peoples' keys.

#### Enough talk, let's do it already!

* When it asks about when the new sub-key should expire, use the same expiration value that you used with the primary key.

```
$ gpg --edit-key 8382A47933F921FCDE56159CC454C65F54870CFD
Secret key is available.

sec  rsa4096/0xC454C65F54870CFD
     created: 2019-03-21  expires: 2020-03-20  usage: SC
     trust: ultimate      validity: ultimate
ssb  rsa4096/0xD9F571006ED93488
     created: 2019-03-21  expires: 2020-03-20  usage: E
[ultimate] (1). John Simpson (Dummy key for documentation) <jms1@jms1.net>

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)
Your selection? 4
RSA keys may be between 1024 and 4096 bits long.
What keysize do you want? (2048) 4096
Requested keysize is 4096 bits
Please specify how long the key should be valid.
         0 = key does not expire
      <n>  = key expires in n days
      <n>w = key expires in n weeks
      <n>m = key expires in n months
      <n>y = key expires in n years
Key is valid for? (0) 1y
Key expires at Fri Mar 20 12:30:47 2020 EDT
Is this correct? (y/N) y
Really create? (y/N) y
We need to generate a lot of random bytes. It is a good idea to perform
some other action (type on the keyboard, move the mouse, utilize the
disks) during the prime generation; this gives the random number
generator a better chance to gain enough entropy.

sec  rsa4096/0xC454C65F54870CFD
     created: 2019-03-21  expires: 2020-03-20  usage: SC
     trust: ultimate      validity: ultimate
ssb  rsa4096/0xD9F571006ED93488
     created: 2019-03-21  expires: 2020-03-20  usage: E
ssb  rsa4096/0xA66D92DF5FB0703D
     created: 2019-03-21  expires: 2020-03-20  usage: S
[ultimate] (1). John Simpson (Dummy key for documentation) <jms1@jms1.net>

gpg> q
Save changes? (y/N) y
```

```
$ gpg --list-keys 8382A47933F921FCDE56159CC454C65F54870CFD
pub   rsa4096/0xC454C65F54870CFD 2019-03-21 [SC] [expires: 2020-03-20]
      8382A47933F921FCDE56159CC454C65F54870CFD
uid                   [ultimate] John Simpson (Dummy key for documentation) <jms1@jms1.net>
sub   rsa4096/0xD9F571006ED93488 2019-03-21 [E] [expires: 2020-03-20]
sub   rsa4096/0xA66D92DF5FB0703D 2019-03-21 [S] [expires: 2020-03-20]
```

### Add an authentication sub-key

In order to use the YubiKey to store an SSH key, we need to create another sub-key with the "Authentication" flag. You may have noted that when we added the signing sub-key above, it had a few "(sign only)" and "(encrypt only)" options, but nothing about authentication.

In order to create a sub-key with the authentication flag, we need to use "expert mode".

```
$ gpg --expert --edit-key 8382A47933F921FCDE56159CC454C65F54870CFD
Secret key is available.

sec  rsa4096/0xC454C65F54870CFD
     created: 2019-03-21  expires: 2020-03-20  usage: SC
     trust: ultimate      validity: ultimate
ssb  rsa4096/0xD9F571006ED93488
     created: 2019-03-21  expires: 2020-03-20  usage: E
ssb  rsa4096/0xA66D92DF5FB0703D
     created: 2019-03-21  expires: 2020-03-20  usage: S
[ultimate] (1). John Simpson (Dummy key for documentation) <jms1@jms1.net>

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

Your selection? a

Possible actions for a RSA key: Sign Encrypt Authenticate
Current allowed actions: Sign Encrypt Authenticate

   (S) Toggle the sign capability
   (E) Toggle the encrypt capability
   (A) Toggle the authenticate capability
   (Q) Finished

Your selection? s

Possible actions for a RSA key: Sign Encrypt Authenticate
Current allowed actions: Encrypt Authenticate

   (S) Toggle the sign capability
   (E) Toggle the encrypt capability
   (A) Toggle the authenticate capability
   (Q) Finished

Your selection? e

Possible actions for a RSA key: Sign Encrypt Authenticate
Current allowed actions: Authenticate

   (S) Toggle the sign capability
   (E) Toggle the encrypt capability
   (A) Toggle the authenticate capability
   (Q) Finished

Your selection? q
RSA keys may be between 1024 and 4096 bits long.
What keysize do you want? (2048) 4096
Requested keysize is 4096 bits
Please specify how long the key should be valid.
         0 = key does not expire
      <n>  = key expires in n days
      <n>w = key expires in n weeks
      <n>m = key expires in n months
      <n>y = key expires in n years
Key is valid for? (0) 1y
Key expires at Fri Mar 20 12:41:06 2020 EDT
Is this correct? (y/N) y
Really create? (y/N) y
We need to generate a lot of random bytes. It is a good idea to perform
some other action (type on the keyboard, move the mouse, utilize the
disks) during the prime generation; this gives the random number
generator a better chance to gain enough entropy.

sec  rsa4096/0xC454C65F54870CFD
     created: 2019-03-21  expires: 2020-03-20  usage: SC
     trust: ultimate      validity: ultimate
ssb  rsa4096/0xD9F571006ED93488
     created: 2019-03-21  expires: 2020-03-20  usage: E
ssb  rsa4096/0xA66D92DF5FB0703D
     created: 2019-03-21  expires: 2020-03-20  usage: S
ssb  rsa4096/0x0DE775EF69201C5F
     created: 2019-03-21  expires: 2020-03-20  usage: A
[ultimate] (1). John Simpson (Dummy key for documentation) <jms1@jms1.net>

gpg> q
Save changes? (y/N) y
```

```
$ gpg --list-keys 8382A47933F921FCDE56159CC454C65F54870CFD
pub   rsa4096/0xC454C65F54870CFD 2019-03-21 [SC] [expires: 2020-03-20]
      8382A47933F921FCDE56159CC454C65F54870CFD
uid                   [ultimate] John Simpson (Dummy key for documentation) <jms1@jms1.net>
sub   rsa4096/0xD9F571006ED93488 2019-03-21 [E] [expires: 2020-03-20]
sub   rsa4096/0xA66D92DF5FB0703D 2019-03-21 [S] [expires: 2020-03-20]
sub   rsa4096/0x0DE775EF69201C5F 2019-03-21 [A] [expires: 2020-03-20]
```

## Back up the keys

Before we go any further, we need to make backup copies of the keys we've just created. 

```
gpg -a --export 8382A47933F921FCDE56159CC454C65F54870CFD \
    > /mnt/usb/newkey/8382A47933F921FCDE56159CC454C65F54870CFD.pub.asc
gpg -a --export-secret-key 8382A47933F921FCDE56159CC454C65F54870CFD \
    > /mnt/usb/newkey/8382A47933F921FCDE56159CC454C65F54870CFD.sec.asc
gpg --export-secret-key 8382A47933F921FCDE56159CC454C65F54870CFD \
    | paperkey -o /mnt/usb/newkey/8382A47933F921FCDE56159CC454C65F54870CFD.paperkey.asc
```

## Load the keys on a YubiKey

### Set YubiKey OpenPGP PIN and Admin PIN

If you have not already done so, you should set your own PIN and Admin PIN codes.

The OpenPGP smart card standard has the following standards for PIN codes:

* Minimum six characters.
* Maximum 254 characters.
* The YubiKey implementation has a limit of 127 characters, as shown in the `gpg --card-status` output.

**YubiKeys do not require that PINs be digits.** However, many *cards* require PINs to be digits, because some card readers have their own integrated PIN pads. In addition, if you want to use the same YubiKey as a smartcard for logging into a macOS user account, the PIN must be all digits, as macOS doesn't allow non-digits in the PIN.

When a YubiKey arrives from the factory, or if its OpenPGP app has been reset, the default PIN codes are:

* PIN: **`123456`**
* PUK: (none, which means that the Admin PIN must be used to unlock the PIN)
* Admin PIN: **`12345678`**

While you're setting the PINs, you may also want to set the cardholder name, language preference, public key URL, and login data. **These are all optional**, however I did it while writing this document, so you will see these steps below.

### Load keys on YubiKey

**TODO** These examples use a different key pair than the examples above, and the key shown here doesn't have a separate signing subkey. Load the dummy key shown above (if it still exists?) and show the process of loading *that* key instead.

```
$ gpg --edit-key 6353320118E1DEA2F38EAE806B2EDC90B5C6DC30
gpg (GnuPG/MacGPG2) 2.2.0; Copyright (C) 2017 Free Software Foundation, Inc.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Secret key is available.

sec  rsa4096/0x6B2EDC90B5C6DC30
     created: 2017-05-27  expires: never       usage: SC
     trust: ultimate      validity: ultimate
ssb  rsa4096/0x297E5961AB566594
     created: 2017-05-27  expires: never       usage: E
ssb  rsa4096/0xBA6C2A169C6C0F60
     created: 2017-11-10  expires: never       usage: A
[ultimate] (1). John M. Simpson <jms1@voalte.com>
[ultimate] (2)  John M. Simpson <jms1@jms1.net>
```

Select the Authentication sub-key.

* Each "`ssb`" line is a sub-key. They are numbered in the order shown here (even though the program doesn't show the numbers.)

* You will see an asterisk appear next to a sub-key when it is selected.

* It is possible to select more than one key. The same `key` command which selects a key will also de-select a key. (You will see this below.)

I'm not really sure what happens if more than one key is selected when you run the `keytocard` command - if you're *lucky* it will shown an error message and refuse to do anything, but if not, who knows...

Make sure the Authentication sub-key is the *only* one selected.

```
gpg> key 2

sec  rsa4096/0x6B2EDC90B5C6DC30
     created: 2017-05-27  expires: never       usage: SC
     trust: ultimate      validity: ultimate
ssb  rsa4096/0x297E5961AB566594
     created: 2017-05-27  expires: never       usage: E
ssb* rsa4096/0xBA6C2A169C6C0F60
     created: 2017-11-10  expires: never       usage: A
[ultimate] (1). John M. Simpson <jms1@voalte.com>
[ultimate] (2)  John M. Simpson <jms1@jms1.net>
```

Send the selected sub-key to the Authentication slot on the YubiKey (or the "card", as `gpg` calls it.)

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

sec  rsa4096/0x6B2EDC90B5C6DC30
     created: 2017-05-27  expires: never       usage: SC
     trust: ultimate      validity: ultimate
ssb  rsa4096/0x297E5961AB566594
     created: 2017-05-27  expires: never       usage: E
ssb* rsa4096/0xBA6C2A169C6C0F60
     created: 2017-11-10  expires: never       usage: A
[ultimate] (1). John M. Simpson <jms1@voalte.com>
[ultimate] (2)  John M. Simpson <jms1@jms1.net>
```

Now select the Encryption sub-key, and un-select the Authentication sub-key.

```
gpg> key 1

sec  rsa4096/0x6B2EDC90B5C6DC30
     created: 2017-05-27  expires: never       usage: SC
     trust: ultimate      validity: ultimate
ssb* rsa4096/0x297E5961AB566594
     created: 2017-05-27  expires: never       usage: E
ssb* rsa4096/0xBA6C2A169C6C0F60
     created: 2017-11-10  expires: never       usage: A
[ultimate] (1). John M. Simpson <jms1@voalte.com>
[ultimate] (2)  John M. Simpson <jms1@jms1.net>

gpg> key 2

sec  rsa4096/0x6B2EDC90B5C6DC30
     created: 2017-05-27  expires: never       usage: SC
     trust: ultimate      validity: ultimate
ssb* rsa4096/0x297E5961AB566594
     created: 2017-05-27  expires: never       usage: E
ssb  rsa4096/0xBA6C2A169C6C0F60
     created: 2017-11-10  expires: never       usage: A
[ultimate] (1). John M. Simpson <jms1@voalte.com>
[ultimate] (2)  John M. Simpson <jms1@jms1.net>
```

Send the selected sub-key to the Encryption slot on the Yubikey.

```
gpg> keytocard
Please select where to store the key:
   (2) Encryption key
Your selection? 2

sec  rsa4096/0x6B2EDC90B5C6DC30
     created: 2017-05-27  expires: never       usage: SC
     trust: ultimate      validity: ultimate
ssb* rsa4096/0x297E5961AB566594
     created: 2017-05-27  expires: never       usage: E
ssb  rsa4096/0xBA6C2A169C6C0F60
     created: 2017-11-10  expires: never       usage: A
[ultimate] (1). John M. Simpson <jms1@voalte.com>
[ultimate] (2)  John M. Simpson <jms1@jms1.net>
```

Now un-select all sub-keys, which results in the main key being selected. (If the key you're using has a separate signing subkey, you would select that subkey instead.)

```
gpg> key 1

sec  rsa4096/0x6B2EDC90B5C6DC30
     created: 2017-05-27  expires: never       usage: SC
     trust: ultimate      validity: ultimate
ssb  rsa4096/0x297E5961AB566594
     created: 2017-05-27  expires: never       usage: E
ssb  rsa4096/0xBA6C2A169C6C0F60
     created: 2017-11-10  expires: never       usage: A
[ultimate] (1). John M. Simpson <jms1@voalte.com>
[ultimate] (2)  John M. Simpson <jms1@jms1.net>
```

Send the key to the Signature slot on the Yubikey.

```
gpg> keytocard
Really move the primary key? (y/N) y
Please select where to store the key:
   (1) Signature key
   (3) Authentication key
Your selection? 1

sec  rsa4096/0x6B2EDC90B5C6DC30
     created: 2017-05-27  expires: never       usage: SC
     trust: ultimate      validity: ultimate
ssb  rsa4096/0x297E5961AB566594
     created: 2017-05-27  expires: never       usage: E
ssb  rsa4096/0xBA6C2A169C6C0F60
     created: 2017-11-10  expires: never       usage: A
[ultimate] (1). John M. Simpson <jms1@voalte.com>
[ultimate] (2)  John M. Simpson <jms1@jms1.net>
```

At this point we're finished with the YubiKey.

**HOWEVER** ... When you quit from `gpg`, it will ask whether you want to "save changes". The "changes" it wants to save are *deleting the secret keys* from the keychain files on the computer where you're working, because it thinks you wanted to *move* them to the YubiKey.

**If you do this, and you don't have some other backup of the secret keys, and then something happens to the YubiKey, those secret keys will be gone forever.**

Unless you *want* to delete these keys from your keyring on the machine where you're typing these command for some reason, *be very careful* to say "no" when it asks about saving changes.

```
gpg> q
Save changes? (y/N) n
Quit without saving? (y/N) y
```

Now if you query the card, you will see the keys in the three slots.

```
$ gpg --card-status

Reader ...........: Yubico Yubikey 4 OTP U2F CCID
Application ID ...: D2760001240102010006069404470000
Version ..........: 2.1
Manufacturer .....: Yubico
Serial number ....: 06940447
Name of cardholder: John Simpson
Language prefs ...: en
Sex ..............: unspecified
URL of public key : https://jms1.net/6B2EDC90B5C6DC30.pub.asc
Login data .......: jms1@jms1.net
Signature PIN ....: not forced
Key attributes ...: rsa4096 rsa4096 rsa4096
Max. PIN lengths .: 127 127 127
PIN retry counter : 3 0 3
Signature counter : 0
Signature key ....: 6353 3201 18E1 DEA2 F38E  AE80 6B2E DC90 B5C6 DC30
      created ....: 2017-05-27 22:28:31
Encryption key....: 0660 766F 2768 F41F D4B9  1DB7 297E 5961 AB56 6594
      created ....: 2017-05-27 22:28:31
Authentication key: BBA5 C6BB 23D2 B53B 0D0F  6C0B BA6C 2A16 9C6C 0F60
      created ....: 2017-11-10 23:29:14
General key info..: pub  rsa4096/0x6B2EDC90B5C6DC30 2017-05-27 John M. Simpson <jms1@voalte.com>
sec   rsa4096/0x6B2EDC90B5C6DC30  created: 2017-05-27  expires: never
ssb   rsa4096/0x297E5961AB566594  created: 2017-05-27  expires: never
ssb   rsa4096/0xBA6C2A169C6C0F60  created: 2017-11-10  expires: never
```

**Note that the Yubikey does not store public keys, it only stores private keys.** The "General key info" line comes from the keyring on the machine where you run the command.


# Make a "laptop key"

There may be times when you need to be able to use a PGP key on a machine (like a laptop) without having to (or being able to) plug in a YubiKey. This means storing the secret keys on the laptop. However, you shouldn't store the secret part of the *primary* key on the laptop, in case an attacker manages to steal a copy of your private keys.

The "`--export-secret-keys`" option creates a file containing the secret parts of the primary and all subkeys. The "`--export-secret-subkeys`" option is similar - it exports the secret parts of the subkeys, *but not the primary key*.

In order to make a "laptop key", we need to set up a secure way to transfer the files. For example, you might create a VeraCrypt virtual disk on a USB stick, since it's encrypted and can be opened on Linux, macOS, or even Windows (if you're into that kind of pain).

The examples below will assume that the transfer media is mounted as "`/mnt/secure`".

* Export the public keys.

    ```
    gpg -a --export $KEYID > /mnt/secure/$KEYID.pub.asc
    ```

* Export the secret subkeys, without the primary key.

    ```
    gpg -a --export-secret-subkeys $KEYID > /mnt/secure/$KEYID.sub.sec.asc
    ```

Transfer these two files to the machine which needs the "laptop key".

On this machine, import the two files, public key first:

```
gpg --import $KEYID.pub.asc
gpg --import $KEYID.sub.sec.asc
```

After doing this, you should see that the secret subkeys are present, but the secret primary key is not:

```
$ gpg --list-secret-keys $KEYID
sec#  rsa4096/0xC454C65F54870CFD 2019-03-21 [SC] [expires: 2020-03-20]
      8382A47933F921FCDE56159CC454C65F54870CFD
uid                   [ultimate] John Simpson (Dummy key for documentation) <jms1@jms1.net>
ssb   rsa4096/0xD9F571006ED93488 2019-03-21 [E] [expires: 2020-03-20]
ssb   rsa4096/0xA66D92DF5FB0703D 2019-03-21 [S] [expires: 2020-03-20]
ssb   rsa4096/0x0DE775EF69201C5F 2019-03-21 [A] [expires: 2020-03-20]
```

## Make macOS use the YubiKey for SSH

### Temporarily

There are two major steps which need to be done.

#### Make sure `gpg-agent` is running with SSH support

First find the PID of the `gpg-agent` process:

```
$ ps auxww | grep gpg-agent
jms1             24857   0.0  0.0  4267768    908 s002  S+    5:22PM   0:00.00 grep gpg-agent
jms1             24465   0.0  0.0  4297020   1236   ??  Ss    5:01PM   0:00.06 gpg-agent --homedir /Users/jms1/.gnupg --use-standard-socket --daemon
```

In this case, the PID is 24465.

Next, check the list of files which are opened by that process.

```
$ lsof -nP -p 24465 | grep ssh
gpg-agent 24465 jms1    6u  unix 0x1338e2dec234dcc3        0t0          /Users/jms1/.gnupg/S.gpg-agent.ssh
```

If it doesn't have an open handle to the `S.gpg-agent.ssh` named pipe, you should:

* Make sure that `gpg-agent` is configured to support SSH

    In `$HOME/.gnupg/gpg-agent.conf`, make sure the "`enable-ssh-support`" and "`use-standard-socket`" options are present.
    
    ```
    $ cat ~/.gnupg/gpg-agent.conf
    ###+++--- GPGConf ---+++###
    default-cache-ttl 0
    max-cache-ttl 1
    ###+++--- GPGConf ---+++### Wed Mar 11 18:32:36 2015 EDT
    # GPGConf edited this configuration file.
    # It will disable options before this marked block, but it will
    # never change anything below these lines.
        
    ########################################
    # 2017-11-08
    # https://florin.myip.org/blog/easy-multifactor-authentication-ssh-using-yubikey-neo-tokens
        
    pinentry-program /usr/local/MacGPG2/libexec/pinentry-mac.app/Contents/MacOS/pinentry-mac
    enable-ssh-support
    write-env-file
    use-standard-socket
    ```

* Kill the current `gpg-agent` process and start a new one.

    ```
    $ gpg-connect-agent killagent /bye ; sleep 1 ; gpg-connect-agent /bye
    OK closing connection
    gpg-connect-agent: no running gpg-agent - starting '/usr/local/MacGPG2/bin/gpg-agent'
    gpg-connect-agent: waiting for the agent to come up ... (5s)
    gpg-connect-agent: connection to agent established
    ```

* Use the "`ps`" and "`lsof`" commands as shown above, and make sure the named pipe is now open.

#### Configure `ssh` to use the `pgp-agent`'s named pipe

The `ssh` and `scp` commands use an environment variable called `SSH_AUTH_SOCK` to locate what is normally an instance of `ssh-agent`. By changing this variable, you can make these commands use `gpg-agent` instead.

```
$ export SSH_AUTH_SOCK="/Users/jms1/.gnupg/S.gpg-agent.ssh"
```

#### Test the connection

At this point, you should be able to run `ssh-add -l` (which lists the keys in the SSH agent) and see the fingerprint of the authentication key stored on your YubiKey.

```
$ ssh-add -l
4096 SHA256:FHvP2rcewMZYNgkUfFnL0mNAfDA5t/oi9I/QywMYfH0 cardno:000608999999 (RSA)
```

In addition, you can use "`ssh-add -L`" to show the full public key, in the format that `openssh` needs for a user's `authorized_keys` file.

```
$ ssh-add -L
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDO8q5JeZuTxSh...sXq3PpNw== cardno: 000608999999
```

The YubiKey only contains the secret key itself, it doesn't have any other information about the "identity" attached to the key. For this reason, it shows "`cardno:`" with the YubiKey's serial number as the comment. If you're using this output for an `authorized_keys` file, you may want to use a more descriptive comment than just the card's serial number, so that if you're inspecting the `authorized_keys` file later on, you'll have a better chance at recognizing which key you're looking at.

### Permanently

I do this on every Mac I own, or use on a regular basis at work.

* [`https://jms1.net/yubikey/make-ssh-use-gpg-agent-macos.md`](https://jms1.net/yubikey/make-ssh-use-gpg-agent-macos.md)

# Other Random Notes

### Remove dummy key

This is a quick checklist for removing a dummy key, like the ones I generated temporarily while working on this document.

```
gpg --delete-secret-and-public-key --yes $KEYID
rm ~/.gnupg/openpgp-revocs.d/$KEYID.rev
unset KEYID
```

### Reset the YubiKey's PGP app

This can be handy when you're changing the PGP key stored within a YubiKey.

Yubico has [official directions](https://support.yubico.com/support/solutions/articles/15000006421-resetting-the-openpgp-applet-on-the-yubikey) for how to do this. Those directions basically explain that Yubico's [YubiKey Manager](https://www.yubico.com/products/services-software/download/yubikey-manager/) software comes with a command line tool which resets the PGP app.

To use it on macOS, you need to download and install the app, and then run the tool directly, like so:

```
$ cd '/Applications/YubiKey Manager.app/Contents/MacOS'
$ ./ykman openpgp reset
WARNING! This will delete all stored OpenPGP keys and data and restore factory settings? [y/N]: y
Resetting OpenPGP data, don't remove your YubiKey...
Success! All data has been cleared and default PINs are set.
PIN:         123456
Reset code:  NOT SET
Admin PIN:   12345678
```

**Note:** [`https://jms1.net/yubikey/reset-yubikey-openpgp-app.md`](https://jms1.net/yubikey/reset-yubikey-openpgp-app.md) is the procedure I cobbled together from information I found around the web when I first started playing with this stuff. I have no idea what the low-level codes on that page are actually doing, and I have no idea if they're correct for any device other than the YubiKey Neo.

Now that Yubico has a supported way to reset the app, I **strongly** recommend using that instead.

# References

These are the various references I consulted (other than my own previous notes) while writing this document.

* [`https://alexcabal.com/creating-the-perfect-gpg-keypair`](https://alexcabal.com/creating-the-perfect-gpg-keypair)

* [`https://blog.eleven-labs.com/en/openpgp-almost-perfect-key-pair-part-1/`](https://blog.eleven-labs.com/en/openpgp-almost-perfect-key-pair-part-1/) (be careful, this web site wants to send notification pop-ups to your browser)

* [Yubico](https://www.yubico.com/)

* [My original write-ups](https://jms1.net/yubikey/)
