]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
ja3: make feature compile time configurable
authorSascha Steinbiss <satta@debian.org>
Fri, 12 Apr 2024 17:54:23 +0000 (19:54 +0200)
committerJeff Lucovsky <jlucovsky@oisf.net>
Sat, 8 Jun 2024 13:36:46 +0000 (09:36 -0400)
(cherry picked from commit 9d0db71ebf65919215b9e09a1b8fbbbc27560388)

14 files changed:
configure.ac
rust/Cargo.toml.in
rust/Makefile.am
rust/src/quic/frames.rs
rust/src/quic/quic.rs
src/app-layer-ssl.c
src/detect-tls-ja3-hash.c
src/detect-tls-ja3-string.c
src/detect-tls-ja3s-hash.c
src/detect-tls-ja3s-string.c
src/feature.h
src/suricata.c
src/util-ja3.c
src/util-ja3.h

index 04305ecd95cdd587e6ffbd7b863c61384d0ed0ed..74ab6fd38329a7b9f9769313abdef3dc7d8a70c2 100644 (file)
         fi
     fi
 
+    AC_ARG_ENABLE(ja3,
+           AS_HELP_STRING([--disable-ja3], [Disable JA3 support]),
+           [enable_ja3="$enableval"],
+           [enable_ja3=yes])
+    if test "$enable_ja3" = "yes"; then
+        AC_DEFINE([HAVE_JA3],[1],[JA3 enabled])
+        enable_ja3="yes"
+    fi
+    AM_CONDITIONAL([HAVE_JA3], [test "x$enable_ja3" != "xno"])
+
 # Check for lz4
 enable_liblz4="yes"
 AC_CHECK_LIB(lz4, LZ4F_createCompressionContext, , enable_liblz4="no")
@@ -2657,6 +2667,7 @@ SURICATA_BUILD_CONF="Suricata Configuration:
   LUA support:                             ${enable_lua}
   libluajit:                               ${enable_luajit}
   GeoIP2 support:                          ${enable_geoip}
+  JA3 support:                             ${enable_ja3}
   Non-bundled htp:                         ${enable_non_bundled_htp}
   Hyperscan support:                       ${enable_hyperscan}
   Libnet support:                          ${enable_libnet}
index 347391bf671c6c2dcb2102f5b511f92ccfda8584..9c0d3b82bef76d661ca7d25fcaccb3e51c61100f 100644 (file)
@@ -21,6 +21,7 @@ lua_int8 = ["lua"]
 strict = []
 debug = []
 debug-validate = []
+ja3 = []
 
 [dependencies]
 nom7 = { version="7.0", package="nom" }
index 2857288fefa311fdaa895f418fee2eff5fe09565..fb172f993ee257c98c2ea3b1427f94349aa030bf 100644 (file)
@@ -16,6 +16,10 @@ if HAVE_LUA
 RUST_FEATURES +=       lua $(LUA_INT8)
 endif
 
+if HAVE_JA3
+RUST_FEATURES +=       ja3
+endif
+
 if DEBUG
 RUST_FEATURES +=       debug
 endif
index e1fb7d0807278a680d66b597bdac1f49455d50ca..d432c79d12531475a551d3e248ab0985d230fb95 100644 (file)
@@ -136,7 +136,7 @@ pub(crate) struct Crypto {
     // We remap the Vec<TlsExtension> from tls_parser::parse_tls_extensions because of
     // the lifetime of TlsExtension due to references to the slice used for parsing
     pub extv: Vec<QuicTlsExtension>,
-    pub ja3: String,
+    pub ja3: Option<String>,
 }
 
 #[derive(Debug, PartialEq)]
@@ -296,7 +296,15 @@ fn parse_quic_handshake(msg: TlsMessage) -> Option<Frame> {
                 ja3.push(',');
                 let ciphers = ch.ciphers;
                 let extv = quic_get_tls_extensions(ch.ext, &mut ja3, true);
-                return Some(Frame::Crypto(Crypto { ciphers, extv, ja3 }));
+                return Some(Frame::Crypto(Crypto {
+                    ciphers,
+                    extv,
+                    ja3: if cfg!(feature = "ja3") {
+                        Some(ja3)
+                    } else {
+                        None
+                    },
+                }));
             }
             ServerHello(sh) => {
                 let mut ja3 = String::with_capacity(256);
@@ -306,7 +314,15 @@ fn parse_quic_handshake(msg: TlsMessage) -> Option<Frame> {
                 ja3.push(',');
                 let ciphers = vec![sh.cipher];
                 let extv = quic_get_tls_extensions(sh.ext, &mut ja3, false);
-                return Some(Frame::Crypto(Crypto { ciphers, extv, ja3 }));
+                return Some(Frame::Crypto(Crypto {
+                    ciphers,
+                    extv,
+                    ja3: if cfg!(feature = "ja3") {
+                        Some(ja3)
+                    } else {
+                        None
+                    },
+                }));
             }
             _ => {}
         }
