]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
tls: adding support for fingerprint rule matching.
authorJean-Paul Roliers <popof.fpn@gmail.com>
Thu, 2 Feb 2012 15:45:35 +0000 (16:45 +0100)
committerEric Leblond <eric@regit.org>
Fri, 24 Aug 2012 10:59:12 +0000 (12:59 +0200)
Add the support for tls.fingerprint keyword in rules.

src/detect-tls.c
src/detect-tls.h
src/detect.h

index 110f775391a818135557406b6ce3b89188233f7d..ba88083f7b74d698bd48bc5e3b2ef79e8a97e0e2 100644 (file)
 /**
  * \brief Regex for parsing "id" option, matching number or "number"
  */
+
 #define PARSE_REGEX  "^\\s*(\\!*)\\s*([A-z0-9\\s\\-\\.=,\\*]+|\"[A-z0-9\\s\\-\\.=,\\*]+\")\\s*$"
+#define PARSE_REGEX_FINGERPRINT  "^\\s*(\\!*)\\s*([A-z0-9\\:\\*]+|\"[A-z0-9\\:\\* ]+\")\\s*$"
 
 static pcre *subject_parse_regex;
 static pcre_extra *subject_parse_regex_study;
 static pcre *issuerdn_parse_regex;
 static pcre_extra *issuerdn_parse_regex_study;
+static pcre *fingerprint_parse_regex;
+static pcre_extra *fingerprint_parse_regex_study;
 
 static int DetectTlsSubjectMatch (ThreadVars *, DetectEngineThreadCtx *, Flow *, uint8_t, void *, Signature *, SigMatch *);
 static int DetectTlsSubjectSetup (DetectEngineCtx *, Signature *, char *);
@@ -78,7 +82,9 @@ static int DetectTlsIssuerDNMatch (ThreadVars *, DetectEngineThreadCtx *, Flow *
 static int DetectTlsIssuerDNSetup (DetectEngineCtx *, Signature *, char *);
 static void DetectTlsIssuerDNRegisterTests(void);
 static void DetectTlsIssuerDNFree(void *);
-
+static int DetectTlsFingerprintMatch (ThreadVars *, DetectEngineThreadCtx *, Flow *, uint8_t, void *, Signature *, SigMatch *);
+static int DetectTlsFingerprintSetup (DetectEngineCtx *, Signature *, char *);
+static void DetectTlsFingerprintFree(void *);
 /**
  * \brief Registration function for keyword: tls.version
  */
@@ -99,6 +105,14 @@ void DetectTlsRegister (void) {
     sigmatch_table[DETECT_AL_TLS_ISSUERDN].Free  = DetectTlsIssuerDNFree;
     sigmatch_table[DETECT_AL_TLS_ISSUERDN].RegisterTests = DetectTlsIssuerDNRegisterTests;
 
+    sigmatch_table[DETECT_AL_TLS_FINGERPRINT].name = "tls.fingerprint";
+    sigmatch_table[DETECT_AL_TLS_FINGERPRINT].Match = NULL;
+    sigmatch_table[DETECT_AL_TLS_FINGERPRINT].AppLayerMatch = DetectTlsFingerprintMatch;
+    sigmatch_table[DETECT_AL_TLS_FINGERPRINT].alproto = ALPROTO_TLS;
+    sigmatch_table[DETECT_AL_TLS_FINGERPRINT].Setup = DetectTlsFingerprintSetup;
+    sigmatch_table[DETECT_AL_TLS_FINGERPRINT].Free  = DetectTlsFingerprintFree;
+    sigmatch_table[DETECT_AL_TLS_FINGERPRINT].RegisterTests = NULL;
+
     const char *eb;
     int eo;
     int opts = 0;
@@ -132,6 +146,21 @@ void DetectTlsRegister (void) {
         SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb);
         goto error;
     }
+
+    SCLogDebug("registering tls.fingerprint rule option");
+
+    fingerprint_parse_regex = pcre_compile(PARSE_REGEX_FINGERPRINT, opts, &eb, &eo, NULL);
+    if (fingerprint_parse_regex == NULL) {
+        SCLogError(SC_ERR_PCRE_COMPILE, "Compile of \"%s\" failed at offset %" PRId32 ": %s", PARSE_REGEX_FINGERPRINT, eo, eb);
+        goto error;
+    }
+
+    fingerprint_parse_regex_study = pcre_study(fingerprint_parse_regex, 0, &eb);
+    if (eb != NULL) {
+        SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb);
+        goto error;
+    }
+
     return;
 
 error:
@@ -208,6 +237,10 @@ static DetectTlsData *DetectTlsSubjectParse (char *str)
 #define MAX_SUBSTRINGS 30
     int ret = 0, res = 0;
     int ov[MAX_SUBSTRINGS];
+    const char *str_ptr;
+    char *orig;
+    char *tmp_str;
+    uint32_t flag = 0;
 
     ret = pcre_exec(subject_parse_regex, subject_parse_regex_study, str, strlen(str), 0, 0,
                     ov, MAX_SUBSTRINGS);
