Skip to main content

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}