]> git.ipfire.org Git - thirdparty/openssl.git/blame - test/recipes/70-test_sslrecords.t
Fix the tests following the state machine changes for TLSv1.3
[thirdparty/openssl.git] / test / recipes / 70-test_sslrecords.t
CommitLineData
4f0c4757
MC
1#! /usr/bin/env perl
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;
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"
18 if $^O =~ /^(VMS|MSWin32)$/;
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
80f397e2
MC
26plan skip_all => "$test_name needs TLSv1.2 enabled"
27 if disabled("tls1_2");
4f0c4757
MC
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
4f0c4757
MC
37#Test 1: Injecting out of context empty records should fail
38my $content_type = TLSProxy::Record::RT_APPLICATION_DATA;
39my $inject_recs_num = 1;
837e591d 40$proxy->serverflags("-tls1_2");
b02b5743 41$proxy->start() or plan skip_all => "Unable to start up Proxy for tests";
8e47ee18 42my $num_tests = 11;
1f3e70a4
MC
43if (!disabled("tls1_1")) {
44 $num_tests++;
45}
8e47ee18
MC
46if (!disabled("tls1_3")) {
47 $num_tests++;
48}
1f3e70a4 49plan tests => $num_tests;
4f0c4757
MC
50ok(TLSProxy::Message->fail(), "Out of context empty records test");
51
52#Test 2: Injecting in context empty records should succeed
53$proxy->clear();
54$content_type = TLSProxy::Record::RT_HANDSHAKE;
837e591d 55$proxy->serverflags("-tls1_2");
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
60$proxy->clear();
61#We allow 32 consecutive in context empty records
62$inject_recs_num = 33;
837e591d 63$proxy->serverflags("-tls1_2");
4f0c4757
MC
64$proxy->start();
65ok(TLSProxy::Message->fail(), "Too many in context empty records test");
66
c3fd55d4
MC
67#Test 4: Injecting a fragmented fatal alert should fail. We actually expect no
68# alerts to be sent from either side because *we* injected the fatal
69# alert, i.e. this will look like a disorderly close
70$proxy->clear();
71$proxy->filter(\&add_frag_alert_filter);
837e591d 72$proxy->serverflags("-tls1_2");
c3fd55d4
MC
73$proxy->start();
74ok(!TLSProxy::Message->end(), "Fragmented alert records test");
75
a2a0c86b
MC
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
a2a0c86b
MC
86my $sslv2testtype = TLSV1_2_IN_SSLV2;
87$proxy->clear();
88$proxy->filter(\&add_sslv2_filter);
837e591d 89$proxy->serverflags("-tls1_2");
a2a0c86b
MC
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();
837e591d 98$proxy->serverflags("-tls1_2");
a2a0c86b
MC
99$proxy->start();
100ok(!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();
837e591d 107$proxy->serverflags("-tls1_2");
a2a0c86b
MC
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();
837e591d 115$proxy->serverflags("-tls1_2");
a2a0c86b
MC
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();
837e591d 123$proxy->serverflags("-tls1_2");
a2a0c86b
MC
124$proxy->start();
125ok(TLSProxy::Message->fail(), "Alert before SSLv2 ClientHello test");
1f3e70a4
MC
126
127#Unregcognised record type tests
128
129#Test 10: Sending an unrecognised record type in TLS1.2 should fail
130$proxy->clear();
9970290e 131$proxy->serverflags("-tls1_2");
1f3e70a4
MC
132$proxy->filter(\&add_unknown_record_type);
133$proxy->start();
134ok(TLSProxy::Message->fail(), "Unrecognised record type in TLS1.2");
135
136#Test 11: Sending an unrecognised record type in TLS1.1 should fail
137if (!disabled("tls1_1")) {
138 $proxy->clear();
139 $proxy->clientflags("-tls1_1");
140 $proxy->start();
141 ok(TLSProxy::Message->fail(), "Unrecognised record type in TLS1.1");
142}
143
8e47ee18
MC
144#Test 12: Sending a different record version in TLS1.2 should fail
145$proxy->clear();
146$proxy->clientflags("-tls1_2");
147$proxy->filter(\&change_version);
148$proxy->start();
149ok(TLSProxy::Message->fail(), "Changed record version in TLS1.2");
150
151#Test 13: Sending a different record version in TLS1.3 should succeed
152if (!disabled("tls1_3")) {
153 $proxy->clear();
154 $proxy->filter(\&change_version);
155 $proxy->start();
156 ok(TLSProxy::Message->success(), "Changed record version in TLS1.3");
157}
158
4f0c4757
MC
159sub add_empty_recs_filter
160{
161 my $proxy = shift;
162
163 # We're only interested in the initial ClientHello
164 if ($proxy->flight != 0) {
165 return;
166 }
167
168 for (my $i = 0; $i < $inject_recs_num; $i++) {
169 my $record = TLSProxy::Record->new(
170 0,
171 $content_type,
172 TLSProxy::Record::VERS_TLS_1_2,
173 0,
174 0,
175 0,
a2a0c86b 176 0,
4f0c4757
MC
177 "",
178 ""
179 );
180
181 push @{$proxy->record_list}, $record;
182 }
183}
c3fd55d4
MC
184
185sub add_frag_alert_filter
186{
187 my $proxy = shift;
188 my $byte;
189
190 # We're only interested in the initial ClientHello
191 if ($proxy->flight != 0) {
192 return;
193 }
194
195 # Add a zero length fragment first
196 #my $record = TLSProxy::Record->new(
197 # 0,
198 # TLSProxy::Record::RT_ALERT,
199 # TLSProxy::Record::VERS_TLS_1_2,
200 # 0,
201 # 0,
202 # 0,
203 # "",
204 # ""
205 #);
206 #push @{$proxy->record_list}, $record;
207
60250017 208 # Now add the alert level (Fatal) as a separate record
c3fd55d4
MC
209 $byte = pack('C', TLSProxy::Message::AL_LEVEL_FATAL);
210 my $record = TLSProxy::Record->new(
211 0,
212 TLSProxy::Record::RT_ALERT,
213 TLSProxy::Record::VERS_TLS_1_2,
214 1,
a2a0c86b 215 0,
c3fd55d4
MC
216 1,
217 1,
218 $byte,
219 $byte
220 );
221 push @{$proxy->record_list}, $record;
222
223 # And finally the description (Unexpected message) in a third record
224 $byte = pack('C', TLSProxy::Message::AL_DESC_UNEXPECTED_MESSAGE);
225 $record = TLSProxy::Record->new(
226 0,
227 TLSProxy::Record::RT_ALERT,
228 TLSProxy::Record::VERS_TLS_1_2,
229 1,
a2a0c86b 230 0,
c3fd55d4
MC
231 1,
232 1,
233 $byte,
234 $byte
235 );
236 push @{$proxy->record_list}, $record;
237}
a2a0c86b
MC
238
239sub add_sslv2_filter
240{
241 my $proxy = shift;
242 my $clienthello;
243 my $record;
244
245 # We're only interested in the initial ClientHello
246 if ($proxy->flight != 0) {
247 return;
248 }
249
250 # Ditch the real ClientHello - we're going to replace it with our own
251 shift @{$proxy->record_list};
252
253 if ($sslv2testtype == ALERT_BEFORE_SSLV2) {
254 my $alert = pack('CC', TLSProxy::Message::AL_LEVEL_FATAL,
255 TLSProxy::Message::AL_DESC_NO_RENEGOTIATION);
256 my $alertlen = length $alert;
257 $record = TLSProxy::Record->new(
258 0,
259 TLSProxy::Record::RT_ALERT,
260 TLSProxy::Record::VERS_TLS_1_2,
261 $alertlen,
262 0,
263 $alertlen,
264 $alertlen,
265 $alert,
266 $alert
267 );
268
269 push @{$proxy->record_list}, $record;
270 }
271
272 if ($sslv2testtype == ALERT_BEFORE_SSLV2
273 || $sslv2testtype == TLSV1_2_IN_SSLV2
274 || $sslv2testtype == SSLV2_IN_SSLV2) {
275 # This is an SSLv2 format ClientHello
276 $clienthello =
277 pack "C44",
278 0x01, # ClientHello
279 0x03, 0x03, #TLSv1.2
280 0x00, 0x03, # Ciphersuites len
281 0x00, 0x00, # Session id len
282 0x00, 0x20, # Challenge len
283 0x00, 0x00, 0x2f, #AES128-SHA
284 0x01, 0x18, 0x9F, 0x76, 0xEC, 0x57, 0xCE, 0xE5, 0xB3, 0xAB, 0x79, 0x90,
285 0xAD, 0xAC, 0x6E, 0xD1, 0x58, 0x35, 0x03, 0x97, 0x16, 0x10, 0x82, 0x56,
286 0xD8, 0x55, 0xFF, 0xE1, 0x8A, 0xA3, 0x2E, 0xF6; # Challenge
287
288 if ($sslv2testtype == SSLV2_IN_SSLV2) {
289 # Set the version to "real" SSLv2
290 vec($clienthello, 1, 8) = 0x00;
291 vec($clienthello, 2, 8) = 0x02;
292 }
293
294 my $chlen = length $clienthello;
295
296 $record = TLSProxy::Record->new(
297 0,
298 TLSProxy::Record::RT_HANDSHAKE,
299 TLSProxy::Record::VERS_TLS_1_2,
300 $chlen,
301 1, #SSLv2
302 $chlen,
303 $chlen,
304 $clienthello,
305 $clienthello
306 );
307
308 push @{$proxy->record_list}, $record;
309 } else {
310 # For this test we're using a real TLS ClientHello
311 $clienthello =
312 pack "C49",
313 0x01, # ClientHello
314 0x00, 0x00, 0x2D, # Message length
315 0x03, 0x03, # TLSv1.2
316 0x01, 0x18, 0x9F, 0x76, 0xEC, 0x57, 0xCE, 0xE5, 0xB3, 0xAB, 0x79, 0x90,
317 0xAD, 0xAC, 0x6E, 0xD1, 0x58, 0x35, 0x03, 0x97, 0x16, 0x10, 0x82, 0x56,
318 0xD8, 0x55, 0xFF, 0xE1, 0x8A, 0xA3, 0x2E, 0xF6, # Random
319 0x00, # Session id len
320 0x00, 0x04, # Ciphersuites len
321 0x00, 0x2f, # AES128-SHA
322 0x00, 0xff, # Empty reneg info SCSV
323 0x01, # Compression methods len
324 0x00, # Null compression
325 0x00, 0x00; # Extensions len
326
327 # Split this into 3: A TLS record; a SSLv2 record and a TLS record.
328 # We deliberately split the second record prior to the Challenge/Random
329 # and set the first byte of the random to 1. This makes the second SSLv2
330 # record look like an SSLv2 ClientHello
331 my $frag1 = substr $clienthello, 0, 6;
332 my $frag2 = substr $clienthello, 6, 32;
333 my $frag3 = substr $clienthello, 38;
334
335 my $fraglen = length $frag1;
336 $record = TLSProxy::Record->new(
337 0,
338 TLSProxy::Record::RT_HANDSHAKE,
339 TLSProxy::Record::VERS_TLS_1_2,
340 $fraglen,
341 0,
342 $fraglen,
343 $fraglen,
344 $frag1,
345 $frag1
346 );
347 push @{$proxy->record_list}, $record;
348
349 $fraglen = length $frag2;
350 my $recvers;
351 if ($sslv2testtype == FRAGMENTED_IN_SSLV2) {
352 $recvers = 1;
353 } else {
354 $recvers = 0;
355 }
356 $record = TLSProxy::Record->new(
357 0,
358 TLSProxy::Record::RT_HANDSHAKE,
359 TLSProxy::Record::VERS_TLS_1_2,
360 $fraglen,
361 $recvers,
362 $fraglen,
363 $fraglen,
364 $frag2,
365 $frag2
366 );
367 push @{$proxy->record_list}, $record;
368
369 $fraglen = length $frag3;
370 $record = TLSProxy::Record->new(
371 0,
372 TLSProxy::Record::RT_HANDSHAKE,
373 TLSProxy::Record::VERS_TLS_1_2,
374 $fraglen,
375 0,
376 $fraglen,
377 $fraglen,
378 $frag3,
379 $frag3
380 );
381 push @{$proxy->record_list}, $record;
382 }
383
384}
1f3e70a4
MC
385
386sub add_unknown_record_type
387{
388 my $proxy = shift;
389
390 # We'll change a record after the initial version neg has taken place
391 if ($proxy->flight != 2) {
392 return;
393 }
394
395 my $lastrec = ${$proxy->record_list}[-1];
396 my $record = TLSProxy::Record->new(
397 2,
398 TLSProxy::Record::RT_UNKNOWN,
399 $lastrec->version(),
400 1,
401 0,
402 1,
403 1,
404 "X",
405 "X"
406 );
407
408 unshift @{$proxy->record_list}, $record;
409}
8e47ee18
MC
410
411sub change_version
412{
413 my $proxy = shift;
414
415 # We'll change a version after the initial version neg has taken place
416 if ($proxy->flight != 2) {
417 return;
418 }
419
420 (${$proxy->record_list}[-1])->version(TLSProxy::Record::VERS_TLS_1_1);
421}