Merge "identity: Add multi-document presentation support."
diff --git a/diced/Android.bp b/diced/Android.bp
new file mode 100644
index 0000000..db0268c
--- /dev/null
+++ b/diced/Android.bp
@@ -0,0 +1,209 @@
+// 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"],
+    vendor_available: true,
+
+    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"],
+    vendor_available: true,
+
+    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",
+        "liblibc",
+        "liblog_rust",
+        "libthiserror",
+    ],
+}
+
+rust_library {
+    name: "libdiced_vendor",
+    crate_name: "diced",
+    srcs: ["src/lib_vendor.rs"],
+
+    vendor_available: true,
+    rustlibs: [
+        "android.hardware.security.dice-V1-rust",
+        "libdiced_open_dice_cbor",
+        "libanyhow",
+        "libbinder_rs",
+        "libdiced_utils",
+        "libkeystore2_crypto_rust",
+        "liblibc",
+        "liblog_rust",
+        "libnix",
+        "libserde",
+        "libserde_cbor",
+        "libthiserror",
+    ],
+}
+
+rust_binary {
+    name: "diced",
+    srcs: ["src/diced_main.rs"],
+    rustlibs: [
+        "android.hardware.security.dice-V1-rust",
+        "libandroid_logger",
+        "libbinder_rs",
+        "libdiced",
+        "libdiced_open_dice_cbor",
+        "libdiced_sample_inputs",
+        "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",
+        "libnix",
+        "libserde",
+        "libserde_cbor",
+        "libthiserror",
+    ],
+}
+
+rust_test {
+    name: "diced_vendor_test",
+    crate_name: "diced_vendor_test",
+    srcs: ["src/lib_vendor.rs"],
+    test_suites: ["general-tests"],
+    auto_gen_config: true,
+    rustlibs: [
+        "android.hardware.security.dice-V1-rust",
+        "libanyhow",
+        "libdiced_open_dice_cbor",
+        "libdiced_sample_inputs",
+        "libdiced_utils",
+        "libbinder_rs",
+        "libkeystore2_crypto_rust",
+        "liblibc",
+        "liblog_rust",
+        "libnix",
+        "libserde",
+        "libserde_cbor",
+        "libthiserror",
+    ],
+}
+
+rust_test {
+    name: "diced_client_test",
+    srcs: [
+        "src/diced_client_test.rs",
+    ],
+    require_root: true,
+    auto_gen_config: true,
+    test_suites: [
+        "general-tests",
+    ],
+
+    rustlibs: [
+        "android.hardware.security.dice-V1-rust",
+        "android.security.dice-rust",
+        "libanyhow",
+        "libbinder_rs",
+        "libdiced_open_dice_cbor",
+        "libdiced_sample_inputs",
+        "libdiced_utils",
+        "libnix",
+    ],
+}
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/open_dice_cbor/Android.bp b/diced/open_dice_cbor/Android.bp
index 0d05ce0..3e67045 100644
--- a/diced/open_dice_cbor/Android.bp
+++ b/diced/open_dice_cbor/Android.bp
@@ -32,4 +32,24 @@
         "libopen_dice_bcc",
         "libopen_dice_cbor",
     ],
+    vendor_available: true,
+}
+
+rust_test {
+    name: "diced_open_dice_cbor_test",
+    crate_name: "diced_open_dice_cbor_test",
+    srcs: ["lib.rs"],
+    test_suites: ["general-tests"],
+    auto_gen_config: true,
+    rustlibs: [
+        "libdiced_sample_inputs",
+        "libkeystore2_crypto_rust",
+        "libopen_dice_bcc_bindgen",
+        "libopen_dice_cbor_bindgen",
+        "libthiserror",
+    ],
+    static_libs: [
+        "libopen_dice_bcc",
+        "libopen_dice_cbor",
+    ],
 }
diff --git a/diced/open_dice_cbor/lib.rs b/diced/open_dice_cbor/lib.rs
index 1b07e61..7122ca5 100644
--- a/diced/open_dice_cbor/lib.rs
+++ b/diced/open_dice_cbor/lib.rs
@@ -790,3 +790,248 @@
         })
     }
 }
