#include "stream-tcp.h"
#include "app-layer-ssl.h"
-/**
- * \brief Regex for parsing "id" option, matching number or "number"
- */
-#define PARSE_REGEX "^\\s*(!?[A-z0-9.]+)\\s*,?\\s*(!?[A-z0-9.]+)?\\s*\\,?\\s*" \
- "(!?[A-z0-9.]+)?\\s*,?\\s*(!?[A-z0-9.]+)?\\s*,?\\s*(!?[A-z0-9.]+)?\\s*$"
-
-static DetectParseRegex parse_regex;
static int DetectSslVersionMatch(DetectEngineThreadCtx *,
Flow *, uint8_t, void *, void *,
#ifdef UNITTESTS
sigmatch_table[DETECT_AL_SSL_VERSION].RegisterTests = DetectSslVersionRegisterTests;
#endif
- DetectSetupParseRegexes(PARSE_REGEX, &parse_regex);
g_tls_generic_list_id = DetectBufferTypeRegister("tls_generic");
}
SCReturnInt(ret ^ ((ssl->data[sig_ver].flags & DETECT_SSL_VERSION_NEGATED) ? 1 : 0));
}
+struct SSLVersionKeywords {
+ const char *word;
+ int index;
+ int value;
+};
+
+struct SSLVersionKeywords ssl_version_keywords[TLS_SIZE] = {
+ { "sslv2", SSLv2, SSL_VERSION_2 },
+ { "sslv3", SSLv3, SSL_VERSION_3 },
+ { "tls1.0", TLS10, TLS_VERSION_10 },
+ { "tls1.1", TLS11, TLS_VERSION_11 },
+ { "tls1.2", TLS12, TLS_VERSION_12 },
+ { "tls1.3", TLS13, TLS_VERSION_13 },
+};
+
/**
* \brief This function is used to parse ssl_version data passed via
* keyword: "ssl_version"
static DetectSslVersionData *DetectSslVersionParse(DetectEngineCtx *de_ctx, const char *str)
{
DetectSslVersionData *ssl = NULL;
- int ret = 0, res = 0;
- int ov[MAX_SUBSTRINGS];
+ const char *tmp_str = str;
+ size_t tmp_len = 0;
+ uint8_t found = 0;
- ret = DetectParsePcreExec(&parse_regex, str, 0, 0, ov, MAX_SUBSTRINGS);
- if (ret < 1 || ret > 5) {
- SCLogError(SC_ERR_PCRE_MATCH, "invalid ssl_version option");
+ /* We have a correct ssl_version options */
+ ssl = SCCalloc(1, sizeof(DetectSslVersionData));
+ if (unlikely(ssl == NULL))
goto error;
- }
- if (ret > 1) {
- uint8_t found = 0, neg = 0;
- char *tmp_str;
-
- /* We have a correct ssl_version options */
- ssl = SCCalloc(1, sizeof (DetectSslVersionData));
- if (unlikely(ssl == NULL))
- goto error;
+ // skip leading space
+ while (tmp_str[0] != 0 && isspace(tmp_str[0])) {
+ tmp_str++;
+ }
+ if (tmp_str[0] == 0) {
+ SCLogError(SC_ERR_INVALID_VALUE, "Invalid empty value");
+ goto error;
+ }
+ // iterate every version separated by comma
+ while (tmp_str[0] != 0) {
+ uint8_t neg = 0;
+ if (tmp_str[0] == '!') {
+ neg = 1;
+ tmp_str++;
+ }
+ // counts word length
+ tmp_len = 0;
+ while (tmp_str[tmp_len] != 0 && !isspace(tmp_str[tmp_len]) && tmp_str[tmp_len] != ',') {
+ tmp_len++;
+ }
- int i;
- for (i = 1; i < ret; i++) {
- char ver_ptr[64];
- res = pcre_copy_substring((char *) str, ov, MAX_SUBSTRINGS, i, ver_ptr, sizeof(ver_ptr));
- if (res < 0) {
- SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed");
- if (found == 0)
+ bool is_keyword = false;
+ for (size_t i = 0; i < TLS_SIZE; i++) {
+ if (tmp_len == strlen(ssl_version_keywords[i].word) &&
+ strncasecmp(ssl_version_keywords[i].word, tmp_str, tmp_len) == 0) {
+ if (ssl->data[ssl_version_keywords[i].index].ver != 0) {
+ SCLogError(SC_ERR_INVALID_VALUE, "Invalid duplicate value");
goto error;
- break;
- }
-
- tmp_str = ver_ptr;
-
- /* Let's see if we need to scape "'s */
- if (tmp_str[0] == '"') {
- tmp_str[strlen(tmp_str) - 1] = '\0';
- tmp_str += 1;
- }
-
-
- if (tmp_str[0] == '!') {
- neg = 1;
- tmp_str++;
- }
-
- if (strcasecmp("sslv2", tmp_str) == 0) {
- ssl->data[SSLv2].ver = SSL_VERSION_2;
- if (neg == 1)
- ssl->data[SSLv2].flags |= DETECT_SSL_VERSION_NEGATED;
- } else if (strcasecmp("sslv3", tmp_str) == 0) {
- ssl->data[SSLv3].ver = SSL_VERSION_3;
- if (neg == 1)
- ssl->data[SSLv3].flags |= DETECT_SSL_VERSION_NEGATED;
- } else if (strcasecmp("tls1.0", tmp_str) == 0) {
- ssl->data[TLS10].ver = TLS_VERSION_10;
- if (neg == 1)
- ssl->data[TLS10].flags |= DETECT_SSL_VERSION_NEGATED;
- } else if (strcasecmp("tls1.1", tmp_str) == 0) {
- ssl->data[TLS11].ver = TLS_VERSION_11;
- if (neg == 1)
- ssl->data[TLS11].flags |= DETECT_SSL_VERSION_NEGATED;
- } else if (strcasecmp("tls1.2", tmp_str) == 0) {
- ssl->data[TLS12].ver = TLS_VERSION_12;
+ }
+ ssl->data[ssl_version_keywords[i].index].ver = ssl_version_keywords[i].value;
if (neg == 1)
- ssl->data[TLS12].flags |= DETECT_SSL_VERSION_NEGATED;
- } else if (strcasecmp("tls1.3", tmp_str) == 0) {
- ssl->data[TLS13].ver = TLS_VERSION_13;
- if (neg == 1)
- ssl->data[TLS13].flags |= DETECT_SSL_VERSION_NEGATED;
- } else if (strcmp(tmp_str, "") == 0) {
- if (found == 0)
- goto error;
+ ssl->data[ssl_version_keywords[i].index].flags |= DETECT_SSL_VERSION_NEGATED;
+ is_keyword = true;
break;
- } else {
- SCLogError(SC_ERR_INVALID_VALUE, "Invalid value");
- goto error;
}
+ }
+ if (!is_keyword) {
+ SCLogError(SC_ERR_INVALID_VALUE, "Invalid unknown value");
+ goto error;
+ }
+
+ /* check consistency between negative and positive values :
+ * if there is a negative value, it overrides positive values
+ */
+ if (found == 0) {
+ found |= 1 << neg;
+ } else if (found != 1 << neg) {
+ SCLogError(SC_ERR_INVALID_VALUE, "Invalid value mixing negative and positive forms");
+ goto error;
+ }
- found = 1;
- neg = 0;
+ tmp_str += tmp_len;
+ while (isspace(tmp_str[0]) || tmp_str[0] == ',') {
+ tmp_str++;
}
}
ssl = DetectSslVersionParse(NULL, "2.5");
FAIL_IF_NOT_NULL(ssl);
DetectSslVersionFree(NULL, ssl);
+ ssl = DetectSslVersionParse(NULL, "tls1.0, !");
+ FAIL_IF_NOT_NULL(ssl);
+ DetectSslVersionFree(NULL, ssl);
+ ssl = DetectSslVersionParse(NULL, "tls1.0, !tls1.0");
+ FAIL_IF_NOT_NULL(ssl);
+ DetectSslVersionFree(NULL, ssl);
+ ssl = DetectSslVersionParse(NULL, "tls1.1, tls1.1");
+ FAIL_IF_NOT_NULL(ssl);
+ DetectSslVersionFree(NULL, ssl);
+ ssl = DetectSslVersionParse(NULL, "tls1.1, !tls1.2");
+ FAIL_IF_NOT_NULL(ssl);
+ DetectSslVersionFree(NULL, ssl);
PASS;
}
static int DetectSslVersionTestParse03(void)
{
DetectSslVersionData *ssl = NULL;
- ssl = DetectSslVersionParse(NULL, "SSlv3,tls1.0, !tls1.2");
+ ssl = DetectSslVersionParse(NULL, "SSlv3 , tls1.0");
FAIL_IF_NULL(ssl);
FAIL_IF_NOT(ssl->data[SSLv3].ver == SSL_VERSION_3);
FAIL_IF_NOT(ssl->data[TLS10].ver == TLS_VERSION_10);
+ DetectSslVersionFree(NULL, ssl);
+ ssl = DetectSslVersionParse(NULL, " !tls1.2");
+ FAIL_IF_NULL(ssl);
FAIL_IF_NOT(ssl->data[TLS12].ver == TLS_VERSION_12);
FAIL_IF_NOT(ssl->data[TLS12].flags & DETECT_SSL_VERSION_NEGATED);
DetectSslVersionFree(NULL, ssl);