Merge "Make RKPD default"
diff --git a/diced/Android.bp b/diced/Android.bp
index e13d863..d4d29d5 100644
--- a/diced/Android.bp
+++ b/diced/Android.bp
@@ -60,7 +60,6 @@
         "libanyhow",
         "libdiced_open_dice_cbor",
         "libdiced_utils",
-        "libkeystore2_crypto_rust",
     ],
 }
 
@@ -75,27 +74,6 @@
         "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",
     ],
 }
 
@@ -121,66 +99,6 @@
     ],
 }
 
-rust_binary {
-    name: "diced",
-    srcs: ["src/diced_main.rs"],
-    prefer_rlib: true,
-    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_binary {
-    name: "diced.microdroid",
-    srcs: ["src/diced_main.rs"],
-    prefer_rlib: true,
-    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.microdroid.rc"],
-    bootstrap: true,
-}
-
-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",
diff --git a/diced/TEST_MAPPING b/diced/TEST_MAPPING
index d81efdd..be1c5e5 100644
--- a/diced/TEST_MAPPING
+++ b/diced/TEST_MAPPING
@@ -1,15 +1,18 @@
 {
   "presubmit": [
     {
+      "name": "libdiced_open_dice.integration_test"
+    },
+    {
+      "name": "libdiced_open_dice_nostd.integration_test"
+    },
+    {
       "name": "diced_utils_test"
     },
     {
       "name": "diced_sample_inputs_test"
     },
     {
-      "name": "diced_test"
-    },
-    {
       "name": "diced_vendor_test"
     }
   ]
diff --git a/diced/diced.microdroid.rc b/diced/diced.microdroid.rc
deleted file mode 100644
index 2226f47..0000000
--- a/diced/diced.microdroid.rc
+++ /dev/null
@@ -1,13 +0,0 @@
-# Start the Diced service.
-#
-# See system/core/init/README.md for information on the init.rc language.
-
-service diced /system/bin/diced.microdroid
-    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/diced.rc b/diced/diced.rc
deleted file mode 100644
index 8c43fa5..0000000
--- a/diced/diced.rc
+++ /dev/null
@@ -1,13 +0,0 @@
-# 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/Android.bp b/diced/open_dice/Android.bp
new file mode 100644
index 0000000..ea3ee3b
--- /dev/null
+++ b/diced/open_dice/Android.bp
@@ -0,0 +1,72 @@
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+rust_defaults {
+    name: "libdiced_open_dice_defaults",
+    crate_name: "diced_open_dice",
+    srcs: ["src/lib.rs"],
+    static_libs: [
+        "libopen_dice_cbor",
+    ],
+    vendor_available: true,
+    apex_available: [
+        "//apex_available:platform",
+        "com.android.virt",
+    ],
+}
+
+rust_library_rlib {
+    name: "libdiced_open_dice_nostd",
+    defaults: ["libdiced_open_dice_defaults"],
+    rustlibs: [
+        "libopen_dice_bcc_bindgen_nostd",
+        "libopen_dice_cbor_bindgen_nostd",
+        "libzeroize_nostd",
+    ],
+     whole_static_libs: [
+        "libopen_dice_cbor",
+        "libcrypto_baremetal",
+    ],
+}
+
+rust_library {
+    name: "libdiced_open_dice",
+    defaults: ["libdiced_open_dice_defaults"],
+    rustlibs: [
+        "libopen_dice_bcc_bindgen",
+        "libopen_dice_cbor_bindgen",
+        // For ZVec
+        "libkeystore2_crypto_rust",
+        "libzeroize",
+    ],
+    features: [
+        "std",
+    ],
+    whole_static_libs: [
+        "libopen_dice_bcc",
+    ],
+}
+
+rust_defaults {
+    name: "libdiced_open_dice_test_defaults",
+    crate_name: "diced_open_dice_test",
+    srcs: ["tests/*.rs"],
+    test_suites: ["general-tests"],
+}
+
+rust_test {
+    name: "libdiced_open_dice.integration_test",
+    defaults: ["libdiced_open_dice_test_defaults"],
+    rustlibs: [
+        "libdiced_open_dice",
+    ],
+}
+
+rust_test {
+    name: "libdiced_open_dice_nostd.integration_test",
+    defaults: ["libdiced_open_dice_test_defaults"],
+    rustlibs: [
+        "libdiced_open_dice_nostd",
+    ],
+}
diff --git a/diced/open_dice/src/bcc.rs b/diced/open_dice/src/bcc.rs
new file mode 100644
index 0000000..e3a96fe
--- /dev/null
+++ b/diced/open_dice/src/bcc.rs
@@ -0,0 +1,92 @@
+// Copyright 2023, 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 mirrors the content in open-dice/include/dice/android/bcc.h
+
+use crate::dice::{Cdi, CdiValues, InputValues};
+use crate::error::{check_result, Result};
+use open_dice_bcc_bindgen::{
+    BccConfigValues, BccFormatConfigDescriptor, BccMainFlow, BCC_INPUT_COMPONENT_NAME,
+    BCC_INPUT_COMPONENT_VERSION, BCC_INPUT_RESETTABLE,
+};
+use std::{ffi::CStr, ptr};
+
+/// Formats a configuration descriptor following the BCC's specification.
+/// See https://cs.android.com/android/platform/superproject/+/master:hardware/interfaces/security/rkp/aidl/android/hardware/security/keymint/ProtectedData.aidl
+pub fn bcc_format_config_descriptor(
+    name: Option<&CStr>,
+    version: Option<u64>,
+    resettable: bool,
+    buffer: &mut [u8],
+) -> Result<usize> {
+    let mut inputs = 0;
+    if name.is_some() {
+        inputs |= BCC_INPUT_COMPONENT_NAME;
+    }
+    if version.is_some() {
+        inputs |= BCC_INPUT_COMPONENT_VERSION;
+    }
+    if resettable {
+        inputs |= BCC_INPUT_RESETTABLE;
+    }
+
+    let values = BccConfigValues {
+        inputs,
+        component_name: name.map_or(ptr::null(), |p| p.as_ptr()),
+        component_version: version.unwrap_or(0),
+    };
+
+    let mut buffer_size = 0;
+    // SAFETY: The function writes to the buffer, within the given bounds, and only reads the
+    // input values. It writes its result to buffer_size.
+    check_result(unsafe {
+        BccFormatConfigDescriptor(&values, buffer.len(), buffer.as_mut_ptr(), &mut buffer_size)
+    })?;
+    Ok(buffer_size)
+}
+
+/// Executes the main BCC flow.
+///
+/// Given a full set of input values along with the current BCC and CDI values,
+/// computes the next CDI values and matching updated BCC.
+pub fn bcc_main_flow(
+    current_cdi_attest: &Cdi,
+    current_cdi_seal: &Cdi,
+    current_bcc: &[u8],
+    input_values: &InputValues,
+    next_cdi_values: &mut CdiValues,
+    next_bcc: &mut [u8],
+) -> Result<usize> {
+    let mut next_bcc_size = 0;
+    // SAFETY: `BccMainFlow` only reads the current `bcc` and CDI values and writes
+    // to `next_bcc` and next CDI values within its bounds. It also reads
+    // `input_values` as a constant input and doesn't store any pointer.
+    // The first argument can be null and is not used in the current implementation.
+    check_result(unsafe {
+        BccMainFlow(
+            ptr::null_mut(), // context
+            current_cdi_attest.as_ptr(),
+            current_cdi_seal.as_ptr(),
+            current_bcc.as_ptr(),
+            current_bcc.len(),
+            input_values.as_ptr(),
+            next_bcc.len(),
+            next_bcc.as_mut_ptr(),
+            &mut next_bcc_size,
+            next_cdi_values.cdi_attest.as_mut_ptr(),
+            next_cdi_values.cdi_seal.as_mut_ptr(),
+        )
+    })?;
+    Ok(next_bcc_size)
+}
diff --git a/diced/open_dice/src/dice.rs b/diced/open_dice/src/dice.rs
new file mode 100644
index 0000000..ed7d843
--- /dev/null
+++ b/diced/open_dice/src/dice.rs
@@ -0,0 +1,198 @@
+// Copyright 2023, 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.
+
+//! Structs and functions about the types used in DICE.
+//! This module mirrors the content in open-dice/include/dice/dice.h
+
+use crate::error::{check_result, Result};
+pub use open_dice_cbor_bindgen::DiceMode;
+use open_dice_cbor_bindgen::{
+    DiceConfigType, DiceDeriveCdiCertificateId, DiceDeriveCdiPrivateKeySeed, DiceInputValues,
+    DiceMainFlow, DICE_CDI_SIZE, DICE_HASH_SIZE, DICE_HIDDEN_SIZE, DICE_ID_SIZE,
+    DICE_INLINE_CONFIG_SIZE, DICE_PRIVATE_KEY_SEED_SIZE,
+};
+use std::ptr;
+use zeroize::{Zeroize, ZeroizeOnDrop};
+
+/// The size of a DICE hash.
+pub const HASH_SIZE: usize = DICE_HASH_SIZE as usize;
+/// The size of the DICE hidden value.
+pub const HIDDEN_SIZE: usize = DICE_HIDDEN_SIZE as usize;
+/// The size of a DICE inline config.
+const INLINE_CONFIG_SIZE: usize = DICE_INLINE_CONFIG_SIZE as usize;
+/// The size of a CDI.
+pub const CDI_SIZE: usize = DICE_CDI_SIZE as usize;
+/// The size of a private key seed.
+pub const PRIVATE_KEY_SEED_SIZE: usize = DICE_PRIVATE_KEY_SEED_SIZE as usize;
+/// The size of an ID.
+pub const ID_SIZE: usize = DICE_ID_SIZE as usize;
+
+/// Array type of hashes used by DICE.
+pub type Hash = [u8; HASH_SIZE];
+/// Array type of additional input.
+pub type Hidden = [u8; HIDDEN_SIZE];
+/// Array type of inline configuration values.
+pub type InlineConfig = [u8; INLINE_CONFIG_SIZE];
+/// Array type of CDIs.
+pub type Cdi = [u8; CDI_SIZE];
+/// Array type of private key seeds.
+pub type PrivateKeySeed = [u8; PRIVATE_KEY_SEED_SIZE];
+/// Array type of DICE ID.
+pub type DiceId = [u8; ID_SIZE];
+
+/// CDI Values.
+#[derive(Zeroize, ZeroizeOnDrop, Default)]
+pub struct CdiValues {
+    /// Attestation CDI.
+    pub cdi_attest: Cdi,
+    /// Sealing CDI.
+    pub cdi_seal: Cdi,
+}
+
+/// Configuration descriptor for DICE input values.
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub enum Config<'a> {
+    /// Reference to an inline descriptor.
+    Inline(&'a InlineConfig),
+    /// Reference to a free form descriptor that will be hashed by the implementation.
+    Descriptor(&'a [u8]),
+}
+
+impl Config<'_> {
+    fn dice_config_type(&self) -> DiceConfigType {
+        match self {
+            Self::Inline(_) => DiceConfigType::kDiceConfigTypeInline,
+            Self::Descriptor(_) => DiceConfigType::kDiceConfigTypeDescriptor,
+        }
+    }
+
+    fn inline_config(&self) -> InlineConfig {
+        match self {
+            Self::Inline(inline) => **inline,
+            Self::Descriptor(_) => [0u8; INLINE_CONFIG_SIZE],
+        }
+    }
+
+    fn descriptor_ptr(&self) -> *const u8 {
+        match self {
+            Self::Descriptor(descriptor) => descriptor.as_ptr(),
+            _ => ptr::null(),
+        }
+    }
+
+    fn descriptor_size(&self) -> usize {
+        match self {
+            Self::Descriptor(descriptor) => descriptor.len(),
+            _ => 0,
+        }
+    }
+}
+
+/// Wrap of `DiceInputValues`.
+#[derive(Clone, Debug)]
+pub struct InputValues(DiceInputValues);
+
+impl InputValues {
+    /// Creates a new `InputValues`.
+    pub fn new(
+        code_hash: Hash,
+        config: Config,
+        authority_hash: Hash,
+        mode: DiceMode,
+        hidden: Hidden,
+    ) -> Self {
+        Self(DiceInputValues {
+            code_hash,
+            code_descriptor: ptr::null(),
+            code_descriptor_size: 0,
+            config_type: config.dice_config_type(),
+            config_value: config.inline_config(),
+            config_descriptor: config.descriptor_ptr(),
+            config_descriptor_size: config.descriptor_size(),
+            authority_hash,
+            authority_descriptor: ptr::null(),
+            authority_descriptor_size: 0,
+            mode,
+            hidden,
+        })
+    }
+
+    /// Returns a raw pointer to the wrapped `DiceInputValues`.
+    pub fn as_ptr(&self) -> *const DiceInputValues {
+        &self.0 as *const DiceInputValues
+    }
+}
+
+/// Derives a CDI private key seed from a `cdi_attest` value.
+pub fn derive_cdi_private_key_seed(cdi_attest: &Cdi) -> Result<PrivateKeySeed> {
+    let mut seed = [0u8; PRIVATE_KEY_SEED_SIZE];
+    // SAFETY: The function writes to the buffer within the given bounds, and only reads the
+    // input values. The first argument context is not used in this function.
+    check_result(unsafe {
+        DiceDeriveCdiPrivateKeySeed(
+            ptr::null_mut(), // context
+            cdi_attest.as_ptr(),
+            seed.as_mut_ptr(),
+        )
+    })?;
+    Ok(seed)
+}
+
+/// Derives an ID from the given `cdi_public_key` value.
+pub fn derive_cdi_certificate_id(cdi_public_key: &[u8]) -> Result<DiceId> {
+    let mut id = [0u8; ID_SIZE];
+    // SAFETY: The function writes to the buffer within the given bounds, and only reads the
+    // input values. The first argument context is not used in this function.
+    check_result(unsafe {
+        DiceDeriveCdiCertificateId(
+            ptr::null_mut(), // context
+            cdi_public_key.as_ptr(),
+            cdi_public_key.len(),
+            id.as_mut_ptr(),
+        )
+    })?;
+    Ok(id)
+}
+
+/// Executes the main DICE flow.
+///
+/// Given a full set of input values and the current CDI values, computes the
+/// next CDI values and a matching certificate.
+/// Returns the actual size of the next CDI certificate.
+pub fn dice_main_flow(
+    current_cdi_attest: &Cdi,
+    current_cdi_seal: &Cdi,
+    input_values: &InputValues,
+    next_cdi_certificate: &mut [u8],
+    next_cdi_values: &mut CdiValues,
+) -> Result<usize> {
+    let mut next_cdi_certificate_actual_size = 0;
+    // SAFETY: The function only reads the current CDI values and inputs and writes
+    // to `next_cdi_certificate` and next CDI values within its bounds.
+    // The first argument can be null and is not used in the current implementation.
+    check_result(unsafe {
+        DiceMainFlow(
+            ptr::null_mut(), // context
+            current_cdi_attest.as_ptr(),
+            current_cdi_seal.as_ptr(),
+            input_values.as_ptr(),
+            next_cdi_certificate.len(),
+            next_cdi_certificate.as_mut_ptr(),
+            &mut next_cdi_certificate_actual_size,
+            next_cdi_values.cdi_attest.as_mut_ptr(),
+            next_cdi_values.cdi_seal.as_mut_ptr(),
+        )
+    })?;
+    Ok(next_cdi_certificate_actual_size)
+}
diff --git a/diced/open_dice/src/error.rs b/diced/open_dice/src/error.rs
new file mode 100644
index 0000000..7405c51
--- /dev/null
+++ b/diced/open_dice/src/error.rs
@@ -0,0 +1,71 @@
+// Copyright 2023, 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.
+
+//! Errors and relating functions thrown in this library.
+
+use open_dice_cbor_bindgen::DiceResult;
+use std::{fmt, result};
+
+#[cfg(feature = "std")]
+use std::error::Error;
+
+/// Error type used by DICE.
+#[derive(Debug)]
+pub enum DiceError {
+    /// Provided input was invalid.
+    InvalidInput,
+    /// Provided buffer was too small.
+    BufferTooSmall,
+    /// Platform error.
+    PlatformError,
+    /// The allocation of a ZVec failed.
+    #[cfg(feature = "std")]
+    ZVecError(keystore2_crypto::zvec::Error),
+}
+
+#[cfg(feature = "std")]
+impl From<keystore2_crypto::zvec::Error> for DiceError {
+    fn from(e: keystore2_crypto::zvec::Error) -> Self {
+        Self::ZVecError(e)
+    }
+}
+
+/// This makes `DiceError` accepted by anyhow.
+#[cfg(feature = "std")]
+impl Error for DiceError {}
+
+impl fmt::Display for DiceError {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        match self {
+            Self::InvalidInput => write!(f, "invalid input"),
+            Self::BufferTooSmall => write!(f, "buffer too small"),
+            Self::PlatformError => write!(f, "platform error"),
+            #[cfg(feature = "std")]
+            Self::ZVecError(e) => write!(f, "ZVec allocation failed {e}"),
+        }
+    }
+}
+
+/// DICE result type.
+pub type Result<T> = result::Result<T, DiceError>;
+
+/// Checks the given `DiceResult`. Returns an error if it's not OK.
+pub fn check_result(result: DiceResult) -> Result<()> {
+    match result {
+        DiceResult::kDiceResultOk => Ok(()),
+        DiceResult::kDiceResultInvalidInput => Err(DiceError::InvalidInput),
+        DiceResult::kDiceResultBufferTooSmall => Err(DiceError::BufferTooSmall),
+        DiceResult::kDiceResultPlatformError => Err(DiceError::PlatformError),
+    }
+}
diff --git a/diced/open_dice/src/lib.rs b/diced/open_dice/src/lib.rs
new file mode 100644
index 0000000..7e8c59a
--- /dev/null
+++ b/diced/open_dice/src/lib.rs
@@ -0,0 +1,42 @@
+// Copyright 2023, 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 safe wrappers around the public API of libopen-dice for
+//! both std and nostd usages.
+
+#![cfg_attr(not(feature = "std"), no_std)]
+
+#[cfg(not(feature = "std"))]
+extern crate core as std;
+
+mod bcc;
+mod dice;
+mod error;
+mod ops;
+#[cfg(feature = "std")]
+mod retry;
+
+pub use bcc::{bcc_format_config_descriptor, bcc_main_flow};
+pub use dice::{
+    derive_cdi_certificate_id, derive_cdi_private_key_seed, dice_main_flow, Cdi, CdiValues, Config,
+    DiceMode, Hash, Hidden, InlineConfig, InputValues, PrivateKeySeed, CDI_SIZE, HASH_SIZE,
+    HIDDEN_SIZE, ID_SIZE, PRIVATE_KEY_SEED_SIZE,
+};
+pub use error::{check_result, DiceError, Result};
+pub use ops::{generate_certificate, hash, kdf};
+#[cfg(feature = "std")]
+pub use retry::{
+    retry_bcc_format_config_descriptor, retry_bcc_main_flow, retry_dice_main_flow,
+    retry_generate_certificate, OwnedDiceArtifacts,
+};
diff --git a/diced/open_dice/src/ops.rs b/diced/open_dice/src/ops.rs
new file mode 100644
index 0000000..3c0ef23
--- /dev/null
+++ b/diced/open_dice/src/ops.rs
@@ -0,0 +1,86 @@
+// Copyright 2023, 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 mirrors the content in open-dice/include/dice/ops.h
+//! It contains the set of functions that implement various operations that the
+//! main DICE functions depend on.
+
+use crate::dice::{Hash, InputValues, HASH_SIZE, PRIVATE_KEY_SEED_SIZE};
+use crate::error::{check_result, Result};
+use open_dice_cbor_bindgen::{DiceGenerateCertificate, DiceHash, DiceKdf};
+use std::ptr;
+
+/// Hashes the provided input using DICE's hash function `DiceHash`.
+pub fn hash(input: &[u8]) -> Result<Hash> {
+    let mut output: Hash = [0; HASH_SIZE];
+    // SAFETY: DiceHash takes a sized input buffer and writes to a constant-sized output buffer.
+    // The first argument context is not used in this function.
+    check_result(unsafe {
+        DiceHash(
+            ptr::null_mut(), // context
+            input.as_ptr(),
+            input.len(),
+            output.as_mut_ptr(),
+        )
+    })?;
+    Ok(output)
+}
+
+/// An implementation of HKDF-SHA512. Derives a key of `derived_key.len()` bytes from `ikm`, `salt`,
+/// and `info`. The derived key is written to the `derived_key`.
+pub fn kdf(ikm: &[u8], salt: &[u8], info: &[u8], derived_key: &mut [u8]) -> Result<()> {
+    // SAFETY: The function writes to the `derived_key`, within the given bounds, and only reads the
+    // input values. The first argument context is not used in this function.
+    check_result(unsafe {
+        DiceKdf(
+            ptr::null_mut(), // context
+            derived_key.len(),
+            ikm.as_ptr(),
+            ikm.len(),
+            salt.as_ptr(),
+            salt.len(),
+            info.as_ptr(),
+            info.len(),
+            derived_key.as_mut_ptr(),
+        )
+    })
+}
+
+/// Generates an X.509 certificate from the given `subject_private_key_seed` and
+/// `input_values`, and signed by `authority_private_key_seed`.
+/// The subject private key seed is supplied here so the implementation can choose
+/// between asymmetric mechanisms, for example ECDSA vs Ed25519.
+/// Returns the actual size of the generated certificate.
+pub fn generate_certificate(
+    subject_private_key_seed: &[u8; PRIVATE_KEY_SEED_SIZE],
+    authority_private_key_seed: &[u8; PRIVATE_KEY_SEED_SIZE],
+    input_values: &InputValues,
+    certificate: &mut [u8],
+) -> Result<usize> {
+    let mut certificate_actual_size = 0;
+    // SAFETY: The function writes to the `certificate` within the given bounds, and only reads the
+    // input values and the key seeds. The first argument context is not used in this function.
+    check_result(unsafe {
+        DiceGenerateCertificate(
+            ptr::null_mut(), // context
+            subject_private_key_seed.as_ptr(),
+            authority_private_key_seed.as_ptr(),
+            input_values.as_ptr(),
+            certificate.len(),
+            certificate.as_mut_ptr(),
+            &mut certificate_actual_size,
+        )
+    })?;
+    Ok(certificate_actual_size)
+}
diff --git a/diced/open_dice/src/retry.rs b/diced/open_dice/src/retry.rs
new file mode 100644
index 0000000..c28b691
--- /dev/null
+++ b/diced/open_dice/src/retry.rs
@@ -0,0 +1,143 @@
+// Copyright 2023, 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 implements a retry version for multiple DICE functions that
+//! require preallocated output buffer. As the retry functions require
+//! memory allocation on heap, currently we only expose these functions in
+//! std environment.
+
+use crate::bcc::{bcc_format_config_descriptor, bcc_main_flow};
+use crate::dice::{dice_main_flow, Cdi, CdiValues, InputValues, PRIVATE_KEY_SEED_SIZE};
+use crate::error::{DiceError, Result};
+use crate::ops::generate_certificate;
+use std::ffi::CStr;
+
+/// Artifacts stores a set of dice artifacts comprising CDI_ATTEST, CDI_SEAL,
+/// and the BCC formatted attestation certificate chain.
+/// As we align with the DICE standards today, this is the certificate chain
+/// is also called DICE certificate chain.
+pub struct OwnedDiceArtifacts {
+    /// CDI Values.
+    pub cdi_values: CdiValues,
+    /// Boot Certificate Chain.
+    pub bcc: Vec<u8>,
+}
+
+/// Retries the given function with bigger output buffer size.
+fn retry_with_bigger_buffer<F>(mut f: F) -> Result<Vec<u8>>
+where
+    F: FnMut(&mut Vec<u8>) -> Result<usize>,
+{
+    const INITIAL_BUFFER_SIZE: usize = 256;
+    const MAX_BUFFER_SIZE: usize = 64 * 1024 * 1024;
+
+    let mut buffer = vec![0u8; INITIAL_BUFFER_SIZE];
+    while buffer.len() <= MAX_BUFFER_SIZE {
+        match f(&mut buffer) {
+            Err(DiceError::BufferTooSmall) => {
+                let new_size = buffer.len() * 2;
+                buffer.resize(new_size, 0);
+            }
+            Err(e) => return Err(e),
+            Ok(actual_size) => {
+                if actual_size > buffer.len() {
+                    panic!(
+                        "actual_size larger than buffer size: open-dice function
+                         may have written past the end of the buffer."
+                    );
+                }
+                buffer.truncate(actual_size);
+                return Ok(buffer);
+            }
+        }
+    }
+    Err(DiceError::PlatformError)
+}
+
+/// Formats a configuration descriptor following the BCC's specification.
+pub fn retry_bcc_format_config_descriptor(
+    name: Option<&CStr>,
+    version: Option<u64>,
+    resettable: bool,
+) -> Result<Vec<u8>> {
+    retry_with_bigger_buffer(|buffer| {
+        bcc_format_config_descriptor(name, version, resettable, buffer)
+    })
+}
+
+/// Executes the main BCC flow.
+///
+/// Given a full set of input values along with the current BCC and CDI values,
+/// computes the next CDI values and matching updated BCC.
+pub fn retry_bcc_main_flow(
+    current_cdi_attest: &Cdi,
+    current_cdi_seal: &Cdi,
+    bcc: &[u8],
+    input_values: &InputValues,
+) -> Result<OwnedDiceArtifacts> {
+    let mut next_cdi_values = CdiValues::default();
+    let next_bcc = retry_with_bigger_buffer(|next_bcc| {
+        bcc_main_flow(
+            current_cdi_attest,
+            current_cdi_seal,
+            bcc,
+            input_values,
+            &mut next_cdi_values,
+            next_bcc,
+        )
+    })?;
+    Ok(OwnedDiceArtifacts { cdi_values: next_cdi_values, bcc: next_bcc })
+}
+
+/// Executes the main DICE flow.
+///
+/// Given a full set of input values and the current CDI values, computes the
+/// next CDI values and a matching certificate.
+pub fn retry_dice_main_flow(
+    current_cdi_attest: &Cdi,
+    current_cdi_seal: &Cdi,
+    input_values: &InputValues,
+) -> Result<(CdiValues, Vec<u8>)> {
+    let mut next_cdi_values = CdiValues::default();
+    let next_cdi_certificate = retry_with_bigger_buffer(|next_cdi_certificate| {
+        dice_main_flow(
+            current_cdi_attest,
+            current_cdi_seal,
+            input_values,
+            next_cdi_certificate,
+            &mut next_cdi_values,
+        )
+    })?;
+    Ok((next_cdi_values, next_cdi_certificate))
+}
+
+/// Generates an X.509 certificate from the given `subject_private_key_seed` and
+/// `input_values`, and signed by `authority_private_key_seed`.
+/// The subject private key seed is supplied here so the implementation can choose
+/// between asymmetric mechanisms, for example ECDSA vs Ed25519.
+/// Returns the generated certificate.
+pub fn retry_generate_certificate(
+    subject_private_key_seed: &[u8; PRIVATE_KEY_SEED_SIZE],
+    authority_private_key_seed: &[u8; PRIVATE_KEY_SEED_SIZE],
+    input_values: &InputValues,
+) -> Result<Vec<u8>> {
+    retry_with_bigger_buffer(|certificate| {
+        generate_certificate(
+            subject_private_key_seed,
+            authority_private_key_seed,
+            input_values,
+            certificate,
+        )
+    })
+}
diff --git a/diced/open_dice/tests/api_test.rs b/diced/open_dice/tests/api_test.rs
new file mode 100644
index 0000000..3823bb7
--- /dev/null
+++ b/diced/open_dice/tests/api_test.rs
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2023 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 diced_open_dice::{
+    derive_cdi_certificate_id, hash, kdf, HASH_SIZE, ID_SIZE, PRIVATE_KEY_SEED_SIZE,
+};
+
+#[test]
+fn hash_succeeds() {
+    const EXPECTED_HASH: [u8; HASH_SIZE] = [
+        0x30, 0x9e, 0xcc, 0x48, 0x9c, 0x12, 0xd6, 0xeb, 0x4c, 0xc4, 0x0f, 0x50, 0xc9, 0x02, 0xf2,
+        0xb4, 0xd0, 0xed, 0x77, 0xee, 0x51, 0x1a, 0x7c, 0x7a, 0x9b, 0xcd, 0x3c, 0xa8, 0x6d, 0x4c,
+        0xd8, 0x6f, 0x98, 0x9d, 0xd3, 0x5b, 0xc5, 0xff, 0x49, 0x96, 0x70, 0xda, 0x34, 0x25, 0x5b,
+        0x45, 0xb0, 0xcf, 0xd8, 0x30, 0xe8, 0x1f, 0x60, 0x5d, 0xcf, 0x7d, 0xc5, 0x54, 0x2e, 0x93,
+        0xae, 0x9c, 0xd7, 0x6f,
+    ];
+    assert_eq!(EXPECTED_HASH, hash(b"hello world").expect("hash failed"));
+}
+
+#[test]
+fn kdf_succeeds() {
+    let mut derived_key = [0u8; PRIVATE_KEY_SEED_SIZE];
+    kdf(b"myInitialKeyMaterial", b"mySalt", b"myInfo", &mut derived_key).unwrap();
+    const EXPECTED_DERIVED_KEY: [u8; PRIVATE_KEY_SEED_SIZE] = [
+        0x91, 0x9b, 0x8d, 0x29, 0xc4, 0x1b, 0x93, 0xd7, 0xeb, 0x09, 0xfa, 0xd7, 0xc9, 0x87, 0xb0,
+        0xd1, 0xcc, 0x26, 0xef, 0x07, 0x83, 0x42, 0xcf, 0xa3, 0x45, 0x0a, 0x57, 0xe9, 0x19, 0x86,
+        0xef, 0x48,
+    ];
+    assert_eq!(EXPECTED_DERIVED_KEY, derived_key);
+}
+
+#[test]
+fn derive_cdi_certificate_id_succeeds() {
+    const EXPECTED_ID: [u8; ID_SIZE] = [
+        0x7a, 0x36, 0x45, 0x2c, 0x02, 0xf6, 0x2b, 0xec, 0xf9, 0x80, 0x06, 0x75, 0x87, 0xa5, 0xc1,
+        0x44, 0x0c, 0xd3, 0xc0, 0x6d,
+    ];
+    assert_eq!(EXPECTED_ID, derive_cdi_certificate_id(b"MyPubKey").unwrap());
+}
diff --git a/diced/open_dice_cbor/Android.bp b/diced/open_dice_cbor/Android.bp
index a84190a..e52af7d 100644
--- a/diced/open_dice_cbor/Android.bp
+++ b/diced/open_dice_cbor/Android.bp
@@ -22,14 +22,12 @@
     srcs: ["lib.rs"],
 
     rustlibs: [
+        "libdiced_open_dice",
         // For ZVec
         "libkeystore2_crypto_rust",
-        "libopen_dice_bcc_bindgen",
         "libopen_dice_cbor_bindgen",
-        "libthiserror",
     ],
     static_libs: [
-        "libopen_dice_bcc",
         "libopen_dice_cbor",
     ],
     vendor_available: true,
@@ -46,14 +44,12 @@
     test_suites: ["general-tests"],
     auto_gen_config: true,
     rustlibs: [
+        "libdiced_open_dice",
         "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 ffb8a48..8af903f 100644
--- a/diced/open_dice_cbor/lib.rs
+++ b/diced/open_dice_cbor/lib.rs
@@ -20,52 +20,30 @@
 //! let context = dice::dice::OpenDiceCborContext::new()
 //! let parent_cdi_attest = [1u8, dice::CDI_SIZE];
 //! let parent_cdi_seal = [2u8, dice::CDI_SIZE];
-//! let input_values = dice::InputValuesOwned {
-//!     code_hash: [3u8, dice::HASH_SIZE],
-//!     config: dice::ConfigOwned::Descriptor("My descriptor".as_bytes().to_vec()),
-//!     authority_hash: [0u8, dice::HASH_SIZE],
-//!     mode: dice::Mode::Normal,
-//!     hidden: [0u8, dice::HIDDEN_SIZE],
+//! let input_values = dice::InputValues::new(
+//!     [3u8, dice::HASH_SIZE], // code_hash
+//!     dice::Config::Descriptor(&"My descriptor".as_bytes().to_vec()),
+//!     [0u8, dice::HASH_SIZE], // authority_hash
+//!     dice::DiceMode::kDiceModeNormal,
+//!     [0u8, dice::HIDDEN_SIZE], // hidden
 //! };
 //! let (cdi_attest, cdi_seal, cert_chain) = context
 //!     .main_flow(&parent_cdi_attest, &parent_cdi_seal, &input_values)?;
 //! ```
 
-use keystore2_crypto::{zvec, ZVec};
-use open_dice_bcc_bindgen::BccMainFlow;
-use open_dice_cbor_bindgen::{
-    DiceConfigType, DiceDeriveCdiCertificateId, DiceDeriveCdiPrivateKeySeed,
-    DiceGenerateCertificate, DiceHash, DiceInputValues, DiceKdf, DiceKeypairFromSeed, DiceMainFlow,
-    DiceMode, DiceResult, DiceSign, DiceVerify, DICE_CDI_SIZE, DICE_HASH_SIZE, DICE_HIDDEN_SIZE,
-    DICE_ID_SIZE, DICE_INLINE_CONFIG_SIZE, DICE_PRIVATE_KEY_SEED_SIZE, DICE_PRIVATE_KEY_SIZE,
-    DICE_PUBLIC_KEY_SIZE, DICE_SIGNATURE_SIZE,
+pub use diced_open_dice::{
+    check_result, derive_cdi_private_key_seed, hash, retry_bcc_format_config_descriptor,
+    retry_bcc_main_flow, retry_dice_main_flow, Config, DiceError, Hash, Hidden, InputValues,
+    OwnedDiceArtifacts, Result, CDI_SIZE, HASH_SIZE, HIDDEN_SIZE, PRIVATE_KEY_SEED_SIZE,
 };
+use keystore2_crypto::ZVec;
+pub use open_dice_cbor_bindgen::DiceMode;
 use open_dice_cbor_bindgen::{
-    DiceConfigType_kDiceConfigTypeDescriptor as DICE_CONFIG_TYPE_DESCRIPTOR,
-    DiceConfigType_kDiceConfigTypeInline as DICE_CONFIG_TYPE_INLINE,
-    DiceMode_kDiceModeDebug as DICE_MODE_DEBUG,
-    DiceMode_kDiceModeMaintenance as DICE_MODE_RECOVERY,
-    DiceMode_kDiceModeNormal as DICE_MODE_NORMAL,
-    DiceMode_kDiceModeNotInitialized as DICE_MODE_NOT_CONFIGURED,
-    DiceResult_kDiceResultBufferTooSmall as DICE_RESULT_BUFFER_TOO_SMALL,
-    DiceResult_kDiceResultInvalidInput as DICE_RESULT_INVALID_INPUT,
-    DiceResult_kDiceResultOk as DICE_RESULT_OK,
-    DiceResult_kDiceResultPlatformError as DICE_RESULT_PLATFORM_ERROR,
+    DiceKeypairFromSeed, DiceSign, DiceVerify, DICE_PRIVATE_KEY_SIZE, DICE_PUBLIC_KEY_SIZE,
+    DICE_SIGNATURE_SIZE,
 };
-use std::ffi::{c_void, NulError};
+use std::ffi::c_void;
 
-/// The size of a DICE hash.
-pub const HASH_SIZE: usize = DICE_HASH_SIZE as usize;
-/// The size of the DICE hidden value.
-pub const HIDDEN_SIZE: usize = DICE_HIDDEN_SIZE as usize;
-/// The size of a DICE inline config.
-pub const INLINE_CONFIG_SIZE: usize = DICE_INLINE_CONFIG_SIZE as usize;
-/// The size of a private key seed.
-pub const PRIVATE_KEY_SEED_SIZE: usize = DICE_PRIVATE_KEY_SEED_SIZE as usize;
-/// The size of a CDI.
-pub const CDI_SIZE: usize = DICE_CDI_SIZE as usize;
-/// The size of an ID.
-pub const ID_SIZE: usize = DICE_ID_SIZE as usize;
 /// The size of a private key.
 pub const PRIVATE_KEY_SIZE: usize = DICE_PRIVATE_KEY_SIZE as usize;
 /// The size of a public key.
@@ -73,280 +51,6 @@
 /// The size of a signature.
 pub const SIGNATURE_SIZE: usize = DICE_SIGNATURE_SIZE as usize;
 
-/// Open dice wrapper error type.
-#[derive(Debug, thiserror::Error, PartialEq, Eq)]
-pub enum Error {
-    /// The libopen-dice backend reported InvalidInput.
-    #[error("Open dice backend: Invalid input")]
-    InvalidInput,
-    /// The libopen-dice backend reported BufferTooSmall.
-    #[error("Open dice backend: Buffer too small")]
-    BufferTooSmall,
-    /// The libopen-dice backend reported PlatformError.
-    #[error("Open dice backend: Platform error")]
-    PlatformError,
-    /// The libopen-dice backend reported an error that is outside of the defined range of errors.
-    /// The returned error code is embedded in this value.
-    #[error("Open dice backend returned an unexpected error code: {0:?}")]
-    Unexpected(u32),
-
-    /// The allocation of a ZVec failed. Most likely due to a failure during the call to mlock.
-    #[error("ZVec allocation failed")]
-    ZVec(#[from] zvec::Error),
-
-    /// Functions that have to convert str to CString may fail if the string has an interior
-    /// nul byte.
-    #[error("Input string has an interior nul byte.")]
-    CStrNulError(#[from] NulError),
-}
-
-/// Open dice result type.
-pub type Result<T> = std::result::Result<T, Error>;
-
-impl From<DiceResult> for Error {
-    fn from(result: DiceResult) -> Self {
-        match result {
-            DICE_RESULT_INVALID_INPUT => Error::InvalidInput,
-            DICE_RESULT_BUFFER_TOO_SMALL => Error::BufferTooSmall,
-            DICE_RESULT_PLATFORM_ERROR => Error::PlatformError,
-            r => Error::Unexpected(r),
-        }
-    }
-}
-
-fn check_result(result: DiceResult) -> Result<()> {
-    if result == DICE_RESULT_OK {
-        Ok(())
-    } else {
-        Err(result.into())
-    }
-}
-
-/// Configuration descriptor for dice input values.
-#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
-pub enum Config<'a> {
-    /// A reference to an inline descriptor.
-    Inline(&'a [u8; INLINE_CONFIG_SIZE]),
-    /// A reference to a free form descriptor that will be hashed by the implementation.
-    Descriptor(&'a [u8]),
-}
-
-enum ConfigOwned {
-    Inline([u8; INLINE_CONFIG_SIZE]),
-    Descriptor(Vec<u8>),
-}
-
-impl Config<'_> {
-    fn get_type(&self) -> DiceConfigType {
-        match self {
-            Self::Inline(_) => DICE_CONFIG_TYPE_INLINE,
-            Self::Descriptor(_) => DICE_CONFIG_TYPE_DESCRIPTOR,
-        }
-    }
-
-    fn get_inline(&self) -> [u8; INLINE_CONFIG_SIZE] {
-        match self {
-            Self::Inline(inline) => **inline,
-            _ => [0u8; INLINE_CONFIG_SIZE],
-        }
-    }
-
-    fn get_descriptor_as_ptr(&self) -> *const u8 {
-        match self {
-            Self::Descriptor(descriptor) => descriptor.as_ptr(),
-            _ => std::ptr::null(),
-        }
-    }
-
-    fn get_descriptor_size(&self) -> usize {
-        match self {
-            Self::Descriptor(descriptor) => descriptor.len(),
-            _ => 0,
-        }
-    }
-}
-
-impl From<Config<'_>> for ConfigOwned {
-    fn from(config: Config) -> Self {
-        match config {
-            Config::Inline(inline) => ConfigOwned::Inline(*inline),
-            Config::Descriptor(descriptor) => ConfigOwned::Descriptor(descriptor.to_owned()),
-        }
-    }
-}
-
-/// DICE modes as defined here:
-/// https://pigweed.googlesource.com/open-dice/+/refs/heads/main/docs/specification.md#mode-value-details
-#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
-pub enum Mode {
-    /// See documentation linked above.
-    NotConfigured = 0,
-    /// See documentation linked above.
-    Normal = 1,
-    /// See documentation linked above.
-    Debug = 2,
-    /// See documentation linked above.
-    Recovery = 3,
-}
-
-impl Mode {
-    fn get_internal(&self) -> DiceMode {
-        match self {
-            Self::NotConfigured => DICE_MODE_NOT_CONFIGURED,
-            Self::Normal => DICE_MODE_NORMAL,
-            Self::Debug => DICE_MODE_DEBUG,
-            Self::Recovery => DICE_MODE_RECOVERY,
-        }
-    }
-}
-
-/// This trait allows API users to supply DICE input values without copying.
-pub trait InputValues {
-    /// Returns the code hash.
-    fn code_hash(&self) -> &[u8; HASH_SIZE];
-    /// Returns the config.
-    fn config(&self) -> Config;
-    /// Returns the authority hash.
-    fn authority_hash(&self) -> &[u8; HASH_SIZE];
-    /// Returns the authority descriptor.
-    fn authority_descriptor(&self) -> Option<&[u8]>;
-    /// Returns the mode.
-    fn mode(&self) -> Mode;
-    /// Returns the hidden value.
-    fn hidden(&self) -> &[u8; HIDDEN_SIZE];
-}
-
-/// An owning convenience type implementing `InputValues`.
-pub struct InputValuesOwned {
-    code_hash: [u8; HASH_SIZE],
-    config: ConfigOwned,
-    authority_hash: [u8; HASH_SIZE],
-    authority_descriptor: Option<Vec<u8>>,
-    mode: Mode,
-    hidden: [u8; HIDDEN_SIZE],
-}
-
-impl InputValuesOwned {
-    /// Construct a new instance of InputValuesOwned.
-    pub fn new(
-        code_hash: [u8; HASH_SIZE],
-        config: Config,
-        authority_hash: [u8; HASH_SIZE],
-        authority_descriptor: Option<Vec<u8>>,
-        mode: Mode,
-        hidden: [u8; HIDDEN_SIZE],
-    ) -> Self {
-        Self {
-            code_hash,
-            config: config.into(),
-            authority_hash,
-            authority_descriptor,
-            mode,
-            hidden,
-        }
-    }
-}
-
-impl InputValues for InputValuesOwned {
-    fn code_hash(&self) -> &[u8; HASH_SIZE] {
-        &self.code_hash
-    }
-    fn config(&self) -> Config {
-        match &self.config {
-            ConfigOwned::Inline(inline) => Config::Inline(inline),
-            ConfigOwned::Descriptor(descriptor) => Config::Descriptor(descriptor.as_slice()),
-        }
-    }
-    fn authority_hash(&self) -> &[u8; HASH_SIZE] {
-        &self.authority_hash
-    }
-    fn authority_descriptor(&self) -> Option<&[u8]> {
-        self.authority_descriptor.as_deref()
-    }
-    fn mode(&self) -> Mode {
-        self.mode
-    }
-    fn hidden(&self) -> &[u8; HIDDEN_SIZE] {
-        &self.hidden
-    }
-}
-
-fn call_with_input_values<T: InputValues + ?Sized, F, R>(input_values: &T, f: F) -> Result<R>
-where
-    F: FnOnce(*const DiceInputValues) -> Result<R>,
-{
-    let input_values = DiceInputValues {
-        code_hash: *input_values.code_hash(),
-        code_descriptor: std::ptr::null(),
-        code_descriptor_size: 0,
-        config_type: input_values.config().get_type(),
-        config_value: input_values.config().get_inline(),
-        config_descriptor: input_values.config().get_descriptor_as_ptr(),
-        config_descriptor_size: input_values.config().get_descriptor_size(),
-        authority_hash: *input_values.authority_hash(),
-        authority_descriptor: input_values
-            .authority_descriptor()
-            .map_or_else(std::ptr::null, <[u8]>::as_ptr),
-        authority_descriptor_size: input_values.authority_descriptor().map_or(0, <[u8]>::len),
-        mode: input_values.mode().get_internal(),
-        hidden: *input_values.hidden(),
-    };
-
-    f(&input_values as *const DiceInputValues)
-}
-
-/// Multiple of the open dice function required preallocated output buffer
-/// which may be too small, this function implements the retry logic to handle
-/// too small buffer allocations.
-/// The callback `F` must expect a mutable reference to a buffer and a size hint
-/// field. The callback is called repeatedly as long as it returns
-/// `Err(Error::BufferTooSmall)`. If the size hint remains 0, the buffer size is
-/// doubled with each iteration. If the size hint is set by the callback, the buffer
-/// will be set to accommodate at least this many bytes.
-/// If the callback returns `Ok(())`, the buffer is truncated to the size hint
-/// exactly.
-/// The function panics if the callback returns `Ok(())` and the size hint is
-/// larger than the buffer size.
-fn retry_while_adjusting_output_buffer<F>(mut f: F) -> Result<Vec<u8>>
-where
-    F: FnMut(&mut Vec<u8>, &mut usize) -> Result<()>,
-{
-    let mut buffer = vec![0; INITIAL_OUT_BUFFER_SIZE];
-    let mut actual_size: usize = 0;
-    loop {
-        match f(&mut buffer, &mut actual_size) {
-            // If Error::BufferTooSmall was returned, the allocated certificate
-            // buffer was to small for the output. So the buffer is resized to the actual
-            // size, and a second attempt is made with the new buffer.
-            Err(Error::BufferTooSmall) => {
-                let new_size = if actual_size == 0 {
-                    // Due to an off spec implementation of open dice cbor, actual size
-                    // does not return the required size if the buffer was too small. So
-                    // we have to try and approach it gradually.
-                    buffer.len() * 2
-                } else {
-                    actual_size
-                };
-                buffer.resize(new_size, 0);
-                continue;
-            }
-            Err(e) => return Err(e),
-            Ok(()) => {
-                if actual_size > buffer.len() {
-                    panic!(
-                        "actual_size larger than buffer size: open-dice function
-                         may have written past the end of the buffer."
-                    );
-                }
-                // Truncate the certificate buffer to the actual size because it may be
-                // smaller than the original allocation.
-                buffer.truncate(actual_size);
-                return Ok(buffer);
-            }
-        }
-    }
-}
-
 /// Some libopen-dice variants use a context. Developers that want to customize these
 /// bindings may want to implement their own Context factory that creates a context
 /// useable by their preferred backend.
@@ -393,165 +97,10 @@
 /// Type alias for Vec<u8> indicating that it holds a BCC certificate chain.
 pub type Bcc = Vec<u8>;
 
-const INITIAL_OUT_BUFFER_SIZE: usize = 1024;
-
 /// ContextImpl is a mixin trait that implements the safe wrappers around the open dice
 /// library calls. Implementations must implement Context::get_context(). As of
 /// this writing, the only implementation is OpenDiceCborContext, which returns NULL.
 pub trait ContextImpl: Context + Send {
-    /// Safe wrapper around open-dice DiceDeriveCdiPrivateKeySeed, see open dice
-    /// documentation for details.
-    fn derive_cdi_private_key_seed(&mut self, cdi_attest: &[u8; CDI_SIZE]) -> Result<ZVec> {
-        let mut seed = ZVec::new(PRIVATE_KEY_SEED_SIZE)?;
-        // SAFETY:
-        // * The first context argument may be NULL and is unused by the wrapped
-        //   implementation.
-        // * The second argument is expected to be a const array of size CDI_SIZE.
-        // * The third argument is expected to be a non const array of size
-        //   PRIVATE_KEY_SEED_SIZE which is fulfilled if the call to ZVec::new above
-        //   succeeds.
-        // * No pointers are expected to be valid beyond the scope of the function
-        //   call.
-        check_result(unsafe {
-            DiceDeriveCdiPrivateKeySeed(self.get_context(), cdi_attest.as_ptr(), seed.as_mut_ptr())
-        })?;
-        Ok(seed)
-    }
-
-    /// Safe wrapper around open-dice DiceDeriveCdiCertificateId, see open dice
-    /// documentation for details.
-    fn derive_cdi_certificate_id(&mut self, cdi_public_key: &[u8]) -> Result<ZVec> {
-        let mut id = ZVec::new(ID_SIZE)?;
-        // SAFETY:
-        // * The first context argument may be NULL and is unused by the wrapped
-        //   implementation.
-        // * The second argument is expected to be a const array with a size given by the
-        //   third argument.
-        // * The fourth argument is expected to be a non const array of size
-        //   ID_SIZE which is fulfilled if the call to ZVec::new above succeeds.
-        // * No pointers are expected to be valid beyond the scope of the function
-        //   call.
-        check_result(unsafe {
-            DiceDeriveCdiCertificateId(
-                self.get_context(),
-                cdi_public_key.as_ptr(),
-                cdi_public_key.len(),
-                id.as_mut_ptr(),
-            )
-        })?;
-        Ok(id)
-    }
-
-    /// Safe wrapper around open-dice DiceMainFlow, see open dice
-    /// documentation for details.
-    /// Returns a tuple of:
-    ///  * The next attestation CDI,
-    ///  * the next seal CDI, and
-    ///  * the next attestation certificate.
-    /// `(next_attest_cdi, next_seal_cdi, next_attestation_cert)`
-    fn main_flow<T: InputValues + ?Sized>(
-        &mut self,
-        current_cdi_attest: &[u8; CDI_SIZE],
-        current_cdi_seal: &[u8; CDI_SIZE],
-        input_values: &T,
-    ) -> Result<(CdiAttest, CdiSeal, Cert)> {
-        let mut next_attest = CdiAttest::new(CDI_SIZE)?;
-        let mut next_seal = CdiSeal::new(CDI_SIZE)?;
-
-        // SAFETY (DiceMainFlow):
-        // * The first context argument may be NULL and is unused by the wrapped
-        //   implementation.
-        // * The second argument and the third argument are const arrays of size CDI_SIZE.
-        //   This is fulfilled as per the definition of the arguments `current_cdi_attest`
-        //   and `current_cdi_seal.
-        // * The fourth argument is a pointer to `DiceInputValues`. It, and its indirect
-        //   references must be valid for the duration of the function call which
-        //   is guaranteed by `call_with_input_values` which puts `DiceInputValues`
-        //   on the stack and initializes it from the `input_values` argument which
-        //   implements the `InputValues` trait.
-        // * The fifth and sixth argument are the length of and the pointer to the
-        //   allocated certificate buffer respectively. They are used to return
-        //   the generated certificate.
-        // * The seventh argument is a pointer to a mutable usize object. It is
-        //   used to return the actual size of the output certificate.
-        // * The eighth argument and the ninth argument are pointers to mutable buffers of size
-        //   CDI_SIZE. This is fulfilled if the allocation above succeeded.
-        // * No pointers are expected to be valid beyond the scope of the function
-        //   call.
-        call_with_input_values(input_values, |input_values| {
-            let cert = retry_while_adjusting_output_buffer(|cert, actual_size| {
-                check_result(unsafe {
-                    DiceMainFlow(
-                        self.get_context(),
-                        current_cdi_attest.as_ptr(),
-                        current_cdi_seal.as_ptr(),
-                        input_values,
-                        cert.len(),
-                        cert.as_mut_ptr(),
-                        actual_size as *mut _,
-                        next_attest.as_mut_ptr(),
-                        next_seal.as_mut_ptr(),
-                    )
-                })
-            })?;
-            Ok((next_attest, next_seal, cert))
-        })
-    }
-
-    /// Safe wrapper around open-dice DiceHash, see open dice
-    /// documentation for details.
-    fn hash(&mut self, input: &[u8]) -> Result<Vec<u8>> {
-        let mut output: Vec<u8> = vec![0; HASH_SIZE];
-
-        // SAFETY:
-        // * The first context argument may be NULL and is unused by the wrapped
-        //   implementation.
-        // * The second argument and the third argument are the pointer to and length of the given
-        //   input buffer respectively.
-        // * The fourth argument must be a pointer to a mutable buffer of size HASH_SIZE
-        //   which is fulfilled by the allocation above.
-        check_result(unsafe {
-            DiceHash(self.get_context(), input.as_ptr(), input.len(), output.as_mut_ptr())
-        })?;
-        Ok(output)
-    }
-
-    /// Safe wrapper around open-dice DiceKdf, see open dice
-    /// documentation for details.
-    fn kdf(&mut self, length: usize, input_key: &[u8], salt: &[u8], info: &[u8]) -> Result<ZVec> {
-        let mut output = ZVec::new(length)?;
-
-        // SAFETY:
-        // * The first context argument may be NULL and is unused by the wrapped
-        //   implementation.
-        // * The second argument is primitive.
-        // * The third argument and the fourth argument are the pointer to and length of the given
-        //   input key.
-        // * The fifth argument and the sixth argument are the pointer to and length of the given
-        //   salt.
-        // * The seventh argument and the eighth argument are the pointer to and length of the
-        //   given info field.
-        // * The ninth argument is a pointer to the output buffer which must have the
-        //   length given by the `length` argument (see second argument). This is
-        //   fulfilled if the allocation of `output` succeeds.
-        // * All pointers must be valid for the duration of the function call, but not
-        //   longer.
-        check_result(unsafe {
-            DiceKdf(
-                self.get_context(),
-                length,
-                input_key.as_ptr(),
-                input_key.len(),
-                salt.as_ptr(),
-                salt.len(),
-                info.as_ptr(),
-                info.len(),
-                output.as_mut_ptr(),
-            )
-        })?;
-        Ok(output)
-    }
-
     /// Safe wrapper around open-dice DiceKeyPairFromSeed, see open dice
     /// documentation for details.
     fn keypair_from_seed(&mut self, seed: &[u8; PRIVATE_KEY_SEED_SIZE]) -> Result<(Vec<u8>, ZVec)> {
@@ -633,162 +182,6 @@
             )
         })
     }
-
-    /// Safe wrapper around open-dice DiceGenerateCertificate, see open dice
-    /// documentation for details.
-    fn generate_certificate<T: InputValues>(
-        &mut self,
-        subject_private_key_seed: &[u8; PRIVATE_KEY_SEED_SIZE],
-        authority_private_key_seed: &[u8; PRIVATE_KEY_SEED_SIZE],
-        input_values: &T,
-    ) -> Result<Vec<u8>> {
-        // SAFETY (DiceMainFlow):
-        // * The first context argument may be NULL and is unused by the wrapped
-        //   implementation.
-        // * The second argument and the third argument are const arrays of size
-        //   `PRIVATE_KEY_SEED_SIZE`. This is fulfilled as per the definition of the arguments.
-        // * The fourth argument is a pointer to `DiceInputValues` it, and its indirect
-        //   references must be valid for the duration of the function call which
-        //   is guaranteed by `call_with_input_values` which puts `DiceInputValues`
-        //   on the stack and initializes it from the `input_values` argument which
-        //   implements the `InputValues` trait.
-        // * The fifth argument and the sixth argument are the length of and the pointer to the
-        //   allocated certificate buffer respectively. They are used to return
-        //   the generated certificate.
-        // * The seventh argument is a pointer to a mutable usize object. It is
-        //   used to return the actual size of the output certificate.
-        // * All pointers must be valid for the duration of the function call but not beyond.
-        call_with_input_values(input_values, |input_values| {
-            let cert = retry_while_adjusting_output_buffer(|cert, actual_size| {
-                check_result(unsafe {
-                    DiceGenerateCertificate(
-                        self.get_context(),
-                        subject_private_key_seed.as_ptr(),
-                        authority_private_key_seed.as_ptr(),
-                        input_values,
-                        cert.len(),
-                        cert.as_mut_ptr(),
-                        actual_size as *mut _,
-                    )
-                })
-            })?;
-            Ok(cert)
-        })
-    }
-
-    /// Safe wrapper around open-dice BccDiceMainFlow, see open dice
-    /// documentation for details.
-    /// Returns a tuple of:
-    ///  * The next attestation CDI,
-    ///  * the next seal CDI, and
-    ///  * the next bcc adding the new certificate to the given bcc.
-    /// `(next_attest_cdi, next_seal_cdi, next_bcc)`
-    fn bcc_main_flow<T: InputValues + ?Sized>(
-        &mut self,
-        current_cdi_attest: &[u8; CDI_SIZE],
-        current_cdi_seal: &[u8; CDI_SIZE],
-        bcc: &[u8],
-        input_values: &T,
-    ) -> Result<(CdiAttest, CdiSeal, Bcc)> {
-        let mut next_attest = CdiAttest::new(CDI_SIZE)?;
-        let mut next_seal = CdiSeal::new(CDI_SIZE)?;
-
-        // SAFETY (BccMainFlow):
-        // * The first context argument may be NULL and is unused by the wrapped
-        //   implementation.
-        // * The second argument and the third argument are const arrays of size CDI_SIZE.
-        //   This is fulfilled as per the definition of the arguments `current_cdi_attest`
-        //   and `current_cdi_seal`.
-        // * The fourth argument and the fifth argument are the pointer to and size of the buffer
-        //   holding the current bcc.
-        // * The sixth argument is a pointer to `DiceInputValues` it, and its indirect
-        //   references must be valid for the duration of the function call which
-        //   is guaranteed by `call_with_input_values` which puts `DiceInputValues`
-        //   on the stack and initializes it from the `input_values` argument which
-        //   implements the `InputValues` trait.
-        // * The seventh argument and the eighth argument are the length of and the pointer to the
-        //   allocated certificate buffer respectively. They are used to return the generated
-        //   certificate.
-        // * The ninth argument is a pointer to a mutable usize object. It is
-        //   used to return the actual size of the output certificate.
-        // * The tenth argument and the eleventh argument are pointers to mutable buffers of
-        //   size CDI_SIZE. This is fulfilled if the allocation above succeeded.
-        // * No pointers are expected to be valid beyond the scope of the function
-        //   call.
-        call_with_input_values(input_values, |input_values| {
-            let next_bcc = retry_while_adjusting_output_buffer(|next_bcc, actual_size| {
-                check_result(unsafe {
-                    BccMainFlow(
-                        self.get_context(),
-                        current_cdi_attest.as_ptr(),
-                        current_cdi_seal.as_ptr(),
-                        bcc.as_ptr(),
-                        bcc.len(),
-                        input_values,
-                        next_bcc.len(),
-                        next_bcc.as_mut_ptr(),
-                        actual_size as *mut _,
-                        next_attest.as_mut_ptr(),
-                        next_seal.as_mut_ptr(),
-                    )
-                })
-            })?;
-            Ok((next_attest, next_seal, next_bcc))
-        })
-    }
-}
-
-/// This submodule provides additional support for the Boot Certificate Chain (BCC)
-/// specification.
-/// See https://cs.android.com/android/platform/superproject/+/master:hardware/interfaces/security/keymint/aidl/android/hardware/security/keymint/ProtectedData.aidl
-pub mod bcc {
-    use super::{check_result, retry_while_adjusting_output_buffer, Result};
-    use open_dice_bcc_bindgen::{
-        BccConfigValues, BccFormatConfigDescriptor, BCC_INPUT_COMPONENT_NAME,
-        BCC_INPUT_COMPONENT_VERSION, BCC_INPUT_RESETTABLE,
-    };
-    use std::ffi::CString;
-
-    /// Safe wrapper around BccFormatConfigDescriptor, see open dice documentation for details.
-    pub fn format_config_descriptor(
-        component_name: Option<&str>,
-        component_version: Option<u64>,
-        resettable: bool,
-    ) -> Result<Vec<u8>> {
-        let component_name = match component_name {
-            Some(n) => Some(CString::new(n)?),
-            None => None,
-        };
-        let input = BccConfigValues {
-            inputs: if component_name.is_some() { BCC_INPUT_COMPONENT_NAME } else { 0 }
-                | if component_version.is_some() { BCC_INPUT_COMPONENT_VERSION } else { 0 }
-                | if resettable { BCC_INPUT_RESETTABLE } else { 0 },
-            // SAFETY: The as_ref() in the line below is vital to keep the component_name object
-            //         alive. Removing as_ref will move the component_name and the pointer will
-            //         become invalid after this statement.
-            component_name: component_name.as_ref().map_or(std::ptr::null(), |s| s.as_ptr()),
-            component_version: component_version.unwrap_or(0),
-        };
-
-        // SAFETY:
-        // * The first argument is a pointer to the BccConfigValues input assembled above.
-        //   It and its indirections must be valid for the duration of the function call.
-        // * The second argument and the third argument are the length of and the pointer to the
-        //   allocated output buffer respectively. The buffer must be at least as long
-        //   as indicated by the size argument.
-        // * The forth argument is a pointer to the actual size returned by the function.
-        // * All pointers must be valid for the duration of the function call but not beyond.
-        retry_while_adjusting_output_buffer(|config_descriptor, actual_size| {
-            check_result(unsafe {
-                BccFormatConfigDescriptor(
-                    &input as *const BccConfigValues,
-                    config_descriptor.len(),
-                    config_descriptor.as_mut_ptr(),
-                    actual_size as *mut _,
-                )
-            })
-        })
-    }
 }
 
 #[cfg(test)]
@@ -840,12 +233,12 @@
     #[test]
     fn hash_derive_sign_verify() {
         let mut ctx = OpenDiceCborContext::new();
-        let seed = ctx.hash("MySeedString".as_bytes()).unwrap();
+        let seed = diced_open_dice::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();
+            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();
@@ -997,41 +390,9 @@
     // 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);
+        let dice_artifacts = make_sample_bcc_and_cdis().unwrap();
+        assert_eq!(&dice_artifacts.cdi_values.cdi_attest, SAMPLE_CDI_ATTEST_TEST_VECTOR);
+        assert_eq!(&dice_artifacts.cdi_values.cdi_seal, SAMPLE_CDI_SEAL_TEST_VECTOR);
+        assert_eq!(&dice_artifacts.bcc, SAMPLE_BCC_TEST_VECTOR);
     }
 }
