diff --git a/src/parser.rs b/src/parser.rs index a4cde29..3eda92c 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -2,7 +2,7 @@ use crate::types::{Asn1Readable, Tlv}; use crate::Tag; use core::fmt; -#[derive(Debug, PartialEq, Eq)] +#[derive(Debug, PartialEq, Eq, Clone, Copy)] pub enum ParseErrorKind { /// Something about the value was invalid. InvalidValue, @@ -15,8 +15,14 @@ pub enum ParseErrorKind { InvalidLength, /// An unexpected tag was encountered. UnexpectedTag { actual: Tag }, - /// There was not enough data available to complete parsing. - ShortData, + /// There was not enough data available to complete parsing. Includes the + /// amount of data needed to advance the parse. + /// + /// Note that provided `needed` additional bytes of data does not ensure + /// that `parse` will succeed -- it is the amount of data required to + /// satisfy the `read` operation that failed, and there may be subsequent + /// `read` operations that require additional data. + ShortData { needed: usize }, /// An internal computation would have overflowed. IntegerOverflow, /// There was extraneous data in the input. @@ -57,6 +63,10 @@ impl ParseError { } } + pub fn kind(&self) -> ParseErrorKind { + self.kind + } + #[doc(hidden)] #[must_use] pub fn add_location(mut self, loc: ParseLocation) -> Self { @@ -123,7 +133,13 @@ impl fmt::Display for ParseError { ParseErrorKind::UnexpectedTag { actual } => { write!(f, "unexpected tag (got {:?})", actual) } - ParseErrorKind::ShortData => write!(f, "short data"), + ParseErrorKind::ShortData { needed } => { + write!( + f, + "short data (needed at least {} additional bytes)", + needed + ) + } ParseErrorKind::IntegerOverflow => write!(f, "integer overflow"), ParseErrorKind::ExtraData => write!(f, "extra data"), ParseErrorKind::InvalidSetOrdering => write!(f, "SET value was ordered incorrectly"), @@ -202,7 +218,9 @@ impl<'a> Parser<'a> { #[inline] fn read_bytes(&mut self, length: usize) -> ParseResult<&'a [u8]> { if length > self.data.len() { - return Err(ParseError::new(ParseErrorKind::ShortData)); + return Err(ParseError::new(ParseErrorKind::ShortData { + needed: length - self.data.len(), + })); } let (result, data) = self.data.split_at(length); self.data = data; @@ -401,9 +419,9 @@ mod tests { "ASN.1 parsing error: DEFINED BY with unknown value" ), ( - ParseError::new(ParseErrorKind::ShortData) + ParseError::new(ParseErrorKind::ShortData{needed: 7}) .add_location(ParseLocation::Field("Abc::123")), - "ASN.1 parsing error: short data", + "ASN.1 parsing error: short data (needed at least 7 additional bytes)", ), ( ParseError::new(ParseErrorKind::UnexpectedTag { @@ -465,7 +483,9 @@ mod tests { &[ (Ok(8), b"\x02\x01\x08"), ( - Err(E::P(ParseError::new(ParseErrorKind::ShortData))), + Err(E::P(ParseError::new(ParseErrorKind::ShortData { + needed: 1, + }))), b"\x02\x01", ), (Err(E::X(7)), b"\x02\x01\x07"), @@ -493,11 +513,17 @@ mod tests { b"\x04\x03abc", ), ( - Err(ParseError::new(ParseErrorKind::ShortData)), + Err(ParseError::new(ParseErrorKind::ShortData { needed: 2 })), b"\x04\x03a", ), - (Err(ParseError::new(ParseErrorKind::ShortData)), b"\x04"), - (Err(ParseError::new(ParseErrorKind::ShortData)), b""), + ( + Err(ParseError::new(ParseErrorKind::ShortData { needed: 1 })), + b"\x04", + ), + ( + Err(ParseError::new(ParseErrorKind::ShortData { needed: 1 })), + b"", + ), // Long form tags ( Ok(Tlv { @@ -618,8 +644,8 @@ mod tests { Err(ParseError::new(ParseErrorKind::InvalidLength)), b"\x04\x89\x01\x01\x01\x01\x01\x01\x01\x01\x01" ), - (Err(ParseError::new(ParseErrorKind::ShortData)), b"\x04\x03\x01\x02"), - (Err(ParseError::new(ParseErrorKind::ShortData)), b"\x04\x82\xff\xff\xff\xff\xff\xff"), + (Err(ParseError::new(ParseErrorKind::ShortData{needed: 1})), b"\x04\x03\x01\x02"), + (Err(ParseError::new(ParseErrorKind::ShortData{needed: 65531})), b"\x04\x82\xff\xff\xff\xff\xff\xff"), // 3 byte length form with leading 0. (Err(ParseError::new(ParseErrorKind::InvalidLength)), b"\x04\x83\x00\xff\xff"), // 4 byte length form with leading 0. @@ -668,11 +694,17 @@ mod tests { b"\x03\x00", ), ( - Err(ParseError::new(ParseErrorKind::ShortData)), + Err(ParseError::new(ParseErrorKind::ShortData { needed: 1 })), b"\x02\x02\x00", ), - (Err(ParseError::new(ParseErrorKind::ShortData)), b""), - (Err(ParseError::new(ParseErrorKind::ShortData)), b"\x02"), + ( + Err(ParseError::new(ParseErrorKind::ShortData { needed: 1 })), + b"", + ), + ( + Err(ParseError::new(ParseErrorKind::ShortData { needed: 1 })), + b"\x02", + ), ( Err(ParseError::new(ParseErrorKind::IntegerOverflow)), b"\x02\x09\x02\x00\x00\x00\x00\x00\x00\x00\x00", @@ -732,11 +764,17 @@ mod tests { b"\x03\x00", ), ( - Err(ParseError::new(ParseErrorKind::ShortData)), + Err(ParseError::new(ParseErrorKind::ShortData { needed: 1 })), b"\x02\x02\x00", ), - (Err(ParseError::new(ParseErrorKind::ShortData)), b""), - (Err(ParseError::new(ParseErrorKind::ShortData)), b"\x02"), + ( + Err(ParseError::new(ParseErrorKind::ShortData { needed: 1 })), + b"", + ), + ( + Err(ParseError::new(ParseErrorKind::ShortData { needed: 1 })), + b"\x02", + ), ( Err(ParseError::new(ParseErrorKind::IntegerOverflow)), b"\x02\x09\x02\x00\x00\x00\x00\x00\x00\x00\x00", @@ -1449,7 +1487,7 @@ mod tests { b"\x30\x06\x02\x01\x01\x02\x01\x02", ), ( - Err(ParseError::new(ParseErrorKind::ShortData)), + Err(ParseError::new(ParseErrorKind::ShortData { needed: 1 })), b"\x30\x04\x02\x01\x01", ), ( @@ -1465,7 +1503,7 @@ mod tests { &[ (Ok((1, 2)), b"\x30\x06\x02\x01\x01\x02\x01\x02"), ( - Err(ParseError::new(ParseErrorKind::ShortData)), + Err(ParseError::new(ParseErrorKind::ShortData { needed: 1 })), b"\x30\x03\x02\x01\x01", ), ( @@ -1490,7 +1528,7 @@ mod tests { ), (Ok(vec![]), b"\x30\x00"), ( - Err(ParseError::new(ParseErrorKind::ShortData)), + Err(ParseError::new(ParseErrorKind::ShortData { needed: 1 })), b"\x30\x02\x02\x01", ), ], @@ -1516,7 +1554,7 @@ mod tests { ), (Ok(vec![]), b"\x30\x00"), ( - Err(ParseError::new(ParseErrorKind::ShortData) + Err(ParseError::new(ParseErrorKind::ShortData { needed: 1 }) .add_location(ParseLocation::Index(0))), b"\x30\x02\x02\x01", ), @@ -1540,7 +1578,7 @@ mod tests { b"\x31\x06\x02\x01\x03\x02\x01\x01", ), ( - Err(ParseError::new(ParseErrorKind::ShortData) + Err(ParseError::new(ParseErrorKind::ShortData { needed: 1 }) .add_location(ParseLocation::Index(0))), b"\x31\x01\x02", ), @@ -1565,8 +1603,14 @@ mod tests { (Ok((None, Some(18))), b"\x02\x01\x12"), (Ok((Some(true), Some(18))), b"\x01\x01\xff\x02\x01\x12"), (Ok((None, None)), b""), - (Err(ParseError::new(ParseErrorKind::ShortData)), b"\x01"), - (Err(ParseError::new(ParseErrorKind::ShortData)), b"\x02"), + ( + Err(ParseError::new(ParseErrorKind::ShortData { needed: 1 })), + b"\x01", + ), + ( + Err(ParseError::new(ParseErrorKind::ShortData { needed: 1 })), + b"\x02", + ), ], |p| { Ok(( @@ -1586,7 +1630,10 @@ mod tests { b"\x04\x03abc", ), (Ok(None), b""), - (Err(ParseError::new(ParseErrorKind::ShortData)), b"\x04"), + ( + Err(ParseError::new(ParseErrorKind::ShortData { needed: 1 })), + b"\x04", + ), ]); assert_parses::>>(&[ @@ -1607,7 +1654,10 @@ mod tests { })), b"\x03\x00", ), - (Err(ParseError::new(ParseErrorKind::ShortData)), b""), + ( + Err(ParseError::new(ParseErrorKind::ShortData { needed: 1 })), + b"", + ), ]); } @@ -1622,7 +1672,10 @@ mod tests { })), b"\x03\x00", ), - (Err(ParseError::new(ParseErrorKind::ShortData)), b""), + ( + Err(ParseError::new(ParseErrorKind::ShortData { needed: 1 })), + b"", + ), ]); } @@ -1638,7 +1691,10 @@ mod tests { })), b"\x03\x00", ), - (Err(ParseError::new(ParseErrorKind::ShortData)), b""), + ( + Err(ParseError::new(ParseErrorKind::ShortData { needed: 1 })), + b"", + ), ]); } @@ -1675,7 +1731,10 @@ mod tests { })), b"\x02\x01\xff", ), - (Err(ParseError::new(ParseErrorKind::ShortData)), b""), + ( + Err(ParseError::new(ParseErrorKind::ShortData { needed: 1 })), + b"", + ), ]); } diff --git a/src/tag.rs b/src/tag.rs index 03b3043..4632060 100644 --- a/src/tag.rs +++ b/src/tag.rs @@ -25,7 +25,7 @@ impl Tag { pub fn from_bytes(mut data: &[u8]) -> ParseResult<(Tag, &[u8])> { let tag = match data.first() { Some(&b) => b, - None => return Err(ParseError::new(ParseErrorKind::ShortData)), + None => return Err(ParseError::new(ParseErrorKind::ShortData { needed: 1 })), }; data = &data[1..]; let mut value = u32::from(tag & 0x1f); diff --git a/tests/derive_test.rs b/tests/derive_test.rs index 42e3072..c3e14b1 100644 --- a/tests/derive_test.rs +++ b/tests/derive_test.rs @@ -465,8 +465,10 @@ fn test_required_implicit() { assert_roundtrips::(&[ (Ok(RequiredImplicit { value: 8 }), b"\x30\x03\x80\x01\x08"), ( - Err(asn1::ParseError::new(asn1::ParseErrorKind::ShortData) - .add_location(asn1::ParseLocation::Field("RequiredImplicit::value"))), + Err( + asn1::ParseError::new(asn1::ParseErrorKind::ShortData { needed: 1 }) + .add_location(asn1::ParseLocation::Field("RequiredImplicit::value")), + ), b"\x30\x00", ), ( @@ -493,8 +495,10 @@ fn test_required_explicit() { b"\x30\x05\xa0\x03\x02\x01\x08", ), ( - Err(asn1::ParseError::new(asn1::ParseErrorKind::ShortData) - .add_location(asn1::ParseLocation::Field("RequiredExplicit::value"))), + Err( + asn1::ParseError::new(asn1::ParseErrorKind::ShortData { needed: 1 }) + .add_location(asn1::ParseLocation::Field("RequiredExplicit::value")), + ), b"\x30\x00", ), (