ytls_extensions/
encrypted_client_hello.rs

1//! yTLS Extension (65037) Encrypted Client Hello handling
2
3use crate::TlsExtError;
4
5use ytls_typed::{HaeadKind, HkdfKind};
6
7/// Downstream Encrypted Client Hello Processor
8pub trait ExtEncryptedClientHelloProcessor {
9    /// Encrypted Client Hello Outer
10    fn encrypted_client_hello_outer(
11        &mut self,
12        _: u8,
13        _: HkdfKind,
14        _: HaeadKind,
15        _: &[u8],
16        _: &[u8],
17    ) -> ();
18}
19
20/// TLS Encrypted CLient Hello handling
21pub struct TlsExtEncryptedClientHello {}
22
23impl TlsExtEncryptedClientHello {
24    #[inline]
25    pub fn client_encrypted_hello_cb<P: ExtEncryptedClientHelloProcessor>(
26        p: &mut P,
27        ec_hello_raw: &[u8],
28    ) -> Result<(), TlsExtError> {
29        if ec_hello_raw.len() < 1 {
30            return Err(TlsExtError::InvalidLength);
31        }
32
33        let inner_outer_kind = ec_hello_raw[0];
34
35        if inner_outer_kind == 0 {
36            if ec_hello_raw.len() < 11 {
37                return Err(TlsExtError::InvalidLength);
38            }
39
40            let hpke_kdf_id: HkdfKind =
41                u16::from_be_bytes([ec_hello_raw[1], ec_hello_raw[2]]).into();
42            let hpke_aead_id: HaeadKind =
43                u16::from_be_bytes([ec_hello_raw[3], ec_hello_raw[4]]).into();
44
45            let config_id = ec_hello_raw[5];
46
47            let enc_len = u16::from_be_bytes([ec_hello_raw[6], ec_hello_raw[7]]);
48
49            let (enc, remaining) = ec_hello_raw[8..].split_at(enc_len as usize);
50            let payload_len = u16::from_be_bytes([remaining[0], remaining[1]]);
51
52            let payload = &remaining[2..];
53
54            if payload_len as usize != payload.len() || payload_len == 0 {
55                return Err(TlsExtError::InvalidLength);
56            }
57
58            p.encrypted_client_hello_outer(config_id, hpke_kdf_id, hpke_aead_id, enc, payload);
59        }
60
61        Ok(())
62    }
63}
64
65#[cfg(test)]
66mod test {
67    use super::*;
68    use hex_literal::hex;
69    use rstest::rstest;
70    use ytls_typed::{HaeadKind, HkdfKind};
71
72    #[derive(Debug, PartialEq)]
73    struct Outer {
74        config_id: u8,
75        kdf: HkdfKind,
76        aead: HaeadKind,
77        enc: Vec<u8>,
78        payload: Vec<u8>,
79    }
80
81    #[derive(Debug, Default, PartialEq)]
82    struct Tester {
83        outers: Vec<Outer>,
84    }
85
86    impl ExtEncryptedClientHelloProcessor for Tester {
87        fn encrypted_client_hello_outer(
88            &mut self,
89            config_id: u8,
90            kdf: HkdfKind,
91            aead: HaeadKind,
92            enc: &[u8],
93            payload: &[u8],
94        ) -> () {
95            self.outers.push(Outer {
96                config_id,
97                kdf,
98                aead,
99                enc: enc.to_vec(),
100                payload: payload.to_vec(),
101            });
102        }
103    }
104
105    #[rstest]
106    #[case(
107        "0000010001e700201f0ccafd25d84fb8e366073175f75c5d679d02b73743dff24a7478053233542d00efd8bf0fd70a2e2b4ff2d8dad3b9bbbd0f15b48916269a84b8bbee033e0d4be473fcd77f33283a1f8d1bca94347d6906d7cddec6bfc828432af8be84196800bdc41987e869b5667be6d7b36c2bf3325731f16faeea249132b5b5bbde0b15f3f664145b4a27737533f7cb35100a2ef9e22274595c23256de677f0305b86266445d776a790714b21854c44bb148acbc9681be792f863b95c44232a0f897e7dc771e3c1286e8afc55d0187d67871cb18a1cd8f3d78bd637933a782d65890da3af5ed4fb72a44565f1afa82db23671775c5f064a7a48349cd3e763f12d120180c566fd33c82e38eaab7c71fcf1150bc40967",
108        Ok(())
109    )]
110    fn encrypted_client_hello(
111        #[case] sni_raw_t: &str,
112        #[case] expected_res: Result<(), TlsExtError>,
113    ) {
114        let sni_raw = hex::decode(sni_raw_t).unwrap();
115        let mut tester = Tester::default();
116        let res = TlsExtEncryptedClientHello::client_encrypted_hello_cb(&mut tester, &sni_raw);
117        insta::assert_debug_snapshot!(tester);
118        assert_eq!(expected_res, res);
119    }
120}