sequoia_openpgp/packet/container.rs
1//! Packet container support.
2//!
3//! Some packets contain other packets. This creates a tree
4//! structure.
5
6use std::fmt;
7use std::hash::{Hash, Hasher};
8use std::slice;
9use std::vec;
10
11use xxhash_rust::xxh3::Xxh3;
12
13use crate::{
14 Packet,
15 packet::{
16 Iter,
17 SEIP,
18 },
19};
20
21/// A packet's body holds either unprocessed bytes, processed bytes,
22/// or packets.
23///
24/// We conceptually divide packets into two parts: the header and the
25/// body. Whereas the header is read eagerly when the packet is
26/// deserialized, the body is only read on demand.
27///
28/// A packet's body is stored here either when configured via
29/// [`PacketParserBuilder::buffer_unread_content`], when one of the
30/// [`PacketPile`] deserialization routines is used, or on demand for
31/// a particular packet using the
32/// [`PacketParser::buffer_unread_content`] method.
33///
34/// [`PacketParserBuilder::buffer_unread_content`]: crate::parse::PacketParserBuilder::buffer_unread_content()
35/// [`PacketPile`]: crate::PacketPile
36/// [`PacketParser::buffer_unread_content`]: crate::parse::PacketParser::buffer_unread_content()
37///
38/// There are three different types of packets:
39///
40/// - Most packets, like the [`UserID`] and [`Signature`] packets, don't
41/// actually have a body.
42///
43/// [`UserID`]: crate::packet::UserID
44/// [`Signature`]: crate::packet::Signature
45///
46/// - Some packets have an unprocessed body. The [`Literal`] data
47/// packet wraps unstructured plaintext, and the [`Unknown`]
48/// packet contains data that we failed to process, say because we
49/// didn't support the packet's version.
50///
51/// [`Literal`]: crate::packet::Literal
52/// [`Unknown`]: crate::packet::Unknown
53///
54/// - Some packets are containers. If the parser does not parse the
55/// packet's child, either because the caller used
56/// [`PacketParser::next`] to get the next packet, or the maximum
57/// recursion depth was reached, then the packets can be stored
58/// here as an unstructured byte stream. (If the caller so
59/// chooses, the content can be parsed later using the regular
60/// deserialization routines, since the content is just an OpenPGP
61/// message.)
62///
63/// [`PacketParser::next`]: crate::parse::PacketParser::next()
64#[derive(Clone, Debug)]
65pub enum Body {
66 /// Unprocessed packet body.
67 ///
68 /// The body has not been processed. This happens in the
69 /// following cases:
70 ///
71 /// - The packet is a [`Literal`] packet.
72 ///
73 /// - The packet is an [`Unknown`] packet, i.e. it contains data
74 /// that we failed to process, say because we didn't support
75 /// the packet's version.
76 ///
77 /// - The packet is an encryption container ([`SEIP`]) and the
78 /// body is encrypted.
79 ///
80 /// Note: if some of a packet's data is streamed, and the
81 /// `PacketParser` is configured to buffer unread content, then
82 /// this is not the packet's entire content; it is just the unread
83 /// content.
84 ///
85 /// [`Literal`]: crate::packet::Literal
86 /// [`Unknown`]: crate::packet::Unknown
87 /// [`SEIP`]: crate::packet::SEIP
88 Unprocessed(Vec<u8>),
89
90 /// Processed packed body.
91 ///
92 /// The body has been processed, i.e. decompressed or decrypted,
93 /// but not parsed into packets.
94 ///
95 /// Note: if some of a packet's data is streamed, and the
96 /// `PacketParser` is configured to buffer unread content, then
97 /// this is not the packet's entire content; it is just the unread
98 /// content.
99 Processed(Vec<u8>),
100
101 /// Parsed packet body.
102 ///
103 /// Used by container packets (such as the encryption and
104 /// compression packets) to reference their immediate children.
105 /// This results in a tree structure.
106 ///
107 /// This is automatically populated when using the [`PacketPile`]
108 /// deserialization routines, e.g., [`PacketPile::from_file`]. By
109 /// default, it is *not* automatically filled in by the
110 /// [`PacketParser`] deserialization routines; this needs to be
111 /// done manually.
112 ///
113 /// [`PacketPile`]: crate::PacketPile
114 /// [`PacketPile::from_file`]: crate::PacketPile#method.from_file
115 /// [`PacketParser`]: crate::parse::PacketParser
116 Structured(Vec<Packet>),
117}
118
119assert_send_and_sync!(Body);
120
121/// Holds packet bodies.
122///
123/// This is used by OpenPGP container packets, like the compressed
124/// data packet, to store the containing packets.
125#[derive(Clone)]
126pub struct Container {
127 /// Holds a packet's body.
128 body: Body,
129
130 /// We compute a digest over the body to implement comparison.
131 body_digest: u64,
132}
133
134assert_send_and_sync!(Container);
135
136impl PartialEq for Container {
137 fn eq(&self, other: &Container) -> bool {
138 use Body::*;
139 match (&self.body, &other.body) {
140 (Unprocessed(_), Unprocessed(_)) =>
141 self.body_digest == other.body_digest,
142 (Processed(_), Processed(_)) =>
143 self.body_digest == other.body_digest,
144 (Structured(a), Structured(b)) =>
145 a == b,
146 _ => false,
147 }
148 }
149}
150
151impl Eq for Container {}
152
153impl Hash for Container {
154 fn hash<H: Hasher>(&self, state: &mut H) {
155 if let Body::Structured(packets) = &self.body {
156 packets.hash(state);
157 } else {
158 self.body_digest.hash(state);
159 }
160 }
161}
162
163impl Default for Container {
164 fn default() -> Self {
165 Self {
166 body: Body::Structured(Vec::with_capacity(0)),
167 body_digest: 0,
168 }
169 }
170}
171
172impl From<Vec<Packet>> for Container {
173 fn from(packets: Vec<Packet>) -> Self {
174 Self {
175 body: Body::Structured(packets),
176 body_digest: 0,
177 }
178 }
179}
180
181impl fmt::Debug for Container {
182 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
183 fn fmt_bytes(f: &mut fmt::Formatter, tag: &str, bytes: &[u8],
184 digest: String)
185 -> fmt::Result
186 {
187 let threshold = 16;
188 let prefix = &bytes[..std::cmp::min(threshold, bytes.len())];
189 let mut prefix_fmt = crate::fmt::hex::encode(prefix);
190 if bytes.len() > threshold {
191 prefix_fmt.push_str("...");
192 }
193 prefix_fmt.push_str(&format!(" ({} bytes)", bytes.len())[..]);
194
195 f.debug_struct("Container")
196 .field(tag, &prefix_fmt)
197 .field("digest", &digest)
198 .finish()
199 }
200
201 use Body::*;
202 match &self.body {
203 Unprocessed(bytes) =>
204 fmt_bytes(f, "unprocessed", bytes, self.body_digest()),
205 Processed(bytes) =>
206 fmt_bytes(f, "processed", bytes, self.body_digest()),
207 Structured(packets) =>
208 f.debug_struct("Container").field("packets", packets).finish(),
209 }
210 }
211}
212
213impl Container {
214 pub(crate) fn default_unprocessed() -> Self {
215 Self {
216 body: Body::Unprocessed(Vec::with_capacity(0)),
217 body_digest: Self::empty_body_digest(),
218 }
219 }
220
221 /// Returns a reference to this Packet's children.
222 ///
223 /// Returns `None` if the body is not structured.
224 pub fn children_ref(&self) -> Option<&[Packet]> {
225 if let Body::Structured(packets) = &self.body {
226 Some(&packets[..])
227 } else {
228 None
229 }
230 }
231
232 /// Returns a mutable reference to this Packet's children.
233 ///
234 /// Returns `None` if the body is not structured.
235 pub fn children_mut(&mut self) -> Option<&mut Vec<Packet>> {
236 if let Body::Structured(packets) = &mut self.body {
237 Some(packets)
238 } else {
239 None
240 }
241 }
242
243 /// Returns an iterator over the packet's descendants. The
244 /// descendants are visited in depth-first order.
245 ///
246 /// Returns `None` if the body is not structured.
247 pub fn descendants(&self) -> Option<Iter> {
248 Some(Iter {
249 // Iterate over each packet in the message.
250 children: self.children()?,
251 child: None,
252 grandchildren: None,
253 depth: 0,
254 })
255 }
256
257 /// Returns an iterator over the packet's immediate children.
258 ///
259 /// Returns `None` if the body is not structured.
260 pub fn children(&self) -> Option<slice::Iter<Packet>> {
261 Some(self.children_ref()?.iter())
262 }
263
264 /// Returns an `IntoIter` over the packet's immediate children.
265 ///
266 /// Returns `None` if the body is not structured.
267 pub fn into_children(self) -> Option<vec::IntoIter<Packet>> {
268 if let Body::Structured(packets) = self.body {
269 Some(packets.into_iter())
270 } else {
271 None
272 }
273 }
274
275 /// Gets the packet's body.
276 pub fn body(&self) -> &Body {
277 &self.body
278 }
279
280 /// Sets the packet's body.
281 pub fn set_body(&mut self, body: Body) -> Body {
282 use Body::*;
283 let mut h = Self::make_body_hash();
284 match &body {
285 Unprocessed(bytes) => h.update(bytes),
286 Processed(bytes) => h.update(bytes),
287 Structured(_) => (),
288 }
289 self.set_body_hash(h);
290 std::mem::replace(&mut self.body, body)
291 }
292
293 /// Returns the hash for the empty body.
294 fn empty_body_digest() -> u64 {
295 use std::sync::OnceLock;
296 static DIGEST: OnceLock<u64> = OnceLock::new();
297 *DIGEST.get_or_init(|| Container::make_body_hash().digest())
298 }
299
300 /// Creates a hash context for hashing the body.
301 pub(crate) // For parse.rs
302 fn make_body_hash() -> Box<Xxh3> {
303 Box::new(Xxh3::new())
304 }
305
306 /// Hashes content that has been streamed.
307 pub(crate) // For parse.rs
308 fn set_body_hash(&mut self, h: Box<Xxh3>) {
309 self.body_digest = h.digest();
310 }
311
312 pub(crate)
313 fn body_digest(&self) -> String {
314 format!("{:08X}", self.body_digest)
315 }
316
317 /// Converts an indentation level to whitespace.
318 #[cfg(test)]
319 fn indent(depth: usize) -> &'static str {
320 use std::cmp;
321
322 let s = " ";
323 &s[0..cmp::min(depth, s.len())]
324 }
325
326 /// Pretty prints the container to stderr.
327 ///
328 /// This function is primarily intended for debugging purposes.
329 ///
330 /// `indent` is the number of spaces to indent the output.
331 #[cfg(test)]
332 pub(crate) fn pretty_print(&self, indent: usize) {
333 for (i, p) in self.children_ref().iter().enumerate() {
334 eprintln!("{}{}: {:?}",
335 Self::indent(indent), i + 1, p);
336 if let Some(children) = self.children_ref()
337 .and_then(|c| c.get(i)).and_then(|p| p.container_ref())
338 {
339 children.pretty_print(indent + 1);
340 }
341 }
342 }
343}
344
345macro_rules! impl_unprocessed_body_forwards {
346 ($typ:ident) => {
347 /// This packet implements the unprocessed container
348 /// interface.
349 ///
350 /// Container packets like this one can contain unprocessed
351 /// data.
352 impl $typ {
353 /// Returns a reference to the container.
354 pub(crate) fn container_ref(&self) -> &packet::Container {
355 &self.container
356 }
357
358 /// Returns a mutable reference to the container.
359 pub(crate) fn container_mut(&mut self) -> &mut packet::Container {
360 &mut self.container
361 }
362
363 /// Gets a reference to the this packet's body.
364 pub fn body(&self) -> &[u8] {
365 use crate::packet::Body::*;
366 match self.container.body() {
367 Unprocessed(bytes) => bytes,
368 Processed(_) => unreachable!(
369 "Unprocessed container has processed body"),
370 Structured(_) => unreachable!(
371 "Unprocessed container has structured body"),
372 }
373 }
374
375 /// Sets the this packet's body.
376 pub fn set_body(&mut self, data: Vec<u8>) -> Vec<u8> {
377 use crate::packet::{Body, Body::*};
378 match self.container.set_body(Body::Unprocessed(data)) {
379 Unprocessed(bytes) => bytes,
380 Processed(_) => unreachable!(
381 "Unprocessed container has processed body"),
382 Structured(_) => unreachable!(
383 "Unprocessed container has structured body"),
384 }
385 }
386 }
387 };
388}
389
390macro_rules! impl_processed_body_forwards {
391 ($typ:ident) => {
392 /// This packet implements the processed container
393 /// interface.
394 ///
395 /// Container packets like this one can contain either
396 /// unprocessed or processed, structured data.
397 impl $typ {
398 /// Returns a reference to the container.
399 pub fn container_ref(&self) -> &packet::Container {
400 &self.container
401 }
402
403 /// Returns a mutable reference to the container.
404 pub fn container_mut(&mut self) -> &mut packet::Container {
405 &mut self.container
406 }
407
408 /// Gets a reference to the this packet's body.
409 pub fn body(&self) -> &crate::packet::Body {
410 self.container_ref().body()
411 }
412
413 /// Sets the this packet's body.
414 pub fn set_body(&mut self, body: crate::packet::Body)
415 -> crate::packet::Body {
416 self.container_mut().set_body(body)
417 }
418 }
419 };
420}
421
422impl Packet {
423 pub(crate) // for packet_pile.rs
424 fn container_ref(&self) -> Option<&Container> {
425 match self {
426 Packet::CompressedData(p) => Some(p.container_ref()),
427 Packet::SEIP(SEIP::V1(p)) => Some(p.container_ref()),
428 Packet::SEIP(SEIP::V2(p)) => Some(p.container_ref()),
429 Packet::Literal(p) => Some(p.container_ref()),
430 Packet::Unknown(p) => Some(p.container_ref()),
431 _ => None,
432 }
433 }
434
435 pub(crate) // for packet_pile.rs, packet_pile_parser.rs, parse.rs
436 fn container_mut(&mut self) -> Option<&mut Container> {
437 match self {
438 Packet::CompressedData(p) => Some(p.container_mut()),
439 Packet::SEIP(SEIP::V1(p)) => Some(p.container_mut()),
440 Packet::SEIP(SEIP::V2(p)) => Some(p.container_mut()),
441 Packet::Literal(p) => Some(p.container_mut()),
442 Packet::Unknown(p) => Some(p.container_mut()),
443 _ => None,
444 }
445 }
446
447 /// Returns an iterator over the packet's immediate children.
448 pub(crate) fn children(& self)
449 -> Option<impl Iterator<Item = &Packet>> {
450 self.container_ref().and_then(|c| c.children())
451 }
452
453 /// Returns an iterator over all the packet's descendants, in
454 /// depth-first order.
455 pub(crate) fn descendants(&self) -> Option<Iter> {
456 self.container_ref().and_then(|c| c.descendants())
457 }
458
459 /// Retrieves the packet's unprocessed body.
460 #[cfg(test)]
461 #[allow(dead_code)] // Not used if no compression feature is enabled.
462 pub(crate) fn unprocessed_body(&self) -> Option<&[u8]> {
463 self.container_ref().and_then(|c| match c.body() {
464 Body::Unprocessed(bytes) => Some(&bytes[..]),
465 _ => None,
466 })
467 }
468
469 /// Retrieves the packet's processed body.
470 #[cfg(test)]
471 pub(crate) fn processed_body(&self) -> Option<&[u8]> {
472 self.container_ref().and_then(|c| match c.body() {
473 Body::Processed(bytes) => Some(&bytes[..]),
474 _ => None,
475 })
476 }
477}