Skip to main content

rustls/
suites.rs

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