Spicy TLS: raise ssl_established event for TLS 1.3

This commit is contained in:
Johanna Amann 2023-06-22 14:07:18 +01:00
parent 061dc73e8f
commit 3f91557c3e
3 changed files with 41 additions and 20 deletions

View file

@ -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"

View file

@ -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);

View file

@ -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);
} }
}; };