diff options
author | Justus Winter <justus@sequoia-pgp.org> | 2019-02-06 16:56:43 +0100 |
---|---|---|
committer | Justus Winter <justus@sequoia-pgp.org> | 2019-02-06 16:56:43 +0100 |
commit | 7e7071cdd64ad387ac82af259a3a44c5488b2392 (patch) | |
tree | bb2be798f52b483780b7475338ac6fcece9f1ba4 | |
parent | b62ea3af257e8d2ccb2555959e047f7ea41eb0d6 (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.rs | 50 | ||||
-rw-r--r-- | openpgp/src/parse/parse.rs | 29 |
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 { |