]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
detect: add (mpm) keyword for tls_sni
authorMats Klepsland <mats.klepsland@gmail.com>
Wed, 18 May 2016 11:49:47 +0000 (13:49 +0200)
committerVictor Julien <victor@inliniac.net>
Thu, 19 May 2016 07:44:45 +0000 (09:44 +0200)
Match on server name indication (SNI) extension in TLS using tls_sni
keyword, e.g:

alert tls any any -> any any (msg:"SNI test"; tls_sni;
        content:"example.com"; sid:12345;)

16 files changed:
src/Makefile.am
src/detect-engine-analyzer.c
src/detect-engine-content-inspection.h
src/detect-engine-mpm.c
src/detect-engine-state.h
src/detect-engine-tls.c [new file with mode: 0644]
src/detect-engine-tls.h [new file with mode: 0644]
src/detect-engine.c
src/detect-fast-pattern.c
src/detect-parse.c
src/detect-tls-sni.c [new file with mode: 0644]
src/detect-tls-sni.h [new file with mode: 0644]
src/detect.c
src/detect.h
src/suricata-common.h
src/util-profiling.c

index e2369c70f79c81e963fc386a78a31dca892d8daf..b81bb7be562e04f60e2e2c6655cb73c20ee57302 100644 (file)
@@ -87,6 +87,7 @@ detect-depth.c detect-depth.h \
 detect-detection-filter.c detect-detection-filter.h \
 detect-distance.c detect-distance.h \
 detect-dns-query.c detect-dns-query.h \
+detect-tls-sni.c detect-tls-sni.h \
 detect-dsize.c detect-dsize.h \
 detect-engine-address.c detect-engine-address.h \
 detect-engine-address-ipv4.c detect-engine-address-ipv4.h \
@@ -98,6 +99,7 @@ detect-engine.c detect-engine.h \
 detect-engine-content-inspection.c detect-engine-content-inspection.h \
 detect-engine-dcepayload.c detect-engine-dcepayload.h \
 detect-engine-dns.c detect-engine-dns.h \
+detect-engine-tls.c detect-engine-tls.h \
 detect-engine-modbus.c detect-engine-modbus.h \
 detect-engine-event.c detect-engine-event.h \
 detect-engine-file.c detect-engine-file.h \
index 80d76e607cc6d8f10c961a7a06456147873241b9..ade8ec0946ec94b8b7ea00ecb1e5ed40781de103 100644 (file)
@@ -478,6 +478,8 @@ static void EngineAnalysisRulesPrintFP(const Signature *s)
         fprintf(rule_engine_analysis_FD, "http user agent content");
     else if (list_type == DETECT_SM_LIST_DNSQUERYNAME_MATCH)
         fprintf(rule_engine_analysis_FD, "dns query name content");
+    else if (list_type == DETECT_SM_LIST_TLSSNI_MATCH)
+        fprintf(rule_engine_analysis_FD, "tls sni extension content");
 
     fprintf(rule_engine_analysis_FD, "\" buffer.\n");
 
