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