mirror of
https://codeberg.org/openpgp/notes.git
synced 2024-11-24 00:22:05 +01:00
256 lines
19 KiB
Markdown
256 lines
19 KiB
Markdown
<!--
|
|
SPDX-FileCopyrightText: 2023 The "Notes on OpenPGP" project
|
|
SPDX-License-Identifier: CC-BY-SA-4.0
|
|
-->
|
|
|
|
(certifications_chapter)=
|
|
|
|
# Certification signatures
|
|
|
|
Signatures make up the magic of OpenPGP.
|
|
They act as the syntax that allows forming and interpreting complex statements about data and identities.
|
|
Without signatures there would only be loose keys, impossible to associate with their owner.
|
|
Signatures are the glue that allows for keys, subkeys and identities to be assembled into hierarchical certificates and for messages to gain authenticity.
|
|
|
|
```{admonition}
|
|
:class: warning
|
|
|
|
- Purpose of a signature
|
|
- Meaning of different signature types, nuances of subpackets
|
|
- Can we have a "catalogue" of statements a user might want to make, mapping these to archetypical signatures?
|
|
- Revocation; Hard vs. Soft
|
|
```
|
|
|
|
## Terminology
|
|
|
|
```{include} mermaid/06-terminology.md
|
|
```
|
|
|
|
The term *signature* can have multiple meanings in the context of the OpenPGP specification.
|
|
Cryptographic keys create raw signatures which are byte sequences calculated according to some signature scheme.
|
|
OpenPGP packs these raw signatures up into OpenPGP signature packets, which carry additional information in the form of signature subpackets.
|
|
For the purpose of this document, the term signature will refer to an OpenPGP signature packet (tag 2).
|
|
|
|
OpenPGP signatures can be separated into *data signatures* and *certifications*.
|
|
A data signature serves the purpose to cryptographically guarantee the authenticity (and implicitly also the integrity) of a message, e.g. an email or a file, while a certification is used to attach metadata or subkeys to a certificate.
|
|
Data signatures are always calculated by keys carrying the **S**igning key flag.
|
|
Different types of signatures are distinguished by a signature type code and are calculated in different ways.
|
|
Signatures can either be distributed standalone as *detached* signatures, or can be inlined with OpenPGP data, such as an OpenPGP message or a key or certificate.
|
|
|
|
Data signatures (type 0x00 and 0x01) are created by hashing the message content and calculating a cryptographic signature over the hash.
|
|
You can read more about data signatures in the [next chapter](signing_data).
|
|
The result is packed up into an OpenPGP signature packet, which can either be included in the OpenPGP message (TODO: See section about forming messages, cleartext signature framework), or distributed separately as a so called *detached* signature.
|
|
Data signatures are always calculated using a **S**igning key.
|
|
|
|
Certifications are separated into *self-certifications* and *third-party certifications*.
|
|
A certification made by a key over components of the same certificate is referred to as a *self-certification*.
|
|
:::{note}
|
|
The **C**certify Others key flag is not required in order to issue self-certifications.
|
|
It is only necessary to issue valid third-party certifications.
|
|
:::
|
|
A typical use-case for a self-certification is to attach a User ID, such as a name and email address to a certificate.
|
|
This is done by calculating the signature over the User ID and the public primary key.
|
|
The resulting User ID certification (typically type 0x13, potentially type 0x10-0x12) can then be inserted into the certificate, right after the User ID packet.
|
|
|
|
Other examples for self-signatures are binding signatures for subkeys.
|
|
In order to add an OpenPGP subkey to a certificate, a subkey binding signature is calculated over the public primary key, followed by the public subkey.
|
|
The resulting subkey binding signature (type 0x18) can then be inserted into the certificate right after the subkey.
|
|
If the subkey itself is intended to be used as a **S**igning key, an extra step is required.
|
|
To prevent an attacker from being able to "adopt" a victims signing subkey and then being able to claim to be the origin of signatures in fact made by victim, subkey binding signatures for signing subkeys need to include an embedded "back signature" (formally known as primary key binding signature) made by the signing key itself.
|
|
|
|
Certifications over User IDs can also be used to certify certificates of third-parties.
|
|
If Alice is certain that `Bob Baker <bob@example.com>` controls the key `0xB0B`, she can create a User ID certification signature for that identity and send it to Bob.
|
|
Bob can then add this signature to his certificate.
|
|
TODO: More WoT.
|
|
|
|
Another important category of signatures are revocations.
|
|
A revocation is used to retract the statement formed by a prior signature.
|
|
A subkey revocation signature revokes a prior subkey binding signature, while a certification revocation revokes a certification signature.
|
|
Typical use-cases for revocations are marking certificates or individual subkeys as unusable, or marking User IDs as no longer used.
|
|
|
|
A revocation signature can either be hard or soft. A soft revocation of a certificate invalidates it from the revocation signature's creation time onwards, meaning signatures that were issued before the revocation remain intact, while a hard revocation invalidates the certificate retroactively, rendering all issued signatures invalid, regardless of creation time. Soft revocations are typically used whenever a key or User ID is retired or superseded gracefully, while hard revocations can for example signal compromise of secret key material.
|
|
|
|
## Signature Types
|
|
There is a number of different Signature Types in the form of numerical IDs.
|
|
These give guidance on what the intent of a signature is and how it needs to be interpreted, however, the meaning of a signature also depends on who issued it.
|
|
A self-signature has a different meaning from a signature issued by a third party.
|
|
|
|
A `DirectKeySignature` issued as a self-signature can be used to set preferences and advertise features that apply to the whole certificate.
|
|
A third-party `DirectKeySignature` carrying a `TrustSignature` subpacket on the other hand can be interpreted as a statement by the issuer that it delegates trust to the signed certificate (WoT).
|
|
|
|
Self-certifications of types `0x10` - `0x13` can be used to bind a User ID to a certificate, while the same types issued by a third-party are statements by the issuer that they have checked the authenticity of the signed User ID to some degree.
|
|
|
|
There are further signature types for signatures on data, as well as designated types to bind and revoke subkeys.
|
|
|
|
## Signature Subpackets
|
|
|
|
A cryptographic signature alone is often not expressive enough to serve certain use-cases.
|
|
For this reason, the OpenPGP protocol introduced signature subpackets with rfc4880.
|
|
These are well-defined data structures that can be placed as subelements into signature packets, which give additional context and meaning to a signature.
|
|
Typical examples are the issuer fingerprint subpacket, which contains the fingerprint of the issuer key, or the key flags subpacket which states, what purpose a component key is intended for.
|
|
|
|
Signature subpackets can reside in two different areas of a signature packet.
|
|
Subpackets in the *hashed area* are incorporated in the digest calculation that is done during signature calculation and are therefore covered by the cryptographic signature.
|
|
In other words; hashed subpackets are *authenticated*.
|
|
If a subpacket is placed in the *unhashed area* instead, it is not included in the signature calculation procedure and is therefore not protected against tampering.
|
|
The unhashed area can be used to retroactively add, change or remove subpackets from a signature without invalidating it.
|
|
|
|
Due to the fact that the unhashed area doesn't provide any cryptographic guarantees, it is only intended for advisory packets, or packets that self-authenticate (e.g. the issuer fingerprint subpacket, whose "correctness" can be proven by successfully verifying the signature using the referenced issuer key).
|
|
In most cases, signature subpackets are simply added into the hashed area.
|
|
|
|
### Criticality
|
|
|
|
Each signature subpacket has a flag that indicates whether or not the subpacket is *critical*.
|
|
Since different OpenPGP implementations might support subsets of the standard, it would be fatal, if for example an implementation did not understand the concept of signature expiration.
|
|
Such an implementation would potentially accept an already expired signature.
|
|
By marking the expiration date subpacket as critical, the user can indicate, that implementations that do not understand this type of subpacket are supposed to reject the signature as invalid.
|
|
|
|
Sections 5.2.3.11 - 5.2.3.36 give guidance on which subpackets are usually marked as critical.
|
|
|
|
### Certification Recipes
|
|
|
|
As mentioned above, different signatures are used for different purposes.
|
|
In this section, we will try to give guidance on how to create certain signatures by example.
|
|
|
|
#### Change Algorithm Preferences
|
|
|
|
In order to change what symmetric, compression, hash or AEAD algorithms are preferred by the key owner, they can issue a direct-key signature (type 0x1F) on the primary key.
|
|
This signature should have the following structure:
|
|
|
|
| Subpacket | Area | Critical | Mandatory | Notes |
|
|
|-----------|------|----------|-----------|-------|
|
|
| Signature Creation Time | Hashed | True | True | Current time |
|
|
| Issuer Fingerprint | Hashed | True or false | Strongly recommended | The primary key is the issuer |
|
|
| Key Flags | Hashed | True | False | Carry over key flags from previous self-signature |
|
|
| Features | Hashed | True | False | Carry over features from previous self-signature |
|
|
| Key Expiration Time | Hashed | True | False | Carry over expiration time from previous self-signature, if present |
|
|
| Hash Alg. Pref. | Hashed | False | False | New preferences |
|
|
| Comp. Alg. Pref. | Hashed | False | False | New preferences |
|
|
| Symm. Alg. Pref. | Hashed | False | False | New preferences |
|
|
| AEAD Alg. Pref. | Hashed | False | False | New preferences |
|
|
|
|
#### Change Expiration Time
|
|
The recommended way to change the expiration time of a certificate is by issuing a new `DirectKey` signature (type 0x1F) with an adjusted Key Expiration Time subpacket.
|
|
The structure of such a signature is the same as in the section above.
|
|
It is also possible to change the expiration date of individual User IDs (see section below) or separate subkeys (see [section X](#add_subkey)).
|
|
|
|
#### Add User ID
|
|
To add (or re-bind) a User ID to a certificate, a signature of type `PositiveCertification` (0x13) is calculated over the primary key and User ID.
|
|
The signature should have the following structure:
|
|
|
|
| Subpacket | Area | Critical | Mandatory | Notes |
|
|
|-----------|------|----------|-----------|-------|
|
|
| Signature Creation Time | Hashed | True | True | Current time |
|
|
| Issuer Fingerprint | Hashed | True or false | Strongly Recommended | The primary key is the issuer |
|
|
| Primary User ID | Hashed | True | False | Optional |
|
|
| Signature Expiration Time | Hashed | True | False | Optional |
|
|
|
|
Self-certifications over User IDs can optionally carry the same subpackets as listed in the previous table (key flags, features, algorithm preferences).
|
|
This way, separate capabilities can be assigned to different identities.
|
|
|
|
#### Remove / Revoke User ID
|
|
Since OpenPGP certificates are often distributed by the means of key servers, new signatures on a certificate are often "merged" into existing copies of the certificate locally by the recipient.
|
|
This means, that it is not really possible to remove signatures / User IDs from a certificate, as there is no way to communicate the intention of packet deletion to the recipient.
|
|
|
|
So in order to mark a User ID as invalid, the user can publish a copy of their certificate with a `CertificationRevocation` (signature type 0x30) attached to the invalidated User ID.
|
|
This signature signals that the holder of the certificate no longer wants to be associated with that User ID.
|
|
|
|
The structure of a certification revocation is as follows:
|
|
|
|
| Subpacket | Area | Critical | Mandatory | Notes |
|
|
|-----------|------|----------|-----------|-------|
|
|
| Signature Creation Time | Hashed | True | True | Current time |
|
|
| Issuer Fingerprint | Hashed | True or false | Strongly Recommended | The primary key is the issuer |
|
|
| Reason for Revocation | Hashed | True | False | Decides over soft / hard revocation |
|
|
|
|
For User ID revocations, the value of the reason subpacket can either be `0` (no reason specified) or `32`, signaling that the User ID is no longer valid.
|
|
The latter would result in a soft revocation, while a reason code of `0` is considered a hard revocation.
|
|
Omitting the reason packet altogether is also equivalent to a hard revocation.
|
|
It is recommended to issue User ID certifications using a reason code `32` and to do certificate revocations using a direct-key signature.
|
|
|
|
#### Add a Subkey
|
|
For the purpose of key freshness, a user might want to add a new subkey to their certificate.
|
|
This can be accomplished by issuing a `SubkeyBinding` signature (type 0x18). The structure is as follows:
|
|
|
|
| Subpacket | Area | Critical | Mandatory | Notes |
|
|
|-----------|------|----------|-----------|-------|
|
|
| Signature Creation Time | Hashed | True | True | Current time |
|
|
| Issuer Fingerprint | Hashed | True or false | Strongly Recommended | The primary key is the issuer |
|
|
| Key Flags | Hashed | True | Strongly Recommended | Determine the usage of the key |
|
|
| Key Expiration Time | Hashed | True | False | Specifies the expiration date of the subkey |
|
|
| Embedded Signature | Hashed | True | If Key Flags contains **S** | Signing subkeys require embedded `PrimaryKeyBinding` signature |
|
|
| Hash Alg. Pref. | Hashed | False | False | Per key preferences |
|
|
| Comp. Alg. Pref. | Hashed | False | False | Per key preferences |
|
|
| Symm. Alg. Pref. | Hashed | False | False | Per key preferences |
|
|
| AEAD Alg. Pref. | Hashed | False | False | Per key preferences |
|
|
|
|
Optional algorithm preference subpackets can be used to signal per-subkey preferences that deviate from those set in the certificates `DirectKey` signature.
|
|
|
|
In order to specify an expiration time for the subkey, a key expiration time subpacket can be included. Note, that the validity of the subkey is bounded by that of the primary key, meaning an expired primary key causes the subkey to be invalidated, no matter the subkey expiration time.
|
|
|
|
If the subkey is intended to be used as a signing key (that is if the Key Flags subpacket contains the **S**ign Data flag), it is required to also include an embedded `PrimaryKeyBinding` "back signature" (type 0x19). This is to prevent an attack where the attacker "adopts" the victims signing subkey as their own in order to claim ownership over documents which were in fact signed by the victim.
|
|
Contrary to the `SubkeyBinding` signature, which is issued by the certificates primary key, the `PrimaryKeyBinding` signature is instead created by the subkey.
|
|
|
|
Note, that a subkey cannot be "older" than the primary key. The value of the subkeys creation date MUST be greater than that of the primary key.
|
|
|
|
#### Revoke a Subkey
|
|
Analogous to User IDs, subkeys can be revoked individually.
|
|
This is done by issuing a `SubkeyRevocation` signature (type 0x28) using the primary key.
|
|
The structure of such a signature is rather minimal:
|
|
|
|
| Subpacket | Area | Critical | Mandatory | Notes |
|
|
|-----------|------|----------|-----------|-------|
|
|
| Signature Creation Time | Hashed | True | True | Current time |
|
|
| Issuer Fingerprint | Hashed | True or false | Strongly Recommended | The primary key is the issuer |
|
|
| Reason for Revocation | Hashed | True | False | Decides over soft / hard revocation |
|
|
|
|
In `SubkeyRevocation` signatures, the reason subpacket cannot have value `32`, but instead may be from the range of `0-3`.
|
|
Values `1` (key superseded) and `3` (key retired and no longer used) are soft reasons, while `0` (no reason) and `2` (key compromised) are considered hard.
|
|
|
|
#### Revoke a Certificate
|
|
A user might want to revoke their whole certificate, rendering it unusable.
|
|
Depending on the circumstances, they might either want to revoke it softly, e.g. in case of migration to a new certificate, or they want to issue a hard revocation, e.g. in case of secret key material compromise. A soft-revoked certificate can be re-validated at a later point in time, by issuing a new certification, while a hard revocation is typically permanent.
|
|
|
|
The recommended way to revoke a certificate is by issuing a `KeyRevocation` signature (type 0x20).
|
|
The structure of a key revocation signature is similar to that of a `CertificationRevocation` signature.
|
|
|
|
| Subpacket | Area | Critical | Mandatory | Notes |
|
|
|-----------|------|----------|-----------|-------|
|
|
| Signature Creation Time | Hashed | True | True | Current time |
|
|
| Issuer Fingerprint | Hashed | True or false | Strongly Recommended | The primary key is the issuer |
|
|
| Reason for Revocation | Hashed | True | False | Decides over soft / hard revocation |
|
|
|
|
For `KeyRevocation` signatures, the same constraints as for `SubkeyRevocation` signatures apply to the reason subpacket.
|
|
|
|
#### Common Subpackets
|
|
|
|
There are some subpackets that are expected to be included in any type of signature.
|
|
|
|
* **Signature Creation Time**: Every OpenPGP signature MUST contain a Signature Creation Time subpacket (2) containing the timestamp at which the signature was made. This packet MUST be present in the hashed area of the signature and SHOULD be marked as critical.
|
|
|
|
* **Issuer Fingerprint**: In order to be able to verify a signature, the verifier needs to know, which (sub-)key was used to issue the signature in the first place. Therefore, every OpenPGP v6 signature SHOULD contain an Issuer Fingerprint subpacket (33) containing the 32 byte fingerprint of the particular component key that was used to create the signature.
|
|
:::{note}
|
|
The issuer key might be a subkey.
|
|
:::
|
|
Since the issuer fingerprint subpacket is self-authenticating, it can either be included as a hashed or unhashed subpacket, but the authors of this book recommend to place it in the hashed area of the signature.
|
|
|
|
### Potential conflicts and duplication
|
|
|
|
Since the hashed and unhashed areas of a signature are just lists of subpackets, in principle they allow duplicates of the same subpacket, which might lead to conflicts.
|
|
Therefore, packets in the hashed area take precendence over the unhashed area.
|
|
However, there may still be conflicts between packets in the same area, e.g. two conflicting expiration dates, etc.
|
|
The specification recommends that implementations favor the last occurence of a conflicting packet in the hashed area.
|
|
|
|
In some cases, duplicate packets with conflicting content even make sense, e.g. if a signature was made by a version 4 issuer key whose key material was migrated from an older OpenPGP version such as v3.
|
|
In this case, either the v3 or v4 key could be used to validate the v4 signature, but since the key ID calculation scheme was changed between v3 and v4, these identifiers would differ.
|
|
Therefore, the signature could contain two isuer key ID subpackets with conflicting, but correct values.
|
|
|
|
```{admonition}
|
|
:class: warning
|
|
|
|
- Key Flags
|
|
- Preferences
|
|
- Embedded Signature (back sig)
|
|
- Trust Signatures (amount, depth)
|
|
- Direct key signatures
|
|
```
|