Do a DICE derivation for the payload

Send measurements of the payload to diced so that it can derive CDIs for
the payload to use.

Bug: 214231981
Test: run microdroid
Change-Id: I931b0835128cb0ab5ce537ec388b0d03c5ca201a
diff --git a/microdroid_manager/Android.bp b/microdroid_manager/Android.bp
index f888b80..1878c87 100644
--- a/microdroid_manager/Android.bp
+++ b/microdroid_manager/Android.bp
@@ -9,6 +9,7 @@
     edition: "2018",
     prefer_rlib: true,
     rustlibs: [
+        "android.hardware.security.dice-V1-rust",
         "android.security.dice-rust",
         "android.system.virtualizationservice-rust",
         "android.system.virtualmachineservice-rust",
@@ -18,6 +19,7 @@
         "libbinder_rpc_unstable_bindgen",
         "libbinder_rs",
         "libbyteorder",
+        "libdiced_utils",
         "libglob",
         "libidsig",
         "libitertools",
diff --git a/microdroid_manager/src/main.rs b/microdroid_manager/src/main.rs
index 960759e..3d145ee 100644
--- a/microdroid_manager/src/main.rs
+++ b/microdroid_manager/src/main.rs
@@ -19,10 +19,15 @@
 mod payload;
 
 use crate::instance::{ApkData, InstanceDisk, MicrodroidData, RootHash};
+use android_hardware_security_dice::aidl::android::hardware::security::dice::{
+    Config::Config, InputValues::InputValues, Mode::Mode,
+};
+use android_security_dice::aidl::android::security::dice::IDiceMaintenance::IDiceMaintenance;
 use anyhow::{anyhow, bail, ensure, Context, Error, Result};
 use apkverify::{get_public_key_der, verify};
 use binder::unstable_api::{new_spibinder, AIBinder};
-use binder::{FromIBinder, Strong};
+use binder::{wait_for_interface, FromIBinder, Strong};
+use diced_utils::cbor::encode_header;
 use glob::glob;
 use idsig::V4Signature;
 use itertools::sorted;
@@ -31,8 +36,10 @@
 use microdroid_payload_config::{Task, TaskType, VmPayloadConfig};
 use once_cell::sync::OnceCell;
 use payload::{get_apex_data_from_payload, load_metadata, to_metadata};
+use ring::digest;
 use rustutils::system_properties;
 use rustutils::system_properties::PropertyWatcher;
+use std::convert::TryInto;
 use std::fs::{self, create_dir, File, OpenOptions};
 use std::io::BufRead;
 use std::os::unix::io::{FromRawFd, IntoRawFd};
@@ -61,6 +68,8 @@
 
 const APEX_CONFIG_DONE_PROP: &str = "apex_config.done";
 const LOGD_ENABLED_PROP: &str = "ro.boot.logd.enabled";
+const ADBD_ENABLED_PROP: &str = "ro.boot.adb.enabled";
+const DEBUGGABLE_PROP: &str = "ro.boot.microdroid.debuggable";
 
 #[derive(thiserror::Error, Debug)]
 enum MicrodroidError {
@@ -137,6 +146,61 @@
     }
 }
 
+fn is_debuggable() -> Result<bool> {
+    // Read all the properties so the behaviour is most similar between debug and non-debug boots.
+    // Defensively default to debug enabled for unrecognised values.
+    let adb = system_properties::read_bool(ADBD_ENABLED_PROP, true)?;
+    let logd = system_properties::read_bool(LOGD_ENABLED_PROP, true)?;
+    let debuggable = system_properties::read_bool(DEBUGGABLE_PROP, true)?;
+    Ok(adb || logd || debuggable)
+}
+
+fn dice_derivation(verified_data: MicrodroidData, payload_config_path: &str) -> Result<()> {
+    // Calculate compound digests of code and authorities
+    let mut code_hash_ctx = digest::Context::new(&digest::SHA512);
+    let mut authority_hash_ctx = digest::Context::new(&digest::SHA512);
+    code_hash_ctx.update(verified_data.apk_data.root_hash.as_ref());
+    authority_hash_ctx.update(verified_data.apk_data.pubkey.as_ref());
+    for extra_apk in verified_data.extra_apks_data {
+        code_hash_ctx.update(extra_apk.root_hash.as_ref());
+        authority_hash_ctx.update(extra_apk.pubkey.as_ref());
+    }
+    for apex in verified_data.apex_data {
+        code_hash_ctx.update(apex.root_digest.as_ref());
+        authority_hash_ctx.update(apex.public_key.as_ref());
+    }
+    let code_hash = code_hash_ctx.finish().as_ref().try_into().unwrap();
+    let authority_hash = authority_hash_ctx.finish().as_ref().try_into().unwrap();
+
+    // {
+    //   -70002: "Microdroid payload",
+    //   -71000: payload_config_path
+    // }
+    let mut config_desc = vec![
+        0xa2, 0x3a, 0x00, 0x01, 0x11, 0x71, 0x72, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x64, 0x72, 0x6f,
+        0x69, 0x64, 0x20, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x3a, 0x00, 0x01, 0x15, 0x57,
+    ];
+    let config_path_bytes = payload_config_path.as_bytes();
+    encode_header(3, config_path_bytes.len().try_into().unwrap(), &mut config_desc)?;
+    config_desc.extend_from_slice(config_path_bytes);
+
+    // Send the details to diced
+    let diced =
+        wait_for_interface::<dyn IDiceMaintenance>("android.security.dice.IDiceMaintenance")
+            .context("IDiceMaintenance service not found")?;
+    diced
+        .demoteSelf(&[InputValues {
+            codeHash: code_hash,
+            config: Config { desc: config_desc },
+            authorityHash: authority_hash,
+            authorityDescriptor: None,
+            mode: if is_debuggable()? { Mode::DEBUG } else { Mode::NORMAL },
+            hidden: [0; 64],
+        }])
+        .context("IDiceMaintenance::demoteSelf failed")?;
+    Ok(())
+}
+
 fn try_run_payload(service: &Strong<dyn IVirtualMachineService>) -> Result<i32> {
     let metadata = load_metadata().context("Failed to load payload metadata")?;
 
@@ -182,6 +246,9 @@
     }
     mount_extra_apks(&config)?;
 
+    info!("DICE derivation for payload");
+    dice_derivation(verified_data, &metadata.payload_config_path)?;
+
     // Wait until apex config is done. (e.g. linker configuration for apexes)
     // TODO(jooyung): wait until sys.boot_completed?
     wait_for_apex_config_done()?;