Merge "pvmfw: Issue MMIO_GUARD_MAP for UART"
diff --git a/compos/compos_key_helper/Android.bp b/compos/compos_key_helper/Android.bp
index a932b40..fdfcfc1 100644
--- a/compos/compos_key_helper/Android.bp
+++ b/compos/compos_key_helper/Android.bp
@@ -24,10 +24,11 @@
defaults: ["compos_key_defaults"],
srcs: ["compos_key_main.cpp"],
- static_libs: ["libcompos_key"],
+ static_libs: [
+ "libcompos_key",
+ "libvm_payload",
+ ],
shared_libs: [
- "android.hardware.security.dice-V1-ndk",
- "android.security.dice-ndk",
"libbinder_ndk",
],
}
diff --git a/compos/compos_key_helper/compos_key_main.cpp b/compos/compos_key_helper/compos_key_main.cpp
index 9ba9f8d..77a9cf9 100644
--- a/compos/compos_key_helper/compos_key_main.cpp
+++ b/compos/compos_key_helper/compos_key_main.cpp
@@ -14,21 +14,15 @@
* limitations under the License.
*/
-#include <aidl/android/security/dice/IDiceNode.h>
#include <android-base/file.h>
#include <android-base/logging.h>
-#include <android/binder_auto_utils.h>
-#include <android/binder_manager.h>
#include <unistd.h>
+#include <vm_payload.h>
#include <string_view>
#include "compos_key.h"
-using aidl::android::hardware::security::dice::Bcc;
-using aidl::android::hardware::security::dice::BccHandover;
-using aidl::android::hardware::security::dice::InputValues;
-using aidl::android::security::dice::IDiceNode;
using android::base::Error;
using android::base::ReadFdToString;
using android::base::Result;
@@ -38,22 +32,15 @@
namespace {
Result<Ed25519KeyPair> deriveKeyFromDice() {
- ndk::SpAIBinder binder{AServiceManager_getService("android.security.dice.IDiceNode")};
- auto dice_node = IDiceNode::fromBinder(binder);
- if (!dice_node) {
- return Error() << "Unable to connect to IDiceNode";
- }
-
- const std::vector<InputValues> empty_input_values;
- BccHandover bcc;
- auto status = dice_node->derive(empty_input_values, &bcc);
- if (!status.isOk()) {
- return Error() << "Derive failed: " << status.getDescription();
+ uint8_t cdi_seal[64];
+ size_t cdi_size = get_dice_sealing_cdi(cdi_seal, sizeof(cdi_seal));
+ if (cdi_size == 0) {
+ return Error() << "Failed to get sealing CDI";
}
// We use the sealing CDI because we want stability - the key needs to be the same
// for any instance of the "same" VM.
- return compos_key::deriveKeyFromSecret(bcc.cdiSeal.data(), bcc.cdiSeal.size());
+ return compos_key::deriveKeyFromSecret(cdi_seal, cdi_size);
}
int write_public_key() {
@@ -70,22 +57,14 @@
}
int write_bcc() {
- ndk::SpAIBinder binder{AServiceManager_getService("android.security.dice.IDiceNode")};
- auto dice_node = IDiceNode::fromBinder(binder);
- if (!dice_node) {
- LOG(ERROR) << "Unable to connect to IDiceNode";
+ uint8_t bcc[2048];
+ size_t bcc_size = get_dice_attestation_chain(bcc, sizeof(bcc));
+ if (bcc_size == 0) {
+ LOG(ERROR) << "Failed to get attestation chain";
return 1;
}
- const std::vector<InputValues> empty_input_values;
- Bcc bcc;
- auto status = dice_node->getAttestationChain(empty_input_values, &bcc);
- if (!status.isOk()) {
- LOG(ERROR) << "GetAttestationChain failed: " << status.getDescription();
- return 1;
- }
-
- if (!WriteFully(STDOUT_FILENO, bcc.data.data(), bcc.data.size())) {
+ if (!WriteFully(STDOUT_FILENO, bcc, bcc_size)) {
PLOG(ERROR) << "Write failed";
return 1;
}
diff --git a/microdroid/Android.bp b/microdroid/Android.bp
index 10e5858..81f94bc 100644
--- a/microdroid/Android.bp
+++ b/microdroid/Android.bp
@@ -70,7 +70,6 @@
"apexd",
"atrace",
"debuggerd",
- "dice-service.microdroid",
"linker",
"linkerconfig",
"servicemanager.microdroid",
@@ -80,7 +79,6 @@
"task_profiles.json",
"public.libraries.android.txt",
- "microdroid_compatibility_matrix",
"microdroid_event-log-tags",
"microdroid_file_contexts",
"microdroid_manifest",
@@ -533,14 +531,6 @@
}
prebuilt_etc {
- name: "microdroid_compatibility_matrix",
- src: "microdroid_compatibility_matrix.xml",
- filename: "compatibility_matrix.current.xml",
- relative_install_path: "vintf",
- installable: false,
-}
-
-prebuilt_etc {
name: "microdroid_manifest",
src: "microdroid_manifest.xml",
filename: "manifest.xml",
diff --git a/microdroid/dice/Android.bp b/microdroid/dice/Android.bp
deleted file mode 100644
index 859533e..0000000
--- a/microdroid/dice/Android.bp
+++ /dev/null
@@ -1,26 +0,0 @@
-package {
- default_applicable_licenses: ["Android-Apache-2.0"],
-}
-
-rust_binary {
- name: "dice-service.microdroid",
- srcs: ["service.rs"],
- prefer_rlib: true,
- rustlibs: [
- "android.hardware.security.dice-V1-rust",
- "android.security.dice-rust",
- "libandroid_logger",
- "libanyhow",
- "libbinder_rs",
- "libbyteorder",
- "libdiced",
- "libdiced_open_dice_cbor",
- "libdiced_sample_inputs",
- "libdiced_utils",
- "liblibc",
- "liblog_rust",
- "libserde",
- ],
- init_rc: ["dice-service.microdroid.rc"],
- bootstrap: true,
-}
diff --git a/microdroid/dice/dice-service.microdroid.rc b/microdroid/dice/dice-service.microdroid.rc
deleted file mode 100644
index 5bcb049..0000000
--- a/microdroid/dice/dice-service.microdroid.rc
+++ /dev/null
@@ -1,3 +0,0 @@
-service dice-microdroid /system/bin/dice-service.microdroid
- user diced
- group diced
diff --git a/microdroid/dice/service.rs b/microdroid/dice/service.rs
deleted file mode 100644
index 2c19481..0000000
--- a/microdroid/dice/service.rs
+++ /dev/null
@@ -1,303 +0,0 @@
-// Copyright 2022, The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-//! Main entry point for the microdroid DICE service implementation.
-
-use android_hardware_security_dice::aidl::android::hardware::security::dice::{
- Bcc::Bcc, BccHandover::BccHandover, InputValues::InputValues as BinderInputValues,
- Signature::Signature,
-};
-use anyhow::{bail, ensure, Context, Error, Result};
-use byteorder::{NativeEndian, ReadBytesExt};
-use dice::{ContextImpl, OpenDiceCborContext};
-use diced::{dice, DiceMaintenance, DiceNode, DiceNodeImpl};
-use diced_utils::make_bcc_handover;
-use libc::{c_void, mmap, munmap, MAP_FAILED, MAP_PRIVATE, PROT_READ};
-use serde::{Deserialize, Serialize};
-use std::fs;
-use std::os::unix::io::AsRawFd;
-use std::panic;
-use std::path::{Path, PathBuf};
-use std::ptr::null_mut;
-use std::slice;
-use std::sync::{Arc, RwLock};
-
-const AVF_STRICT_BOOT: &str = "/sys/firmware/devicetree/base/chosen/avf,strict-boot";
-const DICE_NODE_SERVICE_NAME: &str = "android.security.dice.IDiceNode";
-const DICE_MAINTENANCE_SERVICE_NAME: &str = "android.security.dice.IDiceMaintenance";
-
-/// Artifacts that are mapped into the process address space from the driver.
-struct MappedDriverArtifacts<'a> {
- mmap_addr: *mut c_void,
- mmap_size: usize,
- cdi_attest: &'a [u8; dice::CDI_SIZE],
- cdi_seal: &'a [u8; dice::CDI_SIZE],
- bcc: &'a [u8],
-}
-
-impl MappedDriverArtifacts<'_> {
- fn new(driver_path: &Path) -> Result<Self> {
- let mut file = fs::File::open(driver_path)
- .map_err(|error| Error::new(error).context("Opening driver"))?;
- let mmap_size =
- file.read_u64::<NativeEndian>()
- .map_err(|error| Error::new(error).context("Reading driver"))? as usize;
- // It's safe to map the driver as the service will only create a single
- // mapping per process.
- let mmap_addr = unsafe {
- let fd = file.as_raw_fd();
- mmap(null_mut(), mmap_size, PROT_READ, MAP_PRIVATE, fd, 0)
- };
- if mmap_addr == MAP_FAILED {
- bail!("Failed to mmap {:?}", driver_path);
- }
- // The slice is created for the region of memory that was just
- // successfully mapped into the process address space so it will be
- // accessible and not referenced from anywhere else.
- let mmap_buf =
- unsafe { slice::from_raw_parts((mmap_addr as *const u8).as_ref().unwrap(), mmap_size) };
- // Very inflexible parsing / validation of the BccHandover data. Assumes deterministically
- // encoded CBOR.
- //
- // BccHandover = {
- // 1 : bstr .size 32, ; CDI_Attest
- // 2 : bstr .size 32, ; CDI_Seal
- // 3 : Bcc, ; Certificate chain
- // }
- if mmap_buf[0..4] != [0xa3, 0x01, 0x58, 0x20]
- || mmap_buf[36..39] != [0x02, 0x58, 0x20]
- || mmap_buf[71] != 0x03
- {
- bail!("BccHandover format mismatch");
- }
- Ok(Self {
- mmap_addr,
- mmap_size,
- cdi_attest: mmap_buf[4..36].try_into().unwrap(),
- cdi_seal: mmap_buf[39..71].try_into().unwrap(),
- bcc: &mmap_buf[72..],
- })
- }
-}
-
-impl Drop for MappedDriverArtifacts<'_> {
- fn drop(&mut self) {
- // All references to the mapped region have the same lifetime as self.
- // Since self is being dropped, so are all the references to the mapped
- // region meaning its safe to unmap.
- let ret = unsafe { munmap(self.mmap_addr, self.mmap_size) };
- if ret != 0 {
- log::warn!("Failed to munmap ({})", ret);
- }
- }
-}
-
-/// Artifacts that are kept in the process address space after the artifacts
-/// from the driver have been consumed.
-#[derive(Clone, Serialize, Deserialize)]
-struct RawArtifacts {
- cdi_attest: [u8; dice::CDI_SIZE],
- cdi_seal: [u8; dice::CDI_SIZE],
- bcc: Vec<u8>,
-}
-
-#[derive(Clone, Serialize, Deserialize)]
-enum UpdatableArtifacts {
- Invalid,
- Driver(PathBuf),
- Updated(RawArtifacts),
-}
-
-impl UpdatableArtifacts {
- fn get(
- &self,
- input_values: &BinderInputValues,
- ) -> Result<(dice::CdiAttest, dice::CdiSeal, Vec<u8>)> {
- let input_values: diced_utils::InputValues = input_values.into();
- match self {
- Self::Invalid => bail!("No DICE artifacts available."),
- Self::Driver(driver_path) => {
- let artifacts = MappedDriverArtifacts::new(driver_path.as_path())?;
- dice::OpenDiceCborContext::new().bcc_main_flow(
- artifacts.cdi_attest,
- artifacts.cdi_seal,
- artifacts.bcc,
- &input_values,
- )
- }
- Self::Updated(artifacts) => dice::OpenDiceCborContext::new().bcc_main_flow(
- &artifacts.cdi_attest,
- &artifacts.cdi_seal,
- &artifacts.bcc,
- &input_values,
- ),
- }
- .context("Deriving artifacts")
- }
-
- fn update(self, inputs: &BinderInputValues) -> Result<Self> {
- if let Self::Invalid = self {
- bail!("Cannot update invalid DICE artifacts.");
- }
- let (cdi_attest, cdi_seal, bcc) =
- self.get(inputs).context("Failed to get update artifacts.")?;
- if let Self::Driver(ref driver_path) = self {
- // Writing to the device wipes the artifacts. The string is ignored
- // by the driver but included for documentation.
- fs::write(driver_path, "wipe")
- .map_err(|error| Error::new(error).context("Wiping driver"))?;
- }
- Ok(Self::Updated(RawArtifacts {
- cdi_attest: cdi_attest[..].try_into().unwrap(),
- cdi_seal: cdi_seal[..].try_into().unwrap(),
- bcc,
- }))
- }
-}
-
-struct ArtifactManager {
- artifacts: RwLock<UpdatableArtifacts>,
-}
-
-impl ArtifactManager {
- fn new(driver_path: &Path) -> Self {
- Self {
- artifacts: RwLock::new(if driver_path.exists() {
- log::info!("Using DICE values from driver");
- UpdatableArtifacts::Driver(driver_path.to_path_buf())
- } else if Path::new(AVF_STRICT_BOOT).exists() {
- log::error!("Strict boot requires DICE value from driver but none were found");
- UpdatableArtifacts::Invalid
- } else {
- log::warn!("Using sample DICE values");
- let (cdi_attest, cdi_seal, bcc) = diced_sample_inputs::make_sample_bcc_and_cdis()
- .expect("Failed to create sample dice artifacts.");
- UpdatableArtifacts::Updated(RawArtifacts {
- cdi_attest: cdi_attest[..].try_into().unwrap(),
- cdi_seal: cdi_seal[..].try_into().unwrap(),
- bcc,
- })
- }),
- }
- }
-}
-
-impl DiceNodeImpl for ArtifactManager {
- fn sign(
- &self,
- client: BinderInputValues,
- input_values: &[BinderInputValues],
- message: &[u8],
- ) -> Result<Signature> {
- ensure!(input_values.is_empty(), "Extra input values not supported");
- let artifacts = self.artifacts.read().unwrap().clone();
- let (cdi_attest, _, _) =
- artifacts.get(&client).context("Failed to get signing artifacts.")?;
- let mut dice = OpenDiceCborContext::new();
- let seed = dice
- .derive_cdi_private_key_seed(
- cdi_attest[..].try_into().context("Failed to convert cdi_attest.")?,
- )
- .context("Failed to derive seed from cdi_attest.")?;
- let (_public_key, private_key) = dice
- .keypair_from_seed(seed[..].try_into().context("Failed to convert seed.")?)
- .context("Failed to derive keypair from seed.")?;
- let signature = dice
- .sign(message, private_key[..].try_into().context("Failed to convert private_key.")?)
- .context("Failed to sign.")?;
- Ok(Signature { data: signature })
- }
-
- fn get_attestation_chain(
- &self,
- client: BinderInputValues,
- input_values: &[BinderInputValues],
- ) -> Result<Bcc> {
- ensure!(input_values.is_empty(), "Extra input values not supported");
- let artifacts = self.artifacts.read().unwrap().clone();
- let (_, _, bcc) =
- artifacts.get(&client).context("Failed to get attestation chain artifacts.")?;
- Ok(Bcc { data: bcc })
- }
-
- fn derive(
- &self,
- client: BinderInputValues,
- input_values: &[BinderInputValues],
- ) -> Result<BccHandover> {
- ensure!(input_values.is_empty(), "Extra input values not supported");
- let artifacts = self.artifacts.read().unwrap().clone();
- let (cdi_attest, cdi_seal, bcc) =
- artifacts.get(&client).context("Failed to get attestation chain artifacts.")?;
- make_bcc_handover(
- &cdi_attest
- .to_vec()
- .as_slice()
- .try_into()
- .context("Trying to convert cdi_attest to sized array.")?,
- &cdi_seal
- .to_vec()
- .as_slice()
- .try_into()
- .context("Trying to convert cdi_seal to sized array.")?,
- &bcc,
- )
- .context("Trying to construct BccHandover.")
- }
-
- fn demote(
- &self,
- _client: BinderInputValues,
- _input_values: &[BinderInputValues],
- ) -> Result<()> {
- bail!("Demote not supported.");
- }
-
- fn demote_self(&self, input_values: &[BinderInputValues]) -> Result<()> {
- ensure!(input_values.len() == 1, "Can only demote_self one level.");
- let mut artifacts = self.artifacts.write().unwrap();
- *artifacts = (*artifacts).clone().update(&input_values[0])?;
- Ok(())
- }
-}
-
-fn main() {
- android_logger::init_once(
- android_logger::Config::default().with_tag("dice").with_min_level(log::Level::Debug),
- );
- // Redirect panic messages to logcat.
- panic::set_hook(Box::new(|panic_info| {
- log::error!("{}", panic_info);
- }));
-
- // Saying hi.
- log::info!("DICE service is starting.");
-
- let node_impl = Arc::new(ArtifactManager::new(Path::new("/dev/open-dice0")));
-
- let node = DiceNode::new_as_binder(node_impl.clone())
- .expect("Failed to create IDiceNode service instance.");
-
- let maintenance = DiceMaintenance::new_as_binder(node_impl)
- .expect("Failed to create IDiceMaintenance service instance.");
-
- binder::add_service(DICE_NODE_SERVICE_NAME, node.as_binder())
- .expect("Failed to register IDiceNode Service");
-
- binder::add_service(DICE_MAINTENANCE_SERVICE_NAME, maintenance.as_binder())
- .expect("Failed to register IDiceMaintenance Service");
-
- log::info!("Joining thread pool now.");
- binder::ProcessState::join_thread_pool();
-}
diff --git a/microdroid/init.rc b/microdroid/init.rc
index 8b2bbdb..2b4295f 100644
--- a/microdroid/init.rc
+++ b/microdroid/init.rc
@@ -67,8 +67,6 @@
start servicemanager
- start dice-microdroid
-
on init
mkdir /mnt/apk 0755 system system
mkdir /mnt/extra-apk 0755 root root
diff --git a/microdroid/microdroid_compatibility_matrix.xml b/microdroid/microdroid_compatibility_matrix.xml
deleted file mode 100644
index a345e30..0000000
--- a/microdroid/microdroid_compatibility_matrix.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<compatibility-matrix version="1.0" type="framework">
- <hal format="aidl" optional="true">
- <name>android.hardware.security.dice</name>
- <version>1</version>
- <interface>
- <name>IDiceDevice</name>
- <instance>default</instance>
- </interface>
- </hal>
-</compatibility-matrix>
diff --git a/microdroid/ueventd.rc b/microdroid/ueventd.rc
index fc165c8..268d3a2 100644
--- a/microdroid/ueventd.rc
+++ b/microdroid/ueventd.rc
@@ -28,4 +28,4 @@
# Virtual console for logcat
/dev/hvc2 0666 system system
-/dev/open-dice0 0660 diced diced
+/dev/open-dice0 0660 root root
diff --git a/microdroid/vm_payload/Android.bp b/microdroid/vm_payload/Android.bp
index 4f893d6..f7223ab 100644
--- a/microdroid/vm_payload/Android.bp
+++ b/microdroid/vm_payload/Android.bp
@@ -15,4 +15,7 @@
"libbinder_rs",
"liblog_rust",
],
+ apex_available: [
+ "com.android.compos",
+ ],
}
diff --git a/microdroid/vm_payload/include/vm_payload.h b/microdroid/vm_payload/include/vm_payload.h
index 36480da..6dba760 100644
--- a/microdroid/vm_payload/include/vm_payload.h
+++ b/microdroid/vm_payload/include/vm_payload.h
@@ -20,10 +20,34 @@
extern "C" {
#endif
-/// Notifies the host that the payload is ready.
-/// Returns true if the notification succeeds else false.
+/**
+ * Notifies the host that the payload is ready.
+ * Returns true if the notification succeeds else false.
+ */
bool notify_payload_ready();
+/**
+ * Get the VM's attestation chain.
+ * Returns the size of data or 0 on failure.
+ * TODO: don't expose the contained privacy breaking identifiers to the payload
+ * TODO: keep the DICE chain as an internal detail for as long as possible
+ */
+size_t get_dice_attestation_chain(void *data, size_t size);
+
+/**
+ * Get the VM's attestation CDI.
+ * Returns the size of data or 0 on failure.
+ * TODO: don't expose the raw CDI, only derived values
+ */
+size_t get_dice_attestation_cdi(void *data, size_t size);
+
+/**
+ * Get the VM's sealing CDI.
+ * Returns the size of data or 0 on failure.
+ * TODO: don't expose the raw CDI, only derived values
+ */
+size_t get_dice_sealing_cdi(void *data, size_t size);
+
#ifdef __cplusplus
} // extern "C"
#endif
diff --git a/microdroid/vm_payload/src/lib.rs b/microdroid/vm_payload/src/lib.rs
index 394578a..e3da227 100644
--- a/microdroid/vm_payload/src/lib.rs
+++ b/microdroid/vm_payload/src/lib.rs
@@ -16,4 +16,7 @@
mod vm_service;
-pub use vm_service::notify_payload_ready;
+pub use vm_service::{
+ get_dice_attestation_cdi, get_dice_attestation_chain, get_dice_sealing_cdi,
+ notify_payload_ready,
+};
diff --git a/microdroid/vm_payload/src/vm_service.rs b/microdroid/vm_payload/src/vm_service.rs
index 7414827..18d8222 100644
--- a/microdroid/vm_payload/src/vm_service.rs
+++ b/microdroid/vm_payload/src/vm_service.rs
@@ -28,7 +28,7 @@
android_logger::Config::default().with_tag("vm_payload").with_min_level(Level::Debug),
);
if let Err(e) = try_notify_payload_ready() {
- error!("Failed to notify ready: {}", e);
+ error!("{:?}", e);
false
} else {
info!("Notified host payload ready successfully");
@@ -42,6 +42,90 @@
get_vm_payload_service()?.notifyPayloadReady().context("Cannot notify payload ready")
}
+/// Get the VM's attestation chain.
+/// Returns the size of data or 0 on failure.
+///
+/// # Safety
+///
+/// The data must be size bytes big.
+#[no_mangle]
+pub unsafe extern "C" fn get_dice_attestation_chain(data: *mut u8, size: usize) -> usize {
+ match try_get_dice_attestation_chain() {
+ Err(e) => {
+ error!("{:?}", e);
+ 0
+ }
+ Ok(chain) => {
+ if size < chain.len() {
+ 0
+ } else {
+ std::ptr::copy_nonoverlapping(chain.as_ptr(), data, chain.len());
+ chain.len()
+ }
+ }
+ }
+}
+
+fn try_get_dice_attestation_chain() -> Result<Vec<u8>> {
+ get_vm_payload_service()?.getDiceAttestationChain().context("Cannot get attestation chain")
+}
+
+/// Get the VM's attestation CDI.
+/// Returns the size of data or 0 on failure.
+///
+/// # Safety
+///
+/// The data must be size bytes big.
+#[no_mangle]
+pub unsafe extern "C" fn get_dice_attestation_cdi(data: *mut u8, size: usize) -> usize {
+ match try_get_dice_attestation_cdi() {
+ Err(e) => {
+ error!("{:?}", e);
+ 0
+ }
+ Ok(cdi) => {
+ if size < cdi.len() {
+ 0
+ } else {
+ std::ptr::copy_nonoverlapping(cdi.as_ptr(), data, cdi.len());
+ cdi.len()
+ }
+ }
+ }
+}
+
+fn try_get_dice_attestation_cdi() -> Result<Vec<u8>> {
+ get_vm_payload_service()?.getDiceAttestationCdi().context("Cannot get attestation CDI")
+}
+
+/// Get the VM's sealing CDI.
+/// Returns the size of data or 0 on failure.
+///
+/// # Safety
+///
+/// The data must be size bytes big.
+#[no_mangle]
+pub unsafe extern "C" fn get_dice_sealing_cdi(data: *mut u8, size: usize) -> usize {
+ match try_get_dice_sealing_cdi() {
+ Err(e) => {
+ error!("{:?}", e);
+ 0
+ }
+ Ok(cdi) => {
+ if size < cdi.len() {
+ 0
+ } else {
+ std::ptr::copy_nonoverlapping(cdi.as_ptr(), data, cdi.len());
+ cdi.len()
+ }
+ }
+ }
+}
+
+fn try_get_dice_sealing_cdi() -> Result<Vec<u8>> {
+ get_vm_payload_service()?.getDiceSealingCdi().context("Cannot get sealing CDI")
+}
+
fn get_vm_payload_service() -> Result<Strong<dyn IVmPayloadService>> {
wait_for_interface(VM_PAYLOAD_SERVICE_NAME)
.context(format!("Failed to connect to service: {}", VM_PAYLOAD_SERVICE_NAME))
diff --git a/microdroid_manager/Android.bp b/microdroid_manager/Android.bp
index b281d5c..4b06b3e 100644
--- a/microdroid_manager/Android.bp
+++ b/microdroid_manager/Android.bp
@@ -9,8 +9,6 @@
edition: "2021",
prefer_rlib: true,
rustlibs: [
- "android.hardware.security.dice-V1-rust",
- "android.security.dice-rust",
"android.system.virtualizationcommon-rust",
"android.system.virtualizationservice-rust",
"android.system.virtualmachineservice-rust",
@@ -20,6 +18,9 @@
"libapkverify",
"libbinder_rs",
"libbyteorder",
+ "libdiced",
+ "libdiced_open_dice_cbor",
+ "libdiced_sample_inputs",
"libdiced_utils",
"libglob",
"libitertools",
diff --git a/microdroid_manager/aidl/Android.bp b/microdroid_manager/aidl/Android.bp
index 98ce6f5..0aa8662 100644
--- a/microdroid_manager/aidl/Android.bp
+++ b/microdroid_manager/aidl/Android.bp
@@ -11,6 +11,7 @@
enabled: true,
apex_available: [
"com.android.virt",
+ "com.android.compos",
],
},
},
diff --git a/microdroid_manager/aidl/android/system/virtualization/payload/IVmPayloadService.aidl b/microdroid_manager/aidl/android/system/virtualization/payload/IVmPayloadService.aidl
index 82cbf43..9f56957 100644
--- a/microdroid_manager/aidl/android/system/virtualization/payload/IVmPayloadService.aidl
+++ b/microdroid_manager/aidl/android/system/virtualization/payload/IVmPayloadService.aidl
@@ -26,4 +26,31 @@
/** Notifies that the payload is ready to serve. */
void notifyPayloadReady();
+
+ /**
+ * Gets the DICE attestation chain for the VM.
+ *
+ * STOPSHIP:
+ * TODO: don't expose this to untrusted payloads as it contains privacy breaking identifiers.
+ */
+ byte[] getDiceAttestationChain();
+
+ /**
+ * Gets the DICE attestation CDI for the VM.
+ *
+ * STOPSHIP:
+ * TODO: A better API would handle key derivation on behalf of the payload so they can't forget
+ * to do it themselves. It also means the payload doesn't get the raw CDI so there's less chance
+ * of it leaking.
+ */
+ byte[] getDiceAttestationCdi();
+
+ /**
+ * Gets the DICE sealing CDI for the VM.
+ *
+ * TODO: A better API would handle key derivation on behalf of the payload so they can't forget
+ * to do it themselves. It also means the payload doesn't get the raw CDI so there's less chance
+ * of it leaking.
+ */
+ byte[] getDiceSealingCdi();
}
diff --git a/microdroid_manager/src/dice.rs b/microdroid_manager/src/dice.rs
new file mode 100644
index 0000000..3881db3
--- /dev/null
+++ b/microdroid_manager/src/dice.rs
@@ -0,0 +1,177 @@
+// Copyright 2022, The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+//! Logic for handling the DICE values and boot operations.
+
+use anyhow::{bail, Context, Error, Result};
+use byteorder::{NativeEndian, ReadBytesExt};
+use diced_open_dice_cbor::{
+ Config, ContextImpl, InputValuesOwned, Mode, OpenDiceCborContext, CDI_SIZE, HASH_SIZE,
+ HIDDEN_SIZE,
+};
+use keystore2_crypto::ZVec;
+use libc::{c_void, mmap, munmap, MAP_FAILED, MAP_PRIVATE, PROT_READ};
+use openssl::hkdf::hkdf;
+use openssl::md::Md;
+use std::fs;
+use std::os::unix::io::AsRawFd;
+use std::path::{Path, PathBuf};
+use std::ptr::null_mut;
+use std::slice;
+
+/// Artifacts that are kept in the process address space after the artifacts from the driver have
+/// been consumed.
+pub struct DiceContext {
+ pub cdi_attest: [u8; CDI_SIZE],
+ pub cdi_seal: [u8; CDI_SIZE],
+ pub bcc: Vec<u8>,
+}
+
+/// Artifacts that are mapped into the process address space from the driver.
+pub enum DiceDriver<'a> {
+ Real {
+ driver_path: PathBuf,
+ mmap_addr: *mut c_void,
+ mmap_size: usize,
+ cdi_attest: &'a [u8; CDI_SIZE],
+ cdi_seal: &'a [u8; CDI_SIZE],
+ bcc: &'a [u8],
+ },
+ Fake(DiceContext),
+}
+
+impl DiceDriver<'_> {
+ pub fn new(driver_path: &Path) -> Result<Self> {
+ if driver_path.exists() {
+ log::info!("Using DICE values from driver");
+ } else if super::is_strict_boot() {
+ bail!("Strict boot requires DICE value from driver but none were found");
+ } else {
+ log::warn!("Using sample DICE values");
+ let (cdi_attest, cdi_seal, bcc) = diced_sample_inputs::make_sample_bcc_and_cdis()
+ .expect("Failed to create sample dice artifacts.");
+ return Ok(Self::Fake(DiceContext {
+ cdi_attest: cdi_attest[..].try_into().unwrap(),
+ cdi_seal: cdi_seal[..].try_into().unwrap(),
+ bcc,
+ }));
+ };
+
+ let mut file = fs::File::open(driver_path)
+ .map_err(|error| Error::new(error).context("Opening driver"))?;
+ let mmap_size =
+ file.read_u64::<NativeEndian>()
+ .map_err(|error| Error::new(error).context("Reading driver"))? as usize;
+ // It's safe to map the driver as the service will only create a single
+ // mapping per process.
+ let mmap_addr = unsafe {
+ let fd = file.as_raw_fd();
+ mmap(null_mut(), mmap_size, PROT_READ, MAP_PRIVATE, fd, 0)
+ };
+ if mmap_addr == MAP_FAILED {
+ bail!("Failed to mmap {:?}", driver_path);
+ }
+ // The slice is created for the region of memory that was just
+ // successfully mapped into the process address space so it will be
+ // accessible and not referenced from anywhere else.
+ let mmap_buf =
+ unsafe { slice::from_raw_parts((mmap_addr as *const u8).as_ref().unwrap(), mmap_size) };
+ // Very inflexible parsing / validation of the BccHandover data. Assumes deterministically
+ // encoded CBOR.
+ //
+ // BccHandover = {
+ // 1 : bstr .size 32, ; CDI_Attest
+ // 2 : bstr .size 32, ; CDI_Seal
+ // 3 : Bcc, ; Certificate chain
+ // }
+ if mmap_buf[0..4] != [0xa3, 0x01, 0x58, 0x20]
+ || mmap_buf[36..39] != [0x02, 0x58, 0x20]
+ || mmap_buf[71] != 0x03
+ {
+ bail!("BccHandover format mismatch");
+ }
+ Ok(Self::Real {
+ driver_path: driver_path.to_path_buf(),
+ mmap_addr,
+ mmap_size,
+ cdi_attest: mmap_buf[4..36].try_into().unwrap(),
+ cdi_seal: mmap_buf[39..71].try_into().unwrap(),
+ bcc: &mmap_buf[72..],
+ })
+ }
+
+ pub fn get_sealing_key(&self, identifier: &[u8]) -> Result<ZVec> {
+ // Deterministically derive a key to use for sealing data, rather than using the CDI
+ // directly, so we have the chance to rotate the key if needed. A salt isn't needed as the
+ // input key material is already cryptographically strong.
+ let cdi_seal = match self {
+ Self::Real { cdi_seal, .. } => cdi_seal,
+ Self::Fake(fake) => &fake.cdi_seal,
+ };
+ let salt = &[];
+ let mut key = ZVec::new(32)?;
+ hkdf(&mut key, Md::sha256(), cdi_seal, salt, identifier)?;
+ Ok(key)
+ }
+
+ pub fn derive(
+ self,
+ code_hash: [u8; HASH_SIZE],
+ config_desc: &[u8],
+ authority_hash: [u8; HASH_SIZE],
+ debug: bool,
+ hidden: [u8; HIDDEN_SIZE],
+ ) -> Result<DiceContext> {
+ let input_values = InputValuesOwned::new(
+ code_hash,
+ Config::Descriptor(config_desc),
+ authority_hash,
+ None,
+ if debug { Mode::Debug } else { Mode::Normal },
+ hidden,
+ );
+ let (cdi_attest, cdi_seal, bcc) = match &self {
+ Self::Real { cdi_attest, cdi_seal, bcc, .. } => (*cdi_attest, *cdi_seal, *bcc),
+ Self::Fake(fake) => (&fake.cdi_attest, &fake.cdi_seal, fake.bcc.as_slice()),
+ };
+ let (cdi_attest, cdi_seal, bcc) = OpenDiceCborContext::new()
+ .bcc_main_flow(cdi_attest, cdi_seal, bcc, &input_values)
+ .context("DICE derive from driver")?;
+ if let Self::Real { driver_path, .. } = &self {
+ // Writing to the device wipes the artifacts. The string is ignored by the driver but
+ // included for documentation.
+ fs::write(driver_path, "wipe")
+ .map_err(|err| Error::new(err).context("Wiping driver"))?;
+ }
+ Ok(DiceContext {
+ cdi_attest: cdi_attest[..].try_into().unwrap(),
+ cdi_seal: cdi_seal[..].try_into().unwrap(),
+ bcc,
+ })
+ }
+}
+
+impl Drop for DiceDriver<'_> {
+ fn drop(&mut self) {
+ if let &mut Self::Real { mmap_addr, mmap_size, .. } = self {
+ // All references to the mapped region have the same lifetime as self. Since self is
+ // being dropped, so are all the references to the mapped region meaning its safe to
+ // unmap.
+ let ret = unsafe { munmap(mmap_addr, mmap_size) };
+ if ret != 0 {
+ log::warn!("Failed to munmap ({})", ret);
+ }
+ }
+ }
+}
diff --git a/microdroid_manager/src/instance.rs b/microdroid_manager/src/instance.rs
index 358d88b..96e9360 100644
--- a/microdroid_manager/src/instance.rs
+++ b/microdroid_manager/src/instance.rs
@@ -33,15 +33,11 @@
//! 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 crate::dice::DiceDriver;
use crate::ioutil;
-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 keystore2_crypto::ZVec;
-use openssl::hkdf::hkdf;
-use openssl::md::Md;
use openssl::symm::{decrypt_aead, encrypt_aead, Cipher};
use serde::{Deserialize, Serialize};
use std::fs::{File, OpenOptions};
@@ -51,6 +47,9 @@
/// Path to the instance disk inside the VM
const INSTANCE_IMAGE_PATH: &str = "/dev/block/by-name/vm-instance";
+/// Identifier for the key used to seal the instance data.
+const INSTANCE_KEY_IDENTIFIER: &[u8] = b"microdroid_manager_key";
+
/// Magic string in the instance disk header
const DISK_HEADER_MAGIC: &str = "Android-VM-instance";
@@ -114,7 +113,7 @@
/// Reads the identity data that was written by microdroid manager. The returned data is
/// plaintext, although it is stored encrypted. In case when the partition for microdroid
/// manager doesn't exist, which can happen if it's the first boot, `Ok(None)` is returned.
- pub fn read_microdroid_data(&mut self) -> Result<Option<MicrodroidData>> {
+ pub fn read_microdroid_data(&mut self, dice: &DiceDriver) -> Result<Option<MicrodroidData>> {
let (header, offset) = self.locate_microdroid_header()?;
if header.is_none() {
return Ok(None);
@@ -143,7 +142,7 @@
self.file.read_exact(&mut header)?;
// Decrypt and authenticate the data (along with the header).
- let key = get_key()?;
+ let key = dice.get_sealing_key(INSTANCE_KEY_IDENTIFIER)?;
let plaintext =
decrypt_aead(Cipher::aes_256_gcm(), &key, Some(&nonce), &header, &data, &tag)?;
@@ -153,7 +152,11 @@
/// Writes identity data to the partition for microdroid manager. The partition is appended
/// if it doesn't exist. The data is stored encrypted.
- pub fn write_microdroid_data(&mut self, microdroid_data: &MicrodroidData) -> Result<()> {
+ pub fn write_microdroid_data(
+ &mut self,
+ microdroid_data: &MicrodroidData,
+ dice: &DiceDriver,
+ ) -> Result<()> {
let (header, offset) = self.locate_microdroid_header()?;
let data = serde_cbor::to_vec(microdroid_data)?;
@@ -185,7 +188,7 @@
self.file.write_all(nonce.as_ref())?;
// Then encrypt and sign the data.
- let key = get_key()?;
+ let key = dice.get_sealing_key(INSTANCE_KEY_IDENTIFIER)?;
let mut tag = [0; AES_256_GCM_TAG_LENGTH];
let ciphertext =
encrypt_aead(Cipher::aes_256_gcm(), &key, Some(&nonce), &header, &data, &mut tag)?;
@@ -268,23 +271,6 @@
Ok(ret)
}
-/// 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() -> Result<ZVec> {
- // 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")?;
- // Deterministically derive another key to use for encrypting the data, rather than using the
- // CDI directly, so we have the chance to rotate the key if needed. A salt isn't needed as the
- // input key material is already cryptographically strong.
- let salt = &[];
- let info = b"microdroid_manager_key".as_ref();
- let mut key = ZVec::new(32)?;
- hkdf(&mut key, Md::sha256(), &bcc_handover.cdiSeal, salt, info)?;
- Ok(key)
-}
-
#[derive(Debug, Serialize, Deserialize, PartialEq, Eq)]
pub struct MicrodroidData {
pub salt: Vec<u8>, // Should be [u8; 64] but that isn't serializable.
diff --git a/microdroid_manager/src/main.rs b/microdroid_manager/src/main.rs
index 1349ede..49dcacb 100644
--- a/microdroid_manager/src/main.rs
+++ b/microdroid_manager/src/main.rs
@@ -14,24 +14,22 @@
//! Microdroid Manager
+mod dice;
mod instance;
mod ioutil;
mod payload;
mod vm_payload_service;
+use crate::dice::{DiceContext, DiceDriver};
use crate::instance::{ApexData, ApkData, InstanceDisk, MicrodroidData, RootHash};
use crate::vm_payload_service::register_vm_payload_service;
-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 android_system_virtualizationcommon::aidl::android::system::virtualizationcommon::ErrorCode::ErrorCode;
use android_system_virtualmachineservice::aidl::android::system::virtualmachineservice::IVirtualMachineService::{
VM_BINDER_SERVICE_PORT, VM_STREAM_SERVICE_PORT, IVirtualMachineService,
};
use anyhow::{anyhow, bail, ensure, Context, Error, Result};
use apkverify::{get_public_key_der, verify, V4Signature};
-use binder::{ProcessState, wait_for_interface, Strong};
+use binder::{ProcessState, Strong};
use diced_utils::cbor::{encode_header, encode_number};
use glob::glob;
use itertools::sorted;
@@ -194,9 +192,10 @@
}
fn dice_derivation(
+ dice: DiceDriver,
verified_data: &MicrodroidData,
payload_metadata: &PayloadMetadata,
-) -> Result<()> {
+) -> Result<DiceContext> {
// Calculate compound digests of code and authorities
let mut code_hash_ctx = Sha512::new();
let mut authority_hash_ctx = Sha512::new();
@@ -247,20 +246,8 @@
let app_debuggable = system_properties::read_bool(APP_DEBUGGABLE_PROP, true)?;
// 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 app_debuggable { Mode::DEBUG } else { Mode::NORMAL },
- hidden: verified_data.salt.clone().try_into().unwrap(),
- }])
- .context("IDiceMaintenance::demoteSelf failed")?;
- Ok(())
+ let hidden = verified_data.salt.clone().try_into().unwrap();
+ dice.derive(code_hash, &config_desc, authority_hash, app_debuggable, hidden)
}
fn encode_tstr(tstr: &str, buffer: &mut Vec<u8>) -> Result<()> {
@@ -290,9 +277,11 @@
fn try_run_payload(service: &Strong<dyn IVirtualMachineService>) -> Result<i32> {
let metadata = load_metadata().context("Failed to load payload metadata")?;
+ let dice = DiceDriver::new(Path::new("/dev/open-dice0")).context("Failed to load DICE")?;
let mut instance = InstanceDisk::new().context("Failed to load instance.img")?;
- let saved_data = instance.read_microdroid_data().context("Failed to read identity data")?;
+ let saved_data =
+ instance.read_microdroid_data(&dice).context("Failed to read identity data")?;
if is_strict_boot() {
// Provisioning must happen on the first boot and never again.
@@ -333,7 +322,9 @@
saved_data
} else {
info!("Saving verified data.");
- instance.write_microdroid_data(&verified_data).context("Failed to write identity data")?;
+ instance
+ .write_microdroid_data(&verified_data, &dice)
+ .context("Failed to write identity data")?;
verified_data
};
@@ -343,7 +334,7 @@
// To minimize the exposure to untrusted data, derive dice profile as soon as possible.
info!("DICE derivation for payload");
- dice_derivation(&verified_data, &payload_metadata)?;
+ let dice = dice_derivation(dice, &verified_data, &payload_metadata)?;
// Before reading a file from the APK, start zipfuse
let noexec = false;
@@ -388,7 +379,7 @@
}
system_properties::write("dev.bootcomplete", "1").context("set dev.bootcomplete")?;
- register_vm_payload_service(service.clone())?;
+ register_vm_payload_service(service.clone(), dice)?;
ProcessState::start_thread_pool();
exec_task(task, service)
}
diff --git a/microdroid_manager/src/vm_payload_service.rs b/microdroid_manager/src/vm_payload_service.rs
index 0050a4c..70117c0 100644
--- a/microdroid_manager/src/vm_payload_service.rs
+++ b/microdroid_manager/src/vm_payload_service.rs
@@ -14,6 +14,7 @@
//! Implementation of the AIDL interface `IVmPayloadService`.
+use crate::dice::DiceContext;
use android_system_virtualization_payload::aidl::android::system::virtualization::payload::IVmPayloadService::{
BnVmPayloadService, IVmPayloadService, VM_PAYLOAD_SERVICE_NAME};
use android_system_virtualmachineservice::aidl::android::system::virtualmachineservice::IVirtualMachineService::IVirtualMachineService;
@@ -23,29 +24,43 @@
/// Implementation of `IVmPayloadService`.
struct VmPayloadService {
virtual_machine_service: Strong<dyn IVirtualMachineService>,
+ dice: DiceContext,
}
impl IVmPayloadService for VmPayloadService {
fn notifyPayloadReady(&self) -> binder::Result<()> {
self.virtual_machine_service.notifyPayloadReady()
}
+
+ fn getDiceAttestationChain(&self) -> binder::Result<Vec<u8>> {
+ Ok(self.dice.bcc.clone())
+ }
+
+ fn getDiceAttestationCdi(&self) -> binder::Result<Vec<u8>> {
+ Ok(self.dice.cdi_attest.to_vec())
+ }
+
+ fn getDiceSealingCdi(&self) -> binder::Result<Vec<u8>> {
+ Ok(self.dice.cdi_seal.to_vec())
+ }
}
impl Interface for VmPayloadService {}
impl VmPayloadService {
/// Creates a new `VmPayloadService` instance from the `IVirtualMachineService` reference.
- fn new(vm_service: Strong<dyn IVirtualMachineService>) -> Self {
- Self { virtual_machine_service: vm_service }
+ fn new(vm_service: Strong<dyn IVirtualMachineService>, dice: DiceContext) -> Self {
+ Self { virtual_machine_service: vm_service, dice }
}
}
/// Registers the `IVmPayloadService` service.
pub(crate) fn register_vm_payload_service(
vm_service: Strong<dyn IVirtualMachineService>,
+ dice: DiceContext,
) -> Result<()> {
let vm_payload_binder = BnVmPayloadService::new_binder(
- VmPayloadService::new(vm_service),
+ VmPayloadService::new(vm_service, dice),
BinderFeatures::default(),
);
add_service(VM_PAYLOAD_SERVICE_NAME, vm_payload_binder.as_binder())
diff --git a/tests/testapk/Android.bp b/tests/testapk/Android.bp
index 9e6958c..e1c8124 100644
--- a/tests/testapk/Android.bp
+++ b/tests/testapk/Android.bp
@@ -32,7 +32,6 @@
name: "MicrodroidTestNativeLib",
srcs: ["src/native/testbinary.cpp"],
shared_libs: [
- "android.security.dice-ndk",
"com.android.microdroid.testservice-ndk",
"libbase",
"libbinder_ndk",
diff --git a/tests/testapk/src/native/testbinary.cpp b/tests/testapk/src/native/testbinary.cpp
index fd8e776..d1cfc56 100644
--- a/tests/testapk/src/native/testbinary.cpp
+++ b/tests/testapk/src/native/testbinary.cpp
@@ -13,7 +13,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-#include <aidl/android/security/dice/IDiceNode.h>
#include <aidl/com/android/microdroid/testservice/BnTestService.h>
#include <android-base/file.h>
#include <android-base/properties.h>
@@ -28,15 +27,11 @@
#include <sys/ioctl.h>
#include <sys/system_properties.h>
#include <unistd.h>
+#include <vm_payload.h>
#include <binder_rpc_unstable.hpp>
#include <string>
-#include "vm_payload.h"
-
-using aidl::android::hardware::security::dice::BccHandover;
-using aidl::android::security::dice::IDiceNode;
-
using android::base::ErrnoError;
using android::base::Error;
using android::base::Result;
@@ -79,53 +74,35 @@
}
ndk::ScopedAStatus insecurelyExposeSealingCdi(std::vector<uint8_t>* out) override {
- ndk::SpAIBinder binder(AServiceManager_getService("android.security.dice.IDiceNode"));
- auto service = IDiceNode::fromBinder(binder);
- if (service == nullptr) {
+ uint8_t cdi[64];
+ size_t cdi_size = get_dice_sealing_cdi(cdi, sizeof(cdi));
+ if (cdi_size == 0) {
return ndk::ScopedAStatus::
- fromServiceSpecificErrorWithMessage(0, "Failed to find diced");
+ fromServiceSpecificErrorWithMessage(0, "Failed to get sealing cdi");
}
- BccHandover handover;
- auto deriveStatus = service->derive({}, &handover);
- if (!deriveStatus.isOk()) {
- return ndk::ScopedAStatus::fromServiceSpecificErrorWithMessage(0,
- "Failed call diced");
- }
- *out = {handover.cdiSeal.begin(), handover.cdiSeal.end()};
+ *out = {cdi, cdi + cdi_size};
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus insecurelyExposeAttestationCdi(std::vector<uint8_t>* out) override {
- ndk::SpAIBinder binder(AServiceManager_getService("android.security.dice.IDiceNode"));
- auto service = IDiceNode::fromBinder(binder);
- if (service == nullptr) {
+ uint8_t cdi[64];
+ size_t cdi_size = get_dice_attestation_cdi(cdi, sizeof(cdi));
+ if (cdi_size == 0) {
return ndk::ScopedAStatus::
- fromServiceSpecificErrorWithMessage(0, "Failed to find diced");
+ fromServiceSpecificErrorWithMessage(0, "Failed to get attestation cdi");
}
- BccHandover handover;
- auto deriveStatus = service->derive({}, &handover);
- if (!deriveStatus.isOk()) {
- return ndk::ScopedAStatus::fromServiceSpecificErrorWithMessage(0,
- "Failed call diced");
- }
- *out = {handover.cdiAttest.begin(), handover.cdiAttest.end()};
+ *out = {cdi, cdi + cdi_size};
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus getBcc(std::vector<uint8_t>* out) override {
- ndk::SpAIBinder binder(AServiceManager_getService("android.security.dice.IDiceNode"));
- auto service = IDiceNode::fromBinder(binder);
- if (service == nullptr) {
+ uint8_t bcc[2048];
+ size_t bcc_size = get_dice_attestation_chain(bcc, sizeof(bcc));
+ if (bcc_size == 0) {
return ndk::ScopedAStatus::
- fromServiceSpecificErrorWithMessage(0, "Failed to find diced");
+ fromServiceSpecificErrorWithMessage(0, "Failed to get attestation chain");
}
- BccHandover handover;
- auto deriveStatus = service->derive({}, &handover);
- if (!deriveStatus.isOk()) {
- return ndk::ScopedAStatus::fromServiceSpecificErrorWithMessage(0,
- "Failed call diced");
- }
- *out = {handover.bcc.data.begin(), handover.bcc.data.end()};
+ *out = {bcc, bcc + bcc_size};
return ndk::ScopedAStatus::ok();
}
};