Extract root hash instead of public key from microdroid vendor image

Bug: 285855436
Test: atest virtualizationmanager_device_test
Test: atest MicrodroidTests#bootsWithVendorPartition
Test: adb shell /apex/com.android.virt/bin/vm run-microdroid --vendor /vendor/etc/avf/microdroid/microdroid_vendor.img

Change-Id: I15bae3b53e52311ecbea644a6e78ab81e19f443e
diff --git a/virtualizationmanager/Android.bp b/virtualizationmanager/Android.bp
index 88e9c70..60c94fc 100644
--- a/virtualizationmanager/Android.bp
+++ b/virtualizationmanager/Android.bp
@@ -38,6 +38,7 @@
         "libclap",
         "libcommand_fds",
         "libdisk",
+        "libhex",
         "libhypervisor_props",
         "liblazy_static",
         "liblibc",
diff --git a/virtualizationmanager/src/aidl.rs b/virtualizationmanager/src/aidl.rs
index 7b30f48..8c2099f 100644
--- a/virtualizationmanager/src/aidl.rs
+++ b/virtualizationmanager/src/aidl.rs
@@ -116,7 +116,7 @@
 
 const UNFORMATTED_STORAGE_MAGIC: &str = "UNFORMATTED-STORAGE";
 
-/// Roughly estimated sufficient size for storing vendor public key into DTBO.
+/// Rough size for storing root digest of vendor hash descriptor into DTBO.
 const EMPTY_VENDOR_DT_OVERLAY_BUF_SIZE: usize = 10000;
 
 /// crosvm requires all partitions to be a multiple of 4KiB.
@@ -381,13 +381,17 @@
             check_gdb_allowed(config)?;
         }
 
-        let vendor_public_key = extract_vendor_public_key(config)
-            .context("Failed to extract vendor public key")
-            .or_service_specific_exception(-1)?;
-        let dtbo_vendor = if let Some(vendor_public_key) = vendor_public_key {
+        let vendor_hashtree_descriptor_root_digest =
+            extract_vendor_hashtree_descriptor_root_digest(config)
+                .context("Failed to extract root digest of vendor")
+                .or_service_specific_exception(-1)?;
+        let dtbo_vendor = if let Some(vendor_hashtree_descriptor_root_digest) =
+            vendor_hashtree_descriptor_root_digest
+        {
+            let root_digest_hex = hex::encode(vendor_hashtree_descriptor_root_digest);
             let dtbo_for_vendor_image = temporary_directory.join("dtbo_vendor");
-            create_dtbo_for_vendor_image(&vendor_public_key, &dtbo_for_vendor_image)
-                .context("Failed to write vendor_public_key")
+            create_dtbo_for_vendor_image(root_digest_hex.as_bytes(), &dtbo_for_vendor_image)
+                .context("Failed to write root digest of vendor")
                 .or_service_specific_exception(-1)?;
             let file = File::open(dtbo_for_vendor_image)
                 .context("Failed to open dtbo_vendor")
@@ -571,7 +575,9 @@
     }
 }
 
