Merge "Revert "Static link libcrypto into rkp_factory_extraction_tool"" into main
diff --git a/diced/OWNERS b/diced/OWNERS
deleted file mode 100644
index 387cd93..0000000
--- a/diced/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-alanstokes@google.com
-aliceywang@google.com
-ascull@google.com
diff --git a/diced/TEST_MAPPING b/diced/TEST_MAPPING
deleted file mode 100644
index caf847f..0000000
--- a/diced/TEST_MAPPING
+++ /dev/null
@@ -1,19 +0,0 @@
-{
-  "presubmit": [
-    {
-      "name": "libdiced_open_dice.integration_test"
-    },
-    {
-      "name": "libdiced_open_dice_nostd.integration_test"
-    },
-    {
-      "name": "libopen_dice_cbor_bindgen_test"
-    },
-    {
-      "name": "libopen_dice_bcc_bindgen_test"
-    },
-    {
-      "name": "libdiced_sample_inputs.integration_test"
-    }
-  ]
-}
diff --git a/diced/open_dice/Android.bp b/diced/open_dice/Android.bp
deleted file mode 100644
index c59419b..0000000
--- a/diced/open_dice/Android.bp
+++ /dev/null
@@ -1,257 +0,0 @@
-package {
-    default_visibility: [":__subpackages__"],
-    default_applicable_licenses: ["Android-Apache-2.0"],
-}
-
-rust_defaults {
-    name: "libdiced_open_dice_defaults",
-    crate_name: "diced_open_dice",
-    srcs: ["src/lib.rs"],
-}
-
-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",
-    ],
-    visibility: [
-        "//packages/modules/Virtualization:__subpackages__",
-    ],
-}
-
-rust_library {
-    name: "libdiced_open_dice",
-    defaults: ["libdiced_open_dice_defaults"],
-    vendor_available: true,
-    rustlibs: [
-        "libopen_dice_bcc_bindgen",
-        "libopen_dice_cbor_bindgen",
-        "libzeroize",
-    ],
-    features: [
-        "std",
-    ],
-    shared_libs: [
-        "libcrypto",
-    ],
-    static_libs: [
-        "libopen_dice_cbor",
-    ],
-    whole_static_libs: [
-        "libopen_dice_bcc",
-    ],
-    visibility: [
-        "//system/security/diced:__subpackages__",
-        "//packages/modules/Virtualization:__subpackages__",
-        "//hardware/interfaces/security/dice/aidl:__subpackages__",
-    ],
-    apex_available: [
-        "//apex_available:platform",
-        "com.android.virt",
-    ],
-}
-
-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",
-    ],
-}
-
-rust_defaults {
-    name: "libopen_dice_bindgen_nostd.rust_defaults",
-    bindgen_flags: [
-        "--use-core",
-        "--ctypes-prefix=core::ffi",
-        "--raw-line=#![no_std]",
-    ],
-    no_stdlibs: true,
-    prefer_rlib: true,
-    stdlibs: [
-        "libcore.rust_sysroot",
-        "libcompiler_builtins.rust_sysroot",
-    ],
-    target: {
-        musl: {
-            enabled: false,
-        },
-        glibc: {
-            enabled: false,
-        },
-        darwin: {
-            enabled: false,
-        },
-    },
-}
-
-rust_defaults {
-    name: "libopen_dice.rust_defaults",
-    host_supported: true,
-    vendor_available: true,
-    apex_available: [
-        "//apex_available:platform",
-        "com.android.compos",
-        "com.android.virt",
-    ],
-}
-
-rust_defaults {
-    name: "libopen_dice_cbor_bindgen.rust_defaults",
-    wrapper_src: "bindgen/dice.h",
-    crate_name: "open_dice_cbor_bindgen",
-    source_stem: "bindings",
-    bindgen_flags: [
-        "--rustified-enum DiceConfigType",
-        "--rustified-enum DiceMode",
-        "--rustified-enum DiceResult",
-
-        // By generating only essential functions, we can make bindings concise and
-        // optimize compilation time.
-        "--allowlist-function=DiceDeriveCdiPrivateKeySeed",
-        "--allowlist-function=DiceDeriveCdiCertificateId",
-        "--allowlist-function=DiceMainFlow",
-        "--allowlist-function=DiceHash",
-        "--allowlist-function=DiceKdf",
-        "--allowlist-function=DiceKeypairFromSeed",
-        "--allowlist-function=DiceSign",
-        "--allowlist-function=DiceVerify",
-        "--allowlist-function=DiceGenerateCertificate",
-
-        // We also need some constants in addition to the functions.
-        "--allowlist-var=DICE_CDI_SIZE",
-        "--allowlist-var=DICE_HASH_SIZE",
-        "--allowlist-var=DICE_HIDDEN_SIZE",
-        "--allowlist-var=DICE_INLINE_CONFIG_SIZE",
-        "--allowlist-var=DICE_PRIVATE_KEY_SEED_SIZE",
-        "--allowlist-var=DICE_ID_SIZE",
-        "--allowlist-var=DICE_PUBLIC_KEY_SIZE",
-        "--allowlist-var=DICE_PRIVATE_KEY_SIZE",
-        "--allowlist-var=DICE_SIGNATURE_SIZE",
-    ],
-}
-
-rust_bindgen {
-    name: "libopen_dice_cbor_bindgen",
-    defaults: [
-        "libopen_dice.rust_defaults",
-        "libopen_dice_cbor_bindgen.rust_defaults",
-    ],
-    whole_static_libs: ["libopen_dice_cbor"],
-}
-
-rust_bindgen {
-    name: "libopen_dice_cbor_bindgen_nostd",
-    defaults: [
-        "libopen_dice_cbor_bindgen.rust_defaults",
-        "libopen_dice_bindgen_nostd.rust_defaults",
-    ],
-    whole_static_libs: ["libopen_dice_cbor_baremetal"],
-}
-
-rust_defaults {
-    name: "libopen_dice_bcc_bindgen.rust_defaults",
-    wrapper_src: "bindgen/android/bcc.h",
-    crate_name: "open_dice_bcc_bindgen",
-    source_stem: "bindings",
-    bindgen_flags: [
-        // By generating only essential functions, we can make bindings concise and
-        // optimize compilation time.
-        "--allowlist-function=BccFormatConfigDescriptor",
-        "--allowlist-function=BccMainFlow",
-        "--allowlist-function=BccHandoverMainFlow",
-        "--allowlist-function=BccHandoverParse",
-
-        // We also need some constants in addition to the functions.
-        "--allowlist-var=BCC_INPUT_COMPONENT_NAME",
-        "--allowlist-var=BCC_INPUT_COMPONENT_VERSION",
-        "--allowlist-var=BCC_INPUT_RESETTABLE",
-
-        // Prevent DiceInputValues from being generated a second time and
-        // import it instead from open_dice_cbor_bindgen.
-        "--blocklist-type=DiceInputValues_",
-        "--blocklist-type=DiceInputValues",
-        "--raw-line",
-        "pub use open_dice_cbor_bindgen::DiceInputValues;",
-
-        // Prevent DiceResult from being generated a second time and
-        // import it instead from open_dice_cbor_bindgen.
-        "--blocklist-type=DiceResult",
-        "--raw-line",
-        "pub use open_dice_cbor_bindgen::DiceResult;",
-    ],
-
-}
-
-rust_bindgen {
-    name: "libopen_dice_bcc_bindgen",
-    defaults: [
-        "libopen_dice.rust_defaults",
-        "libopen_dice_bcc_bindgen.rust_defaults",
-    ],
-    rustlibs: [
-        "libopen_dice_cbor_bindgen",
-    ],
-    whole_static_libs: ["libopen_dice_bcc"],
-}
-
-rust_bindgen {
-    name: "libopen_dice_bcc_bindgen_nostd",
-    defaults: [
-        "libopen_dice_bcc_bindgen.rust_defaults",
-        "libopen_dice_bindgen_nostd.rust_defaults",
-    ],
-    rustlibs: [
-        "libopen_dice_cbor_bindgen_nostd",
-    ],
-    whole_static_libs: ["libopen_dice_bcc_baremetal"],
-}
-
-rust_test {
-    name: "libopen_dice_cbor_bindgen_test",
-    srcs: [
-        ":libopen_dice_cbor_bindgen",
-    ],
-    crate_name: "open_dice_cbor_bindgen_test",
-    test_suites: ["general-tests"],
-    auto_gen_config: true,
-    clippy_lints: "none",
-    lints: "none",
-}
-
-rust_test {
-    name: "libopen_dice_bcc_bindgen_test",
-    srcs: [
-        ":libopen_dice_bcc_bindgen",
-    ],
-    crate_name: "open_dice_bcc_bindgen_test",
-    rustlibs: [
-        "libopen_dice_cbor_bindgen",
-    ],
-    test_suites: ["general-tests"],
-    auto_gen_config: true,
-    clippy_lints: "none",
-    lints: "none",
-}
diff --git a/diced/open_dice/bindgen/android/bcc.h b/diced/open_dice/bindgen/android/bcc.h
deleted file mode 100644
index 4dfc862..0000000
--- a/diced/open_dice/bindgen/android/bcc.h
+++ /dev/null
@@ -1,17 +0,0 @@
-// Copyright 2021 Google LLC
-//
-// 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
-//
-//     https://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.
-
-#pragma once
-
-#include <dice/android/bcc.h>
diff --git a/diced/open_dice/bindgen/dice.h b/diced/open_dice/bindgen/dice.h
deleted file mode 100644
index 47fe911..0000000
--- a/diced/open_dice/bindgen/dice.h
+++ /dev/null
@@ -1,18 +0,0 @@
-// Copyright 2021 Google LLC
-//
-// 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
-//
-//     https://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.
-
-#pragma once
-
-#include <dice/dice.h>
-#include <dice/ops.h>
diff --git a/diced/open_dice/src/bcc.rs b/diced/open_dice/src/bcc.rs
deleted file mode 100644
index ca2136f..0000000
--- a/diced/open_dice/src/bcc.rs
+++ /dev/null
@@ -1,204 +0,0 @@
-// 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, DiceArtifacts, InputValues, CDI_SIZE};
-use crate::error::{check_result, DiceError, Result};
-use open_dice_bcc_bindgen::{
-    BccConfigValues, BccFormatConfigDescriptor, BccHandoverMainFlow, BccHandoverParse, 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;
-    check_result(
-        // SAFETY: The function writes to the buffer, within the given bounds, and only reads the
-        // input values. It writes its result to buffer_size.
-        unsafe {
-            BccFormatConfigDescriptor(&values, buffer.len(), buffer.as_mut_ptr(), &mut buffer_size)
-        },
-        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;
-    check_result(
-        // 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.
-        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(),
-            )
-        },
-        next_bcc_size,
-    )?;
-    Ok(next_bcc_size)
-}
-
-/// Executes the main BCC handover flow.
-///
-/// A BCC handover combines the BCC and CDIs in a single CBOR object.
-/// This function takes the current boot stage's BCC handover bundle and produces a
-/// bundle for the next stage.
-pub fn bcc_handover_main_flow(
-    current_bcc_handover: &[u8],
-    input_values: &InputValues,
-    next_bcc_handover: &mut [u8],
-) -> Result<usize> {
-    let mut next_bcc_handover_size = 0;
-    check_result(
-        // SAFETY: The function only reads `current_bcc_handover` and writes to `next_bcc_handover`
-        // 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.
-        unsafe {
-            BccHandoverMainFlow(
-                ptr::null_mut(), // context
-                current_bcc_handover.as_ptr(),
-                current_bcc_handover.len(),
-                input_values.as_ptr(),
-                next_bcc_handover.len(),
-                next_bcc_handover.as_mut_ptr(),
-                &mut next_bcc_handover_size,
-            )
-        },
-        next_bcc_handover_size,
-    )?;
-
-    Ok(next_bcc_handover_size)
-}
-
-/// A BCC handover combines the BCC and CDIs in a single CBOR object.
-/// This struct is used as return of the function `bcc_handover_parse`, its lifetime is tied
-/// to the lifetime of the raw BCC handover slice.
-#[derive(Debug)]
-pub struct BccHandover<'a> {
-    /// Attestation CDI.
-    cdi_attest: &'a [u8; CDI_SIZE],
-    /// Sealing CDI.
-    cdi_seal: &'a [u8; CDI_SIZE],
-    /// Boot Certificate Chain.
-    bcc: Option<&'a [u8]>,
-}
-
-impl<'a> DiceArtifacts for BccHandover<'a> {
-    fn cdi_attest(&self) -> &[u8; CDI_SIZE] {
-        self.cdi_attest
-    }
-
-    fn cdi_seal(&self) -> &[u8; CDI_SIZE] {
-        self.cdi_seal
-    }
-
-    fn bcc(&self) -> Option<&[u8]> {
-        self.bcc
-    }
-}
-
-/// A BCC handover combines the BCC and CDIs in a single CBOR object.
-/// This function parses the `bcc_handover` to extracts the BCC and CDIs.
-/// The lifetime of the returned `BccHandover` is tied to the given `bcc_handover` slice.
-pub fn bcc_handover_parse(bcc_handover: &[u8]) -> Result<BccHandover> {
-    let mut cdi_attest: *const u8 = ptr::null();
-    let mut cdi_seal: *const u8 = ptr::null();
-    let mut bcc: *const u8 = ptr::null();
-    let mut bcc_size = 0;
-    check_result(
-        // SAFETY: The `bcc_handover` is only read and never stored and the returned pointers should
-        // all point within the address range of the `bcc_handover` or be NULL.
-        unsafe {
-            BccHandoverParse(
-                bcc_handover.as_ptr(),
-                bcc_handover.len(),
-                &mut cdi_attest,
-                &mut cdi_seal,
-                &mut bcc,
-                &mut bcc_size,
-            )
-        },
-        bcc_size,
-    )?;
-    let cdi_attest = sub_slice(bcc_handover, cdi_attest, CDI_SIZE)?;
-    let cdi_seal = sub_slice(bcc_handover, cdi_seal, CDI_SIZE)?;
-    let bcc = sub_slice(bcc_handover, bcc, bcc_size).ok();
-    Ok(BccHandover {
-        cdi_attest: cdi_attest.try_into().map_err(|_| DiceError::PlatformError)?,
-        cdi_seal: cdi_seal.try_into().map_err(|_| DiceError::PlatformError)?,
-        bcc,
-    })
-}
-
-/// Gets a slice the `addr` points to and of length `len`.
-/// The slice should be contained in the buffer.
-fn sub_slice(buffer: &[u8], addr: *const u8, len: usize) -> Result<&[u8]> {
-    if addr.is_null() || !buffer.as_ptr_range().contains(&addr) {
-        return Err(DiceError::PlatformError);
-    }
-    // SAFETY: This is safe because addr is not null and is within the range of the buffer.
-    let start: usize = unsafe {
-        addr.offset_from(buffer.as_ptr()).try_into().map_err(|_| DiceError::PlatformError)?
-    };
-    start.checked_add(len).and_then(|end| buffer.get(start..end)).ok_or(DiceError::PlatformError)
-}
diff --git a/diced/open_dice/src/dice.rs b/diced/open_dice/src/dice.rs
deleted file mode 100644
index e42e373..0000000
--- a/diced/open_dice/src/dice.rs
+++ /dev/null
@@ -1,287 +0,0 @@
-// 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, DICE_PRIVATE_KEY_SIZE,
-    DICE_PUBLIC_KEY_SIZE, DICE_SIGNATURE_SIZE,
-};
-use std::{marker::PhantomData, 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 a private key.
-pub const PRIVATE_KEY_SIZE: usize = DICE_PRIVATE_KEY_SIZE as usize;
-/// The size of a public key.
-pub const PUBLIC_KEY_SIZE: usize = DICE_PUBLIC_KEY_SIZE as usize;
-/// The size of a signature.
-pub const SIGNATURE_SIZE: usize = DICE_SIGNATURE_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 the public key.
-pub type PublicKey = [u8; PUBLIC_KEY_SIZE];
-/// Array type of the signature.
-pub type Signature = [u8; SIGNATURE_SIZE];
-/// Array type of DICE ID.
-pub type DiceId = [u8; ID_SIZE];
-
-/// A trait for types that represent Dice artifacts, which include:
-///
-/// - Attestation CDI
-/// - Sealing CDI
-/// - Boot Certificate Chain
-///
-/// Types that implement this trait provide an access these artifacts.
-pub trait DiceArtifacts {
-    /// Returns a reference to the attestation CDI.
-    fn cdi_attest(&self) -> &[u8; CDI_SIZE];
-
-    /// Returns a reference to the sealing CDI.
-    fn cdi_seal(&self) -> &[u8; CDI_SIZE];
-
-    /// Returns a reference to the Boot Certificate Chain, if present.
-    fn bcc(&self) -> Option<&[u8]>;
-}
-
-/// TODO(b/268587826): Clean up the memory cache after zeroing out the memory
-/// for sensitive data like CDI values and private key.
-/// CDI Values.
-#[derive(Debug, Zeroize, ZeroizeOnDrop, Default)]
-pub struct CdiValues {
-    /// Attestation CDI.
-    pub cdi_attest: [u8; CDI_SIZE],
-    /// Sealing CDI.
-    pub cdi_seal: [u8; CDI_SIZE],
-}
-
-/// Private key seed. The data is zeroed out when the struct is dropped.
-#[derive(Zeroize, ZeroizeOnDrop, Default)]
-pub struct PrivateKeySeed([u8; PRIVATE_KEY_SEED_SIZE]);
-
-impl PrivateKeySeed {
-    /// Returns an array reference of the private key seed.
-    pub fn as_array(&self) -> &[u8; PRIVATE_KEY_SEED_SIZE] {
-        &self.0
-    }
-
-    /// Returns a mutable pointer to the slice buffer of the private key seed.
-    pub fn as_mut_ptr(&mut self) -> *mut u8 {
-        self.0.as_mut_ptr()
-    }
-}
-
-/// Private key. The data is zeroed out when the struct is dropped.
-#[derive(Zeroize, ZeroizeOnDrop)]
-pub struct PrivateKey([u8; PRIVATE_KEY_SIZE]);
-
-impl Default for PrivateKey {
-    /// Creates a new `PrivateKey` instance with all bytes set to 0.
-    ///
-    /// Since the size of the private key array is too large to be initialized
-    /// with a default value, this implementation sets all the bytes in the array
-    /// to 0 using the `[0u8; PRIVATE_KEY_SIZE]` syntax.
-    fn default() -> Self {
-        Self([0u8; PRIVATE_KEY_SIZE])
-    }
-}
-
-impl PrivateKey {
-    /// Returns an array reference of the private key.
-    pub fn as_array(&self) -> &[u8; PRIVATE_KEY_SIZE] {
-        &self.0
-    }
-
-    /// Returns a mutable pointer to the slice buffer of the private key.
-    pub fn as_mut_ptr(&mut self) -> *mut u8 {
-        self.0.as_mut_ptr()
-    }
-}
-
-/// 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<'a> {
-    dice_inputs: DiceInputValues,
-    // DiceInputValues contains a pointer to the separate config descriptor, which must therefore
-    // outlive it. Make sure the borrow checker can enforce that.
-    config_descriptor: PhantomData<&'a [u8]>,
-}
-
-impl<'a> InputValues<'a> {
-    /// Creates a new `InputValues`.
-    pub fn new(
-        code_hash: Hash,
-        config: Config<'a>,
-        authority_hash: Hash,
-        mode: DiceMode,
-        hidden: Hidden,
-    ) -> Self {
-        Self {
-            dice_inputs: 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,
-            },
-            config_descriptor: PhantomData,
-        }
-    }
-
-    /// Returns a raw pointer to the wrapped `DiceInputValues`.
-    pub fn as_ptr(&self) -> *const DiceInputValues {
-        &self.dice_inputs 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 = PrivateKeySeed::default();
-    check_result(
-        // 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.
-        unsafe {
-            DiceDeriveCdiPrivateKeySeed(
-                ptr::null_mut(), // context
-                cdi_attest.as_ptr(),
-                seed.as_mut_ptr(),
-            )
-        },
-        seed.0.len(),
-    )?;
-    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];
-    check_result(
-        // 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.
-        unsafe {
-            DiceDeriveCdiCertificateId(
-                ptr::null_mut(), // context
-                cdi_public_key.as_ptr(),
-                cdi_public_key.len(),
-                id.as_mut_ptr(),
-            )
-        },
-        id.len(),
-    )?;
-    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;
-    check_result(
-        // 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.
-        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(),
-            )
-        },
-        next_cdi_certificate_actual_size,
-    )?;
-    Ok(next_cdi_certificate_actual_size)
-}
diff --git a/diced/open_dice/src/error.rs b/diced/open_dice/src/error.rs
deleted file mode 100644
index 53ffd2d..0000000
--- a/diced/open_dice/src/error.rs
+++ /dev/null
@@ -1,63 +0,0 @@
-// 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(usize),
-    /// Platform error.
-    PlatformError,
-}
-
-/// 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(buffer_required_size) => {
-                write!(f, "buffer too small. Required {buffer_required_size} bytes.")
-            }
-            Self::PlatformError => write!(f, "platform error"),
-        }
-    }
-}
-
-/// DICE result type.
-pub type Result<T> = result::Result<T, DiceError>;
-
-/// Checks the given `DiceResult`. Returns an error if it's not OK.
-pub(crate) fn check_result(result: DiceResult, buffer_required_size: usize) -> Result<()> {
-    match result {
-        DiceResult::kDiceResultOk => Ok(()),
-        DiceResult::kDiceResultInvalidInput => Err(DiceError::InvalidInput),
-        DiceResult::kDiceResultBufferTooSmall => {
-            Err(DiceError::BufferTooSmall(buffer_required_size))
-        }
-        DiceResult::kDiceResultPlatformError => Err(DiceError::PlatformError),
-    }
-}
diff --git a/diced/open_dice/src/lib.rs b/diced/open_dice/src/lib.rs
deleted file mode 100644
index 4a85a1e..0000000
--- a/diced/open_dice/src/lib.rs
+++ /dev/null
@@ -1,45 +0,0 @@
-// 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_handover_main_flow, bcc_handover_parse, bcc_main_flow,
-    BccHandover,
-};
-pub use dice::{
-    derive_cdi_certificate_id, derive_cdi_private_key_seed, dice_main_flow, Cdi, CdiValues, Config,
-    DiceArtifacts, DiceMode, Hash, Hidden, InlineConfig, InputValues, PrivateKey, PrivateKeySeed,
-    PublicKey, Signature, CDI_SIZE, HASH_SIZE, HIDDEN_SIZE, ID_SIZE, PRIVATE_KEY_SEED_SIZE,
-};
-pub use error::{DiceError, Result};
-pub use ops::{generate_certificate, hash, kdf, keypair_from_seed, sign, verify};
-#[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
deleted file mode 100644
index 6b9202a..0000000
--- a/diced/open_dice/src/ops.rs
+++ /dev/null
@@ -1,162 +0,0 @@
-// 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, PrivateKey, PublicKey, Signature, HASH_SIZE, PRIVATE_KEY_SEED_SIZE,
-    PRIVATE_KEY_SIZE, PUBLIC_KEY_SIZE, SIGNATURE_SIZE,
-};
-use crate::error::{check_result, Result};
-use open_dice_cbor_bindgen::{
-    DiceGenerateCertificate, DiceHash, DiceKdf, DiceKeypairFromSeed, DiceSign, DiceVerify,
-};
-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];
-    check_result(
-        // 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.
-        unsafe {
-            DiceHash(
-                ptr::null_mut(), // context
-                input.as_ptr(),
-                input.len(),
-                output.as_mut_ptr(),
-            )
-        },
-        output.len(),
-    )?;
-    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<()> {
-    check_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.
-        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(),
-            )
-        },
-        derived_key.len(),
-    )
-}
-
-/// Deterministically generates a public and private key pair from `seed`.
-/// Since this is deterministic, `seed` is as sensitive as a private key and can
-/// be used directly as the private key.
-pub fn keypair_from_seed(seed: &[u8; PRIVATE_KEY_SEED_SIZE]) -> Result<(PublicKey, PrivateKey)> {
-    let mut public_key = [0u8; PUBLIC_KEY_SIZE];
-    let mut private_key = PrivateKey::default();
-    check_result(
-        // SAFETY: The function writes to the `public_key` and `private_key` within the given
-        // bounds, and only reads the `seed`. The first argument context is not used in this
-        // function.
-        unsafe {
-            DiceKeypairFromSeed(
-                ptr::null_mut(), // context
-                seed.as_ptr(),
-                public_key.as_mut_ptr(),
-                private_key.as_mut_ptr(),
-            )
-        },
-        public_key.len(),
-    )?;
-    Ok((public_key, private_key))
-}
-
-/// Signs the `message` with the give `private_key` using `DiceSign`.
-pub fn sign(message: &[u8], private_key: &[u8; PRIVATE_KEY_SIZE]) -> Result<Signature> {
-    let mut signature = [0u8; SIGNATURE_SIZE];
-    check_result(
-        // SAFETY: The function writes to the `signature` within the given bounds, and only reads
-        // the message and the private key. The first argument context is not used in this function.
-        unsafe {
-            DiceSign(
-                ptr::null_mut(), // context
-                message.as_ptr(),
-                message.len(),
-                private_key.as_ptr(),
-                signature.as_mut_ptr(),
-            )
-        },
-        signature.len(),
-    )?;
-    Ok(signature)
-}
-
-/// Verifies the `signature` of the `message` with the given `public_key` using `DiceVerify`.
-pub fn verify(message: &[u8], signature: &Signature, public_key: &PublicKey) -> Result<()> {
-    check_result(
-        // SAFETY: only reads the messages, signature and public key as constant values.
-        // The first argument context is not used in this function.
-        unsafe {
-            DiceVerify(
-                ptr::null_mut(), // context
-                message.as_ptr(),
-                message.len(),
-                signature.as_ptr(),
-                public_key.as_ptr(),
-            )
-        },
-        0,
-    )
-}
-
-/// 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;
-    check_result(
-        // 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.
-        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,
-            )
-        },
-        certificate_actual_size,
-    )?;
-    Ok(certificate_actual_size)
-}
diff --git a/diced/open_dice/src/retry.rs b/diced/open_dice/src/retry.rs
deleted file mode 100644
index 3db4781..0000000
--- a/diced/open_dice/src/retry.rs
+++ /dev/null
@@ -1,146 +0,0 @@
-// 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, DiceArtifacts, InputValues, CDI_SIZE, 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.
-#[derive(Debug)]
-pub struct OwnedDiceArtifacts {
-    /// CDI Values.
-    cdi_values: CdiValues,
-    /// Boot Certificate Chain.
-    bcc: Vec<u8>,
-}
-
-impl DiceArtifacts for OwnedDiceArtifacts {
-    fn cdi_attest(&self) -> &[u8; CDI_SIZE] {
-        &self.cdi_values.cdi_attest
-    }
-
-    fn cdi_seal(&self) -> &[u8; CDI_SIZE] {
-        &self.cdi_values.cdi_seal
-    }
-
-    fn bcc(&self) -> Option<&[u8]> {
-        Some(&self.bcc)
-    }
-}
-
-/// Retries the given function with bigger measured buffer size.
-fn retry_with_measured_buffer<F>(mut f: F) -> Result<Vec<u8>>
-where
-    F: FnMut(&mut Vec<u8>) -> Result<usize>,
-{
-    let mut buffer = Vec::new();
-    match f(&mut buffer) {
-        Err(DiceError::BufferTooSmall(actual_size)) => {
-            buffer.resize(actual_size, 0);
-            f(&mut buffer)?;
-        }
-        Err(e) => return Err(e),
-        Ok(_) => {}
-    };
-    Ok(buffer)
-}
-
-/// 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_measured_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_measured_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_measured_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_measured_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
deleted file mode 100644
index a47265b..0000000
--- a/diced/open_dice/tests/api_test.rs
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * 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, derive_cdi_private_key_seed, hash, kdf, keypair_from_seed, sign,
-    verify, CDI_SIZE, 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());
-}
-
-const EXPECTED_SEED: &[u8] = &[
-    0xfa, 0x3c, 0x2f, 0x58, 0x37, 0xf5, 0x8e, 0x96, 0x16, 0x09, 0xf5, 0x22, 0xa1, 0xf1, 0xba, 0xaa,
-    0x19, 0x95, 0x01, 0x79, 0x2e, 0x60, 0x56, 0xaf, 0xf6, 0x41, 0xe7, 0xff, 0x48, 0xf5, 0x3a, 0x08,
-    0x84, 0x8a, 0x98, 0x85, 0x6d, 0xf5, 0x69, 0x21, 0x03, 0xcd, 0x09, 0xc3, 0x28, 0xd6, 0x06, 0xa7,
-    0x57, 0xbd, 0x48, 0x4b, 0x0f, 0x79, 0x0f, 0xf8, 0x2f, 0xf0, 0x0a, 0x41, 0x94, 0xd8, 0x8c, 0xa8,
-];
-
-const EXPECTED_CDI_ATTEST: &[u8] = &[
-    0xfa, 0x3c, 0x2f, 0x58, 0x37, 0xf5, 0x8e, 0x96, 0x16, 0x09, 0xf5, 0x22, 0xa1, 0xf1, 0xba, 0xaa,
-    0x19, 0x95, 0x01, 0x79, 0x2e, 0x60, 0x56, 0xaf, 0xf6, 0x41, 0xe7, 0xff, 0x48, 0xf5, 0x3a, 0x08,
-];
-
-const EXPECTED_CDI_PRIVATE_KEY_SEED: &[u8] = &[
-    0x5f, 0xcc, 0x8e, 0x1a, 0xd1, 0xc2, 0xb3, 0xe9, 0xfb, 0xe1, 0x68, 0xf0, 0xf6, 0x98, 0xfe, 0x0d,
-    0xee, 0xd4, 0xb5, 0x18, 0xcb, 0x59, 0x70, 0x2d, 0xee, 0x06, 0xe5, 0x70, 0xf1, 0x72, 0x02, 0x6e,
-];
-
-const EXPECTED_PUB_KEY: &[u8] = &[
-    0x47, 0x42, 0x4b, 0xbd, 0xd7, 0x23, 0xb4, 0xcd, 0xca, 0xe2, 0x8e, 0xdc, 0x6b, 0xfc, 0x23, 0xc9,
-    0x21, 0x5c, 0x48, 0x21, 0x47, 0xee, 0x5b, 0xfa, 0xaf, 0x88, 0x9a, 0x52, 0xf1, 0x61, 0x06, 0x37,
-];
-const EXPECTED_PRIV_KEY: &[u8] = &[
-    0x5f, 0xcc, 0x8e, 0x1a, 0xd1, 0xc2, 0xb3, 0xe9, 0xfb, 0xe1, 0x68, 0xf0, 0xf6, 0x98, 0xfe, 0x0d,
-    0xee, 0xd4, 0xb5, 0x18, 0xcb, 0x59, 0x70, 0x2d, 0xee, 0x06, 0xe5, 0x70, 0xf1, 0x72, 0x02, 0x6e,
-    0x47, 0x42, 0x4b, 0xbd, 0xd7, 0x23, 0xb4, 0xcd, 0xca, 0xe2, 0x8e, 0xdc, 0x6b, 0xfc, 0x23, 0xc9,
-    0x21, 0x5c, 0x48, 0x21, 0x47, 0xee, 0x5b, 0xfa, 0xaf, 0x88, 0x9a, 0x52, 0xf1, 0x61, 0x06, 0x37,
-];
-
-const EXPECTED_SIGNATURE: &[u8] = &[
-    0x44, 0xae, 0xcc, 0xe2, 0xb9, 0x96, 0x18, 0x39, 0x0e, 0x61, 0x0f, 0x53, 0x07, 0xbf, 0xf2, 0x32,
-    0x3d, 0x44, 0xd4, 0xf2, 0x07, 0x23, 0x30, 0x85, 0x32, 0x18, 0xd2, 0x69, 0xb8, 0x29, 0x3c, 0x26,
-    0xe6, 0x0d, 0x9c, 0xa5, 0xc2, 0x73, 0xcd, 0x8c, 0xb8, 0x3c, 0x3e, 0x5b, 0xfd, 0x62, 0x8d, 0xf6,
-    0xc4, 0x27, 0xa6, 0xe9, 0x11, 0x06, 0x5a, 0xb2, 0x2b, 0x64, 0xf7, 0xfc, 0xbb, 0xab, 0x4a, 0x0e,
-];
-
-#[test]
-fn hash_derive_sign_verify() {
-    let seed = hash(b"MySeedString").unwrap();
-    assert_eq!(seed, EXPECTED_SEED);
-    let cdi_attest = &seed[..CDI_SIZE];
-    assert_eq!(cdi_attest, EXPECTED_CDI_ATTEST);
-    let cdi_private_key_seed = derive_cdi_private_key_seed(cdi_attest.try_into().unwrap()).unwrap();
-    assert_eq!(cdi_private_key_seed.as_array(), EXPECTED_CDI_PRIVATE_KEY_SEED);
-    let (pub_key, priv_key) = keypair_from_seed(cdi_private_key_seed.as_array()).unwrap();
-    assert_eq!(&pub_key, EXPECTED_PUB_KEY);
-    assert_eq!(priv_key.as_array(), EXPECTED_PRIV_KEY);
-    let mut signature = sign(b"MyMessage", priv_key.as_array()).unwrap();
-    assert_eq!(&signature, EXPECTED_SIGNATURE);
-    assert!(verify(b"MyMessage", &signature, &pub_key).is_ok());
-    assert!(verify(b"MyMessage_fail", &signature, &pub_key).is_err());
-    signature[0] += 1;
-    assert!(verify(b"MyMessage", &signature, &pub_key).is_err());
-}
diff --git a/diced/sample_inputs/src/lib.rs b/diced/sample_inputs/src/lib.rs
deleted file mode 100644
index ebbfd29..0000000
--- a/diced/sample_inputs/src/lib.rs
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * 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.
- */
-
-//! Provides a set of sample inputs for a DICE chain and CDI values derived
-//! from it.
-
-mod sample_inputs;
-
-pub use sample_inputs::make_sample_bcc_and_cdis;
diff --git a/diced/sample_inputs/src/sample_inputs.rs b/diced/sample_inputs/src/sample_inputs.rs
deleted file mode 100644
index c665eb3..0000000
--- a/diced/sample_inputs/src/sample_inputs.rs
+++ /dev/null
@@ -1,167 +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 module provides a set of sample input values for a DICE chain, a sample UDS,
-//! as well as tuple of CDIs and BCC derived thereof.
-
-use anyhow::{anyhow, Context, Result};
-use ciborium::{de, ser, value::Value};
-use coset::{iana, Algorithm, AsCborValue, CoseKey, KeyOperation, KeyType, Label};
-use diced_open_dice::{
-    derive_cdi_private_key_seed, keypair_from_seed, retry_bcc_format_config_descriptor,
-    retry_bcc_main_flow, retry_dice_main_flow, Config, DiceArtifacts, DiceMode, InputValues,
-    OwnedDiceArtifacts, CDI_SIZE, HASH_SIZE, HIDDEN_SIZE,
-};
-use std::ffi::CStr;
-
-/// Sample UDS used to perform the root dice flow by `make_sample_bcc_and_cdis`.
-const UDS: &[u8; CDI_SIZE] = &[
-    0x65, 0x4f, 0xab, 0xa9, 0xa5, 0xad, 0x0f, 0x5e, 0x15, 0xc3, 0x12, 0xf7, 0x77, 0x45, 0xfa, 0x55,
-    0x18, 0x6a, 0xa6, 0x34, 0xb6, 0x7c, 0x82, 0x7b, 0x89, 0x4c, 0xc5, 0x52, 0xd3, 0x27, 0x35, 0x8e,
-];
-
-const CODE_HASH_ABL: [u8; 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_HASH_ABL: [u8; 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 HIDDEN_ABL: [u8; 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_HASH_AVB: [u8; 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_HASH_AVB: [u8; 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 HIDDEN_AVB: [u8; 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_HASH_ANDROID: [u8; 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,
-];
-
-fn ed25519_public_key_to_cbor_value(public_key: &[u8]) -> Result<Value> {
-    let key = CoseKey {
-        kty: KeyType::Assigned(iana::KeyType::OKP),
-        alg: Some(Algorithm::Assigned(iana::Algorithm::EdDSA)),
-        key_ops: vec![KeyOperation::Assigned(iana::KeyOperation::Verify)].into_iter().collect(),
-        params: vec![
-            (
-                Label::Int(iana::Ec2KeyParameter::Crv as i64),
-                Value::from(iana::EllipticCurve::Ed25519 as u64),
-            ),
-            (Label::Int(iana::Ec2KeyParameter::X as i64), Value::Bytes(public_key.to_vec())),
-        ],
-        ..Default::default()
-    };
-    key.to_cbor_value()
-        .map_err(|e| anyhow!(format!("Failed to serialize the key to CBOR data. Error: {e}")))
-}
-
-/// Makes a DICE chain (BCC) from the sample input.
-///
-/// The DICE chain is of the following format:
-/// public key derived from UDS -> ABL certificate -> AVB certificate -> Android certificate
-pub fn make_sample_bcc_and_cdis() -> Result<OwnedDiceArtifacts> {
-    let private_key_seed = derive_cdi_private_key_seed(UDS)
-        .context("In make_sample_bcc_and_cdis: Trying to derive private key seed.")?;
-
-    // Gets the root public key in DICE chain (BCC).
-    let (public_key, _) = keypair_from_seed(private_key_seed.as_array())
-        .context("In make_sample_bcc_and_cids: Failed to generate key pair.")?;
-    let ed25519_public_key_value = ed25519_public_key_to_cbor_value(&public_key)?;
-
-    // Gets the ABL certificate to as the root certificate of DICE chain.
-    let config_descriptor = retry_bcc_format_config_descriptor(
-        Some(CStr::from_bytes_with_nul(b"ABL\0").unwrap()),
-        Some(1), // version
-        true,
-    )?;
-    let input_values = InputValues::new(
-        CODE_HASH_ABL,
-        Config::Descriptor(config_descriptor.as_slice()),
-        AUTHORITY_HASH_ABL,
-        DiceMode::kDiceModeNormal,
-        HIDDEN_ABL,
-    );
-    let (cdi_values, cert) = retry_dice_main_flow(UDS, UDS, &input_values)
-        .context("In make_sample_bcc_and_cdis: Trying to run first main flow.")?;
-    let bcc_value = Value::Array(vec![
-        ed25519_public_key_value,
-        de::from_reader(&cert[..]).context("Deserialize root DICE certificate failed")?,
-    ]);
-    let mut bcc: Vec<u8> = vec![];
-    ser::into_writer(&bcc_value, &mut bcc)?;
-
-    // Appends AVB certificate to DICE chain.
-    let config_descriptor = retry_bcc_format_config_descriptor(
-        Some(CStr::from_bytes_with_nul(b"AVB\0").unwrap()),
-        Some(1), // version
-        true,
-    )?;
-    let input_values = InputValues::new(
-        CODE_HASH_AVB,
-        Config::Descriptor(config_descriptor.as_slice()),
-        AUTHORITY_HASH_AVB,
-        DiceMode::kDiceModeNormal,
-        HIDDEN_AVB,
-    );
-    let dice_artifacts =
-        retry_bcc_main_flow(&cdi_values.cdi_attest, &cdi_values.cdi_seal, &bcc, &input_values)
-            .context("In make_sample_bcc_and_cdis: Trying to run first bcc main flow.")?;
-
-    // Appends Android certificate to DICE chain.
-    let config_descriptor = retry_bcc_format_config_descriptor(
-        Some(CStr::from_bytes_with_nul(b"Android\0").unwrap()),
-        Some(12), // version
-        true,
-    )?;
-    let input_values = InputValues::new(
-        [0u8; HASH_SIZE], // code_hash
-        Config::Descriptor(config_descriptor.as_slice()),
-        AUTHORITY_HASH_ANDROID,
-        DiceMode::kDiceModeNormal,
-        [0u8; HIDDEN_SIZE], // hidden
-    );
-    retry_bcc_main_flow(
-        dice_artifacts.cdi_attest(),
-        dice_artifacts.cdi_seal(),
-        dice_artifacts.bcc().ok_or_else(|| anyhow!("bcc is none"))?,
-        &input_values,
-    )
-    .context("In make_sample_bcc_and_cdis: Trying to run second bcc main flow.")
-}
diff --git a/diced/sample_inputs/tests/api_test.rs b/diced/sample_inputs/tests/api_test.rs
deleted file mode 100644
index f0d6c0d..0000000
--- a/diced/sample_inputs/tests/api_test.rs
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- * 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::DiceArtifacts;
-use diced_sample_inputs::make_sample_bcc_and_cdis;
-
-const EXPECTED_SAMPLE_CDI_ATTEST: &[u8] = &[
-    0x3e, 0x57, 0x65, 0x5d, 0x48, 0x02, 0xbd, 0x5c, 0x66, 0xcc, 0x1f, 0x0f, 0xbe, 0x5e, 0x32, 0xb6,
-    0x9e, 0x3d, 0x04, 0xaf, 0x00, 0x15, 0xbc, 0xdd, 0x1f, 0xbc, 0x59, 0xe4, 0xc3, 0x87, 0x95, 0x5e,
-];
-
-const EXPECTED_SAMPLE_CDI_SEAL: &[u8] = &[
-    0x36, 0x1b, 0xd2, 0xb3, 0xc4, 0xda, 0x77, 0xb2, 0x9c, 0xba, 0x39, 0x53, 0x82, 0x93, 0xd9, 0xb8,
-    0x9f, 0x73, 0x2d, 0x27, 0x06, 0x15, 0xa8, 0xcb, 0x6d, 0x1d, 0xf2, 0xb1, 0x54, 0xbb, 0x62, 0xf1,
-];
-
-const EXPECTED_SAMPLE_BCC: &[u8] = &[
-    0x84, 0xa5, 0x01, 0x01, 0x03, 0x27, 0x04, 0x81, 0x02, 0x20, 0x06, 0x21, 0x58, 0x20, 0x3e, 0x85,
-    0xe5, 0x72, 0x75, 0x55, 0xe5, 0x1e, 0xe7, 0xf3, 0x35, 0x94, 0x8e, 0xbb, 0xbd, 0x74, 0x1e, 0x1d,
-    0xca, 0x49, 0x9c, 0x97, 0x39, 0x77, 0x06, 0xd3, 0xc8, 0x6e, 0x8b, 0xd7, 0x33, 0xf9, 0x84, 0x43,
-    0xa1, 0x01, 0x27, 0xa0, 0x59, 0x01, 0x8a, 0xa9, 0x01, 0x78, 0x28, 0x34, 0x32, 0x64, 0x38, 0x38,
-    0x36, 0x34, 0x66, 0x39, 0x37, 0x62, 0x36, 0x35, 0x34, 0x37, 0x61, 0x35, 0x30, 0x63, 0x31, 0x65,
-    0x30, 0x61, 0x37, 0x34, 0x39, 0x66, 0x38, 0x65, 0x66, 0x38, 0x62, 0x38, 0x31, 0x65, 0x63, 0x36,
-    0x32, 0x61, 0x66, 0x02, 0x78, 0x28, 0x31, 0x66, 0x36, 0x39, 0x36, 0x66, 0x30, 0x37, 0x32, 0x35,
-    0x32, 0x66, 0x32, 0x39, 0x65, 0x39, 0x33, 0x66, 0x65, 0x34, 0x64, 0x65, 0x31, 0x39, 0x65, 0x65,
-    0x33, 0x32, 0x63, 0x64, 0x38, 0x31, 0x64, 0x63, 0x34, 0x30, 0x34, 0x65, 0x37, 0x36, 0x3a, 0x00,
-    0x47, 0x44, 0x50, 0x58, 0x40, 0x16, 0x48, 0xf2, 0x55, 0x53, 0x23, 0xdd, 0x15, 0x2e, 0x83, 0x38,
-    0xc3, 0x64, 0x38, 0x63, 0x26, 0x0f, 0xcf, 0x5b, 0xd1, 0x3a, 0xd3, 0x40, 0x3e, 0x23, 0xf8, 0x34,
-    0x4c, 0x6d, 0xa2, 0xbe, 0x25, 0x1c, 0xb0, 0x29, 0xe8, 0xc3, 0xfb, 0xb8, 0x80, 0xdc, 0xb1, 0xd2,
-    0xb3, 0x91, 0x4d, 0xd3, 0xfb, 0x01, 0x0f, 0xe4, 0xe9, 0x46, 0xa2, 0xc0, 0x26, 0x57, 0x5a, 0xba,
-    0x30, 0xf7, 0x15, 0x98, 0x14, 0x3a, 0x00, 0x47, 0x44, 0x53, 0x56, 0xa3, 0x3a, 0x00, 0x01, 0x11,
-    0x71, 0x63, 0x41, 0x42, 0x4c, 0x3a, 0x00, 0x01, 0x11, 0x72, 0x01, 0x3a, 0x00, 0x01, 0x11, 0x73,
-    0xf6, 0x3a, 0x00, 0x47, 0x44, 0x52, 0x58, 0x40, 0x47, 0xae, 0x42, 0x27, 0x4c, 0xcb, 0x65, 0x4d,
-    0xee, 0x74, 0x2d, 0x05, 0x78, 0x2a, 0x08, 0x2a, 0xa5, 0xf0, 0xcf, 0xea, 0x3e, 0x60, 0xee, 0x97,
-    0x11, 0x4b, 0x5b, 0xe6, 0x05, 0x0c, 0xe8, 0x90, 0xf5, 0x22, 0xc4, 0xc6, 0x67, 0x7a, 0x22, 0x27,
-    0x17, 0xb3, 0x79, 0xcc, 0x37, 0x64, 0x5e, 0x19, 0x4f, 0x96, 0x37, 0x67, 0x3c, 0xd0, 0xc5, 0xed,
-    0x0f, 0xdd, 0xe7, 0x2e, 0x4f, 0x70, 0x97, 0x30, 0x3a, 0x00, 0x47, 0x44, 0x54, 0x58, 0x40, 0xf9,
-    0x00, 0x9d, 0xc2, 0x59, 0x09, 0xe0, 0xb6, 0x98, 0xbd, 0xe3, 0x97, 0x4a, 0xcb, 0x3c, 0xe7, 0x6b,
-    0x24, 0xc3, 0xe4, 0x98, 0xdd, 0xa9, 0x6a, 0x41, 0x59, 0x15, 0xb1, 0x23, 0xe6, 0xc8, 0xdf, 0xfb,
-    0x52, 0xb4, 0x52, 0xc1, 0xb9, 0x61, 0xdd, 0xbc, 0x5b, 0x37, 0x0e, 0x12, 0x12, 0xb2, 0xfd, 0xc1,
-    0x09, 0xb0, 0xcf, 0x33, 0x81, 0x4c, 0xc6, 0x29, 0x1b, 0x99, 0xea, 0xae, 0xfd, 0xaa, 0x0d, 0x3a,
-    0x00, 0x47, 0x44, 0x56, 0x41, 0x01, 0x3a, 0x00, 0x47, 0x44, 0x57, 0x58, 0x2d, 0xa5, 0x01, 0x01,
-    0x03, 0x27, 0x04, 0x81, 0x02, 0x20, 0x06, 0x21, 0x58, 0x20, 0xb1, 0x02, 0xcc, 0x2c, 0xb2, 0x6a,
-    0x3b, 0xe9, 0xc1, 0xd3, 0x95, 0x10, 0xa0, 0xe1, 0xff, 0x51, 0xde, 0x57, 0xd5, 0x65, 0x28, 0xfd,
-    0x7f, 0xeb, 0xd4, 0xca, 0x15, 0xf3, 0xca, 0xdf, 0x37, 0x88, 0x3a, 0x00, 0x47, 0x44, 0x58, 0x41,
-    0x20, 0x58, 0x40, 0x58, 0xd8, 0x03, 0x24, 0x53, 0x60, 0x57, 0xa9, 0x09, 0xfa, 0xab, 0xdc, 0x57,
-    0x1e, 0xf0, 0xe5, 0x1e, 0x51, 0x6f, 0x9e, 0xa3, 0x42, 0xe6, 0x6a, 0x8c, 0xaa, 0xad, 0x08, 0x48,
-    0xde, 0x7f, 0x4f, 0x6e, 0x2f, 0x7f, 0x39, 0x6c, 0xa1, 0xf8, 0x42, 0x71, 0xfe, 0x17, 0x3d, 0xca,
-    0x31, 0x83, 0x92, 0xed, 0xbb, 0x40, 0xb8, 0x10, 0xe0, 0xf2, 0x5a, 0x99, 0x53, 0x38, 0x46, 0x33,
-    0x97, 0x78, 0x05, 0x84, 0x43, 0xa1, 0x01, 0x27, 0xa0, 0x59, 0x01, 0x8a, 0xa9, 0x01, 0x78, 0x28,
-    0x31, 0x66, 0x36, 0x39, 0x36, 0x66, 0x30, 0x37, 0x32, 0x35, 0x32, 0x66, 0x32, 0x39, 0x65, 0x39,
-    0x33, 0x66, 0x65, 0x34, 0x64, 0x65, 0x31, 0x39, 0x65, 0x65, 0x33, 0x32, 0x63, 0x64, 0x38, 0x31,
-    0x64, 0x63, 0x34, 0x30, 0x34, 0x65, 0x37, 0x36, 0x02, 0x78, 0x28, 0x32, 0x35, 0x39, 0x34, 0x38,
-    0x39, 0x65, 0x36, 0x39, 0x37, 0x34, 0x38, 0x37, 0x30, 0x35, 0x64, 0x65, 0x33, 0x65, 0x32, 0x66,
-    0x34, 0x34, 0x32, 0x36, 0x37, 0x65, 0x61, 0x34, 0x39, 0x33, 0x38, 0x66, 0x66, 0x36, 0x61, 0x35,
-    0x37, 0x32, 0x35, 0x3a, 0x00, 0x47, 0x44, 0x50, 0x58, 0x40, 0xa4, 0x0c, 0xcb, 0xc1, 0xbf, 0xfa,
-    0xcc, 0xfd, 0xeb, 0xf4, 0xfc, 0x43, 0x83, 0x7f, 0x46, 0x8d, 0xd8, 0xd8, 0x14, 0xc1, 0x96, 0x14,
-    0x1f, 0x6e, 0xb3, 0xa0, 0xd9, 0x56, 0xb3, 0xbf, 0x2f, 0xfa, 0x88, 0x70, 0x11, 0x07, 0x39, 0xa4,
-    0xd2, 0xa9, 0x6b, 0x18, 0x28, 0xe8, 0x29, 0x20, 0x49, 0x0f, 0xbb, 0x8d, 0x08, 0x8c, 0xc6, 0x54,
-    0xe9, 0x71, 0xd2, 0x7e, 0xa4, 0xfe, 0x58, 0x7f, 0xd3, 0xc7, 0x3a, 0x00, 0x47, 0x44, 0x53, 0x56,
-    0xa3, 0x3a, 0x00, 0x01, 0x11, 0x71, 0x63, 0x41, 0x56, 0x42, 0x3a, 0x00, 0x01, 0x11, 0x72, 0x01,
-    0x3a, 0x00, 0x01, 0x11, 0x73, 0xf6, 0x3a, 0x00, 0x47, 0x44, 0x52, 0x58, 0x40, 0x93, 0x17, 0xe1,
-    0x11, 0x27, 0x59, 0xd0, 0xef, 0x75, 0x0b, 0x2b, 0x1c, 0x0f, 0x5f, 0x52, 0xc3, 0x29, 0x23, 0xb5,
-    0x2a, 0xe6, 0x12, 0x72, 0x6f, 0x39, 0x86, 0x65, 0x2d, 0xf2, 0xe4, 0xe7, 0xd0, 0xaf, 0x0e, 0xa7,
-    0x99, 0x16, 0x89, 0x97, 0x21, 0xf7, 0xdc, 0x89, 0xdc, 0xde, 0xbb, 0x94, 0x88, 0x1f, 0xda, 0xe2,
-    0xf3, 0xe0, 0x54, 0xf9, 0x0e, 0x29, 0xb1, 0xbd, 0xe1, 0x0c, 0x0b, 0xd7, 0xf6, 0x3a, 0x00, 0x47,
-    0x44, 0x54, 0x58, 0x40, 0xb2, 0x69, 0x05, 0x48, 0x56, 0xb5, 0xfa, 0x55, 0x6f, 0xac, 0x56, 0xd9,
-    0x02, 0x35, 0x2b, 0xaa, 0x4c, 0xba, 0x28, 0xdd, 0x82, 0x3a, 0x86, 0xf5, 0xd4, 0xc2, 0xf1, 0xf9,
-    0x35, 0x7d, 0xe4, 0x43, 0x13, 0xbf, 0xfe, 0xd3, 0x36, 0xd8, 0x1c, 0x12, 0x78, 0x5c, 0x9c, 0x3e,
-    0xf6, 0x66, 0xef, 0xab, 0x3d, 0x0f, 0x89, 0xa4, 0x6f, 0xc9, 0x72, 0xee, 0x73, 0x43, 0x02, 0x8a,
-    0xef, 0xbc, 0x05, 0x98, 0x3a, 0x00, 0x47, 0x44, 0x56, 0x41, 0x01, 0x3a, 0x00, 0x47, 0x44, 0x57,
-    0x58, 0x2d, 0xa5, 0x01, 0x01, 0x03, 0x27, 0x04, 0x81, 0x02, 0x20, 0x06, 0x21, 0x58, 0x20, 0x96,
-    0x6d, 0x96, 0x42, 0xda, 0x64, 0x51, 0xad, 0xfa, 0x00, 0xbc, 0xbc, 0x95, 0x8a, 0xb0, 0xb9, 0x76,
-    0x01, 0xe6, 0xbd, 0xc0, 0x26, 0x79, 0x26, 0xfc, 0x0f, 0x1d, 0x87, 0x65, 0xf1, 0xf3, 0x99, 0x3a,
-    0x00, 0x47, 0x44, 0x58, 0x41, 0x20, 0x58, 0x40, 0x10, 0x7f, 0x77, 0xad, 0x70, 0xbd, 0x52, 0x81,
-    0x28, 0x8d, 0x24, 0x81, 0xb4, 0x3f, 0x21, 0x68, 0x9f, 0xc3, 0x80, 0x68, 0x86, 0x55, 0xfb, 0x2e,
-    0x6d, 0x96, 0xe1, 0xe1, 0xb7, 0x28, 0x8d, 0x63, 0x85, 0xba, 0x2a, 0x01, 0x33, 0x87, 0x60, 0x63,
-    0xbb, 0x16, 0x3f, 0x2f, 0x3d, 0xf4, 0x2d, 0x48, 0x5b, 0x87, 0xed, 0xda, 0x34, 0xeb, 0x9c, 0x4d,
-    0x14, 0xac, 0x65, 0xf4, 0xfa, 0xef, 0x45, 0x0b, 0x84, 0x43, 0xa1, 0x01, 0x27, 0xa0, 0x59, 0x01,
-    0x8f, 0xa9, 0x01, 0x78, 0x28, 0x32, 0x35, 0x39, 0x34, 0x38, 0x39, 0x65, 0x36, 0x39, 0x37, 0x34,
-    0x38, 0x37, 0x30, 0x35, 0x64, 0x65, 0x33, 0x65, 0x32, 0x66, 0x34, 0x34, 0x32, 0x36, 0x37, 0x65,
-    0x61, 0x34, 0x39, 0x33, 0x38, 0x66, 0x66, 0x36, 0x61, 0x35, 0x37, 0x32, 0x35, 0x02, 0x78, 0x28,
-    0x35, 0x64, 0x34, 0x65, 0x64, 0x37, 0x66, 0x34, 0x31, 0x37, 0x61, 0x39, 0x35, 0x34, 0x61, 0x31,
-    0x38, 0x31, 0x34, 0x30, 0x37, 0x62, 0x35, 0x38, 0x38, 0x35, 0x61, 0x66, 0x64, 0x37, 0x32, 0x61,
-    0x35, 0x62, 0x66, 0x34, 0x30, 0x64, 0x61, 0x36, 0x3a, 0x00, 0x47, 0x44, 0x50, 0x58, 0x40, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3a,
-    0x00, 0x47, 0x44, 0x53, 0x58, 0x1a, 0xa3, 0x3a, 0x00, 0x01, 0x11, 0x71, 0x67, 0x41, 0x6e, 0x64,
-    0x72, 0x6f, 0x69, 0x64, 0x3a, 0x00, 0x01, 0x11, 0x72, 0x0c, 0x3a, 0x00, 0x01, 0x11, 0x73, 0xf6,
-    0x3a, 0x00, 0x47, 0x44, 0x52, 0x58, 0x40, 0x26, 0x1a, 0xbd, 0x26, 0xd8, 0x37, 0x8f, 0x4a, 0xf2,
-    0x9e, 0x49, 0x4d, 0x93, 0x23, 0xc4, 0x6e, 0x02, 0xda, 0xe0, 0x00, 0x02, 0xe7, 0xed, 0x29, 0xdf,
-    0x2b, 0xb3, 0x69, 0xf3, 0x55, 0x0e, 0x4c, 0x22, 0xdc, 0xcf, 0xf5, 0x92, 0xc9, 0xfa, 0x78, 0x98,
-    0xf1, 0x0e, 0x55, 0x5f, 0xf4, 0x45, 0xed, 0xc0, 0x0a, 0x72, 0x2a, 0x7a, 0x3a, 0xd2, 0xb1, 0xf7,
-    0x76, 0xfe, 0x2a, 0x6b, 0x7b, 0x2a, 0x53, 0x3a, 0x00, 0x47, 0x44, 0x54, 0x58, 0x40, 0x04, 0x25,
-    0x5d, 0x60, 0x5f, 0x5c, 0x45, 0x0d, 0xf2, 0x9a, 0x6e, 0x99, 0x30, 0x03, 0xb8, 0xd6, 0xe1, 0x99,
-    0x71, 0x1b, 0xf8, 0x44, 0xfa, 0xb5, 0x31, 0x79, 0x1c, 0x37, 0x68, 0x4e, 0x1d, 0xc0, 0x24, 0x74,
-    0x68, 0xf8, 0x80, 0x20, 0x3e, 0x44, 0xb1, 0x43, 0xd2, 0x9c, 0xfc, 0x12, 0x9e, 0x77, 0x0a, 0xde,
-    0x29, 0x24, 0xff, 0x2e, 0xfa, 0xc7, 0x10, 0xd5, 0x73, 0xd4, 0xc6, 0xdf, 0x62, 0x9f, 0x3a, 0x00,
-    0x47, 0x44, 0x56, 0x41, 0x01, 0x3a, 0x00, 0x47, 0x44, 0x57, 0x58, 0x2d, 0xa5, 0x01, 0x01, 0x03,
-    0x27, 0x04, 0x81, 0x02, 0x20, 0x06, 0x21, 0x58, 0x20, 0xdb, 0xe7, 0x5b, 0x3f, 0xa3, 0x42, 0xb0,
-    0x9c, 0xf8, 0x40, 0x8c, 0xb0, 0x9c, 0xf0, 0x0a, 0xaf, 0xdf, 0x6f, 0xe5, 0x09, 0x21, 0x11, 0x92,
-    0xe1, 0xf8, 0xc5, 0x09, 0x02, 0x3d, 0x1f, 0xb7, 0xc5, 0x3a, 0x00, 0x47, 0x44, 0x58, 0x41, 0x20,
-    0x58, 0x40, 0xc4, 0xc1, 0xd7, 0x1c, 0x2d, 0x26, 0x89, 0x22, 0xcf, 0xa6, 0x99, 0x77, 0x30, 0x84,
-    0x86, 0x27, 0x59, 0x8f, 0xd8, 0x08, 0x75, 0xe0, 0xb2, 0xef, 0xf9, 0xfa, 0xa5, 0x40, 0x8c, 0xd3,
-    0xeb, 0xbb, 0xda, 0xf2, 0xc8, 0xae, 0x41, 0x22, 0x50, 0x9c, 0xe8, 0xb2, 0x9c, 0x9b, 0x3f, 0x8a,
-    0x78, 0x76, 0xab, 0xd0, 0xbe, 0xfc, 0xe4, 0x79, 0xcb, 0x1b, 0x2b, 0xaa, 0x4d, 0xdd, 0x15, 0x61,
-    0x42, 0x06,
-];
-
-#[test]
-fn sample_bcc_and_cdis_are_as_expected() {
-    let dice_artifacts = make_sample_bcc_and_cdis().unwrap();
-    assert_eq!(dice_artifacts.cdi_attest(), EXPECTED_SAMPLE_CDI_ATTEST);
-    assert_eq!(dice_artifacts.cdi_seal(), EXPECTED_SAMPLE_CDI_SEAL);
-    assert_eq!(dice_artifacts.bcc(), Some(EXPECTED_SAMPLE_BCC));
-}
diff --git a/fsverity_init/Android.bp b/fsverity_init/Android.bp
index 07eaf6a..d9bff3b 100644
--- a/fsverity_init/Android.bp
+++ b/fsverity_init/Android.bp
@@ -13,6 +13,7 @@
         "fsverity_init.cpp",
     ],
     static_libs: [
+        "aconfig_fsverity_init_c_lib",
         "libc++fs",
         "libmini_keyctl_static",
     ],
@@ -23,3 +24,14 @@
     ],
     cflags: ["-Werror", "-Wall", "-Wextra"],
 }
+
+aconfig_declarations {
+    name: "aconfig_fsverity_init",
+    package: "android.security.flag",
+    srcs: ["flags.aconfig"],
+}
+
+cc_aconfig_library {
+    name: "aconfig_fsverity_init_c_lib",
+    aconfig_declarations: "aconfig_fsverity_init",
+}
diff --git a/fsverity_init/flags.aconfig b/fsverity_init/flags.aconfig
new file mode 100644
index 0000000..20640d7
--- /dev/null
+++ b/fsverity_init/flags.aconfig
@@ -0,0 +1,9 @@
+package: "android.security.flag"
+
+flag {
+    name: "deprecate_fsverity_init"
+    namespace: "hardware_backed_security"
+    description: "Feature flag for deprecate fsverity_init"
+    bug: "290064770"
+    is_fixed_read_only: true
+}
diff --git a/fsverity_init/fsverity_init.cpp b/fsverity_init/fsverity_init.cpp
index 797118d..717beeb 100644
--- a/fsverity_init/fsverity_init.cpp
+++ b/fsverity_init/fsverity_init.cpp
@@ -43,6 +43,7 @@
 #include <android-base/file.h>
 #include <android-base/logging.h>
 #include <android-base/strings.h>
+#include <android_security_flag.h>
 #include <log/log.h>
 #include <mini_keyctl_utils.h>
 
@@ -79,6 +80,13 @@
 }
 
 int main(int argc, const char** argv) {
+    if (android::security::flag::deprecate_fsverity_init()) {
+        // Don't load keys to the built-in fs-verity keyring in kernel. This will make existing
+        // files not readable. We expect to only enable the flag when there are no such files or
+        // when failure is ok (e.g. with a fallback).
+        return 0;
+    }
+
     if (argc < 2) {
         LOG(ERROR) << "Not enough arguments";
         return -1;
diff --git a/identity/Android.bp b/identity/Android.bp
index 007a310..f7a540a 100644
--- a/identity/Android.bp
+++ b/identity/Android.bp
@@ -51,6 +51,7 @@
         "liblog",
         "libutils",
         "libutilscallstack",
+        "libkeystore-attestation-application-id",
     ],
     static_libs: [
         "android.hardware.keymaster-V3-cpp",
@@ -60,7 +61,6 @@
         "libcppbor_external",
         "libcredstore_aidl",
         "libkeymaster4support",
-        "libkeystore-attestation-application-id",
         "librkp_support",
     ],
 }
diff --git a/keystore/Android.bp b/keystore/Android.bp
index 221ead9..c79d00b 100644
--- a/keystore/Android.bp
+++ b/keystore/Android.bp
@@ -69,19 +69,16 @@
     defaults: ["keystore_defaults"],
 
     srcs: [
-        ":IKeyAttestationApplicationIdProvider.aidl",
         "keystore_attestation_id.cpp",
-        "KeyAttestationApplicationId.cpp",
-        "KeyAttestationPackageInfo.cpp",
-        "Signature.cpp",
     ],
     shared_libs: [
+        "android.security.aaid_aidl-cpp",
         "libbase",
         "libbinder",
+        "libcrypto",
         "libhidlbase",
         "liblog",
         "libutils",
-        "libcrypto",
     ],
 
     export_include_dirs: ["include"],
diff --git a/keystore/KeyAttestationApplicationId.cpp b/keystore/KeyAttestationApplicationId.cpp
deleted file mode 100644
index 1838b07..0000000
--- a/keystore/KeyAttestationApplicationId.cpp
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
-**
-** Copyright 2016, 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.
-*/
-
-#include "include/keystore/KeyAttestationApplicationId.h"
-
-#include <binder/Parcel.h>
-
-namespace android {
-namespace security {
-namespace keymaster {
-
-KeyAttestationApplicationId::KeyAttestationApplicationId() = default;
-
-KeyAttestationApplicationId::KeyAttestationApplicationId(
-    std::optional<KeyAttestationPackageInfo> package)
-    : packageInfos_(new std::vector<std::optional<KeyAttestationPackageInfo>>()) {
-    packageInfos_->push_back(std::move(package));
-}
-
-KeyAttestationApplicationId::KeyAttestationApplicationId(PackageInfoVector packages)
-    : packageInfos_(std::make_shared<PackageInfoVector>(std::move(packages))) {}
-
-status_t KeyAttestationApplicationId::writeToParcel(Parcel* parcel) const {
-    return parcel->writeParcelableVector(packageInfos_);
-}
-
-status_t KeyAttestationApplicationId::readFromParcel(const Parcel* parcel) {
-    std::optional<std::vector<std::optional<KeyAttestationPackageInfo>>> temp_vector;
-    auto rc = parcel->readParcelableVector(&temp_vector);
-    if (rc != NO_ERROR) return rc;
-    packageInfos_.reset();
-    if (temp_vector) {
-        packageInfos_ = std::make_shared<PackageInfoVector>(std::move(*temp_vector));
-    }
-    return NO_ERROR;
-}
-
-}  // namespace keymaster
-}  // namespace security
-}  // namespace android
diff --git a/keystore/KeyAttestationPackageInfo.cpp b/keystore/KeyAttestationPackageInfo.cpp
deleted file mode 100644
index 8e9a36a..0000000
--- a/keystore/KeyAttestationPackageInfo.cpp
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
-**
-** Copyright 2016, 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.
-*/
-
-#include "include/keystore/KeyAttestationPackageInfo.h"
-
-#include <binder/Parcel.h>
-
-namespace android {
-namespace security {
-namespace keymaster {
-
-KeyAttestationPackageInfo::KeyAttestationPackageInfo() = default;
-
-KeyAttestationPackageInfo::KeyAttestationPackageInfo(const String16& packageName,
-                                                     int64_t versionCode,
-                                                     SharedSignaturesVector signatures)
-    : packageName_(packageName), versionCode_(versionCode), signatures_(signatures) {}
-
-status_t KeyAttestationPackageInfo::writeToParcel(Parcel* parcel) const {
-    auto rc = parcel->writeString16(packageName_);
-    if (rc != NO_ERROR) return rc;
-    rc = parcel->writeInt64(versionCode_);
-    if (rc != NO_ERROR) return rc;
-    return parcel->writeParcelableVector(signatures_);
-}
-
-status_t KeyAttestationPackageInfo::readFromParcel(const Parcel* parcel) {
-    auto rc = parcel->readString16(&packageName_);
-    if (rc != NO_ERROR) return rc;
-    rc = parcel->readInt64(&versionCode_);
-    if (rc != NO_ERROR) return rc;
-
-    std::optional<SignaturesVector> temp_vector;
-    rc = parcel->readParcelableVector(&temp_vector);
-    if (rc != NO_ERROR) return rc;
-    signatures_.reset();
-    if (temp_vector) {
-        signatures_ = std::make_shared<SignaturesVector>(std::move(*temp_vector));
-    }
-    return NO_ERROR;
-}
-
-}  // namespace keymaster
-}  // namespace security
-}  // namespace android
diff --git a/keystore/Signature.cpp b/keystore/Signature.cpp
deleted file mode 100644
index 284f358..0000000
--- a/keystore/Signature.cpp
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
-**
-** Copyright 2016, 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.
-*/
-
-#include "include/keystore/Signature.h"
-
-#include <binder/Parcel.h>
-
-namespace android {
-namespace content {
-namespace pm {
-
-status_t Signature::writeToParcel(Parcel* parcel) const {
-    return parcel->writeByteVector(sig_data_);
-}
-
-status_t Signature::readFromParcel(const Parcel* parcel) {
-    return parcel->readByteVector(&sig_data_);
-}
-
-Signature::Signature(std::vector<uint8_t> signature_data) : sig_data_(std::move(signature_data)) {}
-
-}  // namespace pm
-}  // namespace content
-}  // namespace android
diff --git a/keystore/include/keystore/KeyAttestationApplicationId.h b/keystore/include/keystore/KeyAttestationApplicationId.h
deleted file mode 100644
index 0bf1aad..0000000
--- a/keystore/include/keystore/KeyAttestationApplicationId.h
+++ /dev/null
@@ -1,58 +0,0 @@
-// Copyright 2016 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.
-
-#ifndef KEYSTORE_INCLUDE_KEYSTORE_KEYATTESTATIONAPPLICATIONID_H_
-#define KEYSTORE_INCLUDE_KEYSTORE_KEYATTESTATIONAPPLICATIONID_H_
-
-#include <memory>
-#include <optional>
-#include <vector>
-
-#include <binder/Parcelable.h>
-
-#include "KeyAttestationPackageInfo.h"
-
-namespace android {
-namespace security {
-namespace keymaster {
-
-class KeyAttestationApplicationId : public Parcelable {
-  public:
-    typedef SharedNullableIterator<const KeyAttestationPackageInfo, std::vector>
-        ConstKeyAttestationPackageInfoIterator;
-    typedef std::vector<std::optional<KeyAttestationPackageInfo>> PackageInfoVector;
-    KeyAttestationApplicationId();
-    // Following c'tors are for initializing instances containing test data.
-    explicit KeyAttestationApplicationId(std::optional<KeyAttestationPackageInfo> package);
-    explicit KeyAttestationApplicationId(PackageInfoVector packages);
-
-    status_t writeToParcel(Parcel*) const override;
-    status_t readFromParcel(const Parcel* parcel) override;
-
-    ConstKeyAttestationPackageInfoIterator pinfos_begin() const {
-        return ConstKeyAttestationPackageInfoIterator(packageInfos_);
-    }
-    ConstKeyAttestationPackageInfoIterator pinfos_end() const {
-        return ConstKeyAttestationPackageInfoIterator();
-    }
-
-  private:
-    std::shared_ptr<PackageInfoVector> packageInfos_;
-};
-
-}  // namespace keymaster
-}  // namespace security
-}  // namespace android
-
-#endif  // KEYSTORE_INCLUDE_KEYSTORE_KEYATTESTATIONAPPLICATIONID_H_
diff --git a/keystore/include/keystore/KeyAttestationPackageInfo.h b/keystore/include/keystore/KeyAttestationPackageInfo.h
deleted file mode 100644
index fa638f9..0000000
--- a/keystore/include/keystore/KeyAttestationPackageInfo.h
+++ /dev/null
@@ -1,63 +0,0 @@
-// Copyright 2016 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.
-
-#ifndef KEYSTORE_INCLUDE_KEYSTORE_KEYATTESTATIONPACKAGEINFO_H_
-#define KEYSTORE_INCLUDE_KEYSTORE_KEYATTESTATIONPACKAGEINFO_H_
-
-#include <stdint.h>
-
-#include <memory>
-#include <optional>
-#include <vector>
-
-#include <binder/Parcelable.h>
-
-#include "Signature.h"
-#include "utils.h"
-
-namespace android {
-namespace security {
-namespace keymaster {
-
-class KeyAttestationPackageInfo : public Parcelable {
-  public:
-    typedef SharedNullableIterator<const content::pm::Signature, std::vector>
-        ConstSignatureIterator;
-    typedef std::vector<std::optional<content::pm::Signature>> SignaturesVector;
-    typedef std::shared_ptr<SignaturesVector> SharedSignaturesVector;
-
-    KeyAttestationPackageInfo(const String16& packageName, int64_t versionCode,
-                              SharedSignaturesVector signatures);
-    KeyAttestationPackageInfo();
-
-    status_t writeToParcel(Parcel*) const override;
-    status_t readFromParcel(const Parcel* parcel) override;
-
-    const std::optional<String16>& package_name() const { return packageName_; }
-    int64_t version_code() const { return versionCode_; }
-
-    ConstSignatureIterator sigs_begin() const { return ConstSignatureIterator(signatures_); }
-    ConstSignatureIterator sigs_end() const { return ConstSignatureIterator(); }
-
-  private:
-    std::optional<String16> packageName_;
-    int64_t versionCode_;
-    SharedSignaturesVector signatures_;
-};
-
-}  // namespace keymaster
-}  // namespace security
-}  // namespace android
-
-#endif  // KEYSTORE_INCLUDE_KEYSTORE_KEYATTESTATIONPACKAGEINFO_H_
diff --git a/keystore/include/keystore/Signature.h b/keystore/include/keystore/Signature.h
deleted file mode 100644
index f39acec..0000000
--- a/keystore/include/keystore/Signature.h
+++ /dev/null
@@ -1,47 +0,0 @@
-// Copyright 2016 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.
-
-#ifndef KEYSTORE_INCLUDE_KEYSTORE_SIGNATURE_H_
-#define KEYSTORE_INCLUDE_KEYSTORE_SIGNATURE_H_
-
-#include <vector>
-
-#include <binder/Parcelable.h>
-
-namespace android {
-namespace content {
-namespace pm {
-
-class Signature : public Parcelable {
-  public:
-    Signature() = default;
-    // Intended for initializing instances containing test data.
-    explicit Signature(std::vector<uint8_t> signature_data);
-
-    status_t writeToParcel(Parcel*) const override;
-    status_t readFromParcel(const Parcel* parcel) override;
-
-    const std::vector<uint8_t>& data() const & { return sig_data_; }
-    std::vector<uint8_t>& data() & { return sig_data_; }
-    std::vector<uint8_t>&& data() && { return std::move(sig_data_); }
-
-  private:
-    std::vector<uint8_t> sig_data_;
-};
-
-}  // namespace pm
-}  // namespace content
-}  // namespace android
-
-#endif  // KEYSTORE_INCLUDE_KEYSTORE_SIGNATURE_H_
diff --git a/keystore/include/keystore/keystore_attestation_id.h b/keystore/include/keystore/keystore_attestation_id.h
index 238f4b1..a0d43ad 100644
--- a/keystore/include/keystore/keystore_attestation_id.h
+++ b/keystore/include/keystore/keystore_attestation_id.h
@@ -25,11 +25,11 @@
 
 constexpr size_t KEY_ATTESTATION_APPLICATION_ID_MAX_SIZE = 1024;
 
-namespace keymaster {
+namespace keystore {
 
 class KeyAttestationApplicationId;
 
-}  // namespace keymaster
+}  // namespace keystore
 
 template <typename T> class StatusOr {
   public:
@@ -77,7 +77,7 @@
  */
 
 StatusOr<std::vector<uint8_t>> build_attestation_application_id(
-    const ::android::security::keymaster::KeyAttestationApplicationId& key_attestation_id);
+    const ::android::security::keystore::KeyAttestationApplicationId& key_attestation_id);
 
 }  // namespace security
 }  // namespace android
diff --git a/keystore/keystore_attestation_id.cpp b/keystore/keystore_attestation_id.cpp
index 75c62dd..1534be1 100644
--- a/keystore/keystore_attestation_id.cpp
+++ b/keystore/keystore_attestation_id.cpp
@@ -29,11 +29,11 @@
 #include <binder/Parcelable.h>
 #include <binder/PersistableBundle.h>
 
-#include <android/security/keymaster/BpKeyAttestationApplicationIdProvider.h>
-#include <android/security/keymaster/IKeyAttestationApplicationIdProvider.h>
-#include <keystore/KeyAttestationApplicationId.h>
-#include <keystore/KeyAttestationPackageInfo.h>
-#include <keystore/Signature.h>
+#include <android/security/keystore/BpKeyAttestationApplicationIdProvider.h>
+#include <android/security/keystore/IKeyAttestationApplicationIdProvider.h>
+#include <android/security/keystore/KeyAttestationApplicationId.h>
+#include <android/security/keystore/KeyAttestationPackageInfo.h>
+#include <android/security/keystore/Signature.h>
 
 #include <private/android_filesystem_config.h> /* for AID_SYSTEM */
 
@@ -50,13 +50,13 @@
 constexpr const char* kAttestationSystemPackageName = "AndroidSystem";
 constexpr const char* kUnknownPackageName = "UnknownPackage";
 
-std::vector<uint8_t> signature2SHA256(const content::pm::Signature& sig) {
+std::vector<uint8_t> signature2SHA256(const security::keystore::Signature& sig) {
     std::vector<uint8_t> digest_buffer(SHA256_DIGEST_LENGTH);
-    SHA256(sig.data().data(), sig.data().size(), digest_buffer.data());
+    SHA256(sig.data.data(), sig.data.size(), digest_buffer.data());
     return digest_buffer;
 }
 
-using ::android::security::keymaster::BpKeyAttestationApplicationIdProvider;
+using ::android::security::keystore::BpKeyAttestationApplicationIdProvider;
 
 class KeyAttestationApplicationIdProvider : public BpKeyAttestationApplicationIdProvider {
   public:
@@ -141,8 +141,8 @@
 namespace security {
 namespace {
 
-using ::android::security::keymaster::KeyAttestationApplicationId;
-using ::android::security::keymaster::KeyAttestationPackageInfo;
+using ::android::security::keystore::KeyAttestationApplicationId;
+using ::android::security::keystore::KeyAttestationPackageInfo;
 
 status_t build_attestation_package_info(const KeyAttestationPackageInfo& pinfo,
     std::unique_ptr<KM_ATTESTATION_PACKAGE_INFO>* attestation_package_info_ptr) {
@@ -153,12 +153,12 @@
     attestation_package_info.reset(KM_ATTESTATION_PACKAGE_INFO_new());
     if (!attestation_package_info.get()) return NO_MEMORY;
 
-    if (!pinfo.package_name()) {
+    if (!pinfo.packageName) {
         ALOGE("Key attestation package info lacks package name");
         return BAD_VALUE;
     }
 
-    std::string pkg_name(String8(*pinfo.package_name()).string());
+    std::string pkg_name(String8(pinfo.packageName).c_str());
     if (!ASN1_OCTET_STRING_set(attestation_package_info->package_name,
                                reinterpret_cast<const unsigned char*>(pkg_name.data()),
                                pkg_name.size())) {
@@ -169,7 +169,7 @@
     if (bn_version == nullptr) {
         return NO_MEMORY;
     }
-    if (BN_set_u64(bn_version, static_cast<uint64_t>(pinfo.version_code())) != 1) {
+    if (BN_set_u64(bn_version, static_cast<uint64_t>(pinfo.versionCode)) != 1) {
         BN_free(bn_version);
         return UNKNOWN_ERROR;
     }
@@ -201,15 +201,16 @@
 
     auto attestation_pinfo_stack = reinterpret_cast<_STACK*>(attestation_id->package_infos);
 
-    if (key_attestation_id.pinfos_begin() == key_attestation_id.pinfos_end()) return BAD_VALUE;
+    if (key_attestation_id.packageInfos.begin() == key_attestation_id.packageInfos.end())
+        return BAD_VALUE;
 
-    for (auto pinfo = key_attestation_id.pinfos_begin(); pinfo != key_attestation_id.pinfos_end();
-         ++pinfo) {
-        if (!pinfo->package_name()) {
+    for (auto pinfo = key_attestation_id.packageInfos.begin();
+         pinfo != key_attestation_id.packageInfos.end(); ++pinfo) {
+        if (!pinfo->packageName) {
             ALOGE("Key attestation package info lacks package name");
             return BAD_VALUE;
         }
-        std::string package_name(String8(*pinfo->package_name()).string());
+        std::string package_name(String8(pinfo->packageName).c_str());
         std::unique_ptr<KM_ATTESTATION_PACKAGE_INFO> attestation_package_info;
         auto rc = build_attestation_package_info(*pinfo, &attestation_package_info);
         if (rc != NO_ERROR) {
@@ -231,10 +232,10 @@
      *  signature field actually holds the signing certificate, rather than a signature, we can
      *  simply use the set of signature digests of the first package info.
      */
-    const auto& pinfo = *key_attestation_id.pinfos_begin();
+    const auto& pinfo = *key_attestation_id.packageInfos.begin();
     std::vector<std::vector<uint8_t>> signature_digests;
 
-    for (auto sig = pinfo.sigs_begin(); sig != pinfo.sigs_end(); ++sig) {
+    for (auto sig = pinfo.signatures.begin(); sig != pinfo.signatures.end(); ++sig) {
         signature_digests.push_back(signature2SHA256(*sig));
     }
 
@@ -271,10 +272,10 @@
 
     if (uid == AID_SYSTEM) {
         /* Use a fixed ID for system callers */
-        auto pinfo = std::make_optional<KeyAttestationPackageInfo>(
-            String16(kAttestationSystemPackageName), 1 /* version code */,
-            std::make_shared<KeyAttestationPackageInfo::SignaturesVector>());
-        key_attestation_id = KeyAttestationApplicationId(std::move(pinfo));
+        auto pinfo = KeyAttestationPackageInfo();
+        pinfo.packageName = String16(kAttestationSystemPackageName);
+        pinfo.versionCode = 1;
+        key_attestation_id.packageInfos.push_back(std::move(pinfo));
     } else {
         /* Get the attestation application ID from package manager */
         auto& pm = KeyAttestationApplicationIdProvider::get();
@@ -283,11 +284,12 @@
         // caller is unknown.
         if (!status.isOk()) {
             ALOGW("package manager request for key attestation ID failed with: %s %d",
-                  status.exceptionMessage().string(), status.exceptionCode());
-            auto pinfo = std::make_optional<KeyAttestationPackageInfo>(
-                String16(kUnknownPackageName), 1 /* version code */,
-                std::make_shared<KeyAttestationPackageInfo::SignaturesVector>());
-            key_attestation_id = KeyAttestationApplicationId(std::move(pinfo));
+                  status.exceptionMessage().c_str(), status.exceptionCode());
+
+            auto pinfo = KeyAttestationPackageInfo();
+            pinfo.packageName = String16(kUnknownPackageName);
+            pinfo.versionCode = 1;
+            key_attestation_id.packageInfos.push_back(std::move(pinfo));
         }
     }
 
diff --git a/keystore/tests/Android.bp b/keystore/tests/Android.bp
index f51cc2f..e641f44 100644
--- a/keystore/tests/Android.bp
+++ b/keystore/tests/Android.bp
@@ -35,6 +35,7 @@
         "libutils",
     ],
     shared_libs: [
+        "android.security.aaid_aidl-cpp",
         "libbinder",
         "libkeymaster_messages",
         "libkeystore-attestation-application-id",
diff --git a/keystore/tests/aaid_truncation_test.cpp b/keystore/tests/aaid_truncation_test.cpp
index fa4d769..3a94ec1 100644
--- a/keystore/tests/aaid_truncation_test.cpp
+++ b/keystore/tests/aaid_truncation_test.cpp
@@ -22,14 +22,14 @@
 #include <keymaster/logger.h>
 #include <keystore/keystore_attestation_id.h>
 
-#include <keystore/KeyAttestationApplicationId.h>
-#include <keystore/KeyAttestationPackageInfo.h>
-#include <keystore/Signature.h>
+#include <android/security/keystore/KeyAttestationApplicationId.h>
+#include <android/security/keystore/KeyAttestationPackageInfo.h>
+#include <android/security/keystore/Signature.h>
 
 using ::android::String16;
 using ::android::security::KEY_ATTESTATION_APPLICATION_ID_MAX_SIZE;
-using ::android::security::keymaster::KeyAttestationApplicationId;
-using ::android::security::keymaster::KeyAttestationPackageInfo;
+using ::android::security::keystore::KeyAttestationApplicationId;
+using ::android::security::keystore::KeyAttestationPackageInfo;
 using std::vector;
 
 namespace keystore {
@@ -72,24 +72,27 @@
 
 }  // namespace
 
-using ::android::content::pm::Signature;
 using ::android::security::build_attestation_application_id;
+using ::android::security::keystore::Signature;
 
-std::optional<KeyAttestationPackageInfo>
-make_package_info_with_signatures(const char* package_name,
-                                  KeyAttestationPackageInfo::SignaturesVector signatures) {
-    return std::make_optional<KeyAttestationPackageInfo>(
-        String16(package_name), 1 /* version code */,
-        std::make_shared<KeyAttestationPackageInfo::SignaturesVector>(std::move(signatures)));
+KeyAttestationPackageInfo make_package_info_with_signatures(const char* package_name,
+                                                            std::vector<Signature> signatures) {
+    auto pInfo = KeyAttestationPackageInfo();
+    pInfo.packageName = String16(package_name);
+    pInfo.versionCode = 1;
+    std::move(signatures.begin(), signatures.end(), std::back_inserter(pInfo.signatures));
+
+    return pInfo;
 }
 
-std::optional<KeyAttestationPackageInfo> make_package_info(const char* package_name) {
-    return make_package_info_with_signatures(package_name,
-                                             KeyAttestationPackageInfo::SignaturesVector());
+KeyAttestationPackageInfo make_package_info(const char* package_name) {
+    return make_package_info_with_signatures(package_name, std::vector<Signature>());
 }
 
 TEST(AaidTruncationTest, shortPackageInfoTest) {
-    KeyAttestationApplicationId app_id(make_package_info(kDummyPackageName));
+    KeyAttestationApplicationId app_id;
+    auto pInfo = make_package_info(kDummyPackageName);
+    app_id.packageInfos.push_back(std::move(pInfo));
 
     auto result = build_attestation_application_id(app_id);
     ASSERT_TRUE(result.isOk());
@@ -98,7 +101,9 @@
 }
 
 TEST(AaidTruncationTest, tooLongPackageNameTest) {
-    KeyAttestationApplicationId app_id(make_package_info(kLongPackageName));
+    KeyAttestationApplicationId app_id;
+    auto pInfo = make_package_info(kLongPackageName);
+    app_id.packageInfos.push_back(std::move(pInfo));
 
     auto result = build_attestation_application_id(app_id);
     ASSERT_TRUE(result.isOk());
@@ -108,14 +113,17 @@
 
 TEST(AaidTruncationTest, tooManySignaturesTest) {
     std::vector<uint8_t> dummy_sig_data(kDummySignature, kDummySignature + 32);
-    KeyAttestationPackageInfo::SignaturesVector signatures;
+    std::vector<Signature> signatures;
     // Add 35 signatures which will surely exceed the 1K limit.
     for (size_t i = 0; i < kTooManySignatures; ++i) {
-        signatures.push_back(std::make_optional<Signature>(dummy_sig_data));
+        auto sign = Signature();
+        sign.data = dummy_sig_data;
+        signatures.push_back(std::move(sign));
     }
 
-    KeyAttestationApplicationId app_id(
-        make_package_info_with_signatures(kDummyPackageName, std::move(signatures)));
+    auto pInfo = make_package_info_with_signatures(kDummyPackageName, std::move(signatures));
+    KeyAttestationApplicationId app_id;
+    app_id.packageInfos.push_back(std::move(pInfo));
 
     auto result = build_attestation_application_id(app_id);
     ASSERT_TRUE(result.isOk());
@@ -125,19 +133,22 @@
 
 TEST(AaidTruncationTest, combinedPackagesAndSignaturesTest) {
     std::vector<uint8_t> dummy_sig_data(kDummySignature, kDummySignature + 32);
-    KeyAttestationApplicationId::PackageInfoVector packages;
+    ::std::vector<KeyAttestationPackageInfo> packages;
 
     for (size_t i = 0; i < kTooManyPackages; ++i) {
-        KeyAttestationPackageInfo::SignaturesVector signatures;
+        std::vector<Signature> signatures;
         // Add a few signatures for each package
         for (int j = 0; j < 3; ++j) {
-            signatures.push_back(std::make_optional<Signature>(dummy_sig_data));
+            auto sign = Signature();
+            sign.data = dummy_sig_data;
+            signatures.push_back(std::move(sign));
         }
-        packages.push_back(
-            make_package_info_with_signatures(kReasonablePackageName, std::move(signatures)));
+        packages.push_back(std::move(
+            make_package_info_with_signatures(kReasonablePackageName, std::move(signatures))));
     }
+    KeyAttestationApplicationId app_id;
+    std::move(packages.begin(), packages.end(), std::back_inserter(app_id.packageInfos));
 
-    KeyAttestationApplicationId app_id(std::move(packages));
     auto result = build_attestation_application_id(app_id);
     ASSERT_TRUE(result.isOk());
     std::vector<uint8_t>& encoded_app_id = result;
diff --git a/keystore/tests/fuzzer/Android.bp b/keystore/tests/fuzzer/Android.bp
index 4116ae1..5df5c7a 100644
--- a/keystore/tests/fuzzer/Android.bp
+++ b/keystore/tests/fuzzer/Android.bp
@@ -55,6 +55,7 @@
         "libhidlbase",
     ],
     shared_libs: [
+        "android.security.aaid_aidl-cpp",
         "libbinder",
         "libcrypto",
         "libutils",
diff --git a/keystore/tests/fuzzer/keystoreApplicationId_fuzzer.cpp b/keystore/tests/fuzzer/keystoreApplicationId_fuzzer.cpp
index 0eddb9a..9388001 100644
--- a/keystore/tests/fuzzer/keystoreApplicationId_fuzzer.cpp
+++ b/keystore/tests/fuzzer/keystoreApplicationId_fuzzer.cpp
@@ -15,9 +15,9 @@
  */
 
 #include "keystoreCommon.h"
-#include <keystore/KeyAttestationApplicationId.h>
+#include <android/security/keystore/KeyAttestationApplicationId.h>
 
-using ::security::keymaster::KeyAttestationApplicationId;
+using ::android::security::keystore::KeyAttestationApplicationId;
 
 constexpr size_t kPackageVectorSizeMin = 1;
 constexpr size_t kPackageVectorSizeMax = 10;
@@ -33,26 +33,37 @@
 };
 
 void KeystoreApplicationId::invokeApplicationId() {
-    std::optional<KeyAttestationApplicationId> applicationId;
+    KeyAttestationApplicationId applicationId;
     bool shouldUsePackageInfoVector = mFdp->ConsumeBool();
     if (shouldUsePackageInfoVector) {
-        KeyAttestationApplicationId::PackageInfoVector packageInfoVector;
+        ::std::vector<KeyAttestationPackageInfo> packageInfoVector;
         int32_t packageVectorSize =
             mFdp->ConsumeIntegralInRange<int32_t>(kPackageVectorSizeMin, kPackageVectorSizeMax);
         for (int32_t packageSize = 0; packageSize < packageVectorSize; ++packageSize) {
             auto packageInfoData = initPackageInfoData(mFdp.get());
-            packageInfoVector.push_back(make_optional<KeyAttestationPackageInfo>(
-                String16((packageInfoData.packageName).c_str()), packageInfoData.versionCode,
-                packageInfoData.sharedSignaturesVector));
+            auto pInfo = KeyAttestationPackageInfo();
+            pInfo.packageName = String16((packageInfoData.packageName).c_str());
+            pInfo.versionCode = packageInfoData.versionCode;
+            std::move(packageInfoData.sharedSignaturesVector->begin(),
+                      packageInfoData.sharedSignaturesVector->end(),
+                      std::back_inserter(pInfo.signatures));
+
+            packageInfoVector.push_back(std::move(pInfo));
         }
-        applicationId = KeyAttestationApplicationId(std::move(packageInfoVector));
+
+        std::move(packageInfoVector.begin(), packageInfoVector.end(),
+                  std::back_inserter(applicationId.packageInfos));
     } else {
         auto packageInfoData = initPackageInfoData(mFdp.get());
-        applicationId = KeyAttestationApplicationId(make_optional<KeyAttestationPackageInfo>(
-            String16((packageInfoData.packageName).c_str()), packageInfoData.versionCode,
-            packageInfoData.sharedSignaturesVector));
+        auto pInfo = KeyAttestationPackageInfo();
+        pInfo.packageName = String16((packageInfoData.packageName).c_str());
+        pInfo.versionCode = packageInfoData.versionCode;
+        std::move(packageInfoData.sharedSignaturesVector->begin(),
+                  packageInfoData.sharedSignaturesVector->end(),
+                  std::back_inserter(pInfo.signatures));
+        applicationId.packageInfos.push_back(std::move(pInfo));
     }
-    invokeReadWriteParcel(&applicationId.value());
+    invokeReadWriteParcel(&applicationId);
 }
 
 void KeystoreApplicationId::process(const uint8_t* data, size_t size) {
diff --git a/keystore/tests/fuzzer/keystoreCommon.h b/keystore/tests/fuzzer/keystoreCommon.h
index e1265bf..77d39e0 100644
--- a/keystore/tests/fuzzer/keystoreCommon.h
+++ b/keystore/tests/fuzzer/keystoreCommon.h
@@ -16,18 +16,18 @@
 #ifndef KEYSTORECOMMON_H
 #define KEYSTORECOMMON_H
 
+#include <android/security/keystore/KeyAttestationPackageInfo.h>
+#include <android/security/keystore/Signature.h>
 #include <binder/Parcel.h>
 #include <binder/Parcelable.h>
-#include <keystore/KeyAttestationPackageInfo.h>
-#include <keystore/Signature.h>
 #include <vector>
 
 #include "fuzzer/FuzzedDataProvider.h"
 
 using namespace android;
 using namespace std;
-using ::content::pm::Signature;
-using ::security::keymaster::KeyAttestationPackageInfo;
+using ::android::security::keystore::KeyAttestationPackageInfo;
+using ::android::security::keystore::Signature;
 
 constexpr size_t kSignatureSizeMin = 1;
 constexpr size_t kSignatureSizeMax = 1000;
@@ -38,7 +38,7 @@
 struct PackageInfoData {
     string packageName;
     int64_t versionCode;
-    KeyAttestationPackageInfo::SharedSignaturesVector sharedSignaturesVector;
+    std::shared_ptr<std::vector<Signature>> sharedSignaturesVector;
 };
 
 inline void invokeReadWriteParcel(Parcelable* obj) {
@@ -60,18 +60,20 @@
     packageInfoData.versionCode = fdp->ConsumeIntegral<int64_t>();
     size_t signatureVectorSize =
         fdp->ConsumeIntegralInRange(kSignatureVectorSizeMin, kSignatureVectorSizeMax);
-    KeyAttestationPackageInfo::SignaturesVector signatureVector;
+    std::vector<Signature> signatureVector;
     for (size_t size = 0; size < signatureVectorSize; ++size) {
         bool shouldUseParameterizedConstructor = fdp->ConsumeBool();
         if (shouldUseParameterizedConstructor) {
             vector<uint8_t> signatureData = initSignatureData(fdp);
-            signatureVector.push_back(make_optional<Signature>(signatureData));
+            auto sign = Signature();
+            sign.data = signatureData;
+            signatureVector.push_back(std::move(sign));
         } else {
-            signatureVector.push_back(std::nullopt);
+            signatureVector.push_back(Signature());
         }
     }
     packageInfoData.sharedSignaturesVector =
-        make_shared<KeyAttestationPackageInfo::SignaturesVector>(std::move(signatureVector));
+        make_shared<std::vector<Signature>>(std::move(signatureVector));
     return packageInfoData;
 }
 #endif  // KEYSTORECOMMON_H
diff --git a/keystore/tests/fuzzer/keystorePackageInfo_fuzzer.cpp b/keystore/tests/fuzzer/keystorePackageInfo_fuzzer.cpp
index 63899ff..f1e4204 100644
--- a/keystore/tests/fuzzer/keystorePackageInfo_fuzzer.cpp
+++ b/keystore/tests/fuzzer/keystorePackageInfo_fuzzer.cpp
@@ -28,9 +28,12 @@
 
 void KeystorePackageInfoFuzzer::invokePackageInfo() {
     auto packageInfoData = initPackageInfoData(mFdp.get());
-    KeyAttestationPackageInfo packageInfo(String16((packageInfoData.packageName).c_str()),
-                                          packageInfoData.versionCode,
-                                          packageInfoData.sharedSignaturesVector);
+    auto packageInfo = KeyAttestationPackageInfo();
+    packageInfo.packageName = String16((packageInfoData.packageName).c_str());
+    packageInfo.versionCode = packageInfoData.versionCode;
+    std::move(packageInfoData.sharedSignaturesVector->begin(),
+              packageInfoData.sharedSignaturesVector->end(),
+              std::back_inserter(packageInfo.signatures));
     invokeReadWriteParcel(&packageInfo);
 }
 
diff --git a/keystore/tests/fuzzer/keystoreSignature_fuzzer.cpp b/keystore/tests/fuzzer/keystoreSignature_fuzzer.cpp
index b8f8a73..aab1f25 100644
--- a/keystore/tests/fuzzer/keystoreSignature_fuzzer.cpp
+++ b/keystore/tests/fuzzer/keystoreSignature_fuzzer.cpp
@@ -14,7 +14,9 @@
  * limitations under the License.
  */
 #include "keystoreCommon.h"
-#include <keystore/Signature.h>
+#include <android/security/keystore/Signature.h>
+
+using ::android::security::keystore::Signature;
 
 class KeystoreSignatureFuzzer {
   public:
@@ -27,15 +29,15 @@
 };
 
 void KeystoreSignatureFuzzer::invokeSignature() {
-    std::optional<Signature> signature;
+    Signature signature;
     bool shouldUseParameterizedConstructor = mFdp->ConsumeBool();
     if (shouldUseParameterizedConstructor) {
         std::vector<uint8_t> signatureData = initSignatureData(mFdp.get());
-        signature = Signature(signatureData);
+        signature.data = signatureData;
     } else {
         signature = Signature();
     }
-    invokeReadWriteParcel(&signature.value());
+    invokeReadWriteParcel(&signature);
 }
 
 void KeystoreSignatureFuzzer::process(const uint8_t* data, size_t size) {
diff --git a/keystore2/Android.bp b/keystore2/Android.bp
index a47c2c2..e59b6f2 100644
--- a/keystore2/Android.bp
+++ b/keystore2/Android.bp
@@ -41,11 +41,14 @@
         "android.security.maintenance-rust",
         "android.security.metrics-rust",
         "android.security.rkp_aidl-rust",
+        "libaconfig_android_hardware_biometrics_rust",
+        "libandroid_security_flags_rust",
         "libanyhow",
         "libbinder_rs",
         "libkeystore2_aaid-rust",
         "libkeystore2_apc_compat-rust",
         "libkeystore2_crypto_rust",
+        "libkeystore2_flags_rust",
         "libkeystore2_km_compat",
         "libkeystore2_selinux",
         "libkeystore2_hal_names_rust",
@@ -53,12 +56,14 @@
         "liblibc",
         "liblog_event_list",
         "liblog_rust",
+        "libmessage_macro",
         "librand",
         "librustutils",
         "libserde",
         "libserde_cbor",
         "libthiserror",
         "libtokio",
+        "libwatchdog_rs",
     ],
     shared_libs: [
         "libcutils",
@@ -78,27 +83,6 @@
 }
 
 rust_library {
-    name: "libkeystore2_test_utils",
-    crate_name: "keystore2_test_utils",
-    srcs: ["test_utils/lib.rs"],
-    defaults: [
-        "keymint_use_latest_hal_aidl_rust",
-        "keystore2_use_latest_aidl_rust",
-    ],
-    rustlibs: [
-        "libbinder_rs",
-        "libkeystore2_selinux",
-        "liblog_rust",
-        "libnix",
-        "librand",
-        "libserde",
-        "libserde_cbor",
-        "libthiserror",
-        "libanyhow",
-    ],
-}
-
-rust_library {
     name: "libkeystore2_with_test_utils",
     defaults: ["libkeystore2_defaults"],
     features: [
@@ -112,30 +96,6 @@
 }
 
 rust_test {
-    name: "keystore2_test_utils_test",
-    srcs: ["test_utils/lib.rs"],
-    defaults: [
-        "keymint_use_latest_hal_aidl_rust",
-        "keystore2_use_latest_aidl_rust",
-    ],
-    test_suites: ["general-tests"],
-    require_root: true,
-    auto_gen_config: true,
-    compile_multilib: "first",
-    rustlibs: [
-        "libbinder_rs",
-        "libkeystore2_selinux",
-        "liblog_rust",
-        "libnix",
-        "librand",
-        "libserde",
-        "libserde_cbor",
-        "libthiserror",
-        "libanyhow",
-    ],
-}
-
-rust_test {
     name: "keystore2_test",
     crate_name: "keystore2",
     test_suites: ["general-tests"],
@@ -144,6 +104,7 @@
     defaults: ["libkeystore2_defaults"],
     rustlibs: [
         "libandroid_logger",
+        "libhex",
         "libkeystore2_test_utils",
         "liblibsqlite3_sys",
         "libnix",
@@ -191,3 +152,22 @@
     ],
     afdo: true,
 }
+
+// Keystore Flag definitions
+aconfig_declarations {
+    name: "keystore2_flags",
+    package: "android.security.keystore2",
+    srcs: ["aconfig/flags.aconfig"],
+}
+
+rust_aconfig_library {
+    name: "libkeystore2_flags_rust",
+    crate_name: "keystore2_flags",
+    aconfig_declarations: "keystore2_flags",
+}
+
+rust_aconfig_library {
+    name: "libaconfig_android_hardware_biometrics_rust",
+    crate_name: "aconfig_android_hardware_biometrics_rust",
+    aconfig_declarations: "android.hardware.biometrics.flags-aconfig",
+}
diff --git a/keystore2/OWNERS b/keystore2/OWNERS
new file mode 100644
index 0000000..6b1a95b
--- /dev/null
+++ b/keystore2/OWNERS
@@ -0,0 +1,9 @@
+set noparent
+# Bug component: 1084732
+eranm@google.com
+drysdale@google.com
+hasinitg@google.com
+jbires@google.com
+sethmo@google.com
+trong@google.com
+swillden@google.com
diff --git a/keystore2/TEST_MAPPING b/keystore2/TEST_MAPPING
index 5d0a7dd..1038bea 100644
--- a/keystore2/TEST_MAPPING
+++ b/keystore2/TEST_MAPPING
@@ -30,6 +30,12 @@
   "postsubmit": [
     {
       "name": "CtsKeystorePerformanceTestCases"
+    },
+    {
+      "name": "keystore2_client_tests"
+    },
+    {
+      "name": "libwatchdog_rs.test"
     }
   ]
 }
diff --git a/keystore2/aconfig/flags.aconfig b/keystore2/aconfig/flags.aconfig
new file mode 100644
index 0000000..5d2a422
--- /dev/null
+++ b/keystore2/aconfig/flags.aconfig
@@ -0,0 +1,17 @@
+package: "android.security.keystore2"
+
+flag {
+  name: "wal_db_journalmode"
+  namespace: "hardware_backed_security"
+  description: "This flag controls changing journalmode to wal"
+  bug: "191777960"
+  is_fixed_read_only: true
+}
+
+flag {
+  name: "deprecate_legacy_keystore"
+  namespace: "hardware_backed_security"
+  description: "This flag rolls out legacy keystore deprecation and makes it so that the put command returns a deprecation error"
+  bug: "307460850"
+  is_fixed_read_only: true
+}
diff --git a/keystore2/aidl/android/security/authorization/IKeystoreAuthorization.aidl b/keystore2/aidl/android/security/authorization/IKeystoreAuthorization.aidl
index e3b7d11..b31a51e 100644
--- a/keystore2/aidl/android/security/authorization/IKeystoreAuthorization.aidl
+++ b/keystore2/aidl/android/security/authorization/IKeystoreAuthorization.aidl
@@ -15,6 +15,7 @@
 package android.security.authorization;
 
 import android.hardware.security.keymint.HardwareAuthToken;
+import android.hardware.security.keymint.HardwareAuthenticatorType;
 import android.security.authorization.LockScreenEvent;
 import android.security.authorization.AuthorizationTokens;
 
@@ -108,4 +109,13 @@
      */
     AuthorizationTokens getAuthTokensForCredStore(in long challenge, in long secureUserId,
      in long authTokenMaxAgeMillis);
+
+    /**
+     * Returns the last successful authentication time since boot for the given user with any of the
+     * given authenticator types. This is determined by inspecting the cached auth tokens.
+     *
+     * ## Error conditions:
+     * `ResponseCode::NO_AUTH_TOKEN_FOUND` - if there is no matching authentication token found
+     */
+    long getLastAuthTime(in long secureUserId, in HardwareAuthenticatorType[] authTypes);
 }
diff --git a/keystore2/aidl/android/security/maintenance/IKeystoreMaintenance.aidl b/keystore2/aidl/android/security/maintenance/IKeystoreMaintenance.aidl
index 6a37c78..86d38d7 100644
--- a/keystore2/aidl/android/security/maintenance/IKeystoreMaintenance.aidl
+++ b/keystore2/aidl/android/security/maintenance/IKeystoreMaintenance.aidl
@@ -16,7 +16,6 @@
 
 import android.system.keystore2.Domain;
 import android.system.keystore2.KeyDescriptor;
-import android.security.maintenance.UserState;
 
 /**
  * IKeystoreMaintenance interface exposes the methods for adding/removing users and changing the
@@ -28,10 +27,10 @@
 
     /**
      * Allows LockSettingsService to inform keystore about adding a new user.
-     * Callers require 'AddUser' permission.
+     * Callers require 'ChangeUser' permission.
      *
      * ## Error conditions:
-     * `ResponseCode::PERMISSION_DENIED` - if the callers do not have the 'AddUser' permission.
+     * `ResponseCode::PERMISSION_DENIED` - if the callers do not have the 'ChangeUser' permission.
      * `ResponseCode::SYSTEM_ERROR` - if failed to delete the keys of an existing user with the same
      * user id.
      *
@@ -41,10 +40,10 @@
 
     /**
      * Allows LockSettingsService to inform keystore about removing a user.
-     * Callers require 'RemoveUser' permission.
+     * Callers require 'ChangeUser' permission.
      *
      * ## Error conditions:
-     * `ResponseCode::PERMISSION_DENIED` - if the callers do not have the 'RemoveUser' permission.
+     * `ResponseCode::PERMISSION_DENIED` - if the callers do not have the 'ChangeUser' permission.
      * `ResponseCode::SYSTEM_ERROR` - if failed to delete the keys of the user being deleted.
      *
      * @param userId - Android user id
@@ -77,19 +76,6 @@
     void clearNamespace(Domain domain, long nspace);
 
     /**
-     * Allows querying user state, given user id.
-     * Callers require 'GetState' permission.
-     *
-     * ## Error conditions:
-     * `ResponseCode::PERMISSION_DENIED` - if the callers do not have the 'GetState'
-     *                                     permission.
-     * `ResponseCode::SYSTEM_ERROR` - if an error occurred when querying the user state.
-     *
-     * @param userId - Android user id
-     */
-    UserState getState(in int userId);
-
-    /**
      * This function notifies the Keymint device of the specified securityLevel that
      * early boot has ended, so that they no longer allow early boot keys to be used.
      * ## Error conditions:
diff --git a/keystore2/aidl/android/security/maintenance/UserState.aidl b/keystore2/aidl/android/security/maintenance/UserState.aidl
deleted file mode 100644
index 376f4fb..0000000
--- a/keystore2/aidl/android/security/maintenance/UserState.aidl
+++ /dev/null
@@ -1,23 +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.
-
-package android.security.maintenance;
-
-/** @hide */
-@Backing(type="int")
-enum UserState {
-    UNINITIALIZED = 0,
-    LSKF_UNLOCKED = 1,
-    LSKF_LOCKED = 2,
-}
\ No newline at end of file
diff --git a/keystore2/apc_compat/apc_compat.cpp b/keystore2/apc_compat/apc_compat.cpp
index 9f60db2..ffe7595 100644
--- a/keystore2/apc_compat/apc_compat.cpp
+++ b/keystore2/apc_compat/apc_compat.cpp
@@ -118,8 +118,7 @@
                                                    hidl_ui_options);
         if (!rc.isOk()) {
             LOG(ERROR) << "Communication error: promptUserConfirmation: " << rc.description();
-        }
-        if (rc == ResponseCode::OK) {
+        } else if (rc == ResponseCode::OK) {
             callback_ = callback;
         }
         return responseCode2Compat(rc.withDefault(ResponseCode::SystemError));
diff --git a/keystore2/legacykeystore/lib.rs b/keystore2/legacykeystore/lib.rs
index b826a65..55224f7 100644
--- a/keystore2/legacykeystore/lib.rs
+++ b/keystore2/legacykeystore/lib.rs
@@ -500,8 +500,10 @@
     ) -> Result<bool> {
         let blob = legacy_loader
             .read_legacy_keystore_entry(uid, alias, |ciphertext, iv, tag, _salt, _key_size| {
-                if let Some(key) =
-                    SUPER_KEY.read().unwrap().get_per_boot_key_by_user_id(uid_to_android_user(uid))
+                if let Some(key) = SUPER_KEY
+                    .read()
+                    .unwrap()
+                    .get_after_first_unlock_key_by_user_id(uid_to_android_user(uid))
                 {
                     key.decrypt(ciphertext, iv, tag)
                 } else {
diff --git a/diced/sample_inputs/Android.bp b/keystore2/message_macro/Android.bp
similarity index 65%
copy from diced/sample_inputs/Android.bp
copy to keystore2/message_macro/Android.bp
index cf6ef5f..f1fbad7 100644
--- a/diced/sample_inputs/Android.bp
+++ b/keystore2/message_macro/Android.bp
@@ -1,4 +1,4 @@
-// Copyright 2021, The Android Open Source Project
+// 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.
@@ -21,25 +21,17 @@
     default_applicable_licenses: ["system_security_license"],
 }
 
-rust_library {
-    name: "libdiced_sample_inputs",
-    crate_name: "diced_sample_inputs",
+rust_defaults {
+    name: "libmessage_macro_defaults",
+    crate_name: "message_macro",
     srcs: ["src/lib.rs"],
-    rustlibs: [
-        "libanyhow",
-        "libciborium",
-        "libcoset",
-        "libdiced_open_dice",
-    ],
 }
 
-rust_test {
-    name: "libdiced_sample_inputs.integration_test",
-    crate_name: "diced_sample_inputs_test",
-    srcs: ["tests/*.rs"],
-    test_suites: ["general-tests"],
-    rustlibs: [
-        "libdiced_open_dice",
-        "libdiced_sample_inputs",
+rust_library {
+    name: "libmessage_macro",
+    defaults: ["libmessage_macro_defaults"],
+    apex_available: [
+        "//apex_available:platform",
+        "com.android.virt",
     ],
 }
diff --git a/keystore2/src/ks_err.rs b/keystore2/message_macro/src/lib.rs
similarity index 76%
rename from keystore2/src/ks_err.rs
rename to keystore2/message_macro/src/lib.rs
index c9c38c0..d8cfab0 100644
--- a/keystore2/src/ks_err.rs
+++ b/keystore2/message_macro/src/lib.rs
@@ -12,20 +12,20 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-//! A ks_err macro that expands error messages to include the file and line number
+//! A macro that generates a message containing the current source file name
+//! and line number.
 
+/// Generates a message containing the current source file name and line number.
 ///
 /// # Examples
 ///
 /// ```
-/// use crate::ks_err;
-///
-/// ks_err!("Key is expired.");
+/// source_location_msg!("Key is expired.");
 /// Result:
 /// "src/lib.rs:7 Key is expired."
 /// ```
 #[macro_export]
-macro_rules! ks_err {
+macro_rules! source_location_msg {
     { $($arg:tt)+ } => {
         format!("{}:{}: {}", file!(), line!(), format_args!($($arg)+))
     };
diff --git a/keystore2/src/authorization.rs b/keystore2/src/authorization.rs
index de7f19a..7416b7f 100644
--- a/keystore2/src/authorization.rs
+++ b/keystore2/src/authorization.rs
@@ -14,27 +14,30 @@
 
 //! This module implements IKeystoreAuthorization AIDL interface.
 
-use crate::ks_err;
-use crate::error::Error as KeystoreError;
 use crate::error::anyhow_error_to_cstring;
-use crate::globals::{ENFORCEMENTS, SUPER_KEY, DB, LEGACY_IMPORTER};
+use crate::error::Error as KeystoreError;
+use crate::globals::{DB, ENFORCEMENTS, LEGACY_IMPORTER, SUPER_KEY};
+use crate::ks_err;
 use crate::permission::KeystorePerm;
 use crate::utils::{check_keystore_permission, watchdog as wd};
+use aconfig_android_hardware_biometrics_rust;
 use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
-    HardwareAuthToken::HardwareAuthToken,
+    HardwareAuthToken::HardwareAuthToken, HardwareAuthenticatorType::HardwareAuthenticatorType,
 };
-use android_security_authorization::binder::{BinderFeatures, ExceptionCode, Interface, Result as BinderResult,
-    Strong, Status as BinderStatus};
 use android_security_authorization::aidl::android::security::authorization::{
-    IKeystoreAuthorization::BnKeystoreAuthorization, IKeystoreAuthorization::IKeystoreAuthorization,
-    LockScreenEvent::LockScreenEvent, AuthorizationTokens::AuthorizationTokens,
+    AuthorizationTokens::AuthorizationTokens, IKeystoreAuthorization::BnKeystoreAuthorization,
+    IKeystoreAuthorization::IKeystoreAuthorization, LockScreenEvent::LockScreenEvent,
     ResponseCode::ResponseCode,
 };
-use android_system_keystore2::aidl::android::system::keystore2::{
-    ResponseCode::ResponseCode as KsResponseCode};
+use android_security_authorization::binder::{
+    BinderFeatures, ExceptionCode, Interface, Result as BinderResult, Status as BinderStatus,
+    Strong,
+};
+use android_system_keystore2::aidl::android::system::keystore2::ResponseCode::ResponseCode as KsResponseCode;
 use anyhow::{Context, Result};
 use keystore2_crypto::Password;
 use keystore2_selinux as selinux;
+use std::ffi::CString;
 
 /// This is the Authorization error type, it wraps binder exceptions and the
 /// Authorization ResponseCode
@@ -191,7 +194,7 @@
                 ENFORCEMENTS.set_device_locked(user_id, true);
                 let mut skm = SUPER_KEY.write().unwrap();
                 DB.with(|db| {
-                    skm.lock_screen_lock_bound_key(
+                    skm.lock_unlocked_device_required_keys(
                         &mut db.borrow_mut(),
                         user_id as u32,
                         unlocking_sids.unwrap_or(&[]),
@@ -226,6 +229,31 @@
             ENFORCEMENTS.get_auth_tokens(challenge, secure_user_id, auth_token_max_age_millis)?;
         Ok(AuthorizationTokens { authToken: auth_token, timestampToken: ts_token })
     }
+
+    fn get_last_auth_time(
+        &self,
+        secure_user_id: i64,
+        auth_types: &[HardwareAuthenticatorType],
+    ) -> Result<i64> {
+        // Check keystore permission.
+        check_keystore_permission(KeystorePerm::GetLastAuthTime).context(ks_err!())?;
+
+        let mut max_time: i64 = -1;
+        for auth_type in auth_types.iter() {
+            if let Some(time) = ENFORCEMENTS.get_last_auth_time(secure_user_id, *auth_type) {
+                if time.milliseconds() > max_time {
+                    max_time = time.milliseconds();
+                }
+            }
+        }
+
+        if max_time >= 0 {
+            Ok(max_time)
+        } else {
+            Err(Error::Rc(ResponseCode::NO_AUTH_TOKEN_FOUND))
+                .context(ks_err!("No auth token found"))
+        }
+    }
 }
 
 impl Interface for AuthorizationManager {}
@@ -274,4 +302,19 @@
             Ok,
         )
     }
+
+    fn getLastAuthTime(
+        &self,
+        secure_user_id: i64,
+        auth_types: &[HardwareAuthenticatorType],
+    ) -> binder::Result<i64> {
+        if aconfig_android_hardware_biometrics_rust::last_authentication_time() {
+            map_or_log_err(self.get_last_auth_time(secure_user_id, auth_types), Ok)
+        } else {
+            Err(BinderStatus::new_service_specific_error(
+                ResponseCode::PERMISSION_DENIED.0,
+                Some(CString::new("Feature is not enabled.").unwrap().as_c_str()),
+            ))
+        }
+    }
 }
diff --git a/keystore2/src/crypto/lib.rs b/keystore2/src/crypto/lib.rs
index f8fc574..8434651 100644
--- a/keystore2/src/crypto/lib.rs
+++ b/keystore2/src/crypto/lib.rs
@@ -489,8 +489,8 @@
         let input = vec![0; 16];
         let mut out = vec![0; 16];
         let mut out2 = vec![0; 16];
-        let key = vec![0; 16];
-        let iv = vec![0; 12];
+        let key = [0; 16];
+        let iv = [0; 12];
         let mut tag = vec![0; 16];
         // SAFETY: The various pointers are obtained from references so they are valid, and
         // `AES_gcm_encrypt` and `AES_gcm_decrypt` don't do anything with them after they return.
@@ -523,7 +523,7 @@
 
     #[test]
     fn test_create_key_id() {
-        let blob = vec![0; 16];
+        let blob = [0; 16];
         let mut out: u64 = 0;
         // SAFETY: The pointers are obtained from references so they are valid, the length matches
         // the length of the array, and `CreateKeyId` doesn't access them after it returns.
@@ -537,8 +537,8 @@
     #[test]
     fn test_generate_key_from_password() {
         let mut key = vec![0; 16];
-        let pw = vec![0; 16];
-        let salt = vec![0; 16];
+        let pw = [0; 16];
+        let salt = [0; 16];
         // SAFETY: The pointers are obtained from references so they are valid, the salt is the
         // expected length, the other lengths match the lengths of the arrays, and
         // `generateKeyFromPassword` doesn't access them after it returns.
diff --git a/keystore2/src/database.rs b/keystore2/src/database.rs
index d6bfaf2..83963f9 100644
--- a/keystore2/src/database.rs
+++ b/keystore2/src/database.rs
@@ -55,11 +55,6 @@
     error::{Error as KsError, ErrorCode, ResponseCode},
     super_key::SuperKeyType,
 };
-use anyhow::{anyhow, Context, Result};
-use std::{convert::TryFrom, convert::TryInto, ops::Deref, time::SystemTimeError};
-use utils as db_utils;
-use utils::SqlField;
-
 use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
     HardwareAuthToken::HardwareAuthToken, HardwareAuthenticatorType::HardwareAuthenticatorType,
     SecurityLevel::SecurityLevel,
@@ -70,6 +65,11 @@
 use android_system_keystore2::aidl::android::system::keystore2::{
     Domain::Domain, KeyDescriptor::KeyDescriptor,
 };
+use anyhow::{anyhow, Context, Result};
+use keystore2_flags;
+use std::{convert::TryFrom, convert::TryInto, ops::Deref, time::SystemTimeError};
+use utils as db_utils;
+use utils::SqlField;
 
 use keystore2_crypto::ZVec;
 use lazy_static::lazy_static;
@@ -1036,6 +1036,11 @@
             break;
         }
 
+        if keystore2_flags::wal_db_journalmode() {
+            // Update journal mode to WAL
+            conn.pragma_update(None, "journal_mode", "WAL")
+                .context("Failed to connect in WAL mode for persistent db")?;
+        }
         // Drop the cache size from default (2M) to 0.5M
         conn.execute("PRAGMA persistent.cache_size = -500;", params![])
             .context("Failed to decrease cache size for persistent db")?;
@@ -2850,7 +2855,7 @@
     };
     use crate::key_perm_set;
     use crate::permission::{KeyPerm, KeyPermSet};
-    use crate::super_key::{SuperKeyManager, USER_SUPER_KEY, SuperEncryptionAlgorithm, SuperKeyType};
+    use crate::super_key::{SuperKeyManager, USER_AFTER_FIRST_UNLOCK_SUPER_KEY, SuperEncryptionAlgorithm, SuperKeyType};
     use keystore2_test_utils::TempDir;
     use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
         HardwareAuthToken::HardwareAuthToken,
@@ -4885,11 +4890,13 @@
         let key_name_enc = SuperKeyType {
             alias: "test_super_key_1",
             algorithm: SuperEncryptionAlgorithm::Aes256Gcm,
+            name: "test_super_key_1",
         };
 
         let key_name_nonenc = SuperKeyType {
             alias: "test_super_key_2",
             algorithm: SuperEncryptionAlgorithm::Aes256Gcm,
+            name: "test_super_key_2",
         };
 
         // Install two super keys.
@@ -4961,18 +4968,23 @@
             SuperKeyManager::encrypt_with_password(&super_key, &pw)?;
         db.store_super_key(
             1,
-            &USER_SUPER_KEY,
+            &USER_AFTER_FIRST_UNLOCK_SUPER_KEY,
             &encrypted_super_key,
             &metadata,
             &KeyMetaData::new(),
         )?;
 
         // Check if super key exists.
-        assert!(db.key_exists(Domain::APP, 1, USER_SUPER_KEY.alias, KeyType::Super)?);
+        assert!(db.key_exists(
+            Domain::APP,
+            1,
+            USER_AFTER_FIRST_UNLOCK_SUPER_KEY.alias,
+            KeyType::Super
+        )?);
 
-        let (_, key_entry) = db.load_super_key(&USER_SUPER_KEY, 1)?.unwrap();
+        let (_, key_entry) = db.load_super_key(&USER_AFTER_FIRST_UNLOCK_SUPER_KEY, 1)?.unwrap();
         let loaded_super_key = SuperKeyManager::extract_super_key_from_key_entry(
-            USER_SUPER_KEY.algorithm,
+            USER_AFTER_FIRST_UNLOCK_SUPER_KEY.algorithm,
             key_entry,
             &pw,
             None,
@@ -5039,7 +5051,6 @@
         for storage in increased_storage_types {
             // Verify the expected storage increased.
             let new = db.get_storage_stat(storage).unwrap();
-            let storage = storage;
             let old = &baseline[&storage.0];
             assert!(new.size >= old.size, "{}: {} >= {}", storage.0, new.size, old.size);
             assert!(
diff --git a/keystore2/src/enforcements.rs b/keystore2/src/enforcements.rs
index 3bf582f..95e8837 100644
--- a/keystore2/src/enforcements.rs
+++ b/keystore2/src/enforcements.rs
@@ -774,10 +774,10 @@
                     Candidate { priority: 3, enc_type: SuperEncryptionType::BootLevel(*level) }
                 }
                 KeyParameterValue::UnlockedDeviceRequired if *domain == Domain::APP => {
-                    Candidate { priority: 2, enc_type: SuperEncryptionType::ScreenLockBound }
+                    Candidate { priority: 2, enc_type: SuperEncryptionType::UnlockedDeviceRequired }
                 }
                 KeyParameterValue::UserSecureID(_) if *domain == Domain::APP => {
-                    Candidate { priority: 1, enc_type: SuperEncryptionType::LskfBound }
+                    Candidate { priority: 1, enc_type: SuperEncryptionType::AfterFirstUnlock }
                 }
                 _ => Candidate { priority: 0, enc_type: SuperEncryptionType::None },
             };
@@ -845,6 +845,24 @@
             get_timestamp_token(challenge).context(ks_err!("Error in getting timestamp token."))?;
         Ok((auth_token, tst))
     }
+
+    /// Finds the most recent received time for an auth token that matches the given secure user id and authenticator
+    pub fn get_last_auth_time(
+        &self,
+        secure_user_id: i64,
+        auth_type: HardwareAuthenticatorType,
+    ) -> Option<MonotonicRawTime> {
+        let sids: Vec<i64> = vec![secure_user_id];
+
+        let result =
+            Self::find_auth_token(|entry: &AuthTokenEntry| entry.satisfies(&sids, auth_type));
+
+        if let Some((auth_token_entry, _)) = result {
+            Some(auth_token_entry.time_received())
+        } else {
+            None
+        }
+    }
 }
 
 // TODO: Add tests to enforcement module (b/175578618).
diff --git a/keystore2/src/error.rs b/keystore2/src/error.rs
index 3ca3942..1a048b6 100644
--- a/keystore2/src/error.rs
+++ b/keystore2/src/error.rs
@@ -13,22 +13,19 @@
 // limitations under the License.
 
 //! Keystore error provides convenience methods and types for Keystore error handling.
-//! Clients of Keystore expect one of two error codes, i.e., a Keystore ResponseCode as
-//! defined by the Keystore AIDL interface, or a Keymint ErrorCode as defined by
-//! the Keymint HAL specification.
-//! This crate provides `Error` which can wrap both. It is to be used
-//! internally by Keystore to diagnose error conditions that need to be reported to
-//! the client. To report the error condition to the client the Keystore AIDL
-//! interface defines a wire type `Result` which is distinctly different from Rust's
-//! `enum Result<T,E>`.
 //!
-//! This crate provides the convenience method `map_or_log_err` to convert `anyhow::Error`
-//! into this wire type. In addition to handling the conversion of `Error`
-//! to the `Result` wire type it handles any other error by mapping it to
-//! `ResponseCode::SYSTEM_ERROR` and logs any error condition.
+//! Here are some important types and helper functions:
 //!
-//! Keystore functions should use `anyhow::Result` to return error conditions, and
-//! context should be added every time an error is forwarded.
+//! `Error` type encapsulate Keystore, Keymint, and Binder errors. It is used internally by
+//! Keystore to diagnose error conditions that need to be reported to the client.
+//!
+//! `SerializedError` is used send error codes on the wire.
+//!
+//! `map_or_log_err` is a convenience method used to convert `anyhow::Error` into `SerializedError`
+//! wire type.
+//!
+//! Keystore functions should use `anyhow::Result` to return error conditions, and context should
+//! be added every time an error is forwarded.
 
 pub use android_hardware_security_keymint::aidl::android::hardware::security::keymint::ErrorCode::ErrorCode;
 pub use android_system_keystore2::aidl::android::system::keystore2::ResponseCode::ResponseCode;
@@ -55,10 +52,6 @@
     /// Wraps a Binder status code.
     #[error("Binder transaction error {0:?}")]
     BinderTransaction(StatusCode),
-    /// Wraps a Remote Provisioning ErrorCode as defined by the IRemotelyProvisionedComponent
-    /// AIDL interface spec.
-    #[error("Error::Rp({0:?})")]
-    Rp(ErrorCode),
 }
 
 impl Error {
@@ -103,16 +96,6 @@
     })
 }
 
-/// Helper function to map the binder status we get from calls into a RemotelyProvisionedComponent
-/// to a Keystore Error. We don't create an anyhow error here to make
-/// it easier to evaluate service specific errors.
-pub fn map_rem_prov_error<T>(r: BinderResult<T>) -> Result<T, Error> {
-    r.map_err(|s| match s.exception_code() {
-        ExceptionCode::SERVICE_SPECIFIC => Error::Rp(ErrorCode(s.service_specific_error())),
-        e_code => Error::Binder(e_code, 0),
-    })
-}
-
 /// This function is similar to map_km_error only that we don't expect
 /// any KeyMint error codes, we simply preserve the exception code and optional
 /// service specific exception.
@@ -140,14 +123,6 @@
 ///
 /// All error conditions get logged by this function, except for KEY_NOT_FOUND error.
 ///
-/// All `Error::Rc(x)` and `Error::Km(x)` variants get mapped onto a service specific error
-/// code of x. This is possible because KeyMint `ErrorCode` errors are always negative and
-/// `ResponseCode` codes are always positive.
-/// `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).
@@ -214,9 +189,9 @@
     result.map_or_else(
         |e| {
             let e = map_err(e);
-            let rc = get_error_code(&e);
+            let rc = anyhow_error_to_serialized_error(&e);
             Err(BinderStatus::new_service_specific_error(
-                rc,
+                rc.0,
                 anyhow_error_to_cstring(&e).as_deref(),
             ))
         },
@@ -224,22 +199,42 @@
     )
 }
 
-/// Returns the error code given a reference to the error
-pub fn get_error_code(e: &anyhow::Error) -> i32 {
+/// This type is used to send error codes on the wire.
+///
+/// Errors are squashed into one number space using following rules:
+/// - All Keystore and Keymint errors codes are identity mapped. It's possible because by
+///   convention Keystore `ResponseCode` errors are positive, and Keymint `ErrorCode` errors are
+///   negative.
+/// - `selinux::Error::PermissionDenied` is mapped to `ResponseCode::PERMISSION_DENIED`.
+/// - All other error conditions, e.g. Binder errors, are mapped to `ResponseCode::SYSTEM_ERROR`.
+///
+/// The type should be used to forward all error codes to clients of Keystore AIDL interface and to
+/// metrics events.
+#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
+pub struct SerializedError(pub i32);
+
+/// Returns a SerializedError given a reference to Error.
+pub fn error_to_serialized_error(e: &Error) -> SerializedError {
+    match e {
+        Error::Rc(rcode) => SerializedError(rcode.0),
+        Error::Km(ec) => SerializedError(ec.0),
+        // Binder errors are reported as system error.
+        Error::Binder(_, _) | Error::BinderTransaction(_) => {
+            SerializedError(ResponseCode::SYSTEM_ERROR.0)
+        }
+    }
+}
+
+/// Returns a SerializedError given a reference to anyhow::Error.
+pub fn anyhow_error_to_serialized_error(e: &anyhow::Error) -> SerializedError {
     let root_cause = e.root_cause();
     match root_cause.downcast_ref::<Error>() {
-        Some(Error::Rc(rcode)) => rcode.0,
-        Some(Error::Km(ec)) => ec.0,
-        Some(Error::Rp(_)) => ResponseCode::SYSTEM_ERROR.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
-        }
+        Some(e) => error_to_serialized_error(e),
         None => match root_cause.downcast_ref::<selinux::Error>() {
-            Some(selinux::Error::PermissionDenied) => ResponseCode::PERMISSION_DENIED.0,
-            _ => ResponseCode::SYSTEM_ERROR.0,
+            Some(selinux::Error::PermissionDenied) => {
+                SerializedError(ResponseCode::PERMISSION_DENIED.0)
+            }
+            _ => SerializedError(ResponseCode::SYSTEM_ERROR.0),
         },
     }
 }
diff --git a/keystore2/src/fuzzers/Android.bp b/keystore2/src/fuzzers/Android.bp
index 9f3e104..0809dc8 100644
--- a/keystore2/src/fuzzers/Android.bp
+++ b/keystore2/src/fuzzers/Android.bp
@@ -20,7 +20,6 @@
     name: "keystore2_unsafe_fuzzer",
     srcs: ["keystore2_unsafe_fuzzer.rs"],
     rustlibs: [
-        "libbinder_rs",
         "libkeystore2",
         "libkeystore2_crypto_rust",
         "libkeystore2_hal_names_rust",
diff --git a/keystore2/src/fuzzers/keystore2_unsafe_fuzzer.rs b/keystore2/src/fuzzers/keystore2_unsafe_fuzzer.rs
index b8259cf..8b8843d 100644
--- a/keystore2/src/fuzzers/keystore2_unsafe_fuzzer.rs
+++ b/keystore2/src/fuzzers/keystore2_unsafe_fuzzer.rs
@@ -16,7 +16,6 @@
 
 #![no_main]
 
-use binder::get_declared_instances;
 use keystore2::{legacy_blob::LegacyBlobLoader, utils::ui_opts_2_compat};
 use keystore2_aaid::get_aaid;
 use keystore2_apc_compat::ApcHal;
@@ -94,10 +93,6 @@
         minor_version: usize,
         hidl_interface_name: &'a str,
     },
-    GetAidlInstances {
-        aidl_package: &'a str,
-        aidl_interface_name: &'a str,
-    },
     GetAaid {
         aaid_uid: u32,
     },
@@ -189,12 +184,6 @@
             } => {
                 get_hidl_instances(hidl_package, major_version, minor_version, hidl_interface_name);
             }
-            FuzzCommand::GetAidlInstances { aidl_package, aidl_interface_name } => {
-                get_declared_instances(
-                    format!("{}.{}", aidl_package, aidl_interface_name).as_str(),
-                )
-                .unwrap();
-            }
             FuzzCommand::GetAaid { aaid_uid } => {
                 let _res = get_aaid(aaid_uid);
             }
diff --git a/keystore2/src/km_compat.rs b/keystore2/src/km_compat.rs
index 035edd9..cd58fe4 100644
--- a/keystore2/src/km_compat.rs
+++ b/keystore2/src/km_compat.rs
@@ -32,6 +32,11 @@
 use anyhow::Context;
 use keystore2_crypto::{hmac_sha256, HMAC_SHA256_LEN};
 
+/// Magic prefix used by the km_compat C++ code to mark a key that is owned by an
+/// underlying Keymaster hardware device that has been wrapped by km_compat. (The
+/// final zero byte indicates that the blob is not software emulated.)
+pub const KEYMASTER_BLOB_HW_PREFIX: &[u8] = b"pKMblob\x00";
+
 /// Key data associated with key generation/import.
 #[derive(Debug, PartialEq, Eq)]
 pub enum KeyImportData<'a> {
@@ -159,7 +164,7 @@
     }
 }
 
-impl<T> binder::Interface for BacklevelKeyMintWrapper<T> where T: EmulationDetector {}
+impl<T> binder::Interface for BacklevelKeyMintWrapper<T> where T: EmulationDetector + 'static {}
 
 impl<T> IKeyMintDevice for BacklevelKeyMintWrapper<T>
 where
@@ -195,6 +200,15 @@
         let _ = self.soft.earlyBootEnded();
         self.real.earlyBootEnded()
     }
+    fn getRootOfTrustChallenge(&self) -> binder::Result<[u8; 16]> {
+        self.real.getRootOfTrustChallenge()
+    }
+    fn getRootOfTrust(&self, challenge: &[u8; 16]) -> binder::Result<Vec<u8>> {
+        self.real.getRootOfTrust(challenge)
+    }
+    fn sendRootOfTrust(&self, root_of_trust: &[u8]) -> binder::Result<()> {
+        self.real.sendRootOfTrust(root_of_trust)
+    }
 
     // For methods that emit keyblobs, check whether the underlying real device
     // supports the relevant parameters, and forward to the appropriate device.
@@ -299,15 +313,6 @@
             KeyBlob::Wrapped(keyblob) => self.soft.getKeyCharacteristics(keyblob, app_id, app_data),
         }
     }
-    fn getRootOfTrustChallenge(&self) -> binder::Result<[u8; 16]> {
-        self.real.getRootOfTrustChallenge()
-    }
-    fn getRootOfTrust(&self, challenge: &[u8; 16]) -> binder::Result<Vec<u8>> {
-        self.real.getRootOfTrust(challenge)
-    }
-    fn sendRootOfTrust(&self, root_of_trust: &[u8]) -> binder::Result<()> {
-        self.real.sendRootOfTrust(root_of_trust)
-    }
     fn convertStorageKeyToEphemeral(&self, storage_keyblob: &[u8]) -> binder::Result<Vec<u8>> {
         // Storage keys should never be associated with a software emulated device.
         self.real.convertStorageKeyToEphemeral(storage_keyblob)
diff --git a/keystore2/src/km_compat/km_compat.cpp b/keystore2/src/km_compat/km_compat.cpp
index e27cd1c..e9ff1ff 100644
--- a/keystore2/src/km_compat/km_compat.cpp
+++ b/keystore2/src/km_compat/km_compat.cpp
@@ -144,6 +144,11 @@
 //
 const uint8_t kKeyBlobMagic[7] = {'p', 'K', 'M', 'b', 'l', 'o', 'b'};
 
+// Per RFC 5280 4.1.2.5, an undefined expiration (not-after) field should be set
+// to 9999-12-31T23:59:59Z.
+//
+const uint64_t kUndefinedNotAfter = 253402300799000;
+
 // Prefixes a keyblob returned by e.g. generateKey() with information on whether it
 // originated from the real underlying KeyMaster HAL or from soft-KeyMint.
 //
@@ -260,6 +265,16 @@
     return result;
 }
 
+std::vector<KMV1::KeyParameter>
+extractCombinedParams(const std::vector<KMV1::KeyCharacteristics>& characteristics) {
+    std::vector<KMV1::KeyParameter> result;
+    for (auto characteristic : characteristics) {
+        std::copy(characteristic.authorizations.begin(), characteristic.authorizations.end(),
+                  std::back_inserter(result));
+    }
+    return result;
+}
+
 ScopedAStatus convertErrorCode(KMV1::ErrorCode result) {
     if (result == KMV1::ErrorCode::OK) {
         return ScopedAStatus::ok();
@@ -587,6 +602,15 @@
         LOG(ERROR) << __func__ << " transaction failed. " << result.description();
         return convertErrorCode(KMV1::ErrorCode::UNKNOWN_ERROR);
     }
+    if (errorCode == KMV1::ErrorCode::OK) {
+        auto params = extractCombinedParams(out_creationResult->keyCharacteristics);
+        auto cert = getCertificate(params, out_creationResult->keyBlob, true /* isWrappedKey */);
+        // importWrappedKey used to not generate a certificate. Ignore the error to preserve
+        // backwards compatibility with clients that can't successfully generate a certificate.
+        if (std::holds_alternative<std::vector<Certificate>>(cert)) {
+            out_creationResult->certificateChain = std::get<std::vector<Certificate>>(cert);
+        }
+    }
     return convertErrorCode(errorCode);
 }
 
@@ -1055,7 +1079,7 @@
 
 static std::variant<keystore::X509_Ptr, KMV1::ErrorCode>
 makeCert(::android::sp<Keymaster> mDevice, const std::vector<KeyParameter>& keyParams,
-         const std::vector<uint8_t>& keyBlob) {
+         const std::vector<uint8_t>& keyBlob, bool isWrappedKey) {
     // Start generating the certificate.
     // Get public key for makeCert.
     KMV1::ErrorCode errorCode;
@@ -1097,15 +1121,21 @@
         serial = *blob;
     }
 
+    // There is no way to specify CERTIFICATE_NOT_BEFORE and CERTIFICATE_NOT_AFTER for wrapped keys.
+    // So we provide default values.
     int64_t activation;
-    if (auto date = getParam(keyParams, KMV1::TAG_CERTIFICATE_NOT_BEFORE)) {
+    if (isWrappedKey) {
+        activation = 0;
+    } else if (auto date = getParam(keyParams, KMV1::TAG_CERTIFICATE_NOT_BEFORE)) {
         activation = static_cast<int64_t>(*date);
     } else {
         return KMV1::ErrorCode::MISSING_NOT_BEFORE;
     }
 
     int64_t expiration;
-    if (auto date = getParam(keyParams, KMV1::TAG_CERTIFICATE_NOT_AFTER)) {
+    if (isWrappedKey) {
+        expiration = kUndefinedNotAfter;
+    } else if (auto date = getParam(keyParams, KMV1::TAG_CERTIFICATE_NOT_AFTER)) {
         expiration = static_cast<int64_t>(*date);
     } else {
         return KMV1::ErrorCode::MISSING_NOT_AFTER;
@@ -1235,7 +1265,7 @@
 
 std::variant<std::vector<Certificate>, KMV1::ErrorCode>
 KeyMintDevice::getCertificate(const std::vector<KeyParameter>& keyParams,
-                              const std::vector<uint8_t>& prefixedKeyBlob) {
+                              const std::vector<uint8_t>& prefixedKeyBlob, bool isWrappedKey) {
     const std::vector<uint8_t>& keyBlob = prefixedKeyBlobRemovePrefix(prefixedKeyBlob);
 
     // There are no certificates for symmetric keys.
@@ -1278,7 +1308,7 @@
     }
 
     // makeCert
-    auto certOrError = makeCert(mDevice, keyParams, keyBlob);
+    auto certOrError = makeCert(mDevice, keyParams, keyBlob, isWrappedKey);
     if (std::holds_alternative<KMV1::ErrorCode>(certOrError)) {
         return std::get<KMV1::ErrorCode>(certOrError);
     }
@@ -1420,7 +1450,12 @@
 
 KeymasterDevices initializeKeymasters() {
     auto serviceManager = IServiceManager::getService();
-    CHECK(serviceManager.get()) << "Failed to get ServiceManager";
+    if (!serviceManager.get()) {
+        // New devices no longer have HIDL support, so failing to get hwservicemanager is
+        // expected behavior.
+        LOG(INFO) << "Skipping keymaster compat, this system is AIDL only.";
+        return KeymasterDevices();
+    }
     auto result = enumerateKeymasterDevices<Keymaster4>(serviceManager.get());
     auto softKeymaster = result[SecurityLevel::SOFTWARE];
     if ((!result[SecurityLevel::TRUSTED_ENVIRONMENT]) && (!result[SecurityLevel::STRONGBOX])) {
diff --git a/keystore2/src/km_compat/km_compat.h b/keystore2/src/km_compat/km_compat.h
index 6654c4a..c4bcdaa 100644
--- a/keystore2/src/km_compat/km_compat.h
+++ b/keystore2/src/km_compat/km_compat.h
@@ -150,7 +150,8 @@
     // These are public to allow testing code to use them directly.
     // This class should not be used publicly anyway.
     std::variant<std::vector<Certificate>, KMV1_ErrorCode>
-    getCertificate(const std::vector<KeyParameter>& keyParams, const std::vector<uint8_t>& keyBlob);
+    getCertificate(const std::vector<KeyParameter>& keyParams, const std::vector<uint8_t>& keyBlob,
+                   bool isWrappedKey = false);
 
     void setNumFreeSlots(uint8_t numFreeSlots);
 
diff --git a/keystore2/src/legacy_importer.rs b/keystore2/src/legacy_importer.rs
index 325c213..7dcb98d 100644
--- a/keystore2/src/legacy_importer.rs
+++ b/keystore2/src/legacy_importer.rs
@@ -22,7 +22,7 @@
 use crate::key_parameter::{KeyParameter, KeyParameterValue};
 use crate::ks_err;
 use crate::legacy_blob::{self, Blob, BlobValue, LegacyKeyCharacteristics};
-use crate::super_key::USER_SUPER_KEY;
+use crate::super_key::USER_AFTER_FIRST_UNLOCK_SUPER_KEY;
 use crate::utils::{
     key_characteristics_to_internal, uid_to_android_user, upgrade_keyblob_if_required_with,
     watchdog as wd, AesGcm,
@@ -450,7 +450,7 @@
 
         match self
             .db
-            .load_super_key(&USER_SUPER_KEY, user_id)
+            .load_super_key(&USER_AFTER_FIRST_UNLOCK_SUPER_KEY, user_id)
             .context(ks_err!("Failed to load super key"))?
         {
             Some((_, entry)) => Ok(entry.id()),
@@ -729,7 +729,7 @@
             self.db
                 .store_super_key(
                     user_id,
-                    &USER_SUPER_KEY,
+                    &USER_AFTER_FIRST_UNLOCK_SUPER_KEY,
                     &blob,
                     &blob_metadata,
                     &KeyMetaData::new(),
@@ -772,7 +772,7 @@
 
         let super_key_id = self
             .db
-            .load_super_key(&USER_SUPER_KEY, user_id)
+            .load_super_key(&USER_AFTER_FIRST_UNLOCK_SUPER_KEY, user_id)
             .context(ks_err!("Failed to load super key"))?
             .map(|(_, entry)| entry.id());
 
@@ -914,11 +914,12 @@
     uuid: &Uuid,
     blob: &[u8],
 ) -> Result<(Vec<KeyParameter>, Option<Vec<u8>>)> {
-    let (km_dev, _) = crate::globals::get_keymint_dev_by_uuid(uuid)
+    let (km_dev, info) = crate::globals::get_keymint_dev_by_uuid(uuid)
         .with_context(|| ks_err!("Trying to get km device for id {:?}", uuid))?;
 
     let (characteristics, upgraded_blob) = upgrade_keyblob_if_required_with(
         &*km_dev,
+        info.versionNumber,
         blob,
         &[],
         |blob| {
diff --git a/keystore2/src/lib.rs b/keystore2/src/lib.rs
index 9794889..e51a319 100644
--- a/keystore2/src/lib.rs
+++ b/keystore2/src/lib.rs
@@ -28,7 +28,6 @@
 pub mod id_rotation;
 /// Internal Representation of Key Parameter and convenience functions.
 pub mod key_parameter;
-pub mod ks_err;
 pub mod legacy_blob;
 pub mod legacy_importer;
 pub mod maintenance;
@@ -49,6 +48,7 @@
 mod gc;
 mod km_compat;
 mod super_key;
+mod sw_keyblob;
+mod watchdog_helper;
 
-#[cfg(feature = "watchdog")]
-mod watchdog;
+use message_macro::source_location_msg as ks_err;
diff --git a/keystore2/src/maintenance.rs b/keystore2/src/maintenance.rs
index 73dc881..ea48f4d 100644
--- a/keystore2/src/maintenance.rs
+++ b/keystore2/src/maintenance.rs
@@ -29,9 +29,8 @@
 use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
     IKeyMintDevice::IKeyMintDevice, SecurityLevel::SecurityLevel,
 };
-use android_security_maintenance::aidl::android::security::maintenance::{
-    IKeystoreMaintenance::{BnKeystoreMaintenance, IKeystoreMaintenance},
-    UserState::UserState as AidlUserState,
+use android_security_maintenance::aidl::android::security::maintenance::IKeystoreMaintenance::{
+    BnKeystoreMaintenance, IKeystoreMaintenance,
 };
 use android_security_maintenance::binder::{
     BinderFeatures, Interface, Result as BinderResult, Strong, ThreadState,
@@ -78,12 +77,12 @@
 
         if let Some(pw) = password.as_ref() {
             DB.with(|db| {
-                skm.unlock_screen_lock_bound_key(&mut db.borrow_mut(), user_id as u32, pw)
+                skm.unlock_unlocked_device_required_keys(&mut db.borrow_mut(), user_id as u32, pw)
             })
-            .context(ks_err!("unlock_screen_lock_bound_key failed"))?;
+            .context(ks_err!("unlock_unlocked_device_required_keys failed"))?;
         }
 
-        if let UserState::LskfLocked = DB
+        if let UserState::BeforeFirstUnlock = DB
             .with(|db| skm.get_user_state(&mut db.borrow_mut(), &LEGACY_IMPORTER, user_id as u32))
             .context(ks_err!("Could not get user state while changing password!"))?
         {
@@ -135,27 +134,6 @@
             .context(ks_err!("While invoking the delete listener."))
     }
 
-    fn get_state(user_id: i32) -> Result<AidlUserState> {
-        // Check permission. Function should return if this failed. Therefore having '?' at the end
-        // is very important.
-        check_keystore_permission(KeystorePerm::GetState).context("In get_state.")?;
-        let state = DB
-            .with(|db| {
-                SUPER_KEY.read().unwrap().get_user_state(
-                    &mut db.borrow_mut(),
-                    &LEGACY_IMPORTER,
-                    user_id as u32,
-                )
-            })
-            .context(ks_err!("Trying to get UserState."))?;
-
-        match state {
-            UserState::Uninitialized => Ok(AidlUserState::UNINITIALIZED),
-            UserState::LskfUnlocked(_) => Ok(AidlUserState::LSKF_UNLOCKED),
-            UserState::LskfLocked => Ok(AidlUserState::LSKF_LOCKED),
-        }
-    }
-
     fn call_with_watchdog<F>(sec_level: SecurityLevel, name: &'static str, op: &F) -> Result<()>
     where
         F: Fn(Strong<dyn IKeyMintDevice>) -> binder::Result<()>,
@@ -178,7 +156,7 @@
             (SecurityLevel::TRUSTED_ENVIRONMENT, "TRUSTED_ENVIRONMENT"),
             (SecurityLevel::STRONGBOX, "STRONGBOX"),
         ];
-        sec_levels.iter().fold(Ok(()), move |result, (sec_level, sec_level_string)| {
+        sec_levels.iter().try_fold((), |_result, (sec_level, sec_level_string)| {
             let curr_result = Maintenance::call_with_watchdog(*sec_level, name, &op);
             match curr_result {
                 Ok(()) => log::info!(
@@ -193,7 +171,7 @@
                     e
                 ),
             }
-            result.and(curr_result)
+            curr_result
         })
     }
 
@@ -239,7 +217,7 @@
 
         let user_id = uid_to_android_user(calling_uid);
 
-        let super_key = SUPER_KEY.read().unwrap().get_per_boot_key_by_user_id(user_id);
+        let super_key = SUPER_KEY.read().unwrap().get_after_first_unlock_key_by_user_id(user_id);
 
         DB.with(|db| {
             let (key_id_guard, _) = LEGACY_IMPORTER
@@ -279,36 +257,41 @@
 
 impl IKeystoreMaintenance for Maintenance {
     fn onUserPasswordChanged(&self, user_id: i32, password: Option<&[u8]>) -> BinderResult<()> {
+        log::info!(
+            "onUserPasswordChanged(user={}, password.is_some()={})",
+            user_id,
+            password.is_some()
+        );
         let _wp = wd::watch_millis("IKeystoreMaintenance::onUserPasswordChanged", 500);
         map_or_log_err(Self::on_user_password_changed(user_id, password.map(|pw| pw.into())), Ok)
     }
 
     fn onUserAdded(&self, user_id: i32) -> BinderResult<()> {
+        log::info!("onUserAdded(user={user_id})");
         let _wp = wd::watch_millis("IKeystoreMaintenance::onUserAdded", 500);
         map_or_log_err(self.add_or_remove_user(user_id), Ok)
     }
 
     fn onUserRemoved(&self, user_id: i32) -> BinderResult<()> {
+        log::info!("onUserRemoved(user={user_id})");
         let _wp = wd::watch_millis("IKeystoreMaintenance::onUserRemoved", 500);
         map_or_log_err(self.add_or_remove_user(user_id), Ok)
     }
 
     fn clearNamespace(&self, domain: Domain, nspace: i64) -> BinderResult<()> {
+        log::info!("clearNamespace({domain:?}, nspace={nspace})");
         let _wp = wd::watch_millis("IKeystoreMaintenance::clearNamespace", 500);
         map_or_log_err(self.clear_namespace(domain, nspace), Ok)
     }
 
-    fn getState(&self, user_id: i32) -> BinderResult<AidlUserState> {
-        let _wp = wd::watch_millis("IKeystoreMaintenance::getState", 500);
-        map_or_log_err(Self::get_state(user_id), Ok)
-    }
-
     fn earlyBootEnded(&self) -> BinderResult<()> {
+        log::info!("earlyBootEnded()");
         let _wp = wd::watch_millis("IKeystoreMaintenance::earlyBootEnded", 500);
         map_or_log_err(Self::early_boot_ended(), Ok)
     }
 
     fn onDeviceOffBody(&self) -> BinderResult<()> {
+        log::info!("onDeviceOffBody()");
         let _wp = wd::watch_millis("IKeystoreMaintenance::onDeviceOffBody", 500);
         map_or_log_err(Self::on_device_off_body(), Ok)
     }
@@ -318,11 +301,13 @@
         source: &KeyDescriptor,
         destination: &KeyDescriptor,
     ) -> BinderResult<()> {
+        log::info!("migrateKeyNamespace(src={source:?}, dest={destination:?})");
         let _wp = wd::watch_millis("IKeystoreMaintenance::migrateKeyNamespace", 500);
         map_or_log_err(Self::migrate_key_namespace(source, destination), Ok)
     }
 
     fn deleteAllKeys(&self) -> BinderResult<()> {
+        log::warn!("deleteAllKeys()");
         let _wp = wd::watch_millis("IKeystoreMaintenance::deleteAllKeys", 500);
         map_or_log_err(Self::delete_all_keys(), Ok)
     }
diff --git a/keystore2/src/metrics_store.rs b/keystore2/src/metrics_store.rs
index 5d311f0..5a76d04 100644
--- a/keystore2/src/metrics_store.rs
+++ b/keystore2/src/metrics_store.rs
@@ -17,7 +17,7 @@
 //!    stores them in an in-memory store.
 //! 2. Returns the collected metrics when requested by the statsd proxy.
 
-use crate::error::get_error_code;
+use crate::error::anyhow_error_to_serialized_error;
 use crate::globals::DB;
 use crate::key_parameter::KeyParameterValue as KsKeyParamValue;
 use crate::ks_err;
@@ -119,15 +119,14 @@
         // It is ok to unwrap here since the mutex cannot be poisoned according to the way it is
         // used in this module. And the lock is not acquired by this thread before.
         let mut metrics_store_guard = self.metrics_store.lock().unwrap();
-        let atom_count_map = metrics_store_guard.entry(atom_id).or_insert_with(HashMap::new);
+        let atom_count_map = metrics_store_guard.entry(atom_id).or_default();
         if atom_count_map.len() < MetricsStore::SINGLE_ATOM_STORE_MAX_SIZE {
             let atom_count = atom_count_map.entry(atom).or_insert(0);
             *atom_count += 1;
         } else {
             // Insert an overflow atom
-            let overflow_atom_count_map = metrics_store_guard
-                .entry(AtomID::KEYSTORE2_ATOM_WITH_OVERFLOW)
-                .or_insert_with(HashMap::new);
+            let overflow_atom_count_map =
+                metrics_store_guard.entry(AtomID::KEYSTORE2_ATOM_WITH_OVERFLOW).or_default();
 
             if overflow_atom_count_map.len() < MetricsStore::SINGLE_ATOM_STORE_MAX_SIZE {
                 let overflow_atom = Keystore2AtomWithOverflow { atom_id };
@@ -202,7 +201,7 @@
     };
 
     if let Err(ref e) = result {
-        key_creation_with_general_info.error_code = get_error_code(e);
+        key_creation_with_general_info.error_code = anyhow_error_to_serialized_error(e).0;
     }
 
     key_creation_with_auth_info.security_level = process_security_level(sec_level);
diff --git a/keystore2/src/operation.rs b/keystore2/src/operation.rs
index 2034a8a..eabc1ab 100644
--- a/keystore2/src/operation.rs
+++ b/keystore2/src/operation.rs
@@ -126,7 +126,10 @@
 //! Either way, we have to revaluate the pruning scores.
 
 use crate::enforcements::AuthInfo;
-use crate::error::{map_err_with, map_km_error, map_or_log_err, Error, ErrorCode, ResponseCode};
+use crate::error::{
+    error_to_serialized_error, map_err_with, map_km_error, map_or_log_err, Error, ErrorCode,
+    ResponseCode, SerializedError,
+};
 use crate::ks_err;
 use crate::metrics_store::log_key_operation_event_stats;
 use crate::utils::watchdog as wd;
@@ -162,7 +165,7 @@
     /// Operation is pruned.
     Pruned,
     /// Operation is failed with the error code.
-    ErrorCode(ErrorCode),
+    ErrorCode(SerializedError),
 }
 
 /// Operation bundles all of the operation related resources and tracks the operation's
@@ -305,8 +308,7 @@
         err: Result<T, Error>,
     ) -> Result<T, Error> {
         match &err {
-            Err(Error::Km(e)) => *locked_outcome = Outcome::ErrorCode(*e),
-            Err(_) => *locked_outcome = Outcome::ErrorCode(ErrorCode::UNKNOWN_ERROR),
+            Err(e) => *locked_outcome = Outcome::ErrorCode(error_to_serialized_error(e)),
             Ok(_) => (),
         }
         err
diff --git a/keystore2/src/permission.rs b/keystore2/src/permission.rs
index d9bdf79..bc73744 100644
--- a/keystore2/src/permission.rs
+++ b/keystore2/src/permission.rs
@@ -109,9 +109,6 @@
         /// Checked when an app is uninstalled or wiped.
         #[selinux(name = clear_ns)]
         ClearNs,
-        /// Checked when the user state is queried from Keystore 2.0.
-        #[selinux(name = get_state)]
-        GetState,
         /// Checked when Keystore 2.0 is asked to list a namespace that the caller
         /// does not have the get_info permission for.
         #[selinux(name = list)]
@@ -152,6 +149,9 @@
         /// Checked on calls to IRemotelyProvisionedKeyPool::getAttestationKey
         #[selinux(name = get_attestation_key)]
         GetAttestationKey,
+        /// Checked on IKeystoreAuthorization::getLastAuthTime() is called.
+        #[selinux(name = get_last_auth_time)]
+        GetLastAuthTime,
     }
 );
 
@@ -500,7 +500,6 @@
         let system_server_ctx = Context::new("u:r:system_server:s0")?;
         assert!(check_keystore_permission(&system_server_ctx, KeystorePerm::AddAuth).is_ok());
         assert!(check_keystore_permission(&system_server_ctx, KeystorePerm::ClearNs).is_ok());
-        assert!(check_keystore_permission(&system_server_ctx, KeystorePerm::GetState).is_ok());
         assert!(check_keystore_permission(&system_server_ctx, KeystorePerm::Lock).is_ok());
         assert!(check_keystore_permission(&system_server_ctx, KeystorePerm::Reset).is_ok());
         assert!(check_keystore_permission(&system_server_ctx, KeystorePerm::Unlock).is_ok());
@@ -510,7 +509,6 @@
         let shell_ctx = Context::new("u:r:shell:s0")?;
         assert_perm_failed!(check_keystore_permission(&shell_ctx, KeystorePerm::AddAuth));
         assert_perm_failed!(check_keystore_permission(&shell_ctx, KeystorePerm::ClearNs));
-        assert!(check_keystore_permission(&shell_ctx, KeystorePerm::GetState).is_ok());
         assert_perm_failed!(check_keystore_permission(&shell_ctx, KeystorePerm::List));
         assert_perm_failed!(check_keystore_permission(&shell_ctx, KeystorePerm::Lock));
         assert_perm_failed!(check_keystore_permission(&shell_ctx, KeystorePerm::Reset));
diff --git a/keystore2/src/raw_device.rs b/keystore2/src/raw_device.rs
index fa9872a..44d805c 100644
--- a/keystore2/src/raw_device.rs
+++ b/keystore2/src/raw_device.rs
@@ -263,35 +263,31 @@
     where
         F: Fn(&[u8]) -> Result<T, Error>,
     {
-        match f(&key_blob) {
-            Err(Error::Km(ErrorCode::KEY_REQUIRES_UPGRADE)) => {
-                let upgraded_blob = map_km_error({
-                    let _wp = wd::watch_millis(
-                        "In KeyMintDevice::upgrade_keyblob_if_required_with: calling upgradeKey.",
-                        500,
-                    );
-                    self.km_dev.upgradeKey(&key_blob, &[])
-                })
-                .context(ks_err!("Upgrade failed"))?;
-
+        let (f_result, upgraded_blob) = crate::utils::upgrade_keyblob_if_required_with(
+            &*self.km_dev,
+            self.version(),
+            &key_blob,
+            &[],
+            f,
+            |upgraded_blob| {
                 let mut new_blob_metadata = BlobMetaData::new();
                 new_blob_metadata.add(BlobMetaEntry::KmUuid(self.km_uuid));
 
                 db.set_blob(
                     key_id_guard,
                     SubComponentType::KEY_BLOB,
-                    Some(&upgraded_blob),
+                    Some(upgraded_blob),
                     Some(&new_blob_metadata),
                 )
                 .context(ks_err!("Failed to insert upgraded blob into the database"))?;
-
-                Ok((
-                    f(&upgraded_blob).context(ks_err!("Closure failed after upgrade"))?,
-                    KeyBlob::NonSensitive(upgraded_blob),
-                ))
-            }
-            result => Ok((result.context(ks_err!("Closure failed"))?, key_blob)),
-        }
+                Ok(())
+            },
+        )?;
+        let returned_blob = match upgraded_blob {
+            None => key_blob,
+            Some(upgraded_blob) => KeyBlob::NonSensitive(upgraded_blob),
+        };
+        Ok((f_result, returned_blob))
     }
 
     /// Use the created key in an operation that can be done with
diff --git a/keystore2/src/remote_provisioning.rs b/keystore2/src/remote_provisioning.rs
index 811ad98..3f7833e 100644
--- a/keystore2/src/remote_provisioning.rs
+++ b/keystore2/src/remote_provisioning.rs
@@ -31,9 +31,11 @@
 use keystore2_crypto::parse_subject_from_certificate;
 
 use crate::database::Uuid;
+use crate::globals::get_remotely_provisioned_component_name;
 use crate::ks_err;
 use crate::metrics_store::log_rkp_error_stats;
 use crate::rkpd_client::get_rkpd_attestation_key;
+use crate::watchdog_helper::watchdog as wd;
 use android_security_metrics::aidl::android::security::metrics::RkpError::RkpError as MetricsRkpError;
 
 /// Contains helper functions to check if remote provisioning is enabled on the system and, if so,
@@ -93,7 +95,10 @@
         if !self.is_asymmetric_key(params) || key.domain != Domain::APP {
             Ok(None)
         } else {
-            match get_rkpd_attestation_key(&self.security_level, caller_uid) {
+            let rpc_name = get_remotely_provisioned_component_name(&self.security_level)
+                .context(ks_err!("Trying to get IRPC name."))?;
+            let _wd = wd::watch_millis("Calling get_rkpd_attestation_key()", 500);
+            match get_rkpd_attestation_key(&rpc_name, caller_uid) {
                 Err(e) => {
                     if self.is_rkp_only() {
                         log::error!("Error occurred: {:?}", e);
diff --git a/keystore2/src/rkpd_client.rs b/keystore2/src/rkpd_client.rs
index 0ea2d39..fe64150 100644
--- a/keystore2/src/rkpd_client.rs
+++ b/keystore2/src/rkpd_client.rs
@@ -15,10 +15,6 @@
 //! Helper wrapper around RKPD interface.
 
 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::ErrorCode::ErrorCode as GetKeyErrorCode,
     IGetKeyCallback::IGetKeyCallback, IGetRegistrationCallback::BnGetRegistrationCallback,
@@ -30,6 +26,7 @@
 };
 use android_security_rkp_aidl::binder::{BinderFeatures, Interface, Strong};
 use anyhow::{Context, Result};
+use message_macro::source_location_msg;
 use std::sync::Mutex;
 use std::time::Duration;
 use tokio::sync::oneshot;
@@ -84,52 +81,43 @@
 
 impl IGetRegistrationCallback for GetRegistrationCallback {
     fn onSuccess(&self, registration: &Strong<dyn IRegistration>) -> binder::Result<()> {
-        let _wp = wd::watch_millis("IGetRegistrationCallback::onSuccess", 500);
         self.registration_tx.send(Ok(registration.clone()));
         Ok(())
     }
     fn onCancel(&self) -> binder::Result<()> {
-        let _wp = wd::watch_millis("IGetRegistrationCallback::onCancel", 500);
         log::warn!("IGetRegistrationCallback cancelled");
         self.registration_tx.send(
             Err(Error::Rc(ResponseCode::OUT_OF_KEYS_TRANSIENT_ERROR))
-                .context(ks_err!("GetRegistrationCallback cancelled.")),
+                .context(source_location_msg!("GetRegistrationCallback cancelled.")),
         );
         Ok(())
     }
     fn onError(&self, description: &str) -> binder::Result<()> {
-        let _wp = wd::watch_millis("IGetRegistrationCallback::onError", 500);
         log::error!("IGetRegistrationCallback failed: '{description}'");
-        self.registration_tx.send(
-            Err(Error::Rc(ResponseCode::OUT_OF_KEYS_TRANSIENT_ERROR))
-                .context(ks_err!("GetRegistrationCallback failed: {:?}", description)),
-        );
+        self.registration_tx
+            .send(Err(Error::Rc(ResponseCode::OUT_OF_KEYS_TRANSIENT_ERROR)).context(
+                source_location_msg!("GetRegistrationCallback failed: {:?}", description),
+            ));
         Ok(())
     }
 }
 
 /// Make a new connection to a IRegistration service.
-async fn get_rkpd_registration(
-    security_level: &SecurityLevel,
-) -> Result<binder::Strong<dyn IRegistration>> {
+async fn get_rkpd_registration(rpc_name: &str) -> Result<binder::Strong<dyn IRegistration>> {
     let remote_provisioning: Strong<dyn IRemoteProvisioning> =
         map_binder_status_code(binder::get_interface("remote_provisioning"))
-            .context(ks_err!("Trying to connect to IRemoteProvisioning service."))?;
-
-    let rpc_name = get_remotely_provisioned_component_name(security_level)
-        .context(ks_err!("Trying to get IRPC name."))?;
+            .context(source_location_msg!("Trying to connect to IRemoteProvisioning service."))?;
 
     let (tx, rx) = oneshot::channel();
     let cb = GetRegistrationCallback::new_native_binder(tx);
 
     remote_provisioning
-        .getRegistration(&rpc_name, &cb)
-        .context(ks_err!("Trying to get registration."))?;
+        .getRegistration(rpc_name, &cb)
+        .context(source_location_msg!("Trying to get registration."))?;
 
     match timeout(RKPD_TIMEOUT, rx).await {
-        Err(e) => {
-            Err(Error::Rc(ResponseCode::SYSTEM_ERROR)).context(ks_err!("Waiting for RKPD: {:?}", e))
-        }
+        Err(e) => Err(Error::Rc(ResponseCode::SYSTEM_ERROR))
+            .context(source_location_msg!("Waiting for RKPD: {:?}", e)),
         Ok(v) => v.unwrap(),
     }
 }
@@ -151,7 +139,6 @@
 
 impl IGetKeyCallback for GetKeyCallback {
     fn onSuccess(&self, key: &RemotelyProvisionedKey) -> binder::Result<()> {
-        let _wp = wd::watch_millis("IGetKeyCallback::onSuccess", 500);
         self.key_tx.send(Ok(RemotelyProvisionedKey {
             keyBlob: key.keyBlob.clone(),
             encodedCertChain: key.encodedCertChain.clone(),
@@ -159,16 +146,14 @@
         Ok(())
     }
     fn onCancel(&self) -> binder::Result<()> {
-        let _wp = wd::watch_millis("IGetKeyCallback::onCancel", 500);
         log::warn!("IGetKeyCallback cancelled");
         self.key_tx.send(
             Err(Error::Rc(ResponseCode::OUT_OF_KEYS_TRANSIENT_ERROR))
-                .context(ks_err!("GetKeyCallback cancelled.")),
+                .context(source_location_msg!("GetKeyCallback cancelled.")),
         );
         Ok(())
     }
     fn onError(&self, error: GetKeyErrorCode, description: &str) -> binder::Result<()> {
-        let _wp = wd::watch_millis("IGetKeyCallback::onError", 500);
         log::error!("IGetKeyCallback failed: {description}");
         let rc = match error {
             GetKeyErrorCode::ERROR_UNKNOWN => ResponseCode::OUT_OF_KEYS_TRANSIENT_ERROR,
@@ -184,7 +169,7 @@
                 ResponseCode::OUT_OF_KEYS_TRANSIENT_ERROR
             }
         };
-        self.key_tx.send(Err(Error::Rc(rc)).context(ks_err!(
+        self.key_tx.send(Err(Error::Rc(rc)).context(source_location_msg!(
             "GetKeyCallback failed: {:?} {:?}",
             error,
             description
@@ -202,7 +187,7 @@
 
     registration
         .getKey(caller_uid.try_into().unwrap(), &cb)
-        .context(ks_err!("Trying to get key."))?;
+        .context(source_location_msg!("Trying to get key."))?;
 
     match timeout(RKPD_TIMEOUT, rx).await {
         Err(e) => {
@@ -211,19 +196,19 @@
                 log::error!("IRegistration::cancelGetKey failed: {:?}", e);
             }
             Err(Error::Rc(ResponseCode::OUT_OF_KEYS_TRANSIENT_ERROR))
-                .context(ks_err!("Waiting for RKPD key timed out: {:?}", e))
+                .context(source_location_msg!("Waiting for RKPD key timed out: {:?}", e))
         }
         Ok(v) => v.unwrap(),
     }
 }
 
 async fn get_rkpd_attestation_key_async(
-    security_level: &SecurityLevel,
+    rpc_name: &str,
     caller_uid: u32,
 ) -> Result<RemotelyProvisionedKey> {
-    let registration = get_rkpd_registration(security_level)
+    let registration = get_rkpd_registration(rpc_name)
         .await
-        .context(ks_err!("Trying to get to IRegistration service."))?;
+        .context(source_location_msg!("Trying to get to IRegistration service."))?;
     get_rkpd_attestation_key_from_registration_async(&registration, caller_uid).await
 }
 
@@ -244,17 +229,15 @@
 
 impl IStoreUpgradedKeyCallback for StoreUpgradedKeyCallback {
     fn onSuccess(&self) -> binder::Result<()> {
-        let _wp = wd::watch_millis("IGetRegistrationCallback::onSuccess", 500);
         self.completer.send(Ok(()));
         Ok(())
     }
 
     fn onError(&self, error: &str) -> binder::Result<()> {
-        let _wp = wd::watch_millis("IGetRegistrationCallback::onError", 500);
         log::error!("IGetRegistrationCallback failed: {error}");
         self.completer.send(
             Err(Error::Rc(ResponseCode::SYSTEM_ERROR))
-                .context(ks_err!("Failed to store upgraded key: {:?}", error)),
+                .context(source_location_msg!("Failed to store upgraded key: {:?}", error)),
         );
         Ok(())
     }
@@ -270,61 +253,51 @@
 
     registration
         .storeUpgradedKeyAsync(key_blob, upgraded_blob, &cb)
-        .context(ks_err!("Failed to store upgraded blob with RKPD."))?;
+        .context(source_location_msg!("Failed to store upgraded blob with RKPD."))?;
 
     match timeout(RKPD_TIMEOUT, rx).await {
         Err(e) => Err(Error::Rc(ResponseCode::SYSTEM_ERROR))
-            .context(ks_err!("Waiting for RKPD to complete storing key: {:?}", e)),
+            .context(source_location_msg!("Waiting for RKPD to complete storing key: {:?}", e)),
         Ok(v) => v.unwrap(),
     }
 }
 
 async fn store_rkpd_attestation_key_async(
-    security_level: &SecurityLevel,
+    rpc_name: &str,
     key_blob: &[u8],
     upgraded_blob: &[u8],
 ) -> Result<()> {
-    let registration = get_rkpd_registration(security_level)
+    let registration = get_rkpd_registration(rpc_name)
         .await
-        .context(ks_err!("Trying to get to IRegistration service."))?;
+        .context(source_location_msg!("Trying to get to IRegistration service."))?;
     store_rkpd_attestation_key_with_registration_async(&registration, key_blob, upgraded_blob).await
 }
 
 /// Get attestation key from RKPD.
-pub fn get_rkpd_attestation_key(
-    security_level: &SecurityLevel,
-    caller_uid: u32,
-) -> Result<RemotelyProvisionedKey> {
-    let _wp = wd::watch_millis("Calling get_rkpd_attestation_key()", 500);
-    tokio_rt().block_on(get_rkpd_attestation_key_async(security_level, caller_uid))
+pub fn get_rkpd_attestation_key(rpc_name: &str, caller_uid: u32) -> Result<RemotelyProvisionedKey> {
+    tokio_rt().block_on(get_rkpd_attestation_key_async(rpc_name, caller_uid))
 }
 
 /// Store attestation key in RKPD.
 pub fn store_rkpd_attestation_key(
-    security_level: &SecurityLevel,
+    rpc_name: &str,
     key_blob: &[u8],
     upgraded_blob: &[u8],
 ) -> Result<()> {
-    let _wp = wd::watch_millis("Calling store_rkpd_attestation_key()", 500);
-    tokio_rt().block_on(store_rkpd_attestation_key_async(security_level, key_blob, upgraded_blob))
+    tokio_rt().block_on(store_rkpd_attestation_key_async(rpc_name, key_blob, upgraded_blob))
 }
 
 #[cfg(test)]
 mod tests {
     use super::*;
-    use crate::error::map_km_error;
-    use crate::globals::get_keymint_device;
-    use crate::utils::upgrade_keyblob_if_required_with;
-    use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
-        Algorithm::Algorithm, AttestationKey::AttestationKey, KeyParameter::KeyParameter,
-        KeyParameterValue::KeyParameterValue, Tag::Tag,
-    };
     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};
     use std::sync::{Arc, Mutex};
 
+    const DEFAULT_RPC_SERVICE_NAME: &str =
+        "android.hardware.security.keymint.IRemotelyProvisionedComponent/default";
+
     struct MockRegistrationValues {
         key: RemotelyProvisionedKey,
         latency: Option<Duration>,
@@ -597,7 +570,7 @@
     fn test_get_rkpd_attestation_key() {
         binder::ProcessState::start_thread_pool();
         let key_id = get_next_key_id();
-        let key = get_rkpd_attestation_key(&SecurityLevel::TRUSTED_ENVIRONMENT, key_id).unwrap();
+        let key = get_rkpd_attestation_key(DEFAULT_RPC_SERVICE_NAME, key_id).unwrap();
         assert!(!key.keyBlob.is_empty());
         assert!(!key.encodedCertChain.is_empty());
     }
@@ -605,12 +578,11 @@
     #[test]
     fn test_get_rkpd_attestation_key_same_caller() {
         binder::ProcessState::start_thread_pool();
-        let sec_level = SecurityLevel::TRUSTED_ENVIRONMENT;
         let key_id = get_next_key_id();
 
         // Multiple calls should return the same key.
-        let first_key = get_rkpd_attestation_key(&sec_level, key_id).unwrap();
-        let second_key = get_rkpd_attestation_key(&sec_level, key_id).unwrap();
+        let first_key = get_rkpd_attestation_key(DEFAULT_RPC_SERVICE_NAME, key_id).unwrap();
+        let second_key = get_rkpd_attestation_key(DEFAULT_RPC_SERVICE_NAME, key_id).unwrap();
 
         assert_eq!(first_key.keyBlob, second_key.keyBlob);
         assert_eq!(first_key.encodedCertChain, second_key.encodedCertChain);
@@ -619,13 +591,12 @@
     #[test]
     fn test_get_rkpd_attestation_key_different_caller() {
         binder::ProcessState::start_thread_pool();
-        let sec_level = SecurityLevel::TRUSTED_ENVIRONMENT;
         let first_key_id = get_next_key_id();
         let second_key_id = get_next_key_id();
 
         // Different callers should be getting different keys.
-        let first_key = get_rkpd_attestation_key(&sec_level, first_key_id).unwrap();
-        let second_key = get_rkpd_attestation_key(&sec_level, second_key_id).unwrap();
+        let first_key = get_rkpd_attestation_key(DEFAULT_RPC_SERVICE_NAME, first_key_id).unwrap();
+        let second_key = get_rkpd_attestation_key(DEFAULT_RPC_SERVICE_NAME, second_key_id).unwrap();
 
         assert_ne!(first_key.keyBlob, second_key.keyBlob);
         assert_ne!(first_key.encodedCertChain, second_key.encodedCertChain);
@@ -639,81 +610,24 @@
     //    test case.
     fn test_store_rkpd_attestation_key() {
         binder::ProcessState::start_thread_pool();
-        let sec_level = SecurityLevel::TRUSTED_ENVIRONMENT;
         let key_id = get_next_key_id();
-        let key = get_rkpd_attestation_key(&SecurityLevel::TRUSTED_ENVIRONMENT, key_id).unwrap();
+        let key = get_rkpd_attestation_key(DEFAULT_RPC_SERVICE_NAME, key_id).unwrap();
         let new_blob: [u8; 8] = rand::random();
 
-        assert!(store_rkpd_attestation_key(&sec_level, &key.keyBlob, &new_blob).is_ok());
+        assert!(
+            store_rkpd_attestation_key(DEFAULT_RPC_SERVICE_NAME, &key.keyBlob, &new_blob).is_ok()
+        );
 
-        let new_key =
-            get_rkpd_attestation_key(&SecurityLevel::TRUSTED_ENVIRONMENT, key_id).unwrap();
+        let new_key = get_rkpd_attestation_key(DEFAULT_RPC_SERVICE_NAME, 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!(
+            store_rkpd_attestation_key(DEFAULT_RPC_SERVICE_NAME, &new_blob, &key.keyBlob).is_ok()
+        );
         assert_eq!(new_key.keyBlob, new_blob);
     }
 
     #[test]
-    // This is a helper for a manual test. We want to check that after a system upgrade RKPD
-    // attestation keys can also be upgraded and stored again with RKPD. The steps are:
-    // 1. Run this test and check in stdout that no key upgrade happened.
-    // 2. Perform a system upgrade.
-    // 3. Run this test and check in stdout that key upgrade did happen.
-    //
-    // Note that this test must be run with that same UID every time. Running as root, i.e. UID 0,
-    // should do the trick. Also, use "--nocapture" flag to get stdout.
-    fn test_rkpd_attestation_key_upgrade() {
-        binder::ProcessState::start_thread_pool();
-        let security_level = SecurityLevel::TRUSTED_ENVIRONMENT;
-        let (keymint, _, _) = get_keymint_device(&security_level).unwrap();
-        let key_id = get_next_key_id();
-        let mut key_upgraded = false;
-
-        let key = get_rkpd_attestation_key(&security_level, key_id).unwrap();
-        assert!(!key.keyBlob.is_empty());
-        assert!(!key.encodedCertChain.is_empty());
-
-        upgrade_keyblob_if_required_with(
-            &*keymint,
-            &key.keyBlob,
-            /*upgrade_params=*/ &[],
-            /*km_op=*/
-            |blob| {
-                let params = vec![
-                    KeyParameter {
-                        tag: Tag::ALGORITHM,
-                        value: KeyParameterValue::Algorithm(Algorithm::AES),
-                    },
-                    KeyParameter { tag: Tag::KEY_SIZE, value: KeyParameterValue::Integer(128) },
-                ];
-                let attestation_key = AttestationKey {
-                    keyBlob: blob.to_vec(),
-                    attestKeyParams: vec![],
-                    issuerSubjectName: parse_subject_from_certificate(&key.encodedCertChain)
-                        .unwrap(),
-                };
-
-                map_km_error(keymint.generateKey(&params, Some(&attestation_key)))
-            },
-            /*new_blob_handler=*/
-            |new_blob| {
-                // This handler is only executed if a key upgrade was performed.
-                key_upgraded = true;
-                store_rkpd_attestation_key(&security_level, &key.keyBlob, new_blob).unwrap();
-                Ok(())
-            },
-        )
-        .unwrap();
-
-        if key_upgraded {
-            println!("RKPD key was upgraded and stored with RKPD.");
-        } else {
-            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();
@@ -724,8 +638,7 @@
         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();
+                    let key = get_rkpd_attestation_key(DEFAULT_RPC_SERVICE_NAME, key_id).unwrap();
                     assert!(!key.keyBlob.is_empty());
                     assert!(!key.encodedCertChain.is_empty());
                 }
diff --git a/keystore2/src/security_level.rs b/keystore2/src/security_level.rs
index db44d4b..830fbe1 100644
--- a/keystore2/src/security_level.rs
+++ b/keystore2/src/security_level.rs
@@ -20,7 +20,9 @@
 };
 use crate::database::{BlobInfo, CertificateInfo, KeyIdGuard};
 use crate::error::{self, map_km_error, map_or_log_err, Error, ErrorCode};
-use crate::globals::{DB, ENFORCEMENTS, LEGACY_IMPORTER, SUPER_KEY};
+use crate::globals::{
+    get_remotely_provisioned_component_name, DB, ENFORCEMENTS, LEGACY_IMPORTER, SUPER_KEY,
+};
 use crate::key_parameter::KeyParameter as KsKeyParam;
 use crate::key_parameter::KeyParameterValue as KsKeyParamValue;
 use crate::ks_err;
@@ -247,7 +249,7 @@
                 let super_key = SUPER_KEY
                     .read()
                     .unwrap()
-                    .get_per_boot_key_by_user_id(uid_to_android_user(caller_uid));
+                    .get_after_first_unlock_key_by_user_id(uid_to_android_user(caller_uid));
                 let (key_id_guard, mut key_entry) = DB
                     .with::<_, Result<(KeyIdGuard, KeyEntry)>>(|db| {
                         LEGACY_IMPORTER.with_try_import(key, caller_uid, super_key, || {
@@ -317,7 +319,6 @@
 
         let (begin_result, upgraded_blob) = self
             .upgrade_keyblob_if_required_with(
-                &*self.keymint,
                 key_id_guard,
                 &km_blob,
                 blob_metadata.km_uuid().copied(),
@@ -561,7 +562,6 @@
                 issuer_subject,
             }) => self
                 .upgrade_keyblob_if_required_with(
-                    &*self.keymint,
                     Some(key_id_guard),
                     &KeyBlob::Ref(&blob),
                     blob_metadata.km_uuid().copied(),
@@ -735,7 +735,7 @@
         // Import_wrapped_key requires the rebind permission for the new key.
         check_key_permission(KeyPerm::Rebind, &key, &None).context(ks_err!())?;
 
-        let super_key = SUPER_KEY.read().unwrap().get_per_boot_key_by_user_id(user_id);
+        let super_key = SUPER_KEY.read().unwrap().get_after_first_unlock_key_by_user_id(user_id);
 
         let (wrapping_key_id_guard, mut wrapping_key_entry) = DB
             .with(|db| {
@@ -786,7 +786,6 @@
 
         let (creation_result, _) = self
             .upgrade_keyblob_if_required_with(
-                &*self.keymint,
                 Some(wrapping_key_id_guard),
                 &wrapping_key_blob,
                 wrapping_blob_metadata.km_uuid().copied(),
@@ -842,7 +841,6 @@
 
     fn upgrade_keyblob_if_required_with<T, F>(
         &self,
-        km_dev: &dyn IKeyMintDevice,
         mut key_id_guard: Option<KeyIdGuard>,
         key_blob: &KeyBlob,
         km_uuid: Option<Uuid>,
@@ -853,7 +851,8 @@
         F: Fn(&[u8]) -> Result<T, Error>,
     {
         let (v, upgraded_blob) = crate::utils::upgrade_keyblob_if_required_with(
-            km_dev,
+            &*self.keymint,
+            self.hw_info.versionNumber,
             key_blob,
             params,
             f,
@@ -891,13 +890,17 @@
     where
         F: Fn(&[u8]) -> Result<T, Error>,
     {
+        let rpc_name = get_remotely_provisioned_component_name(&self.security_level)
+            .context(ks_err!("Trying to get IRPC name."))?;
         crate::utils::upgrade_keyblob_if_required_with(
             &*self.keymint,
+            self.hw_info.versionNumber,
             key_blob,
             params,
             f,
             |upgraded_blob| {
-                store_rkpd_attestation_key(&self.security_level, key_blob, upgraded_blob)
+                let _wp = wd::watch_millis("Calling store_rkpd_attestation_key()", 500);
+                store_rkpd_attestation_key(&rpc_name, key_blob, upgraded_blob)
                     .context(ks_err!("Failed store_rkpd_attestation_key()."))
             },
         )
@@ -1059,3 +1062,83 @@
         map_or_log_err(result, Ok)
     }
 }
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use crate::error::map_km_error;
+    use crate::globals::get_keymint_device;
+    use crate::rkpd_client::{get_rkpd_attestation_key, store_rkpd_attestation_key};
+    use crate::utils::upgrade_keyblob_if_required_with;
+    use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
+        Algorithm::Algorithm, AttestationKey::AttestationKey, KeyParameter::KeyParameter,
+        KeyParameterValue::KeyParameterValue, Tag::Tag,
+    };
+    use keystore2_crypto::parse_subject_from_certificate;
+
+    #[test]
+    // This is a helper for a manual test. We want to check that after a system upgrade RKPD
+    // attestation keys can also be upgraded and stored again with RKPD. The steps are:
+    // 1. Run this test and check in stdout that no key upgrade happened.
+    // 2. Perform a system upgrade.
+    // 3. Run this test and check in stdout that key upgrade did happen.
+    //
+    // Note that this test must be run with that same UID every time. Running as root, i.e. UID 0,
+    // should do the trick. Also, use "--nocapture" flag to get stdout.
+    fn test_rkpd_attestation_key_upgrade() {
+        binder::ProcessState::start_thread_pool();
+        let security_level = SecurityLevel::TRUSTED_ENVIRONMENT;
+        let (keymint, info, _) = get_keymint_device(&security_level).unwrap();
+        let key_id = 0;
+        let mut key_upgraded = false;
+
+        let rpc_name = get_remotely_provisioned_component_name(&security_level).unwrap();
+        let key = get_rkpd_attestation_key(&rpc_name, key_id).unwrap();
+        assert!(!key.keyBlob.is_empty());
+        assert!(!key.encodedCertChain.is_empty());
+
+        upgrade_keyblob_if_required_with(
+            &*keymint,
+            info.versionNumber,
+            &key.keyBlob,
+            /*upgrade_params=*/ &[],
+            /*km_op=*/
+            |blob| {
+                let params = vec![
+                    KeyParameter {
+                        tag: Tag::ALGORITHM,
+                        value: KeyParameterValue::Algorithm(Algorithm::AES),
+                    },
+                    KeyParameter {
+                        tag: Tag::ATTESTATION_CHALLENGE,
+                        value: KeyParameterValue::Blob(vec![0; 16]),
+                    },
+                    KeyParameter { tag: Tag::KEY_SIZE, value: KeyParameterValue::Integer(128) },
+                ];
+                let attestation_key = AttestationKey {
+                    keyBlob: blob.to_vec(),
+                    attestKeyParams: vec![],
+                    issuerSubjectName: parse_subject_from_certificate(&key.encodedCertChain)
+                        .unwrap(),
+                };
+
+                map_km_error(keymint.generateKey(&params, Some(&attestation_key)))
+            },
+            /*new_blob_handler=*/
+            |new_blob| {
+                // This handler is only executed if a key upgrade was performed.
+                key_upgraded = true;
+                let _wp = wd::watch_millis("Calling store_rkpd_attestation_key()", 500);
+                store_rkpd_attestation_key(&rpc_name, &key.keyBlob, new_blob).unwrap();
+                Ok(())
+            },
+        )
+        .unwrap();
+
+        if key_upgraded {
+            println!("RKPD key was upgraded and stored with RKPD.");
+        } else {
+            println!("RKPD key was NOT upgraded.");
+        }
+    }
+}
diff --git a/keystore2/src/service.rs b/keystore2/src/service.rs
index 7ba8cbc..1459254 100644
--- a/keystore2/src/service.rs
+++ b/keystore2/src/service.rs
@@ -126,8 +126,10 @@
     fn get_key_entry(&self, key: &KeyDescriptor) -> Result<KeyEntryResponse> {
         let caller_uid = ThreadState::get_calling_uid();
 
-        let super_key =
-            SUPER_KEY.read().unwrap().get_per_boot_key_by_user_id(uid_to_android_user(caller_uid));
+        let super_key = SUPER_KEY
+            .read()
+            .unwrap()
+            .get_after_first_unlock_key_by_user_id(uid_to_android_user(caller_uid));
 
         let (key_id_guard, mut key_entry) = DB
             .with(|db| {
@@ -181,8 +183,10 @@
         certificate_chain: Option<&[u8]>,
     ) -> Result<()> {
         let caller_uid = ThreadState::get_calling_uid();
-        let super_key =
-            SUPER_KEY.read().unwrap().get_per_boot_key_by_user_id(uid_to_android_user(caller_uid));
+        let super_key = SUPER_KEY
+            .read()
+            .unwrap()
+            .get_after_first_unlock_key_by_user_id(uid_to_android_user(caller_uid));
 
         DB.with::<_, Result<()>>(|db| {
             let entry = match LEGACY_IMPORTER.with_try_import(key, caller_uid, super_key, || {
@@ -315,8 +319,10 @@
 
     fn delete_key(&self, key: &KeyDescriptor) -> Result<()> {
         let caller_uid = ThreadState::get_calling_uid();
-        let super_key =
-            SUPER_KEY.read().unwrap().get_per_boot_key_by_user_id(uid_to_android_user(caller_uid));
+        let super_key = SUPER_KEY
+            .read()
+            .unwrap()
+            .get_after_first_unlock_key_by_user_id(uid_to_android_user(caller_uid));
 
         DB.with(|db| {
             LEGACY_IMPORTER.with_try_import(key, caller_uid, super_key, || {
@@ -337,8 +343,10 @@
         access_vector: permission::KeyPermSet,
     ) -> Result<KeyDescriptor> {
         let caller_uid = ThreadState::get_calling_uid();
-        let super_key =
-            SUPER_KEY.read().unwrap().get_per_boot_key_by_user_id(uid_to_android_user(caller_uid));
+        let super_key = SUPER_KEY
+            .read()
+            .unwrap()
+            .get_after_first_unlock_key_by_user_id(uid_to_android_user(caller_uid));
 
         DB.with(|db| {
             LEGACY_IMPORTER.with_try_import(key, caller_uid, super_key, || {
diff --git a/keystore2/src/super_key.rs b/keystore2/src/super_key.rs
index 7fc3ed4..898a8c2 100644
--- a/keystore2/src/super_key.rs
+++ b/keystore2/src/super_key.rs
@@ -78,25 +78,35 @@
     pub alias: &'a str,
     /// Encryption algorithm
     pub algorithm: SuperEncryptionAlgorithm,
+    /// What to call this key in log messages. Not used for anything else.
+    pub name: &'a str,
 }
 
-/// Key used for LskfLocked keys; the corresponding superencryption key is loaded in memory
-/// when the user first unlocks, and remains in memory until the device reboots.
-pub const USER_SUPER_KEY: SuperKeyType =
-    SuperKeyType { alias: "USER_SUPER_KEY", algorithm: SuperEncryptionAlgorithm::Aes256Gcm };
-/// Key used for ScreenLockBound keys; the corresponding superencryption key is loaded in memory
-/// each time the user enters their LSKF, and cleared from memory each time the device is locked.
-/// Symmetric.
-pub const USER_SCREEN_LOCK_BOUND_KEY: SuperKeyType = SuperKeyType {
+/// The user's AfterFirstUnlock super key. This super key is loaded into memory when the user first
+/// unlocks the device, and it remains in memory until the device reboots. This is used to encrypt
+/// keys that require user authentication but not an unlocked device.
+pub const USER_AFTER_FIRST_UNLOCK_SUPER_KEY: SuperKeyType = SuperKeyType {
+    alias: "USER_SUPER_KEY",
+    algorithm: SuperEncryptionAlgorithm::Aes256Gcm,
+    name: "AfterFirstUnlock super key",
+};
+
+/// The user's UnlockedDeviceRequired symmetric super key. This super key is loaded into memory each
+/// time the user unlocks the device, and it is cleared from memory each time the user locks the
+/// device. This is used to encrypt keys that use the UnlockedDeviceRequired key parameter.
+pub const USER_UNLOCKED_DEVICE_REQUIRED_SYMMETRIC_SUPER_KEY: SuperKeyType = SuperKeyType {
     alias: "USER_SCREEN_LOCK_BOUND_KEY",
     algorithm: SuperEncryptionAlgorithm::Aes256Gcm,
+    name: "UnlockedDeviceRequired symmetric super key",
 };
-/// Key used for ScreenLockBound keys; the corresponding superencryption key is loaded in memory
-/// each time the user enters their LSKF, and cleared from memory each time the device is locked.
-/// Asymmetric, so keys can be encrypted when the device is locked.
-pub const USER_SCREEN_LOCK_BOUND_P521_KEY: SuperKeyType = SuperKeyType {
+
+/// The user's UnlockedDeviceRequired asymmetric super key. This is used to allow, while the device
+/// is locked, the creation of keys that use the UnlockedDeviceRequired key parameter. The private
+/// part of this key is loaded and cleared when the symmetric key is loaded and cleared.
+pub const USER_UNLOCKED_DEVICE_REQUIRED_P521_SUPER_KEY: SuperKeyType = SuperKeyType {
     alias: "USER_SCREEN_LOCK_BOUND_P521_KEY",
     algorithm: SuperEncryptionAlgorithm::EcdhP521,
+    name: "UnlockedDeviceRequired asymmetric super key",
 };
 
 /// Superencryption to apply to a new key.
@@ -104,10 +114,10 @@
 pub enum SuperEncryptionType {
     /// Do not superencrypt this key.
     None,
-    /// Superencrypt with a key that remains in memory from first unlock to reboot.
-    LskfBound,
-    /// Superencrypt with a key cleared from memory when the device is locked.
-    ScreenLockBound,
+    /// Superencrypt with the AfterFirstUnlock super key.
+    AfterFirstUnlock,
+    /// Superencrypt with an UnlockedDeviceRequired super key.
+    UnlockedDeviceRequired,
     /// Superencrypt with a key based on the desired boot level
     BootLevel(i32),
 }
@@ -224,33 +234,32 @@
     }
 }
 
-/// Keys for unlocking UNLOCKED_DEVICE_REQUIRED keys, as LockedKeys, complete with
-/// a database descriptor for the encrypting key and the sids for the auth tokens
-/// that can be used to decrypt it.
+/// A user's UnlockedDeviceRequired super keys, encrypted with a biometric-bound key, and
+/// information about that biometric-bound key.
 struct BiometricUnlock {
-    /// List of auth token SIDs that can be used to unlock these keys.
+    /// List of auth token SIDs that are accepted by the encrypting biometric-bound key.
     sids: Vec<i64>,
-    /// Database descriptor of key to use to unlock.
+    /// Key descriptor of the encrypting biometric-bound key.
     key_desc: KeyDescriptor,
-    /// Locked versions of the matching UserSuperKeys fields
-    screen_lock_bound: LockedKey,
-    screen_lock_bound_private: LockedKey,
+    /// The UnlockedDeviceRequired super keys, encrypted with a biometric-bound key.
+    symmetric: LockedKey,
+    private: LockedKey,
 }
 
 #[derive(Default)]
 struct UserSuperKeys {
-    /// The per boot key is used for LSKF binding of authentication bound keys. There is one
-    /// key per android user. The key is stored on flash encrypted with a key derived from a
-    /// secret, that is itself derived from the user's lock screen knowledge factor (LSKF).
-    /// When the user unlocks the device for the first time, this key is unlocked, i.e., decrypted,
-    /// and stays memory resident until the device reboots.
-    per_boot: Option<Arc<SuperKey>>,
-    /// The screen lock key works like the per boot key with the distinction that it is cleared
-    /// from memory when the screen lock is engaged.
-    screen_lock_bound: Option<Arc<SuperKey>>,
-    /// When the device is locked, screen-lock-bound keys can still be encrypted, using
-    /// ECDH public-key encryption. This field holds the decryption private key.
-    screen_lock_bound_private: Option<Arc<SuperKey>>,
+    /// The AfterFirstUnlock super key is used for LSKF binding of authentication bound keys. There
+    /// is one key per android user. The key is stored on flash encrypted with a key derived from a
+    /// secret, that is itself derived from the user's lock screen knowledge factor (LSKF). When the
+    /// user unlocks the device for the first time, this key is unlocked, i.e., decrypted, and stays
+    /// memory resident until the device reboots.
+    after_first_unlock: Option<Arc<SuperKey>>,
+    /// The UnlockedDeviceRequired symmetric super key works like the AfterFirstUnlock super key
+    /// with the distinction that it is cleared from memory when the device is locked.
+    unlocked_device_required_symmetric: Option<Arc<SuperKey>>,
+    /// When the device is locked, keys that use the UnlockedDeviceRequired key parameter can still
+    /// be created, using ECDH public-key encryption. This field holds the decryption private key.
+    unlocked_device_required_private: Option<Arc<SuperKey>>,
     /// Versions of the above two keys, locked behind a biometric.
     biometric_unlock: Option<BiometricUnlock>,
 }
@@ -351,7 +360,7 @@
         self.data.user_keys.remove(&user);
     }
 
-    fn install_per_boot_key_for_user(
+    fn install_after_first_unlock_key_for_user(
         &mut self,
         user: UserId,
         super_key: Arc<SuperKey>,
@@ -359,7 +368,7 @@
         self.data
             .add_key_to_key_index(&super_key)
             .context(ks_err!("add_key_to_key_index failed"))?;
-        self.data.user_keys.entry(user).or_default().per_boot = Some(super_key);
+        self.data.user_keys.entry(user).or_default().after_first_unlock = Some(super_key);
         Ok(())
     }
 
@@ -387,16 +396,21 @@
         })
     }
 
-    pub fn get_per_boot_key_by_user_id(
+    /// Returns the AfterFirstUnlock superencryption key for the given user ID, or None if the user
+    /// has not yet unlocked the device since boot.
+    pub fn get_after_first_unlock_key_by_user_id(
         &self,
         user_id: UserId,
     ) -> Option<Arc<dyn AesGcm + Send + Sync>> {
-        self.get_per_boot_key_by_user_id_internal(user_id)
+        self.get_after_first_unlock_key_by_user_id_internal(user_id)
             .map(|sk| -> Arc<dyn AesGcm + Send + Sync> { sk })
     }
 
-    fn get_per_boot_key_by_user_id_internal(&self, user_id: UserId) -> Option<Arc<SuperKey>> {
-        self.data.user_keys.get(&user_id).and_then(|e| e.per_boot.as_ref().cloned())
+    fn get_after_first_unlock_key_by_user_id_internal(
+        &self,
+        user_id: UserId,
+    ) -> Option<Arc<SuperKey>> {
+        self.data.user_keys.get(&user_id).and_then(|e| e.after_first_unlock.as_ref().cloned())
     }
 
     /// Check if a given key is super-encrypted, from its metadata. If so, unwrap the key using
@@ -470,7 +484,12 @@
         user_id: UserId,
     ) -> Result<bool> {
         let key_in_db = db
-            .key_exists(Domain::APP, user_id as u64 as i64, USER_SUPER_KEY.alias, KeyType::Super)
+            .key_exists(
+                Domain::APP,
+                user_id as u64 as i64,
+                USER_AFTER_FIRST_UNLOCK_SUPER_KEY.alias,
+                KeyType::Super,
+            )
             .context(ks_err!())?;
 
         if key_in_db {
@@ -490,8 +509,8 @@
     ) -> Result<Arc<SuperKey>> {
         let super_key = Self::extract_super_key_from_key_entry(algorithm, entry, pw, None)
             .context(ks_err!("Failed to extract super key from key entry"))?;
-        self.install_per_boot_key_for_user(user_id, super_key.clone())
-            .context(ks_err!("Failed to install per boot key for user!"))?;
+        self.install_after_first_unlock_key_for_user(user_id, super_key.clone())
+            .context(ks_err!("Failed to install AfterFirstUnlock super key for user!"))?;
         Ok(super_key)
     }
 
@@ -588,7 +607,8 @@
     // the KeystoreDB and encrypts the key_blob using ECDH encryption and marks the keyblob to be
     // re-encrypted with the symmetric super key on the first use.
     //
-    // This hybrid scheme allows lock-screen-bound keys to be added when the screen is locked.
+    // This hybrid scheme allows keys that use the UnlockedDeviceRequired key parameter to be
+    // created while the device is locked.
     fn encrypt_with_hybrid_super_key(
         key_blob: &[u8],
         symmetric_key: Option<&SuperKey>,
@@ -597,8 +617,9 @@
         user_id: UserId,
     ) -> Result<(Vec<u8>, BlobMetaData)> {
         if let Some(super_key) = symmetric_key {
-            Self::encrypt_with_aes_super_key(key_blob, super_key)
-                .context(ks_err!("Failed to encrypt with ScreenLockBound super key."))
+            Self::encrypt_with_aes_super_key(key_blob, super_key).context(ks_err!(
+                "Failed to encrypt with UnlockedDeviceRequired symmetric super key."
+            ))
         } else {
             // Symmetric key is not available, use public key encryption
             let loaded = db
@@ -639,39 +660,40 @@
     ) -> Result<(Vec<u8>, BlobMetaData)> {
         match Enforcements::super_encryption_required(domain, key_parameters, flags) {
             SuperEncryptionType::None => Ok((key_blob.to_vec(), BlobMetaData::new())),
-            SuperEncryptionType::LskfBound => {
-                // Encrypt the given key blob with the user's per-boot super key.  If the per-boot
-                // super key is not unlocked or the LSKF is not setup, an error is returned.
+            SuperEncryptionType::AfterFirstUnlock => {
+                // Encrypt the given key blob with the user's AfterFirstUnlock super key. If the
+                // user has not unlocked the device since boot or has no LSKF, an error is returned.
                 match self
                     .get_user_state(db, legacy_importer, user_id)
-                    .context(ks_err!("Failed to get user state."))?
+                    .context(ks_err!("Failed to get user state for user {user_id}"))?
                 {
-                    UserState::LskfUnlocked(super_key) => {
-                        Self::encrypt_with_aes_super_key(key_blob, &super_key)
-                            .context(ks_err!("Failed to encrypt with LskfBound key."))
+                    UserState::AfterFirstUnlock(super_key) => {
+                        Self::encrypt_with_aes_super_key(key_blob, &super_key).context(ks_err!(
+                            "Failed to encrypt with AfterFirstUnlock super key for user {user_id}"
+                        ))
                     }
-                    UserState::LskfLocked => {
+                    UserState::BeforeFirstUnlock => {
                         Err(Error::Rc(ResponseCode::LOCKED)).context(ks_err!("Device is locked."))
                     }
                     UserState::Uninitialized => Err(Error::Rc(ResponseCode::UNINITIALIZED))
-                        .context(ks_err!("LSKF is not setup for the user.")),
+                        .context(ks_err!("LSKF is not setup for user {user_id}")),
                 }
             }
-            SuperEncryptionType::ScreenLockBound => {
-                let screen_lock_bound_symmetric_key = self
+            SuperEncryptionType::UnlockedDeviceRequired => {
+                let symmetric_key = self
                     .data
                     .user_keys
                     .get(&user_id)
-                    .and_then(|e| e.screen_lock_bound.as_ref())
+                    .and_then(|e| e.unlocked_device_required_symmetric.as_ref())
                     .map(|arc| arc.as_ref());
                 Self::encrypt_with_hybrid_super_key(
                     key_blob,
-                    screen_lock_bound_symmetric_key,
-                    &USER_SCREEN_LOCK_BOUND_P521_KEY,
+                    symmetric_key,
+                    &USER_UNLOCKED_DEVICE_REQUIRED_P521_SUPER_KEY,
                     db,
                     user_id,
                 )
-                .context(ks_err!("Failed to encrypt with ScreenLockBound hybrid scheme."))
+                .context(ks_err!("Failed to encrypt with UnlockedDeviceRequired hybrid scheme."))
             }
             SuperEncryptionType::BootLevel(level) => {
                 let key_id = SuperKeyIdentifier::BootLevel(level);
@@ -704,6 +726,47 @@
         }
     }
 
+    fn create_super_key(
+        &mut self,
+        db: &mut KeystoreDB,
+        user_id: UserId,
+        key_type: &SuperKeyType,
+        password: &Password,
+        reencrypt_with: Option<Arc<SuperKey>>,
+    ) -> Result<Arc<SuperKey>> {
+        log::info!("Creating {} for user {}", key_type.name, user_id);
+        let (super_key, public_key) = match key_type.algorithm {
+            SuperEncryptionAlgorithm::Aes256Gcm => {
+                (generate_aes256_key().context(ks_err!("Failed to generate AES-256 key."))?, None)
+            }
+            SuperEncryptionAlgorithm::EcdhP521 => {
+                let key =
+                    ECDHPrivateKey::generate().context(ks_err!("Failed to generate ECDH key"))?;
+                (
+                    key.private_key().context(ks_err!("private_key failed"))?,
+                    Some(key.public_key().context(ks_err!("public_key failed"))?),
+                )
+            }
+        };
+        // Derive an AES-256 key from the password and re-encrypt the super key before we insert it
+        // in the database.
+        let (encrypted_super_key, blob_metadata) =
+            Self::encrypt_with_password(&super_key, password).context(ks_err!())?;
+        let mut key_metadata = KeyMetaData::new();
+        if let Some(pk) = public_key {
+            key_metadata.add(KeyMetaEntry::Sec1PublicKey(pk));
+        }
+        let key_entry = db
+            .store_super_key(user_id, key_type, &encrypted_super_key, &blob_metadata, &key_metadata)
+            .context(ks_err!("Failed to store super key."))?;
+        Ok(Arc::new(SuperKey {
+            algorithm: key_type.algorithm,
+            key: super_key,
+            id: SuperKeyIdentifier::DatabaseId(key_entry.id()),
+            reencrypt_with,
+        }))
+    }
+
     /// Fetch a superencryption key from the database, or create it if it doesn't already exist.
     /// When this is called, the caller must hold the lock on the SuperKeyManager.
     /// So it's OK that the check and creation are different DB transactions.
@@ -724,83 +787,59 @@
                 reencrypt_with,
             )?)
         } else {
-            let (super_key, public_key) = match key_type.algorithm {
-                SuperEncryptionAlgorithm::Aes256Gcm => (
-                    generate_aes256_key().context(ks_err!("Failed to generate AES 256 key."))?,
-                    None,
-                ),
-                SuperEncryptionAlgorithm::EcdhP521 => {
-                    let key = ECDHPrivateKey::generate()
-                        .context(ks_err!("Failed to generate ECDH key"))?;
-                    (
-                        key.private_key().context(ks_err!("private_key failed"))?,
-                        Some(key.public_key().context(ks_err!("public_key failed"))?),
-                    )
-                }
-            };
-            // Derive an AES256 key from the password and re-encrypt the super key
-            // before we insert it in the database.
-            let (encrypted_super_key, blob_metadata) =
-                Self::encrypt_with_password(&super_key, password).context(ks_err!())?;
-            let mut key_metadata = KeyMetaData::new();
-            if let Some(pk) = public_key {
-                key_metadata.add(KeyMetaEntry::Sec1PublicKey(pk));
-            }
-            let key_entry = db
-                .store_super_key(
-                    user_id,
-                    key_type,
-                    &encrypted_super_key,
-                    &blob_metadata,
-                    &key_metadata,
-                )
-                .context(ks_err!("Failed to store super key."))?;
-            Ok(Arc::new(SuperKey {
-                algorithm: key_type.algorithm,
-                key: super_key,
-                id: SuperKeyIdentifier::DatabaseId(key_entry.id()),
-                reencrypt_with,
-            }))
+            self.create_super_key(db, user_id, key_type, password, reencrypt_with)
         }
     }
 
-    /// Decrypt the screen-lock bound keys for this user using the password and store in memory.
-    pub fn unlock_screen_lock_bound_key(
+    /// Decrypt the UnlockedDeviceRequired super keys for this user using the password and store
+    /// them in memory. If these keys don't exist yet, create them.
+    pub fn unlock_unlocked_device_required_keys(
         &mut self,
         db: &mut KeystoreDB,
         user_id: UserId,
         password: &Password,
     ) -> Result<()> {
-        let (screen_lock_bound, screen_lock_bound_private) = self
+        let (symmetric, private) = self
             .data
             .user_keys
             .get(&user_id)
-            .map(|e| (e.screen_lock_bound.clone(), e.screen_lock_bound_private.clone()))
+            .map(|e| {
+                (
+                    e.unlocked_device_required_symmetric.clone(),
+                    e.unlocked_device_required_private.clone(),
+                )
+            })
             .unwrap_or((None, None));
 
-        if screen_lock_bound.is_some() && screen_lock_bound_private.is_some() {
+        if symmetric.is_some() && private.is_some() {
             // Already unlocked.
             return Ok(());
         }
 
-        let aes = if let Some(screen_lock_bound) = screen_lock_bound {
-            // This is weird. If this point is reached only one of the screen locked keys was
-            // initialized. This should never happen.
-            screen_lock_bound
-        } else {
-            self.get_or_create_super_key(db, user_id, &USER_SCREEN_LOCK_BOUND_KEY, password, None)
-                .context(ks_err!("Trying to get or create symmetric key."))?
-        };
-
-        let ecdh = if let Some(screen_lock_bound_private) = screen_lock_bound_private {
-            // This is weird. If this point is reached only one of the screen locked keys was
-            // initialized. This should never happen.
-            screen_lock_bound_private
+        let aes = if let Some(symmetric) = symmetric {
+            // This is weird. If this point is reached only one of the UnlockedDeviceRequired super
+            // keys was initialized. This should never happen.
+            symmetric
         } else {
             self.get_or_create_super_key(
                 db,
                 user_id,
-                &USER_SCREEN_LOCK_BOUND_P521_KEY,
+                &USER_UNLOCKED_DEVICE_REQUIRED_SYMMETRIC_SUPER_KEY,
+                password,
+                None,
+            )
+            .context(ks_err!("Trying to get or create symmetric key."))?
+        };
+
+        let ecdh = if let Some(private) = private {
+            // This is weird. If this point is reached only one of the UnlockedDeviceRequired super
+            // keys was initialized. This should never happen.
+            private
+        } else {
+            self.get_or_create_super_key(
+                db,
+                user_id,
+                &USER_UNLOCKED_DEVICE_REQUIRED_P521_SUPER_KEY,
                 password,
                 Some(aes.clone()),
             )
@@ -810,24 +849,28 @@
         self.data.add_key_to_key_index(&aes)?;
         self.data.add_key_to_key_index(&ecdh)?;
         let entry = self.data.user_keys.entry(user_id).or_default();
-        entry.screen_lock_bound = Some(aes);
-        entry.screen_lock_bound_private = Some(ecdh);
+        entry.unlocked_device_required_symmetric = Some(aes);
+        entry.unlocked_device_required_private = Some(ecdh);
         Ok(())
     }
 
-    /// Wipe the screen-lock bound keys for this user from memory.
-    pub fn lock_screen_lock_bound_key(
+    /// Wipe the user's UnlockedDeviceRequired super keys from memory.
+    pub fn lock_unlocked_device_required_keys(
         &mut self,
         db: &mut KeystoreDB,
         user_id: UserId,
         unlocking_sids: &[i64],
     ) {
-        log::info!("Locking screen bound for user {} sids {:?}", user_id, unlocking_sids);
+        log::info!(
+            "Locking UnlockedDeviceRequired super keys for user {}; unlocking_sids={:?}",
+            user_id,
+            unlocking_sids
+        );
         let entry = self.data.user_keys.entry(user_id).or_default();
         if !unlocking_sids.is_empty() {
             if let (Some(aes), Some(ecdh)) = (
-                entry.screen_lock_bound.as_ref().cloned(),
-                entry.screen_lock_bound_private.as_ref().cloned(),
+                entry.unlocked_device_required_symmetric.as_ref().cloned(),
+                entry.unlocked_device_required_private.as_ref().cloned(),
             ) {
                 let res = (|| -> Result<()> {
                     let key_desc = KeyMintDevice::internal_descriptor(format!(
@@ -862,7 +905,7 @@
                         KeyType::Client, /* TODO Should be Super b/189470584 */
                         |dev| {
                             let _wp = wd::watch_millis(
-                                "In lock_screen_lock_bound_key: calling importKey.",
+                                "In lock_unlocked_device_required_keys: calling importKey.",
                                 500,
                             );
                             dev.importKey(
@@ -876,20 +919,20 @@
                     entry.biometric_unlock = Some(BiometricUnlock {
                         sids: unlocking_sids.into(),
                         key_desc,
-                        screen_lock_bound: LockedKey::new(&encrypting_key, &aes)?,
-                        screen_lock_bound_private: LockedKey::new(&encrypting_key, &ecdh)?,
+                        symmetric: LockedKey::new(&encrypting_key, &aes)?,
+                        private: LockedKey::new(&encrypting_key, &ecdh)?,
                     });
                     Ok(())
                 })();
-                // There is no reason to propagate an error here upwards. We must discard
-                // entry.screen_lock_bound* in any case.
+                // There is no reason to propagate an error here upwards. We must clear the keys
+                // from memory in any case.
                 if let Err(e) = res {
                     log::error!("Error setting up biometric unlock: {:#?}", e);
                 }
             }
         }
-        entry.screen_lock_bound = None;
-        entry.screen_lock_bound_private = None;
+        entry.unlocked_device_required_symmetric = None;
+        entry.unlocked_device_required_private = None;
     }
 
     /// User has unlocked, not using a password. See if any of our stored auth tokens can be used
@@ -912,12 +955,14 @@
                 .context(ks_err!("load_key_entry failed"))?;
             let km_dev: KeyMintDevice = KeyMintDevice::get(SecurityLevel::TRUSTED_ENVIRONMENT)
                 .context(ks_err!("KeyMintDevice::get failed"))?;
+            let mut errs = vec![];
             for sid in &biometric.sids {
+                let sid = *sid;
                 if let Some((auth_token_entry, _)) = db.find_auth_token_entry(|entry| {
-                    entry.auth_token().userId == *sid || entry.auth_token().authenticatorId == *sid
+                    entry.auth_token().userId == sid || entry.auth_token().authenticatorId == sid
                 }) {
                     let res: Result<(Arc<SuperKey>, Arc<SuperKey>)> = (|| {
-                        let slb = biometric.screen_lock_bound.decrypt(
+                        let symmetric = biometric.symmetric.decrypt(
                             db,
                             &km_dev,
                             &key_id_guard,
@@ -925,31 +970,38 @@
                             auth_token_entry.auth_token(),
                             None,
                         )?;
-                        let slbp = biometric.screen_lock_bound_private.decrypt(
+                        let private = biometric.private.decrypt(
                             db,
                             &km_dev,
                             &key_id_guard,
                             &key_entry,
                             auth_token_entry.auth_token(),
-                            Some(slb.clone()),
+                            Some(symmetric.clone()),
                         )?;
-                        Ok((slb, slbp))
+                        Ok((symmetric, private))
                     })();
                     match res {
-                        Ok((slb, slbp)) => {
-                            entry.screen_lock_bound = Some(slb.clone());
-                            entry.screen_lock_bound_private = Some(slbp.clone());
-                            self.data.add_key_to_key_index(&slb)?;
-                            self.data.add_key_to_key_index(&slbp)?;
-                            log::info!("Successfully unlocked with biometric");
+                        Ok((symmetric, private)) => {
+                            entry.unlocked_device_required_symmetric = Some(symmetric.clone());
+                            entry.unlocked_device_required_private = Some(private.clone());
+                            self.data.add_key_to_key_index(&symmetric)?;
+                            self.data.add_key_to_key_index(&private)?;
+                            log::info!("Successfully unlocked user {user_id} with biometric {sid}",);
                             return Ok(());
                         }
                         Err(e) => {
-                            log::warn!("attempt failed: {:?}", e)
+                            // Don't log an error yet, as some other biometric SID might work.
+                            errs.push((sid, e));
                         }
                     }
                 }
             }
+            if !errs.is_empty() {
+                log::warn!("biometric unlock failed for all SIDs, with errors:");
+                for (sid, err) in errs {
+                    log::warn!("  biometric {sid}: {err}");
+                }
+            }
         }
         Ok(())
     }
@@ -963,8 +1015,8 @@
         legacy_importer: &LegacyImporter,
         user_id: UserId,
     ) -> Result<UserState> {
-        match self.get_per_boot_key_by_user_id_internal(user_id) {
-            Some(super_key) => Ok(UserState::LskfUnlocked(super_key)),
+        match self.get_after_first_unlock_key_by_user_id_internal(user_id) {
+            Some(super_key) => Ok(UserState::AfterFirstUnlock(super_key)),
             None => {
                 // Check if a super key exists in the database or legacy database.
                 // If so, return locked user state.
@@ -972,7 +1024,7 @@
                     .super_key_exists_in_db_for_user(db, legacy_importer, user_id)
                     .context(ks_err!())?
                 {
-                    Ok(UserState::LskfLocked)
+                    Ok(UserState::BeforeFirstUnlock)
                 } else {
                     Ok(UserState::Uninitialized)
                 }
@@ -988,6 +1040,7 @@
         legacy_importer: &LegacyImporter,
         user_id: UserId,
     ) -> Result<()> {
+        log::info!("remove_user(user={user_id})");
         // Mark keys created on behalf of the user as unreferenced.
         legacy_importer
             .bulk_delete_user(user_id, false)
@@ -1008,14 +1061,15 @@
         legacy_importer: &LegacyImporter,
         user_id: UserId,
     ) -> Result<()> {
+        log::info!("reset_user(user={user_id})");
         match self.get_user_state(db, legacy_importer, user_id)? {
             UserState::Uninitialized => {
                 Err(Error::sys()).context(ks_err!("Tried to reset an uninitialized user!"))
             }
-            UserState::LskfLocked => {
+            UserState::BeforeFirstUnlock => {
                 Err(Error::sys()).context(ks_err!("Tried to reset a locked user's password!"))
             }
-            UserState::LskfUnlocked(_) => {
+            UserState::AfterFirstUnlock(_) => {
                 // Mark keys created on behalf of the user as unreferenced.
                 legacy_importer
                     .bulk_delete_user(user_id, true)
@@ -1030,8 +1084,9 @@
         }
     }
 
-    /// If the user hasn't been initialized yet, then this function generates the user's super keys
-    /// and sets the user's state to LskfUnlocked.  Otherwise this function returns an error.
+    /// If the user hasn't been initialized yet, then this function generates the user's
+    /// AfterFirstUnlock super key and sets the user's state to AfterFirstUnlock. Otherwise this
+    /// function returns an error.
     pub fn init_user(
         &mut self,
         db: &mut KeystoreDB,
@@ -1039,8 +1094,9 @@
         user_id: UserId,
         password: &Password,
     ) -> Result<()> {
+        log::info!("init_user(user={user_id})");
         match self.get_user_state(db, legacy_importer, user_id)? {
-            UserState::LskfUnlocked(_) | UserState::LskfLocked => {
+            UserState::AfterFirstUnlock(_) | UserState::BeforeFirstUnlock => {
                 Err(Error::sys()).context(ks_err!("Tried to re-init an initialized user!"))
             }
             UserState::Uninitialized => {
@@ -1056,7 +1112,7 @@
                 let key_entry = db
                     .store_super_key(
                         user_id,
-                        &USER_SUPER_KEY,
+                        &USER_AFTER_FIRST_UNLOCK_SUPER_KEY,
                         &encrypted_super_key,
                         &blob_metadata,
                         &KeyMetaData::new(),
@@ -1065,7 +1121,7 @@
 
                 self.populate_cache_from_super_key_blob(
                     user_id,
-                    USER_SUPER_KEY.algorithm,
+                    USER_AFTER_FIRST_UNLOCK_SUPER_KEY.algorithm,
                     key_entry,
                     password,
                 )
@@ -1077,12 +1133,12 @@
 
     /// Unlocks the given user with the given password.
     ///
-    /// If the user is LskfLocked:
-    /// - Unlock the per_boot super key
-    /// - Unlock the screen_lock_bound super key
+    /// If the user state is BeforeFirstUnlock:
+    /// - Unlock the user's AfterFirstUnlock super key
+    /// - Unlock the user's UnlockedDeviceRequired super keys
     ///
-    /// If the user is LskfUnlocked:
-    /// - Unlock the screen_lock_bound super key only
+    /// If the user state is AfterFirstUnlock:
+    /// - Unlock the user's UnlockedDeviceRequired super keys only
     ///
     pub fn unlock_user(
         &mut self,
@@ -1091,13 +1147,16 @@
         user_id: UserId,
         password: &Password,
     ) -> Result<()> {
+        log::info!("unlock_user(user={user_id})");
         match self.get_user_state(db, legacy_importer, user_id)? {
-            UserState::LskfUnlocked(_) => self.unlock_screen_lock_bound_key(db, user_id, password),
+            UserState::AfterFirstUnlock(_) => {
+                self.unlock_unlocked_device_required_keys(db, user_id, password)
+            }
             UserState::Uninitialized => {
                 Err(Error::sys()).context(ks_err!("Tried to unlock an uninitialized user!"))
             }
-            UserState::LskfLocked => {
-                let alias = &USER_SUPER_KEY;
+            UserState::BeforeFirstUnlock => {
+                let alias = &USER_AFTER_FIRST_UNLOCK_SUPER_KEY;
                 let result = legacy_importer
                     .with_try_import_super_key(user_id, password, || {
                         db.load_super_key(alias, user_id)
@@ -1113,7 +1172,7 @@
                             password,
                         )
                         .context(ks_err!("Failed when unlocking user."))?;
-                        self.unlock_screen_lock_bound_key(db, user_id, password)
+                        self.unlock_unlocked_device_required_keys(db, user_id, password)
                     }
                     None => {
                         Err(Error::sys()).context(ks_err!("Locked user does not have a super key!"))
@@ -1128,12 +1187,12 @@
 /// For now, only three states are defined. More states may be added later.
 pub enum UserState {
     // The user has registered LSKF and has unlocked the device by entering PIN/Password,
-    // and hence the per-boot super key is available in the cache.
-    LskfUnlocked(Arc<SuperKey>),
+    // and hence the AfterFirstUnlock super key is available in the cache.
+    AfterFirstUnlock(Arc<SuperKey>),
     // The user has registered LSKF, but has not unlocked the device using password, after reboot.
-    // Hence the per-boot super-key(s) is not available in the cache.
-    // However, the encrypted super key is available in the database.
-    LskfLocked,
+    // Hence the AfterFirstUnlock and UnlockedDeviceRequired super keys are not available in the
+    // cache. However, they exist in the database in encrypted form.
+    BeforeFirstUnlock,
     // There's no user in the device for the given user id, or the user with the user id has not
     // setup LSKF.
     Uninitialized,
@@ -1228,7 +1287,7 @@
         let user_state =
             skm.write().unwrap().get_user_state(keystore_db, legacy_importer, user_id).unwrap();
         match user_state {
-            UserState::LskfUnlocked(_) => {}
+            UserState::AfterFirstUnlock(_) => {}
             _ => panic!("{}", err_msg),
         }
     }
@@ -1243,7 +1302,7 @@
         let user_state =
             skm.write().unwrap().get_user_state(keystore_db, legacy_importer, user_id).unwrap();
         match user_state {
-            UserState::LskfLocked => {}
+            UserState::BeforeFirstUnlock => {}
             _ => panic!("{}", err_msg),
         }
     }
diff --git a/keystore2/src/sw_keyblob.rs b/keystore2/src/sw_keyblob.rs
new file mode 100644
index 0000000..11a9b41
--- /dev/null
+++ b/keystore2/src/sw_keyblob.rs
@@ -0,0 +1,812 @@
+// 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.
+
+//! Code for parsing software-backed keyblobs, as emitted by the C++ reference implementation of
+//! KeyMint.
+
+#![allow(dead_code)]
+
+use crate::error::Error;
+use crate::ks_err;
+use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
+    Algorithm::Algorithm, BlockMode::BlockMode, Digest::Digest, EcCurve::EcCurve,
+    ErrorCode::ErrorCode, HardwareAuthenticatorType::HardwareAuthenticatorType,
+    KeyFormat::KeyFormat, KeyOrigin::KeyOrigin, KeyParameter::KeyParameter,
+    KeyParameterValue::KeyParameterValue, KeyPurpose::KeyPurpose, PaddingMode::PaddingMode,
+    Tag::Tag, TagType::TagType,
+};
+use anyhow::Result;
+use keystore2_crypto::hmac_sha256;
+use std::mem::size_of;
+
+/// Root of trust value.
+const SOFTWARE_ROOT_OF_TRUST: &[u8] = b"SW";
+
+/// Error macro.
+macro_rules! bloberr {
+    { $($arg:tt)+ } => {
+        anyhow::Error::new(Error::Km(ErrorCode::INVALID_KEY_BLOB)).context(ks_err!($($arg)+))
+    };
+}
+
+/// Get the `KeyParameterValue` associated with a tag from a collection of `KeyParameter`s.
+fn get_tag_value(params: &[KeyParameter], tag: Tag) -> Option<&KeyParameterValue> {
+    params.iter().find_map(|kp| if kp.tag == tag { Some(&kp.value) } else { None })
+}
+
+/// Get the [`TagType`] for a [`Tag`].
+fn tag_type(tag: &Tag) -> TagType {
+    TagType((tag.0 as u32 & 0xf0000000) as i32)
+}
+
+/// Extract key material and combined key characteristics from a legacy authenticated keyblob.
+pub fn export_key(
+    data: &[u8],
+    params: &[KeyParameter],
+) -> Result<(KeyFormat, Vec<u8>, Vec<KeyParameter>)> {
+    let hidden = hidden_params(params, &[SOFTWARE_ROOT_OF_TRUST]);
+    let KeyBlob { key_material, hw_enforced, sw_enforced } =
+        KeyBlob::new_from_serialized(data, &hidden)?;
+
+    let mut combined = hw_enforced;
+    combined.extend_from_slice(&sw_enforced);
+
+    let algo_val =
+        get_tag_value(&combined, Tag::ALGORITHM).ok_or_else(|| bloberr!("No algorithm found!"))?;
+
+    let format = match algo_val {
+        KeyParameterValue::Algorithm(Algorithm::AES)
+        | KeyParameterValue::Algorithm(Algorithm::TRIPLE_DES)
+        | KeyParameterValue::Algorithm(Algorithm::HMAC) => KeyFormat::RAW,
+        KeyParameterValue::Algorithm(Algorithm::RSA)
+        | KeyParameterValue::Algorithm(Algorithm::EC) => KeyFormat::PKCS8,
+        _ => return Err(bloberr!("Unexpected algorithm {:?}", algo_val)),
+    };
+    Ok((format, key_material, combined))
+}
+
+/// Plaintext key blob, with key characteristics.
+#[derive(PartialEq, Eq)]
+struct KeyBlob {
+    /// Raw key material.
+    key_material: Vec<u8>,
+    /// Hardware-enforced key characteristics.
+    hw_enforced: Vec<KeyParameter>,
+    /// Software-enforced key characteristics.
+    sw_enforced: Vec<KeyParameter>,
+}
+
+impl KeyBlob {
+    /// Key blob version.
+    const KEY_BLOB_VERSION: u8 = 0;
+
+    /// Hard-coded HMAC key used for keyblob authentication.
+    const LEGACY_HMAC_KEY: &[u8] = b"IntegrityAssuredBlob0\0";
+
+    /// Size (in bytes) of appended MAC.
+    const MAC_LEN: usize = 8;
+
+    /// Parse a serialized [`KeyBlob`].
+    fn new_from_serialized(mut data: &[u8], hidden: &[KeyParameter]) -> Result<Self> {
+        // Keyblob needs to be at least long enough for:
+        // - version byte,
+        // - 4-byte len for key material
+        // - 4-byte len for hw_enforced params
+        // - 4-byte len for sw_enforced params
+        // - MAC tag.
+        if data.len() < (1 + 3 * size_of::<u32>() + Self::MAC_LEN) {
+            return Err(bloberr!("blob not long enough (len = {})", data.len()));
+        }
+
+        // Check the HMAC in the last 8 bytes before doing anything else.
+        let mac = &data[data.len() - Self::MAC_LEN..];
+        let computed_mac = Self::compute_hmac(&data[..data.len() - Self::MAC_LEN], hidden)?;
+        if mac != computed_mac {
+            return Err(bloberr!("invalid key blob"));
+        }
+
+        let version = consume_u8(&mut data)?;
+        if version != Self::KEY_BLOB_VERSION {
+            return Err(bloberr!("unexpected blob version {}", version));
+        }
+        let key_material = consume_vec(&mut data)?;
+        let hw_enforced = deserialize_params(&mut data)?;
+        let sw_enforced = deserialize_params(&mut data)?;
+
+        // Should just be the (already-checked) MAC left.
+        let rest = &data[Self::MAC_LEN..];
+        if !rest.is_empty() {
+            return Err(bloberr!("extra data (len {})", rest.len()));
+        }
+        Ok(KeyBlob { key_material, hw_enforced, sw_enforced })
+    }
+
+    /// Compute the authentication HMAC for a KeyBlob. This is built as:
+    ///   HMAC-SHA256(HK, data || serialize(hidden))
+    /// with HK = b"IntegrityAssuredBlob0\0".
+    fn compute_hmac(data: &[u8], hidden: &[KeyParameter]) -> Result<Vec<u8>> {
+        let hidden_data = serialize_params(hidden)?;
+        let mut combined = data.to_vec();
+        combined.extend_from_slice(&hidden_data);
+        let mut tag = hmac_sha256(Self::LEGACY_HMAC_KEY, &combined)?;
+        tag.truncate(Self::MAC_LEN);
+        Ok(tag)
+    }
+}
+
+/// Build the parameters that are used as the hidden input to HMAC calculations:
+/// - `ApplicationId(data)` if present
+/// - `ApplicationData(data)` if present
+/// - (repeated) `RootOfTrust(rot)` where `rot` is a hardcoded piece of root of trust information.
+fn hidden_params(params: &[KeyParameter], rots: &[&[u8]]) -> Vec<KeyParameter> {
+    let mut results = Vec::new();
+    if let Some(app_id) = get_tag_value(params, Tag::APPLICATION_ID) {
+        results.push(KeyParameter { tag: Tag::APPLICATION_ID, value: app_id.clone() });
+    }
+    if let Some(app_data) = get_tag_value(params, Tag::APPLICATION_DATA) {
+        results.push(KeyParameter { tag: Tag::APPLICATION_DATA, value: app_data.clone() });
+    }
+    for rot in rots {
+        results.push(KeyParameter {
+            tag: Tag::ROOT_OF_TRUST,
+            value: KeyParameterValue::Blob(rot.to_vec()),
+        });
+    }
+    results
+}
+
+/// Retrieve a `u8` from the start of the given slice, if possible.
+fn consume_u8(data: &mut &[u8]) -> Result<u8> {
+    match data.first() {
+        Some(b) => {
+            *data = &(*data)[1..];
+            Ok(*b)
+        }
+        None => Err(bloberr!("failed to find 1 byte")),
+    }
+}
+
+/// Move past a bool value from the start of the given slice, if possible.
+/// Bool values should only be included if `true`, so fail if the value
+/// is anything other than 1.
+fn consume_bool(data: &mut &[u8]) -> Result<bool> {
+    let b = consume_u8(data)?;
+    if b == 0x01 {
+        Ok(true)
+    } else {
+        Err(bloberr!("bool value other than 1 encountered"))
+    }
+}
+
+/// Retrieve a (host-ordered) `u32` from the start of the given slice, if possible.
+fn consume_u32(data: &mut &[u8]) -> Result<u32> {
+    const LEN: usize = size_of::<u32>();
+    if data.len() < LEN {
+        return Err(bloberr!("failed to find {LEN} bytes"));
+    }
+    let chunk: [u8; LEN] = data[..LEN].try_into().unwrap(); // safe: just checked
+    *data = &(*data)[LEN..];
+    Ok(u32::from_ne_bytes(chunk))
+}
+
+/// Retrieve a (host-ordered) `i32` from the start of the given slice, if possible.
+fn consume_i32(data: &mut &[u8]) -> Result<i32> {
+    const LEN: usize = size_of::<i32>();
+    if data.len() < LEN {
+        return Err(bloberr!("failed to find {LEN} bytes"));
+    }
+    let chunk: [u8; LEN] = data[..LEN].try_into().unwrap(); // safe: just checked
+    *data = &(*data)[4..];
+    Ok(i32::from_ne_bytes(chunk))
+}
+
+/// Retrieve a (host-ordered) `i64` from the start of the given slice, if possible.
+fn consume_i64(data: &mut &[u8]) -> Result<i64> {
+    const LEN: usize = size_of::<i64>();
+    if data.len() < LEN {
+        return Err(bloberr!("failed to find {LEN} bytes"));
+    }
+    let chunk: [u8; LEN] = data[..LEN].try_into().unwrap(); // safe: just checked
+    *data = &(*data)[LEN..];
+    Ok(i64::from_ne_bytes(chunk))
+}
+
+/// Retrieve a vector of bytes from the start of the given slice, if possible,
+/// with the length of the data expected to appear as a host-ordered `u32` prefix.
+fn consume_vec(data: &mut &[u8]) -> Result<Vec<u8>> {
+    let len = consume_u32(data)? as usize;
+    if len > data.len() {
+        return Err(bloberr!("failed to find {} bytes", len));
+    }
+    let result = data[..len].to_vec();
+    *data = &(*data)[len..];
+    Ok(result)
+}
+
+/// Retrieve the contents of a tag of `TagType::Bytes`.  The `data` parameter holds
+/// the as-yet unparsed data, and a length and offset are read from this (and consumed).
+/// This length and offset refer to a location in the combined `blob_data`; however,
+/// the offset is expected to be the next unconsumed chunk of `blob_data`, as indicated
+/// by `next_blob_offset` (which itself is updated as a result of consuming the data).
+fn consume_blob(
+    data: &mut &[u8],
+    next_blob_offset: &mut usize,
+    blob_data: &[u8],
+) -> Result<Vec<u8>> {
+    let data_len = consume_u32(data)? as usize;
+    let data_offset = consume_u32(data)? as usize;
+    // Expect the blob data to come from the next offset in the initial blob chunk.
+    if data_offset != *next_blob_offset {
+        return Err(bloberr!("got blob offset {} instead of {}", data_offset, next_blob_offset));
+    }
+    if (data_offset + data_len) > blob_data.len() {
+        return Err(bloberr!(
+            "blob at offset [{}..{}+{}] goes beyond blob data size {}",
+            data_offset,
+            data_offset,
+            data_len,
+            blob_data.len(),
+        ));
+    }
+
+    let slice = &blob_data[data_offset..data_offset + data_len];
+    *next_blob_offset += data_len;
+    Ok(slice.to_vec())
+}
+
+/// Deserialize a collection of [`KeyParam`]s in legacy serialized format. The provided slice is
+/// modified to contain the unconsumed part of the data.
+fn deserialize_params(data: &mut &[u8]) -> Result<Vec<KeyParameter>> {
+    let blob_data_size = consume_u32(data)? as usize;
+    if blob_data_size > data.len() {
+        return Err(bloberr!(
+            "blob data size {} bigger than data (len={})",
+            blob_data_size,
+            data.len()
+        ));
+    }
+
+    let blob_data = &data[..blob_data_size];
+    let mut next_blob_offset = 0;
+
+    // Move past the blob data.
+    *data = &data[blob_data_size..];
+
+    let param_count = consume_u32(data)? as usize;
+    let param_size = consume_u32(data)? as usize;
+    if param_size > data.len() {
+        return Err(bloberr!(
+            "size mismatch 4+{}+4+4+{} > {}",
+            blob_data_size,
+            param_size,
+            data.len()
+        ));
+    }
+
+    let mut results = Vec::new();
+    for _i in 0..param_count {
+        let tag_num = consume_u32(data)? as i32;
+        let tag = Tag(tag_num);
+        let value = match tag_type(&tag) {
+            TagType::INVALID => return Err(bloberr!("invalid tag {:?} encountered", tag)),
+            TagType::ENUM | TagType::ENUM_REP => {
+                let val = consume_i32(data)?;
+                match tag {
+                    Tag::ALGORITHM => KeyParameterValue::Algorithm(Algorithm(val)),
+                    Tag::BLOCK_MODE => KeyParameterValue::BlockMode(BlockMode(val)),
+                    Tag::PADDING => KeyParameterValue::PaddingMode(PaddingMode(val)),
+                    Tag::DIGEST | Tag::RSA_OAEP_MGF_DIGEST => {
+                        KeyParameterValue::Digest(Digest(val))
+                    }
+                    Tag::EC_CURVE => KeyParameterValue::EcCurve(EcCurve(val)),
+                    Tag::ORIGIN => KeyParameterValue::Origin(KeyOrigin(val)),
+                    Tag::PURPOSE => KeyParameterValue::KeyPurpose(KeyPurpose(val)),
+                    Tag::USER_AUTH_TYPE => {
+                        KeyParameterValue::HardwareAuthenticatorType(HardwareAuthenticatorType(val))
+                    }
+                    _ => KeyParameterValue::Integer(val),
+                }
+            }
+            TagType::UINT | TagType::UINT_REP => KeyParameterValue::Integer(consume_i32(data)?),
+            TagType::ULONG | TagType::ULONG_REP => {
+                KeyParameterValue::LongInteger(consume_i64(data)?)
+            }
+            TagType::DATE => KeyParameterValue::DateTime(consume_i64(data)?),
+            TagType::BOOL => KeyParameterValue::BoolValue(consume_bool(data)?),
+            TagType::BIGNUM | TagType::BYTES => {
+                KeyParameterValue::Blob(consume_blob(data, &mut next_blob_offset, blob_data)?)
+            }
+            _ => return Err(bloberr!("unexpected tag type for {:?}", tag)),
+        };
+        results.push(KeyParameter { tag, value });
+    }
+
+    Ok(results)
+}
+
+/// Serialize a collection of [`KeyParameter`]s into a format that is compatible with previous
+/// implementations:
+///
+/// ```text
+/// [0..4]              Size B of `TagType::Bytes` data, in host order.
+/// [4..4+B]      (*)   Concatenated contents of each `TagType::Bytes` tag.
+/// [4+B..4+B+4]        Count N of the number of parameters, in host order.
+/// [8+B..8+B+4]        Size Z of encoded parameters.
+/// [12+B..12+B+Z]      Serialized parameters one after another.
+/// ```
+///
+/// Individual parameters are serialized in the last chunk as:
+///
+/// ```text
+/// [0..4]              Tag number, in host order.
+/// Followed by one of the following depending on the tag's `TagType`; all integers in host order:
+///   [4..5]            Bool value (`TagType::Bool`)
+///   [4..8]            i32 values (`TagType::Uint[Rep]`, `TagType::Enum[Rep]`)
+///   [4..12]           i64 values, in host order (`TagType::UlongRep`, `TagType::Date`)
+///   [4..8] + [8..12]  Size + offset of data in (*) above (`TagType::Bytes`, `TagType::Bignum`)
+/// ```
+fn serialize_params(params: &[KeyParameter]) -> Result<Vec<u8>> {
+    // First 4 bytes are the length of the combined [`TagType::Bytes`] data; come back to set that
+    // in a moment.
+    let mut result = vec![0; 4];
+
+    // Next append the contents of all of the [`TagType::Bytes`] data.
+    let mut blob_size = 0u32;
+    for param in params {
+        let tag_type = tag_type(&param.tag);
+        if let KeyParameterValue::Blob(v) = &param.value {
+            if tag_type != TagType::BIGNUM && tag_type != TagType::BYTES {
+                return Err(bloberr!("unexpected tag type for tag {:?} with blob", param.tag));
+            }
+            result.extend_from_slice(v);
+            blob_size += v.len() as u32;
+        }
+    }
+    // Go back and fill in the combined blob length in native order at the start.
+    result[..4].clone_from_slice(&blob_size.to_ne_bytes());
+
+    result.extend_from_slice(&(params.len() as u32).to_ne_bytes());
+
+    let params_size_offset = result.len();
+    result.extend_from_slice(&[0u8; 4]); // placeholder for size of elements
+    let first_param_offset = result.len();
+    let mut blob_offset = 0u32;
+    for param in params {
+        result.extend_from_slice(&(param.tag.0 as u32).to_ne_bytes());
+        match &param.value {
+            KeyParameterValue::Invalid(_v) => {
+                return Err(bloberr!("invalid tag found in {:?}", param))
+            }
+
+            // Enum-holding variants.
+            KeyParameterValue::Algorithm(v) => {
+                result.extend_from_slice(&(v.0 as u32).to_ne_bytes())
+            }
+            KeyParameterValue::BlockMode(v) => {
+                result.extend_from_slice(&(v.0 as u32).to_ne_bytes())
+            }
+            KeyParameterValue::PaddingMode(v) => {
+                result.extend_from_slice(&(v.0 as u32).to_ne_bytes())
+            }
+            KeyParameterValue::Digest(v) => result.extend_from_slice(&(v.0 as u32).to_ne_bytes()),
+            KeyParameterValue::EcCurve(v) => result.extend_from_slice(&(v.0 as u32).to_ne_bytes()),
+            KeyParameterValue::Origin(v) => result.extend_from_slice(&(v.0 as u32).to_ne_bytes()),
+            KeyParameterValue::KeyPurpose(v) => {
+                result.extend_from_slice(&(v.0 as u32).to_ne_bytes())
+            }
+            KeyParameterValue::HardwareAuthenticatorType(v) => {
+                result.extend_from_slice(&(v.0 as u32).to_ne_bytes())
+            }
+
+            // Value-holding variants.
+            KeyParameterValue::Integer(v) => result.extend_from_slice(&(*v as u32).to_ne_bytes()),
+            KeyParameterValue::BoolValue(_v) => result.push(0x01u8),
+            KeyParameterValue::LongInteger(v) | KeyParameterValue::DateTime(v) => {
+                result.extend_from_slice(&(*v as u64).to_ne_bytes())
+            }
+            KeyParameterValue::Blob(v) => {
+                let blob_len = v.len() as u32;
+                result.extend_from_slice(&blob_len.to_ne_bytes());
+                result.extend_from_slice(&blob_offset.to_ne_bytes());
+                blob_offset += blob_len;
+            }
+
+            _ => return Err(bloberr!("unknown value found in {:?}", param)),
+        }
+    }
+    let serialized_size = (result.len() - first_param_offset) as u32;
+
+    // Go back and fill in the total serialized size.
+    result[params_size_offset..params_size_offset + 4]
+        .clone_from_slice(&serialized_size.to_ne_bytes());
+    Ok(result)
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
+        Algorithm::Algorithm, BlockMode::BlockMode, Digest::Digest, EcCurve::EcCurve,
+        KeyOrigin::KeyOrigin, KeyParameter::KeyParameter,
+        KeyParameterValue::KeyParameterValue as KPV, KeyPurpose::KeyPurpose,
+        PaddingMode::PaddingMode, Tag::Tag,
+    };
+
+    macro_rules! expect_err {
+        ($result:expr, $err_msg:expr) => {
+            assert!(
+                $result.is_err(),
+                "Expected error containing '{}', got success {:?}",
+                $err_msg,
+                $result
+            );
+            let err = $result.err();
+            assert!(
+                format!("{:?}", err).contains($err_msg),
+                "Unexpected error {:?}, doesn't contain '{}'",
+                err,
+                $err_msg
+            );
+        };
+    }
+
+    #[test]
+    fn test_consume_u8() {
+        let buffer = [1, 2];
+        let mut data = &buffer[..];
+        assert_eq!(1u8, consume_u8(&mut data).unwrap());
+        assert_eq!(2u8, consume_u8(&mut data).unwrap());
+        let result = consume_u8(&mut data);
+        expect_err!(result, "failed to find 1 byte");
+    }
+
+    #[test]
+    fn test_consume_u32() {
+        // All supported platforms are little-endian.
+        let buffer = [
+            0x01, 0x02, 0x03, 0x04, // little-endian u32
+            0x04, 0x03, 0x02, 0x01, // little-endian u32
+            0x11, 0x12, 0x13,
+        ];
+        let mut data = &buffer[..];
+        assert_eq!(0x04030201u32, consume_u32(&mut data).unwrap());
+        assert_eq!(0x01020304u32, consume_u32(&mut data).unwrap());
+        let result = consume_u32(&mut data);
+        expect_err!(result, "failed to find 4 bytes");
+    }
+
+    #[test]
+    fn test_consume_i64() {
+        // All supported platforms are little-endian.
+        let buffer = [
+            0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, // little-endian i64
+            0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, // little-endian i64
+            0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+        ];
+        let mut data = &buffer[..];
+        assert_eq!(0x0807060504030201i64, consume_i64(&mut data).unwrap());
+        assert_eq!(0x0102030405060708i64, consume_i64(&mut data).unwrap());
+        let result = consume_i64(&mut data);
+        expect_err!(result, "failed to find 8 bytes");
+    }
+
+    #[test]
+    fn test_consume_vec() {
+        let buffer = [
+            0x01, 0x00, 0x00, 0x00, 0xaa, //
+            0x00, 0x00, 0x00, 0x00, //
+            0x01, 0x00, 0x00, 0x00, 0xbb, //
+            0x07, 0x00, 0x00, 0x00, 0xbb, // not enough data
+        ];
+        let mut data = &buffer[..];
+        assert_eq!(vec![0xaa], consume_vec(&mut data).unwrap());
+        assert_eq!(Vec::<u8>::new(), consume_vec(&mut data).unwrap());
+        assert_eq!(vec![0xbb], consume_vec(&mut data).unwrap());
+        let result = consume_vec(&mut data);
+        expect_err!(result, "failed to find 7 bytes");
+
+        let buffer = [
+            0x01, 0x00, 0x00, //
+        ];
+        let mut data = &buffer[..];
+        let result = consume_vec(&mut data);
+        expect_err!(result, "failed to find 4 bytes");
+    }
+
+    #[test]
+    fn test_key_new_from_serialized() {
+        let hidden = hidden_params(&[], &[SOFTWARE_ROOT_OF_TRUST]);
+        // Test data originally generated by instrumenting Cuttlefish C++ KeyMint while running VTS
+        // tests.
+        let tests = [
+            (
+                concat!(
+                    "0010000000d43c2f04f948521b81bdbf001310f5920000000000000000000000",
+                    "00000000000c0000006400000002000010200000000300003080000000010000",
+                    "2000000000010000200100000004000020020000000600002001000000be0200",
+                    "1000000000c1020030b0ad0100c20200307b150300bd020060a8bb52407b0100",
+                    "00ce02003011643401cf020030000000003b06b13ae6ae6671",
+                ),
+                KeyBlob {
+                    key_material: hex::decode("d43c2f04f948521b81bdbf001310f592").unwrap(),
+                    hw_enforced: vec![],
+                    sw_enforced: vec![
+                        KeyParameter { tag: Tag::ALGORITHM, value: KPV::Algorithm(Algorithm::AES) },
+                        KeyParameter { tag: Tag::KEY_SIZE, value: KPV::Integer(128) },
+                        KeyParameter {
+                            tag: Tag::PURPOSE,
+                            value: KPV::KeyPurpose(KeyPurpose::ENCRYPT),
+                        },
+                        KeyParameter {
+                            tag: Tag::PURPOSE,
+                            value: KPV::KeyPurpose(KeyPurpose::DECRYPT),
+                        },
+                        KeyParameter {
+                            tag: Tag::BLOCK_MODE,
+                            value: KPV::BlockMode(BlockMode::CBC),
+                        },
+                        KeyParameter {
+                            tag: Tag::PADDING,
+                            value: KPV::PaddingMode(PaddingMode::NONE),
+                        },
+                        KeyParameter { tag: Tag::ORIGIN, value: KPV::Origin(KeyOrigin::GENERATED) },
+                        KeyParameter { tag: Tag::OS_VERSION, value: KPV::Integer(110000) },
+                        KeyParameter { tag: Tag::OS_PATCHLEVEL, value: KPV::Integer(202107) },
+                        KeyParameter {
+                            tag: Tag::CREATION_DATETIME,
+                            value: KPV::DateTime(1628871769000),
+                        },
+                        KeyParameter { tag: Tag::VENDOR_PATCHLEVEL, value: KPV::Integer(20210705) },
+                        KeyParameter { tag: Tag::BOOT_PATCHLEVEL, value: KPV::Integer(0) },
+                    ],
+                },
+                Some(KeyFormat::RAW),
+            ),
+            (
+                concat!(
+                    "00df0000003081dc020101044200b6ce876b947e263d61b8e3998d50dc0afb6b",
+                    "a14e46ab7ca532fbe2a379b155d0a5bb99265402857b1601fb20be6c244bf654",
+                    "e9e79413cd503eae3d9cf68ed24f47a00706052b81040023a181890381860004",
+                    "006b840f0db0b12f074ab916c7773cfa7d42967c9e5b4fae09cf999f7e116d14",
+                    "0743bdd028db0a3fcc670e721b9f00bc7fb70aa401c7d6de6582fc26962a29b7",
+                    "45e30142e90685646661550344113aaf28bdee6cb02d19df1faab4398556a909",
+                    "7d6f64b95209601a549389a311231c6cce78354f2cdbc3a904abf70686f5f0c3",
+                    "b877984d000000000000000000000000000000000c0000006400000002000010",
+                    "030000000a000010030000000100002002000000010000200300000005000020",
+                    "000000000300003009020000be02001000000000c1020030b0ad0100c2020030",
+                    "7b150300bd02006018d352407b010000ce02003011643401cf02003000000000",
+                    "2f69002e55e9b0a3"
+                ),
+                KeyBlob {
+                    key_material: hex::decode(concat!(
+                        "3081dc020101044200b6ce876b947e263d61b8e3998d50dc0afb6ba14e46ab7c",
+                        "a532fbe2a379b155d0a5bb99265402857b1601fb20be6c244bf654e9e79413cd",
+                        "503eae3d9cf68ed24f47a00706052b81040023a181890381860004006b840f0d",
+                        "b0b12f074ab916c7773cfa7d42967c9e5b4fae09cf999f7e116d140743bdd028",
+                        "db0a3fcc670e721b9f00bc7fb70aa401c7d6de6582fc26962a29b745e30142e9",
+                        "0685646661550344113aaf28bdee6cb02d19df1faab4398556a9097d6f64b952",
+                        "09601a549389a311231c6cce78354f2cdbc3a904abf70686f5f0c3b877984d",
+                    ))
+                    .unwrap(),
+                    hw_enforced: vec![],
+                    sw_enforced: vec![
+                        KeyParameter { tag: Tag::ALGORITHM, value: KPV::Algorithm(Algorithm::EC) },
+                        KeyParameter { tag: Tag::EC_CURVE, value: KPV::EcCurve(EcCurve::P_521) },
+                        KeyParameter {
+                            tag: Tag::PURPOSE,
+                            value: KPV::KeyPurpose(KeyPurpose::SIGN),
+                        },
+                        KeyParameter {
+                            tag: Tag::PURPOSE,
+                            value: KPV::KeyPurpose(KeyPurpose::VERIFY),
+                        },
+                        KeyParameter { tag: Tag::DIGEST, value: KPV::Digest(Digest::NONE) },
+                        KeyParameter { tag: Tag::KEY_SIZE, value: KPV::Integer(521) },
+                        KeyParameter { tag: Tag::ORIGIN, value: KPV::Origin(KeyOrigin::GENERATED) },
+                        KeyParameter { tag: Tag::OS_VERSION, value: KPV::Integer(110000) },
+                        KeyParameter { tag: Tag::OS_PATCHLEVEL, value: KPV::Integer(202107) },
+                        KeyParameter {
+                            tag: Tag::CREATION_DATETIME,
+                            value: KPV::DateTime(1628871775000),
+                        },
+                        KeyParameter { tag: Tag::VENDOR_PATCHLEVEL, value: KPV::Integer(20210705) },
+                        KeyParameter { tag: Tag::BOOT_PATCHLEVEL, value: KPV::Integer(0) },
+                    ],
+                },
+                Some(KeyFormat::PKCS8),
+            ),
+            (
+                concat!(
+                    "0037000000541d4c440223650d5f51753c1abd80c725034485551e874d62327c",
+                    "65f6247a057f1218bd6c8cd7d319103ddb823fc11fb6c2c7268b5acc00000000",
+                    "0000000000000000000000000c00000064000000020000108000000003000030",
+                    "b801000001000020020000000100002003000000050000200400000008000030",
+                    "00010000be02001000000000c1020030b0ad0100c20200307b150300bd020060",
+                    "00d752407b010000ce02003011643401cf0200300000000036e6986ffc45fbb0",
+                ),
+                KeyBlob {
+                    key_material: hex::decode(concat!(
+                        "541d4c440223650d5f51753c1abd80c725034485551e874d62327c65f6247a05",
+                        "7f1218bd6c8cd7d319103ddb823fc11fb6c2c7268b5acc"
+                    ))
+                    .unwrap(),
+                    hw_enforced: vec![],
+                    sw_enforced: vec![
+                        KeyParameter {
+                            tag: Tag::ALGORITHM,
+                            value: KPV::Algorithm(Algorithm::HMAC),
+                        },
+                        KeyParameter { tag: Tag::KEY_SIZE, value: KPV::Integer(440) },
+                        KeyParameter {
+                            tag: Tag::PURPOSE,
+                            value: KPV::KeyPurpose(KeyPurpose::SIGN),
+                        },
+                        KeyParameter {
+                            tag: Tag::PURPOSE,
+                            value: KPV::KeyPurpose(KeyPurpose::VERIFY),
+                        },
+                        KeyParameter { tag: Tag::DIGEST, value: KPV::Digest(Digest::SHA_2_256) },
+                        KeyParameter { tag: Tag::MIN_MAC_LENGTH, value: KPV::Integer(256) },
+                        KeyParameter { tag: Tag::ORIGIN, value: KPV::Origin(KeyOrigin::GENERATED) },
+                        KeyParameter { tag: Tag::OS_VERSION, value: KPV::Integer(110000) },
+                        KeyParameter { tag: Tag::OS_PATCHLEVEL, value: KPV::Integer(202107) },
+                        KeyParameter {
+                            tag: Tag::CREATION_DATETIME,
+                            value: KPV::DateTime(1628871776000),
+                        },
+                        KeyParameter { tag: Tag::VENDOR_PATCHLEVEL, value: KPV::Integer(20210705) },
+                        KeyParameter { tag: Tag::BOOT_PATCHLEVEL, value: KPV::Integer(0) },
+                    ],
+                },
+                Some(KeyFormat::RAW),
+            ),
+            (
+                concat!(
+                    "00a8040000308204a40201000282010100bc47b5c71116766669b91fa747df87",
+                    "a1963df83956569d4ac232aeba8a246c0ec73bf606374a6d07f30c2162f97082",
+                    "825c7c6e482a2841dfeaec1429d84e52c54a6b2f760dec952c9c44a3c3a80f31",
+                    "c1ced84878edd4858059071c4d20d9ab0aae978bd68c1eb448e174a9736c3973",
+                    "6838151642eda8215107375865a99a57f29467c74c40f37b0221b93ec3f4f22d",
+                    "5337c8bf9245d56936196a92b1dea315ecce8785f9fa9b7d159ca207612cc0de",
+                    "b0957d61dbba5d9bd38784f4fecbf233b04e686a340528665ecd03db8e8a09b2",
+                    "540c84e45c4a99fb338b76bba7722856b5113341c349708937228f167d238ed8",
+                    "efb9cc19547dd620f6a90d95f07e50bfe102030100010282010002f91b69d9af",
+                    "59fe87421af9ba60f15c77f9c1c90effd6634332876f8ee5a116b126f55d3703",
+                    "8bf9f588ae20c8d951d842e35c9ef35a7822d3ebf72c0b7c3e229b289ae2e178",
+                    "a848e06d558c2e03d26871ee98a35f370d461ff1c4acc39d684de680a25ec88e",
+                    "e610260e406c400bdeb2893b2d0330cb483e662fa5abd24c2b82143e85dfe30a",
+                    "e7a31f8262da2903d882b35a34a26b699ff2d812bad4b126a0065ec0e101d73a",
+                    "e6f8b29a9144eb83f54940a371fc7416c2c0370df6a41cb5391f17ba33239e1b",
+                    "4217c8db50db5c6bf77ccf621354ecc652a4f7196054c254566fd7b3bc0f3817",
+                    "d9380b190bd382aaffa37785759f285194c11a188bccde0e2e2902818100fb23",
+                    "3335770c9f3cbd4b6ede5f12d03c449b1997bce06a8249bc3de99972fd0d0a63",
+                    "3f7790d1011bf5eedee16fa45a9107a910656ecaee364ce9edb4369843be71f2",
+                    "7a74852d6c7215a6cc60d9803bcac544922f806d8e5844e0ddd914bd78009490",
+                    "4c2856d2b944fade3fb1d67d4a33fb7663a9ab660ab372c2e4868a0f45990281",
+                    "8100bfecf2bb4012e880fd065a0b088f2d757af2878d3f1305f21ce7a7158458",
+                    "18e01181ff06b2f406239fc50808ce3dbe7b68ec01174913c0f237feb3c8c7eb",
+                    "0078b77fb5b8f214b72f6d3835b1a7ebe8b132feb6cb34ab09ce22b98160fc84",
+                    "20fcbf48d1eee49f874e902f049b206a61a095f0405a4935e7c5e49757ab7b57",
+                    "298902818100ec0049383e16f3716de5fc5b2677148efe5dceb02483b43399bd",
+                    "3765559994a9f3900eed7a7e9e8f3b0eee0e660eca392e3cb736cae612f39e55",
+                    "dad696d3821def10d1f8bbca52f5e6d8e7893ffbdcb491aafdc17bebf86f84d2",
+                    "d8480ed07a7bf9209d20ef6e79429489d4cb7768281a2f7e32ec1830fd6f6332",
+                    "38f521ba764902818100b2c3ce5751580b4e51df3fb175387f5c24b79040a4d6",
+                    "603c6265f70018b441ff3aef7d8e4cd2f480ec0906f1c4c0481304e8861f9d46",
+                    "93fa48e3a9abc362859eeb343e1c5507ac94b5439ce7ac04154a2fb886a4819b",
+                    "2a57e18a2e131b412ac4a09b004766959cdf357745f003e272aab3de02e2d5bc",
+                    "2af4ed75760858ab181902818061d19c2a8dcacde104b97f7c4fae11216157c1",
+                    "c0a258d882984d12383a73dc56fe2ac93512bb321df9706ecdb2f70a44c949c4",
+                    "340a9fae64a0646cf51f37c58c08bebde91667b3b2fa7c895f7983d4786c5526",
+                    "1941b3654533b0598383ebbcffcdf28b6cf13d376e3a70b49b14d8d06e8563a2",
+                    "47f56a337e3b9845b4f2b61356000000000000000000000000000000000d0000",
+                    "007000000002000010010000000300003000080000c800005001000100000000",
+                    "0001000020020000000100002003000000050000200000000006000020010000",
+                    "00be02001000000000c1020030b0ad0100c20200307b150300bd020060a8bb52",
+                    "407b010000ce02003011643401cf02003000000000544862e9c961e857",
+                ),
+                KeyBlob {
+                    key_material: hex::decode(concat!(
+                        "308204a40201000282010100bc47b5c71116766669b91fa747df87a1963df839",
+                        "56569d4ac232aeba8a246c0ec73bf606374a6d07f30c2162f97082825c7c6e48",
+                        "2a2841dfeaec1429d84e52c54a6b2f760dec952c9c44a3c3a80f31c1ced84878",
+                        "edd4858059071c4d20d9ab0aae978bd68c1eb448e174a9736c39736838151642",
+                        "eda8215107375865a99a57f29467c74c40f37b0221b93ec3f4f22d5337c8bf92",
+                        "45d56936196a92b1dea315ecce8785f9fa9b7d159ca207612cc0deb0957d61db",
+                        "ba5d9bd38784f4fecbf233b04e686a340528665ecd03db8e8a09b2540c84e45c",
+                        "4a99fb338b76bba7722856b5113341c349708937228f167d238ed8efb9cc1954",
+                        "7dd620f6a90d95f07e50bfe102030100010282010002f91b69d9af59fe87421a",
+                        "f9ba60f15c77f9c1c90effd6634332876f8ee5a116b126f55d37038bf9f588ae",
+                        "20c8d951d842e35c9ef35a7822d3ebf72c0b7c3e229b289ae2e178a848e06d55",
+                        "8c2e03d26871ee98a35f370d461ff1c4acc39d684de680a25ec88ee610260e40",
+                        "6c400bdeb2893b2d0330cb483e662fa5abd24c2b82143e85dfe30ae7a31f8262",
+                        "da2903d882b35a34a26b699ff2d812bad4b126a0065ec0e101d73ae6f8b29a91",
+                        "44eb83f54940a371fc7416c2c0370df6a41cb5391f17ba33239e1b4217c8db50",
+                        "db5c6bf77ccf621354ecc652a4f7196054c254566fd7b3bc0f3817d9380b190b",
+                        "d382aaffa37785759f285194c11a188bccde0e2e2902818100fb233335770c9f",
+                        "3cbd4b6ede5f12d03c449b1997bce06a8249bc3de99972fd0d0a633f7790d101",
+                        "1bf5eedee16fa45a9107a910656ecaee364ce9edb4369843be71f27a74852d6c",
+                        "7215a6cc60d9803bcac544922f806d8e5844e0ddd914bd780094904c2856d2b9",
+                        "44fade3fb1d67d4a33fb7663a9ab660ab372c2e4868a0f459902818100bfecf2",
+                        "bb4012e880fd065a0b088f2d757af2878d3f1305f21ce7a715845818e01181ff",
+                        "06b2f406239fc50808ce3dbe7b68ec01174913c0f237feb3c8c7eb0078b77fb5",
+                        "b8f214b72f6d3835b1a7ebe8b132feb6cb34ab09ce22b98160fc8420fcbf48d1",
+                        "eee49f874e902f049b206a61a095f0405a4935e7c5e49757ab7b572989028181",
+                        "00ec0049383e16f3716de5fc5b2677148efe5dceb02483b43399bd3765559994",
+                        "a9f3900eed7a7e9e8f3b0eee0e660eca392e3cb736cae612f39e55dad696d382",
+                        "1def10d1f8bbca52f5e6d8e7893ffbdcb491aafdc17bebf86f84d2d8480ed07a",
+                        "7bf9209d20ef6e79429489d4cb7768281a2f7e32ec1830fd6f633238f521ba76",
+                        "4902818100b2c3ce5751580b4e51df3fb175387f5c24b79040a4d6603c6265f7",
+                        "0018b441ff3aef7d8e4cd2f480ec0906f1c4c0481304e8861f9d4693fa48e3a9",
+                        "abc362859eeb343e1c5507ac94b5439ce7ac04154a2fb886a4819b2a57e18a2e",
+                        "131b412ac4a09b004766959cdf357745f003e272aab3de02e2d5bc2af4ed7576",
+                        "0858ab181902818061d19c2a8dcacde104b97f7c4fae11216157c1c0a258d882",
+                        "984d12383a73dc56fe2ac93512bb321df9706ecdb2f70a44c949c4340a9fae64",
+                        "a0646cf51f37c58c08bebde91667b3b2fa7c895f7983d4786c55261941b36545",
+                        "33b0598383ebbcffcdf28b6cf13d376e3a70b49b14d8d06e8563a247f56a337e",
+                        "3b9845b4f2b61356",
+                    ))
+                    .unwrap(),
+                    hw_enforced: vec![],
+                    sw_enforced: vec![
+                        KeyParameter { tag: Tag::ALGORITHM, value: KPV::Algorithm(Algorithm::RSA) },
+                        KeyParameter { tag: Tag::KEY_SIZE, value: KPV::Integer(2048) },
+                        KeyParameter {
+                            tag: Tag::RSA_PUBLIC_EXPONENT,
+                            value: KPV::LongInteger(65537),
+                        },
+                        KeyParameter {
+                            tag: Tag::PURPOSE,
+                            value: KPV::KeyPurpose(KeyPurpose::SIGN),
+                        },
+                        KeyParameter {
+                            tag: Tag::PURPOSE,
+                            value: KPV::KeyPurpose(KeyPurpose::VERIFY),
+                        },
+                        KeyParameter { tag: Tag::DIGEST, value: KPV::Digest(Digest::NONE) },
+                        KeyParameter {
+                            tag: Tag::PADDING,
+                            value: KPV::PaddingMode(PaddingMode::NONE),
+                        },
+                        KeyParameter { tag: Tag::ORIGIN, value: KPV::Origin(KeyOrigin::GENERATED) },
+                        KeyParameter { tag: Tag::OS_VERSION, value: KPV::Integer(110000) },
+                        KeyParameter { tag: Tag::OS_PATCHLEVEL, value: KPV::Integer(202107) },
+                        KeyParameter {
+                            tag: Tag::CREATION_DATETIME,
+                            value: KPV::DateTime(1628871769000),
+                        },
+                        KeyParameter { tag: Tag::VENDOR_PATCHLEVEL, value: KPV::Integer(20210705) },
+                        KeyParameter { tag: Tag::BOOT_PATCHLEVEL, value: KPV::Integer(0) },
+                    ],
+                },
+                // No support for RSA keys in export_key().
+                None,
+            ),
+        ];
+
+        for (input, want, want_format) in tests {
+            let input = hex::decode(input).unwrap();
+            let got = KeyBlob::new_from_serialized(&input, &hidden).expect("invalid keyblob!");
+            assert!(got == want);
+
+            if let Some(want_format) = want_format {
+                let (got_format, _key_material, params) =
+                    export_key(&input, &[]).expect("invalid keyblob!");
+                assert_eq!(got_format, want_format);
+                // All the test cases are software-only keys.
+                assert_eq!(params, got.sw_enforced);
+            }
+        }
+    }
+}
diff --git a/keystore2/src/utils.rs b/keystore2/src/utils.rs
index 584a51c..4fd9c8d 100644
--- a/keystore2/src/utils.rs
+++ b/keystore2/src/utils.rs
@@ -20,9 +20,12 @@
 use crate::ks_err;
 use crate::permission;
 use crate::permission::{KeyPerm, KeyPermSet, KeystorePerm};
+pub use crate::watchdog_helper::watchdog;
 use crate::{
     database::{KeyType, KeystoreDB},
     globals::LEGACY_IMPORTER,
+    km_compat,
+    raw_device::KeyMintDevice,
 };
 use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
     IKeyMintDevice::IKeyMintDevice, KeyCharacteristics::KeyCharacteristics,
@@ -163,13 +166,9 @@
         .collect()
 }
 
-/// This function can be used to upgrade key blobs on demand. The return value of
-/// `km_op` is inspected and if ErrorCode::KEY_REQUIRES_UPGRADE is encountered,
-/// an attempt is made to upgrade the key blob. On success `new_blob_handler` is called
-/// with the upgraded blob as argument. Then `km_op` is called a second time with the
-/// upgraded blob as argument. On success a tuple of the `km_op`s result and the
-/// optional upgraded blob is returned.
-pub fn upgrade_keyblob_if_required_with<T, KmOp, NewBlobHandler>(
+/// Upgrade a keyblob then invoke both the `new_blob_handler` and the `km_op` closures.  On success
+/// a tuple of the `km_op`s result and the optional upgraded blob is returned.
+fn upgrade_keyblob_and_perform_op<T, KmOp, NewBlobHandler>(
     km_dev: &dyn IKeyMintDevice,
     key_blob: &[u8],
     upgrade_params: &[KmKeyParameter],
@@ -180,22 +179,75 @@
     KmOp: Fn(&[u8]) -> Result<T, Error>,
     NewBlobHandler: FnOnce(&[u8]) -> Result<()>,
 {
+    let upgraded_blob = {
+        let _wp = watchdog::watch_millis(
+            "In utils::upgrade_keyblob_and_perform_op: calling upgradeKey.",
+            500,
+        );
+        map_km_error(km_dev.upgradeKey(key_blob, upgrade_params))
+    }
+    .context(ks_err!("Upgrade failed."))?;
+
+    new_blob_handler(&upgraded_blob).context(ks_err!("calling new_blob_handler."))?;
+
+    km_op(&upgraded_blob)
+        .map(|v| (v, Some(upgraded_blob)))
+        .context(ks_err!("Calling km_op after upgrade."))
+}
+
+/// This function can be used to upgrade key blobs on demand. The return value of
+/// `km_op` is inspected and if ErrorCode::KEY_REQUIRES_UPGRADE is encountered,
+/// an attempt is made to upgrade the key blob. On success `new_blob_handler` is called
+/// with the upgraded blob as argument. Then `km_op` is called a second time with the
+/// upgraded blob as argument. On success a tuple of the `km_op`s result and the
+/// optional upgraded blob is returned.
+pub fn upgrade_keyblob_if_required_with<T, KmOp, NewBlobHandler>(
+    km_dev: &dyn IKeyMintDevice,
+    km_dev_version: i32,
+    key_blob: &[u8],
+    upgrade_params: &[KmKeyParameter],
+    km_op: KmOp,
+    new_blob_handler: NewBlobHandler,
+) -> Result<(T, Option<Vec<u8>>)>
+where
+    KmOp: Fn(&[u8]) -> Result<T, Error>,
+    NewBlobHandler: FnOnce(&[u8]) -> Result<()>,
+{
     match km_op(key_blob) {
-        Err(Error::Km(ErrorCode::KEY_REQUIRES_UPGRADE)) => {
-            let upgraded_blob = {
-                let _wp = watchdog::watch_millis(
-                    "In utils::upgrade_keyblob_if_required_with: calling upgradeKey.",
-                    500,
-                );
-                map_km_error(km_dev.upgradeKey(key_blob, upgrade_params))
-            }
-            .context(ks_err!("Upgrade failed."))?;
-
-            new_blob_handler(&upgraded_blob).context(ks_err!("calling new_blob_handler."))?;
-
-            km_op(&upgraded_blob)
-                .map(|v| (v, Some(upgraded_blob)))
-                .context(ks_err!("Calling km_op after upgrade."))
+        Err(Error::Km(ErrorCode::KEY_REQUIRES_UPGRADE)) => upgrade_keyblob_and_perform_op(
+            km_dev,
+            key_blob,
+            upgrade_params,
+            km_op,
+            new_blob_handler,
+        ),
+        // Some devices have been known to upgrade their Keymaster device to be a KeyMint
+        // device with a new release of Android.  If this is the case, then any pre-upgrade
+        // keyblobs will have the km_compat prefix attached to them.
+        //
+        // This prefix gets stripped by the km_compat layer when used pre-upgrade, but after
+        // the upgrade the keyblob will be passed as-is to the KeyMint device, which probably
+        // won't expect to see the km_compat prefix.
+        //
+        // So if a keyblob:
+        //   a) gets rejected with INVALID_KEY_BLOB
+        //   b) when sent to a KeyMint (not km_compat) device
+        //   c) and has the km_compat magic prefix
+        //   d) and was not a software-emulated key pre-upgrade
+        // then strip the prefix and attempt a key upgrade.
+        Err(Error::Km(ErrorCode::INVALID_KEY_BLOB))
+            if km_dev_version >= KeyMintDevice::KEY_MINT_V1
+                && key_blob.starts_with(km_compat::KEYMASTER_BLOB_HW_PREFIX) =>
+        {
+            log::info!("found apparent km_compat(Keymaster) blob, attempt strip-and-upgrade");
+            let inner_keyblob = &key_blob[km_compat::KEYMASTER_BLOB_HW_PREFIX.len()..];
+            upgrade_keyblob_and_perform_op(
+                km_dev,
+                inner_keyblob,
+                upgrade_params,
+                km_op,
+                new_blob_handler,
+            )
         }
         r => r.map(|v| (v, None)).context(ks_err!("Calling km_op.")),
     }
@@ -217,7 +269,7 @@
     let mut current_time = libc::timespec { tv_sec: 0, tv_nsec: 0 };
     // SAFETY: The pointer is valid because it comes from a reference, and clock_gettime doesn't
     // retain it beyond the call.
-    unsafe { libc::clock_gettime(libc::CLOCK_MONOTONIC_RAW, &mut current_time) };
+    unsafe { libc::clock_gettime(libc::CLOCK_BOOTTIME, &mut current_time) };
     current_time.tv_sec as i64 * 1000 + (current_time.tv_nsec as i64 / 1_000_000)
 }
 
@@ -370,36 +422,6 @@
     Ok((legacy_keys.len() + num_keys_in_db) as i32)
 }
 
-/// This module provides helpers for simplified use of the watchdog module.
-#[cfg(feature = "watchdog")]
-pub mod watchdog {
-    pub use crate::watchdog::WatchPoint;
-    use crate::watchdog::Watchdog;
-    use lazy_static::lazy_static;
-    use std::sync::Arc;
-    use std::time::Duration;
-
-    lazy_static! {
-        /// A Watchdog thread, that can be used to create watch points.
-        static ref WD: Arc<Watchdog> = Watchdog::new(Duration::from_secs(10));
-    }
-
-    /// Sets a watch point with `id` and a timeout of `millis` milliseconds.
-    pub fn watch_millis(id: &'static str, millis: u64) -> Option<WatchPoint> {
-        Watchdog::watch(&WD, id, Duration::from_millis(millis))
-    }
-
-    /// Like `watch_millis` but with a callback that is called every time a report
-    /// is printed about this watch point.
-    pub fn watch_millis_with(
-        id: &'static str,
-        millis: u64,
-        callback: impl Fn() -> String + Send + 'static,
-    ) -> Option<WatchPoint> {
-        Watchdog::watch_with(&WD, id, Duration::from_millis(millis), callback)
-    }
-}
-
 /// Trait implemented by objects that can be used to decrypt cipher text using AES-GCM.
 pub trait AesGcm {
     /// Deciphers `data` using the initialization vector `iv` and AEAD tag `tag`
@@ -429,25 +451,6 @@
     }
 }
 
-/// This module provides empty/noop implementations of the watch dog utility functions.
-#[cfg(not(feature = "watchdog"))]
-pub mod watchdog {
-    /// Noop watch point.
-    pub struct WatchPoint();
-    /// Sets a Noop watch point.
-    fn watch_millis(_: &'static str, _: u64) -> Option<WatchPoint> {
-        None
-    }
-
-    pub fn watch_millis_with(
-        _: &'static str,
-        _: u64,
-        _: impl Fn() -> String + Send + 'static,
-    ) -> Option<WatchPoint> {
-        None
-    }
-}
-
 #[cfg(test)]
 mod tests {
     use super::*;
diff --git a/keystore2/src/watchdog_helper.rs b/keystore2/src/watchdog_helper.rs
new file mode 100644
index 0000000..92a0abc
--- /dev/null
+++ b/keystore2/src/watchdog_helper.rs
@@ -0,0 +1,64 @@
+// 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.
+
+//! Helpers for the watchdog module.
+
+/// This module provides helpers for simplified use of the watchdog module.
+#[cfg(feature = "watchdog")]
+pub mod watchdog {
+    use lazy_static::lazy_static;
+    use std::sync::Arc;
+    use std::time::Duration;
+    pub use watchdog_rs::WatchPoint;
+    use watchdog_rs::Watchdog;
+
+    lazy_static! {
+        /// A Watchdog thread, that can be used to create watch points.
+        static ref WD: Arc<Watchdog> = Watchdog::new(Duration::from_secs(10));
+    }
+
+    /// Sets a watch point with `id` and a timeout of `millis` milliseconds.
+    pub fn watch_millis(id: &'static str, millis: u64) -> Option<WatchPoint> {
+        Watchdog::watch(&WD, id, Duration::from_millis(millis))
+    }
+
+    /// Like `watch_millis` but with a callback that is called every time a report
+    /// is printed about this watch point.
+    pub fn watch_millis_with(
+        id: &'static str,
+        millis: u64,
+        callback: impl Fn() -> String + Send + 'static,
+    ) -> Option<WatchPoint> {
+        Watchdog::watch_with(&WD, id, Duration::from_millis(millis), callback)
+    }
+}
+
+/// This module provides empty/noop implementations of the watch dog utility functions.
+#[cfg(not(feature = "watchdog"))]
+pub mod watchdog {
+    /// Noop watch point.
+    pub struct WatchPoint();
+    /// Sets a Noop watch point.
+    fn watch_millis(_: &'static str, _: u64) -> Option<WatchPoint> {
+        None
+    }
+
+    pub fn watch_millis_with(
+        _: &'static str,
+        _: u64,
+        _: impl Fn() -> String + Send + 'static,
+    ) -> Option<WatchPoint> {
+        None
+    }
+}
diff --git a/keystore2/test_utils/Android.bp b/keystore2/test_utils/Android.bp
new file mode 100644
index 0000000..c16aa12
--- /dev/null
+++ b/keystore2/test_utils/Android.bp
@@ -0,0 +1,107 @@
+// 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.
+
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "system_security_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["system_security_license"],
+}
+
+rust_defaults {
+    name: "libkeystore2_test_utils_defaults",
+    defaults: [
+        "keymint_use_latest_hal_aidl_rust",
+        "keystore2_use_latest_aidl_rust",
+    ],
+    rustlibs: [
+        "libanyhow",
+        "libbinder_rs",
+        "libcxx",
+        "libkeystore2_selinux",
+        "liblog_rust",
+        "libnix",
+        "librand",
+        "librustutils",
+        "libserde",
+        "libserde_cbor",
+        "libthiserror",
+        "android.security.authorization-rust",
+    ],
+    static_libs: [
+        "libkeystore2_ffi_test_utils",
+    ],
+    shared_libs: [
+        "libbase",
+        "libcrypto",
+        "libkeymaster_portable",
+        "libkeymint_support",
+        "libkeystore-engine",
+    ],
+}
+
+rust_library {
+    name: "libkeystore2_test_utils",
+    crate_name: "keystore2_test_utils",
+    srcs: ["lib.rs"],
+    defaults: ["libkeystore2_test_utils_defaults"],
+}
+
+rust_test {
+    name: "keystore2_test_utils_test",
+    srcs: ["lib.rs"],
+    defaults: ["libkeystore2_test_utils_defaults"],
+    test_suites: ["general-tests"],
+    require_root: true,
+    auto_gen_config: true,
+    compile_multilib: "first",
+}
+
+cc_library_static {
+    name: "libkeystore2_ffi_test_utils",
+    srcs: ["ffi_test_utils.cpp"],
+    defaults: [
+        "keymint_use_latest_hal_aidl_ndk_shared",
+    ],
+    generated_headers: [
+        "cxx-bridge-header",
+        "libkeystore2_ffi_test_utils_bridge_header",
+    ],
+    generated_sources: ["libkeystore2_ffi_test_utils_bridge_code"],
+    shared_libs: [
+        "libbase",
+        "libcrypto",
+        "libkeymaster_portable",
+        "libkeystore-engine",
+        "libkeymint_support",
+    ],
+}
+
+genrule {
+    name: "libkeystore2_ffi_test_utils_bridge_code",
+    tools: ["cxxbridge"],
+    cmd: "$(location cxxbridge) $(in) >> $(out)",
+    srcs: ["ffi_test_utils.rs"],
+    out: ["libkeystore2_test_utils_cxx_generated.cc"],
+}
+
+genrule {
+    name: "libkeystore2_ffi_test_utils_bridge_header",
+    tools: ["cxxbridge"],
+    cmd: "$(location cxxbridge) $(in) --header >> $(out)",
+    srcs: ["ffi_test_utils.rs"],
+    out: ["ffi_test_utils.rs.h"],
+}
diff --git a/keystore2/test_utils/authorizations.rs b/keystore2/test_utils/authorizations.rs
index 514cbd3..02ceb83 100644
--- a/keystore2/test_utils/authorizations.rs
+++ b/keystore2/test_utils/authorizations.rs
@@ -242,6 +242,99 @@
         });
         self
     }
+
+    /// Set active date-time.
+    pub fn active_date_time(mut self, date: i64) -> Self {
+        self.0.push(KeyParameter {
+            tag: Tag::ACTIVE_DATETIME,
+            value: KeyParameterValue::DateTime(date),
+        });
+        self
+    }
+
+    /// Set origination expire date-time.
+    pub fn origination_expire_date_time(mut self, date: i64) -> Self {
+        self.0.push(KeyParameter {
+            tag: Tag::ORIGINATION_EXPIRE_DATETIME,
+            value: KeyParameterValue::DateTime(date),
+        });
+        self
+    }
+
+    /// Set usage expire date-time.
+    pub fn usage_expire_date_time(mut self, date: i64) -> Self {
+        self.0.push(KeyParameter {
+            tag: Tag::USAGE_EXPIRE_DATETIME,
+            value: KeyParameterValue::DateTime(date),
+        });
+        self
+    }
+
+    /// Set boot loader only.
+    pub fn boot_loader_only(mut self) -> Self {
+        self.0.push(KeyParameter {
+            tag: Tag::BOOTLOADER_ONLY,
+            value: KeyParameterValue::BoolValue(true),
+        });
+        self
+    }
+
+    /// Set early boot only.
+    pub fn early_boot_only(mut self) -> Self {
+        self.0.push(KeyParameter {
+            tag: Tag::EARLY_BOOT_ONLY,
+            value: KeyParameterValue::BoolValue(true),
+        });
+        self
+    }
+
+    /// Set max uses per boot.
+    pub fn max_uses_per_boot(mut self, max_uses: i32) -> Self {
+        self.0.push(KeyParameter {
+            tag: Tag::MAX_USES_PER_BOOT,
+            value: KeyParameterValue::Integer(max_uses),
+        });
+        self
+    }
+
+    /// Set max usage count.
+    pub fn usage_count_limit(mut self, usage_count: i32) -> Self {
+        self.0.push(KeyParameter {
+            tag: Tag::USAGE_COUNT_LIMIT,
+            value: KeyParameterValue::Integer(usage_count),
+        });
+        self
+    }
+
+    /// Set creation date-time.
+    pub fn creation_date_time(mut self, date: i64) -> Self {
+        self.0.push(KeyParameter {
+            tag: Tag::CREATION_DATETIME,
+            value: KeyParameterValue::DateTime(date),
+        });
+        self
+    }
+
+    /// Set include unique id.
+    pub fn include_unique_id(mut self) -> Self {
+        self.0.push(KeyParameter {
+            tag: Tag::INCLUDE_UNIQUE_ID,
+            value: KeyParameterValue::BoolValue(true),
+        });
+        self
+    }
+
+    /// Add app-data.
+    pub fn app_data(mut self, b: Vec<u8>) -> Self {
+        self.0.push(KeyParameter { tag: Tag::APPLICATION_DATA, value: KeyParameterValue::Blob(b) });
+        self
+    }
+
+    /// Add app-id.
+    pub fn app_id(mut self, b: Vec<u8>) -> Self {
+        self.0.push(KeyParameter { tag: Tag::APPLICATION_ID, value: KeyParameterValue::Blob(b) });
+        self
+    }
 }
 
 impl Deref for AuthSetBuilder {
diff --git a/keystore2/tests/ffi_test_utils.cpp b/keystore2/test_utils/ffi_test_utils.cpp
similarity index 66%
rename from keystore2/tests/ffi_test_utils.cpp
rename to keystore2/test_utils/ffi_test_utils.cpp
index 7fbfb8b..4e781d1 100644
--- a/keystore2/tests/ffi_test_utils.cpp
+++ b/keystore2/test_utils/ffi_test_utils.cpp
@@ -1,26 +1,22 @@
 #include "ffi_test_utils.hpp"
 
 #include <iostream>
-
-#include <android-base/logging.h>
-
-#include <KeyMintAidlTestBase.h>
-#include <aidl/android/hardware/security/keymint/ErrorCode.h>
-#include <keymaster/UniquePtr.h>
-
 #include <vector>
 
-#include <hardware/keymaster_defs.h>
-#include <keymaster/android_keymaster_utils.h>
-#include <keymaster/keymaster_tags.h>
-
+#include <android-base/logging.h>
 #include <keymaster/km_openssl/attestation_record.h>
 #include <keymaster/km_openssl/openssl_err.h>
 #include <keymaster/km_openssl/openssl_utils.h>
+#include <keymint_support/attestation_record.h>
+#include <keymint_support/keymint_utils.h>
+#include <openssl/mem.h>
 
-#include <android-base/logging.h>
-
-using aidl::android::hardware::security::keymint::ErrorCode;
+using keymaster::ASN1_OBJECT_Ptr;
+using keymaster::EVP_PKEY_Ptr;
+using keymaster::X509_Ptr;
+using std::endl;
+using std::string;
+using std::vector;
 
 #define TAG_SEQUENCE 0x30
 #define LENGTH_MASK 0x80
@@ -29,6 +25,8 @@
 /* EVP_PKEY_from_keystore is from system/security/keystore-engine. */
 extern "C" EVP_PKEY* EVP_PKEY_from_keystore(const char* key_id);
 
+typedef std::vector<uint8_t> certificate_t;
+
 /**
  * ASN.1 structure for `KeyDescription` Schema.
  * See `IKeyMintDevice.aidl` for documentation of the `KeyDescription` schema.
@@ -91,6 +89,94 @@
 
 const std::string keystore2_grant_id_prefix("ks2_keystore-engine_grant_id:");
 
+string bin2hex(const vector<uint8_t>& data) {
+    string retval;
+    char nibble2hex[16] = {'0', '1', '2', '3', '4', '5', '6', '7',
+                           '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
+    retval.reserve(data.size() * 2 + 1);
+    for (uint8_t byte : data) {
+        retval.push_back(nibble2hex[0x0F & (byte >> 4)]);
+        retval.push_back(nibble2hex[0x0F & byte]);
+    }
+    return retval;
+}
+
+string x509NameToStr(X509_NAME* name) {
+    char* s = X509_NAME_oneline(name, nullptr, 0);
+    string retval(s);
+    OPENSSL_free(s);
+    return retval;
+}
+
+X509_Ptr parseCertBlob(const vector<uint8_t>& blob) {
+    const uint8_t* p = blob.data();
+    return X509_Ptr(d2i_X509(nullptr /* allocate new */, &p, blob.size()));
+}
+
+// Extract attestation record from cert. Returned object is still part of cert; don't free it
+// separately.
+ASN1_OCTET_STRING* getAttestationRecord(X509* certificate) {
+    ASN1_OBJECT_Ptr oid(OBJ_txt2obj(aidl::android::hardware::security::keymint::kAttestionRecordOid,
+                                    1 /* dotted string format */));
+    if (!oid.get()) return nullptr;
+
+    int location = X509_get_ext_by_OBJ(certificate, oid.get(), -1 /* search from beginning */);
+    if (location == -1) return nullptr;
+
+    X509_EXTENSION* attest_rec_ext = X509_get_ext(certificate, location);
+    if (!attest_rec_ext) return nullptr;
+
+    ASN1_OCTET_STRING* attest_rec = X509_EXTENSION_get_data(attest_rec_ext);
+    return attest_rec;
+}
+
+bool ChainSignaturesAreValid(const vector<certificate_t>& chain, bool strict_issuer_check) {
+    std::stringstream cert_data;
+
+    for (size_t i = 0; i < chain.size(); ++i) {
+        cert_data << bin2hex(chain[i]) << std::endl;
+
+        X509_Ptr key_cert(parseCertBlob(chain[i]));
+        X509_Ptr signing_cert;
+        if (i < chain.size() - 1) {
+            signing_cert = parseCertBlob(chain[i + 1]);
+        } else {
+            signing_cert = parseCertBlob(chain[i]);
+        }
+        if (!key_cert.get() || !signing_cert.get()) {
+            LOG(ERROR) << cert_data.str();
+            return false;
+        }
+
+        EVP_PKEY_Ptr signing_pubkey(X509_get_pubkey(signing_cert.get()));
+        if (!signing_pubkey.get()) {
+            LOG(ERROR) << cert_data.str();
+            return false;
+        }
+
+        if (!X509_verify(key_cert.get(), signing_pubkey.get())) {
+            LOG(ERROR) << "Verification of certificate " << i << " failed "
+                       << "OpenSSL error string: " << ERR_error_string(ERR_get_error(), NULL)
+                       << '\n'
+                       << cert_data.str();
+            return false;
+        }
+
+        string cert_issuer = x509NameToStr(X509_get_issuer_name(key_cert.get()));
+        string signer_subj = x509NameToStr(X509_get_subject_name(signing_cert.get()));
+        if (cert_issuer != signer_subj && strict_issuer_check) {
+            LOG(ERROR) << "Cert " << i << " has wrong issuer.\n"
+                       << " Signer subject is " << signer_subj << " Issuer subject is "
+                       << cert_issuer << endl
+                       << cert_data.str();
+        }
+    }
+
+    // Dump cert data.
+    LOG(ERROR) << cert_data.str();
+    return true;
+}
+
 /* This function extracts a certificate from the certs_chain_buffer at the given
  * offset. Each DER encoded certificate starts with TAG_SEQUENCE followed by the
  * total length of the certificate. The length of the certificate is determined
@@ -101,13 +187,12 @@
  * @data_size: Length of the DER encoded X.509 certificates buffer.
  * @index: DER encoded X.509 certificates buffer offset.
  * @cert: Encoded certificate to be extracted from buffer as outcome.
- * @return: ErrorCode::OK on success, otherwise ErrorCode::UNKNOWN_ERROR.
+ * @return: true on success, otherwise false.
  */
-ErrorCode
-extractCertFromCertChainBuffer(uint8_t* certs_chain_buffer, int certs_chain_buffer_size, int& index,
-                               aidl::android::hardware::security::keymint::Certificate& cert) {
+bool extractCertFromCertChainBuffer(uint8_t* certs_chain_buffer, int certs_chain_buffer_size,
+                                    int& index, certificate_t& cert) {
     if (index >= certs_chain_buffer_size) {
-        return ErrorCode::UNKNOWN_ERROR;
+        return false;
     }
 
     uint32_t length = 0;
@@ -140,7 +225,7 @@
                 length += 6;
             } else {
                 // Length is larger than uint32_t max limit.
-                return ErrorCode::UNKNOWN_ERROR;
+                return false;
             }
         }
         cert_bytes.insert(cert_bytes.end(), (certs_chain_buffer + index),
@@ -148,53 +233,47 @@
         index += length;
 
         for (int i = 0; i < cert_bytes.size(); i++) {
-            cert.encodedCertificate = std::move(cert_bytes);
+            cert = std::move(cert_bytes);
         }
     } else {
         // SEQUENCE TAG MISSING.
-        return ErrorCode::UNKNOWN_ERROR;
+        return false;
     }
 
-    return ErrorCode::OK;
+    return true;
 }
 
-ErrorCode getCertificateChain(
-    rust::Vec<rust::u8>& chainBuffer,
-    std::vector<aidl::android::hardware::security::keymint::Certificate>& certChain) {
+bool getCertificateChain(rust::Vec<rust::u8>& chainBuffer, std::vector<certificate_t>& certChain) {
     uint8_t* data = chainBuffer.data();
     int index = 0;
     int data_size = chainBuffer.size();
 
     while (index < data_size) {
-        aidl::android::hardware::security::keymint::Certificate cert =
-            aidl::android::hardware::security::keymint::Certificate();
-        if (extractCertFromCertChainBuffer(data, data_size, index, cert) != ErrorCode::OK) {
-            return ErrorCode::UNKNOWN_ERROR;
+        certificate_t cert;
+        if (!extractCertFromCertChainBuffer(data, data_size, index, cert)) {
+            return false;
         }
         certChain.push_back(std::move(cert));
     }
-    return ErrorCode::OK;
+    return true;
 }
 
 bool validateCertChain(rust::Vec<rust::u8> cert_buf, uint32_t cert_len, bool strict_issuer_check) {
-    std::vector<aidl::android::hardware::security::keymint::Certificate> cert_chain =
-        std::vector<aidl::android::hardware::security::keymint::Certificate>();
+    std::vector<certificate_t> cert_chain = std::vector<certificate_t>();
     if (cert_len <= 0) {
         return false;
     }
-    if (getCertificateChain(cert_buf, cert_chain) != ErrorCode::OK) {
+    if (!getCertificateChain(cert_buf, cert_chain)) {
         return false;
     }
 
+    std::stringstream cert_data;
     for (int i = 0; i < cert_chain.size(); i++) {
-        std::cout << cert_chain[i].toString() << "\n";
+        cert_data << bin2hex(cert_chain[i]) << std::endl;
     }
-    auto result = aidl::android::hardware::security::keymint::test::ChainSignaturesAreValid(
-        cert_chain, strict_issuer_check);
+    LOG(INFO) << cert_data.str() << "\n";
 
-    if (result == testing::AssertionSuccess()) return true;
-
-    return false;
+    return ChainSignaturesAreValid(cert_chain, strict_issuer_check);
 }
 
 /**
@@ -278,7 +357,7 @@
                            rust::Vec<rust::u8> tag) {
     CxxResult cxx_result{};
     keymaster_error_t error;
-    cxx_result.error = KM_ERROR_OK;
+    cxx_result.error = false;
 
     uint8_t* enc_secure_key_data = encrypted_secure_key.data();
     int enc_secure_key_size = encrypted_secure_key.size();
@@ -295,13 +374,16 @@
     keymaster::UniquePtr<TEST_SECURE_KEY_WRAPPER, TEST_SECURE_KEY_WRAPPER_Delete> sec_key_wrapper(
         TEST_SECURE_KEY_WRAPPER_new());
     if (!sec_key_wrapper.get()) {
-        cxx_result.error = KM_ERROR_MEMORY_ALLOCATION_FAILED;
+        LOG(ERROR) << "createWrappedKey - Failed to allocate a memory";
+        cxx_result.error = true;
         return cxx_result;
     }
 
     // Fill version = 0
     if (!ASN1_INTEGER_set(sec_key_wrapper->version, 0)) {
-        cxx_result.error = keymaster::TranslateLastOpenSslError();
+        LOG(ERROR) << "createWrappedKey - Error while filling version: "
+                   << keymaster::TranslateLastOpenSslError();
+        cxx_result.error = true;
         return cxx_result;
     }
 
@@ -309,14 +391,18 @@
     if (enc_transport_key_size &&
         !ASN1_OCTET_STRING_set(sec_key_wrapper->encrypted_transport_key, enc_transport_key_data,
                                enc_transport_key_size)) {
-        cxx_result.error = keymaster::TranslateLastOpenSslError();
+        LOG(ERROR) << "createWrappedKey - Error while filling encrypted transport key: "
+                   << keymaster::TranslateLastOpenSslError();
+        cxx_result.error = true;
         return cxx_result;
     }
 
     // Fill encrypted secure key.
     if (enc_secure_key_size && !ASN1_OCTET_STRING_set(sec_key_wrapper->encrypted_key,
                                                       enc_secure_key_data, enc_secure_key_size)) {
-        cxx_result.error = keymaster::TranslateLastOpenSslError();
+        LOG(ERROR) << "createWrappedKey - Error while filling encrypted secure key: "
+                   << keymaster::TranslateLastOpenSslError();
+        cxx_result.error = true;
         return cxx_result;
     }
 
@@ -324,46 +410,55 @@
     keymaster::AuthorizationSet auth_list = build_wrapped_key_auth_list();
     error = build_auth_list(auth_list, sec_key_wrapper->key_desc->key_params);
     if (error != KM_ERROR_OK) {
-        cxx_result.error = error;
+        cxx_result.error = true;
         return cxx_result;
     }
 
     // Fill secure key format.
     if (!ASN1_INTEGER_set(sec_key_wrapper->key_desc->key_format, KM_KEY_FORMAT_RAW)) {
-        cxx_result.error = keymaster::TranslateLastOpenSslError();
+        LOG(ERROR) << "createWrappedKey - Error while filling secure key format: "
+                   << keymaster::TranslateLastOpenSslError();
+        cxx_result.error = true;
         return cxx_result;
     }
 
     // Fill initialization vector used for encrypting secure key.
     if (iv_size &&
         !ASN1_OCTET_STRING_set(sec_key_wrapper->initialization_vector, iv_data, iv_size)) {
-        cxx_result.error = keymaster::TranslateLastOpenSslError();
+        LOG(ERROR) << "createWrappedKey - Error while filling IV: "
+                   << keymaster::TranslateLastOpenSslError();
+        cxx_result.error = true;
         return cxx_result;
     }
 
     // Fill GCM-tag, extracted during secure key encryption.
     if (tag_size && !ASN1_OCTET_STRING_set(sec_key_wrapper->tag, tag_data, tag_size)) {
-        cxx_result.error = keymaster::TranslateLastOpenSslError();
+        LOG(ERROR) << "createWrappedKey - Error while filling GCM-tag: "
+                   << keymaster::TranslateLastOpenSslError();
+        cxx_result.error = true;
         return cxx_result;
     }
 
     // ASN.1 DER-encoding of secure key wrapper.
     int asn1_data_len = i2d_TEST_SECURE_KEY_WRAPPER(sec_key_wrapper.get(), nullptr);
     if (asn1_data_len < 0) {
-        cxx_result.error = keymaster::TranslateLastOpenSslError();
+        LOG(ERROR) << "createWrappedKey - Error while performing DER encode: "
+                   << keymaster::TranslateLastOpenSslError();
+        cxx_result.error = true;
         return cxx_result;
     }
     std::vector<uint8_t> asn1_data(asn1_data_len, 0);
 
     if (!asn1_data.data()) {
-        cxx_result.error = KM_ERROR_MEMORY_ALLOCATION_FAILED;
+        LOG(ERROR) << "createWrappedKey - Failed to allocate a memory for asn1_data";
+        cxx_result.error = true;
         return cxx_result;
     }
 
     uint8_t* p = asn1_data.data();
     asn1_data_len = i2d_TEST_SECURE_KEY_WRAPPER(sec_key_wrapper.get(), &p);
     if (asn1_data_len < 0) {
-        cxx_result.error = keymaster::TranslateLastOpenSslError();
+        cxx_result.error = true;
         return cxx_result;
     }
 
@@ -506,9 +601,10 @@
     return result;
 }
 
-CxxResult getValueFromAttestRecord(rust::Vec<rust::u8> cert_buf, int32_t tag) {
+CxxResult getValueFromAttestRecord(rust::Vec<rust::u8> cert_buf, int32_t tag,
+                                   int32_t expected_sec_level) {
     CxxResult cxx_result{};
-    cxx_result.error = KM_ERROR_OK;
+    cxx_result.error = false;
 
     uint8_t* cert_data = cert_buf.data();
     int cert_data_size = cert_buf.size();
@@ -516,17 +612,18 @@
     std::vector<uint8_t> cert_bytes;
     cert_bytes.insert(cert_bytes.end(), cert_data, (cert_data + cert_data_size));
 
-    aidl::android::hardware::security::keymint::X509_Ptr cert(
-        aidl::android::hardware::security::keymint::test::parse_cert_blob(cert_bytes));
+    X509_Ptr cert(parseCertBlob(cert_bytes));
     if (!cert.get()) {
-        cxx_result.error = KM_ERROR_MEMORY_ALLOCATION_FAILED;
+        LOG(ERROR) << "getValueFromAttestRecord - Failed to allocate a memory for certificate";
+        cxx_result.error = true;
         return cxx_result;
     }
 
-    ASN1_OCTET_STRING* attest_rec =
-        aidl::android::hardware::security::keymint::test::get_attestation_record(cert.get());
+    ASN1_OCTET_STRING* attest_rec = getAttestationRecord(cert.get());
     if (!attest_rec) {
-        cxx_result.error = keymaster::TranslateLastOpenSslError();
+        LOG(ERROR) << "getValueFromAttestRecord - Error in getAttestationRecord: "
+                   << keymaster::TranslateLastOpenSslError();
+        cxx_result.error = true;
         return cxx_result;
     }
 
@@ -540,24 +637,28 @@
     std::vector<uint8_t> att_unique_id;
     std::vector<uint8_t> att_app_id;
 
-    auto error = aidl::android::hardware::security::keymint::parse_attestation_record(
-        attest_rec->data, attest_rec->length, &att_attestation_version,
-        &att_attestation_security_level, &att_keymint_version, &att_keymint_security_level,
-        &att_challenge, &att_sw_enforced, &att_hw_enforced, &att_unique_id);
-    EXPECT_EQ(ErrorCode::OK, error);
-    if (error != ErrorCode::OK) {
-        cxx_result.error = static_cast<int32_t>(error);
+    int32_t error =
+        static_cast<int32_t>(aidl::android::hardware::security::keymint::parse_attestation_record(
+            attest_rec->data, attest_rec->length, &att_attestation_version,
+            &att_attestation_security_level, &att_keymint_version, &att_keymint_security_level,
+            &att_challenge, &att_sw_enforced, &att_hw_enforced, &att_unique_id));
+    if (error) {
+        LOG(ERROR) << "getValueFromAttestRecord - Error in parse_attestation_record: " << error;
+        cxx_result.error = true;
         return cxx_result;
     }
 
     aidl::android::hardware::security::keymint::Tag auth_tag =
         static_cast<aidl::android::hardware::security::keymint::Tag>(tag);
+    aidl::android::hardware::security::keymint::SecurityLevel tag_security_level =
+        static_cast<aidl::android::hardware::security::keymint::SecurityLevel>(expected_sec_level);
 
     if (auth_tag == aidl::android::hardware::security::keymint::Tag::ATTESTATION_APPLICATION_ID) {
         int pos = att_sw_enforced.find(
             aidl::android::hardware::security::keymint::Tag::ATTESTATION_APPLICATION_ID);
         if (pos == -1) {
-            cxx_result.error = KM_ERROR_ATTESTATION_APPLICATION_ID_MISSING;
+            LOG(ERROR) << "getValueFromAttestRecord - Attestation-application-id missing.";
+            cxx_result.error = true;
             return cxx_result;
         }
         aidl::android::hardware::security::keymint::KeyParameter param = att_sw_enforced[pos];
@@ -569,7 +670,8 @@
 
     if (auth_tag == aidl::android::hardware::security::keymint::Tag::ATTESTATION_CHALLENGE) {
         if (att_challenge.size() == 0) {
-            cxx_result.error = KM_ERROR_ATTESTATION_CHALLENGE_MISSING;
+            LOG(ERROR) << "getValueFromAttestRecord - Attestation-challenge missing.";
+            cxx_result.error = true;
             return cxx_result;
         }
         std::move(att_challenge.begin(), att_challenge.end(), std::back_inserter(cxx_result.data));
@@ -578,16 +680,48 @@
 
     if (auth_tag == aidl::android::hardware::security::keymint::Tag::UNIQUE_ID) {
         if (att_unique_id.size() == 0) {
-            cxx_result.error = KM_ERROR_UNSUPPORTED_TAG;
+            LOG(ERROR) << "getValueFromAttestRecord - unsupported tag - UNIQUE_ID.";
+            cxx_result.error = true;
             return cxx_result;
         }
         std::move(att_unique_id.begin(), att_unique_id.end(), std::back_inserter(cxx_result.data));
         return cxx_result;
     }
 
+    if (auth_tag == aidl::android::hardware::security::keymint::Tag::USAGE_COUNT_LIMIT) {
+        aidl::android::hardware::security::keymint::KeyParameter param;
+        int pos = att_hw_enforced.find(auth_tag);
+        if (tag_security_level ==
+                aidl::android::hardware::security::keymint::SecurityLevel::SOFTWARE ||
+            tag_security_level ==
+                aidl::android::hardware::security::keymint::SecurityLevel::KEYSTORE) {
+            pos = att_sw_enforced.find(auth_tag);
+            if (pos == -1) {
+                LOG(ERROR) << "USAGE_COUNT_LIMIT not found in software enforced auth list";
+                cxx_result.error = KM_ERROR_INVALID_TAG;
+                return cxx_result;
+            }
+            param = att_sw_enforced[pos];
+        } else {
+            pos = att_hw_enforced.find(auth_tag);
+            if (pos == -1) {
+                LOG(ERROR) << "USAGE_COUNT_LIMIT not found in hardware enforced auth list";
+                cxx_result.error = KM_ERROR_INVALID_TAG;
+                return cxx_result;
+            }
+            param = att_hw_enforced[pos];
+        }
+        std::string val = std::to_string(
+            param.value
+                .get<aidl::android::hardware::security::keymint::KeyParameterValue::integer>());
+        std::move(val.begin(), val.end(), std::back_inserter(cxx_result.data));
+        return cxx_result;
+    }
+
     int pos = att_hw_enforced.find(auth_tag);
     if (pos == -1) {
-        cxx_result.error = KM_ERROR_UNSUPPORTED_TAG;
+        LOG(ERROR) << "getValueFromAttestRecord - unsupported tag.";
+        cxx_result.error = true;
         return cxx_result;
     }
     aidl::android::hardware::security::keymint::KeyParameter param = att_hw_enforced[pos];
@@ -596,3 +730,15 @@
     std::move(val.begin(), val.end(), std::back_inserter(cxx_result.data));
     return cxx_result;
 }
+
+uint32_t getOsVersion() {
+    return aidl::android::hardware::security::keymint::getOsVersion();
+}
+
+uint32_t getOsPatchlevel() {
+    return aidl::android::hardware::security::keymint::getOsPatchlevel();
+}
+
+uint32_t getVendorPatchlevel() {
+    return aidl::android::hardware::security::keymint::getVendorPatchlevel();
+}
diff --git a/keystore2/test_utils/ffi_test_utils.hpp b/keystore2/test_utils/ffi_test_utils.hpp
new file mode 100644
index 0000000..c4db1ba
--- /dev/null
+++ b/keystore2/test_utils/ffi_test_utils.hpp
@@ -0,0 +1,16 @@
+#pragma once
+
+#include "ffi_test_utils.rs.h"
+#include "rust/cxx.h"
+
+bool validateCertChain(rust::Vec<rust::u8> cert_buf, uint32_t cert_len, bool strict_issuer_check);
+CxxResult createWrappedKey(rust::Vec<rust::u8> encrypted_secure_key,
+                           rust::Vec<rust::u8> encrypted_transport_key, rust::Vec<rust::u8> iv,
+                           rust::Vec<rust::u8> tag);
+CxxResult buildAsn1DerEncodedWrappedKeyDescription();
+bool performCryptoOpUsingKeystoreEngine(int64_t grant_id);
+CxxResult getValueFromAttestRecord(rust::Vec<rust::u8> cert_buf, int32_t tag,
+                                   int32_t expected_sec_level);
+uint32_t getOsVersion();
+uint32_t getOsPatchlevel();
+uint32_t getVendorPatchlevel();
diff --git a/keystore2/tests/ffi_test_utils.rs b/keystore2/test_utils/ffi_test_utils.rs
similarity index 71%
rename from keystore2/tests/ffi_test_utils.rs
rename to keystore2/test_utils/ffi_test_utils.rs
index c652174..5d6bf46 100644
--- a/keystore2/tests/ffi_test_utils.rs
+++ b/keystore2/test_utils/ffi_test_utils.rs
@@ -12,14 +12,18 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-use android_hardware_security_keymint::aidl::android::hardware::security::keymint::Tag::Tag;
-use keystore2_test_utils::key_generations::Error;
+//! This module implements helper methods to access the functionalities implemented in CPP.
+
+use crate::key_generations::Error;
+use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
+    SecurityLevel::SecurityLevel, Tag::Tag,
+};
 
 #[cxx::bridge]
 mod ffi {
     struct CxxResult {
         data: Vec<u8>,
-        error: i32,
+        error: bool,
     }
 
     unsafe extern "C++" {
@@ -33,7 +37,14 @@
         ) -> CxxResult;
         fn buildAsn1DerEncodedWrappedKeyDescription() -> CxxResult;
         fn performCryptoOpUsingKeystoreEngine(grant_id: i64) -> bool;
-        fn getValueFromAttestRecord(cert_buf: Vec<u8>, tag: i32) -> CxxResult;
+        fn getValueFromAttestRecord(
+            cert_buf: Vec<u8>,
+            tag: i32,
+            expected_sec_level: i32,
+        ) -> CxxResult;
+        fn getOsVersion() -> u32;
+        fn getOsPatchlevel() -> u32;
+        fn getVendorPatchlevel() -> u32;
     }
 }
 
@@ -46,8 +57,9 @@
     Err(Error::ValidateCertChainFailed)
 }
 
+/// Collect the result from CxxResult into a Rust supported structure.
 fn get_result(result: ffi::CxxResult) -> Result<Vec<u8>, Error> {
-    if result.error == 0 && !result.data.is_empty() {
+    if !result.error && !result.data.is_empty() {
         Ok(result.data)
     } else {
         Err(Error::DerEncodeFailed)
@@ -82,6 +94,7 @@
     get_result(ffi::buildAsn1DerEncodedWrappedKeyDescription())
 }
 
+/// Performs crypto operation using Keystore-Engine APIs.
 pub fn perform_crypto_op_using_keystore_engine(grant_id: i64) -> Result<bool, Error> {
     if ffi::performCryptoOpUsingKeystoreEngine(grant_id) {
         return Ok(true);
@@ -90,10 +103,30 @@
     Err(Error::Keystore2EngineOpFailed)
 }
 
-pub fn get_value_from_attest_record(cert_buf: &[u8], tag: Tag) -> Result<Vec<u8>, Error> {
-    let result = ffi::getValueFromAttestRecord(cert_buf.to_vec(), tag.0);
-    if result.error == 0 && !result.data.is_empty() {
+/// Get the value of the given `Tag` from attestation record.
+pub fn get_value_from_attest_record(
+    cert_buf: &[u8],
+    tag: Tag,
+    expected_sec_level: SecurityLevel,
+) -> Result<Vec<u8>, Error> {
+    let result = ffi::getValueFromAttestRecord(cert_buf.to_vec(), tag.0, expected_sec_level.0);
+    if !result.error && !result.data.is_empty() {
         return Ok(result.data);
     }
     Err(Error::AttestRecordGetValueFailed)
 }
+
+/// Get OS Version
+pub fn get_os_version() -> u32 {
+    ffi::getOsVersion()
+}
+
+/// Get OS Patch Level
+pub fn get_os_patchlevel() -> u32 {
+    ffi::getOsPatchlevel()
+}
+
+/// Get vendor Patch Level
+pub fn get_vendor_patchlevel() -> u32 {
+    ffi::getVendorPatchlevel()
+}
diff --git a/keystore2/test_utils/key_generations.rs b/keystore2/test_utils/key_generations.rs
index 0f9ecbe..badc480 100644
--- a/keystore2/test_utils/key_generations.rs
+++ b/keystore2/test_utils/key_generations.rs
@@ -15,19 +15,22 @@
 //! This module implements test utils to generate various types of keys.
 
 use anyhow::Result;
-
 use core::ops::Range;
+use nix::unistd::getuid;
 use std::collections::HashSet;
 use std::fmt::Write;
 
+use binder::ThreadState;
+
 use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
     Algorithm::Algorithm, BlockMode::BlockMode, Digest::Digest, EcCurve::EcCurve,
     ErrorCode::ErrorCode, HardwareAuthenticatorType::HardwareAuthenticatorType,
     KeyOrigin::KeyOrigin, KeyParameter::KeyParameter, KeyParameterValue::KeyParameterValue,
-    KeyPurpose::KeyPurpose, PaddingMode::PaddingMode, Tag::Tag,
+    KeyPurpose::KeyPurpose, PaddingMode::PaddingMode, SecurityLevel::SecurityLevel, Tag::Tag,
 };
 use android_system_keystore2::aidl::android::system::keystore2::{
-    AuthenticatorSpec::AuthenticatorSpec, Authorization::Authorization, Domain::Domain,
+    AuthenticatorSpec::AuthenticatorSpec, Authorization::Authorization,
+    CreateOperationResponse::CreateOperationResponse, Domain::Domain,
     IKeystoreSecurityLevel::IKeystoreSecurityLevel, KeyDescriptor::KeyDescriptor,
     KeyMetadata::KeyMetadata, ResponseCode::ResponseCode,
 };
@@ -35,6 +38,11 @@
 use crate::authorizations::AuthSetBuilder;
 use android_system_keystore2::binder::{ExceptionCode, Result as BinderResult};
 
+use crate::ffi_test_utils::{
+    get_os_patchlevel, get_os_version, get_value_from_attest_record, get_vendor_patchlevel,
+    validate_certchain,
+};
+
 /// Shell namespace.
 pub const SELINUX_SHELL_NAMESPACE: i64 = 1;
 /// Vold namespace.
@@ -383,12 +391,23 @@
     })
 }
 
+/// Indicate whether the default device is KeyMint (rather than Keymaster).
+pub fn has_default_keymint() -> bool {
+    binder::is_declared("android.hardware.security.keymint.IKeyMintDevice/default")
+        .expect("Could not check for declared keymint interface")
+}
+
 /// Verify that given key param is listed in given authorizations list.
 pub fn check_key_param(authorizations: &[Authorization], key_param: &KeyParameter) -> bool {
     authorizations.iter().any(|auth| &auth.keyParameter == key_param)
 }
 
-fn check_key_authorizations(authorizations: &[Authorization], expected_params: &[KeyParameter]) {
+/// Verify the given key authorizations with the expected authorizations.
+pub fn check_key_authorizations(
+    authorizations: &[Authorization],
+    expected_params: &[KeyParameter],
+    expected_key_origin: KeyOrigin,
+) {
     // Make sure key authorizations contains only `ALLOWED_TAGS_IN_KEY_AUTHS`
     authorizations.iter().all(|auth| {
         assert!(
@@ -401,6 +420,13 @@
 
     //Check allowed-expected-key-parameters are present in given key authorizations list.
     expected_params.iter().all(|key_param| {
+        // `INCLUDE_UNIQUE_ID` is not strictly expected to be in key authorizations but has been
+        // put there by some implementations so cope with that.
+        if key_param.tag == Tag::INCLUDE_UNIQUE_ID
+            && !authorizations.iter().any(|auth| auth.keyParameter.tag == key_param.tag)
+        {
+            return true;
+        }
         if ALLOWED_TAGS_IN_KEY_AUTHS.contains(&key_param.tag) {
             assert!(
                 check_key_param(authorizations, key_param),
@@ -410,6 +436,73 @@
         }
         true
     });
+
+    check_common_auths(authorizations, expected_key_origin);
+}
+
+/// Verify common key authorizations.
+fn check_common_auths(authorizations: &[Authorization], expected_key_origin: KeyOrigin) {
+    assert!(check_key_param(
+        authorizations,
+        &KeyParameter {
+            tag: Tag::OS_VERSION,
+            value: KeyParameterValue::Integer(get_os_version().try_into().unwrap())
+        }
+    ));
+    assert!(check_key_param(
+        authorizations,
+        &KeyParameter {
+            tag: Tag::OS_PATCHLEVEL,
+            value: KeyParameterValue::Integer(get_os_patchlevel().try_into().unwrap())
+        }
+    ));
+
+    // Access denied for finding vendor-patch-level ("ro.vendor.build.security_patch") property
+    // in a test running with `untrusted_app` context. Keeping this check to verify
+    // vendor-patch-level in tests running with `su` context.
+    if getuid().is_root() {
+        assert!(check_key_param(
+            authorizations,
+            &KeyParameter {
+                tag: Tag::VENDOR_PATCHLEVEL,
+                value: KeyParameterValue::Integer(get_vendor_patchlevel().try_into().unwrap())
+            }
+        ));
+    }
+    assert!(check_key_param(
+        authorizations,
+        &KeyParameter { tag: Tag::ORIGIN, value: KeyParameterValue::Origin(expected_key_origin) }
+    ));
+    assert!(check_key_param(
+        authorizations,
+        &KeyParameter {
+            tag: Tag::USER_ID,
+            value: KeyParameterValue::Integer(
+                rustutils::users::multiuser_get_user_id(ThreadState::get_calling_uid())
+                    .try_into()
+                    .unwrap()
+            )
+        }
+    ));
+
+    if has_default_keymint() {
+        assert!(authorizations
+            .iter()
+            .map(|auth| &auth.keyParameter)
+            .any(|key_param| key_param.tag == Tag::CREATION_DATETIME));
+    }
+}
+
+/// Get the key `Authorization` for the given auth `Tag`.
+pub fn get_key_auth(authorizations: &[Authorization], tag: Tag) -> Option<&Authorization> {
+    let auths: Vec<&Authorization> =
+        authorizations.iter().filter(|auth| auth.keyParameter.tag == tag).collect();
+
+    if !auths.is_empty() {
+        Some(auths[0])
+    } else {
+        None
+    }
 }
 
 /// Generate EC Key using given security level and domain with below key parameters and
@@ -455,7 +548,11 @@
                 assert!(key_metadata.key.blob.is_some());
             }
 
-            check_key_authorizations(&key_metadata.authorizations, &gen_params);
+            check_key_authorizations(
+                &key_metadata.authorizations,
+                &gen_params,
+                KeyOrigin::GENERATED,
+            );
             Ok(key_metadata)
         }
         Err(e) => Err(e),
@@ -498,7 +595,7 @@
     } else {
         assert!(key_metadata.key.blob.is_none());
     }
-    check_key_authorizations(&key_metadata.authorizations, &gen_params);
+    check_key_authorizations(&key_metadata.authorizations, &gen_params, KeyOrigin::GENERATED);
     Ok(key_metadata)
 }
 
@@ -560,7 +657,7 @@
             || key_metadata.key.blob.is_none()
     );
 
-    check_key_authorizations(&key_metadata.authorizations, &gen_params);
+    check_key_authorizations(&key_metadata.authorizations, &gen_params, KeyOrigin::GENERATED);
     // If `RSA_OAEP_MGF_DIGEST` tag is not mentioned explicitly while generating/importing a key,
     // then make sure `RSA_OAEP_MGF_DIGEST` tag with default value (SHA1) must not be included in
     // key authorization list.
@@ -617,7 +714,7 @@
 
     // Should not have an attestation record.
     assert!(key_metadata.certificateChain.is_none());
-    check_key_authorizations(&key_metadata.authorizations, &gen_params);
+    check_key_authorizations(&key_metadata.authorizations, &gen_params, KeyOrigin::GENERATED);
     Ok(key_metadata)
 }
 
@@ -657,7 +754,7 @@
     // Should not have an attestation record.
     assert!(key_metadata.certificateChain.is_none());
 
-    check_key_authorizations(&key_metadata.authorizations, &gen_params);
+    check_key_authorizations(&key_metadata.authorizations, &gen_params, KeyOrigin::GENERATED);
     Ok(key_metadata)
 }
 
@@ -742,7 +839,11 @@
     // Should have an attestation record.
     assert!(attestation_key_metadata.certificateChain.is_some());
 
-    check_key_authorizations(&attestation_key_metadata.authorizations, &gen_params);
+    check_key_authorizations(
+        &attestation_key_metadata.authorizations,
+        &gen_params,
+        KeyOrigin::GENERATED,
+    );
     Ok(attestation_key_metadata)
 }
 
@@ -777,7 +878,7 @@
     // Shouldn't have an attestation record.
     assert!(ec_key_metadata.certificateChain.is_none());
 
-    check_key_authorizations(&ec_key_metadata.authorizations, &ec_gen_params);
+    check_key_authorizations(&ec_key_metadata.authorizations, &ec_gen_params, KeyOrigin::GENERATED);
     Ok(ec_key_metadata)
 }
 
@@ -802,7 +903,7 @@
     assert!(key_metadata.certificate.is_some());
     assert!(key_metadata.certificateChain.is_none());
 
-    check_key_authorizations(&key_metadata.authorizations, &import_params);
+    check_key_authorizations(&key_metadata.authorizations, &import_params, KeyOrigin::IMPORTED);
 
     // Check below auths explicitly, they might not be addd in import parameters.
     assert!(check_key_param(
@@ -865,7 +966,7 @@
     assert!(key_metadata.certificate.is_some());
     assert!(key_metadata.certificateChain.is_none());
 
-    check_key_authorizations(&key_metadata.authorizations, &import_params);
+    check_key_authorizations(&key_metadata.authorizations, &import_params, KeyOrigin::IMPORTED);
 
     // Check below auths explicitly, they might not be addd in import parameters.
     assert!(check_key_param(
@@ -917,7 +1018,7 @@
         AES_KEY,
     )?;
 
-    check_key_authorizations(&key_metadata.authorizations, &import_params);
+    check_key_authorizations(&key_metadata.authorizations, &import_params, KeyOrigin::IMPORTED);
 
     // Check below auths explicitly, they might not be addd in import parameters.
     assert!(check_key_param(
@@ -976,7 +1077,7 @@
         TRIPLE_DES_KEY,
     )?;
 
-    check_key_authorizations(&key_metadata.authorizations, &import_params);
+    check_key_authorizations(&key_metadata.authorizations, &import_params, KeyOrigin::IMPORTED);
 
     // Check below auths explicitly, they might not be addd in import parameters.
     assert!(check_key_param(
@@ -1036,7 +1137,7 @@
         HMAC_KEY,
     )?;
 
-    check_key_authorizations(&key_metadata.authorizations, &import_params);
+    check_key_authorizations(&key_metadata.authorizations, &import_params, KeyOrigin::IMPORTED);
 
     // Check below auths explicitly, they might not be addd in import parameters.
     assert!(check_key_param(
@@ -1188,7 +1289,11 @@
                 assert!(key_metadata.key.blob.is_some());
             }
 
-            check_key_authorizations(&key_metadata.authorizations, &gen_params);
+            check_key_authorizations(
+                &key_metadata.authorizations,
+                &gen_params,
+                KeyOrigin::GENERATED,
+            );
             Ok(key_metadata)
         }
         Err(e) => Err(e),
@@ -1288,3 +1393,77 @@
         b"entropy",
     )
 }
+
+/// Generate Key and validate key characteristics.
+pub fn generate_key(
+    sec_level: &binder::Strong<dyn IKeystoreSecurityLevel>,
+    gen_params: &AuthSetBuilder,
+    alias: &str,
+) -> binder::Result<KeyMetadata> {
+    let key_metadata = sec_level.generateKey(
+        &KeyDescriptor {
+            domain: Domain::APP,
+            nspace: -1,
+            alias: Some(alias.to_string()),
+            blob: None,
+        },
+        None,
+        gen_params,
+        0,
+        b"entropy",
+    )?;
+
+    if gen_params.iter().any(|kp| {
+        matches!(
+            kp.value,
+            KeyParameterValue::Algorithm(Algorithm::RSA)
+                | KeyParameterValue::Algorithm(Algorithm::EC)
+        )
+    }) {
+        assert!(key_metadata.certificate.is_some());
+        if gen_params.iter().any(|kp| kp.tag == Tag::ATTESTATION_CHALLENGE) {
+            assert!(key_metadata.certificateChain.is_some());
+            let mut cert_chain: Vec<u8> = Vec::new();
+            cert_chain.extend(key_metadata.certificate.as_ref().unwrap());
+            cert_chain.extend(key_metadata.certificateChain.as_ref().unwrap());
+            validate_certchain(&cert_chain).expect("Error while validating cert chain");
+        }
+
+        if let Some(challenge_param) =
+            gen_params.iter().find(|kp| kp.tag == Tag::ATTESTATION_CHALLENGE)
+        {
+            if let KeyParameterValue::Blob(val) = &challenge_param.value {
+                let att_challenge = get_value_from_attest_record(
+                    key_metadata.certificate.as_ref().unwrap(),
+                    challenge_param.tag,
+                    key_metadata.keySecurityLevel,
+                )
+                .expect("Attestation challenge verification failed.");
+                assert_eq!(&att_challenge, val);
+            }
+
+            let att_app_id = get_value_from_attest_record(
+                key_metadata.certificate.as_ref().unwrap(),
+                Tag::ATTESTATION_APPLICATION_ID,
+                SecurityLevel::KEYSTORE,
+            )
+            .expect("Attestation application id verification failed.");
+            assert!(!att_app_id.is_empty());
+        }
+    }
+    check_key_authorizations(&key_metadata.authorizations, gen_params, KeyOrigin::GENERATED);
+
+    Ok(key_metadata)
+}
+
+/// Generate a key using given authorizations and create an operation using the generated key.
+pub fn create_key_and_operation(
+    sec_level: &binder::Strong<dyn IKeystoreSecurityLevel>,
+    gen_params: &AuthSetBuilder,
+    op_params: &AuthSetBuilder,
+    alias: &str,
+) -> binder::Result<CreateOperationResponse> {
+    let key_metadata = generate_key(sec_level, gen_params, alias)?;
+
+    sec_level.createOperation(&key_metadata.key, op_params, false)
+}
diff --git a/keystore2/test_utils/lib.rs b/keystore2/test_utils/lib.rs
index c63bfac..8394ca1 100644
--- a/keystore2/test_utils/lib.rs
+++ b/keystore2/test_utils/lib.rs
@@ -20,12 +20,15 @@
 use std::{env::temp_dir, ops::Deref};
 
 use android_system_keystore2::aidl::android::system::keystore2::IKeystoreService::IKeystoreService;
+use android_security_authorization::aidl::android::security::authorization::IKeystoreAuthorization::IKeystoreAuthorization;
 
 pub mod authorizations;
+pub mod ffi_test_utils;
 pub mod key_generations;
 pub mod run_as;
 
 static KS2_SERVICE_NAME: &str = "android.system.keystore2.IKeystoreService/default";
+static AUTH_SERVICE_NAME: &str = "android.security.authorization";
 
 /// Represents the lifecycle of a temporary directory for testing.
 #[derive(Debug)]
@@ -115,3 +118,8 @@
 pub fn get_keystore_service() -> binder::Strong<dyn IKeystoreService> {
     binder::get_interface(KS2_SERVICE_NAME).unwrap()
 }
+
+/// Get Keystore auth service.
+pub fn get_keystore_auth_service() -> binder::Strong<dyn IKeystoreAuthorization> {
+    binder::get_interface(AUTH_SERVICE_NAME).unwrap()
+}
diff --git a/keystore2/tests/Android.bp b/keystore2/tests/Android.bp
index 32c39dc..e09b224 100644
--- a/keystore2/tests/Android.bp
+++ b/keystore2/tests/Android.bp
@@ -30,74 +30,21 @@
     srcs: ["keystore2_client_tests.rs"],
     test_suites: [
         "general-tests",
+        "vts",
     ],
     test_config: "AndroidTest.xml",
 
     rustlibs: [
-        "librustutils",
-        "libkeystore2_test_utils",
-        "packagemanager_aidl-rust",
-        "libnix",
-        "libanyhow",
+        "android.hardware.security.secureclock-V1-rust",
+        "android.security.authorization-rust",
+        "libaconfig_android_hardware_biometrics_rust",
         "libbinder_rs",
-        "liblazy_static",
-        "liblibc",
-        "libserde",
-        "libthiserror",
-        "libcxx",
+        "libkeystore2_test_utils",
+        "libnix",
         "libopenssl",
-    ],
-    static_libs: [
-        "libkeystore2_ffi_test_utils",
-        "libgtest",
-        "libkeymint_vts_test_utils",
-    ],
-    shared_libs: [
-        "libcrypto",
-        "libkeymaster_portable",
-        "libkeymaster_messages",
-        "libcppbor_external",
-        "libkeystore-engine",
-        "libkeymint_support",
+        "librustutils",
+        "libserde",
+        "packagemanager_aidl-rust",
     ],
     require_root: true,
 }
-
-cc_library_static {
-    name: "libkeystore2_ffi_test_utils",
-    srcs: ["ffi_test_utils.cpp"],
-    defaults: [
-        "keymint_vts_defaults",
-        "hidl_defaults",
-    ],
-    generated_headers: [
-        "cxx-bridge-header",
-        "libkeystore2_ffi_test_utils_bridge_header",
-    ],
-    generated_sources: ["libkeystore2_ffi_test_utils_bridge_code"],
-    static_libs: [
-        "libkeymint_vts_test_utils",
-    ],
-    shared_libs: [
-        "libkeymaster_portable",
-        "libkeymaster_messages",
-        "libcppbor_external",
-        "libkeystore-engine",
-    ],
-}
-
-genrule {
-    name: "libkeystore2_ffi_test_utils_bridge_code",
-    tools: ["cxxbridge"],
-    cmd: "$(location cxxbridge) $(in) >> $(out)",
-    srcs: ["ffi_test_utils.rs"],
-    out: ["libkeystore2_test_utils_cxx_generated.cc"],
-}
-
-genrule {
-    name: "libkeystore2_ffi_test_utils_bridge_header",
-    tools: ["cxxbridge"],
-    cmd: "$(location cxxbridge) $(in) --header >> $(out)",
-    srcs: ["ffi_test_utils.rs"],
-    out: ["ffi_test_utils.rs.h"],
-}
diff --git a/keystore2/tests/ffi_test_utils.hpp b/keystore2/tests/ffi_test_utils.hpp
deleted file mode 100644
index 3ed7edc..0000000
--- a/keystore2/tests/ffi_test_utils.hpp
+++ /dev/null
@@ -1,13 +0,0 @@
-#pragma once
-
-#include "rust/cxx.h"
-#include "ffi_test_utils.rs.h"
-
-bool validateCertChain(rust::Vec<rust::u8> cert_buf, uint32_t cert_len, bool strict_issuer_check);
-CxxResult createWrappedKey(rust::Vec<rust::u8> encrypted_secure_key,
-                              rust::Vec<rust::u8> encrypted_transport_key,
-                              rust::Vec<rust::u8> iv,
-                              rust::Vec<rust::u8> tag);
-CxxResult buildAsn1DerEncodedWrappedKeyDescription();
-bool performCryptoOpUsingKeystoreEngine(int64_t grant_id);
-CxxResult getValueFromAttestRecord(rust::Vec<rust::u8> cert_buf, int32_t tag);
diff --git a/keystore2/tests/keystore2_client_attest_key_tests.rs b/keystore2/tests/keystore2_client_attest_key_tests.rs
index b8ad90d..c9ef298 100644
--- a/keystore2/tests/keystore2_client_attest_key_tests.rs
+++ b/keystore2/tests/keystore2_client_attest_key_tests.rs
@@ -28,7 +28,7 @@
     authorizations, get_keystore_service, key_generations, key_generations::Error,
 };
 
-use crate::ffi_test_utils::{get_value_from_attest_record, validate_certchain};
+use keystore2_test_utils::ffi_test_utils::{get_value_from_attest_record, validate_certchain};
 
 use crate::{
     skip_test_if_no_app_attest_key_feature, skip_test_if_no_device_id_attestation_feature,
@@ -556,9 +556,12 @@
         cert_chain.extend(attest_key_metadata.certificateChain.as_ref().unwrap());
 
         validate_certchain(&cert_chain).expect("Error while validating cert chain");
-        let attest_id_value =
-            get_value_from_attest_record(key_metadata.certificate.as_ref().unwrap(), attest_id)
-                .expect("Attest id verification failed.");
+        let attest_id_value = get_value_from_attest_record(
+            key_metadata.certificate.as_ref().unwrap(),
+            attest_id,
+            SecurityLevel::TRUSTED_ENVIRONMENT,
+        )
+        .expect("Attest id verification failed.");
         assert_eq!(attest_id_value, value);
     }
 }
diff --git a/keystore2/tests/keystore2_client_authorizations_tests.rs b/keystore2/tests/keystore2_client_authorizations_tests.rs
new file mode 100644
index 0000000..279ecd7
--- /dev/null
+++ b/keystore2/tests/keystore2_client_authorizations_tests.rs
@@ -0,0 +1,966 @@
+// 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.
+
+use std::time::SystemTime;
+
+use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
+    Algorithm::Algorithm, BlockMode::BlockMode, Digest::Digest, EcCurve::EcCurve,
+    ErrorCode::ErrorCode, KeyPurpose::KeyPurpose, PaddingMode::PaddingMode,
+    SecurityLevel::SecurityLevel, Tag::Tag,
+};
+
+use android_system_keystore2::aidl::android::system::keystore2::{
+    Domain::Domain, IKeystoreSecurityLevel::IKeystoreSecurityLevel, KeyDescriptor::KeyDescriptor,
+    KeyMetadata::KeyMetadata, ResponseCode::ResponseCode,
+};
+
+use aconfig_android_hardware_biometrics_rust;
+use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
+    HardwareAuthToken::HardwareAuthToken,
+    HardwareAuthenticatorType::HardwareAuthenticatorType
+};
+use android_hardware_security_secureclock::aidl::android::hardware::security::secureclock::Timestamp::Timestamp;
+
+use keystore2_test_utils::{
+    authorizations, get_keystore_auth_service, get_keystore_service, key_generations,
+    key_generations::Error,
+};
+
+use crate::keystore2_client_test_utils::{
+    delete_app_key, perform_sample_asym_sign_verify_op, perform_sample_hmac_sign_verify_op,
+    perform_sample_sym_key_decrypt_op, perform_sample_sym_key_encrypt_op, SAMPLE_PLAIN_TEXT,
+};
+
+use keystore2_test_utils::ffi_test_utils::get_value_from_attest_record;
+
+fn gen_key_including_unique_id(
+    sec_level: &binder::Strong<dyn IKeystoreSecurityLevel>,
+    alias: &str,
+) -> Vec<u8> {
+    let gen_params = authorizations::AuthSetBuilder::new()
+        .no_auth_required()
+        .algorithm(Algorithm::EC)
+        .purpose(KeyPurpose::SIGN)
+        .purpose(KeyPurpose::VERIFY)
+        .digest(Digest::SHA_2_256)
+        .ec_curve(EcCurve::P_256)
+        .attestation_challenge(b"foo".to_vec())
+        .include_unique_id();
+
+    let key_metadata = key_generations::generate_key(sec_level, &gen_params, alias).unwrap();
+
+    let unique_id = get_value_from_attest_record(
+        key_metadata.certificate.as_ref().unwrap(),
+        Tag::UNIQUE_ID,
+        key_metadata.keySecurityLevel,
+    )
+    .expect("Unique id not found.");
+    assert!(!unique_id.is_empty());
+    unique_id
+}
+
+fn generate_key_and_perform_sign_verify_op_max_times(
+    sec_level: &binder::Strong<dyn IKeystoreSecurityLevel>,
+    gen_params: &authorizations::AuthSetBuilder,
+    alias: &str,
+    max_usage_count: i32,
+) -> binder::Result<KeyMetadata> {
+    let key_metadata = key_generations::generate_key(sec_level, gen_params, alias)?;
+
+    // Use above generated key `max_usage_count` times.
+    for _ in 0..max_usage_count {
+        perform_sample_asym_sign_verify_op(sec_level, &key_metadata, None, Some(Digest::SHA_2_256));
+    }
+
+    Ok(key_metadata)
+}
+
+/// Generate a key with `USAGE_COUNT_LIMIT` and verify the key characteristics. Test should be able
+/// to use the key successfully `max_usage_count` times. After exceeding key usage `max_usage_count`
+/// times subsequent attempts to use the key in test should fail with response code `KEY_NOT_FOUND`.
+/// Test should also verify that the attest record includes `USAGE_COUNT_LIMIT` for attested keys.
+fn generate_key_and_perform_op_with_max_usage_limit(
+    sec_level: &binder::Strong<dyn IKeystoreSecurityLevel>,
+    gen_params: &authorizations::AuthSetBuilder,
+    alias: &str,
+    max_usage_count: i32,
+    check_attestation: bool,
+) {
+    // Generate a key and use the key for `max_usage_count` times.
+    let key_metadata = generate_key_and_perform_sign_verify_op_max_times(
+        sec_level,
+        gen_params,
+        alias,
+        max_usage_count,
+    )
+    .unwrap();
+
+    let auth = key_generations::get_key_auth(&key_metadata.authorizations, Tag::USAGE_COUNT_LIMIT)
+        .unwrap();
+    if check_attestation {
+        // Check usage-count-limit is included in attest-record.
+        assert_ne!(
+            gen_params.iter().filter(|kp| kp.tag == Tag::ATTESTATION_CHALLENGE).count(),
+            0,
+            "Attestation challenge is missing in generated key parameters."
+        );
+        let result = get_value_from_attest_record(
+            key_metadata.certificate.as_ref().unwrap(),
+            Tag::USAGE_COUNT_LIMIT,
+            auth.securityLevel,
+        )
+        .expect("Attest id verification failed.");
+        let usage_count: i32 = std::str::from_utf8(&result).unwrap().parse().unwrap();
+        assert_eq!(usage_count, max_usage_count);
+    }
+    if max_usage_count == 1 {
+        assert!(matches!(
+            auth.securityLevel,
+            SecurityLevel::KEYSTORE | SecurityLevel::TRUSTED_ENVIRONMENT
+        ));
+    } else {
+        assert_eq!(auth.securityLevel, SecurityLevel::KEYSTORE);
+    }
+
+    // Try to use the key one more time.
+    let result = key_generations::map_ks_error(sec_level.createOperation(
+        &key_metadata.key,
+        &authorizations::AuthSetBuilder::new().purpose(KeyPurpose::SIGN).digest(Digest::SHA_2_256),
+        false,
+    ));
+    assert!(result.is_err());
+    assert_eq!(Error::Rc(ResponseCode::KEY_NOT_FOUND), result.unwrap_err());
+}
+
+/// Generate a key with `ACTIVE_DATETIME` set to current time. Test should successfully generate
+/// a key and verify the key characteristics. Test should be able to create a sign operation using
+/// the generated key successfully.
+#[test]
+fn keystore2_gen_key_auth_active_datetime_test_success() {
+    let keystore2 = get_keystore_service();
+    let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+
+    let duration_since_epoch = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap();
+    let active_datetime = duration_since_epoch.as_millis();
+    let gen_params = authorizations::AuthSetBuilder::new()
+        .no_auth_required()
+        .algorithm(Algorithm::EC)
+        .purpose(KeyPurpose::SIGN)
+        .purpose(KeyPurpose::VERIFY)
+        .digest(Digest::SHA_2_256)
+        .ec_curve(EcCurve::P_256)
+        .attestation_challenge(b"foo".to_vec())
+        .active_date_time(active_datetime.try_into().unwrap());
+
+    let alias = "ks_test_auth_tags_test";
+    let result = key_generations::create_key_and_operation(
+        &sec_level,
+        &gen_params,
+        &authorizations::AuthSetBuilder::new().purpose(KeyPurpose::SIGN).digest(Digest::SHA_2_256),
+        alias,
+    );
+    assert!(result.is_ok());
+    delete_app_key(&keystore2, alias).unwrap();
+}
+
+/// Generate a key with `ACTIVE_DATETIME` set to future date and time. Test should successfully
+/// generate a key and verify the key characteristics. Try to create a sign operation
+/// using the generated key, test should fail to create an operation with error code
+/// `KEY_NOT_YET_VALID`.
+#[test]
+fn keystore2_gen_key_auth_future_active_datetime_test_op_fail() {
+    let keystore2 = get_keystore_service();
+    let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+
+    let duration_since_epoch = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap();
+    let future_active_datetime = duration_since_epoch.as_millis() + (24 * 60 * 60 * 1000);
+    let gen_params = authorizations::AuthSetBuilder::new()
+        .no_auth_required()
+        .algorithm(Algorithm::EC)
+        .purpose(KeyPurpose::SIGN)
+        .purpose(KeyPurpose::VERIFY)
+        .digest(Digest::SHA_2_256)
+        .ec_curve(EcCurve::P_256)
+        .attestation_challenge(b"foo".to_vec())
+        .active_date_time(future_active_datetime.try_into().unwrap());
+
+    let alias = "ks_test_auth_tags_test";
+    let result = key_generations::map_ks_error(key_generations::create_key_and_operation(
+        &sec_level,
+        &gen_params,
+        &authorizations::AuthSetBuilder::new().purpose(KeyPurpose::SIGN).digest(Digest::SHA_2_256),
+        alias,
+    ));
+    assert!(result.is_err());
+    assert_eq!(Error::Km(ErrorCode::KEY_NOT_YET_VALID), result.unwrap_err());
+    delete_app_key(&keystore2, alias).unwrap();
+}
+
+/// Generate a key with `ORIGINATION_EXPIRE_DATETIME` set to future date and time. Test should
+/// successfully generate a key and verify the key characteristics. Test should be able to create
+/// sign operation using the generated key successfully.
+#[test]
+fn keystore2_gen_key_auth_future_origination_expire_datetime_test_success() {
+    let keystore2 = get_keystore_service();
+    let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+
+    let duration_since_epoch = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap();
+    let origination_expire_datetime = duration_since_epoch.as_millis() + (24 * 60 * 60 * 1000);
+    let gen_params = authorizations::AuthSetBuilder::new()
+        .no_auth_required()
+        .algorithm(Algorithm::EC)
+        .purpose(KeyPurpose::SIGN)
+        .purpose(KeyPurpose::VERIFY)
+        .digest(Digest::SHA_2_256)
+        .ec_curve(EcCurve::P_256)
+        .attestation_challenge(b"foo".to_vec())
+        .origination_expire_date_time(origination_expire_datetime.try_into().unwrap());
+
+    let alias = "ks_test_auth_tags_test";
+    let result = key_generations::create_key_and_operation(
+        &sec_level,
+        &gen_params,
+        &authorizations::AuthSetBuilder::new().purpose(KeyPurpose::SIGN).digest(Digest::SHA_2_256),
+        alias,
+    );
+    assert!(result.is_ok());
+    delete_app_key(&keystore2, alias).unwrap();
+}
+
+/// Generate a key with `ORIGINATION_EXPIRE_DATETIME` set to current date and time. Test should
+/// successfully generate a key and verify the key characteristics. Try to create a sign operation
+/// using the generated key, test should fail to create an operation with error code
+/// `KEY_EXPIRED`.
+#[test]
+fn keystore2_gen_key_auth_origination_expire_datetime_test_op_fail() {
+    let keystore2 = get_keystore_service();
+    let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+
+    let duration_since_epoch = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap();
+    let origination_expire_datetime = duration_since_epoch.as_millis();
+    let gen_params = authorizations::AuthSetBuilder::new()
+        .no_auth_required()
+        .algorithm(Algorithm::EC)
+        .purpose(KeyPurpose::SIGN)
+        .purpose(KeyPurpose::VERIFY)
+        .digest(Digest::SHA_2_256)
+        .ec_curve(EcCurve::P_256)
+        .attestation_challenge(b"foo".to_vec())
+        .origination_expire_date_time(origination_expire_datetime.try_into().unwrap());
+
+    let alias = "ks_test_auth_tags_test";
+    let result = key_generations::map_ks_error(key_generations::create_key_and_operation(
+        &sec_level,
+        &gen_params,
+        &authorizations::AuthSetBuilder::new().purpose(KeyPurpose::SIGN).digest(Digest::SHA_2_256),
+        alias,
+    ));
+    assert!(result.is_err());
+    assert_eq!(Error::Km(ErrorCode::KEY_EXPIRED), result.unwrap_err());
+    delete_app_key(&keystore2, alias).unwrap();
+}
+
+/// Generate a HMAC key with `USAGE_EXPIRE_DATETIME` set to future date and time. Test should
+/// successfully generate a key and verify the key characteristics. Test should be able to create
+/// sign and verify operations using the generated key successfully.
+#[test]
+fn keystore2_gen_key_auth_future_usage_expire_datetime_hmac_verify_op_success() {
+    let keystore2 = get_keystore_service();
+    let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+
+    let duration_since_epoch = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap();
+    let usage_expire_datetime = duration_since_epoch.as_millis() + (24 * 60 * 60 * 1000);
+    let gen_params = authorizations::AuthSetBuilder::new()
+        .no_auth_required()
+        .algorithm(Algorithm::HMAC)
+        .purpose(KeyPurpose::SIGN)
+        .purpose(KeyPurpose::VERIFY)
+        .key_size(128)
+        .min_mac_length(256)
+        .digest(Digest::SHA_2_256)
+        .usage_expire_date_time(usage_expire_datetime.try_into().unwrap());
+
+    let alias = "ks_test_auth_tags_hmac_verify_success";
+    let key_metadata = key_generations::generate_key(&sec_level, &gen_params, alias).unwrap();
+
+    perform_sample_hmac_sign_verify_op(&sec_level, &key_metadata.key);
+    delete_app_key(&keystore2, alias).unwrap();
+}
+
+/// Generate a key with `USAGE_EXPIRE_DATETIME` set to current date and time. Test should
+/// successfully generate a key and verify the key characteristics. Test should be able to create
+/// sign operation successfully and fail while performing verify operation with error code
+/// `KEY_EXPIRED`.
+#[test]
+fn keystore2_gen_key_auth_usage_expire_datetime_hmac_verify_op_fail() {
+    let keystore2 = get_keystore_service();
+    let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+
+    let duration_since_epoch = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap();
+    let usage_expire_datetime = duration_since_epoch.as_millis();
+    let gen_params = authorizations::AuthSetBuilder::new()
+        .no_auth_required()
+        .algorithm(Algorithm::HMAC)
+        .purpose(KeyPurpose::SIGN)
+        .purpose(KeyPurpose::VERIFY)
+        .key_size(128)
+        .min_mac_length(256)
+        .digest(Digest::SHA_2_256)
+        .usage_expire_date_time(usage_expire_datetime.try_into().unwrap());
+
+    let alias = "ks_test_auth_tags_hamc_verify_fail";
+    let key_metadata = key_generations::generate_key(&sec_level, &gen_params, alias).unwrap();
+
+    let result = key_generations::map_ks_error(
+        sec_level.createOperation(
+            &key_metadata.key,
+            &authorizations::AuthSetBuilder::new()
+                .purpose(KeyPurpose::VERIFY)
+                .digest(Digest::SHA_2_256),
+            false,
+        ),
+    );
+    assert!(result.is_err());
+    assert_eq!(Error::Km(ErrorCode::KEY_EXPIRED), result.unwrap_err());
+    delete_app_key(&keystore2, alias).unwrap();
+}
+
+/// Generate AES key with `USAGE_EXPIRE_DATETIME` set to future date and time. Test should
+/// successfully generate a key and verify the key characteristics. Test should be able to create
+/// Encrypt and Decrypt operations successfully.
+#[test]
+fn keystore2_gen_key_auth_usage_future_expire_datetime_decrypt_op_success() {
+    let keystore2 = get_keystore_service();
+    let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+
+    let duration_since_epoch = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap();
+    let usage_expire_datetime = duration_since_epoch.as_millis() + (24 * 60 * 60 * 1000);
+    let gen_params = authorizations::AuthSetBuilder::new()
+        .no_auth_required()
+        .algorithm(Algorithm::AES)
+        .purpose(KeyPurpose::ENCRYPT)
+        .purpose(KeyPurpose::DECRYPT)
+        .key_size(128)
+        .padding_mode(PaddingMode::PKCS7)
+        .block_mode(BlockMode::ECB)
+        .usage_expire_date_time(usage_expire_datetime.try_into().unwrap());
+
+    let alias = "ks_test_auth_tags_test";
+    let key_metadata = key_generations::generate_key(&sec_level, &gen_params, alias).unwrap();
+    let cipher_text = perform_sample_sym_key_encrypt_op(
+        &sec_level,
+        PaddingMode::PKCS7,
+        BlockMode::ECB,
+        &mut None,
+        None,
+        &key_metadata.key,
+    )
+    .unwrap();
+
+    assert!(cipher_text.is_some());
+
+    let plain_text = perform_sample_sym_key_decrypt_op(
+        &sec_level,
+        &cipher_text.unwrap(),
+        PaddingMode::PKCS7,
+        BlockMode::ECB,
+        &mut None,
+        None,
+        &key_metadata.key,
+    )
+    .unwrap();
+    assert!(plain_text.is_some());
+    assert_eq!(plain_text.unwrap(), SAMPLE_PLAIN_TEXT.to_vec());
+    delete_app_key(&keystore2, alias).unwrap();
+}
+
+/// Generate AES key with `USAGE_EXPIRE_DATETIME` set to current date and time. Test should
+/// successfully generate a key and verify the key characteristics. Test should be able to create
+/// Encrypt operation successfully and fail while performing decrypt operation with error code
+/// `KEY_EXPIRED`.
+#[test]
+fn keystore2_gen_key_auth_usage_expire_datetime_decrypt_op_fail() {
+    let keystore2 = get_keystore_service();
+    let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+
+    let duration_since_epoch = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap();
+    let usage_expire_datetime = duration_since_epoch.as_millis();
+    let gen_params = authorizations::AuthSetBuilder::new()
+        .no_auth_required()
+        .algorithm(Algorithm::AES)
+        .purpose(KeyPurpose::ENCRYPT)
+        .purpose(KeyPurpose::DECRYPT)
+        .key_size(128)
+        .padding_mode(PaddingMode::PKCS7)
+        .block_mode(BlockMode::ECB)
+        .usage_expire_date_time(usage_expire_datetime.try_into().unwrap());
+
+    let alias = "ks_test_auth_tags_test";
+    let key_metadata = key_generations::generate_key(&sec_level, &gen_params, alias).unwrap();
+    let cipher_text = perform_sample_sym_key_encrypt_op(
+        &sec_level,
+        PaddingMode::PKCS7,
+        BlockMode::ECB,
+        &mut None,
+        None,
+        &key_metadata.key,
+    )
+    .unwrap();
+
+    assert!(cipher_text.is_some());
+
+    let result = key_generations::map_ks_error(perform_sample_sym_key_decrypt_op(
+        &sec_level,
+        &cipher_text.unwrap(),
+        PaddingMode::PKCS7,
+        BlockMode::ECB,
+        &mut None,
+        None,
+        &key_metadata.key,
+    ));
+    assert!(result.is_err());
+    assert_eq!(Error::Km(ErrorCode::KEY_EXPIRED), result.unwrap_err());
+    delete_app_key(&keystore2, alias).unwrap();
+}
+
+/// Generate a key with `BOOTLOADER_ONLY`. Test should successfully generate
+/// a key and verify the key characteristics. Test should fail with error code `INVALID_KEY_BLOB`
+/// during creation of an operation using this key.
+#[test]
+fn keystore2_gen_key_auth_boot_loader_only_op_fail() {
+    let keystore2 = get_keystore_service();
+    let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+
+    let gen_params = authorizations::AuthSetBuilder::new()
+        .no_auth_required()
+        .algorithm(Algorithm::EC)
+        .purpose(KeyPurpose::SIGN)
+        .purpose(KeyPurpose::VERIFY)
+        .digest(Digest::SHA_2_256)
+        .ec_curve(EcCurve::P_256)
+        .attestation_challenge(b"foo".to_vec())
+        .boot_loader_only();
+
+    let alias = "ks_test_auth_tags_test";
+    let result = key_generations::map_ks_error(key_generations::create_key_and_operation(
+        &sec_level,
+        &gen_params,
+        &authorizations::AuthSetBuilder::new().purpose(KeyPurpose::SIGN).digest(Digest::SHA_2_256),
+        alias,
+    ));
+    assert!(result.is_err());
+    assert_eq!(Error::Km(ErrorCode::INVALID_KEY_BLOB), result.unwrap_err());
+}
+
+/// Generate a key with `EARLY_BOOT_ONLY`. Test should successfully generate
+/// a key and verify the key characteristics. Test should fail with error code `EARLY_BOOT_ENDED`
+/// during creation of an operation using this key.
+#[test]
+fn keystore2_gen_key_auth_early_boot_only_op_fail() {
+    let keystore2 = get_keystore_service();
+    let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+
+    let gen_params = authorizations::AuthSetBuilder::new()
+        .no_auth_required()
+        .algorithm(Algorithm::EC)
+        .purpose(KeyPurpose::SIGN)
+        .purpose(KeyPurpose::VERIFY)
+        .digest(Digest::SHA_2_256)
+        .ec_curve(EcCurve::P_256)
+        .attestation_challenge(b"foo".to_vec())
+        .early_boot_only();
+
+    let alias = "ks_test_auth_tags_test";
+    let result = key_generations::map_ks_error(key_generations::create_key_and_operation(
+        &sec_level,
+        &gen_params,
+        &authorizations::AuthSetBuilder::new().purpose(KeyPurpose::SIGN).digest(Digest::SHA_2_256),
+        alias,
+    ));
+    assert!(result.is_err());
+    assert_eq!(Error::Km(ErrorCode::EARLY_BOOT_ENDED), result.unwrap_err());
+    delete_app_key(&keystore2, alias).unwrap();
+}
+
+/// Generate a key with `MAX_USES_PER_BOOT`. Test should successfully generate
+/// a key and verify the key characteristics. Test should be able to use the key successfully
+/// `MAX_USES_COUNT` times. After exceeding key usage `MAX_USES_COUNT` times
+/// subsequent attempts to use the key in test should fail with error code MAX_OPS_EXCEEDED.
+#[test]
+fn keystore2_gen_key_auth_max_uses_per_boot() {
+    let keystore2 = get_keystore_service();
+    let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+    const MAX_USES_COUNT: i32 = 3;
+
+    let gen_params = authorizations::AuthSetBuilder::new()
+        .no_auth_required()
+        .algorithm(Algorithm::EC)
+        .purpose(KeyPurpose::SIGN)
+        .purpose(KeyPurpose::VERIFY)
+        .digest(Digest::SHA_2_256)
+        .ec_curve(EcCurve::P_256)
+        .attestation_challenge(b"foo".to_vec())
+        .max_uses_per_boot(MAX_USES_COUNT);
+
+    let alias = "ks_test_auth_tags_test";
+    // Generate a key and use the key for `MAX_USES_COUNT` times.
+    let key_metadata = generate_key_and_perform_sign_verify_op_max_times(
+        &sec_level,
+        &gen_params,
+        alias,
+        MAX_USES_COUNT,
+    )
+    .unwrap();
+
+    // Try to use the key one more time.
+    let result = key_generations::map_ks_error(sec_level.createOperation(
+        &key_metadata.key,
+        &authorizations::AuthSetBuilder::new().purpose(KeyPurpose::SIGN).digest(Digest::SHA_2_256),
+        false,
+    ));
+    assert!(result.is_err());
+    assert_eq!(Error::Km(ErrorCode::KEY_MAX_OPS_EXCEEDED), result.unwrap_err());
+    delete_app_key(&keystore2, alias).unwrap();
+}
+
+/// Generate a key with `USAGE_COUNT_LIMIT`. Test should successfully generate
+/// a key and verify the key characteristics. Test should be able to use the key successfully
+/// `MAX_USES_COUNT` times. After exceeding key usage `MAX_USES_COUNT` times
+/// subsequent attempts to use the key in test should fail with response code `KEY_NOT_FOUND`.
+/// Test should also verify that the attest record includes `USAGE_COUNT_LIMIT`.
+#[test]
+fn keystore2_gen_key_auth_usage_count_limit() {
+    let keystore2 = get_keystore_service();
+    let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+    const MAX_USES_COUNT: i32 = 3;
+
+    let gen_params = authorizations::AuthSetBuilder::new()
+        .no_auth_required()
+        .algorithm(Algorithm::EC)
+        .purpose(KeyPurpose::SIGN)
+        .purpose(KeyPurpose::VERIFY)
+        .digest(Digest::SHA_2_256)
+        .ec_curve(EcCurve::P_256)
+        .attestation_challenge(b"foo".to_vec())
+        .usage_count_limit(MAX_USES_COUNT);
+
+    let alias = "ks_test_auth_tags_test";
+    generate_key_and_perform_op_with_max_usage_limit(
+        &sec_level,
+        &gen_params,
+        alias,
+        MAX_USES_COUNT,
+        true,
+    );
+}
+
+/// Generate a key with `USAGE_COUNT_LIMIT`. Test should successfully generate
+/// a key and verify the key characteristics. Test should be able to use the key successfully
+/// `MAX_USES_COUNT` times. After exceeding key usage `MAX_USES_COUNT` times
+/// subsequent attempts to use the key in test should fail with response code `KEY_NOT_FOUND`.
+/// Test should also verify that the attest record includes `USAGE_COUNT_LIMIT`.
+#[test]
+fn keystore2_gen_key_auth_usage_count_limit_one() {
+    let keystore2 = get_keystore_service();
+    let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+    const MAX_USES_COUNT: i32 = 1;
+
+    let gen_params = authorizations::AuthSetBuilder::new()
+        .no_auth_required()
+        .algorithm(Algorithm::EC)
+        .purpose(KeyPurpose::SIGN)
+        .purpose(KeyPurpose::VERIFY)
+        .digest(Digest::SHA_2_256)
+        .ec_curve(EcCurve::P_256)
+        .attestation_challenge(b"foo".to_vec())
+        .usage_count_limit(MAX_USES_COUNT);
+
+    let alias = "ks_test_auth_tags_test";
+    generate_key_and_perform_op_with_max_usage_limit(
+        &sec_level,
+        &gen_params,
+        alias,
+        MAX_USES_COUNT,
+        true,
+    );
+}
+
+/// Generate a non-attested key with `USAGE_COUNT_LIMIT`. Test should successfully generate
+/// a key and verify the key characteristics. Test should be able to use the key successfully
+/// `MAX_USES_COUNT` times. After exceeding key usage `MAX_USES_COUNT` times
+/// subsequent attempts to use the key in test should fail with response code `KEY_NOT_FOUND`.
+#[test]
+fn keystore2_gen_non_attested_key_auth_usage_count_limit() {
+    let keystore2 = get_keystore_service();
+    let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+    const MAX_USES_COUNT: i32 = 2;
+
+    let gen_params = authorizations::AuthSetBuilder::new()
+        .no_auth_required()
+        .algorithm(Algorithm::EC)
+        .purpose(KeyPurpose::SIGN)
+        .purpose(KeyPurpose::VERIFY)
+        .digest(Digest::SHA_2_256)
+        .ec_curve(EcCurve::P_256)
+        .usage_count_limit(MAX_USES_COUNT);
+
+    let alias = "ks_test_auth_tags_test";
+    generate_key_and_perform_op_with_max_usage_limit(
+        &sec_level,
+        &gen_params,
+        alias,
+        MAX_USES_COUNT,
+        false,
+    );
+}
+
+/// Try to generate a key with `Tag::CREATION_DATETIME` set to valid value. Test should fail
+/// to generate a key with `INVALID_ARGUMENT` error as Keystore2 backend doesn't allow user to
+/// specify `CREATION_DATETIME`.
+#[test]
+fn keystore2_gen_key_auth_creation_date_time_test_fail_with_invalid_arg_error() {
+    let keystore2 = get_keystore_service();
+    let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+
+    let duration_since_epoch = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap();
+    let creation_datetime = duration_since_epoch.as_millis();
+    let gen_params = authorizations::AuthSetBuilder::new()
+        .no_auth_required()
+        .algorithm(Algorithm::EC)
+        .purpose(KeyPurpose::SIGN)
+        .purpose(KeyPurpose::VERIFY)
+        .digest(Digest::SHA_2_256)
+        .ec_curve(EcCurve::P_256)
+        .attestation_challenge(b"foo".to_vec())
+        .creation_date_time(creation_datetime.try_into().unwrap());
+
+    let alias = "ks_test_auth_tags_test";
+    let result = key_generations::map_ks_error(sec_level.generateKey(
+        &KeyDescriptor {
+            domain: Domain::APP,
+            nspace: -1,
+            alias: Some(alias.to_string()),
+            blob: None,
+        },
+        None,
+        &gen_params,
+        0,
+        b"entropy",
+    ));
+
+    assert!(result.is_err());
+    assert_eq!(Error::Rc(ResponseCode::INVALID_ARGUMENT), result.unwrap_err());
+}
+
+/// Generate a key with `Tag::INCLUDE_UNIQUE_ID` set. Test should verify that `Tag::UNIQUE_ID` is
+/// included in attest record and it remains the same for new keys generated.
+#[test]
+fn keystore2_gen_key_auth_include_unique_id_success() {
+    let keystore2 = get_keystore_service();
+    let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+
+    let alias_first = "ks_test_auth_tags_test_1";
+    let unique_id_first = gen_key_including_unique_id(&sec_level, alias_first);
+
+    let alias_second = "ks_test_auth_tags_test_2";
+    let unique_id_second = gen_key_including_unique_id(&sec_level, alias_second);
+
+    assert_eq!(unique_id_first, unique_id_second);
+
+    delete_app_key(&keystore2, alias_first).unwrap();
+    delete_app_key(&keystore2, alias_second).unwrap();
+}
+
+/// Generate a key with `APPLICATION_DATA`. Test should create an operation using the
+/// same `APPLICATION_DATA` successfully.
+#[test]
+fn keystore2_gen_key_auth_app_data_test_success() {
+    let keystore2 = get_keystore_service();
+    let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+
+    let gen_params = authorizations::AuthSetBuilder::new()
+        .no_auth_required()
+        .algorithm(Algorithm::EC)
+        .purpose(KeyPurpose::SIGN)
+        .purpose(KeyPurpose::VERIFY)
+        .digest(Digest::SHA_2_256)
+        .ec_curve(EcCurve::P_256)
+        .app_data(b"app-data".to_vec());
+
+    let alias = "ks_test_auth_tags_test";
+    let result = key_generations::create_key_and_operation(
+        &sec_level,
+        &gen_params,
+        &authorizations::AuthSetBuilder::new()
+            .purpose(KeyPurpose::SIGN)
+            .digest(Digest::SHA_2_256)
+            .app_data(b"app-data".to_vec()),
+        alias,
+    );
+    assert!(result.is_ok());
+    delete_app_key(&keystore2, alias).unwrap();
+}
+
+/// Generate a key with `APPLICATION_DATA`. Try to create an operation using the
+/// different `APPLICATION_DATA`, test should fail to create an operation with error code
+/// `INVALID_KEY_BLOB`.
+#[test]
+fn keystore2_gen_key_auth_app_data_test_fail() {
+    let keystore2 = get_keystore_service();
+    let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+
+    let gen_params = authorizations::AuthSetBuilder::new()
+        .no_auth_required()
+        .algorithm(Algorithm::EC)
+        .purpose(KeyPurpose::SIGN)
+        .purpose(KeyPurpose::VERIFY)
+        .digest(Digest::SHA_2_256)
+        .ec_curve(EcCurve::P_256)
+        .app_data(b"app-data".to_vec());
+
+    let alias = "ks_test_auth_tags_test";
+    let result = key_generations::map_ks_error(key_generations::create_key_and_operation(
+        &sec_level,
+        &gen_params,
+        &authorizations::AuthSetBuilder::new()
+            .purpose(KeyPurpose::SIGN)
+            .digest(Digest::SHA_2_256)
+            .app_data(b"invalid-app-data".to_vec()),
+        alias,
+    ));
+    assert!(result.is_err());
+    assert_eq!(Error::Km(ErrorCode::INVALID_KEY_BLOB), result.unwrap_err());
+    delete_app_key(&keystore2, alias).unwrap();
+}
+
+/// Generate a key with `APPLICATION_ID`. Test should create an operation using the
+/// same `APPLICATION_ID` successfully.
+#[test]
+fn keystore2_gen_key_auth_app_id_test_success() {
+    let keystore2 = get_keystore_service();
+    let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+
+    let gen_params = authorizations::AuthSetBuilder::new()
+        .no_auth_required()
+        .algorithm(Algorithm::EC)
+        .purpose(KeyPurpose::SIGN)
+        .purpose(KeyPurpose::VERIFY)
+        .digest(Digest::SHA_2_256)
+        .ec_curve(EcCurve::P_256)
+        .app_id(b"app-id".to_vec());
+
+    let alias = "ks_test_auth_tags_test";
+    let result = key_generations::create_key_and_operation(
+        &sec_level,
+        &gen_params,
+        &authorizations::AuthSetBuilder::new()
+            .purpose(KeyPurpose::SIGN)
+            .digest(Digest::SHA_2_256)
+            .app_id(b"app-id".to_vec()),
+        alias,
+    );
+    assert!(result.is_ok());
+    delete_app_key(&keystore2, alias).unwrap();
+}
+
+/// Generate a key with `APPLICATION_ID`. Try to create an operation using the
+/// different `APPLICATION_ID`, test should fail to create an operation with error code
+/// `INVALID_KEY_BLOB`.
+#[test]
+fn keystore2_gen_key_auth_app_id_test_fail() {
+    let keystore2 = get_keystore_service();
+    let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+
+    let gen_params = authorizations::AuthSetBuilder::new()
+        .no_auth_required()
+        .algorithm(Algorithm::EC)
+        .purpose(KeyPurpose::SIGN)
+        .purpose(KeyPurpose::VERIFY)
+        .digest(Digest::SHA_2_256)
+        .ec_curve(EcCurve::P_256)
+        .app_id(b"app-id".to_vec());
+
+    let alias = "ks_test_auth_tags_test";
+    let result = key_generations::map_ks_error(key_generations::create_key_and_operation(
+        &sec_level,
+        &gen_params,
+        &authorizations::AuthSetBuilder::new()
+            .purpose(KeyPurpose::SIGN)
+            .digest(Digest::SHA_2_256)
+            .app_id(b"invalid-app-id".to_vec()),
+        alias,
+    ));
+    assert!(result.is_err());
+    assert_eq!(Error::Km(ErrorCode::INVALID_KEY_BLOB), result.unwrap_err());
+    delete_app_key(&keystore2, alias).unwrap();
+}
+
+/// Generate an attestation-key without specifying `APPLICATION_ID` and `APPLICATION_DATA`.
+/// Test should be able to generate a new key with specifying app-id and app-data using previously
+/// generated attestation-key.
+#[test]
+fn keystore2_gen_attested_key_auth_app_id_app_data_test_success() {
+    let keystore2 = get_keystore_service();
+    let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+
+    // Generate attestation key.
+    let attest_gen_params = authorizations::AuthSetBuilder::new()
+        .no_auth_required()
+        .algorithm(Algorithm::EC)
+        .purpose(KeyPurpose::ATTEST_KEY)
+        .digest(Digest::SHA_2_256)
+        .ec_curve(EcCurve::P_256)
+        .attestation_challenge(b"foo".to_vec());
+    let attest_alias = "ks_test_auth_tags_attest_key";
+    let attest_key_metadata =
+        key_generations::generate_key(&sec_level, &attest_gen_params, attest_alias).unwrap();
+
+    // Generate attested key.
+    let alias = "ks_test_auth_tags_attested_key";
+    let gen_params = authorizations::AuthSetBuilder::new()
+        .no_auth_required()
+        .algorithm(Algorithm::EC)
+        .purpose(KeyPurpose::SIGN)
+        .purpose(KeyPurpose::VERIFY)
+        .digest(Digest::SHA_2_256)
+        .ec_curve(EcCurve::P_256)
+        .attestation_challenge(b"bar".to_vec())
+        .app_id(b"app-id".to_vec())
+        .app_data(b"app-data".to_vec());
+
+    let result = sec_level.generateKey(
+        &KeyDescriptor {
+            domain: Domain::APP,
+            nspace: -1,
+            alias: Some(alias.to_string()),
+            blob: None,
+        },
+        Some(&attest_key_metadata.key),
+        &gen_params,
+        0,
+        b"entropy",
+    );
+
+    assert!(result.is_ok());
+    delete_app_key(&keystore2, alias).unwrap();
+    delete_app_key(&keystore2, attest_alias).unwrap();
+}
+
+/// Generate an attestation-key with specifying `APPLICATION_ID` and `APPLICATION_DATA`.
+/// Test should try to generate an attested key using previously generated attestation-key without
+/// specifying app-id and app-data. Test should fail to generate a new key with error code
+/// `INVALID_KEY_BLOB`.
+/// It is an oversight of the Keystore API that `APPLICATION_ID` and `APPLICATION_DATA` tags cannot
+/// be provided to generateKey for an attestation key that was generated with them.
+#[test]
+fn keystore2_gen_attestation_key_with_auth_app_id_app_data_test_fail() {
+    let keystore2 = get_keystore_service();
+    let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+
+    // Generate attestation key.
+    let attest_gen_params = authorizations::AuthSetBuilder::new()
+        .no_auth_required()
+        .algorithm(Algorithm::EC)
+        .purpose(KeyPurpose::ATTEST_KEY)
+        .digest(Digest::SHA_2_256)
+        .ec_curve(EcCurve::P_256)
+        .attestation_challenge(b"foo".to_vec())
+        .app_id(b"app-id".to_vec())
+        .app_data(b"app-data".to_vec());
+    let attest_alias = "ks_test_auth_tags_attest_key";
+    let attest_key_metadata =
+        key_generations::generate_key(&sec_level, &attest_gen_params, attest_alias).unwrap();
+
+    // Generate new key using above generated attestation key without providing app-id and app-data.
+    let alias = "ks_test_auth_tags_attested_key";
+    let gen_params = authorizations::AuthSetBuilder::new()
+        .no_auth_required()
+        .algorithm(Algorithm::EC)
+        .purpose(KeyPurpose::SIGN)
+        .purpose(KeyPurpose::VERIFY)
+        .digest(Digest::SHA_2_256)
+        .ec_curve(EcCurve::P_256)
+        .attestation_challenge(b"foo".to_vec());
+
+    let result = key_generations::map_ks_error(sec_level.generateKey(
+        &KeyDescriptor {
+            domain: Domain::APP,
+            nspace: -1,
+            alias: Some(alias.to_string()),
+            blob: None,
+        },
+        Some(&attest_key_metadata.key),
+        &gen_params,
+        0,
+        b"entropy",
+    ));
+
+    assert!(result.is_err());
+    assert_eq!(Error::Km(ErrorCode::INVALID_KEY_BLOB), result.unwrap_err());
+    delete_app_key(&keystore2, attest_alias).unwrap();
+}
+
+fn add_hardware_token(auth_type: HardwareAuthenticatorType) {
+    let keystore_auth = get_keystore_auth_service();
+
+    let token = HardwareAuthToken {
+        challenge: 0,
+        userId: 0,
+        authenticatorId: 0,
+        authenticatorType: auth_type,
+        timestamp: Timestamp { milliSeconds: 500 },
+        mac: vec![],
+    };
+    keystore_auth.addAuthToken(&token).unwrap();
+}
+
+#[test]
+fn keystore2_flagged_off_get_last_auth_password_permission_denied() {
+    if aconfig_android_hardware_biometrics_rust::last_authentication_time() {
+        return;
+    }
+
+    let keystore_auth = get_keystore_auth_service();
+
+    let result = keystore_auth.getLastAuthTime(0, &[HardwareAuthenticatorType::PASSWORD]);
+
+    assert!(result.is_err());
+    assert_eq!(result.unwrap_err().service_specific_error(), ResponseCode::PERMISSION_DENIED.0);
+}
+
+#[test]
+fn keystore2_flagged_on_get_last_auth_password_success() {
+    if !aconfig_android_hardware_biometrics_rust::last_authentication_time() {
+        return;
+    }
+
+    let keystore_auth = get_keystore_auth_service();
+
+    add_hardware_token(HardwareAuthenticatorType::PASSWORD);
+    assert!(keystore_auth.getLastAuthTime(0, &[HardwareAuthenticatorType::PASSWORD]).unwrap() > 0);
+}
+
+#[test]
+fn keystore2_flagged_on_get_last_auth_fingerprint_success() {
+    if !aconfig_android_hardware_biometrics_rust::last_authentication_time() {
+        return;
+    }
+
+    let keystore_auth = get_keystore_auth_service();
+
+    add_hardware_token(HardwareAuthenticatorType::FINGERPRINT);
+    assert!(
+        keystore_auth.getLastAuthTime(0, &[HardwareAuthenticatorType::FINGERPRINT]).unwrap() > 0
+    );
+}
diff --git a/keystore2/tests/keystore2_client_import_keys_tests.rs b/keystore2/tests/keystore2_client_import_keys_tests.rs
index ecba402..31d57a2 100644
--- a/keystore2/tests/keystore2_client_import_keys_tests.rs
+++ b/keystore2/tests/keystore2_client_import_keys_tests.rs
@@ -32,12 +32,14 @@
     authorizations, get_keystore_service, key_generations, key_generations::Error,
 };
 
-use crate::ffi_test_utils::{create_wrapped_key, create_wrapped_key_additional_auth_data};
+use keystore2_test_utils::ffi_test_utils::{
+    create_wrapped_key, create_wrapped_key_additional_auth_data,
+};
 
 use crate::keystore2_client_test_utils::{
-    encrypt_secure_key, encrypt_transport_key, has_default_keymint,
-    perform_sample_asym_sign_verify_op, perform_sample_hmac_sign_verify_op,
-    perform_sample_sym_key_decrypt_op, perform_sample_sym_key_encrypt_op, SAMPLE_PLAIN_TEXT,
+    encrypt_secure_key, encrypt_transport_key, perform_sample_asym_sign_verify_op,
+    perform_sample_hmac_sign_verify_op, perform_sample_sym_key_decrypt_op,
+    perform_sample_sym_key_encrypt_op, SAMPLE_PLAIN_TEXT,
 };
 
 pub fn import_rsa_sign_key_and_perform_sample_operation(
@@ -286,7 +288,7 @@
         key_generations::RSA_2048_KEY,
     ));
 
-    if has_default_keymint() {
+    if key_generations::has_default_keymint() {
         assert!(result.is_err());
         assert_eq!(Error::Km(ErrorCode::INCOMPATIBLE_PURPOSE), result.unwrap_err());
     } else {
diff --git a/keystore2/tests/keystore2_client_keystore_engine_tests.rs b/keystore2/tests/keystore2_client_keystore_engine_tests.rs
index 339eb60..4651931 100644
--- a/keystore2/tests/keystore2_client_keystore_engine_tests.rs
+++ b/keystore2/tests/keystore2_client_keystore_engine_tests.rs
@@ -26,7 +26,7 @@
 
 use keystore2_test_utils::{authorizations::AuthSetBuilder, get_keystore_service, run_as};
 
-use crate::ffi_test_utils::perform_crypto_op_using_keystore_engine;
+use keystore2_test_utils::ffi_test_utils::perform_crypto_op_using_keystore_engine;
 
 use openssl::x509::X509;
 
diff --git a/keystore2/tests/keystore2_client_test_utils.rs b/keystore2/tests/keystore2_client_test_utils.rs
index f7e7985..e76c64b 100644
--- a/keystore2/tests/keystore2_client_test_utils.rs
+++ b/keystore2/tests/keystore2_client_test_utils.rs
@@ -104,12 +104,6 @@
     };
 }
 
-/// Indicate whether the default device is KeyMint (rather than Keymaster).
-pub fn has_default_keymint() -> bool {
-    binder::is_declared("android.hardware.security.keymint.IKeyMintDevice/default")
-        .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(
diff --git a/keystore2/tests/keystore2_client_tests.rs b/keystore2/tests/keystore2_client_tests.rs
index 9be0bf8..ac7f19f 100644
--- a/keystore2/tests/keystore2_client_tests.rs
+++ b/keystore2/tests/keystore2_client_tests.rs
@@ -12,10 +12,10 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-pub mod ffi_test_utils;
 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_authorizations_tests;
 pub mod keystore2_client_delete_key_tests;
 pub mod keystore2_client_ec_key_tests;
 pub mod keystore2_client_grant_key_tests;
diff --git a/keystore2/tests/legacy_blobs/keystore2_legacy_blob_tests.rs b/keystore2/tests/legacy_blobs/keystore2_legacy_blob_tests.rs
index 63122fe..faf954a 100644
--- a/keystore2/tests/legacy_blobs/keystore2_legacy_blob_tests.rs
+++ b/keystore2/tests/legacy_blobs/keystore2_legacy_blob_tests.rs
@@ -25,9 +25,7 @@
     Domain::Domain, KeyDescriptor::KeyDescriptor,
 };
 
-use android_security_maintenance::aidl::android::security::maintenance::{
-    IKeystoreMaintenance::IKeystoreMaintenance, UserState::UserState,
-};
+use android_security_maintenance::aidl::android::security::maintenance::IKeystoreMaintenance::IKeystoreMaintenance;
 
 use android_security_authorization::aidl::android::security::authorization::{
     IKeystoreAuthorization::IKeystoreAuthorization, LockScreenEvent::LockScreenEvent,
@@ -241,9 +239,6 @@
                 }
             }
 
-            let maint_service = get_maintenance();
-            assert_eq!(Ok(UserState(1)), maint_service.getState(99));
-
             let mut key_params: Vec<KsKeyparameter> = Vec::new();
             for param in key_metadata.authorizations {
                 let key_param = KsKeyparameter::new(param.keyParameter.into(), param.securityLevel);
@@ -502,9 +497,6 @@
                 }
             }
 
-            let maint_service = get_maintenance();
-            assert_eq!(Ok(UserState(1)), maint_service.getState(98));
-
             let mut key_params: Vec<KsKeyparameter> = Vec::new();
             for param in key_metadata.authorizations {
                 let key_param = KsKeyparameter::new(param.keyParameter.into(), param.securityLevel);
diff --git a/diced/sample_inputs/Android.bp b/keystore2/watchdog/Android.bp
similarity index 70%
rename from diced/sample_inputs/Android.bp
rename to keystore2/watchdog/Android.bp
index cf6ef5f..62ede89 100644
--- a/diced/sample_inputs/Android.bp
+++ b/keystore2/watchdog/Android.bp
@@ -1,4 +1,4 @@
-// Copyright 2021, The Android Open Source Project
+// 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.
@@ -21,25 +21,29 @@
     default_applicable_licenses: ["system_security_license"],
 }
 
-rust_library {
-    name: "libdiced_sample_inputs",
-    crate_name: "diced_sample_inputs",
+rust_defaults {
+    name: "libwatchdog_defaults",
+    crate_name: "watchdog_rs",
     srcs: ["src/lib.rs"],
     rustlibs: [
-        "libanyhow",
-        "libciborium",
-        "libcoset",
-        "libdiced_open_dice",
+        "liblog_rust",
+    ]
+}
+
+rust_library {
+    name: "libwatchdog_rs",
+    defaults: ["libwatchdog_defaults"],
+    apex_available: [
+        "//apex_available:platform",
+        "com.android.virt",
     ],
 }
 
 rust_test {
-    name: "libdiced_sample_inputs.integration_test",
-    crate_name: "diced_sample_inputs_test",
-    srcs: ["tests/*.rs"],
+    name: "libwatchdog_rs.test",
+    defaults: ["libwatchdog_defaults"],
     test_suites: ["general-tests"],
     rustlibs: [
-        "libdiced_open_dice",
-        "libdiced_sample_inputs",
-    ],
+        "libandroid_logger",
+    ]
 }
diff --git a/keystore2/src/watchdog.rs b/keystore2/watchdog/src/lib.rs
similarity index 100%
rename from keystore2/src/watchdog.rs
rename to keystore2/watchdog/src/lib.rs