1 # Written by Matt Caswell for the OpenSSL project.
2 # ====================================================================
3 # Copyright (c) 1998-2015 The OpenSSL Project. All rights reserved.
5 # Redistribution and use in source and binary forms, with or without
6 # modification, are permitted provided that the following conditions
9 # 1. Redistributions of source code must retain the above copyright
10 # notice, this list of conditions and the following disclaimer.
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
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/)"
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.
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.
31 # 6. Redistributions of any form whatsoever must retain the following
33 # "This product includes software developed by the OpenSSL Project
34 # for use in the OpenSSL Toolkit (http://www.openssl.org/)"
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 # ====================================================================
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).
56 package TLSProxy::Message;
58 use constant TLS_MESSAGE_HEADER_LENGTH => 4;
62 MT_HELLO_REQUEST => 0,
65 MT_NEW_SESSION_TICKET => 4,
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,
73 MT_CERTIFICATE_STATUS => 22,
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"
99 my @message_rec_list = ();
100 my @message_frag_lens = ();
111 @message_rec_list = ();
112 @message_frag_lens = ();
115 #Class method to extract messages from a record
119 my $serverin = shift;
124 @message_frag_lens = ();
126 if ($serverin != $server && length($payload) != 0) {
127 die "Changed peer, but we still have fragment data\n";
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";
137 TLSProxy::Record->server_ccs_seen(1);
139 TLSProxy::Record->client_ccs_seen(1);
141 } elsif ($record->content_type == TLSProxy::Record::RT_HANDSHAKE) {
142 if ($record->len == 0 || $record->len_real == 0) {
143 print " Message truncated\n";
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
151 push @message_rec_list, $record;
153 if ($messlen <= length($payload)) {
155 die "Internal error: invalid messlen: ".$messlen
156 ." payload length:".length($payload)."\n";
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,
165 push @messages, $message;
167 #Check if we have finished the handshake
168 if ($mt == MT_FINISHED && $server) {
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;
179 print " Partial message data read: ".$recoffset." bytes\n";
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";
188 @message_rec_list = ($record);
191 ($mt, $lenhi, $lenlo) = unpack('CnC',
192 substr($record->decrypt_data,
194 $messlen = ($lenhi << 8) | $lenlo;
195 print " Message type: $message_type{$mt}\n";
196 print " Message Length: $messlen\n";
197 $startoffset = $recoffset;
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,
207 $recoffset += $messlen;
208 push @message_frag_lens, $messlen;
209 $message = create_message($server, $mt, $payload,
211 push @messages, $message;
213 #Check if we have finished the handshake
214 if ($mt == MT_FINISHED && $server) {
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;
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
240 #Function to work out which sub-class we need to create and then
244 my ($server, $mt, $data, $startoffset) = @_;
247 #We only support ClientHello in this version...needs to be extended for
249 if ($mt == MT_CLIENT_HELLO) {
250 $message = TLSProxy::ClientHello->new(
258 } elsif ($mt == MT_SERVER_HELLO) {
259 $message = TLSProxy::ServerHello->new(
267 } elsif ($mt == MT_SERVER_KEY_EXCHANGE) {
268 $message = TLSProxy::ServerKeyExchange->new(
277 #Unknown message type
278 $message = TLSProxy::Message->new(
304 return !$success && $end;
314 $message_frag_lens) = @_;
321 startoffset => $startoffset,
322 message_frag_lens => $message_frag_lens
325 return bless $self, $class;
332 $ciphersuite = shift;
337 #Update all the underlying records with the modified data from this message
338 #Note: Does not currently support re-encrypting
344 my $numrecs = $#{$self->records};
346 $self->set_message_contents();
351 $lenlo = length($self->data) & 0xff;
352 $lenhi = length($self->data) >> 8;
353 $msgdata = pack('CnC', $self->mt, $lenhi, $lenlo).$self->data;
357 #The message is fully contained within one record
358 my ($rec) = @{$self->records};
359 my $recdata = $rec->decrypt_data;
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);
369 $rec->data(substr($recdata, 0, $self->startoffset)
371 .substr($recdata, ${$self->message_frag_lens}[0]
372 + TLS_MESSAGE_HEADER_LENGTH));
374 #Update the fragment len in case we changed it above
375 ${$self->message_frag_lens}[0] = length($msgdata)
376 - TLS_MESSAGE_HEADER_LENGTH;
380 #Note we don't currently support changing a fragmented message length
383 foreach my $rec (@{$self->records}) {
384 my $recdata = $rec->decrypt_data;
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));
395 #This is a middle record
396 $rec->data(substr($msgdata, $datadone, length($rec->data)));
397 $datadone += length($rec->data);
403 #To be overridden by sub-classes
404 sub set_message_contents
412 return $self->{server};
415 #Read/write accessors
428 $self->{data} = shift;
430 return $self->{data};
436 $self->{records} = shift;
438 return $self->{records};
444 $self->{startoffset} = shift;
446 return $self->{startoffset};
448 sub message_frag_lens
452 $self->{message_frag_lens} = shift;
454 return $self->{message_frag_lens};