diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-04 12:47:55 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-04 12:47:55 +0000 |
commit | 2aadc03ef15cb5ca5cc2af8a7c08e070742f0ac4 (patch) | |
tree | 033cc839730fda84ff08db877037977be94e5e3a /vendor/der/src/reader.rs | |
parent | Initial commit. (diff) | |
download | cargo-upstream.tar.xz cargo-upstream.zip |
Adding upstream version 0.70.1+ds1.upstream/0.70.1+ds1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vendor/der/src/reader.rs')
-rw-r--r-- | vendor/der/src/reader.rs | 167 |
1 files changed, 167 insertions, 0 deletions
diff --git a/vendor/der/src/reader.rs b/vendor/der/src/reader.rs new file mode 100644 index 0000000..ea52f7b --- /dev/null +++ b/vendor/der/src/reader.rs @@ -0,0 +1,167 @@ +//! Reader trait. + +pub(crate) mod nested; +#[cfg(feature = "pem")] +pub(crate) mod pem; +pub(crate) mod slice; + +pub(crate) use nested::NestedReader; + +use crate::{ + asn1::ContextSpecific, Decode, DecodeValue, Encode, Error, ErrorKind, FixedTag, Header, Length, + Result, Tag, TagMode, TagNumber, +}; + +#[cfg(feature = "alloc")] +use alloc::vec::Vec; + +/// Reader trait which reads DER-encoded input. +pub trait Reader<'r>: Sized { + /// Get the length of the input. + fn input_len(&self) -> Length; + + /// Peek at the next byte of input without modifying the cursor. + fn peek_byte(&self) -> Option<u8>; + + /// Peek forward in the input data, attempting to decode a [`Header`] from + /// the data at the current position in the decoder. + /// + /// Does not modify the decoder's state. + fn peek_header(&self) -> Result<Header>; + + /// Get the position within the buffer. + fn position(&self) -> Length; + + /// Attempt to read data borrowed directly from the input as a slice, + /// updating the internal cursor position. + /// + /// # Returns + /// - `Ok(slice)` on success + /// - `Err(ErrorKind::Incomplete)` if there is not enough data + /// - `Err(ErrorKind::Reader)` if the reader can't borrow from the input + fn read_slice(&mut self, len: Length) -> Result<&'r [u8]>; + + /// Attempt to decode an ASN.1 `CONTEXT-SPECIFIC` field with the + /// provided [`TagNumber`]. + fn context_specific<T>(&mut self, tag_number: TagNumber, tag_mode: TagMode) -> Result<Option<T>> + where + T: DecodeValue<'r> + FixedTag, + { + Ok(match tag_mode { + TagMode::Explicit => ContextSpecific::<T>::decode_explicit(self, tag_number)?, + TagMode::Implicit => ContextSpecific::<T>::decode_implicit(self, tag_number)?, + } + .map(|field| field.value)) + } + + /// Decode a value which impls the [`Decode`] trait. + fn decode<T: Decode<'r>>(&mut self) -> Result<T> { + T::decode(self).map_err(|e| e.nested(self.position())) + } + + /// Return an error with the given [`ErrorKind`], annotating it with + /// context about where the error occurred. + fn error(&mut self, kind: ErrorKind) -> Error { + kind.at(self.position()) + } + + /// Finish decoding, returning the given value if there is no + /// remaining data, or an error otherwise + fn finish<T>(self, value: T) -> Result<T> { + if !self.is_finished() { + Err(ErrorKind::TrailingData { + decoded: self.position(), + remaining: self.remaining_len(), + } + .at(self.position())) + } else { + Ok(value) + } + } + + /// Have we read all of the input data? + fn is_finished(&self) -> bool { + self.remaining_len().is_zero() + } + + /// Offset within the original input stream. + /// + /// This is used for error reporting, and doesn't need to be overridden + /// by any reader implementations (except for the built-in `NestedReader`, + /// which consumes nested input messages) + fn offset(&self) -> Length { + self.position() + } + + /// Peek at the next byte in the decoder and attempt to decode it as a + /// [`Tag`] value. + /// + /// Does not modify the decoder's state. + fn peek_tag(&self) -> Result<Tag> { + match self.peek_byte() { + Some(byte) => byte.try_into(), + None => Err(Error::incomplete(self.input_len())), + } + } + + /// Read a single byte. + fn read_byte(&mut self) -> Result<u8> { + let mut buf = [0]; + self.read_into(&mut buf)?; + Ok(buf[0]) + } + + /// Attempt to read input data, writing it into the provided buffer, and + /// returning a slice on success. + /// + /// # Returns + /// - `Ok(slice)` if there is sufficient data + /// - `Err(ErrorKind::Incomplete)` if there is not enough data + fn read_into<'o>(&mut self, buf: &'o mut [u8]) -> Result<&'o [u8]> { + let input = self.read_slice(buf.len().try_into()?)?; + buf.copy_from_slice(input); + Ok(buf) + } + + /// Read nested data of the given length. + fn read_nested<'n, T, F>(&'n mut self, len: Length, f: F) -> Result<T> + where + F: FnOnce(&mut NestedReader<'n, Self>) -> Result<T>, + { + let mut reader = NestedReader::new(self, len)?; + let ret = f(&mut reader)?; + reader.finish(ret) + } + + /// Read a byte vector of the given length. + #[cfg(feature = "alloc")] + fn read_vec(&mut self, len: Length) -> Result<Vec<u8>> { + let mut bytes = vec![0u8; usize::try_from(len)?]; + self.read_into(&mut bytes)?; + Ok(bytes) + } + + /// Get the number of bytes still remaining in the buffer. + fn remaining_len(&self) -> Length { + debug_assert!(self.position() <= self.input_len()); + self.input_len().saturating_sub(self.position()) + } + + /// Read an ASN.1 `SEQUENCE`, creating a nested [`Reader`] for the body and + /// calling the provided closure with it. + fn sequence<'n, F, T>(&'n mut self, f: F) -> Result<T> + where + F: FnOnce(&mut NestedReader<'n, Self>) -> Result<T>, + { + let header = Header::decode(self)?; + header.tag.assert_eq(Tag::Sequence)?; + self.read_nested(header.length, f) + } + + /// Obtain a slice of bytes contain a complete TLV production suitable for parsing later. + fn tlv_bytes(&mut self) -> Result<&'r [u8]> { + let header = self.peek_header()?; + let header_len = header.encoded_len()?; + self.read_slice((header_len + header.length)?) + } +} |