1use core::fmt;
2
3use crate::common_state::Protocol;
4use crate::crypto::{self, hash};
5use crate::enums::{ProtocolVersion, SignatureScheme};
6use crate::suites::{CipherSuiteCommon, Suite, SupportedCipherSuite};
7use crate::version::Tls13Version;
8
9pub(crate) mod key_schedule;
10
11#[expect(clippy::exhaustive_structs)]
13pub struct Tls13CipherSuite {
14 pub common: CipherSuiteCommon,
16
17 pub protocol_version: &'static Tls13Version,
28
29 pub hkdf_provider: &'static dyn crypto::tls13::Hkdf,
37
38 pub aead_alg: &'static dyn crypto::cipher::Tls13AeadAlgorithm,
44
45 pub quic: Option<&'static dyn crate::quic::Algorithm>,
51}
52
53impl Tls13CipherSuite {
54 pub fn can_resume_from(&self, prev: &'static Self) -> Option<&'static Self> {
56 (prev.common.hash_provider.algorithm() == self.common.hash_provider.algorithm())
57 .then_some(prev)
58 }
59
60 pub fn fips(&self) -> bool {
64 let Self {
65 common,
66 protocol_version: _,
67 hkdf_provider,
68 aead_alg,
69 quic,
70 } = self;
71 common.fips()
72 && hkdf_provider.fips()
73 && aead_alg.fips()
74 && quic.map(|q| q.fips()).unwrap_or(true)
75 }
76
77 pub fn quic_suite(&'static self) -> Option<crate::quic::Suite> {
79 self.quic
80 .map(|quic| crate::quic::Suite { quic, suite: self })
81 }
82}
83
84impl Suite for Tls13CipherSuite {
85 fn client_handler(&self) -> &'static dyn crate::client::ClientHandler<Self> {
86 self.protocol_version.client
87 }
88
89 fn server_handler(&self) -> &'static dyn crate::server::ServerHandler<Self> {
90 self.protocol_version.server
91 }
92
93 fn usable_for_protocol(&self, proto: Protocol) -> bool {
97 match proto {
98 Protocol::Tcp => true,
99 Protocol::Quic => self.quic.is_some(),
100 }
101 }
102
103 fn usable_for_signature_scheme(&self, scheme: SignatureScheme) -> bool {
104 scheme.supported_in_tls13()
105 }
106
107 fn common(&self) -> &CipherSuiteCommon {
108 &self.common
109 }
110
111 const VERSION: ProtocolVersion = ProtocolVersion::TLSv1_3;
112}
113
114impl From<&'static Tls13CipherSuite> for SupportedCipherSuite {
115 fn from(s: &'static Tls13CipherSuite) -> Self {
116 Self::Tls13(s)
117 }
118}
119
120impl PartialEq for Tls13CipherSuite {
121 fn eq(&self, other: &Self) -> bool {
122 self.common.suite == other.common.suite
123 }
124}
125
126impl fmt::Debug for Tls13CipherSuite {
127 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
128 f.debug_struct("Tls13CipherSuite")
129 .field("suite", &self.common.suite)
130 .finish()
131 }
132}
133
134pub(crate) fn construct_client_verify_message(handshake_hash: &hash::Output) -> VerifyMessage {
136 VerifyMessage::new(handshake_hash, CLIENT_CONSTANT)
137}
138
139pub(crate) fn construct_server_verify_message(handshake_hash: &hash::Output) -> VerifyMessage {
141 VerifyMessage::new(handshake_hash, SERVER_CONSTANT)
142}
143
144pub(crate) struct VerifyMessage {
145 buf: [u8; MAX_VERIFY_MSG],
146 used: usize,
147}
148
149impl VerifyMessage {
150 fn new(handshake_hash: &hash::Output, context_string_with_0: &[u8; 34]) -> Self {
151 let used = 64 + context_string_with_0.len() + handshake_hash.as_ref().len();
152 let mut buf = [0x20u8; MAX_VERIFY_MSG];
153
154 let (_spaces, context) = buf.split_at_mut(64);
155 let (context, hash) = context.split_at_mut(34);
156 context.copy_from_slice(context_string_with_0);
157 hash[..handshake_hash.as_ref().len()].copy_from_slice(handshake_hash.as_ref());
158
159 Self { buf, used }
160 }
161}
162
163impl AsRef<[u8]> for VerifyMessage {
164 fn as_ref(&self) -> &[u8] {
165 &self.buf[..self.used]
166 }
167}
168
169const SERVER_CONSTANT: &[u8; 34] = b"TLS 1.3, server CertificateVerify\x00";
170const CLIENT_CONSTANT: &[u8; 34] = b"TLS 1.3, client CertificateVerify\x00";
171const MAX_VERIFY_MSG: usize = 64 + CLIENT_CONSTANT.len() + hash::Output::MAX_LEN;