BXG Blog

Improving Private Key Security with a Yubikey: Creating the Master Key

Now that the Yubikeys are set up to work with OpenPGP, we need to generate a master key. The master key is used to create and revoke subkeys, but doesn’t need to be used for day-to-day operations. If you’re interested in more details about keys vs subkeys, Debian has a good explanation.

Ideally, the master key should be kept offline to reduce the risk of compromise. gpg doesn’t offer a direct way to do this, but we can swap out its configuration directory between operations so that our normal running config doesn’t contain the master key except when we’re using it. The easiest way I’ve seen to do this is to set the GNUPGHOME environment variable, so that’s what I’ll show here. We could also move ~/.gnupg out of the way and put it back or pass --homedir to gpg each time.

As mentioned in the first part of the series, 3072 bits should be large enough. I also set the master key expiration to 10 years to make sure that I have to eventually review my setup.

Last, I need to make sure to remove the signing flag from my key. This requires using expert mode.

Create our offline directory:

$ export GNUPGHOME=/path/to/offline/gnupg
$ mkdir $GNUPGHOME
$ chmod 0700 $GNUPGHOME

Set gpg to use stronger default algorithms:

$ cat >$GNUPGHOME/gpg.conf <<'EOF'
personal-digest-preferences SHA256
cert-digest-algo SHA256
default-preference-list SHA512 SHA384 SHA256 SHA224 AES256 AES192 AES CAST5 ZLIB BZIP2 ZIP Uncompressed
keyid-format long
EOF

Generate the master key itself:

$ gpg2 --full-generate-key --expert
gpg (GnuPG) 2.2.3; 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.

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
Your selection? 8

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
RSA keys may be between 1024 and 4096 bits long.
What keysize do you want? (2048) 3072
Requested keysize is 3072 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) 10y
Key expires at Wed 01 Nov 2027 07:08:06 PM MST
Is this correct? (y/N) y

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

Real name: Benjamin Gordon
Email address: ben@bxg.org
Comment:
You selected this USER-ID:
    "Benjamin Gordon <ben@bxg.org>"

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.
gpg: /home/ben/gnupg-master/trustdb.gpg: trustdb created
gpg: key 24770C40DF746792 marked as ultimately trusted
gpg: directory '/home/ben/gnupg-master/openpgp-revocs.d' created
gpg: revocation certificate stored as '/home/ben/gnupg-master/openpgp-revocs.d/BCD38E83FED87BA945B65D7B24770C40DF746792.rev'
public and secret key created and signed.

pub   rsa3072/24770C40DF746792 2017-11-04 [C] [expires: 2027-11-02]
      BCD38E83FED87BA945B65D7B24770C40DF746792
uid                            Benjamin Gordon <ben@bxg.org>

Notice that gpg created a revocation certificate for us already. If it hadn’t, now would be a good time to do so. Make sure to keep this revocation certificate backed up and stored securely (probably with the offline master key).

Now we need to generate encryption and signing subkeys with gpg. I want to do this with gpg instead of directly on the Yubikey for two main reasons:

  1. I want to share these two subkeys across multiple Yubikeys. If the key is generated on the device, it can’t be extracted, so there’s no way to back it up or copy to another device.
  2. The Yubikey prime generation and key generation algorithms are not open source, and I don’t want to risk discovering another ROCA-style vulnerability that affects my keys later.

Add the two subkeys:

$ gpg2 --edit-key 24770C40DF746792
gpg (GnuPG) 2.2.3; 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  rsa3072/24770C40DF746792
     created: 2017-11-04  expires: 2027-11-02  usage: C   
     trust: ultimate      validity: ultimate
[ultimate] (1). Benjamin Gordon <ben@bxg.org>

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? 6
RSA keys may be between 1024 and 4096 bits long.
What keysize do you want? (2048) 
Requested keysize is 2048 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) 2y
Key expires at Tue 03 Nov 2019 07:29:05 PM MST
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  rsa3072/24770C40DF746792
     created: 2017-11-04  expires: 2027-11-02  usage: C   
     trust: ultimate      validity: ultimate
ssb  rsa2048/1F9F9EEFA71FF33A
     created: 2017-11-04  expires: 2019-11-04  usage: E   
