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