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