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.
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.
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.
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.
With this command, `sq` generates a set of files, each containing an individual OpenPGP packet extracted from the original full certificate in `alice.pub`:
- 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.
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.
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):
The Public-Key packet consists primarily of the cryptographic key data. Let's look at the packet field by field:
-`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).
-`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. 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).
-`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)).
-`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.
-`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."
The overall structure of OpenPGP packets is described in the [Packet Syntax](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#name-packet-syntax) chapter of the RFC.
```
Note that the *Public-Key packet* contains only the public part of the key.
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 data within the signature subpackets with the primary key. Each entry under "Signature Packet -> Hashed area" is one signature subpacket, providing essential information such as algorithm preferences, including *symmetric algorithm preference* and *hash algorithm preferences*.
-`CTB: 0xc2`: This field indicates the Packet type ID for this packet. Bits 7 and 6 show that the packet is in “OpenPGP packet format.” The remaining 6 bits encode the type ID’s value, which is “2” for a Signature packet.
The packet type ID (`0xc2`) defines the semantics of the remaining data in the packet. In this case, as it indicates a [Signature packet](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#signature-packet), the following data is specific to this signature type.
-`pk_algo: 0x1b`: This specifies the Public-Key algorithm ID, with decimal 27 corresponding to [Ed25519](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#name-public-key-algorithms)).
-`hash_algo: 0x0a`: This specifies the hash algorithm ID, with decimal 10 corresponding to [SHA2-512](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#name-hash-algorithms)).
In OpenPGP Signatures, there are two sets of subpacket data: hashed and unhashed. Hashed subpackets are protected by the digital signature of the packet, while unhashed subpackets are not.
A subpacket data set in an OpenPGP Signature contains a list of zero or more Signature subpackets.
The following subpacket data consists of sets of "subpacket length, subpacket type ID, data." Each subpacket is displayed as one line, starting with the [subpacket type description](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#name-signature-subpacket-specifi) (based on the subpacket type ID). Note that bit 7 of the subpacket type ID signals if that subpacket is ["critical."](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#section-5.2.3.7-10)
Critical here means that the receiver must interpret the subpacket and is expected to fail, otherwise. Non-critical subpackets may be ignored by the receiver.
- Notes: The fingerprint identifoes the component key that issued the signature in this packet. In this instance, the value is the primary key fingerprint of the certificate we're looking at.
This next section shows additional components of the Direct Key Signature packet:
-`digest_prefix: 0x6747`: the left 16 bits of the signed hash value
-`salt_len, salt`: a random [salt value](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#name-advantages-of-salted-signat) with size [matching the hash algorithm](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#hash-algorithms-registry))
-`ed25519_sig`: [algorithm-specific](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#name-algorithm-specific-fields-for-ed2) representation of the signature (here: 64 bytes of Ed25519 signature)
The signature's hash is calculated over the following data (see [Computing Signatures](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-11.html#name-computing-signatures) in the RFC):
Now we'll look at a subkey in Alice's certificate. An OpenPGP subkey, when it is linked to an OpenPGP certificate (via its primary key), 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 certificate, which we split apart above. In this split representation of Alice's certificate, the encryption subkey happens to be stored in `alice.pub-4--PublicSubkey`, and the associated binding self-signature for the subkey in `alice.pub-5--Signature`.
````{note}
It's common to look at a packet dump for a full OpenPGP certificate, like this:
```text
$ sq packet dump --hex alice.pub
```
That command shows the details for the full series of packets in an OpenPGP certificate (recall the list of [packets of Alice's certificate](split_alice)). Finding a particular packet in that list can take a bit of focus and practice though.
In the following sections we're making it a bit easier for ourselves, and directly look at individual packets, from the files we created with `sq packet split`, above.
````
### Public-Subkey packet
First, we'll look at the *Public-Subkey packet* that contains the component key data of this subkey:
```text
$ sq packet dump --hex alice.pub-4--PublicSubkey
Public-Subkey Packet, new CTB, 2 header bytes + 42 bytes
00000010 cc 42 af 99 34 c5 c2 5c ca fa b7 4a c8 43 fc 86
00000020 35 2a 46 01 f3 cc 00 f5 4a 09 3e 3f
```
Notice that the structure of this *Public-Subkey packet* is the same as the *Public-Key Packet* of the primary key, [above](public_key). Only the content of the two packets differs in some points:
- The packet type ID (`CTB`) in this packet shows type 14 ([*Public-Subkey packet*](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#name-public-subkey-packet-tag-14)).
- 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, the public part of the cryptographic key pair is labeled with the corresponding name: `x25519_public` (however, note that this difference only reflects the semantics of the field, which is implied by the value of `pk_algo`. The actual data 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.
```{admonition} VISUAL
:class: warning
Add detailed packet diagram analogous to 4.6.1
```
```{admonition} TODO
:class: warning
david points out: "The information on metadata in binding signatures may also make sense in other contexts (direct key signature)?"
Should this text go elsewhere?
- 4.2.3?
- ch 6?
```
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 supersedes 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.pub-5--Signature
Signature Packet, new CTB, 2 header bytes + 171 bytes
Version: 6
Type: SubkeyBinding
Pk algo: Ed25519
Hash algo: SHA512
Hashed area:
Signature creation time: 2023-09-29 15:17:58 UTC (critical)
00000050 b5 ab 15 e3 7f e4 4d b9 a7 ef 71 48 14 3b ab 26
00000060 5f 34 7f 6d 48 2e 9f 78 48 58 6d 9a fb
0000006d 6d b2 db ed25519_sig
00000070 2f 97 8e c8 12 fc 57 7f 85 aa d1 59 bc 80 40 0b
00000080 be 2e f0 e1 23 2d bf 4b 71 7e d0 e4 c0 36 e4 d2
00000090 cf b2 9f b4 a8 4f 3e 2a 21 89 74 c2 33 55 af ac
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 text at the top of this packet dump, the hashed subpacket data contains four pieces of information:
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
```{admonition} TODO
:class: warning
write
```
```text
$ sq packet dump --hex alice.pub-6--PublicSubkey
Public-Subkey Packet, new CTB, 2 header bytes + 42 bytes
000000f0 93 af ba 08 89 f0 e0 91 0f ab 22 26 aa b3 56 57
00000100 30 ea 95 29 06 60 6f 00
00000108 be 44 a1 95 38 a9 6b 3a ed25519_sig
00000110 3e 51 f0 55 09 b1 e2 91 a9 17 86 fa f5 1e 3f d0
00000120 28 46 3c ce 6e 88 14 37 32 ec 3d fa c6 01 ca e5
00000130 a9 4b b7 63 94 c3 0d 92 ab dc fa 23 50 71 60 31
00000140 a6 73 c8 33 5a 9c d9 0a
```
(zooming_in_user_id)=
## Adding an identity component
Now we'll look at an identity that is associated with Alice's certificate.
User IDs are a mechanism for connecting [identities](identity_components) with an OpenPGP certificate. Traditionally, User IDs contain a string that combines a name and an email address.
Like [above](zoom_enc_subkey), to look at the internal packet structure of this identity and its connection the OpenPGP certificate, we'll inspect the two individual packets that constitute the identity component, the [User ID packet](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#name-user-id-packet-tag-13), in the file `alice.pub-2--UserID`, and the certifying self-signature a [Positive certification of a User ID and Public-Key packet](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#name-positive-certification-of-a) in `alice.pub-3--Signature` (these packets are an excerpt of Alice's full OpenPGP private key).
### User ID packet
First, let's look at the User ID packet, which encodes an identity that Alice has connected to her OpenPGP certificate:
```text
$ sq packet dump --hex alice.pub-2--UserID
User ID Packet, new CTB, 2 header bytes + 19 bytes
-`CTB: 0xcd`: The Packet type ID for this packet. 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: “13.” This is the value for a [User ID packet](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#name-user-id-packet-tag-13).
-`length: 0x13`: The remaining length of this packet (here: 19 bytes).
-`value`: 19 bytes of data that contain UTF-8 encoded text. The value corresponds to the string `<alice@example.org>`. With this identity component, Alice states that she uses (and has control of) this email address. Note that the email address is enclosed in `<` and `>` characters, following [RFC 2822](https://www.rfc-editor.org/rfc/rfc2822) conventions.
So, a User ID packet is really just a string, marked as a User ID by the packet type id.
### Linking the User ID with a certification self-signature
As above, when [linking a subkey](zoom_enc_subkey) to the OpenPGP certificate, a self-signature is used to connect this new component to the certificate.
To bind identities to a certificate with a self-signature, one of the signature types `0x10` - `0x13` can be used. Here, the signature type `0x13` (*positive certification*) is used.
```text
$ sq packet dump --hex alice.pub-3--Signature
Signature Packet, new CTB, 2 header bytes + 185 bytes
Version: 6
Type: PositiveCertification
Pk algo: Ed25519
Hash algo: SHA512
Hashed area:
Signature creation time: 2023-09-29 15:17:58 UTC (critical)
00000090 66 07 8b b2 ba 3d b7 89 e4 76 04 6e 35 24 2b 27
000000a0 29 83 be 91 9c 78 6a cc b4 d5 69 47 76 2c 29 d6
000000b0 54 bf 43 19 04 ff 53 98 c0 d5 0b
```
We'll go over this packet dump in less detail, since its structure closely mirrors the [Direct Key Signature](zooming_in_dks) discussed above.
We're again looking at a Signature packet. Its `type` is `0x13` ([corresponding](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#name-signature-types) to a *positive certification* signature).
The public key algorithm and hash function used for this signature are Ed25519 and SHA512.
As shown in the text at the top of this packet dump, the hashed subpacket data contains the following metadata:
This is a combination of metadata about the User ID itself (including defining this User ID as the *primary User ID* of this certificate), algorithm preferences that are associated with this identity, and settings that apply to the primary key.
````{note}
For historical reasons, the self-signature that binds the primary User ID to the certificate also contains subpackets that apply not to the User ID, but to the primary key itself.
Setting key expiration time and key flags on the primary User ID self-signature is one mechanism to configure the primary key.
The interaction between metadata on direct key signatures and User ID binding self-signatures [is subtle](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-11.html#name-notes-on-self-signatures), and there are changes between version 6 and version 4.
```{admonition} TODO
:class: warning
- link to a section that goes into more depth about "#name-notes-on-self-signatures"?
```
````
Followed, again, by the (informational) unhashed subpacket area.
And finally, a salt value for the signature and the 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 User ID
- A serialized form of this self-signature packet (up to, but excluding the unhashed area)