Coverage Report

Created: 2025-07-23 07:04

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