1 //! Handling for data represented as CBOR. Cryptographic objects are encoded following COSE.
2
3 mod dice;
4 mod field_value;
5 mod publickey;
6 pub(crate) mod rkp;
7
8 use ciborium::value::CanonicalValue;
9 use ciborium::{de::from_reader, value::Value};
10 use std::collections::BTreeMap;
11 use std::io::Read;
12
13 type CiboriumError = ciborium::de::Error<std::io::Error>;
14
15 /// Decodes the provided binary CBOR-encoded value and returns a
16 /// ciborium::Value struct wrapped in Result.
value_from_bytes(mut bytes: &[u8]) -> Result<Value, CiboriumError>17 fn value_from_bytes(mut bytes: &[u8]) -> Result<Value, CiboriumError> {
18 let value = from_reader(bytes.by_ref())?;
19 // Ciborium tries to read one Value, but doesn't care if there is trailing data. We do.
20 if !bytes.is_empty() {
21 return Err(CiboriumError::Semantic(Some(0), "unexpected trailing data".to_string()));
22 }
23 Ok(value)
24 }
25
serialize(value: Value) -> Vec<u8>26 fn serialize(value: Value) -> Vec<u8> {
27 let mut data = Vec::new();
28 ciborium::ser::into_writer(&value, &mut data).unwrap();
29 data
30 }
31
canonicalize_map(value: Value) -> Result<Vec<u8>, CiboriumError>32 fn canonicalize_map(value: Value) -> Result<Vec<u8>, CiboriumError> {
33 match value {
34 Value::Map(map) => {
35 let btree: BTreeMap<CanonicalValue, Value> =
36 map.into_iter().map(|(k, v)| (CanonicalValue::from(k), v)).collect();
37
38 let mut data = Vec::new();
39 ciborium::ser::into_writer(&btree, &mut data).unwrap();
40 Ok(data)
41 }
42 _ => Err(CiboriumError::Semantic(None, format!("expected map, got {:?}", &value))),
43 }
44 }
45
46 #[cfg(test)]
47 mod tests {
48 use super::*;
49 use anyhow::Result;
50
51 #[test]
value_from_bytes_valid_succeeds() -> Result<()>52 fn value_from_bytes_valid_succeeds() -> Result<()> {
53 let bytes = [0x82, 0x04, 0x02]; // [4, 2]
54 let val = value_from_bytes(&bytes)?;
55 let array = val.as_array().unwrap();
56 assert_eq!(array.len(), 2);
57 Ok(())
58 }
59
60 #[test]
value_from_bytes_truncated_fails()61 fn value_from_bytes_truncated_fails() {
62 let bytes = [0x82, 0x04];
63 assert!(value_from_bytes(&bytes).is_err());
64 }
65
66 #[test]
value_from_bytes_trailing_bytes_fails()67 fn value_from_bytes_trailing_bytes_fails() {
68 let bytes = [0x82, 0x04, 0x02, 0x00];
69 assert!(value_from_bytes(&bytes).is_err());
70 }
71
72 #[test]
integers_and_lengths_are_canonicalized()73 fn integers_and_lengths_are_canonicalized() {
74 // Both are encodings of the following.
75 // [1, "12", {2 : 1, 1 : 2}]
76 let noncanonical_bytes = [
77 0x83, // array with size 3
78 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, // integer 1
79 0x7a, 0x00, 0x00, 0x00, 0x02, 0x31, 0x32, // string "12"
80 0xa2, // map with size 2
81 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x01, // 2 : 1
82 0x01, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, // 1 : 2
83 ];
84 // This is almost canonical because the keys of the map are not sorted.
85 // In order to be canonical, the entries of the map should be swapped.
86 let almost_canonical_bytes = [
87 0x83, // array with size 3
88 0x01, // integer 1
89 0x62, 0x31, 0x32, // string "12"
90 0xa2, // map with size 2
91 0x02, 0x01, // 2 : 1
92 0x01, 0x02, // 1 : 2
93 ];
94
95 let value = value_from_bytes(noncanonical_bytes.as_slice()).unwrap();
96 let serialized = serialize(value);
97
98 assert_eq!(serialized.as_slice(), almost_canonical_bytes);
99 }
100
101 #[test]
canonicalization_works()102 fn canonicalization_works() {
103 let bytes = [0xa2, 0x03, 0x04, 0x01, 0x02];
104 let value = value_from_bytes(&bytes).unwrap();
105 let canonicalized = canonicalize_map(value.clone()).unwrap();
106 assert_eq!(&hex::encode(canonicalized), "a201020304");
107 }
108 }
109