GnuPG Part 2 – Create and Manage Keys

Here I will explain how to use GnuPG in Linux to generate a PGP keypair, add subkeys, view, export, and revoke keys, and the structure of how keys are stored.

Generate Keys

The basic command to generate a keypair is gpg --gen-key. This uses the default options and only prompts for a name and email address. The --full-gen-key option performs the same function, but with prompts for all parameters such as key type and size. The current default is a 3072-bit RSA key.

gpg --gen-key
gpg --full-gen-key

In Linux, running this or any other gpg command for the first time creates a hidden folder named .gnupg in your home directory. This is where the keys and other relevant files are stored.

View Keys

The most basic option to display current keys is --list-keys. This output can be very confusing to anyone unfamiliar with it. Let’s break it down.

gpg --list-keys
/home/john/.gnupg/pubring.kbx
-----------------------------
pub rsa3072 2020-11-11 [SC] [expires: 2022-11-11]
136FC6B4B12746249F16FEAF4405B01BFDF04FCD
uid [ultimate] John Doe <john.doe@example.com>
sub rsa3072 2020-11-11 [E] [expires: 2022-11-11]

Notice that pubring.kbx is referenced. This is the public keyring; a binary file where all of your public keys are stored. Below that are a few lines with various information. Some of it is straightforward, other things require more context. Let’s break down the different parts.

pub, subKey types (see below)
rsa3072Cipher used in the key
2020-11-11Key creation date
[SC],[E]Usage flags (see below)
[expires: 2022-11-11]Key expiration date
136FC6B4B12746249F16FEAF4405B01BFDF04FCDFingerprint (see below)
uidThe User ID of the key, which is simply the name and email address
[ultimate]Trust level (see below)

Key Types

By default, two key pairs are initially created. A master key (pub) and subkey (sub). These are the public keys for these keypairs. The --list-secret-keys option will show you the same information, but specify the secret keys.

When specifying the secret keys, the fingerprint for the public key is still shown, as a fingerprint typically is not used for private(secret) PGP keys. For all intents and purposes, the public key fingerprint identifies the keypair.

  • pub -> Public key
  • sub -> Public subkey
  • sec -> Private key
  • ssb -> Private subkey

Usage Flags

The master key and subkeys are assigned different functions, as specified by the letters contained in brackets – [SC], [E].

  • C – Certification
  • S – Signing
  • E – Encryption
  • A – Authentication

By default, the master key is assigned the Certification function (which allows it to certify additional subkeys) and the Signing function. The subkey has been given the Encryption function. In practice the master key is moved to a secure location and only used to manage subkeys and sign other public keys. Additional subkeys are added to perform all other daily functions. I will cover this in depth in another article.

Fingerprint / Key ID

The string 136FC6B4B12746249F16FEAF4405B01BFDF04FCD is the fingerprint used to identify the key pair. A key can also be identified with a key ID; either a 16-character long ID, or an 8-character short ID. These comprise the last 16 or 8 characters in the fingerprint.

Fingerprint136F C6B4 B127 4624 9F16 FEAF 4405 B01B FDF0 4FCD
Long ID---- ---- ---- ---- ---- ---- 4405 B01B FDF0 4FCD
Short ID---- ---- ---- ---- ---- ---- ---- ---- FDF0 4FCD

It is worth noting that older GnuPG versions did not show the full fingerprint by default in the --list-keys output. Instead it displayed the 8-character short ID.

pub   3072R/FDF04FCD 2020-11-11 [expires: 2022-11-11]

Trust Level

This designates whether or not you trust a key, and is used in relation to the Web of Trust when importing public keys from friends/contacts. It is a local setting used to control your personal level of trust in the keys on your keyring, and does not affect their broader validity. The trust level itself is less complicated than it may initially seem. Ultimately, keys (and therefore anything encrypted or signed by them) are either trusted or they are not. Trust level affects how this is determined.

Trust LevelDescription
UltimateThis trust level assigns complete trust regardless of the trust path, and is used only for your own keys. Any message signed using these keys is trusted. Any key that has been signed by these keys will also be trusted.
FullThis is used for keys that you fully trust to sign other keys. For instance, if you assign Full trust to Bob’s key, and he uses it to sign Alice’s key, Alice’s key will also be trusted. Full trust should only be used for keys you have verified and signed.
MarginalA key with this trust level is considered valid if it has been signed by at least three other keys with a Marginal trust-level. This option is not often used due to its complexity.
NeverThis is used to designate keys that you explicitly do not trust for whatever reason.
UnknownKeys with this level are not trusted. This is the default trust level assigned to new imported keys until another trust level is assigned.
UndefinedEffectively the same as Unknown, but is intentionally configured. This is typically used as a placeholder for keys that may have a trust level assigned at a later time.
RevokedThis indicates that a key has been revoked and is no longer trusted.