-fn extract_vendor_public_key(config: &VirtualMachineConfig) -> Result<Option<Vec<u8>>> {
+fn extract_vendor_hashtree_descriptor_root_digest(
+    config: &VirtualMachineConfig,
+) -> Result<Option<Vec<u8>>> {
     let VirtualMachineConfig::AppConfig(config) = config else {
         return Ok(None);
     };
@@ -586,15 +592,19 @@
     let size = file.metadata().context("Failed to get metadata from microdroid-vendor.img")?.len();
     let vbmeta = VbMetaImage::verify_reader_region(&file, 0, size)
         .context("Failed to get vbmeta from microdroid-vendor.img")?;
-    let vendor_public_key = vbmeta
-        .public_key()
-        .ok_or(anyhow!("No public key is extracted from microdroid-vendor.img"))?
-        .to_vec();
 
-    Ok(Some(vendor_public_key))
+    for descriptor in vbmeta.descriptors()?.iter() {
+        if let vbmeta::Descriptor::Hashtree(_) = descriptor {
+            return Ok(Some(descriptor.to_hashtree()?.root_digest().to_vec()));
+        }
+    }
+    Err(anyhow!("No root digest is extracted from microdroid-vendor.img"))
 }
 
-fn create_dtbo_for_vendor_image(vendor_public_key: &[u8], dtbo: &PathBuf) -> Result<()> {
+fn create_dtbo_for_vendor_image(
+    vendor_hashtree_descriptor_root_digest: &[u8],
+    dtbo: &PathBuf,
+) -> Result<()> {
     if dtbo.exists() {
         return Err(anyhow!("DTBO file already exists"));
     }
@@ -622,10 +632,16 @@
     let mut avf_node = overlay_node
         .add_subnode(avf_node_name.as_c_str())
         .map_err(|e| anyhow!("Failed to create avf node: {:?}", e))?;
-    let vendor_public_key_name = CString::new("vendor_public_key")?;
+    let vendor_hashtree_descriptor_root_digest_name =
+        CString::new("vendor_hashtree_descriptor_root_digest")?;
     avf_node
-        .setprop(vendor_public_key_name.as_c_str(), vendor_public_key)
-        .map_err(|e| anyhow!("Failed to set avf/vendor_public_key: {:?}", e))?;
+        .setprop(
+            vendor_hashtree_descriptor_root_digest_name.as_c_str(),
+            vendor_hashtree_descriptor_root_digest,
+        )
+        .map_err(|e| {
+            anyhow!("Failed to set avf/vendor_hashtree_descriptor_root_digest: {:?}", e)
+        })?;
 
     fdt.pack().map_err(|e| anyhow!("Failed to pack fdt: {:?}", e))?;
     let mut file = File::create(dtbo)?;
@@ -1528,13 +1544,14 @@
 
     #[test]
     fn test_create_dtbo_for_vendor_image() -> Result<()> {
-        let vendor_public_key = String::from("foo");
-        let vendor_public_key = vendor_public_key.as_bytes();
+        let vendor_hashtree_descriptor_root_digest = String::from("foo");
+        let vendor_hashtree_descriptor_root_digest =
+            vendor_hashtree_descriptor_root_digest.as_bytes();
 
         let tmp_dir = tempfile::TempDir::new()?;
         let dtbo_path = tmp_dir.path().to_path_buf().join("bar");
 
-        create_dtbo_for_vendor_image(vendor_public_key, &dtbo_path)?;
+        create_dtbo_for_vendor_image(vendor_hashtree_descriptor_root_digest, &dtbo_path)?;
 
         let data = std::fs::read(dtbo_path)?;
         let fdt = Fdt::from_slice(&data).unwrap();
@@ -1555,9 +1572,11 @@
         let Some(avf_node) = avf_node else {
             bail!("avf_node shouldn't be None.");
         };
-        let vendor_public_key_name = CString::new("vendor_public_key")?;
-        let key_from_dtbo = avf_node.getprop(vendor_public_key_name.as_c_str()).unwrap();
-        assert_eq!(key_from_dtbo, Some(vendor_public_key));
+        let vendor_hashtree_descriptor_root_digest_name =
+            CString::new("vendor_hashtree_descriptor_root_digest")?;
+        let digest_from_dtbo =
+            avf_node.getprop(vendor_hashtree_descriptor_root_digest_name.as_c_str()).unwrap();
+        assert_eq!(digest_from_dtbo, Some(vendor_hashtree_descriptor_root_digest));
 
         tmp_dir.close()?;
         Ok(())
@@ -1565,15 +1584,17 @@
 
     #[test]
     fn test_create_dtbo_for_vendor_image_throws_error_if_already_exists() -> Result<()> {
-        let vendor_public_key = String::from("foo");
-        let vendor_public_key = vendor_public_key.as_bytes();
+        let vendor_hashtree_descriptor_root_digest = String::from("foo");
+        let vendor_hashtree_descriptor_root_digest =
+            vendor_hashtree_descriptor_root_digest.as_bytes();
 
         let tmp_dir = tempfile::TempDir::new()?;
         let dtbo_path = tmp_dir.path().to_path_buf().join("bar");
 
-        create_dtbo_for_vendor_image(vendor_public_key, &dtbo_path)?;
+        create_dtbo_for_vendor_image(vendor_hashtree_descriptor_root_digest, &dtbo_path)?;
 
-        let ret_second_trial = create_dtbo_for_vendor_image(vendor_public_key, &dtbo_path);
+        let ret_second_trial =
+            create_dtbo_for_vendor_image(vendor_hashtree_descriptor_root_digest, &dtbo_path);
         assert!(ret_second_trial.is_err(), "should fail");
 
         tmp_dir.close()?;