Update copyright year
[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 => 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->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", 8
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
252
253 sub add_empty_recs_filter
254 {
255     my $proxy = shift;
256     my $records = $proxy->record_list;
257
258     # We're only interested in the initial ClientHello
259     if ($proxy->flight != 0) {
260         $fatal_alert = 1 if @{$records}[-1]->is_fatal_alert(1) == 10;
261         return;
262     }
263
264     for (my $i = 0; $i < $inject_recs_num; $i++) {
265         my $record = TLSProxy::Record->new(
266             0,
267             $content_type,
268             TLSProxy::Record::VERS_TLS_1_2,
269             0,
270             0,
271             0,
272             0,
273             "",
274             ""
275         );
276         push @{$records}, $record;
277     }
278 }
279
280 sub add_frag_alert_filter
281 {
282     my $proxy = shift;
283     my $records = $proxy->record_list;
284     my $byte;
285
286     # We're only interested in the initial ClientHello
287     if ($proxy->flight != 0) {
288         $fatal_alert = 1 if @{$records}[-1]->is_fatal_alert(1) == 10;
289         return;
290     }
291
292     # Add a zero length fragment first
293     #my $record = TLSProxy::Record->new(
294     #    0,
295     #    TLSProxy::Record::RT_ALERT,
296     #    TLSProxy::Record::VERS_TLS_1_2,
297     #    0,
298     #    0,
299     #    0,
300     #    "",
301     #    ""
302     #);
303     #push @{$proxy->record_list}, $record;
304
305     # Now add the alert level (Fatal) as a separate record
306     $byte = pack('C', TLSProxy::Message::AL_LEVEL_FATAL);
307     my $record = TLSProxy::Record->new(
308         0,
309         TLSProxy::Record::RT_ALERT,
310         TLSProxy::Record::VERS_TLS_1_2,
311         1,
312         0,
313         1,
314         1,
315         $byte,
316         $byte
317     );
318     push @{$records}, $record;
319
320     # And finally the description (Unexpected message) in a third record
321     $byte = pack('C', TLSProxy::Message::AL_DESC_UNEXPECTED_MESSAGE);
322     $record = TLSProxy::Record->new(
323         0,
324         TLSProxy::Record::RT_ALERT,
325         TLSProxy::Record::VERS_TLS_1_2,
326         1,
327         0,
328         1,
329         1,
330         $byte,
331         $byte
332     );
333     push @{$records}, $record;
334 }
335
336 sub add_sslv2_filter
337 {
338     my $proxy = shift;
339     my $clienthello;
340     my $record;
341
342     # We're only interested in the initial ClientHello
343     if ($proxy->flight != 0) {
344         return;
345     }
346
347     # Ditch the real ClientHello - we're going to replace it with our own
348     shift @{$proxy->record_list};
349
350     if ($sslv2testtype == ALERT_BEFORE_SSLV2) {
351         my $alert = pack('CC', TLSProxy::Message::AL_LEVEL_FATAL,
352                                TLSProxy::Message::AL_DESC_NO_RENEGOTIATION);
353         my $alertlen = length $alert;
354         $record = TLSProxy::Record->new(
355             0,
356             TLSProxy::Record::RT_ALERT,
357             TLSProxy::Record::VERS_TLS_1_2,
358             $alertlen,
359             0,
360             $alertlen,
361             $alertlen,
362             $alert,
363             $alert
364         );
365
366         push @{$proxy->record_list}, $record;
367     }
368
369     if ($sslv2testtype == ALERT_BEFORE_SSLV2
370             || $sslv2testtype == TLSV1_2_IN_SSLV2
371             || $sslv2testtype == SSLV2_IN_SSLV2) {
372         # This is an SSLv2 format ClientHello
373         $clienthello =
374             pack "C44",
375             0x01, # ClientHello
376             0x03, 0x03, #TLSv1.2
377             0x00, 0x03, # Ciphersuites len
378             0x00, 0x00, # Session id len
379             0x00, 0x20, # Challenge len
380             0x00, 0x00, 0x2f, #AES128-SHA
381             0x01, 0x18, 0x9F, 0x76, 0xEC, 0x57, 0xCE, 0xE5, 0xB3, 0xAB, 0x79, 0x90,
382             0xAD, 0xAC, 0x6E, 0xD1, 0x58, 0x35, 0x03, 0x97, 0x16, 0x10, 0x82, 0x56,
383             0xD8, 0x55, 0xFF, 0xE1, 0x8A, 0xA3, 0x2E, 0xF6; # Challenge
384
385         if ($sslv2testtype == SSLV2_IN_SSLV2) {
386             # Set the version to "real" SSLv2
387             vec($clienthello, 1, 8) = 0x00;
388             vec($clienthello, 2, 8) = 0x02;
389         }
390
391         my $chlen = length $clienthello;
392
393         $record = TLSProxy::Record->new(
394             0,
395             TLSProxy::Record::RT_HANDSHAKE,
396             TLSProxy::Record::VERS_TLS_1_2,
397             $chlen,
398             1, #SSLv2
399             $chlen,
400             $chlen,
401             $clienthello,
402             $clienthello
403         );
404
405         push @{$proxy->record_list}, $record;
406     } else {
407         # For this test we're using a real TLS ClientHello
408         $clienthello =
409             pack "C49",
410             0x01, # ClientHello
411             0x00, 0x00, 0x2D, # Message length
412             0x03, 0x03, # TLSv1.2
413             0x01, 0x18, 0x9F, 0x76, 0xEC, 0x57, 0xCE, 0xE5, 0xB3, 0xAB, 0x79, 0x90,
414             0xAD, 0xAC, 0x6E, 0xD1, 0x58, 0x35, 0x03, 0x97, 0x16, 0x10, 0x82, 0x56,
415             0xD8, 0x55, 0xFF, 0xE1, 0x8A, 0xA3, 0x2E, 0xF6, # Random
416             0x00, # Session id len
417             0x00, 0x04, # Ciphersuites len
418             0x00, 0x2f, # AES128-SHA
419             0x00, 0xff, # Empty reneg info SCSV
420             0x01, # Compression methods len
421             0x00, # Null compression
422             0x00, 0x00; # Extensions len
423
424         # Split this into 3: A TLS record; a SSLv2 record and a TLS record.
425         # We deliberately split the second record prior to the Challenge/Random
426         # and set the first byte of the random to 1. This makes the second SSLv2
427         # record look like an SSLv2 ClientHello
428         my $frag1 = substr $clienthello, 0, 6;
429         my $frag2 = substr $clienthello, 6, 32;
430         my $frag3 = substr $clienthello, 38;
431
432         my $fraglen = length $frag1;
433         $record = TLSProxy::Record->new(
434             0,
435             TLSProxy::Record::RT_HANDSHAKE,
436             TLSProxy::Record::VERS_TLS_1_2,
437             $fraglen,
438             0,
439             $fraglen,
440             $fraglen,
441             $frag1,
442             $frag1
443         );
444         push @{$proxy->record_list}, $record;
445
446         $fraglen = length $frag2;
447         my $recvers;
448         if ($sslv2testtype == FRAGMENTED_IN_SSLV2) {
449             $recvers = 1;
450         } else {
451             $recvers = 0;
452         }
453         $record = TLSProxy::Record->new(
454             0,
455             TLSProxy::Record::RT_HANDSHAKE,
456             TLSProxy::Record::VERS_TLS_1_2,
457             $fraglen,
458             $recvers,
459             $fraglen,
460             $fraglen,
461             $frag2,
462             $frag2
463         );
464         push @{$proxy->record_list}, $record;
465
466         $fraglen = length $frag3;
467         $record = TLSProxy::Record->new(
468             0,
469             TLSProxy::Record::RT_HANDSHAKE,
470             TLSProxy::Record::VERS_TLS_1_2,
471             $fraglen,
472             0,
473             $fraglen,
474             $fraglen,
475             $frag3,
476             $frag3
477         );
478         push @{$proxy->record_list}, $record;
479     }
480
481 }
482
483 sub add_unknown_record_type
484 {
485     my $proxy = shift;
486     my $records = $proxy->record_list;
487     state $added_record;
488
489     # We'll change a record after the initial version neg has taken place
490     if ($proxy->flight == 0) {
491         $added_record = 0;
492         return;
493     } elsif ($proxy->flight != 1 || $added_record) {
494         $fatal_alert = 1 if @{$records}[-1]->is_fatal_alert(0) == 10;
495         return;
496     }
497
498     my $record = TLSProxy::Record->new(
499         1,
500         TLSProxy::Record::RT_UNKNOWN,
501         @{$records}[-1]->version(),
502         1,
503         0,
504         1,
505         1,
506         "X",
507         "X"
508     );
509
510     #Find ServerHello record and insert after that
511     my $i;
512     for ($i = 0; ${$proxy->record_list}[$i]->flight() < 1; $i++) {
513         next;
514     }
515     $i++;
516
517     splice @{$proxy->record_list}, $i, 0, $record;
518     $added_record = 1;
519 }
520
521 sub change_version
522 {
523     my $proxy = shift;
524     my $records = $proxy->record_list;
525
526     # We'll change a version after the initial version neg has taken place
527     if ($proxy->flight != 1) {
528         $fatal_alert = 1 if @{$records}[-1]->is_fatal_alert(0) == 70;
529         return;
530     }
531
532     if ($#{$records} > 1) {
533         # ... typically in ServerHelloDone
534         @{$records}[-1]->version(TLSProxy::Record::VERS_TLS_1_1);
535     }
536 }
537
538 sub change_outer_record_type
539 {
540     my $proxy = shift;
541     my $records = $proxy->record_list;
542
543     # We'll change a record after the initial version neg has taken place
544     if ($proxy->flight != 1) {
545         $fatal_alert = 1 if @{$records}[-1]->is_fatal_alert(0) == 10;
546         return;
547     }
548
549     # Find CCS record and change record after that
550     my $i = 0;
551     foreach my $record (@{$records}) {
552         last if $record->content_type == TLSProxy::Record::RT_CCS;
553         $i++;
554     }
555     if (defined(${$records}[++$i])) {
556         ${$records}[$i]->outer_content_type(TLSProxy::Record::RT_HANDSHAKE);
557     }
558 }
559
560 sub not_on_record_boundary
561 {
562     my $proxy = shift;
563     my $records = $proxy->record_list;
564     my $data;
565
566     #Find server's first flight
567     if ($proxy->flight != 1) {
568         $fatal_alert = 1 if @{$records}[-1]->is_fatal_alert(0) == 10;
569         return;
570     }
571
572     if ($boundary_test_type == DATA_AFTER_SERVER_HELLO) {
573         #Merge the ServerHello and EncryptedExtensions records into one
574         my $i = 0;
575         foreach my $record (@{$records}) {
576             if ($record->content_type == TLSProxy::Record::RT_HANDSHAKE) {
577                 $record->{sent} = 1;    # pretend it's sent already
578                 last;
579             }
580             $i++;
581         }
582
583         if (defined(${$records}[$i+1])) {
584             $data = ${$records}[$i]->data();
585             $data .= ${$records}[$i+1]->decrypt_data();
586             ${$records}[$i+1]->data($data);
587             ${$records}[$i+1]->len(length $data);
588
589             #Delete the old ServerHello record
590             splice @{$records}, $i, 1;
591         }
592     } elsif ($boundary_test_type == DATA_AFTER_FINISHED) {
593         return if @{$proxy->{message_list}}[-1]->{mt}
594                   != TLSProxy::Message::MT_FINISHED;
595
596         my $last_record = @{$records}[-1];
597         $data = $last_record->decrypt_data;
598
599         #Add a KeyUpdate message onto the end of the Finished record
600         my $keyupdate = pack "C5",
601             0x18, # KeyUpdate
602             0x00, 0x00, 0x01, # Message length
603             0x00; # Update not requested
604
605         $data .= $keyupdate;
606
607         #Add content type and tag
608         $data .= pack("C", TLSProxy::Record::RT_HANDSHAKE).("\0"x16);
609
610         #Update the record
611         $last_record->data($data);
612         $last_record->len(length $data);
613     } elsif ($boundary_test_type == DATA_AFTER_KEY_UPDATE) {
614         return if @{$proxy->{message_list}}[-1]->{mt}
615                   != TLSProxy::Message::MT_FINISHED;
616
617         #KeyUpdates must end on a record boundary
618
619         my $record = TLSProxy::Record->new(
620             1,
621             TLSProxy::Record::RT_APPLICATION_DATA,
622             TLSProxy::Record::VERS_TLS_1_2,
623             0,
624             0,
625             0,
626             0,
627             "",
628             ""
629         );
630
631         #Add two KeyUpdate messages into a single record
632         my $keyupdate = pack "C5",
633             0x18, # KeyUpdate
634             0x00, 0x00, 0x01, # Message length
635             0x00; # Update not requested
636
637         $data = $keyupdate.$keyupdate;
638
639         #Add content type and tag
640         $data .= pack("C", TLSProxy::Record::RT_HANDSHAKE).("\0"x16);
641
642         $record->data($data);
643         $record->len(length $data);
644         push @{$records}, $record;
645     } else {
646         return if @{$proxy->{message_list}}[-1]->{mt}
647                   != TLSProxy::Message::MT_FINISHED;
648
649         my $record = TLSProxy::Record->new(
650             1,
651             TLSProxy::Record::RT_APPLICATION_DATA,
652             TLSProxy::Record::VERS_TLS_1_2,
653             0,
654             0,
655             0,
656             0,
657             "",
658             ""
659         );
660
661         #Add a partial KeyUpdate message into the record
662         $data = pack "C1",
663             0x18; # KeyUpdate message type. Omit the rest of the message header
664
665         #Add content type and tag
666         $data .= pack("C", TLSProxy::Record::RT_HANDSHAKE).("\0"x16);
667
668         $record->data($data);
669         $record->len(length $data);
670         push @{$records}, $record;
671
672         if ($boundary_test_type == DATA_BETWEEN_KEY_UPDATE) {
673             #Now add an app data record
674             $record = TLSProxy::Record->new(
675                 1,
676                 TLSProxy::Record::RT_APPLICATION_DATA,
677                 TLSProxy::Record::VERS_TLS_1_2,
678                 0,
679                 0,
680                 0,
681                 0,
682                 "",
683                 ""
684             );
685
686             #Add an empty app data record (just content type and tag)
687             $data = pack("C", TLSProxy::Record::RT_APPLICATION_DATA).("\0"x16);
688
689             $record->data($data);
690             $record->len(length $data);
691             push @{$records}, $record;
692         }
693
694         #Now add the rest of the KeyUpdate message
695         $record = TLSProxy::Record->new(
696             1,
697             TLSProxy::Record::RT_APPLICATION_DATA,
698             TLSProxy::Record::VERS_TLS_1_2,
699             0,
700             0,
701             0,
702             0,
703             "",
704             ""
705         );
706
707         #Add the last 4 bytes of the KeyUpdate record
708         $data = pack "C4",
709             0x00, 0x00, 0x01, # Message length
710             0x00; # Update not requested
711
712         #Add content type and tag
713         $data .= pack("C", TLSProxy::Record::RT_HANDSHAKE).("\0"x16);
714
715         $record->data($data);
716         $record->len(length $data);
717         push @{$records}, $record;
718
719     }
720 }