1use std::fmt;
2
3use crate::enums::{CipherSuite, ProtocolVersion, SignatureAlgorithm, SignatureScheme};
4#[cfg(feature = "tls12")]
5use crate::tls12::Tls12CipherSuite;
6#[cfg(feature = "tls12")]
7use crate::tls12::{
8 TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
9 TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
11 TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,
12 TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
13 TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
14 TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
15};
16use crate::tls13::Tls13CipherSuite;
17use crate::tls13::{
18 TLS13_AES_128_GCM_SHA256, TLS13_AES_256_GCM_SHA384, TLS13_CHACHA20_POLY1305_SHA256,
19};
20#[cfg(feature = "tls12")]
21use crate::versions::TLS12;
22use crate::versions::{SupportedProtocolVersion, TLS13};
23
24#[allow(non_camel_case_types)]
26#[derive(Debug, Eq, PartialEq)]
27pub enum BulkAlgorithm {
28 Aes128Gcm,
30
31 Aes256Gcm,
33
34 Chacha20Poly1305,
36}
37
38#[derive(Debug)]
40pub struct CipherSuiteCommon {
41 pub suite: CipherSuite,
43
44 pub bulk: BulkAlgorithm,
46
47 pub(crate) aead_algorithm: &'static ring::aead::Algorithm,
48}
49
50#[derive(Clone, Copy, PartialEq)]
55pub enum SupportedCipherSuite {
56 #[cfg(feature = "tls12")]
58 Tls12(&'static Tls12CipherSuite),
59 Tls13(&'static Tls13CipherSuite),
61}
62
63impl fmt::Debug for SupportedCipherSuite {
64 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
65 self.suite().fmt(f)
66 }
67}
68
69impl SupportedCipherSuite {
70 pub fn hash_algorithm(&self) -> &'static ring::digest::Algorithm {
72 match self {
73 #[cfg(feature = "tls12")]
74 Self::Tls12(inner) => inner.hash_algorithm(),
75 Self::Tls13(inner) => inner.hash_algorithm(),
76 }
77 }
78
79 pub fn suite(&self) -> CipherSuite {
81 self.common().suite
82 }
83
84 pub(crate) fn common(&self) -> &CipherSuiteCommon {
85 match self {
86 #[cfg(feature = "tls12")]
87 Self::Tls12(inner) => &inner.common,
88 Self::Tls13(inner) => &inner.common,
89 }
90 }
91
92 #[cfg(any(test, feature = "quic"))]
93 pub(crate) fn tls13(&self) -> Option<&'static Tls13CipherSuite> {
94 match self {
95 #[cfg(feature = "tls12")]
96 Self::Tls12(_) => None,
97 Self::Tls13(inner) => Some(inner),
98 }
99 }
100
101 pub fn version(&self) -> &'static SupportedProtocolVersion {
103 match self {
104 #[cfg(feature = "tls12")]
105 Self::Tls12(_) => &TLS12,
106 Self::Tls13(_) => &TLS13,
107 }
108 }
109
110 pub fn usable_for_signature_algorithm(&self, _sig_alg: SignatureAlgorithm) -> bool {
113 match self {
114 Self::Tls13(_) => true, #[cfg(feature = "tls12")]
116 Self::Tls12(inner) => inner
117 .sign
118 .iter()
119 .any(|scheme| scheme.sign() == _sig_alg),
120 }
121 }
122}
123
124pub static ALL_CIPHER_SUITES: &[SupportedCipherSuite] = &[
126 TLS13_AES_256_GCM_SHA384,
128 TLS13_AES_128_GCM_SHA256,
129 TLS13_CHACHA20_POLY1305_SHA256,
130 #[cfg(feature = "tls12")]
132 TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
133 #[cfg(feature = "tls12")]
134 TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
135 #[cfg(feature = "tls12")]
136 TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,
137 #[cfg(feature = "tls12")]
138 TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
139 #[cfg(feature = "tls12")]
140 TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
141 #[cfg(feature = "tls12")]
142 TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
143];
144
145pub static DEFAULT_CIPHER_SUITES: &[SupportedCipherSuite] = ALL_CIPHER_SUITES;
150
151pub(crate) fn choose_ciphersuite_preferring_client(
153 client_suites: &[CipherSuite],
154 server_suites: &[SupportedCipherSuite],
155) -> Option<SupportedCipherSuite> {
156 for client_suite in client_suites {
157 if let Some(selected) = server_suites
158 .iter()
159 .find(|x| *client_suite == x.suite())
160 {
161 return Some(*selected);
162 }
163 }
164
165 None
166}
167
168pub(crate) fn choose_ciphersuite_preferring_server(
169 client_suites: &[CipherSuite],
170 server_suites: &[SupportedCipherSuite],
171) -> Option<SupportedCipherSuite> {
172 if let Some(selected) = server_suites
173 .iter()
174 .find(|x| client_suites.contains(&x.suite()))
175 {
176 return Some(*selected);
177 }
178
179 None
180}
181
182pub(crate) fn reduce_given_sigalg(
185 all: &[SupportedCipherSuite],
186 sigalg: SignatureAlgorithm,
187) -> Vec<SupportedCipherSuite> {
188 all.iter()
189 .filter(|&&suite| suite.usable_for_signature_algorithm(sigalg))
190 .copied()
191 .collect()
192}
193
194pub(crate) fn reduce_given_version(
197 all: &[SupportedCipherSuite],
198 version: ProtocolVersion,
199) -> Vec<SupportedCipherSuite> {
200 all.iter()
201 .filter(|&&suite| suite.version().version == version)
202 .copied()
203 .collect()
204}
205
206pub(crate) fn compatible_sigscheme_for_suites(
208 sigscheme: SignatureScheme,
209 common_suites: &[SupportedCipherSuite],
210) -> bool {
211 let sigalg = sigscheme.sign();
212 common_suites
213 .iter()
214 .any(|&suite| suite.usable_for_signature_algorithm(sigalg))
215}
216
217#[cfg(feature = "secret_extraction")]
223#[cfg_attr(docsrs, doc(cfg(feature = "secret_extraction")))]
224pub struct ExtractedSecrets {
225 pub tx: (u64, ConnectionTrafficSecrets),
227
228 pub rx: (u64, ConnectionTrafficSecrets),
230}
231
232#[cfg(feature = "secret_extraction")]
234pub(crate) struct PartiallyExtractedSecrets {
235 pub(crate) tx: ConnectionTrafficSecrets,
237
238 pub(crate) rx: ConnectionTrafficSecrets,
240}
241
242#[cfg(feature = "secret_extraction")]
248#[cfg_attr(docsrs, doc(cfg(feature = "secret_extraction")))]
249#[non_exhaustive]
250pub enum ConnectionTrafficSecrets {
251 Aes128Gcm {
253 key: [u8; 16],
255 salt: [u8; 4],
257 iv: [u8; 8],
259 },
260
261 Aes256Gcm {
263 key: [u8; 32],
265 salt: [u8; 4],
267 iv: [u8; 8],
269 },
270
271 Chacha20Poly1305 {
273 key: [u8; 32],
275 iv: [u8; 12],
277 },
278}
279
280#[cfg(test)]
281mod test {
282 use super::*;
283
284 #[test]
285 fn test_client_pref() {
286 let client = vec![
287 CipherSuite::TLS13_AES_128_GCM_SHA256,
288 CipherSuite::TLS13_AES_256_GCM_SHA384,
289 ];
290 let server = vec![TLS13_AES_256_GCM_SHA384, TLS13_AES_128_GCM_SHA256];
291 let chosen = choose_ciphersuite_preferring_client(&client, &server);
292 assert!(chosen.is_some());
293 assert_eq!(chosen.unwrap(), TLS13_AES_128_GCM_SHA256);
294 }
295
296 #[test]
297 fn test_server_pref() {
298 let client = vec![
299 CipherSuite::TLS13_AES_128_GCM_SHA256,
300 CipherSuite::TLS13_AES_256_GCM_SHA384,
301 ];
302 let server = vec![TLS13_AES_256_GCM_SHA384, TLS13_AES_128_GCM_SHA256];
303 let chosen = choose_ciphersuite_preferring_server(&client, &server);
304 assert!(chosen.is_some());
305 assert_eq!(chosen.unwrap(), TLS13_AES_256_GCM_SHA384);
306 }
307
308 #[test]
309 fn test_pref_fails() {
310 assert!(choose_ciphersuite_preferring_client(
311 &[CipherSuite::TLS_NULL_WITH_NULL_NULL],
312 ALL_CIPHER_SUITES
313 )
314 .is_none());
315 assert!(choose_ciphersuite_preferring_server(
316 &[CipherSuite::TLS_NULL_WITH_NULL_NULL],
317 ALL_CIPHER_SUITES
318 )
319 .is_none());
320 }
321
322 #[test]
323 fn test_scs_is_debug() {
324 println!("{:?}", ALL_CIPHER_SUITES);
325 }
326
327 #[test]
328 fn test_can_resume_to() {
329 assert!(TLS13_AES_128_GCM_SHA256
330 .tls13()
331 .unwrap()
332 .can_resume_from(crate::tls13::TLS13_CHACHA20_POLY1305_SHA256_INTERNAL)
333 .is_some());
334 assert!(TLS13_AES_256_GCM_SHA384
335 .tls13()
336 .unwrap()
337 .can_resume_from(crate::tls13::TLS13_CHACHA20_POLY1305_SHA256_INTERNAL)
338 .is_none());
339 }
340}