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 31my $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 38my $boundary_test_type; 39my $fatal_alert = 0; # set by filters at expected fatal alerts 40 41#Test 1: Injecting out of context empty records should fail 42my $content_type = TLSProxy::Record::RT_APPLICATION_DATA; 43my $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"; 47plan tests => 20; 48ok($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(); 56ok(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(); 66ok($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(); 77ok($fatal_alert, "Fragmented alert records test"); 78 79#Run some SSLv2 ClientHello tests 80 81use 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 extentions 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 94my $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(); 101ok(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(); 112ok(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(); 123ok(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(); 133ok(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(); 143ok(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(); 154ok($fatal_alert, "Unrecognised record type in TLS1.2"); 155 156SKIP: { 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(); 174ok($fatal_alert, "Changed record version in TLS1.2"); 175 176#TLS1.3 specific tests 177SKIP: { 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(\¬_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 253sub 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 280sub 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 336sub 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 483sub 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 521sub 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 538sub 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 560sub 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} 721