rustls/suites.rs
1use alloc::vec::Vec;
2use core::fmt;
3
4use pki_types::FipsStatus;
5
6use crate::common_state::Protocol;
7use crate::crypto::cipher::{AeadKey, Iv};
8use crate::crypto::kx::KeyExchangeAlgorithm;
9use crate::crypto::{CipherSuite, SignatureScheme, hash};
10use crate::enums::ProtocolVersion;
11use crate::tls12::Tls12CipherSuite;
12use crate::tls13::Tls13CipherSuite;
13
14/// Common state for cipher suites (both for TLS 1.2 and TLS 1.3)
15#[expect(clippy::exhaustive_structs)]
16pub struct CipherSuiteCommon {
17 /// The TLS enumeration naming this cipher suite.
18 pub suite: CipherSuite,
19
20 /// Which hash function the suite uses.
21 pub hash_provider: &'static dyn hash::Hash,
22
23 /// Number of TCP-TLS records that can be safely encrypted with a single key of this type
24 ///
25 /// Once a `RecordEncrypter` produced for this suite has encrypted more than
26 /// `confidentiality_limit` records, an attacker gains an advantage in distinguishing it
27 /// from an ideal pseudorandom permutation (PRP).
28 ///
29 /// This is to be set on the assumption that record payloads are maximally sized --
30 /// each is 2<sup>14</sup> bytes. It **does not** consider confidentiality limits for
31 /// QUIC connections - see the [`quic::PacketKey::confidentiality_limit`] field for
32 /// this context.
33 ///
34 /// For AES-GCM implementations, this should be set to 2<sup>24</sup> to limit attack
35 /// probability to one in 2<sup>60</sup>. See [AEBounds] (Table 1) and [draft-irtf-aead-limits-08]:
36 ///
37 /// ```python
38 /// >>> p = 2 ** -60
39 /// >>> L = (2 ** 14 // 16) + 1
40 /// >>> qlim = (math.sqrt(p) * (2 ** (129 // 2)) - 1) / (L + 1)
41 /// >>> print(int(qlim).bit_length())
42 /// 24
43 /// ```
44 /// [AEBounds]: https://eprint.iacr.org/2024/051.pdf
45 /// [draft-irtf-aead-limits-08]: https://www.ietf.org/archive/id/draft-irtf-cfrg-aead-limits-08.html#section-5.1.1
46 /// [`quic::PacketKey::confidentiality_limit`]: crate::quic::PacketKey::confidentiality_limit
47 ///
48 /// For chacha20-poly1305 implementations, this should be set to `u64::MAX`:
49 /// see <https://www.ietf.org/archive/id/draft-irtf-cfrg-aead-limits-08.html#section-5.2.1>
50 pub confidentiality_limit: u64,
51}
52
53impl CipherSuiteCommon {
54 /// Return the FIPS validation status of this implementation.
55 ///
56 /// This is the combination of the constituent parts of the cipher suite.
57 pub fn fips(&self) -> FipsStatus {
58 self.hash_provider.fips()
59 }
60}
61
62/// A cipher suite supported by rustls.
63///
64/// This type carries both configuration and implementation. Compare with
65/// [`CipherSuite`], which carries solely a cipher suite identifier.
66#[non_exhaustive]
67#[derive(Clone, Copy, PartialEq)]
68pub enum SupportedCipherSuite {
69 /// A TLS 1.2 cipher suite
70 Tls12(&'static Tls12CipherSuite),
71 /// A TLS 1.3 cipher suite
72 Tls13(&'static Tls13CipherSuite),
73}
74
75impl SupportedCipherSuite {
76 /// The cipher suite's identifier
77 pub fn suite(&self) -> CipherSuite {
78 self.common().suite
79 }
80
81 /// The hash function the ciphersuite uses.
82 pub(crate) fn hash_provider(&self) -> &'static dyn hash::Hash {
83 self.common().hash_provider
84 }
85
86 pub(crate) fn common(&self) -> &CipherSuiteCommon {
87 match self {
88 Self::Tls12(inner) => &inner.common,
89 Self::Tls13(inner) => &inner.common,
90 }
91 }
92
93 /// Return true if this suite is usable for the given [`Protocol`].
94 pub(crate) fn usable_for_protocol(&self, proto: Protocol) -> bool {
95 match self {
96 Self::Tls12(tls12) => tls12.usable_for_protocol(proto),
97 Self::Tls13(tls13) => tls13.usable_for_protocol(proto),
98 }
99 }
100}
101
102impl fmt::Debug for SupportedCipherSuite {
103 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
104 self.suite().fmt(f)
105 }
106}
107
108pub(crate) trait Suite: fmt::Debug {
109 fn client_handler(&self) -> &'static dyn crate::client::ClientHandler<Self>;
110
111 fn server_handler(&self) -> &'static dyn crate::server::ServerHandler<Self>;
112
113 fn usable_for_protocol(&self, proto: Protocol) -> bool;
114
115 fn filter_signature_schemes(
116 schemes: &mut Vec<SignatureScheme>,
117 client: &[CipherSuite],
118 server: &[&'static Self],
119 );
120
121 fn usable_for_signature_scheme(&self, _scheme: SignatureScheme) -> bool;
122
123 fn usable_for_kx_algorithm(&self, _kxa: KeyExchangeAlgorithm) -> bool {
124 true
125 }
126
127 fn suite(&self) -> CipherSuite {
128 self.common().suite
129 }
130
131 fn common(&self) -> &CipherSuiteCommon;
132
133 const VERSION: ProtocolVersion;
134}
135
136/// Secrets for transmitting/receiving data over a TLS session.
137///
138/// After performing a handshake with rustls, these secrets can be extracted
139/// to configure kTLS for a socket, and have the kernel take over encryption
140/// and/or decryption.
141#[expect(clippy::exhaustive_structs)]
142pub struct ExtractedSecrets {
143 /// sequence number and secrets for the "tx" (transmit) direction
144 pub tx: (u64, ConnectionTrafficSecrets),
145
146 /// sequence number and secrets for the "rx" (receive) direction
147 pub rx: (u64, ConnectionTrafficSecrets),
148}
149
150/// [ExtractedSecrets] minus the sequence numbers
151pub(crate) struct PartiallyExtractedSecrets {
152 /// secrets for the "tx" (transmit) direction
153 pub(crate) tx: ConnectionTrafficSecrets,
154
155 /// secrets for the "rx" (receive) direction
156 pub(crate) rx: ConnectionTrafficSecrets,
157}
158
159/// Secrets used to encrypt/decrypt data in a TLS session.
160///
161/// These can be used to configure kTLS for a socket in one direction.
162/// The only other piece of information needed is the sequence number,
163/// which is in [ExtractedSecrets].
164#[non_exhaustive]
165pub enum ConnectionTrafficSecrets {
166 /// Secrets for the AES_128_GCM AEAD algorithm
167 Aes128Gcm {
168 /// AEAD Key
169 key: AeadKey,
170 /// Initialization vector
171 iv: Iv,
172 },
173
174 /// Secrets for the AES_256_GCM AEAD algorithm
175 Aes256Gcm {
176 /// AEAD Key
177 key: AeadKey,
178 /// Initialization vector
179 iv: Iv,
180 },
181
182 /// Secrets for the CHACHA20_POLY1305 AEAD algorithm
183 Chacha20Poly1305 {
184 /// AEAD Key
185 key: AeadKey,
186 /// Initialization vector
187 iv: Iv,
188 },
189
190 /// Secrets for the SM4_GCM AEAD algorithm
191 Sm4Gcm {
192 /// AEAD Key
193 key: AeadKey,
194 /// Initialization vector
195 iv: Iv,
196 },
197
198 /// Secrets for the SM4_CCM AEAD algorithm
199 Sm4Ccm {
200 /// AEAD Key
201 key: AeadKey,
202 /// Initialization vector
203 iv: Iv,
204 },
205}
206
207#[cfg(test)]
208mod tests {
209 use std::println;
210
211 use super::SupportedCipherSuite;
212 use crate::crypto::TEST_PROVIDER;
213
214 #[test]
215 fn test_scs_is_debug() {
216 println!(
217 "{:?}",
218 SupportedCipherSuite::Tls13(
219 TEST_PROVIDER
220 .tls13_cipher_suites
221 .first()
222 .unwrap()
223 )
224 );
225 }
226}