This is an automated email from the ASF dual-hosted git repository.

jvanderzee pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/trafficserver.git


The following commit(s) were added to refs/heads/master by this push:
     new ff657c7348 Fix JA4 TLS version encoding (#11678)
ff657c7348 is described below

commit ff657c73488c894382bb2175cb40f2a3ae71fbc2
Author: JosiahWI <[email protected]>
AuthorDate: Thu Aug 15 12:01:15 2024 -0500

    Fix JA4 TLS version encoding (#11678)
    
    * Fix JA4 version encoding
    
    The JA4 specification gives a table of which versions are recognized and 
what
    strings should be generated for them. The JA4 module incorrectly takes the
    digits of the version instead of using the string given by the 
specification.
    This fixes it to match up with the spec.
---
 plugins/experimental/ja4_fingerprint/ja4.cc      | 40 ++++++++++++++++--------
 plugins/experimental/ja4_fingerprint/ja4.h       |  8 ++---
 plugins/experimental/ja4_fingerprint/test_ja4.cc | 35 +++++++++++++++------
 3 files changed, 57 insertions(+), 26 deletions(-)

diff --git a/plugins/experimental/ja4_fingerprint/ja4.cc 
b/plugins/experimental/ja4_fingerprint/ja4.cc
index bab4b64273..bb68485ac8 100644
--- a/plugins/experimental/ja4_fingerprint/ja4.cc
+++ b/plugins/experimental/ja4_fingerprint/ja4.cc
@@ -27,14 +27,14 @@
 #include <algorithm>
 #include <cctype>
 #include <cstddef>
+#include <cstdint>
 #include <cstdio>
 #include <iterator>
 #include <string>
 #include <string_view>
 
 static char        convert_protocol_to_char(JA4::Protocol protocol);
-static std::string convert_TLS_version_to_string(std::string_view TLS_version);
-static std::string filter_only_digits(std::string_view src);
+static std::string convert_TLS_version_to_string(std::uint16_t TLS_version);
 static char        convert_SNI_to_char(JA4::SNI SNI_type);
 static std::string convert_count_to_two_digit_string(std::size_t count);
 static std::string convert_ALPN_to_two_char_string(std::string_view ALPN);
@@ -67,18 +67,32 @@ convert_protocol_to_char(JA4::Protocol protocol)
 }
 
 static std::string
-convert_TLS_version_to_string(std::string_view TLS_version)
+convert_TLS_version_to_string(std::uint16_t TLS_version)
 {
-  std::string result{filter_only_digits(TLS_version)};
-  return result.empty() ? "  " : result;
-}
-
-static std::string
-filter_only_digits(std::string_view src)
-{
-  std::string result{};
-  std::copy_if(src.begin(), src.end(), std::back_inserter(result), [](unsigned 
char c) { return std::isdigit(c); });
-  return result;
+  switch (TLS_version) {
+  case 0x304:
+    return "13";
+  case 0x303:
+    return "12";
+  case 0x302:
+    return "11";
+  case 0x301:
+    return "10";
+  case 0x300:
+    return "s3";
+  case 0x200:
+    return "s2";
+  case 0x100:
+    return "s1";
+  case 0xfeff:
+    return "d1";
+  case 0xfefd:
+    return "d2";
+  case 0xfefc:
+    return "d3";
+  default:
+    return "00";
+  }
 }
 
 static char
diff --git a/plugins/experimental/ja4_fingerprint/ja4.h 
b/plugins/experimental/ja4_fingerprint/ja4.h
index 241b5de400..1c81bd2e52 100644
--- a/plugins/experimental/ja4_fingerprint/ja4.h
+++ b/plugins/experimental/ja4_fingerprint/ja4.h
@@ -53,10 +53,10 @@ class TLSClientHelloSummary
 public:
   using difference_type = 
std::iterator_traits<std::vector<std::uint16_t>::iterator>::difference_type;
 
-  Protocol    protocol;
-  SNI         SNI_type;
-  std::string TLS_version;
-  std::string ALPN;
+  Protocol      protocol;
+  SNI           SNI_type;
+  std::uint16_t TLS_version;
+  std::string   ALPN;
 
   std::vector<std::uint16_t> const &get_ciphers() const;
   void                              add_cipher(std::uint16_t cipher);
diff --git a/plugins/experimental/ja4_fingerprint/test_ja4.cc 
b/plugins/experimental/ja4_fingerprint/test_ja4.cc
index 32be140735..b0a7f650d1 100644
--- a/plugins/experimental/ja4_fingerprint/test_ja4.cc
+++ b/plugins/experimental/ja4_fingerprint/test_ja4.cc
@@ -31,6 +31,7 @@
 #include <cctype>
 #include <string>
 #include <string_view>
+#include <unordered_map>
 
 static std::string call_JA4(JA4::TLSClientHelloSummary const &TLS_summary);
 static std::string inc(std::string_view sv);
@@ -64,20 +65,36 @@ TEST_CASE("JA4")
     CHECK(call_JA4(TLS_summary).starts_with('d'));
   }
 
-  SECTION("Given the TLS version is 1.2, "
+  SECTION("Given the TLS version is unknown, "
           "when we create a JA4 fingerprint, "
-          "then indices [1,2] thereof should be \"12\".")
+          "then indices [1,2] thereof should contain \"00\".")
   {
-    TLS_summary.TLS_version = "1.2";
-    CHECK("12" == call_JA4(TLS_summary).substr(1, 2));
+    TLS_summary.TLS_version = 0x123;
+    CHECK("00" == call_JA4(TLS_summary).substr(1, 2));
+    TLS_summary.TLS_version = 0x234;
+    CHECK("00" == call_JA4(TLS_summary).substr(1, 2));
   }
 
-  SECTION("Given the TLS version is 1.2, "
+  SECTION("Given the TLS version is known, "
           "when we create a JA4 fingerprint, "
-          "then indices [1,2] thereof should contain \"13\".")
-  {
-    TLS_summary.TLS_version = "1.3";
-    CHECK("13" == call_JA4(TLS_summary).substr(1, 2));
+          "then indices [1,2] thereof should contain the correct value.")
+  {
+    std::unordered_map<std::uint16_t, std::string> values{
+      {0x304,  "13"},
+      {0x303,  "12"},
+      {0x302,  "11"},
+      {0x301,  "10"},
+      {0x300,  "s3"},
+      {0x200,  "s2"},
+      {0x100,  "s1"},
+      {0xfeff, "d1"},
+      {0xfefd, "d2"},
+      {0xfefc, "d3"}
+    };
+    for (auto const &[version, expected] : values) {
+      TLS_summary.TLS_version = version;
+      CHECK(expected == call_JA4(TLS_summary).substr(1, 2));
+    }
   }
 
   SECTION("Given the SNI is a domain name, "

Reply via email to