]> git.ipfire.org Git - thirdparty/openssl.git/blame - test/recipes/70-test_sslrecords.t
Ignore the record version in TLS1.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";
1f3e70a4
MC
42my $num_tests = 10;
43if (!disabled("tls1_1")) {
44 $num_tests++;
45}
46plan tests => $num_tests;
4f0c4757
MC
47ok(TLSProxy::Message->fail(), "Out of context empty records test");
48
49#Test 2: Injecting in context empty records should succeed
50$proxy->clear();
51$content_type = TLSProxy::Record::RT_HANDSHAKE;
837e591d 52$proxy->serverflags("-tls1_2");
4f0c4757
MC
53$proxy->start();
54ok(TLSProxy::Message->success(), "In context empty records test");
55
56#Test 3: Injecting too many in context empty records should fail
57$proxy->clear();
58#We allow 32 consecutive in context empty records
59$inject_recs_num = 33;
837e591d 60$proxy->serverflags("-tls1_2");
4f0c4757
MC
61$proxy->start();
62ok(TLSProxy::Message->fail(), "Too many in context empty records test");
63
c3fd55d4
MC
64#Test 4: Injecting a fragmented fatal alert should fail. We actually expect no
65# alerts to be sent from either side because *we* injected the fatal
66# alert, i.e. this will look like a disorderly close
67$proxy->clear();
68$proxy->filter(\&add_frag_alert_filter);
837e591d 69$proxy->serverflags("-tls1_2");
c3fd55d4
MC
70$proxy->start();
71ok(!TLSProxy::Message->end(), "Fragmented alert records test");
72
a2a0c86b
MC
73#Run some SSLv2 ClientHello tests
74
75use constant {
76 TLSV1_2_IN_SSLV2 => 0,
77 SSLV2_IN_SSLV2 => 1,
78 FRAGMENTED_IN_TLSV1_2 => 2,
79 FRAGMENTED_IN_SSLV2 => 3,
80 ALERT_BEFORE_SSLV2 => 4
81};
82#Test 5: Inject an SSLv2 style record format for a TLSv1.2 ClientHello
a2a0c86b
MC
83my $sslv2testtype = TLSV1_2_IN_SSLV2;
84$proxy->clear();
85$proxy->filter(\&add_sslv2_filter);
837e591d 86$proxy->serverflags("-tls1_2");
a2a0c86b
MC
87$proxy->start();
88ok(TLSProxy::Message->success(), "TLSv1.2 in SSLv2 ClientHello test");
89
90#Test 6: Inject an SSLv2 style record format for an SSLv2 ClientHello. We don't
91# support this so it should fail. We actually treat it as an unknown
92# protocol so we don't even send an alert in this case.
93$sslv2testtype = SSLV2_IN_SSLV2;
94$proxy->clear();
837e591d 95$proxy->serverflags("-tls1_2");
a2a0c86b
MC
96$proxy->start();
97ok(!TLSProxy::Message->end(), "SSLv2 in SSLv2 ClientHello test");
98
99#Test 7: Sanity check ClientHello fragmentation. This isn't really an SSLv2 test
100# at all, but it gives us confidence that Test 8 fails for the right
101# reasons
102$sslv2testtype = FRAGMENTED_IN_TLSV1_2;
103$proxy->clear();
837e591d 104$proxy->serverflags("-tls1_2");
a2a0c86b
MC
105$proxy->start();
106ok(TLSProxy::Message->success(), "Fragmented ClientHello in TLSv1.2 test");
107
108#Test 8: Fragment a TLSv1.2 ClientHello across a TLS1.2 record; an SSLv2
109# record; and another TLS1.2 record. This isn't allowed so should fail
110$sslv2testtype = FRAGMENTED_IN_SSLV2;
111$proxy->clear();
837e591d 112$proxy->serverflags("-tls1_2");
a2a0c86b
MC
113$proxy->start();
114ok(TLSProxy::Message->fail(), "Fragmented ClientHello in TLSv1.2/SSLv2 test");
115
116#Test 9: Send a TLS warning alert before an SSLv2 ClientHello. This should
117# fail because an SSLv2 ClientHello must be the first record.
118$sslv2testtype = ALERT_BEFORE_SSLV2;
119$proxy->clear();
837e591d 120$proxy->serverflags("-tls1_2");
a2a0c86b
MC
121$proxy->start();
122ok(TLSProxy::Message->fail(), "Alert before SSLv2 ClientHello test");
1f3e70a4
MC
123
124#Unregcognised record type tests
125
126#Test 10: Sending an unrecognised record type in TLS1.2 should fail
127$proxy->clear();
128$proxy->filter(\&add_unknown_record_type);
129$proxy->start();
130ok(TLSProxy::Message->fail(), "Unrecognised record type in TLS1.2");
131
132#Test 11: Sending an unrecognised record type in TLS1.1 should fail
133if (!disabled("tls1_1")) {
134 $proxy->clear();
135 $proxy->clientflags("-tls1_1");
136 $proxy->start();
137 ok(TLSProxy::Message->fail(), "Unrecognised record type in TLS1.1");
138}
139
4f0c4757
MC
140sub add_empty_recs_filter
141{
142 my $proxy = shift;
143
144 # We're only interested in the initial ClientHello
145 if ($proxy->flight != 0) {
146 return;
147 }
148
149 for (my $i = 0; $i < $inject_recs_num; $i++) {
150 my $record = TLSProxy::Record->new(
151 0,
152 $content_type,
153 TLSProxy::Record::VERS_TLS_1_2,
154 0,
155 0,
156 0,
a2a0c86b 157 0,
4f0c4757
MC
158 "",
159 ""
160 );
161
162 push @{$proxy->record_list}, $record;
163 }
164}
c3fd55d4
MC
165
166sub add_frag_alert_filter
167{
168 my $proxy = shift;
169 my $byte;
170
171 # We're only interested in the initial ClientHello
172 if ($proxy->flight != 0) {
173 return;
174 }
175
176 # Add a zero length fragment first
177 #my $record = TLSProxy::Record->new(
178 # 0,
179 # TLSProxy::Record::RT_ALERT,
180 # TLSProxy::Record::VERS_TLS_1_2,
181 # 0,
182 # 0,
183 # 0,
184 # "",
185 # ""
186 #);
187 #push @{$proxy->record_list}, $record;
188
60250017 189 # Now add the alert level (Fatal) as a separate record
c3fd55d4
MC
190 $byte = pack('C', TLSProxy::Message::AL_LEVEL_FATAL);
191 my $record = TLSProxy::Record->new(
192 0,
193 TLSProxy::Record::RT_ALERT,
194 TLSProxy::Record::VERS_TLS_1_2,
195 1,
a2a0c86b 196 0,
c3fd55d4
MC
197 1,
198 1,
199 $byte,
200 $byte
201 );
202 push @{$proxy->record_list}, $record;
203
204 # And finally the description (Unexpected message) in a third record
205 $byte = pack('C', TLSProxy::Message::AL_DESC_UNEXPECTED_MESSAGE);
206 $record = TLSProxy::Record->new(
207 0,
208 TLSProxy::Record::RT_ALERT,
209 TLSProxy::Record::VERS_TLS_1_2,
210 1,
a2a0c86b 211 0,
c3fd55d4
MC
212 1,
213 1,
214 $byte,
215 $byte
216 );
217 push @{$proxy->record_list}, $record;
218}
a2a0c86b
MC
219
220sub add_sslv2_filter
221{
222 my $proxy = shift;
223 my $clienthello;
224 my $record;
225
226 # We're only interested in the initial ClientHello
227 if ($proxy->flight != 0) {
228 return;
229 }
230
231 # Ditch the real ClientHello - we're going to replace it with our own
232 shift @{$proxy->record_list};
233
234 if ($sslv2testtype == ALERT_BEFORE_SSLV2) {
235 my $alert = pack('CC', TLSProxy::Message::AL_LEVEL_FATAL,
236 TLSProxy::Message::AL_DESC_NO_RENEGOTIATION);
237 my $alertlen = length $alert;
238 $record = TLSProxy::Record->new(
239 0,
240 TLSProxy::Record::RT_ALERT,
241 TLSProxy::Record::VERS_TLS_1_2,
242 $alertlen,
243 0,
244 $alertlen,
245 $alertlen,
246 $alert,
247 $alert
248 );
249
250 push @{$proxy->record_list}, $record;
251 }
252
253 if ($sslv2testtype == ALERT_BEFORE_SSLV2
254 || $sslv2testtype == TLSV1_2_IN_SSLV2
255 || $sslv2testtype == SSLV2_IN_SSLV2) {
256 # This is an SSLv2 format ClientHello
257 $clienthello =
258 pack "C44",
259 0x01, # ClientHello
260 0x03, 0x03, #TLSv1.2
261 0x00, 0x03, # Ciphersuites len
262 0x00, 0x00, # Session id len
263 0x00, 0x20, # Challenge len
264 0x00, 0x00, 0x2f, #AES128-SHA
265 0x01, 0x18, 0x9F, 0x76, 0xEC, 0x57, 0xCE, 0xE5, 0xB3, 0xAB, 0x79, 0x90,
266 0xAD, 0xAC, 0x6E, 0xD1, 0x58, 0x35, 0x03, 0x97, 0x16, 0x10, 0x82, 0x56,
267 0xD8, 0x55, 0xFF, 0xE1, 0x8A, 0xA3, 0x2E, 0xF6; # Challenge
268
269 if ($sslv2testtype == SSLV2_IN_SSLV2) {
270 # Set the version to "real" SSLv2
271 vec($clienthello, 1, 8) = 0x00;
272 vec($clienthello, 2, 8) = 0x02;
273 }
274
275 my $chlen = length $clienthello;
276
277 $record = TLSProxy::Record->new(
278 0,
279 TLSProxy::Record::RT_HANDSHAKE,
280 TLSProxy::Record::VERS_TLS_1_2,
281 $chlen,
282 1, #SSLv2
283 $chlen,
284 $chlen,
285 $clienthello,
286 $clienthello
287 );
288
289 push @{$proxy->record_list}, $record;
290 } else {
291 # For this test we're using a real TLS ClientHello
292 $clienthello =
293 pack "C49",
294 0x01, # ClientHello
295 0x00, 0x00, 0x2D, # Message length
296 0x03, 0x03, # TLSv1.2
297 0x01, 0x18, 0x9F, 0x76, 0xEC, 0x57, 0xCE, 0xE5, 0xB3, 0xAB, 0x79, 0x90,
298 0xAD, 0xAC, 0x6E, 0xD1, 0x58, 0x35, 0x03, 0x97, 0x16, 0x10, 0x82, 0x56,
299 0xD8, 0x55, 0xFF, 0xE1, 0x8A, 0xA3, 0x2E, 0xF6, # Random
300 0x00, # Session id len
301 0x00, 0x04, # Ciphersuites len
302 0x00, 0x2f, # AES128-SHA
303 0x00, 0xff, # Empty reneg info SCSV
304 0x01, # Compression methods len
305 0x00, # Null compression
306 0x00, 0x00; # Extensions len
307
308 # Split this into 3: A TLS record; a SSLv2 record and a TLS record.
309 # We deliberately split the second record prior to the Challenge/Random
310 # and set the first byte of the random to 1. This makes the second SSLv2
311 # record look like an SSLv2 ClientHello
312 my $frag1 = substr $clienthello, 0, 6;
313 my $frag2 = substr $clienthello, 6, 32;
314 my $frag3 = substr $clienthello, 38;
315
316 my $fraglen = length $frag1;
317 $record = TLSProxy::Record->new(
318 0,
319 TLSProxy::Record::RT_HANDSHAKE,
320 TLSProxy::Record::VERS_TLS_1_2,
321 $fraglen,
322 0,
323 $fraglen,
324 $fraglen,
325 $frag1,
326 $frag1
327 );
328 push @{$proxy->record_list}, $record;
329
330 $fraglen = length $frag2;
331 my $recvers;
332 if ($sslv2testtype == FRAGMENTED_IN_SSLV2) {
333 $recvers = 1;
334 } else {
335 $recvers = 0;
336 }
337 $record = TLSProxy::Record->new(
338 0,
339 TLSProxy::Record::RT_HANDSHAKE,
340 TLSProxy::Record::VERS_TLS_1_2,
341 $fraglen,
342 $recvers,
343 $fraglen,
344 $fraglen,
345 $frag2,
346 $frag2
347 );
348 push @{$proxy->record_list}, $record;
349
350 $fraglen = length $frag3;
351 $record = TLSProxy::Record->new(
352 0,
353 TLSProxy::Record::RT_HANDSHAKE,
354 TLSProxy::Record::VERS_TLS_1_2,
355 $fraglen,
356 0,
357 $fraglen,
358 $fraglen,
359 $frag3,
360 $frag3
361 );
362 push @{$proxy->record_list}, $record;
363 }
364
365}
1f3e70a4
MC
366
367sub add_unknown_record_type
368{
369 my $proxy = shift;
370
371 # We'll change a record after the initial version neg has taken place
372 if ($proxy->flight != 2) {
373 return;
374 }
375
376 my $lastrec = ${$proxy->record_list}[-1];
377 my $record = TLSProxy::Record->new(
378 2,
379 TLSProxy::Record::RT_UNKNOWN,
380 $lastrec->version(),
381 1,
382 0,
383 1,
384 1,
385 "X",
386 "X"
387 );
388
389 unshift @{$proxy->record_list}, $record;
390}