Skip to content

der: remove IndefiniteLength #1807

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
May 4, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
124 changes: 1 addition & 123 deletions der/src/length.rs
Original file line number Diff line number Diff line change
Expand Up @@ -308,116 +308,10 @@ impl<'a> arbitrary::Arbitrary<'a> for Length {
}
}

/// 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 {
type Error = Error;

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)]
#[allow(clippy::unwrap_used)]
mod tests {
use super::{IndefiniteLength, Length};
use super::Length;
use crate::{Decode, DerOrd, Encode, ErrorKind};
use core::cmp::Ordering;

Expand Down Expand Up @@ -482,22 +376,6 @@ mod tests {
);
}

#[test]
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::from(0x10000u32), length.try_into().unwrap());
}

#[test]
fn add_overflows_when_max_length_exceeded() {
let result = Length::MAX + Length::ONE;
Expand Down
2 changes: 1 addition & 1 deletion der/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -374,7 +374,7 @@ pub use crate::{
encoding_rules::EncodingRules,
error::{Error, ErrorKind, Result},
header::Header,
length::{IndefiniteLength, Length},
length::Length,
ord::{DerOrd, ValueOrd},
reader::{Reader, slice::SliceReader},
tag::{Class, FixedTag, IsConstructed, Tag, TagMode, TagNumber, Tagged},
Expand Down