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"
+    );
+}