]> git.ipfire.org Git - thirdparty/openssl.git/blame - util/TLSProxy/Message.pm
Use -I to add to @INC, and use -w to produce warnings
[thirdparty/openssl.git] / util / TLSProxy / Message.pm
CommitLineData
631c1206
MC
1# Written by Matt Caswell for the OpenSSL project.
2# ====================================================================
3# Copyright (c) 1998-2015 The OpenSSL Project. All rights reserved.
4#
5# Redistribution and use in source and binary forms, with or without
6# modification, are permitted provided that the following conditions
7# are met:
8#
9# 1. Redistributions of source code must retain the above copyright
10# notice, this list of conditions and the following disclaimer.
11#
12# 2. Redistributions in binary form must reproduce the above copyright
13# notice, this list of conditions and the following disclaimer in
14# the documentation and/or other materials provided with the
15# distribution.
16#
17# 3. All advertising materials mentioning features or use of this
18# software must display the following acknowledgment:
19# "This product includes software developed by the OpenSSL Project
20# for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
21#
22# 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
23# endorse or promote products derived from this software without
24# prior written permission. For written permission, please contact
25# openssl-core@openssl.org.
26#
27# 5. Products derived from this software may not be called "OpenSSL"
28# nor may "OpenSSL" appear in their names without prior written
29# permission of the OpenSSL Project.
30#
31# 6. Redistributions of any form whatsoever must retain the following
32# acknowledgment:
33# "This product includes software developed by the OpenSSL Project
34# for use in the OpenSSL Toolkit (http://www.openssl.org/)"
35#
36# THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
37# EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
38# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
39# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
40# ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
41# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
42# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
43# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
44# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
45# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
46# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
47# OF THE POSSIBILITY OF SUCH DAMAGE.
48# ====================================================================
49#
50# This product includes cryptographic software written by Eric Young
51# (eay@cryptsoft.com). This product includes software written by Tim
52# Hudson (tjh@cryptsoft.com).
53
54use strict;
55
56package TLSProxy::Message;
57
58use constant TLS_MESSAGE_HEADER_LENGTH => 4;
59
60#Message types
61use constant {
62 MT_HELLO_REQUEST => 0,
63 MT_CLIENT_HELLO => 1,
64 MT_SERVER_HELLO => 2,
65 MT_NEW_SESSION_TICKET => 4,
66 MT_CERTIFICATE => 11,
67 MT_SERVER_KEY_EXCHANGE => 12,
68 MT_CERTIFICATE_REQUEST => 13,
69 MT_SERVER_HELLO_DONE => 14,
70 MT_CERTIFICATE_VERIFY => 15,
71 MT_CLIENT_KEY_EXCHANGE => 16,
72 MT_FINISHED => 20,
73 MT_CERTIFICATE_STATUS => 22,
74 MT_NEXT_PROTO => 67
75};
76my %message_type = (
77 MT_HELLO_REQUEST, "HelloRequest",
78 MT_CLIENT_HELLO, "ClientHello",
79 MT_SERVER_HELLO, "ServerHello",
80 MT_NEW_SESSION_TICKET, "NewSessionTicket",
81 MT_CERTIFICATE, "Certificate",
82 MT_SERVER_KEY_EXCHANGE, "ServerKeyExchange",
83 MT_CERTIFICATE_REQUEST, "CertificateRequest",
84 MT_SERVER_HELLO_DONE, "ServerHelloDone",
85 MT_CERTIFICATE_VERIFY, "CertificateVerify",
86 MT_CLIENT_KEY_EXCHANGE, "ClientKeyExchange",
87 MT_FINISHED, "Finished",
88 MT_CERTIFICATE_STATUS, "CertificateStatus",
89 MT_NEXT_PROTO, "NextProto"
90);
91
92my $payload = "";
93my $messlen = -1;
94my $mt;
95my $startoffset = -1;
96my $server = 0;
97my $success = 0;
98my $end = 0;
99my @message_rec_list = ();
100my @message_frag_lens = ();
a1accbb1 101my $ciphersuite = 0;
631c1206
MC
102
103sub clear
104{
105 $payload = "";
106 $messlen = -1;
107 $startoffset = -1;
108 $server = 0;
109 $success = 0;
110 $end = 0;
111 @message_rec_list = ();
112 @message_frag_lens = ();
113}
114
115#Class method to extract messages from a record
116sub get_messages
117{
118 my $class = shift;
119 my $serverin = shift;
120 my $record = shift;
121 my @messages = ();
122 my $message;
123
a1accbb1
MC
124 @message_frag_lens = ();
125
631c1206
MC
126 if ($serverin != $server && length($payload) != 0) {
127 die "Changed peer, but we still have fragment data\n";
128 }
129 $server = $serverin;
130
131 if ($record->content_type == TLSProxy::Record::RT_CCS) {
132 if ($payload ne "") {
133 #We can't handle this yet
134 die "CCS received before message data complete\n";
135 }
136 if ($server) {
137 TLSProxy::Record->server_ccs_seen(1);
138 } else {
139 TLSProxy::Record->client_ccs_seen(1);
140 }
141 } elsif ($record->content_type == TLSProxy::Record::RT_HANDSHAKE) {
142 if ($record->len == 0 || $record->len_real == 0) {
143 print " Message truncated\n";
144 } else {
145 my $recoffset = 0;
146
147 if (length $payload > 0) {
148 #We are continuing processing a message started in a previous
149 #record. Add this record to the list associated with this
150 #message
151 push @message_rec_list, $record;
152
153 if ($messlen <= length($payload)) {
154 #Shouldn't happen
155 die "Internal error: invalid messlen: ".$messlen
156 ." payload length:".length($payload)."\n";
157 }
158 if (length($payload) + $record->decrypt_len >= $messlen) {
159 #We can complete the message with this record
160 $recoffset = $messlen - length($payload);
161 $payload .= substr($record->decrypt_data, 0, $recoffset);
162 push @message_frag_lens, $recoffset;
163 $message = create_message($server, $mt, $payload,
164 $startoffset);
165 push @messages, $message;
166
167 #Check if we have finished the handshake
168 if ($mt == MT_FINISHED && $server) {
169 $success = 1;
170 $end = 1;
171 }
172 $payload = "";
173 } else {
174 #This is just part of the total message
175 $payload .= $record->decrypt_data;
176 $recoffset = $record->decrypt_len;
177 push @message_frag_lens, $record->decrypt_len;
178 }
179 print " Partial message data read: ".$recoffset." bytes\n";
180 }
181
182 while ($record->decrypt_len > $recoffset) {
183 #We are at the start of a new message
184 if ($record->decrypt_len - $recoffset < 4) {
185 #Whilst technically probably valid we can't cope with this
186 die "End of record in the middle of a message header\n";
187 }
188 @message_rec_list = ($record);
189 my $lenhi;
190 my $lenlo;
191 ($mt, $lenhi, $lenlo) = unpack('CnC',
192 substr($record->decrypt_data,
193 $recoffset));
194 $messlen = ($lenhi << 8) | $lenlo;
195 print " Message type: $message_type{$mt}\n";
196 print " Message Length: $messlen\n";
197 $startoffset = $recoffset;
198 $recoffset += 4;
199 $payload = "";
200
201 if ($recoffset < $record->decrypt_len) {
202 #Some payload data is present in this record
203 if ($record->decrypt_len - $recoffset >= $messlen) {
204 #We can complete the message with this record
205 $payload .= substr($record->decrypt_data, $recoffset,
206 $messlen);
207 $recoffset += $messlen;
208 push @message_frag_lens, $messlen;
209 $message = create_message($server, $mt, $payload,
210 $startoffset);
211 push @messages, $message;
212
213 #Check if we have finished the handshake
214 if ($mt == MT_FINISHED && $server) {
215 $success = 1;
216 $end = 1;
217 }
218 $payload = "";
219 } else {
220 #This is just part of the total message
221 $payload .= substr($record->decrypt_data, $recoffset,
222 $record->decrypt_len - $recoffset);
223 $recoffset = $record->decrypt_len;
224 push @message_frag_lens, $recoffset;
225 }
226 }
227 }
228 }
229 } elsif ($record->content_type == TLSProxy::Record::RT_APPLICATION_DATA) {
230 print " [ENCRYPTED APPLICATION DATA]\n";
231 print " [".$record->decrypt_data."]\n";
232 } elsif ($record->content_type == TLSProxy::Record::RT_ALERT) {
233 #For now assume all alerts are fatal
234 $end = 1;
235 }
236
237 return @messages;
238}
239
240#Function to work out which sub-class we need to create and then
241#construct it
242sub create_message
243{
244 my ($server, $mt, $data, $startoffset) = @_;
245 my $message;
246
247 #We only support ClientHello in this version...needs to be extended for
248 #others
249 if ($mt == MT_CLIENT_HELLO) {
250 $message = TLSProxy::ClientHello->new(
251 $server,
252 $data,
253 [@message_rec_list],
254 $startoffset,
255 [@message_frag_lens]
256 );
257 $message->parse();
a1accbb1
MC
258 } elsif ($mt == MT_SERVER_HELLO) {
259 $message = TLSProxy::ServerHello->new(
260 $server,
261 $data,
262 [@message_rec_list],
263 $startoffset,
264 [@message_frag_lens]
265 );
266 $message->parse();
267 } elsif ($mt == MT_SERVER_KEY_EXCHANGE) {
268 $message = TLSProxy::ServerKeyExchange->new(
269 $server,
270 $data,
271 [@message_rec_list],
272 $startoffset,
273 [@message_frag_lens]
274 );
275 $message->parse();
631c1206
MC
276 } else {
277 #Unknown message type
278 $message = TLSProxy::Message->new(
279 $server,
280 $mt,
281 $data,
282 [@message_rec_list],
283 $startoffset,
284 [@message_frag_lens]
285 );
286 }
287
288 return $message;
289}
290
291sub end
292{
293 my $class = shift;
294 return $end;
295}
296sub success
297{
298 my $class = shift;
299 return $success;
300}
a1accbb1
MC
301sub fail
302{
303 my $class = shift;
304 return !$success && $end;
305}
631c1206
MC
306sub new
307{
308 my $class = shift;
309 my ($server,
310 $mt,
311 $data,
312 $records,
313 $startoffset,
314 $message_frag_lens) = @_;
315
316 my $self = {
317 server => $server,
318 data => $data,
319 records => $records,
320 mt => $mt,
321 startoffset => $startoffset,
322 message_frag_lens => $message_frag_lens
323 };
324
325 return bless $self, $class;
326}
327
a1accbb1
MC
328sub ciphersuite
329{
330 my $class = shift;
331 if (@_) {
332 $ciphersuite = shift;
333 }
334 return $ciphersuite;
335}
336
631c1206
MC
337#Update all the underlying records with the modified data from this message
338#Note: Does not currently support re-encrypting
339sub repack
340{
341 my $self = shift;
342 my $msgdata;
343
344 my $numrecs = $#{$self->records};
345
346 $self->set_message_contents();
347
348 my $lenhi;
349 my $lenlo;
350
351 $lenlo = length($self->data) & 0xff;
352 $lenhi = length($self->data) >> 8;
353 my $msgdata = pack('CnC', $self->mt, $lenhi, $lenlo).$self->data;
354
355
356 if ($numrecs == 0) {
357 #The message is fully contained within one record
358 my ($rec) = @{$self->records};
359 my $recdata = $rec->decrypt_data;
360
361 if (length($msgdata) != ${$self->message_frag_lens}[0]
362 + TLS_MESSAGE_HEADER_LENGTH) {
363 #Message length has changed! Better adjust the record length
364 my $diff = length($msgdata) - ${$self->message_frag_lens}[0]
365 - TLS_MESSAGE_HEADER_LENGTH;
366 $rec->len($rec->len + $diff);
367 }
368
369 $rec->data(substr($recdata, 0, $self->startoffset)
370 .($msgdata)
371 .substr($recdata, ${$self->message_frag_lens}[0]
372 + TLS_MESSAGE_HEADER_LENGTH));
373
374 #Update the fragment len in case we changed it above
375 ${$self->message_frag_lens}[0] = length($msgdata)
376 - TLS_MESSAGE_HEADER_LENGTH;
377 return;
378 }
379
380 #Note we don't currently support changing a fragmented message length
381 my $recctr = 0;
382 my $datadone = 0;
383 foreach my $rec (@{$self->records}) {
384 my $recdata = $rec->decrypt_data;
385 if ($recctr == 0) {
386 #This is the first record
387 my $remainlen = length($recdata) - $self->startoffset;
388 $rec->data(substr($recdata, 0, $self->startoffset)
389 .substr(($msgdata), 0, $remainlen));
390 $datadone += $remainlen;
391 } elsif ($recctr + 1 == $numrecs) {
392 #This is the last record
393 $rec->data(substr($msgdata, $datadone));
394 } else {
395 #This is a middle record
396 $rec->data(substr($msgdata, $datadone, length($rec->data)));
397 $datadone += length($rec->data);
398 }
399 $recctr++;
400 }
401}
402
403#To be overridden by sub-classes
404sub set_message_contents
405{
406}
407
408#Read only accessors
409sub server
410{
411 my $self = shift;
412 return $self->{server};
413}
414
415#Read/write accessors
416sub mt
417{
418 my $self = shift;
419 if (@_) {
420 $self->{mt} = shift;
421 }
422 return $self->{mt};
423}
424sub data
425{
426 my $self = shift;
427 if (@_) {
428 $self->{data} = shift;
429 }
430 return $self->{data};
431}
432sub records
433{
434 my $self = shift;
435 if (@_) {
436 $self->{records} = shift;
437 }
438 return $self->{records};
439}
440sub startoffset
441{
442 my $self = shift;
443 if (@_) {
444 $self->{startoffset} = shift;
445 }
446 return $self->{startoffset};
447}
448sub message_frag_lens
449{
450 my $self = shift;
451 if (@_) {
452 $self->{message_frag_lens} = shift;
453 }
454 return $self->{message_frag_lens};
455}
456
4571;