diff --git a/diced/src/diced_client_test.rs b/diced/src/diced_client_test.rs
index 3915508..054b2d1 100644
--- a/diced/src/diced_client_test.rs
+++ b/diced/src/diced_client_test.rs
@@ -22,6 +22,7 @@
 use diced_open_dice_cbor as dice;
 use nix::libc::uid_t;
 use std::convert::TryInto;
+use std::ffi::CString;
 
 static DICE_NODE_SERVICE_NAME: &str = "android.security.dice.IDiceNode";
 static DICE_MAINTENANCE_SERVICE_NAME: &str = "android.security.dice.IDiceMaintenance";
@@ -52,11 +53,7 @@
         diced_utils::ResidentArtifacts::new(&former.cdiAttest, &former.cdiSeal, &former.bcc.data)
             .unwrap();
 
-    let input_values: Vec<diced_utils::InputValues> =
-        input_values.iter().map(|v| v.into()).collect();
-
-    let artifacts =
-        artifacts.execute_steps(input_values.iter().map(|v| v as &dyn dice::InputValues)).unwrap();
+    let artifacts = artifacts.execute_steps(input_values.iter()).unwrap();
     let (cdi_attest, cdi_seal, bcc) = artifacts.into_tuple();
     let from_former = diced_utils::make_bcc_handover(
         cdi_attest[..].try_into().unwrap(),
@@ -96,11 +93,7 @@
     )
     .unwrap();
 
