tss_esapi/structures/lists/
pcr_selection.rs1use crate::interface_types::algorithm::HashingAlgorithm;
4use crate::structures::{PcrSelectSize, PcrSelection, PcrSlot};
5use crate::tss2_esys::TPML_PCR_SELECTION;
6use crate::{Error, Result, WrapperErrorKind};
7use log::error;
8use std::collections::HashMap;
9use std::convert::TryFrom;
10
11#[derive(Debug, Clone, PartialEq, Eq, Default)]
14pub struct PcrSelectionList {
15 items: Vec<PcrSelection>,
16}
17
18impl PcrSelectionList {
19 pub const MAX_SIZE: usize = 16;
20 pub fn len(&self) -> usize {
22 self.items.len()
23 }
24
25 pub fn is_empty(&self) -> bool {
27 self.items.is_empty()
28 }
29
30 pub fn get_selections(&self) -> &[PcrSelection] {
32 &self.items
33 }
34
35 pub fn subtract(&mut self, other: &Self) -> Result<()> {
37 if self == other {
38 self.items.clear();
39 return Ok(());
40 }
41
42 if self.is_empty() {
43 error!("Cannot remove items that does not exist");
44 return Err(Error::local_error(WrapperErrorKind::InvalidParam));
45 }
46
47 for other_pcr_selection in other.get_selections() {
48 self.remove_selection(other_pcr_selection)?;
49 }
50
51 self.remove_empty_selections();
52 Ok(())
53 }
54
55 pub fn list_from_option(pcr_list: Option<PcrSelectionList>) -> PcrSelectionList {
59 pcr_list.unwrap_or_default()
60 }
61
62 fn remove_empty_selections(&mut self) {
64 self.items.retain(|v| !v.is_empty());
65 }
66
67 fn remove_selection(&mut self, pcr_selection: &PcrSelection) -> Result<()> {
70 pcr_selection.selected().iter().try_for_each(|&pcr_slot| {
71 self.items
72 .iter_mut()
73 .find(|existing_pcr_selection| {
74 existing_pcr_selection.hashing_algorithm() == pcr_selection.hashing_algorithm()
75 && existing_pcr_selection.is_selected(pcr_slot)
76 })
77 .ok_or_else(|| {
78 error!("Cannot remove items from a selection that does not exists");
79 Error::local_error(WrapperErrorKind::InvalidParam)
80 })
81 .and_then(|existing_pcr_selection| existing_pcr_selection.deselect_exact(pcr_slot))
82 })
83 }
84
85 pub fn builder() -> PcrSelectionListBuilder {
87 PcrSelectionListBuilder::new()
88 }
89}
90
91impl From<PcrSelectionList> for TPML_PCR_SELECTION {
92 fn from(pcr_selections: PcrSelectionList) -> Self {
93 let mut tss_pcr_selection_list: TPML_PCR_SELECTION = Default::default();
94 for pcr_selection in pcr_selections.items {
95 tss_pcr_selection_list.pcrSelections[tss_pcr_selection_list.count as usize] =
96 pcr_selection.into();
97 tss_pcr_selection_list.count += 1;
98 }
99 tss_pcr_selection_list
100 }
101}
102
103impl TryFrom<TPML_PCR_SELECTION> for PcrSelectionList {
104 type Error = Error;
105 fn try_from(tpml_pcr_selection: TPML_PCR_SELECTION) -> Result<PcrSelectionList> {
106 let size = tpml_pcr_selection.count as usize;
107
108 if size > PcrSelectionList::MAX_SIZE {
109 error!(
110 "Invalid size value in TPML_PCR_SELECTION (> {})",
111 PcrSelectionList::MAX_SIZE
112 );
113 return Err(Error::local_error(WrapperErrorKind::InvalidParam));
114 }
115
116 let mut items = Vec::<PcrSelection>::with_capacity(size);
117 for tpms_pcr_selection in tpml_pcr_selection.pcrSelections[..size].iter() {
119 let parsed_pcr_selection = PcrSelection::try_from(*tpms_pcr_selection)?;
121 items.push(parsed_pcr_selection);
122 }
123 Ok(PcrSelectionList { items })
124 }
125}
126
127#[derive(Debug, Default)]
129pub struct PcrSelectionListBuilder {
130 size_of_select: Option<PcrSelectSize>,
131 items: HashMap<HashingAlgorithm, Vec<PcrSlot>>,
132}
133
134impl PcrSelectionListBuilder {
135 pub fn new() -> Self {
136 PcrSelectionListBuilder {
137 size_of_select: None,
138 items: Default::default(),
139 }
140 }
141
142 pub fn with_size_of_select(mut self, size_of_select: PcrSelectSize) -> Self {
147 self.size_of_select = Some(size_of_select);
148 self
149 }
150
151 pub fn with_selection(
160 mut self,
161 hash_algorithm: HashingAlgorithm,
162 pcr_slots: &[PcrSlot],
163 ) -> Self {
164 match self.items.get_mut(&hash_algorithm) {
166 Some(previously_selected_pcr_slots) => {
167 previously_selected_pcr_slots.extend_from_slice(pcr_slots);
169 }
170 None => {
171 let _ = self.items.insert(hash_algorithm, pcr_slots.to_vec());
172 }
173 }
174 self
175 }
176
177 pub fn build(self) -> Result<PcrSelectionList> {
186 let size_of_select = self.size_of_select.unwrap_or_default();
187 self.items
188 .iter()
189 .try_fold(Vec::<PcrSelection>::new(), |mut acc, (&k, v)| {
190 PcrSelection::create(k, size_of_select, v.as_slice()).map(|pcr_select| {
191 acc.push(pcr_select);
192 acc
193 })
194 })
195 .map(|items| PcrSelectionList { items })
196 }
197}