How Keys are Stored

To get a better picture of how the public and private keys are stored, let’s run the tree command on the .gnupg folder to display all files and containing folders.

tree .gnupg
.
├── openpgp-revocs.d
│   └── 136FC6B4B12746249F16FEAF4405B01BFDF04FCD.rev
├── private-keys-v1.d
│   ├── AB6757B4592AE707EC64EBFB48A7AF32AE9ED369.key
│   └── D6877214052460DB7D5C764794E0CDB356C21EBD.key
├── pubring.kbx
├── pubring.kbx~
└── trustdb.gpg

2 directories, 6 files
  • The openpgp-revocs.d directory contains revocation certificates created when keypairs are generated. The .rev files are named with the fingerprint of the corresponding keypair.
  • The private-keys-v1.d directory contains the private keys, stored in individual files unlike the public keys. The name of each of these .key files may look like a key fingerprint, but is actually the keygrip.
  • The pubring.kbx file is a keybox file used to store the public keys in a binary keyring. All public keys are stored in this file, whereas private keys are stored in individual files.
  • The trustdb.gpg file is the trust database where trust levels for keys are stored.

Keygrip

The keygrip is a unique identifier for a keypair that is protocol-agnostic, meaning it will remain consistent regardless of the protocol interacting with the keys; whereas the fingerprint will differ between protocols. This is beyond the scope of these guides, but it is worth noting that you can match the .key files with their corresponding keypair in the --list-keys output by adding the --with-keygrip option.

gpg --list-keys --with-keygrip 
/home/john/.gnupg/pubring.kbx
-----------------------------
pub rsa3072 2020-11-11 [SC] [expires: 2022-11-11]
136FC6B4B12746249F16FEAF4405B01BFDF04FCD
Keygrip = AB6757B4592AE707EC64EBFB48A7AF32AE9ED369
uid [ultimate] John Doe <john.doe@example.com>
sub rsa3072 2020-11-11 [E] [expires: 2022-11-11]
Keygrip = D6877214052460DB7D5C764794E0CDB356C21EBD

Add a Subkey

Practical PGP use typically requires creating additional subkeys. To do this, use the --edit-key option and specify the master key to add a subkey under.

gpg --edit-key <key>

When specifying a key in a command, you can use the UID, fingerprint, or key ID (long or short).

This will take you to a new prompt for managing the key.

gpg --edit-key john.doe@example.com 
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 rsa3072/4405B01BFDF04FCD
created: 2020-11-11 expires: 2022-11-11 usage: SC
trust: ultimate validity: ultimate
ssb rsa3072/81D92EAACC0DF0E4
created: 2020-11-11 expires: 2022-11-11 usage: E
[ultimate] (1). John Doe <john.doe@example.com>
gpg>

From here, use the addkey command to add a new subkey. You will be prompted to specify the parameters. In this case we will add a signing subkey.

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)
(14) Existing key from card
Your selection? 4
RSA keys may be between 1024 and 4096 bits long.
What keysize do you want? (3072) 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) 2y
Key expires at Fri 11 Nov 2022 08:52:38 PM MST
Is this correct? (y/N) y
Really create? (y/N) y

Then use the save command to save and exit.

gpg> save

The new signing subkey now appears in the list.

gpg --list-keys
/home/john/.gnupg/pubring.kbx
-----------------------------
pub rsa3072 2020-11-11 [SC] [expires: 2022-11-11]
136FC6B4B12746249F16FEAF4405B01BFDF04FCD
uid [ultimate] John Doe <john.doe@example.com>
sub rsa3072 2020-11-11 [E] [expires: 2022-11-11]
sub rsa3072 2020-11-11 [S] [expires: 2022-11-11]

Export Keys

Keys can be exported using the --export options, which vary depending on which keys you want to export.

--exportExport public keys
--export-secret-keysExport private keys
--export-secret-subkeysExport private subkeys only

By default, keys are exported in binary format. The --armor option is used to export keys in plain text.

