]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
detect/ja: use multi-protocol support
authorPhilippe Antoine <contact@catenacyber.fr>
Mon, 25 Nov 2024 08:30:51 +0000 (09:30 +0100)
committerVictor Julien <victor@inliniac.net>
Sat, 29 Mar 2025 05:37:57 +0000 (06:37 +0100)
instead of hardcoding list : removes usage of ALPROTO_QUIC and
ALPROTO_TLS in generic SigValidate

Ticket: 7304

src/detect-ja4-hash.c
src/detect-parse.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/detect.h

index 78a9367fdaa5a85da0297c87d1d274777ac5ce15..8dabe34f899ea05a875f85957ea766c821903c82 100644 (file)
@@ -55,6 +55,9 @@ int Ja4IsDisabled(const char *type);
 static InspectionBuffer *Ja4DetectGetHash(DetectEngineThreadCtx *det_ctx,
         const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv,
         const int list_id);
+#ifdef UNITTESTS
+static void DetectJa4RegisterTests(void);
+#endif
 
 static int g_ja4_hash_buffer_id = 0;
 #endif
@@ -70,6 +73,9 @@ void DetectJa4HashRegister(void)
     sigmatch_table[DETECT_JA4_HASH].url = "/rules/ja4-keywords.html#ja4-hash";
 #ifdef HAVE_JA4
     sigmatch_table[DETECT_JA4_HASH].Setup = DetectJa4HashSetup;
+#ifdef UNITTESTS
+    sigmatch_table[DETECT_JA4_HASH].RegisterTests = DetectJa4RegisterTests;
+#endif
 #else  /* HAVE_JA4 */
     sigmatch_table[DETECT_JA4_HASH].Setup = DetectJA4SetupNoSupport;
 #endif /* HAVE_JA4 */
@@ -111,7 +117,8 @@ static int DetectJa4HashSetup(DetectEngineCtx *de_ctx, Signature *s, const char
     if (DetectBufferSetActiveList(de_ctx, s, g_ja4_hash_buffer_id) < 0)
         return -1;
 
-    if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_TLS && s->alproto != ALPROTO_QUIC) {
+    AppProto alprotos[] = { ALPROTO_TLS, ALPROTO_QUIC, ALPROTO_UNKNOWN };
+    if (DetectSignatureSetMultiAppProto(s, alprotos) < 0) {
         SCLogError("rule contains conflicting protocols.");
         return -1;
     }
@@ -126,7 +133,6 @@ static int DetectJa4HashSetup(DetectEngineCtx *de_ctx, Signature *s, const char
         }
         return -2;
     }
-    s->init_data->init_flags |= SIG_FLAG_INIT_JA;
 
     return 0;
 }
@@ -174,4 +180,68 @@ static InspectionBuffer *Ja4DetectGetHash(DetectEngineThreadCtx *det_ctx,
     }
     return buffer;
 }
