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;
8#[cfg(feature = "tls12")]
9use crate::tls12::Tls12CipherSuite;
10use crate::tls13::Tls13CipherSuite;
11#[cfg(feature = "tls12")]
12use crate::versions::TLS12;
13use crate::versions::{SupportedProtocolVersion, TLS13};
14
15/// Common state for cipher suites (both for TLS 1.2 and TLS 1.3)
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 crypto::hash::Hash,
22
23 /// Number of TCP-TLS messages that can be safely encrypted with a single key of this type
24 ///
25 /// Once a `MessageEncrypter` produced for this suite has encrypted more than
26 /// `confidentiality_limit` messages, 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 messages 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 `true` if this is backed by a FIPS-approved implementation.
55 ///
56 /// This means all the constituent parts that do cryptography return `true` for `fips()`.
57 pub fn fips(&self) -> bool {
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#[derive(Clone, Copy, PartialEq)]
67pub enum SupportedCipherSuite {
68 /// A TLS 1.2 cipher suite
69 #[cfg(feature = "tls12")]
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 crypto::hash::Hash {
83 self.common().hash_provider
84 }
85
86 pub(crate) fn common(&self) -> &CipherSuiteCommon {
87 match self {
88 #[cfg(feature = "tls12")]
89 Self::Tls12(inner) => &inner.common,
90 Self::Tls13(inner) => &inner.common,
91 }
92 }
93
94 /// Return the inner `Tls13CipherSuite` for this suite, if it is a TLS1.3 suite.
95 pub fn tls13(&self) -> Option<&'static Tls13CipherSuite> {
96 match self {
97 #[cfg(feature = "tls12")]
98 Self::Tls12(_) => None,
99 Self::Tls13(inner) => Some(inner),
100 }
101 }
102
103 /// Return supported protocol version for the cipher suite.
104 pub fn version(&self) -> &'static SupportedProtocolVersion {
105 match self {
106 #[cfg(feature = "tls12")]
107 Self::Tls12(_) => &TLS12,
108 Self::Tls13(_) => &TLS13,
109 }
110 }
111
112 /// Return true if this suite is usable for a key only offering `sig_alg`
113 /// signatures. This resolves to true for all TLS1.3 suites.
114 pub fn usable_for_signature_algorithm(&self, _sig_alg: SignatureAlgorithm) -> bool {
115 match self {
116 Self::Tls13(_) => true, // no constraint expressed by ciphersuite (e.g., TLS1.3)
117 #[cfg(feature = "tls12")]
118 Self::Tls12(inner) => inner
119 .sign
120 .iter()
121 .any(|scheme| scheme.algorithm() == _sig_alg),
122 }
123 }
124
125 /// Return true if this suite is usable for the given [`Protocol`].
126 ///
127 /// All cipher suites are usable for TCP-TLS. Only TLS1.3 suites
128 /// with `Tls13CipherSuite::quic` provided are usable for QUIC.
129 pub(crate) fn usable_for_protocol(&self, proto: Protocol) -> bool {
130 match proto {
131 Protocol::Tcp => true,
132 Protocol::Quic => self
133 .tls13()
134 .and_then(|cs| cs.quic)
135 .is_some(),
136 }
137 }
138
139 /// Return `true` if this is backed by a FIPS-approved implementation.
140 pub fn fips(&self) -> bool {
141 match self {
142 #[cfg(feature = "tls12")]
143 Self::Tls12(cs) => cs.fips(),
144 Self::Tls13(cs) => cs.fips(),
145 }
146 }
147
148 /// Return the list of `KeyExchangeAlgorithm`s supported by this cipher suite.
149 ///
150 /// TLS 1.3 cipher suites support both ECDHE and DHE key exchange, but TLS 1.2 suites
151 /// support one or the other.
152 pub(crate) fn key_exchange_algorithms(&self) -> &[KeyExchangeAlgorithm] {
153 match self {
154 #[cfg(feature = "tls12")]
155 Self::Tls12(tls12) => core::slice::from_ref(&tls12.kx),
156 Self::Tls13(_) => ALL_KEY_EXCHANGE_ALGORITHMS,
157 }
158 }
159
160 /// Say if the given `KeyExchangeAlgorithm` is supported by this cipher suite.
161 ///
162 /// TLS 1.3 cipher suites support all key exchange types, but TLS 1.2 suites
163 /// support only one.
164 pub(crate) fn usable_for_kx_algorithm(&self, _kxa: KeyExchangeAlgorithm) -> bool {
165 match self {
166 #[cfg(feature = "tls12")]
167 Self::Tls12(tls12) => tls12.kx == _kxa,
168 Self::Tls13(_) => true,
169 }
170 }
171}
172
173impl fmt::Debug for SupportedCipherSuite {
174 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
175 self.suite().fmt(f)
176 }
177}
178
179/// Return true if `sigscheme` is usable by any of the given suites.
180pub(crate) fn compatible_sigscheme_for_suites(
181 sigscheme: SignatureScheme,
182 common_suites: &[SupportedCipherSuite],
183) -> bool {
184 let sigalg = sigscheme.algorithm();
185 common_suites
186 .iter()
187 .any(|&suite| suite.usable_for_signature_algorithm(sigalg))
188}
189
190/// Secrets for transmitting/receiving data over a TLS session.
191///
192/// After performing a handshake with rustls, these secrets can be extracted
193/// to configure kTLS for a socket, and have the kernel take over encryption
194/// and/or decryption.
195pub struct ExtractedSecrets {
196 /// sequence number and secrets for the "tx" (transmit) direction
197 pub tx: (u64, ConnectionTrafficSecrets),
198
199 /// sequence number and secrets for the "rx" (receive) direction
200 pub rx: (u64, ConnectionTrafficSecrets),
201}
202
203/// [ExtractedSecrets] minus the sequence numbers
204pub(crate) struct PartiallyExtractedSecrets {
205 /// secrets for the "tx" (transmit) direction
206 pub(crate) tx: ConnectionTrafficSecrets,
207
208 /// secrets for the "rx" (receive) direction
209 pub(crate) rx: ConnectionTrafficSecrets,
210}
211
212/// Secrets used to encrypt/decrypt data in a TLS session.
213///
214/// These can be used to configure kTLS for a socket in one direction.
215/// The only other piece of information needed is the sequence number,
216/// which is in [ExtractedSecrets].
217#[non_exhaustive]
218pub enum ConnectionTrafficSecrets {
219 /// Secrets for the AES_128_GCM AEAD algorithm
220 Aes128Gcm {
221 /// AEAD Key
222 key: AeadKey,
223 /// Initialization vector
224 iv: Iv,
225 },
226
227 /// Secrets for the AES_256_GCM AEAD algorithm
228 Aes256Gcm {
229 /// AEAD Key
230 key: AeadKey,
231 /// Initialization vector
232 iv: Iv,
233 },
234
235 /// Secrets for the CHACHA20_POLY1305 AEAD algorithm
236 Chacha20Poly1305 {
237 /// AEAD Key
238 key: AeadKey,
239 /// Initialization vector
240 iv: Iv,
241 },
242}
243
244#[cfg(test)]
245#[macro_rules_attribute::apply(test_for_each_provider)]
246mod tests {
247 use std::println;
248
249 use super::provider::tls13::*;
250
251 #[test]
252 fn test_scs_is_debug() {
253 println!("{:?}", super::provider::ALL_CIPHER_SUITES);
254 }
255
256 #[test]
257 fn test_can_resume_to() {
258 assert!(
259 TLS13_AES_128_GCM_SHA256
260 .tls13()
261 .unwrap()
262 .can_resume_from(TLS13_CHACHA20_POLY1305_SHA256_INTERNAL)
263 .is_some()
264 );
265 assert!(
266 TLS13_AES_256_GCM_SHA384
267 .tls13()
268 .unwrap()
269 .can_resume_from(TLS13_CHACHA20_POLY1305_SHA256_INTERNAL)
270 .is_none()
271 );
272 }
273}