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