diff options
Diffstat (limited to 'deps/openssl/openssl/util/perl/TLSProxy/Record.pm')
-rw-r--r-- | deps/openssl/openssl/util/perl/TLSProxy/Record.pm | 244 |
1 files changed, 153 insertions, 91 deletions
diff --git a/deps/openssl/openssl/util/perl/TLSProxy/Record.pm b/deps/openssl/openssl/util/perl/TLSProxy/Record.pm index 786ba0c72b..0a280cb269 100644 --- a/deps/openssl/openssl/util/perl/TLSProxy/Record.pm +++ b/deps/openssl/openssl/util/perl/TLSProxy/Record.pm @@ -11,8 +11,8 @@ use TLSProxy::Proxy; package TLSProxy::Record; -my $server_ccs_seen = 0; -my $client_ccs_seen = 0; +my $server_encrypting = 0; +my $client_encrypting = 0; my $etm = 0; use constant TLS_RECORD_HEADER_LENGTH => 5; @@ -35,12 +35,13 @@ my %record_type = ( ); use constant { - VERS_TLS_1_3 => 772, - VERS_TLS_1_2 => 771, - VERS_TLS_1_1 => 770, - VERS_TLS_1_0 => 769, - VERS_SSL_3_0 => 768, - VERS_SSL_LT_3_0 => 767 + VERS_TLS_1_4 => 0x0305, + VERS_TLS_1_3 => 0x0304, + VERS_TLS_1_2 => 0x0303, + VERS_TLS_1_1 => 0x0302, + VERS_TLS_1_0 => 0x0301, + VERS_SSL_3_0 => 0x0300, + VERS_SSL_LT_3_0 => 0x02ff }; my %tls_version = ( @@ -62,72 +63,66 @@ sub get_records my $partial = ""; my @record_list = (); my @message_list = (); - my $data; - my $content_type; - my $version; - my $len; - my $len_real; - my $decrypt_len; my $recnum = 1; while (length ($packet) > 0) { - print " Record $recnum"; - if ($server) { - print " (server -> client)\n"; - } else { - print " (client -> server)\n"; - } - #Get the record header - if (length($packet) < TLS_RECORD_HEADER_LENGTH - || length($packet) < 5 + unpack("n", substr($packet, 3, 2))) { + print " Record $recnum ", $server ? "(server -> client)\n" + : "(client -> server)\n"; + + #Get the record header (unpack can't fail if $packet is too short) + my ($content_type, $version, $len) = unpack('Cnn', $packet); + + if (length($packet) < TLS_RECORD_HEADER_LENGTH + ($len // 0)) { print "Partial data : ".length($packet)." bytes\n"; $partial = $packet; - $packet = ""; - } else { - ($content_type, $version, $len) = unpack('CnnC*', $packet); - $data = substr($packet, 5, $len); - - print " Content type: ".$record_type{$content_type}."\n"; - print " Version: $tls_version{$version}\n"; - print " Length: $len"; - if ($len == length($data)) { - print "\n"; - $decrypt_len = $len_real = $len; - } else { - print " (expected), ".length($data)." (actual)\n"; - $decrypt_len = $len_real = length($data); - } + last; + } - my $record = TLSProxy::Record->new( - $flight, - $content_type, - $version, - $len, - 0, - $len_real, - $decrypt_len, - substr($packet, TLS_RECORD_HEADER_LENGTH, $len_real), - substr($packet, TLS_RECORD_HEADER_LENGTH, $len_real) - ); - - if (($server && $server_ccs_seen) - || (!$server && $client_ccs_seen)) { - if ($etm) { + my $data = substr($packet, TLS_RECORD_HEADER_LENGTH, $len); + + print " Content type: ".$record_type{$content_type}."\n"; + print " Version: $tls_version{$version}\n"; + print " Length: $len\n"; + + my $record = TLSProxy::Record->new( + $flight, + $content_type, + $version, + $len, + 0, + $len, # len_real + $len, # decrypt_len + $data, # data + $data # decrypt_data + ); + + if ($content_type != RT_CCS + && (!TLSProxy::Proxy->is_tls13() + || $content_type != RT_ALERT)) { + if (($server && $server_encrypting) + || (!$server && $client_encrypting)) { + if (!TLSProxy::Proxy->is_tls13() && $etm) { $record->decryptETM(); } else { $record->decrypt(); } + $record->encrypted(1); + + if (TLSProxy::Proxy->is_tls13()) { + print " Inner content type: " + .$record_type{$record->content_type()}."\n"; + } } + } - push @record_list, $record; + push @record_list, $record; - #Now figure out what messages are contained within this record - my @messages = TLSProxy::Message->get_messages($server, $record); - push @message_list, @messages; + #Now figure out what messages are contained within this record + my @messages = TLSProxy::Message->get_messages($server, $record); + push @message_list, @messages; - $packet = substr($packet, TLS_RECORD_HEADER_LENGTH + $len_real); - $recnum++; - } + $packet = substr($packet, TLS_RECORD_HEADER_LENGTH + $len); + $recnum++; } return (\@record_list, \@message_list, $partial); @@ -135,26 +130,26 @@ sub get_records sub clear { - $server_ccs_seen = 0; - $client_ccs_seen = 0; + $server_encrypting = 0; + $client_encrypting = 0; } #Class level accessors -sub server_ccs_seen +sub server_encrypting { my $class = shift; if (@_) { - $server_ccs_seen = shift; + $server_encrypting = shift; } - return $server_ccs_seen; + return $server_encrypting; } -sub client_ccs_seen +sub client_encrypting { my $class = shift; if (@_) { - $client_ccs_seen = shift; + $client_encrypting= shift; } - return $client_ccs_seen; + return $client_encrypting; } #Enable/Disable Encrypt-then-MAC sub etm @@ -190,7 +185,9 @@ sub new data => $data, decrypt_data => $decrypt_data, orig_decrypt_data => $decrypt_data, - sent => 0 + sent => 0, + encrypted => 0, + outer_content_type => RT_APPLICATION_DATA }; return bless $self, $class; @@ -227,22 +224,44 @@ sub decryptETM sub decrypt() { my ($self) = shift; - + my $mactaglen = 20; my $data = $self->data; - if($self->version >= VERS_TLS_1_1()) { - #TLS1.1+ has an explicit IV. Throw it away + #Throw away any IVs + if (TLSProxy::Proxy->is_tls13()) { + #A TLS1.3 client, when processing the server's initial flight, could + #respond with either an encrypted or an unencrypted alert. + if ($self->content_type() == RT_ALERT) { + #TODO(TLS1.3): Eventually it is sufficient just to check the record + #content type. If an alert is encrypted it will have a record + #content type of application data. However we haven't done the + #record layer changes yet, so it's a bit more complicated. For now + #we will additionally check if the data length is 2 (1 byte for + #alert level, 1 byte for alert description). If it is, then this is + #an unencrypted alert, so don't try to decrypt + return $data if (length($data) == 2); + } + $mactaglen = 16; + } elsif ($self->version >= VERS_TLS_1_1()) { + #16 bytes for a standard IV $data = substr($data, 16); - } - #Find out what the padding byte is - my $padval = unpack("C", substr($data, length($data) - 1)); + #Find out what the padding byte is + my $padval = unpack("C", substr($data, length($data) - 1)); - #Throw away the padding - $data = substr($data, 0, length($data) - ($padval + 1)); + #Throw away the padding + $data = substr($data, 0, length($data) - ($padval + 1)); + } - #Throw away the MAC (assumes MAC is 20 bytes for now. FIXME) - $data = substr($data, 0, length($data) - 20); + #Throw away the MAC or TAG + $data = substr($data, 0, length($data) - $mactaglen); + + if (TLSProxy::Proxy->is_tls13()) { + #Get the content type + my $content_type = unpack("C", substr($data, length($data) - 1)); + $self->content_type($content_type); + $data = substr($data, 0, length($data) - 1); + } $self->decrypt_data($data); $self->decrypt_len(length($data)); @@ -254,9 +273,11 @@ sub decrypt() sub reconstruct_record { my $self = shift; + my $server = shift; my $data; - if ($self->{sent}) { + #We only replay the records in the same direction + if ($self->{sent} || ($self->flight & 1) != $server) { return ""; } $self->{sent} = 1; @@ -264,7 +285,14 @@ sub reconstruct_record if ($self->sslv2) { $data = pack('n', $self->len | 0x8000); } else { - $data = pack('Cnn', $self->content_type, $self->version, $self->len); + if (TLSProxy::Proxy->is_tls13() && $self->encrypted) { + $data = pack('Cnn', $self->outer_content_type, $self->version, + $self->len); + } else { + $data = pack('Cnn', $self->content_type, $self->version, + $self->len); + } + } $data .= $self->data; @@ -277,16 +305,6 @@ sub flight my $self = shift; return $self->{flight}; } -sub content_type -{ - my $self = shift; - return $self->{content_type}; -} -sub version -{ - my $self = shift; - return $self->{version}; -} sub sslv2 { my $self = shift; @@ -336,4 +354,48 @@ sub len } return $self->{len}; } +sub version +{ + my $self = shift; + if (@_) { + $self->{version} = shift; + } + return $self->{version}; +} +sub content_type +{ + my $self = shift; + if (@_) { + $self->{content_type} = shift; + } + return $self->{content_type}; +} +sub encrypted +{ + my $self = shift; + if (@_) { + $self->{encrypted} = shift; + } + return $self->{encrypted}; +} +sub outer_content_type +{ + my $self = shift; + if (@_) { + $self->{outer_content_type} = shift; + } + return $self->{outer_content_type}; +} +sub is_fatal_alert +{ + my $self = shift; + my $server = shift; + + if (($self->{flight} & 1) == $server + && $self->{content_type} == TLSProxy::Record::RT_ALERT) { + my ($level, $alert) = unpack('CC', $self->decrypt_data); + return $alert if ($level == 2); + } + return 0; +} 1; |