mirror of
https://github.com/zeek/zeek.git
synced 2025-10-05 08:08:19 +00:00
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...
This commit is contained in:
parent
cb5902d1ad
commit
038fbf9b9e
24 changed files with 1487 additions and 1162 deletions
|
@ -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)
|
||||
|
|
|
@ -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()
|
||||
|
|
32
src/analyzer/protocol/ssl/DTLS.cc
Normal file
32
src/analyzer/protocol/ssl/DTLS.cc
Normal file
|
@ -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);
|
||||
}
|
31
src/analyzer/protocol/ssl/DTLS.h
Normal file
31
src/analyzer/protocol/ssl/DTLS.h
Normal file
|
@ -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
|
26
src/analyzer/protocol/ssl/Plugin_DTLS.cc
Normal file
26
src/analyzer/protocol/ssl/Plugin_DTLS.cc
Normal file
|
@ -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;
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
||||
};
|
||||
|
|
2
src/analyzer/protocol/ssl/dtls-analyzer.pac
Normal file
2
src/analyzer/protocol/ssl/dtls-analyzer.pac
Normal file
|
@ -0,0 +1,2 @@
|
|||
|
||||
|
40
src/analyzer/protocol/ssl/dtls-protocol.pac
Normal file
40
src/analyzer/protocol/ssl/dtls-protocol.pac
Normal file
|
@ -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;
|
||||
%}
|
||||
|
||||
};
|
30
src/analyzer/protocol/ssl/dtls.pac
Normal file
30
src/analyzer/protocol/ssl/dtls.pac
Normal file
|
@ -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
|
30
src/analyzer/protocol/ssl/proc-certificate.pac
Normal file
30
src/analyzer/protocol/ssl/proc-certificate.pac
Normal file
|
@ -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<const u_char*>(cert.data()),
|
||||
cert.length(), bro_analyzer()->GetAnalyzerTag(),
|
||||
bro_analyzer()->Conn(), is_orig, file_id);
|
||||
file_mgr->EndOfFile(file_id);
|
||||
}
|
||||
return true;
|
||||
%}
|
||||
|
||||
|
42
src/analyzer/protocol/ssl/proc-client-hello.pac
Normal file
42
src/analyzer/protocol/ssl/proc-client-hello.pac
Normal file
|
@ -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<int>* cipher_suites = new vector<int>();
|
||||
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;
|
||||
%}
|
||||
|
36
src/analyzer/protocol/ssl/proc-server-hello.pac
Normal file
36
src/analyzer/protocol/ssl/proc-server-hello.pac
Normal file
|
@ -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<int>* ciphers = new vector<int>();
|
||||
|
||||
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;
|
||||
%}
|
||||
|
|
@ -1,352 +1,19 @@
|
|||
# Analyzer for SSL (Bro-specific part).
|
||||
|
||||
%extern{
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <iterator>
|
||||
|
||||
#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<int>* cipher_suites = new vector<int>();
|
||||
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<int>* ciphers = new vector<int>();
|
||||
|
||||
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<const char*>(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<const u_char*>(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<bytestring>* cert_list = new vector<bytestring>(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<X509Certificate*>* certs = cl;
|
||||
vector<bytestring>* cert_list = new vector<bytestring>();
|
||||
|
||||
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);
|
||||
};
|
||||
|
|
|
@ -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 <string>
|
||||
using std::string;
|
||||
|
|
106
src/analyzer/protocol/ssl/ssl-dtls-analyzer.pac
Normal file
106
src/analyzer/protocol/ssl/ssl-dtls-analyzer.pac
Normal file
|
@ -0,0 +1,106 @@
|
|||
|
||||
%extern{
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <iterator>
|
||||
|
||||
#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);
|
||||
};
|
134
src/analyzer/protocol/ssl/ssl-dtls-protocol.pac
Normal file
134
src/analyzer/protocol/ssl/ssl-dtls-protocol.pac
Normal file
|
@ -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;
|
||||
%}
|
||||
};
|
|
@ -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;
|
||||
%}
|
||||
};
|
||||
|
|
|
@ -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
|
||||
|
|
273
src/analyzer/protocol/ssl/tls-handshake-analyzer.pac
Normal file
273
src/analyzer/protocol/ssl/tls-handshake-analyzer.pac
Normal file
|
@ -0,0 +1,273 @@
|
|||
# Analyzer for SSL/TLS Handshake protocol (Bro-specific part).
|
||||
|
||||
%extern{
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <iterator>
|
||||
|
||||
#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<const char*>(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<X509Certificate*>* certs = cl;
|
||||
vector<bytestring>* cert_list = new vector<bytestring>();
|
||||
|
||||
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);
|
||||
};
|
||||
|
533
src/analyzer/protocol/ssl/tls-handshake-protocol.pac
Normal file
533
src/analyzer/protocol/ssl/tls-handshake-protocol.pac
Normal file
|
@ -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;
|
||||
%}
|
||||
};
|
||||
|
||||
|
24
src/analyzer/protocol/ssl/tls-handshake.pac
Normal file
24
src/analyzer/protocol/ssl/tls-handshake.pac
Normal file
|
@ -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
|
||||
|
BIN
testing/btest/Traces/tls/dtls-openssl.pcap
Normal file
BIN
testing/btest/Traces/tls/dtls-openssl.pcap
Normal file
Binary file not shown.
Loading…
Add table
Add a link
Reference in a new issue