1 // Copyright 2022, The Android Open Source Project
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 //! Types and macros for communication between HAL and TA
16 
17 // Allow missing docs in this crate as the types here are generally 1:1 with the HAL
18 // interface definitions.
19 #![allow(missing_docs)]
20 #![no_std]
21 extern crate alloc;
22 
23 use alloc::{
24     format,
25     string::{String, ToString},
26     vec::Vec,
27 };
28 use coset::TaggedCborSerializable;
29 
30 /// Re-export of crate used for CBOR encoding.
31 pub use ciborium as cbor;
32 /// Re-export of crate used for COSE encoding.
33 pub use coset;
34 
35 pub mod keymint;
36 pub mod legacy;
37 pub mod rpc;
38 pub mod secureclock;
39 pub mod sharedsecret;
40 pub mod types;
41 pub use types::*;
42 
43 #[cfg(test)]
44 mod tests;
45 
46 /// Macro that emits an implementation of `TryFrom<i32>` for an enum type that has `[derive(N)]`
47 /// attached to it.  The implementation assumes that `ValueNotRecognized` has a variant with the
48 /// same name as the enum.
49 #[macro_export]
50 macro_rules! try_from_n {
51     { $ename:ident } => {
52         impl core::convert::TryFrom<i32> for $ename {
53             type Error = $crate::ValueNotRecognized;
54             fn try_from(value: i32) -> Result<Self, Self::Error> {
55                 Self::n(value).ok_or($crate::ValueNotRecognized::$ename)
56             }
57         }
58     };
59 }
60 
61 /// Function that mimics `vec![<val>; <len>]` but which detects allocation failure with the given
62 /// error.
vec_try_fill_with_alloc_err<T: Clone, E>( elem: T, len: usize, alloc_err: fn() -> E, ) -> Result<Vec<T>, E>63 pub fn vec_try_fill_with_alloc_err<T: Clone, E>(
64     elem: T,
65     len: usize,
66     alloc_err: fn() -> E,
67 ) -> Result<Vec<T>, E> {
68     let mut v = alloc::vec::Vec::new();
69     v.try_reserve(len).map_err(|_e| alloc_err())?;
70     v.resize(len, elem);
71     Ok(v)
72 }
73 
74 /// Function that mimics `vec![x1, x2, x3, x4]` but which detects allocation failure with the given
75 /// error.
vec_try4_with_alloc_err<T: Clone, E>( x1: T, x2: T, x3: T, x4: T, alloc_err: fn() -> E, ) -> Result<Vec<T>, E>76 pub fn vec_try4_with_alloc_err<T: Clone, E>(
77     x1: T,
78     x2: T,
79     x3: T,
80     x4: T,
81     alloc_err: fn() -> E,
82 ) -> Result<Vec<T>, E> {
83     let mut v = alloc::vec::Vec::new();
84     match v.try_reserve(4) {
85         Err(_e) => Err(alloc_err()),
86         Ok(_) => {
87             v.push(x1);
88             v.push(x2);
89             v.push(x3);
90             v.push(x4);
91             Ok(v)
92         }
93     }
94 }
95 
96 /// Function that mimics `vec![x1, x2, x3]` but which detects allocation failure with the given
97 /// error.
vec_try3_with_alloc_err<T: Clone, E>( x1: T, x2: T, x3: T, alloc_err: fn() -> E, ) -> Result<Vec<T>, E>98 pub fn vec_try3_with_alloc_err<T: Clone, E>(
99     x1: T,
100     x2: T,
101     x3: T,
102     alloc_err: fn() -> E,
103 ) -> Result<Vec<T>, E> {
104     let mut v = alloc::vec::Vec::new();
105     match v.try_reserve(3) {
106         Err(_e) => Err(alloc_err()),
107         Ok(_) => {
108             v.push(x1);
109             v.push(x2);
110             v.push(x3);
111             Ok(v)
112         }
113     }
114 }
115 
116 /// Function that mimics `vec![x1, x2]` but which detects allocation failure with the given error.
vec_try2_with_alloc_err<T: Clone, E>( x1: T, x2: T, alloc_err: fn() -> E, ) -> Result<Vec<T>, E>117 pub fn vec_try2_with_alloc_err<T: Clone, E>(
118     x1: T,
119     x2: T,
120     alloc_err: fn() -> E,
121 ) -> Result<Vec<T>, E> {
122     let mut v = alloc::vec::Vec::new();
123     match v.try_reserve(2) {
124         Err(_e) => Err(alloc_err()),
125         Ok(_) => {
126             v.push(x1);
127             v.push(x2);
128             Ok(v)
129         }
130     }
131 }
132 
133 /// Function that mimics `vec![x1]` but which detects allocation failure with the given error.
vec_try1_with_alloc_err<T: Clone, E>(x1: T, alloc_err: fn() -> E) -> Result<Vec<T>, E>134 pub fn vec_try1_with_alloc_err<T: Clone, E>(x1: T, alloc_err: fn() -> E) -> Result<Vec<T>, E> {
135     let mut v = alloc::vec::Vec::new();
136     match v.try_reserve(1) {
137         Err(_e) => Err(alloc_err()),
138         Ok(_) => {
139             v.push(x1);
140             Ok(v)
141         }
142     }
143 }
144 
145 /// Macro that mimics `vec!` but which detects allocation failure.
146 #[macro_export]
147 macro_rules! vec_try {
148     { $elem:expr ; $len:expr } => {
149         $crate::vec_try_fill_with_alloc_err($elem, $len, || $crate::CborError::AllocationFailed)
150     };
151     { $x1:expr, $x2:expr, $x3:expr, $x4:expr $(,)? } => {
152         $crate::vec_try4_with_alloc_err($x1, $x2, $x3, $x4, || $crate::CborError::AllocationFailed)
153     };
154     { $x1:expr, $x2:expr, $x3:expr $(,)? } => {
155         $crate::vec_try3_with_alloc_err($x1, $x2, $x3, || $crate::CborError::AllocationFailed)
156     };
157     { $x1:expr, $x2:expr $(,)? } => {
158         $crate::vec_try2_with_alloc_err($x1, $x2, || $crate::CborError::AllocationFailed)
159     };
160     { $x1:expr $(,)? } => {
161         $crate::vec_try1_with_alloc_err($x1, || $crate::CborError::AllocationFailed)
162     };
163 }
164 
165 /// Marker structure indicating that the EOF was encountered when reading CBOR data.
166 #[derive(Debug)]
167 pub struct EndOfFile;
168 
169 /// Error type for failures in encoding or decoding CBOR types.
170 pub enum CborError {
171     /// CBOR decoding failure.
172     DecodeFailed(cbor::de::Error<EndOfFile>),
173     /// CBOR encoding failure.
174     EncodeFailed,
175     /// CBOR input had extra data.
176     ExtraneousData,
177     /// Integer value outside expected range.
178     OutOfRangeIntegerValue,
179     /// Integer value that doesn't match expected set of allowed enum values.
180     NonEnumValue,
181     /// Unexpected CBOR item encountered (got, want).
182     UnexpectedItem(&'static str, &'static str),
183     /// Value conversion failure.
184     InvalidValue,
185     /// Allocation failure.
186     AllocationFailed,
187 }
188 
189 // Can only implement `Into` due to orphan trait rule.
190 #[allow(clippy::from_over_into)]
191 impl Into<coset::CoseError> for CborError {
into(self) -> coset::CoseError192     fn into(self) -> coset::CoseError {
193         match self {
194             CborError::DecodeFailed(inner) => coset::CoseError::DecodeFailed(match inner {
195                 cbor::de::Error::Io(_io) => cbor::de::Error::Io(coset::EndOfFile),
196                 cbor::de::Error::Syntax(v) => cbor::de::Error::Syntax(v),
197                 cbor::de::Error::Semantic(sz, msg) => cbor::de::Error::Semantic(sz, msg),
198                 cbor::de::Error::RecursionLimitExceeded => cbor::de::Error::RecursionLimitExceeded,
199             }),
200             CborError::EncodeFailed => coset::CoseError::EncodeFailed,
201             CborError::ExtraneousData => coset::CoseError::ExtraneousData,
202             CborError::OutOfRangeIntegerValue => coset::CoseError::OutOfRangeIntegerValue,
203             CborError::NonEnumValue => coset::CoseError::OutOfRangeIntegerValue,
204             CborError::UnexpectedItem(got, want) => coset::CoseError::UnexpectedItem(got, want),
205             CborError::InvalidValue => coset::CoseError::EncodeFailed,
206             CborError::AllocationFailed => coset::CoseError::EncodeFailed,
207         }
208     }
209 }
210 
211 impl<T> From<cbor::de::Error<T>> for CborError {
from(e: cbor::de::Error<T>) -> Self212     fn from(e: cbor::de::Error<T>) -> Self {
213         // Make sure we use our [`EndOfFile`] marker.
214         use cbor::de::Error::{Io, RecursionLimitExceeded, Semantic, Syntax};
215         let e = match e {
216             Io(_) => Io(EndOfFile),
217             Syntax(x) => Syntax(x),
218             Semantic(a, b) => Semantic(a, b),
219             RecursionLimitExceeded => RecursionLimitExceeded,
220         };
221         CborError::DecodeFailed(e)
222     }
223 }
224 
225 impl<T> From<cbor::ser::Error<T>> for CborError {
from(_e: cbor::ser::Error<T>) -> Self226     fn from(_e: cbor::ser::Error<T>) -> Self {
227         CborError::EncodeFailed
228     }
229 }
230 
231 impl From<cbor::value::Error> for CborError {
from(_e: cbor::value::Error) -> Self232     fn from(_e: cbor::value::Error) -> Self {
233         CborError::InvalidValue
234     }
235 }
236 
237 impl From<core::num::TryFromIntError> for CborError {
from(_: core::num::TryFromIntError) -> Self238     fn from(_: core::num::TryFromIntError) -> Self {
239         CborError::OutOfRangeIntegerValue
240     }
241 }
242 
243 impl From<coset::CoseError> for CborError {
from(e: coset::CoseError) -> Self244     fn from(e: coset::CoseError) -> Self {
245         match e {
246             coset::CoseError::DecodeFailed(inner) => CborError::DecodeFailed(match inner {
247                 cbor::de::Error::Io(_io) => cbor::de::Error::Io(EndOfFile),
248                 cbor::de::Error::Syntax(v) => cbor::de::Error::Syntax(v),
249                 cbor::de::Error::Semantic(sz, msg) => cbor::de::Error::Semantic(sz, msg),
250                 cbor::de::Error::RecursionLimitExceeded => cbor::de::Error::RecursionLimitExceeded,
251             }),
252             coset::CoseError::EncodeFailed => CborError::EncodeFailed,
253             coset::CoseError::ExtraneousData => CborError::ExtraneousData,
254             coset::CoseError::OutOfRangeIntegerValue => CborError::OutOfRangeIntegerValue,
255             coset::CoseError::UnregisteredIanaValue => CborError::NonEnumValue,
256             coset::CoseError::UnregisteredIanaNonPrivateValue => CborError::NonEnumValue,
257             coset::CoseError::UnexpectedItem(got, want) => CborError::UnexpectedItem(got, want),
258             coset::CoseError::DuplicateMapKey => {
259                 CborError::UnexpectedItem("dup map key", "unique keys")
260             }
261         }
262     }
263 }
264 
265 impl core::fmt::Debug for CborError {
fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result266     fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
267         match self {
268             CborError::DecodeFailed(de) => write!(f, "decode CBOR failure: {:?}", de),
269             CborError::EncodeFailed => write!(f, "encode CBOR failure"),
270             CborError::ExtraneousData => write!(f, "extraneous data in CBOR input"),
271             CborError::OutOfRangeIntegerValue => write!(f, "out of range integer value"),
272             CborError::NonEnumValue => write!(f, "integer not a valid enum value"),
273             CborError::UnexpectedItem(got, want) => write!(f, "got {}, expected {}", got, want),
274             CborError::InvalidValue => write!(f, "invalid CBOR value"),
275             CborError::AllocationFailed => write!(f, "allocation failed"),
276         }
277     }
278 }
279 
280 /// Return an error indicating that an unexpected CBOR type was encountered.
cbor_type_error<T>(value: &cbor::value::Value, want: &'static str) -> Result<T, CborError>281 pub fn cbor_type_error<T>(value: &cbor::value::Value, want: &'static str) -> Result<T, CborError> {
282     use cbor::value::Value;
283     let got = match value {
284         Value::Integer(_) => "int",
285         Value::Bytes(_) => "bstr",
286         Value::Text(_) => "tstr",
287         Value::Array(_) => "array",
288         Value::Map(_) => "map",
289         Value::Tag(_, _) => "tag",
290         Value::Float(_) => "float",
291         Value::Bool(_) => "bool",
292         Value::Null => "null",
293         _ => "unknown",
294     };
295     Err(CborError::UnexpectedItem(got, want))
296 }
297 
298 /// Read a [`cbor::value::Value`] from a byte slice, failing if any extra data remains after the
299 /// `Value` has been read.
read_to_value(mut slice: &[u8]) -> Result<cbor::value::Value, CborError>300 pub fn read_to_value(mut slice: &[u8]) -> Result<cbor::value::Value, CborError> {
301     let value = cbor::de::from_reader_with_recursion_limit(&mut slice, 16)?;
302     if slice.is_empty() {
303         Ok(value)
304     } else {
305         Err(CborError::ExtraneousData)
306     }
307 }
308 
309 /// Trait for types that can be converted to/from a [`cbor::value::Value`].
310 pub trait AsCborValue: Sized {
311     /// Convert a [`cbor::value::Value`] into an instance of the type.
from_cbor_value(value: cbor::value::Value) -> Result<Self, CborError>312     fn from_cbor_value(value: cbor::value::Value) -> Result<Self, CborError>;
313 
314     /// Convert the object into a [`cbor::value::Value`], consuming it along the way.
to_cbor_value(self) -> Result<cbor::value::Value, CborError>315     fn to_cbor_value(self) -> Result<cbor::value::Value, CborError>;
316 
317     /// Create an object instance from serialized CBOR data in a slice.
from_slice(slice: &[u8]) -> Result<Self, CborError>318     fn from_slice(slice: &[u8]) -> Result<Self, CborError> {
319         Self::from_cbor_value(read_to_value(slice)?)
320     }
321 
322     /// Serialize this object to a vector, consuming it along the way.
into_vec(self) -> Result<Vec<u8>, CborError>323     fn into_vec(self) -> Result<Vec<u8>, CborError> {
324         let mut data = Vec::new();
325         cbor::ser::into_writer(&self.to_cbor_value()?, &mut data)?;
326         Ok(data)
327     }
328 
329     /// Return the name used for this type in a CDDL schema, or `None` if this type does not have a
330     /// simple CDDL name. (For example, type `Vec<i64>` maps to a schema `(+ int)` but doesn't
331     /// have a name.)
cddl_typename() -> Option<String>332     fn cddl_typename() -> Option<String> {
333         None
334     }
335 
336     /// Return the CDDL schema for this type, or None if this type is primitive (e.g. `int`, `bool`,
337     /// `bstr`).
cddl_schema() -> Option<String>338     fn cddl_schema() -> Option<String> {
339         None
340     }
341 
342     /// Return a way to refer to this type in CDDL; prefer the CDDL type name if available,
343     /// use the explicit schema if not.
cddl_ref() -> String344     fn cddl_ref() -> String {
345         if let Some(item_name) = Self::cddl_typename() {
346             item_name
347         } else if let Some(item_schema) = Self::cddl_schema() {
348             item_schema
349         } else {
350             panic!("type with unknown CDDL")
351         }
352     }
353 }
354 
355 // Implement the local `AsCborValue` trait for `coset::CoseEncrypt0` ensuring/requiring
356 // use of the relevant CBOR tag.
357 impl AsCborValue for coset::CoseEncrypt0 {
from_cbor_value(value: cbor::value::Value) -> Result<Self, CborError>358     fn from_cbor_value(value: cbor::value::Value) -> Result<Self, CborError> {
359         match value {
360             cbor::value::Value::Tag(tag, inner_value) if tag == coset::CoseEncrypt0::TAG => {
361                 <coset::CoseEncrypt0 as coset::AsCborValue>::from_cbor_value(*inner_value)
362                     .map_err(|e| e.into())
363             }
364             cbor::value::Value::Tag(_, _) => Err(CborError::UnexpectedItem("tag", "tag 16")),
365             _ => cbor_type_error(&value, "tag 16"),
366         }
367     }
to_cbor_value(self) -> Result<cbor::value::Value, CborError>368     fn to_cbor_value(self) -> Result<cbor::value::Value, CborError> {
369         Ok(cbor::value::Value::Tag(
370             coset::CoseEncrypt0::TAG,
371             alloc::boxed::Box::new(coset::AsCborValue::to_cbor_value(self)?),
372         ))
373     }
cddl_schema() -> Option<String>374     fn cddl_schema() -> Option<String> {
375         Some(format!("#6.{}(Cose_Encrypt0)", coset::CoseEncrypt0::TAG))
376     }
377 }
378 
379 /// An `Option<T>` encodes as `( ? t )`, where `t` is whatever `T` encodes as in CDDL.
380 impl<T: AsCborValue> AsCborValue for Option<T> {
from_cbor_value(value: cbor::value::Value) -> Result<Self, CborError>381     fn from_cbor_value(value: cbor::value::Value) -> Result<Self, CborError> {
382         let mut arr = match value {
383             cbor::value::Value::Array(a) => a,
384             _ => return Err(CborError::UnexpectedItem("non-arr", "arr")),
385         };
386         match arr.len() {
387             0 => Ok(None),
388             1 => Ok(Some(<T>::from_cbor_value(arr.remove(0))?)),
389             _ => Err(CborError::UnexpectedItem("arr len >1", "arr len 0/1")),
390         }
391     }
392 
to_cbor_value(self) -> Result<cbor::value::Value, CborError>393     fn to_cbor_value(self) -> Result<cbor::value::Value, CborError> {
394         match self {
395             Some(t) => Ok(cbor::value::Value::Array(vec_try![t.to_cbor_value()?]?)),
396             None => Ok(cbor::value::Value::Array(Vec::new())),
397         }
398     }
399 
cddl_schema() -> Option<String>400     fn cddl_schema() -> Option<String> {
401         Some(format!("[? {}]", <T>::cddl_ref()))
402     }
403 }
404 
405 /// A `Vec<T>` encodes as `( * t )`, where `t` is whatever `T` encodes as in CDDL.
406 impl<T: AsCborValue> AsCborValue for Vec<T> {
from_cbor_value(value: cbor::value::Value) -> Result<Self, CborError>407     fn from_cbor_value(value: cbor::value::Value) -> Result<Self, CborError> {
408         let arr = match value {
409             cbor::value::Value::Array(a) => a,
410             _ => return cbor_type_error(&value, "arr"),
411         };
412         let results: Result<Vec<_>, _> = arr.into_iter().map(<T>::from_cbor_value).collect();
413         results
414     }
415 
to_cbor_value(self) -> Result<cbor::value::Value, CborError>416     fn to_cbor_value(self) -> Result<cbor::value::Value, CborError> {
417         let values: Result<Vec<_>, _> = self.into_iter().map(|v| v.to_cbor_value()).collect();
418         Ok(cbor::value::Value::Array(values?))
419     }
420 
cddl_schema() -> Option<String>421     fn cddl_schema() -> Option<String> {
422         Some(format!("[* {}]", <T>::cddl_ref()))
423     }
424 }
425 
426 impl AsCborValue for Vec<u8> {
from_cbor_value(value: cbor::value::Value) -> Result<Self, CborError>427     fn from_cbor_value(value: cbor::value::Value) -> Result<Self, CborError> {
428         match value {
429             cbor::value::Value::Bytes(bstr) => Ok(bstr),
430             _ => cbor_type_error(&value, "bstr"),
431         }
432     }
433 
to_cbor_value(self) -> Result<cbor::value::Value, CborError>434     fn to_cbor_value(self) -> Result<cbor::value::Value, CborError> {
435         Ok(cbor::value::Value::Bytes(self))
436     }
437 
cddl_typename() -> Option<String>438     fn cddl_typename() -> Option<String> {
439         Some("bstr".to_string())
440     }
441 }
442 
443 impl<const N: usize> AsCborValue for [u8; N] {
from_cbor_value(value: cbor::value::Value) -> Result<Self, CborError>444     fn from_cbor_value(value: cbor::value::Value) -> Result<Self, CborError> {
445         let data = match value {
446             cbor::value::Value::Bytes(bstr) => bstr,
447             _ => return cbor_type_error(&value, "bstr"),
448         };
449         data.try_into()
450             .map_err(|_e| CborError::UnexpectedItem("bstr other size", "bstr specific size"))
451     }
452 
to_cbor_value(self) -> Result<cbor::value::Value, CborError>453     fn to_cbor_value(self) -> Result<cbor::value::Value, CborError> {
454         let mut v = alloc::vec::Vec::new();
455         if v.try_reserve(self.len()).is_err() {
456             return Err(CborError::AllocationFailed);
457         }
458         v.extend_from_slice(&self);
459         Ok(cbor::value::Value::Bytes(v))
460     }
461 
cddl_typename() -> Option<String>462     fn cddl_typename() -> Option<String> {
463         Some(format!("bstr .size {}", N))
464     }
465 }
466 
467 impl AsCborValue for String {
from_cbor_value(value: cbor::value::Value) -> Result<Self, CborError>468     fn from_cbor_value(value: cbor::value::Value) -> Result<Self, CborError> {
469         match value {
470             cbor::value::Value::Text(s) => Ok(s),
471             _ => cbor_type_error(&value, "tstr"),
472         }
473     }
474 
to_cbor_value(self) -> Result<cbor::value::Value, CborError>475     fn to_cbor_value(self) -> Result<cbor::value::Value, CborError> {
476         Ok(cbor::value::Value::Text(self))
477     }
478 
cddl_typename() -> Option<String>479     fn cddl_typename() -> Option<String> {
480         Some("tstr".to_string())
481     }
482 }
483 
484 impl AsCborValue for u64 {
from_cbor_value(value: cbor::value::Value) -> Result<Self, CborError>485     fn from_cbor_value(value: cbor::value::Value) -> Result<Self, CborError> {
486         match value {
487             cbor::value::Value::Integer(i) => {
488                 i.try_into().map_err(|_| crate::CborError::OutOfRangeIntegerValue)
489             }
490             v => crate::cbor_type_error(&v, "u64"),
491         }
492     }
493 
to_cbor_value(self) -> Result<cbor::value::Value, CborError>494     fn to_cbor_value(self) -> Result<cbor::value::Value, CborError> {
495         Ok(cbor::value::Value::Integer(self.into()))
496     }
497 
cddl_typename() -> Option<String>498     fn cddl_typename() -> Option<String> {
499         Some("int".to_string())
500     }
501 }
502 
503 impl AsCborValue for i64 {
from_cbor_value(value: cbor::value::Value) -> Result<Self, CborError>504     fn from_cbor_value(value: cbor::value::Value) -> Result<Self, CborError> {
505         match value {
506             cbor::value::Value::Integer(i) => {
507                 i.try_into().map_err(|_| crate::CborError::OutOfRangeIntegerValue)
508             }
509             v => crate::cbor_type_error(&v, "i64"),
510         }
511     }
512 
to_cbor_value(self) -> Result<cbor::value::Value, CborError>513     fn to_cbor_value(self) -> Result<cbor::value::Value, CborError> {
514         Ok(cbor::value::Value::Integer(self.into()))
515     }
516 
cddl_typename() -> Option<String>517     fn cddl_typename() -> Option<String> {
518         Some("int".to_string())
519     }
520 }
521 
522 impl AsCborValue for u32 {
from_cbor_value(value: cbor::value::Value) -> Result<Self, CborError>523     fn from_cbor_value(value: cbor::value::Value) -> Result<Self, CborError> {
524         match value {
525             cbor::value::Value::Integer(i) => {
526                 i.try_into().map_err(|_| crate::CborError::OutOfRangeIntegerValue)
527             }
528             v => crate::cbor_type_error(&v, "u32"),
529         }
530     }
531 
to_cbor_value(self) -> Result<cbor::value::Value, CborError>532     fn to_cbor_value(self) -> Result<cbor::value::Value, CborError> {
533         Ok(cbor::value::Value::Integer(self.into()))
534     }
535 
cddl_typename() -> Option<String>536     fn cddl_typename() -> Option<String> {
537         Some("int".to_string())
538     }
539 }
540 
541 impl AsCborValue for bool {
from_cbor_value(value: cbor::value::Value) -> Result<Self, CborError>542     fn from_cbor_value(value: cbor::value::Value) -> Result<Self, CborError> {
543         match value {
544             cbor::value::Value::Bool(b) => Ok(b),
545             v => crate::cbor_type_error(&v, "bool"),
546         }
547     }
to_cbor_value(self) -> Result<cbor::value::Value, CborError>548     fn to_cbor_value(self) -> Result<cbor::value::Value, CborError> {
549         Ok(cbor::value::Value::Bool(self))
550     }
551 
cddl_typename() -> Option<String>552     fn cddl_typename() -> Option<String> {
553         Some("bool".to_string())
554     }
555 }
556 
557 impl AsCborValue for () {
from_cbor_value(value: cbor::value::Value) -> Result<Self, CborError>558     fn from_cbor_value(value: cbor::value::Value) -> Result<Self, CborError> {
559         match value {
560             cbor::value::Value::Null => Ok(()),
561             v => crate::cbor_type_error(&v, "null"),
562         }
563     }
to_cbor_value(self) -> Result<cbor::value::Value, CborError>564     fn to_cbor_value(self) -> Result<cbor::value::Value, CborError> {
565         Ok(cbor::value::Value::Null)
566     }
567 
cddl_typename() -> Option<String>568     fn cddl_typename() -> Option<String> {
569         Some("null".to_string())
570     }
571 }
572 
573 impl AsCborValue for i32 {
from_cbor_value(value: cbor::value::Value) -> Result<Self, CborError>574     fn from_cbor_value(value: cbor::value::Value) -> Result<Self, CborError> {
575         match value {
576             cbor::value::Value::Integer(i) => {
577                 i.try_into().map_err(|_| crate::CborError::OutOfRangeIntegerValue)
578             }
579             v => crate::cbor_type_error(&v, "i64"),
580         }
581     }
582 
to_cbor_value(self) -> Result<cbor::value::Value, CborError>583     fn to_cbor_value(self) -> Result<cbor::value::Value, CborError> {
584         Ok(cbor::value::Value::Integer(self.into()))
585     }
586 
cddl_typename() -> Option<String>587     fn cddl_typename() -> Option<String> {
588         Some("int".to_string())
589     }
590 }
591