]> 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)
committerVictor Julien <victor@inliniac.net>
Tue, 16 Apr 2024 06:00:38 +0000 (08:00 +0200)
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 9e568bbfe2c5cb1a050247900509f6c9887243cf..fc83f9f682f3d7c195ea5c412f9a49d4179c8cf1 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")
@@ -2660,6 +2670,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 59e28bd034212d6eb9e7984112bd428e9b015017..c5a1cbe4238b39628cec833e48fd3abc83eb65c1 100644 (file)
@@ -22,6 +22,7 @@ lua_int8 = ["lua"]
 strict = []
 debug = []
 debug-validate = []
+ja3 = []
 
 [dependencies]
 nom7 = { version="7.0", package="nom" }
index 8bf685e5c74a9969140c3b2cc0d9d5c494f1dcbc..a1a2ebc14447c0d961ece9da3909654ec7a2c424 100644 (file)
@@ -18,6 +18,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 8fb4c9a2f583b940541cbc42a1cd4ad9ff158ac8..51f7576bf1984933303f1770a84ccca76cf1a08f 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 52810f731d8daa596df5e8d894661701a3888bcf..0b8a0b656b767198cfd23cbc23f36b66dd5ba0cb 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"
@@ -2949,6 +2951,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
  */
@@ -3048,20 +3075,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)) {
@@ -3070,7 +3086,9 @@ void RegisterSSLParsers(void)
             }
         } else {
             if (RunmodeIsUnittests()) {
+#ifdef HAVE_JA3
                 SC_ATOMIC_SET(ssl_config.enable_ja3, 1);
+#endif /* HAVE_JA3 */
             }
         }
     } else {
index 0cfe18d66e6538463e14c507140ce38b91d49c17..c672123656f38b1684a9414d6e8896630d8aa67a 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
     DetectAppLayerInspectEngineRegister("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 6c2fbc6ad9751a4f4563286f8f9b9ae6fd0983fb..dacebc9dcbef575b9c7c22e0ebf40930ca3314e9 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
     DetectAppLayerInspectEngineRegister("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 a1a334a4f16b11c9e6bcdf3f45674b3e8d886296..688124354fc32ecc953d8d6ddb226a5fdc1ef668 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
     DetectAppLayerInspectEngineRegister("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 32117df684422aec22122909a40e1e55a03f1cfe..a4c8ac5d1e493578c64a51f9f12d690a5893c309 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
     DetectAppLayerInspectEngineRegister("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 035fb3997bb81dd53e53b5a5af192a56efe0233b..a8aebb3a40ea95277a8759ecb6343c664359c9a9 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 ecbec2460c4b1a81a6c760af57e39a44cc244160..7feedf264275140239a30468e69afd2643cc4e2d 100644 (file)
@@ -744,6 +744,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 e9d192ddbe1020c9e5082b54e9ef20d7b1c6b3ce..f7ecb3079bc2b2a994c54bd7ec48a5683f8d831f 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,5 +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 /* HAVE_JA3 */
 #endif /* SURICATA_UTIL_JA3_H */