1*e0c4386eSCy Schubert# -*- mode: perl; -*-
2*e0c4386eSCy Schubert# Copyright 2016-2021 The OpenSSL Project Authors. All Rights Reserved.
3*e0c4386eSCy Schubert#
4*e0c4386eSCy Schubert# Licensed under the Apache License 2.0 (the "License").  You may not use
5*e0c4386eSCy Schubert# this file except in compliance with the License.  You can obtain a copy
6*e0c4386eSCy Schubert# in the file LICENSE in the source distribution or at
7*e0c4386eSCy Schubert# https://www.openssl.org/source/license.html
8*e0c4386eSCy Schubert
9*e0c4386eSCy Schubert
10*e0c4386eSCy Schubert## Test version negotiation
11*e0c4386eSCy Schubert
12*e0c4386eSCy Schubertpackage ssltests;
13*e0c4386eSCy Schubert
14*e0c4386eSCy Schubertuse strict;
15*e0c4386eSCy Schubertuse warnings;
16*e0c4386eSCy Schubert
17*e0c4386eSCy Schubertuse List::Util qw/max min/;
18*e0c4386eSCy Schubert
19*e0c4386eSCy Schubertuse OpenSSL::Test;
20*e0c4386eSCy Schubertuse OpenSSL::Test::Utils qw/anydisabled alldisabled disabled/;
21*e0c4386eSCy Schubertsetup("no_test_here");
22*e0c4386eSCy Schubert
23*e0c4386eSCy Schubertmy @tls_protocols = ("SSLv3", "TLSv1", "TLSv1.1", "TLSv1.2", "TLSv1.3");
24*e0c4386eSCy Schubertmy @tls_protocols_fips = ("TLSv1.2", "TLSv1.3");
25*e0c4386eSCy Schubert# undef stands for "no limit".
26*e0c4386eSCy Schubertmy @min_tls_protocols = (undef, "SSLv3", "TLSv1", "TLSv1.1", "TLSv1.2", "TLSv1.3");
27*e0c4386eSCy Schubertmy @min_tls_protocols_fips = (undef, "TLSv1.2", "TLSv1.3");
28*e0c4386eSCy Schubertmy @max_tls_protocols = ("SSLv3", "TLSv1", "TLSv1.1", "TLSv1.2", "TLSv1.3", undef);
29*e0c4386eSCy Schubertmy @max_tls_protocols_fips = ("TLSv1.2", "TLSv1.3", undef);
30*e0c4386eSCy Schubert
31*e0c4386eSCy Schubertmy @is_tls_disabled = anydisabled("ssl3", "tls1", "tls1_1", "tls1_2", "tls1_3");
32*e0c4386eSCy Schubertmy @is_tls_disabled_fips = anydisabled("tls1_2", "tls1_3");
33*e0c4386eSCy Schubert
34*e0c4386eSCy Schubertmy $min_tls_enabled; my $max_tls_enabled;
35*e0c4386eSCy Schubertmy $min_tls_enabled_fips; my $max_tls_enabled_fips;
36*e0c4386eSCy Schubert
37*e0c4386eSCy Schubert# Protocol configuration works in cascades, i.e.,
38*e0c4386eSCy Schubert# $no_tls1_1 disables TLSv1.1 and below.
39*e0c4386eSCy Schubert#
40*e0c4386eSCy Schubert# $min_enabled and $max_enabled will be correct if there is at least one
41*e0c4386eSCy Schubert# protocol enabled.
42*e0c4386eSCy Schubert
43*e0c4386eSCy Schubertsub min_prot_enabled {
44*e0c4386eSCy Schubert    my $protref = shift;
45*e0c4386eSCy Schubert    my $disabledref = shift;
46*e0c4386eSCy Schubert    my @protocols = @{$protref};
47*e0c4386eSCy Schubert    my @is_disabled = @{$disabledref};
48*e0c4386eSCy Schubert    my $min_enabled;
49*e0c4386eSCy Schubert
50*e0c4386eSCy Schubert    foreach my $i (0..$#protocols) {
51*e0c4386eSCy Schubert        if (!$is_disabled[$i]) {
52*e0c4386eSCy Schubert            $min_enabled = $i;
53*e0c4386eSCy Schubert            last;
54*e0c4386eSCy Schubert        }
55*e0c4386eSCy Schubert    }
56*e0c4386eSCy Schubert    return $min_enabled;
57*e0c4386eSCy Schubert}
58*e0c4386eSCy Schubert
59*e0c4386eSCy Schubertsub max_prot_enabled {
60*e0c4386eSCy Schubert    my $protref = shift;
61*e0c4386eSCy Schubert    my $disabledref = shift;
62*e0c4386eSCy Schubert    my @protocols = @{$protref};
63*e0c4386eSCy Schubert    my @is_disabled = @{$disabledref};
64*e0c4386eSCy Schubert    my $max_enabled;
65*e0c4386eSCy Schubert
66*e0c4386eSCy Schubert    foreach my $i (0..$#protocols) {
67*e0c4386eSCy Schubert        if (!$is_disabled[$i]
68*e0c4386eSCy Schubert                && ($protocols[$i] ne "TLSv1.3"
69*e0c4386eSCy Schubert                    || !disabled("ec")
70*e0c4386eSCy Schubert                    || !disabled("dh"))) {
71*e0c4386eSCy Schubert            $max_enabled = $i;
72*e0c4386eSCy Schubert        }
73*e0c4386eSCy Schubert    }
74*e0c4386eSCy Schubert    return $max_enabled;
75*e0c4386eSCy Schubert}
76*e0c4386eSCy Schubert
77*e0c4386eSCy Schubert$min_tls_enabled = min_prot_enabled(\@tls_protocols, \@is_tls_disabled);
78*e0c4386eSCy Schubert$max_tls_enabled = max_prot_enabled(\@tls_protocols, \@is_tls_disabled);
79*e0c4386eSCy Schubert$min_tls_enabled_fips = min_prot_enabled(\@tls_protocols_fips, \@is_tls_disabled_fips);
80*e0c4386eSCy Schubert$max_tls_enabled_fips = max_prot_enabled(\@tls_protocols_fips, \@is_tls_disabled_fips);
81*e0c4386eSCy Schubert
82*e0c4386eSCy Schubert
83*e0c4386eSCy Schubertmy @dtls_protocols = ("DTLSv1", "DTLSv1.2");
84*e0c4386eSCy Schubertmy @dtls_protocols_fips = ("DTLSv1.2");
85*e0c4386eSCy Schubert# undef stands for "no limit".
86*e0c4386eSCy Schubertmy @min_dtls_protocols = (undef, "DTLSv1", "DTLSv1.2");
87*e0c4386eSCy Schubertmy @min_dtls_protocols_fips = (undef, "DTLSv1.2");
88*e0c4386eSCy Schubertmy @max_dtls_protocols = ("DTLSv1", "DTLSv1.2", undef);
89*e0c4386eSCy Schubertmy @max_dtls_protocols_fips = ("DTLSv1.2", undef);
90*e0c4386eSCy Schubert
91*e0c4386eSCy Schubertmy @is_dtls_disabled = anydisabled("dtls1", "dtls1_2");
92*e0c4386eSCy Schubertmy @is_dtls_disabled_fips = anydisabled("dtls1_2");
93*e0c4386eSCy Schubert
94*e0c4386eSCy Schubertmy $min_dtls_enabled; my $max_dtls_enabled;
95*e0c4386eSCy Schubertmy $min_dtls_enabled_fips; my $max_dtls_enabled_fips;
96*e0c4386eSCy Schubert
97*e0c4386eSCy Schubert# $min_enabled and $max_enabled will be correct if there is at least one
98*e0c4386eSCy Schubert# protocol enabled.
99*e0c4386eSCy Schubert$min_dtls_enabled = min_prot_enabled(\@dtls_protocols, \@is_dtls_disabled);
100*e0c4386eSCy Schubert$max_dtls_enabled = max_prot_enabled(\@dtls_protocols, \@is_dtls_disabled);
101*e0c4386eSCy Schubert$min_dtls_enabled_fips = min_prot_enabled(\@dtls_protocols_fips, \@is_dtls_disabled_fips);
102*e0c4386eSCy Schubert$max_dtls_enabled_fips = max_prot_enabled(\@dtls_protocols_fips, \@is_dtls_disabled_fips);
103*e0c4386eSCy Schubert
104*e0c4386eSCy Schubertsub no_tests {
105*e0c4386eSCy Schubert    my ($dtls, $fips) = @_;
106*e0c4386eSCy Schubert    if ($dtls && $fips) {
107*e0c4386eSCy Schubert        return disabled("dtls1_2");
108*e0c4386eSCy Schubert    }
109*e0c4386eSCy Schubert    return $dtls ? alldisabled("dtls1", "dtls1_2") :
110*e0c4386eSCy Schubert      alldisabled("ssl3", "tls1", "tls1_1", "tls1_2", "tls1_3");
111*e0c4386eSCy Schubert}
112*e0c4386eSCy Schubert
113*e0c4386eSCy Schubertsub generate_version_tests {
114*e0c4386eSCy Schubert    my $method = shift;
115*e0c4386eSCy Schubert    my $fips = shift;
116*e0c4386eSCy Schubert
117*e0c4386eSCy Schubert    my $dtls = $method eq "DTLS";
118*e0c4386eSCy Schubert    # Don't write the redundant "Method = TLS" into the configuration.
119*e0c4386eSCy Schubert    undef $method if !$dtls;
120*e0c4386eSCy Schubert
121*e0c4386eSCy Schubert    my @protocols;
122*e0c4386eSCy Schubert    my @min_protocols;
123*e0c4386eSCy Schubert    my @max_protocols;
124*e0c4386eSCy Schubert    my $min_enabled;
125*e0c4386eSCy Schubert    my $max_enabled;
126*e0c4386eSCy Schubert    if ($fips) {
127*e0c4386eSCy Schubert        @protocols = $dtls ? @dtls_protocols_fips : @tls_protocols_fips;
128*e0c4386eSCy Schubert        @min_protocols = $dtls ? @min_dtls_protocols_fips : @min_tls_protocols_fips;
129*e0c4386eSCy Schubert        @max_protocols = $dtls ? @max_dtls_protocols_fips : @max_tls_protocols_fips;
130*e0c4386eSCy Schubert        $min_enabled  = $dtls ? $min_dtls_enabled_fips : $min_tls_enabled_fips;
131*e0c4386eSCy Schubert        $max_enabled  = $dtls ? $max_dtls_enabled_fips : $max_tls_enabled_fips;
132*e0c4386eSCy Schubert    } else {
133*e0c4386eSCy Schubert        @protocols = $dtls ? @dtls_protocols : @tls_protocols;
134*e0c4386eSCy Schubert        @min_protocols = $dtls ? @min_dtls_protocols : @min_tls_protocols;
135*e0c4386eSCy Schubert        @max_protocols = $dtls ? @max_dtls_protocols : @max_tls_protocols;
136*e0c4386eSCy Schubert        $min_enabled  = $dtls ? $min_dtls_enabled : $min_tls_enabled;
137*e0c4386eSCy Schubert        $max_enabled  = $dtls ? $max_dtls_enabled : $max_tls_enabled;
138*e0c4386eSCy Schubert    }
139*e0c4386eSCy Schubert
140*e0c4386eSCy Schubert    if (no_tests($dtls, $fips)) {
141*e0c4386eSCy Schubert        return;
142*e0c4386eSCy Schubert    }
143*e0c4386eSCy Schubert
144*e0c4386eSCy Schubert    my @tests = ();
145*e0c4386eSCy Schubert
146*e0c4386eSCy Schubert    for (my $sctp = 0; $sctp < ($dtls && !disabled("sctp") ? 2 : 1); $sctp++) {
147*e0c4386eSCy Schubert        foreach my $c_min (0..$#min_protocols) {
148*e0c4386eSCy Schubert            my $c_max_min = $c_min == 0 ? 0 : $c_min - 1;
149*e0c4386eSCy Schubert            foreach my $c_max ($c_max_min..$#max_protocols) {
150*e0c4386eSCy Schubert                foreach my $s_min (0..$#min_protocols) {
151*e0c4386eSCy Schubert                    my $s_max_min = $s_min == 0 ? 0 : $s_min - 1;
152*e0c4386eSCy Schubert                    foreach my $s_max ($s_max_min..$#max_protocols) {
153*e0c4386eSCy Schubert                        my ($result, $protocol) =
154*e0c4386eSCy Schubert                            expected_result($c_min, $c_max, $s_min, $s_max,
155*e0c4386eSCy Schubert                                            $min_enabled, $max_enabled,
156*e0c4386eSCy Schubert                                            \@protocols);
157*e0c4386eSCy Schubert                        push @tests, {
158*e0c4386eSCy Schubert                            "name" => "version-negotiation",
159*e0c4386eSCy Schubert                            "client" => {
160*e0c4386eSCy Schubert                                "CipherString" => "DEFAULT:\@SECLEVEL=0",
161*e0c4386eSCy Schubert                                "MinProtocol" => $min_protocols[$c_min],
162*e0c4386eSCy Schubert                                "MaxProtocol" => $max_protocols[$c_max],
163*e0c4386eSCy Schubert                            },
164*e0c4386eSCy Schubert                            "server" => {
165*e0c4386eSCy Schubert                                "CipherString" => "DEFAULT:\@SECLEVEL=0",
166*e0c4386eSCy Schubert                                "MinProtocol" => $min_protocols[$s_min],
167*e0c4386eSCy Schubert                                "MaxProtocol" => $max_protocols[$s_max],
168*e0c4386eSCy Schubert                            },
169*e0c4386eSCy Schubert                            "test" => {
170*e0c4386eSCy Schubert                                "ExpectedResult" => $result,
171*e0c4386eSCy Schubert                                "ExpectedProtocol" => $protocol,
172*e0c4386eSCy Schubert                                "Method" => $method,
173*e0c4386eSCy Schubert                            }
174*e0c4386eSCy Schubert                        };
175*e0c4386eSCy Schubert                        $tests[-1]{"test"}{"UseSCTP"} = "Yes" if $sctp;
176*e0c4386eSCy Schubert                    }
177*e0c4386eSCy Schubert                }
178*e0c4386eSCy Schubert            }
179*e0c4386eSCy Schubert        }
180*e0c4386eSCy Schubert    }
181*e0c4386eSCy Schubert    return @tests
182*e0c4386eSCy Schubert        if disabled("tls1_3")
183*e0c4386eSCy Schubert           || disabled("tls1_2")
184*e0c4386eSCy Schubert           || (disabled("ec") && disabled("dh"))
185*e0c4386eSCy Schubert           || $dtls;
186*e0c4386eSCy Schubert
187*e0c4386eSCy Schubert    #Add some version/ciphersuite sanity check tests
188*e0c4386eSCy Schubert    push @tests, {
189*e0c4386eSCy Schubert        "name" => "ciphersuite-sanity-check-client",
190*e0c4386eSCy Schubert        "client" => {
191*e0c4386eSCy Schubert            #Offering only <=TLSv1.2 ciphersuites with TLSv1.3 should fail
192*e0c4386eSCy Schubert            "CipherString" => "AES128-SHA",
193*e0c4386eSCy Schubert            "Ciphersuites" => "",
194*e0c4386eSCy Schubert        },
195*e0c4386eSCy Schubert        "server" => {
196*e0c4386eSCy Schubert            "MaxProtocol" => "TLSv1.2"
197*e0c4386eSCy Schubert        },
198*e0c4386eSCy Schubert        "test" => {
199*e0c4386eSCy Schubert            "ExpectedResult" => "ClientFail",
200*e0c4386eSCy Schubert        }
201*e0c4386eSCy Schubert    };
202*e0c4386eSCy Schubert    push @tests, {
203*e0c4386eSCy Schubert        "name" => "ciphersuite-sanity-check-server",
204*e0c4386eSCy Schubert        "client" => {
205*e0c4386eSCy Schubert            "CipherString" => "AES128-SHA",
206*e0c4386eSCy Schubert            "MaxProtocol" => "TLSv1.2"
207*e0c4386eSCy Schubert        },
208*e0c4386eSCy Schubert        "server" => {
209*e0c4386eSCy Schubert            #Allowing only <=TLSv1.2 ciphersuites with TLSv1.3 should fail
210*e0c4386eSCy Schubert            "CipherString" => "AES128-SHA",
211*e0c4386eSCy Schubert            "Ciphersuites" => "",
212*e0c4386eSCy Schubert        },
213*e0c4386eSCy Schubert        "test" => {
214*e0c4386eSCy Schubert            "ExpectedResult" => "ServerFail",
215*e0c4386eSCy Schubert        }
216*e0c4386eSCy Schubert    };
217*e0c4386eSCy Schubert
218*e0c4386eSCy Schubert    return @tests;
219*e0c4386eSCy Schubert}
220*e0c4386eSCy Schubert
221*e0c4386eSCy Schubertsub generate_resumption_tests {
222*e0c4386eSCy Schubert    my $method = shift;
223*e0c4386eSCy Schubert    my $fips = shift;
224*e0c4386eSCy Schubert
225*e0c4386eSCy Schubert    my $dtls = $method eq "DTLS";
226*e0c4386eSCy Schubert    # Don't write the redundant "Method = TLS" into the configuration.
227*e0c4386eSCy Schubert    undef $method if !$dtls;
228*e0c4386eSCy Schubert
229*e0c4386eSCy Schubert    my @protocols;
230*e0c4386eSCy Schubert    my $min_enabled;
231*e0c4386eSCy Schubert    my $max_enabled;
232*e0c4386eSCy Schubert
233*e0c4386eSCy Schubert    if ($fips) {
234*e0c4386eSCy Schubert        @protocols = $dtls ? @dtls_protocols_fips : @tls_protocols_fips;
235*e0c4386eSCy Schubert        $min_enabled  = $dtls ? $min_dtls_enabled_fips : $min_tls_enabled_fips;
236*e0c4386eSCy Schubert        $max_enabled = $dtls ? $max_dtls_enabled_fips : $max_tls_enabled_fips;
237*e0c4386eSCy Schubert    } else {
238*e0c4386eSCy Schubert        @protocols = $dtls ? @dtls_protocols : @tls_protocols;
239*e0c4386eSCy Schubert        $min_enabled  = $dtls ? $min_dtls_enabled : $min_tls_enabled;
240*e0c4386eSCy Schubert        $max_enabled = $dtls ? $max_dtls_enabled : $max_tls_enabled;
241*e0c4386eSCy Schubert    }
242*e0c4386eSCy Schubert
243*e0c4386eSCy Schubert    if (no_tests($dtls)) {
244*e0c4386eSCy Schubert        return;
245*e0c4386eSCy Schubert    }
246*e0c4386eSCy Schubert
247*e0c4386eSCy Schubert    my @server_tests = ();
248*e0c4386eSCy Schubert    my @client_tests = ();
249*e0c4386eSCy Schubert
250*e0c4386eSCy Schubert    # Obtain the first session against a fixed-version server/client.
251*e0c4386eSCy Schubert    foreach my $original_protocol($min_enabled..$max_enabled) {
252*e0c4386eSCy Schubert        # Upgrade or downgrade the server/client max version support and test
253*e0c4386eSCy Schubert        # that it upgrades, downgrades or resumes the session as well.
254*e0c4386eSCy Schubert        foreach my $resume_protocol($min_enabled..$max_enabled) {
255*e0c4386eSCy Schubert            my $resumption_expected;
256*e0c4386eSCy Schubert            # We should only resume on exact version match.
257*e0c4386eSCy Schubert            if ($original_protocol eq $resume_protocol) {
258*e0c4386eSCy Schubert                $resumption_expected = "Yes";
259*e0c4386eSCy Schubert            } else {
260*e0c4386eSCy Schubert                $resumption_expected = "No";
261*e0c4386eSCy Schubert            }
262*e0c4386eSCy Schubert
263*e0c4386eSCy Schubert            for (my $sctp = 0; $sctp < ($dtls && !disabled("sctp") ? 2 : 1);
264*e0c4386eSCy Schubert                 $sctp++) {
265*e0c4386eSCy Schubert                foreach my $ticket ("SessionTicket", "-SessionTicket") {
266*e0c4386eSCy Schubert                    # Client is flexible, server upgrades/downgrades.
267*e0c4386eSCy Schubert                    push @server_tests, {
268*e0c4386eSCy Schubert                        "name" => "resumption",
269*e0c4386eSCy Schubert                        "client" => {
270*e0c4386eSCy Schubert                            "CipherString" => "DEFAULT:\@SECLEVEL=0",
271*e0c4386eSCy Schubert                        },
272*e0c4386eSCy Schubert                        "server" => {
273*e0c4386eSCy Schubert                            "CipherString" => "DEFAULT:\@SECLEVEL=0",
274*e0c4386eSCy Schubert                            "MinProtocol" => $protocols[$original_protocol],
275*e0c4386eSCy Schubert                            "MaxProtocol" => $protocols[$original_protocol],
276*e0c4386eSCy Schubert                            "Options" => $ticket,
277*e0c4386eSCy Schubert                        },
278*e0c4386eSCy Schubert                        "resume_server" => {
279*e0c4386eSCy Schubert                            "CipherString" => "DEFAULT:\@SECLEVEL=0",
280*e0c4386eSCy Schubert                            "MaxProtocol" => $protocols[$resume_protocol],
281*e0c4386eSCy Schubert                            "Options" => $ticket,
282*e0c4386eSCy Schubert                        },
283*e0c4386eSCy Schubert                        "test" => {
284*e0c4386eSCy Schubert                            "ExpectedProtocol" => $protocols[$resume_protocol],
285*e0c4386eSCy Schubert                            "Method" => $method,
286*e0c4386eSCy Schubert                            "HandshakeMode" => "Resume",
287*e0c4386eSCy Schubert                            "ResumptionExpected" => $resumption_expected,
288*e0c4386eSCy Schubert                        }
289*e0c4386eSCy Schubert                    };
290*e0c4386eSCy Schubert                    $server_tests[-1]{"test"}{"UseSCTP"} = "Yes" if $sctp;
291*e0c4386eSCy Schubert                    # Server is flexible, client upgrades/downgrades.
292*e0c4386eSCy Schubert                    push @client_tests, {
293*e0c4386eSCy Schubert                        "name" => "resumption",
294*e0c4386eSCy Schubert                        "client" => {
295*e0c4386eSCy Schubert                            "CipherString" => "DEFAULT:\@SECLEVEL=0",
296*e0c4386eSCy Schubert                            "MinProtocol" => $protocols[$original_protocol],
297*e0c4386eSCy Schubert                            "MaxProtocol" => $protocols[$original_protocol],
298*e0c4386eSCy Schubert                        },
299*e0c4386eSCy Schubert                        "server" => {
300*e0c4386eSCy Schubert                            "CipherString" => "DEFAULT:\@SECLEVEL=0",
301*e0c4386eSCy Schubert                            "Options" => $ticket,
302*e0c4386eSCy Schubert                        },
303*e0c4386eSCy Schubert                        "resume_client" => {
304*e0c4386eSCy Schubert                            "CipherString" => "DEFAULT:\@SECLEVEL=0",
305*e0c4386eSCy Schubert                            "MaxProtocol" => $protocols[$resume_protocol],
306*e0c4386eSCy Schubert                        },
307*e0c4386eSCy Schubert                        "test" => {
308*e0c4386eSCy Schubert                            "ExpectedProtocol" => $protocols[$resume_protocol],
309*e0c4386eSCy Schubert                            "Method" => $method,
310*e0c4386eSCy Schubert                            "HandshakeMode" => "Resume",
311*e0c4386eSCy Schubert                            "ResumptionExpected" => $resumption_expected,
312*e0c4386eSCy Schubert                        }
313*e0c4386eSCy Schubert                    };
314*e0c4386eSCy Schubert                    $client_tests[-1]{"test"}{"UseSCTP"} = "Yes" if $sctp;
315*e0c4386eSCy Schubert                }
316*e0c4386eSCy Schubert            }
317*e0c4386eSCy Schubert        }
318*e0c4386eSCy Schubert    }
319*e0c4386eSCy Schubert
320*e0c4386eSCy Schubert    if (!disabled("tls1_3") && (!disabled("ec") || !disabled("dh")) && !$dtls) {
321*e0c4386eSCy Schubert        push @client_tests, {
322*e0c4386eSCy Schubert            "name" => "resumption-with-hrr",
323*e0c4386eSCy Schubert            "client" => {
324*e0c4386eSCy Schubert            },
325*e0c4386eSCy Schubert            "server" => {
326*e0c4386eSCy Schubert                "Curves" => disabled("ec") ? "ffdhe3072" : "P-256"
327*e0c4386eSCy Schubert            },
328*e0c4386eSCy Schubert            "resume_client" => {
329*e0c4386eSCy Schubert            },
330*e0c4386eSCy Schubert            "test" => {
331*e0c4386eSCy Schubert                "ExpectedProtocol" => "TLSv1.3",
332*e0c4386eSCy Schubert                "Method" => "TLS",
333*e0c4386eSCy Schubert                "HandshakeMode" => "Resume",
334*e0c4386eSCy Schubert                "ResumptionExpected" => "Yes",
335*e0c4386eSCy Schubert            }
336*e0c4386eSCy Schubert        };
337*e0c4386eSCy Schubert    }
338*e0c4386eSCy Schubert
339*e0c4386eSCy Schubert    return (@server_tests, @client_tests);
340*e0c4386eSCy Schubert}
341*e0c4386eSCy Schubert
342*e0c4386eSCy Schubertsub expected_result {
343*e0c4386eSCy Schubert    my ($c_min, $c_max, $s_min, $s_max, $min_enabled, $max_enabled,
344*e0c4386eSCy Schubert        $protocols) = @_;
345*e0c4386eSCy Schubert    my @prots = @$protocols;
346*e0c4386eSCy Schubert
347*e0c4386eSCy Schubert    my $orig_c_max = $c_max;
348*e0c4386eSCy Schubert    # Adjust for "undef" (no limit).
349*e0c4386eSCy Schubert    $c_min = $c_min == 0 ? 0 : $c_min - 1;
350*e0c4386eSCy Schubert    $c_max = $c_max == scalar @$protocols ? $c_max - 1 : $c_max;
351*e0c4386eSCy Schubert    $s_min = $s_min == 0 ? 0 : $s_min - 1;
352*e0c4386eSCy Schubert    $s_max = $s_max == scalar @$protocols ? $s_max - 1 : $s_max;
353*e0c4386eSCy Schubert
354*e0c4386eSCy Schubert    # We now have at least one protocol enabled, so $min_enabled and
355*e0c4386eSCy Schubert    # $max_enabled are well-defined.
356*e0c4386eSCy Schubert    $c_min = max $c_min, $min_enabled;
357*e0c4386eSCy Schubert    $s_min = max $s_min, $min_enabled;
358*e0c4386eSCy Schubert    $c_max = min $c_max, $max_enabled;
359*e0c4386eSCy Schubert    $s_max = min $s_max, $max_enabled;
360*e0c4386eSCy Schubert
361*e0c4386eSCy Schubert    if ($c_min > $c_max
362*e0c4386eSCy Schubert            || ($orig_c_max != scalar @$protocols
363*e0c4386eSCy Schubert                && $prots[$orig_c_max] eq "TLSv1.3"
364*e0c4386eSCy Schubert                && $c_max != $orig_c_max
365*e0c4386eSCy Schubert                && !disabled("tls1_3"))) {
366*e0c4386eSCy Schubert        # Client should fail to even send a hello.
367*e0c4386eSCy Schubert        return ("ClientFail", undef);
368*e0c4386eSCy Schubert    } elsif ($s_min > $s_max) {
369*e0c4386eSCy Schubert        # Server has no protocols, should always fail.
370*e0c4386eSCy Schubert        return ("ServerFail", undef);
371*e0c4386eSCy Schubert    } elsif ($s_min > $c_max) {
372*e0c4386eSCy Schubert        # Server doesn't support the client range.
373*e0c4386eSCy Schubert        return ("ServerFail", undef);
374*e0c4386eSCy Schubert    } elsif ($c_min > $s_max) {
375*e0c4386eSCy Schubert        if ($prots[$c_max] eq "TLSv1.3") {
376*e0c4386eSCy Schubert            # Client will have sent supported_versions, so server will know
377*e0c4386eSCy Schubert            # that there are no overlapping versions.
378*e0c4386eSCy Schubert            return ("ServerFail", undef);
379*e0c4386eSCy Schubert        } else {
380*e0c4386eSCy Schubert            # Server will try with a version that is lower than the lowest
381*e0c4386eSCy Schubert            # supported client version.
382*e0c4386eSCy Schubert            return ("ClientFail", undef);
383*e0c4386eSCy Schubert        }
384*e0c4386eSCy Schubert    } else {
385*e0c4386eSCy Schubert        # Server and client ranges overlap.
386*e0c4386eSCy Schubert        my $max_common = $s_max < $c_max ? $s_max : $c_max;
387*e0c4386eSCy Schubert        return ("Success", $protocols->[$max_common]);
388*e0c4386eSCy Schubert    }
389*e0c4386eSCy Schubert}
390*e0c4386eSCy Schubert
391*e0c4386eSCy Schubert1;
392