Merge changes from topic "BccHandoverParse-bindgen"

* changes:
  pvmfw: Validate input BCC handover
  libs/dice: Introduce dice::Result
  libs/dice: Refactor imports
diff --git a/libs/dice/src/bcc.rs b/libs/dice/src/bcc.rs
new file mode 100644
index 0000000..849dfa0
--- /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<Self> {
+        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::<Cdi>())).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::<Cdi>())).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<usize> {
+    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 9e39436..43d167f 100644
--- a/libs/dice/src/lib.rs
+++ b/libs/dice/src/lib.rs
@@ -18,16 +18,23 @@
 
 #![no_std]
 
-use core::fmt::{self, Debug};
-use open_dice_cbor_bindgen::{
-    DiceHash, DiceResult, DiceResult_kDiceResultBufferTooSmall as DICE_RESULT_BUFFER_TOO_SMALL,
-    DiceResult_kDiceResultInvalidInput as DICE_RESULT_INVALID_INPUT,
-    DiceResult_kDiceResultOk as DICE_RESULT_OK,
-    DiceResult_kDiceResultPlatformError as DICE_RESULT_PLATFORM_ERROR,
-};
+use core::fmt;
+use core::result;
 
+use open_dice_cbor_bindgen::DiceHash;
+use open_dice_cbor_bindgen::DiceResult;
+use open_dice_cbor_bindgen::DiceResult_kDiceResultBufferTooSmall as DICE_RESULT_BUFFER_TOO_SMALL;
+use open_dice_cbor_bindgen::DiceResult_kDiceResultInvalidInput as DICE_RESULT_INVALID_INPUT;
+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];
 
@@ -43,7 +50,7 @@
     Unknown(DiceResult),
 }
 
-impl Debug for Error {
+impl fmt::Debug for Error {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         match self {
             Error::InvalidInput => write!(f, "invalid input"),
@@ -54,7 +61,10 @@
     }
 }
 
-fn check_call(ret: DiceResult) -> Result<(), Error> {
+/// Result of DICE functions.
+pub type Result<T> = result::Result<T, Error>;
+
+fn check_call(ret: DiceResult) -> Result<()> {
     match ret {
         DICE_RESULT_OK => Ok(()),
         DICE_RESULT_INVALID_INPUT => Err(Error::InvalidInput),
@@ -69,7 +79,7 @@
 }
 
 /// Hash the provided input using DICE's default hash function.
-pub fn hash(bytes: &[u8]) -> Result<Hash, Error> {
+pub fn hash(bytes: &[u8]) -> Result<Hash> {
     let mut output: Hash = [0; HASH_SIZE];
     // SAFETY - DiceHash takes a sized input buffer and writes to a constant-sized output buffer.
     check_call(unsafe { DiceHash(ctx(), bytes.as_ptr(), bytes.len(), output.as_mut_ptr()) })?;
diff --git a/pvmfw/Android.bp b/pvmfw/Android.bp
index 0da24c7..6a01713 100644
--- a/pvmfw/Android.bp
+++ b/pvmfw/Android.bp
@@ -15,6 +15,7 @@
         "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 e8f9bb2..bffc140 100644
--- a/pvmfw/src/entry.rs
+++ b/pvmfw/src/entry.rs
@@ -24,6 +24,7 @@
 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 @@
         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 @@
     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 @@
         }
     }
 
-    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 e6a158d..07cbd0c 100644
--- a/pvmfw/src/main.rs
+++ b/pvmfw/src/main.rs
@@ -39,14 +39,15 @@
 };
 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 @@
     } 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)?;