diff --git a/book/source/06-signatures.md b/book/source/06-signatures.md index 946d513..bf7efb7 100644 --- a/book/source/06-signatures.md +++ b/book/source/06-signatures.md @@ -5,56 +5,55 @@ SPDX-License-Identifier: CC-BY-SA-4.0 # 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. +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, 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. +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 -The term *signature* can have two different meanings in the context of OpenPGP: +Within OpenPGP, the term *signature* can have two different meanings: -- 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. +- **Cryptographic signature**: a sequence of bytes created by cryptographic keys, calculated according to a signature scheme. +- **OpenPGP signature packets**: Defined in the [OpenPGP standard](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-signature-packet-type-id-2), these packets combine a raw cryptographic signature along with a *type* designation and additional metadata. ```{figure} diag/meaning_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. +In this document, "signature" will refer to OpenPGP signature packets. (signature_types)= -## Types of signatures in OpenPGP +## Signature types 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. +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 purpose of a signature and how it should be interpreted. -Most OpenPGP signature types can be classified as either: +Signature types can be predominantly classified in two ways: -- *Signatures over data* (type IDs `0x00` and `0x01`), or -- *Signatures on components* (that is: signatures that apply to component keys or identity components). +- **Signatures over data**: These signatures are denoted by type IDs `0x00` for binary documents and `0x01` 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. -Signature on components are a complex topic, which we discuss in depth in {ref}`component_signatures_chapter`. They are grouped in two dimensions: +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: -- 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)? +- 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 ```{figure} mermaid/sig-types.png An overview of signature types in OpenPGP ``` -In this chapter we discuss general principles, which apply to all types of OpenPGP signatures. +This chapter will cover the overarching principles applicable to all OpenPGP signature types. -For more detail about specific types of signatures, see the chapters {ref}`signing_data` and {ref}`component_signatures_chapter`, respectively. +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: -- 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. +- **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** ```{figure} diag/signature_packet.png @@ -63,36 +62,37 @@ Structure of an OpenPGP signature packet ### Creating an OpenPGP signature packet -When someone creates a signature packet, their goal is to make some type of statement about a set of input data, and encode this statement in the signature packet. +Creating an OpenPGP signature packet involves encoding a statement about a specific set of data within the packet. -The input data consists of: +The input data of a signature packet includes: -- a number of packets (usually one or more packets, but in some cases none), which the signature statement is about, and -- some of the data in the signature packet itself. This data specifies the intent of the signature. +- **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 signature type determines which data is used as the input data. Either way, the input data always consists of the information that the signature makes a statement about. +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: -- The data that defines the meaning of the statement, and -- A cryptographic digital signature with which the signer formally endorses that statement. - -So the signature packet hinges on that cryptographic signature. It is produced by the issuer as follows: - -1. A hash digest is calculated from the set of input data. -2. The signature is calculated for this hash digest. +1. **Statement definition**: This part of the packet defines the meaning or intent of the signature. +2. **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. ```{figure} diag/Signature_Creation.png Creating a signature in OpenPGP ``` +(sig-verify)= ### Verifying an OpenPGP signature packet -Verification of a signature packet involves many of the same steps. There are two main differences: +Verifying an OpenPGP signature packet is similar to its creation, with some crucial differences that facilitate the verification by entities other than the signer. -- While only the signer of the signature packet can create the cryptographic signature that it contains, everyone can verify the signature, provided they have access to the public key of the signer. -- After calculating the hash digest, a signature verification mechanism is used, based on the hash digest, the cryptographic signature, and the signer public key, to check if the signature is cryptographically valid. +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. ```{figure} diag/Signature_Verification.png @@ -102,45 +102,45 @@ 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](https://datatracker.ietf.org/doc/html/rfc2440)). +In the OpenPGP protocol, signature subpackets enhance the expressiveness of a signature beyond what is conveyed by just the bare cryptographic signature and the signature type ID. These subpackets, introduced in [RFC 2440](https://datatracker.ietf.org/doc/html/rfc2440), are essential for embedding additional metadata within signature packets. -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](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-signature-subpacket-types-r) and provides the value format (and meaning) for all of them. +Signature subpackets serve as sub-elements within signature packets, providing extra context and meaning to a signature. +They are formatted as key-value pairs, where the keys are defined as [subpacket type IDs](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-signature-subpacket-types-r) by the RFC. The RFC also provides the format and interpretation of the values. -Typical examples are: -- The [*issuer fingerprint*](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#issuer-fingerprint-subpacket) subpacket, which encodes the fingerprint of the component key that issued the signature, or -- The [*key flags*](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-key-flags) subpacket, that defines which capabilities are assigned to a component key, in a certificate. +### Examples of signature subpackets +- The [*issuer fingerprint*](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#issuer-fingerprint-subpacket) subpacket encodes the fingerprint of the component key that issued the signature. +- The [*key flags*](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-key-flags) subpacket defines the capabilities that are assigned to a component key within a certificate. ### Hashed and unhashed signature subpackets -Signature subpackets can reside in [two different areas](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-hashed-vs-unhashed-subpacke) of a signature packet: +Signature subpackets within OpenPGP can reside in one of two distinct areas of a signature packet, each serving a different purpose. -- 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. +- **Hashed area**: Hashed subpackets are included in the hash digest of the signature and are thus covered by its cryptographic signature. They reliably express the signer's intent. +- **Unhashed area**: Unhashed subpackets, conversely, are not included in the hash digest for the signature. They are thus not protected against tampering and can be used to retroactively add, change, or remove metadata in a signature packet without affecting its validity. They are primarily used for advisory purposes or in scenarios where the integrity of the subpacket content can be self-authenticated. An example is the issuer fingerprint subpacket, which can be validated through successful signature verification using the referenced issuer key. + +The majority of signature subpackets are stored in the hashed area. + +For detailed information and specifications, refer to [Hashed vs. Unhashed Subpackets](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-hashed-vs-unhashed-subpacke) in the OpenPGP RFC. ### 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. +In the OpenPGP protocol, each signature subpacket can be marked with a *criticality flag*. This flag plays a pivotal role in the interpretation and validation of the signature. When set, it instructs any receiving implementation encountering an unrecognized subpacket type to treat this as a significant error and to invalidate the signature. -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. +This mechanism accounts for different OpenPGP implementations that may support only certain subsets of the standard. Moreover, it anticipates the evolution of the standard, including 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. +Consider a scenario where an implementation does not recognize a subpacket indicating signature expiration. Without understanding this concept, the implementation might erroneously accept an already expired signature. By marking the expiration date subpacket as critical, the creator of the signature ensures that any recipient who cannot process this subpacket will 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 should be marked as critical. +For specific guidelines on which subpackets should be marked as critical, refer to the RFC sections [5.2.3.11](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-signature-creation-time) to [5.2.3.36](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-intended-recipient-fingerpr). ## 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 signature subpackets](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#notation-data) can be used to effectively extend the otherwise limited set of signature subpacket types in OpenPGP with user-defined notations. Issuers can use these notations to add name-value pairs 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. +Notation names – strings encoded in UTF-8 – may reside in the "user namespace." This namespace is characterized by a notation *tag*, followed by a DNS domain name, both in UTF-8 format. -#### 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. +Notations, as described earlier, allow for user-defined extensions to the OpenPGP signature subpacket types. A practical and popular application of this functionality is seen in Keyoxide, a decentralized identity verification service. Keyoxide uses notations in the `ariadne.id` namespace. For the details of this implementation, refer to the [Keyoxide documentation](https://docs.keyoxide.org/wiki/ariadne-identity/). ### "Negotiating" signature hash algorithm based on recipients preference subpackets