1 | #![allow (clippy::duplicate_mod)] |
2 | |
3 | use crate::crypto::{ActiveKeyExchange, SharedSecret, SupportedKxGroup}; |
4 | use crate::error::{Error, PeerMisbehaved}; |
5 | use crate::msgs::enums::NamedGroup; |
6 | use crate::rand::GetRandomFailed; |
7 | |
8 | use super::ring_like::agreement; |
9 | use super::ring_like::rand::SystemRandom; |
10 | |
11 | use alloc::boxed::Box; |
12 | use 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. |
18 | struct 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 | |
26 | impl 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 | |
49 | impl 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) |
56 | pub static X25519: &dyn SupportedKxGroup = &KxGroup { |
57 | name: NamedGroup::X25519, |
58 | agreement_algorithm: &agreement::X25519, |
59 | }; |
60 | |
61 | /// Ephemeral ECDH on secp256r1 (aka NIST-P256) |
62 | pub 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) |
68 | pub 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. |
74 | pub 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. |
78 | struct KeyExchange { |
79 | name: NamedGroup, |
80 | agreement_algorithm: &'static agreement::Algorithm, |
81 | priv_key: agreement::EphemeralPrivateKey, |
82 | pub_key: agreement::PublicKey, |
83 | } |
84 | |
85 | impl 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)] |
105 | mod tests { |
106 | #[test ] |
107 | fn kxgroup_fmt_yields_name() { |
108 | assert_eq!("X25519" , format!("{:?}" , super::X25519)); |
109 | } |
110 | } |
111 | |
112 | #[cfg (bench)] |
113 | mod 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 | |