Skip to main content

tss_esapi/context/tpm_commands/
duplication_commands.rs

1// Copyright 2021 Contributors to the Parsec project.
2// SPDX-License-Identifier: Apache-2.0
3use crate::Context;
4use crate::{
5    Result, ReturnCode,
6    handles::ObjectHandle,
7    structures::{Data, EncryptedSecret, Name, Private, Public, SymmetricDefinitionObject},
8    tss2_esys::{Esys_Duplicate, Esys_Import, Esys_Rewrap},
9};
10use log::error;
11
12use std::convert::{TryFrom, TryInto};
13use std::ptr::null_mut;
14
15impl Context {
16    /// Duplicate a loaded object so that it may be used in a different hierarchy.
17    ///
18    /// # Details
19    /// This command duplicates a loaded object so that it may be used in a different hierarchy.
20    /// The new parent key for the duplicate may be on the same or different TPM or the Null hierarchy.
21    /// Only the public area of `new_parent_handle` is required to be loaded.
22    ///
23    /// # Arguments
24    /// * `object_to_duplicate` - An [ObjectHandle] of the object that will be duplicated.
25    /// * `new_parent_handle` - An [ObjectHandle] of the new parent.
26    /// * `encryption_key_in` - An optional encryption key. If this parameter is `None`
27    ///   then a [default value][Default::default] is used.
28    /// * `symmetric_alg` - Symmetric algorithm to be used for the inner wrapper.
29    ///
30    /// The `object_to_duplicate` need to be have Fixed TPM and Fixed Parent attributes set to `false`.
31    ///
32    /// # Returns
33    /// The command returns a tuple consisting of:
34    /// * `encryption_key_out` - TPM generated, symmetric encryption key for the inner wrapper if
35    ///   `symmetric_alg` is not `Null`.
36    /// * `duplicate` - Private area that may be encrypted.
37    /// * `out_sym_seed` - Seed protected by the asymmetric algorithms of new parent.
38    ///
39    /// # Example
40    ///
41    /// ```rust
42    /// # use std::convert::{TryFrom, TryInto};
43    /// # use tss_esapi::attributes::{ObjectAttributesBuilder, SessionAttributesBuilder};
44    /// # use tss_esapi::constants::{CommandCode, SessionType};
45    /// # use tss_esapi::handles::ObjectHandle;
46    /// # use tss_esapi::interface_types::{
47    /// #     algorithm::{HashingAlgorithm, PublicAlgorithm},
48    /// #     key_bits::RsaKeyBits,
49    /// #     reserved_handles::Hierarchy,
50    /// #     session_handles::PolicySession,
51    /// # };
52    /// # use tss_esapi::structures::SymmetricDefinition;
53    /// # use tss_esapi::structures::{
54    /// #     PublicBuilder, PublicKeyRsa, PublicRsaParametersBuilder, RsaScheme,
55    /// #     RsaExponent,
56    /// # };
57    /// use tss_esapi::structures::SymmetricDefinitionObject;
58    /// # use tss_esapi::abstraction::cipher::Cipher;
59    /// # use tss_esapi::{Context, TctiNameConf};
60    /// #
61    /// # let mut context = // ...
62    /// #     Context::new(
63    /// #         TctiNameConf::from_environment_variable().expect("Failed to get TCTI"),
64    /// #     ).expect("Failed to create Context");
65    /// #
66    /// # let trial_session = context
67    /// #     .start_auth_session(
68    /// #         None,
69    /// #         None,
70    /// #         None,
71    /// #         SessionType::Trial,
72    /// #         SymmetricDefinition::AES_256_CFB,
73    /// #         HashingAlgorithm::Sha256,
74    /// #     )
75    /// #     .expect("Start auth session failed")
76    /// #     .expect("Start auth session returned a NONE handle");
77    /// #
78    /// # let (policy_auth_session_attributes, policy_auth_session_attributes_mask) =
79    /// #     SessionAttributesBuilder::new()
80    /// #         .with_decrypt(true)
81    /// #         .with_encrypt(true)
82    /// #         .build();
83    /// # context
84    /// #     .tr_sess_set_attributes(
85    /// #         trial_session,
86    /// #         policy_auth_session_attributes,
87    /// #         policy_auth_session_attributes_mask,
88    /// #     )
89    /// #     .expect("tr_sess_set_attributes call failed");
90    /// #
91    /// # let policy_session = PolicySession::try_from(trial_session)
92    /// #     .expect("Failed to convert auth session into policy session");
93    /// #
94    /// # context
95    /// #     .policy_auth_value(policy_session)
96    /// #     .expect("Policy auth value");
97    /// #
98    /// # context
99    /// #     .policy_command_code(policy_session, CommandCode::Duplicate)
100    /// #     .expect("Policy command code");
101    /// #
102    /// # /// Digest of the policy that allows duplication
103    /// # let digest = context
104    /// #     .policy_get_digest(policy_session)
105    /// #     .expect("Could retrieve digest");
106    /// #
107    /// # drop(context);
108    /// # let mut context = // ...
109    /// #     Context::new(
110    /// #         TctiNameConf::from_environment_variable().expect("Failed to get TCTI"),
111    /// #     ).expect("Failed to create Context");
112    /// #
113    /// # let session = context
114    /// #     .start_auth_session(
115    /// #         None,
116    /// #         None,
117    /// #         None,
118    /// #         SessionType::Hmac,
119    /// #         SymmetricDefinition::AES_256_CFB,
120    /// #         HashingAlgorithm::Sha256,
121    /// #     )
122    /// #     .expect("Start auth session failed")
123    /// #     .expect("Start auth session returned a NONE handle");
124    /// #
125    /// # let (session_attributes, session_attributes_mask) = SessionAttributesBuilder::new()
126    /// #     .with_decrypt(true)
127    /// #     .with_encrypt(true)
128    /// #     .build();
129    /// #
130    /// # context.tr_sess_set_attributes(
131    /// #     session,
132    /// #     session_attributes,
133    /// #     session_attributes_mask,
134    /// # ).unwrap();
135    /// #
136    /// # context.set_sessions((Some(session), None, None));
137    /// #
138    /// # // Attributes of parent objects. The `restricted` attribute need
139    /// # // to be `true` so that parents can act as storage keys.
140    /// # let parent_object_attributes = ObjectAttributesBuilder::new()
141    /// #     .with_fixed_tpm(true)
142    /// #     .with_fixed_parent(true)
143    /// #     .with_sensitive_data_origin(true)
144    /// #     .with_user_with_auth(true)
145    /// #     .with_decrypt(true)
146    /// #     .with_sign_encrypt(false)
147    /// #     .with_restricted(true)
148    /// #     .build()
149    /// #     .unwrap();
150    /// #
151    /// # let parent_public = PublicBuilder::new()
152    /// #     .with_public_algorithm(PublicAlgorithm::Rsa)
153    /// #     .with_name_hashing_algorithm(HashingAlgorithm::Sha256)
154    /// #     .with_object_attributes(parent_object_attributes)
155    /// #     .with_rsa_parameters(
156    /// #         PublicRsaParametersBuilder::new_restricted_decryption_key(
157    /// #             Cipher::aes_256_cfb().try_into().unwrap(),
158    /// #             RsaKeyBits::Rsa2048,
159    /// #             RsaExponent::default(),
160    /// #         )
161    /// #         .build()
162    /// #         .unwrap(),
163    /// #     )
164    /// #     .with_rsa_unique_identifier(PublicKeyRsa::default())
165    /// #     .build()
166    /// #     .unwrap();
167    /// #
168    /// # let parent_of_object_to_duplicate_handle = context
169    /// #     .create_primary(
170    /// #         Hierarchy::Owner,
171    /// #         parent_public.clone(),
172    /// #         None,
173    /// #         None,
174    /// #         None,
175    /// #         None,
176    /// #     )
177    /// #     .unwrap()
178    /// #     .key_handle;
179    /// #
180    /// # // Fixed TPM and Fixed Parent should be "false" for an object
181    /// # // to be eligible for duplication
182    /// # let object_attributes = ObjectAttributesBuilder::new()
183    /// #     .with_fixed_tpm(false)
184    /// #     .with_fixed_parent(false)
185    /// #     .with_sensitive_data_origin(true)
186    /// #     .with_user_with_auth(true)
187    /// #     .with_decrypt(true)
188    /// #     .with_sign_encrypt(true)
189    /// #     .with_restricted(false)
190    /// #     .build()
191    /// #     .expect("Attributes to be valid");
192    /// #
193    /// # let public_child = PublicBuilder::new()
194    /// #     .with_public_algorithm(PublicAlgorithm::Rsa)
195    /// #     .with_name_hashing_algorithm(HashingAlgorithm::Sha256)
196    /// #     .with_object_attributes(object_attributes)
197    /// #     .with_auth_policy(digest)
198    /// #     .with_rsa_parameters(
199    /// #         PublicRsaParametersBuilder::new()
200    /// #             .with_scheme(RsaScheme::Null)
201    /// #             .with_key_bits(RsaKeyBits::Rsa2048)
202    /// #             .with_is_signing_key(true)
203    /// #             .with_is_decryption_key(true)
204    /// #             .with_restricted(false)
205    /// #             .build()
206    /// #             .expect("Params to be valid"),
207    /// #     )
208    /// #     .with_rsa_unique_identifier(PublicKeyRsa::default())
209    /// #     .build()
210    /// #     .expect("public to be valid");
211    /// #
212    /// # let result = context
213    /// #     .create(
214    /// #         parent_of_object_to_duplicate_handle,
215    /// #         public_child,
216    /// #         None,
217    /// #         None,
218    /// #         None,
219    /// #         None,
220    /// #     )
221    /// #     .unwrap();
222    /// #
223    /// # let object_to_duplicate_handle: ObjectHandle = context
224    /// #     .load(
225    /// #         parent_of_object_to_duplicate_handle,
226    /// #         result.out_private.clone(),
227    /// #         result.out_public,
228    /// #     )
229    /// #     .unwrap()
230    /// #     .into();
231    /// #
232    /// # let new_parent_handle: ObjectHandle = context
233    /// #     .create_primary(
234    /// #         Hierarchy::Owner,
235    /// #         parent_public,
236    /// #         None,
237    /// #         None,
238    /// #         None,
239    /// #         None,
240    /// #     )
241    /// #     .unwrap()
242    /// #     .key_handle
243    /// #     .into();
244    /// #
245    /// # context.set_sessions((None, None, None));
246    /// #
247    /// # // Create a Policy session with the same exact attributes
248    /// # // as the trial session so that the session digest stays
249    /// # // the same.
250    /// # let policy_auth_session = context
251    /// #     .start_auth_session(
252    /// #         None,
253    /// #         None,
254    /// #         None,
255    /// #         SessionType::Policy,
256    /// #         SymmetricDefinition::AES_256_CFB,
257    /// #         HashingAlgorithm::Sha256,
258    /// #     )
259    /// #     .expect("Start auth session failed")
260    /// #     .expect("Start auth session returned a NONE handle");
261    /// #
262    /// # let (policy_auth_session_attributes, policy_auth_session_attributes_mask) =
263    /// #     SessionAttributesBuilder::new()
264    /// #         .with_decrypt(true)
265    /// #         .with_encrypt(true)
266    /// #         .build();
267    /// # context
268    /// #     .tr_sess_set_attributes(
269    /// #         policy_auth_session,
270    /// #         policy_auth_session_attributes,
271    /// #         policy_auth_session_attributes_mask,
272    /// #     )
273    /// #     .expect("tr_sess_set_attributes call failed");
274    /// #
275    /// # let policy_session = PolicySession::try_from(policy_auth_session)
276    /// #     .expect("Failed to convert auth session into policy session");
277    /// #
278    /// # context
279    /// #     .policy_auth_value(policy_session)
280    /// #     .expect("Policy auth value");
281    /// #
282    /// # context
283    /// #     .policy_command_code(policy_session, CommandCode::Duplicate)
284    /// #     .unwrap();
285    /// #
286    /// # context.set_sessions((Some(policy_auth_session), None, None));
287    ///
288    /// let (encryption_key_out, duplicate, out_sym_seed) = context
289    ///     .duplicate(
290    ///         object_to_duplicate_handle,
291    ///         new_parent_handle,
292    ///         None,
293    ///         SymmetricDefinitionObject::Null,
294    ///     )
295    ///     .unwrap();
296    /// # eprintln!("D: {:?}, P: {:?}, S: {:?}", encryption_key_out, duplicate, out_sym_seed);
297    /// ```
298    pub fn duplicate(
299        &mut self,
300        object_to_duplicate: ObjectHandle,
301        new_parent_handle: ObjectHandle,
302        encryption_key_in: Option<Data>,
303        symmetric_alg: SymmetricDefinitionObject,
304    ) -> Result<(Data, Private, EncryptedSecret)> {
305        let mut encryption_key_out_ptr = null_mut();
306        let mut duplicate_ptr = null_mut();
307        let mut out_sym_seed_ptr = null_mut();
308        ReturnCode::ensure_success(
309            unsafe {
310                Esys_Duplicate(
311                    self.mut_context(),
312                    object_to_duplicate.into(),
313                    new_parent_handle.into(),
314                    self.required_session_1()?,
315                    self.optional_session_2(),
316                    self.optional_session_3(),
317                    &encryption_key_in.unwrap_or_default().into(),
318                    &symmetric_alg.into(),
319                    &mut encryption_key_out_ptr,
320                    &mut duplicate_ptr,
321                    &mut out_sym_seed_ptr,
322                )
323            },
324            |ret| {
325                error!("Error when performing duplication: {:#010X}", ret);
326            },
327        )?;
328
329        Ok((
330            Data::try_from(Context::ffi_data_to_owned(encryption_key_out_ptr)?)?,
331            Private::try_from(Context::ffi_data_to_owned(duplicate_ptr)?)?,
332            EncryptedSecret::try_from(Context::ffi_data_to_owned(out_sym_seed_ptr)?)?,
333        ))
334    }
335
336    /// Re-wrap an already duplicated object for a new parent.
337    ///
338    /// # Arguments
339    ///
340    /// * `old_parent` - An [ObjectHandle] of the parent that protects `in_duplicate`.
341    /// * `new_parent` - An [ObjectHandle] of the parent that will protect the result.
342    /// * `in_duplicate` - The [Private] area encrypted using a key derived from `in_sym_seed`.
343    /// * `name` - The [Name] of the object being re-wrapped.
344    /// * `in_sym_seed` - The [EncryptedSecret] seed protected by `old_parent`.
345    ///
346    /// # Details
347    ///
348    /// *From the specification*
349    /// > This command allows the TPM to serve in the role as a Duplication Authority.
350    ///
351    /// # Returns
352    ///
353    /// A tuple containing the re-wrapped [Private] area and the [EncryptedSecret]
354    /// seed protected by `new_parent`.
355    ///
356    /// # Example
357    ///
358    /// ```rust
359    /// # use std::convert::{TryFrom, TryInto};
360    /// # use tss_esapi::{Context, TctiNameConf};
361    /// # use tss_esapi::attributes::{ObjectAttributesBuilder, SessionAttributesBuilder};
362    /// # use tss_esapi::constants::SessionType;
363    /// # use tss_esapi::handles::{ObjectHandle, SessionHandle};
364    /// # use tss_esapi::interface_types::{
365    /// #     algorithm::{HashingAlgorithm, PublicAlgorithm},
366    /// #     ecc::EccCurve,
367    /// #     key_bits::RsaKeyBits,
368    /// #     reserved_handles::Hierarchy,
369    /// #     session_handles::PolicySession,
370    /// # };
371    /// # use tss_esapi::structures::{
372    /// #     EccPoint, EccScheme, KeyDerivationFunctionScheme, PublicBuilder,
373    /// #     PublicEccParametersBuilder, RsaExponent, SymmetricDefinition,
374    /// #     SymmetricDefinitionObject,
375    /// # };
376    /// # use tss_esapi::utils::create_restricted_decryption_rsa_public;
377    /// # let mut context = Context::new(
378    /// #     TctiNameConf::from_environment_variable().expect("Failed to get TCTI"),
379    /// # )
380    /// # .expect("Failed to create Context");
381    /// # let old_parent_public = create_restricted_decryption_rsa_public(
382    /// #     SymmetricDefinitionObject::AES_128_CFB,
383    /// #     RsaKeyBits::Rsa2048,
384    /// #     RsaExponent::default(),
385    /// # )
386    /// # .expect("Failed to create old parent public area");
387    /// # let new_parent_public = create_restricted_decryption_rsa_public(
388    /// #     SymmetricDefinitionObject::AES_256_CFB,
389    /// #     RsaKeyBits::Rsa2048,
390    /// #     RsaExponent::default(),
391    /// # )
392    /// # .expect("Failed to create new parent public area");
393    /// # let old_parent = context
394    /// #     .execute_with_nullauth_session(|ctx| {
395    /// #         ctx.create_primary(
396    /// #             Hierarchy::Owner,
397    /// #             old_parent_public,
398    /// #             None,
399    /// #             None,
400    /// #             None,
401    /// #             None,
402    /// #         )
403    /// #     })
404    /// #     .expect("Failed to create old parent")
405    /// #     .key_handle;
406    /// # let new_parent = context
407    /// #     .execute_with_nullauth_session(|ctx| {
408    /// #         ctx.create_primary(
409    /// #             Hierarchy::Owner,
410    /// #             new_parent_public,
411    /// #             None,
412    /// #             None,
413    /// #             None,
414    /// #             None,
415    /// #         )
416    /// #     })
417    /// #     .expect("Failed to create new parent")
418    /// #     .key_handle;
419    /// # let old_parent_name = context
420    /// #     .read_public(old_parent)
421    /// #     .expect("Failed to read old parent")
422    /// #     .1;
423    /// # let trial_session = context
424    /// #     .start_auth_session(
425    /// #         None,
426    /// #         None,
427    /// #         None,
428    /// #         SessionType::Trial,
429    /// #         SymmetricDefinition::AES_256_CFB,
430    /// #         HashingAlgorithm::Sha256,
431    /// #     )
432    /// #     .expect("Failed to create trial session")
433    /// #     .expect("Received invalid handle");
434    /// # let trial_policy =
435    /// #     PolicySession::try_from(trial_session).expect("Failed to convert trial session");
436    /// # context
437    /// #     .policy_duplication_select(
438    /// #         trial_policy,
439    /// #         Vec::<u8>::new().try_into().expect("Failed to create empty Name"),
440    /// #         old_parent_name.clone(),
441    /// #         false,
442    /// #     )
443    /// #     .expect("Failed to compute duplication policy");
444    /// # let policy_digest = context
445    /// #     .policy_get_digest(trial_policy)
446    /// #     .expect("Failed to get policy digest");
447    /// # context
448    /// #     .flush_context(SessionHandle::from(trial_session).into())
449    /// #     .expect("Failed to flush trial session");
450    /// # let child_attributes = ObjectAttributesBuilder::new()
451    /// #     .with_fixed_tpm(false)
452    /// #     .with_fixed_parent(false)
453    /// #     .with_sensitive_data_origin(true)
454    /// #     .with_user_with_auth(true)
455    /// #     .with_decrypt(true)
456    /// #     .with_sign_encrypt(true)
457    /// #     .with_restricted(false)
458    /// #     .build()
459    /// #     .expect("Failed to create child attributes");
460    /// # let child_public = PublicBuilder::new()
461    /// #     .with_public_algorithm(PublicAlgorithm::Ecc)
462    /// #     .with_name_hashing_algorithm(HashingAlgorithm::Sha256)
463    /// #     .with_object_attributes(child_attributes)
464    /// #     .with_auth_policy(policy_digest)
465    /// #     .with_ecc_parameters(
466    /// #         PublicEccParametersBuilder::new()
467    /// #             .with_ecc_scheme(EccScheme::Null)
468    /// #             .with_curve(EccCurve::NistP256)
469    /// #             .with_is_signing_key(false)
470    /// #             .with_is_decryption_key(true)
471    /// #             .with_restricted(false)
472    /// #             .with_key_derivation_function_scheme(KeyDerivationFunctionScheme::Null)
473    /// #             .build()
474    /// #             .expect("Failed to create child parameters"),
475    /// #     )
476    /// #     .with_ecc_unique_identifier(EccPoint::default())
477    /// #     .build()
478    /// #     .expect("Failed to create child public area");
479    /// # let create_result = context
480    /// #     .execute_with_nullauth_session(|ctx| {
481    /// #         ctx.create(new_parent, child_public, None, None, None, None)
482    /// #     })
483    /// #     .expect("Failed to create child object");
484    /// # let child_public = create_result.out_public.clone();
485    /// # let child = context
486    /// #     .execute_with_nullauth_session(|ctx| {
487    /// #         ctx.load(new_parent, create_result.out_private, create_result.out_public)
488    /// #     })
489    /// #     .expect("Failed to load child object");
490    /// # let child_name = context
491    /// #     .read_public(child)
492    /// #     .expect("Failed to read child object")
493    /// #     .1;
494    /// # let policy_session = context
495    /// #     .start_auth_session(
496    /// #         None,
497    /// #         None,
498    /// #         None,
499    /// #         SessionType::Policy,
500    /// #         SymmetricDefinition::AES_256_CFB,
501    /// #         HashingAlgorithm::Sha256,
502    /// #     )
503    /// #     .expect("Failed to create policy session")
504    /// #     .expect("Received invalid handle");
505    /// # let (attributes, mask) = SessionAttributesBuilder::new()
506    /// #     .with_decrypt(true)
507    /// #     .with_encrypt(true)
508    /// #     .build();
509    /// # context
510    /// #     .tr_sess_set_attributes(policy_session, attributes, mask)
511    /// #     .expect("Failed to set policy session attributes");
512    /// # let policy =
513    /// #     PolicySession::try_from(policy_session).expect("Failed to convert policy session");
514    /// # context
515    /// #     .policy_duplication_select(policy, child_name.clone(), old_parent_name, false)
516    /// #     .expect("Failed to satisfy duplication policy");
517    /// # context.set_sessions((Some(policy_session), None, None));
518    /// # let (encryption_key, duplicate, in_sym_seed) = context
519    /// #     .duplicate(
520    /// #         child.into(),
521    /// #         old_parent.into(),
522    /// #         None,
523    /// #         SymmetricDefinitionObject::Null,
524    /// #     )
525    /// #     .expect("Failed to duplicate child object");
526    /// # context.clear_sessions();
527    /// # context
528    /// #     .flush_context(SessionHandle::from(policy_session).into())
529    /// #     .expect("Failed to flush policy session");
530    /// let (out_duplicate, out_sym_seed) = context
531    ///     .execute_with_nullauth_session(|ctx| {
532    ///         ctx.rewrap(
533    ///             old_parent.into(),
534    ///             new_parent.into(),
535    ///             duplicate,
536    ///             child_name,
537    ///             in_sym_seed,
538    ///         )
539    ///     })
540    ///     .expect("Failed to re-wrap duplicated object");
541    /// # context
542    /// #     .flush_context(child.into())
543    /// #     .expect("Failed to flush child");
544    /// # let imported_private = context
545    /// #     .execute_with_nullauth_session(|ctx| {
546    /// #         ctx.import(
547    /// #             new_parent.into(),
548    /// #             Some(encryption_key),
549    /// #             child_public.clone(),
550    /// #             out_duplicate,
551    /// #             out_sym_seed,
552    /// #             SymmetricDefinitionObject::Null,
553    /// #         )
554    /// #     })
555    /// #     .expect("Failed to import re-wrapped object");
556    /// # let imported_child = context
557    /// #     .execute_with_nullauth_session(|ctx| {
558    /// #         ctx.load(new_parent, imported_private, child_public)
559    /// #     })
560    /// #     .expect("Failed to load imported object");
561    /// # context
562    /// #     .flush_context(imported_child.into())
563    /// #     .expect("Failed to flush imported child");
564    /// # context
565    /// #     .flush_context(old_parent.into())
566    /// #     .expect("Failed to flush old parent");
567    /// # context
568    /// #     .flush_context(new_parent.into())
569    /// #     .expect("Failed to flush new parent");
570    /// ```
571    pub fn rewrap(
572        &mut self,
573        old_parent: ObjectHandle,
574        new_parent: ObjectHandle,
575        in_duplicate: Private,
576        name: Name,
577        in_sym_seed: EncryptedSecret,
578    ) -> Result<(Private, EncryptedSecret)> {
579        let mut out_duplicate_ptr = null_mut();
580        let mut out_sym_seed_ptr = null_mut();
581        ReturnCode::ensure_success(
582            unsafe {
583                Esys_Rewrap(
584                    self.mut_context(),
585                    old_parent.into(),
586                    new_parent.into(),
587                    self.required_session_1()?,
588                    self.optional_session_2(),
589                    self.optional_session_3(),
590                    &in_duplicate.into(),
591                    &name.into(),
592                    &in_sym_seed.into(),
593                    &mut out_duplicate_ptr,
594                    &mut out_sym_seed_ptr,
595                )
596            },
597            |ret| {
598                error!("Error when performing rewrap: {:#010X}", ret);
599            },
600        )?;
601
602        Ok((
603            Private::try_from(Context::ffi_data_to_owned(out_duplicate_ptr)?)?,
604            EncryptedSecret::try_from(Context::ffi_data_to_owned(out_sym_seed_ptr)?)?,
605        ))
606    }
607
608    /// Import attaches imported object to a new parent.
609    ///
610    /// # Details
611    /// This command allows an object to be encrypted using the symmetric
612    /// encryption values of a Storage Key. After encryption, the
613    /// object may be loaded and used in the new hierarchy. The
614    /// imported object (duplicate) may be singly encrypted, multiply
615    /// encrypted, or unencrypted.
616    ///
617    /// # Arguments
618    /// * `parent_handle` - An [ObjectHandle] of the new parent for the object.
619    /// * `encryption_key` - An optional symmetric encryption key used as the inner wrapper.
620    ///   If `encryption_key` is `None` then a [default value][Default::default] is used.
621    /// * `public` - A [Public] of the imported object.
622    /// * `duplicate` - A symmetrically encrypted duplicated object.
623    /// * `encrypted_secret` - The seed for the symmetric key and HMAC key.
624    /// * `symmetric_alg` - Symmetric algorithm to be used for the inner wrapper.
625    ///
626    /// The `public` is needed to check the integrity value for `duplicate`.
627    ///
628    /// # Returns
629    /// The command returns the sensitive area encrypted with the symmetric key of `parent_handle`.
630    ///
631    /// # Example
632    ///
633    /// ```rust
634    /// # use std::convert::{TryFrom, TryInto};
635    /// # use tss_esapi::attributes::{ObjectAttributesBuilder, SessionAttributesBuilder};
636    /// # use tss_esapi::constants::{CommandCode, SessionType};
637    /// # use tss_esapi::handles::ObjectHandle;
638    /// # use tss_esapi::interface_types::{
639    /// #     algorithm::{HashingAlgorithm, PublicAlgorithm},
640    /// #     key_bits::RsaKeyBits,
641    /// #     reserved_handles::Hierarchy,
642    /// #     session_handles::PolicySession,
643    /// # };
644    /// # use tss_esapi::structures::SymmetricDefinition;
645    /// # use tss_esapi::structures::{
646    /// #     PublicBuilder, PublicKeyRsa, PublicRsaParametersBuilder, RsaScheme,
647    /// #     RsaExponent,
648    /// # };
649    /// use tss_esapi::structures::SymmetricDefinitionObject;
650    /// # use tss_esapi::abstraction::cipher::Cipher;
651    /// # use tss_esapi::{Context, TctiNameConf};
652    /// #
653    /// # let mut context = // ...
654    /// #     Context::new(
655    /// #         TctiNameConf::from_environment_variable().expect("Failed to get TCTI"),
656    /// #     ).expect("Failed to create Context");
657    /// #
658    /// # let trial_session = context
659    /// #     .start_auth_session(
660    /// #         None,
661    /// #         None,
662    /// #         None,
663    /// #         SessionType::Trial,
664    /// #         SymmetricDefinition::AES_256_CFB,
665    /// #         HashingAlgorithm::Sha256,
666    /// #     )
667    /// #     .expect("Start auth session failed")
668    /// #     .expect("Start auth session returned a NONE handle");
669    /// #
670    /// # let (policy_auth_session_attributes, policy_auth_session_attributes_mask) =
671    /// #     SessionAttributesBuilder::new()
672    /// #         .with_decrypt(true)
673    /// #         .with_encrypt(true)
674    /// #         .build();
675    /// # context
676    /// #     .tr_sess_set_attributes(
677    /// #         trial_session,
678    /// #         policy_auth_session_attributes,
679    /// #         policy_auth_session_attributes_mask,
680    /// #     )
681    /// #     .expect("tr_sess_set_attributes call failed");
682    /// #
683    /// # let policy_session = PolicySession::try_from(trial_session)
684    /// #     .expect("Failed to convert auth session into policy session");
685    /// #
686    /// # context
687    /// #     .policy_auth_value(policy_session)
688    /// #     .expect("Policy auth value");
689    /// #
690    /// # context
691    /// #     .policy_command_code(policy_session, CommandCode::Duplicate)
692    /// #     .expect("Policy command code");
693    /// #
694    /// # /// Digest of the policy that allows duplication
695    /// # let digest = context
696    /// #     .policy_get_digest(policy_session)
697    /// #     .expect("Could retrieve digest");
698    /// #
699    /// # drop(context);
700    /// # let mut context = // ...
701    /// #     Context::new(
702    /// #         TctiNameConf::from_environment_variable().expect("Failed to get TCTI"),
703    /// #     ).expect("Failed to create Context");
704    /// #
705    /// # let session = context
706    /// #     .start_auth_session(
707    /// #         None,
708    /// #         None,
709    /// #         None,
710    /// #         SessionType::Hmac,
711    /// #         SymmetricDefinition::AES_256_CFB,
712    /// #         HashingAlgorithm::Sha256,
713    /// #     )
714    /// #     .expect("Start auth session failed")
715    /// #     .expect("Start auth session returned a NONE handle");
716    /// #
717    /// # let (session_attributes, session_attributes_mask) = SessionAttributesBuilder::new()
718    /// #     .with_decrypt(true)
719    /// #     .with_encrypt(true)
720    /// #     .build();
721    /// #
722    /// # context.tr_sess_set_attributes(
723    /// #     session,
724    /// #     session_attributes,
725    /// #     session_attributes_mask,
726    /// # ).unwrap();
727    /// #
728    /// # context.set_sessions((Some(session), None, None));
729    /// #
730    /// # // Attributes of parent objects. The `restricted` attribute need
731    /// # // to be `true` so that parents can act as storage keys.
732    /// # let parent_object_attributes = ObjectAttributesBuilder::new()
733    /// #     .with_fixed_tpm(true)
734    /// #     .with_fixed_parent(true)
735    /// #     .with_sensitive_data_origin(true)
736    /// #     .with_user_with_auth(true)
737    /// #     .with_decrypt(true)
738    /// #     .with_sign_encrypt(false)
739    /// #     .with_restricted(true)
740    /// #     .build()
741    /// #     .unwrap();
742    /// #
743    /// # let parent_public = PublicBuilder::new()
744    /// #     .with_public_algorithm(PublicAlgorithm::Rsa)
745    /// #     .with_name_hashing_algorithm(HashingAlgorithm::Sha256)
746    /// #     .with_object_attributes(parent_object_attributes)
747    /// #     .with_rsa_parameters(
748    /// #         PublicRsaParametersBuilder::new_restricted_decryption_key(
749    /// #             Cipher::aes_256_cfb().try_into().unwrap(),
750    /// #             RsaKeyBits::Rsa2048,
751    /// #             RsaExponent::default(),
752    /// #         )
753    /// #         .build()
754    /// #         .unwrap(),
755    /// #     )
756    /// #     .with_rsa_unique_identifier(PublicKeyRsa::default())
757    /// #     .build()
758    /// #     .unwrap();
759    /// #
760    /// # let parent_of_object_to_duplicate_handle = context
761    /// #     .create_primary(
762    /// #         Hierarchy::Owner,
763    /// #         parent_public.clone(),
764    /// #         None,
765    /// #         None,
766    /// #         None,
767    /// #         None,
768    /// #     )
769    /// #     .unwrap()
770    /// #     .key_handle;
771    /// #
772    /// # // Fixed TPM and Fixed Parent should be "false" for an object
773    /// # // to be eligible for duplication
774    /// # let object_attributes = ObjectAttributesBuilder::new()
775    /// #     .with_fixed_tpm(false)
776    /// #     .with_fixed_parent(false)
777    /// #     .with_sensitive_data_origin(true)
778    /// #     .with_user_with_auth(true)
779    /// #     .with_decrypt(true)
780    /// #     .with_sign_encrypt(true)
781    /// #     .with_restricted(false)
782    /// #     .build()
783    /// #     .expect("Attributes to be valid");
784    /// #
785    /// # let public_child = PublicBuilder::new()
786    /// #     .with_public_algorithm(PublicAlgorithm::Rsa)
787    /// #     .with_name_hashing_algorithm(HashingAlgorithm::Sha256)
788    /// #     .with_object_attributes(object_attributes)
789    /// #     .with_auth_policy(digest)
790    /// #     .with_rsa_parameters(
791    /// #         PublicRsaParametersBuilder::new()
792    /// #             .with_scheme(RsaScheme::Null)
793    /// #             .with_key_bits(RsaKeyBits::Rsa2048)
794    /// #             .with_is_signing_key(true)
795    /// #             .with_is_decryption_key(true)
796    /// #             .with_restricted(false)
797    /// #             .build()
798    /// #             .expect("Params to be valid"),
799    /// #     )
800    /// #     .with_rsa_unique_identifier(PublicKeyRsa::default())
801    /// #     .build()
802    /// #     .expect("public to be valid");
803    /// #
804    /// # let result = context
805    /// #     .create(
806    /// #         parent_of_object_to_duplicate_handle,
807    /// #         public_child,
808    /// #         None,
809    /// #         None,
810    /// #         None,
811    /// #         None,
812    /// #     )
813    /// #     .unwrap();
814    /// #
815    /// # let object_to_duplicate_handle: ObjectHandle = context
816    /// #     .load(
817    /// #         parent_of_object_to_duplicate_handle,
818    /// #         result.out_private.clone(),
819    /// #         result.out_public,
820    /// #     )
821    /// #     .unwrap()
822    /// #     .into();
823    /// #
824    /// # let new_parent_handle: ObjectHandle = context
825    /// #     .create_primary(
826    /// #         Hierarchy::Owner,
827    /// #         parent_public,
828    /// #         None,
829    /// #         None,
830    /// #         None,
831    /// #         None,
832    /// #     )
833    /// #     .unwrap()
834    /// #     .key_handle
835    /// #     .into();
836    /// #
837    /// # context.set_sessions((None, None, None));
838    /// #
839    /// # // Create a Policy session with the same exact attributes
840    /// # // as the trial session so that the session digest stays
841    /// # // the same.
842    /// # let policy_auth_session = context
843    /// #     .start_auth_session(
844    /// #         None,
845    /// #         None,
846    /// #         None,
847    /// #         SessionType::Policy,
848    /// #         SymmetricDefinition::AES_256_CFB,
849    /// #         HashingAlgorithm::Sha256,
850    /// #     )
851    /// #     .expect("Start auth session failed")
852    /// #     .expect("Start auth session returned a NONE handle");
853    /// #
854    /// # let (policy_auth_session_attributes, policy_auth_session_attributes_mask) =
855    /// #     SessionAttributesBuilder::new()
856    /// #         .with_decrypt(true)
857    /// #         .with_encrypt(true)
858    /// #         .build();
859    /// # context
860    /// #     .tr_sess_set_attributes(
861    /// #         policy_auth_session,
862    /// #         policy_auth_session_attributes,
863    /// #         policy_auth_session_attributes_mask,
864    /// #     )
865    /// #     .expect("tr_sess_set_attributes call failed");
866    /// #
867    /// # let policy_session = PolicySession::try_from(policy_auth_session)
868    /// #     .expect("Failed to convert auth session into policy session");
869    /// #
870    /// # context
871    /// #     .policy_auth_value(policy_session)
872    /// #     .expect("Policy auth value");
873    /// #
874    /// # context
875    /// #     .policy_command_code(policy_session, CommandCode::Duplicate)
876    /// #     .unwrap();
877    /// #
878    /// # context.set_sessions((Some(policy_auth_session), None, None));
879    /// #
880    /// # let (encryption_key_out, duplicate, out_sym_seed) = context
881    /// #     .duplicate(
882    /// #         object_to_duplicate_handle,
883    /// #         new_parent_handle,
884    /// #         None,
885    /// #         SymmetricDefinitionObject::Null,
886    /// #     )
887    /// #     .unwrap();
888    /// # eprintln!("D: {:?}, P: {:?}, S: {:?}", encryption_key_out, duplicate, out_sym_seed);
889    /// # let public = context.read_public(object_to_duplicate_handle.into()).unwrap().0;
890    /// #
891    /// # let session = context
892    /// #     .start_auth_session(
893    /// #         None,
894    /// #         None,
895    /// #         None,
896    /// #         SessionType::Hmac,
897    /// #         SymmetricDefinition::AES_256_CFB,
898    /// #         HashingAlgorithm::Sha256,
899    /// #     )
900    /// #     .unwrap();
901    /// # let (session_attributes, session_attributes_mask) = SessionAttributesBuilder::new()
902    /// #     .with_decrypt(true)
903    /// #     .with_encrypt(true)
904    /// #     .build();
905    /// # context.tr_sess_set_attributes(
906    /// #     session.unwrap(),
907    /// #     session_attributes,
908    /// #     session_attributes_mask,
909    /// # )
910    /// # .unwrap();
911    /// # context.set_sessions((session, None, None));
912    ///
913    /// // `encryption_key_out`, `duplicate` and `out_sym_seed` are generated
914    /// // by `duplicate` function
915    /// let private = context.import(
916    ///     new_parent_handle,
917    ///     Some(encryption_key_out),
918    ///     public,
919    ///     duplicate,
920    ///     out_sym_seed,
921    ///     SymmetricDefinitionObject::Null,
922    ///  ).unwrap();
923    /// #
924    /// # eprintln!("P: {:?}", private);
925    /// ```
926    pub fn import(
927        &mut self,
928        parent_handle: ObjectHandle,
929        encryption_key: Option<Data>,
930        public: Public,
931        duplicate: Private,
932        encrypted_secret: EncryptedSecret,
933        symmetric_alg: SymmetricDefinitionObject,
934    ) -> Result<Private> {
935        let mut out_private_ptr = null_mut();
936        ReturnCode::ensure_success(
937            unsafe {
938                Esys_Import(
939                    self.mut_context(),
940                    parent_handle.into(),
941                    self.required_session_1()?,
942                    self.optional_session_2(),
943                    self.optional_session_3(),
944                    &encryption_key.unwrap_or_default().into(),
945                    &public.try_into()?,
946                    &duplicate.into(),
947                    &encrypted_secret.into(),
948                    &symmetric_alg.into(),
949                    &mut out_private_ptr,
950                )
951            },
952            |ret| {
953                error!("Error when performing import: {:#010X}", ret);
954            },
955        )?;
956        Private::try_from(Context::ffi_data_to_owned(out_private_ptr)?)
957    }
958}