-    let input_values: Vec<diced_utils::InputValues> =
-        input_values.iter().map(|v| v.into()).collect();
-
-    let artifacts =
-        artifacts.execute_steps(input_values.iter().map(|v| v as &dyn dice::InputValues)).unwrap();
+    let artifacts = artifacts.execute_steps(input_values.iter()).unwrap();
     let (cdi_attest, cdi_seal, bcc) = artifacts.into_tuple();
     let from_former = diced_utils::make_bcc_handover(
         cdi_attest[..].try_into().unwrap(),
@@ -114,10 +107,11 @@
 }
 
 fn client_input_values(uid: uid_t) -> BinderInputValues {
+    let desc = CString::new(format!("{}", uid)).unwrap();
     BinderInputValues {
         codeHash: [0; dice::HASH_SIZE],
         config: BinderConfig {
-            desc: dice::bcc::format_config_descriptor(Some(&format!("{}", uid)), None, true)
+            desc: dice::retry_bcc_format_config_descriptor(Some(desc.as_c_str()), None, true)
                 .unwrap(),
         },
         authorityHash: [0; dice::HASH_SIZE],
@@ -160,11 +154,8 @@
     .unwrap();
 
     let client = [client];
-    let input_values: Vec<diced_utils::InputValues> =
-        input_values.iter().chain(client.iter()).map(|v| v.into()).collect();
 
-    let artifacts =
-        artifacts.execute_steps(input_values.iter().map(|v| v as &dyn dice::InputValues)).unwrap();
+    let artifacts = artifacts.execute_steps(input_values.iter().chain(client.iter())).unwrap();
     let (cdi_attest, cdi_seal, bcc) = artifacts.into_tuple();
     let from_former = diced_utils::make_bcc_handover(
         cdi_attest[..].try_into().unwrap(),
diff --git a/diced/src/diced_main.rs b/diced/src/diced_main.rs
deleted file mode 100644
index c2cf02c..0000000
--- a/diced/src/diced_main.rs
+++ /dev/null
@@ -1,76 +0,0 @@
-// 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
deleted file mode 100644
index 3e230e4..0000000
--- a/diced/src/error.rs
+++ /dev/null
@@ -1,123 +0,0 @@
-// 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::{ExceptionCode, Result as BinderResult, 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/hal_node.rs b/diced/src/hal_node.rs
index 69cf4ac..ca470e5 100644
--- a/diced/src/hal_node.rs
+++ b/diced/src/hal_node.rs
@@ -187,10 +187,8 @@
         // `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.into()).collect();
             let artifacts = artifacts
-                .execute_steps(input_values.iter().map(|v| v as &dyn dice::InputValues))
+                .execute_steps(input_values)
                 .context("In ResidentHal::get_effective_artifacts:")?;
             f(artifacts)
         })
@@ -205,14 +203,15 @@
             .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(|| {
+                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.")?;
+                    })?,
+                )
+                .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!(
@@ -279,11 +278,8 @@
         *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.into()).collect();
