Skip to content

Commit 4850d16

Browse files
committed
Improved return values of pcr_read.
- Changed pcr_read to return a DigestList instead of PcrData. - Moved PcrData to abstractions and made it possible to construct PcrData from rust native types. - Added subtract to PcrSelectionList. - Added a pcr_read_all functiion to the pcr module in abstractions. This function tries to read all the values in a PcrSelectionList. Signed-off-by: Jesper Brynolf <[email protected]>
1 parent 714fe81 commit 4850d16

File tree

14 files changed

+356
-215
lines changed

14 files changed

+356
-215
lines changed

tss-esapi/src/abstraction/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ pub mod ak;
55
pub mod cipher;
66
pub mod ek;
77
pub mod nv;
8+
pub mod pcr;
89
pub mod transient;
910

1011
use crate::{attributes::ObjectAttributesBuilder, structures::PublicBuilder};

tss-esapi/src/abstraction/pcr.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// Copyright 2021 Contributors to the Parsec project.
2+
// SPDX-License-Identifier: Apache-2.0
3+
mod bank;
4+
mod data;
5+
6+
use crate::{structures::PcrSelectionList, Context, Result};
7+
8+
pub use bank::PcrBank;
9+
pub use data::PcrData;
10+
11+
/// Function that reads all the PCRs in a selection list and returns
12+
/// the result as PCR data.
13+
pub fn pcr_read_all(
14+
context: &mut Context,
15+
mut pcr_selection_list: PcrSelectionList,
16+
) -> Result<PcrData> {
17+
let mut pcr_data = PcrData::new();
18+
while !pcr_selection_list.is_empty() {
19+
let (_, pcrs_read, pcr_digests) = context.pcr_read(&pcr_selection_list)?;
20+
pcr_data.add(&pcrs_read, &pcr_digests)?;
21+
pcr_selection_list.subtract(&pcrs_read)?;
22+
}
23+
Ok(pcr_data)
24+
}

tss-esapi/src/abstraction/pcr/bank.rs

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
// Copyright 2021 Contributors to the Parsec project.
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
use crate::{
5+
structures::{Digest, PcrSlot},
6+
Error, Result, WrapperErrorKind,
7+
};
8+
use log::error;
9+
use std::collections::BTreeMap;
10+
11+
/// Struct for holding PcrSlots and their
12+
/// corresponding values.
13+
#[derive(Debug, Clone, Eq, PartialEq)]
14+
pub struct PcrBank {
15+
bank: BTreeMap<PcrSlot, Digest>,
16+
}
17+
18+
impl PcrBank {
19+
/// Function that creates PcrBank from a vector of pcr slots and
20+
/// a vector of pcr digests.
21+
///
22+
/// # Details
23+
/// The order of pcr slots are assumed to match the order of the Digests.
24+
///
25+
/// # Error
26+
/// - If number of pcr slots does not match the number of pcr digests
27+
/// InconsistentParams error is returned.
28+
///
29+
/// - If the vector of pcr slots contains duplicates then
30+
/// InconsistentParams error is returned.
31+
pub fn create(mut pcr_slots: Vec<PcrSlot>, mut digests: Vec<Digest>) -> Result<PcrBank> {
32+
if pcr_slots.len() != digests.len() {
33+
error!(
34+
"Number of PcrSlots does not match the number of PCR digests. ({} != {})",
35+
pcr_slots.len(),
36+
digests.len()
37+
);
38+
return Err(Error::local_error(WrapperErrorKind::InconsistentParams));
39+
}
40+
pcr_slots
41+
.drain(..)
42+
.zip(digests.drain(..))
43+
.try_fold(BTreeMap::<PcrSlot, Digest>::new(), |mut data, (pcr_slot, digest)| {
44+
if data.insert(pcr_slot, digest).is_none() {
45+
Ok(data)
46+
} else {
47+
error!("Error trying to insert data into PcrSlot {:?} where data have already been inserted", pcr_slot);
48+
Err(Error::local_error(WrapperErrorKind::InconsistentParams))
49+
}
50+
})
51+
.map(|bank| PcrBank { bank })
52+
}
53+
54+
/// Function for retrieving a pcr value corresponding to a pcr slot.
55+
pub fn pcr_value(&self, pcr_slot: PcrSlot) -> Option<&Digest> {
56+
self.bank.get(&pcr_slot)
57+
}
58+
59+
/// Function for retrieiving the number of pcr slot values in the bank.
60+
pub fn len(&self) -> usize {
61+
self.bank.len()
62+
}
63+
64+
/// Returns true if there are no pcr slot values in the bank.
65+
pub fn is_empty(&self) -> bool {
66+
self.bank.is_empty()
67+
}
68+
}
69+
70+
impl<'a> IntoIterator for &'a PcrBank {
71+
type Item = (&'a PcrSlot, &'a Digest);
72+
type IntoIter = ::std::collections::btree_map::Iter<'a, PcrSlot, Digest>;
73+
74+
fn into_iter(self) -> Self::IntoIter {
75+
self.bank.iter()
76+
}
77+
}

