diff --git a/book/source/17-zoom_certificates.md b/book/source/17-zoom_certificates.md index 78dc2a5..d4d123a 100644 --- a/book/source/17-zoom_certificates.md +++ b/book/source/17-zoom_certificates.md @@ -6,15 +6,15 @@ SPDX-License-Identifier: CC-BY-SA-4.0 (zoom_certificates)= # Zooming in: Packet structure of certificates and keys -Now that we've established these concepts, and the components that OpenPGP certificates consist of, let's look at the internal details of an example certificate. +Now that we've established the concepts and components that make up OpenPGP certificates , let's look at the internal details of an example certificate. ## A very minimal OpenPGP certificate -First, we'll look at a very minimal version of a "public key" variant of [](alice_priv). That is, an OpenPGP certificate (which doesn't contain private key material). +In this section, we will examine a very minimal version of a "public key" variant of [Alice's OpenPGP key](alice_priv), specifically an OpenPGP certificate that excludes private key material. -In this section, we use the Sequoia-PGP tool `sq` to handle and transform our example OpenPGP key, and to inspect internal OpenPGP packet data. +To achieve this, we will use the Sequoia-PGP tool `sq` to handle and transform our example OpenPGP key, as well as to inspect internal OpenPGP packet data. -Starting from [Alice's OpenPGP "private key"](alice_priv), we first produce the corresponding "public key", or certificate: +Starting from [Alice's OpenPGP private key](alice_priv), we first produce the corresponding public key/certificate using the following command: ```text $ sq key extract-cert alice.priv > alice.pub @@ -23,13 +23,15 @@ $ sq key extract-cert alice.priv > alice.pub (split_alice)= ### Splitting the OpenPGP certificate into packets -One way to produce a very minimal version of Alice's certificate is to split the data in `alice.pub` into its component packets, and join only the relevant ones back together into a new variant. +To create a very minimal version of Alice's certificate, we will split the data in `alice.pub` into its component packets and reassemble only the relevant ones back into a new variant. + +Execute the following command to achieve this: ```text $ sq packet split alice.pub ``` -With this command, `sq` generates a set of files, each containing an individual OpenPGP packet of the original full certificate in `alice.pub`: +With this command, `sq` generates a set of files, each containing an individual OpenPGP packet extracted from the original full certificate in `alice.pub`: ```text alice.pub-0--PublicKey @@ -50,22 +52,28 @@ alice.pub-9--Signature Overview of the packets in Alice's OpenPGP certificate ``` -### Joining packets into an OpenPGP certificate +This process allows us to focus on the specific packets within Alice's OpenPGP certificate. -For our first step, we'll use just the first two of the packets of Alice's certificate, and join them together as a very minimal certificate: +### Assembling packets into an OpenPGP certificate + +In this step, we'll merge the first two packets of Alice's certificate to create a very minimal certificate: + +Execute the following: ```text $ sq packet join alice.pub-0--PublicKey alice.pub-1--Signature --output alice_minimal.pub ``` +This command combines the contents of `alice.pub-0--PublicKey` and `alice.pub-1--Signature` into a single file named `alice_minimal.pub`. + ### Inspecting this certificate This version of Alice's certificate contains just two packets: -- The [*Public-Key packet*](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#name-public-key-packet-formats) for the primary key, and -- A [*Direct Key Signature*](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#sigtype-direct-key) (a self-signature that binds metadata to the primary key). +- the [*Public-Key packet*](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#name-public-key-packet-formats) for the primary key, and +- a [*Direct Key Signature*](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#sigtype-direct-key), which is a self-signature that binds metadata to the primary key. -This is the shape of the packets we'll be looking at, in the following two sections: +This is the shape of the packets we'll explore in the subsequent sections: ```{figure} diag/pubcert-minimal.png :width: 40% @@ -83,9 +91,9 @@ This diagram needs adjustments about We could show repeat-copies of the individual packet visualization again, below for each packet-related section. ``` -In the real world, you won't usually encounter an OpenPGP certificate that is quite this minimal. However, this is technically a valid OpenPGP certificate (and we'll add more components to it, later in this section). +In real-world scenarios, OpenPGP certificates are typically far more complex than this minimal example. However, this is indeed a valid OpenPGP certificate. In the following sections, we will introduce more components to this certificate, increasing its complexity and exploring their details. -In ASCII-armored representation, this very minimal key looks like this: +In ASCII-armored representation, this very minimal key appears as follows: ```text -----BEGIN PGP PUBLIC KEY BLOCK----- @@ -99,18 +107,20 @@ gAIl6FM5SWuQxg12j0S07ExCOI5NPRDCrSnAV85mAXOzeIGeiVLPQ40oEal3CX/L -----END PGP PUBLIC KEY BLOCK----- ``` -We'll now decode this OpenPGP data, and inspect the two packets in detail. +The output of `sq` is presented as a block of text. We will now decode this OpenPGP data and inspect the two packets it contains. -To inspect the internal structure of the OpenPGP data, we run the Sequoia-PGP tool `sq`, using the `packet dump` subcommand. The output of `sq` is one block of text, but to discuss the content of each packet we'll break the output up into sections here: +To achieve this, we will use the Sequoia-PGP tool `sq` and run the `packet dump` subcommand: ```text $ sq packet dump --hex alice_minimal.pub ``` +This will allow us to gain a detailed understanding of the packet contents. + (public_key)= ### Public-Key packet -The output now starts with a (primary) [Public-Key packet](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#name-public-key-packet-formats): +The output begins with a (primary) [Public-Key packet](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#name-public-key-packet-formats): ```text Public-Key Packet, new CTB, 2 header bytes + 42 bytes @@ -132,23 +142,23 @@ Public-Key Packet, new CTB, 2 header bytes + 42 bytes 00000020 eb e7 42 e2 ab 47 f4 86 b3 ae 65 3e ``` -The Public-Key packet consists in large part of the actual cryptographic key data. Let's look at the packet field by field: +The Public-Key packet consists primarily of the cryptographic key data. Let's look at the packet field by field: -- `CTB: 0xc6`[^CTB]: The [packet type ID](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#name-packet-headers) for this packet. The binary representation of the value `0xc6` is `11000110`. Bits 7 and 6 show that the packet is in *OpenPGP packet format* (as opposed to in *Legacy packet format*). The remaining 6 bits encode the type ID's value: "6". This is the value for a Public-Key packet, as shown in the list of [packet type IDs](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#name-packet-tags). -- `length: 0x2a`: The remaining length of this packet. +- `CTB: 0xc6`[^CTB]: This is the [packet type ID](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#name-packet-headers) for this packet. The binary representation of the value `0xc6` is `11000110`. The first two bits show that the packet is in *OpenPGP packet format* (as opposed to in *Legacy packet format*) and the remaining 6 bits encode the type ID value, which is "6." This type ID value corresponds to a Public-Key packet, as listed in the [packet type IDs](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#name-packet-tags). -The packet type id defines the semantics of the remaining data in the packet. We're looking at a Public-Key packet, which is a kind of [Key Material Packet](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#name-key-material-packets). +- `length: 0x2a`: This indicates the remaining length of this packet. The packet type ID defines the semantics of the remaining data within the packet. In this case, it is a Public-Key packet, which is a kind of [Key Material Packet](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#name-key-material-packets). -- `version: 0x06`: The key material is in version 6 format +- `version: 0x06`: The key material is in version 6 format. This means that the next part of the packet adheres to the structure of [Version 6 Public Keys](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#name-version-6-public-keys). -This means that the next part of the packet follows the structure of [Version 6 Public Keys](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#name-version-6-public-keys) +- `creation_time: 0x6516eaa6`: This field represents the key's creation time. (See also [Time Fields](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#name-time-fields)). -- `creation_time: 0x6516eaa6`: "The time that the key was created" (also see [Time Fields](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#name-time-fields)) -- `pk_algo: 0x1b`: "The public-key algorithm ID of this key" (decimal value 27, see the list of [Public-Key Algorithms](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#name-public-key-algorithms)) -- `public_len: 0x00000020`: "Octet count for the following public key material" (in this case, the length of the following `ed25519_public` field) -- `ed25519_public`: [Algorithm-specific representation](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#name-algorithm-specific-part-for-ed2) of the public key material (the format is based on the value of `pk_algo`), in this case 32 bytes of Ed25519 public key +- `pk_algo: 0x1b`: This corresponds to the key's public-key algorithm ID, which has a decimal value of 27. Refer to the list of [Public-Key Algorithms](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#name-public-key-algorithms)) for more details. -[^CTB]: Sequoia uses the term CTB (Cipher Type Byte) to refer to the RFC's [packet type ID](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#name-packet-headers). In previous versions, the RFC called this field "Packet Tag". +- `public_len: 0x00000020`: This section specifies the octet count for the subsequent public key material. In this case, it represents the length of the following `ed25519_public` field. + +- `ed25519_public`: This is the [algorithm-specific representation](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#name-algorithm-specific-part-for-ed2) of the public key material. The format is based on the value of `pk_algo`, which, in this case, is 32 bytes of Ed25519 public key data. + +[^CTB]: Sequoia uses the term CTB (Cipher Type Byte) to refer to the RFC's [packet type ID](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#name-packet-headers). In earlier RFC versions, this field was known as the "Packet Tag." ```{tip} @@ -160,9 +170,9 @@ Note that the *Public-Key packet* contains only the public part of the key. (zooming_in_dks)= ### Direct Key Signature -The next packet is a [*Direct Key Signature*](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#sigtype-direct-key), which is bound to the primary key (the file `alice.pub-1--Signature` contains this packet). +The next packet in the certificate is a [*Direct Key Signature*](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#sigtype-direct-key), which plays a crucial role in binding specific information to the primary key. This signature is contained within the file `alice.pub-1--Signature`. -This packet "binds the information in the signature subpackets to the key". Each entry under "Signature Packet -> Hashed area" is one signature subpacket, for example, including information about algorithm preferences (*symmetric algorithm preference* and *hash algorithm preferences*). +This packet binds the information within the signature subpackets with the primary key. Each entry under "Signature Packet -> Hashed area" is one signature subpacket, for example, including information about algorithm preferences (*symmetric algorithm preference* and *hash algorithm preferences*). ```text Signature Packet, new CTB, 2 header bytes + 182 bytes