Skip to content

Commit f9d71d1

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. - Removed lower limit for DigestList. - Improved linage between the read pcr list and the read pcr digests in tests. Signed-off-by: Jesper Brynolf <[email protected]>
1 parent 714fe81 commit f9d71d1

File tree

18 files changed

+517
-284
lines changed

18 files changed

+517
-284
lines changed

tss-esapi/src/abstraction/mod.rs

+1
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

+24
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

+77
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

+121
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
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+
Error, Result, WrapperErrorKind,
10+
};
11+
use log::error;
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+
if pcr_slots.len() > digests.len() {
60+
error!("More pcr slots in selection then available digests");
61+
return Err(Error::local_error(WrapperErrorKind::InconsistentParams));
62+
}
63+
let digests_in_bank = digests.drain(..pcr_slots.len()).collect();
64+
Ok((
65+
pcr_selection.hashing_algorithm(),
66+
PcrBank::create(pcr_slots, digests_in_bank)?,
67+
))
68+
})
69+
.collect()
70+
}
71+
72+
/// Function for retrieving the first PCR values associated with hashing_algorithm.
73+
pub fn pcr_bank(&self, hashing_algorithm: HashingAlgorithm) -> Option<&PcrBank> {
74+
self.data
75+
.iter()
76+
.find(|(alg, _)| alg == &hashing_algorithm)
77+
.map(|(_, bank)| bank)
78+
}
79+
80+
/// Function for retrieving the number of banks in the data.
81+
pub fn len(&self) -> usize {
82+
self.data.len()
83+
}
84+
85+
/// Returns true if there are no banks in the data.
86+
pub fn is_empty(&self) -> bool {
87+
self.data.is_empty()
88+
}
89+
}
90+
91+
impl<'a> IntoIterator for PcrData {
92+
type Item = (HashingAlgorithm, PcrBank);
93+
type IntoIter = ::std::vec::IntoIter<(HashingAlgorithm, PcrBank)>;
94+
95+
fn into_iter(self) -> Self::IntoIter {
96+
self.data.into_iter()
97+
}
98+
}
99+
100+
impl From<PcrData> for Vec<TPML_DIGEST> {
101+
fn from(pcr_data: PcrData) -> Self {
102+
pcr_data
103+
.data
104+
.iter()
105+
.flat_map(|(_, pcr_bank)| pcr_bank.into_iter())
106+
.map(|(_, digest)| digest)
107+
.collect::<Vec<&Digest>>()
108+
.chunks(DigestList::MAX_SIZE)
109+
.map(|digests| {
110+
let mut tpml_digest: TPML_DIGEST = Default::default();
111+
for (index, digest) in digests.iter().enumerate() {
112+
tpml_digest.count += 1;
113+
tpml_digest.digests[index].size = digest.len() as u16;
114+
tpml_digest.digests[index].buffer[..digest.len()]
115+
.copy_from_slice(digest.value());
116+
}
117+
tpml_digest
118+
})
119+
.collect()
120+
}
121+
}

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

+9-3
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ impl Context {
130130
/// by the value of the different hashes.
131131
///
132132
/// # Constraints
133-
/// * `hash_list` must be at least 2 and at most 8 elements long
133+
/// * `digest_list` must be at least 2 and at most 8 elements long
134134
///
135135
/// # Errors
136136
/// * if the hash list provided is too short or too long, a `WrongParamSize` wrapper error will be returned
@@ -139,7 +139,13 @@ impl Context {
139139
policy_session: PolicySession,
140140
digest_list: DigestList,
141141
) -> Result<()> {
142-
let digest_list = TPML_DIGEST::try_from(digest_list)?;
142+
if 2 > digest_list.len() {
143+
error!(
144+
"The digest list only contains {} digests, it must contain at least 2",
145+
digest_list.len()
146+
);
147+
return Err(Error::local_error(ErrorKind::WrongParamSize));
148+
}
143149

144150
let ret = unsafe {
145151
Esys_PolicyOR(
@@ -148,7 +154,7 @@ impl Context {
148154
self.optional_session_1(),
149155
self.optional_session_2(),
150156
self.optional_session_3(),
151-
&digest_list,
157+
&TPML_DIGEST::try_from(digest_list)?,
152158
)
153159
};
154160
let ret = Error::from_tss_rc(ret);

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

+8-8
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);

0 commit comments

Comments
 (0)