Define multialg variants of the libdiced_open_dice targets.

Implements and exports "multialg" alternatives to `keypair_from_seed`
and `derive_cdi_leaf_priv` functions (and a few others).

Bug: 391534773
Test: atest libdiced_open_dice_multialg.integration_test
Change-Id: Ia405ee3fc2c092c750eda9dfa44eb142130ec66b
diff --git a/libs/dice/TEST_MAPPING b/libs/dice/TEST_MAPPING
index a43d7a2..d2d89e4 100644
--- a/libs/dice/TEST_MAPPING
+++ b/libs/dice/TEST_MAPPING
@@ -12,6 +12,9 @@
       "name": "libdiced_open_dice.integration_test"
     },
     {
+      "name": "libdiced_open_dice_multialg.integration_test"
+    },
+    {
       "name": "libdiced_open_dice_nostd.integration_test"
     },
     {
diff --git a/libs/dice/open_dice/Android.bp b/libs/dice/open_dice/Android.bp
index 986f496..739f245 100644
--- a/libs/dice/open_dice/Android.bp
+++ b/libs/dice/open_dice/Android.bp
@@ -63,6 +63,33 @@
     ],
 }
 
+rust_library {
+    name: "libdiced_open_dice_multialg",
+    defaults: ["libdiced_open_dice_defaults"],
+    host_supported: true,
+    vendor_available: true,
+    rustlibs: [
+        "libcoset",
+        "libopen_dice_android_bindgen_multialg",
+        "libopen_dice_cbor_bindgen_multialg",
+        "libzeroize",
+    ],
+    features: [
+        "std",
+        "multialg",
+    ],
+    shared_libs: [
+        "libcrypto",
+    ],
+    visibility: [
+        "//system/software_defined_vehicle:__subpackages__",
+    ],
+    apex_available: [
+        "//apex_available:platform",
+        "com.android.virt",
+    ],
+}
+
 rust_defaults {
     name: "libdiced_open_dice_test_defaults",
     crate_name: "diced_open_dice_test",
@@ -80,6 +107,18 @@
 }
 
 rust_test {
+    name: "libdiced_open_dice_multialg.integration_test",
+    defaults: ["libdiced_open_dice_test_defaults"],
+    rustlibs: [
+        "libdiced_open_dice_multialg",
+        "libcoset",
+    ],
+    features: [
+        "multialg",
+    ],
+}
+
+rust_test {
     name: "libdiced_open_dice_nostd.integration_test",
     defaults: ["libdiced_open_dice_test_defaults"],
     rustlibs: [
@@ -174,6 +213,20 @@
 }
 
 rust_bindgen {
+    name: "libopen_dice_cbor_bindgen_multialg",
+    defaults: [
+        "libopen_dice.rust_defaults",
+        "libopen_dice_cbor_bindgen.rust_defaults",
+    ],
+    bindgen_flags: [
+        "--rustified-enum DiceKeyAlgorithm",
+        "--allowlist-type=DiceContext",
+    ],
+    whole_static_libs: ["libopen_dice_cbor_multialg"],
+    shared_libs: ["libcrypto"],
+}
+
+rust_bindgen {
     name: "libopen_dice_cbor_bindgen_nostd",
     defaults: [
         "libopen_dice_cbor_bindgen.rust_defaults",
@@ -231,6 +284,18 @@
 }
 
 rust_bindgen {
+    name: "libopen_dice_android_bindgen_multialg",
+    defaults: [
+        "libopen_dice.rust_defaults",
+        "libopen_dice_android_bindgen.rust_defaults",
+    ],
+    rustlibs: [
+        "libopen_dice_cbor_bindgen_multialg",
+    ],
+    whole_static_libs: ["libopen_dice_android_multialg"],
+}
+
+rust_bindgen {
     name: "libopen_dice_android_bindgen_nostd",
     defaults: [
         "libopen_dice_android_bindgen.rust_defaults",
diff --git a/libs/dice/open_dice/src/lib.rs b/libs/dice/open_dice/src/lib.rs
index 33fb65c..9268b03 100644
--- a/libs/dice/open_dice/src/lib.rs
+++ b/libs/dice/open_dice/src/lib.rs
@@ -43,11 +43,19 @@
 };
 pub use error::{DiceError, Result};
 pub use ops::{
-    derive_cdi_leaf_priv, generate_certificate, hash, kdf, keypair_from_seed, sign,
-    sign_cose_sign1, sign_cose_sign1_with_cdi_leaf_priv, verify,
+    derive_cdi_leaf_priv, generate_certificate, hash, kdf, keypair_from_seed, sign, verify,
+};
+#[cfg(feature = "multialg")]
+pub use ops::{
+    derive_cdi_leaf_priv_multialg, keypair_from_seed_multialg, sign_cose_sign1_multialg,
+    sign_cose_sign1_with_cdi_leaf_priv_multialg, verify_multialg,
 };
 pub use retry::{
     retry_bcc_format_config_descriptor, retry_bcc_main_flow, retry_dice_main_flow,
     retry_generate_certificate, retry_sign_cose_sign1, retry_sign_cose_sign1_with_cdi_leaf_priv,
     OwnedDiceArtifacts,
 };
+#[cfg(feature = "multialg")]
+pub use retry::{
+    retry_sign_cose_sign1_multialg, retry_sign_cose_sign1_with_cdi_leaf_priv_multialg,
+};
diff --git a/libs/dice/open_dice/src/ops.rs b/libs/dice/open_dice/src/ops.rs
index 2014118..b22b113 100644
--- a/libs/dice/open_dice/src/ops.rs
+++ b/libs/dice/open_dice/src/ops.rs
@@ -21,11 +21,17 @@
     PRIVATE_KEY_SEED_SIZE, PRIVATE_KEY_SIZE, VM_KEY_ALGORITHM,
 };
 use crate::error::{check_result, DiceError, Result};
+#[cfg(feature = "multialg")]
+use crate::KeyAlgorithm;
 use alloc::{vec, vec::Vec};
+#[cfg(feature = "multialg")]
+use open_dice_cbor_bindgen::DiceContext_;
 use open_dice_cbor_bindgen::{
     DiceCoseSignAndEncodeSign1, DiceGenerateCertificate, DiceHash, DiceKdf, DiceKeypairFromSeed,
     DicePrincipal, DiceSign, DiceVerify,
 };
+#[cfg(feature = "multialg")]
+use std::ffi::c_void;
 use std::ptr;
 
 /// Hashes the provided input using DICE's hash function `DiceHash`.
@@ -100,6 +106,44 @@
     Ok((public_key, private_key))
 }
 
+/// Deterministically generates a public and private key pair from `seed` and `key_algorithm`.
+/// Since this is deterministic, `seed` is as sensitive as a private key and can
+/// be used directly as the private key.
+#[cfg(feature = "multialg")]
+pub fn keypair_from_seed_multialg(
+    seed: &[u8; PRIVATE_KEY_SEED_SIZE],
+    key_algorithm: KeyAlgorithm,
+) -> Result<(Vec<u8>, PrivateKey)> {
+    let mut public_key = vec![0u8; key_algorithm.public_key_size()];
+    let mut private_key = PrivateKey::default();
+    // This function is used with an open-dice config that uses the same algorithms for the
+    // subject and authority. Therefore, the principal is irrelevant in this context as this
+    // function only derives the key pair cryptographically without caring about which
+    // principal it is for. Hence, we arbitrarily set it to `DicePrincipal::kDicePrincipalSubject`.
+    let principal = DicePrincipal::kDicePrincipalSubject;
+    let context = DiceContext_ {
+        authority_algorithm: key_algorithm.into(),
+        subject_algorithm: key_algorithm.into(),
+    };
+    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 is a pointer to a valid |DiceContext_| object for multi-alg
+        // open-dice.
+        unsafe {
+            DiceKeypairFromSeed(
+                &context as *const DiceContext_ as *mut c_void,
+                principal,
+                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
@@ -114,6 +158,17 @@
     Ok(private_key)
 }
 
+/// Multialg variant of `derive_cdi_leaf_priv`.
+#[cfg(feature = "multialg")]
+pub fn derive_cdi_leaf_priv_multialg(
+    dice_artifacts: &dyn DiceArtifacts,
+    key_algorithm: KeyAlgorithm,
+) -> Result<PrivateKey> {
+    let cdi_priv_key_seed = derive_cdi_private_key_seed(dice_artifacts.cdi_attest())?;
+    let (_, private_key) = keypair_from_seed_multialg(cdi_priv_key_seed.as_array(), key_algorithm)?;
+    Ok(private_key)
+}
+
 /// Signs the `message` with the given `private_key` using `DiceSign`.
 pub fn sign(message: &[u8], private_key: &[u8; PRIVATE_KEY_SIZE]) -> Result<Vec<u8>> {
     let mut signature = vec![0u8; VM_KEY_ALGORITHM.signature_size()];
@@ -173,6 +228,45 @@
     Ok(encoded_signature_actual_size)
 }
 
+/// Multialg variant of `sign_cose_sign1`.
+#[cfg(feature = "multialg")]
+pub fn sign_cose_sign1_multialg(
+    message: &[u8],
+    aad: &[u8],
+    private_key: &[u8; PRIVATE_KEY_SIZE],
+    encoded_signature: &mut [u8],
+    key_algorithm: KeyAlgorithm,
+) -> Result<usize> {
+    let mut encoded_signature_actual_size = 0;
+    let context = DiceContext_ {
+        authority_algorithm: key_algorithm.into(),
+        subject_algorithm: key_algorithm.into(),
+    };
+    check_result(
+        // SAFETY: The function writes to `encoded_signature` and `encoded_signature_actual_size`
+        // within the given bounds. It only reads `message`, `aad`, and `private_key` within their
+        // given bounds.
+        //
+        // The first argument is a pointer to a valid |DiceContext_| object for multi-alg
+        // open-dice.
+        unsafe {
+            DiceCoseSignAndEncodeSign1(
+                &context as *const DiceContext_ as *mut c_void,
+                message.as_ptr(),
+                message.len(),
+                aad.as_ptr(),
+                aad.len(),
+                private_key.as_ptr(),
+                encoded_signature.len(),
+                encoded_signature.as_mut_ptr(),
+                &mut encoded_signature_actual_size,
+            )
+        },
+        encoded_signature_actual_size,
+    )?;
+    Ok(encoded_signature_actual_size)
+}
+
 /// Signs the `message` with a private key derived from the given `dice_artifacts`
 /// CDI Attest. On success, places a `CoseSign1` encoded object in `encoded_signature`.
 /// Uses `DiceCoseSignAndEncodeSign1`.
@@ -188,6 +282,19 @@
     sign_cose_sign1(message, aad, private_key.as_array(), encoded_signature)
 }
 
+/// Multialg variant of `sign_cose_sign1_with_cdi_leaf_priv`.
+#[cfg(feature = "multialg")]
+pub fn sign_cose_sign1_with_cdi_leaf_priv_multialg(
+    message: &[u8],
+    aad: &[u8],
+    dice_artifacts: &dyn DiceArtifacts,
+    encoded_signature: &mut [u8],
+    key_algorithm: KeyAlgorithm,
+) -> Result<usize> {
+    let private_key = derive_cdi_leaf_priv_multialg(dice_artifacts, key_algorithm)?;
+    sign_cose_sign1_multialg(message, aad, private_key.as_array(), encoded_signature, key_algorithm)
+}
+
 /// Verifies the `signature` of the `message` with the given `public_key` using `DiceVerify`.
 pub fn verify(message: &[u8], signature: &[u8], public_key: &[u8]) -> Result<()> {
     if signature.len() != VM_KEY_ALGORITHM.signature_size()
@@ -212,6 +319,40 @@
     )
 }
 
+/// Multialg variant of `verify`.
+#[cfg(feature = "multialg")]
+pub fn verify_multialg(
+    message: &[u8],
+    signature: &[u8],
+    public_key: &[u8],
+    key_algorithm: KeyAlgorithm,
+) -> Result<()> {
+    if signature.len() != key_algorithm.signature_size()
+        || public_key.len() != key_algorithm.public_key_size()
+    {
+        return Err(DiceError::InvalidInput);
+    }
+    let context = DiceContext_ {
+        authority_algorithm: key_algorithm.into(),
+        subject_algorithm: key_algorithm.into(),
+    };
+    check_result(
+        // SAFETY: only reads the messages, signature and public key as constant values.
+        // The first argument is a pointer to a valid |DiceContext_| object for multi-alg
+        // open-dice.
+        unsafe {
+            DiceVerify(
+                &context as *const DiceContext_ as *mut c_void,
+                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
diff --git a/libs/dice/open_dice/src/retry.rs b/libs/dice/open_dice/src/retry.rs
index cf36bc0..d793218 100644
--- a/libs/dice/open_dice/src/retry.rs
+++ b/libs/dice/open_dice/src/retry.rs
@@ -24,6 +24,11 @@
 };
 use crate::error::{DiceError, Result};
 use crate::ops::{generate_certificate, sign_cose_sign1, sign_cose_sign1_with_cdi_leaf_priv};
+#[cfg(feature = "multialg")]
+use crate::{
+    ops::{sign_cose_sign1_multialg, sign_cose_sign1_with_cdi_leaf_priv_multialg},
+    KeyAlgorithm,
+};
 use alloc::vec::Vec;
 #[cfg(feature = "serde_derive")]
 use serde_derive::{Deserialize, Serialize};
@@ -158,6 +163,19 @@
     })
 }
 
+/// Multialg variant of `retry_sign_cose_sign1`.
+#[cfg(feature = "multialg")]
+pub fn retry_sign_cose_sign1_multialg(
+    message: &[u8],
+    aad: &[u8],
+    private_key: &[u8; PRIVATE_KEY_SIZE],
+    key_algorithm: KeyAlgorithm,
+) -> Result<Vec<u8>> {
+    retry_with_measured_buffer(|encoded_signature| {
+        sign_cose_sign1_multialg(message, aad, private_key, encoded_signature, key_algorithm)
+    })
+}
+
 /// Signs a message with the given the private key derived from the
 /// CDI Attest of the given `dice_artifacts` and returns the signature
 /// as an encoded CoseSign1 object.
@@ -170,3 +188,22 @@
         sign_cose_sign1_with_cdi_leaf_priv(message, aad, dice_artifacts, encoded_signature)
     })
 }
