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}