Add DiceDrive::from_file factory method

This new function will be used in microdroid_manager to read the dice
chain written during first_stage_init for Microdroid VMs with microdroid
vendor partition.

This patch also adds a simple unit test to ensure that a dice chain read
from the file is equal to the one written to it.

Bug: 287593065
Test: atest libdice_driver_test
Change-Id: I5fa10a4b405b23f2c1980a920f0e72077623c01c
diff --git a/libs/dice/driver/src/lib.rs b/libs/dice/driver/src/lib.rs
index ec87ae2..79edb51 100644
--- a/libs/dice/driver/src/lib.rs
+++ b/libs/dice/driver/src/lib.rs
@@ -32,7 +32,7 @@
 
 /// Artifacts that are mapped into the process address space from the driver.
 pub enum DiceDriver<'a> {
-    /// Real implementation
+    /// Implementation that reads bcc handover from the dice driver.
     Real {
         /// Path to the driver character device (e.g. /dev/open-dice0).
         driver_path: PathBuf,
@@ -45,6 +45,13 @@
     },
     /// Fake implementation used in tests and non-protected VMs.
     Fake(OwnedDiceArtifacts),
+    /// Implementation that reads bcc handover from the file.
+    FromFile {
+        /// Path to the file to read dice chain from,
+        file_path: PathBuf,
+        /// Dice artifacts read from file_path,
+        dice_artifacts: OwnedDiceArtifacts,
+    },
 }
 
 impl DiceDriver<'_> {
@@ -52,6 +59,7 @@
         match self {
             Self::Real { bcc_handover, .. } => bcc_handover,
             Self::Fake(owned_dice_artifacts) => owned_dice_artifacts,
+            Self::FromFile { dice_artifacts, .. } => dice_artifacts,
         }
     }
 
@@ -97,6 +105,15 @@
         })
     }
 
+    /// Create a new dice driver that reads dice_artifacts from the given file.
+    pub fn from_file(file_path: &Path) -> Result<Self> {
+        let file =
+            fs::File::open(file_path).map_err(|error| Error::new(error).context("open file"))?;
+        let dice_artifacts = serde_cbor::from_reader(file)
+            .map_err(|error| Error::new(error).context("read file"))?;
+        Ok(Self::FromFile { file_path: file_path.to_path_buf(), dice_artifacts })
+    }
+
     /// 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
@@ -155,3 +172,36 @@
         }
     }
 }
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    fn assert_eq_bytes(expected: &[u8], actual: &[u8]) {
+        assert_eq!(
+            expected,
+            actual,
+            "Expected {}, got {}",
+            hex::encode(expected),
+            hex::encode(actual)
+        )
+    }
+
+    #[test]
+    fn test_write_bcc_to_file_read_from_file() -> Result<()> {
+        let dice_artifacts = diced_sample_inputs::make_sample_bcc_and_cdis()?;
+
+        let test_file = tempfile::NamedTempFile::new()?;
+        serde_cbor::to_writer(test_file.as_file(), &dice_artifacts)?;
+        test_file.as_file().sync_all()?;
+
+        let dice = DiceDriver::from_file(test_file.as_ref())?;
+
+        let dice_artifacts2 = dice.dice_artifacts();
+        assert_eq_bytes(dice_artifacts.cdi_attest(), dice_artifacts2.cdi_attest());
+        assert_eq_bytes(dice_artifacts.cdi_seal(), dice_artifacts2.cdi_seal());
+        assert_eq_bytes(dice_artifacts.bcc().expect("bcc"), dice_artifacts2.bcc().expect("bcc"));
+
+        Ok(())
+    }
+}