Skip to main content

tss_esapi/context/tpm_commands/
ephemeral_ec_keys.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::ecc::EccCurve,
7    structures::{EccParameter, EccPoint, SensitiveData},
8    tss2_esys::{Esys_Commit, Esys_EC_Ephemeral},
9};
10use log::error;
11use std::convert::TryFrom;
12use std::ptr::null;
13use std::ptr::null_mut;
14
15impl Context {
16    /// Perform an ECC commit to generate ephemeral key pair (K, L) and counter.
17    ///
18    /// # Arguments
19    ///
20    /// * `sign_handle` - A [KeyHandle] of the ECC key for which the commit is being generated.
21    /// * `p1` - An optional point on the curve used by `sign_handle`.
22    /// * `s2` - An optional octet array used in the commit computation.
23    /// * `y2` - An optional ECC parameter used in the commit computation.
24    ///
25    /// # Details
26    ///
27    /// *From the specification*
28    /// > TPM2_Commit() performs the first part of an ECC anonymous signing operation. The TPM will
29    /// > perform the point multiplications on the provided points and return intermediate signing
30    /// > values.
31    ///
32    /// > The TPM shall return TPM_RC_ATTRIBUTES if the sign attribute is not SET in the key
33    /// > referenced by signHandle.
34    ///
35    /// # Returns
36    ///
37    /// A tuple of `(K, L, E, counter)` where K, L, E are [EccPoint] values
38    /// and counter is a `u16` value to be used in the signing operation.
39    ///
40    /// # Example
41    ///
42    /// ```rust
43    /// # use tss_esapi::{
44    /// #    Context, TctiNameConf,
45    /// #    attributes::{SessionAttributesBuilder, ObjectAttributesBuilder},
46    /// #    constants::SessionType,
47    /// #    interface_types::{
48    /// #        algorithm::{HashingAlgorithm, PublicAlgorithm},
49    /// #        ecc::EccCurve,
50    /// #        reserved_handles::Hierarchy,
51    /// #   },
52    /// #   structures::{
53    /// #       Auth, EccPoint, EccScheme, KeyDerivationFunctionScheme,
54    /// #       PublicBuilder, PublicEccParametersBuilder, SymmetricDefinition,
55    /// #    },
56    /// # };
57    /// # let mut context =
58    /// #     Context::new(
59    /// #         TctiNameConf::from_environment_variable().expect("Failed to get TCTI"),
60    /// #     ).expect("Failed to create Context");
61    /// #
62    /// # let session = context
63    /// #     .start_auth_session(
64    /// #         None,
65    /// #         None,
66    /// #         None,
67    /// #         SessionType::Hmac,
68    /// #         SymmetricDefinition::AES_256_CFB,
69    /// #         HashingAlgorithm::Sha256,
70    /// #     )
71    /// #     .expect("Failed to create session")
72    /// #     .expect("Received invalid handle");
73    /// # let (session_attributes, session_attributes_mask) = SessionAttributesBuilder::new()
74    /// #     .with_decrypt(true)
75    /// #     .with_encrypt(true)
76    /// #     .build();
77    /// # context.tr_sess_set_attributes(session, session_attributes, session_attributes_mask)
78    /// #     .expect("Failed to set attributes on session");
79    /// # context.set_sessions((Some(session), None, None));
80    /// # let mut random_digest = vec![0u8; 16];
81    /// # getrandom::getrandom(&mut random_digest).expect("Failed to get random bytes");
82    /// # let key_auth
83    /// #     = Auth::from_bytes(random_digest.as_slice()).expect("Failed to create key auth");
84    /// #
85    /// # let ecc_parms = PublicEccParametersBuilder::new()
86    /// #     .with_ecc_scheme(EccScheme::EcDaa(
87    /// #         tss_esapi::structures::EcDaaScheme::new(HashingAlgorithm::Sha256, 0),
88    /// #     ))
89    /// #     .with_curve(EccCurve::BnP256)
90    /// #     .with_is_signing_key(true)
91    /// #     .with_is_decryption_key(false)
92    /// #     .with_restricted(false)
93    /// #     .with_key_derivation_function_scheme(KeyDerivationFunctionScheme::Null)
94    /// #     .build()
95    /// #     .expect("Failed to build ECC parameters");
96    /// #
97    /// # let object_attributes = ObjectAttributesBuilder::new()
98    /// #     .with_fixed_tpm(true)
99    /// #     .with_fixed_parent(true)
100    /// #     .with_sensitive_data_origin(true)
101    /// #     .with_user_with_auth(true)
102    /// #     .with_decrypt(false)
103    /// #     .with_sign_encrypt(true)
104    /// #     .with_restricted(false)
105    /// #     .build()
106    /// #     .expect("Failed to build object attributes");
107    /// #
108    /// # let public = PublicBuilder::new()
109    /// #     .with_public_algorithm(PublicAlgorithm::Ecc)
110    /// #     .with_name_hashing_algorithm(HashingAlgorithm::Sha256)
111    /// #     .with_object_attributes(object_attributes)
112    /// #     .with_ecc_parameters(ecc_parms)
113    /// #     .with_ecc_unique_identifier(EccPoint::default())
114    /// #     .build()
115    /// #     .expect("Failed to build public key");
116    /// #
117    /// # let key_handle = context
118    /// #     .create_primary(Hierarchy::Owner, public, Some(key_auth), None, None, None)
119    /// #     .expect("Failed to create primary key")
120    /// #     .key_handle;
121    /// let (_k, _l, _e, counter) = context
122    ///     .commit(key_handle, EccPoint::default(), None, None)
123    ///     .expect("Failed to perform ECC commit");
124    /// ```
125    pub fn commit(
126        &mut self,
127        sign_handle: KeyHandle,
128        p1: impl Into<Option<EccPoint>>,
129        s2: impl Into<Option<SensitiveData>>,
130        y2: impl Into<Option<EccParameter>>,
131    ) -> Result<(EccPoint, EccPoint, EccPoint, u16)> {
132        let mut k_ptr = null_mut();
133        let mut l_ptr = null_mut();
134        let mut e_ptr = null_mut();
135        let mut counter: u16 = 0;
136
137        let potential_p1 = p1.into().map(|v| v.into());
138        let p1_ptr = potential_p1.as_ref().map_or_else(null, std::ptr::from_ref);
139
140        let potential_s2 = s2.into().map(|v| v.into());
141        let s2_ptr = potential_s2.as_ref().map_or_else(null, std::ptr::from_ref);
142
143        let potential_y2 = y2.into().map(|v| v.into());
144        let y2_ptr = potential_y2.as_ref().map_or_else(null, std::ptr::from_ref);
145
146        ReturnCode::ensure_success(
147            unsafe {
148                Esys_Commit(
149                    self.mut_context(),
150                    sign_handle.into(),
151                    self.required_session_1()?,
152                    self.optional_session_2(),
153                    self.optional_session_3(),
154                    p1_ptr,
155                    s2_ptr,
156                    y2_ptr,
157                    &mut k_ptr,
158                    &mut l_ptr,
159                    &mut e_ptr,
160                    &mut counter,
161                )
162            },
163            |ret| {
164                error!("Error when performing ECC commit: {:#010X}", ret);
165            },
166        )?;
167
168        let k_point = Context::ffi_data_to_owned(k_ptr)?;
169        let l_point = Context::ffi_data_to_owned(l_ptr)?;
170        let e_point = Context::ffi_data_to_owned(e_ptr)?;
171        Ok((
172            EccPoint::try_from(k_point.point)?,
173            EccPoint::try_from(l_point.point)?,
174            EccPoint::try_from(e_point.point)?,
175            counter,
176        ))
177    }
178
179    /// Create an ephemeral ECC key.
180    ///
181    /// # Arguments
182    ///
183    /// * `curve` - An [EccCurve] specifying the curve for the ephemeral key.
184    ///
185    /// # Details
186    ///
187    /// *From the specification*
188    /// > TPM2_EC_Ephemeral() creates an ephemeral key for use in a two-phase key exchange protocol.
189    ///
190    /// # Returns
191    ///
192    /// A tuple of `(Q, counter)` where Q is an [EccPoint] representing
193    /// the public ephemeral key and counter is a `u16` to be used
194    /// in a subsequent TPM2_Commit().
195    ///
196    /// # Example
197    ///
198    /// ```rust
199    /// # use tss_esapi::{Context, TctiNameConf};
200    /// use tss_esapi::interface_types::ecc::EccCurve;
201    /// # let mut context =
202    /// #     Context::new(
203    /// #         TctiNameConf::from_environment_variable().expect("Failed to get TCTI"),
204    /// #     ).expect("Failed to create Context");
205    /// let (q_point, counter) = context
206    ///     .ec_ephemeral(EccCurve::NistP256)
207    ///     .expect("Failed to create EC ephemeral key");
208    /// ```
209    pub fn ec_ephemeral(&mut self, curve: EccCurve) -> Result<(EccPoint, u16)> {
210        let mut q_ptr = null_mut();
211        let mut counter: u16 = 0;
212
213        ReturnCode::ensure_success(
214            unsafe {
215                Esys_EC_Ephemeral(
216                    self.mut_context(),
217                    self.optional_session_1(),
218                    self.optional_session_2(),
219                    self.optional_session_3(),
220                    curve.into(),
221                    &mut q_ptr,
222                    &mut counter,
223                )
224            },
225            |ret| {
226                error!("Error when creating EC ephemeral key: {:#010X}", ret);
227            },
228        )?;
229
230        let q_point = Context::ffi_data_to_owned(q_ptr)?;
231        Ok((EccPoint::try_from(q_point.point)?, counter))
232    }
233}