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/// Reads the length octets at the front of `input`.
33///
34/// Returns the length and how many bytes it took.
35///
36/// Under DER two spellings are refused that BER allows, and both are refused
37/// because they let the same element be written two ways. The long form for a
38/// value under 128 is one; a long form carrying leading zero bytes is the
39/// other. Where a signature is computed over the bytes as they were sent, a
40/// parser that accepts either has agreed that two different documents are the
41/// same document.
42pub(crate) fn read_accounted(
43    input: &[u8],
44    encoding: Encoding,
45    offset: u64,
46    mut charge: impl FnMut(u64) -> Result<(), ErrorCode>,
47) -> Result<(Length, usize), (ErrorCode, u64)> {
48    let fail = |code| (code, offset);
49
50    charge(1).map_err(fail)?;
51
52    let first = *input
53        .first()
54        .ok_or_else(|| fail(ErrorCode::UnexpectedEnd))?;
55
56    if first & 0x80 == 0 {
57        return Ok((Length::Definite(u64::from(first)), 1));
58    }
59
60    let count = usize::from(first & 0x7f);
61
62    if count == 0 {
63        return match encoding {
64            Encoding::Ber => Ok((Length::Indefinite, 1)),
65            Encoding::Der => Err(fail(ErrorCode::IndefiniteLengthNotAllowed)),
66        };
67    }
68
69    // 0xff is reserved by X.690 and has no meaning in either encoding.
70    if count == 0x7f {
71        return Err(fail(ErrorCode::LengthTooLarge));
72    }
73
74    // Reserve the complete long-form scan before looking at any length octet.
75    charge(count as u64).map_err(fail)?;
76
77    let bytes = input
78        .get(1..=count)
79        .ok_or_else(|| fail(ErrorCode::UnexpectedEnd))?;
80
81    if encoding.is_der() {
82        // A leading zero means the same number would fit in fewer bytes.
83        if bytes[0] == 0 {
84            return Err(fail(ErrorCode::LengthNotMinimal));
85        }
86        // Anything under 128 belongs in the short form.
87        if count == 1 && bytes[0] < 0x80 {
88            return Err(fail(ErrorCode::LengthNotMinimal));
89        }
90    }
91
92    // More than eight significant bytes cannot be an offset into anything this
93    // machine can address, so the answer is the same whichever way it is read.
94    let significant = bytes.iter().skip_while(|byte| **byte == 0).count();
95    if significant > 8 {
96        return Err(fail(ErrorCode::LengthTooLarge));
97    }
98
99    let mut value: u64 = 0;
100    for byte in bytes {
101        value = value
102            .checked_mul(256)
103            .and_then(|shifted| shifted.checked_add(u64::from(*byte)))
104            .ok_or_else(|| fail(ErrorCode::LengthTooLarge))?;
105    }
106
107    Ok((Length::Definite(value), 1 + count))
108}
109
110#[cfg(test)]
111fn read(
112    input: &[u8],
113    encoding: Encoding,
114    offset: u64,
115) -> Result<(Length, usize), (ErrorCode, u64)> {
116    read_accounted(input, encoding, offset, |_| Ok(()))
117}
118
119#[cfg(test)]
120mod tests;