/src/OpenSK/libraries/cbor/src/writer.rs
Line | Count | Source |
1 | | // Copyright 2019 Google LLC |
2 | | // |
3 | | // Licensed under the Apache License, Version 2.0 (the "License"); |
4 | | // you may not use this file except in compliance with the License. |
5 | | // You may obtain a copy of the License at |
6 | | // |
7 | | // http://www.apache.org/licenses/LICENSE-2.0 |
8 | | // |
9 | | // Unless required by applicable law or agreed to in writing, software |
10 | | // distributed under the License is distributed on an "AS IS" BASIS, |
11 | | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
12 | | // See the License for the specific language governing permissions and |
13 | | // limitations under the License. |
14 | | |
15 | | //! Functionality for serializing CBOR values into bytes. |
16 | | |
17 | | use super::values::{Constants, Value, ValueImpl}; |
18 | | use alloc::vec::Vec; |
19 | | |
20 | | /// Possible errors from a serialization operation. |
21 | | #[derive(Debug, PartialEq)] |
22 | | pub enum EncoderError { |
23 | | TooMuchNesting, |
24 | | DuplicateMapKey, |
25 | | } |
26 | | |
27 | | /// Convert a [`Value`] to serialized CBOR data, consuming it along the way and appending to the provided vector. |
28 | | /// Maximum level of nesting supported is 127; more deeply nested structures will fail with |
29 | | /// [`EncoderError::TooMuchNesting`]. |
30 | 1.60k | pub fn write(value: Value, encoded_cbor: &mut Vec<u8>) -> Result<(), EncoderError> { |
31 | 1.60k | write_nested(value, encoded_cbor, Some(i8::MAX)) |
32 | 1.60k | } |
33 | | |
34 | | /// Convert a [`Value`] to serialized CBOR data, consuming it along the way and appending to the provided vector. If |
35 | | /// `max_nest` is `Some(max)`, then nested structures are only supported up to the given limit (returning |
36 | | /// [`DecoderError::TooMuchNesting`] if the limit is hit). |
37 | 11.6k | pub fn write_nested( |
38 | 11.6k | value: Value, |
39 | 11.6k | encoded_cbor: &mut Vec<u8>, |
40 | 11.6k | max_nest: Option<i8>, |
41 | 11.6k | ) -> Result<(), EncoderError> { |
42 | 11.6k | let mut writer = Writer::new(encoded_cbor); |
43 | 11.6k | writer.encode_cbor(value, max_nest) |
44 | 11.6k | } |
45 | | |
46 | | struct Writer<'a> { |
47 | | encoded_cbor: &'a mut Vec<u8>, |
48 | | } |
49 | | |
50 | | impl<'a> Writer<'a> { |
51 | 11.6k | pub fn new(encoded_cbor: &mut Vec<u8>) -> Writer<'_> { |
52 | 11.6k | Writer { encoded_cbor } |
53 | 11.6k | } |
54 | | |
55 | 6.47M | fn encode_cbor( |
56 | 6.47M | &mut self, |
57 | 6.47M | value: Value, |
58 | 6.47M | remaining_depth: Option<i8>, |
59 | 6.47M | ) -> Result<(), EncoderError> { |
60 | 6.47M | if remaining_depth.is_some_and(|d| d < 0) { |
61 | 0 | return Err(EncoderError::TooMuchNesting); |
62 | 6.47M | } |
63 | 6.47M | let type_label = value.0.type_label(); |
64 | 6.47M | match value.0 { |
65 | 1.18M | ValueImpl::Unsigned(unsigned) => self.start_item(type_label, unsigned), |
66 | 2.11M | ValueImpl::Negative(negative) => self.start_item(type_label, -(negative + 1) as u64), |
67 | 812k | ValueImpl::ByteString(byte_string) => { |
68 | 812k | self.start_item(type_label, byte_string.len() as u64); |
69 | 812k | self.encoded_cbor.extend(byte_string); |
70 | 812k | } |
71 | 52.7k | ValueImpl::TextString(text_string) => { |
72 | 52.7k | self.start_item(type_label, text_string.len() as u64); |
73 | 52.7k | self.encoded_cbor.extend(text_string.into_bytes()); |
74 | 52.7k | } |
75 | 497k | ValueImpl::Array(array) => { |
76 | 497k | self.start_item(type_label, array.len() as u64); |
77 | 4.33M | for el in array { |
78 | 3.83M | self.encode_cbor(el, remaining_depth.map(|d| d - 1))?; |
79 | | } |
80 | | } |
81 | 325k | ValueImpl::Map(map) => { |
82 | 325k | self.start_item(type_label, map.len() as u64); |
83 | 909k | for (k, v) in map { |
84 | 584k | self.encode_cbor(k, remaining_depth.map(|d| d - 1))?; |
85 | 584k | self.encode_cbor(v, remaining_depth.map(|d| d - 1))?; |
86 | | } |
87 | | } |
88 | 1.45M | ValueImpl::Tag(tag, inner_value) => { |
89 | 1.45M | self.start_item(type_label, tag); |
90 | 1.45M | self.encode_cbor(*inner_value, remaining_depth.map(|d| d - 1))?; |
91 | | } |
92 | 29.0k | ValueImpl::Simple(simple_value) => self.start_item(type_label, simple_value as u64), |
93 | | } |
94 | 6.47M | Ok(()) |
95 | 6.47M | } |
96 | | |
97 | 6.47M | fn start_item(&mut self, type_label: u8, size: u64) { |
98 | 6.47M | let (mut first_byte, shift) = match size { |
99 | 6.47M | 0..=23 => (size as u8, 0), |
100 | 1.22M | 24..=0xFF => (Constants::ADDITIONAL_INFORMATION_1_BYTE, 1), |
101 | 382k | 0x100..=0xFFFF => (Constants::ADDITIONAL_INFORMATION_2_BYTES, 2), |
102 | 213k | 0x10000..=0xFFFF_FFFF => (Constants::ADDITIONAL_INFORMATION_4_BYTES, 4), |
103 | 30.6k | _ => (Constants::ADDITIONAL_INFORMATION_8_BYTES, 8), |
104 | | }; |
105 | 6.47M | first_byte |= type_label << Constants::MAJOR_TYPE_BIT_SHIFT; |
106 | 6.47M | self.encoded_cbor.push(first_byte); |
107 | | |
108 | 6.47M | for i in (0..shift).rev() { |
109 | 2.15M | self.encoded_cbor.push((size >> (i * 8)) as u8); |
110 | 2.15M | } |
111 | 6.47M | } |
112 | | } |
113 | | |
114 | | #[cfg(test)] |
115 | | mod test { |
116 | | use super::*; |
117 | | use crate::{ |
118 | | cbor_array, cbor_array_vec, cbor_bytes, cbor_false, cbor_int, cbor_map, cbor_null, |
119 | | cbor_tagged, cbor_text, cbor_true, cbor_undefined, |
120 | | }; |
121 | | use alloc::vec; |
122 | | |
123 | | fn write_return(value: Value) -> Option<Vec<u8>> { |
124 | | let mut encoded_cbor = Vec::new(); |
125 | | if write(value, &mut encoded_cbor).is_ok() { |
126 | | Some(encoded_cbor) |
127 | | } else { |
128 | | None |
129 | | } |
130 | | } |
131 | | |
132 | | #[test] |
133 | | fn test_write_unsigned() { |
134 | | let cases = vec![ |
135 | | (0, vec![0x00]), |
136 | | (1, vec![0x01]), |
137 | | (10, vec![0x0A]), |
138 | | (23, vec![0x17]), |
139 | | (24, vec![0x18, 0x18]), |
140 | | (25, vec![0x18, 0x19]), |
141 | | (100, vec![0x18, 0x64]), |
142 | | (1000, vec![0x19, 0x03, 0xE8]), |
143 | | (1000000, vec![0x1A, 0x00, 0x0F, 0x42, 0x40]), |
144 | | (0xFFFFFFFF, vec![0x1A, 0xFF, 0xFF, 0xFF, 0xFF]), |
145 | | ( |
146 | | 0x100000000, |
147 | | vec![0x1B, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00], |
148 | | ), |
149 | | ( |
150 | | core::i64::MAX, |
151 | | vec![0x1B, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF], |
152 | | ), |
153 | | ]; |
154 | | for (unsigned, correct_cbor) in cases { |
155 | | assert_eq!(write_return(cbor_int!(unsigned)), Some(correct_cbor)); |
156 | | } |
157 | | } |
158 | | |
159 | | #[test] |
160 | | fn test_write_negative() { |
161 | | let cases = vec![ |
162 | | (-1, vec![0x20]), |
163 | | (-10, vec![0x29]), |
164 | | (-23, vec![0x36]), |
165 | | (-24, vec![0x37]), |
166 | | (-25, vec![0x38, 0x18]), |
167 | | (-100, vec![0x38, 0x63]), |
168 | | (-1000, vec![0x39, 0x03, 0xE7]), |
169 | | (-4294967296, vec![0x3A, 0xFF, 0xFF, 0xFF, 0xFF]), |
170 | | ( |
171 | | -4294967297, |
172 | | vec![0x3B, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00], |
173 | | ), |
174 | | ( |
175 | | core::i64::MIN, |
176 | | vec![0x3B, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF], |
177 | | ), |
178 | | ]; |
179 | | for (negative, correct_cbor) in cases { |
180 | | assert_eq!(write_return(cbor_int!(negative)), Some(correct_cbor)); |
181 | | } |
182 | | } |
183 | | |
184 | | #[test] |
185 | | fn test_write_byte_string() { |
186 | | let cases = vec![ |
187 | | (vec![], vec![0x40]), |
188 | | ( |
189 | | vec![0x01, 0x02, 0x03, 0x04], |
190 | | vec![0x44, 0x01, 0x02, 0x03, 0x04], |
191 | | ), |
192 | | ]; |
193 | | for (byte_string, correct_cbor) in cases { |
194 | | assert_eq!(write_return(cbor_bytes!(byte_string)), Some(correct_cbor)); |
195 | | } |
196 | | } |
197 | | |
198 | | #[test] |
199 | | fn test_write_text_string() { |
200 | | let unicode_3byte = vec![0xE6, 0xB0, 0xB4]; |
201 | | let cases = vec![ |
202 | | ("", vec![0x60]), |
203 | | ("a", vec![0x61, 0x61]), |
204 | | ("IETF", vec![0x64, 0x49, 0x45, 0x54, 0x46]), |
205 | | ("\"\\", vec![0x62, 0x22, 0x5C]), |
206 | | ("ü", vec![0x62, 0xC3, 0xBC]), |
207 | | ( |
208 | | core::str::from_utf8(&unicode_3byte).unwrap(), |
209 | | vec![0x63, 0xE6, 0xB0, 0xB4], |
210 | | ), |
211 | | ("𐅑", vec![0x64, 0xF0, 0x90, 0x85, 0x91]), |
212 | | ]; |
213 | | for (text_string, correct_cbor) in cases { |
214 | | assert_eq!(write_return(cbor_text!(text_string)), Some(correct_cbor)); |
215 | | } |
216 | | } |
217 | | |
218 | | #[test] |
219 | | fn test_write_array() { |
220 | | let value_vec: Vec<_> = (1..26).collect(); |
221 | | let expected_cbor = vec![ |
222 | | 0x98, 0x19, // array of 25 elements |
223 | | 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, |
224 | | 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x18, 0x18, 0x19, |
225 | | ]; |
226 | | assert_eq!( |
227 | | write_return(cbor_array_vec!(value_vec)), |
228 | | Some(expected_cbor) |
229 | | ); |
230 | | } |
231 | | |
232 | | #[test] |
233 | | fn test_write_map() { |
234 | | let value_map = cbor_map! { |
235 | | 0 => "a", |
236 | | 23 => "b", |
237 | | 24 => "c", |
238 | | core::u8::MAX as i64 => "d", |
239 | | 256 => "e", |
240 | | core::u16::MAX as i64 => "f", |
241 | | 65536 => "g", |
242 | | core::u32::MAX as i64 => "h", |
243 | | 4294967296_i64 => "i", |
244 | | core::i64::MAX => "j", |
245 | | -1 => "k", |
246 | | -24 => "l", |
247 | | -25 => "m", |
248 | | -256 => "n", |
249 | | -257 => "o", |
250 | | -65537 => "p", |
251 | | -4294967296_i64 => "q", |
252 | | -4294967297_i64 => "r", |
253 | | core::i64::MIN => "s", |
254 | | b"a" => 2, |
255 | | b"bar" => 3, |
256 | | b"foo" => 4, |
257 | | "" => ".", |
258 | | "e" => "E", |
259 | | "aa" => "AA", |
260 | | }; |
261 | | let expected_cbor = vec![ |
262 | | 0xb8, 0x19, // map of 25 pairs: |
263 | | 0x00, // key 0 |
264 | | 0x61, 0x61, // value "a" |
265 | | 0x17, // key 23 |
266 | | 0x61, 0x62, // value "b" |
267 | | 0x18, 0x18, // key 24 |
268 | | 0x61, 0x63, // value "c" |
269 | | 0x18, 0xFF, // key 255 |
270 | | 0x61, 0x64, // value "d" |
271 | | 0x19, 0x01, 0x00, // key 256 |
272 | | 0x61, 0x65, // value "e" |
273 | | 0x19, 0xFF, 0xFF, // key 65535 |
274 | | 0x61, 0x66, // value "f" |
275 | | 0x1A, 0x00, 0x01, 0x00, 0x00, // key 65536 |
276 | | 0x61, 0x67, // value "g" |
277 | | 0x1A, 0xFF, 0xFF, 0xFF, 0xFF, // key 4294967295 |
278 | | 0x61, 0x68, // value "h" |
279 | | // key 4294967296 |
280 | | 0x1B, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x61, 0x69, // value "i" |
281 | | // key INT64_MAX |
282 | | 0x1b, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x61, 0x6a, // value "j" |
283 | | 0x20, // key -1 |
284 | | 0x61, 0x6b, // value "k" |
285 | | 0x37, // key -24 |
286 | | 0x61, 0x6c, // value "l" |
287 | | 0x38, 0x18, // key -25 |
288 | | 0x61, 0x6d, // value "m" |
289 | | 0x38, 0xFF, // key -256 |
290 | | 0x61, 0x6e, // value "n" |
291 | | 0x39, 0x01, 0x00, // key -257 |
292 | | 0x61, 0x6f, // value "o" |
293 | | 0x3A, 0x00, 0x01, 0x00, 0x00, // key -65537 |
294 | | 0x61, 0x70, // value "p" |
295 | | 0x3A, 0xFF, 0xFF, 0xFF, 0xFF, // key -4294967296 |
296 | | 0x61, 0x71, // value "q" |
297 | | // key -4294967297 |
298 | | 0x3B, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x61, 0x72, // value "r" |
299 | | // key INT64_MIN |
300 | | 0x3b, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x61, 0x73, // value "s" |
301 | | 0x41, b'a', // byte string "a" |
302 | | 0x02, 0x43, b'b', b'a', b'r', // byte string "bar" |
303 | | 0x03, 0x43, b'f', b'o', b'o', // byte string "foo" |
304 | | 0x04, 0x60, // key "" |
305 | | 0x61, 0x2e, // value "." |
306 | | 0x61, 0x65, // key "e" |
307 | | 0x61, 0x45, // value "E" |
308 | | 0x62, 0x61, 0x61, // key "aa" |
309 | | 0x62, 0x41, 0x41, // value "AA" |
310 | | ]; |
311 | | assert_eq!(write_return(value_map), Some(expected_cbor)); |
312 | | } |
313 | | |
314 | | #[test] |
315 | | fn test_write_map_sorted() { |
316 | | let sorted_map = cbor_map! { |
317 | | 0 => "a", |
318 | | 1 => "b", |
319 | | -1 => "c", |
320 | | -2 => "d", |
321 | | b"a" => "e", |
322 | | b"b" => "f", |
323 | | "" => "g", |
324 | | "c" => "h", |
325 | | }; |
326 | | let unsorted_map = cbor_map! { |
327 | | 1 => "b", |
328 | | -2 => "d", |
329 | | b"b" => "f", |
330 | | "c" => "h", |
331 | | "" => "g", |
332 | | b"a" => "e", |
333 | | -1 => "c", |
334 | | 0 => "a", |
335 | | }; |
336 | | assert_eq!(write_return(sorted_map), write_return(unsorted_map)); |
337 | | } |
338 | | |
339 | | #[test] |
340 | | fn test_write_map_with_array() { |
341 | | let value_map = cbor_map! { |
342 | | "a" => 1, |
343 | | "b" => cbor_array![2, 3], |
344 | | }; |
345 | | let expected_cbor = vec![ |
346 | | 0xa2, // map of 2 pairs |
347 | | 0x61, 0x61, // "a" |
348 | | 0x01, 0x61, 0x62, // "b" |
349 | | 0x82, // array with 2 elements |
350 | | 0x02, 0x03, |
351 | | ]; |
352 | | assert_eq!(write_return(value_map), Some(expected_cbor)); |
353 | | } |
354 | | |
355 | | #[test] |
356 | | fn test_write_nested_map() { |
357 | | let value_map = cbor_map! { |
358 | | "a" => 1, |
359 | | "b" => cbor_map! { |
360 | | "c" => 2, |
361 | | "d" => 3, |
362 | | }, |
363 | | }; |
364 | | let expected_cbor = vec![ |
365 | | 0xa2, // map of 2 pairs |
366 | | 0x61, 0x61, // "a" |
367 | | 0x01, 0x61, 0x62, // "b" |
368 | | 0xa2, // map of 2 pairs |
369 | | 0x61, 0x63, // "c" |
370 | | 0x02, 0x61, 0x64, // "d" |
371 | | 0x03, |
372 | | ]; |
373 | | assert_eq!(write_return(value_map), Some(expected_cbor)); |
374 | | } |
375 | | |
376 | | #[test] |
377 | | fn test_write_tagged() { |
378 | | let cases = vec![ |
379 | | (cbor_tagged!(6, cbor_int!(0x42)), vec![0xc6, 0x18, 0x42]), |
380 | | (cbor_tagged!(1, cbor_true!()), vec![0xc1, 0xf5]), |
381 | | ( |
382 | | cbor_tagged!( |
383 | | 1000, |
384 | | cbor_map! { |
385 | | "a" => 1, |
386 | | "b" => cbor_array![2, 3], |
387 | | } |
388 | | ), |
389 | | vec![ |
390 | | 0xd9, 0x03, 0xe8, 0xa2, // map of 2 pairs |
391 | | 0x61, 0x61, // "a" |
392 | | 0x01, 0x61, 0x62, // "b" |
393 | | 0x82, // array with 2 elements |
394 | | 0x02, 0x03, |
395 | | ], |
396 | | ), |
397 | | ]; |
398 | | for (value, correct_cbor) in cases { |
399 | | assert_eq!(write_return(value), Some(correct_cbor)); |
400 | | } |
401 | | } |
402 | | |
403 | | #[test] |
404 | | fn test_write_simple() { |
405 | | let cases = vec![ |
406 | | (cbor_false!(), vec![0xF4]), |
407 | | (cbor_true!(), vec![0xF5]), |
408 | | (cbor_null!(), vec![0xF6]), |
409 | | (cbor_undefined!(), vec![0xF7]), |
410 | | ]; |
411 | | for (value, correct_cbor) in cases { |
412 | | assert_eq!(write_return(value), Some(correct_cbor)); |
413 | | } |
414 | | } |
415 | | |
416 | | #[test] |
417 | | fn test_write_single_levels() { |
418 | | let simple_array: Value = cbor_array![2]; |
419 | | let simple_map: Value = cbor_map! {"b" => 3}; |
420 | | let positive_cases = vec![ |
421 | | (cbor_int!(1), 0), |
422 | | (cbor_bytes!(vec![0x01, 0x02, 0x03, 0x04]), 0), |
423 | | (cbor_text!("a"), 0), |
424 | | (cbor_array![], 0), |
425 | | (cbor_map! {}, 0), |
426 | | (simple_array.clone(), 1), |
427 | | (simple_map.clone(), 1), |
428 | | ]; |
429 | | let negative_cases = vec![(simple_array.clone(), 0), (simple_map.clone(), 0)]; |
430 | | for (value, level) in positive_cases { |
431 | | let mut buf = Vec::new(); |
432 | | let mut writer = Writer::new(&mut buf); |
433 | | assert!(writer.encode_cbor(value, Some(level)).is_ok()); |
434 | | } |
435 | | for (value, level) in negative_cases { |
436 | | let mut buf = Vec::new(); |
437 | | let mut writer = Writer::new(&mut buf); |
438 | | assert!(!writer.encode_cbor(value, Some(level)).is_ok()); |
439 | | } |
440 | | } |
441 | | |
442 | | #[test] |
443 | | fn test_write_nested_map_levels() { |
444 | | let cbor_map: Value = cbor_map! { |
445 | | "a" => 1, |
446 | | "b" => cbor_map! { |
447 | | "c" => 2, |
448 | | "d" => 3, |
449 | | }, |
450 | | }; |
451 | | |
452 | | let mut buf = Vec::new(); |
453 | | let mut writer = Writer::new(&mut buf); |
454 | | assert!(writer.encode_cbor(cbor_map.clone(), Some(2)).is_ok()); |
455 | | assert!(writer.encode_cbor(cbor_map.clone(), None).is_ok()); |
456 | | writer = Writer::new(&mut buf); |
457 | | assert!(writer.encode_cbor(cbor_map, Some(1)).is_err()); |
458 | | } |
459 | | |
460 | | #[test] |
461 | | fn test_write_unbalanced_nested_containers() { |
462 | | let cbor_array: Value = cbor_array![ |
463 | | 1, |
464 | | 2, |
465 | | 3, |
466 | | cbor_map! { |
467 | | "a" => 1, |
468 | | "b" => cbor_map! { |
469 | | "c" => 2, |
470 | | "d" => 3, |
471 | | }, |
472 | | }, |
473 | | ]; |
474 | | |
475 | | let mut buf = Vec::new(); |
476 | | let mut writer = Writer::new(&mut buf); |
477 | | assert!(writer.encode_cbor(cbor_array.clone(), Some(3)).is_ok()); |
478 | | writer = Writer::new(&mut buf); |
479 | | assert!(writer.encode_cbor(cbor_array, Some(2)).is_err()); |
480 | | } |
481 | | |
482 | | #[test] |
483 | | fn test_write_overly_nested() { |
484 | | let cbor_map: Value = cbor_map! { |
485 | | "a" => 1, |
486 | | "b" => cbor_map! { |
487 | | "c" => 2, |
488 | | "d" => 3, |
489 | | "h" => cbor_map! { |
490 | | "e" => 4, |
491 | | "f" => 5, |
492 | | "g" => cbor_array![ |
493 | | 6, |
494 | | 7, |
495 | | cbor_array![ |
496 | | 8 |
497 | | ] |
498 | | ], |
499 | | }, |
500 | | }, |
501 | | }; |
502 | | |
503 | | let mut buf = Vec::new(); |
504 | | let mut writer = Writer::new(&mut buf); |
505 | | assert!(writer.encode_cbor(cbor_map.clone(), Some(5)).is_ok()); |
506 | | assert!(writer.encode_cbor(cbor_map.clone(), None).is_ok()); |
507 | | writer = Writer::new(&mut buf); |
508 | | assert!(writer.encode_cbor(cbor_map, Some(4)).is_err()); |
509 | | } |
510 | | } |