+
+#[cfg(test)]
+mod test {
+    use super::*;
+    use diced_sample_inputs::make_sample_bcc_and_cdis;
+    use std::convert::TryInto;
+
+    static SEED_TEST_VECTOR: &[u8] = &[
+        0xfa, 0x3c, 0x2f, 0x58, 0x37, 0xf5, 0x8e, 0x96, 0x16, 0x09, 0xf5, 0x22, 0xa1, 0xf1, 0xba,
+        0xaa, 0x19, 0x95, 0x01, 0x79, 0x2e, 0x60, 0x56, 0xaf, 0xf6, 0x41, 0xe7, 0xff, 0x48, 0xf5,
+        0x3a, 0x08, 0x84, 0x8a, 0x98, 0x85, 0x6d, 0xf5, 0x69, 0x21, 0x03, 0xcd, 0x09, 0xc3, 0x28,
+        0xd6, 0x06, 0xa7, 0x57, 0xbd, 0x48, 0x4b, 0x0f, 0x79, 0x0f, 0xf8, 0x2f, 0xf0, 0x0a, 0x41,
+        0x94, 0xd8, 0x8c, 0xa8,
+    ];
+
+    static CDI_ATTEST_TEST_VECTOR: &[u8] = &[
+        0xfa, 0x3c, 0x2f, 0x58, 0x37, 0xf5, 0x8e, 0x96, 0x16, 0x09, 0xf5, 0x22, 0xa1, 0xf1, 0xba,
+        0xaa, 0x19, 0x95, 0x01, 0x79, 0x2e, 0x60, 0x56, 0xaf, 0xf6, 0x41, 0xe7, 0xff, 0x48, 0xf5,
+        0x3a, 0x08,
+    ];
+    static CDI_PRIVATE_KEY_SEED_TEST_VECTOR: &[u8] = &[
+        0x5f, 0xcc, 0x8e, 0x1a, 0xd1, 0xc2, 0xb3, 0xe9, 0xfb, 0xe1, 0x68, 0xf0, 0xf6, 0x98, 0xfe,
+        0x0d, 0xee, 0xd4, 0xb5, 0x18, 0xcb, 0x59, 0x70, 0x2d, 0xee, 0x06, 0xe5, 0x70, 0xf1, 0x72,
+        0x02, 0x6e,
+    ];
+
+    static PUB_KEY_TEST_VECTOR: &[u8] = &[
+        0x47, 0x42, 0x4b, 0xbd, 0xd7, 0x23, 0xb4, 0xcd, 0xca, 0xe2, 0x8e, 0xdc, 0x6b, 0xfc, 0x23,
+        0xc9, 0x21, 0x5c, 0x48, 0x21, 0x47, 0xee, 0x5b, 0xfa, 0xaf, 0x88, 0x9a, 0x52, 0xf1, 0x61,
+        0x06, 0x37,
+    ];
+    static PRIV_KEY_TEST_VECTOR: &[u8] = &[
+        0x5f, 0xcc, 0x8e, 0x1a, 0xd1, 0xc2, 0xb3, 0xe9, 0xfb, 0xe1, 0x68, 0xf0, 0xf6, 0x98, 0xfe,
+        0x0d, 0xee, 0xd4, 0xb5, 0x18, 0xcb, 0x59, 0x70, 0x2d, 0xee, 0x06, 0xe5, 0x70, 0xf1, 0x72,
+        0x02, 0x6e, 0x47, 0x42, 0x4b, 0xbd, 0xd7, 0x23, 0xb4, 0xcd, 0xca, 0xe2, 0x8e, 0xdc, 0x6b,
+        0xfc, 0x23, 0xc9, 0x21, 0x5c, 0x48, 0x21, 0x47, 0xee, 0x5b, 0xfa, 0xaf, 0x88, 0x9a, 0x52,
+        0xf1, 0x61, 0x06, 0x37,
+    ];
+
+    static SIGNATURE_TEST_VECTOR: &[u8] = &[
+        0x44, 0xae, 0xcc, 0xe2, 0xb9, 0x96, 0x18, 0x39, 0x0e, 0x61, 0x0f, 0x53, 0x07, 0xbf, 0xf2,
+        0x32, 0x3d, 0x44, 0xd4, 0xf2, 0x07, 0x23, 0x30, 0x85, 0x32, 0x18, 0xd2, 0x69, 0xb8, 0x29,
+        0x3c, 0x26, 0xe6, 0x0d, 0x9c, 0xa5, 0xc2, 0x73, 0xcd, 0x8c, 0xb8, 0x3c, 0x3e, 0x5b, 0xfd,
+        0x62, 0x8d, 0xf6, 0xc4, 0x27, 0xa6, 0xe9, 0x11, 0x06, 0x5a, 0xb2, 0x2b, 0x64, 0xf7, 0xfc,
+        0xbb, 0xab, 0x4a, 0x0e,
+    ];
+
+    #[test]
+    fn hash_derive_sign_verify() {
+        let mut ctx = OpenDiceCborContext::new();
+        let seed = ctx.hash("MySeedString".as_bytes()).unwrap();
+        assert_eq!(seed, SEED_TEST_VECTOR);
+        let cdi_attest = &seed[..CDI_SIZE];
+        assert_eq!(cdi_attest, CDI_ATTEST_TEST_VECTOR);
+        let cdi_private_key_seed =
+            ctx.derive_cdi_private_key_seed(cdi_attest.try_into().unwrap()).unwrap();
+        assert_eq!(&cdi_private_key_seed[..], CDI_PRIVATE_KEY_SEED_TEST_VECTOR);
+        let (pub_key, priv_key) =
+            ctx.keypair_from_seed(cdi_private_key_seed[..].try_into().unwrap()).unwrap();
+        assert_eq!(&pub_key, PUB_KEY_TEST_VECTOR);
+        assert_eq!(&priv_key[..], PRIV_KEY_TEST_VECTOR);
+        let mut signature =
+            ctx.sign("MyMessage".as_bytes(), priv_key[..].try_into().unwrap()).unwrap();
+        assert_eq!(&signature, SIGNATURE_TEST_VECTOR);
+        assert!(ctx
+            .verify(
+                "MyMessage".as_bytes(),
+                signature[..].try_into().unwrap(),
+                pub_key[..].try_into().unwrap()
+            )
+            .is_ok());
+        assert!(ctx
+            .verify(
+                "MyMessage_fail".as_bytes(),
+                signature[..].try_into().unwrap(),
+                pub_key[..].try_into().unwrap()
+            )
+            .is_err());
+        signature[0] += 1;
+        assert!(ctx
+            .verify(
+                "MyMessage".as_bytes(),
+                signature[..].try_into().unwrap(),
+                pub_key[..].try_into().unwrap()
+            )
+            .is_err());
+    }
+
+    static SAMPLE_CDI_ATTEST_TEST_VECTOR: &[u8] = &[
+        0x3e, 0x57, 0x65, 0x5d, 0x48, 0x02, 0xbd, 0x5c, 0x66, 0xcc, 0x1f, 0x0f, 0xbe, 0x5e, 0x32,
+        0xb6, 0x9e, 0x3d, 0x04, 0xaf, 0x00, 0x15, 0xbc, 0xdd, 0x1f, 0xbc, 0x59, 0xe4, 0xc3, 0x87,
+        0x95, 0x5e,
+    ];
+
+    static SAMPLE_CDI_SEAL_TEST_VECTOR: &[u8] = &[
+        0x36, 0x1b, 0xd2, 0xb3, 0xc4, 0xda, 0x77, 0xb2, 0x9c, 0xba, 0x39, 0x53, 0x82, 0x93, 0xd9,
+        0xb8, 0x9f, 0x73, 0x2d, 0x27, 0x06, 0x15, 0xa8, 0xcb, 0x6d, 0x1d, 0xf2, 0xb1, 0x54, 0xbb,
+        0x62, 0xf1,
+    ];
+
+    static SAMPLE_BCC_TEST_VECTOR: &[u8] = &[
+        0x84, 0xa5, 0x01, 0x01, 0x03, 0x27, 0x04, 0x02, 0x20, 0x06, 0x21, 0x58, 0x20, 0x3e, 0x85,
+        0xe5, 0x72, 0x75, 0x55, 0xe5, 0x1e, 0xe7, 0xf3, 0x35, 0x94, 0x8e, 0xbb, 0xbd, 0x74, 0x1e,
+        0x1d, 0xca, 0x49, 0x9c, 0x97, 0x39, 0x77, 0x06, 0xd3, 0xc8, 0x6e, 0x8b, 0xd7, 0x33, 0xf9,
+        0x84, 0x43, 0xa1, 0x01, 0x27, 0xa0, 0x59, 0x01, 0x8a, 0xa9, 0x01, 0x78, 0x28, 0x34, 0x32,
+        0x64, 0x38, 0x38, 0x36, 0x34, 0x66, 0x39, 0x37, 0x62, 0x36, 0x35, 0x34, 0x37, 0x61, 0x35,
+        0x30, 0x63, 0x31, 0x65, 0x30, 0x61, 0x37, 0x34, 0x39, 0x66, 0x38, 0x65, 0x66, 0x38, 0x62,
+        0x38, 0x31, 0x65, 0x63, 0x36, 0x32, 0x61, 0x66, 0x02, 0x78, 0x28, 0x31, 0x66, 0x36, 0x39,
+        0x36, 0x66, 0x30, 0x37, 0x32, 0x35, 0x32, 0x66, 0x32, 0x39, 0x65, 0x39, 0x33, 0x66, 0x65,
+        0x34, 0x64, 0x65, 0x31, 0x39, 0x65, 0x65, 0x33, 0x32, 0x63, 0x64, 0x38, 0x31, 0x64, 0x63,
+        0x34, 0x30, 0x34, 0x65, 0x37, 0x36, 0x3a, 0x00, 0x47, 0x44, 0x50, 0x58, 0x40, 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, 0x3a, 0x00, 0x47, 0x44, 0x53, 0x56, 0xa3, 0x3a, 0x00, 0x01, 0x11, 0x71, 0x63,
+        0x41, 0x42, 0x4c, 0x3a, 0x00, 0x01, 0x11, 0x72, 0x01, 0x3a, 0x00, 0x01, 0x11, 0x73, 0xf6,
+        0x3a, 0x00, 0x47, 0x44, 0x52, 0x58, 0x40, 0x47, 0xae, 0x42, 0x27, 0x4c, 0xcb, 0x65, 0x4d,
+        0xee, 0x74, 0x2d, 0x05, 0x78, 0x2a, 0x08, 0x2a, 0xa5, 0xf0, 0xcf, 0xea, 0x3e, 0x60, 0xee,
+        0x97, 0x11, 0x4b, 0x5b, 0xe6, 0x05, 0x0c, 0xe8, 0x90, 0xf5, 0x22, 0xc4, 0xc6, 0x67, 0x7a,
+        0x22, 0x27, 0x17, 0xb3, 0x79, 0xcc, 0x37, 0x64, 0x5e, 0x19, 0x4f, 0x96, 0x37, 0x67, 0x3c,
+        0xd0, 0xc5, 0xed, 0x0f, 0xdd, 0xe7, 0x2e, 0x4f, 0x70, 0x97, 0x30, 0x3a, 0x00, 0x47, 0x44,
+        0x54, 0x58, 0x40, 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, 0x3a, 0x00, 0x47, 0x44, 0x56, 0x41, 0x01, 0x3a,
+        0x00, 0x47, 0x44, 0x57, 0x58, 0x2d, 0xa5, 0x01, 0x01, 0x03, 0x27, 0x04, 0x81, 0x02, 0x20,
+        0x06, 0x21, 0x58, 0x20, 0xb1, 0x02, 0xcc, 0x2c, 0xb2, 0x6a, 0x3b, 0xe9, 0xc1, 0xd3, 0x95,
+        0x10, 0xa0, 0xe1, 0xff, 0x51, 0xde, 0x57, 0xd5, 0x65, 0x28, 0xfd, 0x7f, 0xeb, 0xd4, 0xca,
+        0x15, 0xf3, 0xca, 0xdf, 0x37, 0x88, 0x3a, 0x00, 0x47, 0x44, 0x58, 0x41, 0x20, 0x58, 0x40,
+        0x58, 0xd8, 0x03, 0x24, 0x53, 0x60, 0x57, 0xa9, 0x09, 0xfa, 0xab, 0xdc, 0x57, 0x1e, 0xf0,
+        0xe5, 0x1e, 0x51, 0x6f, 0x9e, 0xa3, 0x42, 0xe6, 0x6a, 0x8c, 0xaa, 0xad, 0x08, 0x48, 0xde,
+        0x7f, 0x4f, 0x6e, 0x2f, 0x7f, 0x39, 0x6c, 0xa1, 0xf8, 0x42, 0x71, 0xfe, 0x17, 0x3d, 0xca,
+        0x31, 0x83, 0x92, 0xed, 0xbb, 0x40, 0xb8, 0x10, 0xe0, 0xf2, 0x5a, 0x99, 0x53, 0x38, 0x46,
+        0x33, 0x97, 0x78, 0x05, 0x84, 0x43, 0xa1, 0x01, 0x27, 0xa0, 0x59, 0x01, 0x8a, 0xa9, 0x01,
+        0x78, 0x28, 0x31, 0x66, 0x36, 0x39, 0x36, 0x66, 0x30, 0x37, 0x32, 0x35, 0x32, 0x66, 0x32,
+        0x39, 0x65, 0x39, 0x33, 0x66, 0x65, 0x34, 0x64, 0x65, 0x31, 0x39, 0x65, 0x65, 0x33, 0x32,
+        0x63, 0x64, 0x38, 0x31, 0x64, 0x63, 0x34, 0x30, 0x34, 0x65, 0x37, 0x36, 0x02, 0x78, 0x28,
+        0x32, 0x35, 0x39, 0x34, 0x38, 0x39, 0x65, 0x36, 0x39, 0x37, 0x34, 0x38, 0x37, 0x30, 0x35,
+        0x64, 0x65, 0x33, 0x65, 0x32, 0x66, 0x34, 0x34, 0x32, 0x36, 0x37, 0x65, 0x61, 0x34, 0x39,
+        0x33, 0x38, 0x66, 0x66, 0x36, 0x61, 0x35, 0x37, 0x32, 0x35, 0x3a, 0x00, 0x47, 0x44, 0x50,
+        0x58, 0x40, 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, 0x3a, 0x00, 0x47, 0x44, 0x53, 0x56, 0xa3, 0x3a, 0x00,
+        0x01, 0x11, 0x71, 0x63, 0x41, 0x56, 0x42, 0x3a, 0x00, 0x01, 0x11, 0x72, 0x01, 0x3a, 0x00,
+        0x01, 0x11, 0x73, 0xf6, 0x3a, 0x00, 0x47, 0x44, 0x52, 0x58, 0x40, 0x93, 0x17, 0xe1, 0x11,
+        0x27, 0x59, 0xd0, 0xef, 0x75, 0x0b, 0x2b, 0x1c, 0x0f, 0x5f, 0x52, 0xc3, 0x29, 0x23, 0xb5,
+        0x2a, 0xe6, 0x12, 0x72, 0x6f, 0x39, 0x86, 0x65, 0x2d, 0xf2, 0xe4, 0xe7, 0xd0, 0xaf, 0x0e,
+        0xa7, 0x99, 0x16, 0x89, 0x97, 0x21, 0xf7, 0xdc, 0x89, 0xdc, 0xde, 0xbb, 0x94, 0x88, 0x1f,
+        0xda, 0xe2, 0xf3, 0xe0, 0x54, 0xf9, 0x0e, 0x29, 0xb1, 0xbd, 0xe1, 0x0c, 0x0b, 0xd7, 0xf6,
+        0x3a, 0x00, 0x47, 0x44, 0x54, 0x58, 0x40, 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, 0x3a, 0x00, 0x47, 0x44,
+        0x56, 0x41, 0x01, 0x3a, 0x00, 0x47, 0x44, 0x57, 0x58, 0x2d, 0xa5, 0x01, 0x01, 0x03, 0x27,
+        0x04, 0x81, 0x02, 0x20, 0x06, 0x21, 0x58, 0x20, 0x96, 0x6d, 0x96, 0x42, 0xda, 0x64, 0x51,
+        0xad, 0xfa, 0x00, 0xbc, 0xbc, 0x95, 0x8a, 0xb0, 0xb9, 0x76, 0x01, 0xe6, 0xbd, 0xc0, 0x26,
+        0x79, 0x26, 0xfc, 0x0f, 0x1d, 0x87, 0x65, 0xf1, 0xf3, 0x99, 0x3a, 0x00, 0x47, 0x44, 0x58,
+        0x41, 0x20, 0x58, 0x40, 0x10, 0x7f, 0x77, 0xad, 0x70, 0xbd, 0x52, 0x81, 0x28, 0x8d, 0x24,
+        0x81, 0xb4, 0x3f, 0x21, 0x68, 0x9f, 0xc3, 0x80, 0x68, 0x86, 0x55, 0xfb, 0x2e, 0x6d, 0x96,
+        0xe1, 0xe1, 0xb7, 0x28, 0x8d, 0x63, 0x85, 0xba, 0x2a, 0x01, 0x33, 0x87, 0x60, 0x63, 0xbb,
+        0x16, 0x3f, 0x2f, 0x3d, 0xf4, 0x2d, 0x48, 0x5b, 0x87, 0xed, 0xda, 0x34, 0xeb, 0x9c, 0x4d,
+        0x14, 0xac, 0x65, 0xf4, 0xfa, 0xef, 0x45, 0x0b, 0x84, 0x43, 0xa1, 0x01, 0x27, 0xa0, 0x59,
+        0x01, 0x8f, 0xa9, 0x01, 0x78, 0x28, 0x32, 0x35, 0x39, 0x34, 0x38, 0x39, 0x65, 0x36, 0x39,
+        0x37, 0x34, 0x38, 0x37, 0x30, 0x35, 0x64, 0x65, 0x33, 0x65, 0x32, 0x66, 0x34, 0x34, 0x32,
+        0x36, 0x37, 0x65, 0x61, 0x34, 0x39, 0x33, 0x38, 0x66, 0x66, 0x36, 0x61, 0x35, 0x37, 0x32,
+        0x35, 0x02, 0x78, 0x28, 0x35, 0x64, 0x34, 0x65, 0x64, 0x37, 0x66, 0x34, 0x31, 0x37, 0x61,
+        0x39, 0x35, 0x34, 0x61, 0x31, 0x38, 0x31, 0x34, 0x30, 0x37, 0x62, 0x35, 0x38, 0x38, 0x35,
+        0x61, 0x66, 0x64, 0x37, 0x32, 0x61, 0x35, 0x62, 0x66, 0x34, 0x30, 0x64, 0x61, 0x36, 0x3a,
+        0x00, 0x47, 0x44, 0x50, 0x58, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x47, 0x44, 0x53,
+        0x58, 0x1a, 0xa3, 0x3a, 0x00, 0x01, 0x11, 0x71, 0x67, 0x41, 0x6e, 0x64, 0x72, 0x6f, 0x69,
+        0x64, 0x3a, 0x00, 0x01, 0x11, 0x72, 0x0c, 0x3a, 0x00, 0x01, 0x11, 0x73, 0xf6, 0x3a, 0x00,
+        0x47, 0x44, 0x52, 0x58, 0x40, 0x26, 0x1a, 0xbd, 0x26, 0xd8, 0x37, 0x8f, 0x4a, 0xf2, 0x9e,
+        0x49, 0x4d, 0x93, 0x23, 0xc4, 0x6e, 0x02, 0xda, 0xe0, 0x00, 0x02, 0xe7, 0xed, 0x29, 0xdf,
+        0x2b, 0xb3, 0x69, 0xf3, 0x55, 0x0e, 0x4c, 0x22, 0xdc, 0xcf, 0xf5, 0x92, 0xc9, 0xfa, 0x78,
+        0x98, 0xf1, 0x0e, 0x55, 0x5f, 0xf4, 0x45, 0xed, 0xc0, 0x0a, 0x72, 0x2a, 0x7a, 0x3a, 0xd2,
+        0xb1, 0xf7, 0x76, 0xfe, 0x2a, 0x6b, 0x7b, 0x2a, 0x53, 0x3a, 0x00, 0x47, 0x44, 0x54, 0x58,
+        0x40, 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, 0x3a, 0x00, 0x47, 0x44, 0x56, 0x41, 0x01, 0x3a, 0x00, 0x47,
+        0x44, 0x57, 0x58, 0x2d, 0xa5, 0x01, 0x01, 0x03, 0x27, 0x04, 0x81, 0x02, 0x20, 0x06, 0x21,
+        0x58, 0x20, 0xdb, 0xe7, 0x5b, 0x3f, 0xa3, 0x42, 0xb0, 0x9c, 0xf8, 0x40, 0x8c, 0xb0, 0x9c,
+        0xf0, 0x0a, 0xaf, 0xdf, 0x6f, 0xe5, 0x09, 0x21, 0x11, 0x92, 0xe1, 0xf8, 0xc5, 0x09, 0x02,
+        0x3d, 0x1f, 0xb7, 0xc5, 0x3a, 0x00, 0x47, 0x44, 0x58, 0x41, 0x20, 0x58, 0x40, 0xc4, 0xc1,
+        0xd7, 0x1c, 0x2d, 0x26, 0x89, 0x22, 0xcf, 0xa6, 0x99, 0x77, 0x30, 0x84, 0x86, 0x27, 0x59,
+        0x8f, 0xd8, 0x08, 0x75, 0xe0, 0xb2, 0xef, 0xf9, 0xfa, 0xa5, 0x40, 0x8c, 0xd3, 0xeb, 0xbb,
+        0xda, 0xf2, 0xc8, 0xae, 0x41, 0x22, 0x50, 0x9c, 0xe8, 0xb2, 0x9c, 0x9b, 0x3f, 0x8a, 0x78,
+        0x76, 0xab, 0xd0, 0xbe, 0xfc, 0xe4, 0x79, 0xcb, 0x1b, 0x2b, 0xaa, 0x4d, 0xdd, 0x15, 0x61,
+        0x42, 0x06,
+    ];
+
+    // This test invokes make_sample_bcc_and_cdis and compares the result bitwise to the target
+    // vectors. The function uses main_flow, bcc_main_flow, format_config_descriptor,
+    // derive_cdi_private_key_seed, and keypair_from_seed. This test is sensitive to errors
+    // and changes in any of those functions.
+    #[test]
+    fn main_flow_and_bcc_main_flow() {
+        let (cdi_attest, cdi_seal, bcc) = make_sample_bcc_and_cdis().unwrap();
+        assert_eq!(&cdi_attest[..], SAMPLE_CDI_ATTEST_TEST_VECTOR);
+        assert_eq!(&cdi_seal[..], SAMPLE_CDI_SEAL_TEST_VECTOR);
+        assert_eq!(&bcc[..], SAMPLE_BCC_TEST_VECTOR);
+    }
+
+    static DERIVED_KEY_TEST_VECTOR: &[u8] = &[
+        0x0e, 0xd6, 0x07, 0x0e, 0x1c, 0x38, 0x2c, 0x76, 0x13, 0xc6, 0x76, 0x25, 0x7e, 0x07, 0x6f,
+        0xdb, 0x1d, 0xb1, 0x0f, 0x3f, 0xed, 0xc5, 0x2b, 0x95, 0xd1, 0x32, 0xf1, 0x63, 0x2f, 0x2a,
+        0x01, 0x5e,
+    ];
+
+    #[test]
+    fn kdf() {
+        let mut ctx = OpenDiceCborContext::new();
+        let derived_key = ctx
+            .kdf(
+                PRIVATE_KEY_SEED_SIZE,
+                "myKey".as_bytes(),
+                "mySalt".as_bytes(),
+                "myInfo".as_bytes(),
+            )
+            .unwrap();
+        assert_eq!(&derived_key[..], DERIVED_KEY_TEST_VECTOR);
+    }
+
+    static CERT_ID_TEST_VECTOR: &[u8] = &[
+        0x7a, 0x36, 0x45, 0x2c, 0x02, 0xf6, 0x2b, 0xec, 0xf9, 0x80, 0x06, 0x75, 0x87, 0xa5, 0xc1,
+        0x44, 0x0c, 0xd3, 0xc0, 0x6d,
+    ];
+
+    #[test]
+    fn derive_cdi_certificate_id() {
+        let mut ctx = OpenDiceCborContext::new();
+        let cert_id = ctx.derive_cdi_certificate_id("MyPubKey".as_bytes()).unwrap();
+        assert_eq!(&cert_id[..], CERT_ID_TEST_VECTOR);
+    }
+}
diff --git a/diced/src/diced_client_test.rs b/diced/src/diced_client_test.rs
new file mode 100644
index 0000000..3f5b68f
--- /dev/null
+++ b/diced/src/diced_client_test.rs
@@ -0,0 +1,196 @@
+// 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::{
+    Config::Config as BinderConfig, InputValues::InputValues as BinderInputValues,
+    Mode::Mode as BinderMode,
+};
+use android_security_dice::aidl::android::security::dice::IDiceMaintenance::IDiceMaintenance;
+use android_security_dice::aidl::android::security::dice::IDiceNode::IDiceNode;
+use anyhow::Result;
+use binder::Strong;
+use diced_open_dice_cbor as dice;
+use nix::libc::uid_t;
+use std::convert::TryInto;
+
+static DICE_NODE_SERVICE_NAME: &str = "android.security.dice.IDiceNode";
+static DICE_MAINTENANCE_SERVICE_NAME: &str = "android.security.dice.IDiceMaintenance";
+
+fn get_dice_node() -> Strong<dyn IDiceNode> {
+    binder::get_interface(DICE_NODE_SERVICE_NAME).unwrap()
+}
+
+fn get_dice_maintenance() -> Strong<dyn IDiceMaintenance> {
+    binder::get_interface(DICE_MAINTENANCE_SERVICE_NAME).unwrap()
+}
+
+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.
+fn equivalence_test() {
+    let node = get_dice_node();
+    let input_values = diced_sample_inputs::get_input_values_vector();
+    let former = node.derive(&[]).expect("Trying to call derive.");
+    let latter = node.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<diced_utils::InputValues> =
+        input_values.iter().map(|v| v.try_into()).collect::<Result<_>>().unwrap();
+
+    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 when we have a parser/verifier, check equivalence rather
+    // than bit by bit equality.
+    assert_eq!(latter, from_former);
+}
+
+fn sign_and_verify() {
+    let node = get_dice_node();
+    let _signature = node.sign(&[], TEST_MESSAGE).expect("Trying to call sign.");
+
+    let _bcc = node.getAttestationChain(&[]).expect("Trying to call getAttestationChain.");
+    // TODO b/204938506 check the signature with the bcc when the verifier is available.
+}
+
+// This test calls derive with an empty argument vector, then demotes the itself 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.
+fn demote_test() {
+    let node = get_dice_node();
+    let input_values = diced_sample_inputs::get_input_values_vector();
+    let former = node.derive(&[]).expect("Trying to call derive.");
+    node.demote(&input_values).expect("Trying to call demote with input values.");
+
+    let latter = node.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<diced_utils::InputValues> =
+        input_values.iter().map(|v| v.try_into()).collect::<Result<_>>().unwrap();
+
+    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);
+}
+
+fn client_input_values(uid: uid_t) -> BinderInputValues {
+    BinderInputValues {
+        codeHash: vec![0; dice::HASH_SIZE],
+        config: BinderConfig {
+            desc: dice::bcc::format_config_descriptor(Some(&format!("{}", uid)), None, true)
+                .unwrap(),
+        },
+        authorityHash: vec![0; dice::HASH_SIZE],
+        authorityDescriptor: None,
+        mode: BinderMode::NORMAL,
+        hidden: vec![0; dice::HIDDEN_SIZE],
+    }
+}
+
+// This test calls derive with an empty argument vector `former` which look like this:
+// <common root> | <caller>
+// It then demotes diced using a set of three input values prefixed with the uid based input
+// values that diced would add to any call. It then calls derive with empty argument vector
+// again which will add another step using the identity of the caller. If diced was demoted
+// correctly the chain of `latter` will
+// look as follows:
+// <common root> | <caller> | <the three sample inputs> | <caller>
+//
+// It then performs the same three derivation steps followed by a set of caller input values
+// on `former` and compares it to `latter`.
+fn demote_self_test() {
+    let maintenance = get_dice_maintenance();
+    let node = get_dice_node();
+    let input_values = diced_sample_inputs::get_input_values_vector();
+    let former = node.derive(&[]).expect("Trying to call derive.");
+
+    let client = client_input_values(nix::unistd::getuid().into());
+
+    let mut demote_vector = vec![client.clone()];
+    demote_vector.append(&mut input_values.clone());
+    maintenance.demoteSelf(&demote_vector).expect("Trying to call demote_self with input values.");
+
+    let latter = node.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 client = [client];
+    let input_values: Vec<diced_utils::InputValues> = input_values
+        .iter()
+        .chain(client.iter())
+        .map(|v| v.try_into())
+        .collect::<Result<_>>()
+        .unwrap();
+
+    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);
+}
+
+#[test]
+fn run_serialized_test() {
+    equivalence_test();
+    sign_and_verify();
+    // The demote self test must run before the demote test or the test fails.
+    // And since demotion is not reversible the test can only pass once per boot.
+    demote_self_test();
+    demote_test();
+}
diff --git a/diced/src/diced_main.rs b/diced/src/diced_main.rs
new file mode 100644
index 0000000..c2cf02c
--- /dev/null
+++ b/diced/src/diced_main.rs
@@ -0,0 +1,76 @@
+// 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 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(
+        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<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.");
+
+    let maintenance = DiceMaintenance::new_as_binder(node_impl)
+        .expect("Failed to create IDiceMaintenance service instance.");
+
+    binder::add_service(DICE_NODE_SERVICE_NAME, node.as_binder())
+        .expect("Failed to register IDiceNode Service");
+
+    binder::add_service(DICE_MAINTENANCE_SERVICE_NAME, maintenance.as_binder())
+        .expect("Failed to register IDiceMaintenance 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/error_vendor.rs b/diced/src/error_vendor.rs
new file mode 100644
index 0000000..10d50dd
--- /dev/null
+++ b/diced/src/error_vendor.rs
@@ -0,0 +1,121 @@
+// 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::ResponseCode::ResponseCode;
+use anyhow::Result;
+use binder::public_api::{
+    ExceptionCode, Result as BinderResult, Status as BinderStatus, StatusCode,
+};
+use std::ffi::CString;
+
+/// This is the error type for DICE HAL implementations. It wraps
+/// `android::hardware::security::dice::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 Keystore 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 => ResponseCode::SYSTEM_ERROR.0,
+    }
+}
diff --git a/diced/src/hal_node.rs b/diced/src/hal_node.rs
new file mode 100644
index 0000000..fd5384f
--- /dev/null
+++ b/diced/src/hal_node.rs
@@ -0,0 +1,722 @@
+// 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 `ResidentHal`, an implementation of a IDiceDevice HAL Interface.
+//! While the name implies that the DICE secrets are memory resident, the residency
+//! is augmented by the implementation of the traits `DiceArtifacts` and
+//! `UpdatableDiceArtifacts`. The implementation outsources all operations that
+//! involve the DICE secrets to a short lived child process. By implementing
+//! `UpdatableDiceArtifacts` accordingly, integrators can limit the exposure of
+//! the resident DICE secrets to user space memory. E.g., an implementation might only
+//! hold a path to a securefs file allowing the child to read and update the kernel state
+//! through this path directly.
+//!
+//! ## Important Safety Note.
+//! The module is not safe to use in multi threaded processes. It uses fork and runs
+//! code that is not async signal safe in the child. Implementing a HAL service without
+//! starting a thread pool is safe, but no secondary thread must be created.
+
+use crate::error_vendor::map_or_log_err;
+use android_hardware_security_dice::aidl::android::hardware::security::dice::{
+    Bcc::Bcc, BccHandover::BccHandover, IDiceDevice::BnDiceDevice, IDiceDevice::IDiceDevice,
+    InputValues::InputValues as BinderInputValues, Signature::Signature,
+};
+use anyhow::{Context, Result};
+use binder::public_api::{BinderFeatures, Result as BinderResult, Strong};
+use dice::{ContextImpl, OpenDiceCborContext};
+use diced_open_dice_cbor as dice;
+use diced_utils as utils;
+use nix::sys::wait::{waitpid, WaitStatus};
+use nix::unistd::{
+    close, fork, pipe as nix_pipe, read as nix_read, write as nix_write, ForkResult,
+};
+use serde::{de::DeserializeOwned, Deserialize, Serialize};
+use std::convert::TryInto;
+use std::io::{Read, Write};
+use std::os::unix::io::RawFd;
+use std::sync::{Arc, RwLock};
+use utils::ResidentArtifacts;
+pub use utils::{DiceArtifacts, UpdatableDiceArtifacts};
+
+/// PipeReader is a simple wrapper around raw pipe file descriptors.
+/// It takes ownership of the file descriptor and closes it on drop. It provides `read_all`, which
+/// reads from the pipe into an expending vector, until no more data can be read.
+struct PipeReader(RawFd);
+
+impl Read for PipeReader {
+    fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
+        let bytes = nix_read(self.0, buf)?;
+        Ok(bytes)
+    }
+}
+
+impl Drop for PipeReader {
+    fn drop(&mut self) {
+        close(self.0).expect("Failed to close reader pipe fd.");
+    }
+}
+
+/// PipeWriter is a simple wrapper around raw pipe file descriptors.
+/// It takes ownership of the file descriptor and closes it on drop. It provides `write`, which
+/// writes the given buffer into the pipe, returning the number of bytes written.
+struct PipeWriter(RawFd);
+
+impl Write for PipeWriter {
+    fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
+        let written = nix_write(self.0, buf)?;
+        Ok(written)
+    }
+
+    fn flush(&mut self) -> std::io::Result<()> {
+        // Flush is a NO-OP.
+        Ok(())
+    }
+}
+
+impl Drop for PipeWriter {
+    fn drop(&mut self) {
+        close(self.0).expect("Failed to close writer pipe fd.");
+    }
+}
+
+fn pipe() -> Result<(PipeReader, PipeWriter), nix::Error> {
+    let (read_fd, write_fd) = nix_pipe()?;
+    Ok((PipeReader(read_fd), PipeWriter(write_fd)))
+}
+
+#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, thiserror::Error)]
+enum RunForkedError {
+    #[error("RunForkedError::String({0:?})")]
+    String(String),
+}
+
+/// Run the given closure in a new process.
+/// Safety: The function runs code that is not async-signal-safe in the child after forking.
+/// This means, that this function must not be called by a multi threaded process.
+fn run_forked<F, R>(f: F) -> Result<R>
+where
+    R: Serialize + DeserializeOwned,
+    F: FnOnce() -> Result<R>,
+{
+    let (reader, writer) = pipe().expect("Failed to create pipe.");
+
+    match unsafe { fork() } {
+        Ok(ForkResult::Parent { child, .. }) => {
+            drop(writer);
+            let status = waitpid(child, None).expect("Failed while waiting for child.");
+            if let WaitStatus::Exited(_, 0) = status {
+                // Child exited successfully.
+                // Read the result from the pipe.
+                // Deserialize the result and return it.
+                let result: Result<R, RunForkedError> =
+                    serde_cbor::from_reader(reader).expect("Failed to deserialize result.");
+
+                result.context("In run_forked:")
+            } else {
+                panic!("Child did not exit as expected {:?}", status);
+            }
+        }
+        Ok(ForkResult::Child) => {
+            // Run the closure.
+            let result = f()
+                .map_err(|err| RunForkedError::String(format! {"Nested anyhow error {:?}", err}));
+
+            // Serialize the result of the closure.
+            serde_cbor::to_writer(writer, &result).expect("Result serialization failed");
+
+            // Set exit status to `0`.
+            std::process::exit(0);
+        }
+        Err(errno) => {
+            panic!("Failed to fork: {:?}", errno);
+        }
+    }
+}
+
+/// A DiceHal backend implementation.
+/// All functions, except `demote`, derive effective dice artifacts starting from
+/// this node and iterating through `input_values` in ascending order.
+pub trait DiceHalImpl {
+    /// Signs the message using the effective dice artifacts and Ed25519Pure.
+    fn sign(&self, input_values: &[BinderInputValues], message: &[u8]) -> Result<Signature>;
+    /// Returns the effective attestation chain.
+    fn get_attestation_chain(&self, input_values: &[BinderInputValues]) -> Result<Bcc>;
+    /// Returns the effective dice artifacts.
+    fn derive(&self, input_values: &[BinderInputValues]) -> Result<BccHandover>;
+    /// This demotes the implementation itself. I.e. a resident node would replace its resident
+    /// artifacts 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, input_values: &[BinderInputValues]) -> Result<()>;
+}
+
+/// The ResidentHal implements a IDiceDevice backend with memory resident DICE secrets.
+pub struct ResidentHal<T: UpdatableDiceArtifacts + Serialize + DeserializeOwned + Clone + Send> {
+    artifacts: RwLock<T>,
+}
+
+impl<T: UpdatableDiceArtifacts + Serialize + DeserializeOwned + Clone + Send> ResidentHal<T> {
+    /// Creates a new Resident node with the given dice secrets and certificate chain.
+    /// ## Safety
+    /// It is not safe to use implementations of ResidentHal in multi threaded environments.
+    /// If using this library to implement a HAL service make sure not to start a thread pool.
+    pub unsafe fn new(artifacts: T) -> Result<Self> {
+        Ok(ResidentHal { artifacts: RwLock::new(artifacts) })
+    }
+
+    fn with_effective_artifacts<R, F>(&self, input_values: &[BinderInputValues], f: F) -> Result<R>
+    where
+        R: Serialize + DeserializeOwned,
+        F: FnOnce(ResidentArtifacts) -> Result<R>,
+    {
+        let artifacts = self.artifacts.read().unwrap().clone();
+
+        // Safety: run_forked must not be be called by a multi threaded process.
+        // This requirement is propagated to the public interface of this module through
+        // `ResidentHal::new`
+        run_forked(move || {
+            let artifacts = artifacts.with_artifacts(|a| ResidentArtifacts::new_from(a))?;
+            let input_values: Vec<utils::InputValues> =
+                input_values.iter().map(|v| v.try_into()).collect::<Result<_>>()?;
+            let artifacts = artifacts
+                .execute_steps(input_values.iter().map(|v| v as &dyn dice::InputValues))
+                .context("In ResidentHal::get_effective_artifacts:")?;
+            f(artifacts)
+        })
+    }
+}
+
+impl<T: UpdatableDiceArtifacts + Serialize + DeserializeOwned + Clone + Send> DiceHalImpl
+    for ResidentHal<T>
+{
+    fn sign(&self, input_values: &[BinderInputValues], message: &[u8]) -> Result<Signature> {
+        let signature: Vec<u8> = self
+            .with_effective_artifacts(input_values, |artifacts| {
+                let (cdi_attest, _, _) = artifacts.into_tuple();
+                let mut dice = OpenDiceCborContext::new();
+                let seed = dice
+                    .derive_cdi_private_key_seed(cdi_attest[..].try_into().with_context(|| {
+                        format!(
+                            "In ResidentHal::sign: Failed to convert cdi_attest (length: {}).",
+                            cdi_attest.len()
+                        )
+                    })?)
+                    .context("In ResidentHal::sign: Failed to derive seed from cdi_attest.")?;
+                let (_public_key, private_key) = dice
+                    .keypair_from_seed(seed[..].try_into().with_context(|| {
+                        format!(
+                            "In ResidentHal::sign: Failed to convert seed (length: {}).",
+                            seed.len()
+                        )
+                    })?)
+                    .context("In ResidentHal::sign: Failed to derive keypair from seed.")?;
+                dice.sign(
+                    message,
+                    private_key[..].try_into().with_context(|| {
+                        format!(
+                            "In ResidentHal::sign: Failed to convert private_key (length: {}).",
+                            private_key.len()
+                        )
+                    })?,
+                )
+                .context("In ResidentHal::sign: Failed to sign.")
+            })
+            .context("In ResidentHal::sign:")?;
+        Ok(Signature { data: signature })
+    }
+
+    fn get_attestation_chain(&self, input_values: &[BinderInputValues]) -> Result<Bcc> {
+        let bcc = self
+            .with_effective_artifacts(input_values, |artifacts| {
+                let (_, _, bcc) = artifacts.into_tuple();
+                Ok(bcc)
+            })
+            .context("In ResidentHal::get_attestation_chain: Failed to get effective_artifacts.")?;
+
+        Ok(Bcc { data: bcc })
+    }
+
+    fn derive(&self, input_values: &[BinderInputValues]) -> Result<BccHandover> {
+        let (cdi_attest, cdi_seal, bcc): (Vec<u8>, Vec<u8>, Vec<u8>) = self
+            .with_effective_artifacts(input_values, |artifacts| {
+                let (cdi_attest, cdi_seal, bcc) = artifacts.into_tuple();
+                Ok((cdi_attest[..].to_vec(), cdi_seal[..].to_vec(), bcc))
+            })?;
+
+        utils::make_bcc_handover(
+            &cdi_attest
+                .as_slice()
+                .try_into()
+                .context("In ResidentHal::derive: Trying to convert cdi_attest to sized array.")?,
+            &cdi_seal
+                .as_slice()
+                .try_into()
+                .context("In ResidentHal::derive: Trying to convert cdi_seal to sized array.")?,
+            &bcc,
+        )
+        .context("In ResidentHal::derive: Trying to construct BccHandover.")
+    }
+
+    fn demote(&self, input_values: &[BinderInputValues]) -> Result<()> {
+        let mut artifacts = self.artifacts.write().unwrap();
+
+        let artifacts_clone = (*artifacts).clone();
+
+        // Safety: run_forked may not be called from a multi threaded process.
+        // This requirement is propagated to the public interface of this module through
+        // `ResidentHal::new`
+        *artifacts = run_forked(|| {
+            let new_artifacts =
+                artifacts_clone.with_artifacts(|a| ResidentArtifacts::new_from(a))?;
+            let input_values: Vec<utils::InputValues> =
+                input_values.iter().map(|v| v.try_into()).collect::<Result<_>>()?;
+
+            let new_artifacts = new_artifacts
+                .execute_steps(input_values.iter().map(|v| v as &dyn dice::InputValues))
+                .context("In ResidentHal::get_effective_artifacts:")?;
+            artifacts_clone.update(&new_artifacts)
+        })?;
+
+        Ok(())
+    }
+}
+
+/// Implements android.hardware.security.dice.IDiceDevice. Forwards public API calls
+/// to the given DiceHalImpl backend.
+pub struct DiceDevice {
+    hal_impl: Arc<dyn DiceHalImpl + Sync + Send>,
+}
+
+impl DiceDevice {
+    /// Constructs an instance of DiceDevice, wraps it with a BnDiceDevice 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(
+        hal_impl: Arc<dyn DiceHalImpl + Sync + Send>,
+    ) -> Result<Strong<dyn IDiceDevice>> {
+        let result = BnDiceDevice::new_binder(DiceDevice { hal_impl }, BinderFeatures::default());
+        Ok(result)
+    }
+}
+
+impl binder::Interface for DiceDevice {}
+
+impl IDiceDevice for DiceDevice {
+    fn sign(&self, input_values: &[BinderInputValues], message: &[u8]) -> BinderResult<Signature> {
+        map_or_log_err(self.hal_impl.sign(input_values, message), Ok)
+    }
+    fn getAttestationChain(&self, input_values: &[BinderInputValues]) -> BinderResult<Bcc> {
+        map_or_log_err(self.hal_impl.get_attestation_chain(input_values), Ok)
+    }
+    fn derive(&self, input_values: &[BinderInputValues]) -> BinderResult<BccHandover> {
+        map_or_log_err(self.hal_impl.derive(input_values), Ok)
+    }
+    fn demote(&self, input_values: &[BinderInputValues]) -> BinderResult<()> {
+        map_or_log_err(self.hal_impl.demote(input_values), Ok)
+    }
+}
+
+#[cfg(test)]
+mod test {
+    use super::*;
+    use android_hardware_security_dice::aidl::android::hardware::security::dice::{
+        BccHandover::BccHandover, Config::Config as BinderConfig,
+        InputValues::InputValues as BinderInputValues, Mode::Mode as BinderMode,
+    };
+    use anyhow::{Context, Result};
+    use diced_open_dice_cbor as dice;
+    use diced_sample_inputs;
+    use diced_utils as utils;
+
+    #[derive(Debug, Serialize, Deserialize, Clone)]
+    struct InsecureSerializableArtifacts {
+        cdi_attest: [u8; dice::CDI_SIZE],
+        cdi_seal: [u8; dice::CDI_SIZE],
+        bcc: Vec<u8>,
+    }
+
+    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<u8> {
+            self.bcc.clone()
+        }
+    }
+
+    impl UpdatableDiceArtifacts for InsecureSerializableArtifacts {
+        fn with_artifacts<F, T>(&self, f: F) -> Result<T>
+        where
+            F: FnOnce(&dyn DiceArtifacts) -> Result<T>,
+        {
+            f(self)
+        }
+        fn update(self, new_artifacts: &impl DiceArtifacts) -> Result<Self> {
+            Ok(Self {
+                cdi_attest: *new_artifacts.cdi_attest(),
+                cdi_seal: *new_artifacts.cdi_seal(),
+                bcc: new_artifacts.bcc(),
+            })
+        }
+    }
+
+    fn make_input_values(
+        code: &str,
+        config_name: &str,
+        authority: &str,
+    ) -> Result<BinderInputValues> {
+        let mut dice_ctx = dice::OpenDiceCborContext::new();
+        Ok(BinderInputValues {
+            codeHash: dice_ctx
+                .hash(code.as_bytes())
+                .context("In make_input_values: code hash failed.")?,
+            config: BinderConfig {
+                desc: dice::bcc::format_config_descriptor(Some(config_name), None, true)
+                    .context("In make_input_values: Failed to format config descriptor.")?,
+            },
+            authorityHash: dice_ctx
+                .hash(authority.as_bytes())
+                .context("In make_input_values: authority hash failed.")?,
+            authorityDescriptor: None,
+            mode: BinderMode::NORMAL,
+            hidden: vec![0; dice::HIDDEN_SIZE],
+        })
+    }
+
+    /// Test the resident artifact batched derivation in process.
+    #[test]
+    fn derive_with_resident_artifacts() -> Result<()> {
+        let (cdi_attest, cdi_seal, bcc) = diced_sample_inputs::make_sample_bcc_and_cdis()?;
+
+        let artifacts =
+            ResidentArtifacts::new(cdi_attest[..].try_into()?, cdi_seal[..].try_into()?, &bcc)?;
+
+        let input_values = &[
+            make_input_values("component 1 code", "component 1", "component 1 authority")?,
+            make_input_values("component 2 code", "component 2", "component 2 authority")?,
+            make_input_values("component 3 code", "component 3", "component 3 authority")?,
+        ];
+
+        let input_values: Vec<utils::InputValues> =
+            input_values.iter().map(|v| v.try_into()).collect::<Result<_>>()?;
+
+        let new_artifacts =
+            artifacts.execute_steps(input_values.iter().map(|v| v as &dyn dice::InputValues))?;
+
+        let result = utils::make_bcc_handover(
+            new_artifacts.cdi_attest(),
+            new_artifacts.cdi_seal(),
+            &new_artifacts.bcc(),
+        )?;
+
+        assert_eq!(result, make_derive_test_vector());
+        Ok(())
+    }
+
+    /// Test the ResidentHal hal implementation which performs the derivation in a separate
+    /// process and returns the result through a pipe. This test compares the result against
+    /// the same test vector as the in process test above.
+    #[test]
+    fn derive_with_insecure_artifacts() -> Result<()> {
+        let (cdi_attest, cdi_seal, bcc) = diced_sample_inputs::make_sample_bcc_and_cdis()?;
+
+        // Safety: ResidentHal can only be used in single threaded environments.
+        // On-device Rust tests run each test in a separate process.
+        let hal_impl = unsafe {
+            ResidentHal::new(InsecureSerializableArtifacts {
+                cdi_attest: cdi_attest[..].try_into()?,
+                cdi_seal: cdi_seal[..].try_into()?,
+                bcc,
+            })
+        }
+        .expect("Failed to create ResidentHal.");
+
+        let bcc_handover = hal_impl
+            .derive(&[
+                make_input_values("component 1 code", "component 1", "component 1 authority")?,
+                make_input_values("component 2 code", "component 2", "component 2 authority")?,
+                make_input_values("component 3 code", "component 3", "component 3 authority")?,
+            ])
+            .expect("Failed to derive artifacts.");
+
+        assert_eq!(bcc_handover, make_derive_test_vector());
+        Ok(())
+    }
+
+    /// Demoting the implementation two steps and then performing one step of child derivation
+    /// must yield the same outcome as three derivations with the same input values.
+    #[test]
+    fn demote() -> Result<()> {
+        let (cdi_attest, cdi_seal, bcc) = diced_sample_inputs::make_sample_bcc_and_cdis()?;
+
+        // Safety: ResidentHal can only be used in single threaded environments.
+        // On-device Rust tests run each test in a separate process.
+        let hal_impl = unsafe {
+            ResidentHal::new(InsecureSerializableArtifacts {
+                cdi_attest: cdi_attest[..].try_into()?,
+                cdi_seal: cdi_seal[..].try_into()?,
+                bcc,
+            })
+        }
+        .expect("Failed to create ResidentHal.");
+
+        hal_impl
+            .demote(&[
+                make_input_values("component 1 code", "component 1", "component 1 authority")?,
+                make_input_values("component 2 code", "component 2", "component 2 authority")?,
+            ])
+            .expect("Failed to demote implementation.");
+
+        let bcc_handover = hal_impl
+            .derive(&[make_input_values(
+                "component 3 code",
+                "component 3",
+                "component 3 authority",
+            )?])
+            .expect("Failed to derive artifacts.");
+
+        assert_eq!(bcc_handover, make_derive_test_vector());
+        Ok(())
+    }
+
+    fn make_derive_test_vector() -> BccHandover {
+        utils::make_bcc_handover(
+            &[
+                // cdi_attest
+                0x8f, 0xdf, 0x93, 0x67, 0xd7, 0x0e, 0xf8, 0xb8, 0xd2, 0x9c, 0x30, 0xeb, 0x4e, 0x9b,
+                0x71, 0x5f, 0x9a, 0x5b, 0x67, 0xa6, 0x29, 0xe0, 0x00, 0x9b, 0x4d, 0xe6, 0x95, 0xcf,
+                0xf9, 0xed, 0x5e, 0x9b,
+            ],
+            &[
+                // cdi_seal
+                0x15, 0x3e, 0xd6, 0x30, 0x5a, 0x8d, 0x4b, 0x6f, 0x07, 0x3f, 0x5d, 0x89, 0xc5, 0x6e,
+                0x30, 0xba, 0x05, 0x56, 0xfc, 0x66, 0xf4, 0xae, 0xce, 0x7f, 0x81, 0xb9, 0xc5, 0x21,
+                0x9b, 0x49, 0x3d, 0xe1,
+            ],
+            &[
+                // bcc
+                0x87, 0xa5, 0x01, 0x01, 0x03, 0x27, 0x04, 0x02, 0x20, 0x06, 0x21, 0x58, 0x20, 0x3e,
+                0x85, 0xe5, 0x72, 0x75, 0x55, 0xe5, 0x1e, 0xe7, 0xf3, 0x35, 0x94, 0x8e, 0xbb, 0xbd,
+                0x74, 0x1e, 0x1d, 0xca, 0x49, 0x9c, 0x97, 0x39, 0x77, 0x06, 0xd3, 0xc8, 0x6e, 0x8b,
+                0xd7, 0x33, 0xf9, 0x84, 0x43, 0xa1, 0x01, 0x27, 0xa0, 0x59, 0x01, 0x8a, 0xa9, 0x01,
+                0x78, 0x28, 0x34, 0x32, 0x64, 0x38, 0x38, 0x36, 0x34, 0x66, 0x39, 0x37, 0x62, 0x36,
+                0x35, 0x34, 0x37, 0x61, 0x35, 0x30, 0x63, 0x31, 0x65, 0x30, 0x61, 0x37, 0x34, 0x39,
+                0x66, 0x38, 0x65, 0x66, 0x38, 0x62, 0x38, 0x31, 0x65, 0x63, 0x36, 0x32, 0x61, 0x66,
+                0x02, 0x78, 0x28, 0x31, 0x66, 0x36, 0x39, 0x36, 0x66, 0x30, 0x37, 0x32, 0x35, 0x32,
+                0x66, 0x32, 0x39, 0x65, 0x39, 0x33, 0x66, 0x65, 0x34, 0x64, 0x65, 0x31, 0x39, 0x65,
+                0x65, 0x33, 0x32, 0x63, 0x64, 0x38, 0x31, 0x64, 0x63, 0x34, 0x30, 0x34, 0x65, 0x37,
+                0x36, 0x3a, 0x00, 0x47, 0x44, 0x50, 0x58, 0x40, 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, 0x3a, 0x00, 0x47, 0x44, 0x53, 0x56, 0xa3, 0x3a, 0x00, 0x01, 0x11, 0x71,
+                0x63, 0x41, 0x42, 0x4c, 0x3a, 0x00, 0x01, 0x11, 0x72, 0x01, 0x3a, 0x00, 0x01, 0x11,
+                0x73, 0xf6, 0x3a, 0x00, 0x47, 0x44, 0x52, 0x58, 0x40, 0x47, 0xae, 0x42, 0x27, 0x4c,
+                0xcb, 0x65, 0x4d, 0xee, 0x74, 0x2d, 0x05, 0x78, 0x2a, 0x08, 0x2a, 0xa5, 0xf0, 0xcf,
+                0xea, 0x3e, 0x60, 0xee, 0x97, 0x11, 0x4b, 0x5b, 0xe6, 0x05, 0x0c, 0xe8, 0x90, 0xf5,
+                0x22, 0xc4, 0xc6, 0x67, 0x7a, 0x22, 0x27, 0x17, 0xb3, 0x79, 0xcc, 0x37, 0x64, 0x5e,
+                0x19, 0x4f, 0x96, 0x37, 0x67, 0x3c, 0xd0, 0xc5, 0xed, 0x0f, 0xdd, 0xe7, 0x2e, 0x4f,
+                0x70, 0x97, 0x30, 0x3a, 0x00, 0x47, 0x44, 0x54, 0x58, 0x40, 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, 0x3a, 0x00, 0x47, 0x44, 0x56, 0x41, 0x01, 0x3a, 0x00, 0x47,
+                0x44, 0x57, 0x58, 0x2d, 0xa5, 0x01, 0x01, 0x03, 0x27, 0x04, 0x81, 0x02, 0x20, 0x06,
+                0x21, 0x58, 0x20, 0xb1, 0x02, 0xcc, 0x2c, 0xb2, 0x6a, 0x3b, 0xe9, 0xc1, 0xd3, 0x95,
+                0x10, 0xa0, 0xe1, 0xff, 0x51, 0xde, 0x57, 0xd5, 0x65, 0x28, 0xfd, 0x7f, 0xeb, 0xd4,
+                0xca, 0x15, 0xf3, 0xca, 0xdf, 0x37, 0x88, 0x3a, 0x00, 0x47, 0x44, 0x58, 0x41, 0x20,
+                0x58, 0x40, 0x58, 0xd8, 0x03, 0x24, 0x53, 0x60, 0x57, 0xa9, 0x09, 0xfa, 0xab, 0xdc,
+                0x57, 0x1e, 0xf0, 0xe5, 0x1e, 0x51, 0x6f, 0x9e, 0xa3, 0x42, 0xe6, 0x6a, 0x8c, 0xaa,
+                0xad, 0x08, 0x48, 0xde, 0x7f, 0x4f, 0x6e, 0x2f, 0x7f, 0x39, 0x6c, 0xa1, 0xf8, 0x42,
+                0x71, 0xfe, 0x17, 0x3d, 0xca, 0x31, 0x83, 0x92, 0xed, 0xbb, 0x40, 0xb8, 0x10, 0xe0,
+                0xf2, 0x5a, 0x99, 0x53, 0x38, 0x46, 0x33, 0x97, 0x78, 0x05, 0x84, 0x43, 0xa1, 0x01,
+                0x27, 0xa0, 0x59, 0x01, 0x8a, 0xa9, 0x01, 0x78, 0x28, 0x31, 0x66, 0x36, 0x39, 0x36,
+                0x66, 0x30, 0x37, 0x32, 0x35, 0x32, 0x66, 0x32, 0x39, 0x65, 0x39, 0x33, 0x66, 0x65,
+                0x34, 0x64, 0x65, 0x31, 0x39, 0x65, 0x65, 0x33, 0x32, 0x63, 0x64, 0x38, 0x31, 0x64,
+                0x63, 0x34, 0x30, 0x34, 0x65, 0x37, 0x36, 0x02, 0x78, 0x28, 0x32, 0x35, 0x39, 0x34,
+                0x38, 0x39, 0x65, 0x36, 0x39, 0x37, 0x34, 0x38, 0x37, 0x30, 0x35, 0x64, 0x65, 0x33,
+                0x65, 0x32, 0x66, 0x34, 0x34, 0x32, 0x36, 0x37, 0x65, 0x61, 0x34, 0x39, 0x33, 0x38,
+                0x66, 0x66, 0x36, 0x61, 0x35, 0x37, 0x32, 0x35, 0x3a, 0x00, 0x47, 0x44, 0x50, 0x58,
+                0x40, 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, 0x3a, 0x00, 0x47, 0x44, 0x53,
+                0x56, 0xa3, 0x3a, 0x00, 0x01, 0x11, 0x71, 0x63, 0x41, 0x56, 0x42, 0x3a, 0x00, 0x01,
+                0x11, 0x72, 0x01, 0x3a, 0x00, 0x01, 0x11, 0x73, 0xf6, 0x3a, 0x00, 0x47, 0x44, 0x52,
+                0x58, 0x40, 0x93, 0x17, 0xe1, 0x11, 0x27, 0x59, 0xd0, 0xef, 0x75, 0x0b, 0x2b, 0x1c,
+                0x0f, 0x5f, 0x52, 0xc3, 0x29, 0x23, 0xb5, 0x2a, 0xe6, 0x12, 0x72, 0x6f, 0x39, 0x86,
+                0x65, 0x2d, 0xf2, 0xe4, 0xe7, 0xd0, 0xaf, 0x0e, 0xa7, 0x99, 0x16, 0x89, 0x97, 0x21,
+                0xf7, 0xdc, 0x89, 0xdc, 0xde, 0xbb, 0x94, 0x88, 0x1f, 0xda, 0xe2, 0xf3, 0xe0, 0x54,
+                0xf9, 0x0e, 0x29, 0xb1, 0xbd, 0xe1, 0x0c, 0x0b, 0xd7, 0xf6, 0x3a, 0x00, 0x47, 0x44,
+                0x54, 0x58, 0x40, 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, 0x3a, 0x00, 0x47,
+                0x44, 0x56, 0x41, 0x01, 0x3a, 0x00, 0x47, 0x44, 0x57, 0x58, 0x2d, 0xa5, 0x01, 0x01,
+                0x03, 0x27, 0x04, 0x81, 0x02, 0x20, 0x06, 0x21, 0x58, 0x20, 0x96, 0x6d, 0x96, 0x42,
+                0xda, 0x64, 0x51, 0xad, 0xfa, 0x00, 0xbc, 0xbc, 0x95, 0x8a, 0xb0, 0xb9, 0x76, 0x01,
+                0xe6, 0xbd, 0xc0, 0x26, 0x79, 0x26, 0xfc, 0x0f, 0x1d, 0x87, 0x65, 0xf1, 0xf3, 0x99,
+                0x3a, 0x00, 0x47, 0x44, 0x58, 0x41, 0x20, 0x58, 0x40, 0x10, 0x7f, 0x77, 0xad, 0x70,
+                0xbd, 0x52, 0x81, 0x28, 0x8d, 0x24, 0x81, 0xb4, 0x3f, 0x21, 0x68, 0x9f, 0xc3, 0x80,
+                0x68, 0x86, 0x55, 0xfb, 0x2e, 0x6d, 0x96, 0xe1, 0xe1, 0xb7, 0x28, 0x8d, 0x63, 0x85,
+                0xba, 0x2a, 0x01, 0x33, 0x87, 0x60, 0x63, 0xbb, 0x16, 0x3f, 0x2f, 0x3d, 0xf4, 0x2d,
+                0x48, 0x5b, 0x87, 0xed, 0xda, 0x34, 0xeb, 0x9c, 0x4d, 0x14, 0xac, 0x65, 0xf4, 0xfa,
+                0xef, 0x45, 0x0b, 0x84, 0x43, 0xa1, 0x01, 0x27, 0xa0, 0x59, 0x01, 0x8f, 0xa9, 0x01,
+                0x78, 0x28, 0x32, 0x35, 0x39, 0x34, 0x38, 0x39, 0x65, 0x36, 0x39, 0x37, 0x34, 0x38,
+                0x37, 0x30, 0x35, 0x64, 0x65, 0x33, 0x65, 0x32, 0x66, 0x34, 0x34, 0x32, 0x36, 0x37,
+                0x65, 0x61, 0x34, 0x39, 0x33, 0x38, 0x66, 0x66, 0x36, 0x61, 0x35, 0x37, 0x32, 0x35,
+                0x02, 0x78, 0x28, 0x35, 0x64, 0x34, 0x65, 0x64, 0x37, 0x66, 0x34, 0x31, 0x37, 0x61,
+                0x39, 0x35, 0x34, 0x61, 0x31, 0x38, 0x31, 0x34, 0x30, 0x37, 0x62, 0x35, 0x38, 0x38,
+                0x35, 0x61, 0x66, 0x64, 0x37, 0x32, 0x61, 0x35, 0x62, 0x66, 0x34, 0x30, 0x64, 0x61,
+                0x36, 0x3a, 0x00, 0x47, 0x44, 0x50, 0x58, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                0x00, 0x00, 0x3a, 0x00, 0x47, 0x44, 0x53, 0x58, 0x1a, 0xa3, 0x3a, 0x00, 0x01, 0x11,
+                0x71, 0x67, 0x41, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x3a, 0x00, 0x01, 0x11, 0x72,
+                0x0c, 0x3a, 0x00, 0x01, 0x11, 0x73, 0xf6, 0x3a, 0x00, 0x47, 0x44, 0x52, 0x58, 0x40,
+                0x26, 0x1a, 0xbd, 0x26, 0xd8, 0x37, 0x8f, 0x4a, 0xf2, 0x9e, 0x49, 0x4d, 0x93, 0x23,
+                0xc4, 0x6e, 0x02, 0xda, 0xe0, 0x00, 0x02, 0xe7, 0xed, 0x29, 0xdf, 0x2b, 0xb3, 0x69,
+                0xf3, 0x55, 0x0e, 0x4c, 0x22, 0xdc, 0xcf, 0xf5, 0x92, 0xc9, 0xfa, 0x78, 0x98, 0xf1,
+                0x0e, 0x55, 0x5f, 0xf4, 0x45, 0xed, 0xc0, 0x0a, 0x72, 0x2a, 0x7a, 0x3a, 0xd2, 0xb1,
+                0xf7, 0x76, 0xfe, 0x2a, 0x6b, 0x7b, 0x2a, 0x53, 0x3a, 0x00, 0x47, 0x44, 0x54, 0x58,
+                0x40, 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, 0x3a, 0x00, 0x47, 0x44, 0x56,
+                0x41, 0x01, 0x3a, 0x00, 0x47, 0x44, 0x57, 0x58, 0x2d, 0xa5, 0x01, 0x01, 0x03, 0x27,
+                0x04, 0x81, 0x02, 0x20, 0x06, 0x21, 0x58, 0x20, 0xdb, 0xe7, 0x5b, 0x3f, 0xa3, 0x42,
+                0xb0, 0x9c, 0xf8, 0x40, 0x8c, 0xb0, 0x9c, 0xf0, 0x0a, 0xaf, 0xdf, 0x6f, 0xe5, 0x09,
+                0x21, 0x11, 0x92, 0xe1, 0xf8, 0xc5, 0x09, 0x02, 0x3d, 0x1f, 0xb7, 0xc5, 0x3a, 0x00,
+                0x47, 0x44, 0x58, 0x41, 0x20, 0x58, 0x40, 0xc4, 0xc1, 0xd7, 0x1c, 0x2d, 0x26, 0x89,
+                0x22, 0xcf, 0xa6, 0x99, 0x77, 0x30, 0x84, 0x86, 0x27, 0x59, 0x8f, 0xd8, 0x08, 0x75,
+                0xe0, 0xb2, 0xef, 0xf9, 0xfa, 0xa5, 0x40, 0x8c, 0xd3, 0xeb, 0xbb, 0xda, 0xf2, 0xc8,
+                0xae, 0x41, 0x22, 0x50, 0x9c, 0xe8, 0xb2, 0x9c, 0x9b, 0x3f, 0x8a, 0x78, 0x76, 0xab,
+                0xd0, 0xbe, 0xfc, 0xe4, 0x79, 0xcb, 0x1b, 0x2b, 0xaa, 0x4d, 0xdd, 0x15, 0x61, 0x42,
+                0x06, 0x84, 0x43, 0xa1, 0x01, 0x27, 0xa0, 0x59, 0x01, 0x8d, 0xa9, 0x01, 0x78, 0x28,
+                0x35, 0x64, 0x34, 0x65, 0x64, 0x37, 0x66, 0x34, 0x31, 0x37, 0x61, 0x39, 0x35, 0x34,
+                0x61, 0x31, 0x38, 0x31, 0x34, 0x30, 0x37, 0x62, 0x35, 0x38, 0x38, 0x35, 0x61, 0x66,
+                0x64, 0x37, 0x32, 0x61, 0x35, 0x62, 0x66, 0x34, 0x30, 0x64, 0x61, 0x36, 0x02, 0x78,
+                0x28, 0x36, 0x39, 0x62, 0x31, 0x37, 0x36, 0x37, 0x35, 0x38, 0x61, 0x36, 0x66, 0x34,
+                0x34, 0x62, 0x35, 0x65, 0x38, 0x39, 0x39, 0x63, 0x64, 0x65, 0x33, 0x63, 0x66, 0x34,
+                0x35, 0x31, 0x39, 0x61, 0x39, 0x33, 0x35, 0x62, 0x63, 0x39, 0x66, 0x65, 0x34, 0x3a,
+                0x00, 0x47, 0x44, 0x50, 0x58, 0x40, 0x31, 0x0d, 0x31, 0xfa, 0x78, 0x58, 0x33, 0xf2,
+                0xf8, 0x58, 0x6b, 0xe9, 0x68, 0x32, 0x44, 0xd0, 0xfc, 0x2d, 0xe1, 0xfc, 0xe1, 0xc2,
+                0x4e, 0x2b, 0xa8, 0x2c, 0xa1, 0xc1, 0x48, 0xc6, 0xaa, 0x91, 0x89, 0x4f, 0xb7, 0x9c,
+                0x40, 0x74, 0x21, 0x36, 0x31, 0x45, 0x09, 0xdf, 0x0c, 0xb4, 0xf9, 0x9a, 0x59, 0xae,
+                0x4f, 0x21, 0x10, 0xc1, 0x38, 0xa8, 0xa2, 0xbe, 0xc6, 0x36, 0xf0, 0x56, 0x58, 0xdb,
+                0x3a, 0x00, 0x47, 0x44, 0x53, 0x58, 0x18, 0xa2, 0x3a, 0x00, 0x01, 0x11, 0x71, 0x6b,
+                0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x20, 0x31, 0x3a, 0x00, 0x01,
+                0x11, 0x73, 0xf6, 0x3a, 0x00, 0x47, 0x44, 0x52, 0x58, 0x40, 0xce, 0x8a, 0x30, 0x4e,
+                0x31, 0x53, 0xea, 0xdd, 0x2f, 0xbd, 0x15, 0xbc, 0x6b, 0x0f, 0xe7, 0x43, 0x50, 0xef,
+                0x65, 0xec, 0x4e, 0x21, 0x64, 0x6e, 0x41, 0x22, 0xac, 0x87, 0xda, 0xf1, 0xf2, 0x80,
+                0xc6, 0x8a, 0xd8, 0x7b, 0xe8, 0xe2, 0x9b, 0x87, 0x21, 0x5e, 0x26, 0x23, 0x11, 0x89,
+                0x86, 0x57, 0x2d, 0x47, 0x73, 0x3f, 0x47, 0x87, 0xfa, 0x58, 0x5c, 0x78, 0x7b, 0xa3,
+                0xfc, 0x2b, 0x6c, 0xed, 0x3a, 0x00, 0x47, 0x44, 0x54, 0x58, 0x40, 0xd8, 0x40, 0xa0,
+                0x60, 0x45, 0x28, 0x5d, 0xd4, 0xc1, 0x08, 0x3c, 0xbc, 0x91, 0xf4, 0xa6, 0xa4, 0xde,
+                0xd3, 0x3d, 0xbb, 0x24, 0x46, 0xa3, 0x58, 0x49, 0x57, 0x4d, 0x2e, 0x6d, 0x7a, 0x78,
+                0x4b, 0x9d, 0x28, 0x9a, 0x4e, 0xf1, 0x23, 0x06, 0x35, 0xff, 0x8e, 0x1e, 0xb3, 0x02,
+                0x63, 0x62, 0x9a, 0x50, 0x6d, 0x18, 0x70, 0x8e, 0xe3, 0x2e, 0x29, 0xb4, 0x22, 0x71,
+                0x31, 0x39, 0x65, 0xd5, 0xb5, 0x3a, 0x00, 0x47, 0x44, 0x56, 0x41, 0x01, 0x3a, 0x00,
+                0x47, 0x44, 0x57, 0x58, 0x2d, 0xa5, 0x01, 0x01, 0x03, 0x27, 0x04, 0x81, 0x02, 0x20,
+                0x06, 0x21, 0x58, 0x20, 0x51, 0x3c, 0x4b, 0x56, 0x0b, 0x49, 0x0b, 0xee, 0xc5, 0x71,
+                0xd4, 0xe7, 0xbc, 0x44, 0x27, 0x4f, 0x4e, 0x67, 0xfc, 0x3a, 0xb9, 0x47, 0x8c, 0x6f,
+                0x24, 0x29, 0xf8, 0xb8, 0x2f, 0xa7, 0xb3, 0x4d, 0x3a, 0x00, 0x47, 0x44, 0x58, 0x41,
+                0x20, 0x58, 0x40, 0x4e, 0x6d, 0x0e, 0x2b, 0x1d, 0x44, 0x99, 0xb6, 0x63, 0x07, 0x86,
+                0x1a, 0xce, 0x4b, 0xdc, 0xd1, 0x3a, 0xdc, 0xbf, 0xaa, 0xb3, 0x06, 0xd9, 0xb5, 0x5c,
+                0x75, 0xf0, 0x14, 0x63, 0xa9, 0x1e, 0x7c, 0x56, 0x62, 0x2c, 0xa5, 0xda, 0xc9, 0x81,
+                0xcb, 0x3d, 0x63, 0x32, 0x6b, 0x76, 0x81, 0xd2, 0x93, 0xeb, 0xac, 0xfe, 0x0c, 0x87,
+                0x66, 0x9e, 0x87, 0x82, 0xb4, 0x81, 0x6e, 0x33, 0xf1, 0x08, 0x01, 0x84, 0x43, 0xa1,
+                0x01, 0x27, 0xa0, 0x59, 0x01, 0x8d, 0xa9, 0x01, 0x78, 0x28, 0x36, 0x39, 0x62, 0x31,
+                0x37, 0x36, 0x37, 0x35, 0x38, 0x61, 0x36, 0x66, 0x34, 0x34, 0x62, 0x35, 0x65, 0x38,
+                0x39, 0x39, 0x63, 0x64, 0x65, 0x33, 0x63, 0x66, 0x34, 0x35, 0x31, 0x39, 0x61, 0x39,
+                0x33, 0x35, 0x62, 0x63, 0x39, 0x66, 0x65, 0x34, 0x02, 0x78, 0x28, 0x32, 0x39, 0x65,
+                0x34, 0x62, 0x61, 0x63, 0x33, 0x30, 0x31, 0x65, 0x66, 0x36, 0x35, 0x61, 0x38, 0x31,
+                0x31, 0x62, 0x39, 0x39, 0x62, 0x30, 0x33, 0x64, 0x65, 0x39, 0x35, 0x34, 0x65, 0x61,
+                0x37, 0x36, 0x61, 0x38, 0x39, 0x31, 0x37, 0x38, 0x35, 0x3a, 0x00, 0x47, 0x44, 0x50,
+                0x58, 0x40, 0xa4, 0x03, 0xe3, 0xde, 0x44, 0x96, 0xed, 0x31, 0x41, 0xa0, 0xba, 0x59,
+                0xee, 0x2b, 0x03, 0x65, 0xcb, 0x63, 0x14, 0x78, 0xbe, 0xad, 0x24, 0x33, 0xb8, 0x6b,
+                0x52, 0xd8, 0xab, 0xd5, 0x79, 0x84, 0x98, 0x6c, 0xc2, 0x66, 0xeb, 0x6c, 0x24, 0xa6,
+                0xfa, 0x32, 0xa8, 0x16, 0xb8, 0x64, 0x37, 0x2b, 0xd4, 0xc0, 0xc4, 0xc2, 0x63, 0x25,
+                0x10, 0xce, 0x47, 0xe3, 0x49, 0xad, 0x41, 0xf5, 0xc8, 0xf6, 0x3a, 0x00, 0x47, 0x44,
+                0x53, 0x58, 0x18, 0xa2, 0x3a, 0x00, 0x01, 0x11, 0x71, 0x6b, 0x63, 0x6f, 0x6d, 0x70,
+                0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x20, 0x32, 0x3a, 0x00, 0x01, 0x11, 0x73, 0xf6, 0x3a,
+                0x00, 0x47, 0x44, 0x52, 0x58, 0x40, 0xc7, 0x50, 0x09, 0xd0, 0xe0, 0xdd, 0x80, 0x77,
+                0xae, 0xa7, 0xc8, 0x88, 0x1e, 0x88, 0xd0, 0xc7, 0x0d, 0x7c, 0x49, 0xc5, 0xb5, 0x64,
+                0x32, 0x28, 0x2c, 0x48, 0x94, 0xc0, 0xd6, 0x7d, 0x9c, 0x86, 0xda, 0xf7, 0x98, 0xc7,
+                0xae, 0xa4, 0x0e, 0x61, 0xc8, 0xb0, 0x8b, 0x8a, 0xe4, 0xad, 0xcf, 0xcf, 0x6d, 0x60,
+                0x60, 0x31, 0xdd, 0xa7, 0x24, 0x9b, 0x27, 0x16, 0x31, 0x90, 0x80, 0x70, 0xc3, 0xba,
+                0x3a, 0x00, 0x47, 0x44, 0x54, 0x58, 0x40, 0xf8, 0x86, 0xc6, 0x94, 0xf9, 0x3f, 0x66,
+                0x3c, 0x43, 0x01, 0x29, 0x27, 0x8d, 0x3c, 0xb2, 0x11, 0xf2, 0x04, 0xb6, 0x67, 0x4f,
+                0x5f, 0x90, 0xcb, 0xc6, 0x73, 0xe6, 0x25, 0x14, 0x63, 0xa7, 0x95, 0x11, 0x0e, 0xa0,
+                0x1d, 0x3f, 0x6a, 0x58, 0x0a, 0x53, 0xaa, 0x68, 0x3b, 0x92, 0x64, 0x2b, 0x2e, 0x79,
+                0x80, 0x70, 0x0e, 0x41, 0xf5, 0xe9, 0x2a, 0x36, 0x0a, 0xa4, 0xe8, 0xb4, 0xe5, 0xdd,
+                0xa6, 0x3a, 0x00, 0x47, 0x44, 0x56, 0x41, 0x01, 0x3a, 0x00, 0x47, 0x44, 0x57, 0x58,
+                0x2d, 0xa5, 0x01, 0x01, 0x03, 0x27, 0x04, 0x81, 0x02, 0x20, 0x06, 0x21, 0x58, 0x20,
+                0x9e, 0x04, 0x11, 0x24, 0x34, 0xba, 0x40, 0xed, 0x86, 0xe9, 0x48, 0x70, 0x3b, 0xe7,
+                0x76, 0xfa, 0xc5, 0xf6, 0x6d, 0xab, 0x86, 0x12, 0x00, 0xbe, 0xc7, 0x00, 0x69, 0x0e,
+                0x97, 0x97, 0xa6, 0x12, 0x3a, 0x00, 0x47, 0x44, 0x58, 0x41, 0x20, 0x58, 0x40, 0xb7,
+                0x31, 0xd5, 0x4c, 0x7d, 0xf5, 0xd7, 0xb8, 0xb4, 0x4f, 0x93, 0x47, 0x2c, 0x3d, 0x50,
+                0xcc, 0xad, 0x28, 0x23, 0x68, 0xcf, 0xc2, 0x90, 0xd7, 0x02, 0x00, 0xd8, 0xf1, 0x00,
+                0x14, 0x03, 0x90, 0x9e, 0x0b, 0x91, 0xa7, 0x22, 0x28, 0xfe, 0x55, 0x42, 0x30, 0x93,
+                0x05, 0x66, 0xcd, 0xce, 0xb8, 0x48, 0x07, 0x56, 0x54, 0x67, 0xa5, 0xd7, 0xe3, 0x16,
+                0xd6, 0x75, 0x7c, 0x94, 0x98, 0x1b, 0x0b, 0x84, 0x43, 0xa1, 0x01, 0x27, 0xa0, 0x59,
+                0x01, 0x8d, 0xa9, 0x01, 0x78, 0x28, 0x32, 0x39, 0x65, 0x34, 0x62, 0x61, 0x63, 0x33,
+                0x30, 0x31, 0x65, 0x66, 0x36, 0x35, 0x61, 0x38, 0x31, 0x31, 0x62, 0x39, 0x39, 0x62,
+                0x30, 0x33, 0x64, 0x65, 0x39, 0x35, 0x34, 0x65, 0x61, 0x37, 0x36, 0x61, 0x38, 0x39,
+                0x31, 0x37, 0x38, 0x35, 0x02, 0x78, 0x28, 0x31, 0x38, 0x37, 0x36, 0x63, 0x61, 0x63,
+                0x34, 0x32, 0x33, 0x39, 0x35, 0x37, 0x66, 0x33, 0x62, 0x66, 0x62, 0x32, 0x62, 0x32,
+                0x63, 0x39, 0x33, 0x37, 0x64, 0x31, 0x34, 0x62, 0x62, 0x38, 0x30, 0x64, 0x30, 0x36,
+                0x37, 0x33, 0x65, 0x66, 0x66, 0x3a, 0x00, 0x47, 0x44, 0x50, 0x58, 0x40, 0xf4, 0x7d,
+                0x11, 0x21, 0xc1, 0x19, 0x57, 0x23, 0x08, 0x6e, 0x5f, 0xe4, 0x55, 0xc5, 0x08, 0x16,
+                0x40, 0x5f, 0x2a, 0x6f, 0x04, 0x1e, 0x6f, 0x22, 0xde, 0x53, 0xbd, 0x37, 0xe2, 0xfb,
+                0xb4, 0x0b, 0x65, 0xf4, 0xdc, 0xc9, 0xf4, 0xce, 0x2d, 0x82, 0x2a, 0xbc, 0xaf, 0x37,
+                0x80, 0x0b, 0x7f, 0xff, 0x3a, 0x98, 0x9c, 0xa7, 0x70, 0x4f, 0xbc, 0x59, 0x4f, 0x4e,
+                0xb1, 0x6d, 0xdf, 0x60, 0x39, 0x11, 0x3a, 0x00, 0x47, 0x44, 0x53, 0x58, 0x18, 0xa2,
+                0x3a, 0x00, 0x01, 0x11, 0x71, 0x6b, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e,
+                0x74, 0x20, 0x33, 0x3a, 0x00, 0x01, 0x11, 0x73, 0xf6, 0x3a, 0x00, 0x47, 0x44, 0x52,
+                0x58, 0x40, 0xa4, 0xd5, 0x6f, 0xc8, 0xd6, 0xc7, 0xe4, 0x22, 0xb4, 0x7a, 0x26, 0x49,
+                0xd5, 0xb4, 0xc1, 0xc6, 0x1b, 0xfa, 0x14, 0x8c, 0x49, 0x72, 0x2f, 0xfe, 0xbc, 0xc1,
+                0xc8, 0xc6, 0x65, 0x62, 0x86, 0xf7, 0xf2, 0x74, 0x45, 0x9b, 0x1a, 0xa0, 0x2b, 0xc4,
+                0x27, 0x13, 0xc5, 0xc3, 0xe5, 0x28, 0xc2, 0x16, 0xcd, 0x90, 0x6d, 0xa0, 0xf7, 0x27,
+                0x04, 0xa8, 0xa2, 0x62, 0xaa, 0x2c, 0x0c, 0x75, 0xd5, 0x9d, 0x3a, 0x00, 0x47, 0x44,
+                0x54, 0x58, 0x40, 0x1d, 0x92, 0x34, 0xfb, 0xfe, 0x74, 0xb7, 0xce, 0x3a, 0x95, 0x45,
+                0xe5, 0x3e, 0x1f, 0x5f, 0x18, 0x53, 0x5f, 0xe1, 0x85, 0xb0, 0x1d, 0xe3, 0x8d, 0x53,
+                0x77, 0xdc, 0x86, 0x32, 0x3d, 0x9b, 0xf9, 0xa5, 0x51, 0x17, 0x51, 0x9a, 0xd8, 0xa6,
+                0x7d, 0x45, 0x98, 0x47, 0xa2, 0x73, 0x54, 0x66, 0x28, 0x66, 0x92, 0x1d, 0x28, 0x8a,
+                0xe7, 0x5d, 0xb8, 0x96, 0x4b, 0x6a, 0x9d, 0xee, 0xc2, 0xe9, 0x20, 0x3a, 0x00, 0x47,
+                0x44, 0x56, 0x41, 0x01, 0x3a, 0x00, 0x47, 0x44, 0x57, 0x58, 0x2d, 0xa5, 0x01, 0x01,
+                0x03, 0x27, 0x04, 0x81, 0x02, 0x20, 0x06, 0x21, 0x58, 0x20, 0x4d, 0xf5, 0x61, 0x1e,
+                0xa6, 0x64, 0x74, 0x0b, 0x6c, 0x99, 0x8b, 0x6d, 0x34, 0x42, 0x21, 0xdd, 0x82, 0x26,
+                0x13, 0xb4, 0xf0, 0xbc, 0x9a, 0x0b, 0xf6, 0x56, 0xbd, 0x5d, 0xea, 0xd5, 0x07, 0x7a,
+                0x3a, 0x00, 0x47, 0x44, 0x58, 0x41, 0x20, 0x58, 0x40, 0x40, 0x4d, 0x09, 0x0d, 0x80,
+                0xba, 0x12, 0x94, 0x05, 0xfb, 0x1a, 0x23, 0xa3, 0xcb, 0x28, 0x6f, 0xd7, 0x29, 0x95,
+                0xda, 0x83, 0x07, 0x3c, 0xbe, 0x7c, 0x37, 0xeb, 0x9c, 0xb2, 0x77, 0x10, 0x3f, 0x6a,
+                0x41, 0x80, 0xce, 0x56, 0xb7, 0x55, 0x22, 0x81, 0x77, 0x2d, 0x3c, 0xf8, 0x16, 0x38,
+                0x49, 0xcc, 0x9a, 0xe8, 0x3a, 0x03, 0x33, 0x4c, 0xe6, 0x87, 0x72, 0xf6, 0x5a, 0x4a,
+                0x3f, 0x4e, 0x0a,
+            ],
+        )
+        .unwrap()
+    }
+}
diff --git a/diced/src/lib.rs b/diced/src/lib.rs
new file mode 100644
index 0000000..8562406
--- /dev/null
+++ b/diced/src/lib.rs
@@ -0,0 +1,203 @@
+// 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 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,
+    InputValues::InputValues as BinderInputValues, Mode::Mode, Signature::Signature,
+};
+use android_security_dice::aidl::android::security::dice::{
+    IDiceMaintenance::BnDiceMaintenance, IDiceMaintenance::IDiceMaintenance, 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 keystore2_selinux as selinux;
+use libc::uid_t;
+use permission::Permission;
+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>,
+}
+
+/// This function uses its namesake in the permission module and in
+/// combination with with_calling_sid from the binder crate to check
+/// if the caller has the given keystore permission.
+pub fn check_caller_permission<T: selinux::ClassPermission>(perm: T) -> Result<()> {
+    ThreadState::with_calling_sid(|calling_sid| {
+        let target_context =
+            selinux::getcon().context("In check_caller_permission: getcon failed.")?;
+
+        selinux::check_permission(
+            calling_sid.ok_or(Error::Rc(ResponseCode::SYSTEM_ERROR)).context(
+                "In check_keystore_permission: Cannot check permission without calling_sid.",
+            )?,
+            &target_context,
+            perm,
+        )
+    })
+}
+
+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> {
+        check_caller_permission(Permission::UseSign).context("In DiceNode::sign:")?;
+        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> {
+        check_caller_permission(Permission::GetAttestationChain)
+            .context("In DiceNode::get_attestation_chain:")?;
+        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> {
+        check_caller_permission(Permission::Derive).context("In DiceNode::derive:")?;
+        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<()> {
+        check_caller_permission(Permission::Demote).context("In DiceNode::demote:")?;
+        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)
+    }
+}
+
+/// Wraps a DiceNodeImpl and implements the IDiceMaintenance AIDL API.
+pub struct DiceMaintenance {
+    node_impl: Arc<dyn DiceNodeImpl + Sync + Send>,
+}
+
+impl DiceMaintenance {
+    /// Constructs an instance of DiceMaintenance, wraps it with a BnDiceMaintenance 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 IDiceMaintenance>> {
+        let result = BnDiceMaintenance::new_binder(
+            DiceMaintenance { node_impl },
+            BinderFeatures { set_requesting_sid: true, ..BinderFeatures::default() },
+        );
+        Ok(result)
+    }
+
+    fn demote_self(&self, input_values: &[BinderInputValues]) -> Result<()> {
+        check_caller_permission(Permission::DemoteSelf)
+            .context("In DiceMaintenance::demote_self:")?;
+        self.node_impl.demote_self(input_values)
+    }
+}
+
+impl binder::Interface for DiceMaintenance {}
+
+impl IDiceMaintenance for DiceMaintenance {
+    fn demoteSelf(&self, input_values: &[BinderInputValues]) -> BinderResult<()> {
+        map_or_log_err(self.demote_self(input_values), Ok)
+    }
+}
diff --git a/diced/src/lib_vendor.rs b/diced/src/lib_vendor.rs
new file mode 100644
index 0000000..01c804b
--- /dev/null
+++ b/diced/src/lib_vendor.rs
@@ -0,0 +1,20 @@
+// 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 crate implements the android.hardware.security.dice.IDiceDevice interface
+//! and provides support for implementing a DICE HAL service.
+
+mod error_vendor;
+pub mod hal_node;
+pub use diced_open_dice_cbor as dice;
diff --git a/diced/src/permission.rs b/diced/src/permission.rs
new file mode 100644
index 0000000..116df1b
--- /dev/null
+++ b/diced/src/permission.rs
@@ -0,0 +1,46 @@
+// 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 crate provides convenience wrappers for the SELinux permission
+//! defined in the diced SELinux access class.
+
+use keystore2_selinux as selinux;
+use selinux::{implement_class, ClassPermission};
+
+implement_class!(
+    /// Permission provides a convenient abstraction from the SELinux class `diced`.
+    #[selinux(class_name = diced)]
+    #[derive(Clone, Copy, Debug, PartialEq)]
+    pub enum Permission {
+        /// Checked when a client attempts to call seal or unseal.
+        #[selinux(name = use_seal)]
+        UseSeal,
+        /// Checked when a client attempts to call IDiceNode::sign.
+        #[selinux(name = use_sign)]
+        UseSign,
+        /// Checked when a client attempts to call IDiceNode::getAttestationChain.
+        #[selinux(name = get_attestation_chain)]
+        GetAttestationChain,
+        /// Checked when a client attempts to call IDiceNode::derive.
+        #[selinux(name = derive)]
+        Derive,
+        /// Checked when a client wants to demote itself by calling IDiceNode::demote.
+        #[selinux(name = demote)]
+        Demote,
+        /// Checked when a client calls IDiceMaintenance::demote in an attempt to
+        /// demote this dice node.
+        #[selinux(name = demote_self)]
+        DemoteSelf,
+    }
+);
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:")
+    }
+}
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..3d3db55
--- /dev/null
+++ b/diced/src/utils.rs
@@ -0,0 +1,497 @@
+// 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(),
+        })
+    }
+
+    /// Creates a ResidentArtifacts object from another one implementing the DiceArtifacts
+    /// trait. Like `new` this function can only create artifacts of appropriate size
+    /// because DiceArtifacts returns array references of appropriate size.
+    pub fn new_from<T: DiceArtifacts + ?Sized>(artifacts: &T) -> Result<Self> {
+        Ok(ResidentArtifacts {
+            cdi_attest: artifacts.cdi_attest()[..].try_into()?,
+            cdi_seal: artifacts.cdi_seal()[..].try_into()?,
+            bcc: artifacts.bcc(),
+        })
+    }
+
+    /// 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:")
+    }
+}
+
+/// An object that implements this trait provides the typical DICE artifacts.
+/// CDI_ATTEST, CDI_SEAL, and a certificate chain up to the public key that
+/// can be derived from CDI_ATTEST. Implementations should check the length of
+/// the stored CDI_* secrets on creation so that any valid instance returns the
+/// correct secrets in an infallible way.
+pub trait DiceArtifacts {
+    /// Returns CDI_ATTEST.
+    fn cdi_attest(&self) -> &[u8; dice::CDI_SIZE];
+    /// Returns CDI_SEAL.
+    fn cdi_seal(&self) -> &[u8; dice::CDI_SIZE];
+    /// Returns the attestation certificate chain in BCC format.
+    fn bcc(&self) -> Vec<u8>;
+}
+
+/// Implement this trait to provide read and write access to a secure artifact
+/// storage that can be used by the ResidentHal implementation.
+pub trait UpdatableDiceArtifacts {
+    /// With artifacts provides access to the stored artifacts for the duration
+    /// of the function call by means of calling the callback.
+    fn with_artifacts<F, T>(&self, f: F) -> Result<T>
+    where
+        F: FnOnce(&dyn DiceArtifacts) -> Result<T>;
+
+    /// Consumes the object and returns a an updated version of itself.
+    fn update(self, new_artifacts: &impl DiceArtifacts) -> Result<Self>
+    where
+        Self: Sized;
+}
+
+impl DiceArtifacts for ResidentArtifacts {
+    fn cdi_attest(&self) -> &[u8; dice::CDI_SIZE] {
+        self.cdi_attest[..].try_into().unwrap()
+    }
+    fn cdi_seal(&self) -> &[u8; dice::CDI_SIZE] {
+        self.cdi_seal[..].try_into().unwrap()
+    }
+    fn bcc(&self) -> Vec<u8> {
+        self.bcc.clone()
+    }
+}
+
+/// 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.");
+    }
+}
diff --git a/fsverity/Android.bp b/fsverity/Android.bp
index 5fb38ae..5c3d6a0 100644
--- a/fsverity/Android.bp
+++ b/fsverity/Android.bp
@@ -41,3 +41,15 @@
         },
     },
 }
