Using your Yubikey to get started with GPG
Tags: devops, linux, security, github
Published: 2020-09-06 13:21:14

## Why store your RSA key on a Yubikey?


Digital security is generally much more difficult than physical security. If I have a secret written on a piece of paper, I could hide that paper somewhere, I could keep it on my person, I could put it in safety deposit box. All of these are pretty good ways to make sure nobody reads whatever is on the paper, and all are simple to reason about. If I have that same secret on a file on my laptop, however, there is much more to think about. Every piece of software I run has permission to read that file.

My laptop has a network connection, so an attacker does not need to ever meet me to steal my secret. A Yubikey almost turns a digital security problem into a physical security one.

If your SSH key is stored on a Yubikey it cannot be copied, it cannot be stolen remotely, and the software on whatever machine you stick it into cannot read it. You can even PIN protect the key, which means that if somebody physically steals your Yubikey they would have to guess the PIN correctly to be able to use it, and even then, they would be unable to extract the key.

PGP can use a number of encryption algorithms to generate its keys. One of those is Rivest–Shamir–Adleman (RSA). RSA is named for its developers, Ron Rivest, Adi Shamir, and Leonard Adleman, who developed the algorithm in 1978.

RSA was one of the first asymmetrical encryption algorithms published. Both its private key and public key can be used to encrypt and decrypt data. Whichever is used to encrypt, the other is used to decrypt.

## Set Yubikey PINs

Install gpg using your operating system’s package manager so that you can interact with your Yubikey.

Plug in your Yubikey, and run gpg --change-pin to change the PIN from the default of 123456. This is the PIN you’ll be asked to enter whenever you need to access the private key, for example when doing git push.

```
$ gpg --change-pin
1 - change PIN
2 - unblock PIN
3 - change Admin PIN
4 - set the Reset Code
Q - quit
Your selection? 1
Please enter the PIN
New PIN
New PIN
PIN changed.
```

If you enter your newly-set PIN incorrectly three times then the Yubikey will be locked, and you must unlock it using the admin PIN, which is 12345678 by default.

You should change the admin PIN too, by running the same command again, this time selecting option 3:

```
$ gpg --change-pin
1 - change PIN
2 - unblock PIN
3 - change Admin PIN
4 - set the Reset Code
Q - quit
Your selection? 3
gpg: 3 Admin PIN attempts remaining before card is permanently locked
Please enter the Admin PIN
New Admin PIN
New Admin PIN
Admin PIN changed.
```

If you later enter the admin PIN incorrectly three times you will need to factory-reset the Yubikey.

## Configure Machines to use GPG Agent

Firstly, you need to configure ssh on the machines you’ll be working on to use gpg-agent to handle authentication, which will in turn load an RSA key from your Yubikey - provided that you enter the correct PIN.

The below snippet appends the appropriate config to your .bashrc (if you use zsh you will need to append these lines to ~/.zshrc instead).

```
$ cat <<EOF >> ~/.bashrc
export GPG_TTY=$(tty)
gpg-connect-agent updatestartuptty /bye
unset SSH_AGENT_PID
export SSH_AUTH_SOCK=$(gpgconf --list-dirs agent-ssh-socket)
EOF
$ . ~/.bashrc
```
Generate an RSA key on your Yubikey for sign GPG

I recommend generating your RSA key on the Yubikey itself, rather than generating the key on your computer and then copying it to the Yubikey. This way you know that it has never been on the filesystem, where it could be snooped upon.

```
$ gpg --card-edit

Reader ...........: Yubico YubiKey OTP FIDO CCID 00 00
Application ID ...: D****************************0
Application type .: OpenPGP
Version ..........: 2.1
Manufacturer .....: Yubico
Serial number ....: 10300768
Name of cardholder: Paul Micheli
Language prefs ...: en
Salutation .......: 
URL of public key : [not set]
Login data .......: [not set]
Signature PIN ....: not forced
Key attributes ...: rsa2048 rsa2048 rsa4096
Max. PIN lengths .: 127 127 127
PIN retry counter : 3 0 3
Signature counter : 0
Signature key ....: [none]
Encryption key....: [none]
Authentication key: [none]
General key info..: [none]
```

Input the admin argument to enable admin commands 

