1use alloc::boxed::Box;
2use alloc::vec;
3use alloc::vec::Vec;
4use core::fmt;
5
6use pki_types::FipsStatus;
7use zeroize::Zeroizing;
8
9use crate::common_state::{Protocol, Side};
10use crate::conn::{ConnectionRandoms, Exporter};
11use crate::crypto::cipher::{AeadKey, RecordDecrypter, RecordEncrypter, Tls12AeadAlgorithm};
12use crate::crypto::kx::{ActiveKeyExchange, KeyExchangeAlgorithm};
13use crate::crypto::tls12::PrfSecret;
14use crate::crypto::{self, CipherSuite, SignatureAlgorithm, SignatureScheme, hash};
15use crate::enums::ProtocolVersion;
16use crate::error::{ApiMisuse, Error, InvalidMessage};
17use crate::msgs::{Codec, HandshakeAlignedProof, KxDecode, Reader};
18use crate::suites::{CipherSuiteCommon, PartiallyExtractedSecrets, Suite, SupportedCipherSuite};
19use crate::version::Tls12Version;
20
21#[expect(clippy::exhaustive_structs)]
23pub struct Tls12CipherSuite {
24 pub common: CipherSuiteCommon,
26
27 pub protocol_version: &'static Tls12Version,
38
39 pub prf_provider: &'static dyn crypto::tls12::Prf,
46
47 pub kx: KeyExchangeAlgorithm,
55
56 pub sign: &'static [SignatureScheme],
63
64 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 .copied()
77 .collect()
78 }
79
80 pub fn fips(&self) -> FipsStatus {
84 let status = Ord::min(self.common.fips(), self.prf_provider.fips());
85 Ord::min(status, self.aead_alg.fips())
86 }
87}
88
89impl Suite for Tls12CipherSuite {
90 fn client_handler(&self) -> &'static dyn crate::client::ClientHandler<Self> {
91 self.protocol_version.client
92 }
93
94 fn server_handler(&self) -> &'static dyn crate::server::ServerHandler<Self> {
95 self.protocol_version.server
96 }
97
98 fn usable_for_protocol(&self, proto: Protocol) -> bool {
102 matches!(proto, Protocol::Tcp)
103 }
104
105 fn usable_for_kx_algorithm(&self, kxa: KeyExchangeAlgorithm) -> bool {
107 self.kx == kxa
108 }
109
110 fn filter_signature_schemes(
111 schemes: &mut Vec<SignatureScheme>,
112 client: &[CipherSuite],
113 server: &[&'static Self],
114 ) {
115 let mut algorithms = SignatureAlgorithmSet::default();
116 for &suite in server {
117 if !client.contains(&suite.suite()) {
118 continue;
119 }
120
121 for &scheme in suite.sign {
122 let Some(alg) = scheme.algorithm() else {
123 continue;
124 };
125
126 algorithms.insert(alg);
127 }
128 }
129
130 schemes.retain(|scheme| {
131 scheme
132 .algorithm()
133 .is_some_and(|alg| algorithms.contains(alg))
134 });
135 }
136
137 fn usable_for_signature_scheme(&self, scheme: SignatureScheme) -> bool {
139 let Some(alg) = scheme.algorithm() else {
140 return false;
141 };
142
143 self.sign
144 .iter()
145 .any(|s| s.algorithm() == Some(alg))
146 }
147
148 fn common(&self) -> &CipherSuiteCommon {
149 &self.common
150 }
151
152 const VERSION: ProtocolVersion = ProtocolVersion::TLSv1_2;
153}
154
155impl From<&'static Tls12CipherSuite> for SupportedCipherSuite {
156 fn from(s: &'static Tls12CipherSuite) -> Self {
157 Self::Tls12(s)
158 }
159}
160
161impl PartialEq for Tls12CipherSuite {
162 fn eq(&self, other: &Self) -> bool {
163 self.common.suite == other.common.suite
164 }
165}
166
167impl fmt::Debug for Tls12CipherSuite {
168 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
169 f.debug_struct("Tls12CipherSuite")
170 .field("suite", &self.common.suite)
171 .finish_non_exhaustive()
172 }
173}
174
175pub(crate) struct ConnectionSecrets {
177 pub(crate) randoms: ConnectionRandoms,
178 suite: &'static Tls12CipherSuite,
179 master_secret: Zeroizing<[u8; 48]>,
180
181 master_secret_prf: Box<dyn PrfSecret>,
185}
186
187impl ConnectionSecrets {
188 pub(crate) fn from_key_exchange(
189 kx: Box<dyn ActiveKeyExchange>,
190 peer_pub_key: &[u8],
191 ems_seed: Option<hash::Output>,
192 randoms: ConnectionRandoms,
193 suite: &'static Tls12CipherSuite,
194 ) -> Result<Self, Error> {
195 let (label, seed) = match ems_seed {
196 Some(seed) => ("extended master secret", Seed::Ems(seed)),
197 None => (
198 "master secret",
199 Seed::Randoms(join_randoms(&randoms.client, &randoms.server)),
200 ),
201 };
202
203 let mut master_secret = [0u8; 48];
208 suite.prf_provider.for_key_exchange(
209 &mut master_secret,
210 kx,
211 peer_pub_key,
212 label.as_bytes(),
213 seed.as_ref(),
214 )?;
215 let master_secret = Zeroizing::new(master_secret);
216
217 let master_secret_prf = suite
218 .prf_provider
219 .new_secret(&master_secret);
220
221 Ok(Self {
222 randoms,
223 suite,
224 master_secret,
225 master_secret_prf,
226 })
227 }
228
229 pub(crate) fn new_resume(
230 randoms: ConnectionRandoms,
231 suite: &'static Tls12CipherSuite,
232 master_secret: &[u8; 48],
233 ) -> Self {
234 Self {
235 randoms,
236 suite,
237 master_secret: Zeroizing::new(*master_secret),
238 master_secret_prf: suite
239 .prf_provider
240 .new_secret(master_secret),
241 }
242 }
243
244 pub(crate) fn make_cipher_pair(&self, side: Side) -> RecordCipherPair {
247 let key_block = self.make_key_block();
250 let shape = self.suite.aead_alg.key_block_shape();
251
252 let (client_write_key, key_block) = key_block.split_at(shape.enc_key_len);
253 let (server_write_key, key_block) = key_block.split_at(shape.enc_key_len);
254 let (client_write_iv, key_block) = key_block.split_at(shape.fixed_iv_len);
255 let (server_write_iv, extra) = key_block.split_at(shape.fixed_iv_len);
256
257 let (write_key, write_iv, read_key, read_iv) = match side {
258 Side::Client => (
259 client_write_key,
260 client_write_iv,
261 server_write_key,
262 server_write_iv,
263 ),
264 Side::Server => (
265 server_write_key,
266 server_write_iv,
267 client_write_key,
268 client_write_iv,
269 ),
270 };
271
272 (
273 self.suite
274 .aead_alg
275 .decrypter(AeadKey::new(read_key), read_iv),
276 self.suite
277 .aead_alg
278 .encrypter(AeadKey::new(write_key), write_iv, extra),
279 )
280 }
281
282 fn make_key_block(&self) -> Zeroizing<Vec<u8>> {
283 let shape = self.suite.aead_alg.key_block_shape();
284
285 let len = (shape.enc_key_len + shape.fixed_iv_len) * 2 + shape.explicit_nonce_len;
286
287 let mut out = vec![0u8; len];
288
289 let randoms = join_randoms(&self.randoms.server, &self.randoms.client);
292 self.master_secret_prf
293 .prf(&mut out, b"key expansion", &randoms);
294
295 Zeroizing::new(out)
296 }
297
298 pub(crate) fn suite(&self) -> &'static Tls12CipherSuite {
299 self.suite
300 }
301
302 pub(crate) fn master_secret(&self) -> &[u8; 48] {
303 &self.master_secret
304 }
305
306 fn make_verify_data(
307 &self,
308 handshake_hash: &hash::Output,
309 label: &[u8],
310 _proof: &HandshakeAlignedProof,
311 ) -> [u8; 12] {
312 let mut out = [0u8; 12];
313 self.master_secret_prf
314 .prf(&mut out, label, handshake_hash.as_ref());
315 out
316 }
317
318 pub(crate) fn client_verify_data(
319 &self,
320 handshake_hash: &hash::Output,
321 proof: &HandshakeAlignedProof,
322 ) -> [u8; 12] {
323 self.make_verify_data(handshake_hash, b"client finished", proof)
324 }
325
326 pub(crate) fn server_verify_data(
327 &self,
328 handshake_hash: &hash::Output,
329 proof: &HandshakeAlignedProof,
330 ) -> [u8; 12] {
331 self.make_verify_data(handshake_hash, b"server finished", proof)
332 }
333
334 pub(crate) fn into_exporter(self) -> Box<dyn Exporter> {
335 let Self {
336 randoms,
337 master_secret_prf,
338 master_secret: _,
339 suite: _,
340 } = self;
341 Box::new(Tls12Exporter {
342 randoms,
343 master_secret_prf,
344 })
345 }
346
347 pub(crate) fn extract_secrets(&self, side: Side) -> Result<PartiallyExtractedSecrets, Error> {
348 let key_block = self.make_key_block();
350 let shape = self.suite.aead_alg.key_block_shape();
351
352 let (client_key, key_block) = key_block.split_at(shape.enc_key_len);
353 let (server_key, key_block) = key_block.split_at(shape.enc_key_len);
354 let (client_iv, key_block) = key_block.split_at(shape.fixed_iv_len);
355 let (server_iv, explicit_nonce) = key_block.split_at(shape.fixed_iv_len);
356
357 let client_secrets = self.suite.aead_alg.extract_keys(
358 AeadKey::new(client_key),
359 client_iv,
360 explicit_nonce,
361 )?;
362 let server_secrets = self.suite.aead_alg.extract_keys(
363 AeadKey::new(server_key),
364 server_iv,
365 explicit_nonce,
366 )?;
367
368 let (tx, rx) = match side {
369 Side::Client => (client_secrets, server_secrets),
370 Side::Server => (server_secrets, client_secrets),
371 };
372 Ok(PartiallyExtractedSecrets { tx, rx })
373 }
374}
375
376pub(crate) struct Tls12Exporter {
377 randoms: ConnectionRandoms,
378 master_secret_prf: Box<dyn PrfSecret>,
379}
380
381impl Exporter for Tls12Exporter {
382 fn derive(&self, label: &[u8], context: Option<&[u8]>, output: &mut [u8]) -> Result<(), Error> {
383 let mut randoms = Vec::with_capacity(
384 32 + 32
385 + context
386 .as_ref()
387 .map(|c| 2 + c.len())
388 .unwrap_or_default(),
389 );
390 randoms.extend_from_slice(&self.randoms.client);
391 randoms.extend_from_slice(&self.randoms.server);
392 if let Some(context) = context {
393 let Ok(len) = u16::try_from(context.len()) else {
394 return Err(ApiMisuse::ExporterContextTooLong.into());
395 };
396 len.encode(&mut randoms);
397 randoms.extend_from_slice(context);
398 }
399
400 self.master_secret_prf
401 .prf(output, label, &randoms);
402 Ok(())
403 }
404}
405
406enum Seed {
407 Ems(hash::Output),
408 Randoms([u8; 64]),
409}
410
411impl AsRef<[u8]> for Seed {
412 fn as_ref(&self) -> &[u8] {
414 match self {
415 Self::Ems(seed) => seed.as_ref(),
417 Self::Randoms(randoms) => randoms.as_ref(),
419 }
420 }
421}
422
423fn join_randoms(first: &[u8; 32], second: &[u8; 32]) -> [u8; 64] {
424 let mut randoms = [0u8; 64];
425 randoms[..32].copy_from_slice(first);
426 randoms[32..].copy_from_slice(second);
427 randoms
428}
429
430type RecordCipherPair = (Box<dyn RecordDecrypter>, Box<dyn RecordEncrypter>);
431
432#[derive(Clone, Copy, Default)]
438struct SignatureAlgorithmSet(u16);
439
440impl SignatureAlgorithmSet {
441 fn insert(&mut self, alg: SignatureAlgorithm) {
442 self.0 |= Self::bit(alg);
443 }
444
445 fn contains(&self, alg: SignatureAlgorithm) -> bool {
446 self.0 & Self::bit(alg) != 0
447 }
448
449 fn bit(alg: SignatureAlgorithm) -> u16 {
450 1 << (u8::from(alg) & 0xf)
451 }
452}
453
454pub(crate) fn decode_kx_params<'a, T: KxDecode<'a>>(
455 kx_algorithm: KeyExchangeAlgorithm,
456 kx_params: &'a [u8],
457) -> Result<T, Error> {
458 let mut rd = Reader::new(kx_params);
459 let kx_params = T::decode(&mut rd, kx_algorithm)?;
460 match rd.any_left() {
461 false => Ok(kx_params),
462 true => Err(InvalidMessage::InvalidDhParams.into()),
463 }
464}
465
466pub(crate) const DOWNGRADE_SENTINEL: [u8; 8] = [0x44, 0x4f, 0x57, 0x4e, 0x47, 0x52, 0x44, 0x01];
467
468#[cfg(test)]
469mod tests {
470 use super::*;
471 use crate::crypto::test_provider::KEY_EXCHANGE_GROUP;
472 use crate::msgs::{ServerEcdhParams, ServerKeyExchangeParams};
473
474 #[test]
475 fn server_ecdhe_remaining_bytes() {
476 let key = KEY_EXCHANGE_GROUP.start().unwrap();
477 let server_params = ServerEcdhParams::new(&*key);
478 let mut server_buf = Vec::new();
479 server_params.encode(&mut server_buf);
480 server_buf.push(34);
481
482 assert!(
483 decode_kx_params::<ServerKeyExchangeParams>(KeyExchangeAlgorithm::ECDHE, &server_buf)
484 .is_err()
485 );
486 }
487
488 #[test]
489 fn client_ecdhe_invalid() {
490 assert!(
491 decode_kx_params::<ServerKeyExchangeParams>(KeyExchangeAlgorithm::ECDHE, &[34],)
492 .is_err()
493 );
494 }
495}