+
+rust_protobuf {
+    name: "libfsverity_digests_proto_rust",
+    crate_name: "fsverity_digests_proto",
+    source_stem: "fsverity_digests_proto",
+    protos: [
+        "fsverity_digests.proto",
+    ],
+    apex_available: [
+        "com.android.compos",
+    ],
+}
diff --git a/keystore2/src/crypto/Android.bp b/keystore2/src/crypto/Android.bp
index 4e76507..76c02c5 100644
--- a/keystore2/src/crypto/Android.bp
+++ b/keystore2/src/crypto/Android.bp
@@ -35,6 +35,7 @@
         "libkeystore2_crypto",
         "libcrypto",
     ],
+    vendor_available: true,
 }
 
 cc_library {
@@ -48,6 +49,7 @@
         "libcrypto",
         "liblog",
     ],
+    vendor_available: true,
 }
 
 rust_bindgen {
@@ -56,6 +58,7 @@
     crate_name: "keystore2_crypto_bindgen",
     source_stem: "bindings",
     host_supported: true,
+    vendor_available: true,
     shared_libs: ["libcrypto"],
     bindgen_flags: [
         "--size_t-is-usize",
diff --git a/keystore2/src/database.rs b/keystore2/src/database.rs
index d73cc8b..7099f5a 100644
--- a/keystore2/src/database.rs
+++ b/keystore2/src/database.rs
@@ -45,6 +45,7 @@
 pub(crate) mod utils;
 mod versioning;
 
+use crate::gc::Gc;
 use crate::impl_metadata; // This is in db_utils.rs
 use crate::key_parameter::{KeyParameter, Tag};
 use crate::metrics_store::log_rkp_error_stats;
@@ -54,7 +55,6 @@
     error::{Error as KsError, ErrorCode, ResponseCode},
     super_key::SuperKeyType,
 };
-use crate::{gc::Gc, super_key::USER_SUPER_KEY};
 use anyhow::{anyhow, Context, Result};
 use std::{convert::TryFrom, convert::TryInto, ops::Deref, time::SystemTimeError};
 use utils as db_utils;
@@ -2895,7 +2895,6 @@
                      ) OR (
                          key_type = ?
                          AND namespace = ?
-                         AND alias = ?
                          AND state = ?
                      );",
                     aid_user_offset = AID_USER_OFFSET
