Skip to main content

tss_esapi/context/tpm_commands/
asymmetric_primitives.rs

1// Copyright 2021 Contributors to the Parsec project.
2// SPDX-License-Identifier: Apache-2.0
3use crate::{
4    Context, Result, ReturnCode,
5    handles::KeyHandle,
6    interface_types::{algorithm::EccKeyExchangeAlgorithm, ecc::EccCurve},
7    structures::Data,
8    structures::{EccParameterDetails, EccPoint, PublicKeyRsa, RsaDecryptionScheme},
9    tss2_esys::{
10        Esys_ECC_Parameters, Esys_ECDH_KeyGen, Esys_ECDH_ZGen, Esys_RSA_Decrypt, Esys_RSA_Encrypt,
11        Esys_ZGen_2Phase,
12    },
13};
14use log::error;
15use std::ptr::null_mut;
16use std::{convert::TryFrom, ptr::null};
17
18impl Context {
19    /// Perform an asymmetric RSA encryption.
20    ///
21    /// # Arguments
22    ///
23    /// * `key_handle` - A [KeyHandle] to to public portion of RSA key to use for encryption.
24    /// * `message`    - The message to be encrypted.
25    /// * `in_scheme`  - The padding scheme to use if scheme associated with
26    ///   the `key_handle` is [RsaDecryptionScheme::Null].
27    /// * `label`      - An optional label to be associated with the message.
28    ///
29    /// # Details
30    ///
31    /// *From the specification*
32    /// > This command performs RSA encryption using the indicated padding scheme
33    /// > according to IETF [RFC 8017](https://www.rfc-editor.org/rfc/rfc8017).
34    ///
35    /// > The label parameter is optional. If provided (label.size != 0) then the TPM shall return TPM_RC_VALUE if
36    /// > the last octet in label is not zero. The terminating octet of zero is included in the label used in the padding
37    /// > scheme.
38    /// > If the scheme does not use a label, the TPM will still verify that label is properly formatted if label is
39    /// > present.
40    ///
41    /// # Returns
42    ///
43    /// The encrypted output.
44    ///
45    /// # Example
46    ///
47    /// ```rust
48    /// # use tss_esapi::{
49    /// #    Context, TctiNameConf,
50    /// #    attributes::{SessionAttributesBuilder, ObjectAttributesBuilder},
51    /// #    constants::SessionType,
52    /// #    interface_types::{
53    /// #        algorithm::{
54    /// #            HashingAlgorithm, PublicAlgorithm, RsaDecryptAlgorithm,
55    /// #        },
56    /// #        key_bits::RsaKeyBits,
57    /// #        reserved_handles::Hierarchy,
58    /// #   },
59    /// #   structures::{
60    /// #       Auth, Data, RsaScheme, PublicBuilder, PublicRsaParametersBuilder, PublicKeyRsa,
61    /// #       RsaDecryptionScheme, HashScheme, SymmetricDefinition, RsaExponent,
62    /// #    },
63    /// # };
64    /// # use std::{env, str::FromStr, convert::TryFrom};
65    /// # // Create context
66    /// # let mut context =
67    /// #     Context::new(
68    /// #         TctiNameConf::from_environment_variable().expect("Failed to get TCTI"),
69    /// #     ).expect("Failed to create Context");
70    /// #
71    /// # let session = context
72    /// #     .start_auth_session(
73    /// #         None,
74    /// #         None,
75    /// #         None,
76    /// #         SessionType::Hmac,
77    /// #         SymmetricDefinition::AES_256_CFB,
78    /// #         tss_esapi::interface_types::algorithm::HashingAlgorithm::Sha256,
79    /// #     )
80    /// #     .expect("Failed to create session")
81    /// #     .expect("Received invalid handle");
82    /// # let (session_attributes, session_attributes_mask) = SessionAttributesBuilder::new()
83    /// #     .with_decrypt(true)
84    /// #     .with_encrypt(true)
85    /// #     .build();
86    /// # context.tr_sess_set_attributes(session, session_attributes, session_attributes_mask)
87    /// #     .expect("Failed to set attributes on session");
88    /// # context.set_sessions((Some(session), None, None));
89    /// # let mut random_digest = vec![0u8; 16];
90    /// # getrandom::getrandom(&mut random_digest).unwrap();
91    /// # let key_auth = Auth::from_bytes(random_digest.as_slice()).unwrap();
92    /// #
93    /// # let object_attributes = ObjectAttributesBuilder::new()
94    /// #     .with_fixed_tpm(true)
95    /// #     .with_fixed_parent(true)
96    /// #     .with_sensitive_data_origin(true)
97    /// #     .with_user_with_auth(true)
98    /// #     .with_decrypt(true)
99    /// #     .with_sign_encrypt(true)
100    /// #     .with_restricted(false)
101    /// #     .build()
102    /// #     .expect("Should be able to build object attributes when the attributes are not conflicting.");
103    /// #
104    /// # let key_pub = PublicBuilder::new()
105    /// #     .with_public_algorithm(PublicAlgorithm::Rsa)
106    /// #     .with_name_hashing_algorithm(HashingAlgorithm::Sha256)
107    /// #     .with_object_attributes(object_attributes)
108    /// #     .with_rsa_parameters(
109    /// #         PublicRsaParametersBuilder::new()
110    /// #             .with_scheme(RsaScheme::Null)
111    /// #             .with_key_bits(RsaKeyBits::Rsa2048)
112    /// #             .with_exponent(RsaExponent::default())
113    /// #             .with_is_signing_key(true)
114    /// #             .with_is_decryption_key(true)
115    /// #             .with_restricted(false)
116    /// #             .build()
117    /// #             .expect("Should be possible to build valid RSA parameters")
118    /// #    )
119    /// #    .with_rsa_unique_identifier(PublicKeyRsa::default())
120    /// #    .build()
121    /// #    .expect("Should be possible to build a valid Public object.");
122    /// #
123    /// # let key_handle = context
124    /// #     .create_primary(
125    /// #         Hierarchy::Owner,
126    /// #         key_pub,
127    /// #         None,
128    /// #         None,
129    /// #         None,
130    /// #         None,
131    /// #     )
132    /// #     .expect("Should be possible to create primary key from using valid Public object.")
133    /// #     .key_handle;
134    /// // Because the key was created with RsaScheme::Null it is possible to
135    /// // provide a scheme for the rsa_encrypt function to use.
136    /// let scheme =
137    ///        RsaDecryptionScheme::create(RsaDecryptAlgorithm::Oaep, Some(HashingAlgorithm::Sha256))
138    ///            .expect("Failed to create rsa decryption scheme");
139    /// let plain_text_bytes = vec![1, 2, 3, 4];
140    /// let message_in = PublicKeyRsa::try_from(plain_text_bytes.clone())
141    ///     .expect("Should be possible to create a PublicKeyRsa object from valid bytes.");
142    /// let cipher_text = context.rsa_encrypt(key_handle, message_in, scheme, None)
143    ///     .expect("Should be possible to call rsa_encrypt using valid arguments.");
144    /// # let message_out = context.rsa_decrypt(key_handle, cipher_text, scheme, None)
145    /// #     .expect("Should be possible to call rsa_decrypt using valid arguments.");
146    /// # let decrypted_bytes = message_out.as_bytes();
147    /// # assert_eq!(plain_text_bytes, decrypted_bytes);
148    /// ```
149    pub fn rsa_encrypt(
150        &mut self,
151        key_handle: KeyHandle,
152        message: PublicKeyRsa,
153        in_scheme: RsaDecryptionScheme,
154        label: impl Into<Option<Data>>,
155    ) -> Result<PublicKeyRsa> {
156        let mut out_data_ptr = null_mut();
157        let potential_label = label.into().map(|v| v.into());
158        let label_ptr = potential_label
159            .as_ref()
160            .map_or_else(null, std::ptr::from_ref);
161        ReturnCode::ensure_success(
162            unsafe {
163                Esys_RSA_Encrypt(
164                    self.mut_context(),
165                    key_handle.into(),
166                    self.optional_session_1(),
167                    self.optional_session_2(),
168                    self.optional_session_3(),
169                    &message.into(),
170                    &in_scheme.into(),
171                    label_ptr,
172                    &mut out_data_ptr,
173                )
174            },
175            |ret| {
176                error!("Error when performing RSA encryption: {:#010X}", ret);
177            },
178        )?;
179        PublicKeyRsa::try_from(Context::ffi_data_to_owned(out_data_ptr)?)
180    }
181
182    /// Perform an asymmetric RSA decryption.
183    ///
184    /// # Arguments
185    ///
186    /// * `key_handle`  - A [KeyHandle] of the RSA key to use for decryption.
187    /// * `cipher_text` - The cipher text to be decrypted.
188    /// * `in_scheme`  - The padding scheme to use if scheme associated with
189    ///   the `key_handle` is [RsaDecryptionScheme::Null].
190    /// * `label`       - An optional label whose association with the message is to be verified.
191    ///
192    /// # Details
193    ///
194    /// *From the specification*
195    /// > This command performs RSA decryption using the indicated padding scheme according to IETF RFC
196    /// > 8017 ((PKCS#1).
197    ///
198    /// > If a label is used in the padding process of the scheme during encryption, the label parameter is required
199    /// > to be present in the decryption process and label is required to be the same in both cases. If label is not
200    /// > the same, the decrypt operation is very likely to fail.
201    ///
202    /// # Returns
203    ///
204    /// The decrypted output.
205    ///
206    /// # Example
207    ///
208    /// ```rust
209    /// # use tss_esapi::{
210    /// #    Context, TctiNameConf,
211    /// #    attributes::{SessionAttributesBuilder, ObjectAttributesBuilder},
212    /// #    constants::SessionType,
213    /// #    interface_types::{
214    /// #        algorithm::{
215    /// #            HashingAlgorithm, PublicAlgorithm, RsaDecryptAlgorithm,
216    /// #        },
217    /// #        key_bits::RsaKeyBits,
218    /// #        reserved_handles::Hierarchy,
219    /// #   },
220    /// #   structures::{
221    /// #       Auth, Data, RsaScheme, PublicBuilder, PublicRsaParametersBuilder, PublicKeyRsa,
222    /// #       RsaDecryptionScheme, HashScheme, SymmetricDefinition, RsaExponent,
223    /// #    },
224    /// # };
225    /// # use std::{env, str::FromStr, convert::TryFrom};
226    /// # // Create context
227    /// # let mut context =
228    /// #     Context::new(
229    /// #         TctiNameConf::from_environment_variable().expect("Failed to get TCTI"),
230    /// #     ).expect("Failed to create Context");
231    /// #
232    /// # let session = context
233    /// #     .start_auth_session(
234    /// #         None,
235    /// #         None,
236    /// #         None,
237    /// #         SessionType::Hmac,
238    /// #         SymmetricDefinition::AES_256_CFB,
239    /// #         tss_esapi::interface_types::algorithm::HashingAlgorithm::Sha256,
240    /// #     )
241    /// #     .expect("Failed to create session")
242    /// #     .expect("Received invalid handle");
243    /// # let (session_attributes, session_attributes_mask) = SessionAttributesBuilder::new()
244    /// #     .with_decrypt(true)
245    /// #     .with_encrypt(true)
246    /// #     .build();
247    /// # context.tr_sess_set_attributes(session, session_attributes, session_attributes_mask)
248    /// #     .expect("Failed to set attributes on session");
249    /// # context.set_sessions((Some(session), None, None));
250    /// # let mut random_digest = vec![0u8; 16];
251    /// # getrandom::getrandom(&mut random_digest).unwrap();
252    /// # let key_auth = Auth::from_bytes(random_digest.as_slice()).unwrap();
253    /// #
254    /// # let object_attributes = ObjectAttributesBuilder::new()
255    /// #     .with_fixed_tpm(true)
256    /// #     .with_fixed_parent(true)
257    /// #     .with_sensitive_data_origin(true)
258    /// #     .with_user_with_auth(true)
259    /// #     .with_decrypt(true)
260    /// #     .with_sign_encrypt(true)
261    /// #     .with_restricted(false)
262    /// #     .build()
263    /// #     .expect("Should be able to build object attributes when the attributes are not conflicting.");
264    /// #
265    /// # let key_pub = PublicBuilder::new()
266    /// #     .with_public_algorithm(PublicAlgorithm::Rsa)
267    /// #     .with_name_hashing_algorithm(HashingAlgorithm::Sha256)
268    /// #     .with_object_attributes(object_attributes)
269    /// #     .with_rsa_parameters(
270    /// #         PublicRsaParametersBuilder::new()
271    /// #             .with_scheme(RsaScheme::Null)
272    /// #             .with_key_bits(RsaKeyBits::Rsa2048)
273    /// #             .with_exponent(RsaExponent::default())
274    /// #             .with_is_signing_key(true)
275    /// #             .with_is_decryption_key(true)
276    /// #             .with_restricted(false)
277    /// #             .build()
278    /// #             .expect("Should be possible to build valid RSA parameters")
279    /// #    )
280    /// #    .with_rsa_unique_identifier(PublicKeyRsa::default())
281    /// #    .build()
282    /// #    .expect("Should be possible to build a valid Public object.");
283    /// #
284    /// # let key_handle = context
285    /// #     .create_primary(
286    /// #         Hierarchy::Owner,
287    /// #         key_pub,
288    /// #         None,
289    /// #         None,
290    /// #         None,
291    /// #         None,
292    /// #     )
293    /// #     .expect("Should be possible to create primary key from using valid Public object.")
294    /// #     .key_handle;
295    /// # let scheme =
296    /// #        RsaDecryptionScheme::create(RsaDecryptAlgorithm::RsaEs, None)
297    /// #            .expect("Failed to create rsa decryption scheme");
298    /// # let plain_text_bytes = vec![4, 3, 2, 1, 0];
299    /// # let message_in = PublicKeyRsa::try_from(plain_text_bytes.clone())
300    /// #     .expect("Should be possible to create a PublicKeyRsa object from valid bytes.");
301    /// # let label = Data::default();
302    /// # let cipher_text = context.rsa_encrypt(key_handle, message_in, scheme, label.clone())
303    /// #     .expect("Should be possible to call rsa_encrypt using valid arguments.");
304    /// // label text needs to be the same as the on used when data was encrypted.
305    /// let message_out = context.rsa_decrypt(key_handle, cipher_text, scheme, label)
306    ///     .expect("Should be possible to call rsa_decrypt using valid arguments.");
307    /// let decrypted_bytes = message_out.as_bytes();
308    /// # assert_eq!(plain_text_bytes, decrypted_bytes);
309    /// ```
310    pub fn rsa_decrypt(
311        &mut self,
312        key_handle: KeyHandle,
313        cipher_text: PublicKeyRsa,
314        in_scheme: RsaDecryptionScheme,
315        label: impl Into<Option<Data>>,
316    ) -> Result<PublicKeyRsa> {
317        let mut message_ptr = null_mut();
318        let potential_label = label.into().map(|v| v.into());
319        let label_ptr = potential_label
320            .as_ref()
321            .map_or_else(null, std::ptr::from_ref);
322        ReturnCode::ensure_success(
323            unsafe {
324                Esys_RSA_Decrypt(
325                    self.mut_context(),
326                    key_handle.into(),
327                    self.required_session_1()?,
328                    self.optional_session_2(),
329                    self.optional_session_3(),
330                    &cipher_text.into(),
331                    &in_scheme.into(),
332                    label_ptr,
333                    &mut message_ptr,
334                )
335            },
336            |ret| {
337                error!("Error when performing RSA decryption: {:#010X}", ret);
338            },
339        )?;
340        PublicKeyRsa::try_from(Context::ffi_data_to_owned(message_ptr)?)
341    }
342
343    /// Generate an ephemeral key pair.
344    ///
345    /// # Arguments
346    /// * `key_handle`- A [KeyHandle] of ECC key which curve parameters will be used
347    ///   to generate the ephemeral key.
348    ///
349    /// # Details
350    /// This command uses the TPM to generate an ephemeral
351    /// key pair. It uses the private ephemeral key and a loaded
352    /// public key to compute the shared secret value.
353    ///
354    /// # Example
355    ///
356    /// ```rust
357    /// # use tss_esapi::{
358    /// #    Context, TctiNameConf,
359    /// #    attributes::{SessionAttributesBuilder, ObjectAttributesBuilder},
360    /// #    constants::SessionType,
361    /// #    interface_types::{
362    /// #        algorithm::{
363    /// #            HashingAlgorithm, PublicAlgorithm, RsaDecryptAlgorithm,
364    /// #        },
365    /// #        ecc::EccCurve,
366    /// #        reserved_handles::Hierarchy,
367    /// #   },
368    /// #   structures::{
369    /// #       Auth, Data, EccScheme, PublicBuilder, PublicEccParametersBuilder, PublicKeyRsa, KeyDerivationFunctionScheme, EccPoint,
370    /// #        RsaDecryptionScheme, HashScheme, SymmetricDefinition,
371    /// #    },
372    /// # };
373    /// # use std::{env, str::FromStr, convert::TryFrom};
374    /// # // Create context
375    /// # let mut context =
376    /// #     Context::new(
377    /// #         TctiNameConf::from_environment_variable().expect("Failed to get TCTI"),
378    /// #     ).expect("Failed to create Context");
379    /// #
380    /// # let session = context
381    /// #     .start_auth_session(
382    /// #         None,
383    /// #         None,
384    /// #         None,
385    /// #         SessionType::Hmac,
386    /// #         SymmetricDefinition::AES_256_CFB,
387    /// #         tss_esapi::interface_types::algorithm::HashingAlgorithm::Sha256,
388    /// #     )
389    /// #     .expect("Failed to create session")
390    /// #     .expect("Received invalid handle");
391    /// # let (session_attributes, session_attributes_mask) = SessionAttributesBuilder::new()
392    /// #     .with_decrypt(true)
393    /// #     .with_encrypt(true)
394    /// #     .build();
395    /// # context.tr_sess_set_attributes(session, session_attributes, session_attributes_mask)
396    /// #     .expect("Failed to set attributes on session");
397    /// # context.set_sessions((Some(session), None, None));
398    /// # let mut random_digest = vec![0u8; 16];
399    /// # getrandom::getrandom(&mut random_digest).unwrap();
400    /// # let key_auth = Auth::from_bytes(random_digest.as_slice()).unwrap();
401    /// #
402    /// // Create a key suitable for ECDH key generation
403    /// let ecc_parms = PublicEccParametersBuilder::new()
404    ///     .with_ecc_scheme(
405    ///         EccScheme::EcDh(HashScheme::new(HashingAlgorithm::Sha256)),
406    ///     )
407    ///     .with_curve(EccCurve::NistP256)
408    ///     .with_is_signing_key(false)
409    ///     .with_is_decryption_key(true)
410    ///     .with_restricted(false)
411    ///     .with_key_derivation_function_scheme(KeyDerivationFunctionScheme::Null)
412    ///     .build()
413    ///     .unwrap();
414    ///
415    /// let object_attributes = ObjectAttributesBuilder::new()
416    ///     .with_fixed_tpm(true)
417    ///     .with_fixed_parent(true)
418    ///     .with_sensitive_data_origin(true)
419    ///     .with_user_with_auth(true)
420    ///     .with_decrypt(true)
421    ///     .with_sign_encrypt(false)
422    ///     .with_restricted(false)
423    ///     .build()
424    ///     .unwrap();
425    ///
426    /// let public = PublicBuilder::new()
427    ///     .with_public_algorithm(PublicAlgorithm::Ecc)
428    ///     .with_name_hashing_algorithm(HashingAlgorithm::Sha256)
429    ///     .with_object_attributes(object_attributes)
430    ///     .with_ecc_parameters(ecc_parms)
431    ///     .with_ecc_unique_identifier(EccPoint::default())
432    ///     .build()
433    ///     .unwrap();
434    ///
435    /// let key_handle = context
436    ///     .create_primary(
437    ///         Hierarchy::Owner,
438    ///         public,
439    ///         Some(key_auth),
440    ///         None,
441    ///         None,
442    ///         None,
443    ///     )
444    ///     .unwrap()
445    ///     .key_handle;
446    ///
447    /// // Generate ephemeral key pair and a shared secret
448    /// let (z_point, pub_point) = context.ecdh_key_gen(key_handle).unwrap();
449    /// ```
450    pub fn ecdh_key_gen(&mut self, key_handle: KeyHandle) -> Result<(EccPoint, EccPoint)> {
451        let mut z_point_ptr = null_mut();
452        let mut pub_point_ptr = null_mut();
453        ReturnCode::ensure_success(
454            unsafe {
455                Esys_ECDH_KeyGen(
456                    self.mut_context(),
457                    key_handle.into(),
458                    self.optional_session_1(),
459                    self.optional_session_2(),
460                    self.optional_session_3(),
461                    &mut z_point_ptr,
462                    &mut pub_point_ptr,
463                )
464            },
465            |ret| {
466                error!("Error when generating ECDH key pair: {:#010X}", ret);
467            },
468        )?;
469
470        let z_point = Context::ffi_data_to_owned(z_point_ptr)?;
471        let pub_point = Context::ffi_data_to_owned(pub_point_ptr)?;
472        Ok((
473            EccPoint::try_from(z_point.point)?,
474            EccPoint::try_from(pub_point.point)?,
475        ))
476    }
477
478    /// Recover Z value from a public point and a private key.
479    ///
480    /// # Arguments
481    /// * `key_handle` - A [KeyHandle] of ECC key which curve parameters will be used
482    ///   to generate the ephemeral key.
483    /// * `in_point` - An [EccPoint] on the curve of the key referenced by `key_handle`
484    ///
485    /// # Details
486    /// This command uses the TPM to recover the Z value from a public point and a private key.
487    /// It will perform the multiplication of the provided `in_point` with the private key and
488    /// return the coordinates of the resultant point.
489    ///
490    /// # Example
491    ///
492    /// ```rust
493    /// # use tss_esapi::{
494    /// #    Context, TctiNameConf,
495    /// #    attributes::{SessionAttributesBuilder, ObjectAttributesBuilder},
496    /// #    constants::SessionType,
497    /// #    interface_types::{
498    /// #        algorithm::{
499    /// #            HashingAlgorithm, PublicAlgorithm, RsaDecryptAlgorithm,
500    /// #        },
501    /// #        ecc::EccCurve,
502    /// #        reserved_handles::Hierarchy,
503    /// #   },
504    /// #   structures::{
505    /// #       Auth, Data, EccScheme, PublicBuilder, PublicEccParametersBuilder, PublicKeyRsa, KeyDerivationFunctionScheme, EccPoint,
506    /// #        RsaDecryptionScheme, HashScheme, SymmetricDefinition,
507    /// #    },
508    /// # };
509    /// # use std::{env, str::FromStr, convert::TryFrom};
510    /// # // Create context
511    /// # let mut context =
512    /// #     Context::new(
513    /// #         TctiNameConf::from_environment_variable().expect("Failed to get TCTI"),
514    /// #     ).expect("Failed to create Context");
515    /// #
516    /// # let session = context
517    /// #     .start_auth_session(
518    /// #         None,
519    /// #         None,
520    /// #         None,
521    /// #         SessionType::Hmac,
522    /// #         SymmetricDefinition::AES_256_CFB,
523    /// #         tss_esapi::interface_types::algorithm::HashingAlgorithm::Sha256,
524    /// #     )
525    /// #     .expect("Failed to create session")
526    /// #     .expect("Received invalid handle");
527    /// # let (session_attributes, session_attributes_mask) = SessionAttributesBuilder::new()
528    /// #     .with_decrypt(true)
529    /// #     .with_encrypt(true)
530    /// #     .build();
531    /// # context.tr_sess_set_attributes(session, session_attributes, session_attributes_mask)
532    /// #     .expect("Failed to set attributes on session");
533    /// # context.set_sessions((Some(session), None, None));
534    /// # let mut random_digest = vec![0u8; 16];
535    /// # getrandom::getrandom(&mut random_digest).unwrap();
536    /// # let key_auth = Auth::from_bytes(random_digest.as_slice()).unwrap();
537    /// #
538    /// // Create a key suitable for ECDH key generation
539    /// let ecc_parms = PublicEccParametersBuilder::new()
540    ///     .with_ecc_scheme(
541    ///         EccScheme::EcDh(HashScheme::new(HashingAlgorithm::Sha256)),
542    ///     )
543    ///     .with_curve(EccCurve::NistP256)
544    ///     .with_is_signing_key(false)
545    ///     .with_is_decryption_key(true)
546    ///     .with_restricted(false)
547    ///     .with_key_derivation_function_scheme(KeyDerivationFunctionScheme::Null)
548    ///     .build()
549    ///     .unwrap();
550    ///
551    /// let object_attributes = ObjectAttributesBuilder::new()
552    ///     .with_fixed_tpm(true)
553    ///     .with_fixed_parent(true)
554    ///     .with_sensitive_data_origin(true)
555    ///     .with_user_with_auth(true)
556    ///     .with_decrypt(true)
557    ///     .with_sign_encrypt(false)
558    ///     .with_restricted(false)
559    ///     .build()
560    ///     .unwrap();
561    ///
562    /// let public = PublicBuilder::new()
563    ///     .with_public_algorithm(PublicAlgorithm::Ecc)
564    ///     .with_name_hashing_algorithm(HashingAlgorithm::Sha256)
565    ///     .with_object_attributes(object_attributes)
566    ///     .with_ecc_parameters(ecc_parms)
567    ///     .with_ecc_unique_identifier(EccPoint::default())
568    ///     .build()
569    ///     .unwrap();
570    ///
571    /// let key_handle = context
572    ///     .create_primary(
573    ///         Hierarchy::Owner,
574    ///         public,
575    ///         Some(key_auth),
576    ///         None,
577    ///         None,
578    ///         None,
579    ///     )
580    ///     .unwrap()
581    ///     .key_handle;
582    ///
583    /// // Generate ephemeral key pair and a shared secret
584    /// let (z_point, pub_point) = context.ecdh_key_gen(key_handle).unwrap();
585    /// let z_point_gen = context.ecdh_z_gen(key_handle, pub_point).unwrap();
586    /// assert_eq!(z_point.x().as_bytes(), z_point_gen.x().as_bytes());
587    /// ```
588    pub fn ecdh_z_gen(&mut self, key_handle: KeyHandle, in_point: EccPoint) -> Result<EccPoint> {
589        let mut out_point_ptr = null_mut();
590        ReturnCode::ensure_success(
591            unsafe {
592                Esys_ECDH_ZGen(
593                    self.mut_context(),
594                    key_handle.into(),
595                    self.required_session_1()?,
596                    self.optional_session_2(),
597                    self.optional_session_3(),
598                    &in_point.into(),
599                    &mut out_point_ptr,
600                )
601            },
602            |ret| {
603                error!("Error when performing ECDH ZGen: {:#010X}", ret);
604            },
605        )?;
606        let out_point = Context::ffi_data_to_owned(out_point_ptr)?;
607        EccPoint::try_from(out_point.point)
608    }
609
610    /// Get the parameters of an ECC curve.
611    ///
612    /// # Arguments
613    ///
614    /// * `curve` - The [EccCurve] to query.
615    ///
616    /// # Details
617    ///
618    /// *From the specification*
619    /// > This command returns the parameters of an ECC curve identified
620    /// > by its TCG-assigned curveID.
621    ///
622    /// # Returns
623    ///
624    /// An [EccParameterDetails] containing the curve parameters.
625    ///
626    /// # Example
627    ///
628    /// ```rust
629    /// # use tss_esapi::{Context, TctiNameConf};
630    /// use tss_esapi::interface_types::ecc::EccCurve;
631    /// # let mut context =
632    /// #     Context::new(
633    /// #         TctiNameConf::from_environment_variable().expect("Failed to get TCTI"),
634    /// #     ).expect("Failed to create Context");
635    /// // Get the parameters of the elliptic curve
636    /// let details = context.ecc_parameters(EccCurve::NistP256).expect("Failed to get ECC parameters");
637    /// ```
638    pub fn ecc_parameters(&mut self, curve: EccCurve) -> Result<EccParameterDetails> {
639        let mut parameters_ptr = null_mut();
640        ReturnCode::ensure_success(
641            unsafe {
642                Esys_ECC_Parameters(
643                    self.mut_context(),
644                    self.optional_session_1(),
645                    self.optional_session_2(),
646                    self.optional_session_3(),
647                    curve.into(),
648                    &mut parameters_ptr,
649                )
650            },
651            |ret| {
652                error!("Error when getting ECC parameters: {:#010X}", ret);
653            },
654        )?;
655        EccParameterDetails::try_from(Context::ffi_data_to_owned(parameters_ptr)?)
656    }
657
658    /// Perform a two-phase ECC key exchange.
659    ///
660    /// # Arguments
661    ///
662    /// * `key_handle` - A [KeyHandle] of the ECC key (Party A).
663    /// * `in_qs_b` - The static public key of Party B as an [EccPoint].
664    /// * `in_qe_b` - The ephemeral public key of Party B as an [EccPoint].
665    /// * `in_scheme` - The key exchange protocol as an [EccKeyExchangeAlgorithm].
666    /// * `counter` - The commit counter from the TPM.
667    ///
668    /// # Details
669    ///
670    /// *From the specification*
671    /// > This command supports two-phase key exchange protocols. The
672    /// > command is used in combination with TPM2_EC_Ephemeral().
673    ///
674    /// # Returns
675    ///
676    /// A tuple of `(EccPoint, EccPoint)` representing `(outZ1, outZ2)`.
677    ///
678    /// # Example
679    ///
680    /// ```rust
681    /// # use tss_esapi::{
682    /// #    Context, TctiNameConf,
683    /// #    attributes::{SessionAttributesBuilder, ObjectAttributesBuilder},
684    /// #    constants::SessionType,
685    /// #    interface_types::{
686    /// #        algorithm::{EccKeyExchangeAlgorithm, HashingAlgorithm, PublicAlgorithm},
687    /// #        ecc::EccCurve,
688    /// #        reserved_handles::Hierarchy,
689    /// #   },
690    /// #   structures::{
691    /// #       Auth, EccPoint, EccScheme, HashScheme, KeyDerivationFunctionScheme,
692    /// #       PublicBuilder, PublicEccParametersBuilder, SymmetricDefinition,
693    /// #    },
694    /// # };
695    /// # let mut context =
696    /// #     Context::new(
697    /// #         TctiNameConf::from_environment_variable().expect("Failed to get TCTI"),
698    /// #     ).expect("Failed to create Context");
699    /// #
700    /// # let session = context
701    /// #     .start_auth_session(
702    /// #         None,
703    /// #         None,
704    /// #         None,
705    /// #         SessionType::Hmac,
706    /// #         SymmetricDefinition::AES_256_CFB,
707    /// #         HashingAlgorithm::Sha256,
708    /// #     )
709    /// #     .expect("Failed to create session")
710    /// #     .expect("Received invalid handle");
711    /// # let (session_attributes, session_attributes_mask) = SessionAttributesBuilder::new()
712    /// #     .with_decrypt(true)
713    /// #     .with_encrypt(true)
714    /// #     .build();
715    /// # context.tr_sess_set_attributes(session, session_attributes, session_attributes_mask)
716    /// #     .expect("Failed to set attributes on session");
717    /// # context.set_sessions((Some(session), None, None));
718    /// # let mut random_digest = vec![0u8; 16];
719    /// # getrandom::getrandom(&mut random_digest).expect("Failed to get random bytes");
720    /// # let key_auth = Auth::from_bytes(random_digest.as_slice()).expect("Failed to create key auth");
721    /// #
722    /// # let ecc_parms = PublicEccParametersBuilder::new()
723    /// #     .with_ecc_scheme(EccScheme::EcDh(HashScheme::new(HashingAlgorithm::Sha256)))
724    /// #     .with_curve(EccCurve::NistP256)
725    /// #     .with_is_signing_key(false)
726    /// #     .with_is_decryption_key(true)
727    /// #     .with_restricted(false)
728    /// #     .with_key_derivation_function_scheme(KeyDerivationFunctionScheme::Null)
729    /// #     .build()
730    /// #     .expect("Failed to build ECC parameters");
731    /// #
732    /// # let 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(false)
740    /// #     .build()
741    /// #     .expect("Failed to build object attributes");
742    /// #
743    /// # let public = PublicBuilder::new()
744    /// #     .with_public_algorithm(PublicAlgorithm::Ecc)
745    /// #     .with_name_hashing_algorithm(HashingAlgorithm::Sha256)
746    /// #     .with_object_attributes(object_attributes)
747    /// #     .with_ecc_parameters(ecc_parms)
748    /// #     .with_ecc_unique_identifier(EccPoint::default())
749    /// #     .build()
750    /// #     .expect("Failed to build public key");
751    /// #
752    /// # let key_handle = context
753    /// #     .create_primary(Hierarchy::Owner, public, Some(key_auth), None, None, None)
754    /// #     .expect("Failed to create primary key")
755    /// #     .key_handle;
756    /// #
757    /// // Get ephemeral key and counter
758    /// let (q_point, counter) = context
759    ///     .ec_ephemeral(EccCurve::NistP256)
760    ///     .expect("Failed to create EC ephemeral key");
761    ///
762    /// // Generate another ephemeral via ecdh_key_gen
763    /// let (_z_point, pub_point) = context
764    ///     .ecdh_key_gen(key_handle)
765    ///     .expect("Failed to generate ECDH key");
766    ///
767    /// // Perform two-phase key exchange
768    /// let (_out_z1, _out_z2) = context
769    ///     .zgen_2phase(
770    ///         key_handle,
771    ///         pub_point,
772    ///         q_point,
773    ///         EccKeyExchangeAlgorithm::EcDh,
774    ///         counter,
775    ///     )
776    ///     .expect("Failed to perform ZGen_2Phase");
777    /// ```
778    pub fn zgen_2phase(
779        &mut self,
780        key_handle: KeyHandle,
781        in_qs_b: EccPoint,
782        in_qe_b: EccPoint,
783        in_scheme: EccKeyExchangeAlgorithm,
784        counter: u16,
785    ) -> Result<(EccPoint, EccPoint)> {
786        let mut out_z1_ptr = null_mut();
787        let mut out_z2_ptr = null_mut();
788        ReturnCode::ensure_success(
789            unsafe {
790                Esys_ZGen_2Phase(
791                    self.mut_context(),
792                    key_handle.into(),
793                    self.required_session_1()?,
794                    self.optional_session_2(),
795                    self.optional_session_3(),
796                    &in_qs_b.into(),
797                    &in_qe_b.into(),
798                    in_scheme.into(),
799                    counter,
800                    &mut out_z1_ptr,
801                    &mut out_z2_ptr,
802                )
803            },
804            |ret| {
805                error!("Error in ZGen_2Phase: {:#010X}", ret);
806            },
807        )?;
808
809        let out_z1 = Context::ffi_data_to_owned(out_z1_ptr)?;
810        let out_z2 = Context::ffi_data_to_owned(out_z2_ptr)?;
811        Ok((
812            EccPoint::try_from(out_z1.point)?,
813            EccPoint::try_from(out_z2.point)?,
814        ))
815    }
816}