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, lots of 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 prolonged.

A key is needed for operations 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 with the exception of 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 herself 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 which are bound to another key (called primary key) by a subkey binding signature.

Subkeys were added to OpenPGP to solve a couple of shortcomings:

  • Subkeys introduce new key material to a key, to prevent the usage 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 to rotate or revoke subkeys without sacrificing existing certifications as the primary key doesn't change. The subkey binding signature is used to extend the certification of the primary key to it's subkeys.
  • Subkeys have flags which indicate their usage (signing, encryption, etc.). OpenPGP allows to have 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 offlined, as it's 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, 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 3 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 is a little CA with the primary key acting as a certificate authority, certifying the subkeys.

You can have a peek into a key by:

$ 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, so that sq packet dump can display its 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.