xref: /netbsd-src/crypto/external/bsd/openssl/dist/util/perl/TLSProxy/ClientHello.pm (revision b0d1725196a7921d003d2c66a14f186abda4176b)
1*b0d17251Schristos# Copyright 2016 The OpenSSL Project Authors. All Rights Reserved.
253060421Schristos#
3*b0d17251Schristos# Licensed under the Apache License 2.0 (the "License").  You may not use
453060421Schristos# this file except in compliance with the License.  You can obtain a copy
553060421Schristos# in the file LICENSE in the source distribution or at
653060421Schristos# https://www.openssl.org/source/license.html
753060421Schristos
853060421Schristosuse strict;
953060421Schristos
1053060421Schristospackage TLSProxy::ClientHello;
1153060421Schristos
1253060421Schristosuse vars '@ISA';
1353060421Schristospush @ISA, 'TLSProxy::Message';
1453060421Schristos
1553060421Schristossub new
1653060421Schristos{
1753060421Schristos    my $class = shift;
1853060421Schristos    my ($server,
1953060421Schristos        $data,
2053060421Schristos        $records,
2153060421Schristos        $startoffset,
2253060421Schristos        $message_frag_lens) = @_;
2353060421Schristos
2453060421Schristos    my $self = $class->SUPER::new(
2553060421Schristos        $server,
2653060421Schristos        1,
2753060421Schristos        $data,
2853060421Schristos        $records,
2953060421Schristos        $startoffset,
3053060421Schristos        $message_frag_lens);
3153060421Schristos
3253060421Schristos    $self->{client_version} = 0;
3353060421Schristos    $self->{random} = [];
3453060421Schristos    $self->{session_id_len} = 0;
3553060421Schristos    $self->{session} = "";
3653060421Schristos    $self->{ciphersuite_len} = 0;
3753060421Schristos    $self->{ciphersuites} = [];
3853060421Schristos    $self->{comp_meth_len} = 0;
3953060421Schristos    $self->{comp_meths} = [];
4053060421Schristos    $self->{extensions_len} = 0;
4153060421Schristos    $self->{extension_data} = "";
4253060421Schristos
4353060421Schristos    return $self;
4453060421Schristos}
4553060421Schristos
4653060421Schristossub parse
4753060421Schristos{
4853060421Schristos    my $self = shift;
4953060421Schristos    my $ptr = 2;
5053060421Schristos    my ($client_version) = unpack('n', $self->data);
5153060421Schristos    my $random = substr($self->data, $ptr, 32);
5253060421Schristos    $ptr += 32;
5353060421Schristos    my $session_id_len = unpack('C', substr($self->data, $ptr));
5453060421Schristos    $ptr++;
5553060421Schristos    my $session = substr($self->data, $ptr, $session_id_len);
5653060421Schristos    $ptr += $session_id_len;
5753060421Schristos    my $ciphersuite_len = unpack('n', substr($self->data, $ptr));
5853060421Schristos    $ptr += 2;
5953060421Schristos    my @ciphersuites = unpack('n*', substr($self->data, $ptr,
6053060421Schristos                                           $ciphersuite_len));
6153060421Schristos    $ptr += $ciphersuite_len;
6253060421Schristos    my $comp_meth_len = unpack('C', substr($self->data, $ptr));
6353060421Schristos    $ptr++;
6453060421Schristos    my @comp_meths = unpack('C*', substr($self->data, $ptr, $comp_meth_len));
6553060421Schristos    $ptr += $comp_meth_len;
6653060421Schristos    my $extensions_len = unpack('n', substr($self->data, $ptr));
6753060421Schristos    $ptr += 2;
6853060421Schristos    #For now we just deal with this as a block of data. In the future we will
6953060421Schristos    #want to parse this
7053060421Schristos    my $extension_data = substr($self->data, $ptr);
7153060421Schristos
7253060421Schristos    if (length($extension_data) != $extensions_len) {
7353060421Schristos        die "Invalid extension length\n";
7453060421Schristos    }
7553060421Schristos    my %extensions = ();
7653060421Schristos    while (length($extension_data) >= 4) {
7753060421Schristos        my ($type, $size) = unpack("nn", $extension_data);
7853060421Schristos        my $extdata = substr($extension_data, 4, $size);
7953060421Schristos        $extension_data = substr($extension_data, 4 + $size);
8053060421Schristos        $extensions{$type} = $extdata;
8153060421Schristos    }
8253060421Schristos
8353060421Schristos    $self->client_version($client_version);
8453060421Schristos    $self->random($random);
8553060421Schristos    $self->session_id_len($session_id_len);
8653060421Schristos    $self->session($session);
8753060421Schristos    $self->ciphersuite_len($ciphersuite_len);
8853060421Schristos    $self->ciphersuites(\@ciphersuites);
8953060421Schristos    $self->comp_meth_len($comp_meth_len);
9053060421Schristos    $self->comp_meths(\@comp_meths);
9153060421Schristos    $self->extensions_len($extensions_len);
9253060421Schristos    $self->extension_data(\%extensions);
9353060421Schristos
9453060421Schristos    $self->process_extensions();
9553060421Schristos
9653060421Schristos    print "    Client Version:".$client_version."\n";
9753060421Schristos    print "    Session ID Len:".$session_id_len."\n";
9853060421Schristos    print "    Ciphersuite len:".$ciphersuite_len."\n";
9953060421Schristos    print "    Compression Method Len:".$comp_meth_len."\n";
10053060421Schristos    print "    Extensions Len:".$extensions_len."\n";
10153060421Schristos}
10253060421Schristos
10353060421Schristos#Perform any actions necessary based on the extensions we've seen
10453060421Schristossub process_extensions
10553060421Schristos{
10653060421Schristos    my $self = shift;
10753060421Schristos    my %extensions = %{$self->extension_data};
10853060421Schristos
10953060421Schristos    #Clear any state from a previous run
11053060421Schristos    TLSProxy::Record->etm(0);
11153060421Schristos
11253060421Schristos    if (exists $extensions{TLSProxy::Message::EXT_ENCRYPT_THEN_MAC}) {
11353060421Schristos        TLSProxy::Record->etm(1);
11453060421Schristos    }
11553060421Schristos}
11653060421Schristos
11713d40330Schristossub extension_contents
11813d40330Schristos{
11913d40330Schristos    my $self = shift;
12013d40330Schristos    my $key = shift;
12113d40330Schristos    my $extension = "";
12213d40330Schristos
12313d40330Schristos    my $extdata = ${$self->extension_data}{$key};
12413d40330Schristos    $extension .= pack("n", $key);
12513d40330Schristos    $extension .= pack("n", length($extdata));
12613d40330Schristos    $extension .= $extdata;
12713d40330Schristos    return $extension;
12813d40330Schristos}
12913d40330Schristos
13053060421Schristos#Reconstruct the on-the-wire message data following changes
13153060421Schristossub set_message_contents
13253060421Schristos{
13353060421Schristos    my $self = shift;
13453060421Schristos    my $data;
13553060421Schristos    my $extensions = "";
13653060421Schristos
13753060421Schristos    $data = pack('n', $self->client_version);
13853060421Schristos    $data .= $self->random;
13953060421Schristos    $data .= pack('C', $self->session_id_len);
14053060421Schristos    $data .= $self->session;
14153060421Schristos    $data .= pack('n', $self->ciphersuite_len);
14253060421Schristos    $data .= pack("n*", @{$self->ciphersuites});
14353060421Schristos    $data .= pack('C', $self->comp_meth_len);
14453060421Schristos    $data .= pack("C*", @{$self->comp_meths});
14553060421Schristos
14653060421Schristos    foreach my $key (keys %{$self->extension_data}) {
14713d40330Schristos        next if ($key == TLSProxy::Message::EXT_PSK);
14813d40330Schristos        $extensions .= $self->extension_contents($key);
149b88c74d5Schristos        #Add extension twice if we are duplicating that extension
150b88c74d5Schristos        $extensions .= $self->extension_contents($key) if ($key == $self->dupext);
15153060421Schristos    }
15213d40330Schristos    #PSK extension always goes last...
15313d40330Schristos    if (defined ${$self->extension_data}{TLSProxy::Message::EXT_PSK}) {
15413d40330Schristos        $extensions .= $self->extension_contents(TLSProxy::Message::EXT_PSK);
15513d40330Schristos    }
15613d40330Schristos    #unless we have EXT_FORCE_LAST
15713d40330Schristos    if (defined ${$self->extension_data}{TLSProxy::Message::EXT_FORCE_LAST}) {
15813d40330Schristos        $extensions .= $self->extension_contents(TLSProxy::Message::EXT_FORCE_LAST);
15953060421Schristos    }
16053060421Schristos
16153060421Schristos    $data .= pack('n', length($extensions));
16253060421Schristos    $data .= $extensions;
16353060421Schristos
16453060421Schristos    $self->data($data);
16553060421Schristos}
16653060421Schristos
16753060421Schristos#Read/write accessors
16853060421Schristossub client_version
16953060421Schristos{
17053060421Schristos    my $self = shift;
17153060421Schristos    if (@_) {
17253060421Schristos      $self->{client_version} = shift;
17353060421Schristos    }
17453060421Schristos    return $self->{client_version};
17553060421Schristos}
17653060421Schristossub random
17753060421Schristos{
17853060421Schristos    my $self = shift;
17953060421Schristos    if (@_) {
18053060421Schristos      $self->{random} = shift;
18153060421Schristos    }
18253060421Schristos    return $self->{random};
18353060421Schristos}
18453060421Schristossub session_id_len
18553060421Schristos{
18653060421Schristos    my $self = shift;
18753060421Schristos    if (@_) {
18853060421Schristos      $self->{session_id_len} = shift;
18953060421Schristos    }
19053060421Schristos    return $self->{session_id_len};
19153060421Schristos}
19253060421Schristossub session
19353060421Schristos{
19453060421Schristos    my $self = shift;
19553060421Schristos    if (@_) {
19653060421Schristos      $self->{session} = shift;
19753060421Schristos    }
19853060421Schristos    return $self->{session};
19953060421Schristos}
20053060421Schristossub ciphersuite_len
20153060421Schristos{
20253060421Schristos    my $self = shift;
20353060421Schristos    if (@_) {
20453060421Schristos      $self->{ciphersuite_len} = shift;
20553060421Schristos    }
20653060421Schristos    return $self->{ciphersuite_len};
20753060421Schristos}
20853060421Schristossub ciphersuites
20953060421Schristos{
21053060421Schristos    my $self = shift;
21153060421Schristos    if (@_) {
21253060421Schristos      $self->{ciphersuites} = shift;
21353060421Schristos    }
21453060421Schristos    return $self->{ciphersuites};
21553060421Schristos}
21653060421Schristossub comp_meth_len
21753060421Schristos{
21853060421Schristos    my $self = shift;
21953060421Schristos    if (@_) {
22053060421Schristos      $self->{comp_meth_len} = shift;
22153060421Schristos    }
22253060421Schristos    return $self->{comp_meth_len};
22353060421Schristos}
22453060421Schristossub comp_meths
22553060421Schristos{
22653060421Schristos    my $self = shift;
22753060421Schristos    if (@_) {
22853060421Schristos      $self->{comp_meths} = shift;
22953060421Schristos    }
23053060421Schristos    return $self->{comp_meths};
23153060421Schristos}
23253060421Schristossub extensions_len
23353060421Schristos{
23453060421Schristos    my $self = shift;
23553060421Schristos    if (@_) {
23653060421Schristos      $self->{extensions_len} = shift;
23753060421Schristos    }
23853060421Schristos    return $self->{extensions_len};
23953060421Schristos}
24053060421Schristossub extension_data
24153060421Schristos{
24253060421Schristos    my $self = shift;
24353060421Schristos    if (@_) {
24453060421Schristos      $self->{extension_data} = shift;
24553060421Schristos    }
24653060421Schristos    return $self->{extension_data};
24753060421Schristos}
24853060421Schristossub set_extension
24953060421Schristos{
25053060421Schristos    my ($self, $ext_type, $ext_data) = @_;
25153060421Schristos    $self->{extension_data}{$ext_type} = $ext_data;
25253060421Schristos}
25353060421Schristossub delete_extension
25453060421Schristos{
25553060421Schristos    my ($self, $ext_type) = @_;
25653060421Schristos    delete $self->{extension_data}{$ext_type};
25753060421Schristos}
25853060421Schristos1;
259