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