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}