]> git.ipfire.org Git - thirdparty/snort3.git/commitdiff
Squashed commit of the following:
authorRuss Combs <rucombs@cisco.com>
Thu, 11 Jun 2015 19:27:40 +0000 (15:27 -0400)
committerRuss Combs <rucombs@cisco.com>
Thu, 11 Jun 2015 19:27:40 +0000 (15:27 -0400)
commit f0852f3da95431b5706963c66463a05b529dbdaa
Author: Bhagyashree Bantwal <bbantwal@cisco.com>
Date:   Mon Jun 8 10:30:38 2015 -0400

port ssl preprocessor from snort

23 files changed:
configure.ac
lua/snort.lua
src/CMakeLists.txt
src/Makefile.am
src/service_inspectors/CMakeLists.txt
src/service_inspectors/Makefile.am
src/service_inspectors/service_inspectors.cc
src/service_inspectors/ssh/ssh.cc
src/service_inspectors/ssl/CMakeLists.txt [new file with mode: 0644]
src/service_inspectors/ssl/Makefile.am [new file with mode: 0644]
src/service_inspectors/ssl/ips_ssl_state.cc [new file with mode: 0644]
src/service_inspectors/ssl/ips_ssl_version.cc [new file with mode: 0644]
src/service_inspectors/ssl/ssl_config.h [new file with mode: 0644]
src/service_inspectors/ssl/ssl_inspector.cc [new file with mode: 0644]
src/service_inspectors/ssl/ssl_inspector.h [new file with mode: 0644]
src/service_inspectors/ssl/ssl_module.cc [new file with mode: 0644]
src/service_inspectors/ssl/ssl_module.h [new file with mode: 0644]
tools/snort2lua/preprocessor_states/CMakeLists.txt
tools/snort2lua/preprocessor_states/Makefile.am
tools/snort2lua/preprocessor_states/pps_ssl.cc [new file with mode: 0644]
tools/snort2lua/preprocessor_states/preprocessor_api.cc
tools/snort2lua/rule_states/rule_api.cc
tools/snort2lua/rule_states/rule_unchanged.cc

index 5ea6393929e7ef93e8b07690b3da6c1f92b3bfdd..93320a31e751b57da261f55b464a86103a87ef8b 100644 (file)
@@ -979,6 +979,7 @@ src/service_inspectors/pop/Makefile \
 src/service_inspectors/rpc_decode/Makefile \
 src/service_inspectors/smtp/Makefile \
 src/service_inspectors/ssh/Makefile \
+src/service_inspectors/ssl/Makefile \
 src/service_inspectors/wizard/Makefile \
 src/protocols/Makefile \
 src/search_engines/Makefile \
index ef790e0c6302bf2695ee5e62b6903ead3c7e6470..4a26a2e61a44588369a64dd539067399bbf33a3f 100644 (file)
@@ -75,6 +75,7 @@ pop = { }
 port_scan = { }
 rpc_decode = { }
 ssh = { }
+ssl = { }
 telnet = { }
 
 -- use http_inspect or new_http_inspect (incomplete)
index 7a869e09a6b8474b3c38890a163ce64712415417..ce85c4769dd8b606cf34de400247802993d22fef 100644 (file)
@@ -63,6 +63,7 @@ if (STATIC_INSPECTORS)
         rpc_decode
         smtp
         ssh
+        ssl
         wizard
     )
 endif()
index f2ac1688372a24fed360877faad9237f5b964632..8c0dd9ed3501aa5da9bac2a0fc29cab8fafc7c6d 100644 (file)
@@ -18,6 +18,7 @@ service_inspectors/pop/libpop.a \
 service_inspectors/rpc_decode/librpc_decode.a \
 service_inspectors/smtp/libsmtp.a \
 service_inspectors/ssh/libssh.a \
+service_inspectors/ssl/libssl.a \
 service_inspectors/wizard/libwizard.a
 endif
 
index 786708d7fbc99144b94fa213e5c46a2c564e081b..176de5c739f00fc1898b19f3edb6e231f9259eb5 100644 (file)
@@ -9,6 +9,7 @@ add_subdirectory(pop)
 add_subdirectory(rpc_decode)
 add_subdirectory(smtp)
 add_subdirectory(ssh)
+add_subdirectory(ssl)
 add_subdirectory(wizard)
 
 if (STATIC_INSPECTORS)
index 2ade44f5d779dc00f6ff2013306c96d8215b5998..acaad9bc25b9fd0bfa3eabed5c43e14391f2572d 100644 (file)
@@ -27,6 +27,7 @@ pop \
 rpc_decode \
 smtp \
 ssh \
+ssl \
 wizard
 
 AM_CXXFLAGS = @AM_CXXFLAGS@
index d2ab393f57935b29b434ce4f762028adf1ecfeb7..f0642376cfdb9d69c8cdd05301adc551f17157ba 100644 (file)
@@ -28,6 +28,8 @@ extern const BaseApi* sin_http_global;
 extern const BaseApi* sin_http_inspect;
 
 #ifdef STATIC_INSPECTORS
+extern const BaseApi* ips_ssl_state;
+extern const BaseApi* ips_ssl_version;
 extern const BaseApi* sin_bo;
 extern const BaseApi* sin_dns;
 extern const BaseApi* sin_ftp_client;
@@ -39,6 +41,7 @@ extern const BaseApi* sin_pop;
 extern const BaseApi* sin_rpc_decode;
 extern const BaseApi* sin_smtp;
 extern const BaseApi* sin_ssh;
+extern const BaseApi* sin_ssl;
 extern const BaseApi* sin_telnet;
 extern const BaseApi* sin_wizard;
 #endif
@@ -49,6 +52,8 @@ const BaseApi* service_inspectors[] =
     sin_http_inspect,
 
 #ifdef STATIC_INSPECTORS
+    ips_ssl_state,
+    ips_ssl_version,
     sin_bo,
     sin_dns,
     sin_ftp_client,
@@ -60,6 +65,7 @@ const BaseApi* service_inspectors[] =
     sin_rpc_decode,
     sin_smtp,
     sin_ssh,
+    sin_ssl,
     sin_telnet,
     sin_wizard,
 #endif
