Home | History | Annotate | Line # | Download | only in TLSProxy
      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