+
+#ifdef UNITTESTS
+static int DetectJa4TestParse01(void)
+{
+    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
+
+    // invalid tests
+    Signature *s =
+            SigInit(de_ctx, "alert ip any any -> any any (sid: 1; file.data; content: \"toto\"; "
+                            "ja4.hash; content: \"q13d0310h3_55b375c5d22e_cd85d2d88918\";)");
+    // cannot have file.data with ja4.hash (quic or tls)
+    FAIL_IF_NOT_NULL(s);
+    s = SigInit(de_ctx, "alert ip any any -> any any (sid: 1; "
+                        "ja4.hash; content: \"q13d0310h3_55b375c5d22e_cd85d2d88918\"; file.data; "
+                        "content: \"toto\";)");
+    // cannot have file.data with ja4.hash (quic or tls)
+    FAIL_IF_NOT_NULL(s);
+    s = SigInit(de_ctx, "alert smb any any -> any any (sid: 1; "
+                        "ja4.hash; content: \"q13d0310h3_55b375c5d22e_cd85d2d88918\";)");
+    // cannot have alproto=smb with ja4.hash (quic or tls)
+    FAIL_IF_NOT_NULL(s);
+    s = SigInit(de_ctx, "alert ip any any -> any any (sid: 1; "
+                        "ja4.hash; content: \"q13d0310h3_55b375c5d22e_cd85d2d88918\"; smb.share; "
+                        "content:\"toto\";)");
+    // cannot have a smb keyword with ja4.hash (quic or tls)
+    FAIL_IF_NOT_NULL(s);
+    s = SigInit(de_ctx, "alert ip any any -> any any (sid: 1; "
+                        "smb.share; content:\"toto\"; ja4.hash; content: "
+                        "\"q13d0310h3_55b375c5d22e_cd85d2d88918\";)");
+    // cannot have a smb keyword with ja4.hash (quic or tls)
+    FAIL_IF_NOT_NULL(s);
+
+    // valid tests
+    s = DetectEngineAppendSig(de_ctx,
+            "alert ip any any -> any any (sid: 1; "
+            "ja4.hash; content: \"q13d0310h3_55b375c5d22e_cd85d2d88918\";)");
+    // just ja4.hash any proto
+    FAIL_IF_NULL(s);
+    s = DetectEngineAppendSig(de_ctx,
+            "alert quic any any -> any any (sid: 2; "
+            "ja4.hash; content: \"q13d0310h3_55b375c5d22e_cd85d2d88918\";)");
+    // just ja4.hash only quic
+    FAIL_IF_NULL(s);
+    s = DetectEngineAppendSig(de_ctx,
+            "alert tls any any -> any any (sid: 3; "
+            "ja4.hash; content: \"q13d0310h3_55b375c5d22e_cd85d2d88918\";)");
+    // just ja4.hash only tls
+    FAIL_IF_NULL(s);
+    s = DetectEngineAppendSig(de_ctx,
+            "alert ip any any -> any any (sid: 4; "
+            "ja4.hash; content: \"q13d0310h3_55b375c5d22e_cd85d2d88918\"; "
+            "quic.version; content:\"|00|\";)");
+    // ja4.hash and a quic keyword
+    FAIL_IF_NULL(s);
+    DetectEngineCtxFree(de_ctx);
+    PASS;
+}
+
+static void DetectJa4RegisterTests(void)
+{
+    UtRegisterTest("DetectJa4TestParse01", DetectJa4TestParse01);
+}
 #endif
+
+#endif // HAVE_JA4
index c67f342aaf093bfb02b04ae1071e707adbf59045..370b832a59db51c1c4b247f64941eca5e4ac6e67 100644 (file)
@@ -2285,11 +2285,6 @@ static int SigValidate(DetectEngineCtx *de_ctx, Signature *s)
     }
     DetectLuaPostSetup(s);
 
-    if ((s->init_data->init_flags & SIG_FLAG_INIT_JA) && s->alproto != ALPROTO_UNKNOWN &&
-            s->alproto != ALPROTO_TLS && s->alproto != ALPROTO_QUIC) {
-        SCLogError("Cannot have ja3/ja4 with protocol %s.", AppProtoToString(s->alproto));
-        SCReturnInt(0);
-    }
     if ((s->flags & SIG_FLAG_FILESTORE) || s->file_flags != 0 ||
         (s->init_data->init_flags & SIG_FLAG_INIT_FILEDATA)) {
         if (s->alproto != ALPROTO_UNKNOWN &&
@@ -2299,6 +2294,21 @@ static int SigValidate(DetectEngineCtx *de_ctx, Signature *s)
                        "support file matching",
                     AppProtoToString(s->alproto));
             SCReturnInt(0);
+        } else if (s->init_data->alprotos[0] != ALPROTO_UNKNOWN) {
+            bool found = false;
+            for (AppProto i = 0; i < SIG_ALPROTO_MAX; i++) {
+                if (s->init_data->alprotos[i] == ALPROTO_UNKNOWN) {
+                    break;
+                }
+                if (AppLayerParserSupportsFiles(IPPROTO_TCP, s->init_data->alprotos[i])) {
+                    found = true;
+                    break;
+                }
+            }
+            if (!found) {
+                SCLogError("No protocol support file matching");
+                SCReturnInt(0);
+            }
         }
         if (s->alproto == ALPROTO_HTTP2 && (s->file_flags & FILE_SIG_NEED_FILENAME)) {
             SCLogError("protocol HTTP2 doesn't support file name matching");
index 0a22eb6a0c5fec772254bcaf486aec4252b8db69..82fb7d76b83e762ab191a9b00f7884aa107e22b0 100644 (file)
@@ -136,7 +136,8 @@ static int DetectTlsJa3HashSetup(DetectEngineCtx *de_ctx, Signature *s, const ch
     if (DetectBufferSetActiveList(de_ctx, s, g_tls_ja3_hash_buffer_id) < 0)
         return -1;
 
-    if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_TLS && s->alproto != ALPROTO_QUIC) {
+    AppProto alprotos[] = { ALPROTO_TLS, ALPROTO_QUIC, ALPROTO_UNKNOWN };
+    if (DetectSignatureSetMultiAppProto(s, alprotos) < 0) {
         SCLogError("rule contains conflicting protocols.");
         return -1;
     }
@@ -151,7 +152,6 @@ static int DetectTlsJa3HashSetup(DetectEngineCtx *de_ctx, Signature *s, const ch
         }
         return -2;
     }
-    s->init_data->init_flags |= SIG_FLAG_INIT_JA;
 
     return 0;
 }
