ytls_record/record/handshake/
cipher_suites.rs1use ytls_traits::ClientHelloProcessor;
7
8use crate::error::CipherSuitesError;
9
10use zerocopy::byteorder::network_endian::U16 as N16;
11
12pub struct CipherSuites {}
14
15impl CipherSuites {
16 pub fn parse_cipher_suites<P: ClientHelloProcessor>(
18 prc: &mut P,
19 bytes: &[u8],
20 ) -> Result<(), CipherSuitesError> {
21 if bytes.len() % 2 != 0 || bytes.len() == 0 {
22 return Err(CipherSuitesError::InvalidLength);
23 }
24
25 let mut cs_iter = bytes.chunks(2);
26
27 while let Some(cs) = cs_iter.next() {
28 prc.handle_cipher_suite(&[cs[0], cs[1]]);
29 }
30 Ok(())
31 }
32}
33
34#[cfg(test)]
35mod test {
36
37 use super::*;
38 use rstest::rstest;
39
40 #[derive(Debug, PartialEq)]
41 struct Tester {
42 suites_encountered: Vec<[u8; 2]>,
43 }
44 impl ClientHelloProcessor for Tester {
45 fn handle_extension(&mut self, _ext_id: u16, _ext_data: &[u8]) -> () {
46 unreachable!()
47 }
48 fn handle_cipher_suite(&mut self, cipher_suite: &[u8; 2]) -> () {
49 self.suites_encountered
50 .push([cipher_suite[0], cipher_suite[1]]);
51 }
52 fn handle_client_random(&mut self, _: &[u8; 32]) {
53 unreachable!()
54 }
55 fn handle_session_id(&mut self, _: &[u8]) {
56 unreachable!()
57 }
58 }
59
60 use hex_literal::hex;
61
62 #[rstest]
64 #[case("130113031302c02bc02fcca9cca8c02cc030c00ac009c013c014009c009d002f0035",
65 Ok(()),
66 Tester { suites_encountered: vec![
67 hex!("1301"), hex!("1303"), hex!("1302"), hex!("c02b"),
68 hex!("c02f"), hex!("cca9"), hex!("cca8"), hex!("c02c"),
69 hex!("c030"), hex!("c00a"), hex!("c009"), hex!("c013"),
70 hex!("c014"), hex!("009c"), hex!("009d"), hex!("002f"),
71 hex!("0035")]
72 } )]
73 #[case("130113031302c02bc02fcca9cca8c02cc030c00ac009c013c014009c009d002f00",
75 Err(CipherSuitesError::InvalidLength),
76 Tester { suites_encountered: vec![] }
77 )]
78 fn t_cipher_suites_parsing(
79 #[case] input: &'static str,
80 #[case] res: Result<(), CipherSuitesError>,
81 #[case] exp: Tester,
82 ) {
83 let mut prc = Tester {
84 suites_encountered: vec![],
85 };
86
87 let r = CipherSuites::parse_cipher_suites(&mut prc, &hex::decode(input).unwrap());
88 assert_eq!(r, res);
89 assert_eq!(exp, prc);
90 }
91}