rustls/
suites.rs

1use core::fmt;
2
3use crate::common_state::Protocol;
4use crate::crypto::cipher::{AeadKey, Iv};
5use crate::crypto::{self, KeyExchangeAlgorithm};
6use crate::enums::{CipherSuite, SignatureAlgorithm, SignatureScheme};
7use crate::msgs::handshake::ALL_KEY_EXCHANGE_ALGORITHMS;
8use crate::tls12::Tls12CipherSuite;
9use crate::tls13::Tls13CipherSuite;
10use crate::versions::SupportedProtocolVersion;
11
12/// Common state for cipher suites (both for TLS 1.2 and TLS 1.3)
13#[allow(clippy::exhaustive_structs)]
14pub struct CipherSuiteCommon {
15    /// The TLS enumeration naming this cipher suite.
16    pub suite: CipherSuite,
17
18    /// Which hash function the suite uses.
19    pub hash_provider: &'static dyn crypto::hash::Hash,
20
21    /// Number of TCP-TLS messages that can be safely encrypted with a single key of this type
22    ///
23    /// Once a `MessageEncrypter` produced for this suite has encrypted more than
24    /// `confidentiality_limit` messages, an attacker gains an advantage in distinguishing it
25    /// from an ideal pseudorandom permutation (PRP).
26    ///
27    /// This is to be set on the assumption that messages are maximally sized --
28    /// each is 2<sup>14</sup> bytes. It **does not** consider confidentiality limits for
29    /// QUIC connections - see the [`quic::PacketKey::confidentiality_limit`] field for
30    /// this context.
31    ///
32    /// For AES-GCM implementations, this should be set to 2<sup>24</sup> to limit attack
33    /// probability to one in 2<sup>60</sup>.  See [AEBounds] (Table 1) and [draft-irtf-aead-limits-08]:
34    ///
35    /// ```python
36    /// >>> p = 2 ** -60
37    /// >>> L = (2 ** 14 // 16) + 1
38    /// >>> qlim = (math.sqrt(p) * (2 ** (129 // 2)) - 1) / (L + 1)
39    /// >>> print(int(qlim).bit_length())
40    /// 24
41    /// ```
42    /// [AEBounds]: https://eprint.iacr.org/2024/051.pdf
43    /// [draft-irtf-aead-limits-08]: https://www.ietf.org/archive/id/draft-irtf-cfrg-aead-limits-08.html#section-5.1.1
44    /// [`quic::PacketKey::confidentiality_limit`]: crate::quic::PacketKey::confidentiality_limit
45    ///
46    /// For chacha20-poly1305 implementations, this should be set to `u64::MAX`:
47    /// see <https://www.ietf.org/archive/id/draft-irtf-cfrg-aead-limits-08.html#section-5.2.1>
48    pub confidentiality_limit: u64,
49}
50
51impl CipherSuiteCommon {
52    /// Return `true` if this is backed by a FIPS-approved implementation.
53    ///
54    /// This means all the constituent parts that do cryptography return `true` for `fips()`.
55    pub fn fips(&self) -> bool {
56        self.hash_provider.fips()
57    }
58}
59
60/// A cipher suite supported by rustls.
61///
62/// This type carries both configuration and implementation. Compare with
63/// [`CipherSuite`], which carries solely a cipher suite identifier.
64#[non_exhaustive]
65#[derive(Clone, Copy, PartialEq)]
66pub enum SupportedCipherSuite {
67    /// A TLS 1.2 cipher suite
68    Tls12(&'static Tls12CipherSuite),
69    /// A TLS 1.3 cipher suite
70    Tls13(&'static Tls13CipherSuite),
71}
72
73impl SupportedCipherSuite {
74    /// The cipher suite's identifier
75    pub fn suite(&self) -> CipherSuite {
76        self.common().suite
77    }
78
79    /// The hash function the ciphersuite uses.
80    pub(crate) fn hash_provider(&self) -> &'static dyn crypto::hash::Hash {
81        self.common().hash_provider
82    }
83
84    pub(crate) fn common(&self) -> &CipherSuiteCommon {
85        match self {
86            Self::Tls12(inner) => &inner.common,
87            Self::Tls13(inner) => &inner.common,
88        }
89    }
90
91    /// Return the inner `Tls13CipherSuite` for this suite, if it is a TLS1.3 suite.
92    pub fn tls13(&self) -> Option<&'static Tls13CipherSuite> {
93        match self {
94            Self::Tls12(_) => None,
95            Self::Tls13(inner) => Some(inner),
96        }
97    }
98
99    /// Return supported protocol version for the cipher suite.
100    pub fn version(&self) -> SupportedProtocolVersion {
101        match self {
102            Self::Tls12(suite) => SupportedProtocolVersion::TLS12(suite.protocol_version),
103            Self::Tls13(suite) => SupportedProtocolVersion::TLS13(suite.protocol_version),
104        }
105    }
106
107    /// Return true if this suite is usable for a key only offering `sig_alg`
108    /// signatures.  This resolves to true for all TLS1.3 suites.
109    pub fn usable_for_signature_algorithm(&self, _sig_alg: SignatureAlgorithm) -> bool {
110        match self {
111            Self::Tls13(_) => true, // no constraint expressed by ciphersuite (e.g., TLS1.3)
112            Self::Tls12(inner) => inner
113                .sign
114                .iter()
115                .any(|scheme| scheme.algorithm() == _sig_alg),
116        }
117    }
118
119    /// Return true if this suite is usable for the given [`Protocol`].
120    ///
121    /// All cipher suites are usable for TCP-TLS.  Only TLS1.3 suites
122    /// with `Tls13CipherSuite::quic` provided are usable for QUIC.
123    pub(crate) fn usable_for_protocol(&self, proto: Protocol) -> bool {
124        match proto {
125            Protocol::Tcp => true,
126            Protocol::Quic => self
127                .tls13()
128                .and_then(|cs| cs.quic)
129                .is_some(),
130        }
131    }
132
133    /// Return `true` if this is backed by a FIPS-approved implementation.
134    pub fn fips(&self) -> bool {
135        match self {
136            Self::Tls12(cs) => cs.fips(),
137            Self::Tls13(cs) => cs.fips(),
138        }
139    }
140
141    /// Return the list of `KeyExchangeAlgorithm`s supported by this cipher suite.
142    ///
143    /// TLS 1.3 cipher suites support both ECDHE and DHE key exchange, but TLS 1.2 suites
144    /// support one or the other.
145    pub(crate) fn key_exchange_algorithms(&self) -> &[KeyExchangeAlgorithm] {
146        match self {
147            Self::Tls12(tls12) => core::slice::from_ref(&tls12.kx),
148            Self::Tls13(_) => ALL_KEY_EXCHANGE_ALGORITHMS,
149        }
150    }
151
152    /// Say if the given `KeyExchangeAlgorithm` is supported by this cipher suite.
153    ///
154    /// TLS 1.3 cipher suites support all key exchange types, but TLS 1.2 suites
155    /// support only one.
156    pub(crate) fn usable_for_kx_algorithm(&self, _kxa: KeyExchangeAlgorithm) -> bool {
157        match self {
158            Self::Tls12(tls12) => tls12.kx == _kxa,
159            Self::Tls13(_) => true,
160        }
161    }
162}
163
164impl fmt::Debug for SupportedCipherSuite {
165    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
166        self.suite().fmt(f)
167    }
168}
169
170/// Return true if `sigscheme` is usable by any of the given suites.
171pub(crate) fn compatible_sigscheme_for_suites(
172    sigscheme: SignatureScheme,
173    common_suites: &[SupportedCipherSuite],
174) -> bool {
175    let sigalg = sigscheme.algorithm();
176    common_suites
177        .iter()
178        .any(|&suite| suite.usable_for_signature_algorithm(sigalg))
179}
180
181/// Secrets for transmitting/receiving data over a TLS session.
182///
183/// After performing a handshake with rustls, these secrets can be extracted
184/// to configure kTLS for a socket, and have the kernel take over encryption
185/// and/or decryption.
186#[allow(clippy::exhaustive_structs)]
187pub struct ExtractedSecrets {
188    /// sequence number and secrets for the "tx" (transmit) direction
189    pub tx: (u64, ConnectionTrafficSecrets),
190
191    /// sequence number and secrets for the "rx" (receive) direction
192    pub rx: (u64, ConnectionTrafficSecrets),
193}
194
195/// [ExtractedSecrets] minus the sequence numbers
196pub(crate) struct PartiallyExtractedSecrets {
197    /// secrets for the "tx" (transmit) direction
198    pub(crate) tx: ConnectionTrafficSecrets,
199
200    /// secrets for the "rx" (receive) direction
201    pub(crate) rx: ConnectionTrafficSecrets,
202}
203
204/// Secrets used to encrypt/decrypt data in a TLS session.
205///
206/// These can be used to configure kTLS for a socket in one direction.
207/// The only other piece of information needed is the sequence number,
208/// which is in [ExtractedSecrets].
209#[non_exhaustive]
210pub enum ConnectionTrafficSecrets {
211    /// Secrets for the AES_128_GCM AEAD algorithm
212    Aes128Gcm {
213        /// AEAD Key
214        key: AeadKey,
215        /// Initialization vector
216        iv: Iv,
217    },
218
219    /// Secrets for the AES_256_GCM AEAD algorithm
220    Aes256Gcm {
221        /// AEAD Key
222        key: AeadKey,
223        /// Initialization vector
224        iv: Iv,
225    },
226
227    /// Secrets for the CHACHA20_POLY1305 AEAD algorithm
228    Chacha20Poly1305 {
229        /// AEAD Key
230        key: AeadKey,
231        /// Initialization vector
232        iv: Iv,
233    },
234}
235
236#[cfg(test)]
237#[macro_rules_attribute::apply(test_for_each_provider)]
238mod tests {
239    use std::println;
240
241    use super::provider::tls13::*;
242
243    #[test]
244    fn test_scs_is_debug() {
245        println!("{:?}", super::provider::ALL_CIPHER_SUITES);
246    }
247
248    #[test]
249    fn test_can_resume_to() {
250        assert!(
251            TLS13_AES_128_GCM_SHA256
252                .tls13()
253                .unwrap()
254                .can_resume_from(TLS13_CHACHA20_POLY1305_SHA256_INTERNAL)
255                .is_some()
256        );
257        assert!(
258            TLS13_AES_256_GCM_SHA384
259                .tls13()
260                .unwrap()
261                .can_resume_from(TLS13_CHACHA20_POLY1305_SHA256_INTERNAL)
262                .is_none()
263        );
264    }
265}