GPG¶
Most of the descripted stuff in the following was taken from https://github.com/drduh/YubiKey-Guide and is just a memory aid for myself. If you are interested in this topic I would suggest to take a look at the link.
Key structure¶
Master-Key
├─ Sub-Key 1 (Used for encryption)
├─ Sub-Key 2 (Used for signing)
└─ Sub-Key 3 (Used for authentication)
The first key to generate is the Master-Key. It will be used for certification only: to issue Sub-Keys that are used for encryption, signing and authentication.
Generating the Master-Key¶
⚠️ Important notes ⚠️
- This should be done offline!
- Do not set the master key to expire - see Note 3.
- If you want to put your Master-Key on a YubiKey you can use just some specific cryptomechanism and key lengths:
- For a YubiKey NEO: RSA 2048
- For a YubiKey 4 or 5:
- RSA 4096 (for master key)
- Elliptic Curves: https://support.yubico.com/hc/en-us/articles/360016649139-YubiKey-5-2-Enhancements-to-OpenPGP-3-4-Support#h.17w9cagj5zl8
Generate a new key with GPG, selecting (8) RSA (set your own capabilities), Certify capability only and (in my current case) 4096 bit key size.
Example
$ gpg --expert --full-generate-key
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? E
Possible actions for a RSA key: Sign Certify Encrypt Authenticate
Current allowed actions: Sign Certify
(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
(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) 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) 0
Key does not expire at all
Is this correct? (y/N) y
Input any name and email address:
GnuPG needs to construct a user ID to identify your key.
Real name: Dr Duh
Email address: doc@duh.to
Comment: [Optional - leave blank]
You selected this USER-ID:
"Dr Duh <doc@duh.to>"
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: /tmp.FLZC0xcM/trustdb.gpg: trustdb created
gpg: key 0xFF3E7D88647EBCDB marked as ultimately trusted
gpg: directory '/tmp.FLZC0xcM/openpgp-revocs.d' created
gpg: revocation certificate stored as '/tmp.FLZC0xcM/openpgp-revocs.d/011CE16BD45B27A55BA8776DFF3E7D88647EBCDB.rev'
public and secret key created and signed.
pub rsa4096/0xFF3E7D88647EBCDB 2017-10-09 [C]
Key fingerprint = 011C E16B D45B 27A5 5BA8 776D FF3E 7D88 647E BCDB
uid Dr Duh <doc@duh.to>
Sub-keys¶
Use a 1 year expiration for sub-keys - they can be renewed using the offline master key. See rotating keys.
Edit the master key to add sub-keys:
$ gpg --expert --edit-key $KEYID
Secret key is available.
sec rsa4096/0xEA5DE91459B80592
created: 2017-10-09 expires: never usage: C
trust: ultimate validity: ultimate
[ultimate] (1). Dr Duh <doc@duh.to>
Use 4096-bit RSA keys.
Now follow the steps regarding on your purpose. After you create the specific Sub-Keys finish your work by saving the keys:
gpg> save
Signing¶
Create a signing key by selecting addkey then (4) RSA (sign only)
Example
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? 10
Please select which elliptic curve you want:
(1) Curve 25519
(3) NIST P-256
(4) NIST P-384
(5) NIST P-521
(6) Brainpool P-256
(7) Brainpool P-384
(8) Brainpool P-512
(9) secp256k1
Your selection? 1
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 Wed Dec 6 07:31:15 2023 CET
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 rsa4096/0xFF3E7D88647EBCDB
created: 2017-10-09 expires: never usage: C
trust: ultimate validity: ultimate
ssb ed25519/0xBECFA3C1AE191D15
created: 2017-10-09 expires: 2018-10-09 usage: S
[ultimate] (1). Dr Duh <doc@duh.to>
Encryption¶
Create an encryption key by selecting (6) RSA (encrypt only)
Example
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
Your selection? 6
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) 1y
Key expires at Mon 10 Sep 2018 00:00:00 PM UTC
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 rsa4096/0xFF3E7D88647EBCDB
created: 2017-10-09 expires: never usage: C
trust: ultimate validity: ultimate
ssb rsa4096/0xBECFA3C1AE191D15
created: 2017-10-09 expires: 2018-10-09 usage: S
ssb rsa4096/0x5912A795E90DD2CF
created: 2017-10-09 expires: 2018-10-09 usage: E
[ultimate] (1). Dr Duh <doc@duh.to>
Authentication¶
Create an authentication key.
GPG doesn't provide an authenticate-only key type, so select (8) RSA (set your own capabilities) and toggle the required capabilities until the only allowed action is Authenticate:
Example
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
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
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) 1y
Key expires at Mon 10 Sep 2018 00:00:00 PM UTC
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 rsa4096/0xFF3E7D88647EBCDB
created: 2017-10-09 expires: never usage: C
trust: ultimate validity: ultimate
ssb rsa4096/0xBECFA3C1AE191D15
created: 2017-10-09 expires: 2018-10-09 usage: S
ssb rsa4096/0x5912A795E90DD2CF
created: 2017-10-09 expires: 2018-10-09 usage: E
ssb rsa4096/0x3F29127E79649A3D
created: 2017-10-09 expires: 2018-10-09 usage: A
[ultimate] (1). Dr Duh <doc@duh.to>
Export secret keys¶
The master key and sub-keys will be encrypted with your passphrase when exported.
Save a copy of your keys:
$ gpg --armor --export-secret-keys $KEYID > $GNUPGHOME/mastersub.key
$ gpg --armor --export-secret-subkeys $KEYID > $GNUPGHOME/sub.key
Backup and store the master key in a safe place, it is best practice to never rule out the possibility of losing it or having the backup fail. Without the master key, it will be impossible to renew or rotate subkeys or generate a revocation certificate, the PGP identity will be useless.
Revocation certificate¶
To create the revocation certificate:
$ gpg --output $GNUPGHOME/revoke.asc --gen-revoke $KEYID
The revoke.asc certificate file should be stored (or printed) in a (secondary) place that allows retrieval in case the main backup fails.
Export public keys¶
$ gpg --armor --export $KEYID | doas tee /mnt/public/gpg-$KEYID-$(date +%F).asc
# Put on Keyserver
$ gpg --send-key $KEYID
$ gpg --keyserver pgp.mit.edu --send-key $KEYID
$ gpg --keyserver keys.gnupg.net --send-key $KEYID
$ gpg --keyserver hkps://keyserver.ubuntu.com:443 --send-key $KEYID
Rotating keys¶
When a sub-key expires, it can either be renewed or replaced. Both actions require access to the offline master key.
- Renewing sub-keys by updating their expiration date indicates you are still in possession of the offline master key and is more convenient.
- Replacing keys, on the other hand, is less convenient but more secure:
- the new sub-keys will not be able to decrypt previous messages, authenticate with SSH, etc.
- Contacts will need to receive the updated public key and any encrypted secrets need to be decrypted and re-encrypted to new sub-keys to be usable.
- This process is functionally equivalent to "losing" the key. However, you will always be able to decrypt previous messages using the offline encrypted backup of the original keys.
Neither rotation method is superior and it's up to personal philosophy on identity management and individual threat model to decide which one to use.
Sub-keys should be ephemeral
Edit the master key:
$ gpg --expert --edit-key $KEYID
Secret key is available
[...]
Renewing sub-keys¶
Renewing sub-keys is simple: - you do not need to generate new keys, - move keys to the YubiKey, - or update any SSH public keys linked to the GPG key
All you need to do is to change the expiry time associated with the public key (which requires access to the master key you just loaded) and then to export that public key and import it on any computer where you wish to use the GPG (as distinct from the SSH) key.
Example
To change the expiration date of all sub-keys, start by selecting all keys:$ gpg --edit-key $KEYID
Secret key is available.
sec rsa4096/0xFF3E7D88647EBCDB
created: 2017-10-09 expires: never usage: C
trust: ultimate validity: ultimate
ssb rsa4096/0xBECFA3C1AE191D15
created: 2017-10-09 expires: 2018-10-09 usage: S
ssb rsa4096/0x5912A795E90DD2CF
created: 2017-10-09 expires: 2018-10-09 usage: E
ssb rsa4096/0x3F29127E79649A3D
created: 2017-10-09 expires: 2018-10-09 usage: A
[ultimate] (1). Dr Duh <doc@duh.to>
gpg> key 1
Secret key is available.
sec rsa4096/0xFF3E7D88647EBCDB
created: 2017-10-09 expires: never usage: C
trust: ultimate validity: ultimate
ssb* rsa4096/0xBECFA3C1AE191D15
created: 2017-10-09 expires: 2018-10-09 usage: S
ssb rsa4096/0x5912A795E90DD2CF
created: 2017-10-09 expires: 2018-10-09 usage: E
ssb rsa4096/0x3F29127E79649A3D
created: 2017-10-09 expires: 2018-10-09 usage: A
[ultimate] (1). Dr Duh <doc@duh.to>
gpg> key 2
Secret key is available.
sec rsa4096/0xFF3E7D88647EBCDB
created: 2017-10-09 expires: never usage: C
trust: ultimate validity: ultimate
ssb* rsa4096/0xBECFA3C1AE191D15
created: 2017-10-09 expires: 2018-10-09 usage: S
ssb* rsa4096/0x5912A795E90DD2CF
created: 2017-10-09 expires: 2018-10-09 usage: E
ssb rsa4096/0x3F29127E79649A3D
created: 2017-10-09 expires: 2018-10-09 usage: A
[ultimate] (1). Dr Duh <doc@duh.to>
gpg> key 3
Secret key is available.
sec rsa4096/0xFF3E7D88647EBCDB
created: 2017-10-09 expires: never usage: C
trust: ultimate validity: ultimate
ssb* rsa4096/0xBECFA3C1AE191D15
created: 2017-10-09 expires: 2018-10-09 usage: S
ssb* rsa4096/0x5912A795E90DD2CF
created: 2017-10-09 expires: 2018-10-09 usage: E
ssb* rsa4096/0x3F29127E79649A3D
created: 2017-10-09 expires: 2018-10-09 usage: A
[ultimate] (1). Dr Duh <doc@duh.to>
Then, use the expire command to set a new expiration date. (Despite the name, this will not cause currently valid keys to become expired.)
gpg> expire
Changing expiration time for a subkey.
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)
Follow these prompts to set a new expiration date, then save to save your changes.
Next, export the public key:
$ gpg --armor --export $KEYID > gpg-$KEYID-$(date +%F).asc
Transfer that public key to the computer from which you use your GPG key, and then import it with:
$ gpg --import gpg-0x*.asc
This will extend the validity of your GPG key and will allow you to use it for SSH authorization. Note that you do not need to update the SSH public key located on remote servers.
Rotating keys¶
Rotating keys is more a bit more involved. First, follow the original steps to generate each sub-key. Previous sub-keys may be kept or deleted from the identity.
Usefull commands¶
List existing keys¶
$ gpg --list-secret-keys --keyid-format LONG
List also the fingerprints of the sub-keys:
gpg --list-secret-keys --with-subkey-fingerprints --keyid-format LONG
Get the public key of a key¶
$ gpg --armor --export $KEYID
Delete existing key¶
# Delete pub key
$ gpg --delete-key $KEYID
# Delte secret key
$ gpg --delete-secret-key $KEYID