Diced: Add service diced an implementation of android.security.dice

Bug: 198197213
Test: diced_test
Change-Id: I7075c2e7ac8e48a13f4eb177f2e989ff1e6695a2
diff --git a/diced/src/resident_node.rs b/diced/src/resident_node.rs
new file mode 100644
index 0000000..5fe4dc9
--- /dev/null
+++ b/diced/src/resident_node.rs
@@ -0,0 +1,191 @@
+// 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 resident dice node keeps CDI_attest and CDI_seal memory resident and can serve
+//! its clients directly by performing all crypto operations including derivations and
+//! certificate generation itself.
+
+use crate::DiceNodeImpl;
+use android_hardware_security_dice::aidl::android::hardware::security::dice::{
+    Bcc::Bcc, BccHandover::BccHandover, InputValues::InputValues as BinderInputValues,
+    Signature::Signature,
+};
+use anyhow::{Context, Result};
+use dice::{ContextImpl, OpenDiceCborContext};
+use diced_open_dice_cbor as dice;
+use diced_utils::{self as utils, InputValues, ResidentArtifacts};
+use std::collections::HashMap;
+use std::convert::TryInto;
+use std::sync::RwLock;
+
+/// The ResidentNode implements a IDiceNode backend with memory resident DICE secrets.
+pub struct ResidentNode {
+    artifacts: RwLock<ResidentArtifacts>,
+    demotion_db: RwLock<HashMap<BinderInputValues, Vec<BinderInputValues>>>,
+}
+
+impl ResidentNode {
+    /// Creates a new Resident node with the given dice secrets and certificate chain.
+    pub fn new(
+        cdi_attest: &[u8; dice::CDI_SIZE],
+        cdi_seal: &[u8; dice::CDI_SIZE],
+        bcc: Vec<u8>,
+    ) -> Result<Self> {
+        Ok(ResidentNode {
+            artifacts: RwLock::new(
+                ResidentArtifacts::new(cdi_attest, cdi_seal, &bcc)
+                    .context("In ResidentNode::new: Trying to initialize ResidentArtifacts")?,
+            ),
+            demotion_db: Default::default(),
+        })
+    }
+
+    fn get_effective_artifacts(
+        &self,
+        client: BinderInputValues,
+        input_values: &[BinderInputValues],
+    ) -> Result<ResidentArtifacts> {
+        let artifacts = self.artifacts.read().unwrap().try_clone()?;
+        let demotion_db = self.demotion_db.read().unwrap();
+
+        let client_arr = [client];
+
+        let input_values: Vec<utils::InputValues> = demotion_db
+            .get(&client_arr[0])
+            .map(|v| v.iter())
+            .unwrap_or_else(|| client_arr.iter())
+            .chain(input_values.iter())
+            .map(|v| v.try_into())
+            .collect::<Result<_>>()?;
+
+        artifacts
+            .execute_steps(input_values.iter().map(|v| v as &dyn dice::InputValues))
+            .context("In get_effective_artifacts:")
+    }
+}
+
+impl DiceNodeImpl for ResidentNode {
+    fn sign(
+        &self,
+        client: BinderInputValues,
+        input_values: &[BinderInputValues],
+        message: &[u8],
+    ) -> Result<Signature> {
+        let (cdi_attest, _, _) = self
+            .get_effective_artifacts(client, input_values)
+            .context("In ResidentNode::sign: Failed to get effective_artifacts.")?
+            .into_tuple();
+        let mut dice = OpenDiceCborContext::new();
+        let seed = dice
+            .derive_cdi_private_key_seed(cdi_attest[..].try_into().with_context(|| {
+                format!(
+                    "In ResidentNode::sign: Failed to convert cdi_attest (length: {}).",
+                    cdi_attest.len()
+                )
+            })?)
+            .context("In ResidentNode::sign: Failed to derive seed from cdi_attest.")?;
+        let (_public_key, private_key) = dice
+            .keypair_from_seed(seed[..].try_into().with_context(|| {
+                format!("In ResidentNode::sign: Failed to convert seed (length: {}).", seed.len())
+            })?)
+            .context("In ResidentNode::sign: Failed to derive keypair from seed.")?;
+        Ok(Signature {
+            data: dice
+                .sign(
+                    message,
+                    private_key[..].try_into().with_context(|| {
+                        format!(
+                            "In ResidentNode::sign: Failed to convert private_key (length: {}).",
+                            private_key.len()
+                        )
+                    })?,
+                )
+                .context("In ResidentNode::sign: Failed to sign.")?,
+        })
+    }
+
+    fn get_attestation_chain(
+        &self,
+        client: BinderInputValues,
+        input_values: &[BinderInputValues],
+    ) -> Result<Bcc> {
+        let (_, _, bcc) = self
+            .get_effective_artifacts(client, input_values)
+            .context("In ResidentNode::get_attestation_chain: Failed to get effective_artifacts.")?
+            .into_tuple();
+
+        Ok(Bcc { data: bcc })
+    }
+
+    fn derive(
+        &self,
+        client: BinderInputValues,
+        input_values: &[BinderInputValues],
+    ) -> Result<BccHandover> {
+        let (cdi_attest, cdi_seal, bcc) =
+            self.get_effective_artifacts(client, input_values)?.into_tuple();
+
+        utils::make_bcc_handover(
+            &cdi_attest[..]
+                .try_into()
+                .context("In ResidentNode::derive: Trying to convert cdi_attest to sized array.")?,
+            &cdi_seal[..]
+                .try_into()
+                .context("In ResidentNode::derive: Trying to convert cdi_attest to sized array.")?,
+            &bcc,
+        )
+        .context("In ResidentNode::derive: Trying to format bcc handover.")
+    }
+
+    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<()> {
+        let mut artifacts = self.artifacts.write().unwrap();
+
+        let input_values = input_values
+            .iter()
+            .map(|v| {
+                v.try_into().with_context(|| format!("Failed to convert input values: {:#?}", v))
+            })
+            .collect::<Result<Vec<InputValues>>>()
+            .context("In ResidentNode::demote_self:")?;
+
+        *artifacts = artifacts
+            .try_clone()
+            .context("In ResidentNode::demote_self: Failed to clone resident artifacts")?
+            .execute_steps(input_values.iter().map(|v| v as &dyn dice::InputValues))
+            .context("In ResidentNode::demote_self:")?;
+        Ok(())
+    }
+}