mirror of
https://github.com/zeek/zeek.git
synced 2025-10-08 01:28:20 +00:00
Merge remote branch 'origin/topic/seth/ssl-updates-for-2.0'
* origin/topic/seth/ssl-updates-for-2.0: Added is_orig fields to the SSL events and adapted script. Closes #692.
This commit is contained in:
commit
f3c2811e14
8 changed files with 118 additions and 67 deletions
|
@ -13,6 +13,44 @@ export {
|
|||
[TLSv11] = "TLSv11",
|
||||
} &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
|
||||
const extensions: table[count] of string = {
|
||||
[0] = "server_name",
|
||||
|
@ -526,8 +564,7 @@ export {
|
|||
[30] = "akid issuer serial mismatch",
|
||||
[31] = "keyusage no certsign",
|
||||
[32] = "unable to get crl issuer",
|
||||
[33] = "unhandled critical extension"
|
||||
|
||||
[33] = "unhandled critical extension",
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -16,32 +16,33 @@ export {
|
|||
subject: string &log &optional;
|
||||
not_valid_before: time &log &optional;
|
||||
not_valid_after: time &log &optional;
|
||||
|
||||
last_alert: string &log &optional;
|
||||
|
||||
cert: string &optional;
|
||||
cert_chain: vector of string &optional;
|
||||
|
||||
|
||||
## This stores the analyzer id used for the analyzer instance attached
|
||||
## to each connection. It is not used for logging since it's a
|
||||
## to each connection. It is not used for logging since it's a
|
||||
## meaningless arbitrary number.
|
||||
analyzer_id: count &optional;
|
||||
};
|
||||
|
||||
|
||||
## This is where the default root CA bundle is defined. By loading the
|
||||
## mozilla-ca-list.bro script it will be set to Mozilla's root CA list.
|
||||
const root_certs: table[string] of string = {} &redef;
|
||||
|
||||
## If true, detach the SSL analyzer from the connection to prevent
|
||||
|
||||
## If true, detach the SSL analyzer from the connection to prevent
|
||||
## continuing to process encrypted traffic. Helps with performance
|
||||
## (especially with large file transfers).
|
||||
const disable_analyzer_after_detection = T &redef;
|
||||
|
||||
|
||||
## The openssl command line utility. If it's in the path the default
|
||||
## value will work, otherwise a full path string can be supplied for the
|
||||
## utility.
|
||||
const openssl_util = "openssl" &redef;
|
||||
|
||||
|
||||
global log_ssl: event(rec: Info);
|
||||
|
||||
|
||||
const ports = {
|
||||
443/tcp, 563/tcp, 585/tcp, 614/tcp, 636/tcp,
|
||||
989/tcp, 990/tcp, 992/tcp, 993/tcp, 995/tcp, 5223/tcp
|
||||
|
@ -86,7 +87,7 @@ function set_session(c: connection)
|
|||
if ( ! c?$ssl )
|
||||
c$ssl = [$ts=network_time(), $uid=c$uid, $id=c$id, $cert_chain=vector()];
|
||||
}
|
||||
|
||||
|
||||
function finish(c: connection)
|
||||
{
|
||||
Log::write(SSL::LOG, c$ssl);
|
||||
|
@ -98,29 +99,33 @@ function finish(c: connection)
|
|||
event ssl_client_hello(c: connection, version: count, possible_ts: time, session_id: string, ciphers: count_set) &priority=5
|
||||
{
|
||||
set_session(c);
|
||||
|
||||
|
||||
# Save the session_id if there is one set.
|
||||
if ( session_id != /^\x00{32}$/ )
|
||||
c$ssl$session_id = bytestring_to_hexstr(session_id);
|
||||
}
|
||||
|
||||
|
||||
event ssl_server_hello(c: connection, version: count, possible_ts: time, session_id: string, cipher: count, comp_method: count) &priority=5
|
||||
{
|
||||
set_session(c);
|
||||
|
||||
|
||||
c$ssl$version = version_strings[version];
|
||||
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);
|
||||
|
||||
|
||||
# We aren't doing anything with client certificates yet.
|
||||
if ( is_orig )
|
||||
return;
|
||||
|
||||
if ( chain_idx == 0 )
|
||||
{
|
||||
# Save the primary cert.
|
||||
c$ssl$cert = der_cert;
|
||||
|
||||
|
||||
# Also save other certificate information about the primary cert.
|
||||
c$ssl$subject = cert$subject;
|
||||
c$ssl$not_valid_before = cert$not_valid_before;
|
||||
|
@ -132,20 +137,27 @@ event x509_certificate(c: connection, cert: X509, is_server: bool, chain_idx: co
|
|||
c$ssl$cert_chain[|c$ssl$cert_chain|] = der_cert;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
if ( extensions[code] == "server_name" )
|
||||
|
||||
if ( is_orig && extensions[code] == "server_name" )
|
||||
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
|
||||
{
|
||||
set_session(c);
|
||||
}
|
||||
|
||||
|
||||
event ssl_established(c: connection) &priority=-5
|
||||
{
|
||||
finish(c);
|
||||
|
@ -163,4 +175,4 @@ event protocol_violation(c: connection, atype: count, aid: count,
|
|||
{
|
||||
if ( c?$ssl )
|
||||
finish(c);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
# 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;
|
||||
|
||||
c$ssl$cert_hash = md5_hash(der_cert);
|
||||
|
|
|
@ -33,10 +33,11 @@ export {
|
|||
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 ( chain_idx != 0 ||
|
||||
if ( is_orig ||
|
||||
chain_idx != 0 ||
|
||||
! c$ssl?$cert_hash ||
|
||||
! addr_matches_host(c$id$resp_h, notify_certs_expiration) )
|
||||
return;
|
||||
|
|
|
@ -44,10 +44,10 @@ event bro_init() &priority=5
|
|||
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.
|
||||
if ( chain_idx != 0 || ! c$ssl?$cert_hash )
|
||||
if ( is_orig || chain_idx != 0 || ! c$ssl?$cert_hash )
|
||||
return;
|
||||
|
||||
local host = c$id$resp_h;
|
||||
|
|
|
@ -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_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_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_extension%(c: connection, data: string%);
|
||||
event x509_error%(c: connection, err: count%);
|
||||
event x509_certificate%(c: connection, is_orig: bool, cert: X509, chain_idx: count, chain_len: count, der_cert: string%);
|
||||
event x509_extension%(c: connection, is_orig: bool, data: string%);
|
||||
event x509_error%(c: connection, is_orig: bool, err: count%);
|
||||
|
||||
event stp_create_endp%(c: connection, e: int, is_orig: bool%);
|
||||
event stp_resume_endp%(e: int%);
|
||||
|
|
|
@ -22,11 +22,17 @@
|
|||
}
|
||||
};
|
||||
|
||||
string orig_label(bool is_orig);
|
||||
void free_X509(void *);
|
||||
X509* d2i_X509_binpac(X509** px, const uint8** in, int len);
|
||||
%}
|
||||
|
||||
%code{
|
||||
string orig_label(bool is_orig)
|
||||
{
|
||||
return string(is_orig ? "originator" :"responder");
|
||||
}
|
||||
|
||||
void free_X509(void* cert)
|
||||
{
|
||||
X509_free((X509*) cert);
|
||||
|
@ -117,14 +123,14 @@ refine connection SSL_Conn += {
|
|||
function proc_alert(rec: SSLRecord, level : int, desc : int) : bool
|
||||
%{
|
||||
BifEvent::generate_ssl_alert(bro_analyzer(), bro_analyzer()->Conn(),
|
||||
level, desc);
|
||||
${rec.is_orig}, level, desc);
|
||||
return true;
|
||||
%}
|
||||
|
||||
function proc_client_hello(rec: SSLRecord,
|
||||
version : uint16, ts : double,
|
||||
session_id : uint8[],
|
||||
cipher_suites16 : uint16[],
|
||||
cipher_suites16 : uint16[],
|
||||
cipher_suites24 : uint24[]) : bool
|
||||
%{
|
||||
if ( state_ == STATE_TRACK_LOST )
|
||||
|
@ -150,15 +156,15 @@ refine connection SSL_Conn += {
|
|||
cipher_set->Assign(ciph, 0);
|
||||
Unref(ciph);
|
||||
}
|
||||
|
||||
|
||||
BifEvent::generate_ssl_client_hello(bro_analyzer(), bro_analyzer()->Conn(),
|
||||
version, ts,
|
||||
to_string_val(session_id),
|
||||
cipher_set);
|
||||
|
||||
|
||||
delete cipher_suites;
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
%}
|
||||
|
||||
|
@ -187,24 +193,24 @@ refine connection SSL_Conn += {
|
|||
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,
|
||||
to_string_val(session_id),
|
||||
ciphers->size()==0 ? 0 : ciphers->at(0), comp_method);
|
||||
|
||||
|
||||
delete ciphers;
|
||||
}
|
||||
|
||||
|
||||
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 )
|
||||
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()));
|
||||
return true;
|
||||
%}
|
||||
|
@ -222,7 +228,7 @@ refine connection SSL_Conn += {
|
|||
if ( x509_certificate )
|
||||
{
|
||||
STACK_OF(X509)* untrusted_certs = 0;
|
||||
|
||||
|
||||
for ( unsigned int i = 0; i < certificates->size(); ++i )
|
||||
{
|
||||
const bytestring& cert = (*certificates)[i];
|
||||
|
@ -231,7 +237,7 @@ refine connection SSL_Conn += {
|
|||
if ( ! pTemp )
|
||||
{
|
||||
BifEvent::generate_x509_error(bro_analyzer(), bro_analyzer()->Conn(),
|
||||
ERR_get_error());
|
||||
${rec.is_orig}, ERR_get_error());
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -257,8 +263,8 @@ refine connection SSL_Conn += {
|
|||
StringVal* der_cert = new StringVal(cert.length(), (const char*) cert.data());
|
||||
|
||||
BifEvent::generate_x509_certificate(bro_analyzer(), bro_analyzer()->Conn(),
|
||||
${rec.is_orig},
|
||||
pX509Cert,
|
||||
! ${rec.is_orig},
|
||||
i, certificates->size(),
|
||||
der_cert);
|
||||
|
||||
|
@ -284,7 +290,7 @@ refine connection SSL_Conn += {
|
|||
|
||||
StringVal* value = new StringVal(length, (char*)pBuffer);
|
||||
BifEvent::generate_x509_extension(bro_analyzer(),
|
||||
bro_analyzer()->Conn(), value);
|
||||
bro_analyzer()->Conn(), ${rec.is_orig}, value);
|
||||
OPENSSL_free(pBuffer);
|
||||
}
|
||||
}
|
||||
|
@ -445,5 +451,5 @@ refine typeattr CiphertextRecord += &let {
|
|||
}
|
||||
|
||||
refine typeattr SSLExtension += &let {
|
||||
proc : bool = $context.connection.proc_ssl_extension(type, data);
|
||||
proc : bool = $context.connection.proc_ssl_extension(rec, type, data);
|
||||
};
|
||||
|
|
|
@ -22,7 +22,6 @@ type uint24 = record {
|
|||
};
|
||||
|
||||
string state_label(int state_nr);
|
||||
string orig_label(bool is_orig);
|
||||
double get_time_from_asn1(const ASN1_TIME * atime);
|
||||
string handshake_type_label(int type);
|
||||
%}
|
||||
|
@ -35,7 +34,7 @@ type SSLRecord(is_orig: bool) = record {
|
|||
head2 : uint8;
|
||||
head3 : 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,
|
||||
&let {
|
||||
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_COMM_ENCRYPTED, STATE_CONN_ESTABLISHED
|
||||
-> ciphertext : CiphertextRecord(rec, is_orig);
|
||||
-> ciphertext : CiphertextRecord(rec);
|
||||
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.
|
||||
STATE_CLIENT_FINISHED, STATE_CLIENT_ENCRYPTED
|
||||
-> ct : CiphertextRecord(rec, is_orig);
|
||||
-> ct : CiphertextRecord(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);
|
||||
ALERT -> alert : Alert(rec);
|
||||
HANDSHAKE -> handshake : PossibleEncryptedHandshake(rec, is_orig);
|
||||
HANDSHAKE -> handshake : PossibleEncryptedHandshake(rec);
|
||||
APPLICATION_DATA -> app_data : ApplicationData(rec);
|
||||
V2_ERROR -> v2_error : V2Error(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);
|
||||
};
|
||||
|
||||
type SSLExtension = record {
|
||||
type SSLExtension(rec: SSLRecord) = record {
|
||||
type: uint16;
|
||||
data_len: uint16;
|
||||
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)
|
||||
{
|
||||
|
@ -389,7 +384,7 @@ type ClientHello(rec: SSLRecord) = record {
|
|||
# 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[] &until($input.length() == 0);
|
||||
extensions : SSLExtension(rec)[] &until($input.length() == 0);
|
||||
} &let {
|
||||
state_changed : bool =
|
||||
$context.connection.transition(STATE_INITIAL,
|
||||
|
@ -663,7 +658,7 @@ type UnknownRecord(rec: SSLRecord) = record {
|
|||
state_changed : bool = $context.connection.lost_track();
|
||||
};
|
||||
|
||||
type CiphertextRecord(rec: SSLRecord, is_orig: bool) = record {
|
||||
type CiphertextRecord(rec: SSLRecord) = record {
|
||||
cont : bytestring &restofdata &transient;
|
||||
} &let {
|
||||
state_changed : bool =
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue