A Visual Explanation of GPG Subkeys

Posted on June 10, 2022 by Richard Goulter
Tags: ,

As with anyone who’s been using git for long enough, I’m familiar enough with SSH keys (Even to the point where I don’t really need to follow the GitHub docs for generating a new key.

My developer journey hasn’t led me to build the same intuition for GPG keys.

So, when I see fancy wiki pages and guids, such as Debian wiki’s page on subkeys, on offline master keys, or on an airgapped master key, it sounds really fancy; but I’m left curious to get an intuition for what’s going on.

I hope to use this blogpost illustrate enough of the details to build an intuition.

Public Key Cryptography

The Wikipedia page on Public Key cryptography has some nice diagrams.

This itself should still be relatively straightforward, comparing with how SSH keys get used with git forges like GitHub, and with SSHing into servers:

So it makes sense: Encrypting;

Or signing:

The Rote GPG Commands

So far, we can just label everything above with “GPG” and it still makes sense:

e.g. Key generation could be done by invoking a command like:

gpg --quick-generate-key "Richard Goulter (NixOS Desktop) <richard.goulter@rgoulter.com>"

e.g. exporting a key, to copy the public part to GitHub or whatever could be done by invoking a command like:

gpg --export --armor "Richard Goulter (NixOS Desktop)"

e.g. encrypting/decrypting a message could be done by invoking a command like:

gpg --encrypt --recipient "My Colleague" document.txt

and the recipient could decrypt it with:

gpg --decrypt document.txt.gpg

e.g. signing could be done by invoking a command like:

gpg --clearsign file.txt

or

gpg --detach-sign file.txt

and the signature could be verified with a command like:

gpg --verify file.txt.asc

or

gpg --verify file.txt.sig

What Starts to Confuse Me: Subkeys

Okay, but having created a key, then list the keys:

gpg --list-keys

outputs something like:

pub   rsa4096 2020-10-05 [SC] [expires: 2022-08-01]
      D9463A85F093811B887DE4B03229F4BB09CC8A22
uid           [ultimate] Richard Goulter (NixOS Desktop) 
sub   rsa4096 2020-10-05 [E] [expires: 2022-08-01]

and secret keys:

gpg --list-secret-keys

outputs something like:

sec   rsa4096 2020-10-05 [SC] [expires: 2022-08-01]
      D9463A85F093811B887DE4B03229F4BB09CC8A22
uid           [ultimate] Richard Goulter (NixOS Desktop) 
ssb   rsa4096 2020-10-05 [E] [expires: 2022-08-01]

I can see the only difference is pub, sub, vs sec and ssb. What?

What’s [SC], [E]?

And if you enable some recommended options in ~/.gnupg/gpg.conf:

keyid-format LONG
with-fingerprint
with-keygrip

re-running:

gpg --list-keys

outputs:

pub   rsa4096/3229F4BB09CC8A22 2020-10-05 [SC] [expires: 2022-08-01]
      Key fingerprint = D946 3A85 F093 811B 887D  E4B0 3229 F4BB 09CC 8A22
      Keygrip = 480A928A7AA17A693FDF4F4E9DEAEBEE1B778FB7
uid                 [ultimate] Richard Goulter (NixOS Desktop) 
sub   rsa4096/15BAE7FB6F3DA787 2020-10-05 [E] [expires: 2022-08-01]
      Keygrip = A996CF5366A2FFCA11EE958FBA3AC4BDFDB6AC76

I feel like this one I’m allowed to be confused by.

Long Id?

Fingerprint??

Keygrip???

A Key Consisting of Multiple Keys

Uh. Hopefully it’s not too late in this blogpost to mention it.
But “key” gets used in multiple ways e.g. “running gpg --quick-generate-key generates a GPG ‘key’”, and in “a GPG ‘key’ consists of at least one key pair”.

Generally, context is often enough to disambiguate these. But given that GPG is confusing enough as it is, it’s worth mentioning the ambiguity.

Taking a look at the terminology GPG’s manual uses: https://www.gnupg.org/gph/en/manual.html#CONCEPTS

GnuPG uses a somewhat more sophisticated scheme in which a user has a primary keypair and then zero or more additional subordinate keypairs. The primary and subordinate keypairs are bundled to facilitate key management and the bundle can often be considered simply as one keypair.

This excerpt refers to the keys being ‘bundled’, and that the bundle can often be considered as a keypair.

The GnuPG FAQ has an answer which better describes the ambiguity. https://www.gnupg.org/faq/gnupg-faq.html#define_key

The word ‘key’ is unfortunately ambiguous. It can either refer to the mathematical structures that allow encryption, decryption, signing and verification to occur, or to the rather large blobs of data that contain those mathematical structures as well as information about the person associated with it, additional subkeys, and so forth.

With respect to the large blobs of data, it is preferable to call them ‘certificates’, so that the word ‘key’ may be unambiguously recognized as meaning just the mathematical structures. Unfortunately, this is a custom that seems to be honored mostly in the breach.

In this blogpost, I’ll try to use the word “key” in scare quotes to indicate “bundle of key pairs”.

Other GPG Features/Complications

So while I feel like the idea of “a key pair, with a private part and a public part” is understandable, there are other features of GPG “keys” which make things more complicated:

GPG “keys” can be set with an expiry date.
(This is useful as a way of indicating you’ve still got access to the private key).

GPG “keys” can have multiple “User IDs” (Name + email). Photos can be included in the GPG “key”.

GPG “keys” can be signed. Or more specifically: the keys and UIDs can be signed.
– I don’t find this intuitive. Sure, Bruce Wayne and Batman are different identities, but I don’t see why they’d want to use the same key.

GPG “keys” can be revoked. That is, an indication that other subkeys or UIDs or signatures should not be trusted.
– I didn’t find this intuitive.

GPG “keys” can have some level of trust.
– This also seems unintuitive to me.

Why Subkeys are Subkeys

I found this StackOverflow answer about why different keys are used for encryption vs signing illuminating:

If you look into the details of the math of public-key encryption, you will discover that signing and decrypting are actually identical operations. Thus in a naïve implementation it is possible to trick somebody into decrypting a message by asking them to sign it.

i.e. it would be bad a idea to use the same (sub)key for both signing and encryption. So, GPG uses a separate subkey for at least encryption.

This answer also explains what the [SC] and [E] refer to:

E = encrypt/decrypt (decrypt a message you received encrypted for you to read)
S = sign (sign data. For example a file or to send signed e-mail)
C = certify (sign another key, establishing a trust-relation)
A = authentication (log in to SSH with a PGP key; this is relatively new usage)

The Wikipedia page about RSA gives an example of using RSA keys, which is useful for understanding “signing and decrypting are identical operations”.

The GPG User Guide (Section “Key Management”, subsection “Key integrity”) sort of does explain the “master” and “subordinate” part:

Using digital signatures is a solution to this problem. When data is signed by a private key, the corresponding public key is bound to the signed data. In other words, only the corresponding public key can be used to verify the signature and ensure that the data has not been modified. A public key can be protected from tampering by using its corresponding private master key to sign the public key components and user IDs, thus binding the components to the public master key. Signing public key components with the corresponding private master signing key is called self-signing, and a public key that has self-signed user IDs bound to it is called a certificate.

The ‘self-signing’ of sub-keys by the master key is a detail which wasn’t clear to me.

“Subordinate” is a surprising word here.
Even the absolutely excellent post “anatomy of a gpg key” expands “subkey” to “sub-component of another key”, not “subordinate key”.

I further feel vindication in that the website https://gpg.wtf/ also discusses ‘what a subkey is’ in its “things that are confusing about gpg”.

The “master key signs the subkeys” can be seen by running a command like:

gpg --check-signatures 0x3229F4BB09CC8A22

which outputs something like:

pub   rsa4096/0x3229F4BB09CC8A22 2020-10-05 [SC] [expires: 2022-08-01]
      Key fingerprint = D946 3A85 F093 811B 887D  E4B0 3229 F4BB 09CC 8A22
      Keygrip = 480A928A7AA17A693FDF4F4E9DEAEBEE1B778FB7
uid                   [ultimate] Richard Goulter (NixOS Desktop) 
sig!3        0x3229F4BB09CC8A22 2022-05-03  Richard Goulter (NixOS Desktop) 
sub   rsa4096/0x15BAE7FB6F3DA787 2020-10-05 [E] [expires: 2022-08-01]
      Keygrip = A996CF5366A2FFCA11EE958FBA3AC4BDFDB6AC76
sig!         0x3229F4BB09CC8A22 2022-05-03  Richard Goulter (NixOS Desktop) 

gpg: 2 good signatures

i.e. The GPG “key” has:

Illustrating the Rote GPG Operations

Going back over the rote commands again, now with a diagrams to illustrate subkeys at work:

Key Generation

could be done by invoking a command like:

gpg --quick-generate-key "Richard Goulter (NixOS Desktop) <richard.goulter@rgoulter.com>"

Export Public Key

Exporting the key to copy the public part to GitHub or whatever:

could be done by invoking a command like:

gpg --export --armor "Richard Goulter (NixOS Desktop)"

Encrypting/Decrypting a Message

could be done by invoking a command like:

gpg --encrypt --recipient "My Colleague" document.txt

and the recipient could decrypt it with:

gpg --decrypt document.txt.gpg

Signing

could be done by invoking a command like:

gpg --clearsign file.txt

or

gpg --detach-sign file.txt

and the signature could be verified with a command like:

gpg --verify file.txt.asc

or

gpg --verify file.txt.sig

GPG for SSH

Again, coming from the mindset of “SSH keys for pushing to git repositories, gpg for signing stuff”, hearing “GPG ‘keys’ can be used for SSH too” sounds like wizardry.

This is also where “keygrip” comes into use. As this blogpost discussing GPG fingerprint vs SSH key fingerprint vs GPG keygrip explains, the keygrip is a way of identifying the key regardless of protocol/usage.

Now that I have a better understanding of subkeys, it seems the main points for “using GPG for SSH” involves two things to understand:

Visualisation of the Offline Master Key Setup

With the above in mind, a summary of the result of these tutorials for setting up master keys could be visualised as follows:

Which seems less complex than all the confusion I had over it made it out to be.

As the Debian wiki article pages discuss, because the private master key is used to self-sign the subkeys in the GPG “key”, it can then be used to revoke the other subkeys.

Yubikey as a GPG Smart Card

Yubikeys can then allow a nicer User Experience for using GPG keys. e.g. the Yubikey supports 3 slots for private keys: for signing, encryption, or authentication.

e.g. Yubico’s PGP walkthrough.


Newer post Older post