pvmfw: refactor: Expose DICE inputs to main()
Refactor the code to give the top-level business logic access to the
DICE inputs to be able to set the hidden input (salt) and make use of
the computed hashes, as it will be required to verify the content of the
instance.img entry.
Note: No functional change intended.
Test: atest MicrodroidHostTests
Change-Id: I111006fb4becc12f5b19480e5b8882754e193102
diff --git a/pvmfw/avb/src/verify.rs b/pvmfw/avb/src/verify.rs
index 67658fd..b03506c 100644
--- a/pvmfw/avb/src/verify.rs
+++ b/pvmfw/avb/src/verify.rs
@@ -23,13 +23,15 @@
/// Verified data returned when the payload verification succeeds.
#[derive(Debug, PartialEq, Eq)]
-pub struct VerifiedBootData {
+pub struct VerifiedBootData<'a> {
/// DebugLevel of the VM.
pub debug_level: DebugLevel,
/// Kernel digest.
pub kernel_digest: Digest,
/// Initrd digest if initrd exists.
pub initrd_digest: Option<Digest>,
+ /// Trusted public key.
+ pub public_key: &'a [u8],
}
/// This enum corresponds to the `DebugLevel` in `VirtualMachineConfig`.
@@ -94,11 +96,11 @@
}
/// Verifies the payload (signed kernel + initrd) against the trusted public key.
-pub fn verify_payload(
+pub fn verify_payload<'a>(
kernel: &[u8],
initrd: Option<&[u8]>,
- trusted_public_key: &[u8],
-) -> Result<VerifiedBootData, AvbSlotVerifyError> {
+ trusted_public_key: &'a [u8],
+) -> Result<VerifiedBootData<'a>, AvbSlotVerifyError> {
let mut payload = Payload::new(kernel, initrd, trusted_public_key);
let mut ops = Ops::from(&mut payload);
let kernel_verify_result = ops.verify_partition(PartitionName::Kernel.as_cstr())?;
@@ -119,6 +121,7 @@
debug_level: DebugLevel::None,
kernel_digest: kernel_descriptor.digest,
initrd_digest: None,
+ public_key: trusted_public_key,
});
}
@@ -142,5 +145,6 @@
debug_level,
kernel_digest: kernel_descriptor.digest,
initrd_digest: Some(initrd_descriptor.digest),
+ public_key: trusted_public_key,
})
}
diff --git a/pvmfw/avb/tests/api_test.rs b/pvmfw/avb/tests/api_test.rs
index 1d7369d..78f274a 100644
--- a/pvmfw/avb/tests/api_test.rs
+++ b/pvmfw/avb/tests/api_test.rs
@@ -53,16 +53,21 @@
#[test]
fn payload_expecting_no_initrd_passes_verification_with_no_initrd() -> Result<()> {
+ let public_key = load_trusted_public_key()?;
let verified_boot_data = verify_payload(
&fs::read(TEST_IMG_WITH_ONE_HASHDESC_PATH)?,
/*initrd=*/ None,
- &load_trusted_public_key()?,
+ &public_key,
)
.map_err(|e| anyhow!("Verification failed. Error: {}", e))?;
let kernel_digest = hash(&[&hex::decode("1111")?, &fs::read(UNSIGNED_TEST_IMG_PATH)?]);
- let expected_boot_data =
- VerifiedBootData { debug_level: DebugLevel::None, kernel_digest, initrd_digest: None };
+ let expected_boot_data = VerifiedBootData {
+ debug_level: DebugLevel::None,
+ kernel_digest,
+ initrd_digest: None,
+ public_key: &public_key,
+ };
assert_eq!(expected_boot_data, verified_boot_data);
Ok(())
diff --git a/pvmfw/avb/tests/utils.rs b/pvmfw/avb/tests/utils.rs
index 9942b98..6713846 100644
--- a/pvmfw/avb/tests/utils.rs
+++ b/pvmfw/avb/tests/utils.rs
@@ -102,16 +102,21 @@
initrd_salt: &[u8],
expected_debug_level: DebugLevel,
) -> Result<()> {
+ let public_key = load_trusted_public_key()?;
let kernel = load_latest_signed_kernel()?;
- let verified_boot_data = verify_payload(&kernel, Some(initrd), &load_trusted_public_key()?)
+ let verified_boot_data = verify_payload(&kernel, Some(initrd), &public_key)
.map_err(|e| anyhow!("Verification failed. Error: {}", e))?;
let footer = extract_avb_footer(&kernel)?;
let kernel_digest =
hash(&[&hash(&[b"bootloader"]), &kernel[..usize::try_from(footer.original_image_size)?]]);
let initrd_digest = Some(hash(&[&hash(&[initrd_salt]), initrd]));
- let expected_boot_data =
- VerifiedBootData { debug_level: expected_debug_level, kernel_digest, initrd_digest };
+ let expected_boot_data = VerifiedBootData {
+ debug_level: expected_debug_level,
+ kernel_digest,
+ initrd_digest,
+ public_key: &public_key,
+ };
assert_eq!(expected_boot_data, verified_boot_data);
Ok(())
diff --git a/pvmfw/src/dice.rs b/pvmfw/src/dice.rs
index e354666..9c5f59a 100644
--- a/pvmfw/src/dice.rs
+++ b/pvmfw/src/dice.rs
@@ -19,7 +19,7 @@
use core::ffi::CStr;
use core::mem::size_of;
use core::slice;
-use dice::bcc::Handover;
+
use dice::Config;
use dice::DiceMode;
use dice::InputValues;
@@ -42,35 +42,40 @@
hash(&digests)
}
-/// Derive the VM-specific secrets and certificate through DICE.
-pub fn derive_next_bcc(
- bcc: &Handover,
- next_bcc: &mut [u8],
- verified_boot_data: &VerifiedBootData,
- authority: &[u8],
-) -> dice::Result<usize> {
- let code_hash = to_dice_hash(verified_boot_data)?;
- let auth_hash = hash(authority)?;
- let mode = to_dice_mode(verified_boot_data.debug_level);
- let component_name = CStr::from_bytes_with_nul(b"vm_entry\0").unwrap();
- let mut config_descriptor_buffer = [0; 128];
- let config_descriptor_size = bcc_format_config_descriptor(
- Some(component_name),
- None, // component_version
- false, // resettable
- &mut config_descriptor_buffer,
- )?;
- let config = &config_descriptor_buffer[..config_descriptor_size];
+pub struct PartialInputs {
+ code_hash: dice::Hash,
+ auth_hash: dice::Hash,
+ mode: DiceMode,
+}
- let input_values = InputValues::new(
- code_hash,
- Config::Descriptor(config),
- auth_hash,
- mode,
- [0u8; HIDDEN_SIZE], // TODO(b/249723852): Get salt from instance.img (virtio-blk) and/or TRNG.
- );
+impl PartialInputs {
+ pub fn new(data: &VerifiedBootData) -> dice::Result<Self> {
+ let code_hash = to_dice_hash(data)?;
+ let auth_hash = hash(data.public_key)?;
+ let mode = to_dice_mode(data.debug_level);
- bcc.main_flow(&input_values, next_bcc)
+ Ok(Self { code_hash, auth_hash, mode })
+ }
+
+ pub fn into_input_values(self, salt: &[u8; HIDDEN_SIZE]) -> dice::Result<InputValues> {
+ let component_name = CStr::from_bytes_with_nul(b"vm_entry\0").unwrap();
+ let mut config_descriptor_buffer = [0; 128];
+ let config_descriptor_size = bcc_format_config_descriptor(
+ Some(component_name),
+ None, // component_version
+ false, // resettable
+ &mut config_descriptor_buffer,
+ )?;
+ let config = &config_descriptor_buffer[..config_descriptor_size];
+
+ Ok(InputValues::new(
+ self.code_hash,
+ Config::Descriptor(config),
+ self.auth_hash,
+ self.mode,
+ *salt,
+ ))
+ }
}
/// Flushes data caches over the provided address range.
diff --git a/pvmfw/src/main.rs b/pvmfw/src/main.rs
index be5a16a..f7774e4 100644
--- a/pvmfw/src/main.rs
+++ b/pvmfw/src/main.rs
@@ -38,7 +38,7 @@
use alloc::boxed::Box;
use crate::{
- dice::derive_next_bcc,
+ dice::PartialInputs,
entry::RebootReason,
fdt::add_dice_node,
helpers::flush,
@@ -90,13 +90,20 @@
})?;
// By leaking the slice, its content will be left behind for the next stage.
let next_bcc = Box::leak(next_bcc);
- let next_bcc_size =
- derive_next_bcc(bcc, next_bcc, &verified_boot_data, PUBLIC_KEY).map_err(|e| {
- error!("Failed to derive next-stage DICE secrets: {e:?}");
- RebootReason::SecretDerivationError
- })?;
- trace!("Next BCC: {:x?}", bcc::Handover::new(&next_bcc[..next_bcc_size]));
+ let dice_inputs = PartialInputs::new(&verified_boot_data).map_err(|e| {
+ error!("Failed to compute partial DICE inputs: {e:?}");
+ RebootReason::InternalError
+ })?;
+ let salt = [0; ::dice::HIDDEN_SIZE]; // TODO(b/249723852): Get from instance.img and/or TRNG.
+ let dice_inputs = dice_inputs.into_input_values(&salt).map_err(|e| {
+ error!("Failed to generate DICE inputs: {e:?}");
+ RebootReason::InternalError
+ })?;
+ let _ = bcc.main_flow(&dice_inputs, next_bcc).map_err(|e| {
+ error!("Failed to derive next-stage DICE secrets: {e:?}");
+ RebootReason::SecretDerivationError
+ })?;
flush(next_bcc);
add_dice_node(fdt, next_bcc.as_ptr() as usize, NEXT_BCC_SIZE).map_err(|e| {