Handle errors codes from rkpd getKey operations

Now we'll get error codes bubbled up from rkpd (via the remote
provisioning system service). Convert those errors into meaningful
keystore errors so clients can act on them.

Test: keystore2_tests
Test: RkpdAppIntegrationTests
Test: CtsKeystoreTestCases:android.keystore.cts.KeyStoreExceptionTest
Bug: 264888027
Change-Id: Ib574fe4da0443f32f95f8579c4a308d36fe4b46f
This commit is contained in:
Seth Moore 2023-01-31 11:22:26 -08:00
parent 2636684821
commit 484010a1e4
3 changed files with 68 additions and 38 deletions

View file

@ -21,6 +21,7 @@
#include <android-base/logging.h> #include <android-base/logging.h>
#include <android/security/rkp/BnGetKeyCallback.h> #include <android/security/rkp/BnGetKeyCallback.h>
#include <android/security/rkp/BnGetRegistrationCallback.h> #include <android/security/rkp/BnGetRegistrationCallback.h>
#include <android/security/rkp/IGetKeyCallback.h>
#include <android/security/rkp/IRemoteProvisioning.h> #include <android/security/rkp/IRemoteProvisioning.h>
#include <binder/IServiceManager.h> #include <binder/IServiceManager.h>
#include <binder/Status.h> #include <binder/Status.h>
@ -38,6 +39,7 @@ using ::android::hardware::security::keymint::IRemotelyProvisionedComponent;
using ::android::hardware::security::keymint::RpcHardwareInfo; using ::android::hardware::security::keymint::RpcHardwareInfo;
using ::android::security::rkp::BnGetKeyCallback; using ::android::security::rkp::BnGetKeyCallback;
using ::android::security::rkp::BnGetRegistrationCallback; using ::android::security::rkp::BnGetRegistrationCallback;
using ::android::security::rkp::IGetKeyCallback;
using ::android::security::rkp::IRegistration; using ::android::security::rkp::IRegistration;
using ::android::security::rkp::IRemoteProvisioning; using ::android::security::rkp::IRemoteProvisioning;
using ::android::security::rkp::RemotelyProvisionedKey; using ::android::security::rkp::RemotelyProvisionedKey;
@ -96,11 +98,11 @@ class GetKeyCallback : public BnGetKeyCallback {
keyPromise_.set_value(std::nullopt); keyPromise_.set_value(std::nullopt);
return Status::ok(); return Status::ok();
} }
Status onError(const String16& error) override { Status onError(IGetKeyCallback::ErrorCode error, const String16& description) override {
if (called_.test_and_set()) { if (called_.test_and_set()) {
return Status::ok(); return Status::ok();
} }
LOG(ERROR) << "GetKeyCallback failed: " << error; LOG(ERROR) << "GetKeyCallback failed: " << static_cast<int>(error) << ", " << description;
keyPromise_.set_value(std::nullopt); keyPromise_.set_value(std::nullopt);
return Status::ok(); return Status::ok();
} }
@ -124,7 +126,8 @@ class GetRegistrationCallback : public BnGetRegistrationCallback {
auto cb = sp<GetKeyCallback>::make(std::move(keyPromise_)); auto cb = sp<GetKeyCallback>::make(std::move(keyPromise_));
auto status = registration->getKey(keyId_, cb); auto status = registration->getKey(keyId_, cb);
if (!status.isOk()) { if (!status.isOk()) {
cb->onError(String16("Failed to register GetKeyCallback")); cb->onError(IGetKeyCallback::ErrorCode::ERROR_UNKNOWN,
String16("Failed to register GetKeyCallback"));
} }
return Status::ok(); return Status::ok();
} }

View file

@ -71,11 +71,6 @@ impl Error {
pub fn perm() -> Self { pub fn perm() -> Self {
Error::Rc(ResponseCode::PERMISSION_DENIED) Error::Rc(ResponseCode::PERMISSION_DENIED)
} }
/// Short hand for `Error::Rc(ResponseCode::OUT_OF_KEYS_TRANSIENT_ERROR)`
pub fn out_of_keys() -> Self {
Error::Rc(ResponseCode::OUT_OF_KEYS_TRANSIENT_ERROR)
}
} }
/// Helper function to map the binder status we get from calls into KeyMint /// Helper function to map the binder status we get from calls into KeyMint

