[dice] Move open-dice Rust wrapper libraries to virt
Since these wrapper libraries are only used in virt projects.
The tests are added to busytown config at cl/573729094.
Test: atest MicrodroidHostTests
Change-Id: I2479086c5ee5f1c7ce8884d32cf18f6f4cf07172
diff --git a/TEST_MAPPING b/TEST_MAPPING
index f1bfe09..1410534 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -84,6 +84,9 @@
"path": "packages/modules/Virtualization/libs/devicemapper"
},
{
+ "path": "packages/modules/Virtualization/libs/dice"
+ },
+ {
"path": "packages/modules/Virtualization/libs/libfdt"
},
{
diff --git a/libs/dice/OWNERS b/libs/dice/OWNERS
new file mode 100644
index 0000000..fbc501d
--- /dev/null
+++ b/libs/dice/OWNERS
@@ -0,0 +1 @@
+ascull@google.com
diff --git a/libs/dice/TEST_MAPPING b/libs/dice/TEST_MAPPING
new file mode 100644
index 0000000..2045ba5
--- /dev/null
+++ b/libs/dice/TEST_MAPPING
@@ -0,0 +1,22 @@
+{
+ "postsubmit": [
+ {
+ "name": "libdiced_open_dice.integration_test"
+ },
+ {
+ "name": "libdiced_open_dice_nostd.integration_test"
+ },
+ {
+ "name": "libopen_dice_cbor_bindgen_test"
+ },
+ {
+ "name": "libopen_dice_android_bindgen_test"
+ },
+ {
+ "name": "libdiced_sample_inputs.integration_test"
+ },
+ {
+ "name": "libdiced_sample_inputs_nostd.integration_test"
+ }
+ ]
+}
diff --git a/libs/dice/open_dice/Android.bp b/libs/dice/open_dice/Android.bp
new file mode 100644
index 0000000..646080d
--- /dev/null
+++ b/libs/dice/open_dice/Android.bp
@@ -0,0 +1,258 @@
+package {
+ default_visibility: [":__subpackages__"],
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+rust_defaults {
+ name: "libdiced_open_dice_defaults",
+ crate_name: "diced_open_dice",
+ defaults: ["avf_build_flags_rust"],
+ srcs: ["src/lib.rs"],
+}
+
+rust_library_rlib {
+ name: "libdiced_open_dice_nostd",
+ defaults: ["libdiced_open_dice_defaults"],
+ rustlibs: [
+ "libopen_dice_android_bindgen_nostd",
+ "libopen_dice_cbor_bindgen_nostd",
+ "libzeroize_nostd",
+ ],
+ features: [
+ "alloc",
+ ],
+ 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_android_bindgen",
+ "libopen_dice_cbor_bindgen",
+ "libzeroize",
+ ],
+ features: [
+ "alloc",
+ "std",
+ ],
+ shared_libs: [
+ "libcrypto",
+ ],
+ static_libs: [
+ "libopen_dice_cbor",
+ ],
+ whole_static_libs: [
+ "libopen_dice_android",
+ ],
+ visibility: [
+ "//packages/modules/Virtualization:__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_android_bindgen.rust_defaults",
+ wrapper_src: "bindgen/android.h",
+ crate_name: "open_dice_android_bindgen",
+ source_stem: "bindings",
+ bindgen_flags: [
+ // By generating only essential functions, we can make bindings concise and
+ // optimize compilation time.
+ "--allowlist-function=DiceAndroidFormatConfigDescriptor",
+ "--allowlist-function=DiceAndroidMainFlow",
+ "--allowlist-function=DiceAndroidHandoverMainFlow",
+ "--allowlist-function=DiceAndroidHandoverParse",
+
+ // We also need some constants in addition to the functions.
+ "--allowlist-var=DICE_ANDROID_CONFIG_.*",
+
+ // 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_android_bindgen",
+ defaults: [
+ "libopen_dice.rust_defaults",
+ "libopen_dice_android_bindgen.rust_defaults",
+ ],
+ rustlibs: [
+ "libopen_dice_cbor_bindgen",
+ ],
+ whole_static_libs: ["libopen_dice_android"],
+}
+
+rust_bindgen {
+ name: "libopen_dice_android_bindgen_nostd",
+ defaults: [
+ "libopen_dice_android_bindgen.rust_defaults",
+ "libopen_dice_bindgen_nostd.rust_defaults",
+ ],
+ rustlibs: [
+ "libopen_dice_cbor_bindgen_nostd",
+ ],
+ whole_static_libs: ["libopen_dice_android_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_android_bindgen_test",
+ srcs: [
+ ":libopen_dice_android_bindgen",
+ ],
+ crate_name: "open_dice_android_bindgen_test",
+ rustlibs: [
+ "libopen_dice_cbor_bindgen",
+ ],
+ test_suites: ["general-tests"],
+ auto_gen_config: true,
+ clippy_lints: "none",
+ lints: "none",
+}
diff --git a/libs/dice/open_dice/bindgen/android.h b/libs/dice/open_dice/bindgen/android.h
new file mode 100644
index 0000000..18f6476
--- /dev/null
+++ b/libs/dice/open_dice/bindgen/android.h
@@ -0,0 +1,17 @@
+// 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.h>
diff --git a/libs/dice/open_dice/bindgen/dice.h b/libs/dice/open_dice/bindgen/dice.h
new file mode 100644
index 0000000..47fe911
--- /dev/null
+++ b/libs/dice/open_dice/bindgen/dice.h
@@ -0,0 +1,18 @@
+// 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/libs/dice/open_dice/src/bcc.rs b/libs/dice/open_dice/src/bcc.rs
new file mode 100644
index 0000000..199e1a9
--- /dev/null
+++ b/libs/dice/open_dice/src/bcc.rs
@@ -0,0 +1,223 @@
+// 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.h
+
+use crate::dice::{Cdi, CdiValues, DiceArtifacts, InputValues, CDI_SIZE};
+use crate::error::{check_result, DiceError, Result};
+use open_dice_android_bindgen::{
+ DiceAndroidConfigValues, DiceAndroidFormatConfigDescriptor, DiceAndroidHandoverMainFlow,
+ DiceAndroidHandoverParse, DiceAndroidMainFlow, DICE_ANDROID_CONFIG_COMPONENT_NAME,
+ DICE_ANDROID_CONFIG_COMPONENT_VERSION, DICE_ANDROID_CONFIG_RESETTABLE,
+ DICE_ANDROID_CONFIG_SECURITY_VERSION,
+};
+use std::{ffi::CStr, ptr};
+
+/// Contains the input values used to construct the Android Profile for DICE
+/// configuration descriptor.
+#[derive(Default, Debug)]
+pub struct DiceConfigValues<'a> {
+ /// Name of the component.
+ pub component_name: Option<&'a CStr>,
+ /// Version of the component.
+ pub component_version: Option<u64>,
+ /// Whether the key changes on factory reset.
+ pub resettable: bool,
+ /// Monotonically increasing version of the component.
+ pub security_version: Option<u64>,
+}
+
+/// Formats a configuration descriptor following the Android Profile for DICE specification.
+/// See https://pigweed.googlesource.com/open-dice/+/refs/heads/main/docs/android.md.
+pub fn bcc_format_config_descriptor(values: &DiceConfigValues, buffer: &mut [u8]) -> Result<usize> {
+ let mut configs = 0;
+
+ let component_name = values.component_name.map_or(ptr::null(), |name| {
+ configs |= DICE_ANDROID_CONFIG_COMPONENT_NAME;
+ name.as_ptr()
+ });
+ let component_version = values.component_version.map_or(0, |version| {
+ configs |= DICE_ANDROID_CONFIG_COMPONENT_VERSION;
+ version
+ });
+ if values.resettable {
+ configs |= DICE_ANDROID_CONFIG_RESETTABLE;
+ }
+ let security_version = values.security_version.map_or(0, |version| {
+ configs |= DICE_ANDROID_CONFIG_SECURITY_VERSION;
+ version
+ });
+
+ let values =
+ DiceAndroidConfigValues { configs, component_name, component_version, security_version };
+
+ 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 {
+ DiceAndroidFormatConfigDescriptor(
+ &values,
+ buffer.len(),
+ buffer.as_mut_ptr(),
+ &mut buffer_size,
+ )
+ },
+ buffer_size,
+ )?;
+ Ok(buffer_size)
+}
+
+/// Executes the main Android DICE flow.
+///
+/// Given a full set of input values along with the current DICE chain and CDI values,
+/// computes the next CDI values and matching updated DICE chain.
+pub fn bcc_main_flow(
+ current_cdi_attest: &Cdi,
+ current_cdi_seal: &Cdi,
+ current_chain: &[u8],
+ input_values: &InputValues,
+ next_cdi_values: &mut CdiValues,
+ next_chain: &mut [u8],
+) -> Result<usize> {
+ let mut next_chain_size = 0;
+ check_result(
+ // SAFETY: `DiceAndroidMainFlow` only reads the `current_chain` and CDI values and writes
+ // to `next_chain` 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 {
+ DiceAndroidMainFlow(
+ ptr::null_mut(), // context
+ current_cdi_attest.as_ptr(),
+ current_cdi_seal.as_ptr(),
+ current_chain.as_ptr(),
+ current_chain.len(),
+ input_values.as_ptr(),
+ next_chain.len(),
+ next_chain.as_mut_ptr(),
+ &mut next_chain_size,
+ next_cdi_values.cdi_attest.as_mut_ptr(),
+ next_cdi_values.cdi_seal.as_mut_ptr(),
+ )
+ },
+ next_chain_size,
+ )?;
+ Ok(next_chain_size)
+}
+
+/// Executes the main Android DICE handover flow.
+///
+/// A handover combines the DICE chain and CDIs in a single CBOR object.
+/// This function takes the current boot stage's handover bundle and produces a
+/// bundle for the next stage.
+pub fn bcc_handover_main_flow(
+ current_handover: &[u8],
+ input_values: &InputValues,
+ next_handover: &mut [u8],
+) -> Result<usize> {
+ let mut next_handover_size = 0;
+ check_result(
+ // SAFETY: The function only reads `current_handover` and writes to `next_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 {
+ DiceAndroidHandoverMainFlow(
+ ptr::null_mut(), // context
+ current_handover.as_ptr(),
+ current_handover.len(),
+ input_values.as_ptr(),
+ next_handover.len(),
+ next_handover.as_mut_ptr(),
+ &mut next_handover_size,
+ )
+ },
+ next_handover_size,
+ )?;
+
+ Ok(next_handover_size)
+}
+
+/// An Android DICE handover object combines the DICE chain and CDIs in a single CBOR object.
+/// This struct is used as return of the function `android_dice_handover_parse`, its lifetime is
+/// tied to the lifetime of the raw handover slice.
+#[derive(Debug)]
+pub struct BccHandover<'a> {
+ /// Attestation CDI.
+ cdi_attest: &'a [u8; CDI_SIZE],
+ /// Sealing CDI.
+ cdi_seal: &'a [u8; CDI_SIZE],
+ /// DICE 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
+ }
+}
+
+/// This function parses the `handover` to extracts the DICE chain and CDIs.
+/// The lifetime of the returned `DiceAndroidHandover` is tied to the given `handover` slice.
+pub fn bcc_handover_parse(handover: &[u8]) -> Result<BccHandover> {
+ let mut cdi_attest: *const u8 = ptr::null();
+ let mut cdi_seal: *const u8 = ptr::null();
+ let mut chain: *const u8 = ptr::null();
+ let mut chain_size = 0;
+ check_result(
+ // SAFETY: The `handover` is only read and never stored and the returned pointers should
+ // all point within the address range of the `handover` or be NULL.
+ unsafe {
+ DiceAndroidHandoverParse(
+ handover.as_ptr(),
+ handover.len(),
+ &mut cdi_attest,
+ &mut cdi_seal,
+ &mut chain,
+ &mut chain_size,
+ )
+ },
+ chain_size,
+ )?;
+ let cdi_attest = sub_slice(handover, cdi_attest, CDI_SIZE)?;
+ let cdi_seal = sub_slice(handover, cdi_seal, CDI_SIZE)?;
+ let bcc = sub_slice(handover, chain, chain_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/libs/dice/open_dice/src/dice.rs b/libs/dice/open_dice/src/dice.rs
new file mode 100644
index 0000000..e42e373
--- /dev/null
+++ b/libs/dice/open_dice/src/dice.rs
@@ -0,0 +1,287 @@
+// 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/libs/dice/open_dice/src/error.rs b/libs/dice/open_dice/src/error.rs
new file mode 100644
index 0000000..53ffd2d
--- /dev/null
+++ b/libs/dice/open_dice/src/error.rs
@@ -0,0 +1,63 @@
+// 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/libs/dice/open_dice/src/lib.rs b/libs/dice/open_dice/src/lib.rs
new file mode 100644
index 0000000..d0004b1
--- /dev/null
+++ b/libs/dice/open_dice/src/lib.rs
@@ -0,0 +1,50 @@
+// 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(feature = "alloc")]
+extern crate alloc;
+
+#[cfg(not(feature = "std"))]
+extern crate core as std;
+
+mod bcc;
+mod dice;
+mod error;
+mod ops;
+#[cfg(feature = "alloc")]
+mod retry;
+
+pub use bcc::{
+ bcc_format_config_descriptor, bcc_handover_main_flow, bcc_handover_parse, bcc_main_flow,
+ BccHandover, DiceConfigValues,
+};
+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::{
+ derive_cdi_leaf_priv, generate_certificate, hash, kdf, keypair_from_seed, sign, verify,
+};
+#[cfg(feature = "alloc")]
+pub use retry::{
+ retry_bcc_format_config_descriptor, retry_bcc_main_flow, retry_dice_main_flow,
+ retry_generate_certificate, OwnedDiceArtifacts,
+};
diff --git a/libs/dice/open_dice/src/ops.rs b/libs/dice/open_dice/src/ops.rs
new file mode 100644
index 0000000..7174d3e
--- /dev/null
+++ b/libs/dice/open_dice/src/ops.rs
@@ -0,0 +1,173 @@
+// 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::{
+ derive_cdi_private_key_seed, DiceArtifacts, 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))
+}
+
+/// Derives the CDI_Leaf_Priv from the provided `dice_artifacts`.
+///
+/// The corresponding public key is included in the leaf certificate of the DICE chain
+/// contained in `dice_artifacts`.
+pub fn derive_cdi_leaf_priv(dice_artifacts: &dyn DiceArtifacts) -> Result<PrivateKey> {
+ let cdi_priv_key_seed = derive_cdi_private_key_seed(dice_artifacts.cdi_attest())?;
+ let (_, private_key) = keypair_from_seed(cdi_priv_key_seed.as_array())?;
+ Ok(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/libs/dice/open_dice/src/retry.rs b/libs/dice/open_dice/src/retry.rs
new file mode 100644
index 0000000..a6303bd
--- /dev/null
+++ b/libs/dice/open_dice/src/retry.rs
@@ -0,0 +1,141 @@
+// 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, DiceConfigValues};
+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;
+#[cfg(feature = "alloc")]
+use alloc::vec::Vec;
+
+/// 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(values: &DiceConfigValues) -> Result<Vec<u8>> {
+ retry_with_measured_buffer(|buffer| bcc_format_config_descriptor(values, 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/libs/dice/open_dice/tests/api_test.rs b/libs/dice/open_dice/tests/api_test.rs
new file mode 100644
index 0000000..a47265b
--- /dev/null
+++ b/libs/dice/open_dice/tests/api_test.rs
@@ -0,0 +1,107 @@
+/*
+ * 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/libs/dice/sample_inputs/Android.bp b/libs/dice/sample_inputs/Android.bp
new file mode 100644
index 0000000..013038c
--- /dev/null
+++ b/libs/dice/sample_inputs/Android.bp
@@ -0,0 +1,81 @@
+// 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 {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+rust_defaults {
+ name: "libdiced_sample_inputs_defaults",
+ crate_name: "diced_sample_inputs",
+ defaults: ["avf_build_flags_rust"],
+ srcs: ["src/lib.rs"],
+}
+
+rust_library {
+ name: "libdiced_sample_inputs",
+ defaults: ["libdiced_sample_inputs_defaults"],
+ features: [
+ "std",
+ ],
+ rustlibs: [
+ "libciborium",
+ "libcoset",
+ "libdiced_open_dice",
+ "liblog_rust",
+ ],
+}
+
+rust_library_rlib {
+ name: "libdiced_sample_inputs_nostd",
+ defaults: ["libdiced_sample_inputs_defaults"],
+ rustlibs: [
+ "libciborium_nostd",
+ "libcoset_nostd",
+ "libdiced_open_dice_nostd",
+ "liblog_rust_nostd",
+ ],
+ visibility: [
+ "//packages/modules/Virtualization:__subpackages__",
+ ],
+}
+
+rust_defaults {
+ name: "libdiced_sample_inputs_test_defaults",
+ crate_name: "diced_sample_inputs_test",
+ srcs: ["tests/*.rs"],
+ test_suites: ["general-tests"],
+ rustlibs: [
+ "libanyhow",
+ "libhwtrust",
+ ],
+}
+
+rust_test {
+ name: "libdiced_sample_inputs.integration_test",
+ defaults: ["libdiced_sample_inputs_test_defaults"],
+ rustlibs: [
+ "libdiced_open_dice",
+ "libdiced_sample_inputs",
+ ],
+}
+
+rust_test {
+ name: "libdiced_sample_inputs_nostd.integration_test",
+ defaults: ["libdiced_sample_inputs_test_defaults"],
+ rustlibs: [
+ "libdiced_open_dice_nostd",
+ "libdiced_sample_inputs_nostd",
+ ],
+}
diff --git a/libs/dice/sample_inputs/src/lib.rs b/libs/dice/sample_inputs/src/lib.rs
new file mode 100644
index 0000000..9d6deca
--- /dev/null
+++ b/libs/dice/sample_inputs/src/lib.rs
@@ -0,0 +1,26 @@
+/*
+ * 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.
+
+#![cfg_attr(not(feature = "std"), no_std)]
+
+extern crate alloc;
+
+mod sample_inputs;
+
+pub use sample_inputs::make_sample_bcc_and_cdis;
diff --git a/libs/dice/sample_inputs/src/sample_inputs.rs b/libs/dice/sample_inputs/src/sample_inputs.rs
new file mode 100644
index 0000000..54f551b
--- /dev/null
+++ b/libs/dice/sample_inputs/src/sample_inputs.rs
@@ -0,0 +1,200 @@
+// 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 alloc::vec;
+use alloc::vec::Vec;
+use ciborium::{de, ser, value::Value};
+use core::ffi::CStr;
+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, DiceConfigValues, DiceError,
+ DiceMode, InputValues, OwnedDiceArtifacts, Result, CDI_SIZE, HASH_SIZE, HIDDEN_SIZE,
+};
+use log::error;
+
+/// 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| {
+ error!("Failed to serialize the key to CBOR data: {e}");
+ DiceError::InvalidInput
+ })
+}
+
+/// 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).map_err(|e| {
+ error!("In make_sample_bcc_and_cdis: Trying to derive private key seed. Error: {e}");
+ e
+ })?;
+
+ // Gets the root public key in DICE chain (BCC).
+ let (public_key, _) = keypair_from_seed(private_key_seed.as_array()).map_err(|e| {
+ error!("In make_sample_bcc_and_cids: Failed to generate key pair. Error: {e}");
+ e
+ })?;
+ 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_values = DiceConfigValues {
+ component_name: Some(CStr::from_bytes_with_nul(b"ABL\0").unwrap()),
+ component_version: Some(1),
+ resettable: true,
+ ..Default::default()
+ };
+ let config_descriptor = retry_bcc_format_config_descriptor(&config_values)?;
+ 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).map_err(|e| {
+ error!("In make_sample_bcc_and_cdis: Trying to run first main flow. Error: {e}");
+ e
+ })?;
+ let bcc_value = Value::Array(vec![
+ ed25519_public_key_value,
+ de::from_reader(&cert[..]).map_err(|e| {
+ error!("Deserialize root DICE certificate failed: {e}");
+ DiceError::InvalidInput
+ })?,
+ ]);
+ let mut bcc: Vec<u8> = vec![];
+ ser::into_writer(&bcc_value, &mut bcc).map_err(|e| {
+ error!("Serialize BCC failed: {e}");
+ DiceError::InvalidInput
+ })?;
+
+ // Appends AVB certificate to DICE chain.
+ let config_values = DiceConfigValues {
+ component_name: Some(CStr::from_bytes_with_nul(b"AVB\0").unwrap()),
+ component_version: Some(1),
+ resettable: true,
+ ..Default::default()
+ };
+ let config_descriptor = retry_bcc_format_config_descriptor(&config_values)?;
+ 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)
+ .map_err(|e| {
+ error!(
+ "In make_sample_bcc_and_cdis: Trying to run first bcc main flow. Error: {e}"
+ );
+ e
+ })?;
+
+ // Appends Android certificate to DICE chain.
+ let config_values = DiceConfigValues {
+ component_name: Some(CStr::from_bytes_with_nul(b"Android\0").unwrap()),
+ component_version: Some(12),
+ resettable: true,
+ ..Default::default()
+ };
+ let config_descriptor = retry_bcc_format_config_descriptor(&config_values)?;
+ 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(|| {
+ error!("bcc is none");
+ DiceError::InvalidInput
+ })?,
+ &input_values,
+ )
+ .map_err(|e| {
+ error!("In make_sample_bcc_and_cdis: Trying to run second bcc main flow. Error: {e}");
+ e
+ })
+}
diff --git a/libs/dice/sample_inputs/tests/api_test.rs b/libs/dice/sample_inputs/tests/api_test.rs
new file mode 100644
index 0000000..0823f16
--- /dev/null
+++ b/libs/dice/sample_inputs/tests/api_test.rs
@@ -0,0 +1,146 @@
+/*
+ * 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 anyhow::Result;
+use diced_open_dice::{derive_cdi_leaf_priv, sign, DiceArtifacts};
+use diced_sample_inputs::make_sample_bcc_and_cdis;
+use hwtrust::{dice, session::Session};
+
+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,
+];
+const MESSAGE: &[u8] = b"Message for testing";
+
+#[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));
+}
+
+#[test]
+fn cdi_leaf_priv_corresponds_to_leaf_public_key_in_dice_chain() -> Result<()> {
+ let dice_artifacts = make_sample_bcc_and_cdis().unwrap();
+ let private_key = derive_cdi_leaf_priv(&dice_artifacts).unwrap();
+ let signature = sign(MESSAGE, private_key.as_array()).unwrap();
+
+ let session = Session::default();
+ let chain = dice::Chain::from_cbor(&session, dice_artifacts.bcc().unwrap())?;
+ let public_key = chain.leaf().subject_public_key();
+ public_key.verify(&signature, MESSAGE)
+}