1use crate::common_state::Protocol;
2use crate::crypto;
3use crate::crypto::cipher::{AeadKey, Iv};
4use crate::enums::{CipherSuite, ProtocolVersion, SignatureAlgorithm, SignatureScheme};
5#[cfg(feature = "tls12")]
6use crate::tls12::Tls12CipherSuite;
7use crate::tls13::Tls13CipherSuite;
8#[cfg(feature = "tls12")]
9use crate::versions::TLS12;
10use crate::versions::{SupportedProtocolVersion, TLS13};
11
12use alloc::vec::Vec;
13use core::fmt;
14
15pub struct CipherSuiteCommon {
17 pub suite: CipherSuite,
19
20 pub hash_provider: &'static dyn crypto::hash::Hash,
22
23 pub confidentiality_limit: u64,
32
33 pub integrity_limit: u64,
42}
43
44#[derive(Clone, Copy, PartialEq)]
49pub enum SupportedCipherSuite {
50 #[cfg(feature = "tls12")]
52 Tls12(&'static Tls12CipherSuite),
53 Tls13(&'static Tls13CipherSuite),
55}
56
57impl fmt::Debug for SupportedCipherSuite {
58 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
59 self.suite().fmt(f)
60 }
61}
62
63impl SupportedCipherSuite {
64 pub fn suite(&self) -> CipherSuite {
66 self.common().suite
67 }
68
69 pub(crate) fn hash_provider(&self) -> &'static dyn crypto::hash::Hash {
71 self.common().hash_provider
72 }
73
74 pub(crate) fn common(&self) -> &CipherSuiteCommon {
75 match self {
76 #[cfg(feature = "tls12")]
77 Self::Tls12(inner) => &inner.common,
78 Self::Tls13(inner) => &inner.common,
79 }
80 }
81
82 pub fn tls13(&self) -> Option<&'static Tls13CipherSuite> {
84 match self {
85 #[cfg(feature = "tls12")]
86 Self::Tls12(_) => None,
87 Self::Tls13(inner) => Some(inner),
88 }
89 }
90
91 pub fn version(&self) -> &'static SupportedProtocolVersion {
93 match self {
94 #[cfg(feature = "tls12")]
95 Self::Tls12(_) => &TLS12,
96 Self::Tls13(_) => &TLS13,
97 }
98 }
99
100 pub fn usable_for_signature_algorithm(&self, _sig_alg: SignatureAlgorithm) -> bool {
103 match self {
104 Self::Tls13(_) => true, #[cfg(feature = "tls12")]
106 Self::Tls12(inner) => inner
107 .sign
108 .iter()
109 .any(|scheme| scheme.sign() == _sig_alg),
110 }
111 }
112
113 pub(crate) fn usable_for_protocol(&self, proto: Protocol) -> bool {
118 match proto {
119 Protocol::Tcp => true,
120 Protocol::Quic => self
121 .tls13()
122 .and_then(|cs| cs.quic)
123 .is_some(),
124 }
125 }
126}
127
128pub(crate) fn choose_ciphersuite_preferring_client(
130 client_suites: &[CipherSuite],
131 server_suites: &[SupportedCipherSuite],
132) -> Option<SupportedCipherSuite> {
133 for client_suite in client_suites {
134 if let Some(selected) = server_suites
135 .iter()
136 .find(|x| *client_suite == x.suite())
137 {
138 return Some(*selected);
139 }
140 }
141
142 None
143}
144
145pub(crate) fn choose_ciphersuite_preferring_server(
146 client_suites: &[CipherSuite],
147 server_suites: &[SupportedCipherSuite],
148) -> Option<SupportedCipherSuite> {
149 if let Some(selected) = server_suites
150 .iter()
151 .find(|x| client_suites.contains(&x.suite()))
152 {
153 return Some(*selected);
154 }
155
156 None
157}
158
159pub(crate) fn reduce_given_sigalg(
162 all: &[SupportedCipherSuite],
163 sigalg: SignatureAlgorithm,
164) -> Vec<SupportedCipherSuite> {
165 all.iter()
166 .filter(|&&suite| suite.usable_for_signature_algorithm(sigalg))
167 .copied()
168 .collect()
169}
170
171pub(crate) fn reduce_given_version_and_protocol(
174 all: &[SupportedCipherSuite],
175 version: ProtocolVersion,
176 proto: Protocol,
177) -> Vec<SupportedCipherSuite> {
178 all.iter()
179 .filter(|&&suite| suite.version().version == version && suite.usable_for_protocol(proto))
180 .copied()
181 .collect()
182}
183
184pub(crate) fn compatible_sigscheme_for_suites(
186 sigscheme: SignatureScheme,
187 common_suites: &[SupportedCipherSuite],
188) -> bool {
189 let sigalg = sigscheme.sign();
190 common_suites
191 .iter()
192 .any(|&suite| suite.usable_for_signature_algorithm(sigalg))
193}
194
195pub struct ExtractedSecrets {
201 pub tx: (u64, ConnectionTrafficSecrets),
203
204 pub rx: (u64, ConnectionTrafficSecrets),
206}
207
208pub(crate) struct PartiallyExtractedSecrets {
210 pub(crate) tx: ConnectionTrafficSecrets,
212
213 pub(crate) rx: ConnectionTrafficSecrets,
215}
216
217#[non_exhaustive]
223pub enum ConnectionTrafficSecrets {
224 Aes128Gcm {
226 key: AeadKey,
228 iv: Iv,
230 },
231
232 Aes256Gcm {
234 key: AeadKey,
236 iv: Iv,
238 },
239
240 Chacha20Poly1305 {
242 key: AeadKey,
244 iv: Iv,
246 },
247}
248
249#[cfg(all(test, feature = "ring"))]
250#[cfg(all(test, any(feature = "ring", feature = "aws_lc_rs")))]
251mod tests {
252 use super::*;
253 use crate::enums::CipherSuite;
254 use crate::test_provider::tls13::*;
255
256 #[test]
257 fn test_client_pref() {
258 let client = vec![
259 CipherSuite::TLS13_AES_128_GCM_SHA256,
260 CipherSuite::TLS13_AES_256_GCM_SHA384,
261 ];
262 let server = vec![TLS13_AES_256_GCM_SHA384, TLS13_AES_128_GCM_SHA256];
263 let chosen = choose_ciphersuite_preferring_client(&client, &server);
264 assert!(chosen.is_some());
265 assert_eq!(chosen.unwrap(), TLS13_AES_128_GCM_SHA256);
266 }
267
268 #[test]
269 fn test_server_pref() {
270 let client = vec![
271 CipherSuite::TLS13_AES_128_GCM_SHA256,
272 CipherSuite::TLS13_AES_256_GCM_SHA384,
273 ];
274 let server = vec![TLS13_AES_256_GCM_SHA384, TLS13_AES_128_GCM_SHA256];
275 let chosen = choose_ciphersuite_preferring_server(&client, &server);
276 assert!(chosen.is_some());
277 assert_eq!(chosen.unwrap(), TLS13_AES_256_GCM_SHA384);
278 }
279
280 #[test]
281 fn test_pref_fails() {
282 assert!(choose_ciphersuite_preferring_client(
283 &[CipherSuite::TLS_NULL_WITH_NULL_NULL],
284 crypto::ring::ALL_CIPHER_SUITES
285 )
286 .is_none());
287 assert!(choose_ciphersuite_preferring_server(
288 &[CipherSuite::TLS_NULL_WITH_NULL_NULL],
289 crypto::ring::ALL_CIPHER_SUITES
290 )
291 .is_none());
292 }
293
294 #[test]
295 fn test_scs_is_debug() {
296 println!("{:?}", crypto::ring::ALL_CIPHER_SUITES);
297 }
298
299 #[test]
300 fn test_can_resume_to() {
301 assert!(TLS13_AES_128_GCM_SHA256
302 .tls13()
303 .unwrap()
304 .can_resume_from(TLS13_CHACHA20_POLY1305_SHA256_INTERNAL)
305 .is_some());
306 assert!(TLS13_AES_256_GCM_SHA384
307 .tls13()
308 .unwrap()
309 .can_resume_from(TLS13_CHACHA20_POLY1305_SHA256_INTERNAL)
310 .is_none());
311 }
312}