1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
//! ASN.1 length encoding and decoding
//!
//! ASN.1 uses two forms:
//! - Short form: Length < 128, encoded in one byte
//! - Long form: Length >= 128, first byte indicates number of length bytes
//! - Indefinite form: Only in BER/CER, not allowed in DER
use crate::error::{Error, Result};
#[cfg(not(feature = "std"))]
use alloc::vec::Vec;
/// ASN.1 length
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Length {
/// Definite length
Definite(usize),
/// Indefinite length (only in BER/CER, not allowed in DER)
Indefinite,
}
impl Length {
/// Calculate how many bytes this length requires when encoded
pub fn encoded_len(&self) -> Result<usize> {
match self {
Length::Definite(len) => {
if *len < 128 {
Ok(1)
} else {
let mut temp = *len;
let mut num_bytes = 0usize;
while temp > 0 {
temp >>= 8;
num_bytes = num_bytes.checked_add(1).ok_or(Error::LengthOverflow)?;
}
// 1 byte for length-of-length + num_bytes
num_bytes.checked_add(1).ok_or(Error::LengthOverflow)
}
}
Length::Indefinite => Ok(1), // Single 0x80 byte
}
}
/// Encode this length to a buffer
pub fn encode(&self, buffer: &mut Vec<u8>) -> Result<()> {
match self {
Length::Definite(len) => {
if *len < 128 {
// Short form
buffer.push(*len as u8);
} else {
// Long form
let mut temp = *len;
let mut num_bytes = 0;
while temp > 0 {
temp >>= 8;
num_bytes += 1;
}
if num_bytes > 127 {
return Err(Error::LengthTooLarge);
}
// First byte: 0x80 | num_bytes
buffer.push(0x80 | num_bytes);
// Encode length bytes in big-endian order
for i in (0..num_bytes).rev() {
buffer.push((*len >> (i * 8)) as u8);
}
}
Ok(())
}
Length::Indefinite => {
buffer.push(0x80);
Ok(())
}
}
}
/// Decode a length from a byte slice
/// Returns (length, bytes_consumed)
pub fn decode(bytes: &[u8], position: usize) -> Result<(Self, usize)> {
if bytes.is_empty() {
return Err(Error::UnexpectedEof { position });
}
let first_byte = bytes[0];
if first_byte < 0x80 {
// Short form (fast path - most common)
Ok((Length::Definite(first_byte as usize), 1))
} else if first_byte == 0x80 {
// Indefinite form
Ok((Length::Indefinite, 1))
} else {
// Long form (cold path)
#[cfg(feature = "unchecked")]
{
Self::decode_long_form_unchecked(bytes, first_byte, position)
}
#[cfg(not(feature = "unchecked"))]
{
Self::decode_long_form_checked(bytes, first_byte, position)
}
}
}
/// Decode long form length with validation (safe)
#[cfg(not(feature = "unchecked"))]
#[cold]
#[inline(never)]
fn decode_long_form_checked(
bytes: &[u8],
first_byte: u8,
position: usize,
) -> Result<(Self, usize)> {
let num_bytes = (first_byte & 0x7F) as usize;
if num_bytes == 0 {
// 0x80 is indefinite, handled above
// 0x80 with zero bytes is invalid
return Err(Error::InvalidLength { position });
}
if num_bytes > 8 {
// usize is at most 8 bytes on 64-bit systems
return Err(Error::InvalidLength { position });
}
if bytes.len() < 1 + num_bytes {
return Err(Error::UnexpectedEof {
position: position + bytes.len(),
});
}
let mut length: usize = 0;
for i in 0..num_bytes {
length = length.checked_shl(8).ok_or(Error::LengthOverflow)?;
length = length
.checked_add(bytes[1 + i] as usize)
.ok_or(Error::LengthOverflow)?;
}
// DER requires shortest encoding (no leading zeros)
// We'll check this in DER-specific validation
// For now, just decode
Ok((Length::Definite(length), 1 + num_bytes))
}
/// Decode long form length without validation (fast but assumes valid DER)
#[cfg(feature = "unchecked")]
#[cold]
#[inline(never)]
fn decode_long_form_unchecked(
bytes: &[u8],
first_byte: u8,
_position: usize,
) -> Result<(Self, usize)> {
let num_bytes = (first_byte & 0x7F) as usize;
// Skip validation - assume valid DER
let mut length: usize = 0;
for i in 0..num_bytes {
length = (length << 8) | (bytes[1 + i] as usize);
}
Ok((Length::Definite(length), 1 + num_bytes))
}
/// Get the definite length value, or error if indefinite
pub fn definite(&self) -> Result<usize> {
match self {
Length::Definite(len) => Ok(*len),
Length::Indefinite => Err(Error::Custom(
#[cfg(feature = "std")]
"Expected definite length".to_string(),
#[cfg(not(feature = "std"))]
"Expected definite length",
)),
}
}
/// Check if this is definite length
pub fn is_definite(&self) -> bool {
matches!(self, Length::Definite(_))
}
/// Check if this is indefinite length
pub fn is_indefinite(&self) -> bool {
matches!(self, Length::Indefinite)
}
}