70-test_sslrecords.t 21 KB

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