From 02146bbe96373e717f2ebfaf9dd107aaa0b0196f Mon Sep 17 00:00:00 2001 From: Paul Schaub Date: Sat, 25 Nov 2023 00:17:32 +0100 Subject: [PATCH] Incorporate super helpful feedback from @dvzrv --- book/source/09-verification.md | 93 ++++++++++++++++++++++------------ 1 file changed, 61 insertions(+), 32 deletions(-) diff --git a/book/source/09-verification.md b/book/source/09-verification.md index 8f638e3..44e5826 100644 --- a/book/source/09-verification.md +++ b/book/source/09-verification.md @@ -7,7 +7,8 @@ SPDX-License-Identifier: CC-BY-SA-4.0 # Signature verification Signature verification in the OpenPGP protocol is a complex process. -There are lots of different factors that can influence the validity of a signature, most importantly its expiration date. +There are lots of different factors that can influence the validity of a signature. +Most importantly its expiration date: A signature can be valid at one point in time and invalid merely a second later. Signatures can be invalid due to the absence or presence of other signatures (e.g. revocations). Some signatures can be verified standalone, while others require the verification of a chain-like structure of other signatures, mostly within the issuer's certificate. @@ -49,9 +50,9 @@ Unknown subpackets which are not marked as critical do not have an effect on whe A signature is valid only for a constrained period of time: -- The creation time of the signature acts as a lower bound for the validity. A signature only becomes valid after its creation time. Hard revocation signatures are an exception: they are by definition valid since the dawn of time, and have no lower temporal bound. +- The creation time of the signature acts as a lower bound for the validity. A signature only becomes valid after its creation time. Hard revocation signatures are an exception: They are by definition valid at any point in time, and have no lower temporal bound. -- If present, the signature's expiration time defines an upper bound for its validity. +- If present, the signature's expiration time acts as a natural upper bound for its validity. When checking a signature for validity, a reference time is used. This can be the current time during validation, or a point in time that relates to the signature that is getting checked. @@ -64,19 +65,19 @@ The same reference time must be used when verifying additional qualifying signat Some signatures can be verified on their own, while others require the verification of additional signatures on the issuer certificate. We will call the former category *self-qualifying* signatures. Typically, self-qualifying signatures are self-signatures, meaning signatures issued by an OpenPGP key over its own components. -Examples for self-qualifying signatures are direct key self-signatures (0x1F), User ID self-certifications (0x10-0x13), key-revocation self-signatures (0x20), certification revocation self-signatures (0x30) or signatures used to bind or revoke subkeys (0x18, 0x19, 0x28). +Examples for self-qualifying signatures are direct key self-signatures (`0x1F`), User ID self-certifications (`0x10`-`0x13`), key-revocation self-signatures (`0x20`), certification revocation self-signatures (`0x30`) or signatures used to bind or revoke subkeys (`0x18`, `0x19`, `0x28`). -Examples for signatures which are not self-qualifying are data signatures (0x00, 0x01) and signatures issued over third-party certificates, such as third-party direct key signatures (0x1F) or key-revocations (0x20), third-party certification or revocation signatures (0x10-0x13, 0x30). +Examples for signatures which are not self-qualifying are data signatures (`0x00`, `0x01`) and signatures issued over third-party certificates, such as third-party direct key signatures (`0x1F`) or key-revocations (`0x20`), third-party certification or revocation signatures (`0x10`-`0x13`, `0x30`). ### Signature qualification -To verify non-self-qualifying signatures, it is not sufficient to only look at the signature itself. -The reason is, that the issuer (sub-) key needs to be qualified to create such a signature (e.g. because a special key-flag is required). -This qualification typically comes via another self-signature on the key itself. +To verify non-self-qualifying signatures, it is required to look at more than just the signature itself. +The reason is, that the issuer (sub-) key needs to be qualified to create such a signature (e.g. because a specific key-flag is required). +This qualification typically emerges via a self-signature on the key itself. -Instead, a chain of valid signatures from the signature itself to the primary key of the issuer certificate needs to be established. +In short, a chain of valid signatures from the signature itself to the primary key of the issuer certificate needs to be established. -For example, a data signature over an email body may be issued by a subkey only if that subkey is validly bound to the certificate via a subkey binding signature. That binding signature needs to contain a *key flags* subpacket that marks the subkey as *signing* capable. +For example, a data signature over an email body may be issued by a subkey only if that subkey is validly bound to the issuer's certificate via a subkey binding signature. That binding signature needs to contain a *key flags* subpacket that marks the subkey as *signing* capable. Similarly, certification signatures over third-party certificates require the issuer key to carry a self-signature with the *certification* key flag. Self-qualifying signatures have no such limitations. @@ -86,25 +87,33 @@ This construct is referred to as a [revocation certificate](https://www.ietf.org On the other hand, in order to verify a data signature over a text document, an implementation would need to verify not only the data signature itself, but also the binding signature (and back-signature) of the signing subkey, which qualify the signing subkey. ```{figure} mermaid/09-sigtree.png +:name: fig-signature-verification-signature-tree +:alt: Depicts a diagrammatic representation of a certificate and a data signature. Arrows between the primary key and other components of the certificate show, how signatures bind the certificate together. In this example, they form a tree of signatures, which all need to be verified in order for the data signature to be valid. Tree of signatures ``` ### Attribute shadowing -When determining preferences of a key, different signatures can be inspected. +When determining preferences of a key, several signatures may have to be inspected. For example, when using a signing subkey to generate a data signature, the implementation might want to check for hash algorithm preferences on the subkey binding signature. -At the same time, the specification states, that signature subpackets on the direct key signature of the OpenPGP keys primary key apply to the whole key (therefore also to the signing subkey). +However, the RFC [states](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#section-5.2.3.10-2), that signature subpackets on the direct key signature of the OpenPGP certificate's primary key (which also may contain preferences) apply to the entire OpenPGP key (therefore also to the signing subkey). In this case, the implementation uses the preferences from the subkey binding signature, but if no such subpacket is found on the latest binding signature, it falls back to the preferences of the direct key signature. This is called attribute shadowing, since direct key signature subpackets apply to all subkeys, but are shadowed by binding signature subpackets. ```{figure} drawio/attribute-shadowing.png +:name: fig-signature-verification-attribute-shadowing +:alt: Depicts a certificate with to dedicated signing subkeys and a subkey binding signature each. The primary key carries a direct-key signature, which specifies SHA-512 and SHA-256 as hash algorithm preferences. The binding signature of the first signing subkey does not specify preferences, while the binding signature of the second subkey defines SHA-384. Signatures made using the first subkey source the hash algorithm preferences from the direct-key signature, due to the absence of a preference subpacket on the binding signature, while for signature made using the second subkey the direct-key signature's preferences are shadowed by the subkey signatures preferences subpacket. -Attributes from the primary key's direct key signature apply to the whole certificate, but can be shadowed by binding signatures. +Inheritance and Shadowing of Attributes ``` -Note: Attribute shadowing should only be used for algorithm preferences, since there are subpacket types where shadowing makes no sense (e.g. key expiration time subpackets). +```{admonition} Note +:class: note + +Attribute shadowing should only be used for algorithm preferences, since there are subpacket types where shadowing makes no sense (e.g. key expiration time subpackets). +``` ### Signature shadowing @@ -112,17 +121,25 @@ When inspecting signatures on a component of an OpenPGP certificate, of the sign In other words; If there are three binding signatures `A, B, C` for a subkey, where `A` was created at `t0`, `B` at `t1` and `C` at `t3` with `t0 < t1 < t2 < t3`, at `t2` an implementation only needs to consider `B`, as `C` is not yet in effect. `A` is shadowed, because it is older than `B`. ```{figure} drawio/cert-validity-subkey.png +:name: fig-signature-verification-subkey-validity +:alt: Depicts a gantt-style diagram visualizing how the validity of a certificates components changes over time, depending on component signatures. An example for how certificate validity can change with time. ``` -Note: Signature shadowing is not to be mistaken with attribute shadowing. +```{admonition} +:class: note -Attribute- and signature shadowing also combine, so it is not always obvious, what properties a key has at any given time. +Signature shadowing is not to be mistaken with attribute shadowing. +``` + +As attribute and signature shadowing can occur in combination, it is not always obvious, which properties a key has at a given time. ```{figure} drawio/dk-attributes-and-shadowing.png +:name: fig-signature-verification-signature-shadowing +:alt: Depicts a certificate with a subkey, whose capabilities change over time, due to signature shadowing another. -Signatures shadow another, based on reference time. +Signatures shadow one another, based on reference time. ``` ### Revocations @@ -131,14 +148,18 @@ A signature might be *disqualified* by the presence of a revocation signature. Revocations can be limited in scope, e.g. a subkey-revocation signature only revokes a single subkey. Moreover, revocations can also be constrained to a certain validity period by including a soft revocation reason and expiration time in the revocation signature. -TODO: Give guidance, which revocations need to be considered for different types of signatures +```{admonition} +:class: todo + +Give guidance, which revocations need to be considered for different types of signatures +``` ## Which signatures take precedence? An OpenPGP certificate or component can have multiple signatures with conflicting information attached to it. -When verifying a non-self-qualifying signature, an implementation needs to identify self-qualifying signatures on the certificate to qualify that signature. -There might be more than one candidate for such a signature. +When verifying a non-self-qualifying signature, an implementation needs to consider self-qualifying signatures on the issuer's certificate for qualification. +There might be several signatures per component. For example, there might be multiple subkey binding signatures for the same subkey. In general, for each category of signatures, only that with the latest signature creation time is considered and takes precedence. @@ -146,8 +167,10 @@ In general, for each category of signatures, only that with the latest signature Alternatively, there might be competing qualifying signatures of different types, e.g. a direct key signature and a self-certification signature on a primary User ID. In this case, depending on how a key is "addressed", different attributes from both candidates "shadow" another. -``` -TODO: Replace hash algorithm preferences with AEAD preferences for a more realistic example. +```{admonition} +:class: todo + +Replace hash algorithm preferences with AEAD preferences for a more realistic example. ``` For example, the latest direct key signature could list "SHA512, SHA384" as hash algorithm preferences, while the latest self-certification of User ID "Bob" could list "SHA256" only. @@ -165,24 +188,30 @@ If instead the user wants to write as "Bobby", the impementation should inspect However, since this signature does not carry any hash algorithm preferences subpacket, the implementation must fall back to the direct key signature instead. The same is true, if the certificate is used without any User ID as sender. -But it gets more complicated still. -Algorithm preferences can also "live" on subkey binding signatures, so if the certificate has a dedicated signing subkey, there is yet another signature which could take precedence. +To complicate things further: +Algorithm preferences can also be stated on subkey binding signatures, so if the certificate has a dedicated signing subkey, there is yet another signature which could take precedence. Preferences from the subkey binding signature take precedence over the direct key signature, but not over self-certifications on the User ID. -TODO: Have a table that lists which signatures take precedence in which cases. +```{admonition} +:class: todo -There can be more than one signature on a component. For example, there could be 3 direct key signatures, e.g. because the user extended the lifespan of their key 2 times already. +Have a table that lists which signatures take precedence in which cases. +``` + +There can be more than one signature on a component. As an example, there are 3 direct key signatures (e.g. due to extending the key's expiry two times). In general, for each component, only the newest self-signature is "in effect", and older signatures are "shadowed". For each certificate, there is at most one "active" direct key signature, for each User ID at most one active self-certification and for each subkey exactly one subkey binding. -TODO: direct key signatures can be revoked, canceling them, meaning an older one might get active? + +```{admonition} +:class: todo + +direct key signatures can be revoked, [canceling them](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#section-5.2.3.10-4), meaning an older direct-key signature might become active again? The text of the spec is confusing here. +``` ## Complexity of the packet format -Unfortunately, the OpenPGP packet format allows for quite a lot of flexibility when composing certificates. -User ID packets for example, are not fixed in regard to their position, which means that an attacker (or canonicalizer) can change the order in which User IDs appear in the certificates packet sequence. +Unfortunately, the OpenPGP packet format allows a lot of flexibility when composing certificates. +User ID packets for example, are not fixed in regard to their position, which means that an attacker (or an implementations internal certificate canonicalization procedure) can change the order in which User IDs appear in the certificate's packet sequence. As a concrete example, consider a certificate with multiple User IDs, all marked as primary. Or equally, a certificate with multiple User IDs of which none is marked as primary. Clients might apply different heuristics to figure out, which User ID actually qualifies as the primary User ID here. - -You might wonder which signature on the primary key takes precedence in case of multiple signature candidates with conflicting signature subpackets. -