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:
Johanna Amann 2015-03-10 20:37:33 -07:00
parent cb5902d1ad
commit 038fbf9b9e
24 changed files with 1487 additions and 1162 deletions

View file

@ -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)

View file

@ -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()

View 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);
}

View 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

View 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;
}
}

View file

@ -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);

View file

@ -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;
};

View file

@ -0,0 +1,2 @@

View 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;
%}
};

View 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

View 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;
%}

View 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;
%}

View 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;
%}

View file

@ -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);
};

View file

@ -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;

View 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);
};

View 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;
%}
};

View file

@ -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;
%}
};

View file

@ -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

View 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);
};

View 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;
%}
};

View 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

Binary file not shown.