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}