1*e1997b9aSAndroid Build Coastguard Worker // Copyright 2020, The Android Open Source Project
2*e1997b9aSAndroid Build Coastguard Worker //
3*e1997b9aSAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License");
4*e1997b9aSAndroid Build Coastguard Worker // you may not use this file except in compliance with the License.
5*e1997b9aSAndroid Build Coastguard Worker // You may obtain a copy of the License at
6*e1997b9aSAndroid Build Coastguard Worker //
7*e1997b9aSAndroid Build Coastguard Worker // http://www.apache.org/licenses/LICENSE-2.0
8*e1997b9aSAndroid Build Coastguard Worker //
9*e1997b9aSAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
10*e1997b9aSAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS,
11*e1997b9aSAndroid Build Coastguard Worker // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*e1997b9aSAndroid Build Coastguard Worker // See the License for the specific language governing permissions and
13*e1997b9aSAndroid Build Coastguard Worker // limitations under the License.
14*e1997b9aSAndroid Build Coastguard Worker
15*e1997b9aSAndroid Build Coastguard Worker //! Keystore error provides convenience methods and types for Keystore error handling.
16*e1997b9aSAndroid Build Coastguard Worker //!
17*e1997b9aSAndroid Build Coastguard Worker //! Here are some important types and helper functions:
18*e1997b9aSAndroid Build Coastguard Worker //!
19*e1997b9aSAndroid Build Coastguard Worker //! `Error` type encapsulate Keystore, Keymint, and Binder errors. It is used internally by
20*e1997b9aSAndroid Build Coastguard Worker //! Keystore to diagnose error conditions that need to be reported to the client.
21*e1997b9aSAndroid Build Coastguard Worker //!
22*e1997b9aSAndroid Build Coastguard Worker //! `SerializedError` is used send error codes on the wire.
23*e1997b9aSAndroid Build Coastguard Worker //!
24*e1997b9aSAndroid Build Coastguard Worker //! `into_[logged_]binder` is a convenience method used to convert `anyhow::Error` into
25*e1997b9aSAndroid Build Coastguard Worker //! `SerializedError` wire type.
26*e1997b9aSAndroid Build Coastguard Worker //!
27*e1997b9aSAndroid Build Coastguard Worker //! Keystore functions should use `anyhow::Result` to return error conditions, and context should
28*e1997b9aSAndroid Build Coastguard Worker //! be added every time an error is forwarded.
29*e1997b9aSAndroid Build Coastguard Worker
30*e1997b9aSAndroid Build Coastguard Worker pub use android_hardware_security_keymint::aidl::android::hardware::security::keymint::ErrorCode::ErrorCode;
31*e1997b9aSAndroid Build Coastguard Worker use android_security_rkp_aidl::aidl::android::security::rkp::IGetKeyCallback::ErrorCode::ErrorCode as GetKeyErrorCode;
32*e1997b9aSAndroid Build Coastguard Worker pub use android_system_keystore2::aidl::android::system::keystore2::ResponseCode::ResponseCode;
33*e1997b9aSAndroid Build Coastguard Worker use android_system_keystore2::binder::{
34*e1997b9aSAndroid Build Coastguard Worker ExceptionCode, Result as BinderResult, Status as BinderStatus, StatusCode,
35*e1997b9aSAndroid Build Coastguard Worker };
36*e1997b9aSAndroid Build Coastguard Worker use keystore2_selinux as selinux;
37*e1997b9aSAndroid Build Coastguard Worker use postprocessor_client::Error as PostProcessorError;
38*e1997b9aSAndroid Build Coastguard Worker use rkpd_client::Error as RkpdError;
39*e1997b9aSAndroid Build Coastguard Worker use std::cmp::PartialEq;
40*e1997b9aSAndroid Build Coastguard Worker use std::ffi::CString;
41*e1997b9aSAndroid Build Coastguard Worker
42*e1997b9aSAndroid Build Coastguard Worker #[cfg(test)]
43*e1997b9aSAndroid Build Coastguard Worker pub mod tests;
44*e1997b9aSAndroid Build Coastguard Worker
45*e1997b9aSAndroid Build Coastguard Worker /// This is the main Keystore error type. It wraps the Keystore `ResponseCode` generated
46*e1997b9aSAndroid Build Coastguard Worker /// from AIDL in the `Rc` variant and Keymint `ErrorCode` in the Km variant.
47*e1997b9aSAndroid Build Coastguard Worker #[derive(Debug, thiserror::Error, PartialEq, Eq)]
48*e1997b9aSAndroid Build Coastguard Worker pub enum Error {
49*e1997b9aSAndroid Build Coastguard Worker /// Wraps a Keystore `ResponseCode` as defined by the Keystore AIDL interface specification.
50*e1997b9aSAndroid Build Coastguard Worker #[error("Error::Rc({0:?})")]
51*e1997b9aSAndroid Build Coastguard Worker Rc(ResponseCode),
52*e1997b9aSAndroid Build Coastguard Worker /// Wraps a Keymint `ErrorCode` as defined by the Keymint AIDL interface specification.
53*e1997b9aSAndroid Build Coastguard Worker #[error("Error::Km({0:?})")]
54*e1997b9aSAndroid Build Coastguard Worker Km(ErrorCode),
55*e1997b9aSAndroid Build Coastguard Worker /// Wraps a Binder exception code other than a service specific exception.
56*e1997b9aSAndroid Build Coastguard Worker #[error("Binder exception code {0:?}, {1:?}")]
57*e1997b9aSAndroid Build Coastguard Worker Binder(ExceptionCode, i32),
58*e1997b9aSAndroid Build Coastguard Worker /// Wraps a Binder status code.
59*e1997b9aSAndroid Build Coastguard Worker #[error("Binder transaction error {0:?}")]
60*e1997b9aSAndroid Build Coastguard Worker BinderTransaction(StatusCode),
61*e1997b9aSAndroid Build Coastguard Worker }
62*e1997b9aSAndroid Build Coastguard Worker
63*e1997b9aSAndroid Build Coastguard Worker impl Error {
64*e1997b9aSAndroid Build Coastguard Worker /// Short hand for `Error::Rc(ResponseCode::SYSTEM_ERROR)`
sys() -> Self65*e1997b9aSAndroid Build Coastguard Worker pub fn sys() -> Self {
66*e1997b9aSAndroid Build Coastguard Worker Error::Rc(ResponseCode::SYSTEM_ERROR)
67*e1997b9aSAndroid Build Coastguard Worker }
68*e1997b9aSAndroid Build Coastguard Worker
69*e1997b9aSAndroid Build Coastguard Worker /// Short hand for `Error::Rc(ResponseCode::PERMISSION_DENIED)`
perm() -> Self70*e1997b9aSAndroid Build Coastguard Worker pub fn perm() -> Self {
71*e1997b9aSAndroid Build Coastguard Worker Error::Rc(ResponseCode::PERMISSION_DENIED)
72*e1997b9aSAndroid Build Coastguard Worker }
73*e1997b9aSAndroid Build Coastguard Worker }
74*e1997b9aSAndroid Build Coastguard Worker
75*e1997b9aSAndroid Build Coastguard Worker impl From<RkpdError> for Error {
from(e: RkpdError) -> Self76*e1997b9aSAndroid Build Coastguard Worker fn from(e: RkpdError) -> Self {
77*e1997b9aSAndroid Build Coastguard Worker match e {
78*e1997b9aSAndroid Build Coastguard Worker RkpdError::RequestCancelled | RkpdError::GetRegistrationFailed => {
79*e1997b9aSAndroid Build Coastguard Worker Error::Rc(ResponseCode::OUT_OF_KEYS_TRANSIENT_ERROR)
80*e1997b9aSAndroid Build Coastguard Worker }
81*e1997b9aSAndroid Build Coastguard Worker RkpdError::GetKeyFailed(e) => {
82*e1997b9aSAndroid Build Coastguard Worker let response_code = match e {
83*e1997b9aSAndroid Build Coastguard Worker GetKeyErrorCode::ERROR_UNKNOWN => ResponseCode::OUT_OF_KEYS_TRANSIENT_ERROR,
84*e1997b9aSAndroid Build Coastguard Worker GetKeyErrorCode::ERROR_PERMANENT => ResponseCode::OUT_OF_KEYS_PERMANENT_ERROR,
85*e1997b9aSAndroid Build Coastguard Worker GetKeyErrorCode::ERROR_PENDING_INTERNET_CONNECTIVITY => {
86*e1997b9aSAndroid Build Coastguard Worker ResponseCode::OUT_OF_KEYS_PENDING_INTERNET_CONNECTIVITY
87*e1997b9aSAndroid Build Coastguard Worker }
88*e1997b9aSAndroid Build Coastguard Worker GetKeyErrorCode::ERROR_REQUIRES_SECURITY_PATCH => {
89*e1997b9aSAndroid Build Coastguard Worker ResponseCode::OUT_OF_KEYS_REQUIRES_SYSTEM_UPGRADE
90*e1997b9aSAndroid Build Coastguard Worker }
91*e1997b9aSAndroid Build Coastguard Worker _ => {
92*e1997b9aSAndroid Build Coastguard Worker log::error!("Unexpected get key error from rkpd: {e:?}");
93*e1997b9aSAndroid Build Coastguard Worker ResponseCode::OUT_OF_KEYS_TRANSIENT_ERROR
94*e1997b9aSAndroid Build Coastguard Worker }
95*e1997b9aSAndroid Build Coastguard Worker };
96*e1997b9aSAndroid Build Coastguard Worker Error::Rc(response_code)
97*e1997b9aSAndroid Build Coastguard Worker }
98*e1997b9aSAndroid Build Coastguard Worker RkpdError::RetryableTimeout => Error::Rc(ResponseCode::OUT_OF_KEYS_TRANSIENT_ERROR),
99*e1997b9aSAndroid Build Coastguard Worker RkpdError::StoreUpgradedKeyFailed | RkpdError::Timeout => {
100*e1997b9aSAndroid Build Coastguard Worker Error::Rc(ResponseCode::SYSTEM_ERROR)
101*e1997b9aSAndroid Build Coastguard Worker }
102*e1997b9aSAndroid Build Coastguard Worker RkpdError::BinderTransaction(s) => Error::BinderTransaction(s),
103*e1997b9aSAndroid Build Coastguard Worker }
104*e1997b9aSAndroid Build Coastguard Worker }
105*e1997b9aSAndroid Build Coastguard Worker }
106*e1997b9aSAndroid Build Coastguard Worker
107*e1997b9aSAndroid Build Coastguard Worker impl From<PostProcessorError> for Error {
from(e: PostProcessorError) -> Self108*e1997b9aSAndroid Build Coastguard Worker fn from(e: PostProcessorError) -> Self {
109*e1997b9aSAndroid Build Coastguard Worker match e {
110*e1997b9aSAndroid Build Coastguard Worker PostProcessorError(s) => Error::BinderTransaction(s),
111*e1997b9aSAndroid Build Coastguard Worker }
112*e1997b9aSAndroid Build Coastguard Worker }
113*e1997b9aSAndroid Build Coastguard Worker }
114*e1997b9aSAndroid Build Coastguard Worker
115*e1997b9aSAndroid Build Coastguard Worker /// Maps an `rkpd_client::Error` that is wrapped with an `anyhow::Error` to a keystore2 `Error`.
wrapped_rkpd_error_to_ks_error(e: &anyhow::Error) -> Error116*e1997b9aSAndroid Build Coastguard Worker pub fn wrapped_rkpd_error_to_ks_error(e: &anyhow::Error) -> Error {
117*e1997b9aSAndroid Build Coastguard Worker match e.downcast_ref::<RkpdError>() {
118*e1997b9aSAndroid Build Coastguard Worker Some(e) => Error::from(*e),
119*e1997b9aSAndroid Build Coastguard Worker None => {
120*e1997b9aSAndroid Build Coastguard Worker log::error!("Failed to downcast the anyhow::Error to rkpd_client::Error: {e:?}");
121*e1997b9aSAndroid Build Coastguard Worker Error::Rc(ResponseCode::SYSTEM_ERROR)
122*e1997b9aSAndroid Build Coastguard Worker }
123*e1997b9aSAndroid Build Coastguard Worker }
124*e1997b9aSAndroid Build Coastguard Worker }
125*e1997b9aSAndroid Build Coastguard Worker
126*e1997b9aSAndroid Build Coastguard Worker /// Helper function to map the binder status we get from calls into KeyMint
127*e1997b9aSAndroid Build Coastguard Worker /// to a Keystore Error. We don't create an anyhow error here to make
128*e1997b9aSAndroid Build Coastguard Worker /// it easier to evaluate KeyMint errors, which we must do in some cases, e.g.,
129*e1997b9aSAndroid Build Coastguard Worker /// when diagnosing authentication requirements, update requirements, and running
130*e1997b9aSAndroid Build Coastguard Worker /// out of operation slots.
map_km_error<T>(r: BinderResult<T>) -> Result<T, Error>131*e1997b9aSAndroid Build Coastguard Worker pub fn map_km_error<T>(r: BinderResult<T>) -> Result<T, Error> {
132*e1997b9aSAndroid Build Coastguard Worker r.map_err(|s| {
133*e1997b9aSAndroid Build Coastguard Worker match s.exception_code() {
134*e1997b9aSAndroid Build Coastguard Worker ExceptionCode::SERVICE_SPECIFIC => {
135*e1997b9aSAndroid Build Coastguard Worker let se = s.service_specific_error();
136*e1997b9aSAndroid Build Coastguard Worker if se < 0 {
137*e1997b9aSAndroid Build Coastguard Worker // Negative service specific errors are KM error codes.
138*e1997b9aSAndroid Build Coastguard Worker Error::Km(ErrorCode(s.service_specific_error()))
139*e1997b9aSAndroid Build Coastguard Worker } else {
140*e1997b9aSAndroid Build Coastguard Worker // Non negative error codes cannot be KM error codes.
141*e1997b9aSAndroid Build Coastguard Worker // So we create an `Error::Binder` variant to preserve
142*e1997b9aSAndroid Build Coastguard Worker // the service specific error code for logging.
143*e1997b9aSAndroid Build Coastguard Worker Error::Binder(ExceptionCode::SERVICE_SPECIFIC, se)
144*e1997b9aSAndroid Build Coastguard Worker }
145*e1997b9aSAndroid Build Coastguard Worker }
146*e1997b9aSAndroid Build Coastguard Worker // We create `Error::Binder` to preserve the exception code
147*e1997b9aSAndroid Build Coastguard Worker // for logging.
148*e1997b9aSAndroid Build Coastguard Worker e_code => Error::Binder(e_code, 0),
149*e1997b9aSAndroid Build Coastguard Worker }
150*e1997b9aSAndroid Build Coastguard Worker })
151*e1997b9aSAndroid Build Coastguard Worker }
152*e1997b9aSAndroid Build Coastguard Worker
153*e1997b9aSAndroid Build Coastguard Worker /// This function is similar to map_km_error only that we don't expect
154*e1997b9aSAndroid Build Coastguard Worker /// any KeyMint error codes, we simply preserve the exception code and optional
155*e1997b9aSAndroid Build Coastguard Worker /// service specific exception.
map_binder_status<T>(r: BinderResult<T>) -> Result<T, Error>156*e1997b9aSAndroid Build Coastguard Worker pub fn map_binder_status<T>(r: BinderResult<T>) -> Result<T, Error> {
157*e1997b9aSAndroid Build Coastguard Worker r.map_err(|s| match s.exception_code() {
158*e1997b9aSAndroid Build Coastguard Worker ExceptionCode::SERVICE_SPECIFIC => {
159*e1997b9aSAndroid Build Coastguard Worker let se = s.service_specific_error();
160*e1997b9aSAndroid Build Coastguard Worker Error::Binder(ExceptionCode::SERVICE_SPECIFIC, se)
161*e1997b9aSAndroid Build Coastguard Worker }
162*e1997b9aSAndroid Build Coastguard Worker ExceptionCode::TRANSACTION_FAILED => {
163*e1997b9aSAndroid Build Coastguard Worker let e = s.transaction_error();
164*e1997b9aSAndroid Build Coastguard Worker Error::BinderTransaction(e)
165*e1997b9aSAndroid Build Coastguard Worker }
166*e1997b9aSAndroid Build Coastguard Worker e_code => Error::Binder(e_code, 0),
167*e1997b9aSAndroid Build Coastguard Worker })
168*e1997b9aSAndroid Build Coastguard Worker }
169*e1997b9aSAndroid Build Coastguard Worker
170*e1997b9aSAndroid Build Coastguard Worker /// This function maps a status code onto a Keystore Error.
map_binder_status_code<T>(r: Result<T, StatusCode>) -> Result<T, Error>171*e1997b9aSAndroid Build Coastguard Worker pub fn map_binder_status_code<T>(r: Result<T, StatusCode>) -> Result<T, Error> {
172*e1997b9aSAndroid Build Coastguard Worker r.map_err(Error::BinderTransaction)
173*e1997b9aSAndroid Build Coastguard Worker }
174*e1997b9aSAndroid Build Coastguard Worker
175*e1997b9aSAndroid Build Coastguard Worker /// Convert an [`anyhow::Error`] to a [`binder::Status`], logging the value
176*e1997b9aSAndroid Build Coastguard Worker /// along the way (except if it is `KEY_NOT_FOUND`).
into_logged_binder(e: anyhow::Error) -> BinderStatus177*e1997b9aSAndroid Build Coastguard Worker pub fn into_logged_binder(e: anyhow::Error) -> BinderStatus {
178*e1997b9aSAndroid Build Coastguard Worker // Log everything except key not found.
179*e1997b9aSAndroid Build Coastguard Worker if !matches!(
180*e1997b9aSAndroid Build Coastguard Worker e.root_cause().downcast_ref::<Error>(),
181*e1997b9aSAndroid Build Coastguard Worker Some(Error::Rc(ResponseCode::KEY_NOT_FOUND))
182*e1997b9aSAndroid Build Coastguard Worker ) {
183*e1997b9aSAndroid Build Coastguard Worker log::error!("{:?}", e);
184*e1997b9aSAndroid Build Coastguard Worker }
185*e1997b9aSAndroid Build Coastguard Worker into_binder(e)
186*e1997b9aSAndroid Build Coastguard Worker }
187*e1997b9aSAndroid Build Coastguard Worker
188*e1997b9aSAndroid Build Coastguard Worker /// This function turns an anyhow error into an optional CString.
189*e1997b9aSAndroid Build Coastguard Worker /// This is especially useful to add a message string to a service specific error.
190*e1997b9aSAndroid Build Coastguard Worker /// If the formatted string was not convertible because it contained a nul byte,
191*e1997b9aSAndroid Build Coastguard Worker /// None is returned and a warning is logged.
anyhow_error_to_cstring(e: &anyhow::Error) -> Option<CString>192*e1997b9aSAndroid Build Coastguard Worker pub fn anyhow_error_to_cstring(e: &anyhow::Error) -> Option<CString> {
193*e1997b9aSAndroid Build Coastguard Worker match CString::new(format!("{:?}", e)) {
194*e1997b9aSAndroid Build Coastguard Worker Ok(msg) => Some(msg),
195*e1997b9aSAndroid Build Coastguard Worker Err(_) => {
196*e1997b9aSAndroid Build Coastguard Worker log::warn!("Cannot convert error message to CStr. It contained a nul byte.");
197*e1997b9aSAndroid Build Coastguard Worker None
198*e1997b9aSAndroid Build Coastguard Worker }
199*e1997b9aSAndroid Build Coastguard Worker }
200*e1997b9aSAndroid Build Coastguard Worker }
201*e1997b9aSAndroid Build Coastguard Worker
202*e1997b9aSAndroid Build Coastguard Worker /// Convert an [`anyhow::Error`] to a [`binder::Status`].
into_binder(e: anyhow::Error) -> binder::Status203*e1997b9aSAndroid Build Coastguard Worker pub fn into_binder(e: anyhow::Error) -> binder::Status {
204*e1997b9aSAndroid Build Coastguard Worker let rc = anyhow_error_to_serialized_error(&e);
205*e1997b9aSAndroid Build Coastguard Worker BinderStatus::new_service_specific_error(rc.0, anyhow_error_to_cstring(&e).as_deref())
206*e1997b9aSAndroid Build Coastguard Worker }
207*e1997b9aSAndroid Build Coastguard Worker
208*e1997b9aSAndroid Build Coastguard Worker /// This type is used to send error codes on the wire.
209*e1997b9aSAndroid Build Coastguard Worker ///
210*e1997b9aSAndroid Build Coastguard Worker /// Errors are squashed into one number space using following rules:
211*e1997b9aSAndroid Build Coastguard Worker /// - All Keystore and Keymint errors codes are identity mapped. It's possible because by
212*e1997b9aSAndroid Build Coastguard Worker /// convention Keystore `ResponseCode` errors are positive, and Keymint `ErrorCode` errors are
213*e1997b9aSAndroid Build Coastguard Worker /// negative.
214*e1997b9aSAndroid Build Coastguard Worker /// - `selinux::Error::PermissionDenied` is mapped to `ResponseCode::PERMISSION_DENIED`.
215*e1997b9aSAndroid Build Coastguard Worker /// - All other error conditions, e.g. Binder errors, are mapped to `ResponseCode::SYSTEM_ERROR`.
216*e1997b9aSAndroid Build Coastguard Worker ///
217*e1997b9aSAndroid Build Coastguard Worker /// The type should be used to forward all error codes to clients of Keystore AIDL interface and to
218*e1997b9aSAndroid Build Coastguard Worker /// metrics events.
219*e1997b9aSAndroid Build Coastguard Worker #[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
220*e1997b9aSAndroid Build Coastguard Worker pub struct SerializedError(pub i32);
221*e1997b9aSAndroid Build Coastguard Worker
222*e1997b9aSAndroid Build Coastguard Worker /// Returns a SerializedError given a reference to Error.
error_to_serialized_error(e: &Error) -> SerializedError223*e1997b9aSAndroid Build Coastguard Worker pub fn error_to_serialized_error(e: &Error) -> SerializedError {
224*e1997b9aSAndroid Build Coastguard Worker match e {
225*e1997b9aSAndroid Build Coastguard Worker Error::Rc(rcode) => SerializedError(rcode.0),
226*e1997b9aSAndroid Build Coastguard Worker Error::Km(ec) => SerializedError(ec.0),
227*e1997b9aSAndroid Build Coastguard Worker // Binder errors are reported as system error.
228*e1997b9aSAndroid Build Coastguard Worker Error::Binder(_, _) | Error::BinderTransaction(_) => {
229*e1997b9aSAndroid Build Coastguard Worker SerializedError(ResponseCode::SYSTEM_ERROR.0)
230*e1997b9aSAndroid Build Coastguard Worker }
231*e1997b9aSAndroid Build Coastguard Worker }
232*e1997b9aSAndroid Build Coastguard Worker }
233*e1997b9aSAndroid Build Coastguard Worker
234*e1997b9aSAndroid Build Coastguard Worker /// Returns a SerializedError given a reference to anyhow::Error.
anyhow_error_to_serialized_error(e: &anyhow::Error) -> SerializedError235*e1997b9aSAndroid Build Coastguard Worker pub fn anyhow_error_to_serialized_error(e: &anyhow::Error) -> SerializedError {
236*e1997b9aSAndroid Build Coastguard Worker let root_cause = e.root_cause();
237*e1997b9aSAndroid Build Coastguard Worker match root_cause.downcast_ref::<Error>() {
238*e1997b9aSAndroid Build Coastguard Worker Some(e) => error_to_serialized_error(e),
239*e1997b9aSAndroid Build Coastguard Worker None => match root_cause.downcast_ref::<selinux::Error>() {
240*e1997b9aSAndroid Build Coastguard Worker Some(selinux::Error::PermissionDenied) => {
241*e1997b9aSAndroid Build Coastguard Worker SerializedError(ResponseCode::PERMISSION_DENIED.0)
242*e1997b9aSAndroid Build Coastguard Worker }
243*e1997b9aSAndroid Build Coastguard Worker _ => SerializedError(ResponseCode::SYSTEM_ERROR.0),
244*e1997b9aSAndroid Build Coastguard Worker },
245*e1997b9aSAndroid Build Coastguard Worker }
246*e1997b9aSAndroid Build Coastguard Worker }
247