What is Yubikey?

The Yubikey 4 is a digital security key by Yubico, packed with authentication and cryptographic features such as OpenPGP, OATH-TOTP, FIDO U2F, and PIV. In this post, we're going to leverage its OpenPGP functionality to store signing, encryption, and authentication subkeys that cannot be tampered with. You'll be able to sign your git commits and tags using your Yubikey, SSH into your remote instance, and encrypt your emails for heightened privacy.

Yubikey 4 by Yubico

Prerequisites

This post is specifically tailored for MacOS. Other OSs are similar in their setup but may require further configuration to get things working.

I'll make the following assumptions:

  • You have a Mac with MacOS 10.14 (Mojave) installed
  • You've installed GPGSuite
  • You have a Yubikey 4 (as of this writing, the Yubikey 5 series is now available at Yubico's online store with a few extra features such as NFC and new onboard crypto generators)
  • You will be generating a new key and subkeys to transfer to your Yubikey

Generating the keys

We'll use the included gpg2 command line tool to generate our master key and its subkeys.

Master key

So let's get started and generate the master key. You'll only use it for signing other keys but it has a lot of power and needs to be kept safe!

Open up a terminal and get started with:

$ gpg2 --full-generate-key

We'll go through the menus that follow one-by-one.

You are first asked what kind of key you want to generate. Since we will use the master key to only sign other keys, we will use the RSA (sign only) option:

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? 4

Yubikey 4 (and 5) support 4096 bit RSA keys. So for the added security, we will select it:

RSA keys may be between 1024 and 4096 bits long.
What keysize do you want? (2048) 4096
Requested keysize is 4096 bits

You may want to set a certain limited validity of your key depending on your use case, but for the purposes of this walkthrough, I will just select an infinite validity:

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)
Key does not expire at all
Is this correct? (y/N) y

You will now be prompted to create an associated user identity for your new key. Just follow the prompts and leave the comment blank if you'd like:

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

Real name: Duncan Dean
Email address: [email protected]
Comment:
You selected this USER-ID:
    "Duncan Dean <[email protected]>"

Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? o

GPG is now going to use your /dev/urandom to generate pseudo-random bytes using environmental noise collected from device drivers and other sources. After some time, your new key will be ready to use!

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 A34F68F9A41D01DA marked as ultimately trusted
gpg: revocation certificate stored as '/Users/duncan/.gnupg/openpgp-revocs.d/6AAFF506D269AB21F34AA4BDA34F68F9A41D01DA.rev'
public and secret key created and signed.

Note that this key cannot be used for encryption.  You may want to use
the command "--edit-key" to generate a subkey for this purpose.
pub   rsa4096 2018-10-10 [SC]
      6AAFF506D269AB21F34AA4BDA34F68F9A41D01DA
uid                      Duncan Dean <[email protected]>

In my case:

  • the key ID is A41D01DA (Last 8 digits of fingerprint)
  • the key fingerprint is 6AAFF506D269AB21F34AA4BDA34F68F9A41D01DA.

Use your key ID when you see [KEY_ID] and your key fingerprint when you see [KEY_FINGERPRINT] in any following commands in this post.

A revocation certificate was also generated, which we will store securely until we need it one day if we lose our key and want to revoke it.

Subkey 1: Signing

Next, we generate the first subkey for our master key that we will need for everyday use when it comes to signing files and commits:

$ gpg2 --expert --edit-key [KEY_ID]

Now, in the gpg console we use the addkey command to add a subkey:

gpg> addkey

Then we go through a similar set of prompts as before:

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? 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) 
Key does not expire at all
Is this correct? (y/N) y
Really create? (y/N) y

Take note of the subkey ID.

Subkey 2: Encryption

We go through the same steps as in Subkey 1, however at the first prompt for key kind, we select option (6) an RSA (encrypt only) key. Again, note down the subkey ID.

Subkey 3: Authentication

For the authentication key, the steps differ slightly to the previous two subkeys, so we'll go through them in detail.

As before, use the addkey command to start creating a subkey:

gpg> addkey

Then we want more granular configuration over the capabilities of our third subkey, so we select option (8):

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

The subkey's current configuration allows for signing and encryption, but not authentication. So we toggle signing to off:

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? s

Then toggle encryption to off:

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

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

Your selection? e

Finally, we must toggle authentication to allow it:

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

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

Your selection? a

Then we are finished with configuring the capabilities:

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

Same drill as last time, 4096 bits, with no expiry for us, thanks:

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) 
Key does not expire at all
Is this correct? (y/N) y
Really create? (y/N) y

That's it for the key generation!


Next part coming soon as an update to this post.


View this post on Instagram

Auto signing with Yubikey 4

A post shared by Duncan Dean (@this.duncs) on

Example of a git signing flow that uses the Yubikey for signing commits by default.