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