1use alloc::boxed::Box;
2use alloc::vec;
3use alloc::vec::Vec;
4use core::fmt;
5
6use zeroize::{Zeroize, Zeroizing};
7
8use crate::common_state::{CommonState, Side};
9use crate::conn::ConnectionRandoms;
10use crate::crypto;
11use crate::crypto::cipher::{AeadKey, MessageDecrypter, MessageEncrypter, Tls12AeadAlgorithm};
12use crate::crypto::hash;
13use crate::enums::{AlertDescription, SignatureScheme};
14use crate::error::{Error, InvalidMessage};
15use crate::msgs::codec::{Codec, Reader};
16use crate::msgs::handshake::{KeyExchangeAlgorithm, KxDecode};
17use crate::suites::{CipherSuiteCommon, PartiallyExtractedSecrets, SupportedCipherSuite};
18use crate::version::Tls12Version;
19
20#[allow(clippy::exhaustive_structs)]
22pub struct Tls12CipherSuite {
23 pub common: CipherSuiteCommon,
25
26 pub protocol_version: &'static Tls12Version,
37
38 pub prf_provider: &'static dyn crypto::tls12::Prf,
45
46 pub kx: KeyExchangeAlgorithm,
54
55 pub sign: &'static [SignatureScheme],
62
63 pub aead_alg: &'static dyn Tls12AeadAlgorithm,
66}
67
68impl Tls12CipherSuite {
69 pub fn resolve_sig_schemes(&self, offered: &[SignatureScheme]) -> Vec<SignatureScheme> {
73 self.sign
74 .iter()
75 .filter(|pref| offered.contains(pref))
76 .cloned()
77 .collect()
78 }
79
80 pub fn fips(&self) -> bool {
84 self.common.fips() && self.prf_provider.fips() && self.aead_alg.fips()
85 }
86}
87
88impl From<&'static Tls12CipherSuite> for SupportedCipherSuite {
89 fn from(s: &'static Tls12CipherSuite) -> Self {
90 Self::Tls12(s)
91 }
92}
93
94impl PartialEq for Tls12CipherSuite {
95 fn eq(&self, other: &Self) -> bool {
96 self.common.suite == other.common.suite
97 }
98}
99
100impl fmt::Debug for Tls12CipherSuite {
101 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
102 f.debug_struct("Tls12CipherSuite")
103 .field("suite", &self.common.suite)
104 .finish()
105 }
106}
107
108pub(crate) struct ConnectionSecrets {
110 pub(crate) randoms: ConnectionRandoms,
111 suite: &'static Tls12CipherSuite,
112 master_secret: [u8; 48],
113 master_secret_prf: Box<dyn crypto::tls12::PrfSecret>,
114}
115
116impl ConnectionSecrets {
117 pub(crate) fn from_key_exchange(
118 kx: Box<dyn crypto::ActiveKeyExchange>,
119 peer_pub_key: &[u8],
120 ems_seed: Option<hash::Output>,
121 randoms: ConnectionRandoms,
122 suite: &'static Tls12CipherSuite,
123 ) -> Result<Self, Error> {
124 let (label, seed) = match ems_seed {
125 Some(seed) => ("extended master secret", Seed::Ems(seed)),
126 None => (
127 "master secret",
128 Seed::Randoms(join_randoms(&randoms.client, &randoms.server)),
129 ),
130 };
131
132 let mut master_secret = [0u8; 48];
137 suite.prf_provider.for_key_exchange(
138 &mut master_secret,
139 kx,
140 peer_pub_key,
141 label.as_bytes(),
142 seed.as_ref(),
143 )?;
144
145 let master_secret_prf = suite
146 .prf_provider
147 .new_secret(&master_secret);
148
149 Ok(Self {
150 randoms,
151 suite,
152 master_secret,
153 master_secret_prf,
154 })
155 }
156
157 pub(crate) fn new_resume(
158 randoms: ConnectionRandoms,
159 suite: &'static Tls12CipherSuite,
160 master_secret: &[u8; 48],
161 ) -> Self {
162 Self {
163 randoms,
164 suite,
165 master_secret: *master_secret,
166 master_secret_prf: suite
167 .prf_provider
168 .new_secret(master_secret),
169 }
170 }
171
172 pub(crate) fn make_cipher_pair(&self, side: Side) -> MessageCipherPair {
175 let key_block = self.make_key_block();
178 let shape = self.suite.aead_alg.key_block_shape();
179
180 let (client_write_key, key_block) = key_block.split_at(shape.enc_key_len);
181 let (server_write_key, key_block) = key_block.split_at(shape.enc_key_len);
182 let (client_write_iv, key_block) = key_block.split_at(shape.fixed_iv_len);
183 let (server_write_iv, extra) = key_block.split_at(shape.fixed_iv_len);
184
185 let (write_key, write_iv, read_key, read_iv) = match side {
186 Side::Client => (
187 client_write_key,
188 client_write_iv,
189 server_write_key,
190 server_write_iv,
191 ),
192 Side::Server => (
193 server_write_key,
194 server_write_iv,
195 client_write_key,
196 client_write_iv,
197 ),
198 };
199
200 (
201 self.suite
202 .aead_alg
203 .decrypter(AeadKey::new(read_key), read_iv),
204 self.suite
205 .aead_alg
206 .encrypter(AeadKey::new(write_key), write_iv, extra),
207 )
208 }
209
210 fn make_key_block(&self) -> Zeroizing<Vec<u8>> {
211 let shape = self.suite.aead_alg.key_block_shape();
212
213 let len = (shape.enc_key_len + shape.fixed_iv_len) * 2 + shape.explicit_nonce_len;
214
215 let mut out = vec![0u8; len];
216
217 let randoms = join_randoms(&self.randoms.server, &self.randoms.client);
220 self.master_secret_prf
221 .prf(&mut out, b"key expansion", &randoms);
222
223 Zeroizing::new(out)
224 }
225
226 pub(crate) fn suite(&self) -> &'static Tls12CipherSuite {
227 self.suite
228 }
229
230 pub(crate) fn master_secret(&self) -> &[u8; 48] {
231 &self.master_secret
232 }
233
234 fn make_verify_data(&self, handshake_hash: &hash::Output, label: &[u8]) -> [u8; 12] {
235 let mut out = [0u8; 12];
236 self.master_secret_prf
237 .prf(&mut out, label, handshake_hash.as_ref());
238 out
239 }
240
241 pub(crate) fn client_verify_data(&self, handshake_hash: &hash::Output) -> [u8; 12] {
242 self.make_verify_data(handshake_hash, b"client finished")
243 }
244
245 pub(crate) fn server_verify_data(&self, handshake_hash: &hash::Output) -> [u8; 12] {
246 self.make_verify_data(handshake_hash, b"server finished")
247 }
248
249 pub(crate) fn export_keying_material(
250 &self,
251 output: &mut [u8],
252 label: &[u8],
253 context: Option<&[u8]>,
254 ) {
255 let mut randoms = Vec::new();
256 randoms.extend_from_slice(&self.randoms.client);
257 randoms.extend_from_slice(&self.randoms.server);
258 if let Some(context) = context {
259 assert!(context.len() <= 0xffff);
260 (context.len() as u16).encode(&mut randoms);
261 randoms.extend_from_slice(context);
262 }
263
264 self.master_secret_prf
265 .prf(output, label, &randoms);
266 }
267
268 pub(crate) fn extract_secrets(&self, side: Side) -> Result<PartiallyExtractedSecrets, Error> {
269 let key_block = self.make_key_block();
271 let shape = self.suite.aead_alg.key_block_shape();
272
273 let (client_key, key_block) = key_block.split_at(shape.enc_key_len);
274 let (server_key, key_block) = key_block.split_at(shape.enc_key_len);
275 let (client_iv, key_block) = key_block.split_at(shape.fixed_iv_len);
276 let (server_iv, explicit_nonce) = key_block.split_at(shape.fixed_iv_len);
277
278 let client_secrets = self.suite.aead_alg.extract_keys(
279 AeadKey::new(client_key),
280 client_iv,
281 explicit_nonce,
282 )?;
283 let server_secrets = self.suite.aead_alg.extract_keys(
284 AeadKey::new(server_key),
285 server_iv,
286 explicit_nonce,
287 )?;
288
289 let (tx, rx) = match side {
290 Side::Client => (client_secrets, server_secrets),
291 Side::Server => (server_secrets, client_secrets),
292 };
293 Ok(PartiallyExtractedSecrets { tx, rx })
294 }
295}
296
297impl Drop for ConnectionSecrets {
298 fn drop(&mut self) {
299 self.master_secret.zeroize();
300 }
301}
302
303enum Seed {
304 Ems(hash::Output),
305 Randoms([u8; 64]),
306}
307
308impl AsRef<[u8]> for Seed {
309 fn as_ref(&self) -> &[u8] {
311 match self {
312 Self::Ems(seed) => seed.as_ref(),
314 Self::Randoms(randoms) => randoms.as_ref(),
316 }
317 }
318}
319
320fn join_randoms(first: &[u8; 32], second: &[u8; 32]) -> [u8; 64] {
321 let mut randoms = [0u8; 64];
322 randoms[..32].copy_from_slice(first);
323 randoms[32..].copy_from_slice(second);
324 randoms
325}
326
327type MessageCipherPair = (Box<dyn MessageDecrypter>, Box<dyn MessageEncrypter>);
328
329pub(crate) fn decode_kx_params<'a, T: KxDecode<'a>>(
330 kx_algorithm: KeyExchangeAlgorithm,
331 common: &mut CommonState,
332 kx_params: &'a [u8],
333) -> Result<T, Error> {
334 let mut rd = Reader::init(kx_params);
335 let kx_params = T::decode(&mut rd, kx_algorithm)?;
336 match rd.any_left() {
337 false => Ok(kx_params),
338 true => Err(common.send_fatal_alert(
339 AlertDescription::DecodeError,
340 InvalidMessage::InvalidDhParams,
341 )),
342 }
343}
344
345pub(crate) const DOWNGRADE_SENTINEL: [u8; 8] = [0x44, 0x4f, 0x57, 0x4e, 0x47, 0x52, 0x44, 0x01];
346
347#[cfg(test)]
348#[macro_rules_attribute::apply(test_for_each_provider)]
349mod tests {
350 use super::provider::kx_group::X25519;
351 use super::*;
352 use crate::common_state::{CommonState, Side};
353 use crate::msgs::handshake::{ServerEcdhParams, ServerKeyExchangeParams};
354
355 #[test]
356 fn server_ecdhe_remaining_bytes() {
357 let key = X25519.start().unwrap();
358 let server_params = ServerEcdhParams::new(&*key);
359 let mut server_buf = Vec::new();
360 server_params.encode(&mut server_buf);
361 server_buf.push(34);
362
363 let mut common = CommonState::new(Side::Client);
364 assert!(
365 decode_kx_params::<ServerKeyExchangeParams>(
366 KeyExchangeAlgorithm::ECDHE,
367 &mut common,
368 &server_buf
369 )
370 .is_err()
371 );
372 }
373
374 #[test]
375 fn client_ecdhe_invalid() {
376 let mut common = CommonState::new(Side::Server);
377 assert!(
378 decode_kx_params::<ServerKeyExchangeParams>(
379 KeyExchangeAlgorithm::ECDHE,
380 &mut common,
381 &[34],
382 )
383 .is_err()
384 );
385 }
386}