tss_esapi/context/tpm_commands/context_management.rs
1// Copyright 2021 Contributors to the Parsec project.
2// SPDX-License-Identifier: Apache-2.0
3use crate::{
4 context::handle_manager::HandleDropAction,
5 handles::{handle_conversion::TryIntoNotNone, AuthHandle, ObjectHandle, PersistentTpmHandle},
6 interface_types::{dynamic_handles::Persistent, resource_handles::Provision},
7 tss2_esys::{Esys_ContextLoad, Esys_ContextSave, Esys_EvictControl, Esys_FlushContext},
8 utils::TpmsContext,
9 Context, Error, Result,
10};
11use log::error;
12use std::convert::{TryFrom, TryInto};
13use std::ptr::null_mut;
14
15impl Context {
16 /// Save the context of an object from the TPM and return it.
17 ///
18 /// # Errors
19 /// * if conversion from `TPMS_CONTEXT` to `TpmsContext` fails, a `WrongParamSize` error will
20 /// be returned
21 pub fn context_save(&mut self, handle: ObjectHandle) -> Result<TpmsContext> {
22 let mut context_ptr = null_mut();
23 let ret = unsafe { Esys_ContextSave(self.mut_context(), handle.into(), &mut context_ptr) };
24 let ret = Error::from_tss_rc(ret);
25 if ret.is_success() {
26 TpmsContext::try_from(Context::ffi_data_to_owned(context_ptr))
27 } else {
28 error!("Error in saving context: {}", ret);
29 Err(ret)
30 }
31 }
32
33 /// Load a previously saved context into the TPM and return the object handle.
34 ///
35 /// # Errors
36 /// * if conversion from `TpmsContext` to the native `TPMS_CONTEXT` fails, a `WrongParamSize`
37 /// error will be returned
38 pub fn context_load(&mut self, context: TpmsContext) -> Result<ObjectHandle> {
39 let mut loaded_handle = ObjectHandle::None.into();
40 let ret = unsafe {
41 Esys_ContextLoad(self.mut_context(), &context.try_into()?, &mut loaded_handle)
42 };
43 let ret = Error::from_tss_rc(ret);
44 if ret.is_success() {
45 self.handle_manager
46 .add_handle(loaded_handle.into(), HandleDropAction::Flush)?;
47 Ok(loaded_handle.into())
48 } else {
49 error!("Error in loading context: {}", ret);
50 Err(ret)
51 }
52 }
53
54 /// Flush the context of an object from the TPM.
55 ///
56 /// # Example
57 ///
58 /// ```rust
59 /// # use tss_esapi::{
60 /// # Context, tcti_ldr::TctiNameConf, structures::Auth,
61 /// # constants::{
62 /// # tss::{TPMA_SESSION_DECRYPT, TPMA_SESSION_ENCRYPT},
63 /// # SessionType,
64 /// # },
65 /// # interface_types::{
66 /// # resource_handles::Hierarchy,
67 /// # algorithm::{HashingAlgorithm, RsaSchemeAlgorithm},
68 /// # key_bits::RsaKeyBits,
69 /// # },
70 /// # utils::create_unrestricted_signing_rsa_public,
71 /// # attributes::SessionAttributesBuilder,
72 /// # structures::{SymmetricDefinition, RsaExponent, RsaScheme},
73 /// # };
74 /// # use std::convert::TryFrom;
75 /// # use std::str::FromStr;
76 /// # // Create context
77 /// # let mut context =
78 /// # Context::new(
79 /// # TctiNameConf::from_environment_variable().expect("Failed to get TCTI"),
80 /// # ).expect("Failed to create Context");
81 ///
82 /// // Create session for a key
83 /// let session = context
84 /// .start_auth_session(
85 /// None,
86 /// None,
87 /// None,
88 /// SessionType::Hmac,
89 /// SymmetricDefinition::AES_256_CFB,
90 /// HashingAlgorithm::Sha256,
91 /// )
92 /// .expect("Failed to create session")
93 /// .expect("Received invalid handle");
94 /// let (session_attributes, session_attributes_mask) = SessionAttributesBuilder::new()
95 /// .with_decrypt(true)
96 /// .with_encrypt(true)
97 /// .build();
98 /// context.tr_sess_set_attributes(session, session_attributes, session_attributes_mask)
99 /// .expect("Failed to set attributes on session");
100 ///
101 /// // Create public area for a rsa key
102 /// let public_area = create_unrestricted_signing_rsa_public(
103 /// RsaScheme::create(RsaSchemeAlgorithm::RsaSsa, Some(HashingAlgorithm::Sha256))
104 /// .expect("Failed to create RSA scheme"),
105 /// RsaKeyBits::Rsa2048,
106 /// RsaExponent::default(),
107 /// )
108 /// .expect("Failed to create rsa public area");
109 ///
110 /// // Execute context methods using the session
111 /// context.execute_with_session(Some(session), |ctx| {
112 /// let mut random_digest = vec![0u8; 16];
113 /// getrandom::getrandom(&mut random_digest).expect("Call to getrandom failed");
114 /// let key_auth = Auth::try_from(random_digest).expect("Failed to create Auth");
115 /// let key_handle = ctx
116 /// .create_primary(
117 /// Hierarchy::Owner,
118 /// public_area,
119 /// Some(key_auth),
120 /// None,
121 /// None,
122 /// None,
123 /// )
124 /// .expect("Failed to create primary key")
125 /// .key_handle;
126 ///
127 /// // Flush the context of the key.
128 /// ctx.flush_context(key_handle.into()).expect("Call to flush_context failed");
129 /// assert!(ctx.read_public(key_handle).is_err());
130 /// })
131 /// ```
132 pub fn flush_context(&mut self, handle: ObjectHandle) -> Result<()> {
133 let ret = unsafe { Esys_FlushContext(self.mut_context(), handle.try_into_not_none()?) };
134 let ret = Error::from_tss_rc(ret);
135 if ret.is_success() {
136 self.handle_manager.set_as_flushed(handle)?;
137 Ok(())
138 } else {
139 error!("Error in flushing context: {}", ret);
140 Err(ret)
141 }
142 }
143
144 /// Evicts persistent objects or allows certain transient objects
145 /// to be made persistent.
146 ///
147 /// # Details
148 /// In order to be able to perform this action an authorization
149 /// session is required.
150 ///
151 /// # Arguments
152 /// * `auth` - An a handle used for authorization that is limited to the ones
153 /// specified in [Provision].
154 /// * `object_handle` - The handle of a loaded object.
155 /// * `persistent` - If the `object_handle` is transient object then this
156 /// then this will become the persistent handle of that
157 /// object. If the `object_handle` refers to a persistent
158 /// object then this shall be the persistent handle of that
159 /// object.
160 ///
161 /// # Returns
162 /// If the input `object_handle` was transient object then it will be made
163 /// persistent and the returned [ObjectHandle] will refer to the persistent
164 /// object.
165 ///
166 /// If the input `object_handle` refers to a persistent object the returned
167 /// value will be ObjectHandle::None and the input `object_handle` will not
168 /// be valid after this call is made.
169 ///
170 /// # Example
171 ///
172 /// Make transient object persistent:
173 /// ```rust
174 /// # use tss_esapi::{
175 /// # Context, tcti_ldr::TctiNameConf, Result,
176 /// # constants::{
177 /// # SessionType, CapabilityType,
178 /// # tss::TPM2_PERSISTENT_FIRST,
179 /// # },
180 /// # handles::PcrHandle,
181 /// # structures::{Digest, CapabilityData, Auth, RsaExponent, SymmetricDefinitionObject},
182 /// # interface_types::{
183 /// # resource_handles::Hierarchy,
184 /// # key_bits::RsaKeyBits,
185 /// # },
186 /// # handles::{ObjectHandle, TpmHandle, PersistentTpmHandle},
187 /// # utils::create_restricted_decryption_rsa_public,
188 /// # tss2_esys::TPM2_HANDLE,
189 /// # };
190 /// # use std::{env, str::FromStr, convert::TryFrom};
191 /// # // Create context
192 /// # let mut context =
193 /// # Context::new(
194 /// # TctiNameConf::from_environment_variable().expect("Failed to get TCTI"),
195 /// # ).expect("Failed to create Context");
196 /// # // Create persistent TPM handle with
197 /// # let persistent_tpm_handle =
198 /// # PersistentTpmHandle::new(u32::from_be_bytes([0x81, 0x00, 0x00, 0x01]))
199 /// # .expect("Failed to create Persistent TPM handle");
200 /// # // -----> REMOVE ANY PREVIOUS HANDLES <---------------
201 /// # let mut property = TPM2_PERSISTENT_FIRST;
202 /// # while let Ok((capability_data, more_data_available)) =
203 /// # context.get_capability(CapabilityType::Handles, property, 1)
204 /// # {
205 /// # if let CapabilityData::Handles(persistent_handles) = capability_data {
206 /// # if let Some(&retrieved_persistent_handle) = persistent_handles.first() {
207 /// # if retrieved_persistent_handle == persistent_tpm_handle.into() {
208 /// # let handle = context
209 /// # .tr_from_tpm_public(TpmHandle::Persistent(persistent_tpm_handle))
210 /// # .expect("Failed to retrieve handle from TPM");
211 /// # context.execute_with_session(Some(tss_esapi::interface_types::session_handles::AuthSession::Password), |ctx| {
212 /// # ctx
213 /// # .evict_control(
214 /// # tss_esapi::interface_types::resource_handles::Provision::Owner,
215 /// # handle,
216 /// # tss_esapi::interface_types::dynamic_handles::Persistent::Persistent(persistent_tpm_handle),
217 /// # )
218 /// # .expect("Failed to evict persitent handle")
219 /// # });
220 /// # break;
221 /// # }
222 /// # if more_data_available {
223 /// # property = TPM2_HANDLE::from(retrieved_persistent_handle) + 1;
224 /// # }
225 /// # }
226 /// # }
227 /// # if !more_data_available {
228 /// # break;
229 /// # }
230 /// # }
231 /// # let transient_object_handle = context.execute_with_session(Some(tss_esapi::interface_types::session_handles::AuthSession::Password), |ctx| {
232 /// # // Create primary key handle
233 /// # let auth_value_primary = Auth::try_from(vec![1, 2, 3, 4, 5])
234 /// # .expect("Failed to crate auth value for primary key");
235 /// # ctx
236 /// # .create_primary(
237 /// # Hierarchy::Owner,
238 /// # create_restricted_decryption_rsa_public(
239 /// # SymmetricDefinitionObject::AES_256_CFB,
240 /// # RsaKeyBits::Rsa2048,
241 /// # RsaExponent::default(),
242 /// # ).expect("Failed to Public structure for key"),
243 /// # Some(auth_value_primary),
244 /// # None,
245 /// # None,
246 /// # None,
247 /// # )
248 /// # .map(|v| ObjectHandle::from(v.key_handle))
249 /// # .expect("Failed to create primary key")
250 /// # });
251 /// use tss_esapi::{
252 /// interface_types::{
253 /// resource_handles::Provision,
254 /// dynamic_handles::Persistent,
255 /// session_handles::AuthSession,
256 /// },
257 /// };
258 /// // Create interface type Persistent by using the persistent tpm handle.
259 /// let persistent = Persistent::Persistent(persistent_tpm_handle);
260 /// // Make transient_object_handle persistent.
261 /// // An authorization session is required!
262 /// let mut persistent_object_handle = context.execute_with_session(Some(AuthSession::Password), |ctx| {
263 /// ctx
264 /// .evict_control(Provision::Owner, transient_object_handle.into(), persistent)
265 /// .expect("Failed to make the transient_object_handle handle persistent")
266 /// });
267 /// # assert_ne!(persistent_object_handle, ObjectHandle::Null);
268 /// # assert_ne!(persistent_object_handle, ObjectHandle::None);
269 /// # // Flush out the transient_object_handle
270 /// # context
271 /// # .flush_context(ObjectHandle::from(transient_object_handle))
272 /// # .expect("Failed to flush context");
273 /// # // Close the persistent_handle returned by evict_control
274 /// # context
275 /// # .tr_close(&mut persistent_object_handle)
276 /// # .expect("Failed to close persistent handle");
277 /// # // Retrieve the handle from the tpm again.
278 /// # let retireved_persistent_handle = context.execute_without_session(|ctx| {
279 /// # ctx.tr_from_tpm_public(TpmHandle::Persistent(persistent_tpm_handle))
280 /// # .expect("Failed to load the persistent handle")
281 /// # });
282 /// # // Evict the persitent handle from the tpm
283 /// # let _ = context.execute_with_session(Some(AuthSession::Password), |ctx| {
284 /// # ctx
285 /// # .evict_control(Provision::Owner, retireved_persistent_handle, persistent)
286 /// # .expect("Failed to evict persistent handle")
287 /// # });
288 /// # assert_ne!(retireved_persistent_handle, ObjectHandle::None);
289 /// ```
290 ///
291 /// Make persistent object transient
292 /// ```rust
293 /// # use tss_esapi::{
294 /// # Context, tcti_ldr::TctiNameConf, Result,
295 /// # constants::{
296 /// # SessionType, CapabilityType,
297 /// # tss::TPM2_PERSISTENT_FIRST,
298 /// # },
299 /// # handles::PcrHandle,
300 /// # structures::{Digest, CapabilityData, Auth, RsaExponent, SymmetricDefinitionObject},
301 /// # interface_types::{
302 /// # resource_handles::Hierarchy,
303 /// # key_bits::RsaKeyBits,
304 /// # },
305 /// # handles::{ObjectHandle, TpmHandle, PersistentTpmHandle},
306 /// # utils::create_restricted_decryption_rsa_public,
307 /// # tss2_esys::TPM2_HANDLE,
308 /// # };
309 /// # use std::{env, str::FromStr, convert::TryFrom};
310 /// # // Create context
311 /// # let mut context =
312 /// # Context::new(
313 /// # TctiNameConf::from_environment_variable().expect("Failed to get TCTI"),
314 /// # ).expect("Failed to create Context");
315 /// # // Create persistent TPM handle with
316 /// # let persistent_tpm_handle =
317 /// # PersistentTpmHandle::new(u32::from_be_bytes([0x81, 0x00, 0x00, 0x01]))
318 /// # .expect("Failed to create Persistent TPM handle");
319 /// # // -----> REMOVE ANY PREVIOUS HANDLES <---------------
320 /// # let mut property = TPM2_PERSISTENT_FIRST;
321 /// # while let Ok((capability_data, more_data_available)) =
322 /// # context.get_capability(CapabilityType::Handles, property, 1)
323 /// # {
324 /// # if let CapabilityData::Handles(persistent_handles) = capability_data {
325 /// # if let Some(&retrieved_persistent_handle) = persistent_handles.first() {
326 /// # if retrieved_persistent_handle == persistent_tpm_handle.into() {
327 /// # let handle = context
328 /// # .tr_from_tpm_public(TpmHandle::Persistent(persistent_tpm_handle))
329 /// # .expect("Failed to retrieve handle from TPM");
330 /// # context.execute_with_session(Some(tss_esapi::interface_types::session_handles::AuthSession::Password), |ctx| {
331 /// # ctx
332 /// # .evict_control(
333 /// # tss_esapi::interface_types::resource_handles::Provision::Owner,
334 /// # handle,
335 /// # tss_esapi::interface_types::dynamic_handles::Persistent::Persistent(persistent_tpm_handle),
336 /// # )
337 /// # .expect("Failed to evict persitent handle")
338 /// # });
339 /// # break;
340 /// # }
341 /// # if more_data_available {
342 /// # property = TPM2_HANDLE::from(retrieved_persistent_handle) + 1;
343 /// # }
344 /// # }
345 /// # }
346 /// # if !more_data_available {
347 /// # break;
348 /// # }
349 /// # }
350 /// # let transient_object_handle = context.execute_with_session(Some(tss_esapi::interface_types::session_handles::AuthSession::Password), |ctx| {
351 /// # // Create primary key handle
352 /// # let auth_value_primary = Auth::try_from(vec![1, 2, 3, 4, 5])
353 /// # .expect("Failed to crate auth value for primary key");
354 /// # ctx
355 /// # .create_primary(
356 /// # Hierarchy::Owner,
357 /// # create_restricted_decryption_rsa_public(
358 /// # SymmetricDefinitionObject::AES_256_CFB,
359 /// # RsaKeyBits::Rsa2048,
360 /// # RsaExponent::default(),
361 /// # ).expect("Failed to Public structure for key"),
362 /// # Some(auth_value_primary),
363 /// # None,
364 /// # None,
365 /// # None,
366 /// # )
367 /// # .map(|v| ObjectHandle::from(v.key_handle))
368 /// # .expect("Failed to create primary key")
369 /// # });
370 /// use tss_esapi::{
371 /// interface_types::{
372 /// resource_handles::Provision,
373 /// dynamic_handles::Persistent,
374 /// session_handles::AuthSession,
375 /// },
376 /// };
377 /// // Create interface type Persistent by using the persistent tpm handle.
378 /// let persistent = Persistent::Persistent(persistent_tpm_handle);
379 /// # // Evict control to make transient_object_handle persistent.
380 /// # // An authorization session is required!
381 /// # let mut persistent_object_handle = context.execute_with_session(Some(AuthSession::Password), |ctx| {
382 /// # ctx
383 /// # .evict_control(Provision::Owner, transient_object_handle.into(), persistent)
384 /// # .expect("Failed to make the transient_object_handle handle persistent")
385 /// # });
386 /// # assert_ne!(persistent_object_handle, ObjectHandle::Null);
387 /// # assert_ne!(persistent_object_handle, ObjectHandle::None);
388 /// # // Flush out the transient_object_handle
389 /// # context
390 /// # .flush_context(ObjectHandle::from(transient_object_handle))
391 /// # .expect("Failed to flush context");
392 /// # // Close the persistent_handle returned by evict_control
393 /// # context
394 /// # .tr_close(&mut persistent_object_handle)
395 /// # .expect("Failed to close persistent handle");
396 /// # // Retrieve the handle from the tpm again.
397 /// # let retrieved_persistent_handle = context.execute_without_session(|ctx| {
398 /// # ctx.tr_from_tpm_public(TpmHandle::Persistent(persistent_tpm_handle))
399 /// # .expect("Failed to load the persistent handle")
400 /// # });
401 /// // Evict the persitent handle from the tpm
402 /// // An authorization session is required!
403 /// let _ = context.execute_with_session(Some(AuthSession::Password), |ctx| {
404 /// ctx
405 /// .evict_control(Provision::Owner, retrieved_persistent_handle, persistent)
406 /// .expect("Failed to evict persistent handle")
407 /// });
408 /// # assert_ne!(retrieved_persistent_handle, ObjectHandle::None);
409 /// ```
410 pub fn evict_control(
411 &mut self,
412 auth: Provision,
413 object_handle: ObjectHandle,
414 persistent: Persistent,
415 ) -> Result<ObjectHandle> {
416 let mut new_object_handle = ObjectHandle::None.into();
417 let ret = unsafe {
418 Esys_EvictControl(
419 self.mut_context(),
420 AuthHandle::from(auth).into(),
421 object_handle.into(),
422 self.required_session_1()?,
423 self.optional_session_2(),
424 self.optional_session_3(),
425 PersistentTpmHandle::from(persistent).into(),
426 &mut new_object_handle,
427 )
428 };
429 let ret = Error::from_tss_rc(ret);
430 if ret.is_success() {
431 let new_object_handle = ObjectHandle::from(new_object_handle);
432 // If you look at the specification and see that it says ESYS_TR_NULL
433 // then that is an error in the spec. ESYS_TR_NULL was renamed to
434 // ESYS_TR NONE.
435 if new_object_handle.is_none() {
436 self.handle_manager.set_as_closed(object_handle)?;
437 } else {
438 self.handle_manager
439 .add_handle(new_object_handle, HandleDropAction::Close)?;
440 }
441 Ok(new_object_handle)
442 } else {
443 error!("Error in evict control: {}", ret);
444 Err(ret)
445 }
446 }
447}