Deleted Added
full compact
70-test_sslrecords.t (1.1.1.3) 70-test_sslrecords.t (1.1.1.1)
1#! /usr/bin/env perl
1#! /usr/bin/env perl
2# Copyright 2016-2018 The OpenSSL Project Authors. All Rights Reserved.
2# Copyright 2016 The OpenSSL Project Authors. All Rights Reserved.
3#
4# Licensed under the OpenSSL license (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;
3#
4# Licensed under the OpenSSL license (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"
10use OpenSSL::Test qw/:DEFAULT cmdstr srctop_file bldtop_dir/;
11use OpenSSL::Test::Utils;
12use TLSProxy::Proxy;
13
14my $test_name = "test_sslrecords";
15setup($test_name);
16
17plan skip_all => "TLSProxy isn't usable on $^O"
20 if $^O =~ /^(VMS)$/;
18 if $^O =~ /^(VMS|MSWin32)$/;
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
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
19
20plan skip_all => "$test_name needs the dynamic engine feature enabled"
21 if disabled("engine") || disabled("dynamic-engine");
22
23plan skip_all => "$test_name needs the sock feature enabled"
24 if disabled("sock");
25
26plan skip_all => "$test_name needs TLSv1.2 enabled"
27 if disabled("tls1_2");
28
29$ENV{OPENSSL_ia32cap} = '~0x200000200000000';
30my $proxy = TLSProxy::Proxy->new(
31 \&add_empty_recs_filter,
32 cmdstr(app(["openssl"]), display => 1),
33 srctop_file("apps", "server.pem"),
34 (!$ENV{HARNESS_ACTIVE} || $ENV{HARNESS_VERBOSE})
35);
36
39my $boundary_test_type;
40my $fatal_alert = 0; # set by filters at expected fatal alerts
41
42#Test 1: Injecting out of context empty records should fail
43my $content_type = TLSProxy::Record::RT_APPLICATION_DATA;
44my $inject_recs_num = 1;
37#Test 1: Injecting out of context empty records should fail
38my $content_type = TLSProxy::Record::RT_APPLICATION_DATA;
39my $inject_recs_num = 1;
45$proxy->serverflags("-tls1_2");
46$proxy->start() or plan skip_all => "Unable to start up Proxy for tests";
40$proxy->start() or plan skip_all => "Unable to start up Proxy for tests";
47plan tests => 18;
48ok($fatal_alert, "Out of context empty records test");
41my $num_tests = 10;
42if (!disabled("tls1_1")) {
43 $num_tests++;
44}
45plan tests => $num_tests;
46ok(TLSProxy::Message->fail(), "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;
47
48#Test 2: Injecting in context empty records should succeed
49$proxy->clear();
50$content_type = TLSProxy::Record::RT_HANDSHAKE;
53$proxy->serverflags("-tls1_2");
54$proxy->start();
55ok(TLSProxy::Message->success(), "In context empty records test");
56
57#Test 3: Injecting too many in context empty records should fail
51$proxy->start();
52ok(TLSProxy::Message->success(), "In context empty records test");
53
54#Test 3: Injecting too many in context empty records should fail
58$fatal_alert = 0;
59$proxy->clear();
60#We allow 32 consecutive in context empty records
61$inject_recs_num = 33;
55$proxy->clear();
56#We allow 32 consecutive in context empty records
57$inject_recs_num = 33;
62$proxy->serverflags("-tls1_2");
63$proxy->start();
58$proxy->start();
64ok($fatal_alert, "Too many in context empty records test");
59ok(TLSProxy::Message->fail(), "Too many in context empty records test");
65
60
66#Test 4: Injecting a fragmented fatal alert should fail. We expect the server to
67# send back an alert of its own because it cannot handle fragmented
68# alerts
69$fatal_alert = 0;
61#Test 4: Injecting a fragmented fatal alert should fail. We actually expect no
62# alerts to be sent from either side because *we* injected the fatal
63# alert, i.e. this will look like a disorderly close
70$proxy->clear();
71$proxy->filter(\&add_frag_alert_filter);
64$proxy->clear();
65$proxy->filter(\&add_frag_alert_filter);
72$proxy->serverflags("-tls1_2");
73$proxy->start();
66$proxy->start();
74ok($fatal_alert, "Fragmented alert records test");
67ok(!TLSProxy::Message->end(), "Fragmented alert records test");
75
76#Run some SSLv2 ClientHello tests
77
78use constant {
79 TLSV1_2_IN_SSLV2 => 0,
80 SSLV2_IN_SSLV2 => 1,
81 FRAGMENTED_IN_TLSV1_2 => 2,
82 FRAGMENTED_IN_SSLV2 => 3,
83 ALERT_BEFORE_SSLV2 => 4
84};
85#Test 5: Inject an SSLv2 style record format for a TLSv1.2 ClientHello
86my $sslv2testtype = TLSV1_2_IN_SSLV2;
87$proxy->clear();
88$proxy->filter(\&add_sslv2_filter);
68
69#Run some SSLv2 ClientHello tests
70
71use constant {
72 TLSV1_2_IN_SSLV2 => 0,
73 SSLV2_IN_SSLV2 => 1,
74 FRAGMENTED_IN_TLSV1_2 => 2,
75 FRAGMENTED_IN_SSLV2 => 3,
76 ALERT_BEFORE_SSLV2 => 4
77};
78#Test 5: Inject an SSLv2 style record format for a TLSv1.2 ClientHello
79my $sslv2testtype = TLSV1_2_IN_SSLV2;
80$proxy->clear();
81$proxy->filter(\&add_sslv2_filter);
89$proxy->serverflags("-tls1_2");
90$proxy->start();
91ok(TLSProxy::Message->success(), "TLSv1.2 in SSLv2 ClientHello test");
92
93#Test 6: Inject an SSLv2 style record format for an SSLv2 ClientHello. We don't
94# support this so it should fail. We actually treat it as an unknown
95# protocol so we don't even send an alert in this case.
96$sslv2testtype = SSLV2_IN_SSLV2;
97$proxy->clear();
82$proxy->start();
83ok(TLSProxy::Message->success(), "TLSv1.2 in SSLv2 ClientHello test");
84
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();
98$proxy->serverflags("-tls1_2");
99$proxy->start();
90$proxy->start();
100ok(TLSProxy::Message->fail(), "SSLv2 in SSLv2 ClientHello test");
91ok(!TLSProxy::Message->end(), "SSLv2 in SSLv2 ClientHello test");
101
102#Test 7: Sanity check ClientHello fragmentation. This isn't really an SSLv2 test
103# at all, but it gives us confidence that Test 8 fails for the right
104# reasons
105$sslv2testtype = FRAGMENTED_IN_TLSV1_2;
106$proxy->clear();
92
93#Test 7: Sanity check ClientHello fragmentation. This isn't really an SSLv2 test
94# at all, but it gives us confidence that Test 8 fails for the right
95# reasons
96$sslv2testtype = FRAGMENTED_IN_TLSV1_2;
97$proxy->clear();
107$proxy->serverflags("-tls1_2");
108$proxy->start();
109ok(TLSProxy::Message->success(), "Fragmented ClientHello in TLSv1.2 test");
110
111#Test 8: Fragment a TLSv1.2 ClientHello across a TLS1.2 record; an SSLv2
112# record; and another TLS1.2 record. This isn't allowed so should fail
113$sslv2testtype = FRAGMENTED_IN_SSLV2;
114$proxy->clear();
98$proxy->start();
99ok(TLSProxy::Message->success(), "Fragmented ClientHello in TLSv1.2 test");
100
101#Test 8: Fragment a TLSv1.2 ClientHello across a TLS1.2 record; an SSLv2
102# record; and another TLS1.2 record. This isn't allowed so should fail
103$sslv2testtype = FRAGMENTED_IN_SSLV2;
104$proxy->clear();
115$proxy->serverflags("-tls1_2");
116$proxy->start();
117ok(TLSProxy::Message->fail(), "Fragmented ClientHello in TLSv1.2/SSLv2 test");
118
119#Test 9: Send a TLS warning alert before an SSLv2 ClientHello. This should
120# fail because an SSLv2 ClientHello must be the first record.
121$sslv2testtype = ALERT_BEFORE_SSLV2;
122$proxy->clear();
105$proxy->start();
106ok(TLSProxy::Message->fail(), "Fragmented ClientHello in TLSv1.2/SSLv2 test");
107
108#Test 9: Send a TLS warning alert before an SSLv2 ClientHello. This should
109# fail because an SSLv2 ClientHello must be the first record.
110$sslv2testtype = ALERT_BEFORE_SSLV2;
111$proxy->clear();
123$proxy->serverflags("-tls1_2");
124$proxy->start();
125ok(TLSProxy::Message->fail(), "Alert before SSLv2 ClientHello test");
126
127#Unrecognised record type tests
128
129#Test 10: Sending an unrecognised record type in TLS1.2 should fail
112$proxy->start();
113ok(TLSProxy::Message->fail(), "Alert before SSLv2 ClientHello test");
114
115#Unrecognised record type tests
116
117#Test 10: Sending an unrecognised record type in TLS1.2 should fail
130$fatal_alert = 0;
131$proxy->clear();
118$proxy->clear();
132$proxy->serverflags("-tls1_2");
133$proxy->filter(\&add_unknown_record_type);
134$proxy->start();
119$proxy->filter(\&add_unknown_record_type);
120$proxy->start();
135ok($fatal_alert, "Unrecognised record type in TLS1.2");
121ok(TLSProxy::Message->fail(), "Unrecognised record type in TLS1.2");
136
122
137SKIP: {
138 skip "TLSv1.1 disabled", 1 if disabled("tls1_1");
139
140 #Test 11: Sending an unrecognised record type in TLS1.1 should fail
141 $fatal_alert = 0;
123#Test 11: Sending an unrecognised record type in TLS1.1 should fail
124if (!disabled("tls1_1")) {
142 $proxy->clear();
143 $proxy->clientflags("-tls1_1");
144 $proxy->start();
125 $proxy->clear();
126 $proxy->clientflags("-tls1_1");
127 $proxy->start();
145 ok($fatal_alert, "Unrecognised record type in TLS1.1");
128 ok(TLSProxy::Message->fail(), "Unrecognised record type in TLS1.1");
146}
147
129}
130
148#Test 12: Sending a different record version in TLS1.2 should fail
149$fatal_alert = 0;
150$proxy->clear();
151$proxy->clientflags("-tls1_2");
152$proxy->filter(\&change_version);
153$proxy->start();
154ok($fatal_alert, "Changed record version in TLS1.2");
155
156#TLS1.3 specific tests
157SKIP: {
158 skip "TLSv1.3 disabled", 6 if disabled("tls1_3");
159
160 #Test 13: Sending a different record version in TLS1.3 should fail
161 $proxy->clear();
162 $proxy->filter(\&change_version);
163 $proxy->start();
164 ok(TLSProxy::Message->fail(), "Changed record version in TLS1.3");
165
166 #Test 14: Sending an unrecognised record type in TLS1.3 should fail
167 $fatal_alert = 0;
168 $proxy->clear();
169 $proxy->filter(\&add_unknown_record_type);
170 $proxy->start();
171 ok($fatal_alert, "Unrecognised record type in TLS1.3");
172
173 #Test 15: Sending an outer record type other than app data once encrypted
174 #should fail
175 $fatal_alert = 0;
176 $proxy->clear();
177 $proxy->filter(\&change_outer_record_type);
178 $proxy->start();
179 ok($fatal_alert, "Wrong outer record type in TLS1.3");
180
181 use constant {
182 DATA_AFTER_SERVER_HELLO => 0,
183 DATA_AFTER_FINISHED => 1,
184 DATA_AFTER_KEY_UPDATE => 2
185 };
186
187 #Test 16: Sending a ServerHello which doesn't end on a record boundary
188 # should fail
189 $fatal_alert = 0;
190 $proxy->clear();
191 $boundary_test_type = DATA_AFTER_SERVER_HELLO;
192 $proxy->filter(\&not_on_record_boundary);
193 $proxy->start();
194 ok($fatal_alert, "Record not on boundary in TLS1.3 (ServerHello)");
195
196 #Test 17: Sending a Finished which doesn't end on a record boundary
197 # should fail
198 $fatal_alert = 0;
199 $proxy->clear();
200 $boundary_test_type = DATA_AFTER_FINISHED;
201 $proxy->filter(\&not_on_record_boundary);
202 $proxy->start();
203 ok($fatal_alert, "Record not on boundary in TLS1.3 (Finished)");
204
205 #Test 18: Sending a KeyUpdate which doesn't end on a record boundary
206 # should fail
207 $fatal_alert = 0;
208 $proxy->clear();
209 $boundary_test_type = DATA_AFTER_KEY_UPDATE;
210 $proxy->filter(\&not_on_record_boundary);
211 $proxy->start();
212 ok($fatal_alert, "Record not on boundary in TLS1.3 (KeyUpdate)");
213 }
214
215
216sub add_empty_recs_filter
217{
218 my $proxy = shift;
131sub add_empty_recs_filter
132{
133 my $proxy = shift;
219 my $records = $proxy->record_list;
220
221 # We're only interested in the initial ClientHello
222 if ($proxy->flight != 0) {
134
135 # We're only interested in the initial ClientHello
136 if ($proxy->flight != 0) {
223 $fatal_alert = 1 if @{$records}[-1]->is_fatal_alert(1) == 10;
224 return;
225 }
226
227 for (my $i = 0; $i < $inject_recs_num; $i++) {
228 my $record = TLSProxy::Record->new(
229 0,
230 $content_type,
231 TLSProxy::Record::VERS_TLS_1_2,
232 0,
233 0,
234 0,
235 0,
236 "",
237 ""
238 );
137 return;
138 }
139
140 for (my $i = 0; $i < $inject_recs_num; $i++) {
141 my $record = TLSProxy::Record->new(
142 0,
143 $content_type,
144 TLSProxy::Record::VERS_TLS_1_2,
145 0,
146 0,
147 0,
148 0,
149 "",
150 ""
151 );
239 push @{$records}, $record;
152
153 push @{$proxy->record_list}, $record;
240 }
241}
242
243sub add_frag_alert_filter
244{
245 my $proxy = shift;
154 }
155}
156
157sub add_frag_alert_filter
158{
159 my $proxy = shift;
246 my $records = $proxy->record_list;
247 my $byte;
248
249 # We're only interested in the initial ClientHello
250 if ($proxy->flight != 0) {
160 my $byte;
161
162 # We're only interested in the initial ClientHello
163 if ($proxy->flight != 0) {
251 $fatal_alert = 1 if @{$records}[-1]->is_fatal_alert(1) == 10;
252 return;
253 }
254
255 # Add a zero length fragment first
256 #my $record = TLSProxy::Record->new(
257 # 0,
258 # TLSProxy::Record::RT_ALERT,
259 # TLSProxy::Record::VERS_TLS_1_2,

--- 13 unchanged lines hidden (view full) ---

273 TLSProxy::Record::VERS_TLS_1_2,
274 1,
275 0,
276 1,
277 1,
278 $byte,
279 $byte
280 );
164 return;
165 }
166
167 # Add a zero length fragment first
168 #my $record = TLSProxy::Record->new(
169 # 0,
170 # TLSProxy::Record::RT_ALERT,
171 # TLSProxy::Record::VERS_TLS_1_2,

--- 13 unchanged lines hidden (view full) ---

185 TLSProxy::Record::VERS_TLS_1_2,
186 1,
187 0,
188 1,
189 1,
190 $byte,
191 $byte
192 );
281 push @{$records}, $record;
193 push @{$proxy->record_list}, $record;
282
283 # And finally the description (Unexpected message) in a third record
284 $byte = pack('C', TLSProxy::Message::AL_DESC_UNEXPECTED_MESSAGE);
285 $record = TLSProxy::Record->new(
286 0,
287 TLSProxy::Record::RT_ALERT,
288 TLSProxy::Record::VERS_TLS_1_2,
289 1,
290 0,
291 1,
292 1,
293 $byte,
294 $byte
295 );
194
195 # And finally the description (Unexpected message) in a third record
196 $byte = pack('C', TLSProxy::Message::AL_DESC_UNEXPECTED_MESSAGE);
197 $record = TLSProxy::Record->new(
198 0,
199 TLSProxy::Record::RT_ALERT,
200 TLSProxy::Record::VERS_TLS_1_2,
201 1,
202 0,
203 1,
204 1,
205 $byte,
206 $byte
207 );
296 push @{$records}, $record;
208 push @{$proxy->record_list}, $record;
297}
298
299sub add_sslv2_filter
300{
301 my $proxy = shift;
302 my $clienthello;
303 my $record;
304

--- 136 unchanged lines hidden (view full) ---

441 push @{$proxy->record_list}, $record;
442 }
443
444}
445
446sub add_unknown_record_type
447{
448 my $proxy = shift;
209}
210
211sub add_sslv2_filter
212{
213 my $proxy = shift;
214 my $clienthello;
215 my $record;
216

--- 136 unchanged lines hidden (view full) ---

353 push @{$proxy->record_list}, $record;
354 }
355
356}
357
358sub add_unknown_record_type
359{
360 my $proxy = shift;
449 my $records = $proxy->record_list;
450 state $added_record;
451
452 # We'll change a record after the initial version neg has taken place
361
362 # We'll change a record after the initial version neg has taken place
453 if ($proxy->flight == 0) {
454 $added_record = 0;
363 if ($proxy->flight != 2) {
455 return;
364 return;
456 } elsif ($proxy->flight != 1 || $added_record) {
457 $fatal_alert = 1 if @{$records}[-1]->is_fatal_alert(0) == 10;
458 return;
459 }
460
365 }
366
367 my $lastrec = ${$proxy->record_list}[-1];
461 my $record = TLSProxy::Record->new(
368 my $record = TLSProxy::Record->new(
462 1,
369 2,
463 TLSProxy::Record::RT_UNKNOWN,
370 TLSProxy::Record::RT_UNKNOWN,
464 @{$records}[-1]->version(),
371 $lastrec->version(),
465 1,
466 0,
467 1,
468 1,
469 "X",
470 "X"
471 );
472
372 1,
373 0,
374 1,
375 1,
376 "X",
377 "X"
378 );
379
473 #Find ServerHello record and insert after that
474 my $i;
475 for ($i = 0; ${$proxy->record_list}[$i]->flight() < 1; $i++) {
476 next;
477 }
478 $i++;
479
480 splice @{$proxy->record_list}, $i, 0, $record;
481 $added_record = 1;
380 unshift @{$proxy->record_list}, $record;
482}
381}
483
484sub change_version
485{
486 my $proxy = shift;
487 my $records = $proxy->record_list;
488
489 # We'll change a version after the initial version neg has taken place
490 if ($proxy->flight != 1) {
491 $fatal_alert = 1 if @{$records}[-1]->is_fatal_alert(0) == 70;
492 return;
493 }
494
495 if ($#{$records} > 1) {
496 # ... typically in ServerHelloDone
497 @{$records}[-1]->version(TLSProxy::Record::VERS_TLS_1_1);
498 }
499}
500
501sub change_outer_record_type
502{
503 my $proxy = shift;
504 my $records = $proxy->record_list;
505
506 # We'll change a record after the initial version neg has taken place
507 if ($proxy->flight != 1) {
508 $fatal_alert = 1 if @{$records}[-1]->is_fatal_alert(0) == 10;
509 return;
510 }
511
512 # Find CCS record and change record after that
513 my $i = 0;
514 foreach my $record (@{$records}) {
515 last if $record->content_type == TLSProxy::Record::RT_CCS;
516 $i++;
517 }
518 if (defined(${$records}[++$i])) {
519 ${$records}[$i]->outer_content_type(TLSProxy::Record::RT_HANDSHAKE);
520 }
521}
522
523sub not_on_record_boundary
524{
525 my $proxy = shift;
526 my $records = $proxy->record_list;
527 my $data;
528
529 #Find server's first flight
530 if ($proxy->flight != 1) {
531 $fatal_alert = 1 if @{$records}[-1]->is_fatal_alert(0) == 10;
532 return;
533 }
534
535 if ($boundary_test_type == DATA_AFTER_SERVER_HELLO) {
536 #Merge the ServerHello and EncryptedExtensions records into one
537 my $i = 0;
538 foreach my $record (@{$records}) {
539 if ($record->content_type == TLSProxy::Record::RT_HANDSHAKE) {
540 $record->{sent} = 1; # pretend it's sent already
541 last;
542 }
543 $i++;
544 }
545
546 if (defined(${$records}[$i+1])) {
547 $data = ${$records}[$i]->data();
548 $data .= ${$records}[$i+1]->decrypt_data();
549 ${$records}[$i+1]->data($data);
550 ${$records}[$i+1]->len(length $data);
551
552 #Delete the old ServerHello record
553 splice @{$records}, $i, 1;
554 }
555 } elsif ($boundary_test_type == DATA_AFTER_FINISHED) {
556 return if @{$proxy->{message_list}}[-1]->{mt}
557 != TLSProxy::Message::MT_FINISHED;
558
559 my $last_record = @{$records}[-1];
560 $data = $last_record->decrypt_data;
561
562 #Add a KeyUpdate message onto the end of the Finished record
563 my $keyupdate = pack "C5",
564 0x18, # KeyUpdate
565 0x00, 0x00, 0x01, # Message length
566 0x00; # Update not requested
567
568 $data .= $keyupdate;
569
570 #Add content type and tag
571 $data .= pack("C", TLSProxy::Record::RT_HANDSHAKE).("\0"x16);
572
573 #Update the record
574 $last_record->data($data);
575 $last_record->len(length $data);
576 } else {
577 return if @{$proxy->{message_list}}[-1]->{mt}
578 != TLSProxy::Message::MT_FINISHED;
579
580 #KeyUpdates must end on a record boundary
581
582 my $record = TLSProxy::Record->new(
583 1,
584 TLSProxy::Record::RT_APPLICATION_DATA,
585 TLSProxy::Record::VERS_TLS_1_2,
586 0,
587 0,
588 0,
589 0,
590 "",
591 ""
592 );
593
594 #Add two KeyUpdate messages into a single record
595 my $keyupdate = pack "C5",
596 0x18, # KeyUpdate
597 0x00, 0x00, 0x01, # Message length
598 0x00; # Update not requested
599
600 $data = $keyupdate.$keyupdate;
601
602 #Add content type and tag
603 $data .= pack("C", TLSProxy::Record::RT_HANDSHAKE).("\0"x16);
604
605 $record->data($data);
606 $record->len(length $data);
607 push @{$records}, $record;
608 }
609}