[ultimate] (1). Benjamin Gordon <ben@bxg.org>

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) 
Requested keysize is 2048 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) 2y
Key expires at Tue 03 Nov 2019 07:30:10 PM MST
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  rsa3072/24770C40DF746792
     created: 2017-11-04  expires: 2027-11-02  usage: C   
     trust: ultimate      validity: ultimate
ssb  rsa2048/1F9F9EEFA71FF33A
     created: 2017-11-04  expires: 2019-11-04  usage: E   
ssb  rsa2048/935364AE6E8071BD
     created: 2017-11-04  expires: 2019-11-04  usage: S   
[ultimate] (1). Benjamin Gordon <ben@bxg.org>

gpg> save

Next, back those new keys up. Make sure to keep this file safe. While we’re loading the Yubikeys, we’ll need to restore them a couple of times, so keep the backups handy for now.

$ gpg2 --armor --export-secret-keys 24770C40DF746792 > $GNUPGHOME/24770C40DF746792.pgp.asc
$ gpg2 --armor --export-secret-subkeys 1F9F9EEFA71FF33A > $GNUPGHOME/1F9F9EEFA71FF33A.pgp.asc
$ gpg2 --armor --export-secret-subkeys 935364AE6E8071BD > $GNUPGHOME/935364AE6E8071BD.pgp.asc

Next, generate a new authentication key and move the signing/encryption keys to the card. This needs to be repeated for each Yubikey. I like to delete and re-import my private key before starting each one to make sure I’m in a known state. Moving the subkey to a card removes it from the on-disk keyring, so re-importing is required after the first one, anyway.

$ gpg2 --delete-secret-key 24770C40DF746792
gpg (GnuPG) 2.2.3; 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.


sec  rsa3072/24770C40DF746792 2017-12-04 Benjamin Gordon <ben@bxg.org>

Delete this key from the keyring? (y/N) y
This is a secret key! - really delete? (y/N) y

$ gpg2 --import $GNUPGHOME/24770C40DF746792.pgp.asc 
gpg: key 24770C40DF746792: "Benjamin Gordon <ben@bxg.org>" not changed
gpg: key 24770C40DF746792: secret key imported
gpg: Total number processed: 1
gpg:              unchanged: 1
gpg:       secret keys read: 1
gpg:   secret keys imported: 1

$ gpg2 --edit-key 24770C40DF746792
gpg (GnuPG) 2.2.3; 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  rsa3072/24770C40DF746792
     created: 2017-11-04  expires: 2027-11-02  usage: C   
     trust: ultimate      validity: ultimate
ssb  rsa2048/1F9F9EEFA71FF33A
     created: 2017-11-04  expires: 2019-11-04  usage: E   
ssb  rsa2048/935364AE6E8071BD
     created: 2017-11-04  expires: 2019-11-04  usage: S   
[ultimate] (1). Benjamin Gordon <ben@bxg.org>

gpg> addcardkey
Signature key ....: [none]
Encryption key....: [none]
Authentication key: [none]

Please select the type of key to generate:
   (1) Signature key
   (2) Encryption key
   (3) Authentication key
Your selection? 3
What keysize do you want for the Authentication key? (25519) 2048
The card will now be re-configured to generate a key of 2048 bits
Note: There is no guarantee that the card supports the requested size.
      If the key generation does not succeed, please check the
      documentation of your card to see what sizes are allowed.
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) 2y
Key expires at Tue 03 Nov 2019 08:13:11 PM MST
Is this correct? (y/N) y
Really create? (y/N) y

sec  rsa3072/24770C40DF746792
     created: 2017-11-04  expires: 2027-11-02  usage: C   
     trust: ultimate      validity: ultimate
ssb  rsa2048/1F9F9EEFA71FF33A
     created: 2017-11-04  expires: 2019-11-04  usage: E   
ssb  rsa2048/935364AE6E8071BD
     created: 2017-11-04  expires: 2019-11-04  usage: S   
ssb  rsa2048/BAB118CABB39E1EB
     created: 2017-11-04  expires: 2019-11-04  usage: A   
     card-no: 0006 07020132
[ultimate] (1). Benjamin Gordon <ben@bxg.org>

gpg> toggle

sec  rsa3072/24770C40DF746792
     created: 2017-11-04  expires: 2027-11-02  usage: C   
     trust: ultimate      validity: ultimate
ssb  rsa2048/1F9F9EEFA71FF33A
     created: 2017-11-04  expires: 2019-11-04  usage: E   
