• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //! Functionality for KeyMint implementation that is common across HAL and TA.
2 
3 #![no_std]
4 extern crate alloc;
5 
6 use alloc::{
7     string::{String, ToString},
8     vec::Vec,
9 };
10 use core::convert::From;
11 use der::ErrorKind;
12 use kmr_wire::{cbor, keymint::ErrorCode, rpc, CborError};
13 
14 pub use kmr_wire as wire;
15 
16 pub mod crypto;
17 pub mod keyblob;
18 pub mod tag;
19 
20 /// General error type.
21 #[derive(Debug)]
22 pub enum Error {
23     Cbor(CborError),
24     Der(ErrorKind),
25     // The IKeyMintDevice, ISharedSecret and ISecureClock HALs all share the same numbering
26     // space for error codes, encoded here as [`kmr_wire::keymint::ErrorCode`].
27     Hal(ErrorCode, String),
28     // The IRemotelyProvisionedComponent HAL uses its own error codes.
29     Rpc(rpc::ErrorCode, String),
30     // For an allocation error, hold a string literal rather than an allocated String to
31     // avoid allocating in error path.
32     Alloc(&'static str),
33 }
34 
35 // The following macros for error generation allow the message portion to be automatically
36 // compiled out in future, avoiding potential information leakage and allocation.
37 
38 /// Macro to build an [`Error::Hal`] instance for a specific [`ErrorCode`] value known at compile
39 /// time: `km_err!(InvalidTag, "some {} format", arg)`.
40 #[macro_export]
41 macro_rules! km_err {
42     { $error_code:ident, $($arg:tt)+ } => {
43         $crate::Error::Hal(kmr_wire::keymint::ErrorCode::$error_code,
44                            alloc::format!("{}:{}: {}", file!(), line!(), format_args!($($arg)+))) };
45 }
46 
47 /// Macro to build an [`Error::Hal`] instance:
48 /// `km_verr!(rc, "some {} format", arg)`.
49 #[macro_export]
50 macro_rules! km_verr {
51     { $error_code:expr, $($arg:tt)+ } => {
52         $crate::Error::Hal($error_code,
53                            alloc::format!("{}:{}: {}", file!(), line!(), format_args!($($arg)+))) };
54 }
55 
56 /// Macro to build an [`Error::Alloc`] instance. Note that this builds a `&'static str` at compile
57 /// time, so there is no allocation needed for the message (which would be failure-prone when
58 /// dealing with an allocation failure).
59 #[macro_export]
60 macro_rules! alloc_err {
61     { $len:expr } => {
62         $crate::Error::Alloc(
63             concat!(file!(), ":", line!(), ": failed allocation of size ", stringify!($len))
64         )
65     }
66 }
67 
68 /// Macro to build an [`Error::Rpc`] instance for a specific [`rpc::ErrorCode`] value known at
69 /// compile time: `rpc_err!(Removed, "some {} format", arg)`.
70 #[macro_export]
71 macro_rules! rpc_err {
72     { $error_code:ident, $($arg:tt)+ } => {
73         $crate::Error::Rpc(kmr_wire::rpc::ErrorCode::$error_code,
74                            alloc::format!("{}:{}: {}", file!(), line!(), format_args!($($arg)+))) };
75 }
76 
77 /// Macro to allocate a `Vec<T>` with the given length reserved, detecting allocation failure.
78 #[macro_export]
79 macro_rules! vec_try_with_capacity {
80     { $len:expr} => {
81         {
82             let mut v = alloc::vec::Vec::new();
83             match v.try_reserve($len) {
84                 Err(_e) => Err($crate::alloc_err!($len)),
85                 Ok(_) => Ok(v),
86             }
87         }
88     }
89 }
90 
91 /// Macro that mimics `vec!` but which detects allocation failure.
92 #[macro_export]
93 macro_rules! vec_try {
94     { $elem:expr ; $len:expr } => {
95         kmr_wire::vec_try_fill_with_alloc_err($elem, $len, || $crate::alloc_err!($len))
96     };
97     { $x1:expr, $x2:expr, $x3:expr, $x4:expr $(,)? } => {
98         kmr_wire::vec_try4_with_alloc_err($x1, $x2, $x3, $x4, || $crate::alloc_err!(4))
99     };
100     { $x1:expr, $x2:expr, $x3:expr $(,)? } => {
101         kmr_wire::vec_try3_with_alloc_err($x1, $x2, $x3, || $crate::alloc_err!(3))
102     };
103     { $x1:expr, $x2:expr $(,)? } => {
104         kmr_wire::vec_try2_with_alloc_err($x1, $x2, || $crate::alloc_err!(2))
105     };
106     { $x1:expr $(,)? } => {
107         kmr_wire::vec_try1_with_alloc_err($x1, || $crate::alloc_err!(1))
108     };
109 }
110 
111 /// Function that mimics `slice.to_vec()` but which detects allocation failures.
112 #[inline]
try_to_vec<T: Clone>(s: &[T]) -> Result<Vec<T>, Error>113 pub fn try_to_vec<T: Clone>(s: &[T]) -> Result<Vec<T>, Error> {
114     let mut v = vec_try_with_capacity!(s.len())?;
115     v.extend_from_slice(s);
116     Ok(v)
117 }
118 
119 /// Extension trait to provide fallible-allocation variants of `Vec` methods.
120 pub trait FallibleAllocExt<T> {
try_push(&mut self, value: T) -> Result<(), alloc::collections::TryReserveError>121     fn try_push(&mut self, value: T) -> Result<(), alloc::collections::TryReserveError>;
try_extend_from_slice( &mut self, other: &[T], ) -> Result<(), alloc::collections::TryReserveError> where T: Clone122     fn try_extend_from_slice(
123         &mut self,
124         other: &[T],
125     ) -> Result<(), alloc::collections::TryReserveError>
126     where
127         T: Clone;
128 }
129 
130 impl<T> FallibleAllocExt<T> for Vec<T> {
try_push(&mut self, value: T) -> Result<(), alloc::collections::TryReserveError>131     fn try_push(&mut self, value: T) -> Result<(), alloc::collections::TryReserveError> {
132         self.try_reserve(1)?;
133         self.push(value);
134         Ok(())
135     }
try_extend_from_slice( &mut self, other: &[T], ) -> Result<(), alloc::collections::TryReserveError> where T: Clone,136     fn try_extend_from_slice(
137         &mut self,
138         other: &[T],
139     ) -> Result<(), alloc::collections::TryReserveError>
140     where
141         T: Clone,
142     {
143         self.try_reserve(other.len())?;
144         self.extend_from_slice(other);
145         Ok(())
146     }
147 }
148 
149 impl From<alloc::collections::TryReserveError> for Error {
from(_e: alloc::collections::TryReserveError) -> Self150     fn from(_e: alloc::collections::TryReserveError) -> Self {
151         Error::Hal(
152             kmr_wire::keymint::ErrorCode::MemoryAllocationFailed,
153             "allocation of Vec failed".to_string(),
154         )
155     }
156 }
157 
158 impl From<CborError> for Error {
from(e: CborError) -> Self159     fn from(e: CborError) -> Self {
160         Error::Cbor(e)
161     }
162 }
163 
164 impl From<cbor::value::Error> for Error {
from(e: cbor::value::Error) -> Self165     fn from(e: cbor::value::Error) -> Self {
166         Self::Cbor(e.into())
167     }
168 }
169 
170 impl From<der::Error> for Error {
from(e: der::Error) -> Self171     fn from(e: der::Error) -> Self {
172         Error::Der(e.kind())
173     }
174 }
175 
176 /// Check for an expected error.
177 #[macro_export]
178 macro_rules! expect_err {
179     ($result:expr, $err_msg:expr) => {
180         assert!(
181             $result.is_err(),
182             "Expected error containing '{}', got success {:?}",
183             $err_msg,
184             $result
185         );
186         let err = $result.err();
187         assert!(
188             alloc::format!("{:?}", err).contains($err_msg),
189             "Unexpected error {:?}, doesn't contain '{}'",
190             err,
191             $err_msg
192         );
193     };
194 }
195