Merge "Change error.rs to use generated types."
This commit is contained in:
commit
5061b81606
3 changed files with 77 additions and 139 deletions
|
@ -18,9 +18,10 @@ rust_library {
|
|||
srcs: ["src/lib.rs"],
|
||||
|
||||
rustlibs: [
|
||||
"libandroid_hardware_keymint",
|
||||
"libandroid_security_keystore2",
|
||||
"libanyhow",
|
||||
"libandroid_hardware_keymint",
|
||||
"libbinder_rs",
|
||||
"libkeystore_aidl_generated",
|
||||
"libkeystore2_selinux",
|
||||
"liblazy_static",
|
||||
|
@ -40,9 +41,10 @@ rust_test {
|
|||
auto_gen_config: true,
|
||||
rustlibs: [
|
||||
"libandroid_logger",
|
||||
"libandroid_hardware_keymint",
|
||||
"libandroid_security_keystore2",
|
||||
"libanyhow",
|
||||
"libandroid_hardware_keymint",
|
||||
"libbinder_rs",
|
||||
"libkeystore_aidl_generated",
|
||||
"libkeystore2_selinux",
|
||||
"liblazy_static",
|
||||
|
|
|
@ -31,35 +31,16 @@
|
|||
//! context should be added every time an error is forwarded.
|
||||
|
||||
use std::cmp::PartialEq;
|
||||
use std::convert::From;
|
||||
|
||||
use keystore_aidl_generated as aidl;
|
||||
use keystore_aidl_generated::ResponseCode as AidlRc;
|
||||
pub use android_hardware_keymint::aidl::android::hardware::keymint::ErrorCode as Ec;
|
||||
pub use android_security_keystore2::aidl::android::security::keystore2::ResponseCode as Rc;
|
||||
|
||||
use android_hardware_keymint::aidl::android::hardware::keymint::ErrorCode::ErrorCode;
|
||||
use android_security_keystore2::aidl::android::security::keystore2::ResponseCode::ResponseCode;
|
||||
|
||||
use keystore2_selinux as selinux;
|
||||
|
||||
pub use aidl::ResponseCode;
|
||||
|
||||
/// AidlResult wraps the `android.security.keystore2.Result` generated from AIDL
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub struct AidlResult(aidl::Result);
|
||||
|
||||
impl AidlResult {
|
||||
/// Creates an instance of AidlResult indicating no error has occurred.
|
||||
pub fn ok() -> Self {
|
||||
Self(aidl::Result { rc: AidlRc::Ok, km_error_code: 0 })
|
||||
}
|
||||
|
||||
/// Creates an instance of AidlResult indicating the given ResponseCode.
|
||||
pub fn rc(rc: AidlRc) -> Self {
|
||||
Self(aidl::Result { rc, km_error_code: 0 })
|
||||
}
|
||||
|
||||
/// Creates an instance of AidlResult indicating the given KM ErrorCode.
|
||||
pub fn ec(ec: aidl::ErrorCode) -> Self {
|
||||
Self(aidl::Result { rc: AidlRc::KeymintErrorCode, km_error_code: ec })
|
||||
}
|
||||
}
|
||||
use android_security_keystore2::binder::{Result as BinderResult, Status as BinderStatus};
|
||||
|
||||
/// This is the main Keystore error type. It wraps the Keystore `ResponseCode` generated
|
||||
/// from AIDL in the `Rc` variant and Keymint `ErrorCode` in the Km variant.
|
||||
|
@ -67,35 +48,21 @@ impl AidlResult {
|
|||
pub enum Error {
|
||||
/// Wraps a Keystore `ResponseCode` as defined by the Keystore AIDL interface specification.
|
||||
#[error("Error::Rc({0:?})")]
|
||||
Rc(AidlRc),
|
||||
Rc(ResponseCode),
|
||||
/// Wraps a Keymint `ErrorCode` as defined by the Keymint AIDL interface specification.
|
||||
#[error("Error::Km({0:?})")]
|
||||
Km(aidl::ErrorCode), // TODO Keymint ErrorCode is a generated AIDL type.
|
||||
Km(ErrorCode),
|
||||
}
|
||||
|
||||
impl Error {
|
||||
/// Short hand for `Error::Rc(ResponseCode::SystemError)`
|
||||
pub fn sys() -> Self {
|
||||
Error::Rc(AidlRc::SystemError)
|
||||
Error::Rc(Rc::SystemError)
|
||||
}
|
||||
|
||||
/// Short hand for `Error::Rc(ResponseCode::PermissionDenied`
|
||||
pub fn perm() -> Self {
|
||||
Error::Rc(AidlRc::PermissionDenied)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<anyhow::Error> for AidlResult {
|
||||
fn from(error: anyhow::Error) -> Self {
|
||||
let root_cause = error.root_cause();
|
||||
match root_cause.downcast_ref::<Error>() {
|
||||
Some(Error::Rc(rcode)) => AidlResult::rc(*rcode),
|
||||
Some(Error::Km(ec)) => AidlResult::ec(*ec),
|
||||
None => match root_cause.downcast_ref::<selinux::Error>() {
|
||||
Some(selinux::Error::PermissionDenied) => AidlResult::rc(AidlRc::PermissionDenied),
|
||||
_ => AidlResult::rc(AidlRc::SystemError),
|
||||
},
|
||||
}
|
||||
Error::Rc(Rc::PermissionDenied)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -129,14 +96,23 @@ impl From<anyhow::Error> for AidlResult {
|
|||
///
|
||||
/// aidl_result_ = map_or_log_err(loadKey(), |r| { some_side_effect(); AidlResult::rc(r) });
|
||||
/// ```
|
||||
pub fn map_or_log_err<T>(
|
||||
result: anyhow::Result<T>,
|
||||
handle_ok: impl FnOnce(T) -> AidlResult,
|
||||
) -> AidlResult {
|
||||
pub fn map_or_log_err<T, U, F>(result: anyhow::Result<U>, handle_ok: F) -> BinderResult<T>
|
||||
where
|
||||
F: FnOnce(U) -> BinderResult<T>,
|
||||
{
|
||||
result.map_or_else(
|
||||
|e| {
|
||||
log::error!("{:?}", e);
|
||||
e.into()
|
||||
let root_cause = e.root_cause();
|
||||
let rc = match root_cause.downcast_ref::<Error>() {
|
||||
Some(Error::Rc(rcode)) => *rcode,
|
||||
Some(Error::Km(ec)) => *ec,
|
||||
None => match root_cause.downcast_ref::<selinux::Error>() {
|
||||
Some(selinux::Error::PermissionDenied) => Rc::PermissionDenied,
|
||||
_ => Rc::SystemError,
|
||||
},
|
||||
};
|
||||
Err(BinderStatus::new_service_specific_error(rc, None))
|
||||
},
|
||||
handle_ok,
|
||||
)
|
||||
|
@ -145,16 +121,14 @@ pub fn map_or_log_err<T>(
|
|||
#[cfg(test)]
|
||||
pub mod tests {
|
||||
|
||||
use anyhow::{anyhow, Context, Result};
|
||||
|
||||
use super::aidl::ErrorCode;
|
||||
use super::*;
|
||||
use anyhow::{anyhow, Context};
|
||||
|
||||
fn nested_nested_rc(rc: AidlRc) -> anyhow::Result<()> {
|
||||
fn nested_nested_rc(rc: ResponseCode) -> anyhow::Result<()> {
|
||||
Err(anyhow!(Error::Rc(rc))).context("nested nested rc")
|
||||
}
|
||||
|
||||
fn nested_rc(rc: AidlRc) -> anyhow::Result<()> {
|
||||
fn nested_rc(rc: ResponseCode) -> anyhow::Result<()> {
|
||||
nested_nested_rc(rc).context("nested rc")
|
||||
}
|
||||
|
||||
|
@ -166,11 +140,11 @@ pub mod tests {
|
|||
nested_nested_ec(ec).context("nested ec")
|
||||
}
|
||||
|
||||
fn nested_nested_ok(rc: AidlRc) -> anyhow::Result<AidlRc> {
|
||||
fn nested_nested_ok(rc: ResponseCode) -> anyhow::Result<ResponseCode> {
|
||||
Ok(rc)
|
||||
}
|
||||
|
||||
fn nested_ok(rc: AidlRc) -> anyhow::Result<AidlRc> {
|
||||
fn nested_ok(rc: ResponseCode) -> anyhow::Result<ResponseCode> {
|
||||
nested_nested_ok(rc).context("nested ok")
|
||||
}
|
||||
|
||||
|
@ -203,90 +177,52 @@ pub mod tests {
|
|||
.with_tag("keystore_error_tests")
|
||||
.with_min_level(log::Level::Debug),
|
||||
);
|
||||
// All Error::Rc(x) get mapped on aidl::Result{x, 0}
|
||||
// All Error::Rc(x) get mapped on a service specific error
|
||||
// code of x.
|
||||
for rc in Rc::Ok..Rc::BackendBusy {
|
||||
assert_eq!(
|
||||
Result::<(), i32>::Err(rc),
|
||||
map_or_log_err(nested_rc(rc), |_| Err(BinderStatus::ok()))
|
||||
.map_err(|s| s.service_specific_error())
|
||||
);
|
||||
}
|
||||
|
||||
// All KeystoreKerror::Km(x) get mapped on a service
|
||||
// specific error of x.
|
||||
for ec in Ec::UNKNOWN_ERROR..Ec::ROOT_OF_TRUST_ALREADY_SET {
|
||||
assert_eq!(
|
||||
Result::<(), i32>::Err(ec),
|
||||
map_or_log_err(nested_ec(ec), |_| Err(BinderStatus::ok()))
|
||||
.map_err(|s| s.service_specific_error())
|
||||
);
|
||||
}
|
||||
|
||||
// selinux::Error::Perm() needs to be mapped to Rc::PermissionDenied
|
||||
assert_eq!(
|
||||
AidlResult::rc(AidlRc::Ok),
|
||||
map_or_log_err(nested_rc(AidlRc::Ok), |_| AidlResult::ec(0))
|
||||
);
|
||||
assert_eq!(
|
||||
AidlResult::rc(AidlRc::Locked),
|
||||
map_or_log_err(nested_rc(AidlRc::Locked), |_| AidlResult::ec(0))
|
||||
);
|
||||
assert_eq!(
|
||||
AidlResult::rc(AidlRc::Uninitialized),
|
||||
map_or_log_err(nested_rc(AidlRc::Uninitialized), |_| AidlResult::ec(0))
|
||||
);
|
||||
assert_eq!(
|
||||
AidlResult::rc(AidlRc::SystemError),
|
||||
map_or_log_err(nested_rc(AidlRc::SystemError), |_| AidlResult::ec(0))
|
||||
);
|
||||
assert_eq!(
|
||||
AidlResult::rc(AidlRc::PermissionDenied),
|
||||
map_or_log_err(nested_rc(AidlRc::PermissionDenied), |_| AidlResult::ec(0))
|
||||
);
|
||||
assert_eq!(
|
||||
AidlResult::rc(AidlRc::KeyNotFound),
|
||||
map_or_log_err(nested_rc(AidlRc::KeyNotFound), |_| AidlResult::ec(0))
|
||||
);
|
||||
assert_eq!(
|
||||
AidlResult::rc(AidlRc::ValueCorrupted),
|
||||
map_or_log_err(nested_rc(AidlRc::ValueCorrupted), |_| AidlResult::ec(0))
|
||||
);
|
||||
assert_eq!(
|
||||
AidlResult::rc(AidlRc::WrongPassword),
|
||||
map_or_log_err(nested_rc(AidlRc::WrongPassword), |_| AidlResult::ec(0))
|
||||
);
|
||||
assert_eq!(
|
||||
AidlResult::rc(AidlRc::OpAuthNeeded),
|
||||
map_or_log_err(nested_rc(AidlRc::OpAuthNeeded), |_| AidlResult::ec(0))
|
||||
);
|
||||
assert_eq!(
|
||||
AidlResult::rc(AidlRc::KeyPermanentlyInvalidated),
|
||||
map_or_log_err(nested_rc(AidlRc::KeyPermanentlyInvalidated), |_| AidlResult::ec(0))
|
||||
);
|
||||
assert_eq!(
|
||||
AidlResult::rc(AidlRc::NoSuchSecurityLevel),
|
||||
map_or_log_err(nested_rc(AidlRc::NoSuchSecurityLevel), |_| AidlResult::ec(0))
|
||||
);
|
||||
assert_eq!(
|
||||
AidlResult::rc(AidlRc::KeymintErrorCode),
|
||||
map_or_log_err(nested_rc(AidlRc::KeymintErrorCode), |_| AidlResult::ec(0))
|
||||
);
|
||||
assert_eq!(
|
||||
AidlResult::rc(AidlRc::BackendBusy),
|
||||
map_or_log_err(nested_rc(AidlRc::BackendBusy), |_| AidlResult::ec(0))
|
||||
Result::<(), i32>::Err(Rc::PermissionDenied),
|
||||
map_or_log_err(nested_selinux_perm(), |_| Err(BinderStatus::ok()))
|
||||
.map_err(|s| s.service_specific_error())
|
||||
);
|
||||
|
||||
// All KeystoreKerror::Km(x) get mapped on
|
||||
// aidl::Result{AidlRc::KeymintErrorCode, x}
|
||||
// All other errors get mapped on System Error.
|
||||
assert_eq!(
|
||||
AidlResult::ec(-7),
|
||||
map_or_log_err(nested_ec(-7), |_| AidlResult::rc(AidlRc::SystemError))
|
||||
);
|
||||
|
||||
// All other get mapped on System Error.
|
||||
assert_eq!(
|
||||
AidlResult::rc(AidlRc::SystemError),
|
||||
map_or_log_err(nested_other_error(), |_| AidlResult::ec(0))
|
||||
Result::<(), i32>::Err(Rc::SystemError),
|
||||
map_or_log_err(nested_other_error(), |_| Err(BinderStatus::ok()))
|
||||
.map_err(|s| s.service_specific_error())
|
||||
);
|
||||
|
||||
// Result::Ok variants get passed to the ok handler.
|
||||
assert_eq!(
|
||||
AidlResult::rc(AidlRc::OpAuthNeeded),
|
||||
map_or_log_err(nested_ok(AidlRc::OpAuthNeeded), AidlResult::rc)
|
||||
);
|
||||
assert_eq!(AidlResult::ok(), map_or_log_err(nested_ok(AidlRc::Ok), AidlResult::rc));
|
||||
assert_eq!(Ok(Rc::OpAuthNeeded), map_or_log_err(nested_ok(Rc::OpAuthNeeded), Ok));
|
||||
assert_eq!(Ok(Rc::Ok), map_or_log_err(nested_ok(Rc::Ok), Ok));
|
||||
|
||||
// selinux::Error::Perm() needs to be mapped to AidlRc::PermissionDenied
|
||||
assert_eq!(
|
||||
AidlResult::rc(AidlRc::PermissionDenied),
|
||||
map_or_log_err(nested_selinux_perm(), |_| AidlResult::ec(0))
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
//Helper function to test whether error cases are handled as expected.
|
||||
pub fn check_result_contains_error_string<T>(result: Result<T>, expected_error_string: &str) {
|
||||
pub fn check_result_contains_error_string<T>(
|
||||
result: anyhow::Result<T>,
|
||||
expected_error_string: &str,
|
||||
) {
|
||||
let error_str = format!(
|
||||
"{:#?}",
|
||||
result.err().unwrap_or_else(|| panic!("Expected the error: {}", expected_error_string))
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
//! and the methods to work with KeyParameter.
|
||||
|
||||
use crate::error::Error as KeystoreError;
|
||||
use crate::error::ResponseCode;
|
||||
use crate::error::Rc;
|
||||
pub use android_hardware_keymint::aidl::android::hardware::keymint::{
|
||||
Algorithm, Algorithm::Algorithm as AlgorithmType, BlockMode,
|
||||
BlockMode::BlockMode as BlockModeType, Digest, Digest::Digest as DigestType, EcCurve,
|
||||
|
@ -354,14 +354,14 @@ impl KeyParameter {
|
|||
Tag::PURPOSE => {
|
||||
let key_purpose: KeyPurposeType = data
|
||||
.get()
|
||||
.map_err(|_| KeystoreError::Rc(ResponseCode::ValueCorrupted))
|
||||
.map_err(|_| KeystoreError::Rc(Rc::ValueCorrupted))
|
||||
.context("Failed to read sql data for tag: PURPOSE.")?;
|
||||
KeyParameterValue::KeyPurpose(key_purpose)
|
||||
}
|
||||
Tag::ALGORITHM => {
|
||||
let algorithm: AlgorithmType = data
|
||||
.get()
|
||||
.map_err(|_| KeystoreError::Rc(ResponseCode::ValueCorrupted))
|
||||
.map_err(|_| KeystoreError::Rc(Rc::ValueCorrupted))
|
||||
.context("Failed to read sql data for tag: ALGORITHM.")?;
|
||||
KeyParameterValue::Algorithm(algorithm)
|
||||
}
|
||||
|
@ -373,21 +373,21 @@ impl KeyParameter {
|
|||
Tag::BLOCK_MODE => {
|
||||
let block_mode: BlockModeType = data
|
||||
.get()
|
||||
.map_err(|_| KeystoreError::Rc(ResponseCode::ValueCorrupted))
|
||||
.map_err(|_| KeystoreError::Rc(Rc::ValueCorrupted))
|
||||
.context("Failed to read sql data for tag: BLOCK_MODE.")?;
|
||||
KeyParameterValue::BlockMode(block_mode)
|
||||
}
|
||||
Tag::DIGEST => {
|
||||
let digest: DigestType = data
|
||||
.get()
|
||||
.map_err(|_| KeystoreError::Rc(ResponseCode::ValueCorrupted))
|
||||
.map_err(|_| KeystoreError::Rc(Rc::ValueCorrupted))
|
||||
.context("Failed to read sql data for tag: DIGEST.")?;
|
||||
KeyParameterValue::Digest(digest)
|
||||
}
|
||||
Tag::PADDING => {
|
||||
let padding: PaddingModeType = data
|
||||
.get()
|
||||
.map_err(|_| KeystoreError::Rc(ResponseCode::ValueCorrupted))
|
||||
.map_err(|_| KeystoreError::Rc(Rc::ValueCorrupted))
|
||||
.context("Failed to read sql data for tag: PADDING.")?;
|
||||
KeyParameterValue::PaddingMode(padding)
|
||||
}
|
||||
|
@ -400,7 +400,7 @@ impl KeyParameter {
|
|||
Tag::EC_CURVE => {
|
||||
let ec_curve: EcCurveType = data
|
||||
.get()
|
||||
.map_err(|_| KeystoreError::Rc(ResponseCode::ValueCorrupted))
|
||||
.map_err(|_| KeystoreError::Rc(Rc::ValueCorrupted))
|
||||
.context("Failed to read sql data for tag: EC_CURVE.")?;
|
||||
KeyParameterValue::EcCurve(ec_curve)
|
||||
}
|
||||
|
@ -455,7 +455,7 @@ impl KeyParameter {
|
|||
Tag::USER_AUTH_TYPE => {
|
||||
let user_auth_type: HardwareAuthenticatorTypeType = data
|
||||
.get()
|
||||
.map_err(|_| KeystoreError::Rc(ResponseCode::ValueCorrupted))
|
||||
.map_err(|_| KeystoreError::Rc(Rc::ValueCorrupted))
|
||||
.context("Failed to read sql data for tag: USER_AUTH_TYPE.")?;
|
||||
KeyParameterValue::HardwareAuthenticatorType(user_auth_type)
|
||||
}
|
||||
|
@ -486,7 +486,7 @@ impl KeyParameter {
|
|||
Tag::ORIGIN => {
|
||||
let origin: KeyOriginType = data
|
||||
.get()
|
||||
.map_err(|_| KeystoreError::Rc(ResponseCode::ValueCorrupted))
|
||||
.map_err(|_| KeystoreError::Rc(Rc::ValueCorrupted))
|
||||
.context("Failed to read sql data for tag: ORIGIN.")?;
|
||||
KeyParameterValue::KeyOrigin(origin)
|
||||
}
|
||||
|
@ -598,7 +598,7 @@ impl KeyParameter {
|
|||
KeyParameterValue::ConfirmationToken(confirmation_token)
|
||||
}
|
||||
_ => {
|
||||
return Err(KeystoreError::Rc(ResponseCode::ValueCorrupted))
|
||||
return Err(KeystoreError::Rc(Rc::ValueCorrupted))
|
||||
.context("Failed to decode Tag enum from value.")?
|
||||
}
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue