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}