2 # Copyright 2016-2020 The OpenSSL Project Authors. All Rights Reserved.
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
10 ## Test version negotiation
17 use List::Util qw/max min/;
20 use OpenSSL::Test::Utils qw/anydisabled alldisabled disabled/;
21 setup("no_test_here");
23 my @tls_protocols = ("SSLv3", "TLSv1", "TLSv1.1", "TLSv1.2", "TLSv1.3");
24 my @tls_protocols_fips = ("TLSv1.2", "TLSv1.3");
25 # undef stands for "no limit".
26 my @min_tls_protocols = (undef, "SSLv3", "TLSv1", "TLSv1.1", "TLSv1.2", "TLSv1.3");
27 my @min_tls_protocols_fips = (undef, "TLSv1.2", "TLSv1.3");
28 my @max_tls_protocols = ("SSLv3", "TLSv1", "TLSv1.1", "TLSv1.2", "TLSv1.3", undef);
29 my @max_tls_protocols_fips = ("TLSv1.2", "TLSv1.3", undef);
31 my @is_tls_disabled = anydisabled("ssl3", "tls1", "tls1_1", "tls1_2", "tls1_3");
32 my @is_tls_disabled_fips = anydisabled("tls1_2", "tls1_3");
34 my $min_tls_enabled; my $max_tls_enabled;
35 my $min_tls_enabled_fips; my $max_tls_enabled_fips;
37 # Protocol configuration works in cascades, i.e.,
38 # $no_tls1_1 disables TLSv1.1 and below.
40 # $min_enabled and $max_enabled will be correct if there is at least one
43 sub min_prot_enabled {
45 my $disabledref = shift;
46 my @protocols = @{$protref};
47 my @is_disabled = @{$disabledref};
50 foreach my $i (0..$#protocols) {
51 if (!$is_disabled[$i]) {
59 sub max_prot_enabled {
61 my $disabledref = shift;
62 my @protocols = @{$protref};
63 my @is_disabled = @{$disabledref};
66 foreach my $i (0..$#protocols) {
67 if (!$is_disabled[$i]) {
74 $min_tls_enabled = min_prot_enabled(\@tls_protocols, \@is_tls_disabled);
75 $max_tls_enabled = max_prot_enabled(\@tls_protocols, \@is_tls_disabled);
76 $min_tls_enabled_fips = min_prot_enabled(\@tls_protocols_fips, \@is_tls_disabled_fips);
77 $max_tls_enabled_fips = max_prot_enabled(\@tls_protocols_fips, \@is_tls_disabled_fips);
80 my @dtls_protocols = ("DTLSv1", "DTLSv1.2");
81 my @dtls_protocols_fips = ("DTLSv1.2");
82 # undef stands for "no limit".
83 my @min_dtls_protocols = (undef, "DTLSv1", "DTLSv1.2");
84 my @min_dtls_protocols_fips = (undef, "DTLSv1.2");
85 my @max_dtls_protocols = ("DTLSv1", "DTLSv1.2", undef);
86 my @max_dtls_protocols_fips = ("DTLSv1.2", undef);
88 my @is_dtls_disabled = anydisabled("dtls1", "dtls1_2");
89 my @is_dtls_disabled_fips = anydisabled("dtls1_2");
91 my $min_dtls_enabled; my $max_dtls_enabled;
92 my $min_dtls_enabled_fips; my $max_dtls_enabled_fips;
94 # $min_enabled and $max_enabled will be correct if there is at least one
96 $min_dtls_enabled = min_prot_enabled(\@dtls_protocols, \@is_dtls_disabled);
97 $max_dtls_enabled = max_prot_enabled(\@dtls_protocols, \@is_dtls_disabled);
98 $min_dtls_enabled_fips = min_prot_enabled(\@dtls_protocols_fips, \@is_dtls_disabled_fips);
99 $max_dtls_enabled_fips = max_prot_enabled(\@dtls_protocols_fips, \@is_dtls_disabled_fips);
103 return $dtls ? alldisabled("dtls1", "dtls1_2") :
104 alldisabled("ssl3", "tls1", "tls1_1", "tls1_2", "tls1_3");
107 sub generate_version_tests {
111 my $dtls = $method eq "DTLS";
112 # Don't write the redundant "Method = TLS" into the configuration.
113 undef $method if !$dtls;
121 @protocols = $dtls ? @dtls_protocols_fips : @tls_protocols_fips;
122 @min_protocols = $dtls ? @min_dtls_protocols_fips : @min_tls_protocols_fips;
123 @max_protocols = $dtls ? @max_dtls_protocols_fips : @max_tls_protocols_fips;
124 $min_enabled = $dtls ? $min_dtls_enabled_fips : $min_tls_enabled_fips;
125 $max_enabled = $dtls ? $max_dtls_enabled_fips : $max_tls_enabled_fips;
127 @protocols = $dtls ? @dtls_protocols : @tls_protocols;
128 @min_protocols = $dtls ? @min_dtls_protocols : @min_tls_protocols;
129 @max_protocols = $dtls ? @max_dtls_protocols : @max_tls_protocols;
130 $min_enabled = $dtls ? $min_dtls_enabled : $min_tls_enabled;
131 $max_enabled = $dtls ? $max_dtls_enabled : $max_tls_enabled;
134 if (no_tests($dtls)) {
140 for (my $sctp = 0; $sctp < ($dtls && !disabled("sctp") ? 2 : 1); $sctp++) {
141 foreach my $c_min (0..$#min_protocols) {
142 my $c_max_min = $c_min == 0 ? 0 : $c_min - 1;
143 foreach my $c_max ($c_max_min..$#max_protocols) {
144 foreach my $s_min (0..$#min_protocols) {
145 my $s_max_min = $s_min == 0 ? 0 : $s_min - 1;
146 foreach my $s_max ($s_max_min..$#max_protocols) {
147 my ($result, $protocol) =
148 expected_result($c_min, $c_max, $s_min, $s_max,
149 $min_enabled, $max_enabled,
152 "name" => "version-negotiation",
154 "MinProtocol" => $min_protocols[$c_min],
155 "MaxProtocol" => $max_protocols[$c_max],
158 "MinProtocol" => $min_protocols[$s_min],
159 "MaxProtocol" => $max_protocols[$s_max],
162 "ExpectedResult" => $result,
163 "ExpectedProtocol" => $protocol,
167 $tests[-1]{"test"}{"UseSCTP"} = "Yes" if $sctp;
173 return @tests if disabled("tls1_3") || disabled("tls1_2") || $dtls;
175 #Add some version/ciphersuite sanity check tests
177 "name" => "ciphersuite-sanity-check-client",
179 #Offering only <=TLSv1.2 ciphersuites with TLSv1.3 should fail
180 "CipherString" => "AES128-SHA",
181 "Ciphersuites" => "",
184 "MaxProtocol" => "TLSv1.2"
187 "ExpectedResult" => "ClientFail",
191 "name" => "ciphersuite-sanity-check-server",
193 "CipherString" => "AES128-SHA",
194 "MaxProtocol" => "TLSv1.2"
197 #Allowing only <=TLSv1.2 ciphersuites with TLSv1.3 should fail
198 "CipherString" => "AES128-SHA",
199 "Ciphersuites" => "",
202 "ExpectedResult" => "ServerFail",
209 sub generate_resumption_tests {
213 my $dtls = $method eq "DTLS";
214 # Don't write the redundant "Method = TLS" into the configuration.
215 undef $method if !$dtls;
222 @protocols = $dtls ? @dtls_protocols_fips : @tls_protocols_fips;
223 $min_enabled = $dtls ? $min_dtls_enabled_fips : $min_tls_enabled_fips;
224 $max_enabled = $dtls ? $max_dtls_enabled_fips : $max_tls_enabled_fips;
226 @protocols = $dtls ? @dtls_protocols : @tls_protocols;
227 $min_enabled = $dtls ? $min_dtls_enabled : $min_tls_enabled;
228 $max_enabled = $dtls ? $max_dtls_enabled : $max_tls_enabled;
231 if (no_tests($dtls)) {
235 my @server_tests = ();
236 my @client_tests = ();
238 # Obtain the first session against a fixed-version server/client.
239 foreach my $original_protocol($min_enabled..$max_enabled) {
240 # Upgrade or downgrade the server/client max version support and test
241 # that it upgrades, downgrades or resumes the session as well.
242 foreach my $resume_protocol($min_enabled..$max_enabled) {
243 my $resumption_expected;
244 # We should only resume on exact version match.
245 if ($original_protocol eq $resume_protocol) {
246 $resumption_expected = "Yes";
248 $resumption_expected = "No";
251 for (my $sctp = 0; $sctp < ($dtls && !disabled("sctp") ? 2 : 1);
253 foreach my $ticket ("SessionTicket", "-SessionTicket") {
254 # Client is flexible, server upgrades/downgrades.
255 push @server_tests, {
256 "name" => "resumption",
259 "MinProtocol" => $protocols[$original_protocol],
260 "MaxProtocol" => $protocols[$original_protocol],
261 "Options" => $ticket,
264 "MaxProtocol" => $protocols[$resume_protocol],
265 "Options" => $ticket,
268 "ExpectedProtocol" => $protocols[$resume_protocol],
270 "HandshakeMode" => "Resume",
271 "ResumptionExpected" => $resumption_expected,
274 $server_tests[-1]{"test"}{"UseSCTP"} = "Yes" if $sctp;
275 # Server is flexible, client upgrades/downgrades.
276 push @client_tests, {
277 "name" => "resumption",
279 "MinProtocol" => $protocols[$original_protocol],
280 "MaxProtocol" => $protocols[$original_protocol],
283 "Options" => $ticket,
286 "MaxProtocol" => $protocols[$resume_protocol],
289 "ExpectedProtocol" => $protocols[$resume_protocol],
291 "HandshakeMode" => "Resume",
292 "ResumptionExpected" => $resumption_expected,
295 $client_tests[-1]{"test"}{"UseSCTP"} = "Yes" if $sctp;
301 if (!disabled("tls1_3") && !$dtls) {
302 push @client_tests, {
303 "name" => "resumption-with-hrr",
307 "Curves" => disabled("ec") ? "ffdhe3072" : "P-256"
312 "ExpectedProtocol" => "TLSv1.3",
314 "HandshakeMode" => "Resume",
315 "ResumptionExpected" => "Yes",
320 return (@server_tests, @client_tests);
323 sub expected_result {
324 my ($c_min, $c_max, $s_min, $s_max, $min_enabled, $max_enabled,
327 # Adjust for "undef" (no limit).
328 $c_min = $c_min == 0 ? 0 : $c_min - 1;
329 $c_max = $c_max == scalar @$protocols ? $c_max - 1 : $c_max;
330 $s_min = $s_min == 0 ? 0 : $s_min - 1;
331 $s_max = $s_max == scalar @$protocols ? $s_max - 1 : $s_max;
333 # We now have at least one protocol enabled, so $min_enabled and
334 # $max_enabled are well-defined.
335 $c_min = max $c_min, $min_enabled;
336 $s_min = max $s_min, $min_enabled;
337 $c_max = min $c_max, $max_enabled;
338 $s_max = min $s_max, $max_enabled;
340 if ($c_min > $c_max) {
341 # Client should fail to even send a hello.
342 return ("ClientFail", undef);
343 } elsif ($s_min > $s_max) {
344 # Server has no protocols, should always fail.
345 return ("ServerFail", undef);
346 } elsif ($s_min > $c_max) {
347 # Server doesn't support the client range.
348 return ("ServerFail", undef);
349 } elsif ($c_min > $s_max) {
350 my @prots = @$protocols;
351 if ($prots[$c_max] eq "TLSv1.3") {
352 # Client will have sent supported_versions, so server will know
353 # that there are no overlapping versions.
354 return ("ServerFail", undef);
356 # Server will try with a version that is lower than the lowest
357 # supported client version.
358 return ("ClientFail", undef);
361 # Server and client ranges overlap.
362 my $max_common = $s_max < $c_max ? $s_max : $c_max;
363 return ("Success", $protocols->[$max_common]);