index 5e80b9b8ccd56ee79e80bec3fdd3a11fb2050e44..7636fdf2c0d5aebb6ce372f54404ac0552803f24 100644 (file)
@@ -49,6 +49,7 @@ enum {
     DETECT_ENGINE_CONTENT_INSPECTION_MODE_HHHD,
     DETECT_ENGINE_CONTENT_INSPECTION_MODE_HRHHD,
     DETECT_ENGINE_CONTENT_INSPECTION_MODE_DNSQUERY,
+    DETECT_ENGINE_CONTENT_INSPECTION_MODE_TLSSNI,
     DETECT_ENGINE_CONTENT_INSPECTION_MODE_FD_SMTP,
     DETECT_ENGINE_CONTENT_INSPECTION_MODE_BASE64,
     DETECT_ENGINE_CONTENT_INSPECTION_MODE_TEMPLATE_BUFFER,
index 75232c50345fade81352fb91bf7d04abf05b79e9..04cca7844f7bf1ef2a7c95efddab397966027799 100644 (file)
@@ -106,6 +106,8 @@ AppLayerMpms app_mpms[] = {
 
     { "dns_query", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_DNSQUERYNAME_MATCH, SIG_GROUP_HEAD_MPM_DNSQUERY, 17},
 
+    { "tls_sni", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_TLSSNI_MATCH, SIG_GROUP_HEAD_MPM_TLSSNI, 18},
+
     { NULL, 0, 0, 0, 0, 0, }
 };
 
@@ -1207,7 +1209,9 @@ void MpmStoreFixup(SigGroupHead *sgh)
 
     SET_TS(sgh, sgh->mpm_dnsquery_ctx_ts);
 
-    BUG_ON(APP_MPMS_MAX != 18 || i != 18);
+    SET_TS(sgh, sgh->mpm_tlssni_ctx_ts);
+
+    BUG_ON(APP_MPMS_MAX != 19 || i != 19);
 
 #undef SET_TS
 #undef SET_TC
index c5264816ee5ba74b9a57bee24cc951ba2944a4b0..7b48f2c5b7cdd2a059999599f1c160f69418fb04 100644 (file)
@@ -87,7 +87,8 @@
 #define DE_STATE_FLAG_FD_SMTP_INSPECT     (1 << 21)
 #define DE_STATE_FLAG_DNSREQUEST_INSPECT  (1 << 22)
 #define DE_STATE_FLAG_DNSRESPONSE_INSPECT (1 << 23)
-#define DE_STATE_FLAG_TEMPLATE_BUFFER_INSPECT (1 << 24)
+#define DE_STATE_FLAG_TLSSNI_INSPECT      (1 << 24)
+#define DE_STATE_FLAG_TEMPLATE_BUFFER_INSPECT (1 << 25)
 
 /* state flags */
 #define DETECT_ENGINE_STATE_FLAG_FILE_STORE_DISABLED 0x0001
diff --git a/src/detect-engine-tls.c b/src/detect-engine-tls.c
new file mode 100644 (file)
index 0000000..2cac96a
--- /dev/null
@@ -0,0 +1,145 @@
+/* Copyright (C) 2016 Open Information Security Foundation
+ *
+ * You can copy, redistribute or modify this Program under the terms of
+ * the GNU General Public License version 2 as published by the Free
+ * Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2 along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+/** \file
+ *
+ *  \author Mats Klepsland <mats.klepsland@gmail.com>
+ *
+ */
+
+#include "suricata-common.h"
+#include "suricata.h"
+#include "decode.h"
+
+#include "detect.h"
+#include "detect-engine.h"
+#include "detect-parse.h"
+#include "detect-engine-state.h"
+#include "detect-engine-content-inspection.h"
+
+#include "flow-util.h"
+#include "util-debug.h"
+#include "util-print.h"
+#include "flow.h"
+
+#include "app-layer.h"
+#include "app-layer-parser.h"
+#include "app-layer-protos.h"
+#include "app-layer-ssl.h"
+
+#include "util-unittest.h"
+#include "util-unittest-helper.h"
+#include "util-validate.h"
+
+/**
+ * \brief TLS sni match -- searches for one pattern per signature.
+ *
+ * \param det_ctx   Detection engine thread ctx
+ * \param hrh       Buffer to inspect
+ * \param hrh_len   Buffer length
+ * \param flags     Flags
+ *
+ * \retval ret      Number of matches
+ */
+static inline uint32_t TlsSniPatternSearch(DetectEngineThreadCtx *det_ctx,
+                                           const uint8_t *buffer,
+                                           const uint32_t buffer_len,
+                                           const uint8_t flags)
+{
+    SCEnter();
+
+    uint32_t ret = 0;
+
+    DEBUG_VALIDATE_BUG_ON(flags & STREAM_TOCLIENT);
+    DEBUG_VALIDATE_BUG_ON(det_ctx->sgh->mpm_tlssni_ctx_ts == NULL);
+
+    if (buffer_len >= det_ctx->sgh->mpm_tlssni_ctx_ts->minlen) {
+        ret = mpm_table[det_ctx->sgh->mpm_tlssni_ctx_ts->mpm_type].
+            Search(det_ctx->sgh->mpm_tlssni_ctx_ts, &det_ctx->mtcu,
+                    &det_ctx->pmq, buffer, buffer_len);
+    }
+
+    SCReturnUInt(ret);
+}
+
+/**
+ *  \brief Run the pattern matcher against the SNI buffer
+ *
+ *  \param det_ctx    Detection engine thread ctx
+ *  \param f          Locked flow
+ *  \param dns_state  Initialized dns state
+ *  \param flags      Flags
+ *
+ *  \retval cnt       Number of matches
+ */
+uint32_t DetectTlsSniInspectMpm(DetectEngineThreadCtx *det_ctx, Flow *f,
+                                SSLState *ssl_state, uint8_t flags)
+{
+    SCEnter();
+
+    uint8_t *buffer;
+    uint32_t buffer_len;
+    uint32_t cnt = 0;
+
+    if (ssl_state->client_connp.sni == NULL)
+        return 0;
+
+    buffer = (uint8_t *)ssl_state->client_connp.sni;
+    buffer_len = strlen(ssl_state->client_connp.sni);
+
+    cnt = TlsSniPatternSearch(det_ctx, buffer, buffer_len, flags);
+
+    SCReturnUInt(cnt);
+}
+
+/** \brief Do the content inspection and validation for a signature
+ *
+ *  \param de_ctx   Detection engine context
+ *  \param det_ctx  Detection engine thread context
+ *  \param s        Signature to inspect
+ *  \param sm       SigMatch to inspect
+ *  \param f        Flow
+ *  \param flags    App layer flags
+ *  \param state    App layer state
+ *
+ *  \retval 0       No match
+ *  \retval 1       Match
+ */
+int DetectEngineInspectTlsSni(ThreadVars *tv, DetectEngineCtx *de_ctx,
+                              DetectEngineThreadCtx *det_ctx, Signature *s,
+                              Flow *f, uint8_t flags, void *alstate, void *txv,
+                              uint64_t tx_id)
+{
+    uint8_t *buffer;
+    uint16_t buffer_len;
+    int cnt = 0;
+
+    SSLState *ssl_state = (SSLState *)alstate;
+
+    if (ssl_state->client_connp.sni == NULL)
+        return 0;
+
+    buffer = (uint8_t *)ssl_state->client_connp.sni;
+    buffer_len = strlen(ssl_state->client_connp.sni);
+
+    cnt = DetectEngineContentInspection(de_ctx, det_ctx, s,
+            s->sm_lists[DETECT_SM_LIST_TLSSNI_MATCH],
+            f, buffer, buffer_len, 0,
+            DETECT_ENGINE_CONTENT_INSPECTION_MODE_TLSSNI, NULL);
+
+    return cnt;
+}
diff --git a/src/detect-engine-tls.h b/src/detect-engine-tls.h
new file mode 100644 (file)
index 0000000..3a9d530
--- /dev/null
@@ -0,0 +1,31 @@
+/* Copyright (C) 2016 Open Information Security Foundation
+ *
+ * You can copy, redistribute or modify this Program under the terms of
+ * the GNU General Public License version 2 as published by the Free
+ * Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2 along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+/** \file
+ *
+ *  \author Mats Klepsland <mats.klepsland@gmail.com>
+ */
+
+#ifndef __DETECT_ENGINE_TLS_H__
+#define __DETECT_ENGINE_TLS_H__
+
+int DetectEngineInspectTlsSni(ThreadVars *tv, DetectEngineCtx *de_ctx,
+                              DetectEngineThreadCtx *det_ctx,
+                              Signature *s, Flow *f, uint8_t flags,
+                              void *alstate, void *txv, uint64_t tx_id);
+
+#endif /* __DETECT_ENGINE_TLS_H__ */
index 1546aef3eed76c7fd76ed75160e6c667715b63d3..6a66a45d9fee2c159372672efa7293f69fef4c9b 100644 (file)
@@ -59,6 +59,7 @@
 #include "detect-engine-hrhhd.h"
 #include "detect-engine-file.h"
 #include "detect-engine-dns.h"
+#include "detect-engine-tls.h"
 #include "detect-engine-modbus.h"
 #include "detect-engine-filedata-smtp.h"
 #include "detect-engine-template.h"
@@ -269,6 +270,13 @@ void DetectEngineRegisterAppInspectionEngines(void)
           DE_STATE_FLAG_DNSREQUEST_INSPECT,
           0,
           DetectEngineInspectDnsRequest },
