70-test_sslrecords.t (1.1.1.3) | 70-test_sslrecords.t (1.1.1.1) |
---|---|
1#! /usr/bin/env perl | 1#! /usr/bin/env perl |
2# Copyright 2016-2018 The OpenSSL Project Authors. All Rights Reserved. | 2# Copyright 2016 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 9use strict; | 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 9use strict; |
10use feature 'state'; 11 | |
12use OpenSSL::Test qw/:DEFAULT cmdstr srctop_file bldtop_dir/; 13use OpenSSL::Test::Utils; 14use TLSProxy::Proxy; 15 16my $test_name = "test_sslrecords"; 17setup($test_name); 18 19plan skip_all => "TLSProxy isn't usable on $^O" | 10use OpenSSL::Test qw/:DEFAULT cmdstr srctop_file bldtop_dir/; 11use OpenSSL::Test::Utils; 12use TLSProxy::Proxy; 13 14my $test_name = "test_sslrecords"; 15setup($test_name); 16 17plan skip_all => "TLSProxy isn't usable on $^O" |
20 if $^O =~ /^(VMS)$/; | 18 if $^O =~ /^(VMS|MSWin32)$/; |
21 22plan skip_all => "$test_name needs the dynamic engine feature enabled" 23 if disabled("engine") || disabled("dynamic-engine"); 24 25plan skip_all => "$test_name needs the sock feature enabled" 26 if disabled("sock"); 27 28plan skip_all => "$test_name needs TLSv1.2 enabled" 29 if disabled("tls1_2"); 30 31$ENV{OPENSSL_ia32cap} = '~0x200000200000000'; 32my $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 | 19 20plan skip_all => "$test_name needs the dynamic engine feature enabled" 21 if disabled("engine") || disabled("dynamic-engine"); 22 23plan skip_all => "$test_name needs the sock feature enabled" 24 if disabled("sock"); 25 26plan skip_all => "$test_name needs TLSv1.2 enabled" 27 if disabled("tls1_2"); 28 29$ENV{OPENSSL_ia32cap} = '~0x200000200000000'; 30my $proxy = TLSProxy::Proxy->new( 31 \&add_empty_recs_filter, 32 cmdstr(app(["openssl"]), display => 1), 33 srctop_file("apps", "server.pem"), 34 (!$ENV{HARNESS_ACTIVE} || $ENV{HARNESS_VERBOSE}) 35); 36 |
39my $boundary_test_type; 40my $fatal_alert = 0; # set by filters at expected fatal alerts 41 | |
42#Test 1: Injecting out of context empty records should fail 43my $content_type = TLSProxy::Record::RT_APPLICATION_DATA; 44my $inject_recs_num = 1; | 37#Test 1: Injecting out of context empty records should fail 38my $content_type = TLSProxy::Record::RT_APPLICATION_DATA; 39my $inject_recs_num = 1; |
45$proxy->serverflags("-tls1_2"); | |
46$proxy->start() or plan skip_all => "Unable to start up Proxy for tests"; | 40$proxy->start() or plan skip_all => "Unable to start up Proxy for tests"; |
47plan tests => 18; 48ok($fatal_alert, "Out of context empty records test"); | 41my $num_tests = 10; 42if (!disabled("tls1_1")) { 43 $num_tests++; 44} 45plan tests => $num_tests; 46ok(TLSProxy::Message->fail(), "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; | 47 48#Test 2: Injecting in context empty records should succeed 49$proxy->clear(); 50$content_type = TLSProxy::Record::RT_HANDSHAKE; |
53$proxy->serverflags("-tls1_2"); | |
54$proxy->start(); 55ok(TLSProxy::Message->success(), "In context empty records test"); 56 57#Test 3: Injecting too many in context empty records should fail | 51$proxy->start(); 52ok(TLSProxy::Message->success(), "In context empty records test"); 53 54#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; | 55$proxy->clear(); 56#We allow 32 consecutive in context empty records 57$inject_recs_num = 33; |
62$proxy->serverflags("-tls1_2"); | |
63$proxy->start(); | 58$proxy->start(); |
64ok($fatal_alert, "Too many in context empty records test"); | 59ok(TLSProxy::Message->fail(), "Too many in context empty records test"); |
65 | 60 |
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; | 61#Test 4: Injecting a fragmented fatal alert should fail. We actually expect no 62# alerts to be sent from either side because *we* injected the fatal 63# alert, i.e. this will look like a disorderly close |
70$proxy->clear(); 71$proxy->filter(\&add_frag_alert_filter); | 64$proxy->clear(); 65$proxy->filter(\&add_frag_alert_filter); |
72$proxy->serverflags("-tls1_2"); | |
73$proxy->start(); | 66$proxy->start(); |
74ok($fatal_alert, "Fragmented alert records test"); | 67ok(!TLSProxy::Message->end(), "Fragmented alert records test"); |
75 76#Run some SSLv2 ClientHello tests 77 78use 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 86my $sslv2testtype = TLSV1_2_IN_SSLV2; 87$proxy->clear(); 88$proxy->filter(\&add_sslv2_filter); | 68 69#Run some SSLv2 ClientHello tests 70 71use constant { 72 TLSV1_2_IN_SSLV2 => 0, 73 SSLV2_IN_SSLV2 => 1, 74 FRAGMENTED_IN_TLSV1_2 => 2, 75 FRAGMENTED_IN_SSLV2 => 3, 76 ALERT_BEFORE_SSLV2 => 4 77}; 78#Test 5: Inject an SSLv2 style record format for a TLSv1.2 ClientHello 79my $sslv2testtype = TLSV1_2_IN_SSLV2; 80$proxy->clear(); 81$proxy->filter(\&add_sslv2_filter); |
89$proxy->serverflags("-tls1_2"); | |
90$proxy->start(); 91ok(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(); | 82$proxy->start(); 83ok(TLSProxy::Message->success(), "TLSv1.2 in SSLv2 ClientHello test"); 84 85#Test 6: Inject an SSLv2 style record format for an SSLv2 ClientHello. We don't 86# support this so it should fail. We actually treat it as an unknown 87# protocol so we don't even send an alert in this case. 88$sslv2testtype = SSLV2_IN_SSLV2; 89$proxy->clear(); |
98$proxy->serverflags("-tls1_2"); | |
99$proxy->start(); | 90$proxy->start(); |
100ok(TLSProxy::Message->fail(), "SSLv2 in SSLv2 ClientHello test"); | 91ok(!TLSProxy::Message->end(), "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(); | 92 93#Test 7: Sanity check ClientHello fragmentation. This isn't really an SSLv2 test 94# at all, but it gives us confidence that Test 8 fails for the right 95# reasons 96$sslv2testtype = FRAGMENTED_IN_TLSV1_2; 97$proxy->clear(); |
107$proxy->serverflags("-tls1_2"); | |
108$proxy->start(); 109ok(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(); | 98$proxy->start(); 99ok(TLSProxy::Message->success(), "Fragmented ClientHello in TLSv1.2 test"); 100 101#Test 8: Fragment a TLSv1.2 ClientHello across a TLS1.2 record; an SSLv2 102# record; and another TLS1.2 record. This isn't allowed so should fail 103$sslv2testtype = FRAGMENTED_IN_SSLV2; 104$proxy->clear(); |
115$proxy->serverflags("-tls1_2"); | |
116$proxy->start(); 117ok(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(); | 105$proxy->start(); 106ok(TLSProxy::Message->fail(), "Fragmented ClientHello in TLSv1.2/SSLv2 test"); 107 108#Test 9: Send a TLS warning alert before an SSLv2 ClientHello. This should 109# fail because an SSLv2 ClientHello must be the first record. 110$sslv2testtype = ALERT_BEFORE_SSLV2; 111$proxy->clear(); |
123$proxy->serverflags("-tls1_2"); | |
124$proxy->start(); 125ok(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 | 112$proxy->start(); 113ok(TLSProxy::Message->fail(), "Alert before SSLv2 ClientHello test"); 114 115#Unrecognised record type tests 116 117#Test 10: Sending an unrecognised record type in TLS1.2 should fail |
130$fatal_alert = 0; | |
131$proxy->clear(); | 118$proxy->clear(); |
132$proxy->serverflags("-tls1_2"); | |
133$proxy->filter(\&add_unknown_record_type); 134$proxy->start(); | 119$proxy->filter(\&add_unknown_record_type); 120$proxy->start(); |
135ok($fatal_alert, "Unrecognised record type in TLS1.2"); | 121ok(TLSProxy::Message->fail(), "Unrecognised record type in TLS1.2"); |
136 | 122 |
137SKIP: { 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; | 123#Test 11: Sending an unrecognised record type in TLS1.1 should fail 124if (!disabled("tls1_1")) { |
142 $proxy->clear(); 143 $proxy->clientflags("-tls1_1"); 144 $proxy->start(); | 125 $proxy->clear(); 126 $proxy->clientflags("-tls1_1"); 127 $proxy->start(); |
145 ok($fatal_alert, "Unrecognised record type in TLS1.1"); | 128 ok(TLSProxy::Message->fail(), "Unrecognised record type in TLS1.1"); |
146} 147 | 129} 130 |
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(); 154ok($fatal_alert, "Changed record version in TLS1.2"); 155 156#TLS1.3 specific tests 157SKIP: { 158 skip "TLSv1.3 disabled", 6 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 }; 186 187 #Test 16: Sending a ServerHello which doesn't end on a record boundary 188 # should fail 189 $fatal_alert = 0; 190 $proxy->clear(); 191 $boundary_test_type = DATA_AFTER_SERVER_HELLO; 192 $proxy->filter(\¬_on_record_boundary); 193 $proxy->start(); 194 ok($fatal_alert, "Record not on boundary in TLS1.3 (ServerHello)"); 195 196 #Test 17: Sending a Finished which doesn't end on a record boundary 197 # should fail 198 $fatal_alert = 0; 199 $proxy->clear(); 200 $boundary_test_type = DATA_AFTER_FINISHED; 201 $proxy->filter(\¬_on_record_boundary); 202 $proxy->start(); 203 ok($fatal_alert, "Record not on boundary in TLS1.3 (Finished)"); 204 205 #Test 18: Sending a KeyUpdate which doesn't end on a record boundary 206 # should fail 207 $fatal_alert = 0; 208 $proxy->clear(); 209 $boundary_test_type = DATA_AFTER_KEY_UPDATE; 210 $proxy->filter(\¬_on_record_boundary); 211 $proxy->start(); 212 ok($fatal_alert, "Record not on boundary in TLS1.3 (KeyUpdate)"); 213 } 214 215 | |
216sub add_empty_recs_filter 217{ 218 my $proxy = shift; | 131sub add_empty_recs_filter 132{ 133 my $proxy = shift; |
219 my $records = $proxy->record_list; | |
220 221 # We're only interested in the initial ClientHello 222 if ($proxy->flight != 0) { | 134 135 # We're only interested in the initial ClientHello 136 if ($proxy->flight != 0) { |
223 $fatal_alert = 1 if @{$records}[-1]->is_fatal_alert(1) == 10; | |
224 return; 225 } 226 227 for (my $i = 0; $i < $inject_recs_num; $i++) { 228 my $record = TLSProxy::Record->new( 229 0, 230 $content_type, 231 TLSProxy::Record::VERS_TLS_1_2, 232 0, 233 0, 234 0, 235 0, 236 "", 237 "" 238 ); | 137 return; 138 } 139 140 for (my $i = 0; $i < $inject_recs_num; $i++) { 141 my $record = TLSProxy::Record->new( 142 0, 143 $content_type, 144 TLSProxy::Record::VERS_TLS_1_2, 145 0, 146 0, 147 0, 148 0, 149 "", 150 "" 151 ); |
239 push @{$records}, $record; | 152 153 push @{$proxy->record_list}, $record; |
240 } 241} 242 243sub add_frag_alert_filter 244{ 245 my $proxy = shift; | 154 } 155} 156 157sub add_frag_alert_filter 158{ 159 my $proxy = shift; |
246 my $records = $proxy->record_list; | |
247 my $byte; 248 249 # We're only interested in the initial ClientHello 250 if ($proxy->flight != 0) { | 160 my $byte; 161 162 # We're only interested in the initial ClientHello 163 if ($proxy->flight != 0) { |
251 $fatal_alert = 1 if @{$records}[-1]->is_fatal_alert(1) == 10; | |
252 return; 253 } 254 255 # Add a zero length fragment first 256 #my $record = TLSProxy::Record->new( 257 # 0, 258 # TLSProxy::Record::RT_ALERT, 259 # TLSProxy::Record::VERS_TLS_1_2, --- 13 unchanged lines hidden (view full) --- 273 TLSProxy::Record::VERS_TLS_1_2, 274 1, 275 0, 276 1, 277 1, 278 $byte, 279 $byte 280 ); | 164 return; 165 } 166 167 # Add a zero length fragment first 168 #my $record = TLSProxy::Record->new( 169 # 0, 170 # TLSProxy::Record::RT_ALERT, 171 # TLSProxy::Record::VERS_TLS_1_2, --- 13 unchanged lines hidden (view full) --- 185 TLSProxy::Record::VERS_TLS_1_2, 186 1, 187 0, 188 1, 189 1, 190 $byte, 191 $byte 192 ); |
281 push @{$records}, $record; | 193 push @{$proxy->record_list}, $record; |
282 283 # And finally the description (Unexpected message) in a third record 284 $byte = pack('C', TLSProxy::Message::AL_DESC_UNEXPECTED_MESSAGE); 285 $record = TLSProxy::Record->new( 286 0, 287 TLSProxy::Record::RT_ALERT, 288 TLSProxy::Record::VERS_TLS_1_2, 289 1, 290 0, 291 1, 292 1, 293 $byte, 294 $byte 295 ); | 194 195 # And finally the description (Unexpected message) in a third record 196 $byte = pack('C', TLSProxy::Message::AL_DESC_UNEXPECTED_MESSAGE); 197 $record = TLSProxy::Record->new( 198 0, 199 TLSProxy::Record::RT_ALERT, 200 TLSProxy::Record::VERS_TLS_1_2, 201 1, 202 0, 203 1, 204 1, 205 $byte, 206 $byte 207 ); |
296 push @{$records}, $record; | 208 push @{$proxy->record_list}, $record; |
297} 298 299sub add_sslv2_filter 300{ 301 my $proxy = shift; 302 my $clienthello; 303 my $record; 304 --- 136 unchanged lines hidden (view full) --- 441 push @{$proxy->record_list}, $record; 442 } 443 444} 445 446sub add_unknown_record_type 447{ 448 my $proxy = shift; | 209} 210 211sub add_sslv2_filter 212{ 213 my $proxy = shift; 214 my $clienthello; 215 my $record; 216 --- 136 unchanged lines hidden (view full) --- 353 push @{$proxy->record_list}, $record; 354 } 355 356} 357 358sub add_unknown_record_type 359{ 360 my $proxy = shift; |
449 my $records = $proxy->record_list; 450 state $added_record; | |
451 452 # We'll change a record after the initial version neg has taken place | 361 362 # We'll change a record after the initial version neg has taken place |
453 if ($proxy->flight == 0) { 454 $added_record = 0; | 363 if ($proxy->flight != 2) { |
455 return; | 364 return; |
456 } elsif ($proxy->flight != 1 || $added_record) { 457 $fatal_alert = 1 if @{$records}[-1]->is_fatal_alert(0) == 10; 458 return; | |
459 } 460 | 365 } 366 |
367 my $lastrec = ${$proxy->record_list}[-1]; |
|
461 my $record = TLSProxy::Record->new( | 368 my $record = TLSProxy::Record->new( |
462 1, | 369 2, |
463 TLSProxy::Record::RT_UNKNOWN, | 370 TLSProxy::Record::RT_UNKNOWN, |
464 @{$records}[-1]->version(), | 371 $lastrec->version(), |
465 1, 466 0, 467 1, 468 1, 469 "X", 470 "X" 471 ); 472 | 372 1, 373 0, 374 1, 375 1, 376 "X", 377 "X" 378 ); 379 |
473 #Find ServerHello record and insert after that 474 my $i; 475 for ($i = 0; ${$proxy->record_list}[$i]->flight() < 1; $i++) { 476 next; 477 } 478 $i++; 479 480 splice @{$proxy->record_list}, $i, 0, $record; 481 $added_record = 1; | 380 unshift @{$proxy->record_list}, $record; |
482} | 381} |
483 484sub change_version 485{ 486 my $proxy = shift; 487 my $records = $proxy->record_list; 488 489 # We'll change a version after the initial version neg has taken place 490 if ($proxy->flight != 1) { 491 $fatal_alert = 1 if @{$records}[-1]->is_fatal_alert(0) == 70; 492 return; 493 } 494 495 if ($#{$records} > 1) { 496 # ... typically in ServerHelloDone 497 @{$records}[-1]->version(TLSProxy::Record::VERS_TLS_1_1); 498 } 499} 500 501sub change_outer_record_type 502{ 503 my $proxy = shift; 504 my $records = $proxy->record_list; 505 506 # We'll change a record after the initial version neg has taken place 507 if ($proxy->flight != 1) { 508 $fatal_alert = 1 if @{$records}[-1]->is_fatal_alert(0) == 10; 509 return; 510 } 511 512 # Find CCS record and change record after that 513 my $i = 0; 514 foreach my $record (@{$records}) { 515 last if $record->content_type == TLSProxy::Record::RT_CCS; 516 $i++; 517 } 518 if (defined(${$records}[++$i])) { 519 ${$records}[$i]->outer_content_type(TLSProxy::Record::RT_HANDSHAKE); 520 } 521} 522 523sub not_on_record_boundary 524{ 525 my $proxy = shift; 526 my $records = $proxy->record_list; 527 my $data; 528 529 #Find server's first flight 530 if ($proxy->flight != 1) { 531 $fatal_alert = 1 if @{$records}[-1]->is_fatal_alert(0) == 10; 532 return; 533 } 534 535 if ($boundary_test_type == DATA_AFTER_SERVER_HELLO) { 536 #Merge the ServerHello and EncryptedExtensions records into one 537 my $i = 0; 538 foreach my $record (@{$records}) { 539 if ($record->content_type == TLSProxy::Record::RT_HANDSHAKE) { 540 $record->{sent} = 1; # pretend it's sent already 541 last; 542 } 543 $i++; 544 } 545 546 if (defined(${$records}[$i+1])) { 547 $data = ${$records}[$i]->data(); 548 $data .= ${$records}[$i+1]->decrypt_data(); 549 ${$records}[$i+1]->data($data); 550 ${$records}[$i+1]->len(length $data); 551 552 #Delete the old ServerHello record 553 splice @{$records}, $i, 1; 554 } 555 } elsif ($boundary_test_type == DATA_AFTER_FINISHED) { 556 return if @{$proxy->{message_list}}[-1]->{mt} 557 != TLSProxy::Message::MT_FINISHED; 558 559 my $last_record = @{$records}[-1]; 560 $data = $last_record->decrypt_data; 561 562 #Add a KeyUpdate message onto the end of the Finished record 563 my $keyupdate = pack "C5", 564 0x18, # KeyUpdate 565 0x00, 0x00, 0x01, # Message length 566 0x00; # Update not requested 567 568 $data .= $keyupdate; 569 570 #Add content type and tag 571 $data .= pack("C", TLSProxy::Record::RT_HANDSHAKE).("\0"x16); 572 573 #Update the record 574 $last_record->data($data); 575 $last_record->len(length $data); 576 } else { 577 return if @{$proxy->{message_list}}[-1]->{mt} 578 != TLSProxy::Message::MT_FINISHED; 579 580 #KeyUpdates must end on a record boundary 581 582 my $record = TLSProxy::Record->new( 583 1, 584 TLSProxy::Record::RT_APPLICATION_DATA, 585 TLSProxy::Record::VERS_TLS_1_2, 586 0, 587 0, 588 0, 589 0, 590 "", 591 "" 592 ); 593 594 #Add two KeyUpdate messages into a single record 595 my $keyupdate = pack "C5", 596 0x18, # KeyUpdate 597 0x00, 0x00, 0x01, # Message length 598 0x00; # Update not requested 599 600 $data = $keyupdate.$keyupdate; 601 602 #Add content type and tag 603 $data .= pack("C", TLSProxy::Record::RT_HANDSHAKE).("\0"x16); 604 605 $record->data($data); 606 $record->len(length $data); 607 push @{$records}, $record; 608 } 609} | |