-
             let new_artifacts = new_artifacts
-                .execute_steps(input_values.iter().map(|v| v as &dyn dice::InputValues))
+                .execute_steps(input_values)
                 .context("In ResidentHal::get_effective_artifacts:")?;
             artifacts_clone.update(&new_artifacts)
         })?;
@@ -338,6 +334,7 @@
     use diced_open_dice_cbor as dice;
     use diced_sample_inputs;
     use diced_utils as utils;
+    use std::ffi::CStr;
 
     #[derive(Debug, Serialize, Deserialize, Clone)]
     struct InsecureSerializableArtifacts {
@@ -346,6 +343,16 @@
         bcc: Vec<u8>,
     }
 
+    impl From<dice::OwnedDiceArtifacts> for InsecureSerializableArtifacts {
+        fn from(dice_artifacts: dice::OwnedDiceArtifacts) -> Self {
+            Self {
+                cdi_attest: dice_artifacts.cdi_values.cdi_attest,
+                cdi_seal: dice_artifacts.cdi_values.cdi_seal,
+                bcc: dice_artifacts.bcc[..].to_vec(),
+            }
+        }
+    }
+
     impl DiceArtifacts for InsecureSerializableArtifacts {
         fn cdi_attest(&self) -> &[u8; dice::CDI_SIZE] {
             &self.cdi_attest
@@ -376,25 +383,18 @@
 
     fn make_input_values(
         code: &str,
-        config_name: &str,
+        config_name: &CStr,
         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.")?
-                .as_slice()
-                .try_into()?,
+            codeHash: dice::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)
+                desc: dice::retry_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.")?
-                .as_slice()
-                .try_into()?,
+            authorityHash: dice::hash(authority.as_bytes())
+                .context("In make_input_values: authority hash failed.")?,
             authorityDescriptor: None,
             mode: BinderMode::NORMAL,
             hidden: [0; dice::HIDDEN_SIZE],
@@ -404,21 +404,27 @@
     /// 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 artifacts: ResidentArtifacts =
+            diced_sample_inputs::make_sample_bcc_and_cdis()?.try_into()?;
 
         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")?,
+            make_input_values(
+                "component 1 code",
+                CStr::from_bytes_with_nul(b"component 1\0").unwrap(),
+                "component 1 authority",
+            )?,
+            make_input_values(
+                "component 2 code",
+                CStr::from_bytes_with_nul(b"component 2\0").unwrap(),
+                "component 2 authority",
+            )?,
+            make_input_values(
+                "component 3 code",
+                CStr::from_bytes_with_nul(b"component 3\0").unwrap(),
+                "component 3 authority",
+            )?,
         ];
-
-        let input_values: Vec<utils::InputValues> = input_values.iter().map(|v| v.into()).collect();
-
-        let new_artifacts =
-            artifacts.execute_steps(input_values.iter().map(|v| v as &dyn dice::InputValues))?;
+        let new_artifacts = artifacts.execute_steps(input_values)?;
 
         let result = utils::make_bcc_handover(
             new_artifacts.cdi_attest(),
@@ -435,24 +441,31 @@
     /// 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()?;
+        let dice_artifacts = 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 hal_impl =
+            unsafe { ResidentHal::new(InsecureSerializableArtifacts::from(dice_artifacts)) }
+                .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")?,
+                make_input_values(
+                    "component 1 code",
+                    CStr::from_bytes_with_nul(b"component 1\0").unwrap(),
+                    "component 1 authority",
+                )?,
+                make_input_values(
+                    "component 2 code",
+                    CStr::from_bytes_with_nul(b"component 2\0").unwrap(),
+                    "component 2 authority",
+                )?,
+                make_input_values(
+                    "component 3 code",
+                    CStr::from_bytes_with_nul(b"component 3\0").unwrap(),
+                    "component 3 authority",
+                )?,
             ])
             .expect("Failed to derive artifacts.");
 