+        /* TLS */
+        { IPPROTO_TCP,
+          ALPROTO_TLS,
+          DETECT_SM_LIST_TLSSNI_MATCH,
+          DE_STATE_FLAG_TLSSNI_INSPECT,
+          0,
+          DetectEngineInspectTlsSni },
         /* SMTP */
         { IPPROTO_TCP,
           ALPROTO_SMTP,
@@ -2726,6 +2734,9 @@ const char *DetectSigmatchListEnumToString(enum DetectSigmatchListEnum type)
         case DETECT_SM_LIST_DNSRESPONSE_MATCH:
             return "dns response";
 
+        case DETECT_SM_LIST_TLSSNI_MATCH:
+            return "tls sni extension";
+
         case DETECT_SM_LIST_MODBUS_MATCH:
             return "modbus";
 
index dff7a4cc4aeb00e6c2f000dcfbab0e9383520757..dc7d94c64e09d6a15ce8445bba7b62751fcf2aa5 100644 (file)
@@ -136,6 +136,8 @@ void SupportFastPatternForSigMatchTypes(void)
 
     SupportFastPatternForSigMatchList(DETECT_SM_LIST_DNSQUERYNAME_MATCH, 2);
 
+    SupportFastPatternForSigMatchList(DETECT_SM_LIST_TLSSNI_MATCH, 2);
+
 #if 0
     SCFPSupportSMList *tmp = sm_fp_support_smlist_list;
     while (tmp != NULL) {
@@ -202,15 +204,16 @@ static int DetectFastPatternSetup(DetectEngineCtx *de_ctx, Signature *s, char *a
         s->sm_lists_tail[DETECT_SM_LIST_HUADMATCH] == NULL &&
         s->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH] == NULL &&
         s->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH] == NULL &&
-        s->sm_lists_tail[DETECT_SM_LIST_DNSQUERYNAME_MATCH] == NULL) {
+        s->sm_lists_tail[DETECT_SM_LIST_DNSQUERYNAME_MATCH] == NULL &&
+        s->sm_lists_tail[DETECT_SM_LIST_TLSSNI_MATCH] == NULL) {
         SCLogWarning(SC_WARN_COMPATIBILITY, "fast_pattern found inside the "
                      "rule, without a preceding content based keyword.  "
                      "Currently we provide fast_pattern support for content, "
                      "uricontent, http_client_body, http_server_body, http_header, "
                      "http_raw_header, http_method, http_cookie, "
                      "http_raw_uri, http_stat_msg, http_stat_code, "
-                     "http_user_agent, http_host, http_raw_host or "
-                     "dns_query option");
+                     "http_user_agent, http_host, http_raw_host, "
+                     "dns_query or tls_sni option");
         return -1;
     }
 