tss-esapi/src/abstraction/pcr/data.rs

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
// Copyright 2021 Contributors to the Parsec project.
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
use crate::{
5+
abstraction::pcr::PcrBank,
6+
interface_types::algorithm::HashingAlgorithm,
7+
structures::{Digest, DigestList, PcrSelectionList},
8+
tss2_esys::TPML_DIGEST,
9+
Result,
10+
};
11+
12+
/// Struct holding pcr banks and their associated
13+
/// hashing algorithm
14+
#[derive(Debug, Clone, PartialEq, Eq)]
15+
pub struct PcrData {
16+
data: Vec<(HashingAlgorithm, PcrBank)>,
17+
}
18+
19+
impl PcrData {
20+
/// Creates new empty PcrData
21+
pub const fn new() -> Self {
22+
PcrData { data: Vec::new() }
23+
}
24+
25+
/// Function for creating PcrData from a pcr selection list and pcr digests list.
26+
pub fn create(
27+
pcr_selection_list: &PcrSelectionList,
28+
digest_list: &DigestList,
29+
) -> Result<PcrData> {
30+
Ok(PcrData {
31+
data: Self::create_data(pcr_selection_list, digest_list.value().to_vec())?,
32+
})
33+
}
34+
35+
/// Adds data to the PcrData
36+
pub fn add(
37+
&mut self,
38+
pcr_selection_list: &PcrSelectionList,
39+
digest_list: &DigestList,
40+
) -> Result<()> {
41+
self.data.append(&mut Self::create_data(
42+
pcr_selection_list,
43+
digest_list.value().to_vec(),
44+
)?);
45+
Ok(())
46+
}
47+
48+
/// Function for turning a pcr selection list and pcr digests values
49+
/// into the format in which data is stored in PcrData.
50+
fn create_data(
51+
pcr_selection_list: &PcrSelectionList,
52+
mut digests: Vec<Digest>,
53+
) -> Result<Vec<(HashingAlgorithm, PcrBank)>> {
54+
pcr_selection_list
55+
.get_selections()
56+
.iter()
57+
.map(|pcr_selection| {
58+
let pcr_slots = pcr_selection.selected_pcrs();
59+
let number_of_pcrs = pcr_slots.len();
60+
Ok((
61+
pcr_selection.hashing_algorithm(),
62+
PcrBank::create(pcr_slots, digests.drain(..number_of_pcrs).collect())?,
63+
))
64+
})
65+
.collect()
66+
}
67+
68+
/// Function for retrieving the first PCR values associated with hashing_algorithm.
69+
pub fn pcr_bank(&self, hashing_algorithm: HashingAlgorithm) -> Option<&PcrBank> {
70+
self.data
71+
.iter()
72+
.find(|(alg, _)| alg == &hashing_algorithm)
73+
.map(|(_, bank)| bank)
74+
}
75+
76+
/// Function for retrieving the number of banks in the data.
77+
pub fn len(&self) -> usize {
78+
self.data.len()
79+
}
80+
81+
/// Returns true if there are no banks in the data.
82+
pub fn is_empty(&self) -> bool {
83+
self.data.is_empty()
84+
}
85+
}
86+
87+
impl<'a> IntoIterator for PcrData {
88+
type Item = (HashingAlgorithm, PcrBank);
89+
type IntoIter = ::std::vec::IntoIter<(HashingAlgorithm, PcrBank)>;
90+
91+
fn into_iter(self) -> Self::IntoIter {
92+
self.data.into_iter()
93+
}
94+
}
95+
96+
impl From<PcrData> for TPML_DIGEST {
97+
fn from(pcr_data: PcrData) -> Self {
98+
let mut tpml_digest: TPML_DIGEST = Default::default();
99+
100+
for (_, pcr_bank) in pcr_data.into_iter() {
101+
for (_, pcr_value) in pcr_bank.into_iter() {
102+
let i = tpml_digest.count as usize;
103+
let size = pcr_value.value().len() as u16;
104+
tpml_digest.digests[i].size = size;
105+
tpml_digest.digests[i].buffer[..size as usize].copy_from_slice(pcr_value.value());
106+
tpml_digest.count += 1;
107+
}
108+
}
109+
tpml_digest
110+
}
111+
}