+
+/// Multialg variant of `retry_sign_cose_sign1_with_cdi_leaf_priv`.
+#[cfg(feature = "multialg")]
+pub fn retry_sign_cose_sign1_with_cdi_leaf_priv_multialg(
+    message: &[u8],
+    aad: &[u8],
+    dice_artifacts: &dyn DiceArtifacts,
+    key_algorithm: KeyAlgorithm,
+) -> Result<Vec<u8>> {
+    retry_with_measured_buffer(|encoded_signature| {
+        sign_cose_sign1_with_cdi_leaf_priv_multialg(
+            message,
+            aad,
+            dice_artifacts,
+            encoded_signature,
+            key_algorithm,
+        )
+    })
+}
diff --git a/libs/dice/open_dice/tests/api_test.rs b/libs/dice/open_dice/tests/api_test.rs
index b0c2ca7..0f8af10 100644
--- a/libs/dice/open_dice/tests/api_test.rs
+++ b/libs/dice/open_dice/tests/api_test.rs
@@ -21,6 +21,11 @@
         retry_sign_cose_sign1, retry_sign_cose_sign1_with_cdi_leaf_priv, sign, verify,
         DiceArtifacts, PrivateKey, CDI_SIZE, HASH_SIZE, ID_SIZE, PRIVATE_KEY_SEED_SIZE,
     };