index ec24ab81ee219efb229aac1ee99de29f59aed31f..147bcf0416b8ba1971b2f814f87ce3622a1d33b2 100644 (file)
@@ -230,7 +230,9 @@ impl QuicState {
                     }
                 }
                 Frame::Crypto(c) => {
-                    ja3 = Some(c.ja3.clone());
+                    if let Some(ja3str) = &c.ja3 {
+                        ja3 = Some(ja3str.clone());
+                    }
                     for e in &c.extv {
                         if e.etype == TlsExtensionType::ServerName && !e.values.is_empty() {
                             sni = Some(e.values[0].to_vec());
index 302225f1903d76aefbd6e5c151502fc53d9b285c..2bde7de096e27d6b8155f539326e066abdc9b71a 100644 (file)
@@ -43,6 +43,8 @@
 #include "decode-events.h"
 #include "conf.h"
 
+#include "feature.h"
+
 #include "util-spm.h"
 #include "util-unittest.h"
 #include "util-debug.h"
@@ -2950,6 +2952,31 @@ static int SSLRegisterPatternsForProtocolDetection(void)
     return 0;
 }
 
+#ifdef HAVE_JA3
+static void CheckJA3Enabled(void)
+{
+    const char *strval = NULL;
+    /* Check if we should generate JA3 fingerprints */
+    int enable_ja3 = SSL_CONFIG_DEFAULT_JA3;
+    if (ConfGet("app-layer.protocols.tls.ja3-fingerprints", &strval) != 1) {
+        enable_ja3 = SSL_CONFIG_DEFAULT_JA3;
+    } else if (strcmp(strval, "auto") == 0) {
+        enable_ja3 = SSL_CONFIG_DEFAULT_JA3;
+    } else if (ConfValIsFalse(strval)) {
+        enable_ja3 = 0;
+        ssl_config.disable_ja3 = true;
+    } else if (ConfValIsTrue(strval)) {
+        enable_ja3 = true;
+    }
+    SC_ATOMIC_SET(ssl_config.enable_ja3, enable_ja3);
+    if (!ssl_config.disable_ja3 && !g_disable_hashing) {
+        /* The feature is available, i.e. _could_ be activated by a rule or
+           even is enabled in the configuration. */
+        ProvidesFeature(FEATURE_JA3);
+    }
+}
+#endif /* HAVE_JA3 */
+
 /**
  * \brief Function to register the SSL protocol parser and other functions
  */
@@ -3049,20 +3076,9 @@ void RegisterSSLParsers(void)
         }
         SCLogDebug("ssl_config.encrypt_mode %u", ssl_config.encrypt_mode);
 
-        /* Check if we should generate JA3 fingerprints */
-        int enable_ja3 = SSL_CONFIG_DEFAULT_JA3;
-        const char *strval = NULL;
-        if (ConfGet("app-layer.protocols.tls.ja3-fingerprints", &strval) != 1) {
-            enable_ja3 = SSL_CONFIG_DEFAULT_JA3;
-        } else if (strcmp(strval, "auto") == 0) {
-            enable_ja3 = SSL_CONFIG_DEFAULT_JA3;
-        } else if (ConfValIsFalse(strval)) {
-            enable_ja3 = 0;
-            ssl_config.disable_ja3 = true;
-        } else if (ConfValIsTrue(strval)) {
-            enable_ja3 = true;
-        }
-        SC_ATOMIC_SET(ssl_config.enable_ja3, enable_ja3);
+#ifdef HAVE_JA3
+        CheckJA3Enabled();
+#endif /* HAVE_JA3 */
 
         if (g_disable_hashing) {
             if (SC_ATOMIC_GET(ssl_config.enable_ja3)) {
@@ -3071,7 +3087,9 @@ void RegisterSSLParsers(void)
             }
         } else {
             if (RunmodeIsUnittests()) {
+#ifdef HAVE_JA3
                 SC_ATOMIC_SET(ssl_config.enable_ja3, 1);
+#endif /* HAVE_JA3 */
             }
         }
     } else {
index 7660fde4c2a07227f272bb32787adbdfe39bcfc2..8ac08a0807ea467f47916be8db30ce2388587d87 100644 (file)
 #include "util-unittest.h"
 #include "util-unittest-helper.h"
 
+#ifndef HAVE_JA3
+static int DetectJA3SetupNoSupport(DetectEngineCtx *a, Signature *b, const char *c)
+{
+    SCLogError("no JA3 support built in");
+    return -1;
+}
+#endif
+
 static int DetectTlsJa3HashSetup(DetectEngineCtx *, Signature *, const char *);
 static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx,
        const DetectEngineTransforms *transforms,
@@ -76,10 +84,15 @@ void DetectTlsJa3HashRegister(void)
     sigmatch_table[DETECT_AL_TLS_JA3_HASH].alias = "ja3_hash";
     sigmatch_table[DETECT_AL_TLS_JA3_HASH].desc = "sticky buffer to match the JA3 hash buffer";
     sigmatch_table[DETECT_AL_TLS_JA3_HASH].url = "/rules/ja3-keywords.html#ja3-hash";
+#ifdef HAVE_JA3
     sigmatch_table[DETECT_AL_TLS_JA3_HASH].Setup = DetectTlsJa3HashSetup;
+#else  /* HAVE_JA3 */
+    sigmatch_table[DETECT_AL_TLS_JA3_HASH].Setup = DetectJA3SetupNoSupport;
+#endif /* HAVE_JA3 */
     sigmatch_table[DETECT_AL_TLS_JA3_HASH].flags |= SIGMATCH_NOOPT;
     sigmatch_table[DETECT_AL_TLS_JA3_HASH].flags |= SIGMATCH_INFO_STICKY_BUFFER;
 
+#ifdef HAVE_JA3
     DetectAppLayerInspectEngineRegister2("ja3.hash", ALPROTO_TLS, SIG_FLAG_TOSERVER, 0,
             DetectEngineInspectBufferGeneric, GetData);
 
@@ -101,6 +114,7 @@ void DetectTlsJa3HashRegister(void)
             DetectTlsJa3HashValidateCallback);
 
     g_tls_ja3_hash_buffer_id = DetectBufferTypeGetByName("ja3.hash");
