Move dice_driver to libs/dice/driver
The dice_driver will be used by the derive_microdroid_vendor_dice_node
binary, hence moving the implementation to libs.
Bug: 287593065
Test: builds
Test: presubmit
Change-Id: If28834f84b24c75738ec6501d25745e20e674547
diff --git a/libs/dice/driver/src/lib.rs b/libs/dice/driver/src/lib.rs
new file mode 100644
index 0000000..ec87ae2
--- /dev/null
+++ b/libs/dice/driver/src/lib.rs
@@ -0,0 +1,157 @@
+// 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::{anyhow, bail, Context, Error, Result};
+use byteorder::{NativeEndian, ReadBytesExt};
+use diced_open_dice::{
+ bcc_handover_parse, retry_bcc_main_flow, BccHandover, Config, DiceArtifacts, DiceMode, Hash,
+ Hidden, InputValues, OwnedDiceArtifacts,
+};
+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 mapped into the process address space from the driver.
+pub enum DiceDriver<'a> {
+ /// Real implementation
+ Real {
+ /// Path to the driver character device (e.g. /dev/open-dice0).
+ driver_path: PathBuf,
+ /// Address of the memory to mmap driver to.
+ mmap_addr: *mut c_void,
+ /// Size of the mmap.
+ mmap_size: usize,
+ /// BCC handover.
+ bcc_handover: BccHandover<'a>,
+ },
+ /// Fake implementation used in tests and non-protected VMs.
+ Fake(OwnedDiceArtifacts),
+}
+
+impl DiceDriver<'_> {
+ fn dice_artifacts(&self) -> &dyn DiceArtifacts {
+ match self {
+ Self::Real { bcc_handover, .. } => bcc_handover,
+ Self::Fake(owned_dice_artifacts) => owned_dice_artifacts,
+ }
+ }
+
+ /// Creates a new dice driver from the given driver_path.
+ pub fn new(driver_path: &Path, is_strict_boot: bool) -> Result<Self> {
+ if driver_path.exists() {
+ log::info!("Using DICE values from driver");
+ } else if is_strict_boot {
+ bail!("Strict boot requires DICE value from driver but none were found");
+ } else {
+ log::warn!("Using sample DICE values");
+ let dice_artifacts = diced_sample_inputs::make_sample_bcc_and_cdis()
+ .expect("Failed to create sample dice artifacts.");
+ return Ok(Self::Fake(dice_artifacts));
+ };
+
+ 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;
+ // SAFETY: 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);
+ }
+ let mmap_buf =
+ // SAFETY: 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.
+ unsafe { slice::from_raw_parts((mmap_addr as *const u8).as_ref().unwrap(), mmap_size) };
+ let bcc_handover =
+ bcc_handover_parse(mmap_buf).map_err(|_| anyhow!("Failed to parse Bcc Handover"))?;
+ Ok(Self::Real {
+ driver_path: driver_path.to_path_buf(),
+ mmap_addr,
+ mmap_size,
+ bcc_handover,
+ })
+ }
+
+ /// Derives a sealing key of `key_length` bytes from the DICE sealing CDI.
+ pub fn get_sealing_key(&self, identifier: &[u8], key_length: usize) -> 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 mut key = ZVec::new(key_length)?;
+ let salt = &[];
+ hkdf(&mut key, Md::sha256(), self.dice_artifacts().cdi_seal(), salt, identifier)?;
+ Ok(key)
+ }
+
+ /// Derives a new dice chain.
+ pub fn derive(
+ self,
+ code_hash: Hash,
+ config_desc: &[u8],
+ authority_hash: Hash,
+ debug: bool,
+ hidden: Hidden,
+ ) -> Result<OwnedDiceArtifacts> {
+ let input_values = InputValues::new(
+ code_hash,
+ Config::Descriptor(config_desc),
+ authority_hash,
+ if debug { DiceMode::kDiceModeDebug } else { DiceMode::kDiceModeNormal },
+ hidden,
+ );
+ let current_dice_artifacts = self.dice_artifacts();
+ let next_dice_artifacts = retry_bcc_main_flow(
+ current_dice_artifacts.cdi_attest(),
+ current_dice_artifacts.cdi_seal(),
+ current_dice_artifacts.bcc().ok_or_else(|| anyhow!("bcc is none"))?,
+ &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(next_dice_artifacts)
+ }
+}
+
+impl Drop for DiceDriver<'_> {
+ fn drop(&mut self) {
+ if let &mut Self::Real { mmap_addr, mmap_size, .. } = self {
+ // SAFETY: 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 it's
+ // safe to unmap.
+ let ret = unsafe { munmap(mmap_addr, mmap_size) };
+ if ret != 0 {
+ log::warn!("Failed to munmap ({})", ret);
+ }
+ }
+ }
+}