[dice] Add API to derive CDI_Leaf_Priv from DiceArtifacts

This function will be uses in several places for pVM
remote attestation.

Bug: 303807447
Test: atest libdiced_sample_inputs.integration_test \
libdiced_sample_inputs_nostd.integration_test

Change-Id: I6f45ff35c6e48eb42a32d28c1eb3e851859db655
diff --git a/diced/open_dice/src/lib.rs b/diced/open_dice/src/lib.rs
index 83ae07f..d0004b1 100644
--- a/diced/open_dice/src/lib.rs
+++ b/diced/open_dice/src/lib.rs
@@ -40,7 +40,9 @@
     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};
+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,
diff --git a/diced/open_dice/src/ops.rs b/diced/open_dice/src/ops.rs
index 6b9202a..fe981df 100644
--- a/diced/open_dice/src/ops.rs
+++ b/diced/open_dice/src/ops.rs
@@ -17,8 +17,8 @@
 //! 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,
+    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::{
@@ -91,6 +91,16 @@
     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];
diff --git a/diced/sample_inputs/Android.bp b/diced/sample_inputs/Android.bp
index e66d436..ba76769 100644
--- a/diced/sample_inputs/Android.bp
+++ b/diced/sample_inputs/Android.bp
@@ -60,6 +60,10 @@
     crate_name: "diced_sample_inputs_test",
     srcs: ["tests/*.rs"],
     test_suites: ["general-tests"],
+    rustlibs: [
+        "libanyhow",
+        "libhwtrust",
+    ],
 }
 
 rust_test {
diff --git a/diced/sample_inputs/tests/api_test.rs b/diced/sample_inputs/tests/api_test.rs
index f0d6c0d..0823f16 100644
--- a/diced/sample_inputs/tests/api_test.rs
+++ b/diced/sample_inputs/tests/api_test.rs
@@ -14,8 +14,10 @@
  * limitations under the License.
  */
 
-use diced_open_dice::DiceArtifacts;
+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,
@@ -121,6 +123,7 @@
     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() {
@@ -129,3 +132,15 @@
     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)
+}