Coverage Report

Created: 2025-11-16 06:37

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