Commit f9796787f5 for openssl.org
commit f9796787f5189a23242f95d081c871d8bca479b2
Author: skaiea13-ai <246881935+skaiea13-ai@users.noreply.github.com>
Date: Sun Aug 30 14:12:36 2026 +0900
apps/ocsp.c: fail on invalid response times
Propagate OCSP_check_validity() failures through print_ocsp_summary(),
so the command returns a nonzero exit status for stale responses.
Add a request-aware regression test using the existing signed fixtures.
Resolves: https://github.com/openssl/openssl/issues/32367
References: 639bb581ce5b "apps/ocsp: Return non zero exit code with invalid certID"
References: https://github.com/openssl/openssl/issues/7151
Co-Authored-by: Mounir Idrassi <mounir.idrassi@idrix.fr>
Assisted-by: OpenAI Codex:GPT-5
Assisted-by: OpenAI Codex:GPT-6
Reviewed-by: Frederik Wedel-Heinen <fwh.openssl@gmail.com>
Reviewed-by: Mounir Idrassi <mounir.idrassi@idrix.fr>
Reviewed-by: Tomas Mraz <tomas@openssl.foundation>
Reviewed-by: Eugene Syromiatnikov <esyr@openssl.org>
Merge-date: Mon Oct 19 13:41:13 2026
Merged-from: https://github.com/openssl/openssl/pull/32600
diff --git a/apps/ocsp.c b/apps/ocsp.c
index e302c1cf6b..c4c82efbc1 100644
--- a/apps/ocsp.c
+++ b/apps/ocsp.c
@@ -1059,6 +1059,7 @@ static int print_ocsp_summary(BIO *out, OCSP_BASICRESP *bs, OCSP_REQUEST *req,
if (!OCSP_check_validity(thisupd, nextupd, nsec, maxage)) {
BIO_puts(out, "WARNING: Status times invalid.\n");
ERR_print_errors(out);
+ ret = 0;
}
BIO_printf(out, "%s\n"
"\tThis Update: ",
diff --git a/test/recipes/80-test_ocsp.t b/test/recipes/80-test_ocsp.t
index cec3d7d64a..fc7f6971d8 100644
--- a/test/recipes/80-test_ocsp.t
+++ b/test/recipes/80-test_ocsp.t
@@ -38,23 +38,40 @@ sub test_ocsp {
my $expected_exit = shift;
my $nochecks = shift;
my $opt_untrusted = shift // "-verify_other";
+ my $certfile = shift;
my $outputfile = basename($inputfile, '.ors') . '.dat';
+ my %appopts = defined($certfile)
+ ? (stdout => "$outputfile.out", stderr => "$outputfile.err") : ();
run(app(["openssl", "base64", "-d",
"-in", catfile($ocspdir,$inputfile),
"-out", $outputfile]));
my @certopt = ($opt_untrusted, catfile($ocspdir, $untrusted));
+ my @requestopt = defined($certfile)
+ ? ("-issuer", catfile($ocspdir, $CAfile),
+ "-cert", catfile($ocspdir, $certfile), "-no_nonce")
+ : ();
with({ exit_checker => sub { return shift == $expected_exit; } },
sub { ok(run(app(["openssl", "ocsp", "-respin", $outputfile,
+ @requestopt,
"-partial_chain", @check_time,
"-CAfile", catfile($ocspdir, $CAfile),
@certopt,
"-no-CApath", "-no-CAstore",
- $nochecks ? "-no_cert_checks" : ()])),
+ $nochecks ? "-no_cert_checks" : ()], %appopts)),
$title); });
+
+ return unless defined($certfile);
+ my $output = '';
+ foreach my $suffix (qw(out err)) {
+ open my $fh, '<', "$outputfile.$suffix"
+ or die "Cannot open $outputfile.$suffix: $!";
+ $output .= join('', <$fh>);
+ }
+ return $output;
}
-plan tests => 15;
+plan tests => 16;
subtest "=== VALID OCSP RESPONSES ===" => sub {
plan tests => 7;
@@ -75,6 +92,20 @@ subtest "=== VALID OCSP RESPONSES ===" => sub {
"D3.ors", "D3_Issuer_Root.pem", "", 0, 0);
};
+subtest "=== INVALID OCSP RESPONSE TIMES ===" => sub {
+ plan tests => 3;
+
+ my $output = test_ocsp("NON-DELEGATED; expired response",
+ "ND1.ors", "ND1_Issuer_ICA.pem", "", 1, 0, undef,
+ "ND1_Cert_EE.pem");
+ like($output, qr/Response verify OK/, "response signature verified");
+ SKIP: {
+ skip "Error strings disabled", 1
+ if disabled("err") || disabled("autoerrinit");
+ like($output, qr/status expired/, "response status expired");
+ }
+};
+
subtest "=== INVALID SIGNATURE on the OCSP RESPONSE ===" => sub {
plan tests => 6;