+#endif /* HAVE_JA3 */
 }
 
 /**
index 87a61bfd873879729b7547a2cf7bda60fa997965..5f718ac352e7f931d3e09aaf9312eb8c86827904 100644 (file)
 #include "util-unittest.h"
 #include "util-unittest-helper.h"
 
+#ifndef HAVE_JA3
+static int DetectJA3SetupNoSupport(DetectEngineCtx *a, Signature *b, const char *c)
+{
+    SCLogError("no JA3 support built in");
+    return -1;
+}
+#endif /* HAVE_JA3 */
+
 static int DetectTlsJa3StringSetup(DetectEngineCtx *, Signature *, const char *);
 static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx,
        const DetectEngineTransforms *transforms,
@@ -72,10 +80,15 @@ void DetectTlsJa3StringRegister(void)
     sigmatch_table[DETECT_AL_TLS_JA3_STRING].alias = "ja3_string";
     sigmatch_table[DETECT_AL_TLS_JA3_STRING].desc = "sticky buffer to match the JA3 string buffer";
     sigmatch_table[DETECT_AL_TLS_JA3_STRING].url = "/rules/ja3-keywords.html#ja3-string";
+#ifdef HAVE_JA3
     sigmatch_table[DETECT_AL_TLS_JA3_STRING].Setup = DetectTlsJa3StringSetup;
+#else  /* HAVE_JA3 */
+    sigmatch_table[DETECT_AL_TLS_JA3_STRING].Setup = DetectJA3SetupNoSupport;
+#endif /* HAVE_JA3 */
     sigmatch_table[DETECT_AL_TLS_JA3_STRING].flags |= SIGMATCH_NOOPT;
     sigmatch_table[DETECT_AL_TLS_JA3_STRING].flags |= SIGMATCH_INFO_STICKY_BUFFER;
 
