Encrypt instance.img data with key from sealing CDI
Microdroid connects to diced to retreive the sealing CDI from which it
derives the key used to encrypt the instance.img data.
Bug: 214231981
Test: run microdroid
Change-Id: Ifee99e3c55b649d236fefcbbc9132613fd35660e
diff --git a/microdroid_manager/Android.bp b/microdroid_manager/Android.bp
index 23a61d9..f888b80 100644
--- a/microdroid_manager/Android.bp
+++ b/microdroid_manager/Android.bp
@@ -9,6 +9,7 @@
edition: "2018",
prefer_rlib: true,
rustlibs: [
+ "android.security.dice-rust",
"android.system.virtualizationservice-rust",
"android.system.virtualmachineservice-rust",
"libanyhow",
diff --git a/microdroid_manager/src/instance.rs b/microdroid_manager/src/instance.rs
index aadb71f..3c322b7 100644
--- a/microdroid_manager/src/instance.rs
+++ b/microdroid_manager/src/instance.rs
@@ -33,7 +33,9 @@
//! The payload of a partition is encrypted/signed by a key that is unique to the loader and to the
//! VM as well. Failing to decrypt/authenticate a partition by a loader stops the boot process.
+use android_security_dice::aidl::android::security::dice::IDiceNode::IDiceNode;
use anyhow::{anyhow, bail, Context, Result};
+use binder::wait_for_interface;
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
use ring::aead::{Aad, Algorithm, LessSafeKey, Nonce, UnboundKey, AES_256_GCM};
use ring::hkdf::{Salt, HKDF_SHA256};
@@ -131,7 +133,7 @@
// Decrypt and authenticate the data (along with the header). The data is decrypted in
// place. `open_in_place` returns slice to the decrypted part in the buffer.
- let plaintext_len = get_key().open_in_place(nonce, Aad::from(&header), &mut data)?.len();
+ let plaintext_len = get_key()?.open_in_place(nonce, Aad::from(&header), &mut data)?.len();
// Truncate to remove the tag
data.truncate(plaintext_len);
@@ -174,7 +176,7 @@
// Then encrypt and sign the data. The non-encrypted input data is copied to a vector
// because it is encrypted in place, and also the tag is appended.
- get_key().seal_in_place_append_tag(nonce, Aad::from(&header), &mut data)?;
+ get_key()?.seal_in_place_append_tag(nonce, Aad::from(&header), &mut data)?;
// Persist the encrypted payload data
self.file.write_all(&data)?;
@@ -276,17 +278,18 @@
/// Returns the key that is used to encrypt the microdroid manager partition. It is derived from
/// the sealing CDI of the previous stage, which is Android Boot Loader (ABL).
-fn get_key() -> ZeroOnDropKey {
- // Sealing CDI from the previous stage. For now, this is hardcoded.
- // TODO(jiyong): actually read this from the previous stage
- const SEALING_CDI: [u8; 32] = [10; 32];
+fn get_key() -> Result<ZeroOnDropKey> {
+ // Sealing CDI from the previous stage.
+ let diced = wait_for_interface::<dyn IDiceNode>("android.security.dice.IDiceNode")
+ .context("IDiceNode service not found")?;
+ let bcc_handover = diced.derive(&[]).context("Failed to get BccHandover")?;
// Derive a key from the Sealing CDI
// Step 1 is extraction: https://datatracker.ietf.org/doc/html/rfc5869#section-2.2 where a
// pseduo random key (PRK) is extracted from (Input Keying Material - IKM, which is secret) and
// optional salt.
let salt = Salt::new(HKDF_SHA256, &[]); // use 0 as salt
- let prk = salt.extract(&SEALING_CDI); // Sealing CDI as IKM
+ let prk = salt.extract(&bcc_handover.cdiSeal); // Sealing CDI as IKM
// Step 2 is expansion: https://datatracker.ietf.org/doc/html/rfc5869#section-2.3 where the PRK
// (optionally with the `info` which gives contextual information) is expanded into the output
@@ -308,7 +311,7 @@
::std::ptr::write_volatile::<[u8; 32]>(&mut key, [0; 32]);
}
- ret
+ Ok(ret)
}
#[derive(Debug, Serialize, Deserialize, PartialEq)]