@@ -217,52 +250,45 @@ static DetectTlsData *DetectTlsSubjectParse (char *str)
         goto error;
     }
 
-    if (ret == 3) {
-        const char *str_ptr;
-        char *orig;
-        char *tmp_str;
-        uint32_t flag = 0;
-
-        res = pcre_get_substring((char *)str, ov, MAX_SUBSTRINGS, 1, &str_ptr);
-        if (res < 0) {
-            SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed");
-            goto error;
-        }
-        if (str_ptr[0] == '!')
-            flag = DETECT_CONTENT_NEGATED;
+    res = pcre_get_substring((char *)str, ov, MAX_SUBSTRINGS, 1, &str_ptr);
+    if (res < 0) {
+        SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed");
+        goto error;
+    }
+    if (str_ptr[0] == '!')
+        flag = DETECT_CONTENT_NEGATED;
 
-        res = pcre_get_substring((char *)str, ov, MAX_SUBSTRINGS, 2, &str_ptr);
-        if (res < 0) {
-            SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed");
-            goto error;
-        }
+    res = pcre_get_substring((char *)str, ov, MAX_SUBSTRINGS, 2, &str_ptr);
+    if (res < 0) {
+        SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed");
+        goto error;
+    }
 
-        /* We have a correct id option */
-        tls = SCMalloc(sizeof(DetectTlsData));
-        if (tls == NULL)
-            goto error;
-        tls->subject = NULL;
-        tls->flags = flag;
+    /* We have a correct id option */
+    tls = SCMalloc(sizeof(DetectTlsData));
+    if (tls == NULL)
+        goto error;
+    tls->subject = NULL;
+    tls->flags = flag;
 
-        orig = SCStrdup((char*)str_ptr);
-        tmp_str=orig;
-        if (tmp_str == NULL) {
-            goto error;
-        }
+    orig = SCStrdup((char*)str_ptr);
+    tmp_str=orig;
+    if (tmp_str == NULL) {
+        goto error;
+    }
 
-        /* Let's see if we need to escape "'s */
-        if (tmp_str[0] == '"')
-        {
-            tmp_str[strlen(tmp_str) - 1] = '\0';
-            tmp_str += 1;
-        }
+    /* Let's see if we need to escape "'s */
+    if (tmp_str[0] == '"')
+    {
+        tmp_str[strlen(tmp_str) - 1] = '\0';
+        tmp_str += 1;
+    }
 
-        tls->subject = SCStrdup(tmp_str);
+    tls->subject = SCStrdup(tmp_str);
 
-        SCFree(orig);
+    SCFree(orig);
 
-        SCLogDebug("will look for TLS subject %s", tls->subject);
-    }
+    SCLogDebug("will look for TLS subject %s", tls->subject);
 
     return tls;
 
@@ -533,6 +559,192 @@ static void DetectTlsIssuerDNFree(void *ptr)
     SCFree(id_d);
 }
 