+#ifdef HAVE_JA3
     DetectAppLayerInspectEngineRegister2("ja3.string", ALPROTO_TLS, SIG_FLAG_TOSERVER, 0,
             DetectEngineInspectBufferGeneric, GetData);
 
@@ -91,6 +104,7 @@ void DetectTlsJa3StringRegister(void)
     DetectBufferTypeSetDescriptionByName("ja3.string", "TLS JA3 string");
 
     g_tls_ja3_str_buffer_id = DetectBufferTypeGetByName("ja3.string");
+#endif /* HAVE_JA3 */
 }
 
 /**
index 583566012d08cde28b54eb8e4672a4c9e937c8de..4e352c0c9d270d843c22ec749e926b8e9cff8a4b 100644 (file)
 #include "util-unittest.h"
 #include "util-unittest-helper.h"
 
+#ifndef HAVE_JA3
+static int DetectJA3SetupNoSupport(DetectEngineCtx *a, Signature *b, const char *c)
+{
+    SCLogError("no JA3 support built in");
+    return -1;
+}
+#endif /* HAVE_JA3 */
+
 static int DetectTlsJa3SHashSetup(DetectEngineCtx *, Signature *, const char *);
 static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx,
        const DetectEngineTransforms *transforms,
@@ -75,10 +83,15 @@ void DetectTlsJa3SHashRegister(void)
     sigmatch_table[DETECT_AL_TLS_JA3S_HASH].name = "ja3s.hash";
     sigmatch_table[DETECT_AL_TLS_JA3S_HASH].desc = "sticky buffer to match the JA3S hash buffer";
     sigmatch_table[DETECT_AL_TLS_JA3S_HASH].url = "/rules/ja3-keywords.html#ja3s-hash";
+#ifdef HAVE_JA3
     sigmatch_table[DETECT_AL_TLS_JA3S_HASH].Setup = DetectTlsJa3SHashSetup;
+#else  /* HAVE_JA3 */
+    sigmatch_table[DETECT_AL_TLS_JA3S_HASH].Setup = DetectJA3SetupNoSupport;
+#endif /* HAVE_JA3 */
     sigmatch_table[DETECT_AL_TLS_JA3S_HASH].flags |= SIGMATCH_NOOPT;
     sigmatch_table[DETECT_AL_TLS_JA3S_HASH].flags |= SIGMATCH_INFO_STICKY_BUFFER;
 
+#ifdef HAVE_JA3
     DetectAppLayerInspectEngineRegister2("ja3s.hash", ALPROTO_TLS, SIG_FLAG_TOCLIENT, 0,
             DetectEngineInspectBufferGeneric, GetData);
 
@@ -100,6 +113,7 @@ void DetectTlsJa3SHashRegister(void)
             DetectTlsJa3SHashValidateCallback);
 
     g_tls_ja3s_hash_buffer_id = DetectBufferTypeGetByName("ja3s.hash");
+#endif /* HAVE_JA3 */
 }
 
 /**
index 0f7f7d61d0677bf7c608e069deb5f3ecc65a329d..bd4ceb556a9d26206966729e53a547bb4ef507af 100644 (file)
 #include "util-unittest.h"
 #include "util-unittest-helper.h"
 
+#ifndef HAVE_JA3
+static int DetectJA3SetupNoSupport(DetectEngineCtx *a, Signature *b, const char *c)
+{
+    SCLogError("no JA3 support built in");
+    return -1;
+}
+#endif /* HAVE_JA3 */
+
 static int DetectTlsJa3SStringSetup(DetectEngineCtx *, Signature *, const char *);
 static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx,
        const DetectEngineTransforms *transforms,
@@ -72,10 +80,15 @@ void DetectTlsJa3SStringRegister(void)
     sigmatch_table[DETECT_AL_TLS_JA3S_STRING].desc =
             "sticky buffer to match the JA3S string buffer";
     sigmatch_table[DETECT_AL_TLS_JA3S_STRING].url = "/rules/ja3-keywords.html#ja3s-string";
+#ifdef HAVE_JA3
     sigmatch_table[DETECT_AL_TLS_JA3S_STRING].Setup = DetectTlsJa3SStringSetup;
