tss_esapi/context/tpm_commands/hash_hmac_event_sequences.rs
1// Copyright 2021 Contributors to the Parsec project.
2// SPDX-License-Identifier: Apache-2.0
3use 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};
12use log::error;
13use std::ptr::null_mut;
14
15impl Context {
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
145 // Missing function: MAC_Start
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
325 // Missing function: EventSequenceComplete
326}