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}