1 //! This module defines a helper for parsing fields in a CBOR map.
2 
3 use coset::{cbor::value::Value, AsCborValue, CoseEncrypt, CoseError, CoseMac0, CoseSign1};
4 use thiserror::Error;
5 
6 #[derive(Error, Debug)]
7 pub enum FieldValueError {
8     #[error("expected a value for field {0}, but none was found")]
9     Missing(&'static str),
10     #[error("expected bytes for field {0}, but found `{1:?}`")]
11     NotBytes(&'static str, Value),
12     #[error("expected string for field {0}, but found `{1:?}`")]
13     NotString(&'static str, Value),
14     #[error("expected null for field {0}, but found `{1:?}`")]
15     NotNull(&'static str, Value),
16     #[error("expected u32 for field {0}, but found `{1:?}`")]
17     NotU32(&'static str, Value),
18     #[error("expected i64 for field {0}, but found `{1:?}`")]
19     NotI64(&'static str, Value),
20     #[error("expected u64 for field {0}, but found `{1:?}`")]
21     NotU64(&'static str, Value),
22     #[error("expected boolean for field {0}, but found `{1:?}`")]
23     NotBool(&'static str, Value),
24     #[error("expected map for field {0}, but found `{1:?}`")]
25     NotMap(&'static str, Value),
26     #[error("expected array for field {0}, but found `{1:?}`")]
27     NotArray(&'static str, Value),
28     #[error("unable to parse field {0} as COSE_Sign1: `{1:?}`")]
29     CoseSign1ParseError(&'static str, CoseError),
30     #[error("unable to parse field {0} as COSE_Encrypt: `{1:?}`")]
31     CoseEncryptParseError(&'static str, CoseError),
32     #[error("unable to parse field {0} as COSE_Mac0: `{1:?}`")]
33     CoseMac0ParseError(&'static str, CoseError),
34     #[error("field {0} may be set only once; encountered multiple values: `{1:?}`, `{2:?}`")]
35     DuplicateField(&'static str, Value, Value),
36 }
37 
38 pub(super) struct FieldValue {
39     name: &'static str,
40     value: Option<Value>,
41 }
42 
43 impl FieldValue {
new(name: &'static str) -> Self44     pub fn new(name: &'static str) -> Self {
45         Self { name, value: None }
46     }
47 
from_optional_value(name: &'static str, value: Option<Value>) -> Self48     pub fn from_optional_value(name: &'static str, value: Option<Value>) -> Self {
49         Self { name, value }
50     }
51 
set_once(&mut self, value: Value) -> Result<(), FieldValueError>52     pub fn set_once(&mut self, value: Value) -> Result<(), FieldValueError> {
53         match &self.value {
54             None => {
55                 self.value = Some(value);
56                 Ok(())
57             }
58             Some(previous) => {
59                 Err(FieldValueError::DuplicateField(self.name, previous.clone(), value))
60             }
61         }
62     }
63 
is_bytes(&self) -> bool64     pub fn is_bytes(&self) -> bool {
65         self.value.as_ref().map_or(false, |v| v.is_bytes())
66     }
67 
into_optional_bytes(self) -> Result<Option<Vec<u8>>, FieldValueError>68     pub fn into_optional_bytes(self) -> Result<Option<Vec<u8>>, FieldValueError> {
69         self.value
70             .map(|v| match v {
71                 Value::Bytes(b) => Ok(b),
72                 _ => Err(FieldValueError::NotBytes(self.name, v)),
73             })
74             .transpose()
75     }
76 
into_bytes(self) -> Result<Vec<u8>, FieldValueError>77     pub fn into_bytes(self) -> Result<Vec<u8>, FieldValueError> {
78         require_present(self.name, self.into_optional_bytes())
79     }
80 
into_optional_string(self) -> Result<Option<String>, FieldValueError>81     pub fn into_optional_string(self) -> Result<Option<String>, FieldValueError> {
82         self.value
83             .map(|v| match v {
84                 Value::Text(s) => Ok(s),
85                 _ => Err(FieldValueError::NotString(self.name, v)),
86             })
87             .transpose()
88     }
89 
into_string(self) -> Result<String, FieldValueError>90     pub fn into_string(self) -> Result<String, FieldValueError> {
91         require_present(self.name, self.into_optional_string())
92     }
93 
into_cose_encrypt(self) -> Result<CoseEncrypt, FieldValueError>94     pub fn into_cose_encrypt(self) -> Result<CoseEncrypt, FieldValueError> {
95         require_present(self.name, self.into_optional_cose_encrypt())
96     }
97 
into_optional_cose_encrypt(self) -> Result<Option<CoseEncrypt>, FieldValueError>98     pub fn into_optional_cose_encrypt(self) -> Result<Option<CoseEncrypt>, FieldValueError> {
99         self.value
100             .map(|v| match v {
101                 Value::Array(_) => CoseEncrypt::from_cbor_value(v)
102                     .map_err(|e| FieldValueError::CoseEncryptParseError(self.name, e)),
103                 _ => Err(FieldValueError::NotArray(self.name, v)),
104             })
105             .transpose()
106     }
107 
into_cose_mac0(self) -> Result<CoseMac0, FieldValueError>108     pub fn into_cose_mac0(self) -> Result<CoseMac0, FieldValueError> {
109         require_present(self.name, self.into_optional_cose_mac0())
110     }
111 
into_optional_cose_mac0(self) -> Result<Option<CoseMac0>, FieldValueError>112     pub fn into_optional_cose_mac0(self) -> Result<Option<CoseMac0>, FieldValueError> {
113         self.value
114             .map(|v| match v {
115                 Value::Array(_) => CoseMac0::from_cbor_value(v)
116                     .map_err(|e| FieldValueError::CoseMac0ParseError(self.name, e)),
117                 _ => Err(FieldValueError::NotArray(self.name, v)),
118             })
119             .transpose()
120     }
121 
into_cose_sign1(self) -> Result<CoseSign1, FieldValueError>122     pub fn into_cose_sign1(self) -> Result<CoseSign1, FieldValueError> {
123         require_present(self.name, self.into_optional_cose_sign1())
124     }
125 
into_optional_cose_sign1(self) -> Result<Option<CoseSign1>, FieldValueError>126     pub fn into_optional_cose_sign1(self) -> Result<Option<CoseSign1>, FieldValueError> {
127         self.value
128             .map(|v| match v {
129                 Value::Array(_) => CoseSign1::from_cbor_value(v)
130                     .map_err(|e| FieldValueError::CoseSign1ParseError(self.name, e)),
131                 _ => Err(FieldValueError::NotArray(self.name, v)),
132             })
133             .transpose()
134     }
135 
into_array(self) -> Result<Vec<Value>, FieldValueError>136     pub fn into_array(self) -> Result<Vec<Value>, FieldValueError> {
137         require_present(self.name, self.into_optional_array())
138     }
139 
into_optional_array(self) -> Result<Option<Vec<Value>>, FieldValueError>140     pub fn into_optional_array(self) -> Result<Option<Vec<Value>>, FieldValueError> {
141         self.value
142             .map(|v| match v {
143                 Value::Array(v) => Ok(v),
144                 _ => Err(FieldValueError::NotArray(self.name, v)),
145             })
146             .transpose()
147     }
148 
into_map(self) -> Result<Vec<(Value, Value)>, FieldValueError>149     pub fn into_map(self) -> Result<Vec<(Value, Value)>, FieldValueError> {
150         require_present(self.name, self.into_optional_map())
151     }
152 
into_optional_map(self) -> Result<Option<Vec<(Value, Value)>>, FieldValueError>153     pub fn into_optional_map(self) -> Result<Option<Vec<(Value, Value)>>, FieldValueError> {
154         self.value
155             .map(|v| match v {
156                 Value::Map(v) => Ok(v),
157                 _ => Err(FieldValueError::NotMap(self.name, v)),
158             })
159             .transpose()
160     }
161 
into_bool(self) -> Result<bool, FieldValueError>162     pub fn into_bool(self) -> Result<bool, FieldValueError> {
163         require_present(self.name, self.into_optional_bool())
164     }
165 
into_optional_bool(self) -> Result<Option<bool>, FieldValueError>166     pub fn into_optional_bool(self) -> Result<Option<bool>, FieldValueError> {
167         self.value
168             .map(|v| match v {
169                 Value::Bool(b) => Ok(b),
170                 Value::Integer(i) if i == 0.into() => Ok(false),
171                 Value::Integer(i) if i == 1.into() => Ok(true),
172                 _ => Err(FieldValueError::NotBool(self.name, v)),
173             })
174             .transpose()
175     }
176 
is_null(&self) -> Result<bool, FieldValueError>177     pub fn is_null(&self) -> Result<bool, FieldValueError> {
178         // If there's no value, return false; if there is a null value, return true; anything else
179         // is an error.
180         self.value
181             .as_ref()
182             .map(|v| match *v {
183                 Value::Null => Ok(true),
184                 _ => Err(FieldValueError::NotNull(self.name, v.clone())),
185             })
186             .unwrap_or(Ok(false))
187     }
188 
is_integer(&self) -> bool189     pub fn is_integer(&self) -> bool {
190         self.value.as_ref().map_or(false, |v| v.is_integer())
191     }
192 
into_u32(self) -> Result<u32, FieldValueError>193     pub fn into_u32(self) -> Result<u32, FieldValueError> {
194         require_present(self.name, self.into_optional_u32())
195     }
196 
into_optional_u32(self) -> Result<Option<u32>, FieldValueError>197     pub fn into_optional_u32(self) -> Result<Option<u32>, FieldValueError> {
198         self.value
199             .map(|v| {
200                 let value =
201                     if let Value::Integer(i) = v { i128::from(i).try_into().ok() } else { None };
202                 value.ok_or_else(|| FieldValueError::NotU32(self.name, v))
203             })
204             .transpose()
205     }
206 
into_optional_i64(self) -> Result<Option<i64>, FieldValueError>207     pub fn into_optional_i64(self) -> Result<Option<i64>, FieldValueError> {
208         self.value
209             .map(|v| {
210                 let value =
211                     if let Value::Integer(i) = v { i128::from(i).try_into().ok() } else { None };
212                 value.ok_or_else(|| FieldValueError::NotI64(self.name, v))
213             })
214             .transpose()
215     }
216 
into_u64(self) -> Result<u64, FieldValueError>217     pub fn into_u64(self) -> Result<u64, FieldValueError> {
218         require_present(self.name, self.into_optional_u64())
219     }
220 
into_optional_u64(self) -> Result<Option<u64>, FieldValueError>221     pub fn into_optional_u64(self) -> Result<Option<u64>, FieldValueError> {
222         self.value
223             .map(|v| {
224                 let value =
225                     if let Value::Integer(i) = v { i128::from(i).try_into().ok() } else { None };
226                 value.ok_or_else(|| FieldValueError::NotU64(self.name, v))
227             })
228             .transpose()
229     }
230 }
231 
require_present<T>( name: &'static str, value: Result<Option<T>, FieldValueError>, ) -> Result<T, FieldValueError>232 fn require_present<T>(
233     name: &'static str,
234     value: Result<Option<T>, FieldValueError>,
235 ) -> Result<T, FieldValueError> {
236     value.and_then(|opt| opt.ok_or(FieldValueError::Missing(name)))
237 }
238