@@ -2915,7 +2914,6 @@
                     // OR super key:
                     KeyType::Super,
                     user_id,
-                    USER_SUPER_KEY.alias,
                     KeyLifeCycle::Live
                 ])
                 .context("In unbind_keys_for_user. Failed to query the keys created by apps.")?;
@@ -3218,7 +3216,7 @@
     };
     use crate::key_perm_set;
     use crate::permission::{KeyPerm, KeyPermSet};
-    use crate::super_key::SuperKeyManager;
+    use crate::super_key::{SuperKeyManager, USER_SUPER_KEY, SuperEncryptionAlgorithm, SuperKeyType};
     use keystore2_test_utils::TempDir;
     use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
         HardwareAuthToken::HardwareAuthToken,
@@ -5456,6 +5454,80 @@
     }
 
     #[test]
+    fn test_unbind_keys_for_user_removes_superkeys() -> Result<()> {
+        let mut db = new_test_db()?;
+        let super_key = keystore2_crypto::generate_aes256_key()?;
+        let pw: keystore2_crypto::Password = (&b"xyzabc"[..]).into();
+        let (encrypted_super_key, metadata) =
+            SuperKeyManager::encrypt_with_password(&super_key, &pw)?;
+
+        let key_name_enc = SuperKeyType {
+            alias: "test_super_key_1",
+            algorithm: SuperEncryptionAlgorithm::Aes256Gcm,
+        };
+
+        let key_name_nonenc = SuperKeyType {
+            alias: "test_super_key_2",
+            algorithm: SuperEncryptionAlgorithm::Aes256Gcm,
+        };
+
+        // Install two super keys.
+        db.store_super_key(
+            1,
+            &key_name_nonenc,
+            &super_key,
+            &BlobMetaData::new(),
+            &KeyMetaData::new(),
+        )?;
+        db.store_super_key(1, &key_name_enc, &encrypted_super_key, &metadata, &KeyMetaData::new())?;
+
+        // Check that both can be found in the database.
+        assert!(db.load_super_key(&key_name_enc, 1)?.is_some());
+        assert!(db.load_super_key(&key_name_nonenc, 1)?.is_some());
+
+        // Install the same keys for a different user.
+        db.store_super_key(
+            2,
+            &key_name_nonenc,
+            &super_key,
+            &BlobMetaData::new(),
+            &KeyMetaData::new(),
+        )?;
+        db.store_super_key(2, &key_name_enc, &encrypted_super_key, &metadata, &KeyMetaData::new())?;
+
+        // Check that the second pair of keys can be found in the database.
+        assert!(db.load_super_key(&key_name_enc, 2)?.is_some());
+        assert!(db.load_super_key(&key_name_nonenc, 2)?.is_some());
+
+        // Delete only encrypted keys.
+        db.unbind_keys_for_user(1, true)?;
+
+        // The encrypted superkey should be gone now.
+        assert!(db.load_super_key(&key_name_enc, 1)?.is_none());
+        assert!(db.load_super_key(&key_name_nonenc, 1)?.is_some());
+
+        // Reinsert the encrypted key.
+        db.store_super_key(1, &key_name_enc, &encrypted_super_key, &metadata, &KeyMetaData::new())?;
+
+        // Check that both can be found in the database, again..
+        assert!(db.load_super_key(&key_name_enc, 1)?.is_some());
+        assert!(db.load_super_key(&key_name_nonenc, 1)?.is_some());
+
+        // Delete all even unencrypted keys.
+        db.unbind_keys_for_user(1, false)?;
+
+        // Both should be gone now.
+        assert!(db.load_super_key(&key_name_enc, 1)?.is_none());
+        assert!(db.load_super_key(&key_name_nonenc, 1)?.is_none());
+
+        // Check that the second pair of keys was untouched.
+        assert!(db.load_super_key(&key_name_enc, 2)?.is_some());
+        assert!(db.load_super_key(&key_name_nonenc, 2)?.is_some());
+
+        Ok(())
+    }
+
+    #[test]
     fn test_store_super_key() -> Result<()> {
         let mut db = new_test_db()?;
         let pw: keystore2_crypto::Password = (&b"xyzabc"[..]).into();
@@ -5474,7 +5546,7 @@
             &KeyMetaData::new(),
         )?;
 
