]> git.ipfire.org Git - thirdparty/openssl.git/blame - test/recipes/70-test_sslrecords.t
Update copyright year
[thirdparty/openssl.git] / test / recipes / 70-test_sslrecords.t
CommitLineData
4f0c4757 1#! /usr/bin/env perl
a28d06f3 2# Copyright 2016-2021 The OpenSSL Project Authors. All Rights Reserved.
4f0c4757 3#
909f1a2e 4# Licensed under the Apache License 2.0 (the "License"). You may not use
4f0c4757
MC
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;
c4220c0f
AP
10use feature 'state';
11
4f0c4757
MC
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"
c5856878 20 if $^O =~ /^(VMS)$/;
4f0c4757
MC
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
80f397e2
MC
28plan skip_all => "$test_name needs TLSv1.2 enabled"
29 if disabled("tls1_2");
4f0c4757
MC
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
774c909b 39my $boundary_test_type;
c4220c0f 40my $fatal_alert = 0; # set by filters at expected fatal alerts
774c909b 41
4f0c4757
MC
42#Test 1: Injecting out of context empty records should fail
43my $content_type = TLSProxy::Record::RT_APPLICATION_DATA;
44my $inject_recs_num = 1;
837e591d 45$proxy->serverflags("-tls1_2");
a763ca11 46$proxy->clientflags("-no_tls1_3");
b02b5743 47$proxy->start() or plan skip_all => "Unable to start up Proxy for tests";
73e62d40 48plan tests => 20;
c4220c0f 49ok($fatal_alert, "Out of context empty records test");
4f0c4757
MC
50
51#Test 2: Injecting in context empty records should succeed
52$proxy->clear();
53$content_type = TLSProxy::Record::RT_HANDSHAKE;
837e591d 54$proxy->serverflags("-tls1_2");
a763ca11 55$proxy->clientflags("-no_tls1_3");
4f0c4757
MC
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
c4220c0f 60$fatal_alert = 0;
4f0c4757
MC
61$proxy->clear();
62#We allow 32 consecutive in context empty records
63$inject_recs_num = 33;
837e591d 64$proxy->serverflags("-tls1_2");
a763ca11 65$proxy->clientflags("-no_tls1_3");
4f0c4757 66$proxy->start();
c4220c0f 67ok($fatal_alert, "Too many in context empty records test");
4f0c4757 68
bd990e25
MC
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
c4220c0f 72$fatal_alert = 0;
c3fd55d4
MC
73$proxy->clear();
74$proxy->filter(\&add_frag_alert_filter);
837e591d 75$proxy->serverflags("-tls1_2");
a763ca11 76$proxy->clientflags("-no_tls1_3");
c3fd55d4 77$proxy->start();
c4220c0f 78ok($fatal_alert, "Fragmented alert records test");
c3fd55d4 79
a2a0c86b
MC
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};
aba03ae5
KR
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
a2a0c86b 94#Test 5: Inject an SSLv2 style record format for a TLSv1.2 ClientHello
a2a0c86b
MC
95my $sslv2testtype = TLSV1_2_IN_SSLV2;
96$proxy->clear();
97$proxy->filter(\&add_sslv2_filter);
837e591d 98$proxy->serverflags("-tls1_2");
a763ca11 99$proxy->clientflags("-no_tls1_3");
aba03ae5 100$proxy->ciphers("AES128-SHA:\@SECLEVEL=0");
a2a0c86b
MC
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();
837e591d 109$proxy->serverflags("-tls1_2");
a763ca11 110$proxy->clientflags("-no_tls1_3");
aba03ae5 111$proxy->ciphers("AES128-SHA:\@SECLEVEL=0");
a2a0c86b 112$proxy->start();
0f82d2f5 113ok(TLSProxy::Message->fail(), "SSLv2 in SSLv2 ClientHello test");
a2a0c86b
MC
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();
837e591d 120$proxy->serverflags("-tls1_2");
a763ca11 121$proxy->clientflags("-no_tls1_3");
aba03ae5 122$proxy->ciphers("AES128-SHA:\@SECLEVEL=0");
a2a0c86b
MC
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();
837e591d 130$proxy->serverflags("-tls1_2");
a763ca11 131$proxy->clientflags("-no_tls1_3");
aba03ae5 132$proxy->ciphers("AES128-SHA:\@SECLEVEL=0");
a2a0c86b
MC
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();
837e591d 140$proxy->serverflags("-tls1_2");
a763ca11 141$proxy->clientflags("-no_tls1_3");
aba03ae5 142$proxy->ciphers("AES128-SHA:\@SECLEVEL=0");
a2a0c86b
MC
143$proxy->start();
144ok(TLSProxy::Message->fail(), "Alert before SSLv2 ClientHello test");
1f3e70a4 145
69687aa8 146#Unrecognised record type tests
1f3e70a4
MC
147
148#Test 10: Sending an unrecognised record type in TLS1.2 should fail
c4220c0f 149$fatal_alert = 0;
1f3e70a4 150$proxy->clear();
9970290e 151$proxy->serverflags("-tls1_2");
a763ca11 152$proxy->clientflags("-no_tls1_3");
1f3e70a4
MC
153$proxy->filter(\&add_unknown_record_type);
154$proxy->start();
c4220c0f 155ok($fatal_alert, "Unrecognised record type in TLS1.2");
1f3e70a4 156
774c909b
MC
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
c4220c0f 161 $fatal_alert = 0;
1f3e70a4 162 $proxy->clear();
aba03ae5
KR
163 $proxy->clientflags("-tls1_1 -cipher DEFAULT:\@SECLEVEL=0");
164 $proxy->ciphers("AES128-SHA:\@SECLEVEL=0");
1f3e70a4 165 $proxy->start();
c4220c0f 166 ok($fatal_alert, "Unrecognised record type in TLS1.1");
1f3e70a4
MC
167}
168
8e47ee18 169#Test 12: Sending a different record version in TLS1.2 should fail
c4220c0f 170$fatal_alert = 0;
8e47ee18
MC
171$proxy->clear();
172$proxy->clientflags("-tls1_2");
173$proxy->filter(\&change_version);
174$proxy->start();
c4220c0f 175ok($fatal_alert, "Changed record version in TLS1.2");
8e47ee18 176
b4c6e37e 177#TLS1.3 specific tests
774c909b 178SKIP: {
a763ca11
MC
179 skip "TLSv1.3 disabled", 8
180 if disabled("tls1_3") || (disabled("ec") && disabled("dh"));
774c909b 181
3295d242 182 #Test 13: Sending a different record version in TLS1.3 should fail
8e47ee18
MC
183 $proxy->clear();
184 $proxy->filter(\&change_version);
185 $proxy->start();
3295d242 186 ok(TLSProxy::Message->fail(), "Changed record version in TLS1.3");
b4c6e37e
MC
187
188 #Test 14: Sending an unrecognised record type in TLS1.3 should fail
c4220c0f 189 $fatal_alert = 0;
b4c6e37e
MC
190 $proxy->clear();
191 $proxy->filter(\&add_unknown_record_type);
192 $proxy->start();
c4220c0f 193 ok($fatal_alert, "Unrecognised record type in TLS1.3");
b4c6e37e
MC
194
195 #Test 15: Sending an outer record type other than app data once encrypted
196 #should fail
c4220c0f 197 $fatal_alert = 0;
b4c6e37e
MC
198 $proxy->clear();
199 $proxy->filter(\&change_outer_record_type);
200 $proxy->start();
c4220c0f 201 ok($fatal_alert, "Wrong outer record type in TLS1.3");
774c909b
MC
202
203 use constant {
204 DATA_AFTER_SERVER_HELLO => 0,
205 DATA_AFTER_FINISHED => 1,
73e62d40
MC
206 DATA_AFTER_KEY_UPDATE => 2,
207 DATA_BETWEEN_KEY_UPDATE => 3,
208 NO_DATA_BETWEEN_KEY_UPDATE => 4,
774c909b
MC
209 };
210
211 #Test 16: Sending a ServerHello which doesn't end on a record boundary
212 # should fail
c4220c0f 213 $fatal_alert = 0;
774c909b
MC
214 $proxy->clear();
215 $boundary_test_type = DATA_AFTER_SERVER_HELLO;
216 $proxy->filter(\&not_on_record_boundary);
217 $proxy->start();
c4220c0f 218 ok($fatal_alert, "Record not on boundary in TLS1.3 (ServerHello)");
774c909b
MC
219
220 #Test 17: Sending a Finished which doesn't end on a record boundary
221 # should fail
c4220c0f 222 $fatal_alert = 0;
774c909b
MC
223 $proxy->clear();
224 $boundary_test_type = DATA_AFTER_FINISHED;
774c909b 225 $proxy->start();
c4220c0f 226 ok($fatal_alert, "Record not on boundary in TLS1.3 (Finished)");
774c909b
MC
227
228 #Test 18: Sending a KeyUpdate which doesn't end on a record boundary
229 # should fail
c4220c0f 230 $fatal_alert = 0;
774c909b
MC
231 $proxy->clear();
232 $boundary_test_type = DATA_AFTER_KEY_UPDATE;
774c909b 233 $proxy->start();
c4220c0f 234 ok($fatal_alert, "Record not on boundary in TLS1.3 (KeyUpdate)");
73e62d40
MC
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");
b4c6e37e
MC
251 }
252
8e47ee18 253
4f0c4757
MC
254sub add_empty_recs_filter
255{
256 my $proxy = shift;
c4220c0f 257 my $records = $proxy->record_list;
4f0c4757
MC
258
259 # We're only interested in the initial ClientHello
260 if ($proxy->flight != 0) {
c4220c0f 261 $fatal_alert = 1 if @{$records}[-1]->is_fatal_alert(1) == 10;
4f0c4757
MC
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,
a2a0c86b 273 0,
4f0c4757
MC
274 "",
275 ""
276 );
c4220c0f 277 push @{$records}, $record;
4f0c4757
MC
278 }
279}
c3fd55d4
MC
280
281sub add_frag_alert_filter
282{
283 my $proxy = shift;
c4220c0f 284 my $records = $proxy->record_list;
c3fd55d4
MC
285 my $byte;
286
287 # We're only interested in the initial ClientHello
288 if ($proxy->flight != 0) {
c4220c0f 289 $fatal_alert = 1 if @{$records}[-1]->is_fatal_alert(1) == 10;
c3fd55d4
MC
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
60250017 306 # Now add the alert level (Fatal) as a separate record
c3fd55d4
MC
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,
a2a0c86b 313 0,
c3fd55d4
MC
314 1,
315 1,
316 $byte,
317 $byte
318 );
c4220c0f 319 push @{$records}, $record;
c3fd55d4
MC
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,
a2a0c86b 328 0,
c3fd55d4
MC
329 1,
330 1,
331 $byte,
332 $byte
333 );
c4220c0f 334 push @{$records}, $record;
c3fd55d4 335}
a2a0c86b
MC
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}
1f3e70a4
MC
483
484sub add_unknown_record_type
485{
486 my $proxy = shift;
c4220c0f
AP
487 my $records = $proxy->record_list;
488 state $added_record;
1f3e70a4
MC
489
490 # We'll change a record after the initial version neg has taken place
c4220c0f
AP
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;
1f3e70a4
MC
496 return;
497 }
498
1f3e70a4 499 my $record = TLSProxy::Record->new(
b4c6e37e 500 1,
1f3e70a4 501 TLSProxy::Record::RT_UNKNOWN,
c4220c0f 502 @{$records}[-1]->version(),
1f3e70a4
MC
503 1,
504 0,
505 1,
506 1,
507 "X",
508 "X"
509 );
510
b4c6e37e
MC
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;
c4220c0f 519 $added_record = 1;
1f3e70a4 520}
8e47ee18
MC
521
522sub change_version
523{
524 my $proxy = shift;
c4220c0f 525 my $records = $proxy->record_list;
8e47ee18
MC
526
527 # We'll change a version after the initial version neg has taken place
3295d242 528 if ($proxy->flight != 1) {
c4220c0f 529 $fatal_alert = 1 if @{$records}[-1]->is_fatal_alert(0) == 70;
8e47ee18
MC
530 return;
531 }
532
c4220c0f
AP
533 if ($#{$records} > 1) {
534 # ... typically in ServerHelloDone
535 @{$records}[-1]->version(TLSProxy::Record::VERS_TLS_1_1);
536 }
8e47ee18 537}
b4c6e37e
MC
538
539sub change_outer_record_type
540{
541 my $proxy = shift;
c4220c0f 542 my $records = $proxy->record_list;
b4c6e37e
MC
543
544 # We'll change a record after the initial version neg has taken place
545 if ($proxy->flight != 1) {
c4220c0f 546 $fatal_alert = 1 if @{$records}[-1]->is_fatal_alert(0) == 10;
b4c6e37e
MC
547 return;
548 }
549
c4220c0f
AP
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);
b4c6e37e 558 }
b4c6e37e 559}
774c909b
MC
560
561sub not_on_record_boundary
562{
563 my $proxy = shift;
c4220c0f 564 my $records = $proxy->record_list;
774c909b
MC
565 my $data;
566
567 #Find server's first flight
568 if ($proxy->flight != 1) {
c4220c0f 569 $fatal_alert = 1 if @{$records}[-1]->is_fatal_alert(0) == 10;
774c909b
MC
570 return;
571 }
572
573 if ($boundary_test_type == DATA_AFTER_SERVER_HELLO) {
574 #Merge the ServerHello and EncryptedExtensions records into one
c4220c0f
AP
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++;
774c909b 582 }
774c909b 583
c4220c0f
AP
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 }
774c909b 593 } elsif ($boundary_test_type == DATA_AFTER_FINISHED) {
c4220c0f
AP
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;
774c909b
MC
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
c4220c0f
AP
612 $last_record->data($data);
613 $last_record->len(length $data);
73e62d40 614 } elsif ($boundary_test_type == DATA_AFTER_KEY_UPDATE) {
c4220c0f
AP
615 return if @{$proxy->{message_list}}[-1]->{mt}
616 != TLSProxy::Message::MT_FINISHED;
617
774c909b
MC
618 #KeyUpdates must end on a record boundary
619
620 my $record = TLSProxy::Record->new(
621 1,
622 TLSProxy::Record::RT_APPLICATION_DATA,
c4220c0f 623 TLSProxy::Record::VERS_TLS_1_2,
774c909b
MC
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);
c4220c0f 645 push @{$records}, $record;
73e62d40
MC
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
774c909b
MC
720 }
721}