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