tss_esapi/context/tpm_commands/
object_commands.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::{KeyHandle, ObjectHandle, TpmHandle},
6    interface_types::resource_handles::Hierarchy,
7    structures::{
8        Auth, CreateKeyResult, CreationData, CreationTicket, Data, Digest, EncryptedSecret,
9        IdObject, Name, PcrSelectionList, Private, Public, Sensitive, SensitiveData,
10    },
11    tss2_esys::{
12        Esys_ActivateCredential, Esys_Create, Esys_Load, Esys_LoadExternal, Esys_MakeCredential,
13        Esys_ObjectChangeAuth, Esys_ReadPublic, Esys_Unseal, TPM2B_SENSITIVE_CREATE,
14        TPMS_SENSITIVE_CREATE,
15    },
16    Context, Error, Result,
17};
18use log::error;
19use std::{
20    convert::{TryFrom, TryInto},
21    mem::size_of,
22    ptr::{null, null_mut},
23};
24
25impl Context {
26    /// Create a key and return the handle.
27    ///
28    /// The authentication value, initial data, outside info and creation PCRs are passed as slices
29    /// which are then converted by the method into TSS native structures.
30    ///
31    /// # Parameters
32    /// * `parent_handle` - The [KeyHandle] of the parent for the new object that is being created.
33    /// * `public` -  The public part of the object that is being created.
34    /// * `auth_value` - The value used to be used for authorize usage of the object.
35    /// * `sensitive_data` - The data that is to be sealed, a key or derivation values.
36    /// * `outside_info` - Data that will be included in the creation data for this
37    ///                  object to provide permanent, verifiable linkage between
38    ///                  the object that is being created and some object owner data.
39    /// * `creation_pcrs`- PCRs that will be used in creation data.
40    ///
41    /// # Errors
42    /// * if either of the slices is larger than the maximum size of the native objects, a
43    ///   `WrongParamSize` wrapper error is returned
44    // TODO: Fix when compacting the arguments into a struct
45    #[allow(clippy::too_many_arguments)]
46    pub fn create(
47        &mut self,
48        parent_handle: KeyHandle,
49        public: Public,
50        auth_value: Option<Auth>,
51        sensitive_data: Option<SensitiveData>,
52        outside_info: Option<Data>,
53        creation_pcrs: Option<PcrSelectionList>,
54    ) -> Result<CreateKeyResult> {
55        let sensitive_create = TPM2B_SENSITIVE_CREATE {
56            #[allow(unused_qualifications)]
57            size: size_of::<TPMS_SENSITIVE_CREATE>().try_into().unwrap(), // will not fail on targets of at least 16 bits
58            sensitive: TPMS_SENSITIVE_CREATE {
59                userAuth: auth_value.unwrap_or_default().into(),
60                data: sensitive_data.unwrap_or_default().into(),
61            },
62        };
63        let creation_pcrs = PcrSelectionList::list_from_option(creation_pcrs);
64
65        let mut out_public_ptr = null_mut();
66        let mut out_private_ptr = null_mut();
67        let mut creation_data_ptr = null_mut();
68        let mut creation_hash_ptr = null_mut();
69        let mut creation_ticket_ptr = null_mut();
70
71        let ret = unsafe {
72            Esys_Create(
73                self.mut_context(),
74                parent_handle.into(),
75                self.optional_session_1(),
76                self.optional_session_2(),
77                self.optional_session_3(),
78                &sensitive_create,
79                &public.try_into()?,
80                &outside_info.unwrap_or_default().into(),
81                &creation_pcrs.into(),
82                &mut out_private_ptr,
83                &mut out_public_ptr,
84                &mut creation_data_ptr,
85                &mut creation_hash_ptr,
86                &mut creation_ticket_ptr,
87            )
88        };
89        let ret = Error::from_tss_rc(ret);
90
91        if ret.is_success() {
92            let out_private_owned = Context::ffi_data_to_owned(out_private_ptr);
93            let out_public_owned = Context::ffi_data_to_owned(out_public_ptr);
94            let creation_data_owned = Context::ffi_data_to_owned(creation_data_ptr);
95            let creation_hash_owned = Context::ffi_data_to_owned(creation_hash_ptr);
96            let creation_ticket_owned = Context::ffi_data_to_owned(creation_ticket_ptr);
97            Ok(CreateKeyResult {
98                out_private: Private::try_from(out_private_owned)?,
99                out_public: Public::try_from(out_public_owned)?,
100                creation_data: CreationData::try_from(creation_data_owned)?,
101                creation_hash: Digest::try_from(creation_hash_owned)?,
102                creation_ticket: CreationTicket::try_from(creation_ticket_owned)?,
103            })
104        } else {
105            error!("Error in creating derived key: {}", ret);
106            Err(ret)
107        }
108    }
109
110    /// Load a previously generated key back into the TPM and return its new handle.
111    pub fn load(
112        &mut self,
113        parent_handle: KeyHandle,
114        private: Private,
115        public: Public,
116    ) -> Result<KeyHandle> {
117        let mut object_handle = ObjectHandle::None.into();
118        let ret = unsafe {
119            Esys_Load(
120                self.mut_context(),
121                parent_handle.into(),
122                self.optional_session_1(),
123                self.optional_session_2(),
124                self.optional_session_3(),
125                &private.into(),
126                &public.try_into()?,
127                &mut object_handle,
128            )
129        };
130        let ret = Error::from_tss_rc(ret);
131        if ret.is_success() {
132            let key_handle = KeyHandle::from(object_handle);
133            self.handle_manager
134                .add_handle(key_handle.into(), HandleDropAction::Flush)?;
135            Ok(key_handle)
136        } else {
137            error!("Error in loading: {}", ret);
138            Err(ret)
139        }
140    }
141
142    /// Load an external key into the TPM and return its new handle.
143    pub fn load_external(
144        &mut self,
145        private: Sensitive,
146        public: Public,
147        hierarchy: Hierarchy,
148    ) -> Result<KeyHandle> {
149        let mut object_handle = ObjectHandle::None.into();
150        let ret = unsafe {
151            #[allow(unexpected_cfgs)]
152            Esys_LoadExternal(
153                self.mut_context(),
154                self.optional_session_1(),
155                self.optional_session_2(),
156                self.optional_session_3(),
157                &private.try_into()?,
158                &public.try_into()?,
159                if cfg!(tpm2_tss_version = "2") {
160                    TpmHandle::from(hierarchy).into()
161                } else {
162                    ObjectHandle::from(hierarchy).into()
163                },
164                &mut object_handle,
165            )
166        };
167
168        let ret = Error::from_tss_rc(ret);
169
170        if ret.is_success() {
171            let key_handle = KeyHandle::from(object_handle);
172            self.handle_manager
173                .add_handle(key_handle.into(), HandleDropAction::Flush)?;
174            Ok(key_handle)
175        } else {
176            error!("Error in loading external object: {}", ret);
177            Err(ret)
178        }
179    }
180
181    /// Load the public part of an external key and return its new handle.
182    pub fn load_external_public(
183        &mut self,
184        public: Public,
185        hierarchy: Hierarchy,
186    ) -> Result<KeyHandle> {
187        let mut object_handle = ObjectHandle::None.into();
188        let ret = unsafe {
189            #[allow(unexpected_cfgs)]
190            Esys_LoadExternal(
191                self.mut_context(),
192                self.optional_session_1(),
193                self.optional_session_2(),
194                self.optional_session_3(),
195                null(),
196                &public.try_into()?,
197                if cfg!(tpm2_tss_version = "2") {
198                    TpmHandle::from(hierarchy).into()
199                } else {
200                    ObjectHandle::from(hierarchy).into()
201                },
202                &mut object_handle,
203            )
204        };
205
206        let ret = Error::from_tss_rc(ret);
207
208        if ret.is_success() {
209            let key_handle = KeyHandle::from(object_handle);
210            self.handle_manager
211                .add_handle(key_handle.into(), HandleDropAction::Flush)?;
212            Ok(key_handle)
213        } else {
214            error!("Error in loading external public object: {}", ret);
215            Err(ret)
216        }
217    }
218
219    /// Read the public part of a key currently in the TPM and return it.
220    pub fn read_public(&mut self, key_handle: KeyHandle) -> Result<(Public, Name, Name)> {
221        let mut out_public_ptr = null_mut();
222        let mut name_ptr = null_mut();
223        let mut qualified_name_ptr = null_mut();
224        let ret = unsafe {
225            Esys_ReadPublic(
226                self.mut_context(),
227                key_handle.into(),
228                self.optional_session_1(),
229                self.optional_session_2(),
230                self.optional_session_3(),
231                &mut out_public_ptr,
232                &mut name_ptr,
233                &mut qualified_name_ptr,
234            )
235        };
236        let ret = Error::from_tss_rc(ret);
237
238        if ret.is_success() {
239            Ok((
240                Public::try_from(Context::ffi_data_to_owned(out_public_ptr))?,
241                Name::try_from(Context::ffi_data_to_owned(name_ptr))?,
242                Name::try_from(Context::ffi_data_to_owned(qualified_name_ptr))?,
243            ))
244        } else {
245            error!("Error in reading public part of object: {}", ret);
246            Err(ret)
247        }
248    }
249
250    /// Activates a credential in a way that ensures parameters are validated.
251    pub fn activate_credential(
252        &mut self,
253        activate_handle: KeyHandle,
254        key_handle: KeyHandle,
255        credential_blob: IdObject,
256        secret: EncryptedSecret,
257    ) -> Result<Digest> {
258        let mut cert_info_ptr = null_mut();
259        let ret = unsafe {
260            Esys_ActivateCredential(
261                self.mut_context(),
262                activate_handle.into(),
263                key_handle.into(),
264                self.required_session_1()?,
265                self.required_session_2()?,
266                self.optional_session_3(),
267                &credential_blob.into(),
268                &secret.into(),
269                &mut cert_info_ptr,
270            )
271        };
272
273        let ret = Error::from_tss_rc(ret);
274
275        if ret.is_success() {
276            Digest::try_from(Context::ffi_data_to_owned(cert_info_ptr))
277        } else {
278            error!("Error when activating credential: {}", ret);
279            Err(ret)
280        }
281    }
282
283    /// Perform actions to create a [IdObject] containing an activation credential.
284    ///
285    /// This does not use any TPM secrets, and is really just a convenience function.
286    pub fn make_credential(
287        &mut self,
288        key_handle: KeyHandle,
289        credential: Digest,
290        object_name: Name,
291    ) -> Result<(IdObject, EncryptedSecret)> {
292        let mut credential_blob_ptr = null_mut();
293        let mut secret_ptr = null_mut();
294        let ret = unsafe {
295            Esys_MakeCredential(
296                self.mut_context(),
297                key_handle.into(),
298                self.optional_session_1(),
299                self.optional_session_2(),
300                self.optional_session_3(),
301                &credential.into(),
302                object_name.as_ref(),
303                &mut credential_blob_ptr,
304                &mut secret_ptr,
305            )
306        };
307
308        let ret = Error::from_tss_rc(ret);
309
310        if ret.is_success() {
311            Ok((
312                IdObject::try_from(Context::ffi_data_to_owned(credential_blob_ptr))?,
313                EncryptedSecret::try_from(Context::ffi_data_to_owned(secret_ptr))?,
314            ))
315        } else {
316            error!("Error when making credential: {}", ret);
317            Err(ret)
318        }
319    }
320
321    /// Unseal and return data from a Sealed Data Object
322    pub fn unseal(&mut self, item_handle: ObjectHandle) -> Result<SensitiveData> {
323        let mut out_data_ptr = null_mut();
324
325        let ret = unsafe {
326            Esys_Unseal(
327                self.mut_context(),
328                item_handle.into(),
329                self.optional_session_1(),
330                self.optional_session_2(),
331                self.optional_session_3(),
332                &mut out_data_ptr,
333            )
334        };
335        let ret = Error::from_tss_rc(ret);
336
337        if ret.is_success() {
338            SensitiveData::try_from(Context::ffi_data_to_owned(out_data_ptr))
339        } else {
340            error!("Error in unsealing: {}", ret);
341            Err(ret)
342        }
343    }
344
345    /// Change authorization for a TPM-resident object.
346    pub fn object_change_auth(
347        &mut self,
348        object_handle: ObjectHandle,
349        parent_handle: ObjectHandle,
350        new_auth: Auth,
351    ) -> Result<Private> {
352        let mut out_private_ptr = null_mut();
353        let ret = unsafe {
354            Esys_ObjectChangeAuth(
355                self.mut_context(),
356                object_handle.into(),
357                parent_handle.into(),
358                self.required_session_1()?,
359                self.optional_session_2(),
360                self.optional_session_3(),
361                &new_auth.into(),
362                &mut out_private_ptr,
363            )
364        };
365        let ret = Error::from_tss_rc(ret);
366        if ret.is_success() {
367            Private::try_from(Context::ffi_data_to_owned(out_private_ptr))
368        } else {
369            error!("Error changing object auth: {}", ret);
370            Err(ret)
371        }
372    }
373
374    // Missing function: CreateLoaded
375}