[openssl] master update

dev at ddvo.net dev at ddvo.net
Tue Mar 10 15:13:59 UTC 2020


The branch master has been updated
       via  44387c9000197b219e7673d5522517a1a6499af8 (commit)
       via  cfca56dfaee0518c2cd99a9c5cda29ad557380e1 (commit)
       via  7269071e5eb54683353a1d2f8831a4ed03485b86 (commit)
       via  62dcd2aa17b27b7892ad62540f9034c9192f6530 (commit)
       via  da42c2a3d752628e15b47aa7511e7044745080cb (commit)
       via  b5adba204244563346d4acefb06723629e6d8f11 (commit)
       via  4c7f8981e8b9919529707be03015601a29ed7a08 (commit)
      from  041a96e7acc89685228980b5615a53bee7f07b0f (commit)


- Log -----------------------------------------------------------------
commit 44387c9000197b219e7673d5522517a1a6499af8
Author: Dr. David von Oheimb <David.von.Oheimb at siemens.com>
Date:   Thu Mar 5 09:16:29 2020 +0100

    Move OSSL_CMP_X509_digest() to x_all.c, renaming it to X509_digest_sig()
    
    Reviewed-by: Matt Caswell <matt at openssl.org>
    Reviewed-by: David von Oheimb <david.von.oheimb at siemens.com>
    (Merged from https://github.com/openssl/openssl/pull/11142)

commit cfca56dfaee0518c2cd99a9c5cda29ad557380e1
Author: Dr. David von Oheimb <David.von.Oheimb at siemens.com>
Date:   Wed Feb 26 21:41:47 2020 +0100

    Fix handling of CMP msg senderKID and improve doc of related CTX functions
    
    Reviewed-by: Matt Caswell <matt at openssl.org>
    Reviewed-by: David von Oheimb <david.von.oheimb at siemens.com>
    (Merged from https://github.com/openssl/openssl/pull/11142)

commit 7269071e5eb54683353a1d2f8831a4ed03485b86
Author: Dr. David von Oheimb <David.von.Oheimb at siemens.com>
Date:   Tue Feb 25 08:58:39 2020 +0100

    Fix error in case CMP msg POPO is not provided in OSSL_CRMF_MSGS_verify_popo()
    
    Reviewed-by: Matt Caswell <matt at openssl.org>
    Reviewed-by: David von Oheimb <david.von.oheimb at siemens.com>
    (Merged from https://github.com/openssl/openssl/pull/11142)

commit 62dcd2aa17b27b7892ad62540f9034c9192f6530
Author: Dr. David von Oheimb <David.von.Oheimb at siemens.com>
Date:   Tue Mar 10 10:29:46 2020 +0100

    Chunk 8 of CMP contribution to OpenSSL: CMP server and cmp_mock_srv.c for testing
    
    Certificate Management Protocol (CMP, RFC 4210) extension to OpenSSL
    Also includes CRMF (RFC 4211) and HTTP transfer (RFC 6712).
    Adds the CMP and CRMF API to libcrypto and the "cmp" app to the CLI.
    Adds extensive documentation and tests.
    
    Reviewed-by: Matt Caswell <matt at openssl.org>
    Reviewed-by: David von Oheimb <david.von.oheimb at siemens.com>
    (Merged from https://github.com/openssl/openssl/pull/11142)

commit da42c2a3d752628e15b47aa7511e7044745080cb
Author: Dr. David von Oheimb <David.von.Oheimb at siemens.com>
Date:   Thu Mar 5 08:43:06 2020 +0100

    Extract sk_ASN1_UTF8STRING2text() from ts_get_status_text() in ts_rsp_verify.c to asn1_lib.c
    
    Reviewed-by: Matt Caswell <matt at openssl.org>
    Reviewed-by: David von Oheimb <david.von.oheimb at siemens.com>
    (Merged from https://github.com/openssl/openssl/pull/11142)

commit b5adba204244563346d4acefb06723629e6d8f11
Author: Dr. David von Oheimb <David.von.Oheimb at siemens.com>
Date:   Tue Mar 10 10:40:43 2020 +0100

    fix coding style nits w.r.t. 'defined' in http_local.h, http.h, and ocsp.h
    
    Reviewed-by: Matt Caswell <matt at openssl.org>
    Reviewed-by: David von Oheimb <david.von.oheimb at siemens.com>
    (Merged from https://github.com/openssl/openssl/pull/11142)

commit 4c7f8981e8b9919529707be03015601a29ed7a08
Author: Dr. David von Oheimb <David.von.Oheimb at siemens.com>
Date:   Tue Mar 10 10:39:22 2020 +0100

    fix two mistakes w.r.t. ERR_LIB_* parameters in ERR_add_error_txt()
    
    Reviewed-by: Matt Caswell <matt at openssl.org>
    Reviewed-by: David von Oheimb <david.von.oheimb at siemens.com>
    (Merged from https://github.com/openssl/openssl/pull/11142)

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

Summary of changes:
 apps/build.info                                    |   3 +
 apps/cmp_mock_srv.c                                | 406 ++++++++++++++
 apps/cmp_mock_srv.h                                |  34 ++
 crypto/asn1/asn1_lib.c                             |  97 +++-
 crypto/cmp/build.info                              |   3 +-
 crypto/cmp/cmp_err.c                               |  13 +-
 crypto/cmp/cmp_hdr.c                               |  64 +--
 crypto/cmp/cmp_local.h                             |  65 +--
 crypto/cmp/cmp_msg.c                               | 131 +++--
 crypto/cmp/cmp_protect.c                           |  15 +-
 crypto/cmp/cmp_server.c                            | 615 +++++++++++++++++++++
 crypto/cmp/cmp_status.c                            |  98 ++--
 crypto/cmp/cmp_util.c                              |  20 +
 crypto/crmf/crmf_err.c                             |  13 +-
 crypto/crmf/crmf_lib.c                             |  80 +--
 crypto/err/err_prn.c                               |   4 +-
 crypto/err/openssl.txt                             |  12 +-
 crypto/http/http_local.h                           |   2 +-
 crypto/ts/ts_rsp_verify.c                          |  29 +-
 crypto/x509/x_all.c                                |  29 +
 doc/internal/man3/ossl_cmp_hdr_init.pod            |  13 +-
 doc/internal/man3/ossl_cmp_mock_srv_new.pod        |  85 +++
 ...sinfo_new.pod => ossl_cmp_pkisi_get_status.pod} |  53 +-
 doc/man3/OSSL_CMP_CTX_new.pod                      |  85 +--
 doc/man3/OSSL_CMP_CTX_snprint_PKIStatus.pod        |  46 --
 doc/man3/OSSL_CMP_MSG_get0_header.pod              |  17 +-
 doc/man3/OSSL_CMP_SRV_CTX_new.pod                  | 159 ++++++
 doc/man3/OSSL_CMP_STATUSINFO_new.pod               |  66 +++
 doc/man3/X509_digest.pod                           |  17 +-
 doc/man3/X509_dup.pod                              |   4 +
 doc/man3/d2i_X509.pod                              |   2 +
 include/internal/cryptlib.h                        |   3 +
 include/openssl/cmp.h                              |  71 ++-
 include/openssl/cmp_util.h                         |   4 +-
 include/openssl/cmperr.h                           |  14 +-
 include/openssl/crmf.h                             |  17 +-
 include/openssl/crmferr.h                          |  14 +-
 include/openssl/http.h                             |   2 +-
 include/openssl/ocsp.h                             |   2 +-
 include/openssl/x509.h                             |   1 +
 test/build.info                                    |   9 +-
 test/cmp_ctx_test.c                                |   1 +
 test/cmp_hdr_test.c                                |  17 +-
 test/cmp_msg_test.c                                |  10 +-
 test/cmp_protect_test.c                            |  35 +-
 test/cmp_server_test.c                             | 160 ++++++
 test/cmp_status_test.c                             |  16 +-
 test/cmp_vfy_test.c                                |  10 +-
 test/recipes/65-test_cmp_server.t                  |  26 +
 .../CR_protected_PBM_1234.der                      | Bin 0 -> 420 bytes
 util/libcrypto.num                                 |  24 +
 util/other.syms                                    |   6 +
 52 files changed, 2257 insertions(+), 465 deletions(-)
 create mode 100644 apps/cmp_mock_srv.c
 create mode 100644 apps/cmp_mock_srv.h
 create mode 100644 crypto/cmp/cmp_server.c
 create mode 100644 doc/internal/man3/ossl_cmp_mock_srv_new.pod
 rename doc/internal/man3/{ossl_cmp_statusinfo_new.pod => ossl_cmp_pkisi_get_status.pod} (58%)
 delete mode 100644 doc/man3/OSSL_CMP_CTX_snprint_PKIStatus.pod
 create mode 100644 doc/man3/OSSL_CMP_SRV_CTX_new.pod
 create mode 100644 doc/man3/OSSL_CMP_STATUSINFO_new.pod
 create mode 100644 test/cmp_server_test.c
 create mode 100644 test/recipes/65-test_cmp_server.t
 create mode 100644 test/recipes/65-test_cmp_server_data/CR_protected_PBM_1234.der

diff --git a/apps/build.info b/apps/build.info
index 495e56065e..2186de3a27 100644
--- a/apps/build.info
+++ b/apps/build.info
@@ -23,6 +23,9 @@ IF[{- !$disabled{'deprecated-3.0'} -}]
   $OPENSSLSRC=$OPENSSLSRC \
         dhparam.c dsa.c dsaparam.c gendsa.c rsa.c rsautl.c genrsa.c
 ENDIF
+IF[{- !$disabled{'cmp'} -}]
+  $OPENSSLSRC=$OPENSSLSRC cmp_mock_srv.c
+ENDIF
 
 IF[{- !$disabled{apps} -}]
   PROGRAMS=openssl
diff --git a/apps/cmp_mock_srv.c b/apps/cmp_mock_srv.c
new file mode 100644
index 0000000000..2e02104884
--- /dev/null
+++ b/apps/cmp_mock_srv.c
@@ -0,0 +1,406 @@
+/*
+ * Copyright 2018-2020 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright Siemens AG 2018-2020
+ *
+ * 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 atf
+ * https://www.openssl.org/source/license.html
+ */
+
+#include "apps.h"
+#include "cmp_mock_srv.h"
+
+#include <openssl/cmp.h>
+#include <openssl/err.h>
+#include <openssl/cmperr.h>
+
+/* the context for the CMP mock server */
+typedef struct
+{
+    X509 *certOut;             /* certificate to be returned in cp/ip/kup msg */
+    STACK_OF(X509) *chainOut;  /* chain of certOut to add to extraCerts field */
+    STACK_OF(X509) *caPubsOut; /* certs to return in caPubs field of ip msg */
+    OSSL_CMP_PKISI *statusOut; /* status for ip/cp/kup/rp msg unless polling */
+    int sendError;             /* send error response also on valid requests */
+    OSSL_CMP_MSG *certReq;     /* ir/cr/p10cr/kur remembered while polling */
+    int certReqId;             /* id of last ir/cr/kur, used for polling */
+    int pollCount;             /* number of polls before actual cert response */
+    int checkAfterTime;        /* time the client should wait between polling */
+} mock_srv_ctx;
+
+
+static void mock_srv_ctx_free(mock_srv_ctx *ctx)
+{
+    if (ctx == NULL)
+        return;
+
+    OSSL_CMP_PKISI_free(ctx->statusOut);
+    X509_free(ctx->certOut);
+    sk_X509_pop_free(ctx->chainOut, X509_free);
+    sk_X509_pop_free(ctx->caPubsOut, X509_free);
+    OSSL_CMP_MSG_free(ctx->certReq);
+    OPENSSL_free(ctx);
+}
+
+static mock_srv_ctx *mock_srv_ctx_new(void)
+{
+    mock_srv_ctx *ctx = OPENSSL_zalloc(sizeof(mock_srv_ctx));
+
+    if (ctx == NULL)
+        goto err;
+
+    if ((ctx->statusOut = OSSL_CMP_PKISI_new()) == NULL)
+        goto err;
+
+    ctx->certReqId = -1;
+
+    /* all other elements are initialized to 0 or NULL, respectively */
+    return ctx;
+ err:
+    mock_srv_ctx_free(ctx);
+    return NULL;
+}
+
+int ossl_cmp_mock_srv_set1_certOut(OSSL_CMP_SRV_CTX *srv_ctx, X509 *cert)
+{
+    mock_srv_ctx *ctx = OSSL_CMP_SRV_CTX_get0_custom_ctx(srv_ctx);
+
+    if (ctx == NULL) {
+        CMPerr(0, CMP_R_NULL_ARGUMENT);
+        return 0;
+    }
+    if (cert == NULL || X509_up_ref(cert)) {
+        X509_free(ctx->certOut);
+        ctx->certOut = cert;
+        return 1;
+    }
+    return 0;
+}
+
+int ossl_cmp_mock_srv_set1_chainOut(OSSL_CMP_SRV_CTX *srv_ctx,
+                                    STACK_OF(X509) *chain)
+{
+    mock_srv_ctx *ctx = OSSL_CMP_SRV_CTX_get0_custom_ctx(srv_ctx);
+    STACK_OF(X509) *chain_copy = NULL;
+
+    if (ctx == NULL) {
+        CMPerr(0, CMP_R_NULL_ARGUMENT);
+        return 0;
+    }
+    if (chain != NULL && (chain_copy = X509_chain_up_ref(chain)) == NULL)
+        return 0;
+    sk_X509_pop_free(ctx->chainOut, X509_free);
+    ctx->chainOut = chain_copy;
+    return 1;
+}
+
+int ossl_cmp_mock_srv_set1_caPubsOut(OSSL_CMP_SRV_CTX *srv_ctx,
+                                     STACK_OF(X509) *caPubs)
+{
+    mock_srv_ctx *ctx = OSSL_CMP_SRV_CTX_get0_custom_ctx(srv_ctx);
+    STACK_OF(X509) *caPubs_copy = NULL;
+
+    if (ctx == NULL) {
+        CMPerr(0, CMP_R_NULL_ARGUMENT);
+        return 0;
+    }
+    if (caPubs != NULL && (caPubs_copy = X509_chain_up_ref(caPubs)) == NULL)
+        return 0;
+    sk_X509_pop_free(ctx->caPubsOut, X509_free);
+    ctx->caPubsOut = caPubs_copy;
+    return 1;
+}
+
+int ossl_cmp_mock_srv_set_statusInfo(OSSL_CMP_SRV_CTX *srv_ctx, int status,
+                                     int fail_info, const char *text)
+{
+    mock_srv_ctx *ctx = OSSL_CMP_SRV_CTX_get0_custom_ctx(srv_ctx);
+    OSSL_CMP_PKISI *si;
+
+    if (ctx == NULL) {
+        CMPerr(0, CMP_R_NULL_ARGUMENT);
+        return 0;
+    }
+    if ((si = OSSL_CMP_STATUSINFO_new(status, fail_info, text)) == NULL)
+        return 0;
+    OSSL_CMP_PKISI_free(ctx->statusOut);
+    ctx->statusOut = si;
+    return 1;
+}
+
+int ossl_cmp_mock_srv_set_send_error(OSSL_CMP_SRV_CTX *srv_ctx, int val)
+{
+    mock_srv_ctx *ctx = OSSL_CMP_SRV_CTX_get0_custom_ctx(srv_ctx);
+
+    if (ctx == NULL) {
+        CMPerr(0, CMP_R_NULL_ARGUMENT);
+        return 0;
+    }
+    ctx->sendError = val != 0;
+    return 1;
+}
+
+int ossl_cmp_mock_srv_set_pollCount(OSSL_CMP_SRV_CTX *srv_ctx, int count)
+{
+    mock_srv_ctx *ctx = OSSL_CMP_SRV_CTX_get0_custom_ctx(srv_ctx);
+
+    if (ctx == NULL) {
+        CMPerr(0, CMP_R_NULL_ARGUMENT);
+        return 0;
+    }
+    if (count < 0) {
+        CMPerr(0, CMP_R_INVALID_ARGS);
+        return 0;
+    }
+    ctx->pollCount = count;
+    return 1;
+}
+
+int ossl_cmp_mock_srv_set_checkAfterTime(OSSL_CMP_SRV_CTX *srv_ctx, int sec)
+{
+    mock_srv_ctx *ctx = OSSL_CMP_SRV_CTX_get0_custom_ctx(srv_ctx);
+
+    if (ctx == NULL) {
+        CMPerr(0, CMP_R_NULL_ARGUMENT);
+        return 0;
+    }
+    ctx->checkAfterTime = sec;
+    return 1;
+}
+
+static OSSL_CMP_PKISI *process_cert_request(OSSL_CMP_SRV_CTX *srv_ctx,
+                                            const OSSL_CMP_MSG *cert_req,
+                                            int certReqId,
+                                            const OSSL_CRMF_MSG *crm,
+                                            const X509_REQ *p10cr,
+                                            X509 **certOut,
+                                            STACK_OF(X509) **chainOut,
+                                            STACK_OF(X509) **caPubs)
+{
+    mock_srv_ctx *ctx = OSSL_CMP_SRV_CTX_get0_custom_ctx(srv_ctx);
+    OSSL_CMP_PKISI *si = NULL;
+
+    if (ctx == NULL || cert_req == NULL
+            || certOut == NULL || chainOut == NULL || caPubs == NULL) {
+        CMPerr(0, CMP_R_NULL_ARGUMENT);
+        return NULL;
+    }
+    if (ctx->sendError) {
+        CMPerr(0, CMP_R_ERROR_PROCESSING_MSG);
+        return NULL;
+    }
+
+    *certOut = NULL;
+    *chainOut = NULL;
+    *caPubs = NULL;
+    ctx->certReqId = certReqId;
+    if (ctx->pollCount > 0) {
+        ctx->pollCount--;
+        OSSL_CMP_MSG_free(ctx->certReq);
+        if ((ctx->certReq = OSSL_CMP_MSG_dup(cert_req)) == NULL)
+            return NULL;
+        return OSSL_CMP_STATUSINFO_new(OSSL_CMP_PKISTATUS_waiting, 0, NULL);
+    }
+    if (ctx->certOut != NULL
+            && (*certOut = X509_dup(ctx->certOut)) == NULL)
+        goto err;
+    if (ctx->chainOut != NULL
+            && (*chainOut = X509_chain_up_ref(ctx->chainOut)) == NULL)
+        goto err;
+    if (ctx->caPubsOut != NULL
+            && (*caPubs = X509_chain_up_ref(ctx->caPubsOut)) == NULL)
+        goto err;
+    if (ctx->statusOut != NULL
+            && (si = OSSL_CMP_PKISI_dup(ctx->statusOut)) == NULL)
+        goto err;
+    return si;
+
+ err:
+    X509_free(*certOut);
+    *certOut = NULL;
+    sk_X509_pop_free(*chainOut, X509_free);
+    *chainOut = NULL;
+    sk_X509_pop_free(*caPubs, X509_free);
+    *caPubs = NULL;
+    return NULL;
+}
+
+static OSSL_CMP_PKISI *process_rr(OSSL_CMP_SRV_CTX *srv_ctx,
+                                  const OSSL_CMP_MSG *rr,
+                                  const X509_NAME *issuer,
+                                  const ASN1_INTEGER *serial)
+{
+    mock_srv_ctx *ctx = OSSL_CMP_SRV_CTX_get0_custom_ctx(srv_ctx);
+
+    if (ctx == NULL || rr == NULL || issuer == NULL || serial == NULL) {
+        CMPerr(0, CMP_R_NULL_ARGUMENT);
+        return NULL;
+    }
+    if (ctx->sendError || ctx->certOut == NULL) {
+        CMPerr(0, CMP_R_ERROR_PROCESSING_MSG);
+        return NULL;
+    }
+
+    /* accept revocation only for the certificate we sent in ir/cr/kur */
+    if (X509_NAME_cmp(issuer, X509_get_issuer_name(ctx->certOut)) != 0
+            || ASN1_INTEGER_cmp(serial,
+                                X509_get0_serialNumber(ctx->certOut)) != 0) {
+        CMPerr(0, CMP_R_REQUEST_NOT_ACCEPTED);
+        return NULL;
+    }
+    return OSSL_CMP_PKISI_dup(ctx->statusOut);
+}
+
+static int process_genm(OSSL_CMP_SRV_CTX *srv_ctx,
+                        const OSSL_CMP_MSG *genm,
+                        const STACK_OF(OSSL_CMP_ITAV) *in,
+                        STACK_OF(OSSL_CMP_ITAV) **out)
+{
+    mock_srv_ctx *ctx = OSSL_CMP_SRV_CTX_get0_custom_ctx(srv_ctx);
+
+    if (ctx == NULL || genm == NULL || in == NULL || out == NULL) {
+        CMPerr(0, CMP_R_NULL_ARGUMENT);
+        return 0;
+    }
+    if (ctx->sendError) {
+        CMPerr(0, CMP_R_ERROR_PROCESSING_MSG);
+        return 0;
+    }
+
+    *out = sk_OSSL_CMP_ITAV_deep_copy(in, OSSL_CMP_ITAV_dup,
+                                      OSSL_CMP_ITAV_free);
+    return *out != NULL;
+}
+
+static void process_error(OSSL_CMP_SRV_CTX *srv_ctx, const OSSL_CMP_MSG *error,
+                          const OSSL_CMP_PKISI *statusInfo,
+                          const ASN1_INTEGER *errorCode,
+                          const OSSL_CMP_PKIFREETEXT *errorDetails)
+{
+    mock_srv_ctx *ctx = OSSL_CMP_SRV_CTX_get0_custom_ctx(srv_ctx);
+    char buf[OSSL_CMP_PKISI_BUFLEN];
+    char *sibuf;
+    int i;
+
+    if (ctx == NULL || error == NULL) {
+        CMPerr(0, CMP_R_NULL_ARGUMENT);
+        return;
+    }
+
+    BIO_printf(bio_err, "mock server received error:\n");
+
+    if (statusInfo == NULL) {
+        BIO_printf(bio_err, "pkiStatusInfo absent\n");
+    } else {
+        sibuf = OSSL_CMP_snprint_PKIStatusInfo(statusInfo, buf, sizeof(buf));
+        BIO_printf(bio_err, "pkiStatusInfo: %s\n",
+                   sibuf != NULL ? sibuf: "<invalid>");
+    }
+
+    if (errorCode == NULL)
+        BIO_printf(bio_err, "errorCode absent\n");
+    else
+        BIO_printf(bio_err, "errorCode: %ld\n", ASN1_INTEGER_get(errorCode));
+
+    if (sk_ASN1_UTF8STRING_num(errorDetails) <= 0) {
+        BIO_printf(bio_err, "errorDetails absent\n");
+    } else {
+        BIO_printf(bio_err, "errorDetails: ");
+        for (i = 0; i < sk_ASN1_UTF8STRING_num(errorDetails); i++) {
+            if (i > 0)
+                BIO_printf(bio_err, ", ");
+            BIO_printf(bio_err, "\"");
+            ASN1_STRING_print(bio_err,
+                              sk_ASN1_UTF8STRING_value(errorDetails, i));
+            BIO_printf(bio_err, "\"");
+        }
+        BIO_printf(bio_err, "\n");
+    }
+}
+
+static int process_certConf(OSSL_CMP_SRV_CTX *srv_ctx,
+                            const OSSL_CMP_MSG *certConf, int certReqId,
+                            const ASN1_OCTET_STRING *certHash,
+                            const OSSL_CMP_PKISI *si)
+{
+    mock_srv_ctx *ctx = OSSL_CMP_SRV_CTX_get0_custom_ctx(srv_ctx);
+    ASN1_OCTET_STRING *digest;
+
+    if (ctx == NULL || certConf == NULL || certHash == NULL) {
+        CMPerr(0, CMP_R_NULL_ARGUMENT);
+        return 0;
+    }
+    if (ctx->sendError || ctx->certOut == NULL) {
+        CMPerr(0, CMP_R_ERROR_PROCESSING_MSG);
+        return 0;
+    }
+
+    if (certReqId != ctx->certReqId) {
+        /* in case of error, invalid reqId -1 */
+        CMPerr(0, CMP_R_BAD_REQUEST_ID);
+        return 0;
+    }
+
+    if ((digest = X509_digest_sig(ctx->certOut)) == NULL)
+        return 0;
+    if (ASN1_OCTET_STRING_cmp(certHash, digest) != 0) {
+        ASN1_OCTET_STRING_free(digest);
+        CMPerr(0, CMP_R_CERTHASH_UNMATCHED);
+        return 0;
+    }
+    ASN1_OCTET_STRING_free(digest);
+    return 1;
+}
+
+static int process_pollReq(OSSL_CMP_SRV_CTX *srv_ctx,
+                           const OSSL_CMP_MSG *pollReq, int certReqId,
+                           OSSL_CMP_MSG **certReq, int64_t *check_after)
+{
+    mock_srv_ctx *ctx = OSSL_CMP_SRV_CTX_get0_custom_ctx(srv_ctx);
+
+    if (ctx == NULL || pollReq == NULL
+            || certReq == NULL || check_after == NULL) {
+        CMPerr(0, CMP_R_NULL_ARGUMENT);
+        return 0;
+    }
+    if (ctx->sendError || ctx->certReq == NULL) {
+        *certReq = NULL;
+        CMPerr(0, CMP_R_ERROR_PROCESSING_MSG);
+        return 0;
+    }
+
+    if (ctx->pollCount == 0) {
+        *certReq = ctx->certReq;
+        ctx->certReq = NULL;
+        *check_after = 0;
+    } else {
+        ctx->pollCount--;
+        *certReq = NULL;
+        *check_after = ctx->checkAfterTime;
+    }
+    return 1;
+}
+
+OSSL_CMP_SRV_CTX *ossl_cmp_mock_srv_new(void)
+{
+    OSSL_CMP_SRV_CTX *srv_ctx = OSSL_CMP_SRV_CTX_new();
+    mock_srv_ctx *ctx = mock_srv_ctx_new();
+
+    if (srv_ctx != NULL && ctx != NULL
+            && OSSL_CMP_SRV_CTX_init(srv_ctx, ctx, process_cert_request,
+                                     process_rr, process_genm, process_error,
+                                     process_certConf, process_pollReq))
+        return srv_ctx;
+
+    mock_srv_ctx_free(ctx);
+    OSSL_CMP_SRV_CTX_free(srv_ctx);
+    return NULL;
+}
+
+void ossl_cmp_mock_srv_free(OSSL_CMP_SRV_CTX *srv_ctx)
+{
+    if (srv_ctx != NULL)
+        mock_srv_ctx_free(OSSL_CMP_SRV_CTX_get0_custom_ctx(srv_ctx));
+    OSSL_CMP_SRV_CTX_free(srv_ctx);
+}
diff --git a/apps/cmp_mock_srv.h b/apps/cmp_mock_srv.h
new file mode 100644
index 0000000000..bddc44df5b
--- /dev/null
+++ b/apps/cmp_mock_srv.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2018-2020 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright Siemens AG 2018-2020
+ *
+ * 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
+ * https://www.openssl.org/source/license.html
+ */
+
+#ifndef OSSL_APPS_CMP_MOCK_SRV_H
+# define OSSL_APPS_CMP_MOCK_SRV_H
+
+# include <openssl/opensslconf.h>
+# ifndef OPENSSL_NO_CMP
+
+#  include <openssl/cmp.h>
+
+OSSL_CMP_SRV_CTX *ossl_cmp_mock_srv_new(void);
+void ossl_cmp_mock_srv_free(OSSL_CMP_SRV_CTX *srv_ctx);
+
+int ossl_cmp_mock_srv_set1_certOut(OSSL_CMP_SRV_CTX *srv_ctx, X509 *cert);
+int ossl_cmp_mock_srv_set1_chainOut(OSSL_CMP_SRV_CTX *srv_ctx,
+                                    STACK_OF(X509) *chain);
+int ossl_cmp_mock_srv_set1_caPubsOut(OSSL_CMP_SRV_CTX *srv_ctx,
+                                     STACK_OF(X509) *caPubs);
+int ossl_cmp_mock_srv_set_statusInfo(OSSL_CMP_SRV_CTX *srv_ctx, int status,
+                                     int fail_info, const char *text);
+int ossl_cmp_mock_srv_set_send_error(OSSL_CMP_SRV_CTX *srv_ctx, int val);
+int ossl_cmp_mock_srv_set_pollCount(OSSL_CMP_SRV_CTX *srv_ctx, int count);
+int ossl_cmp_mock_srv_set_checkAfterTime(OSSL_CMP_SRV_CTX *srv_ctx, int sec);
+
+# endif /* !defined(OPENSSL_NO_CMP) */
+#endif /* !defined(OSSL_APPS_CMP_MOCK_SRV_H) */
diff --git a/crypto/asn1/asn1_lib.c b/crypto/asn1/asn1_lib.c
index 52eb16ba9c..765bbda5c7 100644
--- a/crypto/asn1/asn1_lib.c
+++ b/crypto/asn1/asn1_lib.c
@@ -22,11 +22,13 @@ static int _asn1_check_infinite_end(const unsigned char **p, long len)
     /*
      * If there is 0 or 1 byte left, the length check should pick things up
      */
-    if (len <= 0)
-        return 1;
-    else if ((len >= 2) && ((*p)[0] == 0) && ((*p)[1] == 0)) {
-        (*p) += 2;
+    if (len <= 0) {
         return 1;
+    } else {
+        if ((len >= 2) && ((*p)[0] == 0) && ((*p)[1] == 0)) {
+            (*p) += 2;
+            return 1;
+        }
     }
     return 0;
 }
@@ -45,7 +47,7 @@ int ASN1_get_object(const unsigned char **pp, long *plength, int *ptag,
                     int *pclass, long omax)
 {
     int i, ret;
-    long l;
+    long len;
     const unsigned char *p = *pp;
     int tag, xclass, inf;
     long max = omax;
@@ -59,18 +61,18 @@ int ASN1_get_object(const unsigned char **pp, long *plength, int *ptag,
         p++;
         if (--max == 0)
             goto err;
-        l = 0;
+        len = 0;
         while (*p & 0x80) {
-            l <<= 7L;
-            l |= *(p++) & 0x7f;
+            len <<= 7L;
+            len |= *(p++) & 0x7f;
             if (--max == 0)
                 goto err;
-            if (l > (INT_MAX >> 7L))
+            if (len > (INT_MAX >> 7L))
                 goto err;
         }
-        l <<= 7L;
-        l |= *(p++) & 0x7f;
-        tag = (int)l;
+        len <<= 7L;
+        len |= *(p++) & 0x7f;
+        tag = (int)len;
         if (--max == 0)
             goto err;
     } else {
@@ -141,8 +143,9 @@ static int asn1_get_length(const unsigned char **pp, int *inf, long *rl,
             }
             if (ret > LONG_MAX)
                 return 0;
-        } else
+        } else {
             ret = i;
+        }
     }
     *pp = p;
     *rl = (long)ret;
@@ -160,9 +163,9 @@ void ASN1_put_object(unsigned char **pp, int constructed, int length, int tag,
 
     i = (constructed) ? V_ASN1_CONSTRUCTED : 0;
     i |= (xclass & V_ASN1_PRIVATE);
-    if (tag < 31)
+    if (tag < 31) {
         *(p++) = i | (tag & V_ASN1_PRIMITIVE_TAG);
-    else {
+    } else {
         *(p++) = i | V_ASN1_PRIMITIVE_TAG;
         for (i = 0, ttag = tag; ttag > 0; i++)
             ttag >>= 7;
@@ -185,6 +188,7 @@ void ASN1_put_object(unsigned char **pp, int constructed, int length, int tag,
 int ASN1_put_eoc(unsigned char **pp)
 {
     unsigned char *p = *pp;
+
     *p++ = 0;
     *p++ = 0;
     *pp = p;
@@ -194,20 +198,21 @@ int ASN1_put_eoc(unsigned char **pp)
 static void asn1_put_length(unsigned char **pp, int length)
 {
     unsigned char *p = *pp;
-    int i, l;
-    if (length <= 127)
+    int i, len;
+
+    if (length <= 127) {
         *(p++) = (unsigned char)length;
-    else {
-        l = length;
-        for (i = 0; l > 0; i++)
-            l >>= 8;
+    } else {
+        len = length;
+        for (i = 0; len > 0; i++)
+            len >>= 8;
         *(p++) = i | 0x80;
-        l = i;
+        len = i;
         while (i-- > 0) {
             p[i] = length & 0xff;
             length >>= 8;
         }
-        p += l;
+        p += len;
     }
     *pp = p;
 }
@@ -215,6 +220,7 @@ static void asn1_put_length(unsigned char **pp, int length)
 int ASN1_object_size(int constructed, int length, int tag)
 {
     int ret = 1;
+
     if (length < 0)
         return -1;
     if (tag >= 31) {
@@ -256,6 +262,7 @@ int ASN1_STRING_copy(ASN1_STRING *dst, const ASN1_STRING *str)
 ASN1_STRING *ASN1_STRING_dup(const ASN1_STRING *str)
 {
     ASN1_STRING *ret;
+
     if (!str)
         return NULL;
     ret = ASN1_STRING_new();
@@ -359,8 +366,9 @@ int ASN1_STRING_cmp(const ASN1_STRING *a, const ASN1_STRING *b)
             return a->type - b->type;
         else
             return i;
-    } else
+    } else {
         return i;
+    }
 }
 
 int ASN1_STRING_length(const ASN1_STRING *x)
@@ -383,9 +391,48 @@ const unsigned char *ASN1_STRING_get0_data(const ASN1_STRING *x)
     return x->data;
 }
 
-# ifndef OPENSSL_NO_DEPRECATED_1_1_0
+#ifndef OPENSSL_NO_DEPRECATED_1_1_0
 unsigned char *ASN1_STRING_data(ASN1_STRING *x)
 {
     return x->data;
 }
 #endif
+
+char *sk_ASN1_UTF8STRING2text(STACK_OF(ASN1_UTF8STRING) *text, const char *sep,
+                              size_t max_len /* excluding NUL terminator */)
+{
+    int i;
+    ASN1_UTF8STRING *current;
+    size_t length = 0, sep_len;
+    char *result = NULL;
+    char *p;
+
+    if (!ossl_assert(sep != NULL))
+        return NULL;
+    sep_len = strlen(sep);
+
+    for (i = 0; i < sk_ASN1_UTF8STRING_num(text); ++i) {
+        current = sk_ASN1_UTF8STRING_value(text, i);
+        if (i > 0)
+            length += sep_len;
+        length += ASN1_STRING_length(current);
+        if (length > max_len)
+            return NULL;
+    }
+    if ((result = OPENSSL_malloc(length + 1)) == NULL)
+        return NULL;
+
+    for (i = 0, p = result; i < sk_ASN1_UTF8STRING_num(text); ++i) {
+        current = sk_ASN1_UTF8STRING_value(text, i);
+        length = ASN1_STRING_length(current);
+        if (i > 0 && sep_len > 0) {
+            strncpy(p, sep, sep_len);
+            p += sep_len;
+        }
+        strncpy(p, (const char *)ASN1_STRING_get0_data(current), length);
+        p += length;
+    }
+    *p = '\0';
+
+    return result;
+}
diff --git a/crypto/cmp/build.info b/crypto/cmp/build.info
index 41a5899319..1667334e2a 100644
--- a/crypto/cmp/build.info
+++ b/crypto/cmp/build.info
@@ -1,3 +1,4 @@
 LIBS=../../libcrypto
 SOURCE[../../libcrypto]= cmp_asn.c cmp_ctx.c cmp_err.c cmp_util.c \
-        cmp_status.c cmp_hdr.c cmp_protect.c cmp_msg.c cmp_vfy.c
+        cmp_status.c cmp_hdr.c cmp_protect.c cmp_msg.c cmp_vfy.c \
+        cmp_server.c
diff --git a/crypto/cmp/cmp_err.c b/crypto/cmp/cmp_err.c
index f82ef9e325..0d311a8ddf 100644
--- a/crypto/cmp/cmp_err.c
+++ b/crypto/cmp/cmp_err.c
@@ -1,6 +1,6 @@
 /*
  * Generated by util/mkerr.pl DO NOT EDIT
- * Copyright 1995-2019 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 1995-2020 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
@@ -17,9 +17,12 @@ static const ERR_STRING_DATA CMP_str_reasons[] = {
     {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_ALGORITHM_NOT_SUPPORTED),
     "algorithm not supported"},
     {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_BAD_REQUEST_ID), "bad request id"},
+    {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_CERTHASH_UNMATCHED), "certhash unmatched"},
     {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_CERTID_NOT_FOUND), "certid not found"},
     {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_CERTIFICATE_NOT_FOUND),
     "certificate not found"},
+    {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_CERTREQMSG_NOT_FOUND),
+    "certreqmsg not found"},
     {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_CERTRESPONSE_NOT_FOUND),
     "certresponse not found"},
     {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_CERT_AND_KEY_DO_NOT_MATCH),
@@ -48,10 +51,16 @@ static const ERR_STRING_DATA CMP_str_reasons[] = {
     {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_ERROR_CREATING_RR), "error creating rr"},
     {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_ERROR_PARSING_PKISTATUS),
     "error parsing pkistatus"},
+    {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_ERROR_PROCESSING_MSG),
+    "error processing msg"},
     {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_ERROR_PROTECTING_MESSAGE),
     "error protecting message"},
     {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_ERROR_SETTING_CERTHASH),
     "error setting certhash"},
+    {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_ERROR_TRANSFERRING_OUT),
+    "error transferring out"},
+    {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_ERROR_UNEXPECTED_CERTCONF),
+    "error unexpected certconf"},
     {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_ERROR_VALIDATING_PROTECTION),
     "error validating protection"},
     {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_FAILED_EXTRACTING_PUBKEY),
@@ -72,6 +81,8 @@ static const ERR_STRING_DATA CMP_str_reasons[] = {
     "missing sender identification"},
     {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_MISSING_TRUST_STORE),
     "missing trust store"},
+    {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_MULTIPLE_REQUESTS_NOT_SUPPORTED),
+    "multiple requests not supported"},
     {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_MULTIPLE_SAN_SOURCES),
     "multiple san sources"},
     {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_NO_STDIO), "no stdio"},
diff --git a/crypto/cmp/cmp_hdr.c b/crypto/cmp/cmp_hdr.c
index 29f477f1b5..9d6d6ceb2c 100644
--- a/crypto/cmp/cmp_hdr.c
+++ b/crypto/cmp/cmp_hdr.c
@@ -63,31 +63,42 @@ ASN1_OCTET_STRING *OSSL_CMP_HDR_get0_recipNonce(const OSSL_CMP_PKIHEADER *hdr)
     return hdr->recipNonce;
 }
 
+int ossl_cmp_general_name_is_NULL_DN(GENERAL_NAME *name)
+{
+    X509_NAME *null = X509_NAME_new();
+    int res = name == NULL || null == NULL
+        || (name->type == GEN_DIRNAME
+                && X509_NAME_cmp(name->d.directoryName, null) == 0);
+
+    X509_NAME_free(null);
+    return res;
+}
+
 /* assign to *tgt a copy of src (which may be NULL to indicate an empty DN) */
 static int set1_general_name(GENERAL_NAME **tgt, const X509_NAME *src)
 {
-    GENERAL_NAME *gen;
+    GENERAL_NAME *name;
 
     if (!ossl_assert(tgt != NULL))
         return 0;
-    if ((gen = GENERAL_NAME_new()) == NULL)
+    if ((name = GENERAL_NAME_new()) == NULL)
         goto err;
-    gen->type = GEN_DIRNAME;
+    name->type = GEN_DIRNAME;
 
     if (src == NULL) { /* NULL-DN */
-        if ((gen->d.directoryName = X509_NAME_new()) == NULL)
+        if ((name->d.directoryName = X509_NAME_new()) == NULL)
             goto err;
-    } else if (!X509_NAME_set(&gen->d.directoryName, src)) {
+    } else if (!X509_NAME_set(&name->d.directoryName, src)) {
         goto err;
     }
 
     GENERAL_NAME_free(*tgt);
-    *tgt = gen;
+    *tgt = name;
 
     return 1;
 
  err:
-    GENERAL_NAME_free(gen);
+    GENERAL_NAME_free(name);
     return 0;
 }
 
@@ -153,25 +164,6 @@ int ossl_cmp_hdr_set1_senderKID(OSSL_CMP_PKIHEADER *hdr,
 }
 
 /* push the given text string to the given PKIFREETEXT ft */
-int ossl_cmp_pkifreetext_push_str(OSSL_CMP_PKIFREETEXT *ft, const char *text)
-{
-    ASN1_UTF8STRING *utf8string;
-
-    if (!ossl_assert(ft != NULL && text != NULL))
-        return 0;
-    if ((utf8string = ASN1_UTF8STRING_new()) == NULL)
-        return 0;
-    if (!ASN1_STRING_set(utf8string, text, -1))
-        goto err;
-    if (!sk_ASN1_UTF8STRING_push(ft, utf8string))
-        goto err;
-    return 1;
-
- err:
-    ASN1_UTF8STRING_free(utf8string);
-    return 0;
-}
-
 int ossl_cmp_hdr_push0_freeText(OSSL_CMP_PKIHEADER *hdr, ASN1_UTF8STRING *text)
 {
     if (!ossl_assert(hdr != NULL && text != NULL))
@@ -193,7 +185,8 @@ int ossl_cmp_hdr_push1_freeText(OSSL_CMP_PKIHEADER *hdr, ASN1_UTF8STRING *text)
             && (hdr->freeText = sk_ASN1_UTF8STRING_new_null()) == NULL)
         return 0;
 
-    return ossl_cmp_pkifreetext_push_str(hdr->freeText, (char *)text->data);
+    return
+        ossl_cmp_sk_ASN1_UTF8STRING_push_str(hdr->freeText, (char *)text->data);
 }
 
 int ossl_cmp_hdr_generalInfo_push0_item(OSSL_CMP_PKIHEADER *hdr,
@@ -205,7 +198,7 @@ int ossl_cmp_hdr_generalInfo_push0_item(OSSL_CMP_PKIHEADER *hdr,
 }
 
 int ossl_cmp_hdr_generalInfo_push1_items(OSSL_CMP_PKIHEADER *hdr,
-                                         STACK_OF(OSSL_CMP_ITAV) *itavs)
+                                         const STACK_OF(OSSL_CMP_ITAV) *itavs)
 {
     int i;
     OSSL_CMP_ITAV *itav;
@@ -250,7 +243,7 @@ int ossl_cmp_hdr_set_implicitConfirm(OSSL_CMP_PKIHEADER *hdr)
 }
 
 /* return 1 if implicitConfirm in the generalInfo field of the header is set */
-int ossl_cmp_hdr_check_implicitConfirm(const OSSL_CMP_PKIHEADER *hdr)
+int ossl_cmp_hdr_has_implicitConfirm(const OSSL_CMP_PKIHEADER *hdr)
 {
     int itavCount;
     int i;
@@ -283,19 +276,12 @@ int ossl_cmp_hdr_init(OSSL_CMP_CTX *ctx, OSSL_CMP_PKIHEADER *hdr)
     if (!ossl_cmp_hdr_set_pvno(hdr, OSSL_CMP_PVNO))
         return 0;
 
-    sender = ctx->clCert != NULL ?
-        X509_get_subject_name(ctx->clCert) : ctx->subjectName;
     /*
      * The sender name is copied from the subject of the client cert, if any,
-     * or else from the the subject name provided for certification requests.
-     * As required by RFC 4210 section 5.1.1., if the sender name is not known
-     * to the client it set to NULL-DN. In this case for identification at least
-     * the senderKID must be set, which we take from any referenceValue given.
+     * or else from the subject name provided for certification requests.
      */
-    if (sender == NULL && ctx->referenceValue == NULL) {
-        CMPerr(0, CMP_R_MISSING_SENDER_IDENTIFICATION);
-        return 0;
-    }
+    sender = ctx->clCert != NULL ?
+        X509_get_subject_name(ctx->clCert) : ctx->subjectName;
     if (!ossl_cmp_hdr_set1_sender(hdr, sender))
         return 0;
 
diff --git a/crypto/cmp/cmp_local.h b/crypto/cmp/cmp_local.h
index 015a3d4e67..353c7ce995 100644
--- a/crypto/cmp/cmp_local.h
+++ b/crypto/cmp/cmp_local.h
@@ -246,7 +246,6 @@ struct ossl_cmp_itav_st {
     } infoValue;
 } /* OSSL_CMP_ITAV */;
 DECLARE_ASN1_FUNCTIONS(OSSL_CMP_ITAV)
-DECLARE_ASN1_DUP_FUNCTION(OSSL_CMP_ITAV)
 
 typedef struct ossl_cmp_certorenccert_st {
     int type;
@@ -284,8 +283,6 @@ struct ossl_cmp_pkisi_st {
     OSSL_CMP_PKIFREETEXT *statusString;
     OSSL_CMP_PKIFAILUREINFO *failInfo;
 } /* OSSL_CMP_PKISI */;
-DECLARE_ASN1_FUNCTIONS(OSSL_CMP_PKISI)
-DECLARE_ASN1_DUP_FUNCTION(OSSL_CMP_PKISI)
 DECLARE_ASN1_DUP_FUNCTION(OSSL_CRMF_CERTID)
 
 /*-
@@ -296,10 +293,11 @@ DECLARE_ASN1_DUP_FUNCTION(OSSL_CRMF_CERTID)
  *      crlEntryDetails     Extensions       OPTIONAL
  *  }
  */
-typedef struct ossl_cmp_revdetails_st {
+struct ossl_cmp_revdetails_st {
     OSSL_CRMF_CERTTEMPLATE *certDetails;
     X509_EXTENSIONS *crlEntryDetails;
-} OSSL_CMP_REVDETAILS;
+} /* OSSL_CMP_REVDETAILS */;
+typedef struct ossl_cmp_revdetails_st OSSL_CMP_REVDETAILS;
 DECLARE_ASN1_FUNCTIONS(OSSL_CMP_REVDETAILS)
 DEFINE_STACK_OF(OSSL_CMP_REVDETAILS)
 
@@ -375,7 +373,6 @@ struct ossl_cmp_certstatus_st {
     OSSL_CMP_PKISI *statusInfo;
 } /* OSSL_CMP_CERTSTATUS */;
 DECLARE_ASN1_FUNCTIONS(OSSL_CMP_CERTSTATUS)
-
 typedef STACK_OF(OSSL_CMP_CERTSTATUS) OSSL_CMP_CERTCONFIRMCONTENT;
 DECLARE_ASN1_FUNCTIONS(OSSL_CMP_CERTCONFIRMCONTENT)
 
@@ -670,7 +667,6 @@ struct ossl_cmp_msg_st {
     STACK_OF(X509) *extraCerts; /* 1 */
 } /* OSSL_CMP_MSG */;
 DECLARE_ASN1_FUNCTIONS(OSSL_CMP_MSG)
-DECLARE_ASN1_DUP_FUNCTION(OSSL_CMP_MSG)
 
 /*-
  * ProtectedPart ::= SEQUENCE {
@@ -728,17 +724,6 @@ DECLARE_ASN1_FUNCTIONS(CMP_PROTECTEDPART)
  *   }
  */
 
-/*
- * constants
- */
-/* certReqId for the first - and so far only - certificate request */
-# define OSSL_CMP_CERTREQID 0
-/* sequence id for the first - and so far only - revocation request */
-# define OSSL_CMP_REVREQSID 0
-/*
- * functions
- */
-
 /* from cmp_asn.c */
 int ossl_cmp_asn1_get_int(const ASN1_INTEGER *a);
 
@@ -755,6 +740,9 @@ int ossl_cmp_sk_X509_add1_certs(STACK_OF(X509) *sk, STACK_OF(X509) *certs,
                                 int no_self_issued, int no_dups, int prepend);
 int ossl_cmp_X509_STORE_add1_certs(X509_STORE *store, STACK_OF(X509) *certs,
                                    int only_self_issued);
+STACK_OF(X509) *ossl_cmp_X509_STORE_get1_certs(X509_STORE *store);
+int ossl_cmp_sk_ASN1_UTF8STRING_push_str(STACK_OF(ASN1_UTF8STRING) *sk,
+                                         const char *text);
 int ossl_cmp_asn1_octet_string_set1(ASN1_OCTET_STRING **tgt,
                                     const ASN1_OCTET_STRING *src);
 int ossl_cmp_asn1_octet_string_set1_bytes(ASN1_OCTET_STRING **tgt,
@@ -800,32 +788,30 @@ int ossl_cmp_ctx_set1_recipNonce(OSSL_CMP_CTX *ctx,
                                  const ASN1_OCTET_STRING *nonce);
 
 /* from cmp_status.c */
-OSSL_CMP_PKISI *
-ossl_cmp_statusinfo_new(int status, int fail_info, const char *text);
-int ossl_cmp_pkisi_get_pkistatus(const OSSL_CMP_PKISI *statusInfo);
+int ossl_cmp_pkisi_get_status(const OSSL_CMP_PKISI *si);
 const char *ossl_cmp_PKIStatus_to_string(int status);
-OSSL_CMP_PKIFREETEXT *ossl_cmp_pkisi_get0_statusstring(const OSSL_CMP_PKISI *si);
+OSSL_CMP_PKIFREETEXT *ossl_cmp_pkisi_get0_statusString(const OSSL_CMP_PKISI *si);
 int ossl_cmp_pkisi_get_pkifailureinfo(const OSSL_CMP_PKISI *si);
-int ossl_cmp_pkisi_pkifailureinfo_check(const OSSL_CMP_PKISI *si, int bit_index);
+int ossl_cmp_pkisi_check_pkifailureinfo(const OSSL_CMP_PKISI *si, int index);
 
 /* from cmp_hdr.c */
 int ossl_cmp_hdr_set_pvno(OSSL_CMP_PKIHEADER *hdr, int pvno);
 int ossl_cmp_hdr_get_pvno(const OSSL_CMP_PKIHEADER *hdr);
 ASN1_OCTET_STRING *ossl_cmp_hdr_get0_senderNonce(const OSSL_CMP_PKIHEADER *hdr);
+int ossl_cmp_general_name_is_NULL_DN(GENERAL_NAME *name);
 int ossl_cmp_hdr_set1_sender(OSSL_CMP_PKIHEADER *hdr, const X509_NAME *nm);
 int ossl_cmp_hdr_set1_recipient(OSSL_CMP_PKIHEADER *hdr, const X509_NAME *nm);
 int ossl_cmp_hdr_update_messageTime(OSSL_CMP_PKIHEADER *hdr);
 int ossl_cmp_hdr_set1_senderKID(OSSL_CMP_PKIHEADER *hdr,
                                 const ASN1_OCTET_STRING *senderKID);
-int ossl_cmp_pkifreetext_push_str(OSSL_CMP_PKIFREETEXT *ft, const char *text);
 int ossl_cmp_hdr_push0_freeText(OSSL_CMP_PKIHEADER *hdr, ASN1_UTF8STRING *text);
 int ossl_cmp_hdr_push1_freeText(OSSL_CMP_PKIHEADER *hdr, ASN1_UTF8STRING *text);
 int ossl_cmp_hdr_generalInfo_push0_item(OSSL_CMP_PKIHEADER *hdr,
                                         OSSL_CMP_ITAV *itav);
 int ossl_cmp_hdr_generalInfo_push1_items(OSSL_CMP_PKIHEADER *hdr,
-                                         STACK_OF(OSSL_CMP_ITAV) *itavs);
+                                         const STACK_OF(OSSL_CMP_ITAV) *itavs);
 int ossl_cmp_hdr_set_implicitConfirm(OSSL_CMP_PKIHEADER *hdr);
-int ossl_cmp_hdr_check_implicitConfirm(const OSSL_CMP_PKIHEADER *hdr);
+int ossl_cmp_hdr_has_implicitConfirm(const OSSL_CMP_PKIHEADER *hdr);
 # define OSSL_CMP_TRANSACTIONID_LENGTH 16
 # define OSSL_CMP_SENDERNONCE_LENGTH 16
 int ossl_cmp_hdr_init(OSSL_CMP_CTX *ctx, OSSL_CMP_PKIHEADER *hdr);
@@ -860,6 +846,10 @@ int ossl_cmp_hdr_init(OSSL_CMP_CTX *ctx, OSSL_CMP_PKIHEADER *hdr);
 # define OSSL_CMP_PKIBODY_POLLREQ  25
 # define OSSL_CMP_PKIBODY_POLLREP  26
 # define OSSL_CMP_PKIBODY_TYPE_MAX OSSL_CMP_PKIBODY_POLLREP
+/* certReqId for the first - and so far only - certificate request */
+# define OSSL_CMP_CERTREQID 0
+/* sequence id for the first - and so far only - revocation request */
+# define OSSL_CMP_REVREQSID 0
 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);
@@ -875,24 +865,26 @@ OSSL_CMP_MSG *ossl_cmp_rr_new(OSSL_CMP_CTX *ctx);
 OSSL_CMP_MSG *ossl_cmp_rp_new(OSSL_CMP_CTX *ctx, OSSL_CMP_PKISI *si,
                               OSSL_CRMF_CERTID *certId, int unprot_err);
 OSSL_CMP_MSG *ossl_cmp_pkiconf_new(OSSL_CMP_CTX *ctx);
+OSSL_CMP_MSG *ossl_cmp_pollRep_new(OSSL_CMP_CTX *ctx, int crid,
+                                   int64_t poll_after);
 int ossl_cmp_msg_gen_push0_ITAV(OSSL_CMP_MSG *msg, OSSL_CMP_ITAV *itav);
 int ossl_cmp_msg_gen_push1_ITAVs(OSSL_CMP_MSG *msg,
-                                 STACK_OF(OSSL_CMP_ITAV) *itavs);
+                                 const STACK_OF(OSSL_CMP_ITAV) *itavs);
 OSSL_CMP_MSG *ossl_cmp_genm_new(OSSL_CMP_CTX *ctx);
-OSSL_CMP_MSG *ossl_cmp_genp_new(OSSL_CMP_CTX *ctx);
+OSSL_CMP_MSG *ossl_cmp_genp_new(OSSL_CMP_CTX *ctx,
+                                const STACK_OF(OSSL_CMP_ITAV) *itavs);
 OSSL_CMP_MSG *ossl_cmp_error_new(OSSL_CMP_CTX *ctx, OSSL_CMP_PKISI *si,
                                  int errorCode,
-                                 OSSL_CMP_PKIFREETEXT *errorDetails,
-                                 int unprotected);
-int ossl_cmp_certstatus_set_certHash(OSSL_CMP_CERTSTATUS *certStatus,
-                                     const X509 *cert);
+                                 const char *details, int unprotected);
+int ossl_cmp_certstatus_set0_certHash(OSSL_CMP_CERTSTATUS *certStatus,
+                                      ASN1_OCTET_STRING *hash);
 OSSL_CMP_MSG *ossl_cmp_certConf_new(OSSL_CMP_CTX *ctx, int fail_info,
                                     const char *text);
 OSSL_CMP_MSG *ossl_cmp_pollReq_new(OSSL_CMP_CTX *ctx, int crid);
 OSSL_CMP_MSG *ossl_cmp_pollRep_new(OSSL_CMP_CTX *ctx, int crid,
                                    int64_t poll_after);
 OSSL_CMP_PKISI *
-ossl_cmp_revrepcontent_get_pkistatusinfo(OSSL_CMP_REVREPCONTENT *rrep, int rsid);
+ossl_cmp_revrepcontent_get_pkisi(OSSL_CMP_REVREPCONTENT *rrep, int rsid);
 OSSL_CRMF_CERTID *ossl_cmp_revrepcontent_get_CertId(OSSL_CMP_REVREPCONTENT *rrep,
                                                     int rsid);
 OSSL_CMP_POLLREP *
@@ -904,11 +896,6 @@ ossl_cmp_certrepmessage_get0_certresponse(const OSSL_CMP_CERTREPMESSAGE *crepmsg
 X509 *ossl_cmp_certresponse_get1_certificate(EVP_PKEY *privkey,
                                              const OSSL_CMP_CERTRESPONSE *crep);
 OSSL_CMP_MSG *ossl_cmp_msg_load(const char *file);
-/* BIO definitions */
-# define OSSL_d2i_CMP_MSG_bio(bp, p) \
-    ASN1_d2i_bio_of(OSSL_CMP_MSG, OSSL_CMP_MSG_new, d2i_OSSL_CMP_MSG, bp, p)
-# define OSSL_i2d_CMP_MSG_bio(bp, o) \
-    ASN1_i2d_bio_of(OSSL_CMP_MSG, i2d_OSSL_CMP_MSG, bp, o)
 
 /* from cmp_protect.c */
 ASN1_BIT_STRING *ossl_cmp_calc_protection(const OSSL_CMP_MSG *msg,
@@ -925,4 +912,4 @@ int ossl_cmp_msg_check_received(OSSL_CMP_CTX *ctx, const OSSL_CMP_MSG *msg,
                                 ossl_cmp_allow_unprotected_cb_t cb, int cb_arg);
 int ossl_cmp_verify_popo(const OSSL_CMP_MSG *msg, int accept_RAVerified);
 
-#endif /* !defined OSSL_CRYPTO_CMP_LOCAL_H */
+#endif /* !defined(OSSL_CRYPTO_CMP_LOCAL_H) */
diff --git a/crypto/cmp/cmp_msg.c b/crypto/cmp/cmp_msg.c
index c794dc98bb..714c883a0d 100644
--- a/crypto/cmp/cmp_msg.c
+++ b/crypto/cmp/cmp_msg.c
@@ -205,18 +205,20 @@ static X509_NAME *determine_subj(OSSL_CMP_CTX *ctx, X509 *refcert,
  * Create CRMF certificate request message for IR/CR/KUR
  * returns a pointer to the OSSL_CRMF_MSG on success, NULL on error
  */
-static OSSL_CRMF_MSG *crm_new(OSSL_CMP_CTX *ctx, int bodytype,
-                              int rid, EVP_PKEY *rkey)
+static OSSL_CRMF_MSG *crm_new(OSSL_CMP_CTX *ctx, int bodytype, int rid)
 {
     OSSL_CRMF_MSG *crm = NULL;
     X509 *refcert = ctx->oldCert != NULL ? ctx->oldCert : ctx->clCert;
     /* refcert defaults to current client cert */
+    EVP_PKEY *rkey = OSSL_CMP_CTX_get0_newPkey(ctx, 0);
     STACK_OF(GENERAL_NAME) *default_sans = NULL;
     X509_NAME *subject = determine_subj(ctx, refcert, bodytype);
     int crit = ctx->setSubjectAltNameCritical || subject == NULL;
     /* RFC5280: subjectAltName MUST be critical if subject is null */
     X509_EXTENSIONS *exts = NULL;
 
+    if (rkey == NULL)
+        rkey = ctx->pkey; /* default is independent of ctx->oldClCert */
     if (rkey == NULL
             || (bodytype == OSSL_CMP_PKIBODY_KUR && refcert == NULL)) {
         CMPerr(0, CMP_R_INVALID_ARGS);
@@ -300,19 +302,12 @@ static OSSL_CRMF_MSG *crm_new(OSSL_CMP_CTX *ctx, int bodytype,
 
 OSSL_CMP_MSG *ossl_cmp_certReq_new(OSSL_CMP_CTX *ctx, int type, int err_code)
 {
-    EVP_PKEY *rkey;
-    EVP_PKEY *privkey;
     OSSL_CMP_MSG *msg;
     OSSL_CRMF_MSG *crm = NULL;
 
     if (!ossl_assert(ctx != NULL))
         return NULL;
 
-    rkey = OSSL_CMP_CTX_get0_newPkey(ctx, 0);
-    if (rkey == NULL)
-        return NULL;
-    privkey = OSSL_CMP_CTX_get0_newPkey(ctx, 1);
-
     if (type != OSSL_CMP_PKIBODY_IR && type != OSSL_CMP_PKIBODY_CR
             && type != OSSL_CMP_PKIBODY_KUR && type != OSSL_CMP_PKIBODY_P10CR) {
         CMPerr(0, CMP_R_INVALID_ARGS);
@@ -329,15 +324,19 @@ OSSL_CMP_MSG *ossl_cmp_certReq_new(OSSL_CMP_CTX *ctx, int type, int err_code)
     /* body */
     /* For P10CR the content has already been set in OSSL_CMP_MSG_create */
     if (type != OSSL_CMP_PKIBODY_P10CR) {
+        EVP_PKEY *privkey = OSSL_CMP_CTX_get0_newPkey(ctx, 1);
+
+        if (privkey == NULL)
+            privkey = ctx->pkey; /* default is independent of ctx->oldCert */
         if (ctx->popoMethod == OSSL_CRMF_POPO_SIGNATURE && privkey == NULL) {
             CMPerr(0, CMP_R_MISSING_PRIVATE_KEY);
             goto err;
         }
-        if ((crm = crm_new(ctx, type, OSSL_CMP_CERTREQID, rkey)) == NULL
-                || !OSSL_CRMF_MSG_create_popo(crm, privkey, ctx->digest,
-                                              ctx->popoMethod)
-                /* value.ir is same for cr and kur */
-                || !sk_OSSL_CRMF_MSG_push(msg->body->value.ir, crm))
+        if ((crm = crm_new(ctx, type, OSSL_CMP_CERTREQID)) == NULL
+            || !OSSL_CRMF_MSG_create_popo(crm, privkey, ctx->digest,
+                                          ctx->popoMethod)
+            /* value.ir is same for cr and kur */
+            || !sk_OSSL_CRMF_MSG_push(msg->body->value.ir, crm))
             goto err;
         crm = NULL;
         /* TODO: here optional 2nd certreqmsg could be pushed to the stack */
@@ -385,7 +384,7 @@ OSSL_CMP_MSG *ossl_cmp_certRep_new(OSSL_CMP_CTX *ctx, int bodytype,
             || !ASN1_INTEGER_set(resp->certReqId, certReqId))
         goto err;
 
-    status = ossl_cmp_pkisi_get_pkistatus(resp->status);
+    status = ossl_cmp_pkisi_get_status(resp->status);
     if (status != OSSL_CMP_PKISTATUS_rejection
             && status != OSSL_CMP_PKISTATUS_waiting && cert != NULL) {
         if (encrypted) {
@@ -416,7 +415,7 @@ OSSL_CMP_MSG *ossl_cmp_certRep_new(OSSL_CMP_CTX *ctx, int bodytype,
         goto err;
 
     if (!unprotectedErrors
-            || ossl_cmp_pkisi_get_pkistatus(si) != OSSL_CMP_PKISTATUS_rejection)
+            || ossl_cmp_pkisi_get_status(si) != OSSL_CMP_PKISTATUS_rejection)
         if (!ossl_cmp_msg_protect(ctx, msg))
             goto err;
 
@@ -511,7 +510,7 @@ OSSL_CMP_MSG *ossl_cmp_rp_new(OSSL_CMP_CTX *ctx, OSSL_CMP_PKISI *si,
     }
 
     if (!unprot_err
-            || ossl_cmp_pkisi_get_pkistatus(si) != OSSL_CMP_PKISTATUS_rejection)
+            || ossl_cmp_pkisi_get_status(si) != OSSL_CMP_PKISTATUS_rejection)
         if (!ossl_cmp_msg_protect(ctx, msg))
             goto err;
 
@@ -560,7 +559,7 @@ int ossl_cmp_msg_gen_push0_ITAV(OSSL_CMP_MSG *msg, OSSL_CMP_ITAV *itav)
 }
 
 int ossl_cmp_msg_gen_push1_ITAVs(OSSL_CMP_MSG *msg,
-                                 STACK_OF(OSSL_CMP_ITAV) *itavs)
+                                 const STACK_OF(OSSL_CMP_ITAV) *itavs)
 {
     int i;
     OSSL_CMP_ITAV *itav = NULL;
@@ -583,7 +582,9 @@ int ossl_cmp_msg_gen_push1_ITAVs(OSSL_CMP_MSG *msg,
  * Creates a new General Message/Response with an empty itav stack
  * returns a pointer to the PKIMessage on success, NULL on error
  */
-static OSSL_CMP_MSG *gen_new(OSSL_CMP_CTX *ctx, int body_type, int err_code)
+static OSSL_CMP_MSG *gen_new(OSSL_CMP_CTX *ctx,
+                             const STACK_OF(OSSL_CMP_ITAV) *itavs,
+                             int body_type, int err_code)
 {
     OSSL_CMP_MSG *msg = NULL;
 
@@ -594,7 +595,7 @@ static OSSL_CMP_MSG *gen_new(OSSL_CMP_CTX *ctx, int body_type, int err_code)
         return NULL;
 
     if (ctx->genm_ITAVs != NULL
-            && !ossl_cmp_msg_gen_push1_ITAVs(msg, ctx->genm_ITAVs))
+            && !ossl_cmp_msg_gen_push1_ITAVs(msg, itavs))
         goto err;
 
     if (!ossl_cmp_msg_protect(ctx, msg))
@@ -610,20 +611,23 @@ static OSSL_CMP_MSG *gen_new(OSSL_CMP_CTX *ctx, int body_type, int err_code)
 
 OSSL_CMP_MSG *ossl_cmp_genm_new(OSSL_CMP_CTX *ctx)
 {
-    return gen_new(ctx, OSSL_CMP_PKIBODY_GENM, CMP_R_ERROR_CREATING_GENM);
+    return gen_new(ctx, ctx->genm_ITAVs,
+                   OSSL_CMP_PKIBODY_GENM, CMP_R_ERROR_CREATING_GENM);
 }
 
-OSSL_CMP_MSG *ossl_cmp_genp_new(OSSL_CMP_CTX *ctx)
+OSSL_CMP_MSG *ossl_cmp_genp_new(OSSL_CMP_CTX *ctx,
+                                const STACK_OF(OSSL_CMP_ITAV) *itavs)
 {
-    return gen_new(ctx, OSSL_CMP_PKIBODY_GENP, CMP_R_ERROR_CREATING_GENP);
+    return gen_new(ctx, itavs,
+                   OSSL_CMP_PKIBODY_GENP, CMP_R_ERROR_CREATING_GENP);
 }
 
 OSSL_CMP_MSG *ossl_cmp_error_new(OSSL_CMP_CTX *ctx, OSSL_CMP_PKISI *si,
                                  int errorCode,
-                                 OSSL_CMP_PKIFREETEXT *errorDetails,
-                                 int unprotected)
+                                 const char *details, int unprotected)
 {
     OSSL_CMP_MSG *msg = NULL;
+    OSSL_CMP_PKIFREETEXT *ft;
 
     if (!ossl_assert(ctx != NULL && si != NULL))
         return NULL;
@@ -641,11 +645,13 @@ OSSL_CMP_MSG *ossl_cmp_error_new(OSSL_CMP_CTX *ctx, OSSL_CMP_PKISI *si,
         if (!ASN1_INTEGER_set(msg->body->value.error->errorCode, errorCode))
             goto err;
     }
-    if (errorDetails != NULL)
-        if ((msg->body->value.error->errorDetails =
-             sk_ASN1_UTF8STRING_deep_copy(errorDetails, ASN1_STRING_dup,
-                                          ASN1_STRING_free)) == NULL)
+    if (details != NULL) {
+        if ((ft = sk_ASN1_UTF8STRING_new_null()) == NULL)
+            goto err;
+        msg->body->value.error->errorDetails = ft;
+        if (!ossl_cmp_sk_ASN1_UTF8STRING_push_str(ft, details))
             goto err;
+    }
 
     if (!unprotected && !ossl_cmp_msg_protect(ctx, msg))
         goto err;
@@ -658,44 +664,18 @@ OSSL_CMP_MSG *ossl_cmp_error_new(OSSL_CMP_CTX *ctx, OSSL_CMP_PKISI *si,
 }
 
 /*
- * OSSL_CMP_CERTSTATUS_set_certHash() calculates a hash of the certificate,
- * using the same hash algorithm as is used to create and verify the
- * certificate signature, and places the hash into the certHash field of a
- * OSSL_CMP_CERTSTATUS structure. This is used in the certConf message,
- * for example, to confirm that the certificate was received successfully.
+ * Set the certHash field of a OSSL_CMP_CERTSTATUS structure.
+ * This is used in the certConf message, for example,
+ * to confirm that the certificate was received successfully.
  */
-int ossl_cmp_certstatus_set_certHash(OSSL_CMP_CERTSTATUS *certStatus,
-                                     const X509 *cert)
+int ossl_cmp_certstatus_set0_certHash(OSSL_CMP_CERTSTATUS *certStatus,
+                                      ASN1_OCTET_STRING *hash)
 {
-    unsigned int len;
-    unsigned char hash[EVP_MAX_MD_SIZE];
-    int md_NID;
-    const EVP_MD *md = NULL;
-
-    if (!ossl_assert(certStatus != NULL && cert != NULL))
-        return 0;
-
-    /*-
-     * select hash algorithm, as stated in Appendix F. Compilable ASN.1 defs:
-     * the hash of the certificate, using the same hash algorithm
-     * as is used to create and verify the certificate signature
-     */
-    if (OBJ_find_sigid_algs(X509_get_signature_nid(cert), &md_NID, NULL)
-            && (md = EVP_get_digestbynid(md_NID)) != NULL) {
-        if (!X509_digest(cert, md, hash, &len))
-            goto err;
-        if (!ossl_cmp_asn1_octet_string_set1_bytes(&certStatus->certHash, hash,
-                                                   len))
-            goto err;
-    } else {
-        CMPerr(0, CMP_R_UNSUPPORTED_ALGORITHM);
+    if (!ossl_assert(certStatus != NULL))
         return 0;
-    }
-
+    ASN1_OCTET_STRING_free(certStatus->certHash);
+    certStatus->certHash = hash;
     return 1;
- err:
-    CMPerr(0, CMP_R_ERROR_SETTING_CERTHASH);
-    return 0;
 }
 
 /*
@@ -707,6 +687,7 @@ OSSL_CMP_MSG *ossl_cmp_certConf_new(OSSL_CMP_CTX *ctx, int fail_info,
 {
     OSSL_CMP_MSG *msg = NULL;
     OSSL_CMP_CERTSTATUS *certStatus = NULL;
+    ASN1_OCTET_STRING *certHash = NULL;
     OSSL_CMP_PKISI *sinfo;
 
     if (!ossl_assert(ctx != NULL && ctx->newCert != NULL))
@@ -732,8 +713,12 @@ OSSL_CMP_MSG *ossl_cmp_certConf_new(OSSL_CMP_CTX *ctx, int fail_info,
      * the hash of the certificate, using the same hash algorithm
      * as is used to create and verify the certificate signature
      */
-    if (!ossl_cmp_certstatus_set_certHash(certStatus, ctx->newCert))
+    if ((certHash = X509_digest_sig(ctx->newCert)) == NULL)
+        goto err;
+
+    if (!ossl_cmp_certstatus_set0_certHash(certStatus, certHash))
         goto err;
+    certHash = NULL;
     /*
      * For any particular CertStatus, omission of the statusInfo field
      * indicates ACCEPTANCE of the specified certificate.  Alternatively,
@@ -742,8 +727,8 @@ OSSL_CMP_MSG *ossl_cmp_certConf_new(OSSL_CMP_CTX *ctx, int fail_info,
      * the CA/RA.
      */
     sinfo = fail_info != 0 ?
-        ossl_cmp_statusinfo_new(OSSL_CMP_PKISTATUS_rejection, fail_info, text) :
-        ossl_cmp_statusinfo_new(OSSL_CMP_PKISTATUS_accepted, 0, text);
+        OSSL_CMP_STATUSINFO_new(OSSL_CMP_PKISTATUS_rejection, fail_info, text) :
+        OSSL_CMP_STATUSINFO_new(OSSL_CMP_PKISTATUS_accepted, 0, text);
     if (sinfo == NULL)
         goto err;
     certStatus->statusInfo = sinfo;
@@ -756,6 +741,7 @@ OSSL_CMP_MSG *ossl_cmp_certConf_new(OSSL_CMP_CTX *ctx, int fail_info,
  err:
     CMPerr(0, CMP_R_ERROR_CREATING_CERTCONF);
     OSSL_CMP_MSG_free(msg);
+    ASN1_OCTET_STRING_free(certHash);
     return NULL;
 }
 
@@ -827,7 +813,7 @@ OSSL_CMP_MSG *ossl_cmp_pollRep_new(OSSL_CMP_CTX *ctx, int crid,
  * returns NULL on error
  */
 OSSL_CMP_PKISI *
-ossl_cmp_revrepcontent_get_pkistatusinfo(OSSL_CMP_REVREPCONTENT *rrep, int rsid)
+ossl_cmp_revrepcontent_get_pkisi(OSSL_CMP_REVREPCONTENT *rrep, int rsid)
 {
     OSSL_CMP_PKISI *status;
 
@@ -994,3 +980,14 @@ OSSL_CMP_MSG *ossl_cmp_msg_load(const char *file)
     BIO_free(bio);
     return msg;
 }
+
+OSSL_CMP_MSG *OSSL_d2i_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);
+}
+
+int OSSL_i2d_CMP_MSG_bio(BIO *bio, const OSSL_CMP_MSG *msg)
+{
+    return ASN1_i2d_bio_of(OSSL_CMP_MSG, i2d_OSSL_CMP_MSG, bio, msg);
+}
diff --git a/crypto/cmp/cmp_protect.c b/crypto/cmp/cmp_protect.c
index c1b4b8584d..ce20ef203e 100644
--- a/crypto/cmp/cmp_protect.c
+++ b/crypto/cmp/cmp_protect.c
@@ -286,6 +286,8 @@ int ossl_cmp_msg_protect(OSSL_CMP_CTX *ctx, OSSL_CMP_MSG *msg)
              * to section 5.1.1
              */
             subjKeyIDStr = X509_get0_subject_key_id(ctx->clCert);
+            if (subjKeyIDStr == NULL)
+                subjKeyIDStr = ctx->referenceValue; /* fallback */
             if (subjKeyIDStr != NULL
                     && !ossl_cmp_hdr_set1_senderKID(msg->header, subjKeyIDStr))
                 goto err;
@@ -306,7 +308,18 @@ int ossl_cmp_msg_protect(OSSL_CMP_CTX *ctx, OSSL_CMP_MSG *msg)
         }
     }
 
-    return 1;
+    /*
+     * As required by RFC 4210 section 5.1.1., if the sender name is not known
+     * to the client it set to NULL-DN. In this case for identification at least
+     * the senderKID must be set, where we took the referenceValue as fallback.
+     */
+
+    if (ossl_cmp_general_name_is_NULL_DN(msg->header->sender)
+            && msg->header->senderKID == NULL)
+        CMPerr(0, CMP_R_MISSING_SENDER_IDENTIFICATION);
+    else
+        return 1;
+
  err:
     CMPerr(0, CMP_R_ERROR_PROTECTING_MESSAGE);
     return 0;
diff --git a/crypto/cmp/cmp_server.c b/crypto/cmp/cmp_server.c
new file mode 100644
index 0000000000..a91f67b264
--- /dev/null
+++ b/crypto/cmp/cmp_server.c
@@ -0,0 +1,615 @@
+/*
+ * Copyright 2007-2019 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright Nokia 2007-2019
+ * Copyright Siemens AG 2015-2019
+ *
+ * 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
+ * https://www.openssl.org/source/license.html
+ */
+
+/* general CMP server functions */
+
+#include <openssl/asn1t.h>
+
+#include "cmp_local.h"
+
+/* explicit #includes not strictly needed since implied by the above: */
+#include <openssl/cmp.h>
+#include <openssl/err.h>
+
+/* the context for the generic CMP server */
+struct ossl_cmp_srv_ctx_st
+{
+    OSSL_CMP_CTX *ctx; /* Client CMP context, partly reused for srv */
+    void *custom_ctx;  /* pointer to specific server context */
+
+    OSSL_CMP_SRV_cert_request_cb_t process_cert_request;
+    OSSL_CMP_SRV_rr_cb_t process_rr;
+    OSSL_CMP_SRV_genm_cb_t process_genm;
+    OSSL_CMP_SRV_error_cb_t process_error;
+    OSSL_CMP_SRV_certConf_cb_t process_certConf;
+    OSSL_CMP_SRV_pollReq_cb_t process_pollReq;
+
+    int sendUnprotectedErrors; /* Send error and rejection msgs unprotected */
+    int acceptUnprotected;     /* Accept requests with no/invalid prot. */
+    int acceptRAVerified;      /* Accept ir/cr/kur with POPO RAVerified */
+    int grantImplicitConfirm;  /* Grant implicit confirmation if requested */
+
+}; /* OSSL_CMP_SRV_CTX */
+
+void OSSL_CMP_SRV_CTX_free(OSSL_CMP_SRV_CTX *srv_ctx)
+{
+    if (srv_ctx == NULL)
+        return;
+
+    OSSL_CMP_CTX_free(srv_ctx->ctx);
+    OPENSSL_free(srv_ctx);
+}
+
+OSSL_CMP_SRV_CTX *OSSL_CMP_SRV_CTX_new(void)
+{
+    OSSL_CMP_SRV_CTX *ctx = OPENSSL_zalloc(sizeof(OSSL_CMP_SRV_CTX));
+
+    if (ctx == NULL)
+        goto err;
+
+    if ((ctx->ctx = OSSL_CMP_CTX_new()) == NULL)
+        goto err;
+
+    /* all other elements are initialized to 0 or NULL, respectively */
+    return ctx;
+ err:
+    OSSL_CMP_SRV_CTX_free(ctx);
+    return NULL;
+}
+
+int OSSL_CMP_SRV_CTX_init(OSSL_CMP_SRV_CTX *srv_ctx, void *custom_ctx,
+                          OSSL_CMP_SRV_cert_request_cb_t process_cert_request,
+                          OSSL_CMP_SRV_rr_cb_t process_rr,
+                          OSSL_CMP_SRV_genm_cb_t process_genm,
+                          OSSL_CMP_SRV_error_cb_t process_error,
+                          OSSL_CMP_SRV_certConf_cb_t process_certConf,
+                          OSSL_CMP_SRV_pollReq_cb_t process_pollReq)
+{
+    if (srv_ctx == NULL) {
+        CMPerr(0, CMP_R_NULL_ARGUMENT);
+        return 0;
+    }
+    srv_ctx->custom_ctx = custom_ctx;
+    srv_ctx->process_cert_request = process_cert_request;
+    srv_ctx->process_rr = process_rr;
+    srv_ctx->process_genm = process_genm;
+    srv_ctx->process_error = process_error;
+    srv_ctx->process_certConf = process_certConf;
+    srv_ctx->process_pollReq = process_pollReq;
+    return 1;
+}
+
+OSSL_CMP_CTX *OSSL_CMP_SRV_CTX_get0_cmp_ctx(const OSSL_CMP_SRV_CTX *srv_ctx)
+{
+    if (srv_ctx == NULL) {
+        CMPerr(0, CMP_R_NULL_ARGUMENT);
+        return NULL;
+    }
+    return srv_ctx->ctx;
+}
+
+void *OSSL_CMP_SRV_CTX_get0_custom_ctx(const OSSL_CMP_SRV_CTX *srv_ctx)
+{
+    if (srv_ctx == NULL) {
+        CMPerr(0, CMP_R_NULL_ARGUMENT);
+        return NULL;
+    }
+    return srv_ctx->custom_ctx;
+}
+
+int OSSL_CMP_SRV_CTX_set_send_unprotected_errors(OSSL_CMP_SRV_CTX *srv_ctx,
+                                                 int val)
+{
+    if (srv_ctx == NULL) {
+        CMPerr(0, CMP_R_NULL_ARGUMENT);
+        return 0;
+    }
+    srv_ctx->sendUnprotectedErrors = val != 0;
+    return 1;
+}
+
+int OSSL_CMP_SRV_CTX_set_accept_unprotected(OSSL_CMP_SRV_CTX *srv_ctx, int val)
+{
+    if (srv_ctx == NULL) {
+        CMPerr(0, CMP_R_NULL_ARGUMENT);
+        return 0;
+    }
+    srv_ctx->acceptUnprotected = val != 0;
+    return 1;
+}
+
+int OSSL_CMP_SRV_CTX_set_accept_raverified(OSSL_CMP_SRV_CTX *srv_ctx, int val)
+{
+    if (srv_ctx == NULL) {
+        CMPerr(0, CMP_R_NULL_ARGUMENT);
+        return 0;
+    }
+    srv_ctx->acceptRAVerified = val != 0;
+    return 1;
+}
+
+int OSSL_CMP_SRV_CTX_set_grant_implicit_confirm(OSSL_CMP_SRV_CTX *srv_ctx,
+                                                int val)
+{
+    if (srv_ctx == NULL) {
+        CMPerr(0, CMP_R_NULL_ARGUMENT);
+        return 0;
+    }
+    srv_ctx->grantImplicitConfirm = val != 0;
+    return 1;
+}
+
+/*
+ * Processes an ir/cr/p10cr/kur and returns a certification response.
+ * Only handles the first certification request contained in req
+ * returns an ip/cp/kup on success and NULL on error
+ */
+static OSSL_CMP_MSG *process_cert_request(OSSL_CMP_SRV_CTX *srv_ctx,
+                                          const OSSL_CMP_MSG *req)
+{
+    OSSL_CMP_MSG *msg = NULL;
+    OSSL_CMP_PKISI *si = NULL;
+    X509 *certOut = NULL;
+    STACK_OF(X509) *chainOut = NULL, *caPubs = NULL;
+    const OSSL_CRMF_MSG *crm = NULL;
+    const X509_REQ *p10cr = NULL;
+    int bodytype;
+    int certReqId;
+
+    if (!ossl_assert(srv_ctx != NULL && srv_ctx->ctx != NULL && req != NULL))
+        return NULL;
+
+    switch (ossl_cmp_msg_get_bodytype(req)) {
+    case OSSL_CMP_PKIBODY_P10CR:
+    case OSSL_CMP_PKIBODY_CR:
+        bodytype = OSSL_CMP_PKIBODY_CP;
+        break;
+    case OSSL_CMP_PKIBODY_IR:
+        bodytype = OSSL_CMP_PKIBODY_IP;
+        break;
+    case OSSL_CMP_PKIBODY_KUR:
+        bodytype = OSSL_CMP_PKIBODY_KUP;
+        break;
+    default:
+        CMPerr(0, CMP_R_UNEXPECTED_PKIBODY);
+        return NULL;
+    }
+
+    if (ossl_cmp_msg_get_bodytype(req) == OSSL_CMP_PKIBODY_P10CR) {
+        certReqId = OSSL_CMP_CERTREQID;
+        p10cr = req->body->value.p10cr;
+    } else {
+        OSSL_CRMF_MSGS *reqs = req->body->value.ir; /* same for cr and kur */
+
+        if (sk_OSSL_CRMF_MSG_num(reqs) != 1) { /* TODO: handle case > 1 */
+            CMPerr(0, CMP_R_MULTIPLE_REQUESTS_NOT_SUPPORTED);
+            return NULL;
+        }
+
+        if ((crm = sk_OSSL_CRMF_MSG_value(reqs, OSSL_CMP_CERTREQID)) == NULL) {
+            CMPerr(0, CMP_R_CERTREQMSG_NOT_FOUND);
+            return NULL;
+        }
+        certReqId = OSSL_CRMF_MSG_get_certReqId(crm);
+    }
+
+    if (!ossl_cmp_verify_popo(req, srv_ctx->acceptRAVerified)) {
+        /* Proof of possession could not be verified */
+        si = OSSL_CMP_STATUSINFO_new(OSSL_CMP_PKISTATUS_rejection,
+                                     1 << OSSL_CMP_PKIFAILUREINFO_badPOP,
+                                     ERR_reason_error_string(ERR_peek_error()));
+        if (si == NULL)
+            return NULL;
+    } else {
+        OSSL_CMP_PKIHEADER *hdr = OSSL_CMP_MSG_get0_header(req);
+
+        si = srv_ctx->process_cert_request(srv_ctx, req, certReqId, crm, p10cr,
+                                           &certOut, &chainOut, &caPubs);
+        if (si == NULL)
+            goto err;
+        /* set OSSL_CMP_OPT_IMPLICITCONFIRM if and only if transaction ends */
+        if (!OSSL_CMP_CTX_set_option(srv_ctx->ctx, OSSL_CMP_OPT_IMPLICITCONFIRM,
+                                     ossl_cmp_hdr_has_implicitConfirm(hdr)
+                                         && srv_ctx->grantImplicitConfirm
+                                         /* do not set if polling starts: */
+                                         && certOut != NULL))
+            goto err;
+    }
+
+    msg = ossl_cmp_certRep_new(srv_ctx->ctx, bodytype, certReqId, si,
+                               certOut, chainOut, caPubs, 0 /* encrypted */,
+                               srv_ctx->sendUnprotectedErrors);
+    /*
+     * TODO when implemented in ossl_cmp_certrep_new():
+     * in case OSSL_CRMF_POPO_KEYENC, set encrypted
+     */
+    if (msg == NULL)
+        CMPerr(0, CMP_R_ERROR_CREATING_CERTREP);
+
+ err:
+    OSSL_CMP_PKISI_free(si);
+    X509_free(certOut);
+    sk_X509_pop_free(chainOut, X509_free);
+    sk_X509_pop_free(caPubs, X509_free);
+    return msg;
+}
+
+static OSSL_CMP_MSG *process_rr(OSSL_CMP_SRV_CTX *srv_ctx,
+                                const OSSL_CMP_MSG *req)
+{
+    OSSL_CMP_MSG *msg = NULL;
+    OSSL_CMP_REVDETAILS *details;
+    OSSL_CRMF_CERTID *certId;
+    OSSL_CRMF_CERTTEMPLATE *tmpl;
+    X509_NAME *issuer;
+    ASN1_INTEGER *serial;
+    OSSL_CMP_PKISI *si;
+
+    if (!ossl_assert(srv_ctx != NULL && srv_ctx->ctx != NULL && req != NULL))
+        return NULL;
+
+    if (sk_OSSL_CMP_REVDETAILS_num(req->body->value.rr) != 1) {
+        /* TODO: handle multiple elements if multiple requests have been sent */
+        CMPerr(0, CMP_R_MULTIPLE_REQUESTS_NOT_SUPPORTED);
+        return NULL;
+    }
+
+    if ((details = sk_OSSL_CMP_REVDETAILS_value(req->body->value.rr,
+                                                OSSL_CMP_REVREQSID)) == NULL) {
+        CMPerr(0, CMP_R_ERROR_PROCESSING_MSG);
+        return NULL;
+    }
+
+    tmpl = details->certDetails;
+    issuer = OSSL_CRMF_CERTTEMPLATE_get0_issuer(tmpl);
+    serial = OSSL_CRMF_CERTTEMPLATE_get0_serialNumber(tmpl);
+    /* here issuer and serial may safely be NULL */
+    if ((certId = OSSL_CRMF_CERTID_gen(issuer, serial)) == NULL)
+        return NULL;
+    if ((si = srv_ctx->process_rr(srv_ctx, req, issuer, serial)) == NULL)
+        goto err;
+
+    if ((msg = ossl_cmp_rp_new(srv_ctx->ctx, si, certId,
+                               srv_ctx->sendUnprotectedErrors)) == NULL)
+        CMPerr(0, CMP_R_ERROR_CREATING_RR);
+
+ err:
+    OSSL_CRMF_CERTID_free(certId);
+    OSSL_CMP_PKISI_free(si);
+    return msg;
+}
+
+/*
+ * Processes genm and creates a genp message mirroring the contents of the
+ * incoming message
+ */
+static OSSL_CMP_MSG *process_genm(OSSL_CMP_SRV_CTX *srv_ctx,
+                                  const OSSL_CMP_MSG *req)
+{
+    OSSL_CMP_GENMSGCONTENT *itavs;
+    OSSL_CMP_MSG *msg;
+
+    if (!ossl_assert(srv_ctx != NULL && srv_ctx->ctx != NULL && req != NULL))
+        return NULL;
+
+    if (!srv_ctx->process_genm(srv_ctx, req, req->body->value.genm, &itavs))
+        return NULL;
+
+    msg = ossl_cmp_genp_new(srv_ctx->ctx, itavs);
+    sk_OSSL_CMP_ITAV_pop_free(itavs, OSSL_CMP_ITAV_free);
+    return msg;
+}
+
+static OSSL_CMP_MSG *process_error(OSSL_CMP_SRV_CTX *srv_ctx,
+                                   const OSSL_CMP_MSG *req)
+{
+    OSSL_CMP_ERRORMSGCONTENT *errorContent;
+    OSSL_CMP_MSG *msg;
+
+    if (!ossl_assert(srv_ctx != NULL && srv_ctx->ctx != NULL && req != NULL))
+        return NULL;
+    errorContent = req->body->value.error;
+    srv_ctx->process_error(srv_ctx, req, errorContent->pKIStatusInfo,
+                           errorContent->errorCode, errorContent->errorDetails);
+
+    if ((msg = ossl_cmp_pkiconf_new(srv_ctx->ctx)) == NULL)
+        CMPerr(0, CMP_R_ERROR_CREATING_PKICONF);
+    return msg;
+}
+
+static OSSL_CMP_MSG *process_certConf(OSSL_CMP_SRV_CTX *srv_ctx,
+                                      const OSSL_CMP_MSG *req)
+{
+    OSSL_CMP_CTX *ctx;
+    OSSL_CMP_CERTCONFIRMCONTENT *ccc;
+    int num;
+    OSSL_CMP_MSG *msg = NULL;
+    OSSL_CMP_CERTSTATUS *status = NULL;
+
+    if (!ossl_assert(srv_ctx != NULL && srv_ctx->ctx != NULL && req != NULL))
+        return NULL;
+
+    ctx = srv_ctx->ctx;
+    ccc = req->body->value.certConf;
+    num = sk_OSSL_CMP_CERTSTATUS_num(ccc);
+
+    if (OSSL_CMP_CTX_get_option(ctx, OSSL_CMP_OPT_IMPLICITCONFIRM) == 1) {
+        CMPerr(0, CMP_R_ERROR_UNEXPECTED_CERTCONF);
+        return NULL;
+    }
+
+    if (num == 0) {
+        ossl_cmp_err(ctx, "certificate rejected by client");
+    } else {
+        if (num > 1)
+            ossl_cmp_warn(ctx, "All CertStatus but the first will be ignored");
+        status = sk_OSSL_CMP_CERTSTATUS_value(ccc, OSSL_CMP_CERTREQID);
+    }
+
+    if (status != NULL) {
+        int certReqId = ossl_cmp_asn1_get_int(status->certReqId);
+        ASN1_OCTET_STRING *certHash = status->certHash;
+        OSSL_CMP_PKISI *si = status->statusInfo;
+
+        if (!srv_ctx->process_certConf(srv_ctx, req, certReqId, certHash, si))
+            return NULL; /* reason code may be: CMP_R_CERTHASH_UNMATCHED */
+
+        if (si != NULL && ossl_cmp_pkisi_get_status(si)
+            != OSSL_CMP_PKISTATUS_accepted) {
+            int pki_status = ossl_cmp_pkisi_get_status(si);
+            const char *str = ossl_cmp_PKIStatus_to_string(pki_status);
+
+            ossl_cmp_log2(INFO, ctx, "certificate rejected by client %s %s",
+                          str == NULL ? "without" : "with",
+                          str == NULL ? "PKIStatus" : str);
+        }
+    }
+
+    if ((msg = ossl_cmp_pkiconf_new(ctx)) == NULL)
+        CMPerr(0, CMP_R_ERROR_CREATING_PKICONF);
+    return msg;
+}
+
+static OSSL_CMP_MSG *process_pollReq(OSSL_CMP_SRV_CTX *srv_ctx,
+                                     const OSSL_CMP_MSG *req)
+{
+    OSSL_CMP_POLLREQCONTENT *prc;
+    OSSL_CMP_POLLREQ *pr;
+    int certReqId;
+    OSSL_CMP_MSG *certReq;
+    int64_t check_after = 0;
+    OSSL_CMP_MSG *msg = NULL;
+
+    if (!ossl_assert(srv_ctx != NULL && srv_ctx->ctx != NULL && req != NULL))
+        return NULL;
+
+    prc = req->body->value.pollReq;
+    if (sk_OSSL_CMP_POLLREQ_num(prc) != 1) { /* TODO: handle case > 1 */
+        CMPerr(0, CMP_R_MULTIPLE_REQUESTS_NOT_SUPPORTED);
+        return NULL;
+    }
+
+    pr = sk_OSSL_CMP_POLLREQ_value(prc, 0);
+    certReqId = ossl_cmp_asn1_get_int(pr->certReqId);
+    if (!srv_ctx->process_pollReq(srv_ctx, req, certReqId,
+                                  &certReq, &check_after))
+        return NULL;
+
+    if (certReq != NULL) {
+        msg = process_cert_request(srv_ctx, certReq);
+        OSSL_CMP_MSG_free(certReq);
+    } else {
+        if ((msg = ossl_cmp_pollRep_new(srv_ctx->ctx, certReqId,
+                                        check_after)) == NULL)
+            CMPerr(0, CMP_R_ERROR_CREATING_POLLREP);
+    }
+    return msg;
+}
+
+/*
+ * Determines whether missing protection is allowed
+ */
+static int unprotected_exception(const OSSL_CMP_CTX *ctx,
+                                 const OSSL_CMP_MSG *req,
+                                 int invalid_protection,
+                                 int accept_unprotected_requests)
+{
+    if (accept_unprotected_requests) {
+        ossl_cmp_log1(WARN, ctx, "ignoring %s protection of request message",
+                      invalid_protection ? "invalid" : "missing");
+        return 1;
+    }
+    if (ossl_cmp_msg_get_bodytype(req) == OSSL_CMP_PKIBODY_ERROR
+        && OSSL_CMP_CTX_get_option(ctx, OSSL_CMP_OPT_UNPROTECTED_ERRORS) == 1) {
+        ossl_cmp_warn(ctx, "ignoring missing protection of error message");
+        return 1;
+    }
+    return 0;
+}
+
+/*
+ * returns created message and NULL on internal error
+ */
+OSSL_CMP_MSG *OSSL_CMP_SRV_process_request(OSSL_CMP_SRV_CTX *srv_ctx,
+                                           const OSSL_CMP_MSG *req)
+{
+    OSSL_CMP_CTX *ctx;
+    OSSL_CMP_PKIHEADER *hdr;
+    int req_type, rsp_type;
+    OSSL_CMP_MSG *rsp = NULL;
+
+    if (srv_ctx == NULL || srv_ctx->ctx == NULL
+            || req == NULL || req->body == NULL
+            || (hdr = OSSL_CMP_MSG_get0_header(req)) == NULL) {
+        CMPerr(0, CMP_R_NULL_ARGUMENT);
+        return 0;
+    }
+    ctx = srv_ctx->ctx;
+
+    if (hdr->sender->type != GEN_DIRNAME) {
+        CMPerr(0, CMP_R_SENDER_GENERALNAME_TYPE_NOT_SUPPORTED);
+        goto err;
+    }
+    if (!OSSL_CMP_CTX_set1_recipient(ctx, hdr->sender->d.directoryName))
+        goto err;
+
+    req_type = ossl_cmp_msg_get_bodytype(req);
+    switch (req_type) {
+    case OSSL_CMP_PKIBODY_IR:
+    case OSSL_CMP_PKIBODY_CR:
+    case OSSL_CMP_PKIBODY_P10CR:
+    case OSSL_CMP_PKIBODY_KUR:
+    case OSSL_CMP_PKIBODY_RR:
+    case OSSL_CMP_PKIBODY_GENM:
+    case OSSL_CMP_PKIBODY_ERROR:
+        if (ctx->transactionID != NULL) {
+            char *tid;
+
+            tid = OPENSSL_buf2hexstr(ctx->transactionID->data,
+                                     ctx->transactionID->length);
+            ossl_cmp_log1(WARN, ctx,
+                          "Assuming that last transaction with ID=%s got aborted",
+                          tid);
+            OPENSSL_free(tid);
+        }
+        /* start of a new transaction, set transactionID and senderNonce */
+        if (!OSSL_CMP_CTX_set1_transactionID(ctx, hdr->transactionID)
+                || !ossl_cmp_ctx_set1_recipNonce(ctx, hdr->senderNonce))
+            goto err;
+        break;
+    default:
+        /* transactionID should be already initialized */
+        if (ctx->transactionID == NULL) {
+            CMPerr(0, CMP_R_UNEXPECTED_PKIBODY);
+            /* ignore any (extra) error in next two function calls: */
+            (void)OSSL_CMP_CTX_set1_transactionID(ctx, hdr->transactionID);
+            (void)ossl_cmp_ctx_set1_recipNonce(ctx, hdr->senderNonce);
+            goto err;
+        }
+    }
+
+    if (ossl_cmp_msg_check_received(ctx, req, unprotected_exception,
+                                    srv_ctx->acceptUnprotected) < 0)
+        goto err;
+
+    switch (req_type) {
+    case OSSL_CMP_PKIBODY_IR:
+    case OSSL_CMP_PKIBODY_CR:
+    case OSSL_CMP_PKIBODY_P10CR:
+    case OSSL_CMP_PKIBODY_KUR:
+        if (srv_ctx->process_cert_request == NULL)
+            CMPerr(0, CMP_R_UNEXPECTED_PKIBODY);
+        else
+            rsp = process_cert_request(srv_ctx, req);
+        break;
+    case OSSL_CMP_PKIBODY_RR:
+        if (srv_ctx->process_rr == NULL)
+            CMPerr(0, CMP_R_UNEXPECTED_PKIBODY);
+        else
+            rsp = process_rr(srv_ctx, req);
+        break;
+    case OSSL_CMP_PKIBODY_GENM:
+        if (srv_ctx->process_genm == NULL)
+            CMPerr(0, CMP_R_UNEXPECTED_PKIBODY);
+        else
+            rsp = process_genm(srv_ctx, req);
+        break;
+    case OSSL_CMP_PKIBODY_ERROR:
+        if (srv_ctx->process_error == NULL)
+            CMPerr(0, CMP_R_UNEXPECTED_PKIBODY);
+        else
+            rsp = process_error(srv_ctx, req);
+        break;
+    case OSSL_CMP_PKIBODY_CERTCONF:
+        if (srv_ctx->process_certConf == NULL)
+            CMPerr(0, CMP_R_UNEXPECTED_PKIBODY);
+        else
+            rsp = process_certConf(srv_ctx, req);
+        break;
+    case OSSL_CMP_PKIBODY_POLLREQ:
+        if (srv_ctx->process_pollReq == NULL)
+            CMPerr(0, CMP_R_UNEXPECTED_PKIBODY);
+        else
+            rsp = process_pollReq(srv_ctx, req);
+        break;
+    default:
+        /* TODO possibly support further request message types */
+        CMPerr(0, CMP_R_UNEXPECTED_PKIBODY);
+    }
+
+ err:
+    if (rsp == NULL) {
+        /* on error, try to respond with CMP error message to client */
+        const char *data = NULL;
+        int flags = 0;
+        unsigned long err = ERR_peek_error_data(&data, &flags);
+        int fail_info = 1 << OSSL_CMP_PKIFAILUREINFO_badRequest;
+        /* TODO fail_info could be more specific */
+        OSSL_CMP_PKISI *si = NULL;
+
+        if ((si = OSSL_CMP_STATUSINFO_new(OSSL_CMP_PKISTATUS_rejection,
+                                          fail_info, NULL)) == NULL)
+            return 0;
+        if (err != 0 && (flags & ERR_TXT_STRING) != 0)
+            data = ERR_reason_error_string(err);
+        rsp = ossl_cmp_error_new(srv_ctx->ctx, si,
+                                 err != 0 ? ERR_GET_REASON(err) : -1,
+                                 data, srv_ctx->sendUnprotectedErrors);
+        OSSL_CMP_PKISI_free(si);
+    }
+
+    /* possibly close the transaction */
+    rsp_type =
+        rsp != NULL ? ossl_cmp_msg_get_bodytype(rsp) : OSSL_CMP_PKIBODY_ERROR;
+    switch (rsp_type) {
+    case OSSL_CMP_PKIBODY_IP:
+    case OSSL_CMP_PKIBODY_CP:
+    case OSSL_CMP_PKIBODY_KUP:
+    case OSSL_CMP_PKIBODY_RP:
+        if (OSSL_CMP_CTX_get_option(ctx, OSSL_CMP_OPT_IMPLICITCONFIRM) == 0)
+            break;
+        /* fall through */
+
+    case OSSL_CMP_PKIBODY_PKICONF:
+    case OSSL_CMP_PKIBODY_GENP:
+    case OSSL_CMP_PKIBODY_ERROR:
+        /* TODO possibly support further terminating response message types */
+        (void)OSSL_CMP_CTX_set1_transactionID(ctx, NULL); /* ignore any error */
+
+    default: /* not closing transaction in other cases */
+        break;
+    }
+    return rsp;
+}
+
+/*
+ * Server interface that may substitute OSSL_CMP_MSG_http_perform at the client.
+ * The OSSL_CMP_SRV_CTX must be set as client_ctx->transfer_cb_arg.
+ * returns received message on success, else NULL and pushes an element on the
+ * error stack.
+ */
+OSSL_CMP_MSG * OSSL_CMP_CTX_server_perform(OSSL_CMP_CTX *client_ctx,
+                                           const OSSL_CMP_MSG *req)
+{
+    OSSL_CMP_SRV_CTX *srv_ctx = NULL;
+
+    if (client_ctx == NULL || req == NULL) {
+        CMPerr(0, CMP_R_NULL_ARGUMENT);
+        return 0;
+    }
+
+    if ((srv_ctx = OSSL_CMP_CTX_get_transfer_cb_arg(client_ctx)) == NULL) {
+        CMPerr(0, CMP_R_ERROR_TRANSFERRING_OUT);
+        return 0;
+    }
+
+    return OSSL_CMP_SRV_process_request(srv_ctx, req);
+}
diff --git a/crypto/cmp/cmp_status.c b/crypto/cmp/cmp_status.c
index 7ebc57d37b..6232239237 100644
--- a/crypto/cmp/cmp_status.c
+++ b/crypto/cmp/cmp_status.c
@@ -28,17 +28,13 @@
 
 /* CMP functions related to PKIStatus */
 
-int ossl_cmp_pkisi_get_pkistatus(const OSSL_CMP_PKISI *si)
+int ossl_cmp_pkisi_get_status(const OSSL_CMP_PKISI *si)
 {
     if (!ossl_assert(si != NULL && si->status != NULL))
         return -1;
     return ossl_cmp_asn1_get_int(si->status);
 }
 
-/*
- * return the declared identifier and a short explanation for the PKIStatus
- * value as specified in RFC4210, Appendix F.
- */
 const char *ossl_cmp_PKIStatus_to_string(int status)
 {
     switch (status) {
@@ -67,21 +63,13 @@ const char *ossl_cmp_PKIStatus_to_string(int status)
     }
 }
 
-/*
- * returns a pointer to the statusString contained in a PKIStatusInfo
- * returns NULL on error
- */
-OSSL_CMP_PKIFREETEXT *ossl_cmp_pkisi_get0_statusstring(const OSSL_CMP_PKISI *si)
+OSSL_CMP_PKIFREETEXT *ossl_cmp_pkisi_get0_statusString(const OSSL_CMP_PKISI *si)
 {
     if (!ossl_assert(si != NULL))
         return NULL;
     return si->statusString;
 }
 
-/*
- * returns the FailureInfo bits of the given PKIStatusInfo
- * returns -1 on error
- */
 int ossl_cmp_pkisi_get_pkifailureinfo(const OSSL_CMP_PKISI *si)
 {
     int i;
@@ -95,12 +83,9 @@ int ossl_cmp_pkisi_get_pkifailureinfo(const OSSL_CMP_PKISI *si)
     return res;
 }
 
-/*
- * internal function
+/*-
  * convert PKIFailureInfo number to human-readable string
- *
- * returns pointer to static string
- * returns NULL on error
+ * returns pointer to static string, or NULL on error
  */
 static const char *CMP_PKIFAILUREINFO_to_string(int number)
 {
@@ -164,11 +149,7 @@ static const char *CMP_PKIFAILUREINFO_to_string(int number)
     }
 }
 
-/*
- * checks PKIFailureInfo bits in a given PKIStatusInfo
- * returns 1 if a given bit is set, 0 if not, -1 on error
- */
-int ossl_cmp_pkisi_pkifailureinfo_check(const OSSL_CMP_PKISI *si, int bit_index)
+int ossl_cmp_pkisi_check_pkifailureinfo(const OSSL_CMP_PKISI *si, int bit_index)
 {
     if (!ossl_assert(si != NULL && si->failInfo != NULL))
         return -1;
@@ -180,16 +161,17 @@ int ossl_cmp_pkisi_pkifailureinfo_check(const OSSL_CMP_PKISI *si, int bit_index)
     return ASN1_BIT_STRING_get_bit(si->failInfo, bit_index);
 }
 
-/*
+/*-
  * place human-readable error string created from PKIStatusInfo in given buffer
  * returns pointer to the same buffer containing the string, or NULL on error
  */
-char *OSSL_CMP_CTX_snprint_PKIStatus(OSSL_CMP_CTX *ctx, char *buf,
-                                     size_t bufsize)
+static
+char *snprint_PKIStatusInfo_parts(int status, int fail_info,
+                                  const OSSL_CMP_PKIFREETEXT *status_strings,
+                                  char *buf, size_t bufsize)
 {
-    int status, failure, fail_info;
+    int failure;
     const char *status_string, *failure_string;
-    OSSL_CMP_PKIFREETEXT *status_strings;
     ASN1_UTF8STRING *text;
     int i;
     int printed_chars;
@@ -197,22 +179,22 @@ char *OSSL_CMP_CTX_snprint_PKIStatus(OSSL_CMP_CTX *ctx, char *buf,
     int n_status_strings;
     char *write_ptr = buf;
 
-#define ADVANCE_BUFFER                                         \
-    if (printed_chars < 0 || (size_t)printed_chars >= bufsize) \
-        return NULL; \
-    write_ptr += printed_chars; \
-    bufsize -= printed_chars;
-
-    if (ctx == NULL
-            || buf == NULL
-            || (status = OSSL_CMP_CTX_get_status(ctx)) < 0
+    if (buf == NULL
+            || status < 0
             || (status_string = ossl_cmp_PKIStatus_to_string(status)) == NULL)
         return NULL;
+
+#define ADVANCE_BUFFER                                         \
+        if (printed_chars < 0 || (size_t)printed_chars >= bufsize) \
+            return NULL; \
+        write_ptr += printed_chars; \
+        bufsize -= printed_chars;
+
     printed_chars = BIO_snprintf(write_ptr, bufsize, "%s", status_string);
     ADVANCE_BUFFER;
 
     /* failInfo is optional and may be empty */
-    if ((fail_info = OSSL_CMP_CTX_get_failInfoCode(ctx)) > 0) {
+    if (fail_info != 0) {
         printed_chars = BIO_snprintf(write_ptr, bufsize, "; PKIFailureInfo: ");
         ADVANCE_BUFFER;
         for (failure = 0; failure <= OSSL_CMP_PKIFAILUREINFO_MAX; failure++) {
@@ -220,7 +202,7 @@ char *OSSL_CMP_CTX_snprint_PKIStatus(OSSL_CMP_CTX *ctx, char *buf,
                 failure_string = CMP_PKIFAILUREINFO_to_string(failure);
                 if (failure_string != NULL) {
                     printed_chars = BIO_snprintf(write_ptr, bufsize, "%s%s",
-                                                 failure > 0 ? ", " : "",
+                                                 failinfo_found ? ", " : "",
                                                  failure_string);
                     ADVANCE_BUFFER;
                     failinfo_found = 1;
@@ -235,7 +217,6 @@ char *OSSL_CMP_CTX_snprint_PKIStatus(OSSL_CMP_CTX *ctx, char *buf,
     }
 
     /* statusString sequence is optional and may be empty */
-    status_strings = OSSL_CMP_CTX_get0_statusString(ctx);
     n_status_strings = sk_ASN1_UTF8STRING_num(status_strings);
     if (n_status_strings > 0) {
         printed_chars = BIO_snprintf(write_ptr, bufsize, "; StatusString%s: ",
@@ -253,13 +234,44 @@ char *OSSL_CMP_CTX_snprint_PKIStatus(OSSL_CMP_CTX *ctx, char *buf,
     return buf;
 }
 
-/*
+char *OSSL_CMP_snprint_PKIStatusInfo(const OSSL_CMP_PKISI *statusInfo,
+                                     char *buf, size_t bufsize)
+{
+    int failure_info;
+
+    if (statusInfo == NULL) {
+        CMPerr(0, CMP_R_NULL_ARGUMENT);
+        return NULL;
+    }
+
+    failure_info = ossl_cmp_pkisi_get_pkifailureinfo(statusInfo);
+
+    return snprint_PKIStatusInfo_parts(ASN1_INTEGER_get(statusInfo->status),
+                                       failure_info,
+                                       statusInfo->statusString, buf, bufsize);
+}
+
+char *OSSL_CMP_CTX_snprint_PKIStatus(const OSSL_CMP_CTX *ctx, char *buf,
+                                     size_t bufsize)
+{
+    if (ctx == NULL) {
+        CMPerr(0, CMP_R_NULL_ARGUMENT);
+        return NULL;
+    }
+
+    return snprint_PKIStatusInfo_parts(OSSL_CMP_CTX_get_status(ctx),
+                                       OSSL_CMP_CTX_get_failInfoCode(ctx),
+                                       OSSL_CMP_CTX_get0_statusString(ctx),
+                                       buf, bufsize);
+}
+
+/*-
  * Creates a new PKIStatusInfo structure and fills it in
  * returns a pointer to the structure on success, NULL on error
  * note: strongly overlaps with TS_RESP_CTX_set_status_info()
  * and TS_RESP_CTX_add_failure_info() in ../ts/ts_rsp_sign.c
  */
-OSSL_CMP_PKISI *ossl_cmp_statusinfo_new(int status, int fail_info,
+OSSL_CMP_PKISI *OSSL_CMP_STATUSINFO_new(int status, int fail_info,
                                         const char *text)
 {
     OSSL_CMP_PKISI *si = OSSL_CMP_PKISI_new();
diff --git a/crypto/cmp/cmp_util.c b/crypto/cmp/cmp_util.c
index ad4ae66454..70c060166a 100644
--- a/crypto/cmp/cmp_util.c
+++ b/crypto/cmp/cmp_util.c
@@ -320,6 +320,26 @@ STACK_OF(X509) *ossl_cmp_build_cert_chain(STACK_OF(X509) *certs, X509 *cert)
     return result;
 }
 
+int ossl_cmp_sk_ASN1_UTF8STRING_push_str(STACK_OF(ASN1_UTF8STRING) *sk,
+                                         const char *text)
+{
+    ASN1_UTF8STRING *utf8string;
+
+    if (!ossl_assert(sk != NULL && text != NULL))
+        return 0;
+    if ((utf8string = ASN1_UTF8STRING_new()) == NULL)
+        return 0;
+    if (!ASN1_STRING_set(utf8string, text, -1))
+        goto err;
+    if (!sk_ASN1_UTF8STRING_push(sk, utf8string))
+        goto err;
+    return 1;
+
+ err:
+    ASN1_UTF8STRING_free(utf8string);
+    return 0;
+}
+
 int ossl_cmp_asn1_octet_string_set1(ASN1_OCTET_STRING **tgt,
                                     const ASN1_OCTET_STRING *src)
 {
diff --git a/crypto/crmf/crmf_err.c b/crypto/crmf/crmf_err.c
index 87e6a2da60..159d5b2c91 100644
--- a/crypto/crmf/crmf_err.c
+++ b/crypto/crmf/crmf_err.c
@@ -1,6 +1,6 @@
 /*
  * Generated by util/mkerr.pl DO NOT EDIT
- * Copyright 1995-2019 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 1995-2020 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
@@ -30,6 +30,15 @@ static const ERR_STRING_DATA CRMF_str_reasons[] = {
     "iterationcount below 100"},
     {ERR_PACK(ERR_LIB_CRMF, 0, CRMF_R_MALFORMED_IV), "malformed iv"},
     {ERR_PACK(ERR_LIB_CRMF, 0, CRMF_R_NULL_ARGUMENT), "null argument"},
+    {ERR_PACK(ERR_LIB_CRMF, 0, CRMF_R_POPO_INCONSISTENT_PUBLIC_KEY),
+    "popo inconsistent public key"},
+    {ERR_PACK(ERR_LIB_CRMF, 0, CRMF_R_POPO_MISSING), "popo missing"},
+    {ERR_PACK(ERR_LIB_CRMF, 0, CRMF_R_POPO_MISSING_PUBLIC_KEY),
+    "popo missing public key"},
+    {ERR_PACK(ERR_LIB_CRMF, 0, CRMF_R_POPO_MISSING_SUBJECT),
+    "popo missing subject"},
+    {ERR_PACK(ERR_LIB_CRMF, 0, CRMF_R_POPO_RAVERIFIED_NOT_ACCEPTED),
+    "popo raverified not accepted"},
     {ERR_PACK(ERR_LIB_CRMF, 0, CRMF_R_SETTING_MAC_ALGOR_FAILURE),
     "setting mac algor failure"},
     {ERR_PACK(ERR_LIB_CRMF, 0, CRMF_R_SETTING_OWF_ALGOR_FAILURE),
@@ -44,8 +53,6 @@ static const ERR_STRING_DATA CRMF_str_reasons[] = {
     "unsupported method for creating popo"},
     {ERR_PACK(ERR_LIB_CRMF, 0, CRMF_R_UNSUPPORTED_POPO_METHOD),
     "unsupported popo method"},
-    {ERR_PACK(ERR_LIB_CRMF, 0, CRMF_R_UNSUPPORTED_POPO_NOT_ACCEPTED),
-    "unsupported popo not accepted"},
     {0, NULL}
 };
 
diff --git a/crypto/crmf/crmf_lib.c b/crypto/crmf/crmf_lib.c
index 863d26f86e..dd69372f3e 100644
--- a/crypto/crmf/crmf_lib.c
+++ b/crypto/crmf/crmf_lib.c
@@ -303,7 +303,7 @@ static int crmf_asn1_get_int(const ASN1_INTEGER *a)
     return (int)res;
 }
 
-int OSSL_CRMF_MSG_get_certReqId(OSSL_CRMF_MSG *crm)
+int OSSL_CRMF_MSG_get_certReqId(const OSSL_CRMF_MSG *crm)
 {
     if (crm == NULL || /* not really needed: */ crm->certReq == NULL) {
         CRMFerr(CRMF_F_OSSL_CRMF_MSG_GET_CERTREQID, CRMF_R_NULL_ARGUMENT);
@@ -485,21 +485,29 @@ int OSSL_CRMF_MSGS_verify_popo(const OSSL_CRMF_MSGS *reqs,
     X509_PUBKEY *pubkey = NULL;
     OSSL_CRMF_POPOSIGNINGKEY *sig = NULL;
 
-    if (reqs == NULL
-            || (req = sk_OSSL_CRMF_MSG_value(reqs, rid)) == NULL
-            || req->popo == NULL) {
-        CRMFerr(CRMF_F_OSSL_CRMF_MSGS_VERIFY_POPO,
-                CRMF_R_NULL_ARGUMENT);
+    if (reqs == NULL || (req = sk_OSSL_CRMF_MSG_value(reqs, rid)) == NULL) {
+        CRMFerr(CRMF_F_OSSL_CRMF_MSGS_VERIFY_POPO, CRMF_R_NULL_ARGUMENT);
+        return 0;
+    }
+
+    if (req->popo == NULL) {
+        CRMFerr(0, CRMF_R_POPO_MISSING);
         return 0;
     }
 
     switch (req->popo->type) {
     case OSSL_CRMF_POPO_RAVERIFIED:
-        if (acceptRAVerified)
-            return 1;
+        if (!acceptRAVerified) {
+            CRMFerr(0, CRMF_R_POPO_RAVERIFIED_NOT_ACCEPTED);
+            return 0;
+        }
         break;
     case OSSL_CRMF_POPO_SIGNATURE:
         pubkey = req->certReq->certTemplate->publicKey;
+        if (pubkey == NULL) {
+            CRMFerr(0, CRMF_R_POPO_MISSING_PUBLIC_KEY);
+            return 0;
+        }
         sig = req->popo->value.signature;
         if (sig->poposkInput != NULL) {
             /*
@@ -507,26 +515,34 @@ int OSSL_CRMF_MSGS_verify_popo(const OSSL_CRMF_MSGS *reqs,
              * the public key from the certificate template. This MUST be
              * exactly the same value as contained in the certificate template.
              */
-            const ASN1_ITEM *rptr = ASN1_ITEM_rptr(OSSL_CRMF_POPOSIGNINGKEYINPUT);
-
-            if (pubkey == NULL
-                    || sig->poposkInput->publicKey == NULL
-                    || X509_PUBKEY_cmp(pubkey, sig->poposkInput->publicKey)
-                    || ASN1_item_verify(rptr, sig->algorithmIdentifier,
-                                        sig->signature, sig->poposkInput,
-                                        X509_PUBKEY_get0(pubkey)) < 1)
-                break;
+            if (sig->poposkInput->publicKey == NULL) {
+                CRMFerr(0, CRMF_R_POPO_MISSING_PUBLIC_KEY);
+                return 0;
+            }
+            if (X509_PUBKEY_cmp(pubkey, sig->poposkInput->publicKey) != 0) {
+                CRMFerr(0, CRMF_R_POPO_INCONSISTENT_PUBLIC_KEY);
+                return 0;
+            }
+            /*
+             * TODO check the contents of the authInfo sub-field,
+             * see RFC 4211 https://tools.ietf.org/html/rfc4211#section-4.1
+             */
+            if (ASN1_item_verify(ASN1_ITEM_rptr(OSSL_CRMF_POPOSIGNINGKEYINPUT),
+                                 sig->algorithmIdentifier, sig->signature,
+                                 sig->poposkInput,
+                                 X509_PUBKEY_get0(pubkey)) < 1)
+                return 0;
         } else {
-            if (pubkey == NULL
-                    || req->certReq->certTemplate->subject == NULL
-                    || ASN1_item_verify(ASN1_ITEM_rptr(OSSL_CRMF_CERTREQUEST),
-                                        sig->algorithmIdentifier,
-                                        sig->signature,
-                                        req->certReq,
-                                        X509_PUBKEY_get0(pubkey)) < 1)
-                break;
+            if (req->certReq->certTemplate->subject == NULL) {
+                CRMFerr(0, CRMF_R_POPO_MISSING_SUBJECT);
+                return 0;
+            }
+            if (ASN1_item_verify(ASN1_ITEM_rptr(OSSL_CRMF_CERTREQUEST),
+                                 sig->algorithmIdentifier, sig->signature,
+                                 req->certReq, X509_PUBKEY_get0(pubkey)) < 1)
+                return 0;
         }
-        return 1;
+        break;
     case OSSL_CRMF_POPO_KEYENC:
         /*
          * TODO: when OSSL_CMP_certrep_new() supports encrypted certs,
@@ -540,19 +556,19 @@ int OSSL_CRMF_MSGS_verify_popo(const OSSL_CRMF_MSGS *reqs,
                 CRMF_R_UNSUPPORTED_POPO_METHOD);
         return 0;
     }
-    CRMFerr(CRMF_F_OSSL_CRMF_MSGS_VERIFY_POPO,
-            CRMF_R_UNSUPPORTED_POPO_NOT_ACCEPTED);
-    return 0;
+    return 1;
 }
 
 /* retrieves the serialNumber of the given cert template or NULL on error */
-ASN1_INTEGER *OSSL_CRMF_CERTTEMPLATE_get0_serialNumber(OSSL_CRMF_CERTTEMPLATE *tmpl)
+ASN1_INTEGER
+*OSSL_CRMF_CERTTEMPLATE_get0_serialNumber(const OSSL_CRMF_CERTTEMPLATE *tmpl)
 {
     return tmpl != NULL ? tmpl->serialNumber : NULL;
 }
 
 /* retrieves the issuer name of the given cert template or NULL on error */
-X509_NAME *OSSL_CRMF_CERTTEMPLATE_get0_issuer(OSSL_CRMF_CERTTEMPLATE *tmpl)
+X509_NAME
+*OSSL_CRMF_CERTTEMPLATE_get0_issuer(const OSSL_CRMF_CERTTEMPLATE *tmpl)
 {
     return tmpl != NULL ? tmpl->issuer : NULL;
 }
@@ -606,7 +622,7 @@ int OSSL_CRMF_CERTTEMPLATE_fill(OSSL_CRMF_CERTTEMPLATE *tmpl,
  * returns a pointer to the decrypted certificate
  * returns NULL on error or if no certificate available
  */
-X509 *OSSL_CRMF_ENCRYPTEDVALUE_get1_encCert(OSSL_CRMF_ENCRYPTEDVALUE *ecert,
+X509 *OSSL_CRMF_ENCRYPTEDVALUE_get1_encCert(const OSSL_CRMF_ENCRYPTEDVALUE *ecert,
                                             EVP_PKEY *pkey)
 {
     X509 *cert = NULL; /* decrypted certificate */
diff --git a/crypto/err/err_prn.c b/crypto/err/err_prn.c
index 9a5889829d..1647d93043 100644
--- a/crypto/err/err_prn.c
+++ b/crypto/err/err_prn.c
@@ -68,7 +68,7 @@ void ERR_add_error_txt(const char *separator, const char *txt)
     if (separator == NULL)
         separator = "";
     if (err == 0)
-        put_error(ERR_LIB_CMP, NULL, 0, "", 0);
+        put_error(ERR_LIB_NONE, NULL, 0, "", 0);
 
     do {
         size_t available_len, data_len;
@@ -125,7 +125,7 @@ void ERR_add_error_txt(const char *separator, const char *txt)
                 ERR_add_error_data(2, separator, tmp);
                 OPENSSL_free(tmp);
             }
-            put_error(ERR_LIB_CMP, func, err, file, line);
+            put_error(ERR_GET_LIB(err), func, err, file, line);
             txt = curr;
         } else {
             if (trailing_separator) {
diff --git a/crypto/err/openssl.txt b/crypto/err/openssl.txt
index 8689e34925..c921207698 100644
--- a/crypto/err/openssl.txt
+++ b/crypto/err/openssl.txt
@@ -2076,8 +2076,10 @@ BN_R_TOO_MANY_ITERATIONS:113:too many iterations
 BN_R_TOO_MANY_TEMPORARY_VARIABLES:109:too many temporary variables
 CMP_R_ALGORITHM_NOT_SUPPORTED:139:algorithm not supported
 CMP_R_BAD_REQUEST_ID:108:bad request id
+CMP_R_CERTHASH_UNMATCHED:156:certhash unmatched
 CMP_R_CERTID_NOT_FOUND:109:certid not found
 CMP_R_CERTIFICATE_NOT_FOUND:112:certificate not found
+CMP_R_CERTREQMSG_NOT_FOUND:157:certreqmsg not found
 CMP_R_CERTRESPONSE_NOT_FOUND:113:certresponse not found
 CMP_R_CERT_AND_KEY_DO_NOT_MATCH:114:cert and key do not match
 CMP_R_ERROR_CALCULATING_PROTECTION:115:error calculating protection
@@ -2093,8 +2095,11 @@ CMP_R_ERROR_CREATING_POLLREQ:124:error creating pollreq
 CMP_R_ERROR_CREATING_RP:125:error creating rp
 CMP_R_ERROR_CREATING_RR:126:error creating rr
 CMP_R_ERROR_PARSING_PKISTATUS:107:error parsing pkistatus
+CMP_R_ERROR_PROCESSING_MSG:158:error processing msg
 CMP_R_ERROR_PROTECTING_MESSAGE:127:error protecting message
 CMP_R_ERROR_SETTING_CERTHASH:128:error setting certhash
+CMP_R_ERROR_TRANSFERRING_OUT:159:error transferring out
+CMP_R_ERROR_UNEXPECTED_CERTCONF:160:error unexpected certconf
 CMP_R_ERROR_VALIDATING_PROTECTION:140:error validating protection
 CMP_R_FAILED_EXTRACTING_PUBKEY:141:failed extracting pubkey
 CMP_R_FAILURE_OBTAINING_RANDOM:110:failure obtaining random
@@ -2107,6 +2112,7 @@ CMP_R_MISSING_PRIVATE_KEY:131:missing private key
 CMP_R_MISSING_PROTECTION:143:missing protection
 CMP_R_MISSING_SENDER_IDENTIFICATION:111:missing sender identification
 CMP_R_MISSING_TRUST_STORE:144:missing trust store
+CMP_R_MULTIPLE_REQUESTS_NOT_SUPPORTED:161:multiple requests not supported
 CMP_R_MULTIPLE_SAN_SOURCES:102:multiple san sources
 CMP_R_NO_STDIO:194:no stdio
 CMP_R_NO_SUITABLE_SENDER_CERT:145:no suitable sender cert
@@ -2256,6 +2262,11 @@ CRMF_R_FAILURE_OBTAINING_RANDOM:107:failure obtaining random
 CRMF_R_ITERATIONCOUNT_BELOW_100:108:iterationcount below 100
 CRMF_R_MALFORMED_IV:101:malformed iv
 CRMF_R_NULL_ARGUMENT:109:null argument
+CRMF_R_POPO_INCONSISTENT_PUBLIC_KEY:117:popo inconsistent public key
+CRMF_R_POPO_MISSING:121:popo missing
+CRMF_R_POPO_MISSING_PUBLIC_KEY:118:popo missing public key
+CRMF_R_POPO_MISSING_SUBJECT:119:popo missing subject
+CRMF_R_POPO_RAVERIFIED_NOT_ACCEPTED:120:popo raverified not accepted
 CRMF_R_SETTING_MAC_ALGOR_FAILURE:110:setting mac algor failure
 CRMF_R_SETTING_OWF_ALGOR_FAILURE:111:setting owf algor failure
 CRMF_R_UNSUPPORTED_ALGORITHM:112:unsupported algorithm
@@ -2264,7 +2275,6 @@ CRMF_R_UNSUPPORTED_CIPHER:114:unsupported cipher
 CRMF_R_UNSUPPORTED_METHOD_FOR_CREATING_POPO:115:\
 	unsupported method for creating popo
 CRMF_R_UNSUPPORTED_POPO_METHOD:116:unsupported popo method
-CRMF_R_UNSUPPORTED_POPO_NOT_ACCEPTED:117:unsupported popo not accepted
 CRYPTO_R_BAD_ALGORITHM_NAME:117:bad algorithm name
 CRYPTO_R_CONFLICTING_NAMES:118:conflicting names
 CRYPTO_R_FIPS_MODE_NOT_SUPPORTED:101:fips mode not supported
diff --git a/crypto/http/http_local.h b/crypto/http/http_local.h
index 4e6577f66d..4722750018 100644
--- a/crypto/http/http_local.h
+++ b/crypto/http/http_local.h
@@ -46,4 +46,4 @@ ASN1_VALUE *HTTP_sendreq_bio(BIO *bio, OSSL_HTTP_bio_cb_t bio_update_fn,
                              int maxline, unsigned long max_resp_len,
                              int timeout, const ASN1_ITEM *rsp_it);
 
-#endif /* !defined OSSL_CRYPTO_HTTP_LOCAL_H */
+#endif /* !defined(OSSL_CRYPTO_HTTP_LOCAL_H) */
diff --git a/crypto/ts/ts_rsp_verify.c b/crypto/ts/ts_rsp_verify.c
index 7d2161f2d0..dfb068c8b6 100644
--- a/crypto/ts/ts_rsp_verify.c
+++ b/crypto/ts/ts_rsp_verify.c
@@ -495,34 +495,7 @@ static int ts_check_status_info(TS_RESP *response)
 
 static char *ts_get_status_text(STACK_OF(ASN1_UTF8STRING) *text)
 {
-    int i;
-    int length = 0;
-    char *result = NULL;
-    char *p;
-
-    for (i = 0; i < sk_ASN1_UTF8STRING_num(text); ++i) {
-        ASN1_UTF8STRING *current = sk_ASN1_UTF8STRING_value(text, i);
-        if (ASN1_STRING_length(current) > TS_MAX_STATUS_LENGTH - length - 1)
-            return NULL;
-        length += ASN1_STRING_length(current);
-        length += 1;            /* separator character */
-    }
-    if ((result = OPENSSL_malloc(length)) == NULL) {
-        TSerr(TS_F_TS_GET_STATUS_TEXT, ERR_R_MALLOC_FAILURE);
-        return NULL;
-    }
-
-    for (i = 0, p = result; i < sk_ASN1_UTF8STRING_num(text); ++i) {
-        ASN1_UTF8STRING *current = sk_ASN1_UTF8STRING_value(text, i);
-        length = ASN1_STRING_length(current);
-        if (i > 0)
-            *p++ = '/';
-        strncpy(p, (const char *)ASN1_STRING_get0_data(current), length);
-        p += length;
-    }
-    *p = '\0';
-
-    return result;
+    return sk_ASN1_UTF8STRING2text(text, "/", TS_MAX_STATUS_LENGTH);
 }
 
 static int ts_check_policy(const ASN1_OBJECT *req_oid,
diff --git a/crypto/x509/x_all.c b/crypto/x509/x_all.c
index 6a6748bad4..2d7387b9e0 100644
--- a/crypto/x509/x_all.c
+++ b/crypto/x509/x_all.c
@@ -450,6 +450,35 @@ int X509_digest(const X509 *data, const EVP_MD *type, unsigned char *md,
             (ASN1_ITEM_rptr(X509), type, (char *)data, md, len));
 }
 
+/* calculate cert digest using the same hash algorithm as in its signature */
+ASN1_OCTET_STRING *X509_digest_sig(const X509 *cert)
+{
+    unsigned int len;
+    unsigned char hash[EVP_MAX_MD_SIZE];
+    int md_NID;
+    const EVP_MD *md = NULL;
+    ASN1_OCTET_STRING *new = NULL;
+
+    if (cert == NULL) {
+        X509err(0, ERR_R_PASSED_NULL_PARAMETER);
+        return NULL;
+    }
+
+    if (!OBJ_find_sigid_algs(X509_get_signature_nid(cert), &md_NID, NULL)
+            || (md = EVP_get_digestbynid(md_NID)) == NULL) {
+        CMPerr(0, X509_R_UNSUPPORTED_ALGORITHM);
+        return NULL;
+    }
+    if (!X509_digest(cert, md, hash, &len)
+            || (new = ASN1_OCTET_STRING_new()) == NULL)
+        return NULL;
+    if (!(ASN1_OCTET_STRING_set(new, hash, len))) {
+        ASN1_OCTET_STRING_free(new);
+        return NULL;
+    }
+    return new;
+}
+
 int X509_CRL_digest(const X509_CRL *data, const EVP_MD *type,
                     unsigned char *md, unsigned int *len)
 {
diff --git a/doc/internal/man3/ossl_cmp_hdr_init.pod b/doc/internal/man3/ossl_cmp_hdr_init.pod
index a7a4d87f09..5df7486cb0 100644
--- a/doc/internal/man3/ossl_cmp_hdr_init.pod
+++ b/doc/internal/man3/ossl_cmp_hdr_init.pod
@@ -5,6 +5,7 @@
 ossl_cmp_hdr_set_pvno,
 ossl_cmp_hdr_get_pvno,
 ossl_cmp_hdr_get0_sendernonce,
+ossl_cmp_general_name_is_NULL_DN,
 ossl_cmp_hdr_set1_sender,
 ossl_cmp_hdr_set1_recipient,
 ossl_cmp_hdr_update_messagetime,
@@ -14,7 +15,7 @@ ossl_cmp_hdr_push1_freeText,
 ossl_cmp_hdr_generalinfo_item_push0,
 ossl_cmp_hdr_generalinfo_items_push1,
 ossl_cmp_hdr_set_implicitConfirm,
-ossl_cmp_hdr_check_implicitConfirm,
+ossl_cmp_hdr_has_implicitConfirm,
 ossl_cmp_hdr_init
 - functions manipulating CMP message headers
 
@@ -26,6 +27,7 @@ ossl_cmp_hdr_init
   int ossl_cmp_hdr_get_pvno(const OSSL_CMP_PKIHEADER *hdr);
   ASN1_OCTET_STRING
      *ossl_cmp_hdr_get0_sendernonce(const OSSL_CMP_PKIHEADER *hdr);
+  int ossl_cmp_general_name_is_NULL_DN(GENERAL_NAME *name);
 
   int ossl_cmp_hdr_set1_sender(OSSL_CMP_PKIHEADER *hdr, const X509_NAME *nm);
   int ossl_cmp_hdr_set1_recipient(OSSL_CMP_PKIHEADER *hdr, const X509_NAME *nm);
@@ -41,7 +43,7 @@ ossl_cmp_hdr_init
   int ossl_cmp_hdr_push1_freeText(OSSL_CMP_PKIHEADER *hdr,
                                   ASN1_UTF8STRING *text);
   int ossl_cmp_hdr_set_implicitConfirm(OSSL_CMP_PKIHEADER *hdr);
-  int ossl_cmp_hdr_check_implicitConfirm(OSSL_CMP_PKIHEADER *hdr);
+  int ossl_cmp_hdr_has_implicitConfirm(OSSL_CMP_PKIHEADER *hdr);
   int ossl_cmp_hdr_init(OSSL_CMP_CTX *ctx, OSSL_CMP_PKIHEADER *hdr);
 
 =head1 DESCRIPTION
@@ -52,6 +54,9 @@ ossl_cmp_hdr_get_pvno() returns the pvno of the given B<hdr> or -1 on error.
 
 ossl_cmp_hdr_get0_sendernonce() returns the sender nonce of the given PKIHeader.
 
+ossl_cmp_general_name_is_NULL_DN() determines if the given GENERAL_NAME
+is the NULL-DN.
+
 ossl_cmp_hdr_set1_sender() sets the sender field in the given PKIHeader
 to the given X509 Name value, without consuming the pointer.
 
@@ -85,7 +90,7 @@ pointer.
 ossl_cmp_hdr_set_implicitConfirm() sets implicitConfirm in the generalInfo field
 of the PKIMessage header.
 
-ossl_cmp_hdr_check_implicitConfirm() returns 1 if implicitConfirm is
+ossl_cmp_hdr_has_implicitConfirm() returns 1 if implicitConfirm is
 set int generalInfo field of the given PKIMessage header, 0 if not.
 
 ossl_cmp_hdr_init() initializes a PKIHeader structure based on the
@@ -107,6 +112,8 @@ ossl_cmp_hdr_get_pvno() returns the pvno of the given B<hdr> or -1 on error.
 
 ossl_cmp_hdr_get0_sendernonce() returns the respective nonce.
 
+ossl_cmp_general_name_is_NULL_DN() returns 1 given a NULL-DN, else 0.
+
 All other functions return 1 on success, 0 on error.
 
 See the individual functions above.
diff --git a/doc/internal/man3/ossl_cmp_mock_srv_new.pod b/doc/internal/man3/ossl_cmp_mock_srv_new.pod
new file mode 100644
index 0000000000..da1f44b391
--- /dev/null
+++ b/doc/internal/man3/ossl_cmp_mock_srv_new.pod
@@ -0,0 +1,85 @@
+=pod
+
+=head1 NAME
+
+ossl_cmp_mock_srv_new,
+ossl_cmp_mock_srv_free,
+ossl_cmp_mock_srv_set1_certOut,
+ossl_cmp_mock_srv_set1_chainOut,
+ossl_cmp_mock_srv_set1_caPubsOut,
+ossl_cmp_mock_srv_set_statusInfo,
+ossl_cmp_mock_srv_set_send_error,
+ossl_cmp_mock_srv_set_pollCount,
+ossl_cmp_mock_srv_set_checkAfterTime
+- functions used for testing with CMP mock server
+
+=head1 SYNOPSIS
+
+ #include <openssl/cmp.h>
+
+ OSSL_CMP_SRV_CTX *ossl_cmp_mock_srv_new(void);
+ void ossl_cmp_mock_srv_free(OSSL_CMP_SRV_CTX *srv_ctx);
+
+ int ossl_cmp_mock_srv_set1_certOut(OSSL_CMP_SRV_CTX *srv_ctx, X509 *cert);
+ int ossl_cmp_mock_srv_set1_chainOut(OSSL_CMP_SRV_CTX *srv_ctx,
+                                     STACK_OF(X509) *chain);
+ int ossl_cmp_mock_srv_set1_caPubsOut(OSSL_CMP_SRV_CTX *srv_ctx,
+                                      STACK_OF(X509) *caPubs);
+ int ossl_cmp_mock_srv_set_statusInfo(OSSL_CMP_SRV_CTX *srv_ctx, int status,
+                                      int fail_info, const char *text);
+ int ossl_cmp_mock_srv_set_send_error(OSSL_CMP_SRV_CTX *srv_ctx, int val);
+ int ossl_cmp_mock_srv_set_pollCount(OSSL_CMP_SRV_CTX *srv_ctx, int count);
+ int ossl_cmp_mock_srv_set_checkAfterTime(OSSL_CMP_SRV_CTX *srv_ctx, int sec);
+
+=head1 DESCRIPTION
+
+ossl_cmp_mock_srv_new() allocates the contexts for the CMP mock server.
+
+ossl_cmp_mock_srv_free() deallocates the contexts for the CMP mock server.
+
+OSSL_CMP_SRV_CTX_set1_certOut() sets the certificate to be returned in
+cp/ip/kup.
+
+OSSL_CMP_SRV_CTX_set1_chainOut() sets the certificate chain to be added to
+the extraCerts in a cp/ip/kup.
+It should to useful to validate B<certOut>.
+
+OSSL_CMP_SRV_CTX_set1_caPubsOut() sets the caPubs to be returned in an ip.
+
+OSSL_CMP_SRV_CTX_set_statusInfo() sets the status info to be returned.
+
+OSSL_CMP_SRV_CTX_set_send_error() enables enforcement of error responses.
+
+OSSL_CMP_SRV_CTX_set_pollCount() sets the number of polls before cert response.
+
+OSSL_CMP_SRV_CTX_set_checkAfterTime() sets the number of seconds
+the client should wait for the next poll.
+
+
+=head1 NOTES
+
+CMP is defined in RFC 4210 (and CRMF in RFC 4211).
+
+=head1 RETURN VALUES
+
+ossl_cmp_mock_srv() returns a B<OSSL_CMP_SRV_CTX> structure on success,
+NULL on error.
+
+ossl_cmp_mock_srv_free() does not return a value.
+
+All other functions return 1 on success, 0 on error.
+
+=head1 HISTORY
+
+The OpenSSL CMP support was added in OpenSSL 3.0.
+
+=head1 COPYRIGHT
+
+Copyright 2007-2020 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/internal/man3/ossl_cmp_statusinfo_new.pod b/doc/internal/man3/ossl_cmp_pkisi_get_status.pod
similarity index 58%
rename from doc/internal/man3/ossl_cmp_statusinfo_new.pod
rename to doc/internal/man3/ossl_cmp_pkisi_get_status.pod
index ee7dd35cf5..deca1aa2bb 100644
--- a/doc/internal/man3/ossl_cmp_statusinfo_new.pod
+++ b/doc/internal/man3/ossl_cmp_pkisi_get_status.pod
@@ -2,13 +2,11 @@
 
 =head1 NAME
 
-ossl_cmp_statusinfo_new,
-ossl_cmp_pkisi_pkistatus_get,
-ossl_cmp_pkisi_pkifailureinfo_get,
-ossl_cmp_pkisi_pkifailureinfo_check,
-ossl_cmp_pkisi_failinfo_get0,
-ossl_cmp_pkisi_statusstring_get0,
-ossl_pkisi_snprint
+ossl_cmp_pkisi_get_status,
+ossl_cmp_PKIStatus_to_string,
+ossl_cmp_pkisi_get0_statusString,
+ossl_cmp_pkisi_get_pkifailureinfo,
+ossl_cmp_pkisi_check_pkifailureinfo
 - functions for managing PKI status information
 
 =head1 SYNOPSIS
@@ -44,40 +42,27 @@ ossl_pkisi_snprint
 # define OSSL_CMP_PKIFAILUREINFO_duplicateCertReq    26
 # define OSSL_CMP_PKIFAILUREINFO_MAX                 26
 
-  OSSL_CMP_PKISI *ossl_cmp_statusinfo_new(int status, int fail_info,
-                                          const char *text);
-  int ossl_cmp_pkisi_pkistatus_get(OSSL_CMP_PKISI *si);
-  int ossl_cmp_pkisi_pkifailureinfo_get(OSSL_CMP_PKISI *si);
-  int ossl_cmp_pkisi_pkifailureinfo_check(OSSL_CMP_PKISI *si, int bit_index);
-  OSSL_CMP_PKIFAILUREINFO *ossl_cmp_pkisi_failinfo_get0(const OSSL_CMP_PKISI *si);
-  OSSL_CMP_PKIFREETEXT *ossl_cmp_pkisi_statusstring_get0(const OSSL_CMP_PKISI *si);
-  char *ossl_pkisi_snprint(OSSL_CMP_PKISI *si, char *buf, int bufsize);
+  int ossl_cmp_pkisi_get_status(const OSSL_CMP_PKISI *si);
+  const char *ossl_cmp_PKIStatus_to_string(int status);
+  OSSL_CMP_PKIFREETEXT *ossl_cmp_pkisi_get0_statusString(const OSSL_CMP_PKISI *si);
+  int ossl_cmp_pkisi_get_pkifailureinfo(const OSSL_CMP_PKISI *si);
+  int ossl_cmp_pkisi_check_pkifailureinfo(const OSSL_CMP_PKISI *si, int index);
 
 =head1 DESCRIPTION
 
-ossl_cmp_statusinfo_new() creates a new PKIStatusInfo structure and fills it
-with the given values. It sets the status field to B<status>.
-If B<text> is not NULL, it is copied to statusString.
-B<fail_info> is is interpreted as bit pattern for the failInfo field.
-Returns a pointer to the structure on success, or NULL on error.
+ossl_cmp_pkisi_get_status() returns the PKIStatus of B<si>, or -1 on error.
 
-ossl_cmp_pkisi_pkistatus_get() returns the PKIStatus of B<si>, or -1 on error.
+ossl_cmp_PKIStatus_to_string() returns a human-readable string representing
+the PKIStatus values as specified in RFC 4210, Appendix F.
 
-ossl_cmp_pkisi_pkifailureinfo_get() returns the PKIFailureInfo bits
-of B<si>, encoded as integer, or -1 on error.
-
-ossl_cmp_pkisi_pkifailureinfo_check() returns the state of the bit (0 or 1)
-with index B<bit_index> in the PKIFailureInfo of the B<si>, or -1 on error.
-
-ossl_cmp_pkisi_failinfo_get0() returns a direct pointer to the failInfo
-field contained in B<si>, or NULL on error.
-
-ossl_cmp_pkisi_statusstring_get0() returns a direct pointer to the statusString
+ossl_cmp_pkisi_get0_statusString() returns a direct pointer to the statusString
 field contained in B<si>.
 
-ossl_pkisi_snprint() places at max B<bufsize> characters of human-readable
-error string of B<si> in pre-allocated B<buf>. Returns pointer to the same
-B<buf> containing the string, or NULL on error.
+ossl_cmp_pkisi_get_pkifailureinfo() returns the PKIFailureInfo bits
+of B<si>, encoded as integer, or -1 on error.
+
+ossl_cmp_pkisi_check_pkifailureinfo() returns the state of the bit (0 or 1)
+with index B<index> in the PKIFailureInfo of the B<si>, or -1 on error.
 
 =head1 NOTES
 
diff --git a/doc/man3/OSSL_CMP_CTX_new.pod b/doc/man3/OSSL_CMP_CTX_new.pod
index b10cfc4801..032ef817c0 100644
--- a/doc/man3/OSSL_CMP_CTX_new.pod
+++ b/doc/man3/OSSL_CMP_CTX_new.pod
@@ -239,7 +239,7 @@ The following options can be set:
 
     OSSL_CMP_OPT_MAC_ALGNID
         The MAC algorithm NID to be used in RFC 4210's MSG_MAC_ALG,
-        if applicable used for message protection. 
+        if applicable used for message protection.
         Default is HMAC-SHA1 as per RFC 4210.
 
 =item B<OSSL_CMP_OPT_REVOCATION_REASON>
@@ -362,7 +362,6 @@ The transfer callback may make use of a custom defined argument stored in
 the ctx by means of OSSL_CMP_CTX_set_transfer_cb_arg(), which may be retrieved
 again through OSSL_CMP_CTX_get_transfer_cb_arg().
 
-
 OSSL_CMP_CTX_set_transfer_cb_arg() sets an argument, respectively a pointer to a
 structure containing arguments, optionally to be used by the transfer callback.
 B<arg> is not consumed, and it must therefore explicitly be freed when not
@@ -372,9 +371,9 @@ OSSL_CMP_CTX_get_transfer_cb_arg() gets the argument, respectively the pointer
 to a structure containing arguments, previously set by
 OSSL_CMP_CTX_set_transfer_cb_arg() or NULL if unset.
 
-OSSL_CMP_CTX_set1_srvCert() pins the server certificate to be directly trusted
-(even if it is expired) for verifying response messages.
-The cert pointer is not consumed. It may be NULL to clear the entry.
+OSSL_CMP_CTX_set1_srvCert() pins the given server certificate B<srvCert>
+directly trusts it (even if it is expired) for verifying response messages.
+The B<cert> argument may be NULL to clear the entry.
 
 OSSL_CMP_CTX_set1_expected_sender() sets the Distinguished Name (DN) expected to
 be given in the sender response for messages protected with MSG_SIG_ALG. This
@@ -384,8 +383,7 @@ identify the server certificate.
 This can be used to ensure that only a particular entity is accepted to act as
 CMP server, and attackers are not able to use arbitrary certificates of a
 trusted PKI hierarchy to fraudulently pose as server.
-This defaults to the subject DN of the certificate set via
-OSSL_CMP_CTX_set1_srvCert(), if any.
+This defaults to the subject of the B<srvCert>, if any.
 
 OSSL_CMP_CTX_set0_trustedStore() sets the X509_STORE type certificate store
 containing trusted (root) CA certificates. The certificate store may also hold
@@ -404,32 +402,52 @@ The reference counts of those certificates handled successfully are increased.
 OSSL_CMP_CTX_get0_untrusted_certs(OSSL_CMP_CTX *ctx) returns a pointer to the
 list of untrusted certs, which my be empty if unset.
 
-OSSL_CMP_CTX_set1_clCert() sets the client certificate in the given
-OSSL_CMP_CTX structure. The client certificate will then be used by the
-functions to set the "sender" field for outgoing messages and it will be
-included in the extraCerts field.
-
-OSSL_CMP_CTX_set1_pkey() sets the private key corresponding to the client
-certificate set with B<OSSL_CMP_CTX_set1_clCert()> in the given CMP context.
-Used to create the protection in case of MSG_SIG_ALG.
-
-OSSL_CMP_CTX_set1_referenceValue() sets the given referenceValue in the given
-B<ctx> or clears it if the B<ref> argument is NULL.
-
-OSSL_CMP_CTX_set1_secretValue() sets the B<sec> with the length B<len> in the
-given B<ctx> or clears it if the B<sec> argument is NULL.
+OSSL_CMP_CTX_set1_clCert() sets the client certificate in the given B<ctx>.
+The public key of this B<clCert> must correspond to
+the private key set via B<OSSL_CMP_CTX_set1_pkey()>.
+When using signature-based protection of CMP request messages
+this "protection certificate" will be included first in the extraCerts field.
+The subject of this B<clCert> will be used as the "sender" field
+of outgoing CMP messages, with the fallback being
+the B<subjectName> set via B<OSSL_CMP_CTX_set1_subjectName()>.
+The B<cert> argument may be NULL to clear the entry.
+
+OSSL_CMP_CTX_set1_pkey() sets the private key corresponding to
+the client certificate B<clCert> set via B<OSSL_CMP_CTX_set1_clCert()>.
+This key is used create signature-based protection (protectionAlg = MSG_SIG_ALG)
+of outgoing messages
+unless a PBM secret has been set via  B<OSSL_CMP_CTX_set1_secretValue()>.
+The B<pkey> argument may be NULL to clear the entry.
+
+OSSL_CMP_CTX_set1_secretValue() sets the byte string B<sec> with length B<len>
+as PBM secret in the given B<ctx> or clears it if the B<sec> argument is NULL.
+If present, this secret is used to create PBM-based protection of outgoing
+messages and to verify any PBM-based protection of incoming messages
+(protectionAlg = MSG_MAC_ALG). PBM stands for Password-Based MAC.
+PBM-based protection takes precedence over signature-based protection.
+
+OSSL_CMP_CTX_set1_referenceValue() sets the given referenceValue B<ref> with
+length B<len> in the given B<ctx> or clears it if the B<ref> argument is NULL.
+According to RFC 4210 section 5.1.1, if no value for the "sender" field in
+CMP message headers can be determined (i.e., no B<clCert> and no B<subjectName>
+is given) then the "sender" field will contain the NULL-DN
+and the senderKID field of the CMP message header must be set.
+When signature-based protection is used the senderKID will be set to
+the subjectKeyIdentifier of the <clCert> as far as present.
+If not present or when PBM-based protection is used
+the B<ref> value is taken as the fallback value for the senderKID.
 
 OSSL_CMP_CTX_set1_recipient() sets the recipient name that will be used in the
 PKIHeader of a request message, i.e. the X509 name of the (CA) server.
-Setting is overruled by subject of srvCert if set.
-If neither srvCert nor recipient are set, the recipient of the PKI message is
+Setting is overruled by subject of B<srvCert> if set.
+If neither B<srvCert> nor recipient are set, the recipient of the PKI message is
 determined in the following order: issuer, issuer of old cert (oldCert),
-issuer of client cert (clCert), else NULL-DN.
+issuer of client cert (B<clCert>), else NULL-DN.
 When a response is received, its sender must match the recipient of the request.
 
 OSSL_CMP_CTX_push0_geninfo_ITAV() adds B<itav> to the stack in the B<ctx> to be
 added to the GeneralInfo field of the CMP PKIMessage header of a request
-message sent with this context.  Consumes the pointer to B<itav>.
+message sent with this context.
 
 OSSL_CMP_CTX_set1_extraCertsOut() sets the stack of extraCerts that will be
 sent to remote.
@@ -450,24 +468,22 @@ will be set in the CertTemplate, i.e., the X509 name of the CA server.
 
 OSSL_CMP_CTX_set1_subjectName() sets the subject DN that will be used in
 the CertTemplate structure when requesting a new cert. For Key Update Requests
-(KUR), it defaults to the subject DN of the reference certificate,
+(KUR), it defaults to the subject DN of the B<reference certificate>,
 see B<OSSL_CMP_CTX_set1_oldCert()>. This default is used for Initialization
 Requests (IR) and Certification Requests (CR) only if no SANs are set.
-
-If clCert is not set (e.g. in case of IR with MSG_MAC_ALG), the subject DN
-is also used as sender of the PKI message.
+The B<subjectName> is also used as the "sender" field for outgoing CMP messages
+if no B<clCert> has been set (e.g., in case requests are protected using PBM).
 
 OSSL_CMP_CTX_push1_subjectAltName() adds the given X509 name to the list of
 alternate names on the certificate template request. This cannot be used if
 any Subject Alternative Name extension is set via
 OSSL_CMP_CTX_set0_reqExtensions().
 By default, unless OSSL_CMP_OPT_SUBJECTALTNAME_NODEFAULT has been set,
-the Subject Alternative Names are copied from the reference certificate,
-see OSSL_CMP_CTX_set1_oldCert().
-
+the Subject Alternative Names are copied from the B<reference certificate>,
+see B<OSSL_CMP_CTX_set1_oldCert()>.
 If set and the subject DN is not set with OSSL_CMP_CTX_set1_subjectName(), then
 the certificate template of an IR and CR will not be filled with the default
-subject DN from the reference certificate (see OSSL_CMP_CTX_set1_oldCert().
+subject DN from the B<reference certificate>.
 If a subject DN is desired it needs to be set explicitly with
 OSSL_CMP_CTX_set1_subjectName().
 
@@ -483,7 +499,7 @@ to the X509_EXTENSIONS of the requested certificate template.
 OSSL_CMP_CTX_set1_oldCert() sets the old certificate to be updated in
 Key Update Requests (KUR) or to be revoked in Revocation Requests (RR).
 It must be given for RR, else it defaults to B<clCert>.
-The reference certificate determined in this way, if any, is also used for
+The B<reference certificate> determined in this way, if any, is also used for
 deriving default subject DN and Subject Alternative Names for IR, CR, and KUR.
 Its issuer, if any, is used as default recipient in the CMP message header.
 
@@ -491,7 +507,6 @@ OSSL_CMP_CTX_set1_p10CSR() sets the PKCS#10 CSR to be used in P10CR.
 
 OSSL_CMP_CTX_push0_genm_ITAV() adds B<itav> to the stack in the B<ctx> which
 will be the body of a General Message sent with this context.
-Consumes the pointer to B<itav>.
 
 OSSL_CMP_CTX_set_certConf_cb() sets the callback used for evaluating the newly
 enrolled certificate before the library sends, depending on its result,
diff --git a/doc/man3/OSSL_CMP_CTX_snprint_PKIStatus.pod b/doc/man3/OSSL_CMP_CTX_snprint_PKIStatus.pod
deleted file mode 100644
index 3ae6831ee2..0000000000
--- a/doc/man3/OSSL_CMP_CTX_snprint_PKIStatus.pod
+++ /dev/null
@@ -1,46 +0,0 @@
-=pod
-
-=head1 NAME
-
-OSSL_CMP_CTX_snprint_PKIStatus
-- function(s) for managing the CMP PKIStatus
-
-=head1 SYNOPSIS
-
- #include <openssl/cmp.h>
-
- char *OSSL_CMP_CTX_snprint_PKIStatus(OSSL_CMP_CTX *ctx, char *buf, int bufsize);
-
-=head1 DESCRIPTION
-
-This is the PKIStatus API for using CMP (Certificate Management Protocol) with
-OpenSSL.
-
-OSSL_CMP_CTX_snprint_PKIStatus() takes the PKIStatusInfo components contained
-in the given CMP context and places a human-readable string created from them
-in the given buffer, with the given maximal length.
-On success it returns a copy of the buffer pointer containing the string.
-
-=head1 NOTES
-
-CMP is defined in RFC 4210 (and CRMF in RFC 4211).
-
-=head1 RETURN VALUES
-
-OSSL_CMP_CTX_snprint_PKIStatus()
-returns the intended pointer value as described above or NULL on error.
-
-=head1 HISTORY
-
-The OpenSSL CMP support was added in OpenSSL 3.0.
-
-=head1 COPYRIGHT
-
-Copyright 2007-2019 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/OSSL_CMP_MSG_get0_header.pod b/doc/man3/OSSL_CMP_MSG_get0_header.pod
index 3ed1140082..cee99cd00b 100644
--- a/doc/man3/OSSL_CMP_MSG_get0_header.pod
+++ b/doc/man3/OSSL_CMP_MSG_get0_header.pod
@@ -2,7 +2,9 @@
 
 =head1 NAME
 
-OSSL_CMP_MSG_get0_header
+OSSL_CMP_MSG_get0_header,
+OSSL_d2i_CMP_MSG_bio,
+OSSL_i2d_CMP_MSG_bio
 - function(s) manipulating CMP messages
 
 =head1 SYNOPSIS
@@ -10,20 +12,31 @@ OSSL_CMP_MSG_get0_header
   #include <openssl/cmp.h>
 
   OSSL_CMP_PKIHEADER *OSSL_CMP_MSG_get0_header(const OSSL_CMP_MSG *msg);
+  OSSL_CMP_MSG *OSSL_d2i_CMP_MSG_bio(BIO *bio, OSSL_CMP_MSG **msg);
+  int OSSL_i2d_CMP_MSG_bio(BIO *bio, const OSSL_CMP_MSG *msg);
 
 =head1 DESCRIPTION
 
 OSSL_CMP_MSG_get0_header returns the header of the given CMP message.
 
+OSSL_d2i_CMP_MSG_bio parses an ASN.1-encoded OSSL_CMP_MSG from the BIO I<bio>.
+It assigns a pointer to the new structure to I<*msg> if I<msg> is not NULL.
+
+OSSL_i2d_CMP_MSG_bio writes the OSSL_CMP_MSG I<msg> in ASN.1 encoding to BIO I<bio>.
+
 =head1 NOTES
 
 CMP is defined in RFC 4210.
 
 =head1 RETURN VALUES
 
-CMP_MSG_get0_header() returns the intended pointer value as described above
+OSSL_CMP_MSG_get0_header() returns the intended pointer value as described above
 or NULL if the respective entry does not exist and on error.
 
+OSSL_d2i_CMP_MSG_bio() returns the parsed message or NULL on error.
+
+OSSL_i2d_CMP_MSG_bio() returns 1 on success or 0 on error.
+
 =head1 HISTORY
 
 The OpenSSL CMP support was added in OpenSSL 3.0.
diff --git a/doc/man3/OSSL_CMP_SRV_CTX_new.pod b/doc/man3/OSSL_CMP_SRV_CTX_new.pod
new file mode 100644
index 0000000000..45ac0174b7
--- /dev/null
+++ b/doc/man3/OSSL_CMP_SRV_CTX_new.pod
@@ -0,0 +1,159 @@
+=pod
+
+=head1 NAME
+
+OSSL_CMP_SRV_process_request,
+OSSL_CMP_CTX_server_perform,
+OSSL_CMP_SRV_CTX_new,
+OSSL_CMP_SRV_CTX_free,
+OSSL_CMP_SRV_cert_request_cb_t,
+OSSL_CMP_SRV_rr_cb_t,
+OSSL_CMP_SRV_certConf_cb_t,
+OSSL_CMP_SRV_genm_cb_t,
+OSSL_CMP_SRV_error_cb_t,
+OSSL_CMP_SRV_pollReq_cb_t,
+OSSL_CMP_SRV_CTX_init,
+OSSL_CMP_SRV_CTX_get0_cmp_ctx,
+OSSL_CMP_SRV_CTX_get0_custom_ctx,
+OSSL_CMP_SRV_CTX_set_send_unprotected_errors,
+OSSL_CMP_SRV_CTX_set_accept_unprotected,
+OSSL_CMP_SRV_CTX_set_accept_raverified,
+OSSL_CMP_SRV_CTX_set_grant_implicit_confirm
+- generic functions to set up and control a CMP server
+
+=head1 SYNOPSIS
+
+ #include <openssl/cmp.h>
+
+ OSSL_CMP_MSG *OSSL_CMP_SRV_process_request(OSSL_CMP_SRV_CTX *srv_ctx,
+                                            const OSSL_CMP_MSG *req);
+ OSSL_CMP_MSG *OSSL_CMP_CTX_server_perform(OSSL_CMP_CTX *client_ctx,
+                                           const OSSL_CMP_MSG *req);
+ OSSL_CMP_SRV_CTX *OSSL_CMP_SRV_CTX_new(void);
+ void OSSL_CMP_SRV_CTX_free(OSSL_CMP_SRV_CTX *srv_ctx);
+
+ typedef OSSL_CMP_PKISI *(*OSSL_CMP_SRV_cert_request_cb_t)(
+                                                 OSSL_CMP_SRV_CTX *srv_ctx,
+                                                 const OSSL_CMP_MSG *req,
+                                                 int certReqId,
+                                                 const OSSL_CRMF_MSG *crm,
+                                                 const X509_REQ *p10cr,
+                                                 X509 **certOut,
+                                                 STACK_OF(X509) **chainOut,
+                                                 STACK_OF(X509) **caPubs);
+ typedef OSSL_CMP_PKISI *(*OSSL_CMP_SRV_rr_cb_t)(OSSL_CMP_SRV_CTX *srv_ctx,
+                                                 const OSSL_CMP_MSG *req,
+                                                 const X509_NAME *issuer,
+                                                 const ASN1_INTEGER *serial);
+ typedef int (*OSSL_CMP_SRV_genm_cb_t)(OSSL_CMP_SRV_CTX *srv_ctx,
+                                       const OSSL_CMP_MSG *req,
+                                       STACK_OF(OSSL_CMP_ITAV) *in,
+                                       STACK_OF(OSSL_CMP_ITAV) **out);
+ typedef void (*OSSL_CMP_SRV_error_cb_t)(OSSL_CMP_SRV_CTX *srv_ctx,
+                                         const OSSL_CMP_MSG *req,
+                                         const OSSL_CMP_PKISI *statusInfo,
+                                         const ASN1_INTEGER *errorCode,
+                                         const OSSL_CMP_PKIFREETEXT *errorDetails);
+ typedef int (*OSSL_CMP_SRV_certConf_cb_t)(OSSL_CMP_SRV_CTX *srv_ctx,
+                                           const OSSL_CMP_MSG *req,
+                                           int certReqId,
+                                           const ASN1_OCTET_STRING *certHash,
+                                           const OSSL_CMP_PKISI *si);
+ typedef int (*OSSL_CMP_SRV_pollReq_cb_t)(OSSL_CMP_SRV_CTX *srv_ctx,
+                                          const OSSL_CMP_MSG *req,
+                                          int certReqId,
+                                          OSSL_CMP_MSG **certReq,
+                                          int64_t *check_after);
+ int OSSL_CMP_SRV_CTX_init(OSSL_CMP_SRV_CTX *srv_ctx, void *custom_ctx,
+                           OSSL_CMP_SRV_cert_request_cb_t process_cert_request,
+                           OSSL_CMP_SRV_rr_cb_t process_rr,
+                           OSSL_CMP_SRV_genm_cb_t process_genm,
+                           OSSL_CMP_SRV_error_cb_t process_error,
+                           OSSL_CMP_SRV_certConf_cb_t process_certConf,
+                           OSSL_CMP_SRV_pollReq_cb_t process_pollReq);
+
+ OSSL_CMP_CTX *OSSL_CMP_SRV_CTX_get0_cmp_ctx(const OSSL_CMP_SRV_CTX *srv_ctx);
+ void *OSSL_CMP_SRV_CTX_get0_custom_ctx(const OSSL_CMP_SRV_CTX *srv_ctx);
+
+ int OSSL_CMP_SRV_CTX_set_send_unprotected_errors(OSSL_CMP_SRV_CTX *srv_ctx,
+                                                  int val);
+ int OSSL_CMP_SRV_CTX_set_accept_unprotected(OSSL_CMP_SRV_CTX *srv_ctx, int val);
+ int OSSL_CMP_SRV_CTX_set_accept_raverified(OSSL_CMP_SRV_CTX *srv_ctx, int val);
+ int OSSL_CMP_SRV_CTX_set_grant_implicit_confirm(OSSL_CMP_SRV_CTX *srv_ctx,
+                                                 int val);
+
+=head1 DESCRIPTION
+
+OSSL_CMP_SRV_process_request() implements the generic aspects of a CMP server.
+It does the typical generic checks on the given request message, calls
+the respective callback function (if present) for more specific processing,
+and then assembles a result message, which may be a CMP error message.
+
+OSSL_CMP_CTX_server_perform() is an interface to
+B<OSSL_CMP_SRV_process_request()> that can be used by a CMP client
+in the same way as B<OSSL_CMP_MSG_http_perform()>.
+The B<OSSL_CMP_SRV_CTX> must be set as B<transfer_cb_arg> of B<client_ctx>.
+
+OSSL_CMP_SRV_CTX_new() creates and initializes an OSSL_CMP_SRV_CTX structure
+and returns a pointer to it on success, NULL on error.
+
+OSSL_CMP_SRV_CTX_free() deletes the given B<srv_ctx>.
+
+OSSL_CMP_SRV_CTX_init() sets in the given B<srv_ctx> a custom server context
+pointer as well as callback functions performing the specific processing of CMP
+certificate requests, revocation requests, certificate confirmation requests,
+general messages, error messages, and poll requests.
+All arguments except B<srv_ctx> may be NULL.
+If a callback for some message type is not given this means that the respective
+type of CMP message is not supported by the server.
+
+OSSL_CMP_SRV_CTX_get0_cmp_ctx() returns the B<OSSL_CMP_CTX> from the B<srv_ctx>.
+
+OSSL_CMP_SRV_CTX_get0_custom_ctx() returns the custom server context from
+B<srv_ctx> that has been set using B<OSSL_CMP_SRV_CTX_init>.
+
+OSSL_CMP_SRV_CTX_set_send_unprotected_errors() enables sending error messages
+and other forms of negative responses unprotected.
+
+OSSL_CMP_SRV_CTX_set_accept_unprotected() enables acceptance of requests
+without protection of with invalid protection.
+
+OSSL_CMP_SRV_CTX_set_accept_raverified() enables acceptance of ir/cr/kur
+messages with POPO 'RAVerified'.
+
+OSSL_CMP_SRV_CTX_set_grant_implicit_confirm() enables granting implicit
+confirmation of newly enrolled certificates if requested.
+
+=head1 NOTES
+
+CMP is defined in RFC 4210 (and CRMF in RFC 4211).
+
+=head1 RETURN VALUES
+
+OSSL_CMP_SRV_CTX_new() returns a B<OSSL_CMP_SRV_CTX> structure on success,
+NULL on error.
+
+OSSL_CMP_SRV_CTX_free() does not return a value.
+
+OSSL_CMP_SRV_CTX_get0_cmp_ctx() returns a B<OSSL_CMP_CTX> structure on success,
+NULL on error.
+
+OSSL_CMP_SRV_CTX_get0_custom_ctx() returns the custom server context
+that has been set using B<OSSL_CMP_SRV_CTX_init>.
+
+All other functions return 1 on success, 0 on error.
+
+=head1 HISTORY
+
+The OpenSSL CMP support was added in OpenSSL 3.0.
+
+=head1 COPYRIGHT
+
+Copyright 2007-2019 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/OSSL_CMP_STATUSINFO_new.pod b/doc/man3/OSSL_CMP_STATUSINFO_new.pod
new file mode 100644
index 0000000000..520a104d7e
--- /dev/null
+++ b/doc/man3/OSSL_CMP_STATUSINFO_new.pod
@@ -0,0 +1,66 @@
+=pod
+
+=head1 NAME
+
+OSSL_CMP_STATUSINFO_new,
+OSSL_CMP_snprint_PKIStatusInfo,
+OSSL_CMP_CTX_snprint_PKIStatus
+- function(s) for managing the CMP PKIStatus
+
+=head1 SYNOPSIS
+
+ #include <openssl/cmp.h>
+
+ OSSL_CMP_PKISI *OSSL_CMP_STATUSINFO_new(int status, int fail_info,
+                                         const char *text);
+ char *OSSL_CMP_snprint_PKIStatusInfo(const OSSL_CMP_PKISI *statusInfo,
+                                      char *buf, size_t bufsize);
+ char *OSSL_CMP_CTX_snprint_PKIStatus(const OSSL_CMP_CTX *ctx, char *buf,
+                                      size_t bufsize);
+
+=head1 DESCRIPTION
+
+This is the PKIStatus API for using CMP (Certificate Management Protocol) with
+OpenSSL.
+
+OSSL_CMP_STATUSINFO_new() creates a new PKIStatusInfo structure
+and fills in the given values.
+It sets the status field to B<status>,
+copies B<text> (unless it is NULL) to statusString,
+and interprets B<fail_info> as bit pattern for the failInfo field.
+
+OSSL_CMP_snprint_PKIStatusInfo() places a human-readable string
+representing the given statusInfo
+in the given buffer, with the given maximal length.
+
+OSSL_CMP_CTX_snprint_PKIStatus() places a human-readable string
+representing the PKIStatusInfo components of the CMP context B<ctx>
+in the given buffer, with the given maximal length.
+
+=head1 NOTES
+
+CMP is defined in RFC 4210 (and CRMF in RFC 4211).
+
+=head1 RETURN VALUES
+
+OSSL_CMP_STATUSINFO_new()
+returns a pointer to the structure on success, or NULL on error.
+
+OSSL_CMP_snprint_PKIStatusInfo() and
+OSSL_CMP_CTX_snprint_PKIStatus()
+return a copy of the buffer pointer containing the string or NULL on error.
+
+=head1 HISTORY
+
+The OpenSSL CMP support was added in OpenSSL 3.0.
+
+=head1 COPYRIGHT
+
+Copyright 2007-2019 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/X509_digest.pod b/doc/man3/X509_digest.pod
index 52eb522b36..dfddd12e10 100644
--- a/doc/man3/X509_digest.pod
+++ b/doc/man3/X509_digest.pod
@@ -2,7 +2,9 @@
 
 =head1 NAME
 
-X509_digest, X509_CRL_digest,
+X509_digest,
+X509_digest_sig,
+X509_CRL_digest,
 X509_pubkey_digest,
 X509_NAME_digest,
 X509_REQ_digest,
@@ -15,6 +17,7 @@ PKCS7_ISSUER_AND_SERIAL_digest
 
  int X509_digest(const X509 *data, const EVP_MD *type, unsigned char *md,
                  unsigned int *len);
+ ASN1_OCTET_STRING *X509_digest_sig(const X509 *cert);
 
  int X509_CRL_digest(const X509_CRL *data, const EVP_MD *type, unsigned char *md,
                      unsigned int *len);
@@ -36,8 +39,12 @@ PKCS7_ISSUER_AND_SERIAL_digest
 
 =head1 DESCRIPTION
 
+X509_digest_sig() calculates a digest of the given certificate
+using the same hash algorithm as in its signature.
+
 X509_pubkey_digest() returns a digest of the DER representation of the public
 key in the specified X509 B<data> object.
+
 All other functions described here return a digest of the DER representation
 of their entire B<data> objects.
 
@@ -49,12 +56,18 @@ to a place where the digest size will be stored.
 
 =head1 RETURN VALUES
 
-All functions described here return 1 for success and 0 for failure.
+X509_digest_sig() returns an ASN1_OCTET_STRING on success, else NULL.
+
+All other functions described here return 1 for success and 0 for failure.
 
 =head1 SEE ALSO
 
 L<EVP_sha1(3)>
 
+=head1 HISTORY
+
+The X509_digest_sig() function was added in OpenSSL 3.0.
+
 =head1 COPYRIGHT
 
 Copyright 2017-2018 The OpenSSL Project Authors. All Rights Reserved.
diff --git a/doc/man3/X509_dup.pod b/doc/man3/X509_dup.pod
index d7d8477896..cb1e9edf2c 100644
--- a/doc/man3/X509_dup.pod
+++ b/doc/man3/X509_dup.pod
@@ -122,13 +122,17 @@ OCSP_SIGNATURE_free,
 OCSP_SIGNATURE_new,
 OCSP_SINGLERESP_free,
 OCSP_SINGLERESP_new,
+OSSL_CMP_ITAV_dup,
 OSSL_CMP_ITAV_free,
+OSSL_CMP_MSG_dup,
 OSSL_CMP_MSG_it,
 OSSL_CMP_MSG_free,
 OSSL_CMP_PKIHEADER_free,
 OSSL_CMP_PKIHEADER_it,
 OSSL_CMP_PKIHEADER_new,
+OSSL_CMP_PKISI_dup,
 OSSL_CMP_PKISI_free,
+OSSL_CMP_PKISI_it,
 OSSL_CMP_PKISI_new,
 OSSL_CMP_PKISTATUS_it,
 OSSL_CRMF_CERTID_free,
diff --git a/doc/man3/d2i_X509.pod b/doc/man3/d2i_X509.pod
index d41d2e0c4b..354757387f 100644
--- a/doc/man3/d2i_X509.pod
+++ b/doc/man3/d2i_X509.pod
@@ -98,6 +98,7 @@ d2i_OCSP_SIGNATURE,
 d2i_OCSP_SINGLERESP,
 d2i_OSSL_CMP_MSG,
 d2i_OSSL_CMP_PKIHEADER,
+d2i_OSSL_CMP_PKISI,
 d2i_OSSL_CRMF_CERTID,
 d2i_OSSL_CRMF_CERTTEMPLATE,
 d2i_OSSL_CRMF_ENCRYPTEDVALUE,
@@ -289,6 +290,7 @@ i2d_OCSP_SIGNATURE,
 i2d_OCSP_SINGLERESP,
 i2d_OSSL_CMP_MSG,
 i2d_OSSL_CMP_PKIHEADER,
+i2d_OSSL_CMP_PKISI,
 i2d_OSSL_CRMF_CERTID,
 i2d_OSSL_CRMF_CERTTEMPLATE,
 i2d_OSSL_CRMF_ENCRYPTEDVALUE,
diff --git a/include/internal/cryptlib.h b/include/internal/cryptlib.h
index 7ad6007fd9..19e2c9744e 100644
--- a/include/internal/cryptlib.h
+++ b/include/internal/cryptlib.h
@@ -23,6 +23,7 @@
 # include <openssl/crypto.h>
 # include <openssl/buffer.h>
 # include <openssl/bio.h>
+# include <openssl/asn1.h>
 # include <openssl/err.h>
 # include "internal/nelem.h"
 
@@ -234,5 +235,7 @@ static ossl_inline void ossl_sleep(unsigned long millis)
 }
 #endif /* defined OPENSSL_SYS_UNIX */
 
+char *sk_ASN1_UTF8STRING2text(STACK_OF(ASN1_UTF8STRING) *text, const char *sep,
+                              size_t max_len);
 
 #endif
diff --git a/include/openssl/cmp.h b/include/openssl/cmp.h
index 43dcc69993..54e756c501 100644
--- a/include/openssl/cmp.h
+++ b/include/openssl/cmp.h
@@ -207,13 +207,17 @@ typedef struct ossl_cmp_ctx_st OSSL_CMP_CTX;
 typedef struct ossl_cmp_pkiheader_st OSSL_CMP_PKIHEADER;
 DECLARE_ASN1_FUNCTIONS(OSSL_CMP_PKIHEADER)
 typedef struct ossl_cmp_msg_st OSSL_CMP_MSG;
+DECLARE_ASN1_DUP_FUNCTION(OSSL_CMP_MSG)
 DECLARE_ASN1_ENCODE_FUNCTIONS(OSSL_CMP_MSG, OSSL_CMP_MSG, OSSL_CMP_MSG)
 typedef struct ossl_cmp_certstatus_st OSSL_CMP_CERTSTATUS;
 DEFINE_STACK_OF(OSSL_CMP_CERTSTATUS)
 typedef struct ossl_cmp_itav_st OSSL_CMP_ITAV;
+DECLARE_ASN1_DUP_FUNCTION(OSSL_CMP_ITAV)
 DEFINE_STACK_OF(OSSL_CMP_ITAV)
 typedef struct ossl_cmp_revrepcontent_st OSSL_CMP_REVREPCONTENT;
 typedef struct ossl_cmp_pkisi_st OSSL_CMP_PKISI;
+DECLARE_ASN1_FUNCTIONS(OSSL_CMP_PKISI)
+DECLARE_ASN1_DUP_FUNCTION(OSSL_CMP_PKISI)
 DEFINE_STACK_OF(OSSL_CMP_PKISI)
 typedef struct ossl_cmp_certrepmessage_st OSSL_CMP_CERTREPMESSAGE;
 DEFINE_STACK_OF(OSSL_CMP_CERTREPMESSAGE)
@@ -272,9 +276,9 @@ void OSSL_CMP_CTX_print_errors(OSSL_CMP_CTX *ctx);
 int OSSL_CMP_CTX_set1_serverPath(OSSL_CMP_CTX *ctx, const char *path);
 int OSSL_CMP_CTX_set1_serverName(OSSL_CMP_CTX *ctx, const char *name);
 int OSSL_CMP_CTX_set_serverPort(OSSL_CMP_CTX *ctx, int port);
+#  define OSSL_CMP_DEFAULT_PORT 80
 int OSSL_CMP_CTX_set1_proxyName(OSSL_CMP_CTX *ctx, const char *name);
 int OSSL_CMP_CTX_set_proxyPort(OSSL_CMP_CTX *ctx, int port);
-#  define OSSL_CMP_DEFAULT_PORT 80
 int OSSL_CMP_CTX_set_http_cb(OSSL_CMP_CTX *ctx, OSSL_HTTP_bio_cb_t cb);
 int OSSL_CMP_CTX_set_http_cb_arg(OSSL_CMP_CTX *ctx, void *arg);
 void *OSSL_CMP_CTX_get_http_cb_arg(const OSSL_CMP_CTX *ctx);
@@ -329,32 +333,85 @@ int OSSL_CMP_CTX_get_failInfoCode(const OSSL_CMP_CTX *ctx);
 X509 *OSSL_CMP_CTX_get0_newCert(const OSSL_CMP_CTX *ctx);
 STACK_OF(X509) *OSSL_CMP_CTX_get1_caPubs(const OSSL_CMP_CTX *ctx);
 STACK_OF(X509) *OSSL_CMP_CTX_get1_extraCertsIn(const OSSL_CMP_CTX *ctx);
-/* support application-level CMP debugging in cmp.c: */
 int OSSL_CMP_CTX_set1_transactionID(OSSL_CMP_CTX *ctx,
                                     const ASN1_OCTET_STRING *id);
 int OSSL_CMP_CTX_set1_senderNonce(OSSL_CMP_CTX *ctx,
                                   const ASN1_OCTET_STRING *nonce);
 
 /* from cmp_status.c */
-char *OSSL_CMP_CTX_snprint_PKIStatus(OSSL_CMP_CTX *ctx, char *buf,
+char *OSSL_CMP_CTX_snprint_PKIStatus(const OSSL_CMP_CTX *ctx, char *buf,
                                      size_t bufsize);
+char *OSSL_CMP_snprint_PKIStatusInfo(const OSSL_CMP_PKISI *statusInfo,
+                                     char *buf, size_t bufsize);
+OSSL_CMP_PKISI *
+OSSL_CMP_STATUSINFO_new(int status, int fail_info, const char *text);
 
 /* from cmp_hdr.c */
-/* support application-level CMP debugging in cmp.c: */
 ASN1_OCTET_STRING *OSSL_CMP_HDR_get0_transactionID(const OSSL_CMP_PKIHEADER *hdr);
 ASN1_OCTET_STRING *OSSL_CMP_HDR_get0_recipNonce(const OSSL_CMP_PKIHEADER *hdr);
 
 /* from cmp_msg.c */
-/* support application-level CMP debugging in cmp.c: */
 OSSL_CMP_PKIHEADER *OSSL_CMP_MSG_get0_header(const OSSL_CMP_MSG *msg);
+OSSL_CMP_MSG *OSSL_d2i_CMP_MSG_bio(BIO *bio, OSSL_CMP_MSG **msg);
+int OSSL_i2d_CMP_MSG_bio(BIO *bio, const OSSL_CMP_MSG *msg);
 
 /* from cmp_vfy.c */
 int OSSL_CMP_validate_msg(OSSL_CMP_CTX *ctx, const OSSL_CMP_MSG *msg);
 int OSSL_CMP_validate_cert_path(OSSL_CMP_CTX *ctx,
                                 X509_STORE *trusted_store, X509 *cert);
 
+/* from cmp_server.c */
+typedef struct ossl_cmp_srv_ctx_st OSSL_CMP_SRV_CTX;
+OSSL_CMP_MSG *OSSL_CMP_SRV_process_request(OSSL_CMP_SRV_CTX *srv_ctx,
+                                           const OSSL_CMP_MSG *req);
+OSSL_CMP_MSG * OSSL_CMP_CTX_server_perform(OSSL_CMP_CTX *client_ctx,
+                                           const OSSL_CMP_MSG *req);
+OSSL_CMP_SRV_CTX *OSSL_CMP_SRV_CTX_new(void);
+void OSSL_CMP_SRV_CTX_free(OSSL_CMP_SRV_CTX *srv_ctx);
+typedef OSSL_CMP_PKISI *(*OSSL_CMP_SRV_cert_request_cb_t)
+    (OSSL_CMP_SRV_CTX *srv_ctx, const OSSL_CMP_MSG *req, int certReqId,
+     const OSSL_CRMF_MSG *crm, const X509_REQ *p10cr,
+     X509 **certOut, STACK_OF(X509) **chainOut, STACK_OF(X509) **caPubs);
+typedef OSSL_CMP_PKISI *(*OSSL_CMP_SRV_rr_cb_t)(OSSL_CMP_SRV_CTX *srv_ctx,
+                                                const OSSL_CMP_MSG *req,
+                                                const X509_NAME *issuer,
+                                                const ASN1_INTEGER *serial);
+typedef int (*OSSL_CMP_SRV_genm_cb_t)(OSSL_CMP_SRV_CTX *srv_ctx,
+                                      const OSSL_CMP_MSG *req,
+                                      const STACK_OF(OSSL_CMP_ITAV) *in,
+                                      STACK_OF(OSSL_CMP_ITAV) **out);
+typedef void (*OSSL_CMP_SRV_error_cb_t)(OSSL_CMP_SRV_CTX *srv_ctx,
+                                        const OSSL_CMP_MSG *req,
+                                        const OSSL_CMP_PKISI *statusInfo,
+                                        const ASN1_INTEGER *errorCode,
+                                        const OSSL_CMP_PKIFREETEXT *errorDetails);
+typedef int (*OSSL_CMP_SRV_certConf_cb_t)(OSSL_CMP_SRV_CTX *srv_ctx,
+                                          const OSSL_CMP_MSG *req,
+                                          int certReqId,
+                                          const ASN1_OCTET_STRING *certHash,
+                                          const OSSL_CMP_PKISI *si);
+typedef int (*OSSL_CMP_SRV_pollReq_cb_t)(OSSL_CMP_SRV_CTX *srv_ctx,
+                                         const OSSL_CMP_MSG *req, int certReqId,
+                                         OSSL_CMP_MSG **certReq,
+                                         int64_t *check_after);
+int OSSL_CMP_SRV_CTX_init(OSSL_CMP_SRV_CTX *srv_ctx, void *custom_ctx,
+                          OSSL_CMP_SRV_cert_request_cb_t process_cert_request,
+                          OSSL_CMP_SRV_rr_cb_t process_rr,
+                          OSSL_CMP_SRV_genm_cb_t process_genm,
+                          OSSL_CMP_SRV_error_cb_t process_error,
+                          OSSL_CMP_SRV_certConf_cb_t process_certConf,
+                          OSSL_CMP_SRV_pollReq_cb_t process_pollReq);
+OSSL_CMP_CTX *OSSL_CMP_SRV_CTX_get0_cmp_ctx(const OSSL_CMP_SRV_CTX *srv_ctx);
+void *OSSL_CMP_SRV_CTX_get0_custom_ctx(const OSSL_CMP_SRV_CTX *srv_ctx);
+int OSSL_CMP_SRV_CTX_set_send_unprotected_errors(OSSL_CMP_SRV_CTX *srv_ctx,
+                                                 int val);
+int OSSL_CMP_SRV_CTX_set_accept_unprotected(OSSL_CMP_SRV_CTX *srv_ctx, int val);
+int OSSL_CMP_SRV_CTX_set_accept_raverified(OSSL_CMP_SRV_CTX *srv_ctx, int val);
+int OSSL_CMP_SRV_CTX_set_grant_implicit_confirm(OSSL_CMP_SRV_CTX *srv_ctx,
+                                                int val);
+
 #  ifdef  __cplusplus
 }
 #  endif
-# endif /* !defined OPENSSL_NO_CMP */
-#endif /* !defined OPENSSL_CMP_H */
+# endif /* !defined(OPENSSL_NO_CMP) */
+#endif /* !defined(OPENSSL_CMP_H) */
diff --git a/include/openssl/cmp_util.h b/include/openssl/cmp_util.h
index 56fb49e188..6b6025b6ce 100644
--- a/include/openssl/cmp_util.h
+++ b/include/openssl/cmp_util.h
@@ -50,5 +50,5 @@ void OSSL_CMP_print_errors_cb(OSSL_cmp_log_cb_t log_fn);
 #  ifdef  __cplusplus
 }
 #  endif
-# endif /* !defined OPENSSL_NO_CMP */
-#endif /* !defined OPENSSL_CMP_UTIL_H */
+# endif /* !defined(OPENSSL_NO_CMP) */
+#endif /* !defined(OPENSSL_CMP_UTIL_H) */
diff --git a/include/openssl/cmperr.h b/include/openssl/cmperr.h
index 51795a52ab..f868cc104f 100644
--- a/include/openssl/cmperr.h
+++ b/include/openssl/cmperr.h
@@ -1,6 +1,6 @@
 /*
  * Generated by util/mkerr.pl DO NOT EDIT
- * Copyright 1995-2019 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 1995-2020 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
@@ -19,7 +19,7 @@
 
 # ifndef OPENSSL_NO_CMP
 
-#  ifdef __cplusplus
+#  ifdef  __cplusplus
 extern "C"
 #  endif
 int ERR_load_CMP_strings(void);
@@ -27,16 +27,18 @@ int ERR_load_CMP_strings(void);
 /*
  * CMP function codes.
  */
-#  ifndef OPENSSL_NO_DEPRECATED_3_0
-#  endif
+# ifndef OPENSSL_NO_DEPRECATED_3_0
+# endif
 
 /*
  * CMP reason codes.
  */
 #  define CMP_R_ALGORITHM_NOT_SUPPORTED                    139
 #  define CMP_R_BAD_REQUEST_ID                             108
+#  define CMP_R_CERTHASH_UNMATCHED                         156
 #  define CMP_R_CERTID_NOT_FOUND                           109
 #  define CMP_R_CERTIFICATE_NOT_FOUND                      112
+#  define CMP_R_CERTREQMSG_NOT_FOUND                       157
 #  define CMP_R_CERTRESPONSE_NOT_FOUND                     113
 #  define CMP_R_CERT_AND_KEY_DO_NOT_MATCH                  114
 #  define CMP_R_ERROR_CALCULATING_PROTECTION               115
@@ -52,8 +54,11 @@ int ERR_load_CMP_strings(void);
 #  define CMP_R_ERROR_CREATING_RP                          125
 #  define CMP_R_ERROR_CREATING_RR                          126
 #  define CMP_R_ERROR_PARSING_PKISTATUS                    107
+#  define CMP_R_ERROR_PROCESSING_MSG                       158
 #  define CMP_R_ERROR_PROTECTING_MESSAGE                   127
 #  define CMP_R_ERROR_SETTING_CERTHASH                     128
+#  define CMP_R_ERROR_TRANSFERRING_OUT                     159
+#  define CMP_R_ERROR_UNEXPECTED_CERTCONF                  160
 #  define CMP_R_ERROR_VALIDATING_PROTECTION                140
 #  define CMP_R_FAILED_EXTRACTING_PUBKEY                   141
 #  define CMP_R_FAILURE_OBTAINING_RANDOM                   110
@@ -65,6 +70,7 @@ int ERR_load_CMP_strings(void);
 #  define CMP_R_MISSING_PROTECTION                         143
 #  define CMP_R_MISSING_SENDER_IDENTIFICATION              111
 #  define CMP_R_MISSING_TRUST_STORE                        144
+#  define CMP_R_MULTIPLE_REQUESTS_NOT_SUPPORTED            161
 #  define CMP_R_MULTIPLE_SAN_SOURCES                       102
 #  define CMP_R_NO_STDIO                                   194
 #  define CMP_R_NO_SUITABLE_SENDER_CERT                    145
diff --git a/include/openssl/crmf.h b/include/openssl/crmf.h
index 09b57f6bce..b578906a67 100644
--- a/include/openssl/crmf.h
+++ b/include/openssl/crmf.h
@@ -106,7 +106,7 @@ int OSSL_CRMF_MSG_set1_regInfo_certReq(OSSL_CRMF_MSG *msg,
 
 int OSSL_CRMF_MSG_set_validity(OSSL_CRMF_MSG *crm, time_t from, time_t to);
 int OSSL_CRMF_MSG_set_certReqId(OSSL_CRMF_MSG *crm, int rid);
-int OSSL_CRMF_MSG_get_certReqId(OSSL_CRMF_MSG *crm);
+int OSSL_CRMF_MSG_get_certReqId(const OSSL_CRMF_MSG *crm);
 int OSSL_CRMF_MSG_set0_extensions(OSSL_CRMF_MSG *crm, X509_EXTENSIONS *exts);
 
 int OSSL_CRMF_MSG_push0_extension(OSSL_CRMF_MSG *crm, X509_EXTENSION *ext);
@@ -120,8 +120,10 @@ int OSSL_CRMF_MSG_create_popo(OSSL_CRMF_MSG *crm, EVP_PKEY *pkey,
 int OSSL_CRMF_MSGS_verify_popo(const OSSL_CRMF_MSGS *reqs,
                                int rid, int acceptRAVerified);
 OSSL_CRMF_CERTTEMPLATE *OSSL_CRMF_MSG_get0_tmpl(const OSSL_CRMF_MSG *crm);
-ASN1_INTEGER *OSSL_CRMF_CERTTEMPLATE_get0_serialNumber(OSSL_CRMF_CERTTEMPLATE *t);
-X509_NAME *OSSL_CRMF_CERTTEMPLATE_get0_issuer(OSSL_CRMF_CERTTEMPLATE *tmpl);
+ASN1_INTEGER
+*OSSL_CRMF_CERTTEMPLATE_get0_serialNumber(const OSSL_CRMF_CERTTEMPLATE *tmpl);
+X509_NAME
+*OSSL_CRMF_CERTTEMPLATE_get0_issuer(const OSSL_CRMF_CERTTEMPLATE *tmpl);
 X509_NAME *OSSL_CRMF_CERTID_get0_issuer(const OSSL_CRMF_CERTID *cid);
 ASN1_INTEGER *OSSL_CRMF_CERTID_get0_serialNumber(const OSSL_CRMF_CERTID *cid);
 int OSSL_CRMF_CERTTEMPLATE_fill(OSSL_CRMF_CERTTEMPLATE *tmpl,
@@ -129,11 +131,12 @@ int OSSL_CRMF_CERTTEMPLATE_fill(OSSL_CRMF_CERTTEMPLATE *tmpl,
                                 const X509_NAME *subject,
                                 const X509_NAME *issuer,
                                 const ASN1_INTEGER *serial);
-X509 *OSSL_CRMF_ENCRYPTEDVALUE_get1_encCert(OSSL_CRMF_ENCRYPTEDVALUE *ecert,
-                                            EVP_PKEY *pkey);
+X509
+*OSSL_CRMF_ENCRYPTEDVALUE_get1_encCert(const OSSL_CRMF_ENCRYPTEDVALUE *ecert,
+                                       EVP_PKEY *pkey);
 
 #  ifdef __cplusplus
 }
 #  endif
-# endif /* !defined OPENSSL_NO_CRMF */
-#endif /* !defined OPENSSL_CRMF_H */
+# endif /* !defined(OPENSSL_NO_CRMF) */
+#endif /* !defined(OPENSSL_CRMF_H) */
diff --git a/include/openssl/crmferr.h b/include/openssl/crmferr.h
index 97a3028ce2..22936c620e 100644
--- a/include/openssl/crmferr.h
+++ b/include/openssl/crmferr.h
@@ -1,6 +1,6 @@
 /*
  * Generated by util/mkerr.pl DO NOT EDIT
- * Copyright 1995-2019 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 1995-2020 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
@@ -19,7 +19,7 @@
 
 # ifndef OPENSSL_NO_CRMF
 
-#  ifdef __cplusplus
+#  ifdef  __cplusplus
 extern "C"
 #  endif
 int ERR_load_CRMF_strings(void);
@@ -27,7 +27,7 @@ int ERR_load_CRMF_strings(void);
 /*
  * CRMF function codes.
  */
-#  ifndef OPENSSL_NO_DEPRECATED_3_0
+# ifndef OPENSSL_NO_DEPRECATED_3_0
 #   define CRMF_F_CRMF_POPOSIGNINGKEY_INIT                  0
 #   define CRMF_F_OSSL_CRMF_CERTID_GEN                      0
 #   define CRMF_F_OSSL_CRMF_CERTTEMPLATE_FILL               0
@@ -47,7 +47,7 @@ int ERR_load_CRMF_strings(void);
 #   define CRMF_F_OSSL_CRMF_MSG_SET_VALIDITY                0
 #   define CRMF_F_OSSL_CRMF_PBMP_NEW                        0
 #   define CRMF_F_OSSL_CRMF_PBM_NEW                         0
-#  endif
+# endif
 
 /*
  * CRMF reason codes.
@@ -62,6 +62,11 @@ int ERR_load_CRMF_strings(void);
 #  define CRMF_R_ITERATIONCOUNT_BELOW_100                  108
 #  define CRMF_R_MALFORMED_IV                              101
 #  define CRMF_R_NULL_ARGUMENT                             109
+#  define CRMF_R_POPO_INCONSISTENT_PUBLIC_KEY              117
+#  define CRMF_R_POPO_MISSING                              121
+#  define CRMF_R_POPO_MISSING_PUBLIC_KEY                   118
+#  define CRMF_R_POPO_MISSING_SUBJECT                      119
+#  define CRMF_R_POPO_RAVERIFIED_NOT_ACCEPTED              120
 #  define CRMF_R_SETTING_MAC_ALGOR_FAILURE                 110
 #  define CRMF_R_SETTING_OWF_ALGOR_FAILURE                 111
 #  define CRMF_R_UNSUPPORTED_ALGORITHM                     112
@@ -69,7 +74,6 @@ int ERR_load_CRMF_strings(void);
 #  define CRMF_R_UNSUPPORTED_CIPHER                        114
 #  define CRMF_R_UNSUPPORTED_METHOD_FOR_CREATING_POPO      115
 #  define CRMF_R_UNSUPPORTED_POPO_METHOD                   116
-#  define CRMF_R_UNSUPPORTED_POPO_NOT_ACCEPTED             117
 
 # endif
 #endif
diff --git a/include/openssl/http.h b/include/openssl/http.h
index e37f636e05..950acf1408 100644
--- a/include/openssl/http.h
+++ b/include/openssl/http.h
@@ -69,4 +69,4 @@ int OSSL_HTTP_parse_url(const char *url, char **phost, char **pport,
 # ifdef  __cplusplus
 }
 # endif
-#endif /* !defined OPENSSL_HTTP_H */
+#endif /* !defined(OPENSSL_HTTP_H) */
diff --git a/include/openssl/ocsp.h b/include/openssl/ocsp.h
index 209afd6f5d..4b0f635cf7 100644
--- a/include/openssl/ocsp.h
+++ b/include/openssl/ocsp.h
@@ -371,5 +371,5 @@ int OCSP_basic_verify(OCSP_BASICRESP *bs, STACK_OF(X509) *certs,
 #  ifdef  __cplusplus
 }
 #  endif
-# endif /* !defined OPENSSL_NO_OCSP */
+# endif /* !defined(OPENSSL_NO_OCSP) */
 #endif
diff --git a/include/openssl/x509.h b/include/openssl/x509.h
index a2d6e44e96..80328cb2eb 100644
--- a/include/openssl/x509.h
+++ b/include/openssl/x509.h
@@ -382,6 +382,7 @@ int X509_pubkey_digest(const X509 *data, const EVP_MD *type,
                        unsigned char *md, unsigned int *len);
 int X509_digest(const X509 *data, const EVP_MD *type,
                 unsigned char *md, unsigned int *len);
+ASN1_OCTET_STRING *X509_digest_sig(const X509 *cert);
 int X509_CRL_digest(const X509_CRL *data, const EVP_MD *type,
                     unsigned char *md, unsigned int *len);
 int X509_REQ_digest(const X509_REQ *data, const EVP_MD *type,
diff --git a/test/build.info b/test/build.info
index 1573087c28..fcf2ac57ac 100644
--- a/test/build.info
+++ b/test/build.info
@@ -438,7 +438,8 @@ IF[{- !$disabled{tests} -}]
 
   IF[{- !$disabled{cmp} -}]
     PROGRAMS{noinst}=cmp_asn_test cmp_ctx_test cmp_status_test cmp_hdr_test \
-                     cmp_protect_test cmp_msg_test cmp_vfy_test
+                     cmp_protect_test cmp_msg_test cmp_vfy_test \
+                     cmp_server_test
   ENDIF
 
   SOURCE[cmp_asn_test]=cmp_asn_test.c cmp_testlib.c
@@ -465,10 +466,14 @@ IF[{- !$disabled{tests} -}]
   INCLUDE[cmp_msg_test]=.. ../include ../apps/include
   DEPEND[cmp_msg_test]=../libcrypto.a libtestutil.a
 
-  SOURCE[cmp_vfy_test]=cmp_status_test.c cmp_testlib.c
+  SOURCE[cmp_vfy_test]=cmp_vfy_test.c cmp_testlib.c
   INCLUDE[cmp_vfy_test]=.. ../include ../apps/include
   DEPEND[cmp_vfy_test]=../libcrypto.a libtestutil.a
 
+  SOURCE[cmp_server_test]=cmp_server_test.c cmp_testlib.c
+  INCLUDE[cmp_server_test]=.. ../include ../apps/include
+  DEPEND[cmp_server_test]=../libcrypto.a libtestutil.a
+
   # Internal test programs.  These are essentially a collection of internal
   # test routines.  Some of them need to reach internal symbols that aren't
   # available through the shared library (at least on Linux, Solaris, Windows
diff --git a/test/cmp_ctx_test.c b/test/cmp_ctx_test.c
index 26c65778b9..903e204622 100644
--- a/test/cmp_ctx_test.c
+++ b/test/cmp_ctx_test.c
@@ -118,6 +118,7 @@ static int msg_total_size_log_cb(const char *func, const char *file, int line,
                                  OSSL_CMP_severity level, const char *msg)
 {
     msg_total_size += strlen(msg);
+    TEST_note("total=%d len=%ld msg='%s'\n", msg_total_size, strlen(msg), msg);
     return 1;
 }
 
diff --git a/test/cmp_hdr_test.c b/test/cmp_hdr_test.c
index c12b72f29e..feba118c44 100644
--- a/test/cmp_hdr_test.c
+++ b/test/cmp_hdr_test.c
@@ -350,9 +350,9 @@ static int
 execute_HDR_set_and_check_implicitConfirm_test(CMP_HDR_TEST_FIXTURE
                                                * fixture)
 {
-    return TEST_false(ossl_cmp_hdr_check_implicitConfirm(fixture->hdr))
+    return TEST_false(ossl_cmp_hdr_has_implicitConfirm(fixture->hdr))
         && TEST_true(ossl_cmp_hdr_set_implicitConfirm(fixture->hdr))
-        && TEST_true(ossl_cmp_hdr_check_implicitConfirm(fixture->hdr));
+        && TEST_true(ossl_cmp_hdr_has_implicitConfirm(fixture->hdr));
 }
 
 static int test_HDR_set_and_check_implicit_confirm(void)
@@ -397,7 +397,7 @@ static int execute_HDR_init_test(CMP_HDR_TEST_FIXTURE *fixture)
     return 1;
 }
 
-static int test_HDR_init(void)
+static int test_HDR_init_with_ref(void)
 {
     SETUP_TEST_FIXTURE(CMP_HDR_TEST_FIXTURE, set_up);
     unsigned char ref[CMP_TEST_REFVALUE_LENGTH];
@@ -431,14 +431,6 @@ static int test_HDR_init_with_subject(void)
     return result;
 }
 
-static int test_HDR_init_no_ref_no_subject(void)
-{
-    SETUP_TEST_FIXTURE(CMP_HDR_TEST_FIXTURE, set_up);
-    fixture->expected = 0;
-    EXECUTE_TEST(execute_HDR_init_test, tear_down);
-    return result;
-}
-
 
 void cleanup_tests(void)
 {
@@ -464,9 +456,8 @@ int setup_tests(void)
     /* also tests public function OSSL_CMP_HDR_get0_transactionID(): */
     /* also tests public function OSSL_CMP_HDR_get0_recipNonce(): */
     /* also tests internal function ossl_cmp_hdr_get_pvno(): */
-    ADD_TEST(test_HDR_init);
+    ADD_TEST(test_HDR_init_with_ref);
     ADD_TEST(test_HDR_init_with_subject);
-    ADD_TEST(test_HDR_init_no_ref_no_subject);
     /*
      *  TODO make sure that total number of tests (here currently 24) is shown,
      *  also for other cmp_*text.c. Currently the test drivers always show 1.
diff --git a/test/cmp_msg_test.c b/test/cmp_msg_test.c
index 8f95865869..3919480610 100644
--- a/test/cmp_msg_test.c
+++ b/test/cmp_msg_test.c
@@ -91,8 +91,7 @@ static int execute_errormsg_create_test(CMP_MSG_TEST_FIXTURE *fixture)
 {
     EXECUTE_MSG_CREATION_TEST(ossl_cmp_error_new(fixture->cmp_ctx, fixture->si,
                                                  fixture->err_code,
-                                                 NULL /* fixture->free_text */,
-                                                 0));
+                                                 "details", 0));
 }
 
 static int execute_rr_create_test(CMP_MSG_TEST_FIXTURE *fixture)
@@ -317,7 +316,7 @@ static int test_cmp_create_certconf_fail_info_max(void)
 static int test_cmp_create_error_msg(void)
 {
     SETUP_TEST_FIXTURE(CMP_MSG_TEST_FIXTURE, set_up);
-    fixture->si = ossl_cmp_statusinfo_new(OSSL_CMP_PKISTATUS_rejection,
+    fixture->si = OSSL_CMP_STATUSINFO_new(OSSL_CMP_PKISTATUS_rejection,
                                           OSSL_CMP_PKIFAILUREINFO_systemFailure,
                                           NULL);
     fixture->err_code = -1;
@@ -419,7 +418,7 @@ static int test_cmp_create_certrep(void)
 
 static int execute_rp_create(CMP_MSG_TEST_FIXTURE *fixture)
 {
-    OSSL_CMP_PKISI *si = ossl_cmp_statusinfo_new(33, 44, "a text");
+    OSSL_CMP_PKISI *si = OSSL_CMP_STATUSINFO_new(33, 44, "a text");
     X509_NAME *issuer = X509_NAME_new();
     ASN1_INTEGER *serial = ASN1_INTEGER_new();
     OSSL_CRMF_CERTID *cid = NULL;
@@ -439,8 +438,7 @@ static int execute_rp_create(CMP_MSG_TEST_FIXTURE *fixture)
     if (!TEST_ptr(ossl_cmp_revrepcontent_get_CertId(rpmsg->body->value.rp, 0)))
         goto err;
 
-    if (!TEST_ptr(ossl_cmp_revrepcontent_get_pkistatusinfo(rpmsg->body->
-                                                           value.rp, 0)))
+    if (!TEST_ptr(ossl_cmp_revrepcontent_get_pkisi(rpmsg->body->value.rp, 0)))
         goto err;
 
     res = 1;
diff --git a/test/cmp_protect_test.c b/test/cmp_protect_test.c
index 5d5df89abd..a506ec33ea 100644
--- a/test/cmp_protect_test.c
+++ b/test/cmp_protect_test.c
@@ -278,6 +278,38 @@ static int test_MSG_protect_no_key_no_secret(void)
     return result;
 }
 
+static int test_MSG_protect_pbmac_no_sender(int with_ref)
+{
+    static unsigned char secret[] = { 47, 11, 8, 15 };
+    static unsigned char ref[] = { 0xca, 0xfe, 0xba, 0xbe };
+
+    SETUP_TEST_FIXTURE(CMP_PROTECT_TEST_FIXTURE, set_up);
+    fixture->expected = with_ref;
+    if (!TEST_ptr(fixture->msg = OSSL_CMP_MSG_dup(ir_unprotected))
+            || !SET_OPT_UNPROTECTED_SEND(fixture->cmp_ctx, 0)
+            || !ossl_cmp_hdr_set1_sender(fixture->msg->header, NULL)
+            || !OSSL_CMP_CTX_set1_secretValue(fixture->cmp_ctx,
+                                              secret, sizeof(secret))
+            || (!OSSL_CMP_CTX_set1_referenceValue(fixture->cmp_ctx,
+                                                  with_ref ? ref : NULL,
+                                                  sizeof(ref)))) {
+        tear_down(fixture);
+        fixture = NULL;
+    }
+    EXECUTE_TEST(execute_MSG_protect_test, tear_down);
+    return result;
+}
+
+static int test_MSG_protect_pbmac_no_sender_with_ref(void)
+{
+    return test_MSG_protect_pbmac_no_sender(1);
+}
+
+static int test_MSG_protect_pbmac_no_sender_no_ref(void)
+{
+    return test_MSG_protect_pbmac_no_sender(0);
+}
+
 static int execute_MSG_add_extraCerts_test(CMP_PROTECT_TEST_FIXTURE *fixture)
 {
     return TEST_true(ossl_cmp_msg_add_extraCerts(fixture->cmp_ctx,
@@ -511,7 +543,8 @@ int setup_tests(void)
     ADD_TEST(test_MSG_protect_certificate_based_without_cert);
     ADD_TEST(test_MSG_protect_unprotected_request);
     ADD_TEST(test_MSG_protect_no_key_no_secret);
-
+    ADD_TEST(test_MSG_protect_pbmac_no_sender_with_ref);
+    ADD_TEST(test_MSG_protect_pbmac_no_sender_no_ref);
     ADD_TEST(test_MSG_add_extraCerts);
 
 #ifndef OPENSSL_NO_EC
diff --git a/test/cmp_server_test.c b/test/cmp_server_test.c
new file mode 100644
index 0000000000..13159299e9
--- /dev/null
+++ b/test/cmp_server_test.c
@@ -0,0 +1,160 @@
+/*
+ * Copyright 2007-2020 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright Nokia 2007-2020
+ * Copyright Siemens AG 2015-2020
+ *
+ * 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
+ * https://www.openssl.org/source/license.html
+ */
+
+#include "cmp_testlib.h"
+
+typedef struct test_fixture {
+    const char *test_case_name;
+    int expected;
+    OSSL_CMP_SRV_CTX *srv_ctx;
+    OSSL_CMP_MSG *req;
+} CMP_SRV_TEST_FIXTURE;
+
+static OSSL_CMP_MSG *request = NULL;
+
+static void tear_down(CMP_SRV_TEST_FIXTURE *fixture)
+{
+    OSSL_CMP_SRV_CTX_free(fixture->srv_ctx);
+    OPENSSL_free(fixture);
+}
+
+static CMP_SRV_TEST_FIXTURE *set_up(const char *const test_case_name)
+{
+    CMP_SRV_TEST_FIXTURE *fixture;
+
+    if (!TEST_ptr(fixture = OPENSSL_zalloc(sizeof(*fixture))))
+        return NULL;
+    fixture->test_case_name = test_case_name;
+    if (!TEST_ptr(fixture->srv_ctx = OSSL_CMP_SRV_CTX_new()))
+        goto err;
+    return fixture;
+
+ err:
+    tear_down(fixture);
+    return NULL;
+}
+
+static int dummy_errorCode = CMP_R_MULTIPLE_SAN_SOURCES; /* any reason code */
+
+static OSSL_CMP_PKISI *process_cert_request(OSSL_CMP_SRV_CTX *srv_ctx,
+                                            const OSSL_CMP_MSG *cert_req,
+                                            int certReqId,
+                                            const OSSL_CRMF_MSG *crm,
+                                            const X509_REQ *p10cr,
+                                            X509 **certOut,
+                                            STACK_OF(X509) **chainOut,
+                                            STACK_OF(X509) **caPubs)
+{
+    CMPerr(0, dummy_errorCode);
+    return NULL;
+}
+
+static int execute_test_handle_request(CMP_SRV_TEST_FIXTURE *fixture)
+{
+    OSSL_CMP_SRV_CTX *ctx = fixture->srv_ctx;
+    OSSL_CMP_CTX *client_ctx;
+    OSSL_CMP_CTX *cmp_ctx;
+    char *dummy_custom_ctx = "@test_dummy", *custom_ctx;
+    OSSL_CMP_MSG *rsp = NULL;
+    OSSL_CMP_ERRORMSGCONTENT *errorContent;
+    int res = 0;
+
+    if (!TEST_ptr(client_ctx = OSSL_CMP_CTX_new())
+            || !TEST_true(OSSL_CMP_CTX_set_transfer_cb_arg(client_ctx, ctx)))
+        goto end;
+
+    if (!TEST_true(OSSL_CMP_SRV_CTX_init(ctx, dummy_custom_ctx,
+                                         process_cert_request, NULL, NULL,
+                                         NULL, NULL, NULL))
+        || !TEST_ptr(custom_ctx = OSSL_CMP_SRV_CTX_get0_custom_ctx(ctx))
+        || !TEST_int_eq(strcmp(custom_ctx, dummy_custom_ctx), 0))
+        goto end;
+
+    if (!TEST_true(OSSL_CMP_SRV_CTX_set_send_unprotected_errors(ctx, 0))
+            || !TEST_true(OSSL_CMP_SRV_CTX_set_accept_unprotected(ctx, 0))
+            || !TEST_true(OSSL_CMP_SRV_CTX_set_accept_raverified(ctx, 1))
+            || !TEST_true(OSSL_CMP_SRV_CTX_set_grant_implicit_confirm(ctx, 1)))
+        goto end;
+
+    if (!TEST_ptr(cmp_ctx = OSSL_CMP_SRV_CTX_get0_cmp_ctx(ctx))
+            || !OSSL_CMP_CTX_set1_referenceValue(cmp_ctx,
+                                                 (unsigned char *)"server", 6)
+            || !OSSL_CMP_CTX_set1_secretValue(cmp_ctx,
+                                              (unsigned char *)"1234", 4))
+        goto end;
+
+    if (!TEST_ptr(rsp = OSSL_CMP_CTX_server_perform(client_ctx, fixture->req))
+            || !TEST_int_eq(ossl_cmp_msg_get_bodytype(rsp),
+                            OSSL_CMP_PKIBODY_ERROR)
+            || !TEST_ptr(errorContent = rsp->body->value.error)
+            || !TEST_int_eq(ASN1_INTEGER_get(errorContent->errorCode),
+                            dummy_errorCode))
+        goto end;
+
+    res = 1;
+
+ end:
+    OSSL_CMP_MSG_free(rsp);
+    OSSL_CMP_CTX_free(client_ctx);
+    return res;
+}
+
+static int test_handle_request(void)
+{
+    SETUP_TEST_FIXTURE(CMP_SRV_TEST_FIXTURE, set_up);
+    fixture->req = request;
+    fixture->expected = 1;
+    EXECUTE_TEST(execute_test_handle_request, tear_down);
+    return result;
+}
+
+void cleanup_tests(void)
+{
+    OSSL_CMP_MSG_free(request);
+    return;
+}
+
+int setup_tests(void)
+{
+    const char *request_f;
+
+    if (!test_skip_common_options()) {
+        TEST_error("Error parsing test options\n");
+        return 0;
+    }
+
+    if (!TEST_ptr(request_f = test_get_argument(0))) {
+        TEST_error("usage: cmp_server_test CR_protected_PBM_1234.der\n");
+        return 0;
+    }
+
+    if (!TEST_ptr(request = load_pkimsg(request_f))) {
+        cleanup_tests();
+        return 0;
+    }
+
+    /*
+     * this (indirectly) calls
+     * OSSL_CMP_SRV_CTX_new(),
+     * OSSL_CMP_SRV_CTX_free(),
+     * OSSL_CMP_CTX_server_perform(),
+     * OSSL_CMP_SRV_process_request(),
+     * OSSL_CMP_SRV_CTX_init(),
+     * OSSL_CMP_SRV_CTX_get0_cmp_ctx(),
+     * OSSL_CMP_SRV_CTX_get0_custom_ctx(),
+     * OSSL_CMP_SRV_CTX_set_send_unprotected_errors(),
+     * OSSL_CMP_SRV_CTX_set_accept_unprotected(),
+     * OSSL_CMP_SRV_CTX_set_accept_raverified(), and
+     * OSSL_CMP_SRV_CTX_set_grant_implicit_confirm()
+     */
+    ADD_TEST(test_handle_request);
+    return 1;
+}
diff --git a/test/cmp_status_test.c b/test/cmp_status_test.c
index 7311c2e444..15cd6a5fd0 100644
--- a/test/cmp_status_test.c
+++ b/test/cmp_status_test.c
@@ -45,18 +45,18 @@ static int execute_PKISI_test(CMP_STATUS_TEST_FIXTURE *fixture)
     ASN1_UTF8STRING *statusString = NULL;
     int res = 0, i;
 
-    if (!TEST_ptr(si = ossl_cmp_statusinfo_new(fixture->pkistatus,
+    if (!TEST_ptr(si = OSSL_CMP_STATUSINFO_new(fixture->pkistatus,
                                                fixture->pkifailure,
                                                fixture->text)))
         goto end;
 
-    status = ossl_cmp_pkisi_get_pkistatus(si);
+    status = ossl_cmp_pkisi_get_status(si);
     if (!TEST_int_eq(fixture->pkistatus, status)
             || !TEST_str_eq(fixture->str, ossl_cmp_PKIStatus_to_string(status)))
         goto end;
 
     if (!TEST_ptr(statusString =
-                  sk_ASN1_UTF8STRING_value(ossl_cmp_pkisi_get0_statusstring(si),
+                  sk_ASN1_UTF8STRING_value(ossl_cmp_pkisi_get0_statusString(si),
                                            0))
             || !TEST_str_eq(fixture->text, (char *)statusString->data))
         goto end;
@@ -66,7 +66,7 @@ static int execute_PKISI_test(CMP_STATUS_TEST_FIXTURE *fixture)
         goto end;
     for (i = 0; i <= OSSL_CMP_PKIFAILUREINFO_MAX; i++)
         if (!TEST_int_eq((fixture->pkifailure >> i) & 1,
-                         ossl_cmp_pkisi_pkifailureinfo_check(si, i)))
+                         ossl_cmp_pkisi_check_pkifailureinfo(si, i)))
             goto end;
 
     res = 1;
@@ -99,12 +99,12 @@ int setup_tests(void)
 {
     /*-
      * this tests all of:
-     * ossl_cmp_statusinfo_new()
-     * ossl_cmp_pkisi_get_pkistatus()
+     * OSSL_CMP_STATUSINFO_new()
+     * ossl_cmp_pkisi_get_status()
      * ossl_cmp_PKIStatus_to_string()
-     * ossl_cmp_pkisi_get0_statusstring()
+     * ossl_cmp_pkisi_get0_statusString()
      * ossl_cmp_pkisi_get_pkifailureinfo()
-     * ossl_cmp_pkisi_pkifailureinfo_check()
+     * ossl_cmp_pkisi_check_pkifailureinfo()
      */
     ADD_TEST(test_PKISI);
     return 1;
diff --git a/test/cmp_vfy_test.c b/test/cmp_vfy_test.c
index 41ddad86ba..f52efa9855 100644
--- a/test/cmp_vfy_test.c
+++ b/test/cmp_vfy_test.c
@@ -69,7 +69,7 @@ static CMP_VFY_TEST_FIXTURE *set_up(const char *const test_case_name)
         return NULL;
     }
     X509_VERIFY_PARAM_set_time(X509_STORE_get0_param(ts), test_time_valid);
-    X509_STORE_set_verify_cb(ts, OSSL_CMP_print_cert_verify_cb);
+    X509_STORE_set_verify_cb(ts, X509_STORE_CTX_print_verify_cb);
     return fixture;
 }
 
@@ -437,8 +437,7 @@ static void setup_check_received(CMP_VFY_TEST_FIXTURE **fixture, int expected,
                                                       nonce_data, nonce_len))) {
         tear_down((*fixture));
         (*fixture) = NULL;
-    }
-    else if (trid_data != NULL) {
+    } else if (trid_data != NULL) {
         ASN1_OCTET_STRING *trid = ASN1_OCTET_STRING_new();
         if (trid == NULL
             || !ASN1_OCTET_STRING_set(trid, trid_data,
@@ -549,6 +548,11 @@ int setup_tests(void)
     ts.tm_year += 10;              /* February 18th 2028 */
     test_time_after_expiration = mktime(&ts);
 
+    if (!test_skip_common_options()) {
+        TEST_error("Error parsing test options\n");
+        return 0;
+    }
+
     RAND_bytes(rand_data, OSSL_CMP_TRANSACTIONID_LENGTH);
     if (!TEST_ptr(server_f = test_get_argument(0))
             || !TEST_ptr(client_f = test_get_argument(1))
diff --git a/test/recipes/65-test_cmp_server.t b/test/recipes/65-test_cmp_server.t
new file mode 100644
index 0000000000..87dbdb10b2
--- /dev/null
+++ b/test/recipes/65-test_cmp_server.t
@@ -0,0 +1,26 @@
+#! /usr/bin/env perl
+# Copyright 2007-2020 The OpenSSL Project Authors. All Rights Reserved.
+# Copyright Nokia 2007-2020
+# Copyright Siemens AG 2015-2020
+#
+# 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
+# https://www.openssl.org/source/license.html
+
+use strict;
+use OpenSSL::Test qw/:DEFAULT data_file/;
+use OpenSSL::Test::Utils;
+
+setup("test_cmp_server");
+
+plan skip_all => "This test is not supported in a no-cmp build"
+    if disabled("cmp");
+
+plan skip_all => "This test is not supported in a no-ec build"
+    if disabled("ec");
+
+plan tests => 1;
+
+ok(run(test(["cmp_server_test",
+             data_file("CR_protected_PBM_1234.der")])));
diff --git a/test/recipes/65-test_cmp_server_data/CR_protected_PBM_1234.der b/test/recipes/65-test_cmp_server_data/CR_protected_PBM_1234.der
new file mode 100644
index 0000000000..fc1c0aff9b
Binary files /dev/null and b/test/recipes/65-test_cmp_server_data/CR_protected_PBM_1234.der differ
diff --git a/util/libcrypto.num b/util/libcrypto.num
index d7a94f8adf..15dd512a49 100644
--- a/util/libcrypto.num
+++ b/util/libcrypto.num
@@ -4956,3 +4956,27 @@ OSSL_SELF_TEST_onbegin                  ?	3_0_0	EXIST::FUNCTION:
 OSSL_SELF_TEST_oncorrupt_byte           ?	3_0_0	EXIST::FUNCTION:
 OSSL_SELF_TEST_onend                    ?	3_0_0	EXIST::FUNCTION:
 OSSL_PROVIDER_set_default_search_path   ?	3_0_0	EXIST::FUNCTION:
+X509_digest_sig                         ?	3_0_0	EXIST::FUNCTION:
+OSSL_CMP_MSG_dup                        ?	3_0_0	EXIST::FUNCTION:CMP
+OSSL_CMP_ITAV_dup                       ?	3_0_0	EXIST::FUNCTION:CMP
+d2i_OSSL_CMP_PKISI                      ?	3_0_0	EXIST::FUNCTION:CMP
+i2d_OSSL_CMP_PKISI                      ?	3_0_0	EXIST::FUNCTION:CMP
+OSSL_CMP_PKISI_free                     ?	3_0_0	EXIST::FUNCTION:CMP
+OSSL_CMP_PKISI_new                      ?	3_0_0	EXIST::FUNCTION:CMP
+OSSL_CMP_PKISI_it                       ?	3_0_0	EXIST::FUNCTION:CMP
+OSSL_CMP_PKISI_dup                      ?	3_0_0	EXIST::FUNCTION:CMP
+OSSL_CMP_snprint_PKIStatusInfo          ?	3_0_0	EXIST::FUNCTION:CMP
+OSSL_CMP_STATUSINFO_new                 ?	3_0_0	EXIST::FUNCTION:CMP
+OSSL_d2i_CMP_MSG_bio                    ?	3_0_0	EXIST::FUNCTION:CMP
+OSSL_i2d_CMP_MSG_bio                    ?	3_0_0	EXIST::FUNCTION:CMP
+OSSL_CMP_SRV_process_request            ?	3_0_0	EXIST::FUNCTION:CMP
+OSSL_CMP_CTX_server_perform             ?	3_0_0	EXIST::FUNCTION:CMP
+OSSL_CMP_SRV_CTX_new                    ?	3_0_0	EXIST::FUNCTION:CMP
+OSSL_CMP_SRV_CTX_free                   ?	3_0_0	EXIST::FUNCTION:CMP
+OSSL_CMP_SRV_CTX_init                   ?	3_0_0	EXIST::FUNCTION:CMP
+OSSL_CMP_SRV_CTX_get0_cmp_ctx           ?	3_0_0	EXIST::FUNCTION:CMP
+OSSL_CMP_SRV_CTX_get0_custom_ctx        ?	3_0_0	EXIST::FUNCTION:CMP
+OSSL_CMP_SRV_CTX_set_send_unprotected_errors ?	3_0_0	EXIST::FUNCTION:CMP
+OSSL_CMP_SRV_CTX_set_accept_unprotected ?	3_0_0	EXIST::FUNCTION:CMP
+OSSL_CMP_SRV_CTX_set_accept_raverified  ?	3_0_0	EXIST::FUNCTION:CMP
+OSSL_CMP_SRV_CTX_set_grant_implicit_confirm ?	3_0_0	EXIST::FUNCTION:CMP
diff --git a/util/other.syms b/util/other.syms
index 4996dd874b..1d2a2689ef 100644
--- a/util/other.syms
+++ b/util/other.syms
@@ -367,6 +367,12 @@ OSSL_CMP_severity                       datatype
 OSSL_cmp_certConf_cb_t                  datatype
 OSSL_cmp_log_cb_t                       datatype
 OSSL_cmp_transfer_cb_t                  datatype
+OSSL_CMP_SRV_cert_request_cb_t          datatype
+OSSL_CMP_SRV_rr_cb_t                    datatype
+OSSL_CMP_SRV_certConf_cb_t              datatype
+OSSL_CMP_SRV_genm_cb_t                  datatype
+OSSL_CMP_SRV_error_cb_t                 datatype
+OSSL_CMP_SRV_pollReq_cb_t               datatype
 OSSL_PARAM_TYPE                         define
 OSSL_PARAM_octet_ptr                    define
 OSSL_PARAM_octet_string                 define


More information about the openssl-commits mailing list