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:
- 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.
- 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.