Skip to main content

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}