1*b0d17251Schristos# Copyright 2016 The OpenSSL Project Authors. All Rights Reserved. 253060421Schristos# 3*b0d17251Schristos# Licensed under the Apache License 2.0 (the "License"). You may not use 453060421Schristos# this file except in compliance with the License. You can obtain a copy 553060421Schristos# in the file LICENSE in the source distribution or at 653060421Schristos# https://www.openssl.org/source/license.html 753060421Schristos 853060421Schristosuse strict; 953060421Schristos 1053060421Schristospackage TLSProxy::ClientHello; 1153060421Schristos 1253060421Schristosuse vars '@ISA'; 1353060421Schristospush @ISA, 'TLSProxy::Message'; 1453060421Schristos 1553060421Schristossub new 1653060421Schristos{ 1753060421Schristos my $class = shift; 1853060421Schristos my ($server, 1953060421Schristos $data, 2053060421Schristos $records, 2153060421Schristos $startoffset, 2253060421Schristos $message_frag_lens) = @_; 2353060421Schristos 2453060421Schristos my $self = $class->SUPER::new( 2553060421Schristos $server, 2653060421Schristos 1, 2753060421Schristos $data, 2853060421Schristos $records, 2953060421Schristos $startoffset, 3053060421Schristos $message_frag_lens); 3153060421Schristos 3253060421Schristos $self->{client_version} = 0; 3353060421Schristos $self->{random} = []; 3453060421Schristos $self->{session_id_len} = 0; 3553060421Schristos $self->{session} = ""; 3653060421Schristos $self->{ciphersuite_len} = 0; 3753060421Schristos $self->{ciphersuites} = []; 3853060421Schristos $self->{comp_meth_len} = 0; 3953060421Schristos $self->{comp_meths} = []; 4053060421Schristos $self->{extensions_len} = 0; 4153060421Schristos $self->{extension_data} = ""; 4253060421Schristos 4353060421Schristos return $self; 4453060421Schristos} 4553060421Schristos 4653060421Schristossub parse 4753060421Schristos{ 4853060421Schristos my $self = shift; 4953060421Schristos my $ptr = 2; 5053060421Schristos my ($client_version) = unpack('n', $self->data); 5153060421Schristos my $random = substr($self->data, $ptr, 32); 5253060421Schristos $ptr += 32; 5353060421Schristos my $session_id_len = unpack('C', substr($self->data, $ptr)); 5453060421Schristos $ptr++; 5553060421Schristos my $session = substr($self->data, $ptr, $session_id_len); 5653060421Schristos $ptr += $session_id_len; 5753060421Schristos my $ciphersuite_len = unpack('n', substr($self->data, $ptr)); 5853060421Schristos $ptr += 2; 5953060421Schristos my @ciphersuites = unpack('n*', substr($self->data, $ptr, 6053060421Schristos $ciphersuite_len)); 6153060421Schristos $ptr += $ciphersuite_len; 6253060421Schristos my $comp_meth_len = unpack('C', substr($self->data, $ptr)); 6353060421Schristos $ptr++; 6453060421Schristos my @comp_meths = unpack('C*', substr($self->data, $ptr, $comp_meth_len)); 6553060421Schristos $ptr += $comp_meth_len; 6653060421Schristos my $extensions_len = unpack('n', substr($self->data, $ptr)); 6753060421Schristos $ptr += 2; 6853060421Schristos #For now we just deal with this as a block of data. In the future we will 6953060421Schristos #want to parse this 7053060421Schristos my $extension_data = substr($self->data, $ptr); 7153060421Schristos 7253060421Schristos if (length($extension_data) != $extensions_len) { 7353060421Schristos die "Invalid extension length\n"; 7453060421Schristos } 7553060421Schristos my %extensions = (); 7653060421Schristos while (length($extension_data) >= 4) { 7753060421Schristos my ($type, $size) = unpack("nn", $extension_data); 7853060421Schristos my $extdata = substr($extension_data, 4, $size); 7953060421Schristos $extension_data = substr($extension_data, 4 + $size); 8053060421Schristos $extensions{$type} = $extdata; 8153060421Schristos } 8253060421Schristos 8353060421Schristos $self->client_version($client_version); 8453060421Schristos $self->random($random); 8553060421Schristos $self->session_id_len($session_id_len); 8653060421Schristos $self->session($session); 8753060421Schristos $self->ciphersuite_len($ciphersuite_len); 8853060421Schristos $self->ciphersuites(\@ciphersuites); 8953060421Schristos $self->comp_meth_len($comp_meth_len); 9053060421Schristos $self->comp_meths(\@comp_meths); 9153060421Schristos $self->extensions_len($extensions_len); 9253060421Schristos $self->extension_data(\%extensions); 9353060421Schristos 9453060421Schristos $self->process_extensions(); 9553060421Schristos 9653060421Schristos print " Client Version:".$client_version."\n"; 9753060421Schristos print " Session ID Len:".$session_id_len."\n"; 9853060421Schristos print " Ciphersuite len:".$ciphersuite_len."\n"; 9953060421Schristos print " Compression Method Len:".$comp_meth_len."\n"; 10053060421Schristos print " Extensions Len:".$extensions_len."\n"; 10153060421Schristos} 10253060421Schristos 10353060421Schristos#Perform any actions necessary based on the extensions we've seen 10453060421Schristossub process_extensions 10553060421Schristos{ 10653060421Schristos my $self = shift; 10753060421Schristos my %extensions = %{$self->extension_data}; 10853060421Schristos 10953060421Schristos #Clear any state from a previous run 11053060421Schristos TLSProxy::Record->etm(0); 11153060421Schristos 11253060421Schristos if (exists $extensions{TLSProxy::Message::EXT_ENCRYPT_THEN_MAC}) { 11353060421Schristos TLSProxy::Record->etm(1); 11453060421Schristos } 11553060421Schristos} 11653060421Schristos 11713d40330Schristossub extension_contents 11813d40330Schristos{ 11913d40330Schristos my $self = shift; 12013d40330Schristos my $key = shift; 12113d40330Schristos my $extension = ""; 12213d40330Schristos 12313d40330Schristos my $extdata = ${$self->extension_data}{$key}; 12413d40330Schristos $extension .= pack("n", $key); 12513d40330Schristos $extension .= pack("n", length($extdata)); 12613d40330Schristos $extension .= $extdata; 12713d40330Schristos return $extension; 12813d40330Schristos} 12913d40330Schristos 13053060421Schristos#Reconstruct the on-the-wire message data following changes 13153060421Schristossub set_message_contents 13253060421Schristos{ 13353060421Schristos my $self = shift; 13453060421Schristos my $data; 13553060421Schristos my $extensions = ""; 13653060421Schristos 13753060421Schristos $data = pack('n', $self->client_version); 13853060421Schristos $data .= $self->random; 13953060421Schristos $data .= pack('C', $self->session_id_len); 14053060421Schristos $data .= $self->session; 14153060421Schristos $data .= pack('n', $self->ciphersuite_len); 14253060421Schristos $data .= pack("n*", @{$self->ciphersuites}); 14353060421Schristos $data .= pack('C', $self->comp_meth_len); 14453060421Schristos $data .= pack("C*", @{$self->comp_meths}); 14553060421Schristos 14653060421Schristos foreach my $key (keys %{$self->extension_data}) { 14713d40330Schristos next if ($key == TLSProxy::Message::EXT_PSK); 14813d40330Schristos $extensions .= $self->extension_contents($key); 149b88c74d5Schristos #Add extension twice if we are duplicating that extension 150b88c74d5Schristos $extensions .= $self->extension_contents($key) if ($key == $self->dupext); 15153060421Schristos } 15213d40330Schristos #PSK extension always goes last... 15313d40330Schristos if (defined ${$self->extension_data}{TLSProxy::Message::EXT_PSK}) { 15413d40330Schristos $extensions .= $self->extension_contents(TLSProxy::Message::EXT_PSK); 15513d40330Schristos } 15613d40330Schristos #unless we have EXT_FORCE_LAST 15713d40330Schristos if (defined ${$self->extension_data}{TLSProxy::Message::EXT_FORCE_LAST}) { 15813d40330Schristos $extensions .= $self->extension_contents(TLSProxy::Message::EXT_FORCE_LAST); 15953060421Schristos } 16053060421Schristos 16153060421Schristos $data .= pack('n', length($extensions)); 16253060421Schristos $data .= $extensions; 16353060421Schristos 16453060421Schristos $self->data($data); 16553060421Schristos} 16653060421Schristos 16753060421Schristos#Read/write accessors 16853060421Schristossub client_version 16953060421Schristos{ 17053060421Schristos my $self = shift; 17153060421Schristos if (@_) { 17253060421Schristos $self->{client_version} = shift; 17353060421Schristos } 17453060421Schristos return $self->{client_version}; 17553060421Schristos} 17653060421Schristossub random 17753060421Schristos{ 17853060421Schristos my $self = shift; 17953060421Schristos if (@_) { 18053060421Schristos $self->{random} = shift; 18153060421Schristos } 18253060421Schristos return $self->{random}; 18353060421Schristos} 18453060421Schristossub session_id_len 18553060421Schristos{ 18653060421Schristos my $self = shift; 18753060421Schristos if (@_) { 18853060421Schristos $self->{session_id_len} = shift; 18953060421Schristos } 19053060421Schristos return $self->{session_id_len}; 19153060421Schristos} 19253060421Schristossub session 19353060421Schristos{ 19453060421Schristos my $self = shift; 19553060421Schristos if (@_) { 19653060421Schristos $self->{session} = shift; 19753060421Schristos } 19853060421Schristos return $self->{session}; 19953060421Schristos} 20053060421Schristossub ciphersuite_len 20153060421Schristos{ 20253060421Schristos my $self = shift; 20353060421Schristos if (@_) { 20453060421Schristos $self->{ciphersuite_len} = shift; 20553060421Schristos } 20653060421Schristos return $self->{ciphersuite_len}; 20753060421Schristos} 20853060421Schristossub ciphersuites 20953060421Schristos{ 21053060421Schristos my $self = shift; 21153060421Schristos if (@_) { 21253060421Schristos $self->{ciphersuites} = shift; 21353060421Schristos } 21453060421Schristos return $self->{ciphersuites}; 21553060421Schristos} 21653060421Schristossub comp_meth_len 21753060421Schristos{ 21853060421Schristos my $self = shift; 21953060421Schristos if (@_) { 22053060421Schristos $self->{comp_meth_len} = shift; 22153060421Schristos } 22253060421Schristos return $self->{comp_meth_len}; 22353060421Schristos} 22453060421Schristossub comp_meths 22553060421Schristos{ 22653060421Schristos my $self = shift; 22753060421Schristos if (@_) { 22853060421Schristos $self->{comp_meths} = shift; 22953060421Schristos } 23053060421Schristos return $self->{comp_meths}; 23153060421Schristos} 23253060421Schristossub extensions_len 23353060421Schristos{ 23453060421Schristos my $self = shift; 23553060421Schristos if (@_) { 23653060421Schristos $self->{extensions_len} = shift; 23753060421Schristos } 23853060421Schristos return $self->{extensions_len}; 23953060421Schristos} 24053060421Schristossub extension_data 24153060421Schristos{ 24253060421Schristos my $self = shift; 24353060421Schristos if (@_) { 24453060421Schristos $self->{extension_data} = shift; 24553060421Schristos } 24653060421Schristos return $self->{extension_data}; 24753060421Schristos} 24853060421Schristossub set_extension 24953060421Schristos{ 25053060421Schristos my ($self, $ext_type, $ext_data) = @_; 25153060421Schristos $self->{extension_data}{$ext_type} = $ext_data; 25253060421Schristos} 25353060421Schristossub delete_extension 25453060421Schristos{ 25553060421Schristos my ($self, $ext_type) = @_; 25653060421Schristos delete $self->{extension_data}{$ext_type}; 25753060421Schristos} 25853060421Schristos1; 259