summaryrefslogtreecommitdiffstats
path: root/vendor/der/src/length.rs
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-18 02:49:42 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-18 02:49:42 +0000
commit837b550238aa671a591ccf282dddeab29cadb206 (patch)
tree914b6b8862bace72bd3245ca184d374b08d8a672 /vendor/der/src/length.rs
parentAdding debian version 1.70.0+dfsg2-1. (diff)
downloadrustc-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.rs147
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]