[openssl] master update

Dr. Paul Dale pauli at openssl.org
Sat Jun 5 07:41:28 UTC 2021


The branch master has been updated
       via  3d9d1ce52904660757dadeb629926932abe25158 (commit)
       via  d2b6c06274f37c5c6c967939ee556c4be5b568d0 (commit)
       via  7be04a3ac40fb6cf83be2c619dc30625988c6742 (commit)
       via  6282d6c28456543734defc45f653adeec1362958 (commit)
       via  c6313780586f94b0542f55c3ffa399f5ad2c7297 (commit)
       via  5dca2afca3f5de55f3de3a404ede1a96c6d9af26 (commit)
       via  dea2878fac8bde549fa0dd3b8e895703b174391b (commit)
       via  c8a9af97c928118ae4626d793d0b73552648b7ea (commit)
       via  62653483464b78ae57bff9b807ee3328e0f078f3 (commit)
       via  d6ded941c94803adf090f17093c8ff905f259ca8 (commit)
      from  f43f9d6313e31e90bb33a7f6f2fc0c657ef8495a (commit)


- Log -----------------------------------------------------------------
commit 3d9d1ce52904660757dadeb629926932abe25158
Author: Matt Caswell <matt at openssl.org>
Date:   Tue Jun 1 15:17:38 2021 +0100

    Add documentation for newly added ASN1 functions
    
    Reviewed-by: Shane Lontis <shane.lontis at oracle.com>
    Reviewed-by: Paul Dale <pauli at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/15591)

commit d2b6c06274f37c5c6c967939ee556c4be5b568d0
Author: Matt Caswell <matt at openssl.org>
Date:   Thu May 27 15:03:06 2021 +0100

    Ensure libctx/propq is propagated when handling X509_REQ
    
    When we create via d2i or dup an X509_REQ we should ensure that the libctx
    is properly propagated. We also ensure we create X509_REQ objects with the
    proper libctx assigned in the CMP tests.
    
    Reviewed-by: Shane Lontis <shane.lontis at oracle.com>
    Reviewed-by: Paul Dale <pauli at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/15591)

commit 7be04a3ac40fb6cf83be2c619dc30625988c6742
Author: Matt Caswell <matt at openssl.org>
Date:   Thu May 27 10:56:02 2021 +0100

    Give ASN.1 objects the ability to report their libctx/propq
    
    Some ASN.1 objects have an embedded libctx/propq. If they have one we
    give the ASN.1 code the ability to find these values and use them where
    needed. This is used for OSSL_CMP_MSG_dup() and X509_dup().
    
    Reviewed-by: Shane Lontis <shane.lontis at oracle.com>
    Reviewed-by: Paul Dale <pauli at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/15591)

commit 6282d6c28456543734defc45f653adeec1362958
Author: Matt Caswell <matt at openssl.org>
Date:   Thu May 27 09:00:47 2021 +0100

    Make sure X509_dup() also dup's any associated EVP_PKEY
    
    Otherwise we can end up with a blank EVP_PKEY. If it is later recreated
    it can end up with the wrong libctx/propq.
    
    Reviewed-by: Shane Lontis <shane.lontis at oracle.com>
    Reviewed-by: Paul Dale <pauli at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/15591)

commit c6313780586f94b0542f55c3ffa399f5ad2c7297
Author: Matt Caswell <matt at openssl.org>
Date:   Wed May 26 17:18:13 2021 +0100

    Use the new ASN.1 libctx aware capabilities in CMP
    
    Make sure we pass the libctx/propq around everywhere that we need it to
    ensure we get provider keys when needed.
    
    Reviewed-by: Shane Lontis <shane.lontis at oracle.com>
    Reviewed-by: Paul Dale <pauli at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/15591)

commit 5dca2afca3f5de55f3de3a404ede1a96c6d9af26
Author: Matt Caswell <matt at openssl.org>
Date:   Tue May 25 17:46:11 2021 +0100

    Use the new ASN.1 libctx aware functions in CMS
    
    Make sure we pass the libctx around when working with CMS structures
    
    Reviewed-by: Shane Lontis <shane.lontis at oracle.com>
    Reviewed-by: Paul Dale <pauli at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/15591)

commit dea2878fac8bde549fa0dd3b8e895703b174391b
Author: Matt Caswell <matt at openssl.org>
Date:   Tue May 25 17:16:18 2021 +0100

    Teach more of the ASN.1 code about libctx/propq
    
    Make sure we pass libctx/propq down to all the layers so that objects that
    are created during parsing have the right values. Then use this new
    capability for PKCS7.
    
    Reviewed-by: Shane Lontis <shane.lontis at oracle.com>
    Reviewed-by: Paul Dale <pauli at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/15591)

commit c8a9af97c928118ae4626d793d0b73552648b7ea
Author: Matt Caswell <matt at openssl.org>
Date:   Fri May 21 17:25:05 2021 +0100

    Teach the ASN.1 code how to create embedded objects with libctx/propq
    
    An ASN.1 object such as an X509 may have embedded objects in it such as
    an X509_PUBKEY. If there is a libctx/propq in use then we need to make sure
    we pass these down to the constructors of these embedded objects.
    
    Reviewed-by: Shane Lontis <shane.lontis at oracle.com>
    Reviewed-by: Paul Dale <pauli at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/15591)

commit 62653483464b78ae57bff9b807ee3328e0f078f3
Author: Matt Caswell <matt at openssl.org>
Date:   Fri May 21 15:50:43 2021 +0100

    Fix evp_extra_test to use libctx in an X509_PUBKEY
    
    Reviewed-by: Shane Lontis <shane.lontis at oracle.com>
    Reviewed-by: Paul Dale <pauli at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/15591)

commit d6ded941c94803adf090f17093c8ff905f259ca8
Author: Matt Caswell <matt at openssl.org>
Date:   Fri May 21 15:50:09 2021 +0100

    Provide the ability to create an X509_PUBKEY with a libctx/propq
    
    Reviewed-by: Shane Lontis <shane.lontis at oracle.com>
    Reviewed-by: Paul Dale <pauli at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/15591)

-----------------------------------------------------------------------

Summary of changes:
 apps/cmp.c                     |   2 +-
 crypto/asn1/a_d2i_fp.c         |  20 ++-
 crypto/asn1/a_dup.c            |  13 +-
 crypto/asn1/asn1_local.h       |   3 +
 crypto/asn1/asn_mime.c         |  16 ++-
 crypto/asn1/tasn_dec.c         | 100 ++++++++++-----
 crypto/asn1/tasn_new.c         |  47 +++++--
 crypto/cmp/cmp_asn.c           |  44 ++++++-
 crypto/cmp/cmp_local.h         |   7 +-
 crypto/cmp/cmp_msg.c           |  92 ++++++++++++-
 crypto/cms/cms_io.c            |  13 +-
 crypto/cms/cms_lib.c           |  10 +-
 crypto/pkcs7/pk7_asn1.c        |  13 +-
 crypto/pkcs7/pk7_mime.c        |   9 +-
 crypto/x509/x_all.c            |  29 ++++-
 crypto/x509/x_pubkey.c         |  39 ++++--
 crypto/x509/x_req.c            |  31 +++++
 crypto/x509/x_x509.c           |  33 ++++-
 doc/build.info                 |  18 +++
 doc/man3/ASN1_EXTERN_FUNCS.pod | 181 ++++++++++++++++++++++++++
 doc/man3/ASN1_aux_cb.pod       | 284 +++++++++++++++++++++++++++++++++++++++++
 doc/man3/ASN1_item_d2i_bio.pod |  53 +++++++-
 doc/man3/ASN1_item_new.pod     |  45 +++++++
 doc/man3/SMIME_read_ASN1.pod   |   8 +-
 doc/man3/X509_PUBKEY_new.pod   |  15 ++-
 doc/man7/migration_guide.pod   |  12 +-
 include/openssl/asn1.h.in      |  14 +-
 include/openssl/asn1t.h.in     |  12 +-
 include/openssl/cmp.h.in       |   3 +-
 include/openssl/x509.h.in      |   1 +
 test/cmp_client_test.c         |   2 +-
 test/cmp_msg_test.c            |   4 +-
 test/cmp_protect_test.c        |  10 +-
 test/cmp_server_test.c         |   2 +-
 test/cmp_vfy_test.c            |  28 ++--
 test/evp_extra_test.c          |  10 +-
 test/helpers/cmp_testlib.c     |   4 +-
 test/helpers/cmp_testlib.h     |   2 +-
 test/testutil.h                |   2 +-
 test/testutil/load.c           |   7 +-
 util/libcrypto.num             |   5 +
 util/missingcrypto.txt         |   4 -
 util/other.syms                |  13 ++
 43 files changed, 1111 insertions(+), 149 deletions(-)
 create mode 100644 doc/man3/ASN1_EXTERN_FUNCS.pod
 create mode 100644 doc/man3/ASN1_aux_cb.pod
 create mode 100644 doc/man3/ASN1_item_new.pod

diff --git a/apps/cmp.c b/apps/cmp.c
index 03530f2584..dfd2981425 100644
--- a/apps/cmp.c
+++ b/apps/cmp.c
@@ -729,7 +729,7 @@ static OSSL_CMP_MSG *read_PKIMESSAGE(char **filenames)
     file = *filenames;
     *filenames = next_item(file);
 
-    ret = OSSL_CMP_MSG_read(file);
+    ret = OSSL_CMP_MSG_read(file, app_get0_libctx(), app_get0_propq());
     if (ret == NULL)
         CMP_err1("cannot read PKIMessage from file '%s'", file);
     return ret;
diff --git a/crypto/asn1/a_d2i_fp.c b/crypto/asn1/a_d2i_fp.c
index f1e96b2eaf..e8602053f9 100644
--- a/crypto/asn1/a_d2i_fp.c
+++ b/crypto/asn1/a_d2i_fp.c
@@ -55,7 +55,8 @@ void *ASN1_d2i_bio(void *(*xnew) (void), d2i_of_void *d2i, BIO *in, void **x)
 
 #endif
 
-void *ASN1_item_d2i_bio(const ASN1_ITEM *it, BIO *in, void *x)
+void *ASN1_item_d2i_bio_ex(const ASN1_ITEM *it, BIO *in, void *x,
+                           OSSL_LIB_CTX *libctx, const char *propq)
 {
     BUF_MEM *b = NULL;
     const unsigned char *p;
@@ -69,14 +70,20 @@ void *ASN1_item_d2i_bio(const ASN1_ITEM *it, BIO *in, void *x)
         goto err;
 
     p = (const unsigned char *)b->data;
-    ret = ASN1_item_d2i(x, &p, len, it);
+    ret = ASN1_item_d2i_ex(x, &p, len, it, libctx, propq);
  err:
     BUF_MEM_free(b);
     return ret;
 }
 
+void *ASN1_item_d2i_bio(const ASN1_ITEM *it, BIO *in, void *x)
+{
+    return ASN1_item_d2i_bio_ex(it, in, x, NULL, NULL);
+}
+
 #ifndef OPENSSL_NO_STDIO
-void *ASN1_item_d2i_fp(const ASN1_ITEM *it, FILE *in, void *x)
+void *ASN1_item_d2i_fp_ex(const ASN1_ITEM *it, FILE *in, void *x,
+                          OSSL_LIB_CTX *libctx, const char *propq)
 {
     BIO *b;
     char *ret;
@@ -86,10 +93,15 @@ void *ASN1_item_d2i_fp(const ASN1_ITEM *it, FILE *in, void *x)
         return NULL;
     }
     BIO_set_fp(b, in, BIO_NOCLOSE);
-    ret = ASN1_item_d2i_bio(it, b, x);
+    ret = ASN1_item_d2i_bio_ex(it, b, x, libctx, propq);
     BIO_free(b);
     return ret;
 }
+
+void *ASN1_item_d2i_fp(const ASN1_ITEM *it, FILE *in, void *x)
+{
+    return ASN1_item_d2i_fp_ex(it, in, x, NULL, NULL);
+}
 #endif
 
 #define HEADER_SIZE   8
diff --git a/crypto/asn1/a_dup.c b/crypto/asn1/a_dup.c
index 2fa3ccd28a..93e8b2aa8d 100644
--- a/crypto/asn1/a_dup.c
+++ b/crypto/asn1/a_dup.c
@@ -56,6 +56,8 @@ void *ASN1_item_dup(const ASN1_ITEM *it, const void *x)
     const unsigned char *p;
     long i;
     ASN1_VALUE *ret;
+    OSSL_LIB_CTX *libctx = NULL;
+    const char *propq = NULL;
 
     if (x == NULL)
         return NULL;
@@ -67,9 +69,12 @@ void *ASN1_item_dup(const ASN1_ITEM *it, const void *x)
         asn1_cb = aux != NULL ? aux->asn1_cb : NULL;
     }
 
-    if (asn1_cb != NULL
-        && !asn1_cb(ASN1_OP_DUP_PRE, (ASN1_VALUE **)&x, it, NULL))
-        goto auxerr;
+    if (asn1_cb != NULL) {
+        if (!asn1_cb(ASN1_OP_DUP_PRE, (ASN1_VALUE **)&x, it, NULL)
+                || !asn1_cb(ASN1_OP_GET0_LIBCTX, (ASN1_VALUE **)&x, it, &libctx)
+                || !asn1_cb(ASN1_OP_GET0_PROPQ, (ASN1_VALUE **)&x, it, &propq))
+            goto auxerr;
+    }
 
     i = ASN1_item_i2d(x, &b, it);
     if (b == NULL) {
@@ -77,7 +82,7 @@ void *ASN1_item_dup(const ASN1_ITEM *it, const void *x)
         return NULL;
     }
     p = b;