-        //check if super key exists
+        // Check if super key exists.
         assert!(db.key_exists(Domain::APP, 1, USER_SUPER_KEY.alias, KeyType::Super)?);
 
         let (_, key_entry) = db.load_super_key(&USER_SUPER_KEY, 1)?.unwrap();
@@ -5488,6 +5560,7 @@
         let decrypted_secret_bytes =
             loaded_super_key.aes_gcm_decrypt(&encrypted_secret, &iv, &tag)?;
         assert_eq!(secret_bytes, &*decrypted_secret_bytes);
+
         Ok(())
     }
 
diff --git a/keystore2/src/super_key.rs b/keystore2/src/super_key.rs
index a1e4c48..ca5e593 100644
--- a/keystore2/src/super_key.rs
+++ b/keystore2/src/super_key.rs
@@ -75,9 +75,9 @@
 /// A particular user may have several superencryption keys in the database, each for a
 /// different purpose, distinguished by alias. Each is associated with a static
 /// constant of this type.
-pub struct SuperKeyType {
+pub struct SuperKeyType<'a> {
     /// Alias used to look the key up in the `persistent.keyentry` table.
-    pub alias: &'static str,
+    pub alias: &'a str,
     /// Encryption algorithm
     pub algorithm: SuperEncryptionAlgorithm,
 }
