/rust/registry/src/index.crates.io-1949cf8c6b5b557f/aws-lc-rs-1.16.3/src/agreement.rs
Line | Count | Source |
1 | | // Copyright 2015-2017 Brian Smith. |
2 | | // SPDX-License-Identifier: ISC |
3 | | // Modifications copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. |
4 | | // SPDX-License-Identifier: Apache-2.0 OR ISC |
5 | | |
6 | | //! Key Agreement: ECDH, including X25519. |
7 | | //! |
8 | | //! # Example |
9 | | //! |
10 | | //! Note that this example uses X25519, but ECDH using NIST P-256/P-384 is done |
11 | | //! exactly the same way, just substituting |
12 | | //! `agreement::ECDH_P256`/`agreement::ECDH_P384` for `agreement::X25519`. |
13 | | //! |
14 | | //! ``` |
15 | | //! use aws_lc_rs::{agreement, rand}; |
16 | | //! |
17 | | //! let rng = rand::SystemRandom::new(); |
18 | | //! |
19 | | //! let my_private_key = agreement::EphemeralPrivateKey::generate(&agreement::X25519, &rng)?; |
20 | | //! |
21 | | //! // Make `my_public_key` a byte slice containing my public key. In a real |
22 | | //! // application, this would be sent to the peer in an encoded protocol |
23 | | //! // message. |
24 | | //! let my_public_key = my_private_key.compute_public_key()?; |
25 | | //! |
26 | | //! let peer_public_key = { |
27 | | //! // In a real application, the peer public key would be parsed out of a |
28 | | //! // protocol message. Here we just generate one. |
29 | | //! let peer_public_key = { |
30 | | //! let peer_private_key = |
31 | | //! agreement::EphemeralPrivateKey::generate(&agreement::X25519, &rng)?; |
32 | | //! peer_private_key.compute_public_key()? |
33 | | //! }; |
34 | | //! |
35 | | //! agreement::UnparsedPublicKey::new(&agreement::X25519, peer_public_key) |
36 | | //! }; |
37 | | //! |
38 | | //! agreement::agree_ephemeral( |
39 | | //! my_private_key, |
40 | | //! &peer_public_key, |
41 | | //! aws_lc_rs::error::Unspecified, |
42 | | //! |_key_material| { |
43 | | //! // In a real application, we'd apply a KDF to the key material and the |
44 | | //! // public keys (as recommended in RFC 7748) and then derive session |
45 | | //! // keys from the result. We omit all that here. |
46 | | //! Ok(()) |
47 | | //! }, |
48 | | //! )?; |
49 | | //! |
50 | | //! # Ok::<(), aws_lc_rs::error::Unspecified>(()) |
51 | | //! ``` |
52 | | mod ephemeral; |
53 | | |
54 | | use crate::ec::encoding::sec1::{ |
55 | | marshal_sec1_private_key, marshal_sec1_public_point, marshal_sec1_public_point_into_buffer, |
56 | | parse_sec1_private_bn, parse_sec1_public_point, |
57 | | }; |
58 | | #[cfg(not(feature = "fips"))] |
59 | | use crate::ec::verify_evp_key_nid; |
60 | | use crate::ec::{evp_key_generate, validate_ec_evp_key}; |
61 | | use crate::error::{KeyRejected, Unspecified}; |
62 | | use crate::hex; |
63 | | pub use ephemeral::{agree_ephemeral, EphemeralPrivateKey}; |
64 | | |
65 | | use crate::aws_lc::{ |
66 | | i2d_ECPrivateKey, EVP_PKEY_get0_EC_KEY, NID_X9_62_prime256v1, NID_secp384r1, NID_secp521r1, |
67 | | EVP_PKEY, EVP_PKEY_EC, EVP_PKEY_X25519, NID_X25519, |
68 | | }; |
69 | | |
70 | | use crate::buffer::Buffer; |
71 | | use crate::ec; |
72 | | use crate::ec::encoding::rfc5915::parse_rfc5915_private_key; |
73 | | use crate::encoding::{ |
74 | | AsBigEndian, AsDer, Curve25519SeedBin, EcPrivateKeyBin, EcPrivateKeyRfc5915Der, |
75 | | EcPublicKeyCompressedBin, EcPublicKeyUncompressedBin, Pkcs8V1Der, PublicKeyX509Der, |
76 | | }; |
77 | | use crate::evp_pkey::No_EVP_PKEY_CTX_consumer; |
78 | | use crate::pkcs8::Version; |
79 | | use crate::ptr::LcPtr; |
80 | | use core::fmt; |
81 | | use core::fmt::{Debug, Formatter}; |
82 | | use core::ptr::null_mut; |
83 | | |
84 | | #[allow(non_camel_case_types)] |
85 | | #[derive(PartialEq, Eq)] |
86 | | enum AlgorithmID { |
87 | | ECDH_P256, |
88 | | ECDH_P384, |
89 | | ECDH_P521, |
90 | | X25519, |
91 | | } |
92 | | |
93 | | impl AlgorithmID { |
94 | | #[inline] |
95 | 0 | const fn nid(&self) -> i32 { |
96 | 0 | match self { |
97 | 0 | AlgorithmID::ECDH_P256 => NID_X9_62_prime256v1, |
98 | 0 | AlgorithmID::ECDH_P384 => NID_secp384r1, |
99 | 0 | AlgorithmID::ECDH_P521 => NID_secp521r1, |
100 | 0 | AlgorithmID::X25519 => NID_X25519, |
101 | | } |
102 | 0 | } Unexecuted instantiation: <aws_lc_rs::agreement::AlgorithmID>::nid Unexecuted instantiation: <aws_lc_rs::agreement::AlgorithmID>::nid |
103 | | |
104 | | // Uncompressed public key length in bytes |
105 | | #[inline] |
106 | 0 | const fn pub_key_len(&self) -> usize { |
107 | 0 | match self { |
108 | 0 | AlgorithmID::ECDH_P256 => ec::uncompressed_public_key_size_bytes(256), |
109 | 0 | AlgorithmID::ECDH_P384 => ec::uncompressed_public_key_size_bytes(384), |
110 | 0 | AlgorithmID::ECDH_P521 => ec::uncompressed_public_key_size_bytes(521), |
111 | 0 | AlgorithmID::X25519 => 32, |
112 | | } |
113 | 0 | } |
114 | | |
115 | | #[inline] |
116 | 0 | const fn private_key_len(&self) -> usize { |
117 | 0 | match self { |
118 | 0 | AlgorithmID::ECDH_P256 | AlgorithmID::X25519 => 32, |
119 | 0 | AlgorithmID::ECDH_P384 => 48, |
120 | 0 | AlgorithmID::ECDH_P521 => 66, |
121 | | } |
122 | 0 | } |
123 | | } |
124 | | |
125 | | impl Debug for AlgorithmID { |
126 | 0 | fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> { |
127 | 0 | let output = match self { |
128 | 0 | AlgorithmID::ECDH_P256 => "curve: P256", |
129 | 0 | AlgorithmID::ECDH_P384 => "curve: P384", |
130 | 0 | AlgorithmID::ECDH_P521 => "curve: P521", |
131 | 0 | AlgorithmID::X25519 => "curve: Curve25519", |
132 | | }; |
133 | 0 | f.write_str(output) |
134 | 0 | } |
135 | | } |
136 | | |
137 | | /// A key agreement algorithm. |
138 | | #[derive(PartialEq, Eq)] |
139 | | pub struct Algorithm { |
140 | | id: AlgorithmID, |
141 | | } |
142 | | |
143 | | impl Debug for Algorithm { |
144 | 0 | fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> { |
145 | 0 | f.write_str(&format!("Algorithm {{ {:?} }}", self.id)) |
146 | 0 | } |
147 | | } |
148 | | |
149 | | /// ECDH using the NSA Suite B P-256 (secp256r1) curve. |
150 | | pub const ECDH_P256: Algorithm = Algorithm { |
151 | | id: AlgorithmID::ECDH_P256, |
152 | | }; |
153 | | |
154 | | /// ECDH using the NSA Suite B P-384 (secp384r1) curve. |
155 | | pub const ECDH_P384: Algorithm = Algorithm { |
156 | | id: AlgorithmID::ECDH_P384, |
157 | | }; |
158 | | |
159 | | /// ECDH using the NSA Suite B P-521 (secp521r1) curve. |
160 | | pub const ECDH_P521: Algorithm = Algorithm { |
161 | | id: AlgorithmID::ECDH_P521, |
162 | | }; |
163 | | |
164 | | /// X25519 (ECDH using Curve25519) as described in [RFC 7748]. |
165 | | /// |
166 | | /// Everything is as described in RFC 7748. Key agreement will fail if the |
167 | | /// result of the X25519 operation is zero; see the notes on the |
168 | | /// "all-zero value" in [RFC 7748 section 6.1]. |
169 | | /// |
170 | | /// [RFC 7748]: https://tools.ietf.org/html/rfc7748 |
171 | | /// [RFC 7748 section 6.1]: https://tools.ietf.org/html/rfc7748#section-6.1 |
172 | | pub const X25519: Algorithm = Algorithm { |
173 | | id: AlgorithmID::X25519, |
174 | | }; |
175 | | |
176 | | #[allow(non_camel_case_types)] |
177 | | enum KeyInner { |
178 | | ECDH_P256(LcPtr<EVP_PKEY>), |
179 | | ECDH_P384(LcPtr<EVP_PKEY>), |
180 | | ECDH_P521(LcPtr<EVP_PKEY>), |
181 | | X25519(LcPtr<EVP_PKEY>), |
182 | | } |
183 | | |
184 | | impl Clone for KeyInner { |
185 | 0 | fn clone(&self) -> KeyInner { |
186 | 0 | match self { |
187 | 0 | KeyInner::ECDH_P256(evp_pkey) => KeyInner::ECDH_P256(evp_pkey.clone()), |
188 | 0 | KeyInner::ECDH_P384(evp_pkey) => KeyInner::ECDH_P384(evp_pkey.clone()), |
189 | 0 | KeyInner::ECDH_P521(evp_pkey) => KeyInner::ECDH_P521(evp_pkey.clone()), |
190 | 0 | KeyInner::X25519(evp_pkey) => KeyInner::X25519(evp_pkey.clone()), |
191 | | } |
192 | 0 | } |
193 | | } |
194 | | |
195 | | /// A private key for use (only) with `agree`. The |
196 | | /// signature of `agree` allows `PrivateKey` to be |
197 | | /// used for more than one key agreement. |
198 | | pub struct PrivateKey { |
199 | | inner_key: KeyInner, |
200 | | } |
201 | | |
202 | | impl KeyInner { |
203 | | #[inline] |
204 | 0 | fn algorithm(&self) -> &'static Algorithm { |
205 | 0 | match self { |
206 | 0 | KeyInner::ECDH_P256(..) => &ECDH_P256, |
207 | 0 | KeyInner::ECDH_P384(..) => &ECDH_P384, |
208 | 0 | KeyInner::ECDH_P521(..) => &ECDH_P521, |
209 | 0 | KeyInner::X25519(..) => &X25519, |
210 | | } |
211 | 0 | } Unexecuted instantiation: <aws_lc_rs::agreement::KeyInner>::algorithm Unexecuted instantiation: <aws_lc_rs::agreement::KeyInner>::algorithm |
212 | | |
213 | 0 | fn get_evp_pkey(&self) -> &LcPtr<EVP_PKEY> { |
214 | 0 | match self { |
215 | 0 | KeyInner::ECDH_P256(evp_pkey) |
216 | 0 | | KeyInner::ECDH_P384(evp_pkey) |
217 | 0 | | KeyInner::ECDH_P521(evp_pkey) |
218 | 0 | | KeyInner::X25519(evp_pkey) => evp_pkey, |
219 | | } |
220 | 0 | } |
221 | | } |
222 | | |
223 | | // See EVP_PKEY documentation here: |
224 | | // https://github.com/aws/aws-lc/blob/125af14c57451565b875fbf1282a38a6ecf83782/include/openssl/evp.h#L83-L89 |
225 | | // An |EVP_PKEY| object represents a public or private key. A given object may |
226 | | // be used concurrently on multiple threads by non-mutating functions, provided |
227 | | // no other thread is concurrently calling a mutating function. Unless otherwise |
228 | | // documented, functions which take a |const| pointer are non-mutating and |
229 | | // functions which take a non-|const| pointer are mutating. |
230 | | unsafe impl Send for PrivateKey {} |
231 | | unsafe impl Sync for PrivateKey {} |
232 | | |
233 | | impl Debug for PrivateKey { |
234 | 0 | fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> { |
235 | 0 | f.write_str(&format!( |
236 | 0 | "PrivateKey {{ algorithm: {:?} }}", |
237 | 0 | self.inner_key.algorithm() |
238 | 0 | )) |
239 | 0 | } |
240 | | } |
241 | | |
242 | | impl PrivateKey { |
243 | 0 | fn new(alg: &'static Algorithm, evp_pkey: LcPtr<EVP_PKEY>) -> Self { |
244 | 0 | match alg.id { |
245 | 0 | AlgorithmID::X25519 => Self { |
246 | 0 | inner_key: KeyInner::X25519(evp_pkey), |
247 | 0 | }, |
248 | 0 | AlgorithmID::ECDH_P256 => Self { |
249 | 0 | inner_key: KeyInner::ECDH_P256(evp_pkey), |
250 | 0 | }, |
251 | 0 | AlgorithmID::ECDH_P384 => Self { |
252 | 0 | inner_key: KeyInner::ECDH_P384(evp_pkey), |
253 | 0 | }, |
254 | 0 | AlgorithmID::ECDH_P521 => Self { |
255 | 0 | inner_key: KeyInner::ECDH_P521(evp_pkey), |
256 | 0 | }, |
257 | | } |
258 | 0 | } |
259 | | |
260 | | #[inline] |
261 | | /// Generate a new private key for the given algorithm. |
262 | | // # FIPS |
263 | | // Use this function with one of the following algorithms: |
264 | | // * `ECDH_P256` |
265 | | // * `ECDH_P384` |
266 | | // * `ECDH_P521` |
267 | | // |
268 | | /// # Errors |
269 | | /// `error::Unspecified` when operation fails due to internal error. |
270 | 0 | pub fn generate(alg: &'static Algorithm) -> Result<Self, Unspecified> { |
271 | 0 | let evp_pkey = match alg.id { |
272 | 0 | AlgorithmID::X25519 => generate_x25519()?, |
273 | 0 | _ => evp_key_generate(alg.id.nid())?, |
274 | | }; |
275 | 0 | Ok(Self::new(alg, evp_pkey)) |
276 | 0 | } Unexecuted instantiation: <aws_lc_rs::agreement::PrivateKey>::generate Unexecuted instantiation: <aws_lc_rs::agreement::PrivateKey>::generate |
277 | | |
278 | | /// Deserializes a DER-encoded private key structure to produce a `agreement::PrivateKey`. |
279 | | /// |
280 | | /// This function is typically used to deserialize RFC 5915 encoded private keys, but it will |
281 | | /// attempt to automatically detect other key formats. This function supports unencrypted |
282 | | /// PKCS#8 `PrivateKeyInfo` structures as well as key type specific formats. |
283 | | /// |
284 | | /// X25519 keys are not supported. See `PrivateKey::as_der`. |
285 | | /// |
286 | | /// # Errors |
287 | | /// `error::KeyRejected` if parsing failed or key otherwise unacceptable. |
288 | | /// |
289 | | /// # Panics |
290 | 0 | pub fn from_private_key_der( |
291 | 0 | alg: &'static Algorithm, |
292 | 0 | key_bytes: &[u8], |
293 | 0 | ) -> Result<Self, KeyRejected> { |
294 | 0 | if AlgorithmID::X25519 == alg.id { |
295 | 0 | return Err(KeyRejected::invalid_encoding()); |
296 | 0 | } |
297 | 0 | let evp_pkey = LcPtr::<EVP_PKEY>::parse_rfc5208_private_key(key_bytes, EVP_PKEY_EC) |
298 | 0 | .or(parse_rfc5915_private_key(key_bytes, alg.id.nid()))?; |
299 | | #[cfg(not(feature = "fips"))] |
300 | 0 | verify_evp_key_nid(&evp_pkey.as_const(), alg.id.nid())?; |
301 | | #[cfg(feature = "fips")] |
302 | | validate_ec_evp_key(&evp_pkey.as_const(), alg.id.nid())?; |
303 | | |
304 | 0 | Ok(Self::new(alg, evp_pkey)) |
305 | 0 | } |
306 | | |
307 | | /// Constructs an ECDH key from private key bytes |
308 | | /// |
309 | | /// The private key must encoded as a big-endian fixed-length integer. For |
310 | | /// example, a P-256 private key must be 32 bytes prefixed with leading |
311 | | /// zeros as needed. |
312 | | /// |
313 | | /// # Errors |
314 | | /// `error::KeyRejected` if parsing failed or key otherwise unacceptable. |
315 | 0 | pub fn from_private_key( |
316 | 0 | alg: &'static Algorithm, |
317 | 0 | key_bytes: &[u8], |
318 | 0 | ) -> Result<Self, KeyRejected> { |
319 | 0 | if key_bytes.len() != alg.id.private_key_len() { |
320 | 0 | return Err(KeyRejected::wrong_algorithm()); |
321 | 0 | } |
322 | 0 | let evp_pkey = if AlgorithmID::X25519 == alg.id { |
323 | 0 | LcPtr::<EVP_PKEY>::parse_raw_private_key(key_bytes, EVP_PKEY_X25519)? |
324 | | } else { |
325 | 0 | parse_sec1_private_bn(key_bytes, alg.id.nid())? |
326 | | }; |
327 | 0 | Ok(Self::new(alg, evp_pkey)) |
328 | 0 | } |
329 | | |
330 | | #[cfg(any(test, dev_tests_only))] |
331 | | #[allow(missing_docs, clippy::missing_errors_doc)] |
332 | | pub fn generate_for_test( |
333 | | alg: &'static Algorithm, |
334 | | rng: &mut dyn crate::rand::SecureRandom, |
335 | | ) -> Result<Self, Unspecified> { |
336 | | match alg.id { |
337 | | AlgorithmID::X25519 => { |
338 | | let mut priv_key = [0u8; AlgorithmID::X25519.private_key_len()]; |
339 | | rng.mut_fill(&mut priv_key)?; |
340 | | Self::from_x25519_private_key(&priv_key) |
341 | | } |
342 | | AlgorithmID::ECDH_P256 => { |
343 | | let mut priv_key = [0u8; AlgorithmID::ECDH_P256.private_key_len()]; |
344 | | rng.mut_fill(&mut priv_key)?; |
345 | | Self::from_p256_private_key(&priv_key) |
346 | | } |
347 | | AlgorithmID::ECDH_P384 => { |
348 | | let mut priv_key = [0u8; AlgorithmID::ECDH_P384.private_key_len()]; |
349 | | rng.mut_fill(&mut priv_key)?; |
350 | | Self::from_p384_private_key(&priv_key) |
351 | | } |
352 | | AlgorithmID::ECDH_P521 => { |
353 | | let mut priv_key = [0u8; AlgorithmID::ECDH_P521.private_key_len()]; |
354 | | rng.mut_fill(&mut priv_key)?; |
355 | | Self::from_p521_private_key(&priv_key) |
356 | | } |
357 | | } |
358 | | } |
359 | | |
360 | | #[cfg(any(test, dev_tests_only))] |
361 | | fn from_x25519_private_key( |
362 | | priv_key: &[u8; AlgorithmID::X25519.private_key_len()], |
363 | | ) -> Result<Self, Unspecified> { |
364 | | let pkey = LcPtr::<EVP_PKEY>::parse_raw_private_key(priv_key, EVP_PKEY_X25519)?; |
365 | | |
366 | | Ok(PrivateKey { |
367 | | inner_key: KeyInner::X25519(pkey), |
368 | | }) |
369 | | } |
370 | | |
371 | | #[cfg(any(test, dev_tests_only))] |
372 | | fn from_p256_private_key(priv_key: &[u8]) -> Result<Self, Unspecified> { |
373 | | let pkey = parse_sec1_private_bn(priv_key, ECDH_P256.id.nid())?; |
374 | | Ok(PrivateKey { |
375 | | inner_key: KeyInner::ECDH_P256(pkey), |
376 | | }) |
377 | | } |
378 | | |
379 | | #[cfg(any(test, dev_tests_only))] |
380 | | fn from_p384_private_key(priv_key: &[u8]) -> Result<Self, Unspecified> { |
381 | | let pkey = parse_sec1_private_bn(priv_key, ECDH_P384.id.nid())?; |
382 | | Ok(PrivateKey { |
383 | | inner_key: KeyInner::ECDH_P384(pkey), |
384 | | }) |
385 | | } |
386 | | |
387 | | #[cfg(any(test, dev_tests_only))] |
388 | | fn from_p521_private_key(priv_key: &[u8]) -> Result<Self, Unspecified> { |
389 | | let pkey = parse_sec1_private_bn(priv_key, ECDH_P521.id.nid())?; |
390 | | Ok(PrivateKey { |
391 | | inner_key: KeyInner::ECDH_P521(pkey), |
392 | | }) |
393 | | } |
394 | | |
395 | | /// Computes the public key from the private key. |
396 | | /// |
397 | | /// # Errors |
398 | | /// `error::Unspecified` when operation fails due to internal error. |
399 | 0 | pub fn compute_public_key(&self) -> Result<PublicKey, Unspecified> { |
400 | 0 | match &self.inner_key { |
401 | 0 | KeyInner::ECDH_P256(evp_pkey) |
402 | 0 | | KeyInner::ECDH_P384(evp_pkey) |
403 | 0 | | KeyInner::ECDH_P521(evp_pkey) => { |
404 | 0 | let mut public_key = [0u8; MAX_PUBLIC_KEY_LEN]; |
405 | 0 | let len = marshal_sec1_public_point_into_buffer(&mut public_key, evp_pkey, false)?; |
406 | 0 | Ok(PublicKey { |
407 | 0 | inner_key: self.inner_key.clone(), |
408 | 0 | key_bytes: public_key, |
409 | 0 | len, |
410 | 0 | }) |
411 | | } |
412 | 0 | KeyInner::X25519(priv_key) => { |
413 | 0 | let mut buffer = [0u8; MAX_PUBLIC_KEY_LEN]; |
414 | 0 | let out_len = priv_key |
415 | 0 | .as_const() |
416 | 0 | .marshal_raw_public_to_buffer(&mut buffer)?; |
417 | 0 | Ok(PublicKey { |
418 | 0 | inner_key: self.inner_key.clone(), |
419 | 0 | key_bytes: buffer, |
420 | 0 | len: out_len, |
421 | 0 | }) |
422 | | } |
423 | | } |
424 | 0 | } |
425 | | |
426 | | /// The algorithm for the private key. |
427 | | #[inline] |
428 | | #[must_use] |
429 | 0 | pub fn algorithm(&self) -> &'static Algorithm { |
430 | 0 | self.inner_key.algorithm() |
431 | 0 | } Unexecuted instantiation: <aws_lc_rs::agreement::PrivateKey>::algorithm Unexecuted instantiation: <aws_lc_rs::agreement::PrivateKey>::algorithm |
432 | | } |
433 | | |
434 | | impl AsDer<EcPrivateKeyRfc5915Der<'static>> for PrivateKey { |
435 | | /// Serializes the key as a DER-encoded `ECPrivateKey` (RFC 5915) structure. |
436 | | /// |
437 | | /// X25519 is not supported. |
438 | | /// |
439 | | /// # Errors |
440 | | /// `error::Unspecified` if serialization failed. |
441 | 0 | fn as_der(&self) -> Result<EcPrivateKeyRfc5915Der<'static>, Unspecified> { |
442 | 0 | if AlgorithmID::X25519 == self.inner_key.algorithm().id { |
443 | 0 | return Err(Unspecified); |
444 | 0 | } |
445 | | |
446 | 0 | let mut outp = null_mut::<u8>(); |
447 | 0 | let ec_key = { |
448 | 0 | self.inner_key |
449 | 0 | .get_evp_pkey() |
450 | 0 | .project_const_lifetime(unsafe { |
451 | 0 | |evp_pkey| EVP_PKEY_get0_EC_KEY(evp_pkey.as_const_ptr()) |
452 | 0 | })? |
453 | | }; |
454 | 0 | let length = usize::try_from(unsafe { i2d_ECPrivateKey(ec_key.as_const_ptr(), &mut outp) }) |
455 | 0 | .map_err(|_| Unspecified)?; |
456 | 0 | let mut outp = LcPtr::new(outp)?; |
457 | 0 | Ok(EcPrivateKeyRfc5915Der::take_from_slice(unsafe { |
458 | 0 | core::slice::from_raw_parts_mut(outp.as_mut_ptr(), length) |
459 | 0 | })) |
460 | 0 | } |
461 | | } |
462 | | |
463 | | impl AsDer<Pkcs8V1Der<'static>> for PrivateKey { |
464 | | /// Serializes the key as a PKCS #8 private key structure. |
465 | | /// |
466 | | /// X25519 is not supported. |
467 | | /// |
468 | | /// # Errors |
469 | | /// `error::Unspecified` if serialization failed. |
470 | 0 | fn as_der(&self) -> Result<Pkcs8V1Der<'static>, Unspecified> { |
471 | 0 | if AlgorithmID::X25519 == self.inner_key.algorithm().id { |
472 | 0 | return Err(Unspecified); |
473 | 0 | } |
474 | | |
475 | 0 | Ok(Pkcs8V1Der::new( |
476 | 0 | self.inner_key |
477 | 0 | .get_evp_pkey() |
478 | 0 | .as_const() |
479 | 0 | .marshal_rfc5208_private_key(Version::V1)?, |
480 | | )) |
481 | 0 | } |
482 | | } |
483 | | |
484 | | impl AsBigEndian<EcPrivateKeyBin<'static>> for PrivateKey { |
485 | | /// Exposes the private key encoded as a big-endian fixed-length integer. |
486 | | /// |
487 | | /// X25519 is not supported. |
488 | | /// |
489 | | /// # Errors |
490 | | /// `error::Unspecified` if serialization failed. |
491 | 0 | fn as_be_bytes(&self) -> Result<EcPrivateKeyBin<'static>, Unspecified> { |
492 | 0 | if AlgorithmID::X25519 == self.inner_key.algorithm().id { |
493 | 0 | return Err(Unspecified); |
494 | 0 | } |
495 | 0 | let buffer = marshal_sec1_private_key(self.inner_key.get_evp_pkey())?; |
496 | 0 | Ok(EcPrivateKeyBin::new(buffer)) |
497 | 0 | } |
498 | | } |
499 | | |
500 | | impl AsBigEndian<Curve25519SeedBin<'static>> for PrivateKey { |
501 | | /// Exposes the seed encoded as a big-endian fixed-length integer. |
502 | | /// |
503 | | /// Only X25519 is supported. |
504 | | /// |
505 | | /// # Errors |
506 | | /// `error::Unspecified` if serialization failed. |
507 | 0 | fn as_be_bytes(&self) -> Result<Curve25519SeedBin<'static>, Unspecified> { |
508 | 0 | if AlgorithmID::X25519 != self.inner_key.algorithm().id { |
509 | 0 | return Err(Unspecified); |
510 | 0 | } |
511 | 0 | let evp_pkey = self.inner_key.get_evp_pkey(); |
512 | 0 | Ok(Curve25519SeedBin::new( |
513 | 0 | evp_pkey.as_const().marshal_raw_private_key()?, |
514 | | )) |
515 | 0 | } |
516 | | } |
517 | | |
518 | 0 | pub(crate) fn generate_x25519() -> Result<LcPtr<EVP_PKEY>, Unspecified> { |
519 | 0 | LcPtr::<EVP_PKEY>::generate(EVP_PKEY_X25519, No_EVP_PKEY_CTX_consumer) |
520 | 0 | } |
521 | | |
522 | | const MAX_PUBLIC_KEY_LEN: usize = ec::PUBLIC_KEY_MAX_LEN; |
523 | | |
524 | | /// A public key for key agreement. |
525 | | pub struct PublicKey { |
526 | | inner_key: KeyInner, |
527 | | key_bytes: [u8; MAX_PUBLIC_KEY_LEN], |
528 | | len: usize, |
529 | | } |
530 | | |
531 | | impl PublicKey { |
532 | | /// The algorithm for the public key. |
533 | | #[must_use] |
534 | 0 | pub fn algorithm(&self) -> &'static Algorithm { |
535 | 0 | self.inner_key.algorithm() |
536 | 0 | } |
537 | | } |
538 | | |
539 | | // See EVP_PKEY documentation here: |
540 | | // https://github.com/aws/aws-lc/blob/125af14c57451565b875fbf1282a38a6ecf83782/include/openssl/evp.h#L83-L89 |
541 | | // An |EVP_PKEY| object represents a public or private key. A given object may |
542 | | // be used concurrently on multiple threads by non-mutating functions, provided |
543 | | // no other thread is concurrently calling a mutating function. Unless otherwise |
544 | | // documented, functions which take a |const| pointer are non-mutating and |
545 | | // functions which take a non-|const| pointer are mutating. |
546 | | unsafe impl Send for PublicKey {} |
547 | | unsafe impl Sync for PublicKey {} |
548 | | |
549 | | impl Debug for PublicKey { |
550 | 0 | fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { |
551 | 0 | f.write_str(&format!( |
552 | 0 | "PublicKey {{ algorithm: {:?}, bytes: \"{}\" }}", |
553 | 0 | self.inner_key.algorithm(), |
554 | 0 | hex::encode(&self.key_bytes[0..self.len]) |
555 | 0 | )) |
556 | 0 | } |
557 | | } |
558 | | |
559 | | impl AsRef<[u8]> for PublicKey { |
560 | | /// Serializes the public key in an uncompressed form (X9.62) using the |
561 | | /// Octet-String-to-Elliptic-Curve-Point algorithm in |
562 | | /// [SEC 1: Elliptic Curve Cryptography, Version 2.0]. |
563 | 0 | fn as_ref(&self) -> &[u8] { |
564 | 0 | &self.key_bytes[0..self.len] |
565 | 0 | } |
566 | | } |
567 | | |
568 | | impl Clone for PublicKey { |
569 | 0 | fn clone(&self) -> Self { |
570 | 0 | PublicKey { |
571 | 0 | inner_key: self.inner_key.clone(), |
572 | 0 | key_bytes: self.key_bytes, |
573 | 0 | len: self.len, |
574 | 0 | } |
575 | 0 | } |
576 | | } |
577 | | |
578 | | impl AsDer<PublicKeyX509Der<'static>> for PublicKey { |
579 | | /// Provides the public key as a DER-encoded (X.509) `SubjectPublicKeyInfo` structure. |
580 | | /// # Errors |
581 | | /// Returns an error if the public key fails to marshal to X.509. |
582 | 0 | fn as_der(&self) -> Result<PublicKeyX509Der<'static>, crate::error::Unspecified> { |
583 | 0 | match &self.inner_key { |
584 | 0 | KeyInner::ECDH_P256(evp_pkey) |
585 | 0 | | KeyInner::ECDH_P384(evp_pkey) |
586 | 0 | | KeyInner::ECDH_P521(evp_pkey) |
587 | 0 | | KeyInner::X25519(evp_pkey) => { |
588 | 0 | let der = evp_pkey.as_const().marshal_rfc5280_public_key()?; |
589 | 0 | Ok(PublicKeyX509Der::from(Buffer::new(der))) |
590 | | } |
591 | | } |
592 | 0 | } |
593 | | } |
594 | | |
595 | | impl AsBigEndian<EcPublicKeyCompressedBin<'static>> for PublicKey { |
596 | | /// Provides the public key elliptic curve point to a compressed point format. |
597 | | /// # Errors |
598 | | /// Returns an error if the underlying implementation is unable to marshal the public key to this format. |
599 | 0 | fn as_be_bytes(&self) -> Result<EcPublicKeyCompressedBin<'static>, crate::error::Unspecified> { |
600 | 0 | let evp_pkey = match &self.inner_key { |
601 | 0 | KeyInner::ECDH_P256(evp_pkey) |
602 | 0 | | KeyInner::ECDH_P384(evp_pkey) |
603 | 0 | | KeyInner::ECDH_P521(evp_pkey) => evp_pkey, |
604 | 0 | KeyInner::X25519(_) => return Err(Unspecified), |
605 | | }; |
606 | 0 | let pub_point = marshal_sec1_public_point(evp_pkey, true)?; |
607 | 0 | Ok(EcPublicKeyCompressedBin::new(pub_point)) |
608 | 0 | } |
609 | | } |
610 | | |
611 | | impl AsBigEndian<EcPublicKeyUncompressedBin<'static>> for PublicKey { |
612 | | /// Provides the public key elliptic curve point to a compressed point format. |
613 | | /// |
614 | | /// Equivalent to [`PublicKey::as_ref`] for ECDH key types, except that it provides you a copy instead of a reference. |
615 | | /// |
616 | | /// # Errors |
617 | | /// Returns an error if the underlying implementation is unable to marshal the public key to this format. |
618 | 0 | fn as_be_bytes( |
619 | 0 | &self, |
620 | 0 | ) -> Result<EcPublicKeyUncompressedBin<'static>, crate::error::Unspecified> { |
621 | 0 | if self.algorithm().id == AlgorithmID::X25519 { |
622 | 0 | return Err(Unspecified); |
623 | 0 | } |
624 | | |
625 | 0 | let mut buffer = vec![0u8; self.len]; |
626 | 0 | buffer.copy_from_slice(&self.key_bytes[0..self.len]); |
627 | | |
628 | 0 | Ok(EcPublicKeyUncompressedBin::new(buffer)) |
629 | 0 | } |
630 | | } |
631 | | |
632 | | /// An unparsed, possibly malformed, public key for key agreement. |
633 | | #[derive(Clone)] |
634 | | pub struct UnparsedPublicKey<B: AsRef<[u8]>> { |
635 | | alg: &'static Algorithm, |
636 | | bytes: B, |
637 | | } |
638 | | |
639 | | impl<B: Copy + AsRef<[u8]>> Copy for UnparsedPublicKey<B> {} |
640 | | |
641 | | impl<B: Debug + AsRef<[u8]>> Debug for UnparsedPublicKey<B> { |
642 | 0 | fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> { |
643 | 0 | f.write_str(&format!( |
644 | 0 | "UnparsedPublicKey {{ algorithm: {:?}, bytes: {:?} }}", |
645 | 0 | self.alg, |
646 | 0 | hex::encode(self.bytes.as_ref()) |
647 | 0 | )) |
648 | 0 | } |
649 | | } |
650 | | |
651 | | impl<B: AsRef<[u8]>> UnparsedPublicKey<B> { |
652 | | /// Constructs a new `UnparsedPublicKey`. |
653 | 0 | pub fn new(algorithm: &'static Algorithm, bytes: B) -> Self { |
654 | 0 | UnparsedPublicKey { |
655 | 0 | alg: algorithm, |
656 | 0 | bytes, |
657 | 0 | } |
658 | 0 | } Unexecuted instantiation: <aws_lc_rs::agreement::UnparsedPublicKey<&alloc::vec::Vec<u8>>>::new Unexecuted instantiation: <aws_lc_rs::agreement::UnparsedPublicKey<&[u8]>>::new Unexecuted instantiation: <aws_lc_rs::agreement::UnparsedPublicKey<_>>::new |
659 | | |
660 | | /// The agreement algorithm associated with this public key |
661 | 0 | pub fn algorithm(&self) -> &'static Algorithm { |
662 | 0 | self.alg |
663 | 0 | } |
664 | | |
665 | | /// The bytes provided for this public key |
666 | 0 | pub fn bytes(&self) -> &B { |
667 | 0 | &self.bytes |
668 | 0 | } Unexecuted instantiation: <aws_lc_rs::agreement::UnparsedPublicKey<&alloc::vec::Vec<u8>>>::bytes Unexecuted instantiation: <aws_lc_rs::agreement::UnparsedPublicKey<_>>::bytes |
669 | | } |
670 | | |
671 | | /// A parsed public key for key agreement. |
672 | | /// |
673 | | /// This represents a public key that has been successfully parsed and validated |
674 | | /// from its encoded form. The key can be used with the `agree` function to |
675 | | /// perform key agreement operations. |
676 | | #[derive(Debug, Clone)] |
677 | | pub struct ParsedPublicKey { |
678 | | format: ParsedPublicKeyFormat, |
679 | | nid: i32, |
680 | | key: LcPtr<EVP_PKEY>, |
681 | | bytes: Box<[u8]>, |
682 | | } |
683 | | |
684 | | // See EVP_PKEY documentation here: |
685 | | // https://github.com/aws/aws-lc/blob/125af14c57451565b875fbf1282a38a6ecf83782/include/openssl/evp.h#L83-L89 |
686 | | // An |EVP_PKEY| object represents a public or private key. A given object may |
687 | | // be used concurrently on multiple threads by non-mutating functions, provided |
688 | | // no other thread is concurrently calling a mutating function. Unless otherwise |
689 | | // documented, functions which take a |const| pointer are non-mutating and |
690 | | // functions which take a non-|const| pointer are mutating. |
691 | | unsafe impl Send for ParsedPublicKey {} |
692 | | unsafe impl Sync for ParsedPublicKey {} |
693 | | |
694 | | #[derive(Clone, Copy, PartialEq, Eq, Debug)] |
695 | | /// The format of a parsed public key. |
696 | | /// |
697 | | /// This is used to distinguish between different types of public key formats |
698 | | /// supported by *aws-lc-rs*. |
699 | | #[non_exhaustive] |
700 | | pub enum ParsedPublicKeyFormat { |
701 | | /// The key is in an X.509 SubjectPublicKeyInfo format. |
702 | | X509, |
703 | | /// The key is in an uncompressed form (X9.62). |
704 | | Uncompressed, |
705 | | /// The key is in a compressed form (SEC 1: Elliptic Curve Cryptography, Version 2.0). |
706 | | Compressed, |
707 | | /// The key is in a hybrid form (SEC 1: Elliptic Curve Cryptography, Version 2.0). |
708 | | Hybrid, |
709 | | /// The key is in a raw form. (X25519 only) |
710 | | Raw, |
711 | | /// The key is in an unknown format. |
712 | | Unknown, |
713 | | } |
714 | | |
715 | | /// A parsed public key for key agreement. |
716 | | impl ParsedPublicKey { |
717 | 0 | fn nid(&self) -> i32 { |
718 | 0 | self.nid |
719 | 0 | } |
720 | | |
721 | | /// The format of the data the public key was parsed from. |
722 | | #[must_use] |
723 | 0 | pub fn format(&self) -> ParsedPublicKeyFormat { |
724 | 0 | self.format |
725 | 0 | } |
726 | | |
727 | 0 | pub(crate) fn mut_key(&mut self) -> &mut LcPtr<EVP_PKEY> { |
728 | 0 | &mut self.key |
729 | 0 | } |
730 | | |
731 | | /// The algorithm of the public key. |
732 | | #[must_use] |
733 | | #[allow(non_upper_case_globals)] |
734 | 0 | pub fn alg(&self) -> &'static Algorithm { |
735 | 0 | match self.nid() { |
736 | 0 | NID_X25519 => &X25519, |
737 | 0 | NID_X9_62_prime256v1 => &ECDH_P256, |
738 | 0 | NID_secp384r1 => &ECDH_P384, |
739 | 0 | NID_secp521r1 => &ECDH_P521, |
740 | 0 | _ => unreachable!("Unreachable agreement algorithm nid: {}", self.nid()), |
741 | | } |
742 | 0 | } |
743 | | } |
744 | | |
745 | | impl ParsedPublicKey { |
746 | | #[allow(non_upper_case_globals)] |
747 | 0 | pub(crate) fn new(bytes: impl AsRef<[u8]>, nid: i32) -> Result<Self, KeyRejected> { |
748 | 0 | let bytes = bytes.as_ref().to_vec().into_boxed_slice(); |
749 | 0 | if bytes.is_empty() { |
750 | 0 | return Err(KeyRejected::unspecified()); |
751 | 0 | } |
752 | 0 | match nid { |
753 | | NID_X25519 => { |
754 | | let format: ParsedPublicKeyFormat; |
755 | 0 | let key = if let Ok(evp_pkey) = |
756 | 0 | LcPtr::<EVP_PKEY>::parse_rfc5280_public_key(&bytes, EVP_PKEY_X25519) |
757 | | { |
758 | 0 | format = ParsedPublicKeyFormat::X509; |
759 | 0 | evp_pkey |
760 | | } else { |
761 | 0 | format = ParsedPublicKeyFormat::Raw; |
762 | 0 | try_parse_x25519_public_key_raw_bytes(&bytes)? |
763 | | }; |
764 | | |
765 | 0 | Ok(ParsedPublicKey { |
766 | 0 | format, |
767 | 0 | nid, |
768 | 0 | key, |
769 | 0 | bytes, |
770 | 0 | }) |
771 | | } |
772 | | NID_X9_62_prime256v1 | NID_secp384r1 | NID_secp521r1 => { |
773 | | let format: ParsedPublicKeyFormat; |
774 | 0 | let key = if let Ok(evp_pkey) = |
775 | 0 | LcPtr::<EVP_PKEY>::parse_rfc5280_public_key(&bytes, EVP_PKEY_EC) |
776 | | { |
777 | 0 | validate_ec_evp_key(&evp_pkey.as_const(), nid)?; |
778 | 0 | format = ParsedPublicKeyFormat::X509; |
779 | 0 | evp_pkey |
780 | 0 | } else if let Ok(evp_pkey) = parse_sec1_public_point(&bytes, nid) { |
781 | 0 | format = match bytes[0] { |
782 | 0 | 0x02 | 0x03 => ParsedPublicKeyFormat::Compressed, |
783 | 0 | 0x04 => ParsedPublicKeyFormat::Uncompressed, |
784 | 0 | 0x06 | 0x07 => ParsedPublicKeyFormat::Hybrid, |
785 | 0 | _ => ParsedPublicKeyFormat::Unknown, |
786 | | }; |
787 | 0 | evp_pkey |
788 | | } else { |
789 | 0 | return Err(KeyRejected::invalid_encoding()); |
790 | | }; |
791 | | |
792 | 0 | Ok(ParsedPublicKey { |
793 | 0 | format, |
794 | 0 | nid, |
795 | 0 | key, |
796 | 0 | bytes, |
797 | 0 | }) |
798 | | } |
799 | 0 | _ => Err(KeyRejected::unspecified()), |
800 | | } |
801 | 0 | } Unexecuted instantiation: <aws_lc_rs::agreement::ParsedPublicKey>::new::<&&alloc::vec::Vec<u8>> Unexecuted instantiation: <aws_lc_rs::agreement::ParsedPublicKey>::new::<&&[u8]> Unexecuted instantiation: <aws_lc_rs::agreement::ParsedPublicKey>::new::<_> |
802 | | } |
803 | | |
804 | | impl AsRef<[u8]> for ParsedPublicKey { |
805 | | /// Returns the original bytes from which this key was parsed. |
806 | 0 | fn as_ref(&self) -> &[u8] { |
807 | 0 | &self.bytes |
808 | 0 | } |
809 | | } |
810 | | |
811 | | impl<B: AsRef<[u8]>> UnparsedPublicKey<B> { |
812 | | #[allow(dead_code)] |
813 | 0 | fn parse(&self) -> Result<ParsedPublicKey, KeyRejected> { |
814 | 0 | ParsedPublicKey::new(&self.bytes, self.alg.id.nid()) |
815 | 0 | } Unexecuted instantiation: <aws_lc_rs::agreement::UnparsedPublicKey<&alloc::vec::Vec<u8>>>::parse Unexecuted instantiation: <aws_lc_rs::agreement::UnparsedPublicKey<&[u8]>>::parse Unexecuted instantiation: <aws_lc_rs::agreement::UnparsedPublicKey<_>>::parse |
816 | | } |
817 | | |
818 | | impl<B: AsRef<[u8]>> TryFrom<&UnparsedPublicKey<B>> for ParsedPublicKey { |
819 | | type Error = KeyRejected; |
820 | 0 | fn try_from(upk: &UnparsedPublicKey<B>) -> Result<Self, Self::Error> { |
821 | 0 | upk.parse() |
822 | 0 | } Unexecuted instantiation: <aws_lc_rs::agreement::ParsedPublicKey as core::convert::TryFrom<&aws_lc_rs::agreement::UnparsedPublicKey<&[u8]>>>::try_from Unexecuted instantiation: <aws_lc_rs::agreement::ParsedPublicKey as core::convert::TryFrom<&aws_lc_rs::agreement::UnparsedPublicKey<_>>>::try_from |
823 | | } |
824 | | |
825 | | impl<B: AsRef<[u8]>> TryFrom<UnparsedPublicKey<B>> for ParsedPublicKey { |
826 | | type Error = KeyRejected; |
827 | 0 | fn try_from(upk: UnparsedPublicKey<B>) -> Result<Self, Self::Error> { |
828 | 0 | upk.parse() |
829 | 0 | } Unexecuted instantiation: <aws_lc_rs::agreement::ParsedPublicKey as core::convert::TryFrom<aws_lc_rs::agreement::UnparsedPublicKey<&alloc::vec::Vec<u8>>>>::try_from Unexecuted instantiation: <aws_lc_rs::agreement::ParsedPublicKey as core::convert::TryFrom<aws_lc_rs::agreement::UnparsedPublicKey<_>>>::try_from |
830 | | } |
831 | | |
832 | | /// Performs a key agreement with a private key and the given public key. |
833 | | /// |
834 | | /// `my_private_key` is the private key to use. Only a reference to the key |
835 | | /// is required, allowing the key to continue to be used. |
836 | | /// |
837 | | /// `peer_public_key` is the peer's public key. `agree` will return |
838 | | /// `Err(error_value)` if it does not match `my_private_key's` algorithm/curve. |
839 | | /// `agree` verifies that it is encoded in the standard form for the |
840 | | /// algorithm and that the key is *valid*; see the algorithm's documentation for |
841 | | /// details on how keys are to be encoded and what constitutes a valid key for |
842 | | /// that algorithm. |
843 | | /// |
844 | | /// `error_value` is the value to return if an error occurs before `kdf` is |
845 | | /// called, e.g. when decoding of the peer's public key fails or when the public |
846 | | /// key is otherwise invalid. |
847 | | /// |
848 | | /// After the key agreement is done, `agree` calls `kdf` with the raw |
849 | | /// key material from the key agreement operation and then returns what `kdf` |
850 | | /// returns. |
851 | | // # FIPS |
852 | | // Use this function with one of the following key algorithms: |
853 | | // * `ECDH_P256` |
854 | | // * `ECDH_P384` |
855 | | // * `ECDH_P521` |
856 | | // |
857 | | /// # Errors |
858 | | /// `error_value` on internal failure. |
859 | | #[inline] |
860 | | #[allow(clippy::missing_panics_doc)] |
861 | 0 | pub fn agree<B: TryInto<ParsedPublicKey>, F, R, E>( |
862 | 0 | my_private_key: &PrivateKey, |
863 | 0 | peer_public_key: B, |
864 | 0 | error_value: E, |
865 | 0 | kdf: F, |
866 | 0 | ) -> Result<R, E> |
867 | 0 | where |
868 | 0 | F: FnOnce(&[u8]) -> Result<R, E>, |
869 | | { |
870 | 0 | let expected_alg = my_private_key.algorithm(); |
871 | | |
872 | 0 | let parse_result = peer_public_key.try_into(); |
873 | | |
874 | 0 | if let Ok(mut peer_pub_key) = parse_result { |
875 | 0 | if peer_pub_key.alg() != expected_alg { |
876 | 0 | return Err(error_value); |
877 | 0 | } |
878 | 0 | let secret = my_private_key |
879 | 0 | .inner_key |
880 | 0 | .get_evp_pkey() |
881 | 0 | .agree(peer_pub_key.mut_key()) |
882 | 0 | .or(Err(error_value))?; |
883 | | |
884 | 0 | kdf(secret.as_ref()) |
885 | | } else { |
886 | 0 | Err(error_value) |
887 | | } |
888 | 0 | } Unexecuted instantiation: aws_lc_rs::agreement::agree::<aws_lc_rs::agreement::UnparsedPublicKey<&alloc::vec::Vec<u8>>, <rustls::crypto::aws_lc_rs::hpke::DhKem<32>>::encap_impl::{closure#0}, [u8; 32], aws_lc_rs::error::Unspecified>Unexecuted instantiation: aws_lc_rs::agreement::agree::<aws_lc_rs::agreement::UnparsedPublicKey<&alloc::vec::Vec<u8>>, <rustls::crypto::aws_lc_rs::hpke::DhKem<32>>::decap::{closure#0}, [u8; 32], aws_lc_rs::error::Unspecified>Unexecuted instantiation: aws_lc_rs::agreement::agree::<aws_lc_rs::agreement::UnparsedPublicKey<&alloc::vec::Vec<u8>>, <rustls::crypto::aws_lc_rs::hpke::DhKem<48>>::encap_impl::{closure#0}, [u8; 48], aws_lc_rs::error::Unspecified>Unexecuted instantiation: aws_lc_rs::agreement::agree::<aws_lc_rs::agreement::UnparsedPublicKey<&alloc::vec::Vec<u8>>, <rustls::crypto::aws_lc_rs::hpke::DhKem<48>>::decap::{closure#0}, [u8; 48], aws_lc_rs::error::Unspecified>Unexecuted instantiation: aws_lc_rs::agreement::agree::<aws_lc_rs::agreement::UnparsedPublicKey<&alloc::vec::Vec<u8>>, <rustls::crypto::aws_lc_rs::hpke::DhKem<64>>::encap_impl::{closure#0}, [u8; 64], aws_lc_rs::error::Unspecified>Unexecuted instantiation: aws_lc_rs::agreement::agree::<aws_lc_rs::agreement::UnparsedPublicKey<&alloc::vec::Vec<u8>>, <rustls::crypto::aws_lc_rs::hpke::DhKem<64>>::decap::{closure#0}, [u8; 64], aws_lc_rs::error::Unspecified>Unexecuted instantiation: aws_lc_rs::agreement::agree::<&aws_lc_rs::agreement::UnparsedPublicKey<&[u8]>, rustls::crypto::aws_lc_rs::ring_shim::agree_ephemeral::{closure#0}, rustls::crypto::SharedSecret, ()>Unexecuted instantiation: aws_lc_rs::agreement::agree::<_, _, _, _> |
889 | | |
890 | 0 | fn try_parse_x25519_public_key_raw_bytes(key_bytes: &[u8]) -> Result<LcPtr<EVP_PKEY>, KeyRejected> { |
891 | 0 | let expected_pub_key_len = X25519.id.pub_key_len(); |
892 | 0 | if key_bytes.len() != expected_pub_key_len { |
893 | 0 | return Err(KeyRejected::invalid_encoding()); |
894 | 0 | } |
895 | | |
896 | 0 | LcPtr::<EVP_PKEY>::parse_raw_public_key(key_bytes, EVP_PKEY_X25519) |
897 | 0 | } |
898 | | |
899 | | #[cfg(test)] |
900 | | mod agreement_tests; |
901 | | #[cfg(test)] |
902 | | mod parsed_public_key_tests; |