1e1051a39Sopenharmony_ci# Copyright 2016-2018 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::ServerHello; 11e1051a39Sopenharmony_ci 12e1051a39Sopenharmony_ciuse vars '@ISA'; 13e1051a39Sopenharmony_cipush @ISA, 'TLSProxy::Message'; 14e1051a39Sopenharmony_ci 15e1051a39Sopenharmony_cimy $hrrrandom = pack("C*", 0xCF, 0x21, 0xAD, 0x74, 0xE5, 0x9A, 0x61, 0x11, 0xBE, 16e1051a39Sopenharmony_ci 0x1D, 0x8C, 0x02, 0x1E, 0x65, 0xB8, 0x91, 0xC2, 0xA2, 17e1051a39Sopenharmony_ci 0x11, 0x16, 0x7A, 0xBB, 0x8C, 0x5E, 0x07, 0x9E, 0x09, 18e1051a39Sopenharmony_ci 0xE2, 0xC8, 0xA8, 0x33, 0x9C); 19e1051a39Sopenharmony_ci 20e1051a39Sopenharmony_cisub new 21e1051a39Sopenharmony_ci{ 22e1051a39Sopenharmony_ci my $class = shift; 23e1051a39Sopenharmony_ci my ($server, 24e1051a39Sopenharmony_ci $data, 25e1051a39Sopenharmony_ci $records, 26e1051a39Sopenharmony_ci $startoffset, 27e1051a39Sopenharmony_ci $message_frag_lens) = @_; 28e1051a39Sopenharmony_ci 29e1051a39Sopenharmony_ci my $self = $class->SUPER::new( 30e1051a39Sopenharmony_ci $server, 31e1051a39Sopenharmony_ci TLSProxy::Message::MT_SERVER_HELLO, 32e1051a39Sopenharmony_ci $data, 33e1051a39Sopenharmony_ci $records, 34e1051a39Sopenharmony_ci $startoffset, 35e1051a39Sopenharmony_ci $message_frag_lens); 36e1051a39Sopenharmony_ci 37e1051a39Sopenharmony_ci $self->{server_version} = 0; 38e1051a39Sopenharmony_ci $self->{random} = []; 39e1051a39Sopenharmony_ci $self->{session_id_len} = 0; 40e1051a39Sopenharmony_ci $self->{session} = ""; 41e1051a39Sopenharmony_ci $self->{ciphersuite} = 0; 42e1051a39Sopenharmony_ci $self->{comp_meth} = 0; 43e1051a39Sopenharmony_ci $self->{extension_data} = ""; 44e1051a39Sopenharmony_ci 45e1051a39Sopenharmony_ci return $self; 46e1051a39Sopenharmony_ci} 47e1051a39Sopenharmony_ci 48e1051a39Sopenharmony_cisub parse 49e1051a39Sopenharmony_ci{ 50e1051a39Sopenharmony_ci my $self = shift; 51e1051a39Sopenharmony_ci my $ptr = 2; 52e1051a39Sopenharmony_ci my ($server_version) = unpack('n', $self->data); 53e1051a39Sopenharmony_ci my $neg_version = $server_version; 54e1051a39Sopenharmony_ci 55e1051a39Sopenharmony_ci my $random = substr($self->data, $ptr, 32); 56e1051a39Sopenharmony_ci $ptr += 32; 57e1051a39Sopenharmony_ci my $session_id_len = 0; 58e1051a39Sopenharmony_ci my $session = ""; 59e1051a39Sopenharmony_ci $session_id_len = unpack('C', substr($self->data, $ptr)); 60e1051a39Sopenharmony_ci $ptr++; 61e1051a39Sopenharmony_ci $session = substr($self->data, $ptr, $session_id_len); 62e1051a39Sopenharmony_ci $ptr += $session_id_len; 63e1051a39Sopenharmony_ci 64e1051a39Sopenharmony_ci my $ciphersuite = unpack('n', substr($self->data, $ptr)); 65e1051a39Sopenharmony_ci $ptr += 2; 66e1051a39Sopenharmony_ci my $comp_meth = 0; 67e1051a39Sopenharmony_ci $comp_meth = unpack('C', substr($self->data, $ptr)); 68e1051a39Sopenharmony_ci $ptr++; 69e1051a39Sopenharmony_ci 70e1051a39Sopenharmony_ci my $extensions_len = unpack('n', substr($self->data, $ptr)); 71e1051a39Sopenharmony_ci if (!defined $extensions_len) { 72e1051a39Sopenharmony_ci $extensions_len = 0; 73e1051a39Sopenharmony_ci } else { 74e1051a39Sopenharmony_ci $ptr += 2; 75e1051a39Sopenharmony_ci } 76e1051a39Sopenharmony_ci #For now we just deal with this as a block of data. In the future we will 77e1051a39Sopenharmony_ci #want to parse this 78e1051a39Sopenharmony_ci my $extension_data; 79e1051a39Sopenharmony_ci if ($extensions_len != 0) { 80e1051a39Sopenharmony_ci $extension_data = substr($self->data, $ptr); 81e1051a39Sopenharmony_ci 82e1051a39Sopenharmony_ci if (length($extension_data) != $extensions_len) { 83e1051a39Sopenharmony_ci die "Invalid extension length\n"; 84e1051a39Sopenharmony_ci } 85e1051a39Sopenharmony_ci } else { 86e1051a39Sopenharmony_ci if (length($self->data) != $ptr) { 87e1051a39Sopenharmony_ci die "Invalid extension length\n"; 88e1051a39Sopenharmony_ci } 89e1051a39Sopenharmony_ci $extension_data = ""; 90e1051a39Sopenharmony_ci } 91e1051a39Sopenharmony_ci my %extensions = (); 92e1051a39Sopenharmony_ci while (length($extension_data) >= 4) { 93e1051a39Sopenharmony_ci my ($type, $size) = unpack("nn", $extension_data); 94e1051a39Sopenharmony_ci my $extdata = substr($extension_data, 4, $size); 95e1051a39Sopenharmony_ci $extension_data = substr($extension_data, 4 + $size); 96e1051a39Sopenharmony_ci $extensions{$type} = $extdata; 97e1051a39Sopenharmony_ci if ($type == TLSProxy::Message::EXT_SUPPORTED_VERSIONS) { 98e1051a39Sopenharmony_ci $neg_version = unpack('n', $extdata); 99e1051a39Sopenharmony_ci } 100e1051a39Sopenharmony_ci } 101e1051a39Sopenharmony_ci 102e1051a39Sopenharmony_ci if ($random eq $hrrrandom) { 103e1051a39Sopenharmony_ci TLSProxy::Proxy->is_tls13(1); 104e1051a39Sopenharmony_ci } elsif ($neg_version == TLSProxy::Record::VERS_TLS_1_3) { 105e1051a39Sopenharmony_ci TLSProxy::Proxy->is_tls13(1); 106e1051a39Sopenharmony_ci 107e1051a39Sopenharmony_ci TLSProxy::Record->server_encrypting(1); 108e1051a39Sopenharmony_ci TLSProxy::Record->client_encrypting(1); 109e1051a39Sopenharmony_ci } 110e1051a39Sopenharmony_ci 111e1051a39Sopenharmony_ci $self->server_version($server_version); 112e1051a39Sopenharmony_ci $self->random($random); 113e1051a39Sopenharmony_ci $self->session_id_len($session_id_len); 114e1051a39Sopenharmony_ci $self->session($session); 115e1051a39Sopenharmony_ci $self->ciphersuite($ciphersuite); 116e1051a39Sopenharmony_ci TLSProxy::Proxy->ciphersuite($ciphersuite); 117e1051a39Sopenharmony_ci $self->comp_meth($comp_meth); 118e1051a39Sopenharmony_ci $self->extension_data(\%extensions); 119e1051a39Sopenharmony_ci 120e1051a39Sopenharmony_ci $self->process_data(); 121e1051a39Sopenharmony_ci 122e1051a39Sopenharmony_ci 123e1051a39Sopenharmony_ci print " Server Version:".$server_version."\n"; 124e1051a39Sopenharmony_ci print " Session ID Len:".$session_id_len."\n"; 125e1051a39Sopenharmony_ci print " Ciphersuite:".$ciphersuite."\n"; 126e1051a39Sopenharmony_ci print " Compression Method:".$comp_meth."\n"; 127e1051a39Sopenharmony_ci print " Extensions Len:".$extensions_len."\n"; 128e1051a39Sopenharmony_ci} 129e1051a39Sopenharmony_ci 130e1051a39Sopenharmony_ci#Perform any actions necessary based on the data we've seen 131e1051a39Sopenharmony_cisub process_data 132e1051a39Sopenharmony_ci{ 133e1051a39Sopenharmony_ci my $self = shift; 134e1051a39Sopenharmony_ci 135e1051a39Sopenharmony_ci TLSProxy::Message->ciphersuite($self->ciphersuite); 136e1051a39Sopenharmony_ci} 137e1051a39Sopenharmony_ci 138e1051a39Sopenharmony_ci#Reconstruct the on-the-wire message data following changes 139e1051a39Sopenharmony_cisub set_message_contents 140e1051a39Sopenharmony_ci{ 141e1051a39Sopenharmony_ci my $self = shift; 142e1051a39Sopenharmony_ci my $data; 143e1051a39Sopenharmony_ci my $extensions = ""; 144e1051a39Sopenharmony_ci 145e1051a39Sopenharmony_ci $data = pack('n', $self->server_version); 146e1051a39Sopenharmony_ci $data .= $self->random; 147e1051a39Sopenharmony_ci $data .= pack('C', $self->session_id_len); 148e1051a39Sopenharmony_ci $data .= $self->session; 149e1051a39Sopenharmony_ci $data .= pack('n', $self->ciphersuite); 150e1051a39Sopenharmony_ci $data .= pack('C', $self->comp_meth); 151e1051a39Sopenharmony_ci 152e1051a39Sopenharmony_ci foreach my $key (keys %{$self->extension_data}) { 153e1051a39Sopenharmony_ci my $extdata = ${$self->extension_data}{$key}; 154e1051a39Sopenharmony_ci $extensions .= pack("n", $key); 155e1051a39Sopenharmony_ci $extensions .= pack("n", length($extdata)); 156e1051a39Sopenharmony_ci $extensions .= $extdata; 157e1051a39Sopenharmony_ci if ($key == $self->dupext) { 158e1051a39Sopenharmony_ci $extensions .= pack("n", $key); 159e1051a39Sopenharmony_ci $extensions .= pack("n", length($extdata)); 160e1051a39Sopenharmony_ci $extensions .= $extdata; 161e1051a39Sopenharmony_ci } 162e1051a39Sopenharmony_ci } 163e1051a39Sopenharmony_ci 164e1051a39Sopenharmony_ci $data .= pack('n', length($extensions)); 165e1051a39Sopenharmony_ci $data .= $extensions; 166e1051a39Sopenharmony_ci $self->data($data); 167e1051a39Sopenharmony_ci} 168e1051a39Sopenharmony_ci 169e1051a39Sopenharmony_ci#Read/write accessors 170e1051a39Sopenharmony_cisub server_version 171e1051a39Sopenharmony_ci{ 172e1051a39Sopenharmony_ci my $self = shift; 173e1051a39Sopenharmony_ci if (@_) { 174e1051a39Sopenharmony_ci $self->{server_version} = shift; 175e1051a39Sopenharmony_ci } 176e1051a39Sopenharmony_ci return $self->{server_version}; 177e1051a39Sopenharmony_ci} 178e1051a39Sopenharmony_cisub random 179e1051a39Sopenharmony_ci{ 180e1051a39Sopenharmony_ci my $self = shift; 181e1051a39Sopenharmony_ci if (@_) { 182e1051a39Sopenharmony_ci $self->{random} = shift; 183e1051a39Sopenharmony_ci } 184e1051a39Sopenharmony_ci return $self->{random}; 185e1051a39Sopenharmony_ci} 186e1051a39Sopenharmony_cisub session_id_len 187e1051a39Sopenharmony_ci{ 188e1051a39Sopenharmony_ci my $self = shift; 189e1051a39Sopenharmony_ci if (@_) { 190e1051a39Sopenharmony_ci $self->{session_id_len} = shift; 191e1051a39Sopenharmony_ci } 192e1051a39Sopenharmony_ci return $self->{session_id_len}; 193e1051a39Sopenharmony_ci} 194e1051a39Sopenharmony_cisub session 195e1051a39Sopenharmony_ci{ 196e1051a39Sopenharmony_ci my $self = shift; 197e1051a39Sopenharmony_ci if (@_) { 198e1051a39Sopenharmony_ci $self->{session} = shift; 199e1051a39Sopenharmony_ci } 200e1051a39Sopenharmony_ci return $self->{session}; 201e1051a39Sopenharmony_ci} 202e1051a39Sopenharmony_cisub ciphersuite 203e1051a39Sopenharmony_ci{ 204e1051a39Sopenharmony_ci my $self = shift; 205e1051a39Sopenharmony_ci if (@_) { 206e1051a39Sopenharmony_ci $self->{ciphersuite} = shift; 207e1051a39Sopenharmony_ci } 208e1051a39Sopenharmony_ci return $self->{ciphersuite}; 209e1051a39Sopenharmony_ci} 210e1051a39Sopenharmony_cisub comp_meth 211e1051a39Sopenharmony_ci{ 212e1051a39Sopenharmony_ci my $self = shift; 213e1051a39Sopenharmony_ci if (@_) { 214e1051a39Sopenharmony_ci $self->{comp_meth} = shift; 215e1051a39Sopenharmony_ci } 216e1051a39Sopenharmony_ci return $self->{comp_meth}; 217e1051a39Sopenharmony_ci} 218e1051a39Sopenharmony_cisub extension_data 219e1051a39Sopenharmony_ci{ 220e1051a39Sopenharmony_ci my $self = shift; 221e1051a39Sopenharmony_ci if (@_) { 222e1051a39Sopenharmony_ci $self->{extension_data} = shift; 223e1051a39Sopenharmony_ci } 224e1051a39Sopenharmony_ci return $self->{extension_data}; 225e1051a39Sopenharmony_ci} 226e1051a39Sopenharmony_cisub set_extension 227e1051a39Sopenharmony_ci{ 228e1051a39Sopenharmony_ci my ($self, $ext_type, $ext_data) = @_; 229e1051a39Sopenharmony_ci $self->{extension_data}{$ext_type} = $ext_data; 230e1051a39Sopenharmony_ci} 231e1051a39Sopenharmony_cisub delete_extension 232e1051a39Sopenharmony_ci{ 233e1051a39Sopenharmony_ci my ($self, $ext_type) = @_; 234e1051a39Sopenharmony_ci delete $self->{extension_data}{$ext_type}; 235e1051a39Sopenharmony_ci} 236e1051a39Sopenharmony_ci1; 237