Added is_orig fields to the SSL events and adapted script.

- Added a field named $last_alert to the SSL log.  This doesn't even
  indicate the direction the alert was sent, but we need to start somewhere.

- The x509_certificate function has an is_orig field now instead of
  is_server and it's position in the argument list has moved.

- A bit of reorganization and cleanup in the core analyzer.
This commit is contained in:
Seth Hall 2011-12-09 16:56:12 -05:00
parent c8839da069
commit ec721dffec
8 changed files with 89 additions and 39 deletions

View file

@ -13,6 +13,44 @@ export {
[TLSv11] = "TLSv11", [TLSv11] = "TLSv11",
} &default="UNKNOWN"; } &default="UNKNOWN";
const alert_levels: table[count] of string = {
[1] = "warning",
[2] = "fatal",
} &default=function(i: count):string { return fmt("unknown-%d", i); };
const alert_descriptions: table[count] of string = {
[0] = "close_notify",
[10] = "unexpected_message",
[20] = "bad_record_mac",
[21] = "decryption_failed",
[22] = "record_overflow",
[30] = "decompression_failure",
[40] = "handshake_failure",
[41] = "no_certificate",
[42] = "bad_certificate",
[43] = "unsupported_certificate",
[44] = "certificate_revoked",
[45] = "certificate_expired",
[46] = "certificate_unknown",
[47] = "illegal_parameter",
[48] = "unknown_ca",
[49] = "access_denied",
[50] = "decode_error",
[51] = "decrypt_error",
[60] = "export_restriction",
[70] = "protocol_version",
[71] = "insufficient_security",
[80] = "internal_error",
[90] = "user_canceled",
[100] = "no_renegotiation",
[110] = "unsupported_extension",
[111] = "certificate_unobtainable",
[112] = "unrecognized_name",
[113] = "bad_certificate_status_response",
[114] = "bad_certificate_hash_value",
[115] = "unknown_psk_identity",
} &default=function(i: count):string { return fmt("unknown-%d", i); };
# http://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xml # http://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xml
const extensions: table[count] of string = { const extensions: table[count] of string = {
[0] = "server_name", [0] = "server_name",
@ -526,8 +564,7 @@ export {
[30] = "akid issuer serial mismatch", [30] = "akid issuer serial mismatch",
[31] = "keyusage no certsign", [31] = "keyusage no certsign",
[32] = "unable to get crl issuer", [32] = "unable to get crl issuer",
[33] = "unhandled critical extension" [33] = "unhandled critical extension",
}; };
} }

View file

