1use core::fmt::Write;
19
20use time::OffsetDateTime;
21
22use super::{CertConsumer, MAX_DEPTH};
23use crate::error::{Error, ErrorCode};
24use crate::utils::epoch::MATTER_EPOCH_SECS;
25
26#[derive(Debug)]
27#[cfg_attr(feature = "defmt", derive(defmt::Format))]
28pub struct ASN1Writer<'a> {
29 buf: &'a mut [u8],
30 offset: usize,
32 depth: [usize; MAX_DEPTH],
35 current_depth: usize,
37}
38
39const RESERVE_LEN_BYTES: usize = 3;
40impl<'a> ASN1Writer<'a> {
41 pub fn new(buf: &'a mut [u8]) -> Self {
42 Self {
43 buf,
44 offset: 0,
45 depth: [0; MAX_DEPTH],
46 current_depth: 0,
47 }
48 }
49
50 pub fn append_with<F>(&mut self, size: usize, f: F) -> Result<(), Error>
51 where
52 F: FnOnce(&mut Self),
53 {
54 if self.offset + size <= self.buf.len() {
55 f(self);
56 self.offset += size;
57 return Ok(());
58 }
59 Err(ErrorCode::BufferTooSmall.into())
60 }
61
62 pub fn append_tlv<F>(&mut self, tag: u8, len: usize, f: F) -> Result<(), Error>
63 where
64 F: FnOnce(&mut Self),
65 {
66 let total_len = 1 + ASN1Writer::bytes_to_encode_len(len)? + len;
67 if self.offset + total_len <= self.buf.len() {
68 self.buf[self.offset] = tag;
69 self.offset += 1;
70 self.offset = self.encode_len(self.offset, len)?;
71 f(self);
72 self.offset += len;
73 return Ok(());
74 }
75 Err(ErrorCode::BufferTooSmall.into())
76 }
77
78 fn add_compound(&mut self, val: u8) -> Result<(), Error> {
79 self.append_with(1 + RESERVE_LEN_BYTES, |t| t.buf[t.offset] = val)?;
82 self.depth[self.current_depth] = self.offset;
83 self.current_depth += 1;
84 if self.current_depth >= MAX_DEPTH {
85 Err(ErrorCode::BufferTooSmall.into())
86 } else {
87 Ok(())
88 }
89 }
90
91 fn encode_len(&mut self, mut at_offset: usize, len: usize) -> Result<usize, Error> {
92 let mut bytes_of_len = ASN1Writer::bytes_to_encode_len(len)?;
93 if bytes_of_len > 1 {
94 self.buf[at_offset] = (0x80 | (bytes_of_len - 1)) as u8;
95 at_offset += 1;
96 bytes_of_len -= 1;
97 }
98
99 let mut octet_number = bytes_of_len - 1;
102 loop {
104 self.buf[at_offset] = ((len >> (octet_number * 8)) & 0xff) as u8;
105
106 at_offset += 1;
107 if octet_number == 0 {
108 break;
109 }
110 octet_number -= 1;
111 }
112
113 Ok(at_offset)
114 }
115
116 fn end_compound(&mut self) -> Result<(), Error> {
117 if self.current_depth == 0 {
118 Err(ErrorCode::Invalid)?;
119 }
120 let seq_len = self.get_compound_len();
121 let write_offset = self.get_length_encoding_offset();
122
123 let mut write_offset = self.encode_len(write_offset, seq_len)?;
124
125 let shift_len = self.depth[self.current_depth - 1] - write_offset;
127 if shift_len > 0 {
128 for _i in 0..seq_len {
129 self.buf[write_offset] = self.buf[write_offset + shift_len];
130 write_offset += 1;
131 }
132 }
133 self.current_depth -= 1;
134 self.offset -= shift_len;
135 Ok(())
136 }
137
138 fn get_compound_len(&self) -> usize {
139 self.offset - self.depth[self.current_depth - 1]
140 }
141
142 fn bytes_to_encode_len(len: usize) -> Result<usize, Error> {
143 let len = if len < 128 {
144 1
146 } else if len < 256 {
147 2
149 } else if len < 65536 {
150 3
152 } else {
153 Err(ErrorCode::BufferTooSmall)?
154 };
155 Ok(len)
156 }
157
158 fn get_length_encoding_offset(&self) -> usize {
159 self.depth[self.current_depth - 1] - RESERVE_LEN_BYTES
160 }
161
162 pub fn as_slice(&self) -> &[u8] {
163 &self.buf[..self.offset]
164 }
165
166 fn write_str(&mut self, vtype: u8, s: &[u8]) -> Result<(), Error> {
167 self.append_tlv(vtype, s.len(), |t| {
168 let end_offset = t.offset + s.len();
169 t.buf[t.offset..end_offset].copy_from_slice(s);
170 })
171 }
172}
173
174impl CertConsumer for ASN1Writer<'_> {
175 fn start_seq(&mut self, _tag: &str) -> Result<(), Error> {
176 self.add_compound(0x30)
177 }
178
179 fn end_seq(&mut self) -> Result<(), Error> {
180 self.end_compound()
181 }
182
183 fn integer(&mut self, _tag: &str, i: &[u8]) -> Result<(), Error> {
184 self.write_str(0x02, i)
185 }
186
187 fn printstr(&mut self, _tag: &str, s: &str) -> Result<(), Error> {
188 self.write_str(0x13, s.as_bytes())
190 }
191
192 fn utf8str(&mut self, _tag: &str, s: &str) -> Result<(), Error> {
193 self.write_str(0x0c, s.as_bytes())
195 }
196
197 fn bitstr(&mut self, _tag: &str, truncate: bool, s: &[u8]) -> Result<(), Error> {
198 let mut last_byte = s.len() - 1;
202 let mut num_of_zero = 0;
203 if truncate {
204 while s[last_byte] == 0 {
205 last_byte -= 1;
206 }
207 num_of_zero = s[last_byte].trailing_zeros() as u8;
210 }
211 let s = &s[..(last_byte + 1)];
212 self.append_tlv(0x03, s.len() + 1, |t| {
213 t.buf[t.offset] = num_of_zero;
214 let end_offset = t.offset + 1 + s.len();
215 t.buf[(t.offset + 1)..end_offset].copy_from_slice(s);
216 })
217 }
218
219 fn ostr(&mut self, _tag: &str, s: &[u8]) -> Result<(), Error> {
220 self.write_str(0x04, s)
222 }
223
224 fn start_compound_ostr(&mut self, _tag: &str) -> Result<(), Error> {
225 self.add_compound(0x04)
227 }
228
229 fn end_compound_ostr(&mut self) -> Result<(), Error> {
230 self.end_compound()
231 }
232
233 fn bool(&mut self, _tag: &str, b: bool) -> Result<(), Error> {
234 self.append_tlv(0x01, 1, |t| {
235 if b {
236 t.buf[t.offset] = 0xFF;
237 } else {
238 t.buf[t.offset] = 0x00;
239 }
240 })
241 }
242
243 fn start_set(&mut self, _tag: &str) -> Result<(), Error> {
244 self.add_compound(0x31)
245 }
246
247 fn end_set(&mut self) -> Result<(), Error> {
248 self.end_compound()
249 }
250
251 fn ctx(&mut self, _tag: &str, id: u8, val: &[u8]) -> Result<(), Error> {
252 self.write_str(0x80 | id, val)
253 }
254
255 fn start_ctx(&mut self, _tag: &str, val: u8) -> Result<(), Error> {
256 self.add_compound(0xA0 | val)
257 }
258
259 fn end_ctx(&mut self) -> Result<(), Error> {
260 self.end_compound()
261 }
262
263 fn oid(&mut self, _tag: &str, oid: &[u8]) -> Result<(), Error> {
264 self.write_str(0x06, oid)
265 }
266
267 fn utctime(&mut self, _tag: &str, epoch: u64) -> Result<(), Error> {
268 let matter_epoch = MATTER_EPOCH_SECS + epoch;
269
270 let dt = unwrap!(
271 OffsetDateTime::from_unix_timestamp(matter_epoch as _),
272 "DateTimeError"
273 );
274
275 let mut time_str: heapless::String<32> = heapless::String::<32>::new();
276
277 if dt.year() >= 2050 {
278 write_unwrap!(
280 &mut time_str,
281 "{:04}{:02}{:02}{:02}{:02}{:02}Z",
282 dt.year(),
283 dt.month() as u8,
284 dt.day(),
285 dt.hour(),
286 dt.minute(),
287 dt.second()
288 );
289 self.write_str(0x18, time_str.as_bytes())
290 } else {
291 write_unwrap!(
292 &mut time_str,
293 "{:02}{:02}{:02}{:02}{:02}{:02}Z",
294 dt.year() % 100,
295 dt.month() as u8,
296 dt.day(),
297 dt.hour(),
298 dt.minute(),
299 dt.second()
300 );
301 self.write_str(0x17, time_str.as_bytes())
302 }
303 }
304
305 fn raw(&mut self, _tag: &str, data: &[u8]) -> Result<(), Error> {
306 self.append_with(data.len(), |t| {
307 let end_offset = t.offset + data.len();
308 t.buf[t.offset..end_offset].copy_from_slice(data);
309 })
310 }
311}