Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9f8fd2b1 authored by Orlando Arbildo's avatar Orlando Arbildo
Browse files

hwcryptohal: Adding hwcrypto key tests

Adding test for hwcrypto key interface.

Bug: 393162614
Test: atest VtsAidlHwCryptoTests
Change-Id: I11db0dbe125f3ca53bccfbbe3ac0e5e4b5acb771
parent 48bbcaff
Loading
Loading
Loading
Loading
+3 −2
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@ rust_defaults {
        "libvsock",
        "librpcbinder_rs",
        "librustutils",
        "libhwcryptohal_common",
    ],
    arch: {
        arm64: {
@@ -50,8 +51,8 @@ rust_library {
}

rust_test {
    name: "VtsAidlHwCryptoConnTest",
    srcs: ["connection_test.rs"],
    name: "VtsAidlHwCryptoTests",
    srcs: ["hwcryptokey_tests.rs"],
    require_root: true,
    defaults: [
        "hw_crypto_hal_aidl_rust_defaults",
+0 −56
Original line number Diff line number Diff line
<?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>
+0 −23
Original line number Diff line number Diff line
/*
 * 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");
}
+165 −0
Original line number Diff line number Diff line
/*
 * 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"
    );
}