@ -16,6 +16,7 @@ export {
subject: string &log &optional; subject: string &log &optional;
not_valid_before: time &log &optional; not_valid_before: time &log &optional;
not_valid_after: time &log &optional; not_valid_after: time &log &optional;
last_alert: string &log &optional;
cert: string &optional; cert: string &optional;
cert_chain: vector of string &optional; cert_chain: vector of string &optional;
@ -112,10 +113,13 @@ event ssl_server_hello(c: connection, version: count, possible_ts: time, session
c$ssl$cipher = cipher_desc[cipher]; c$ssl$cipher = cipher_desc[cipher];
} }
event x509_certificate(c: connection, cert: X509, is_server: bool, chain_idx: count, chain_len: count, der_cert: string) &priority=5 event x509_certificate(c: connection, is_orig: bool, cert: X509, chain_idx: count, chain_len: count, der_cert: string) &priority=5
{ {
set_session(c); set_session(c);
# We aren't doing anything with client certificates yet.
if ( is_orig ) return;
if ( chain_idx == 0 ) if ( chain_idx == 0 )
{ {
# Save the primary cert. # Save the primary cert.
@ -133,14 +137,21 @@ event x509_certificate(c: connection, cert: X509, is_server: bool, chain_idx: co
} }
} }
event ssl_extension(c: connection, code: count, val: string) &priority=5 event ssl_extension(c: connection, is_orig: bool, code: count, val: string) &priority=5
{ {
set_session(c); set_session(c);
if ( extensions[code] == "server_name" ) if ( is_orig && extensions[code] == "server_name" )
c$ssl$server_name = sub_bytes(val, 6, |val|); c$ssl$server_name = sub_bytes(val, 6, |val|);
} }
event ssl_alert(c: connection, is_orig: bool, level: count, desc: count) &priority=5
{
set_session(c);
c$ssl$last_alert = alert_descriptions[desc];
}
event ssl_established(c: connection) &priority=5 event ssl_established(c: connection) &priority=5
{ {
set_session(c); set_session(c);

View file

@ -10,11 +10,11 @@ export {
}; };
} }
event x509_certificate(c: connection, cert: X509, is_server: bool, chain_idx: count, chain_len: count, der_cert: string) &priority=4 event x509_certificate(c: connection, is_orig: bool, cert: X509, chain_idx: count, chain_len: count, der_cert: string) &priority=4
{ {
# We aren't tracking client certificates yet and we are also only tracking # We aren't tracking client certificates yet and we are also only tracking
# the primary cert. Watch that this came from an SSL analyzed session too. # the primary cert. Watch that this came from an SSL analyzed session too.
if ( ! is_server || chain_idx != 0 || ! c?$ssl ) if ( is_orig || chain_idx != 0 || ! c?$ssl )
return; return;
c$ssl$cert_hash = md5_hash(der_cert); c$ssl$cert_hash = md5_hash(der_cert);

View file

@ -33,10 +33,11 @@ export {
const notify_when_cert_expiring_in = 30days &redef; const notify_when_cert_expiring_in = 30days &redef;
} }
event x509_certificate(c: connection, cert: X509, is_server: bool, chain_idx: count, chain_len: count, der_cert: string) &priority=3 event x509_certificate(c: connection, is_orig: bool, cert: X509, chain_idx: count, chain_len: count, der_cert: string) &priority=3
{ {
# If this isn't the host cert or we aren't interested in the server, just return. # If this isn't the host cert or we aren't interested in the server, just return.
if ( chain_idx != 0 || if ( is_orig ||
chain_idx != 0 ||
! c$ssl?$cert_hash || ! c$ssl?$cert_hash ||
! addr_matches_host(c$id$resp_h, notify_certs_expiration) ) ! addr_matches_host(c$id$resp_h, notify_certs_expiration) )
return; return;

View file

@ -44,10 +44,10 @@ event bro_init() &priority=5
Log::create_stream(Known::CERTS_LOG, [$columns=CertsInfo, $ev=log_known_certs]); Log::create_stream(Known::CERTS_LOG, [$columns=CertsInfo, $ev=log_known_certs]);
} }
event x509_certificate(c: connection, cert: X509, is_server: bool, chain_idx: count, chain_len: count, der_cert: string) &priority=3 event x509_certificate(c: connection, is_orig: bool, cert: X509, chain_idx: count, chain_len: count, der_cert: string) &priority=3
{ {
# Make sure this is the server cert and we have a hash for it. # Make sure this is the server cert and we have a hash for it.
if ( chain_idx != 0 || ! c$ssl?$cert_hash ) if ( is_orig || chain_idx != 0 || ! c$ssl?$cert_hash )
return; return;
local host = c$id$resp_h; local host = c$id$resp_h;

View file

@ -279,13 +279,13 @@ event ssh_server_version%(c: connection, version: string%);
event ssl_client_hello%(c: connection, version: count, possible_ts: time, session_id: string, ciphers: count_set%); event ssl_client_hello%(c: connection, version: count, possible_ts: time, session_id: string, ciphers: count_set%);
event ssl_server_hello%(c: connection, version: count, possible_ts: time, session_id: string, cipher: count, comp_method: count%); event ssl_server_hello%(c: connection, version: count, possible_ts: time, session_id: string, cipher: count, comp_method: count%);
event ssl_extension%(c: connection, code: count, val: string%); event ssl_extension%(c: connection, is_orig: bool, code: count, val: string%);
event ssl_alert%(c: connection, is_orig: bool, level: count, desc: count%);
event ssl_established%(c: connection%); event ssl_established%(c: connection%);
event ssl_alert%(c: connection, level: count, desc: count%);
event x509_certificate%(c: connection, cert: X509, is_server: bool, chain_idx: count, chain_len: count, der_cert: string%); event x509_certificate%(c: connection, is_orig: bool, cert: X509, chain_idx: count, chain_len: count, der_cert: string%);
event x509_extension%(c: connection, data: string%); event x509_extension%(c: connection, is_orig: bool, data: string%);
event x509_error%(c: connection, err: count%); event x509_error%(c: connection, is_orig: bool, err: count%);
event stp_create_endp%(c: connection, e: int, is_orig: bool%); event stp_create_endp%(c: connection, e: int, is_orig: bool%);
event stp_resume_endp%(e: int%); event stp_resume_endp%(e: int%);

View file

@ -22,11 +22,17 @@
} }
}; };
string orig_label(bool is_orig);
void free_X509(void *); void free_X509(void *);
X509* d2i_X509_binpac(X509** px, const uint8** in, int len); X509* d2i_X509_binpac(X509** px, const uint8** in, int len);
%} %}
%code{ %code{
string orig_label(bool is_orig)
{
return string(is_orig ? "originator" :"responder");
}
void free_X509(void* cert) void free_X509(void* cert)
{ {
X509_free((X509*) cert); X509_free((X509*) cert);
@ -117,7 +123,7 @@ refine connection SSL_Conn += {
function proc_alert(rec: SSLRecord, level : int, desc : int) : bool function proc_alert(rec: SSLRecord, level : int, desc : int) : bool
%{ %{
BifEvent::generate_ssl_alert(bro_analyzer(), bro_analyzer()->Conn(), BifEvent::generate_ssl_alert(bro_analyzer(), bro_analyzer()->Conn(),
level, desc); ${rec.is_orig}, level, desc);
return true; return true;
%} %}
@ -200,11 +206,11 @@ refine connection SSL_Conn += {
return true; return true;
%} %}
function proc_ssl_extension(type: int, data: bytestring) : bool function proc_ssl_extension(rec: SSLRecord, type: int, data: bytestring) : bool
%{ %{
if ( ssl_extension ) if ( ssl_extension )
BifEvent::generate_ssl_extension(bro_analyzer(), BifEvent::generate_ssl_extension(bro_analyzer(),
bro_analyzer()->Conn(), type, bro_analyzer()->Conn(), ${rec.is_orig}, type,
new StringVal(data.length(), (const char*) data.data())); new StringVal(data.length(), (const char*) data.data()));
return true; return true;
%} %}
@ -231,7 +237,7 @@ refine connection SSL_Conn += {
if ( ! pTemp ) if ( ! pTemp )
{ {
BifEvent::generate_x509_error(bro_analyzer(), bro_analyzer()->Conn(), BifEvent::generate_x509_error(bro_analyzer(), bro_analyzer()->Conn(),
ERR_get_error()); ${rec.is_orig}, ERR_get_error());
return false; return false;
} }
@ -257,8 +263,8 @@ refine connection SSL_Conn += {
StringVal* der_cert = new StringVal(cert.length(), (const char*) cert.data()); StringVal* der_cert = new StringVal(cert.length(), (const char*) cert.data());
BifEvent::generate_x509_certificate(bro_analyzer(), bro_analyzer()->Conn(), BifEvent::generate_x509_certificate(bro_analyzer(), bro_analyzer()->Conn(),
${rec.is_orig},
pX509Cert, pX509Cert,
! ${rec.is_orig},
i, certificates->size(), i, certificates->size(),
der_cert); der_cert);
@ -284,7 +290,7 @@ refine connection SSL_Conn += {
StringVal* value = new StringVal(length, (char*)pBuffer); StringVal* value = new StringVal(length, (char*)pBuffer);
BifEvent::generate_x509_extension(bro_analyzer(), BifEvent::generate_x509_extension(bro_analyzer(),
bro_analyzer()->Conn(), value); bro_analyzer()->Conn(), ${rec.is_orig}, value);
OPENSSL_free(pBuffer); OPENSSL_free(pBuffer);
} }
} }
@ -445,5 +451,5 @@ refine typeattr CiphertextRecord += &let {
} }
refine typeattr SSLExtension += &let { refine typeattr SSLExtension += &let {
proc : bool = $context.connection.proc_ssl_extension(type, data); proc : bool = $context.connection.proc_ssl_extension(rec, type, data);
}; };

View file

@ -22,7 +22,6 @@ type uint24 = record {
}; };
string state_label(int state_nr); string state_label(int state_nr);
string orig_label(bool is_orig);
double get_time_from_asn1(const ASN1_TIME * atime); double get_time_from_asn1(const ASN1_TIME * atime);
string handshake_type_label(int type); string handshake_type_label(int type);
%} %}
@ -35,7 +34,7 @@ type SSLRecord(is_orig: bool) = record {
head2 : uint8; head2 : uint8;
head3 : uint8; head3 : uint8;
head4 : uint8; head4 : uint8;
rec : RecordText(this, is_orig)[] &length=length, &requires(content_type); rec : RecordText(this)[] &length=length, &requires(content_type);
} &length = length+5, &byteorder=bigendian, } &length = length+5, &byteorder=bigendian,
&let { &let {
version : int = version : int =
@ -54,25 +53,25 @@ type SSLRecord(is_orig: bool) = record {
}; };
}; };
type RecordText(rec: SSLRecord, is_orig: bool) = case $context.connection.state() of { type RecordText(rec: SSLRecord) = case $context.connection.state() of {
STATE_ABBREV_SERVER_ENCRYPTED, STATE_CLIENT_ENCRYPTED, STATE_ABBREV_SERVER_ENCRYPTED, STATE_CLIENT_ENCRYPTED,
STATE_COMM_ENCRYPTED, STATE_CONN_ESTABLISHED STATE_COMM_ENCRYPTED, STATE_CONN_ESTABLISHED
-> ciphertext : CiphertextRecord(rec, is_orig); -> ciphertext : CiphertextRecord(rec);
default default
-> plaintext : PlaintextRecord(rec, is_orig); -> plaintext : PlaintextRecord(rec);
}; };
type PossibleEncryptedHandshake(rec: SSLRecord, is_orig: bool) = case $context.connection.state() of { type PossibleEncryptedHandshake(rec: SSLRecord) = case $context.connection.state() of {
# Deal with encrypted handshakes before the server cipher spec change. # Deal with encrypted handshakes before the server cipher spec change.
STATE_CLIENT_FINISHED, STATE_CLIENT_ENCRYPTED STATE_CLIENT_FINISHED, STATE_CLIENT_ENCRYPTED
-> ct : CiphertextRecord(rec, is_orig); -> ct : CiphertextRecord(rec);
default -> hs : Handshake(rec); default -> hs : Handshake(rec);
}; };
type PlaintextRecord(rec: SSLRecord, is_orig: bool) = case rec.content_type of { type PlaintextRecord(rec: SSLRecord) = case rec.content_type of {
CHANGE_CIPHER_SPEC -> ch_cipher : ChangeCipherSpec(rec); CHANGE_CIPHER_SPEC -> ch_cipher : ChangeCipherSpec(rec);
ALERT -> alert : Alert(rec); ALERT -> alert : Alert(rec);
HANDSHAKE -> handshake : PossibleEncryptedHandshake(rec, is_orig); HANDSHAKE -> handshake : PossibleEncryptedHandshake(rec);
APPLICATION_DATA -> app_data : ApplicationData(rec); APPLICATION_DATA -> app_data : ApplicationData(rec);
V2_ERROR -> v2_error : V2Error(rec); V2_ERROR -> v2_error : V2Error(rec);
V2_CLIENT_HELLO -> v2_client_hello : V2ClientHello(rec); V2_CLIENT_HELLO -> v2_client_hello : V2ClientHello(rec);
@ -81,7 +80,7 @@ type PlaintextRecord(rec: SSLRecord, is_orig: bool) = case rec.content_type of {
default -> unknown_record : UnknownRecord(rec); default -> unknown_record : UnknownRecord(rec);
}; };
type SSLExtension = record { type SSLExtension(rec: SSLRecord) = record {
type: uint16; type: uint16;
data_len: uint16; data_len: uint16;
data: bytestring &length=data_len; data: bytestring &length=data_len;
@ -156,10 +155,6 @@ enum AnalyzerState {
} }
} }
string orig_label(bool is_orig)
{
return string(is_orig ? "originator" :"responder");
}
double get_time_from_asn1(const ASN1_TIME * atime) double get_time_from_asn1(const ASN1_TIME * atime)
{ {
@ -389,7 +384,7 @@ type ClientHello(rec: SSLRecord) = record {
# This weirdness is to deal with the possible existence or absence # This weirdness is to deal with the possible existence or absence
# of the following fields. # of the following fields.
ext_len: uint16[] &until($element == 0 || $element != 0); ext_len: uint16[] &until($element == 0 || $element != 0);
extensions : SSLExtension[] &until($input.length() == 0); extensions : SSLExtension(rec)[] &until($input.length() == 0);
} &let { } &let {
state_changed : bool = state_changed : bool =
$context.connection.transition(STATE_INITIAL, $context.connection.transition(STATE_INITIAL,
@ -663,7 +658,7 @@ type UnknownRecord(rec: SSLRecord) = record {
state_changed : bool = $context.connection.lost_track(); state_changed : bool = $context.connection.lost_track();
}; };
type CiphertextRecord(rec: SSLRecord, is_orig: bool) = record { type CiphertextRecord(rec: SSLRecord) = record {
cont : bytestring &restofdata &transient; cont : bytestring &restofdata &transient;
} &let { } &let {
state_changed : bool = state_changed : bool =