gpg --export --armor FDF04FCD
-----BEGIN PGP PUBLIC KEY BLOCK-----
lQGVBF+sJTkBDADDFvnyKEivlX7G32p7s8z2/yRSiLB5ufrP9ximnybwxYqgAp6z
v5v3sRkFqtWqeQLbOLM3VrLUjI+ZYZStthJX8Y0wpQizdsjqNe22N5ZRBY8GOyv8
hc2VUwWt8DX2pHwQBwZ7wcjiBiYpAdLnR1dIH4eTCGruVJzLdXeip2SG18CZZz35
--Output cut for brevity--
-----END PGP PUBLIC KEY BLOCK-----

You may notice that these functions encode the master key and all subkeys for the specified identity into a single file. This is the standard way of handling PGP keys. The --export-secret-subkeys option is a function specific to GnuPG and used for storing the private master key separately from the subkeys. I will elaborate on this in a later article.

To export keys to a file, you can use the --output <filename> option or use standard Linux output redirection.

gpg --output publickeys.gpg --export --armor FDF04FCD
gpg --export --armor FDF04FCD > publickeys.gpg

Revoke Keys

In the event that you lose access to your keys or the private key becomes compromised, you will need to have a revocation certificate on hand. This is used to invalidate a keypair and inform others that it should no longer be trusted. In the latest versions of GnuPG, a revocation certificate is generated and stored in the openpgp-revocs.d directory when the keys are initially generated. This file is in plain text format and has a description that explains that the key has a colon at the beginning to prevent accidental usage.

Due to the de-centralized nature of PGP’s trust model (Web of Trust), revoking a key can be difficult, as it must be distributed to your contacts and any key servers where your public key was uploaded. This is why it is important to safeguard your keys and consider manual revocation a last resort.

If you don’t already have a revocation certificate, it can be generated with the --gen-revoke option. You will need to output it to a file.

gpg --output revoke-FDF04FCD.asc --gen-revoke FDF04FCD

The .asc extension identifies the file as an armored ASCII file. You can also use the .rev extension as seen on the files in openpgp-revocs.d. Either way it is still a plain text file and will function the same.

To revoke the key, the revocation certificate must be imported to your keyring using the --import option. In this example I will use the existing certificate in openpgp-revocs.d after removing the aforementioned colon from the file.

gpg --import .gnupg/openpgp-revocs.d/136FC6B4B12746249F16FEAF4405B01BFDF04FCD.rev

The key will now show as revoked in the --list-keys output.

gpg --list-keys 
/home/john/.gnupg/pubring.kbx
-----------------------------
pub rsa3072 2020-11-11 [SC] [revoked: 2020-11-11]
136FC6B4B12746249F16FEAF4405B01BFDF04FCD
uid [ revoked] John Doe <john.doe@example.com>

Revoke a Subkey

One reason for creating subkeys is so that they can be used for daily functions and revoked if necessary, while the master key is stored in a more secure location. The --edit-key option can be used to revoke a subkey.

gpg --edit-key FDF04FCD

When using the edit prompt, subkeys are numbered in a top-down order (although they are not labeled as such in the output). For instance, you would use key 2 to select the second subkey in the list (the signing subkey in this case). An asterisk (*) will be displayed on that line once the key has been selected.

gpg> key 2
sec rsa3072/4405B01BFDF04FCD
created: 2020-11-11 expires: 2022-11-11 usage: SC
trust: ultimate validity: ultimate
ssb rsa3072/81D92EAACC0DF0E4
created: 2020-11-11 expires: 2022-11-11 usage: E
ssb* rsa3072/9AD81DC868DAFE98
created: 2020-12-04 expires: 2021-12-04 usage: S
[ultimate] (1). John Doe <john.doe@example.com>

Once selected, use the revkey command to revoke the subkey.

gpg> revkey

The output will now show the key as revoked along with a revocation date.

sec rsa3072/4405B01BFDF04FCD
created: 2020-11-11 expires: 2022-11-11 usage: SC
trust: ultimate validity: ultimate
ssb rsa3072/81D92EAACC0DF0E4
created: 2020-11-11 expires: 2022-11-11 usage: E
The following key was revoked on 2020-12-13 by RSA key 4405B01BFDF04FCD John Doe <john.doe@example.com>
ssb rsa3072/9AD81DC868DAFE98
created: 2020-12-04 revoked: 2020-12-13 usage: S
[ultimate] (1). John Doe <john.doe@example.com>

As with other key edits, the changes must be saved.

gpg> save

<< GnuPG Part 1 – Introduction