+    #[cfg(feature = "multialg")]
+    use diced_open_dice::{
+        keypair_from_seed_multialg, retry_sign_cose_sign1_multialg,
+        retry_sign_cose_sign1_with_cdi_leaf_priv_multialg, verify_multialg, KeyAlgorithm,
+    };
 
     use coset::{CborSerializable, CoseSign1};
 
@@ -93,7 +98,21 @@
         0xfc, 0x23, 0xc9, 0x21, 0x5c, 0x48, 0x21, 0x47, 0xee, 0x5b, 0xfa, 0xaf, 0x88, 0x9a, 0x52,
         0xf1, 0x61, 0x06, 0x37,
     ];
-
+    #[cfg(feature = "multialg")]
+    const EXPECTED_EC_P256_PUB_KEY: &[u8] = &[
+        0xa7, 0x93, 0x70, 0x16, 0xff, 0xe8, 0x3c, 0x23, 0x5f, 0x6b, 0xf9, 0x38, 0x7e, 0x9c, 0xe5,
+        0x21, 0xb5, 0x8a, 0x9b, 0x68, 0x5a, 0x2f, 0x62, 0xf4, 0x15, 0x94, 0x1c, 0x61, 0xb3, 0xbb,
+        0xe1, 0x26, 0x61, 0x47, 0x97, 0xbf, 0x3a, 0x1f, 0x6b, 0x87, 0x86, 0x47, 0x5e, 0xc3, 0xa6,
+        0x8b, 0x95, 0x89, 0x9e, 0x29, 0xd5, 0x55, 0x2a, 0xdd, 0x2a, 0x3f, 0xe5, 0xf0, 0x7a, 0xd6,
+        0xc4, 0x7b, 0x64, 0xe0,
+    ];
+    #[cfg(feature = "multialg")]
+    const EXPECTED_EC_P256_PRIV_KEY: &[u8] = &[
+        0x62, 0x32, 0x1b, 0xb, 0x5c, 0xac, 0x8f, 0x20, 0x61, 0xb7, 0xa3, 0xbb, 0x46, 0x2b, 0x4e,
+        0xb3, 0x3f, 0xa7, 0xf6, 0x9b, 0x2f, 0x5b, 0x80, 0xa8, 0x55, 0x5e, 0x80, 0x26, 0xbb, 0x72,
+        0xbe, 0xe7, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+        0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+    ];
     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,
