From: Tom Peters (thopeter) Date: Tue, 20 Jun 2017 17:42:51 +0000 (-0400) Subject: Merge pull request #929 in SNORT/snort3 from ssl_splitter to master X-Git-Tag: 3.0.0-239~39 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=da3607d50655008648bbf9d0177bc7e9211c0c53;p=thirdparty%2Fsnort3.git Merge pull request #929 in SNORT/snort3 from ssl_splitter to master Squashed commit of the following: commit 79d04e69161c7d6e9c5ae83546e1102ceb746148 Author: Steven Baigal Date: Mon Jun 12 16:32:33 2017 -0400 add ssl splitter --- diff --git a/src/service_inspectors/ssl/CMakeLists.txt b/src/service_inspectors/ssl/CMakeLists.txt index d91614fbf..5db4f30de 100644 --- a/src/service_inspectors/ssl/CMakeLists.txt +++ b/src/service_inspectors/ssl/CMakeLists.txt @@ -1,12 +1,14 @@ set( FILE_LIST + ips_ssl_state.cc + ips_ssl_version.cc + ssl_config.h ssl_inspector.cc ssl_inspector.h - ssl_config.h ssl_module.cc ssl_module.h - ips_ssl_state.cc - ips_ssl_version.cc + ssl_splitter.cc + ssl_splitter.h ) # can't be be linked dynamically yet diff --git a/src/service_inspectors/ssl/Makefile.am b/src/service_inspectors/ssl/Makefile.am index 43309288c..b38c5da15 100644 --- a/src/service_inspectors/ssl/Makefile.am +++ b/src/service_inspectors/ssl/Makefile.am @@ -1,12 +1,14 @@ file_list = \ +ips_ssl_state.cc \ +ips_ssl_version.cc \ ssl_config.h \ ssl_inspector.cc \ ssl_inspector.h \ ssl_module.cc \ ssl_module.h \ -ips_ssl_state.cc \ -ips_ssl_version.cc +ssl_splitter.cc \ +ssl_splitter.h # can't be linked dynamically yet #if STATIC_INSPECTORS diff --git a/src/service_inspectors/ssl/ssl_inspector.cc b/src/service_inspectors/ssl/ssl_inspector.cc index d340fbf8b..4060e3385 100644 --- a/src/service_inspectors/ssl/ssl_inspector.cc +++ b/src/service_inspectors/ssl/ssl_inspector.cc @@ -37,6 +37,7 @@ #include "stream/stream_splitter.h" #include "ssl_module.h" +#include "ssl_splitter.h" THREAD_LOCAL ProfileStats sslPerfStats; THREAD_LOCAL SslStats sslstats; @@ -413,7 +414,7 @@ public: void eval(Packet*) override; StreamSplitter* get_splitter(bool c2s) - { return new StopAndWaitSplitter(c2s); } + { return new SslSplitter(c2s); } private: SSL_PROTO_CONF* config; diff --git a/src/service_inspectors/ssl/ssl_splitter.cc b/src/service_inspectors/ssl/ssl_splitter.cc new file mode 100644 index 000000000..0da15dcab --- /dev/null +++ b/src/service_inspectors/ssl/ssl_splitter.cc @@ -0,0 +1,142 @@ +//-------------------------------------------------------------------------- +// Copyright (C) 2017-2017 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_splitter.cc author Steven Baigal + +#include "ssl_splitter.h" + +#include + +#include "protocols/ssl.h" + +SslSplitter::SslSplitter(bool c2s) : StreamSplitter(c2s) +{ + paf_state = SSL_PAF_STATES_START; + remain_len = 0; + len_bytes[0] = len_bytes[1] = 0; + is_sslv2 = false; +} + +StreamSplitter::Status SslSplitter::scan( + Flow*, const uint8_t* data, uint32_t len, + uint32_t, uint32_t* fp) +{ + uint32_t n = 0; + uint32_t skip_len = 0; + uint32_t last_fp = 0; + + while (n < len) + { + switch (paf_state) + { + case SSL_PAF_STATES_START: + if (data[n] >= SSL_CHANGE_CIPHER_REC and data[n] <= SSL_HEARTBEAT_REC) + { + is_sslv2 = false; + paf_state = SSL_PAF_STATES_VER_MJR; + } + else if ((data[n] & 0x80) or is_sslv2) + { + len_bytes[0] = data[n]; + is_sslv2 = true; + paf_state = SSL_PAF_STATES_LEN2_V2; + } + else + { + // unknown + if (last_fp > 0) + { + // stop here and flush out the good records + // it will come to ABORT on subsequent scan + n = len; + } + else + { + return StreamSplitter::ABORT; + } + } + break; + case SSL_PAF_STATES_VER_MJR: + paf_state = SSL_PAF_STATES_VER_MNR; + break; + case SSL_PAF_STATES_VER_MNR: + paf_state = SSL_PAF_STATES_LEN1; + break; + case SSL_PAF_STATES_LEN1: + len_bytes[0] = data[n]; + paf_state = SSL_PAF_STATES_LEN2; + break; + case SSL_PAF_STATES_LEN2: + len_bytes[1] = data[n]; + remain_len = (len_bytes[0] << 8) + len_bytes[1]; + if (remain_len == 0) + { + last_fp = n; + paf_state = SSL_PAF_STATES_START; + } + else + { + paf_state = SSL_PAF_STATES_DATA; + } + break; + case SSL_PAF_STATES_DATA: + skip_len = ((len-n) > remain_len) ? remain_len : (len - n); + remain_len -= skip_len; + n += skip_len; + if (remain_len == 0) + { + last_fp = n; + paf_state = SSL_PAF_STATES_START; + } + n--; + break; + case SSL_PAF_STATES_LEN2_V2: + len_bytes[1] = data[n]; + if (len_bytes[0] & 0x80) + { + // sslv2 using 2-byte length + len_bytes[0] = len_bytes[0] & 0x7F; + paf_state = SSL_PAF_STATES_DATA; + } + else + { + // sslv2 using 3-byte length + len_bytes[0] = len_bytes[0] & 0x3F; + paf_state = SSL_PAF_STATES_PAD_V2; + } + remain_len = (len_bytes[0] << 8) + len_bytes[1]; + break; + case SSL_PAF_STATES_PAD_V2: + paf_state = SSL_PAF_STATES_DATA; + break; + } + + n++; + } + // if a flush point was found, flush from there + if (last_fp > 0) + { + *fp = last_fp; + remain_len = 0; + paf_state = SSL_PAF_STATES_START; + return StreamSplitter::FLUSH; + } + + return StreamSplitter::SEARCH; +} + diff --git a/src/service_inspectors/ssl/ssl_splitter.h b/src/service_inspectors/ssl/ssl_splitter.h new file mode 100644 index 000000000..0ceaaf9d9 --- /dev/null +++ b/src/service_inspectors/ssl/ssl_splitter.h @@ -0,0 +1,67 @@ +//-------------------------------------------------------------------------- +// Copyright (C) 2017-2017 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_splitter.h author Steven Baigal + +#ifndef SSL_SPLITTER_H +#define SSL_SPLITTER_H + +// Protocol aware flushing for SSL +// TLSPlaintext records are flushed when end-of-record meets end-of segment +// The splitter supports both sslv2 and sslv3 record format, +// it starts by checking the first byte, if it is a valid sslv3 content type, +// mark the session as sslv3; else if the MSB bit was set, marks it as sslv2, +// if this bit is not set, yet the session was marked sslv2 from prior detection, +// continue as sslv2 + +#include "stream/stream_splitter.h" + +// Enumerations for PAF states +enum SslPafStates +{ + SSL_PAF_STATES_START = 0, //start, detect the ssl version, sslv3 type or sslv2 byte-0 + SSL_PAF_STATES_VER_MJR, // version major + SSL_PAF_STATES_VER_MNR, // version minor + SSL_PAF_STATES_LEN1, // length byte-0 + SSL_PAF_STATES_LEN2, // length byte-1 + SSL_PAF_STATES_DATA, // fragment + SSL_PAF_STATES_LEN2_V2, // sslv2, length byte-1 + SSL_PAF_STATES_PAD_V2, // sslv2, padding byte if needed +}; + +class SslSplitter : public StreamSplitter +{ +public: + SslSplitter(bool c2s); + + Status scan(Flow*, const uint8_t* data, uint32_t len, + uint32_t flags, uint32_t* fp) override; + + bool is_paf() override + { + return true; + } + +private: + SslPafStates paf_state; + uint16_t remain_len; + uint8_t len_bytes[2]; // temporary buffer to hold 2-byte length field + bool is_sslv2; +}; + +#endif