[][src]Module sequoia_openpgp::parse

OpenPGP packet parser.

An OpenPGP message is a sequence of packets. Some of the packets contain other packets. These containers include encrypted packets (the SED and SEIP packets), and compressed packets. This structure results in a tree, which is laid out in depth-first order.

There are two major concerns that inform the design of the parsing API.

First, when processing a container, it is possible to either recurse into the container, and process its children, or treat the contents of the container as an opaque byte stream, and process the packet following the container. The low-level PacketParser and mid-level PacketPileParser abstractions allow the caller to choose the behavior by either calling the recurse() method or the next() method, as appropriate. OpenPGP doesn't impose any restrictions on the amount of nesting. So, to prevent a denial of service attack, the parsers doesn't recurse more than MAX_RECURSION_DEPTH times, by default.

Second, packets can contain an effectively unbounded amount of data. To avoid errors due to memory exhaustion, the PacketParser and PacketPileParser abstractions support parsing packets in a streaming manner, i.e., never buffering more than O(1) bytes of data. To do this, the parsers initially only parse a packet's header (which is rarely more than a few kilobytes of data), and return control to the caller. After inspecting that data, the caller can decide how to handle the packet's contents. If the content is deemed interesting, it can be streamed or buffered. Otherwise, it can be dropped. Streaming is possible not only for literal data packets, but also containers (other packets also support the interface, but just return EOF). For instance, encryption can be stripped by saving the decrypted content of an encryption packet, which is just an OpenPGP message.

We explicitly chose to not use a callback-based API, but something that is closer to Rust's iterator API. Unfortunately, because a PacketParser needs mutable access to the input stream (so that the content can be streamed), only a single PacketParser item can be live at a time (without a fair amount of unsafe nastiness). This is incompatible with Rust's iterator concept, which allows any number of items to be live at any time. For instance:

let mut iter = v.iter_mut();

let x = iter.next().unwrap();
let y = iter.next().unwrap();

*x += 10; // This does not cause an error!
*y += 10;

This crate provide three abstractions for parsing OpenPGP messages:

  • The PacketParser abstraction produces one packet at a time. What is done with those packets is completely up to the caller.

  • The PacketPileParser abstraction builds on the PacketParser abstraction and provides a similar interface. However, after each iteration, the PacketPileParser adds the packet to a PacketPile, which is returned once the packets are completely processed.

    This interface should only be used if the caller actually wants a PacketPile; if the OpenPGP message is parsed in place, then using a PacketParser is better.

  • The PacketPile::from_file (and related methods) is the most convenient, but least flexible way to parse a sequence of OpenPGP packets. Whereas a PacketPileParser allows the caller to determine how to handle individual packets, the PacketPile::from_file parses the whole message at once and returns a PacketPile.

    This interface should only be used if the caller is certain that the parsed message will fit in memory.

In all cases, the default behavior can be configured using a PacketParserBuilder.



Packet maps.


Streaming decryption and verification.



A low-level OpenPGP message parser.


A builder for configuring a PacketParser.


Information about the stream of packets parsed by the PacketParser.


A PacketPileParser parses an OpenPGP message with the convenience of PacketPile::from_file and the flexibility of a PacketParser.



The return type of PacketParser::next() and PacketParser::recurse().



Parsing of packets and related structures.