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