der_parser/ber/integer.rs
1use crate::error::*;
2
3/// Decode an unsigned integer into a big endian byte slice with all leading
4/// zeroes removed.
5///
6/// Returns a byte array of the requested size containing a big endian integer.
7fn remove_zeroes(bytes: &[u8]) -> Result<&[u8], BerError> {
8 // skip leading 0s
9 match bytes {
10 // [] => Err(BerError::DerConstraintFailed),
11 [0] => Ok(bytes),
12 // [0, byte, ..] if *byte < 0x80 => Err(BerError::DerConstraintFailed),
13 // [0, rest @ ..] => Ok(&rest),
14 [0, rest @ ..] => remove_zeroes(rest),
15 // [byte, ..] if *byte >= 0x80 => Err(BerError::IntegerTooLarge),
16 _ => Ok(bytes),
17 }
18}
19
20// XXX const generics require rustc >= 1.51
21// /// Decode an unsigned integer into a byte array of the requested size
22// /// containing a big endian integer.
23// pub(crate) fn decode_array_uint<const N: usize>(bytes: &[u8]) -> Result<[u8; N], BerError> {
24// // Check if MSB is set *before* leading zeroes
25// if is_highest_bit_set(bytes) {
26// return Err(BerError::IntegerNegative);
27// }
28// let input = remove_zeroes(bytes)?;
29
30// if input.len() > N {
31// return Err(BerError::IntegerTooLarge);
32// }
33
34// // Input has leading zeroes removed, so we need to add them back
35// let mut output = [0u8; N];
36// assert!(input.len() <= N);
37// output[N.saturating_sub(input.len())..].copy_from_slice(input);
38// Ok(output)
39// }
40
41pub(crate) fn decode_array_uint8(bytes: &[u8]) -> Result<[u8; 8], BerError> {
42 // Check if MSB is set *before* leading zeroes
43 if is_highest_bit_set(bytes) {
44 return Err(BerError::IntegerNegative);
45 }
46 let input = remove_zeroes(bytes)?;
47
48 if input.len() > 8 {
49 return Err(BerError::IntegerTooLarge);
50 }
51
52 // Input has leading zeroes removed, so we need to add them back
53 let mut output = [0u8; 8];
54 assert!(input.len() <= 8);
55 output[8_usize.saturating_sub(input.len())..].copy_from_slice(input);
56 Ok(output)
57}
58
59pub(crate) fn decode_array_uint4(bytes: &[u8]) -> Result<[u8; 4], BerError> {
60 // Check if MSB is set *before* leading zeroes
61 if is_highest_bit_set(bytes) {
62 return Err(BerError::IntegerNegative);
63 }
64 let input = remove_zeroes(bytes)?;
65
66 if input.len() > 4 {
67 return Err(BerError::IntegerTooLarge);
68 }
69
70 // Input has leading zeroes removed, so we need to add them back
71 let mut output = [0u8; 4];
72 assert!(input.len() <= 4);
73 output[4_usize.saturating_sub(input.len())..].copy_from_slice(input);
74 Ok(output)
75}
76
77// XXX const generics require rustc >= 1.51
78// /// Decode an unsigned integer of the specified size.
79// ///
80// /// Returns a byte array of the requested size containing a big endian integer.
81// pub(crate) fn decode_array_int<const N: usize>(input: &[u8]) -> Result<[u8; N], BerError> {
82// let input = remove_zeroes(input)?;
83
84// if input.len() > N {
85// return Err(BerError::IntegerTooLarge);
86// }
87
88// // any.tag().assert_eq(Tag::Integer)?;
89// let mut output = [0xFFu8; N];
90// let offset = N.saturating_sub(input.len());
91// output[offset..].copy_from_slice(input);
92// Ok(output)
93// }
94
95pub(crate) fn decode_array_int8(input: &[u8]) -> Result<[u8; 8], BerError> {
96 let input = remove_zeroes(input)?;
97
98 if input.len() > 8 {
99 return Err(BerError::IntegerTooLarge);
100 }
101
102 // any.tag().assert_eq(Tag::Integer)?;
103 let mut output = [0xFFu8; 8];
104 let offset = 8_usize.saturating_sub(input.len());
105 output[offset..].copy_from_slice(input);
106 Ok(output)
107}
108
109pub(crate) fn decode_array_int4(input: &[u8]) -> Result<[u8; 4], BerError> {
110 let input = remove_zeroes(input)?;
111
112 if input.len() > 4 {
113 return Err(BerError::IntegerTooLarge);
114 }
115
116 // any.tag().assert_eq(Tag::Integer)?;
117 let mut output = [0xFFu8; 4];
118 let offset = 4_usize.saturating_sub(input.len());
119 output[offset..].copy_from_slice(input);
120 Ok(output)
121}
122
123/// Is the highest bit of the first byte in the slice 1? (if present)
124#[inline]
125pub(crate) fn is_highest_bit_set(bytes: &[u8]) -> bool {
126 bytes
127 .first()
128 .map(|byte| byte & 0b10000000 != 0)
129 .unwrap_or(false)
130}