Coverage Report

Created: 2026-08-14 07:05

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