diff --git a/libs/dice/src/bcc.rs b/libs/dice/src/bcc.rs new file mode 100644 index 00000000..849dfa0f --- /dev/null +++ b/libs/dice/src/bcc.rs @@ -0,0 +1,88 @@ +/* + * 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. + */ + +//! Wrapper around dice/android/bcc.h. + +use core::mem; +use core::ptr; + +use open_dice_bcc_bindgen::BccHandoverParse; + +use crate::check_call; +use crate::Cdi; +use crate::Error; +use crate::Result; + +/// Boot Chain Certificate handover format combining the BCC and CDIs in a single CBOR object. +#[derive(Clone, Debug)] +pub struct Handover<'a> { + /// Attestation CDI. + pub cdi_attest: &'a Cdi, + /// Sealing CDI. + pub cdi_seal: &'a Cdi, + /// Boot Chain Certificate (optional). + pub bcc: Option<&'a [u8]>, +} + +impl<'a> Handover<'a> { + /// Validates and extracts the fields of a BCC handover buffer. + pub fn new(buffer: &'a [u8]) -> Result { + let mut cdi_attest: *const u8 = ptr::null(); + let mut cdi_seal: *const u8 = ptr::null(); + let mut bcc: *const u8 = ptr::null(); + let mut bcc_size: usize = 0; + + // SAFETY - The buffer is only read and never stored and the returned pointers should all + // point within the address range of the buffer or be NULL. + check_call(unsafe { + BccHandoverParse( + buffer.as_ptr(), + buffer.len(), + &mut cdi_attest as *mut *const u8, + &mut cdi_seal as *mut *const u8, + &mut bcc as *mut *const u8, + &mut bcc_size as *mut usize, + ) + })?; + + let cdi_attest = { + let i = index_from_ptr(buffer, cdi_attest).ok_or(Error::PlatformError)?; + let s = buffer.get(i..(i + mem::size_of::())).ok_or(Error::PlatformError)?; + s.try_into().map_err(|_| Error::PlatformError)? + }; + let cdi_seal = { + let i = index_from_ptr(buffer, cdi_seal).ok_or(Error::PlatformError)?; + let s = buffer.get(i..(i + mem::size_of::())).ok_or(Error::PlatformError)?; + s.try_into().map_err(|_| Error::PlatformError)? + }; + let bcc = if bcc.is_null() { + None + } else { + let i = index_from_ptr(buffer, bcc).ok_or(Error::PlatformError)?; + Some(buffer.get(i..(i + bcc_size)).ok_or(Error::PlatformError)?) + }; + + Ok(Self { cdi_attest, cdi_seal, bcc }) + } +} + +fn index_from_ptr(slice: &[u8], pointer: *const u8) -> Option { + if slice.as_ptr_range().contains(&pointer) { + (pointer as usize).checked_sub(slice.as_ptr() as usize) + } else { + None + } +} diff --git a/libs/dice/src/lib.rs b/libs/dice/src/lib.rs index 862f3e9b..43d167f0 100644 --- a/libs/dice/src/lib.rs +++ b/libs/dice/src/lib.rs @@ -28,8 +28,13 @@ use open_dice_cbor_bindgen::DiceResult_kDiceResultInvalidInput as DICE_RESULT_IN use open_dice_cbor_bindgen::DiceResult_kDiceResultOk as DICE_RESULT_OK; use open_dice_cbor_bindgen::DiceResult_kDiceResultPlatformError as DICE_RESULT_PLATFORM_ERROR; +pub mod bcc; + +const CDI_SIZE: usize = open_dice_cbor_bindgen::DICE_CDI_SIZE as usize; const HASH_SIZE: usize = open_dice_cbor_bindgen::DICE_HASH_SIZE as usize; +/// Array type of CDIs. +pub type Cdi = [u8; CDI_SIZE]; /// Array type of hashes used by DICE. pub type Hash = [u8; HASH_SIZE]; diff --git a/pvmfw/Android.bp b/pvmfw/Android.bp index 0da24c7b..6a017137 100644 --- a/pvmfw/Android.bp +++ b/pvmfw/Android.bp @@ -15,6 +15,7 @@ rust_ffi_static { "libaarch64_paging", "libavb_nostd", "libbuddy_system_allocator", + "libdice_nostd", "liblibfdt", "liblog_rust_nostd", "libpvmfw_embedded_key", diff --git a/pvmfw/src/entry.rs b/pvmfw/src/entry.rs index e8f9bb2a..bffc1403 100644 --- a/pvmfw/src/entry.rs +++ b/pvmfw/src/entry.rs @@ -24,6 +24,7 @@ use crate::mmu; use core::arch::asm; use core::num::NonZeroUsize; use core::slice; +use dice::bcc::Handover; use log::debug; use log::error; use log::info; @@ -228,8 +229,9 @@ fn main_wrapper(fdt: usize, payload: usize, payload_size: usize) -> Result<(), R RebootReason::InvalidConfig })?; - let bcc = appended.get_bcc_mut().ok_or_else(|| { - error!("Invalid BCC"); + let bcc_slice = appended.get_bcc_mut(); + let bcc = Handover::new(bcc_slice).map_err(|e| { + error!("Invalid BCC Handover: {e:?}"); RebootReason::InvalidBcc })?; @@ -243,7 +245,7 @@ fn main_wrapper(fdt: usize, payload: usize, payload_size: usize) -> Result<(), R let slices = MemorySlices::new(fdt, payload, payload_size, &mut memory)?; // This wrapper allows main() to be blissfully ignorant of platform details. - crate::main(slices.fdt, slices.kernel, slices.ramdisk, bcc, &mut memory)?; + crate::main(slices.fdt, slices.kernel, slices.ramdisk, &bcc, &mut memory)?; // TODO: Overwrite BCC before jumping to payload to avoid leaking our sealing key. @@ -366,12 +368,10 @@ impl<'a> AppendedPayload<'a> { } } - fn get_bcc_mut(&mut self) -> Option<&mut [u8]> { - let bcc = match self { + fn get_bcc_mut(&mut self) -> &mut [u8] { + match self { Self::LegacyBcc(ref mut bcc) => bcc, Self::Config(ref mut cfg) => cfg.get_bcc_mut(), - }; - // TODO(b/256148034): return None if BccHandoverParse(bcc) != kDiceResultOk. - Some(bcc) + } } } diff --git a/pvmfw/src/main.rs b/pvmfw/src/main.rs index e6a158d3..07cbd0c0 100644 --- a/pvmfw/src/main.rs +++ b/pvmfw/src/main.rs @@ -39,14 +39,15 @@ use crate::{ }; use avb::PUBLIC_KEY; use avb_nostd::verify_image; +use dice::bcc; use libfdt::Fdt; -use log::{debug, error, info}; +use log::{debug, error, info, trace}; fn main( fdt: &Fdt, signed_kernel: &[u8], ramdisk: Option<&[u8]>, - bcc: &[u8], + bcc: &bcc::Handover, memory: &mut MemoryTracker, ) -> Result<(), RebootReason> { info!("pVM firmware"); @@ -57,7 +58,7 @@ fn main( } else { debug!("Ramdisk: None"); } - debug!("BCC: {:?} ({:#x} bytes)", bcc.as_ptr(), bcc.len()); + trace!("BCC: {bcc:x?}"); // Set up PCI bus for VirtIO devices. let pci_node = pci_node(fdt)?;