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, Error, Result, ReturnCode, WrapperErrorKind,
8 context::handle_manager::HandleDropAction,
9 handles::{KeyHandle, ObjectHandle, TpmHandle},
10 interface_types::reserved_handles::Hierarchy,
11 structures::{
12 Auth, CreateKeyResult, Data, Digest, EncryptedSecret, IdObject, Name, PcrSelectionList,
13 Private, Public, Sensitive, SensitiveData,
14 },
15 tss2_esys::{
16 Esys_ActivateCredential, Esys_Create, Esys_Load, Esys_LoadExternal, Esys_MakeCredential,
17 Esys_ObjectChangeAuth, Esys_ReadPublic, Esys_Unseal,
18 },
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.required_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.required_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!(
233 "Only NULL hierarchy is valid in load_external when loading both private and public part."
234 );
235 return Err(Error::local_error(WrapperErrorKind::InvalidParam));
236 }
237 let mut object_handle = ObjectHandle::None.into();
238 let potential_private_in = potential_private.map(|v| v.try_into()).transpose()?;
239 let private_in_ptr = potential_private_in
240 .as_ref()
241 .map_or_else(null, std::ptr::from_ref);
242 let public_in = public.try_into()?;
243 ReturnCode::ensure_success(
244 unsafe {
245 Esys_LoadExternal(
246 self.mut_context(),
247 self.optional_session_1(),
248 self.optional_session_2(),
249 self.optional_session_3(),
250 private_in_ptr,
251 &public_in,
252 if cfg!(hierarchy_is_esys_tr) {
253 ObjectHandle::from(hierarchy).into()
254 } else {
255 TpmHandle::from(hierarchy).into()
256 },
257 &mut object_handle,
258 )
259 },
260 |ret| {
261 error!("Error in loading external object: {:#010X}", ret);
262 },
263 )?;
264
265 let key_handle = KeyHandle::from(object_handle);
266 self.handle_manager
267 .add_handle(key_handle.into(), HandleDropAction::Flush)?;
268 Ok(key_handle)
269 }
270
271 /// Read the public part of a key currently in the TPM and return it.
272 pub fn read_public(&mut self, key_handle: KeyHandle) -> Result<(Public, Name, Name)> {
273 let mut out_public_ptr = null_mut();
274 let mut name_ptr = null_mut();
275 let mut qualified_name_ptr = null_mut();
276 ReturnCode::ensure_success(
277 unsafe {
278 Esys_ReadPublic(
279 self.mut_context(),
280 key_handle.into(),
281 self.optional_session_1(),
282 self.optional_session_2(),
283 self.optional_session_3(),
284 &mut out_public_ptr,
285 &mut name_ptr,
286 &mut qualified_name_ptr,
287 )
288 },
289 |ret| {
290 error!("Error in reading public part of object: {:#010X}", ret);
291 },
292 )?;
293 Ok((
294 Public::try_from(Context::ffi_data_to_owned(out_public_ptr)?)?,
295 Name::try_from(Context::ffi_data_to_owned(name_ptr)?)?,
296 Name::try_from(Context::ffi_data_to_owned(qualified_name_ptr)?)?,
297 ))
298 }
299
300 /// Activates a credential in a way that ensures parameters are validated.
301 pub fn activate_credential(
302 &mut self,
303 activate_handle: KeyHandle,
304 key_handle: KeyHandle,
305 credential_blob: IdObject,
306 secret: EncryptedSecret,
307 ) -> Result<Digest> {
308 let mut cert_info_ptr = null_mut();
309 ReturnCode::ensure_success(
310 unsafe {
311 Esys_ActivateCredential(
312 self.mut_context(),
313 activate_handle.into(),
314 key_handle.into(),
315 self.required_session_1()?,
316 self.required_session_2()?,
317 self.optional_session_3(),
318 &credential_blob.into(),
319 &secret.into(),
320 &mut cert_info_ptr,
321 )
322 },
323 |ret| {
324 error!("Error when activating credential: {:#010X}", ret);
325 },
326 )?;
327
328 Digest::try_from(Context::ffi_data_to_owned(cert_info_ptr)?)
329 }
330
331 /// Perform actions to create a [IdObject] containing an activation credential.
332 ///
333 /// This does not use any TPM secrets, and is really just a convenience function.
334 pub fn make_credential(
335 &mut self,
336 key_handle: KeyHandle,
337 credential: Digest,
338 object_name: Name,
339 ) -> Result<(IdObject, EncryptedSecret)> {
340 let mut credential_blob_ptr = null_mut();
341 let mut secret_ptr = null_mut();
342 ReturnCode::ensure_success(
343 unsafe {
344 Esys_MakeCredential(
345 self.mut_context(),
346 key_handle.into(),
347 self.optional_session_1(),
348 self.optional_session_2(),
349 self.optional_session_3(),
350 &credential.into(),
351 object_name.as_ref(),
352 &mut credential_blob_ptr,
353 &mut secret_ptr,
354 )
355 },
356 |ret| {
357 error!("Error when making credential: {:#010X}", ret);
358 },
359 )?;
360 Ok((
361 IdObject::try_from(Context::ffi_data_to_owned(credential_blob_ptr)?)?,
362 EncryptedSecret::try_from(Context::ffi_data_to_owned(secret_ptr)?)?,
363 ))
364 }
365
366 /// Unseal and return data from a Sealed Data Object
367 pub fn unseal(&mut self, item_handle: ObjectHandle) -> Result<SensitiveData> {
368 let mut out_data_ptr = null_mut();
369
370 ReturnCode::ensure_success(
371 unsafe {
372 Esys_Unseal(
373 self.mut_context(),
374 item_handle.into(),
375 self.required_session_1()?,
376 self.optional_session_2(),
377 self.optional_session_3(),
378 &mut out_data_ptr,
379 )
380 },
381 |ret| {
382 error!("Error in unsealing: {:#010X}", ret);
383 },
384 )?;
385 SensitiveData::try_from(Context::ffi_data_to_owned(out_data_ptr)?)
386 }
387
388 /// Change authorization for a TPM-resident object.
389 pub fn object_change_auth(
390 &mut self,
391 object_handle: ObjectHandle,
392 parent_handle: ObjectHandle,
393 new_auth: Auth,
394 ) -> Result<Private> {
395 let mut out_private_ptr = null_mut();
396 ReturnCode::ensure_success(
397 unsafe {
398 Esys_ObjectChangeAuth(
399 self.mut_context(),
400 object_handle.into(),
401 parent_handle.into(),
402 self.required_session_1()?,
403 self.optional_session_2(),
404 self.optional_session_3(),
405 &new_auth.into(),
406 &mut out_private_ptr,
407 )
408 },
409 |ret| {
410 error!("Error changing object auth: {:#010X}", ret);
411 },
412 )?;
413 Private::try_from(Context::ffi_data_to_owned(out_private_ptr)?)
414 }
415
416 // Missing function: CreateLoaded
417}