Diced: Implement HAL proxy node and initialize it in diced_main.
Still using sample artifacts if no HAL was found.
Test: diced_client_test
Bug: 198197213
Change-Id: I2d218f04cd53a6177dddd3e984879832287bd4dc
diff --git a/diced/Android.bp b/diced/Android.bp
index bef1dec..db0268c 100644
--- a/diced/Android.bp
+++ b/diced/Android.bp
@@ -125,6 +125,7 @@
name: "diced",
srcs: ["src/diced_main.rs"],
rustlibs: [
+ "android.hardware.security.dice-V1-rust",
"libandroid_logger",
"libbinder_rs",
"libdiced",
diff --git a/diced/src/diced_main.rs b/diced/src/diced_main.rs
index c6a5b68..c2cf02c 100644
--- a/diced/src/diced_main.rs
+++ b/diced/src/diced_main.rs
@@ -14,13 +14,15 @@
//! Main entry point for diced, the friendly neighborhood DICE service.
-use diced::{DiceMaintenance, DiceNode, ResidentNode};
+use binder::get_interface;
+use diced::{DiceMaintenance, DiceNode, DiceNodeImpl, ProxyNodeHal, ResidentNode};
use std::convert::TryInto;
use std::panic;
use std::sync::Arc;
static DICE_NODE_SERVICE_NAME: &str = "android.security.dice.IDiceNode";
static DICE_MAINTENANCE_SERVICE_NAME: &str = "android.security.dice.IDiceMaintenance";
+static DICE_HAL_SERVICE_NAME: &str = "android.hardware.security.dice.IDiceDevice/default";
fn main() {
android_logger::init_once(
@@ -34,17 +36,28 @@
// Saying hi.
log::info!("Diced, your friendly neighborhood DICE service, is starting.");
- let (cdi_attest, cdi_seal, bcc) = diced_sample_inputs::make_sample_bcc_and_cdis()
- .expect("Failed to create sample dice artifacts.");
-
- let node_impl = Arc::new(
- ResidentNode::new(
- cdi_attest[..].try_into().expect("Failed to convert cdi_attest into array ref."),
- cdi_seal[..].try_into().expect("Failed to convert cdi_seal into array ref."),
- bcc,
- )
- .expect("Failed to construct a resident node."),
- );
+ let node_impl: Arc<dyn DiceNodeImpl + Send + Sync> = match get_interface(DICE_HAL_SERVICE_NAME)
+ {
+ Ok(dice_device) => {
+ Arc::new(ProxyNodeHal::new(dice_device).expect("Failed to construct a proxy node."))
+ }
+ Err(e) => {
+ log::warn!("Failed to connect to DICE HAL: {:?}", e);
+ log::warn!("Using sample dice artifacts.");
+ let (cdi_attest, cdi_seal, bcc) = diced_sample_inputs::make_sample_bcc_and_cdis()
+ .expect("Failed to create sample dice artifacts.");
+ Arc::new(
+ ResidentNode::new(
+ cdi_attest[..]
+ .try_into()
+ .expect("Failed to convert cdi_attest into array ref."),
+ cdi_seal[..].try_into().expect("Failed to convert cdi_seal into array ref."),
+ bcc,
+ )
+ .expect("Failed to construct a resident node."),
+ )
+ }
+ };
let node = DiceNode::new_as_binder(node_impl.clone())
.expect("Failed to create IDiceNode service instance.");
diff --git a/diced/src/lib.rs b/diced/src/lib.rs
index 9ebee28..8562406 100644
--- a/diced/src/lib.rs
+++ b/diced/src/lib.rs
@@ -16,8 +16,10 @@
mod error;
mod permission;
+mod proxy_node_hal;
mod resident_node;
+pub use crate::proxy_node_hal::ProxyNodeHal;
pub use crate::resident_node::ResidentNode;
use android_hardware_security_dice::aidl::android::hardware::security::dice::{
Bcc::Bcc, BccHandover::BccHandover, Config::Config as BinderConfig,
diff --git a/diced/src/proxy_node_hal.rs b/diced/src/proxy_node_hal.rs
new file mode 100644
index 0000000..3f31419
--- /dev/null
+++ b/diced/src/proxy_node_hal.rs
@@ -0,0 +1,119 @@
+// 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.
+
+//! A proxy dice node delegates all accesses to CDI_attest and CDI_seal to a parent
+//! node, here an implementation of android.hardware.security.dice.IDiceDevice.
+
+#![allow(dead_code)]
+
+use crate::DiceNodeImpl;
+use android_hardware_security_dice::aidl::android::hardware::security::dice::{
+ Bcc::Bcc, BccHandover::BccHandover, IDiceDevice::IDiceDevice,
+ InputValues::InputValues as BinderInputValues, Signature::Signature,
+};
+use anyhow::{Context, Result};
+use binder::public_api::Strong;
+use std::collections::HashMap;
+use std::sync::RwLock;
+
+/// The ProxyNodeHal implements a IDiceNode backend delegating crypto operations
+/// to the corresponding HAL.
+pub struct ProxyNodeHal {
+ parent: Strong<dyn IDiceDevice>,
+ demotion_db: RwLock<HashMap<BinderInputValues, Vec<BinderInputValues>>>,
+}
+
+impl ProxyNodeHal {
+ /// Creates a new proxy node with a reference to the parent service.
+ pub fn new(parent: Strong<dyn IDiceDevice>) -> Result<Self> {
+ Ok(ProxyNodeHal { parent, demotion_db: Default::default() })
+ }
+
+ fn get_effective_input_values(
+ &self,
+ client: BinderInputValues,
+ input_values: &[BinderInputValues],
+ ) -> Vec<BinderInputValues> {
+ let demotion_db = self.demotion_db.read().unwrap();
+
+ let client_arr = [client];
+
+ demotion_db
+ .get(&client_arr[0])
+ .map(|v| v.iter())
+ .unwrap_or_else(|| client_arr.iter())
+ .chain(input_values.iter())
+ .cloned()
+ .collect()
+ }
+}
+
+impl DiceNodeImpl for ProxyNodeHal {
+ fn sign(
+ &self,
+ client: BinderInputValues,
+ input_values: &[BinderInputValues],
+ message: &[u8],
+ ) -> Result<Signature> {
+ self.parent
+ .sign(&self.get_effective_input_values(client, input_values), message)
+ .context("In ProxyNodeHal::sign:")
+ }
+
+ fn get_attestation_chain(
+ &self,
+ client: BinderInputValues,
+ input_values: &[BinderInputValues],
+ ) -> Result<Bcc> {
+ self.parent
+ .getAttestationChain(&self.get_effective_input_values(client, input_values))
+ .context("In ProxyNodeHal::get_attestation_chain:")
+ }
+
+ fn derive(
+ &self,
+ client: BinderInputValues,
+ input_values: &[BinderInputValues],
+ ) -> Result<BccHandover> {
+ self.parent
+ .derive(&self.get_effective_input_values(client, input_values))
+ .context("In ProxyNodeHal::derive:")
+ }
+
+ fn demote(&self, client: BinderInputValues, input_values: &[BinderInputValues]) -> Result<()> {
+ let mut demotion_db = self.demotion_db.write().unwrap();
+
+ let client_arr = [client];
+
+ // The following statement consults demotion database which yields an optional demotion
+ // path. It then constructs an iterator over the following elements, then clones and
+ // collects them into a new vector:
+ // [ demotion path | client ], input_values
+ let new_path: Vec<BinderInputValues> = demotion_db
+ .get(&client_arr[0])
+ .map(|v| v.iter())
+ .unwrap_or_else(|| client_arr.iter())
+ .chain(input_values)
+ .cloned()
+ .collect();
+
+ let [client] = client_arr;
+ demotion_db.insert(client, new_path);
+ Ok(())
+ }
+
+ fn demote_self(&self, input_values: &[BinderInputValues]) -> Result<()> {
+ self.parent.demote(input_values).context("In ProxyNodeHal::demote_self:")
+ }
+}