Commit 3986e51059 for openssl.org

commit 3986e51059db880b6795d42a9f4b0f9b2fb8fc90
Author: Bob Beck <beck@openssl.org>
Date:   Fri Sep 4 14:34:14 2026 -0600

    Remove the library context from X509_REQ

    The X509_PUBKEY in a request holds the library context and property
    query it needs to decode the public key, and the X509_REQ carried a
    copy, just as X509 did. Worse, X509_REQ_new_ex() created the request
    with ASN1_item_new() rather than ASN1_item_new_ex(), so only the copy
    got the context and the public key was decoded in the default one.

    Drop the copy, create the request with ASN1_item_new_ex() so the
    X509_PUBKEY is seeded, and take the context from it in
    X509_REQ_sign(), X509_REQ_digest() and d2i_X509_REQ_bio(). Remove
    ossl_x509_req_set0_libctx(), which had no other callers.

    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/x509/x_all.c b/crypto/x509/x_all.c
index f102a74989..11ea028332 100644
--- a/crypto/x509/x_all.c
+++ b/crypto/x509/x_all.c
@@ -275,6 +275,8 @@ X509 *X509_load_http(const char *url, BIO *bio, BIO *rbio, int timeout)
 int X509_REQ_sign(X509_REQ *x, EVP_PKEY *pkey, const EVP_MD *md)
 {
     STACK_OF(X509_EXTENSION) *exts;
+    OSSL_LIB_CTX *libctx;
+    const char *propq;
     int bad = 0;

     if (x == NULL) {
@@ -287,9 +289,10 @@ int X509_REQ_sign(X509_REQ *x, EVP_PKEY *pkey, const EVP_MD *md)
     if (bad)
         return 0;
     x->req_info.enc.modified = 1;
+    ossl_x509_req_get0_libctx(x, &libctx, &propq);
     return ASN1_item_sign_ex(ASN1_ITEM_rptr(X509_REQ_INFO), &x->sig_alg, NULL,
         x->signature, &x->req_info, NULL,
-        pkey, md, x->libctx, x->propq);
+        pkey, md, libctx, propq);
 }

 int X509_REQ_sign_ctx(X509_REQ *x, EVP_MD_CTX *ctx)
@@ -470,10 +473,8 @@ X509_REQ *d2i_X509_REQ_bio(BIO *bp, X509_REQ **req)
     OSSL_LIB_CTX *libctx = NULL;
     const char *propq = NULL;

-    if (req != NULL && *req != NULL) {
-        libctx = (*req)->libctx;
-        propq = (*req)->propq;
-    }
+    if (req != NULL && *req != NULL)
+        ossl_x509_req_get0_libctx(*req, &libctx, &propq);

     return ASN1_item_d2i_bio_ex(ASN1_ITEM_rptr(X509_REQ), bp, req, libctx, propq);
 }
@@ -809,8 +810,12 @@ int X509_CRL_digest(const X509_CRL *data, const EVP_MD *type,
 int X509_REQ_digest(const X509_REQ *data, const EVP_MD *type,
     unsigned char *md, unsigned int *len)
 {
+    OSSL_LIB_CTX *libctx;
+    const char *propq;
+
+    ossl_x509_req_get0_libctx(data, &libctx, &propq);
     return ossl_asn1_item_digest_ex(ASN1_ITEM_rptr(X509_REQ), type, (char *)data,
-        md, len, data->libctx, data->propq);
+        md, len, libctx, propq);
 }

 int X509_NAME_digest(const X509_NAME *data, const EVP_MD *type,
diff --git a/crypto/x509/x_req.c b/crypto/x509/x_req.c
index 5137885a5b..5a70edda2f 100644
--- a/crypto/x509/x_req.c
+++ b/crypto/x509/x_req.c
@@ -60,13 +60,10 @@ static int req_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it,

     case ASN1_OP_FREE_POST:
         ASN1_OCTET_STRING_free(ret->distinguishing_id);
-        OPENSSL_free(ret->propq);
         break;
     case ASN1_OP_DUP_POST: {
         X509_REQ *old = exarg;

-        if (!ossl_x509_req_set0_libctx(ret, old->libctx, old->propq))
-            return 0;
         if (old->req_info.pubkey != NULL) {
             EVP_PKEY *pkey = X509_PUBKEY_get0(old->req_info.pubkey);

@@ -85,16 +82,12 @@ static int req_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it,
             }
         }
     } break;
