From: Jean-Paul Roliers Date: Thu, 2 Feb 2012 15:45:35 +0000 (+0100) Subject: tls: adding support for fingerprint rule matching. X-Git-Tag: suricata-1.4beta1~71 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=00d435736268c35ddba7000c47c6e9a72c983358;p=thirdparty%2Fsuricata.git tls: adding support for fingerprint rule matching. Add the support for tls.fingerprint keyword in rules. --- diff --git a/src/detect-tls.c b/src/detect-tls.c index 110f775391..ba88083f7b 100644 --- a/src/detect-tls.c +++ b/src/detect-tls.c @@ -63,12 +63,16 @@ /** * \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 */ diff --git a/src/detect-tls.h b/src/detect-tls.h index 550052e8be..71652eb99d 100644 --- a/src/detect-tls.h +++ b/src/detect-tls.h @@ -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 */ diff --git a/src/detect.h b/src/detect.h index 2b0041aafe..86ca8d3ff0 100644 --- a/src/detect.h +++ b/src/detect.h @@ -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,