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