Coverage Report

Created: 2025-12-31 06:11

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/rustls-0.23.35/src/suites.rs
Line
Count
Source
1
use core::fmt;
2
3
use crate::common_state::Protocol;
4
use crate::crypto::cipher::{AeadKey, Iv};
5
use crate::crypto::{self, KeyExchangeAlgorithm};
6
use crate::enums::{CipherSuite, SignatureAlgorithm, SignatureScheme};
7
use crate::msgs::handshake::ALL_KEY_EXCHANGE_ALGORITHMS;
8
#[cfg(feature = "tls12")]
9
use crate::tls12::Tls12CipherSuite;
10
use crate::tls13::Tls13CipherSuite;
11
#[cfg(feature = "tls12")]
12
use crate::versions::TLS12;
13
use crate::versions::{SupportedProtocolVersion, TLS13};
14
15
/// Common state for cipher suites (both for TLS 1.2 and TLS 1.3)
16
pub 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
53
impl 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
0
    pub fn fips(&self) -> bool {
58
0
        self.hash_provider.fips()
59
0
    }
Unexecuted instantiation: <rustls::suites::CipherSuiteCommon>::fips
Unexecuted instantiation: <rustls::suites::CipherSuiteCommon>::fips
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)]
67
pub 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
75
impl SupportedCipherSuite {
76
    /// The cipher suite's identifier
77
0
    pub fn suite(&self) -> CipherSuite {
78
0
        self.common().suite
79
0
    }
Unexecuted instantiation: <rustls::suites::SupportedCipherSuite>::suite
Unexecuted instantiation: <rustls::suites::SupportedCipherSuite>::suite
80
81
    /// The hash function the ciphersuite uses.
82
0
    pub(crate) fn hash_provider(&self) -> &'static dyn crypto::hash::Hash {
83
0
        self.common().hash_provider
84
0
    }
Unexecuted instantiation: <rustls::suites::SupportedCipherSuite>::hash_provider
Unexecuted instantiation: <rustls::suites::SupportedCipherSuite>::hash_provider
85
86
0
    pub(crate) fn common(&self) -> &CipherSuiteCommon {
87
0
        match self {
88
            #[cfg(feature = "tls12")]
89
            Self::Tls12(inner) => &inner.common,
90
0
            Self::Tls13(inner) => &inner.common,
91
        }
92
0
    }
Unexecuted instantiation: <rustls::suites::SupportedCipherSuite>::common
Unexecuted instantiation: <rustls::suites::SupportedCipherSuite>::common
93
94
    /// Return the inner `Tls13CipherSuite` for this suite, if it is a TLS1.3 suite.
95
0
    pub fn tls13(&self) -> Option<&'static Tls13CipherSuite> {
96
0
        match self {
97
            #[cfg(feature = "tls12")]
98
            Self::Tls12(_) => None,
99
0
            Self::Tls13(inner) => Some(inner),
100
        }
101
0
    }
Unexecuted instantiation: <rustls::suites::SupportedCipherSuite>::tls13
Unexecuted instantiation: <rustls::suites::SupportedCipherSuite>::tls13
102
103
    /// Return supported protocol version for the cipher suite.
104
0
    pub fn version(&self) -> &'static SupportedProtocolVersion {
105
0
        match self {
106
            #[cfg(feature = "tls12")]
107
            Self::Tls12(_) => &TLS12,
108
0
            Self::Tls13(_) => &TLS13,
109
        }
110
0
    }
Unexecuted instantiation: <rustls::suites::SupportedCipherSuite>::version
Unexecuted instantiation: <rustls::suites::SupportedCipherSuite>::version
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
0
    pub fn usable_for_signature_algorithm(&self, _sig_alg: SignatureAlgorithm) -> bool {
115
0
        match self {
116
0
            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
0
    }
Unexecuted instantiation: <rustls::suites::SupportedCipherSuite>::usable_for_signature_algorithm
Unexecuted instantiation: <rustls::suites::SupportedCipherSuite>::usable_for_signature_algorithm
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
0
    pub(crate) fn usable_for_protocol(&self, proto: Protocol) -> bool {
130
0
        match proto {
131
0
            Protocol::Tcp => true,
132
0
            Protocol::Quic => self
133
0
                .tls13()
134
0
                .and_then(|cs| cs.quic)
135
0
                .is_some(),
136
        }
137
0
    }
Unexecuted instantiation: <rustls::suites::SupportedCipherSuite>::usable_for_protocol
Unexecuted instantiation: <rustls::suites::SupportedCipherSuite>::usable_for_protocol
138
139
    /// Return `true` if this is backed by a FIPS-approved implementation.
140
0
    pub fn fips(&self) -> bool {
141
0
        match self {
142
            #[cfg(feature = "tls12")]
143
            Self::Tls12(cs) => cs.fips(),
144
0
            Self::Tls13(cs) => cs.fips(),
145
        }
146
0
    }
Unexecuted instantiation: <rustls::suites::SupportedCipherSuite>::fips
Unexecuted instantiation: <rustls::suites::SupportedCipherSuite>::fips
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
0
    pub(crate) fn key_exchange_algorithms(&self) -> &[KeyExchangeAlgorithm] {
153
0
        match self {
154
            #[cfg(feature = "tls12")]
155
            Self::Tls12(tls12) => core::slice::from_ref(&tls12.kx),
156
0
            Self::Tls13(_) => ALL_KEY_EXCHANGE_ALGORITHMS,
157
        }
158
0
    }
Unexecuted instantiation: <rustls::suites::SupportedCipherSuite>::key_exchange_algorithms
Unexecuted instantiation: <rustls::suites::SupportedCipherSuite>::key_exchange_algorithms
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
0
    pub(crate) fn usable_for_kx_algorithm(&self, _kxa: KeyExchangeAlgorithm) -> bool {
165
0
        match self {
166
            #[cfg(feature = "tls12")]
167
            Self::Tls12(tls12) => tls12.kx == _kxa,
168
0
            Self::Tls13(_) => true,
169
        }
170
0
    }
Unexecuted instantiation: <rustls::suites::SupportedCipherSuite>::usable_for_kx_algorithm
Unexecuted instantiation: <rustls::suites::SupportedCipherSuite>::usable_for_kx_algorithm
171
}
172
173
impl fmt::Debug for SupportedCipherSuite {
174
0
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
175
0
        self.suite().fmt(f)
176
0
    }
Unexecuted instantiation: <rustls::suites::SupportedCipherSuite as core::fmt::Debug>::fmt
Unexecuted instantiation: <rustls::suites::SupportedCipherSuite as core::fmt::Debug>::fmt
177
}
178
179
/// Return true if `sigscheme` is usable by any of the given suites.
180
0
pub(crate) fn compatible_sigscheme_for_suites(
181
0
    sigscheme: SignatureScheme,
182
0
    common_suites: &[SupportedCipherSuite],
183
0
) -> bool {
184
0
    let sigalg = sigscheme.algorithm();
185
0
    common_suites
186
0
        .iter()
187
0
        .any(|&suite| suite.usable_for_signature_algorithm(sigalg))
Unexecuted instantiation: rustls::suites::compatible_sigscheme_for_suites::{closure#0}
Unexecuted instantiation: rustls::suites::compatible_sigscheme_for_suites::{closure#0}
188
0
}
Unexecuted instantiation: rustls::suites::compatible_sigscheme_for_suites
Unexecuted instantiation: rustls::suites::compatible_sigscheme_for_suites
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.
195
pub 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
204
pub(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]
218
pub 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)]
246
mod 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
}