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 8use strict; 9 10package TLSProxy::Certificate; 11 12use vars '@ISA'; 13push @ISA, 'TLSProxy::Message'; 14 15sub 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 39sub 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 129sub 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 172sub context 173{ 174 my $self = shift; 175 if (@_) { 176 $self->{context} = shift; 177 } 178 return $self->{context}; 179} 180sub first_certificate 181{ 182 my $self = shift; 183 if (@_) { 184 $self->{first_certificate} = shift; 185 } 186 return $self->{first_certificate}; 187} 188sub remaining_certdata 189{ 190 my $self = shift; 191 if (@_) { 192 $self->{remaining_certdata} = shift; 193 } 194 return $self->{remaining_certdata}; 195} 196sub extension_data 197{ 198 my $self = shift; 199 if (@_) { 200 $self->{extension_data} = shift; 201 } 202 return $self->{extension_data}; 203} 204sub set_extension 205{ 206 my ($self, $ext_type, $ext_data) = @_; 207 $self->{extension_data}{$ext_type} = $ext_data; 208} 209sub delete_extension 210{ 211 my ($self, $ext_type) = @_; 212 delete $self->{extension_data}{$ext_type}; 213} 2141; 215