tss_esapi/context/general_esys_tr.rs
1// Copyright 2021 Contributors to the Parsec project.
2// SPDX-License-Identifier: Apache-2.0
3use crate::{
4 constants::tss::TPM2_RH_UNASSIGNED,
5 context::handle_manager::HandleDropAction,
6 ffi::{to_owned_bytes, FfiSizeType},
7 handles::ObjectHandle,
8 handles::{handle_conversion::TryIntoNotNone, TpmHandle},
9 structures::Auth,
10 structures::Name,
11 tss2_esys::{
12 Esys_TR_Close, Esys_TR_Deserialize, Esys_TR_FromTPMPublic, Esys_TR_GetName,
13 Esys_TR_Serialize, Esys_TR_SetAuth,
14 },
15 Context, Error, Result, ReturnCode, WrapperErrorKind,
16};
17use log::error;
18use std::convert::{TryFrom, TryInto};
19use std::ptr::null_mut;
20use zeroize::Zeroize;
21
22impl Context {
23 /// Set the authentication value for a given object handle in the ESYS context.
24 ///
25 /// # Arguments
26 /// * `object_handle` - The [ObjectHandle] associated with an object for which the auth is to be set.
27 /// * `auth` - The [Auth] that is to be set.
28 ///
29 /// ```rust
30 /// # use tss_esapi::{Context, TctiNameConf};
31 /// use tss_esapi::{handles::ObjectHandle, structures::Auth};
32 /// # // Create context
33 /// # let mut context =
34 /// # Context::new(
35 /// # TctiNameConf::from_environment_variable().expect("Failed to get TCTI"),
36 /// # ).expect("Failed to create Context");
37 ///
38 /// // Sets auth for Owner to empty string.
39 /// context
40 /// .tr_set_auth(ObjectHandle::Owner, Auth::default())
41 /// .expect("Failed to call tr_set_auth");
42 /// ```
43 pub fn tr_set_auth(&mut self, object_handle: ObjectHandle, auth: Auth) -> Result<()> {
44 let mut auth_value = auth.into();
45 ReturnCode::ensure_success(
46 unsafe { Esys_TR_SetAuth(self.mut_context(), object_handle.into(), &auth_value) },
47 |ret| {
48 auth_value.buffer.zeroize();
49 error!("Error when setting authentication value: {:#010X}", ret);
50 },
51 )
52 }
53
54 /// Retrieve the name of an object from the object handle.
55 ///
56 /// # Arguments
57 /// * `object_handle` - Handle to the object for which the 'name' shall be retrieved.
58 ///
59 /// # Returns
60 /// The objects name.
61 ///
62 /// # Example
63 /// ```rust
64 /// # use tss_esapi::{
65 /// # Context, TctiNameConf, attributes::{SessionAttributes, NvIndexAttributes},
66 /// # constants::SessionType, handles::NvIndexTpmHandle,
67 /// # interface_types::{algorithm::HashingAlgorithm, reserved_handles::Provision},
68 /// # structures::{SymmetricDefinition, NvPublic},
69 /// # };
70 /// # // Create context
71 /// # let mut context =
72 /// # Context::new(
73 /// # TctiNameConf::from_environment_variable().expect("Failed to get TCTI"),
74 /// # ).expect("Failed to create Context");
75 /// #
76 /// # let session = context
77 /// # .start_auth_session(
78 /// # None,
79 /// # None,
80 /// # None,
81 /// # SessionType::Hmac,
82 /// # SymmetricDefinition::AES_256_CFB,
83 /// # HashingAlgorithm::Sha256,
84 /// # )
85 /// # .expect("Failed to create session")
86 /// # .expect("Received invalid handle");
87 /// # let (session_attributes, session_attributes_mask) = SessionAttributes::builder()
88 /// # .with_decrypt(true)
89 /// # .with_encrypt(true)
90 /// # .build();
91 /// # context.tr_sess_set_attributes(session, session_attributes, session_attributes_mask)
92 /// # .expect("Failed to set attributes on session");
93 /// # context.set_sessions((Some(session), None, None));
94 /// #
95 /// # let nv_index = NvIndexTpmHandle::new(0x01500401)
96 /// # .expect("Failed to create NV index tpm handle");
97 /// #
98 /// # // Create NV index attributes
99 /// # let owner_nv_index_attributes = NvIndexAttributes::builder()
100 /// # .with_owner_write(true)
101 /// # .with_owner_read(true)
102 /// # .build()
103 /// # .expect("Failed to create owner nv index attributes");
104 /// #
105 /// # // Create owner nv public.
106 /// # let owner_nv_public = NvPublic::builder()
107 /// # .with_nv_index(nv_index)
108 /// # .with_index_name_algorithm(HashingAlgorithm::Sha256)
109 /// # .with_index_attributes(owner_nv_index_attributes)
110 /// # .with_data_area_size(32)
111 /// # .build()
112 /// # .expect("Failed to build NvPublic for owner");
113 /// #
114 /// # // Define the NV space.
115 /// # let nv_index_handle = context
116 /// # .nv_define_space(Provision::Owner, None, owner_nv_public)
117 /// # .expect("Call to nv_define_space failed");
118 ///
119 /// // Get the name using tr_get_name
120 /// let tr_get_name_result = context.tr_get_name(nv_index_handle.into());
121 ///
122 /// // Get the name from the NV by calling nv_read_public
123 /// let nv_read_public_result = context.nv_read_public(nv_index_handle);
124 /// #
125 /// # context
126 /// # .nv_undefine_space(Provision::Owner, nv_index_handle)
127 /// # .expect("Call to nv_undefine_space failed");
128 /// #
129 /// // Process result by comparing the names
130 /// let (_public_area, expected_name) = nv_read_public_result.expect("Call to nv_read_public failed");
131 /// let actual_name = tr_get_name_result.expect("Call to tr_get_name failed");
132 /// assert_eq!(expected_name, actual_name);
133 /// ```
134 pub fn tr_get_name(&mut self, object_handle: ObjectHandle) -> Result<Name> {
135 let mut name_ptr = null_mut();
136 ReturnCode::ensure_success(
137 unsafe { Esys_TR_GetName(self.mut_context(), object_handle.into(), &mut name_ptr) },
138 |ret| {
139 error!("Error in getting name: {:#010X}", ret);
140 },
141 )?;
142 Name::try_from(Context::ffi_data_to_owned(name_ptr)?)
143 }
144
145 /// Used to construct an esys object from the resources inside the TPM.
146 ///
147 /// # Arguments
148 /// * `tpm_handle` - The TPM handle that references the TPM object for which
149 /// the ESYS object is being created.
150 ///
151 /// # Returns
152 /// A handle to the ESYS object that was created from a TPM resource.
153 ///
154 /// # Example
155 /// ```rust
156 /// # use tss_esapi::{
157 /// # Context, TctiNameConf, attributes::{SessionAttributes, NvIndexAttributes},
158 /// # constants::SessionType,
159 /// # interface_types::{algorithm::HashingAlgorithm, reserved_handles::Provision},
160 /// # structures::{SymmetricDefinition, NvPublic},
161 /// # };
162 /// use tss_esapi::{
163 /// handles::NvIndexTpmHandle,
164 /// };
165 /// # // Create context
166 /// # let mut context =
167 /// # Context::new(
168 /// # TctiNameConf::from_environment_variable().expect("Failed to get TCTI"),
169 /// # ).expect("Failed to create Context");
170 /// #
171 /// # let session = context
172 /// # .start_auth_session(
173 /// # None,
174 /// # None,
175 /// # None,
176 /// # SessionType::Hmac,
177 /// # SymmetricDefinition::AES_256_CFB,
178 /// # HashingAlgorithm::Sha256,
179 /// # )
180 /// # .expect("Failed to create session")
181 /// # .expect("Received invalid handle");
182 /// # let (session_attributes, session_attributes_mask) = SessionAttributes::builder()
183 /// # .with_decrypt(true)
184 /// # .with_encrypt(true)
185 /// # .build();
186 /// # context.tr_sess_set_attributes(session, session_attributes, session_attributes_mask)
187 /// # .expect("Failed to set attributes on session");
188 /// # context.set_sessions((Some(session), None, None));
189 /// #
190 /// let nv_index = NvIndexTpmHandle::new(0x01500402)
191 /// .expect("Failed to create NV index tpm handle");
192 /// #
193 /// # // Create NV index attributes
194 /// # let owner_nv_index_attributes = NvIndexAttributes::builder()
195 /// # .with_owner_write(true)
196 /// # .with_owner_read(true)
197 /// # .build()
198 /// # .expect("Failed to create owner nv index attributes");
199 /// #
200 /// # // Create owner nv public.
201 /// # let owner_nv_public = NvPublic::builder()
202 /// # .with_nv_index(nv_index)
203 /// # .with_index_name_algorithm(HashingAlgorithm::Sha256)
204 /// # .with_index_attributes(owner_nv_index_attributes)
205 /// # .with_data_area_size(32)
206 /// # .build()
207 /// # .expect("Failed to build NvPublic for owner");
208 /// #
209 /// # // Define the NV space.
210 /// # let nv_index_handle = context
211 /// # .nv_define_space(Provision::Owner, None, owner_nv_public)
212 /// # .expect("Call to nv_define_space failed");
213 /// #
214 /// # // Retrieve the name of the NV space.
215 /// # let nv_read_public_result = context.nv_read_public(nv_index_handle);
216 /// #
217 /// # // Close the handle (remove all the metadata).
218 /// # let mut handle_to_be_closed = nv_index_handle.into();
219 /// # let tr_close_result = context
220 /// # .tr_close(&mut handle_to_be_closed);
221 /// #
222 /// // Call function without session (session can be provided in order to
223 /// // verify that the public data read actually originates from this TPM).
224 /// let retrieved_handle = context.execute_without_session(|ctx| {
225 /// ctx.tr_from_tpm_public(nv_index.into())
226 /// })
227 /// .expect("Call to tr_from_tpm_public failed.");
228 /// #
229 /// # // Use the retrieved handle to get the name of the object.
230 /// # let tr_get_name_result = context
231 /// # .tr_get_name(retrieved_handle);
232 /// #
233 /// # context
234 /// # .nv_undefine_space(Provision::Owner, retrieved_handle.into())
235 /// # .expect("Call to nv_undefine_space failed");
236 /// #
237 /// # // Process results.
238 /// # tr_close_result.expect("Call to tr_close_result failed");
239 /// # let (_, expected_name) = nv_read_public_result.expect("Call to nv_read_public failed");
240 /// # let actual_name = tr_get_name_result.expect("Call to tr_get_name failed");
241 /// # assert_eq!(expected_name, actual_name);
242 /// ```
243 pub fn tr_from_tpm_public(&mut self, tpm_handle: TpmHandle) -> Result<ObjectHandle> {
244 let mut object = ObjectHandle::None.into();
245 ReturnCode::ensure_success(
246 unsafe {
247 Esys_TR_FromTPMPublic(
248 self.mut_context(),
249 tpm_handle.into(),
250 self.optional_session_1(),
251 self.optional_session_2(),
252 self.optional_session_3(),
253 &mut object,
254 )
255 },
256 |ret| {
257 error!(
258 "Error when getting ESYS handle from TPM handle: {:#010X}",
259 ret
260 );
261 },
262 )?;
263 self.handle_manager.add_handle(
264 object.into(),
265 if tpm_handle.may_be_flushed() {
266 HandleDropAction::Flush
267 } else {
268 HandleDropAction::Close
269 },
270 )?;
271 Ok(object.into())
272 }
273
274 /// Instructs the ESAPI to release the metadata and resources allocated for a specific ObjectHandle.
275 ///
276 /// This is useful for cleaning up handles for which the context cannot be flushed.
277 ///
278 /// # Arguments
279 /// * object_handle`- An [ObjectHandle] referring to an object for which all metadata and
280 /// resources is going to be released.
281 ///
282 /// # Example
283 /// ```rust
284 /// # use tss_esapi::{
285 /// # Context, TctiNameConf, attributes::{SessionAttributes, NvIndexAttributes},
286 /// # constants::SessionType, handles::NvIndexTpmHandle,
287 /// # interface_types::{algorithm::HashingAlgorithm, reserved_handles::Provision},
288 /// # structures::{SymmetricDefinition, NvPublic},
289 /// # };
290 /// # // Create context
291 /// # let mut context =
292 /// # Context::new(
293 /// # TctiNameConf::from_environment_variable().expect("Failed to get TCTI"),
294 /// # ).expect("Failed to create Context");
295 /// #
296 /// # let session = context
297 /// # .start_auth_session(
298 /// # None,
299 /// # None,
300 /// # None,
301 /// # SessionType::Hmac,
302 /// # SymmetricDefinition::AES_256_CFB,
303 /// # HashingAlgorithm::Sha256,
304 /// # )
305 /// # .expect("Failed to create session")
306 /// # .expect("Received invalid handle");
307 /// # let (session_attributes, session_attributes_mask) = SessionAttributes::builder()
308 /// # .with_decrypt(true)
309 /// # .with_encrypt(true)
310 /// # .build();
311 /// # context.tr_sess_set_attributes(session, session_attributes, session_attributes_mask)
312 /// # .expect("Failed to set attributes on session");
313 /// # context.set_sessions((Some(session), None, None));
314 /// #
315 /// let nv_index = NvIndexTpmHandle::new(0x01500403)
316 /// .expect("Failed to create NV index tpm handle");
317 /// #
318 /// # // Create NV index attributes
319 /// # let owner_nv_index_attributes = NvIndexAttributes::builder()
320 /// # .with_owner_write(true)
321 /// # .with_owner_read(true)
322 /// # .build()
323 /// # .expect("Failed to create owner nv index attributes");
324 /// #
325 /// # // Create owner nv public.
326 /// # let owner_nv_public = NvPublic::builder()
327 /// # .with_nv_index(nv_index)
328 /// # .with_index_name_algorithm(HashingAlgorithm::Sha256)
329 /// # .with_index_attributes(owner_nv_index_attributes)
330 /// # .with_data_area_size(32)
331 /// # .build()
332 /// # .expect("Failed to build NvPublic for owner");
333 /// #
334 /// # // Define the NV space.
335 /// # let nv_index_handle = context
336 /// # .nv_define_space(Provision::Owner, None, owner_nv_public)
337 /// # .expect("Call to nv_define_space failed");
338 /// #
339 /// # // Close the handle (remove all the metadata).
340 /// # let mut handle_to_be_closed = nv_index_handle.into();
341 /// let tr_close_result = context
342 /// .tr_close(&mut handle_to_be_closed);
343 /// #
344 /// # // Use the retrieved handle to get the name of the object.
345 /// # let tr_get_name_result = context
346 /// # .tr_get_name(nv_index_handle.into());
347 /// #
348 /// # // Call function without session (session can be provided in order to
349 /// # // verify that the public data read actually originates from this TPM).
350 /// # let retrieved_handle = context.execute_without_session(|ctx| {
351 /// # ctx.tr_from_tpm_public(nv_index.into())
352 /// # })
353 /// # .expect("Call to tr_from_tpm_public failed.");
354 /// #
355 /// # context
356 /// # .nv_undefine_space(Provision::Owner, retrieved_handle.into())
357 /// # .expect("Call to nv_undefine_space failed");
358 /// #
359 /// // Process results.
360 /// tr_close_result.expect("Call to tr_close failed.");
361 /// # tr_get_name_result.expect_err("Calling tr_get_name with invalid handle did not result in an error.");
362 /// ```
363 pub fn tr_close(&mut self, object_handle: &mut ObjectHandle) -> Result<()> {
364 let mut rsrc_handle = object_handle.try_into_not_none()?;
365 ReturnCode::ensure_success(
366 unsafe { Esys_TR_Close(self.mut_context(), &mut rsrc_handle) },
367 |ret| {
368 error!("Error when closing an ESYS handle: {:#010X}", ret);
369 },
370 )?;
371
372 self.handle_manager.set_as_closed(*object_handle)?;
373 *object_handle = ObjectHandle::from(rsrc_handle);
374 Ok(())
375 }
376
377 #[cfg(has_esys_tr_get_tpm_handle)]
378 /// Retrieve the `TpmHandle` stored in the given object.
379 pub fn tr_get_tpm_handle(&mut self, object_handle: ObjectHandle) -> Result<TpmHandle> {
380 use crate::tss2_esys::Esys_TR_GetTpmHandle;
381 let mut tpm_handle = TPM2_RH_UNASSIGNED;
382 ReturnCode::ensure_success(
383 unsafe {
384 Esys_TR_GetTpmHandle(self.mut_context(), object_handle.into(), &mut tpm_handle)
385 },
386 |ret| {
387 error!(
388 "Error when getting TPM handle from ESYS handle: {:#010X}",
389 ret
390 );
391 },
392 )?;
393 TpmHandle::try_from(tpm_handle)
394 }
395
396 /// Serialize the metadata of the object identified by `handle` into a new buffer.
397 ///
398 /// This can subsequently be used to recreate the object in the future.
399 /// The object can only be recreated in a new context, if it was made persistent
400 /// with `evict_control`.
401 ///
402 /// # Arguments
403 /// * `handle` - A handle to the object which should be serialized.
404 ///
405 /// # Returns
406 /// A buffer that can be stored and later deserialized.
407 ///
408 /// # Errors
409 /// * if the TPM cannot serialize the handle, a TSS error is returned.
410 /// * if the buffer length cannot be converted to a `usize`, an `InvalidParam`
411 /// wrapper error is returned.
412 ///
413 /// ```rust
414 /// # use tss_esapi::{
415 /// # Context, TctiNameConf,
416 /// # interface_types::reserved_handles::Hierarchy,
417 /// # structures::HashScheme,
418 /// # utils::create_unrestricted_signing_ecc_public,
419 /// # interface_types::{
420 /// # ecc::EccCurve,
421 /// # algorithm::HashingAlgorithm,
422 /// # session_handles::AuthSession,
423 /// # },
424 /// # structures::EccScheme,
425 /// # };
426 /// # let mut context =
427 /// # Context::new(
428 /// # TctiNameConf::from_environment_variable().expect("Failed to get TCTI"),
429 /// # ).expect("Failed to create Context");
430 /// # context.set_sessions((Some(AuthSession::Password), None, None));
431 /// # let public = create_unrestricted_signing_ecc_public(
432 /// # EccScheme::EcDsa(HashScheme::new(HashingAlgorithm::Sha256)),
433 /// # EccCurve::NistP256)
434 /// # .unwrap();
435 /// let key_handle = context
436 /// .create_primary(
437 /// Hierarchy::Owner,
438 /// public,
439 /// None,
440 /// None,
441 /// None,
442 /// None,
443 /// ).unwrap()
444 /// .key_handle;
445 /// let data = context.tr_serialize(key_handle.into()).unwrap();
446 /// ```
447 pub fn tr_serialize(&mut self, handle: ObjectHandle) -> Result<Vec<u8>> {
448 let mut len = 0;
449 let mut buffer: *mut u8 = null_mut();
450 ReturnCode::ensure_success(
451 unsafe { Esys_TR_Serialize(self.mut_context(), handle.into(), &mut buffer, &mut len) },
452 |ret| {
453 error!("Error while serializing handle: {}", ret);
454 },
455 )?;
456 Ok(to_owned_bytes(
457 buffer,
458 len.try_into().map_err(|e| {
459 error!("Failed to convert buffer len to usize: {}", e);
460 Error::local_error(WrapperErrorKind::InvalidParam)
461 })?,
462 ))
463 }
464
465 /// Deserialize the metadata from `buffer` into a new object.
466 ///
467 /// This can be used to restore an object from a context in the past.
468 ///
469 /// # Arguments
470 /// * `buffer` - The buffer containing the data to restore the object.
471 /// It can be created using [`tr_serialize`](Self::tr_serialize).
472 ///
473 /// # Returns
474 /// A handle to the object that was created from the buffer.
475 ///
476 /// # Errors
477 /// * if the TPM cannot deserialize the buffer, a TSS error is returned.
478 /// * if the buffer length cannot be converted to a `usize`, an `InvalidParam`
479 /// wrapper error is returned.
480 ///
481 /// ```rust
482 /// # use tss_esapi::{
483 /// # Context, TctiNameConf,
484 /// # interface_types::reserved_handles::Hierarchy,
485 /// # structures::HashScheme,
486 /// # utils::create_unrestricted_signing_ecc_public,
487 /// # interface_types::{
488 /// # ecc::EccCurve,
489 /// # algorithm::HashingAlgorithm,
490 /// # session_handles::AuthSession,
491 /// # },
492 /// # structures::EccScheme,
493 /// # };
494 /// # let mut context =
495 /// # Context::new(
496 /// # TctiNameConf::from_environment_variable().expect("Failed to get TCTI"),
497 /// # ).expect("Failed to create Context");
498 /// # context.set_sessions((Some(AuthSession::Password), None, None));
499 /// # let public = create_unrestricted_signing_ecc_public(
500 /// # EccScheme::EcDsa(HashScheme::new(HashingAlgorithm::Sha256)),
501 /// # EccCurve::NistP256)
502 /// # .unwrap();
503 /// let key_handle = context
504 /// .create_primary(
505 /// Hierarchy::Owner,
506 /// public,
507 /// None,
508 /// None,
509 /// None,
510 /// None,
511 /// ).unwrap()
512 /// .key_handle;
513 /// # context.set_sessions((None, None, None));
514 /// let public_key = context.read_public(key_handle).unwrap();
515 /// let data = context.tr_serialize(key_handle.into()).unwrap();
516 /// let new_handle = context.tr_deserialize(&data).unwrap();
517 /// assert_eq!(public_key, context.read_public(new_handle.into()).unwrap());
518 /// ```
519 pub fn tr_deserialize(&mut self, buffer: &[u8]) -> Result<ObjectHandle> {
520 let mut handle = TPM2_RH_UNASSIGNED;
521 let size = FfiSizeType::try_from(buffer.len())?;
522 ReturnCode::ensure_success(
523 unsafe {
524 Esys_TR_Deserialize(
525 self.mut_context(),
526 buffer.as_ptr(),
527 size.into(),
528 &mut handle,
529 )
530 },
531 |ret| {
532 error!("Error while deserializing buffer: {}", ret);
533 },
534 )?;
535 Ok(ObjectHandle::from(handle))
536 }
537}