@@ -229,7 +232,8 @@ static int DetectFastPatternSetup(DetectEngineCtx *de_ctx, Signature *s, char *a
             DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HUADMATCH],
             DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH],
             DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH],
-            DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_DNSQUERYNAME_MATCH]);
+            DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_DNSQUERYNAME_MATCH],
+            DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_TLSSNI_MATCH]);
     if (pm == NULL) {
         SCLogError(SC_ERR_INVALID_SIGNATURE, "fast_pattern found inside "
                    "the rule, without a content context. Please use a "
index d86826cdf1ae4194ad0fda53e57a95e33b98b866..4adef8f84ea4429b905f326045907ded3a9332af 100644 (file)
@@ -167,6 +167,7 @@ const char *DetectListToHumanString(int list)
         CASE_CODE_STRING(DETECT_SM_LIST_DNSREQUEST_MATCH, "dns_request");
         CASE_CODE_STRING(DETECT_SM_LIST_DNSRESPONSE_MATCH, "dns_response");
         CASE_CODE_STRING(DETECT_SM_LIST_DNSQUERYNAME_MATCH, "dns_query");
+        CASE_CODE_STRING(DETECT_SM_LIST_TLSSNI_MATCH, "tls_sni");
         CASE_CODE_STRING(DETECT_SM_LIST_MODBUS_MATCH, "modbus");
         CASE_CODE_STRING(DETECT_SM_LIST_TEMPLATE_BUFFER_MATCH, "template");
         CASE_CODE_STRING(DETECT_SM_LIST_POSTMATCH, "postmatch");
@@ -207,6 +208,7 @@ const char *DetectListToString(int list)
         CASE_CODE(DETECT_SM_LIST_DNSREQUEST_MATCH);
         CASE_CODE(DETECT_SM_LIST_DNSRESPONSE_MATCH);
         CASE_CODE(DETECT_SM_LIST_DNSQUERYNAME_MATCH);
+        CASE_CODE(DETECT_SM_LIST_TLSSNI_MATCH);
         CASE_CODE(DETECT_SM_LIST_MODBUS_MATCH);
         CASE_CODE(DETECT_SM_LIST_TEMPLATE_BUFFER_MATCH);
         CASE_CODE(DETECT_SM_LIST_POSTMATCH);
@@ -1554,6 +1556,10 @@ static Signature *SigInitHelper(DetectEngineCtx *de_ctx, char *sigstr,
         sig->flags |= SIG_FLAG_STATE_MATCH;
     }
 
+    /* TLS */
+    if (sig->sm_lists[DETECT_SM_LIST_TLSSNI_MATCH])
+        sig->flags |= SIG_FLAG_STATE_MATCH;
+
     if (sig->sm_lists[DETECT_SM_LIST_MODBUS_MATCH])
         sig->flags |= SIG_FLAG_STATE_MATCH;
     if (sig->sm_lists[DETECT_SM_LIST_APP_EVENT])
diff --git a/src/detect-tls-sni.c b/src/detect-tls-sni.c
new file mode 100644 (file)
index 0000000..31c001c
--- /dev/null
@@ -0,0 +1,341 @@
+/* Copyright (C) 2007-2016 Open Information Security Foundation
+ *
+ * You can copy, redistribute or modify this Program under the terms of
+ * the GNU General Public License version 2 as published by the Free
+ * Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2 along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+/**
+ * \file
+ *
+ * \author Mats Klepsland <mats.klepsland@gmail.com>
+ *
+ * Implements support for tls_sni keyword.
+ */
+
+#include "suricata-common.h"
+#include "threads.h"
+#include "debug.h"
+#include "decode.h"
+#include "detect.h"
+
+#include "detect-parse.h"
+#include "detect-engine.h"
+#include "detect-engine-mpm.h"
+#include "detect-content.h"
+#include "detect-pcre.h"
+
+#include "flow.h"
+#include "flow-util.h"
+#include "flow-var.h"
+
+#include "util-debug.h"
+#include "util-unittest.h"
+#include "util-spm.h"
+#include "util-print.h"
+
+#include "stream-tcp.h"
+
+#include "app-layer.h"
+#include "app-layer-ssl.h"
+
+#include "util-unittest.h"
+#include "util-unittest-helper.h"
+
+static int DetectTlsSniSetup(DetectEngineCtx *, Signature *, char *);
+static void DetectTlsSniRegisterTests(void);
+
+/**
+ * \brief Registration function for keyword: tls_sni
+ */
+void DetectTlsSniRegister(void)
+{
+    sigmatch_table[DETECT_AL_TLS_SNI].name = "tls_sni";
+    sigmatch_table[DETECT_AL_TLS_SNI].desc = "content modifier to match specifically and only on the TLS SNI buffer";
+    sigmatch_table[DETECT_AL_TLS_SNI].Match = NULL;
+    sigmatch_table[DETECT_AL_TLS_SNI].AppLayerMatch = NULL;
+    sigmatch_table[DETECT_AL_TLS_SNI].alproto = ALPROTO_TLS;
+    sigmatch_table[DETECT_AL_TLS_SNI].Setup = DetectTlsSniSetup;
+    sigmatch_table[DETECT_AL_TLS_SNI].Free  = NULL;
+    sigmatch_table[DETECT_AL_TLS_SNI].RegisterTests = DetectTlsSniRegisterTests;
+
+    sigmatch_table[DETECT_AL_TLS_SNI].flags |= SIGMATCH_NOOPT;
+    sigmatch_table[DETECT_AL_TLS_SNI].flags |= SIGMATCH_PAYLOAD;
+}
+
+
+/**
+ * \brief this function setup the tls_sni modifier keyword used in the rule
+ *
+ * \param de_ctx   Pointer to the Detection Engine Context
+ * \param s        Pointer to the Signature to which the current keyword belongs
+ * \param str      Should hold an empty string always
+ *
+ * \retval 0       On success
+ */
+static int DetectTlsSniSetup(DetectEngineCtx *de_ctx, Signature *s, char *str)
+{
+    s->list = DETECT_SM_LIST_TLSSNI_MATCH;
+    s->alproto = ALPROTO_TLS;
+    return 0;
+}
+
+#ifdef UNITTESTS
+
+/**
+ * \test Test matching on a simple google.com SNI
+ */
+static int DetectTlsSniTest01(void)
+{
+    /* client hello */
+    uint8_t buf[] = { 0x16, 0x03, 0x03, 0x00, 0xAE, 0x01, 0x00, 0x00, 0xAA,
+                      0x03, 0x03, 0x57, 0x04, 0x9F, 0x5D, 0xC9, 0x5C, 0x87,
+                      0xAE, 0xF2, 0xA7, 0x4A, 0xFC, 0x59, 0x78, 0x23, 0x31,
+                      0x61, 0x2D, 0x29, 0x92, 0xB6, 0x70, 0xA5, 0xA1, 0xFC,
+                      0x0E, 0x79, 0xFE, 0xC3, 0x97, 0x37, 0xC0, 0x00, 0x00,
+                      0x44, 0x00, 0x04, 0x00, 0x05, 0x00, 0x0A, 0x00, 0x0D,
+                      0x00, 0x10, 0x00, 0x13, 0x00, 0x16, 0x00, 0x2F, 0x00,
+                      0x30, 0x00, 0x31, 0x00, 0x32, 0x00, 0x33, 0x00, 0x35,
+                      0x00, 0x36, 0x00, 0x37, 0x00, 0x38, 0x00, 0x39, 0x00,
+                      0x3C, 0x00, 0x3D, 0x00, 0x3E, 0x00, 0x3F, 0x00, 0x40,
+                      0x00, 0x41, 0x00, 0x44, 0x00, 0x45, 0x00, 0x66, 0x00,
+                      0x67, 0x00, 0x68, 0x00, 0x69, 0x00, 0x6A, 0x00, 0x6B,
+                      0x00, 0x84, 0x00, 0x87, 0x00, 0xFF, 0x01, 0x00, 0x00,
+                      0x13, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x0D, 0x00, 0x00,
+                      0x0A, 0x67, 0x6F, 0x6F, 0x67, 0x6C, 0x65, 0x2E, 0x63,
+                      0x6F, 0x6D, };
+
+    int result = 0;
+    Flow f;
+    SSLState *ssl_state = NULL;
+    Packet *p = NULL;
+    Signature *s = NULL;
+    ThreadVars tv;
+    DetectEngineThreadCtx *det_ctx = NULL;
+    TcpSession ssn;
+    AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
+
+    memset(&tv, 0, sizeof(ThreadVars));
+    memset(&f, 0, sizeof(Flow));
+    memset(&ssn, 0, sizeof(TcpSession));
+
+    p = UTHBuildPacketReal(buf, sizeof(buf), IPPROTO_TCP,
+                           "192.168.1.5", "192.168.1.1",
+                           41424, 443);
+
+    FLOW_INITIALIZE(&f);
+    f.protoctx = (void *)&ssn;
+    f.flags |= FLOW_IPV4;
+    f.proto = IPPROTO_TCP;
+    f.protomap = FlowGetProtoMapping(f.proto);
+
+    p->flow = &f;
+    p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST;
+    p->flowflags |= FLOW_PKT_TOSERVER|FLOW_PKT_ESTABLISHED;
+    f.alproto = ALPROTO_TLS;
+
+    StreamTcpInitConfig(TRUE);
+
+    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
+    if (de_ctx == NULL) {
+        goto end;
+    }
+    de_ctx->mpm_matcher = DEFAULT_MPM;
+    de_ctx->flags |= DE_QUIET;
+
+    s = DetectEngineAppendSig(de_ctx, "alert tls any any -> any any "
+                              "(msg:\"Test tls_sni option\"; "
+                              "tls_sni; content:\"google.com\"; sid:1;)");
+    if (s == NULL) {
+        goto end;
+    }
+
+    SigGroupBuild(de_ctx);
+    DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx);
+
+    SCMutexLock(&f.m);
+    int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, buf, sizeof(buf));
+    if (r != 0) {
+        printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
+        SCMutexUnlock(&f.m);
+        goto end;
+    }
+    SCMutexUnlock(&f.m);
+
+    ssl_state = f.alstate;
+    if (ssl_state == NULL) {
+        printf("no ssl state: ");
+        goto end;
+    }
+
+    /* do detect */
+    SigMatchSignatures(&tv, de_ctx, det_ctx, p);
+
+    if (!(PacketAlertCheck(p, 1))) {
+        printf("sig 1 didn't alert, but it should have: ");
+        goto end;
+    }
+
+    result = 1;
+
+end:
+    if (alp_tctx != NULL)
+        AppLayerParserThreadCtxFree(alp_tctx);
+    if (det_ctx != NULL)
+        DetectEngineThreadCtxDeinit(&tv, det_ctx);
+    if (de_ctx != NULL)
+        SigGroupCleanup(de_ctx);
+    if (de_ctx != NULL)
+        DetectEngineCtxFree(de_ctx);
+
+    StreamTcpFreeConfig(TRUE);
+    FLOW_DESTROY(&f);
+    UTHFreePacket(p);
+    return result;
+}
+
+/**
+ * \test Test matching on a simple google.com SNI with pcre
+ */
+static int DetectTlsSniTest02(void)
+{
+    /* client hello */
+    uint8_t buf[] = { 0x16, 0x03, 0x03, 0x00, 0xAE, 0x01, 0x00, 0x00, 0xAA,
+                      0x03, 0x03, 0x57, 0x04, 0x9F, 0x5D, 0xC9, 0x5C, 0x87,
+                      0xAE, 0xF2, 0xA7, 0x4A, 0xFC, 0x59, 0x78, 0x23, 0x31,
+                      0x61, 0x2D, 0x29, 0x92, 0xB6, 0x70, 0xA5, 0xA1, 0xFC,
+                      0x0E, 0x79, 0xFE, 0xC3, 0x97, 0x37, 0xC0, 0x00, 0x00,
+                      0x44, 0x00, 0x04, 0x00, 0x05, 0x00, 0x0A, 0x00, 0x0D,
+                      0x00, 0x10, 0x00, 0x13, 0x00, 0x16, 0x00, 0x2F, 0x00,
+                      0x30, 0x00, 0x31, 0x00, 0x32, 0x00, 0x33, 0x00, 0x35,
+                      0x00, 0x36, 0x00, 0x37, 0x00, 0x38, 0x00, 0x39, 0x00,
+                      0x3C, 0x00, 0x3D, 0x00, 0x3E, 0x00, 0x3F, 0x00, 0x40,
+                      0x00, 0x41, 0x00, 0x44, 0x00, 0x45, 0x00, 0x66, 0x00,
+                      0x67, 0x00, 0x68, 0x00, 0x69, 0x00, 0x6A, 0x00, 0x6B,
+                      0x00, 0x84, 0x00, 0x87, 0x00, 0xFF, 0x01, 0x00, 0x00,
+                      0x13, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x0D, 0x00, 0x00,
+                      0x0A, 0x67, 0x6F, 0x6F, 0x67, 0x6C, 0x65, 0x2E, 0x63,
+                      0x6F, 0x6D, };
+
+    int result = 0;
+    Flow f;
+    SSLState *ssl_state = NULL;
+    Packet *p = NULL;
+    Signature *s = NULL;
+    ThreadVars tv;
+    DetectEngineThreadCtx *det_ctx = NULL;
+    TcpSession ssn;
+    AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
+
+    memset(&tv, 0, sizeof(ThreadVars));
+    memset(&f, 0, sizeof(Flow));
+    memset(&ssn, 0, sizeof(TcpSession));
+
+    p = UTHBuildPacketReal(buf, sizeof(buf), IPPROTO_TCP,
+                           "192.168.1.5", "192.168.1.1",
+                           41424, 443);
+
+    FLOW_INITIALIZE(&f);
+    f.protoctx = (void *)&ssn;
+    f.flags |= FLOW_IPV4;
+    f.proto = IPPROTO_TCP;
+    f.protomap = FlowGetProtoMapping(f.proto);
+
+    p->flow = &f;
+    p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST;
+    p->flowflags |= FLOW_PKT_TOSERVER|FLOW_PKT_ESTABLISHED;
+    f.alproto = ALPROTO_TLS;
+
+    StreamTcpInitConfig(TRUE);
+
+    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
+    if (de_ctx == NULL) {
+        goto end;
+    }
+    de_ctx->mpm_matcher = DEFAULT_MPM;
+    de_ctx->flags |= DE_QUIET;
+
+    s = DetectEngineAppendSig(de_ctx, "alert tls any any -> any any "
+                              "(msg:\"Test tls_sni option\"; "
+                              "tls_sni; content:\"google\"; nocase; "
+                              "pcre:\"/google\\.com$/i\"; sid:1;)");
+    if (s == NULL) {
+        goto end;
+    }
+
+    s = DetectEngineAppendSig(de_ctx, "alert tls any any -> any any "
+                              "(msg:\"Test tls_sni option\"; "
+                              "tls_sni; content:\"google\"; nocase; "
+                              "pcre:\"/^\\.[a-z]{2,3}$/iR\"; sid:2;)");
+    if (s == NULL) {
+        goto end;
+    }
+
+    SigGroupBuild(de_ctx);
+    DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx);
+
+    SCMutexLock(&f.m);
+    int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, buf, sizeof(buf));
+    if (r != 0) {
+        printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
+        SCMutexUnlock(&f.m);
+        goto end;
+    }
+    SCMutexUnlock(&f.m);
+
+    ssl_state = f.alstate;
+    if (ssl_state == NULL) {
+        printf("no ssl state: ");
+        goto end;
+    }
+
+    /* do detect */
+    SigMatchSignatures(&tv, de_ctx, det_ctx, p);
+
+    if (!(PacketAlertCheck(p, 1))) {
+        printf("sig 1 didn't alert, but it should have: ");
+        goto end;
+    }
+
+    if (!(PacketAlertCheck(p, 2))) {
+        printf("sig 2 didn't alert, but it should have: ");
+        goto end;
+    }
+
+    result = 1;
+
+end:
+    if (alp_tctx != NULL)
+        AppLayerParserThreadCtxFree(alp_tctx);
+    if (det_ctx != NULL)
+        DetectEngineThreadCtxDeinit(&tv, det_ctx);
+    if (de_ctx != NULL)
+        SigGroupCleanup(de_ctx);
+    if (de_ctx != NULL)
+        DetectEngineCtxFree(de_ctx);
+
+    StreamTcpFreeConfig(TRUE);
+    FLOW_DESTROY(&f);
+    UTHFreePacket(p);
+    return result;
+}
+
+#endif
+
+static void DetectTlsSniRegisterTests(void)
+{
+#ifdef UNITTESTS
+    UtRegisterTest("DetectTlsSniTest01", DetectTlsSniTest01);
+    UtRegisterTest("DetectTlsSniTest02", DetectTlsSniTest02);
+#endif
+}
diff --git a/src/detect-tls-sni.h b/src/detect-tls-sni.h
new file mode 100644 (file)
index 0000000..8e6d930
--- /dev/null
@@ -0,0 +1,33 @@
+/* Copyright (C) 2016 Open Information Security Foundation
+ *
+ * You can copy, redistribute or modify this Program under the terms of
+ * the GNU General Public License version 2 as published by the Free
+ * Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2 along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+/**
+ * \file
+ *
+ * \author Mats Klepsland <mats.klepsland@gmail.com>
+ */
+
+#ifndef __DETECT_TLS_SNI_H__
+#define __DETECT_TLS_SNI_H__
+
+#include "app-layer-ssl.h"
+
+void DetectTlsSniRegister(void);
+uint32_t DetectTlsSniInspectMpm(DetectEngineThreadCtx *det_ctx, Flow *f,
+                                SSLState *ssl_state, uint8_t flags);
+
+#endif /* __DETECT_TLS_SNI_H__ */
index 60ca9795f578171bb6be4021c32eb187e72d6f56..3c5929516bfb4de07bc6aa81ed181ad7e0ece758 100644 (file)
@@ -48,6 +48,7 @@
 #include "detect-engine-dcepayload.h"
 #include "detect-engine-uri.h"
 #include "detect-dns-query.h"
