# OpenPGP Signatures Signatures are perhaps the single most central mechanism in OpenPGP. They act as the syntax that allows forming and interpreting rich statements about certificates and their components, as well as data. Without signatures, there would only be loose keys, impossible to associate with a certificate, or their owner. Signatures are the glue that allows for components (component keys and identity components) to be assembled into hierarchical certificates, and for messages to gain authenticity. ## Terminology The term *signature* can have multiple meanings in the context of OpenPGP: - Cryptographic keys create raw signatures which are byte sequences calculated according to some signature scheme. - [*OpenPGP signature packets*](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-signature-packet-type-id-2), which combine a *type* setting, additional metadata, and a raw cryptographic signature. ```{figure} diag/types_of_signatures.png Two meanings of the term "signature" in OpenPGP ``` For the purpose of this document, the term signature will refer to OpenPGP signature packets. (signature_types)= ## Types of signatures in OpenPGP The OpenPGP standard defines a set of [Signature Types](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-signature-types), each identified by a numerical *signature type ID*. Signature types define the intent of a signature, and how it needs to be interpreted. Most OpenPGP signature types can be classified as either: - *Signatures over data* (type IDs `0x00` and `0x01`), or - *Signatures on components* (that is: signatures that apply to component keys or identity components). Signature on components are a complex topic, which we discuss in depth in {ref}`component_signatures_chapter`. They are grouped in two dimensions: - Who issued the signature (self-signature vs. third party signature)? - What kind of statement does the signature make (certify an identity, or bind component keys into a certificate)? ```{figure} mermaid/06-terminology.png An overview of signature types in OpenPGP ``` ```{admonition} TODO :class: warning Group "Third-Party Certification" and "Self-Signature" as "Signature on components", in the diagram? ``` In this chapter, we discuss the general principles of OpenPGP signatures, which apply to all types of OpenPGP signatures. For more detail about specific types of signatures, see the chapters {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: - A *signature type ID* (see above), which specifies the intended meaning of the signature, - Metadata (which is variable and depends in part on the type ID), - Most of this metadata is encoded as so-called "subpackets," see {ref}`signature_subpackets`, - A raw cryptographic signature. ```{figure} diag/signature_packet.png Structure of an OpenPGP signature packet ``` ### Generation and validation of cryptographic signatures in OpenPGP The central element of an OpenPGP signature packet is the raw cryptographic signature it contains. This cryptographic signature is calculated by the issuer of that signature packet. In abstract terms, the cryptographic signature certifies a set of input data ("signature over"): The signer is making a statement about that set of input data. That statement is encoded as the signature packet. If we look more closely, the cryptographic signature is actually calculated in two steps: 1. A hash digest is calculated from the set of input data. 2. The signature is calculated for this hash digest. The exact input data depends on the signature type. However, the input data always comprises the information that the signature makes a statement about. It includes the metadata in the OpenPGP signature packet itself. (signature_subpackets)= ## Signature subpackets Just a cryptographic signature, combined with a signature type identifier, is often not sufficiently expressive. For this reason, the OpenPGP protocol introduced signature subpackets (in [RFC 2440](https://datatracker.ietf.org/doc/html/rfc2440)). Subpackets are well-defined data structures that can be placed into signature packets as subelements. They give additional context and meaning to a signature. Subpackets encode data in a key-value format. All possible keys are defined in the RFC as [subpacket type IDs](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-signature-subpacket-types-r), and the value format (and meaning) are defined in the RFC for each subpacket type ID. Typical examples are: - the [*issuer fingerprint*](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#issuer-fingerprint-subpacket) subpacket, which contains the fingerprint of the issuer key, or - the [*key flags*](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-key-flags) subpacket which defines what purpose a component key is used for, in a certificate. 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. 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*. 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. RFC Sections [5.2.3.11](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-signature-creation-time) - [5.2.3.36](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-intended-recipient-fingerpr) give guidance on which subpackets are usually marked as critical. ## Advanced topics ### Notation signature subpackets [Notations](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#notation-data) 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](https://keyoxide.org/). Keyoxide uses notations in the `ariadne.id` namespace. See the [Keyoxide documentation](https://docs.keyoxide.org/wiki/ariadne-identity/) for more details. ### "Negotiating" signature hash algorithm based on recipients preference subpackets ```{admonition} TODO :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? ```{admonition} TODO :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. ```