From 038fbf9b9eadb7b9fe79e3af63595002b80b7dc4 Mon Sep 17 00:00:00 2001 From: Johanna Amann Date: Tue, 10 Mar 2015 20:37:33 -0700 Subject: [PATCH 01/11] First step for a DTLS analyzer. This commit mostly does a lot of refactoring of the current SSL analyzer, which is split into several parts. The handshake protocol is completely taken out of the SSL analyzer and was refactored into its own analyzer (called tls-handshake-analyzer). This will also (finally) make it possible to deal with TLS record fragmentation. Apart from that, the parts of the SSL analyzer that are common to DTLS were split into their own pac files. Both the SSL analyzer and the (very basic, mostly nonfunctional) DTLS analyzer use their own pac files and those shared pac files. All SSL tests still pass after refactoring so I hope I did not break anything too badly. At the moment, we have two different modules in one directory and I guess the way I am doing this might be an abuse of the system. It seems to work though... --- scripts/base/protocols/ssl/main.bro | 10 +- src/analyzer/protocol/ssl/CMakeLists.txt | 10 +- src/analyzer/protocol/ssl/DTLS.cc | 32 + src/analyzer/protocol/ssl/DTLS.h | 31 + src/analyzer/protocol/ssl/Plugin_DTLS.cc | 26 + .../protocol/ssl/{Plugin.cc => Plugin_SSL.cc} | 0 src/analyzer/protocol/ssl/SSL.cc | 19 + src/analyzer/protocol/ssl/SSL.h | 8 +- src/analyzer/protocol/ssl/dtls-analyzer.pac | 2 + src/analyzer/protocol/ssl/dtls-protocol.pac | 40 ++ src/analyzer/protocol/ssl/dtls.pac | 30 + .../protocol/ssl/proc-certificate.pac | 30 + .../protocol/ssl/proc-client-hello.pac | 42 ++ .../protocol/ssl/proc-server-hello.pac | 36 + src/analyzer/protocol/ssl/ssl-analyzer.pac | 528 +------------- src/analyzer/protocol/ssl/ssl-defs.pac | 79 +++ .../protocol/ssl/ssl-dtls-analyzer.pac | 106 +++ .../protocol/ssl/ssl-dtls-protocol.pac | 134 ++++ src/analyzer/protocol/ssl/ssl-protocol.pac | 645 +----------------- src/analyzer/protocol/ssl/ssl.pac | 11 +- .../protocol/ssl/tls-handshake-analyzer.pac | 273 ++++++++ .../protocol/ssl/tls-handshake-protocol.pac | 533 +++++++++++++++ src/analyzer/protocol/ssl/tls-handshake.pac | 24 + testing/btest/Traces/tls/dtls-openssl.pcap | Bin 0 -> 3181 bytes 24 files changed, 1487 insertions(+), 1162 deletions(-) create mode 100644 src/analyzer/protocol/ssl/DTLS.cc create mode 100644 src/analyzer/protocol/ssl/DTLS.h create mode 100644 src/analyzer/protocol/ssl/Plugin_DTLS.cc rename src/analyzer/protocol/ssl/{Plugin.cc => Plugin_SSL.cc} (100%) create mode 100644 src/analyzer/protocol/ssl/dtls-analyzer.pac create mode 100644 src/analyzer/protocol/ssl/dtls-protocol.pac create mode 100644 src/analyzer/protocol/ssl/dtls.pac create mode 100644 src/analyzer/protocol/ssl/proc-certificate.pac create mode 100644 src/analyzer/protocol/ssl/proc-client-hello.pac create mode 100644 src/analyzer/protocol/ssl/proc-server-hello.pac create mode 100644 src/analyzer/protocol/ssl/ssl-dtls-analyzer.pac create mode 100644 src/analyzer/protocol/ssl/ssl-dtls-protocol.pac create mode 100644 src/analyzer/protocol/ssl/tls-handshake-analyzer.pac create mode 100644 src/analyzer/protocol/ssl/tls-handshake-protocol.pac create mode 100644 src/analyzer/protocol/ssl/tls-handshake.pac create mode 100644 testing/btest/Traces/tls/dtls-openssl.pcap diff --git a/scripts/base/protocols/ssl/main.bro b/scripts/base/protocols/ssl/main.bro index a1461db82d..d2b0332756 100644 --- a/scripts/base/protocols/ssl/main.bro +++ b/scripts/base/protocols/ssl/main.bro @@ -92,16 +92,20 @@ redef record Info += { delay_tokens: set[string] &optional; }; -const ports = { +const ssl_ports = { 443/tcp, 563/tcp, 585/tcp, 614/tcp, 636/tcp, 989/tcp, 990/tcp, 992/tcp, 993/tcp, 995/tcp, 5223/tcp }; -redef likely_server_ports += { ports }; + +const dtls_ports = { 4433/udp }; + +redef likely_server_ports += { ssl_ports, dtls_ports }; event bro_init() &priority=5 { Log::create_stream(SSL::LOG, [$columns=Info, $ev=log_ssl]); - Analyzer::register_for_ports(Analyzer::ANALYZER_SSL, ports); + Analyzer::register_for_ports(Analyzer::ANALYZER_SSL, ssl_ports); + Analyzer::register_for_ports(Analyzer::ANALYZER_DTLS, dtls_ports); } function set_session(c: connection) diff --git a/src/analyzer/protocol/ssl/CMakeLists.txt b/src/analyzer/protocol/ssl/CMakeLists.txt index 2591c5dfec..fab0d30f07 100644 --- a/src/analyzer/protocol/ssl/CMakeLists.txt +++ b/src/analyzer/protocol/ssl/CMakeLists.txt @@ -4,7 +4,13 @@ include(BroPlugin) include_directories(BEFORE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR}) bro_plugin_begin(Bro SSL) -bro_plugin_cc(SSL.cc Plugin.cc) +bro_plugin_cc(SSL.cc Plugin_SSL.cc) bro_plugin_bif(events.bif) -bro_plugin_pac(ssl.pac ssl-analyzer.pac ssl-protocol.pac ssl-defs.pac) +bro_plugin_pac(tls-handshake.pac tls-handshake-protocol.pac tls-handshake-analyzer.pac) +bro_plugin_pac(ssl.pac ssl-dtls-analyzer.pac ssl-analyzer.pac ssl-dtls-protocol.pac ssl-protocol.pac ssl-defs.pac) +bro_plugin_end() + +bro_plugin_begin(Bro DTLS) +bro_plugin_cc(DTLS.cc Plugin_DTLS.cc) +bro_plugin_pac(dtls.pac ssl-dtls-analyzer.pac dtls-analyzer.pac ssl-dtls-protocol.pac dtls-protocol.pac ssl-defs.pac) bro_plugin_end() diff --git a/src/analyzer/protocol/ssl/DTLS.cc b/src/analyzer/protocol/ssl/DTLS.cc new file mode 100644 index 0000000000..7c49dba439 --- /dev/null +++ b/src/analyzer/protocol/ssl/DTLS.cc @@ -0,0 +1,32 @@ + +#include "DTLS.h" +#include "Reporter.h" +#include "util.h" + +#include "events.bif.h" + +using namespace analyzer::dtls; + +DTLS_Analyzer::DTLS_Analyzer(Connection* c) +: analyzer::Analyzer("DTLS", c) + { + interp = new binpac::DTLS::SSL_Conn(this); + fprintf(stderr, "Instantiated :)\n"); + } + +DTLS_Analyzer::~DTLS_Analyzer() + { + delete interp; + } + +void DTLS_Analyzer::Done() + { + Analyzer::Done(); + } + +void DTLS_Analyzer::DeliverPacket(int len, const u_char* data, bool orig, uint64 seq, const IP_Hdr* ip, int caplen) + { + Analyzer::DeliverPacket(len, data, orig, seq, ip, caplen); + fprintf(stderr, "Delivered packet :)\n"); + interp->NewData(orig, data, data + len); + } diff --git a/src/analyzer/protocol/ssl/DTLS.h b/src/analyzer/protocol/ssl/DTLS.h new file mode 100644 index 0000000000..c45a311c8c --- /dev/null +++ b/src/analyzer/protocol/ssl/DTLS.h @@ -0,0 +1,31 @@ +#ifndef ANALYZER_PROTOCOL_SSL_DTLS_H +#define ANALYZER_PROTOCOL_SSL_DTLS_H + +#include "events.bif.h" + +#include "analyzer/protocol/udp/UDP.h" +#include "dtls_pac.h" + +namespace analyzer { namespace dtls { + +class DTLS_Analyzer : public analyzer::Analyzer { +public: + DTLS_Analyzer(Connection* conn); + virtual ~DTLS_Analyzer(); + + // Overriden from Analyzer. + virtual void Done(); + virtual void DeliverPacket(int len, const u_char* data, bool orig, + uint64 seq, const IP_Hdr* ip, int caplen); + + + static analyzer::Analyzer* Instantiate(Connection* conn) + { return new DTLS_Analyzer(conn); } + +protected: + binpac::DTLS::SSL_Conn* interp; +}; + +} } // namespace analyzer::* + +#endif diff --git a/src/analyzer/protocol/ssl/Plugin_DTLS.cc b/src/analyzer/protocol/ssl/Plugin_DTLS.cc new file mode 100644 index 0000000000..6820816e31 --- /dev/null +++ b/src/analyzer/protocol/ssl/Plugin_DTLS.cc @@ -0,0 +1,26 @@ +// See the file in the main distribution directory for copyright. + + +#include "plugin/Plugin.h" + +#include "DTLS.h" + +namespace plugin { +namespace Bro_DTLS { + +class Plugin : public plugin::Plugin { +public: + plugin::Configuration Configure() + { + AddComponent(new ::analyzer::Component("DTLS", ::analyzer::dtls::DTLS_Analyzer::Instantiate)); + + plugin::Configuration config; + config.name = "Bro::DTLS"; + config.description = "DTLS analyzer"; + return config; + } +} plugin; + +} +} + diff --git a/src/analyzer/protocol/ssl/Plugin.cc b/src/analyzer/protocol/ssl/Plugin_SSL.cc similarity index 100% rename from src/analyzer/protocol/ssl/Plugin.cc rename to src/analyzer/protocol/ssl/Plugin_SSL.cc diff --git a/src/analyzer/protocol/ssl/SSL.cc b/src/analyzer/protocol/ssl/SSL.cc index 5e5d24888a..a26807c14b 100644 --- a/src/analyzer/protocol/ssl/SSL.cc +++ b/src/analyzer/protocol/ssl/SSL.cc @@ -5,6 +5,8 @@ #include "util.h" #include "events.bif.h" +#include "ssl_pac.h" +#include "tls-handshake_pac.h" using namespace analyzer::ssl; @@ -12,12 +14,14 @@ SSL_Analyzer::SSL_Analyzer(Connection* c) : tcp::TCP_ApplicationAnalyzer("SSL", c) { interp = new binpac::SSL::SSL_Conn(this); + handshake_interp = new binpac::TLSHandshake::Handshake_Conn(this); had_gap = false; } SSL_Analyzer::~SSL_Analyzer() { delete interp; + delete handshake_interp; } void SSL_Analyzer::Done() @@ -57,6 +61,21 @@ void SSL_Analyzer::DeliverStream(int len, const u_char* data, bool orig) } } +void SSL_Analyzer::SendHandshake(uint8 msg_type, uint32 length, const u_char* begin, const u_char* end, bool orig) + { + handshake_interp->set_msg_type(msg_type); + handshake_interp->set_msg_length(length); + try + { + handshake_interp->NewData(orig, begin, end); + } + catch ( const binpac::Exception& e ) + { + ProtocolViolation(fmt("Binpac exception: %s", e.c_msg())); + fprintf(stderr, "Handshake exception: %s\n", e.c_msg()); + } + } + void SSL_Analyzer::Undelivered(uint64 seq, int len, bool orig) { tcp::TCP_ApplicationAnalyzer::Undelivered(seq, len, orig); diff --git a/src/analyzer/protocol/ssl/SSL.h b/src/analyzer/protocol/ssl/SSL.h index 5ef09aa147..a17611846c 100644 --- a/src/analyzer/protocol/ssl/SSL.h +++ b/src/analyzer/protocol/ssl/SSL.h @@ -4,7 +4,10 @@ #include "events.bif.h" #include "analyzer/protocol/tcp/TCP.h" -#include "ssl_pac.h" + +namespace binpac { namespace SSL { class SSL_Conn; } } + +namespace binpac { namespace TLSHandshake { class Handshake_Conn; } } namespace analyzer { namespace ssl { @@ -18,6 +21,8 @@ public: virtual void DeliverStream(int len, const u_char* data, bool orig); virtual void Undelivered(uint64 seq, int len, bool orig); + void SendHandshake(uint8 msg_type, uint32 length, const u_char* begin, const u_char* end, bool orig); + // Overriden from tcp::TCP_ApplicationAnalyzer. virtual void EndpointEOF(bool is_orig); @@ -26,6 +31,7 @@ public: protected: binpac::SSL::SSL_Conn* interp; + binpac::TLSHandshake::Handshake_Conn* handshake_interp; bool had_gap; }; diff --git a/src/analyzer/protocol/ssl/dtls-analyzer.pac b/src/analyzer/protocol/ssl/dtls-analyzer.pac new file mode 100644 index 0000000000..139597f9cb --- /dev/null +++ b/src/analyzer/protocol/ssl/dtls-analyzer.pac @@ -0,0 +1,2 @@ + + diff --git a/src/analyzer/protocol/ssl/dtls-protocol.pac b/src/analyzer/protocol/ssl/dtls-protocol.pac new file mode 100644 index 0000000000..94cddf9cbc --- /dev/null +++ b/src/analyzer/protocol/ssl/dtls-protocol.pac @@ -0,0 +1,40 @@ + +###################################################################### +# initial datatype for binpac +###################################################################### + +type DTLSPDU(is_orig: bool) = record { + records: SSLRecord(is_orig)[] &transient; +}; + +type SSLRecord(is_orig: bool) = record { + content_type: uint8; + version: uint16; + epoch: uint16; + sequence_number: uint48; + length: uint16; + rec: PlaintextRecord(this)[] &length=length; +# data: bytestring &restofdata &transient; +} &byteorder = bigendian, + &let { + parse : bool = $context.connection.proc_dtls(this, to_int()(sequence_number)); +}; + +type Handshake(rec: SSLRecord) = record { + msg_type: uint8; + length: uint24; + message_seq: uint16; + fragment_offset: uint24; + fragment_length: uint24; +} + +refine connection SSL_Conn += { + + function proc_dtls(pdu: SSLRecord, sequence: uint64): bool + %{ + fprintf(stderr, "Type: %d, sequence number: %d, epoch: %d\n", ${pdu.content_type}, sequence, ${pdu.epoch}); + + return true; + %} + +}; diff --git a/src/analyzer/protocol/ssl/dtls.pac b/src/analyzer/protocol/ssl/dtls.pac new file mode 100644 index 0000000000..50424f0d8c --- /dev/null +++ b/src/analyzer/protocol/ssl/dtls.pac @@ -0,0 +1,30 @@ +# binpac file for SSL analyzer + +%include binpac.pac +%include bro.pac + +%extern{ +#include "events.bif.h" +%} + +analyzer DTLS withcontext { + connection: SSL_Conn; + flow: DTLS_Flow; +}; + +connection SSL_Conn(bro_analyzer: BroAnalyzer) { + upflow = DTLS_Flow(true); + downflow = DTLS_Flow(false); +}; + +%include ssl-dtls-protocol.pac +%include dtls-protocol.pac + +flow DTLS_Flow(is_orig: bool) { +# flowunit = SSLRecord(is_orig) withcontext(connection, this); + datagram = DTLSPDU(is_orig) withcontext(connection, this); +} + +%include ssl-dtls-analyzer.pac +%include dtls-analyzer.pac +%include ssl-defs.pac diff --git a/src/analyzer/protocol/ssl/proc-certificate.pac b/src/analyzer/protocol/ssl/proc-certificate.pac new file mode 100644 index 0000000000..c2353e3a88 --- /dev/null +++ b/src/analyzer/protocol/ssl/proc-certificate.pac @@ -0,0 +1,30 @@ + function proc_certificate(is_orig: bool, certificates : bytestring[]) : bool + %{ + if ( certificates->size() == 0 ) + return true; + + ODesc common; + common.AddRaw("Analyzer::ANALYZER_SSL"); + common.Add(bro_analyzer()->Conn()->StartTime()); + common.AddRaw(is_orig ? "T" : "F", 1); + bro_analyzer()->Conn()->IDString(&common); + + for ( unsigned int i = 0; i < certificates->size(); ++i ) + { + const bytestring& cert = (*certificates)[i]; + + ODesc file_handle; + file_handle.Add(common.Description()); + file_handle.Add(i); + + string file_id = file_mgr->HashHandle(file_handle.Description()); + + file_mgr->DataIn(reinterpret_cast(cert.data()), + cert.length(), bro_analyzer()->GetAnalyzerTag(), + bro_analyzer()->Conn(), is_orig, file_id); + file_mgr->EndOfFile(file_id); + } + return true; + %} + + diff --git a/src/analyzer/protocol/ssl/proc-client-hello.pac b/src/analyzer/protocol/ssl/proc-client-hello.pac new file mode 100644 index 0000000000..601d0fce94 --- /dev/null +++ b/src/analyzer/protocol/ssl/proc-client-hello.pac @@ -0,0 +1,42 @@ + function proc_client_hello( + version : uint16, ts : double, + client_random : bytestring, + session_id : uint8[], + cipher_suites16 : uint16[], + cipher_suites24 : uint24[]) : bool + %{ + if ( ! version_ok(version) ) + { + bro_analyzer()->ProtocolViolation(fmt("unsupported client SSL version 0x%04x", version)); + bro_analyzer()->SetSkip(true); + } + else + bro_analyzer()->ProtocolConfirmation(); + + if ( ssl_client_hello ) + { + vector* cipher_suites = new vector(); + if ( cipher_suites16 ) + std::copy(cipher_suites16->begin(), cipher_suites16->end(), std::back_inserter(*cipher_suites)); + else + std::transform(cipher_suites24->begin(), cipher_suites24->end(), std::back_inserter(*cipher_suites), to_int()); + + VectorVal* cipher_vec = new VectorVal(internal_type("index_vec")->AsVectorType()); + for ( unsigned int i = 0; i < cipher_suites->size(); ++i ) + { + Val* ciph = new Val((*cipher_suites)[i], TYPE_COUNT); + cipher_vec->Assign(i, ciph); + } + + BifEvent::generate_ssl_client_hello(bro_analyzer(), bro_analyzer()->Conn(), + version, ts, new StringVal(client_random.length(), + (const char*) client_random.data()), + to_string_val(session_id), + cipher_vec); + + delete cipher_suites; + } + + return true; + %} + diff --git a/src/analyzer/protocol/ssl/proc-server-hello.pac b/src/analyzer/protocol/ssl/proc-server-hello.pac new file mode 100644 index 0000000000..2dfc940774 --- /dev/null +++ b/src/analyzer/protocol/ssl/proc-server-hello.pac @@ -0,0 +1,36 @@ + function proc_server_hello( + version : uint16, ts : double, + server_random : bytestring, + session_id : uint8[], + cipher_suites16 : uint16[], + cipher_suites24 : uint24[], + comp_method : uint8) : bool + %{ + if ( ! version_ok(version) ) + { + bro_analyzer()->ProtocolViolation(fmt("unsupported server SSL version 0x%04x", version)); + bro_analyzer()->SetSkip(true); + } + + if ( ssl_server_hello ) + { + vector* ciphers = new vector(); + + if ( cipher_suites16 ) + std::copy(cipher_suites16->begin(), cipher_suites16->end(), std::back_inserter(*ciphers)); + else + std::transform(cipher_suites24->begin(), cipher_suites24->end(), std::back_inserter(*ciphers), to_int()); + + BifEvent::generate_ssl_server_hello(bro_analyzer(), + bro_analyzer()->Conn(), + version, ts, new StringVal(server_random.length(), + (const char*) server_random.data()), + to_string_val(session_id), + ciphers->size()==0 ? 0 : ciphers->at(0), comp_method); + + delete ciphers; + } + + return true; + %} + diff --git a/src/analyzer/protocol/ssl/ssl-analyzer.pac b/src/analyzer/protocol/ssl/ssl-analyzer.pac index c835fd6632..709e8c32b2 100644 --- a/src/analyzer/protocol/ssl/ssl-analyzer.pac +++ b/src/analyzer/protocol/ssl/ssl-analyzer.pac @@ -1,352 +1,19 @@ # Analyzer for SSL (Bro-specific part). -%extern{ -#include -#include -#include -#include - -#include "util.h" - -#include "file_analysis/Manager.h" -%} - - -%header{ - class extract_certs { - public: - bytestring const& operator() (X509Certificate* cert) const - { - return cert->certificate(); - } - }; - - string orig_label(bool is_orig); - string handshake_type_label(int type); - %} - -%code{ -string orig_label(bool is_orig) - { - return string(is_orig ? "originator" :"responder"); - } - - string handshake_type_label(int type) - { - switch ( type ) { - case HELLO_REQUEST: return string("HELLO_REQUEST"); - case CLIENT_HELLO: return string("CLIENT_HELLO"); - case SERVER_HELLO: return string("SERVER_HELLO"); - case SESSION_TICKET: return string("SESSION_TICKET"); - case CERTIFICATE: return string("CERTIFICATE"); - case SERVER_KEY_EXCHANGE: return string("SERVER_KEY_EXCHANGE"); - case CERTIFICATE_REQUEST: return string("CERTIFICATE_REQUEST"); - case SERVER_HELLO_DONE: return string("SERVER_HELLO_DONE"); - case CERTIFICATE_VERIFY: return string("CERTIFICATE_VERIFY"); - case CLIENT_KEY_EXCHANGE: return string("CLIENT_KEY_EXCHANGE"); - case FINISHED: return string("FINISHED"); - case CERTIFICATE_URL: return string("CERTIFICATE_URL"); - case CERTIFICATE_STATUS: return string("CERTIFICATE_STATUS"); - default: return string(fmt("UNKNOWN (%d)", type)); - } - } - -%} - - -function to_string_val(data : uint8[]) : StringVal - %{ - char tmp[32]; - memset(tmp, 0, sizeof(tmp)); - - // Just return an empty string if the string is longer than 32 bytes - if ( data && data->size() <= 32 ) - { - for ( unsigned int i = data->size(); i > 0; --i ) - tmp[i-1] = (*data)[i-1]; - } - - return new StringVal(32, tmp); - %} - -function version_ok(vers : uint16) : bool - %{ - switch ( vers ) { - case SSLv20: - case SSLv30: - case TLSv10: - case TLSv11: - case TLSv12: - return true; - - default: - return false; - } - %} - refine connection SSL_Conn += { - %member{ - int established_; - %} + %include proc-client-hello.pac + %include proc-server-hello.pac + %include proc-certificate.pac - %init{ - established_ = false; - %} - - %cleanup{ - %} - - function proc_alert(rec: SSLRecord, level : int, desc : int) : bool - %{ - BifEvent::generate_ssl_alert(bro_analyzer(), bro_analyzer()->Conn(), - ${rec.is_orig}, level, desc); - return true; - %} - - function proc_client_hello(rec: SSLRecord, - version : uint16, ts : double, - client_random : bytestring, - session_id : uint8[], - cipher_suites16 : uint16[], - cipher_suites24 : uint24[]) : bool - %{ - if ( ! version_ok(version) ) - { - bro_analyzer()->ProtocolViolation(fmt("unsupported client SSL version 0x%04x", version)); - bro_analyzer()->SetSkip(true); - } - else - bro_analyzer()->ProtocolConfirmation(); - - if ( ssl_client_hello ) - { - vector* cipher_suites = new vector(); - if ( cipher_suites16 ) - std::copy(cipher_suites16->begin(), cipher_suites16->end(), std::back_inserter(*cipher_suites)); - else - std::transform(cipher_suites24->begin(), cipher_suites24->end(), std::back_inserter(*cipher_suites), to_int()); - - VectorVal* cipher_vec = new VectorVal(internal_type("index_vec")->AsVectorType()); - for ( unsigned int i = 0; i < cipher_suites->size(); ++i ) - { - Val* ciph = new Val((*cipher_suites)[i], TYPE_COUNT); - cipher_vec->Assign(i, ciph); - } - - BifEvent::generate_ssl_client_hello(bro_analyzer(), bro_analyzer()->Conn(), - version, ts, new StringVal(client_random.length(), - (const char*) client_random.data()), - to_string_val(session_id), - cipher_vec); - - delete cipher_suites; - } - - return true; - %} - - function proc_server_hello(rec: SSLRecord, - version : uint16, ts : double, - server_random : bytestring, - session_id : uint8[], - cipher_suites16 : uint16[], - cipher_suites24 : uint24[], - comp_method : uint8) : bool - %{ - if ( ! version_ok(version) ) - { - bro_analyzer()->ProtocolViolation(fmt("unsupported server SSL version 0x%04x", version)); - bro_analyzer()->SetSkip(true); - } - - if ( ssl_server_hello ) - { - vector* ciphers = new vector(); - - if ( cipher_suites16 ) - std::copy(cipher_suites16->begin(), cipher_suites16->end(), std::back_inserter(*ciphers)); - else - std::transform(cipher_suites24->begin(), cipher_suites24->end(), std::back_inserter(*ciphers), to_int()); - - BifEvent::generate_ssl_server_hello(bro_analyzer(), - bro_analyzer()->Conn(), - version, ts, new StringVal(server_random.length(), - (const char*) server_random.data()), - to_string_val(session_id), - ciphers->size()==0 ? 0 : ciphers->at(0), comp_method); - - delete ciphers; - } - - return true; - %} - - function proc_session_ticket_handshake(rec: SessionTicketHandshake, is_orig: bool): bool - %{ - if ( ssl_session_ticket_handshake ) - { - BifEvent::generate_ssl_session_ticket_handshake(bro_analyzer(), - bro_analyzer()->Conn(), - ${rec.ticket_lifetime_hint}, - new StringVal(${rec.data}.length(), (const char*) ${rec.data}.data())); - } - return true; - %} - - function proc_ssl_extension(rec: SSLRecord, type: int, sourcedata: const_bytestring) : bool - %{ - // We cheat a little bit here. We want to throw this event - // for every extension we encounter, even those that are - // handled by more specialized events later. To access the - // parsed data, we use sourcedata, which contains the whole - // data blob of the extension, including headers. We skip - // over those (4 bytes). - size_t length = sourcedata.length(); - if ( length < 4 ) - { - // This should be impossible due to the binpac parser - // and protocol description - bro_analyzer()->ProtocolViolation(fmt("Impossible extension length: %zu", length)); - bro_analyzer()->SetSkip(true); - return true; - } - - length -= 4; - const unsigned char* data = sourcedata.begin() + 4; - - if ( ssl_extension ) - BifEvent::generate_ssl_extension(bro_analyzer(), - bro_analyzer()->Conn(), ${rec.is_orig}, type, - new StringVal(length, reinterpret_cast(data))); - return true; - %} - - function proc_ec_point_formats(rec: SSLRecord, point_format_list: uint8[]) : bool - %{ - VectorVal* points = new VectorVal(internal_type("index_vec")->AsVectorType()); - - if ( point_format_list ) - { - for ( unsigned int i = 0; i < point_format_list->size(); ++i ) - points->Assign(i, new Val((*point_format_list)[i], TYPE_COUNT)); - } - - BifEvent::generate_ssl_extension_ec_point_formats(bro_analyzer(), bro_analyzer()->Conn(), - ${rec.is_orig}, points); - - return true; - %} - - function proc_elliptic_curves(rec: SSLRecord, list: uint16[]) : bool - %{ - VectorVal* curves = new VectorVal(internal_type("index_vec")->AsVectorType()); - - if ( list ) - { - for ( unsigned int i = 0; i < list->size(); ++i ) - curves->Assign(i, new Val((*list)[i], TYPE_COUNT)); - } - - BifEvent::generate_ssl_extension_elliptic_curves(bro_analyzer(), bro_analyzer()->Conn(), - ${rec.is_orig}, curves); - - return true; - %} - - function proc_apnl(rec: SSLRecord, protocols: ProtocolName[]) : bool - %{ - VectorVal* plist = new VectorVal(internal_type("string_vec")->AsVectorType()); - - if ( protocols ) - { - for ( unsigned int i = 0; i < protocols->size(); ++i ) - plist->Assign(i, new StringVal((*protocols)[i]->name().length(), (const char*) (*protocols)[i]->name().data())); - } - - BifEvent::generate_ssl_extension_application_layer_protocol_negotiation(bro_analyzer(), bro_analyzer()->Conn(), - ${rec.is_orig}, plist); - - return true; - %} - - function proc_server_name(rec: SSLRecord, list: ServerName[]) : bool - %{ - VectorVal* servers = new VectorVal(internal_type("string_vec")->AsVectorType()); - - if ( list ) - { - for ( unsigned int i = 0, j = 0; i < list->size(); ++i ) - { - ServerName* servername = (*list)[i]; - if ( servername->name_type() != 0 ) - { - bro_analyzer()->Weird(fmt("Encountered unknown type in server name ssl extension: %d", servername->name_type())); - continue; - } - - if ( servername->host_name() ) - servers->Assign(j++, new StringVal(servername->host_name()->host_name().length(), (const char*) servername->host_name()->host_name().data())); - else - bro_analyzer()->Weird("Empty server_name extension in ssl connection"); - } - } - - BifEvent::generate_ssl_extension_server_name(bro_analyzer(), bro_analyzer()->Conn(), - ${rec.is_orig}, servers); - - return true; - %} - - function proc_certificate(rec: SSLRecord, certificates : bytestring[]) : bool - %{ - if ( certificates->size() == 0 ) - return true; - - ODesc common; - common.AddRaw("Analyzer::ANALYZER_SSL"); - common.Add(bro_analyzer()->Conn()->StartTime()); - common.AddRaw(${rec.is_orig} ? "T" : "F", 1); - bro_analyzer()->Conn()->IDString(&common); - - for ( unsigned int i = 0; i < certificates->size(); ++i ) - { - const bytestring& cert = (*certificates)[i]; - - ODesc file_handle; - file_handle.Add(common.Description()); - file_handle.Add(i); - - string file_id = file_mgr->HashHandle(file_handle.Description()); - - file_mgr->DataIn(reinterpret_cast(cert.data()), - cert.length(), bro_analyzer()->GetAnalyzerTag(), - bro_analyzer()->Conn(), ${rec.is_orig}, file_id); - file_mgr->EndOfFile(file_id); - } - return true; - %} - - function proc_v2_certificate(rec: SSLRecord, cert : bytestring) : bool + function proc_v2_certificate(is_orig: bool, cert : bytestring) : bool %{ vector* cert_list = new vector(1,cert); - bool ret = proc_certificate(rec, cert_list); + bool ret = proc_certificate(is_orig, cert_list); delete cert_list; return ret; %} - function proc_v3_certificate(rec: SSLRecord, cl : X509Certificate[]) : bool - %{ - vector* certs = cl; - vector* cert_list = new vector(); - - std::transform(certs->begin(), certs->end(), - std::back_inserter(*cert_list), extract_certs()); - - bool ret = proc_certificate(rec, cert_list); - delete cert_list; - return ret; - %} function proc_v2_client_master_key(rec: SSLRecord, cipher_kind: int) : bool %{ @@ -356,209 +23,40 @@ refine connection SSL_Conn += { return true; %} - function proc_unknown_handshake(hs: Handshake, is_orig: bool) : bool + function proc_handshake(rec: SSLRecord, msg_type: uint8, length: uint24, data: bytestring, is_orig: bool) : bool %{ - bro_analyzer()->ProtocolViolation(fmt("unknown handshake message (%d) from %s", - ${hs.msg_type}, orig_label(is_orig).c_str())); + fprintf(stderr, "Forwarding to Handshake analyzer: msg_type: %u, length: %u\n", msg_type, to_int()(length)); + fprintf(stderr, "%u\n", data.end() - data.begin()); + bro_analyzer()->SendHandshake(msg_type, to_int()(length), data.begin(), data.end(), is_orig); return true; %} - - function proc_unknown_record(rec: SSLRecord) : bool - %{ - bro_analyzer()->ProtocolViolation(fmt("unknown SSL record type (%d) from %s", - ${rec.content_type}, - orig_label(${rec.is_orig}).c_str())); - return true; - %} - - function proc_ciphertext_record(rec : SSLRecord) : bool - %{ - if ( client_state_ == STATE_ENCRYPTED && - server_state_ == STATE_ENCRYPTED && - established_ == false ) - { - established_ = true; - BifEvent::generate_ssl_established(bro_analyzer(), - bro_analyzer()->Conn()); - } - - BifEvent::generate_ssl_encrypted_data(bro_analyzer(), - bro_analyzer()->Conn(), ${rec.is_orig}, ${rec.content_type}, ${rec.length}); - - return true; - %} - - function proc_heartbeat(rec : SSLRecord, type: uint8, payload_length: uint16, data: bytestring) : bool - %{ - BifEvent::generate_ssl_heartbeat(bro_analyzer(), - bro_analyzer()->Conn(), ${rec.is_orig}, ${rec.length}, type, payload_length, - new StringVal(data.length(), (const char*) data.data())); - return true; - %} - - function proc_check_v2_server_hello_version(version: uint16) : bool - %{ - if ( version != SSLv20 ) - { - bro_analyzer()->ProtocolViolation(fmt("Invalid version in SSL server hello. Version: %d", version)); - bro_analyzer()->SetSkip(true); - return false; - } - - return true; - %} - - function proc_certificate_status(rec : SSLRecord, status_type: uint8, response: bytestring) : bool - %{ - if ( status_type == 1 ) // ocsp - { - BifEvent::generate_ssl_stapled_ocsp(bro_analyzer(), - bro_analyzer()->Conn(), ${rec.is_orig}, - new StringVal(response.length(), - (const char*) response.data())); - } - - return true; - %} - - function proc_ec_server_key_exchange(rec: SSLRecord, curve_type: uint8, curve: uint16) : bool - %{ - if ( curve_type == NAMED_CURVE ) - BifEvent::generate_ssl_server_curve(bro_analyzer(), - bro_analyzer()->Conn(), curve); - - return true; - %} - - function proc_dh_server_key_exchange(rec: SSLRecord, p: bytestring, g: bytestring, Ys: bytestring) : bool - %{ - BifEvent::generate_ssl_dh_server_params(bro_analyzer(), - bro_analyzer()->Conn(), - new StringVal(p.length(), (const char*) p.data()), - new StringVal(g.length(), (const char*) g.data()), - new StringVal(Ys.length(), (const char*) Ys.data()) - ); - - return true; - %} - - function proc_ccs(rec: SSLRecord) : bool - %{ - BifEvent::generate_ssl_change_cipher_spec(bro_analyzer(), - bro_analyzer()->Conn(), ${rec.is_orig}); - - return true; - %} - - function proc_handshake(rec: SSLRecord, msg_type: uint8, length: uint24) : bool - %{ - BifEvent::generate_ssl_handshake_message(bro_analyzer(), - bro_analyzer()->Conn(), ${rec.is_orig}, msg_type, to_int()(length)); - - return true; - %} - }; -refine typeattr Alert += &let { - proc : bool = $context.connection.proc_alert(rec, level, description); -}; refine typeattr V2Error += &let { proc : bool = $context.connection.proc_alert(rec, -1, error_code); }; -refine typeattr Heartbeat += &let { - proc : bool = $context.connection.proc_heartbeat(rec, type, payload_length, data); -}; - -refine typeattr ClientHello += &let { - proc : bool = $context.connection.proc_client_hello(rec, client_version, - gmt_unix_time, random_bytes, - session_id, csuits, 0); -}; refine typeattr V2ClientHello += &let { - proc : bool = $context.connection.proc_client_hello(rec, client_version, 0, + proc : bool = $context.connection.proc_client_hello(client_version, 0, challenge, session_id, 0, ciphers); }; -refine typeattr ServerHello += &let { - proc : bool = $context.connection.proc_server_hello(rec, server_version, - gmt_unix_time, random_bytes, session_id, cipher_suite, 0, - compression_method); -}; - refine typeattr V2ServerHello += &let { check_v2 : bool = $context.connection.proc_check_v2_server_hello_version(server_version); - proc : bool = $context.connection.proc_server_hello(rec, server_version, 0, + proc : bool = $context.connection.proc_server_hello(server_version, 0, conn_id_data, 0, 0, ciphers, 0) &requires(check_v2) &if(check_v2 == true); - cert : bool = $context.connection.proc_v2_certificate(rec, cert_data) + cert : bool = $context.connection.proc_v2_certificate(rec.is_orig, cert_data) &requires(proc) &requires(check_v2) &if(check_v2 == true); }; -refine typeattr Certificate += &let { - proc : bool = $context.connection.proc_v3_certificate(rec, certificates); -}; - refine typeattr V2ClientMasterKey += &let { proc : bool = $context.connection.proc_v2_client_master_key(rec, cipher_kind); }; -refine typeattr UnknownHandshake += &let { - proc : bool = $context.connection.proc_unknown_handshake(hs, is_orig); -}; - -refine typeattr SessionTicketHandshake += &let { - proc : bool = $context.connection.proc_session_ticket_handshake(this, rec.is_orig); -} - -refine typeattr UnknownRecord += &let { - proc : bool = $context.connection.proc_unknown_record(rec); -}; - -refine typeattr CiphertextRecord += &let { - proc : bool = $context.connection.proc_ciphertext_record(rec); -} - -refine typeattr SSLExtension += &let { - proc : bool = $context.connection.proc_ssl_extension(rec, type, sourcedata); -}; - -refine typeattr EcPointFormats += &let { - proc : bool = $context.connection.proc_ec_point_formats(rec, point_format_list); -}; - -refine typeattr EllipticCurves += &let { - proc : bool = $context.connection.proc_elliptic_curves(rec, elliptic_curve_list); -}; - -refine typeattr ApplicationLayerProtocolNegotiationExtension += &let { - proc : bool = $context.connection.proc_apnl(rec, protocol_name_list); -}; - -refine typeattr ServerNameExt += &let { - proc : bool = $context.connection.proc_server_name(rec, server_names); -}; - -refine typeattr CertificateStatus += &let { - proc : bool = $context.connection.proc_certificate_status(rec, status_type, response); -}; - -refine typeattr EcServerKeyExchange += &let { - proc : bool = $context.connection.proc_ec_server_key_exchange(rec, curve_type, curve); -}; - -refine typeattr DhServerKeyExchange += &let { - proc : bool = $context.connection.proc_dh_server_key_exchange(rec, dh_p, dh_g, dh_Ys); -}; - -refine typeattr ChangeCipherSpec += &let { - proc : bool = $context.connection.proc_ccs(rec); -}; - refine typeattr Handshake += &let { - proc : bool = $context.connection.proc_handshake(rec, msg_type, length); + proc : bool = $context.connection.proc_handshake(rec, msg_type, length, data, rec.is_orig); }; diff --git a/src/analyzer/protocol/ssl/ssl-defs.pac b/src/analyzer/protocol/ssl/ssl-defs.pac index 29eb1d1fb9..c29bbcbabe 100644 --- a/src/analyzer/protocol/ssl/ssl-defs.pac +++ b/src/analyzer/protocol/ssl/ssl-defs.pac @@ -1,5 +1,84 @@ # Some common definitions for the SSL and SSL record-layer analyzers. +type uint24 = record { + byte1 : uint8; + byte2 : uint8; + byte3 : uint8; +}; + +type uint48 = record { + byte1 : uint8; + byte2 : uint8; + byte3 : uint8; + byte4 : uint8; + byte5 : uint8; + byte6 : uint8; +}; + + +%header{ + string orig_label(bool is_orig); + %} + + +%code{ +string orig_label(bool is_orig) + { + return string(is_orig ? "originator" :"responder"); + } +%} + +%header{ + class to_int { + public: + int operator()(uint24 * num) const + { + return (num->byte1() << 16) | (num->byte2() << 8) | num->byte3(); + } + + uint64 operator()(uint48 * num) const + { + return ((uint64)num->byte1() << 40) | ((uint64)num->byte2() << 32) | ((uint64)num->byte3() << 24) | + ((uint64)num->byte4() << 16) | ((uint64)num->byte5() << 8) | (uint64)num->byte6(); + } + }; + + string state_label(int state_nr); +%} + +extern type to_int; + +function to_string_val(data : uint8[]) : StringVal + %{ + char tmp[32]; + memset(tmp, 0, sizeof(tmp)); + + // Just return an empty string if the string is longer than 32 bytes + if ( data && data->size() <= 32 ) + { + for ( unsigned int i = data->size(); i > 0; --i ) + tmp[i-1] = (*data)[i-1]; + } + + return new StringVal(32, tmp); + %} + +function version_ok(vers : uint16) : bool + %{ + switch ( vers ) { + case SSLv20: + case SSLv30: + case TLSv10: + case TLSv11: + case TLSv12: + return true; + + default: + return false; + } + %} + + %extern{ #include using std::string; diff --git a/src/analyzer/protocol/ssl/ssl-dtls-analyzer.pac b/src/analyzer/protocol/ssl/ssl-dtls-analyzer.pac new file mode 100644 index 0000000000..0e8418644e --- /dev/null +++ b/src/analyzer/protocol/ssl/ssl-dtls-analyzer.pac @@ -0,0 +1,106 @@ + +%extern{ +#include +#include +#include +#include + +#include "util.h" + +#include "file_analysis/Manager.h" +%} + +refine connection SSL_Conn += { + + %member{ + int established_; + %} + + %init{ + established_ = false; + %} + + %cleanup{ + %} + + function proc_alert(rec: SSLRecord, level : int, desc : int) : bool + %{ + BifEvent::generate_ssl_alert(bro_analyzer(), bro_analyzer()->Conn(), + ${rec.is_orig}, level, desc); + return true; + %} + function proc_unknown_record(rec: SSLRecord) : bool + %{ + bro_analyzer()->ProtocolViolation(fmt("unknown SSL record type (%d) from %s", + ${rec.content_type}, + orig_label(${rec.is_orig}).c_str())); + return true; + %} + + function proc_ciphertext_record(rec : SSLRecord) : bool + %{ + if ( client_state_ == STATE_ENCRYPTED && + server_state_ == STATE_ENCRYPTED && + established_ == false ) + { + established_ = true; + BifEvent::generate_ssl_established(bro_analyzer(), + bro_analyzer()->Conn()); + } + + BifEvent::generate_ssl_encrypted_data(bro_analyzer(), + bro_analyzer()->Conn(), ${rec.is_orig}, ${rec.content_type}, ${rec.length}); + + return true; + %} + + function proc_heartbeat(rec : SSLRecord, type: uint8, payload_length: uint16, data: bytestring) : bool + %{ + BifEvent::generate_ssl_heartbeat(bro_analyzer(), + bro_analyzer()->Conn(), ${rec.is_orig}, ${rec.length}, type, payload_length, + new StringVal(data.length(), (const char*) data.data())); + return true; + %} + + function proc_check_v2_server_hello_version(version: uint16) : bool + %{ + if ( version != SSLv20 ) + { + bro_analyzer()->ProtocolViolation(fmt("Invalid version in SSL server hello. Version: %d", version)); + bro_analyzer()->SetSkip(true); + return false; + } + + return true; + %} + + + function proc_ccs(rec: SSLRecord) : bool + %{ + BifEvent::generate_ssl_change_cipher_spec(bro_analyzer(), + bro_analyzer()->Conn(), ${rec.is_orig}); + + return true; + %} + +}; + +refine typeattr Alert += &let { + proc : bool = $context.connection.proc_alert(rec, level, description); +}; + +refine typeattr Heartbeat += &let { + proc : bool = $context.connection.proc_heartbeat(rec, type, payload_length, data); +}; + +refine typeattr UnknownRecord += &let { + proc : bool = $context.connection.proc_unknown_record(rec); +}; + +refine typeattr CiphertextRecord += &let { + proc : bool = $context.connection.proc_ciphertext_record(rec); +} + +refine typeattr ChangeCipherSpec += &let { + proc : bool = $context.connection.proc_ccs(rec); +}; diff --git a/src/analyzer/protocol/ssl/ssl-dtls-protocol.pac b/src/analyzer/protocol/ssl/ssl-dtls-protocol.pac new file mode 100644 index 0000000000..c3277d150e --- /dev/null +++ b/src/analyzer/protocol/ssl/ssl-dtls-protocol.pac @@ -0,0 +1,134 @@ + +###################################################################### +# General definitions +###################################################################### + +type PlaintextRecord(rec: SSLRecord) = case rec.content_type of { + CHANGE_CIPHER_SPEC -> ch_cipher : ChangeCipherSpec(rec); + ALERT -> alert : Alert(rec); + HEARTBEAT -> heartbeat: Heartbeat(rec); + APPLICATION_DATA -> app_data : ApplicationData(rec); + default -> unknown_record : UnknownRecord(rec); +}; + + +###################################################################### +# Encryption Tracking +###################################################################### + +enum AnalyzerState { + STATE_CLEAR, + STATE_ENCRYPTED +}; + +%code{ + string state_label(int state_nr) + { + switch ( state_nr ) { + case STATE_CLEAR: + return string("CLEAR"); + + case STATE_ENCRYPTED: + return string("ENCRYPTED"); + + default: + return string(fmt("UNKNOWN (%d)", state_nr)); + } + } +%} + +###################################################################### +# Change Cipher Spec Protocol (7.1.) +###################################################################### + +type ChangeCipherSpec(rec: SSLRecord) = record { + type : uint8; +} &length = 1, &let { + state_changed : bool = + $context.connection.startEncryption(rec.is_orig); +}; + + +###################################################################### +# Alert Protocol (7.2.) +###################################################################### + +type Alert(rec: SSLRecord) = record { + level : uint8; + description: uint8; +}; + + +###################################################################### +# V3 Application Data +###################################################################### + +# Application data should always be encrypted, so we should not +# reach this point. +type ApplicationData(rec: SSLRecord) = record { + data : bytestring &restofdata &transient; +}; + +###################################################################### +# V3 Heartbeat +###################################################################### + +type Heartbeat(rec: SSLRecord) = record { + type : uint8; + payload_length : uint16; + data : bytestring &restofdata; +}; + + + +###################################################################### +# Fragmentation (6.2.1.) +###################################################################### + +type UnknownRecord(rec: SSLRecord) = record { + cont : bytestring &restofdata &transient; +}; + +type CiphertextRecord(rec: SSLRecord) = record { + cont : bytestring &restofdata &transient; +}; + +###################################################################### +# binpac analyzer for SSL including +###################################################################### + +refine connection SSL_Conn += { + + %member{ + int client_state_; + int server_state_; + int record_layer_version_; + %} + + %init{ + server_state_ = STATE_CLEAR; + client_state_ = STATE_CLEAR; + record_layer_version_ = UNKNOWN_VERSION; + %} + + function client_state() : int %{ return client_state_; %} + + function server_state() : int %{ return client_state_; %} + + function state(is_orig: bool) : int + %{ + if ( is_orig ) + return client_state_; + else + return server_state_; + %} + + function startEncryption(is_orig: bool) : bool + %{ + if ( is_orig ) + client_state_ = STATE_ENCRYPTED; + else + server_state_ = STATE_ENCRYPTED; + return true; + %} +}; diff --git a/src/analyzer/protocol/ssl/ssl-protocol.pac b/src/analyzer/protocol/ssl/ssl-protocol.pac index cb794bd8a4..d5628e9cc7 100644 --- a/src/analyzer/protocol/ssl/ssl-protocol.pac +++ b/src/analyzer/protocol/ssl/ssl-protocol.pac @@ -2,30 +2,6 @@ # To be used in conjunction with an SSL record-layer analyzer. # Separation is necessary due to possible fragmentation of SSL records. -###################################################################### -# General definitions -###################################################################### - -type uint24 = record { - byte1 : uint8; - byte2 : uint8; - byte3 : uint8; -}; - -%header{ - class to_int { - public: - int operator()(uint24 * num) const - { - return (num->byte1() << 16) | (num->byte2() << 8) | num->byte3(); - } - }; - - string state_label(int state_nr); -%} - -extern type to_int; - type SSLRecord(is_orig: bool) = record { head0 : uint8; head1 : uint8; @@ -58,161 +34,20 @@ type RecordText(rec: SSLRecord) = case $context.connection.state(rec.is_orig) of -> plaintext : PlaintextRecord(rec); }; -type PlaintextRecord(rec: SSLRecord) = case rec.content_type of { - CHANGE_CIPHER_SPEC -> ch_cipher : ChangeCipherSpec(rec); - ALERT -> alert : Alert(rec); +refine casetype PlaintextRecord += { HANDSHAKE -> handshake : Handshake(rec); - HEARTBEAT -> heartbeat: Heartbeat(rec); - APPLICATION_DATA -> app_data : ApplicationData(rec); V2_ERROR -> v2_error : V2Error(rec); V2_CLIENT_HELLO -> v2_client_hello : V2ClientHello(rec); V2_CLIENT_MASTER_KEY -> v2_client_master_key : V2ClientMasterKey(rec); V2_SERVER_HELLO -> v2_server_hello : V2ServerHello(rec); - default -> unknown_record : UnknownRecord(rec); }; -###################################################################### -# TLS Extensions -###################################################################### - -type SSLExtension(rec: SSLRecord) = record { - type: uint16; - data_len: uint16; - - # Pretty code ahead. Deal with the fact that perhaps extensions are - # not really present and we do not want to fail because of that. - ext: case type of { - EXT_APPLICATION_LAYER_PROTOCOL_NEGOTIATION -> apnl: ApplicationLayerProtocolNegotiationExtension(rec)[] &until($element == 0 || $element != 0); - EXT_ELLIPTIC_CURVES -> elliptic_curves: EllipticCurves(rec)[] &until($element == 0 || $element != 0); - EXT_EC_POINT_FORMATS -> ec_point_formats: EcPointFormats(rec)[] &until($element == 0 || $element != 0); -# EXT_STATUS_REQUEST -> status_request: StatusRequest(rec)[] &until($element == 0 || $element != 0); - EXT_SERVER_NAME -> server_name: ServerNameExt(rec)[] &until($element == 0 || $element != 0); - default -> data: bytestring &restofdata; - }; -} &length=data_len+4 &exportsourcedata; - -type ServerNameHostName() = record { - length: uint16; - host_name: bytestring &length=length; +type Handshake(rec: SSLRecord) = record { + msg_type: uint8; + length: uint24; + data: bytestring &length=to_int()(length); }; -type ServerName() = record { - name_type: uint8; # has to be 0 for host-name - name: case name_type of { - 0 -> host_name: ServerNameHostName; - default -> data : bytestring &restofdata &transient; # unknown name - }; -}; - -type ServerNameExt(rec: SSLRecord) = record { - length: uint16; - server_names: ServerName[] &until($input.length() == 0); -} &length=length+2; - -# Do not parse for now. Structure is correct, but only contains asn.1 data that we would not use further. -#type OcspStatusRequest(rec: SSLRecord) = record { -# responder_id_list_length: uint16; -# responder_id_list: bytestring &length=responder_id_list_length; -# request_extensions_length: uint16; -# request_extensions: bytestring &length=request_extensions_length; -#}; -# -#type StatusRequest(rec: SSLRecord) = record { -# status_type: uint8; # 1 -> ocsp -# req: case status_type of { -# 1 -> ocsp_status_request: OcspStatusRequest(rec); -# default -> data : bytestring &restofdata &transient; # unknown -# }; -#}; - -type EcPointFormats(rec: SSLRecord) = record { - length: uint8; - point_format_list: uint8[length]; -}; - -type EllipticCurves(rec: SSLRecord) = record { - length: uint16; - elliptic_curve_list: uint16[length/2]; -}; - -type ProtocolName() = record { - length: uint8; - name: bytestring &length=length; -}; - -type ApplicationLayerProtocolNegotiationExtension(rec: SSLRecord) = record { - length: uint16; - protocol_name_list: ProtocolName[] &until($input.length() == 0); -} &length=length+2; - -###################################################################### -# Encryption Tracking -###################################################################### - -enum AnalyzerState { - STATE_CLEAR, - STATE_ENCRYPTED -}; - -%code{ - string state_label(int state_nr) - { - switch ( state_nr ) { - case STATE_CLEAR: - return string("CLEAR"); - - case STATE_ENCRYPTED: - return string("ENCRYPTED"); - - default: - return string(fmt("UNKNOWN (%d)", state_nr)); - } - } -%} - -###################################################################### -# SSLv3 Handshake Protocols (7.) -###################################################################### - -enum HandshakeType { - HELLO_REQUEST = 0, - CLIENT_HELLO = 1, - SERVER_HELLO = 2, - SESSION_TICKET = 4, # RFC 5077 - CERTIFICATE = 11, - SERVER_KEY_EXCHANGE = 12, - CERTIFICATE_REQUEST = 13, - SERVER_HELLO_DONE = 14, - CERTIFICATE_VERIFY = 15, - CLIENT_KEY_EXCHANGE = 16, - FINISHED = 20, - CERTIFICATE_URL = 21, # RFC 3546 - CERTIFICATE_STATUS = 22, # RFC 3546 -}; - - -###################################################################### -# V3 Change Cipher Spec Protocol (7.1.) -###################################################################### - -type ChangeCipherSpec(rec: SSLRecord) = record { - type : uint8; -} &length = 1, &let { - state_changed : bool = - $context.connection.startEncryption(rec.is_orig); -}; - - -###################################################################### -# V3 Alert Protocol (7.2.) -###################################################################### - -type Alert(rec: SSLRecord) = record { - level : uint8; - description: uint8; -}; - - ###################################################################### # V2 Error Records (SSLv2 2.7.) ###################################################################### @@ -224,53 +59,6 @@ type V2Error(rec: SSLRecord) = record { }; -###################################################################### -# V3 Application Data -###################################################################### - -# Application data should always be encrypted, so we should not -# reach this point. -type ApplicationData(rec: SSLRecord) = record { - data : bytestring &restofdata &transient; -}; - -###################################################################### -# V3 Heartbeat -###################################################################### - -type Heartbeat(rec: SSLRecord) = record { - type : uint8; - payload_length : uint16; - data : bytestring &restofdata; -}; - -###################################################################### -# V3 Hello Request (7.4.1.1.) -###################################################################### - -# Hello Request is empty -type HelloRequest(rec: SSLRecord) = empty; - - -###################################################################### -# V3 Client Hello (7.4.1.2.) -###################################################################### - -type ClientHello(rec: SSLRecord) = record { - client_version : uint16; - gmt_unix_time : uint32; - random_bytes : bytestring &length = 28; - session_len : uint8; - session_id : uint8[session_len]; - csuit_len : uint16 &check(csuit_len > 1 && csuit_len % 2 == 0); - csuits : uint16[csuit_len/2]; - cmeth_len : uint8 &check(cmeth_len > 0); - cmeths : uint8[cmeth_len]; - # This weirdness is to deal with the possible existence or absence - # of the following fields. - ext_len: uint16[] &until($element == 0 || $element != 0); - extensions : SSLExtension(rec)[] &until($input.length() == 0); -}; ###################################################################### # V2 Client Hello (SSLv2 2.5.) @@ -288,26 +76,6 @@ type V2ClientHello(rec: SSLRecord) = record { }; -###################################################################### -# V3 Server Hello (7.4.1.3.) -###################################################################### - -type ServerHello(rec: SSLRecord) = record { - server_version : uint16; - gmt_unix_time : uint32; - random_bytes : bytestring &length = 28; - session_len : uint8; - session_id : uint8[session_len]; - cipher_suite : uint16[1]; - compression_method : uint8; - # This weirdness is to deal with the possible existence or absence - # of the following fields. - ext_len: uint16[] &until($element == 0 || $element != 0); - extensions : SSLExtension(rec)[] &until($input.length() == 0); -} &let { - cipher_set : bool = - $context.connection.set_cipher(cipher_suite[0]); -}; ###################################################################### # V2 Server Hello (SSLv2 2.6.) @@ -329,298 +97,6 @@ type V2ServerHello(rec: SSLRecord) = record { }; -###################################################################### -# V3 Server Certificate (7.4.2.) -###################################################################### - -type X509Certificate = record { - length : uint24; - certificate : bytestring &length = to_int()(length); -}; - -type Certificate(rec: SSLRecord) = record { - length : uint24; - certificates : X509Certificate[] &until($input.length() == 0); -} &length = to_int()(length)+3; - -# OCSP Stapling - -type CertificateStatus(rec: SSLRecord) = record { - status_type: uint8; # 1 = ocsp, everything else is undefined - length : uint24; - response: bytestring &restofdata; -}; - -###################################################################### -# V3 Server Key Exchange Message (7.4.3.) -###################################################################### - -# Usually, the server key exchange does not contain any information -# that we are interested in. -# -# The exception is when we are using an ECDHE, DHE or DH-Anon suite. -# In this case, we can extract information about the chosen cipher from -# here. -type ServerKeyExchange(rec: SSLRecord) = case $context.connection.chosen_cipher() of { - TLS_ECDH_ECDSA_WITH_NULL_SHA, - TLS_ECDH_ECDSA_WITH_RC4_128_SHA, - TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA, - TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA, - TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA, - TLS_ECDHE_ECDSA_WITH_NULL_SHA, - TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, - TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA, - TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, - TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, - TLS_ECDH_RSA_WITH_NULL_SHA, - TLS_ECDH_RSA_WITH_RC4_128_SHA, - TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA, - TLS_ECDH_RSA_WITH_AES_128_CBC_SHA, - TLS_ECDH_RSA_WITH_AES_256_CBC_SHA, - TLS_ECDHE_RSA_WITH_NULL_SHA, - TLS_ECDHE_RSA_WITH_RC4_128_SHA, - TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, - TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, - TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, - TLS_ECDH_ANON_WITH_NULL_SHA, - TLS_ECDH_ANON_WITH_RC4_128_SHA, - TLS_ECDH_ANON_WITH_3DES_EDE_CBC_SHA, - TLS_ECDH_ANON_WITH_AES_128_CBC_SHA, - TLS_ECDH_ANON_WITH_AES_256_CBC_SHA, - TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, - TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384, - TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256, - TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384, - TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, - TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384, - TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256, - TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384, - TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, - TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, - TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256, - TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384, - TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, - TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, - TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256, - TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384, - TLS_ECDHE_PSK_WITH_RC4_128_SHA, - TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA, - TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA, - TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA, - TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256, - TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384, - TLS_ECDHE_PSK_WITH_NULL_SHA, - TLS_ECDHE_PSK_WITH_NULL_SHA256, - TLS_ECDHE_PSK_WITH_NULL_SHA384, - TLS_ECDHE_ECDSA_WITH_ARIA_128_CBC_SHA256, - TLS_ECDHE_ECDSA_WITH_ARIA_256_CBC_SHA384, - TLS_ECDH_ECDSA_WITH_ARIA_128_CBC_SHA256, - TLS_ECDH_ECDSA_WITH_ARIA_256_CBC_SHA384, - TLS_ECDHE_RSA_WITH_ARIA_128_CBC_SHA256, - TLS_ECDHE_RSA_WITH_ARIA_256_CBC_SHA384, - TLS_ECDH_RSA_WITH_ARIA_128_CBC_SHA256, - TLS_ECDH_RSA_WITH_ARIA_256_CBC_SHA384, - TLS_ECDHE_ECDSA_WITH_ARIA_128_GCM_SHA256, - TLS_ECDHE_ECDSA_WITH_ARIA_256_GCM_SHA384, - TLS_ECDH_ECDSA_WITH_ARIA_128_GCM_SHA256, - TLS_ECDH_ECDSA_WITH_ARIA_256_GCM_SHA384, - TLS_ECDHE_RSA_WITH_ARIA_128_GCM_SHA256, - TLS_ECDHE_RSA_WITH_ARIA_256_GCM_SHA384, - TLS_ECDH_RSA_WITH_ARIA_128_GCM_SHA256, - TLS_ECDH_RSA_WITH_ARIA_256_GCM_SHA384, - TLS_ECDHE_PSK_WITH_ARIA_128_CBC_SHA256, - TLS_ECDHE_PSK_WITH_ARIA_256_CBC_SHA384, - TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256, - TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384, - TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256, - TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384, - TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256, - TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384, - TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256, - TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384, - TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256, - TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384, - TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256, - TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384, - TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256, - TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384, - TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256, - TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384, - TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256, - TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384, - TLS_ECDHE_ECDSA_WITH_AES_128_CCM, - TLS_ECDHE_ECDSA_WITH_AES_256_CCM, - TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8, - TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8, - TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, - TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 - -> ec_server_key_exchange : EcServerKeyExchange(rec); - - # DHE suites - TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA, - TLS_DHE_DSS_WITH_DES_CBC_SHA, - TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA, - TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA, - TLS_DHE_RSA_WITH_DES_CBC_SHA, - TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA, - TLS_DHE_DSS_WITH_AES_128_CBC_SHA, - TLS_DHE_RSA_WITH_AES_128_CBC_SHA, - TLS_DHE_DSS_WITH_AES_256_CBC_SHA, - TLS_DHE_RSA_WITH_AES_256_CBC_SHA, - TLS_DHE_DSS_WITH_AES_128_CBC_SHA256, - TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA, - TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA, - TLS_DHE_DSS_EXPORT1024_WITH_DES_CBC_SHA, - TLS_DHE_DSS_EXPORT1024_WITH_RC4_56_SHA, - TLS_DHE_DSS_WITH_RC4_128_SHA, - TLS_DHE_RSA_WITH_AES_128_CBC_SHA256, - TLS_DHE_DSS_WITH_AES_256_CBC_SHA256, - TLS_DHE_RSA_WITH_AES_256_CBC_SHA256, - TLS_DHE_DSS_WITH_3DES_EDE_CBC_RMD, - TLS_DHE_DSS_WITH_AES_128_CBC_RMD, - TLS_DHE_DSS_WITH_AES_256_CBC_RMD, - TLS_DHE_RSA_WITH_3DES_EDE_CBC_RMD, - TLS_DHE_RSA_WITH_AES_128_CBC_RMD, - TLS_DHE_RSA_WITH_AES_256_CBC_RMD, - TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA, - TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA, - TLS_DHE_PSK_WITH_RC4_128_SHA, - TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA, - TLS_DHE_PSK_WITH_AES_128_CBC_SHA, - TLS_DHE_PSK_WITH_AES_256_CBC_SHA, - TLS_DHE_DSS_WITH_SEED_CBC_SHA, - TLS_DHE_RSA_WITH_SEED_CBC_SHA, - TLS_DHE_RSA_WITH_AES_128_GCM_SHA256, - TLS_DHE_RSA_WITH_AES_256_GCM_SHA384, - TLS_DHE_DSS_WITH_AES_128_GCM_SHA256, - TLS_DHE_DSS_WITH_AES_256_GCM_SHA384, - TLS_DHE_PSK_WITH_AES_128_GCM_SHA256, - TLS_DHE_PSK_WITH_AES_256_GCM_SHA384, - TLS_DHE_PSK_WITH_AES_128_CBC_SHA256, - TLS_DHE_PSK_WITH_AES_256_CBC_SHA384, - TLS_DHE_PSK_WITH_NULL_SHA256, - TLS_DHE_PSK_WITH_NULL_SHA384, - TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256, - TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256, - TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256, - TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256, - TLS_DHE_DSS_WITH_ARIA_128_CBC_SHA256, - TLS_DHE_DSS_WITH_ARIA_256_CBC_SHA384, - TLS_DHE_RSA_WITH_ARIA_128_CBC_SHA256, - TLS_DHE_RSA_WITH_ARIA_256_CBC_SHA384, - TLS_DHE_RSA_WITH_ARIA_128_GCM_SHA256, - TLS_DHE_RSA_WITH_ARIA_256_GCM_SHA384, - TLS_DHE_DSS_WITH_ARIA_128_GCM_SHA256, - TLS_DHE_DSS_WITH_ARIA_256_GCM_SHA384, - TLS_DHE_PSK_WITH_ARIA_128_CBC_SHA256, - TLS_DHE_PSK_WITH_ARIA_256_CBC_SHA384, - TLS_DHE_PSK_WITH_ARIA_128_GCM_SHA256, - TLS_DHE_PSK_WITH_ARIA_256_GCM_SHA384, - TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256, - TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384, - TLS_DHE_DSS_WITH_CAMELLIA_128_GCM_SHA256, - TLS_DHE_DSS_WITH_CAMELLIA_256_GCM_SHA384, - TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256, - TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384, - TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256, - TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384, - TLS_DHE_RSA_WITH_AES_128_CCM, - TLS_DHE_RSA_WITH_AES_256_CCM, - TLS_DHE_RSA_WITH_AES_128_CCM_8, - TLS_DHE_RSA_WITH_AES_256_CCM_8, - TLS_DHE_PSK_WITH_AES_128_CCM, - TLS_DHE_PSK_WITH_AES_256_CCM, - TLS_PSK_DHE_WITH_AES_128_CCM_8, - TLS_PSK_DHE_WITH_AES_256_CCM_8, - TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256, - # DH-anon suites - TLS_DH_ANON_EXPORT_WITH_RC4_40_MD5, - TLS_DH_ANON_WITH_RC4_128_MD5, - TLS_DH_ANON_EXPORT_WITH_DES40_CBC_SHA, - TLS_DH_ANON_WITH_DES_CBC_SHA, - TLS_DH_ANON_WITH_3DES_EDE_CBC_SHA, - TLS_DH_ANON_WITH_AES_128_CBC_SHA, - TLS_DH_ANON_WITH_AES_256_CBC_SHA, - TLS_DH_ANON_WITH_CAMELLIA_128_CBC_SHA, - TLS_DH_ANON_WITH_AES_128_CBC_SHA256, - TLS_DH_ANON_WITH_AES_256_CBC_SHA256, - TLS_DH_ANON_WITH_CAMELLIA_256_CBC_SHA, - TLS_DH_ANON_WITH_SEED_CBC_SHA, - TLS_DH_ANON_WITH_AES_128_GCM_SHA256, - TLS_DH_ANON_WITH_AES_256_GCM_SHA384, - TLS_DH_ANON_WITH_CAMELLIA_128_CBC_SHA256, - TLS_DH_ANON_WITH_CAMELLIA_256_CBC_SHA256, - TLS_DH_ANON_WITH_ARIA_128_CBC_SHA256, - TLS_DH_ANON_WITH_ARIA_256_CBC_SHA384, - TLS_DH_ANON_WITH_ARIA_128_GCM_SHA256, - TLS_DH_ANON_WITH_ARIA_256_GCM_SHA384, - TLS_DH_ANON_WITH_CAMELLIA_128_GCM_SHA256, - TLS_DH_ANON_WITH_CAMELLIA_256_GCM_SHA384 - # DH non-anon suites do not send a ServerKeyExchange - -> dh_server_key_exchange : DhServerKeyExchange(rec); - - default - -> key : bytestring &restofdata &transient; -}; - -# For the moment, we really only are interested in the curve name. If it -# is not set (if the server sends explicit parameters), we do not bother. -# We also do not parse the actual signature data following the named curve. -type EcServerKeyExchange(rec: SSLRecord) = record { - curve_type: uint8; - curve: uint16; # only if curve_type = 3 (NAMED_CURVE) - data: bytestring &restofdata &transient; -}; - -# For both, dh_anon and dhe the ServerKeyExchange starts with a ServerDHParams -# structure. After that, they start to differ, but we do not care about that. -type DhServerKeyExchange(rec: SSLRecord) = record { - dh_p_length: uint16; - dh_p: bytestring &length=dh_p_length; - dh_g_length: uint16; - dh_g: bytestring &length=dh_g_length; - dh_Ys_length: uint16; - dh_Ys: bytestring &length=dh_Ys_length; - data: bytestring &restofdata &transient; -}; - - -###################################################################### -# V3 Certificate Request (7.4.4.) -###################################################################### - -# For now, ignore Certificate Request Details; just eat up message. -type CertificateRequest(rec: SSLRecord) = record { - cont : bytestring &restofdata &transient; -}; - - -###################################################################### -# V3 Server Hello Done (7.4.5.) -###################################################################### - -# Server Hello Done is empty -type ServerHelloDone(rec: SSLRecord) = empty; - - -###################################################################### -# V3 Client Certificate (7.4.6.) -###################################################################### - -# Client Certificate is identical to Server Certificate; -# no further definition here - - -###################################################################### -# V3 Client Key Exchange Message (7.4.7.) -###################################################################### - -# For now ignore details of ClientKeyExchange (most of it is -# encrypted anyway); just eat up message. -type ClientKeyExchange(rec: SSLRecord) = record { - key : bytestring &restofdata &transient; -}; - ###################################################################### # V2 Client Master Key (SSLv2 2.5.) ###################################################################### @@ -641,75 +117,6 @@ type V2ClientMasterKey(rec: SSLRecord) = record { }; -###################################################################### -# V3 Certificate Verify (7.4.8.) -###################################################################### - -# For now, ignore Certificate Verify; just eat up the message. -type CertificateVerify(rec: SSLRecord) = record { - cont : bytestring &restofdata &transient; -}; - - -###################################################################### -# V3 Finished (7.4.9.) -###################################################################### - -# The finished messages are always sent after encryption is in effect, -# so we will not be able to read those messages. -type Finished(rec: SSLRecord) = record { - cont : bytestring &restofdata &transient; -}; - -type SessionTicketHandshake(rec: SSLRecord) = record { - ticket_lifetime_hint: uint32; - data: bytestring &restofdata; -}; - -###################################################################### -# V3 Handshake Protocol (7.) -###################################################################### - -type UnknownHandshake(hs: Handshake, is_orig: bool) = record { - data : bytestring &restofdata &transient; -}; - -type Handshake(rec: SSLRecord) = record { - msg_type : uint8; - length : uint24; - - body : case msg_type of { - HELLO_REQUEST -> hello_request : HelloRequest(rec); - CLIENT_HELLO -> client_hello : ClientHello(rec); - SERVER_HELLO -> server_hello : ServerHello(rec); - SESSION_TICKET -> session_ticket : SessionTicketHandshake(rec); - CERTIFICATE -> certificate : Certificate(rec); - SERVER_KEY_EXCHANGE -> server_key_exchange : ServerKeyExchange(rec); - CERTIFICATE_REQUEST -> certificate_request : CertificateRequest(rec); - SERVER_HELLO_DONE -> server_hello_done : ServerHelloDone(rec); - CERTIFICATE_VERIFY -> certificate_verify : CertificateVerify(rec); - CLIENT_KEY_EXCHANGE -> client_key_exchange : ClientKeyExchange(rec); - FINISHED -> finished : Finished(rec); - CERTIFICATE_URL -> certificate_url : bytestring &restofdata &transient; - CERTIFICATE_STATUS -> certificate_status : CertificateStatus(rec); - default -> unknown_handshake : UnknownHandshake(this, rec.is_orig); - } &length = to_int()(length); -}; - - -###################################################################### -# Fragmentation (6.2.1.) -###################################################################### - -type UnknownRecord(rec: SSLRecord) = record { - cont : bytestring &restofdata &transient; -}; - -type CiphertextRecord(rec: SSLRecord) = record { - cont : bytestring &restofdata &transient; -}; - - ###################################################################### # initial datatype for binpac ###################################################################### @@ -725,28 +132,6 @@ type SSLPDU(is_orig: bool) = record { refine connection SSL_Conn += { - %member{ - int client_state_; - int server_state_; - int record_layer_version_; - uint32 chosen_cipher_; - %} - - %init{ - server_state_ = STATE_CLEAR; - client_state_ = STATE_CLEAR; - record_layer_version_ = UNKNOWN_VERSION; - chosen_cipher_ = NO_CHOSEN_CIPHER; - %} - - function chosen_cipher() : int %{ return chosen_cipher_; %} - - function set_cipher(cipher: uint32) : bool - %{ - chosen_cipher_ = cipher; - return true; - %} - function determine_ssl_record_layer(head0 : uint8, head1 : uint8, head2 : uint8, head3: uint8, head4: uint8, is_orig: bool) : int %{ @@ -818,24 +203,4 @@ refine connection SSL_Conn += { return UNKNOWN_VERSION; %} - function client_state() : int %{ return client_state_; %} - - function server_state() : int %{ return client_state_; %} - - function state(is_orig: bool) : int - %{ - if ( is_orig ) - return client_state_; - else - return server_state_; - %} - - function startEncryption(is_orig: bool) : bool - %{ - if ( is_orig ) - client_state_ = STATE_ENCRYPTED; - else - server_state_ = STATE_ENCRYPTED; - return true; - %} }; diff --git a/src/analyzer/protocol/ssl/ssl.pac b/src/analyzer/protocol/ssl/ssl.pac index 4a32227088..f7e7c17e7f 100644 --- a/src/analyzer/protocol/ssl/ssl.pac +++ b/src/analyzer/protocol/ssl/ssl.pac @@ -10,23 +10,32 @@ %extern{ #include "events.bif.h" + +namespace analyzer { namespace ssl { class SSL_Analyzer; } } +typedef analyzer::ssl::SSL_Analyzer* SSLAnalyzer; + +#include "SSL.h" %} +extern type SSLAnalyzer; + analyzer SSL withcontext { connection: SSL_Conn; flow: SSL_Flow; }; -connection SSL_Conn(bro_analyzer: BroAnalyzer) { +connection SSL_Conn(bro_analyzer: SSLAnalyzer) { upflow = SSL_Flow(true); downflow = SSL_Flow(false); }; +%include ssl-dtls-protocol.pac %include ssl-protocol.pac flow SSL_Flow(is_orig: bool) { flowunit = SSLPDU(is_orig) withcontext(connection, this); } +%include ssl-dtls-analyzer.pac %include ssl-analyzer.pac %include ssl-defs.pac diff --git a/src/analyzer/protocol/ssl/tls-handshake-analyzer.pac b/src/analyzer/protocol/ssl/tls-handshake-analyzer.pac new file mode 100644 index 0000000000..fb6ce2e7a4 --- /dev/null +++ b/src/analyzer/protocol/ssl/tls-handshake-analyzer.pac @@ -0,0 +1,273 @@ +# Analyzer for SSL/TLS Handshake protocol (Bro-specific part). + +%extern{ +#include +#include +#include +#include + +#include "util.h" + +#include "file_analysis/Manager.h" +%} + +%header{ + class extract_certs { + public: + bytestring const& operator() (X509Certificate* cert) const + { + return cert->certificate(); + } + }; + + string orig_label(bool is_orig); + string handshake_type_label(int type); + %} + +refine connection Handshake_Conn += { + + %include proc-client-hello.pac + %include proc-server-hello.pac + %include proc-certificate.pac + + function proc_session_ticket_handshake(rec: SessionTicketHandshake, is_orig: bool): bool + %{ + if ( ssl_session_ticket_handshake ) + { + BifEvent::generate_ssl_session_ticket_handshake(bro_analyzer(), + bro_analyzer()->Conn(), + ${rec.ticket_lifetime_hint}, + new StringVal(${rec.data}.length(), (const char*) ${rec.data}.data())); + } + return true; + %} + + function proc_ssl_extension(rec: Handshake, type: int, sourcedata: const_bytestring) : bool + %{ + // We cheat a little bit here. We want to throw this event + // for every extension we encounter, even those that are + // handled by more specialized events later. To access the + // parsed data, we use sourcedata, which contains the whole + // data blob of the extension, including headers. We skip + // over those (4 bytes). + size_t length = sourcedata.length(); + if ( length < 4 ) + { + // This should be impossible due to the binpac parser + // and protocol description + bro_analyzer()->ProtocolViolation(fmt("Impossible extension length: %zu", length)); + bro_analyzer()->SetSkip(true); + return true; + } + + length -= 4; + const unsigned char* data = sourcedata.begin() + 4; + + if ( ssl_extension ) + BifEvent::generate_ssl_extension(bro_analyzer(), + bro_analyzer()->Conn(), ${rec.is_orig}, type, + new StringVal(length, reinterpret_cast(data))); + return true; + %} + + function proc_ec_point_formats(rec: Handshake, point_format_list: uint8[]) : bool + %{ + VectorVal* points = new VectorVal(internal_type("index_vec")->AsVectorType()); + + if ( point_format_list ) + { + for ( unsigned int i = 0; i < point_format_list->size(); ++i ) + points->Assign(i, new Val((*point_format_list)[i], TYPE_COUNT)); + } + + BifEvent::generate_ssl_extension_ec_point_formats(bro_analyzer(), bro_analyzer()->Conn(), + ${rec.is_orig}, points); + + return true; + %} + + function proc_elliptic_curves(rec: Handshake, list: uint16[]) : bool + %{ + VectorVal* curves = new VectorVal(internal_type("index_vec")->AsVectorType()); + + if ( list ) + { + for ( unsigned int i = 0; i < list->size(); ++i ) + curves->Assign(i, new Val((*list)[i], TYPE_COUNT)); + } + + BifEvent::generate_ssl_extension_elliptic_curves(bro_analyzer(), bro_analyzer()->Conn(), + ${rec.is_orig}, curves); + + return true; + %} + + function proc_apnl(rec: Handshake, protocols: ProtocolName[]) : bool + %{ + VectorVal* plist = new VectorVal(internal_type("string_vec")->AsVectorType()); + + if ( protocols ) + { + for ( unsigned int i = 0; i < protocols->size(); ++i ) + plist->Assign(i, new StringVal((*protocols)[i]->name().length(), (const char*) (*protocols)[i]->name().data())); + } + + BifEvent::generate_ssl_extension_application_layer_protocol_negotiation(bro_analyzer(), bro_analyzer()->Conn(), + ${rec.is_orig}, plist); + + return true; + %} + + function proc_server_name(rec: Handshake, list: ServerName[]) : bool + %{ + VectorVal* servers = new VectorVal(internal_type("string_vec")->AsVectorType()); + + if ( list ) + { + for ( unsigned int i = 0, j = 0; i < list->size(); ++i ) + { + ServerName* servername = (*list)[i]; + if ( servername->name_type() != 0 ) + { + bro_analyzer()->Weird(fmt("Encountered unknown type in server name ssl extension: %d", servername->name_type())); + continue; + } + + if ( servername->host_name() ) + servers->Assign(j++, new StringVal(servername->host_name()->host_name().length(), (const char*) servername->host_name()->host_name().data())); + else + bro_analyzer()->Weird("Empty server_name extension in ssl connection"); + } + } + + BifEvent::generate_ssl_extension_server_name(bro_analyzer(), bro_analyzer()->Conn(), + ${rec.is_orig}, servers); + + return true; + %} + + function proc_v3_certificate(is_orig: bool, cl : X509Certificate[]) : bool + %{ + vector* certs = cl; + vector* cert_list = new vector(); + + std::transform(certs->begin(), certs->end(), + std::back_inserter(*cert_list), extract_certs()); + + bool ret = proc_certificate(is_orig, cert_list); + delete cert_list; + return ret; + %} + + function proc_unknown_handshake(hs: Handshake, is_orig: bool) : bool + %{ + bro_analyzer()->ProtocolViolation(fmt("unknown handshake message (%d) from %s", + ${hs.msg_type}, orig_label(is_orig).c_str())); + return true; + %} + + function proc_certificate_status(rec : Handshake, status_type: uint8, response: bytestring) : bool + %{ + if ( status_type == 1 ) // ocsp + { + BifEvent::generate_ssl_stapled_ocsp(bro_analyzer(), + bro_analyzer()->Conn(), ${rec.is_orig}, + new StringVal(response.length(), + (const char*) response.data())); + } + + return true; + %} + + function proc_ec_server_key_exchange(rec: Handshake, curve_type: uint8, curve: uint16) : bool + %{ + if ( curve_type == NAMED_CURVE ) + BifEvent::generate_ssl_server_curve(bro_analyzer(), + bro_analyzer()->Conn(), curve); + + return true; + %} + + function proc_dh_server_key_exchange(rec: Handshake, p: bytestring, g: bytestring, Ys: bytestring) : bool + %{ + BifEvent::generate_ssl_dh_server_params(bro_analyzer(), + bro_analyzer()->Conn(), + new StringVal(p.length(), (const char*) p.data()), + new StringVal(g.length(), (const char*) g.data()), + new StringVal(Ys.length(), (const char*) Ys.data()) + ); + + return true; + %} + + function proc_handshake(is_orig: bool, msg_type: uint8, length: uint32) : bool + %{ + BifEvent::generate_ssl_handshake_message(bro_analyzer(), + bro_analyzer()->Conn(), is_orig, msg_type, length); + + return true; + %} + + +}; + +refine typeattr ClientHello += &let { + proc : bool = $context.connection.proc_client_hello(client_version, + gmt_unix_time, random_bytes, + session_id, csuits, 0); +}; + +refine typeattr ServerHello += &let { + proc : bool = $context.connection.proc_server_hello(server_version, + gmt_unix_time, random_bytes, session_id, cipher_suite, 0, + compression_method); +}; + +refine typeattr Certificate += &let { + proc : bool = $context.connection.proc_v3_certificate(rec.is_orig, certificates); +}; + +refine typeattr UnknownHandshake += &let { + proc : bool = $context.connection.proc_unknown_handshake(hs, is_orig); +}; + +refine typeattr SessionTicketHandshake += &let { + proc : bool = $context.connection.proc_session_ticket_handshake(this, rec.is_orig); +} + +refine typeattr SSLExtension += &let { + proc : bool = $context.connection.proc_ssl_extension(rec, type, sourcedata); +}; + +refine typeattr EcPointFormats += &let { + proc : bool = $context.connection.proc_ec_point_formats(rec, point_format_list); +}; + +refine typeattr EllipticCurves += &let { + proc : bool = $context.connection.proc_elliptic_curves(rec, elliptic_curve_list); +}; + +refine typeattr ApplicationLayerProtocolNegotiationExtension += &let { + proc : bool = $context.connection.proc_apnl(rec, protocol_name_list); +}; + +refine typeattr ServerNameExt += &let { + proc : bool = $context.connection.proc_server_name(rec, server_names); +}; + +refine typeattr CertificateStatus += &let { + proc : bool = $context.connection.proc_certificate_status(rec, status_type, response); +}; + +refine typeattr EcServerKeyExchange += &let { + proc : bool = $context.connection.proc_ec_server_key_exchange(rec, curve_type, curve); +}; + +refine typeattr DhServerKeyExchange += &let { + proc : bool = $context.connection.proc_dh_server_key_exchange(rec, dh_p, dh_g, dh_Ys); +}; + +refine typeattr Handshake += &let { + proc : bool = $context.connection.proc_handshake(is_orig, msg_type, msg_length); +}; + diff --git a/src/analyzer/protocol/ssl/tls-handshake-protocol.pac b/src/analyzer/protocol/ssl/tls-handshake-protocol.pac new file mode 100644 index 0000000000..723d95d7a4 --- /dev/null +++ b/src/analyzer/protocol/ssl/tls-handshake-protocol.pac @@ -0,0 +1,533 @@ +###################################################################### +# Handshake Protocols (7.) +###################################################################### + +enum HandshakeType { + HELLO_REQUEST = 0, + CLIENT_HELLO = 1, + SERVER_HELLO = 2, + SESSION_TICKET = 4, # RFC 5077 + CERTIFICATE = 11, + SERVER_KEY_EXCHANGE = 12, + CERTIFICATE_REQUEST = 13, + SERVER_HELLO_DONE = 14, + CERTIFICATE_VERIFY = 15, + CLIENT_KEY_EXCHANGE = 16, + FINISHED = 20, + CERTIFICATE_URL = 21, # RFC 3546 + CERTIFICATE_STATUS = 22, # RFC 3546 +}; + + +###################################################################### +# V3 Handshake Protocol (7.) +###################################################################### + +type UnknownHandshake(hs: Handshake, is_orig: bool) = record { + data : bytestring &restofdata &transient; +}; + +type Handshake(is_orig: bool) = record { + body : case msg_type of { + HELLO_REQUEST -> hello_request : HelloRequest(this); + CLIENT_HELLO -> client_hello : ClientHello(this); + SERVER_HELLO -> server_hello : ServerHello(this); + SESSION_TICKET -> session_ticket : SessionTicketHandshake(this); + CERTIFICATE -> certificate : Certificate(this); + SERVER_KEY_EXCHANGE -> server_key_exchange : ServerKeyExchange(this); + CERTIFICATE_REQUEST -> certificate_request : CertificateRequest(this); + SERVER_HELLO_DONE -> server_hello_done : ServerHelloDone(this); + CERTIFICATE_VERIFY -> certificate_verify : CertificateVerify(this); + CLIENT_KEY_EXCHANGE -> client_key_exchange : ClientKeyExchange(this); + FINISHED -> finished : Finished(this); + CERTIFICATE_URL -> certificate_url : bytestring &restofdata &transient; + CERTIFICATE_STATUS -> certificate_status : CertificateStatus(this); + default -> unknown_handshake : UnknownHandshake(this, is_orig); + } &length = msg_length; +} &byteorder = bigendian, + &let { + msg_type: uint8 = $context.connection.msg_type(); + msg_length: uint32 = $context.connection.msg_length(); +}; + +###################################################################### +# V3 Hello Request (7.4.1.1.) +###################################################################### + +# Hello Request is empty +type HelloRequest(rec: Handshake) = empty; + + +###################################################################### +# V3 Client Hello (7.4.1.2.) +###################################################################### + +type ClientHello(rec: Handshake) = record { + client_version : uint16; + gmt_unix_time : uint32; + random_bytes : bytestring &length = 28; + session_len : uint8; + session_id : uint8[session_len]; + csuit_len : uint16 &check(csuit_len > 1 && csuit_len % 2 == 0); + csuits : uint16[csuit_len/2]; + cmeth_len : uint8 &check(cmeth_len > 0); + cmeths : uint8[cmeth_len]; + # This weirdness is to deal with the possible existence or absence + # of the following fields. + ext_len: uint16[] &until($element == 0 || $element != 0); + extensions : SSLExtension(rec)[] &until($input.length() == 0); +}; + +###################################################################### +# V3 Server Hello (7.4.1.3.) +###################################################################### + +type ServerHello(rec: Handshake) = record { + server_version : uint16; + gmt_unix_time : uint32; + random_bytes : bytestring &length = 28; + session_len : uint8; + session_id : uint8[session_len]; + cipher_suite : uint16[1]; + compression_method : uint8; + # This weirdness is to deal with the possible existence or absence + # of the following fields. + ext_len: uint16[] &until($element == 0 || $element != 0); + extensions : SSLExtension(rec)[] &until($input.length() == 0); +} &let { + cipher_set : bool = + $context.connection.set_cipher(cipher_suite[0]); +}; + +###################################################################### +# V3 Server Certificate (7.4.2.) +###################################################################### + +type X509Certificate = record { + length : uint24; + certificate : bytestring &length = to_int()(length); +}; + +type Certificate(rec: Handshake) = record { + length : uint24; + certificates : X509Certificate[] &until($input.length() == 0); +} &length = to_int()(length)+3; + +# OCSP Stapling + +type CertificateStatus(rec: Handshake) = record { + status_type: uint8; # 1 = ocsp, everything else is undefined + length : uint24; + response: bytestring &restofdata; +}; + +###################################################################### +# V3 Server Key Exchange Message (7.4.3.) +###################################################################### + +# Usually, the server key exchange does not contain any information +# that we are interested in. +# +# The exception is when we are using an ECDHE, DHE or DH-Anon suite. +# In this case, we can extract information about the chosen cipher from +# here. +type ServerKeyExchange(rec: Handshake) = case $context.connection.chosen_cipher() of { + TLS_ECDH_ECDSA_WITH_NULL_SHA, + TLS_ECDH_ECDSA_WITH_RC4_128_SHA, + TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA, + TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA, + TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA, + TLS_ECDHE_ECDSA_WITH_NULL_SHA, + TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, + TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA, + TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, + TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, + TLS_ECDH_RSA_WITH_NULL_SHA, + TLS_ECDH_RSA_WITH_RC4_128_SHA, + TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA, + TLS_ECDH_RSA_WITH_AES_128_CBC_SHA, + TLS_ECDH_RSA_WITH_AES_256_CBC_SHA, + TLS_ECDHE_RSA_WITH_NULL_SHA, + TLS_ECDHE_RSA_WITH_RC4_128_SHA, + TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, + TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, + TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, + TLS_ECDH_ANON_WITH_NULL_SHA, + TLS_ECDH_ANON_WITH_RC4_128_SHA, + TLS_ECDH_ANON_WITH_3DES_EDE_CBC_SHA, + TLS_ECDH_ANON_WITH_AES_128_CBC_SHA, + TLS_ECDH_ANON_WITH_AES_256_CBC_SHA, + TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, + TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384, + TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256, + TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384, + TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, + TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384, + TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256, + TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384, + TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, + TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, + TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256, + TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384, + TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, + TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, + TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256, + TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384, + TLS_ECDHE_PSK_WITH_RC4_128_SHA, + TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA, + TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA, + TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA, + TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256, + TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384, + TLS_ECDHE_PSK_WITH_NULL_SHA, + TLS_ECDHE_PSK_WITH_NULL_SHA256, + TLS_ECDHE_PSK_WITH_NULL_SHA384, + TLS_ECDHE_ECDSA_WITH_ARIA_128_CBC_SHA256, + TLS_ECDHE_ECDSA_WITH_ARIA_256_CBC_SHA384, + TLS_ECDH_ECDSA_WITH_ARIA_128_CBC_SHA256, + TLS_ECDH_ECDSA_WITH_ARIA_256_CBC_SHA384, + TLS_ECDHE_RSA_WITH_ARIA_128_CBC_SHA256, + TLS_ECDHE_RSA_WITH_ARIA_256_CBC_SHA384, + TLS_ECDH_RSA_WITH_ARIA_128_CBC_SHA256, + TLS_ECDH_RSA_WITH_ARIA_256_CBC_SHA384, + TLS_ECDHE_ECDSA_WITH_ARIA_128_GCM_SHA256, + TLS_ECDHE_ECDSA_WITH_ARIA_256_GCM_SHA384, + TLS_ECDH_ECDSA_WITH_ARIA_128_GCM_SHA256, + TLS_ECDH_ECDSA_WITH_ARIA_256_GCM_SHA384, + TLS_ECDHE_RSA_WITH_ARIA_128_GCM_SHA256, + TLS_ECDHE_RSA_WITH_ARIA_256_GCM_SHA384, + TLS_ECDH_RSA_WITH_ARIA_128_GCM_SHA256, + TLS_ECDH_RSA_WITH_ARIA_256_GCM_SHA384, + TLS_ECDHE_PSK_WITH_ARIA_128_CBC_SHA256, + TLS_ECDHE_PSK_WITH_ARIA_256_CBC_SHA384, + TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256, + TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384, + TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256, + TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384, + TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256, + TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384, + TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256, + TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384, + TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256, + TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384, + TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256, + TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384, + TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256, + TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384, + TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256, + TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384, + TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256, + TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384, + TLS_ECDHE_ECDSA_WITH_AES_128_CCM, + TLS_ECDHE_ECDSA_WITH_AES_256_CCM, + TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8, + TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8, + TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, + TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 + -> ec_server_key_exchange : EcServerKeyExchange(rec); + + # DHE suites + TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA, + TLS_DHE_DSS_WITH_DES_CBC_SHA, + TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA, + TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA, + TLS_DHE_RSA_WITH_DES_CBC_SHA, + TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA, + TLS_DHE_DSS_WITH_AES_128_CBC_SHA, + TLS_DHE_RSA_WITH_AES_128_CBC_SHA, + TLS_DHE_DSS_WITH_AES_256_CBC_SHA, + TLS_DHE_RSA_WITH_AES_256_CBC_SHA, + TLS_DHE_DSS_WITH_AES_128_CBC_SHA256, + TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA, + TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA, + TLS_DHE_DSS_EXPORT1024_WITH_DES_CBC_SHA, + TLS_DHE_DSS_EXPORT1024_WITH_RC4_56_SHA, + TLS_DHE_DSS_WITH_RC4_128_SHA, + TLS_DHE_RSA_WITH_AES_128_CBC_SHA256, + TLS_DHE_DSS_WITH_AES_256_CBC_SHA256, + TLS_DHE_RSA_WITH_AES_256_CBC_SHA256, + TLS_DHE_DSS_WITH_3DES_EDE_CBC_RMD, + TLS_DHE_DSS_WITH_AES_128_CBC_RMD, + TLS_DHE_DSS_WITH_AES_256_CBC_RMD, + TLS_DHE_RSA_WITH_3DES_EDE_CBC_RMD, + TLS_DHE_RSA_WITH_AES_128_CBC_RMD, + TLS_DHE_RSA_WITH_AES_256_CBC_RMD, + TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA, + TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA, + TLS_DHE_PSK_WITH_RC4_128_SHA, + TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA, + TLS_DHE_PSK_WITH_AES_128_CBC_SHA, + TLS_DHE_PSK_WITH_AES_256_CBC_SHA, + TLS_DHE_DSS_WITH_SEED_CBC_SHA, + TLS_DHE_RSA_WITH_SEED_CBC_SHA, + TLS_DHE_RSA_WITH_AES_128_GCM_SHA256, + TLS_DHE_RSA_WITH_AES_256_GCM_SHA384, + TLS_DHE_DSS_WITH_AES_128_GCM_SHA256, + TLS_DHE_DSS_WITH_AES_256_GCM_SHA384, + TLS_DHE_PSK_WITH_AES_128_GCM_SHA256, + TLS_DHE_PSK_WITH_AES_256_GCM_SHA384, + TLS_DHE_PSK_WITH_AES_128_CBC_SHA256, + TLS_DHE_PSK_WITH_AES_256_CBC_SHA384, + TLS_DHE_PSK_WITH_NULL_SHA256, + TLS_DHE_PSK_WITH_NULL_SHA384, + TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256, + TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256, + TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256, + TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256, + TLS_DHE_DSS_WITH_ARIA_128_CBC_SHA256, + TLS_DHE_DSS_WITH_ARIA_256_CBC_SHA384, + TLS_DHE_RSA_WITH_ARIA_128_CBC_SHA256, + TLS_DHE_RSA_WITH_ARIA_256_CBC_SHA384, + TLS_DHE_RSA_WITH_ARIA_128_GCM_SHA256, + TLS_DHE_RSA_WITH_ARIA_256_GCM_SHA384, + TLS_DHE_DSS_WITH_ARIA_128_GCM_SHA256, + TLS_DHE_DSS_WITH_ARIA_256_GCM_SHA384, + TLS_DHE_PSK_WITH_ARIA_128_CBC_SHA256, + TLS_DHE_PSK_WITH_ARIA_256_CBC_SHA384, + TLS_DHE_PSK_WITH_ARIA_128_GCM_SHA256, + TLS_DHE_PSK_WITH_ARIA_256_GCM_SHA384, + TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256, + TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384, + TLS_DHE_DSS_WITH_CAMELLIA_128_GCM_SHA256, + TLS_DHE_DSS_WITH_CAMELLIA_256_GCM_SHA384, + TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256, + TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384, + TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256, + TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384, + TLS_DHE_RSA_WITH_AES_128_CCM, + TLS_DHE_RSA_WITH_AES_256_CCM, + TLS_DHE_RSA_WITH_AES_128_CCM_8, + TLS_DHE_RSA_WITH_AES_256_CCM_8, + TLS_DHE_PSK_WITH_AES_128_CCM, + TLS_DHE_PSK_WITH_AES_256_CCM, + TLS_PSK_DHE_WITH_AES_128_CCM_8, + TLS_PSK_DHE_WITH_AES_256_CCM_8, + TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256, + # DH-anon suites + TLS_DH_ANON_EXPORT_WITH_RC4_40_MD5, + TLS_DH_ANON_WITH_RC4_128_MD5, + TLS_DH_ANON_EXPORT_WITH_DES40_CBC_SHA, + TLS_DH_ANON_WITH_DES_CBC_SHA, + TLS_DH_ANON_WITH_3DES_EDE_CBC_SHA, + TLS_DH_ANON_WITH_AES_128_CBC_SHA, + TLS_DH_ANON_WITH_AES_256_CBC_SHA, + TLS_DH_ANON_WITH_CAMELLIA_128_CBC_SHA, + TLS_DH_ANON_WITH_AES_128_CBC_SHA256, + TLS_DH_ANON_WITH_AES_256_CBC_SHA256, + TLS_DH_ANON_WITH_CAMELLIA_256_CBC_SHA, + TLS_DH_ANON_WITH_SEED_CBC_SHA, + TLS_DH_ANON_WITH_AES_128_GCM_SHA256, + TLS_DH_ANON_WITH_AES_256_GCM_SHA384, + TLS_DH_ANON_WITH_CAMELLIA_128_CBC_SHA256, + TLS_DH_ANON_WITH_CAMELLIA_256_CBC_SHA256, + TLS_DH_ANON_WITH_ARIA_128_CBC_SHA256, + TLS_DH_ANON_WITH_ARIA_256_CBC_SHA384, + TLS_DH_ANON_WITH_ARIA_128_GCM_SHA256, + TLS_DH_ANON_WITH_ARIA_256_GCM_SHA384, + TLS_DH_ANON_WITH_CAMELLIA_128_GCM_SHA256, + TLS_DH_ANON_WITH_CAMELLIA_256_GCM_SHA384 + # DH non-anon suites do not send a ServerKeyExchange + -> dh_server_key_exchange : DhServerKeyExchange(rec); + + default + -> key : bytestring &restofdata &transient; +}; + +# For the moment, we really only are interested in the curve name. If it +# is not set (if the server sends explicit parameters), we do not bother. +# We also do not parse the actual signature data following the named curve. +type EcServerKeyExchange(rec: Handshake) = record { + curve_type: uint8; + curve: uint16; # only if curve_type = 3 (NAMED_CURVE) + data: bytestring &restofdata &transient; +}; + +# For both, dh_anon and dhe the ServerKeyExchange starts with a ServerDHParams +# structure. After that, they start to differ, but we do not care about that. +type DhServerKeyExchange(rec: Handshake) = record { + dh_p_length: uint16; + dh_p: bytestring &length=dh_p_length; + dh_g_length: uint16; + dh_g: bytestring &length=dh_g_length; + dh_Ys_length: uint16; + dh_Ys: bytestring &length=dh_Ys_length; + data: bytestring &restofdata &transient; +}; + + +###################################################################### +# V3 Certificate Request (7.4.4.) +###################################################################### + +# For now, ignore Certificate Request Details; just eat up message. +type CertificateRequest(rec: Handshake) = record { + cont : bytestring &restofdata &transient; +}; + + +###################################################################### +# V3 Server Hello Done (7.4.5.) +###################################################################### + +# Server Hello Done is empty +type ServerHelloDone(rec: Handshake) = empty; + + +###################################################################### +# V3 Client Certificate (7.4.6.) +###################################################################### + +# Client Certificate is identical to Server Certificate; +# no further definition here + + +###################################################################### +# V3 Client Key Exchange Message (7.4.7.) +###################################################################### + +# For now ignore details of ClientKeyExchange (most of it is +# encrypted anyway); just eat up message. +type ClientKeyExchange(rec: Handshake) = record { + key : bytestring &restofdata &transient; +}; + + +###################################################################### +# V3 Certificate Verify (7.4.8.) +###################################################################### + +# For now, ignore Certificate Verify; just eat up the message. +type CertificateVerify(rec: Handshake) = record { + cont : bytestring &restofdata &transient; +}; + + +###################################################################### +# V3 Finished (7.4.9.) +###################################################################### + +# The finished messages are always sent after encryption is in effect, +# so we will not be able to read those messages. +type Finished(rec: Handshake) = record { + cont : bytestring &restofdata &transient; +}; + +type SessionTicketHandshake(rec: Handshake) = record { + ticket_lifetime_hint: uint32; + data: bytestring &restofdata; +}; + +###################################################################### +# TLS Extensions +###################################################################### + +type SSLExtension(rec: Handshake) = record { + type: uint16; + data_len: uint16; + + # Pretty code ahead. Deal with the fact that perhaps extensions are + # not really present and we do not want to fail because of that. + ext: case type of { + EXT_APPLICATION_LAYER_PROTOCOL_NEGOTIATION -> apnl: ApplicationLayerProtocolNegotiationExtension(rec)[] &until($element == 0 || $element != 0); + EXT_ELLIPTIC_CURVES -> elliptic_curves: EllipticCurves(rec)[] &until($element == 0 || $element != 0); + EXT_EC_POINT_FORMATS -> ec_point_formats: EcPointFormats(rec)[] &until($element == 0 || $element != 0); +# EXT_STATUS_REQUEST -> status_request: StatusRequest(rec)[] &until($element == 0 || $element != 0); + EXT_SERVER_NAME -> server_name: ServerNameExt(rec)[] &until($element == 0 || $element != 0); + default -> data: bytestring &restofdata; + }; +} &length=data_len+4 &exportsourcedata; + +type ServerNameHostName() = record { + length: uint16; + host_name: bytestring &length=length; +}; + +type ServerName() = record { + name_type: uint8; # has to be 0 for host-name + name: case name_type of { + 0 -> host_name: ServerNameHostName; + default -> data : bytestring &restofdata &transient; # unknown name + }; +}; + +type ServerNameExt(rec: Handshake) = record { + length: uint16; + server_names: ServerName[] &until($input.length() == 0); +} &length=length+2; + +# Do not parse for now. Structure is correct, but only contains asn.1 data that we would not use further. +#type OcspStatusRequest(rec: Handshake) = record { +# responder_id_list_length: uint16; +# responder_id_list: bytestring &length=responder_id_list_length; +# request_extensions_length: uint16; +# request_extensions: bytestring &length=request_extensions_length; +#}; +# +#type StatusRequest(rec: Handshake) = record { +# status_type: uint8; # 1 -> ocsp +# req: case status_type of { +# 1 -> ocsp_status_request: OcspStatusRequest(rec); +# default -> data : bytestring &restofdata &transient; # unknown +# }; +#}; + +type EcPointFormats(rec: Handshake) = record { + length: uint8; + point_format_list: uint8[length]; +}; + +type EllipticCurves(rec: Handshake) = record { + length: uint16; + elliptic_curve_list: uint16[length/2]; +}; + +type ProtocolName() = record { + length: uint8; + name: bytestring &length=length; +}; + +type ApplicationLayerProtocolNegotiationExtension(rec: Handshake) = record { + length: uint16; + protocol_name_list: ProtocolName[] &until($input.length() == 0); +} &length=length+2; + +refine connection Handshake_Conn += { + + %member{ + uint32 chosen_cipher_; + uint8 msg_type_; + uint32 msg_length_; + %} + + %init{ + chosen_cipher_ = NO_CHOSEN_CIPHER; + msg_type_ = 0; + msg_length_ = 0; + %} + + function chosen_cipher() : int %{ return chosen_cipher_; %} + + function msg_type() : uint8 %{ return msg_type_; %} + + function msg_length() : uint32 %{ return msg_length_; %} + + function set_msg_type(type: uint8) : bool + %{ + msg_type_ = type; + return true; + %} + + function set_msg_length(len: uint32) : bool + %{ + msg_length_ = len; + return true; + %} + + function set_cipher(cipher: uint32) : bool + %{ + chosen_cipher_ = cipher; + return true; + %} +}; + + diff --git a/src/analyzer/protocol/ssl/tls-handshake.pac b/src/analyzer/protocol/ssl/tls-handshake.pac new file mode 100644 index 0000000000..a1bd2e3954 --- /dev/null +++ b/src/analyzer/protocol/ssl/tls-handshake.pac @@ -0,0 +1,24 @@ +# Binpac analyzer just for the TLS handshake protocol and nothing else + +%include binpac.pac +%include bro.pac + +analyzer TLSHandshake withcontext { + connection: Handshake_Conn; + flow: Handshake_Flow; +}; + +connection Handshake_Conn(bro_analyzer: BroAnalyzer) { + upflow = Handshake_Flow(true); + downflow = Handshake_Flow(false); +}; + +flow Handshake_Flow(is_orig: bool) { + datagram = Handshake(is_orig) withcontext(connection, this); +} + +%include tls-handshake-protocol.pac +%include tls-handshake-analyzer.pac + +%include ssl-defs.pac + diff --git a/testing/btest/Traces/tls/dtls-openssl.pcap b/testing/btest/Traces/tls/dtls-openssl.pcap new file mode 100644 index 0000000000000000000000000000000000000000..b07e6921a10c25dcfdf1d87bae393b596f360900 GIT binary patch literal 3181 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 dNQVH&hCtjar4{~22S Date: Tue, 10 Mar 2015 14:29:40 -0700 Subject: [PATCH 02/11] When setting the SSL analyzer to fail, also stop processing data that already has been delivered to the analyzer, not just future data. No testcase because this is hard to reproduce, this was only found due to mistakenly triggering an error in life traffic at a site... --- src/analyzer/protocol/ssl/ssl-protocol.pac | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/analyzer/protocol/ssl/ssl-protocol.pac b/src/analyzer/protocol/ssl/ssl-protocol.pac index d5628e9cc7..b0f51cd54a 100644 --- a/src/analyzer/protocol/ssl/ssl-protocol.pac +++ b/src/analyzer/protocol/ssl/ssl-protocol.pac @@ -135,6 +135,12 @@ refine connection SSL_Conn += { function determine_ssl_record_layer(head0 : uint8, head1 : uint8, head2 : uint8, head3: uint8, head4: uint8, is_orig: bool) : int %{ + // stop processing if we already had a protocol violation or otherwhise + // decided that we do not want to parse anymore. Just setting skip is not + // enough for the data that is already in the pipe. + if ( bro_analyzer()->Skipping() ) + return UNKNOWN_VERSION; + // re-check record layer version to be sure that we still are synchronized with // the data stream if ( record_layer_version_ != UNKNOWN_VERSION && record_layer_version_ != SSLv20 ) From 47de9066126b5f7d33d59b4ac0198b880e464fbc Mon Sep 17 00:00:00 2001 From: Johanna Amann Date: Wed, 11 Mar 2015 15:53:32 -0700 Subject: [PATCH 03/11] Make handshake analyzer flow-based. This means we can feed data to it in chunks, which makes dealing with fragmentation a little bit more convenient. --- src/analyzer/protocol/ssl/SSL.cc | 5 +- .../protocol/ssl/tls-handshake-analyzer.pac | 20 ++-- .../protocol/ssl/tls-handshake-protocol.pac | 97 ++++++++++--------- src/analyzer/protocol/ssl/tls-handshake.pac | 7 +- 4 files changed, 67 insertions(+), 62 deletions(-) diff --git a/src/analyzer/protocol/ssl/SSL.cc b/src/analyzer/protocol/ssl/SSL.cc index a26807c14b..17df73bd6e 100644 --- a/src/analyzer/protocol/ssl/SSL.cc +++ b/src/analyzer/protocol/ssl/SSL.cc @@ -63,10 +63,11 @@ void SSL_Analyzer::DeliverStream(int len, const u_char* data, bool orig) void SSL_Analyzer::SendHandshake(uint8 msg_type, uint32 length, const u_char* begin, const u_char* end, bool orig) { - handshake_interp->set_msg_type(msg_type); - handshake_interp->set_msg_length(length); try { + handshake_interp->NewData(orig, (const unsigned char*) &msg_type, (const unsigned char*) &msg_type + 1); + uint32 host_length = htonl(length); + handshake_interp->NewData(orig, (const unsigned char*) &host_length, (const unsigned char*) &host_length + sizeof(host_length)); handshake_interp->NewData(orig, begin, end); } catch ( const binpac::Exception& e ) diff --git a/src/analyzer/protocol/ssl/tls-handshake-analyzer.pac b/src/analyzer/protocol/ssl/tls-handshake-analyzer.pac index fb6ce2e7a4..a52381189b 100644 --- a/src/analyzer/protocol/ssl/tls-handshake-analyzer.pac +++ b/src/analyzer/protocol/ssl/tls-handshake-analyzer.pac @@ -42,7 +42,7 @@ refine connection Handshake_Conn += { return true; %} - function proc_ssl_extension(rec: Handshake, type: int, sourcedata: const_bytestring) : bool + function proc_ssl_extension(rec: HandshakeRecord, type: int, sourcedata: const_bytestring) : bool %{ // We cheat a little bit here. We want to throw this event // for every extension we encounter, even those that are @@ -70,7 +70,7 @@ refine connection Handshake_Conn += { return true; %} - function proc_ec_point_formats(rec: Handshake, point_format_list: uint8[]) : bool + function proc_ec_point_formats(rec: HandshakeRecord, point_format_list: uint8[]) : bool %{ VectorVal* points = new VectorVal(internal_type("index_vec")->AsVectorType()); @@ -86,7 +86,7 @@ refine connection Handshake_Conn += { return true; %} - function proc_elliptic_curves(rec: Handshake, list: uint16[]) : bool + function proc_elliptic_curves(rec: HandshakeRecord, list: uint16[]) : bool %{ VectorVal* curves = new VectorVal(internal_type("index_vec")->AsVectorType()); @@ -102,7 +102,7 @@ refine connection Handshake_Conn += { return true; %} - function proc_apnl(rec: Handshake, protocols: ProtocolName[]) : bool + function proc_apnl(rec: HandshakeRecord, protocols: ProtocolName[]) : bool %{ VectorVal* plist = new VectorVal(internal_type("string_vec")->AsVectorType()); @@ -118,7 +118,7 @@ refine connection Handshake_Conn += { return true; %} - function proc_server_name(rec: Handshake, list: ServerName[]) : bool + function proc_server_name(rec: HandshakeRecord, list: ServerName[]) : bool %{ VectorVal* servers = new VectorVal(internal_type("string_vec")->AsVectorType()); @@ -159,14 +159,14 @@ refine connection Handshake_Conn += { return ret; %} - function proc_unknown_handshake(hs: Handshake, is_orig: bool) : bool + function proc_unknown_handshake(hs: HandshakeRecord, is_orig: bool) : bool %{ bro_analyzer()->ProtocolViolation(fmt("unknown handshake message (%d) from %s", ${hs.msg_type}, orig_label(is_orig).c_str())); return true; %} - function proc_certificate_status(rec : Handshake, status_type: uint8, response: bytestring) : bool + function proc_certificate_status(rec : HandshakeRecord, status_type: uint8, response: bytestring) : bool %{ if ( status_type == 1 ) // ocsp { @@ -179,7 +179,7 @@ refine connection Handshake_Conn += { return true; %} - function proc_ec_server_key_exchange(rec: Handshake, curve_type: uint8, curve: uint16) : bool + function proc_ec_server_key_exchange(rec: HandshakeRecord, curve_type: uint8, curve: uint16) : bool %{ if ( curve_type == NAMED_CURVE ) BifEvent::generate_ssl_server_curve(bro_analyzer(), @@ -188,7 +188,7 @@ refine connection Handshake_Conn += { return true; %} - function proc_dh_server_key_exchange(rec: Handshake, p: bytestring, g: bytestring, Ys: bytestring) : bool + function proc_dh_server_key_exchange(rec: HandshakeRecord, p: bytestring, g: bytestring, Ys: bytestring) : bool %{ BifEvent::generate_ssl_dh_server_params(bro_analyzer(), bro_analyzer()->Conn(), @@ -268,6 +268,6 @@ refine typeattr DhServerKeyExchange += &let { }; refine typeattr Handshake += &let { - proc : bool = $context.connection.proc_handshake(is_orig, msg_type, msg_length); + proc : bool = $context.connection.proc_handshake(rec.is_orig, rec.msg_type, rec.msg_length); }; diff --git a/src/analyzer/protocol/ssl/tls-handshake-protocol.pac b/src/analyzer/protocol/ssl/tls-handshake-protocol.pac index 723d95d7a4..25f890d089 100644 --- a/src/analyzer/protocol/ssl/tls-handshake-protocol.pac +++ b/src/analyzer/protocol/ssl/tls-handshake-protocol.pac @@ -23,31 +23,36 @@ enum HandshakeType { # V3 Handshake Protocol (7.) ###################################################################### -type UnknownHandshake(hs: Handshake, is_orig: bool) = record { - data : bytestring &restofdata &transient; -}; +type HandshakeRecord(is_orig: bool) = record { + msg_type: uint8; + msg_length: uint32; + rec: Handshake(this); +# rec: bytestring &length=10 &transient; +} &length=(msg_length + 5); -type Handshake(is_orig: bool) = record { - body : case msg_type of { - HELLO_REQUEST -> hello_request : HelloRequest(this); - CLIENT_HELLO -> client_hello : ClientHello(this); - SERVER_HELLO -> server_hello : ServerHello(this); - SESSION_TICKET -> session_ticket : SessionTicketHandshake(this); - CERTIFICATE -> certificate : Certificate(this); - SERVER_KEY_EXCHANGE -> server_key_exchange : ServerKeyExchange(this); - CERTIFICATE_REQUEST -> certificate_request : CertificateRequest(this); - SERVER_HELLO_DONE -> server_hello_done : ServerHelloDone(this); - CERTIFICATE_VERIFY -> certificate_verify : CertificateVerify(this); - CLIENT_KEY_EXCHANGE -> client_key_exchange : ClientKeyExchange(this); - FINISHED -> finished : Finished(this); - CERTIFICATE_URL -> certificate_url : bytestring &restofdata &transient; - CERTIFICATE_STATUS -> certificate_status : CertificateStatus(this); - default -> unknown_handshake : UnknownHandshake(this, is_orig); - } &length = msg_length; -} &byteorder = bigendian, - &let { - msg_type: uint8 = $context.connection.msg_type(); - msg_length: uint32 = $context.connection.msg_length(); +type Handshake(rec: HandshakeRecord) = case rec.msg_type of { + HELLO_REQUEST -> hello_request : HelloRequest(rec); + CLIENT_HELLO -> client_hello : ClientHello(rec); + SERVER_HELLO -> server_hello : ServerHello(rec); + SESSION_TICKET -> session_ticket : SessionTicketHandshake(rec); + CERTIFICATE -> certificate : Certificate(rec); + SERVER_KEY_EXCHANGE -> server_key_exchange : ServerKeyExchange(rec); + CERTIFICATE_REQUEST -> certificate_request : CertificateRequest(rec); + SERVER_HELLO_DONE -> server_hello_done : ServerHelloDone(rec); + CERTIFICATE_VERIFY -> certificate_verify : CertificateVerify(rec); + CLIENT_KEY_EXCHANGE -> client_key_exchange : ClientKeyExchange(rec); + FINISHED -> finished : Finished(rec); + CERTIFICATE_URL -> certificate_url : bytestring &restofdata &transient; + CERTIFICATE_STATUS -> certificate_status : CertificateStatus(rec); + default -> unknown_handshake : UnknownHandshake(rec, rec.is_orig); +} + +type HandshakePDU(is_orig: bool) = record { + records: HandshakeRecord(is_orig)[] &transient; +} &byteorder = bigendian; + +type UnknownHandshake(hs: HandshakeRecord, is_orig: bool) = record { + data : bytestring &restofdata &transient; }; ###################################################################### @@ -55,14 +60,14 @@ type Handshake(is_orig: bool) = record { ###################################################################### # Hello Request is empty -type HelloRequest(rec: Handshake) = empty; +type HelloRequest(rec: HandshakeRecord) = empty; ###################################################################### # V3 Client Hello (7.4.1.2.) ###################################################################### -type ClientHello(rec: Handshake) = record { +type ClientHello(rec: HandshakeRecord) = record { client_version : uint16; gmt_unix_time : uint32; random_bytes : bytestring &length = 28; @@ -82,7 +87,7 @@ type ClientHello(rec: Handshake) = record { # V3 Server Hello (7.4.1.3.) ###################################################################### -type ServerHello(rec: Handshake) = record { +type ServerHello(rec: HandshakeRecord) = record { server_version : uint16; gmt_unix_time : uint32; random_bytes : bytestring &length = 28; @@ -108,14 +113,14 @@ type X509Certificate = record { certificate : bytestring &length = to_int()(length); }; -type Certificate(rec: Handshake) = record { +type Certificate(rec: HandshakeRecord) = record { length : uint24; certificates : X509Certificate[] &until($input.length() == 0); } &length = to_int()(length)+3; # OCSP Stapling -type CertificateStatus(rec: Handshake) = record { +type CertificateStatus(rec: HandshakeRecord) = record { status_type: uint8; # 1 = ocsp, everything else is undefined length : uint24; response: bytestring &restofdata; @@ -131,7 +136,7 @@ type CertificateStatus(rec: Handshake) = record { # The exception is when we are using an ECDHE, DHE or DH-Anon suite. # In this case, we can extract information about the chosen cipher from # here. -type ServerKeyExchange(rec: Handshake) = case $context.connection.chosen_cipher() of { +type ServerKeyExchange(rec: HandshakeRecord) = case $context.connection.chosen_cipher() of { TLS_ECDH_ECDSA_WITH_NULL_SHA, TLS_ECDH_ECDSA_WITH_RC4_128_SHA, TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA, @@ -336,7 +341,7 @@ type ServerKeyExchange(rec: Handshake) = case $context.connection.chosen_cipher( # For the moment, we really only are interested in the curve name. If it # is not set (if the server sends explicit parameters), we do not bother. # We also do not parse the actual signature data following the named curve. -type EcServerKeyExchange(rec: Handshake) = record { +type EcServerKeyExchange(rec: HandshakeRecord) = record { curve_type: uint8; curve: uint16; # only if curve_type = 3 (NAMED_CURVE) data: bytestring &restofdata &transient; @@ -344,7 +349,7 @@ type EcServerKeyExchange(rec: Handshake) = record { # For both, dh_anon and dhe the ServerKeyExchange starts with a ServerDHParams # structure. After that, they start to differ, but we do not care about that. -type DhServerKeyExchange(rec: Handshake) = record { +type DhServerKeyExchange(rec: HandshakeRecord) = record { dh_p_length: uint16; dh_p: bytestring &length=dh_p_length; dh_g_length: uint16; @@ -360,7 +365,7 @@ type DhServerKeyExchange(rec: Handshake) = record { ###################################################################### # For now, ignore Certificate Request Details; just eat up message. -type CertificateRequest(rec: Handshake) = record { +type CertificateRequest(rec: HandshakeRecord) = record { cont : bytestring &restofdata &transient; }; @@ -370,7 +375,7 @@ type CertificateRequest(rec: Handshake) = record { ###################################################################### # Server Hello Done is empty -type ServerHelloDone(rec: Handshake) = empty; +type ServerHelloDone(rec: HandshakeRecord) = empty; ###################################################################### @@ -387,7 +392,7 @@ type ServerHelloDone(rec: Handshake) = empty; # For now ignore details of ClientKeyExchange (most of it is # encrypted anyway); just eat up message. -type ClientKeyExchange(rec: Handshake) = record { +type ClientKeyExchange(rec: HandshakeRecord) = record { key : bytestring &restofdata &transient; }; @@ -397,7 +402,7 @@ type ClientKeyExchange(rec: Handshake) = record { ###################################################################### # For now, ignore Certificate Verify; just eat up the message. -type CertificateVerify(rec: Handshake) = record { +type CertificateVerify(rec: HandshakeRecord) = record { cont : bytestring &restofdata &transient; }; @@ -408,11 +413,11 @@ type CertificateVerify(rec: Handshake) = record { # The finished messages are always sent after encryption is in effect, # so we will not be able to read those messages. -type Finished(rec: Handshake) = record { +type Finished(rec: HandshakeRecord) = record { cont : bytestring &restofdata &transient; }; -type SessionTicketHandshake(rec: Handshake) = record { +type SessionTicketHandshake(rec: HandshakeRecord) = record { ticket_lifetime_hint: uint32; data: bytestring &restofdata; }; @@ -421,7 +426,7 @@ type SessionTicketHandshake(rec: Handshake) = record { # TLS Extensions ###################################################################### -type SSLExtension(rec: Handshake) = record { +type SSLExtension(rec: HandshakeRecord) = record { type: uint16; data_len: uint16; @@ -450,20 +455,20 @@ type ServerName() = record { }; }; -type ServerNameExt(rec: Handshake) = record { +type ServerNameExt(rec: HandshakeRecord) = record { length: uint16; server_names: ServerName[] &until($input.length() == 0); } &length=length+2; # Do not parse for now. Structure is correct, but only contains asn.1 data that we would not use further. -#type OcspStatusRequest(rec: Handshake) = record { +#type OcspStatusRequest(rec: HandshakeRecord) = record { # responder_id_list_length: uint16; # responder_id_list: bytestring &length=responder_id_list_length; # request_extensions_length: uint16; # request_extensions: bytestring &length=request_extensions_length; #}; # -#type StatusRequest(rec: Handshake) = record { +#type StatusRequest(rec: HandshakeRecord) = record { # status_type: uint8; # 1 -> ocsp # req: case status_type of { # 1 -> ocsp_status_request: OcspStatusRequest(rec); @@ -471,12 +476,12 @@ type ServerNameExt(rec: Handshake) = record { # }; #}; -type EcPointFormats(rec: Handshake) = record { +type EcPointFormats(rec: HandshakeRecord) = record { length: uint8; point_format_list: uint8[length]; }; -type EllipticCurves(rec: Handshake) = record { +type EllipticCurves(rec: HandshakeRecord) = record { length: uint16; elliptic_curve_list: uint16[length/2]; }; @@ -486,7 +491,7 @@ type ProtocolName() = record { name: bytestring &length=length; }; -type ApplicationLayerProtocolNegotiationExtension(rec: Handshake) = record { +type ApplicationLayerProtocolNegotiationExtension(rec: HandshakeRecord) = record { length: uint16; protocol_name_list: ProtocolName[] &until($input.length() == 0); } &length=length+2; @@ -509,7 +514,7 @@ refine connection Handshake_Conn += { function msg_type() : uint8 %{ return msg_type_; %} - function msg_length() : uint32 %{ return msg_length_; %} + function msg_length() : uint32 %{ fprintf(stderr, "Got length %d\n", msg_length_); return msg_length_; %} function set_msg_type(type: uint8) : bool %{ diff --git a/src/analyzer/protocol/ssl/tls-handshake.pac b/src/analyzer/protocol/ssl/tls-handshake.pac index a1bd2e3954..36d6999557 100644 --- a/src/analyzer/protocol/ssl/tls-handshake.pac +++ b/src/analyzer/protocol/ssl/tls-handshake.pac @@ -13,12 +13,11 @@ connection Handshake_Conn(bro_analyzer: BroAnalyzer) { downflow = Handshake_Flow(false); }; +%include tls-handshake-protocol.pac + flow Handshake_Flow(is_orig: bool) { - datagram = Handshake(is_orig) withcontext(connection, this); + flowunit = HandshakePDU(is_orig) withcontext(connection, this); } -%include tls-handshake-protocol.pac %include tls-handshake-analyzer.pac - %include ssl-defs.pac - From ba27bb54d48e13b0b972596c0ef51330689b862b Mon Sep 17 00:00:00 2001 From: Johanna Amann Date: Wed, 11 Mar 2015 18:23:08 -0700 Subject: [PATCH 04/11] Implement correct parsing of TLS record fragmentation. Finally. Our test-case is a >400kb certificate with 10,000 alternative names. :) --- src/analyzer/protocol/ssl/SSL.cc | 6 +---- src/analyzer/protocol/ssl/SSL.h | 2 +- src/analyzer/protocol/ssl/ssl-analyzer.pac | 8 +++--- src/analyzer/protocol/ssl/ssl-protocol.pac | 7 ++--- .../protocol/ssl/tls-handshake-analyzer.pac | 4 +-- .../protocol/ssl/tls-handshake-protocol.pac | 25 ++---------------- src/analyzer/protocol/ssl/tls-handshake.pac | 2 +- .../.stdout | 1 + .../ssl.log | 10 +++++++ .../tls/tls-fragmented-handshake.pcap.gz | Bin 0 -> 37320 bytes .../scripts/base/protocols/ssl/fragment.test | 12 +++++++++ 11 files changed, 37 insertions(+), 40 deletions(-) create mode 100644 testing/btest/Baseline/scripts.base.protocols.ssl.fragment/.stdout create mode 100644 testing/btest/Baseline/scripts.base.protocols.ssl.fragment/ssl.log create mode 100644 testing/btest/Traces/tls/tls-fragmented-handshake.pcap.gz create mode 100644 testing/btest/scripts/base/protocols/ssl/fragment.test diff --git a/src/analyzer/protocol/ssl/SSL.cc b/src/analyzer/protocol/ssl/SSL.cc index 17df73bd6e..71b7511716 100644 --- a/src/analyzer/protocol/ssl/SSL.cc +++ b/src/analyzer/protocol/ssl/SSL.cc @@ -61,19 +61,15 @@ void SSL_Analyzer::DeliverStream(int len, const u_char* data, bool orig) } } -void SSL_Analyzer::SendHandshake(uint8 msg_type, uint32 length, const u_char* begin, const u_char* end, bool orig) +void SSL_Analyzer::SendHandshake(const u_char* begin, const u_char* end, bool orig) { try { - handshake_interp->NewData(orig, (const unsigned char*) &msg_type, (const unsigned char*) &msg_type + 1); - uint32 host_length = htonl(length); - handshake_interp->NewData(orig, (const unsigned char*) &host_length, (const unsigned char*) &host_length + sizeof(host_length)); handshake_interp->NewData(orig, begin, end); } catch ( const binpac::Exception& e ) { ProtocolViolation(fmt("Binpac exception: %s", e.c_msg())); - fprintf(stderr, "Handshake exception: %s\n", e.c_msg()); } } diff --git a/src/analyzer/protocol/ssl/SSL.h b/src/analyzer/protocol/ssl/SSL.h index a17611846c..3294aa9db5 100644 --- a/src/analyzer/protocol/ssl/SSL.h +++ b/src/analyzer/protocol/ssl/SSL.h @@ -21,7 +21,7 @@ public: virtual void DeliverStream(int len, const u_char* data, bool orig); virtual void Undelivered(uint64 seq, int len, bool orig); - void SendHandshake(uint8 msg_type, uint32 length, const u_char* begin, const u_char* end, bool orig); + void SendHandshake(const u_char* begin, const u_char* end, bool orig); // Overriden from tcp::TCP_ApplicationAnalyzer. virtual void EndpointEOF(bool is_orig); diff --git a/src/analyzer/protocol/ssl/ssl-analyzer.pac b/src/analyzer/protocol/ssl/ssl-analyzer.pac index 709e8c32b2..3d61b215a2 100644 --- a/src/analyzer/protocol/ssl/ssl-analyzer.pac +++ b/src/analyzer/protocol/ssl/ssl-analyzer.pac @@ -23,11 +23,9 @@ refine connection SSL_Conn += { return true; %} - function proc_handshake(rec: SSLRecord, msg_type: uint8, length: uint24, data: bytestring, is_orig: bool) : bool + function proc_handshake(rec: SSLRecord, data: bytestring, is_orig: bool) : bool %{ - fprintf(stderr, "Forwarding to Handshake analyzer: msg_type: %u, length: %u\n", msg_type, to_int()(length)); - fprintf(stderr, "%u\n", data.end() - data.begin()); - bro_analyzer()->SendHandshake(msg_type, to_int()(length), data.begin(), data.end(), is_orig); + bro_analyzer()->SendHandshake(data.begin(), data.end(), is_orig); return true; %} }; @@ -58,5 +56,5 @@ refine typeattr V2ClientMasterKey += &let { }; refine typeattr Handshake += &let { - proc : bool = $context.connection.proc_handshake(rec, msg_type, length, data, rec.is_orig); + proc : bool = $context.connection.proc_handshake(rec, data, rec.is_orig); }; diff --git a/src/analyzer/protocol/ssl/ssl-protocol.pac b/src/analyzer/protocol/ssl/ssl-protocol.pac index b0f51cd54a..a90bd03868 100644 --- a/src/analyzer/protocol/ssl/ssl-protocol.pac +++ b/src/analyzer/protocol/ssl/ssl-protocol.pac @@ -43,9 +43,10 @@ refine casetype PlaintextRecord += { }; type Handshake(rec: SSLRecord) = record { - msg_type: uint8; - length: uint24; - data: bytestring &length=to_int()(length); +# msg_type: uint8; +# length: uint24; +# data: bytestring &length=to_int()(length); + data: bytestring &restofdata; }; ###################################################################### diff --git a/src/analyzer/protocol/ssl/tls-handshake-analyzer.pac b/src/analyzer/protocol/ssl/tls-handshake-analyzer.pac index a52381189b..17432fa5cb 100644 --- a/src/analyzer/protocol/ssl/tls-handshake-analyzer.pac +++ b/src/analyzer/protocol/ssl/tls-handshake-analyzer.pac @@ -200,10 +200,10 @@ refine connection Handshake_Conn += { return true; %} - function proc_handshake(is_orig: bool, msg_type: uint8, length: uint32) : bool + function proc_handshake(is_orig: bool, msg_type: uint8, length: uint24) : bool %{ BifEvent::generate_ssl_handshake_message(bro_analyzer(), - bro_analyzer()->Conn(), is_orig, msg_type, length); + bro_analyzer()->Conn(), is_orig, msg_type, to_int()(length)); return true; %} diff --git a/src/analyzer/protocol/ssl/tls-handshake-protocol.pac b/src/analyzer/protocol/ssl/tls-handshake-protocol.pac index 25f890d089..296df5fb9d 100644 --- a/src/analyzer/protocol/ssl/tls-handshake-protocol.pac +++ b/src/analyzer/protocol/ssl/tls-handshake-protocol.pac @@ -25,10 +25,9 @@ enum HandshakeType { type HandshakeRecord(is_orig: bool) = record { msg_type: uint8; - msg_length: uint32; + msg_length: uint24; rec: Handshake(this); -# rec: bytestring &length=10 &transient; -} &length=(msg_length + 5); +} &length=(to_int()(msg_length) + 4); type Handshake(rec: HandshakeRecord) = case rec.msg_type of { HELLO_REQUEST -> hello_request : HelloRequest(rec); @@ -500,34 +499,14 @@ refine connection Handshake_Conn += { %member{ uint32 chosen_cipher_; - uint8 msg_type_; - uint32 msg_length_; %} %init{ chosen_cipher_ = NO_CHOSEN_CIPHER; - msg_type_ = 0; - msg_length_ = 0; %} function chosen_cipher() : int %{ return chosen_cipher_; %} - function msg_type() : uint8 %{ return msg_type_; %} - - function msg_length() : uint32 %{ fprintf(stderr, "Got length %d\n", msg_length_); return msg_length_; %} - - function set_msg_type(type: uint8) : bool - %{ - msg_type_ = type; - return true; - %} - - function set_msg_length(len: uint32) : bool - %{ - msg_length_ = len; - return true; - %} - function set_cipher(cipher: uint32) : bool %{ chosen_cipher_ = cipher; diff --git a/src/analyzer/protocol/ssl/tls-handshake.pac b/src/analyzer/protocol/ssl/tls-handshake.pac index 36d6999557..a3c45fa492 100644 --- a/src/analyzer/protocol/ssl/tls-handshake.pac +++ b/src/analyzer/protocol/ssl/tls-handshake.pac @@ -13,6 +13,7 @@ connection Handshake_Conn(bro_analyzer: BroAnalyzer) { downflow = Handshake_Flow(false); }; +%include ssl-defs.pac %include tls-handshake-protocol.pac flow Handshake_Flow(is_orig: bool) { @@ -20,4 +21,3 @@ flow Handshake_Flow(is_orig: bool) { } %include tls-handshake-analyzer.pac -%include ssl-defs.pac diff --git a/testing/btest/Baseline/scripts.base.protocols.ssl.fragment/.stdout b/testing/btest/Baseline/scripts.base.protocols.ssl.fragment/.stdout new file mode 100644 index 0000000000..5caff40c4a --- /dev/null +++ b/testing/btest/Baseline/scripts.base.protocols.ssl.fragment/.stdout @@ -0,0 +1 @@ +10000 diff --git a/testing/btest/Baseline/scripts.base.protocols.ssl.fragment/ssl.log b/testing/btest/Baseline/scripts.base.protocols.ssl.fragment/ssl.log new file mode 100644 index 0000000000..c8278858e5 --- /dev/null +++ b/testing/btest/Baseline/scripts.base.protocols.ssl.fragment/ssl.log @@ -0,0 +1,10 @@ +#separator \x09 +#set_separator , +#empty_field (empty) +#unset_field - +#path ssl +#open 2015-03-12-01-22-34 +#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p version cipher curve server_name resumed last_alert next_protocol established cert_chain_fuids client_cert_chain_fuids subject issuer client_subject client_issuer +#types time string addr port addr port string string string string bool string string bool vector[string] vector[string] string string string string +1426117218.083491 CXWv6p3arKYeMETxOg 192.168.6.86 61454 104.236.167.107 4433 TLSv12 TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 secp256r1 104.236.167.107 F - - F FsQdqWuF9t3e4W0d (empty) - - - - +#close 2015-03-12-01-22-34 diff --git a/testing/btest/Traces/tls/tls-fragmented-handshake.pcap.gz b/testing/btest/Traces/tls/tls-fragmented-handshake.pcap.gz new file mode 100644 index 0000000000000000000000000000000000000000..6642502fa068a4c7c98ca20d145b6ae997adce6b GIT binary patch literal 37320 zcmb@Pd0bQ1*7u+1u`N|^r4GowMWIy@5rrxW3M8o`B9c_8AY-a15z&Ns45UsMg<=XQ z2!X^pkSan%P-dbiB0`7~B?2LV010z|03jsgygSq(AfVXykDkx@tYXg2$v%6p@A|E^ zj!x9qUk3>PXaE1r@;mOk*4^hI=EM=K-;u*>j~>Jx_C0#g^N69B+d;4Yxi~tTgJt7Q z6+FGu3(hauwnrm-yUqFA!E4_SBBI-%lr7@Suq$!Ge*N7ZrR(r_oW z4EfmMV$F)GP0yg3{(+CB@ydV11l&BJ$I7?mKr$}U9d zEE4^UgNJqhHX43^#73Q$IY z={*r5*HKPc4=4EbjjH;T2h8xIoJ2da9lrHdz;Tz{(9F3xPJQ(l_%X*m+Q@waS8w4# zv<0D<-zovay5H~v-2)mW@NKhB5};3aw5*qvyUD$R0k27WkF1_Okxv(4jQ(Pi? z@?U0byRV(=PfyRhbl;HfAJ;HDK3(hh((KNJ0GAMUc)>ibnOEm;4LODFJ!q))zG2oq z|D&7CbTn*Xt6v8EvMK+>(ro{}^r#aq2RkF3?CbJdYQhU>u*02=>8Iy$ydPW`4Onsq z3YSqKNmf_^>l;E$&y(U-riEu+j;6fARTj`AMTI_mL2StLk4tlvV;s7wnqq9VS&{7F z=%r3P3op+>N|C)qZ!*&&)UoenE=@xR--|D;5YeF;mjHxY8LhgAz0p-sJ#?3zUn-*v zc@l=Z)G33vLg}I>P*~k^Ea3^RSkB5JuwN1JY%S3erny)xBD_tlOffKI8Z2yi=HY`^ zt$Q|kc|v8~oBTW_5Oif!JIAf8=F1#BXAtU2H&rOi5xrN@#WfpCzJWTs=y0)Uh`^7| z2u_o$q3TECWQ8&^qKHKqmC*^Ey}sz-$Gl*ks7N*>DPU|XW1z(a^iUEs!i#F?UY`^6 zvY=Q>p>}VQjU=e&2 zdNll5grYo$NS8;=GjCI97Izt8g9d%W2TCw7c_W55S}Y9f`U)2=PDdidv4O$;XL)oM z3nAwdLb&xt-d*O*VX>yOOoaApYZiHf=TZ?$E9$ipa)$hAvaW^;1tXUTk|Cn(9(0cS zNdlZj5tisffdLWdq2ER?aLq_INX+_(+I}U?^N1B_WCgma0&Q4<&Zt0R zE6_a^XzeI;@v%+cq1A^&9O`S{8mf`cIJ6bej(A(dicBt#r$+!)VFQp*ZGlvMxDJC%NrLj&WK)P$ zaZ5_e^^cRla9p`{;NuG$x^_MK`{38LtL(zx2a6X=rT#7K81N;RO226_{e$;Y_^fd! z@!|r|L#4-q(slbc?aD6)nMJM+ZlVlEH!JY?Bv^3yAN>)X!% z>;38PA}^KJlw1!-FknZ7OpP8 zwIVI{_U^m-<*6%3vBxKz6vTGzzH3mPv0~hb&#Ll2S46}v*{yoAZX*;k)AD8wCS?UGg!r;T>{y)z=ja-cniWt>kI@% zmoQp7xJD{LTxQ0$lb&NMBKO+;e)rHtjcd36eWY}i!A^&D&;B;8*}d;>RIJOzuB(SN zbqiM2?kG3h9kBN^Or>EJ*kcNoCZ^mMy`B+E49EM%%Lg^7S?9#q;?35IVUwt=mM_yB ze2S!Nq$IrzOgRQR0=KT=oe6Ln`Mnx*5q@ppKR1}G!gjVB@22d1W2%D3-M)OdbcMl6 zhjrzVR(5;t9*WiYEK|Lc_b~;L=k5_-DA>M{JJfwAQX*t_(IQ&$1%h^dFDK#95G9l%|w_KDKvX zD%+#<6>7s;Qz!~dvXo#keXz@4Odnbqs(*;)bPRW$xgu<3yRj9;YGh9}CKetykT_-n zLnt@23b49s9qSU?6?-^gMZt<%T@};a!wI?tYif^_8(IfA+^vXpiSL@qWRcMDQl3-P z9lNY&DBo(nrg@m{d=Wg@tYNtFEGcqRn0KidYmz?Pd+k2jTUdi}EzaWy6YgwEaV<qaDav(GMkH;%b{zHjJO4k^; zJFKgSbg-+udnjHb>-Oc(Gl`9EZ`ueEj7%YGI|k$_7V!KZ=SwA_ZG}>azjb%?K;jMN znlSfvV{3}TNM$u99-gH%-Hv-U^#FpM3^L%~xd&Y0FZy@ZgUeq&S@Wa&$#rvoclfpP z|J)Y8H7!1w`StHReqHl_Zu9>g_29q-*Dx%5R>C6h2bWgv;E0E9b|ib(w8Rn%4-uF3 zth)zg^F5*r$OB}LQZcu1G}1f=?vuvQ2(&orZC2#BF(qRo1&K+%M@B+kRd}=grPY30 z*k6W(KW+Mx=8iZ7()qX|0j#a( zg2jZE>;7WIAROGqFzfl*=dSGdV(qe{^S4BO?YRBS$BQw~E)fhA+%{$=yZSF|wu_69bPL zaJa!-9cI^_wVSekoB5jG4$DZ)8~ zFz^RtT!a{@+GxVl85K9NnDsqohs2{VE-ki~Q&C8R;@-0)gK)v`?a?m_2%)~EG;g-9wi&(rzC( zQo7o}&LQ*jOf@zJNCrW^O%rTV_6#UZEI3JEllukf6ea;5MAL>=`5zn&RuU$}_A3 zT<&(px+HYvA7<+o7}olanW(>g@KKX|`lp!^?vHf6jxbF54^KSGO6*hMURxL|Iu5e* z2edMBgq6c&TNw>ri}x;7(=ksUF7m`>1aW5<*yCFaDg=?1u;U)3JVc;l9~H%Q?kkAc zBdjyp3>-mw3pa0WQOHJ7h8ZQ02RjTCk?{}6!GZmLju}@5w?E5rA$Rv5Prwvd)VJ0e zG6RC|S13(p_FdJO1bD$f?G2`3SU`K0HN|D*b4@5j#H^~^9`SKpJr_%FYWJop2zz*`%E6Bt9Ps9fe_$dk%v)-IV9tAE zGP7Ue^ZJiR|6O9za_5JLZ#Ex)dT`r3txq*wUUGlr`-IlCMbsZn&Sd`Zd$i5(HVmi< zV_1a9uhgPSEOSD6z!Ri!!a~XhZ!<-~1V8%CQG0^gFh5cc8qDVBVX(J@MrX}S=I%K;x|aFRm|wb_g{pH~h$YuxFO>Hxo{l8%I}eSkHR8 zXZ*=JR?$zJH$v**DaF|{2;kPC`GcJTIxE4QL11?Gl)LQa+;}|xQ0ejv-*0TpsN7)8 zs@(JLWUler%IqImC40u7tY+=m5vC6Wps(aIbpGIt5UxXC;Xcj_O%(R%;dK zr>3vwnEsr5vgDgZ*ehPMR7^jtvz_{rKkfPmN!v?#(`M_);h~!A=i-o@UmjmVk(~Q` zB|Uo|kFp~-d3%=%m);u*eTKWQbZWH2MGOt}KyqpOKww(C-&v_&e!oX&`#^O)lgip^ z_)E~0l35zsfA#)!R&BM#&rK)isE;>oaNj-M?U;VhJ3}@Y27&uUOUZvN#~s)RwF()8 z!Dg`j_G}Rg&^+UQ`%B}dE=PBc>Au{UlITU)>t4&xY6bJZYk#qe2tKF!T8wt|z|rfL z%V9G!RauyAgiPZ}P;{CAahxl+biRXCn7RgX<@LO{g6&N^$6ryOvrEO)a^Ca$;Ied0 zkD^_jI~8-y!SFgVo6<-5j1qc zqm+s`>RZ}b6cn=DzeMM__(ErT6sz3^{9<|F7vn~OIc}tL7h?um%Z0F{winxpD?>KS$W-^_8dzAt)p>=-6ctq@#F7H60>$y? z%0nCCN^BNkuX-&!OIpR*uDssf-1Fm2idBVE=W%}TC}}W*U{)j$oU%UY}czQCRRvdO+~hA>frkH1dpOUoktvv z#+wRJoxuI9aZ2FoGz@mIWY?m20piiUFx<$0Zt_B(lO>kw+!SCOSRkY!xhCpYuoF*~+ztu@g*|NoUWjS#kJ>ALh<>*!6Vl*2N3%{_)3*Ocgt3 zgT3tpulV}82ww2M$H5UNR`czINW^mgPA70WJIX-ONkbaI`%Fj%+JVnnVx24w`<9v- zp{RkkQ&~5_29s-B!_wy*gr^L}%%!X-$@{kIte4>#-yf3aHaUMS+`36q)kJieyVvnt z_124vuV#OHVZbv)XG1j!tE2d2v%p7gv=E2tshn zfJ4(=kuMdAyOb`KUf}tXwTrNSdd)rSw2HH}Y4Mz#pL5Tum`dE(yNPxo+11xBX{Qey zydH$hre|P;FuRV-eZ)&4 zw_m#5&^8!6aI4XaE4=n8SKUjD z4mtkP?V7gM;OoE2cEU_LGT)i%iw8h-g9Usg7}!pZa^;fEJ`HjiBA6@J%mcrV_KAU` z*DSSQb!{(p5=}y~UtEh;F+CB#*x9+!k@g}ay2dlx_1fTf>FlFLGct8+);Nv2gi;&; z8Nc+j5fR~pG_Z|;VT{Brwp4V0wTXCHxi-NmE{=U2!aW9DxdX`n-q_XdEMsTf&*Mue zF3Cs&Jqej`8AVk~E+Qj&1r@G_wf2Vi*j1dJO(t`4_U1;HoLGdt=B0JEUe#owGws)# zvNDz0dsO} zRZPL~y7m`HVn9eX>spF-_rOuAr8#V7CQ-NY=_=sJMNS(bBfx^!mjhpfhyXll@(BY- zs`V&BcKSQgSRpAjo!PF`L9=xBj7*XZ8=-6PoY!&@dLvW{m|PE&PJ(m{O>yB|;Eccm zIx=mEDIr}i-Kg5;gRgIvA>WxS7+uOMewA)|v}jA`H;%aHA*XA!vbk42-E=>P+aY2r zIMwA3g%?Q3c?y09Nl#60>AI91&aL_26tgyC_&1b|fkHIb#2(*eRbXGpxFLq<2I1`) ztVmRD<&Z%Sr%rmAp+OMMjS^$o$GA&3Q38oD55S(i4~qm1JK_XcR>tZ{!OtsCyK8R{ zUrAJBSR55>Q86|Cr{{{7+FA2eoGnfB<^=wn+kCaeC2T__+|cdL;hyh()e_C0a<&NO ztq=So?{wwTsZ9aKfyWdDAke60#~?f?lv4bL^QFzv0tOAN178cbY*H@?{}tyOXL>jL12IQZFD2T!J0^N4PfXnFE_=A8Mo&1wq^2YWxYs3mj60dz+(t`0%-SsB{v68K_Q4tLDe|$Kw`jS_)SlBBUlV3;ioav*Oi|PYg5q4BUf!8 z1-c^+99J0IG3Xm{3eBRx204`r~I{5J#TK;MueR1zXEuJuNRf5D_FO~>HxjHcSV~|HF+c0C;l0vqV zSBXvS@ujm_S~qcsgTAF&3NLT7Fs~#eQ`(L)NnG@6<*zl{gKVP9efcNf_FBY?Qj40IXA32^<+ zBtVn-O7|#wIyQRBs+mLe8`@c zZdbJz4qpDNY&&da$2wJ0P*UR5NHWRACNVK?n{I?W5YA?sgX*@h${%6~1aV8_AdXbE zOws)xuz(AJUOY-C+1)Mx>o@x(i}F7Z2TUFdz9m=;27FnOOqjnijuJNH34-RrlG5Nn z!7=XWQMicf-x$IjWs-&}3-tDgv9jyZJBp(%QH`Ytq{6fVP^xrA* z?>&f32Z?jQ@;w*a%;jkUsHsrOlZ*hZV;DrLDdVq}nrO^O_7Lnb#w2ZKRVKPuZSYmX z)8FK>r^$Ve>3Eo#)FikE2&d()sNyMSkHGyMm*sr0Ul;HM@|9Jt}nrSD)|z?Nq;ENeT3v_`mHL1T;v33MHVylrrzRYzhrYu74D_03m(e zb>9s5lF~1E<|8KffU5)GXA>L5!h5(4I7P$Q3OSy?RLKg!RuH^yhBWj6MxAg3D>Rzk z5k435L`ZitGY)U7H)Z}#_j>4;F*@Ybwb?kl|D}QzX^M94`%MdJz%|BY3=g_deY@!} ztZyk5Y`HzYsTyc;B}0Sm&jtVJnR4@e_-e7RfeNOzIhfYzVlb@>C8EI#o}#g3GTI%x z!S`CC7K3wCu+!KyDepz)dlUFlst7d+RejWCQv%$Tm!4}(ASzg;cwknEY}pLDKRa05 zOy=m0zux#EG)s?uKygze)+E%W&nY%iK2RmC0z~L5xsXYM)Jz>rp?ep=a%I$GWgM84 z$Er+m@7dr>O*Ch4JOs$`CZ?tN3?XSET@9j@+pZ?q^f6%5M~emYUJejb1+k%{=1?)v zC$3IprSbSA#%E9b$WLLo_mEXlLrQ{5JlCWwah5Fr>truJ?RVqFrxB?L>Xo#a4$L+5^8@e}mN3%wXeQ)jc#InPJS7q$R_3$g>Nv8K` z&_@vI9mz}uQn_FIQU!Dccwn*M#{~{J|44(J9?ApZrcN-mrUt07k*HgJGOSHHlK&Ne znWa~@MxSp-H`C{@rr*1HZd>uD(IxC=0*1Iu;iGheM+srx@%ZqK)(T&^^*kw`OwSoS zBzCwfEBL-tO&`9iZ%d^5KKvj2(~ESj4}V`8v5I_QacLlWe$b8PsgClZyV88ERql2aPUb$C%Tt!DLa9%4#2{CWTdQ?(-m1QbJHC9 z)1_T4p_ZL0YPDmPvGG4!1yBOm;(WPsdovJ(G8(NZl=`E3_B9)BR37|$_6gq~;&^X) z>>Y-woahh!`>(Q}U|)5t`_q3Jwix2J>|CSU2X$Wi!5O+dJ zMPQc8z$~8*_O5tsb4#6qBR{GZMk@uY=Bt)e0ioPS40Ya;(%0b>o!XgL1&w})Mi8PK zjQi{_1@CCmxMaV<^+oWPA0kXYe#7U;PO6~8sZja^Ba5v?L~>vb08UGzB9O9}Z@CAA z!Rgk=ixC|;&W?RY(lnrhBn_Nb&A`qMSIv6ozW6djB-IEAt!yEy{VPm5m8D1ck%UCm z8fwC=rXww&p^qFnxL`^$Fn@}+?B#!{fV=Yglr zH^(su7YG10W%eu zK2WFFtAM+-lb(0|oR&q{zU?FZsmsDU@09D7xq92q2YT!9kQ2(FSdmmu%k}My7XheA zmw=Es+R27W14|Na>3uSi%EN)Y$*6XD*biW;Uk_SYYOGJT>e~~E*=G^QPh7-QHE9>j zOdp%52OcR0nhPCFHm1u)C_%`8%tb&Z+n51VPYTbt*Ipxd2VW!6ev#`NpTG-D!1pj> z5wLb@IqB0xCxJ2^c1+@QTtTBHLDs;-V$B9&6$uewOE)af`Xf}NU9i}Z_B`ZljX}2S zpM!JK?T;31?bMi&$yOX8TU&%M>mq>UnX(jRMm17z5AOOCBM=QEDBS>ri*sKLD#cDN zpr6PHl59&g-PhhgGElTBfKaXlHWnJ#SR~tOSnUhTnAC++C}i($Te^jJ`sXQR@1?aI zG04S0xL_3o5Y5*FsSTnW5X~R=p+0B#L`obpk#qlare!q+FK`ce9;O0gMwGfii#(2aHYiI>MbiewcRlrWA$S#+0f=6jjCx zgQZ}-1jo%_zU#m||0U=~iGhae&EDN-?N=A>Yq~UtrfT|_usFHs^nt2&6c7*&#>gEWxZ zN+||Xlq^>nKAcSSdWUCE7P4m~)qMb`s3J~Hg)|e;s(d72Z;k#&%3mN{plWN=c z2;z~An>B9(T+hzshhvZi3Z6YSW4KL6$+D!UJ3^?c0}>&KgfG46W1)%Kd5tKM>P-c`SEZ=7DWbbI^vGcjd; zqukbp9s?BMZlgN*R1-}wLJW_Fce75|}vK~UV1GC`S>vEczzfUWfP3#M2>5UN&FRRvX;(SJ{?{rt4++?15Zacfh4Fi96lDOY}IL z`tIa>;!5|V%N~bP$Dh2Vrg!)>cJdCNG&8~EMhEjjUCwEpjUW%RInb1+18Y82)?+ac z=L8i1r>UX_I8FJveB%s@^x^h;5c(-`3#1J{6^SmV4}+4Aq3bs^0vkL*&8s>$yfnp0 zQ{E?tM2(68sHXr>e~IT7^}Ze~ENIsgh_PrZaqSws$y^Gf1e4WUdmC?JKw&(?WcAnH zmXEsrt&olJ+lLC7((<7~rnJ0K$ljpY*4#AaZm?d8znKM0d^pi%v^z`)5@z;Ok%+QEhTiej{9HYw z^q{H^u@!kBw%eYQH^}Hbo-r&TWNu0+&PhT-78E4S%paEG>OD+u_j~qCH&nQlt(Fge zK6o-i-7oA)=PVbUwvnI4nYJDLY}oqd4W$Ky`VD$4qk?GJmq1u}3<|^o*51ys zG(=49%o7Y%N$>g~UmK*ZL016lJ_MVL2~H8149YJ9@j*3mqt|~g^4GPO5B~dR*)G`5 zj&=KpF(JRdbbD_iyYKweJjY29#^Xgu8p17yBZolsXBODwx#05O0*@$PZ&FoERVe%a zz)eGU!76~WI0AMS6q8)_J6&Nq@S^8@@J&)gxPOiGg9H|yWvO}Nn3uQd;__yJ?DT-3?_(QLRVr;=% zg-m85?pPi$KSd!m( z{+h%Ts?^9J+3&hLIH7c_`R3Z$H_s85ZXPY{Zs&pYV>L~CIok!KhXjo((?iTg{{sS^ zLy5pEw*={{0=!vR*V942kQzM!%Y)=Rykfp2F_-x`Y-NwJH|4x+4+q1CFH|uF|3P|_ zaVY-Ybn5iUNir(mnFQejz|RS9JtRhhTc!>|*0vZx?{oD;9ttXo5Po{h*;LJcoFEyh z`>3XCPMfbc1z^Q@!$8{cBd{Bmfko(fp%g*r&zI8tu|fC`=0{Z8;q!rFoeD%6Sjbq?e>VZ_E9v%Ys|qL?f(A9AxW^NdE^J7L!zqCX zRKBm#Fwm-1vkWIB9x|26+*BAgUcZ~-uWItZR)`>EN)ZKs9E`!T#)t!%W9L1YV>&TV z6(?MBeEOq>&RczOiqD^*B2MyG;PQf3AnQL%9T_?NEX`EIThYWqxfFGUk|Ku_N;Po9 zTA)fIZ%FwFhSUPhO3p9^!MmjZjEMk@6-}M(evhI=iAd(<@c5_mda`uw+~!f2x8S|2^%QL zsJvdQt0h_*+`oEvo;6)vxVI^K4(^wrYbvJk>7F}hoUF*p0kL98;3L+#0~W4IP+z|^ z0)!NT=@xGhdHNJd{#ZWbP&X`pfY|5x7&Pg-T7+d#el2X3vZ-+f(cr3 zBaIRRe!5v8x6KozwuXYTJsnvaKnZ1f)JIq=(^GHQ>_hIG&V>6Gf4WiY3*Ps`Up+Kk z`~YORbaM+q*pp3J4{ARz`I>Tdy0H)_@wCO|fY8u7khNV-Lm4Q_20`F+_zd_T3on3p z^!zXD*Vdh(9Z#+|%@HLM$mS@Q-_KxQcJwFF6tdQcEZO4Q(*jOq^}ifce>G9f3N zFkqnLn5>&{fDuclFk>HyipjcxhRV8nP%}Z!6`g-~NR*NDMBpF|)&KucWu`1Q^Se=Y zQ;Hk<^M*q|_tl!sCrA!H!wsM@LPSG=i8Xn1`mns!!RPt0_(BZaI>Wm$B;H~)5h#sv zfbUw8B5$6#q{vtGKrr(EJI_&>)%b?l-knrWQ9(ATnDm;e6p5OA#AuK>Ap-Dz4^77^ zDtgk-{T&&b7TgvX-zg zJ@%lc&0BGovBbv=6mwvtBcFVM?| z7d%Y(x_Eo9?kS`B`16g{q(%5&vy&t{_?o{LJB;w9lXlC5&l_JWH`P`D{wq*Yb)*(NiTJ1oMCGd{fw!p^=%K>WX ze#4k@UDp^DMV_)^b>YuVXXhCG67*-uTn*Qt*UnQg-{OxJcfI+CUCJ^P(Lik}C`f%J z$0eIWMOY9e$w9b-{PVH3WAVhwE>&7=IzN+wvPlP9UH?+f9O;T(=IUK{{hW(V-7k;B zm?`1wyUc{5y^l#XkwIL-nyT0entQpHAgiTV2wL)_hxbYT7alqyj+7hbiZ=LukUROt zo)l!M(ChHQ1 z`C!kEC#A`Di!YyYCnfBgN9Giz=vVfiFIA$>8lSvp=@pD^hF8< z?6;KXdR$=u1Z5mp5Be8^RrF;d(7J|{LD(rv%*KYow0!?X-<96Y$TW0QDgmue(5@RH zPavodF9%uOzlAbL6lLKUC3FA-s$Cn7oS%C{B|R*C**j3u_6Sf>tfnKE_qx`EzY0AG zk`_bpp&)|;rfmYG?M6#bmZME*8PHohPdW^oVH}!{2!Z&K%>3?bJ_3Ehw^WY;EM~eSP?M+Q;xVXbn+JY4vhU-8g*KYS?!c)D z1WrxSVee8}I$YNLq8>j~CT1pacZET5B!l9?P_Pdl1N-nTsb7e~0qnySMb39Gf?rKp z>-HYLKHxE;%SZ0mHtlrFiffZsqbX4>zY%OJyiAVV9;7390J*3gWK0pt9)aLHC>_@K zO87t3gHOV;K>hx5;)IqUla->`R1QD}T~*E4wG|;Jaoa7bdafNj?|?k2ze9bZT83J`o=$O1?M-( z9P(X*hw5Zf#X|y97{c{$h~nL&Gw*Q+-G?@0Q4?W|E)RE+(2) zG6;37Wj!IA3}t6hqhTkyJls%Pp>?nSHf2#$VBK9F7?gQvT`jAM959rvG%f9F{}rVc zYWAA-kUVe5?+*2@Yf3EC$#Vz^ANVgURcNUb{!AdgX3BFP`TZr`^`2DT)+jQB$JBY= z8kRSk7!-HMwx55Qpg5StFT&mzR{Q0Tf*vnDplqu!xW;WzzK1w2Vk}Y&Uf?PR?|5%#4ciU7KvW$;|kZCQ1Q41*~ zf1SQ|pj_O-Yk&psR#o9984K39nV6n4Qg^Ar^~sY3_?X71FVHK7mp#;+UA(Jz$0?)n zruT$49@@IK@oBh_h8TGP?>|tvE~{!dot~3tthiQ0T|0nq&bw!m+putv zVNp52w!uMZVSUF29%*V^8k5NkttRKNDL`rx0WHZAC|Y(ROB}9g7!%hI-R^ros9LOwm{NW@ZbJ^3YgKTC3#52 zHXRF;VkvmG-W1MFQpz@F%3Hyht{=%HElNHxnWlru)ozLg3)8JK6q9I3?*j`HYRTp> zNtqfY7c5L|PHXnd>qSTnrde33%zr-6m5)Bq;bLB(}dy3 z@?1UC`RVvE@6mgB{geh9lkiZ05Ufj-zBud1ppkHp(>}@tno3DioHaMNBz_qjG`+|J z8MV5ybocT!A;|fU01+^;Hk_i%4$-gx^)GLV*Cq!d$+ZvEwMhiG=}Z;G!A-i5XF?nS z0#nNrrJ%WjWs_cu(c9700~W52VCRemFiArWmzw5_a-oqP)L>Um=&_K}6$1Z$LO3zF zp9UVQtJC)w@j?9KingBP%5^&=?S{~js^}V!w^gXu;=>09O;PlMz9-vEC}0<1^4H|a zK-~5i+`8DeEhJt(dJ@EKqwF90Qa>_2lEVz!k9+{D7YavG*02goBefuJ87QaAre^bi512$A&;NTwS=xnF0?kE$&U({FGb_z_^=fvbik2e`w zX+30rUA(h*<0;zwxA}z=I82#xIF+ebtJkKSz?>CN))}QI>|qkg!==$eOY>^Nh+mgA z<=&vYEmnV&8i`p8f^O;5$T9>zi~kMX1Quh~{S8Tj9{hmsw>z!fZwPPJ(CZ0Y{cBm^ z$E*u$GCw~>BH|lZs@j2_xhgjv(u&Vk>r2(Gqsl4v<%AjwX$~a|sc06Np%e|k4}N^l zbE-ZnV?}-$E;H<%GC}dmYtK&)yV<#smb~GHV?Oj`1Tf;MylccZ~Ys^yB$m5>(?W#6H`p|vsGdPcSz%Dzjz1WTWiz($rgWhk^8 zefo*ur#w!U%Utdu753btWVtnPoHmm83HALa9E!zbl=cS6PLHFs>Y26TC^-ct66B+F zn=VyQg_g|VN5E|w%}6S?X<=v3!3t2VKkCwV(GsZvN#hGLa>MG^i8!}|hED>_fAGpL z1hn8NWdWtxEEGiBi6dL5?;Qdpu|uf#>03-rDiEsTT%|>RT@l!jjc$WQQ&7&6@al?m zz*DFM;E(h!IohTF(H55sRC5gjrVCEtvHgTy3OIo=*dQ^>2~O&ms~ z1m-{T^3|Wh<92fSq0$_L+pXa;#B2Z3?)rH}W;~QYBWIul*BBMk@Lxch@eJf zb?r^oXaxG)wOLJC7ric=@m-O;ylKg7;jT@VC7Tyi#k@1+J&it$UE#YtQLCJ@OR#gj zX>49h<;+X~7-(unD-WjkLz4OEh}B9Pu|tHJyLI*4Nz25J*RGyqWV{em(9E9g9y6| z5!Bv>;=tPrwEHSSJY|b1i4kj$(t!8}!T)sy?=q;v$6N3dI~{ypV1!wR`}X&8^rvV| z`3BggXpO0w_cyHu7AOMDVB~-VFL#NBO2sXNffM)PIN7t{ejF&_-adU-62UUl&*}H5 z+9^nKeXL*du&*jar8m~xYB;!U! zIe`b(Y_L+7k?$ZC;tT+8OC@{cH&q&CHR|u3m|loAp8Gi^Vk!xdmuxz1%AtgcawrN! zQkpEJL|$l$ysYRrz`5OdH3YoUh@@Sxd} z6g`BJi&U~HRWCk98`wDpGi>WIu^-5*1_#`3MZE>SowXJ19HuT6BkSea&-W(m;f*Z9 z-W&Azvw}@oJdy}}kRtzEK~!r~18utGLZo^=YpIC=JS3BklM`?9=@uX`nROxT;SecY zTq9$yE_S~)e7!W17dG@u-x*PNK7Z(hjN_igFO67>e2#Xsc`jt?wPjs!K|SZ?_2Eys zc6JS8sngYrtuFLwcAT^o^z}EJf|gjLJ!pER`mk40KqGwWo87$%4Bv ze?*@-zT)umAGBuI?s~d&>-Wi7ksTN;8lzQ`*#Si3^c84f;AVpt1rYH_@Mw^1}50Pz!7uv%OJ@ssr^MHUYPmxMJb3I^R9MPBfcCXxmW)f&2)_k3i9 zgheP}rDLx(lXyYe-7bBx5xN87ab1DPf^!h}KJYPdHB2J+?t#7@%H`FmVp9Wh;PAlq z4q0IB?VtzEAW`A8J*(Xmpk?7Bkf`v8O+x7no)xVa-yd^~>)x7r8teXXCgJO7OMA)% znD;uVx{EFZ!qoJ}4*!0{@CB!Gf?}ZP47*qvnwyZpI9}p!lnCK~u{ zmg?Nyt-vtjpgYlR;3vr&j;VEEPJD3NOb=A>~SWG4OF-19KU88(2xV3&t3 zg;EMH%Olcbp>`lvJ!jXH6P}v7mqTnN7Jo#m%k_?)T24wB$Q@ahpyTr7N$ejnXMSIC zc*PIPXaC3Q>8`Ci7pzw`1=>8-2i{GxoOnPNvI5V4OR|4IW#ISVex_1T*}Z)4cjv2j zUEFzf!-5+ztD?7itWYueSbaCCGBt@L|t4Sl?8a$4BaO zz|)u+9zJjuF?AdYoW&U8g8mIJCSv5?Z%bhbc^-GXw|-|rxp zhN=+Xk|u4(|AE#u^7NuZ=^$_AG8G%5oU!azto9v>WU5wg+x0)TH?@_n){ z!k3GrAn;0l0 z#Vl7@7pih~G4|FlA81bvm|H>hmR(Ak!|2>~=p$i_stU@|1q};9EgfCbFcM{L**);P zrw}PFvU)2#WsGOAHx+iRPwuJqyPPz+aq@mA%0fH;K+x)YW92~E_r2~@m-#*)x`N)xO0XT6;Z3*PK3wY_8AU)weU!bYEc%KY9`FdeHJxEme~zd#30%k@-&S02?pl*ps)Zh+k9>fc?9DGXqrzN@OWy+LGm3I+* zPA7dC76wob4Yn2<(CaP-_d}0$!Rk&_19@0wV_wO$v35 zqN8<(|L>vZ*Tp~eetF91Tl~q!xnH2apWdXJVVCeQXJlzXRJ@5AEmV@ddHAWCiK&_z zXo`?px_qQY&^Wh~@$g8L20C*DS%T8O@6ZPiwJA6ku>_Vj{NJ00LPUH&v+#{6+As=I zLJ)?SHS`Zl{Tv5x-1Qx6R2sNo3RUUp4y-C;O^!AbNo@RIi^*`>a7;pll5A`03l+@1>tOO9BFjsih5C2D{5mcV?cdcoLxC{h{MB#D!E!3+4xAr4q&pMX^s zj#8kZIy0#x1gLF+O5#&_?U-tD+8dNCiT=kmYW>^500=Nf z@oJd9N&`%l{wXSbG-lj6Ulq7Kit9wpvlnC&24t^?%w^UXbbR{8q>Z&>khAeXg|@^L3{whU}(IT zhp*SGQsBU3OR(5^$jz9#9h`n)j)@xD5jPKBc%V;9CuKFfIh~||l2s3Mcbe`dX;efk zmgo{)x~;Lrosso94ZXo64Vv^hzc94s7#HRT7a?WUA>0PY;s3REtualVVR#8K#F@d2 zasEKsEsGMzLZi+Vx%9*=3-J;gBid|08%0EeP!ze@o>Luji?G2aLENC!OSGb5C2kzB z?Kz^uS_G;AL|kuDptev-X=yp_x$J}N2RNt8w!dG#oaE$u=Y8MjeV*@qyrpR0L5#cD zJ|BIps*io1K7T2Fc=tN=bX!eV)4se_1+hP+>5W@P=a&8%Aj>_`2D&pg@rr6@5D>Qy zk_geU(FDSfkPFI}c&g}m5Y(gdk>39f{?ZQu)=YR+3&IU86gI*;gplBf2ka3GgCc~xMlW8!J+ka%h`TCaFXc+N9q92-2;JH_6;F^;^u7S zTtDHp4gvPvt@BOZ7LZtfYX!G(muPYE7Wy9eoExtVL;D&?u~8-`SJ3TAMD1K6e3dJ~ zEV`RBC0hu${&XaJ%`L5YzGZW}o;J;j=Q4LJ&0e`~%}{3|AcmU++Z48-(+)D?7!R$?UK2eu4-uh!Xx1Q3SzqY=k1a8d?hMuZrC26$9tmAvZqhpU>~KjzeT^_a;Tr-ZCNrd7|97!Rm&CD?(gHi`*}<4PZ%Q860#hc^PmRyWd_=%=){0B(;_c`NwIuJ^J{o;^Cb@8(o58*a~K zX0BW_5c*76p`sSvuVNb+J&OOXHXxlc4NVLX4`SS&6Hwb^BrB9AG4GesXCxDCy7OFf zi!Ll+^j8P4i3(x<7&qO0K`jlM@lY)!85E6sQ9g;LS!PyL>T#O%(nMpecKU$;Cak!| zv4;!$PAScfp=yX3kHK7@TQFB43wEv<*}#<=$|6atj909Rj)w2Th&@ZB8IH})pd-WC z9#5^=8YO0Yx;#&rC1E7UFYU!m8*#tgk9j%LP?vxSQW!E4iycPQP{8_G&y1JPVmk$S z(hisNd+exMB@FhmHA4mH?RJKxgG0aN2+4{V#G6qi?Rp1e&UraTjB3?kE~DD~{GMHy z@9AbAq0XOe6z!vZXi_CHFNM#(ByXtW^yT??5dSb-shU8vsBuiOEMpaAMaJ=-J;fT zwVthFzc@vd|7;U#85@DTS67G-j~wz1pt9$c>z@^w>LyBd^j2tW%eSTm`wlOw5n=$cexC Date: Thu, 12 Mar 2015 15:46:17 -0700 Subject: [PATCH 05/11] DTLS working. The only thing that is missing is a signature to detect the protocol (it has no well-known port). Reassembly is kind of fidgety - at the moment we only support re-assembling one simultaneous message per direction (which looking at our test-traffic might not be a problem). And I am not quite sure if I got all cases correct... But - it works :) --- scripts/base/protocols/ssl/consts.bro | 7 + src/analyzer/protocol/ssl/CMakeLists.txt | 2 +- src/analyzer/protocol/ssl/DTLS.cc | 39 ++++- src/analyzer/protocol/ssl/DTLS.h | 9 +- src/analyzer/protocol/ssl/SSL.cc | 3 + src/analyzer/protocol/ssl/dtls-analyzer.pac | 148 ++++++++++++++++++ src/analyzer/protocol/ssl/dtls-protocol.pac | 40 +++-- src/analyzer/protocol/ssl/dtls.pac | 10 +- src/analyzer/protocol/ssl/ssl-defs.pac | 11 +- src/analyzer/protocol/ssl/ssl-protocol.pac | 4 +- .../protocol/ssl/tls-handshake-protocol.pac | 49 ++++-- .../scripts.base.protocols.ssl.dtls/ssl.log | 10 ++ .../scripts.base.protocols.ssl.dtls/x509.log | 10 ++ .../scripts/base/protocols/ssl/dtls.test | 5 + 14 files changed, 312 insertions(+), 35 deletions(-) create mode 100644 testing/btest/Baseline/scripts.base.protocols.ssl.dtls/ssl.log create mode 100644 testing/btest/Baseline/scripts.base.protocols.ssl.dtls/x509.log create mode 100644 testing/btest/scripts/base/protocols/ssl/dtls.test diff --git a/scripts/base/protocols/ssl/consts.bro b/scripts/base/protocols/ssl/consts.bro index 3d115419d4..05559ee5d0 100644 --- a/scripts/base/protocols/ssl/consts.bro +++ b/scripts/base/protocols/ssl/consts.bro @@ -6,6 +6,11 @@ export { const TLSv10 = 0x0301; const TLSv11 = 0x0302; const TLSv12 = 0x0303; + + const DTLSv10 = 0xFEFF; + # DTLSv11 does not exist + const DTLSv12 = 0xFEFD; + ## Mapping between the constants and string values for SSL/TLS versions. const version_strings: table[count] of string = { [SSLv2] = "SSLv2", @@ -13,6 +18,8 @@ export { [TLSv10] = "TLSv10", [TLSv11] = "TLSv11", [TLSv12] = "TLSv12", + [DTLSv10] = "DTLSv10", + [DTLSv12] = "DTLSv12" } &default=function(i: count):string { return fmt("unknown-%d", i); }; ## TLS content types: diff --git a/src/analyzer/protocol/ssl/CMakeLists.txt b/src/analyzer/protocol/ssl/CMakeLists.txt index fab0d30f07..f69b7354e3 100644 --- a/src/analyzer/protocol/ssl/CMakeLists.txt +++ b/src/analyzer/protocol/ssl/CMakeLists.txt @@ -6,7 +6,7 @@ include_directories(BEFORE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DI bro_plugin_begin(Bro SSL) bro_plugin_cc(SSL.cc Plugin_SSL.cc) bro_plugin_bif(events.bif) -bro_plugin_pac(tls-handshake.pac tls-handshake-protocol.pac tls-handshake-analyzer.pac) +bro_plugin_pac(tls-handshake.pac tls-handshake-protocol.pac tls-handshake-analyzer.pac ssl-defs.pac) bro_plugin_pac(ssl.pac ssl-dtls-analyzer.pac ssl-analyzer.pac ssl-dtls-protocol.pac ssl-protocol.pac ssl-defs.pac) bro_plugin_end() diff --git a/src/analyzer/protocol/ssl/DTLS.cc b/src/analyzer/protocol/ssl/DTLS.cc index 7c49dba439..c90e414031 100644 --- a/src/analyzer/protocol/ssl/DTLS.cc +++ b/src/analyzer/protocol/ssl/DTLS.cc @@ -5,28 +5,61 @@ #include "events.bif.h" +#include "dtls_pac.h" +#include "tls-handshake_pac.h" + using namespace analyzer::dtls; DTLS_Analyzer::DTLS_Analyzer(Connection* c) : analyzer::Analyzer("DTLS", c) { interp = new binpac::DTLS::SSL_Conn(this); - fprintf(stderr, "Instantiated :)\n"); + handshake_interp = new binpac::TLSHandshake::Handshake_Conn(this); } DTLS_Analyzer::~DTLS_Analyzer() { delete interp; + delete handshake_interp; } void DTLS_Analyzer::Done() { - Analyzer::Done(); + Analyzer::Done(); + interp->FlowEOF(true); + interp->FlowEOF(false); + handshake_interp->FlowEOF(true); + handshake_interp->FlowEOF(false); } void DTLS_Analyzer::DeliverPacket(int len, const u_char* data, bool orig, uint64 seq, const IP_Hdr* ip, int caplen) { Analyzer::DeliverPacket(len, data, orig, seq, ip, caplen); - fprintf(stderr, "Delivered packet :)\n"); interp->NewData(orig, data, data + len); } + +void DTLS_Analyzer::EndOfData(bool is_orig) + { + Analyzer::EndOfData(is_orig); + interp->FlowEOF(is_orig); + handshake_interp->FlowEOF(is_orig); + } + + +void DTLS_Analyzer::SendHandshake(uint8 msg_type, uint32 length, const u_char* begin, const u_char* end, bool orig) + { + try + { + handshake_interp->NewData(orig, (const unsigned char*) &msg_type, (const unsigned char*) &msg_type + 1); + uint32 host_length = htonl(length); + // the parser inspects a uint24 - since it is big-endian, it should be ok to just skip + // the first byte of the uint32. Since we get the data from an uint24 from the dtls-parser, this should + // always yield the correct result. + handshake_interp->NewData(orig, (const unsigned char*) &host_length + 1, (const unsigned char*) &host_length + sizeof(host_length)); + handshake_interp->NewData(orig, begin, end); + } + catch ( const binpac::Exception& e ) + { + ProtocolViolation(fmt("Binpac exception: %s", e.c_msg())); + } + } diff --git a/src/analyzer/protocol/ssl/DTLS.h b/src/analyzer/protocol/ssl/DTLS.h index c45a311c8c..6611a6974e 100644 --- a/src/analyzer/protocol/ssl/DTLS.h +++ b/src/analyzer/protocol/ssl/DTLS.h @@ -4,7 +4,10 @@ #include "events.bif.h" #include "analyzer/protocol/udp/UDP.h" -#include "dtls_pac.h" + +namespace binpac { namespace DTLS { class SSL_Conn; } } + +namespace binpac { namespace TLSHandshake { class Handshake_Conn; } } namespace analyzer { namespace dtls { @@ -17,6 +20,9 @@ public: virtual void Done(); virtual void DeliverPacket(int len, const u_char* data, bool orig, uint64 seq, const IP_Hdr* ip, int caplen); + virtual void EndOfData(bool is_orig); + + void SendHandshake(uint8 msg_type, uint32 length, const u_char* begin, const u_char* end, bool orig); static analyzer::Analyzer* Instantiate(Connection* conn) @@ -24,6 +30,7 @@ public: protected: binpac::DTLS::SSL_Conn* interp; + binpac::TLSHandshake::Handshake_Conn* handshake_interp; }; } } // namespace analyzer::* diff --git a/src/analyzer/protocol/ssl/SSL.cc b/src/analyzer/protocol/ssl/SSL.cc index 71b7511716..d571439f19 100644 --- a/src/analyzer/protocol/ssl/SSL.cc +++ b/src/analyzer/protocol/ssl/SSL.cc @@ -30,12 +30,15 @@ void SSL_Analyzer::Done() interp->FlowEOF(true); interp->FlowEOF(false); + handshake_interp->FlowEOF(true); + handshake_interp->FlowEOF(false); } void SSL_Analyzer::EndpointEOF(bool is_orig) { tcp::TCP_ApplicationAnalyzer::EndpointEOF(is_orig); interp->FlowEOF(is_orig); + handshake_interp->FlowEOF(is_orig); } void SSL_Analyzer::DeliverStream(int len, const u_char* data, bool orig) diff --git a/src/analyzer/protocol/ssl/dtls-analyzer.pac b/src/analyzer/protocol/ssl/dtls-analyzer.pac index 139597f9cb..f4c2df9e3f 100644 --- a/src/analyzer/protocol/ssl/dtls-analyzer.pac +++ b/src/analyzer/protocol/ssl/dtls-analyzer.pac @@ -1,2 +1,150 @@ +refine connection SSL_Conn += { + + %member{ + + struct message_info { + uint64 message_first_sequence; // the minumum dtls sequence number for this handshake fragment + bool first_sequence_seen; // did we actually see the fragment with the smallest number + uint64 message_last_sequence; // the mazimum dtls sequence number for this handshake fragment + uint16 message_handshake_sequence; // the handshake sequence number of this handshake (to identify) + uint32 message_length; // data length of this handshake (data in buffer) + uint32 message_sequence_seen; // a bitfield that shows which sequence numbers we already saw, offset from first_seq. + u_char* buffer; + } server, client; + %} + + %init{ + memset(&server, 0, sizeof(server)); + memset(&client, 0, sizeof(client)); + %} + + %cleanup{ + delete [] server.buffer; + delete [] client.buffer; + %} + + function proc_dtls(pdu: SSLRecord, sequence: uint64): bool + %{ + //fprintf(stderr, "Type: %d, sequence number: %d, epoch: %d\n", ${pdu.content_type}, sequence, ${pdu.epoch}); + + return true; + %} + + function proc_handshake(pdu: SSLRecord, rec: Handshake): bool + %{ + uint32 foffset = to_int()(${rec.fragment_offset}); + uint32 flength = to_int()(${rec.fragment_length}); + uint32 length = to_int()(${rec.length}); + uint64 sequence_number = to_int()(${pdu.sequence_number}); + //fprintf(stderr, "Handshake type: %d, length: %u, seq: %u, foffset: %u, flength: %u\n", ${rec.msg_type}, to_int()(${rec.length}), ${rec.message_seq}, to_int()(${rec.fragment_offset}), to_int()(${rec.fragment_length})); + + if ( foffset == 0 && length == flength ) + { + //fprintf(stderr, "Complete fragment, forwarding...\n"); + bro_analyzer()->SendHandshake(${rec.msg_type}, length, ${rec.data}.begin(), ${rec.data}.end(), ${pdu.is_orig}); + return true; + } + + // if we fall through here, the message has to be reassembled. Let's first get the right info record... + message_info* i; + if ( ${pdu.is_orig} ) + i = &client; + else + i = &server; + + if ( length > MAX_DTLS_HANDSHAKE_RECORD ) + { + bro_analyzer()->ProtocolViolation(fmt("DTLS record length %u larger than allowed maximum.", length)); + return true; + } + + if ( i->message_handshake_sequence != ${rec.message_seq} || i->message_length != length || i->buffer == 0 ) + { + // cannot resume reassembling. Let's abandon the current data and try anew... + delete [] i->buffer; + memset(i, 0, sizeof(message_info)); + i->message_handshake_sequence = ${rec.message_seq}; + i->message_length = length; + i->buffer = new u_char[length]; + // does not have to be the first sequence number - we cannot figure that out at this point. If it is not, + // we will fix that later... + i->message_first_sequence = sequence_number; + } + + // if we arrive here, we are actually ready to resume. + if ( i->message_first_sequence > sequence_number ) + { + if ( i->first_sequence_seen ) + { + bro_analyzer()->ProtocolViolation("Saw second and different first message fragment for handshake."); + return true; + } + // first sequence number was incorrect, let's fix that. + uint64 diff = i->message_first_sequence - sequence_number; + i->message_sequence_seen = i->message_sequence_seen << diff; + i->message_first_sequence = sequence_number; + } + + // if we have offset 0, we know the smallest number... + if ( foffset == 0 ) + i->first_sequence_seen = true; + + // check if we already saw the message + if ( ( i->message_sequence_seen & ( 1 << (sequence_number - i->message_first_sequence) ) ) != 0 ) + return true; // do not handle same message fragment twice + + // copy data from fragment to buffer + if ( ${rec.data}.length() != flength ) + { + bro_analyzer()->ProtocolViolation(fmt("DTLS handshake record length does not match packet length")); + return true; + } + + if ( foffset + flength > length ) + { + bro_analyzer()->ProtocolViolation(fmt("DTLS handshake fragment trying to write past end of buffer")); + return true; + } + + // store that we handled fragment + i->message_sequence_seen |= 1 << (sequence_number - i->message_first_sequence); + memcpy(i->buffer + foffset, ${rec.data}.data(), ${rec.data}.length()); + + //fprintf(stderr, "Copied to buffer offset %u length %u\n", foffset, ${rec.data}.length()); + + // store last fragment information if this is the last fragment... + + // check if we saw all fragments so far. If yes, forward... + if ( foffset + flength == length ) + i->message_last_sequence = sequence_number; + + if ( i->message_last_sequence != 0 && i->first_sequence_seen ) + { + uint64 total_length = i->message_last_sequence - i->message_first_sequence; + if ( total_length > 32 ) + { + bro_analyzer()->ProtocolViolation(fmt("DTLS Message fragmented over more than 32 pieces. Cannot reassemble.")); + return true; + } + + if ( ( ~(i->message_sequence_seen) & ( ( 1<<(total_length+1) ) -1 ) ) == 0 ) + { + //fprintf(stderr, "ALl fragments here. Total length %u\n", length); + bro_analyzer()->SendHandshake(${rec.msg_type}, length, i->buffer, i->buffer + length, ${pdu.is_orig}); + } + } + + + return true; + %} +}; + +refine typeattr SSLRecord += &let { + proc: bool = $context.connection.proc_dtls(this, to_int()(sequence_number)); +}; + +refine typeattr Handshake += &let { + proc: bool = $context.connection.proc_handshake(rec, this); +}; diff --git a/src/analyzer/protocol/ssl/dtls-protocol.pac b/src/analyzer/protocol/ssl/dtls-protocol.pac index 94cddf9cbc..6faa191d18 100644 --- a/src/analyzer/protocol/ssl/dtls-protocol.pac +++ b/src/analyzer/protocol/ssl/dtls-protocol.pac @@ -10,14 +10,27 @@ type DTLSPDU(is_orig: bool) = record { type SSLRecord(is_orig: bool) = record { content_type: uint8; version: uint16; +# the epoch signalizes that a changecipherspec message has been received. Hence, everything with +# an epoch > 0 should be encrypted epoch: uint16; sequence_number: uint48; length: uint16; - rec: PlaintextRecord(this)[] &length=length; -# data: bytestring &restofdata &transient; -} &byteorder = bigendian, - &let { - parse : bool = $context.connection.proc_dtls(this, to_int()(sequence_number)); + cont: case valid of { + true -> rec: RecordText(this)[] &length=length; + false -> swallow: bytestring &restofdata; + }; +} &byteorder = bigendian, &let { +# Do not parse body if packet version invalid + valid: bool = $context.connection.dtls_version_ok(version); +}; + +type RecordText(rec: SSLRecord) = case rec.epoch of { + 0 -> plaintext : PlaintextRecord(rec); + default -> ciphertext : CiphertextRecord(rec); +}; + +refine casetype PlaintextRecord += { + HANDSHAKE -> handshake : Handshake(rec); }; type Handshake(rec: SSLRecord) = record { @@ -26,15 +39,22 @@ type Handshake(rec: SSLRecord) = record { message_seq: uint16; fragment_offset: uint24; fragment_length: uint24; + data: bytestring &restofdata; } refine connection SSL_Conn += { - function proc_dtls(pdu: SSLRecord, sequence: uint64): bool - %{ - fprintf(stderr, "Type: %d, sequence number: %d, epoch: %d\n", ${pdu.content_type}, sequence, ${pdu.epoch}); + function dtls_version_ok(version: uint16): uint16 + %{ + switch ( version ) { + case DTLSv10: + case DTLSv12: + return true; - return true; - %} + default: + bro_analyzer()->ProtocolViolation(fmt("Invalid version in DTLS connection. Packet reported version: %d", version)); + return false; + } + %} }; diff --git a/src/analyzer/protocol/ssl/dtls.pac b/src/analyzer/protocol/ssl/dtls.pac index 50424f0d8c..b08dd61f8f 100644 --- a/src/analyzer/protocol/ssl/dtls.pac +++ b/src/analyzer/protocol/ssl/dtls.pac @@ -5,14 +5,21 @@ %extern{ #include "events.bif.h" + +namespace analyzer { namespace dtls { class DTLS_Analyzer; } } +typedef analyzer::dtls::DTLS_Analyzer* DTLSAnalyzer; + +#include "DTLS.h" %} +extern type DTLSAnalyzer; + analyzer DTLS withcontext { connection: SSL_Conn; flow: DTLS_Flow; }; -connection SSL_Conn(bro_analyzer: BroAnalyzer) { +connection SSL_Conn(bro_analyzer: DTLSAnalyzer) { upflow = DTLS_Flow(true); downflow = DTLS_Flow(false); }; @@ -21,7 +28,6 @@ connection SSL_Conn(bro_analyzer: BroAnalyzer) { %include dtls-protocol.pac flow DTLS_Flow(is_orig: bool) { -# flowunit = SSLRecord(is_orig) withcontext(connection, this); datagram = DTLSPDU(is_orig) withcontext(connection, this); } diff --git a/src/analyzer/protocol/ssl/ssl-defs.pac b/src/analyzer/protocol/ssl/ssl-defs.pac index c29bbcbabe..aefc69a81c 100644 --- a/src/analyzer/protocol/ssl/ssl-defs.pac +++ b/src/analyzer/protocol/ssl/ssl-defs.pac @@ -71,6 +71,8 @@ function version_ok(vers : uint16) : bool case TLSv10: case TLSv11: case TLSv12: + case DTLSv10: + case DTLSv12: return true; default: @@ -86,6 +88,9 @@ using std::string; #include "events.bif.h" %} +# a maximum of 100k for one record seems safe +let MAX_DTLS_HANDSHAKE_RECORD: uint32 = 100000; + enum ContentType { CHANGE_CIPHER_SPEC = 20, ALERT = 21, @@ -106,7 +111,11 @@ enum SSLVersions { SSLv30 = 0x0300, TLSv10 = 0x0301, TLSv11 = 0x0302, - TLSv12 = 0x0303 + TLSv12 = 0x0303, + + DTLSv10 = 0xFEFF, +# DTLSv11 does not exist. + DTLSv12 = 0xFEFD }; enum SSLExtensions { diff --git a/src/analyzer/protocol/ssl/ssl-protocol.pac b/src/analyzer/protocol/ssl/ssl-protocol.pac index a90bd03868..7f9799e0bc 100644 --- a/src/analyzer/protocol/ssl/ssl-protocol.pac +++ b/src/analyzer/protocol/ssl/ssl-protocol.pac @@ -42,10 +42,8 @@ refine casetype PlaintextRecord += { V2_SERVER_HELLO -> v2_server_hello : V2ServerHello(rec); }; +# Handshakes are parsed by the handshake analyzer. type Handshake(rec: SSLRecord) = record { -# msg_type: uint8; -# length: uint24; -# data: bytestring &length=to_int()(length); data: bytestring &restofdata; }; diff --git a/src/analyzer/protocol/ssl/tls-handshake-protocol.pac b/src/analyzer/protocol/ssl/tls-handshake-protocol.pac index 296df5fb9d..b24352d099 100644 --- a/src/analyzer/protocol/ssl/tls-handshake-protocol.pac +++ b/src/analyzer/protocol/ssl/tls-handshake-protocol.pac @@ -6,6 +6,7 @@ enum HandshakeType { HELLO_REQUEST = 0, CLIENT_HELLO = 1, SERVER_HELLO = 2, + HELLO_VERIFY_REQUEST = 3, # DTLS SESSION_TICKET = 4, # RFC 5077 CERTIFICATE = 11, SERVER_KEY_EXCHANGE = 12, @@ -30,20 +31,21 @@ type HandshakeRecord(is_orig: bool) = record { } &length=(to_int()(msg_length) + 4); type Handshake(rec: HandshakeRecord) = case rec.msg_type of { - HELLO_REQUEST -> hello_request : HelloRequest(rec); - CLIENT_HELLO -> client_hello : ClientHello(rec); - SERVER_HELLO -> server_hello : ServerHello(rec); - SESSION_TICKET -> session_ticket : SessionTicketHandshake(rec); - CERTIFICATE -> certificate : Certificate(rec); - SERVER_KEY_EXCHANGE -> server_key_exchange : ServerKeyExchange(rec); - CERTIFICATE_REQUEST -> certificate_request : CertificateRequest(rec); - SERVER_HELLO_DONE -> server_hello_done : ServerHelloDone(rec); - CERTIFICATE_VERIFY -> certificate_verify : CertificateVerify(rec); - CLIENT_KEY_EXCHANGE -> client_key_exchange : ClientKeyExchange(rec); - FINISHED -> finished : Finished(rec); - CERTIFICATE_URL -> certificate_url : bytestring &restofdata &transient; - CERTIFICATE_STATUS -> certificate_status : CertificateStatus(rec); - default -> unknown_handshake : UnknownHandshake(rec, rec.is_orig); + HELLO_REQUEST -> hello_request : HelloRequest(rec); + CLIENT_HELLO -> client_hello : ClientHello(rec); + SERVER_HELLO -> server_hello : ServerHello(rec); + HELLO_VERIFY_REQUEST -> hello_verify_request : HelloVerifyRequest(rec); + SESSION_TICKET -> session_ticket : SessionTicketHandshake(rec); + CERTIFICATE -> certificate : Certificate(rec); + SERVER_KEY_EXCHANGE -> server_key_exchange : ServerKeyExchange(rec); + CERTIFICATE_REQUEST -> certificate_request : CertificateRequest(rec); + SERVER_HELLO_DONE -> server_hello_done : ServerHelloDone(rec); + CERTIFICATE_VERIFY -> certificate_verify : CertificateVerify(rec); + CLIENT_KEY_EXCHANGE -> client_key_exchange : ClientKeyExchange(rec); + FINISHED -> finished : Finished(rec); + CERTIFICATE_URL -> certificate_url : bytestring &restofdata &transient; + CERTIFICATE_STATUS -> certificate_status : CertificateStatus(rec); + default -> unknown_handshake : UnknownHandshake(rec, rec.is_orig); } type HandshakePDU(is_orig: bool) = record { @@ -72,6 +74,10 @@ type ClientHello(rec: HandshakeRecord) = record { random_bytes : bytestring &length = 28; session_len : uint8; session_id : uint8[session_len]; + dtls_cookie: case client_version of { + DTLSv10 -> cookie: ClientHelloCookie(rec); + default -> nothing: bytestring &length=0; + }; csuit_len : uint16 &check(csuit_len > 1 && csuit_len % 2 == 0); csuits : uint16[csuit_len/2]; cmeth_len : uint8 &check(cmeth_len > 0); @@ -82,6 +88,11 @@ type ClientHello(rec: HandshakeRecord) = record { extensions : SSLExtension(rec)[] &until($input.length() == 0); }; +type ClientHelloCookie(rec: HandshakeRecord) = record { + cookie_len : uint8; + cookie : bytestring &length = cookie_len; +}; + ###################################################################### # V3 Server Hello (7.4.1.3.) ###################################################################### @@ -103,6 +114,16 @@ type ServerHello(rec: HandshakeRecord) = record { $context.connection.set_cipher(cipher_suite[0]); }; +###################################################################### +# DTLS Hello Verify Request +###################################################################### + +type HelloVerifyRequest(rec: HandshakeRecord) = record { + version: uint16; + cookie_length: uint8; + cookie: bytestring &length=cookie_length; +}; + ###################################################################### # V3 Server Certificate (7.4.2.) ###################################################################### diff --git a/testing/btest/Baseline/scripts.base.protocols.ssl.dtls/ssl.log b/testing/btest/Baseline/scripts.base.protocols.ssl.dtls/ssl.log new file mode 100644 index 0000000000..cd9d04e020 --- /dev/null +++ b/testing/btest/Baseline/scripts.base.protocols.ssl.dtls/ssl.log @@ -0,0 +1,10 @@ +#separator \x09 +#set_separator , +#empty_field (empty) +#unset_field - +#path ssl +#open 2015-03-12-22-40-14 +#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p version cipher curve server_name resumed last_alert next_protocol established cert_chain_fuids client_cert_chain_fuids subject issuer client_subject client_issuer +#types time string addr port addr port string string string string bool string string bool vector[string] vector[string] string string string string +1425932016.520157 CXWv6p3arKYeMETxOg 192.168.6.86 63721 104.236.167.107 4433 DTLSv10 TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA secp256r1 - F - - T FZi2Ct2AcCswhiIjKe (empty) CN=bro CN=bro - - +#close 2015-03-12-22-40-14 diff --git a/testing/btest/Baseline/scripts.base.protocols.ssl.dtls/x509.log b/testing/btest/Baseline/scripts.base.protocols.ssl.dtls/x509.log new file mode 100644 index 0000000000..290c5bfb49 --- /dev/null +++ b/testing/btest/Baseline/scripts.base.protocols.ssl.dtls/x509.log @@ -0,0 +1,10 @@ +#separator \x09 +#set_separator , +#empty_field (empty) +#unset_field - +#path x509 +#open 2015-03-12-22-40-14 +#fields ts id certificate.version certificate.serial certificate.subject certificate.issuer certificate.not_valid_before certificate.not_valid_after certificate.key_alg certificate.sig_alg certificate.key_type certificate.key_length certificate.exponent certificate.curve san.dns san.uri san.email san.ip basic_constraints.ca basic_constraints.path_len +#types time string count string string string time time string string string count string string vector[string] vector[string] vector[string] vector[addr] bool count +1425932016.611299 FZi2Ct2AcCswhiIjKe 3 E8E48E456C32945F CN=bro CN=bro 1425931873.000000 1457467873.000000 rsaEncryption sha1WithRSAEncryption rsa 2048 65537 - - - - - T - +#close 2015-03-12-22-40-14 diff --git a/testing/btest/scripts/base/protocols/ssl/dtls.test b/testing/btest/scripts/base/protocols/ssl/dtls.test new file mode 100644 index 0000000000..46b74d2b78 --- /dev/null +++ b/testing/btest/scripts/base/protocols/ssl/dtls.test @@ -0,0 +1,5 @@ +# This tests a normal SSL connection and the log it outputs. + +# @TEST-EXEC: bro -r $TRACES/tls/dtls-openssl.pcap %INPUT +# @TEST-EXEC: btest-diff ssl.log +# @TEST-EXEC: btest-diff x509.log From 88beb3127099f24ca0023d437581f25deaac56fb Mon Sep 17 00:00:00 2001 From: Johanna Amann Date: Thu, 12 Mar 2015 16:09:10 -0700 Subject: [PATCH 06/11] Only force logging of SSL if it actually was the SSL analyzer that failed. --- scripts/base/protocols/ssl/main.bro | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/base/protocols/ssl/main.bro b/scripts/base/protocols/ssl/main.bro index d2b0332756..2b448fec6c 100644 --- a/scripts/base/protocols/ssl/main.bro +++ b/scripts/base/protocols/ssl/main.bro @@ -282,6 +282,6 @@ event protocol_confirmation(c: connection, atype: Analyzer::Tag, aid: count) &pr event protocol_violation(c: connection, atype: Analyzer::Tag, aid: count, reason: string) &priority=5 { - if ( c?$ssl ) + if ( c?$ssl && atype == Analyzer::ANALYZER_SSL ) finish(c, T); } From 90bc5add6e27b687d290e14799b06aec6d6bfff6 Mon Sep 17 00:00:00 2001 From: Johanna Amann Date: Wed, 18 Mar 2015 11:15:18 -0700 Subject: [PATCH 07/11] Make the plugin structure more... legal. --- src/analyzer/protocol/ssl/CMakeLists.txt | 6 +---- .../protocol/ssl/{Plugin_SSL.cc => Plugin.cc} | 4 ++- src/analyzer/protocol/ssl/Plugin_DTLS.cc | 26 ------------------- 3 files changed, 4 insertions(+), 32 deletions(-) rename src/analyzer/protocol/ssl/{Plugin_SSL.cc => Plugin.cc} (71%) delete mode 100644 src/analyzer/protocol/ssl/Plugin_DTLS.cc diff --git a/src/analyzer/protocol/ssl/CMakeLists.txt b/src/analyzer/protocol/ssl/CMakeLists.txt index f69b7354e3..7f4efdece1 100644 --- a/src/analyzer/protocol/ssl/CMakeLists.txt +++ b/src/analyzer/protocol/ssl/CMakeLists.txt @@ -4,13 +4,9 @@ include(BroPlugin) include_directories(BEFORE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR}) bro_plugin_begin(Bro SSL) -bro_plugin_cc(SSL.cc Plugin_SSL.cc) +bro_plugin_cc(SSL.cc DTLS.cc Plugin.cc) bro_plugin_bif(events.bif) bro_plugin_pac(tls-handshake.pac tls-handshake-protocol.pac tls-handshake-analyzer.pac ssl-defs.pac) bro_plugin_pac(ssl.pac ssl-dtls-analyzer.pac ssl-analyzer.pac ssl-dtls-protocol.pac ssl-protocol.pac ssl-defs.pac) -bro_plugin_end() - -bro_plugin_begin(Bro DTLS) -bro_plugin_cc(DTLS.cc Plugin_DTLS.cc) bro_plugin_pac(dtls.pac ssl-dtls-analyzer.pac dtls-analyzer.pac ssl-dtls-protocol.pac dtls-protocol.pac ssl-defs.pac) bro_plugin_end() diff --git a/src/analyzer/protocol/ssl/Plugin_SSL.cc b/src/analyzer/protocol/ssl/Plugin.cc similarity index 71% rename from src/analyzer/protocol/ssl/Plugin_SSL.cc rename to src/analyzer/protocol/ssl/Plugin.cc index 0479c9c97f..485463de17 100644 --- a/src/analyzer/protocol/ssl/Plugin_SSL.cc +++ b/src/analyzer/protocol/ssl/Plugin.cc @@ -4,6 +4,7 @@ #include "plugin/Plugin.h" #include "SSL.h" +#include "DTLS.h" namespace plugin { namespace Bro_SSL { @@ -13,10 +14,11 @@ public: plugin::Configuration Configure() { AddComponent(new ::analyzer::Component("SSL", ::analyzer::ssl::SSL_Analyzer::Instantiate)); + AddComponent(new ::analyzer::Component("DTLS", ::analyzer::dtls::DTLS_Analyzer::Instantiate)); plugin::Configuration config; config.name = "Bro::SSL"; - config.description = "SSL analyzer"; + config.description = "SSL/TLS and DTLS analyzer"; return config; } } plugin; diff --git a/src/analyzer/protocol/ssl/Plugin_DTLS.cc b/src/analyzer/protocol/ssl/Plugin_DTLS.cc deleted file mode 100644 index 6820816e31..0000000000 --- a/src/analyzer/protocol/ssl/Plugin_DTLS.cc +++ /dev/null @@ -1,26 +0,0 @@ -// See the file in the main distribution directory for copyright. - - -#include "plugin/Plugin.h" - -#include "DTLS.h" - -namespace plugin { -namespace Bro_DTLS { - -class Plugin : public plugin::Plugin { -public: - plugin::Configuration Configure() - { - AddComponent(new ::analyzer::Component("DTLS", ::analyzer::dtls::DTLS_Analyzer::Instantiate)); - - plugin::Configuration config; - config.name = "Bro::DTLS"; - config.description = "DTLS analyzer"; - return config; - } -} plugin; - -} -} - From 58ed2eb9aedc9c7f8cbce06e0582f3d1364ea53a Mon Sep 17 00:00:00 2001 From: Johanna Amann Date: Wed, 18 Mar 2015 11:58:46 -0700 Subject: [PATCH 08/11] add signature for dtls client hello --- scripts/base/protocols/ssl/dpd.sig | 7 +++++++ scripts/base/protocols/ssl/main.bro | 4 +++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/scripts/base/protocols/ssl/dpd.sig b/scripts/base/protocols/ssl/dpd.sig index b888d84cec..e238575568 100644 --- a/scripts/base/protocols/ssl/dpd.sig +++ b/scripts/base/protocols/ssl/dpd.sig @@ -13,3 +13,10 @@ signature dpd_ssl_client { payload /^(\x16\x03[\x00\x01\x02\x03]..\x01...\x03[\x00\x01\x02\x03]|...?\x01[\x00\x03][\x00\x01\x02\x03]).*/ tcp-state originator } + +signature dpd_dtls_client { + ip-proto == udp + # Client hello. + payload /^\x16\xfe[\xff\xfd]\x00\x00\x00\x00\x00\x00\x00...\x01...........\xfe[\xff\xfd].*/ + enable "dtls" +} diff --git a/scripts/base/protocols/ssl/main.bro b/scripts/base/protocols/ssl/main.bro index 2b448fec6c..75e41e4077 100644 --- a/scripts/base/protocols/ssl/main.bro +++ b/scripts/base/protocols/ssl/main.bro @@ -97,7 +97,9 @@ const ssl_ports = { 989/tcp, 990/tcp, 992/tcp, 993/tcp, 995/tcp, 5223/tcp }; -const dtls_ports = { 4433/udp }; +# As far as I know, there are no well known dtls ports at the moment. Let's +# just add 443 for now for good measure - who knows :) +const dtls_ports = { 443/udp }; redef likely_server_ports += { ssl_ports, dtls_ports }; From 5f557849a676be81dfea2fbb51e62955442b79dc Mon Sep 17 00:00:00 2001 From: Johanna Amann Date: Wed, 18 Mar 2015 12:48:22 -0700 Subject: [PATCH 09/11] add a simple leak test for dtls --- testing/btest/core/leaks/dtls.bro | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 testing/btest/core/leaks/dtls.bro diff --git a/testing/btest/core/leaks/dtls.bro b/testing/btest/core/leaks/dtls.bro new file mode 100644 index 0000000000..3f3aeb62d2 --- /dev/null +++ b/testing/btest/core/leaks/dtls.bro @@ -0,0 +1,15 @@ +# Needs perftools support. +# +# @TEST-GROUP: leaks +# +# @TEST-REQUIRES: bro --help 2>&1 | grep -q mem-leaks +# +# @TEST-EXEC: HEAP_CHECK_DUMP_DIRECTORY=. HEAPCHECK=local btest-bg-run bro bro -b -m -r $TRACES/tls/dtls-openssl.pcap %INPUT +# @TEST-EXEC: btest-bg-wait 30 + +@load base/protocols/ssl + +event ssl_established(c: connection) &priority=3 + { + print "established"; + } From e180403e76ff6fb0c31fcf79aca1a07d530b7b51 Mon Sep 17 00:00:00 2001 From: Johanna Amann Date: Wed, 18 Mar 2015 12:56:02 -0700 Subject: [PATCH 10/11] update test baselines --- .../Baseline/core.print-bpf-filters/output2 | 10 +++---- testing/btest/Baseline/plugins.hooks/output | 27 ++++++++++++------- 2 files changed, 23 insertions(+), 14 deletions(-) diff --git a/testing/btest/Baseline/core.print-bpf-filters/output2 b/testing/btest/Baseline/core.print-bpf-filters/output2 index f843da2909..8022ebbb5c 100644 --- a/testing/btest/Baseline/core.print-bpf-filters/output2 +++ b/testing/btest/Baseline/core.print-bpf-filters/output2 @@ -14,7 +14,7 @@ 1 3128 1 3306 1 3544 -1 443 +2 443 1 502 1 5072 1 514 @@ -44,8 +44,8 @@ 1 992 1 993 1 995 -49 and -48 or -49 port +50 and +49 or +50 port 34 tcp -15 udp +16 udp diff --git a/testing/btest/Baseline/plugins.hooks/output b/testing/btest/Baseline/plugins.hooks/output index 63f0a87742..596b3c808a 100644 --- a/testing/btest/Baseline/plugins.hooks/output +++ b/testing/btest/Baseline/plugins.hooks/output @@ -12,6 +12,7 @@ 0.000000 MetaHookPost CallFunction(Analyzer::__register_for_port, , (Analyzer::ANALYZER_DNS, 53/udp)) -> 0.000000 MetaHookPost CallFunction(Analyzer::__register_for_port, , (Analyzer::ANALYZER_DNS, 5353/udp)) -> 0.000000 MetaHookPost CallFunction(Analyzer::__register_for_port, , (Analyzer::ANALYZER_DNS, 5355/udp)) -> +0.000000 MetaHookPost CallFunction(Analyzer::__register_for_port, , (Analyzer::ANALYZER_DTLS, 443/udp)) -> 0.000000 MetaHookPost CallFunction(Analyzer::__register_for_port, , (Analyzer::ANALYZER_FTP, 21/tcp)) -> 0.000000 MetaHookPost CallFunction(Analyzer::__register_for_port, , (Analyzer::ANALYZER_FTP, 2811/tcp)) -> 0.000000 MetaHookPost CallFunction(Analyzer::__register_for_port, , (Analyzer::ANALYZER_GTPV1, 2123/udp)) -> @@ -65,6 +66,7 @@ 0.000000 MetaHookPost CallFunction(Analyzer::register_for_port, , (Analyzer::ANALYZER_DNS, 53/udp)) -> 0.000000 MetaHookPost CallFunction(Analyzer::register_for_port, , (Analyzer::ANALYZER_DNS, 5353/udp)) -> 0.000000 MetaHookPost CallFunction(Analyzer::register_for_port, , (Analyzer::ANALYZER_DNS, 5355/udp)) -> +0.000000 MetaHookPost CallFunction(Analyzer::register_for_port, , (Analyzer::ANALYZER_DTLS, 443/udp)) -> 0.000000 MetaHookPost CallFunction(Analyzer::register_for_port, , (Analyzer::ANALYZER_FTP, 21/tcp)) -> 0.000000 MetaHookPost CallFunction(Analyzer::register_for_port, , (Analyzer::ANALYZER_FTP, 2811/tcp)) -> 0.000000 MetaHookPost CallFunction(Analyzer::register_for_port, , (Analyzer::ANALYZER_GTPV1, 2123/udp)) -> @@ -108,6 +110,7 @@ 0.000000 MetaHookPost CallFunction(Analyzer::register_for_ports, , (Analyzer::ANALYZER_DHCP, {67<...>/udp})) -> 0.000000 MetaHookPost CallFunction(Analyzer::register_for_ports, , (Analyzer::ANALYZER_DNP3_TCP, {20000<...>/tcp})) -> 0.000000 MetaHookPost CallFunction(Analyzer::register_for_ports, , (Analyzer::ANALYZER_DNS, {5355<...>/udp})) -> +0.000000 MetaHookPost CallFunction(Analyzer::register_for_ports, , (Analyzer::ANALYZER_DTLS, {443/udp})) -> 0.000000 MetaHookPost CallFunction(Analyzer::register_for_ports, , (Analyzer::ANALYZER_FTP, {2811<...>/tcp})) -> 0.000000 MetaHookPost CallFunction(Analyzer::register_for_ports, , (Analyzer::ANALYZER_GTPV1, {2152<...>/udp})) -> 0.000000 MetaHookPost CallFunction(Analyzer::register_for_ports, , (Analyzer::ANALYZER_HTTP, {631<...>/tcp})) -> @@ -192,7 +195,7 @@ 0.000000 MetaHookPost CallFunction(Log::__create_stream, , (Weird::LOG, [columns=, ev=Weird::log_weird])) -> 0.000000 MetaHookPost CallFunction(Log::__create_stream, , (X509::LOG, [columns=, ev=X509::log_x509])) -> 0.000000 MetaHookPost CallFunction(Log::__create_stream, , (mysql::LOG, [columns=, ev=MySQL::log_mysql])) -> -0.000000 MetaHookPost CallFunction(Log::__write, , (PacketFilter::LOG, [ts=1426273629.648148, node=bro, filter=ip or not ip, init=T, success=T])) -> +0.000000 MetaHookPost CallFunction(Log::__write, , (PacketFilter::LOG, [ts=1426708489.193732, node=bro, filter=ip or not ip, init=T, success=T])) -> 0.000000 MetaHookPost CallFunction(Log::add_default_filter, , (Cluster::LOG)) -> 0.000000 MetaHookPost CallFunction(Log::add_default_filter, , (Communication::LOG)) -> 0.000000 MetaHookPost CallFunction(Log::add_default_filter, , (Conn::LOG)) -> @@ -286,8 +289,8 @@ 0.000000 MetaHookPost CallFunction(Log::create_stream, , (Weird::LOG, [columns=, ev=Weird::log_weird])) -> 0.000000 MetaHookPost CallFunction(Log::create_stream, , (X509::LOG, [columns=, ev=X509::log_x509])) -> 0.000000 MetaHookPost CallFunction(Log::create_stream, , (mysql::LOG, [columns=, ev=MySQL::log_mysql])) -> -0.000000 MetaHookPost CallFunction(Log::default_path_func, , (PacketFilter::LOG, , [ts=1426273629.648148, node=bro, filter=ip or not ip, init=T, success=T])) -> -0.000000 MetaHookPost CallFunction(Log::write, , (PacketFilter::LOG, [ts=1426273629.648148, node=bro, filter=ip or not ip, init=T, success=T])) -> +0.000000 MetaHookPost CallFunction(Log::default_path_func, , (PacketFilter::LOG, , [ts=1426708489.193732, node=bro, filter=ip or not ip, init=T, success=T])) -> +0.000000 MetaHookPost CallFunction(Log::write, , (PacketFilter::LOG, [ts=1426708489.193732, node=bro, filter=ip or not ip, init=T, success=T])) -> 0.000000 MetaHookPost CallFunction(Notice::want_pp, , ()) -> 0.000000 MetaHookPost CallFunction(PacketFilter::build, , ()) -> 0.000000 MetaHookPost CallFunction(PacketFilter::combine_filters, , (ip or not ip, and, )) -> @@ -557,6 +560,7 @@ 0.000000 MetaHookPre CallFunction(Analyzer::__register_for_port, , (Analyzer::ANALYZER_DNS, 53/udp)) 0.000000 MetaHookPre CallFunction(Analyzer::__register_for_port, , (Analyzer::ANALYZER_DNS, 5353/udp)) 0.000000 MetaHookPre CallFunction(Analyzer::__register_for_port, , (Analyzer::ANALYZER_DNS, 5355/udp)) +0.000000 MetaHookPre CallFunction(Analyzer::__register_for_port, , (Analyzer::ANALYZER_DTLS, 443/udp)) 0.000000 MetaHookPre CallFunction(Analyzer::__register_for_port, , (Analyzer::ANALYZER_FTP, 21/tcp)) 0.000000 MetaHookPre CallFunction(Analyzer::__register_for_port, , (Analyzer::ANALYZER_FTP, 2811/tcp)) 0.000000 MetaHookPre CallFunction(Analyzer::__register_for_port, , (Analyzer::ANALYZER_GTPV1, 2123/udp)) @@ -610,6 +614,7 @@ 0.000000 MetaHookPre CallFunction(Analyzer::register_for_port, , (Analyzer::ANALYZER_DNS, 53/udp)) 0.000000 MetaHookPre CallFunction(Analyzer::register_for_port, , (Analyzer::ANALYZER_DNS, 5353/udp)) 0.000000 MetaHookPre CallFunction(Analyzer::register_for_port, , (Analyzer::ANALYZER_DNS, 5355/udp)) +0.000000 MetaHookPre CallFunction(Analyzer::register_for_port, , (Analyzer::ANALYZER_DTLS, 443/udp)) 0.000000 MetaHookPre CallFunction(Analyzer::register_for_port, , (Analyzer::ANALYZER_FTP, 21/tcp)) 0.000000 MetaHookPre CallFunction(Analyzer::register_for_port, , (Analyzer::ANALYZER_FTP, 2811/tcp)) 0.000000 MetaHookPre CallFunction(Analyzer::register_for_port, , (Analyzer::ANALYZER_GTPV1, 2123/udp)) @@ -653,6 +658,7 @@ 0.000000 MetaHookPre CallFunction(Analyzer::register_for_ports, , (Analyzer::ANALYZER_DHCP, {67<...>/udp})) 0.000000 MetaHookPre CallFunction(Analyzer::register_for_ports, , (Analyzer::ANALYZER_DNP3_TCP, {20000<...>/tcp})) 0.000000 MetaHookPre CallFunction(Analyzer::register_for_ports, , (Analyzer::ANALYZER_DNS, {5355<...>/udp})) +0.000000 MetaHookPre CallFunction(Analyzer::register_for_ports, , (Analyzer::ANALYZER_DTLS, {443/udp})) 0.000000 MetaHookPre CallFunction(Analyzer::register_for_ports, , (Analyzer::ANALYZER_FTP, {2811<...>/tcp})) 0.000000 MetaHookPre CallFunction(Analyzer::register_for_ports, , (Analyzer::ANALYZER_GTPV1, {2152<...>/udp})) 0.000000 MetaHookPre CallFunction(Analyzer::register_for_ports, , (Analyzer::ANALYZER_HTTP, {631<...>/tcp})) @@ -737,7 +743,7 @@ 0.000000 MetaHookPre CallFunction(Log::__create_stream, , (Weird::LOG, [columns=, ev=Weird::log_weird])) 0.000000 MetaHookPre CallFunction(Log::__create_stream, , (X509::LOG, [columns=, ev=X509::log_x509])) 0.000000 MetaHookPre CallFunction(Log::__create_stream, , (mysql::LOG, [columns=, ev=MySQL::log_mysql])) -0.000000 MetaHookPre CallFunction(Log::__write, , (PacketFilter::LOG, [ts=1426273629.648148, node=bro, filter=ip or not ip, init=T, success=T])) +0.000000 MetaHookPre CallFunction(Log::__write, , (PacketFilter::LOG, [ts=1426708489.193732, node=bro, filter=ip or not ip, init=T, success=T])) 0.000000 MetaHookPre CallFunction(Log::add_default_filter, , (Cluster::LOG)) 0.000000 MetaHookPre CallFunction(Log::add_default_filter, , (Communication::LOG)) 0.000000 MetaHookPre CallFunction(Log::add_default_filter, , (Conn::LOG)) @@ -831,8 +837,8 @@ 0.000000 MetaHookPre CallFunction(Log::create_stream, , (Weird::LOG, [columns=, ev=Weird::log_weird])) 0.000000 MetaHookPre CallFunction(Log::create_stream, , (X509::LOG, [columns=, ev=X509::log_x509])) 0.000000 MetaHookPre CallFunction(Log::create_stream, , (mysql::LOG, [columns=, ev=MySQL::log_mysql])) -0.000000 MetaHookPre CallFunction(Log::default_path_func, , (PacketFilter::LOG, , [ts=1426273629.648148, node=bro, filter=ip or not ip, init=T, success=T])) -0.000000 MetaHookPre CallFunction(Log::write, , (PacketFilter::LOG, [ts=1426273629.648148, node=bro, filter=ip or not ip, init=T, success=T])) +0.000000 MetaHookPre CallFunction(Log::default_path_func, , (PacketFilter::LOG, , [ts=1426708489.193732, node=bro, filter=ip or not ip, init=T, success=T])) +0.000000 MetaHookPre CallFunction(Log::write, , (PacketFilter::LOG, [ts=1426708489.193732, node=bro, filter=ip or not ip, init=T, success=T])) 0.000000 MetaHookPre CallFunction(Notice::want_pp, , ()) 0.000000 MetaHookPre CallFunction(PacketFilter::build, , ()) 0.000000 MetaHookPre CallFunction(PacketFilter::combine_filters, , (ip or not ip, and, )) @@ -1102,6 +1108,7 @@ 0.000000 | HookCallFunction Analyzer::__register_for_port(Analyzer::ANALYZER_DNS, 53/udp) 0.000000 | HookCallFunction Analyzer::__register_for_port(Analyzer::ANALYZER_DNS, 5353/udp) 0.000000 | HookCallFunction Analyzer::__register_for_port(Analyzer::ANALYZER_DNS, 5355/udp) +0.000000 | HookCallFunction Analyzer::__register_for_port(Analyzer::ANALYZER_DTLS, 443/udp) 0.000000 | HookCallFunction Analyzer::__register_for_port(Analyzer::ANALYZER_FTP, 21/tcp) 0.000000 | HookCallFunction Analyzer::__register_for_port(Analyzer::ANALYZER_FTP, 2811/tcp) 0.000000 | HookCallFunction Analyzer::__register_for_port(Analyzer::ANALYZER_GTPV1, 2123/udp) @@ -1155,6 +1162,7 @@ 0.000000 | HookCallFunction Analyzer::register_for_port(Analyzer::ANALYZER_DNS, 53/udp) 0.000000 | HookCallFunction Analyzer::register_for_port(Analyzer::ANALYZER_DNS, 5353/udp) 0.000000 | HookCallFunction Analyzer::register_for_port(Analyzer::ANALYZER_DNS, 5355/udp) +0.000000 | HookCallFunction Analyzer::register_for_port(Analyzer::ANALYZER_DTLS, 443/udp) 0.000000 | HookCallFunction Analyzer::register_for_port(Analyzer::ANALYZER_FTP, 21/tcp) 0.000000 | HookCallFunction Analyzer::register_for_port(Analyzer::ANALYZER_FTP, 2811/tcp) 0.000000 | HookCallFunction Analyzer::register_for_port(Analyzer::ANALYZER_GTPV1, 2123/udp) @@ -1198,6 +1206,7 @@ 0.000000 | HookCallFunction Analyzer::register_for_ports(Analyzer::ANALYZER_DHCP, {67<...>/udp}) 0.000000 | HookCallFunction Analyzer::register_for_ports(Analyzer::ANALYZER_DNP3_TCP, {20000<...>/tcp}) 0.000000 | HookCallFunction Analyzer::register_for_ports(Analyzer::ANALYZER_DNS, {5355<...>/udp}) +0.000000 | HookCallFunction Analyzer::register_for_ports(Analyzer::ANALYZER_DTLS, {443/udp}) 0.000000 | HookCallFunction Analyzer::register_for_ports(Analyzer::ANALYZER_FTP, {2811<...>/tcp}) 0.000000 | HookCallFunction Analyzer::register_for_ports(Analyzer::ANALYZER_GTPV1, {2152<...>/udp}) 0.000000 | HookCallFunction Analyzer::register_for_ports(Analyzer::ANALYZER_HTTP, {631<...>/tcp}) @@ -1281,7 +1290,7 @@ 0.000000 | HookCallFunction Log::__create_stream(Weird::LOG, [columns=, ev=Weird::log_weird]) 0.000000 | HookCallFunction Log::__create_stream(X509::LOG, [columns=, ev=X509::log_x509]) 0.000000 | HookCallFunction Log::__create_stream(mysql::LOG, [columns=, ev=MySQL::log_mysql]) -0.000000 | HookCallFunction Log::__write(PacketFilter::LOG, [ts=1426273629.648148, node=bro, filter=ip or not ip, init=T, success=T]) +0.000000 | HookCallFunction Log::__write(PacketFilter::LOG, [ts=1426708489.193732, node=bro, filter=ip or not ip, init=T, success=T]) 0.000000 | HookCallFunction Log::add_default_filter(Cluster::LOG) 0.000000 | HookCallFunction Log::add_default_filter(Communication::LOG) 0.000000 | HookCallFunction Log::add_default_filter(Conn::LOG) @@ -1375,8 +1384,8 @@ 0.000000 | HookCallFunction Log::create_stream(Weird::LOG, [columns=, ev=Weird::log_weird]) 0.000000 | HookCallFunction Log::create_stream(X509::LOG, [columns=, ev=X509::log_x509]) 0.000000 | HookCallFunction Log::create_stream(mysql::LOG, [columns=, ev=MySQL::log_mysql]) -0.000000 | HookCallFunction Log::default_path_func(PacketFilter::LOG, , [ts=1426273629.648148, node=bro, filter=ip or not ip, init=T, success=T]) -0.000000 | HookCallFunction Log::write(PacketFilter::LOG, [ts=1426273629.648148, node=bro, filter=ip or not ip, init=T, success=T]) +0.000000 | HookCallFunction Log::default_path_func(PacketFilter::LOG, , [ts=1426708489.193732, node=bro, filter=ip or not ip, init=T, success=T]) +0.000000 | HookCallFunction Log::write(PacketFilter::LOG, [ts=1426708489.193732, node=bro, filter=ip or not ip, init=T, success=T]) 0.000000 | HookCallFunction Notice::want_pp() 0.000000 | HookCallFunction PacketFilter::build() 0.000000 | HookCallFunction PacketFilter::combine_filters(ip or not ip, and, ) From 443106dbdb85ed3033db62c631b279e96e47a3fb Mon Sep 17 00:00:00 2001 From: Johanna Amann Date: Wed, 18 Mar 2015 13:25:06 -0700 Subject: [PATCH 11/11] a few more small script-level fixes Sorry, forgot to commit these. --- scripts/base/protocols/ssl/files.bro | 4 ++++ scripts/base/protocols/ssl/main.bro | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/scripts/base/protocols/ssl/files.bro b/scripts/base/protocols/ssl/files.bro index 65f43ed772..90273639e5 100644 --- a/scripts/base/protocols/ssl/files.bro +++ b/scripts/base/protocols/ssl/files.bro @@ -85,6 +85,10 @@ event bro_init() &priority=5 Files::register_protocol(Analyzer::ANALYZER_SSL, [$get_file_handle = SSL::get_file_handle, $describe = SSL::describe_file]); + + Files::register_protocol(Analyzer::ANALYZER_DTLS, + [$get_file_handle = SSL::get_file_handle, + $describe = SSL::describe_file]); } event file_over_new_connection(f: fa_file, c: connection, is_orig: bool) &priority=5 diff --git a/scripts/base/protocols/ssl/main.bro b/scripts/base/protocols/ssl/main.bro index 75e41e4077..326d8d374d 100644 --- a/scripts/base/protocols/ssl/main.bro +++ b/scripts/base/protocols/ssl/main.bro @@ -274,7 +274,7 @@ event connection_state_remove(c: connection) &priority=-5 event protocol_confirmation(c: connection, atype: Analyzer::Tag, aid: count) &priority=5 { - if ( atype == Analyzer::ANALYZER_SSL ) + if ( atype == Analyzer::ANALYZER_SSL || atype == Analyzer::ANALYZER_DTLS ) { set_session(c); c$ssl$analyzer_id = aid; @@ -284,6 +284,6 @@ event protocol_confirmation(c: connection, atype: Analyzer::Tag, aid: count) &pr event protocol_violation(c: connection, atype: Analyzer::Tag, aid: count, reason: string) &priority=5 { - if ( c?$ssl && atype == Analyzer::ANALYZER_SSL ) + if ( c?$ssl && ( atype == Analyzer::ANALYZER_SSL || atype == Analyzer::ANALYZER_DTLS ) ) finish(c, T); }