1 # Copyright 2016-2018 The OpenSSL Project Authors. All Rights Reserved.
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
12 package TLSProxy::Record;
14 my $server_encrypting = 0;
15 my $client_encrypting = 0;
18 use constant TLS_RECORD_HEADER_LENGTH => 5;
22 RT_APPLICATION_DATA => 23,
30 RT_APPLICATION_DATA, "APPLICATION DATA",
31 RT_HANDSHAKE, "HANDSHAKE",
38 VERS_TLS_1_4 => 0x0305,
39 VERS_TLS_1_3_DRAFT => 0x7f1a,
40 VERS_TLS_1_3 => 0x0304,
41 VERS_TLS_1_2 => 0x0303,
42 VERS_TLS_1_1 => 0x0302,
43 VERS_TLS_1_0 => 0x0301,
44 VERS_SSL_3_0 => 0x0300,
45 VERS_SSL_LT_3_0 => 0x02ff
49 VERS_TLS_1_3, "TLS1.3",
50 VERS_TLS_1_2, "TLS1.2",
51 VERS_TLS_1_1, "TLS1.1",
52 VERS_TLS_1_0, "TLS1.0",
54 VERS_SSL_LT_3_0, "SSL<3"
57 #Class method to extract records from a packet of data
66 my @message_list = ();
75 while (length ($packet) > 0) {
76 print " Record $recnum";
78 print " (server -> client)\n";
80 print " (client -> server)\n";
82 #Get the record header
83 if (length($packet) < TLS_RECORD_HEADER_LENGTH
84 || length($packet) < 5 + unpack("n", substr($packet, 3, 2))) {
85 print "Partial data : ".length($packet)." bytes\n";
89 ($content_type, $version, $len) = unpack('CnnC*', $packet);
90 $data = substr($packet, 5, $len);
92 print " Content type: ".$record_type{$content_type}."\n";
93 print " Version: $tls_version{$version}\n";
94 print " Length: $len";
95 if ($len == length($data)) {
97 $decrypt_len = $len_real = $len;
99 print " (expected), ".length($data)." (actual)\n";
100 $decrypt_len = $len_real = length($data);
103 my $record = TLSProxy::Record->new(
111 substr($packet, TLS_RECORD_HEADER_LENGTH, $len_real),
112 substr($packet, TLS_RECORD_HEADER_LENGTH, $len_real)
115 if ($content_type != RT_CCS) {
116 if (($server && $server_encrypting)
117 || (!$server && $client_encrypting)) {
118 if (!TLSProxy::Proxy->is_tls13() && $etm) {
119 $record->decryptETM();
123 $record->encrypted(1);
125 if (TLSProxy::Proxy->is_tls13()) {
126 print " Inner content type: "
127 .$record_type{$record->content_type()}."\n";
132 push @record_list, $record;
134 #Now figure out what messages are contained within this record
135 my @messages = TLSProxy::Message->get_messages($server, $record);
136 push @message_list, @messages;
138 $packet = substr($packet, TLS_RECORD_HEADER_LENGTH + $len_real);
143 return (\@record_list, \@message_list, $partial);
148 $server_encrypting = 0;
149 $client_encrypting = 0;
152 #Class level accessors
153 sub server_encrypting
157 $server_encrypting = shift;
159 return $server_encrypting;
161 sub client_encrypting
165 $client_encrypting= shift;
167 return $client_encrypting;
169 #Enable/Disable Encrypt-then-MAC
194 content_type => $content_type,
198 len_real => $len_real,
199 decrypt_len => $decrypt_len,
201 decrypt_data => $decrypt_data,
202 orig_decrypt_data => $decrypt_data,
205 outer_content_type => RT_APPLICATION_DATA
208 return bless $self, $class;
211 #Decrypt using encrypt-then-MAC
216 my $data = $self->data;
218 if($self->version >= VERS_TLS_1_1()) {
219 #TLS1.1+ has an explicit IV. Throw it away
220 $data = substr($data, 16);
223 #Throw away the MAC (assumes MAC is 20 bytes for now. FIXME)
224 $data = substr($data, 0, length($data) - 20);
226 #Find out what the padding byte is
227 my $padval = unpack("C", substr($data, length($data) - 1));
229 #Throw away the padding
230 $data = substr($data, 0, length($data) - ($padval + 1));
232 $self->decrypt_data($data);
233 $self->decrypt_len(length($data));
243 my $data = $self->data;
246 if (TLSProxy::Proxy->is_tls13()) {
247 #A TLS1.3 client, when processing the server's initial flight, could
248 #respond with either an encrypted or an unencrypted alert.
249 if ($self->content_type() == RT_ALERT) {
250 #TODO(TLS1.3): Eventually it is sufficient just to check the record
251 #content type. If an alert is encrypted it will have a record
252 #content type of application data. However we haven't done the
253 #record layer changes yet, so it's a bit more complicated. For now
254 #we will additionally check if the data length is 2 (1 byte for
255 #alert level, 1 byte for alert description). If it is, then this is
256 #an unencrypted alert, so don't try to decrypt
257 return $data if (length($data) == 2);
260 } elsif ($self->version >= VERS_TLS_1_1()) {
261 #16 bytes for a standard IV
262 $data = substr($data, 16);
264 #Find out what the padding byte is
265 my $padval = unpack("C", substr($data, length($data) - 1));
267 #Throw away the padding
268 $data = substr($data, 0, length($data) - ($padval + 1));
271 #Throw away the MAC or TAG
272 $data = substr($data, 0, length($data) - $mactaglen);
274 if (TLSProxy::Proxy->is_tls13()) {
275 #Get the content type
276 my $content_type = unpack("C", substr($data, length($data) - 1));
277 $self->content_type($content_type);
278 $data = substr($data, 0, length($data) - 1);
281 $self->decrypt_data($data);
282 $self->decrypt_len(length($data));
287 #Reconstruct the on-the-wire record representation
288 sub reconstruct_record
300 $data = pack('n', $self->len | 0x8000);
302 if (TLSProxy::Proxy->is_tls13() && $self->encrypted) {
303 $data = pack('Cnn', $self->outer_content_type, $self->version,
306 $data = pack('Cnn', $self->content_type, $self->version,
311 $data .= $self->data;
320 return $self->{flight};
325 return $self->{sslv2};
330 return $self->{len_real};
332 sub orig_decrypt_data
335 return $self->{orig_decrypt_data};
338 #Read/write accessors
343 $self->{decrypt_len} = shift;
345 return $self->{decrypt_len};
351 $self->{data} = shift;
353 return $self->{data};
359 $self->{decrypt_data} = shift;
361 return $self->{decrypt_data};
367 $self->{len} = shift;
375 $self->{version} = shift;
377 return $self->{version};
383 $self->{content_type} = shift;
385 return $self->{content_type};
391 $self->{encrypted} = shift;
393 return $self->{encrypted};
395 sub outer_content_type
399 $self->{outer_content_type} = shift;
401 return $self->{outer_content_type};