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