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}