-    ret = ASN1_item_d2i(NULL, &p, i, it);
+    ret = ASN1_item_d2i_ex(NULL, &p, i, it, libctx, propq);
     OPENSSL_free(b);
 
     if (asn1_cb != NULL
diff --git a/crypto/asn1/asn1_local.h b/crypto/asn1/asn1_local.h
index 15843ac689..f73bd8fc6a 100644
--- a/crypto/asn1/asn1_local.h
+++ b/crypto/asn1/asn1_local.h
@@ -89,3 +89,6 @@ int ossl_c2i_uint64_int(uint64_t *ret, int *neg, const unsigned char **pp,
 int ossl_i2c_uint64_int(unsigned char *p, uint64_t r, int neg);
 
 ASN1_TIME *ossl_asn1_time_from_tm(ASN1_TIME *s, struct tm *ts, int type);
+
+int ossl_asn1_item_ex_new_intern(ASN1_VALUE **pval, const ASN1_ITEM *it,
+                                 OSSL_LIB_CTX *libctx, const char *propq);
diff --git a/crypto/asn1/asn_mime.c b/crypto/asn1/asn_mime.c
index 1c1f72f800..1b8ac34106 100644
--- a/crypto/asn1/asn_mime.c
+++ b/crypto/asn1/asn_mime.c
@@ -130,7 +130,8 @@ int PEM_write_bio_ASN1_stream(BIO *out, ASN1_VALUE *val, BIO *in, int flags,
     return r;
 }
 
-static ASN1_VALUE *b64_read_asn1(BIO *bio, const ASN1_ITEM *it, ASN1_VALUE **x)
+static ASN1_VALUE *b64_read_asn1(BIO *bio, const ASN1_ITEM *it, ASN1_VALUE **x,
+                                 OSSL_LIB_CTX *libctx, const char *propq)
 {
     BIO *b64;
     ASN1_VALUE *val;
@@ -140,7 +141,7 @@ static ASN1_VALUE *b64_read_asn1(BIO *bio, const ASN1_ITEM *it, ASN1_VALUE **x)
         return 0;
     }
     bio = BIO_push(b64, bio);
-    val = ASN1_item_d2i_bio(it, bio, x);
+    val = ASN1_item_d2i_bio_ex(it, bio, x, libctx, propq);
     if (!val)
         ERR_raise(ERR_LIB_ASN1, ASN1_R_DECODE_ERROR);
     (void)BIO_flush(bio);
@@ -388,8 +389,9 @@ static int asn1_output_data(BIO *out, BIO *data, ASN1_VALUE *val, int flags,
  * opaque this is set to NULL
  */
 
-ASN1_VALUE *SMIME_read_ASN1_ex(BIO *bio, int flags, BIO **bcont, const ASN1_ITEM *it,
-                               ASN1_VALUE **x)
+ASN1_VALUE *SMIME_read_ASN1_ex(BIO *bio, int flags, BIO **bcont,
+                               const ASN1_ITEM *it, ASN1_VALUE **x,
+                               OSSL_LIB_CTX *libctx, const char *propq)
 {
     BIO *asnin;
     STACK_OF(MIME_HEADER) *headers = NULL;
@@ -461,7 +463,7 @@ ASN1_VALUE *SMIME_read_ASN1_ex(BIO *bio, int flags, BIO **bcont, const ASN1_ITEM
         }
         sk_MIME_HEADER_pop_free(headers, mime_hdr_free);
         /* Read in ASN1 */
-        if ((val = b64_read_asn1(asnin, it, x)) == NULL) {
+        if ((val = b64_read_asn1(asnin, it, x, libctx, propq)) == NULL) {
             ERR_raise(ERR_LIB_ASN1, ASN1_R_ASN1_SIG_PARSE_ERROR);
             sk_BIO_pop_free(parts, BIO_vfree);
             return NULL;
@@ -489,7 +491,7 @@ ASN1_VALUE *SMIME_read_ASN1_ex(BIO *bio, int flags, BIO **bcont, const ASN1_ITEM
 
     sk_MIME_HEADER_pop_free(headers, mime_hdr_free);
 
-    if ((val = b64_read_asn1(bio, it, x)) == NULL) {
+    if ((val = b64_read_asn1(bio, it, x, libctx, propq)) == NULL) {
         ERR_raise(ERR_LIB_ASN1, ASN1_R_ASN1_PARSE_ERROR);
         return NULL;
     }
@@ -498,7 +500,7 @@ ASN1_VALUE *SMIME_read_ASN1_ex(BIO *bio, int flags, BIO **bcont, const ASN1_ITEM
 
 ASN1_VALUE *SMIME_read_ASN1(BIO *bio, BIO **bcont, const ASN1_ITEM *it)
 {
-    return SMIME_read_ASN1_ex(bio, 0, bcont, it, NULL);
+    return SMIME_read_ASN1_ex(bio, 0, bcont, it, NULL, NULL, NULL);
 }
 
 /* Copy text from one BIO to another making the output CRLF at EOL */
diff --git a/crypto/asn1/tasn_dec.c b/crypto/asn1/tasn_dec.c
index aaf3de7e19..eff67d87fc 100644
--- a/crypto/asn1/tasn_dec.c
+++ b/crypto/asn1/tasn_dec.c
@@ -28,7 +28,8 @@
 static int asn1_item_embed_d2i(ASN1_VALUE **pval, const unsigned char **in,
                                long len, const ASN1_ITEM *it,
                                int tag, int aclass, char opt, ASN1_TLC *ctx,
-                               int depth);
+                               int depth, OSSL_LIB_CTX *libctx,
+                               const char *propq);
 
 static int asn1_check_eoc(const unsigned char **in, long len);
 static int asn1_find_end(const unsigned char **in, long len, char inf);
@@ -46,11 +47,13 @@ static int asn1_check_tlen(long *olen, int *otag, unsigned char *oclass,
 static int asn1_template_ex_d2i(ASN1_VALUE **pval,
                                 const unsigned char **in, long len,
                                 const ASN1_TEMPLATE *tt, char opt,
-                                ASN1_TLC *ctx, int depth);
+                                ASN1_TLC *ctx, int depth, OSSL_LIB_CTX *libctx,
+                                const char *propq);
 static int asn1_template_noexp_d2i(ASN1_VALUE **val,
                                    const unsigned char **in, long len,
                                    const ASN1_TEMPLATE *tt, char opt,
-                                   ASN1_TLC *ctx, int depth);
+                                   ASN1_TLC *ctx, int depth,
+                                   OSSL_LIB_CTX *libctx, const char *propq);
 static int asn1_d2i_ex_primitive(ASN1_VALUE **pval,
                                  const unsigned char **in, long len,
                                  const ASN1_ITEM *it,
@@ -101,9 +104,36 @@ unsigned long ASN1_tag2bit(int tag)
  * this will simply be a special case.
  */
 
-ASN1_VALUE *ASN1_item_d2i(ASN1_VALUE **pval,
-                          const unsigned char **in, long len,
-                          const ASN1_ITEM *it)
+static int asn1_item_ex_d2i_intern(ASN1_VALUE **pval, const unsigned char **in,
+                                   long len, const ASN1_ITEM *it, int tag,
+                                   int aclass, char opt, ASN1_TLC *ctx,
+                                   OSSL_LIB_CTX *libctx, const char *propq)
+{
+    int rv;
+
+    if (pval == NULL || it == NULL) {
+        ERR_raise(ERR_LIB_ASN1, ERR_R_PASSED_NULL_PARAMETER);
+        return 0;
+    }
+    rv = asn1_item_embed_d2i(pval, in, len, it, tag, aclass, opt, ctx, 0,
+                             libctx, propq);
+    if (rv <= 0)
+        ASN1_item_ex_free(pval, it);
+    return rv;
+}
+
+int ASN1_item_ex_d2i(ASN1_VALUE **pval, const unsigned char **in, long len,
+                     const ASN1_ITEM *it,
+                     int tag, int aclass, char opt, ASN1_TLC *ctx)
+{
+    return asn1_item_ex_d2i_intern(pval, in, len, it, tag, aclass, opt, ctx,
+                                   NULL, NULL);
+}
+
+ASN1_VALUE *ASN1_item_d2i_ex(ASN1_VALUE **pval,
+                             const unsigned char **in, long len,
+                             const ASN1_ITEM *it, OSSL_LIB_CTX *libctx,
+                             const char *propq)
 {
     ASN1_TLC c;
     ASN1_VALUE *ptmpval = NULL;
@@ -111,25 +141,17 @@ ASN1_VALUE *ASN1_item_d2i(ASN1_VALUE **pval,
     if (pval == NULL)
         pval = &ptmpval;
     asn1_tlc_clear_nc(&c);
-    if (ASN1_item_ex_d2i(pval, in, len, it, -1, 0, 0, &c) > 0)
+    if (asn1_item_ex_d2i_intern(pval, in, len, it, -1, 0, 0, &c, libctx,
+                                propq) > 0)
         return *pval;
     return NULL;
 }
 
-int ASN1_item_ex_d2i(ASN1_VALUE **pval, const unsigned char **in, long len,
-                     const ASN1_ITEM *it,
-                     int tag, int aclass, char opt, ASN1_TLC *ctx)
+ASN1_VALUE *ASN1_item_d2i(ASN1_VALUE **pval,
+                          const unsigned char **in, long len,
+                          const ASN1_ITEM *it)
 {
-    int rv;
-
-    if (pval == NULL || it == NULL) {
-        ERR_raise(ERR_LIB_ASN1, ERR_R_PASSED_NULL_PARAMETER);
-        return 0;
-    }
-    rv = asn1_item_embed_d2i(pval, in, len, it, tag, aclass, opt, ctx, 0);
-    if (rv <= 0)
-        ASN1_item_ex_free(pval, it);
-    return rv;
+    return ASN1_item_d2i_ex(pval, in, len, it, NULL, NULL);
 }
 
 /*
@@ -140,7 +162,8 @@ int ASN1_item_ex_d2i(ASN1_VALUE **pval, const unsigned char **in, long len,
 static int asn1_item_embed_d2i(ASN1_VALUE **pval, const unsigned char **in,
                                long len, const ASN1_ITEM *it,
                                int tag, int aclass, char opt, ASN1_TLC *ctx,
-                               int depth)
+                               int depth, OSSL_LIB_CTX *libctx,
+                               const char *propq)
 {
     const ASN1_TEMPLATE *tt, *errtt = NULL;
     const ASN1_EXTERN_FUNCS *ef;
@@ -188,8 +211,8 @@ static int asn1_item_embed_d2i(ASN1_VALUE **pval, const unsigned char **in,
                           ASN1_R_ILLEGAL_OPTIONS_ON_ITEM_TEMPLATE);
                 goto err;
             }
-            return asn1_template_ex_d2i(pval, in, len,
-                                        it->templates, opt, ctx, depth);
+            return asn1_template_ex_d2i(pval, in, len, it->templates, opt, ctx,
+                                        depth, libctx, propq);
         }
         return asn1_d2i_ex_primitive(pval, in, len, it,
                                      tag, aclass, opt, ctx);
@@ -235,6 +258,9 @@ static int asn1_item_embed_d2i(ASN1_VALUE **pval, const unsigned char **in,
     case ASN1_ITYPE_EXTERN:
         /* Use new style d2i */
         ef = it->funcs;
+        if (ef->asn1_ex_d2i_ex != NULL)
+            return ef->asn1_ex_d2i_ex(pval, in, len, it, tag, aclass, opt, ctx,
+                                      libctx, propq);
         return ef->asn1_ex_d2i(pval, in, len, it, tag, aclass, opt, ctx);
 
     case ASN1_ITYPE_CHOICE:
@@ -258,7 +284,7 @@ static int asn1_item_embed_d2i(ASN1_VALUE **pval, const unsigned char **in,
                 ossl_asn1_template_free(pchptr, tt);
                 ossl_asn1_set_choice_selector(pval, -1, it);
             }
-        } else if (!ASN1_item_ex_new(pval, it)) {
+        } else if (!ossl_asn1_item_ex_new_intern(pval, it, libctx, propq)) {
             ERR_raise(ERR_LIB_ASN1, ERR_R_NESTED_ASN1_ERROR);
             goto err;
         }
@@ -269,7 +295,8 @@ static int asn1_item_embed_d2i(ASN1_VALUE **pval, const unsigned char **in,
             /*
              * We mark field as OPTIONAL so its absence can be recognised.
              */
-            ret = asn1_template_ex_d2i(pchptr, &p, len, tt, 1, ctx, depth);
+            ret = asn1_template_ex_d2i(pchptr, &p, len, tt, 1, ctx, depth,
+                                       libctx, propq);
             /* If field not present, try the next one */
             if (ret == -1)
                 continue;
@@ -335,7 +362,8 @@ static int asn1_item_embed_d2i(ASN1_VALUE **pval, const unsigned char **in,
             goto err;
         }
 
-        if (*pval == NULL && !ASN1_item_ex_new(pval, it)) {
+        if (*pval == NULL
+                && !ossl_asn1_item_ex_new_intern(pval, it, libctx, propq)) {
             ERR_raise(ERR_LIB_ASN1, ERR_R_NESTED_ASN1_ERROR);
             goto err;
         }
@@ -392,7 +420,7 @@ static int asn1_item_embed_d2i(ASN1_VALUE **pval, const unsigned char **in,
              */
 
             ret = asn1_template_ex_d2i(pseqval, &p, len, seqtt, isopt, ctx,
-                                       depth);
+                                       depth, libctx, propq);
             if (!ret) {
                 errtt = seqtt;
                 goto err;
@@ -468,7 +496,8 @@ static int asn1_item_embed_d2i(ASN1_VALUE **pval, const unsigned char **in,
 static int asn1_template_ex_d2i(ASN1_VALUE **val,
                                 const unsigned char **in, long inlen,
                                 const ASN1_TEMPLATE *tt, char opt,
-                                ASN1_TLC *ctx, int depth)
+                                ASN1_TLC *ctx, int depth,
+                                OSSL_LIB_CTX *libctx, const char *propq)
 {
     int flags, aclass;
     int ret;
@@ -502,7 +531,8 @@ static int asn1_template_ex_d2i(ASN1_VALUE **val,
             return 0;
         }
         /* We've found the field so it can't be OPTIONAL now */
-        ret = asn1_template_noexp_d2i(val, &p, len, tt, 0, ctx, depth);
+        ret = asn1_template_noexp_d2i(val, &p, len, tt, 0, ctx, depth, libctx,
+                                      propq);
         if (!ret) {
             ERR_raise(ERR_LIB_ASN1, ERR_R_NESTED_ASN1_ERROR);
             return 0;
@@ -525,7 +555,8 @@ static int asn1_template_ex_d2i(ASN1_VALUE **val,
             }
         }
     } else
-        return asn1_template_noexp_d2i(val, in, inlen, tt, opt, ctx, depth);
+        return asn1_template_noexp_d2i(val, in, inlen, tt, opt, ctx, depth,
+                                       libctx, propq);
 
     *in = p;
     return 1;
@@ -537,7 +568,8 @@ static int asn1_template_ex_d2i(ASN1_VALUE **val,
 static int asn1_template_noexp_d2i(ASN1_VALUE **val,
                                    const unsigned char **in, long len,
                                    const ASN1_TEMPLATE *tt, char opt,
-                                   ASN1_TLC *ctx, int depth)
+                                   ASN1_TLC *ctx, int depth,
+                                   OSSL_LIB_CTX *libctx, const char *propq)
 {
     int flags, aclass;
     int ret;
@@ -618,7 +650,7 @@ static int asn1_template_noexp_d2i(ASN1_VALUE **val,
             skfield = NULL;
             if (!asn1_item_embed_d2i(&skfield, &p, len,
                                      ASN1_ITEM_ptr(tt->item), -1, 0, 0, ctx,
-                                     depth)) {
+                                     depth, libctx, propq)) {
                 ERR_raise(ERR_LIB_ASN1, ERR_R_NESTED_ASN1_ERROR);
                 /* |skfield| may be partially allocated despite failure. */
                 ASN1_item_free(skfield, ASN1_ITEM_ptr(tt->item));
@@ -639,7 +671,7 @@ static int asn1_template_noexp_d2i(ASN1_VALUE **val,
         /* IMPLICIT tagging */
         ret = asn1_item_embed_d2i(val, &p, len,
                                   ASN1_ITEM_ptr(tt->item), tt->tag, aclass, opt,
-                                  ctx, depth);
+                                  ctx, depth, libctx, propq);
         if (!ret) {
             ERR_raise(ERR_LIB_ASN1, ERR_R_NESTED_ASN1_ERROR);
             goto err;
@@ -648,7 +680,7 @@ static int asn1_template_noexp_d2i(ASN1_VALUE **val,
     } else {
         /* Nothing special */
         ret = asn1_item_embed_d2i(val, &p, len, ASN1_ITEM_ptr(tt->item),
-                                  -1, 0, opt, ctx, depth);
+                                  -1, 0, opt, ctx, depth, libctx, propq);
         if (!ret) {
             ERR_raise(ERR_LIB_ASN1, ERR_R_NESTED_ASN1_ERROR);
             goto err;
diff --git a/crypto/asn1/tasn_new.c b/crypto/asn1/tasn_new.c
index 2ac9ab3e03..4b624bbdd4 100644
--- a/crypto/asn1/tasn_new.c
+++ b/crypto/asn1/tasn_new.c
@@ -16,11 +16,13 @@
 #include "asn1_local.h"
 
 static int asn1_item_embed_new(ASN1_VALUE **pval, const ASN1_ITEM *it,
-                               int embed);
+                               int embed, OSSL_LIB_CTX *libctx,
+                               const char *propq);
 static int asn1_primitive_new(ASN1_VALUE **pval, const ASN1_ITEM *it,
                               int embed);
 static void asn1_item_clear(ASN1_VALUE **pval, const ASN1_ITEM *it);
-static int asn1_template_new(ASN1_VALUE **pval, const ASN1_TEMPLATE *tt);
+static int asn1_template_new(ASN1_VALUE **pval, const ASN1_TEMPLATE *tt,
+                             OSSL_LIB_CTX *libctx, const char *propq);
 static void asn1_template_clear(ASN1_VALUE **pval, const ASN1_TEMPLATE *tt);
 static void asn1_primitive_clear(ASN1_VALUE **pval, const ASN1_ITEM *it);
 
@@ -32,14 +34,31 @@ ASN1_VALUE *ASN1_item_new(const ASN1_ITEM *it)
     return NULL;
 }
 
+ASN1_VALUE *ASN1_item_new_ex(const ASN1_ITEM *it, OSSL_LIB_CTX *libctx,
+                             const char *propq)
+{
+    ASN1_VALUE *ret = NULL;
+    if (asn1_item_embed_new(&ret, it, 0, libctx, propq) > 0)
+        return ret;
+    return NULL;
+}
+
 /* Allocate an ASN1 structure */
 
+
+int ossl_asn1_item_ex_new_intern(ASN1_VALUE **pval, const ASN1_ITEM *it,
+                                 OSSL_LIB_CTX *libctx, const char *propq)
+{
+    return asn1_item_embed_new(pval, it, 0, libctx, propq);
+}
+
 int ASN1_item_ex_new(ASN1_VALUE **pval, const ASN1_ITEM *it)
 {
-    return asn1_item_embed_new(pval, it, 0);
+    return asn1_item_embed_new(pval, it, 0, NULL, NULL);
 }
 
-int asn1_item_embed_new(ASN1_VALUE **pval, const ASN1_ITEM *it, int embed)
+int asn1_item_embed_new(ASN1_VALUE **pval, const ASN1_ITEM *it, int embed,
+                        OSSL_LIB_CTX *libctx, const char *propq)
 {
     const ASN1_TEMPLATE *tt = NULL;
     const ASN1_EXTERN_FUNCS *ef;
@@ -56,15 +75,20 @@ int asn1_item_embed_new(ASN1_VALUE **pval, const ASN1_ITEM *it, int embed)
 
     case ASN1_ITYPE_EXTERN:
         ef = it->funcs;
-        if (ef && ef->asn1_ex_new) {
-            if (!ef->asn1_ex_new(pval, it))
-                goto memerr;
+        if (ef != NULL) {
+            if (ef->asn1_ex_new_ex != NULL) {
+                if (!ef->asn1_ex_new_ex(pval, it, libctx, propq))
+                    goto memerr;
+            } else if (ef->asn1_ex_new != NULL) {
+                if (!ef->asn1_ex_new(pval, it))
+                    goto memerr;
+            }
         }
         break;
 
     case ASN1_ITYPE_PRIMITIVE:
         if (it->templates) {
-            if (!asn1_template_new(pval, it->templates))
+            if (!asn1_template_new(pval, it->templates, libctx, propq))
                 goto memerr;
         } else if (!asn1_primitive_new(pval, it, embed))
             goto memerr;
@@ -124,7 +148,7 @@ int asn1_item_embed_new(ASN1_VALUE **pval, const ASN1_ITEM *it, int embed)
         ossl_asn1_enc_init(pval, it);
         for (i = 0, tt = it->templates; i < it->tcount; tt++, i++) {
             pseqval = ossl_asn1_get_field_ptr(pval, tt);
-            if (!asn1_template_new(pseqval, tt))
+            if (!asn1_template_new(pseqval, tt, libctx, propq))
                 goto memerr2;
         }
         if (asn1_cb && !asn1_cb(ASN1_OP_NEW_POST, pval, it, NULL))
@@ -180,7 +204,8 @@ static void asn1_item_clear(ASN1_VALUE **pval, const ASN1_ITEM *it)
     }
 }
 
-static int asn1_template_new(ASN1_VALUE **pval, const ASN1_TEMPLATE *tt)
+static int asn1_template_new(ASN1_VALUE **pval, const ASN1_TEMPLATE *tt,
+                             OSSL_LIB_CTX *libctx, const char *propq)
 {
     const ASN1_ITEM *it = ASN1_ITEM_ptr(tt->item);
     int embed = tt->flags & ASN1_TFLG_EMBED;
@@ -214,7 +239,7 @@ static int asn1_template_new(ASN1_VALUE **pval, const ASN1_TEMPLATE *tt)
         goto done;
     }
     /* Otherwise pass it back to the item routine */
-    ret = asn1_item_embed_new(pval, it, embed);
+    ret = asn1_item_embed_new(pval, it, embed, libctx, propq);
  done:
     return ret;
 }
diff --git a/crypto/cmp/cmp_asn.c b/crypto/cmp/cmp_asn.c
index e2f7169dda..31b67178d8 100644
--- a/crypto/cmp/cmp_asn.c
+++ b/crypto/cmp/cmp_asn.c
@@ -208,6 +208,45 @@ int ossl_cmp_asn1_get_int(const ASN1_INTEGER *a)
     return (int)res;
 }
 
+static int ossl_cmp_msg_cb(int operation, ASN1_VALUE **pval,
+                           const ASN1_ITEM *it, void *exarg)
+{
+    OSSL_CMP_MSG *msg = (OSSL_CMP_MSG *)*pval;
+
+    switch (operation) {
+    case ASN1_OP_FREE_POST:
+        OPENSSL_free(msg->propq);
+        break;
+
+    case ASN1_OP_DUP_POST:
+        {
+            OSSL_CMP_MSG *old = exarg;
+
+            if (!ossl_cmp_msg_set0_libctx(msg, old->libctx, old->propq))
+                return 0;
+        }
+        break;
+    case ASN1_OP_GET0_LIBCTX:
+        {
+            OSSL_LIB_CTX **libctx = exarg;
+
+            *libctx = msg->libctx;
+        }
+        break;
+    case ASN1_OP_GET0_PROPQ:
+        {
+            const char **propq = exarg;
+
+            *propq = msg->propq;
+        }
+        break;
+    default:
+        break;
+    }
+
+    return 1;
+}
+
 ASN1_CHOICE(OSSL_CMP_CERTORENCCERT) = {
     /* OSSL_CMP_CMPCERTIFICATE is effectively X509 so it is used directly */
     ASN1_EXP(OSSL_CMP_CERTORENCCERT, value.certificate, X509, 0),
@@ -405,14 +444,13 @@ ASN1_SEQUENCE(OSSL_CMP_PROTECTEDPART) = {
 } ASN1_SEQUENCE_END(OSSL_CMP_PROTECTEDPART)
 IMPLEMENT_ASN1_FUNCTIONS(OSSL_CMP_PROTECTEDPART)
 
-ASN1_SEQUENCE(OSSL_CMP_MSG) = {
+ASN1_SEQUENCE_cb(OSSL_CMP_MSG, ossl_cmp_msg_cb) = {
     ASN1_SIMPLE(OSSL_CMP_MSG, header, OSSL_CMP_PKIHEADER),
     ASN1_SIMPLE(OSSL_CMP_MSG, body, OSSL_CMP_PKIBODY),
     ASN1_EXP_OPT(OSSL_CMP_MSG, protection, ASN1_BIT_STRING, 0),
     /* OSSL_CMP_CMPCERTIFICATE is effectively X509 so it is used directly */
     ASN1_EXP_SEQUENCE_OF_OPT(OSSL_CMP_MSG, extraCerts, X509, 1)
-} ASN1_SEQUENCE_END(OSSL_CMP_MSG)
-IMPLEMENT_ASN1_FUNCTIONS(OSSL_CMP_MSG)
+} ASN1_SEQUENCE_END_cb(OSSL_CMP_MSG, OSSL_CMP_MSG)
 IMPLEMENT_ASN1_DUP_FUNCTION(OSSL_CMP_MSG)
 
 ASN1_ITEM_TEMPLATE(OSSL_CMP_MSGS) =
diff --git a/crypto/cmp/cmp_local.h b/crypto/cmp/cmp_local.h
index 2b22db3e82..9dba9e8169 100644
--- a/crypto/cmp/cmp_local.h
+++ b/crypto/cmp/cmp_local.h
@@ -670,8 +670,11 @@ struct ossl_cmp_msg_st {
     ASN1_BIT_STRING *protection; /* 0 */
     /* OSSL_CMP_CMPCERTIFICATE is effectively X509 so it is used directly */
     STACK_OF(X509) *extraCerts; /* 1 */
+    OSSL_LIB_CTX *libctx;
+    char *propq;
 } /* OSSL_CMP_MSG */;
-DECLARE_ASN1_FUNCTIONS(OSSL_CMP_MSG)
+OSSL_CMP_MSG *OSSL_CMP_MSG_new(OSSL_LIB_CTX *libctx, const char *propq);
+void OSSL_CMP_MSG_free(OSSL_CMP_MSG *msg);
 
 /*-
  * ProtectedPart ::= SEQUENCE {
@@ -852,6 +855,8 @@ int ossl_cmp_hdr_init(OSSL_CMP_CTX *ctx, OSSL_CMP_PKIHEADER *hdr);
 # define OSSL_CMP_CERTREQID 0
 /* sequence id for the first - and so far only - revocation request */
 # define OSSL_CMP_REVREQSID 0
+int ossl_cmp_msg_set0_libctx(OSSL_CMP_MSG *msg, OSSL_LIB_CTX *libctx,
+                             const char *propq);
 const char *ossl_cmp_bodytype_to_string(int type);
 int ossl_cmp_msg_set_bodytype(OSSL_CMP_MSG *msg, int type);
 int ossl_cmp_msg_get_bodytype(const OSSL_CMP_MSG *msg);
diff --git a/crypto/cmp/cmp_msg.c b/crypto/cmp/cmp_msg.c
index b9c347afb8..b625147b6e 100644
--- a/crypto/cmp/cmp_msg.c
+++ b/crypto/cmp/cmp_msg.c
@@ -20,6 +20,46 @@
 #include <openssl/err.h>
 #include <openssl/x509.h>
 
+OSSL_CMP_MSG *OSSL_CMP_MSG_new(OSSL_LIB_CTX *libctx, const char *propq)
+{
+    OSSL_CMP_MSG *msg = NULL;
+
+    msg = (OSSL_CMP_MSG *)ASN1_item_new_ex(ASN1_ITEM_rptr(OSSL_CMP_MSG),
+                                           libctx, propq);
+    if (!ossl_cmp_msg_set0_libctx(msg, libctx, propq)) {
+        OSSL_CMP_MSG_free(msg);
+        msg = NULL;
+    }
+    return msg;
+}
+
+void OSSL_CMP_MSG_free(OSSL_CMP_MSG *msg)
+{
+    ASN1_item_free((ASN1_VALUE *)msg, ASN1_ITEM_rptr(OSSL_CMP_MSG));
+}
+
+/*
+ * This should only be used if the X509 object was embedded inside another
+ * asn1 object and it needs a libctx to operate.
+ * Use OSSL_CMP_MSG_new() instead if possible.
+ */
+int ossl_cmp_msg_set0_libctx(OSSL_CMP_MSG *msg, OSSL_LIB_CTX *libctx,
+                             const char *propq)
+{
+    if (msg != NULL) {
+        msg->libctx = libctx;
+        OPENSSL_free(msg->propq);
+        msg->propq = NULL;
+        if (propq != NULL) {
+            msg->propq = OPENSSL_strdup(propq);
+            if (msg->propq == NULL)
+                return 0;
+        }
+    }
+    return 1;
+}
+
+
 OSSL_CMP_PKIHEADER *OSSL_CMP_MSG_get0_header(const OSSL_CMP_MSG *msg)
 {
     if (msg == NULL) {
@@ -125,7 +165,7 @@ OSSL_CMP_MSG *ossl_cmp_msg_create(OSSL_CMP_CTX *ctx, int bodytype)
     if (!ossl_assert(ctx != NULL))
         return NULL;
 
-    if ((msg = OSSL_CMP_MSG_new()) == NULL)
+    if ((msg = OSSL_CMP_MSG_new(ctx->libctx, ctx->propq)) == NULL)
         return NULL;
     if (!ossl_cmp_hdr_init(ctx, msg->header)
             || !ossl_cmp_msg_set_bodytype(msg, bodytype))
@@ -1031,9 +1071,10 @@ int OSSL_CMP_MSG_update_transactionID(OSSL_CMP_CTX *ctx, OSSL_CMP_MSG *msg)
             || ossl_cmp_msg_protect(ctx, msg);
 }
 
-OSSL_CMP_MSG *OSSL_CMP_MSG_read(const char *file)
+OSSL_CMP_MSG *OSSL_CMP_MSG_read(const char *file, OSSL_LIB_CTX *libctx,
+                                const char *propq)
 {
-    OSSL_CMP_MSG *msg = NULL;
+    OSSL_CMP_MSG *msg;
     BIO *bio = NULL;
 
     if (file == NULL) {
@@ -1041,9 +1082,18 @@ OSSL_CMP_MSG *OSSL_CMP_MSG_read(const char *file)
         return NULL;
     }
 
+    msg = OSSL_CMP_MSG_new(libctx, propq);
+    if (msg == NULL){
+        ERR_raise(ERR_LIB_CMP, ERR_R_MALLOC_FAILURE);
+        return NULL;
+    }
+
     if ((bio = BIO_new_file(file, "rb")) == NULL)
         return NULL;
-    msg = d2i_OSSL_CMP_MSG_bio(bio, NULL);
+    if (d2i_OSSL_CMP_MSG_bio(bio, &msg) == NULL) {
+        OSSL_CMP_MSG_free(msg);
+        msg = NULL;
+    }
     BIO_free(bio);
     return msg;
 }
@@ -1066,10 +1116,40 @@ int OSSL_CMP_MSG_write(const char *file, const OSSL_CMP_MSG *msg)
     return res;
 }
 
+OSSL_CMP_MSG *d2i_OSSL_CMP_MSG(OSSL_CMP_MSG **msg, const unsigned char **in,
+                               long len)
+{
+    OSSL_LIB_CTX *libctx = NULL;
+    const char *propq = NULL;
+
+    if (msg != NULL && *msg != NULL) {
+        libctx  = (*msg)->libctx;
+        propq = (*msg)->propq;
+    }
+
+    return (OSSL_CMP_MSG *)ASN1_item_d2i_ex((ASN1_VALUE **)msg, in, len,
+                                            ASN1_ITEM_rptr(OSSL_CMP_MSG),
+                                            libctx, propq);
+}
+
+int i2d_OSSL_CMP_MSG(const OSSL_CMP_MSG *msg, unsigned char **out)
+{
+    return ASN1_item_i2d((const ASN1_VALUE *)msg, out,
+                         ASN1_ITEM_rptr(OSSL_CMP_MSG));
+}
+
 OSSL_CMP_MSG *d2i_OSSL_CMP_MSG_bio(BIO *bio, OSSL_CMP_MSG **msg)
 {
-    return ASN1_d2i_bio_of(OSSL_CMP_MSG, OSSL_CMP_MSG_new,
-                           d2i_OSSL_CMP_MSG, bio, msg);
+    OSSL_LIB_CTX *libctx = NULL;
+    const char *propq = NULL;
+
+    if (msg != NULL && *msg != NULL) {
+        libctx  = (*msg)->libctx;
+        propq = (*msg)->propq;
+    }
+
+    return ASN1_item_d2i_bio_ex(ASN1_ITEM_rptr(OSSL_CMP_MSG), bio, msg, libctx,
+                                propq);
 }
 
 int i2d_OSSL_CMP_MSG_bio(BIO *bio, const OSSL_CMP_MSG *msg)
diff --git a/crypto/cms/cms_io.c b/crypto/cms/cms_io.c
index 9c260d0904..3768ea4db2 100644
--- a/crypto/cms/cms_io.c
+++ b/crypto/cms/cms_io.c
@@ -36,8 +36,11 @@ int CMS_stream(unsigned char ***boundary, CMS_ContentInfo *cms)
 CMS_ContentInfo *d2i_CMS_bio(BIO *bp, CMS_ContentInfo **cms)
 {
     CMS_ContentInfo *ci;
+    const CMS_CTX *ctx = ossl_cms_get0_cmsctx(cms == NULL ? NULL : *cms);
 
-    ci = ASN1_item_d2i_bio(ASN1_ITEM_rptr(CMS_ContentInfo), bp, cms);
+    ci = ASN1_item_d2i_bio_ex(ASN1_ITEM_rptr(CMS_ContentInfo), bp, cms,
+                              ossl_cms_ctx_get0_libctx(ctx),
+                              ossl_cms_ctx_get0_propq(ctx));
     if (ci != NULL)
         ossl_cms_resolve_libctx(ci);
     return ci;
@@ -90,13 +93,17 @@ int SMIME_write_CMS(BIO *bio, CMS_ContentInfo *cms, BIO *data, int flags)
                                ossl_cms_ctx_get0_propq(ctx));
 }
 
-CMS_ContentInfo *SMIME_read_CMS_ex(BIO *bio, int flags, BIO **bcont, CMS_ContentInfo **cms)
+CMS_ContentInfo *SMIME_read_CMS_ex(BIO *bio, int flags, BIO **bcont,
+                                   CMS_ContentInfo **cms)
 {
     CMS_ContentInfo *ci;
+    const CMS_CTX *ctx = ossl_cms_get0_cmsctx(cms == NULL ? NULL : *cms);
 
     ci = (CMS_ContentInfo *)SMIME_read_ASN1_ex(bio, flags, bcont,
                                                ASN1_ITEM_rptr(CMS_ContentInfo),
-                                               (ASN1_VALUE **)cms);
+                                               (ASN1_VALUE **)cms,
+                                               ossl_cms_ctx_get0_libctx(ctx),
+                                               ossl_cms_ctx_get0_propq(ctx));
     if (ci != NULL)
         ossl_cms_resolve_libctx(ci);
     return ci;
diff --git a/crypto/cms/cms_lib.c b/crypto/cms/cms_lib.c
index 673a1f7ad5..4ad9302910 100644
--- a/crypto/cms/cms_lib.c
+++ b/crypto/cms/cms_lib.c
@@ -28,9 +28,12 @@ CMS_ContentInfo *d2i_CMS_ContentInfo(CMS_ContentInfo **a,
                                      const unsigned char **in, long len)
 {
     CMS_ContentInfo *ci;
+    const CMS_CTX *ctx = ossl_cms_get0_cmsctx(a == NULL ? NULL : *a);
 
-    ci = (CMS_ContentInfo *)ASN1_item_d2i((ASN1_VALUE **)a, in, len,
-                                          (CMS_ContentInfo_it()));
+    ci = (CMS_ContentInfo *)ASN1_item_d2i_ex((ASN1_VALUE **)a, in, len,
+                                          (CMS_ContentInfo_it()),
+                                          ossl_cms_ctx_get0_libctx(ctx),
+                                          ossl_cms_ctx_get0_propq(ctx));
     if (ci != NULL)
         ossl_cms_resolve_libctx(ci);
     return ci;
@@ -45,7 +48,8 @@ CMS_ContentInfo *CMS_ContentInfo_new_ex(OSSL_LIB_CTX *libctx, const char *propq)
 {
     CMS_ContentInfo *ci;
 
-    ci = (CMS_ContentInfo *)ASN1_item_new(ASN1_ITEM_rptr(CMS_ContentInfo));
+    ci = (CMS_ContentInfo *)ASN1_item_new_ex(ASN1_ITEM_rptr(CMS_ContentInfo),
+                                             libctx, propq);
     if (ci != NULL) {
         ci->ctx.libctx = libctx;
         ci->ctx.propq = NULL;
diff --git a/crypto/pkcs7/pk7_asn1.c b/crypto/pkcs7/pk7_asn1.c
index 60ad5b1e76..1cd867721e 100644
--- a/crypto/pkcs7/pk7_asn1.c
+++ b/crypto/pkcs7/pk7_asn1.c
@@ -66,8 +66,16 @@ ASN1_NDEF_SEQUENCE_cb(PKCS7, pk7_cb) = {
 PKCS7 *d2i_PKCS7(PKCS7 **a, const unsigned char **in, long len)
 {
     PKCS7 *ret;
+    OSSL_LIB_CTX *libctx = NULL;
+    const char *propq = NULL;
 
-    ret = (PKCS7 *)ASN1_item_d2i((ASN1_VALUE **)a, in, len, (PKCS7_it()));
+    if (a != NULL && *a != NULL) {
+        libctx = (*a)->ctx.libctx;
+        propq = (*a)->ctx.propq;
+    }
+
+    ret = (PKCS7 *)ASN1_item_d2i_ex((ASN1_VALUE **)a, in, len, (PKCS7_it()),
+                                    libctx, propq);
     if (ret != NULL)
         ossl_pkcs7_resolve_libctx(ret);
     return ret;
@@ -85,7 +93,8 @@ PKCS7 *PKCS7_new(void)
 
 PKCS7 *PKCS7_new_ex(OSSL_LIB_CTX *libctx, const char *propq)
 {
-    PKCS7 *pkcs7 = PKCS7_new();
+    PKCS7 *pkcs7 = (PKCS7 *)ASN1_item_new_ex(ASN1_ITEM_rptr(PKCS7), libctx,
+                                             propq);
 
     if (pkcs7 != NULL) {
         pkcs7->ctx.libctx = libctx;
diff --git a/crypto/pkcs7/pk7_mime.c b/crypto/pkcs7/pk7_mime.c
index b446423384..49a0da5f81 100644
--- a/crypto/pkcs7/pk7_mime.c
+++ b/crypto/pkcs7/pk7_mime.c
@@ -49,9 +49,16 @@ int SMIME_write_PKCS7(BIO *bio, PKCS7 *p7, BIO *data, int flags)
 PKCS7 *SMIME_read_PKCS7_ex(BIO *bio, BIO **bcont, PKCS7 **p7)
 {
     PKCS7 *ret;
+    OSSL_LIB_CTX *libctx = NULL;
+    const char *propq = NULL;
+
+    if (p7 != NULL && *p7 != NULL) {
+        libctx = (*p7)->ctx.libctx;
+        propq = (*p7)->ctx.propq;
+    }
 
     ret = (PKCS7 *)SMIME_read_ASN1_ex(bio, 0, bcont, ASN1_ITEM_rptr(PKCS7),
-                                      (ASN1_VALUE **)p7);
+                                      (ASN1_VALUE **)p7, libctx, propq);
     if (ret != NULL)
         ossl_pkcs7_resolve_libctx(ret);
     return ret;
diff --git a/crypto/x509/x_all.c b/crypto/x509/x_all.c
index ba400d1103..88c75c3d36 100644
--- a/crypto/x509/x_all.c
+++ b/crypto/x509/x_all.c
@@ -182,8 +182,15 @@ int i2d_X509_CRL_bio(BIO *bp, const X509_CRL *crl)
 PKCS7 *d2i_PKCS7_fp(FILE *fp, PKCS7 **p7)
 {
     PKCS7 *ret;
+    OSSL_LIB_CTX *libctx = NULL;
+    const char *propq = NULL;
 
-    ret = ASN1_item_d2i_fp(ASN1_ITEM_rptr(PKCS7), fp, p7);
+    if (p7 != NULL && *p7 != NULL) {
+        libctx = (*p7)->ctx.libctx;
+        propq = (*p7)->ctx.propq;
+    }
+
+    ret = ASN1_item_d2i_fp_ex(ASN1_ITEM_rptr(PKCS7), fp, p7, libctx, propq);
     if (ret != NULL)
         ossl_pkcs7_resolve_libctx(ret);
     return ret;
@@ -198,8 +205,16 @@ int i2d_PKCS7_fp(FILE *fp, const PKCS7 *p7)
 PKCS7 *d2i_PKCS7_bio(BIO *bp, PKCS7 **p7)
 {
     PKCS7 *ret;
+    OSSL_LIB_CTX *libctx = NULL;
+    const char *propq = NULL;
+
+    if (p7 != NULL && *p7 != NULL) {
+        libctx = (*p7)->ctx.libctx;
+        propq = (*p7)->ctx.propq;
+    }
 
-    ret = ASN1_item_d2i_bio(ASN1_ITEM_rptr(PKCS7), bp, p7);
+
+    ret = ASN1_item_d2i_bio_ex(ASN1_ITEM_rptr(PKCS7), bp, p7, libctx, propq);
     if (ret != NULL)
         ossl_pkcs7_resolve_libctx(ret);
     return ret;
@@ -224,7 +239,15 @@ int i2d_X509_REQ_fp(FILE *fp, const X509_REQ *req)
 
 X509_REQ *d2i_X509_REQ_bio(BIO *bp, X509_REQ **req)
 {
-    return ASN1_item_d2i_bio(ASN1_ITEM_rptr(X509_REQ), bp, req);
+    OSSL_LIB_CTX *libctx = NULL;
+    const char *propq = NULL;
+
+    if (req != NULL && *req != NULL) {
+        libctx = (*req)->libctx;
+        propq = (*req)->propq;
+    }
+
+    return ASN1_item_d2i_bio_ex(ASN1_ITEM_rptr(X509_REQ), bp, req, libctx, propq);
 }
 
 int i2d_X509_REQ_bio(BIO *bp, const X509_REQ *req)
diff --git a/crypto/x509/x_pubkey.c b/crypto/x509/x_pubkey.c
index c21184d964..2fe5724743 100644
--- a/crypto/x509/x_pubkey.c
+++ b/crypto/x509/x_pubkey.c
@@ -71,6 +71,7 @@ static void x509_pubkey_ex_free(ASN1_VALUE **pval, const ASN1_ITEM *it)
     X509_ALGOR_free(pubkey->algor);
     ASN1_BIT_STRING_free(pubkey->public_key);
     EVP_PKEY_free(pubkey->pkey);
+    OPENSSL_free(pubkey->propq);
     OPENSSL_free(pubkey);
     *pval = NULL;
 }
@@ -85,12 +86,15 @@ static int x509_pubkey_ex_populate(ASN1_VALUE **pval, const ASN1_ITEM *it)
             || (pubkey->public_key = ASN1_BIT_STRING_new()) != NULL);
 }
 
-static int x509_pubkey_ex_new(ASN1_VALUE **pval, const ASN1_ITEM *it)
+
+static int x509_pubkey_ex_new_ex(ASN1_VALUE **pval, const ASN1_ITEM *it,
+                                 OSSL_LIB_CTX *libctx, const char *propq)
 {
     X509_PUBKEY *ret;
 
     if ((ret = OPENSSL_zalloc(sizeof(*ret))) == NULL
-        || !x509_pubkey_ex_populate((ASN1_VALUE **)&ret, NULL)) {
+        || !x509_pubkey_ex_populate((ASN1_VALUE **)&ret, NULL)
+        || !x509_pubkey_set0_libctx(ret, libctx, propq)) {
         x509_pubkey_ex_free((ASN1_VALUE **)&ret, NULL);
         ERR_raise(ERR_LIB_ASN1, ERR_R_MALLOC_FAILURE);
     } else {
@@ -100,17 +104,18 @@ static int x509_pubkey_ex_new(ASN1_VALUE **pval, const ASN1_ITEM *it)
     return ret != NULL;
 }
 
-static int x509_pubkey_ex_d2i(ASN1_VALUE **pval,
-                              const unsigned char **in, long len,
-                              const ASN1_ITEM *it, int tag, int aclass,
-                              char opt, ASN1_TLC *ctx)
+static int x509_pubkey_ex_d2i_ex(ASN1_VALUE **pval,
+                                 const unsigned char **in, long len,
+                                 const ASN1_ITEM *it, int tag, int aclass,
+                                 char opt, ASN1_TLC *ctx, OSSL_LIB_CTX *libctx,
+                                 const char *propq)
 {
     const unsigned char *in_saved = *in;
     X509_PUBKEY *pubkey;
     int ret;
     OSSL_DECODER_CTX *dctx = NULL;
 
-    if (*pval == NULL && !x509_pubkey_ex_new(pval, it))
+    if (*pval == NULL && !x509_pubkey_ex_new_ex(pval, it, libctx, propq))
         return 0;
     if (!x509_pubkey_ex_populate(pval, NULL)) {
         ERR_raise(ERR_LIB_ASN1, ERR_R_MALLOC_FAILURE);
@@ -190,17 +195,31 @@ static int x509_pubkey_ex_print(BIO *out, const ASN1_VALUE **pval, int indent,
 
 static const ASN1_EXTERN_FUNCS x509_pubkey_ff = {
     NULL,
-    x509_pubkey_ex_new,
+    NULL,
     x509_pubkey_ex_free,
     0,                          /* Default clear behaviour is OK */
-    x509_pubkey_ex_d2i,
+    NULL,
     x509_pubkey_ex_i2d,
-    x509_pubkey_ex_print
+    x509_pubkey_ex_print,
+    x509_pubkey_ex_new_ex,
+    x509_pubkey_ex_d2i_ex,
 };
 
 IMPLEMENT_EXTERN_ASN1(X509_PUBKEY, V_ASN1_SEQUENCE, x509_pubkey_ff)
 IMPLEMENT_ASN1_FUNCTIONS(X509_PUBKEY)
 
+X509_PUBKEY *X509_PUBKEY_new_ex(OSSL_LIB_CTX *libctx, const char *propq)
+{
+    X509_PUBKEY *pubkey = NULL;
+
+    pubkey = (X509_PUBKEY *)ASN1_item_new_ex(X509_PUBKEY_it(), libctx, propq);
+    if (!x509_pubkey_set0_libctx(pubkey, libctx, propq)) {
+        X509_PUBKEY_free(pubkey);
+        pubkey = NULL;
+    }
+    return pubkey;
+}
+
 /*
  * X509_PUBKEY_dup() must be implemented manually, because there is no
  * support for it in ASN1_EXTERN_FUNCS.
diff --git a/crypto/x509/x_req.c b/crypto/x509/x_req.c
index 1b4e1587dd..293d4be713 100644
--- a/crypto/x509/x_req.c
+++ b/crypto/x509/x_req.c
@@ -68,6 +68,37 @@ static int req_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it,
 
             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);
+
+                if (pkey != NULL) {
+                    pkey = EVP_PKEY_dup(pkey);
+                    if (pkey == NULL) {
+                        ERR_raise(ERR_LIB_X509, ERR_R_MALLOC_FAILURE);
+                        return 0;
+                    }
+                    if (!X509_PUBKEY_set(&ret->req_info.pubkey, pkey)) {
+                        EVP_PKEY_free(pkey);
+                        ERR_raise(ERR_LIB_X509, ERR_R_INTERNAL_ERROR);
+                        return 0;
+                    }
+                    EVP_PKEY_free(pkey);
+                }
+            }
+        }
+        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;
     }
diff --git a/crypto/x509/x_x509.c b/crypto/x509/x_x509.c
index 7959ee223f..260bfda683 100644
--- a/crypto/x509/x_x509.c
+++ b/crypto/x509/x_x509.c
@@ -104,6 +104,37 @@ static int x509_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it,
 
             if (!ossl_x509_set0_libctx(ret, old->libctx, old->propq))
                 return 0;
+            if (old->cert_info.key != NULL) {
+                EVP_PKEY *pkey = X509_PUBKEY_get0(old->cert_info.key);
+
+                if (pkey != NULL) {
+                    pkey = EVP_PKEY_dup(pkey);
+                    if (pkey == NULL) {
+                        ERR_raise(ERR_LIB_X509, ERR_R_MALLOC_FAILURE);
+                        return 0;
+                    }
+                    if (!X509_PUBKEY_set(&ret->cert_info.key, pkey)) {
+                        EVP_PKEY_free(pkey);
+                        ERR_raise(ERR_LIB_X509, ERR_R_INTERNAL_ERROR);
+                        return 0;
+                    }
+                    EVP_PKEY_free(pkey);
+                }
+            }
+        }
+        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;
     default:
@@ -169,7 +200,7 @@ X509 *X509_new_ex(OSSL_LIB_CTX *libctx, const char *propq)
 {
     X509 *cert = NULL;
 
-    cert = (X509 *)ASN1_item_new((X509_it()));
+    cert = (X509 *)ASN1_item_new_ex(X509_it(), libctx, propq);
     if (!ossl_x509_set0_libctx(cert, libctx, propq)) {
         X509_free(cert);
         cert = NULL;
diff --git a/doc/build.info b/doc/build.info
index b77dac210c..946cc24032 100644
--- a/doc/build.info
+++ b/doc/build.info
@@ -471,6 +471,10 @@ DEPEND[html/man3/ADMISSIONS.html]=man3/ADMISSIONS.pod
 GENERATE[html/man3/ADMISSIONS.html]=man3/ADMISSIONS.pod
 DEPEND[man/man3/ADMISSIONS.3]=man3/ADMISSIONS.pod
 GENERATE[man/man3/ADMISSIONS.3]=man3/ADMISSIONS.pod
+DEPEND[html/man3/ASN1_EXTERN_FUNCS.html]=man3/ASN1_EXTERN_FUNCS.pod
+GENERATE[html/man3/ASN1_EXTERN_FUNCS.html]=man3/ASN1_EXTERN_FUNCS.pod
+DEPEND[man/man3/ASN1_EXTERN_FUNCS.3]=man3/ASN1_EXTERN_FUNCS.pod
+GENERATE[man/man3/ASN1_EXTERN_FUNCS.3]=man3/ASN1_EXTERN_FUNCS.pod
 DEPEND[html/man3/ASN1_INTEGER_get_int64.html]=man3/ASN1_INTEGER_get_int64.pod
 GENERATE[html/man3/ASN1_INTEGER_get_int64.html]=man3/ASN1_INTEGER_get_int64.pod
 DEPEND[man/man3/ASN1_INTEGER_get_int64.3]=man3/ASN1_INTEGER_get_int64.pod
@@ -511,6 +515,10 @@ DEPEND[html/man3/ASN1_TYPE_get.html]=man3/ASN1_TYPE_get.pod
 GENERATE[html/man3/ASN1_TYPE_get.html]=man3/ASN1_TYPE_get.pod
 DEPEND[man/man3/ASN1_TYPE_get.3]=man3/ASN1_TYPE_get.pod
 GENERATE[man/man3/ASN1_TYPE_get.3]=man3/ASN1_TYPE_get.pod
+DEPEND[html/man3/ASN1_aux_cb.html]=man3/ASN1_aux_cb.pod
+GENERATE[html/man3/ASN1_aux_cb.html]=man3/ASN1_aux_cb.pod
+DEPEND[man/man3/ASN1_aux_cb.3]=man3/ASN1_aux_cb.pod
+GENERATE[man/man3/ASN1_aux_cb.3]=man3/ASN1_aux_cb.pod
 DEPEND[html/man3/ASN1_generate_nconf.html]=man3/ASN1_generate_nconf.pod
 GENERATE[html/man3/ASN1_generate_nconf.html]=man3/ASN1_generate_nconf.pod
 DEPEND[man/man3/ASN1_generate_nconf.3]=man3/ASN1_generate_nconf.pod
@@ -519,6 +527,10 @@ DEPEND[html/man3/ASN1_item_d2i_bio.html]=man3/ASN1_item_d2i_bio.pod
 GENERATE[html/man3/ASN1_item_d2i_bio.html]=man3/ASN1_item_d2i_bio.pod
 DEPEND[man/man3/ASN1_item_d2i_bio.3]=man3/ASN1_item_d2i_bio.pod
 GENERATE[man/man3/ASN1_item_d2i_bio.3]=man3/ASN1_item_d2i_bio.pod
+DEPEND[html/man3/ASN1_item_new.html]=man3/ASN1_item_new.pod
+GENERATE[html/man3/ASN1_item_new.html]=man3/ASN1_item_new.pod
+DEPEND[man/man3/ASN1_item_new.3]=man3/ASN1_item_new.pod
+GENERATE[man/man3/ASN1_item_new.3]=man3/ASN1_item_new.pod
 DEPEND[html/man3/ASN1_item_sign.html]=man3/ASN1_item_sign.pod
 GENERATE[html/man3/ASN1_item_sign.html]=man3/ASN1_item_sign.pod
 DEPEND[man/man3/ASN1_item_sign.3]=man3/ASN1_item_sign.pod
@@ -2825,6 +2837,7 @@ DEPEND[man/man3/s2i_ASN1_IA5STRING.3]=man3/s2i_ASN1_IA5STRING.pod
 GENERATE[man/man3/s2i_ASN1_IA5STRING.3]=man3/s2i_ASN1_IA5STRING.pod
 IMAGEDOCS[man3]=
 HTMLDOCS[man3]=html/man3/ADMISSIONS.html \
+html/man3/ASN1_EXTERN_FUNCS.html \
 html/man3/ASN1_INTEGER_get_int64.html \
 html/man3/ASN1_INTEGER_new.html \
 html/man3/ASN1_ITEM_lookup.html \
@@ -2835,8 +2848,10 @@ html/man3/ASN1_STRING_new.html \
 html/man3/ASN1_STRING_print_ex.html \
 html/man3/ASN1_TIME_set.html \
 html/man3/ASN1_TYPE_get.html \
+html/man3/ASN1_aux_cb.html \
 html/man3/ASN1_generate_nconf.html \
 html/man3/ASN1_item_d2i_bio.html \
+html/man3/ASN1_item_new.html \
 html/man3/ASN1_item_sign.html \
 html/man3/ASYNC_WAIT_CTX_new.html \
 html/man3/ASYNC_start_job.html \
@@ -3414,6 +3429,7 @@ html/man3/i2d_re_X509_tbs.html \
 html/man3/o2i_SCT_LIST.html \
 html/man3/s2i_ASN1_IA5STRING.html
 MANDOCS[man3]=man/man3/ADMISSIONS.3 \
+man/man3/ASN1_EXTERN_FUNCS.3 \
 man/man3/ASN1_INTEGER_get_int64.3 \
 man/man3/ASN1_INTEGER_new.3 \
 man/man3/ASN1_ITEM_lookup.3 \
@@ -3424,8 +3440,10 @@ man/man3/ASN1_STRING_new.3 \
 man/man3/ASN1_STRING_print_ex.3 \
 man/man3/ASN1_TIME_set.3 \
 man/man3/ASN1_TYPE_get.3 \
+man/man3/ASN1_aux_cb.3 \
 man/man3/ASN1_generate_nconf.3 \
 man/man3/ASN1_item_d2i_bio.3 \
+man/man3/ASN1_item_new.3 \
 man/man3/ASN1_item_sign.3 \
 man/man3/ASYNC_WAIT_CTX_new.3 \
 man/man3/ASYNC_start_job.3 \
diff --git a/doc/man3/ASN1_EXTERN_FUNCS.pod b/doc/man3/ASN1_EXTERN_FUNCS.pod
new file mode 100644
index 0000000000..800cc500ea
--- /dev/null
+++ b/doc/man3/ASN1_EXTERN_FUNCS.pod
@@ -0,0 +1,181 @@
+=pod
+
+=head1 NAME
+
+ASN1_EXTERN_FUNCS, ASN1_ex_d2i, ASN1_ex_d2i_ex, ASN1_ex_i2d, ASN1_ex_new_func,
+ASN1_ex_new_ex_func, ASN1_ex_free_func, ASN1_ex_print_func,
+IMPLEMENT_EXTERN_ASN1
+- ASN.1 external function support
+
+=head1 SYNOPSIS
+
+ #include <openssl/asn1t.h>
+
+ typedef int ASN1_ex_d2i(ASN1_VALUE **pval, const unsigned char **in, long len,
+                         const ASN1_ITEM *it, int tag, int aclass, char opt,
+                         ASN1_TLC *ctx);
+ typedef int ASN1_ex_d2i_ex(ASN1_VALUE **pval, const unsigned char **in, long len,
+                            const ASN1_ITEM *it, int tag, int aclass, char opt,
+                            ASN1_TLC *ctx, OSSL_LIB_CTX *libctx,
+                            const char *propq);
+ typedef int ASN1_ex_i2d(const ASN1_VALUE **pval, unsigned char **out,
+                         const ASN1_ITEM *it, int tag, int aclass);
+ typedef int ASN1_ex_new_func(ASN1_VALUE **pval, const ASN1_ITEM *it);
+ typedef int ASN1_ex_new_ex_func(ASN1_VALUE **pval, const ASN1_ITEM *it,
+                                 OSSL_LIB_CTX *libctx, const char *propq);
+ typedef void ASN1_ex_free_func(ASN1_VALUE **pval, const ASN1_ITEM *it);
+ typedef int ASN1_ex_print_func(BIO *out, const ASN1_VALUE **pval,
+                                int indent, const char *fname,
+                                const ASN1_PCTX *pctx);
+
+ struct ASN1_EXTERN_FUNCS_st {
+    void *app_data;
+    ASN1_ex_new_func *asn1_ex_new;
+    ASN1_ex_free_func *asn1_ex_free;
+    ASN1_ex_free_func *asn1_ex_clear;
+    ASN1_ex_d2i *asn1_ex_d2i;
+    ASN1_ex_i2d *asn1_ex_i2d;
+    ASN1_ex_print_func *asn1_ex_print;
+    ASN1_ex_new_ex_func *asn1_ex_new_ex;
+    ASN1_ex_d2i_ex *asn1_ex_d2i_ex;
+ };
+ typedef struct ASN1_EXTERN_FUNCS_st ASN1_EXTERN_FUNCS;
+
+ #define IMPLEMENT_EXTERN_ASN1(sname, tag, fptrs)
+
+=head1 DESCRIPTION
+
+ASN.1 data structures templates are typically defined in OpenSSL using a series
+of macros such as ASN1_SEQUENCE(), ASN1_SEQUENCE_END() and so on. Instead
+templates can also be defined based entirely on external functions. These
+external functions are called to perform operations such as creating a new
+B<ASN1_VALUE> or converting an B<ASN1_VALUE> to or from DER encoding.
+
+The macro IMPLEMENT_EXTERN_ASN1() can be used to create such an externally
+defined structure. The name of the structure should be supplied in the I<sname>
+parameter. The tag for the structure (e.g. typically B<V_ASN1_SEQUENCE>) should
+be supplied in the I<tag> parameter. Finally a pointer to an
+B<ASN1_EXTERN_FUNCS> structure should be supplied in the I<fptrs> parameter.
+
+The B<ASN1_EXTERN_FUNCS> structure has the following entries.
+
+=over 4
+
+=item I<app_data>
+
+A pointer to arbitrary application specific data.
+
+=item I<asn1_ex_new>
+
+A "new" function responsible for constructing a new B<ASN1_VALUE> object. The
+newly constructed value should be stored in I<*pval>. The I<it> parameter is a
+pointer to the B<ASN1_ITEM> template object created via the
+IMPLEMENT_EXTERN_ASN1() macro.
+
+Returns a positive value on success or 0 on error.
+
+=item I<asn1_ex_free>
+
+A "free" function responsible for freeing the B<ASN1_VALUE> passed in I<*pval>
+that was previously allocated via a "new" function. The I<it> parameter is a
+pointer to the B<ASN1_ITEM> template object created via the
+IMPLEMENT_EXTERN_ASN1() macro.
+
+=item I<asn1_ex_clear>
+
+A "clear" function responsible for clearing any data in the B<ASN1_VALUE> passed
+in I<*pval> and making it suitable for reuse. The I<it> parameter is a pointer
+to the B<ASN1_ITEM> template object created via the IMPLEMENT_EXTERN_ASN1()
+macro.
+
+=item I<asn1_ex_d2i>
+
+A "d2i" function responsible for converting DER data with the tag I<tag> and
+class I<class> into an B<ASN1_VALUE>. If I<*pval> is non-NULL then the
+B<ASN_VALUE> it points to should be reused. Otherwise a new B<ASN1_VALUE>
+should be allocated and stored in I<*pval>. I<*in> points to the DER data to be
+decoded and I<len> is the length of that data. After decoding I<*in> should be
+updated to point at the next byte after the decoded data. If the B<ASN1_VALUE>
+is considered optional in this context then I<opt> will be nonzero. Otherwise
+it will be zero. The I<it> parameter is a pointer to the B<ASN1_ITEM> template
+object created via the IMPLEMENT_EXTERN_ASN1() macro. A pointer to the current
+B<ASN1_TLC> context (which may be required for other ASN1 function calls) is
+passed in the I<ctx> parameter.
+
+The I<asn1_ex_d2i> entry may be NULL if I<asn1_ex_d2i_ex> has been specified
+instead.
+
+Returns <= 0 on error or a positive value on success.
+
+=item I<asn1_ex_i2d>
+
+An "i2d" function responsible for converting an B<ASN1_VALUE> into DER encoding.
+On entry I<*pval> will contain the B<ASN1_VALUE> to be encoded. If default
+tagging is to be used then I<tag> will be -1 on entry. Otherwise if implicit
+tagging should be used then I<tag> and I<aclass> will be the tag and associated
+class.
+
+If I<out> is not NULL then this function should write the DER encoded data to
+the buffer in I<*out>, and then increment I<*out> to point to immediately after
+the data just written.
+
+If I<out> is NULL then no data should be written but the length calculated and
+returned as if it were.
+
+The I<asn1_ex_i2d> entry may be NULL if I<asn1_ex_i2d_ex> has been specified
+instead.
+
+The return value should be negative if a fatal error occurred, or 0 if a
+non-fatal error occurred. Otherwise it should return the length of the encoded
+data.
+
+=item I<asn1_ex_print>
+
+A "print" function. I<out> is the BIO to print the output to. I<*pval> is the
+B<ASN1_VALUE> to be printed. I<indent> is the number of spaces of indenting to
+be printed before any data is printed. I<fname> is currently unused and is
+always "". I<pctx> is a pointer to the B<ASN1_PCTX> for the print operation.
+
+Returns 0 on error or a positive value on success. If the return value is 2 then
+an additional newline will be printed after the data printed by this function.
+
+=item I<asn1_ex_new_ex>
+
+This is the same as I<asn1_ex_new> except that it is additionally passed the
+OSSL_LIB_CTX to be used in I<libctx> and any property query string to be used
+for algorithm fetching in the I<propq> parameter. See
+L<crypto(7)/ALGORITHM FETCHING> for further details. If I<asn1_ex_new_ex> is
+non NULL, then it will always be called in preference to I<asn1_ex_new>.
+
+=item I<asn1_ex_d2i_ex>
+
+This is the same as I<asn1_ex_d2i> except that it is additionally passed the
+OSSL_LIB_CTX to be used in I<libctx> and any property query string to be used
+for algorithm fetching in the I<propq> parameter. See
+L<crypto(7)/ALGORITHM FETCHING> for further details. If I<asn1_ex_d2i_ex> is
+non NULL, then it will always be called in preference to I<asn1_ex_d2i>.
+
+=back
+
+=head1 RETURN VALUES
+
+Return values for the various callbacks are as described above.
+
+=head1 SEE ALSO
+
+L<ASN1_item_new_ex(3)>
+
+=head1 HISTORY
+
+The I<asn1_ex_new_ex> and I<asn1_ex_d2i_ex> callbacks were added in OpenSSL 3.0.
+
+=head1 COPYRIGHT
+
+Copyright 2021 The OpenSSL Project Authors. All Rights Reserved.
+
+Licensed under the Apache License 2.0 (the "License").  You may not use
+this file except in compliance with the License.  You can obtain a copy
+in the file LICENSE in the source distribution or at
+L<https://www.openssl.org/source/license.html>.
+
+=cut
diff --git a/doc/man3/ASN1_aux_cb.pod b/doc/man3/ASN1_aux_cb.pod
new file mode 100644
index 0000000000..12f7ddf82d
--- /dev/null
+++ b/doc/man3/ASN1_aux_cb.pod
@@ -0,0 +1,284 @@
+=pod
+
+=head1 NAME
+
+ASN1_AUX, ASN1_PRINT_ARG, ASN1_STREAM_ARG, ASN1_aux_cb, ASN1_aux_const_cb
+- ASN.1 auxilliary data
+
+=head1 SYNOPSIS
+
+ #include <openssl/asn1t.h>
+
+ struct ASN1_AUX_st {
+     void *app_data;
+     int flags;
+     int ref_offset;             /* Offset of reference value */
+     int ref_lock;               /* Offset to an CRYPTO_RWLOCK */
+     ASN1_aux_cb *asn1_cb;
+     int enc_offset;             /* Offset of ASN1_ENCODING structure */
+     ASN1_aux_const_cb *asn1_const_cb; /* for ASN1_OP_I2D_ and ASN1_OP_PRINT_ */
+ };
+ typedef struct ASN1_AUX_st ASN1_AUX;
+
+ struct ASN1_PRINT_ARG_st {
+     BIO *out;
+     int indent;
+     const ASN1_PCTX *pctx;
+ };
+ typedef struct ASN1_PRINT_ARG_st ASN1_PRINT_ARG;
+
+ struct ASN1_STREAM_ARG_st {
+     BIO *out;
+     BIO *ndef_bio;
+     unsigned char **boundary;
+ };
+ typedef struct ASN1_STREAM_ARG_st ASN1_STREAM_ARG;
+
+ typedef int ASN1_aux_cb(int operation, ASN1_VALUE **in, const ASN1_ITEM *it,
+                         void *exarg);
+ typedef int ASN1_aux_const_cb(int operation, const ASN1_VALUE **in,
+                               const ASN1_ITEM *it, void *exarg);
+
+=head1 DESCRIPTION
+
+ASN.1 data structures can be associated with an B<ASN1_AUX> object to supply
+additional information about the ASN.1 structure. An B<ASN1_AUX> structure is
+associated with the structure during the definition of the ASN.1 template. For
+example an B<ASN1_AUX> structure will be associated by using one of the various
+ASN.1 template definition macros that supply auxilliary information such as
+ASN1_SEQUENCE_enc(), ASN1_SEQUENCE_ref(), ASN1_SEQUENCE_cb_const_cb(),
+ASN1_SEQUENCE_const_cb(), ASN1_SEQUENCE_cb() or ASN1_NDEF_SEQUENCE_cb().
+
+An B<ASN1_AUX> structure contains the following information.
+
+=over 4
+
+=item I<app_data>
+
+Arbitrary application data
+
+=item I<flags>
+
+Flags which indicate the auxiliarly functionality supported.
+
+The B<ASN1_AFLG_REFCOUNT> flag indicates that objects support reference counting.
+
+The B<ASN1_AFLG_ENCODING> flag indicates that the original encoding of the
+object will be saved.
+
+The B<ASN1_AFLG_BROKEN> flag is a work around for broken encoders where the
+sequence length value may not be correct. This should generally not be used.
+
+The B<ASN1_AFLG_CONST_CB> flag indicates that the "const" form of the
+B<ASN1_AUX> callback should be used in preference to the non-const form.
+
+=item I<ref_offset>
+
+If the B<ASN1_AFLG_REFCOUNT> flag is set then this value is assumed to be an
+offset into the B<ASN1_VALUE> structure where a B<CRYPTO_REF_COUNT> may be
+found for the purposes of reference counting.
+
+=item I<ref_lock>
+
+If the B<ASN1_AFLG_REFCOUNT> flag is set then this value is assumed to be an
+offset into the B<ASN1_VALUE> structure where a B<CRYPTO_RWLOCK> may be
+found for the purposes of reference counting.
+
+=item I<asn1_cb>
+
+A callback that will be invoked at various points during the processing of
+the the B<ASN1_VALLUE>. See below for further details.
+
+=item I<enc_offset>
+
+Offset into the B<ASN1_VALUE> object where the original encoding of the object
+will be saved if the B<ASN1_AFLG_ENCODING> flag has been set.
+
+=item I<asn1_const_cb>
+
+A callback that will be invoked at various points during the processing of
+the the B<ASN1_VALLUE>. This is used in preference to the I<asn1_cb> callback if
+the B<ASN1_AFLG_CONST_CB> flag is set. See below for further details.
+
+=back
+
+During the processing of an B<ASN1_VALUE> object the callbacks set via
+I<asn1_cb> or I<asn1_const_cb> will be invoked as a result of various events
+indicated via the I<operation> parameter. The value of I<*in> will be the
+B<ASN1_VALUE> object being processed based on the template in I<it>. An
+additional operation specific parameter may be passed in I<exarg>. The currently
+supported operations are as follows. The callbacks should return a positive
+value on success or zero on error, unless otherwise noted below.
+
+=over 4
+
+=item B<ASN1_OP_NEW_PRE>
+
+Invoked when processing a B<CHOICE>, B<SEQUENCE> or B<NDEF_SEQUENCE> structure
+prior to an B<ASN1_VALUE> object being allocated. The callback may allocate the
+B<ASN1_VALUE> itself and store it in I<*pval>. If it does so it should return 2
+from the callback. On error it should return 0.
+
+=item B<ASN1_OP_NEW_POST>
+
+Invoked when processing a B<CHOICE>, B<SEQUENCE> or B<NDEF_SEQUENCE> structure
+after an B<ASN1_VALUE> object has been allocated. The allocated object is in
+I<*pval>.
+
+=item B<ASN1_OP_FREE_PRE>
+
+Invoked when processing a B<CHOICE>, B<SEQUENCE> or B<NDEF_SEQUENCE> structure
+immediately before an B<ASN1_VALUE> is freed. If the callback originally
+constructed the B<ASN1_VALUE> via B<ASN1_OP_NEW_PRE> then it should free it at
+this point and return 2 from the callback. Otherwise it should return 1 for
+success or 0 on error.
+
+=item B<ASN1_OP_FREE_POST>
+
+Invoked when processing a B<CHOICE>, B<SEQUENCE> or B<NDEF_SEQUENCE> structure
+immediately after B<ASN1_VALUE> sub-structures are freed.
+
+=item B<ASN1_OP_D2I_PRE>
+
+Invoked when processing a B<CHOICE>, B<SEQUENCE> or B<NDEF_SEQUENCE> structure
+immediately before a "d2i" operation for the B<ASN1_VALUE>.
+
+=item B<ASN1_OP_D2I_POST>
+
+Invoked when processing a B<CHOICE>, B<SEQUENCE> or B<NDEF_SEQUENCE> structure
+immediately after a "d2i" operation for the B<ASN1_VALUE>.
+
+=item B<ASN1_OP_I2D_PRE>
+
+Invoked when processing a B<CHOICE>, B<SEQUENCE> or B<NDEF_SEQUENCE> structure
+immediately before a "i2d" operation for the B<ASN1_VALUE>.
+
+=item B<ASN1_OP_I2D_POST>
+
+Invoked when processing a B<CHOICE>, B<SEQUENCE> or B<NDEF_SEQUENCE> structure
+immediately after a "i2d" operation for the B<ASN1_VALUE>.
+
+=item B<ASN1_OP_PRINT_PRE>
+
+Invoked when processing a B<SEQUENCE> or B<NDEF_SEQUENCE> structure immediately
+before printing the B<ASN1_VALUE>. The I<exarg> argument will be a pointer to an
+B<ASN1_PRINT_ARG> structure (see below).
+
+=item B<ASN1_OP_PRINT_POST>
+
+Invoked when processing a B<SEQUENCE> or B<NDEF_SEQUENCE> structure immediately
+after printing the B<ASN1_VALUE>. The I<exarg> argument will be a pointer to an
+B<ASN1_PRINT_ARG> structure (see below).
+
+=item B<ASN1_OP_STREAM_PRE>
+
+Invoked immediately prior to streaming the B<ASN1_VALUE> data using indefinite
+length encoding. The I<exarg> argument will be a pointer to a B<ASN1_STREAM_ARG>
+structure (see below).
+
+=item B<ASN1_OP_STREAM_POST>
+
+Invoked immediately after streaming the B<ASN1_VALUE> data using indefinite
+length encoding. The I<exarg> argument will be a pointer to a B<ASN1_STREAM_ARG>
+structure (see below).
+
+=item B<ASN1_OP_DETACHED_PRE>
+
+Invoked immediately prior to processing the B<ASN1_VALUE> data as a "detached"
+value (as used in CMS and PKCS7). The I<exarg> argument will be a pointer to a
+B<ASN1_STREAM_ARG> structure (see below).
+
+=item B<ASN1_OP_DETACHED_POST>
+
+Invoked immediately after processing the B<ASN1_VALUE> data as a "detached"
+value (as used in CMS and PKCS7). The I<exarg> argument will be a pointer to a
+B<ASN1_STREAM_ARG> structure (see below).
+
+=item B<ASN1_OP_DUP_PRE>
+
+Invoked immediate prior to an ASN1_VALUE being duplicated via a call to
+ASN1_item_dup().
+
+=item B<ASN1_OP_DUP_POST>
+
+Invoked immediate after to an ASN1_VALUE has been duplicated via a call to
+ASN1_item_dup().
+
+=item B<ASN1_OP_GET0_LIBCTX>
+
+Invoked in order to obtain the B<OSSL_LIB_CTX> associated with an B<ASN1_VALUE>
+if any. A pointer to an B<OSSL_LIB_CTX> should be stored in I<*exarg> if such
+a value exists.
+
+=item B<ASN1_OP_GET0_PROPQ>
+
+Invoked in order to obtain the property query string associated with an
+B<ASN1_VALUE> if any. A pointer to the property query string should be stored in
+I<*exarg> if such a value exists.
+
+=back
+
+An B<ASN1_PRINT_ARG> object is used during processing of B<ASN1_OP_PRINT_PRE>
+and B<ASN1_OP_PRINT_POST> callback operations. It contains the following
+information.
+
+=over 4
+
+=item I<out>
+
+The B<BIO> being used to print the data out.
+
+=item I<ndef_bio>
+
+The current number of indent spaces that should be used for printing this data.
+
+=item I<pctx>
+
+The context for the B<ASN1_PCTX> operation.
+
+=back
+
+An B<ASN1_STREAM_ARG> object is used during processing of B<ASN1_OP_STREAM_PRE>,
+B<ASN1_OP_STREAM_POST>, B<ASN1_OP_DETACHED_PRE> and B<ASN1_OP_DETACHED_POST>
+callback operations. It contains the following information.
+
+=over 4
+
+=item I<out>
+
+The B<BIO> to stream through
+
+=item I<ndef_bio>
+
+The B<BIO> with filters appended
+
+=item I<boundary>
+
+The streaming I/O boundary.
+
+=back
+
+=head1 RETURN VALUES
+
+The callbacks return 0 on error and a positive value on success. Some operations
+require specific positive success values as noted above.
+
+=head1 SEE ALSO
+
+L<ASN1_item_new_ex(3)>
+
+=head1 HISTORY
+
+The ASN1_aux_const_cb() callback and the B<ASN1_OP_GET0_LIBCTX> and
+B<ASN1_OP_GET0_PROPQ> operation types were added in OpenSSL 3.0.
+
+=head1 COPYRIGHT
+
+Copyright 2021 The OpenSSL Project Authors. All Rights Reserved.
+
+Licensed under the Apache License 2.0 (the "License").  You may not use
+this file except in compliance with the License.  You can obtain a copy
+in the file LICENSE in the source distribution or at
+L<https://www.openssl.org/source/license.html>.
+
+=cut
diff --git a/doc/man3/ASN1_item_d2i_bio.pod b/doc/man3/ASN1_item_d2i_bio.pod
index bd3c9b06c2..9083f85f69 100644
--- a/doc/man3/ASN1_item_d2i_bio.pod
+++ b/doc/man3/ASN1_item_d2i_bio.pod
@@ -2,23 +2,65 @@
 
 =head1 NAME
 
-ASN1_item_d2i_bio,
-ASN1_item_i2d_mem_bio
+ASN1_item_d2i_ex, ASN1_item_d2i, ASN1_item_d2i_bio_ex, ASN1_item_d2i_bio,
+ASN1_item_d2i_fp_ex, ASN1_item_d2i_fp, ASN1_item_i2d_mem_bio
 - decode and encode DER-encoded ASN.1 structures
 
 =head1 SYNOPSIS
 
  #include <openssl/asn1.h>
 
+ ASN1_VALUE *ASN1_item_d2i_ex(ASN1_VALUE **val, const unsigned char **in,
+                              long len, const ASN1_ITEM *it,
+                              OSSL_LIB_CTX *libctx, const char *propq);
+ ASN1_VALUE *ASN1_item_d2i(ASN1_VALUE **val, const unsigned char **in,
+                           long len, const ASN1_ITEM *it);
+
+ void *ASN1_item_d2i_bio_ex(const ASN1_ITEM *it, BIO *in, void *pval,
+                            OSSL_LIB_CTX *libctx, const char *propq);
  void *ASN1_item_d2i_bio(const ASN1_ITEM *it, BIO *in, void *pval);
+
+ void *ASN1_item_d2i_fp_ex(const ASN1_ITEM *it, FILE *in, void *x,
+                           OSSL_LIB_CTX *libctx, const char *propq);
+ void *ASN1_item_d2i_fp(const ASN1_ITEM *it, FILE *in, void *x);
+
  BIO *ASN1_item_i2d_mem_bio(const ASN1_ITEM *it, const ASN1_VALUE *val);
 
 =head1 DESCRIPTION
 
-ASN1_item_d2i_bio() decodes the contents of its input BIO I<in>,
+ASN1_item_d2i_ex() decodes the contents of the data stored in I<*in> of length
+I<len> which must be a DER-encoded ASN.1 structure, using the ASN.1 template
+I<it>. It places the result in I<*pval> unless I<pval> is NULL. If I<*pval> is
+non-NULL on entry then the B<ASN1_VALUE> present there will be reused. Otherwise
+a new B<ASN1_VALUE> will be allocated. If any algorithm fetches are required
+during the process then they will use the B<OSSL_LIB_CTX>provided in the
+I<libctx> parameter and the property query string in I<propq>. See
+L<crypto(7)/ALGORITHM FETCHING> for more information about algorithm fetching.
+On exit I<*in> will be updated to point to the next byte in the buffer after the
+decoded structure.
+
+ASN1_item_d2i() is the same as ASN1_item_d2i_ex() except that the default
+OSSL_LIB_CTX is used (i.e. NULL) and with a NULL property query string.
+
+ASN1_item_d2i_bio_ex() decodes the contents of its input BIO I<in>,
 which must be a DER-encoded ASN.1 structure, using the ASN.1 template I<it>
 and places the result in I<*pval> unless I<pval> is NULL.
-If I<in> is NULL it returns NULL, else a pointer to the parsed structure.
+If I<in> is NULL it returns NULL, else a pointer to the parsed structure. If any
+algorithm fetches are required during the process then they will use the
+B<OSSL_LIB_CTX> provided in the I<libctx> parameter and the property query
+string in I<propq>. See L<crypto(7)/ALGORITHM FETCHING> for more information
+about algorithm fetching.
+
+ASN1_item_d2i_bio() is the same as ASN1_item_d2i_bio_ex() except that the
+default B<OSSL_LIB_CTX> is used (i.e. NULL) and with a NULL property query
+string.
+
+ASN1_item_d2i_fp_ex() is the same as ASN1_item_d2i_bio_ex() except that a FILE
+pointer is provided instead of a BIO.
+
+ASN1_item_d2i_fp() is the same as ASN1_item_d2i_fp_ex() except that the
+default B<OSSL_LIB_CTX> is used (i.e. NULL) and with a NULL property query
+string.
 
 ASN1_item_i2d_mem_bio() encodes the given ASN.1 value I<val>
 using the ASN.1 template I<it> and returns the result in a memory BIO.
@@ -31,7 +73,8 @@ ASN1_item_i2d_mem_bio() returns a pointer to a memory BIO or NULL on error.
 
 =head1 HISTORY
 
-ASN1_item_i2d_mem_bio() was added in OpenSSL 3.0.
+The functions ASN1_item_d2i_ex(), ASN1_item_d2i_bio_ex(), ASN1_item_d2i_fp_ex()
+and ASN1_item_i2d_mem_bio() were added in OpenSSL 3.0.
 
 =head1 COPYRIGHT
 
diff --git a/doc/man3/ASN1_item_new.pod b/doc/man3/ASN1_item_new.pod
new file mode 100644
index 0000000000..4a495604d4
--- /dev/null
+++ b/doc/man3/ASN1_item_new.pod
@@ -0,0 +1,45 @@
+=pod
+
+=head1 NAME
+
+ASN1_item_new_ex, ASN1_item_new
+- create new ASN.1 values
+
+=head1 SYNOPSIS
+
+ #include <openssl/asn1.h>
+
+ ASN1_VALUE *ASN1_item_new_ex(const ASN1_ITEM *it, OSSL_LIB_CTX *libctx,
+                              const char *propq);
+ ASN1_VALUE *ASN1_item_new(const ASN1_ITEM *it);
+
+=head1 DESCRIPTION
+
+ASN1_item_new_ex() creates a new B<ASN1_VALUE> structure based on the
+B<ASN1_ITEM> template given in the I<it> parameter. If any algorithm fetches are
+required during the process then they will use the B<OSSL_LIB_CTX> provided in
+the I<libctx> parameter and the property query string in I<propq>. See
+L<crypto(7)/ALGORITHM FETCHING> for more information about algorithm fetching.
+
+ASN1_item_new() is the same as ASN1_item_new_ex() except that the default
+B<OSSL_LIB_CTX> is used (i.e. NULL) and with a NULL property query string.
+
+=head1 RETURN VALUES
+
+ASN1_item_new_ex() and ASN1_item_new() return a pointer to the newly created
+B<ASN1_VALUE> or NULL on error.
+
+=head1 HISTORY
+
+The function ASN1_item_new_ex() was added in OpenSSL 3.0.
+
+=head1 COPYRIGHT
+
+Copyright 2021 The OpenSSL Project Authors. All Rights Reserved.
+
+Licensed under the Apache License 2.0 (the "License").  You may not use
+this file except in compliance with the License.  You can obtain a copy
+in the file LICENSE in the source distribution or at
+L<https://www.openssl.org/source/license.html>.
+
+=cut
diff --git a/doc/man3/SMIME_read_ASN1.pod b/doc/man3/SMIME_read_ASN1.pod
index 56d1e67dcd..a90d9a4004 100644
--- a/doc/man3/SMIME_read_ASN1.pod
+++ b/doc/man3/SMIME_read_ASN1.pod
@@ -10,7 +10,8 @@ SMIME_read_ASN1_ex, SMIME_read_ASN1
  #include <openssl/asn1.h>
 
  ASN1_VALUE *SMIME_read_ASN1_ex(BIO *in, int flags, BIO **bcont,
-                                const ASN1_ITEM *it, ASN1_VALUE **x);
+                                const ASN1_ITEM *it, ASN1_VALUE **x,
+                                OSSL_LIB_CTX *libctx, const char *propq);
  ASN1_VALUE *SMIME_read_ASN1(BIO *in, BIO **bcont, const ASN1_ITEM *it);
 
 =head1 DESCRIPTION
@@ -25,7 +26,10 @@ to be followed by B<CR> and B<LF> characters, else only by an B<LF> character.
 I<x> can be used to optionally supply
 a previously created I<it> ASN1_VALUE object (such as CMS_ContentInfo or PKCS7),
 it can be set to NULL. Valid values that can be used by ASN.1 structure I<it>
-are ASN1_ITEM_rptr(PKCS7) or ASN1_ITEM_rptr(CMS_ContentInfo).
+are ASN1_ITEM_rptr(PKCS7) or ASN1_ITEM_rptr(CMS_ContentInfo). Any algorithm
+fetches that occur during the operation will use the B<OSSL_LIB_CTX> supplied in
+the I<libctx> parameter, and use the property query string I<propq> See
+L<crypto(7)/ALGORITHM FETCHING> for further details about algorithm fetching.
 
 If cleartext signing is used then the content is saved in a memory bio which is
 written to I<*bcont>, otherwise I<*bcont> is set to NULL.
diff --git a/doc/man3/X509_PUBKEY_new.pod b/doc/man3/X509_PUBKEY_new.pod
index 059f2ac564..3d22857b80 100644
--- a/doc/man3/X509_PUBKEY_new.pod
+++ b/doc/man3/X509_PUBKEY_new.pod
@@ -2,7 +2,7 @@
 
 =head1 NAME
 
-X509_PUBKEY_new, X509_PUBKEY_free, X509_PUBKEY_dup,
+X509_PUBKEY_new_ex, X509_PUBKEY_new, X509_PUBKEY_free, X509_PUBKEY_dup,
 X509_PUBKEY_set, X509_PUBKEY_get0, X509_PUBKEY_get,
 d2i_PUBKEY_ex, d2i_PUBKEY, i2d_PUBKEY, d2i_PUBKEY_bio, d2i_PUBKEY_fp,
 i2d_PUBKEY_fp, i2d_PUBKEY_bio, X509_PUBKEY_set0_param, X509_PUBKEY_get0_param,
@@ -12,6 +12,7 @@ X509_PUBKEY_eq - SubjectPublicKeyInfo public key functions
 
  #include <openssl/x509.h>
 
+ X509_PUBKEY *X509_PUBKEY_new_ex(OSSL_LIB_CTX *libctx, const char *propq);
  X509_PUBKEY *X509_PUBKEY_new(void);
  void X509_PUBKEY_free(X509_PUBKEY *a);
  X509_PUBKEY *X509_PUBKEY_dup(const X509_PUBKEY *a);
@@ -44,7 +45,14 @@ X509_PUBKEY_eq - SubjectPublicKeyInfo public key functions
 The B<X509_PUBKEY> structure represents the ASN.1 B<SubjectPublicKeyInfo>
 structure defined in RFC5280 and used in certificates and certificate requests.
 
-X509_PUBKEY_new() allocates and initializes an B<X509_PUBKEY> structure.
+X509_PUBKEY_new_ex() allocates and initializes an B<X509_PUBKEY> structure
+associated with the given B<OSSL_LIB_CTX> in the I<libctx> parameter. Any
+algorithm fetches associated with using the B<X509_PUBKEY> object will use
+the property query string I<propq>. See L<crypto(7)/ALGORITHM FETCHING> for
+further information about algorithm fetching.
+
+X509_PUBKEY_new() is the same as X509_PUBKEY_new_ex() except that the default
+(NULL) B<OSSL_LIB_CTX> and a NULL property query string are used.
 
 X509_PUBKEY_dup() creates a duplicate copy of the B<X509_PUBKEY> object
 specified by I<a>.
@@ -127,7 +135,8 @@ L<X509_get_pubkey(3)>,
 
 =head1 HISTORY
 
-The X509_PUBKEY_eq() function was added in OpenSSL 3.0.
+The X509_PUBKEY_new_ex() and X509_PUBKEY_eq() functions were added in OpenSSL
+3.0.
 
 =head1 COPYRIGHT
 
diff --git a/doc/man7/migration_guide.pod b/doc/man7/migration_guide.pod
index e2d21a9540..6a71d68b9a 100644
--- a/doc/man7/migration_guide.pod
+++ b/doc/man7/migration_guide.pod
@@ -562,10 +562,11 @@ B<const EVP_CIPHER *> such as EVP_aes_128_cbc() should be replaced vith a call t
 L<EVP_CIPHER_fetch(3)>. See L<crypto(7)/ALGORITHM FETCHING>.
 
 Some functions can be passed an object that has already been set up with a library
-context such as L<d2i_X509(3)>, L<d2i_X509_CRL(3)> and L<d2i_X509_REQ(3)>.
-If NULL is passed instead then the created object will be set up with the
-default library context. Use L<X509_new_ex(3)>, L<X509_CRL_new_ex(3)> and
-L<X509_REQ_new_ex(3)> if a library context is required.
+context such as L<d2i_X509(3)>, L<d2i_X509_CRL(3)>, L<d2i_X509_REQ(3)> and
+L<d2i_X509_PUBKEY(3)>. If NULL is passed instead then the created object will be
+set up with the default library context. Use L<X509_new_ex(3)>,
+L<X509_CRL_new_ex(3)>, L<X509_REQ_new_ex(3)> and L<X509_PUBKEY_new_ex(3)> if a
+library context is required.
 
 All functions listed below with a I<NAME> have a replacment function I<NAME_ex>
 that takes B<OSSL_LIB_CTX> as an additional argument. Functions that have other
@@ -575,7 +576,8 @@ mappings are listed along with the respective name.
 
 =item -
 
-L<ASN1_item_sign(3)> and L<ASN1_item_verify(3)>
+L<ASN1_item_new(3)>, L<ASN1_item_d2i(3)>, L<ASN1_item_d2i_fp(3)>,
+L<ASN1_item_d2i_bio(3)>, L<ASN1_item_sign(3)> and L<ASN1_item_verify(3)>
 
 =item -
 
diff --git a/include/openssl/asn1.h.in b/include/openssl/asn1.h.in
index e2b2b25cf3..40b43a227a 100644
--- a/include/openssl/asn1.h.in
+++ b/include/openssl/asn1.h.in
@@ -762,6 +762,8 @@ void *ASN1_d2i_fp(void *(*xnew) (void), d2i_of_void *d2i, FILE *in, void **x);
                         in, \
                         CHECKED_PPTR_OF(type, x)))
 
+void *ASN1_item_d2i_fp_ex(const ASN1_ITEM *it, FILE *in, void *x,
+                          OSSL_LIB_CTX *libctx, const char *propq);
 void *ASN1_item_d2i_fp(const ASN1_ITEM *it, FILE *in, void *x);
 int ASN1_i2d_fp(i2d_of_void *i2d, FILE *out, const void *x);
 
@@ -784,6 +786,8 @@ void *ASN1_d2i_bio(void *(*xnew) (void), d2i_of_void *d2i, BIO *in, void **x);
                           in, \
                           CHECKED_PPTR_OF(type, x)))
 
+void *ASN1_item_d2i_bio_ex(const ASN1_ITEM *it, BIO *in, void *pval,
+                           OSSL_LIB_CTX *libctx, const char *propq);
 void *ASN1_item_d2i_bio(const ASN1_ITEM *it, BIO *in, void *pval);
 int ASN1_i2d_bio(i2d_of_void *i2d, BIO *out, const void *x);
 
@@ -843,7 +847,12 @@ void ASN1_STRING_TABLE_cleanup(void);
 
 /* Old API compatible functions */
 ASN1_VALUE *ASN1_item_new(const ASN1_ITEM *it);
+ASN1_VALUE *ASN1_item_new_ex(const ASN1_ITEM *it, OSSL_LIB_CTX *libctx,
+                             const char *propq);
 void ASN1_item_free(ASN1_VALUE *val, const ASN1_ITEM *it);
+ASN1_VALUE *ASN1_item_d2i_ex(ASN1_VALUE **val, const unsigned char **in,
+                             long len, const ASN1_ITEM *it,
+                             OSSL_LIB_CTX *libctx, const char *propq);
 ASN1_VALUE *ASN1_item_d2i(ASN1_VALUE **val, const unsigned char **in,
                           long len, const ASN1_ITEM *it);
 int ASN1_item_i2d(const ASN1_VALUE *val, unsigned char **out, const ASN1_ITEM *it);
@@ -919,8 +928,9 @@ int SMIME_write_ASN1_ex(BIO *bio, ASN1_VALUE *val, BIO *data, int flags,
                         STACK_OF(X509_ALGOR) *mdalgs, const ASN1_ITEM *it,
                         OSSL_LIB_CTX *libctx, const char *propq);
 ASN1_VALUE *SMIME_read_ASN1(BIO *bio, BIO **bcont, const ASN1_ITEM *it);
-ASN1_VALUE *SMIME_read_ASN1_ex(BIO *bio, int flags, BIO **bcont, const ASN1_ITEM *it,
-                               ASN1_VALUE **x);
+ASN1_VALUE *SMIME_read_ASN1_ex(BIO *bio, int flags, BIO **bcont,
+                               const ASN1_ITEM *it, ASN1_VALUE **x,
+                               OSSL_LIB_CTX *libctx, const char *propq);
 int SMIME_crlf_copy(BIO *in, BIO *out, int flags);
 int SMIME_text(BIO *in, BIO *out);
 
diff --git a/include/openssl/asn1t.h.in b/include/openssl/asn1t.h.in
index 2f40d1ca15..2e47473327 100644
--- a/include/openssl/asn1t.h.in
+++ b/include/openssl/asn1t.h.in
@@ -631,9 +631,15 @@ typedef int ASN1_ex_d2i(ASN1_VALUE **pval, const unsigned char **in, long len,
                         const ASN1_ITEM *it, int tag, int aclass, char opt,
                         ASN1_TLC *ctx);
 
+typedef int ASN1_ex_d2i_ex(ASN1_VALUE **pval, const unsigned char **in, long len,
+                           const ASN1_ITEM *it, int tag, int aclass, char opt,
+                           ASN1_TLC *ctx, OSSL_LIB_CTX *libctx,
+                           const char *propq);
 typedef int ASN1_ex_i2d(const ASN1_VALUE **pval, unsigned char **out,
                         const ASN1_ITEM *it, int tag, int aclass);
 typedef int ASN1_ex_new_func(ASN1_VALUE **pval, const ASN1_ITEM *it);
+typedef int ASN1_ex_new_ex_func(ASN1_VALUE **pval, const ASN1_ITEM *it,
+                                OSSL_LIB_CTX *libctx, const char *propq);
 typedef void ASN1_ex_free_func(ASN1_VALUE **pval, const ASN1_ITEM *it);
 
 typedef int ASN1_ex_print_func(BIO *out, const ASN1_VALUE **pval,
@@ -657,6 +663,8 @@ typedef struct ASN1_EXTERN_FUNCS_st {
     ASN1_ex_d2i *asn1_ex_d2i;
     ASN1_ex_i2d *asn1_ex_i2d;
     ASN1_ex_print_func *asn1_ex_print;
+    ASN1_ex_new_ex_func *asn1_ex_new_ex;
+    ASN1_ex_d2i_ex *asn1_ex_d2i_ex;
 } ASN1_EXTERN_FUNCS;
 
 typedef struct ASN1_PRIMITIVE_FUNCS_st {
@@ -696,7 +704,7 @@ typedef struct ASN1_AUX_st {
     void *app_data;
     int flags;
     int ref_offset;             /* Offset of reference value */
-    int ref_lock;               /* Lock type to use */
+    int ref_lock;               /* Offset of lock value */
     ASN1_aux_cb *asn1_cb;
     int enc_offset;             /* Offset of ASN1_ENCODING structure */
     ASN1_aux_const_cb *asn1_const_cb; /* for ASN1_OP_I2D_ and ASN1_OP_PRINT_ */
@@ -748,6 +756,8 @@ typedef struct ASN1_STREAM_ARG_st {
 # define ASN1_OP_DETACHED_POST   13
 # define ASN1_OP_DUP_PRE         14
 # define ASN1_OP_DUP_POST        15
+# define ASN1_OP_GET0_LIBCTX     16
+# define ASN1_OP_GET0_PROPQ      17
 
 /* Macro to implement a primitive type */
 # define IMPLEMENT_ASN1_TYPE(stname) IMPLEMENT_ASN1_TYPE_ex(stname, stname, 0)
diff --git a/include/openssl/cmp.h.in b/include/openssl/cmp.h.in
index 352ffcdb2f..27afa27d6a 100644
--- a/include/openssl/cmp.h.in
+++ b/include/openssl/cmp.h.in
@@ -380,7 +380,8 @@ ASN1_OCTET_STRING *OSSL_CMP_HDR_get0_recipNonce(const OSSL_CMP_PKIHEADER *hdr);
 OSSL_CMP_PKIHEADER *OSSL_CMP_MSG_get0_header(const OSSL_CMP_MSG *msg);
 int OSSL_CMP_MSG_update_transactionID(OSSL_CMP_CTX *ctx, OSSL_CMP_MSG *msg);
 OSSL_CRMF_MSG *OSSL_CMP_CTX_setup_CRM(OSSL_CMP_CTX *ctx, int for_KUR, int rid);
-OSSL_CMP_MSG *OSSL_CMP_MSG_read(const char *file);
+OSSL_CMP_MSG *OSSL_CMP_MSG_read(const char *file, OSSL_LIB_CTX *libctx,
+                                const char *propq);
 int OSSL_CMP_MSG_write(const char *file, const OSSL_CMP_MSG *msg);
 OSSL_CMP_MSG *d2i_OSSL_CMP_MSG_bio(BIO *bio, OSSL_CMP_MSG **msg);
 int i2d_OSSL_CMP_MSG_bio(BIO *bio, const OSSL_CMP_MSG *msg);
diff --git a/include/openssl/x509.h.in b/include/openssl/x509.h.in
index d5d3cdb719..38c7b42c22 100644
--- a/include/openssl/x509.h.in
+++ b/include/openssl/x509.h.in
@@ -550,6 +550,7 @@ DECLARE_ASN1_FUNCTIONS(X509_VAL)
 
 DECLARE_ASN1_FUNCTIONS(X509_PUBKEY)
 
+X509_PUBKEY *X509_PUBKEY_new_ex(OSSL_LIB_CTX *libctx, const char *propq);
 int X509_PUBKEY_set(X509_PUBKEY **x, EVP_PKEY *pkey);
 EVP_PKEY *X509_PUBKEY_get0(const X509_PUBKEY *key);
 EVP_PKEY *X509_PUBKEY_get(const X509_PUBKEY *key);
diff --git a/test/cmp_client_test.c b/test/cmp_client_test.c
index 863a765886..f470f5e445 100644
--- a/test/cmp_client_test.c
+++ b/test/cmp_client_test.c
@@ -223,7 +223,7 @@ static int test_exec_P10CR_ses(void)
     SETUP_TEST_FIXTURE(CMP_SES_TEST_FIXTURE, set_up);
     fixture->req_type = OSSL_CMP_P10CR;
     fixture->expected = 1;
-    if (!TEST_ptr(req = load_csr_der(pkcs10_f))
+    if (!TEST_ptr(req = load_csr_der(pkcs10_f, libctx))
             || !TEST_true(OSSL_CMP_CTX_set1_p10CSR(fixture->cmp_ctx, req))) {
         tear_down(fixture);
         fixture = NULL;
diff --git a/test/cmp_msg_test.c b/test/cmp_msg_test.c
index a9a858c07a..4f2ca1b40b 100644
--- a/test/cmp_msg_test.c
+++ b/test/cmp_msg_test.c
@@ -226,7 +226,7 @@ static int test_cmp_create_p10cr(void)
     fixture->bodytype = OSSL_CMP_PKIBODY_P10CR;
     fixture->err_code = CMP_R_ERROR_CREATING_CERTREQ;
     fixture->expected = 1;
-    if (!TEST_ptr(p10cr = load_csr_der(pkcs10_f))
+    if (!TEST_ptr(p10cr = load_csr_der(pkcs10_f, libctx))
             || !TEST_true(set1_newPkey(ctx, newkey))
             || !TEST_true(OSSL_CMP_CTX_set1_p10CSR(ctx, p10cr))) {
         tear_down(fixture);
@@ -504,7 +504,7 @@ static int test_cmp_pkimessage_create(int bodytype)
     switch (fixture->bodytype = bodytype) {
     case OSSL_CMP_PKIBODY_P10CR:
         fixture->expected = 1;
-        p10cr = load_csr_der(pkcs10_f);
+        p10cr = load_csr_der(pkcs10_f, libctx);
         if (!TEST_true(OSSL_CMP_CTX_set1_p10CSR(fixture->cmp_ctx, p10cr))) {
             tear_down(fixture);
             fixture = NULL;
diff --git a/test/cmp_protect_test.c b/test/cmp_protect_test.c
index 5fafb69475..9111b89423 100644
--- a/test/cmp_protect_test.c
+++ b/test/cmp_protect_test.c
@@ -143,7 +143,7 @@ static int execute_calc_protection_signature_test(CMP_PROTECT_TEST_FIXTURE *
 static int test_cmp_calc_protection_no_key_no_secret(void)
 {
     SETUP_TEST_FIXTURE(CMP_PROTECT_TEST_FIXTURE, set_up);
-    if (!TEST_ptr(fixture->msg = load_pkimsg(ir_unprotected_f))
+    if (!TEST_ptr(fixture->msg = load_pkimsg(ir_unprotected_f, libctx))
             || !TEST_ptr(fixture->msg->header->protectionAlg =
                          X509_ALGOR_new() /* no specific alg needed here */)) {
         tear_down(fixture);
@@ -159,7 +159,7 @@ static int test_cmp_calc_protection_pkey(void)
     SETUP_TEST_FIXTURE(CMP_PROTECT_TEST_FIXTURE, set_up);
     fixture->pubkey = loadedpubkey;
     if (!TEST_true(OSSL_CMP_CTX_set1_pkey(fixture->cmp_ctx, loadedprivkey))
-            || !TEST_ptr(fixture->msg = load_pkimsg(ir_protected_f))) {
+            || !TEST_ptr(fixture->msg = load_pkimsg(ir_protected_f, libctx))) {
         tear_down(fixture);
         fixture = NULL;
     }
@@ -174,7 +174,7 @@ static int test_cmp_calc_protection_pbmac(void)
     SETUP_TEST_FIXTURE(CMP_PROTECT_TEST_FIXTURE, set_up);
     if (!TEST_true(OSSL_CMP_CTX_set1_secretValue(fixture->cmp_ctx,
                                                  sec_insta, sizeof(sec_insta)))
-            || !TEST_ptr(fixture->msg = load_pkimsg(ip_PBM_f))) {
+            || !TEST_ptr(fixture->msg = load_pkimsg(ip_PBM_f, libctx))) {
         tear_down(fixture);
         fixture = NULL;
     }
@@ -577,8 +577,8 @@ int setup_tests(void)
         return 0;
     if (TEST_true(EVP_PKEY_up_ref(loadedprivkey)))
         loadedpubkey = loadedprivkey;
-    if (!TEST_ptr(ir_protected = load_pkimsg(ir_protected_f))
-            || !TEST_ptr(ir_unprotected = load_pkimsg(ir_unprotected_f)))
+    if (!TEST_ptr(ir_protected = load_pkimsg(ir_protected_f, libctx))
+            || !TEST_ptr(ir_unprotected = load_pkimsg(ir_unprotected_f, libctx)))
         return 0;
     if (!TEST_ptr(endentity1 = load_cert_pem(endentity1_f, libctx))
             || !TEST_ptr(endentity2 = load_cert_pem(endentity2_f, libctx))
diff --git a/test/cmp_server_test.c b/test/cmp_server_test.c
index bff42c8baf..d93a75db81 100644
--- a/test/cmp_server_test.c
+++ b/test/cmp_server_test.c
@@ -148,7 +148,7 @@ int setup_tests(void)
     if (!test_arg_libctx(&libctx, &default_null_provider, &provider, 1, USAGE))
         return 0;
 
-    if (!TEST_ptr(request = load_pkimsg(request_f))) {
+    if (!TEST_ptr(request = load_pkimsg(request_f, libctx))) {
         cleanup_tests();
         return 0;
     }
diff --git a/test/cmp_vfy_test.c b/test/cmp_vfy_test.c
index 2a06e0b097..a480090363 100644
--- a/test/cmp_vfy_test.c
+++ b/test/cmp_vfy_test.c
@@ -91,7 +91,7 @@ static int flip_bit(ASN1_BIT_STRING *bitstr)
 
 static int execute_verify_popo_test(CMP_VFY_TEST_FIXTURE *fixture)
 {
-    if ((fixture->msg = load_pkimsg(ir_protected_f)) == NULL)
+    if ((fixture->msg = load_pkimsg(ir_protected_f, libctx)) == NULL)
         return 0;
     if (fixture->expected == 0) {
         const OSSL_CRMF_MSGS *reqs = fixture->msg->body->value.ir;
@@ -153,7 +153,7 @@ static int test_validate_msg_mac_alg_protection(void)
     fixture->expected = 1;
     if (!TEST_true(OSSL_CMP_CTX_set1_secretValue(fixture->cmp_ctx, sec_1,
                                                  sizeof(sec_1)))
-            || !TEST_ptr(fixture->msg = load_pkimsg(ip_waiting_f))) {
+            || !TEST_ptr(fixture->msg = load_pkimsg(ip_waiting_f, libctx))) {
         tear_down(fixture);
         fixture = NULL;
     }
@@ -174,7 +174,7 @@ static int test_validate_msg_mac_alg_protection_bad(void)
 
     if (!TEST_true(OSSL_CMP_CTX_set1_secretValue(fixture->cmp_ctx, sec_bad,
                                                  sizeof(sec_bad)))
-            || !TEST_ptr(fixture->msg = load_pkimsg(ip_waiting_f))) {
+            || !TEST_ptr(fixture->msg = load_pkimsg(ip_waiting_f, libctx))) {
         tear_down(fixture);
         fixture = NULL;
     }
@@ -203,7 +203,7 @@ static int test_validate_msg_signature_partial_chain(int expired)
     ts = OSSL_CMP_CTX_get0_trustedStore(fixture->cmp_ctx);
     fixture->expected = !expired;
     if (ts == NULL
-            || !TEST_ptr(fixture->msg = load_pkimsg(ir_protected_f))
+            || !TEST_ptr(fixture->msg = load_pkimsg(ir_protected_f, libctx))
             || !add_trusted(fixture->cmp_ctx, srvcert)) {
         tear_down(fixture);
         fixture = NULL;
@@ -233,7 +233,7 @@ static int test_validate_msg_signature_srvcert_wrong(void)
 {
     SETUP_TEST_FIXTURE(CMP_VFY_TEST_FIXTURE, set_up);
     fixture->expected = 0;
-    if (!TEST_ptr(fixture->msg = load_pkimsg(ir_protected_f))
+    if (!TEST_ptr(fixture->msg = load_pkimsg(ir_protected_f, libctx))
         || !TEST_true(OSSL_CMP_CTX_set1_srvCert(fixture->cmp_ctx, clcert))) {
         tear_down(fixture);
         fixture = NULL;
@@ -246,7 +246,7 @@ static int test_validate_msg_signature_srvcert(int bad_sig)
 {
     SETUP_TEST_FIXTURE(CMP_VFY_TEST_FIXTURE, set_up);
     fixture->expected = !bad_sig;
-    if (!TEST_ptr(fixture->msg = load_pkimsg(ir_protected_f))
+    if (!TEST_ptr(fixture->msg = load_pkimsg(ir_protected_f, libctx))
         || !TEST_true(OSSL_CMP_CTX_set1_srvCert(fixture->cmp_ctx, srvcert))
         || (bad_sig && !flip_bit(fixture->msg->protection))) {
         tear_down(fixture);
@@ -272,7 +272,7 @@ static int test_validate_msg_signature_sender_cert_untrusted(void)
 {
     SETUP_TEST_FIXTURE(CMP_VFY_TEST_FIXTURE, set_up);
     fixture->expected = 1;
-    if (!TEST_ptr(fixture->msg = load_pkimsg(ir_protected_0_extracerts))
+    if (!TEST_ptr(fixture->msg = load_pkimsg(ir_protected_0_extracerts, libctx))
             || !add_trusted(fixture->cmp_ctx, instaca_cert)
             || !add_untrusted(fixture->cmp_ctx, insta_cert)) {
         tear_down(fixture);
@@ -286,7 +286,7 @@ static int test_validate_msg_signature_sender_cert_trusted(void)
 {
     SETUP_TEST_FIXTURE(CMP_VFY_TEST_FIXTURE, set_up);
     fixture->expected = 1;
-    if (!TEST_ptr(fixture->msg = load_pkimsg(ir_protected_0_extracerts))
+    if (!TEST_ptr(fixture->msg = load_pkimsg(ir_protected_0_extracerts, libctx))
             || !add_trusted(fixture->cmp_ctx, instaca_cert)
             || !add_trusted(fixture->cmp_ctx, insta_cert)) {
         tear_down(fixture);
@@ -300,7 +300,7 @@ static int test_validate_msg_signature_sender_cert_extracert(void)
 {
     SETUP_TEST_FIXTURE(CMP_VFY_TEST_FIXTURE, set_up);
     fixture->expected = 1;
-    if (!TEST_ptr(fixture->msg = load_pkimsg(ir_protected_2_extracerts))
+    if (!TEST_ptr(fixture->msg = load_pkimsg(ir_protected_2_extracerts, libctx))
             || !add_trusted(fixture->cmp_ctx, instaca_cert)) {
         tear_down(fixture);
         fixture = NULL;
@@ -315,7 +315,7 @@ static int test_validate_msg_signature_sender_cert_absent(void)
 {
     SETUP_TEST_FIXTURE(CMP_VFY_TEST_FIXTURE, set_up);
     fixture->expected = 0;
-    if (!TEST_ptr(fixture->msg = load_pkimsg(ir_protected_0_extracerts))) {
+    if (!TEST_ptr(fixture->msg = load_pkimsg(ir_protected_0_extracerts, libctx))) {
         tear_down(fixture);
         fixture = NULL;
     }
@@ -328,7 +328,7 @@ static int test_validate_with_sender(const X509_NAME *name, int expected)
 {
     SETUP_TEST_FIXTURE(CMP_VFY_TEST_FIXTURE, set_up);
     fixture->expected = expected;
-    if (!TEST_ptr(fixture->msg = load_pkimsg(ir_protected_f))
+    if (!TEST_ptr(fixture->msg = load_pkimsg(ir_protected_f, libctx))
         || !TEST_true(OSSL_CMP_CTX_set1_expected_sender(fixture->cmp_ctx, name))
         || !TEST_true(OSSL_CMP_CTX_set1_srvCert(fixture->cmp_ctx, srvcert))) {
         tear_down(fixture);
@@ -353,7 +353,7 @@ static int test_validate_msg_unprotected_request(void)
 {
     SETUP_TEST_FIXTURE(CMP_VFY_TEST_FIXTURE, set_up);
     fixture->expected = 0;
-    if (!TEST_ptr(fixture->msg = load_pkimsg(ir_unprotected_f))) {
+    if (!TEST_ptr(fixture->msg = load_pkimsg(ir_unprotected_f, libctx))) {
         tear_down(fixture);
         fixture = NULL;
     }
@@ -620,8 +620,8 @@ int setup_tests(void)
         goto err;
     if (!TEST_int_eq(1, RAND_bytes(rand_data, OSSL_CMP_TRANSACTIONID_LENGTH)))
         goto err;
-    if (!TEST_ptr(ir_unprotected = load_pkimsg(ir_unprotected_f))
-            || !TEST_ptr(ir_rmprotection = load_pkimsg(ir_rmprotection_f)))
+    if (!TEST_ptr(ir_unprotected = load_pkimsg(ir_unprotected_f, libctx))
+            || !TEST_ptr(ir_rmprotection = load_pkimsg(ir_rmprotection_f, libctx)))
         goto err;
 
     /* Message validation tests */
diff --git a/test/evp_extra_test.c b/test/evp_extra_test.c
index f91784b3a9..f26330b5d8 100644
--- a/test/evp_extra_test.c
+++ b/test/evp_extra_test.c
@@ -1945,11 +1945,13 @@ static int test_emptyikm_HKDF(void)
 static int test_X509_PUBKEY_inplace(void)
 {
     int ret = 0;
-    X509_PUBKEY *xp = NULL;
+    X509_PUBKEY *xp = X509_PUBKEY_new_ex(testctx, testpropq);
     const unsigned char *p = kExampleECPubKeyDER;
     size_t input_len = sizeof(kExampleECPubKeyDER);
 
-    if (!TEST_ptr(xp = d2i_X509_PUBKEY(NULL, &p, input_len)))
+    if (!TEST_ptr(xp))
+        goto done;
+    if (!TEST_ptr(d2i_X509_PUBKEY(&xp, &p, input_len)))
         goto done;
 
     if (!TEST_ptr(X509_PUBKEY_get0(xp)))
@@ -1978,7 +1980,9 @@ static int test_X509_PUBKEY_dup(void)
     const unsigned char *p = kExampleECPubKeyDER;
     size_t input_len = sizeof(kExampleECPubKeyDER);
 
-    if (!TEST_ptr(xp = d2i_X509_PUBKEY(NULL, &p, input_len))
+    xp = X509_PUBKEY_new_ex(testctx, testpropq);
+    if (!TEST_ptr(xp)
+            || !TEST_ptr(d2i_X509_PUBKEY(&xp, &p, input_len))
             || !TEST_ptr(xq = X509_PUBKEY_dup(xp))
             || !TEST_ptr_ne(xp, xq))
         goto done;
diff --git a/test/helpers/cmp_testlib.c b/test/helpers/cmp_testlib.c
index 2d7297c42b..e0fb1d3d34 100644
--- a/test/helpers/cmp_testlib.c
+++ b/test/helpers/cmp_testlib.c
@@ -12,11 +12,11 @@
 #include "cmp_testlib.h"
 #include <openssl/rsa.h> /* needed in case config no-deprecated */
 
-OSSL_CMP_MSG *load_pkimsg(const char *file)
+OSSL_CMP_MSG *load_pkimsg(const char *file, OSSL_LIB_CTX *libctx)
 {
     OSSL_CMP_MSG *msg;
 
-    (void)TEST_ptr((msg = OSSL_CMP_MSG_read(file)));
+    (void)TEST_ptr((msg = OSSL_CMP_MSG_read(file, libctx, NULL)));
     return msg;
 }
 
diff --git a/test/helpers/cmp_testlib.h b/test/helpers/cmp_testlib.h
index 681b06ae22..50b085beca 100644
--- a/test/helpers/cmp_testlib.h
+++ b/test/helpers/cmp_testlib.h
@@ -21,7 +21,7 @@
 
 # ifndef OPENSSL_NO_CMP
 #  define CMP_TEST_REFVALUE_LENGTH 15 /* arbitrary value */
-OSSL_CMP_MSG *load_pkimsg(const char *file);
+OSSL_CMP_MSG *load_pkimsg(const char *file, OSSL_LIB_CTX *libctx);
 int valid_asn1_encoding(const OSSL_CMP_MSG *msg);
 int STACK_OF_X509_cmp(const STACK_OF(X509) *sk1, const STACK_OF(X509) *sk2);
 int STACK_OF_X509_push1(STACK_OF(X509) *sk, X509 *cert);
diff --git a/test/testutil.h b/test/testutil.h
index 710f51c147..c28df702cc 100644
--- a/test/testutil.h
+++ b/test/testutil.h
@@ -592,6 +592,6 @@ EVP_PKEY *load_pkey_pem(const char *file, OSSL_LIB_CTX *libctx);
 X509 *load_cert_pem(const char *file, OSSL_LIB_CTX *libctx);
 X509 *load_cert_der(const unsigned char *bytes, int len);
 STACK_OF(X509) *load_certs_pem(const char *file);
-X509_REQ *load_csr_der(const char *file);
+X509_REQ *load_csr_der(const char *file, OSSL_LIB_CTX *libctx);
 
 #endif                          /* OSSL_TESTUTIL_H */
diff --git a/test/testutil/load.c b/test/testutil/load.c
index 444fb8a78d..be30d7e053 100644
--- a/test/testutil/load.c
+++ b/test/testutil/load.c
@@ -81,14 +81,17 @@ EVP_PKEY *load_pkey_pem(const char *file, OSSL_LIB_CTX *libctx)
     return key;
 }
 
-X509_REQ *load_csr_der(const char *file)
+X509_REQ *load_csr_der(const char *file, OSSL_LIB_CTX *libctx)
 {
     X509_REQ *csr = NULL;
     BIO *bio = NULL;
 
     if (!TEST_ptr(file) || !TEST_ptr(bio = BIO_new_file(file, "rb")))
         return NULL;
-    (void)TEST_ptr(csr = d2i_X509_REQ_bio(bio, NULL));
+
+    csr = X509_REQ_new_ex(libctx, NULL);
+    if (TEST_ptr(csr))
+        (void)TEST_ptr(d2i_X509_REQ_bio(bio, &csr));
     BIO_free(bio);
     return csr;
 }
diff --git a/util/libcrypto.num b/util/libcrypto.num
index 6f763f1063..5c36c4d44a 100644
--- a/util/libcrypto.num
+++ b/util/libcrypto.num
@@ -5407,3 +5407,8 @@ b2i_PVK_bio_ex                          ?	3_0_0	EXIST::FUNCTION:
 i2b_PVK_bio_ex                          ?	3_0_0	EXIST::FUNCTION:
 NCONF_get0_libctx                       ?	3_0_0	EXIST::FUNCTION:
 NCONF_get_section_names                 ?	3_0_0	EXIST::FUNCTION:
+X509_PUBKEY_new_ex                      ?	3_0_0	EXIST::FUNCTION:
+ASN1_item_new_ex                        ?	3_0_0	EXIST::FUNCTION:
+ASN1_item_d2i_fp_ex                     ?	3_0_0	EXIST::FUNCTION:STDIO
+ASN1_item_d2i_bio_ex                    ?	3_0_0	EXIST::FUNCTION:
+ASN1_item_d2i_ex                        ?	3_0_0	EXIST::FUNCTION:
diff --git a/util/missingcrypto.txt b/util/missingcrypto.txt
index cd81ba7e09..67bfc7859d 100644
--- a/util/missingcrypto.txt
+++ b/util/missingcrypto.txt
@@ -137,9 +137,6 @@ ASN1_dup(3)
 ASN1_get_object(3)
 ASN1_i2d_bio(3)
 ASN1_i2d_fp(3)
-ASN1_item_d2i(3)
-ASN1_item_d2i_bio(3)
-ASN1_item_d2i_fp(3)
 ASN1_item_digest(3)
 ASN1_item_dup(3)
 ASN1_item_ex_d2i(3)
@@ -151,7 +148,6 @@ ASN1_item_i2d(3)
 ASN1_item_i2d_bio(3)
 ASN1_item_i2d_fp(3)
 ASN1_item_ndef_i2d(3)
-ASN1_item_new(3)
 ASN1_item_pack(3)
 ASN1_item_print(3)
 ASN1_item_unpack(3)
diff --git a/util/other.syms b/util/other.syms
index 05c70df44f..8e1824c220 100644
--- a/util/other.syms
+++ b/util/other.syms
@@ -11,7 +11,20 @@ OPENSSL_instrument_bus2                 assembler
 #
 ADMISSION_SYNTAX                        datatype
 ADMISSIONS                              datatype
+ASN1_AUX                                datatype
+ASN1_aux_cb                             datatype
+ASN1_aux_const_cb                       datatype
+ASN1_ex_d2i                             datatype
+ASN1_ex_d2i_ex                          datatype
+ASN1_ex_free_func                       datatype
+ASN1_ex_i2d                             datatype
+ASN1_ex_new_func                        datatype
+ASN1_ex_new_ex_func                     datatype
+ASN1_ex_print_func                      datatype
+ASN1_EXTERN_FUNCS                       datatype
 ASN1_ITEM                               datatype
+ASN1_PRINT_ARG                          datatype
+ASN1_STREAM_ARG                         datatype
 ASN1_STRING_TABLE                       datatype
 ASYNC_callback_fn                       datatype
 BIO_ADDR                                datatype


More information about the openssl-commits mailing list