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    handles::KeyHandle,
5    structures::Data,
6    structures::{EccPoint, PublicKeyRsa, RsaDecryptionScheme},
7    tss2_esys::{Esys_ECDH_KeyGen, Esys_ECDH_ZGen, Esys_RSA_Decrypt, Esys_RSA_Encrypt},
8    Context, Result, ReturnCode,
9};
10use log::error;
11use std::ptr::null_mut;
12use std::{convert::TryFrom, ptr::null};
13
14impl Context {
15    /// Perform an asymmetric RSA encryption.
16    ///
17    /// # Arguments
18    ///
19    /// * `key_handle` - A [KeyHandle] to to public portion of RSA key to use for encryption.
20    /// * `message`    - The message to be encrypted.
21    /// * `in_scheme`  - The padding scheme to use if scheme associated with
22    ///   the `key_handle` is [RsaDecryptionScheme::Null].
23    /// * `label`      - An optional label to be associated with the message.
24    ///
25    /// # Details
26    ///
27    /// *From the specification*
28    /// > This command performs RSA encryption using the indicated padding scheme
29    /// > according to IETF [RFC 8017](https://www.rfc-editor.org/rfc/rfc8017).
30    ///
31    /// > The label parameter is optional. If provided (label.size != 0) then the TPM shall return TPM_RC_VALUE if
32    /// > the last octet in label is not zero. The terminating octet of zero is included in the label used in the padding
33    /// > scheme.
34    /// > If the scheme does not use a label, the TPM will still verify that label is properly formatted if label is
35    /// > present.
36    ///
37    /// # Returns
38    ///
39    /// The encrypted output.
40    ///
41    /// # Example
42    ///
43    /// ```rust
44    /// # use tss_esapi::{
45    /// #    Context, TctiNameConf,
46    /// #    attributes::{SessionAttributesBuilder, ObjectAttributesBuilder},
47    /// #    constants::SessionType,
48    /// #    interface_types::{
49    /// #        algorithm::{
50    /// #            HashingAlgorithm, PublicAlgorithm, RsaDecryptAlgorithm,
51    /// #        },
52    /// #        key_bits::RsaKeyBits,
53    /// #        reserved_handles::Hierarchy,
54    /// #   },
55    /// #   structures::{
56    /// #       Auth, Data, RsaScheme, PublicBuilder, PublicRsaParametersBuilder, PublicKeyRsa,
57    /// #       RsaDecryptionScheme, HashScheme, SymmetricDefinition, RsaExponent,
58    /// #    },
59    /// # };
60    /// # use std::{env, str::FromStr, convert::TryFrom};
61    /// # // Create context
62    /// # let mut context =
63    /// #     Context::new(
64    /// #         TctiNameConf::from_environment_variable().expect("Failed to get TCTI"),
65    /// #     ).expect("Failed to create Context");
66    /// #
67    /// # let session = context
68    /// #     .start_auth_session(
69    /// #         None,
70    /// #         None,
71    /// #         None,
72    /// #         SessionType::Hmac,
73    /// #         SymmetricDefinition::AES_256_CFB,
74    /// #         tss_esapi::interface_types::algorithm::HashingAlgorithm::Sha256,
75    /// #     )
76    /// #     .expect("Failed to create session")
77    /// #     .expect("Received invalid handle");
78    /// # let (session_attributes, session_attributes_mask) = SessionAttributesBuilder::new()
79    /// #     .with_decrypt(true)
80    /// #     .with_encrypt(true)
81    /// #     .build();
82    /// # context.tr_sess_set_attributes(session, session_attributes, session_attributes_mask)
83    /// #     .expect("Failed to set attributes on session");
84    /// # context.set_sessions((Some(session), None, None));
85    /// # let mut random_digest = vec![0u8; 16];
86    /// # getrandom::getrandom(&mut random_digest).unwrap();
87    /// # let key_auth = Auth::from_bytes(random_digest.as_slice()).unwrap();
88    /// #
89    /// # let object_attributes = ObjectAttributesBuilder::new()
90    /// #     .with_fixed_tpm(true)
91    /// #     .with_fixed_parent(true)
92    /// #     .with_sensitive_data_origin(true)
93    /// #     .with_user_with_auth(true)
94    /// #     .with_decrypt(true)
95    /// #     .with_sign_encrypt(true)
96    /// #     .with_restricted(false)
97    /// #     .build()
98    /// #     .expect("Should be able to build object attributes when the attributes are not conflicting.");
99    /// #
100    /// # let key_pub = PublicBuilder::new()
101    /// #     .with_public_algorithm(PublicAlgorithm::Rsa)
102    /// #     .with_name_hashing_algorithm(HashingAlgorithm::Sha256)
103    /// #     .with_object_attributes(object_attributes)
104    /// #     .with_rsa_parameters(
105    /// #         PublicRsaParametersBuilder::new()
106    /// #             .with_scheme(RsaScheme::Null)
107    /// #             .with_key_bits(RsaKeyBits::Rsa2048)
108    /// #             .with_exponent(RsaExponent::default())
109    /// #             .with_is_signing_key(true)
110    /// #             .with_is_decryption_key(true)
111    /// #             .with_restricted(false)
112    /// #             .build()
113    /// #             .expect("Should be possible to build valid RSA parameters")
114    /// #    )
115    /// #    .with_rsa_unique_identifier(PublicKeyRsa::default())
116    /// #    .build()
117    /// #    .expect("Should be possible to build a valid Public object.");
118    /// #
119    /// # let key_handle = context
120    /// #     .create_primary(
121    /// #         Hierarchy::Owner,
122    /// #         key_pub,
123    /// #         None,
124    /// #         None,
125    /// #         None,
126    /// #         None,
127    /// #     )
128    /// #     .expect("Should be possible to create primary key from using valid Public object.")
129    /// #     .key_handle;
130    /// // Because the key was created with RsaScheme::Null it is possible to
131    /// // provide a scheme for the rsa_encrypt function to use.
132    /// let scheme =
133    ///        RsaDecryptionScheme::create(RsaDecryptAlgorithm::Oaep, Some(HashingAlgorithm::Sha256))
134    ///            .expect("Failed to create rsa decryption scheme");
135    /// let plain_text_bytes = vec![1, 2, 3, 4];
136    /// let message_in = PublicKeyRsa::try_from(plain_text_bytes.clone())
137    ///     .expect("Should be possible to create a PublicKeyRsa object from valid bytes.");
138    /// let cipher_text = context.rsa_encrypt(key_handle, message_in, scheme, None)
139    ///     .expect("Should be possible to call rsa_encrypt using valid arguments.");
140    /// # let message_out = context.rsa_decrypt(key_handle, cipher_text, scheme, None)
141    /// #     .expect("Should be possible to call rsa_decrypt using valid arguments.");
142    /// # let decrypted_bytes = message_out.as_bytes();
143    /// # assert_eq!(plain_text_bytes, decrypted_bytes);
144    /// ```
145    pub fn rsa_encrypt(
146        &mut self,
147        key_handle: KeyHandle,
148        message: PublicKeyRsa,
149        in_scheme: RsaDecryptionScheme,
150        label: impl Into<Option<Data>>,
151    ) -> Result<PublicKeyRsa> {
152        let mut out_data_ptr = null_mut();
153        let potential_label = label.into().map(|v| v.into());
154        let label_ptr = potential_label
155            .as_ref()
156            .map_or_else(null, std::ptr::from_ref);
157        ReturnCode::ensure_success(
158            unsafe {
159                Esys_RSA_Encrypt(
160                    self.mut_context(),
161                    key_handle.into(),
162                    self.optional_session_1(),
163                    self.optional_session_2(),
164                    self.optional_session_3(),
165                    &message.into(),
166                    &in_scheme.into(),
167                    label_ptr,
168                    &mut out_data_ptr,
169                )
170            },
171            |ret| {
172                error!("Error when performing RSA encryption: {:#010X}", ret);
173            },
174        )?;
175        PublicKeyRsa::try_from(Context::ffi_data_to_owned(out_data_ptr)?)
176    }
177
178    /// Perform an asymmetric RSA decryption.
179    ///
180    /// # Arguments
181    ///
182    /// * `key_handle`  - A [KeyHandle] of the RSA key to use for decryption.
183    /// * `cipher_text` - The cipher text to be decrypted.
184    /// * `in_scheme`  - The padding scheme to use if scheme associated with
185    ///   the `key_handle` is [RsaDecryptionScheme::Null].
186    /// * `label`       - An optional label whose association with the message is to be verified.
187    ///
188    /// # Details
189    ///
190    /// *From the specification*
191    /// > This command performs RSA decryption using the indicated padding scheme according to IETF RFC
192    /// > 8017 ((PKCS#1).
193    ///
194    /// > If a label is used in the padding process of the scheme during encryption, the label parameter is required
195    /// > to be present in the decryption process and label is required to be the same in both cases. If label is not
196    /// > the same, the decrypt operation is very likely to fail.
197    ///
198    /// # Returns
199    ///
200    /// The decrypted output.
201    ///
202    /// # Example
203    ///
204    /// ```rust
205    /// # use tss_esapi::{
206    /// #    Context, TctiNameConf,
207    /// #    attributes::{SessionAttributesBuilder, ObjectAttributesBuilder},
208    /// #    constants::SessionType,
209    /// #    interface_types::{
210    /// #        algorithm::{
211    /// #            HashingAlgorithm, PublicAlgorithm, RsaDecryptAlgorithm,
212    /// #        },
213    /// #        key_bits::RsaKeyBits,
214    /// #        reserved_handles::Hierarchy,
215    /// #   },
216    /// #   structures::{
217    /// #       Auth, Data, RsaScheme, PublicBuilder, PublicRsaParametersBuilder, PublicKeyRsa,
218    /// #       RsaDecryptionScheme, HashScheme, SymmetricDefinition, RsaExponent,
219    /// #    },
220    /// # };
221    /// # use std::{env, str::FromStr, convert::TryFrom};
222    /// # // Create context
223    /// # let mut context =
224    /// #     Context::new(
225    /// #         TctiNameConf::from_environment_variable().expect("Failed to get TCTI"),
226    /// #     ).expect("Failed to create Context");
227    /// #
228    /// # let session = context
229    /// #     .start_auth_session(
230    /// #         None,
231    /// #         None,
232    /// #         None,
233    /// #         SessionType::Hmac,
234    /// #         SymmetricDefinition::AES_256_CFB,
235    /// #         tss_esapi::interface_types::algorithm::HashingAlgorithm::Sha256,
236    /// #     )
237    /// #     .expect("Failed to create session")
238    /// #     .expect("Received invalid handle");
239    /// # let (session_attributes, session_attributes_mask) = SessionAttributesBuilder::new()
240    /// #     .with_decrypt(true)
241    /// #     .with_encrypt(true)
242    /// #     .build();
243    /// # context.tr_sess_set_attributes(session, session_attributes, session_attributes_mask)
244    /// #     .expect("Failed to set attributes on session");
245    /// # context.set_sessions((Some(session), None, None));
246    /// # let mut random_digest = vec![0u8; 16];
247    /// # getrandom::getrandom(&mut random_digest).unwrap();
248    /// # let key_auth = Auth::from_bytes(random_digest.as_slice()).unwrap();
249    /// #
250    /// # let object_attributes = ObjectAttributesBuilder::new()
251    /// #     .with_fixed_tpm(true)
252    /// #     .with_fixed_parent(true)
253    /// #     .with_sensitive_data_origin(true)
254    /// #     .with_user_with_auth(true)
255    /// #     .with_decrypt(true)
256    /// #     .with_sign_encrypt(true)
257    /// #     .with_restricted(false)
258    /// #     .build()
259    /// #     .expect("Should be able to build object attributes when the attributes are not conflicting.");
260    /// #
261    /// # let key_pub = PublicBuilder::new()
262    /// #     .with_public_algorithm(PublicAlgorithm::Rsa)
263    /// #     .with_name_hashing_algorithm(HashingAlgorithm::Sha256)
264    /// #     .with_object_attributes(object_attributes)
265    /// #     .with_rsa_parameters(
266    /// #         PublicRsaParametersBuilder::new()
267    /// #             .with_scheme(RsaScheme::Null)
268    /// #             .with_key_bits(RsaKeyBits::Rsa2048)
269    /// #             .with_exponent(RsaExponent::default())
270    /// #             .with_is_signing_key(true)
271    /// #             .with_is_decryption_key(true)
272    /// #             .with_restricted(false)
273    /// #             .build()
274    /// #             .expect("Should be possible to build valid RSA parameters")
275    /// #    )
276    /// #    .with_rsa_unique_identifier(PublicKeyRsa::default())
277    /// #    .build()
278    /// #    .expect("Should be possible to build a valid Public object.");
279    /// #
280    /// # let key_handle = context
281    /// #     .create_primary(
282    /// #         Hierarchy::Owner,
283    /// #         key_pub,
284    /// #         None,
285    /// #         None,
286    /// #         None,
287    /// #         None,
288    /// #     )
289    /// #     .expect("Should be possible to create primary key from using valid Public object.")
290    /// #     .key_handle;
291    /// # let scheme =
292    /// #        RsaDecryptionScheme::create(RsaDecryptAlgorithm::RsaEs, None)
293    /// #            .expect("Failed to create rsa decryption scheme");
294    /// # let plain_text_bytes = vec![4, 3, 2, 1, 0];
295    /// # let message_in = PublicKeyRsa::try_from(plain_text_bytes.clone())
296    /// #     .expect("Should be possible to create a PublicKeyRsa object from valid bytes.");
297    /// # let label = Data::default();
298    /// # let cipher_text = context.rsa_encrypt(key_handle, message_in, scheme, label.clone())
299    /// #     .expect("Should be possible to call rsa_encrypt using valid arguments.");
300    /// // label text needs to be the same as the on used when data was encrypted.
301    /// let message_out = context.rsa_decrypt(key_handle, cipher_text, scheme, label)
302    ///     .expect("Should be possible to call rsa_decrypt using valid arguments.");
303    /// let decrypted_bytes = message_out.as_bytes();
304    /// # assert_eq!(plain_text_bytes, decrypted_bytes);
305    /// ```
306    pub fn rsa_decrypt(
307        &mut self,
308        key_handle: KeyHandle,
309        cipher_text: PublicKeyRsa,
310        in_scheme: RsaDecryptionScheme,
311        label: impl Into<Option<Data>>,
312    ) -> Result<PublicKeyRsa> {
313        let mut message_ptr = null_mut();
314        let potential_label = label.into().map(|v| v.into());
315        let label_ptr = potential_label
316            .as_ref()
317            .map_or_else(null, std::ptr::from_ref);
318        ReturnCode::ensure_success(
319            unsafe {
320                Esys_RSA_Decrypt(
321                    self.mut_context(),
322                    key_handle.into(),
323                    self.required_session_1()?,
324                    self.optional_session_2(),
325                    self.optional_session_3(),
326                    &cipher_text.into(),
327                    &in_scheme.into(),
328                    label_ptr,
329                    &mut message_ptr,
330                )
331            },
332            |ret| {
333                error!("Error when performing RSA decryption: {:#010X}", ret);
334            },
335        )?;
336        PublicKeyRsa::try_from(Context::ffi_data_to_owned(message_ptr)?)
337    }
338
339    /// Generate an ephemeral key pair.
340    ///
341    /// # Arguments
342    /// * `key_handle`- A [KeyHandle] of ECC key which curve parameters will be used
343    ///   to generate the ephemeral key.
344    ///
345    /// # Details
346    /// This command uses the TPM to generate an ephemeral
347    /// key pair. It uses the private ephemeral key and a loaded
348    /// public key to compute the shared secret value.
349    ///
350    /// # Example
351    ///
352    /// ```rust
353    /// # use tss_esapi::{
354    /// #    Context, TctiNameConf,
355    /// #    attributes::{SessionAttributesBuilder, ObjectAttributesBuilder},
356    /// #    constants::SessionType,
357    /// #    interface_types::{
358    /// #        algorithm::{
359    /// #            HashingAlgorithm, PublicAlgorithm, RsaDecryptAlgorithm,
360    /// #        },
361    /// #        ecc::EccCurve,
362    /// #        reserved_handles::Hierarchy,
363    /// #   },
364    /// #   structures::{
365    /// #       Auth, Data, EccScheme, PublicBuilder, PublicEccParametersBuilder, PublicKeyRsa, KeyDerivationFunctionScheme, EccPoint,
366    /// #        RsaDecryptionScheme, HashScheme, SymmetricDefinition,
367    /// #    },
368    /// # };
369    /// # use std::{env, str::FromStr, convert::TryFrom};
370    /// # // Create context
371    /// # let mut context =
372    /// #     Context::new(
373    /// #         TctiNameConf::from_environment_variable().expect("Failed to get TCTI"),
374    /// #     ).expect("Failed to create Context");
375    /// #
376    /// # let session = context
377    /// #     .start_auth_session(
378    /// #         None,
379    /// #         None,
380    /// #         None,
381    /// #         SessionType::Hmac,
382    /// #         SymmetricDefinition::AES_256_CFB,
383    /// #         tss_esapi::interface_types::algorithm::HashingAlgorithm::Sha256,
384    /// #     )
385    /// #     .expect("Failed to create session")
386    /// #     .expect("Received invalid handle");
387    /// # let (session_attributes, session_attributes_mask) = SessionAttributesBuilder::new()
388    /// #     .with_decrypt(true)
389    /// #     .with_encrypt(true)
390    /// #     .build();
391    /// # context.tr_sess_set_attributes(session, session_attributes, session_attributes_mask)
392    /// #     .expect("Failed to set attributes on session");
393    /// # context.set_sessions((Some(session), None, None));
394    /// # let mut random_digest = vec![0u8; 16];
395    /// # getrandom::getrandom(&mut random_digest).unwrap();
396    /// # let key_auth = Auth::from_bytes(random_digest.as_slice()).unwrap();
397    /// #
398    /// // Create a key suitable for ECDH key generation
399    /// let ecc_parms = PublicEccParametersBuilder::new()
400    ///     .with_ecc_scheme(
401    ///         EccScheme::EcDh(HashScheme::new(HashingAlgorithm::Sha256)),
402    ///     )
403    ///     .with_curve(EccCurve::NistP256)
404    ///     .with_is_signing_key(false)
405    ///     .with_is_decryption_key(true)
406    ///     .with_restricted(false)
407    ///     .with_key_derivation_function_scheme(KeyDerivationFunctionScheme::Null)
408    ///     .build()
409    ///     .unwrap();
410    ///
411    /// let object_attributes = ObjectAttributesBuilder::new()
412    ///     .with_fixed_tpm(true)
413    ///     .with_fixed_parent(true)
414    ///     .with_sensitive_data_origin(true)
415    ///     .with_user_with_auth(true)
416    ///     .with_decrypt(true)
417    ///     .with_sign_encrypt(false)
418    ///     .with_restricted(false)
419    ///     .build()
420    ///     .unwrap();
421    ///
422    /// let public = PublicBuilder::new()
423    ///     .with_public_algorithm(PublicAlgorithm::Ecc)
424    ///     .with_name_hashing_algorithm(HashingAlgorithm::Sha256)
425    ///     .with_object_attributes(object_attributes)
426    ///     .with_ecc_parameters(ecc_parms)
427    ///     .with_ecc_unique_identifier(EccPoint::default())
428    ///     .build()
429    ///     .unwrap();
430    ///
431    /// let key_handle = context
432    ///     .create_primary(
433    ///         Hierarchy::Owner,
434    ///         public,
435    ///         Some(key_auth),
436    ///         None,
437    ///         None,
438    ///         None,
439    ///     )
440    ///     .unwrap()
441    ///     .key_handle;
442    ///
443    /// // Generate ephemeral key pair and a shared secret
444    /// let (z_point, pub_point) = context.ecdh_key_gen(key_handle).unwrap();
445    /// ```
446    pub fn ecdh_key_gen(&mut self, key_handle: KeyHandle) -> Result<(EccPoint, EccPoint)> {
447        let mut z_point_ptr = null_mut();
448        let mut pub_point_ptr = null_mut();
449        ReturnCode::ensure_success(
450            unsafe {
451                Esys_ECDH_KeyGen(
452                    self.mut_context(),
453                    key_handle.into(),
454                    self.optional_session_1(),
455                    self.optional_session_2(),
456                    self.optional_session_3(),
457                    &mut z_point_ptr,
458                    &mut pub_point_ptr,
459                )
460            },
461            |ret| {
462                error!("Error when generating ECDH key pair: {:#010X}", ret);
463            },
464        )?;
465
466        let z_point = Context::ffi_data_to_owned(z_point_ptr)?;
467        let pub_point = Context::ffi_data_to_owned(pub_point_ptr)?;
468        Ok((
469            EccPoint::try_from(z_point.point)?,
470            EccPoint::try_from(pub_point.point)?,
471        ))
472    }
473
474    /// Recover Z value from a public point and a private key.
475    ///
476    /// # Arguments
477    /// * `key_handle` - A [KeyHandle] of ECC key which curve parameters will be used
478    ///   to generate the ephemeral key.
479    /// * `in_point` - An [EccPoint] on the curve of the key referenced by `key_handle`
480    ///
481    /// # Details
482    /// This command uses the TPM to recover the Z value from a public point and a private key.
483    /// It will perform the multiplication of the provided `in_point` with the private key and
484    /// return the coordinates of the resultant point.
485    ///
486    /// # Example
487    ///
488    /// ```rust
489    /// # use tss_esapi::{
490    /// #    Context, TctiNameConf,
491    /// #    attributes::{SessionAttributesBuilder, ObjectAttributesBuilder},
492    /// #    constants::SessionType,
493    /// #    interface_types::{
494    /// #        algorithm::{
495    /// #            HashingAlgorithm, PublicAlgorithm, RsaDecryptAlgorithm,
496    /// #        },
497    /// #        ecc::EccCurve,
498    /// #        reserved_handles::Hierarchy,
499    /// #   },
500    /// #   structures::{
501    /// #       Auth, Data, EccScheme, PublicBuilder, PublicEccParametersBuilder, PublicKeyRsa, KeyDerivationFunctionScheme, EccPoint,
502    /// #        RsaDecryptionScheme, HashScheme, SymmetricDefinition,
503    /// #    },
504    /// # };
505    /// # use std::{env, str::FromStr, convert::TryFrom};
506    /// # // Create context
507    /// # let mut context =
508    /// #     Context::new(
509    /// #         TctiNameConf::from_environment_variable().expect("Failed to get TCTI"),
510    /// #     ).expect("Failed to create Context");
511    /// #
512    /// # let session = context
513    /// #     .start_auth_session(
514    /// #         None,
515    /// #         None,
516    /// #         None,
517    /// #         SessionType::Hmac,
518    /// #         SymmetricDefinition::AES_256_CFB,
519    /// #         tss_esapi::interface_types::algorithm::HashingAlgorithm::Sha256,
520    /// #     )
521    /// #     .expect("Failed to create session")
522    /// #     .expect("Received invalid handle");
523    /// # let (session_attributes, session_attributes_mask) = SessionAttributesBuilder::new()
524    /// #     .with_decrypt(true)
525    /// #     .with_encrypt(true)
526    /// #     .build();
527    /// # context.tr_sess_set_attributes(session, session_attributes, session_attributes_mask)
528    /// #     .expect("Failed to set attributes on session");
529    /// # context.set_sessions((Some(session), None, None));
530    /// # let mut random_digest = vec![0u8; 16];
531    /// # getrandom::getrandom(&mut random_digest).unwrap();
532    /// # let key_auth = Auth::from_bytes(random_digest.as_slice()).unwrap();
533    /// #
534    /// // Create a key suitable for ECDH key generation
535    /// let ecc_parms = PublicEccParametersBuilder::new()
536    ///     .with_ecc_scheme(
537    ///         EccScheme::EcDh(HashScheme::new(HashingAlgorithm::Sha256)),
538    ///     )
539    ///     .with_curve(EccCurve::NistP256)
540    ///     .with_is_signing_key(false)
541    ///     .with_is_decryption_key(true)
542    ///     .with_restricted(false)
543    ///     .with_key_derivation_function_scheme(KeyDerivationFunctionScheme::Null)
544    ///     .build()
545    ///     .unwrap();
546    ///
547    /// let object_attributes = ObjectAttributesBuilder::new()
548    ///     .with_fixed_tpm(true)
549    ///     .with_fixed_parent(true)
550    ///     .with_sensitive_data_origin(true)
551    ///     .with_user_with_auth(true)
552    ///     .with_decrypt(true)
553    ///     .with_sign_encrypt(false)
554    ///     .with_restricted(false)
555    ///     .build()
556    ///     .unwrap();
557    ///
558    /// let public = PublicBuilder::new()
559    ///     .with_public_algorithm(PublicAlgorithm::Ecc)
560    ///     .with_name_hashing_algorithm(HashingAlgorithm::Sha256)
561    ///     .with_object_attributes(object_attributes)
562    ///     .with_ecc_parameters(ecc_parms)
563    ///     .with_ecc_unique_identifier(EccPoint::default())
564    ///     .build()
565    ///     .unwrap();
566    ///
567    /// let key_handle = context
568    ///     .create_primary(
569    ///         Hierarchy::Owner,
570    ///         public,
571    ///         Some(key_auth),
572    ///         None,
573    ///         None,
574    ///         None,
575    ///     )
576    ///     .unwrap()
577    ///     .key_handle;
578    ///
579    /// // Generate ephemeral key pair and a shared secret
580    /// let (z_point, pub_point) = context.ecdh_key_gen(key_handle).unwrap();
581    /// let z_point_gen = context.ecdh_z_gen(key_handle, pub_point).unwrap();
582    /// assert_eq!(z_point.x().as_bytes(), z_point_gen.x().as_bytes());
583    /// ```
584    pub fn ecdh_z_gen(&mut self, key_handle: KeyHandle, in_point: EccPoint) -> Result<EccPoint> {
585        let mut out_point_ptr = null_mut();
586        ReturnCode::ensure_success(
587            unsafe {
588                Esys_ECDH_ZGen(
589                    self.mut_context(),
590                    key_handle.into(),
591                    self.required_session_1()?,
592                    self.optional_session_2(),
593                    self.optional_session_3(),
594                    &in_point.into(),
595                    &mut out_point_ptr,
596                )
597            },
598            |ret| {
599                error!("Error when performing ECDH ZGen: {:#010X}", ret);
600            },
601        )?;
602        let out_point = Context::ffi_data_to_owned(out_point_ptr)?;
603        EccPoint::try_from(out_point.point)
604    }
605
606    // Missing function: ECC_Parameters
607    // Missing function: ZGen_2Phase
608}