blob: 0326610f68519d87d859f67360814e8220a2e908 [file] [log] [blame]
Janis Danisevskis7d77a762020-07-20 13:03:31 -07001// Copyright 2020, 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//! Keystore error provides convenience methods and types for Keystore error handling.
16//! Clients of Keystore expect one of two error codes, i.e., a Keystore ResponseCode as
17//! defined by the Keystore AIDL interface, or a Keymint ErrorCode as defined by
18//! the Keymint HAL specification.
19//! This crate provides `Error` which can wrap both. It is to be used
20//! internally by Keystore to diagnose error conditions that need to be reported to
21//! the client. To report the error condition to the client the Keystore AIDL
22//! interface defines a wire type `Result` which is distinctly different from Rust's
23//! `enum Result<T,E>`.
24//!
25//! This crate provides the convenience method `map_or_log_err` to convert `anyhow::Error`
26//! into this wire type. In addition to handling the conversion of `Error`
27//! to the `Result` wire type it handles any other error by mapping it to
28//! `ResponseCode::SystemError` and logs any error condition.
29//!
30//! Keystore functions should use `anyhow::Result` to return error conditions, and
31//! context should be added every time an error is forwarded.
32
33use std::cmp::PartialEq;
Janis Danisevskis7d77a762020-07-20 13:03:31 -070034
Janis Danisevskise24f3472020-08-12 17:58:49 -070035pub use android_hardware_keymint::aidl::android::hardware::keymint::ErrorCode as Ec;
36pub use android_security_keystore2::aidl::android::security::keystore2::ResponseCode as Rc;
37
38use android_hardware_keymint::aidl::android::hardware::keymint::ErrorCode::ErrorCode;
39use android_security_keystore2::aidl::android::security::keystore2::ResponseCode::ResponseCode;
Janis Danisevskis7d77a762020-07-20 13:03:31 -070040
Janis Danisevskisce995432020-07-21 12:22:34 -070041use keystore2_selinux as selinux;
42
Janis Danisevskis017d2092020-09-02 10:15:52 -070043use android_security_keystore2::binder::{
44 ExceptionCode, Result as BinderResult, Status as BinderStatus,
45};
Janis Danisevskis7d77a762020-07-20 13:03:31 -070046
47/// This is the main Keystore error type. It wraps the Keystore `ResponseCode` generated
48/// from AIDL in the `Rc` variant and Keymint `ErrorCode` in the Km variant.
49#[derive(Debug, thiserror::Error, PartialEq)]
50pub enum Error {
51 /// Wraps a Keystore `ResponseCode` as defined by the Keystore AIDL interface specification.
52 #[error("Error::Rc({0:?})")]
Janis Danisevskise24f3472020-08-12 17:58:49 -070053 Rc(ResponseCode),
Janis Danisevskis7d77a762020-07-20 13:03:31 -070054 /// Wraps a Keymint `ErrorCode` as defined by the Keymint AIDL interface specification.
55 #[error("Error::Km({0:?})")]
Janis Danisevskise24f3472020-08-12 17:58:49 -070056 Km(ErrorCode),
Janis Danisevskis017d2092020-09-02 10:15:52 -070057 /// Wraps a Binder exception code other than a service specific exception.
58 #[error("Binder exception code {0:?}, {1:?}")]
59 Binder(ExceptionCode, i32),
Janis Danisevskis7d77a762020-07-20 13:03:31 -070060}
61
62impl Error {
63 /// Short hand for `Error::Rc(ResponseCode::SystemError)`
64 pub fn sys() -> Self {
Janis Danisevskise24f3472020-08-12 17:58:49 -070065 Error::Rc(Rc::SystemError)
Janis Danisevskis7d77a762020-07-20 13:03:31 -070066 }
67
68 /// Short hand for `Error::Rc(ResponseCode::PermissionDenied`
69 pub fn perm() -> Self {
Janis Danisevskise24f3472020-08-12 17:58:49 -070070 Error::Rc(Rc::PermissionDenied)
Janis Danisevskis7d77a762020-07-20 13:03:31 -070071 }
72}
73
Janis Danisevskis017d2092020-09-02 10:15:52 -070074/// Helper function to map the binder status we get from calls into KeyMint
75/// to a Keystore Error. We don't create an anyhow error here to make
76/// it easier to evaluate KeyMint errors, which we must do in some cases, e.g.,
77/// when diagnosing authentication requirements, update requirements, and running
78/// out of operation slots.
79pub fn map_km_error<T>(r: BinderResult<T>) -> Result<T, Error> {
80 r.map_err(|s| {
81 match s.exception_code() {
82 ExceptionCode::SERVICE_SPECIFIC => {
83 let se = s.service_specific_error();
84 if se < 0 {
85 // Negative service specific errors are KM error codes.
86 Error::Km(s.service_specific_error())
87 } else {
88 // Non negative error codes cannot be KM error codes.
89 // So we create an `Error::Binder` variant to preserve
90 // the service specific error code for logging.
91 // `map_or_log_err` will map this on a system error,
92 // but not before logging the details to logcat.
93 Error::Binder(ExceptionCode::SERVICE_SPECIFIC, se)
94 }
95 }
96 // We create `Error::Binder` to preserve the exception code
97 // for logging.
98 // `map_or_log_err` will map this on a system error.
99 e_code => Error::Binder(e_code, 0),
100 }
101 })
102}
103
Janis Danisevskis7d77a762020-07-20 13:03:31 -0700104/// This function should be used by Keystore service calls to translate error conditions
105/// into `android.security.keystore2.Result` which is imported here as `aidl::Result`
106/// and newtyped as AidlResult.
107/// All error conditions get logged by this function.
108/// All `Error::Rc(x)` variants get mapped onto `aidl::Result{x, 0}`.
109/// All `Error::Km(x)` variants get mapped onto
110/// `aidl::Result{aidl::ResponseCode::KeymintErrorCode, x}`.
Janis Danisevskisce995432020-07-21 12:22:34 -0700111/// `selinux::Error::perm()` is mapped on `aidl::Result{aidl::ResponseCode::PermissionDenied, 0}`.
Janis Danisevskis7d77a762020-07-20 13:03:31 -0700112///
113/// All non `Error` error conditions get mapped onto
114/// `aidl::Result{aidl::ResponseCode::SystemError}`.
115///
116/// `handle_ok` will be called if `result` is `Ok(value)` where `value` will be passed
117/// as argument to `handle_ok`. `handle_ok` must generate an `AidlResult`, typically
118/// `AidlResult::ok()`, but other response codes may be used, e.g.,
119/// `aidl::ResponseCode::OpAuthNeeded` which does not required logging.
120///
121/// # Examples
122///
123/// ```
124/// fn loadKey() -> anyhow::Result<aidl::ResponseCode> {
125/// if (good_but_auth_required) {
126/// Ok(aidl::ResponseCode::OpAuthRequired)
127/// } else {
128/// Err(anyhow!(Error::Rc(aidl::ResponseCode::KeyNotFound)))
129/// }
130/// }
131///
132/// aidl_result_ = map_or_log_err(loadKey(), |r| { some_side_effect(); AidlResult::rc(r) });
133/// ```
Janis Danisevskise24f3472020-08-12 17:58:49 -0700134pub fn map_or_log_err<T, U, F>(result: anyhow::Result<U>, handle_ok: F) -> BinderResult<T>
135where
136 F: FnOnce(U) -> BinderResult<T>,
137{
Janis Danisevskis7d77a762020-07-20 13:03:31 -0700138 result.map_or_else(
139 |e| {
140 log::error!("{:?}", e);
Janis Danisevskise24f3472020-08-12 17:58:49 -0700141 let root_cause = e.root_cause();
142 let rc = match root_cause.downcast_ref::<Error>() {
143 Some(Error::Rc(rcode)) => *rcode,
144 Some(Error::Km(ec)) => *ec,
Janis Danisevskis017d2092020-09-02 10:15:52 -0700145 // If an Error::Binder reaches this stage we report a system error.
146 // The exception code and possible service specific error will be
147 // printed in the error log above.
148 Some(Error::Binder(_, _)) => Rc::SystemError,
Janis Danisevskise24f3472020-08-12 17:58:49 -0700149 None => match root_cause.downcast_ref::<selinux::Error>() {
150 Some(selinux::Error::PermissionDenied) => Rc::PermissionDenied,
151 _ => Rc::SystemError,
152 },
153 };
154 Err(BinderStatus::new_service_specific_error(rc, None))
Janis Danisevskis7d77a762020-07-20 13:03:31 -0700155 },
156 handle_ok,
157 )
158}
159
160#[cfg(test)]
Hasini Gunasingheaf993662020-07-24 18:40:20 +0000161pub mod tests {
Janis Danisevskis7d77a762020-07-20 13:03:31 -0700162
Janis Danisevskis7d77a762020-07-20 13:03:31 -0700163 use super::*;
Janis Danisevskis017d2092020-09-02 10:15:52 -0700164 use android_security_keystore2::binder::{
165 ExceptionCode, Result as BinderResult, Status as BinderStatus,
166 };
Janis Danisevskise24f3472020-08-12 17:58:49 -0700167 use anyhow::{anyhow, Context};
Janis Danisevskis7d77a762020-07-20 13:03:31 -0700168
Janis Danisevskise24f3472020-08-12 17:58:49 -0700169 fn nested_nested_rc(rc: ResponseCode) -> anyhow::Result<()> {
Janis Danisevskis7d77a762020-07-20 13:03:31 -0700170 Err(anyhow!(Error::Rc(rc))).context("nested nested rc")
171 }
172
Janis Danisevskise24f3472020-08-12 17:58:49 -0700173 fn nested_rc(rc: ResponseCode) -> anyhow::Result<()> {
Janis Danisevskis7d77a762020-07-20 13:03:31 -0700174 nested_nested_rc(rc).context("nested rc")
175 }
176
177 fn nested_nested_ec(ec: ErrorCode) -> anyhow::Result<()> {
178 Err(anyhow!(Error::Km(ec))).context("nested nested ec")
179 }
180
181 fn nested_ec(ec: ErrorCode) -> anyhow::Result<()> {
182 nested_nested_ec(ec).context("nested ec")
183 }
184
Janis Danisevskise24f3472020-08-12 17:58:49 -0700185 fn nested_nested_ok(rc: ResponseCode) -> anyhow::Result<ResponseCode> {
Janis Danisevskis7d77a762020-07-20 13:03:31 -0700186 Ok(rc)
187 }
188
Janis Danisevskise24f3472020-08-12 17:58:49 -0700189 fn nested_ok(rc: ResponseCode) -> anyhow::Result<ResponseCode> {
Janis Danisevskis7d77a762020-07-20 13:03:31 -0700190 nested_nested_ok(rc).context("nested ok")
191 }
192
Janis Danisevskisce995432020-07-21 12:22:34 -0700193 fn nested_nested_selinux_perm() -> anyhow::Result<()> {
194 Err(anyhow!(selinux::Error::perm())).context("nested nexted selinux permission denied")
195 }
196
197 fn nested_selinux_perm() -> anyhow::Result<()> {
198 nested_nested_selinux_perm().context("nested selinux permission denied")
199 }
200
Janis Danisevskis7d77a762020-07-20 13:03:31 -0700201 #[derive(Debug, thiserror::Error)]
202 enum TestError {
203 #[error("TestError::Fail")]
204 Fail = 0,
205 }
206
207 fn nested_nested_other_error() -> anyhow::Result<()> {
208 Err(anyhow!(TestError::Fail)).context("nested nested other error")
209 }
210
211 fn nested_other_error() -> anyhow::Result<()> {
212 nested_nested_other_error().context("nested other error")
213 }
214
Janis Danisevskis017d2092020-09-02 10:15:52 -0700215 fn binder_sse_error(sse: i32) -> BinderResult<()> {
216 Err(BinderStatus::new_service_specific_error(sse, None))
217 }
218
219 fn binder_exception(ex: ExceptionCode) -> BinderResult<()> {
220 Err(BinderStatus::new_exception(ex, None))
221 }
222
Janis Danisevskis7d77a762020-07-20 13:03:31 -0700223 #[test]
224 fn keystore_error_test() -> anyhow::Result<(), String> {
225 android_logger::init_once(
226 android_logger::Config::default()
227 .with_tag("keystore_error_tests")
228 .with_min_level(log::Level::Debug),
229 );
Janis Danisevskise24f3472020-08-12 17:58:49 -0700230 // All Error::Rc(x) get mapped on a service specific error
231 // code of x.
232 for rc in Rc::Ok..Rc::BackendBusy {
233 assert_eq!(
234 Result::<(), i32>::Err(rc),
235 map_or_log_err(nested_rc(rc), |_| Err(BinderStatus::ok()))
236 .map_err(|s| s.service_specific_error())
237 );
238 }
239
Janis Danisevskis017d2092020-09-02 10:15:52 -0700240 // All Keystore Error::Km(x) get mapped on a service
Janis Danisevskise24f3472020-08-12 17:58:49 -0700241 // specific error of x.
242 for ec in Ec::UNKNOWN_ERROR..Ec::ROOT_OF_TRUST_ALREADY_SET {
243 assert_eq!(
244 Result::<(), i32>::Err(ec),
245 map_or_log_err(nested_ec(ec), |_| Err(BinderStatus::ok()))
246 .map_err(|s| s.service_specific_error())
247 );
248 }
249
Janis Danisevskis017d2092020-09-02 10:15:52 -0700250 // All Keymint errors x received through a Binder Result get mapped on
251 // a service specific error of x.
252 for ec in Ec::UNKNOWN_ERROR..Ec::ROOT_OF_TRUST_ALREADY_SET {
253 assert_eq!(
254 Result::<(), i32>::Err(ec),
255 map_or_log_err(
256 map_km_error(binder_sse_error(ec))
257 .with_context(|| format!("Km error code: {}.", ec)),
258 |_| Err(BinderStatus::ok())
259 )
260 .map_err(|s| s.service_specific_error())
261 );
262 }
263
264 // map_km_error creates an Error::Binder variant storing
265 // ExceptionCode::SERVICE_SPECIFIC and the given
266 // service specific error.
267 let sse = map_km_error(binder_sse_error(1));
268 assert_eq!(Err(Error::Binder(ExceptionCode::SERVICE_SPECIFIC, 1)), sse);
269 // map_or_log_err then maps it on a service specific error of Rc::SystemError.
270 assert_eq!(
271 Result::<(), i32>::Err(Rc::SystemError),
272 map_or_log_err(sse.context("Non negative service specific error."), |_| Err(
273 BinderStatus::ok()
274 ))
275 .map_err(|s| s.service_specific_error())
276 );
277
278 // map_km_error creates a Error::Binder variant storing the given exception code.
279 let binder_exception = map_km_error(binder_exception(ExceptionCode::TRANSACTION_FAILED));
280 assert_eq!(Err(Error::Binder(ExceptionCode::TRANSACTION_FAILED, 0)), binder_exception);
281 // map_or_log_err then maps it on a service specific error of Rc::SystemError.
282 assert_eq!(
283 Result::<(), i32>::Err(Rc::SystemError),
284 map_or_log_err(binder_exception.context("Binder Exception."), |_| Err(
285 BinderStatus::ok()
286 ))
287 .map_err(|s| s.service_specific_error())
288 );
289
Janis Danisevskise24f3472020-08-12 17:58:49 -0700290 // selinux::Error::Perm() needs to be mapped to Rc::PermissionDenied
Janis Danisevskis7d77a762020-07-20 13:03:31 -0700291 assert_eq!(
Janis Danisevskise24f3472020-08-12 17:58:49 -0700292 Result::<(), i32>::Err(Rc::PermissionDenied),
293 map_or_log_err(nested_selinux_perm(), |_| Err(BinderStatus::ok()))
294 .map_err(|s| s.service_specific_error())
Janis Danisevskis7d77a762020-07-20 13:03:31 -0700295 );
296
Janis Danisevskise24f3472020-08-12 17:58:49 -0700297 // All other errors get mapped on System Error.
Janis Danisevskis7d77a762020-07-20 13:03:31 -0700298 assert_eq!(
Janis Danisevskise24f3472020-08-12 17:58:49 -0700299 Result::<(), i32>::Err(Rc::SystemError),
300 map_or_log_err(nested_other_error(), |_| Err(BinderStatus::ok()))
301 .map_err(|s| s.service_specific_error())
Janis Danisevskis7d77a762020-07-20 13:03:31 -0700302 );
303
304 // Result::Ok variants get passed to the ok handler.
Janis Danisevskise24f3472020-08-12 17:58:49 -0700305 assert_eq!(Ok(Rc::OpAuthNeeded), map_or_log_err(nested_ok(Rc::OpAuthNeeded), Ok));
306 assert_eq!(Ok(Rc::Ok), map_or_log_err(nested_ok(Rc::Ok), Ok));
Janis Danisevskis7d77a762020-07-20 13:03:31 -0700307
Janis Danisevskis7d77a762020-07-20 13:03:31 -0700308 Ok(())
309 }
Hasini Gunasingheaf993662020-07-24 18:40:20 +0000310
311 //Helper function to test whether error cases are handled as expected.
Janis Danisevskise24f3472020-08-12 17:58:49 -0700312 pub fn check_result_contains_error_string<T>(
313 result: anyhow::Result<T>,
314 expected_error_string: &str,
315 ) {
Hasini Gunasingheaf993662020-07-24 18:40:20 +0000316 let error_str = format!(
317 "{:#?}",
318 result.err().unwrap_or_else(|| panic!("Expected the error: {}", expected_error_string))
319 );
320 assert!(
321 error_str.contains(expected_error_string),
322 "The string \"{}\" should contain \"{}\"",
323 error_str,
324 expected_error_string
325 );
326 }
Janis Danisevskis7d77a762020-07-20 13:03:31 -0700327} // mod tests