tss-esapi/src/context/tpm_commands/integrity_collection_pcr.rs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,8 @@
22
// SPDX-License-Identifier: Apache-2.0
33
use crate::{
44
handles::PcrHandle,
5-
structures::{DigestValues, PcrSelectionList},
5+
structures::{DigestList, DigestValues, PcrSelectionList},
66
tss2_esys::*,
7-
utils::PcrData,
87
Context, Error, Result,
98
};
109
use log::error;
@@ -149,16 +148,16 @@ impl Context {
149148
/// .with_selection(HashingAlgorithm::Sha256, &[PcrSlot::Slot0, PcrSlot::Slot1])
150149
/// .build();
151150
///
152-
/// let (update_counter, read_pcr_list, pcr_data) = context.pcr_read(&pcr_selection_list)
151+
/// let (update_counter, read_pcr_list, digest_list) = context.pcr_read(&pcr_selection_list)
153152
/// .expect("Call to pcr_read failed");
154153
/// ```
155154
pub fn pcr_read(
156155
&mut self,
157156
pcr_selection_list: &PcrSelectionList,
158-
) -> Result<(u32, PcrSelectionList, PcrData)> {
157+
) -> Result<(u32, PcrSelectionList, DigestList)> {
159158
let mut pcr_update_counter: u32 = 0;
160159
let mut tss_pcr_selection_list_out_ptr = null_mut();
161-
let mut tss_digest_ptr = null_mut();
160+
let mut tss_digest_list_out_ptr = null_mut();
162161
let ret = unsafe {
163162
Esys_PCR_Read(
164163
self.mut_context(),
@@ -168,19 +167,20 @@ impl Context {
168167
&pcr_selection_list.clone().into(),
169168
&mut pcr_update_counter,
170169
&mut tss_pcr_selection_list_out_ptr,
171-
&mut tss_digest_ptr,
170+
&mut tss_digest_list_out_ptr,
172171
)
173172
};
174173
let ret = Error::from_tss_rc(ret);
175174

176175
if ret.is_success() {
177176
let tss_pcr_selection_list_out =
178177
unsafe { MBox::<TPML_PCR_SELECTION>::from_raw(tss_pcr_selection_list_out_ptr) };
179-
let tss_digest = unsafe { MBox::<TPML_DIGEST>::from_raw(tss_digest_ptr) };
178+
let tss_digest_list_out =
179+
unsafe { MBox::<TPML_DIGEST>::from_raw(tss_digest_list_out_ptr) };
180180
Ok((
181181
pcr_update_counter,
182182
PcrSelectionList::try_from(*tss_pcr_selection_list_out)?,
183-
PcrData::new(tss_pcr_selection_list_out.as_ref(), tss_digest.as_ref())?,
183+
DigestList::try_from(*tss_digest_list_out)?,
184184
))
185185
} else {
186186
error!("Error when reading PCR: {}", ret);

tss-esapi/src/structures/lists/digest.rs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,16 +15,30 @@ impl DigestList {
1515
// minimum is two for TPM2_PolicyOR().
1616
pub const MIN_SIZE: usize = 2;
1717
pub const MAX_SIZE: usize = 8;
18-
pub fn new() -> Self {
18+
19+
/// Creates a nnew empty DigestList
20+
pub const fn new() -> Self {
1921
DigestList {
2022
digests: Vec::new(),
2123
}
2224
}
2325

26+
/// Returns the values in the digest list.
2427
pub fn value(&self) -> &[Digest] {
2528
&self.digests
2629
}
2730

31+
/// Returns the number of digests in the digestlist
32+
pub fn len(&self) -> usize {
33+
self.digests.len()
34+
}
35+
36+
/// Indicates if the digest list contains any digests.
37+
pub fn is_empty(&self) -> bool {
38+
self.digests.is_empty()
39+
}
40+
41+
/// Adds a new digest to the digest list.
2842
pub fn add(&mut self, dig: Digest) -> Result<()> {
2943
if self.digests.len() >= DigestList::MAX_SIZE {
3044
error!("Error: Exceeded maximum count(> {})", DigestList::MAX_SIZE);

tss-esapi/src/structures/lists/pcr_selection.rs

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use crate::{Error, Result, WrapperErrorKind};
77
use log::error;
88
use std::collections::HashMap;
99
use std::convert::TryFrom;
10+
1011
/// A struct representing a pcr selection list. This
1112
/// corresponds to the TSS TPML_PCR_SELECTION.
1213
#[derive(Debug, Clone, PartialEq, Eq)]
@@ -31,12 +32,50 @@ impl PcrSelectionList {
3132
&self.items
3233
}
3334

35+
/// Subtracts other from self
36+
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+
53+
Ok(())
54+
}
55+
3456
/// Function for retrieving the PcrSelectionList from Option<PcrSelectionList>
3557
///
3658
/// This returns an empty list if None is passed
3759
pub fn list_from_option(pcr_list: Option<PcrSelectionList>) -> PcrSelectionList {
3860
pcr_list.unwrap_or_else(|| PcrSelectionListBuilder::new().build())
3961
}
62+
63+
/// Private methods for removing pcr selections that are empty.
64+
fn remove_empty_selections(&mut self) {
65+
self.items.retain(|v| v.is_empty());
66+
}
67+
68+
/// Private function for removing PcrSelection for the PcrSelectionList.
69+
fn remove_selection(&mut self, other: &PcrSelection) -> Result<()> {
70+
self.items
71+
.iter_mut()
72+
.find(|local| local.hashing_algorithm() == other.hashing_algorithm())
73+
.ok_or_else(|| {
74+
error!("Cannot remove item that does not exist");
75+
Error::local_error(WrapperErrorKind::InvalidParam)
76+
})
77+
.and_then(|local| local.subtract(other))
78+
}
4079
}
4180

4281
impl From<PcrSelectionList> for TPML_PCR_SELECTION {

tss-esapi/src/structures/pcr/selection.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ pub struct PcrSelection {
1919
}
2020

2121
impl PcrSelection {
22+
/// Creates new PcrSelection
2223
pub fn new(
2324
hashing_algorithm: HashingAlgorithm,
2425
size_of_select: PcrSelectSize,
@@ -31,12 +32,14 @@ impl PcrSelection {
3132
}
3233
}
3334

35+
/// Returns the hashing algorithm for the selection
3436
pub fn hashing_algorithm(&self) -> HashingAlgorithm {
3537
self.hashing_algorithm
3638
}
3739

38-
pub fn selected_pcrs(&self) -> &BitFlags<PcrSlot> {
39-
&self.selected_pcrs
40+
/// Returns the selected pcrs.
41+
pub fn selected_pcrs(&self) -> Vec<PcrSlot> {
42+
self.selected_pcrs.iter().collect()
4043
}
4144

4245
pub fn merge(&mut self, other: &Self) -> Result<()> {

0 commit comments

Comments
 (0)