diff options
Diffstat (limited to 'vendor/der/src/reader')
-rw-r--r-- | vendor/der/src/reader/nested.rs | 96 | ||||
-rw-r--r-- | vendor/der/src/reader/pem.rs | 83 | ||||
-rw-r--r-- | vendor/der/src/reader/slice.rs | 214 |
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 + } +} |