From 86124738cd468e5fb9306ef043ffe87598ca295b Mon Sep 17 00:00:00 2001 From: Janis Danisevskis Date: Tue, 9 Nov 2021 23:00:26 -0800 Subject: [PATCH 1/2] Dice HAL: Added default implementation. Test: ... one ... Bug: 198197213 Change-Id: If855e2a4a0150d80e7cecce0a078cdeca00bdb50 --- security/dice/aidl/default/Android.bp | 30 +++++ ...curity.dice-service.non-secure-software.rc | 9 ++ ...urity.dice-service.non-secure-software.xml | 6 + security/dice/aidl/default/service.rs | 107 ++++++++++++++++++ 4 files changed, 152 insertions(+) create mode 100644 security/dice/aidl/default/Android.bp create mode 100644 security/dice/aidl/default/android.hardware.security.dice-service.non-secure-software.rc create mode 100644 security/dice/aidl/default/android.hardware.security.dice-service.non-secure-software.xml create mode 100644 security/dice/aidl/default/service.rs diff --git a/security/dice/aidl/default/Android.bp b/security/dice/aidl/default/Android.bp new file mode 100644 index 0000000000..b67a44aa84 --- /dev/null +++ b/security/dice/aidl/default/Android.bp @@ -0,0 +1,30 @@ +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "hardware_interfaces_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["hardware_interfaces_license"], +} + +rust_binary { + name: "android.hardware.security.dice-service.non-secure-software", + srcs: ["service.rs"], + relative_install_path: "hw", + vendor: true, + rustlibs: [ + "android.hardware.security.dice-V1-rust", + "libdiced_open_dice_cbor", + "libdiced_sample_inputs", + "libdiced_vendor", + "libandroid_logger", + "libanyhow", + "libbinder_rs", + "liblog_rust", + "libserde", + ], + init_rc: ["android.hardware.security.dice-service.non-secure-software.rc"], + vintf_fragments: [ + "android.hardware.security.dice-service.non-secure-software.xml", + ], +} diff --git a/security/dice/aidl/default/android.hardware.security.dice-service.non-secure-software.rc b/security/dice/aidl/default/android.hardware.security.dice-service.non-secure-software.rc new file mode 100644 index 0000000000..28e43c3bfa --- /dev/null +++ b/security/dice/aidl/default/android.hardware.security.dice-service.non-secure-software.rc @@ -0,0 +1,9 @@ +service vendor.dice /vendor/bin/hw/android.hardware.security.dice-service.non-secure-software + class early_hal + user nobody + # The diced HAL cannot be allowed to restart. When it crashes for any reason. + # it loses security critical state. The only remedy is to restart the device. + # This may be implementation depended. It is safe to restart the HAL if the + # state change during a call to "demote" is is preserved. + # see android/hardware/security/dice/IDiceDevice.aidl for details on "demote". + oneshot diff --git a/security/dice/aidl/default/android.hardware.security.dice-service.non-secure-software.xml b/security/dice/aidl/default/android.hardware.security.dice-service.non-secure-software.xml new file mode 100644 index 0000000000..94ef24363b --- /dev/null +++ b/security/dice/aidl/default/android.hardware.security.dice-service.non-secure-software.xml @@ -0,0 +1,6 @@ + + + android.hardware.security.dice + IDiceDevice/default + + \ No newline at end of file diff --git a/security/dice/aidl/default/service.rs b/security/dice/aidl/default/service.rs new file mode 100644 index 0000000000..eebf3332a6 --- /dev/null +++ b/security/dice/aidl/default/service.rs @@ -0,0 +1,107 @@ +// Copyright 2021, 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. + +//! Main entry point for the android.hardware.security.dice service. + +use anyhow::Result; +use diced::{ + dice, + hal_node::{DiceArtifacts, DiceDevice, ResidentHal, UpdatableDiceArtifacts}, +}; +use diced_sample_inputs::make_sample_bcc_and_cdis; +use serde::{Deserialize, Serialize}; +use std::convert::TryInto; +use std::panic; +use std::sync::Arc; + +static DICE_HAL_SERVICE_NAME: &str = "android.hardware.security.dice.IDiceDevice/default"; + +#[derive(Debug, Serialize, Deserialize, Clone)] +struct InsecureSerializableArtifacts { + cdi_attest: [u8; dice::CDI_SIZE], + cdi_seal: [u8; dice::CDI_SIZE], + bcc: Vec, +} + +impl DiceArtifacts for InsecureSerializableArtifacts { + fn cdi_attest(&self) -> &[u8; dice::CDI_SIZE] { + &self.cdi_attest + } + fn cdi_seal(&self) -> &[u8; dice::CDI_SIZE] { + &self.cdi_seal + } + fn bcc(&self) -> Vec { + self.bcc.clone() + } +} + +impl UpdatableDiceArtifacts for InsecureSerializableArtifacts { + fn with_artifacts(&self, f: F) -> Result + where + F: FnOnce(&dyn DiceArtifacts) -> Result, + { + f(self) + } + fn update(self, new_artifacts: &impl DiceArtifacts) -> Result { + Ok(Self { + cdi_attest: *new_artifacts.cdi_attest(), + cdi_seal: *new_artifacts.cdi_seal(), + bcc: new_artifacts.bcc(), + }) + } +} + +fn main() { + android_logger::init_once( + android_logger::Config::default() + .with_tag("android.hardware.security.dice") + .with_min_level(log::Level::Debug), + ); + // Redirect panic messages to logcat. + panic::set_hook(Box::new(|panic_info| { + log::error!("{}", panic_info); + })); + + // Saying hi. + log::info!("android.hardware.security.dice is starting."); + + let (cdi_attest, cdi_seal, bcc) = + make_sample_bcc_and_cdis().expect("Failed to construct sample dice chain."); + + let hal_impl = Arc::new( + unsafe { + // Safety: ResidentHal cannot be used in multi threaded processes. + // This service does not start a thread pool. The main thread is the only thread + // joining the thread pool, thereby keeping the process single threaded. + ResidentHal::new(InsecureSerializableArtifacts { + cdi_attest: cdi_attest[..] + .try_into() + .expect("Failed to convert cdi_attest to array reference."), + cdi_seal: cdi_seal[..] + .try_into() + .expect("Failed to convert cdi_seal to array reference."), + bcc, + }) + } + .expect("Failed to create ResidentHal implementation."), + ); + + let hal = DiceDevice::new_as_binder(hal_impl).expect("Failed to construct hal service."); + + binder::add_service(DICE_HAL_SERVICE_NAME, hal.as_binder()) + .expect("Failed to register IDiceDevice Service"); + + log::info!("Joining thread pool now."); + binder::ProcessState::join_thread_pool(); +} From 21244fc19217720fa2a233f63503d3d404ceee12 Mon Sep 17 00:00:00 2001 From: Janis Danisevskis Date: Tue, 16 Nov 2021 08:47:50 -0800 Subject: [PATCH 2/2] Dice HAL: Add VTS Test. This CL adds a VTS test for the DICE HAL, and a test specific for demotion testing. Demotion testing leaves the device in a permanently modified state untill the next reboot, which is why it needs a special test config. The current test config restarts the device before testing, in a followup the device also has to reboot after the test. Bug: 198197213 Test: atest VtsAidlDiceTargetTest atest VtsAidlDiceDemoteTargetTest Change-Id: I4278a1352df749da50dc8e5d118fc37336026061 --- security/dice/aidl/vts/functional/Android.bp | 54 ++++++++++++ .../VtsAidlDiceDemoteTargetTest.xml | 33 ++++++++ .../aidl/vts/functional/dice_demote_test.rs | 67 +++++++++++++++ .../dice/aidl/vts/functional/dice_test.rs | 82 +++++++++++++++++++ security/dice/aidl/vts/functional/utils.rs | 53 ++++++++++++ 5 files changed, 289 insertions(+) create mode 100644 security/dice/aidl/vts/functional/Android.bp create mode 100644 security/dice/aidl/vts/functional/VtsAidlDiceDemoteTargetTest.xml create mode 100644 security/dice/aidl/vts/functional/dice_demote_test.rs create mode 100644 security/dice/aidl/vts/functional/dice_test.rs create mode 100644 security/dice/aidl/vts/functional/utils.rs diff --git a/security/dice/aidl/vts/functional/Android.bp b/security/dice/aidl/vts/functional/Android.bp new file mode 100644 index 0000000000..f5bc949f11 --- /dev/null +++ b/security/dice/aidl/vts/functional/Android.bp @@ -0,0 +1,54 @@ +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "hardware_interfaces_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["hardware_interfaces_license"], +} + +rust_test { + name: "VtsAidlDiceTargetTest", + srcs: [ + "dice_test.rs", + ], + require_root: true, + auto_gen_config: true, + test_suites: [ + "general-tests", + "vts", + ], + + rustlibs: [ + "android.hardware.security.dice-V1-rust", + "libanyhow", + "libbinder_rs", + "libdiced_open_dice_cbor", + "libdiced_sample_inputs", + "libdiced_utils", + "libkeystore2_vintf_rust", + ], +} + +rust_test { + name: "VtsAidlDiceDemoteTargetTest", + srcs: [ + "dice_demote_test.rs", + ], + + test_config: "VtsAidlDiceDemoteTargetTest.xml", + test_suites: [ + "general-tests", + "vts", + ], + + rustlibs: [ + "android.hardware.security.dice-V1-rust", + "libanyhow", + "libbinder_rs", + "libdiced_open_dice_cbor", + "libdiced_sample_inputs", + "libdiced_utils", + "libkeystore2_vintf_rust", + ], +} diff --git a/security/dice/aidl/vts/functional/VtsAidlDiceDemoteTargetTest.xml b/security/dice/aidl/vts/functional/VtsAidlDiceDemoteTargetTest.xml new file mode 100644 index 0000000000..2991580000 --- /dev/null +++ b/security/dice/aidl/vts/functional/VtsAidlDiceDemoteTargetTest.xml @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/security/dice/aidl/vts/functional/dice_demote_test.rs b/security/dice/aidl/vts/functional/dice_demote_test.rs new file mode 100644 index 0000000000..02ff2a455a --- /dev/null +++ b/security/dice/aidl/vts/functional/dice_demote_test.rs @@ -0,0 +1,67 @@ +// Copyright 2021, 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. + +use diced_open_dice_cbor as dice; +use diced_sample_inputs; +use diced_utils; +use std::convert::TryInto; + +mod utils; +use utils::with_connection; + +// This test calls derive with an empty argument vector, then demotes the HAL using +// a set of three input values, and then calls derive with empty argument vector again. +// It then performs the same three derivation steps on the result of the former and compares +// the result to the result of the latter. +#[test] +fn demote_test() { + with_connection(|device| { + let input_values = diced_sample_inputs::get_input_values_vector(); + let former = device.derive(&[]).expect("Trying to call derive."); + device + .demote(&input_values) + .expect("Trying to call demote with input values."); + + let latter = device + .derive(&[]) + .expect("Trying to call derive after demote."); + + let artifacts = diced_utils::ResidentArtifacts::new( + former.cdiAttest[..].try_into().unwrap(), + former.cdiSeal[..].try_into().unwrap(), + &former.bcc.data, + ) + .unwrap(); + + let input_values: Vec = input_values + .iter() + .map(|v| v.into()) + .collect(); + + let artifacts = artifacts + .execute_steps(input_values.iter().map(|v| v as &dyn dice::InputValues)) + .unwrap(); + let (cdi_attest, cdi_seal, bcc) = artifacts.into_tuple(); + let from_former = diced_utils::make_bcc_handover( + cdi_attest[..].try_into().unwrap(), + cdi_seal[..].try_into().unwrap(), + &bcc, + ) + .unwrap(); + // TODO b/204938506 when we have a parser/verifier, check equivalence rather + // than bit by bit equality. + assert_eq!(latter, from_former); + Ok(()) + }) +} diff --git a/security/dice/aidl/vts/functional/dice_test.rs b/security/dice/aidl/vts/functional/dice_test.rs new file mode 100644 index 0000000000..574b634d52 --- /dev/null +++ b/security/dice/aidl/vts/functional/dice_test.rs @@ -0,0 +1,82 @@ +// Copyright 2021, 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. + +use diced_open_dice_cbor as dice; +use diced_sample_inputs; +use diced_utils; +use std::convert::{TryInto, Into}; + +mod utils; +use utils::with_connection; + +static TEST_MESSAGE: &[u8] = &[ + // "My test message!" + 0x4d, 0x79, 0x20, 0x74, 0x65, 0x73, 0x74, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x21, + 0x0a, +]; + +// This test calls derive with an empty argument vector and with a set of three input values. +// It then performs the same three derivation steps on the result of the former and compares +// the result to the result of the latter. +#[test] +fn equivalence_test() { + with_connection(|device| { + let input_values = diced_sample_inputs::get_input_values_vector(); + let former = device.derive(&[]).expect("Trying to call derive."); + let latter = device + .derive(&input_values) + .expect("Trying to call derive with input values."); + let artifacts = diced_utils::ResidentArtifacts::new( + former.cdiAttest[..].try_into().unwrap(), + former.cdiSeal[..].try_into().unwrap(), + &former.bcc.data, + ) + .unwrap(); + + let input_values: Vec = input_values + .iter() + .map(|v| v.into()) + .collect(); + + let artifacts = artifacts + .execute_steps(input_values.iter().map(|v| v as &dyn dice::InputValues)) + .unwrap(); + let (cdi_attest, cdi_seal, bcc) = artifacts.into_tuple(); + let from_former = diced_utils::make_bcc_handover( + cdi_attest[..].try_into().unwrap(), + cdi_seal[..].try_into().unwrap(), + &bcc, + ) + .unwrap(); + // TODO b/204938506 when we have a parser/verifier, check equivalence rather + // than bit by bit equality. + assert_eq!(latter, from_former); + Ok(()) + }) +} + +#[test] +fn sign_and_verify() { + with_connection(|device| { + let _signature = device + .sign(&[], TEST_MESSAGE) + .expect("Trying to call sign."); + + let _bcc = device + .getAttestationChain(&[]) + .expect("Trying to call getAttestationChain."); + // TODO b/204938506 check the signature with the bcc when the verifier is available. + Ok(()) + }) +} diff --git a/security/dice/aidl/vts/functional/utils.rs b/security/dice/aidl/vts/functional/utils.rs new file mode 100644 index 0000000000..4e6708ec5e --- /dev/null +++ b/security/dice/aidl/vts/functional/utils.rs @@ -0,0 +1,53 @@ +// Copyright 2021, 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. + +use android_hardware_security_dice::aidl::android::hardware::security::dice::IDiceDevice::IDiceDevice; +use anyhow::Result; +use binder::Strong; +use keystore2_vintf::get_aidl_instances; +use std::sync::Arc; + +static DICE_DEVICE_SERVICE_NAME: &str = &"android.hardware.security.dice"; +static DICE_DEVICE_INTERFACE_NAME: &str = &"IDiceDevice"; + +/// This function iterates through all announced IDiceDevice services and runs the given test +/// closure against connections to each of them. It also modifies the panic hook to indicate +/// on which instance the test failed in case the test closure panics. +pub fn with_connection(test: F) +where + F: Fn(&Strong) -> Result, +{ + let instances = get_aidl_instances(DICE_DEVICE_SERVICE_NAME, 1, DICE_DEVICE_INTERFACE_NAME); + let panic_hook = Arc::new(std::panic::take_hook()); + for i in instances.into_iter() { + let panic_hook_clone = panic_hook.clone(); + let instance_clone = i.clone(); + std::panic::set_hook(Box::new(move |v| { + println!("While testing instance: \"{}\"", instance_clone); + panic_hook_clone(v) + })); + let connection: Strong = binder::get_interface(&format!( + "{}.{}/{}", + DICE_DEVICE_SERVICE_NAME, DICE_DEVICE_INTERFACE_NAME, i + )) + .unwrap(); + test(&connection).unwrap(); + drop(std::panic::take_hook()); + } + // Cannot call unwrap here because the panic hook is not Debug. + std::panic::set_hook(match Arc::try_unwrap(panic_hook) { + Ok(hook) => hook, + _ => panic!("Failed to unwrap and reset previous panic hook."), + }) +}