@@ -140,6 +159,41 @@
         assert!(verify_result.is_err());
     }
 
+    #[cfg(feature = "multialg")]
+    #[test]
+    fn sign_cose_sign1_verify_multialg() {
+        let (pub_key, priv_key) = get_test_key_pair_ec_p256();
+
+        let signature_res = retry_sign_cose_sign1_multialg(
+            b"MyMessage",
+            b"MyAad",
+            priv_key.as_array(),
+            KeyAlgorithm::EcdsaP256,
+        );
+        assert!(signature_res.is_ok());
+        let signature = signature_res.unwrap();
+        let cose_sign1_res = CoseSign1::from_slice(&signature);
+        assert!(cose_sign1_res.is_ok());
+        let mut cose_sign1 = cose_sign1_res.unwrap();
+
+        let mut verify_result = cose_sign1.verify_signature(b"MyAad", |sign, data| {
+            verify_multialg(data, sign, &pub_key, KeyAlgorithm::EcdsaP256)
+        });
+        assert!(verify_result.is_ok());
+
+        verify_result = cose_sign1.verify_signature(b"BadAad", |sign, data| {
+            verify_multialg(data, sign, &pub_key, KeyAlgorithm::EcdsaP256)
+        });
+        assert!(verify_result.is_err());
+
+        // if we modify the signature, the payload should no longer verify
+        cose_sign1.signature.push(0xAA);
+        verify_result = cose_sign1.verify_signature(b"MyAad", |sign, data| {
+            verify_multialg(data, sign, &pub_key, KeyAlgorithm::EcdsaP256)
+        });
+        assert!(verify_result.is_err());
+    }
+
     struct TestArtifactsForSigning {}
 
     impl DiceArtifacts for TestArtifactsForSigning {
@@ -182,6 +236,41 @@
         assert!(verify_result.is_err());
     }
 
