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
use crate::{
Asn1DerError, DerObject, Sink, error::ErrorChain, rust::mem,
typed::{ DerTypeView, DerDecodable, DerEncodable }
};
#[derive(Copy, Clone)]
pub struct Integer<'a> {
object: DerObject<'a>
}
impl<'a> Integer<'a> {
#[cfg_attr(feature = "no_panic", no_panic::no_panic)]
pub fn new<S: Sink + Into<&'a[u8]>>(be_value: &[u8], is_negative: bool, mut sink: S)
-> Result<Self, Asn1DerError>
{
Self::write(be_value, is_negative, &mut sink).propagate(e!("Failed to construct integer"))?;
let object = DerObject::decode(sink.into())
.propagate(e!("Failed to load constructed integer"))?;
Ok(Self{ object })
}
#[cfg_attr(feature = "no_panic", no_panic::no_panic)]
pub fn is_negative(&self) -> bool {
match self.object.value().get(0) {
Some(first) => first & 0b1000_0000 != 0,
None => false
}
}
#[cfg_attr(feature = "no_panic", no_panic::no_panic)]
pub fn get_numbytes(&self) -> &[u8] {
let slice = self.object.value();
match slice.len() {
len if len >= 1 && slice[0] == 0 => &slice[1..],
_ => slice
}
}
#[cfg_attr(feature = "no_panic", no_panic::no_panic)]
pub fn copy_numbytes<T: AsMut<[u8]>>(&self, mut buf: T) -> Result<T, Asn1DerError> {
let (slice, buf_slice) = (self.get_numbytes(), buf.as_mut());
let to_skip = match slice.len() {
len if len > buf_slice.len() => Err(eunsupported!("The numeric value is too large"))?,
len => buf_slice.len() - len
};
buf_slice.iter_mut().skip(to_skip).zip(slice.iter()).for_each(|(t, b)| *t = *b);
Ok(buf)
}
#[cfg_attr(feature = "no_panic", no_panic::no_panic)] #[inline(always)]
pub fn write<S: Sink>(value: &[u8], is_negative: bool, sink: &mut S)
-> Result<(), Asn1DerError>
{
let to_skip = value.iter().take_while(|b| **b == 0).count();
let len = value.iter().skip(to_skip).count();
let value_prefix = match value.get(to_skip) {
None => b"\x00".as_ref(),
Some(first) if first & 0b1000_0000 != 0 && !is_negative => b"\x00".as_ref(),
_ => b"".as_ref()
};
let len = match len.checked_add(value_prefix.len()) {
Some(len) => len,
None => Err(eunsupported!("The number length would exceed `usize::max_value()`"))?
};
let mut value = value_prefix.iter()
.chain(value.iter().skip(to_skip));
DerObject::write(Self::TAG, len, &mut value, sink).propagate(e!("Failed to write integer"))
}
}
impl<'a> DerTypeView<'a> for Integer<'a> {
const TAG: u8 = b'\x02';
#[cfg_attr(feature = "no_panic", no_panic::no_panic)]
fn object(&self) -> DerObject<'a> {
self.object
}
}
impl<'a> DerDecodable<'a> for Integer<'a> {
#[cfg_attr(feature = "no_panic", no_panic::no_panic)]
fn load(object: DerObject<'a>) -> Result<Self, Asn1DerError> {
match object.value() {
_ if object.tag() != Self::TAG => Err(einval!("DER object is not an integer"))?,
value if value.is_empty() => Err(einval!("DER object is not a valid integer"))?,
value if value.len() >= 2 && value[0] == b'\x00' && value[1] & 0b1000_0000 == 0 =>
Err(einval!("DER object is not a valid integer")),
value if value.len() >= 2 && value[0] == b'\xff' && value[1] & 0b1000_0000 != 0 =>
Err(einval!("DER object is not a valid integer")),
_ => Ok(Self{ object }),
}
}
}
impl<'a> DerEncodable for Integer<'a> {
#[cfg_attr(feature = "no_panic", no_panic::no_panic)]
fn encode<S: Sink>(&self, sink: &mut S) -> Result<(), Asn1DerError> {
self.object().encode(sink).propagate(e!("Failed to encode integer"))
}
}
macro_rules! impl_dercodable {
(unsigned: $num:ty) => {
impl<'a> DerDecodable<'a> for $num {
#[cfg_attr(feature = "no_panic", no_panic::no_panic)]
fn load(object: DerObject<'a>) -> Result<Self, Asn1DerError> {
let integer = Integer::load(object).propagate(e!("Failed to load integer"))?;
let buf = integer.copy_numbytes([0; mem::size_of::<Self>()])
.propagate(e!("The numeric value is too large"))?;
match Self::from_be_bytes(buf) {
_ if integer.is_negative() =>
Err(eunsupported!("The numeric value is negative")),
num => Ok(num)
}
}
}
impl DerEncodable for $num {
#[cfg_attr(feature = "no_panic", no_panic::no_panic)]
fn encode<S: Sink>(&self, sink: &mut S) -> Result<(), Asn1DerError> {
Integer::write(&self.to_be_bytes(), false, sink)
}
}
};
(unsigned: $($num:ty),+) => ($( impl_dercodable!(unsigned: $num); )+);
}
impl_dercodable!(unsigned: u8, u16, u32, u64, u128, usize);