View file

@ -13,16 +13,15 @@
// limitations under the License. // limitations under the License.
//! Helper wrapper around RKPD interface. //! Helper wrapper around RKPD interface.
// TODO(b/264891956): Return RKP specific errors.
use crate::error::{map_binder_status_code, Error}; use crate::error::{map_binder_status_code, Error, ResponseCode};
use crate::globals::get_remotely_provisioned_component_name; use crate::globals::get_remotely_provisioned_component_name;
use crate::ks_err; use crate::ks_err;
use crate::utils::watchdog as wd; use crate::utils::watchdog as wd;
use android_hardware_security_keymint::aidl::android::hardware::security::keymint::SecurityLevel::SecurityLevel; use android_hardware_security_keymint::aidl::android::hardware::security::keymint::SecurityLevel::SecurityLevel;
use android_security_rkp_aidl::aidl::android::security::rkp::{ use android_security_rkp_aidl::aidl::android::security::rkp::{
IGetKeyCallback::BnGetKeyCallback, IGetKeyCallback::IGetKeyCallback, IGetKeyCallback::BnGetKeyCallback, IGetKeyCallback::ErrorCode::ErrorCode as GetKeyErrorCode,
IGetRegistrationCallback::BnGetRegistrationCallback, IGetKeyCallback::IGetKeyCallback, IGetRegistrationCallback::BnGetRegistrationCallback,
IGetRegistrationCallback::IGetRegistrationCallback, IRegistration::IRegistration, IGetRegistrationCallback::IGetRegistrationCallback, IRegistration::IRegistration,
IRemoteProvisioning::IRemoteProvisioning, IRemoteProvisioning::IRemoteProvisioning,
IStoreUpgradedKeyCallback::BnStoreUpgradedKeyCallback, IStoreUpgradedKeyCallback::BnStoreUpgradedKeyCallback,
@ -30,7 +29,6 @@ use android_security_rkp_aidl::aidl::android::security::rkp::{
RemotelyProvisionedKey::RemotelyProvisionedKey, RemotelyProvisionedKey::RemotelyProvisionedKey,
}; };
use android_security_rkp_aidl::binder::{BinderFeatures, Interface, Strong}; use android_security_rkp_aidl::binder::{BinderFeatures, Interface, Strong};
use android_system_keystore2::aidl::android::system::keystore2::ResponseCode::ResponseCode;
use anyhow::{Context, Result}; use anyhow::{Context, Result};
use std::sync::Mutex; use std::sync::Mutex;
use std::time::Duration; use std::time::Duration;
@ -91,17 +89,17 @@ impl IGetRegistrationCallback for GetRegistrationCallback {
let _wp = wd::watch_millis("IGetRegistrationCallback::onCancel", 500); let _wp = wd::watch_millis("IGetRegistrationCallback::onCancel", 500);
log::warn!("IGetRegistrationCallback cancelled"); log::warn!("IGetRegistrationCallback cancelled");
self.registration_tx.send( self.registration_tx.send(
Err(Error::Rc(ResponseCode::OUT_OF_KEYS)) Err(Error::Rc(ResponseCode::OUT_OF_KEYS_TRANSIENT_ERROR))
.context(ks_err!("GetRegistrationCallback cancelled.")), .context(ks_err!("GetRegistrationCallback cancelled.")),
); );
Ok(()) Ok(())
} }
fn onError(&self, error: &str) -> binder::Result<()> { fn onError(&self, description: &str) -> binder::Result<()> {
let _wp = wd::watch_millis("IGetRegistrationCallback::onError", 500); let _wp = wd::watch_millis("IGetRegistrationCallback::onError", 500);
log::error!("IGetRegistrationCallback failed: '{error}'"); log::error!("IGetRegistrationCallback failed: '{description}'");
self.registration_tx.send( self.registration_tx.send(
Err(Error::Rc(ResponseCode::OUT_OF_KEYS)) Err(Error::Rc(ResponseCode::OUT_OF_KEYS_TRANSIENT_ERROR))
.context(ks_err!("GetRegistrationCallback failed: {:?}", error)), .context(ks_err!("GetRegistrationCallback failed: {:?}", description)),
); );
Ok(()) Ok(())
} }
@ -161,17 +159,33 @@ impl IGetKeyCallback for GetKeyCallback {
let _wp = wd::watch_millis("IGetKeyCallback::onCancel", 500); let _wp = wd::watch_millis("IGetKeyCallback::onCancel", 500);
log::warn!("IGetKeyCallback cancelled"); log::warn!("IGetKeyCallback cancelled");
self.key_tx.send( self.key_tx.send(
Err(Error::Rc(ResponseCode::OUT_OF_KEYS)).context(ks_err!("GetKeyCallback cancelled.")), Err(Error::Rc(ResponseCode::OUT_OF_KEYS_TRANSIENT_ERROR))
.context(ks_err!("GetKeyCallback cancelled.")),
); );
Ok(()) Ok(())
} }
fn onError(&self, error: &str) -> binder::Result<()> { fn onError(&self, error: GetKeyErrorCode, description: &str) -> binder::Result<()> {
let _wp = wd::watch_millis("IGetKeyCallback::onError", 500); let _wp = wd::watch_millis("IGetKeyCallback::onError", 500);
log::error!("IGetKeyCallback failed: {error}"); log::error!("IGetKeyCallback failed: {description}");
self.key_tx.send( let rc = match error {
Err(Error::Rc(ResponseCode::OUT_OF_KEYS)) GetKeyErrorCode::ERROR_UNKNOWN => ResponseCode::OUT_OF_KEYS_TRANSIENT_ERROR,
.context(ks_err!("GetKeyCallback failed: {:?}", error)), GetKeyErrorCode::ERROR_PERMANENT => ResponseCode::OUT_OF_KEYS_PERMANENT_ERROR,
); GetKeyErrorCode::ERROR_PENDING_INTERNET_CONNECTIVITY => {
ResponseCode::OUT_OF_KEYS_PENDING_INTERNET_CONNECTIVITY
}
GetKeyErrorCode::ERROR_REQUIRES_SECURITY_PATCH => {
ResponseCode::OUT_OF_KEYS_REQUIRES_SYSTEM_UPGRADE
}
_ => {
log::error!("Unexpected error from rkpd: {error:?}");
ResponseCode::OUT_OF_KEYS_TRANSIENT_ERROR
}
};
self.key_tx.send(Err(Error::Rc(rc)).context(ks_err!(
"GetKeyCallback failed: {:?} {:?}",
error,
description
)));
Ok(()) Ok(())
} }
} }
@ -188,7 +202,7 @@ async fn get_rkpd_attestation_key_from_registration_async(
.context(ks_err!("Trying to get key."))?; .context(ks_err!("Trying to get key."))?;
match timeout(RKPD_TIMEOUT, rx).await { match timeout(RKPD_TIMEOUT, rx).await {
Err(e) => Err(Error::Rc(ResponseCode::OUT_OF_KEYS)) Err(e) => Err(Error::Rc(ResponseCode::OUT_OF_KEYS_TRANSIENT_ERROR))
.context(ks_err!("Waiting for RKPD key timed out: {:?}", e)), .context(ks_err!("Waiting for RKPD key timed out: {:?}", e)),
Ok(v) => v.unwrap(), Ok(v) => v.unwrap(),
} }
@ -298,6 +312,7 @@ mod tests {
}; };
use android_security_rkp_aidl::aidl::android::security::rkp::IRegistration::BnRegistration; use android_security_rkp_aidl::aidl::android::security::rkp::IRegistration::BnRegistration;
use keystore2_crypto::parse_subject_from_certificate; use keystore2_crypto::parse_subject_from_certificate;
use std::collections::HashMap;
use std::sync::atomic::{AtomicU32, Ordering}; use std::sync::atomic::{AtomicU32, Ordering};
#[derive(Default)] #[derive(Default)]
@ -403,7 +418,7 @@ mod tests {
let result = tokio_rt().block_on(rx).unwrap(); let result = tokio_rt().block_on(rx).unwrap();
assert_eq!( assert_eq!(
result.unwrap_err().downcast::<Error>().unwrap(), result.unwrap_err().downcast::<Error>().unwrap(),
Error::Rc(ResponseCode::OUT_OF_KEYS) Error::Rc(ResponseCode::OUT_OF_KEYS_TRANSIENT_ERROR)
); );
} }
@ -416,7 +431,7 @@ mod tests {
let result = tokio_rt().block_on(rx).unwrap(); let result = tokio_rt().block_on(rx).unwrap();
assert_eq!( assert_eq!(
result.unwrap_err().downcast::<Error>().unwrap(), result.unwrap_err().downcast::<Error>().unwrap(),
Error::Rc(ResponseCode::OUT_OF_KEYS) Error::Rc(ResponseCode::OUT_OF_KEYS_TRANSIENT_ERROR)
); );
} }
@ -441,21 +456,38 @@ mod tests {
let result = tokio_rt().block_on(rx).unwrap(); let result = tokio_rt().block_on(rx).unwrap();
assert_eq!( assert_eq!(
result.unwrap_err().downcast::<Error>().unwrap(), result.unwrap_err().downcast::<Error>().unwrap(),
Error::Rc(ResponseCode::OUT_OF_KEYS) Error::Rc(ResponseCode::OUT_OF_KEYS_TRANSIENT_ERROR)
); );
} }
#[test] #[test]
fn test_get_key_cb_error() { fn test_get_key_cb_error() {
let (tx, rx) = oneshot::channel(); let error_mapping = HashMap::from([
let cb = GetKeyCallback::new_native_binder(tx); (GetKeyErrorCode::ERROR_UNKNOWN, ResponseCode::OUT_OF_KEYS_TRANSIENT_ERROR),
assert!(cb.onError("error").is_ok()); (GetKeyErrorCode::ERROR_PERMANENT, ResponseCode::OUT_OF_KEYS_PERMANENT_ERROR),
(
GetKeyErrorCode::ERROR_PENDING_INTERNET_CONNECTIVITY,
ResponseCode::OUT_OF_KEYS_PENDING_INTERNET_CONNECTIVITY,
),
(
GetKeyErrorCode::ERROR_REQUIRES_SECURITY_PATCH,
ResponseCode::OUT_OF_KEYS_REQUIRES_SYSTEM_UPGRADE,
),
]);
let result = tokio_rt().block_on(rx).unwrap(); // Loop over the generated list of enum values to better ensure this test stays in
assert_eq!( // sync with the AIDL.
result.unwrap_err().downcast::<Error>().unwrap(), for get_key_error in GetKeyErrorCode::enum_values() {
Error::Rc(ResponseCode::OUT_OF_KEYS) let (tx, rx) = oneshot::channel();
); let cb = GetKeyCallback::new_native_binder(tx);
assert!(cb.onError(get_key_error, "error").is_ok());
let result = tokio_rt().block_on(rx).unwrap();
assert_eq!(
result.unwrap_err().downcast::<Error>().unwrap(),
Error::Rc(error_mapping[&get_key_error]),
);
}
} }
#[test] #[test]
@ -503,7 +535,7 @@ mod tests {
tokio_rt().block_on(get_rkpd_attestation_key_from_registration_async(&registration, 0)); tokio_rt().block_on(get_rkpd_attestation_key_from_registration_async(&registration, 0));
assert_eq!( assert_eq!(
result.unwrap_err().downcast::<Error>().unwrap(), result.unwrap_err().downcast::<Error>().unwrap(),
Error::Rc(ResponseCode::OUT_OF_KEYS) Error::Rc(ResponseCode::OUT_OF_KEYS_TRANSIENT_ERROR)
); );
} }