sequoia_openpgp/parse/
packet_parser_builder.rs

1use std::io;
2use std::path::Path;
3
4use buffered_reader::BufferedReader;
5
6use crate::Result;
7use crate::parse::PacketParserResult;
8use crate::parse::PacketParser;
9use crate::parse::PacketParserEOF;
10use crate::parse::PacketParserState;
11use crate::parse::PacketParserSettings;
12use crate::parse::ParserResult;
13use crate::parse::Parse;
14use crate::parse::Cookie;
15use crate::armor;
16use crate::packet;
17
18/// Controls transparent stripping of ASCII armor when parsing.
19///
20/// When parsing OpenPGP data streams, the [`PacketParser`] will by
21/// default automatically detect and remove any ASCII armor encoding
22/// (see [Section 6 of RFC 4880]).  This automatism can be disabled
23/// and fine-tuned using [`PacketParserBuilder::dearmor`].
24///
25///   [Section 6 of RFC 4880]: https://tools.ietf.org/html/rfc4880#section-6
26///   [`PacketParserBuilder::dearmor`]: PacketParserBuilder::dearmor()
27#[derive(PartialEq)]
28pub enum Dearmor {
29    /// Unconditionally treat the input as if it were an OpenPGP
30    /// message encoded using ASCII armor.
31    ///
32    /// Parsing a binary encoded OpenPGP message using this mode will
33    /// fail.  The [`ReaderMode`] allow further customization of the
34    /// ASCII armor parser.
35    ///
36    ///   [`ReaderMode`]: crate::armor::ReaderMode
37    Enabled(armor::ReaderMode),
38    /// Unconditionally treat the input as if it were a binary OpenPGP
39    /// message.
40    ///
41    /// Parsing an ASCII armor encoded OpenPGP message using this mode will
42    /// fail.
43    Disabled,
44    /// If input does not appear to be a binary encoded OpenPGP
45    /// message, treat it as if it were encoded using ASCII armor.
46    ///
47    /// This is the default.  The [`ReaderMode`] allow further
48    /// customization of the ASCII armor parser.
49    ///
50    ///   [`ReaderMode`]: crate::armor::ReaderMode
51    Auto(armor::ReaderMode),
52}
53assert_send_and_sync!(Dearmor);
54
55impl Default for Dearmor {
56    fn default() -> Self {
57        Dearmor::Auto(Default::default())
58    }
59}
60
61/// This is the level at which we insert the dearmoring filter into
62/// the buffered reader stack.
63pub(super) const ARMOR_READER_LEVEL: isize = -2;
64
65/// A builder for configuring a `PacketParser`.
66///
67/// Since the default settings are usually appropriate, this mechanism
68/// will only be needed in exceptional circumstances.  Instead use,
69/// for instance, `PacketParser::from_file` or
70/// `PacketParser::from_reader` to start parsing an OpenPGP message.
71///
72/// # Examples
73///
74/// ```rust
75/// # fn main() -> sequoia_openpgp::Result<()> {
76/// use sequoia_openpgp as openpgp;
77/// use openpgp::parse::{Parse, PacketParserResult, PacketParserBuilder};
78///
79/// // Parse a message.
80/// let message_data: &[u8] = // ...
81/// #    include_bytes!("../../tests/data/messages/compressed-data-algo-0.pgp");
82/// let mut ppr = PacketParserBuilder::from_bytes(message_data)?
83///     // Customize the `PacketParserBuilder` here.
84///     .build()?;
85/// while let PacketParserResult::Some(mut pp) = ppr {
86///     // ...
87///
88///     // Start parsing the next packet, recursing.
89///     ppr = pp.recurse()?.1;
90/// }
91/// # Ok(()) }
92/// ```
93pub struct PacketParserBuilder<'a> {
94    bio: Box<dyn BufferedReader<Cookie> + 'a>,
95    dearmor: Dearmor,
96    settings: PacketParserSettings,
97    csf_transformation: bool,
98}
99assert_send_and_sync!(PacketParserBuilder<'_>);
100
101impl<'a> Parse<'a, PacketParserBuilder<'a>> for PacketParserBuilder<'a> {
102    /// Starts parsing an OpenPGP object stored in a `BufferedReader` object.
103    ///
104    /// This function returns a `PacketParser` for the first packet in
105    /// the stream.
106    fn from_buffered_reader<R>(reader: R) -> Result<PacketParserBuilder<'a>>
107    where
108        R: BufferedReader<Cookie> + 'a,
109    {
110        PacketParserBuilder::from_cookie_reader(reader.into_boxed())
111    }
112
113    /// Creates a `PacketParserBuilder` for an OpenPGP message stored
114    /// in a `std::io::Read` object.
115    fn from_reader<R: io::Read + 'a + Send + Sync>(reader: R) -> Result<Self> {
116        PacketParserBuilder::from_cookie_reader(
117            Box::new(buffered_reader::Generic::with_cookie(
118                reader, None, Cookie::default())))
119    }
120
121    /// Creates a `PacketParserBuilder` for an OpenPGP message stored
122    /// in the file named `path`.
123    fn from_file<P: AsRef<Path>>(path: P) -> Result<Self> {
124        PacketParserBuilder::from_cookie_reader(
125            Box::new(buffered_reader::File::with_cookie(path, Cookie::default())?))
126    }
127
128    /// Creates a `PacketParserBuilder` for an OpenPGP message stored
129    /// in the specified buffer.
130    fn from_bytes<D: AsRef<[u8]> + ?Sized>(data: &'a D) -> Result<PacketParserBuilder<'a>> {
131        PacketParserBuilder::from_cookie_reader(
132            Box::new(buffered_reader::Memory::with_cookie(
133                data.as_ref(), Cookie::default())))
134    }
135}
136
137impl<'a> PacketParserBuilder<'a> {
138    // Creates a `PacketParserBuilder` for an OpenPGP message stored
139    // in a `BufferedReader` object.
140    //
141    // Note: this clears the `level` field of the
142    // `Cookie` cookie.
143    pub(crate) fn from_cookie_reader(mut bio: Box<dyn BufferedReader<Cookie> + 'a>)
144            -> Result<Self> {
145        bio.cookie_mut().level = None;
146        Ok(PacketParserBuilder {
147            bio,
148            dearmor: Default::default(),
149            settings: PacketParserSettings::default(),
150            csf_transformation: false,
151        })
152    }
153
154    /// Sets the maximum recursion depth.
155    ///
156    /// Setting this to 0 means that the `PacketParser` will never
157    /// recurse; it will only parse the top-level packets.
158    ///
159    /// This is a u8, because recursing more than 255 times makes no
160    /// sense.  The default is [`DEFAULT_MAX_RECURSION_DEPTH`].
161    /// (GnuPG defaults to a maximum recursion depth of 32.)
162    ///
163    /// [`DEFAULT_MAX_RECURSION_DEPTH`]: crate::parse::DEFAULT_MAX_RECURSION_DEPTH
164    ///
165    /// # Examples
166    ///
167    /// ```rust
168    /// # fn main() -> sequoia_openpgp::Result<()> {
169    /// use sequoia_openpgp as openpgp;
170    /// use openpgp::Packet;
171    /// use openpgp::parse::{Parse, PacketParserResult, PacketParserBuilder};
172    ///
173    /// // Parse a compressed message.
174    /// let message_data: &[u8] = // ...
175    /// #    include_bytes!("../../tests/data/messages/compressed-data-algo-0.pgp");
176    /// let mut ppr = PacketParserBuilder::from_bytes(message_data)?
177    ///     .max_recursion_depth(0)
178    ///     .build()?;
179    /// while let PacketParserResult::Some(mut pp) = ppr {
180    ///     assert_eq!(pp.recursion_depth(), 0);
181    ///
182    ///     // Start parsing the next packet, recursing.
183    ///     ppr = pp.recurse()?.1;
184    /// }
185    /// # Ok(()) }
186    /// ```
187    pub fn max_recursion_depth(mut self, value: u8) -> Self {
188        self.settings.max_recursion_depth = value;
189        self
190    }
191
192    /// Sets the maximum size in bytes of non-container packets.
193    ///
194    /// Packets that exceed this limit will be returned as
195    /// `Packet::Unknown`, with the error set to
196    /// `Error::PacketTooLarge`.
197    ///
198    /// This limit applies to any packet type that is *not* a
199    /// container packet, i.e. any packet that is not a literal data
200    /// packet, a compressed data packet, a symmetrically encrypted
201    /// data packet, or an AEAD encrypted data packet.
202    ///
203    /// The default is [`DEFAULT_MAX_PACKET_SIZE`].
204    ///
205    /// [`DEFAULT_MAX_PACKET_SIZE`]: crate::parse::DEFAULT_MAX_PACKET_SIZE
206    ///
207    /// # Examples
208    ///
209    /// ```rust
210    /// # fn main() -> sequoia_openpgp::Result<()> {
211    /// use sequoia_openpgp as openpgp;
212    /// use openpgp::{Error, Packet};
213    /// use openpgp::packet::Tag;
214    /// use openpgp::parse::{Parse, PacketParserResult, PacketParserBuilder};
215    /// use openpgp::serialize::MarshalInto;
216    ///
217    /// // Parse a signed message.
218    /// let message_data: &[u8] = // ...
219    /// #    include_bytes!("../../tests/data/messages/signed-1.gpg");
220    /// let mut ppr = PacketParserBuilder::from_bytes(message_data)?
221    ///     .max_packet_size(256)    // Only parse 256 bytes of headers.
222    ///     .buffer_unread_content() // Used below.
223    ///     .build()?;
224    /// while let PacketParserResult::Some(mut pp) = ppr {
225    ///     match &pp.packet {
226    ///         Packet::OnePassSig(p) =>
227    ///             // The OnePassSig packet was small enough.
228    ///             assert!(p.serialized_len() < 256),
229    ///         Packet::Literal(p) =>
230    ///             // Likewise the `Literal` packet, excluding the body.
231    ///             assert!(p.serialized_len() - p.body().len() < 256),
232    ///         Packet::Unknown(p) =>
233    ///             // The signature packet was too big.
234    ///             assert_eq!(
235    ///                 &Error::PacketTooLarge(Tag::Signature, 307, 256),
236    ///                 p.error().downcast_ref().unwrap()),
237    ///         _ => unreachable!(),
238    ///     }
239    ///
240    ///     // Start parsing the next packet, recursing.
241    ///     ppr = pp.recurse()?.1;
242    /// }
243    /// # Ok(()) }
244    /// ```
245    pub fn max_packet_size(mut self, value: u32) -> Self {
246        self.settings.max_packet_size = value;
247        self
248    }
249
250    /// Causes `PacketParser::build()` to buffer any unread content.
251    ///
252    /// The unread content can be accessed using [`Literal::body`],
253    /// [`Unknown::body`], or [`Container::body`].
254    ///
255    ///   [`Literal::body`]: crate::packet::Literal::body()
256    ///   [`Unknown::body`]: crate::packet::Unknown::body()
257    ///   [`Container::body`]: crate::packet::Container::body()
258    ///
259    /// # Examples
260    ///
261    /// ```rust
262    /// # fn main() -> sequoia_openpgp::Result<()> {
263    /// use sequoia_openpgp as openpgp;
264    /// use openpgp::Packet;
265    /// use openpgp::parse::{Parse, PacketParserResult, PacketParserBuilder};
266    ///
267    /// // Parse a simple message.
268    /// let message_data = b"\xcb\x12t\x00\x00\x00\x00\x00Hello world.";
269    /// let mut ppr = PacketParserBuilder::from_bytes(message_data)?
270    ///     .buffer_unread_content()
271    ///     .build()?;
272    /// while let PacketParserResult::Some(mut pp) = ppr {
273    ///     // Start parsing the next packet, recursing.
274    ///     let (packet, tmp) = pp.recurse()?;
275    ///     ppr = tmp;
276    ///
277    ///     match packet {
278    ///         Packet::Literal(l) => assert_eq!(l.body(), b"Hello world."),
279    ///         _ => unreachable!(),
280    ///     }
281    /// }
282    /// # Ok(()) }
283    /// ```
284    pub fn buffer_unread_content(mut self) -> Self {
285        self.settings.buffer_unread_content = true;
286        self
287    }
288
289    /// Causes `PacketParser::finish()` to drop any unread content.
290    ///
291    /// This is the default.
292    ///
293    /// # Examples
294    ///
295    /// ```rust
296    /// # fn main() -> sequoia_openpgp::Result<()> {
297    /// use sequoia_openpgp as openpgp;
298    /// use openpgp::Packet;
299    /// use openpgp::parse::{Parse, PacketParserResult, PacketParserBuilder};
300    ///
301    /// // Parse a simple message.
302    /// let message_data = b"\xcb\x12t\x00\x00\x00\x00\x00Hello world.";
303    /// let mut ppr = PacketParserBuilder::from_bytes(message_data)?
304    ///     .drop_unread_content()
305    ///     .build()?;
306    /// while let PacketParserResult::Some(mut pp) = ppr {
307    ///     // Start parsing the next packet, recursing.
308    ///     let (packet, tmp) = pp.recurse()?;
309    ///     ppr = tmp;
310    ///
311    ///     match packet {
312    ///         Packet::Literal(l) => assert_eq!(l.body(), b""),
313    ///         _ => unreachable!(),
314    ///     }
315    /// }
316    /// # Ok(()) }
317    /// ```
318    pub fn drop_unread_content(mut self) -> Self {
319        self.settings.buffer_unread_content = false;
320        self
321    }
322
323    /// Controls mapping.
324    ///
325    /// Note that enabling mapping buffers all the data.
326    ///
327    /// # Examples
328    ///
329    /// ```
330    /// # fn main() -> sequoia_openpgp::Result<()> {
331    /// use sequoia_openpgp as openpgp;
332    /// use openpgp::parse::{Parse, PacketParserBuilder};
333    ///
334    /// let message_data = b"\xcb\x12t\x00\x00\x00\x00\x00Hello world.";
335    /// let pp = PacketParserBuilder::from_bytes(message_data)?
336    ///     .map(true) // Enable mapping.
337    ///     .build()?
338    ///     .expect("One packet, not EOF");
339    /// let map = pp.map().expect("Mapping is enabled");
340    ///
341    /// assert_eq!(map.iter().nth(0).unwrap().name(), "CTB");
342    /// assert_eq!(map.iter().nth(0).unwrap().offset(), 0);
343    /// assert_eq!(map.iter().nth(0).unwrap().as_bytes(), &[0xcb]);
344    /// # Ok(()) }
345    /// ```
346    pub fn map(mut self, enable: bool) -> Self {
347        self.settings.map = enable;
348        self
349    }
350
351    /// Controls dearmoring.
352    ///
353    /// By default, if the input does not appear to be plain binary
354    /// OpenPGP data, we assume that it is ASCII-armored.  This method
355    /// can be used to tweak the behavior.  See [`Dearmor`] for
356    /// details.
357    ///
358    ///
359    /// # Examples
360    ///
361    /// ```
362    /// # fn main() -> sequoia_openpgp::Result<()> {
363    /// use sequoia_openpgp as openpgp;
364    /// use openpgp::parse::{Parse, PacketParserBuilder, Dearmor};
365    ///
366    /// let message_data = b"\xcb\x12t\x00\x00\x00\x00\x00Hello world.";
367    /// let pp = PacketParserBuilder::from_bytes(message_data)?
368    ///     .dearmor(Dearmor::Disabled) // Disable dearmoring.
369    ///     .build()?
370    ///     .expect("One packet, not EOF");
371    /// # Ok(()) }
372    /// ```
373    pub fn dearmor(mut self, mode: Dearmor) -> Self {
374        self.dearmor = mode;
375        self
376    }
377
378    /// Controls automatic hashing.
379    ///
380    /// When encountering a [`OnePassSig`] packet, the packet parser
381    /// will, by default, start hashing later packets using the hash
382    /// algorithm specified in the packet.  In some cases, this is not
383    /// needed, and hashing will incur a non-trivial overhead.
384    ///
385    /// If automatic hashing is disabled, then hashing may be
386    /// explicitly enabled using [`PacketParser::start_hashing`] while
387    /// parsing each [`OnePassSig`] packet.
388    ///
389    ///   [`OnePassSig`]: crate::packet::OnePassSig
390    ///
391    /// # Examples
392    ///
393    /// ```
394    /// # fn main() -> sequoia_openpgp::Result<()> {
395    /// # use sequoia_openpgp as openpgp;
396    /// # use openpgp::parse::{Parse, PacketParserBuilder};
397    /// #
398    /// let message_data = b"\xcb\x12t\x00\x00\x00\x00\x00Hello world.";
399    /// let pp = PacketParserBuilder::from_bytes(message_data)?
400    ///     .automatic_hashing(false) // Disable automatic hashing.
401    ///     .build()?
402    ///     .expect("One packet, not EOF");
403    /// # Ok(()) }
404    /// ```
405    pub fn automatic_hashing(mut self, enable: bool) -> Self {
406        self.settings.automatic_hashing = enable;
407        self
408    }
409
410    /// Controls transparent transformation of messages using the
411    /// cleartext signature framework into signed messages.
412    ///
413    /// XXX: This could be controlled by `Dearmor`, but we cannot add
414    /// values to that now.
415    pub(crate) fn csf_transformation(mut self, enable: bool) -> Self {
416        self.csf_transformation = enable;
417        self
418    }
419
420    /// Builds the `PacketParser`.
421    ///
422    /// # Examples
423    ///
424    /// ```rust
425    /// # fn main() -> sequoia_openpgp::Result<()> {
426    /// use sequoia_openpgp as openpgp;
427    /// use openpgp::parse::{Parse, PacketParserResult, PacketParserBuilder};
428    ///
429    /// // Parse a message.
430    /// let message_data: &[u8] = // ...
431    /// #    include_bytes!("../../tests/data/messages/compressed-data-algo-0.pgp");
432    /// let mut ppr = PacketParserBuilder::from_bytes(message_data)?
433    ///     // Customize the `PacketParserBuilder` here.
434    ///     .build()?;
435    /// while let PacketParserResult::Some(mut pp) = ppr {
436    ///     // ...
437    ///
438    ///     // Start parsing the next packet, recursing.
439    ///     ppr = pp.recurse()?.1;
440    /// }
441    /// # Ok(()) }
442    #[allow(clippy::redundant_pattern_matching)]
443    pub fn build(mut self)
444        -> Result<PacketParserResult<'a>>
445        where Self: 'a
446    {
447        let state = PacketParserState::new(self.settings);
448
449        let dearmor_mode = match self.dearmor {
450            Dearmor::Enabled(mode) => Some(mode),
451            Dearmor::Disabled => None,
452            Dearmor::Auto(mode) => {
453                if self.bio.eof() {
454                    None
455                } else {
456                    let mut reader = buffered_reader::Dup::with_cookie(
457                        self.bio, Cookie::default());
458                    let header = packet::Header::parse(&mut reader);
459                    self.bio = Box::new(reader).into_inner().unwrap();
460                    if let Ok(header) = header {
461                        if let Err(_) = header.valid(false) {
462                            // Invalid header: better try an ASCII armor
463                            // decoder.
464                            Some(mode)
465                        } else {
466                            None
467                        }
468                    } else {
469                        // Failed to parse the header: better try an ASCII
470                        // armor decoder.
471                        Some(mode)
472                    }
473                }
474            }
475        };
476
477        if let Some(mode) = dearmor_mode {
478            // Add a top-level filter so that it is peeled off when
479            // the packet parser is finished.  We use level -2 for that.
480            self.bio =
481                armor::Reader::from_cookie_reader_csft(self.bio, Some(mode),
482                    Cookie::new(ARMOR_READER_LEVEL), self.csf_transformation)
483                .into_boxed();
484        }
485
486        // Parse the first packet.
487        match PacketParser::parse(Box::new(self.bio), state, vec![ 0 ])? {
488            ParserResult::Success(mut pp) => {
489                // We successfully parsed the first packet's header.
490                pp.state.message_validator.push(
491                    pp.packet.tag(), pp.packet.version(), &[0]);
492                pp.state.keyring_validator.push(pp.packet.tag());
493                pp.state.cert_validator.push(pp.packet.tag());
494                Ok(PacketParserResult::Some(pp))
495            },
496            ParserResult::EOF((reader, state, _path)) => {
497                // `bio` is empty.  We're done.
498                Ok(PacketParserResult::EOF(PacketParserEOF::new(state, reader)))
499            }
500        }
501    }
502}
503
504#[cfg(test)]
505mod tests {
506    use super::*;
507
508    #[test]
509    fn armor() {
510        // Not ASCII armor encoded data.
511        let msg = crate::tests::message("sig.gpg");
512
513        // Make sure we can read the first packet.
514        let ppr = PacketParserBuilder::from_bytes(msg).unwrap()
515            .dearmor(Dearmor::Disabled)
516            .build();
517        assert_match!(Ok(PacketParserResult::Some(ref _pp)) = ppr);
518
519        let ppr = PacketParserBuilder::from_bytes(msg).unwrap()
520            .dearmor(Dearmor::Auto(Default::default()))
521            .build();
522        assert_match!(Ok(PacketParserResult::Some(ref _pp)) = ppr);
523
524        let ppr = PacketParserBuilder::from_bytes(msg).unwrap()
525            .dearmor(Dearmor::Enabled(Default::default()))
526            .build();
527        assert_match!(Err(_) = ppr);
528
529        // ASCII armor encoded data.
530        let msg = crate::tests::message("a-cypherpunks-manifesto.txt.ed25519.sig");
531
532        // Make sure we can read the first packet.
533        let ppr = PacketParserBuilder::from_bytes(msg).unwrap()
534            .dearmor(Dearmor::Disabled)
535            .build();
536        assert_match!(Err(_) = ppr);
537
538        let ppr = PacketParserBuilder::from_bytes(msg).unwrap()
539            .dearmor(Dearmor::Auto(Default::default()))
540            .build();
541        assert_match!(Ok(PacketParserResult::Some(ref _pp)) = ppr);
542
543        let ppr = PacketParserBuilder::from_bytes(msg).unwrap()
544            .dearmor(Dearmor::Enabled(Default::default()))
545            .build();
546        assert_match!(Ok(PacketParserResult::Some(ref _pp)) = ppr);
547    }
548}