rip out state handline from ssl analyzer.

still seems to work, but basically untested.
This commit is contained in:
Bernhard Amann 2014-04-10 15:11:43 -07:00
parent 285ef548ff
commit cc838c6b2e
2 changed files with 55 additions and 273 deletions

View file

@ -107,25 +107,6 @@ refine connection SSL_Conn += {
%cleanup{
%}
function proc_change_cipher_spec(rec: SSLRecord) : bool
%{
if ( state_ == STATE_TRACK_LOST )
bro_analyzer()->ProtocolViolation(fmt("unexpected ChangeCipherSpec from %s at state %s",
orig_label(${rec.is_orig}).c_str(),
state_label(old_state_).c_str()));
return true;
%}
function proc_application_data(rec: SSLRecord) : bool
%{
if ( state_ != STATE_CONN_ESTABLISHED &&
(state_ != STATE_CLIENT_FINISHED && ! ${rec.is_orig}) )
bro_analyzer()->ProtocolViolation(fmt("unexpected ApplicationData from %s at state %s",
orig_label(${rec.is_orig}).c_str(),
state_label(old_state_).c_str()));
return true;
%}
function proc_alert(rec: SSLRecord, level : int, desc : int) : bool
%{
BifEvent::generate_ssl_alert(bro_analyzer(), bro_analyzer()->Conn(),
@ -267,11 +248,6 @@ refine connection SSL_Conn += {
function proc_v2_client_master_key(rec: SSLRecord, cipher_kind: int) : bool
%{
if ( state_ == STATE_TRACK_LOST )
bro_analyzer()->ProtocolViolation(fmt("unexpected v2 client master key message from %s in state %s",
orig_label(${rec.is_orig}).c_str(),
state_label(old_state_).c_str()));
BifEvent::generate_ssl_established(bro_analyzer(),
bro_analyzer()->Conn());
@ -285,17 +261,6 @@ refine connection SSL_Conn += {
return true;
%}
function proc_handshake(hs: Handshake, is_orig: bool) : bool
%{
if ( state_ == STATE_TRACK_LOST )
bro_analyzer()->ProtocolViolation(fmt("unexpected Handshake message %s from %s in state %s",
handshake_type_label(${hs.msg_type}).c_str(),
orig_label(is_orig).c_str(),
state_label(old_state_).c_str()));
return true;
%}
function proc_unknown_record(rec: SSLRecord) : bool
%{
bro_analyzer()->ProtocolViolation(fmt("unknown SSL record type (%d) from %s",
@ -306,13 +271,8 @@ refine connection SSL_Conn += {
function proc_ciphertext_record(rec : SSLRecord) : bool
%{
if ( state_ == STATE_TRACK_LOST )
bro_analyzer()->ProtocolViolation(fmt("unexpected ciphertext record from %s in state %s",
orig_label(${rec.is_orig}).c_str(),
state_label(old_state_).c_str()));
else if ( state_ == STATE_CONN_ESTABLISHED &&
old_state_ == STATE_COMM_ENCRYPTED )
if ( client_state_ == STATE_ENCRYPTED &&
server_state_ == STATE_ENCRYPTED )
{
BifEvent::generate_ssl_established(bro_analyzer(),
bro_analyzer()->Conn());
@ -322,10 +282,10 @@ refine connection SSL_Conn += {
%}
};
refine typeattr ChangeCipherSpec += &let {
proc : bool = $context.connection.proc_change_cipher_spec(rec)
&requires(state_changed);
};
#refine typeattr ChangeCipherSpec += &let {
# proc : bool = $context.connection.proc_change_cipher_spec(rec)
# &requires(state_changed);
#};
refine typeattr Alert += &let {
proc : bool = $context.connection.proc_alert(rec, level, description);
@ -335,42 +295,37 @@ refine typeattr V2Error += &let {
proc : bool = $context.connection.proc_alert(rec, -1, error_code);
};
refine typeattr ApplicationData += &let {
proc : bool = $context.connection.proc_application_data(rec);
};
#refine typeattr ApplicationData += &let {
# proc : bool = $context.connection.proc_application_data(rec);
#};
refine typeattr ClientHello += &let {
proc : bool = $context.connection.proc_client_hello(rec, client_version,
gmt_unix_time, random_bytes,
session_id, csuits, 0)
&requires(state_changed);
session_id, csuits, 0);
};
refine typeattr V2ClientHello += &let {
proc : bool = $context.connection.proc_client_hello(rec, client_version, 0,
challenge, session_id, 0, ciphers)
&requires(state_changed);
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)
&requires(state_changed);
compression_method);
};
refine typeattr V2ServerHello += &let {
proc : bool = $context.connection.proc_server_hello(rec, server_version, 0,
conn_id_data, 0, 0, ciphers, 0)
&requires(state_changed);
conn_id_data, 0, 0, ciphers, 0);
cert : bool = $context.connection.proc_v2_certificate(rec, cert_data)
&requires(proc);
};
refine typeattr Certificate += &let {
proc : bool = $context.connection.proc_v3_certificate(rec, certificates)
&requires(state_changed);
proc : bool = $context.connection.proc_v3_certificate(rec, certificates);
};
refine typeattr V2ClientMasterKey += &let {
@ -382,9 +337,9 @@ refine typeattr UnknownHandshake += &let {
proc : bool = $context.connection.proc_unknown_handshake(hs, is_orig);
};
refine typeattr Handshake += &let {
proc : bool = $context.connection.proc_handshake(this, rec.is_orig);
};
#refine typeattr Handshake += &let {
# proc : bool = $context.connection.proc_handshake(this, rec.is_orig);
#};
refine typeattr SessionTicketHandshake += &let {
proc : bool = $context.connection.proc_session_ticket_handshake(this, rec.is_orig);

View file

@ -34,7 +34,7 @@ type SSLRecord(is_orig: bool) = record {
head4 : uint8;
rec : RecordText(this)[] &length=length, &requires(content_type);
} &length = length+5, &byteorder=bigendian,
&let {
&let {
version : int =
$context.connection.determine_ssl_version(head0, head1, head2);
@ -51,9 +51,8 @@ type SSLRecord(is_orig: bool) = record {
};
};
type RecordText(rec: SSLRecord) = case $context.connection.state() of {
STATE_ABBREV_SERVER_ENCRYPTED, STATE_CLIENT_ENCRYPTED,
STATE_COMM_ENCRYPTED, STATE_CONN_ESTABLISHED
type RecordText(rec: SSLRecord) = case $context.connection.state(rec.is_orig) of {
STATE_ENCRYPTED
-> ciphertext : CiphertextRecord(rec);
default
-> plaintext : PlaintextRecord(rec);
@ -82,64 +81,18 @@ type SSLExtension(rec: SSLRecord) = record {
######################################################################
enum AnalyzerState {
STATE_INITIAL,
STATE_CLIENT_HELLO_RCVD,
STATE_IN_SERVER_HELLO,
STATE_SERVER_HELLO_DONE,
STATE_CLIENT_CERT,
STATE_CLIENT_KEY_WITH_CERT,
STATE_CLIENT_KEY_NO_CERT,
STATE_CLIENT_CERT_VERIFIED,
STATE_CLIENT_ENCRYPTED,
STATE_CLIENT_FINISHED,
STATE_ABBREV_SERVER_ENCRYPTED,
STATE_ABBREV_SERVER_FINISHED,
STATE_COMM_ENCRYPTED,
STATE_CONN_ESTABLISHED,
STATE_V2_CL_MASTER_KEY_EXPECTED,
STATE_TRACK_LOST,
STATE_ANY
STATE_CLEAR,
STATE_ENCRYPTED
};
%code{
string state_label(int state_nr)
{
switch ( state_nr ) {
case STATE_INITIAL:
return string("INITIAL");
case STATE_CLIENT_HELLO_RCVD:
return string("CLIENT_HELLO_RCVD");
case STATE_IN_SERVER_HELLO:
return string("IN_SERVER_HELLO");
case STATE_SERVER_HELLO_DONE:
return string("SERVER_HELLO_DONE");
case STATE_CLIENT_CERT:
return string("CLIENT_CERT");
case STATE_CLIENT_KEY_WITH_CERT:
return string("CLIENT_KEY_WITH_CERT");
case STATE_CLIENT_KEY_NO_CERT:
return string("CLIENT_KEY_NO_CERT");
case STATE_CLIENT_CERT_VERIFIED:
return string("CLIENT_CERT_VERIFIED");
case STATE_CLIENT_ENCRYPTED:
return string("CLIENT_ENCRYPTED");
case STATE_CLIENT_FINISHED:
return string("CLIENT_FINISHED");
case STATE_ABBREV_SERVER_ENCRYPTED:
return string("ABBREV_SERVER_ENCRYPTED");
case STATE_ABBREV_SERVER_FINISHED:
return string("ABBREV_SERVER_FINISHED");
case STATE_COMM_ENCRYPTED:
return string("COMM_ENCRYPTED");
case STATE_CONN_ESTABLISHED:
return string("CONN_ESTABLISHED");
case STATE_V2_CL_MASTER_KEY_EXPECTED:
return string("STATE_V2_CL_MASTER_KEY_EXPECTED");
case STATE_TRACK_LOST:
return string("TRACK_LOST");
case STATE_ANY:
return string("ANY");
case STATE_CLEAR:
return string("CLEAR");
case STATE_ENCRYPTED:
return string("ENCRYPTED");
default:
return string(fmt("UNKNOWN (%d)", state_nr));
@ -176,21 +129,7 @@ type ChangeCipherSpec(rec: SSLRecord) = record {
type : uint8;
} &length = 1, &let {
state_changed : bool =
$context.connection.transition(STATE_CLIENT_FINISHED,
STATE_COMM_ENCRYPTED, rec.is_orig, false) ||
$context.connection.transition(STATE_IN_SERVER_HELLO,
STATE_ABBREV_SERVER_ENCRYPTED, rec.is_orig, false) ||
$context.connection.transition(STATE_CLIENT_KEY_NO_CERT,
STATE_CLIENT_ENCRYPTED, rec.is_orig, true) ||
$context.connection.transition(STATE_CLIENT_CERT_VERIFIED,
STATE_CLIENT_ENCRYPTED, rec.is_orig, true) ||
$context.connection.transition(STATE_CLIENT_CERT,
STATE_CLIENT_ENCRYPTED, rec.is_orig, true) ||
$context.connection.transition(STATE_CLIENT_KEY_WITH_CERT,
STATE_CLIENT_ENCRYPTED, rec.is_orig, true) ||
$context.connection.transition(STATE_ABBREV_SERVER_FINISHED,
STATE_COMM_ENCRYPTED, rec.is_orig, true) ||
$context.connection.lost_track();
$context.connection.startEncryption(rec.is_orig);
};
@ -209,7 +148,7 @@ type Alert(rec: SSLRecord) = record {
######################################################################
type V2Error(rec: SSLRecord) = record {
data: bytestring &restofdata &transient;
data : bytestring &restofdata &transient;
} &let {
error_code : uint16 = ((rec.head3 << 8) | rec.head4);
};
@ -234,9 +173,7 @@ type ApplicationData(rec: SSLRecord) = record {
######################################################################
# Hello Request is empty
type HelloRequest(rec: SSLRecord) = empty &let {
hr: bool = $context.connection.set_hello_requested(true);
};
type HelloRequest(rec: SSLRecord) = empty;
######################################################################
@ -257,13 +194,6 @@ type ClientHello(rec: SSLRecord) = record {
# of the following fields.
ext_len: uint16[] &until($element == 0 || $element != 0);
extensions : SSLExtension(rec)[] &until($input.length() == 0);
} &let {
state_changed : bool =
$context.connection.transition(STATE_INITIAL,
STATE_CLIENT_HELLO_RCVD, rec.is_orig, true) ||
($context.connection.hello_requested() &&
$context.connection.transition(STATE_ANY, STATE_CLIENT_HELLO_RCVD, rec.is_orig, true)) ||
$context.connection.lost_track();
};
@ -279,13 +209,6 @@ type V2ClientHello(rec: SSLRecord) = record {
session_id : uint8[session_len];
challenge : bytestring &length = chal_len;
} &length = 6 + csuit_len + session_len + chal_len, &let {
state_changed : bool =
$context.connection.transition(STATE_INITIAL,
STATE_CLIENT_HELLO_RCVD, rec.is_orig, true) ||
($context.connection.hello_requested() &&
$context.connection.transition(STATE_ANY, STATE_CLIENT_HELLO_RCVD, rec.is_orig, true)) ||
$context.connection.lost_track();
client_version : int = rec.version;
};
@ -306,11 +229,6 @@ type ServerHello(rec: SSLRecord) = record {
# of the following fields.
ext_len: uint16[] &until($element == 0 || $element != 0);
extensions : SSLExtension(rec)[] &until($input.length() == 0);
} &let {
state_changed : bool =
$context.connection.transition(STATE_CLIENT_HELLO_RCVD,
STATE_IN_SERVER_HELLO, rec.is_orig, false) ||
$context.connection.lost_track();
};
@ -329,14 +247,6 @@ type V2ServerHello(rec: SSLRecord) = record {
ciphers : uint24[ciph_len/3];
conn_id_data : bytestring &length = conn_id_len;
} &let {
state_changed : bool =
(session_id_hit > 0 ?
$context.connection.transition(STATE_CLIENT_HELLO_RCVD,
STATE_CONN_ESTABLISHED, rec.is_orig, false) :
$context.connection.transition(STATE_CLIENT_HELLO_RCVD,
STATE_V2_CL_MASTER_KEY_EXPECTED, rec.is_orig, false)) ||
$context.connection.lost_track();
session_id_hit : uint8 = rec.head3;
cert_type : uint8 = rec.head4;
};
@ -357,12 +267,10 @@ type Certificate(rec: SSLRecord) = record {
length : uint24;
certificates : CertificateList &length = to_int()(length);
} &let {
state_changed : bool =
$context.connection.transition(STATE_IN_SERVER_HELLO,
STATE_IN_SERVER_HELLO, rec.is_orig, false) ||
$context.connection.transition(STATE_SERVER_HELLO_DONE,
STATE_CLIENT_CERT, rec.is_orig, true) ||
$context.connection.lost_track();
state_changed_client : bool =
$context.connection.startEncryption(true);
state_changed_server : bool =
$context.connection.startEncryption(false);
};
@ -373,11 +281,6 @@ type Certificate(rec: SSLRecord) = record {
# For now ignore details; just eat up complete message
type ServerKeyExchange(rec: SSLRecord) = record {
key : bytestring &restofdata &transient;
} &let {
state_changed : bool =
$context.connection.transition(STATE_IN_SERVER_HELLO,
STATE_IN_SERVER_HELLO, rec.is_orig, false) ||
$context.connection.lost_track();
};
@ -388,11 +291,6 @@ type ServerKeyExchange(rec: SSLRecord) = record {
# For now, ignore Certificate Request Details; just eat up message.
type CertificateRequest(rec: SSLRecord) = record {
cont : bytestring &restofdata &transient;
} &let {
state_changed : bool =
$context.connection.transition(STATE_IN_SERVER_HELLO,
STATE_IN_SERVER_HELLO, rec.is_orig, false) ||
$context.connection.lost_track();
};
@ -401,12 +299,7 @@ type CertificateRequest(rec: SSLRecord) = record {
######################################################################
# Server Hello Done is empty
type ServerHelloDone(rec: SSLRecord) = empty &let {
state_changed : bool =
$context.connection.transition(STATE_IN_SERVER_HELLO,
STATE_SERVER_HELLO_DONE, rec.is_orig, false) ||
$context.connection.lost_track();
};
type ServerHelloDone(rec: SSLRecord) = empty;
######################################################################
@ -425,15 +318,6 @@ type ServerHelloDone(rec: SSLRecord) = empty &let {
# encrypted anyway); just eat up message.
type ClientKeyExchange(rec: SSLRecord) = record {
key : bytestring &restofdata &transient;
} &let {
state_changed : bool =
$context.connection.transition(STATE_SERVER_HELLO_DONE,
STATE_CLIENT_KEY_NO_CERT, rec.is_orig, true) ||
$context.connection.transition(STATE_CLIENT_CERT,
STATE_CLIENT_KEY_WITH_CERT, rec.is_orig, true) ||
$context.connection.transition(STATE_CLIENT_CERT,
STATE_CLIENT_KEY_WITH_CERT, rec.is_orig, true) ||
$context.connection.lost_track();
};
######################################################################
@ -449,11 +333,6 @@ type V2ClientMasterKey(rec: SSLRecord) = record {
en_key_data : bytestring &length = en_key_len &transient;
key_arg_data : bytestring &length = key_arg_len &transient;
} &length = 7 + cl_key_len + en_key_len + key_arg_len, &let {
state_changed : bool =
$context.connection.transition(STATE_V2_CL_MASTER_KEY_EXPECTED,
STATE_CONN_ESTABLISHED, rec.is_orig, true) ||
$context.connection.lost_track();
cipher_kind : int = (((rec.head3 << 16) | (rec.head4 << 8)) | cipher_kind_8);
};
@ -465,11 +344,6 @@ type V2ClientMasterKey(rec: SSLRecord) = record {
# For now, ignore Certificate Verify; just eat up the message.
type CertificateVerify(rec: SSLRecord) = record {
cont : bytestring &restofdata &transient;
} &let {
state_changed : bool =
$context.connection.transition(STATE_CLIENT_KEY_WITH_CERT,
STATE_CLIENT_CERT_VERIFIED, rec.is_orig, true) ||
$context.connection.lost_track();
};
@ -481,13 +355,6 @@ type CertificateVerify(rec: SSLRecord) = record {
# so we will not be able to read those messages.
type Finished(rec: SSLRecord) = record {
cont : bytestring &restofdata &transient;
} &let {
state_changed : bool =
$context.connection.transition(STATE_SERVER_HELLO_DONE,
STATE_COMM_ENCRYPTED, rec.is_orig, true) ||
$context.connection.transition(STATE_CLIENT_FINISHED,
STATE_COMM_ENCRYPTED, rec.is_orig, false) ||
$context.connection.lost_track();
};
type SessionTicketHandshake(rec: SSLRecord) = record {
@ -499,10 +366,8 @@ type SessionTicketHandshake(rec: SSLRecord) = record {
# V3 Handshake Protocol (7.)
######################################################################
type UnknownHandshake(hs: Handshake, is_orig: bool) = record {
type UnknownHandshake(hs: Handshake, is_orig: bool) = record {
data : bytestring &restofdata &transient;
} &let {
state_changed : bool = $context.connection.lost_track();
};
type Handshake(rec: SSLRecord) = record {
@ -532,33 +397,12 @@ type Handshake(rec: SSLRecord) = record {
# Fragmentation (6.2.1.)
######################################################################
type UnknownRecord(rec: SSLRecord) = record {
type UnknownRecord(rec: SSLRecord) = record {
cont : bytestring &restofdata &transient;
} &let {
state_changed : bool = $context.connection.lost_track();
};
type CiphertextRecord(rec: SSLRecord) = record {
cont : bytestring &restofdata &transient;
} &let {
state_changed : bool =
$context.connection.transition(STATE_CLIENT_FINISHED,
STATE_CLIENT_FINISHED, rec.is_orig, false) ||
$context.connection.transition(STATE_CLIENT_FINISHED,
STATE_CLIENT_FINISHED, rec.is_orig, true) ||
$context.connection.transition(STATE_ABBREV_SERVER_ENCRYPTED,
STATE_ABBREV_SERVER_FINISHED, rec.is_orig, false) ||
$context.connection.transition(STATE_CLIENT_ENCRYPTED,
STATE_CLIENT_FINISHED, rec.is_orig, true) ||
$context.connection.transition(STATE_COMM_ENCRYPTED,
STATE_CONN_ESTABLISHED, rec.is_orig, false) ||
$context.connection.transition(STATE_COMM_ENCRYPTED,
STATE_CONN_ESTABLISHED, rec.is_orig, true) ||
$context.connection.transition(STATE_CONN_ESTABLISHED,
STATE_CONN_ESTABLISHED, rec.is_orig, false) ||
$context.connection.transition(STATE_CONN_ESTABLISHED,
STATE_CONN_ESTABLISHED, rec.is_orig, true) ||
$context.connection.lost_track();
};
@ -578,22 +422,22 @@ type SSLPDU(is_orig: bool) = record {
refine connection SSL_Conn += {
%member{
int state_;
int client_state_;
int server_state_;
int old_state_;
bool hello_requested_;
%}
%init{
state_ = STATE_INITIAL;
old_state_ = STATE_INITIAL;
hello_requested_ = false;
server_state_ = STATE_CLEAR;
client_state_ = STATE_CLEAR;
%}
function determine_ssl_version(head0 : uint8, head1 : uint8,
head2 : uint8) : int
%{
if ( head0 >= 20 && head0 <= 23 &&
head1 == 0x03 && head2 <= 0x03 )
head1 == 0x03 && head2 <= 0x03 )
// This is most probably SSL version 3.
return (head1 << 8) | head2;
@ -606,39 +450,22 @@ refine connection SSL_Conn += {
return UNKNOWN_VERSION;
%}
function state() : int %{ return state_; %}
function old_state() : int %{ return old_state_; %}
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 transition(olds : AnalyzerState, news : AnalyzerState,
current_record_is_orig : bool, is_orig : bool) : bool
function startEncryption(is_orig: bool) : bool
%{
if ( (olds != STATE_ANY && olds != state_) ||
current_record_is_orig != is_orig )
return false;
old_state_ = state_;
state_ = news;
//printf("transitioning from %s to %s\n", state_label(old_state()).c_str(), state_label(state()).c_str());
if ( is_orig )
client_state_ = STATE_ENCRYPTED;
else
server_state_ = STATE_ENCRYPTED;
return true;
%}
function lost_track() : bool
%{
state_ = STATE_TRACK_LOST;
return false;
%}
function hello_requested() : bool
%{
bool ret = hello_requested_;
hello_requested_ = false;
return ret;
%}
function set_hello_requested(val : bool) : bool
%{
hello_requested_ = val;
return val;
%}
};