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:
parent
2636684821
commit
484010a1e4
3 changed files with 68 additions and 38 deletions
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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,22 +456,39 @@ 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 error_mapping = HashMap::from([
|
||||||
|
(GetKeyErrorCode::ERROR_UNKNOWN, ResponseCode::OUT_OF_KEYS_TRANSIENT_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,
|
||||||
|
),
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Loop over the generated list of enum values to better ensure this test stays in
|
||||||
|
// sync with the AIDL.
|
||||||
|
for get_key_error in GetKeyErrorCode::enum_values() {
|
||||||
let (tx, rx) = oneshot::channel();
|
let (tx, rx) = oneshot::channel();
|
||||||
let cb = GetKeyCallback::new_native_binder(tx);
|
let cb = GetKeyCallback::new_native_binder(tx);
|
||||||
assert!(cb.onError("error").is_ok());
|
assert!(cb.onError(get_key_error, "error").is_ok());
|
||||||
|
|
||||||
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(error_mapping[&get_key_error]),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_store_upgraded_cb_success() {
|
fn test_store_upgraded_cb_success() {
|
||||||
|
@ -503,7 +535,7 @@ mod tests {
|
||||||
tokio_rt().block_on(get_rkpd_attestation_key_from_registration_async(®istration, 0));
|
tokio_rt().block_on(get_rkpd_attestation_key_from_registration_async(®istration, 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)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue