diff --git a/book/source/04-certificates.md b/book/source/04-certificates.md index 5f51224..8d2ae8c 100644 --- a/book/source/04-certificates.md +++ b/book/source/04-certificates.md @@ -599,7 +599,18 @@ In the following examples, we will only look at OpenPGP keys that include the pr ### Encryption subkey -Now we'll look at a subkey in Alice's key. In the split version of Alice's key, the encryption subkey is in `alice.priv-4--SecretSubkey`, and the binding self-signature for the subkey in `alice.priv-5--Signature`. +Now we'll look at a subkey in Alice's key. An OpenPGP subkey, when it is linked to an OpenPGP certificate, effectively consists of two elements: + +- a key packet that contains the component key itself, and +- a signature packet that links this component key to the primary key (and thus implicitly to the full OpenPGP certificate). + +In this section, we'll use the files that contain individual packets of Alice's key, which we generated above. In this split representation of Alice's key, the encryption subkey happens to be stored in `alice.priv-4--SecretSubkey`, and the associated binding self-signature for the subkey in `alice.priv-5--Signature`. + +If we were looking at a regular (not split apart) OpenPGP key, we would look at the output of something like `$ sq packet dump --hex alice.priv`, and would be shown a longer series of packets. That series would contain the two packets we'll now look at, with the exact same content. They would just be slightly harder to locate, in the larger context of a full OpenPGP key. + +#### Secret-Subkey packet + +First, we'll look at the *Secret-Subkey packet* that contains the component key data of this subkey: ```text $ sq packet dump --hex alice.priv-4--SecretSubkey @@ -630,10 +641,21 @@ Secret-Subkey Packet, new CTB, 2 header bytes + 75 bytes 00000040 c9 77 fb bd 23 41 73 c9 57 5a bf 7c 4c ``` -Notice that the structure of this *Secret-Subkey packet* is exactly the same as the *Secret-Key Packet*, above. The packet tag (`CTB`) is set to packet type 7, here (*Secret-Subkey packet*). +Notice that the structure of this *Secret-Subkey packet* is the same as the *Secret-Key Packet* of the primary key, above. Only the content of the two packets differs in some points: -The `pk_algo` value is set to 0x19 (or decimal) 25, which [corresponds to](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#name-public-key-algorithms) X25519. +- The packet tag (`CTB`) in this packet shows type 7 ([*Secret-Subkey packet*](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#name-secret-subkey-packet-tag-7)). +- The `pk_algo` value is set to `0x19` (decimal 25), which [corresponds to](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#name-public-key-algorithms) X25519. Note that even though both the primary key and this subkey use a cryptographic mechanism based on Curve25519, this encryption key uses Curve 25519 in a different way (X25519 is a Diffie–Hellman function built out of Curve25519). +- Accordingly, both parts of the cryptographic key pair are labeled with the corresponding names `x25519_public` and `x25519_secret` (however, note that this difference only reflects the semantics of the fields, which are implied by the value of `pk_algo`. The actual data in both fields consists of just 32 bytes of cryptographic key material, without any type information.) +#### Subkey binding signature + +The subkey packet above by itself is disconnected from the OpenPGP certificate that it is a part of. The link between the subkey and the full OpenPGP key is made with a cryptographic signature, which is issued by the OpenPGP key's primary key. + +The type of signature that is used for this is called a *subkey binding signature*, because it "binds" (as in "connects") the subkey to the rest of the key. + +In addition to its core purpose of making the connection, this signature also contains additional metadata about the subkey. One reason why this metadata is in a binding signature (and not in the subkey packet) is that it may change over time. The subkey packet itself may not change over time. So metadata about the subkey that can change is stored in self-signatures: if the key holder wants to change some metadata (for example, the key's expiration time), they can issue a newer version of the same kind of signature. Receiving OpenPGP software will then understand that the newer self-signature supercedes the older signature, and that the metadata in the newer signature reflects the most current intent of the key holder. + +Note that this subkey binding signature packet is quite similar to the Direct Key Signature we discussed packet above. Both signatures perform the same function in terms of adding metadata to a component key. In particular, the hashed subpacket data contains many of the same pieces of metadata. ```text $ sq packet dump --hex alice.priv-5--Signature @@ -691,6 +713,31 @@ Signature Packet, new CTB, 2 header bytes + 171 bytes 000000a0 41 36 1b 2b 60 09 f2 d9 19 f4 41 12 0b ``` +We'll go over this packet dump in less detail, since its structure mirrors the *Direct Key Signature* (described above) very closely. + +The first difference is in the `type` field, showing that this signature is of type `0x18` ([Subkey Binding Signature](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#name-subkey-binding-signature-si)). + +The `pk_algo` of this signature is informed by the algorithm of the primary key (`0x1b`, corresponding to Ed25519). The signature in this packet is issued by the primary key, so by definition it uses the signing algorithm of the primary key (that is: the algorithm used to produce the cryptographic signature in this packet is entire independent of the `pk_algo` of the key material of this subkey itself, which uses the X25519 mechanism). + +As shown in the header of this packet dump, the hashed subpacket data contains four pieces of information: + +- Signature creation time: `2023-09-29 15:17:58 UTC` (**critical**) +- Key expiration time: `P1095DT62781S` (**critical**) +- Key flags: `EtEr` (**critical**) (encryption for communication, encryption for storage) +- Issuer Fingerprint: `AAA18CBB254685C58358320563FD37B67F3300F9FB0EC457378CD29F102698B3` + +The remainder of the packet has the same content as the *Direct Key Signature* above: +- A 16 bit digest prefix +- A salt value +- The cryptographic signature itself + +The signature is calculated over a hash. The hash, in this case, is calculated over the following data (for details, see [Computing Signatures](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-11.html#name-computing-signatures) in the RFC): + +- The signature's salt +- A serialized form of the primary key's public data +- A serialized form of the subkey's public data +- A serialized form of this subkey binding signature packet (up to, but excluding the unhashed area) + ### Signing subkey ```text