index cc4acf4b2b6ff63483ff63b92e8e17d9c5d48aad..9b62f425d014c381c4cfd993f677bbe3af7d25e0 100644 (file)
@@ -125,7 +125,8 @@ static int DetectTlsJa3StringSetup(DetectEngineCtx *de_ctx, Signature *s, const
     if (DetectBufferSetActiveList(de_ctx, s, g_tls_ja3_str_buffer_id) < 0)
         return -1;
 
-    if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_TLS && s->alproto != ALPROTO_QUIC) {
+    AppProto alprotos[] = { ALPROTO_TLS, ALPROTO_QUIC, ALPROTO_UNKNOWN };
+    if (DetectSignatureSetMultiAppProto(s, alprotos) < 0) {
         SCLogError("rule contains conflicting protocols.");
         return -1;
     }
@@ -140,7 +141,6 @@ static int DetectTlsJa3StringSetup(DetectEngineCtx *de_ctx, Signature *s, const
         }
         return -2;
     }
-    s->init_data->init_flags |= SIG_FLAG_INIT_JA;
 
     return 0;
 }
index 3b439161cd560cb9e4e71cf8877c0e99d8e382dd..9dba78195933370ddfa22ce1a4185024038bf08e 100644 (file)
@@ -134,7 +134,8 @@ static int DetectTlsJa3SHashSetup(DetectEngineCtx *de_ctx, Signature *s, const c
     if (DetectBufferSetActiveList(de_ctx, s, g_tls_ja3s_hash_buffer_id) < 0)
         return -1;
 
-    if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_TLS && s->alproto != ALPROTO_QUIC) {
+    AppProto alprotos[] = { ALPROTO_TLS, ALPROTO_QUIC, ALPROTO_UNKNOWN };
+    if (DetectSignatureSetMultiAppProto(s, alprotos) < 0) {
         SCLogError("rule contains conflicting protocols.");
         return -1;
     }
@@ -149,7 +150,6 @@ static int DetectTlsJa3SHashSetup(DetectEngineCtx *de_ctx, Signature *s, const c
         }
         return -2;
     }
-    s->init_data->init_flags |= SIG_FLAG_INIT_JA;
 
     return 0;
 }
index 2b7710d87fb6153644cc065bc7f2b7b80836345d..fd789bd90247f981787cba21c3004f596175d56a 100644 (file)
@@ -124,7 +124,8 @@ static int DetectTlsJa3SStringSetup(DetectEngineCtx *de_ctx, Signature *s, const
     if (DetectBufferSetActiveList(de_ctx, s, g_tls_ja3s_str_buffer_id) < 0)
         return -1;
 
-    if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_TLS && s->alproto != ALPROTO_QUIC) {
+    AppProto alprotos[] = { ALPROTO_TLS, ALPROTO_QUIC, ALPROTO_UNKNOWN };
+    if (DetectSignatureSetMultiAppProto(s, alprotos) < 0) {
         SCLogError("rule contains conflicting protocols.");
         return -1;
     }
@@ -139,7 +140,6 @@ static int DetectTlsJa3SStringSetup(DetectEngineCtx *de_ctx, Signature *s, const
         }
         return -2;
     }
-    s->init_data->init_flags |= SIG_FLAG_INIT_JA;
 
     return 0;
 }
index 89838b936822e61a1d66ef94d7e97eeddd01c02f..74319a6982cec4f418e9fd0a30293b63b445871d 100644 (file)
@@ -295,8 +295,7 @@ typedef struct DetectPort_ {
 #define SIG_FLAG_INIT_NEED_FLUSH            BIT_U32(7)
 #define SIG_FLAG_INIT_PRIO_EXPLICIT                                                                \
     BIT_U32(8) /**< priority is explicitly set by the priority keyword */
-#define SIG_FLAG_INIT_FILEDATA              BIT_U32(9)  /**< signature has filedata keyword */
-#define SIG_FLAG_INIT_JA                    BIT_U32(10) /**< signature has ja3/ja4 keyword */
+#define SIG_FLAG_INIT_FILEDATA BIT_U32(9) /**< signature has filedata keyword */
 
 /* signature mask flags */
 /** \note: additions should be added to the rule analyzer as well */