Expand description

Packet-related data types.

OpenPGP data structures are packet based. This module defines the corresponding data structures.

Most users of this library will not need to generate these packets themselves. Instead, the packets are instantiated as a side effect of parsing a message, or creating a message. The main current exception are Signature packets. Working with Signature packets is, however, simplified by using the SignatureBuilder.

Data Types

Many OpenPGP packets include a version field. Versioning is used to make it easier to change the standard. For instance, using versioning, it is possible to remove a field from a packet without introducing a new packet type, which would also require changing the grammar. Versioning also enables a degree of forward compatibility when a new version of a packet can be safely ignored. For instance, there are currently two versions of the Signature packet with completely different layouts: v3 and v4. An implementation that does not understand the latest version of the packet can still parse and display a message using them; it will just be unable to verify that signature.

In Sequoia, packets that have a version field are represented by enums, and each supported version of the packet has a variant, and a corresponding struct. This is the case even when only one version of the packet is currently defined, as is the case with the OnePassSig packet. The enums implement forwarders for common operations. As such, users of this library can often ignore that there are multiple versions of a given packet.

Unknown Packets

Sequoia gracefully handles unsupported packets by storing them as Unknown packets. There are several types of unknown packets:

  • Packets that are known, but explicitly not supported.

    The two major examples are the SED packet type and v3 Signature packets, which have both been considered insecure for well over a decade.

    Note: future versions of Sequoia may add limited support for these packets to enable parsing archived messages.

  • Packets that are known about, but that use unsupported options, e.g., a Compressed Data packet using an unknown or unsupported algorithm.

  • Packets that are unknown, e.g., future or private extensions.

When Sequoia parses a message containing these packets, it doesn’t fail. Instead, Sequoia stores them in the Unknown data structure. This allows applications to not only continue to process such messages (albeit with degraded performance), but to losslessly reserialize the messages, should that be required.


Packets can be divided into two categories: containers and non-containers. A container is a packet that contains other OpenPGP packets. For instance, by definition, a Compressed Data packet contains an OpenPGP Message. It is possible to iterate over a container’s descendants using the Container::descendants method. (Note: Containers Deref to Container.)

Packet Headers and Bodies

Conceptually, packets have zero or more headers and an optional body. The headers are small, and have a known upper bound. The version field is, for instance, 4 bytes, and although Signature SubpacketArea areas are variable in size, they are limited to 64 KB. In contrast the body, can be unbounded in size.

To limit memory use, and enable streaming processing (i.e., ensuring that processing a message can be done using a fixed size buffer), Sequoia does not require that a packet’s body be present in memory. For instance, the body of a literal data packet may be streamed. And, at the end, a Literal packet is still returned. This allows the caller to examine the message structure, and the message headers in in toto even when streaming. It is even possible to compare two streamed version of a packet: Sequoia stores a hash of the body. See the Body data structure for more details.


There are several reasonable ways to define equality for Packets. Unfortunately, none of them are appropriate in all situations. This makes choosing a general-purpose equality function for Eq difficult.

Consider defining Eq as the equivalence of two Packets’ serialized forms. If an application naively deduplicates signatures, then an attacker can potentially perform a denial of service attack by causing the application to process many cryptographically-valid Signatures by varying the content of one cryptographically-valid Signature’s unhashed area. This attack can be prevented by only comparing data that is protected by the signature. But this means that naively deduplicating Signature packets will return in “a random” variant being used. So, again, an attacker could create variants of a cryptographically-valid Signature to get the implementation to incorrectly drop a useful one.

These issues are also relevant when comparing Keys: should the secret key material be compared? Usually we want to merge the secret key material. But, again, if done naively, the incorrect secret key material may be retained or dropped completely.

Instead of trying to come up with a definition of equality that is reasonable for all situations, we use a conservative definition: two packets are considered equal if the serialized forms of their packet bodies as defined by RFC 4880 are equal. That is, two packets are considered equal if and only if their serialized forms are equal modulo the OpenPGP framing (CTB and length style, potential partial body encoding). This definition will avoid unintentionally dropping information when naively deduplicating packets, but it will result in potential redundancies.

For some packets, we provide additional variants of equality. For instance, Key::public_cmp compares just the public parts of two keys.


pub use self::header::Header;
pub use self::user_attribute::UserAttribute;


AEAD encrypted data packets.

OpenPGP packet headers.

Key-related functionality.

One-pass signature packets.

PublicKey-Encrypted Session Key packets.

Brings the most relevant types and traits into scope for working with packets.

Symmetrically Encrypted Integrity Protected data packets.

Signature-related functionality.

Symmetric-Key Encrypted Session Key Packets.

User Attribute packets and subpackets.


Fields used by multiple packet types.

Holds a compressed data packet.

Holds packet bodies.

An iterator over the contents of a packet in depth-first order.

Holds a literal packet.

Holds an MDC packet.

Holds a Marker packet.

Holds a Trust packet.

Holds an unknown packet.

Holds a UserID packet.


Holds an AEAD encrypted data packet.

A packet’s body holds either unprocessed bytes, processed bytes, or packets.

Holds a public key, public subkey, private key or private subkey packet.

Holds a one-pass signature packet.

Holds an asymmetrically encrypted session key.

Enumeration of packet types.

Holds a SEIP packet.

Holds a symmetrically encrypted session key.

Holds a signature packet.

The OpenPGP packet tags as defined in Section 4.3 of RFC 4880.


Convenient downcasting from Packets to Packet Bodies.