-    case ASN1_OP_GET0_LIBCTX: {
-        OSSL_LIB_CTX **libctx = exarg;
-
-        *libctx = ret->libctx;
-    } break;
-    case ASN1_OP_GET0_PROPQ: {
-        const char **propq = exarg;
-
-        *propq = ret->propq;
-    } break;
+    case ASN1_OP_GET0_LIBCTX:
+        ossl_x509_req_get0_libctx(ret, exarg, NULL);
+        break;
+    case ASN1_OP_GET0_PROPQ:
+        ossl_x509_req_get0_libctx(ret, NULL, exarg);
+        break;
     }

     return 1;
@@ -133,35 +126,18 @@ ASN1_OCTET_STRING *X509_REQ_get0_distinguishing_id(X509_REQ *x)
     return x->distinguishing_id;
 }

-/*
- * This should only be used if the X509_REQ object was embedded inside another
- * asn1 object and it needs a libctx to operate.
- * Use X509_REQ_new_ex() instead if possible.
- */
-int ossl_x509_req_set0_libctx(X509_REQ *x, OSSL_LIB_CTX *libctx,
-    const char *propq)
+void ossl_x509_req_get0_libctx(const X509_REQ *x, OSSL_LIB_CTX **libctx,
+    const char **propq)
 {
-    if (x != NULL) {
-        x->libctx = libctx;
-        OPENSSL_free(x->propq);
-        x->propq = NULL;
-        if (propq != NULL) {
-            x->propq = OPENSSL_strdup(propq);
-            if (x->propq == NULL)
-                return 0;
-        }
-    }
-    return 1;
+    if (libctx != NULL)
+        *libctx = NULL;
+    if (propq != NULL)
+        *propq = NULL;
+    if (x->req_info.pubkey != NULL)
+        (void)ossl_x509_PUBKEY_get0_libctx(libctx, propq, x->req_info.pubkey);
 }

 X509_REQ *X509_REQ_new_ex(OSSL_LIB_CTX *libctx, const char *propq)
 {
-    X509_REQ *req = NULL;
-
-    req = (X509_REQ *)ASN1_item_new(ASN1_ITEM_rptr(X509_REQ));
-    if (!ossl_x509_req_set0_libctx(req, libctx, propq)) {
-        X509_REQ_free(req);
-        req = NULL;
-    }
-    return req;
+    return (X509_REQ *)ASN1_item_new_ex(ASN1_ITEM_rptr(X509_REQ), libctx, propq);
 }
diff --git a/include/crypto/x509.h b/include/crypto/x509.h
index f58bd9e90e..6343322ecd 100644
--- a/include/crypto/x509.h
+++ b/include/crypto/x509.h
@@ -99,8 +99,6 @@ struct X509_req_st {

     /* Set on live certificates for authentication purposes */
     ASN1_OCTET_STRING *distinguishing_id;
-    OSSL_LIB_CTX *libctx;
-    char *propq;
 };

 struct X509_crl_info_st {
@@ -450,8 +448,18 @@ void ossl_x509_get0_libctx(const X509 *x, OSSL_LIB_CTX **libctx,
     const char **propq);
 int ossl_x509_crl_set0_libctx(X509_CRL *x, OSSL_LIB_CTX *libctx,
     const char *propq);
-int ossl_x509_req_set0_libctx(X509_REQ *x, OSSL_LIB_CTX *libctx,
-    const char *propq);
+/**
+ * @brief Get the library context and property query of a request.
+ *
+ * As for ossl_x509_get0_libctx(): the request has none of its own; the
+ * one given to X509_REQ_new_ex() is kept by its X509_PUBKEY.
+ *
+ * @param x the certificate request
+ * @param libctx where to store the library context, may be NULL
+ * @param propq where to store the property query, may be NULL
+ */
+void ossl_x509_req_get0_libctx(const X509_REQ *x, OSSL_LIB_CTX **libctx,
+    const char **propq);
 int ossl_asn1_item_digest_ex(const ASN1_ITEM *it, const EVP_MD *type,
     void *data, unsigned char *md, unsigned int *len,
     OSSL_LIB_CTX *libctx, const char *propq);