1#![allow(clippy::duplicate_mod)]
2
3use crate::crypto::{ActiveKeyExchange, SharedSecret, SupportedKxGroup};
4use crate::error::{Error, PeerMisbehaved};
5use crate::msgs::enums::NamedGroup;
6use crate::rand::GetRandomFailed;
7
8use super::ring_like::agreement;
9use super::ring_like::rand::SystemRandom;
10
11use alloc::boxed::Box;
12use core::fmt;
13
14/// A key-exchange group supported by *ring*.
15///
16/// All possible instances of this class are provided by the library in
17/// the [`ALL_KX_GROUPS`] array.
18struct KxGroup {
19 /// The IANA "TLS Supported Groups" name of the group
20 name: NamedGroup,
21
22 /// The corresponding ring agreement::Algorithm
23 agreement_algorithm: &'static agreement::Algorithm,
24}
25
26impl SupportedKxGroup for KxGroup {
27 fn start(&self) -> Result<Box<dyn ActiveKeyExchange>, Error> {
28 let rng: SystemRandom = SystemRandom::new();
29 let priv_key: EphemeralPrivateKey = agreement::EphemeralPrivateKey::generate(self.agreement_algorithm, &rng)
30 .map_err(|_| GetRandomFailed)?;
31
32 let pub_key: PublicKey = priv_key
33 .compute_public_key()
34 .map_err(|_| GetRandomFailed)?;
35
36 Ok(Box::new(KeyExchange {
37 name: self.name,
38 agreement_algorithm: self.agreement_algorithm,
39 priv_key,
40 pub_key,
41 }))
42 }
43
44 fn name(&self) -> NamedGroup {
45 self.name
46 }
47}
48
49impl fmt::Debug for KxGroup {
50 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
51 self.name.fmt(f)
52 }
53}
54
55/// Ephemeral ECDH on curve25519 (see RFC7748)
56pub static X25519: &dyn SupportedKxGroup = &KxGroup {
57 name: NamedGroup::X25519,
58 agreement_algorithm: &agreement::X25519,
59};
60
61/// Ephemeral ECDH on secp256r1 (aka NIST-P256)
62pub static SECP256R1: &dyn SupportedKxGroup = &KxGroup {
63 name: NamedGroup::secp256r1,
64 agreement_algorithm: &agreement::ECDH_P256,
65};
66
67/// Ephemeral ECDH on secp384r1 (aka NIST-P384)
68pub static SECP384R1: &dyn SupportedKxGroup = &KxGroup {
69 name: NamedGroup::secp384r1,
70 agreement_algorithm: &agreement::ECDH_P384,
71};
72
73/// A list of all the key exchange groups supported by rustls.
74pub static ALL_KX_GROUPS: &[&dyn SupportedKxGroup] = &[X25519, SECP256R1, SECP384R1];
75
76/// An in-progress key exchange. This has the algorithm,
77/// our private key, and our public key.
78struct KeyExchange {
79 name: NamedGroup,
80 agreement_algorithm: &'static agreement::Algorithm,
81 priv_key: agreement::EphemeralPrivateKey,
82 pub_key: agreement::PublicKey,
83}
84
85impl ActiveKeyExchange for KeyExchange {
86 /// Completes the key exchange, given the peer's public key.
87 fn complete(self: Box<Self>, peer: &[u8]) -> Result<SharedSecret, Error> {
88 let peer_key: UnparsedPublicKey<&[u8]> = agreement::UnparsedPublicKey::new(self.agreement_algorithm, bytes:peer);
89 super::ring_shim::agree_ephemeral(self.priv_key, &peer_key)
90 .map_err(|_| PeerMisbehaved::InvalidKeyShare.into())
91 }
92
93 /// Return the group being used.
94 fn group(&self) -> NamedGroup {
95 self.name
96 }
97
98 /// Return the public key being used.
99 fn pub_key(&self) -> &[u8] {
100 self.pub_key.as_ref()
101 }
102}
103
104#[cfg(test)]
105mod tests {
106 #[test]
107 fn kxgroup_fmt_yields_name() {
108 assert_eq!("X25519", format!("{:?}", super::X25519));
109 }
110}
111
112#[cfg(bench)]
113mod benchmarks {
114 #[bench]
115 fn bench_x25519(b: &mut test::Bencher) {
116 bench_any(b, super::X25519);
117 }
118
119 #[bench]
120 fn bench_ecdh_p256(b: &mut test::Bencher) {
121 bench_any(b, super::SECP256R1);
122 }
123
124 #[bench]
125 fn bench_ecdh_p384(b: &mut test::Bencher) {
126 bench_any(b, super::SECP384R1);
127 }
128
129 fn bench_any(b: &mut test::Bencher, kxg: &dyn super::SupportedKxGroup) {
130 b.iter(|| {
131 let akx = kxg.start().unwrap();
132 let pub_key = akx.pub_key().to_vec();
133 test::black_box(akx.complete(&pub_key).unwrap());
134 });
135 }
136}
137