Commit dc20d355b5 for openssl.org
commit dc20d355b553f1dd3c99e468e2cfa0d696a74bab
Author: Uni <pedroluiscolmenares722@gmail.com>
Date: Fri Mar 6 18:19:31 2026 +0100
Fix intermittent hang in 82-test_ech_client_server.t
Reviewed-by: Neil Horman <nhorman@openssl.org>
Reviewed-by: Matt Caswell <matt@openssl.foundation>
MergeDate: Tue Mar 10 18:22:17 2026
(Merged from https://github.com/openssl/openssl/pull/30289)
diff --git a/test/recipes/82-test_ech_client_server.t b/test/recipes/82-test_ech_client_server.t
index 480744491c..446323120c 100644
--- a/test/recipes/82-test_ech_client_server.t
+++ b/test/recipes/82-test_ech_client_server.t
@@ -12,7 +12,6 @@ use warnings;
use IPC::Open3;
use OpenSSL::Test qw/:DEFAULT srctop_file srctop_dir bldtop_file/;
use OpenSSL::Test::Utils;
-use Symbol 'gensym';
# servers randomly pick a port, then set this for clients to use
# we also record the pid so we can kill it later if needed
@@ -71,193 +70,200 @@ my $good_b64 = extract_ecl();
sub start_ech_client_server
{
my ( $test_type, $winpattern ) = @_;
+ my $timeout = 60;
- # start an s_server listening on some random port, with ECH enabled
- # and willing to accept one request
-
- # openssl s_server -accept 0 -naccept 1
- # -key $server_key -cert $server_cert
- # -key2 $server_key -cert2 $server_cert
- # -ech_key $echconfig_pem
- # -servername example.com
- # -tls1_3
- my @s_server_cmd;
- if ($test_type eq "cid-free" ) {
- # turn on trial-decrypt, so client can use random CID
- @s_server_cmd = ("s_server", "-accept", "0", "-naccept", "1",
- "-cert", $server_pem, "-key", $server_key,
- "-cert2", $server_pem, "-key2", $server_key,
- "-ech_key", $echconfig_pem,
- "-servername", "example.com",
- "-ech_trialdecrypt",
- "-tls1_3");
- } elsif ($test_type eq "keydir" ) {
- # load keys from key dir (some will fail)
- @s_server_cmd = ("s_server", "-accept", "0", "-naccept", "1",
- "-cert", $server_pem, "-key", $server_key,
- "-cert2", $server_pem, "-key2", $server_key,
- "-ech_dir", $ech_dir,
- "-ech_noretry_dir", $ech_dir,
- "-servername", "example.com",
- "-tls1_3");
- } else {
- # default for all other tests (for now)
- @s_server_cmd = ("s_server", "-accept", "0", "-naccept", "1",
- "-cert", $server_pem, "-key", $server_key,
- "-cert2", $server_pem, "-key2", $server_key,
- "-ech_key", $echconfig_pem,
- "-servername", "example.com",
- "-ech_greaseretries",
- "-tls1_3");
- }
- print("@s_server_cmd\n");
- $s_server_pid = open3(my $s_server_i, my $s_server_o,
- my $s_server_e = gensym,
- $shlib_wrap, $apps_openssl, @s_server_cmd);
- # we're looking for...
- # ACCEPT 0.0.0.0:45921
- # ACCEPT [::]:45921
- $s_server_port = "0";
- while (<$s_server_o>) {
- print($_);
- chomp;
- if (/^ACCEPT 0.0.0.0:(\d+)/) {
- $s_server_port = $1;
- last;
- } elsif (/^ACCEPT \[::\]:(\d+)/) {
- $s_server_port = $1;
- last;
- } elsif (/^Using default/) {
- ;
- } elsif (/^Added (\d+) ECH/) {
- ;
- } elsif (/^Added ECH key pair/) {
- ;
- } elsif (/^Loaded/) {
- ;
- } elsif (/^Setting secondary/) {
- ;
+ eval {
+ local $SIG{ALRM} = sub { die "timeout\n" };
+ alarm $timeout;
+ my @s_server_cmd;
+ if ($test_type eq "cid-free" ) {
+ # turn on trial-decrypt, so client can use random CID
+ @s_server_cmd = ("s_server", "-accept", "0", "-naccept", "1",
+ "-cert", $server_pem, "-key", $server_key,
+ "-cert2", $server_pem, "-key2", $server_key,
+ "-ech_key", $echconfig_pem,
+ "-servername", "example.com",
+ "-ech_trialdecrypt",
+ "-tls1_3");
+ } elsif ($test_type eq "keydir" ) {
+ # load keys from key dir (some will fail)
+ @s_server_cmd = ("s_server", "-accept", "0", "-naccept", "1",
+ "-cert", $server_pem, "-key", $server_key,
+ "-cert2", $server_pem, "-key2", $server_key,
+ "-ech_dir", $ech_dir,
+ "-ech_noretry_dir", $ech_dir,
+ "-servername", "example.com",
+ "-tls1_3");
} else {
- last;
+ # default for all other tests (for now)
+ @s_server_cmd = ("s_server", "-accept", "0", "-naccept", "1",
+ "-cert", $server_pem, "-key", $server_key,
+ "-cert2", $server_pem, "-key2", $server_key,
+ "-ech_key", $echconfig_pem,
+ "-servername", "example.com",
+ "-ech_greaseretries",
+ "-tls1_3");
}
- }
- # openssl s_client -connect localhost:NNNNN
- # -servername server.example
- # -CAfile test/certs/rootcert.pem
- # -ech_config_list "ADn+...AA="
- # -prexit
- my @s_client_cmd;
- if ($test_type eq "GREASE-suite" ) {
- # GREASE with suite
- @s_client_cmd = ("s_client",
- "-connect", "localhost:$s_server_port",
- "-servername", "server.example",
- "-CAfile", $root_pem,
- "-ech_grease_suite", "0x21,2,3",
- "-prexit");
- } elsif ($test_type eq "bad-GREASE-suite" ) {
- # bad GREASE suite
- @s_client_cmd = ("s_client",
- "-connect", "localhost:$s_server_port",
- "-servername", "server.example",
- "-CAfile", $root_pem,
- "-ech_grease_suite", "thisisnotagoodone",
- "-prexit");
- } elsif ($test_type eq "lots-of-options" ) {
- # real ECH with lots of options
- @s_client_cmd = ("s_client",
- "-connect", "localhost:$s_server_port",
- "-servername", "server.example",
- "-CAfile", $root_pem,
- "-ech_config_list", $good_b64,
- "-ech_outer_sni", "foodle.doodle",
- "-ech_select", "0",
- "-alpn", "http/1.1",
- "-ech_outer_alpn", "http451",
- "-prexit");
- } elsif ($test_type eq "GREASE-type" ) {
- # GREASE with type
- @s_client_cmd = ("s_client",
- "-connect", "localhost:$s_server_port",
- "-servername", "server.example",
- "-CAfile", $root_pem,
- "-ech_grease_type", "12345",
- "-prexit");
- } elsif ($test_type eq "GREASE" ) {
- # GREASE with suite
- @s_client_cmd = ("s_client",
- "-connect", "localhost:$s_server_port",
- "-servername", "server.example",
- "-CAfile", $root_pem,
- "-ech_grease",
- "-prexit");
- } elsif ($test_type eq "no-outer" ) {
- # Real ECH, no outer SNI
- @s_client_cmd = ("s_client",
- "-connect", "localhost:$s_server_port",
- "-servername", "server.example",
- "-CAfile", $root_pem,
- "-ech_config_list", $good_b64,
- "-ech_no_outer_sni",
- "-prexit");
- } elsif ($test_type eq "bad-ech" ) {
- # bad ECH
- @s_client_cmd = ("s_client",
- "-connect", "localhost:$s_server_port",
- "-servername", "server.example",
- "-CAfile", $root_pem,
- "-ech_config_list", "AEH+DQA91wAgACCBdNrnZxqNrUXSyimqqnfmNG4lHtVsbmaaIeRoUoFWFQAEAAEAAQAOc2VydmVyLmV4YW1wbGUAAA==",
- "-prexit");
- } elsif ($test_type eq "cid-free" ) {
- # Real ECH, ignore CID
- @s_client_cmd = ("s_client",
- "-connect", "localhost:$s_server_port",
- "-servername", "server.example",
- "-CAfile", $root_pem,
- "-ech_config_list", $good_b64,
- "-ech_ignore_cid",
- "-prexit");
- } elsif ($test_type eq "cid-wrong" ) {
- # Real ECH, ignore CID, no trial decrypt
- @s_client_cmd = ("s_client",
- "-connect", "localhost:$s_server_port",
- "-servername", "server.example",
- "-CAfile", $root_pem,
- "-ech_config_list", $good_b64,
- "-ech_ignore_cid",
- "-prexit");
- } else {
- # Real ECH, and default
- @s_client_cmd = ("s_client",
- "-connect", "localhost:$s_server_port",
- "-servername", "server.example",
- "-CAfile", $root_pem,
- "-ech_config_list", $good_b64,
- "-prexit");
- }
- print("@s_client_cmd\n");
- local (*sc_input);
- my $s_client_pid = open3(*sc_input, my $s_client_o,
- my $s_client_e = gensym,
- $shlib_wrap, $apps_openssl, @s_client_cmd);
- print sc_input "Q\n";
- close(sc_input);
- waitpid($s_client_pid, 0);
- # the output from s_client that we want to check is written to its
- # stdout, e.g: "^ECH: success, yay!"
- $s_client_match = 0;
- while (<$s_client_o>) {
- print($_);
- chomp;
- if (/$winpattern/) {
- $s_client_match = 1;
- last;
+ print("@s_server_cmd\n");
+ $s_server_pid = open3(my $s_server_i, my $s_server_o,
+ my $s_server_e,
+ $shlib_wrap, $apps_openssl, @s_server_cmd);
+ # we're looking for...
+ # ACCEPT 0.0.0.0:45921
+ # ACCEPT [::]:45921
+ $s_server_port = "0";
+ while (<$s_server_o>) {
+ print($_);
+ chomp;
+ if (/^ACCEPT 0.0.0.0:(\d+)/) {
+ $s_server_port = $1;
+ last;
+ } elsif (/^ACCEPT \[::\]:(\d+)/) {
+ $s_server_port = $1;
+ last;
+ } elsif (/^Using default/) {
+ ;
+ } elsif (/^Added (\d+) ECH/) {
+ ;
+ } elsif (/^Added ECH key pair/) {
+ ;
+ } elsif (/^Loaded/) {
+ ;
+ } elsif (/^Setting secondary/) {
+ ;
+ } else {
+ last;
+ }
+ }
+ # openssl s_client -connect localhost:NNNNN
+ # -servername server.example
+ # -CAfile test/certs/rootcert.pem
+ # -ech_config_list "ADn+...AA="
+ # -prexit
+ my @s_client_cmd;
+ if ($test_type eq "GREASE-suite" ) {
+ # GREASE with suite
+ @s_client_cmd = ("s_client",
+ "-connect", "localhost:$s_server_port",
+ "-servername", "server.example",
+ "-CAfile", $root_pem,
+ "-ech_grease_suite", "0x21,2,3",
+ "-prexit");
+ } elsif ($test_type eq "bad-GREASE-suite" ) {
+ # bad GREASE suite
+ @s_client_cmd = ("s_client",
+ "-connect", "localhost:$s_server_port",
+ "-servername", "server.example",
+ "-CAfile", $root_pem,
+ "-ech_grease_suite", "thisisnotagoodone",
+ "-prexit");
+ } elsif ($test_type eq "lots-of-options" ) {
+ # real ECH with lots of options
+ @s_client_cmd = ("s_client",
+ "-connect", "localhost:$s_server_port",
+ "-servername", "server.example",
+ "-CAfile", $root_pem,
+ "-ech_config_list", $good_b64,
+ "-ech_outer_sni", "foodle.doodle",
+ "-ech_select", "0",
+ "-alpn", "http/1.1",
+ "-ech_outer_alpn", "http451",
+ "-prexit");
+ } elsif ($test_type eq "GREASE-type" ) {
+ # GREASE with type
+ @s_client_cmd = ("s_client",
+ "-connect", "localhost:$s_server_port",
+ "-servername", "server.example",
+ "-CAfile", $root_pem,
+ "-ech_grease_type", "12345",
+ "-prexit");
+ } elsif ($test_type eq "GREASE" ) {
+ # GREASE with suite
+ @s_client_cmd = ("s_client",
+ "-connect", "localhost:$s_server_port",
+ "-servername", "server.example",
+ "-CAfile", $root_pem,
+ "-ech_grease",
+ "-prexit");
+ } elsif ($test_type eq "no-outer" ) {
+ # Real ECH, no outer SNI
+ @s_client_cmd = ("s_client",
+ "-connect", "localhost:$s_server_port",
+ "-servername", "server.example",
+ "-CAfile", $root_pem,
+ "-ech_config_list", $good_b64,
+ "-ech_no_outer_sni",
+ "-prexit");
+ } elsif ($test_type eq "bad-ech" ) {
+ # bad ECH
+ @s_client_cmd = ("s_client",
+ "-connect", "localhost:$s_server_port",
+ "-servername", "server.example",
+ "-CAfile", $root_pem,
+ "-ech_config_list", "AEH+DQA91wAgACCBdNrnZxqNrUXSyimqqnfmNG4lHtVsbmaaIeRoUoFWFQAEAAEAAQAOc2VydmVyLmV4YW1wbGUAAA==",
+ "-prexit");
+ } elsif ($test_type eq "cid-free" ) {
+ # Real ECH, ignore CID
+ @s_client_cmd = ("s_client",
+ "-connect", "localhost:$s_server_port",
+ "-servername", "server.example",
+ "-CAfile", $root_pem,
+ "-ech_config_list", $good_b64,
+ "-ech_ignore_cid",
+ "-prexit");
+ } elsif ($test_type eq "cid-wrong" ) {
+ # Real ECH, ignore CID, no trial decrypt
+ @s_client_cmd = ("s_client",
+ "-connect", "localhost:$s_server_port",
+ "-servername", "server.example",
+ "-CAfile", $root_pem,
+ "-ech_config_list", $good_b64,
+ "-ech_ignore_cid",
+ "-prexit");
+ } else {
+ # Real ECH, and default
+ @s_client_cmd = ("s_client",
+ "-connect", "localhost:$s_server_port",
+ "-servername", "server.example",
+ "-CAfile", $root_pem,
+ "-ech_config_list", $good_b64,
+ "-prexit");
+ }
+ print("@s_client_cmd\n");
+ local (*sc_input);
+ my $s_client_pid = open3(*sc_input, my $s_client_o,
+ my $s_client_e,
+ $shlib_wrap, $apps_openssl, @s_client_cmd);
+ print sc_input "Q\n";
+ close(sc_input);
+ waitpid($s_client_pid, 0);
+ my $stillthere = kill 0, $s_server_pid;
+ if ($stillthere) {
+ print("s_server process ($s_server_pid) is not dead yet.\n");
+ kill 'HUP', $s_server_pid;
+ }
+ # the output from s_client that we want to check is written to its
+ # stdout, e.g: "^ECH: success, yay!"
+ $s_client_match = 0;
+ while (<$s_client_o>) {
+ print($_);
+ chomp;
+ if (/$winpattern/) {
+ $s_client_match = 1;
+ last;
+ }
+ }
+
+ alarm 0;
+ };
+ if ($@) {
+ if ($@ eq "timeout\n") {
+ print("TIMEOUT: test timed out after ${timeout}s\n");
+ kill 'KILL', $s_server_pid
+ if $s_server_pid && kill(0, $s_server_pid);
+ } else {
+ die $@;
}
- }
- my $stillthere = kill 0, $s_server_pid;
- if ($stillthere) {
- print("s_server process ($s_server_pid) is not dead yet.\n");
- kill 'HUP', $s_server_pid;
}
}