zeek/src/analyzer/protocol/ssl/ssl-protocol.pac
Johanna Amann ba27bb54d4 Implement correct parsing of TLS record fragmentation.
Finally. Our test-case is a >400kb certificate with 10,000 alternative
names. :)
2015-03-11 18:23:08 -07:00

213 lines
6.7 KiB
JavaScript

# Analyzer for SSL messages (general part).
# To be used in conjunction with an SSL record-layer analyzer.
# Separation is necessary due to possible fragmentation of SSL records.
type SSLRecord(is_orig: bool) = record {
head0 : uint8;
head1 : uint8;
head2 : uint8;
head3 : uint8;
head4 : uint8;
rec : RecordText(this)[] &length=length, &requires(content_type);
} &length = length+5, &byteorder=bigendian,
&let {
version : int =
$context.connection.determine_ssl_record_layer(head0, head1, head2, head3, head4, is_orig);
content_type : int = case version of {
SSLv20 -> head2+300;
default -> head0;
};
length : int = case version of {
# fail analyzer if the packet cannot be recognized as TLS.
UNKNOWN_VERSION -> 0;
SSLv20 -> (((head0 & 0x7f) << 8) | head1) - 3;
default -> (head3 << 8) | head4;
};
};
type RecordText(rec: SSLRecord) = case $context.connection.state(rec.is_orig) of {
STATE_ENCRYPTED
-> ciphertext : CiphertextRecord(rec);
default
-> plaintext : PlaintextRecord(rec);
};
refine casetype PlaintextRecord += {
HANDSHAKE -> handshake : Handshake(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);
};
type Handshake(rec: SSLRecord) = record {
# msg_type: uint8;
# length: uint24;
# data: bytestring &length=to_int()(length);
data: bytestring &restofdata;
};
######################################################################
# V2 Error Records (SSLv2 2.7.)
######################################################################
type V2Error(rec: SSLRecord) = record {
data : bytestring &restofdata &transient;
} &let {
error_code : uint16 = ((rec.head3 << 8) | rec.head4);
};
######################################################################
# V2 Client Hello (SSLv2 2.5.)
######################################################################
type V2ClientHello(rec: SSLRecord) = record {
csuit_len : uint16;
session_len : uint16;
chal_len : uint16;
ciphers : uint24[csuit_len/3];
session_id : uint8[session_len];
challenge : bytestring &length = chal_len;
} &length = 6 + csuit_len + session_len + chal_len, &let {
client_version : int = rec.version;
};
######################################################################
# V2 Server Hello (SSLv2 2.6.)
######################################################################
type V2ServerHello(rec: SSLRecord) = record {
#session_id_hit : uint8;
#cert_type : uint8;
server_version : uint16;
cert_len : uint16;
ciph_len : uint16;
conn_id_len : uint16;
cert_data : bytestring &length = cert_len;
ciphers : uint24[ciph_len/3];
conn_id_data : bytestring &length = conn_id_len;
} &let {
session_id_hit : uint8 = rec.head3;
cert_type : uint8 = rec.head4;
};
######################################################################
# V2 Client Master Key (SSLv2 2.5.)
######################################################################
type V2ClientMasterKey(rec: SSLRecord) = record {
cipher_kind_8 : uint8;
cl_key_len : uint16;
en_key_len : uint16;
key_arg_len : uint16;
cl_key_data : bytestring &length = cl_key_len &transient;
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 {
cipher_kind : int = (((rec.head3 << 16) | (rec.head4 << 8)) | cipher_kind_8);
# encryption starts for both sides after this message.
state_changed_client : bool = $context.connection.startEncryption(true);
state_changed_server : bool = $context.connection.startEncryption(false);
};
######################################################################
# initial datatype for binpac
######################################################################
type SSLPDU(is_orig: bool) = record {
records : SSLRecord(is_orig)[] &transient;
} &byteorder = bigendian;
######################################################################
# binpac analyzer for SSL including
######################################################################
refine connection SSL_Conn += {
function determine_ssl_record_layer(head0 : uint8, head1 : uint8,
head2 : uint8, head3: uint8, head4: uint8, is_orig: bool) : int
%{
// stop processing if we already had a protocol violation or otherwhise
// decided that we do not want to parse anymore. Just setting skip is not
// enough for the data that is already in the pipe.
if ( bro_analyzer()->Skipping() )
return UNKNOWN_VERSION;
// re-check record layer version to be sure that we still are synchronized with
// the data stream
if ( record_layer_version_ != UNKNOWN_VERSION && record_layer_version_ != SSLv20 )
{
uint16 version = (head1<<8) | head2;
if ( version != SSLv30 && version != TLSv10 &&
version != TLSv11 && version != TLSv12 )
{
bro_analyzer()->ProtocolViolation(fmt("Invalid version late in TLS connection. Packet reported version: %d", version));
bro_analyzer()->SetSkip(true);
return UNKNOWN_VERSION;
}
}
if ( record_layer_version_ != UNKNOWN_VERSION )
return record_layer_version_;
if ( head0 & 0x80 )
{
if ( head2 == 0x01 && is_orig ) // SSLv2 client hello.
{
uint16 version = (head3 << 8) | head4;
if ( version != SSLv20 && version != SSLv30 && version != TLSv10 &&
version != TLSv11 && version != TLSv12 )
{
bro_analyzer()->ProtocolViolation(fmt("Invalid version in SSL client hello. Version: %d", version));
bro_analyzer()->SetSkip(true);
return UNKNOWN_VERSION;
}
else
return SSLv20;
}
else if ( head2 == 0x04 && head4 < 2 && ! is_orig ) // SSLv2 server hello. This connection will continue using SSLv2.
{
record_layer_version_ = SSLv20;
return SSLv20;
}
else // this is not SSL or TLS.
{
bro_analyzer()->ProtocolViolation(fmt("Invalid headers in SSL connection. Head1: %d, head2: %d, head3: %d", head1, head2, head3));
bro_analyzer()->SetSkip(true);
return UNKNOWN_VERSION;
}
}
uint16 version = (head1<<8) | head2;
if ( version != SSLv30 && version != TLSv10 &&
version != TLSv11 && version != TLSv12 )
{
bro_analyzer()->ProtocolViolation(fmt("Invalid version in TLS connection. Version: %d", version));
bro_analyzer()->SetSkip(true);
return UNKNOWN_VERSION;
}
if ( head0 >=20 && head0 <= 30 )
{ // ok, set record layer version, this never can be downgraded to v2
record_layer_version_ = version;
return version;
}
bro_analyzer()->ProtocolViolation(fmt("Invalid type in TLS connection. Version: %d, Type: %d", version, head0));
bro_analyzer()->SetSkip(true);
return UNKNOWN_VERSION;
%}
};