diff options
author | Justus Winter <justus@sequoia-pgp.org> | 2024-01-15 18:35:00 +0100 |
---|---|---|
committer | Justus Winter <justus@sequoia-pgp.org> | 2024-01-22 13:48:32 +0100 |
commit | b838d4b1bfc4b432e908741c94b336df19d201ad (patch) | |
tree | af9d9a77b046f8de9d9887aeae99a683b2c16565 /openpgp/src | |
parent | 96d829d681ea1b860bf4b16439082929f4636147 (diff) |
openpgp: Add Parse::from_buffered_reader.
- Add a buffered-reader-based function to trait Parse. This allows
us to manipulate the buffered reader stack before and after
parsing, e.g. to parse several armored objects in one stream. The
CertParser also does this, but uses internal interfaces for that.
Diffstat (limited to 'openpgp/src')
-rw-r--r-- | openpgp/src/armor.rs | 9 | ||||
-rw-r--r-- | openpgp/src/cert.rs | 17 | ||||
-rw-r--r-- | openpgp/src/cert/parser/mod.rs | 10 | ||||
-rw-r--r-- | openpgp/src/cert/raw.rs | 23 | ||||
-rw-r--r-- | openpgp/src/message/mod.rs | 16 | ||||
-rw-r--r-- | openpgp/src/packet_pile.rs | 11 | ||||
-rw-r--r-- | openpgp/src/parse.rs | 46 | ||||
-rw-r--r-- | openpgp/src/parse/packet_parser_builder.rs | 11 | ||||
-rw-r--r-- | openpgp/src/parse/packet_pile_parser.rs | 7 | ||||
-rw-r--r-- | openpgp/src/parse/stream.rs | 21 |
10 files changed, 156 insertions, 15 deletions
diff --git a/openpgp/src/armor.rs b/openpgp/src/armor.rs index 97e82d1e..992977b7 100644 --- a/openpgp/src/armor.rs +++ b/openpgp/src/armor.rs @@ -627,6 +627,15 @@ impl<'a> Reader<'a> { mode, Default::default()) } + /// Constructs a new `Reader` from the given `BufferedReader`. + pub fn from_buffered_reader<R, M>(reader: R, mode: M) -> Result<Self> + where + R: BufferedReader<Cookie> + 'a, + M: Into<Option<ReaderMode>>, + { + Ok(Self::from_cookie_reader(reader.into_boxed(), mode, Default::default())) + } + /// Constructs a new `Reader` from the given `io::Read`er. /// /// [ASCII Armor], designed to protect OpenPGP data in transit, diff --git a/openpgp/src/cert.rs b/openpgp/src/cert.rs index 9c8a1869..81a05c5d 100644 --- a/openpgp/src/cert.rs +++ b/openpgp/src/cert.rs @@ -141,6 +141,8 @@ use std::fmt; use std::ops::{Deref, DerefMut}; use std::time; +use buffered_reader::BufferedReader; + use crate::{ crypto::{ Signer, @@ -165,7 +167,7 @@ use crate::{ KeyHandle, policy::Policy, }; -use crate::parse::{Parse, PacketParserResult, PacketParser}; +use crate::parse::{Cookie, Parse, PacketParserResult, PacketParser}; use crate::types::{ AEADAlgorithm, CompressionAlgorithm, @@ -775,6 +777,19 @@ impl<'a> Parse<'a, Cert> for Cert { /// /// If `reader` contains multiple certificates, this returns an /// error. Use [`CertParser`] if you want to parse a keyring. + fn from_buffered_reader<R>(reader: R) -> Result<Cert> + where + R: BufferedReader<Cookie> + 'a, + { + Cert::try_from(PacketParser::from_buffered_reader(reader)?) + } + + /// Parses and returns a certificate. + /// + /// The reader must return an OpenPGP-encoded certificate. + /// + /// If `reader` contains multiple certificates, this returns an + /// error. Use [`CertParser`] if you want to parse a keyring. fn from_reader<R: io::Read + Send + Sync>(reader: R) -> Result<Self> { Cert::try_from(PacketParser::from_reader(reader)?) } diff --git a/openpgp/src/cert/parser/mod.rs b/openpgp/src/cert/parser/mod.rs index 147f32de..e8963d94 100644 --- a/openpgp/src/cert/parser/mod.rs +++ b/openpgp/src/cert/parser/mod.rs @@ -3,6 +3,7 @@ use std::mem; use std::vec; use std::path::Path; +use buffered_reader::BufferedReader; use lalrpop_util::ParseError; use crate::{ @@ -11,6 +12,7 @@ use crate::{ packet::Tag, Packet, parse::{ + Cookie, Parse, PacketParserResult, PacketParser @@ -594,6 +596,14 @@ impl<'a> From<Vec<Packet>> for CertParser<'a> { impl<'a> Parse<'a, CertParser<'a>> for CertParser<'a> { + /// Initializes a `CertParser` from a `BufferedReader`. + fn from_buffered_reader<R>(reader: R) -> Result<CertParser<'a>> + where + R: BufferedReader<Cookie> + 'a, + { + Ok(Self::from(PacketParser::from_buffered_reader(reader)?)) + } + /// Initializes a `CertParser` from a `Read`er. fn from_reader<R: 'a + io::Read + Send + Sync>(reader: R) -> Result<Self> { Ok(Self::from(PacketParser::from_reader(reader)?)) diff --git a/openpgp/src/cert/raw.rs b/openpgp/src/cert/raw.rs index e9610818..bd981c24 100644 --- a/openpgp/src/cert/raw.rs +++ b/openpgp/src/cert/raw.rs @@ -459,8 +459,11 @@ impl<'a> Parse<'a, RawCert<'a>> for RawCert<'a> { /// Returns the first RawCert encountered in the reader. /// /// Returns an error if there are multiple certificates. - fn from_reader<R: 'a + Read + Send + Sync>(reader: R) -> Result<Self> { - let mut parser = RawCertParser::from_reader(reader)?; + fn from_buffered_reader<R>(reader: R) -> Result<RawCert<'a>> + where + R: BufferedReader<Cookie> + 'a + { + let mut parser = RawCertParser::from_buffered_reader(reader)?; if let Some(cert_result) = parser.next() { if parser.next().is_some() { Err(Error::MalformedCert( @@ -473,6 +476,14 @@ impl<'a> Parse<'a, RawCert<'a>> for RawCert<'a> { Err(Error::MalformedCert("No data".into()).into()) } } + + /// Returns the first RawCert encountered in the reader. + /// + /// Returns an error if there are multiple certificates. + fn from_reader<R: 'a + Read + Send + Sync>(reader: R) -> Result<Self> { + let br = Generic::with_cookie(reader, None, Cookie::default()); + Self::from_buffered_reader(br) + } } impl<'a> crate::seal::Sealed for RawCert<'a> {} @@ -655,6 +666,14 @@ impl<'a> RawCertParser<'a> { impl<'a> Parse<'a, RawCertParser<'a>> for RawCertParser<'a> { + /// Initializes a `RawCertParser` from a `BufferedReader`. + fn from_buffered_reader<R>(reader: R) -> Result<RawCertParser<'a>> + where + R: BufferedReader<Cookie> + 'a + { + RawCertParser::new(reader) + } + /// Initializes a `RawCertParser` from a `Read`er. fn from_reader<R: 'a + Read + Send + Sync>(reader: R) -> Result<Self> { RawCertParser::new(Generic::with_cookie(reader, None, Default::default())) diff --git a/openpgp/src/message/mod.rs b/openpgp/src/message/mod.rs index 5a9d3b1f..d6da5a8f 100644 --- a/openpgp/src/message/mod.rs +++ b/openpgp/src/message/mod.rs @@ -29,13 +29,15 @@ use std::fmt; use std::io; use std::path::Path; +use buffered_reader::BufferedReader; + use crate::Result; use crate::Error; use crate::Packet; use crate::PacketPile; use crate::packet::Literal; use crate::packet::Tag; -use crate::parse::Parse; +use crate::parse::{Cookie, Parse}; mod lexer; lalrpop_util::lalrpop_mod!(#[allow(clippy::all, deprecated)] grammar, "/message/grammar.rs"); @@ -348,6 +350,18 @@ impl<'a> Parse<'a, Message> for Message { /// See [`Message::try_from`] for more details. /// /// [`Message::try_from`]: Message::try_from() + fn from_buffered_reader<R>(reader: R) -> Result<Message> + where + R: BufferedReader<Cookie> + 'a, + { + Self::try_from(PacketPile::from_buffered_reader(reader)?) + } + + /// Reads a `Message` from the specified reader. + /// + /// See [`Message::try_from`] for more details. + /// + /// [`Message::try_from`]: Message::try_from() fn from_reader<R: 'a + io::Read + Send + Sync>(reader: R) -> Result<Self> { Self::try_from(PacketPile::from_reader(reader)?) } diff --git a/openpgp/src/packet_pile.rs b/openpgp/src/packet_pile.rs index f62eb6f6..1678c523 100644 --- a/openpgp/src/packet_pile.rs +++ b/openpgp/src/packet_pile.rs @@ -120,6 +120,17 @@ impl fmt::Debug for PacketPile { } impl<'a> Parse<'a, PacketPile> for PacketPile { + /// Deserializes the OpenPGP message stored in the file named by + /// `path`. + /// + /// See `from_reader` for more details and caveats. + fn from_buffered_reader<R>(reader: R) -> Result<PacketPile> + where + R: BufferedReader<Cookie> + 'a, + { + PacketPile::from_cookie_reader(reader.into_boxed()) + } + /// Deserializes the OpenPGP message stored in a `std::io::Read` /// object. /// diff --git a/openpgp/src/parse.rs b/openpgp/src/parse.rs index 1b2333a0..b731b74e 100644 --- a/openpgp/src/parse.rs +++ b/openpgp/src/parse.rs @@ -281,6 +281,20 @@ pub(crate) const RECOVERY_THRESHOLD: usize = 32 * 1024; /// This is a uniform interface to parse packets, messages, keys, and /// related data structures. pub trait Parse<'a, T> { + /// Reads from the given buffered reader. + fn from_buffered_reader<R>(reader: R) -> Result<T> + where + R: BufferedReader<Cookie> + 'a, + { + // XXXv2: Make this function the mandatory one instead of + // Parse::from_reader. + + // Currently, we express the default implementation over + // Self::from_reader, which is no worse than using from_reader + // directly. + Self::from_reader(reader) + } + /// Reads from the given reader. fn from_reader<R: 'a + Read + Send + Sync>(reader: R) -> Result<T>; @@ -338,15 +352,14 @@ macro_rules! impl_parse_with_buffered_reader { // from_buffered_reader should be a closure that takes a // BufferedReader and returns a Result<Self>. ($typ: ident, $from_buffered_reader: expr) => { - impl $typ { - fn from_buffered_reader<'a, B>(br: B) -> Result<Self> - where B: 'a + BufferedReader<Cookie>, + impl<'a> Parse<'a, $typ> for $typ { + fn from_buffered_reader<R>(reader: R) -> Result<Self> + where + R: BufferedReader<Cookie> + 'a, { - Ok($from_buffered_reader(br.into_boxed())?) + Ok($from_buffered_reader(reader.into_boxed())?) } - } - impl<'a> Parse<'a, $typ> for $typ { fn from_reader<R: 'a + Read + Send + Sync>(reader: R) -> Result<Self> { let br = buffered_reader::Generic::with_cookie( reader, None, Cookie::default()); @@ -3222,10 +3235,11 @@ impl_parse_with_buffered_reader!( }) }); -impl<'a> Parse<'a, Packet> for Packet { - fn from_reader<R: 'a + Read + Send + Sync>(reader: R) -> Result<Self> { +impl_parse_with_buffered_reader!( + Packet, + |br| -> Result<Self> { let ppr = - PacketParserBuilder::from_reader(reader) + PacketParserBuilder::from_buffered_reader(br) ?.buffer_unread_content().build()?; let (p, ppr) = match ppr { @@ -3244,8 +3258,7 @@ impl<'a> Parse<'a, Packet> for Packet { Err(Error::InvalidOperation( "Excess data after packet".into()).into()), } - } -} + }); // State that lives for the life of the packet parser, not the life of // an individual packet. @@ -3968,6 +3981,17 @@ impl<'a> PacketParserResult<'a> { } impl<'a> Parse<'a, PacketParserResult<'a>> for PacketParser<'a> { + /// Starts parsing an OpenPGP object stored in a `BufferedReader` object. + /// + /// This function returns a `PacketParser` for the first packet in + /// the stream. + fn from_buffered_reader<R>(reader: R) -> Result<PacketParserResult<'a>> + where + R: BufferedReader<Cookie> + 'a, + { + PacketParserBuilder::from_buffered_reader(reader)?.build() + } + /// Starts parsing an OpenPGP message stored in a `std::io::Read` object. /// /// This function returns a `PacketParser` for the first packet in diff --git a/openpgp/src/parse/packet_parser_builder.rs b/openpgp/src/parse/packet_parser_builder.rs index 02a83ad3..2b52efd5 100644 --- a/openpgp/src/parse/packet_parser_builder.rs +++ b/openpgp/src/parse/packet_parser_builder.rs @@ -99,6 +99,17 @@ pub struct PacketParserBuilder<'a> { assert_send_and_sync!(PacketParserBuilder<'_>); impl<'a> Parse<'a, PacketParserBuilder<'a>> for PacketParserBuilder<'a> { + /// Starts parsing an OpenPGP object stored in a `BufferedReader` object. + /// + /// This function returns a `PacketParser` for the first packet in + /// the stream. + fn from_buffered_reader<R>(reader: R) -> Result<PacketParserBuilder<'a>> + where + R: BufferedReader<Cookie> + 'a, + { + PacketParserBuilder::from_cookie_reader(reader.into_boxed()) + } + /// Creates a `PacketParserBuilder` for an OpenPGP message stored /// in a `std::io::Read` object. fn from_reader<R: io::Read + 'a + Send + Sync>(reader: R) -> Result<Self> { diff --git a/openpgp/src/parse/packet_pile_parser.rs b/openpgp/src/parse/packet_pile_parser.rs index ea65912e..b06cf6d8 100644 --- a/openpgp/src/parse/packet_pile_parser.rs +++ b/openpgp/src/parse/packet_pile_parser.rs @@ -218,6 +218,13 @@ impl<'a> TryFrom<PacketParserBuilder<'a>> for PacketPileParser<'a> { } impl<'a> Parse<'a, PacketPileParser<'a>> for PacketPileParser<'a> { + fn from_buffered_reader<R>(reader: R) -> Result<PacketPileParser<'a>> + where + R: BufferedReader<Cookie> + 'a + { + PacketPileParser::from_cookie_reader(reader.into_boxed()) + } + /// Creates a `PacketPileParser` to parse the OpenPGP message stored /// in the `io::Read` object. fn from_reader<R: io::Read + 'a + Send + Sync>(reader: R) diff --git a/openpgp/src/parse/stream.rs b/openpgp/src/parse/stream.rs index 288df6ac..63d42507 100644 --- a/openpgp/src/parse/stream.rs +++ b/openpgp/src/parse/stream.rs @@ -1059,6 +1059,13 @@ assert_send_and_sync!(VerifierBuilder<'_>); impl<'a> Parse<'a, VerifierBuilder<'a>> for VerifierBuilder<'a> { + fn from_buffered_reader<R>(reader: R) -> Result<VerifierBuilder<'a>> + where + R: BufferedReader<Cookie> + 'a, + { + VerifierBuilder::new(reader) + } + fn from_reader<R>(reader: R) -> Result<VerifierBuilder<'a>> where R: io::Read + 'a + Send + Sync, { @@ -1460,6 +1467,13 @@ assert_send_and_sync!(DetachedVerifierBuilder<'_>); impl<'a> Parse<'a, DetachedVerifierBuilder<'a>> for DetachedVerifierBuilder<'a> { + fn from_buffered_reader<R>(reader: R) -> Result<DetachedVerifierBuilder<'a>> + where + R: BufferedReader<Cookie> + 'a, + { + DetachedVerifierBuilder::new(reader) + } + fn from_reader<R>(reader: R) -> Result<DetachedVerifierBuilder<'a>> where R: io::Read + 'a + Send + Sync, { @@ -1817,6 +1831,13 @@ assert_send_and_sync!(DecryptorBuilder<'_>); impl<'a> Parse<'a, DecryptorBuilder<'a>> for DecryptorBuilder<'a> { + fn from_buffered_reader<R>(reader: R) -> Result<DecryptorBuilder<'a>> + where + R: BufferedReader<Cookie> + 'a, + { + DecryptorBuilder::new(reader) + } + fn from_reader<R>(reader: R) -> Result<DecryptorBuilder<'a>> where R: io::Read + 'a + Send + Sync, { |