Cope with mixed KeyMint/Keymaster-4.x devices
The keystore2_client_tests have an implicit assumption that any
StrongBox implementation on the device is of the same type (KeyMint or
Keymaster) as the TEE implementation on the device.
However, waivers have been issued for some device types that allow a
mixed combination: StrongBox implementing Keymaster, TEE implementing
KeyMint.
Coping with this requires a pervasive change to use a new `SecLevel`
struct that holds the security level enum value that's associated
with an `IKeystoreSecurityLevel` object, so it's possible to perform
different behaviour for Keymaster/KeyMint on a per-security level basis.
- Add and use `SecLevel::tee()` and `SecLevel::strongbox()`
constructors.
- Move test utilities to take and use `&SecLevel` throughout.
- Canonicalize import ordering along the way.
Then use the `SecLevel::is_keymaster()` and `is_keymint()` methods
to ensure that test behaviour is specific to the device under test,
not just the default device.
Also, device unique attestation was only introduced in KeyMaster 4.1,
so skip those tests if the StrongBox device is not of that level.
Bug: 336695416
Test: keystore2_client_tests
Test: keystore2_test_utils_test
Test: legacykeystore_test
Change-Id: Ie470ec293fcca0cae772a529d8d38ef2d81f2710
diff --git a/keystore2/test_utils/lib.rs b/keystore2/test_utils/lib.rs
index 8394ca1..8b766dd 100644
--- a/keystore2/test_utils/lib.rs
+++ b/keystore2/test_utils/lib.rs
@@ -19,7 +19,13 @@
use std::path::{Path, PathBuf};
use std::{env::temp_dir, ops::Deref};
-use android_system_keystore2::aidl::android::system::keystore2::IKeystoreService::IKeystoreService;
+use android_system_keystore2::aidl::android::system::keystore2::{
+ IKeystoreService::IKeystoreService,
+ IKeystoreSecurityLevel::IKeystoreSecurityLevel,
+};
+use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
+ ErrorCode::ErrorCode, SecurityLevel::SecurityLevel,
+};
use android_security_authorization::aidl::android::security::authorization::IKeystoreAuthorization::IKeystoreAuthorization;
pub mod authorizations;
@@ -123,3 +129,51 @@
pub fn get_keystore_auth_service() -> binder::Strong<dyn IKeystoreAuthorization> {
binder::get_interface(AUTH_SERVICE_NAME).unwrap()
}
+
+/// Security level-specific data.
+pub struct SecLevel {
+ /// Binder connection for the top-level service.
+ pub keystore2: binder::Strong<dyn IKeystoreService>,
+ /// Binder connection for the security level.
+ pub binder: binder::Strong<dyn IKeystoreSecurityLevel>,
+ /// Security level.
+ pub level: SecurityLevel,
+}
+
+impl SecLevel {
+ /// Return security level data for TEE.
+ pub fn tee() -> Self {
+ let level = SecurityLevel::TRUSTED_ENVIRONMENT;
+ let keystore2 = get_keystore_service();
+ let binder =
+ keystore2.getSecurityLevel(level).expect("TEE security level should always be present");
+ Self { keystore2, binder, level }
+ }
+ /// Return security level data for StrongBox, if present.
+ pub fn strongbox() -> Option<Self> {
+ let level = SecurityLevel::STRONGBOX;
+ let keystore2 = get_keystore_service();
+ match key_generations::map_ks_error(keystore2.getSecurityLevel(level)) {
+ Ok(binder) => Some(Self { keystore2, binder, level }),
+ Err(e) => {
+ assert_eq!(e, key_generations::Error::Km(ErrorCode::HARDWARE_TYPE_UNAVAILABLE));
+ None
+ }
+ }
+ }
+ /// Indicate whether this security level is a KeyMint implementation (not Keymaster).
+ pub fn is_keymint(&self) -> bool {
+ let instance = match self.level {
+ SecurityLevel::TRUSTED_ENVIRONMENT => "default",
+ SecurityLevel::STRONGBOX => "strongbox",
+ l => panic!("unexpected level {l:?}"),
+ };
+ let name = format!("android.hardware.security.keymint.IKeyMintDevice/{instance}");
+ binder::is_declared(&name).expect("Could not check for declared keymint interface")
+ }
+
+ /// Indicate whether this security level is a Keymaster implementation (not KeyMint).
+ pub fn is_keymaster(&self) -> bool {
+ !self.is_keymint()
+ }
+}