Skip to main content

structured_asn1/
length.rs

1//! Length octets, in both the definite and the indefinite form.
2
3use crate::error::ErrorCode;
4
5/// How long an element's contents are, when that is stated.
6#[derive(Debug, Clone, Copy, PartialEq, Eq)]
7pub enum Length {
8    /// The contents are this many bytes.
9    Definite(u64),
10    /// The contents run until an end-of-contents marker. BER only.
11    Indefinite,
12}
13
14/// Whether the caller will accept the indefinite form here.
15#[derive(Debug, Clone, Copy, PartialEq, Eq)]
16pub enum Encoding {
17    /// DER: definite lengths, encoded in the fewest bytes.
18    Der,
19    /// BER: also the indefinite form, and long-form lengths that could have
20    /// been shorter.
21    Ber,
22}
23
24impl Encoding {
25    /// Whether this encoding requires the fewest possible length bytes.
26    #[must_use]
27    pub fn is_der(self) -> bool {
28        self == Self::Der
29    }
30}
31
32/// Minimal definite-length octets, without a tag or copied value.
33///
34/// X.690 ยง10.1 requires the shortest definite form for DER. The scalar u64
35/// representation needs at most nine octets, so construction is bounded and
36/// allocation-free. A format can stream canonical framing around original
37/// borrowed fields without serializing or reparsing their payloads.
38/// <https://www.itu.int/rec/T-REC-X.690-202102-I/en>
39#[derive(Debug, Clone, Copy)]
40pub struct DerLength {
41    bytes: [u8; 9],
42    length: u8,
43}
44
45impl DerLength {
46    /// Encodes one scalar content length; this does not validate a value's
47    /// grammar, its availability, or the caller's overall output length.
48    #[must_use]
49    pub fn new(length: u64) -> Self {
50        let mut bytes = [0; 9];
51        if length < 128 {
52            bytes[0] = length.to_be_bytes()[7];
53            return Self { bytes, length: 1 };
54        }
55        let count = (64 - length.leading_zeros()).div_ceil(8).to_le_bytes()[0];
56        bytes[0] = 0x80 | count;
57        let count_usize = usize::from(count);
58        bytes[1..=count_usize].copy_from_slice(&length.to_be_bytes()[8 - count_usize..]);
59        Self {
60            bytes,
61            length: 1 + count,
62        }
63    }
64
65    /// Exact minimal length octets, not a whole element or source range.
66    #[must_use]
67    pub fn as_bytes(&self) -> &[u8] {
68        &self.bytes[..usize::from(self.length)]
69    }
70}
71
72impl AsRef<[u8]> for DerLength {
73    fn as_ref(&self) -> &[u8] {
74        self.as_bytes()
75    }
76}
77
78/// Reads the length octets at the front of `input`.
79///
80/// Returns the length and how many bytes it took.
81///
82/// Under DER two spellings are refused that BER allows, and both are refused
83/// because they let the same element be written two ways. The long form for a
84/// value under 128 is one; a long form carrying leading zero bytes is the
85/// other. Where a signature is computed over the bytes as they were sent, a
86/// parser that accepts either has agreed that two different documents are the
87/// same document.
88pub(crate) fn read_accounted(
89    input: &[u8],
90    encoding: Encoding,
91    offset: u64,
92    mut charge: impl FnMut(u64) -> Result<(), ErrorCode>,
93) -> Result<(Length, usize), (ErrorCode, u64)> {
94    let fail = |code| (code, offset);
95
96    charge(1).map_err(fail)?;
97
98    let first = *input
99        .first()
100        .ok_or_else(|| fail(ErrorCode::UnexpectedEnd))?;
101
102    if first & 0x80 == 0 {
103        return Ok((Length::Definite(u64::from(first)), 1));
104    }
105
106    let count = usize::from(first & 0x7f);
107
108    if count == 0 {
109        return match encoding {
110            Encoding::Ber => Ok((Length::Indefinite, 1)),
111            Encoding::Der => Err(fail(ErrorCode::IndefiniteLengthNotAllowed)),
112        };
113    }
114
115    // 0xff is reserved by X.690 and has no meaning in either encoding.
116    if count == 0x7f {
117        return Err(fail(ErrorCode::LengthTooLarge));
118    }
119
120    // Reserve the complete long-form scan before looking at any length octet.
121    charge(count as u64).map_err(fail)?;
122
123    let bytes = input
124        .get(1..=count)
125        .ok_or_else(|| fail(ErrorCode::UnexpectedEnd))?;
126
127    if encoding.is_der() {
128        // A leading zero means the same number would fit in fewer bytes.
129        if bytes[0] == 0 {
130            return Err(fail(ErrorCode::LengthNotMinimal));
131        }
132        // Anything under 128 belongs in the short form.
133        if count == 1 && bytes[0] < 0x80 {
134            return Err(fail(ErrorCode::LengthNotMinimal));
135        }
136    }
137
138    // More than eight significant bytes cannot be an offset into anything this
139    // machine can address, so the answer is the same whichever way it is read.
140    let significant = bytes.iter().skip_while(|byte| **byte == 0).count();
141    if significant > 8 {
142        return Err(fail(ErrorCode::LengthTooLarge));
143    }
144
145    let mut value: u64 = 0;
146    for byte in bytes {
147        value = value
148            .checked_mul(256)
149            .and_then(|shifted| shifted.checked_add(u64::from(*byte)))
150            .ok_or_else(|| fail(ErrorCode::LengthTooLarge))?;
151    }
152
153    Ok((Length::Definite(value), 1 + count))
154}
155
156#[cfg(test)]
157fn read(
158    input: &[u8],
159    encoding: Encoding,
160    offset: u64,
161) -> Result<(Length, usize), (ErrorCode, u64)> {
162    read_accounted(input, encoding, offset, |_| Ok(()))
163}
164
165#[cfg(test)]
166mod tests;