hwcryptohal: Adding hwcrypto key tests
Adding test for hwcrypto key interface.
Bug: 393162614
Test: atest VtsAidlHwCryptoTests
Change-Id: I11db0dbe125f3ca53bccfbbe3ac0e5e4b5acb771
diff --git a/security/see/hwcrypto/aidl/vts/functional/Android.bp b/security/see/hwcrypto/aidl/vts/functional/Android.bp
index c2514d1..fc8215e 100644
--- a/security/see/hwcrypto/aidl/vts/functional/Android.bp
+++ b/security/see/hwcrypto/aidl/vts/functional/Android.bp
@@ -30,6 +30,7 @@
"libvsock",
"librpcbinder_rs",
"librustutils",
+ "libhwcryptohal_common",
],
arch: {
arm64: {
@@ -50,8 +51,8 @@
}
rust_test {
- name: "VtsAidlHwCryptoConnTest",
- srcs: ["connection_test.rs"],
+ name: "VtsAidlHwCryptoTests",
+ srcs: ["hwcryptokey_tests.rs"],
require_root: true,
defaults: [
"hw_crypto_hal_aidl_rust_defaults",
diff --git a/security/see/hwcrypto/aidl/vts/functional/AndroidTestSystem.xml b/security/see/hwcrypto/aidl/vts/functional/AndroidTestSystem.xml
deleted file mode 100644
index 649be23..0000000
--- a/security/see/hwcrypto/aidl/vts/functional/AndroidTestSystem.xml
+++ /dev/null
@@ -1,56 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright 2025 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- -->
- <configuration description="Runs {MODULE}">
- <!-- object type="module_controller" class="com.android.tradefed.testtype.suite.module.CommandSuccessModuleController" -->
- <!--Skip the test when trusty VM is not enabled. -->
- <!--option name="run-command" value="getprop trusty.test_vm.nonsecure_vm_ready | grep 1" /-->
- <!--/object-->
- <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer" />
- <!-- Target Preparers - Run Shell Commands -->
- <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
- <option name="cleanup" value="true" />
- <option name="push-file" key="trusty-vm-launcher.sh" value="/data/local/tmp/trusty_test_vm/trusty-vm-launcher.sh" />
- <option name="push-file" key="trusty-wait-ready.sh" value="/data/local/tmp/trusty_test_vm/trusty-wait-ready.sh" />
- <option name="push-file" key="wait_hw_crypto" value="/data/local/tmp/trusty_test_vm/wait_hw_crypto" />
- <option name="push-file" key="trusty-test_vm-config.json" value="/data/local/tmp/trusty_test_vm/trusty-test_vm-config.json" />
- <option name="push-file" key="trusty_test_vm.elf" value="/data/local/tmp/trusty_test_vm/trusty_test_vm.elf" />
- <option name="push-file" key="VtsAidlHwCryptoConnTestSystem" value="/data/local/tmp/VtsAidlHwCryptoConnTestSystem" />
- </target_preparer>
- <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
- <option name="throw-if-cmd-fail" value="true" />
- <!--Note: the first run-command shall not expect the background command to have started -->
- <option name="run-bg-command" value="sh /data/local/tmp/trusty_test_vm/trusty-vm-launcher.sh" />
- <option name="run-command" value="sh /data/local/tmp/trusty_test_vm/trusty-wait-ready.sh" />
- <option name="run-bg-command" value="start trusty-hwcryptohal" />
- <option name="run-command" value="/data/local/tmp/trusty_test_vm/wait_hw_crypto" />
- <option name="run-command" value="start storageproxyd_test_system" />
- <option name="teardown-command" value="stop storageproxyd_test_system" />
- <option name="teardown-command" value="stop trusty-hwcryptohal" />
- <option name="teardown-command" value="killall storageproxyd_test_system || true" />
- <option name="teardown-command" value="stop trusty-hwcryptohal" />
- <option name="teardown-command" value="killall trusty || true" />
- </target_preparer>
-
- <test class="com.android.tradefed.testtype.rust.RustBinaryTest" >
- <option name="test-device-path" value="/data/local/tmp" />
- <option name="module-name" value="VtsAidlHwCryptoConnTestSystem" />
- <!-- Rust tests are run in parallel by default. Run these ones
- single-threaded, so that one test's secrets don't affect
- the behaviour of a different test. -->
- <option name="native-test-flag" value="--test-threads=1" />
- </test>
- </configuration>
diff --git a/security/see/hwcrypto/aidl/vts/functional/connection_test.rs b/security/see/hwcrypto/aidl/vts/functional/connection_test.rs
deleted file mode 100644
index 338923d..0000000
--- a/security/see/hwcrypto/aidl/vts/functional/connection_test.rs
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * Copyright (C) 2024 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//! HwCrypto Connection tests.
-
-#[test]
-fn test_hwcrypto_key_connection() {
- let hw_crypto_key = hwcryptohal_vts_test::get_hwcryptokey();
- assert!(hw_crypto_key.is_ok(), "Couldn't get back a hwcryptokey binder object");
-}
diff --git a/security/see/hwcrypto/aidl/vts/functional/hwcryptokey_tests.rs b/security/see/hwcrypto/aidl/vts/functional/hwcryptokey_tests.rs
new file mode 100644
index 0000000..fcce839
--- /dev/null
+++ b/security/see/hwcrypto/aidl/vts/functional/hwcryptokey_tests.rs
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//! HwCryptoKey tests.
+
+use android_hardware_security_see_hwcrypto::aidl::android::hardware::security::see::hwcrypto::IHwCryptoKey::{
+ DerivedKeyParameters::DerivedKeyParameters, DerivedKeyPolicy::DerivedKeyPolicy,
+ DiceBoundDerivationKey::DiceBoundDerivationKey, KeySlot::KeySlot,
+};
+use android_hardware_security_see_hwcrypto::aidl::android::hardware::security::see::hwcrypto::types::{
+ HalErrorCode, AesKey::AesKey, ExplicitKeyMaterial::ExplicitKeyMaterial, KeyType::KeyType, KeyLifetime::KeyLifetime, KeyUse::KeyUse,
+ HmacKey::HmacKey, ProtectionId::ProtectionId,
+};
+use android_hardware_security_see_hwcrypto::aidl::android::hardware::security::see::hwcrypto::KeyPolicy::KeyPolicy;
+use hwcryptohal_common;
+
+#[test]
+fn test_hwcrypto_key_connection() {
+ let hw_crypto_key = hwcryptohal_vts_test::get_hwcryptokey();
+ assert!(hw_crypto_key.is_ok(), "Couldn't get back a hwcryptokey binder object");
+}
+
+#[test]
+fn test_hwcrypto_key_get_current_dice_policy() {
+ let hw_crypto_key = hwcryptohal_vts_test::get_hwcryptokey()
+ .expect("Couldn't get back a hwcryptokey binder object");
+ let dice_policy = hw_crypto_key.getCurrentDicePolicy().expect("Couldn't get dice policy back");
+ assert!(!dice_policy.is_empty(), "received empty dice policy");
+}
+
+#[test]
+fn test_hwcrypto_get_keyslot_data() {
+ let hw_crypto_key = hwcryptohal_vts_test::get_hwcryptokey()
+ .expect("Couldn't get back a hwcryptokey binder object");
+ let key = hw_crypto_key.getKeyslotData(KeySlot::KEYMINT_SHARED_HMAC_KEY);
+ assert_eq!(
+ key.err()
+ .expect("should not be able to access this keylost from the host")
+ .service_specific_error(),
+ HalErrorCode::UNAUTHORIZED,
+ "wrong error type received"
+ );
+}
+
+#[test]
+fn test_hwcrypto_import_clear_key() {
+ let hw_crypto_key = hwcryptohal_vts_test::get_hwcryptokey()
+ .expect("Couldn't get back a hwcryptokey binder object");
+ let clear_key = ExplicitKeyMaterial::Aes(AesKey::Aes128([0; 16]));
+ let mut policy = KeyPolicy {
+ usage: KeyUse::ENCRYPT_DECRYPT,
+ keyLifetime: KeyLifetime::PORTABLE,
+ keyPermissions: Vec::new(),
+ keyManagementKey: false,
+ keyType: KeyType::AES_128_GCM,
+ };
+ let key = hw_crypto_key.importClearKey(&clear_key, &policy).expect("couldn't import key");
+ assert!(key.getPublicKey().is_err(), "symmetric keys don't have a public key");
+ let imported_policy = key.getKeyPolicy().expect("couldn't get key policy");
+ let serialized_policy =
+ hwcryptohal_common::key_policy_to_cbor(&policy).expect("couldn't serialize policy");
+ let serialized_impoorted_policy = hwcryptohal_common::key_policy_to_cbor(&imported_policy)
+ .expect("couldn't serialize policy");
+ assert_eq!(serialized_policy, serialized_impoorted_policy, "policies should match");
+ policy.keyLifetime = KeyLifetime::EPHEMERAL;
+ let key = hw_crypto_key.importClearKey(&clear_key, &policy);
+ assert!(key.is_err(), "imported keys should be of type PORTABLE");
+ policy.keyLifetime = KeyLifetime::HARDWARE;
+ let key = hw_crypto_key.importClearKey(&clear_key, &policy);
+ assert!(key.is_err(), "imported keys should be of type PORTABLE");
+}
+
+#[test]
+fn test_hwcrypto_token_export_import() {
+ // This test is not representative of the complete flow because here the exporter and importer
+ // are the same client, which is not something we would usually do
+ let hw_crypto_key = hwcryptohal_vts_test::get_hwcryptokey()
+ .expect("Couldn't get back a hwcryptokey binder object");
+ let clear_key = ExplicitKeyMaterial::Hmac(HmacKey::Sha256([0; 32]));
+ let policy = KeyPolicy {
+ usage: KeyUse::DERIVE,
+ keyLifetime: KeyLifetime::PORTABLE,
+ keyPermissions: Vec::new(),
+ keyManagementKey: false,
+ keyType: KeyType::HMAC_SHA256,
+ };
+ let key = hw_crypto_key.importClearKey(&clear_key, &policy).expect("couldn't import clear key");
+ let dice_policy = hw_crypto_key.getCurrentDicePolicy().expect("Couldn't get dice policy back");
+ let token =
+ key.getShareableToken(dice_policy.as_slice()).expect("Couldn't get shareable token");
+ let imported_key = hw_crypto_key
+ .keyTokenImport(&token, dice_policy.as_slice());
+ assert!(imported_key.is_ok(), "Couldn't import shareable token");
+ // TODO: Use operations to verify that the keys match
+}
+
+#[test]
+fn test_hwcrypto_android_invalid_calls() {
+ let hw_crypto_key = hwcryptohal_vts_test::get_hwcryptokey()
+ .expect("Couldn't get back a hwcryptokey binder object");
+ let clear_key = ExplicitKeyMaterial::Hmac(HmacKey::Sha256([0; 32]));
+ let policy = KeyPolicy {
+ usage: KeyUse::DERIVE,
+ keyLifetime: KeyLifetime::PORTABLE,
+ keyPermissions: Vec::new(),
+ keyManagementKey: false,
+ keyType: KeyType::HMAC_SHA256,
+ };
+ let key = hw_crypto_key.importClearKey(&clear_key, &policy).expect("couldn't import clear key");
+ let protections = Vec::new();
+ let res = key.setProtectionId(ProtectionId::WIDEVINE_OUTPUT_BUFFER, &protections);
+ assert_eq!(
+ res.err()
+ .expect("should not be call this function from the host")
+ .service_specific_error(),
+ HalErrorCode::UNAUTHORIZED,
+ "wrong error type received"
+ );
+ let derivation_key = DiceBoundDerivationKey::OpaqueKey(Some(key));
+ let res = hw_crypto_key.deriveCurrentDicePolicyBoundKey(&derivation_key);
+ assert_eq!(
+ res.err()
+ .expect("should not be call this function from the host")
+ .service_specific_error(),
+ HalErrorCode::UNAUTHORIZED,
+ "wrong error type received"
+ );
+ let fake_policy = Vec::new();
+ let res = hw_crypto_key.deriveDicePolicyBoundKey(&derivation_key, &fake_policy);
+ assert_eq!(
+ res.err()
+ .expect("should not be call this function from the host")
+ .service_specific_error(),
+ HalErrorCode::UNAUTHORIZED,
+ "wrong error type received"
+ );
+ let key = hw_crypto_key.importClearKey(&clear_key, &policy).expect("couldn't import clear key");
+ let derived_policy = DerivedKeyPolicy::OpaqueKey(Vec::new());
+ let derived_parameters = DerivedKeyParameters {
+ derivationKey: Some(key),
+ keyPolicy: derived_policy,
+ context: Vec::new(),
+ };
+ let res = hw_crypto_key.deriveKey(&derived_parameters);
+ assert_eq!(
+ res.err()
+ .expect("should not be call this function from the host")
+ .service_specific_error(),
+ HalErrorCode::UNAUTHORIZED,
+ "wrong error type received"
+ );
+}