ja4: handles non alphanumeric alpn

Ticket: 7267

Follows more closely the specification :
https://github.com/FoxIO-LLC/ja4/blob/main/technical_details/JA4.md#alpn-extension-value

Also fixes the case with a single-char alpn.
pull/11852/head
Philippe Antoine 5 months ago committed by Victor Julien
parent 9203656496
commit 1e152d1f10

@ -27,6 +27,8 @@ use sha2::Sha256;
use std::cmp::min;
use std::os::raw::c_char;
use tls_parser::{TlsCipherSuiteID, TlsExtensionType, TlsVersion};
#[cfg(feature = "ja4")]
use crate::jsonbuilder::HEX;
#[derive(Debug, PartialEq)]
pub struct JA4 {
@ -137,7 +139,8 @@ impl JA4 {
}
pub fn set_alpn(&mut self, alpn: &[u8]) {
if alpn.len() > 1 {
if !alpn.is_empty() {
// If the first ALPN value is only a single character, then that character is treated as both the first and last character.
if alpn.len() == 2 {
// GREASE values are 2 bytes, so this could be one -- check
let v: u16 = (alpn[0] as u16) << 8 | alpn[alpn.len() - 1] as u16;
@ -145,6 +148,12 @@ impl JA4 {
return;
}
}
if !alpn[0].is_ascii_alphanumeric() || !alpn[alpn.len() - 1].is_ascii_alphanumeric() {
// If the first or last byte of the first ALPN is non-alphanumeric (meaning not 0x30-0x39, 0x41-0x5A, or 0x61-0x7A), then we print the first and last characters of the hex representation of the first ALPN instead.
self.alpn[0] = char::from(HEX[(alpn[0] >> 4) as usize]);
self.alpn[1] = char::from(HEX[(alpn[alpn.len() - 1] & 0xF) as usize]);
return
}
self.alpn[0] = char::from(alpn[0]);
self.alpn[1] = char::from(alpn[alpn.len() - 1]);
}
@ -322,15 +331,41 @@ mod tests {
fn test_short_alpn() {
let mut j = JA4::new();
j.set_alpn("a".as_bytes());
j.set_alpn("b".as_bytes());
let mut s = j.get_hash();
s.truncate(10);
assert_eq!(s, "t00i0000bb");
j.set_alpn("h2".as_bytes());
let mut s = j.get_hash();
s.truncate(10);
assert_eq!(s, "t00i0000h2");
// from https://github.com/FoxIO-LLC/ja4/blob/main/technical_details/JA4.md#alpn-extension-value
j.set_alpn(&[0xab]);
let mut s = j.get_hash();
s.truncate(10);
assert_eq!(s, "t00i0000ab");
j.set_alpn(&[0xab, 0xcd]);
let mut s = j.get_hash();
s.truncate(10);
assert_eq!(s, "t00i0000ad");
j.set_alpn(&[0x30, 0xab]);
let mut s = j.get_hash();
s.truncate(10);
assert_eq!(s, "t00i00003b");
j.set_alpn(&[0x30, 0x31, 0xab, 0xcd]);
let mut s = j.get_hash();
s.truncate(10);
assert_eq!(s, "t00i000000");
assert_eq!(s, "t00i00003d");
j.set_alpn("aa".as_bytes());
j.set_alpn(&[0x30, 0xab, 0xcd, 0x31]);
let mut s = j.get_hash();
s.truncate(10);
assert_eq!(s, "t00i0000aa");
assert_eq!(s, "t00i000001");
}
#[test]

Loading…
Cancel
Save