From 8f8b1212afc714ce2737c842eaf633005b7bbcb0 Mon Sep 17 00:00:00 2001 From: Gurvinder Singh Date: Sun, 2 Jan 2011 18:04:12 +0100 Subject: [PATCH] support for ssl_version keyword --- src/Makefile.am | 1 + src/app-layer-detect-proto.c | 4 +- src/app-layer-protos.h | 3 +- src/app-layer-ssl.c | 182 +++------ src/app-layer-ssl.h | 15 +- src/app-layer-tls.c | 25 +- src/app-layer-tls.h | 8 + src/detect-ssl-version.c | 772 +++++++++++++++++++++++++++++++++++ src/detect-ssl-version.h | 48 +++ src/detect.c | 2 + src/detect.h | 1 + src/suricata.c | 2 - 12 files changed, 932 insertions(+), 131 deletions(-) create mode 100644 src/detect-ssl-version.c create mode 100644 src/detect-ssl-version.h diff --git a/src/Makefile.am b/src/Makefile.am index d92fc89fe2..fa760022f9 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -134,6 +134,7 @@ detect-http-client-body.c detect-http-client-body.h \ detect-http-stat-msg.c detect-http-stat-msg.h \ detect-asn1.c detect-asn1.h \ detect-http-stat-code.c detect-http-stat-code.h \ +detect-ssl-version.c detect-ssl-version.h \ util-atomic.h \ util-print.c util-print.h \ util-fmemopen.c util-fmemopen.h \ diff --git a/src/app-layer-detect-proto.c b/src/app-layer-detect-proto.c index b404c5b9a1..e325691ab3 100644 --- a/src/app-layer-detect-proto.c +++ b/src/app-layer-detect-proto.c @@ -367,8 +367,8 @@ void AppLayerDetectProtoThreadInit(void) { AlpProtoAdd(&alp_proto_ctx, IPPROTO_TCP, ALPROTO_SSH, "SSH-", 4, 0, STREAM_TOSERVER); /** SSLv2 */ - AlpProtoAdd(&alp_proto_ctx, IPPROTO_TCP, ALPROTO_SSL, "|01 00 02|", 5, 2, STREAM_TOSERVER); - AlpProtoAdd(&alp_proto_ctx, IPPROTO_TCP, ALPROTO_SSL, "|00 02|", 7, 5, STREAM_TOCLIENT); + AlpProtoAdd(&alp_proto_ctx, IPPROTO_TCP, ALPROTO_TLS, "|01 00 02|", 5, 2, STREAM_TOSERVER); + AlpProtoAdd(&alp_proto_ctx, IPPROTO_TCP, ALPROTO_TLS, "|00 02|", 7, 5, STREAM_TOCLIENT); /** SSLv3 */ AlpProtoAdd(&alp_proto_ctx, IPPROTO_TCP, ALPROTO_TLS, "|01 03 00|", 3, 0, STREAM_TOSERVER); diff --git a/src/app-layer-protos.h b/src/app-layer-protos.h index 77045d88b8..42be211553 100644 --- a/src/app-layer-protos.h +++ b/src/app-layer-protos.h @@ -29,8 +29,7 @@ enum { ALPROTO_HTTP, ALPROTO_FTP, ALPROTO_SMTP, - ALPROTO_SSL, /* SSLv2 */ - ALPROTO_TLS, /* SSLv3 & TLSv1 */ + ALPROTO_TLS, /* SSLv2, SSLv3 & TLSv1 */ ALPROTO_SSH, ALPROTO_IMAP, ALPROTO_MSN, diff --git a/src/app-layer-ssl.c b/src/app-layer-ssl.c index 3f176c01bb..60b3a0a93f 100644 --- a/src/app-layer-ssl.c +++ b/src/app-layer-ssl.c @@ -43,6 +43,7 @@ #include "app-layer-parser.h" #include "app-layer-ssl.h" +#include "app-layer-tls.h" #include "util-spm.h" #include "util-unittest.h" @@ -54,75 +55,66 @@ /** * \brief Function to parse the SSL field in packet received from the client * - * \param ssl_state Pointer the state in which the value to be stored + * \param app_state Pointer the state in which the value to be stored * \param pstate Application layer tarser state for this session * \param input Pointer the received input data * \param input_len Length in bytes of the received data * \param output Pointer to the list of parsed output elements */ -static int SSLParseClientRecord(Flow *f, void *ssl_state, AppLayerParserState *pstate, +int SSLParseClientRecord(Flow *f, void *app_state, AppLayerParserState *pstate, uint8_t *input, uint32_t input_len, AppLayerParserResult *output) { SCEnter(); SslClient *client = NULL; - SslState *ssl_st = NULL; - - /* SSL client message should be larger than 9 bytes as we need to know, to - what is the SSL version and message type */ - if (input_len < 9) { - SCLogDebug("Input message length (%"PRIu32") is not equal to minimum " - "valid ssl record message length, thus returning", input_len); - SCReturnInt(1); - } + TlsState *app_st = NULL; client = (SslClient *)input; - ssl_st = (SslState *)ssl_state; + app_st = (TlsState *)app_state; switch (client->msg_type) { case SSL_CLIENT_HELLO: if (client->major_ver != 0x02) { - SCLogError(SC_ERR_ALPARSER, "SSL version is not equal to 2, " - "incorrect message!!"); + SCLogDebug("SSL version is not equal to 2, incorrect message!!"); SCReturnInt(-1); } - ssl_st->flags |= SSL_FLAG_CLIENT_HS; - ssl_st->client_content_type = client->msg_type; - ssl_st->client_version = client->minor_ver|client->major_ver; + app_st->flags |= TLS_FLAG_SSL_CLIENT_HS; + app_st->client_content_type = client->msg_type; + app_st->client_version = client->minor_ver|client->major_ver; if (client->session_id_len == 0) { - ssl_st->flags |= SSL_FLAG_NO_SESSION_ID; + app_st->flags |= TLS_FLAG_SSL_NO_SESSION_ID; } SCLogDebug("SSLv2 CLIENT_HELLO message has been received"); break; case SSL_CLIENT_MASTER_KEY: - if ( ! (ssl_st->flags & SSL_FLAG_CLIENT_HS)) { + if ( ! (app_st->flags & TLS_FLAG_SSL_CLIENT_HS)) { SCLogDebug("client hello is not seen before master key " "message!!"); break; } - ssl_st->flags |= SSL_FLAG_CLIENT_MASTER_KEY; - ssl_st->client_content_type = client->msg_type; + app_st->flags |= TLS_FLAG_SSL_CLIENT_MASTER_KEY; + app_st->client_content_type = client->msg_type; SCLogDebug("SSLv2 CLIENT_MASTER_KEY message has been received"); break; case SSL_CLIENT_CERTIFICATE: case SSL_CLIENT_FINISHED: case SSL_REQUEST_CERTIFICATE: - if ((ssl_st->flags & SSL_FLAG_CLIENT_HS) && - (ssl_st->flags & SSL_FLAG_SERVER_HS)) + if ((app_st->flags & TLS_FLAG_SSL_CLIENT_HS) && + (app_st->flags & TLS_FLAG_SSL_SERVER_HS)) { - if (ssl_st->flags & SSL_FLAG_NO_SESSION_ID) { - ssl_st->flags |= SSL_FLAG_CLIENT_SSN_ENCRYPTED; + if (app_st->flags & TLS_FLAG_SSL_NO_SESSION_ID) { + app_st->flags |= TLS_FLAG_SSL_CLIENT_SSN_ENCRYPTED; SCLogDebug("SSLv2 Client side has started the encryption"); - } else if (ssl_st->flags & SSL_FLAG_CLIENT_MASTER_KEY) { - ssl_st->flags |= SSL_FLAG_CLIENT_SSN_ENCRYPTED; + } else if (app_st->flags & TLS_FLAG_SSL_CLIENT_MASTER_KEY) { + app_st->flags |= TLS_FLAG_SSL_CLIENT_SSN_ENCRYPTED; SCLogDebug("SSLv2 Client side has started the encryption"); } - if ((ssl_st->flags & SSL_FLAG_CLIENT_SSN_ENCRYPTED) && - (ssl_st->flags & SSL_FLAG_SERVER_SSN_ENCRYPTED)) + if ((app_st->flags & TLS_FLAG_SSL_CLIENT_SSN_ENCRYPTED) && + (app_st->flags & TLS_FLAG_SSL_SERVER_SSN_ENCRYPTED)) { pstate->flags |= APP_LAYER_PARSER_DONE; pstate->flags |= APP_LAYER_PARSER_NO_INSPECTION; @@ -130,16 +122,18 @@ static int SSLParseClientRecord(Flow *f, void *ssl_state, AppLayerParserState *p SCLogDebug("SSLv2 No reassembly & inspection has been set"); } } - ssl_st->client_content_type = client->msg_type; + app_st->client_content_type = client->msg_type; break; case SSL_ERROR: - SCLogError(SC_ERR_ALPARSER, "Error encountered in establishing the " - "sslv2 session"); + SCLogWarning(SC_ERR_ALPARSER, "Error encountered in establishing the " + "sslv2 session, may be tls version"); SCReturnInt(-1); default: - SCLogError(SC_ERR_ALPARSER, "Incorrect message type (%"PRIu8") " - "while establishing the sslv2 session", client->msg_type); + SCLogDebug("Incorrect message type (%"PRIu8") " + "while establishing the sslv2 session, may be tls version", + client->msg_type); + SCReturnInt(-1); break; } SCReturnInt(1); @@ -148,51 +142,43 @@ static int SSLParseClientRecord(Flow *f, void *ssl_state, AppLayerParserState *p /** * \brief Function to parse the SSL field in packet received from the server * - * \param ssl_state Pointer the state in which the value to be stored + * \param app_state Pointer the state in which the value to be stored * \param pstate Application layer tarser state for this session * \param input Pointer the received input data * \param input_len Length in bytes of the received data * \param output Pointer to the list of parsed output elements */ -static int SSLParseServerRecord(Flow *f, void *ssl_state, AppLayerParserState *pstate, +int SSLParseServerRecord(Flow *f, void *app_state, AppLayerParserState *pstate, uint8_t *input, uint32_t input_len, AppLayerParserResult *output) { - SCEnter(); SCEnter(); SslServer *server = (SslServer *)input; - SslState *ssl_st = (SslState *)ssl_state; - - if (input_len < 7) { - SCLogDebug("Input message lentgh (%"PRIu32") is not equal to minimum " - "valid ssl record message length, thus returning!!", input_len); - SCReturnInt(1); - } + TlsState *app_st = (TlsState *)app_state; switch (server->msg_type) { case SSL_SERVER_HELLO: if (server->major_ver != 0x02) { - SCLogError(SC_ERR_ALPARSER, "SSL version is not equal to 2, " - "incorrect message!!"); + SCLogDebug("SSL version is not equal to 2, incorrect message!!"); SCReturnInt(-1); } SCLogDebug("SSLv2 SERVER_HELLO message has been received"); - ssl_st->flags |= SSL_FLAG_SERVER_HS; - ssl_st->server_content_type = server->msg_type; - ssl_st->server_version = server->minor_ver|server->major_ver; + app_st->flags |= TLS_FLAG_SSL_SERVER_HS; + app_st->server_content_type = server->msg_type; + app_st->server_version = server->minor_ver|server->major_ver; break; case SSL_SERVER_VERIFY: case SSL_SERVER_FINISHED: case SSL_REQUEST_CERTIFICATE: - if ((ssl_st->flags & SSL_FLAG_SERVER_HS) && - (ssl_st->flags & SSL_FLAG_CLIENT_HS)) + if ((app_st->flags & TLS_FLAG_SSL_SERVER_HS) && + (app_st->flags & TLS_FLAG_SSL_CLIENT_HS)) { - ssl_st->flags |= SSL_FLAG_SERVER_SSN_ENCRYPTED; + app_st->flags |= TLS_FLAG_SSL_SERVER_SSN_ENCRYPTED; SCLogDebug("SSLv2 Server side has started the encryption"); - if ((ssl_st->flags & SSL_FLAG_CLIENT_SSN_ENCRYPTED) && - (ssl_st->flags & SSL_FLAG_SERVER_SSN_ENCRYPTED)) + if ((app_st->flags & TLS_FLAG_SSL_CLIENT_SSN_ENCRYPTED) && + (app_st->flags & TLS_FLAG_SSL_SERVER_SSN_ENCRYPTED)) { pstate->flags |= APP_LAYER_PARSER_DONE; pstate->flags |= APP_LAYER_PARSER_NO_INSPECTION; @@ -200,57 +186,23 @@ static int SSLParseServerRecord(Flow *f, void *ssl_state, AppLayerParserState *p SCLogDebug("SSLv2 No reassembly & inspection has been set"); } } - ssl_st->server_content_type = server->msg_type; + app_st->server_content_type = server->msg_type; break; case SSL_ERROR: - SCLogError(SC_ERR_ALPARSER, "Error encountered in establishing the " - "sslv2 session"); + SCLogWarning(SC_ERR_ALPARSER, "Error encountered in establishing the " + "sslv2 session, may be tls version"); SCReturnInt(-1); default: - SCLogError(SC_ERR_ALPARSER, "Incorrect message type (%"PRIu8") " - "while establishing the sslv2 session", server->msg_type); + SCLogDebug("Incorrect message type (%"PRIu8") " + "while establishing the sslv2 session, may be tls version", + server->msg_type); + SCReturnInt(-1); break; } SCReturnInt(1); } -/** \brief Function to allocates the TLS state memory - */ -static void *SSLStateAlloc(void) -{ - SCEnter(); - void *s = SCMalloc(sizeof(SslState)); - if (s == NULL) - return NULL; - - memset(s, 0, sizeof(SslState)); - SCReturnPtr(s, "SslState"); -} - -/** \brief Function to free the TLS state memory - */ -static void SSLStateFree(void *s) -{ - SCEnter(); - SCFree(s); - SCReturn; -} - -/** \brief Function to register the SSL protocol parsers and other functions - */ -void RegisterSSLParsers(void) -{ - AppLayerRegisterProto("ssl", ALPROTO_SSL, STREAM_TOSERVER, - SSLParseClientRecord); - - AppLayerRegisterProto("ssl", ALPROTO_SSL, STREAM_TOCLIENT, - SSLParseServerRecord); - - AppLayerRegisterStateFuncs(ALPROTO_SSL, SSLStateAlloc, SSLStateFree); - -} - #ifdef UNITTESTS #include "util-unittest-helper.h" #include "stream-tcp-reassemble.h" @@ -277,27 +229,27 @@ static int SSLParserTest01(void) { StreamTcpInitConfig(TRUE); FlowL7DataPtrInit(&f); - int r = AppLayerParse(&f, ALPROTO_SSL, STREAM_TOSERVER|STREAM_EOF, sslbuf, ssllen); + int r = AppLayerParse(&f, ALPROTO_TLS, STREAM_TOSERVER|STREAM_EOF, sslbuf, ssllen); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); goto end; } - SslState *ssl_state = f.aldata[AlpGetStateIdx(ALPROTO_SSL)]; - if (ssl_state == NULL) { + TlsState *app_state = f.aldata[AlpGetStateIdx(ALPROTO_TLS)]; + if (app_state == NULL) { printf("no ssl state: "); goto end; } - if (ssl_state->client_content_type != 0x1) { + if (app_state->client_content_type != 0x1) { printf("expected content_type %" PRIu8 ", got %" PRIu8 ": ", 0x1, - ssl_state->client_content_type); + app_state->client_content_type); goto end; } - if (ssl_state->client_version != SSL_CLIENT_VERSION) { + if (app_state->client_version != SSL_CLIENT_VERSION) { printf("expected version %04" PRIu16 ", got %04" PRIu16 ": ", - SSL_CLIENT_VERSION, ssl_state->client_version); + SSL_CLIENT_VERSION, app_state->client_version); goto end; } @@ -332,30 +284,30 @@ static int SSLParserTest02(void) { StreamTcpInitConfig(TRUE); FlowL7DataPtrInit(&f); - int r = AppLayerParse(&f, ALPROTO_SSL, STREAM_TOCLIENT|STREAM_EOF, sslbuf, ssllen); + int r = AppLayerParse(&f, ALPROTO_TLS, STREAM_TOCLIENT|STREAM_EOF, sslbuf, ssllen); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } - SslState *ssl_state = f.aldata[AlpGetStateIdx(ALPROTO_SSL)]; - if (ssl_state == NULL) { + TlsState *app_state = f.aldata[AlpGetStateIdx(ALPROTO_TLS)]; + if (app_state == NULL) { printf("no ssl state: "); result = 0; goto end; } - if (ssl_state->server_content_type != SSL_SERVER_HELLO) { + if (app_state->server_content_type != SSL_SERVER_HELLO) { printf("expected content_type %" PRIu8 ", got %" PRIu8 ": ", - SSL_SERVER_HELLO, ssl_state->client_content_type); + SSL_SERVER_HELLO, app_state->client_content_type); result = 0; goto end; } - if (ssl_state->server_version != SSL_SERVER_VERSION) { + if (app_state->server_version != SSL_SERVER_VERSION) { printf("expected version %04" PRIu16 ", got %04" PRIu16 ": ", - SSL_SERVER_VERSION, ssl_state->client_version); + SSL_SERVER_VERSION, app_state->client_version); result = 0; goto end; } @@ -658,23 +610,23 @@ static int SSLParserTest03(void) { goto end; } - SslState *ssl_state = f.aldata[AlpGetStateIdx(ALPROTO_SSL)]; - if (ssl_state == NULL) { + TlsState *app_state = f.aldata[AlpGetStateIdx(ALPROTO_TLS)]; + if (app_state == NULL) { printf("no ssl state: "); result = 0; goto end; } - if (ssl_state->client_content_type != 0x7) { + if (app_state->client_content_type != 0x7) { printf("expected content_type %" PRIu8 ", got %" PRIu8 ": ", 0x7, - ssl_state->client_content_type); + app_state->client_content_type); result = 0; goto end; } - if (ssl_state->client_version != SSL_CLIENT_VERSION) { + if (app_state->client_version != SSL_CLIENT_VERSION) { printf("expected version %04" PRIu16 ", got %04" PRIu16 ": ", - SSL_CLIENT_VERSION, ssl_state->client_version); + SSL_CLIENT_VERSION, app_state->client_version); result = 0; goto end; } diff --git a/src/app-layer-ssl.h b/src/app-layer-ssl.h index 91a0f2b5e0..05d2a60dbf 100644 --- a/src/app-layer-ssl.h +++ b/src/app-layer-ssl.h @@ -27,14 +27,6 @@ #define SSL_CLIENT_VERSION 0x0002 #define SSL_SERVER_VERSION 0x0002 -/* SSL state flags */ -#define SSL_FLAG_CLIENT_HS 0x01 -#define SSL_FLAG_SERVER_HS 0x02 -#define SSL_FLAG_CLIENT_MASTER_KEY 0x04 -#define SSL_FLAG_CLIENT_SSN_ENCRYPTED 0x08 -#define SSL_FLAG_SERVER_SSN_ENCRYPTED 0x10 -#define SSL_FLAG_NO_SESSION_ID 0x20 - /* SSL message types */ #define SSL_ERROR 0 #define SSL_CLIENT_HELLO 1 @@ -75,7 +67,12 @@ typedef struct SslServer_ { uint8_t major_ver; } SslServer; -void RegisterSSLParsers(void); +int SSLParseClientRecord(Flow *, void *, AppLayerParserState *, uint8_t *, + uint32_t , AppLayerParserResult *); + +int SSLParseServerRecord(Flow *, void *, AppLayerParserState *, uint8_t *, + uint32_t , AppLayerParserResult *); + void SSLParserRegisterTests(void); #endif /* _APP_LAYER_SSL_H */ diff --git a/src/app-layer-tls.c b/src/app-layer-tls.c index 5ff206d99f..06028bbe4d 100644 --- a/src/app-layer-tls.c +++ b/src/app-layer-tls.c @@ -42,6 +42,7 @@ #include "app-layer-protos.h" #include "app-layer-parser.h" #include "app-layer-tls.h" +#include "app-layer-ssl.h" #include "conf.h" @@ -165,7 +166,7 @@ static int TLSParseClientVersion(Flow *f, void *tls_state, AppLayerParserState * * \brief Function to parse the TLS field in packet received from the client * * \param tls_state Pointer the state in which the value to be stored - * \param pstate Application layer tarser state for this session + * \param pstate Application layer parser state for this session * \param input Pointer the received input data * \param input_len Length in bytes of the received data * \param output Pointer to the list of parsed output elements @@ -176,6 +177,17 @@ static int TLSParseClientRecord(Flow *f, void *tls_state, AppLayerParserState *p { SCEnter(); + /* SSL client message should be larger than 9 bytes as we need to know, to + what is the SSL version and message type */ + if (input_len >= 9) { + if (SSLParseClientRecord(f, tls_state, pstate, input, input_len, output) + == 1) + { + SCLogDebug("it seems the ssl version 2 is detected"); + SCReturnInt(1); + } + } + SCLogDebug("tls_state %p, pstate %p, input %p,input_len %" PRIu32 "", tls_state, pstate, input, input_len); //PrintRawDataFp(stdout, input,input_len); @@ -301,6 +313,15 @@ static int TLSParseServerRecord(Flow *f, void *tls_state, AppLayerParserState *p { SCEnter(); + if (input_len >= 7) { + if (SSLParseServerRecord(f, tls_state, pstate, input, input_len, output) + == 1) + { + SCLogDebug("it seems the ssl version 2 is detected"); + SCReturnInt(1); + } + } + SCLogDebug("tls_state %p, pstate %p, input %p,input_len %" PRIu32 "", tls_state, pstate, input, input_len); //PrintRawDataFp(stdout, input,input_len); @@ -1372,5 +1393,7 @@ void TLSParserRegisterTests(void) { UtRegisterTest("TLSParserMultimsgTest01", TLSParserMultimsgTest01, 1); UtRegisterTest("TLSParserMultimsgTest02", TLSParserMultimsgTest02, 1); + + SSLParserRegisterTests(); #endif /* UNITTESTS */ } diff --git a/src/app-layer-tls.h b/src/app-layer-tls.h index 22cfd507dc..df0d8f5111 100644 --- a/src/app-layer-tls.h +++ b/src/app-layer-tls.h @@ -32,6 +32,13 @@ client will now on sends encrypted msgs. */ +#define TLS_FLAG_SSL_CLIENT_HS 0x04 /**< SSL state flags */ +#define TLS_FLAG_SSL_SERVER_HS 0x08 +#define TLS_FLAG_SSL_CLIENT_MASTER_KEY 0x10 +#define TLS_FLAG_SSL_CLIENT_SSN_ENCRYPTED 0x20 +#define TLS_FLAG_SSL_SERVER_SSN_ENCRYPTED 0x40 +#define TLS_FLAG_SSL_NO_SESSION_ID 0x80 + enum { TLS_FIELD_NONE = 0, @@ -59,6 +66,7 @@ typedef struct TlsState_ { enum { TLS_VERSION_INVALID = 0x0000, TLS_VERSION_VALID = 0x0001, + SSL_VERSION_2 = 0x0002, SSL_VERSION_3 = 0x0300, TLS_VERSION_10 = 0x0301, TLS_VERSION_11 = 0x0302, diff --git a/src/detect-ssl-version.c b/src/detect-ssl-version.c new file mode 100644 index 0000000000..3a785807f8 --- /dev/null +++ b/src/detect-ssl-version.c @@ -0,0 +1,772 @@ +/* Copyright (C) 2007-2010 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 detect-ssl-version.c + * + * \author Gurvinder Singh + * + * Implements the ssl_version 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-engine-state.h" + +#include "flow.h" +#include "flow-var.h" +#include "flow-util.h" + +#include "util-debug.h" +#include "util-unittest.h" +#include "util-unittest-helper.h" + +#include "app-layer.h" +#include "app-layer-tls.h" + +#include "detect-ssl-version.h" + +#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 pcre *parse_regex; +static pcre_extra *parse_regex_study; + +int DetectSslVersionMatch (ThreadVars *, DetectEngineThreadCtx *, Flow *, + uint8_t, void *, Signature *, SigMatch *); +static int DetectSslVersionSetup (DetectEngineCtx *, Signature *, char *); +void DetectSslVersionRegisterTests(void); +void DetectSslVersionFree(void *); + +/** + * \brief Registration function for keyword: ssl_version + */ +void DetectSslVersionRegister (void) { + sigmatch_table[DETECT_AL_SSL_VERSION].name = "ssl_version"; + sigmatch_table[DETECT_AL_SSL_VERSION].Match = NULL; + sigmatch_table[DETECT_AL_SSL_VERSION].AppLayerMatch = DetectSslVersionMatch; + sigmatch_table[DETECT_AL_SSL_VERSION].alproto = ALPROTO_TLS; + sigmatch_table[DETECT_AL_SSL_VERSION].Setup = DetectSslVersionSetup; + sigmatch_table[DETECT_AL_SSL_VERSION].Free = DetectSslVersionFree; + sigmatch_table[DETECT_AL_SSL_VERSION].RegisterTests = DetectSslVersionRegisterTests; + + const char *eb; + int eo; + int opts = 0; + + SCLogDebug("registering ssl_version rule option"); + + parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL); + if (parse_regex == NULL) { + SCLogError(SC_ERR_PCRE_COMPILE, "Compile of \"%s\" failed at offset %" PRId32 ": %s", + PARSE_REGEX, eo, eb); + goto error; + } + + parse_regex_study = pcre_study(parse_regex, 0, &eb); + if (eb != NULL) { + SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); + goto error; + } + return; + +error: + return; +} + +/** + * \brief match the specified version on a ssl 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 DetectSslVersionData + * + * \retval 0 no match + * \retval 1 match + */ +int DetectSslVersionMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, + Flow *f, uint8_t flags, void *state, Signature *s, SigMatch *m) +{ + SCEnter(); + + DetectSslVersionData *ssl = (DetectSslVersionData *)m->ctx; + TlsState *app_state = (TlsState *)state; + if (app_state == NULL) { + SCLogDebug("no app state, no match"); + SCReturnInt(0); + } + + if (ssl == NULL) { + SCLogDebug("no ssl_version data, no match"); + SCReturnInt(0); + } + + SCMutexLock(&f->m); + int ret = 0; + uint16_t ver = 0; + uint8_t sig_ver = -1; + if (flags & STREAM_TOCLIENT) { + SCLogDebug("server (toclient) version is 0x%02X", + app_state->server_version); + ver = app_state->server_version; + } else if (flags & STREAM_TOSERVER) { + SCLogDebug("client (toserver) version is 0x%02X", + app_state->client_version); + ver = app_state->client_version; + } + switch(ver) { + case SSL_VERSION_2: + if (ver == ssl->data[SSLv2].ver) + ret = 1; + sig_ver = SSLv2; + break; + case SSL_VERSION_3: + if (ver == ssl->data[SSLv3].ver) + ret = 1; + sig_ver = SSLv3; + break; + case TLS_VERSION_10: + if (ver == ssl->data[TLS10].ver) + ret = 1; + sig_ver = TLS10; + break; + case TLS_VERSION_11: + if (ver == ssl->data[TLS11].ver) + ret = 1; + sig_ver = TLS11; + break; + case TLS_VERSION_12: + if (ver == ssl->data[TLS12].ver) + ret = 1; + sig_ver = TLS12; + break; + } + + SCMutexUnlock(&f->m); + + SCReturnInt(ret ^ ((ssl->data[sig_ver].flags & DETECT_SSL_VERSION_NEGATED) ? 1 : 0)); +} + +/** + * \brief This function is used to parse ssl_version data passed via + * keyword: "ssl_version" + * + * \param str Pointer to the user provided options + * + * \retval ssl pointer to DetectSslVersionData on success + * \retval NULL on failure + */ +DetectSslVersionData *DetectSslVersionParse (char *str) +{ + DetectSslVersionData *ssl = NULL; + #define MAX_SUBSTRINGS 30 + int ret = 0, res = 0; + int ov[MAX_SUBSTRINGS]; + + ret = pcre_exec(parse_regex, parse_regex_study, str, strlen(str), 0, 0, + ov, MAX_SUBSTRINGS); + + if (ret < 1 || ret > 5) { + SCLogError(SC_ERR_PCRE_MATCH, "invalid ssl_version option"); + goto error; + } + + if (ret > 1) { + const char *str_ptr[5]; + char *orig; + uint8_t found = 0, neg = 0; + char *tmp_str; + + /* We have a correct ssl_version options */ + ssl = SCCalloc(1, sizeof (DetectSslVersionData)); + if (ssl == NULL) + goto error; + + for (int i = 1; i <= 5; i++) { + res = pcre_get_substring((char *) str, ov, MAX_SUBSTRINGS, i, &str_ptr[i]); + if (res < 0) { + SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); + if (found == 0) + goto error; + break; + } + + orig = SCStrdup((char*) str_ptr[i]); + tmp_str = orig; + if (tmp_str == NULL) { + goto error; + } + + /* 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 (strncasecmp("sslv2", tmp_str, 5) == 0) { + ssl->data[SSLv2].ver = SSL_VERSION_2; + if (neg == 1) + ssl->data[SSLv2].flags |= DETECT_SSL_VERSION_NEGATED; + } else if (strncasecmp("sslv3", tmp_str, 5) == 0) { + ssl->data[SSLv3].ver = SSL_VERSION_3; + if (neg == 1) + ssl->data[SSLv3].flags |= DETECT_SSL_VERSION_NEGATED; + } else if (strncasecmp("tls1.0", tmp_str, 6) == 0) { + ssl->data[TLS10].ver = TLS_VERSION_10; + if (neg == 1) + ssl->data[TLS10].flags |= DETECT_SSL_VERSION_NEGATED; + } else if (strncasecmp("tls1.1", tmp_str, 6) == 0) { + ssl->data[TLS11].ver = TLS_VERSION_11; + if (neg == 1) + ssl->data[TLS11].flags |= DETECT_SSL_VERSION_NEGATED; + } else if (strncasecmp("tls1.2", tmp_str, 6) == 0) { + ssl->data[TLS12].ver = TLS_VERSION_12; + if (neg == 1) + ssl->data[TLS12].flags |= DETECT_SSL_VERSION_NEGATED; + } else if (strcmp(tmp_str, "") == 0) { + SCFree(orig); + if (found == 0) + goto error; + break; + } else { + SCLogError(SC_ERR_INVALID_VALUE, "Invalid value"); + neg = 0; + SCFree(orig); + continue; + } + + found = 1; + neg = 0; + SCFree(orig); + } + } + + return ssl; + +error: + if (ssl != NULL) + DetectSslVersionFree(ssl); + return NULL; + +} + +/** + * \brief this function is used to add the parsed "id" option + * \brief into the current signature + * + * \param de_ctx pointer to the Detection Engine Context + * \param s pointer to the Current Signature + * \param idstr pointer to the user provided "id" option + * + * \retval 0 on Success + * \retval -1 on Failure + */ +static int DetectSslVersionSetup (DetectEngineCtx *de_ctx, Signature *s, char *str) +{ + DetectSslVersionData *ssl = NULL; + SigMatch *sm = NULL; + + ssl = DetectSslVersionParse(str); + if (ssl == 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_SSL_VERSION; + sm->ctx = (void *)ssl; + + SigMatchAppendAppLayer(s, sm); + + 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 (ssl != NULL) DetectSslVersionFree(ssl); + if (sm != NULL) SCFree(sm); + return -1; + +} + +/** + * \brief this function will free memory associated with DetectSslVersionData + * + * \param id_d pointer to DetectSslVersionData + */ +void DetectSslVersionFree(void *ptr) { + DetectSslVersionData *svd = (DetectSslVersionData *)ptr; + SCFree(svd); +} + +#ifdef UNITTESTS /* UNITTESTS */ + +/** + * \test DetectSslVersionTestParse01 is a test to make sure that we parse the + * "ssl_version" option correctly when given valid ssl_version option + */ +int DetectSslVersionTestParse01 (void) { + DetectSslVersionData *ssl = NULL; + ssl = DetectSslVersionParse("SSlv3"); + if (ssl != NULL && ssl->data[SSLv3].ver == SSL_VERSION_3) { + DetectSslVersionFree(ssl); + return 1; + } + + return 0; +} + +/** + * \test DetectSslVersionTestParse02 is a test to make sure that we parse the + * "ssl_version" option correctly when given an invalid ssl_version option + * it should return ssl = NULL + */ +int DetectSslVersionTestParse02 (void) { + DetectSslVersionData *ssl = NULL; + ssl = DetectSslVersionParse("2.5"); + if (ssl == NULL) { + DetectSslVersionFree(ssl); + return 1; + } + + return 0; +} + +/** + * \test DetectSslVersionTestParse03 is a test to make sure that we parse the + * "ssl_version" options correctly when given valid ssl_version options + */ +int DetectSslVersionTestParse03 (void) { + DetectSslVersionData *ssl = NULL; + ssl = DetectSslVersionParse("SSlv3,tls1.0, !tls1.2"); + if (ssl != NULL && ssl->data[SSLv3].ver == SSL_VERSION_3 && + ssl->data[TLS10].ver == TLS_VERSION_10 && + ssl->data[TLS12].ver == TLS_VERSION_12 && + ssl->data[TLS12].flags & DETECT_SSL_VERSION_NEGATED) + { + DetectSslVersionFree(ssl); + return 1; + } + + return 0; +} + +#include "stream-tcp-reassemble.h" + +/** \test Send a get request in three chunks + more data. */ +static int DetectSslVersionTestDetect01(void) { + int result = 0; + Flow f; + uint8_t sslbuf1[] = { 0x16 }; + uint32_t ssllen1 = sizeof(sslbuf1); + uint8_t sslbuf2[] = { 0x03 }; + uint32_t ssllen2 = sizeof(sslbuf2); + uint8_t sslbuf3[] = { 0x01 }; + uint32_t ssllen3 = sizeof(sslbuf3); + uint8_t sslbuf4[] = { 0x01, 0x00, 0x00, 0xad, 0x03, 0x01 }; + uint32_t ssllen4 = sizeof(sslbuf4); + TcpSession ssn; + Packet *p = NULL; + Signature *s = NULL; + ThreadVars th_v; + DetectEngineThreadCtx *det_ctx = NULL; + + memset(&th_v, 0, sizeof(th_v)); + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + p->flow = &f; + p->flowflags |= FLOW_PKT_TOSERVER; + p->flowflags |= FLOW_PKT_ESTABLISHED; + p->flags |= PKT_HAS_FLOW; + f.alproto = ALPROTO_TLS; + + StreamTcpInitConfig(TRUE); + FlowL7DataPtrInit(&f); + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) { + goto end; + } + + de_ctx->flags |= DE_QUIET; + + s = de_ctx->sig_list = SigInit(de_ctx,"alert tls any any -> any any (msg:\"TLS\"; ssl_version:tls1.0; sid:1;)"); + if (s == NULL) { + goto end; + } + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + int r = AppLayerParse(&f, ALPROTO_TLS, STREAM_TOSERVER, sslbuf1, ssllen1); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + goto end; + } + + r = AppLayerParse(&f, ALPROTO_TLS, STREAM_TOSERVER, sslbuf2, ssllen2); + if (r != 0) { + printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); + goto end; + } + + r = AppLayerParse(&f, ALPROTO_TLS, STREAM_TOSERVER, sslbuf3, ssllen3); + if (r != 0) { + printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); + goto end; + } + + r = AppLayerParse(&f, ALPROTO_TLS, STREAM_TOSERVER, sslbuf4, ssllen4); + if (r != 0) { + printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); + goto end; + } + + TlsState *app_state = f.aldata[AlpGetStateIdx(ALPROTO_TLS)]; + if (app_state == NULL) { + printf("no ssl state: "); + goto end; + } + + if (app_state->client_content_type != 0x16) { + printf("expected content_type %" PRIu8 ", got %" PRIu8 ": ", 0x16, app_state->client_content_type); + goto end; + } + + if (app_state->client_version != TLS_VERSION_10) { + printf("expected version %04" PRIu16 ", got %04" PRIu16 ": ", TLS_VERSION_10, app_state->client_version); + goto end; + } + + SCLogDebug("app_state is at %p, app_state->server_version 0x%02X app_state->client_version 0x%02X", + app_state, app_state->server_version, app_state->client_version); + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + + if (!(PacketAlertCheck(p, 1))) { + goto end; + } + + result = 1; +end: + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + DetectEngineCtxFree(de_ctx); + + FlowL7DataPtrFree(&f); + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + + UTHFreePackets(&p, 1); + return result; +} + +static int DetectSslVersionTestDetect02(void) { + int result = 0; + Flow f; + uint8_t sslbuf1[] = { 0x16 }; + uint32_t ssllen1 = sizeof(sslbuf1); + uint8_t sslbuf2[] = { 0x03 }; + uint32_t ssllen2 = sizeof(sslbuf2); + uint8_t sslbuf3[] = { 0x01 }; + uint32_t ssllen3 = sizeof(sslbuf3); + uint8_t sslbuf4[] = { 0x01, 0x00, 0x00, 0xad, 0x03, 0x02 }; + uint32_t ssllen4 = sizeof(sslbuf4); + TcpSession ssn; + Packet *p = NULL; + Signature *s = NULL; + ThreadVars th_v; + DetectEngineThreadCtx *det_ctx = NULL; + + memset(&th_v, 0, sizeof(th_v)); + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + p->flow = &f; + p->flowflags |= FLOW_PKT_TOSERVER; + p->flowflags |= FLOW_PKT_ESTABLISHED; + p->flags |= PKT_HAS_FLOW; + f.alproto = ALPROTO_TLS; + + StreamTcpInitConfig(TRUE); + FlowL7DataPtrInit(&f); + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) { + goto end; + } + + de_ctx->flags |= DE_QUIET; + + s = de_ctx->sig_list = SigInit(de_ctx,"alert tls any any -> any any (msg:\"TLS\"; ssl_version:tls1.0; sid:1;)"); + if (s == NULL) { + goto end; + } + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + int r = AppLayerParse(&f, ALPROTO_TLS, STREAM_TOSERVER, sslbuf1, ssllen1); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + goto end; + } + + r = AppLayerParse(&f, ALPROTO_TLS, STREAM_TOSERVER, sslbuf2, ssllen2); + if (r != 0) { + printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); + goto end; + } + + r = AppLayerParse(&f, ALPROTO_TLS, STREAM_TOSERVER, sslbuf3, ssllen3); + if (r != 0) { + printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); + goto end; + } + + r = AppLayerParse(&f, ALPROTO_TLS, STREAM_TOSERVER, sslbuf4, ssllen4); + if (r != 0) { + printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); + goto end; + } + + TlsState *app_state = f.aldata[AlpGetStateIdx(ALPROTO_TLS)]; + if (app_state == NULL) { + printf("no ssl state: "); + goto end; + } + + if (app_state->client_content_type != 0x16) { + printf("expected content_type %" PRIu8 ", got %" PRIu8 ": ", 0x16, app_state->client_content_type); + goto end; + } + + if (app_state->client_version != TLS_VERSION_10) { + printf("expected version %04" PRIu16 ", got %04" PRIu16 ": ", TLS_VERSION_10, app_state->client_version); + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + + if (!(PacketAlertCheck(p, 1))) { + printf("signature 1 didn't match while it should have: "); + goto end; + } + + result = 1; +end: + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + DetectEngineCtxFree(de_ctx); + + FlowL7DataPtrFree(&f); + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + + UTHFreePackets(&p, 1); + return result; +} + +static int DetectSslVersionTestDetect03(void) { + DetectEngineCtx *de_ctx = NULL; + int result = 0; + Flow f; + uint8_t sslbuf1[] = { 0x16 }; + uint32_t ssllen1 = sizeof(sslbuf1); + uint8_t sslbuf2[] = { 0x03 }; + uint32_t ssllen2 = sizeof(sslbuf2); + uint8_t sslbuf3[] = { 0x01 }; + uint32_t ssllen3 = sizeof(sslbuf3); + uint8_t sslbuf4[] = { 0x01, 0x00, 0x00, 0xad, 0x03, 0x02 }; + uint32_t ssllen4 = sizeof(sslbuf4); + TcpSession ssn; + Packet *p = NULL; + Signature *s = NULL; + ThreadVars th_v; + DetectEngineThreadCtx *det_ctx = NULL; + + memset(&th_v, 0, sizeof(th_v)); + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + p->tcph->th_seq = htonl(1000); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + p->flow = &f; + p->flowflags |= FLOW_PKT_TOSERVER; + p->flowflags |= FLOW_PKT_ESTABLISHED; + p->flags |= PKT_HAS_FLOW; + f.alproto = ALPROTO_TLS; + f.proto = p->proto; + + StreamTcpInitConfig(TRUE); + FlowL7DataPtrInit(&f); + + StreamMsg *stream_msg = StreamMsgGetFromPool(); + if (stream_msg == NULL) { + printf("no stream_msg: "); + goto end; + } + + memcpy(stream_msg->data.data, sslbuf4, ssllen4); + stream_msg->data.data_len = ssllen4; + + ssn.toserver_smsg_head = stream_msg; + ssn.toserver_smsg_tail = stream_msg; + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) { + goto end; + } + + de_ctx->flags |= DE_QUIET; + + s = de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"TLS\"; ssl_version:tls1.0; content:\"|01 00 00 AD|\"; sid:1;)"); + if (s == NULL) { + goto end; + } + + if (s->flags & SIG_FLAG_PACKET) { + SCLogDebug("SIG_FLAG_PACKET flags"); + } + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + int r = AppLayerParse(&f, ALPROTO_TLS, STREAM_TOSERVER, sslbuf1, ssllen1); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + goto end; + } + + r = AppLayerParse(&f, ALPROTO_TLS, STREAM_TOSERVER, sslbuf2, ssllen2); + if (r != 0) { + printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); + goto end; + } + + r = AppLayerParse(&f, ALPROTO_TLS, STREAM_TOSERVER, sslbuf3, ssllen3); + if (r != 0) { + printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); + goto end; + } + + r = AppLayerParse(&f, ALPROTO_TLS, STREAM_TOSERVER, sslbuf4, ssllen4); + if (r != 0) { + printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); + goto end; + } + + TlsState *app_state = f.aldata[AlpGetStateIdx(ALPROTO_TLS)]; + if (app_state == NULL) { + printf("no ssl state: "); + goto end; + } + + if (app_state->client_content_type != 0x16) { + printf("expected content_type %" PRIu8 ", got %" PRIu8 ": ", 0x16, app_state->client_content_type); + goto end; + } + + if (app_state->client_version != TLS_VERSION_10) { + printf("expected version %04" PRIu16 ", got %04" PRIu16 ": ", TLS_VERSION_10, app_state->client_version); + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + + if (!(PacketAlertCheck(p, 1))) { + printf("signature 1 didn't match while it should have: "); + goto end; + } + + result = 1; +end: + if (de_ctx != NULL) { + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + DetectEngineCtxFree(de_ctx); + } + + FlowL7DataPtrFree(&f); + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p, 1); + return result; +} + +#endif /* UNITTESTS */ + +/** + * \brief this function registers unit tests for DetectSslVersion + */ +void DetectSslVersionRegisterTests(void) { +#ifdef UNITTESTS /* UNITTESTS */ + UtRegisterTest("DetectSslVersionTestParse01", DetectSslVersionTestParse01, 1); + UtRegisterTest("DetectSslVersionTestParse02", DetectSslVersionTestParse02, 1); + UtRegisterTest("DetectSslVersionTestParse03", DetectSslVersionTestParse03, 1); + UtRegisterTest("DetectSslVersionTestDetect01", DetectSslVersionTestDetect01, 1); + UtRegisterTest("DetectSslVersionTestDetect02", DetectSslVersionTestDetect02, 1); + UtRegisterTest("DetectSslVersionTestDetect03", DetectSslVersionTestDetect03, 1); +#endif /* UNITTESTS */ +} diff --git a/src/detect-ssl-version.h b/src/detect-ssl-version.h new file mode 100644 index 0000000000..67084f311a --- /dev/null +++ b/src/detect-ssl-version.h @@ -0,0 +1,48 @@ +/* Copyright (C) 2007-2010 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 detect-ssl-version.h + * + * \author Gurvinder Singh + * + */ + +#ifndef DETECT_SSL_VERSION_H +#define DETECT_SSL_VERSION_H + +#define DETECT_SSL_VERSION_NEGATED 0x01 + +#define SSLv2 0 +#define SSLv3 1 +#define TLS10 2 +#define TLS11 3 +#define TLS12 4 + +typedef struct SSLVersionData_ { + uint16_t ver; /** ssl version to match */ + uint8_t flags; +}SSLVersionData; + +typedef struct DetectSslVersionData_ { + SSLVersionData data[5]; +} DetectSslVersionData; + +/* prototypes */ +void DetectSslVersionRegister (void); + +#endif /* DETECT_SSL_VERSION_H */ diff --git a/src/detect.c b/src/detect.c index e60195c587..2d1ab770d0 100644 --- a/src/detect.c +++ b/src/detect.c @@ -130,6 +130,7 @@ #include "detect-ssh-proto-version.h" #include "detect-ssh-software-version.h" #include "detect-http-stat-code.h" +#include "detect-ssl-version.h" #include "action-globals.h" #include "tm-modules.h" @@ -3949,6 +3950,7 @@ void SigTableSetup(void) { DetectSshVersionRegister(); DetectSshSoftwareVersionRegister(); DetectHttpStatCodeRegister(); + DetectSslVersionRegister(); uint8_t i = 0; for (i = 0; i < DETECT_TBLSIZE; i++) { diff --git a/src/detect.h b/src/detect.h index 21cb306f03..eadbf75ab1 100644 --- a/src/detect.h +++ b/src/detect.h @@ -982,6 +982,7 @@ enum { DETECT_AL_HTTP_STAT_CODE, DETECT_AL_SSH_PROTOVERSION, DETECT_AL_SSH_SOFTWAREVERSION, + DETECT_AL_SSL_VERSION, DETECT_DCE_IFACE, DETECT_DCE_OPNUM, diff --git a/src/suricata.c b/src/suricata.c index a318e27bff..6283389f7b 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -948,7 +948,6 @@ int main(int argc, char **argv) RegisterDCERPCParsers(); RegisterDCERPCUDPParsers(); RegisterFTPParsers(); - RegisterSSLParsers(); RegisterSSHParsers(); AppLayerParsersInitPostProcess(); @@ -1018,7 +1017,6 @@ int main(int argc, char **argv) SCClassConfRegisterTests(); SCThresholdConfRegisterTests(); SCRConfRegisterTests(); - SSLParserRegisterTests(); #ifdef __SC_CUDA_SUPPORT__ SCCudaRegisterTests(); #endif