mirror of
https://github.com/zeek/zeek.git
synced 2025-10-02 06:38:20 +00:00
Spicy TLS: raise ssl_established event for TLS 1.3
This commit is contained in:
parent
061dc73e8f
commit
3f91557c3e
3 changed files with 41 additions and 20 deletions
|
@ -67,5 +67,6 @@ uses_seh = "uses_seh"
|
||||||
[default.extend-words]
|
[default.extend-words]
|
||||||
caf = "caf"
|
caf = "caf"
|
||||||
helo = "helo"
|
helo = "helo"
|
||||||
|
inout = "inout"
|
||||||
# Seems we use this in the management framework
|
# Seems we use this in the management framework
|
||||||
requestor = "requestor"
|
requestor = "requestor"
|
||||||
|
|
|
@ -25,8 +25,9 @@ on TLS::NewSessionTicket -> event ssl_session_ticket_handshake($conn, self.ticke
|
||||||
|
|
||||||
on TLS::PlaintextRecord::ccs -> event ssl_change_cipher_spec($conn, $is_orig);
|
on TLS::PlaintextRecord::ccs -> event ssl_change_cipher_spec($conn, $is_orig);
|
||||||
on TLS::PlaintextRecord::ccs if ( msg.context().ccs_seen == 2 ) -> event ssl_established($conn);
|
on TLS::PlaintextRecord::ccs if ( msg.context().ccs_seen == 2 ) -> event ssl_established($conn);
|
||||||
on TLS::PlaintextRecord::appdata if ( self.encrypted == False ) -> event ssl_plaintext_data($conn, TLS::get_direction(sh), msg.record_version, content_type, self.length);
|
on TLS::PlaintextRecord::trigger_one if ( sh.both_sides_encrypted_first_time == True ) -> event ssl_established($conn);
|
||||||
on TLS::PlaintextRecord::appdata if ( self.encrypted == True ) -> event ssl_encrypted_data($conn, TLS::get_direction(sh), msg.record_version, content_type, self.length);
|
on TLS::PlaintextRecord::trigger_two if ( self.encrypted == False ) -> event ssl_plaintext_data($conn, TLS::get_direction(sh), msg.record_version, content_type, self.length);
|
||||||
|
on TLS::PlaintextRecord::trigger_two if ( self.encrypted == True ) -> event ssl_encrypted_data($conn, TLS::get_direction(sh), msg.record_version, content_type, self.length);
|
||||||
|
|
||||||
on TLS::Handshake_message -> event ssl_handshake_message($conn, TLS::get_direction(sh), self.msg_type, self.length);
|
on TLS::Handshake_message -> event ssl_handshake_message($conn, TLS::get_direction(sh), self.msg_type, self.length);
|
||||||
|
|
||||||
|
|
|
@ -568,6 +568,7 @@ type Share = unit {
|
||||||
# var skipping: bool;
|
# var skipping: bool;
|
||||||
var client_encrypted: bool;
|
var client_encrypted: bool;
|
||||||
var server_encrypted: bool;
|
var server_encrypted: bool;
|
||||||
|
var both_sides_encrypted_first_time: bool;
|
||||||
|
|
||||||
on %init {
|
on %init {
|
||||||
self.ccs_seen = 0;
|
self.ccs_seen = 0;
|
||||||
|
@ -578,6 +579,7 @@ type Share = unit {
|
||||||
self.flip_already_alerted = False;
|
self.flip_already_alerted = False;
|
||||||
self.server_encrypted = False;
|
self.server_encrypted = False;
|
||||||
self.client_encrypted = False;
|
self.client_encrypted = False;
|
||||||
|
self.both_sides_encrypted_first_time = False;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -588,7 +590,7 @@ function get_encrypted(sh: Share) : bool {
|
||||||
return sh.server_encrypted;
|
return sh.server_encrypted;
|
||||||
}
|
}
|
||||||
|
|
||||||
function startEncryption(handshakesink: sink, alertsink: sink, inout sh: Share) {
|
function startEncryption(inout handshakesink: sink, inout alertsink: sink, inout sh: Share) {
|
||||||
local old_state: bool;
|
local old_state: bool;
|
||||||
|
|
||||||
if ( get_direction(sh) ) {
|
if ( get_direction(sh) ) {
|
||||||
|
@ -605,19 +607,19 @@ function startEncryption(handshakesink: sink, alertsink: sink, inout sh: Share)
|
||||||
print "Closing sink";
|
print "Closing sink";
|
||||||
handshakesink.close();
|
handshakesink.close();
|
||||||
alertsink.close();
|
alertsink.close();
|
||||||
sh.ccs_seen++; # do we need this?
|
|
||||||
|
if ( sh.client_encrypted && sh.server_encrypted ) {
|
||||||
|
print "Encrypted first time";
|
||||||
|
sh.both_sides_encrypted_first_time = True;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
# This function is called several times in certain circumstances.
|
# This function is called several times in certain circumstances.
|
||||||
# If it is called twice, it is first called due to the supported_versions
|
# If it is called twice, it is first called due to the outer version in
|
||||||
# field in the server hello - and then again due to the outer version in
|
# the server hello - and then again due to the supported_versions
|
||||||
# the server hello. So - once we have a version here, let's just stick
|
# field in the server hello.
|
||||||
# with it.
|
|
||||||
function set_version(version: uint16, inout sh: Share) : bool {
|
function set_version(version: uint16, inout sh: Share) : bool {
|
||||||
if ( sh.parsed_version != UNKNOWN_VERSION )
|
|
||||||
return False;
|
|
||||||
|
|
||||||
sh.parsed_version = version;
|
sh.parsed_version = version;
|
||||||
if ( version == TLSv13 || version/0xFF == 0x7F )
|
if ( version == TLSv13 || version/0xFF == 0x7F )
|
||||||
sh.tls_13 = True;
|
sh.tls_13 = True;
|
||||||
|
@ -698,7 +700,10 @@ type DTLSRecordFragment = unit(content_type: uint8, handshakesink: sink, alertsi
|
||||||
|
|
||||||
type PlaintextRecord = unit(content_type: uint8, handshakesink: sink, alertsink: sink, inout msg: Message, inout sh: Share) {
|
type PlaintextRecord = unit(content_type: uint8, handshakesink: sink, alertsink: sink, inout msg: Message, inout sh: Share) {
|
||||||
length: uint16;
|
length: uint16;
|
||||||
var encrypted: bool = determine_encryption_on(self, handshakesink, alertsink, msg, sh);
|
var encrypted: bool;
|
||||||
|
# convenient triggers to hang stuff in the evt file from. Two of them for event ordering :)
|
||||||
|
trigger_one: bytes &size=0;
|
||||||
|
trigger_two: bytes &size=0;
|
||||||
switch ( ContentType(content_type) ) {
|
switch ( ContentType(content_type) ) {
|
||||||
ContentType::handshake -> : bytes &size=self.length -> handshakesink;
|
ContentType::handshake -> : bytes &size=self.length -> handshakesink;
|
||||||
ContentType::application_data -> {
|
ContentType::application_data -> {
|
||||||
|
@ -717,6 +722,10 @@ type PlaintextRecord = unit(content_type: uint8, handshakesink: sink, alertsink:
|
||||||
print "Unhandled content type", content_type;
|
print "Unhandled content type", content_type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
on length {
|
||||||
|
self.encrypted = determine_encryption_on(self, content_type, handshakesink, alertsink, msg, sh);
|
||||||
|
}
|
||||||
|
|
||||||
on ccs {
|
on ccs {
|
||||||
# I know this looks a bit weird. Basically - in TLS 1.3, CCS is meaningless
|
# I know this looks a bit weird. Basically - in TLS 1.3, CCS is meaningless
|
||||||
# fluff that just is used to pretend to TLS 1.2 devices listening in that
|
# fluff that just is used to pretend to TLS 1.2 devices listening in that
|
||||||
|
@ -726,8 +735,14 @@ type PlaintextRecord = unit(content_type: uint8, handshakesink: sink, alertsink:
|
||||||
if ( sh.tls_13 )
|
if ( sh.tls_13 )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
print "CCS accepted";
|
||||||
|
sh.ccs_seen++; # used in TLS.evt
|
||||||
startEncryption(handshakesink, alertsink, sh);
|
startEncryption(handshakesink, alertsink, sh);
|
||||||
}
|
}
|
||||||
|
on trigger_two {
|
||||||
|
if ( sh.both_sides_encrypted_first_time )
|
||||||
|
sh.both_sides_encrypted_first_time = False;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
## So - this falls a bit under the envelope of dirty hack - but I don't
|
## So - this falls a bit under the envelope of dirty hack - but I don't
|
||||||
|
@ -750,7 +765,7 @@ type PlaintextRecord = unit(content_type: uint8, handshakesink: sink, alertsink:
|
||||||
## a bit of context here - we can't really say when we get the first packet
|
## a bit of context here - we can't really say when we get the first packet
|
||||||
## that uses the final cryptographic key material - and will contain content
|
## that uses the final cryptographic key material - and will contain content
|
||||||
## data. We just don't have that information available in TLS 1.3 anymore.
|
## data. We just don't have that information available in TLS 1.3 anymore.
|
||||||
function determine_encryption_on(pr: PlaintextRecord, handshakesink: sink, alertsink: sink, inout msg: Message, inout sh: Share) : bool {
|
function determine_encryption_on(pr: PlaintextRecord, content_type: uint8, handshakesink: sink, alertsink: sink, inout msg: Message, inout sh: Share) : bool {
|
||||||
if ( get_encrypted(sh) )
|
if ( get_encrypted(sh) )
|
||||||
return True;
|
return True;
|
||||||
|
|
||||||
|
@ -758,6 +773,9 @@ function determine_encryption_on(pr: PlaintextRecord, handshakesink: sink, alert
|
||||||
if ( pr.length == 0 )
|
if ( pr.length == 0 )
|
||||||
return False;
|
return False;
|
||||||
|
|
||||||
|
if ( content_type != 23 ) # application_data
|
||||||
|
return False;
|
||||||
|
|
||||||
## in theory, we should check for TLS13 or draft-TLS13 instead of doing the reverse.
|
## in theory, we should check for TLS13 or draft-TLS13 instead of doing the reverse.
|
||||||
## But - people use weird version numbers. And all of those weird version numbers are
|
## But - people use weird version numbers. And all of those weird version numbers are
|
||||||
## some sort of TLS1.3. So - let's do it this way round instead.
|
## some sort of TLS1.3. So - let's do it this way round instead.
|
||||||
|
@ -896,7 +914,7 @@ type ClientHello = unit(len: uint64, msg: Message, inout sh: Share) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
# Draft versions of TLS 1.3 had a diffent server hello - distinguish here
|
# Draft versions of TLS 1.3 had a different server hello - distinguish here
|
||||||
type ServerHelloChoice = unit(len: uint64, msg: Message, inout sh: Share) {
|
type ServerHelloChoice = unit(len: uint64, msg: Message, inout sh: Share) {
|
||||||
direction_check: DirectionCheck(sh, False); # should be sent by responder
|
direction_check: DirectionCheck(sh, False); # should be sent by responder
|
||||||
sv : bitfield(16) {
|
sv : bitfield(16) {
|
||||||
|
@ -907,8 +925,8 @@ type ServerHelloChoice = unit(len: uint64, msg: Message, inout sh: Share) {
|
||||||
var parsed_version: uint16;
|
var parsed_version: uint16;
|
||||||
|
|
||||||
switch ( self.parsed_version ) {
|
switch ( self.parsed_version ) {
|
||||||
TLSv13, TLSv13_draft, 0x7F00 -> : ServerHelloOneThree(len, msg, sh, self.sv.server_version);
|
TLSv13, TLSv13_draft, 0x7F00 -> sh_one_three : ServerHelloOneThree(len, msg, sh, self.sv.server_version);
|
||||||
* -> : ServerHello(len, msg, sh, self.sv.server_version);
|
* -> sh_normal : ServerHello(len, msg, sh, self.sv.server_version);
|
||||||
};
|
};
|
||||||
|
|
||||||
on sv {
|
on sv {
|
||||||
|
@ -927,7 +945,7 @@ type ServerHelloChoice = unit(len: uint64, msg: Message, inout sh: Share) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
# Draft versions of TLS 1.3 had a diffent server hello.
|
# Draft versions of TLS 1.3 had a different server hello.
|
||||||
type ServerHelloOneThree = unit(len: uint64, msg: Message, inout sh: Share, server_version: uint16) {
|
type ServerHelloOneThree = unit(len: uint64, msg: Message, inout sh: Share, server_version: uint16) {
|
||||||
random_bytes: bytes &size=32;
|
random_bytes: bytes &size=32;
|
||||||
gmt_unix_time: uint32 &parse-from=self.random_bytes;
|
gmt_unix_time: uint32 &parse-from=self.random_bytes;
|
||||||
|
@ -986,7 +1004,7 @@ type Extension = unit(inout sh: Share, client_hello: bool) {
|
||||||
};
|
};
|
||||||
|
|
||||||
on code {
|
on code {
|
||||||
print "Extension", self.code;
|
print "Extension", self.code, client_hello;
|
||||||
}
|
}
|
||||||
on unknown {
|
on unknown {
|
||||||
print "Unknown extension", self.code;
|
print "Unknown extension", self.code;
|
||||||
|
@ -1050,11 +1068,12 @@ type SupportedVersions = unit(sh: Share) {
|
||||||
versions: uint16[self.length/2];
|
versions: uint16[self.length/2];
|
||||||
};
|
};
|
||||||
|
|
||||||
# If the server sends it, this is the authorative version. Set it.
|
# If the server sends it, this is the authoritative version. Set it.
|
||||||
type OneSupportedVersion = unit(inout sh: Share) {
|
type OneSupportedVersion = unit(inout sh: Share) {
|
||||||
version: uint16;
|
version: uint16;
|
||||||
|
|
||||||
on version {
|
on version {
|
||||||
|
print "Setting version to ", self.version;
|
||||||
set_version(self.version, sh);
|
set_version(self.version, sh);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue