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