summaryrefslogtreecommitdiffstats
path: root/vendor/der/src/reader.rs
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-04 12:47:55 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-04 12:47:55 +0000
commit2aadc03ef15cb5ca5cc2af8a7c08e070742f0ac4 (patch)
tree033cc839730fda84ff08db877037977be94e5e3a /vendor/der/src/reader.rs
parentInitial commit. (diff)
downloadcargo-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.rs167
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)?)
+ }
+}