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

Bug: 198197213
Test: diced_test
Change-Id: I7075c2e7ac8e48a13f4eb177f2e989ff1e6695a2
diff --git a/diced/Android.bp b/diced/Android.bp
new file mode 100644
index 0000000..8de046f
--- /dev/null
+++ b/diced/Android.bp
@@ -0,0 +1,136 @@
+// 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.
+
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "system_security_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["system_security_license"],
+}
+
+rust_library {
+    name: "libdiced_utils",
+    crate_name: "diced_utils",
+    srcs: ["src/utils.rs"],
+
+    rustlibs: [
+        "android.hardware.security.dice-V1-rust",
+        "libanyhow",
+        "libdiced_open_dice_cbor",
+        "libkeystore2_crypto_rust",
+    ],
+}
+
+rust_test {
+    name: "diced_utils_test",
+    crate_name: "diced_utils_test",
+    srcs: ["src/utils.rs"],
+    test_suites: ["general-tests"],
+    auto_gen_config: true,
+    rustlibs: [
+        "android.hardware.security.dice-V1-rust",
+        "libanyhow",
+        "libdiced_open_dice_cbor",
+        "libkeystore2_crypto_rust",
+    ],
+}
+
+rust_library {
+    name: "libdiced_sample_inputs",
+    crate_name: "diced_sample_inputs",
+    srcs: ["src/sample_inputs.rs"],
+
+    rustlibs: [
+        "android.hardware.security.dice-V1-rust",
+        "libanyhow",
+        "libdiced_open_dice_cbor",
+        "libdiced_utils",
+        "libkeystore2_crypto_rust",
+    ],
+}
+
+rust_test {
+    name: "diced_sample_inputs_test",
+    crate_name: "diced_sample_inputs_test",
+    srcs: ["src/sample_inputs.rs"],
+    test_suites: ["general-tests"],
+    auto_gen_config: true,
+    rustlibs: [
+        "android.hardware.security.dice-V1-rust",
+        "libanyhow",
+        "libdiced_open_dice_cbor",
+        "libdiced_utils",
+        "libkeystore2_crypto_rust",
+    ],
+}
+
+rust_library {
+    name: "libdiced",
+    crate_name: "diced",
+    srcs: ["src/lib.rs"],
+
+    rustlibs: [
+        "android.hardware.security.dice-V1-rust",
+        "android.security.dice-rust",
+        "libdiced_open_dice_cbor",
+        "libanyhow",
+        "libbinder_rs",
+        "libdiced_utils",
+        "libkeystore2_crypto_rust",
+        "libkeystore2_selinux",
+        "libkeystore2_vintf_rust",
+        "liblibc",
+        "liblog_event_list",
+        "liblog_rust",
+        "libthiserror",
+    ],
+}
+
+rust_binary {
+    name: "diced",
+    srcs: ["src/diced_main.rs"],
+    rustlibs: [
+        "libandroid_logger",
+        "libbinder_rs",
+        "libdiced",
+        "libdiced_open_dice_cbor",
+        "libdiced_utils",
+        "liblog_rust",
+    ],
+    init_rc: ["diced.rc"],
+}
+
+rust_test {
+    name: "diced_test",
+    crate_name: "diced_test",
+    srcs: ["src/lib.rs"],
+    test_suites: ["general-tests"],
+    auto_gen_config: true,
+    rustlibs: [
+        "android.hardware.security.dice-V1-rust",
+        "android.security.dice-rust",
+        "libanyhow",
+        "libbinder_rs",
+        "libdiced_open_dice_cbor",
+        "libdiced_utils",
+        "libkeystore2_crypto_rust",
+        "libkeystore2_selinux",
+        "libkeystore2_vintf_rust",
+        "liblibc",
+        "liblog_rust",
+        "libthiserror",
+    ],
+}
diff --git a/diced/diced.rc b/diced/diced.rc
new file mode 100644
index 0000000..8c43fa5
--- /dev/null
+++ b/diced/diced.rc
@@ -0,0 +1,13 @@
+# Start the Diced service.
+#
+# See system/core/init/README.md for information on the init.rc language.
+
+service diced /system/bin/diced
+    class main
+    user diced
+    group diced
+    # The diced service must not be allowed to restart.
+    # If it crashes for any reason security critical state is lost.
+    # The only remedy is to restart the device.
+    oneshot
+    writepid /dev/cpuset/foreground/tasks
diff --git a/diced/src/diced_main.rs b/diced/src/diced_main.rs
new file mode 100644
index 0000000..bc6e762
--- /dev/null
+++ b/diced/src/diced_main.rs
@@ -0,0 +1,50 @@
+// 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 diced, the friendly neighborhood DICE service.
+
+use diced::dice::CDI_SIZE;
+use diced::DiceNode;
+use diced::ResidentNode;
+use std::panic;
+use std::sync::Arc;
+
+static DICE_SERVICE_NAME: &str = "android.security.dice";
+
+fn main() {
+    android_logger::init_once(
+        android_logger::Config::default().with_tag("diced").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!("Diced, your friendly neighborhood DICE service, is starting.");
+
+    let node_impl = Arc::new(
+        ResidentNode::new(&[0u8; CDI_SIZE], &[1u8; CDI_SIZE], vec![])
+            .expect("Failed to construct a resident node."),
+    );
+
+    let node =
+        DiceNode::new_as_binder(node_impl).expect("Failed to create IDiceNode service instance.");
+
+    binder::add_service(DICE_SERVICE_NAME, node.as_binder())
+        .expect("Failed to register IDiceNode Service");
+
+    log::info!("Joining thread pool now.");
+    binder::ProcessState::join_thread_pool();
+}
diff --git a/diced/src/error.rs b/diced/src/error.rs
new file mode 100644
index 0000000..92aa97c
--- /dev/null
+++ b/diced/src/error.rs
@@ -0,0 +1,125 @@
+// 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_security_dice::aidl::android::security::dice::ResponseCode::ResponseCode;
+use anyhow::Result;
+use binder::{
+    public_api::Result as BinderResult, ExceptionCode, Status as BinderStatus, StatusCode,
+};
+use keystore2_selinux as selinux;
+use std::ffi::CString;
+
+/// This is the main Diced error type. It wraps the Diced `ResponseCode` generated
+/// from AIDL in the `Rc` variant and Binder and BinderTransaction errors in the respective
+/// variants.
+#[allow(dead_code)] // Binder error forwarding will be needed when proxy nodes are implemented.
+#[derive(Debug, thiserror::Error, Eq, PartialEq, Clone)]
+pub enum Error {
+    /// Wraps a dice `ResponseCode` as defined by the android.security.dice AIDL interface
+    /// specification.
+    #[error("Error::Rc({0:?})")]
+    Rc(ResponseCode),
+    /// Wraps a Binder exception code other than a service specific exception.
+    #[error("Binder exception code {0:?}, {1:?}")]
+    Binder(ExceptionCode, i32),
+    /// Wraps a Binder status code.
+    #[error("Binder transaction error {0:?}")]
+    BinderTransaction(StatusCode),
+}
+
+/// This function should be used by dice service calls to translate error conditions
+/// into service specific exceptions.
+///
+/// All error conditions get logged by this function.
+///
+/// All `Error::Rc(x)` variants get mapped onto a service specific error code of x.
+/// `selinux::Error::PermissionDenied` is mapped on `ResponseCode::PERMISSION_DENIED`.
+///
+/// All non `Error` error conditions and the Error::Binder variant get mapped onto
+/// ResponseCode::SYSTEM_ERROR`.
+///
+/// `handle_ok` will be called if `result` is `Ok(value)` where `value` will be passed
+/// as argument to `handle_ok`. `handle_ok` must generate a `BinderResult<T>`, but it
+/// typically returns Ok(value).
+///
+/// # Examples
+///
+/// ```
+/// fn do_something() -> anyhow::Result<Vec<u8>> {
+///     Err(anyhow!(Error::Rc(ResponseCode::NOT_IMPLEMENTED)))
+/// }
+///
+/// map_or_log_err(do_something(), Ok)
+/// ```
+pub fn map_or_log_err<T, U, F>(result: Result<U>, handle_ok: F) -> BinderResult<T>
+where
+    F: FnOnce(U) -> BinderResult<T>,
+{
+    map_err_with(
+        result,
+        |e| {
+            log::error!("{:?}", e);
+            e
+        },
+        handle_ok,
+    )
+}
+
+/// This function behaves similar to map_or_log_error, but it does not log the errors, instead
+/// it calls map_err on the error before mapping it to a binder result allowing callers to
+/// log or transform the error before mapping it.
+fn map_err_with<T, U, F1, F2>(result: Result<U>, map_err: F1, handle_ok: F2) -> BinderResult<T>
+where
+    F1: FnOnce(anyhow::Error) -> anyhow::Error,
+    F2: FnOnce(U) -> BinderResult<T>,
+{
+    result.map_or_else(
+        |e| {
+            let e = map_err(e);
+            let msg = match CString::new(format!("{:?}", e)) {
+                Ok(msg) => Some(msg),
+                Err(_) => {
+                    log::warn!(
+                        "Cannot convert error message to CStr. It contained a nul byte.
+                         Omitting message from service specific error."
+                    );
+                    None
+                }
+            };
+            let rc = get_error_code(&e);
+            Err(BinderStatus::new_service_specific_error(rc, msg.as_deref()))
+        },
+        handle_ok,
+    )
+}
+
+/// Extracts the error code from an `anyhow::Error` mapping any error that does not have a
+/// root cause of `Error::Rc` onto `ResponseCode::SYSTEM_ERROR` and to `e` with `Error::Rc(e)`
+/// otherwise.
+fn get_error_code(e: &anyhow::Error) -> i32 {
+    let root_cause = e.root_cause();
+    match root_cause.downcast_ref::<Error>() {
+        Some(Error::Rc(rcode)) => rcode.0,
+        // If an Error::Binder reaches this stage we report a system error.
+        // The exception code and possible service specific error will be
+        // printed in the error log above.
+        Some(Error::Binder(_, _)) | Some(Error::BinderTransaction(_)) => {
+            ResponseCode::SYSTEM_ERROR.0
+        }
+        None => match root_cause.downcast_ref::<selinux::Error>() {
+            Some(selinux::Error::PermissionDenied) => ResponseCode::PERMISSION_DENIED.0,
+            _ => ResponseCode::SYSTEM_ERROR.0,
+        },
+    }
+}
diff --git a/diced/src/lib.rs b/diced/src/lib.rs
new file mode 100644
index 0000000..ac9484a
--- /dev/null
+++ b/diced/src/lib.rs
@@ -0,0 +1,140 @@
+// 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.
+
+//! Implement the android.security.dice.IDiceNode service.
+
+mod error;
+mod resident_node;
+
+pub use crate::resident_node::ResidentNode;
+use android_hardware_security_dice::aidl::android::hardware::security::dice::{
+    Bcc::Bcc, BccHandover::BccHandover, Config::Config as BinderConfig,
+    InputValues::InputValues as BinderInputValues, Mode::Mode, Signature::Signature,
+};
+use android_security_dice::aidl::android::security::dice::{
+    IDiceNode::BnDiceNode, IDiceNode::IDiceNode, ResponseCode::ResponseCode,
+};
+use anyhow::{Context, Result};
+use binder::{public_api::Result as BinderResult, BinderFeatures, Strong, ThreadState};
+pub use diced_open_dice_cbor as dice;
+use error::{map_or_log_err, Error};
+use libc::uid_t;
+use std::sync::Arc;
+
+/// A DiceNode backend implementation.
+/// All functions except demote_self derive effective dice artifacts staring from
+/// this node and iterating through `{ [client | demotion path], input_values }`
+/// in ascending order.
+pub trait DiceNodeImpl {
+    /// Signs the message using the effective dice artifacts and Ed25519Pure.
+    fn sign(
+        &self,
+        client: BinderInputValues,
+        input_values: &[BinderInputValues],
+        message: &[u8],
+    ) -> Result<Signature>;
+    /// Returns the effective attestation chain.
+    fn get_attestation_chain(
+        &self,
+        client: BinderInputValues,
+        input_values: &[BinderInputValues],
+    ) -> Result<Bcc>;
+    /// Returns the effective dice artifacts.
+    fn derive(
+        &self,
+        client: BinderInputValues,
+        input_values: &[BinderInputValues],
+    ) -> Result<BccHandover>;
+    /// Adds [ `client` | `input_values` ] to the demotion path of the given client.
+    /// This changes the effective dice artifacts for all subsequent API calls of the
+    /// given client.
+    fn demote(&self, client: BinderInputValues, input_values: &[BinderInputValues]) -> Result<()>;
+    /// This demotes the implementation itself. I.e. a resident node would replace its resident
+    /// with the effective artifacts derived using `input_values`. A proxy node would
+    /// simply call `demote` on its parent node. This is not reversible and changes
+    /// the effective dice artifacts of all clients.
+    fn demote_self(&self, input_values: &[BinderInputValues]) -> Result<()>;
+}
+
+/// Wraps a DiceNodeImpl and implements the actual IDiceNode AIDL API.
+pub struct DiceNode {
+    node_impl: Arc<dyn DiceNodeImpl + Sync + Send>,
+}
+
+fn client_input_values(uid: uid_t) -> Result<BinderInputValues> {
+    Ok(BinderInputValues {
+        codeHash: vec![0; dice::HASH_SIZE],
+        config: BinderConfig {
+            desc: dice::bcc::format_config_descriptor(Some(&format!("{}", uid)), None, true)
+                .context("In client_input_values: failed to format config descriptor")?,
+        },
+        authorityHash: vec![0; dice::HASH_SIZE],
+        authorityDescriptor: None,
+        hidden: vec![0; dice::HIDDEN_SIZE],
+        mode: Mode::NORMAL,
+    })
+}
+
+impl DiceNode {
+    /// Constructs an instance of DiceNode, wraps it with a BnDiceNode object and
+    /// returns a strong pointer to the binder. The result can be used to register
+    /// the service with service manager.
+    pub fn new_as_binder(
+        node_impl: Arc<dyn DiceNodeImpl + Sync + Send>,
+    ) -> Result<Strong<dyn IDiceNode>> {
+        let result = BnDiceNode::new_binder(
+            DiceNode { node_impl },
+            BinderFeatures { set_requesting_sid: true, ..BinderFeatures::default() },
+        );
+        Ok(result)
+    }
+
+    fn sign(&self, input_values: &[BinderInputValues], message: &[u8]) -> Result<Signature> {
+        let client =
+            client_input_values(ThreadState::get_calling_uid()).context("In DiceNode::sign:")?;
+        self.node_impl.sign(client, input_values, message)
+    }
+    fn get_attestation_chain(&self, input_values: &[BinderInputValues]) -> Result<Bcc> {
+        let client = client_input_values(ThreadState::get_calling_uid())
+            .context("In DiceNode::get_attestation_chain:")?;
+        self.node_impl.get_attestation_chain(client, input_values)
+    }
+    fn derive(&self, input_values: &[BinderInputValues]) -> Result<BccHandover> {
+        let client =
+            client_input_values(ThreadState::get_calling_uid()).context("In DiceNode::extend:")?;
+        self.node_impl.derive(client, input_values)
+    }
+    fn demote(&self, input_values: &[BinderInputValues]) -> Result<()> {
+        let client =
+            client_input_values(ThreadState::get_calling_uid()).context("In DiceNode::demote:")?;
+        self.node_impl.demote(client, input_values)
+    }
+}
+
+impl binder::Interface for DiceNode {}
+
+impl IDiceNode for DiceNode {
+    fn sign(&self, input_values: &[BinderInputValues], message: &[u8]) -> BinderResult<Signature> {
+        map_or_log_err(self.sign(input_values, message), Ok)
+    }
+    fn getAttestationChain(&self, input_values: &[BinderInputValues]) -> BinderResult<Bcc> {
+        map_or_log_err(self.get_attestation_chain(input_values), Ok)
+    }
+    fn derive(&self, input_values: &[BinderInputValues]) -> BinderResult<BccHandover> {
+        map_or_log_err(self.derive(input_values), Ok)
+    }
+    fn demote(&self, input_values: &[BinderInputValues]) -> BinderResult<()> {
+        map_or_log_err(self.demote(input_values), Ok)
+    }
+}
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(())
+    }
+}
diff --git a/diced/src/sample_inputs.rs b/diced/src/sample_inputs.rs
new file mode 100644
index 0000000..f76ebc9
--- /dev/null
+++ b/diced/src/sample_inputs.rs
@@ -0,0 +1,255 @@
+// 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.
+
+//! This module provides a set of sample input values for a DICE chain, a sample UDS,
+//! as well as tuple of CDIs and BCC derived thereof.
+
+use android_hardware_security_dice::aidl::android::hardware::security::dice::{
+    Config::Config as BinderConfig, InputValues::InputValues as BinderInputValues, Mode::Mode,
+};
+use anyhow::{Context, Result};
+use dice::ContextImpl;
+use diced_open_dice_cbor as dice;
+use diced_utils::cbor;
+use diced_utils::InputValues;
+use keystore2_crypto::ZVec;
+use std::convert::{TryFrom, TryInto};
+use std::io::Write;
+
+/// Sample UDS used to perform the root dice flow by `make_sample_bcc_and_cdis`.
+pub static UDS: &[u8; dice::CDI_SIZE] = &[
+    0x65, 0x4f, 0xab, 0xa9, 0xa5, 0xad, 0x0f, 0x5e, 0x15, 0xc3, 0x12, 0xf7, 0x77, 0x45, 0xfa, 0x55,
+    0x18, 0x6a, 0xa6, 0x34, 0xb6, 0x7c, 0x82, 0x7b, 0x89, 0x4c, 0xc5, 0x52, 0xd3, 0x27, 0x35, 0x8e,
+];
+
+fn encode_pub_key_ed25519(pub_key: &[u8], stream: &mut dyn Write) -> Result<()> {
+    cbor::encode_header(5 /* CBOR MAP */, 5, stream)
+        .context("In encode_pub_key_ed25519: Trying to encode map header.")?;
+    cbor::encode_number(1, stream)
+        .context("In encode_pub_key_ed25519: Trying to encode Key type tag.")?;
+    cbor::encode_number(1, stream)
+        .context("In encode_pub_key_ed25519: Trying to encode Key type.")?;
+    cbor::encode_number(3, stream)
+        .context("In encode_pub_key_ed25519: Trying to encode algorithm tag.")?;
+    // Encoding a -8 for AlgorithmEdDSA. The encoded number is -1 - <header argument>,
+    // the an argument of 7 below.
+    cbor::encode_header(1 /* CBOR NEGATIVE INT */, 7 /* -1 -7 = -8*/, stream)
+        .context("In encode_pub_key_ed25519: Trying to encode algorithm.")?;
+    cbor::encode_number(4, stream)
+        .context("In encode_pub_key_ed25519: Trying to encode ops tag.")?;
+    // Ops 2 for verify.
+    cbor::encode_number(2, stream).context("In encode_pub_key_ed25519: Trying to encode ops.")?;
+    cbor::encode_header(1 /* CBOR NEGATIVE INT */, 0 /* -1 -0 = -1*/, stream)
+        .context("In encode_pub_key_ed25519: Trying to encode curve tag.")?;
+    // Curve 6 for Ed25519
+    cbor::encode_number(6, stream).context("In encode_pub_key_ed25519: Trying to encode curve.")?;
+    cbor::encode_header(1 /* CBOR NEGATIVE INT */, 1 /* -1 -1 = -2*/, stream)
+        .context("In encode_pub_key_ed25519: Trying to encode X coordinate tag.")?;
+    cbor::encode_bstr(pub_key, stream)
+        .context("In encode_pub_key_ed25519: Trying to encode X coordinate.")?;
+    Ok(())
+}
+
+/// Derives a tuple of (CDI_ATTEST, CDI_SEAL, BCC) derived of the vector of input values returned
+/// by `get_input_values_vector`.
+pub fn make_sample_bcc_and_cdis() -> Result<(ZVec, ZVec, Vec<u8>)> {
+    let mut dice_ctx = dice::OpenDiceCborContext::new();
+    let private_key_seed = dice_ctx
+        .derive_cdi_private_key_seed(UDS)
+        .context("In make_sample_bcc_and_cdis: Trying to derive private key seed.")?;
+
+    let (public_key, _) =
+        dice_ctx
+            .keypair_from_seed(&private_key_seed[..].try_into().context(
+                "In make_sample_bcc_and_cids: Failed to convert seed to array reference.",
+            )?)
+            .context("In make_sample_bcc_and_cids: Failed to generate key pair.")?;
+
+    let input_values_vector = get_input_values_vector();
+
+    let (cdi_attest, cdi_seal, mut cert) = dice_ctx
+        .main_flow(
+            UDS,
+            UDS,
+            &InputValues::try_from(&input_values_vector[0])
+                .context("In make_sample_bcc_and_cdis: Trying to convert input values. (0)")?,
+        )
+        .context("In make_sample_bcc_and_cdis: Trying to run first main flow.")?;
+
+    let mut bcc: Vec<u8> = vec![];
+
+    cbor::encode_header(4 /* CBOR ARRAY */, 2, &mut bcc)
+        .context("In make_sample_bcc_and_cdis: Trying to encode array header.")?;
+    encode_pub_key_ed25519(&public_key, &mut bcc)
+        .context("In make_sample_bcc_and_cdis: Trying encode pub_key.")?;
+
+    bcc.append(&mut cert);
+
+    let (cdi_attest, cdi_seal, bcc) = dice_ctx
+        .bcc_main_flow(
+            &cdi_attest[..].try_into().context(
+                "In make_sample_bcc_and_cdis: Failed to convert cdi_attest to array reference. (1)",
+            )?,
+            &cdi_seal[..].try_into().context(
+                "In make_sample_bcc_and_cdis: Failed to convert cdi_seal to array reference. (1)",
+            )?,
+            &bcc,
+            &InputValues::try_from(&input_values_vector[1])
+                .context("In make_sample_bcc_and_cdis: Trying to convert input values. (1)")?,
+        )
+        .context("In make_sample_bcc_and_cdis: Trying to run first bcc main flow.")?;
+    dice_ctx
+        .bcc_main_flow(
+            &cdi_attest[..].try_into().context(
+                "In make_sample_bcc_and_cdis: Failed to convert cdi_attest to array reference. (2)",
+            )?,
+            &cdi_seal[..].try_into().context(
+                "In make_sample_bcc_and_cdis: Failed to convert cdi_seal to array reference. (2)",
+            )?,
+            &bcc,
+            &InputValues::try_from(&input_values_vector[2])
+                .context("In make_sample_bcc_and_cdis: Trying to convert input values. (2)")?,
+        )
+        .context("In make_sample_bcc_and_cdis: Trying to run second bcc main flow.")
+}
+
+fn make_input_values(
+    code_hash: &[u8; dice::HASH_SIZE],
+    authority_hash: &[u8; dice::HASH_SIZE],
+    config_name: &str,
+    config_version: u64,
+    config_resettable: bool,
+    mode: Mode,
+    hidden: &[u8; dice::HIDDEN_SIZE],
+) -> Result<BinderInputValues> {
+    Ok(BinderInputValues {
+        codeHash: code_hash.to_vec(),
+        config: BinderConfig {
+            desc: dice::bcc::format_config_descriptor(
+                Some(config_name),
+                Some(config_version),
+                config_resettable,
+            )
+            .context("In make_input_values: Failed to format config descriptor.")?,
+        },
+        authorityHash: authority_hash.to_vec(),
+        authorityDescriptor: None,
+        hidden: hidden.to_vec(),
+        mode,
+    })
+}
+
+/// Returns a set of sample input for a dice chain comprising the android boot loader ABL,
+/// the verified boot information AVB, and Android S.
+pub fn get_input_values_vector() -> Vec<BinderInputValues> {
+    vec![
+        make_input_values(
+            &[
+                // code hash
+                0x16, 0x48, 0xf2, 0x55, 0x53, 0x23, 0xdd, 0x15, 0x2e, 0x83, 0x38, 0xc3, 0x64, 0x38,
+                0x63, 0x26, 0x0f, 0xcf, 0x5b, 0xd1, 0x3a, 0xd3, 0x40, 0x3e, 0x23, 0xf8, 0x34, 0x4c,
+                0x6d, 0xa2, 0xbe, 0x25, 0x1c, 0xb0, 0x29, 0xe8, 0xc3, 0xfb, 0xb8, 0x80, 0xdc, 0xb1,
+                0xd2, 0xb3, 0x91, 0x4d, 0xd3, 0xfb, 0x01, 0x0f, 0xe4, 0xe9, 0x46, 0xa2, 0xc0, 0x26,
+                0x57, 0x5a, 0xba, 0x30, 0xf7, 0x15, 0x98, 0x14,
+            ],
+            &[
+                // authority hash
+                0xf9, 0x00, 0x9d, 0xc2, 0x59, 0x09, 0xe0, 0xb6, 0x98, 0xbd, 0xe3, 0x97, 0x4a, 0xcb,
+                0x3c, 0xe7, 0x6b, 0x24, 0xc3, 0xe4, 0x98, 0xdd, 0xa9, 0x6a, 0x41, 0x59, 0x15, 0xb1,
+                0x23, 0xe6, 0xc8, 0xdf, 0xfb, 0x52, 0xb4, 0x52, 0xc1, 0xb9, 0x61, 0xdd, 0xbc, 0x5b,
+                0x37, 0x0e, 0x12, 0x12, 0xb2, 0xfd, 0xc1, 0x09, 0xb0, 0xcf, 0x33, 0x81, 0x4c, 0xc6,
+                0x29, 0x1b, 0x99, 0xea, 0xae, 0xfd, 0xaa, 0x0d,
+            ],
+            "ABL", // config name
+            1,     // config version
+            true,  // resettable
+            Mode::NORMAL,
+            &[
+                // hidden
+                0xa2, 0x01, 0xd0, 0xc0, 0xaa, 0x75, 0x3c, 0x06, 0x43, 0x98, 0x6c, 0xc3, 0x5a, 0xb5,
+                0x5f, 0x1f, 0x0f, 0x92, 0x44, 0x3b, 0x0e, 0xd4, 0x29, 0x75, 0xe3, 0xdb, 0x36, 0xda,
+                0xc8, 0x07, 0x97, 0x4d, 0xff, 0xbc, 0x6a, 0xa4, 0x8a, 0xef, 0xc4, 0x7f, 0xf8, 0x61,
+                0x7d, 0x51, 0x4d, 0x2f, 0xdf, 0x7e, 0x8c, 0x3d, 0xa3, 0xfc, 0x63, 0xd4, 0xd4, 0x74,
+                0x8a, 0xc4, 0x14, 0x45, 0x83, 0x6b, 0x12, 0x7e,
+            ],
+        )
+        .unwrap(),
+        make_input_values(
+            &[
+                // code hash
+                0xa4, 0x0c, 0xcb, 0xc1, 0xbf, 0xfa, 0xcc, 0xfd, 0xeb, 0xf4, 0xfc, 0x43, 0x83, 0x7f,
+                0x46, 0x8d, 0xd8, 0xd8, 0x14, 0xc1, 0x96, 0x14, 0x1f, 0x6e, 0xb3, 0xa0, 0xd9, 0x56,
+                0xb3, 0xbf, 0x2f, 0xfa, 0x88, 0x70, 0x11, 0x07, 0x39, 0xa4, 0xd2, 0xa9, 0x6b, 0x18,
+                0x28, 0xe8, 0x29, 0x20, 0x49, 0x0f, 0xbb, 0x8d, 0x08, 0x8c, 0xc6, 0x54, 0xe9, 0x71,
+                0xd2, 0x7e, 0xa4, 0xfe, 0x58, 0x7f, 0xd3, 0xc7,
+            ],
+            &[
+                // authority hash
+                0xb2, 0x69, 0x05, 0x48, 0x56, 0xb5, 0xfa, 0x55, 0x6f, 0xac, 0x56, 0xd9, 0x02, 0x35,
+                0x2b, 0xaa, 0x4c, 0xba, 0x28, 0xdd, 0x82, 0x3a, 0x86, 0xf5, 0xd4, 0xc2, 0xf1, 0xf9,
+                0x35, 0x7d, 0xe4, 0x43, 0x13, 0xbf, 0xfe, 0xd3, 0x36, 0xd8, 0x1c, 0x12, 0x78, 0x5c,
+                0x9c, 0x3e, 0xf6, 0x66, 0xef, 0xab, 0x3d, 0x0f, 0x89, 0xa4, 0x6f, 0xc9, 0x72, 0xee,
+                0x73, 0x43, 0x02, 0x8a, 0xef, 0xbc, 0x05, 0x98,
+            ],
+            "AVB", // config name
+            1,     // config version
+            true,  // resettable
+            Mode::NORMAL,
+            &[
+                // hidden
+                0x5b, 0x3f, 0xc9, 0x6b, 0xe3, 0x95, 0x59, 0x40, 0x5e, 0x64, 0xe5, 0x64, 0x3f, 0xfd,
+                0x21, 0x09, 0x9d, 0xf3, 0xcd, 0xc7, 0xa4, 0x2a, 0xe2, 0x97, 0xdd, 0xe2, 0x4f, 0xb0,
+                0x7d, 0x7e, 0xf5, 0x8e, 0xd6, 0x4d, 0x84, 0x25, 0x54, 0x41, 0x3f, 0x8f, 0x78, 0x64,
+                0x1a, 0x51, 0x27, 0x9d, 0x55, 0x8a, 0xe9, 0x90, 0x35, 0xab, 0x39, 0x80, 0x4b, 0x94,
+                0x40, 0x84, 0xa2, 0xfd, 0x73, 0xeb, 0x35, 0x7a,
+            ],
+        )
+        .unwrap(),
+        make_input_values(
+            &[
+                // code hash
+                0; dice::HASH_SIZE
+            ],
+            &[
+                // authority hash
+                0x04, 0x25, 0x5d, 0x60, 0x5f, 0x5c, 0x45, 0x0d, 0xf2, 0x9a, 0x6e, 0x99, 0x30, 0x03,
+                0xb8, 0xd6, 0xe1, 0x99, 0x71, 0x1b, 0xf8, 0x44, 0xfa, 0xb5, 0x31, 0x79, 0x1c, 0x37,
+                0x68, 0x4e, 0x1d, 0xc0, 0x24, 0x74, 0x68, 0xf8, 0x80, 0x20, 0x3e, 0x44, 0xb1, 0x43,
+                0xd2, 0x9c, 0xfc, 0x12, 0x9e, 0x77, 0x0a, 0xde, 0x29, 0x24, 0xff, 0x2e, 0xfa, 0xc7,
+                0x10, 0xd5, 0x73, 0xd4, 0xc6, 0xdf, 0x62, 0x9f,
+            ],
+            "Android", // config name
+            12,        // config version
+            true,      // resettable
+            Mode::NORMAL,
+            &[
+                // hidden
+                0; dice::HIDDEN_SIZE
+            ],
+        )
+        .unwrap(),
+    ]
+}
+
+#[cfg(test)]
+mod test {
+    use super::*;
+
+    // This simple test checks if the invocation succeeds, essentially it tests
+    // if the initial bcc is accepted by `DiceContext::bcc_main_flow`.
+    #[test]
+    fn make_sample_bcc_and_cdis_test() {
+        make_sample_bcc_and_cdis().unwrap();
+    }
+}
diff --git a/diced/src/utils.rs b/diced/src/utils.rs
new file mode 100644
index 0000000..abb8a7b
--- /dev/null
+++ b/diced/src/utils.rs
@@ -0,0 +1,445 @@
+// 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.
+
+//! Implements utility functions and types for diced and the dice HAL.
+
+use android_hardware_security_dice::aidl::android::hardware::security::dice::{
+    Bcc::Bcc, BccHandover::BccHandover, InputValues::InputValues as BinderInputValues,
+    Mode::Mode as BinderMode,
+};
+use anyhow::{anyhow, Context, Result};
+use dice::ContextImpl;
+use diced_open_dice_cbor as dice;
+use keystore2_crypto::ZVec;
+use std::convert::{TryFrom, TryInto};
+
+/// This new type wraps a reference to BinderInputValues and implements the open dice
+/// InputValues trait.
+#[derive(Debug)]
+pub struct InputValues<'a>(&'a BinderInputValues);
+
+impl<'a> TryFrom<&'a BinderInputValues> for InputValues<'a> {
+    type Error = anyhow::Error;
+
+    fn try_from(input_values: &'a BinderInputValues) -> Result<InputValues<'a>> {
+        if input_values.codeHash.len() != dice::HASH_SIZE {
+            return Err(anyhow!(format!(
+                "In try_from: Code hash has invalid size: {}",
+                input_values.codeHash.len()
+            )));
+        }
+        if input_values.authorityHash.len() != dice::HASH_SIZE {
+            return Err(anyhow!(format!(
+                "In try_from: Authority hash has invalid size: {}",
+                input_values.authorityHash.len()
+            )));
+        }
+        if input_values.hidden.len() != dice::HIDDEN_SIZE {
+            return Err(anyhow!(format!(
+                "In try_from: Hidden has invalid size: {}",
+                input_values.hidden.len()
+            )));
+        }
+
+        Ok(Self(input_values))
+    }
+}
+
+impl From<&InputValues<'_>> for BinderInputValues {
+    fn from(input_values: &InputValues) -> BinderInputValues {
+        input_values.0.clone()
+    }
+}
+impl From<InputValues<'_>> for BinderInputValues {
+    fn from(input_values: InputValues) -> BinderInputValues {
+        input_values.0.clone()
+    }
+}
+
+impl dice::InputValues for InputValues<'_> {
+    fn code_hash(&self) -> &[u8; dice::HASH_SIZE] {
+        // If `self` was created using try_from the length was checked and this cannot panic.
+        self.0.codeHash.as_slice().try_into().unwrap()
+    }
+
+    fn config(&self) -> dice::Config {
+        dice::Config::Descriptor(self.0.config.desc.as_slice())
+    }
+
+    fn authority_hash(&self) -> &[u8; dice::HASH_SIZE] {
+        // If `self` was created using try_from the length was checked and this cannot panic.
+        self.0.authorityHash.as_slice().try_into().unwrap()
+    }
+
+    fn authority_descriptor(&self) -> Option<&[u8]> {
+        self.0.authorityDescriptor.as_deref()
+    }
+
+    fn mode(&self) -> dice::Mode {
+        match self.0.mode {
+            BinderMode::NOT_INITIALIZED => dice::Mode::NotConfigured,
+            BinderMode::NORMAL => dice::Mode::Normal,
+            BinderMode::DEBUG => dice::Mode::Debug,
+            BinderMode::RECOVERY => dice::Mode::Recovery,
+            _ => dice::Mode::NotConfigured,
+        }
+    }
+
+    fn hidden(&self) -> &[u8; dice::HIDDEN_SIZE] {
+        // If `self` was created using try_from the length was checked and this cannot panic.
+        self.0.hidden.as_slice().try_into().unwrap()
+    }
+}
+
+/// Initializes an aidl defined BccHandover object with the arguments `cdi_attest`, `cdi_seal`,
+/// and `bcc`.
+pub fn make_bcc_handover(
+    cdi_attest: &[u8; dice::CDI_SIZE],
+    cdi_seal: &[u8; dice::CDI_SIZE],
+    bcc: &[u8],
+) -> Result<BccHandover> {
+    Ok(BccHandover {
+        cdiAttest: cdi_attest.to_vec(),
+        cdiSeal: cdi_seal.to_vec(),
+        bcc: Bcc { data: bcc.to_vec() },
+    })
+}
+
+/// ResidentArtifacts stores a set of dice artifacts comprising CDI_ATTEST, CDI_SEAL,
+/// and the BCC formatted attestation certificate chain. The sensitive secrets are
+/// stored in zeroing vectors, and it implements functionality to perform DICE
+/// derivation steps using libopen-dice-cbor.
+pub struct ResidentArtifacts {
+    cdi_attest: ZVec,
+    cdi_seal: ZVec,
+    bcc: Vec<u8>,
+}
+
+impl ResidentArtifacts {
+    /// Create a ResidentArtifacts object. The parameters ensure that the stored secrets
+    /// can only have the appropriate size, so that subsequent casts to array references
+    /// cannot fail.
+    pub fn new(
+        cdi_attest: &[u8; dice::CDI_SIZE],
+        cdi_seal: &[u8; dice::CDI_SIZE],
+        bcc: &[u8],
+    ) -> Result<Self> {
+        Ok(ResidentArtifacts {
+            cdi_attest: cdi_attest[..]
+                .try_into()
+                .context("In ResidentArtifacts::new: Trying to convert cdi_attest to ZVec.")?,
+            cdi_seal: cdi_seal[..]
+                .try_into()
+                .context("In ResidentArtifacts::new: Trying to convert cdi_seal to ZVec.")?,
+            bcc: bcc.to_vec(),
+        })
+    }
+
+    /// Attempts to clone the artifacts. This operation is fallible due to the fallible
+    /// nature of ZVec.
+    pub fn try_clone(&self) -> Result<Self> {
+        Ok(ResidentArtifacts {
+            cdi_attest: self
+                .cdi_attest
+                .try_clone()
+                .context("In ResidentArtifacts::new: Trying to clone cdi_attest.")?,
+            cdi_seal: self
+                .cdi_seal
+                .try_clone()
+                .context("In ResidentArtifacts::new: Trying to clone cdi_seal.")?,
+            bcc: self.bcc.clone(),
+        })
+    }
+
+    /// Deconstruct the Artifacts into a tuple.
+    /// (CDI_ATTEST, CDI_SEAL, BCC)
+    pub fn into_tuple(self) -> (ZVec, ZVec, Vec<u8>) {
+        let ResidentArtifacts { cdi_attest, cdi_seal, bcc } = self;
+        (cdi_attest, cdi_seal, bcc)
+    }
+
+    fn execute_step(self, input_values: &dyn dice::InputValues) -> Result<Self> {
+        let ResidentArtifacts { cdi_attest, cdi_seal, bcc } = self;
+
+        let (cdi_attest, cdi_seal, bcc) = dice::OpenDiceCborContext::new()
+            .bcc_main_flow(
+                cdi_attest[..].try_into().with_context(|| {
+                    format!("Trying to convert cdi_attest. (length: {})", cdi_attest.len())
+                })?,
+                cdi_seal[..].try_into().with_context(|| {
+                    format!("Trying to convert cdi_seal. (length: {})", cdi_seal.len())
+                })?,
+                &bcc,
+                input_values,
+            )
+            .context("In ResidentArtifacts::execute_step:")?;
+        Ok(ResidentArtifacts { cdi_attest, cdi_seal, bcc })
+    }
+
+    /// Iterate through the iterator of dice input values performing one
+    /// BCC main flow step on each element.
+    pub fn execute_steps<'a, Iter>(self, input_values: Iter) -> Result<Self>
+    where
+        Iter: IntoIterator<Item = &'a dyn dice::InputValues>,
+    {
+        input_values
+            .into_iter()
+            .try_fold(self, |acc, input_values| acc.execute_step(input_values))
+            .context("In ResidentArtifacts::execute_step:")
+    }
+}
+
+/// This submodule implements a limited set of CBOR generation functionality. Essentially,
+/// a cbor header generator and some convenience functions for number and BSTR encoding.
+pub mod cbor {
+    use anyhow::{anyhow, Context, Result};
+    use std::convert::TryInto;
+    use std::io::Write;
+
+    /// CBOR encodes a positive number.
+    pub fn encode_number(n: u64, buffer: &mut dyn Write) -> Result<()> {
+        encode_header(0, n, buffer)
+    }
+
+    /// CBOR encodes a binary string.
+    pub fn encode_bstr(bstr: &[u8], buffer: &mut dyn Write) -> Result<()> {
+        encode_header(
+            2,
+            bstr.len().try_into().context("In encode_bstr: Failed to convert usize to u64.")?,
+            buffer,
+        )
+        .context("In encode_bstr: While writing header.")?;
+        let written = buffer.write(bstr).context("In encode_bstr: While writing payload.")?;
+        if written != bstr.len() {
+            return Err(anyhow!("In encode_bstr: Buffer too small. ({}, {})", written, bstr.len()));
+        }
+        Ok(())
+    }
+
+    /// Formats a CBOR header. `t` is the type, and n is the header argument.
+    pub fn encode_header(t: u8, n: u64, buffer: &mut dyn Write) -> Result<()> {
+        match n {
+            n if n < 24 => {
+                let written = buffer
+                    .write(&u8::to_be_bytes(((t as u8) << 5) | (n as u8 & 0x1F)))
+                    .with_context(|| {
+                    format!("In encode_header: Failed to write header ({}, {})", t, n)
+                })?;
+                if written != 1 {
+                    return Err(anyhow!("In encode_header: Buffer to small. ({}, {})", t, n));
+                }
+            }
+            n if n <= 0xFF => {
+                let written =
+                    buffer.write(&u8::to_be_bytes(((t as u8) << 5) | (24u8 & 0x1F))).with_context(
+                        || format!("In encode_header: Failed to write header ({}, {})", t, n),
+                    )?;
+                if written != 1 {
+                    return Err(anyhow!("In encode_header: Buffer to small. ({}, {})", t, n));
+                }
+                let written = buffer.write(&u8::to_be_bytes(n as u8)).with_context(|| {
+                    format!("In encode_header: Failed to write size ({}, {})", t, n)
+                })?;
+                if written != 1 {
+                    return Err(anyhow!(
+                        "In encode_header while writing size: Buffer to small. ({}, {})",
+                        t,
+                        n
+                    ));
+                }
+            }
+            n if n <= 0xFFFF => {
+                let written =
+                    buffer.write(&u8::to_be_bytes(((t as u8) << 5) | (25u8 & 0x1F))).with_context(
+                        || format!("In encode_header: Failed to write header ({}, {})", t, n),
+                    )?;
+                if written != 1 {
+                    return Err(anyhow!("In encode_header: Buffer to small. ({}, {})", t, n));
+                }
+                let written = buffer.write(&u16::to_be_bytes(n as u16)).with_context(|| {
+                    format!("In encode_header: Failed to write size ({}, {})", t, n)
+                })?;
+                if written != 2 {
+                    return Err(anyhow!(
+                        "In encode_header while writing size: Buffer to small. ({}, {})",
+                        t,
+                        n
+                    ));
+                }
+            }
+            n if n <= 0xFFFFFFFF => {
+                let written =
+                    buffer.write(&u8::to_be_bytes(((t as u8) << 5) | (26u8 & 0x1F))).with_context(
+                        || format!("In encode_header: Failed to write header ({}, {})", t, n),
+                    )?;
+                if written != 1 {
+                    return Err(anyhow!("In encode_header: Buffer to small. ({}, {})", t, n));
+                }
+                let written = buffer.write(&u32::to_be_bytes(n as u32)).with_context(|| {
+                    format!("In encode_header: Failed to write size ({}, {})", t, n)
+                })?;
+                if written != 4 {
+                    return Err(anyhow!(
+                        "In encode_header while writing size: Buffer to small. ({}, {})",
+                        t,
+                        n
+                    ));
+                }
+            }
+            n => {
+                let written =
+                    buffer.write(&u8::to_be_bytes(((t as u8) << 5) | (27u8 & 0x1F))).with_context(
+                        || format!("In encode_header: Failed to write header ({}, {})", t, n),
+                    )?;
+                if written != 1 {
+                    return Err(anyhow!("In encode_header: Buffer to small. ({}, {})", t, n));
+                }
+                let written = buffer.write(&u64::to_be_bytes(n as u64)).with_context(|| {
+                    format!("In encode_header: Failed to write size ({}, {})", t, n)
+                })?;
+                if written != 8 {
+                    return Err(anyhow!(
+                        "In encode_header while writing size: Buffer to small. ({}, {})",
+                        t,
+                        n
+                    ));
+                }
+            }
+        }
+        Ok(())
+    }
+
+    #[cfg(test)]
+    mod test {
+        use super::*;
+
+        fn encode_header_helper(t: u8, n: u64) -> Vec<u8> {
+            let mut b: Vec<u8> = vec![];
+            encode_header(t, n, &mut b).unwrap();
+            b
+        }
+
+        #[test]
+        fn encode_header_test() {
+            assert_eq!(&encode_header_helper(0, 0), &[0b000_00000]);
+            assert_eq!(&encode_header_helper(0, 23), &[0b000_10111]);
+            assert_eq!(&encode_header_helper(0, 24), &[0b000_11000, 24]);
+            assert_eq!(&encode_header_helper(0, 0xff), &[0b000_11000, 0xff]);
+            assert_eq!(&encode_header_helper(0, 0x100), &[0b000_11001, 0x01, 0x00]);
+            assert_eq!(&encode_header_helper(0, 0xffff), &[0b000_11001, 0xff, 0xff]);
+            assert_eq!(&encode_header_helper(0, 0x10000), &[0b000_11010, 0x00, 0x01, 0x00, 0x00]);
+            assert_eq!(
+                &encode_header_helper(0, 0xffffffff),
+                &[0b000_11010, 0xff, 0xff, 0xff, 0xff]
+            );
+            assert_eq!(
+                &encode_header_helper(0, 0x100000000),
+                &[0b000_11011, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00]
+            );
+            assert_eq!(
+                &encode_header_helper(0, 0xffffffffffffffff),
+                &[0b000_11011, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff]
+            );
+        }
+    }
+}
+
+#[cfg(test)]
+mod test {
+    use super::*;
+    use android_hardware_security_dice::aidl::android::hardware::security::dice::{
+        Config::Config as BinderConfig, InputValues::InputValues as BinderInputValues,
+    };
+    use dice::InputValues as DiceInputValues;
+    use diced_open_dice_cbor as dice;
+
+    static CODE_HASH_TEST_VECTOR: [u8; dice::HASH_SIZE] = [1u8; dice::HASH_SIZE];
+    static CONFIG_DESCRIPTOR_TEST_VECTOR: &[u8] = &[3, 2, 1];
+    static AUTHORITY_HASH_TEST_VECTOR: [u8; dice::HASH_SIZE] = [3u8; dice::HASH_SIZE];
+    static AUTHORITY_DESCRIPTOR_TEST_VECTOR: &[u8] = &[1, 2, 3];
+    static HIDDEN_TEST_VECTOR: [u8; dice::HIDDEN_SIZE] = [4u8; dice::HIDDEN_SIZE];
+
+    #[test]
+    fn try_from_input_values_binder() {
+        let input_values_good = BinderInputValues {
+            codeHash: CODE_HASH_TEST_VECTOR.to_vec(),
+            config: BinderConfig { desc: CONFIG_DESCRIPTOR_TEST_VECTOR.to_vec() },
+            authorityHash: AUTHORITY_HASH_TEST_VECTOR.to_vec(),
+            authorityDescriptor: Some(AUTHORITY_DESCRIPTOR_TEST_VECTOR.to_vec()),
+            mode: BinderMode::NORMAL,
+            hidden: HIDDEN_TEST_VECTOR.to_vec(),
+        };
+
+        let converted_input_values: InputValues =
+            (&input_values_good).try_into().expect("This should succeed.");
+        assert_eq!(*converted_input_values.code_hash(), CODE_HASH_TEST_VECTOR);
+        assert_eq!(
+            converted_input_values.config(),
+            dice::Config::Descriptor(CONFIG_DESCRIPTOR_TEST_VECTOR)
+        );
+        assert_eq!(*converted_input_values.authority_hash(), AUTHORITY_HASH_TEST_VECTOR);
+        assert_eq!(
+            converted_input_values.authority_descriptor(),
+            Some(AUTHORITY_DESCRIPTOR_TEST_VECTOR)
+        );
+        assert_eq!(converted_input_values.mode(), dice::Mode::Normal);
+        assert_eq!(*converted_input_values.hidden(), HIDDEN_TEST_VECTOR);
+
+        // One more time without authority descriptor.
+        let input_values_still_good_without_authority_descriptor =
+            BinderInputValues { authorityDescriptor: None, ..input_values_good.clone() };
+
+        let converted_input_values: InputValues =
+            (&input_values_still_good_without_authority_descriptor)
+                .try_into()
+                .expect("This should succeed.");
+        assert_eq!(*converted_input_values.code_hash(), CODE_HASH_TEST_VECTOR);
+        assert_eq!(
+            converted_input_values.config(),
+            dice::Config::Descriptor(CONFIG_DESCRIPTOR_TEST_VECTOR)
+        );
+        assert_eq!(*converted_input_values.authority_hash(), AUTHORITY_HASH_TEST_VECTOR);
+        assert_eq!(converted_input_values.authority_descriptor(), None);
+        assert_eq!(converted_input_values.mode(), dice::Mode::Normal);
+        assert_eq!(*converted_input_values.hidden(), HIDDEN_TEST_VECTOR);
+
+        // Now check the failure cases.
+        // Wrong sized codeHash.
+        let input_values_bad_code_hash = BinderInputValues {
+            codeHash: vec![1u8; dice::HASH_SIZE + 1],
+            ..input_values_good.clone()
+        };
+
+        InputValues::try_from(&input_values_bad_code_hash)
+            .expect_err("Conversion of input values with wrong sized code hash succeeded.");
+
+        // Wrong sized authority hash.
+        let input_values_bad_authority_hash = BinderInputValues {
+            authorityHash: vec![1u8; dice::HASH_SIZE + 1],
+            ..input_values_good.clone()
+        };
+
+        InputValues::try_from(&input_values_bad_authority_hash)
+            .expect_err("Conversion of input values with wrong sized authority hash succeeded.");
+
+        // Wrong sized hidden.
+        let input_values_bad_hidden = BinderInputValues {
+            authorityHash: vec![1u8; dice::HASH_SIZE + 1],
+            ..input_values_good.clone()
+        };
+
+        InputValues::try_from(&input_values_bad_hidden)
+            .expect_err("Conversion of input values with wrong sized hidden succeeded.");
+    }
+}