1pub mod error;
2
3use rand::RngExt;
4use std::str::FromStr;
5use sha2::{Sha256, Digest};
6use std::net::{SocketAddr, TcpStream, ToSocketAddrs};
7use std::io::{Write, Read};
8use std::time::Duration;
9use rand::seq::IndexedRandom;
10use crate::error::{DetailedError, JarmError};
11
12const ALPN_EXTENSION: &[u8; 2] = b"\x00\x10";
13const SOCKET_BUFFER: u64 = 1484;
14const DEFAULT_TIMEOUT: Duration = Duration::from_secs(30);
15
16
17pub struct JarmPart {
18 pub raw: String
19}
20
21impl JarmPart {
22 pub fn new(raw: &str) -> JarmPart {
23 JarmPart {
24 raw: raw.to_string(),
25 }
26 }
27}
28
29#[non_exhaustive]
30pub struct Jarm {
31 pub parts: Vec<JarmPart>,
32 pub queue: Vec<PacketSpecification>,
33 pub rng: Box<dyn JarmRng + 'static>,
34 pub timeout: Duration,
35}
36
37impl Default for Jarm {
38 fn default() -> Self {
39 Jarm::new("localhost".to_string(), "80".to_string())
40 }
41}
42
43impl Jarm {
44 pub fn new(host: String, port: String) -> Jarm {
45 Jarm {
46 parts: Vec::new(),
47 queue: vec![
48 PacketSpecification {
50 host: host.clone(),
51 port: port.clone(),
52 tls_version: TlsVersion::TLS1_2,
53 cipher_list: CipherList::ALL,
54 cipher_order: CipherOrder::FORWARD,
55 use_grease: false,
56 use_rare_apln: false,
57 tls_version_support: TlsVersionSupport::TLS1_2,
58 extension_order: CipherOrder::REVERSE,
59 },
60 PacketSpecification {
61 host: host.clone(),
62 port: port.clone(),
63 tls_version: TlsVersion::TLS1_2,
64 cipher_list: CipherList::ALL,
65 cipher_order: CipherOrder::REVERSE,
66 use_grease: false,
67 use_rare_apln: false,
68 tls_version_support: TlsVersionSupport::TLS1_2,
69 extension_order: CipherOrder::FORWARD,
70 },
71 PacketSpecification {
72 host: host.clone(),
73 port: port.clone(),
74 tls_version: TlsVersion::TLS1_2,
75 cipher_list: CipherList::ALL,
76 cipher_order: CipherOrder::TOP_HALF,
77 use_grease: false,
78 use_rare_apln: false,
79 tls_version_support: TlsVersionSupport::NO_SUPPORT,
80 extension_order: CipherOrder::FORWARD,
81 },
82 PacketSpecification {
83 host: host.clone(),
84 port: port.clone(),
85 tls_version: TlsVersion::TLS1_2,
86 cipher_list: CipherList::ALL,
87 cipher_order: CipherOrder::BOTTOM_HALF,
88 use_grease: false,
89 use_rare_apln: true,
90 tls_version_support: TlsVersionSupport::NO_SUPPORT,
91 extension_order: CipherOrder::FORWARD,
92 },
93 PacketSpecification {
94 host: host.clone(),
95 port: port.clone(),
96 tls_version: TlsVersion::TLS1_2,
97 cipher_list: CipherList::ALL,
98 cipher_order: CipherOrder::MIDDLE_OUT,
99 use_grease: true,
100 use_rare_apln: true,
101 tls_version_support: TlsVersionSupport::NO_SUPPORT,
102 extension_order: CipherOrder::REVERSE,
103 },
104 PacketSpecification {
105 host: host.clone(),
106 port: port.clone(),
107 tls_version: TlsVersion::TLS1_1,
108 cipher_list: CipherList::ALL,
109 cipher_order: CipherOrder::FORWARD,
110 use_grease: false,
111 use_rare_apln: false,
112 tls_version_support: TlsVersionSupport::NO_SUPPORT,
113 extension_order: CipherOrder::FORWARD,
114 },
115 PacketSpecification {
116 host: host.clone(),
117 port: port.clone(),
118 tls_version: TlsVersion::TLS1_3,
119 cipher_list: CipherList::ALL,
120 cipher_order: CipherOrder::FORWARD,
121 use_grease: false,
122 use_rare_apln: false,
123 tls_version_support: TlsVersionSupport::TLS1_3,
124 extension_order: CipherOrder::REVERSE,
125 },
126 PacketSpecification {
127 host: host.clone(),
128 port: port.clone(),
129 tls_version: TlsVersion::TLS1_3,
130 cipher_list: CipherList::ALL,
131 cipher_order: CipherOrder::REVERSE,
132 use_grease: false,
133 use_rare_apln: false,
134 tls_version_support: TlsVersionSupport::TLS1_3,
135 extension_order: CipherOrder::FORWARD,
136 },
137 PacketSpecification {
138 host: host.clone(),
139 port: port.clone(),
140 tls_version: TlsVersion::TLS1_3,
141 cipher_list: CipherList::NO1_3,
142 cipher_order: CipherOrder::FORWARD,
143 use_grease: false,
144 use_rare_apln: false,
145 tls_version_support: TlsVersionSupport::TLS1_3,
146 extension_order: CipherOrder::FORWARD,
147 },
148 PacketSpecification {
149 host,
150 port,
151 tls_version: TlsVersion::TLS1_3,
152 cipher_list: CipherList::ALL,
153 cipher_order: CipherOrder::MIDDLE_OUT,
154 use_grease: true,
155 use_rare_apln: false,
156 tls_version_support: TlsVersionSupport::TLS1_3,
157 extension_order: CipherOrder::REVERSE,
158 },
159 ],
161 rng: Box::new(PseudoRng {}),
162 timeout: DEFAULT_TIMEOUT
163 }
164 }
165
166 pub fn retrieve_parts(&mut self) -> Result<Vec<JarmPart>, JarmError> {
167 let mut parts = Vec::new();
168 for spec in &self.queue {
169 let payload = build_packet(spec, self.rng.as_ref());
170
171 let url = format!("{}:{}", spec.host, spec.port);
173 let address = resolve(url)?; let mut data = [0_u8; SOCKET_BUFFER as usize];
175 match TcpStream::connect_timeout(&address, self.timeout) {
176 Ok(mut stream) => {
177 stream.set_read_timeout(Some(self.timeout))?;
178 stream.set_write_timeout(Some(self.timeout))?;
179 stream.write_all(&payload)?;
180 let mut handle = stream.take(SOCKET_BUFFER);
181 let _read_result = handle.read(&mut data)?;
182 },
183 Err(e) => return Err(JarmError::Connection(DetailedError::from(Box::from(e))))
184 }
185 let jarm_part = read_packet(Vec::from(data));
186 parts.push(jarm_part);
187 }
188 Ok(parts)
189 }
190
191 pub fn hash(&mut self) -> Result<String, JarmError> {
192 if self.parts.is_empty(){
193 self.parts = self.retrieve_parts()?
194 }
195 if self.parts.iter().all(|p| p.raw == "|||") {
196 return Ok("0".repeat(62));
197 }
198
199 let mut fuzzy_hash = String::new();
200 let mut alpns_and_ext = String::new();
201
202 for part in &self.parts {
203 let components: Vec<&str> = part.raw.split('|').collect();
204 fuzzy_hash.push_str(&cipher_bytes(components[0]));
206 fuzzy_hash.push(version_byte(components[1]));
207 alpns_and_ext.push_str(components[2]);
208 alpns_and_ext.push_str(components[3]);
209 }
210
211 let mut hasher = Sha256::new();
213 hasher.update(alpns_and_ext.into_bytes());
214 let sha256 = hex::encode(hasher.finalize());
215 fuzzy_hash.push_str(sha256.get(0..32).unwrap());
216 Ok(fuzzy_hash)
217 }
218}
219
220#[derive(PartialEq, Eq)]
221pub enum TlsVersion {
222 TLS1_1,
223 TLS1_2,
224 TLS1_3,
225}
226
227#[derive(PartialEq, Eq)]
228pub enum CipherList {
229 ALL,
230 NO1_3,
231}
232
233#[allow(non_camel_case_types)]
234#[derive(PartialEq, Eq)]
235pub enum CipherOrder {
236 FORWARD,
237 REVERSE,
238 TOP_HALF,
239 BOTTOM_HALF,
240 MIDDLE_OUT,
241}
242
243#[allow(non_camel_case_types)]
244#[derive(PartialEq, Eq)]
245pub enum TlsVersionSupport {
246 TLS1_2,
247 TLS1_3,
248 NO_SUPPORT,
249}
250
251pub struct PacketSpecification {
252 pub host: String,
253 pub port: String,
254 pub tls_version: TlsVersion,
255 pub cipher_list: CipherList,
256 pub cipher_order: CipherOrder,
257 pub use_grease: bool,
258 pub use_rare_apln: bool,
259 pub tls_version_support: TlsVersionSupport,
260 pub extension_order: CipherOrder,
261}
262
263
264pub fn build_packet(jarm_details: &PacketSpecification, rng: &dyn JarmRng) -> Vec<u8> {
265 let mut client_hello = Vec::new();
266 let mut payload= b"\x16".to_vec();
267
268 match jarm_details.tls_version {
269 TlsVersion::TLS1_1 => {
270 payload.extend(b"\x03\x02");
271 client_hello.extend(b"\x03\x02");
272 }
273 TlsVersion::TLS1_2 => {
274 payload.extend(b"\x03\x03");
275 client_hello.extend(b"\x03\x03");
276 }
277 TlsVersion::TLS1_3 => {
278 payload.extend(b"\x03\x01");
279 client_hello.extend(b"\x03\x03");
280 }
281 }
282
283 client_hello.extend(rng.random_bytes());
284 let session_id = rng.random_bytes();
285 let session_id_length = pack_as_unsigned_char(session_id.len());
286 client_hello.push(session_id_length);
287 client_hello.extend(session_id);
288
289 let cipher_choice = get_ciphers(jarm_details, rng);
290 let client_suites_length = pack_as_unsigned_short(cipher_choice.len());
291 client_hello.extend(client_suites_length);
292 client_hello.extend(cipher_choice);
293 client_hello.push(b'\x01'); client_hello.push(b'\x00'); client_hello.extend(get_extensions(jarm_details, rng));
296
297 let mut inner_length = b"\x00".to_vec();
299 inner_length.extend(pack_as_unsigned_short(client_hello.len()));
300 let mut handshake_protocol = b"\x01".to_vec();
301 handshake_protocol.extend(inner_length);
302 handshake_protocol.extend(client_hello);
303 let outer_length = pack_as_unsigned_short(handshake_protocol.len());
304 payload.extend(outer_length);
305 payload.extend(handshake_protocol);
306 payload
307}
308
309pub fn pack_as_unsigned_char(n: usize) -> u8 {
310 if n >= 256 {
311 panic!("Can't pack_as_unsigned_char {n:?} as it is over 255")
312 }
313 n as u8
314}
315
316pub fn pack_as_unsigned_short(n: usize) -> Vec<u8> {
317 vec![(n >> 8) as u8, n as u8]
318}
319
320pub fn get_ciphers(jarm_details: &PacketSpecification, rng: &dyn JarmRng) -> Vec<u8> {
321 let mut selected_ciphers = Vec::new();
322
323 let mut list = match jarm_details.cipher_list {
324 CipherList::ALL => {
325 vec![b"\x00\x16".to_vec(), b"\x00\x33".to_vec(), b"\x00\x67".to_vec(), b"\xc0\x9e".to_vec(), b"\xc0\xa2".to_vec(), b"\x00\x9e".to_vec(), b"\x00\x39".to_vec(), b"\x00\x6b".to_vec(),
326 b"\xc0\x9f".to_vec(), b"\xc0\xa3".to_vec(), b"\x00\x9f".to_vec(), b"\x00\x45".to_vec(), b"\x00\xbe".to_vec(), b"\x00\x88".to_vec(), b"\x00\xc4".to_vec(), b"\x00\x9a".to_vec(),
327 b"\xc0\x08".to_vec(), b"\xc0\x09".to_vec(), b"\xc0\x23".to_vec(), b"\xc0\xac".to_vec(), b"\xc0\xae".to_vec(), b"\xc0\x2b".to_vec(), b"\xc0\x0a".to_vec(), b"\xc0\x24".to_vec(),
328 b"\xc0\xad".to_vec(), b"\xc0\xaf".to_vec(), b"\xc0\x2c".to_vec(), b"\xc0\x72".to_vec(), b"\xc0\x73".to_vec(), b"\xcc\xa9".to_vec(), b"\x13\x02".to_vec(), b"\x13\x01".to_vec(),
329 b"\xcc\x14".to_vec(), b"\xc0\x07".to_vec(), b"\xc0\x12".to_vec(), b"\xc0\x13".to_vec(), b"\xc0\x27".to_vec(), b"\xc0\x2f".to_vec(), b"\xc0\x14".to_vec(), b"\xc0\x28".to_vec(),
330 b"\xc0\x30".to_vec(), b"\xc0\x60".to_vec(), b"\xc0\x61".to_vec(), b"\xc0\x76".to_vec(), b"\xc0\x77".to_vec(), b"\xcc\xa8".to_vec(), b"\x13\x05".to_vec(), b"\x13\x04".to_vec(),
331 b"\x13\x03".to_vec(), b"\xcc\x13".to_vec(), b"\xc0\x11".to_vec(), b"\x00\x0a".to_vec(), b"\x00\x2f".to_vec(), b"\x00\x3c".to_vec(), b"\xc0\x9c".to_vec(), b"\xc0\xa0".to_vec(),
332 b"\x00\x9c".to_vec(), b"\x00\x35".to_vec(), b"\x00\x3d".to_vec(), b"\xc0\x9d".to_vec(), b"\xc0\xa1".to_vec(), b"\x00\x9d".to_vec(), b"\x00\x41".to_vec(), b"\x00\xba".to_vec(),
333 b"\x00\x84".to_vec(), b"\x00\xc0".to_vec(), b"\x00\x07".to_vec(), b"\x00\x04".to_vec(), b"\x00\x05".to_vec(),
334 ]
335 }
336 CipherList::NO1_3 => {
337 vec![b"\x00\x16".to_vec(), b"\x00\x33".to_vec(), b"\x00\x67".to_vec(), b"\xc0\x9e".to_vec(), b"\xc0\xa2".to_vec(), b"\x00\x9e".to_vec(), b"\x00\x39".to_vec(), b"\x00\x6b".to_vec(),
338 b"\xc0\x9f".to_vec(), b"\xc0\xa3".to_vec(), b"\x00\x9f".to_vec(), b"\x00\x45".to_vec(), b"\x00\xbe".to_vec(), b"\x00\x88".to_vec(), b"\x00\xc4".to_vec(), b"\x00\x9a".to_vec(),
339 b"\xc0\x08".to_vec(), b"\xc0\x09".to_vec(), b"\xc0\x23".to_vec(), b"\xc0\xac".to_vec(), b"\xc0\xae".to_vec(), b"\xc0\x2b".to_vec(), b"\xc0\x0a".to_vec(), b"\xc0\x24".to_vec(),
340 b"\xc0\xad".to_vec(), b"\xc0\xaf".to_vec(), b"\xc0\x2c".to_vec(), b"\xc0\x72".to_vec(), b"\xc0\x73".to_vec(), b"\xcc\xa9".to_vec(), b"\xcc\x14".to_vec(), b"\xc0\x07".to_vec(),
341 b"\xc0\x12".to_vec(), b"\xc0\x13".to_vec(), b"\xc0\x27".to_vec(), b"\xc0\x2f".to_vec(), b"\xc0\x14".to_vec(), b"\xc0\x28".to_vec(), b"\xc0\x30".to_vec(), b"\xc0\x60".to_vec(),
342 b"\xc0\x61".to_vec(), b"\xc0\x76".to_vec(), b"\xc0\x77".to_vec(), b"\xcc\xa8".to_vec(), b"\xcc\x13".to_vec(), b"\xc0\x11".to_vec(), b"\x00\x0a".to_vec(), b"\x00\x2f".to_vec(),
343 b"\x00\x3c".to_vec(), b"\xc0\x9c".to_vec(), b"\xc0\xa0".to_vec(), b"\x00\x9c".to_vec(), b"\x00\x35".to_vec(), b"\x00\x3d".to_vec(), b"\xc0\x9d".to_vec(), b"\xc0\xa1".to_vec(),
344 b"\x00\x9d".to_vec(), b"\x00\x41".to_vec(), b"\x00\xba".to_vec(), b"\x00\x84".to_vec(), b"\x00\xc0".to_vec(), b"\x00\x07".to_vec(), b"\x00\x04".to_vec(), b"\x00\x05".to_vec(),
345 ]
346 }
347 };
348
349 cipher_mung(&mut list, &jarm_details.cipher_order);
350 if jarm_details.use_grease {
351 list.insert(0, rng.random_grease());
352 }
353
354 for x in list {
355 selected_ciphers.extend(x);
356 }
357 selected_ciphers
358}
359
360pub fn get_extensions(jarm_details: &PacketSpecification, rng: &dyn JarmRng) -> Vec<u8> {
361 let mut extension_bytes = Vec::new();
362 let mut all_extensions = Vec::new();
363
364 if jarm_details.use_grease {
365 all_extensions.extend(rng.random_grease());
366 all_extensions.extend(b"\x00\x00");
367 }
368 all_extensions.extend(extension_server_name(jarm_details));
369
370 let extended_master_secret = b"\x00\x17\x00\x00";
372 all_extensions.extend(extended_master_secret);
373 let max_fragment_length = b"\x00\x01\x00\x01\x01";
374 all_extensions.extend(max_fragment_length);
375 let renegotiation_info = b"\xff\x01\x00\x01\x00";
376 all_extensions.extend(renegotiation_info);
377 let supported_groups = b"\x00\x0a\x00\x0a\x00\x08\x00\x1d\x00\x17\x00\x18\x00\x19";
378 all_extensions.extend(supported_groups);
379 let ec_point_formats = b"\x00\x0b\x00\x02\x01\x00";
380 all_extensions.extend(ec_point_formats);
381 let session_ticket = b"\x00\x23\x00\x00";
382 all_extensions.extend(session_ticket);
383
384 all_extensions.extend(aplns(jarm_details));
386 let signature_algorithms = b"\x00\x0d\x00\x14\x00\x12\x04\x03\x08\x04\x04\x01\x05\x03\x08\x05\x05\x01\x08\x06\x06\x01\x02\x01";
387 all_extensions.extend(signature_algorithms);
388
389 all_extensions.extend(key_share(jarm_details.use_grease, rng));
391 let psk_key_exchange_modes = b"\x00\x2d\x00\x02\x01\x01";
392 all_extensions.extend(psk_key_exchange_modes);
393
394 if jarm_details.tls_version == TlsVersion::TLS1_3
395 || jarm_details.tls_version_support == TlsVersionSupport::TLS1_2 {
396 all_extensions.extend(supported_versions(jarm_details, rng));
397 }
398
399 extension_bytes.extend(pack_as_unsigned_short(all_extensions.len()));
400 extension_bytes.extend(all_extensions);
401 extension_bytes
402}
403
404pub fn extension_server_name(jarm_details: &PacketSpecification) -> Vec<u8> {
405 let mut ext_sni = b"\x00\x00".to_vec();
406 let host_length = jarm_details.host.len();
407 let ext_sni_length = host_length + 5;
408 ext_sni.extend(pack_as_unsigned_short(ext_sni_length));
409
410 let ext_sni_length2 = host_length + 3;
411 ext_sni.extend(pack_as_unsigned_short(ext_sni_length2));
412 ext_sni.push(b'\x00');
413
414 let ext_sni_length3 = host_length;
415 ext_sni.extend(pack_as_unsigned_short(ext_sni_length3));
416
417 ext_sni.extend(jarm_details.host.bytes());
418 ext_sni
419}
420
421pub fn aplns(jarm_details: &PacketSpecification) -> Vec<u8> {
423 let mut ext = b"\x00\x10".to_vec();
424 let mut alpns: Vec<Vec<u8>> = if jarm_details.use_rare_apln {
425 vec![
426 b"\x08\x68\x74\x74\x70\x2f\x30\x2e\x39".to_vec(),
427 b"\x08\x68\x74\x74\x70\x2f\x31\x2e\x30".to_vec(),
428 b"\x06\x73\x70\x64\x79\x2f\x31".to_vec(),
429 b"\x06\x73\x70\x64\x79\x2f\x32".to_vec(),
430 b"\x06\x73\x70\x64\x79\x2f\x33".to_vec(),
431 b"\x03\x68\x32\x63".to_vec(),
432 b"\x02\x68\x71".to_vec(),
433 ]
434 } else {
435 vec![
436 b"\x08\x68\x74\x74\x70\x2f\x30\x2e\x39".to_vec(),
437 b"\x08\x68\x74\x74\x70\x2f\x31\x2e\x30".to_vec(),
438 b"\x08\x68\x74\x74\x70\x2f\x31\x2e\x31".to_vec(),
439 b"\x06\x73\x70\x64\x79\x2f\x31".to_vec(),
440 b"\x06\x73\x70\x64\x79\x2f\x32".to_vec(),
441 b"\x06\x73\x70\x64\x79\x2f\x33\x02\x68\x32".to_vec(),
442 b"\x03\x68\x32\x63".to_vec(),
443 b"\x02\x68\x71".to_vec()
444 ]
445 };
446
447 cipher_mung(&mut alpns, &jarm_details.extension_order);
448
449 let mut all_alpns = Vec::new();
451 for alpn in alpns {
452 all_alpns.extend(alpn);
453 }
454
455 let second_length = all_alpns.len();
456 let first_length = second_length + 2;
457 ext.extend(pack_as_unsigned_short(first_length));
458 ext.extend(pack_as_unsigned_short(second_length));
459 ext.extend(all_alpns);
460 ext
461}
462
463pub fn cipher_mung(ciphers: &mut Vec<Vec<u8>>, cipher_order: &CipherOrder) {
464 match cipher_order {
465 CipherOrder::FORWARD => {} CipherOrder::REVERSE => { ciphers.reverse() }
467 CipherOrder::TOP_HALF => {
468 let middle_one = if ciphers.len() % 2 == 1 {
470 Some(ciphers[ciphers.len() / 2].clone())
471 } else {
472 None
473 };
474 cipher_mung(ciphers, &CipherOrder::REVERSE);
475 cipher_mung(ciphers, &CipherOrder::BOTTOM_HALF);
476
477 if let Some(x) = middle_one {
478 ciphers.insert(0, x);
479 }
480 }
481 CipherOrder::BOTTOM_HALF => {
482 let mut range_to_drain = 0..ciphers.len() / 2;
483 if ciphers.len() % 2 == 1 {
484 range_to_drain.end += 1;
486 }
487 ciphers.drain(range_to_drain);
488
489 }
490 CipherOrder::MIDDLE_OUT => {
491 let middle = ciphers.len() / 2;
492 let mut output = Vec::new();
493 if ciphers.len() % 2 == 1 {
494 output.push(ciphers[middle].clone());
496
497 for i in 1..middle+1 {
498 output.push(ciphers[middle + i].clone());
499 output.push(ciphers[middle - i].clone());
500 }
501 } else {
502 for i in 1..middle+1 {
503 output.push(ciphers[middle - 1 + i].clone());
504 output.push(ciphers[middle - i].clone());
505 }
506 }
507 *ciphers = output;
508 }
509 }
510}
511
512pub fn key_share(grease: bool, rng: &dyn JarmRng) -> Vec<u8> {
513 let mut ext = b"\x00\x33".to_vec();
514
515 let mut share_ext = if grease {
516 let mut grease_start = rng.random_grease();
517 grease_start.extend(b"\x00\x01\x00");
518 grease_start
519 } else {
520 Vec::new()
521 };
522 share_ext.extend(b"\x00\x1d"); share_ext.extend(b"\x00\x20"); share_ext.extend(rng.random_bytes()); let second_length = share_ext.len();
527 let first_length = second_length + 2;
528 ext.extend(pack_as_unsigned_short(first_length));
529 ext.extend(pack_as_unsigned_short(second_length));
530 ext.extend(share_ext);
531 ext
532}
533
534pub fn supported_versions(jarm_details: &PacketSpecification, rng: &dyn JarmRng) -> Vec<u8> {
535 let mut tls = if jarm_details.tls_version_support == TlsVersionSupport::TLS1_2 {
536 vec![b"\x03\x01".to_vec(), b"\x03\x02".to_vec(), b"\x03\x03".to_vec()]
537 } else { vec![b"\x03\x01".to_vec(), b"\x03\x02".to_vec(), b"\x03\x03".to_vec(), b"\x03\x04".to_vec()]
539 };
540 cipher_mung(&mut tls, &jarm_details.extension_order);
541
542 let mut ext = b"\x00\x2b".to_vec();
544 let mut versions = if jarm_details.use_grease {
545 rng.random_grease()
546 } else {
547 Vec::new()
548 };
549
550 for version in tls {
551 versions.extend(version);
552 }
553
554 let second_length = versions.len();
555 let first_length = second_length + 1;
556 ext.extend(pack_as_unsigned_short(first_length));
557 ext.push(pack_as_unsigned_char(second_length));
558 ext.extend(versions);
559 ext
560}
561
562pub fn read_packet(data: Vec<u8>) -> JarmPart {
563 if (data[0] != 22) || (data[5] != 2){
564 return JarmPart::new("|||"); }
566
567 let mut jarm = String::new();
568 let counter = data[43] as usize;
569
570 let start = counter + 44;
572 let end = counter + 45;
573 let selected_cipher = &data[start..=end];
574
575 let version = &data[9..=10];
577
578 jarm += &*hex::encode(selected_cipher);
580 jarm += "|";
581 jarm += &*hex::encode(version);
582 jarm += "|";
583
584 let extensions = extract_extension_info(data, counter);
586 jarm += &*extensions;
587 JarmPart { raw: jarm}
588}
589
590pub fn as_u32_be(array: &[u8]) -> u32 {
592 if array.len() != 2 {
593 eprintln!("array = {array:?}");
594 unimplemented!() }
596 ((array[0] as u32) << 8) + (array[1] as u32)
597}
598
599pub fn extract_extension_info(data: Vec<u8>, counter: usize) -> String {
600 if data_has_errors(&data, counter) {
602 return "|".to_string();
603 }
604
605 let mut count = 49 + (counter as u32);
607 let length_start = counter + 47;
608 let length_end = counter + 48;
609
610 let length_slice: &[u8] = &data[length_start..=length_end];
611 let length = as_u32_be(length_slice);
612 let maximum = length + (count - 1);
613
614 let mut types: Vec<&[u8]> = Vec::new();
615 let mut values: Vec<Option<&[u8]>> = Vec::new();
616
617 while count < maximum {
618 let slice_start = count as usize;
619 types.push(&data[slice_start..slice_start+2]);
620
621 let ext_length_start = (count + 2) as usize;
622 let ext_length_end = ext_length_start + 2;
623 let ext_length_slice: &[u8] = &data[ext_length_start..ext_length_end];
624 let ext_length = as_u32_be(ext_length_slice);
625
626 if ext_length == 0 {
627 values.push(None); count += 4;
629 } else {
630 let value = &data[slice_start + 4..slice_start + 4 + ext_length as usize];
631 values.push(Some(value));
632 count += ext_length + 4
633 }
634 }
635
636 let alpn = find_extension(&types, values);
638
639 let formatted_types = add_formatting_hyphen(&types);
640 format!("{alpn}|{formatted_types}")
641}
642
643fn data_has_errors(data: &[u8], counter: usize) -> bool {
644 let length_start = counter + 47;
645 if data[length_start] == 11 {
646 return true;
647 }
648 if data[(counter + 50)..(counter + 53)] == b"\x0e\xac\x0b".to_vec() ||
649 data[(counter + 82)..(counter + 85)] == b"\x0f\xf0\x0b".to_vec() {
650 return true;
651 }
652 let server_hello_length_slice: &[u8] = &data[3..5];
653 let server_hello_length = as_u32_be(server_hello_length_slice);
654 if (counter as u32) + 42 >= server_hello_length {
655 return true;
656 }
657 false
658}
659
660pub fn add_formatting_hyphen(types: &[&[u8]]) -> String {
661 let types_hex_encoded: Vec<String> = types.iter().map(hex::encode).collect();
662 types_hex_encoded.join("-")
663}
664
665
666pub fn find_extension(types: &[&[u8]], values: Vec<Option<&[u8]>>) -> String {
667 let mut i = 0;
668 while i < types.len() {
669 if types.get(i).unwrap() == ALPN_EXTENSION {
670 let x = values.get(i).unwrap();
671 match x {
672 None => {}
673 Some(y) => {
674 match std::str::from_utf8(&y[3..]) {
675 Ok(s) => return s.to_string(),
676 Err(e) => panic!("Invalid UTF-8 sequence: {e}"),
677 };
678 }
679 }
680 }
681 i += 1
682 }
683 "".to_string()
684}
685
686pub fn cipher_bytes(cipher: &str) -> String {
687 if cipher.is_empty() {
688 return "00".to_string()
689 }
690
691 let list = vec![
692 b"\x00\x04", b"\x00\x05", b"\x00\x07", b"\x00\x0a", b"\x00\x16", b"\x00\x2f", b"\x00\x33", b"\x00\x35",
693 b"\x00\x39", b"\x00\x3c", b"\x00\x3d", b"\x00\x41", b"\x00\x45", b"\x00\x67", b"\x00\x6b", b"\x00\x84",
694 b"\x00\x88", b"\x00\x9a", b"\x00\x9c", b"\x00\x9d", b"\x00\x9e", b"\x00\x9f", b"\x00\xba", b"\x00\xbe",
695 b"\x00\xc0", b"\x00\xc4", b"\xc0\x07", b"\xc0\x08", b"\xc0\x09", b"\xc0\x0a", b"\xc0\x11", b"\xc0\x12",
696 b"\xc0\x13", b"\xc0\x14", b"\xc0\x23", b"\xc0\x24", b"\xc0\x27", b"\xc0\x28", b"\xc0\x2b", b"\xc0\x2c",
697 b"\xc0\x2f", b"\xc0\x30", b"\xc0\x60", b"\xc0\x61", b"\xc0\x72", b"\xc0\x73", b"\xc0\x76", b"\xc0\x77",
698 b"\xc0\x9c", b"\xc0\x9d", b"\xc0\x9e", b"\xc0\x9f", b"\xc0\xa0", b"\xc0\xa1", b"\xc0\xa2", b"\xc0\xa3",
699 b"\xc0\xac", b"\xc0\xad", b"\xc0\xae", b"\xc0\xaf", b"\xcc\x13", b"\xcc\x14", b"\xcc\xa8", b"\xcc\xa9",
700 b"\x13\x01", b"\x13\x02", b"\x13\x03", b"\x13\x04", b"\x13\x05"
701 ];
702 let count = match list.iter().position(|&bytes| hex::encode(bytes) == cipher) {
703 None => { list.len() + 1 }
704 Some(index) => { index + 1 }
705 };
706
707 let hex_value = hex::encode(count.to_be_bytes());
708 hex_value.get(hex_value.len() - 2..hex_value.len()).unwrap().to_string()
709}
710
711pub fn version_byte(version: &str) -> char {
712 if version.is_empty() {
713 return '0';
714 }
715 let option = "abcdef".to_string();
716 let version_index: usize = 3;
717 let count: usize = match version.get(version_index..version_index+1) {
718 None => { panic!("version not expected {version:?}")}
719 Some(str_count) => { usize::from_str(str_count).unwrap() }
720 };
721 option.chars().nth(count).unwrap()
722}
723
724
725fn resolve(url: String) -> Result<SocketAddr, JarmError> {
728 let mut ips = match url.to_socket_addrs() {
729 Ok(address) => address,
730 Err(e) => {
731 let error = DetailedError::from(Box::from(e));
732 return Err(JarmError::DnsResolve(error))
733 },
734 };
735 if let Some(address) = ips.next() {
736 Ok(address)
737 } else {
738 Err(JarmError::DnsResolve(DetailedError::default()))
739 }
740}
741
742
743pub trait JarmRng {
744 fn random_bytes(&self) -> Vec<u8>;
745
746 fn random_grease(&self) -> Vec<u8>;
747}
748
749pub struct PseudoRng {}
750
751pub struct TestRng {}
752
753impl JarmRng for TestRng { fn random_bytes(&self) -> Vec<u8> {
755 vec![42; 32]
756 }
757
758 fn random_grease(&self) -> Vec<u8> {
759 b"\x0a\x0a".to_vec()
760 }
761}
762
763#[cfg(not(tarpaulin_include))] impl JarmRng for PseudoRng { fn random_bytes(&self) -> Vec<u8> {
766 let mut rng = rand::rng();
767 rng.random::<[u8; 32]>().to_vec()
768 }
769
770 fn random_grease(&self) -> Vec<u8> {
771 let grease_list = vec![
772 b"\x0a\x0a".to_vec(),
773 b"\x1a\x1a".to_vec(),
774 b"\x2a\x2a".to_vec(),
775 b"\x3a\x3a".to_vec(),
776 b"\x4a\x4a".to_vec(),
777 b"\x5a\x5a".to_vec(),
778 b"\x6a\x6a".to_vec(),
779 b"\x7a\x7a".to_vec(),
780 b"\x8a\x8a".to_vec(),
781 b"\x9a\x9a".to_vec(),
782 b"\xaa\xaa".to_vec(),
783 b"\xba\xba".to_vec(),
784 b"\xca\xca".to_vec(),
785 b"\xda\xda".to_vec(),
786 b"\xea\xea".to_vec(),
787 b"\xfa\xfa".to_vec(),
788 ];
789 grease_list.choose(&mut rand::rng()).unwrap().clone()
790 }
791}
792
793#[cfg(test)]
794mod tests {
795 use rstest::*;
796 use crate::resolve;
797 use crate::error::JarmError;
798
799 #[rstest]
800 #[case("invalid_url")]
801 #[case("google.com")] fn test_dns_resolve_error(#[case] invalid_url: String) {
803 let expected_error = "invalid socket address";
804 let error = resolve(invalid_url).err().unwrap();
805 if let JarmError::DnsResolve(err) = error {
806 let underlying_error = err.underlying_error.unwrap();
807 assert_eq!(underlying_error.to_string(), expected_error);
808 } else { panic!("unexpected type") }
809 }
810}