rustls/crypto/aws_lc_rs/
kx.rs1use alloc::boxed::Box;
2use core::fmt;
3
4use aws_lc_rs::agreement;
5use aws_lc_rs::rand::SystemRandom;
6
7use crate::crypto::kx::{ActiveKeyExchange, SharedSecret, StartedKeyExchange};
8use crate::crypto::{GetRandomFailed, NamedGroup, SupportedKxGroup};
9use crate::error::{Error, PeerMisbehaved};
10
11struct KxGroup {
13 name: NamedGroup,
15
16 agreement_algorithm: &'static agreement::Algorithm,
18
19 fips_allowed: bool,
24
25 pub_key_validator: fn(&[u8]) -> bool,
38}
39
40impl SupportedKxGroup for KxGroup {
41 fn start(&self) -> Result<StartedKeyExchange, Error> {
42 let rng = SystemRandom::new();
43 let priv_key = agreement::EphemeralPrivateKey::generate(self.agreement_algorithm, &rng)
44 .map_err(|_| GetRandomFailed)?;
45
46 let pub_key = priv_key
47 .compute_public_key()
48 .map_err(|_| GetRandomFailed)?;
49
50 Ok(StartedKeyExchange::Single(Box::new(KeyExchange {
51 name: self.name,
52 agreement_algorithm: self.agreement_algorithm,
53 priv_key,
54 pub_key,
55 pub_key_validator: self.pub_key_validator,
56 })))
57 }
58
59 fn name(&self) -> NamedGroup {
60 self.name
61 }
62
63 fn fips(&self) -> bool {
64 self.fips_allowed && super::fips()
65 }
66}
67
68impl fmt::Debug for KxGroup {
69 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
70 self.name.fmt(f)
71 }
72}
73
74pub static X25519: &dyn SupportedKxGroup = &KxGroup {
76 name: NamedGroup::X25519,
77 agreement_algorithm: &agreement::X25519,
78
79 fips_allowed: false,
85
86 pub_key_validator: |point: &[u8]| point.len() == 32,
87};
88
89pub static SECP256R1: &dyn SupportedKxGroup = &KxGroup {
91 name: NamedGroup::secp256r1,
92 agreement_algorithm: &agreement::ECDH_P256,
93 fips_allowed: true,
94 pub_key_validator: uncompressed_point,
95};
96
97pub static SECP384R1: &dyn SupportedKxGroup = &KxGroup {
99 name: NamedGroup::secp384r1,
100 agreement_algorithm: &agreement::ECDH_P384,
101 fips_allowed: true,
102 pub_key_validator: uncompressed_point,
103};
104
105fn uncompressed_point(point: &[u8]) -> bool {
106 matches!(point.first(), Some(0x04))
110}
111
112struct KeyExchange {
115 name: NamedGroup,
116 agreement_algorithm: &'static agreement::Algorithm,
117 priv_key: agreement::EphemeralPrivateKey,
118 pub_key: agreement::PublicKey,
119 pub_key_validator: fn(&[u8]) -> bool,
120}
121
122impl ActiveKeyExchange for KeyExchange {
123 fn complete(self: Box<Self>, peer: &[u8]) -> Result<SharedSecret, Error> {
125 if !(self.pub_key_validator)(peer) {
126 return Err(PeerMisbehaved::InvalidKeyShare.into());
127 }
128 let peer_key = agreement::UnparsedPublicKey::new(self.agreement_algorithm, peer);
129 super::ring_shim::agree_ephemeral(self.priv_key, &peer_key)
130 .map_err(|_| PeerMisbehaved::InvalidKeyShare.into())
131 }
132
133 fn group(&self) -> NamedGroup {
135 self.name
136 }
137
138 fn pub_key(&self) -> &[u8] {
140 self.pub_key.as_ref()
141 }
142}
143
144#[cfg(test)]
145mod tests {
146 use std::format;
147
148 #[test]
149 fn kxgroup_fmt_yields_name() {
150 assert_eq!("X25519", format!("{:?}", super::X25519));
151 }
152}
153
154#[cfg(bench)]
155mod benchmarks {
156 #[bench]
157 fn bench_x25519(b: &mut test::Bencher) {
158 bench_any(b, super::X25519);
159 }
160
161 #[bench]
162 fn bench_ecdh_p256(b: &mut test::Bencher) {
163 bench_any(b, super::SECP256R1);
164 }
165
166 #[bench]
167 fn bench_ecdh_p384(b: &mut test::Bencher) {
168 bench_any(b, super::SECP384R1);
169 }
170
171 fn bench_any(b: &mut test::Bencher, kxg: &dyn super::SupportedKxGroup) {
172 b.iter(|| {
173 let akx = kxg.start().unwrap().into_single();
174 let pub_key = akx.pub_key().to_vec();
175 test::black_box(akx.complete(&pub_key).unwrap());
176 });
177 }
178}