GPG keyservers and signatures: what happened to my signatures?!
One of the most important parts of PGP is keysigning. Key signatures allow users to share their trust in other users’ public keys, and are the primary building block in the web of trust model.
Given how important key signatures are, it may come as a surprise that GPG (one of the most commonly used PGP programs) makes it frustratingly difficult to retrieve the signatures on other people’s public keys. GPG does not automatically pull signatures from keyservers when receiving public keys, nor does it show an option to do so in either the
--help menu or the man pages. The only place where I could find how to do this was a brief mention in the 242-page GPG manual, so I wrote this post which summarises how to do so.
Scroll to the bottom for if you’re only interested in the command used.
What are PGP signatures anyway?
Before we talk about what a PGP signature is, we must first discuss what a PGP key is.
Broadly speaking, when you create a PGP key, you’re creating two things: a public-private keypair, and an identity (name and email address) which represents your keys. When you first create a PGP key, you’re automatically given a primary key (which is used to sign all your other keys), an encryption sub-key (which is used to encrypt and decrypt emails sent to you), and a single identity. Your primary key will automatically sign all your sub-keys as well as your identities (these are known as self-signatures, since you’re signing yourself).
After creating your key, you can then attach new identities to it. For example, you can attach alternate names which you go by or email addresses which you want to be covered by your PGP key. You can (and should) also create new sub-keys, each of which is used for a specific purpose. (You might want to use one subkey to be used for signing your Git commits, another for sending secure emails to your loved ones and another for receiving security disclosures from researchers.) Doing so also gives the advantage that, if you lose a sub-key or it expires, it can be revoked without affecting your other sub-keys or your primary key.
In the end, your PGP key might look like this:
However, a public key on its own does little to attest its own validity. Anyone can create a public key claiming to be from Alice, sign their own key and publish it, so we need a mechanism to know when to trust other people’s public keys.
Key signatures solve this problem. A PGP key signature is a digital signature which demonstrates that the signer is confident that the signee’s key really belongs to the signee. What exactly constitutes enough confidence varies: for example, a signer might only sign the public keys of people that they know personally, or might be content with signing strangers’ keys provided that the signee meets in person and shows their passport and public key fingerprint. Because, by nature, PGP key signatures are existentially unforgeable, a signature from user Alice on Bob’s public key gives us overwhelming confidence that Alice Bob’s public key. If we know that the user Alice is actually controlled by Alice, and that Alice is careful in signing other people’s public keys, this gives us a degree of confidence that Bob’s public key is actually controlled by Bob. This is the foundation of the web of trust model.
We can see what a signature looks like under the hood as well. If we export a PGP public key to the file
public-key.asc and run
gpg --list-packets < public-key.asc, we see the segments of data that make up the public key.
In total, we get about 60 lines of data. That’s a lot! However, the most notable things are the key ID, email addresses, self-signatures and various other bits of data about the key in the packets.
Now let’s suppose that we wish to sign the key using our own key. We do this using
gpg -u <signing_key_id> --sign-key <signee_key_id>. Once we’ve signed the key, we can export it again and view it using
Most of the packets in the public key remain unchanged (except perhaps for the length of the public key). However, at the bottom of the public key is a new signature packet (shown in the screenshot above). This packet contains the ID of the signing key as well as a digital signature of the signee’s public key fingerprint. As a PGP key acquires more signatures, it continues to acquire signature packets, increasing in size as it does so.
Because PGP signatures are highly modular in this way, we can do a number of things with them. We can remove individual signatures from keys, export public keys with only specified signatures, and merge signatures from two copies of the same public key together.
With that out of the way, let’s move onto how to actually retrieve key signatures from keyservers!
The first prerequisite is that we need to store the public keys that were used to sign the key. When GPG imports a key, it automatically removes all keys which are untrusted, or which aren’t present in the GPG keyring (which would show up as “?”). In addition, these keys must be trusted with a level of at least 3 (“I trust marginally”).
Additionally, we need to pay special attention to the keyservers we retrieve public keys from. Not all keyservers support signed keys - some will remove signatures from keys when they are uploaded. The keyservers I know which store key signatures include:
--receive-keys command, which is used to retrieve keys from the keyservers, has two options which should be turned off to receive signatures:
self-sigs-onlyremoves all signatures which aren’t self-signatures. This is done to reduce the impact of spam signatures (there may be thousands of these on a key), but will also remove all legitimate keys.
import-cleanremoves all signatures which are expired, revoked, or which aren’t in your GPG keychain. Because PGP relies on a web of trust, you ought not to care about signatures which you don’t trust anyway, which is why these are removed on import. You may or may not want this one turned off depending on your use case.
These can be disabled using
Hence, either of the following commands should work:
gpg --keyserver-options no-self-sigs-only,no-import-clean,auto-key-retrieve --auto-key-import --keyserver keyserver.ubuntu.com --receive-keys <key_fingerprint>to retrieve a new key from the keyserver
gpg --keyserver-options no-self-sigs-only,no-import-clean,auto-key-retrieve --auto-key-import --keyserver keyserver.ubuntu.com --refresh-keysto update all keys in your keychain with signatures and revocations from the keyserver
The same options also apply to importing keys from files, so
gpg --import-options no-self-sigs-only,no-import-clean,auto-key-retrieve --auto-key-import --import <file> will also work.
When we run this command, we retrieve a public key from the keyservers, complete with all of the signatures on it!