clia_rustls_mod/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 /// at least 2 ** 14 bytes. It **does not** consider confidentiality limits for
31 /// QUIC connections - see the [`quic::KeyBuilder.confidentiality_limit`] field for
32 /// this context.
33 pub confidentiality_limit: u64,
34}
35
36impl CipherSuiteCommon {
37 /// Return `true` if this is backed by a FIPS-approved implementation.
38 ///
39 /// This means all the constituent parts that do cryptography return `true` for `fips()`.
40 pub fn fips(&self) -> bool {
41 self.hash_provider.fips()
42 }
43}
44
45/// A cipher suite supported by rustls.
46///
47/// This type carries both configuration and implementation. Compare with
48/// [`CipherSuite`], which carries solely a cipher suite identifier.
49#[derive(Clone, Copy, PartialEq)]
50pub enum SupportedCipherSuite {
51 /// A TLS 1.2 cipher suite
52 #[cfg(feature = "tls12")]
53 Tls12(&'static Tls12CipherSuite),
54 /// A TLS 1.3 cipher suite
55 Tls13(&'static Tls13CipherSuite),
56}
57
58impl SupportedCipherSuite {
59 /// The cipher suite's identifier
60 pub fn suite(&self) -> CipherSuite {
61 self.common().suite
62 }
63
64 /// The hash function the ciphersuite uses.
65 pub(crate) fn hash_provider(&self) -> &'static dyn crypto::hash::Hash {
66 self.common().hash_provider
67 }
68
69 pub(crate) fn common(&self) -> &CipherSuiteCommon {
70 match self {
71 #[cfg(feature = "tls12")]
72 Self::Tls12(inner) => &inner.common,
73 Self::Tls13(inner) => &inner.common,
74 }
75 }
76
77 /// Return the inner `Tls13CipherSuite` for this suite, if it is a TLS1.3 suite.
78 pub fn tls13(&self) -> Option<&'static Tls13CipherSuite> {
79 match self {
80 #[cfg(feature = "tls12")]
81 Self::Tls12(_) => None,
82 Self::Tls13(inner) => Some(inner),
83 }
84 }
85
86 /// Return supported protocol version for the cipher suite.
87 pub fn version(&self) -> &'static SupportedProtocolVersion {
88 match self {
89 #[cfg(feature = "tls12")]
90 Self::Tls12(_) => &TLS12,
91 Self::Tls13(_) => &TLS13,
92 }
93 }
94
95 /// Return true if this suite is usable for a key only offering `sig_alg`
96 /// signatures. This resolves to true for all TLS1.3 suites.
97 pub fn usable_for_signature_algorithm(&self, _sig_alg: SignatureAlgorithm) -> bool {
98 match self {
99 Self::Tls13(_) => true, // no constraint expressed by ciphersuite (e.g., TLS1.3)
100 #[cfg(feature = "tls12")]
101 Self::Tls12(inner) => inner
102 .sign
103 .iter()
104 .any(|scheme| scheme.sign() == _sig_alg),
105 }
106 }
107
108 /// Return true if this suite is usable for the given [`Protocol`].
109 ///
110 /// All cipher suites are usable for TCP-TLS. Only TLS1.3 suites
111 /// with `Tls13CipherSuite::quic` provided are usable for QUIC.
112 pub(crate) fn usable_for_protocol(&self, proto: Protocol) -> bool {
113 match proto {
114 Protocol::Tcp => true,
115 Protocol::Quic => self
116 .tls13()
117 .and_then(|cs| cs.quic)
118 .is_some(),
119 }
120 }
121
122 /// Return `true` if this is backed by a FIPS-approved implementation.
123 pub fn fips(&self) -> bool {
124 match self {
125 #[cfg(feature = "tls12")]
126 Self::Tls12(cs) => cs.fips(),
127 Self::Tls13(cs) => cs.fips(),
128 }
129 }
130
131 /// Return the list of `KeyExchangeAlgorithm`s supported by this cipher suite.
132 ///
133 /// TLS 1.3 cipher suites support both ECDHE and DHE key exchange, but TLS 1.2 suites
134 /// support one or the other.
135 pub(crate) fn key_exchange_algorithms(&self) -> &[KeyExchangeAlgorithm] {
136 match self {
137 #[cfg(feature = "tls12")]
138 Self::Tls12(tls12) => core::slice::from_ref(&tls12.kx),
139 Self::Tls13(_) => ALL_KEY_EXCHANGE_ALGORITHMS,
140 }
141 }
142
143 /// Say if the given `KeyExchangeAlgorithm` is supported by this cipher suite.
144 ///
145 /// TLS 1.3 cipher suites support all key exchange types, but TLS 1.2 suites
146 /// support only one.
147 pub(crate) fn usable_for_kx_algorithm(&self, _kxa: KeyExchangeAlgorithm) -> bool {
148 match self {
149 #[cfg(feature = "tls12")]
150 Self::Tls12(tls12) => tls12.kx == _kxa,
151 Self::Tls13(_) => true,
152 }
153 }
154}
155
156impl fmt::Debug for SupportedCipherSuite {
157 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
158 self.suite().fmt(f)
159 }
160}
161
162/// Return true if `sigscheme` is usable by any of the given suites.
163pub(crate) fn compatible_sigscheme_for_suites(
164 sigscheme: SignatureScheme,
165 common_suites: &[SupportedCipherSuite],
166) -> bool {
167 let sigalg = sigscheme.sign();
168 common_suites
169 .iter()
170 .any(|&suite| suite.usable_for_signature_algorithm(sigalg))
171}
172
173/// Secrets for transmitting/receiving data over a TLS session.
174///
175/// After performing a handshake with rustls, these secrets can be extracted
176/// to configure kTLS for a socket, and have the kernel take over encryption
177/// and/or decryption.
178pub struct ExtractedSecrets {
179 /// sequence number and secrets for the "tx" (transmit) direction
180 pub tx: (u64, ConnectionTrafficSecrets),
181
182 /// sequence number and secrets for the "rx" (receive) direction
183 pub rx: (u64, ConnectionTrafficSecrets),
184}
185
186/// [ExtractedSecrets] minus the sequence numbers
187pub(crate) struct PartiallyExtractedSecrets {
188 /// secrets for the "tx" (transmit) direction
189 pub(crate) tx: ConnectionTrafficSecrets,
190
191 /// secrets for the "rx" (receive) direction
192 pub(crate) rx: ConnectionTrafficSecrets,
193}
194
195/// Secrets used to encrypt/decrypt data in a TLS session.
196///
197/// These can be used to configure kTLS for a socket in one direction.
198/// The only other piece of information needed is the sequence number,
199/// which is in [ExtractedSecrets].
200#[non_exhaustive]
201pub enum ConnectionTrafficSecrets {
202 /// Secrets for the AES_128_GCM AEAD algorithm
203 Aes128Gcm {
204 /// AEAD Key
205 key: AeadKey,
206 /// Initialization vector
207 iv: Iv,
208 },
209
210 /// Secrets for the AES_256_GCM AEAD algorithm
211 Aes256Gcm {
212 /// AEAD Key
213 key: AeadKey,
214 /// Initialization vector
215 iv: Iv,
216 },
217
218 /// Secrets for the CHACHA20_POLY1305 AEAD algorithm
219 Chacha20Poly1305 {
220 /// AEAD Key
221 key: AeadKey,
222 /// Initialization vector
223 iv: Iv,
224 },
225}
226
227test_for_each_provider! {
228 use provider::tls13::*;
229 use std::println;
230
231 #[test]
232 fn test_scs_is_debug() {
233 println!("{:?}", provider::ALL_CIPHER_SUITES);
234 }
235
236 #[test]
237 fn test_can_resume_to() {
238 assert!(TLS13_AES_128_GCM_SHA256
239 .tls13()
240 .unwrap()
241 .can_resume_from(TLS13_CHACHA20_POLY1305_SHA256_INTERNAL)
242 .is_some());
243 assert!(TLS13_AES_256_GCM_SHA384
244 .tls13()
245 .unwrap()
246 .can_resume_from(TLS13_CHACHA20_POLY1305_SHA256_INTERNAL)
247 .is_none());
248 }
249}