Skip to main content

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}