1use alloc::boxed::Box;
2use alloc::vec;
3use alloc::vec::Vec;
4use core::fmt;
5
6use zeroize::Zeroizing;
7
8use crate::common_state::{CommonState, Protocol, Side};
9use crate::conn::{ConnectionRandoms, Exporter};
10use crate::crypto::cipher::{AeadKey, MessageDecrypter, MessageEncrypter, Tls12AeadAlgorithm};
11use crate::crypto::{self, hash};
12use crate::enums::{AlertDescription, ProtocolVersion, SignatureScheme};
13use crate::error::{ApiMisuse, Error, InvalidMessage};
14use crate::msgs::codec::{Codec, Reader};
15use crate::msgs::handshake::{KeyExchangeAlgorithm, KxDecode};
16use crate::suites::{CipherSuiteCommon, PartiallyExtractedSecrets, Suite, SupportedCipherSuite};
17use crate::version::Tls12Version;
18
19#[expect(clippy::exhaustive_structs)]
21pub struct Tls12CipherSuite {
22 pub common: CipherSuiteCommon,
24
25 pub protocol_version: &'static Tls12Version,
36
37 pub prf_provider: &'static dyn crypto::tls12::Prf,
44
45 pub kx: KeyExchangeAlgorithm,
53
54 pub sign: &'static [SignatureScheme],
61
62 pub aead_alg: &'static dyn Tls12AeadAlgorithm,
65}
66
67impl Tls12CipherSuite {
68 pub fn resolve_sig_schemes(&self, offered: &[SignatureScheme]) -> Vec<SignatureScheme> {
72 self.sign
73 .iter()
74 .filter(|pref| offered.contains(pref))
75 .copied()
76 .collect()
77 }
78
79 pub fn fips(&self) -> bool {
83 self.common.fips() && self.prf_provider.fips() && self.aead_alg.fips()
84 }
85}
86
87impl Suite for Tls12CipherSuite {
88 fn client_handler(&self) -> &'static dyn crate::client::ClientHandler<Self> {
89 self.protocol_version.client
90 }
91
92 fn server_handler(&self) -> &'static dyn crate::server::ServerHandler<Self> {
93 self.protocol_version.server
94 }
95
96 fn usable_for_protocol(&self, proto: Protocol) -> bool {
100 matches!(proto, Protocol::Tcp)
101 }
102
103 fn usable_for_kx_algorithm(&self, kxa: KeyExchangeAlgorithm) -> bool {
105 self.kx == kxa
106 }
107
108 fn usable_for_signature_scheme(&self, scheme: SignatureScheme) -> bool {
111 self.sign
112 .iter()
113 .any(|s| s.algorithm() == scheme.algorithm())
114 }
115
116 fn common(&self) -> &CipherSuiteCommon {
117 &self.common
118 }
119
120 const VERSION: ProtocolVersion = ProtocolVersion::TLSv1_2;
121}
122
123impl From<&'static Tls12CipherSuite> for SupportedCipherSuite {
124 fn from(s: &'static Tls12CipherSuite) -> Self {
125 Self::Tls12(s)
126 }
127}
128
129impl PartialEq for Tls12CipherSuite {
130 fn eq(&self, other: &Self) -> bool {
131 self.common.suite == other.common.suite
132 }
133}
134
135impl fmt::Debug for Tls12CipherSuite {
136 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
137 f.debug_struct("Tls12CipherSuite")
138 .field("suite", &self.common.suite)
139 .finish()
140 }
141}
142
143pub(crate) struct ConnectionSecrets {
145 pub(crate) randoms: ConnectionRandoms,
146 suite: &'static Tls12CipherSuite,
147 master_secret: Zeroizing<[u8; 48]>,
148
149 master_secret_prf: Box<dyn crypto::tls12::PrfSecret>,
153}
154
155impl ConnectionSecrets {
156 pub(crate) fn from_key_exchange(
157 kx: Box<dyn crypto::ActiveKeyExchange>,
158 peer_pub_key: &[u8],
159 ems_seed: Option<hash::Output>,
160 randoms: ConnectionRandoms,
161 suite: &'static Tls12CipherSuite,
162 ) -> Result<Self, Error> {
163 let (label, seed) = match ems_seed {
164 Some(seed) => ("extended master secret", Seed::Ems(seed)),
165 None => (
166 "master secret",
167 Seed::Randoms(join_randoms(&randoms.client, &randoms.server)),
168 ),
169 };
170
171 let mut master_secret = [0u8; 48];
176 suite.prf_provider.for_key_exchange(
177 &mut master_secret,
178 kx,
179 peer_pub_key,
180 label.as_bytes(),
181 seed.as_ref(),
182 )?;
183 let master_secret = Zeroizing::new(master_secret);
184
185 let master_secret_prf = suite
186 .prf_provider
187 .new_secret(&master_secret);
188
189 Ok(Self {
190 randoms,
191 suite,
192 master_secret,
193 master_secret_prf,
194 })
195 }
196
197 pub(crate) fn new_resume(
198 randoms: ConnectionRandoms,
199 suite: &'static Tls12CipherSuite,
200 master_secret: &[u8; 48],
201 ) -> Self {
202 Self {
203 randoms,
204 suite,
205 master_secret: Zeroizing::new(*master_secret),
206 master_secret_prf: suite
207 .prf_provider
208 .new_secret(master_secret),
209 }
210 }
211
212 pub(crate) fn make_cipher_pair(&self, side: Side) -> MessageCipherPair {
215 let key_block = self.make_key_block();
218 let shape = self.suite.aead_alg.key_block_shape();
219
220 let (client_write_key, key_block) = key_block.split_at(shape.enc_key_len);
221 let (server_write_key, key_block) = key_block.split_at(shape.enc_key_len);
222 let (client_write_iv, key_block) = key_block.split_at(shape.fixed_iv_len);
223 let (server_write_iv, extra) = key_block.split_at(shape.fixed_iv_len);
224
225 let (write_key, write_iv, read_key, read_iv) = match side {
226 Side::Client => (
227 client_write_key,
228 client_write_iv,
229 server_write_key,
230 server_write_iv,
231 ),
232 Side::Server => (
233 server_write_key,
234 server_write_iv,
235 client_write_key,
236 client_write_iv,
237 ),
238 };
239
240 (
241 self.suite
242 .aead_alg
243 .decrypter(AeadKey::new(read_key), read_iv),
244 self.suite
245 .aead_alg
246 .encrypter(AeadKey::new(write_key), write_iv, extra),
247 )
248 }
249
250 fn make_key_block(&self) -> Zeroizing<Vec<u8>> {
251 let shape = self.suite.aead_alg.key_block_shape();
252
253 let len = (shape.enc_key_len + shape.fixed_iv_len) * 2 + shape.explicit_nonce_len;
254
255 let mut out = vec![0u8; len];
256
257 let randoms = join_randoms(&self.randoms.server, &self.randoms.client);
260 self.master_secret_prf
261 .prf(&mut out, b"key expansion", &randoms);
262
263 Zeroizing::new(out)
264 }
265
266 pub(crate) fn suite(&self) -> &'static Tls12CipherSuite {
267 self.suite
268 }
269
270 pub(crate) fn master_secret(&self) -> &[u8; 48] {
271 &self.master_secret
272 }
273
274 fn make_verify_data(&self, handshake_hash: &hash::Output, label: &[u8]) -> [u8; 12] {
275 let mut out = [0u8; 12];
276 self.master_secret_prf
277 .prf(&mut out, label, handshake_hash.as_ref());
278 out
279 }
280
281 pub(crate) fn client_verify_data(&self, handshake_hash: &hash::Output) -> [u8; 12] {
282 self.make_verify_data(handshake_hash, b"client finished")
283 }
284
285 pub(crate) fn server_verify_data(&self, handshake_hash: &hash::Output) -> [u8; 12] {
286 self.make_verify_data(handshake_hash, b"server finished")
287 }
288
289 pub(crate) fn into_exporter(self) -> Box<dyn Exporter> {
290 let Self {
291 randoms,
292 master_secret_prf,
293 master_secret: _,
294 suite: _,
295 } = self;
296 Box::new(Tls12Exporter {
297 randoms,
298 master_secret_prf,
299 })
300 }
301
302 pub(crate) fn extract_secrets(&self, side: Side) -> Result<PartiallyExtractedSecrets, Error> {
303 let key_block = self.make_key_block();
305 let shape = self.suite.aead_alg.key_block_shape();
306
307 let (client_key, key_block) = key_block.split_at(shape.enc_key_len);
308 let (server_key, key_block) = key_block.split_at(shape.enc_key_len);
309 let (client_iv, key_block) = key_block.split_at(shape.fixed_iv_len);
310 let (server_iv, explicit_nonce) = key_block.split_at(shape.fixed_iv_len);
311
312 let client_secrets = self.suite.aead_alg.extract_keys(
313 AeadKey::new(client_key),
314 client_iv,
315 explicit_nonce,
316 )?;
317 let server_secrets = self.suite.aead_alg.extract_keys(
318 AeadKey::new(server_key),
319 server_iv,
320 explicit_nonce,
321 )?;
322
323 let (tx, rx) = match side {
324 Side::Client => (client_secrets, server_secrets),
325 Side::Server => (server_secrets, client_secrets),
326 };
327 Ok(PartiallyExtractedSecrets { tx, rx })
328 }
329}
330
331pub(crate) struct Tls12Exporter {
332 randoms: ConnectionRandoms,
333 master_secret_prf: Box<dyn crypto::tls12::PrfSecret>,
334}
335
336impl Exporter for Tls12Exporter {
337 fn derive(&self, label: &[u8], context: Option<&[u8]>, output: &mut [u8]) -> Result<(), Error> {
338 let mut randoms = Vec::with_capacity(
339 32 + 32
340 + context
341 .as_ref()
342 .map(|c| 2 + c.len())
343 .unwrap_or_default(),
344 );
345 randoms.extend_from_slice(&self.randoms.client);
346 randoms.extend_from_slice(&self.randoms.server);
347 if let Some(context) = context {
348 match u16::try_from(context.len()) {
349 Ok(len) => len.encode(&mut randoms),
350 Err(_) => return Err(ApiMisuse::ExporterContextTooLong.into()),
351 }
352 randoms.extend_from_slice(context);
353 }
354
355 self.master_secret_prf
356 .prf(output, label, &randoms);
357 Ok(())
358 }
359}
360
361enum Seed {
362 Ems(hash::Output),
363 Randoms([u8; 64]),
364}
365
366impl AsRef<[u8]> for Seed {
367 fn as_ref(&self) -> &[u8] {
369 match self {
370 Self::Ems(seed) => seed.as_ref(),
372 Self::Randoms(randoms) => randoms.as_ref(),
374 }
375 }
376}
377
378fn join_randoms(first: &[u8; 32], second: &[u8; 32]) -> [u8; 64] {
379 let mut randoms = [0u8; 64];
380 randoms[..32].copy_from_slice(first);
381 randoms[32..].copy_from_slice(second);
382 randoms
383}
384
385type MessageCipherPair = (Box<dyn MessageDecrypter>, Box<dyn MessageEncrypter>);
386
387pub(crate) fn decode_kx_params<'a, T: KxDecode<'a>>(
388 kx_algorithm: KeyExchangeAlgorithm,
389 common: &mut CommonState,
390 kx_params: &'a [u8],
391) -> Result<T, Error> {
392 let mut rd = Reader::init(kx_params);
393 let kx_params = T::decode(&mut rd, kx_algorithm)?;
394 match rd.any_left() {
395 false => Ok(kx_params),
396 true => Err(common.send_fatal_alert(
397 AlertDescription::DecodeError,
398 InvalidMessage::InvalidDhParams,
399 )),
400 }
401}
402
403pub(crate) const DOWNGRADE_SENTINEL: [u8; 8] = [0x44, 0x4f, 0x57, 0x4e, 0x47, 0x52, 0x44, 0x01];
404
405#[cfg(test)]
406#[macro_rules_attribute::apply(test_for_each_provider)]
407mod tests {
408 use super::provider::kx_group::X25519;
409 use super::*;
410 use crate::common_state::{CommonState, Side};
411 use crate::msgs::handshake::{ServerEcdhParams, ServerKeyExchangeParams};
412
413 #[test]
414 fn server_ecdhe_remaining_bytes() {
415 let key = X25519.start().unwrap();
416 let server_params = ServerEcdhParams::new(&*key);
417 let mut server_buf = Vec::new();
418 server_params.encode(&mut server_buf);
419 server_buf.push(34);
420
421 let mut common = CommonState::new(Side::Client);
422 assert!(
423 decode_kx_params::<ServerKeyExchangeParams>(
424 KeyExchangeAlgorithm::ECDHE,
425 &mut common,
426 &server_buf
427 )
428 .is_err()
429 );
430 }
431
432 #[test]
433 fn client_ecdhe_invalid() {
434 let mut common = CommonState::new(Side::Server);
435 assert!(
436 decode_kx_params::<ServerKeyExchangeParams>(
437 KeyExchangeAlgorithm::ECDHE,
438 &mut common,
439 &[34],
440 )
441 .is_err()
442 );
443 }
444}