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