+#include "detect-tls-sni.h"
 #include "detect-engine-state.h"
 #include "detect-engine-analyzer.h"
 #include "detect-engine-filedata-smtp.h"
@@ -1065,6 +1066,24 @@ static inline void DetectMpmPrefilter(DetectEngineCtx *de_ctx,
                         DetectDnsQueryInspectMpm(det_ctx, p->flow, alstate, flags, tx, idx);
                         PACKET_PROFILING_DETECT_END(p, PROF_DETECT_MPM_DNSQUERY);
                     }
+                    FLOWLOCK_UNLOCK(p->flow);
+                }
+            }
+        } else if (alproto == ALPROTO_TLS && has_state) {
+            if (p->flowflags & FLOW_PKT_TOSERVER) {
+                if (det_ctx->sgh->flags & SIG_GROUP_HEAD_MPM_TLSSNI) {
+                    FLOWLOCK_RDLOCK(p->flow);
+                    void *alstate = FlowGetAppState(p->flow);
+                    if (alstate == NULL) {
+                        SCLogDebug("no alstate");
+                        FLOWLOCK_UNLOCK(p->flow);
+                        return;
+                    }
+
+                    PACKET_PROFILING_DETECT_START(p, PROF_DETECT_MPM_TLSSNI);
+                    DetectTlsSniInspectMpm(det_ctx, p->flow, alstate, flags);
+                    PACKET_PROFILING_DETECT_END(p, PROF_DETECT_MPM_TLSSNI);
+
                     FLOWLOCK_UNLOCK(p->flow);
                 }
             }
@@ -4407,6 +4426,7 @@ void SigTableSetup(void)
     DetectLuaRegister();
     DetectIPRepRegister();
     DetectDnsQueryRegister();
+    DetectTlsSniRegister();
     DetectModbusRegister();
     DetectAppLayerProtocolRegister();
     DetectBase64DecodeRegister();
index 333381457be298b39ad5b1270f3417fd56fa46d7..90c6502984259bdcce27ce8d481c95b06d9e0bb9 100644 (file)
@@ -124,6 +124,8 @@ enum DetectSigmatchListEnum {
     DETECT_SM_LIST_DNSRESPONSE_MATCH,   /**< per DNS response tx match list */
     DETECT_SM_LIST_DNSQUERYNAME_MATCH,  /**< per query in a tx list */
 
+    DETECT_SM_LIST_TLSSNI_MATCH,
+
     DETECT_SM_LIST_MODBUS_MATCH,
 
     DETECT_SM_LIST_BASE64_DATA,
@@ -929,9 +931,10 @@ typedef struct SigTableElmt_ {
 #define SIG_GROUP_HEAD_HAVEFILEMD5      (1 << 21)
 #define SIG_GROUP_HEAD_HAVEFILESIZE     (1 << 22)
 #define SIG_GROUP_HEAD_MPM_DNSQUERY     (1 << 23)
-#define SIG_GROUP_HEAD_MPM_FD_SMTP      (1 << 24)
+#define SIG_GROUP_HEAD_MPM_TLSSNI       (1 << 24)
+#define SIG_GROUP_HEAD_MPM_FD_SMTP      (1 << 25)
 
-#define APP_MPMS_MAX 18
+#define APP_MPMS_MAX 19
 
 enum MpmBuiltinBuffers {
     MPMB_TCP_PKT_TS,
@@ -1009,6 +1012,7 @@ typedef struct SigGroupHead_ {
             const MpmCtx *mpm_hhhd_ctx_ts;
             const MpmCtx *mpm_hrhhd_ctx_ts;
             const MpmCtx *mpm_dnsquery_ctx_ts;
+            const MpmCtx *mpm_tlssni_ctx_ts;
             const MpmCtx *mpm_smtp_filedata_ctx_ts;
         };
         struct {
@@ -1209,6 +1213,7 @@ enum {
     DETECT_IPREP,
 
     DETECT_AL_DNS_QUERY,
+    DETECT_AL_TLS_SNI,
     DETECT_AL_MODBUS,
 
     DETECT_XBITS,
index 18791c3b04bcd59537082e121dcf842e7e16c134..141e8671d961a522fb708cac2168968085ec5d47 100644 (file)
@@ -320,6 +320,7 @@ typedef enum PacketProfileDetectId_ {
     PROF_DETECT_MPM_HHHD,
     PROF_DETECT_MPM_HRHHD,
     PROF_DETECT_MPM_DNSQUERY,
+    PROF_DETECT_MPM_TLSSNI,
     PROF_DETECT_IPONLY,
     PROF_DETECT_RULES,
     PROF_DETECT_STATEFUL,
index ee25076e8ca788d2a56aeca7e37c35ed72572eee..f63ee92987e4f9f402906f6c40e202644af02761 100644 (file)
@@ -1028,6 +1028,7 @@ const char * PacketProfileDetectIdToString(PacketProfileDetectId id)
         CASE_CODE (PROF_DETECT_MPM_HSCD);
         CASE_CODE (PROF_DETECT_MPM_HUAD);
         CASE_CODE (PROF_DETECT_MPM_DNSQUERY);
+        CASE_CODE (PROF_DETECT_MPM_TLSSNI);
         CASE_CODE (PROF_DETECT_IPONLY);
         CASE_CODE (PROF_DETECT_RULES);
         CASE_CODE (PROF_DETECT_PREFILTER);