/src/spdm-rs/external/ring/src/agreement.rs
Line | Count | Source |
1 | | // Copyright 2015-2017 Brian Smith. |
2 | | // |
3 | | // Permission to use, copy, modify, and/or distribute this software for any |
4 | | // purpose with or without fee is hereby granted, provided that the above |
5 | | // copyright notice and this permission notice appear in all copies. |
6 | | // |
7 | | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
8 | | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
9 | | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY |
10 | | // SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
11 | | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION |
12 | | // OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN |
13 | | // CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
14 | | |
15 | | //! Key Agreement: ECDH, including X25519. |
16 | | //! |
17 | | //! # Example |
18 | | //! |
19 | | //! Note that this example uses X25519, but ECDH using NIST P-256/P-384 is done |
20 | | //! exactly the same way, just substituting |
21 | | //! `agreement::ECDH_P256`/`agreement::ECDH_P384` for `agreement::X25519`. |
22 | | //! |
23 | | //! ``` |
24 | | //! use ring::{agreement, rand}; |
25 | | //! |
26 | | //! let rng = rand::SystemRandom::new(); |
27 | | //! |
28 | | //! let my_private_key = agreement::EphemeralPrivateKey::generate(&agreement::X25519, &rng)?; |
29 | | //! |
30 | | //! // Make `my_public_key` a byte slice containing my public key. In a real |
31 | | //! // application, this would be sent to the peer in an encoded protocol |
32 | | //! // message. |
33 | | //! let my_public_key = my_private_key.compute_public_key()?; |
34 | | //! |
35 | | //! let peer_public_key_bytes = { |
36 | | //! // In a real application, the peer public key would be parsed out of a |
37 | | //! // protocol message. Here we just generate one. |
38 | | //! let peer_private_key = |
39 | | //! agreement::EphemeralPrivateKey::generate(&agreement::X25519, &rng)?; |
40 | | //! peer_private_key.compute_public_key()? |
41 | | //! }; |
42 | | //! |
43 | | //! let peer_public_key = agreement::UnparsedPublicKey::new( |
44 | | //! &agreement::X25519, |
45 | | //! peer_public_key_bytes); |
46 | | //! |
47 | | //! agreement::agree_ephemeral( |
48 | | //! my_private_key, |
49 | | //! &peer_public_key, |
50 | | //! |_key_material| { |
51 | | //! // In a real application, we'd apply a KDF to the key material and the |
52 | | //! // public keys (as recommended in RFC 7748) and then derive session |
53 | | //! // keys from the result. We omit all that here. |
54 | | //! }, |
55 | | //! )?; |
56 | | //! |
57 | | //! # Ok::<(), ring::error::Unspecified>(()) |
58 | | //! ``` |
59 | | |
60 | | // The "NSA Guide" steps here are from from section 3.1, "Ephemeral Unified |
61 | | // Model." |
62 | | |
63 | | use crate::{cpu, debug, ec, error, rand}; |
64 | | |
65 | | pub use crate::ec::{ |
66 | | curve25519::x25519::X25519, |
67 | | suite_b::ecdh::{ECDH_P256, ECDH_P384}, |
68 | | }; |
69 | | |
70 | | /// A key agreement algorithm. |
71 | | pub struct Algorithm { |
72 | | pub(crate) curve: &'static ec::Curve, |
73 | | pub(crate) ecdh: fn( |
74 | | out: &mut [u8], |
75 | | private_key: &ec::Seed, |
76 | | peer_public_key: untrusted::Input, |
77 | | cpu: cpu::Features, |
78 | | ) -> Result<(), error::Unspecified>, |
79 | | } |
80 | | |
81 | | derive_debug_via_field!(Algorithm, curve); |
82 | | |
83 | | impl Eq for Algorithm {} |
84 | | impl PartialEq for Algorithm { |
85 | 0 | fn eq(&self, other: &Self) -> bool { |
86 | 0 | self.curve.id == other.curve.id |
87 | 0 | } |
88 | | } |
89 | | |
90 | | /// An ephemeral private key for use (only) with `agree_ephemeral`. The |
91 | | /// signature of `agree_ephemeral` ensures that an `EphemeralPrivateKey` can be |
92 | | /// used for at most one key agreement. |
93 | | pub struct EphemeralPrivateKey { |
94 | | private_key: ec::Seed, |
95 | | algorithm: &'static Algorithm, |
96 | | } |
97 | | |
98 | | derive_debug_via_field!( |
99 | | EphemeralPrivateKey, |
100 | | stringify!(EphemeralPrivateKey), |
101 | | algorithm |
102 | | ); |
103 | | |
104 | | impl EphemeralPrivateKey { |
105 | | /// Generate a new ephemeral private key for the given algorithm. |
106 | 0 | pub fn generate( |
107 | 0 | alg: &'static Algorithm, |
108 | 0 | rng: &dyn rand::SecureRandom, |
109 | 0 | ) -> Result<Self, error::Unspecified> { |
110 | 0 | let cpu_features = cpu::features(); |
111 | | |
112 | | // NSA Guide Step 1. |
113 | | // |
114 | | // This only handles the key generation part of step 1. The rest of |
115 | | // step one is done by `compute_public_key()`. |
116 | 0 | let private_key = ec::Seed::generate(alg.curve, rng, cpu_features)?; |
117 | 0 | Ok(Self { |
118 | 0 | private_key, |
119 | 0 | algorithm: alg, |
120 | 0 | }) |
121 | 0 | } |
122 | | |
123 | | /// Computes the public key from the private key. |
124 | | #[inline(always)] |
125 | 0 | pub fn compute_public_key(&self) -> Result<PublicKey, error::Unspecified> { |
126 | | // NSA Guide Step 1. |
127 | | // |
128 | | // Obviously, this only handles the part of Step 1 between the private |
129 | | // key generation and the sending of the public key to the peer. `out` |
130 | | // is what should be sent to the peer. |
131 | 0 | self.private_key |
132 | 0 | .compute_public_key(cpu::features()) |
133 | 0 | .map(|public_key| PublicKey { |
134 | 0 | algorithm: self.algorithm, |
135 | 0 | bytes: public_key, |
136 | 0 | }) Unexecuted instantiation: <ring::agreement::EphemeralPrivateKey>::compute_public_key::{closure#0}Unexecuted instantiation: <ring::agreement::EphemeralPrivateKey>::compute_public_key::{closure#0} |
137 | 0 | } |
138 | | |
139 | | /// The algorithm for the private key. |
140 | | #[inline] |
141 | 0 | pub fn algorithm(&self) -> &'static Algorithm { |
142 | 0 | self.algorithm |
143 | 0 | } |
144 | | |
145 | | /// Do not use. |
146 | | #[deprecated] |
147 | | #[cfg(test)] |
148 | | pub fn bytes(&self) -> &[u8] { |
149 | | self.bytes_for_test() |
150 | | } |
151 | | |
152 | | #[cfg(test)] |
153 | | pub(super) fn bytes_for_test(&self) -> &[u8] { |
154 | | self.private_key.bytes_less_safe() |
155 | | } |
156 | | |
157 | | /// Export the private key bytes for secure storage (e.g., checkpoint/resume). |
158 | | /// This is intended for serialization to secure storage only. |
159 | 0 | pub fn export_private_key_bytes(&self) -> &[u8] { |
160 | 0 | self.private_key.bytes_less_safe() |
161 | 0 | } |
162 | | |
163 | | /// Construct an ephemeral private key from raw bytes. |
164 | | /// This is intended for deserialization from secure storage only. |
165 | 0 | pub fn from_private_key_bytes(alg: &'static Algorithm, bytes: &[u8]) -> Result<Self, error::Unspecified> { |
166 | 0 | let private_key = |
167 | 0 | ec::Seed::from_bytes(alg.curve, untrusted::Input::from(bytes), cpu::features())?; |
168 | 0 | Ok(EphemeralPrivateKey { |
169 | 0 | private_key, |
170 | 0 | algorithm: alg, |
171 | 0 | }) |
172 | 0 | } |
173 | | } |
174 | | |
175 | | /// A public key for key agreement. |
176 | | #[derive(Clone)] |
177 | | pub struct PublicKey { |
178 | | algorithm: &'static Algorithm, |
179 | | bytes: ec::PublicKey, |
180 | | } |
181 | | |
182 | | impl AsRef<[u8]> for PublicKey { |
183 | 0 | fn as_ref(&self) -> &[u8] { |
184 | 0 | self.bytes.as_ref() |
185 | 0 | } |
186 | | } |
187 | | |
188 | | impl core::fmt::Debug for PublicKey { |
189 | 0 | fn fmt(&self, f: &mut core::fmt::Formatter) -> Result<(), core::fmt::Error> { |
190 | 0 | f.debug_struct("PublicKey") |
191 | 0 | .field("algorithm", &self.algorithm) |
192 | 0 | .field("bytes", &debug::HexStr(self.as_ref())) |
193 | 0 | .finish() |
194 | 0 | } |
195 | | } |
196 | | |
197 | | impl PublicKey { |
198 | | /// The algorithm for the public key. |
199 | | #[inline] |
200 | 0 | pub fn algorithm(&self) -> &'static Algorithm { |
201 | 0 | self.algorithm |
202 | 0 | } |
203 | | } |
204 | | |
205 | | /// An unparsed, possibly malformed, public key for key agreement. |
206 | | #[derive(Clone, Copy)] |
207 | | pub struct UnparsedPublicKey<B> { |
208 | | algorithm: &'static Algorithm, |
209 | | bytes: B, |
210 | | } |
211 | | |
212 | | impl<B> AsRef<[u8]> for UnparsedPublicKey<B> |
213 | | where |
214 | | B: AsRef<[u8]>, |
215 | | { |
216 | 0 | fn as_ref(&self) -> &[u8] { |
217 | 0 | self.bytes.as_ref() |
218 | 0 | } |
219 | | } |
220 | | |
221 | | impl<B: core::fmt::Debug> core::fmt::Debug for UnparsedPublicKey<B> |
222 | | where |
223 | | B: AsRef<[u8]>, |
224 | | { |
225 | 0 | fn fmt(&self, f: &mut core::fmt::Formatter) -> Result<(), core::fmt::Error> { |
226 | 0 | f.debug_struct("UnparsedPublicKey") |
227 | 0 | .field("algorithm", &self.algorithm) |
228 | 0 | .field("bytes", &debug::HexStr(self.bytes.as_ref())) |
229 | 0 | .finish() |
230 | 0 | } |
231 | | } |
232 | | |
233 | | impl<B> UnparsedPublicKey<B> { |
234 | | /// Constructs a new `UnparsedPublicKey`. |
235 | 0 | pub fn new(algorithm: &'static Algorithm, bytes: B) -> Self { |
236 | 0 | Self { algorithm, bytes } |
237 | 0 | } Unexecuted instantiation: <ring::agreement::UnparsedPublicKey<&[u8]>>::new Unexecuted instantiation: <ring::agreement::UnparsedPublicKey<_>>::new |
238 | | |
239 | | /// The algorithm for the public key. |
240 | | #[inline] |
241 | 0 | pub fn algorithm(&self) -> &'static Algorithm { |
242 | 0 | self.algorithm |
243 | 0 | } |
244 | | |
245 | | /// TODO: doc |
246 | | #[inline] |
247 | 0 | pub fn bytes(&self) -> &B { |
248 | 0 | &self.bytes |
249 | 0 | } |
250 | | } |
251 | | |
252 | | /// Performs a key agreement with an ephemeral private key and the given public |
253 | | /// key. |
254 | | /// |
255 | | /// `my_private_key` is the ephemeral private key to use. Since it is moved, it |
256 | | /// will not be usable after calling `agree_ephemeral`, thus guaranteeing that |
257 | | /// the key is used for only one key agreement. |
258 | | /// |
259 | | /// `peer_public_key` is the peer's public key. `agree_ephemeral` will return |
260 | | /// `Err(error_value)` if it does not match `my_private_key's` algorithm/curve. |
261 | | /// `agree_ephemeral` verifies that it is encoded in the standard form for the |
262 | | /// algorithm and that the key is *valid*; see the algorithm's documentation for |
263 | | /// details on how keys are to be encoded and what constitutes a valid key for |
264 | | /// that algorithm. |
265 | | /// |
266 | | /// After the key agreement is done, `agree_ephemeral` calls `kdf` with the raw |
267 | | /// key material from the key agreement operation and then returns what `kdf` |
268 | | /// returns. |
269 | | #[inline] |
270 | 0 | pub fn agree_ephemeral<B: AsRef<[u8]>, R>( |
271 | 0 | my_private_key: EphemeralPrivateKey, |
272 | 0 | peer_public_key: &UnparsedPublicKey<B>, |
273 | 0 | kdf: impl FnOnce(&[u8]) -> R, |
274 | 0 | ) -> Result<R, error::Unspecified> { |
275 | 0 | let peer_public_key = UnparsedPublicKey { |
276 | 0 | algorithm: peer_public_key.algorithm, |
277 | 0 | bytes: peer_public_key.bytes.as_ref(), |
278 | 0 | }; |
279 | 0 | agree_ephemeral_(my_private_key, peer_public_key, kdf, cpu::features()) |
280 | 0 | } Unexecuted instantiation: ring::agreement::agree_ephemeral::<&[u8], (), <spdmlib::crypto::spdm_ring::dhe_impl::SpdmDheKeyExchangeP256 as spdmlib::crypto::crypto_callbacks::SpdmDheKeyExchange>::compute_final_key::{closure#0}>Unexecuted instantiation: ring::agreement::agree_ephemeral::<&[u8], (), <spdmlib::crypto::spdm_ring::dhe_impl::SpdmDheKeyExchangeP384 as spdmlib::crypto::crypto_callbacks::SpdmDheKeyExchange>::compute_final_key::{closure#0}>Unexecuted instantiation: ring::agreement::agree_ephemeral::<_, _, _> |
281 | | |
282 | 0 | fn agree_ephemeral_<R>( |
283 | 0 | my_private_key: EphemeralPrivateKey, |
284 | 0 | peer_public_key: UnparsedPublicKey<&[u8]>, |
285 | 0 | kdf: impl FnOnce(&[u8]) -> R, |
286 | 0 | cpu: cpu::Features, |
287 | 0 | ) -> Result<R, error::Unspecified> { |
288 | | // NSA Guide Prerequisite 1. |
289 | | // |
290 | | // The domain parameters are hard-coded. This check verifies that the |
291 | | // peer's public key's domain parameters match the domain parameters of |
292 | | // this private key. |
293 | 0 | if peer_public_key.algorithm != my_private_key.algorithm { |
294 | 0 | return Err(error::Unspecified); |
295 | 0 | } |
296 | | |
297 | 0 | let alg = &my_private_key.algorithm; |
298 | | |
299 | | // NSA Guide Prerequisite 2, regarding which KDFs are allowed, is delegated |
300 | | // to the caller. |
301 | | |
302 | | // NSA Guide Prerequisite 3, "Prior to or during the key-agreement process, |
303 | | // each party shall obtain the identifier associated with the other party |
304 | | // during the key-agreement scheme," is delegated to the caller. |
305 | | |
306 | | // NSA Guide Step 1 is handled by `EphemeralPrivateKey::generate()` and |
307 | | // `EphemeralPrivateKey::compute_public_key()`. |
308 | | |
309 | 0 | let mut shared_key = [0u8; ec::ELEM_MAX_BYTES]; |
310 | 0 | let shared_key = &mut shared_key[..alg.curve.elem_scalar_seed_len]; |
311 | | |
312 | | // NSA Guide Steps 2, 3, and 4. |
313 | | // |
314 | | // We have a pretty liberal interpretation of the NIST's spec's "Destroy" |
315 | | // that doesn't meet the NSA requirement to "zeroize." |
316 | 0 | (alg.ecdh)( |
317 | 0 | shared_key, |
318 | 0 | &my_private_key.private_key, |
319 | 0 | untrusted::Input::from(peer_public_key.bytes), |
320 | 0 | cpu, |
321 | 0 | )?; |
322 | | |
323 | | // NSA Guide Steps 5 and 6. |
324 | | // |
325 | | // Again, we have a pretty liberal interpretation of the NIST's spec's |
326 | | // "Destroy" that doesn't meet the NSA requirement to "zeroize." |
327 | 0 | Ok(kdf(shared_key)) |
328 | 0 | } Unexecuted instantiation: ring::agreement::agree_ephemeral_::<(), <spdmlib::crypto::spdm_ring::dhe_impl::SpdmDheKeyExchangeP256 as spdmlib::crypto::crypto_callbacks::SpdmDheKeyExchange>::compute_final_key::{closure#0}>Unexecuted instantiation: ring::agreement::agree_ephemeral_::<(), <spdmlib::crypto::spdm_ring::dhe_impl::SpdmDheKeyExchangeP384 as spdmlib::crypto::crypto_callbacks::SpdmDheKeyExchange>::compute_final_key::{closure#0}>Unexecuted instantiation: ring::agreement::agree_ephemeral_::<_, _> |