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