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