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::Certificate;
     11 
     12 use vars '@ISA';
     13 push @ISA, 'TLSProxy::Message';
     14 
     15 sub new
     16 {
     17     my $class = shift;
     18     my ($server,
     19         $data,
     20         $records,
     21         $startoffset,
     22         $message_frag_lens) = @_;
     23 
     24     my $self = $class->SUPER::new(
     25         $server,
     26         TLSProxy::Message::MT_CERTIFICATE,
     27         $data,
     28         $records,
     29         $startoffset,
     30         $message_frag_lens);
     31 
     32     $self->{first_certificate} = "";
     33     $self->{extension_data} = "";
     34     $self->{remaining_certdata} = "";
     35 
     36     return $self;
     37 }
     38 
     39 sub parse
     40 {
     41     my $self = shift;
     42 
     43     if (TLSProxy::Proxy->is_tls13()) {
     44         my $context_len = unpack('C', $self->data);
     45         my $context = substr($self->data, 1, $context_len);
     46 
     47         my $remdata = substr($self->data, 1 + $context_len);
     48 
     49         my ($hicertlistlen, $certlistlen) = unpack('Cn', $remdata);
     50         $certlistlen += ($hicertlistlen << 16);
     51 
     52         $remdata = substr($remdata, 3);
     53 
     54         die "Invalid Certificate List length"
     55             if length($remdata) != $certlistlen;
     56 
     57         my ($hicertlen, $certlen) = unpack('Cn', $remdata);
     58         $certlen += ($hicertlen << 16);
     59 
     60         die "Certificate too long" if ($certlen + 3) > $certlistlen;
     61 
     62         $remdata = substr($remdata, 3);
     63 
     64         my $certdata = substr($remdata, 0, $certlen);
     65 
     66         $remdata = substr($remdata, $certlen);
     67 
     68         my $extensions_len = unpack('n', $remdata);
     69         $remdata = substr($remdata, 2);
     70 
     71         die "Extensions too long"
     72             if ($certlen + 3 + $extensions_len + 2) > $certlistlen;
     73 
     74         my $extension_data = "";
     75         if ($extensions_len != 0) {
     76             $extension_data = substr($remdata, 0, $extensions_len);
     77 
     78             if (length($extension_data) != $extensions_len) {
     79                 die "Invalid extension length\n";
     80             }
     81         }
     82         my %extensions = ();
     83         while (length($extension_data) >= 4) {
     84             my ($type, $size) = unpack("nn", $extension_data);
     85             my $extdata = substr($extension_data, 4, $size);
     86             $extension_data = substr($extension_data, 4 + $size);
     87             $extensions{$type} = $extdata;
     88         }
     89         $remdata = substr($remdata, $extensions_len);
     90 
     91         $self->context($context);
     92         $self->first_certificate($certdata);
     93         $self->extension_data(\%extensions);
     94         $self->remaining_certdata($remdata);
     95 
     96         print "    Context:".$context."\n";
     97         print "    Certificate List Len:".$certlistlen."\n";
     98         print "    Certificate Len:".$certlen."\n";
     99         print "    Extensions Len:".$extensions_len."\n";
    100     } else {
    101         my ($hicertlistlen, $certlistlen) = unpack('Cn', $self->data);
    102         $certlistlen += ($hicertlistlen << 16);
    103 
    104         my $remdata = substr($self->data, 3);
    105 
    106         die "Invalid Certificate List length"
    107             if length($remdata) != $certlistlen;
    108 
    109         my ($hicertlen, $certlen) = unpack('Cn', $remdata);
    110         $certlen += ($hicertlen << 16);
    111 
    112         die "Certificate too long" if ($certlen + 3) > $certlistlen;
    113 
    114         $remdata = substr($remdata, 3);
    115 
    116         my $certdata = substr($remdata, 0, $certlen);
    117 
    118         $remdata = substr($remdata, $certlen);
    119 
    120         $self->first_certificate($certdata);
    121         $self->remaining_certdata($remdata);
    122 
    123         print "    Certificate List Len:".$certlistlen."\n";
    124         print "    Certificate Len:".$certlen."\n";
    125     }
    126 }
    127 
    128 #Reconstruct the on-the-wire message data following changes
    129 sub set_message_contents
    130 {
    131     my $self = shift;
    132     my $data;
    133     my $extensions = "";
    134 
    135     if (TLSProxy::Proxy->is_tls13()) {
    136         foreach my $key (keys %{$self->extension_data}) {
    137             my $extdata = ${$self->extension_data}{$key};
    138             $extensions .= pack("n", $key);
    139             $extensions .= pack("n", length($extdata));
    140             $extensions .= $extdata;
    141         }
    142         $data = pack('C', length($self->context()));
    143         $data .= $self->context;
    144         my $certlen = length($self->first_certificate);
    145         my $certlistlen = $certlen + length($extensions)
    146                           + length($self->remaining_certdata);
    147         my $hi = $certlistlen >> 16;
    148         $certlistlen = $certlistlen & 0xffff;
    149         $data .= pack('Cn', $hi, $certlistlen);
    150         $hi = $certlen >> 16;
    151         $certlen = $certlen & 0xffff;
    152         $data .= pack('Cn', $hi, $certlen);
    153         $data .= pack('n', length($extensions));
    154         $data .= $extensions;
    155         $data .= $self->remaining_certdata();
    156         $self->data($data);
    157     } else {
    158         my $certlen = length($self->first_certificate);
    159         my $certlistlen = $certlen + length($self->remaining_certdata);
    160         my $hi = $certlistlen >> 16;
    161         $certlistlen = $certlistlen & 0xffff;
    162         $data .= pack('Cn', $hi, $certlistlen);
    163         $hi = $certlen >> 16;
    164         $certlen = $certlen & 0xffff;
    165         $data .= pack('Cn', $hi, $certlen);
    166         $data .= $self->remaining_certdata();
    167         $self->data($data);
    168     }
    169 }
    170 
    171 #Read/write accessors
    172 sub context
    173 {
    174     my $self = shift;
    175     if (@_) {
    176       $self->{context} = shift;
    177     }
    178     return $self->{context};
    179 }
    180 sub first_certificate
    181 {
    182     my $self = shift;
    183     if (@_) {
    184       $self->{first_certificate} = shift;
    185     }
    186     return $self->{first_certificate};
    187 }
    188 sub remaining_certdata
    189 {
    190     my $self = shift;
    191     if (@_) {
    192       $self->{remaining_certdata} = shift;
    193     }
    194     return $self->{remaining_certdata};
    195 }
    196 sub extension_data
    197 {
    198     my $self = shift;
    199     if (@_) {
    200       $self->{extension_data} = shift;
    201     }
    202     return $self->{extension_data};
    203 }
    204 sub set_extension
    205 {
    206     my ($self, $ext_type, $ext_data) = @_;
    207     $self->{extension_data}{$ext_type} = $ext_data;
    208 }
    209 sub delete_extension
    210 {
    211     my ($self, $ext_type) = @_;
    212     delete $self->{extension_data}{$ext_type};
    213 }
    214 1;
    215