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