+    #[cfg(feature = "multialg")]
+    #[test]
+    fn sign_cose_sign1_with_cdi_leaf_priv_verify_multialg() {
+        let dice = TestArtifactsForSigning {};
+
+        let signature_res = retry_sign_cose_sign1_with_cdi_leaf_priv_multialg(
+            b"MyMessage",
+            b"MyAad",
+            &dice,
+            KeyAlgorithm::EcdsaP256,
+        );
+        assert!(signature_res.is_ok());
+        let signature = signature_res.unwrap();
+        let cose_sign1_res = CoseSign1::from_slice(&signature);
+        assert!(cose_sign1_res.is_ok());
+        let mut cose_sign1 = cose_sign1_res.unwrap();
+
+        let mut verify_result = cose_sign1.verify_signature(b"MyAad", |sign, data| {
+            verify_multialg(data, sign, EXPECTED_EC_P256_PUB_KEY, KeyAlgorithm::EcdsaP256)
+        });
+        assert!(verify_result.is_ok());
+
+        verify_result = cose_sign1.verify_signature(b"BadAad", |sign, data| {
+            verify_multialg(data, sign, EXPECTED_EC_P256_PUB_KEY, KeyAlgorithm::EcdsaP256)
+        });
+        assert!(verify_result.is_err());
+
+        // if we modify the signature, the payload should no longer verify
+        cose_sign1.signature.push(0xAA);
+        verify_result = cose_sign1.verify_signature(b"MyAad", |sign, data| {
+            verify_multialg(data, sign, EXPECTED_EC_P256_PUB_KEY, KeyAlgorithm::EcdsaP256)
+        });
+        assert!(verify_result.is_err());
+    }
+
     fn get_test_key_pair() -> (Vec<u8>, PrivateKey) {
         let seed = hash(b"MySeedString").unwrap();
         assert_eq!(seed, EXPECTED_SEED);
@@ -196,4 +285,23 @@
 
         (pub_key, priv_key)
     }
+
+    #[cfg(feature = "multialg")]
+    fn get_test_key_pair_ec_p256() -> (Vec<u8>, PrivateKey) {
+        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_multialg(cdi_private_key_seed.as_array(), KeyAlgorithm::EcdsaP256)
+                .unwrap();
+
+        assert_eq!(&pub_key, EXPECTED_EC_P256_PUB_KEY);
+        assert_eq!(priv_key.as_array(), EXPECTED_EC_P256_PRIV_KEY);
+
+        (pub_key, priv_key)
+    }
 }