summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJustus Winter <justus@sequoia-pgp.org>2019-02-06 16:56:43 +0100
committerJustus Winter <justus@sequoia-pgp.org>2019-02-06 16:56:43 +0100
commit7e7071cdd64ad387ac82af259a3a44c5488b2392 (patch)
treebb2be798f52b483780b7475338ac6fcece9f1ba4
parentb62ea3af257e8d2ccb2555959e047f7ea41eb0d6 (diff)
openpgp: Store parsing errors in the Unknown packet.
- This improves diagnostics on soft errors producing unknown packets. - Fixes #65.
-rw-r--r--openpgp/src/packet/unknown.rs50
-rw-r--r--openpgp/src/parse/parse.rs29
2 files changed, 64 insertions, 15 deletions
diff --git a/openpgp/src/packet/unknown.rs b/openpgp/src/packet/unknown.rs
index ca7d40e6..77c7ff3c 100644
--- a/openpgp/src/packet/unknown.rs
+++ b/openpgp/src/packet/unknown.rs
@@ -1,3 +1,6 @@
+use failure;
+use std::hash::{Hash, Hasher};
+
use packet::Tag;
use packet;
use Packet;
@@ -8,20 +11,49 @@ use Packet;
/// how to process rather than abort.
///
/// This packet effectively holds a binary blob.
-#[derive(PartialEq, Eq, Hash, Clone, Debug)]
+#[derive(Debug)]
pub struct Unknown {
/// CTB packet header fields.
pub(crate) common: packet::Common,
/// Packet tag.
tag: Tag,
+ /// Error that caused parsing or processing to abort.
+ error: failure::Error,
+}
+
+impl Eq for Unknown {}
+
+impl PartialEq for Unknown {
+ fn eq(&self, other: &Unknown) -> bool {
+ self.common == other.common && self.tag == other.tag
+ }
+}
+
+impl Hash for Unknown {
+ fn hash<H: Hasher>(&self, state: &mut H) {
+ self.common.hash(state);
+ self.tag.hash(state);
+ }
+}
+
+impl Clone for Unknown {
+ fn clone(&self) -> Self {
+ Unknown {
+ common: self.common.clone(),
+ tag: self.tag,
+ error: failure::err_msg(format!("{}", self.error)),
+ }
+ }
}
+
impl Unknown {
/// Returns a new `Unknown` packet.
- pub fn new(tag: Tag) -> Self {
+ pub fn new(tag: Tag, error: failure::Error) -> Self {
Unknown {
common: Default::default(),
tag: tag,
+ error: error,
}
}
@@ -35,6 +67,20 @@ impl Unknown {
self.tag = tag;
}
+ /// Gets the unknown packet's error.
+ ///
+ /// This is the error that caused parsing or processing to abort.
+ pub fn error(&self) -> &failure::Error {
+ &self.error
+ }
+
+ /// Sets the unknown packet's error.
+ ///
+ /// This is the error that caused parsing or processing to abort.
+ pub fn set_error(&mut self, error: failure::Error) -> failure::Error {
+ ::std::mem::replace(&mut self.error, error)
+ }
+
/// Sets the packet's contents.
///
/// This is the raw packet content not include the CTB and length
diff --git a/openpgp/src/parse/parse.rs b/openpgp/src/parse/parse.rs
index 38ce8088..c97b654a 100644
--- a/openpgp/src/parse/parse.rs
+++ b/openpgp/src/parse/parse.rs
@@ -190,15 +190,10 @@ macro_rules! make_php_try {
Ok(b)
},
Err(e) => {
- // XXX: Ugh, this is getting unwieldy, and we
- // are loosing information for no good reason.
- // Why not simply pass the error to fail()?
- // Otoh, currently the information isn't even
- // stored.
let e = match e.downcast::<io::Error>() {
Ok(e) =>
if let io::ErrorKind::UnexpectedEof = e.kind() {
- return $parser.fail("truncated")
+ return $parser.error(e.into());
} else {
e.into()
},
@@ -207,7 +202,7 @@ macro_rules! make_php_try {
let e = match e.downcast::<Error>() {
Ok(e) => match e {
Error::MalformedMPI(_) =>
- return $parser.fail("malformed MPI"),
+ return $parser.error(e.into()),
_ =>
e.into(),
},
@@ -337,8 +332,12 @@ impl<'a> PacketHeaderParser<'a> {
// Something went wrong while parsing the packet's header. Aborts
// and returns an Unknown packet instead.
- fn fail(self, _reason: &'static str) -> Result<PacketParser<'a>> {
- Unknown::parse(self)
+ fn fail(self, reason: &'static str) -> Result<PacketParser<'a>> {
+ self.error(Error::MalformedPacket(reason.into()).into())
+ }
+
+ fn error(self, error: failure::Error) -> Result<PacketParser<'a>> {
+ Unknown::parse(self, error)
}
fn field(&mut self, name: &'static str, size: usize) {
@@ -891,10 +890,11 @@ impl<'a> Parse<'a, Header> for Header {
impl Unknown {
/// Parses the body of any packet and returns an Unknown.
- fn parse<'a>(php: PacketHeaderParser<'a>) -> Result<PacketParser<'a>>
+ fn parse<'a>(php: PacketHeaderParser<'a>, error: failure::Error)
+ -> Result<PacketParser<'a>>
{
let tag = php.header.ctb.tag;
- php.ok(Packet::Unknown(Unknown::new(tag)))
+ php.ok(Packet::Unknown(Unknown::new(tag, error)))
.map(|pp| pp.set_decrypted(false))
}
}
@@ -926,7 +926,9 @@ pub(crate) fn to_unknown_packet<R: Read>(reader: R) -> Result<Unknown>
let parser = PacketHeaderParser::new(
reader, PacketParserState::new(Default::default()), vec![ 0 ], header, Vec::new());
- let mut pp = Unknown::parse(parser)?;
+ let mut pp =
+ Unknown::parse(parser,
+ failure::err_msg("explicit conversion to unknown"))?;
pp.buffer_unread_content()?;
pp.finish()?;
@@ -2994,7 +2996,8 @@ impl <'a> PacketParser<'a> {
Tag::MDC => MDC::parse(parser),
Tag::PKESK => PKESK::parse(parser),
Tag::AED => AED::parse(parser),
- _ => Unknown::parse(parser),
+ _ => Unknown::parse(parser,
+ Error::UnsupportedPacketType(tag).into()),
}?;
if tag == Tag::OnePassSig {