diff --git a/der/src/document.rs b/der/src/document.rs index 927703d05..3f0008334 100644 --- a/der/src/document.rs +++ b/der/src/document.rs @@ -1,6 +1,6 @@ //! ASN.1 DER-encoded documents stored on the heap. -use crate::{Decode, Encode, Error, FixedTag, Length, Reader, SliceReader, Tag, Writer}; +use crate::{Decode, Encode, Error, FixedTag, Header, Length, Reader, SliceReader, Tag, Writer}; use alloc::vec::Vec; use core::fmt::{self, Debug}; @@ -148,7 +148,7 @@ impl<'a> Decode<'a> for Document { type Error = Error; fn decode>(reader: &mut R) -> Result { - let header = reader.peek_header()?; + let header = Header::peek(reader)?; let length = (header.encoded_len()? + header.length)?; let bytes = reader.read_slice(length)?; @@ -323,7 +323,7 @@ impl ZeroizeOnDrop for SecretDocument {} /// Attempt to decode a ASN.1 `SEQUENCE` from the given decoder, returning the /// entire sequence including the header. fn decode_sequence<'a>(decoder: &mut SliceReader<'a>) -> Result<&'a [u8], Error> { - let header = decoder.peek_header()?; + let header = Header::peek(decoder)?; header.tag.assert_eq(Tag::Sequence)?; let len = (header.encoded_len()? + header.length)?; diff --git a/der/src/header.rs b/der/src/header.rs index b069d8569..3d2dcd568 100644 --- a/der/src/header.rs +++ b/der/src/header.rs @@ -24,6 +24,24 @@ impl Header { let length = length.try_into().map_err(|_| ErrorKind::Overflow)?; Ok(Self { tag, length }) } + + /// Peek forward in the reader, attempting to decode a [`Header`] at the current position. + /// + /// Does not modify the reader's state. + pub fn peek<'a>(reader: &impl Reader<'a>) -> Result { + let mut buf = [0u8; Self::MAX_SIZE]; + + for i in 2..Self::MAX_SIZE { + let slice = &mut buf[0..i]; + if reader.peek_into(slice).is_ok() { + if let Ok(header) = Self::from_der(slice) { + return Ok(header); + } + } + } + + Self::from_der(&buf) + } } impl<'a> Decode<'a> for Header { @@ -63,3 +81,25 @@ impl DerOrd for Header { } } } + +#[cfg(test)] +mod tests { + use super::Header; + use crate::{Length, Reader, SliceReader, Tag}; + use hex_literal::hex; + + #[test] + #[allow(clippy::unwrap_used)] + fn peek() { + // INTEGER: 42 + const EXAMPLE_MSG: &[u8] = &hex!("02012A00"); + + let reader = SliceReader::new(EXAMPLE_MSG).unwrap(); + assert_eq!(reader.position(), Length::ZERO); + + let header = Header::peek(&reader).unwrap(); + assert_eq!(header.tag, Tag::Integer); + assert_eq!(header.length, Length::ONE); + assert_eq!(reader.position(), Length::ZERO); // Position unchanged + } +} diff --git a/der/src/reader.rs b/der/src/reader.rs index 0e035c431..fe77d0359 100644 --- a/der/src/reader.rs +++ b/der/src/reader.rs @@ -110,19 +110,18 @@ pub trait Reader<'r>: Sized { /// the data at the current position in the decoder. /// /// Does not modify the decoder's state. + #[deprecated(since = "0.8.0-rc.1", note = "use `Header::peek` instead")] fn peek_header(&self) -> Result { - let mut buf = [0u8; Header::MAX_SIZE]; - - for i in 2..Header::MAX_SIZE { - let slice = &mut buf[0..i]; - if self.peek_into(slice).is_ok() { - if let Ok(header) = Header::from_der(slice) { - return Ok(header); - } - } - } + Header::peek(self) + } - Header::from_der(&buf) + /// Peek at the next byte in the reader. + #[deprecated(since = "0.8.0-rc.1", note = "use `Tag::peek` instead")] + fn peek_tag(&self) -> Result { + match self.peek_byte() { + Some(byte) => byte.try_into(), + None => Err(Error::incomplete(self.input_len())), + } } /// Read a single byte. @@ -172,7 +171,7 @@ pub trait Reader<'r>: Sized { /// Obtain a slice of bytes contain a complete TLV production suitable for parsing later. fn tlv_bytes(&mut self) -> Result<&'r [u8], Error> { - let header = self.peek_header()?; + let header = Header::peek(self)?; let header_len = header.encoded_len()?; self.read_slice((header_len + header.length)?) } diff --git a/der/src/reader/slice.rs b/der/src/reader/slice.rs index bbba4b440..96585c582 100644 --- a/der/src/reader/slice.rs +++ b/der/src/reader/slice.rs @@ -165,7 +165,7 @@ impl<'a> Reader<'a> for SliceReader<'a> { #[allow(clippy::unwrap_used, clippy::panic)] mod tests { use super::SliceReader; - use crate::{Decode, ErrorKind, Length, Reader, Tag}; + use crate::{Decode, ErrorKind, Length, Reader}; use hex_literal::hex; // INTEGER: 42 @@ -226,15 +226,4 @@ mod tests { err.kind() ); } - - #[test] - fn peek_header() { - let reader = SliceReader::new(EXAMPLE_MSG).unwrap(); - assert_eq!(reader.position(), Length::ZERO); - - let header = reader.peek_header().unwrap(); - assert_eq!(header.tag, Tag::Integer); - assert_eq!(header.length, Length::ONE); - assert_eq!(reader.position(), Length::ZERO); // Position unchanged - } }