diff --git a/ondevice-signing/VerityUtils.cpp b/ondevice-signing/VerityUtils.cpp
index 47cba00..24a46b9 100644
--- a/ondevice-signing/VerityUtils.cpp
+++ b/ondevice-signing/VerityUtils.cpp
@@ -283,9 +283,10 @@
 }
 
 Result<void> verifyAllFilesUsingCompOs(const std::string& directory_path,
-                                       std::map<std::string, std::string> digests,
+                                       const std::map<std::string, std::string>& digests,
                                        const SigningKey& signing_key) {
     std::error_code ec;
+    size_t verified_count = 0;
     auto it = std::filesystem::recursive_directory_iterator(directory_path, ec);
     for (auto end = std::filesystem::recursive_directory_iterator(); it != end; it.increment(ec)) {
         auto& path = it->path();
@@ -305,7 +306,9 @@
             if (verity_digest.ok()) {
                 // The file is already in fs-verity. We need to make sure it was signed
                 // by CompOS, so we just check that it has the digest we expect.
-                if (verity_digest.value() != compos_digest) {
+                if (verity_digest.value() == compos_digest) {
+                    ++verified_count;
+                } else {
                     return Error() << "fs-verity digest does not match CompOS digest: " << path;
                 }
             } else {
@@ -333,6 +336,7 @@
                 if (!enabled.ok()) {
                     return Error() << enabled.error();
                 }
+                ++verified_count;
             }
         } else if (it->is_directory()) {
             // These are fine to ignore
@@ -346,6 +350,12 @@
         return Error() << "Failed to iterate " << directory_path << ": " << ec.message();
     }
 
+    // Make sure all the files we expected have been seen
+    if (verified_count != digests.size()) {
+        return Error() << "Verified " << verified_count << " files, but expected "
+                       << digests.size();
+    }
+
     return {};
 }
 
diff --git a/ondevice-signing/include/VerityUtils.h b/ondevice-signing/include/VerityUtils.h
index 7715628..0559c35 100644
--- a/ondevice-signing/include/VerityUtils.h
+++ b/ondevice-signing/include/VerityUtils.h
@@ -34,6 +34,7 @@
 android::base::Result<std::map<std::string, std::string>>
 addFilesToVerityRecursive(const std::string& path, const SigningKey& key);
 
-android::base::Result<void> verifyAllFilesUsingCompOs(const std::string& directory_path,
-                                                      std::map<std::string, std::string> digests,
-                                                      const SigningKey& signing_key);
+android::base::Result<void>
+verifyAllFilesUsingCompOs(const std::string& directory_path,
+                          const std::map<std::string, std::string>& digests,
+                          const SigningKey& signing_key);
diff --git a/ondevice-signing/odsign_main.cpp b/ondevice-signing/odsign_main.cpp
index 0433a3e..a324857 100644
--- a/ondevice-signing/odsign_main.cpp
+++ b/ondevice-signing/odsign_main.cpp
@@ -39,7 +39,6 @@
 
 using android::base::ErrnoError;
 using android::base::Error;
-using android::base::GetProperty;
 using android::base::Result;
 using android::base::SetProperty;
 
@@ -149,11 +148,6 @@
     return access(kCompOsVerifyPath, X_OK) == 0 && access(kKvmDevicePath, F_OK) == 0;
 }
 
