Keys, subkeys, and certificates
A key in the context of OpenPGP is actually a dataset containing User IDs, key material (both public and secret), metadata like the expiration date, preferences, certifications, signatures, and subkeys – to name a few. This dataset is not fixed; parts of it will (likely) be modified over time as new certifications might be added, User IDs might change, and the expiration might be extended.
A key is needed for operations that only the keyholder should be able to do, like decrypting or signing.
A certificate is the public representation of a key. It contains the same objects as the key except for the secret key material. It is used for operations everyone should be able to do, like encryption or signature verification.
The objects within a key (and a certificate) can be signed using the secret key material of that key. This signifies that the keyholder either added the object themselves, or is content with it (like third-party certifications). Keys, and specifically certificates, can also hold unsigned objects like additional User IDs or unapproved certifications.
Keys (and certificates) can and usually have subkeys. These are keys that are bound to another key (called the primary key) by a subkey binding signature.
Subkeys were added to OpenPGP to solve a few shortcomings:
- Subkeys introduce new key material to a key to prevent the use of the same key material for potentially conflicting operations. Both decrypting and signing are technically an encryption using the private key material. Signing an encrypted message might therefore inadvertently decrypt the message. OpenPGP prevents this as signatures are never created using the original data, but a checksum of it. Still, this is uncomfortably close and open to implementation mistakes. Using different keypairs for encryption/decryption and signing/verifying eliminates this problem.
- Subkeys are grouped under a primary key, which represents the bundle. Hence, designating this bundle is done via the fingerprint of the primary key. This allows rotation or revocation of subkeys without affecting existing certifications, as the primary key doesn't change. The subkey binding signature is used to extend the certification of the primary key to its subkeys.
- Subkeys have flags which indicate their usage (signing, encryption, etc.). OpenPGP allows having more than one subkey with the same flags. Having two subkeys flagged for encryption in a certificate will encrypt a message for both subkeys.
- By careful arrangement, the primary key of this bundle can be kept offline, as its secret key material is then only needed for updating metadata (User IDs, expiration) and subkey bindings. Day-to-day usage can then be completely delegated to subkeys.
Subkeys do not have User IDs, as these are associated with the primary key, but they can have an expiration date.
There is no limit to the number of subkeys a key can have. When generating a new key, sq
creates three subkeys with it. One for encryption, one for signing, and one for authentication. The primary key is used to certify the authenticity of the subkeys. As subkeys have markings (flags) for their use case, an application (like sq
) can choose the right subkey for each operation. In some ways, a key acts like a little CA, with the primary key acting as a certificate authority, certifying the subkeys.
You can peek into the internals of a key using:
$ sq key generate --own-key --userid alice --output - --rev-cert /dev/null --overwrite | sq packet dump
This example generates a key with a User ID of "alice", it specifies --output
, so that the generated key is not added to the key store. Using --output -
redirects the new key to STDOUT
, and piping the output into sq packet dump
displays its expanded contents. --rev-cert
and --overwrite
are needed as a side effect of --output
- in this example the result is discarded. --own-key
authorizes the new key to introduce certificates - you can try --shared-key
instead to see an unauthorized key.