tss_esapi/context/tpm_commands/object_commands.rs
1// Copyright 2021 Contributors to the Parsec project.
2// SPDX-License-Identifier: Apache-2.0
3mod create_command_input;
4mod create_command_output;
5
6use crate::{
7 context::handle_manager::HandleDropAction,
8 handles::{KeyHandle, ObjectHandle, TpmHandle},
9 interface_types::reserved_handles::Hierarchy,
10 structures::{
11 Auth, CreateKeyResult, Data, Digest, EncryptedSecret, IdObject, Name, PcrSelectionList,
12 Private, Public, Sensitive, SensitiveData,
13 },
14 tss2_esys::{
15 Esys_ActivateCredential, Esys_Create, Esys_Load, Esys_LoadExternal, Esys_MakeCredential,
16 Esys_ObjectChangeAuth, Esys_ReadPublic, Esys_Unseal,
17 },
18 Context, Error, Result, ReturnCode, WrapperErrorKind,
19};
20use create_command_input::CreateCommandInputHandler;
21use create_command_output::CreateCommandOutputHandler;
22use log::error;
23use std::convert::{TryFrom, TryInto};
24use std::ptr::{null, null_mut};
25
26impl Context {
27 /// Create a key and return the handle.
28 ///
29 /// The authentication value, initial data, outside info and creation PCRs are passed as slices
30 /// which are then converted by the method into TSS native structures.
31 ///
32 /// # Parameters
33 /// * `parent_handle` - The [KeyHandle] of the parent for the new object that is being created.
34 /// * `public` - The public part of the object that is being created.
35 /// * `auth_value` - The value used to be used for authorize usage of the object.
36 /// * `sensitive_data` - The data that is to be sealed, a key or derivation values.
37 /// * `outside_info` - Data that will be included in the creation data for this
38 /// object to provide permanent, verifiable linkage between the object
39 /// that is being created and some object owner data.
40 /// * `creation_pcrs`- PCRs that will be used in creation data.
41 ///
42 /// # Errors
43 /// * if either of the slices is larger than the maximum size of the native objects, a
44 /// `WrongParamSize` wrapper error is returned
45 // TODO: Fix when compacting the arguments into a struct
46 #[allow(clippy::too_many_arguments)]
47 pub fn create(
48 &mut self,
49 parent_handle: KeyHandle,
50 public: Public,
51 auth_value: Option<Auth>,
52 sensitive_data: Option<SensitiveData>,
53 outside_info: Option<Data>,
54 creation_pcrs: Option<PcrSelectionList>,
55 ) -> Result<CreateKeyResult> {
56 let input_parameters = CreateCommandInputHandler::create(
57 parent_handle,
58 public,
59 auth_value,
60 sensitive_data,
61 outside_info,
62 creation_pcrs,
63 )?;
64
65 let mut output_parameters = CreateCommandOutputHandler::new();
66
67 ReturnCode::ensure_success(
68 unsafe {
69 Esys_Create(
70 self.mut_context(),
71 input_parameters.ffi_in_parent_handle(),
72 self.optional_session_1(),
73 self.optional_session_2(),
74 self.optional_session_3(),
75 input_parameters.ffi_in_sensitive(),
76 input_parameters.ffi_in_public(),
77 input_parameters.ffi_outside_info(),
78 input_parameters.ffi_creation_pcr(),
79 output_parameters.ffi_out_private_ptr(),
80 output_parameters.ffi_out_public_ptr(),
81 output_parameters.ffi_creation_data_ptr(),
82 output_parameters.ffi_creation_hash_ptr(),
83 output_parameters.ffi_creation_ticket_ptr(),
84 )
85 },
86 |ret| {
87 error!("Error in creating derived key: {:#010X}", ret);
88 },
89 )?;
90
91 output_parameters.try_into()
92 }
93
94 /// Load a previously generated key back into the TPM and return its new handle.
95 pub fn load(
96 &mut self,
97 parent_handle: KeyHandle,
98 private: Private,
99 public: Public,
100 ) -> Result<KeyHandle> {
101 let mut object_handle = ObjectHandle::None.into();
102 ReturnCode::ensure_success(
103 unsafe {
104 Esys_Load(
105 self.mut_context(),
106 parent_handle.into(),
107 self.optional_session_1(),
108 self.optional_session_2(),
109 self.optional_session_3(),
110 &private.into(),
111 &public.try_into()?,
112 &mut object_handle,
113 )
114 },
115 |ret| {
116 error!("Error in loading: {:#010X}", ret);
117 },
118 )?;
119 let key_handle = KeyHandle::from(object_handle);
120 self.handle_manager
121 .add_handle(key_handle.into(), HandleDropAction::Flush)?;
122 Ok(key_handle)
123 }
124
125 /// Load an external key into the TPM and return its new handle.
126 ///
127 /// # Details
128 /// This command is used to load an object that is not a Protected Object into the TPM. The command allows
129 /// loading of a public area or both a public and sensitive area.
130 ///
131 /// # Arguments
132 /// * `private` - The optional sensitive portion of the object.
133 /// * `public` - The public portion of the object.
134 /// * `hierarchy` - The hierarchy with which the object area is associated.
135 ///
136 /// # Returns
137 /// The handle to the loaded key.
138 ///
139 /// # Example
140 ///
141 /// ```rust
142 /// # use tss_esapi::{
143 /// # Context, TctiNameConf,
144 /// # attributes::ObjectAttributesBuilder,
145 /// # constants::SessionType,
146 /// # interface_types::{
147 /// # algorithm::{HashingAlgorithm, PublicAlgorithm, RsaSchemeAlgorithm},
148 /// # key_bits::RsaKeyBits,
149 /// # reserved_handles::Hierarchy,
150 /// # },
151 /// # structures::{
152 /// # Public, PublicBuilder, PublicKeyRsa, PublicRsaParametersBuilder, RsaScheme,
153 /// # SymmetricDefinition,
154 /// # },
155 /// # };
156 /// #
157 /// # const KEY: [u8; 256] = [
158 /// # 231, 97, 201, 180, 0, 1, 185, 150, 85, 90, 174, 188, 105, 133, 188, 3, 206, 5, 222, 71, 185, 1,
159 /// # 209, 243, 36, 130, 250, 116, 17, 0, 24, 4, 25, 225, 250, 198, 245, 210, 140, 23, 139, 169, 15,
160 /// # 193, 4, 145, 52, 138, 149, 155, 238, 36, 74, 152, 179, 108, 200, 248, 250, 100, 115, 214, 166,
161 /// # 165, 1, 27, 51, 11, 11, 244, 218, 157, 3, 174, 171, 142, 45, 8, 9, 36, 202, 171, 165, 43, 208,
162 /// # 186, 232, 15, 241, 95, 81, 174, 189, 30, 213, 47, 86, 115, 239, 49, 214, 235, 151, 9, 189, 174,
163 /// # 144, 238, 200, 201, 241, 157, 43, 37, 6, 96, 94, 152, 159, 205, 54, 9, 181, 14, 35, 246, 49,
164 /// # 150, 163, 118, 242, 59, 54, 42, 221, 215, 248, 23, 18, 223, 179, 229, 0, 204, 65, 69, 166, 180,
165 /// # 11, 49, 131, 96, 163, 96, 158, 7, 109, 119, 208, 17, 237, 125, 187, 121, 94, 65, 2, 86, 105,
166 /// # 68, 51, 197, 73, 108, 185, 231, 126, 199, 81, 1, 251, 211, 45, 47, 15, 113, 135, 197, 152, 239,
167 /// # 180, 111, 18, 192, 136, 222, 11, 99, 41, 248, 205, 253, 209, 56, 214, 32, 225, 3, 49, 161, 58,
168 /// # 57, 190, 69, 86, 95, 185, 184, 155, 76, 8, 122, 104, 81, 222, 234, 246, 40, 98, 182, 90, 160,
169 /// # 111, 74, 102, 36, 148, 99, 69, 207, 214, 104, 87, 128, 238, 26, 121, 107, 166, 4, 64, 5, 210,
170 /// # 164, 162, 189,
171 /// # ];
172 /// #
173 /// # // Create context
174 /// # let mut context =
175 /// # Context::new(
176 /// # TctiNameConf::from_environment_variable().expect("Failed to get TCTI"),
177 /// # ).expect("Failed to create Context");
178 /// #
179 /// # let session = context
180 /// # .start_auth_session(
181 /// # None,
182 /// # None,
183 /// # None,
184 /// # SessionType::Hmac,
185 /// # SymmetricDefinition::AES_256_CFB,
186 /// # tss_esapi::interface_types::algorithm::HashingAlgorithm::Sha256,
187 /// # )
188 /// # .expect("Failed to create session")
189 /// # .expect("Received invalid handle");
190 /// #
191 /// let object_attributes = ObjectAttributesBuilder::new()
192 /// .with_user_with_auth(true)
193 /// .with_decrypt(false)
194 /// .with_sign_encrypt(true)
195 /// .with_restricted(false)
196 /// .build()
197 /// .expect("Failed to build object attributes");
198 ///
199 /// let public = PublicBuilder::new()
200 /// .with_public_algorithm(PublicAlgorithm::Rsa)
201 /// .with_name_hashing_algorithm(HashingAlgorithm::Sha256)
202 /// .with_object_attributes(object_attributes)
203 /// .with_rsa_parameters(
204 /// PublicRsaParametersBuilder::new_unrestricted_signing_key(
205 /// RsaScheme::create(RsaSchemeAlgorithm::RsaSsa, Some(HashingAlgorithm::Sha256))
206 /// .expect("Failed to create rsa scheme"),
207 /// RsaKeyBits::Rsa2048,
208 /// Default::default(),
209 /// )
210 /// .build()
211 /// .expect("Failed to create rsa parameters for public structure"),
212 /// )
213 /// .with_rsa_unique_identifier(
214 /// PublicKeyRsa::from_bytes(&KEY[..256])
215 /// .expect("Failed to create Public RSA key from buffer"),
216 /// )
217 /// .build()
218 /// .expect("Failed to build Public structure");
219 ///
220 /// // Load public key into Owner hierarchy.
221 /// let key_handle = context.load_external(None, public, Hierarchy::Owner)
222 /// .expect("The load_external should have returned a valid key handle.");
223 /// ```
224 pub fn load_external(
225 &mut self,
226 private: impl Into<Option<Sensitive>>,
227 public: Public,
228 hierarchy: Hierarchy,
229 ) -> Result<KeyHandle> {
230 let potential_private = private.into();
231 if (hierarchy != Hierarchy::Null) && potential_private.is_some() {
232 error!("Only NULL hierarchy is valid in load_external when loading both private and public part.");
233 return Err(Error::local_error(WrapperErrorKind::InvalidParam));
234 }
235 let mut object_handle = ObjectHandle::None.into();
236 let potential_private_in = potential_private.map(|v| v.try_into()).transpose()?;
237 let private_in_ptr = potential_private_in
238 .as_ref()
239 .map_or_else(null, std::ptr::from_ref);
240 let public_in = public.try_into()?;
241 ReturnCode::ensure_success(
242 unsafe {
243 Esys_LoadExternal(
244 self.mut_context(),
245 self.optional_session_1(),
246 self.optional_session_2(),
247 self.optional_session_3(),
248 private_in_ptr,
249 &public_in,
250 if cfg!(hierarchy_is_esys_tr) {
251 ObjectHandle::from(hierarchy).into()
252 } else {
253 TpmHandle::from(hierarchy).into()
254 },
255 &mut object_handle,
256 )
257 },
258 |ret| {
259 error!("Error in loading external object: {:#010X}", ret);
260 },
261 )?;
262
263 let key_handle = KeyHandle::from(object_handle);
264 self.handle_manager
265 .add_handle(key_handle.into(), HandleDropAction::Flush)?;
266 Ok(key_handle)
267 }
268
269 /// Read the public part of a key currently in the TPM and return it.
270 pub fn read_public(&mut self, key_handle: KeyHandle) -> Result<(Public, Name, Name)> {
271 let mut out_public_ptr = null_mut();
272 let mut name_ptr = null_mut();
273 let mut qualified_name_ptr = null_mut();
274 ReturnCode::ensure_success(
275 unsafe {
276 Esys_ReadPublic(
277 self.mut_context(),
278 key_handle.into(),
279 self.optional_session_1(),
280 self.optional_session_2(),
281 self.optional_session_3(),
282 &mut out_public_ptr,
283 &mut name_ptr,
284 &mut qualified_name_ptr,
285 )
286 },
287 |ret| {
288 error!("Error in reading public part of object: {:#010X}", ret);
289 },
290 )?;
291 Ok((
292 Public::try_from(Context::ffi_data_to_owned(out_public_ptr)?)?,
293 Name::try_from(Context::ffi_data_to_owned(name_ptr)?)?,
294 Name::try_from(Context::ffi_data_to_owned(qualified_name_ptr)?)?,
295 ))
296 }
297
298 /// Activates a credential in a way that ensures parameters are validated.
299 pub fn activate_credential(
300 &mut self,
301 activate_handle: KeyHandle,
302 key_handle: KeyHandle,
303 credential_blob: IdObject,
304 secret: EncryptedSecret,
305 ) -> Result<Digest> {
306 let mut cert_info_ptr = null_mut();
307 ReturnCode::ensure_success(
308 unsafe {
309 Esys_ActivateCredential(
310 self.mut_context(),
311 activate_handle.into(),
312 key_handle.into(),
313 self.required_session_1()?,
314 self.required_session_2()?,
315 self.optional_session_3(),
316 &credential_blob.into(),
317 &secret.into(),
318 &mut cert_info_ptr,
319 )
320 },
321 |ret| {
322 error!("Error when activating credential: {:#010X}", ret);
323 },
324 )?;
325
326 Digest::try_from(Context::ffi_data_to_owned(cert_info_ptr)?)
327 }
328
329 /// Perform actions to create a [IdObject] containing an activation credential.
330 ///
331 /// This does not use any TPM secrets, and is really just a convenience function.
332 pub fn make_credential(
333 &mut self,
334 key_handle: KeyHandle,
335 credential: Digest,
336 object_name: Name,
337 ) -> Result<(IdObject, EncryptedSecret)> {
338 let mut credential_blob_ptr = null_mut();
339 let mut secret_ptr = null_mut();
340 ReturnCode::ensure_success(
341 unsafe {
342 Esys_MakeCredential(
343 self.mut_context(),
344 key_handle.into(),
345 self.optional_session_1(),
346 self.optional_session_2(),
347 self.optional_session_3(),
348 &credential.into(),
349 object_name.as_ref(),
350 &mut credential_blob_ptr,
351 &mut secret_ptr,
352 )
353 },
354 |ret| {
355 error!("Error when making credential: {:#010X}", ret);
356 },
357 )?;
358 Ok((
359 IdObject::try_from(Context::ffi_data_to_owned(credential_blob_ptr)?)?,
360 EncryptedSecret::try_from(Context::ffi_data_to_owned(secret_ptr)?)?,
361 ))
362 }
363
364 /// Unseal and return data from a Sealed Data Object
365 pub fn unseal(&mut self, item_handle: ObjectHandle) -> Result<SensitiveData> {
366 let mut out_data_ptr = null_mut();
367
368 ReturnCode::ensure_success(
369 unsafe {
370 Esys_Unseal(
371 self.mut_context(),
372 item_handle.into(),
373 self.optional_session_1(),
374 self.optional_session_2(),
375 self.optional_session_3(),
376 &mut out_data_ptr,
377 )
378 },
379 |ret| {
380 error!("Error in unsealing: {:#010X}", ret);
381 },
382 )?;
383 SensitiveData::try_from(Context::ffi_data_to_owned(out_data_ptr)?)
384 }
385
386 /// Change authorization for a TPM-resident object.
387 pub fn object_change_auth(
388 &mut self,
389 object_handle: ObjectHandle,
390 parent_handle: ObjectHandle,
391 new_auth: Auth,
392 ) -> Result<Private> {
393 let mut out_private_ptr = null_mut();
394 ReturnCode::ensure_success(
395 unsafe {
396 Esys_ObjectChangeAuth(
397 self.mut_context(),
398 object_handle.into(),
399 parent_handle.into(),
400 self.required_session_1()?,
401 self.optional_session_2(),
402 self.optional_session_3(),
403 &new_auth.into(),
404 &mut out_private_ptr,
405 )
406 },
407 |ret| {
408 error!("Error changing object auth: {:#010X}", ret);
409 },
410 )?;
411 Private::try_from(Context::ffi_data_to_owned(out_private_ptr)?)
412 }
413
414 // Missing function: CreateLoaded
415}