Commit 2de7a90e7f for openssl.org

commit 2de7a90e7ff07f975de83618b216d6f94763c4a8
Author: Bob Beck <beck@openssl.org>
Date:   Thu Oct 8 11:50:28 2026 -0600

    Verify an OCSP signer's chain in the signer's library context

    The OCSP signature is checked in the signer's library context, but the
    signer's chain was verified in the default one. Create the
    X509_STORE_CTX in the signer's library context too.

    This was a pre-existing issue, but surfaced by these changes.

    Reviewed-by: Tomas Mraz <tomas@openssl.foundation>
    Reviewed-by: Dmitry Belyavskiy <beldmit@gmail.com>
    Merge-date: Mon Oct 26 19:04:41 2026
    Merged-from: https://github.com/openssl/openssl/pull/32690

diff --git a/crypto/ocsp/ocsp_vfy.c b/crypto/ocsp/ocsp_vfy.c
index e6dd9e4bb6..458710d1e3 100644
--- a/crypto/ocsp/ocsp_vfy.c
+++ b/crypto/ocsp/ocsp_vfy.c
@@ -31,11 +31,15 @@ static int ocsp_verify_signer(X509 *signer, int response,
     X509_STORE *st, unsigned long flags,
     STACK_OF(X509) *untrusted, STACK_OF(X509) **chain)
 {
-    X509_STORE_CTX *ctx = X509_STORE_CTX_new();
+    OSSL_LIB_CTX *libctx;
+    const char *propq;
+    X509_STORE_CTX *ctx;
     X509_VERIFY_PARAM *vp;
     int ret = -1;

-    if (ctx == NULL) {
+    /* The chain is verified in the signer's library context, as the signature is */
+    ossl_x509_get0_libctx(signer, &libctx, &propq);
+    if ((ctx = X509_STORE_CTX_new_ex(libctx, propq)) == NULL) {
         ERR_raise(ERR_LIB_OCSP, ERR_R_X509_LIB);
         goto end;
     }
diff --git a/test/ocspapitest.c b/test/ocspapitest.c
index 4e9861e5ed..2444b85b05 100644
--- a/test/ocspapitest.c
+++ b/test/ocspapitest.c
@@ -15,11 +15,16 @@
 #include <openssl/x509.h>
 #include <openssl/asn1.h>
 #include <openssl/pem.h>
+#include <openssl/provider.h>
+#include <openssl/evp.h>

 #include "testutil.h"

 static const char *certstr;
 static const char *privkeystr;
+static const char *eecertstr;
+static const char *eekeystr;
+static const char *cacertstr;

 #ifndef OPENSSL_NO_OCSP
 static int get_cert_and_key(X509 **cert_out, EVP_PKEY **key_out)
@@ -213,9 +218,47 @@ err:
     return ret;
 }

+/*
+ * A request whose signer and issuer are decoded in their own library
+ * context verifies while the default library context can fetch nothing.
+ */
+static int test_req_verify_signer_libctx(void)
+{
+    OSSL_LIB_CTX *libctx = NULL;
+    OSSL_PROVIDER *prov = NULL;
+    X509 *signer = NULL, *ca = NULL;
+    EVP_PKEY *key = NULL;
+    X509_STORE *store = NULL;
+    OCSP_REQUEST *req = NULL;
+    int ret = 0;
+
+    if (!TEST_ptr(libctx = OSSL_LIB_CTX_new())
+        || !TEST_ptr(prov = OSSL_PROVIDER_load(libctx, "default"))
+        || !TEST_ptr(signer = load_cert_pem(eecertstr, libctx))
+        || !TEST_ptr(ca = load_cert_pem(cacertstr, libctx))
+        || !TEST_ptr(key = load_pkey_pem(eekeystr, libctx))
+        || !TEST_ptr(store = X509_STORE_new())
+        || !TEST_true(X509_STORE_add_cert(store, ca))
+        || !TEST_ptr(req = OCSP_REQUEST_new())
+        || !TEST_true(OCSP_request_sign(req, signer, key, EVP_sha256(), NULL, 0))
+        || !TEST_true(EVP_set_default_properties(NULL, "provider=absent")))
+        goto end;
+    ret = TEST_int_gt(OCSP_request_verify(req, NULL, store, OCSP_PARTIAL_CHAIN), 0);
+    EVP_set_default_properties(NULL, "");
+end:
+    OCSP_REQUEST_free(req);
+    X509_STORE_free(store);
+    EVP_PKEY_free(key);
+    X509_free(ca);
+    X509_free(signer);
+    OSSL_PROVIDER_unload(prov);
+    OSSL_LIB_CTX_free(libctx);
+    return ret;
+}
+
 #endif /* OPENSSL_NO_OCSP */

-OPT_TEST_DECLARE_USAGE("certfile privkeyfile\n")
+OPT_TEST_DECLARE_USAGE("certfile privkeyfile eecertfile eekeyfile cacertfile\n")

 int setup_tests(void)
 {
@@ -225,12 +268,16 @@ int setup_tests(void)
     }

     if (!TEST_ptr(certstr = test_get_argument(0))
-        || !TEST_ptr(privkeystr = test_get_argument(1)))
+        || !TEST_ptr(privkeystr = test_get_argument(1))
+        || !TEST_ptr(eecertstr = test_get_argument(2))
+        || !TEST_ptr(eekeystr = test_get_argument(3))
+        || !TEST_ptr(cacertstr = test_get_argument(4)))
         return 0;
 #ifndef OPENSSL_NO_OCSP
     ADD_TEST(test_resp_signer);
     ADD_ALL_TESTS(test_access_description, 3);
     ADD_TEST(test_ocsp_url_svcloc_new);
+    ADD_TEST(test_req_verify_signer_libctx);
 #endif
     return 1;
 }
diff --git a/test/recipes/80-test_ocsp.t b/test/recipes/80-test_ocsp.t
index fc7f6971d8..82c3c4d98d 100644
--- a/test/recipes/80-test_ocsp.t
+++ b/test/recipes/80-test_ocsp.t
@@ -15,7 +15,7 @@ use File::Spec::Functions qw/devnull catfile/;
 use File::Basename;
 use File::Copy;
 use File::Compare qw/compare/;
-use OpenSSL::Test qw/:DEFAULT with pipe srctop_dir data_file/;
+use OpenSSL::Test qw/:DEFAULT with pipe srctop_dir srctop_file data_file/;
 use OpenSSL::Test::Utils;

 setup("test_ocsp");
@@ -259,7 +259,10 @@ my $key = data_file("key.pem");
 subtest "=== OCSP API TESTS===" => sub {
     plan tests => 1;

-    ok(run(test(["ocspapitest", $cert, $key])),
+    ok(run(test(["ocspapitest", $cert, $key,
+                 srctop_file("test", "certs", "ee-cert.pem"),
+                 srctop_file("test", "certs", "ee-key.pem"),
+                 srctop_file("test", "certs", "ca-cert.pem")])),
                  "running ocspapitest");
 };