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