Step by step guide on how to set up Yubikey with GPG subkeys
Tags: yubikey, gpg, mfa, 2fa
Published: 2021-04-14 14:12:06

Everything around us is moving to digital. Our society is becoming more dependent upon online platforms, and it grows increasingly important that we embrace stronger online security measures.

Basic two-factor authentication using 6 digits and a mobile app is not enough to keep personal and professional accounts and services secured.

This method can be abused in a number of ways, like phishing attacks, third party login, and brute force.

Because of this, it’s essential for professionals to add another layer of protection, incorporating hardware devices like smart cards, and YubiKey is a popular choice for it. It allows your private key to be stored and accessed only when you need it to decrypt your data.

Up next is a simple and straightforward guide on generating GPG keys via your machine and transferring them to the security dongle YubiKey 4.
<br/>

## What is GPG?

GPG, or GNU Privacy Guard, is a public key cryptography implementation. This allows for the secure transmission of information between parties and can be used to verify that the origin of a message is genuine.
<br/>

## What is YubiKey?

The YubiKey is a hardware authentication device manufactured by Yubico that supports one-time passwords, public-key cryptography and authentication, and the Universal 2nd Factor and FIDO2 protocols developed by the FIDO Alliance.

Now that we covered all the basics let’s get to work.
<br/>

## Prerequisite
Before starting this guide, you need to download the GPG Suite.

If you work on macOS, click here to download the software installer and install it. If you work on Linux, you already have it preinstalled.

Also, you have to have a YubiKey!
<br/>

## Step 1 - generate Certify key

Start key generation by running the following command:

```
gpg --full-generate-key --expert
```
<br/>

**Certify key generation - step 1**

```
-> gpg --full-generate-key --expert
gpg (GnuPG) 2.2.19; Copyright (C) 2019 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.
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)
   (7) DSA (set your own capabilities)
   (8) RSA (set your own capabilities)
   (9) ECC and ECC
  (10) ECC (sign only)
  (11) ECC (set your own capabilities)
  (13) Existing key
  (14) Existing key from card
Your selection? 8
```
Select **8** ( RSA - set your own capabilities) and press enter.
<br/>

On this prompt, it is necessary to toggle off sign capability  (**S**) and encrypt capability (**E**) by entering capital letter associated with it and pressing enter.

When "Current allowed actions" has only "Certify", insert **Q**(finished) and press enter.
<br/>

**Certify key generation - step 2**

```
Possible actions for a RSA key: Sign Certify Encrypt Authenticate Current allowed actions: Sign Certify Encrypt
    (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 Certify Encrypt Authenticate 
Current allowed actions: Certify Encrypt
    (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 Certify Encrypt Authenticate Current allowed actions: Certify
    (S) Toggle the sign capability
    (E) Toggle the encrypt capability
    (A) Toggle the authenticate capability
    (Q) Finished Your selection? q
```
<br/>

In the following step when prompted for key size put **4096** and press enter, after that it will prompt you to input key expiration time. For this step only set it as **0** (key does not expire), press enter, and then insert **y** to confirm and press enter again.

```
RSA keys may be between 1024 and 4096 bits long. 
What keysize do you want? (3072) 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
```
<br/>

Afterward, it will request your name and email address to construct a user ID to identify the key.

The comment is optional. When satisfied enter **O** (Okay) and press enter.
<br/>

**Key identification**

```
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:
     "John Doe (Some Comment) <john.doe@email.com>" 
Real name: Real Name 
E-mail address: real.name@barrage.net 
Comment: 
You selected this USER-ID:
     "Real Name <real.name@barrage.net>" 
Change (N)ame, (C)omment, (E)-mail or (O)kay/(Q)uit? o
```
<br/>

**Important**: Popup window requesting to set passphrase will show. (it is recommended to save passphrase in LastPass or another secure password manager)

After you have set the passphrase your key has been created and you will get a message similar to one in the snipper below.
<br/>

**Key generation - random bytes**
```
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, utilise the disks) during the prime generation; this gives the random number generator a better chance to gain enough entropy.
gpg: key 9CD3AF89EB04F8FF marked as ultimately trusted
gpg: directory '/home/realname/.gnupg/openpgp-revocs.d' created
gpg: revocation certificate stored as '/home/realname/.gnupg/openpgp-revocs.d/DAF272D92DAE18C1790A1E8A7C258D4980E4DCB5.rev'
public and secret key created and signed.

pub   rsa4096 2020-06-17 [C]
      DAF272D92DAE18C1790A1E8A7C258D4980E4DCB5
uid                      Real Name <real.name@barrage.net>

```
<br/>

You have now generated your certification key.
<br/>

## Step 2 - create RSA sign only key
<br/>

After we have created the key for the certificate we need to add the rest of them.

```
gpg --edit-key --expert <your_email_address>
```
(the address you provided in the previous step)

<br/>

**Edit key**

