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