Merge "Define multialg variants of the libdiced_open_dice targets." into main
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)
+ }
}