Skip to content

Commit 08efe62

Browse files
authored
Merge pull request #606 from mstrug/mstrug/hash-hmac-sequence-implementation
Added hash/HMAC sequence support
2 parents f3d9883 + 9ae3d65 commit 08efe62

File tree

2 files changed

+474
-5
lines changed

2 files changed

+474
-5
lines changed
Lines changed: 319 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,326 @@
11
// Copyright 2021 Contributors to the Parsec project.
22
// SPDX-License-Identifier: Apache-2.0
3-
use crate::Context;
3+
use crate::{
4+
handles::{ObjectHandle, TpmHandle},
5+
interface_types::{algorithm::HashingAlgorithm, reserved_handles::Hierarchy},
6+
structures::{Auth, Digest, HashcheckTicket, MaxBuffer},
7+
tss2_esys::{
8+
Esys_HMAC_Start, Esys_HashSequenceStart, Esys_SequenceComplete, Esys_SequenceUpdate,
9+
},
10+
Context, Result, ReturnCode,
11+
};
12+
use log::error;
13+
use std::ptr::null_mut;
414

515
impl Context {
6-
// Missing function: HMAC_Start
16+
/// Starts HMAC sequence of large data (larger than [`MaxBuffer::MAX_SIZE`]) using the specified algorithm.
17+
///
18+
/// # Details
19+
/// When the amount of data to be included in a digest cannot be sent to the TPM in one atomic HMAC
20+
/// command then a sequence of commands may be used to provide incremental updates to the digest.
21+
///
22+
/// Follow the pattern:
23+
/// - Initialize sequence with [`Context::hmac_sequence_start`]
24+
/// - Send data to calculate the hash with [`Context::sequence_update`]
25+
/// - Finish hash calculation with call to [`Context::sequence_complete`]
26+
///
27+
/// # Example
28+
///
29+
/// ```rust
30+
/// # use tss_esapi::{Context, tcti_ldr::TctiNameConf,
31+
/// # attributes::{ObjectAttributesBuilder, SessionAttributesBuilder},
32+
/// # structures::{
33+
/// # Auth, MaxBuffer, Ticket, SymmetricDefinition,
34+
/// # RsaExponent, RsaScheme, KeyedHashScheme,
35+
/// # PublicBuilder, PublicKeyedHashParameters
36+
/// # },
37+
/// # constants::{
38+
/// # tss::{TPMA_SESSION_DECRYPT, TPMA_SESSION_ENCRYPT},
39+
/// # SessionType,
40+
/// # },
41+
/// # interface_types::{
42+
/// # algorithm::{HashingAlgorithm, PublicAlgorithm, RsaSchemeAlgorithm},
43+
/// # key_bits::RsaKeyBits, reserved_handles::Hierarchy
44+
/// # },
45+
/// # utils::create_unrestricted_signing_rsa_public,
46+
/// # };
47+
/// # use std::convert::TryFrom;
48+
/// # use std::str::FromStr;
49+
/// # // Create context with session
50+
/// # let mut context =
51+
/// # Context::new(
52+
/// # TctiNameConf::from_environment_variable().expect("Failed to get TCTI"),
53+
/// # ).expect("Failed to create Context");
54+
/// # let session = context
55+
/// # .start_auth_session(
56+
/// # None,
57+
/// # None,
58+
/// # None,
59+
/// # SessionType::Hmac,
60+
/// # SymmetricDefinition::AES_256_CFB,
61+
/// # HashingAlgorithm::Sha256,
62+
/// # )
63+
/// # .expect("Failed to create session");
64+
/// # let (session_attributes, session_attributes_mask) = SessionAttributesBuilder::new()
65+
/// # .with_decrypt(true)
66+
/// # .with_encrypt(true)
67+
/// # .build();
68+
/// # context.tr_sess_set_attributes(session.unwrap(), session_attributes, session_attributes_mask)
69+
/// # .expect("Failed to set attributes on session");
70+
/// # context.set_sessions((session, None, None));
71+
/// #
72+
/// let object_attributes = ObjectAttributesBuilder::new()
73+
/// .with_sign_encrypt(true)
74+
/// .with_sensitive_data_origin(true)
75+
/// .with_user_with_auth(true)
76+
/// .build()
77+
/// .expect("Failed to build object attributes");
78+
///
79+
/// let key_pub = PublicBuilder::new()
80+
/// .with_public_algorithm(PublicAlgorithm::KeyedHash)
81+
/// .with_name_hashing_algorithm(HashingAlgorithm::Sha256)
82+
/// .with_object_attributes(object_attributes)
83+
/// .with_keyed_hash_parameters(PublicKeyedHashParameters::new(
84+
/// KeyedHashScheme::HMAC_SHA_256,
85+
/// ))
86+
/// .with_keyed_hash_unique_identifier(Default::default())
87+
/// .build()
88+
/// .expect("Failed to build public structure for key.");
89+
///
90+
/// let key = context
91+
/// .create_primary(Hierarchy::Owner, key_pub, None, None, None, None)
92+
/// .unwrap();
93+
///
94+
/// let data = [0xEE; 5000];
95+
///
96+
/// let handle = context
97+
/// .hmac_sequence_start(key.key_handle.into(), HashingAlgorithm::Sha256, None)
98+
/// .unwrap();
99+
///
100+
/// let chunks = data.chunks_exact(MaxBuffer::MAX_SIZE);
101+
/// let last_chunk = chunks.remainder();
102+
/// for chunk in chunks {
103+
/// context
104+
/// .sequence_update(handle, MaxBuffer::from_bytes(chunk).unwrap())
105+
/// .unwrap();
106+
/// }
107+
/// let (actual_hashed_data, ticket) = context
108+
/// .sequence_complete(
109+
/// handle,
110+
/// MaxBuffer::from_bytes(last_chunk).unwrap(),
111+
/// Hierarchy::Null,
112+
/// )
113+
/// .unwrap();
114+
/// ```
115+
pub fn hmac_sequence_start(
116+
&mut self,
117+
handle: ObjectHandle,
118+
hashing_algorithm: HashingAlgorithm,
119+
auth: Option<Auth>,
120+
) -> Result<ObjectHandle> {
121+
let mut sequence_handle = ObjectHandle::None.into();
122+
ReturnCode::ensure_success(
123+
unsafe {
124+
Esys_HMAC_Start(
125+
self.mut_context(),
126+
handle.into(),
127+
self.optional_session_1(),
128+
self.optional_session_2(),
129+
self.optional_session_3(),
130+
&auth.unwrap_or_default().into(),
131+
hashing_algorithm.into(),
132+
&mut sequence_handle,
133+
)
134+
},
135+
|ret| {
136+
error!(
137+
"Error failed to perform HMAC sequence start operation: {:#010X}",
138+
ret
139+
);
140+
},
141+
)?;
142+
Ok(ObjectHandle::from(sequence_handle))
143+
}
144+
7145
// Missing function: MAC_Start
8-
// Missing function: HashSequenceStart
9-
// Missing function: SequenceUpdate
10-
// Missing function: SequenceComplete
146+
147+
/// Starts hash sequence of large data (larger than [`MaxBuffer::MAX_SIZE`]) using the specified algorithm.
148+
///
149+
/// # Details
150+
/// When the amount of data to be included in a digest cannot be sent to the TPM in one atomic hash
151+
/// command then a sequence of commands may be used to provide incremental updates to the digest.
152+
///
153+
/// Follow the pattern:
154+
/// - Initialize sequence with [`Context::hmac_sequence_start`]
155+
/// - Send data to calculate the hash with [`Context::sequence_update`]
156+
/// - Finish hash calculation with call to [`Context::sequence_complete`]
157+
///
158+
/// # Example
159+
///
160+
/// ```rust
161+
/// # use tss_esapi::{Context, tcti_ldr::TctiNameConf,
162+
/// # attributes::SessionAttributesBuilder,
163+
/// # structures::{Auth, MaxBuffer, Ticket, SymmetricDefinition, RsaExponent, RsaScheme},
164+
/// # constants::{
165+
/// # tss::{TPMA_SESSION_DECRYPT, TPMA_SESSION_ENCRYPT},
166+
/// # SessionType,
167+
/// # },
168+
/// # interface_types::{
169+
/// # algorithm::{HashingAlgorithm, RsaSchemeAlgorithm},
170+
/// # key_bits::RsaKeyBits, reserved_handles::Hierarchy
171+
/// # },
172+
/// # utils::create_unrestricted_signing_rsa_public,
173+
/// # };
174+
/// # use std::convert::TryFrom;
175+
/// # use std::str::FromStr;
176+
/// # // Create context with session
177+
/// # let mut context =
178+
/// # Context::new(
179+
/// # TctiNameConf::from_environment_variable().expect("Failed to get TCTI"),
180+
/// # ).expect("Failed to create Context");
181+
/// # let session = context
182+
/// # .start_auth_session(
183+
/// # None,
184+
/// # None,
185+
/// # None,
186+
/// # SessionType::Hmac,
187+
/// # SymmetricDefinition::AES_256_CFB,
188+
/// # HashingAlgorithm::Sha256,
189+
/// # )
190+
/// # .expect("Failed to create session");
191+
/// # let (session_attributes, session_attributes_mask) = SessionAttributesBuilder::new()
192+
/// # .with_decrypt(true)
193+
/// # .with_encrypt(true)
194+
/// # .build();
195+
/// # context.tr_sess_set_attributes(session.unwrap(), session_attributes, session_attributes_mask)
196+
/// # .expect("Failed to set attributes on session");
197+
/// # context.set_sessions((session, None, None));
198+
///
199+
/// let data = [0xEE; 2*1025];
200+
///
201+
/// let handle = context
202+
/// .hash_sequence_start(HashingAlgorithm::Sha256, None)
203+
/// .unwrap();
204+
///
205+
/// let chunks = data.chunks_exact(MaxBuffer::MAX_SIZE);
206+
/// let last_chunk = chunks.remainder();
207+
/// for chunk in chunks {
208+
/// context
209+
/// .sequence_update(handle, MaxBuffer::from_bytes(chunk).unwrap())
210+
/// .unwrap();
211+
/// }
212+
/// let (actual_hashed_data, ticket) = context
213+
/// .sequence_complete(
214+
/// handle,
215+
/// MaxBuffer::from_bytes(last_chunk).unwrap(),
216+
/// Hierarchy::Owner,
217+
/// )
218+
/// .unwrap();
219+
/// ```
220+
pub fn hash_sequence_start(
221+
&mut self,
222+
hashing_algorithm: HashingAlgorithm,
223+
auth: Option<Auth>,
224+
) -> Result<ObjectHandle> {
225+
let mut sequence_handle = ObjectHandle::None.into();
226+
ReturnCode::ensure_success(
227+
unsafe {
228+
Esys_HashSequenceStart(
229+
self.mut_context(),
230+
self.optional_session_1(),
231+
self.optional_session_2(),
232+
self.optional_session_3(),
233+
&auth.unwrap_or_default().into(),
234+
hashing_algorithm.into(),
235+
&mut sequence_handle,
236+
)
237+
},
238+
|ret| {
239+
error!(
240+
"Error failed to perform hash sequence start operation: {:#010X}",
241+
ret
242+
);
243+
},
244+
)?;
245+
Ok(ObjectHandle::from(sequence_handle))
246+
}
247+
248+
/// Continues hash or HMAC sequence.
249+
///
250+
/// See [`Context::hash_sequence_start`], [`Context::hmac_sequence_start`].
251+
pub fn sequence_update(
252+
&mut self,
253+
sequence_handle: ObjectHandle,
254+
data: MaxBuffer,
255+
) -> Result<()> {
256+
ReturnCode::ensure_success(
257+
unsafe {
258+
Esys_SequenceUpdate(
259+
self.mut_context(),
260+
sequence_handle.into(),
261+
self.optional_session_1(),
262+
self.optional_session_2(),
263+
self.optional_session_3(),
264+
&data.into(),
265+
)
266+
},
267+
|ret| {
268+
error!(
269+
"Error failed to perform sequence update operation: {:#010X}",
270+
ret
271+
);
272+
},
273+
)
274+
}
275+
276+
/// Finishes hash or HMAC sequence.
277+
///
278+
/// /// See [`Context::hash_sequence_start`], [`Context::hmac_sequence_start`].
279+
pub fn sequence_complete(
280+
&mut self,
281+
sequence_handle: ObjectHandle,
282+
data: MaxBuffer,
283+
hierarchy: Hierarchy,
284+
) -> Result<(Digest, Option<HashcheckTicket>)> {
285+
let mut out_hash_ptr = null_mut();
286+
let mut validation_ptr = null_mut();
287+
ReturnCode::ensure_success(
288+
unsafe {
289+
Esys_SequenceComplete(
290+
self.mut_context(),
291+
sequence_handle.into(),
292+
self.optional_session_1(),
293+
self.optional_session_2(),
294+
self.optional_session_3(),
295+
&data.into(),
296+
if cfg!(hierarchy_is_esys_tr) {
297+
ObjectHandle::from(hierarchy).into()
298+
} else {
299+
TpmHandle::from(hierarchy).into()
300+
},
301+
&mut out_hash_ptr,
302+
&mut validation_ptr,
303+
)
304+
},
305+
|ret| {
306+
error!(
307+
"Error failed to perform sequence complete operation: {:#010X}",
308+
ret
309+
);
310+
},
311+
)?;
312+
Ok((
313+
Digest::try_from(Context::ffi_data_to_owned(out_hash_ptr)?)?,
314+
if validation_ptr.is_null() {
315+
// For HMAC sequence validation parameter is NULL
316+
None
317+
} else {
318+
Some(HashcheckTicket::try_from(Context::ffi_data_to_owned(
319+
validation_ptr,
320+
)?)?)
321+
},
322+
))
323+
}
324+
11325
// Missing function: EventSequenceComplete
12326
}

0 commit comments

Comments
 (0)