ssb  rsa2048/935364AE6E8071BD
     created: 2017-11-04  expires: 2019-11-04  usage: S   
ssb  rsa2048/BAB118CABB39E1EB
     created: 2017-11-04  expires: 2019-11-04  usage: A   
     card-no: 0006 07020132
[ultimate] (1). Benjamin Gordon <ben@bxg.org>

gpg> key 1

sec  rsa3072/24770C40DF746792
     created: 2017-11-04  expires: 2027-11-02  usage: C   
     trust: ultimate      validity: ultimate
ssb* rsa2048/1F9F9EEFA71FF33A
     created: 2017-11-04  expires: 2019-11-04  usage: E   
ssb  rsa2048/935364AE6E8071BD
     created: 2017-11-04  expires: 2019-11-04  usage: S   
ssb  rsa2048/BAB118CABB39E1EB
     created: 2017-11-04  expires: 2019-11-04  usage: A   
     card-no: 0006 07020132
[ultimate] (1). Benjamin Gordon <ben@bxg.org>

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

sec  rsa3072/24770C40DF746792
     created: 2017-11-04  expires: 2027-11-02  usage: C   
     trust: ultimate      validity: ultimate
ssb* rsa2048/1F9F9EEFA71FF33A
     created: 2017-11-04  expires: 2019-11-04  usage: E   
ssb  rsa2048/935364AE6E8071BD
     created: 2017-11-04  expires: 2019-11-04  usage: S   
ssb  rsa2048/BAB118CABB39E1EB
     created: 2017-11-04  expires: 2019-11-04  usage: A   
     card-no: 0006 07020132
[ultimate] (1). Benjamin Gordon <ben@bxg.org>

gpg> key 2

sec  rsa3072/24770C40DF746792
     created: 2017-11-04  expires: 2027-11-02  usage: C   
     trust: ultimate      validity: ultimate
ssb* rsa2048/1F9F9EEFA71FF33A
     created: 2017-11-04  expires: 2019-11-04  usage: E   
ssb* rsa2048/935364AE6E8071BD
     created: 2017-11-04  expires: 2019-11-04  usage: S   
ssb  rsa2048/BAB118CABB39E1EB
     created: 2017-11-04  expires: 2019-11-04  usage: A   
     card-no: 0006 07020132
[ultimate] (1). Benjamin Gordon <ben@bxg.org>

gpg> key 1

sec  rsa3072/24770C40DF746792
     created: 2017-11-04  expires: 2027-11-02  usage: C   
     trust: ultimate      validity: ultimate
ssb  rsa2048/1F9F9EEFA71FF33A
     created: 2017-11-04  expires: 2019-11-04  usage: E   
ssb* rsa2048/935364AE6E8071BD
     created: 2017-11-04  expires: 2019-11-04  usage: S   
ssb  rsa2048/BAB118CABB39E1EB
     created: 2017-11-04  expires: 2019-11-04  usage: A   
     card-no: 0006 07020132
[ultimate] (1). Benjamin Gordon <ben@bxg.org>

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

sec  rsa3072/24770C40DF746792
     created: 2017-11-04  expires: 2027-11-02  usage: C   
     trust: ultimate      validity: ultimate
ssb  rsa2048/1F9F9EEFA71FF33A
     created: 2017-11-04  expires: 2019-11-04  usage: E   
ssb* rsa2048/935364AE6E8071BD
     created: 2017-11-04  expires: 2019-11-04  usage: S   
ssb  rsa2048/BAB118CABB39E1EB
     created: 2017-11-04  expires: 2019-11-04  usage: A   
     card-no: 0006 07020132
[ultimate] (1). Benjamin Gordon <ben@bxg.org>

gpg> save

Repeat this for each additional Yubikey. When you’re finally done, export the public key:

$ gpg2 --armor --export 24770C40DF746792 > 24770C40DF746792.pgp.asc

And upload this to a public keyserver or post it on your web site somewhere. If you post it on your web site, save the URL for the next step.

Last, switch back to your normal gpg directory (and take the master key safely offline somewhere):

unset GNUPGHOME
# Import the public key here if you want, or we'll do it later.

And there you have it. A new master gpg key and a bunch of Yubikeys with the subkeys. These aren’t quite ready to use yet; next time I’ll go through changing the Yubikey settings and re-attaching them to the main gpg keyring.