summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJustus Winter <justus@sequoia-pgp.org>2024-01-15 18:35:00 +0100
committerJustus Winter <justus@sequoia-pgp.org>2024-01-22 13:48:32 +0100
commitb838d4b1bfc4b432e908741c94b336df19d201ad (patch)
treeaf9d9a77b046f8de9d9887aeae99a683b2c16565
parent96d829d681ea1b860bf4b16439082929f4636147 (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.
-rw-r--r--openpgp/NEWS2
-rw-r--r--openpgp/src/armor.rs9
-rw-r--r--openpgp/src/cert.rs17
-rw-r--r--openpgp/src/cert/parser/mod.rs10
-rw-r--r--openpgp/src/cert/raw.rs23
-rw-r--r--openpgp/src/message/mod.rs16
-rw-r--r--openpgp/src/packet_pile.rs11
-rw-r--r--openpgp/src/parse.rs46
-rw-r--r--openpgp/src/parse/packet_parser_builder.rs11
-rw-r--r--openpgp/src/parse/packet_pile_parser.rs7
-rw-r--r--openpgp/src/parse/stream.rs21
11 files changed, 158 insertions, 15 deletions
diff --git a/openpgp/NEWS b/openpgp/NEWS
index f694f869..1aac12d3 100644
--- a/openpgp/NEWS
+++ b/openpgp/NEWS
@@ -12,6 +12,8 @@
- KeyAmalgamation::active_certifications_by_key
- UserIDAmalgamation::valid_third_party_revocations_by_key
- KeyAmalgamation::valid_third_party_revocations_by_key
+ - Parse::from_buffered_reader
+ - armor::Reader::from_buffered_reader
* Changes in 1.17.0
** Notable fixes
- Sequoia now ignores some formatting errors when reading secret
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,
{