@@ -464,30 +477,33 @@
     /// 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()?;
+        let dice_artifacts = 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 hal_impl =
+            unsafe { ResidentHal::new(InsecureSerializableArtifacts::from(dice_artifacts)) }
+                .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")?,
+                make_input_values(
+                    "component 1 code",
+                    CStr::from_bytes_with_nul(b"component 1\0").unwrap(),
+                    "component 1 authority",
+                )?,
+                make_input_values(
+                    "component 2 code",
+                    CStr::from_bytes_with_nul(b"component 2\0").unwrap(),
+                    "component 2 authority",
+                )?,
             ])
             .expect("Failed to demote implementation.");
 
         let bcc_handover = hal_impl
             .derive(&[make_input_values(
                 "component 3 code",
-                "component 3",
+                CStr::from_bytes_with_nul(b"component 3\0").unwrap(),
                 "component 3 authority",
             )?])
             .expect("Failed to derive artifacts.");
diff --git a/diced/src/lib.rs b/diced/src/lib.rs
deleted file mode 100644
index 50e0e96..0000000
--- a/diced/src/lib.rs
+++ /dev/null
@@ -1,203 +0,0 @@
-// 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::{BinderFeatures, Result as BinderResult, 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: [0; dice::HASH_SIZE],
-        config: BinderConfig {
-            desc: dice::bcc::format_config_descriptor(Some(&format!("{}", uid)), None, false)
-                .context("In client_input_values: failed to format config descriptor")?,
-        },
-        authorityHash: [0; dice::HASH_SIZE],
-        authorityDescriptor: None,
-        hidden: [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/permission.rs b/diced/src/permission.rs
deleted file mode 100644
index 62ca653..0000000
--- a/diced/src/permission.rs
+++ /dev/null
@@ -1,46 +0,0 @@
-// 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, Eq)]
-    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
deleted file mode 100644
index 8d883d2..0000000
--- a/diced/src/proxy_node_hal.rs
+++ /dev/null
@@ -1,119 +0,0 @@
-// 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::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
deleted file mode 100644
index 99a6dc9..0000000
--- a/diced/src/resident_node.rs
+++ /dev/null
@@ -1,191 +0,0 @@
-// 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.into())
-            .collect();
-
-        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
index ff239ed..802a6d3 100644
--- a/diced/src/sample_inputs.rs
+++ b/diced/src/sample_inputs.rs
@@ -21,10 +21,9 @@
 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 diced_utils::{cbor, to_dice_input_values};
+use std::convert::TryInto;
+use std::ffi::CStr;
 use std::io::Write;
 
 /// Sample UDS used to perform the root dice flow by `make_sample_bcc_and_cdis`.
@@ -66,10 +65,9 @@
 
 /// 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>)> {
+pub fn make_sample_bcc_and_cdis() -> Result<dice::OwnedDiceArtifacts> {
     let mut dice_ctx = dice::OpenDiceCborContext::new();
-    let private_key_seed = dice_ctx
-        .derive_cdi_private_key_seed(UDS)
+    let private_key_seed = dice::derive_cdi_private_key_seed(UDS)
         .context("In make_sample_bcc_and_cdis: Trying to derive private key seed.")?;
 
     let (public_key, _) =
@@ -81,14 +79,9 @@
 
     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 (cdi_values, mut cert) =
+        dice::retry_dice_main_flow(UDS, UDS, &to_dice_input_values(&input_values_vector[0]))
+            .context("In make_sample_bcc_and_cdis: Trying to run first main flow.")?;
 
     let mut bcc: Vec<u8> = vec![];
 
@@ -99,56 +92,44 @@
 
     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.")
+    let dice_artifacts = dice::retry_bcc_main_flow(
+        &cdi_values.cdi_attest,
+        &cdi_values.cdi_seal,
+        &bcc,
+        &to_dice_input_values(&input_values_vector[1]),
+    )
+    .context("In make_sample_bcc_and_cdis: Trying to run first bcc main flow.")?;
+    dice::retry_bcc_main_flow(
+        &dice_artifacts.cdi_values.cdi_attest,
+        &dice_artifacts.cdi_values.cdi_seal,
+        &dice_artifacts.bcc,
+        &to_dice_input_values(&input_values_vector[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,
+    code_hash: dice::Hash,
+    authority_hash: dice::Hash,
+    config_name: &CStr,
     config_version: u64,
     config_resettable: bool,
     mode: Mode,
-    hidden: &[u8; dice::HIDDEN_SIZE],
+    hidden: dice::Hidden,
 ) -> Result<BinderInputValues> {
     Ok(BinderInputValues {
-        codeHash: *code_hash,
+        codeHash: code_hash,
         config: BinderConfig {
-            desc: dice::bcc::format_config_descriptor(
+            desc: dice::retry_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,
+        authorityHash: authority_hash,
         authorityDescriptor: None,
-        hidden: *hidden,
+        hidden,
         mode,
     })
 }
@@ -156,90 +137,84 @@
 /// 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> {
+    const CODE_HASH1: [u8; dice::HASH_SIZE] = [
+        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,
+    ];
+    const AUTHORITY_HASH1: [u8; dice::HASH_SIZE] = [
+        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,
+    ];
+    const HIDDEN1: [u8; dice::HIDDEN_SIZE] = [
+        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,
+    ];
+    const CODE_HASH2: [u8; dice::HASH_SIZE] = [
+        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,
+    ];
+    const AUTHORITY_HASH2: [u8; dice::HASH_SIZE] = [
+        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,
+    ];
+    const HIDDEN2: [u8; dice::HIDDEN_SIZE] = [
+        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,
+    ];
+    const AUTHORITY_HASH3: [u8; dice::HASH_SIZE] = [
+        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,
+    ];
     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
+            CODE_HASH1,
+            AUTHORITY_HASH1,
+            CStr::from_bytes_with_nul(b"ABL\0").unwrap(), // 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,
-            ],
+            HIDDEN1,
         )
         .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
+            CODE_HASH2,
+            AUTHORITY_HASH2,
+            CStr::from_bytes_with_nul(b"AVB\0").unwrap(), // 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,
-            ],
+            HIDDEN2,
         )
         .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
+            [0; dice::HASH_SIZE], // code hash
+            AUTHORITY_HASH3,
+            CStr::from_bytes_with_nul(b"Android\0").unwrap(), // config name
+            12,                                               // config version
+            true,                                             // resettable
             Mode::NORMAL,
-            &[
-                // hidden
-                0; dice::HIDDEN_SIZE
-            ],
+            [0; dice::HIDDEN_SIZE], // hidden,
         )
         .unwrap(),
     ]
diff --git a/diced/src/utils.rs b/diced/src/utils.rs
index 37f78ac..c249366 100644
--- a/diced/src/utils.rs
+++ b/diced/src/utils.rs
@@ -19,63 +19,31 @@
     Mode::Mode as BinderMode,
 };
 use anyhow::{Context, Result};
-use dice::ContextImpl;
 use diced_open_dice_cbor as dice;
 use keystore2_crypto::ZVec;
 use std::convert::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> From<&'a BinderInputValues> for InputValues<'a> {
-    fn from(input_values: &'a BinderInputValues) -> InputValues<'a> {
-        Self(input_values)
+/// Converts the `InputValues` from the binder to the `InputValues` type in `diced_open_dice` crate.
+pub fn to_dice_input_values(input: &BinderInputValues) -> dice::InputValues {
+    if input.authorityDescriptor.is_some() {
+        unimplemented!("Authority descriptor is not yet implemented in the current library.");
     }
+    dice::InputValues::new(
+        input.codeHash,
+        dice::Config::Descriptor(input.config.desc.as_slice()),
+        input.authorityHash,
+        to_dice_mode(input.mode),
+        input.hidden,
+    )
 }
 
-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] {
-        &self.0.codeHash
-    }
-
-    fn config(&self) -> dice::Config {
-        dice::Config::Descriptor(self.0.config.desc.as_slice())
-    }
-
-    fn authority_hash(&self) -> &[u8; dice::HASH_SIZE] {
-        &self.0.authorityHash
-    }
-
-    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
+fn to_dice_mode(binder_mode: BinderMode) -> dice::DiceMode {
+    match binder_mode {
+        BinderMode::NOT_INITIALIZED => dice::DiceMode::kDiceModeNotInitialized,
+        BinderMode::NORMAL => dice::DiceMode::kDiceModeNormal,
+        BinderMode::DEBUG => dice::DiceMode::kDiceModeDebug,
+        BinderMode::RECOVERY => dice::DiceMode::kDiceModeMaintenance,
+        _ => dice::DiceMode::kDiceModeNotInitialized,
     }
 }
 
@@ -99,6 +67,18 @@
     bcc: Vec<u8>,
 }
 
+impl TryFrom<dice::OwnedDiceArtifacts> for ResidentArtifacts {
+    type Error = anyhow::Error;
+
+    fn try_from(dice_artifacts: dice::OwnedDiceArtifacts) -> Result<Self, Self::Error> {
+        Ok(ResidentArtifacts {
+            cdi_attest: dice_artifacts.cdi_values.cdi_attest[..].try_into()?,
+            cdi_seal: dice_artifacts.cdi_values.cdi_seal[..].try_into()?,
+            bcc: dice_artifacts.bcc[..].to_vec(),
+        })
+    }
+}
+
 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
@@ -153,33 +133,32 @@
         (cdi_attest, cdi_seal, bcc)
     }
 
-    fn execute_step(self, input_values: &dyn dice::InputValues) -> Result<Self> {
+    fn execute_step(self, input_values: &BinderInputValues) -> 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 })
+        dice::retry_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,
+            &to_dice_input_values(input_values),
+        )
+        .context("In ResidentArtifacts::execute_step:")?
+        .try_into()
     }
 
     /// 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>
+    pub fn execute_steps<'a, I>(self, input_values: I) -> Result<Self>
     where
-        Iter: IntoIterator<Item = &'a dyn dice::InputValues>,
+        I: IntoIterator<Item = &'a BinderInputValues>,
     {
         input_values
             .into_iter()
-            .try_fold(self, |acc, input_values| acc.execute_step(input_values))
+            .try_fold(self, |acc, input| acc.execute_step(input))
             .context("In ResidentArtifacts::execute_step:")
     }
 }
diff --git a/identity/CredentialData.cpp b/identity/CredentialData.cpp
index fb08333..1bf1527 100644
--- a/identity/CredentialData.cpp
+++ b/identity/CredentialData.cpp
@@ -581,13 +581,17 @@
 
     vector<vector<uint8_t>> keysNeedingCert;
 
-    int64_t nowMilliSeconds =
-        std::chrono::system_clock::to_time_t(std::chrono::system_clock::now()) * 1000;
+    time_t now = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
+    int64_t nowMilliseconds;
+    if (__builtin_mul_overflow(int64_t(now), int64_t(1000), &nowMilliseconds)) {
+        LOG(ERROR) << "Overflow converting " << now << " to milliseconds";
+        return {};
+    }
 
     for (AuthKeyData& data : authKeyDatas_) {
         bool keyExceedUseCount = (data.useCount >= maxUsesPerKey_);
         int64_t expirationDateAdjusted = data.expirationDateMillisSinceEpoch - minValidTimeMillis_;
-        bool keyBeyondAdjustedExpirationDate = (nowMilliSeconds > expirationDateAdjusted);
+        bool keyBeyondAdjustedExpirationDate = (nowMilliseconds > expirationDateAdjusted);
         bool newKeyNeeded =
             (data.certificate.size() == 0) || keyExceedUseCount || keyBeyondAdjustedExpirationDate;
         bool certificationPending = (data.pendingCertificate.size() > 0);
diff --git a/identity/RemotelyProvisionedKey.cpp b/identity/RemotelyProvisionedKey.cpp
index 7e90d63..784a680 100644
--- a/identity/RemotelyProvisionedKey.cpp
+++ b/identity/RemotelyProvisionedKey.cpp
@@ -21,6 +21,7 @@
 #include <android-base/logging.h>
 #include <android/security/rkp/BnGetKeyCallback.h>
 #include <android/security/rkp/BnGetRegistrationCallback.h>
+#include <android/security/rkp/IGetKeyCallback.h>
 #include <android/security/rkp/IRemoteProvisioning.h>
 #include <binder/IServiceManager.h>
 #include <binder/Status.h>
@@ -38,6 +39,7 @@
 using ::android::hardware::security::keymint::RpcHardwareInfo;
 using ::android::security::rkp::BnGetKeyCallback;
 using ::android::security::rkp::BnGetRegistrationCallback;
+using ::android::security::rkp::IGetKeyCallback;
 using ::android::security::rkp::IRegistration;
 using ::android::security::rkp::IRemoteProvisioning;
 using ::android::security::rkp::RemotelyProvisionedKey;
@@ -96,11 +98,11 @@
         keyPromise_.set_value(std::nullopt);
         return Status::ok();
     }
-    Status onError(const String16& error) override {
+    Status onError(IGetKeyCallback::ErrorCode error, const String16& description) override {
         if (called_.test_and_set()) {
             return Status::ok();
         }
-        LOG(ERROR) << "GetKeyCallback failed: " << error;
+        LOG(ERROR) << "GetKeyCallback failed: " << static_cast<int>(error) << ", " << description;
         keyPromise_.set_value(std::nullopt);
         return Status::ok();
     }
@@ -124,7 +126,8 @@
         auto cb = sp<GetKeyCallback>::make(std::move(keyPromise_));
         auto status = registration->getKey(keyId_, cb);
         if (!status.isOk()) {
-            cb->onError(String16("Failed to register GetKeyCallback"));
+            cb->onError(IGetKeyCallback::ErrorCode::ERROR_UNKNOWN,
+                        String16("Failed to register GetKeyCallback"));
         }
         return Status::ok();
     }
diff --git a/keystore-engine/keystore2_engine.cpp b/keystore-engine/keystore2_engine.cpp
index 69caf51..dc90be3 100644
--- a/keystore-engine/keystore2_engine.cpp
+++ b/keystore-engine/keystore2_engine.cpp
@@ -146,11 +146,13 @@
         return nullptr;
     }
 