```
gpg/card> admin
Admin commands are allowed
```
Run the Generate command to generate the RSA key.

```
gpg/card> generate
```

You will be asked if you want to backup the encryption key. If you are only using this key for SSH authentication I would recommend you do not do this. It is fairly easy to go though this process again if you lose your Yubikey, and it means your key will never leave your Yubikey.

```
Make off-card backup of encryption key? (Y/n) n
Please note that the factory settings of the PINs are
   PIN = `123456'     Admin PIN = `12345678'
You should change them using the command --change-pin
gpg: gpg-agent is not available in this session
Please enter the PIN
What keysize do you want for the Signature key? (2048)
What keysize do you want for the Encryption key? (2048)
What keysize do you want for the Authentication key? (2048)
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
```

By default, your key will not expire. I would recommend setting an expiry date.

```
Key is valid for? (0) 1y
Key expires at Thu 11 Aug 2021 14:18:02 GMT
Is this correct? (y/N) y
You need a user ID to identify your key; the software constructs the user ID
from the Real Name, Comment and Email Address in this form:
    "Heinrich Heine (Der Dichter) <heinrichh@duesseldorf.de>"
Real name: Paul Micheli
Email address: paul@*********.com>
Comment:
You selected this USER-ID:
    "Paul Micheli <paul@*********.com>"
Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? O
gpg: generating new key
gpg: 3 Admin PIN attempts remaining before card is permanently locked
Please enter the Admin PIN
gpg: please wait while key is being generated ...
gpg: key generation completed (4 seconds)
gpg: signatures created so far: 0
gpg: generating new key
gpg: please wait while key is being generated ...
gpg: key generation completed (6 seconds)
gpg: signatures created so far: 1
gpg: signatures created so far: 2
gpg: generating new key
gpg: please wait while key is being generated ...
gpg: key generation completed (9 seconds)
gpg: signatures created so far: 3
gpg: signatures created so far: 4
gpg: key A4D581D2 marked as ultimately trusted
public and secret key created and signed.
gpg: checking the trustdb
gpg: public key of ultimately trusted key 53157188 not found
gpg: 3 marginal(s) needed, 1 complete(s) needed, PGP trust model
gpg: depth: 0  valid:   2  signed:   0  trust: 0-, 0q, 0n, 0m, 0f, 2u
gpg: next trustdb check due at 2018-11-14
pub   2**/********2 2017-11-14 [expires: 2018-11-14]
      Key fingerprint = 3***************************2
uid                  Paul Micheli <paul@*********.com>>
sub   2***/*********A 2020-08-11 [expires: 2021-08-11]
sub   2***/*********A 2020-08-11 [expires: 2021-08-11]
```

Quit

```
gpg/card> quit
```

Your RSA key is now generated, and the public key is stored on your GPG keychain.

## Viewing the public key

With your Yubikey inserted and unlocked, find the ID of your GPG key:

```
$ gpg --list-secret-keys --keyid-format LONG
/home/paulmicheli/.gnupg/pubring.kbx
------------------------------------
sec   r***/*********E 2020-07-30 [SC] [expires: 2022-07-30]
      6**************************************E     
uid                 [ultimate] Paul Micheli <paul@********.com>
ssb   r***/*********0 2020-07-30 [E] [expires: 2022-07-30]

sec>  r***/*********4 2020-07-30 [SC]
      7**************************************H
      Card serial no. = 0006 10300768
uid                 [ultimate] Paul Micheli <paul@*********.com>
ssb   r***/********8 2020-07-30 [E]
```

Then, get your public key so that you can tell GitHub about it. The argument here is the long ID from the above command:


```
$ gpg --armor --export  A97FDF705EF51C50
-----BEGIN PGP PUBLIC KEY BLOCK-----
mQG********************kyd
[NOPE NOT HAVING THE MIDDLE]
I**********************==
=ZDdO
-----END PGP PUBLIC KEY BLOCK-----
```

I have a whole series of YubiKey tips & Tricks if anyone is interested let me know

* Using your Yubikey for Signed Git Commits
* Using your YubiKeys with Acquia MFA OATH-TOTP
* Using your Yubikey to store your SSH Key (RSA 4096)
* Using Your YubiKey as a Smart Card in macOS
* Using your YubiKey for two-factor auth with GitHub