+/**
+ * \brief This function is used to parse fingerprint passed via keyword: "fingerprint"
+ *
+ * \param idstr Pointer to the user provided fingerprint option
+ *
+ * \retval pointer to DetectTlsData on success
+ * \retval NULL on failure
+ */
+static DetectTlsData *DetectTlsFingerprintParse (char *str)
+{
+    DetectTlsData *tls = NULL;
+#define MAX_SUBSTRINGS 30
+    int ret = 0, res = 0;
+    int ov[MAX_SUBSTRINGS];
+    const char *str_ptr;
+    char *orig;
+    char *tmp_str;
+    uint32_t flag = 0;
+
+    ret = pcre_exec(fingerprint_parse_regex, fingerprint_parse_regex_study, str, strlen(str), 0, 0,
+                    ov, MAX_SUBSTRINGS);
+
+    if (ret != 3) {
+        SCLogError(SC_ERR_PCRE_MATCH, "invalid tls.fingerprint option");
+        goto error;
+    }
+
+    res = pcre_get_substring((char *)str, ov, MAX_SUBSTRINGS, 1, &str_ptr);
+    if (res < 0) {
+        SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed");
+        goto error;
+    }
+    if (str_ptr[0] == '!')
+        flag = DETECT_CONTENT_NEGATED;
+
+    res = pcre_get_substring((char *)str, ov, MAX_SUBSTRINGS, 2, &str_ptr);
+    if (res < 0) {
+        SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed");
+        goto error;
+    }
+
+    /* We have a correct id option */
+    tls = SCMalloc(sizeof(DetectTlsData));
+    if (tls == NULL)
+        goto error;
+    tls->fingerprint = NULL;
+    tls->flags = flag;
+
+    orig = SCStrdup((char*)str_ptr);
+    tmp_str=orig;
+    if (tmp_str == NULL) {
+        goto error;
+    }
+
+    /* Let's see if we need to escape "'s */
+    if (tmp_str[0] == '"')
+    {
+        tmp_str[strlen(tmp_str) - 1] = '\0';
+        tmp_str += 1;
+    }
+
+    tls->fingerprint = SCStrdup(tmp_str);
+    if (tls->fingerprint == NULL) {
+        SCLogError(SC_ERR_MEM_ALLOC, "Unable to allocate fingerprint");
+    }
+
+    SCFree(orig);
+
+    SCLogDebug("will look for TLS fingerprint %s", tls->subject);
+
+    return tls;
+
+error:
+    if (tls != NULL)
+        DetectTlsFingerprintFree(tls);
+    return NULL;
+
+}
+/**
+ * \brief match the specified fingerprint on a tls session
+ *
+ * \param t pointer to thread vars
+ * \param det_ctx pointer to the pattern matcher thread
+ * \param p pointer to the current packet
+ * \param m pointer to the sigmatch that we will cast into DetectTlsData
+ *
+ * \retval 0 no match
+ * \retval 1 match
+ */
+static int DetectTlsFingerprintMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, void *state, Signature *s, SigMatch *m)
+{
+    SCEnter();
+    DetectTlsData *tls_data = (DetectTlsData *)m->ctx;
+    SSLState *ssl_state = (SSLState *)state;
+    if (ssl_state == NULL) {
+        SCLogDebug("no tls state, no match");
+        SCReturnInt(0);
+    }
+
+    int ret = 0;
+    FLOWLOCK_RDLOCK(f);
+
+    if (tls_data->flags & DETECT_CONTENT_NEGATED) {
+        ret = 1;
+    } else {
+        ret = 0;
+    }
+    if (ssl_state->server_connp.cert0_fingerprint != NULL) {
+        SCLogDebug("TLS: Fingerprint is [%s], looking for [%s]\n",
+                   ssl_state->server_connp.cert0_fingerprint,
+                   tls_data->fingerprint);
+
+        if (tls_data->fingerprint &&
+            (strstr(ssl_state->server_connp.cert0_fingerprint,
+                    tls_data->fingerprint) != NULL)) {
+            if (tls_data->flags & DETECT_CONTENT_NEGATED) {
+                ret = 0;
+            } else {
+                ret = 1;
+
+            }
+        }
+    }
+
+    FLOWLOCK_UNLOCK(f);
+
+    SCReturnInt(ret);
+}
+
+/**
+ * \brief this function is used to add the parsed "fingerprint" option
+ * \brief into the current signature
+ *
+ * \param de_ctx pointer to the Detection Engine Context
+ * \param s pointer to the Current Signature
+ * \param id pointer to the user provided "fingerprint" option
+ *
+ * \retval 0 on Success
+ * \retval -1 on Failure
+ */
+static int DetectTlsFingerprintSetup (DetectEngineCtx *de_ctx, Signature *s, char *str)
+{
+    DetectTlsData *tls = NULL;
+    SigMatch *sm = NULL;
+
+    tls = DetectTlsFingerprintParse(str);
+    if (tls == NULL) goto error;
+
+    /* Okay so far so good, lets get this into a SigMatch
+     * and put it in the Signature. */
+    sm = SigMatchAlloc();
+    if (sm == NULL)
+        goto error;
+
+    sm->type = DETECT_AL_TLS_FINGERPRINT;
+    sm->ctx = (void *)tls;
+
+    SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_AMATCH);
+
+    if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_TLS) {
+        SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains conflicting keywords.");
+        goto error;
+    }
+
+    s->alproto = ALPROTO_TLS;
+    return 0;
+
+error:
+    if (tls != NULL) DetectTlsFingerprintFree(tls);
+    if (sm != NULL) SCFree(sm);
+    return -1;
+
+}
+
+/**
+ * \brief this function will free memory associated with DetectTlsData
+ *
+ * \param pointer to DetectTlsData
+ */
+static void DetectTlsFingerprintFree(void *ptr) {
+    DetectTlsData *id_d = (DetectTlsData *)ptr;
+    if (id_d->fingerprint)
+        SCFree(id_d->fingerprint);
+    SCFree(id_d);
+}
+
 /**
  * \brief this function registers unit tests for DetectTlsIssuerDN
  */
index 550052e8be11cbc310372349abef80c408020592..71652eb99decfacce8e25cf70e3c954fc77efbc8 100644 (file)
@@ -39,6 +39,7 @@ typedef struct DetectTlsData_ {
     uint32_t flags; /** flags containing match variant (Negation for example) */
     char * subject; /** tls certificate subject substring to match */
     char * issuerdn; /** tls certificate issuerDN substring to match */
+    char * fingerprint; /** tls fingerprint substring to match */
 } DetectTlsData;
 
 /* prototypes */
index 2b0041aafe1244eeaf225216ab1b5a0a8c450341..86ca8d3ff09b956142bd72614837eb6264787107 100644 (file)
@@ -995,6 +995,7 @@ enum {
     DETECT_AL_TLS_VERSION,
     DETECT_AL_TLS_SUBJECT,
     DETECT_AL_TLS_ISSUERDN,
+    DETECT_AL_TLS_FINGERPRINT,
 
     DETECT_AL_HTTP_COOKIE,
     DETECT_AL_HTTP_METHOD,