# Written by Matt Caswell for the OpenSSL project. # ==================================================================== # Copyright (c) 1998-2015 The OpenSSL Project. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in # the documentation and/or other materials provided with the # distribution. # # 3. All advertising materials mentioning features or use of this # software must display the following acknowledgment: # "This product includes software developed by the OpenSSL Project # for use in the OpenSSL Toolkit. (http://www.openssl.org/)" # # 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to # endorse or promote products derived from this software without # prior written permission. For written permission, please contact # openssl-core@openssl.org. # # 5. Products derived from this software may not be called "OpenSSL" # nor may "OpenSSL" appear in their names without prior written # permission of the OpenSSL Project. # # 6. Redistributions of any form whatsoever must retain the following # acknowledgment: # "This product includes software developed by the OpenSSL Project # for use in the OpenSSL Toolkit (http://www.openssl.org/)" # # THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY # EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR # ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT # NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, # STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED # OF THE POSSIBILITY OF SUCH DAMAGE. # ==================================================================== # # This product includes cryptographic software written by Eric Young # (eay@cryptsoft.com). This product includes software written by Tim # Hudson (tjh@cryptsoft.com). use strict; use TLSProxy::Proxy; package TLSProxy::Record; my $server_ccs_seen = 0; my $client_ccs_seen = 0; my $etm = 0; use constant TLS_RECORD_HEADER_LENGTH => 5; #Record types use constant { RT_APPLICATION_DATA => 23, RT_HANDSHAKE => 22, RT_ALERT => 21, RT_CCS => 20 }; my %record_type = ( RT_APPLICATION_DATA, "APPLICATION DATA", RT_HANDSHAKE, "HANDSHAKE", RT_ALERT, "ALERT", RT_CCS, "CCS" ); 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 }; my %tls_version = ( VERS_TLS_1_3, "TLS1.3", VERS_TLS_1_2, "TLS1.2", VERS_TLS_1_1, "TLS1.1", VERS_TLS_1_0, "TLS1.0", VERS_SSL_3_0, "SSL3", VERS_SSL_LT_3_0, "SSL<3" ); #Class method to extract records from a packet of data sub get_records { my $class = shift; my $server = shift; my $flight = shift; my $packet = shift; 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) { print "Partial data : ".length($packet)." bytes\n"; $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); } my $record = TLSProxy::Record->new( $flight, $content_type, $version, $len, $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) { $record->decryptETM(); } else { $record->decrypt(); } } 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; $packet = substr($packet, TLS_RECORD_HEADER_LENGTH + $len_real); $recnum++; } } return (\@record_list, \@message_list); } sub clear { $server_ccs_seen = 0; $client_ccs_seen = 0; } #Class level accessors sub server_ccs_seen { my $class = shift; if (@_) { $server_ccs_seen = shift; } return $server_ccs_seen; } sub client_ccs_seen { my $class = shift; if (@_) { $client_ccs_seen = shift; } return $client_ccs_seen; } #Enable/Disable Encrypt-then-MAC sub etm { my $class = shift; if (@_) { $etm = shift; } return $etm; } sub new { my $class = shift; my ($flight, $content_type, $version, $len, $len_real, $decrypt_len, $data, $decrypt_data) = @_; my $self = { flight => $flight, content_type => $content_type, version => $version, len => $len, len_real => $len_real, decrypt_len => $decrypt_len, data => $data, decrypt_data => $decrypt_data, orig_decrypt_data => $decrypt_data }; return bless $self, $class; } #Decrypt using encrypt-then-MAC sub decryptETM { my ($self) = shift; my $data = $self->data; if($self->version >= VERS_TLS_1_1()) { #TLS1.1+ has an explicit IV. Throw it away $data = substr($data, 16); } #Throw away the MAC (assumes MAC is 20 bytes for now. FIXME) $data = substr($data, 0, length($data) - 20); #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)); $self->decrypt_data($data); $self->decrypt_len(length($data)); return $data; } #Standard decrypt sub decrypt() { my ($self) = shift; my $data = $self->data; if($self->version >= VERS_TLS_1_1()) { #TLS1.1+ has an explicit IV. Throw it away $data = substr($data, 16); } #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 MAC (assumes MAC is 20 bytes for now. FIXME) $data = substr($data, 0, length($data) - 20); $self->decrypt_data($data); $self->decrypt_len(length($data)); return $data; } #Reconstruct the on-the-wire record representation sub reconstruct_record { my $self = shift; my $data; $data = pack('Cnn', $self->content_type, $self->version, $self->len); $data .= $self->data; return $data; } #Read only accessors 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 len_real { my $self = shift; return $self->{len_real}; } sub orig_decrypt_data { my $self = shift; return $self->{orig_decrypt_data}; } #Read/write accessors sub decrypt_len { my $self = shift; if (@_) { $self->{decrypt_len} = shift; } return $self->{decrypt_len}; } sub data { my $self = shift; if (@_) { $self->{data} = shift; } return $self->{data}; } sub decrypt_data { my $self = shift; if (@_) { $self->{decrypt_data} = shift; } return $self->{decrypt_data}; } sub len { my $self = shift; if (@_) { $self->{len} = shift; } return $self->{len}; } 1;