```
gpg --edit-key --expert real.name@barrage.net   

gpg (GnuPG) 2.2.19; Copyright (C) 2019 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. 
gpg: checking the trustdb 
gpg: marginals needed: 3  completes needed: 1  trust model: pgp 
gpg: depth: 0  valid:   1  signed:   0  trust: 0-, 0q, 0n, 0m, 0f, 1u 
sec  rsa4096/7C258D4980E4DCB5
     created: 2020-06-17
     expires: never
     usage: C  
     trust: ultimate      validity: ultimate
[ultimate] (1). Real Name <real.name@barrage.net>

```
<br/>

Insert **addkey** command to start the procedure for adding the second key

**add key - RSA sign only**

```
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
   (14) Existing key from card 
Your selection? 4
```
<br/>

This step is similar to one from the creation of the first key, just on this step you choose **4** ( RSA - sign only ) and press enter

**add key - RSA sign only - length**

```
RSA keys may be between 1024 and 4096 bits long. 
What keysize do you want? (3072) 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 Thu Jun 17 09:44:10 2021 CEST 
Is this correct? (y/N) y 
Really create? (y/N) y
```
<br/>

It will again prompt you for keysize **4096** and for an expiration time. This time you input **1y** meaning the key will expire in 1 year. On the next two prompts confirm creation with inputting **y** and pressing enter. Passphrase window will pop out requiring you to insert the passphrase which you have set up in 1st step.

## Step 3 - generate RSA encrypt only key
<br/>

This step is identical as previous (STEP 2) in every part besides selecting **6** (RSA - encrypt only) on first prompt. Afterwards key length is **4096**, expiration time is **1y** and confirm twice with **y** and passphrase on end


**add key - RSA encrypt only**

```
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
  (14) Existing key from card
 
Your selection? 6
RSA keys may be between 1024 and 4096 bits long.
What keysize do you want? (3072) 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 Thu Jun 17 09:46:10 2021 CEST
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, utilise the
disks) during the prime generation; this gives the random number
generator a better chance to gain enough entropy.
sec  rsa4096/7C258D4980E4DCB5
     created: 2020-06-17  expires: never       usage: C  
     trust: ultimate      validity: ultimate
ssb  rsa4096/6DCB9294B2139D96
     created: 2020-06-17  expires: 2020-06-17  usage: S  
ssb  rsa4096/40DDCC2E39087DC0
     created: 2020-06-17  expires: 2020-06-17  usage: E  
[ultimate] (1). Real Name <real.name@barrage.net>
```
<br/>


##Step 4 - generate RSA authentication key
<br/>

This step is kind of combination between step 1 and step 2.

Insert command **addkey** and press enter, on prompt enter **8** (RSA - set your own capabilities)

This time current allowed actions start with: Sign and encrypt; you need to toggle them out and toggle in authenticate capability. It can be done by inputting **S** to toggle out Sign capability, afterward **E** to toggle out encrypt capability and finally **A** to toggle in authenticate capability. When you have only Authenticate in current allowed actions input **Q** and press enter.

**add key - RSA authentication**

```
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
  (14) Existing key from card
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? s
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
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
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

```
<br/>

Afterward key length will be prompted - **4096** again, key expiration - **1y**, confirm twice with **y** and enter passphrase. If you have done everything correctly something like this should appear

**add key - RSA authentication - length**

```
RSA keys may be between 1024 and 4096 bits long.
What keysize do you want? (3072) 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 Thu Jun 17 09:48:10 2021 CEST
Is this correct? (y/N) y
Really create? (y/N) y
```
<br/>


**add key - RSA authentication - summary**

```
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, utilise the
disks) during the prime generation; this gives the random number
generator a better chance to gain enough entropy.
sec  rsa4096/7C258D4980E4DCB5
     created: 2020-06-17  expires: never       usage: C  
     trust: ultimate      validity: ultimate
ssb  rsa4096/6DCB9294B2139D96
     created: 2020-06-17  expires: 2020-06-17  usage: S  
ssb  rsa4096/40DDCC2E39087DC0
     created: 2020-06-17  expires: 2020-06-17  usage: E   
ssb  rsa4096/23BA279F2C8D06F9
     created: 2020-06-17  expires: 2020-06-17  usage: A  
[ultimate] (1). Real Name <real.name@barrage.net>
 
gpg> save

```
<br/>

Last but not least, enter command **save** to finish your key creation process.

<br/>

## Step 5 - create backups

Run following commands to export keys

Provide passphrase where necessary.

**create backups - commands**

```
gpg --export-ownertrust > ~/.gnupg/backup_trustdb.txt
gpg --armor --export-secret-keys <your_email_address> > ~/.gnupg/secret_keys_<your_email_address>.asc
###(enter passphrase if prompted)
gpg --armor --export-secret-subkeys <your_email_address> > ~/.gnupg/secret_subkeys_<your_email_address>.asc 
###(enter passphrase if prompted)
```
<br/>

you can list keys with

**list keys**

