mirror of
https://codeberg.org/openpgp/notes.git
synced 2024-11-27 10:02:06 +01:00
823 lines
49 KiB
Markdown
823 lines
49 KiB
Markdown
(certificates_chapter)=
|
||
# Certificates
|
||
|
||
OpenPGP fundamentally hinges on the concept of "OpenPGP certificates," also known as "OpenPGP keys." These certificates are complex data structures essential for identity verification, data encryption, and digital signatures. Understanding their structure and function is pivotal to effectively applying the OpenPGP standard.
|
||
|
||
## Terminology: Understanding "keys"
|
||
|
||
The term "(cryptographic) keys" is central to grasping the concept of OpenPGP certificates. However, it can refer to different entities, making it a potentially confusing term. Let's clarify those differences.
|
||
|
||
### Public vs. private keys
|
||
|
||
The term "key," without additional context, can refer to either public or private asymmetric key material. Additionally, symmetric keys may be used in OpenPGP to encrypt private key material, adding a layer of security and complexity.
|
||
|
||
### Layers of keys in OpenPGP
|
||
|
||
In OpenPGP, the term "key" may refer to three distinct layers, each serving a unique purpose:
|
||
|
||
1. A (bare) ["cryptographic key"](asymmetric_key_pair) comprises the private and/or public parameters forming a key. For instance, in the case of an RSA private key, the key consists of the exponent `d` along with the prime numbers `p` and `q`.
|
||
2. An OpenPGP *component key* includes either an "OpenPGP primary key" or an "OpenPGP subkey." It is a building block of an OpenPGP certificate, consisting of a cryptographic keypair coupled with some invariant metadata, such as key creation time.
|
||
3. An "OpenPGP certificate" (or "OpenPGP key") consists of several component keys, identity components, and other elements. These certificates are dynamic, evolving over time as components are added, expire, or are marked as invalid.
|
||
|
||
The following section will delve into the OpenPGP-specific layers (2 and 3) to provide a clearer understanding of their roles within OpenPGP certificates.
|
||
|
||
For detailed insights on structure and handling, refer to our chapters on OpenPGP [certificates](certificates_chapter) and [private keys](private_key_chapter). Additionally, managing certificates, and understanding their authentication and trust models are vital topics. While this document briefly touches upon these aspects, they are integral to working proficiently with OpenPGP.
|
||
|
||
## Structure of OpenPGP certificates
|
||
|
||
An OpenPGP certificate (or "OpenPGP key") is a collection of an arbitrary number of elements[^packets]:
|
||
|
||
[^packets]: In technical terms, the elements of an OpenPGP certificate are a collection of "packets." Each component key and identity component is internally represented as a packet. Another common type of packet is the "signature" packet, which connect the components of a certificate.
|
||
|
||
- Component keys
|
||
- Identity components
|
||
- Additional metadata, including connections between the certificate's components
|
||
|
||
We sometimes collectively refer to component keys and identity information as "the components of a certificate."
|
||
|
||
```{admonition} Warning
|
||
Please clarify who "we" is in this statement.
|
||
```
|
||
|
||
```{figure} diag/OpenPGP_Certificate.png
|
||
|
||
Typical components in an OpenPGP certificate
|
||
```
|
||
|
||
Every element in an OpenPGP certificate revolves around a central component: the *OpenPGP primary key*. The primary key acts as a personal CA (Certification Authority) for the certificate's owner, enabling cryptographic statements regarding subkeys, identities, expiration, revocation, and more.
|
||
|
||
```{note}
|
||
OpenPGP certificates tend to have a long lifespan, with the potential for modifications (typically by their owner) over time. Components may be added or invalidated throughout a certificate's lifetime.
|
||
```
|
||
|
||
### OpenPGP component keys
|
||
|
||
An OpenPGP certificate usually contains multiple component keys.
|
||
|
||
OpenPGP component keys consist of an [asymmetric cryptographic keypair](asymmetric_key_pair) and a creation timestamp. Once created, these attributes of a component key remain fixed (for ECDH keys, two additional parameters are part of a component key's constitutive data[^ecdh-parameters]).
|
||
|
||
[^ecdh-parameters]: For [ECDH](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#name-algorithm-specific-part-for-ecd) component keys, two additional algorithm parameters are integral to the component key's constitutive and immutable properties. Those parameters specify a hash function and a symmetric encryption algorithm.
|
||
|
||
```{figure} diag/Component_Key.svg
|
||
|
||
An OpenPGP component key
|
||
```
|
||
|
||
Component keys containing private key material also contain metadata that specifies the password protection scheme for the private key material.
|
||
|
||
For each OpenPGP component key, an *OpenPGP fingerprint* can be generated. This fingerprint is derived from the combination of the public key material and creation timestamp (and ECDH parameters, if applicable).
|
||
|
||
```{figure} diag/Fingerprint.png
|
||
|
||
Every OpenPGP component key is identifiable by a unique fingerprint.
|
||
```
|
||
|
||
The fingerprint of our example OpenPGP component key is `AAA1 8CBB 2546 85C5 8358 3205 63FD 37B6 7F33 00F9 FB0E C457 378C D29F 1026 98B3` [^keyid].
|
||
|
||
[^keyid]: In OpenPGP version 4, the rightmost 64 bits were sometimes used as a shorter identifier, called "Key ID."
|
||
For example, an OpenPGP version 4 certificate with the fingerprint `B3D2 7B09 FBA4 1235 2B41 8972 C8B8 6AC4 2455 4239` might be referenced by the 64-bit Key ID `C8B8 6AC4 2455 4239` or formatted as `0xC8B86AC424554239`.
|
||
Historically, even shorter 32-bit identifiers were used, like this: `2455 4239`, or `0x24554239`. Such identifiers still appear in very old documents about PGP. However, [32-bit identifiers have been long deemed unfit for purpose](https://evil32.com/). At one point, 32-bit identifiers were called "short Key ID," while 64-bit identifiers were referred to as "long Key ID."
|
||
|
||
Component keys serve in one of two roles: either as an "OpenPGP primary key" or as an "OpenPGP subkey."
|
||
|
||
#### Primary key
|
||
|
||
The OpenPGP primary key is a distinct component key that serves a central role in an OpenPGP certificate:
|
||
|
||
- Its fingerprint acts as the unique identifier for the entire OpenPGP certificate.
|
||
- It facilitates lifecycle operations, such as adding or invalidating subkeys or identities within a certificate.
|
||
|
||
```{admonition} Terminology
|
||
:class: note
|
||
|
||
In the RFC, the OpenPGP primary key is occasionally referred to as "top-level key." Informally, it has also been termed the "master key."
|
||
```
|
||
|
||
#### Subkeys
|
||
|
||
In addition to the primary key, modern OpenPGP certificates usually contain several subkeys, although they are not technically required.
|
||
|
||
Subkeys have the same structural attributes as the primary key but fulfill a different role. Subkeys are cryptographically linked with the primary key (elaborated below).
|
||
|
||
```{figure} diag/Subkeys.png
|
||
:name: Certificate with subkeys
|
||
:alt: Three component keys depicted. The primary key is positioned at the top, designated for certification. Below it, linked by arrows, are two more component keys, used as subkeys. They are labeled as "for encryption" and "for signing," respectively.
|
||
|
||
OpenPGP certificates can contain multiple subkeys.
|
||
```
|
||
|
||
#### Key Flags: defining which operations a component key can perform
|
||
|
||
Each component key has a set of ["Key Flags"](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#key-flags) that specify which operations that key can perform.
|
||
|
||
The commonly used key flags are:
|
||
|
||
- **C**ertification (issuing third-party certifications)
|
||
- **S**igning (signing data)
|
||
- **E**ncryption (encrypting data)
|
||
- **A**uthentication (commonly used for OpenPGP authentication)
|
||
|
||
By convention, only the primary key is allowed to perform "certification" operations. All other operations can be configured on either the primary key or a subkey.
|
||
|
||
```{note}
|
||
|
||
It is considered good practice to have separate component keys for each type of operation: to allow only *Certification* operations with the primary key, and to use separate *Signing*, *Encryption* and *Authentication* subkeys (independently: with most algorithms, encryption can't be shared with the other capabilities[^key-flag-sharing]).
|
||
```
|
||
|
||
[^key-flag-sharing]: With ECC algorithms, it's actually not possible to share encryption functionality with the signing-based functionalities, e.g.: ed25519 used for signing; cv25519 used for encryption.
|
||
|
||
|
||
### Identity components
|
||
|
||
#### User IDs
|
||
|
||
An OpenPGP certificate can contain any number of [User IDs](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#name-user-id-packet-tag-13). Each User ID associates the certificate with an identity.
|
||
|
||
Often, identities in a User ID consist of a string that is composed of a name and an email address (this string must be UTF-8 encoded).
|
||
|
||
```{figure} diag/user_id.png
|
||
|
||
OpenPGP certificates can contain any number of User IDs
|
||
```
|
||
|
||
#### Primary User ID and its implications
|
||
|
||
One User ID in a certificate has the special property of being the [Primary User ID](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#name-primary-user-id).
|
||
|
||
User IDs are associated with preference settings (such as preferred encryption algorithms, more on this below). The preferences associated with the Primary User ID are used by default.
|
||
|
||
|
||
#### User attributes
|
||
|
||
[User attributes](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#name-user-attribute-packet-tag-1) are similar to User IDs, but less commonly used.
|
||
|
||
The OpenPGP standard currently only defines one format to store in User Attributes: an [image](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#name-the-image-attribute-subpack), "presumably (but not required to be) that of the key owner".
|
||
|
||
### Linking the components of an OpenPGP certificate
|
||
|
||
So far we've looked at the components in an OpenPGP certificate, but certificates actually contain another set of elements, which bind the components together, and add metadata to them.
|
||
|
||
Internally, an OpenPGP certificate consists of a sequence of OpenPGP packets. These packets are just stringed together, one after the other. When a certificate is stored in a file[^tpk], it's easy to remove some of these packets, or add new ones.
|
||
|
||
[^tpk]: When stored in a file, OpenPGP certificates are in a format called [transferable public key](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#name-transferable-public-keys).
|
||
|
||
However, the owner of a certificate doesn't want a third party to add subkeys (or add identity claims) to their certificate, pretending that the certificate owner put those components there.
|
||
|
||
To prevent malicious addition of components, OpenPGP uses cryptographic signatures. These signatures show that components have been added by the owner of the OpenPGP certificate (these linking signatures are issued by the primary key of the certificate).
|
||
|
||
So while anyone can still unilaterally store unrelated subkeys and identity claims in an OpenPGP certificate dataset, OpenPGP implementations that read this file should discard components that don't have a valid cryptographic connection with the certificate.
|
||
|
||
(Conversely, it's easy for a third party to leave out packets when passing on an OpenPGP certificate. An attacker can, for example, choose to omit revocation packets. The recipient of such a partial copy has no way to notice the omission, without access to a different source for the certificate that contains the revocation packet.)
|
||
|
||
Note, though, that there are some cases where third parties legitimately add "unbound" packets to certificates (that is: packets that are not signed by the certificate's owner):
|
||
|
||
- [Third-party certifications](third_party_cert) are traditionally added to the certificate that they make a statement about (this can cause problems in systems that unconditionally accept and include such certifications[^flooding]),
|
||
- OpenPGP software may add [unbound identity data](unbound_user_ids), locally.
|
||
|
||
[^flooding]: Storing third-party identity certifications in the target OpenPGP certificate is convenient for consumers: it is easy to find all relevant certifications in one central location. However, when third parties can unilaterally add certifications, this opens an avenue for denial-of-service attacks by flooding. The SKS network of OpenPGP key servers [allowed and experienced this problem](https://dkg.fifthhorseman.net/blog/openpgp-certificate-flooding.html).
|
||
|
||
#### Binding subkeys to an OpenPGP certificate
|
||
|
||
Linking a subkey to an OpenPGP certificate is done with a ["Subkey Binding Signature"](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#sigtype-subkey-binding). Such a signature signals that the "primary key wants to be associated with the subkey".
|
||
|
||
The subkey binding signature also adds metadata.
|
||
|
||
```{figure} diag/subkey_binding.png
|
||
|
||
Linking an OpenPGP subkey to the primary key with a binding signature
|
||
```
|
||
|
||
The [Signature packet](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#name-signature-packet-tag-2) that binds the subkey to the primary key has the signature type [SubkeyBinding](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#name-subkey-binding-signature-si).
|
||
|
||
##### Binding signing subkeys to an OpenPGP certificate
|
||
|
||
Binding subkeys with the "signing" key flag is a special case:
|
||
|
||
When binding a signing subkey to a primary key, it is not sufficient that the "primary key wants to be associated with the subkey." In addition, the subkey must signal that it "wants to be associated with that primary key."
|
||
|
||
Otherwise, Alice could "adopt" Bob's signing subkey and convincingly claim that she made signatures that were in fact issued by Bob.
|
||
|
||
```{figure} diag/subkey_binding_backsig.png
|
||
|
||
Linking an OpenPGP signing subkey to the primary key with a binding signature, and an embedded primary key binding signature
|
||
```
|
||
|
||
This additional "Primary Key Binding" Signature is informally called a "back signature" (because the subkey uses the signature to point "back" to the primary key).
|
||
|
||
|
||
#### Binding identities with certifying self-signatures
|
||
|
||
"User ID" identity components are bound to an OpenPGP certificate by issuing a self-signature ("User Attributes" work analogously).
|
||
|
||
For example, the User ID `Alice Adams <alice@example.org>` may be associated with Alice's certificate `AAA1 8CBB 2546 85C5 8358 3205 63FD 37B6 7F33 00F9 FB0E C457 378C D29F 1026 98B3`.
|
||
|
||
Alice can link a User ID to her OpenPGP certificate with a cryptographic signature. To link a User ID, a self-signature is created (usually with the signature type [PositiveCertification](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#sigtype-positive-cert)). This signature is issued by the primary key.
|
||
|
||
```{figure} diag/user_id_certification.png
|
||
---
|
||
---
|
||
Linking a User ID to an OpenPGP certificate
|
||
```
|
||
|
||
(third_party_cert)=
|
||
## Third party (identity) certifications
|
||
|
||
```{admonition} TODO
|
||
:class: warning
|
||
|
||
This section needs writing
|
||
```
|
||
|
||
## Revocations
|
||
|
||
```{admonition} TODO
|
||
:class: warning
|
||
|
||
This section only contains notes and still needs to be written
|
||
```
|
||
|
||
Note: certification signatures [can be made irrevocable](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#name-revocable).
|
||
|
||
### Hard vs. soft revocations
|
||
|
||
|
||
## Advanced topics
|
||
|
||
```{admonition} TODO
|
||
:class: warning
|
||
|
||
This section only contains notes and still needs to be written
|
||
```
|
||
|
||
### Certificate Management / Evolution of a certificate over time
|
||
|
||
Minimized versions, merging, effective "append only" semantics, ...
|
||
|
||
### Merging
|
||
|
||
- How to merge two copies of the same certificate?
|
||
- Canonicalization
|
||
|
||
### How to generate "minimized" certificate?
|
||
|
||
### When are certificates valid?
|
||
|
||
- Full certificate: Primary revoked/key expired/binding signature expired,
|
||
- Subkey: Revoked/key expired/binding signature expired
|
||
- User ID: revoked, binding expired, ...
|
||
|
||
### Best Practices regarding Key Freshness
|
||
|
||
```{admonition} TODO
|
||
:class: warning
|
||
|
||
- Expiry
|
||
- Subkey rotation
|
||
|
||
Wiktor suggests to check: https://blogs.gentoo.org/mgorny/2018/08/13/openpgp-key-expiration-is-not-a-security-measure/ for important material
|
||
```
|
||
|
||
### Metadata Leak of Social Graph
|
||
|
||
(unbound_user_ids)=
|
||
### Adding unbound User IDs to a certificate
|
||
|
||
Some OpenPGP subsystems may add User IDs to a certificate, which are not bound to the primary key by the certificate's owner. This can be useful to store local identity information (e.g., Sequoia's public store attaches "pet-names" to certificates, in this way).
|
||
|
||
## Zooming in: Packet structure
|
||
|
||
Now that we've established the concepts of the components that OpenPGP certificates consist of, let's look at the internal details of our example certificate.
|
||
|
||
### A very minimal OpenPGP "Transferrable Secret Key"
|
||
|
||
We'll start with a very minimal version of [](alice_priv), stored as a "Transferrable Secret Key" (that is, including 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.
|
||
|
||
One way to produce this minimal version of Alice's key is:
|
||
|
||
```text
|
||
$ sq packet split alice.priv
|
||
```
|
||
|
||
With this command, `sq` generates a set of files, one for each packet in `alice.priv`:
|
||
|
||
```text
|
||
alice.priv-0--SecretKey
|
||
alice.priv-1--Signature
|
||
alice.priv-2--UserID
|
||
alice.priv-3--Signature
|
||
alice.priv-4--SecretSubkey
|
||
alice.priv-5--Signature
|
||
alice.priv-6--SecretSubkey
|
||
alice.priv-7--Signature
|
||
alice.priv-8--SecretSubkey
|
||
alice.priv-9--Signature
|
||
```
|
||
|
||
For our first step, we'll use just the first two of these packets, and join them together as a private key:
|
||
|
||
```text
|
||
$ sq packet join alice.priv-0--SecretKey alice.priv-1--Signature --output alice_minimal.priv
|
||
```
|
||
|
||
This version of Alice's key contains just two packets:
|
||
|
||
- The [*"Secret-Key Packet"*](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#name-secret-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).
|
||
|
||
In the real world, you won't usually encounter an OpenPGP key that is quite this minimal. However, this is technically a valid OpenPGP key (and we'll add more components to it, later in this section).
|
||
|
||
In ASCII-armored representation, this very minimal key looks like this:
|
||
|
||
```text
|
||
-----BEGIN PGP PRIVATE KEY BLOCK-----
|
||
Comment: AAA1 8CBB 2546 85C5 8358 3205 63FD 37B6 7F33 00F9 FB0E C457 378C D29F 1026 98B3
|
||
|
||
xUsGZRbqphsAAAAgUyTpQ6+rFfdu1bUSmHlpzRtdEGXr50Liq0f0hrOuZT4A7+GZ
|
||
tV8R+6qT6CadO7ItciB9/71C3UvpozaBO6XMz/vCtgYfGwoAAAA9BYJlFuqmBYkF
|
||
pI+9AwsJBwMVCggCmwECHgEiIQaqoYy7JUaFxYNYMgVj/Te2fzMA+fsOxFc3jNKf
|
||
ECaYswAAAAoJEKqhjLslRoXFZ0cgouNjgeNr0E9W18g4gAIl6FM5SWuQxg12j0S0
|
||
7ExCOI5NPRDCrSnAV85mAXOzeIGeiVLPQ40oEal3CX/L+BXIoY2sIEQrLd4TAEEy
|
||
0BA8aQZTPEmMdiOCM1QB+V+BQZAO
|
||
=f0GN
|
||
-----END PGP PRIVATE KEY BLOCK-----
|
||
```
|
||
|
||
We'll now decode this OpenPGP data, and inspect the two packets in detail.
|
||
|
||
To generate the output, we run the Sequoia-PGP tool `sq`, using the `packet dump` subcommand. The output of `sq` is one block of text, but we'll break the output up into sections here, to discuss the content of each packet:
|
||
|
||
```text
|
||
$ sq packet dump --hex alice_minimal.priv
|
||
```
|
||
|
||
#### Secret-Key Packet
|
||
|
||
The output starts with the (primary) [Secret-Key Packet](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#name-secret-key-packet-formats) (the file `alice.priv-0--SecretKey` contains this packet):
|
||
|
||
```text
|
||
Secret-Key Packet, new CTB, 2 header bytes + 75 bytes
|
||
Version: 6
|
||
Creation time: 2023-09-29 15:17:58 UTC
|
||
Pk algo: Ed25519
|
||
Pk size: 256 bits
|
||
Fingerprint: AAA18CBB254685C58358320563FD37B67F3300F9FB0EC457378CD29F102698B3
|
||
KeyID: AAA18CBB254685C5
|
||
|
||
Secret Key:
|
||
|
||
Unencrypted
|
||
|
||
00000000 c5 CTB
|
||
00000001 4b length
|
||
00000002 06 version
|
||
00000003 65 16 ea a6 creation_time
|
||
00000007 1b pk_algo
|
||
00000008 00 00 00 20 public_len
|
||
0000000c 53 24 e9 43 ed25519_public
|
||
00000010 af ab 15 f7 6e d5 b5 12 98 79 69 cd 1b 5d 10 65
|
||
00000020 eb e7 42 e2 ab 47 f4 86 b3 ae 65 3e
|
||
0000002c 00 s2k_usage
|
||
0000002d ef e1 99 ed25519_secret
|
||
00000030 b5 5f 11 fb aa 93 e8 26 9d 3b b2 2d 72 20 7d ff
|
||
00000040 bd 42 dd 4b e9 a3 36 81 3b a5 cc cf fb
|
||
```
|
||
|
||
The Secret-Key Packet consists in large part of the actual cryptographic key data. Let's look at the packet field by field:
|
||
|
||
- `CTB: 0xc5`[^CTB]: The [Packet Tag](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 `0xc5` is `11000101`. 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 Tag's value: "5". This is the value for a Secret-Key Packet, as shown in the list of [Packet Tags](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#name-packet-tags).
|
||
- `length: 0x4b`: The remaining length of this packet.
|
||
|
||
The packet tag defines the semantics of the remaining data in the packet. We're looking at a Secret-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 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`: "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 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 the Ed25519 public key
|
||
|
||
This concludes the Public Key section of the packet. The remaining data follows the [Secret-Key Packet Format](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#name-secret-key-packet-formats):
|
||
|
||
- `s2k_usage: 0x00`: [This "S2K usage" value](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#name-secret-key-encryption-s2k-u) specifies that the secret-key data is not encrypted
|
||
- `ed25519_secret`: [Algorithm-specific representation](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#name-algorithm-specific-part-for-ed2) of the secret key data (the format is based on the value of `pk_algo`)
|
||
|
||
[^CTB]: Sequoia uses the term "CTB" (Cipher Type Byte) to refer to the RFC's ["Packet Tag"](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#name-packet-headers)
|
||
|
||
```{tip}
|
||
|
||
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 "Secret-Key" Packet contains both the private and the public part of the key.
|
||
|
||
#### 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.priv-1--Signature` contains this packet).
|
||
|
||
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 algo preferences"* and *"Hash preferences"*).
|
||
|
||
```text
|
||
Signature Packet, new CTB, 2 header bytes + 182 bytes
|
||
Version: 6
|
||
Type: DirectKey
|
||
Pk algo: Ed25519
|
||
Hash algo: SHA512
|
||
Hashed area:
|
||
Signature creation time: 2023-09-29 15:17:58 UTC (critical)
|
||
Key expiration time: P1095DT62781S (critical)
|
||
Symmetric algo preferences: AES256, AES128
|
||
Hash preferences: SHA512, SHA256
|
||
Key flags: C (critical)
|
||
Features: MDC
|
||
Issuer Fingerprint: AAA18CBB254685C58358320563FD37B67F3300F9FB0EC457378CD29F102698B3
|
||
Unhashed area:
|
||
Issuer: AAA18CBB254685C5
|
||
Digest prefix: 6747
|
||
Level: 0 (signature over data)
|
||
|
||
00000000 c2 CTB
|
||
00000001 b6 length
|
||
00000002 06 version
|
||
00000003 1f type
|
||
00000004 1b pk_algo
|
||
00000005 0a hash_algo
|
||
00000006 00 00 00 3d hashed_area_len
|
||
0000000a 05 subpacket length
|
||
0000000b 82 subpacket tag
|
||
0000000c 65 16 ea a6 sig creation time
|
||
00000010 05 subpacket length
|
||
00000011 89 subpacket tag
|
||
00000012 05 a4 8f bd key expiry time
|
||
00000016 03 subpacket length
|
||
00000017 0b subpacket tag
|
||
00000018 09 07 pref sym algos
|
||
0000001a 03 subpacket length
|
||
0000001b 15 subpacket tag
|
||
0000001c 0a 08 pref hash algos
|
||
0000001e 02 subpacket length
|
||
0000001f 9b subpacket tag
|
||
00000020 01 key flags
|
||
00000021 02 subpacket length
|
||
00000022 1e subpacket tag
|
||
00000023 01 features
|
||
00000024 22 subpacket length
|
||
00000025 21 subpacket tag
|
||
00000026 06 version
|
||
00000027 aa a1 8c bb 25 46 85 c5 83 issuer fp
|
||
00000030 58 32 05 63 fd 37 b6 7f 33 00 f9 fb 0e c4 57 37
|
||
00000040 8c d2 9f 10 26 98 b3
|
||
00000047 00 00 00 0a unhashed_area_len
|
||
0000004b 09 subpacket length
|
||
0000004c 10 subpacket tag
|
||
0000004d aa a1 8c issuer
|
||
00000050 bb 25 46 85 c5
|
||
00000055 67 digest_prefix1
|
||
00000056 47 digest_prefix2
|
||
00000057 20 salt_len
|
||
00000058 a2 e3 63 81 e3 6b d0 4f salt
|
||
00000060 56 d7 c8 38 80 02 25 e8 53 39 49 6b 90 c6 0d 76
|
||
00000070 8f 44 b4 ec 4c 42 38 8e
|
||
00000078 4d 3d 10 c2 ad 29 c0 57 ed25519_sig
|
||
00000080 ce 66 01 73 b3 78 81 9e 89 52 cf 43 8d 28 11 a9
|
||
00000090 77 09 7f cb f8 15 c8 a1 8d ac 20 44 2b 2d de 13
|
||
000000a0 00 41 32 d0 10 3c 69 06 53 3c 49 8c 76 23 82 33
|
||
000000b0 54 01 f9 5f 81 41 90 0e
|
||
```
|
||
|
||
Let’s look at the packet field by field:
|
||
|
||
- `CTB: 0xc2`: The Packet Tag 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 Tag’s value: “2”. This is the value for a Signature Packet.
|
||
- `length: 0xb6`: The remaining length of this packet.
|
||
|
||
The packet tag defines the semantics of the remaining data in the packet. We're looking at a [Signature Packet](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#signature-packet), so the following data is interpreted accordingly.
|
||
|
||
- `version: 0x06`: This is a version 6 signature (some of the following packet format is specific to this signature version).
|
||
- `type: 0x1f`: The [Signature Type](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#name-signature-types)
|
||
- `pk_algo: 0x1b`: Public-key algorithm (decimal 27 corresponds, to [Ed25519](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#name-public-key-algorithms))
|
||
- `hash_algo: 0x0a`: Hash algorithm (decimal 10, corresponds to [SHA2-512](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#name-hash-algorithms))
|
||
- `hashed_area_len: 0x0000003d`: Length of the following hashed subpacket data
|
||
|
||
The next part of this packet contains "hashed subpacket data." A "subpacket data set" in an OpenPGP Signature contains a list of zero or more "Signature subpackets."
|
||
|
||
There are two sets of "subpacket data" in a Signature: "hashed," and "unhashed." The difference is that the hashed subpackets are protected by the digital signature of this packet, while the unhashed subpackets are not.
|
||
|
||
The following subpacket data consists of sets of "subpacket length, subpacket tag, data." We'll show the information for each subpacket 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 tag). Note that bit 7 of the subpacket tag 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].
|
||
|
||
[^critical]: "Critical" here means: the receiver must be able to interpret the subpacket and is expected to fail, otherwise. non-critical subpackets may be ignored by the receiver
|
||
|
||
- [Signature Creation Time](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#signature-creation-subpacket) (subpacket type 2) *critical*: `0x6516eaa6`
|
||
- [Key Expiration Time](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#key-expiration-subpacket) (subpacket type 9) *critical*: `0x05a48fbd`
|
||
- [Preferred Symmetric Ciphers for v1 SEIPD](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#preferred-v1-seipd) (type 11): `0x09 0x07`. (These values [correspond to](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#symmetric-algos): "AES with 256-bit key" and "AES with 128-bit key")
|
||
- [Preferred Hash Algorithms](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#preferred-hashes-subpacket) (subpacket type 21): `0x0a 0x08`. (These values [correspond to](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#name-hash-algorithms): "SHA2-512" and "SHA2-256")
|
||
- [Key Flags](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#key-flags) (subpacket type 27) *critical*: `0x01`. (This value [corresponds](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#name-key-flags) to the "certifications" key flag)
|
||
- [Features](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#features-subpacket) (subpacket type 30): `0x01`. (This value [corresponds](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#name-features) to: "Symmetrically Encrypted Integrity Protected Data packet version 1")
|
||
- [Issuer Fingerprint](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#issuer-fingerprint-subpacket) (subpacket type 33): `aaa18cbb254685c58358320563fd37b67f3300f9fb0ec457378cd29f102698b3` (this is the fingerprint of the component key that issued the signature in this packet. Not that here, the value is the primary key fingerprint of the certificate we're looking at.)
|
||
|
||
The next part of this packet contains "unhashed subpacket data":
|
||
|
||
- `unhashed_area_len: 0x0000000a`: Length of the following unhashed subpacket data.
|
||
|
||
As above, the following subpacket data consists of sets of "length, tag, data." In this case, only subpacket follows:
|
||
|
||
- [Issuer Key ID](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#issuer-keyid-subpacket) (subpacket type 16): `aaa18cbb254685c5` (this is the shortened version 6 "Key ID" of the fingerprint of this certificate's primary key)
|
||
|
||
This concludes the unhashed subpacket data.
|
||
|
||
- `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) (the size must be [matching for 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 (in this case: 64 bytes of Ed25519 signature)
|
||
|
||
```{figure} diag/key-minimal.png
|
||
:width: 40%
|
||
|
||
A minimal OpenPGP key, visualized
|
||
```
|
||
|
||
### Seen as an OpenPGP certificate
|
||
|
||
Let's now look at a "public key" view of the (very minimal) OpenPGP key above. That is, the same data, but without the private key material parts.
|
||
|
||
An OpenPGP user might give such a certificate to a communication partner, or upload it to a key server:
|
||
|
||
```text
|
||
$ sq key extract-cert alice_minimal.priv
|
||
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||
Comment: AAA1 8CBB 2546 85C5 8358 3205 63FD 37B6 7F33 00F9 FB0E C457 378C D29F 1026 98B3
|
||
|
||
xioGZRbqphsAAAAgUyTpQ6+rFfdu1bUSmHlpzRtdEGXr50Liq0f0hrOuZT7CtgYf
|
||
GwoAAAA9BYJlFuqmBYkFpI+9AwsJBwMVCggCmwECHgEiIQaqoYy7JUaFxYNYMgVj
|
||
/Te2fzMA+fsOxFc3jNKfECaYswAAAAoJEKqhjLslRoXFZ0cgouNjgeNr0E9W18g4
|
||
gAIl6FM5SWuQxg12j0S07ExCOI5NPRDCrSnAV85mAXOzeIGeiVLPQ40oEal3CX/L
|
||
+BXIoY2sIEQrLd4TAEEy0BA8aQZTPEmMdiOCM1QB+V+BQZAO
|
||
=5nyq
|
||
-----END PGP PUBLIC KEY BLOCK-----
|
||
```
|
||
|
||
```text
|
||
$ sq packet dump --hex alice_minimal.pub
|
||
```
|
||
|
||
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):
|
||
|
||
```text
|
||
Public-Key Packet, new CTB, 2 header bytes + 42 bytes
|
||
Version: 6
|
||
Creation time: 2023-09-29 15:17:58 UTC
|
||
Pk algo: Ed25519
|
||
Pk size: 256 bits
|
||
Fingerprint: AAA18CBB254685C58358320563FD37B67F3300F9FB0EC457378CD29F102698B3
|
||
KeyID: AAA18CBB254685C5
|
||
|
||
00000000 c6 CTB
|
||
00000001 2a length
|
||
00000002 06 version
|
||
00000003 65 16 ea a6 creation_time
|
||
00000007 1b pk_algo
|
||
00000008 00 00 00 20 public_len
|
||
0000000c 53 24 e9 43 ed25519_public
|
||
00000010 af ab 15 f7 6e d5 b5 12 98 79 69 cd 1b 5d 10 65
|
||
00000020 eb e7 42 e2 ab 47 f4 86 b3 ae 65 3e
|
||
```
|
||
|
||
Note that the packet is almost identical to the Secret Key Packet seen above.
|
||
|
||
The packet tag (called `CTB` in the output) has changed to the packet type ["Public-Key Packet"](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#name-public-key-packet-tag-6) instead of "Secret-Key Packet."
|
||
|
||
The two packet types are very similar. Compared to the "Secret-Key Packet" packet shown above, this "Public-Key Packet" just leaves out the last section, which contained the private-key related fields `s2k_usage` and `ed25519_secret`.
|
||
|
||
The second packet in the certificate (the Direct Key Signature) is bit-for-bit identical as in the previous section. So we omit showing it again, here.
|
||
|
||
```{figure} diag/pubcert-minimal.png
|
||
:width: 40%
|
||
|
||
A minimal OpenPGP public certificate, visualized
|
||
```
|
||
|
||
In the following examples, we will only look at OpenPGP keys that include the private key material. The corresponding "certificate" variants, which only contain the public key material, are easy to imagine: like here, they just leave out the private key material.
|
||
|
||
### Subkeys
|
||
|
||
```{admonition} TODO
|
||
:class: warning
|
||
|
||
The following text is unfinished and still needs processing/writing.
|
||
|
||
**This point marks the end of the material that should be read/edited.**
|
||
```
|
||
|
||
From here on, we'll look at the dumps in shorter format (you can see more detail by copying the certificates into the ["Sequoia OpenPGP Packet dumper"](https://dump.sequoia-pgp.org/) and checking the "HexDump" checkbox).
|
||
|
||
### User IDs
|
||
|
||
User IDs are a mechanism for attaching *identities* to an OpenPGP certificate. Typically, a User ID will contain a name and an email address.
|
||
|
||
To look into these, we'll make a certificate that has one [User ID](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#uid). User IDs are *"intended to represent the name and email address of the key holder"*. A certificate can have multiple User IDs associated with it.
|
||
|
||
Let's look into the details of this key:
|
||
|
||
```text
|
||
-----BEGIN PGP PRIVATE KEY BLOCK-----
|
||
Comment: AAA1 8CBB 2546 85C5 8358 3205 63FD 37B6 7F33 00F9 FB0E C457 378C D29F 1026 98B3
|
||
Comment: <alice@example.org>
|
||
|
||
xUsGZRbqphsAAAAgUyTpQ6+rFfdu1bUSmHlpzRtdEGXr50Liq0f0hrOuZT4A7+GZ
|
||
tV8R+6qT6CadO7ItciB9/71C3UvpozaBO6XMz/vCtgYfGwoAAAA9BYJlFuqmBYkF
|
||
pI+9AwsJBwMVCggCmwECHgEiIQaqoYy7JUaFxYNYMgVj/Te2fzMA+fsOxFc3jNKf
|
||
ECaYswAAAAoJEKqhjLslRoXFZ0cgouNjgeNr0E9W18g4gAIl6FM5SWuQxg12j0S0
|
||
7ExCOI5NPRDCrSnAV85mAXOzeIGeiVLPQ40oEal3CX/L+BXIoY2sIEQrLd4TAEEy
|
||
0BA8aQZTPEmMdiOCM1QB+V+BQZAOzRM8YWxpY2VAZXhhbXBsZS5vcmc+wrkGExsK
|
||
AAAAQAWCZRbqpgWJBaSPvQMLCQcDFQoIApkBApsBAh4BIiEGqqGMuyVGhcWDWDIF
|
||
Y/03tn8zAPn7DsRXN4zSnxAmmLMAAAAKCRCqoYy7JUaFxdu4IIotb9pnNbxdBHe0
|
||
nWeobsXWiFNf4u/5Zgi/wuDbwFYN69QspRkBD7om0IKiz1zreqly2fOyZgeLsro9
|
||
t4nkdgRuNSQrJymDvpGceGrMtNVpR3YsKdZUv0MZBP9TmMDVCw==
|
||
=bgQM
|
||
-----END PGP PRIVATE KEY BLOCK-----
|
||
```
|
||
|
||
```text
|
||
$ sq packet dump --hex alice_userid.priv
|
||
Secret-Key Packet, new CTB, 2 header bytes + 75 bytes
|
||
Version: 6
|
||
Creation time: 2023-09-29 15:17:58 UTC
|
||
Pk algo: Ed25519
|
||
Pk size: 256 bits
|
||
Fingerprint: AAA18CBB254685C58358320563FD37B67F3300F9FB0EC457378CD29F102698B3
|
||
KeyID: AAA18CBB254685C5
|
||
|
||
Secret Key:
|
||
|
||
Unencrypted
|
||
|
||
00000000 c5 CTB
|
||
00000001 4b length
|
||
00000002 06 version
|
||
00000003 65 16 ea a6 creation_time
|
||
00000007 1b pk_algo
|
||
00000008 00 00 00 20 public_len
|
||
0000000c 53 24 e9 43 ed25519_public
|
||
00000010 af ab 15 f7 6e d5 b5 12 98 79 69 cd 1b 5d 10 65
|
||
00000020 eb e7 42 e2 ab 47 f4 86 b3 ae 65 3e
|
||
0000002c 00 s2k_usage
|
||
0000002d ef e1 99 ed25519_secret
|
||
00000030 b5 5f 11 fb aa 93 e8 26 9d 3b b2 2d 72 20 7d ff
|
||
00000040 bd 42 dd 4b e9 a3 36 81 3b a5 cc cf fb
|
||
|
||
Signature Packet, new CTB, 2 header bytes + 182 bytes
|
||
Version: 6
|
||
Type: DirectKey
|
||
Pk algo: Ed25519
|
||
Hash algo: SHA512
|
||
Hashed area:
|
||
Signature creation time: 2023-09-29 15:17:58 UTC (critical)
|
||
Key expiration time: P1095DT62781S (critical)
|
||
Symmetric algo preferences: AES256, AES128
|
||
Hash preferences: SHA512, SHA256
|
||
Key flags: C (critical)
|
||
Features: MDC
|
||
Issuer Fingerprint: AAA18CBB254685C58358320563FD37B67F3300F9FB0EC457378CD29F102698B3
|
||
Unhashed area:
|
||
Issuer: AAA18CBB254685C5
|
||
Digest prefix: 6747
|
||
Level: 0 (signature over data)
|
||
|
||
00000000 c2 CTB
|
||
00000001 b6 length
|
||
00000002 06 version
|
||
00000003 1f type
|
||
00000004 1b pk_algo
|
||
00000005 0a hash_algo
|
||
00000006 00 00 00 3d hashed_area_len
|
||
0000000a 05 subpacket length
|
||
0000000b 82 subpacket tag
|
||
0000000c 65 16 ea a6 sig creation time
|
||
00000010 05 subpacket length
|
||
00000011 89 subpacket tag
|
||
00000012 05 a4 8f bd key expiry time
|
||
00000016 03 subpacket length
|
||
00000017 0b subpacket tag
|
||
00000018 09 07 pref sym algos
|
||
0000001a 03 subpacket length
|
||
0000001b 15 subpacket tag
|
||
0000001c 0a 08 pref hash algos
|
||
0000001e 02 subpacket length
|
||
0000001f 9b subpacket tag
|
||
00000020 01 key flags
|
||
00000021 02 subpacket length
|
||
00000022 1e subpacket tag
|
||
00000023 01 features
|
||
00000024 22 subpacket length
|
||
00000025 21 subpacket tag
|
||
00000026 06 version
|
||
00000027 aa a1 8c bb 25 46 85 c5 83 issuer fp
|
||
00000030 58 32 05 63 fd 37 b6 7f 33 00 f9 fb 0e c4 57 37
|
||
00000040 8c d2 9f 10 26 98 b3
|
||
00000047 00 00 00 0a unhashed_area_len
|
||
0000004b 09 subpacket length
|
||
0000004c 10 subpacket tag
|
||
0000004d aa a1 8c issuer
|
||
00000050 bb 25 46 85 c5
|
||
00000055 67 digest_prefix1
|
||
00000056 47 digest_prefix2
|
||
00000057 20 salt_len
|
||
00000058 a2 e3 63 81 e3 6b d0 4f salt
|
||
00000060 56 d7 c8 38 80 02 25 e8 53 39 49 6b 90 c6 0d 76
|
||
00000070 8f 44 b4 ec 4c 42 38 8e
|
||
00000078 4d 3d 10 c2 ad 29 c0 57 ed25519_sig
|
||
00000080 ce 66 01 73 b3 78 81 9e 89 52 cf 43 8d 28 11 a9
|
||
00000090 77 09 7f cb f8 15 c8 a1 8d ac 20 44 2b 2d de 13
|
||
000000a0 00 41 32 d0 10 3c 69 06 53 3c 49 8c 76 23 82 33
|
||
000000b0 54 01 f9 5f 81 41 90 0e
|
||
|
||
User ID Packet, new CTB, 2 header bytes + 19 bytes
|
||
Value: <alice@example.org>
|
||
|
||
00000000 cd CTB
|
||
00000001 13 length
|
||
00000002 3c 61 6c 69 63 65 40 65 78 61 6d 70 6c 65 value
|
||
00000010 2e 6f 72 67 3e
|
||
|
||
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)
|
||
Key expiration time: P1095DT62781S (critical)
|
||
Symmetric algo preferences: AES256, AES128
|
||
Hash preferences: SHA512, SHA256
|
||
Primary User ID: true (critical)
|
||
Key flags: C (critical)
|
||
Features: MDC
|
||
Issuer Fingerprint: AAA18CBB254685C58358320563FD37B67F3300F9FB0EC457378CD29F102698B3
|
||
Unhashed area:
|
||
Issuer: AAA18CBB254685C5
|
||
Digest prefix: DBB8
|
||
Level: 0 (signature over data)
|
||
|
||
00000000 c2 CTB
|
||
00000001 b9 length
|
||
00000002 06 version
|
||
00000003 13 type
|
||
00000004 1b pk_algo
|
||
00000005 0a hash_algo
|
||
00000006 00 00 00 40 hashed_area_len
|
||
0000000a 05 subpacket length
|
||
0000000b 82 subpacket tag
|
||
0000000c 65 16 ea a6 sig creation time
|
||
00000010 05 subpacket length
|
||
00000011 89 subpacket tag
|
||
00000012 05 a4 8f bd key expiry time
|
||
00000016 03 subpacket length
|
||
00000017 0b subpacket tag
|
||
00000018 09 07 pref sym algos
|
||
0000001a 03 subpacket length
|
||
0000001b 15 subpacket tag
|
||
0000001c 0a 08 pref hash algos
|
||
0000001e 02 subpacket length
|
||
0000001f 99 subpacket tag
|
||
00000020 01 primary user id
|
||
00000021 02 subpacket length
|
||
00000022 9b subpacket tag
|
||
00000023 01 key flags
|
||
00000024 02 subpacket length
|
||
00000025 1e subpacket tag
|
||
00000026 01 features
|
||
00000027 22 subpacket length
|
||
00000028 21 subpacket tag
|
||
00000029 06 version
|
||
0000002a aa a1 8c bb 25 46 issuer fp
|
||
00000030 85 c5 83 58 32 05 63 fd 37 b6 7f 33 00 f9 fb 0e
|
||
00000040 c4 57 37 8c d2 9f 10 26 98 b3
|
||
0000004a 00 00 00 0a unhashed_area_len
|
||
0000004e 09 subpacket length
|
||
0000004f 10 subpacket tag
|
||
00000050 aa a1 8c bb 25 46 85 c5 issuer
|
||
00000058 db digest_prefix1
|
||
00000059 b8 digest_prefix2
|
||
0000005a 20 salt_len
|
||
0000005b 8a 2d 6f da 67 salt
|
||
00000060 35 bc 5d 04 77 b4 9d 67 a8 6e c5 d6 88 53 5f e2
|
||
00000070 ef f9 66 08 bf c2 e0 db c0 56 0d
|
||
0000007b eb d4 2c a5 19 ed25519_sig
|
||
00000080 01 0f ba 26 d0 82 a2 cf 5c eb 7a a9 72 d9 f3 b2
|
||
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
|
||
```
|
||
|
||
Instead of two packets, as before, we see four packets in this certificate:
|
||
|
||
* First, a "Secret-Key Packet,"
|
||
* then a "Signature Packet" (these two packets are the same as above).
|
||
* Third, a [*"User ID Packet"*](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#uid), which contains the name and email address we used
|
||
* Finally, a [*"Positive Certification Signature"*](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#sigtype-positive-cert) (type 0x13), *"Positive certification of a User ID and Public-Key packet"*. This is a cryptographic artifact that "binds the User ID packet and the Key packet together", i.e. it certifies that the owner of the key wants this User ID associated with their key. (Only the person who controls the private part of this key can create this signature packet. The signature serves as proof that the owner of the key has added this User ID to the certificate)
|
||
|
||
|
||
### Certifications (Third Party Signatures)
|
||
|
||
### Revocations
|