-    rsa->n = BN_dup(public_rsa->n);
-    rsa->e = BN_dup(public_rsa->e);
-    if (rsa->n == nullptr || rsa->e == nullptr) {
+    bssl::UniquePtr<BIGNUM> n(BN_dup(RSA_get0_n(public_rsa)));
+    bssl::UniquePtr<BIGNUM> e(BN_dup(RSA_get0_e(public_rsa)));
+    if (n == nullptr || e == nullptr || !RSA_set0_key(rsa.get(), n.get(), e.get(), nullptr)) {
         return nullptr;
     }
+    OWNERSHIP_TRANSFERRED(n);
+    OWNERSHIP_TRANSFERRED(e);
 
     bssl::UniquePtr<EVP_PKEY> result(EVP_PKEY_new());
     if (result.get() == nullptr || !EVP_PKEY_assign_RSA(result.get(), rsa.get())) {
@@ -420,19 +422,19 @@
         Keystore2KeyBackend{response.metadata.key, response.iSecurityLevel});
 
     bssl::UniquePtr<EVP_PKEY> result;
-    switch (EVP_PKEY_type(pkey->type)) {
+    switch (EVP_PKEY_id(pkey.get())) {
     case EVP_PKEY_RSA: {
-        bssl::UniquePtr<RSA> public_rsa(EVP_PKEY_get1_RSA(pkey.get()));
-        result = wrap_rsa(key_backend, public_rsa.get());
+        RSA* public_rsa = EVP_PKEY_get0_RSA(pkey.get());
+        result = wrap_rsa(key_backend, public_rsa);
         break;
     }
     case EVP_PKEY_EC: {
-        bssl::UniquePtr<EC_KEY> public_ecdsa(EVP_PKEY_get1_EC_KEY(pkey.get()));
-        result = wrap_ecdsa(key_backend, public_ecdsa.get());
+        EC_KEY* public_ecdsa = EVP_PKEY_get0_EC_KEY(pkey.get());
+        result = wrap_ecdsa(key_backend, public_ecdsa);
         break;
     }
     default:
-        LOG(ERROR) << AT << "Unsupported key type " << EVP_PKEY_type(pkey->type);
+        LOG(ERROR) << AT << "Unsupported key type " << EVP_PKEY_id(pkey.get());
         return nullptr;
     }
 
diff --git a/keystore2/src/error.rs b/keystore2/src/error.rs
index d1d58a4..3ca3942 100644
--- a/keystore2/src/error.rs
+++ b/keystore2/src/error.rs
@@ -71,11 +71,6 @@
     pub fn perm() -> Self {
         Error::Rc(ResponseCode::PERMISSION_DENIED)
     }
-
-    /// Short hand for `Error::Rc(ResponseCode::OUT_OF_KEYS_TRANSIENT_ERROR)`
-    pub fn out_of_keys() -> Self {
-        Error::Rc(ResponseCode::OUT_OF_KEYS_TRANSIENT_ERROR)
-    }
 }
 
 /// Helper function to map the binder status we get from calls into KeyMint
diff --git a/keystore2/src/rkpd_client.rs b/keystore2/src/rkpd_client.rs
index ecde4e8..f1e8e11 100644
--- a/keystore2/src/rkpd_client.rs
+++ b/keystore2/src/rkpd_client.rs
@@ -13,16 +13,15 @@
 // limitations under the License.
 
 //! Helper wrapper around RKPD interface.
-// TODO(b/264891956): Return RKP specific errors.
 
-use crate::error::{map_binder_status_code, Error};
+use crate::error::{map_binder_status_code, Error, ResponseCode};
 use crate::globals::get_remotely_provisioned_component_name;
 use crate::ks_err;
 use crate::utils::watchdog as wd;
 use android_hardware_security_keymint::aidl::android::hardware::security::keymint::SecurityLevel::SecurityLevel;
 use android_security_rkp_aidl::aidl::android::security::rkp::{
-    IGetKeyCallback::BnGetKeyCallback, IGetKeyCallback::IGetKeyCallback,
-    IGetRegistrationCallback::BnGetRegistrationCallback,
+    IGetKeyCallback::BnGetKeyCallback, IGetKeyCallback::ErrorCode::ErrorCode as GetKeyErrorCode,
+    IGetKeyCallback::IGetKeyCallback, IGetRegistrationCallback::BnGetRegistrationCallback,
     IGetRegistrationCallback::IGetRegistrationCallback, IRegistration::IRegistration,
     IRemoteProvisioning::IRemoteProvisioning,
     IStoreUpgradedKeyCallback::BnStoreUpgradedKeyCallback,
@@ -30,7 +29,6 @@
     RemotelyProvisionedKey::RemotelyProvisionedKey,
 };
 use android_security_rkp_aidl::binder::{BinderFeatures, Interface, Strong};
-use android_system_keystore2::aidl::android::system::keystore2::ResponseCode::ResponseCode;
 use anyhow::{Context, Result};
 use std::sync::Mutex;
 use std::time::Duration;
@@ -91,17 +89,17 @@
         let _wp = wd::watch_millis("IGetRegistrationCallback::onCancel", 500);
         log::warn!("IGetRegistrationCallback cancelled");
         self.registration_tx.send(
-            Err(Error::Rc(ResponseCode::OUT_OF_KEYS))
+            Err(Error::Rc(ResponseCode::OUT_OF_KEYS_TRANSIENT_ERROR))
                 .context(ks_err!("GetRegistrationCallback cancelled.")),
         );
         Ok(())
     }
-    fn onError(&self, error: &str) -> binder::Result<()> {
+    fn onError(&self, description: &str) -> binder::Result<()> {
         let _wp = wd::watch_millis("IGetRegistrationCallback::onError", 500);
-        log::error!("IGetRegistrationCallback failed: '{error}'");
+        log::error!("IGetRegistrationCallback failed: '{description}'");
         self.registration_tx.send(
-            Err(Error::Rc(ResponseCode::OUT_OF_KEYS))
-                .context(ks_err!("GetRegistrationCallback failed: {:?}", error)),
+            Err(Error::Rc(ResponseCode::OUT_OF_KEYS_TRANSIENT_ERROR))
+                .context(ks_err!("GetRegistrationCallback failed: {:?}", description)),
         );
         Ok(())
     }
@@ -161,17 +159,33 @@
         let _wp = wd::watch_millis("IGetKeyCallback::onCancel", 500);
         log::warn!("IGetKeyCallback cancelled");
         self.key_tx.send(
-            Err(Error::Rc(ResponseCode::OUT_OF_KEYS)).context(ks_err!("GetKeyCallback cancelled.")),
+            Err(Error::Rc(ResponseCode::OUT_OF_KEYS_TRANSIENT_ERROR))
+                .context(ks_err!("GetKeyCallback cancelled.")),
         );
         Ok(())
     }
-    fn onError(&self, error: &str) -> binder::Result<()> {
+    fn onError(&self, error: GetKeyErrorCode, description: &str) -> binder::Result<()> {
         let _wp = wd::watch_millis("IGetKeyCallback::onError", 500);
-        log::error!("IGetKeyCallback failed: {error}");
-        self.key_tx.send(
-            Err(Error::Rc(ResponseCode::OUT_OF_KEYS))
-                .context(ks_err!("GetKeyCallback failed: {:?}", error)),
-        );
+        log::error!("IGetKeyCallback failed: {description}");
+        let rc = match error {
+            GetKeyErrorCode::ERROR_UNKNOWN => ResponseCode::OUT_OF_KEYS_TRANSIENT_ERROR,
+            GetKeyErrorCode::ERROR_PERMANENT => ResponseCode::OUT_OF_KEYS_PERMANENT_ERROR,
+            GetKeyErrorCode::ERROR_PENDING_INTERNET_CONNECTIVITY => {
+                ResponseCode::OUT_OF_KEYS_PENDING_INTERNET_CONNECTIVITY
+            }
+            GetKeyErrorCode::ERROR_REQUIRES_SECURITY_PATCH => {
+                ResponseCode::OUT_OF_KEYS_REQUIRES_SYSTEM_UPGRADE
+            }
+            _ => {
+                log::error!("Unexpected error from rkpd: {error:?}");
+                ResponseCode::OUT_OF_KEYS_TRANSIENT_ERROR
+            }
+        };
+        self.key_tx.send(Err(Error::Rc(rc)).context(ks_err!(
+            "GetKeyCallback failed: {:?} {:?}",
+            error,
+            description
+        )));
         Ok(())
     }
 }
@@ -188,7 +202,7 @@
         .context(ks_err!("Trying to get key."))?;
 
     match timeout(RKPD_TIMEOUT, rx).await {
-        Err(e) => Err(Error::Rc(ResponseCode::OUT_OF_KEYS))
+        Err(e) => Err(Error::Rc(ResponseCode::OUT_OF_KEYS_TRANSIENT_ERROR))
             .context(ks_err!("Waiting for RKPD key timed out: {:?}", e)),
         Ok(v) => v.unwrap(),
     }
@@ -298,6 +312,7 @@
     };
     use android_security_rkp_aidl::aidl::android::security::rkp::IRegistration::BnRegistration;
     use keystore2_crypto::parse_subject_from_certificate;
+    use std::collections::HashMap;
     use std::sync::atomic::{AtomicU32, Ordering};
 
     #[derive(Default)]
@@ -403,7 +418,7 @@
         let result = tokio_rt().block_on(rx).unwrap();
         assert_eq!(
             result.unwrap_err().downcast::<Error>().unwrap(),
-            Error::Rc(ResponseCode::OUT_OF_KEYS)
+            Error::Rc(ResponseCode::OUT_OF_KEYS_TRANSIENT_ERROR)
         );
     }
 
@@ -416,7 +431,7 @@
         let result = tokio_rt().block_on(rx).unwrap();
         assert_eq!(
             result.unwrap_err().downcast::<Error>().unwrap(),
-            Error::Rc(ResponseCode::OUT_OF_KEYS)
+            Error::Rc(ResponseCode::OUT_OF_KEYS_TRANSIENT_ERROR)
         );
     }
 
@@ -441,21 +456,38 @@
         let result = tokio_rt().block_on(rx).unwrap();
         assert_eq!(
             result.unwrap_err().downcast::<Error>().unwrap(),
-            Error::Rc(ResponseCode::OUT_OF_KEYS)
+            Error::Rc(ResponseCode::OUT_OF_KEYS_TRANSIENT_ERROR)
         );
     }
 
     #[test]
     fn test_get_key_cb_error() {
-        let (tx, rx) = oneshot::channel();
-        let cb = GetKeyCallback::new_native_binder(tx);
-        assert!(cb.onError("error").is_ok());
+        let error_mapping = HashMap::from([
+            (GetKeyErrorCode::ERROR_UNKNOWN, ResponseCode::OUT_OF_KEYS_TRANSIENT_ERROR),
+            (GetKeyErrorCode::ERROR_PERMANENT, ResponseCode::OUT_OF_KEYS_PERMANENT_ERROR),
+            (
+                GetKeyErrorCode::ERROR_PENDING_INTERNET_CONNECTIVITY,
+                ResponseCode::OUT_OF_KEYS_PENDING_INTERNET_CONNECTIVITY,
+            ),
+            (
+                GetKeyErrorCode::ERROR_REQUIRES_SECURITY_PATCH,
+                ResponseCode::OUT_OF_KEYS_REQUIRES_SYSTEM_UPGRADE,
+            ),
+        ]);
 
-        let result = tokio_rt().block_on(rx).unwrap();
-        assert_eq!(
-            result.unwrap_err().downcast::<Error>().unwrap(),
-            Error::Rc(ResponseCode::OUT_OF_KEYS)
-        );
+        // Loop over the generated list of enum values to better ensure this test stays in
+        // sync with the AIDL.
+        for get_key_error in GetKeyErrorCode::enum_values() {
+            let (tx, rx) = oneshot::channel();
+            let cb = GetKeyCallback::new_native_binder(tx);
+            assert!(cb.onError(get_key_error, "error").is_ok());
+
+            let result = tokio_rt().block_on(rx).unwrap();
+            assert_eq!(
+                result.unwrap_err().downcast::<Error>().unwrap(),
+                Error::Rc(error_mapping[&get_key_error]),
+            );
+        }
     }
 
     #[test]
@@ -503,7 +535,7 @@
             tokio_rt().block_on(get_rkpd_attestation_key_from_registration_async(&registration, 0));
         assert_eq!(
             result.unwrap_err().downcast::<Error>().unwrap(),
-            Error::Rc(ResponseCode::OUT_OF_KEYS)
+            Error::Rc(ResponseCode::OUT_OF_KEYS_TRANSIENT_ERROR)
         );
     }
 
@@ -590,6 +622,9 @@
 
         let new_key =
             get_rkpd_attestation_key(&SecurityLevel::TRUSTED_ENVIRONMENT, key_id).unwrap();
+
+        // Restore original key so that we don't leave RKPD with invalid blobs.
+        assert!(store_rkpd_attestation_key(&sec_level, &new_blob, &key.keyBlob).is_ok());
         assert_eq!(new_key.keyBlob, new_blob);
     }
 
@@ -651,4 +686,28 @@
             println!("RKPD key was NOT upgraded.");
         }
     }
+
+    #[test]
+    fn test_stress_get_rkpd_attestation_key() {
+        binder::ProcessState::start_thread_pool();
+        let key_id = get_next_key_id();
+        let mut threads = vec![];
+        const NTHREADS: u32 = 10;
+        const NCALLS: u32 = 1000;
+
+        for _ in 0..NTHREADS {
+            threads.push(std::thread::spawn(move || {
+                for _ in 0..NCALLS {
+                    let key = get_rkpd_attestation_key(&SecurityLevel::TRUSTED_ENVIRONMENT, key_id)
+                        .unwrap();
+                    assert!(!key.keyBlob.is_empty());
+                    assert!(!key.encodedCertChain.is_empty());
+                }
+            }));
+        }
+
+        for t in threads {
+            assert!(t.join().is_ok());
+        }
+    }
 }
diff --git a/keystore2/tests/keystore2_client_delete_key_tests.rs b/keystore2/tests/keystore2_client_delete_key_tests.rs
new file mode 100644
index 0000000..2a06edb
--- /dev/null
+++ b/keystore2/tests/keystore2_client_delete_key_tests.rs
@@ -0,0 +1,150 @@
+// Copyright 2022, 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 nix::unistd::getuid;
+
+use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
+    ErrorCode::ErrorCode, SecurityLevel::SecurityLevel,
+};
+use android_system_keystore2::aidl::android::system::keystore2::{
+    Domain::Domain, KeyDescriptor::KeyDescriptor, ResponseCode::ResponseCode,
+};
+
+use keystore2_test_utils::{get_keystore_service, key_generations, key_generations::Error};
+
+/// Generate a key and delete it using keystore2 service `deleteKey` API. Test should successfully
+/// delete the generated key.
+#[test]
+fn keystore2_delete_key_success() {
+    let keystore2 = get_keystore_service();
+    let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+    let alias = "delete_key_success_key";
+
+    let key_metadata = key_generations::generate_ec_p256_signing_key(
+        &sec_level,
+        Domain::APP,
+        -1,
+        Some(alias.to_string()),
+        None,
+    )
+    .unwrap();
+
+    keystore2.deleteKey(&key_metadata.key).expect("Failed to delete a key.");
+
+    // Check wehther deleted key is removed from keystore.
+    let result = key_generations::map_ks_error(keystore2.getKeyEntry(&key_metadata.key));
+    assert!(result.is_err());
+    assert_eq!(Error::Rc(ResponseCode::KEY_NOT_FOUND), result.unwrap_err());
+}
+
+/// Try to delete non-existing key with domain other than BLOB using keystore2 service `deleteKey`
+/// API. Test should fail with an error code `KEY_NOT_FOUND`.
+#[test]
+fn keystore2_delete_key_fail() {
+    let test_alias = "delete_key_failure_key";
+    let keystore2 = get_keystore_service();
+
+    let result = key_generations::map_ks_error(keystore2.deleteKey(&KeyDescriptor {
+        domain: Domain::SELINUX,
+        nspace: key_generations::SELINUX_SHELL_NAMESPACE,
+        alias: Some(test_alias.to_string()),
+        blob: None,
+    }));
+    assert!(result.is_err());
+    assert_eq!(Error::Rc(ResponseCode::KEY_NOT_FOUND), result.unwrap_err());
+}
+
+/// Generate a key with `Domain::BLOB`. Try to delete a key with `Domain::BLOB` using keystore2
+/// service `deleteKey` API. Test should fail to delete a key with domain BLOB with an error code
+/// `INVALID_ARGUMENT`.
+#[test]
+fn keystore2_delete_key_with_blob_domain_fail() {
+    let keystore2 = get_keystore_service();
+    let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+    let alias = "delete_key_blob_fail_key";
+
+    let key_metadata = key_generations::generate_ec_p256_signing_key(
+        &sec_level,
+        Domain::BLOB,
+        key_generations::SELINUX_SHELL_NAMESPACE,
+        Some(alias.to_string()),
+        None,
+    )
+    .unwrap();
+
+    let result = key_generations::map_ks_error(keystore2.deleteKey(&key_metadata.key));
+    assert!(result.is_err());
+    assert_eq!(Error::Rc(ResponseCode::INVALID_ARGUMENT), result.unwrap_err());
+}
+
+/// Generate a key with `Domain::BLOB`. Delete generated key with `Domain::BLOB` using underlying
+/// security level `deleteKey` API. Test should delete the key successfully.
+#[test]
+fn keystore2_delete_key_blob_success() {
+    let keystore2 = get_keystore_service();
+    let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+    let alias = "delete_key_blob_success_key";
+
+    let key_metadata = key_generations::generate_ec_p256_signing_key(
+        &sec_level,
+        Domain::BLOB,
+        key_generations::SELINUX_SHELL_NAMESPACE,
+        Some(alias.to_string()),
+        None,
+    )
+    .unwrap();
+
+    let result = sec_level.deleteKey(&key_metadata.key);
+    assert!(result.is_ok());
+}
+
+/// Try to delete a key with `Domain::BLOB` without providing key-blob. Test should fail to delete a
+/// key with error code `INVALID_ARGUMENT`.
+#[test]
+fn keystore2_delete_key_fails_with_missing_key_blob() {
+    let keystore2 = get_keystore_service();
+    let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+
+    let result = key_generations::map_ks_error(sec_level.deleteKey(&KeyDescriptor {
+        domain: Domain::BLOB,
+        nspace: key_generations::SELINUX_SHELL_NAMESPACE,
+        alias: None,
+        blob: None,
+    }));
+    assert!(result.is_err());
+    assert_eq!(Error::Km(ErrorCode::INVALID_ARGUMENT), result.unwrap_err());
+}
+
+/// Try to delete a key with domain other than `Domain::BLOB` using underlying security-level
+/// `deleteKey` API. Test should fail to delete a key-blob from underlying security-level backend
+/// with error code `INVALID_ARGUMENT`.
+#[test]
+fn keystore2_delete_key_blob_fail() {
+    let keystore2 = get_keystore_service();
+    let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+    let alias = format!("ks_delete_keyblob_test_key_{}", getuid());
+
+    let key_metadata = key_generations::generate_ec_p256_signing_key(
+        &sec_level,
+        Domain::APP,
+        -1,
+        Some(alias),
+        None,
+    )
+    .unwrap();
+
+    let result = key_generations::map_ks_error(sec_level.deleteKey(&key_metadata.key));
+    assert!(result.is_err());
+    assert_eq!(Error::Km(ErrorCode::INVALID_ARGUMENT), result.unwrap_err());
+}
diff --git a/keystore2/tests/keystore2_client_grant_key_tests.rs b/keystore2/tests/keystore2_client_grant_key_tests.rs
index 7c75734..bde872d 100644
--- a/keystore2/tests/keystore2_client_grant_key_tests.rs
+++ b/keystore2/tests/keystore2_client_grant_key_tests.rs
@@ -19,7 +19,8 @@
     Digest::Digest, KeyPurpose::KeyPurpose, SecurityLevel::SecurityLevel,
 };
 use android_system_keystore2::aidl::android::system::keystore2::{
-    Domain::Domain, KeyDescriptor::KeyDescriptor, KeyPermission::KeyPermission,
+    Domain::Domain, IKeystoreSecurityLevel::IKeystoreSecurityLevel,
+    IKeystoreService::IKeystoreService, KeyDescriptor::KeyDescriptor, KeyPermission::KeyPermission,
     ResponseCode::ResponseCode,
 };
 
