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