use crate::{
structures::{Digest, PcrSlot},
Error, Result, WrapperErrorKind,
};
use log::error;
use std::collections::BTreeMap;
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct PcrBank {
bank: BTreeMap<PcrSlot, Digest>,
}
impl PcrBank {
pub fn create(mut pcr_slots: Vec<PcrSlot>, mut digests: Vec<Digest>) -> Result<PcrBank> {
if pcr_slots.len() != digests.len() {
error!(
"Number of PcrSlots does not match the number of PCR digests. ({} != {})",
pcr_slots.len(),
digests.len()
);
return Err(Error::local_error(WrapperErrorKind::InconsistentParams));
}
pcr_slots
.drain(..)
.zip(digests.drain(..))
.try_fold(BTreeMap::<PcrSlot, Digest>::new(), |mut data, (pcr_slot, digest)| {
if data.insert(pcr_slot, digest).is_none() {
Ok(data)
} else {
error!("Error trying to insert data into PcrSlot {:?} where data have already been inserted", pcr_slot);
Err(Error::local_error(WrapperErrorKind::InconsistentParams))
}
})
.map(|bank| PcrBank { bank })
}
pub fn get_digest(&self, pcr_slot: PcrSlot) -> Option<&Digest> {
self.bank.get(&pcr_slot)
}
pub fn has_digest(&self, pcr_slot: PcrSlot) -> bool {
self.bank.contains_key(&pcr_slot)
}
pub fn len(&self) -> usize {
self.bank.len()
}
pub fn is_empty(&self) -> bool {
self.bank.is_empty()
}
pub fn remove_digest(&mut self, pcr_slot: PcrSlot) -> Option<Digest> {
self.bank.remove(&pcr_slot)
}
pub fn insert_digest(&mut self, pcr_slot: PcrSlot, digest: Digest) -> Result<()> {
self.ensure_non_existing(pcr_slot, "Failed to insert")?;
let _ = self.bank.insert(pcr_slot, digest);
Ok(())
}
pub fn try_extend(&mut self, other: PcrBank) -> Result<()> {
other
.bank
.keys()
.try_for_each(|&pcr_slot| self.ensure_non_existing(pcr_slot, "Failed to extend"))?;
self.bank.extend(other.bank);
Ok(())
}
fn ensure_non_existing(&self, pcr_slot: PcrSlot, error_msg: &str) -> Result<()> {
if self.has_digest(pcr_slot) {
error!(
"{}, a digest already for PcrSlot {:?} exists in the bank",
error_msg, pcr_slot
);
return Err(Error::local_error(WrapperErrorKind::InvalidParam));
}
Ok(())
}
}
impl<'a> IntoIterator for &'a PcrBank {
type Item = (&'a PcrSlot, &'a Digest);
type IntoIter = ::std::collections::btree_map::Iter<'a, PcrSlot, Digest>;
fn into_iter(self) -> Self::IntoIter {
self.bank.iter()
}
}