@@ -27,7 +28,9 @@
     authorizations, get_keystore_service, key_generations, key_generations::Error, run_as,
 };
 
-use crate::keystore2_client_test_utils::perform_sample_sign_operation;
+use crate::keystore2_client_test_utils::{
+    generate_ec_key_and_grant_to_users, perform_sample_sign_operation,
+};
 
 /// Generate an EC signing key and grant it to the user with given access vector.
 fn generate_ec_key_and_grant_to_user(
@@ -50,6 +53,36 @@
     keystore2.grant(&key_metadata.key, grantee_uid, access_vector)
 }
 
+fn load_grant_key_and_perform_sign_operation(
+    keystore2: &binder::Strong<dyn IKeystoreService>,
+    sec_level: &binder::Strong<dyn IKeystoreSecurityLevel>,
+    grant_key_nspace: i64,
+) -> Result<(), binder::Status> {
+    let key_entry_response = keystore2.getKeyEntry(&KeyDescriptor {
+        domain: Domain::GRANT,
+        nspace: grant_key_nspace,
+        alias: None,
+        blob: None,
+    })?;
+
+    // Perform sample crypto operation using granted key.
+    let op_response = sec_level.createOperation(
+        &key_entry_response.metadata.key,
+        &authorizations::AuthSetBuilder::new().purpose(KeyPurpose::SIGN).digest(Digest::SHA_2_256),
+        false,
+    )?;
+
+    assert!(op_response.iOperation.is_some());
+    assert_eq!(
+        Ok(()),
+        key_generations::map_ks_error(perform_sample_sign_operation(
+            &op_response.iOperation.unwrap()
+        ))
+    );
+
+    Ok(())
+}
+
 /// Try to grant a key with permission that does not map to any of the `KeyPermission` values.
 /// An error is expected with values that does not map to set of permissions listed in
 /// `KeyPermission`.
@@ -203,3 +236,520 @@
         )
     };
 }
+
+/// Grant a key to the user with DELETE access. In grantee context load the key and delete it.
+/// Verify that grantee should succeed in deleting the granted key and in grantor context test
+/// should fail to find the key with error response `KEY_NOT_FOUND`.
+#[test]
+fn keystore2_grant_delete_key_success() {
+    static GRANTOR_SU_CTX: &str = "u:r:su:s0";
+    static GRANTEE_CTX: &str = "u:r:untrusted_app:s0:c91,c256,c10,c20";
+    const USER_ID: u32 = 99;
+    const APPLICATION_ID: u32 = 10001;
+    static GRANTEE_UID: u32 = USER_ID * AID_USER_OFFSET + APPLICATION_ID;
+    static GRANTEE_GID: u32 = GRANTEE_UID;
+    static ALIAS: &str = "ks_grant_key_delete_success";
+
+    // Generate a key and grant it to a user with DELETE permission.
+    let grant_key_nspace = unsafe {
+        run_as::run_as(GRANTOR_SU_CTX, Uid::from_raw(0), Gid::from_raw(0), || {
+            let keystore2 = get_keystore_service();
+            let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+            let access_vector = KeyPermission::DELETE.0;
+            let mut grant_keys = generate_ec_key_and_grant_to_users(
+                &keystore2,
+                &sec_level,
+                Some(ALIAS.to_string()),
+                vec![GRANTEE_UID.try_into().unwrap()],
+                access_vector,
+            )
+            .unwrap();
+
+            grant_keys.remove(0)
+        })
+    };
+
+    // Grantee context, delete the key.
+    unsafe {
+        run_as::run_as(
+            GRANTEE_CTX,
+            Uid::from_raw(GRANTEE_UID),
+            Gid::from_raw(GRANTEE_GID),
+            move || {
+                let keystore2 = get_keystore_service();
+                keystore2
+                    .deleteKey(&KeyDescriptor {
+                        domain: Domain::GRANT,
+                        nspace: grant_key_nspace,
+                        alias: None,
+                        blob: None,
+                    })
+                    .unwrap();
+            },
+        )
+    };
+
+    // Verify whether key got deleted in grantor's context.
+    unsafe {
+        run_as::run_as(GRANTOR_SU_CTX, Uid::from_raw(0), Gid::from_raw(0), move || {
+            let keystore2_inst = get_keystore_service();
+            let result =
+                key_generations::map_ks_error(keystore2_inst.getKeyEntry(&KeyDescriptor {
+                    domain: Domain::APP,
+                    nspace: -1,
+                    alias: Some(ALIAS.to_string()),
+                    blob: None,
+                }));
+            assert!(result.is_err());
+            assert_eq!(Error::Rc(ResponseCode::KEY_NOT_FOUND), result.unwrap_err());
+        })
+    };
+}
+
+/// Grant a key to the user. In grantee context load the granted key and try to grant it to second
+/// user. Test should fail with a response code `PERMISSION_DENIED` to grant a key to second user
+/// from grantee context. Test should make sure second grantee should not have a access to granted
+/// key.
+#[test]
+fn keystore2_grant_key_fails_with_permission_denied() {
+    static GRANTOR_SU_CTX: &str = "u:r:su:s0";
+    static GRANTEE_CTX: &str = "u:r:untrusted_app:s0:c91,c256,c10,c20";
+    const USER_ID: u32 = 99;
+    const APPLICATION_ID: u32 = 10001;
+    static GRANTEE_UID: u32 = USER_ID * AID_USER_OFFSET + APPLICATION_ID;
+    static GRANTEE_GID: u32 = GRANTEE_UID;
+
+    const SEC_USER_ID: u32 = 98;
+    const SEC_APPLICATION_ID: u32 = 10001;
+    static SEC_GRANTEE_UID: u32 = SEC_USER_ID * AID_USER_OFFSET + SEC_APPLICATION_ID;
+    static SEC_GRANTEE_GID: u32 = SEC_GRANTEE_UID;
+
+    // Generate a key and grant it to a user with GET_INFO permission.
+    let grant_key_nspace = unsafe {
+        run_as::run_as(GRANTOR_SU_CTX, Uid::from_raw(0), Gid::from_raw(0), || {
+            let keystore2 = get_keystore_service();
+            let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+            let access_vector = KeyPermission::GET_INFO.0;
+            let alias = format!("ks_grant_perm_denied_key_{}", getuid());
+            let mut grant_keys = generate_ec_key_and_grant_to_users(
+                &keystore2,
+                &sec_level,
+                Some(alias),
+                vec![GRANTEE_UID.try_into().unwrap()],
+                access_vector,
+            )
+            .unwrap();
+
+            grant_keys.remove(0)
+        })
+    };
+
+    // Grantee context, load the granted key and try to grant it to `SEC_GRANTEE_UID` grantee.
+    unsafe {
+        run_as::run_as(
+            GRANTEE_CTX,
+            Uid::from_raw(GRANTEE_UID),
+            Gid::from_raw(GRANTEE_GID),
+            move || {
+                let keystore2 = get_keystore_service();
+                let access_vector = KeyPermission::GET_INFO.0;
+
+                let key_entry_response = keystore2
+                    .getKeyEntry(&KeyDescriptor {
+                        domain: Domain::GRANT,
+                        nspace: grant_key_nspace,
+                        alias: None,
+                        blob: None,
+                    })
+                    .unwrap();
+
+                let result = key_generations::map_ks_error(keystore2.grant(
+                    &key_entry_response.metadata.key,
+                    SEC_GRANTEE_UID.try_into().unwrap(),
+                    access_vector,
+                ));
+                assert!(result.is_err());
+                assert_eq!(Error::Rc(ResponseCode::PERMISSION_DENIED), result.unwrap_err());
+            },
+        )
+    };
+
+    // Make sure second grantee shouldn't have access to the above granted key.
+    unsafe {
+        run_as::run_as(
+            GRANTEE_CTX,
+            Uid::from_raw(SEC_GRANTEE_UID),
+            Gid::from_raw(SEC_GRANTEE_GID),
+            move || {
+                let keystore2 = get_keystore_service();
+
+                let result = key_generations::map_ks_error(keystore2.getKeyEntry(&KeyDescriptor {
+                    domain: Domain::GRANT,
+                    nspace: grant_key_nspace,
+                    alias: None,
+                    blob: None,
+                }));
+
+                assert!(result.is_err());
+                assert_eq!(Error::Rc(ResponseCode::KEY_NOT_FOUND), result.unwrap_err());
+            },
+        )
+    };
+}
+
+/// Try to grant a key with `GRANT` access. Keystore2 system shouldn't allow to grant a key with
+/// `GRANT` access. Test should fail to grant a key with `PERMISSION_DENIED` error response code.
+#[test]
+fn keystore2_grant_key_fails_with_grant_perm_expect_perm_denied() {
+    let keystore2 = get_keystore_service();
+    let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+    let access_vector = KeyPermission::GRANT.0;
+    let alias = format!("ks_grant_access_vec_key_{}", getuid());
+    let user_id = 98;
+    let application_id = 10001;
+    let grantee_uid = user_id * AID_USER_OFFSET + application_id;
+
+    let result = key_generations::map_ks_error(generate_ec_key_and_grant_to_users(
+        &keystore2,
+        &sec_level,
+        Some(alias),
+        vec![grantee_uid.try_into().unwrap()],
+        access_vector,
+    ));
+    assert!(result.is_err());
+    assert_eq!(Error::Rc(ResponseCode::PERMISSION_DENIED), result.unwrap_err());
+}
+
+/// Try to grant a non-existing key to the user. Test should fail with `KEY_NOT_FOUND` error
+/// response.
+#[test]
+fn keystore2_grant_fails_with_non_existing_key_expect_key_not_found_err() {
+    let keystore2 = get_keystore_service();
+    let alias = format!("ks_grant_test_non_existing_key_5_{}", getuid());
+    let user_id = 98;
+    let application_id = 10001;
+    let grantee_uid = user_id * AID_USER_OFFSET + application_id;
+    let access_vector = KeyPermission::GET_INFO.0;
+
+    let result = key_generations::map_ks_error(keystore2.grant(
+        &KeyDescriptor {
+            domain: Domain::SELINUX,
+            nspace: key_generations::SELINUX_SHELL_NAMESPACE,
+            alias: Some(alias),
+            blob: None,
+        },
+        grantee_uid.try_into().unwrap(),
+        access_vector,
+    ));
+    assert!(result.is_err());
+    assert_eq!(Error::Rc(ResponseCode::KEY_NOT_FOUND), result.unwrap_err());
+}
+
+/// Grant a key to the user and immediately ungrant the granted key. In grantee context try to load
+/// the key. Grantee should fail to load the ungranted key with `KEY_NOT_FOUND` error response.
+#[test]
+fn keystore2_ungrant_key_success() {
+    static GRANTOR_SU_CTX: &str = "u:r:su:s0";
+    static GRANTEE_CTX: &str = "u:r:untrusted_app:s0:c91,c256,c10,c20";
+    const USER_ID: u32 = 99;
+    const APPLICATION_ID: u32 = 10001;
+    static GRANTEE_UID: u32 = USER_ID * AID_USER_OFFSET + APPLICATION_ID;
+    static GRANTEE_GID: u32 = GRANTEE_UID;
+
+    // Generate a key and grant it to a user with GET_INFO permission.
+    let grant_key_nspace = unsafe {
+        run_as::run_as(GRANTOR_SU_CTX, Uid::from_raw(0), Gid::from_raw(0), || {
+            let keystore2 = get_keystore_service();
+            let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+            let alias = format!("ks_ungrant_test_key_1{}", getuid());
+            let access_vector = KeyPermission::GET_INFO.0;
+            let mut grant_keys = generate_ec_key_and_grant_to_users(
+                &keystore2,
+                &sec_level,
+                Some(alias.to_string()),
+                vec![GRANTEE_UID.try_into().unwrap()],
+                access_vector,
+            )
+            .unwrap();
+
+            let grant_key_nspace = grant_keys.remove(0);
+
+            //Ungrant above granted key.
+            keystore2
+                .ungrant(
+                    &KeyDescriptor {
+                        domain: Domain::APP,
+                        nspace: -1,
+                        alias: Some(alias),
+                        blob: None,
+                    },
+                    GRANTEE_UID.try_into().unwrap(),
+                )
+                .unwrap();
+
+            grant_key_nspace
+        })
+    };
+
+    // Grantee context, try to load the ungranted key.
+    unsafe {
+        run_as::run_as(
+            GRANTEE_CTX,
+            Uid::from_raw(GRANTEE_UID),
+            Gid::from_raw(GRANTEE_GID),
+            move || {
+                let keystore2 = get_keystore_service();
+                let result = key_generations::map_ks_error(keystore2.getKeyEntry(&KeyDescriptor {
+                    domain: Domain::GRANT,
+                    nspace: grant_key_nspace,
+                    alias: None,
+                    blob: None,
+                }));
+                assert!(result.is_err());
+                assert_eq!(Error::Rc(ResponseCode::KEY_NOT_FOUND), result.unwrap_err());
+            },
+        )
+    };
+}
+
+/// Generate a key, grant it to the user and then delete the granted key. Try to ungrant
+/// a deleted key. Test should fail to ungrant a non-existing key with `KEY_NOT_FOUND` error
+/// response. Generate a new key with the same alias and try to access the previously granted
+/// key in grantee context. Test should fail to load the granted key in grantee context as the
+/// associated key is deleted from grantor context.
+#[test]
+fn keystore2_ungrant_fails_with_non_existing_key_expect_key_not_found_error() {
+    static GRANTOR_SU_CTX: &str = "u:r:su:s0";
+    static GRANTEE_CTX: &str = "u:r:untrusted_app:s0:c91,c256,c10,c20";
+
+    const APPLICATION_ID: u32 = 10001;
+    const USER_ID: u32 = 99;
+    static GRANTEE_UID: u32 = USER_ID * AID_USER_OFFSET + APPLICATION_ID;
+    static GRANTEE_GID: u32 = GRANTEE_UID;
+
+    let grant_key_nspace = unsafe {
+        run_as::run_as(GRANTOR_SU_CTX, Uid::from_raw(0), Gid::from_raw(0), || {
+            let keystore2 = get_keystore_service();
+            let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+            let alias = format!("{}{}", "ks_grant_delete_ungrant_test_key_1", getuid());
+
+            let key_metadata = key_generations::generate_ec_p256_signing_key(
+                &sec_level,
+                Domain::SELINUX,
+                key_generations::SELINUX_SHELL_NAMESPACE,
+                Some(alias.to_string()),
+                None,
+            )
+            .unwrap();
+
+            let access_vector = KeyPermission::GET_INFO.0;
+            let grant_key = keystore2
+                .grant(&key_metadata.key, GRANTEE_UID.try_into().unwrap(), access_vector)
+                .unwrap();
+            assert_eq!(grant_key.domain, Domain::GRANT);
+
+            // Delete above granted key.
+            keystore2.deleteKey(&key_metadata.key).unwrap();
+
+            // Try to ungrant above granted key.
+            let result = key_generations::map_ks_error(
+                keystore2.ungrant(&key_metadata.key, GRANTEE_UID.try_into().unwrap()),
+            );
+            assert!(result.is_err());
+            assert_eq!(Error::Rc(ResponseCode::KEY_NOT_FOUND), result.unwrap_err());
+
+            // Generate a new key with the same alias and try to access the earlier granted key
+            // in grantee context.
+            let result = key_generations::generate_ec_p256_signing_key(
+                &sec_level,
+                Domain::SELINUX,
+                key_generations::SELINUX_SHELL_NAMESPACE,
+                Some(alias),
+                None,
+            );
+            assert!(result.is_ok());
+
+            grant_key.nspace
+        })
+    };
+
+    // Make sure grant did not persist, try to access the earlier granted key in grantee context.
+    // Grantee context should fail to load the granted key as its associated key is deleted in
+    // grantor context.
+    unsafe {
+        run_as::run_as(
+            GRANTEE_CTX,
+            Uid::from_raw(GRANTEE_UID),
+            Gid::from_raw(GRANTEE_GID),
+            move || {
+                let keystore2 = get_keystore_service();
+
+                let result = key_generations::map_ks_error(keystore2.getKeyEntry(&KeyDescriptor {
+                    domain: Domain::GRANT,
+                    nspace: grant_key_nspace,
+                    alias: None,
+                    blob: None,
+                }));
+                assert!(result.is_err());
+                assert_eq!(Error::Rc(ResponseCode::KEY_NOT_FOUND), result.unwrap_err());
+            },
+        )
+    };
+}
+
+/// Grant a key to multiple users. Verify that all grantees should succeed in loading the key and
+/// use it for performing an operation successfully.
+#[test]
+fn keystore2_grant_key_to_multi_users_success() {
+    static GRANTOR_SU_CTX: &str = "u:r:su:s0";
+    static GRANTEE_CTX: &str = "u:r:untrusted_app:s0:c91,c256,c10,c20";
+
+    const APPLICATION_ID: u32 = 10001;
+    const USER_ID_1: u32 = 99;
+    static GRANTEE_1_UID: u32 = USER_ID_1 * AID_USER_OFFSET + APPLICATION_ID;
+    static GRANTEE_1_GID: u32 = GRANTEE_1_UID;
+
+    const USER_ID_2: u32 = 98;
+    static GRANTEE_2_UID: u32 = USER_ID_2 * AID_USER_OFFSET + APPLICATION_ID;
+    static GRANTEE_2_GID: u32 = GRANTEE_2_UID;
+
+    // Generate a key and grant it to multiple users with GET_INFO|USE permissions.
+    let mut grant_keys = unsafe {
+        run_as::run_as(GRANTOR_SU_CTX, Uid::from_raw(0), Gid::from_raw(0), || {
+            let keystore2 = get_keystore_service();
+            let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+            let alias = format!("ks_grant_test_key_2{}", getuid());
+            let access_vector = KeyPermission::GET_INFO.0 | KeyPermission::USE.0;
+
+            generate_ec_key_and_grant_to_users(
+                &keystore2,
+                &sec_level,
+                Some(alias),
+                vec![GRANTEE_1_UID.try_into().unwrap(), GRANTEE_2_UID.try_into().unwrap()],
+                access_vector,
+            )
+            .unwrap()
+        })
+    };
+
+    for (grantee_uid, grantee_gid) in
+        &[(GRANTEE_1_UID, GRANTEE_1_GID), (GRANTEE_2_UID, GRANTEE_2_GID)]
+    {
+        let grant_key_nspace = grant_keys.remove(0);
+        unsafe {
+            run_as::run_as(
+                GRANTEE_CTX,
+                Uid::from_raw(*grantee_uid),
+                Gid::from_raw(*grantee_gid),
+                move || {
+                    let keystore2 = get_keystore_service();
+                    let sec_level =
+                        keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+
+                    assert_eq!(
+                        Ok(()),
+                        key_generations::map_ks_error(load_grant_key_and_perform_sign_operation(
+                            &keystore2,
+                            &sec_level,
+                            grant_key_nspace
+                        ))
+                    );
+                },
+            )
+        };
+    }
+}
+
+/// Grant a key to multiple users with GET_INFO|DELETE permissions. In one of the grantee context
+/// use the key and delete it. Try to load the granted key in another grantee context. Test should
+/// fail to load the granted key with `KEY_NOT_FOUND` error response.
+#[test]
+fn keystore2_grant_key_to_multi_users_delete_fails_with_key_not_found_error() {
+    static GRANTOR_SU_CTX: &str = "u:r:su:s0";
+    static GRANTEE_CTX: &str = "u:r:untrusted_app:s0:c91,c256,c10,c20";
+
+    const USER_ID_1: u32 = 99;
+    const APPLICATION_ID: u32 = 10001;
+    static GRANTEE_1_UID: u32 = USER_ID_1 * AID_USER_OFFSET + APPLICATION_ID;
+    static GRANTEE_1_GID: u32 = GRANTEE_1_UID;
+
+    const USER_ID_2: u32 = 98;
+    static GRANTEE_2_UID: u32 = USER_ID_2 * AID_USER_OFFSET + APPLICATION_ID;
+    static GRANTEE_2_GID: u32 = GRANTEE_2_UID;
+
+    // Generate a key and grant it to multiple users with GET_INFO permission.
+    let mut grant_keys = unsafe {
+        run_as::run_as(GRANTOR_SU_CTX, Uid::from_raw(0), Gid::from_raw(0), || {
+            let keystore2 = get_keystore_service();
+            let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+            let alias = format!("ks_grant_test_key_2{}", getuid());
+            let access_vector =
+                KeyPermission::GET_INFO.0 | KeyPermission::USE.0 | KeyPermission::DELETE.0;
+
+            generate_ec_key_and_grant_to_users(
+                &keystore2,
+                &sec_level,
+                Some(alias),
+                vec![GRANTEE_1_UID.try_into().unwrap(), GRANTEE_2_UID.try_into().unwrap()],
+                access_vector,
+            )
+            .unwrap()
+        })
+    };
+
+    // Grantee #1 context
+    let grant_key1_nspace = grant_keys.remove(0);
+    unsafe {
+        run_as::run_as(
+            GRANTEE_CTX,
+            Uid::from_raw(GRANTEE_1_UID),
+            Gid::from_raw(GRANTEE_1_GID),
+            move || {
+                let keystore2 = get_keystore_service();
+                let sec_level =
+                    keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+
+                assert_eq!(
+                    Ok(()),
+                    key_generations::map_ks_error(load_grant_key_and_perform_sign_operation(
+                        &keystore2,
+                        &sec_level,
+                        grant_key1_nspace
+                    ))
+                );
+
+                // Delete the granted key.
+                keystore2
+                    .deleteKey(&KeyDescriptor {
+                        domain: Domain::GRANT,
+                        nspace: grant_key1_nspace,
+                        alias: None,
+                        blob: None,
+                    })
+                    .unwrap();
+            },
+        )
+    };
+
+    // Grantee #2 context
+    let grant_key2_nspace = grant_keys.remove(0);
+    unsafe {
+        run_as::run_as(
+            GRANTEE_CTX,
+            Uid::from_raw(GRANTEE_2_UID),
+            Gid::from_raw(GRANTEE_2_GID),
+            move || {
+                let keystore2 = get_keystore_service();
+
+                let result = key_generations::map_ks_error(keystore2.getKeyEntry(&KeyDescriptor {
+                    domain: Domain::GRANT,
+                    nspace: grant_key2_nspace,
+                    alias: None,
+                    blob: None,
+                }));
+                assert!(result.is_err());
+                assert_eq!(Error::Rc(ResponseCode::KEY_NOT_FOUND), result.unwrap_err());
+            },
+        )
+    };
+}
diff --git a/keystore2/tests/keystore2_client_test_utils.rs b/keystore2/tests/keystore2_client_test_utils.rs
index 56995e4..58e6b7d 100644
--- a/keystore2/tests/keystore2_client_test_utils.rs
+++ b/keystore2/tests/keystore2_client_test_utils.rs
@@ -90,6 +90,29 @@
         .expect("Could not check for declared keymint interface")
 }
 
