ytls_extensions/
encrypted_client_hello.rs1use crate::TlsExtError;
4
5use ytls_typed::{HaeadKind, HkdfKind};
6
7pub trait ExtEncryptedClientHelloProcessor {
9 fn encrypted_client_hello_outer(
11 &mut self,
12 _: u8,
13 _: HkdfKind,
14 _: HaeadKind,
15 _: &[u8],
16 _: &[u8],
17 ) -> ();
18}
19
20pub 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}