structured_asn1/
length.rs1use crate::error::ErrorCode;
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq)]
7pub enum Length {
8 Definite(u64),
10 Indefinite,
12}
13
14#[derive(Debug, Clone, Copy, PartialEq, Eq)]
16pub enum Encoding {
17 Der,
19 Ber,
22}
23
24impl Encoding {
25 #[must_use]
27 pub fn is_der(self) -> bool {
28 self == Self::Der
29 }
30}
31
32pub(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 if count == 0x7f {
71 return Err(fail(ErrorCode::LengthTooLarge));
72 }
73
74 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 if bytes[0] == 0 {
84 return Err(fail(ErrorCode::LengthNotMinimal));
85 }
86 if count == 1 && bytes[0] < 0x80 {
88 return Err(fail(ErrorCode::LengthNotMinimal));
89 }
90 }
91
92 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;