diff --git a/tss-esapi/src/structures/lists/pcr_selection.rs b/tss-esapi/src/structures/lists/pcr_selection.rs index 072fcbcb..d2fbdd20 100644 --- a/tss-esapi/src/structures/lists/pcr_selection.rs +++ b/tss-esapi/src/structures/lists/pcr_selection.rs @@ -11,7 +11,7 @@ use std::convert::TryFrom; /// corresponds to the TSS TPML_PCR_SELECTION. #[derive(Debug, Clone, PartialEq, Eq)] pub struct PcrSelectionList { - items: HashMap, + items: Vec, } impl PcrSelectionList { @@ -26,94 +26,23 @@ impl PcrSelectionList { self.items.is_empty() } + /// Gets the selections + pub fn get_selections(&self) -> &[PcrSelection] { + &self.items + } + /// Function for retrieving the PcrSelectionList from Option /// /// This returns an empty list if None is passed pub fn list_from_option(pcr_list: Option) -> PcrSelectionList { pcr_list.unwrap_or_else(|| PcrSelectionListBuilder::new().build()) } - - /// Removes items in `other` from `self. - /// - /// # Arguments - /// - /// * `other` - A PcrSelectionList containing items - /// that will be removed from `self`. - /// - /// - /// # Constraints - /// - /// * Cannot be called with `other` that contains items that - /// are not present in `self`. - /// - /// * Cannot be called with `other` that contains pcr selection - /// associated with a hashing algorithm that cannot be subtracted - /// from the pcr selection associated with the same hashing algorithm - /// in `self`. - /// - /// # Errors - /// - /// * Calling the method with `other` that contains items - /// not present in `self` will result in an InvalidParam error. - /// - /// - /// # Examples - /// ``` - /// use tss_esapi::structures::{PcrSelectionListBuilder, PcrSlot}; - /// use tss_esapi::interface_types::algorithm::HashingAlgorithm; - /// // pcr selections - /// let mut pcr_selection_list = PcrSelectionListBuilder::new() - /// .with_size_of_select(Default::default()) - /// .with_selection(HashingAlgorithm::Sha256, &[PcrSlot::Slot0, PcrSlot::Slot8]) - /// .build(); - /// - /// // Another pcr selections - /// let other = PcrSelectionListBuilder::new() - /// .with_size_of_select(Default::default()) - /// .with_selection( - /// HashingAlgorithm::Sha256, &[PcrSlot::Slot0], - /// ) - /// .build(); - /// pcr_selection_list.subtract(&other).unwrap(); - /// assert_eq!(pcr_selection_list.len(), 1); - /// ``` - pub fn subtract(&mut self, other: &Self) -> Result<()> { - if self == other { - self.items.clear(); - return Ok(()); - } - - if self.is_empty() { - error!("Error: Trying to remove item that did not exist"); - return Err(Error::local_error(WrapperErrorKind::InvalidParam)); - } - - for hashing_algorithm in other.items.keys() { - // Lookup selection in self. - let pcr_selection = match self.items.get_mut(hashing_algorithm) { - Some(val) => val, - None => { - error!("Error: Trying to remove item that did not exist"); - return Err(Error::local_error(WrapperErrorKind::InvalidParam)); - } - }; - // Check if value exists in other and if not then nothing needs to be done - if let Some(val) = other.items.get(hashing_algorithm) { - pcr_selection.subtract(val)?; - - if pcr_selection.is_empty() { - let _ = self.items.remove(hashing_algorithm); - } - } - } - Ok(()) - } } impl From for TPML_PCR_SELECTION { fn from(pcr_selections: PcrSelectionList) -> TPML_PCR_SELECTION { let mut tss_pcr_selection_list: TPML_PCR_SELECTION = Default::default(); - for (_, pcr_selection) in pcr_selections.items { + for pcr_selection in pcr_selections.items { tss_pcr_selection_list.pcrSelections[tss_pcr_selection_list.count as usize] = pcr_selection.into(); tss_pcr_selection_list.count += 1; @@ -137,23 +66,12 @@ impl TryFrom for PcrSelectionList { return Err(Error::local_error(WrapperErrorKind::InvalidParam)); } - let mut items = HashMap::::new(); + let mut items = Vec::::with_capacity(size); // Loop over available selections for tpms_pcr_selection in tpml_pcr_selection.pcrSelections[..size].iter() { // Parse pcr selection. let parsed_pcr_selection = PcrSelection::try_from(*tpms_pcr_selection)?; - // Insert the selection into the storage. Or merge with an existing. - match items.get_mut(&parsed_pcr_selection.hashing_algorithm()) { - Some(previously_parsed_pcr_selection) => { - previously_parsed_pcr_selection.merge(&parsed_pcr_selection)?; - } - None => { - let _ = items.insert( - parsed_pcr_selection.hashing_algorithm(), - parsed_pcr_selection, - ); - } - } + items.push(parsed_pcr_selection); } Ok(PcrSelectionList { items }) } @@ -222,7 +140,7 @@ impl PcrSelectionListBuilder { items: self .items .iter() - .map(|(k, v)| (*k, PcrSelection::new(*k, size_of_select, v.as_slice()))) + .map(|(k, v)| PcrSelection::new(*k, size_of_select, v.as_slice())) .collect(), } } diff --git a/tss-esapi/src/structures/pcr/selection.rs b/tss-esapi/src/structures/pcr/selection.rs index c8dc7741..599fc7db 100644 --- a/tss-esapi/src/structures/pcr/selection.rs +++ b/tss-esapi/src/structures/pcr/selection.rs @@ -35,6 +35,10 @@ impl PcrSelection { self.hashing_algorithm } + pub fn selected_pcrs(&self) -> &BitFlags { + &self.selected_pcrs + } + pub fn merge(&mut self, other: &Self) -> Result<()> { // Check that the hashing algorithm match if self.hashing_algorithm != other.hashing_algorithm { diff --git a/tss-esapi/src/utils/mod.rs b/tss-esapi/src/utils/mod.rs index 9cec7cc7..e055dd2d 100644 --- a/tss-esapi/src/utils/mod.rs +++ b/tss-esapi/src/utils/mod.rs @@ -524,7 +524,6 @@ impl PublicIdUnion { /// Rust enum representation of `TPMU_PUBLIC_PARMS`. // Most of the field types are from bindgen which does not implement Debug on them. #[allow(missing_debug_implementations)] -#[allow(clippy::pub_enum_variant_names)] #[derive(Copy, Clone)] pub enum PublicParmsUnion { KeyedHashDetail(KeyedHashParameters), diff --git a/tss-esapi/tests/pcr_selection_list_tests.rs b/tss-esapi/tests/pcr_selection_list_tests.rs index 80788d9f..58e98f0e 100644 --- a/tss-esapi/tests/pcr_selection_list_tests.rs +++ b/tss-esapi/tests/pcr_selection_list_tests.rs @@ -1,166 +1,97 @@ // Copyright 2020 Contributors to the Parsec project. // SPDX-License-Identifier: Apache-2.0 +use std::convert::TryFrom; use tss_esapi::{ interface_types::algorithm::HashingAlgorithm, - structures::{PcrSelectSize, PcrSelectionListBuilder, PcrSlot}, + structures::{PcrSelectSize, PcrSelection, PcrSelectionList, PcrSlot}, + tss2_esys::{TPML_PCR_SELECTION, TPMS_PCR_SELECTION}, }; mod test_pcr_selection_list { use super::*; - #[test] - fn test_subtract_remaining_values() { - let mut pcr_selection_list = PcrSelectionListBuilder::new() - .with_size_of_select(Default::default()) - .with_selection( - HashingAlgorithm::Sha256, - &[PcrSlot::Slot0, PcrSlot::Slot8, PcrSlot::Slot16], - ) - .build(); - - let pcr_selection_list_1 = PcrSelectionListBuilder::new() - .with_size_of_select(Default::default()) - .with_selection(HashingAlgorithm::Sha256, &[PcrSlot::Slot0, PcrSlot::Slot8]) - .build(); - - let expected = PcrSelectionListBuilder::new() - .with_size_of_select(Default::default()) - .with_selection(HashingAlgorithm::Sha256, &[PcrSlot::Slot16]) - .build(); - - pcr_selection_list.subtract(&pcr_selection_list_1).unwrap(); - - assert_eq!(expected, pcr_selection_list); - } #[test] - fn test_subtract_nothing_remaining() { - let mut pcr_selection_list = PcrSelectionListBuilder::new() - .with_size_of_select(Default::default()) - .with_selection( - HashingAlgorithm::Sha256, - &[PcrSlot::Slot0, PcrSlot::Slot8, PcrSlot::Slot16], - ) - .build(); - - let pcr_selection_list_1 = PcrSelectionListBuilder::new() - .with_size_of_select(Default::default()) - .with_selection( - HashingAlgorithm::Sha256, - &[PcrSlot::Slot0, PcrSlot::Slot8, PcrSlot::Slot16], - ) - .build(); - - pcr_selection_list.subtract(&pcr_selection_list_1).unwrap(); - - assert!(pcr_selection_list.is_empty()); - } - - #[test] - fn test_subtract_with_non_equal_size_of_select_failure() { - // pcr selections with 3 bytes size of select. - let mut pcr_selection_list = PcrSelectionListBuilder::new() - .with_size_of_select(PcrSelectSize::ThreeBytes) - .with_selection( - HashingAlgorithm::Sha256, - &[PcrSlot::Slot0, PcrSlot::Slot8, PcrSlot::Slot16], - ) - .build(); - - // Pcr selections with 2 bytes size of select. - let pcr_selection_list_1 = PcrSelectionListBuilder::new() - .with_size_of_select(PcrSelectSize::TwoBytes) - .with_selection( - HashingAlgorithm::Sha256, - &[PcrSlot::Slot0, PcrSlot::Slot8, PcrSlot::Slot16], - ) - .build(); - - pcr_selection_list - .subtract(&pcr_selection_list_1) - .unwrap_err(); - } - - #[test] - fn test_subtract_attempting_to_subtract_a_non_existant_value_failure() { - // pcr selections - let mut pcr_selection_list = PcrSelectionListBuilder::new() - .with_size_of_select(Default::default()) - .with_selection(HashingAlgorithm::Sha256, &[PcrSlot::Slot0, PcrSlot::Slot8]) - .build(); - - // Pcr selections with 1 more pcr slot then the previous. - let pcr_selection_list_1 = PcrSelectionListBuilder::new() - .with_size_of_select(Default::default()) - .with_selection( - HashingAlgorithm::Sha256, - &[PcrSlot::Slot0, PcrSlot::Slot8, PcrSlot::Slot16], - ) - .build(); - - pcr_selection_list - .subtract(&pcr_selection_list_1) - .unwrap_err(); - } - - #[test] - fn test_subtract_with_larg_selection_ramining_value() { - // pcr selections - let mut pcr_selection_list = PcrSelectionListBuilder::new() - .with_size_of_select(Default::default()) - .with_selection( - HashingAlgorithm::Sha1, - &[ - PcrSlot::Slot1, - PcrSlot::Slot3, - PcrSlot::Slot5, - PcrSlot::Slot7, - ], - ) - .with_selection( - HashingAlgorithm::Sha256, - &[PcrSlot::Slot0, PcrSlot::Slot7, PcrSlot::Slot8], - ) - .with_selection( - HashingAlgorithm::Sha512, - &[ - PcrSlot::Slot4, - PcrSlot::Slot8, - PcrSlot::Slot12, - PcrSlot::Slot16, - ], - ) - .build(); - - let pcr_selection_list_1 = PcrSelectionListBuilder::new() - .with_size_of_select(Default::default()) - .with_selection( - HashingAlgorithm::Sha1, - &[ - PcrSlot::Slot1, - /*PcrSlot::Slot3, PcrSlot::Slot5,*/ PcrSlot::Slot7, - ], - ) - .with_selection( - HashingAlgorithm::Sha256, - &[PcrSlot::Slot0, PcrSlot::Slot7, PcrSlot::Slot8], - ) - .with_selection( - HashingAlgorithm::Sha512, - &[ - PcrSlot::Slot4, - PcrSlot::Slot8, - /*PcrSlot::Slot12,*/ PcrSlot::Slot16, - ], - ) - .build(); - - let expected = PcrSelectionListBuilder::new() - .with_size_of_select(Default::default()) - .with_selection(HashingAlgorithm::Sha1, &[PcrSlot::Slot3, PcrSlot::Slot5]) - .with_selection(HashingAlgorithm::Sha512, &[PcrSlot::Slot12]) - .build(); - - pcr_selection_list.subtract(&pcr_selection_list_1).unwrap(); - assert_eq!(expected, pcr_selection_list); + fn from_tpml_retains_order() { + let selection_1 = PcrSelection::new( + HashingAlgorithm::Sha256, + PcrSelectSize::ThreeBytes, + &[PcrSlot::Slot10], + ); + let selection_1 = TPMS_PCR_SELECTION::try_from(selection_1).unwrap(); + + let selection_2 = PcrSelection::new( + HashingAlgorithm::Sha256, + PcrSelectSize::ThreeBytes, + &[PcrSlot::Slot11], + ); + let selection_2 = TPMS_PCR_SELECTION::try_from(selection_2).unwrap(); + + let selection_3 = PcrSelection::new( + HashingAlgorithm::Sha1, + PcrSelectSize::ThreeBytes, + &[PcrSlot::Slot16], + ); + let selection_3 = TPMS_PCR_SELECTION::try_from(selection_3).unwrap(); + + let selection_4 = PcrSelection::new( + HashingAlgorithm::Sha1, + PcrSelectSize::ThreeBytes, + &[PcrSlot::Slot2], + ); + let selection_4 = TPMS_PCR_SELECTION::try_from(selection_4).unwrap(); + + let empty_selection = + PcrSelection::new(HashingAlgorithm::Sha1, PcrSelectSize::ThreeBytes, &[]); + let empty_selection = TPMS_PCR_SELECTION::try_from(empty_selection).unwrap(); + + let tpml_selections = TPML_PCR_SELECTION { + count: 4, + pcrSelections: [ + selection_1, + selection_2, + selection_3, + selection_4, + empty_selection, + empty_selection, + empty_selection, + empty_selection, + empty_selection, + empty_selection, + empty_selection, + empty_selection, + empty_selection, + empty_selection, + empty_selection, + empty_selection, + ], + }; + + let selections = PcrSelectionList::try_from(tpml_selections).unwrap(); + let tpml_selections = TPML_PCR_SELECTION::try_from(selections).unwrap(); + let selections = PcrSelectionList::try_from(tpml_selections).unwrap(); + + assert_eq!(selections.len(), 4); + + let sel_1 = selections.get_selections()[0]; + let sel_2 = selections.get_selections()[1]; + let sel_3 = selections.get_selections()[2]; + let sel_4 = selections.get_selections()[3]; + + assert_eq!(sel_1.hashing_algorithm(), HashingAlgorithm::Sha256); + assert!(!sel_1.is_empty()); + assert!(sel_1.selected_pcrs().contains(PcrSlot::Slot10)); + assert!(!sel_1.selected_pcrs().contains(PcrSlot::Slot11)); + + assert_eq!(sel_2.hashing_algorithm(), HashingAlgorithm::Sha256); + assert!(!sel_2.is_empty()); + assert!(sel_2.selected_pcrs().contains(PcrSlot::Slot11)); + + assert_eq!(sel_3.hashing_algorithm(), HashingAlgorithm::Sha1); + assert!(!sel_3.is_empty()); + assert!(sel_3.selected_pcrs().contains(PcrSlot::Slot16)); + + assert_eq!(sel_4.hashing_algorithm(), HashingAlgorithm::Sha1); + assert!(!sel_4.is_empty()); + assert!(sel_4.selected_pcrs().contains(PcrSlot::Slot2)); } }