mirror of
https://github.com/zeek/zeek.git
synced 2025-10-12 03:28:19 +00:00
Merge remote-tracking branch 'origin/topic/johanna/dtls'
* origin/topic/johanna/dtls: a few more small script-level fixes update test baselines add a simple leak test for dtls add signature for dtls client hello Make the plugin structure more... legal. Only force logging of SSL if it actually was the SSL analyzer that failed. DTLS working. Implement correct parsing of TLS record fragmentation. Make handshake analyzer flow-based. This means we can feed data to it in chunks, which makes dealing with fragmentation a little bit more convenient. When setting the SSL analyzer to fail, also stop processing data that already has been delivered to the analyzer, not just future data. First step for a DTLS analyzer. BIT-1347 #merged Conflicts: scripts/base/protocols/ssl/main.bro testing/btest/Baseline/plugins.hooks/output
This commit is contained in:
commit
99c50251d4
39 changed files with 1803 additions and 1178 deletions
7
CHANGES
7
CHANGES
|
@ -1,4 +1,11 @@
|
|||
|
||||
2.3-595 | 2015-03-23 12:33:42 -0700
|
||||
|
||||
* DTLS analyzer. (Johanna Amann)
|
||||
|
||||
* Implement correct parsing of TLS record fragmentation. (Johanna
|
||||
Amann)
|
||||
|
||||
2.3-582 | 2015-03-23 11:34:25 -0700
|
||||
|
||||
* BIT-1313: In debug builds, "bro -B <x>" now supports "all" and
|
||||
|
|
2
NEWS
2
NEWS
|
@ -63,6 +63,8 @@ New Functionality
|
|||
|
||||
- A new icmp_sent_payload event provides access to ICMP payload.
|
||||
|
||||
- Bro now parses DTLS traffic.
|
||||
|
||||
Changed Functionality
|
||||
---------------------
|
||||
|
||||
|
|
2
VERSION
2
VERSION
|
@ -1 +1 @@
|
|||
2.3-582
|
||||
2.3-595
|
||||
|
|
|
@ -6,6 +6,11 @@ export {
|
|||
const TLSv10 = 0x0301;
|
||||
const TLSv11 = 0x0302;
|
||||
const TLSv12 = 0x0303;
|
||||
|
||||
const DTLSv10 = 0xFEFF;
|
||||
# DTLSv11 does not exist
|
||||
const DTLSv12 = 0xFEFD;
|
||||
|
||||
## Mapping between the constants and string values for SSL/TLS versions.
|
||||
const version_strings: table[count] of string = {
|
||||
[SSLv2] = "SSLv2",
|
||||
|
@ -13,6 +18,8 @@ export {
|
|||
[TLSv10] = "TLSv10",
|
||||
[TLSv11] = "TLSv11",
|
||||
[TLSv12] = "TLSv12",
|
||||
[DTLSv10] = "DTLSv10",
|
||||
[DTLSv12] = "DTLSv12"
|
||||
} &default=function(i: count):string { return fmt("unknown-%d", i); };
|
||||
|
||||
## TLS content types:
|
||||
|
|
|
@ -13,3 +13,10 @@ signature dpd_ssl_client {
|
|||
payload /^(\x16\x03[\x00\x01\x02\x03]..\x01...\x03[\x00\x01\x02\x03]|...?\x01[\x00\x03][\x00\x01\x02\x03]).*/
|
||||
tcp-state originator
|
||||
}
|
||||
|
||||
signature dpd_dtls_client {
|
||||
ip-proto == udp
|
||||
# Client hello.
|
||||
payload /^\x16\xfe[\xff\xfd]\x00\x00\x00\x00\x00\x00\x00...\x01...........\xfe[\xff\xfd].*/
|
||||
enable "dtls"
|
||||
}
|
||||
|
|
|
@ -85,6 +85,10 @@ event bro_init() &priority=5
|
|||
Files::register_protocol(Analyzer::ANALYZER_SSL,
|
||||
[$get_file_handle = SSL::get_file_handle,
|
||||
$describe = SSL::describe_file]);
|
||||
|
||||
Files::register_protocol(Analyzer::ANALYZER_DTLS,
|
||||
[$get_file_handle = SSL::get_file_handle,
|
||||
$describe = SSL::describe_file]);
|
||||
}
|
||||
|
||||
event file_over_new_connection(f: fa_file, c: connection, is_orig: bool) &priority=5
|
||||
|
|
|
@ -92,16 +92,22 @@ 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 };
|
||||
|
||||
# There are no well known DTLS ports at the moment. Let's
|
||||
# just add 443 for now for good measure - who knows :)
|
||||
const dtls_ports = { 443/udp };
|
||||
|
||||
redef likely_server_ports += { ssl_ports, dtls_ports };
|
||||
|
||||
event bro_init() &priority=5
|
||||
{
|
||||
Log::create_stream(SSL::LOG, [$columns=Info, $ev=log_ssl, $path="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)
|
||||
|
@ -268,7 +274,7 @@ event connection_state_remove(c: connection) &priority=-5
|
|||
|
||||
event protocol_confirmation(c: connection, atype: Analyzer::Tag, aid: count) &priority=5
|
||||
{
|
||||
if ( atype == Analyzer::ANALYZER_SSL )
|
||||
if ( atype == Analyzer::ANALYZER_SSL || atype == Analyzer::ANALYZER_DTLS )
|
||||
{
|
||||
set_session(c);
|
||||
c$ssl$analyzer_id = aid;
|
||||
|
@ -278,6 +284,6 @@ event protocol_confirmation(c: connection, atype: Analyzer::Tag, aid: count) &pr
|
|||
event protocol_violation(c: connection, atype: Analyzer::Tag, aid: count,
|
||||
reason: string) &priority=5
|
||||
{
|
||||
if ( c?$ssl )
|
||||
if ( c?$ssl && ( atype == Analyzer::ANALYZER_SSL || atype == Analyzer::ANALYZER_DTLS ) )
|
||||
finish(c, T);
|
||||
}
|
||||
|
|
|
@ -4,7 +4,9 @@ include(BroPlugin)
|
|||
include_directories(BEFORE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
||||
bro_plugin_begin(Bro SSL)
|
||||
bro_plugin_cc(SSL.cc Plugin.cc)
|
||||
bro_plugin_cc(SSL.cc DTLS.cc Plugin.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 ssl-defs.pac)
|
||||
bro_plugin_pac(ssl.pac ssl-dtls-analyzer.pac ssl-analyzer.pac ssl-dtls-protocol.pac ssl-protocol.pac ssl-defs.pac)
|
||||
bro_plugin_pac(dtls.pac ssl-dtls-analyzer.pac dtls-analyzer.pac ssl-dtls-protocol.pac dtls-protocol.pac ssl-defs.pac)
|
||||
bro_plugin_end()
|
||||
|
|
65
src/analyzer/protocol/ssl/DTLS.cc
Normal file
65
src/analyzer/protocol/ssl/DTLS.cc
Normal file
|
@ -0,0 +1,65 @@
|
|||
|
||||
#include "DTLS.h"
|
||||
#include "Reporter.h"
|
||||
#include "util.h"
|
||||
|
||||
#include "events.bif.h"
|
||||
|
||||
#include "dtls_pac.h"
|
||||
#include "tls-handshake_pac.h"
|
||||
|
||||
using namespace analyzer::dtls;
|
||||
|
||||
DTLS_Analyzer::DTLS_Analyzer(Connection* c)
|
||||
: analyzer::Analyzer("DTLS", c)
|
||||
{
|
||||
interp = new binpac::DTLS::SSL_Conn(this);
|
||||
handshake_interp = new binpac::TLSHandshake::Handshake_Conn(this);
|
||||
}
|
||||
|
||||
DTLS_Analyzer::~DTLS_Analyzer()
|
||||
{
|
||||
delete interp;
|
||||
delete handshake_interp;
|
||||
}
|
||||
|
||||
void DTLS_Analyzer::Done()
|
||||
{
|
||||
Analyzer::Done();
|
||||
interp->FlowEOF(true);
|
||||
interp->FlowEOF(false);
|
||||
handshake_interp->FlowEOF(true);
|
||||
handshake_interp->FlowEOF(false);
|
||||
}
|
||||
|
||||
void DTLS_Analyzer::DeliverPacket(int len, const u_char* data, bool orig, uint64 seq, const IP_Hdr* ip, int caplen)
|
||||
{
|
||||
Analyzer::DeliverPacket(len, data, orig, seq, ip, caplen);
|
||||
interp->NewData(orig, data, data + len);
|
||||
}
|
||||
|
||||
void DTLS_Analyzer::EndOfData(bool is_orig)
|
||||
{
|
||||
Analyzer::EndOfData(is_orig);
|
||||
interp->FlowEOF(is_orig);
|
||||
handshake_interp->FlowEOF(is_orig);
|
||||
}
|
||||
|
||||
|
||||
void DTLS_Analyzer::SendHandshake(uint8 msg_type, uint32 length, const u_char* begin, const u_char* end, bool orig)
|
||||
{
|
||||
try
|
||||
{
|
||||
handshake_interp->NewData(orig, (const unsigned char*) &msg_type, (const unsigned char*) &msg_type + 1);
|
||||
uint32 host_length = htonl(length);
|
||||
// the parser inspects a uint24 - since it is big-endian, it should be ok to just skip
|
||||
// the first byte of the uint32. Since we get the data from an uint24 from the dtls-parser, this should
|
||||
// always yield the correct result.
|
||||
handshake_interp->NewData(orig, (const unsigned char*) &host_length + 1, (const unsigned char*) &host_length + sizeof(host_length));
|
||||
handshake_interp->NewData(orig, begin, end);
|
||||
}
|
||||
catch ( const binpac::Exception& e )
|
||||
{
|
||||
ProtocolViolation(fmt("Binpac exception: %s", e.c_msg()));
|
||||
}
|
||||
}
|
38
src/analyzer/protocol/ssl/DTLS.h
Normal file
38
src/analyzer/protocol/ssl/DTLS.h
Normal file
|
@ -0,0 +1,38 @@
|
|||
#ifndef ANALYZER_PROTOCOL_SSL_DTLS_H
|
||||
#define ANALYZER_PROTOCOL_SSL_DTLS_H
|
||||
|
||||
#include "events.bif.h"
|
||||
|
||||
#include "analyzer/protocol/udp/UDP.h"
|
||||
|
||||
namespace binpac { namespace DTLS { class SSL_Conn; } }
|
||||
|
||||
namespace binpac { namespace TLSHandshake { class Handshake_Conn; } }
|
||||
|
||||
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);
|
||||
virtual void EndOfData(bool is_orig);
|
||||
|
||||
void SendHandshake(uint8 msg_type, uint32 length, const u_char* begin, const u_char* end, bool orig);
|
||||
|
||||
|
||||
static analyzer::Analyzer* Instantiate(Connection* conn)
|
||||
{ return new DTLS_Analyzer(conn); }
|
||||
|
||||
protected:
|
||||
binpac::DTLS::SSL_Conn* interp;
|
||||
binpac::TLSHandshake::Handshake_Conn* handshake_interp;
|
||||
};
|
||||
|
||||
} } // namespace analyzer::*
|
||||
|
||||
#endif
|
|
@ -4,6 +4,7 @@
|
|||
#include "plugin/Plugin.h"
|
||||
|
||||
#include "SSL.h"
|
||||
#include "DTLS.h"
|
||||
|
||||
namespace plugin {
|
||||
namespace Bro_SSL {
|
||||
|
@ -13,10 +14,11 @@ public:
|
|||
plugin::Configuration Configure()
|
||||
{
|
||||
AddComponent(new ::analyzer::Component("SSL", ::analyzer::ssl::SSL_Analyzer::Instantiate));
|
||||
AddComponent(new ::analyzer::Component("DTLS", ::analyzer::dtls::DTLS_Analyzer::Instantiate));
|
||||
|
||||
plugin::Configuration config;
|
||||
config.name = "Bro::SSL";
|
||||
config.description = "SSL analyzer";
|
||||
config.description = "SSL/TLS and DTLS analyzers";
|
||||
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()
|
||||
|
@ -26,12 +30,15 @@ void SSL_Analyzer::Done()
|
|||
|
||||
interp->FlowEOF(true);
|
||||
interp->FlowEOF(false);
|
||||
handshake_interp->FlowEOF(true);
|
||||
handshake_interp->FlowEOF(false);
|
||||
}
|
||||
|
||||
void SSL_Analyzer::EndpointEOF(bool is_orig)
|
||||
{
|
||||
tcp::TCP_ApplicationAnalyzer::EndpointEOF(is_orig);
|
||||
interp->FlowEOF(is_orig);
|
||||
handshake_interp->FlowEOF(is_orig);
|
||||
}
|
||||
|
||||
void SSL_Analyzer::DeliverStream(int len, const u_char* data, bool orig)
|
||||
|
@ -57,6 +64,18 @@ void SSL_Analyzer::DeliverStream(int len, const u_char* data, bool orig)
|
|||
}
|
||||
}
|
||||
|
||||
void SSL_Analyzer::SendHandshake(const u_char* begin, const u_char* end, bool orig)
|
||||
{
|
||||
try
|
||||
{
|
||||
handshake_interp->NewData(orig, begin, end);
|
||||
}
|
||||
catch ( const binpac::Exception& e )
|
||||
{
|
||||
ProtocolViolation(fmt("Binpac exception: %s", 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(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;
|
||||
|
||||
};
|
||||
|
|
150
src/analyzer/protocol/ssl/dtls-analyzer.pac
Normal file
150
src/analyzer/protocol/ssl/dtls-analyzer.pac
Normal file
|
@ -0,0 +1,150 @@
|
|||
|
||||
refine connection SSL_Conn += {
|
||||
|
||||
%member{
|
||||
|
||||
struct message_info {
|
||||
uint64 message_first_sequence; // the minumum dtls sequence number for this handshake fragment
|
||||
bool first_sequence_seen; // did we actually see the fragment with the smallest number
|
||||
uint64 message_last_sequence; // the mazimum dtls sequence number for this handshake fragment
|
||||
uint16 message_handshake_sequence; // the handshake sequence number of this handshake (to identify)
|
||||
uint32 message_length; // data length of this handshake (data in buffer)
|
||||
uint32 message_sequence_seen; // a bitfield that shows which sequence numbers we already saw, offset from first_seq.
|
||||
u_char* buffer;
|
||||
} server, client;
|
||||
%}
|
||||
|
||||
%init{
|
||||
memset(&server, 0, sizeof(server));
|
||||
memset(&client, 0, sizeof(client));
|
||||
%}
|
||||
|
||||
%cleanup{
|
||||
delete [] server.buffer;
|
||||
delete [] client.buffer;
|
||||
%}
|
||||
|
||||
function proc_dtls(pdu: SSLRecord, sequence: uint64): bool
|
||||
%{
|
||||
//fprintf(stderr, "Type: %d, sequence number: %d, epoch: %d\n", ${pdu.content_type}, sequence, ${pdu.epoch});
|
||||
|
||||
return true;
|
||||
%}
|
||||
|
||||
function proc_handshake(pdu: SSLRecord, rec: Handshake): bool
|
||||
%{
|
||||
uint32 foffset = to_int()(${rec.fragment_offset});
|
||||
uint32 flength = to_int()(${rec.fragment_length});
|
||||
uint32 length = to_int()(${rec.length});
|
||||
uint64 sequence_number = to_int()(${pdu.sequence_number});
|
||||
//fprintf(stderr, "Handshake type: %d, length: %u, seq: %u, foffset: %u, flength: %u\n", ${rec.msg_type}, to_int()(${rec.length}), ${rec.message_seq}, to_int()(${rec.fragment_offset}), to_int()(${rec.fragment_length}));
|
||||
|
||||
if ( foffset == 0 && length == flength )
|
||||
{
|
||||
//fprintf(stderr, "Complete fragment, forwarding...\n");
|
||||
bro_analyzer()->SendHandshake(${rec.msg_type}, length, ${rec.data}.begin(), ${rec.data}.end(), ${pdu.is_orig});
|
||||
return true;
|
||||
}
|
||||
|
||||
// if we fall through here, the message has to be reassembled. Let's first get the right info record...
|
||||
message_info* i;
|
||||
if ( ${pdu.is_orig} )
|
||||
i = &client;
|
||||
else
|
||||
i = &server;
|
||||
|
||||
if ( length > MAX_DTLS_HANDSHAKE_RECORD )
|
||||
{
|
||||
bro_analyzer()->ProtocolViolation(fmt("DTLS record length %u larger than allowed maximum.", length));
|
||||
return true;
|
||||
}
|
||||
|
||||
if ( i->message_handshake_sequence != ${rec.message_seq} || i->message_length != length || i->buffer == 0 )
|
||||
{
|
||||
// cannot resume reassembling. Let's abandon the current data and try anew...
|
||||
delete [] i->buffer;
|
||||
memset(i, 0, sizeof(message_info));
|
||||
i->message_handshake_sequence = ${rec.message_seq};
|
||||
i->message_length = length;
|
||||
i->buffer = new u_char[length];
|
||||
// does not have to be the first sequence number - we cannot figure that out at this point. If it is not,
|
||||
// we will fix that later...
|
||||
i->message_first_sequence = sequence_number;
|
||||
}
|
||||
|
||||
// if we arrive here, we are actually ready to resume.
|
||||
if ( i->message_first_sequence > sequence_number )
|
||||
{
|
||||
if ( i->first_sequence_seen )
|
||||
{
|
||||
bro_analyzer()->ProtocolViolation("Saw second and different first message fragment for handshake.");
|
||||
return true;
|
||||
}
|
||||
// first sequence number was incorrect, let's fix that.
|
||||
uint64 diff = i->message_first_sequence - sequence_number;
|
||||
i->message_sequence_seen = i->message_sequence_seen << diff;
|
||||
i->message_first_sequence = sequence_number;
|
||||
}
|
||||
|
||||
// if we have offset 0, we know the smallest number...
|
||||
if ( foffset == 0 )
|
||||
i->first_sequence_seen = true;
|
||||
|
||||
// check if we already saw the message
|
||||
if ( ( i->message_sequence_seen & ( 1 << (sequence_number - i->message_first_sequence) ) ) != 0 )
|
||||
return true; // do not handle same message fragment twice
|
||||
|
||||
// copy data from fragment to buffer
|
||||
if ( ${rec.data}.length() != flength )
|
||||
{
|
||||
bro_analyzer()->ProtocolViolation(fmt("DTLS handshake record length does not match packet length"));
|
||||
return true;
|
||||
}
|
||||
|
||||
if ( foffset + flength > length )
|
||||
{
|
||||
bro_analyzer()->ProtocolViolation(fmt("DTLS handshake fragment trying to write past end of buffer"));
|
||||
return true;
|
||||
}
|
||||
|
||||
// store that we handled fragment
|
||||
i->message_sequence_seen |= 1 << (sequence_number - i->message_first_sequence);
|
||||
memcpy(i->buffer + foffset, ${rec.data}.data(), ${rec.data}.length());
|
||||
|
||||
//fprintf(stderr, "Copied to buffer offset %u length %u\n", foffset, ${rec.data}.length());
|
||||
|
||||
// store last fragment information if this is the last fragment...
|
||||
|
||||
// check if we saw all fragments so far. If yes, forward...
|
||||
if ( foffset + flength == length )
|
||||
i->message_last_sequence = sequence_number;
|
||||
|
||||
if ( i->message_last_sequence != 0 && i->first_sequence_seen )
|
||||
{
|
||||
uint64 total_length = i->message_last_sequence - i->message_first_sequence;
|
||||
if ( total_length > 32 )
|
||||
{
|
||||
bro_analyzer()->ProtocolViolation(fmt("DTLS Message fragmented over more than 32 pieces. Cannot reassemble."));
|
||||
return true;
|
||||
}
|
||||
|
||||
if ( ( ~(i->message_sequence_seen) & ( ( 1<<(total_length+1) ) -1 ) ) == 0 )
|
||||
{
|
||||
//fprintf(stderr, "ALl fragments here. Total length %u\n", length);
|
||||
bro_analyzer()->SendHandshake(${rec.msg_type}, length, i->buffer, i->buffer + length, ${pdu.is_orig});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
%}
|
||||
};
|
||||
|
||||
refine typeattr SSLRecord += &let {
|
||||
proc: bool = $context.connection.proc_dtls(this, to_int()(sequence_number));
|
||||
};
|
||||
|
||||
refine typeattr Handshake += &let {
|
||||
proc: bool = $context.connection.proc_handshake(rec, this);
|
||||
};
|
||||
|
60
src/analyzer/protocol/ssl/dtls-protocol.pac
Normal file
60
src/analyzer/protocol/ssl/dtls-protocol.pac
Normal file
|
@ -0,0 +1,60 @@
|
|||
|
||||
######################################################################
|
||||
# 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;
|
||||
# the epoch signalizes that a changecipherspec message has been received. Hence, everything with
|
||||
# an epoch > 0 should be encrypted
|
||||
epoch: uint16;
|
||||
sequence_number: uint48;
|
||||
length: uint16;
|
||||
cont: case valid of {
|
||||
true -> rec: RecordText(this)[] &length=length;
|
||||
false -> swallow: bytestring &restofdata;
|
||||
};
|
||||
} &byteorder = bigendian, &let {
|
||||
# Do not parse body if packet version invalid
|
||||
valid: bool = $context.connection.dtls_version_ok(version);
|
||||
};
|
||||
|
||||
type RecordText(rec: SSLRecord) = case rec.epoch of {
|
||||
0 -> plaintext : PlaintextRecord(rec);
|
||||
default -> ciphertext : CiphertextRecord(rec);
|
||||
};
|
||||
|
||||
refine casetype PlaintextRecord += {
|
||||
HANDSHAKE -> handshake : Handshake(rec);
|
||||
};
|
||||
|
||||
type Handshake(rec: SSLRecord) = record {
|
||||
msg_type: uint8;
|
||||
length: uint24;
|
||||
message_seq: uint16;
|
||||
fragment_offset: uint24;
|
||||
fragment_length: uint24;
|
||||
data: bytestring &restofdata;
|
||||
}
|
||||
|
||||
refine connection SSL_Conn += {
|
||||
|
||||
function dtls_version_ok(version: uint16): uint16
|
||||
%{
|
||||
switch ( version ) {
|
||||
case DTLSv10:
|
||||
case DTLSv12:
|
||||
return true;
|
||||
|
||||
default:
|
||||
bro_analyzer()->ProtocolViolation(fmt("Invalid version in DTLS connection. Packet reported version: %d", version));
|
||||
return false;
|
||||
}
|
||||
%}
|
||||
|
||||
};
|
36
src/analyzer/protocol/ssl/dtls.pac
Normal file
36
src/analyzer/protocol/ssl/dtls.pac
Normal file
|
@ -0,0 +1,36 @@
|
|||
# binpac file for SSL analyzer
|
||||
|
||||
%include binpac.pac
|
||||
%include bro.pac
|
||||
|
||||
%extern{
|
||||
#include "events.bif.h"
|
||||
|
||||
namespace analyzer { namespace dtls { class DTLS_Analyzer; } }
|
||||
typedef analyzer::dtls::DTLS_Analyzer* DTLSAnalyzer;
|
||||
|
||||
#include "DTLS.h"
|
||||
%}
|
||||
|
||||
extern type DTLSAnalyzer;
|
||||
|
||||
analyzer DTLS withcontext {
|
||||
connection: SSL_Conn;
|
||||
flow: DTLS_Flow;
|
||||
};
|
||||
|
||||
connection SSL_Conn(bro_analyzer: DTLSAnalyzer) {
|
||||
upflow = DTLS_Flow(true);
|
||||
downflow = DTLS_Flow(false);
|
||||
};
|
||||
|
||||
%include ssl-dtls-protocol.pac
|
||||
%include dtls-protocol.pac
|
||||
|
||||
flow DTLS_Flow(is_orig: bool) {
|
||||
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,38 @@ refine connection SSL_Conn += {
|
|||
return true;
|
||||
%}
|
||||
|
||||
function proc_unknown_handshake(hs: Handshake, is_orig: bool) : bool
|
||||
function proc_handshake(rec: SSLRecord, 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()));
|
||||
bro_analyzer()->SendHandshake(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, data, rec.is_orig);
|
||||
};
|
||||
|
|
|
@ -1,5 +1,86 @@
|
|||
# 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:
|
||||
case DTLSv10:
|
||||
case DTLSv12:
|
||||
return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
%}
|
||||
|
||||
|
||||
%extern{
|
||||
#include <string>
|
||||
using std::string;
|
||||
|
@ -7,6 +88,9 @@ using std::string;
|
|||
#include "events.bif.h"
|
||||
%}
|
||||
|
||||
# a maximum of 100k for one record seems safe
|
||||
let MAX_DTLS_HANDSHAKE_RECORD: uint32 = 100000;
|
||||
|
||||
enum ContentType {
|
||||
CHANGE_CIPHER_SPEC = 20,
|
||||
ALERT = 21,
|
||||
|
@ -27,7 +111,11 @@ enum SSLVersions {
|
|||
SSLv30 = 0x0300,
|
||||
TLSv10 = 0x0301,
|
||||
TLSv11 = 0x0302,
|
||||
TLSv12 = 0x0303
|
||||
TLSv12 = 0x0303,
|
||||
|
||||
DTLSv10 = 0xFEFF,
|
||||
# DTLSv11 does not exist.
|
||||
DTLSv12 = 0xFEFD
|
||||
};
|
||||
|
||||
enum SSLExtensions {
|
||||
|
|
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,160 +34,18 @@ 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;
|
||||
# Handshakes are parsed by the handshake analyzer.
|
||||
type Handshake(rec: SSLRecord) = record {
|
||||
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: 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 +58,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 +75,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 +96,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 +116,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 +131,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
|
||||
%{
|
||||
|
@ -824,24 +208,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: HandshakeRecord, type: int, sourcedata: const_bytestring) : bool
|
||||
%{
|
||||
// We cheat a little bit here. We want to throw this event
|
||||
// for every extension we encounter, even those that are
|
||||
// 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: HandshakeRecord, 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: HandshakeRecord, 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: HandshakeRecord, 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: HandshakeRecord, 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: HandshakeRecord, is_orig: bool) : bool
|
||||
%{
|
||||
bro_analyzer()->ProtocolViolation(fmt("unknown handshake message (%d) from %s",
|
||||
${hs.msg_type}, orig_label(is_orig).c_str()));
|
||||
return true;
|
||||
%}
|
||||
|
||||
function proc_certificate_status(rec : HandshakeRecord, 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: HandshakeRecord, 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: HandshakeRecord, 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: uint24) : bool
|
||||
%{
|
||||
BifEvent::generate_ssl_handshake_message(bro_analyzer(),
|
||||
bro_analyzer()->Conn(), is_orig, msg_type, to_int()(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(rec.is_orig, rec.msg_type, rec.msg_length);
|
||||
};
|
||||
|
538
src/analyzer/protocol/ssl/tls-handshake-protocol.pac
Normal file
538
src/analyzer/protocol/ssl/tls-handshake-protocol.pac
Normal file
|
@ -0,0 +1,538 @@
|
|||
######################################################################
|
||||
# Handshake Protocols (7.)
|
||||
######################################################################
|
||||
|
||||
enum HandshakeType {
|
||||
HELLO_REQUEST = 0,
|
||||
CLIENT_HELLO = 1,
|
||||
SERVER_HELLO = 2,
|
||||
HELLO_VERIFY_REQUEST = 3, # DTLS
|
||||
SESSION_TICKET = 4, # RFC 5077
|
||||
CERTIFICATE = 11,
|
||||
SERVER_KEY_EXCHANGE = 12,
|
||||
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 HandshakeRecord(is_orig: bool) = record {
|
||||
msg_type: uint8;
|
||||
msg_length: uint24;
|
||||
rec: Handshake(this);
|
||||
} &length=(to_int()(msg_length) + 4);
|
||||
|
||||
type Handshake(rec: HandshakeRecord) = case rec.msg_type of {
|
||||
HELLO_REQUEST -> hello_request : HelloRequest(rec);
|
||||
CLIENT_HELLO -> client_hello : ClientHello(rec);
|
||||
SERVER_HELLO -> server_hello : ServerHello(rec);
|
||||
HELLO_VERIFY_REQUEST -> hello_verify_request : HelloVerifyRequest(rec);
|
||||
SESSION_TICKET -> session_ticket : SessionTicketHandshake(rec);
|
||||
CERTIFICATE -> certificate : Certificate(rec);
|
||||
SERVER_KEY_EXCHANGE -> server_key_exchange : ServerKeyExchange(rec);
|
||||
CERTIFICATE_REQUEST -> certificate_request : CertificateRequest(rec);
|
||||
SERVER_HELLO_DONE -> server_hello_done : ServerHelloDone(rec);
|
||||
CERTIFICATE_VERIFY -> certificate_verify : CertificateVerify(rec);
|
||||
CLIENT_KEY_EXCHANGE -> client_key_exchange : ClientKeyExchange(rec);
|
||||
FINISHED -> finished : Finished(rec);
|
||||
CERTIFICATE_URL -> certificate_url : bytestring &restofdata &transient;
|
||||
CERTIFICATE_STATUS -> certificate_status : CertificateStatus(rec);
|
||||
default -> unknown_handshake : UnknownHandshake(rec, rec.is_orig);
|
||||
}
|
||||
|
||||
type HandshakePDU(is_orig: bool) = record {
|
||||
records: HandshakeRecord(is_orig)[] &transient;
|
||||
} &byteorder = bigendian;
|
||||
|
||||
type UnknownHandshake(hs: HandshakeRecord, is_orig: bool) = record {
|
||||
data : bytestring &restofdata &transient;
|
||||
};
|
||||
|
||||
######################################################################
|
||||
# V3 Hello Request (7.4.1.1.)
|
||||
######################################################################
|
||||
|
||||
# Hello Request is empty
|
||||
type HelloRequest(rec: HandshakeRecord) = empty;
|
||||
|
||||
|
||||
######################################################################
|
||||
# V3 Client Hello (7.4.1.2.)
|
||||
######################################################################
|
||||
|
||||
type ClientHello(rec: HandshakeRecord) = record {
|
||||
client_version : uint16;
|
||||
gmt_unix_time : uint32;
|
||||
random_bytes : bytestring &length = 28;
|
||||
session_len : uint8;
|
||||
session_id : uint8[session_len];
|
||||
dtls_cookie: case client_version of {
|
||||
DTLSv10 -> cookie: ClientHelloCookie(rec);
|
||||
default -> nothing: bytestring &length=0;
|
||||
};
|
||||
csuit_len : uint16 &check(csuit_len > 1 && csuit_len % 2 == 0);
|
||||
csuits : uint16[csuit_len/2];
|
||||
cmeth_len : uint8 &check(cmeth_len > 0);
|
||||
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);
|
||||
};
|
||||
|
||||
type ClientHelloCookie(rec: HandshakeRecord) = record {
|
||||
cookie_len : uint8;
|
||||
cookie : bytestring &length = cookie_len;
|
||||
};
|
||||
|
||||
######################################################################
|
||||
# V3 Server Hello (7.4.1.3.)
|
||||
######################################################################
|
||||
|
||||
type ServerHello(rec: HandshakeRecord) = 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]);
|
||||
};
|
||||
|
||||
######################################################################
|
||||
# DTLS Hello Verify Request
|
||||
######################################################################
|
||||
|
||||
type HelloVerifyRequest(rec: HandshakeRecord) = record {
|
||||
version: uint16;
|
||||
cookie_length: uint8;
|
||||
cookie: bytestring &length=cookie_length;
|
||||
};
|
||||
|
||||
######################################################################
|
||||
# V3 Server Certificate (7.4.2.)
|
||||
######################################################################
|
||||
|
||||
type X509Certificate = record {
|
||||
length : uint24;
|
||||
certificate : bytestring &length = to_int()(length);
|
||||
};
|
||||
|
||||
type Certificate(rec: HandshakeRecord) = record {
|
||||
length : uint24;
|
||||
certificates : X509Certificate[] &until($input.length() == 0);
|
||||
} &length = to_int()(length)+3;
|
||||
|
||||
# OCSP Stapling
|
||||
|
||||
type CertificateStatus(rec: HandshakeRecord) = 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: HandshakeRecord) = case $context.connection.chosen_cipher() of {
|
||||
TLS_ECDH_ECDSA_WITH_NULL_SHA,
|
||||
TLS_ECDH_ECDSA_WITH_RC4_128_SHA,
|
||||
TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA,
|
||||
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: HandshakeRecord) = 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: HandshakeRecord) = 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: HandshakeRecord) = record {
|
||||
cont : bytestring &restofdata &transient;
|
||||
};
|
||||
|
||||
|
||||
######################################################################
|
||||
# V3 Server Hello Done (7.4.5.)
|
||||
######################################################################
|
||||
|
||||
# Server Hello Done is empty
|
||||
type ServerHelloDone(rec: HandshakeRecord) = 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: HandshakeRecord) = record {
|
||||
key : bytestring &restofdata &transient;
|
||||
};
|
||||
|
||||
|
||||
######################################################################
|
||||
# V3 Certificate Verify (7.4.8.)
|
||||
######################################################################
|
||||
|
||||
# For now, ignore Certificate Verify; just eat up the message.
|
||||
type CertificateVerify(rec: HandshakeRecord) = 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: HandshakeRecord) = record {
|
||||
cont : bytestring &restofdata &transient;
|
||||
};
|
||||
|
||||
type SessionTicketHandshake(rec: HandshakeRecord) = record {
|
||||
ticket_lifetime_hint: uint32;
|
||||
data: bytestring &restofdata;
|
||||
};
|
||||
|
||||
######################################################################
|
||||
# TLS Extensions
|
||||
######################################################################
|
||||
|
||||
type SSLExtension(rec: HandshakeRecord) = 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: HandshakeRecord) = record {
|
||||
length: uint16;
|
||||
server_names: ServerName[] &until($input.length() == 0);
|
||||
} &length=length+2;
|
||||
|
||||
# Do not parse for now. Structure is correct, but only contains asn.1 data that we would not use further.
|
||||
#type OcspStatusRequest(rec: HandshakeRecord) = record {
|
||||
# responder_id_list_length: uint16;
|
||||
# responder_id_list: bytestring &length=responder_id_list_length;
|
||||
# request_extensions_length: uint16;
|
||||
# request_extensions: bytestring &length=request_extensions_length;
|
||||
#};
|
||||
#
|
||||
#type StatusRequest(rec: HandshakeRecord) = 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: HandshakeRecord) = record {
|
||||
length: uint8;
|
||||
point_format_list: uint8[length];
|
||||
};
|
||||
|
||||
type EllipticCurves(rec: HandshakeRecord) = record {
|
||||
length: uint16;
|
||||
elliptic_curve_list: uint16[length/2];
|
||||
};
|
||||
|
||||
type ProtocolName() = record {
|
||||
length: uint8;
|
||||
name: bytestring &length=length;
|
||||
};
|
||||
|
||||
type ApplicationLayerProtocolNegotiationExtension(rec: HandshakeRecord) = record {
|
||||
length: uint16;
|
||||
protocol_name_list: ProtocolName[] &until($input.length() == 0);
|
||||
} &length=length+2;
|
||||
|
||||
refine connection Handshake_Conn += {
|
||||
|
||||
%member{
|
||||
uint32 chosen_cipher_;
|
||||
%}
|
||||
|
||||
%init{
|
||||
chosen_cipher_ = NO_CHOSEN_CIPHER;
|
||||
%}
|
||||
|
||||
function chosen_cipher() : int %{ return chosen_cipher_; %}
|
||||
|
||||
function set_cipher(cipher: uint32) : bool
|
||||
%{
|
||||
chosen_cipher_ = cipher;
|
||||
return true;
|
||||
%}
|
||||
};
|
||||
|
||||
|
23
src/analyzer/protocol/ssl/tls-handshake.pac
Normal file
23
src/analyzer/protocol/ssl/tls-handshake.pac
Normal file
|
@ -0,0 +1,23 @@
|
|||
# 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);
|
||||
};
|
||||
|
||||
%include ssl-defs.pac
|
||||
%include tls-handshake-protocol.pac
|
||||
|
||||
flow Handshake_Flow(is_orig: bool) {
|
||||
flowunit = HandshakePDU(is_orig) withcontext(connection, this);
|
||||
}
|
||||
|
||||
%include tls-handshake-analyzer.pac
|
|
@ -14,7 +14,7 @@
|
|||
1 3128
|
||||
1 3306
|
||||
1 3544
|
||||
1 443
|
||||
2 443
|
||||
1 502
|
||||
1 5072
|
||||
1 514
|
||||
|
@ -44,8 +44,8 @@
|
|||
1 992
|
||||
1 993
|
||||
1 995
|
||||
49 and
|
||||
48 or
|
||||
49 port
|
||||
50 and
|
||||
49 or
|
||||
50 port
|
||||
34 tcp
|
||||
15 udp
|
||||
16 udp
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
0.000000 MetaHookPost CallFunction(Analyzer::__register_for_port, <frame>, (Analyzer::ANALYZER_DNS, 53/udp)) -> <no result>
|
||||
0.000000 MetaHookPost CallFunction(Analyzer::__register_for_port, <frame>, (Analyzer::ANALYZER_DNS, 5353/udp)) -> <no result>
|
||||
0.000000 MetaHookPost CallFunction(Analyzer::__register_for_port, <frame>, (Analyzer::ANALYZER_DNS, 5355/udp)) -> <no result>
|
||||
0.000000 MetaHookPost CallFunction(Analyzer::__register_for_port, <frame>, (Analyzer::ANALYZER_DTLS, 443/udp)) -> <no result>
|
||||
0.000000 MetaHookPost CallFunction(Analyzer::__register_for_port, <frame>, (Analyzer::ANALYZER_FTP, 21/tcp)) -> <no result>
|
||||
0.000000 MetaHookPost CallFunction(Analyzer::__register_for_port, <frame>, (Analyzer::ANALYZER_FTP, 2811/tcp)) -> <no result>
|
||||
0.000000 MetaHookPost CallFunction(Analyzer::__register_for_port, <frame>, (Analyzer::ANALYZER_GTPV1, 2123/udp)) -> <no result>
|
||||
|
@ -65,6 +66,7 @@
|
|||
0.000000 MetaHookPost CallFunction(Analyzer::register_for_port, <frame>, (Analyzer::ANALYZER_DNS, 53/udp)) -> <no result>
|
||||
0.000000 MetaHookPost CallFunction(Analyzer::register_for_port, <frame>, (Analyzer::ANALYZER_DNS, 5353/udp)) -> <no result>
|
||||
0.000000 MetaHookPost CallFunction(Analyzer::register_for_port, <frame>, (Analyzer::ANALYZER_DNS, 5355/udp)) -> <no result>
|
||||
0.000000 MetaHookPost CallFunction(Analyzer::register_for_port, <frame>, (Analyzer::ANALYZER_DTLS, 443/udp)) -> <no result>
|
||||
0.000000 MetaHookPost CallFunction(Analyzer::register_for_port, <frame>, (Analyzer::ANALYZER_FTP, 21/tcp)) -> <no result>
|
||||
0.000000 MetaHookPost CallFunction(Analyzer::register_for_port, <frame>, (Analyzer::ANALYZER_FTP, 2811/tcp)) -> <no result>
|
||||
0.000000 MetaHookPost CallFunction(Analyzer::register_for_port, <frame>, (Analyzer::ANALYZER_GTPV1, 2123/udp)) -> <no result>
|
||||
|
@ -108,6 +110,7 @@
|
|||
0.000000 MetaHookPost CallFunction(Analyzer::register_for_ports, <frame>, (Analyzer::ANALYZER_DHCP, {67<...>/udp})) -> <no result>
|
||||
0.000000 MetaHookPost CallFunction(Analyzer::register_for_ports, <frame>, (Analyzer::ANALYZER_DNP3_TCP, {20000<...>/tcp})) -> <no result>
|
||||
0.000000 MetaHookPost CallFunction(Analyzer::register_for_ports, <frame>, (Analyzer::ANALYZER_DNS, {5355<...>/udp})) -> <no result>
|
||||
0.000000 MetaHookPost CallFunction(Analyzer::register_for_ports, <frame>, (Analyzer::ANALYZER_DTLS, {443/udp})) -> <no result>
|
||||
0.000000 MetaHookPost CallFunction(Analyzer::register_for_ports, <frame>, (Analyzer::ANALYZER_FTP, {2811<...>/tcp})) -> <no result>
|
||||
0.000000 MetaHookPost CallFunction(Analyzer::register_for_ports, <frame>, (Analyzer::ANALYZER_GTPV1, {2152<...>/udp})) -> <no result>
|
||||
0.000000 MetaHookPost CallFunction(Analyzer::register_for_ports, <frame>, (Analyzer::ANALYZER_HTTP, {631<...>/tcp})) -> <no result>
|
||||
|
@ -125,6 +128,7 @@
|
|||
0.000000 MetaHookPost CallFunction(Cluster::is_enabled, <frame>, ()) -> <no result>
|
||||
0.000000 MetaHookPost CallFunction(Cluster::is_enabled, <null>, ()) -> <no result>
|
||||
0.000000 MetaHookPost CallFunction(Files::register_analyzer_add_callback, <frame>, (Files::ANALYZER_EXTRACT, FileExtract::on_add{ if (!FileExtract::args?$extract_filename) FileExtract::args$extract_filename = cat(extract-, FileExtract::f$last_active, -, FileExtract::f$source, -, FileExtract::f$id)FileExtract::f$info$extracted = FileExtract::args$extract_filenameFileExtract::args$extract_filename = build_path_compressed(FileExtract::prefix, FileExtract::args$extract_filename)mkdir(FileExtract::prefix)})) -> <no result>
|
||||
0.000000 MetaHookPost CallFunction(Files::register_protocol, <frame>, (Analyzer::ANALYZER_DTLS, [get_file_handle=SSL::get_file_handle{ return ()}, describe=SSL::describe_file{ <init> SSL::cid{ if (SSL::f$source != SSL || !SSL::f?$info || !SSL::f$info?$x509 || !SSL::f$info$x509?$certificate) return ()for ([SSL::cid] in SSL::f$conns) { if (SSL::f$conns[SSL::cid]?$ssl) { SSL::c = SSL::f$conns[SSL::cid]return (cat(SSL::c$id$resp_h, :, SSL::c$id$resp_p))}}return (cat(Serial: , SSL::f$info$x509$certificate$serial, Subject: , SSL::f$info$x509$certificate$subject, Issuer: , SSL::f$info$x509$certificate$issuer))}}])) -> <no result>
|
||||
0.000000 MetaHookPost CallFunction(Files::register_protocol, <frame>, (Analyzer::ANALYZER_FTP_DATA, [get_file_handle=FTP::get_file_handle{ if (!FTP::c$id$resp_h, FTP::c$id$resp_p in FTP::ftp_data_expected) return ()return (cat(Analyzer::ANALYZER_FTP_DATA, FTP::c$start_time, FTP::c$id, FTP::is_orig))}, describe=FTP::describe_file{ <init> FTP::cid{ if (FTP::f$source != FTP) return ()for ([FTP::cid] in FTP::f$conns) { if (FTP::f$conns[FTP::cid]?$ftp) return (FTP::describe(FTP::f$conns[FTP::cid]$ftp))}return ()}}])) -> <no result>
|
||||
0.000000 MetaHookPost CallFunction(Files::register_protocol, <frame>, (Analyzer::ANALYZER_HTTP, [get_file_handle=HTTP::get_file_handle{ if (!HTTP::c?$http) return ()if (HTTP::c$http$range_request && !HTTP::is_orig) { return (cat(Analyzer::ANALYZER_HTTP, HTTP::is_orig, HTTP::c$id$orig_h, HTTP::build_url(HTTP::c$http)))}else{ HTTP::mime_depth = HTTP::is_orig ? HTTP::c$http$orig_mime_depth : HTTP::c$http$resp_mime_depthreturn (cat(Analyzer::ANALYZER_HTTP, HTTP::c$start_time, HTTP::is_orig, HTTP::c$http$trans_depth, HTTP::mime_depth, id_string(HTTP::c$id)))}}, describe=HTTP::describe_file{ <init> HTTP::cid{ if (HTTP::f$source != HTTP) return ()for ([HTTP::cid] in HTTP::f$conns) { if (HTTP::f$conns[HTTP::cid]?$http) return (HTTP::build_url_http(HTTP::f$conns[HTTP::cid]$http))}return ()}}])) -> <no result>
|
||||
0.000000 MetaHookPost CallFunction(Files::register_protocol, <frame>, (Analyzer::ANALYZER_IRC_DATA, [get_file_handle=IRC::get_file_handle{ return (cat(Analyzer::ANALYZER_IRC_DATA, IRC::c$start_time, IRC::c$id, IRC::is_orig))}, describe=anonymous-function{ return ()}])) -> <no result>
|
||||
|
@ -192,7 +196,7 @@
|
|||
0.000000 MetaHookPost CallFunction(Log::__create_stream, <frame>, (Weird::LOG, [columns=<no value description>, ev=Weird::log_weird, path=weird])) -> <no result>
|
||||
0.000000 MetaHookPost CallFunction(Log::__create_stream, <frame>, (X509::LOG, [columns=<no value description>, ev=X509::log_x509, path=x509])) -> <no result>
|
||||
0.000000 MetaHookPost CallFunction(Log::__create_stream, <frame>, (mysql::LOG, [columns=<no value description>, ev=MySQL::log_mysql, path=mysql])) -> <no result>
|
||||
0.000000 MetaHookPost CallFunction(Log::__write, <frame>, (PacketFilter::LOG, [ts=1426793275.574315, node=bro, filter=ip or not ip, init=T, success=T])) -> <no result>
|
||||
0.000000 MetaHookPost CallFunction(Log::__write, <frame>, (PacketFilter::LOG, [ts=1427139545.064324, node=bro, filter=ip or not ip, init=T, success=T])) -> <no result>
|
||||
0.000000 MetaHookPost CallFunction(Log::add_default_filter, <frame>, (Cluster::LOG)) -> <no result>
|
||||
0.000000 MetaHookPost CallFunction(Log::add_default_filter, <frame>, (Communication::LOG)) -> <no result>
|
||||
0.000000 MetaHookPost CallFunction(Log::add_default_filter, <frame>, (Conn::LOG)) -> <no result>
|
||||
|
@ -286,7 +290,7 @@
|
|||
0.000000 MetaHookPost CallFunction(Log::create_stream, <frame>, (Weird::LOG, [columns=<no value description>, ev=Weird::log_weird, path=weird])) -> <no result>
|
||||
0.000000 MetaHookPost CallFunction(Log::create_stream, <frame>, (X509::LOG, [columns=<no value description>, ev=X509::log_x509, path=x509])) -> <no result>
|
||||
0.000000 MetaHookPost CallFunction(Log::create_stream, <frame>, (mysql::LOG, [columns=<no value description>, ev=MySQL::log_mysql, path=mysql])) -> <no result>
|
||||
0.000000 MetaHookPost CallFunction(Log::write, <frame>, (PacketFilter::LOG, [ts=1426793275.574315, node=bro, filter=ip or not ip, init=T, success=T])) -> <no result>
|
||||
0.000000 MetaHookPost CallFunction(Log::write, <frame>, (PacketFilter::LOG, [ts=1427139545.064324, node=bro, filter=ip or not ip, init=T, success=T])) -> <no result>
|
||||
0.000000 MetaHookPost CallFunction(Notice::want_pp, <frame>, ()) -> <no result>
|
||||
0.000000 MetaHookPost CallFunction(PacketFilter::build, <frame>, ()) -> <no result>
|
||||
0.000000 MetaHookPost CallFunction(PacketFilter::combine_filters, <frame>, (ip or not ip, and, )) -> <no result>
|
||||
|
@ -549,6 +553,7 @@
|
|||
0.000000 MetaHookPre CallFunction(Analyzer::__register_for_port, <frame>, (Analyzer::ANALYZER_DNS, 53/udp))
|
||||
0.000000 MetaHookPre CallFunction(Analyzer::__register_for_port, <frame>, (Analyzer::ANALYZER_DNS, 5353/udp))
|
||||
0.000000 MetaHookPre CallFunction(Analyzer::__register_for_port, <frame>, (Analyzer::ANALYZER_DNS, 5355/udp))
|
||||
0.000000 MetaHookPre CallFunction(Analyzer::__register_for_port, <frame>, (Analyzer::ANALYZER_DTLS, 443/udp))
|
||||
0.000000 MetaHookPre CallFunction(Analyzer::__register_for_port, <frame>, (Analyzer::ANALYZER_FTP, 21/tcp))
|
||||
0.000000 MetaHookPre CallFunction(Analyzer::__register_for_port, <frame>, (Analyzer::ANALYZER_FTP, 2811/tcp))
|
||||
0.000000 MetaHookPre CallFunction(Analyzer::__register_for_port, <frame>, (Analyzer::ANALYZER_GTPV1, 2123/udp))
|
||||
|
@ -602,6 +607,7 @@
|
|||
0.000000 MetaHookPre CallFunction(Analyzer::register_for_port, <frame>, (Analyzer::ANALYZER_DNS, 53/udp))
|
||||
0.000000 MetaHookPre CallFunction(Analyzer::register_for_port, <frame>, (Analyzer::ANALYZER_DNS, 5353/udp))
|
||||
0.000000 MetaHookPre CallFunction(Analyzer::register_for_port, <frame>, (Analyzer::ANALYZER_DNS, 5355/udp))
|
||||
0.000000 MetaHookPre CallFunction(Analyzer::register_for_port, <frame>, (Analyzer::ANALYZER_DTLS, 443/udp))
|
||||
0.000000 MetaHookPre CallFunction(Analyzer::register_for_port, <frame>, (Analyzer::ANALYZER_FTP, 21/tcp))
|
||||
0.000000 MetaHookPre CallFunction(Analyzer::register_for_port, <frame>, (Analyzer::ANALYZER_FTP, 2811/tcp))
|
||||
0.000000 MetaHookPre CallFunction(Analyzer::register_for_port, <frame>, (Analyzer::ANALYZER_GTPV1, 2123/udp))
|
||||
|
@ -645,6 +651,7 @@
|
|||
0.000000 MetaHookPre CallFunction(Analyzer::register_for_ports, <frame>, (Analyzer::ANALYZER_DHCP, {67<...>/udp}))
|
||||
0.000000 MetaHookPre CallFunction(Analyzer::register_for_ports, <frame>, (Analyzer::ANALYZER_DNP3_TCP, {20000<...>/tcp}))
|
||||
0.000000 MetaHookPre CallFunction(Analyzer::register_for_ports, <frame>, (Analyzer::ANALYZER_DNS, {5355<...>/udp}))
|
||||
0.000000 MetaHookPre CallFunction(Analyzer::register_for_ports, <frame>, (Analyzer::ANALYZER_DTLS, {443/udp}))
|
||||
0.000000 MetaHookPre CallFunction(Analyzer::register_for_ports, <frame>, (Analyzer::ANALYZER_FTP, {2811<...>/tcp}))
|
||||
0.000000 MetaHookPre CallFunction(Analyzer::register_for_ports, <frame>, (Analyzer::ANALYZER_GTPV1, {2152<...>/udp}))
|
||||
0.000000 MetaHookPre CallFunction(Analyzer::register_for_ports, <frame>, (Analyzer::ANALYZER_HTTP, {631<...>/tcp}))
|
||||
|
@ -662,6 +669,7 @@
|
|||
0.000000 MetaHookPre CallFunction(Cluster::is_enabled, <frame>, ())
|
||||
0.000000 MetaHookPre CallFunction(Cluster::is_enabled, <null>, ())
|
||||
0.000000 MetaHookPre CallFunction(Files::register_analyzer_add_callback, <frame>, (Files::ANALYZER_EXTRACT, FileExtract::on_add{ if (!FileExtract::args?$extract_filename) FileExtract::args$extract_filename = cat(extract-, FileExtract::f$last_active, -, FileExtract::f$source, -, FileExtract::f$id)FileExtract::f$info$extracted = FileExtract::args$extract_filenameFileExtract::args$extract_filename = build_path_compressed(FileExtract::prefix, FileExtract::args$extract_filename)mkdir(FileExtract::prefix)}))
|
||||
0.000000 MetaHookPre CallFunction(Files::register_protocol, <frame>, (Analyzer::ANALYZER_DTLS, [get_file_handle=SSL::get_file_handle{ return ()}, describe=SSL::describe_file{ <init> SSL::cid{ if (SSL::f$source != SSL || !SSL::f?$info || !SSL::f$info?$x509 || !SSL::f$info$x509?$certificate) return ()for ([SSL::cid] in SSL::f$conns) { if (SSL::f$conns[SSL::cid]?$ssl) { SSL::c = SSL::f$conns[SSL::cid]return (cat(SSL::c$id$resp_h, :, SSL::c$id$resp_p))}}return (cat(Serial: , SSL::f$info$x509$certificate$serial, Subject: , SSL::f$info$x509$certificate$subject, Issuer: , SSL::f$info$x509$certificate$issuer))}}]))
|
||||
0.000000 MetaHookPre CallFunction(Files::register_protocol, <frame>, (Analyzer::ANALYZER_FTP_DATA, [get_file_handle=FTP::get_file_handle{ if (!FTP::c$id$resp_h, FTP::c$id$resp_p in FTP::ftp_data_expected) return ()return (cat(Analyzer::ANALYZER_FTP_DATA, FTP::c$start_time, FTP::c$id, FTP::is_orig))}, describe=FTP::describe_file{ <init> FTP::cid{ if (FTP::f$source != FTP) return ()for ([FTP::cid] in FTP::f$conns) { if (FTP::f$conns[FTP::cid]?$ftp) return (FTP::describe(FTP::f$conns[FTP::cid]$ftp))}return ()}}]))
|
||||
0.000000 MetaHookPre CallFunction(Files::register_protocol, <frame>, (Analyzer::ANALYZER_HTTP, [get_file_handle=HTTP::get_file_handle{ if (!HTTP::c?$http) return ()if (HTTP::c$http$range_request && !HTTP::is_orig) { return (cat(Analyzer::ANALYZER_HTTP, HTTP::is_orig, HTTP::c$id$orig_h, HTTP::build_url(HTTP::c$http)))}else{ HTTP::mime_depth = HTTP::is_orig ? HTTP::c$http$orig_mime_depth : HTTP::c$http$resp_mime_depthreturn (cat(Analyzer::ANALYZER_HTTP, HTTP::c$start_time, HTTP::is_orig, HTTP::c$http$trans_depth, HTTP::mime_depth, id_string(HTTP::c$id)))}}, describe=HTTP::describe_file{ <init> HTTP::cid{ if (HTTP::f$source != HTTP) return ()for ([HTTP::cid] in HTTP::f$conns) { if (HTTP::f$conns[HTTP::cid]?$http) return (HTTP::build_url_http(HTTP::f$conns[HTTP::cid]$http))}return ()}}]))
|
||||
0.000000 MetaHookPre CallFunction(Files::register_protocol, <frame>, (Analyzer::ANALYZER_IRC_DATA, [get_file_handle=IRC::get_file_handle{ return (cat(Analyzer::ANALYZER_IRC_DATA, IRC::c$start_time, IRC::c$id, IRC::is_orig))}, describe=anonymous-function{ return ()}]))
|
||||
|
@ -729,7 +737,7 @@
|
|||
0.000000 MetaHookPre CallFunction(Log::__create_stream, <frame>, (Weird::LOG, [columns=<no value description>, ev=Weird::log_weird, path=weird]))
|
||||
0.000000 MetaHookPre CallFunction(Log::__create_stream, <frame>, (X509::LOG, [columns=<no value description>, ev=X509::log_x509, path=x509]))
|
||||
0.000000 MetaHookPre CallFunction(Log::__create_stream, <frame>, (mysql::LOG, [columns=<no value description>, ev=MySQL::log_mysql, path=mysql]))
|
||||
0.000000 MetaHookPre CallFunction(Log::__write, <frame>, (PacketFilter::LOG, [ts=1426793275.574315, node=bro, filter=ip or not ip, init=T, success=T]))
|
||||
0.000000 MetaHookPre CallFunction(Log::__write, <frame>, (PacketFilter::LOG, [ts=1427139545.064324, node=bro, filter=ip or not ip, init=T, success=T]))
|
||||
0.000000 MetaHookPre CallFunction(Log::add_default_filter, <frame>, (Cluster::LOG))
|
||||
0.000000 MetaHookPre CallFunction(Log::add_default_filter, <frame>, (Communication::LOG))
|
||||
0.000000 MetaHookPre CallFunction(Log::add_default_filter, <frame>, (Conn::LOG))
|
||||
|
@ -823,7 +831,7 @@
|
|||
0.000000 MetaHookPre CallFunction(Log::create_stream, <frame>, (Weird::LOG, [columns=<no value description>, ev=Weird::log_weird, path=weird]))
|
||||
0.000000 MetaHookPre CallFunction(Log::create_stream, <frame>, (X509::LOG, [columns=<no value description>, ev=X509::log_x509, path=x509]))
|
||||
0.000000 MetaHookPre CallFunction(Log::create_stream, <frame>, (mysql::LOG, [columns=<no value description>, ev=MySQL::log_mysql, path=mysql]))
|
||||
0.000000 MetaHookPre CallFunction(Log::write, <frame>, (PacketFilter::LOG, [ts=1426793275.574315, node=bro, filter=ip or not ip, init=T, success=T]))
|
||||
0.000000 MetaHookPre CallFunction(Log::write, <frame>, (PacketFilter::LOG, [ts=1427139545.064324, node=bro, filter=ip or not ip, init=T, success=T]))
|
||||
0.000000 MetaHookPre CallFunction(Notice::want_pp, <frame>, ())
|
||||
0.000000 MetaHookPre CallFunction(PacketFilter::build, <frame>, ())
|
||||
0.000000 MetaHookPre CallFunction(PacketFilter::combine_filters, <frame>, (ip or not ip, and, ))
|
||||
|
@ -1086,6 +1094,7 @@
|
|||
0.000000 | HookCallFunction Analyzer::__register_for_port(Analyzer::ANALYZER_DNS, 53/udp)
|
||||
0.000000 | HookCallFunction Analyzer::__register_for_port(Analyzer::ANALYZER_DNS, 5353/udp)
|
||||
0.000000 | HookCallFunction Analyzer::__register_for_port(Analyzer::ANALYZER_DNS, 5355/udp)
|
||||
0.000000 | HookCallFunction Analyzer::__register_for_port(Analyzer::ANALYZER_DTLS, 443/udp)
|
||||
0.000000 | HookCallFunction Analyzer::__register_for_port(Analyzer::ANALYZER_FTP, 21/tcp)
|
||||
0.000000 | HookCallFunction Analyzer::__register_for_port(Analyzer::ANALYZER_FTP, 2811/tcp)
|
||||
0.000000 | HookCallFunction Analyzer::__register_for_port(Analyzer::ANALYZER_GTPV1, 2123/udp)
|
||||
|
@ -1139,6 +1148,7 @@
|
|||
0.000000 | HookCallFunction Analyzer::register_for_port(Analyzer::ANALYZER_DNS, 53/udp)
|
||||
0.000000 | HookCallFunction Analyzer::register_for_port(Analyzer::ANALYZER_DNS, 5353/udp)
|
||||
0.000000 | HookCallFunction Analyzer::register_for_port(Analyzer::ANALYZER_DNS, 5355/udp)
|
||||
0.000000 | HookCallFunction Analyzer::register_for_port(Analyzer::ANALYZER_DTLS, 443/udp)
|
||||
0.000000 | HookCallFunction Analyzer::register_for_port(Analyzer::ANALYZER_FTP, 21/tcp)
|
||||
0.000000 | HookCallFunction Analyzer::register_for_port(Analyzer::ANALYZER_FTP, 2811/tcp)
|
||||
0.000000 | HookCallFunction Analyzer::register_for_port(Analyzer::ANALYZER_GTPV1, 2123/udp)
|
||||
|
@ -1182,6 +1192,7 @@
|
|||
0.000000 | HookCallFunction Analyzer::register_for_ports(Analyzer::ANALYZER_DHCP, {67<...>/udp})
|
||||
0.000000 | HookCallFunction Analyzer::register_for_ports(Analyzer::ANALYZER_DNP3_TCP, {20000<...>/tcp})
|
||||
0.000000 | HookCallFunction Analyzer::register_for_ports(Analyzer::ANALYZER_DNS, {5355<...>/udp})
|
||||
0.000000 | HookCallFunction Analyzer::register_for_ports(Analyzer::ANALYZER_DTLS, {443/udp})
|
||||
0.000000 | HookCallFunction Analyzer::register_for_ports(Analyzer::ANALYZER_FTP, {2811<...>/tcp})
|
||||
0.000000 | HookCallFunction Analyzer::register_for_ports(Analyzer::ANALYZER_GTPV1, {2152<...>/udp})
|
||||
0.000000 | HookCallFunction Analyzer::register_for_ports(Analyzer::ANALYZER_HTTP, {631<...>/tcp})
|
||||
|
@ -1198,6 +1209,7 @@
|
|||
0.000000 | HookCallFunction Analyzer::register_for_ports(Analyzer::ANALYZER_TEREDO, {3544/udp})
|
||||
0.000000 | HookCallFunction Cluster::is_enabled()
|
||||
0.000000 | HookCallFunction Files::register_analyzer_add_callback(Files::ANALYZER_EXTRACT, FileExtract::on_add{ if (!FileExtract::args?$extract_filename) FileExtract::args$extract_filename = cat(extract-, FileExtract::f$last_active, -, FileExtract::f$source, -, FileExtract::f$id)FileExtract::f$info$extracted = FileExtract::args$extract_filenameFileExtract::args$extract_filename = build_path_compressed(FileExtract::prefix, FileExtract::args$extract_filename)mkdir(FileExtract::prefix)})
|
||||
0.000000 | HookCallFunction Files::register_protocol(Analyzer::ANALYZER_DTLS, [get_file_handle=SSL::get_file_handle{ return ()}, describe=SSL::describe_file{ <init> SSL::cid{ if (SSL::f$source != SSL || !SSL::f?$info || !SSL::f$info?$x509 || !SSL::f$info$x509?$certificate) return ()for ([SSL::cid] in SSL::f$conns) { if (SSL::f$conns[SSL::cid]?$ssl) { SSL::c = SSL::f$conns[SSL::cid]return (cat(SSL::c$id$resp_h, :, SSL::c$id$resp_p))}}return (cat(Serial: , SSL::f$info$x509$certificate$serial, Subject: , SSL::f$info$x509$certificate$subject, Issuer: , SSL::f$info$x509$certificate$issuer))}}])
|
||||
0.000000 | HookCallFunction Files::register_protocol(Analyzer::ANALYZER_FTP_DATA, [get_file_handle=FTP::get_file_handle{ if (!FTP::c$id$resp_h, FTP::c$id$resp_p in FTP::ftp_data_expected) return ()return (cat(Analyzer::ANALYZER_FTP_DATA, FTP::c$start_time, FTP::c$id, FTP::is_orig))}, describe=FTP::describe_file{ <init> FTP::cid{ if (FTP::f$source != FTP) return ()for ([FTP::cid] in FTP::f$conns) { if (FTP::f$conns[FTP::cid]?$ftp) return (FTP::describe(FTP::f$conns[FTP::cid]$ftp))}return ()}}])
|
||||
0.000000 | HookCallFunction Files::register_protocol(Analyzer::ANALYZER_HTTP, [get_file_handle=HTTP::get_file_handle{ if (!HTTP::c?$http) return ()if (HTTP::c$http$range_request && !HTTP::is_orig) { return (cat(Analyzer::ANALYZER_HTTP, HTTP::is_orig, HTTP::c$id$orig_h, HTTP::build_url(HTTP::c$http)))}else{ HTTP::mime_depth = HTTP::is_orig ? HTTP::c$http$orig_mime_depth : HTTP::c$http$resp_mime_depthreturn (cat(Analyzer::ANALYZER_HTTP, HTTP::c$start_time, HTTP::is_orig, HTTP::c$http$trans_depth, HTTP::mime_depth, id_string(HTTP::c$id)))}}, describe=HTTP::describe_file{ <init> HTTP::cid{ if (HTTP::f$source != HTTP) return ()for ([HTTP::cid] in HTTP::f$conns) { if (HTTP::f$conns[HTTP::cid]?$http) return (HTTP::build_url_http(HTTP::f$conns[HTTP::cid]$http))}return ()}}])
|
||||
0.000000 | HookCallFunction Files::register_protocol(Analyzer::ANALYZER_IRC_DATA, [get_file_handle=IRC::get_file_handle{ return (cat(Analyzer::ANALYZER_IRC_DATA, IRC::c$start_time, IRC::c$id, IRC::is_orig))}, describe=anonymous-function{ return ()}])
|
||||
|
@ -1265,7 +1277,7 @@
|
|||
0.000000 | HookCallFunction Log::__create_stream(Weird::LOG, [columns=<no value description>, ev=Weird::log_weird, path=weird])
|
||||
0.000000 | HookCallFunction Log::__create_stream(X509::LOG, [columns=<no value description>, ev=X509::log_x509, path=x509])
|
||||
0.000000 | HookCallFunction Log::__create_stream(mysql::LOG, [columns=<no value description>, ev=MySQL::log_mysql, path=mysql])
|
||||
0.000000 | HookCallFunction Log::__write(PacketFilter::LOG, [ts=1426793275.574315, node=bro, filter=ip or not ip, init=T, success=T])
|
||||
0.000000 | HookCallFunction Log::__write(PacketFilter::LOG, [ts=1427139545.064324, node=bro, filter=ip or not ip, init=T, success=T])
|
||||
0.000000 | HookCallFunction Log::add_default_filter(Cluster::LOG)
|
||||
0.000000 | HookCallFunction Log::add_default_filter(Communication::LOG)
|
||||
0.000000 | HookCallFunction Log::add_default_filter(Conn::LOG)
|
||||
|
@ -1359,7 +1371,7 @@
|
|||
0.000000 | HookCallFunction Log::create_stream(Weird::LOG, [columns=<no value description>, ev=Weird::log_weird, path=weird])
|
||||
0.000000 | HookCallFunction Log::create_stream(X509::LOG, [columns=<no value description>, ev=X509::log_x509, path=x509])
|
||||
0.000000 | HookCallFunction Log::create_stream(mysql::LOG, [columns=<no value description>, ev=MySQL::log_mysql, path=mysql])
|
||||
0.000000 | HookCallFunction Log::write(PacketFilter::LOG, [ts=1426793275.574315, node=bro, filter=ip or not ip, init=T, success=T])
|
||||
0.000000 | HookCallFunction Log::write(PacketFilter::LOG, [ts=1427139545.064324, node=bro, filter=ip or not ip, init=T, success=T])
|
||||
0.000000 | HookCallFunction Notice::want_pp()
|
||||
0.000000 | HookCallFunction PacketFilter::build()
|
||||
0.000000 | HookCallFunction PacketFilter::combine_filters(ip or not ip, and, )
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
#separator \x09
|
||||
#set_separator ,
|
||||
#empty_field (empty)
|
||||
#unset_field -
|
||||
#path ssl
|
||||
#open 2015-03-12-22-40-14
|
||||
#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p version cipher curve server_name resumed last_alert next_protocol established cert_chain_fuids client_cert_chain_fuids subject issuer client_subject client_issuer
|
||||
#types time string addr port addr port string string string string bool string string bool vector[string] vector[string] string string string string
|
||||
1425932016.520157 CXWv6p3arKYeMETxOg 192.168.6.86 63721 104.236.167.107 4433 DTLSv10 TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA secp256r1 - F - - T FZi2Ct2AcCswhiIjKe (empty) CN=bro CN=bro - -
|
||||
#close 2015-03-12-22-40-14
|
|
@ -0,0 +1,10 @@
|
|||
#separator \x09
|
||||
#set_separator ,
|
||||
#empty_field (empty)
|
||||
#unset_field -
|
||||
#path x509
|
||||
#open 2015-03-12-22-40-14
|
||||
#fields ts id certificate.version certificate.serial certificate.subject certificate.issuer certificate.not_valid_before certificate.not_valid_after certificate.key_alg certificate.sig_alg certificate.key_type certificate.key_length certificate.exponent certificate.curve san.dns san.uri san.email san.ip basic_constraints.ca basic_constraints.path_len
|
||||
#types time string count string string string time time string string string count string string vector[string] vector[string] vector[string] vector[addr] bool count
|
||||
1425932016.611299 FZi2Ct2AcCswhiIjKe 3 E8E48E456C32945F CN=bro CN=bro 1425931873.000000 1457467873.000000 rsaEncryption sha1WithRSAEncryption rsa 2048 65537 - - - - - T -
|
||||
#close 2015-03-12-22-40-14
|
|
@ -0,0 +1 @@
|
|||
10000
|
|
@ -0,0 +1,10 @@
|
|||
#separator \x09
|
||||
#set_separator ,
|
||||
#empty_field (empty)
|
||||
#unset_field -
|
||||
#path ssl
|
||||
#open 2015-03-12-01-22-34
|
||||
#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p version cipher curve server_name resumed last_alert next_protocol established cert_chain_fuids client_cert_chain_fuids subject issuer client_subject client_issuer
|
||||
#types time string addr port addr port string string string string bool string string bool vector[string] vector[string] string string string string
|
||||
1426117218.083491 CXWv6p3arKYeMETxOg 192.168.6.86 61454 104.236.167.107 4433 TLSv12 TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 secp256r1 104.236.167.107 F - - F FsQdqWuF9t3e4W0d (empty) - - - -
|
||||
#close 2015-03-12-01-22-34
|
BIN
testing/btest/Traces/tls/dtls-openssl.pcap
Normal file
BIN
testing/btest/Traces/tls/dtls-openssl.pcap
Normal file
Binary file not shown.
BIN
testing/btest/Traces/tls/tls-fragmented-handshake.pcap.gz
Normal file
BIN
testing/btest/Traces/tls/tls-fragmented-handshake.pcap.gz
Normal file
Binary file not shown.
15
testing/btest/core/leaks/dtls.bro
Normal file
15
testing/btest/core/leaks/dtls.bro
Normal file
|
@ -0,0 +1,15 @@
|
|||
# Needs perftools support.
|
||||
#
|
||||
# @TEST-GROUP: leaks
|
||||
#
|
||||
# @TEST-REQUIRES: bro --help 2>&1 | grep -q mem-leaks
|
||||
#
|
||||
# @TEST-EXEC: HEAP_CHECK_DUMP_DIRECTORY=. HEAPCHECK=local btest-bg-run bro bro -b -m -r $TRACES/tls/dtls-openssl.pcap %INPUT
|
||||
# @TEST-EXEC: btest-bg-wait 30
|
||||
|
||||
@load base/protocols/ssl
|
||||
|
||||
event ssl_established(c: connection) &priority=3
|
||||
{
|
||||
print "established";
|
||||
}
|
5
testing/btest/scripts/base/protocols/ssl/dtls.test
Normal file
5
testing/btest/scripts/base/protocols/ssl/dtls.test
Normal file
|
@ -0,0 +1,5 @@
|
|||
# This tests a normal SSL connection and the log it outputs.
|
||||
|
||||
# @TEST-EXEC: bro -r $TRACES/tls/dtls-openssl.pcap %INPUT
|
||||
# @TEST-EXEC: btest-diff ssl.log
|
||||
# @TEST-EXEC: btest-diff x509.log
|
12
testing/btest/scripts/base/protocols/ssl/fragment.test
Normal file
12
testing/btest/scripts/base/protocols/ssl/fragment.test
Normal file
|
@ -0,0 +1,12 @@
|
|||
# Test a heavily fragmented tls connection
|
||||
|
||||
# @TEST-EXEC: cat $TRACES/tls/tls-fragmented-handshake.pcap.gz | gunzip | bro -r - %INPUT
|
||||
# @TEST-EXEC: btest-diff ssl.log
|
||||
# @TEST-EXEC: btest-diff .stdout
|
||||
|
||||
# Certificate has 10,000 alternative names :)
|
||||
event x509_ext_subject_alternative_name(f: fa_file, ext: X509::SubjectAlternativeName)
|
||||
{
|
||||
print |ext$dns|;
|
||||
}
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue