70-test_sslrecords.t 22 KB

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