+/// Generate EC key and grant it to the list of users with given access vector.
+/// Returns the list of granted keys `nspace` values in the order of given grantee uids.
+pub fn generate_ec_key_and_grant_to_users(
+    keystore2: &binder::Strong<dyn IKeystoreService>,
+    sec_level: &binder::Strong<dyn IKeystoreSecurityLevel>,
+    alias: Option<String>,
+    grantee_uids: Vec<i32>,
+    access_vector: i32,
+) -> Result<Vec<i64>, binder::Status> {
+    let key_metadata =
+        key_generations::generate_ec_p256_signing_key(sec_level, Domain::APP, -1, alias, None)?;
+
+    let mut granted_keys = Vec::new();
+
+    for uid in grantee_uids {
+        let granted_key = keystore2.grant(&key_metadata.key, uid, access_vector)?;
+        assert_eq!(granted_key.domain, Domain::GRANT);
+        granted_keys.push(granted_key.nspace);
+    }
+
+    Ok(granted_keys)
+}
+
 /// Generate a EC_P256 key using given domain, namespace and alias.
 /// Create an operation using the generated key and perform sample signing operation.
 pub fn create_signing_operation(
diff --git a/keystore2/tests/keystore2_client_tests.rs b/keystore2/tests/keystore2_client_tests.rs
index d705aa4..45c5fb7 100644
--- a/keystore2/tests/keystore2_client_tests.rs
+++ b/keystore2/tests/keystore2_client_tests.rs
@@ -16,6 +16,7 @@
 pub mod keystore2_client_3des_key_tests;
 pub mod keystore2_client_aes_key_tests;
 pub mod keystore2_client_attest_key_tests;
+pub mod keystore2_client_delete_key_tests;
 pub mod keystore2_client_ec_key_tests;
 pub mod keystore2_client_grant_key_tests;
 pub mod keystore2_client_hmac_key_tests;
@@ -25,3 +26,4 @@
 pub mod keystore2_client_operation_tests;
 pub mod keystore2_client_rsa_key_tests;
 pub mod keystore2_client_test_utils;
+pub mod keystore2_client_update_subcomponent_tests;
diff --git a/keystore2/tests/keystore2_client_update_subcomponent_tests.rs b/keystore2/tests/keystore2_client_update_subcomponent_tests.rs
new file mode 100644
index 0000000..c987f22
--- /dev/null
+++ b/keystore2/tests/keystore2_client_update_subcomponent_tests.rs
@@ -0,0 +1,230 @@
+// Copyright 2022, 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 nix::unistd::{getuid, Gid, Uid};
+use rustutils::users::AID_USER_OFFSET;
+
+use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
+    ErrorCode::ErrorCode, SecurityLevel::SecurityLevel,
+};
+use android_system_keystore2::aidl::android::system::keystore2::{
+    Domain::Domain, KeyDescriptor::KeyDescriptor, KeyPermission::KeyPermission,
+    ResponseCode::ResponseCode,
+};
+
+use keystore2_test_utils::{get_keystore_service, key_generations, key_generations::Error, run_as};
+
+/// Generate a key and update its public certificate and certificate chain. Test should be able to
+/// load the key and able to verify whether its certificate and cert-chain are updated successfully.
+#[test]
+fn keystore2_update_subcomponent_success() {
+    let alias = "update_subcomponent_success_key";
+
+    let keystore2 = get_keystore_service();
+    let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+
+    let key_metadata = key_generations::generate_ec_p256_signing_key(
+        &sec_level,
+        Domain::SELINUX,
+        key_generations::SELINUX_SHELL_NAMESPACE,
+        Some(alias.to_string()),
+        None,
+    )
+    .unwrap();
+
+    let other_cert: [u8; 32] = [123; 32];
+    let other_cert_chain: [u8; 32] = [12; 32];
+
+    keystore2
+        .updateSubcomponent(&key_metadata.key, Some(&other_cert), Some(&other_cert_chain))
+        .expect("updateSubcomponent should have succeeded.");
+
+    let key_entry_response = keystore2.getKeyEntry(&key_metadata.key).unwrap();
+    assert_eq!(Some(other_cert.to_vec()), key_entry_response.metadata.certificate);
+    assert_eq!(Some(other_cert_chain.to_vec()), key_entry_response.metadata.certificateChain);
+}
+
+/// Try to update non-existing asymmetric key public cert and certificate chain. Test should fail
+/// to update with error response code `KEY_NOT_FOUND`.
+#[test]
+fn keystore2_update_subcomponent_fail() {
+    let alias = "update_component_failure_key";
+
+    let keystore2 = get_keystore_service();
+
+    let other_cert: [u8; 32] = [123; 32];
+    let other_cert_chain: [u8; 32] = [12; 32];
+
+    let result = key_generations::map_ks_error(keystore2.updateSubcomponent(
+        &KeyDescriptor {
+            domain: Domain::SELINUX,
+            nspace: key_generations::SELINUX_SHELL_NAMESPACE,
+            alias: Some(alias.to_string()),
+            blob: None,
+        },
+        Some(&other_cert),
+        Some(&other_cert_chain),
+    ));
+    assert!(result.is_err());
+    assert_eq!(Error::Rc(ResponseCode::KEY_NOT_FOUND), result.unwrap_err());
+}
+
+/// Generate a key and grant it to two users. For one user grant it with only `GET_INFO` access
+/// permission and for another user grant it with GET_INFO and UPDATE access permissions. In a
+/// grantee context where key is granted with only GET_INFO access permission, try to update
+/// key's public certificate and certificate chain. Test should fail to update with error response
+/// code `PERMISSION_DENIED` because grantee does not possess UPDATE access permission for the
+/// specified key. In a grantee context where key is granted with UPDATE and GET_INFO access
+/// permissions, test should be able to update public certificate and cert-chain successfully.
+#[test]
+fn keystore2_update_subcomponent_fails_permission_denied() {
+    static GRANTOR_SU_CTX: &str = "u:r:su:s0";
+    static GRANTEE_CTX: &str = "u:r:untrusted_app:s0:c91,c256,c10,c20";
+
+    const USER_ID_1: u32 = 99;
+    const APPLICATION_ID: u32 = 10001;
+    static GRANTEE_1_UID: u32 = USER_ID_1 * AID_USER_OFFSET + APPLICATION_ID;
+    static GRANTEE_1_GID: u32 = GRANTEE_1_UID;
+
+    const USER_ID_2: u32 = 98;
+    static GRANTEE_2_UID: u32 = USER_ID_2 * AID_USER_OFFSET + APPLICATION_ID;
+    static GRANTEE_2_GID: u32 = GRANTEE_2_UID;
+
+    // Generate a key and grant it to multiple users with different access permissions.
+    let mut granted_keys = unsafe {
+        run_as::run_as(GRANTOR_SU_CTX, Uid::from_raw(0), Gid::from_raw(0), || {
+            let keystore2 = get_keystore_service();
+            let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+            let alias = format!("ks_update_subcompo_test_1_{}", getuid());
+            let mut granted_keys = Vec::new();
+
+            let key_metadata = key_generations::generate_ec_p256_signing_key(
+                &sec_level,
+                Domain::APP,
+                -1,
+                Some(alias),
+                None,
+            )
+            .unwrap();
+
+            // Grant a key without update permission.
+            let access_vector = KeyPermission::GET_INFO.0;
+            let granted_key = keystore2
+                .grant(&key_metadata.key, GRANTEE_1_UID.try_into().unwrap(), access_vector)
+                .unwrap();
+            assert_eq!(granted_key.domain, Domain::GRANT);
+            granted_keys.push(granted_key.nspace);
+
+            // Grant a key with update permission.
+            let access_vector = KeyPermission::GET_INFO.0 | KeyPermission::UPDATE.0;
+            let granted_key = keystore2
+                .grant(&key_metadata.key, GRANTEE_2_UID.try_into().unwrap(), access_vector)
+                .unwrap();
+            assert_eq!(granted_key.domain, Domain::GRANT);
+            granted_keys.push(granted_key.nspace);
+
+            granted_keys
+        })
+    };
+
+    // Grantee context, try to update the key public certs, permission denied error is expected.
+    let granted_key1_nspace = granted_keys.remove(0);
+    unsafe {
+        run_as::run_as(
+            GRANTEE_CTX,
+            Uid::from_raw(GRANTEE_1_UID),
+            Gid::from_raw(GRANTEE_1_GID),
+            move || {
+                let keystore2 = get_keystore_service();
+
+                let other_cert: [u8; 32] = [123; 32];
+                let other_cert_chain: [u8; 32] = [12; 32];
+
+                let result = key_generations::map_ks_error(keystore2.updateSubcomponent(
+                    &KeyDescriptor {
+                        domain: Domain::GRANT,
+                        nspace: granted_key1_nspace,
+                        alias: None,
+                        blob: None,
+                    },
+                    Some(&other_cert),
+                    Some(&other_cert_chain),
+                ));
+                assert!(result.is_err());
+                assert_eq!(Error::Rc(ResponseCode::PERMISSION_DENIED), result.unwrap_err());
+            },
+        )
+    };
+
+    // Grantee context, update granted key public certs. Update should happen successfully.
+    let granted_key2_nspace = granted_keys.remove(0);
+    unsafe {
+        run_as::run_as(
+            GRANTEE_CTX,
+            Uid::from_raw(GRANTEE_2_UID),
+            Gid::from_raw(GRANTEE_2_GID),
+            move || {
+                let keystore2 = get_keystore_service();
+
+                let other_cert: [u8; 32] = [124; 32];
+                let other_cert_chain: [u8; 32] = [13; 32];
+
+                keystore2
+                    .updateSubcomponent(
+                        &KeyDescriptor {
+                            domain: Domain::GRANT,
+                            nspace: granted_key2_nspace,
+                            alias: None,
+                            blob: None,
+                        },
+                        Some(&other_cert),
+                        Some(&other_cert_chain),
+                    )
+                    .expect("updateSubcomponent should have succeeded.");
+
+                let key_entry_response = keystore2
+                    .getKeyEntry(&KeyDescriptor {
+                        domain: Domain::GRANT,
+                        nspace: granted_key2_nspace,
+                        alias: None,
+                        blob: None,
+                    })
+                    .unwrap();
+                assert_eq!(Some(other_cert.to_vec()), key_entry_response.metadata.certificate);
+                assert_eq!(
+                    Some(other_cert_chain.to_vec()),
+                    key_entry_response.metadata.certificateChain
+                );
+            },
+        )
+    };
+}
+
+#[test]
+fn keystore2_get_security_level_success() {
+    let keystore2 = get_keystore_service();
+    assert!(
+        keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).is_ok(),
+        "getSecurityLevel with SecurityLevel::TRUSTED_ENVIRONMENT should have succeeded."
+    );
+}
+
+#[test]
+fn keystore2_get_security_level_failure() {
+    let keystore2 = get_keystore_service();
+    let result = key_generations::map_ks_error(keystore2.getSecurityLevel(SecurityLevel::SOFTWARE));
+
+    assert!(result.is_err());
+    assert_eq!(Error::Km(ErrorCode::HARDWARE_TYPE_UNAVAILABLE), result.unwrap_err());
+}