From: Sascha Steinbiss Date: Fri, 12 Apr 2024 17:54:23 +0000 (+0200) Subject: ja3: make feature compile time configurable X-Git-Tag: suricata-8.0.0-beta1~1474 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=9d0db71ebf65919215b9e09a1b8fbbbc27560388;p=thirdparty%2Fsuricata.git ja3: make feature compile time configurable --- diff --git a/configure.ac b/configure.ac index 9e568bbfe2..fc83f9f682 100644 --- a/configure.ac +++ b/configure.ac @@ -2207,6 +2207,16 @@ 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} diff --git a/rust/Cargo.toml.in b/rust/Cargo.toml.in index 59e28bd034..c5a1cbe423 100644 --- a/rust/Cargo.toml.in +++ b/rust/Cargo.toml.in @@ -22,6 +22,7 @@ lua_int8 = ["lua"] strict = [] debug = [] debug-validate = [] +ja3 = [] [dependencies] nom7 = { version="7.0", package="nom" } diff --git a/rust/Makefile.am b/rust/Makefile.am index 8bf685e5c7..a1a2ebc144 100644 --- a/rust/Makefile.am +++ b/rust/Makefile.am @@ -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 diff --git a/rust/src/quic/frames.rs b/rust/src/quic/frames.rs index e1fb7d0807..d432c79d12 100644 --- a/rust/src/quic/frames.rs +++ b/rust/src/quic/frames.rs @@ -136,7 +136,7 @@ pub(crate) struct Crypto { // We remap the Vec from tls_parser::parse_tls_extensions because of // the lifetime of TlsExtension due to references to the slice used for parsing pub extv: Vec, - pub ja3: String, + pub ja3: Option, } #[derive(Debug, PartialEq)] @@ -296,7 +296,15 @@ fn parse_quic_handshake(msg: TlsMessage) -> Option { 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 { 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 + }, + })); } _ => {} } diff --git a/rust/src/quic/quic.rs b/rust/src/quic/quic.rs index 8fb4c9a2f5..51f7576bf1 100644 --- a/rust/src/quic/quic.rs +++ b/rust/src/quic/quic.rs @@ -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()); diff --git a/src/app-layer-ssl.c b/src/app-layer-ssl.c index 52810f731d..0b8a0b656b 100644 --- a/src/app-layer-ssl.c +++ b/src/app-layer-ssl.c @@ -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 { diff --git a/src/detect-tls-ja3-hash.c b/src/detect-tls-ja3-hash.c index 0cfe18d66e..c672123656 100644 --- a/src/detect-tls-ja3-hash.c +++ b/src/detect-tls-ja3-hash.c @@ -56,6 +56,14 @@ #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 */ } /** diff --git a/src/detect-tls-ja3-string.c b/src/detect-tls-ja3-string.c index 6c2fbc6ad9..dacebc9dcb 100644 --- a/src/detect-tls-ja3-string.c +++ b/src/detect-tls-ja3-string.c @@ -56,6 +56,14 @@ #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 */ } /** diff --git a/src/detect-tls-ja3s-hash.c b/src/detect-tls-ja3s-hash.c index a1a334a4f1..688124354f 100644 --- a/src/detect-tls-ja3s-hash.c +++ b/src/detect-tls-ja3s-hash.c @@ -56,6 +56,14 @@ #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 */ } /** diff --git a/src/detect-tls-ja3s-string.c b/src/detect-tls-ja3s-string.c index 32117df684..a4c8ac5d1e 100644 --- a/src/detect-tls-ja3s-string.c +++ b/src/detect-tls-ja3s-string.c @@ -56,6 +56,14 @@ #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 */ } /** diff --git a/src/feature.h b/src/feature.h index 035fb3997b..a8aebb3a40 100644 --- a/src/feature.h +++ b/src/feature.h @@ -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 *); diff --git a/src/suricata.c b/src/suricata.c index ecbec2460c..7feedf2642 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -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 diff --git a/src/util-ja3.c b/src/util-ja3.c index b361b3e74e..b89a62e0d0 100644 --- a/src/util-ja3.c +++ b/src/util-ja3.c @@ -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 */ diff --git a/src/util-ja3.h b/src/util-ja3.h index e9d192ddbe..f7ecb3079b 100644 --- a/src/util-ja3.h +++ b/src/util-ja3.h @@ -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 */