diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-18 02:49:42 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-18 02:49:42 +0000 |
commit | 837b550238aa671a591ccf282dddeab29cadb206 (patch) | |
tree | 914b6b8862bace72bd3245ca184d374b08d8a672 /vendor/der/src/length.rs | |
parent | Adding debian version 1.70.0+dfsg2-1. (diff) | |
download | rustc-837b550238aa671a591ccf282dddeab29cadb206.tar.xz rustc-837b550238aa671a591ccf282dddeab29cadb206.zip |
Merging upstream version 1.71.1+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vendor/der/src/length.rs')
-rw-r--r-- | vendor/der/src/length.rs | 147 |
1 files changed, 143 insertions, 4 deletions
diff --git a/vendor/der/src/length.rs b/vendor/der/src/length.rs index 76ee0e997..d183a69fe 100644 --- a/vendor/der/src/length.rs +++ b/vendor/der/src/length.rs @@ -14,6 +14,13 @@ const MAX_DER_OCTETS: usize = 5; /// Maximum length as a `u32` (256 MiB). const MAX_U32: u32 = 0xfff_ffff; +/// Octet identifying an indefinite length as described in X.690 Section +/// 8.1.3.6.1: +/// +/// > The single octet shall have bit 8 set to one, and bits 7 to +/// > 1 set to zero. +const INDEFINITE_LENGTH_OCTET: u8 = 0b10000000; // 0x80 + /// ASN.1-encoded length. /// /// Maximum length is defined by the [`Length::MAX`] constant (256 MiB). @@ -204,7 +211,8 @@ impl<'a> Decode<'a> for Length { match reader.read_byte()? { // Note: per X.690 Section 8.1.3.6.1 the byte 0x80 encodes indefinite // lengths, which are not allowed in DER, so disallow that byte. - len if len < 0x80 => Ok(len.into()), + len if len < INDEFINITE_LENGTH_OCTET => Ok(len.into()), + INDEFINITE_LENGTH_OCTET => Err(ErrorKind::IndefiniteLength.into()), // 1-4 byte variable-sized length prefix tag @ 0x81..=0x84 => { let nbytes = tag.checked_sub(0x80).ok_or(ErrorKind::Overlength)? as usize; @@ -246,7 +254,7 @@ impl Encode for Length { } } - fn encode(&self, writer: &mut dyn Writer) -> Result<()> { + fn encode(&self, writer: &mut impl Writer) -> Result<()> { match self.initial_octet() { Some(tag_byte) => { writer.write_byte(tag_byte)?; @@ -286,9 +294,126 @@ impl fmt::Display for Length { } } +// Implement by hand because the derive would create invalid values. +// Generate a u32 with a valid range. +#[cfg(feature = "arbitrary")] +impl<'a> arbitrary::Arbitrary<'a> for Length { + fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> { + Ok(Self(u.int_in_range(0..=MAX_U32)?)) + } + + fn size_hint(depth: usize) -> (usize, Option<usize>) { + u32::size_hint(depth) + } +} + +/// Length type with support for indefinite lengths as used by ASN.1 BER, +/// as described in X.690 Section 8.1.3.6: +/// +/// > 8.1.3.6 For the indefinite form, the length octets indicate that the +/// > contents octets are terminated by end-of-contents +/// > octets (see 8.1.5), and shall consist of a single octet. +/// > +/// > 8.1.3.6.1 The single octet shall have bit 8 set to one, and bits 7 to +/// > 1 set to zero. +/// > +/// > 8.1.3.6.2 If this form of length is used, then end-of-contents octets +/// > (see 8.1.5) shall be present in the encoding following the contents +/// > octets. +/// +/// Indefinite lengths are non-canonical and therefore invalid DER, however +/// there are interoperability corner cases where we have little choice but to +/// tolerate some BER productions where this is helpful. +#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] +pub struct IndefiniteLength(Option<Length>); + +impl IndefiniteLength { + /// Length of `0`. + pub const ZERO: Self = Self(Some(Length::ZERO)); + + /// Length of `1`. + pub const ONE: Self = Self(Some(Length::ONE)); + + /// Indefinite length. + pub const INDEFINITE: Self = Self(None); +} + +impl IndefiniteLength { + /// Create a definite length from a type which can be converted into a + /// `Length`. + pub fn new(length: impl Into<Length>) -> Self { + Self(Some(length.into())) + } + + /// Is this length definite? + pub fn is_definite(self) -> bool { + self.0.is_some() + } + /// Is this length indefinite? + pub fn is_indefinite(self) -> bool { + self.0.is_none() + } +} + +impl<'a> Decode<'a> for IndefiniteLength { + fn decode<R: Reader<'a>>(reader: &mut R) -> Result<IndefiniteLength> { + if reader.peek_byte() == Some(INDEFINITE_LENGTH_OCTET) { + // Consume the byte we already peeked at. + let byte = reader.read_byte()?; + debug_assert_eq!(byte, INDEFINITE_LENGTH_OCTET); + + Ok(Self::INDEFINITE) + } else { + Length::decode(reader).map(Into::into) + } + } +} + +impl Encode for IndefiniteLength { + fn encoded_len(&self) -> Result<Length> { + match self.0 { + Some(length) => length.encoded_len(), + None => Ok(Length::ONE), + } + } + + fn encode(&self, writer: &mut impl Writer) -> Result<()> { + match self.0 { + Some(length) => length.encode(writer), + None => writer.write_byte(INDEFINITE_LENGTH_OCTET), + } + } +} + +impl From<Length> for IndefiniteLength { + fn from(length: Length) -> IndefiniteLength { + Self(Some(length)) + } +} + +impl From<Option<Length>> for IndefiniteLength { + fn from(length: Option<Length>) -> IndefiniteLength { + IndefiniteLength(length) + } +} + +impl From<IndefiniteLength> for Option<Length> { + fn from(length: IndefiniteLength) -> Option<Length> { + length.0 + } +} + +impl TryFrom<IndefiniteLength> for Length { + type Error = Error; + + fn try_from(length: IndefiniteLength) -> Result<Length> { + length.0.ok_or_else(|| ErrorKind::IndefiniteLength.into()) + } +} + #[cfg(test)] mod tests { - use super::Length; + use super::{IndefiniteLength, Length}; use crate::{Decode, DerOrd, Encode, ErrorKind}; use core::cmp::Ordering; @@ -355,8 +480,22 @@ mod tests { } #[test] - fn reject_indefinite_lengths() { + fn indefinite_lengths() { + // DER disallows indefinite lengths assert!(Length::from_der(&[0x80]).is_err()); + + // The `IndefiniteLength` type supports them + let indefinite_length = IndefiniteLength::from_der(&[0x80]).unwrap(); + assert!(indefinite_length.is_indefinite()); + assert_eq!(indefinite_length, IndefiniteLength::INDEFINITE); + + // It also supports definite lengths. + let length = IndefiniteLength::from_der(&[0x83, 0x01, 0x00, 0x00]).unwrap(); + assert!(length.is_definite()); + assert_eq!( + Length::try_from(0x10000u32).unwrap(), + length.try_into().unwrap() + ); } #[test] |