+#else  /* HAVE_JA3 */
+    sigmatch_table[DETECT_AL_TLS_JA3S_STRING].Setup = DetectJA3SetupNoSupport;
+#endif /* HAVE_JA3 */
     sigmatch_table[DETECT_AL_TLS_JA3S_STRING].flags |= SIGMATCH_NOOPT;
     sigmatch_table[DETECT_AL_TLS_JA3S_STRING].flags |= SIGMATCH_INFO_STICKY_BUFFER;
 
+#ifdef HAVE_JA3
     DetectAppLayerInspectEngineRegister2("ja3s.string", ALPROTO_TLS, SIG_FLAG_TOCLIENT, 0,
             DetectEngineInspectBufferGeneric, GetData);
 
@@ -91,6 +104,7 @@ void DetectTlsJa3SStringRegister(void)
     DetectBufferTypeSetDescriptionByName("ja3s.string", "TLS JA3S string");
 
     g_tls_ja3s_str_buffer_id = DetectBufferTypeGetByName("ja3s.string");
+#endif /*  HAVE_JA3 */
 }
 
 /**
index 6549c5bbeab5fc7155468e4098ba17aca00a6e12..40d6736718b67a4bfbfb14718192ec98e76dcf12 100644 (file)
@@ -26,6 +26,7 @@
 
 /* Provided feature names */
 #define FEATURE_OUTPUT_FILESTORE    "output::file-store"
+#define FEATURE_JA3                 "ja3"
 
 void ProvidesFeature(const char *);
 bool RequiresFeature(const char *);
index 4dbe0956cea57c8e640b7df7c5820fc622c0daf6..c0b7e942c969a6c726a9ab379d30b654054af86f 100644 (file)
@@ -743,6 +743,9 @@ static void PrintBuildInfo(void)
 #ifdef HAVE_LUA
     strlcat(features, "HAVE_LUA ", sizeof(features));
 #endif
+#ifdef HAVE_JA3
+    strlcat(features, "HAVE_JA3 ", sizeof(features));
+#endif
 #ifdef HAVE_LUAJIT
     strlcat(features, "HAVE_LUAJIT ", sizeof(features));
 #endif
index b361b3e74e3978dbb4acdf9dfbc1502abf46e434..b89a62e0d0bf6d9901ab3dd6f5062f46ac2e8bd7 100644 (file)
@@ -64,6 +64,8 @@ void Ja3BufferFree(JA3Buffer **buffer)
     *buffer = NULL;
 }
 
+#ifdef HAVE_JA3
+
 /**
  * \internal
  * \brief Resize buffer if it is full.
@@ -300,3 +302,29 @@ InspectionBuffer *Ja3DetectGetString(DetectEngineThreadCtx *det_ctx,
     }
     return buffer;
 }
+
+#else /* HAVE_JA3 */
+
+/* Stubs for when JA3 is disabled */
+
+int Ja3BufferAppendBuffer(JA3Buffer **buffer1, JA3Buffer **buffer2)
+{
+    return 0;
+}
+
+int Ja3BufferAddValue(JA3Buffer **buffer, uint32_t value)
+{
+    return 0;
+}
+
+char *Ja3GenerateHash(JA3Buffer *buffer)
+{
+    return NULL;
+}
+
+int Ja3IsDisabled(const char *type)
+{
+    return true;
+}
+
+#endif /* HAVE_JA3 */
index 5a0f8c508e6dbc7f653ceb5e1a55d5c3ee5ecdbb..c5de15fa77574584c06f1ac602bd33f0b97de9ea 100644 (file)
@@ -41,6 +41,7 @@ int Ja3BufferAddValue(JA3Buffer **, uint32_t);
 char *Ja3GenerateHash(JA3Buffer *);
 int Ja3IsDisabled(const char *);
 
+#ifdef HAVE_JA3
 InspectionBuffer *Ja3DetectGetHash(DetectEngineThreadCtx *det_ctx,
         const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv,
         const int list_id);
@@ -48,6 +49,5 @@ InspectionBuffer *Ja3DetectGetHash(DetectEngineThreadCtx *det_ctx,
 InspectionBuffer *Ja3DetectGetString(DetectEngineThreadCtx *det_ctx,
         const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv,
         const int list_id);
-
-#endif /* __UTIL_JA3_H__ */
-
+#endif /* HAVE_JA3 */
+#endif /* SURICATA_UTIL_JA3_H */