Commit 8da3880874 for openssl.org
commit 8da3880874acaac2e338665f216e430f78f976f1
Author: Mounir IDRASSI <mounir.idrassi@idrix.fr>
Date: Tue Aug 4 12:11:39 2026 +0900
apps/x509.c: failing exit status on every failure path reaching err:
With -multi, a later certificate failure could return success after an
earlier certificate succeeded because ret retained the earlier result
on reaching err:.
Set ret = 1 at err: so every path reaching it reports failure. Paths
bypassing err: remain unchanged, including the pre-existing
X509_VERIFY_PARAM_new() failure under -checkend, which will be addressed
separately.
Add a regression test using -multi -checkhost with a two-certificate
chain whose second certificate fails.
Fixes #32189
Reviewed-by: Jakub Zelenka <jakub.zelenka@openssl.foundation>
Reviewed-by: Todd Short <todd.short@me.com>
Merge-date: Mon Sep 7 14:01:00 2026
Merged-from: https://github.com/openssl/openssl/pull/32190
diff --git a/apps/x509.c b/apps/x509.c
index 867961e61d..3fd41465e2 100644
--- a/apps/x509.c
+++ b/apps/x509.c
@@ -1266,6 +1266,8 @@ end_cert_loop:
goto end;
err:
+ /* Every path reaching this label is a failure path */
+ ret = 1;
ERR_print_errors(bio_err);
end:
diff --git a/test/recipes/25-test_x509.t b/test/recipes/25-test_x509.t
index ce29004782..f4610a9aa5 100644
--- a/test/recipes/25-test_x509.t
+++ b/test/recipes/25-test_x509.t
@@ -17,7 +17,7 @@ use File::Compare qw/compare_text/;
setup("test_x509");
-plan tests => 155;
+plan tests => 156;
# Prevent MSys2 filename munging for arguments that look like file paths but
# aren't
@@ -815,6 +815,22 @@ ok(!run(app(["openssl", "x509", "-multi", "-checkend",
ok(!run(app(["openssl", "x509", "-checkend", "60", "-in", $c_key])),
"Bad parse with -checkend returns non-zero");
+# Regression test: with -multi, a failure on a later certificate must set
+# a failing exit status even after an earlier certificate succeeded, i.e.
+# the per-certificate success status must not leak into the final result.
+subtest "x509 -multi later failure is not masked by earlier success" => sub {
+ plan tests => 1;
+
+ # goodcn2-chain.pem holds two certificates without subjectAltName, so
+ # -checkhost falls back to the CN: "www.good.org" matches the first
+ # certificate ("CN=www.good.org") but not the second ("CN=Test NC CA 1")
+ my $chain = srctop_file(@certs, "goodcn2-chain.pem");
+
+ ok(!run(app(["openssl", "x509", "-multi", "-in", $chain, "-noout",
+ "-checkhost", "www.good.org"])),
+ "-multi returns non-zero when a later certificate fails -checkhost");
+};
+
# Signing using DER-encoded key and CA cert/key inputs,
# exercising -keyform, -CAform and -CAkeyform
subtest 'x509 signing with DER -keyform, -CAform and -CAkeyform' => sub {