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}