aws_lc_rs/
agreement.rs

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//! ```
52mod ephemeral;
53
54use crate::ec::encoding::sec1::{
55    marshal_sec1_private_key, marshal_sec1_public_point, marshal_sec1_public_point_into_buffer,
56    parse_sec1_private_bn,
57};
58#[cfg(feature = "fips")]
59use crate::ec::validate_ec_evp_key;
60#[cfg(not(feature = "fips"))]
61use crate::ec::verify_evp_key_nid;
62use crate::ec::{encoding, evp_key_generate};
63use crate::error::{KeyRejected, Unspecified};
64use crate::hex;
65pub use ephemeral::{agree_ephemeral, EphemeralPrivateKey};
66
67use crate::aws_lc::{
68    EVP_PKEY_derive, EVP_PKEY_derive_init, EVP_PKEY_derive_set_peer, EVP_PKEY_get0_EC_KEY,
69    NID_X9_62_prime256v1, NID_secp384r1, NID_secp521r1, EVP_PKEY, EVP_PKEY_EC, EVP_PKEY_X25519,
70    NID_X25519,
71};
72
73use crate::buffer::Buffer;
74use crate::ec;
75use crate::ec::encoding::rfc5915::parse_rfc5915_private_key;
76use crate::encoding::{
77    AsBigEndian, AsDer, Curve25519SeedBin, EcPrivateKeyBin, EcPrivateKeyRfc5915Der,
78    EcPublicKeyCompressedBin, EcPublicKeyUncompressedBin, Pkcs8V1Der, PublicKeyX509Der,
79};
80use crate::evp_pkey::No_EVP_PKEY_CTX_consumer;
81use crate::fips::indicator_check;
82use crate::pkcs8::Version;
83use crate::ptr::LcPtr;
84use core::fmt;
85use core::fmt::{Debug, Formatter};
86use core::ptr::null_mut;
87
88#[allow(non_camel_case_types)]
89#[derive(PartialEq, Eq)]
90enum AlgorithmID {
91    ECDH_P256,
92    ECDH_P384,
93    ECDH_P521,
94    X25519,
95}
96
97impl AlgorithmID {
98    #[inline]
99    const fn nid(&self) -> i32 {
100        match self {
101            AlgorithmID::ECDH_P256 => NID_X9_62_prime256v1,
102            AlgorithmID::ECDH_P384 => NID_secp384r1,
103            AlgorithmID::ECDH_P521 => NID_secp521r1,
104            AlgorithmID::X25519 => NID_X25519,
105        }
106    }
107
108    // Uncompressed public key length in bytes
109    #[inline]
110    const fn pub_key_len(&self) -> usize {
111        match self {
112            AlgorithmID::ECDH_P256 => ec::uncompressed_public_key_size_bytes(256),
113            AlgorithmID::ECDH_P384 => ec::uncompressed_public_key_size_bytes(384),
114            AlgorithmID::ECDH_P521 => ec::uncompressed_public_key_size_bytes(521),
115            AlgorithmID::X25519 => 32,
116        }
117    }
118
119    #[inline]
120    const fn private_key_len(&self) -> usize {
121        match self {
122            AlgorithmID::ECDH_P256 | AlgorithmID::X25519 => 32,
123            AlgorithmID::ECDH_P384 => 48,
124            AlgorithmID::ECDH_P521 => 66,
125        }
126    }
127}
128
129impl Debug for AlgorithmID {
130    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> {
131        let output = match self {
132            AlgorithmID::ECDH_P256 => "curve: P256",
133            AlgorithmID::ECDH_P384 => "curve: P384",
134            AlgorithmID::ECDH_P521 => "curve: P521",
135            AlgorithmID::X25519 => "curve: Curve25519",
136        };
137        f.write_str(output)
138    }
139}
140
141/// A key agreement algorithm.
142#[derive(PartialEq, Eq)]
143pub struct Algorithm {
144    id: AlgorithmID,
145}
146
147impl Debug for Algorithm {
148    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> {
149        f.write_str(&format!("Algorithm {{ {:?} }}", self.id))
150    }
151}
152
153/// ECDH using the NSA Suite B P-256 (secp256r1) curve.
154pub const ECDH_P256: Algorithm = Algorithm {
155    id: AlgorithmID::ECDH_P256,
156};
157
158/// ECDH using the NSA Suite B P-384 (secp384r1) curve.
159pub const ECDH_P384: Algorithm = Algorithm {
160    id: AlgorithmID::ECDH_P384,
161};
162
163/// ECDH using the NSA Suite B P-521 (secp521r1) curve.
164pub const ECDH_P521: Algorithm = Algorithm {
165    id: AlgorithmID::ECDH_P521,
166};
167
168/// X25519 (ECDH using Curve25519) as described in [RFC 7748].
169///
170/// Everything is as described in RFC 7748. Key agreement will fail if the
171/// result of the X25519 operation is zero; see the notes on the
172/// "all-zero value" in [RFC 7748 section 6.1].
173///
174/// [RFC 7748]: https://tools.ietf.org/html/rfc7748
175/// [RFC 7748 section 6.1]: https://tools.ietf.org/html/rfc7748#section-6.1
176pub const X25519: Algorithm = Algorithm {
177    id: AlgorithmID::X25519,
178};
179
180#[allow(non_camel_case_types)]
181enum KeyInner {
182    ECDH_P256(LcPtr<EVP_PKEY>),
183    ECDH_P384(LcPtr<EVP_PKEY>),
184    ECDH_P521(LcPtr<EVP_PKEY>),
185    X25519(LcPtr<EVP_PKEY>),
186}
187
188impl Clone for KeyInner {
189    fn clone(&self) -> KeyInner {
190        match self {
191            KeyInner::ECDH_P256(evp_pkey) => KeyInner::ECDH_P256(evp_pkey.clone()),
192            KeyInner::ECDH_P384(evp_pkey) => KeyInner::ECDH_P384(evp_pkey.clone()),
193            KeyInner::ECDH_P521(evp_pkey) => KeyInner::ECDH_P521(evp_pkey.clone()),
194            KeyInner::X25519(evp_pkey) => KeyInner::X25519(evp_pkey.clone()),
195        }
196    }
197}
198
199/// A private key for use (only) with `agree`. The
200/// signature of `agree` allows `PrivateKey` to be
201/// used for more than one key agreement.
202pub struct PrivateKey {
203    inner_key: KeyInner,
204}
205
206impl KeyInner {
207    #[inline]
208    fn algorithm(&self) -> &'static Algorithm {
209        match self {
210            KeyInner::ECDH_P256(..) => &ECDH_P256,
211            KeyInner::ECDH_P384(..) => &ECDH_P384,
212            KeyInner::ECDH_P521(..) => &ECDH_P521,
213            KeyInner::X25519(..) => &X25519,
214        }
215    }
216
217    fn get_evp_pkey(&self) -> &LcPtr<EVP_PKEY> {
218        match self {
219            KeyInner::ECDH_P256(evp_pkey)
220            | KeyInner::ECDH_P384(evp_pkey)
221            | KeyInner::ECDH_P521(evp_pkey)
222            | KeyInner::X25519(evp_pkey) => evp_pkey,
223        }
224    }
225}
226
227unsafe impl Send for PrivateKey {}
228
229// https://github.com/awslabs/aws-lc/blob/main/include/openssl/ec_key.h#L88
230// An |EC_KEY| object represents a public or private EC key. A given object may
231// be used concurrently on multiple threads by non-mutating functions, provided
232// no other thread is concurrently calling a mutating function. Unless otherwise
233// documented, functions which take a |const| pointer are non-mutating and
234// functions which take a non-|const| pointer are mutating.
235unsafe impl Sync for PrivateKey {}
236
237impl Debug for PrivateKey {
238    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> {
239        f.write_str(&format!(
240            "PrivateKey {{ algorithm: {:?} }}",
241            self.inner_key.algorithm()
242        ))
243    }
244}
245
246impl PrivateKey {
247    fn new(alg: &'static Algorithm, evp_pkey: LcPtr<EVP_PKEY>) -> Self {
248        match alg.id {
249            AlgorithmID::X25519 => Self {
250                inner_key: KeyInner::X25519(evp_pkey),
251            },
252            AlgorithmID::ECDH_P256 => Self {
253                inner_key: KeyInner::ECDH_P256(evp_pkey),
254            },
255            AlgorithmID::ECDH_P384 => Self {
256                inner_key: KeyInner::ECDH_P384(evp_pkey),
257            },
258            AlgorithmID::ECDH_P521 => Self {
259                inner_key: KeyInner::ECDH_P521(evp_pkey),
260            },
261        }
262    }
263
264    #[inline]
265    /// Generate a new private key for the given algorithm.
266    // # FIPS
267    // Use this function with one of the following algorithms:
268    // * `ECDH_P256`
269    // * `ECDH_P384`
270    // * `ECDH_P521`
271    //
272    /// # Errors
273    /// `error::Unspecified` when operation fails due to internal error.
274    pub fn generate(alg: &'static Algorithm) -> Result<Self, Unspecified> {
275        let evp_pkey = match alg.id {
276            AlgorithmID::X25519 => generate_x25519()?,
277            _ => evp_key_generate(alg.id.nid())?,
278        };
279        Ok(Self::new(alg, evp_pkey))
280    }
281
282    /// Deserializes a DER-encoded private key structure to produce a `agreement::PrivateKey`.
283    ///
284    /// This function is typically used to deserialize RFC 5915 encoded private keys, but it will
285    /// attempt to automatically detect other key formats. This function supports unencrypted
286    /// PKCS#8 `PrivateKeyInfo` structures as well as key type specific formats.
287    ///
288    /// X25519 keys are not supported. See `PrivateKey::as_der`.
289    ///
290    /// # Errors
291    /// `error::KeyRejected` if parsing failed or key otherwise unacceptable.
292    ///
293    /// # Panics
294    pub fn from_private_key_der(
295        alg: &'static Algorithm,
296        key_bytes: &[u8],
297    ) -> Result<Self, KeyRejected> {
298        if AlgorithmID::X25519 == alg.id {
299            return Err(KeyRejected::invalid_encoding());
300        }
301        let evp_pkey = LcPtr::<EVP_PKEY>::parse_rfc5208_private_key(key_bytes, EVP_PKEY_EC)
302            .or(parse_rfc5915_private_key(key_bytes, alg.id.nid()))?;
303        #[cfg(not(feature = "fips"))]
304        verify_evp_key_nid(&evp_pkey.as_const(), alg.id.nid())?;
305        #[cfg(feature = "fips")]
306        validate_ec_evp_key(&evp_pkey.as_const(), alg.id.nid())?;
307
308        Ok(Self::new(alg, evp_pkey))
309    }
310
311    /// Constructs an ECDH key from private key bytes
312    ///
313    /// The private key must encoded as a big-endian fixed-length integer. For
314    /// example, a P-256 private key must be 32 bytes prefixed with leading
315    /// zeros as needed.
316    ///
317    /// # Errors
318    /// `error::KeyRejected` if parsing failed or key otherwise unacceptable.
319    pub fn from_private_key(
320        alg: &'static Algorithm,
321        key_bytes: &[u8],
322    ) -> Result<Self, KeyRejected> {
323        if key_bytes.len() != alg.id.private_key_len() {
324            return Err(KeyRejected::wrong_algorithm());
325        }
326        let evp_pkey = if AlgorithmID::X25519 == alg.id {
327            LcPtr::<EVP_PKEY>::parse_raw_private_key(key_bytes, EVP_PKEY_X25519)?
328        } else {
329            parse_sec1_private_bn(key_bytes, alg.id.nid())?
330        };
331        Ok(Self::new(alg, evp_pkey))
332    }
333
334    #[cfg(test)]
335    #[allow(missing_docs, clippy::missing_errors_doc)]
336    pub fn generate_for_test(
337        alg: &'static Algorithm,
338        rng: &dyn crate::rand::SecureRandom,
339    ) -> Result<Self, Unspecified> {
340        match alg.id {
341            AlgorithmID::X25519 => {
342                let mut priv_key = [0u8; AlgorithmID::X25519.private_key_len()];
343                rng.fill(&mut priv_key)?;
344                Self::from_x25519_private_key(&priv_key)
345            }
346            AlgorithmID::ECDH_P256 => {
347                let mut priv_key = [0u8; AlgorithmID::ECDH_P256.private_key_len()];
348                rng.fill(&mut priv_key)?;
349                Self::from_p256_private_key(&priv_key)
350            }
351            AlgorithmID::ECDH_P384 => {
352                let mut priv_key = [0u8; AlgorithmID::ECDH_P384.private_key_len()];
353                rng.fill(&mut priv_key)?;
354                Self::from_p384_private_key(&priv_key)
355            }
356            AlgorithmID::ECDH_P521 => {
357                let mut priv_key = [0u8; AlgorithmID::ECDH_P521.private_key_len()];
358                rng.fill(&mut priv_key)?;
359                Self::from_p521_private_key(&priv_key)
360            }
361        }
362    }
363
364    #[cfg(test)]
365    fn from_x25519_private_key(
366        priv_key: &[u8; AlgorithmID::X25519.private_key_len()],
367    ) -> Result<Self, Unspecified> {
368        let pkey = LcPtr::<EVP_PKEY>::parse_raw_private_key(priv_key, EVP_PKEY_X25519)?;
369
370        Ok(PrivateKey {
371            inner_key: KeyInner::X25519(pkey),
372        })
373    }
374
375    #[cfg(test)]
376    fn from_p256_private_key(priv_key: &[u8]) -> Result<Self, Unspecified> {
377        let pkey = parse_sec1_private_bn(priv_key, ECDH_P256.id.nid())?;
378        Ok(PrivateKey {
379            inner_key: KeyInner::ECDH_P256(pkey),
380        })
381    }
382
383    #[cfg(test)]
384    fn from_p384_private_key(priv_key: &[u8]) -> Result<Self, Unspecified> {
385        let pkey = parse_sec1_private_bn(priv_key, ECDH_P384.id.nid())?;
386        Ok(PrivateKey {
387            inner_key: KeyInner::ECDH_P384(pkey),
388        })
389    }
390
391    #[cfg(test)]
392    fn from_p521_private_key(priv_key: &[u8]) -> Result<Self, Unspecified> {
393        let pkey = parse_sec1_private_bn(priv_key, ECDH_P521.id.nid())?;
394        Ok(PrivateKey {
395            inner_key: KeyInner::ECDH_P521(pkey),
396        })
397    }
398
399    /// Computes the public key from the private key.
400    ///
401    /// # Errors
402    /// `error::Unspecified` when operation fails due to internal error.
403    pub fn compute_public_key(&self) -> Result<PublicKey, Unspecified> {
404        match &self.inner_key {
405            KeyInner::ECDH_P256(evp_pkey)
406            | KeyInner::ECDH_P384(evp_pkey)
407            | KeyInner::ECDH_P521(evp_pkey) => {
408                let mut public_key = [0u8; MAX_PUBLIC_KEY_LEN];
409                let len = marshal_sec1_public_point_into_buffer(&mut public_key, evp_pkey, false)?;
410                Ok(PublicKey {
411                    inner_key: self.inner_key.clone(),
412                    key_bytes: public_key,
413                    len,
414                })
415            }
416            KeyInner::X25519(priv_key) => {
417                let mut buffer = [0u8; MAX_PUBLIC_KEY_LEN];
418                let out_len = priv_key
419                    .as_const()
420                    .marshal_raw_public_to_buffer(&mut buffer)?;
421                Ok(PublicKey {
422                    inner_key: self.inner_key.clone(),
423                    key_bytes: buffer,
424                    len: out_len,
425                })
426            }
427        }
428    }
429
430    /// The algorithm for the private key.
431    #[inline]
432    #[must_use]
433    pub fn algorithm(&self) -> &'static Algorithm {
434        self.inner_key.algorithm()
435    }
436}
437
438impl AsDer<EcPrivateKeyRfc5915Der<'static>> for PrivateKey {
439    /// Serializes the key as a DER-encoded `ECPrivateKey` (RFC 5915) structure.
440    ///
441    /// X25519 is not supported.
442    ///
443    /// # Errors
444    /// `error::Unspecified`  if serialization failed.
445    fn as_der(&self) -> Result<EcPrivateKeyRfc5915Der<'static>, Unspecified> {
446        if AlgorithmID::X25519 == self.inner_key.algorithm().id {
447            return Err(Unspecified);
448        }
449
450        let mut outp = null_mut::<u8>();
451        let ec_key = {
452            self.inner_key
453                .get_evp_pkey()
454                .project_const_lifetime(unsafe {
455                    |evp_pkey| EVP_PKEY_get0_EC_KEY(*evp_pkey.as_const())
456                })?
457        };
458        let length = usize::try_from(unsafe { aws_lc::i2d_ECPrivateKey(*ec_key, &mut outp) })
459            .map_err(|_| Unspecified)?;
460        let mut outp = LcPtr::new(outp)?;
461        Ok(EcPrivateKeyRfc5915Der::take_from_slice(unsafe {
462            core::slice::from_raw_parts_mut(*outp.as_mut(), length)
463        }))
464    }
465}
466
467impl AsDer<Pkcs8V1Der<'static>> for PrivateKey {
468    /// Serializes the key as a PKCS #8 private key structure.
469    ///
470    /// X25519 is not supported.
471    ///
472    /// # Errors
473    /// `error::Unspecified`  if serialization failed.
474    fn as_der(&self) -> Result<Pkcs8V1Der<'static>, Unspecified> {
475        if AlgorithmID::X25519 == self.inner_key.algorithm().id {
476            return Err(Unspecified);
477        }
478
479        Ok(Pkcs8V1Der::new(
480            self.inner_key
481                .get_evp_pkey()
482                .as_const()
483                .marshal_rfc5208_private_key(Version::V1)?,
484        ))
485    }
486}
487
488impl AsBigEndian<EcPrivateKeyBin<'static>> for PrivateKey {
489    /// Exposes the private key encoded as a big-endian fixed-length integer.
490    ///
491    /// X25519 is not supported.
492    ///
493    /// # Errors
494    /// `error::Unspecified` if serialization failed.
495    fn as_be_bytes(&self) -> Result<EcPrivateKeyBin<'static>, Unspecified> {
496        if AlgorithmID::X25519 == self.inner_key.algorithm().id {
497            return Err(Unspecified);
498        }
499        let buffer = marshal_sec1_private_key(self.inner_key.get_evp_pkey())?;
500        Ok(EcPrivateKeyBin::new(buffer))
501    }
502}
503
504impl AsBigEndian<Curve25519SeedBin<'static>> for PrivateKey {
505    /// Exposes the seed encoded as a big-endian fixed-length integer.
506    ///
507    /// Only X25519 is supported.
508    ///
509    /// # Errors
510    /// `error::Unspecified` if serialization failed.
511    fn as_be_bytes(&self) -> Result<Curve25519SeedBin<'static>, Unspecified> {
512        if AlgorithmID::X25519 != self.inner_key.algorithm().id {
513            return Err(Unspecified);
514        }
515        let evp_pkey = self.inner_key.get_evp_pkey();
516        Ok(Curve25519SeedBin::new(
517            evp_pkey.as_const().marshal_raw_private_key()?,
518        ))
519    }
520}
521
522pub(crate) fn generate_x25519() -> Result<LcPtr<EVP_PKEY>, Unspecified> {
523    LcPtr::<EVP_PKEY>::generate(EVP_PKEY_X25519, No_EVP_PKEY_CTX_consumer)
524}
525
526const MAX_PUBLIC_KEY_LEN: usize = ec::PUBLIC_KEY_MAX_LEN;
527
528/// A public key for key agreement.
529pub struct PublicKey {
530    inner_key: KeyInner,
531    key_bytes: [u8; MAX_PUBLIC_KEY_LEN],
532    len: usize,
533}
534
535impl PublicKey {
536    /// The algorithm for the public key.
537    #[must_use]
538    pub fn algorithm(&self) -> &'static Algorithm {
539        self.inner_key.algorithm()
540    }
541}
542
543unsafe impl Send for PublicKey {}
544unsafe impl Sync for PublicKey {}
545
546impl Debug for PublicKey {
547    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
548        f.write_str(&format!(
549            "PublicKey {{ algorithm: {:?}, bytes: \"{}\" }}",
550            self.inner_key.algorithm(),
551            hex::encode(&self.key_bytes[0..self.len])
552        ))
553    }
554}
555
556impl AsRef<[u8]> for PublicKey {
557    /// Serializes the public key in an uncompressed form (X9.62) using the
558    /// Octet-String-to-Elliptic-Curve-Point algorithm in
559    /// [SEC 1: Elliptic Curve Cryptography, Version 2.0].
560    fn as_ref(&self) -> &[u8] {
561        &self.key_bytes[0..self.len]
562    }
563}
564
565impl Clone for PublicKey {
566    fn clone(&self) -> Self {
567        PublicKey {
568            inner_key: self.inner_key.clone(),
569            key_bytes: self.key_bytes,
570            len: self.len,
571        }
572    }
573}
574
575impl AsDer<PublicKeyX509Der<'static>> for PublicKey {
576    /// Provides the public key as a DER-encoded (X.509) `SubjectPublicKeyInfo` structure.
577    /// # Errors
578    /// Returns an error if the public key fails to marshal to X.509.
579    fn as_der(&self) -> Result<PublicKeyX509Der<'static>, crate::error::Unspecified> {
580        match &self.inner_key {
581            KeyInner::ECDH_P256(evp_pkey)
582            | KeyInner::ECDH_P384(evp_pkey)
583            | KeyInner::ECDH_P521(evp_pkey)
584            | KeyInner::X25519(evp_pkey) => {
585                let der = evp_pkey.as_const().marshal_rfc5280_public_key()?;
586                Ok(PublicKeyX509Der::from(Buffer::new(der)))
587            }
588        }
589    }
590}
591
592impl AsBigEndian<EcPublicKeyCompressedBin<'static>> for PublicKey {
593    /// Provides the public key elliptic curve point to a compressed point format.
594    /// # Errors
595    /// Returns an error if the underlying implementation is unable to marshal the public key to this format.
596    fn as_be_bytes(&self) -> Result<EcPublicKeyCompressedBin<'static>, crate::error::Unspecified> {
597        let evp_pkey = match &self.inner_key {
598            KeyInner::ECDH_P256(evp_pkey)
599            | KeyInner::ECDH_P384(evp_pkey)
600            | KeyInner::ECDH_P521(evp_pkey) => evp_pkey,
601            KeyInner::X25519(_) => return Err(Unspecified),
602        };
603        let pub_point = marshal_sec1_public_point(evp_pkey, true)?;
604        Ok(EcPublicKeyCompressedBin::new(pub_point))
605    }
606}
607
608impl AsBigEndian<EcPublicKeyUncompressedBin<'static>> for PublicKey {
609    /// Provides the public key elliptic curve point to a compressed point format.
610    ///
611    /// Equivalent to [`PublicKey::as_ref`] for ECDH key types, except that it provides you a copy instead of a reference.
612    ///
613    /// # Errors
614    /// Returns an error if the underlying implementation is unable to marshal the public key to this format.
615    fn as_be_bytes(
616        &self,
617    ) -> Result<EcPublicKeyUncompressedBin<'static>, crate::error::Unspecified> {
618        if self.algorithm().id == AlgorithmID::X25519 {
619            return Err(Unspecified);
620        }
621
622        let mut buffer = vec![0u8; self.len];
623        buffer.copy_from_slice(&self.key_bytes[0..self.len]);
624
625        Ok(EcPublicKeyUncompressedBin::new(buffer))
626    }
627}
628
629/// An unparsed, possibly malformed, public key for key agreement.
630#[derive(Clone)]
631pub struct UnparsedPublicKey<B: AsRef<[u8]>> {
632    alg: &'static Algorithm,
633    bytes: B,
634}
635
636impl<B: Copy + AsRef<[u8]>> Copy for UnparsedPublicKey<B> {}
637
638impl<B: Debug + AsRef<[u8]>> Debug for UnparsedPublicKey<B> {
639    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> {
640        f.write_str(&format!(
641            "UnparsedPublicKey {{ algorithm: {:?}, bytes: {:?} }}",
642            self.alg,
643            hex::encode(self.bytes.as_ref())
644        ))
645    }
646}
647
648impl<B: AsRef<[u8]>> UnparsedPublicKey<B> {
649    /// Constructs a new `UnparsedPublicKey`.
650    pub fn new(algorithm: &'static Algorithm, bytes: B) -> Self {
651        UnparsedPublicKey {
652            alg: algorithm,
653            bytes,
654        }
655    }
656
657    /// The agreement algorithm associated with this public key
658    pub fn algorithm(&self) -> &'static Algorithm {
659        self.alg
660    }
661
662    /// The bytes provided for this public key
663    pub fn bytes(&self) -> &B {
664        &self.bytes
665    }
666}
667
668/// Performs a key agreement with a private key and the given public key.
669///
670/// `my_private_key` is the private key to use. Only a reference to the key
671/// is required, allowing the key to continue to be used.
672///
673/// `peer_public_key` is the peer's public key. `agree` will return
674/// `Err(error_value)` if it does not match `my_private_key's` algorithm/curve.
675/// `agree` verifies that it is encoded in the standard form for the
676/// algorithm and that the key is *valid*; see the algorithm's documentation for
677/// details on how keys are to be encoded and what constitutes a valid key for
678/// that algorithm.
679///
680/// `error_value` is the value to return if an error occurs before `kdf` is
681/// called, e.g. when decoding of the peer's public key fails or when the public
682/// key is otherwise invalid.
683///
684/// After the key agreement is done, `agree` calls `kdf` with the raw
685/// key material from the key agreement operation and then returns what `kdf`
686/// returns.
687// # FIPS
688// Use this function with one of the following key algorithms:
689// * `ECDH_P256`
690// * `ECDH_P384`
691// * `ECDH_P521`
692//
693/// # Errors
694/// `error_value` on internal failure.
695#[inline]
696#[allow(clippy::missing_panics_doc)]
697pub fn agree<B: AsRef<[u8]>, F, R, E>(
698    my_private_key: &PrivateKey,
699    peer_public_key: &UnparsedPublicKey<B>,
700    error_value: E,
701    kdf: F,
702) -> Result<R, E>
703where
704    F: FnOnce(&[u8]) -> Result<R, E>,
705{
706    let expected_alg = my_private_key.algorithm();
707    let expected_nid = expected_alg.id.nid();
708
709    if peer_public_key.alg != expected_alg {
710        return Err(error_value);
711    }
712
713    let peer_pub_bytes = peer_public_key.bytes.as_ref();
714
715    let mut buffer = [0u8; MAX_AGREEMENT_SECRET_LEN];
716
717    let secret: &[u8] = match &my_private_key.inner_key {
718        KeyInner::X25519(priv_key) => {
719            x25519_diffie_hellman(&mut buffer, priv_key, peer_pub_bytes).or(Err(error_value))?
720        }
721        KeyInner::ECDH_P256(priv_key)
722        | KeyInner::ECDH_P384(priv_key)
723        | KeyInner::ECDH_P521(priv_key) => {
724            ec_key_ecdh(&mut buffer, priv_key, peer_pub_bytes, expected_nid).or(Err(error_value))?
725        }
726    };
727    kdf(secret)
728}
729
730// Current max secret length is P-521's.
731const MAX_AGREEMENT_SECRET_LEN: usize = AlgorithmID::ECDH_P521.private_key_len();
732
733#[inline]
734#[allow(clippy::needless_pass_by_value)]
735fn ec_key_ecdh<'a>(
736    buffer: &'a mut [u8; MAX_AGREEMENT_SECRET_LEN],
737    priv_key: &LcPtr<EVP_PKEY>,
738    peer_pub_key_bytes: &[u8],
739    nid: i32,
740) -> Result<&'a [u8], Unspecified> {
741    let mut pub_key = encoding::parse_ec_public_key(peer_pub_key_bytes, nid)?;
742
743    let mut pkey_ctx = priv_key.create_EVP_PKEY_CTX()?;
744
745    if 1 != unsafe { EVP_PKEY_derive_init(*pkey_ctx.as_mut()) } {
746        return Err(Unspecified);
747    }
748
749    if 1 != unsafe { EVP_PKEY_derive_set_peer(*pkey_ctx.as_mut(), *pub_key.as_mut()) } {
750        return Err(Unspecified);
751    }
752
753    let mut out_key_len = buffer.len();
754
755    if 1 != indicator_check!(unsafe {
756        EVP_PKEY_derive(*pkey_ctx.as_mut(), buffer.as_mut_ptr(), &mut out_key_len)
757    }) {
758        return Err(Unspecified);
759    }
760
761    if 0 == out_key_len {
762        return Err(Unspecified);
763    }
764
765    Ok(&buffer[0..out_key_len])
766}
767
768#[inline]
769fn x25519_diffie_hellman<'a>(
770    buffer: &'a mut [u8; MAX_AGREEMENT_SECRET_LEN],
771    priv_key: &LcPtr<EVP_PKEY>,
772    peer_pub_key: &[u8],
773) -> Result<&'a [u8], ()> {
774    let mut pkey_ctx = priv_key.create_EVP_PKEY_CTX()?;
775
776    if 1 != unsafe { EVP_PKEY_derive_init(*pkey_ctx.as_mut()) } {
777        return Err(());
778    }
779
780    let mut pub_key = try_parse_x25519_public_key_bytes(peer_pub_key)?;
781
782    if 1 != unsafe { EVP_PKEY_derive_set_peer(*pkey_ctx.as_mut(), *pub_key.as_mut()) } {
783        return Err(());
784    }
785
786    let mut out_key_len = buffer.len();
787
788    if 1 != indicator_check!(unsafe {
789        EVP_PKEY_derive(*pkey_ctx.as_mut(), buffer.as_mut_ptr(), &mut out_key_len)
790    }) {
791        return Err(());
792    }
793
794    debug_assert!(out_key_len == AlgorithmID::X25519.pub_key_len());
795
796    Ok(&buffer[0..AlgorithmID::X25519.pub_key_len()])
797}
798
799pub(crate) fn try_parse_x25519_public_key_bytes(
800    key_bytes: &[u8],
801) -> Result<LcPtr<EVP_PKEY>, Unspecified> {
802    LcPtr::<EVP_PKEY>::parse_rfc5280_public_key(key_bytes, EVP_PKEY_X25519)
803        .or(try_parse_x25519_public_key_raw_bytes(key_bytes))
804}
805
806fn try_parse_x25519_public_key_raw_bytes(key_bytes: &[u8]) -> Result<LcPtr<EVP_PKEY>, Unspecified> {
807    let expected_pub_key_len = X25519.id.pub_key_len();
808    if key_bytes.len() != expected_pub_key_len {
809        return Err(Unspecified);
810    }
811
812    Ok(LcPtr::<EVP_PKEY>::parse_raw_public_key(
813        key_bytes,
814        EVP_PKEY_X25519,
815    )?)
816}
817
818#[cfg(test)]
819mod tests {
820    use crate::agreement::{
821        agree, Algorithm, PrivateKey, PublicKey, UnparsedPublicKey, ECDH_P256, ECDH_P384,
822        ECDH_P521, X25519,
823    };
824    use crate::encoding::{
825        AsBigEndian, AsDer, Curve25519SeedBin, EcPrivateKeyBin, EcPrivateKeyRfc5915Der,
826        EcPublicKeyCompressedBin, EcPublicKeyUncompressedBin, Pkcs8V1Der, PublicKeyX509Der,
827    };
828    use crate::{rand, test};
829
830    #[test]
831    fn test_agreement_x25519() {
832        let alg = &X25519;
833        let peer_public = UnparsedPublicKey::new(
834            alg,
835            test::from_dirty_hex(
836                "e6db6867583030db3594c1a424b15f7c726624ec26b3353b10a903a6d0ab1c4c",
837            ),
838        );
839
840        let my_private = test::from_dirty_hex(
841            "a546e36bf0527c9d3b16154b82465edd62144c0ac1fc5a18506a2244ba449ac4",
842        );
843
844        let my_private = {
845            let rng = test::rand::FixedSliceRandom { bytes: &my_private };
846            PrivateKey::generate_for_test(alg, &rng).unwrap()
847        };
848
849        let my_public = test::from_dirty_hex(
850            "1c9fd88f45606d932a80c71824ae151d15d73e77de38e8e000852e614fae7019",
851        );
852        let output = test::from_dirty_hex(
853            "c3da55379de9c6908e94ea4df28d084f32eccf03491c71f754b4075577a28552",
854        );
855
856        assert_eq!(my_private.algorithm(), alg);
857
858        let be_private_key_buffer: Curve25519SeedBin = my_private.as_be_bytes().unwrap();
859        let be_private_key =
860            PrivateKey::from_private_key(&X25519, be_private_key_buffer.as_ref()).unwrap();
861        {
862            let result = agree(&be_private_key, &peer_public, (), |key_material| {
863                assert_eq!(key_material, &output[..]);
864                Ok(())
865            });
866            assert_eq!(result, Ok(()));
867        }
868
869        let computed_public = my_private.compute_public_key().unwrap();
870        assert_eq!(computed_public.as_ref(), &my_public[..]);
871
872        assert_eq!(computed_public.algorithm(), alg);
873        {
874            let result = agree(&my_private, &peer_public, (), |key_material| {
875                assert_eq!(key_material, &output[..]);
876                Ok(())
877            });
878            assert_eq!(result, Ok(()));
879        }
880        {
881            let result = agree(&my_private, &peer_public, (), |key_material| {
882                assert_eq!(key_material, &output[..]);
883                Ok(())
884            });
885            assert_eq!(result, Ok(()));
886        }
887    }
888
889    #[test]
890    fn test_agreement_invalid_keys() {
891        fn test_with_key(alg: &'static Algorithm, my_private_key: &PrivateKey, test_key: &[u8]) {
892            assert!(PrivateKey::from_private_key(alg, test_key).is_err());
893            assert!(PrivateKey::from_private_key_der(alg, test_key).is_err());
894            assert!(agree(
895                my_private_key,
896                &UnparsedPublicKey::new(alg, test_key),
897                (),
898                |_| Ok(())
899            )
900            .is_err());
901        }
902
903        let alg_variants: [&'static Algorithm; 4] = [&X25519, &ECDH_P256, &ECDH_P384, &ECDH_P521];
904
905        for alg in alg_variants {
906            let my_private_key = PrivateKey::generate(alg).unwrap();
907
908            let empty_key = [];
909            test_with_key(alg, &my_private_key, &empty_key);
910
911            let wrong_size_key: [u8; 31] = [
912                0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
913                23, 24, 25, 26, 27, 28, 29, 30,
914            ];
915            test_with_key(alg, &my_private_key, &wrong_size_key);
916        }
917    }
918
919    #[test]
920    fn test_agreement_ecdh_p256() {
921        let alg = &ECDH_P256;
922        let peer_public = UnparsedPublicKey::new(
923            alg,
924            test::from_dirty_hex(
925                "04D12DFB5289C8D4F81208B70270398C342296970A0BCCB74C736FC7554494BF6356FBF3CA366CC23E8157854C13C58D6AAC23F046ADA30F8353E74F33039872AB",
926            ),
927        );
928        assert_eq!(peer_public.algorithm(), alg);
929        assert_eq!(peer_public.bytes(), &peer_public.bytes);
930
931        let my_private = test::from_dirty_hex(
932            "C88F01F510D9AC3F70A292DAA2316DE544E9AAB8AFE84049C62A9C57862D1433",
933        );
934
935        let my_private = {
936            let rng = test::rand::FixedSliceRandom { bytes: &my_private };
937            PrivateKey::generate_for_test(alg, &rng).unwrap()
938        };
939
940        let my_public = test::from_dirty_hex(
941            "04DAD0B65394221CF9B051E1FECA5787D098DFE637FC90B9EF945D0C37725811805271A0461CDB8252D61F1C456FA3E59AB1F45B33ACCF5F58389E0577B8990BB3",
942        );
943        let output = test::from_dirty_hex(
944            "D6840F6B42F6EDAFD13116E0E12565202FEF8E9ECE7DCE03812464D04B9442DE",
945        );
946
947        assert_eq!(my_private.algorithm(), alg);
948
949        let be_private_key_buffer: EcPrivateKeyBin = my_private.as_be_bytes().unwrap();
950        let be_private_key =
951            PrivateKey::from_private_key(&ECDH_P256, be_private_key_buffer.as_ref()).unwrap();
952        {
953            let result = agree(&be_private_key, &peer_public, (), |key_material| {
954                assert_eq!(key_material, &output[..]);
955                Ok(())
956            });
957            assert_eq!(result, Ok(()));
958        }
959
960        let der_private_key_buffer: EcPrivateKeyRfc5915Der = my_private.as_der().unwrap();
961        let der_private_key =
962            PrivateKey::from_private_key_der(&ECDH_P256, der_private_key_buffer.as_ref()).unwrap();
963        {
964            let result = agree(&der_private_key, &peer_public, (), |key_material| {
965                assert_eq!(key_material, &output[..]);
966                Ok(())
967            });
968            assert_eq!(result, Ok(()));
969        }
970
971        let pkcs8_private_key_buffer: Pkcs8V1Der = my_private.as_der().unwrap();
972        let pkcs8_private_key =
973            PrivateKey::from_private_key_der(&ECDH_P256, pkcs8_private_key_buffer.as_ref())
974                .unwrap();
975        {
976            let result = agree(&pkcs8_private_key, &peer_public, (), |key_material| {
977                assert_eq!(key_material, &output[..]);
978                Ok(())
979            });
980            assert_eq!(result, Ok(()));
981        }
982
983        let computed_public = my_private.compute_public_key().unwrap();
984        assert_eq!(computed_public.as_ref(), &my_public[..]);
985
986        assert_eq!(computed_public.algorithm(), alg);
987
988        {
989            let result = agree(&my_private, &peer_public, (), |key_material| {
990                assert_eq!(key_material, &output[..]);
991                Ok(())
992            });
993            assert_eq!(result, Ok(()));
994        }
995
996        {
997            let result = agree(&my_private, &peer_public, (), |key_material| {
998                assert_eq!(key_material, &output[..]);
999                Ok(())
1000            });
1001            assert_eq!(result, Ok(()));
1002        }
1003    }
1004
1005    #[test]
1006    fn test_agreement_ecdh_p384() {
1007        let alg = &ECDH_P384;
1008        let peer_public = UnparsedPublicKey::new(
1009            alg,
1010            test::from_dirty_hex(
1011                "04E558DBEF53EECDE3D3FCCFC1AEA08A89A987475D12FD950D83CFA41732BC509D0D1AC43A0336DEF96FDA41D0774A3571DCFBEC7AACF3196472169E838430367F66EEBE3C6E70C416DD5F0C68759DD1FFF83FA40142209DFF5EAAD96DB9E6386C",
1012            ),
1013        );
1014
1015        let my_private = test::from_dirty_hex(
1016            "099F3C7034D4A2C699884D73A375A67F7624EF7C6B3C0F160647B67414DCE655E35B538041E649EE3FAEF896783AB194",
1017        );
1018
1019        let my_private = {
1020            let rng = test::rand::FixedSliceRandom { bytes: &my_private };
1021            PrivateKey::generate_for_test(alg, &rng).unwrap()
1022        };
1023
1024        let my_public = test::from_dirty_hex(
1025            "04667842D7D180AC2CDE6F74F37551F55755C7645C20EF73E31634FE72B4C55EE6DE3AC808ACB4BDB4C88732AEE95F41AA9482ED1FC0EEB9CAFC4984625CCFC23F65032149E0E144ADA024181535A0F38EEB9FCFF3C2C947DAE69B4C634573A81C",
1026        );
1027        let output = test::from_dirty_hex(
1028            "11187331C279962D93D604243FD592CB9D0A926F422E47187521287E7156C5C4D603135569B9E9D09CF5D4A270F59746",
1029        );
1030
1031        assert_eq!(my_private.algorithm(), alg);
1032
1033        let be_private_key_buffer: EcPrivateKeyBin = my_private.as_be_bytes().unwrap();
1034        let be_private_key =
1035            PrivateKey::from_private_key(&ECDH_P384, be_private_key_buffer.as_ref()).unwrap();
1036        {
1037            let result = agree(&be_private_key, &peer_public, (), |key_material| {
1038                assert_eq!(key_material, &output[..]);
1039                Ok(())
1040            });
1041            assert_eq!(result, Ok(()));
1042        }
1043
1044        let der_private_key_buffer: EcPrivateKeyRfc5915Der = my_private.as_der().unwrap();
1045        let der_private_key =
1046            PrivateKey::from_private_key_der(&ECDH_P384, der_private_key_buffer.as_ref()).unwrap();
1047        {
1048            let result = agree(&der_private_key, &peer_public, (), |key_material| {
1049                assert_eq!(key_material, &output[..]);
1050                Ok(())
1051            });
1052            assert_eq!(result, Ok(()));
1053        }
1054
1055        let computed_public = my_private.compute_public_key().unwrap();
1056        assert_eq!(computed_public.as_ref(), &my_public[..]);
1057
1058        assert_eq!(computed_public.algorithm(), alg);
1059
1060        {
1061            let result = agree(&my_private, &peer_public, (), |key_material| {
1062                assert_eq!(key_material, &output[..]);
1063                Ok(())
1064            });
1065            assert_eq!(result, Ok(()));
1066        }
1067    }
1068
1069    #[test]
1070    fn test_agreement_ecdh_p521() {
1071        let alg = &ECDH_P521;
1072        let peer_public = UnparsedPublicKey::new(
1073            alg,
1074            test::from_dirty_hex(
1075                "0401a32099b02c0bd85371f60b0dd20890e6c7af048c8179890fda308b359dbbc2b7a832bb8c6526c4af99a7ea3f0b3cb96ae1eb7684132795c478ad6f962e4a6f446d017627357b39e9d7632a1370b3e93c1afb5c851b910eb4ead0c9d387df67cde85003e0e427552f1cd09059aad0262e235cce5fba8cedc4fdc1463da76dcd4b6d1a46",
1076            ),
1077        );
1078
1079        let my_private = test::from_dirty_hex(
1080            "00df14b1f1432a7b0fb053965fd8643afee26b2451ecb6a8a53a655d5fbe16e4c64ce8647225eb11e7fdcb23627471dffc5c2523bd2ae89957cba3a57a23933e5a78",
1081        );
1082
1083        let my_private = {
1084            let rng = test::rand::FixedSliceRandom { bytes: &my_private };
1085            PrivateKey::generate_for_test(alg, &rng).unwrap()
1086        };
1087
1088        let my_public = test::from_dirty_hex(
1089            "04004e8583bbbb2ecd93f0714c332dff5ab3bc6396e62f3c560229664329baa5138c3bb1c36428abd4e23d17fcb7a2cfcc224b2e734c8941f6f121722d7b6b9415457601cf0874f204b0363f020864672fadbf87c8811eb147758b254b74b14fae742159f0f671a018212bbf25b8519e126d4cad778cfff50d288fd39ceb0cac635b175ec0",
1090        );
1091        let output = test::from_dirty_hex(
1092            "01aaf24e5d47e4080c18c55ea35581cd8da30f1a079565045d2008d51b12d0abb4411cda7a0785b15d149ed301a3697062f42da237aa7f07e0af3fd00eb1800d9c41",
1093        );
1094
1095        assert_eq!(my_private.algorithm(), alg);
1096
1097        let be_private_key_buffer: EcPrivateKeyBin = my_private.as_be_bytes().unwrap();
1098        let be_private_key =
1099            PrivateKey::from_private_key(&ECDH_P521, be_private_key_buffer.as_ref()).unwrap();
1100        {
1101            let result = agree(&be_private_key, &peer_public, (), |key_material| {
1102                assert_eq!(key_material, &output[..]);
1103                Ok(())
1104            });
1105            assert_eq!(result, Ok(()));
1106        }
1107
1108        let der_private_key_buffer: EcPrivateKeyRfc5915Der = my_private.as_der().unwrap();
1109        let der_private_key =
1110            PrivateKey::from_private_key_der(&ECDH_P521, der_private_key_buffer.as_ref()).unwrap();
1111        {
1112            let result = agree(&der_private_key, &peer_public, (), |key_material| {
1113                assert_eq!(key_material, &output[..]);
1114                Ok(())
1115            });
1116            assert_eq!(result, Ok(()));
1117        }
1118
1119        let computed_public = my_private.compute_public_key().unwrap();
1120        assert_eq!(computed_public.as_ref(), &my_public[..]);
1121
1122        assert_eq!(computed_public.algorithm(), alg);
1123        {
1124            let result = agree(&my_private, &peer_public, (), |key_material| {
1125                assert_eq!(key_material, &output[..]);
1126                Ok(())
1127            });
1128            assert_eq!(result, Ok(()));
1129        }
1130        {
1131            let result = agree(&my_private, &peer_public, (), |key_material| {
1132                assert_eq!(key_material, &output[..]);
1133                Ok(())
1134            });
1135            assert_eq!(result, Ok(()));
1136        }
1137    }
1138
1139    #[test]
1140    fn agreement_traits() {
1141        use crate::test;
1142        use regex::{self, Regex};
1143
1144        let rng = rand::SystemRandom::new();
1145        let private_key = PrivateKey::generate_for_test(&ECDH_P256, &rng).unwrap();
1146
1147        test::compile_time_assert_send::<PrivateKey>();
1148        test::compile_time_assert_sync::<PrivateKey>();
1149
1150        assert_eq!(
1151            format!("{:?}", &private_key),
1152            "PrivateKey { algorithm: Algorithm { curve: P256 } }"
1153        );
1154
1155        let ephemeral_private_key = PrivateKey::generate_for_test(&ECDH_P256, &rng).unwrap();
1156
1157        test::compile_time_assert_send::<PrivateKey>();
1158        test::compile_time_assert_sync::<PrivateKey>();
1159
1160        assert_eq!(
1161            format!("{:?}", &ephemeral_private_key),
1162            "PrivateKey { algorithm: Algorithm { curve: P256 } }"
1163        );
1164
1165        let public_key = private_key.compute_public_key().unwrap();
1166        let pubkey_re = Regex::new(
1167            "PublicKey \\{ algorithm: Algorithm \\{ curve: P256 \\}, bytes: \"[0-9a-f]+\" \\}",
1168        )
1169        .unwrap();
1170        let pubkey_debug = format!("{:?}", &public_key);
1171
1172        assert!(
1173            pubkey_re.is_match(&pubkey_debug),
1174            "pubkey_debug: {pubkey_debug}"
1175        );
1176
1177        #[allow(clippy::redundant_clone)]
1178        let pubkey_clone = public_key.clone();
1179        assert_eq!(public_key.as_ref(), pubkey_clone.as_ref());
1180        assert_eq!(pubkey_debug, format!("{:?}", &pubkey_clone));
1181
1182        test::compile_time_assert_clone::<PublicKey>();
1183        test::compile_time_assert_send::<PublicKey>();
1184        test::compile_time_assert_sync::<PublicKey>();
1185
1186        // Verify `PublicKey` implements `Debug`.
1187        //
1188        // TODO: Test the actual output.
1189        let _: &dyn core::fmt::Debug = &public_key;
1190
1191        test::compile_time_assert_clone::<UnparsedPublicKey<&[u8]>>();
1192        test::compile_time_assert_copy::<UnparsedPublicKey<&[u8]>>();
1193        test::compile_time_assert_sync::<UnparsedPublicKey<&[u8]>>();
1194
1195        test::compile_time_assert_clone::<UnparsedPublicKey<Vec<u8>>>();
1196        test::compile_time_assert_sync::<UnparsedPublicKey<Vec<u8>>>();
1197
1198        let bytes = [0x01, 0x02, 0x03];
1199
1200        let unparsed_public_key = UnparsedPublicKey::new(&X25519, &bytes);
1201        let unparsed_pubkey_clone = unparsed_public_key;
1202        assert_eq!(
1203            format!("{unparsed_public_key:?}"),
1204            r#"UnparsedPublicKey { algorithm: Algorithm { curve: Curve25519 }, bytes: "010203" }"#
1205        );
1206        assert_eq!(
1207            format!("{unparsed_pubkey_clone:?}"),
1208            r#"UnparsedPublicKey { algorithm: Algorithm { curve: Curve25519 }, bytes: "010203" }"#
1209        );
1210
1211        let unparsed_public_key = UnparsedPublicKey::new(&X25519, Vec::from(bytes));
1212        #[allow(clippy::redundant_clone)]
1213        let unparsed_pubkey_clone = unparsed_public_key.clone();
1214        assert_eq!(
1215            format!("{unparsed_public_key:?}"),
1216            r#"UnparsedPublicKey { algorithm: Algorithm { curve: Curve25519 }, bytes: "010203" }"#
1217        );
1218        assert_eq!(
1219            format!("{unparsed_pubkey_clone:?}"),
1220            r#"UnparsedPublicKey { algorithm: Algorithm { curve: Curve25519 }, bytes: "010203" }"#
1221        );
1222    }
1223
1224    #[test]
1225    fn test_agreement_random() {
1226        let test_algorithms = [&ECDH_P256, &ECDH_P384, &ECDH_P521, &X25519];
1227
1228        for alg in test_algorithms {
1229            test_agreement_random_helper(alg);
1230        }
1231    }
1232
1233    fn test_agreement_random_helper(alg: &'static Algorithm) {
1234        let peer_private = PrivateKey::generate(alg).unwrap();
1235        let my_private = PrivateKey::generate(alg).unwrap();
1236
1237        let peer_public_keys =
1238            public_key_formats_helper(&peer_private.compute_public_key().unwrap());
1239
1240        let my_public_keys = public_key_formats_helper(&my_private.compute_public_key().unwrap());
1241
1242        let mut results: Vec<Vec<u8>> = Vec::new();
1243
1244        for peer_public in peer_public_keys {
1245            let peer_public = UnparsedPublicKey::new(alg, peer_public);
1246            let result = agree(&my_private, &peer_public, (), |key_material| {
1247                results.push(key_material.to_vec());
1248                Ok(())
1249            });
1250            assert_eq!(result, Ok(()));
1251        }
1252
1253        for my_public in my_public_keys {
1254            let my_public = UnparsedPublicKey::new(alg, my_public);
1255            let result = agree(&peer_private, &my_public, (), |key_material| {
1256                results.push(key_material.to_vec());
1257                Ok(())
1258            });
1259            assert_eq!(result, Ok(()));
1260        }
1261
1262        let key_types_tested = match alg.id {
1263            crate::agreement::AlgorithmID::ECDH_P256
1264            | crate::agreement::AlgorithmID::ECDH_P384
1265            | crate::agreement::AlgorithmID::ECDH_P521 => 4,
1266            crate::agreement::AlgorithmID::X25519 => 2,
1267        };
1268
1269        assert_eq!(results.len(), key_types_tested * 2); // Multiplied by two because we tested the other direction
1270
1271        assert_eq!(results[0..key_types_tested], results[key_types_tested..]);
1272    }
1273
1274    fn public_key_formats_helper(public_key: &PublicKey) -> Vec<Vec<u8>> {
1275        let verify_ec_raw_traits = matches!(
1276            public_key.algorithm().id,
1277            crate::agreement::AlgorithmID::ECDH_P256
1278                | crate::agreement::AlgorithmID::ECDH_P384
1279                | crate::agreement::AlgorithmID::ECDH_P521
1280        );
1281
1282        let mut public_keys = Vec::<Vec<u8>>::new();
1283        public_keys.push(public_key.as_ref().into());
1284
1285        if verify_ec_raw_traits {
1286            let raw = AsBigEndian::<EcPublicKeyCompressedBin>::as_be_bytes(public_key).unwrap();
1287            public_keys.push(raw.as_ref().into());
1288            let raw = AsBigEndian::<EcPublicKeyUncompressedBin>::as_be_bytes(public_key).unwrap();
1289            public_keys.push(raw.as_ref().into());
1290        }
1291
1292        let peer_x509 = AsDer::<PublicKeyX509Der>::as_der(public_key).unwrap();
1293        public_keys.push(peer_x509.as_ref().into());
1294
1295        public_keys
1296    }
1297
1298    #[test]
1299    fn private_key_drop() {
1300        let private_key = PrivateKey::generate(&ECDH_P256).unwrap();
1301        let public_key = private_key.compute_public_key().unwrap();
1302        // PublicKey maintains a reference counted pointer to private keys EVP_PKEY so we test that with drop
1303        drop(private_key);
1304        let _ = AsBigEndian::<EcPublicKeyCompressedBin>::as_be_bytes(&public_key).unwrap();
1305        let _ = AsBigEndian::<EcPublicKeyUncompressedBin>::as_be_bytes(&public_key).unwrap();
1306        let _ = AsDer::<PublicKeyX509Der>::as_der(&public_key).unwrap();
1307    }
1308}