index 44dd924c4a5eb63ef10a072766331f24a07f00ec..6bc9848c6d73c53a73fb7915fc34251289ac6b9e 100644 (file)
@@ -63,9 +63,6 @@ static unsigned int ProcessSSHProtocolVersionExchange(SSH_PROTO_CONF*, SSHData*,
 static unsigned int ProcessSSHKeyExchange(SSHData*, Packet*, uint8_t, unsigned int);
 static unsigned int ProcessSSHKeyInitExchange(SSHData*, Packet*, uint8_t, unsigned int);
 
-/* Ultimately calls SnortEventqAdd
-   Arguments are: gid, sid, rev, classification, priority, message, rule_info */
-
 unsigned SshFlowData::flow_id = 0;
 
 SSHData* SetNewSSHData(Packet* p)
diff --git a/src/service_inspectors/ssl/CMakeLists.txt b/src/service_inspectors/ssl/CMakeLists.txt
new file mode 100644 (file)
index 0000000..c93406d
--- /dev/null
@@ -0,0 +1,18 @@
+
+set( FILE_LIST
+    ssl_inspector.cc
+    ssl_inspector.h
+    ssl_config.h
+    ssl_module.cc
+    ssl_module.h
+    ips_ssl_state.cc
+    ips_ssl_version.cc
+)
+
+if (STATIC_INSPECTORS)
+    add_library( ssl STATIC ${FILE_LIST})
+
+else (STATIC_INSPECTORS)
+    add_shared_library(ssl inspectors ${FILE_LIST})
+
+endif (STATIC_INSPECTORS)
diff --git a/src/service_inspectors/ssl/Makefile.am b/src/service_inspectors/ssl/Makefile.am
new file mode 100644 (file)
index 0000000..9832890
--- /dev/null
@@ -0,0 +1,24 @@
+AUTOMAKE_OPTIONS=foreign no-dependencies
+
+file_list = \
+ssl_config.h \
+ssl_inspector.cc \
+ssl_inspector.h \
+ssl_module.cc \
+ssl_module.h \
+ips_ssl_state.cc \
+ips_ssl_version.cc
+
+if STATIC_INSPECTORS
+noinst_LIBRARIES = libssl.a
+libssl_a_SOURCES = $(file_list)
+else
+shlibdir = $(pkglibdir)/inspectors
+shlib_LTLIBRARIES = libssl.la
+libssl_la_CXXFLAGS = $(AM_CXXFLAGS) -DBUILDING_SO
+libssl_la_LDFLAGS = -export-dynamic -shared
+libssl_la_SOURCES = $(file_list)
+endif
+
+AM_CXXFLAGS = @AM_CXXFLAGS@
+
diff --git a/src/service_inspectors/ssl/ips_ssl_state.cc b/src/service_inspectors/ssl/ips_ssl_state.cc
new file mode 100644 (file)
index 0000000..fd3abe1
--- /dev/null
@@ -0,0 +1,295 @@
+//--------------------------------------------------------------------------
+// Copyright (C) 2015-2015 Cisco and/or its affiliates. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation.  You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// 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 along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+//--------------------------------------------------------------------------
+// ips_ssl_state.cc author Bhagyashree Bantwal <bbantwal@cisco.com>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "ssl_inspector.h"
+#include "protocols/ssl.h"
+#include "framework/ips_option.h"
+#include "framework/module.h"
+#include "framework/parameter.h"
+#include "detection/detect.h"
+#include "detection/detection_defines.h"
+#include "hash/sfhashfcn.h"
+#include "time/profiler.h"
+
+//-------------------------------------------------------------------------
+// ssl_state
+//-------------------------------------------------------------------------
+
+#define s_name "ssl_state"
+#define s_help \
+    "detection option for ssl state"
+
+static THREAD_LOCAL ProfileStats sslStateRuleOptionPerfStats;
+
+struct SslStateRuleOptionData
+{
+    int flags;
+    int mask;
+};
+
+class SslStateOption : public IpsOption
+{
+public:
+    SslStateOption(const SslStateRuleOptionData& c) :
+        IpsOption(s_name)
+    { ssod = c; }
+
+    uint32_t hash() const override;
+    bool operator==(const IpsOption&) const override;
+
+    int eval(Cursor&, Packet*) override;
+
+private:
+    SslStateRuleOptionData ssod;
+};
+
+//-------------------------------------------------------------------------
+// ssl_state option
+//-------------------------------------------------------------------------
+
+uint32_t SslStateOption::hash() const
+{
+    uint32_t a,b,c;
+
+    a = ssod.flags;
+    b = ssod.mask;
+    c = 0;
+
+    mix_str(a,b,c,get_name());
+    final (a,b,c);
+
+    return c;
+}
+
+bool SslStateOption::operator==(const IpsOption& ips) const
+{
+    if ( strcmp(get_name(), ips.get_name()) )
+        return false;
+
+    const SslStateOption& rhs = (SslStateOption&)ips;
+
+    if ( (ssod.flags == rhs.ssod.flags) &&
+        (ssod.mask == rhs.ssod.mask) )
+        return true;
+
+    return false;
+}
+
+int SslStateOption::eval(Cursor&, Packet* pkt)
+{
+    SSLData* sd;
+
+    PROFILE_VARS;
+    MODULE_PROFILE_START(sslStateRuleOptionPerfStats);
+
+    if ( !(pkt->packet_flags & PKT_REBUILT_STREAM) && !pkt->is_full_pdu() )
+    {
+        MODULE_PROFILE_END(sslStateRuleOptionPerfStats);
+        return DETECTION_OPTION_NO_MATCH;
+    }
+
+    if (!pkt->flow)
+    {
+        MODULE_PROFILE_END(sslStateRuleOptionPerfStats);
+        return DETECTION_OPTION_NO_MATCH;
+    }
+
+    sd = get_ssl_session_data(pkt->flow);
+
+    if (!sd)
+    {
+        MODULE_PROFILE_END(sslStateRuleOptionPerfStats);
+        return DETECTION_OPTION_NO_MATCH;
+    }
+
+    if ((ssod.flags & sd->ssn_flags) ^ ssod.mask)
+    {
+        MODULE_PROFILE_END(sslStateRuleOptionPerfStats);
+        return DETECTION_OPTION_MATCH;
+    }
+
+    MODULE_PROFILE_END(sslStateRuleOptionPerfStats);
+
+    return DETECTION_OPTION_NO_MATCH;
+}
+
+//-------------------------------------------------------------------------
+// ssl_state module
+//-------------------------------------------------------------------------
+
+static const Parameter s_params[] =
+{
+    { "client_hello", Parameter::PT_IMPLIED, nullptr, nullptr,
+      "check for client hello" },
+
+    { "server_hello", Parameter::PT_IMPLIED, nullptr, nullptr,
+      "check for server hello" },
+
+    { "client_keyx", Parameter::PT_IMPLIED, nullptr, nullptr,
+      "check for client keyx" },
+
+    { "server_keyx", Parameter::PT_IMPLIED, nullptr, nullptr,
+      "check for server keyx" },
+
+    { "unknown", Parameter::PT_IMPLIED, nullptr, nullptr,
+      "check for unknown record" },
+
+    { "!client_hello", Parameter::PT_IMPLIED, nullptr, nullptr,
+      "check for records that are not client hello" },
+
+    { "!server_hello", Parameter::PT_IMPLIED, nullptr, nullptr,
+      "check for records that are not server hello" },
+
+    { "!client_keyx", Parameter::PT_IMPLIED, nullptr, nullptr,
+      "check for records that are not client keyx" },
+
+    { "!server_keyx", Parameter::PT_IMPLIED, nullptr, nullptr,
+      "check for records that are not server keyx" },
+
+    { "!unknown", Parameter::PT_IMPLIED, nullptr, nullptr,
+      "check for records that are not unknown" },
+
+    { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
+};
+
+class SslStateModule : public Module
+{
+public:
+    SslStateModule() : Module(s_name, s_help, s_params) { }
+
+    bool begin(const char*, int, SnortConfig*) override;
+    bool set(const char*, Value&, SnortConfig*) override;
+
+    ProfileStats* get_profile() const override
+    { return &sslStateRuleOptionPerfStats; }
+
+    SslStateRuleOptionData ssod;
+};
+
+bool SslStateModule::begin(const char*, int, SnortConfig*)
+{
+    ssod.flags = 0;
+    ssod.mask = 0;
+    return true;
+}
+
+bool SslStateModule::set(const char*, Value& v, SnortConfig*)
+{
+    if ( v.is("client_hello") )
+        ssod.flags |= SSL_CUR_CLIENT_HELLO_FLAG;
+
+    else if ( v.is("server_hello") )
+        ssod.flags |= SSL_CUR_SERVER_HELLO_FLAG;
+
+    else if ( v.is("client_keyx") )
+        ssod.flags |= SSL_CUR_CLIENT_KEYX_FLAG;
+
+    else if ( v.is("server_keyx") )
+        ssod.flags |= SSL_CUR_SERVER_KEYX_FLAG;
+
+    else if ( v.is("unknown") )
+        ssod.flags |= SSL_UNKNOWN_FLAG;
+
+    else if ( v.is("!client_hello") )
+    {
+        ssod.flags |= SSL_CUR_CLIENT_HELLO_FLAG;
+        ssod.mask |= SSL_CUR_CLIENT_HELLO_FLAG;
+    }
+    else if ( v.is("!server_hello") )
+    {
+        ssod.flags |= SSL_CUR_SERVER_HELLO_FLAG;
+        ssod.mask |= SSL_CUR_SERVER_HELLO_FLAG;
+    }
+    else if ( v.is("!client_keyx") )
+    {
+        ssod.flags |= SSL_CUR_CLIENT_KEYX_FLAG;
+        ssod.mask |= SSL_CUR_CLIENT_KEYX_FLAG;
+    }
+    else if ( v.is("!server_keyx") )
+    {
+        ssod.flags |= SSL_CUR_SERVER_KEYX_FLAG;
+        ssod.mask |= SSL_CUR_SERVER_KEYX_FLAG;
+    }
+    else if ( v.is("!unknown") )
+    {
+        ssod.flags |= SSL_UNKNOWN_FLAG;
+        ssod.mask |= SSL_UNKNOWN_FLAG;
+    }
+    else
+        return false;
+
+    return true;
+}
+
+//-------------------------------------------------------------------------
+// ssl_state api methods
+//-------------------------------------------------------------------------
+
+static Module* ssl_state_mod_ctor()
+{
+    return new SslStateModule;
+}
+
+static void mod_dtor(Module* m)
+{
+    delete m;
+}
+
+static IpsOption* ssl_state_ctor(Module* p, OptTreeNode*)
+{
+    SslStateModule* m = (SslStateModule*)p;
+    return new SslStateOption(m->ssod);
+}
+
+static void opt_dtor(IpsOption* p)
+{
+    delete p;
+}
+
+static const IpsApi ssl_state_api =
+{
+    {
+        PT_IPS_OPTION,
+        sizeof(IpsApi),
+        IPSAPI_VERSION,
+        0,
+        API_RESERVED,
+        API_OPTIONS,
+        s_name,
+        s_help,
+        ssl_state_mod_ctor,
+        mod_dtor
+    },
+    OPT_TYPE_DETECTION,
+    0, PROTO_BIT__TCP,
+    nullptr,
+    nullptr,
+    nullptr,
+    nullptr,
+    ssl_state_ctor,
+    opt_dtor,
+    nullptr
+};
+
+const BaseApi* ips_ssl_state = &ssl_state_api.base;
+
diff --git a/src/service_inspectors/ssl/ips_ssl_version.cc b/src/service_inspectors/ssl/ips_ssl_version.cc
new file mode 100644 (file)
index 0000000..879a2ff
--- /dev/null
@@ -0,0 +1,296 @@
+//--------------------------------------------------------------------------
+// Copyright (C) 2015-2015 Cisco and/or its affiliates. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation.  You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// 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 along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+//--------------------------------------------------------------------------
+// ips_ssl_version.cc author Bhagyashree Bantwal <bbantwal@cisco.com>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "ssl_inspector.h"
+#include "protocols/ssl.h"
+#include "framework/ips_option.h"
+#include "framework/module.h"
+#include "framework/parameter.h"
+#include "detection/detect.h"
+#include "detection/detection_defines.h"
+#include "hash/sfhashfcn.h"
+#include "time/profiler.h"
+
+//-------------------------------------------------------------------------
+// ssl_version
+//-------------------------------------------------------------------------
+
+#define s_name "ssl_version"
+#define s_help \
+    "detection option for ssl version"
+
+static THREAD_LOCAL ProfileStats sslVersionRuleOptionPerfStats;
+
+struct SslVersionRuleOptionData
+{
+    int flags;
+    int mask;
+};
+
+class SslVersionOption : public IpsOption
+{
+public:
+    SslVersionOption(const SslVersionRuleOptionData& c) :
+        IpsOption(s_name)
+    { svod = c; }
+
+    uint32_t hash() const override;
+    bool operator==(const IpsOption&) const override;
+
+    int eval(Cursor&, Packet*) override;
+
+private:
+    SslVersionRuleOptionData svod;
+};
+
+//-------------------------------------------------------------------------
+// ssl_version option
+//-------------------------------------------------------------------------
+
+uint32_t SslVersionOption::hash() const
+{
+    uint32_t a,b,c;
+
+    a = svod.flags;
+    b = svod.mask;
+    c = 0;
+
+    mix_str(a,b,c,get_name());
+    final (a,b,c);
+
+    return c;
+}
+
+bool SslVersionOption::operator==(const IpsOption& ips) const
+{
+    if ( strcmp(get_name(), ips.get_name()) )
+        return false;
+
+    const SslVersionOption& rhs = (SslVersionOption&)ips;
+
+    if ( (svod.flags == rhs.svod.flags) &&
+        (svod.mask == rhs.svod.mask) )
+        return true;
+
+    return false;
+}
+
+int SslVersionOption::eval(Cursor&, Packet* pkt)
+{
+    SSLData* sd;
+
+    PROFILE_VARS;
+    MODULE_PROFILE_START(sslVersionRuleOptionPerfStats);
+
+    if ( !(pkt->packet_flags & PKT_REBUILT_STREAM) && !pkt->is_full_pdu() )
+    {
+        MODULE_PROFILE_END(sslVersionRuleOptionPerfStats);
+        return DETECTION_OPTION_NO_MATCH;
+    }
+
+    if (!pkt->flow)
+    {
+        MODULE_PROFILE_END(sslVersionRuleOptionPerfStats);
+        return DETECTION_OPTION_NO_MATCH;
+    }
+
+    sd = get_ssl_session_data(pkt->flow);
+
+    if (!sd)
+    {
+        MODULE_PROFILE_END(sslVersionRuleOptionPerfStats);
+        return DETECTION_OPTION_NO_MATCH;
+    }
+
+    if ((svod.flags & sd->ssn_flags) ^ svod.mask)
+    {
+        MODULE_PROFILE_END(sslVersionRuleOptionPerfStats);
+        return DETECTION_OPTION_MATCH;
+    }
+
+    MODULE_PROFILE_END(sslVersionRuleOptionPerfStats);
+
+    return DETECTION_OPTION_NO_MATCH;
+}
+
+//-------------------------------------------------------------------------
+// ssl_version module
+//-------------------------------------------------------------------------
+
+static const Parameter s_params[] =
+{
+    { "sslv2", Parameter::PT_IMPLIED, nullptr, nullptr,
+      "check for sslv2" },
+
+    { "sslv3", Parameter::PT_IMPLIED, nullptr, nullptr,
+      "check for sslv3" },
+
+    { "tls1.0", Parameter::PT_IMPLIED, nullptr, nullptr,
+      "check for tls1.0" },
+
+    { "tls1.1", Parameter::PT_IMPLIED, nullptr, nullptr,
+      "check for tls1.1" },
+
+    { "tls1.2", Parameter::PT_IMPLIED, nullptr, nullptr,
+      "check for tls1.2" },
+
+    { "!sslv2", Parameter::PT_IMPLIED, nullptr, nullptr,
+      "check for records that are not sslv2" },
+
+    { "!sslv3", Parameter::PT_IMPLIED, nullptr, nullptr,
+      "check for records that are not sslv3" },
+
+    { "!tls1.0", Parameter::PT_IMPLIED, nullptr, nullptr,
+      "check for records that are not tls1.0" },
+
+    { "!tls1.1", Parameter::PT_IMPLIED, nullptr, nullptr,
+      "check for records that are not tls1.1" },
+
+    { "!tls1.2", Parameter::PT_IMPLIED, nullptr, nullptr,
+      "check for records that are not tls1.2" },
+
+    { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
+};
+
+class SslVersionModule : public Module
+{
+public:
+    SslVersionModule() : Module(s_name, s_help, s_params) { }
+
+    bool begin(const char*, int, SnortConfig*) override;
+    bool set(const char*, Value&, SnortConfig*) override;
+
+    ProfileStats* get_profile() const override
+    { return &sslVersionRuleOptionPerfStats; }
+
+    SslVersionRuleOptionData svod;
+};
+
+bool SslVersionModule::begin(const char*, int, SnortConfig*)
+{
+    svod.flags = 0;
+    svod.mask = 0;
+    return true;
+}
+
+bool SslVersionModule::set(const char*, Value& v, SnortConfig*)
+{
+
+    if ( v.is("sslv2") )
+        svod.flags |= SSL_VER_SSLV2_FLAG;
+
+    else if ( v.is("sslv3") )
+        svod.flags |= SSL_VER_SSLV3_FLAG;
+
+    else if ( v.is("tls1.0") )
+        svod.flags |= SSL_VER_TLS10_FLAG;
+
+    else if ( v.is("tls1.1") )
+        svod.flags |= SSL_VER_TLS11_FLAG;
+
+    else if ( v.is("tls1.2") )
+        svod.flags |= SSL_VER_TLS12_FLAG;
+
+    else if ( v.is("!sslv2") )
+    {
+        svod.flags |= SSL_VER_SSLV2_FLAG;
+        svod.mask |= SSL_VER_SSLV2_FLAG;
+    }
+    else if ( v.is("!sslv3") )
+    {
+        svod.flags |= SSL_VER_SSLV3_FLAG;
+        svod.mask |= SSL_VER_SSLV3_FLAG;
+    }
+    else if ( v.is("!tls1.0") )
+    {
+        svod.flags |= SSL_VER_TLS10_FLAG;
+        svod.mask |= SSL_VER_TLS10_FLAG;
+    }
+    else if ( v.is("!tls1.1") )
+    {
+        svod.flags |= SSL_VER_TLS11_FLAG;
+        svod.mask |= SSL_VER_TLS11_FLAG;
+    }
+    else if ( v.is("!tls1.2") )
+    {
+        svod.flags |= SSL_VER_TLS12_FLAG;
+        svod.mask |= SSL_VER_TLS12_FLAG;
+    }
+    else
+        return false;
+
+    return true;
+}
+
+//-------------------------------------------------------------------------
+// ssl_version api methods
+//-------------------------------------------------------------------------
+
+static Module* ssl_version_mod_ctor()
+{
+    return new SslVersionModule;
+}
+
+static void mod_dtor(Module* m)
+{
+    delete m;
+}
+
+static IpsOption* ssl_version_ctor(Module* p, OptTreeNode*)
+{
+    SslVersionModule* m = (SslVersionModule*)p;
+    return new SslVersionOption(m->svod);
+}
+
+static void opt_dtor(IpsOption* p)
+{
+    delete p;
+}
+
+static const IpsApi ssl_version_api =
+{
+    {
+        PT_IPS_OPTION,
+        sizeof(IpsApi),
+        IPSAPI_VERSION,
+        0,
+        API_RESERVED,
+        API_OPTIONS,
+        s_name,
+        s_help,
+        ssl_version_mod_ctor,
+        mod_dtor
+    },
+    OPT_TYPE_DETECTION,
+    0, PROTO_BIT__TCP,
+    nullptr,
+    nullptr,
+    nullptr,
+    nullptr,
+    ssl_version_ctor,
+    opt_dtor,
+    nullptr
+};
+
+const BaseApi* ips_ssl_version = &ssl_version_api.base;
+
diff --git a/src/service_inspectors/ssl/ssl_config.h b/src/service_inspectors/ssl/ssl_config.h
new file mode 100644 (file)
index 0000000..5cb2813
--- /dev/null
@@ -0,0 +1,36 @@
+//--------------------------------------------------------------------------
+// Copyright (C) 2015-2015 Cisco and/or its affiliates. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation.  You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// 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 along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+//--------------------------------------------------------------------------
+//
+
+#ifndef SSL_CONFIG_H
+#define SSL_CONFIG_H
+
+#define SSLPP_TRUSTSERVER_FLAG  0x0002
+
+/*
+ * Global SSL preprocessor configuration.
+ *
+ */
+struct SSL_PROTO_CONF
+{
+    uint16_t flags;
+    int max_heartbeat_len;
+};
+
+#endif
+
diff --git a/src/service_inspectors/ssl/ssl_inspector.cc b/src/service_inspectors/ssl/ssl_inspector.cc
new file mode 100644 (file)
index 0000000..77a9f1a
--- /dev/null
@@ -0,0 +1,517 @@
+//--------------------------------------------------------------------------
+// Copyright (C) 2015-2015 Cisco and/or its affiliates. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation.  You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// 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 along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+//--------------------------------------------------------------------------
+//
+
+/*
+ * SSL inspector
+ *
+ */
+
+#include "ssl_inspector.h"
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <assert.h>
+#include <string.h>
+#include <stdio.h>
+#include <sys/types.h>
+
+#include "snort_types.h"
+#include "snort_debug.h"
+
+#include "ssl.h"
+#include "ssl_module.h"
+#include "profiler.h"
+#include "stream/stream_api.h"
+#include "parser.h"
+#include "framework/inspector.h"
+#include "utils/sfsnprintfappend.h"
+#include "target_based/sftarget_protocol_reference.h"
+#include "detect.h"
+
+THREAD_LOCAL ProfileStats sslPerfStats;
+THREAD_LOCAL SimpleStats sslstats;
+THREAD_LOCAL SSL_counters_t counts;
+
+/*
+ * Function prototype(s)
+ */
+static void snort_ssl(SSL_PROTO_CONF* GlobalConf, Packet* p);
+
+unsigned SslFlowData::flow_id = 0;
+
+SSLData* SetNewSSLData(Packet* p)
+{
+    SslFlowData* fd = new SslFlowData;
+    p->flow->set_application_data(fd);
+    return &fd->session;
+}
+
+SSLData* get_ssl_session_data(Flow* flow)
+{
+    SslFlowData* fd = (SslFlowData*)flow->get_application_data(
+        SslFlowData::flow_id);
+
+    return fd ? &fd->session : NULL;
+}
+
+void SSL_InitGlobals(void)
+{
+    memset(&counts, 0, sizeof(counts));
+}
+
+static void PrintSslConf(SSL_PROTO_CONF* config)
+{
+    if (config == NULL)
+        return;
+    LogMessage("SSL config:\n");
+    if ( config->flags & SSLPP_TRUSTSERVER_FLAG )
+    {
+        LogMessage("    Server side data is trusted\n");
+    }
+
+    LogMessage("\n");
+}
+
+static void SSL_UpdateCounts(const uint32_t new_flags)
+{
+    if (new_flags & SSL_CHANGE_CIPHER_FLAG)
+        counts.cipher_change++;
+
+    if (new_flags & SSL_ALERT_FLAG)
+        counts.alerts++;
+
+    if (new_flags & SSL_CLIENT_HELLO_FLAG)
+        counts.hs_chello++;
+
+    if (new_flags & SSL_SERVER_HELLO_FLAG)
+        counts.hs_shello++;
+
+    if (new_flags & SSL_CERTIFICATE_FLAG)
+        counts.hs_cert++;
+
+    if (new_flags & SSL_SERVER_KEYX_FLAG)
+        counts.hs_skey++;
+
+    if (new_flags & SSL_CLIENT_KEYX_FLAG)
+        counts.hs_ckey++;
+
+    if (new_flags & SSL_SFINISHED_FLAG)
+        counts.hs_finished++;
+
+    if (new_flags & SSL_HS_SDONE_FLAG)
+        counts.hs_sdone++;
+
+    if (new_flags & SSL_SAPP_FLAG)
+        counts.sapp++;
+
+    if (new_flags & SSL_CAPP_FLAG)
+        counts.capp++;
+}
+
+static inline bool SSLPP_is_encrypted(SSL_PROTO_CONF* config, uint32_t ssl_flags, Packet* packet)
+{
+    if (config->flags & SSLPP_TRUSTSERVER_FLAG)
+    {
+        if (ssl_flags & SSL_SAPP_FLAG)
+            return true;
+    }
+
+    if (SSL_IS_CLEAN(ssl_flags))
+    {
+        if (((ssl_flags & SSLPP_ENCRYPTED_FLAGS) == SSLPP_ENCRYPTED_FLAGS) ||
+            ((ssl_flags & SSLPP_ENCRYPTED_FLAGS2) == SSLPP_ENCRYPTED_FLAGS2))
+        {
+            counts.completed_hs++;
+            return true;
+        }
+        /* Check if we're either midstream or if packets were missed after the
+         *          * connection was established */
+        else if ((stream.get_session_flags (packet->flow) & SSNFLAG_MIDSTREAM) ||
+            (stream.missed_packets(packet->flow, SSN_DIR_BOTH)))
+        {
+            if ((ssl_flags & (SSL_CAPP_FLAG | SSL_SAPP_FLAG)) == (SSL_CAPP_FLAG | SSL_SAPP_FLAG))
+            {
+                return true;
+            }
+        }
+    }
+
+    return false;
+}
+
+static inline uint32_t SSLPP_process_alert(SSL_PROTO_CONF* config, uint32_t ssn_flags, uint32_t
+    new_flags, Packet* packet)
+{
+    DEBUG_WRAP(DebugMessage(DEBUG_SSL, "Process Alert\n"); );
+
+    ssn_flags |= new_flags;
+
+    /* Check if we've seen a handshake, that this isn't it,
+     *      * that the cipher flags is not set, and that we are disabling detection */
+    if (SSL_IS_HANDSHAKE(ssn_flags) &&
+        !SSL_IS_HANDSHAKE(new_flags) &&
+        !(new_flags & SSL_CHANGE_CIPHER_FLAG) &&
+        !(new_flags & SSL_HEARTBEAT_SEEN))
+    {
+        DEBUG_WRAP(DebugMessage(DEBUG_SSL, "Disabling detect\n"); );
+        DisableDetect(packet);
+    }
+
+    /* Need to negate the application flags from the opposing side. */
+
+    if (packet->packet_flags & PKT_FROM_CLIENT)
+        return ssn_flags & ~SSL_SAPP_FLAG;
+
+    else if (packet->packet_flags & PKT_FROM_SERVER)
+        return ssn_flags & ~SSL_CAPP_FLAG;
+
+    return ssn_flags;
+}
+
+static inline uint32_t SSLPP_process_hs(uint32_t ssl_flags, uint32_t new_flags)
+{
+    DEBUG_WRAP(DebugMessage(DEBUG_SSL, "Process Handshake\n"); );
+
+    if (!SSL_BAD_HS(new_flags))
+    {
+        ssl_flags |= new_flags & (SSL_CLIENT_HELLO_FLAG |
+            SSL_SERVER_HELLO_FLAG |
+            SSL_CLIENT_KEYX_FLAG |
+            SSL_SFINISHED_FLAG);
+    }
+    else
+    {
+        counts.bad_handshakes++;
+    }
+
+    return ssl_flags;
+}
+
+static inline uint32_t SSLPP_process_app(SSL_PROTO_CONF* config, uint32_t ssn_flags, uint32_t
+    new_flags, Packet* packet)
+{
+    DEBUG_WRAP(DebugMessage(DEBUG_SSL, "Process Application\n"); );
+
+    if (SSLPP_is_encrypted(config, ssn_flags | new_flags, packet) )
+    {
+        ssn_flags |= SSL_ENCRYPTED_FLAG;
+
+        // Heartbleed check is disabled. Stop inspection on this session.
+        if (!config->max_heartbeat_len)
+        {
+            DEBUG_WRAP(DebugMessage(DEBUG_SSL, "STOPPING INSPECTION (process_app)\n"); );
+            stream.stop_inspection(packet->flow,
+                packet, SSN_DIR_BOTH, -1, 0);
+            counts.stopped++;
+        }
+        else if (!(new_flags & SSL_HEARTBEAT_SEEN))
+        {
+            DisableDetect(packet);
+        }
+    }
+
+    return ssn_flags | new_flags;
+}
+
+static inline void SSLPP_process_other(SSL_PROTO_CONF* config, SSLData* sd, uint32_t new_flags,
+    Packet* packet)
+{
+    /* Encrypted SSLv2 will appear unrecognizable.  Check if the handshake was
+     *      * seen and stop inspecting if so. */
+    /* Check for an existing handshake from both sides */
+    if ((sd->ssn_flags & SSL_VER_SSLV2_FLAG) &&
+        SSL_IS_CHELLO(sd->ssn_flags) && SSL_IS_SHELLO(sd->ssn_flags) &&
+        !(new_flags & SSL_CHANGE_CIPHER_FLAG) &&
+        !(new_flags & SSL_HEARTBEAT_SEEN))
+    {
+        sd->ssn_flags |= SSL_ENCRYPTED_FLAG | new_flags;
+
+        if (!config->max_heartbeat_len)
+        {
+            DEBUG_WRAP(DebugMessage(DEBUG_SSL, "STOPPING INSPECTION (process_other)\n"); );
+            stream.stop_inspection(packet->flow,
+                packet, SSN_DIR_BOTH, -1, 0);
+        }
+        else if (!(new_flags & SSL_HEARTBEAT_SEEN))
+        {
+            DisableDetect(packet);
+        }
+    }
+    else
+    {
+        counts.unrecognized++;
+
+        /* Special handling for SSLv2 */
+        if (new_flags & SSL_VER_SSLV2_FLAG)
+            sd->ssn_flags |= new_flags;
+
+        if (new_flags & SSL_UNKNOWN_FLAG)
+            sd->ssn_flags |= new_flags;
+    }
+}
+
+/* Main runtime entry point for SSL preprocessor.
+ * Analyzes SSL packets for anomalies/exploits.
+ *
+ * PARAMETERS:
+ *
+ * p:    Pointer to current packet to process.
+ * contextp:    Pointer to context block, not used.
+ *
+ * RETURNS:     Nothing.
+ */
+static void snort_ssl(SSL_PROTO_CONF* config, Packet* p)
+{
+    SSLData* sd = NULL;
+    uint8_t dir;
+    uint8_t index;
+    uint32_t new_flags;
+    uint8_t heartbleed_type = 0;
+    PROFILE_VARS;
+
+    MODULE_PROFILE_START(sslPerfStats);
+
+    /* Attempt to get a previously allocated SSL block. */
+    sd = get_ssl_session_data(p->flow);
+
+    if (sd == NULL)
+    {
+        /* Check the stream session. If it does not currently
+         * have our SSL data-block attached, create one.
+         */
+        sd = SetNewSSLData(p);
+
+        if ( !sd )
+        {
+            /* Could not get/create the session data for this packet. */
+            MODULE_PROFILE_END(sslPerfStats);
+            return;
+        }
+    }
+    SSL_CLEAR_TEMPORARY_FLAGS(sd->ssn_flags);
+
+    dir = (p->packet_flags & PKT_FROM_SERVER) ? 1 : 0;
+    index = (p->packet_flags & PKT_REBUILT_STREAM) ? 2 : 0;
+    new_flags = SSL_decode(p->data, (int)p->dsize, p->packet_flags, sd->ssn_flags,
+        &heartbleed_type, &(sd->partial_rec_len[dir+index]), config->max_heartbeat_len);
+
+    if (heartbleed_type & SSL_HEARTBLEED_REQUEST)
+    {
+        SnortEventqAdd(GID_SSL, SSL_ALERT_HB_REQUEST);
+    }
+    else if (heartbleed_type & SSL_HEARTBLEED_RESPONSE)
+    {
+        SnortEventqAdd(GID_SSL, SSL_ALERT_HB_RESPONSE);
+    }
+    else if (heartbleed_type & SSL_HEARTBLEED_UNKNOWN)
+    {
+        if (!dir)
+        {
+            SnortEventqAdd(GID_SSL, SSL_ALERT_HB_REQUEST);
+        }
+        else
+        {
+            SnortEventqAdd(GID_SSL, SSL_ALERT_HB_RESPONSE);
+        }
+    }
+    if (sd->ssn_flags & SSL_ENCRYPTED_FLAG )
+    {
+        counts.decoded++;
+
+        SSL_UpdateCounts(new_flags);
+
+        if (!(new_flags & SSL_HEARTBEAT_SEEN))
+        {
+            DisableDetect(p);
+        }
+
+        sd->ssn_flags |= new_flags;
+
+        MODULE_PROFILE_END(sslPerfStats);
+        return;
+    }
+
+// If the client used an SSLv2 ClientHello with an SSLv3/TLS version and
+// the server replied with an SSLv3/TLS ServerHello, remove the backward
+// compatibility flag and the SSLv2 flag since this session will continue
+// as SSLv3/TLS.
+
+    if ((sd->ssn_flags & SSL_V3_BACK_COMPAT_V2) && SSL_V3_SERVER_HELLO(new_flags))
+        sd->ssn_flags &= ~(SSL_VER_SSLV2_FLAG|SSL_V3_BACK_COMPAT_V2);
+
+    if ( (SSL_IS_CHELLO(new_flags) && SSL_IS_CHELLO(sd->ssn_flags) && SSL_IS_SHELLO(sd->ssn_flags) )
+            || (SSL_IS_CHELLO(new_flags) && SSL_IS_SHELLO(sd->ssn_flags) ))
+    {
+        SnortEventqAdd(GID_SSL, SSL_INVALID_CLIENT_HELLO);
+    }
+    else if (!(config->flags & SSLPP_TRUSTSERVER_FLAG))
+    {
+        if ( (SSL_IS_SHELLO(new_flags) && !SSL_IS_CHELLO(sd->ssn_flags) ))
+        {
+            if (!(stream.missed_packets(p->flow, SSN_DIR_FROM_CLIENT)))
+                SnortEventqAdd(GID_SSL, SSL_INVALID_SERVER_HELLO);
+        }
+    }
+
+    counts.decoded++;
+
+    SSL_UpdateCounts(new_flags);
+
+    /* Note, there can be multiple record types in each SSL packet.
+     *      * Processing them in this order is intentional.  If there is an
+     *           * Alert, we don't care about the other records */
+
+    if (SSL_IS_ALERT(new_flags))
+    {
+        sd->ssn_flags = SSLPP_process_alert(config, sd->ssn_flags, new_flags, p);
+    }
+    else if (SSL_IS_HANDSHAKE(new_flags))
+    {
+        sd->ssn_flags = SSLPP_process_hs(sd->ssn_flags, new_flags);
+    }
+    else if (SSL_IS_APP(new_flags))
+    {
+        sd->ssn_flags = SSLPP_process_app(config, sd->ssn_flags, new_flags, p);
+    }
+    else
+    {
+        /* Different record type that we don't care about.
+         *          * Either it's a 'change cipher spec' or we failed to recognize the
+         *                   * record type.  Do not update session data */
+        SSLPP_process_other(config, sd, new_flags, p);
+
+        /* Application data is updated inside of SSLPP_process_other */
+
+        MODULE_PROFILE_END(sslPerfStats);
+        return;
+    }
+
+    sd->ssn_flags |= new_flags;
+
+    MODULE_PROFILE_END(sslPerfStats);
+}
+
+//-------------------------------------------------------------------------
+// class stuff
+//-------------------------------------------------------------------------
+
+class Ssl : public Inspector
+{
+public:
+    Ssl(SSL_PROTO_CONF*);
+    ~Ssl();
+
+    void show(SnortConfig*) override;
+    void eval(Packet*) override;
+
+private:
+    SSL_PROTO_CONF* config;
+};
+
+Ssl::Ssl(SSL_PROTO_CONF* pc)
+{
+    config = pc;
+}
+
+Ssl::~Ssl()
+{
+    if ( config )
+        delete config;
+}
+
+void Ssl::show(SnortConfig*)
+{
+    PrintSslConf(config);
+}
+
+void Ssl::eval(Packet* p)
+{
+    // precondition - what we registered for
+    assert(p->is_tcp() && p->dsize && p->data);
+
+    ++sslstats.total_packets;
+    snort_ssl(config, p);
+}
+
+//-------------------------------------------------------------------------
+// api stuff
+//-------------------------------------------------------------------------
+
+static Module* mod_ctor()
+{ return new SslModule; }
+
+static void mod_dtor(Module* m)
+{ delete m; }
+
+static void ssl_init()
+{
+    SslFlowData::init();
+}
+
+static Inspector* ssl_ctor(Module* m)
+{
+    SslModule* mod = (SslModule*)m;
+    return new Ssl(mod->get_data());
+}
+
+static void ssl_dtor(Inspector* p)
+{
+    delete p;
+}
+
+const InspectApi ssl_api =
+{
+    {
+        PT_INSPECTOR,
+        sizeof(InspectApi),
+        INSAPI_VERSION,
+        0,
+        API_RESERVED,
+        API_OPTIONS,
+        SSL_NAME,
+        SSL_HELP,
+        mod_ctor,
+        mod_dtor
+    },
+    IT_SERVICE,
+    (uint16_t)PktType::TCP,
+    nullptr, // buffers
+    "ssl",
+    ssl_init,
+    nullptr, // pterm
+    nullptr, // tinit
+    nullptr, // tterm
+    ssl_ctor,
+    ssl_dtor,
+    nullptr, // ssn
+    nullptr  // reset
+};
+
+#ifdef BUILDING_SO
+SO_PUBLIC const BaseApi* snort_plugins[] =
+{
+    &ssl_api.base,
+    nullptr
+};
+#else
+const BaseApi* sin_ssl = &ssl_api.base;
+#endif
+
diff --git a/src/service_inspectors/ssl/ssl_inspector.h b/src/service_inspectors/ssl/ssl_inspector.h
new file mode 100644 (file)
index 0000000..2d46ff6
--- /dev/null
@@ -0,0 +1,87 @@
+//--------------------------------------------------------------------------
+// Copyright (C) 2015-2015 Cisco and/or its affiliates. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation.  You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// 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 along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+//--------------------------------------------------------------------------
+//
+
+/*
+ * ssl.h: Definitions, structs, function prototype(s) for
+ *             the SSL service inspectors.
+ */
+
+#ifndef SSL_INSPECTOR_H
+#define SSL_INSPECTOR_H
+
+#include "protocols/packet.h"
+#include "stream/stream_api.h"
+#include "profiler.h"
+#include "ssl_config.h"
+
+#define SSLPP_ENCRYPTED_FLAGS \
+    (SSL_HS_SDONE_FLAG | SSL_CLIENT_KEYX_FLAG | \
+    SSL_CAPP_FLAG | SSL_SAPP_FLAG)
+#define SSLPP_ENCRYPTED_FLAGS2 \
+    (SSL_HS_SDONE_FLAG | SSL_CHANGE_CIPHER_FLAG | \
+    SSL_CAPP_FLAG | SSL_SAPP_FLAG)
+
+struct SSLData
+{
+    uint32_t ssn_flags;
+    uint16_t partial_rec_len[4];
+};
+
+struct SSL_counters_t
+{
+    uint64_t stopped;
+    uint64_t disabled;
+    uint64_t decoded;
+    uint64_t alerts;
+    uint64_t cipher_change;
+    uint64_t unrecognized;
+    uint64_t completed_hs;
+    uint64_t bad_handshakes;
+    uint64_t hs_chello;
+    uint64_t hs_shello;
+    uint64_t hs_cert;
+    uint64_t hs_skey;
+    uint64_t hs_ckey;
+    uint64_t hs_finished;
+    uint64_t hs_sdone;
+    uint64_t capp;
+    uint64_t sapp;
+};
+
+class SslFlowData : public FlowData
+{
+public:
+    SslFlowData() : FlowData(flow_id)
+    { memset(&session, 0, sizeof(session)); }
+
+    ~SslFlowData() { }
+
+    static void init()
+    { flow_id = FlowData::get_flow_id(); }
+
+public:
+    static unsigned flow_id;
+    SSLData session;
+};
+
+SSLData* get_ssl_session_data(Flow* flow);
+void SSL_InitGlobals(void);
+
+#endif /* SSL_INSPECTOR_H */
+
diff --git a/src/service_inspectors/ssl/ssl_module.cc b/src/service_inspectors/ssl/ssl_module.cc
new file mode 100644 (file)
index 0000000..becbbe7
--- /dev/null
@@ -0,0 +1,121 @@
+//--------------------------------------------------------------------------
+// Copyright (C) 2015-2015 Cisco and/or its affiliates. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation.  You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// 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 along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+//--------------------------------------------------------------------------
+
+// ssl_module.cc author Bhagyashree Bantwal <bbantwal@cisco.com>
+
+#include "ssl_module.h"
+
+#include <assert.h>
+#include <sstream>
+
+#include "parser.h"
+#include "ssl_inspector.h"
+
+using namespace std;
+
+#define SSL_INVALID_CLIENT_HELLO_STR "Invalid Client HELLO after Server HELLO Detected"
+#define SSL_INVALID_SERVER_HELLO_STR "Invalid Server HELLO without Client HELLO Detected"
+#define SSL_HEARTBLEED_REQUEST_STR "Heartbeat Read Overrun Attempt Detected"
+#define SSL_HEARTBLEED_RESPONSE_STR "Large Heartbeat Response Detected"
+
+static const Parameter s_params[] =
+{
+    { "trust_servers", Parameter::PT_BOOL, nullptr, "false",
+      "disables requirement that application (encrypted) data must be observed on both sides" },
+
+    { "max_heartbeat_length", Parameter::PT_INT, "0:65535", "0",
+      "maximum length of heartbeat record allowed" },
+
+    { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
+};
+
+static const RuleMap ssl_rules[] =
+{
+    { SSL_INVALID_CLIENT_HELLO, SSL_INVALID_CLIENT_HELLO_STR },
+    { SSL_INVALID_SERVER_HELLO, SSL_INVALID_SERVER_HELLO_STR },
+    { SSL_ALERT_HB_REQUEST, SSL_HEARTBLEED_REQUEST_STR },
+    { SSL_ALERT_HB_RESPONSE, SSL_HEARTBLEED_RESPONSE_STR },
+
+    { 0, nullptr }
+};
+
+//-------------------------------------------------------------------------
+// ssl module
+//-------------------------------------------------------------------------
+
+SslModule::SslModule() : Module(SSL_NAME, SSL_HELP, s_params)
+{
+    conf = nullptr;
+}
+
+SslModule::~SslModule()
+{
+    if ( conf )
+        delete conf;
+}
+
+const RuleMap* SslModule::get_rules() const
+{ return ssl_rules; }
+
+const PegInfo* SslModule::get_pegs() const
+{ return simple_pegs; }
+
+PegCount* SslModule::get_counts() const
+{ return (PegCount*)&sslstats; }
+
+ProfileStats* SslModule::get_profile() const
+{ return &sslPerfStats; }
+
+bool SslModule::set(const char*, Value& v, SnortConfig*)
+{
+    if ( v.is("trust_servers") )
+    {
+        if (v.get_bool())
+            conf->flags |= SSLPP_TRUSTSERVER_FLAG;
+    }
+    else if ( v.is("max_heartbeat_length") )
+        conf->max_heartbeat_len = v.get_long();
+
+    else
+        return false;
+
+    return true;
+}
+
+SSL_PROTO_CONF* SslModule::get_data()
+{
+    SSL_PROTO_CONF* tmp = conf;
+    conf = nullptr;
+    return tmp;
+}
+
+bool SslModule::begin(const char*, int, SnortConfig*)
+{
+    conf = new SSL_PROTO_CONF;
+    conf->max_heartbeat_len = 0;
+    conf->flags = 0;
+    return true;
+}
+
+bool SslModule::end(const char*, int, SnortConfig*)
+{
+    SSL_InitGlobals();
+
+    return true;
+}
+
diff --git a/src/service_inspectors/ssl/ssl_module.h b/src/service_inspectors/ssl/ssl_module.h
new file mode 100644 (file)
index 0000000..01f96f2
--- /dev/null
@@ -0,0 +1,69 @@
+//--------------------------------------------------------------------------
+// Copyright (C) 2015-2015 Cisco and/or its affiliates. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation.  You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// 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 along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+//--------------------------------------------------------------------------
+
+// ssl_module.h author Bhagyashree Bantwal <bbantwal@cisco.com>
+
+#ifndef SSL_MODULE_H
+#define SSL_MODULE_H
+
+#include "framework/module.h"
+#include "framework/bits.h"
+#include "main/thread.h"
+#include "ssl_config.h"
+
+#define GID_SSL 137
+
+#define     SSL_INVALID_CLIENT_HELLO               1
+#define     SSL_INVALID_SERVER_HELLO               2
+#define     SSL_ALERT_HB_REQUEST                   3
+#define     SSL_ALERT_HB_RESPONSE                  4
+
+#define SSL_NAME "ssl"
+#define SSL_HELP "ssl inspection"
+
+struct SnortConfig;
+
+extern THREAD_LOCAL SimpleStats sslstats;
+extern THREAD_LOCAL ProfileStats sslPerfStats;
+
+class SslModule : public Module
+{
+public:
+    SslModule();
+    ~SslModule();
+
+    bool set(const char*, Value&, SnortConfig*) override;
+    bool begin(const char*, int, SnortConfig*) override;
+    bool end(const char*, int, SnortConfig*) override;
+
+    unsigned get_gid() const override
+    { return GID_SSL; }
+
+    const RuleMap* get_rules() const override;
+    const PegInfo* get_pegs() const override;
+    PegCount* get_counts() const override;
+    ProfileStats* get_profile() const override;
+
+    SSL_PROTO_CONF* get_data();
+
+private:
+    SSL_PROTO_CONF* conf;
+};
+
+#endif
+
index fb7e1615b39d165c4c842155d8f8ad7fdd552b5c..3d76e291e99aa5247ff410b964f8497a4976e021 100644 (file)
@@ -13,6 +13,7 @@ add_library(preprocessor_states
     pps_perfmonitor.cc
     pps_rpc_decode.cc
     pps_ssh.cc
+    pps_ssl.cc
     pps_dns.cc
     pps_pop.cc
     pps_imap.cc
index 0d190f55f2e2f56f12bb76c7027fee023da233c8..c75a3a47c4ab9af84d4e6d36cba54305ad7e25e1 100644 (file)
@@ -17,6 +17,7 @@ pps_normalizers.cc \
 pps_perfmonitor.cc \
 pps_rpc_decode.cc \
 pps_ssh.cc \
+pps_ssl.cc \
 pps_dns.cc \
 pps_pop.cc \
 pps_imap.cc \
diff --git a/tools/snort2lua/preprocessor_states/pps_ssl.cc b/tools/snort2lua/preprocessor_states/pps_ssl.cc
new file mode 100644 (file)
index 0000000..0bb028b
--- /dev/null
@@ -0,0 +1,162 @@
+//--------------------------------------------------------------------------
+// Copyright (C) 2015-2015 Cisco and/or its affiliates. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation.  You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// 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 along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+//--------------------------------------------------------------------------
+// pps_ssl.cc author Bhagya Bantwal <bbantwal@cisco.com>
+
+#include <sstream>
+#include <vector>
+
+#include "conversion_state.h"
+#include "helpers/s2l_util.h"
+#include "helpers/util_binder.h"
+
+namespace preprocessors
+{
+namespace
+{
+class Ssl : public ConversionState
+{
+public:
+    Ssl(Converter& c) : ConversionState(c) { }
+    virtual ~Ssl() { }
+    virtual bool convert(std::istringstream& data_stream);
+};
+} // namespace
+
+bool Ssl::convert(std::istringstream& data_stream)
+{
+    std::string keyword;
+    bool retval = true;
+    bool ports_set = false;
+    Binder bind(table_api);
+
+    bind.set_when_proto("tcp");
+    bind.set_use_type("ssl");
+
+    table_api.open_table("ssl");
+
+    // parse the file configuration
+    while (util::get_string(data_stream, keyword, ","))
+    {
+        bool tmpval = true;
+        std::istringstream arg_stream(keyword);
+
+        // should be gauranteed to happen.  Checking for error just cause
+        if (!(arg_stream >> keyword))
+            tmpval = false;
+
+        else if (!keyword.compare("noinspect_encrypted"))
+            table_api.add_deleted_comment("noinspect_encrypted");
+
+        else if (!keyword.compare("trustservers"))
+            tmpval = table_api.add_option("trust_servers", true);
+
+        else if (!keyword.compare("max_heartbeat_length"))
+        {
+            tmpval = parse_int_option("max_heartbeat_length", arg_stream, false);
+        }
+        else if (!keyword.compare("ports"))
+        {
+            std::string tmp = "";
+            table_api.add_diff_option_comment("ports", "bindings");
+
+            if (arg_stream >> keyword)
+            {
+                if (!keyword.compare("{"))
+                {
+                    while (arg_stream >> keyword && keyword.compare("}"))
+                    {
+                        ports_set = true;
+                        bind.add_when_port(keyword);
+                    }
+                }
+                else
+                {
+                    data_api.failed_conversion(arg_stream, "ports <bracketed_port_list>");
+                    retval = false;
+                }
+            }
+        }
+        else
+        {
+            tmpval = false;
+        }
+
+        if (!tmpval)
+        {
+            data_api.failed_conversion(arg_stream, keyword);
+            retval = false;
+        }
+    }
+
+    if (!ports_set)
+    {
+        bind.add_when_port("443");
+        bind.add_when_port("465");
+        bind.add_when_port("563");
+        bind.add_when_port("639");
+        bind.add_when_port("989");
+        bind.add_when_port("992");
+        bind.add_when_port("993");
+        bind.add_when_port("994");
+        bind.add_when_port("995");
+        bind.add_when_port("7801");
+        bind.add_when_port("7802");
+        bind.add_when_port("7900");
+        bind.add_when_port("7901");
+        bind.add_when_port("7902");
+        bind.add_when_port("7903");
+        bind.add_when_port("7904");
+        bind.add_when_port("7905");
+        bind.add_when_port("7906");
+        bind.add_when_port("7907");
+        bind.add_when_port("7908");
+        bind.add_when_port("7909");
+        bind.add_when_port("7910");
+        bind.add_when_port("7911");
+        bind.add_when_port("7912");
+        bind.add_when_port("7913");
+        bind.add_when_port("7914");
+        bind.add_when_port("7915");
+        bind.add_when_port("7916");
+        bind.add_when_port("7917");
+        bind.add_when_port("7918");
+        bind.add_when_port("7919");
+        bind.add_when_port("7920");
+    }
+
+    return retval;
+}
+
+/**************************
+ *******  A P I ***********
+ **************************/
+
+static ConversionState* ctor(Converter& c)
+{
+    return new Ssl(c);
+}
+
+static const ConvertMap preprocessor_ssl =
+{
+    "ssl",
+    ctor,
+};
+
+const ConvertMap* ssl_map = &preprocessor_ssl;
+}
+
index 5001ab4693fd6ab6780123eee2f5320ebdf99211..b84d30072dafba622bb77e8d1fda22bb20096a24 100644 (file)
@@ -39,6 +39,7 @@ extern const ConvertMap* normalizer_tcp_map;
 extern const ConvertMap* perfmonitor_map;
 extern const ConvertMap* rpc_decode_map;
 extern const ConvertMap* ssh_map;
+extern const ConvertMap* ssl_map;
 extern const ConvertMap* dns_map;
 extern const ConvertMap* pop_map;
 extern const ConvertMap* imap_map;
@@ -69,6 +70,7 @@ const std::vector<const ConvertMap*> preprocessor_api =
     perfmonitor_map,
     rpc_decode_map,
     ssh_map,
+    ssl_map,
     dns_map,
     pop_map,
     imap_map,
index af862f2c29bec654618ccdf0fae34480d72c2e0f..3a7f82a8ac0667c3e2866ea8244fcb715960acc2 100644 (file)
@@ -71,6 +71,8 @@ extern const ConvertMap* session_map;
 extern const ConvertMap* sid_map;
 extern const ConvertMap* stream_reassemble_map;
 extern const ConvertMap* stream_size_map;
+extern const ConvertMap* ssl_state_map;
+extern const ConvertMap* ssl_version_map;
 extern const ConvertMap* tag_map;
 extern const ConvertMap* threshold_map;
 extern const ConvertMap* ttl_map;
@@ -128,6 +130,8 @@ const std::vector<const ConvertMap*> rule_options_api =
     sid_map,
     stream_reassemble_map,
     stream_size_map,
+    ssl_state_map,
+    ssl_version_map,
     tag_map,
     threshold_map,
     ttl_map,
index 31589c76ff9e3baca26992ab8f60d1f57937b33c..16ab080ec69f61740258d546b6662e336869b6db 100644 (file)
@@ -547,5 +547,32 @@ static const ConvertMap rule_priority =
 };
 
 const ConvertMap* priority_map = &rule_priority;
+
+/************************************
+ *********  SSL STATE  **************
+ ************************************/
+
+static const std::string ssl_state = "ssl_state";
+static const ConvertMap rule_ssl_state =
+{
+    ssl_state,
+    unchanged_rule_ctor<& ssl_state>,
+};
+
+const ConvertMap* ssl_state_map = &rule_ssl_state;
+
+/************************************
+ *********  SSL VERSION **************
+ ************************************/
+
+static const std::string ssl_version = "ssl_version";
+static const ConvertMap rule_ssl_version =
+{
+    ssl_version,
+    unchanged_rule_ctor<& ssl_version>,
+};
+
+const ConvertMap* ssl_version_map = &rule_ssl_version;
+
 } // namespace rule