ECDSA with SHA3 verification does not depend on FIPS provider version
[openssl.git] / test / recipes / 70-test_sslrecords.t
1 #! /usr/bin/env perl
2 # Copyright 2016-2022 The OpenSSL Project Authors. All Rights Reserved.
3 #
4 # Licensed under the Apache License 2.0 (the "License").  You may not use
5 # this file except in compliance with the License.  You can obtain a copy
6 # in the file LICENSE in the source distribution or at
7 # https://www.openssl.org/source/license.html
8
9 use strict;
10 use feature 'state';
11
12 use OpenSSL::Test qw/:DEFAULT cmdstr srctop_file bldtop_dir/;
13 use OpenSSL::Test::Utils;
14 use TLSProxy::Proxy;
15
16 my $test_name = "test_sslrecords";
17 setup($test_name);
18
19 plan skip_all => "TLSProxy isn't usable on $^O"
20     if $^O =~ /^(VMS)$/;
21
22 plan skip_all => "$test_name needs the dynamic engine feature enabled"
23     if disabled("engine") || disabled("dynamic-engine");
24
25 plan skip_all => "$test_name needs the sock feature enabled"
26     if disabled("sock");
27
28 plan skip_all => "$test_name needs TLSv1.2 enabled"
29     if disabled("tls1_2");
30
31 my $proxy = TLSProxy::Proxy->new(
32     \&add_empty_recs_filter,
33     cmdstr(app(["openssl"]), display => 1),
34     srctop_file("apps", "server.pem"),
35     (!$ENV{HARNESS_ACTIVE} || $ENV{HARNESS_VERBOSE})
36 );
37
38 my $boundary_test_type;
39 my $fatal_alert = 0;    # set by filters at expected fatal alerts
40
41 #Test 1: Injecting out of context empty records should fail
42 my $content_type = TLSProxy::Record::RT_APPLICATION_DATA;
43 my $inject_recs_num = 1;
44 $proxy->serverflags("-tls1_2");
45 $proxy->clientflags("-no_tls1_3");
46 $proxy->start() or plan skip_all => "Unable to start up Proxy for tests";
47 plan tests => 21;
48 ok($fatal_alert, "Out of context empty records test");
49
50 #Test 2: Injecting in context empty records should succeed
51 $proxy->clear();
52 $content_type = TLSProxy::Record::RT_HANDSHAKE;
53 $proxy->serverflags("-tls1_2");
54 $proxy->clientflags("-no_tls1_3");
55 $proxy->start();
56 ok(TLSProxy::Message->success(), "In context empty records test");
57
58 #Test 3: Injecting too many in context empty records should fail
59 $fatal_alert = 0;
60 $proxy->clear();
61 #We allow 32 consecutive in context empty records
62 $inject_recs_num = 33;
63 $proxy->serverflags("-tls1_2");
64 $proxy->clientflags("-no_tls1_3");
65 $proxy->start();
66 ok($fatal_alert, "Too many in context empty records test");
67
68 #Test 4: Injecting a fragmented fatal alert should fail. We expect the server to
69 #        send back an alert of its own because it cannot handle fragmented
70 #        alerts
71 $fatal_alert = 0;
72 $proxy->clear();
73 $proxy->filter(\&add_frag_alert_filter);
74 $proxy->serverflags("-tls1_2");
75 $proxy->clientflags("-no_tls1_3");
76 $proxy->start();
77 ok($fatal_alert, "Fragmented alert records test");
78
79 #Run some SSLv2 ClientHello tests
80
81 use constant {
82     TLSV1_2_IN_SSLV2 => 0,
83     SSLV2_IN_SSLV2 => 1,
84     FRAGMENTED_IN_TLSV1_2 => 2,
85     FRAGMENTED_IN_SSLV2 => 3,
86     ALERT_BEFORE_SSLV2 => 4
87 };
88
89 # The TLSv1.2 in SSLv2 ClientHello need to run at security level 0
90 # because in a SSLv2 ClientHello we can't send extensions to indicate
91 # which signature algorithm we want to use, and the default is SHA1.
92
93 #Test 5: Inject an SSLv2 style record format for a TLSv1.2 ClientHello
94 my $sslv2testtype = TLSV1_2_IN_SSLV2;
95 $proxy->clear();
96 $proxy->filter(\&add_sslv2_filter);
97 $proxy->serverflags("-tls1_2");
98 $proxy->clientflags("-no_tls1_3 -legacy_renegotiation");
99 $proxy->ciphers("AES128-SHA:\@SECLEVEL=0");
100 $proxy->start();
101 ok(TLSProxy::Message->success(), "TLSv1.2 in SSLv2 ClientHello test");
102
103 #Test 6: Inject an SSLv2 style record format for an SSLv2 ClientHello. We don't
104 #        support this so it should fail. We actually treat it as an unknown
105 #        protocol so we don't even send an alert in this case.
106 $sslv2testtype = SSLV2_IN_SSLV2;
107 $proxy->clear();
108 $proxy->serverflags("-tls1_2");
109 $proxy->clientflags("-no_tls1_3");
110 $proxy->ciphers("AES128-SHA:\@SECLEVEL=0");
111 $proxy->start();
112 ok(TLSProxy::Message->fail(), "SSLv2 in SSLv2 ClientHello test");
113
114 #Test 7: Sanity check ClientHello fragmentation. This isn't really an SSLv2 test
115 #        at all, but it gives us confidence that Test 8 fails for the right
116 #        reasons
117 $sslv2testtype = FRAGMENTED_IN_TLSV1_2;
118 $proxy->clear();
119 $proxy->serverflags("-tls1_2");
120 $proxy->clientflags("-no_tls1_3");
121 $proxy->ciphers("AES128-SHA:\@SECLEVEL=0");
122 $proxy->start();
123 ok(TLSProxy::Message->success(), "Fragmented ClientHello in TLSv1.2 test");
124
125 #Test 8: Fragment a TLSv1.2 ClientHello across a TLS1.2 record; an SSLv2
126 #        record; and another TLS1.2 record. This isn't allowed so should fail
127 $sslv2testtype = FRAGMENTED_IN_SSLV2;
128 $proxy->clear();
129 $proxy->serverflags("-tls1_2");
130 $proxy->clientflags("-no_tls1_3");
131 $proxy->ciphers("AES128-SHA:\@SECLEVEL=0");
132 $proxy->start();
133 ok(TLSProxy::Message->fail(), "Fragmented ClientHello in TLSv1.2/SSLv2 test");
134
135 #Test 9: Send a TLS warning alert before an SSLv2 ClientHello. This should
136 #        fail because an SSLv2 ClientHello must be the first record.
137 $sslv2testtype = ALERT_BEFORE_SSLV2;
138 $proxy->clear();
139 $proxy->serverflags("-tls1_2");
140 $proxy->clientflags("-no_tls1_3");
141 $proxy->ciphers("AES128-SHA:\@SECLEVEL=0");
142 $proxy->start();
143 ok(TLSProxy::Message->fail(), "Alert before SSLv2 ClientHello test");
144
145 #Unrecognised record type tests
146
147 #Test 10: Sending an unrecognised record type in TLS1.2 should fail
148 $fatal_alert = 0;
149 $proxy->clear();
150 $proxy->serverflags("-tls1_2");
151 $proxy->clientflags("-no_tls1_3");
152 $proxy->filter(\&add_unknown_record_type);
153 $proxy->start();
154 ok($fatal_alert, "Unrecognised record type in TLS1.2");
155
156 SKIP: {
157     skip "TLSv1.1 disabled", 1 if disabled("tls1_1");
158
159     #Test 11: Sending an unrecognised record type in TLS1.1 should fail
160     $fatal_alert = 0;
161     $proxy->clear();
162     $proxy->clientflags("-tls1_1 -cipher DEFAULT:\@SECLEVEL=0");
163     $proxy->ciphers("AES128-SHA:\@SECLEVEL=0");
164     $proxy->start();
165     ok($fatal_alert, "Unrecognised record type in TLS1.1");
166 }
167
168 #Test 12: Sending a different record version in TLS1.2 should fail
169 $fatal_alert = 0;
170 $proxy->clear();
171 $proxy->clientflags("-tls1_2");
172 $proxy->filter(\&change_version);
173 $proxy->start();
174 ok($fatal_alert, "Changed record version in TLS1.2");
175
176 #TLS1.3 specific tests
177 SKIP: {
178     skip "TLSv1.3 disabled", 9
179         if disabled("tls1_3") || (disabled("ec") && disabled("dh"));
180
181     #Test 13: Sending a different record version in TLS1.3 should fail
182     $proxy->clear();
183     $proxy->filter(\&change_version);
184     $proxy->start();
185     ok(TLSProxy::Message->fail(), "Changed record version in TLS1.3");
186
187     #Test 14: Sending an unrecognised record type in TLS1.3 should fail
188     $fatal_alert = 0;
189     $proxy->clear();
190     $proxy->filter(\&add_unknown_record_type);
191     $proxy->start();
192     ok($fatal_alert, "Unrecognised record type in TLS1.3");
193
194     #Test 15: Sending an outer record type other than app data once encrypted
195     #should fail
196     $fatal_alert = 0;
197     $proxy->clear();
198     $proxy->filter(\&change_outer_record_type);
199     $proxy->start();
200     ok($fatal_alert, "Wrong outer record type in TLS1.3");
201
202     use constant {
203         DATA_AFTER_SERVER_HELLO => 0,
204         DATA_AFTER_FINISHED => 1,
205         DATA_AFTER_KEY_UPDATE => 2,
206         DATA_BETWEEN_KEY_UPDATE => 3,
207         NO_DATA_BETWEEN_KEY_UPDATE => 4,
208     };
209
210     #Test 16: Sending a ServerHello which doesn't end on a record boundary
211     #         should fail
212     $fatal_alert = 0;
213     $proxy->clear();
214     $boundary_test_type = DATA_AFTER_SERVER_HELLO;
215     $proxy->filter(\&not_on_record_boundary);
216     $proxy->start();
217     ok($fatal_alert, "Record not on boundary in TLS1.3 (ServerHello)");
218
219     #Test 17: Sending a Finished which doesn't end on a record boundary
220     #         should fail
221     $fatal_alert = 0;
222     $proxy->clear();
223     $boundary_test_type = DATA_AFTER_FINISHED;
224     $proxy->start();
225     ok($fatal_alert, "Record not on boundary in TLS1.3 (Finished)");
226
227     #Test 18: Sending a KeyUpdate which doesn't end on a record boundary
228     #         should fail
229     $fatal_alert = 0;
230     $proxy->clear();
231     $boundary_test_type = DATA_AFTER_KEY_UPDATE;
232     $proxy->start();
233     ok($fatal_alert, "Record not on boundary in TLS1.3 (KeyUpdate)");
234
235     #Test 19: Sending application data in the middle of a fragmented KeyUpdate
236     #         should fail. Strictly speaking this is not a record boundary test
237     #         but we use the same filter.
238     $fatal_alert = 0;
239     $proxy->clear();
240     $boundary_test_type = DATA_BETWEEN_KEY_UPDATE;
241     $proxy->start();
242     ok($fatal_alert, "Data between KeyUpdate");
243
244     #Test 20: Fragmented KeyUpdate. This should succeed. Strictly speaking this
245     #         is not a record boundary test but we use the same filter.
246     $proxy->clear();
247     $boundary_test_type = NO_DATA_BETWEEN_KEY_UPDATE;
248     $proxy->start();
249     ok(TLSProxy::Message->success(), "No data between KeyUpdate");
250
251     SKIP: {
252         skip "EC disabled", 1 if disabled("ec");
253
254         #Test 21: Force an HRR and change the "real" ServerHello to have a protocol
255         #         record version of 0x0301 (TLSv1.0). At this point we have already
256         #         decided that we are doing TLSv1.3 but are still using plaintext
257         #         records. The server should be sending a record version of 0x303
258         #         (TLSv1.2), but the RFC requires us to ignore this field so we
259         #         should tolerate the incorrect version.
260         $proxy->clear();
261         $proxy->filter(\&change_server_hello_version);
262         $proxy->serverflags("-groups P-256"); # Force an HRR
263         $proxy->start();
264         ok(TLSProxy::Message->success(), "Bad ServerHello record version after HRR");
265     }
266  }
267
268
269 sub add_empty_recs_filter
270 {
271     my $proxy = shift;
272     my $records = $proxy->record_list;
273
274     # We're only interested in the initial ClientHello
275     if ($proxy->flight != 0) {
276         $fatal_alert = 1 if @{$records}[-1]->is_fatal_alert(1) == 10;
277         return;
278     }
279
280     for (my $i = 0; $i < $inject_recs_num; $i++) {
281         my $record = TLSProxy::Record->new(
282             0,
283             $content_type,
284             TLSProxy::Record::VERS_TLS_1_2,
285             0,
286             0,
287             0,
288             0,
289             "",
290             ""
291         );
292         push @{$records}, $record;
293     }
294 }
295
296 sub add_frag_alert_filter
297 {
298     my $proxy = shift;
299     my $records = $proxy->record_list;
300     my $byte;
301
302     # We're only interested in the initial ClientHello
303     if ($proxy->flight != 0) {
304         $fatal_alert = 1 if @{$records}[-1]->is_fatal_alert(1) == 10;
305         return;
306     }
307
308     # Add a zero length fragment first
309     #my $record = TLSProxy::Record->new(
310     #    0,
311     #    TLSProxy::Record::RT_ALERT,
312     #    TLSProxy::Record::VERS_TLS_1_2,
313     #    0,
314     #    0,
315     #    0,
316     #    "",
317     #    ""
318     #);
319     #push @{$proxy->record_list}, $record;
320
321     # Now add the alert level (Fatal) as a separate record
322     $byte = pack('C', TLSProxy::Message::AL_LEVEL_FATAL);
323     my $record = TLSProxy::Record->new(
324         0,
325         TLSProxy::Record::RT_ALERT,
326         TLSProxy::Record::VERS_TLS_1_2,
327         1,
328         0,
329         1,
330         1,
331         $byte,
332         $byte
333     );
334     push @{$records}, $record;
335
336     # And finally the description (Unexpected message) in a third record
337     $byte = pack('C', TLSProxy::Message::AL_DESC_UNEXPECTED_MESSAGE);
338     $record = TLSProxy::Record->new(
339         0,
340         TLSProxy::Record::RT_ALERT,
341         TLSProxy::Record::VERS_TLS_1_2,
342         1,
343         0,
344         1,
345         1,
346         $byte,
347         $byte
348     );
349     push @{$records}, $record;
350 }
351
352 sub add_sslv2_filter
353 {
354     my $proxy = shift;
355     my $clienthello;
356     my $record;
357
358     # We're only interested in the initial ClientHello
359     if ($proxy->flight != 0) {
360         return;
361     }
362
363     # Ditch the real ClientHello - we're going to replace it with our own
364     shift @{$proxy->record_list};
365
366     if ($sslv2testtype == ALERT_BEFORE_SSLV2) {
367         my $alert = pack('CC', TLSProxy::Message::AL_LEVEL_FATAL,
368                                TLSProxy::Message::AL_DESC_NO_RENEGOTIATION);
369         my $alertlen = length $alert;
370         $record = TLSProxy::Record->new(
371             0,
372             TLSProxy::Record::RT_ALERT,
373             TLSProxy::Record::VERS_TLS_1_2,
374             $alertlen,
375             0,
376             $alertlen,
377             $alertlen,
378             $alert,
379             $alert
380         );
381
382         push @{$proxy->record_list}, $record;
383     }
384
385     if ($sslv2testtype == ALERT_BEFORE_SSLV2
386             || $sslv2testtype == TLSV1_2_IN_SSLV2
387             || $sslv2testtype == SSLV2_IN_SSLV2) {
388         # This is an SSLv2 format ClientHello
389         $clienthello =
390             pack "C44",
391             0x01, # ClientHello
392             0x03, 0x03, #TLSv1.2
393             0x00, 0x03, # Ciphersuites len
394             0x00, 0x00, # Session id len
395             0x00, 0x20, # Challenge len
396             0x00, 0x00, 0x2f, #AES128-SHA
397             0x01, 0x18, 0x9F, 0x76, 0xEC, 0x57, 0xCE, 0xE5, 0xB3, 0xAB, 0x79, 0x90,
398             0xAD, 0xAC, 0x6E, 0xD1, 0x58, 0x35, 0x03, 0x97, 0x16, 0x10, 0x82, 0x56,
399             0xD8, 0x55, 0xFF, 0xE1, 0x8A, 0xA3, 0x2E, 0xF6; # Challenge
400
401         if ($sslv2testtype == SSLV2_IN_SSLV2) {
402             # Set the version to "real" SSLv2
403             vec($clienthello, 1, 8) = 0x00;
404             vec($clienthello, 2, 8) = 0x02;
405         }
406
407         my $chlen = length $clienthello;
408
409         $record = TLSProxy::Record->new(
410             0,
411             TLSProxy::Record::RT_HANDSHAKE,
412             TLSProxy::Record::VERS_TLS_1_2,
413             $chlen,
414             1, #SSLv2
415             $chlen,
416             $chlen,
417             $clienthello,
418             $clienthello
419         );
420
421         push @{$proxy->record_list}, $record;
422     } else {
423         # For this test we're using a real TLS ClientHello
424         $clienthello =
425             pack "C49",
426             0x01, # ClientHello
427             0x00, 0x00, 0x2D, # Message length
428             0x03, 0x03, # TLSv1.2
429             0x01, 0x18, 0x9F, 0x76, 0xEC, 0x57, 0xCE, 0xE5, 0xB3, 0xAB, 0x79, 0x90,
430             0xAD, 0xAC, 0x6E, 0xD1, 0x58, 0x35, 0x03, 0x97, 0x16, 0x10, 0x82, 0x56,
431             0xD8, 0x55, 0xFF, 0xE1, 0x8A, 0xA3, 0x2E, 0xF6, # Random
432             0x00, # Session id len
433             0x00, 0x04, # Ciphersuites len
434             0x00, 0x2f, # AES128-SHA
435             0x00, 0xff, # Empty reneg info SCSV
436             0x01, # Compression methods len
437             0x00, # Null compression
438             0x00, 0x00; # Extensions len
439
440         # Split this into 3: A TLS record; a SSLv2 record and a TLS record.
441         # We deliberately split the second record prior to the Challenge/Random
442         # and set the first byte of the random to 1. This makes the second SSLv2
443         # record look like an SSLv2 ClientHello
444         my $frag1 = substr $clienthello, 0, 6;
445         my $frag2 = substr $clienthello, 6, 32;
446         my $frag3 = substr $clienthello, 38;
447
448         my $fraglen = length $frag1;
449         $record = TLSProxy::Record->new(
450             0,
451             TLSProxy::Record::RT_HANDSHAKE,
452             TLSProxy::Record::VERS_TLS_1_2,
453             $fraglen,
454             0,
455             $fraglen,
456             $fraglen,
457             $frag1,
458             $frag1
459         );
460         push @{$proxy->record_list}, $record;
461
462         $fraglen = length $frag2;
463         my $recvers;
464         if ($sslv2testtype == FRAGMENTED_IN_SSLV2) {
465             $recvers = 1;
466         } else {
467             $recvers = 0;
468         }
469         $record = TLSProxy::Record->new(
470             0,
471             TLSProxy::Record::RT_HANDSHAKE,
472             TLSProxy::Record::VERS_TLS_1_2,
473             $fraglen,
474             $recvers,
475             $fraglen,
476             $fraglen,
477             $frag2,
478             $frag2
479         );
480         push @{$proxy->record_list}, $record;
481
482         $fraglen = length $frag3;
483         $record = TLSProxy::Record->new(
484             0,
485             TLSProxy::Record::RT_HANDSHAKE,
486             TLSProxy::Record::VERS_TLS_1_2,
487             $fraglen,
488             0,
489             $fraglen,
490             $fraglen,
491             $frag3,
492             $frag3
493         );
494         push @{$proxy->record_list}, $record;
495     }
496
497 }
498
499 sub add_unknown_record_type
500 {
501     my $proxy = shift;
502     my $records = $proxy->record_list;
503     state $added_record;
504
505     # We'll change a record after the initial version neg has taken place
506     if ($proxy->flight == 0) {
507         $added_record = 0;
508         return;
509     } elsif ($proxy->flight != 1 || $added_record) {
510         $fatal_alert = 1 if @{$records}[-1]->is_fatal_alert(0) == 10;
511         return;
512     }
513
514     my $record = TLSProxy::Record->new(
515         1,
516         TLSProxy::Record::RT_UNKNOWN,
517         @{$records}[-1]->version(),
518         1,
519         0,
520         1,
521         1,
522         "X",
523         "X"
524     );
525
526     #Find ServerHello record and insert after that
527     my $i;
528     for ($i = 0; ${$proxy->record_list}[$i]->flight() < 1; $i++) {
529         next;
530     }
531     $i++;
532
533     splice @{$proxy->record_list}, $i, 0, $record;
534     $added_record = 1;
535 }
536
537 sub change_version
538 {
539     my $proxy = shift;
540     my $records = $proxy->record_list;
541
542     # We'll change a version after the initial version neg has taken place
543     if ($proxy->flight != 1) {
544         $fatal_alert = 1 if @{$records}[-1]->is_fatal_alert(0) == 70;
545         return;
546     }
547
548     if ($#{$records} > 1) {
549         # ... typically in ServerHelloDone
550         @{$records}[-1]->version(TLSProxy::Record::VERS_TLS_1_1);
551     }
552 }
553
554 sub change_server_hello_version
555 {
556     my $proxy = shift;
557     my $records = $proxy->record_list;
558
559     # We're only interested in changing the ServerHello after an HRR
560     if ($proxy->flight != 3) {
561         return;
562     }
563
564     # The ServerHello has index 5
565     # 0 - ClientHello
566     # 1 - HRR
567     # 2 - CCS
568     # 3 - ClientHello(2)
569     # 4 - CCS
570     # 5 - ServerHello
571     @{$records}[5]->version(TLSProxy::Record::VERS_TLS_1_0);
572 }
573
574 sub change_outer_record_type
575 {
576     my $proxy = shift;
577     my $records = $proxy->record_list;
578
579     # We'll change a record after the initial version neg has taken place
580     if ($proxy->flight != 1) {
581         $fatal_alert = 1 if @{$records}[-1]->is_fatal_alert(0) == 10;
582         return;
583     }
584
585     # Find CCS record and change record after that
586     my $i = 0;
587     foreach my $record (@{$records}) {
588         last if $record->content_type == TLSProxy::Record::RT_CCS;
589         $i++;
590     }
591     if (defined(${$records}[++$i])) {
592         ${$records}[$i]->outer_content_type(TLSProxy::Record::RT_HANDSHAKE);
593     }
594 }
595
596 sub not_on_record_boundary
597 {
598     my $proxy = shift;
599     my $records = $proxy->record_list;
600     my $data;
601
602     #Find server's first flight
603     if ($proxy->flight != 1) {
604         $fatal_alert = 1 if @{$records}[-1]->is_fatal_alert(0) == 10;
605         return;
606     }
607
608     if ($boundary_test_type == DATA_AFTER_SERVER_HELLO) {
609         #Merge the ServerHello and EncryptedExtensions records into one
610         my $i = 0;
611         foreach my $record (@{$records}) {
612             if ($record->content_type == TLSProxy::Record::RT_HANDSHAKE) {
613                 $record->{sent} = 1;    # pretend it's sent already
614                 last;
615             }
616             $i++;
617         }
618
619         if (defined(${$records}[$i+1])) {
620             $data = ${$records}[$i]->data();
621             $data .= ${$records}[$i+1]->decrypt_data();
622             ${$records}[$i+1]->data($data);
623             ${$records}[$i+1]->len(length $data);
624
625             #Delete the old ServerHello record
626             splice @{$records}, $i, 1;
627         }
628     } elsif ($boundary_test_type == DATA_AFTER_FINISHED) {
629         return if @{$proxy->{message_list}}[-1]->{mt}
630                   != TLSProxy::Message::MT_FINISHED;
631
632         my $last_record = @{$records}[-1];
633         $data = $last_record->decrypt_data;
634
635         #Add a KeyUpdate message onto the end of the Finished record
636         my $keyupdate = pack "C5",
637             0x18, # KeyUpdate
638             0x00, 0x00, 0x01, # Message length
639             0x00; # Update not requested
640
641         $data .= $keyupdate;
642
643         #Add content type and tag
644         $data .= pack("C", TLSProxy::Record::RT_HANDSHAKE).("\0"x16);
645
646         #Update the record
647         $last_record->data($data);
648         $last_record->len(length $data);
649     } elsif ($boundary_test_type == DATA_AFTER_KEY_UPDATE) {
650         return if @{$proxy->{message_list}}[-1]->{mt}
651                   != TLSProxy::Message::MT_FINISHED;
652
653         #KeyUpdates must end on a record boundary
654
655         my $record = TLSProxy::Record->new(
656             1,
657             TLSProxy::Record::RT_APPLICATION_DATA,
658             TLSProxy::Record::VERS_TLS_1_2,
659             0,
660             0,
661             0,
662             0,
663             "",
664             ""
665         );
666
667         #Add two KeyUpdate messages into a single record
668         my $keyupdate = pack "C5",
669             0x18, # KeyUpdate
670             0x00, 0x00, 0x01, # Message length
671             0x00; # Update not requested
672
673         $data = $keyupdate.$keyupdate;
674
675         #Add content type and tag
676         $data .= pack("C", TLSProxy::Record::RT_HANDSHAKE).("\0"x16);
677
678         $record->data($data);
679         $record->len(length $data);
680         push @{$records}, $record;
681     } else {
682         return if @{$proxy->{message_list}}[-1]->{mt}
683                   != TLSProxy::Message::MT_FINISHED;
684
685         my $record = TLSProxy::Record->new(
686             1,
687             TLSProxy::Record::RT_APPLICATION_DATA,
688             TLSProxy::Record::VERS_TLS_1_2,
689             0,
690             0,
691             0,
692             0,
693             "",
694             ""
695         );
696
697         #Add a partial KeyUpdate message into the record
698         $data = pack "C1",
699             0x18; # KeyUpdate message type. Omit the rest of the message header
700
701         #Add content type and tag
702         $data .= pack("C", TLSProxy::Record::RT_HANDSHAKE).("\0"x16);
703
704         $record->data($data);
705         $record->len(length $data);
706         push @{$records}, $record;
707
708         if ($boundary_test_type == DATA_BETWEEN_KEY_UPDATE) {
709             #Now add an app data record
710             $record = TLSProxy::Record->new(
711                 1,
712                 TLSProxy::Record::RT_APPLICATION_DATA,
713                 TLSProxy::Record::VERS_TLS_1_2,
714                 0,
715                 0,
716                 0,
717                 0,
718                 "",
719                 ""
720             );
721
722             #Add an empty app data record (just content type and tag)
723             $data = pack("C", TLSProxy::Record::RT_APPLICATION_DATA).("\0"x16);
724
725             $record->data($data);
726             $record->len(length $data);
727             push @{$records}, $record;
728         }
729
730         #Now add the rest of the KeyUpdate message
731         $record = TLSProxy::Record->new(
732             1,
733             TLSProxy::Record::RT_APPLICATION_DATA,
734             TLSProxy::Record::VERS_TLS_1_2,
735             0,
736             0,
737             0,
738             0,
739             "",
740             ""
741         );
742
743         #Add the last 4 bytes of the KeyUpdate record
744         $data = pack "C4",
745             0x00, 0x00, 0x01, # Message length
746             0x00; # Update not requested
747
748         #Add content type and tag
749         $data .= pack("C", TLSProxy::Record::RT_HANDSHAKE).("\0"x16);
750
751         $record->data($data);
752         $record->len(length $data);
753         push @{$records}, $record;
754
755     }
756 }