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