xref: /freebsd-src/crypto/openssl/util/perl/TLSProxy/ClientHello.pm (revision e0c4386e7e71d93b0edc0c8fa156263fc4a8b0b6)
1*e0c4386eSCy Schubert# Copyright 2016 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::ClientHello;
11*e0c4386eSCy Schubert
12*e0c4386eSCy Schubertuse vars '@ISA';
13*e0c4386eSCy Schubertpush @ISA, 'TLSProxy::Message';
14*e0c4386eSCy Schubert
15*e0c4386eSCy Schubertsub new
16*e0c4386eSCy Schubert{
17*e0c4386eSCy Schubert    my $class = shift;
18*e0c4386eSCy Schubert    my ($server,
19*e0c4386eSCy Schubert        $data,
20*e0c4386eSCy Schubert        $records,
21*e0c4386eSCy Schubert        $startoffset,
22*e0c4386eSCy Schubert        $message_frag_lens) = @_;
23*e0c4386eSCy Schubert
24*e0c4386eSCy Schubert    my $self = $class->SUPER::new(
25*e0c4386eSCy Schubert        $server,
26*e0c4386eSCy Schubert        1,
27*e0c4386eSCy Schubert        $data,
28*e0c4386eSCy Schubert        $records,
29*e0c4386eSCy Schubert        $startoffset,
30*e0c4386eSCy Schubert        $message_frag_lens);
31*e0c4386eSCy Schubert
32*e0c4386eSCy Schubert    $self->{client_version} = 0;
33*e0c4386eSCy Schubert    $self->{random} = [];
34*e0c4386eSCy Schubert    $self->{session_id_len} = 0;
35*e0c4386eSCy Schubert    $self->{session} = "";
36*e0c4386eSCy Schubert    $self->{ciphersuite_len} = 0;
37*e0c4386eSCy Schubert    $self->{ciphersuites} = [];
38*e0c4386eSCy Schubert    $self->{comp_meth_len} = 0;
39*e0c4386eSCy Schubert    $self->{comp_meths} = [];
40*e0c4386eSCy Schubert    $self->{extensions_len} = 0;
41*e0c4386eSCy Schubert    $self->{extension_data} = "";
42*e0c4386eSCy Schubert
43*e0c4386eSCy Schubert    return $self;
44*e0c4386eSCy Schubert}
45*e0c4386eSCy Schubert
46*e0c4386eSCy Schubertsub parse
47*e0c4386eSCy Schubert{
48*e0c4386eSCy Schubert    my $self = shift;
49*e0c4386eSCy Schubert    my $ptr = 2;
50*e0c4386eSCy Schubert    my ($client_version) = unpack('n', $self->data);
51*e0c4386eSCy Schubert    my $random = substr($self->data, $ptr, 32);
52*e0c4386eSCy Schubert    $ptr += 32;
53*e0c4386eSCy Schubert    my $session_id_len = unpack('C', substr($self->data, $ptr));
54*e0c4386eSCy Schubert    $ptr++;
55*e0c4386eSCy Schubert    my $session = substr($self->data, $ptr, $session_id_len);
56*e0c4386eSCy Schubert    $ptr += $session_id_len;
57*e0c4386eSCy Schubert    my $ciphersuite_len = unpack('n', substr($self->data, $ptr));
58*e0c4386eSCy Schubert    $ptr += 2;
59*e0c4386eSCy Schubert    my @ciphersuites = unpack('n*', substr($self->data, $ptr,
60*e0c4386eSCy Schubert                                           $ciphersuite_len));
61*e0c4386eSCy Schubert    $ptr += $ciphersuite_len;
62*e0c4386eSCy Schubert    my $comp_meth_len = unpack('C', substr($self->data, $ptr));
63*e0c4386eSCy Schubert    $ptr++;
64*e0c4386eSCy Schubert    my @comp_meths = unpack('C*', substr($self->data, $ptr, $comp_meth_len));
65*e0c4386eSCy Schubert    $ptr += $comp_meth_len;
66*e0c4386eSCy Schubert    my $extensions_len = unpack('n', substr($self->data, $ptr));
67*e0c4386eSCy Schubert    $ptr += 2;
68*e0c4386eSCy Schubert    #For now we just deal with this as a block of data. In the future we will
69*e0c4386eSCy Schubert    #want to parse this
70*e0c4386eSCy Schubert    my $extension_data = substr($self->data, $ptr);
71*e0c4386eSCy Schubert
72*e0c4386eSCy Schubert    if (length($extension_data) != $extensions_len) {
73*e0c4386eSCy Schubert        die "Invalid extension length\n";
74*e0c4386eSCy Schubert    }
75*e0c4386eSCy Schubert    my %extensions = ();
76*e0c4386eSCy Schubert    while (length($extension_data) >= 4) {
77*e0c4386eSCy Schubert        my ($type, $size) = unpack("nn", $extension_data);
78*e0c4386eSCy Schubert        my $extdata = substr($extension_data, 4, $size);
79*e0c4386eSCy Schubert        $extension_data = substr($extension_data, 4 + $size);
80*e0c4386eSCy Schubert        $extensions{$type} = $extdata;
81*e0c4386eSCy Schubert    }
82*e0c4386eSCy Schubert
83*e0c4386eSCy Schubert    $self->client_version($client_version);
84*e0c4386eSCy Schubert    $self->random($random);
85*e0c4386eSCy Schubert    $self->session_id_len($session_id_len);
86*e0c4386eSCy Schubert    $self->session($session);
87*e0c4386eSCy Schubert    $self->ciphersuite_len($ciphersuite_len);
88*e0c4386eSCy Schubert    $self->ciphersuites(\@ciphersuites);
89*e0c4386eSCy Schubert    $self->comp_meth_len($comp_meth_len);
90*e0c4386eSCy Schubert    $self->comp_meths(\@comp_meths);
91*e0c4386eSCy Schubert    $self->extensions_len($extensions_len);
92*e0c4386eSCy Schubert    $self->extension_data(\%extensions);
93*e0c4386eSCy Schubert
94*e0c4386eSCy Schubert    $self->process_extensions();
95*e0c4386eSCy Schubert
96*e0c4386eSCy Schubert    print "    Client Version:".$client_version."\n";
97*e0c4386eSCy Schubert    print "    Session ID Len:".$session_id_len."\n";
98*e0c4386eSCy Schubert    print "    Ciphersuite len:".$ciphersuite_len."\n";
99*e0c4386eSCy Schubert    print "    Compression Method Len:".$comp_meth_len."\n";
100*e0c4386eSCy Schubert    print "    Extensions Len:".$extensions_len."\n";
101*e0c4386eSCy Schubert}
102*e0c4386eSCy Schubert
103*e0c4386eSCy Schubert#Perform any actions necessary based on the extensions we've seen
104*e0c4386eSCy Schubertsub process_extensions
105*e0c4386eSCy Schubert{
106*e0c4386eSCy Schubert    my $self = shift;
107*e0c4386eSCy Schubert    my %extensions = %{$self->extension_data};
108*e0c4386eSCy Schubert
109*e0c4386eSCy Schubert    #Clear any state from a previous run
110*e0c4386eSCy Schubert    TLSProxy::Record->etm(0);
111*e0c4386eSCy Schubert
112*e0c4386eSCy Schubert    if (exists $extensions{TLSProxy::Message::EXT_ENCRYPT_THEN_MAC}) {
113*e0c4386eSCy Schubert        TLSProxy::Record->etm(1);
114*e0c4386eSCy Schubert    }
115*e0c4386eSCy Schubert}
116*e0c4386eSCy Schubert
117*e0c4386eSCy Schubertsub extension_contents
118*e0c4386eSCy Schubert{
119*e0c4386eSCy Schubert    my $self = shift;
120*e0c4386eSCy Schubert    my $key = shift;
121*e0c4386eSCy Schubert    my $extension = "";
122*e0c4386eSCy Schubert
123*e0c4386eSCy Schubert    my $extdata = ${$self->extension_data}{$key};
124*e0c4386eSCy Schubert    $extension .= pack("n", $key);
125*e0c4386eSCy Schubert    $extension .= pack("n", length($extdata));
126*e0c4386eSCy Schubert    $extension .= $extdata;
127*e0c4386eSCy Schubert    return $extension;
128*e0c4386eSCy Schubert}
129*e0c4386eSCy Schubert
130*e0c4386eSCy Schubert#Reconstruct the on-the-wire message data following changes
131*e0c4386eSCy Schubertsub set_message_contents
132*e0c4386eSCy Schubert{
133*e0c4386eSCy Schubert    my $self = shift;
134*e0c4386eSCy Schubert    my $data;
135*e0c4386eSCy Schubert    my $extensions = "";
136*e0c4386eSCy Schubert
137*e0c4386eSCy Schubert    $data = pack('n', $self->client_version);
138*e0c4386eSCy Schubert    $data .= $self->random;
139*e0c4386eSCy Schubert    $data .= pack('C', $self->session_id_len);
140*e0c4386eSCy Schubert    $data .= $self->session;
141*e0c4386eSCy Schubert    $data .= pack('n', $self->ciphersuite_len);
142*e0c4386eSCy Schubert    $data .= pack("n*", @{$self->ciphersuites});
143*e0c4386eSCy Schubert    $data .= pack('C', $self->comp_meth_len);
144*e0c4386eSCy Schubert    $data .= pack("C*", @{$self->comp_meths});
145*e0c4386eSCy Schubert
146*e0c4386eSCy Schubert    foreach my $key (keys %{$self->extension_data}) {
147*e0c4386eSCy Schubert        next if ($key == TLSProxy::Message::EXT_PSK);
148*e0c4386eSCy Schubert        $extensions .= $self->extension_contents($key);
149*e0c4386eSCy Schubert        #Add extension twice if we are duplicating that extension
150*e0c4386eSCy Schubert        $extensions .= $self->extension_contents($key) if ($key == $self->dupext);
151*e0c4386eSCy Schubert    }
152*e0c4386eSCy Schubert    #PSK extension always goes last...
153*e0c4386eSCy Schubert    if (defined ${$self->extension_data}{TLSProxy::Message::EXT_PSK}) {
154*e0c4386eSCy Schubert        $extensions .= $self->extension_contents(TLSProxy::Message::EXT_PSK);
155*e0c4386eSCy Schubert    }
156*e0c4386eSCy Schubert    #unless we have EXT_FORCE_LAST
157*e0c4386eSCy Schubert    if (defined ${$self->extension_data}{TLSProxy::Message::EXT_FORCE_LAST}) {
158*e0c4386eSCy Schubert        $extensions .= $self->extension_contents(TLSProxy::Message::EXT_FORCE_LAST);
159*e0c4386eSCy Schubert    }
160*e0c4386eSCy Schubert
161*e0c4386eSCy Schubert    $data .= pack('n', length($extensions));
162*e0c4386eSCy Schubert    $data .= $extensions;
163*e0c4386eSCy Schubert
164*e0c4386eSCy Schubert    $self->data($data);
165*e0c4386eSCy Schubert}
166*e0c4386eSCy Schubert
167*e0c4386eSCy Schubert#Read/write accessors
168*e0c4386eSCy Schubertsub client_version
169*e0c4386eSCy Schubert{
170*e0c4386eSCy Schubert    my $self = shift;
171*e0c4386eSCy Schubert    if (@_) {
172*e0c4386eSCy Schubert      $self->{client_version} = shift;
173*e0c4386eSCy Schubert    }
174*e0c4386eSCy Schubert    return $self->{client_version};
175*e0c4386eSCy Schubert}
176*e0c4386eSCy Schubertsub random
177*e0c4386eSCy Schubert{
178*e0c4386eSCy Schubert    my $self = shift;
179*e0c4386eSCy Schubert    if (@_) {
180*e0c4386eSCy Schubert      $self->{random} = shift;
181*e0c4386eSCy Schubert    }
182*e0c4386eSCy Schubert    return $self->{random};
183*e0c4386eSCy Schubert}
184*e0c4386eSCy Schubertsub session_id_len
185*e0c4386eSCy Schubert{
186*e0c4386eSCy Schubert    my $self = shift;
187*e0c4386eSCy Schubert    if (@_) {
188*e0c4386eSCy Schubert      $self->{session_id_len} = shift;
189*e0c4386eSCy Schubert    }
190*e0c4386eSCy Schubert    return $self->{session_id_len};
191*e0c4386eSCy Schubert}
192*e0c4386eSCy Schubertsub session
193*e0c4386eSCy Schubert{
194*e0c4386eSCy Schubert    my $self = shift;
195*e0c4386eSCy Schubert    if (@_) {
196*e0c4386eSCy Schubert      $self->{session} = shift;
197*e0c4386eSCy Schubert    }
198*e0c4386eSCy Schubert    return $self->{session};
199*e0c4386eSCy Schubert}
200*e0c4386eSCy Schubertsub ciphersuite_len
201*e0c4386eSCy Schubert{
202*e0c4386eSCy Schubert    my $self = shift;
203*e0c4386eSCy Schubert    if (@_) {
204*e0c4386eSCy Schubert      $self->{ciphersuite_len} = shift;
205*e0c4386eSCy Schubert    }
206*e0c4386eSCy Schubert    return $self->{ciphersuite_len};
207*e0c4386eSCy Schubert}
208*e0c4386eSCy Schubertsub ciphersuites
209*e0c4386eSCy Schubert{
210*e0c4386eSCy Schubert    my $self = shift;
211*e0c4386eSCy Schubert    if (@_) {
212*e0c4386eSCy Schubert      $self->{ciphersuites} = shift;
213*e0c4386eSCy Schubert    }
214*e0c4386eSCy Schubert    return $self->{ciphersuites};
215*e0c4386eSCy Schubert}
216*e0c4386eSCy Schubertsub comp_meth_len
217*e0c4386eSCy Schubert{
218*e0c4386eSCy Schubert    my $self = shift;
219*e0c4386eSCy Schubert    if (@_) {
220*e0c4386eSCy Schubert      $self->{comp_meth_len} = shift;
221*e0c4386eSCy Schubert    }
222*e0c4386eSCy Schubert    return $self->{comp_meth_len};
223*e0c4386eSCy Schubert}
224*e0c4386eSCy Schubertsub comp_meths
225*e0c4386eSCy Schubert{
226*e0c4386eSCy Schubert    my $self = shift;
227*e0c4386eSCy Schubert    if (@_) {
228*e0c4386eSCy Schubert      $self->{comp_meths} = shift;
229*e0c4386eSCy Schubert    }
230*e0c4386eSCy Schubert    return $self->{comp_meths};
231*e0c4386eSCy Schubert}
232*e0c4386eSCy Schubertsub extensions_len
233*e0c4386eSCy Schubert{
234*e0c4386eSCy Schubert    my $self = shift;
235*e0c4386eSCy Schubert    if (@_) {
236*e0c4386eSCy Schubert      $self->{extensions_len} = shift;
237*e0c4386eSCy Schubert    }
238*e0c4386eSCy Schubert    return $self->{extensions_len};
239*e0c4386eSCy Schubert}
240*e0c4386eSCy Schubertsub extension_data
241*e0c4386eSCy Schubert{
242*e0c4386eSCy Schubert    my $self = shift;
243*e0c4386eSCy Schubert    if (@_) {
244*e0c4386eSCy Schubert      $self->{extension_data} = shift;
245*e0c4386eSCy Schubert    }
246*e0c4386eSCy Schubert    return $self->{extension_data};
247*e0c4386eSCy Schubert}
248*e0c4386eSCy Schubertsub set_extension
249*e0c4386eSCy Schubert{
250*e0c4386eSCy Schubert    my ($self, $ext_type, $ext_data) = @_;
251*e0c4386eSCy Schubert    $self->{extension_data}{$ext_type} = $ext_data;
252*e0c4386eSCy Schubert}
253*e0c4386eSCy Schubertsub delete_extension
254*e0c4386eSCy Schubert{
255*e0c4386eSCy Schubert    my ($self, $ext_type) = @_;
256*e0c4386eSCy Schubert    delete $self->{extension_data}{$ext_type};
257*e0c4386eSCy Schubert}
258*e0c4386eSCy Schubert1;
259