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
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
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
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 v = vec![1, 2, 3, 4]; 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:
PacketParserabstraction produces one packet at a time. What is done with those packets is completely up to the caller.
PacketPileParserabstraction builds on the
PacketParserabstraction and provides a similar interface. However, after each iteration, the
PacketPileParseradds 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
PacketPile::from_file(and related methods) is the most convenient, but least flexible way to parse a sequence of OpenPGP packets. Whereas a
PacketPileParserallows the caller to determine how to handle individual packets, the
PacketPile::from_fileparses the whole message at once and returns a
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
Streaming decryption and verification.
A low-level OpenPGP message parser.
A builder for configuring a
Information about the stream of packets parsed by the
How to decode the input.
The return type of
Parsing of packets and related structures.