```
ls -all ~/.gnupg/openpgp-revocs.d
```
<br/>

## Step 6 - transport keys to yubikey

Insert yubikey into usb slot in your machine and write command

```
gpg --card-status

```
<br/>

to get data from your Yubikey. If it works it should provide with Yubikey related data.

Enter command

```
gpg --card-edit

```
<br/>

to be able to edit card data. Type command

```
verify
```
<br/>

and it will prompt you administrator pin.

**Important: Default admin pin is 12345678.**

You can use command

```
help

```
<br/>

to view all possible commands for your Yubikey.

When you are done you can type command

```
quit
```
<br/>

To insert keys into your yubikey run following commands and it will output like from the screen below:

```
gpg --edit-key --expert <your_email_address>

```
<br/>

**Exporting keys to yubikey - list keys**

```
gpg --edit-key --expert john.doe@barrage.net
 
gpg (GnuPG) 2.2.19; Copyright (C) 2019 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/7C258D4980E4DCB5
     created: 2020-06-17  expires: never       usage: C  
     trust: ultimate      validity: ultimate
ssb  rsa4096/6DCB9294B2139D96
     created: 2020-06-17  expires: 2020-06-17  usage: S  
ssb  rsa4096/40DDCC2E39087DC0
     created: 2020-06-17  expires: 2020-06-17  usage: E   
ssb  rsa4096/23BA279F2C8D06F9
     created: 2020-06-17  expires: 2020-06-17  usage: A  
[ultimate] (1). Real Name <real.name@barrage.net>

```
<br/>

To add the key you need to select it and transfer to Yubikey. If for example we typekey1 it will select 1st key and put * next to its ssb (like on picture below). Typing key 1 again will deselect that key

**add key to yubikey - key 1**

```
ssb* rsa4096/2C66AD4A15960BDB
     created: 2020-06-16  expires: 2021-06-16  usage: S
```
<br/>


##Add 1st key (signature key)
<br/>

Select 1st key with command: **key 1**

Write command: **keytocard**

When it prompts where to store, type : **1** (Signature key)

enter passphrase

enter admin pin
<br/>

## Add 2nd key (encryption key)
<br/>

Deselect 1st key with command: **key 1**

Select 2nd key with command: **key 2**

Write command: **keytocard**

where to store: **2** (encryption)

enter passphrase

enter admin pin
<br/>

## Add 3rd key (authentication key)

Deselect 2nd key with command: **key 2**

Select 3rd key with command: **key 3**

Write command: **keytocard**

where to store: **3** (authentication)

enter passphrase

enter admin pin

Deselect 3rd key: **key 3**

Write command: **save**

```
gpg -k (list public keys)

gpg -K (list private keys)
```
<br/>

**Important** - You must change password and admin password on Yubikey for obvious security reasons

Enter edit mode with command: **gpg --card-edit**

Enter command: **admin** to allow admin commands

Enter command: **passwd** and following will be shown

```
1 - change PIN
2 - unblock PIN
3 - change Admin PIN
4 - set the Reset Code
Q - quit
```
<br/>

Select **1** to change PIN

enter current pin (default: 123456) 
enter new pin
confirm new pin
After you have finished PIN change it will give you the password menu again;

Select **3** to change Admin PIN 

enter current admin pin (default: 12345678)
enter new pin
confirm new pin

**Important**: Save PIN, ADMIN PIN and PASSPHRASE to LastPass and protect access to them with LastPass master password

##Step 7 - associate GPG with gitLab
<br/>

## Add GPG key in your gitlab settings
Export public key to clipboard with following command:

```
gpg --armor --export <your_email_address>  | pbcopy
```
<br/>

After that go to your gitlab site, click on your user button and click on settings in dropdown menu

<br/>

Go to the GPG Keys section in the menu, paste your public key from clipboard into text area, press add keys and the result should look like this

## Associate GPG key on your local machine to GIT repository

List your secret keys with following command

```
gpg --list-secret-keys --keyid-format LONG <your_email_address>
```
<br/>

**List secret keys**

```
sec   rsa4096/7C258D4980E4DCB5 2020-06-17 [C]
      DAF272D92DAE18C1790A1E8A7C258D4980E4DCB5
uid                 [ultimate] Real Name <real.name@barrage.net>
ssb  rsa4096/6DCB9294B2139D96 2020-06-17 [S] [expires: 2021-06-17]
ssb  rsa4096/40DDCC2E39087DC0 2020-06-17 [E] [expires: 2021-06-17]
ssb  rsa4096/23BA279F2C8D06F9 2020-06-17 [A] [expires: 2021-06-17]
```
<br/>

copy GPG key id that starts with ssb and has S next to date.

in this example → **6DCB9294B2139D96**

Run the following commands to edit your local git configuration.
```
git config --global user.signingkey 6DCB9294B2139D96
```
<br/>

```
git config --global gpg.program gpg
```
<br/>

```
git config --global commit.gpgsign true
```
<br/>