1 # Copyright 2016-2019 The OpenSSL Project Authors. All Rights Reserved. 2 # 3 # Licensed under the OpenSSL license (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 8 use strict; 9 10 package TLSProxy::ServerHello; 11 12 use vars '@ISA'; 13 push @ISA, 'TLSProxy::Message'; 14 15 my $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 20 sub 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 48 sub 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 131 sub 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 139 sub 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 170 sub server_version 171 { 172 my $self = shift; 173 if (@_) { 174 $self->{server_version} = shift; 175 } 176 return $self->{server_version}; 177 } 178 sub random 179 { 180 my $self = shift; 181 if (@_) { 182 $self->{random} = shift; 183 } 184 return $self->{random}; 185 } 186 sub session_id_len 187 { 188 my $self = shift; 189 if (@_) { 190 $self->{session_id_len} = shift; 191 } 192 return $self->{session_id_len}; 193 } 194 sub session 195 { 196 my $self = shift; 197 if (@_) { 198 $self->{session} = shift; 199 } 200 return $self->{session}; 201 } 202 sub ciphersuite 203 { 204 my $self = shift; 205 if (@_) { 206 $self->{ciphersuite} = shift; 207 } 208 return $self->{ciphersuite}; 209 } 210 sub comp_meth 211 { 212 my $self = shift; 213 if (@_) { 214 $self->{comp_meth} = shift; 215 } 216 return $self->{comp_meth}; 217 } 218 sub extension_data 219 { 220 my $self = shift; 221 if (@_) { 222 $self->{extension_data} = shift; 223 } 224 return $self->{extension_data}; 225 } 226 sub set_extension 227 { 228 my ($self, $ext_type, $ext_data) = @_; 229 $self->{extension_data}{$ext_type} = $ext_data; 230 } 231 sub delete_extension 232 { 233 my ($self, $ext_type) = @_; 234 delete $self->{extension_data}{$ext_type}; 235 } 236 1; 237