blob: e6443b7a615f2eec173754f4d195a1061d342710 [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;
34use std::convert::From;
35
36use keystore_aidl_generated as aidl;
37use keystore_aidl_generated::ResponseCode as AidlRc;
38
Janis Danisevskisce995432020-07-21 12:22:34 -070039use keystore2_selinux as selinux;
40
Janis Danisevskis7d77a762020-07-20 13:03:31 -070041pub use aidl::ResponseCode;
42
43/// AidlResult wraps the `android.security.keystore2.Result` generated from AIDL
44#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
45pub struct AidlResult(aidl::Result);
46
47impl AidlResult {
48 /// Creates an instance of AidlResult indicating no error has occurred.
49 pub fn ok() -> Self {
50 Self(aidl::Result { rc: AidlRc::Ok, km_error_code: 0 })
51 }
52
53 /// Creates an instance of AidlResult indicating the given ResponseCode.
54 pub fn rc(rc: AidlRc) -> Self {
55 Self(aidl::Result { rc, km_error_code: 0 })
56 }
57
58 /// Creates an instance of AidlResult indicating the given KM ErrorCode.
59 pub fn ec(ec: aidl::ErrorCode) -> Self {
60 Self(aidl::Result { rc: AidlRc::KeymintErrorCode, km_error_code: ec })
61 }
62}
63
64/// This is the main Keystore error type. It wraps the Keystore `ResponseCode` generated
65/// from AIDL in the `Rc` variant and Keymint `ErrorCode` in the Km variant.
66#[derive(Debug, thiserror::Error, PartialEq)]
67pub enum Error {
68 /// Wraps a Keystore `ResponseCode` as defined by the Keystore AIDL interface specification.
69 #[error("Error::Rc({0:?})")]
70 Rc(AidlRc),
71 /// Wraps a Keymint `ErrorCode` as defined by the Keymint AIDL interface specification.
72 #[error("Error::Km({0:?})")]
73 Km(aidl::ErrorCode), // TODO Keymint ErrorCode is a generated AIDL type.
74}
75
76impl Error {
77 /// Short hand for `Error::Rc(ResponseCode::SystemError)`
78 pub fn sys() -> Self {
79 Error::Rc(AidlRc::SystemError)
80 }
81
82 /// Short hand for `Error::Rc(ResponseCode::PermissionDenied`
83 pub fn perm() -> Self {
84 Error::Rc(AidlRc::PermissionDenied)
85 }
86}
87
88impl From<anyhow::Error> for AidlResult {
89 fn from(error: anyhow::Error) -> Self {
90 let root_cause = error.root_cause();
91 match root_cause.downcast_ref::<Error>() {
92 Some(Error::Rc(rcode)) => AidlResult::rc(*rcode),
93 Some(Error::Km(ec)) => AidlResult::ec(*ec),
Janis Danisevskisce995432020-07-21 12:22:34 -070094 None => match root_cause.downcast_ref::<selinux::Error>() {
95 Some(selinux::Error::PermissionDenied) => AidlResult::rc(AidlRc::PermissionDenied),
96 _ => AidlResult::rc(AidlRc::SystemError),
97 },
Janis Danisevskis7d77a762020-07-20 13:03:31 -070098 }
99 }
100}
101
102/// This function should be used by Keystore service calls to translate error conditions
103/// into `android.security.keystore2.Result` which is imported here as `aidl::Result`
104/// and newtyped as AidlResult.
105/// All error conditions get logged by this function.
106/// All `Error::Rc(x)` variants get mapped onto `aidl::Result{x, 0}`.
107/// All `Error::Km(x)` variants get mapped onto
108/// `aidl::Result{aidl::ResponseCode::KeymintErrorCode, x}`.
Janis Danisevskisce995432020-07-21 12:22:34 -0700109/// `selinux::Error::perm()` is mapped on `aidl::Result{aidl::ResponseCode::PermissionDenied, 0}`.
Janis Danisevskis7d77a762020-07-20 13:03:31 -0700110///
111/// All non `Error` error conditions get mapped onto
112/// `aidl::Result{aidl::ResponseCode::SystemError}`.
113///
114/// `handle_ok` will be called if `result` is `Ok(value)` where `value` will be passed
115/// as argument to `handle_ok`. `handle_ok` must generate an `AidlResult`, typically
116/// `AidlResult::ok()`, but other response codes may be used, e.g.,
117/// `aidl::ResponseCode::OpAuthNeeded` which does not required logging.
118///
119/// # Examples
120///
121/// ```
122/// fn loadKey() -> anyhow::Result<aidl::ResponseCode> {
123/// if (good_but_auth_required) {
124/// Ok(aidl::ResponseCode::OpAuthRequired)
125/// } else {
126/// Err(anyhow!(Error::Rc(aidl::ResponseCode::KeyNotFound)))
127/// }
128/// }
129///
130/// aidl_result_ = map_or_log_err(loadKey(), |r| { some_side_effect(); AidlResult::rc(r) });
131/// ```
132pub fn map_or_log_err<T>(
133 result: anyhow::Result<T>,
134 handle_ok: impl FnOnce(T) -> AidlResult,
135) -> AidlResult {
136 result.map_or_else(
137 |e| {
138 log::error!("{:?}", e);
139 e.into()
140 },
141 handle_ok,
142 )
143}
144
145#[cfg(test)]
146mod tests {
147
148 use anyhow::{anyhow, Context};
149
150 use super::aidl::ErrorCode;
151 use super::*;
152
153 fn nested_nested_rc(rc: AidlRc) -> anyhow::Result<()> {
154 Err(anyhow!(Error::Rc(rc))).context("nested nested rc")
155 }
156
157 fn nested_rc(rc: AidlRc) -> anyhow::Result<()> {
158 nested_nested_rc(rc).context("nested rc")
159 }
160
161 fn nested_nested_ec(ec: ErrorCode) -> anyhow::Result<()> {
162 Err(anyhow!(Error::Km(ec))).context("nested nested ec")
163 }
164
165 fn nested_ec(ec: ErrorCode) -> anyhow::Result<()> {
166 nested_nested_ec(ec).context("nested ec")
167 }
168
169 fn nested_nested_ok(rc: AidlRc) -> anyhow::Result<AidlRc> {
170 Ok(rc)
171 }
172
173 fn nested_ok(rc: AidlRc) -> anyhow::Result<AidlRc> {
174 nested_nested_ok(rc).context("nested ok")
175 }
176
Janis Danisevskisce995432020-07-21 12:22:34 -0700177 fn nested_nested_selinux_perm() -> anyhow::Result<()> {
178 Err(anyhow!(selinux::Error::perm())).context("nested nexted selinux permission denied")
179 }
180
181 fn nested_selinux_perm() -> anyhow::Result<()> {
182 nested_nested_selinux_perm().context("nested selinux permission denied")
183 }
184
Janis Danisevskis7d77a762020-07-20 13:03:31 -0700185 #[derive(Debug, thiserror::Error)]
186 enum TestError {
187 #[error("TestError::Fail")]
188 Fail = 0,
189 }
190
191 fn nested_nested_other_error() -> anyhow::Result<()> {
192 Err(anyhow!(TestError::Fail)).context("nested nested other error")
193 }
194
195 fn nested_other_error() -> anyhow::Result<()> {
196 nested_nested_other_error().context("nested other error")
197 }
198
199 #[test]
200 fn keystore_error_test() -> anyhow::Result<(), String> {
201 android_logger::init_once(
202 android_logger::Config::default()
203 .with_tag("keystore_error_tests")
204 .with_min_level(log::Level::Debug),
205 );
206 // All Error::Rc(x) get mapped on aidl::Result{x, 0}
207 assert_eq!(
208 AidlResult::rc(AidlRc::Ok),
209 map_or_log_err(nested_rc(AidlRc::Ok), |_| AidlResult::ec(0))
210 );
211 assert_eq!(
212 AidlResult::rc(AidlRc::Locked),
213 map_or_log_err(nested_rc(AidlRc::Locked), |_| AidlResult::ec(0))
214 );
215 assert_eq!(
216 AidlResult::rc(AidlRc::Uninitialized),
217 map_or_log_err(nested_rc(AidlRc::Uninitialized), |_| AidlResult::ec(0))
218 );
219 assert_eq!(
220 AidlResult::rc(AidlRc::SystemError),
221 map_or_log_err(nested_rc(AidlRc::SystemError), |_| AidlResult::ec(0))
222 );
223 assert_eq!(
224 AidlResult::rc(AidlRc::PermissionDenied),
225 map_or_log_err(nested_rc(AidlRc::PermissionDenied), |_| AidlResult::ec(0))
226 );
227 assert_eq!(
228 AidlResult::rc(AidlRc::KeyNotFound),
229 map_or_log_err(nested_rc(AidlRc::KeyNotFound), |_| AidlResult::ec(0))
230 );
231 assert_eq!(
232 AidlResult::rc(AidlRc::ValueCorrupted),
233 map_or_log_err(nested_rc(AidlRc::ValueCorrupted), |_| AidlResult::ec(0))
234 );
235 assert_eq!(
236 AidlResult::rc(AidlRc::WrongPassword),
237 map_or_log_err(nested_rc(AidlRc::WrongPassword), |_| AidlResult::ec(0))
238 );
239 assert_eq!(
240 AidlResult::rc(AidlRc::OpAuthNeeded),
241 map_or_log_err(nested_rc(AidlRc::OpAuthNeeded), |_| AidlResult::ec(0))
242 );
243 assert_eq!(
244 AidlResult::rc(AidlRc::KeyPermanentlyInvalidated),
245 map_or_log_err(nested_rc(AidlRc::KeyPermanentlyInvalidated), |_| AidlResult::ec(0))
246 );
247 assert_eq!(
248 AidlResult::rc(AidlRc::NoSuchSecurityLevel),
249 map_or_log_err(nested_rc(AidlRc::NoSuchSecurityLevel), |_| AidlResult::ec(0))
250 );
251 assert_eq!(
252 AidlResult::rc(AidlRc::KeymintErrorCode),
253 map_or_log_err(nested_rc(AidlRc::KeymintErrorCode), |_| AidlResult::ec(0))
254 );
255 assert_eq!(
256 AidlResult::rc(AidlRc::BackendBusy),
257 map_or_log_err(nested_rc(AidlRc::BackendBusy), |_| AidlResult::ec(0))
258 );
259
260 // All KeystoreKerror::Km(x) get mapped on
261 // aidl::Result{AidlRc::KeymintErrorCode, x}
262 assert_eq!(
263 AidlResult::ec(-7),
264 map_or_log_err(nested_ec(-7), |_| AidlResult::rc(AidlRc::SystemError))
265 );
266
267 // All other get mapped on System Error.
268 assert_eq!(
269 AidlResult::rc(AidlRc::SystemError),
270 map_or_log_err(nested_other_error(), |_| AidlResult::ec(0))
271 );
272
273 // Result::Ok variants get passed to the ok handler.
274 assert_eq!(
275 AidlResult::rc(AidlRc::OpAuthNeeded),
276 map_or_log_err(nested_ok(AidlRc::OpAuthNeeded), AidlResult::rc)
277 );
278 assert_eq!(AidlResult::ok(), map_or_log_err(nested_ok(AidlRc::Ok), AidlResult::rc));
279
Janis Danisevskisce995432020-07-21 12:22:34 -0700280 // selinux::Error::Perm() needs to be mapped to AidlRc::PermissionDenied
281 assert_eq!(
282 AidlResult::rc(AidlRc::PermissionDenied),
283 map_or_log_err(nested_selinux_perm(), |_| AidlResult::ec(0))
284 );
Janis Danisevskis7d77a762020-07-20 13:03:31 -0700285 Ok(())
286 }
287} // mod tests