tss_esapi/structures/pcr/selection.rs
1// Copyright 2020 Contributors to the Parsec project.
2// SPDX-License-Identifier: Apache-2.0
3use crate::{
4 interface_types::algorithm::HashingAlgorithm,
5 structures::{PcrSelectSize, PcrSlot, PcrSlotCollection},
6 tss2_esys::TPMS_PCR_SELECTION,
7 Error, Result, WrapperErrorKind,
8};
9use log::error;
10use std::convert::TryFrom;
11/// This module contains the PcrSelection struct.
12/// The TSS counterpart of this struct is the
13/// TPMS_PCR_SELECTION.
14#[derive(Debug, Copy, Clone, PartialEq, Eq)]
15pub struct PcrSelection {
16 hashing_algorithm: HashingAlgorithm,
17 pcr_slot_collection: PcrSlotCollection,
18}
19
20impl PcrSelection {
21 /// Creates new PcrSelection
22 ///
23 /// # Errors
24 /// Returns InconsistentParams error if a pcr slot
25 /// has been provided that ends up in an octet outside the
26 /// range specified by the `size_of_select` parameter.
27 pub fn create(
28 hashing_algorithm: HashingAlgorithm,
29 size_of_select: PcrSelectSize,
30 selected_pcr_slots: &[PcrSlot],
31 ) -> Result<Self> {
32 PcrSlotCollection::create(size_of_select, selected_pcr_slots).map(|pcr_slot_collection| {
33 PcrSelection {
34 hashing_algorithm,
35 pcr_slot_collection,
36 }
37 })
38 }
39
40 /// Returns the hashing algorithm for the selection
41 pub const fn hashing_algorithm(&self) -> HashingAlgorithm {
42 self.hashing_algorithm
43 }
44
45 /// Returns 'Size of Select'
46 ///
47 /// NB! This is not the same as how many [PcrSlot]
48 /// there are in the selection but rather how many
49 /// octets that are needed to hold the bit field
50 /// that indicate what slots that are selected.
51 pub const fn size_of_select(&self) -> PcrSelectSize {
52 self.pcr_slot_collection.size_of_select()
53 }
54
55 /// Returns the selected pcrs.
56 pub fn selected(&self) -> Vec<PcrSlot> {
57 self.pcr_slot_collection.collection()
58 }
59
60 /// Returns true if the specified [PcrSlot] is selected in
61 /// the [PcrSelection].
62 pub fn is_selected(&self, pcr_slot: PcrSlot) -> bool {
63 self.pcr_slot_collection.contains(pcr_slot)
64 }
65
66 /// Removes the specified [PcrSlot]s from the selected pcrs.
67 ///
68 /// # Errors
69 /// If one of the specified pcr slots does not exist in the selected pcrs.
70 pub fn deselect_exact(&mut self, pcr_slot: PcrSlot) -> Result<()> {
71 self.pcr_slot_collection.remove_exact(pcr_slot)
72 }
73
74 /// Removes the specified [PcrSlot]s from the selected pcrs.
75 pub fn deselect(&mut self, pcr_slot: PcrSlot) {
76 self.pcr_slot_collection.remove(pcr_slot)
77 }
78
79 /// Merges another [PcrSelection] into `self` if the
80 /// elements in the collection does not already exist
81 /// in `self`.
82 ///
83 /// # Constraints
84 /// * Cannot be called with `other` that has a hashing_algorithm
85 /// that is different from the one in `self`.
86 /// * Cannot be called with `other` that has a size_of_select
87 /// that is different from the one in `self`.
88 /// * Cannot be called with `other`that contains pcr slots present
89 /// in `self`.
90 ///
91 /// # Errors
92 /// Returns InvalidParam if there is a hashing algorithm mismatch
93 /// Returns InvalidParam if there is size of select mismatch.
94 /// Returns InvalidParam if `other` contains items that are present in `self`
95 pub fn merge_exact(&mut self, other: &Self) -> Result<()> {
96 // Check that the hashing algorithm match
97 if self.hashing_algorithm != other.hashing_algorithm {
98 error!("Found inconsistencies in the hashing algorithm");
99 return Err(Error::local_error(WrapperErrorKind::InvalidParam));
100 }
101
102 self.pcr_slot_collection
103 .merge_exact(&other.pcr_slot_collection)
104 }
105
106 /// Removes the selected pcr slots in `other` from `self`if none
107 /// of the pcr slots are present in `self`.
108 ///
109 /// # Constraints
110 /// * Cannot be called with `other` that has a hashing_algorithm
111 /// that is different from the one in `self`.
112 /// * Cannot be called with `other` that has a size_of_select
113 /// that is different from the one in `self`.
114 /// * Cannot be called with `other`that contains pcr slots not present
115 /// in `self`.
116 pub fn subtract_exact(&mut self, other: &Self) -> Result<()> {
117 // Check that the hashing algorithm match
118 if self.hashing_algorithm != other.hashing_algorithm {
119 error!("Mismatched hashing algorithm ");
120 return Err(Error::local_error(WrapperErrorKind::InconsistentParams));
121 }
122
123 self.pcr_slot_collection
124 .subtract_exact(&other.pcr_slot_collection)
125 }
126
127 /// Indicates whether the pcr selection is empty.
128 pub fn is_empty(&self) -> bool {
129 self.pcr_slot_collection.is_empty()
130 }
131}
132
133impl TryFrom<TPMS_PCR_SELECTION> for PcrSelection {
134 type Error = Error;
135
136 fn try_from(tss_pcr_selection: TPMS_PCR_SELECTION) -> Result<Self> {
137 // Parse hashing algorithm.
138 let hashing_algorithm =
139 HashingAlgorithm::try_from(tss_pcr_selection.hash).map_err(|e| {
140 error!("Error converting hash to a HashingAlgorithm: {}", e);
141 Error::local_error(WrapperErrorKind::InvalidParam)
142 })?;
143
144 let pcr_slot_collection = PcrSlotCollection::try_from((
145 tss_pcr_selection.sizeofSelect,
146 tss_pcr_selection.pcrSelect,
147 ))?;
148
149 Ok(PcrSelection {
150 hashing_algorithm,
151 pcr_slot_collection,
152 })
153 }
154}
155
156impl From<PcrSelection> for TPMS_PCR_SELECTION {
157 fn from(pcr_selection: PcrSelection) -> Self {
158 let (size_of_select, pcr_select) = pcr_selection.pcr_slot_collection.into();
159 TPMS_PCR_SELECTION {
160 hash: pcr_selection.hashing_algorithm.into(),
161 sizeofSelect: size_of_select,
162 pcrSelect: pcr_select,
163 }
164 }
165}