-bool isDebugBuild() {
-    std::string build_type = GetProperty("ro.build.type", "");
-    return build_type == "userdebug" || build_type == "eng";
-}
-
 Result<void> verifyExistingRootCert(const SigningKey& key) {
     if (access(kSigningKeyCert.c_str(), F_OK) < 0) {
         return ErrnoError() << "Key certificate not found: " << kSigningKeyCert;
@@ -531,43 +525,46 @@
         return art::odrefresh::ExitCode::kCompilationRequired;
     }
 
-    // Read the CompOS signature before checking, otherwise odrefresh will delete it
-    // (And there's no point checking the artifacts if we don't have a valid signature.)
+    // Make sure the artifacts we have are genuinely produced by the current
+    // instance of CompOS.
     auto compos_info = getComposInfo(compos_key);
     if (!compos_info.ok()) {
         LOG(WARNING) << compos_info.error();
     } else {
-        odrefresh_status = checkArtifacts();
-        if (odrefresh_status != art::odrefresh::ExitCode::kOkay) {
-            LOG(WARNING) << "Pending artifacts are not OK";
-            return odrefresh_status;
-        }
-
-        // The artifacts appear to be up to date - but we haven't
-        // verified that they are genuine yet.
-
         std::map<std::string, std::string> compos_digests(compos_info->file_hashes().begin(),
                                                           compos_info->file_hashes().end());
 
         auto status = verifyAllFilesUsingCompOs(kArtArtifactsDir, compos_digests, signing_key);
         if (!status.ok()) {
-            LOG(WARNING) << status.error();
+            LOG(WARNING) << "Faild to verify CompOS artifacts: " << status.error();
         } else {
-            auto persisted = persistDigests(compos_digests, signing_key);
-
-            if (!persisted.ok()) {
-                LOG(WARNING) << persisted.error();
-            } else {
-                LOG(INFO) << "Pending artifacts successfully verified.";
+            LOG(INFO) << "CompOS artifacts successfully verified.";
+            odrefresh_status = checkArtifacts();
+            if (odrefresh_status == art::odrefresh::ExitCode::kOkay) {
+                // We have digests of all the files, and they aren't going to change, so
+                // we can just sign them & save them now, and skip checking them later.
+                auto persisted = persistDigests(compos_digests, signing_key);
+                if (!persisted.ok()) {
+                    LOG(ERROR) << persisted.error();
+                    // Don't try to compile again - if we can't write the digests, things
+                    // are pretty bad.
+                    return art::odrefresh::ExitCode::kCleanupFailed;
+                }
+                LOG(INFO) << "Persisted CompOS digests.";
                 *digests_verified = true;
-                return art::odrefresh::ExitCode::kOkay;
             }
+            return odrefresh_status;
         }
     }
 
     // We can't use the existing artifacts, so we will need to generate new
     // ones.
-    removeDirectory(kArtArtifactsDir);
+    if (removeDirectory(kArtArtifactsDir) == 0) {
+        // We have unsigned artifacts that we can't delete, so it's not safe to continue.
+        LOG(ERROR) << "Unable to delete invalid CompOS artifacts";
+        return art::odrefresh::ExitCode::kCleanupFailed;
+    }
+
     return art::odrefresh::ExitCode::kCompilationRequired;
 }
 }  // namespace
@@ -607,7 +604,7 @@
         LOG(INFO) << "Device doesn't support fsverity. Falling back to full verification.";
     }
 
-    bool useCompOs = kUseCompOs && supportsFsVerity && compOsPresent() && isDebugBuild();
+    bool useCompOs = kUseCompOs && supportsFsVerity && compOsPresent();
 
     if (supportsFsVerity) {
         auto existing_cert = verifyExistingRootCert(*key);