xref: /netbsd-src/crypto/external/bsd/openssl/dist/test/ssl-tests/protocol_version.pm (revision b0d1725196a7921d003d2c66a14f186abda4176b)
1c7da899bSchristos# -*- mode: perl; -*-
2*b0d17251Schristos# Copyright 2016-2021 The OpenSSL Project Authors. All Rights Reserved.
3c7da899bSchristos#
4*b0d17251Schristos# Licensed under the Apache License 2.0 (the "License").  You may not use
5c7da899bSchristos# this file except in compliance with the License.  You can obtain a copy
6c7da899bSchristos# in the file LICENSE in the source distribution or at
7c7da899bSchristos# https://www.openssl.org/source/license.html
8c7da899bSchristos
9c7da899bSchristos
10c7da899bSchristos## Test version negotiation
11c7da899bSchristos
12c7da899bSchristospackage ssltests;
13c7da899bSchristos
14c7da899bSchristosuse strict;
15c7da899bSchristosuse warnings;
16c7da899bSchristos
17c7da899bSchristosuse List::Util qw/max min/;
18c7da899bSchristos
19c7da899bSchristosuse OpenSSL::Test;
2013d40330Schristosuse OpenSSL::Test::Utils qw/anydisabled alldisabled disabled/;
21c7da899bSchristossetup("no_test_here");
22c7da899bSchristos
2313d40330Schristosmy @tls_protocols = ("SSLv3", "TLSv1", "TLSv1.1", "TLSv1.2", "TLSv1.3");
24*b0d17251Schristosmy @tls_protocols_fips = ("TLSv1.2", "TLSv1.3");
25c7da899bSchristos# undef stands for "no limit".
2613d40330Schristosmy @min_tls_protocols = (undef, "SSLv3", "TLSv1", "TLSv1.1", "TLSv1.2", "TLSv1.3");
27*b0d17251Schristosmy @min_tls_protocols_fips = (undef, "TLSv1.2", "TLSv1.3");
2813d40330Schristosmy @max_tls_protocols = ("SSLv3", "TLSv1", "TLSv1.1", "TLSv1.2", "TLSv1.3", undef);
29*b0d17251Schristosmy @max_tls_protocols_fips = ("TLSv1.2", "TLSv1.3", undef);
30c7da899bSchristos
3113d40330Schristosmy @is_tls_disabled = anydisabled("ssl3", "tls1", "tls1_1", "tls1_2", "tls1_3");
32*b0d17251Schristosmy @is_tls_disabled_fips = anydisabled("tls1_2", "tls1_3");
33c7da899bSchristos
34c7da899bSchristosmy $min_tls_enabled; my $max_tls_enabled;
35*b0d17251Schristosmy $min_tls_enabled_fips; my $max_tls_enabled_fips;
36c7da899bSchristos
37c7da899bSchristos# Protocol configuration works in cascades, i.e.,
38c7da899bSchristos# $no_tls1_1 disables TLSv1.1 and below.
39c7da899bSchristos#
40c7da899bSchristos# $min_enabled and $max_enabled will be correct if there is at least one
41c7da899bSchristos# protocol enabled.
42*b0d17251Schristos
43*b0d17251Schristossub min_prot_enabled {
44*b0d17251Schristos    my $protref = shift;
45*b0d17251Schristos    my $disabledref = shift;
46*b0d17251Schristos    my @protocols = @{$protref};
47*b0d17251Schristos    my @is_disabled = @{$disabledref};
48*b0d17251Schristos    my $min_enabled;
49*b0d17251Schristos
50*b0d17251Schristos    foreach my $i (0..$#protocols) {
51*b0d17251Schristos        if (!$is_disabled[$i]) {
52*b0d17251Schristos            $min_enabled = $i;
53c7da899bSchristos            last;
54c7da899bSchristos        }
55c7da899bSchristos    }
56*b0d17251Schristos    return $min_enabled;
57*b0d17251Schristos}
58c7da899bSchristos
59*b0d17251Schristossub max_prot_enabled {
60*b0d17251Schristos    my $protref = shift;
61*b0d17251Schristos    my $disabledref = shift;
62*b0d17251Schristos    my @protocols = @{$protref};
63*b0d17251Schristos    my @is_disabled = @{$disabledref};
64*b0d17251Schristos    my $max_enabled;
65*b0d17251Schristos
66*b0d17251Schristos    foreach my $i (0..$#protocols) {
67*b0d17251Schristos        if (!$is_disabled[$i]
68*b0d17251Schristos                && ($protocols[$i] ne "TLSv1.3"
69*b0d17251Schristos                    || !disabled("ec")
70*b0d17251Schristos                    || !disabled("dh"))) {
71*b0d17251Schristos            $max_enabled = $i;
72c7da899bSchristos        }
73c7da899bSchristos    }
74*b0d17251Schristos    return $max_enabled;
75*b0d17251Schristos}
76*b0d17251Schristos
77*b0d17251Schristos$min_tls_enabled = min_prot_enabled(\@tls_protocols, \@is_tls_disabled);
78*b0d17251Schristos$max_tls_enabled = max_prot_enabled(\@tls_protocols, \@is_tls_disabled);
79*b0d17251Schristos$min_tls_enabled_fips = min_prot_enabled(\@tls_protocols_fips, \@is_tls_disabled_fips);
80*b0d17251Schristos$max_tls_enabled_fips = max_prot_enabled(\@tls_protocols_fips, \@is_tls_disabled_fips);
81*b0d17251Schristos
82c7da899bSchristos
83c7da899bSchristosmy @dtls_protocols = ("DTLSv1", "DTLSv1.2");
84*b0d17251Schristosmy @dtls_protocols_fips = ("DTLSv1.2");
85c7da899bSchristos# undef stands for "no limit".
86c7da899bSchristosmy @min_dtls_protocols = (undef, "DTLSv1", "DTLSv1.2");
87*b0d17251Schristosmy @min_dtls_protocols_fips = (undef, "DTLSv1.2");
88c7da899bSchristosmy @max_dtls_protocols = ("DTLSv1", "DTLSv1.2", undef);
89*b0d17251Schristosmy @max_dtls_protocols_fips = ("DTLSv1.2", undef);
90c7da899bSchristos
91c7da899bSchristosmy @is_dtls_disabled = anydisabled("dtls1", "dtls1_2");
92*b0d17251Schristosmy @is_dtls_disabled_fips = anydisabled("dtls1_2");
93c7da899bSchristos
94c7da899bSchristosmy $min_dtls_enabled; my $max_dtls_enabled;
95*b0d17251Schristosmy $min_dtls_enabled_fips; my $max_dtls_enabled_fips;
96c7da899bSchristos
97c7da899bSchristos# $min_enabled and $max_enabled will be correct if there is at least one
98c7da899bSchristos# protocol enabled.
99*b0d17251Schristos$min_dtls_enabled = min_prot_enabled(\@dtls_protocols, \@is_dtls_disabled);
100*b0d17251Schristos$max_dtls_enabled = max_prot_enabled(\@dtls_protocols, \@is_dtls_disabled);
101*b0d17251Schristos$min_dtls_enabled_fips = min_prot_enabled(\@dtls_protocols_fips, \@is_dtls_disabled_fips);
102*b0d17251Schristos$max_dtls_enabled_fips = max_prot_enabled(\@dtls_protocols_fips, \@is_dtls_disabled_fips);
103c7da899bSchristos
104c7da899bSchristossub no_tests {
105*b0d17251Schristos    my ($dtls, $fips) = @_;
106*b0d17251Schristos    if ($dtls && $fips) {
107*b0d17251Schristos        return disabled("dtls1_2");
108*b0d17251Schristos    }
109c7da899bSchristos    return $dtls ? alldisabled("dtls1", "dtls1_2") :
11013d40330Schristos      alldisabled("ssl3", "tls1", "tls1_1", "tls1_2", "tls1_3");
111c7da899bSchristos}
112c7da899bSchristos
113c7da899bSchristossub generate_version_tests {
114*b0d17251Schristos    my $method = shift;
115*b0d17251Schristos    my $fips = shift;
116c7da899bSchristos
117c7da899bSchristos    my $dtls = $method eq "DTLS";
118c7da899bSchristos    # Don't write the redundant "Method = TLS" into the configuration.
119c7da899bSchristos    undef $method if !$dtls;
120c7da899bSchristos
121*b0d17251Schristos    my @protocols;
122*b0d17251Schristos    my @min_protocols;
123*b0d17251Schristos    my @max_protocols;
124*b0d17251Schristos    my $min_enabled;
125*b0d17251Schristos    my $max_enabled;
126*b0d17251Schristos    if ($fips) {
127*b0d17251Schristos        @protocols = $dtls ? @dtls_protocols_fips : @tls_protocols_fips;
128*b0d17251Schristos        @min_protocols = $dtls ? @min_dtls_protocols_fips : @min_tls_protocols_fips;
129*b0d17251Schristos        @max_protocols = $dtls ? @max_dtls_protocols_fips : @max_tls_protocols_fips;
130*b0d17251Schristos        $min_enabled  = $dtls ? $min_dtls_enabled_fips : $min_tls_enabled_fips;
131*b0d17251Schristos        $max_enabled  = $dtls ? $max_dtls_enabled_fips : $max_tls_enabled_fips;
132*b0d17251Schristos    } else {
133*b0d17251Schristos        @protocols = $dtls ? @dtls_protocols : @tls_protocols;
134*b0d17251Schristos        @min_protocols = $dtls ? @min_dtls_protocols : @min_tls_protocols;
135*b0d17251Schristos        @max_protocols = $dtls ? @max_dtls_protocols : @max_tls_protocols;
136*b0d17251Schristos        $min_enabled  = $dtls ? $min_dtls_enabled : $min_tls_enabled;
137*b0d17251Schristos        $max_enabled  = $dtls ? $max_dtls_enabled : $max_tls_enabled;
138*b0d17251Schristos    }
139c7da899bSchristos
140*b0d17251Schristos    if (no_tests($dtls, $fips)) {
141c7da899bSchristos        return;
142c7da899bSchristos    }
143c7da899bSchristos
144c7da899bSchristos    my @tests = ();
145c7da899bSchristos
14613d40330Schristos    for (my $sctp = 0; $sctp < ($dtls && !disabled("sctp") ? 2 : 1); $sctp++) {
147c7da899bSchristos        foreach my $c_min (0..$#min_protocols) {
148c7da899bSchristos            my $c_max_min = $c_min == 0 ? 0 : $c_min - 1;
149c7da899bSchristos            foreach my $c_max ($c_max_min..$#max_protocols) {
150c7da899bSchristos                foreach my $s_min (0..$#min_protocols) {
151c7da899bSchristos                    my $s_max_min = $s_min == 0 ? 0 : $s_min - 1;
152c7da899bSchristos                    foreach my $s_max ($s_max_min..$#max_protocols) {
153c7da899bSchristos                        my ($result, $protocol) =
154c7da899bSchristos                            expected_result($c_min, $c_max, $s_min, $s_max,
15513d40330Schristos                                            $min_enabled, $max_enabled,
15613d40330Schristos                                            \@protocols);
157c7da899bSchristos                        push @tests, {
158c7da899bSchristos                            "name" => "version-negotiation",
159c7da899bSchristos                            "client" => {
160*b0d17251Schristos                                "CipherString" => "DEFAULT:\@SECLEVEL=0",
161c7da899bSchristos                                "MinProtocol" => $min_protocols[$c_min],
162c7da899bSchristos                                "MaxProtocol" => $max_protocols[$c_max],
163c7da899bSchristos                            },
164c7da899bSchristos                            "server" => {
165*b0d17251Schristos                                "CipherString" => "DEFAULT:\@SECLEVEL=0",
166c7da899bSchristos                                "MinProtocol" => $min_protocols[$s_min],
167c7da899bSchristos                                "MaxProtocol" => $max_protocols[$s_max],
168c7da899bSchristos                            },
169c7da899bSchristos                            "test" => {
170c7da899bSchristos                                "ExpectedResult" => $result,
171c7da899bSchristos                                "ExpectedProtocol" => $protocol,
172c7da899bSchristos                                "Method" => $method,
173c7da899bSchristos                            }
174c7da899bSchristos                        };
17513d40330Schristos                        $tests[-1]{"test"}{"UseSCTP"} = "Yes" if $sctp;
176c7da899bSchristos                    }
177c7da899bSchristos                }
178c7da899bSchristos            }
179c7da899bSchristos        }
18013d40330Schristos    }
181*b0d17251Schristos    return @tests
182*b0d17251Schristos        if disabled("tls1_3")
183*b0d17251Schristos           || disabled("tls1_2")
184*b0d17251Schristos           || (disabled("ec") && disabled("dh"))
185*b0d17251Schristos           || $dtls;
18613d40330Schristos
18713d40330Schristos    #Add some version/ciphersuite sanity check tests
18813d40330Schristos    push @tests, {
18913d40330Schristos        "name" => "ciphersuite-sanity-check-client",
19013d40330Schristos        "client" => {
19113d40330Schristos            #Offering only <=TLSv1.2 ciphersuites with TLSv1.3 should fail
19213d40330Schristos            "CipherString" => "AES128-SHA",
19313d40330Schristos            "Ciphersuites" => "",
19413d40330Schristos        },
19513d40330Schristos        "server" => {
19613d40330Schristos            "MaxProtocol" => "TLSv1.2"
19713d40330Schristos        },
19813d40330Schristos        "test" => {
19913d40330Schristos            "ExpectedResult" => "ClientFail",
20013d40330Schristos        }
20113d40330Schristos    };
20213d40330Schristos    push @tests, {
20313d40330Schristos        "name" => "ciphersuite-sanity-check-server",
20413d40330Schristos        "client" => {
20513d40330Schristos            "CipherString" => "AES128-SHA",
20613d40330Schristos            "MaxProtocol" => "TLSv1.2"
20713d40330Schristos        },
20813d40330Schristos        "server" => {
20913d40330Schristos            #Allowing only <=TLSv1.2 ciphersuites with TLSv1.3 should fail
21013d40330Schristos            "CipherString" => "AES128-SHA",
21113d40330Schristos            "Ciphersuites" => "",
21213d40330Schristos        },
21313d40330Schristos        "test" => {
21413d40330Schristos            "ExpectedResult" => "ServerFail",
21513d40330Schristos        }
21613d40330Schristos    };
21713d40330Schristos
218c7da899bSchristos    return @tests;
219c7da899bSchristos}
220c7da899bSchristos
221c7da899bSchristossub generate_resumption_tests {
222*b0d17251Schristos    my $method = shift;
223*b0d17251Schristos    my $fips = shift;
224c7da899bSchristos
225c7da899bSchristos    my $dtls = $method eq "DTLS";
226c7da899bSchristos    # Don't write the redundant "Method = TLS" into the configuration.
227c7da899bSchristos    undef $method if !$dtls;
228c7da899bSchristos
229*b0d17251Schristos    my @protocols;
230*b0d17251Schristos    my $min_enabled;
231*b0d17251Schristos    my $max_enabled;
232*b0d17251Schristos
233*b0d17251Schristos    if ($fips) {
234*b0d17251Schristos        @protocols = $dtls ? @dtls_protocols_fips : @tls_protocols_fips;
235*b0d17251Schristos        $min_enabled  = $dtls ? $min_dtls_enabled_fips : $min_tls_enabled_fips;
236*b0d17251Schristos        $max_enabled = $dtls ? $max_dtls_enabled_fips : $max_tls_enabled_fips;
237*b0d17251Schristos    } else {
238*b0d17251Schristos        @protocols = $dtls ? @dtls_protocols : @tls_protocols;
239*b0d17251Schristos        $min_enabled  = $dtls ? $min_dtls_enabled : $min_tls_enabled;
240*b0d17251Schristos        $max_enabled = $dtls ? $max_dtls_enabled : $max_tls_enabled;
241*b0d17251Schristos    }
242c7da899bSchristos
243c7da899bSchristos    if (no_tests($dtls)) {
244c7da899bSchristos        return;
245c7da899bSchristos    }
246c7da899bSchristos
247c7da899bSchristos    my @server_tests = ();
248c7da899bSchristos    my @client_tests = ();
249c7da899bSchristos
250c7da899bSchristos    # Obtain the first session against a fixed-version server/client.
25113d40330Schristos    foreach my $original_protocol($min_enabled..$max_enabled) {
252c7da899bSchristos        # Upgrade or downgrade the server/client max version support and test
253c7da899bSchristos        # that it upgrades, downgrades or resumes the session as well.
25413d40330Schristos        foreach my $resume_protocol($min_enabled..$max_enabled) {
255c7da899bSchristos            my $resumption_expected;
256c7da899bSchristos            # We should only resume on exact version match.
257c7da899bSchristos            if ($original_protocol eq $resume_protocol) {
258c7da899bSchristos                $resumption_expected = "Yes";
259c7da899bSchristos            } else {
260c7da899bSchristos                $resumption_expected = "No";
261c7da899bSchristos            }
262c7da899bSchristos
26313d40330Schristos            for (my $sctp = 0; $sctp < ($dtls && !disabled("sctp") ? 2 : 1);
26413d40330Schristos                 $sctp++) {
265c7da899bSchristos                foreach my $ticket ("SessionTicket", "-SessionTicket") {
266c7da899bSchristos                    # Client is flexible, server upgrades/downgrades.
267c7da899bSchristos                    push @server_tests, {
268c7da899bSchristos                        "name" => "resumption",
269*b0d17251Schristos                        "client" => {
270*b0d17251Schristos                            "CipherString" => "DEFAULT:\@SECLEVEL=0",
271*b0d17251Schristos                        },
272c7da899bSchristos                        "server" => {
273*b0d17251Schristos                            "CipherString" => "DEFAULT:\@SECLEVEL=0",
274c7da899bSchristos                            "MinProtocol" => $protocols[$original_protocol],
275c7da899bSchristos                            "MaxProtocol" => $protocols[$original_protocol],
276c7da899bSchristos                            "Options" => $ticket,
277c7da899bSchristos                        },
278c7da899bSchristos                        "resume_server" => {
279*b0d17251Schristos                            "CipherString" => "DEFAULT:\@SECLEVEL=0",
280c7da899bSchristos                            "MaxProtocol" => $protocols[$resume_protocol],
28113d40330Schristos                            "Options" => $ticket,
282c7da899bSchristos                        },
283c7da899bSchristos                        "test" => {
284c7da899bSchristos                            "ExpectedProtocol" => $protocols[$resume_protocol],
285c7da899bSchristos                            "Method" => $method,
286c7da899bSchristos                            "HandshakeMode" => "Resume",
287c7da899bSchristos                            "ResumptionExpected" => $resumption_expected,
288c7da899bSchristos                        }
289c7da899bSchristos                    };
29013d40330Schristos                    $server_tests[-1]{"test"}{"UseSCTP"} = "Yes" if $sctp;
291c7da899bSchristos                    # Server is flexible, client upgrades/downgrades.
292c7da899bSchristos                    push @client_tests, {
293c7da899bSchristos                        "name" => "resumption",
294c7da899bSchristos                        "client" => {
295*b0d17251Schristos                            "CipherString" => "DEFAULT:\@SECLEVEL=0",
296c7da899bSchristos                            "MinProtocol" => $protocols[$original_protocol],
297c7da899bSchristos                            "MaxProtocol" => $protocols[$original_protocol],
298c7da899bSchristos                        },
299c7da899bSchristos                        "server" => {
300*b0d17251Schristos                            "CipherString" => "DEFAULT:\@SECLEVEL=0",
301c7da899bSchristos                            "Options" => $ticket,
302c7da899bSchristos                        },
303c7da899bSchristos                        "resume_client" => {
304*b0d17251Schristos                            "CipherString" => "DEFAULT:\@SECLEVEL=0",
305c7da899bSchristos                            "MaxProtocol" => $protocols[$resume_protocol],
306c7da899bSchristos                        },
307c7da899bSchristos                        "test" => {
308c7da899bSchristos                            "ExpectedProtocol" => $protocols[$resume_protocol],
309c7da899bSchristos                            "Method" => $method,
310c7da899bSchristos                            "HandshakeMode" => "Resume",
311c7da899bSchristos                            "ResumptionExpected" => $resumption_expected,
312c7da899bSchristos                        }
313c7da899bSchristos                    };
31413d40330Schristos                    $client_tests[-1]{"test"}{"UseSCTP"} = "Yes" if $sctp;
315c7da899bSchristos                }
316c7da899bSchristos            }
317c7da899bSchristos        }
31813d40330Schristos    }
31913d40330Schristos
320*b0d17251Schristos    if (!disabled("tls1_3") && (!disabled("ec") || !disabled("dh")) && !$dtls) {
32113d40330Schristos        push @client_tests, {
32213d40330Schristos            "name" => "resumption-with-hrr",
32313d40330Schristos            "client" => {
32413d40330Schristos            },
32513d40330Schristos            "server" => {
326*b0d17251Schristos                "Curves" => disabled("ec") ? "ffdhe3072" : "P-256"
32713d40330Schristos            },
32813d40330Schristos            "resume_client" => {
32913d40330Schristos            },
33013d40330Schristos            "test" => {
33113d40330Schristos                "ExpectedProtocol" => "TLSv1.3",
33213d40330Schristos                "Method" => "TLS",
33313d40330Schristos                "HandshakeMode" => "Resume",
33413d40330Schristos                "ResumptionExpected" => "Yes",
33513d40330Schristos            }
33613d40330Schristos        };
33713d40330Schristos    }
338c7da899bSchristos
339c7da899bSchristos    return (@server_tests, @client_tests);
340c7da899bSchristos}
341c7da899bSchristos
342c7da899bSchristossub expected_result {
343c7da899bSchristos    my ($c_min, $c_max, $s_min, $s_max, $min_enabled, $max_enabled,
344c7da899bSchristos        $protocols) = @_;
345*b0d17251Schristos    my @prots = @$protocols;
346c7da899bSchristos
347*b0d17251Schristos    my $orig_c_max = $c_max;
348c7da899bSchristos    # Adjust for "undef" (no limit).
349c7da899bSchristos    $c_min = $c_min == 0 ? 0 : $c_min - 1;
350c7da899bSchristos    $c_max = $c_max == scalar @$protocols ? $c_max - 1 : $c_max;
351c7da899bSchristos    $s_min = $s_min == 0 ? 0 : $s_min - 1;
352c7da899bSchristos    $s_max = $s_max == scalar @$protocols ? $s_max - 1 : $s_max;
353c7da899bSchristos
354c7da899bSchristos    # We now have at least one protocol enabled, so $min_enabled and
355c7da899bSchristos    # $max_enabled are well-defined.
356c7da899bSchristos    $c_min = max $c_min, $min_enabled;
357c7da899bSchristos    $s_min = max $s_min, $min_enabled;
358c7da899bSchristos    $c_max = min $c_max, $max_enabled;
359c7da899bSchristos    $s_max = min $s_max, $max_enabled;
360c7da899bSchristos
361*b0d17251Schristos    if ($c_min > $c_max
362*b0d17251Schristos            || ($orig_c_max != scalar @$protocols
363*b0d17251Schristos                && $prots[$orig_c_max] eq "TLSv1.3"
364*b0d17251Schristos                && $c_max != $orig_c_max
365*b0d17251Schristos                && !disabled("tls1_3"))) {
366c7da899bSchristos        # Client should fail to even send a hello.
36713d40330Schristos        return ("ClientFail", undef);
368c7da899bSchristos    } elsif ($s_min > $s_max) {
369c7da899bSchristos        # Server has no protocols, should always fail.
370c7da899bSchristos        return ("ServerFail", undef);
371c7da899bSchristos    } elsif ($s_min > $c_max) {
372c7da899bSchristos        # Server doesn't support the client range.
373c7da899bSchristos        return ("ServerFail", undef);
374c7da899bSchristos    } elsif ($c_min > $s_max) {
37513d40330Schristos        if ($prots[$c_max] eq "TLSv1.3") {
37613d40330Schristos            # Client will have sent supported_versions, so server will know
37713d40330Schristos            # that there are no overlapping versions.
37813d40330Schristos            return ("ServerFail", undef);
37913d40330Schristos        } else {
380c7da899bSchristos            # Server will try with a version that is lower than the lowest
381c7da899bSchristos            # supported client version.
382c7da899bSchristos            return ("ClientFail", undef);
38313d40330Schristos        }
384c7da899bSchristos    } else {
385c7da899bSchristos        # Server and client ranges overlap.
386c7da899bSchristos        my $max_common = $s_max < $c_max ? $s_max : $c_max;
387c7da899bSchristos        return ("Success", $protocols->[$max_common]);
388c7da899bSchristos    }
389c7da899bSchristos}
390c7da899bSchristos
391c7da899bSchristos1;
392