summaryrefslogtreecommitdiffstats
path: root/vendor/der/src/reader
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/der/src/reader')
-rw-r--r--vendor/der/src/reader/nested.rs96
-rw-r--r--vendor/der/src/reader/pem.rs83
-rw-r--r--vendor/der/src/reader/slice.rs214
3 files changed, 393 insertions, 0 deletions
diff --git a/vendor/der/src/reader/nested.rs b/vendor/der/src/reader/nested.rs
new file mode 100644
index 000000000..40ede69ac
--- /dev/null
+++ b/vendor/der/src/reader/nested.rs
@@ -0,0 +1,96 @@
+//! Reader type for consuming nested TLV records within a DER document.
+
+use crate::{reader::Reader, Error, ErrorKind, Header, Length, Result};
+
+/// Reader type used by [`Reader::read_nested`].
+pub struct NestedReader<'i, R> {
+ /// Inner reader type.
+ inner: &'i mut R,
+
+ /// Nested input length.
+ input_len: Length,
+
+ /// Position within the nested input.
+ position: Length,
+}
+
+impl<'i, 'r, R: Reader<'r>> NestedReader<'i, R> {
+ /// Create a new nested reader which can read the given [`Length`].
+ pub(crate) fn new(inner: &'i mut R, len: Length) -> Result<Self> {
+ if len <= inner.remaining_len() {
+ Ok(Self {
+ inner,
+ input_len: len,
+ position: Length::ZERO,
+ })
+ } else {
+ Err(ErrorKind::Incomplete {
+ expected_len: (inner.offset() + len)?,
+ actual_len: (inner.offset() + inner.remaining_len())?,
+ }
+ .at(inner.offset()))
+ }
+ }
+
+ /// Move the position cursor the given length, returning an error if there
+ /// isn't enough remaining data in the nested input.
+ fn advance_position(&mut self, len: Length) -> Result<()> {
+ let new_position = (self.position + len)?;
+
+ if new_position <= self.input_len {
+ self.position = new_position;
+ Ok(())
+ } else {
+ Err(ErrorKind::Incomplete {
+ expected_len: (self.inner.offset() + len)?,
+ actual_len: (self.inner.offset() + self.remaining_len())?,
+ }
+ .at(self.inner.offset()))
+ }
+ }
+}
+
+impl<'i, 'r, R: Reader<'r>> Reader<'r> for NestedReader<'i, R> {
+ fn input_len(&self) -> Length {
+ self.input_len
+ }
+
+ fn peek_byte(&self) -> Option<u8> {
+ if self.is_finished() {
+ None
+ } else {
+ self.inner.peek_byte()
+ }
+ }
+
+ fn peek_header(&self) -> Result<Header> {
+ if self.is_finished() {
+ Err(Error::incomplete(self.offset()))
+ } else {
+ // TODO(tarcieri): handle peeking past nested length
+ self.inner.peek_header()
+ }
+ }
+
+ fn position(&self) -> Length {
+ self.position
+ }
+
+ fn read_slice(&mut self, len: Length) -> Result<&'r [u8]> {
+ self.advance_position(len)?;
+ self.inner.read_slice(len)
+ }
+
+ fn error(&mut self, kind: ErrorKind) -> Error {
+ self.inner.error(kind)
+ }
+
+ fn offset(&self) -> Length {
+ self.inner.offset()
+ }
+
+ fn read_into<'o>(&mut self, out: &'o mut [u8]) -> Result<&'o [u8]> {
+ self.advance_position(Length::try_from(out.len())?)?;
+ self.inner.read_into(out)
+ }
+}
diff --git a/vendor/der/src/reader/pem.rs b/vendor/der/src/reader/pem.rs
new file mode 100644
index 000000000..01bb4f20e
--- /dev/null
+++ b/vendor/der/src/reader/pem.rs
@@ -0,0 +1,83 @@
+//! Streaming PEM reader.
+
+use super::Reader;
+use crate::{ErrorKind, Header, Length, Result};
+use pem_rfc7468::Decoder;
+
+/// `Reader` type which decodes PEM on-the-fly.
+#[cfg(feature = "pem")]
+#[cfg_attr(docsrs, doc(cfg(feature = "pem")))]
+#[derive(Clone)]
+pub struct PemReader<'i> {
+ /// Inner PEM decoder.
+ decoder: Decoder<'i>,
+
+ /// Input length (in bytes after Base64 decoding).
+ input_len: Length,
+
+ /// Position in the input buffer (in bytes after Base64 decoding).
+ position: Length,
+}
+
+#[cfg(feature = "pem")]
+#[cfg_attr(docsrs, doc(cfg(feature = "pem")))]
+impl<'i> PemReader<'i> {
+ /// Create a new PEM reader which decodes data on-the-fly.
+ ///
+ /// Uses the default 64-character line wrapping.
+ pub fn new(pem: &'i [u8]) -> Result<Self> {
+ let decoder = Decoder::new(pem)?;
+ let input_len = Length::try_from(decoder.remaining_len())?;
+
+ Ok(Self {
+ decoder,
+ input_len,
+ position: Length::ZERO,
+ })
+ }
+
+ /// Get the PEM label which will be used in the encapsulation boundaries
+ /// for this document.
+ pub fn type_label(&self) -> &'i str {
+ self.decoder.type_label()
+ }
+}
+
+#[cfg(feature = "pem")]
+#[cfg_attr(docsrs, doc(cfg(feature = "pem")))]
+impl<'i> Reader<'i> for PemReader<'i> {
+ fn input_len(&self) -> Length {
+ self.input_len
+ }
+
+ fn peek_byte(&self) -> Option<u8> {
+ // TODO(tarcieri): lookahead buffer
+ None
+ }
+
+ fn peek_header(&self) -> Result<Header> {
+ // TODO(tarcieri): lookahead buffer
+ Err(ErrorKind::Reader.into())
+ }
+
+ fn position(&self) -> Length {
+ self.position
+ }
+
+ fn read_slice(&mut self, _len: Length) -> Result<&'i [u8]> {
+ // Can't borrow from PEM because it requires decoding
+ Err(ErrorKind::Reader.into())
+ }
+
+ fn read_into<'o>(&mut self, buf: &'o mut [u8]) -> Result<&'o [u8]> {
+ let bytes = self.decoder.decode(buf)?;
+ self.position = (self.position + bytes.len())?;
+
+ debug_assert_eq!(
+ self.position,
+ (self.input_len - Length::try_from(self.decoder.remaining_len())?)?
+ );
+
+ Ok(bytes)
+ }
+}
diff --git a/vendor/der/src/reader/slice.rs b/vendor/der/src/reader/slice.rs
new file mode 100644
index 000000000..6bab091f3
--- /dev/null
+++ b/vendor/der/src/reader/slice.rs
@@ -0,0 +1,214 @@
+//! Slice reader.
+
+use crate::{ByteSlice, Decode, Error, ErrorKind, Header, Length, Reader, Result, Tag};
+
+/// [`Reader`] which consumes an input byte slice.
+#[derive(Clone, Debug)]
+pub struct SliceReader<'a> {
+ /// Byte slice being decoded.
+ bytes: ByteSlice<'a>,
+
+ /// Did the decoding operation fail?
+ failed: bool,
+
+ /// Position within the decoded slice.
+ position: Length,
+}
+
+impl<'a> SliceReader<'a> {
+ /// Create a new slice reader for the given byte slice.
+ pub fn new(bytes: &'a [u8]) -> Result<Self> {
+ Ok(Self {
+ bytes: ByteSlice::new(bytes)?,
+ failed: false,
+ position: Length::ZERO,
+ })
+ }
+
+ /// Return an error with the given [`ErrorKind`], annotating it with
+ /// context about where the error occurred.
+ pub fn error(&mut self, kind: ErrorKind) -> Error {
+ self.failed = true;
+ kind.at(self.position)
+ }
+
+ /// Return an error for an invalid value with the given tag.
+ pub fn value_error(&mut self, tag: Tag) -> Error {
+ self.error(tag.value_error().kind())
+ }
+
+ /// Did the decoding operation fail due to an error?
+ pub fn is_failed(&self) -> bool {
+ self.failed
+ }
+
+ /// Obtain the remaining bytes in this slice reader from the current cursor
+ /// position.
+ fn remaining(&self) -> Result<&'a [u8]> {
+ if self.is_failed() {
+ Err(ErrorKind::Failed.at(self.position))
+ } else {
+ self.bytes
+ .as_slice()
+ .get(self.position.try_into()?..)
+ .ok_or_else(|| Error::incomplete(self.input_len()))
+ }
+ }
+}
+
+impl<'a> Reader<'a> for SliceReader<'a> {
+ fn input_len(&self) -> Length {
+ self.bytes.len()
+ }
+
+ fn peek_byte(&self) -> Option<u8> {
+ self.remaining()
+ .ok()
+ .and_then(|bytes| bytes.get(0).cloned())
+ }
+
+ fn peek_header(&self) -> Result<Header> {
+ Header::decode(&mut self.clone())
+ }
+
+ fn position(&self) -> Length {
+ self.position
+ }
+
+ fn read_slice(&mut self, len: Length) -> Result<&'a [u8]> {
+ if self.is_failed() {
+ return Err(self.error(ErrorKind::Failed));
+ }
+
+ match self.remaining()?.get(..len.try_into()?) {
+ Some(result) => {
+ self.position = (self.position + len)?;
+ Ok(result)
+ }
+ None => Err(self.error(ErrorKind::Incomplete {
+ expected_len: (self.position + len)?,
+ actual_len: self.input_len(),
+ })),
+ }
+ }
+
+ fn decode<T: Decode<'a>>(&mut self) -> Result<T> {
+ if self.is_failed() {
+ return Err(self.error(ErrorKind::Failed));
+ }
+
+ T::decode(self).map_err(|e| {
+ self.failed = true;
+ e.nested(self.position)
+ })
+ }
+
+ fn error(&mut self, kind: ErrorKind) -> Error {
+ self.failed = true;
+ kind.at(self.position)
+ }
+
+ fn finish<T>(self, value: T) -> Result<T> {
+ if self.is_failed() {
+ Err(ErrorKind::Failed.at(self.position))
+ } else if !self.is_finished() {
+ Err(ErrorKind::TrailingData {
+ decoded: self.position,
+ remaining: self.remaining_len(),
+ }
+ .at(self.position))
+ } else {
+ Ok(value)
+ }
+ }
+
+ fn remaining_len(&self) -> Length {
+ debug_assert!(self.position <= self.input_len());
+ self.input_len().saturating_sub(self.position)
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::SliceReader;
+ use crate::{Decode, ErrorKind, Length, Reader, Tag};
+ use hex_literal::hex;
+
+ // INTEGER: 42
+ const EXAMPLE_MSG: &[u8] = &hex!("02012A00");
+
+ #[test]
+ fn empty_message() {
+ let mut reader = SliceReader::new(&[]).unwrap();
+ let err = bool::decode(&mut reader).err().unwrap();
+ assert_eq!(Some(Length::ZERO), err.position());
+
+ match err.kind() {
+ ErrorKind::Incomplete {
+ expected_len,
+ actual_len,
+ } => {
+ assert_eq!(actual_len, 0u8.into());
+ assert_eq!(expected_len, 1u8.into());
+ }
+ other => panic!("unexpected error kind: {:?}", other),
+ }
+ }
+
+ #[test]
+ fn invalid_field_length() {
+ const MSG_LEN: usize = 2;
+
+ let mut reader = SliceReader::new(&EXAMPLE_MSG[..MSG_LEN]).unwrap();
+ let err = i8::decode(&mut reader).err().unwrap();
+ assert_eq!(Some(Length::from(2u8)), err.position());
+
+ match err.kind() {
+ ErrorKind::Incomplete {
+ expected_len,
+ actual_len,
+ } => {
+ assert_eq!(actual_len, MSG_LEN.try_into().unwrap());
+ assert_eq!(expected_len, (MSG_LEN + 1).try_into().unwrap());
+ }
+ other => panic!("unexpected error kind: {:?}", other),
+ }
+ }
+
+ #[test]
+ fn trailing_data() {
+ let mut reader = SliceReader::new(EXAMPLE_MSG).unwrap();
+ let x = i8::decode(&mut reader).unwrap();
+ assert_eq!(42i8, x);
+
+ let err = reader.finish(x).err().unwrap();
+ assert_eq!(Some(Length::from(3u8)), err.position());
+
+ assert_eq!(
+ ErrorKind::TrailingData {
+ decoded: 3u8.into(),
+ remaining: 1u8.into()
+ },
+ err.kind()
+ );
+ }
+
+ #[test]
+ fn peek_tag() {
+ let reader = SliceReader::new(EXAMPLE_MSG).unwrap();
+ assert_eq!(reader.position(), Length::ZERO);
+ assert_eq!(reader.peek_tag().unwrap(), Tag::Integer);
+ assert_eq!(reader.position(), Length::ZERO); // Position unchanged
+ }
+
+ #[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
+ }
+}