1*4724848cSchristos# Copyright 2016-2019 The OpenSSL Project Authors. All Rights Reserved. 2*4724848cSchristos# 3*4724848cSchristos# Licensed under the OpenSSL license (the "License"). You may not use 4*4724848cSchristos# this file except in compliance with the License. You can obtain a copy 5*4724848cSchristos# in the file LICENSE in the source distribution or at 6*4724848cSchristos# https://www.openssl.org/source/license.html 7*4724848cSchristos 8*4724848cSchristosuse strict; 9*4724848cSchristos 10*4724848cSchristospackage TLSProxy::ClientHello; 11*4724848cSchristos 12*4724848cSchristosuse vars '@ISA'; 13*4724848cSchristospush @ISA, 'TLSProxy::Message'; 14*4724848cSchristos 15*4724848cSchristossub new 16*4724848cSchristos{ 17*4724848cSchristos my $class = shift; 18*4724848cSchristos my ($server, 19*4724848cSchristos $data, 20*4724848cSchristos $records, 21*4724848cSchristos $startoffset, 22*4724848cSchristos $message_frag_lens) = @_; 23*4724848cSchristos 24*4724848cSchristos my $self = $class->SUPER::new( 25*4724848cSchristos $server, 26*4724848cSchristos 1, 27*4724848cSchristos $data, 28*4724848cSchristos $records, 29*4724848cSchristos $startoffset, 30*4724848cSchristos $message_frag_lens); 31*4724848cSchristos 32*4724848cSchristos $self->{client_version} = 0; 33*4724848cSchristos $self->{random} = []; 34*4724848cSchristos $self->{session_id_len} = 0; 35*4724848cSchristos $self->{session} = ""; 36*4724848cSchristos $self->{ciphersuite_len} = 0; 37*4724848cSchristos $self->{ciphersuites} = []; 38*4724848cSchristos $self->{comp_meth_len} = 0; 39*4724848cSchristos $self->{comp_meths} = []; 40*4724848cSchristos $self->{extensions_len} = 0; 41*4724848cSchristos $self->{extension_data} = ""; 42*4724848cSchristos 43*4724848cSchristos return $self; 44*4724848cSchristos} 45*4724848cSchristos 46*4724848cSchristossub parse 47*4724848cSchristos{ 48*4724848cSchristos my $self = shift; 49*4724848cSchristos my $ptr = 2; 50*4724848cSchristos my ($client_version) = unpack('n', $self->data); 51*4724848cSchristos my $random = substr($self->data, $ptr, 32); 52*4724848cSchristos $ptr += 32; 53*4724848cSchristos my $session_id_len = unpack('C', substr($self->data, $ptr)); 54*4724848cSchristos $ptr++; 55*4724848cSchristos my $session = substr($self->data, $ptr, $session_id_len); 56*4724848cSchristos $ptr += $session_id_len; 57*4724848cSchristos my $ciphersuite_len = unpack('n', substr($self->data, $ptr)); 58*4724848cSchristos $ptr += 2; 59*4724848cSchristos my @ciphersuites = unpack('n*', substr($self->data, $ptr, 60*4724848cSchristos $ciphersuite_len)); 61*4724848cSchristos $ptr += $ciphersuite_len; 62*4724848cSchristos my $comp_meth_len = unpack('C', substr($self->data, $ptr)); 63*4724848cSchristos $ptr++; 64*4724848cSchristos my @comp_meths = unpack('C*', substr($self->data, $ptr, $comp_meth_len)); 65*4724848cSchristos $ptr += $comp_meth_len; 66*4724848cSchristos my $extensions_len = unpack('n', substr($self->data, $ptr)); 67*4724848cSchristos $ptr += 2; 68*4724848cSchristos #For now we just deal with this as a block of data. In the future we will 69*4724848cSchristos #want to parse this 70*4724848cSchristos my $extension_data = substr($self->data, $ptr); 71*4724848cSchristos 72*4724848cSchristos if (length($extension_data) != $extensions_len) { 73*4724848cSchristos die "Invalid extension length\n"; 74*4724848cSchristos } 75*4724848cSchristos my %extensions = (); 76*4724848cSchristos while (length($extension_data) >= 4) { 77*4724848cSchristos my ($type, $size) = unpack("nn", $extension_data); 78*4724848cSchristos my $extdata = substr($extension_data, 4, $size); 79*4724848cSchristos $extension_data = substr($extension_data, 4 + $size); 80*4724848cSchristos $extensions{$type} = $extdata; 81*4724848cSchristos } 82*4724848cSchristos 83*4724848cSchristos $self->client_version($client_version); 84*4724848cSchristos $self->random($random); 85*4724848cSchristos $self->session_id_len($session_id_len); 86*4724848cSchristos $self->session($session); 87*4724848cSchristos $self->ciphersuite_len($ciphersuite_len); 88*4724848cSchristos $self->ciphersuites(\@ciphersuites); 89*4724848cSchristos $self->comp_meth_len($comp_meth_len); 90*4724848cSchristos $self->comp_meths(\@comp_meths); 91*4724848cSchristos $self->extensions_len($extensions_len); 92*4724848cSchristos $self->extension_data(\%extensions); 93*4724848cSchristos 94*4724848cSchristos $self->process_extensions(); 95*4724848cSchristos 96*4724848cSchristos print " Client Version:".$client_version."\n"; 97*4724848cSchristos print " Session ID Len:".$session_id_len."\n"; 98*4724848cSchristos print " Ciphersuite len:".$ciphersuite_len."\n"; 99*4724848cSchristos print " Compression Method Len:".$comp_meth_len."\n"; 100*4724848cSchristos print " Extensions Len:".$extensions_len."\n"; 101*4724848cSchristos} 102*4724848cSchristos 103*4724848cSchristos#Perform any actions necessary based on the extensions we've seen 104*4724848cSchristossub process_extensions 105*4724848cSchristos{ 106*4724848cSchristos my $self = shift; 107*4724848cSchristos my %extensions = %{$self->extension_data}; 108*4724848cSchristos 109*4724848cSchristos #Clear any state from a previous run 110*4724848cSchristos TLSProxy::Record->etm(0); 111*4724848cSchristos 112*4724848cSchristos if (exists $extensions{TLSProxy::Message::EXT_ENCRYPT_THEN_MAC}) { 113*4724848cSchristos TLSProxy::Record->etm(1); 114*4724848cSchristos } 115*4724848cSchristos} 116*4724848cSchristos 117*4724848cSchristossub extension_contents 118*4724848cSchristos{ 119*4724848cSchristos my $self = shift; 120*4724848cSchristos my $key = shift; 121*4724848cSchristos my $extension = ""; 122*4724848cSchristos 123*4724848cSchristos my $extdata = ${$self->extension_data}{$key}; 124*4724848cSchristos $extension .= pack("n", $key); 125*4724848cSchristos $extension .= pack("n", length($extdata)); 126*4724848cSchristos $extension .= $extdata; 127*4724848cSchristos return $extension; 128*4724848cSchristos} 129*4724848cSchristos 130*4724848cSchristos#Reconstruct the on-the-wire message data following changes 131*4724848cSchristossub set_message_contents 132*4724848cSchristos{ 133*4724848cSchristos my $self = shift; 134*4724848cSchristos my $data; 135*4724848cSchristos my $extensions = ""; 136*4724848cSchristos 137*4724848cSchristos $data = pack('n', $self->client_version); 138*4724848cSchristos $data .= $self->random; 139*4724848cSchristos $data .= pack('C', $self->session_id_len); 140*4724848cSchristos $data .= $self->session; 141*4724848cSchristos $data .= pack('n', $self->ciphersuite_len); 142*4724848cSchristos $data .= pack("n*", @{$self->ciphersuites}); 143*4724848cSchristos $data .= pack('C', $self->comp_meth_len); 144*4724848cSchristos $data .= pack("C*", @{$self->comp_meths}); 145*4724848cSchristos 146*4724848cSchristos foreach my $key (keys %{$self->extension_data}) { 147*4724848cSchristos next if ($key == TLSProxy::Message::EXT_PSK); 148*4724848cSchristos $extensions .= $self->extension_contents($key); 149*4724848cSchristos #Add extension twice if we are duplicating that extension 150*4724848cSchristos $extensions .= $self->extension_contents($key) if ($key == $self->dupext); 151*4724848cSchristos } 152*4724848cSchristos #PSK extension always goes last... 153*4724848cSchristos if (defined ${$self->extension_data}{TLSProxy::Message::EXT_PSK}) { 154*4724848cSchristos $extensions .= $self->extension_contents(TLSProxy::Message::EXT_PSK); 155*4724848cSchristos } 156*4724848cSchristos #unless we have EXT_FORCE_LAST 157*4724848cSchristos if (defined ${$self->extension_data}{TLSProxy::Message::EXT_FORCE_LAST}) { 158*4724848cSchristos $extensions .= $self->extension_contents(TLSProxy::Message::EXT_FORCE_LAST); 159*4724848cSchristos } 160*4724848cSchristos 161*4724848cSchristos $data .= pack('n', length($extensions)); 162*4724848cSchristos $data .= $extensions; 163*4724848cSchristos 164*4724848cSchristos $self->data($data); 165*4724848cSchristos} 166*4724848cSchristos 167*4724848cSchristos#Read/write accessors 168*4724848cSchristossub client_version 169*4724848cSchristos{ 170*4724848cSchristos my $self = shift; 171*4724848cSchristos if (@_) { 172*4724848cSchristos $self->{client_version} = shift; 173*4724848cSchristos } 174*4724848cSchristos return $self->{client_version}; 175*4724848cSchristos} 176*4724848cSchristossub random 177*4724848cSchristos{ 178*4724848cSchristos my $self = shift; 179*4724848cSchristos if (@_) { 180*4724848cSchristos $self->{random} = shift; 181*4724848cSchristos } 182*4724848cSchristos return $self->{random}; 183*4724848cSchristos} 184*4724848cSchristossub session_id_len 185*4724848cSchristos{ 186*4724848cSchristos my $self = shift; 187*4724848cSchristos if (@_) { 188*4724848cSchristos $self->{session_id_len} = shift; 189*4724848cSchristos } 190*4724848cSchristos return $self->{session_id_len}; 191*4724848cSchristos} 192*4724848cSchristossub session 193*4724848cSchristos{ 194*4724848cSchristos my $self = shift; 195*4724848cSchristos if (@_) { 196*4724848cSchristos $self->{session} = shift; 197*4724848cSchristos } 198*4724848cSchristos return $self->{session}; 199*4724848cSchristos} 200*4724848cSchristossub ciphersuite_len 201*4724848cSchristos{ 202*4724848cSchristos my $self = shift; 203*4724848cSchristos if (@_) { 204*4724848cSchristos $self->{ciphersuite_len} = shift; 205*4724848cSchristos } 206*4724848cSchristos return $self->{ciphersuite_len}; 207*4724848cSchristos} 208*4724848cSchristossub ciphersuites 209*4724848cSchristos{ 210*4724848cSchristos my $self = shift; 211*4724848cSchristos if (@_) { 212*4724848cSchristos $self->{ciphersuites} = shift; 213*4724848cSchristos } 214*4724848cSchristos return $self->{ciphersuites}; 215*4724848cSchristos} 216*4724848cSchristossub comp_meth_len 217*4724848cSchristos{ 218*4724848cSchristos my $self = shift; 219*4724848cSchristos if (@_) { 220*4724848cSchristos $self->{comp_meth_len} = shift; 221*4724848cSchristos } 222*4724848cSchristos return $self->{comp_meth_len}; 223*4724848cSchristos} 224*4724848cSchristossub comp_meths 225*4724848cSchristos{ 226*4724848cSchristos my $self = shift; 227*4724848cSchristos if (@_) { 228*4724848cSchristos $self->{comp_meths} = shift; 229*4724848cSchristos } 230*4724848cSchristos return $self->{comp_meths}; 231*4724848cSchristos} 232*4724848cSchristossub extensions_len 233*4724848cSchristos{ 234*4724848cSchristos my $self = shift; 235*4724848cSchristos if (@_) { 236*4724848cSchristos $self->{extensions_len} = shift; 237*4724848cSchristos } 238*4724848cSchristos return $self->{extensions_len}; 239*4724848cSchristos} 240*4724848cSchristossub extension_data 241*4724848cSchristos{ 242*4724848cSchristos my $self = shift; 243*4724848cSchristos if (@_) { 244*4724848cSchristos $self->{extension_data} = shift; 245*4724848cSchristos } 246*4724848cSchristos return $self->{extension_data}; 247*4724848cSchristos} 248*4724848cSchristossub set_extension 249*4724848cSchristos{ 250*4724848cSchristos my ($self, $ext_type, $ext_data) = @_; 251*4724848cSchristos $self->{extension_data}{$ext_type} = $ext_data; 252*4724848cSchristos} 253*4724848cSchristossub delete_extension 254*4724848cSchristos{ 255*4724848cSchristos my ($self, $ext_type) = @_; 256*4724848cSchristos delete $self->{extension_data}{$ext_type}; 257*4724848cSchristos} 258*4724848cSchristos1; 259