1*e0c4386eSCy Schubert# Copyright 2016-2018 The OpenSSL Project Authors. All Rights Reserved. 2*e0c4386eSCy Schubert# 3*e0c4386eSCy Schubert# Licensed under the Apache License 2.0 (the "License"). You may not use 4*e0c4386eSCy Schubert# this file except in compliance with the License. You can obtain a copy 5*e0c4386eSCy Schubert# in the file LICENSE in the source distribution or at 6*e0c4386eSCy Schubert# https://www.openssl.org/source/license.html 7*e0c4386eSCy Schubert 8*e0c4386eSCy Schubertuse strict; 9*e0c4386eSCy Schubert 10*e0c4386eSCy Schubertuse TLSProxy::Proxy; 11*e0c4386eSCy Schubert 12*e0c4386eSCy Schubertpackage TLSProxy::Record; 13*e0c4386eSCy Schubert 14*e0c4386eSCy Schubertmy $server_encrypting = 0; 15*e0c4386eSCy Schubertmy $client_encrypting = 0; 16*e0c4386eSCy Schubertmy $etm = 0; 17*e0c4386eSCy Schubert 18*e0c4386eSCy Schubertuse constant TLS_RECORD_HEADER_LENGTH => 5; 19*e0c4386eSCy Schubert 20*e0c4386eSCy Schubert#Record types 21*e0c4386eSCy Schubertuse constant { 22*e0c4386eSCy Schubert RT_APPLICATION_DATA => 23, 23*e0c4386eSCy Schubert RT_HANDSHAKE => 22, 24*e0c4386eSCy Schubert RT_ALERT => 21, 25*e0c4386eSCy Schubert RT_CCS => 20, 26*e0c4386eSCy Schubert RT_UNKNOWN => 100 27*e0c4386eSCy Schubert}; 28*e0c4386eSCy Schubert 29*e0c4386eSCy Schubertmy %record_type = ( 30*e0c4386eSCy Schubert RT_APPLICATION_DATA, "APPLICATION DATA", 31*e0c4386eSCy Schubert RT_HANDSHAKE, "HANDSHAKE", 32*e0c4386eSCy Schubert RT_ALERT, "ALERT", 33*e0c4386eSCy Schubert RT_CCS, "CCS", 34*e0c4386eSCy Schubert RT_UNKNOWN, "UNKNOWN" 35*e0c4386eSCy Schubert); 36*e0c4386eSCy Schubert 37*e0c4386eSCy Schubertuse constant { 38*e0c4386eSCy Schubert VERS_TLS_1_4 => 0x0305, 39*e0c4386eSCy Schubert VERS_TLS_1_3 => 0x0304, 40*e0c4386eSCy Schubert VERS_TLS_1_2 => 0x0303, 41*e0c4386eSCy Schubert VERS_TLS_1_1 => 0x0302, 42*e0c4386eSCy Schubert VERS_TLS_1_0 => 0x0301, 43*e0c4386eSCy Schubert VERS_SSL_3_0 => 0x0300, 44*e0c4386eSCy Schubert VERS_SSL_LT_3_0 => 0x02ff 45*e0c4386eSCy Schubert}; 46*e0c4386eSCy Schubert 47*e0c4386eSCy Schubertmy %tls_version = ( 48*e0c4386eSCy Schubert VERS_TLS_1_3, "TLS1.3", 49*e0c4386eSCy Schubert VERS_TLS_1_2, "TLS1.2", 50*e0c4386eSCy Schubert VERS_TLS_1_1, "TLS1.1", 51*e0c4386eSCy Schubert VERS_TLS_1_0, "TLS1.0", 52*e0c4386eSCy Schubert VERS_SSL_3_0, "SSL3", 53*e0c4386eSCy Schubert VERS_SSL_LT_3_0, "SSL<3" 54*e0c4386eSCy Schubert); 55*e0c4386eSCy Schubert 56*e0c4386eSCy Schubert#Class method to extract records from a packet of data 57*e0c4386eSCy Schubertsub get_records 58*e0c4386eSCy Schubert{ 59*e0c4386eSCy Schubert my $class = shift; 60*e0c4386eSCy Schubert my $server = shift; 61*e0c4386eSCy Schubert my $flight = shift; 62*e0c4386eSCy Schubert my $packet = shift; 63*e0c4386eSCy Schubert my $partial = ""; 64*e0c4386eSCy Schubert my @record_list = (); 65*e0c4386eSCy Schubert my @message_list = (); 66*e0c4386eSCy Schubert 67*e0c4386eSCy Schubert my $recnum = 1; 68*e0c4386eSCy Schubert while (length ($packet) > 0) { 69*e0c4386eSCy Schubert print " Record $recnum ", $server ? "(server -> client)\n" 70*e0c4386eSCy Schubert : "(client -> server)\n"; 71*e0c4386eSCy Schubert 72*e0c4386eSCy Schubert #Get the record header (unpack can't fail if $packet is too short) 73*e0c4386eSCy Schubert my ($content_type, $version, $len) = unpack('Cnn', $packet); 74*e0c4386eSCy Schubert 75*e0c4386eSCy Schubert if (length($packet) < TLS_RECORD_HEADER_LENGTH + ($len // 0)) { 76*e0c4386eSCy Schubert print "Partial data : ".length($packet)." bytes\n"; 77*e0c4386eSCy Schubert $partial = $packet; 78*e0c4386eSCy Schubert last; 79*e0c4386eSCy Schubert } 80*e0c4386eSCy Schubert 81*e0c4386eSCy Schubert my $data = substr($packet, TLS_RECORD_HEADER_LENGTH, $len); 82*e0c4386eSCy Schubert 83*e0c4386eSCy Schubert print " Content type: ".$record_type{$content_type}."\n"; 84*e0c4386eSCy Schubert print " Version: $tls_version{$version}\n"; 85*e0c4386eSCy Schubert print " Length: $len\n"; 86*e0c4386eSCy Schubert 87*e0c4386eSCy Schubert my $record = TLSProxy::Record->new( 88*e0c4386eSCy Schubert $flight, 89*e0c4386eSCy Schubert $content_type, 90*e0c4386eSCy Schubert $version, 91*e0c4386eSCy Schubert $len, 92*e0c4386eSCy Schubert 0, 93*e0c4386eSCy Schubert $len, # len_real 94*e0c4386eSCy Schubert $len, # decrypt_len 95*e0c4386eSCy Schubert $data, # data 96*e0c4386eSCy Schubert $data # decrypt_data 97*e0c4386eSCy Schubert ); 98*e0c4386eSCy Schubert 99*e0c4386eSCy Schubert if ($content_type != RT_CCS 100*e0c4386eSCy Schubert && (!TLSProxy::Proxy->is_tls13() 101*e0c4386eSCy Schubert || $content_type != RT_ALERT)) { 102*e0c4386eSCy Schubert if (($server && $server_encrypting) 103*e0c4386eSCy Schubert || (!$server && $client_encrypting)) { 104*e0c4386eSCy Schubert if (!TLSProxy::Proxy->is_tls13() && $etm) { 105*e0c4386eSCy Schubert $record->decryptETM(); 106*e0c4386eSCy Schubert } else { 107*e0c4386eSCy Schubert $record->decrypt(); 108*e0c4386eSCy Schubert } 109*e0c4386eSCy Schubert $record->encrypted(1); 110*e0c4386eSCy Schubert 111*e0c4386eSCy Schubert if (TLSProxy::Proxy->is_tls13()) { 112*e0c4386eSCy Schubert print " Inner content type: " 113*e0c4386eSCy Schubert .$record_type{$record->content_type()}."\n"; 114*e0c4386eSCy Schubert } 115*e0c4386eSCy Schubert } 116*e0c4386eSCy Schubert } 117*e0c4386eSCy Schubert 118*e0c4386eSCy Schubert push @record_list, $record; 119*e0c4386eSCy Schubert 120*e0c4386eSCy Schubert #Now figure out what messages are contained within this record 121*e0c4386eSCy Schubert my @messages = TLSProxy::Message->get_messages($server, $record); 122*e0c4386eSCy Schubert push @message_list, @messages; 123*e0c4386eSCy Schubert 124*e0c4386eSCy Schubert $packet = substr($packet, TLS_RECORD_HEADER_LENGTH + $len); 125*e0c4386eSCy Schubert $recnum++; 126*e0c4386eSCy Schubert } 127*e0c4386eSCy Schubert 128*e0c4386eSCy Schubert return (\@record_list, \@message_list, $partial); 129*e0c4386eSCy Schubert} 130*e0c4386eSCy Schubert 131*e0c4386eSCy Schubertsub clear 132*e0c4386eSCy Schubert{ 133*e0c4386eSCy Schubert $server_encrypting = 0; 134*e0c4386eSCy Schubert $client_encrypting = 0; 135*e0c4386eSCy Schubert} 136*e0c4386eSCy Schubert 137*e0c4386eSCy Schubert#Class level accessors 138*e0c4386eSCy Schubertsub server_encrypting 139*e0c4386eSCy Schubert{ 140*e0c4386eSCy Schubert my $class = shift; 141*e0c4386eSCy Schubert if (@_) { 142*e0c4386eSCy Schubert $server_encrypting = shift; 143*e0c4386eSCy Schubert } 144*e0c4386eSCy Schubert return $server_encrypting; 145*e0c4386eSCy Schubert} 146*e0c4386eSCy Schubertsub client_encrypting 147*e0c4386eSCy Schubert{ 148*e0c4386eSCy Schubert my $class = shift; 149*e0c4386eSCy Schubert if (@_) { 150*e0c4386eSCy Schubert $client_encrypting= shift; 151*e0c4386eSCy Schubert } 152*e0c4386eSCy Schubert return $client_encrypting; 153*e0c4386eSCy Schubert} 154*e0c4386eSCy Schubert#Enable/Disable Encrypt-then-MAC 155*e0c4386eSCy Schubertsub etm 156*e0c4386eSCy Schubert{ 157*e0c4386eSCy Schubert my $class = shift; 158*e0c4386eSCy Schubert if (@_) { 159*e0c4386eSCy Schubert $etm = shift; 160*e0c4386eSCy Schubert } 161*e0c4386eSCy Schubert return $etm; 162*e0c4386eSCy Schubert} 163*e0c4386eSCy Schubert 164*e0c4386eSCy Schubertsub new 165*e0c4386eSCy Schubert{ 166*e0c4386eSCy Schubert my $class = shift; 167*e0c4386eSCy Schubert my ($flight, 168*e0c4386eSCy Schubert $content_type, 169*e0c4386eSCy Schubert $version, 170*e0c4386eSCy Schubert $len, 171*e0c4386eSCy Schubert $sslv2, 172*e0c4386eSCy Schubert $len_real, 173*e0c4386eSCy Schubert $decrypt_len, 174*e0c4386eSCy Schubert $data, 175*e0c4386eSCy Schubert $decrypt_data) = @_; 176*e0c4386eSCy Schubert 177*e0c4386eSCy Schubert my $self = { 178*e0c4386eSCy Schubert flight => $flight, 179*e0c4386eSCy Schubert content_type => $content_type, 180*e0c4386eSCy Schubert version => $version, 181*e0c4386eSCy Schubert len => $len, 182*e0c4386eSCy Schubert sslv2 => $sslv2, 183*e0c4386eSCy Schubert len_real => $len_real, 184*e0c4386eSCy Schubert decrypt_len => $decrypt_len, 185*e0c4386eSCy Schubert data => $data, 186*e0c4386eSCy Schubert decrypt_data => $decrypt_data, 187*e0c4386eSCy Schubert orig_decrypt_data => $decrypt_data, 188*e0c4386eSCy Schubert sent => 0, 189*e0c4386eSCy Schubert encrypted => 0, 190*e0c4386eSCy Schubert outer_content_type => RT_APPLICATION_DATA 191*e0c4386eSCy Schubert }; 192*e0c4386eSCy Schubert 193*e0c4386eSCy Schubert return bless $self, $class; 194*e0c4386eSCy Schubert} 195*e0c4386eSCy Schubert 196*e0c4386eSCy Schubert#Decrypt using encrypt-then-MAC 197*e0c4386eSCy Schubertsub decryptETM 198*e0c4386eSCy Schubert{ 199*e0c4386eSCy Schubert my ($self) = shift; 200*e0c4386eSCy Schubert 201*e0c4386eSCy Schubert my $data = $self->data; 202*e0c4386eSCy Schubert 203*e0c4386eSCy Schubert if($self->version >= VERS_TLS_1_1()) { 204*e0c4386eSCy Schubert #TLS1.1+ has an explicit IV. Throw it away 205*e0c4386eSCy Schubert $data = substr($data, 16); 206*e0c4386eSCy Schubert } 207*e0c4386eSCy Schubert 208*e0c4386eSCy Schubert #Throw away the MAC (assumes MAC is 20 bytes for now. FIXME) 209*e0c4386eSCy Schubert $data = substr($data, 0, length($data) - 20); 210*e0c4386eSCy Schubert 211*e0c4386eSCy Schubert #Find out what the padding byte is 212*e0c4386eSCy Schubert my $padval = unpack("C", substr($data, length($data) - 1)); 213*e0c4386eSCy Schubert 214*e0c4386eSCy Schubert #Throw away the padding 215*e0c4386eSCy Schubert $data = substr($data, 0, length($data) - ($padval + 1)); 216*e0c4386eSCy Schubert 217*e0c4386eSCy Schubert $self->decrypt_data($data); 218*e0c4386eSCy Schubert $self->decrypt_len(length($data)); 219*e0c4386eSCy Schubert 220*e0c4386eSCy Schubert return $data; 221*e0c4386eSCy Schubert} 222*e0c4386eSCy Schubert 223*e0c4386eSCy Schubert#Standard decrypt 224*e0c4386eSCy Schubertsub decrypt() 225*e0c4386eSCy Schubert{ 226*e0c4386eSCy Schubert my ($self) = shift; 227*e0c4386eSCy Schubert my $mactaglen = 20; 228*e0c4386eSCy Schubert my $data = $self->data; 229*e0c4386eSCy Schubert 230*e0c4386eSCy Schubert #Throw away any IVs 231*e0c4386eSCy Schubert if (TLSProxy::Proxy->is_tls13()) { 232*e0c4386eSCy Schubert #A TLS1.3 client, when processing the server's initial flight, could 233*e0c4386eSCy Schubert #respond with either an encrypted or an unencrypted alert. 234*e0c4386eSCy Schubert if ($self->content_type() == RT_ALERT) { 235*e0c4386eSCy Schubert #TODO(TLS1.3): Eventually it is sufficient just to check the record 236*e0c4386eSCy Schubert #content type. If an alert is encrypted it will have a record 237*e0c4386eSCy Schubert #content type of application data. However we haven't done the 238*e0c4386eSCy Schubert #record layer changes yet, so it's a bit more complicated. For now 239*e0c4386eSCy Schubert #we will additionally check if the data length is 2 (1 byte for 240*e0c4386eSCy Schubert #alert level, 1 byte for alert description). If it is, then this is 241*e0c4386eSCy Schubert #an unencrypted alert, so don't try to decrypt 242*e0c4386eSCy Schubert return $data if (length($data) == 2); 243*e0c4386eSCy Schubert } 244*e0c4386eSCy Schubert $mactaglen = 16; 245*e0c4386eSCy Schubert } elsif ($self->version >= VERS_TLS_1_1()) { 246*e0c4386eSCy Schubert #16 bytes for a standard IV 247*e0c4386eSCy Schubert $data = substr($data, 16); 248*e0c4386eSCy Schubert 249*e0c4386eSCy Schubert #Find out what the padding byte is 250*e0c4386eSCy Schubert my $padval = unpack("C", substr($data, length($data) - 1)); 251*e0c4386eSCy Schubert 252*e0c4386eSCy Schubert #Throw away the padding 253*e0c4386eSCy Schubert $data = substr($data, 0, length($data) - ($padval + 1)); 254*e0c4386eSCy Schubert } 255*e0c4386eSCy Schubert 256*e0c4386eSCy Schubert #Throw away the MAC or TAG 257*e0c4386eSCy Schubert $data = substr($data, 0, length($data) - $mactaglen); 258*e0c4386eSCy Schubert 259*e0c4386eSCy Schubert if (TLSProxy::Proxy->is_tls13()) { 260*e0c4386eSCy Schubert #Get the content type 261*e0c4386eSCy Schubert my $content_type = unpack("C", substr($data, length($data) - 1)); 262*e0c4386eSCy Schubert $self->content_type($content_type); 263*e0c4386eSCy Schubert $data = substr($data, 0, length($data) - 1); 264*e0c4386eSCy Schubert } 265*e0c4386eSCy Schubert 266*e0c4386eSCy Schubert $self->decrypt_data($data); 267*e0c4386eSCy Schubert $self->decrypt_len(length($data)); 268*e0c4386eSCy Schubert 269*e0c4386eSCy Schubert return $data; 270*e0c4386eSCy Schubert} 271*e0c4386eSCy Schubert 272*e0c4386eSCy Schubert#Reconstruct the on-the-wire record representation 273*e0c4386eSCy Schubertsub reconstruct_record 274*e0c4386eSCy Schubert{ 275*e0c4386eSCy Schubert my $self = shift; 276*e0c4386eSCy Schubert my $server = shift; 277*e0c4386eSCy Schubert my $data; 278*e0c4386eSCy Schubert 279*e0c4386eSCy Schubert #We only replay the records in the same direction 280*e0c4386eSCy Schubert if ($self->{sent} || ($self->flight & 1) != $server) { 281*e0c4386eSCy Schubert return ""; 282*e0c4386eSCy Schubert } 283*e0c4386eSCy Schubert $self->{sent} = 1; 284*e0c4386eSCy Schubert 285*e0c4386eSCy Schubert if ($self->sslv2) { 286*e0c4386eSCy Schubert $data = pack('n', $self->len | 0x8000); 287*e0c4386eSCy Schubert } else { 288*e0c4386eSCy Schubert if (TLSProxy::Proxy->is_tls13() && $self->encrypted) { 289*e0c4386eSCy Schubert $data = pack('Cnn', $self->outer_content_type, $self->version, 290*e0c4386eSCy Schubert $self->len); 291*e0c4386eSCy Schubert } else { 292*e0c4386eSCy Schubert $data = pack('Cnn', $self->content_type, $self->version, 293*e0c4386eSCy Schubert $self->len); 294*e0c4386eSCy Schubert } 295*e0c4386eSCy Schubert 296*e0c4386eSCy Schubert } 297*e0c4386eSCy Schubert $data .= $self->data; 298*e0c4386eSCy Schubert 299*e0c4386eSCy Schubert return $data; 300*e0c4386eSCy Schubert} 301*e0c4386eSCy Schubert 302*e0c4386eSCy Schubert#Read only accessors 303*e0c4386eSCy Schubertsub flight 304*e0c4386eSCy Schubert{ 305*e0c4386eSCy Schubert my $self = shift; 306*e0c4386eSCy Schubert return $self->{flight}; 307*e0c4386eSCy Schubert} 308*e0c4386eSCy Schubertsub sslv2 309*e0c4386eSCy Schubert{ 310*e0c4386eSCy Schubert my $self = shift; 311*e0c4386eSCy Schubert return $self->{sslv2}; 312*e0c4386eSCy Schubert} 313*e0c4386eSCy Schubertsub len_real 314*e0c4386eSCy Schubert{ 315*e0c4386eSCy Schubert my $self = shift; 316*e0c4386eSCy Schubert return $self->{len_real}; 317*e0c4386eSCy Schubert} 318*e0c4386eSCy Schubertsub orig_decrypt_data 319*e0c4386eSCy Schubert{ 320*e0c4386eSCy Schubert my $self = shift; 321*e0c4386eSCy Schubert return $self->{orig_decrypt_data}; 322*e0c4386eSCy Schubert} 323*e0c4386eSCy Schubert 324*e0c4386eSCy Schubert#Read/write accessors 325*e0c4386eSCy Schubertsub decrypt_len 326*e0c4386eSCy Schubert{ 327*e0c4386eSCy Schubert my $self = shift; 328*e0c4386eSCy Schubert if (@_) { 329*e0c4386eSCy Schubert $self->{decrypt_len} = shift; 330*e0c4386eSCy Schubert } 331*e0c4386eSCy Schubert return $self->{decrypt_len}; 332*e0c4386eSCy Schubert} 333*e0c4386eSCy Schubertsub data 334*e0c4386eSCy Schubert{ 335*e0c4386eSCy Schubert my $self = shift; 336*e0c4386eSCy Schubert if (@_) { 337*e0c4386eSCy Schubert $self->{data} = shift; 338*e0c4386eSCy Schubert } 339*e0c4386eSCy Schubert return $self->{data}; 340*e0c4386eSCy Schubert} 341*e0c4386eSCy Schubertsub decrypt_data 342*e0c4386eSCy Schubert{ 343*e0c4386eSCy Schubert my $self = shift; 344*e0c4386eSCy Schubert if (@_) { 345*e0c4386eSCy Schubert $self->{decrypt_data} = shift; 346*e0c4386eSCy Schubert } 347*e0c4386eSCy Schubert return $self->{decrypt_data}; 348*e0c4386eSCy Schubert} 349*e0c4386eSCy Schubertsub len 350*e0c4386eSCy Schubert{ 351*e0c4386eSCy Schubert my $self = shift; 352*e0c4386eSCy Schubert if (@_) { 353*e0c4386eSCy Schubert $self->{len} = shift; 354*e0c4386eSCy Schubert } 355*e0c4386eSCy Schubert return $self->{len}; 356*e0c4386eSCy Schubert} 357*e0c4386eSCy Schubertsub version 358*e0c4386eSCy Schubert{ 359*e0c4386eSCy Schubert my $self = shift; 360*e0c4386eSCy Schubert if (@_) { 361*e0c4386eSCy Schubert $self->{version} = shift; 362*e0c4386eSCy Schubert } 363*e0c4386eSCy Schubert return $self->{version}; 364*e0c4386eSCy Schubert} 365*e0c4386eSCy Schubertsub content_type 366*e0c4386eSCy Schubert{ 367*e0c4386eSCy Schubert my $self = shift; 368*e0c4386eSCy Schubert if (@_) { 369*e0c4386eSCy Schubert $self->{content_type} = shift; 370*e0c4386eSCy Schubert } 371*e0c4386eSCy Schubert return $self->{content_type}; 372*e0c4386eSCy Schubert} 373*e0c4386eSCy Schubertsub encrypted 374*e0c4386eSCy Schubert{ 375*e0c4386eSCy Schubert my $self = shift; 376*e0c4386eSCy Schubert if (@_) { 377*e0c4386eSCy Schubert $self->{encrypted} = shift; 378*e0c4386eSCy Schubert } 379*e0c4386eSCy Schubert return $self->{encrypted}; 380*e0c4386eSCy Schubert} 381*e0c4386eSCy Schubertsub outer_content_type 382*e0c4386eSCy Schubert{ 383*e0c4386eSCy Schubert my $self = shift; 384*e0c4386eSCy Schubert if (@_) { 385*e0c4386eSCy Schubert $self->{outer_content_type} = shift; 386*e0c4386eSCy Schubert } 387*e0c4386eSCy Schubert return $self->{outer_content_type}; 388*e0c4386eSCy Schubert} 389*e0c4386eSCy Schubertsub is_fatal_alert 390*e0c4386eSCy Schubert{ 391*e0c4386eSCy Schubert my $self = shift; 392*e0c4386eSCy Schubert my $server = shift; 393*e0c4386eSCy Schubert 394*e0c4386eSCy Schubert if (($self->{flight} & 1) == $server 395*e0c4386eSCy Schubert && $self->{content_type} == TLSProxy::Record::RT_ALERT) { 396*e0c4386eSCy Schubert my ($level, $alert) = unpack('CC', $self->decrypt_data); 397*e0c4386eSCy Schubert return $alert if ($level == 2); 398*e0c4386eSCy Schubert } 399*e0c4386eSCy Schubert return 0; 400*e0c4386eSCy Schubert} 401*e0c4386eSCy Schubert1; 402