10 KiB
OpenPGP Signatures
Signatures are a fundamental mechanism within OpenPGP. They provide the syntax for forming and interpreting comprehensive statements about certificates and their components, as well as for ensuring the integrity and authenticity of data.
Without signatures, keys would remain unassociated with any certificate or owner. Signatures are crucial for binding component keys and identity components into hierarchical certificates and for establishing the authenticity of messages.
Terminology
Within OpenPGP, the term signature can have two different meanings:
- Cryptographic signature: a sequence of bytes created by cryptographic keys, calculated according to a signature scheme.
- OpenPGP signature packets: Defined in the OpenPGP standard, these packets combine a raw cryptographic signature along with a type designation and additional metadata.
Two meanings of the term "signature" in OpenPGP
In this document, "signature" will refer to OpenPGP signature packets.
(signature_types)=
Signature types in OpenPGP
The OpenPGP standard defines a set of Signature types, each identified by a numerical signature type ID. Signature types define the purpose of a signature and how it should be interpreted.
Signature types can be predominantly classified in two ways:
- Signatures over data: These signatures are denoted by type IDs
0x00
for binary documents and0x01
for canonical text documents. The signer uses these signatures to claim ownership, assert creation, or certify the immutability of the document. - Signatures on components: These are signatures that are associated with component keys or identity components of a certificate.
Signatures on components are a complex topic, and we discuss them in depth in {ref}component_signatures_chapter
. They are grouped based on two criteria:
- the origin of the signature, distinguishing between a self-signature and a third-party signature
- the nature of the statement made by the signature, such as certifying an identity or binding component keys into a certificate
An overview of signature types in OpenPGP
This chapter will cover the overarching principles applicable to all OpenPGP signature types.
For more detail about specific types of signatures, see the chapters on {ref}signing_data
and {ref}component_signatures_chapter
, respectively.
Structure of an OpenPGP signature packet
As outlined above, an OpenPGP signature is a composite data structure, which combines:
- Signature type ID: specifies the signature's intended meaning, as detailed above
- Metadata: varies based, in part, on the signature type ID; mostly encoded as "subpackets" (see {ref}
signature_subpackets
) - Raw cryptographic signature
Structure of an OpenPGP signature packet
Creating an OpenPGP signature packet
Creating an OpenPGP signature packet involves encoding a statement about a specific set of data within the packet.
The input data of a signature packet includes:
- Packets being signed: Typically one or more packets, though sometimes none, depending on the context. These are the packets to which the signature statement pertains.
- Data within the signature packet: This includes information that specifies the intent of the signature.
The input data is determined by the signature type and consists of the exact content that the signature statement addresses.
The signature packet consists of two parts:
- Statement definition: This part of the packet defines the meaning or intent of the signature.
- Cryptographic digital signature: This is the formal endorsement by the signer, created as follows:
- A hash digest is calculated from the input data.
- The signature is then calculated for this hash digest.
Creating a signature in OpenPGP
Verifying an OpenPGP signature packet
Verifying an OpenPGP signature packet is similar to its creation, with some crucial differences that facilitate the verification by entities other than the signer.
The main differences:
- Access to public key: Unlike the creation process, which is exclusive to the signer, verification can be performed by anyone who has access to the public key of the signer.
- Use of signature verification mechanism: After calculating the hash digest from the input data, a signature verification mechanism is employed. This mechanism uses the hash digest, the cryptographic signature from the signature packet, and the public key of the signer. Its purpose is to ascertain the cryptographic validity of the signature.
Verifying a signature in OpenPGP
(signature_subpackets)=
Signature subpackets
A bare cryptographic signature - even when combined with a signature type ID - is usually not sufficiently expressive. So, to encode additional metadata in signature packets, the OpenPGP protocol introduced signature subpackets (in RFC 2440).
Subpackets are well-defined data structures that can be placed into signature packets as sub-elements. They provide additional context and meaning for a signature. Subpackets encode data in a key-value format. The RFC defines all possible keys as subpacket type IDs and provides the value format (and meaning) for all of them.
Typical examples are:
- The issuer fingerprint subpacket, which encodes the fingerprint of the component key that issued the signature, or
- The key flags subpacket, that defines which capabilities are assigned to a component key, in a certificate.
Hashed and unhashed signature subpackets
Signature subpackets can reside in two different areas of a signature packet:
- Subpackets in the hashed area are included in the hash digest for that signature. In other words: hashed subpackets are covered by the cryptographic signature in the signature packet. Recipients of the signature can be sure that these subpackets express the intent of the issuer of the signature.
- Subpackets in the unhashed area, by contrast, are not included in the hash digest for that signature. They are therefore not protected against tampering. The unhashed area can be used to retroactively add, change or remove metadata in a signature packet, without invalidating it. Since 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 stored in the hashed area.
Criticality of subpackets
Each signature subpacket has a flag that indicates whether the subpacket is critical. When set, the criticality flag signals that a receiving implementation that does not know a subpacket type, must consider this an error, and may not consider the signature valid.
The reason for this mechanism is that OpenPGP implementations may only support subsets of the standard - and the standard may be extended over time, including by the addition of new subpacket types.
However, 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 creating implementation can indicate that recipients who do not understand this of subpacket must consider the signature as invalid.
RFC Sections 5.2.3.11 - 5.2.3.36 give guidance on which subpackets should be marked as critical.
Advanced topics
Notation signature subpackets
Notations are a signature subpacket type that can be used to effectively extend the otherwise limited set of signature subpacket types with user-defined notations. An issuer can use notations to add name-value data to an OpenPGP signature.
Notation names are UTF-8 encoded strings. They may reside in the "user namespace," which means a notation tag (in UTF-8 string format) followed by a DNS domain name.
Use of notations by Keyoxide
Notations have, for example, been used for the popular decentralized identity verification service Keyoxide. Keyoxide uses notations in the ariadne.id
namespace. See the Keyoxide documentation for more details.
"Negotiating" signature hash algorithm based on recipients preference subpackets
:class: warning
investigate, discuss: GnuPG uses preference packets for the User ID that was addressed while sequoia completely omits User ID preferences and either uses Direct Key Sigs or (I think) primary User ID.
Explore viability of having multiple signatures, e.g. v4+v6?
:class: warning
C-R 5.2. says: An implementation MUST generate a version 6 signature when signing with a version 6 key. An implementation MUST generate a version 4 signature when signing with a version 4 key.