blob: f0d0d27b6625b30a298bc64c6daf52e9cb464a8c [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.
Janis Danisevskis7d77a762020-07-20 13:03:31 -070016//!
Tri Vocd6fc7a2023-08-31 11:46:32 -040017//! Here are some important types and helper functions:
Janis Danisevskis7d77a762020-07-20 13:03:31 -070018//!
Tri Vocd6fc7a2023-08-31 11:46:32 -040019//! `Error` type encapsulate Keystore, Keymint, and Binder errors. It is used internally by
20//! Keystore to diagnose error conditions that need to be reported to the client.
21//!
22//! `SerializedError` is used send error codes on the wire.
23//!
24//! `map_or_log_err` is a convenience method used to convert `anyhow::Error` into `SerializedError`
25//! wire type.
26//!
27//! Keystore functions should use `anyhow::Result` to return error conditions, and context should
28//! be added every time an error is forwarded.
Janis Danisevskis7d77a762020-07-20 13:03:31 -070029
Shawn Willden708744a2020-12-11 13:05:27 +000030pub use android_hardware_security_keymint::aidl::android::hardware::security::keymint::ErrorCode::ErrorCode;
Alice Wang849cfe42023-11-10 12:43:36 +000031use android_security_rkp_aidl::aidl::android::security::rkp::IGetKeyCallback::ErrorCode::ErrorCode as GetKeyErrorCode;
Janis Danisevskisc5b210b2020-09-11 13:27:37 -070032pub use android_system_keystore2::aidl::android::system::keystore2::ResponseCode::ResponseCode;
Janis Danisevskisc5b210b2020-09-11 13:27:37 -070033use android_system_keystore2::binder::{
Janis Danisevskisba998992020-12-29 16:08:40 -080034 ExceptionCode, Result as BinderResult, Status as BinderStatus, StatusCode,
Janis Danisevskis017d2092020-09-02 10:15:52 -070035};
Janis Danisevskis2ee014b2021-05-05 14:29:08 -070036use keystore2_selinux as selinux;
Alice Wang01c16b62023-11-07 14:27:49 +000037use rkpd_client::Error as RkpdError;
Janis Danisevskis2ee014b2021-05-05 14:29:08 -070038use std::cmp::PartialEq;
Janis Danisevskisea03cff2021-12-16 08:10:17 -080039use std::ffi::CString;
Janis Danisevskis7d77a762020-07-20 13:03:31 -070040
41/// This is the main Keystore error type. It wraps the Keystore `ResponseCode` generated
42/// from AIDL in the `Rc` variant and Keymint `ErrorCode` in the Km variant.
Chris Wailes263de9f2022-08-11 15:00:51 -070043#[derive(Debug, thiserror::Error, PartialEq, Eq)]
Janis Danisevskis7d77a762020-07-20 13:03:31 -070044pub enum Error {
45 /// Wraps a Keystore `ResponseCode` as defined by the Keystore AIDL interface specification.
46 #[error("Error::Rc({0:?})")]
Janis Danisevskise24f3472020-08-12 17:58:49 -070047 Rc(ResponseCode),
Janis Danisevskis7d77a762020-07-20 13:03:31 -070048 /// Wraps a Keymint `ErrorCode` as defined by the Keymint AIDL interface specification.
49 #[error("Error::Km({0:?})")]
Janis Danisevskise24f3472020-08-12 17:58:49 -070050 Km(ErrorCode),
Janis Danisevskis017d2092020-09-02 10:15:52 -070051 /// Wraps a Binder exception code other than a service specific exception.
52 #[error("Binder exception code {0:?}, {1:?}")]
53 Binder(ExceptionCode, i32),
Janis Danisevskisba998992020-12-29 16:08:40 -080054 /// Wraps a Binder status code.
55 #[error("Binder transaction error {0:?}")]
56 BinderTransaction(StatusCode),
Janis Danisevskis7d77a762020-07-20 13:03:31 -070057}
58
59impl Error {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -070060 /// Short hand for `Error::Rc(ResponseCode::SYSTEM_ERROR)`
Janis Danisevskis7d77a762020-07-20 13:03:31 -070061 pub fn sys() -> Self {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -070062 Error::Rc(ResponseCode::SYSTEM_ERROR)
Janis Danisevskis7d77a762020-07-20 13:03:31 -070063 }
64
Seth Moore7ee79f92021-12-07 11:42:49 -080065 /// Short hand for `Error::Rc(ResponseCode::PERMISSION_DENIED)`
Janis Danisevskis7d77a762020-07-20 13:03:31 -070066 pub fn perm() -> Self {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -070067 Error::Rc(ResponseCode::PERMISSION_DENIED)
Janis Danisevskis7d77a762020-07-20 13:03:31 -070068 }
69}
70
Alice Wang849cfe42023-11-10 12:43:36 +000071impl From<RkpdError> for Error {
72 fn from(e: RkpdError) -> Self {
73 match e {
74 RkpdError::RequestCancelled | RkpdError::GetRegistrationFailed => {
75 Error::Rc(ResponseCode::OUT_OF_KEYS_TRANSIENT_ERROR)
76 }
77 RkpdError::GetKeyFailed(e) => {
78 let response_code = match e {
79 GetKeyErrorCode::ERROR_UNKNOWN => ResponseCode::OUT_OF_KEYS_TRANSIENT_ERROR,
80 GetKeyErrorCode::ERROR_PERMANENT => ResponseCode::OUT_OF_KEYS_PERMANENT_ERROR,
81 GetKeyErrorCode::ERROR_PENDING_INTERNET_CONNECTIVITY => {
82 ResponseCode::OUT_OF_KEYS_PENDING_INTERNET_CONNECTIVITY
83 }
84 GetKeyErrorCode::ERROR_REQUIRES_SECURITY_PATCH => {
85 ResponseCode::OUT_OF_KEYS_REQUIRES_SYSTEM_UPGRADE
86 }
87 _ => {
88 log::error!("Unexpected get key error from rkpd: {e:?}");
89 ResponseCode::OUT_OF_KEYS_TRANSIENT_ERROR
90 }
91 };
92 Error::Rc(response_code)
93 }
94 RkpdError::RetryableTimeout => Error::Rc(ResponseCode::OUT_OF_KEYS_TRANSIENT_ERROR),
95 RkpdError::StoreUpgradedKeyFailed | RkpdError::Timeout => {
96 Error::Rc(ResponseCode::SYSTEM_ERROR)
97 }
98 RkpdError::BinderTransaction(s) => Error::BinderTransaction(s),
99 }
100 }
101}
102
103/// Maps an `rkpd_client::Error` that is wrapped with an `anyhow::Error` to a keystore2 `Error`.
104pub fn wrapped_rkpd_error_to_ks_error(e: &anyhow::Error) -> Error {
105 match e.downcast_ref::<RkpdError>() {
106 Some(e) => Error::from(*e),
107 None => {
108 log::error!("Failed to downcast the anyhow::Error to rkpd_client::Error: {e:?}");
109 Error::Rc(ResponseCode::SYSTEM_ERROR)
110 }
111 }
112}
113
Janis Danisevskis017d2092020-09-02 10:15:52 -0700114/// Helper function to map the binder status we get from calls into KeyMint
115/// to a Keystore Error. We don't create an anyhow error here to make
116/// it easier to evaluate KeyMint errors, which we must do in some cases, e.g.,
117/// when diagnosing authentication requirements, update requirements, and running
118/// out of operation slots.
119pub fn map_km_error<T>(r: BinderResult<T>) -> Result<T, Error> {
120 r.map_err(|s| {
121 match s.exception_code() {
122 ExceptionCode::SERVICE_SPECIFIC => {
123 let se = s.service_specific_error();
124 if se < 0 {
125 // Negative service specific errors are KM error codes.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700126 Error::Km(ErrorCode(s.service_specific_error()))
Janis Danisevskis017d2092020-09-02 10:15:52 -0700127 } else {
128 // Non negative error codes cannot be KM error codes.
129 // So we create an `Error::Binder` variant to preserve
130 // the service specific error code for logging.
131 // `map_or_log_err` will map this on a system error,
132 // but not before logging the details to logcat.
133 Error::Binder(ExceptionCode::SERVICE_SPECIFIC, se)
134 }
135 }
136 // We create `Error::Binder` to preserve the exception code
137 // for logging.
138 // `map_or_log_err` will map this on a system error.
139 e_code => Error::Binder(e_code, 0),
140 }
141 })
142}
143
Janis Danisevskisba998992020-12-29 16:08:40 -0800144/// This function is similar to map_km_error only that we don't expect
145/// any KeyMint error codes, we simply preserve the exception code and optional
146/// service specific exception.
147pub fn map_binder_status<T>(r: BinderResult<T>) -> Result<T, Error> {
148 r.map_err(|s| match s.exception_code() {
149 ExceptionCode::SERVICE_SPECIFIC => {
150 let se = s.service_specific_error();
151 Error::Binder(ExceptionCode::SERVICE_SPECIFIC, se)
152 }
153 ExceptionCode::TRANSACTION_FAILED => {
154 let e = s.transaction_error();
155 Error::BinderTransaction(e)
156 }
157 e_code => Error::Binder(e_code, 0),
158 })
159}
160
161/// This function maps a status code onto a Keystore Error.
162pub fn map_binder_status_code<T>(r: Result<T, StatusCode>) -> Result<T, Error> {
163 r.map_err(Error::BinderTransaction)
164}
165
Janis Danisevskis7d77a762020-07-20 13:03:31 -0700166/// This function should be used by Keystore service calls to translate error conditions
Janis Danisevskis8ea5f552020-11-20 11:22:59 -0800167/// into service specific exceptions.
Janis Danisevskis7d77a762020-07-20 13:03:31 -0700168///
Hasini Gunasinghee1d1bbd2021-04-20 18:13:25 +0000169/// All error conditions get logged by this function, except for KEY_NOT_FOUND error.
Janis Danisevskis8ea5f552020-11-20 11:22:59 -0800170///
Janis Danisevskis7d77a762020-07-20 13:03:31 -0700171/// `handle_ok` will be called if `result` is `Ok(value)` where `value` will be passed
Janis Danisevskis8ea5f552020-11-20 11:22:59 -0800172/// as argument to `handle_ok`. `handle_ok` must generate a `BinderResult<T>`, but it
173/// typically returns Ok(value).
Janis Danisevskis7d77a762020-07-20 13:03:31 -0700174///
175/// # Examples
176///
177/// ```
Janis Danisevskis8ea5f552020-11-20 11:22:59 -0800178/// fn loadKey() -> anyhow::Result<Vec<u8>> {
Janis Danisevskis7d77a762020-07-20 13:03:31 -0700179/// if (good_but_auth_required) {
Janis Danisevskis8ea5f552020-11-20 11:22:59 -0800180/// Ok(vec!['k', 'e', 'y'])
Janis Danisevskis7d77a762020-07-20 13:03:31 -0700181/// } else {
Janis Danisevskis8ea5f552020-11-20 11:22:59 -0800182/// Err(anyhow!(Error::Rc(ResponseCode::KEY_NOT_FOUND)))
Janis Danisevskis7d77a762020-07-20 13:03:31 -0700183/// }
184/// }
185///
Janis Danisevskis8ea5f552020-11-20 11:22:59 -0800186/// map_or_log_err(loadKey(), Ok)
Janis Danisevskis7d77a762020-07-20 13:03:31 -0700187/// ```
Janis Danisevskise24f3472020-08-12 17:58:49 -0700188pub fn map_or_log_err<T, U, F>(result: anyhow::Result<U>, handle_ok: F) -> BinderResult<T>
189where
190 F: FnOnce(U) -> BinderResult<T>,
191{
Janis Danisevskis778245c2021-03-04 15:40:23 -0800192 map_err_with(
193 result,
Janis Danisevskis7d77a762020-07-20 13:03:31 -0700194 |e| {
Hasini Gunasinghee1d1bbd2021-04-20 18:13:25 +0000195 // Make the key not found errors silent.
196 if !matches!(
197 e.root_cause().downcast_ref::<Error>(),
198 Some(Error::Rc(ResponseCode::KEY_NOT_FOUND))
199 ) {
200 log::error!("{:?}", e);
201 }
Janis Danisevskis778245c2021-03-04 15:40:23 -0800202 e
203 },
204 handle_ok,
205 )
206}
207
Janis Danisevskisea03cff2021-12-16 08:10:17 -0800208/// This function turns an anyhow error into an optional CString.
209/// This is especially useful to add a message string to a service specific error.
210/// If the formatted string was not convertible because it contained a nul byte,
211/// None is returned and a warning is logged.
212pub fn anyhow_error_to_cstring(e: &anyhow::Error) -> Option<CString> {
213 match CString::new(format!("{:?}", e)) {
214 Ok(msg) => Some(msg),
215 Err(_) => {
216 log::warn!("Cannot convert error message to CStr. It contained a nul byte.");
217 None
218 }
219 }
220}
221
Janis Danisevskis778245c2021-03-04 15:40:23 -0800222/// This function behaves similar to map_or_log_error, but it does not log the errors, instead
223/// it calls map_err on the error before mapping it to a binder result allowing callers to
224/// log or transform the error before mapping it.
225pub fn map_err_with<T, U, F1, F2>(
226 result: anyhow::Result<U>,
227 map_err: F1,
228 handle_ok: F2,
229) -> BinderResult<T>
230where
231 F1: FnOnce(anyhow::Error) -> anyhow::Error,
232 F2: FnOnce(U) -> BinderResult<T>,
233{
234 result.map_or_else(
235 |e| {
236 let e = map_err(e);
Tri Vocd6fc7a2023-08-31 11:46:32 -0400237 let rc = anyhow_error_to_serialized_error(&e);
Janis Danisevskisea03cff2021-12-16 08:10:17 -0800238 Err(BinderStatus::new_service_specific_error(
Tri Vocd6fc7a2023-08-31 11:46:32 -0400239 rc.0,
Janis Danisevskisea03cff2021-12-16 08:10:17 -0800240 anyhow_error_to_cstring(&e).as_deref(),
241 ))
Janis Danisevskis7d77a762020-07-20 13:03:31 -0700242 },
243 handle_ok,
244 )
245}
246
Tri Vocd6fc7a2023-08-31 11:46:32 -0400247/// This type is used to send error codes on the wire.
248///
249/// Errors are squashed into one number space using following rules:
250/// - All Keystore and Keymint errors codes are identity mapped. It's possible because by
251/// convention Keystore `ResponseCode` errors are positive, and Keymint `ErrorCode` errors are
252/// negative.
253/// - `selinux::Error::PermissionDenied` is mapped to `ResponseCode::PERMISSION_DENIED`.
254/// - All other error conditions, e.g. Binder errors, are mapped to `ResponseCode::SYSTEM_ERROR`.
255///
256/// The type should be used to forward all error codes to clients of Keystore AIDL interface and to
257/// metrics events.
258#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
259pub struct SerializedError(pub i32);
260
261/// Returns a SerializedError given a reference to Error.
262pub fn error_to_serialized_error(e: &Error) -> SerializedError {
263 match e {
264 Error::Rc(rcode) => SerializedError(rcode.0),
265 Error::Km(ec) => SerializedError(ec.0),
266 // Binder errors are reported as system error.
267 Error::Binder(_, _) | Error::BinderTransaction(_) => {
268 SerializedError(ResponseCode::SYSTEM_ERROR.0)
269 }
270 }
271}
272
273/// Returns a SerializedError given a reference to anyhow::Error.
274pub fn anyhow_error_to_serialized_error(e: &anyhow::Error) -> SerializedError {
Hasini Gunasingheb7142972021-02-20 03:11:27 +0000275 let root_cause = e.root_cause();
276 match root_cause.downcast_ref::<Error>() {
Tri Vocd6fc7a2023-08-31 11:46:32 -0400277 Some(e) => error_to_serialized_error(e),
Hasini Gunasingheb7142972021-02-20 03:11:27 +0000278 None => match root_cause.downcast_ref::<selinux::Error>() {
Tri Vocd6fc7a2023-08-31 11:46:32 -0400279 Some(selinux::Error::PermissionDenied) => {
280 SerializedError(ResponseCode::PERMISSION_DENIED.0)
281 }
282 _ => SerializedError(ResponseCode::SYSTEM_ERROR.0),
Hasini Gunasingheb7142972021-02-20 03:11:27 +0000283 },
284 }
285}
286
Janis Danisevskis7d77a762020-07-20 13:03:31 -0700287#[cfg(test)]
Hasini Gunasingheaf993662020-07-24 18:40:20 +0000288pub mod tests {
Janis Danisevskis7d77a762020-07-20 13:03:31 -0700289
Janis Danisevskis7d77a762020-07-20 13:03:31 -0700290 use super::*;
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700291 use android_system_keystore2::binder::{
Janis Danisevskis017d2092020-09-02 10:15:52 -0700292 ExceptionCode, Result as BinderResult, Status as BinderStatus,
293 };
Janis Danisevskise24f3472020-08-12 17:58:49 -0700294 use anyhow::{anyhow, Context};
Janis Danisevskis7d77a762020-07-20 13:03:31 -0700295
Janis Danisevskise24f3472020-08-12 17:58:49 -0700296 fn nested_nested_rc(rc: ResponseCode) -> anyhow::Result<()> {
Janis Danisevskis7d77a762020-07-20 13:03:31 -0700297 Err(anyhow!(Error::Rc(rc))).context("nested nested rc")
298 }
299
Janis Danisevskise24f3472020-08-12 17:58:49 -0700300 fn nested_rc(rc: ResponseCode) -> anyhow::Result<()> {
Janis Danisevskis7d77a762020-07-20 13:03:31 -0700301 nested_nested_rc(rc).context("nested rc")
302 }
303
304 fn nested_nested_ec(ec: ErrorCode) -> anyhow::Result<()> {
305 Err(anyhow!(Error::Km(ec))).context("nested nested ec")
306 }
307
308 fn nested_ec(ec: ErrorCode) -> anyhow::Result<()> {
309 nested_nested_ec(ec).context("nested ec")
310 }
311
Janis Danisevskise24f3472020-08-12 17:58:49 -0700312 fn nested_nested_ok(rc: ResponseCode) -> anyhow::Result<ResponseCode> {
Janis Danisevskis7d77a762020-07-20 13:03:31 -0700313 Ok(rc)
314 }
315
Janis Danisevskise24f3472020-08-12 17:58:49 -0700316 fn nested_ok(rc: ResponseCode) -> anyhow::Result<ResponseCode> {
Janis Danisevskis7d77a762020-07-20 13:03:31 -0700317 nested_nested_ok(rc).context("nested ok")
318 }
319
Janis Danisevskisce995432020-07-21 12:22:34 -0700320 fn nested_nested_selinux_perm() -> anyhow::Result<()> {
321 Err(anyhow!(selinux::Error::perm())).context("nested nexted selinux permission denied")
322 }
323
324 fn nested_selinux_perm() -> anyhow::Result<()> {
325 nested_nested_selinux_perm().context("nested selinux permission denied")
326 }
327
Janis Danisevskis7d77a762020-07-20 13:03:31 -0700328 #[derive(Debug, thiserror::Error)]
329 enum TestError {
330 #[error("TestError::Fail")]
331 Fail = 0,
332 }
333
334 fn nested_nested_other_error() -> anyhow::Result<()> {
335 Err(anyhow!(TestError::Fail)).context("nested nested other error")
336 }
337
338 fn nested_other_error() -> anyhow::Result<()> {
339 nested_nested_other_error().context("nested other error")
340 }
341
Janis Danisevskis017d2092020-09-02 10:15:52 -0700342 fn binder_sse_error(sse: i32) -> BinderResult<()> {
343 Err(BinderStatus::new_service_specific_error(sse, None))
344 }
345
346 fn binder_exception(ex: ExceptionCode) -> BinderResult<()> {
347 Err(BinderStatus::new_exception(ex, None))
348 }
349
Janis Danisevskis7d77a762020-07-20 13:03:31 -0700350 #[test]
351 fn keystore_error_test() -> anyhow::Result<(), String> {
352 android_logger::init_once(
353 android_logger::Config::default()
354 .with_tag("keystore_error_tests")
Jeff Vander Stoep153d1aa2024-02-07 14:33:36 +0100355 .with_max_level(log::LevelFilter::Debug),
Janis Danisevskis7d77a762020-07-20 13:03:31 -0700356 );
Janis Danisevskise24f3472020-08-12 17:58:49 -0700357 // All Error::Rc(x) get mapped on a service specific error
358 // code of x.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700359 for rc in ResponseCode::LOCKED.0..ResponseCode::BACKEND_BUSY.0 {
Janis Danisevskise24f3472020-08-12 17:58:49 -0700360 assert_eq!(
361 Result::<(), i32>::Err(rc),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700362 map_or_log_err(nested_rc(ResponseCode(rc)), |_| Err(BinderStatus::ok()))
Janis Danisevskise24f3472020-08-12 17:58:49 -0700363 .map_err(|s| s.service_specific_error())
364 );
365 }
366
Janis Danisevskis017d2092020-09-02 10:15:52 -0700367 // All Keystore Error::Km(x) get mapped on a service
Janis Danisevskise24f3472020-08-12 17:58:49 -0700368 // specific error of x.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700369 for ec in ErrorCode::UNKNOWN_ERROR.0..ErrorCode::ROOT_OF_TRUST_ALREADY_SET.0 {
Janis Danisevskise24f3472020-08-12 17:58:49 -0700370 assert_eq!(
371 Result::<(), i32>::Err(ec),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700372 map_or_log_err(nested_ec(ErrorCode(ec)), |_| Err(BinderStatus::ok()))
Janis Danisevskise24f3472020-08-12 17:58:49 -0700373 .map_err(|s| s.service_specific_error())
374 );
375 }
376
Janis Danisevskis017d2092020-09-02 10:15:52 -0700377 // All Keymint errors x received through a Binder Result get mapped on
378 // a service specific error of x.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700379 for ec in ErrorCode::UNKNOWN_ERROR.0..ErrorCode::ROOT_OF_TRUST_ALREADY_SET.0 {
Janis Danisevskis017d2092020-09-02 10:15:52 -0700380 assert_eq!(
381 Result::<(), i32>::Err(ec),
382 map_or_log_err(
383 map_km_error(binder_sse_error(ec))
384 .with_context(|| format!("Km error code: {}.", ec)),
385 |_| Err(BinderStatus::ok())
386 )
387 .map_err(|s| s.service_specific_error())
388 );
389 }
390
391 // map_km_error creates an Error::Binder variant storing
392 // ExceptionCode::SERVICE_SPECIFIC and the given
393 // service specific error.
394 let sse = map_km_error(binder_sse_error(1));
395 assert_eq!(Err(Error::Binder(ExceptionCode::SERVICE_SPECIFIC, 1)), sse);
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700396 // map_or_log_err then maps it on a service specific error of ResponseCode::SYSTEM_ERROR.
Janis Danisevskis017d2092020-09-02 10:15:52 -0700397 assert_eq!(
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700398 Result::<(), ResponseCode>::Err(ResponseCode::SYSTEM_ERROR),
Janis Danisevskis017d2092020-09-02 10:15:52 -0700399 map_or_log_err(sse.context("Non negative service specific error."), |_| Err(
400 BinderStatus::ok()
401 ))
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700402 .map_err(|s| ResponseCode(s.service_specific_error()))
Janis Danisevskis017d2092020-09-02 10:15:52 -0700403 );
404
405 // map_km_error creates a Error::Binder variant storing the given exception code.
406 let binder_exception = map_km_error(binder_exception(ExceptionCode::TRANSACTION_FAILED));
407 assert_eq!(Err(Error::Binder(ExceptionCode::TRANSACTION_FAILED, 0)), binder_exception);
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700408 // map_or_log_err then maps it on a service specific error of ResponseCode::SYSTEM_ERROR.
Janis Danisevskis017d2092020-09-02 10:15:52 -0700409 assert_eq!(
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700410 Result::<(), ResponseCode>::Err(ResponseCode::SYSTEM_ERROR),
Janis Danisevskis017d2092020-09-02 10:15:52 -0700411 map_or_log_err(binder_exception.context("Binder Exception."), |_| Err(
412 BinderStatus::ok()
413 ))
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700414 .map_err(|s| ResponseCode(s.service_specific_error()))
Janis Danisevskis017d2092020-09-02 10:15:52 -0700415 );
416
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700417 // selinux::Error::Perm() needs to be mapped to ResponseCode::PERMISSION_DENIED
Janis Danisevskis7d77a762020-07-20 13:03:31 -0700418 assert_eq!(
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700419 Result::<(), ResponseCode>::Err(ResponseCode::PERMISSION_DENIED),
Janis Danisevskise24f3472020-08-12 17:58:49 -0700420 map_or_log_err(nested_selinux_perm(), |_| Err(BinderStatus::ok()))
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700421 .map_err(|s| ResponseCode(s.service_specific_error()))
Janis Danisevskis7d77a762020-07-20 13:03:31 -0700422 );
423
Janis Danisevskise24f3472020-08-12 17:58:49 -0700424 // All other errors get mapped on System Error.
Janis Danisevskis7d77a762020-07-20 13:03:31 -0700425 assert_eq!(
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700426 Result::<(), ResponseCode>::Err(ResponseCode::SYSTEM_ERROR),
Janis Danisevskise24f3472020-08-12 17:58:49 -0700427 map_or_log_err(nested_other_error(), |_| Err(BinderStatus::ok()))
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700428 .map_err(|s| ResponseCode(s.service_specific_error()))
Janis Danisevskis7d77a762020-07-20 13:03:31 -0700429 );
430
431 // Result::Ok variants get passed to the ok handler.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700432 assert_eq!(Ok(ResponseCode::LOCKED), map_or_log_err(nested_ok(ResponseCode::LOCKED), Ok));
433 assert_eq!(
434 Ok(ResponseCode::SYSTEM_ERROR),
435 map_or_log_err(nested_ok(ResponseCode::SYSTEM_ERROR), Ok)
436 );
Janis Danisevskis7d77a762020-07-20 13:03:31 -0700437
Janis Danisevskis7d77a762020-07-20 13:03:31 -0700438 Ok(())
439 }
Hasini Gunasingheaf993662020-07-24 18:40:20 +0000440
441 //Helper function to test whether error cases are handled as expected.
Janis Danisevskise24f3472020-08-12 17:58:49 -0700442 pub fn check_result_contains_error_string<T>(
443 result: anyhow::Result<T>,
444 expected_error_string: &str,
445 ) {
Hasini Gunasingheaf993662020-07-24 18:40:20 +0000446 let error_str = format!(
447 "{:#?}",
448 result.err().unwrap_or_else(|| panic!("Expected the error: {}", expected_error_string))
449 );
450 assert!(
451 error_str.contains(expected_error_string),
452 "The string \"{}\" should contain \"{}\"",
453 error_str,
454 expected_error_string
455 );
456 }
Alice Wang849cfe42023-11-10 12:43:36 +0000457
458 #[test]
459 fn rkpd_error_is_in_sync_with_response_code() {
460 let error_mapping = [
461 (RkpdError::RequestCancelled, ResponseCode::OUT_OF_KEYS_TRANSIENT_ERROR),
462 (RkpdError::GetRegistrationFailed, ResponseCode::OUT_OF_KEYS_TRANSIENT_ERROR),
463 (
464 RkpdError::GetKeyFailed(GetKeyErrorCode::ERROR_UNKNOWN),
465 ResponseCode::OUT_OF_KEYS_TRANSIENT_ERROR,
466 ),
467 (
468 RkpdError::GetKeyFailed(GetKeyErrorCode::ERROR_PERMANENT),
469 ResponseCode::OUT_OF_KEYS_PERMANENT_ERROR,
470 ),
471 (
472 RkpdError::GetKeyFailed(GetKeyErrorCode::ERROR_PENDING_INTERNET_CONNECTIVITY),
473 ResponseCode::OUT_OF_KEYS_PENDING_INTERNET_CONNECTIVITY,
474 ),
475 (
476 RkpdError::GetKeyFailed(GetKeyErrorCode::ERROR_REQUIRES_SECURITY_PATCH),
477 ResponseCode::OUT_OF_KEYS_REQUIRES_SYSTEM_UPGRADE,
478 ),
479 (RkpdError::StoreUpgradedKeyFailed, ResponseCode::SYSTEM_ERROR),
480 (RkpdError::RetryableTimeout, ResponseCode::OUT_OF_KEYS_TRANSIENT_ERROR),
481 (RkpdError::Timeout, ResponseCode::SYSTEM_ERROR),
482 ];
483 for (rkpd_error, expected_response_code) in error_mapping {
484 let e: Error = rkpd_error.into();
485 assert_eq!(e, Error::Rc(expected_response_code));
486 }
487 }
Janis Danisevskis7d77a762020-07-20 13:03:31 -0700488} // mod tests