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