ytls_extensions/
compress_certificate.rs1use crate::TlsExtError;
4use ytls_typed::CertificateCompressKind;
5
6pub trait ExtCompressCertProcessor {
8 fn compress_certificate(&mut self, _: CertificateCompressKind) -> ();
10}
11
12pub struct TlsExtCompressCert {}
14
15impl TlsExtCompressCert {
16 #[inline]
18 pub fn client_compress_certificate_cb<P: ExtCompressCertProcessor>(
19 p: &mut P,
20 compress_alg_raw: &[u8],
21 ) -> Result<(), TlsExtError> {
22 if compress_alg_raw.len() < 1 {
23 return Err(TlsExtError::InvalidLength);
24 }
25 let compress_algs_len = compress_alg_raw[0];
26
27 if compress_algs_len == 0 {
28 return Err(TlsExtError::NoData);
29 }
30
31 if compress_alg_raw.len() < 4
32 || compress_algs_len as usize != compress_alg_raw.len() - 1
33 || compress_algs_len % 2 != 0
34 {
35 return Err(TlsExtError::InvalidLength);
36 }
37
38 let remaining = &compress_alg_raw[1..];
39 let expected_len = remaining.len();
40
41 if compress_algs_len as usize != expected_len {
42 return Err(TlsExtError::InvalidLength);
43 }
44
45 let mut comp_algs_i = remaining.chunks(2);
46
47 while let Some(comp_alg) = comp_algs_i.next() {
48 let comp_alg_id = u16::from_be_bytes([comp_alg[0], comp_alg[1]]);
49 p.compress_certificate(comp_alg_id.into());
50 }
51 Ok(())
52 }
53}
54
55#[cfg(test)]
56mod test {
57 use super::*;
58 use hex_literal::hex;
59 use rstest::rstest;
60 use ytls_typed::CertificateCompressKind as Cck;
61
62 #[derive(Debug, Default, PartialEq)]
63 struct Tester {
64 seen: Vec<Cck>,
65 }
66
67 impl ExtCompressCertProcessor for Tester {
68 fn compress_certificate(&mut self, comp_alg: Cck) -> () {
69 self.seen.push(comp_alg);
70 }
71 }
72
73 #[rstest]
74 #[case(
75 "06000100020003",
76 Tester { seen: vec![Cck::Zlib, Cck::Brotli, Cck::Zstd] },
77 Ok(())
78 )]
79 #[case(
80 "",
81 Tester { seen: vec![] },
82 Err(TlsExtError::InvalidLength)
83 )]
84 fn client_compress_certificate(
85 #[case] raw_t: &str,
86 #[case] expected_tester: Tester,
87 #[case] expected_res: Result<(), TlsExtError>,
88 ) {
89 let in_raw = hex::decode(raw_t).unwrap();
90 let mut tester = Tester::default();
91 let res = TlsExtCompressCert::client_compress_certificate_cb(&mut tester, &in_raw);
92 assert_eq!(expected_tester, tester);
93 assert_eq!(expected_res, res);
94 }
95}