[openssl] master update

Matt Caswell matt at openssl.org
Thu Dec 12 11:01:52 UTC 2019


The branch master has been updated
       via  3dbc5156b0b2c7a57be160706e6ad38a14edae37 (commit)
      from  0402c90ff9caac4c680e3cb6db7729e00d3fc20b (commit)


- Log -----------------------------------------------------------------
commit 3dbc5156b0b2c7a57be160706e6ad38a14edae37
Author: Dr. David von Oheimb <David.von.Oheimb at siemens.com>
Date:   Tue Nov 5 09:56:59 2019 +0100

    chunk 6 of CMP contribution to OpenSSL
    
    Reviewed-by: Bernd Edlinger <bernd.edlinger at hotmail.de>
    Reviewed-by: Matt Caswell <matt at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/10297)

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

Summary of changes:
 crypto/cmp/build.info                              |   2 +-
 crypto/cmp/cmp_ctx.c                               |   6 +-
 crypto/cmp/cmp_err.c                               |  61 +-
 crypto/cmp/cmp_local.h                             |  98 +-
 crypto/cmp/cmp_msg.c                               | 996 +++++++++++++++++++++
 crypto/cmp/cmp_protect.c                           | 313 +++++++
 crypto/cmp/cmp_status.c                            |   3 +-
 crypto/crmf/crmf_asn.c                             |   3 +-
 crypto/crmf/crmf_lib.c                             |  19 +-
 crypto/crmf/crmf_local.h                           |   4 +-
 crypto/crmf/crmf_pbm.c                             |  14 +-
 crypto/err/openssl.txt                             |  32 +-
 doc/man3/OSSL_CMP_MSG_get0_header.pod              |  40 +
 include/openssl/cmp.h                              |  10 +-
 include/openssl/cmp_util.h                         |   7 +-
 include/openssl/cmperr.h                           |  31 +-
 test/build.info                                    |  11 +-
 test/cmp_asn_test.c                                |   9 +-
 test/cmp_ctx_test.c                                | 118 +--
 test/cmp_hdr_test.c                                |  18 +-
 test/cmp_msg_test.c                                | 577 ++++++++++++
 test/cmp_protect_test.c                            | 517 +++++++++++
 test/cmp_testlib.h                                 |   2 +-
 test/recipes/65-test_cmp_msg.t                     |  24 +
 test/recipes/65-test_cmp_msg_data/pkcs10.der       | Bin 0 -> 615 bytes
 test/recipes/65-test_cmp_msg_data/server.crt       |  17 +
 test/recipes/65-test_cmp_protect.t                 |  35 +
 .../65-test_cmp_protect_data/EndEntity1.crt        |  16 +
 .../65-test_cmp_protect_data/EndEntity2.crt        |  13 +
 test/recipes/65-test_cmp_protect_data/IP_PBM.der   | Bin 0 -> 2107 bytes
 test/recipes/65-test_cmp_protect_data/IP_PBM.txt   |   1 +
 .../65-test_cmp_protect_data/IR_protected.der      | Bin 0 -> 968 bytes
 .../65-test_cmp_protect_data/IR_unprotected.der    | Bin 0 -> 838 bytes
 .../65-test_cmp_protect_data/Intermediate_CA.crt   |  12 +
 test/recipes/65-test_cmp_protect_data/Root_CA.crt  |  17 +
 test/recipes/65-test_cmp_protect_data/server.crt   |  17 +
 test/recipes/65-test_cmp_protect_data/server.pem   |  27 +
 util/libcrypto.num                                 |   1 +
 util/other.syms                                    |   2 +
 39 files changed, 2963 insertions(+), 110 deletions(-)
 create mode 100644 crypto/cmp/cmp_msg.c
 create mode 100644 crypto/cmp/cmp_protect.c
 create mode 100644 doc/man3/OSSL_CMP_MSG_get0_header.pod
 create mode 100644 test/cmp_msg_test.c
 create mode 100644 test/cmp_protect_test.c
 create mode 100644 test/recipes/65-test_cmp_msg.t
 create mode 100644 test/recipes/65-test_cmp_msg_data/pkcs10.der
 create mode 100644 test/recipes/65-test_cmp_msg_data/server.crt
 create mode 100644 test/recipes/65-test_cmp_protect.t
 create mode 100644 test/recipes/65-test_cmp_protect_data/EndEntity1.crt
 create mode 100644 test/recipes/65-test_cmp_protect_data/EndEntity2.crt
 create mode 100644 test/recipes/65-test_cmp_protect_data/IP_PBM.der
 create mode 100644 test/recipes/65-test_cmp_protect_data/IP_PBM.txt
 create mode 100644 test/recipes/65-test_cmp_protect_data/IR_protected.der
 create mode 100644 test/recipes/65-test_cmp_protect_data/IR_unprotected.der
 create mode 100644 test/recipes/65-test_cmp_protect_data/Intermediate_CA.crt
 create mode 100644 test/recipes/65-test_cmp_protect_data/Root_CA.crt
 create mode 100644 test/recipes/65-test_cmp_protect_data/server.crt
 create mode 100644 test/recipes/65-test_cmp_protect_data/server.pem

diff --git a/crypto/cmp/build.info b/crypto/cmp/build.info
index 154022762a..760c3423ad 100644
--- a/crypto/cmp/build.info
+++ b/crypto/cmp/build.info
@@ -1,3 +1,3 @@
 LIBS=../../libcrypto
 SOURCE[../../libcrypto]= cmp_asn.c cmp_ctx.c cmp_err.c cmp_util.c \
-        cmp_status.c cmp_hdr.c
+        cmp_status.c cmp_hdr.c cmp_protect.c cmp_msg.c
diff --git a/crypto/cmp/cmp_ctx.c b/crypto/cmp/cmp_ctx.c
index 89ecab1413..0bd12f47ac 100644
--- a/crypto/cmp/cmp_ctx.c
+++ b/crypto/cmp/cmp_ctx.c
@@ -946,7 +946,8 @@ int OSSL_CMP_CTX_get_failInfoCode(const OSSL_CMP_CTX *ctx)
  * Sets a Boolean or integer option of the context to the "val" arg.
  * Returns 1 on success, 0 on error
  */
-int OSSL_CMP_CTX_set_option(OSSL_CMP_CTX *ctx, int opt, int val) {
+int OSSL_CMP_CTX_set_option(OSSL_CMP_CTX *ctx, int opt, int val)
+{
     int min_val;
 
     if (ctx == NULL) {
@@ -1049,7 +1050,8 @@ int OSSL_CMP_CTX_set_option(OSSL_CMP_CTX *ctx, int opt, int val) {
  * Reads a Boolean or integer option value from the context.
  * Returns -1 on error (which is the default OSSL_CMP_OPT_REVOCATION_REASON)
  */
-int OSSL_CMP_CTX_get_option(const OSSL_CMP_CTX *ctx, int opt) {
+int OSSL_CMP_CTX_get_option(const OSSL_CMP_CTX *ctx, int opt)
+{
     if (ctx == NULL) {
         CMPerr(0, CMP_R_NULL_ARGUMENT);
         return -1;
diff --git a/crypto/cmp/cmp_err.c b/crypto/cmp/cmp_err.c
index 683b8472d7..8b4a6ca708 100644
--- a/crypto/cmp/cmp_err.c
+++ b/crypto/cmp/cmp_err.c
@@ -1,7 +1,6 @@
 /*
- * Copyright 2007-2019 The OpenSSL Project Authors. All Rights Reserved.
- * Copyright Nokia 2007-2019
- * Copyright Siemens AG 2015-2019
+ * Generated by util/mkerr.pl DO NOT EDIT
+ * Copyright 1995-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
@@ -15,17 +14,69 @@
 #ifndef OPENSSL_NO_ERR
 
 static const ERR_STRING_DATA CMP_str_reasons[] = {
+    {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_BAD_REQUEST_ID), "bad request id"},
+    {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_CERTRESPONSE_NOT_FOUND),
+    "certresponse not found"},
+    {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_CERT_AND_KEY_DO_NOT_MATCH),
+    "cert and key do not match"},
+    {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_ERROR_CALCULATING_PROTECTION),
+    "error calculating protection"},
+    {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_ERROR_CREATING_CERTCONF),
+    "error creating certconf"},
+    {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_ERROR_CREATING_CERTREP),
+    "error creating certrep"},
+    {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_ERROR_CREATING_ERROR),
+    "error creating error"},
+    {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_ERROR_CREATING_GENM),
+    "error creating genm"},
+    {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_ERROR_CREATING_GENP),
+    "error creating genp"},
+    {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_ERROR_CREATING_P10CR),
+    "error creating p10cr"},
+    {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_ERROR_CREATING_PKICONF),
+    "error creating pkiconf"},
+    {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_ERROR_CREATING_POLLREP),
+    "error creating pollrep"},
+    {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_ERROR_CREATING_POLLREQ),
+    "error creating pollreq"},
+    {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_ERROR_CREATING_RP), "error creating rp"},
+    {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_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_FAILURE_OBTAINING_RANDOM),
     "failure obtaining random"},
+    {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_FAIL_INFO_OUT_OF_RANGE),
+    "fail info out of range"},
     {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_INVALID_ARGS), "invalid args"},
-    {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_MULTIPLE_SAN_SOURCES),
-    "multiple san sources"},
+    {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_MISSING_KEY_INPUT_FOR_CREATING_PROTECTION),
+    "missing key input for creating protection"},
+    {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_MISSING_PRIVATE_KEY),
+    "missing private key"},
     {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_MISSING_SENDER_IDENTIFICATION),
     "missing sender identification"},
+    {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"},
     {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_NULL_ARGUMENT), "null argument"},
+    {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_PKISTATUSINFO_NOT_FOUND),
+    "pkistatusinfo not found"},
+    {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_UNEXPECTED_PKIBODY), "unexpected pkibody"},
+    {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_UNKNOWN_ALGORITHM_ID),
+    "unknown algorithm id"},
+    {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_UNKNOWN_CERT_TYPE), "unknown cert type"},
+    {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_UNSUPPORTED_ALGORITHM),
+    "unsupported algorithm"},
+    {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_UNSUPPORTED_KEY_TYPE),
+    "unsupported key type"},
+    {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_WRONG_ALGORITHM_OID),
+    "wrong algorithm oid"},
     {0, NULL}
 };
 
diff --git a/crypto/cmp/cmp_local.h b/crypto/cmp/cmp_local.h
index b49ead62df..b7ab6454b5 100644
--- a/crypto/cmp/cmp_local.h
+++ b/crypto/cmp/cmp_local.h
@@ -42,7 +42,7 @@ struct ossl_cmp_ctx_st {
     int proxyPort;
     int msgtimeout; /* max seconds to wait for each CMP message round trip */
     int totaltimeout; /* maximum number seconds an enrollment may take, incl. */
-      /* attempts polling for a response if a 'waiting' PKIStatus is received */
+    /* attempts polling for a response if a 'waiting' PKIStatus is received */
     time_t end_time; /* session start time + totaltimeout */
     OSSL_cmp_http_cb_t http_cb;
     void *http_cb_arg; /* allows to store optional argument to cb */
@@ -279,6 +279,7 @@ struct ossl_cmp_pkisi_st {
 } /* OSSL_CMP_PKISI */;
 DECLARE_ASN1_FUNCTIONS(OSSL_CMP_PKISI)
 DECLARE_ASN1_DUP_FUNCTION(OSSL_CMP_PKISI)
+DECLARE_ASN1_DUP_FUNCTION(OSSL_CRMF_CERTID)
 
 /*-
  *  RevReqContent ::= SEQUENCE OF RevDetails
@@ -526,6 +527,7 @@ DECLARE_ASN1_FUNCTIONS(OSSL_CMP_GENREPCONTENT)
  *           certConf [24] CertConfirmContent,         --Certificate confirm
  *           pollReq  [25] PollReqContent,             --Polling request
  *           pollRep  [26] PollRepContent              --Polling response
+ *   }
  */
 typedef struct ossl_cmp_pkibody_st {
     int type;
@@ -679,6 +681,13 @@ 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
  */
@@ -752,4 +761,91 @@ int ossl_cmp_hdr_check_implicitConfirm(const OSSL_CMP_PKIHEADER *hdr);
 # define OSSL_CMP_SENDERNONCE_LENGTH 16
 int ossl_cmp_hdr_init(OSSL_CMP_CTX *ctx, OSSL_CMP_PKIHEADER *hdr);
 
+/* from cmp_msg.c */
+/* OSSL_CMP_MSG bodytype ASN.1 choice IDs */
+# define OSSL_CMP_PKIBODY_IR        0
+# define OSSL_CMP_PKIBODY_IP        1
+# define OSSL_CMP_PKIBODY_CR        2
+# define OSSL_CMP_PKIBODY_CP        3
+# define OSSL_CMP_PKIBODY_P10CR     4
+# define OSSL_CMP_PKIBODY_POPDECC   5
+# define OSSL_CMP_PKIBODY_POPDECR   6
+# define OSSL_CMP_PKIBODY_KUR       7
+# define OSSL_CMP_PKIBODY_KUP       8
+# define OSSL_CMP_PKIBODY_KRR       9
+# define OSSL_CMP_PKIBODY_KRP      10
+# define OSSL_CMP_PKIBODY_RR       11
+# define OSSL_CMP_PKIBODY_RP       12
+# define OSSL_CMP_PKIBODY_CCR      13
+# define OSSL_CMP_PKIBODY_CCP      14
+# define OSSL_CMP_PKIBODY_CKUANN   15
+# define OSSL_CMP_PKIBODY_CANN     16
+# define OSSL_CMP_PKIBODY_RANN     17
+# define OSSL_CMP_PKIBODY_CRLANN   18
+# define OSSL_CMP_PKIBODY_PKICONF  19
+# define OSSL_CMP_PKIBODY_NESTED   20
+# define OSSL_CMP_PKIBODY_GENM     21
+# define OSSL_CMP_PKIBODY_GENP     22
+# define OSSL_CMP_PKIBODY_ERROR    23
+# define OSSL_CMP_PKIBODY_CERTCONF 24
+# define OSSL_CMP_PKIBODY_POLLREQ  25
+# define OSSL_CMP_PKIBODY_POLLREP  26
+# define OSSL_CMP_PKIBODY_TYPE_MAX OSSL_CMP_PKIBODY_POLLREP
+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);
+OSSL_CMP_MSG *ossl_cmp_msg_create(OSSL_CMP_CTX *ctx, int bodytype);
+OSSL_CMP_MSG *ossl_cmp_certReq_new(OSSL_CMP_CTX *ctx, int bodytype,
+                                   int err_code);
+OSSL_CMP_MSG *ossl_cmp_certRep_new(OSSL_CMP_CTX *ctx, int bodytype,
+                                   int certReqId, OSSL_CMP_PKISI *si,
+                                   X509 *cert, STACK_OF(X509) *chain,
+                                   STACK_OF(X509) *caPubs, int encrypted,
+                                   int unprotectedErrors);
+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);
+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);
+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_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);
+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_CRMF_CERTID *ossl_cmp_revrepcontent_get_CertId(OSSL_CMP_REVREPCONTENT *rrep,
+                                               int rsid);
+OSSL_CMP_POLLREP *
+ossl_cmp_pollrepcontent_get0_pollrep(const OSSL_CMP_POLLREPCONTENT *prc,
+                                     int rid);
+OSSL_CMP_CERTRESPONSE *
+ossl_cmp_certrepmessage_get0_certresponse(const OSSL_CMP_CERTREPMESSAGE *crepmsg,
+                                          int rid);
+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,
+                                          const ASN1_OCTET_STRING *secret,
+                                          EVP_PKEY *pkey);
+int ossl_cmp_msg_add_extraCerts(OSSL_CMP_CTX *ctx, OSSL_CMP_MSG *msg);
+int ossl_cmp_msg_protect(OSSL_CMP_CTX *ctx, OSSL_CMP_MSG *msg);
+
 #endif /* !defined OSSL_CRYPTO_CMP_LOCAL_H */
diff --git a/crypto/cmp/cmp_msg.c b/crypto/cmp/cmp_msg.c
new file mode 100644
index 0000000000..00381932f3
--- /dev/null
+++ b/crypto/cmp/cmp_msg.c
@@ -0,0 +1,996 @@
+/*
+ * 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
+ */
+
+/* CMP functions for PKIMessage construction */
+
+#include "cmp_local.h"
+
+/* explicit #includes not strictly needed since implied by the above: */
+#include <openssl/asn1t.h>
+#include <openssl/cmp.h>
+#include <openssl/crmf.h>
+#include <openssl/err.h>
+#include <openssl/x509.h>
+
+OSSL_CMP_PKIHEADER *OSSL_CMP_MSG_get0_header(const OSSL_CMP_MSG *msg)
+{
+    if (msg == NULL) {
+        CMPerr(0, CMP_R_NULL_ARGUMENT);
+        return NULL;
+    }
+    return msg->header;
+}
+
+const char *ossl_cmp_bodytype_to_string(int type)
+{
+    static const char *type_names[] = {
+        "IR", "IP", "CR", "CP", "P10CR",
+        "POPDECC", "POPDECR", "KUR", "KUP",
+        "KRR", "KRP", "RR", "RP", "CCR", "CCP",
+        "CKUANN", "CANN", "RANN", "CRLANN", "PKICONF", "NESTED",
+        "GENM", "GENP", "ERROR", "CERTCONF", "POLLREQ", "POLLREP",
+    };
+
+    if (type < 0 || type > OSSL_CMP_PKIBODY_TYPE_MAX)
+        return "illegal body type";
+    return type_names[type];
+}
+
+int ossl_cmp_msg_set_bodytype(OSSL_CMP_MSG *msg, int type)
+{
+    if (!ossl_assert(msg != NULL && msg->body != NULL))
+        return 0;
+
+    msg->body->type = type;
+    return 1;
+}
+
+int ossl_cmp_msg_get_bodytype(const OSSL_CMP_MSG *msg)
+{
+    if (!ossl_assert(msg != NULL && msg->body != NULL))
+        return -1;
+
+    return msg->body->type;
+}
+
+/* Add an extension to the referenced extension stack, which may be NULL */
+static int add1_extension(X509_EXTENSIONS **pexts, int nid, int crit, void *ex)
+{
+    X509_EXTENSION *ext;
+    int res;
+
+    if (!ossl_assert(pexts != NULL)) /* pointer to var must not be NULL */
+        return 0;
+
+    if ((ext = X509V3_EXT_i2d(nid, crit, ex)) == NULL)
+        return 0;
+
+    res = X509v3_add_ext(pexts, ext, 0) != NULL;
+    X509_EXTENSION_free(ext);
+    return res;
+}
+
+/* Add a CRL revocation reason code to extension stack, which may be NULL */
+static int add_crl_reason_extension(X509_EXTENSIONS **pexts, int reason_code)
+{
+    ASN1_ENUMERATED *val = ASN1_ENUMERATED_new();
+    int res = 0;
+
+    if (val != NULL && ASN1_ENUMERATED_set(val, reason_code))
+        res = add1_extension(pexts, NID_crl_reason, 0 /* non-critical */, val);
+    ASN1_ENUMERATED_free(val);
+    return res;
+}
+
+OSSL_CMP_MSG *ossl_cmp_msg_create(OSSL_CMP_CTX *ctx, int bodytype)
+{
+    OSSL_CMP_MSG *msg = NULL;
+
+    if (!ossl_assert(ctx != NULL))
+        return NULL;
+
+    if ((msg = OSSL_CMP_MSG_new()) == NULL)
+        return NULL;
+    if (!ossl_cmp_hdr_init(ctx, msg->header)
+            || !ossl_cmp_msg_set_bodytype(msg, bodytype))
+        goto err;
+    if (ctx->geninfo_ITAVs != NULL
+            && !ossl_cmp_hdr_generalInfo_push1_items(msg->header,
+                                                     ctx->geninfo_ITAVs))
+        goto err;
+
+    switch (bodytype) {
+    case OSSL_CMP_PKIBODY_IR:
+    case OSSL_CMP_PKIBODY_CR:
+    case OSSL_CMP_PKIBODY_KUR:
+        if ((msg->body->value.ir = OSSL_CRMF_MSGS_new()) == NULL)
+            goto err;
+        return msg;
+
+    case OSSL_CMP_PKIBODY_P10CR:
+        if (ctx->p10CSR == NULL) {
+            CMPerr(0, CMP_R_ERROR_CREATING_P10CR);
+            goto err;
+        }
+        if ((msg->body->value.p10cr = X509_REQ_dup(ctx->p10CSR)) == NULL)
+            goto err;
+        return msg;
+
+    case OSSL_CMP_PKIBODY_IP:
+    case OSSL_CMP_PKIBODY_CP:
+    case OSSL_CMP_PKIBODY_KUP:
+        if ((msg->body->value.ip = OSSL_CMP_CERTREPMESSAGE_new()) == NULL)
+            goto err;
+        return msg;
+
+    case OSSL_CMP_PKIBODY_RR:
+        if ((msg->body->value.rr = sk_OSSL_CMP_REVDETAILS_new_null()) == NULL)
+            goto err;
+        return msg;
+    case OSSL_CMP_PKIBODY_RP:
+        if ((msg->body->value.rp = OSSL_CMP_REVREPCONTENT_new()) == NULL)
+            goto err;
+        return msg;
+
+    case OSSL_CMP_PKIBODY_CERTCONF:
+        if ((msg->body->value.certConf =
+             sk_OSSL_CMP_CERTSTATUS_new_null()) == NULL)
+            goto err;
+        return msg;
+    case OSSL_CMP_PKIBODY_PKICONF:
+        if ((msg->body->value.pkiconf = ASN1_TYPE_new()) == NULL)
+            goto err;
+        ASN1_TYPE_set(msg->body->value.pkiconf, V_ASN1_NULL, NULL);
+        return msg;
+
+    case OSSL_CMP_PKIBODY_POLLREQ:
+        if ((msg->body->value.pollReq = sk_OSSL_CMP_POLLREQ_new_null()) == NULL)
+            goto err;
+        return msg;
+    case OSSL_CMP_PKIBODY_POLLREP:
+        if ((msg->body->value.pollRep = sk_OSSL_CMP_POLLREP_new_null()) == NULL)
+            goto err;
+        return msg;
+
+    case OSSL_CMP_PKIBODY_GENM:
+    case OSSL_CMP_PKIBODY_GENP:
+        if ((msg->body->value.genm = sk_OSSL_CMP_ITAV_new_null()) == NULL)
+            goto err;
+        return msg;
+
+    case OSSL_CMP_PKIBODY_ERROR:
+        if ((msg->body->value.error = OSSL_CMP_ERRORMSGCONTENT_new()) == NULL)
+            goto err;
+        return msg;
+
+    default:
+        CMPerr(0, CMP_R_UNEXPECTED_PKIBODY);
+        goto err;
+    }
+
+ err:
+    OSSL_CMP_MSG_free(msg);
+    return NULL;
+}
+
+#define HAS_SAN(ctx) \
+    (sk_GENERAL_NAME_num((ctx)->subjectAltNames) > 0 \
+         || OSSL_CMP_CTX_reqExtensions_have_SAN(ctx) == 1)
+
+static X509_NAME *determine_subj(OSSL_CMP_CTX *ctx, X509 *refcert,
+                                 int bodytype)
+{
+    if (ctx->subjectName != NULL)
+        return ctx->subjectName;
+
+    if (refcert != NULL
+            && (bodytype == OSSL_CMP_PKIBODY_KUR || !HAS_SAN(ctx)))
+        /*
+         * For KUR, copy subjectName from reference certificate.
+         * For IR or CR, do the same only if there is no subjectAltName.
+         */
+        return X509_get_subject_name(refcert);
+    return NULL;
+}
+
+/*
+ * 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)
+{
+    OSSL_CRMF_MSG *crm = NULL;
+    X509 *refcert = ctx->oldCert != NULL ? ctx->oldCert : ctx->clCert;
+    /* refcert defaults to current client cert */
+    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
+            || (bodytype == OSSL_CMP_PKIBODY_KUR && refcert == NULL)) {
+        CMPerr(0, CMP_R_INVALID_ARGS);
+        return NULL;
+    }
+    if ((crm = OSSL_CRMF_MSG_new()) == NULL)
+        return NULL;
+    if (!OSSL_CRMF_MSG_set_certReqId(crm, rid)
+            /*
+             * fill certTemplate, corresponding to CertificationRequestInfo
+             * of PKCS#10. The rkey param cannot be NULL so far -
+             * it could be NULL if centralized key creation was supported
+             */
+            || !OSSL_CRMF_CERTTEMPLATE_fill(OSSL_CRMF_MSG_get0_tmpl(crm), rkey,
+                                            subject, ctx->issuer,
+                                            NULL/* serial */))
+        goto err;
+    if (ctx->days != 0) {
+        time_t notBefore, notAfter;
+
+        notBefore = time(NULL);
+        notAfter = notBefore + 60 * 60 * 24 * ctx->days;
+        if (!OSSL_CRMF_MSG_set_validity(crm, notBefore, notAfter))
+            goto err;
+    }
+
+    /* extensions */
+    if (refcert != NULL && !ctx->SubjectAltName_nodefault)
+        default_sans = X509V3_get_d2i(X509_get0_extensions(refcert),
+                                      NID_subject_alt_name, NULL, NULL);
+    /* exts are copied from ctx to allow reuse */
+    if (ctx->reqExtensions != NULL) {
+        exts = sk_X509_EXTENSION_deep_copy(ctx->reqExtensions,
+                                           X509_EXTENSION_dup,
+                                           X509_EXTENSION_free);
+        if (exts == NULL)
+            goto err;
+    }
+    if (sk_GENERAL_NAME_num(ctx->subjectAltNames) > 0
+            && !add1_extension(&exts, NID_subject_alt_name,
+                               crit, ctx->subjectAltNames))
+        goto err;
+    if (!HAS_SAN(ctx) && default_sans != NULL
+            && !add1_extension(&exts, NID_subject_alt_name, crit, default_sans))
+        goto err;
+    if (ctx->policies != NULL
+            && !add1_extension(&exts, NID_certificate_policies,
+                               ctx->setPoliciesCritical, ctx->policies))
+        goto err;
+    if (!OSSL_CRMF_MSG_set0_extensions(crm, exts))
+        goto err;
+    exts = NULL;
+    /* end fill certTemplate, now set any controls */
+
+    /* for KUR, set OldCertId according to D.6 */
+    if (bodytype == OSSL_CMP_PKIBODY_KUR) {
+        OSSL_CRMF_CERTID *cid =
+            OSSL_CRMF_CERTID_gen(X509_get_issuer_name(refcert),
+                                 X509_get_serialNumber(refcert));
+        int ret;
+
+        if (cid == NULL)
+            goto err;
+        ret = OSSL_CRMF_MSG_set1_regCtrl_oldCertID(crm, cid);
+        OSSL_CRMF_CERTID_free(cid);
+        if (ret == 0)
+            goto err;
+    }
+
+    goto end;
+
+ err:
+    OSSL_CRMF_MSG_free(crm);
+    crm = NULL;
+
+ end:
+    sk_X509_EXTENSION_pop_free(exts, X509_EXTENSION_free);
+    sk_GENERAL_NAME_pop_free(default_sans, GENERAL_NAME_free);
+    return crm;
+}
+
+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);
+        return NULL;
+    }
+
+    if ((msg = ossl_cmp_msg_create(ctx, type)) == NULL)
+        goto err;
+
+    /* header */
+    if (ctx->implicitConfirm && !ossl_cmp_hdr_set_implicitConfirm(msg->header))
+        goto err;
+
+    /* body */
+    /* For P10CR the content has already been set in OSSL_CMP_MSG_create */
+    if (type != OSSL_CMP_PKIBODY_P10CR) {
+        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))
+            goto err;
+        crm = NULL;
+        /* TODO: here optional 2nd certreqmsg could be pushed to the stack */
+    }
+
+    if (!ossl_cmp_msg_protect(ctx, msg))
+        goto err;
+
+    return msg;
+
+ err:
+    CMPerr(0, err_code);
+    OSSL_CRMF_MSG_free(crm);
+    OSSL_CMP_MSG_free(msg);
+    return NULL;
+}
+
+OSSL_CMP_MSG *ossl_cmp_certRep_new(OSSL_CMP_CTX *ctx, int bodytype,
+                                   int certReqId, OSSL_CMP_PKISI *si,
+                                   X509 *cert, STACK_OF(X509) *chain,
+                                   STACK_OF(X509) *caPubs, int encrypted,
+                                   int unprotectedErrors)
+{
+    OSSL_CMP_MSG *msg = NULL;
+    OSSL_CMP_CERTREPMESSAGE *repMsg = NULL;
+    OSSL_CMP_CERTRESPONSE *resp = NULL;
+    int status = -1;
+
+    if (!ossl_assert(ctx != NULL && si != NULL))
+        return NULL;
+
+    if ((msg = ossl_cmp_msg_create(ctx, bodytype)) == NULL)
+        goto err;
+    repMsg = msg->body->value.ip; /* value.ip is same for cp and kup */
+
+    /* header */
+    if (ctx->implicitConfirm && !ossl_cmp_hdr_set_implicitConfirm(msg->header))
+        goto err;
+
+    /* body */
+    if ((resp = OSSL_CMP_CERTRESPONSE_new()) == NULL)
+        goto err;
+    OSSL_CMP_PKISI_free(resp->status);
+    if ((resp->status = OSSL_CMP_PKISI_dup(si)) == NULL
+            || !ASN1_INTEGER_set(resp->certReqId, certReqId))
+        goto err;
+
+    status = ossl_cmp_pkisi_get_pkistatus(resp->status);
+    if (status != OSSL_CMP_PKISTATUS_rejection
+            && status != OSSL_CMP_PKISTATUS_waiting && cert != NULL) {
+        if (encrypted) {
+            CMPerr(0, CMP_R_INVALID_ARGS);
+            goto err;
+        }
+
+        if ((resp->certifiedKeyPair = OSSL_CMP_CERTIFIEDKEYPAIR_new())
+            == NULL)
+            goto err;
+        resp->certifiedKeyPair->certOrEncCert->type =
+            OSSL_CMP_CERTORENCCERT_CERTIFICATE;
+        if (!X509_up_ref(cert))
+            goto err;
+        resp->certifiedKeyPair->certOrEncCert->value.certificate = cert;
+    }
+
+    if (!sk_OSSL_CMP_CERTRESPONSE_push(repMsg->response, resp))
+        goto err;
+    resp = NULL;
+    /* TODO: here optional 2nd certrep could be pushed to the stack */
+
+    if (bodytype == OSSL_CMP_PKIBODY_IP && caPubs != NULL
+            && (repMsg->caPubs = X509_chain_up_ref(caPubs)) == NULL)
+        goto err;
+    if (chain != NULL
+            && !ossl_cmp_sk_X509_add1_certs(msg->extraCerts, chain, 0, 1, 0))
+        goto err;
+
+    if (!unprotectedErrors
+            || ossl_cmp_pkisi_get_pkistatus(si) != OSSL_CMP_PKISTATUS_rejection)
+        if (!ossl_cmp_msg_protect(ctx, msg))
+            goto err;
+
+    return msg;
+
+ err:
+    CMPerr(0, CMP_R_ERROR_CREATING_CERTREP);
+    OSSL_CMP_CERTRESPONSE_free(resp);
+    OSSL_CMP_MSG_free(msg);
+    return NULL;
+}
+
+OSSL_CMP_MSG *ossl_cmp_rr_new(OSSL_CMP_CTX *ctx)
+{
+    OSSL_CMP_MSG *msg = NULL;
+    OSSL_CMP_REVDETAILS *rd;
+
+    if (!ossl_assert(ctx != NULL && ctx->oldCert != NULL))
+        return NULL;
+
+    if ((rd = OSSL_CMP_REVDETAILS_new()) == NULL)
+        goto err;
+
+    /* Fill the template from the contents of the certificate to be revoked */
+    if (!OSSL_CRMF_CERTTEMPLATE_fill(rd->certDetails,
+                                     NULL/* pubkey would be redundant */,
+                                     NULL/* subject would be redundant */,
+                                     X509_get_issuer_name(ctx->oldCert),
+                                     X509_get_serialNumber(ctx->oldCert)))
+        goto err;
+
+    /* revocation reason code is optional */
+    if (ctx->revocationReason != CRL_REASON_NONE
+            && !add_crl_reason_extension(&rd->crlEntryDetails,
+                                         ctx->revocationReason))
+        goto err;
+
+    if ((msg = ossl_cmp_msg_create(ctx, OSSL_CMP_PKIBODY_RR)) == NULL)
+        goto err;
+
+    if (!sk_OSSL_CMP_REVDETAILS_push(msg->body->value.rr, rd))
+        goto err;
+    rd = NULL;
+
+    /*
+     * TODO: the Revocation Passphrase according to section 5.3.19.9 could be
+     *       set here if set in ctx
+     */
+
+    if (!ossl_cmp_msg_protect(ctx, msg))
+        goto err;
+
+    return msg;
+
+ err:
+    CMPerr(0, CMP_R_ERROR_CREATING_RR);
+    OSSL_CMP_MSG_free(msg);
+    OSSL_CMP_REVDETAILS_free(rd);
+    return NULL;
+}
+
+OSSL_CMP_MSG *ossl_cmp_rp_new(OSSL_CMP_CTX *ctx, OSSL_CMP_PKISI *si,
+                              OSSL_CRMF_CERTID *cid, int unprot_err)
+{
+    OSSL_CMP_REVREPCONTENT *rep = NULL;
+    OSSL_CMP_PKISI *si1 = NULL;
+    OSSL_CRMF_CERTID *cid_copy = NULL;
+    OSSL_CMP_MSG *msg = NULL;
+
+    if (!ossl_assert(ctx != NULL && si != NULL && cid != NULL))
+        return NULL;
+
+    if ((msg = ossl_cmp_msg_create(ctx, OSSL_CMP_PKIBODY_RP)) == NULL)
+        goto err;
+    rep = msg->body->value.rp;
+
+    if ((si1 = OSSL_CMP_PKISI_dup(si)) == NULL)
+        goto err;
+
+    if (!sk_OSSL_CMP_PKISI_push(rep->status, si1)) {
+        OSSL_CMP_PKISI_free(si1);
+        goto err;
+    }
+
+    if ((rep->revCerts = sk_OSSL_CRMF_CERTID_new_null()) == NULL)
+        goto err;
+    if ((cid_copy = OSSL_CRMF_CERTID_dup(cid)) == NULL)
+        goto err;
+    if (!sk_OSSL_CRMF_CERTID_push(rep->revCerts, cid_copy)) {
+        OSSL_CRMF_CERTID_free(cid_copy);
+        goto err;
+    }
+
+    if (!unprot_err
+            || ossl_cmp_pkisi_get_pkistatus(si) != OSSL_CMP_PKISTATUS_rejection)
+        if (!ossl_cmp_msg_protect(ctx, msg))
+            goto err;
+
+    return msg;
+
+ err:
+    CMPerr(0, CMP_R_ERROR_CREATING_RP);
+    OSSL_CMP_MSG_free(msg);
+    return NULL;
+}
+
+OSSL_CMP_MSG *ossl_cmp_pkiconf_new(OSSL_CMP_CTX *ctx)
+{
+    OSSL_CMP_MSG *msg;
+
+    if (!ossl_assert(ctx != NULL))
+        return NULL;
+
+    if ((msg = ossl_cmp_msg_create(ctx, OSSL_CMP_PKIBODY_PKICONF)) == NULL)
+        goto err;
+    if (ossl_cmp_msg_protect(ctx, msg))
+        return msg;
+
+ err:
+    CMPerr(0, CMP_R_ERROR_CREATING_PKICONF);
+    OSSL_CMP_MSG_free(msg);
+    return NULL;
+}
+
+int ossl_cmp_msg_gen_push0_ITAV(OSSL_CMP_MSG *msg, OSSL_CMP_ITAV *itav)
+{
+    int bodytype;
+
+    if (!ossl_assert(msg != NULL && itav != NULL))
+        return 0;
+
+    bodytype = ossl_cmp_msg_get_bodytype(msg);
+    if (bodytype != OSSL_CMP_PKIBODY_GENM
+            && bodytype != OSSL_CMP_PKIBODY_GENP) {
+        CMPerr(0, CMP_R_INVALID_ARGS);
+        return 0;
+    }
+
+    /* value.genp has the same structure, so this works for genp as well */
+    return OSSL_CMP_ITAV_push0_stack_item(&msg->body->value.genm, itav);
+}
+
+int ossl_cmp_msg_gen_push1_ITAVs(OSSL_CMP_MSG *msg,
+                                 STACK_OF(OSSL_CMP_ITAV) *itavs)
+{
+    int i;
+    OSSL_CMP_ITAV *itav = NULL;
+
+    if (!ossl_assert(msg != NULL))
+        return 0;
+
+    for (i = 0; i < sk_OSSL_CMP_ITAV_num(itavs); i++) {
+        if ((itav = OSSL_CMP_ITAV_dup(sk_OSSL_CMP_ITAV_value(itavs,i))) == NULL)
+            return 0;
+        if (!ossl_cmp_msg_gen_push0_ITAV(msg, itav)) {
+            OSSL_CMP_ITAV_free(itav);
+            return 0;
+        }
+    }
+    return 1;
+}
+
+/*
+ * 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)
+{
+    OSSL_CMP_MSG *msg = NULL;
+
+    if (!ossl_assert(ctx != NULL))
+        return NULL;
+
+    if ((msg = ossl_cmp_msg_create(ctx, body_type)) == NULL)
+        return NULL;
+
+    if (ctx->genm_ITAVs != NULL
+            && !ossl_cmp_msg_gen_push1_ITAVs(msg, ctx->genm_ITAVs))
+        goto err;
+
+    if (!ossl_cmp_msg_protect(ctx, msg))
+        goto err;
+
+    return msg;
+
+ err:
+    CMPerr(0, err_code);
+    OSSL_CMP_MSG_free(msg);
+    return NULL;
+}
+
+OSSL_CMP_MSG *ossl_cmp_genm_new(OSSL_CMP_CTX *ctx)
+{
+    return gen_new(ctx, OSSL_CMP_PKIBODY_GENM, CMP_R_ERROR_CREATING_GENM);
+}
+
+OSSL_CMP_MSG *ossl_cmp_genp_new(OSSL_CMP_CTX *ctx)
+{
+    return gen_new(ctx, 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)
+{
+    OSSL_CMP_MSG *msg = NULL;
+
+    if (!ossl_assert(ctx != NULL && si != NULL))
+        return NULL;
+
+    if ((msg = ossl_cmp_msg_create(ctx, OSSL_CMP_PKIBODY_ERROR)) == NULL)
+        goto err;
+
+    OSSL_CMP_PKISI_free(msg->body->value.error->pKIStatusInfo);
+    if ((msg->body->value.error->pKIStatusInfo = OSSL_CMP_PKISI_dup(si))
+        == NULL)
+        goto err;
+    if (errorCode >= 0) {
+        if ((msg->body->value.error->errorCode = ASN1_INTEGER_new()) == NULL)
+            goto err;
+        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)
+            goto err;
+
+    if (!unprotected && !ossl_cmp_msg_protect(ctx, msg))
+        goto err;
+    return msg;
+
+ err:
+    CMPerr(0, CMP_R_ERROR_CREATING_ERROR);
+    OSSL_CMP_MSG_free(msg);
+    return NULL;
+}
+
+/*
+ * 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.
+ */
+int ossl_cmp_certstatus_set_certHash(OSSL_CMP_CERTSTATUS *certStatus,
+                                     const X509 *cert)
+{
+    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);
+        return 0;
+    }
+
+    return 1;
+ err:
+    CMPerr(0, CMP_R_ERROR_SETTING_CERTHASH);
+    return 0;
+}
+
+/*
+ * TODO: handle potential 2nd certificate when signing and encrypting
+ * certificates have been requested/received
+ */
+OSSL_CMP_MSG *ossl_cmp_certConf_new(OSSL_CMP_CTX *ctx, int fail_info,
+                                    const char *text)
+{
+    OSSL_CMP_MSG *msg = NULL;
+    OSSL_CMP_CERTSTATUS *certStatus = NULL;
+    OSSL_CMP_PKISI *sinfo;
+
+    if (!ossl_assert(ctx != NULL && ctx->newCert != NULL))
+        return NULL;
+
+    if ((unsigned)fail_info > OSSL_CMP_PKIFAILUREINFO_MAX_BIT_PATTERN) {
+        CMPerr(0, CMP_R_FAIL_INFO_OUT_OF_RANGE);
+        return NULL;
+    }
+
+    if ((msg = ossl_cmp_msg_create(ctx, OSSL_CMP_PKIBODY_CERTCONF)) == NULL)
+        goto err;
+
+    if ((certStatus = OSSL_CMP_CERTSTATUS_new()) == NULL)
+        goto err;
+    /* consume certStatus into msg right away so it gets deallocated with msg */
+    if (!sk_OSSL_CMP_CERTSTATUS_push(msg->body->value.certConf, certStatus))
+        goto err;
+    /* set the ID of the certReq */
+    if (!ASN1_INTEGER_set(certStatus->certReqId, OSSL_CMP_CERTREQID))
+        goto err;
+    /*
+     * 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))
+        goto err;
+    /*
+     * For any particular CertStatus, omission of the statusInfo field
+     * indicates ACCEPTANCE of the specified certificate.  Alternatively,
+     * explicit status details (with respect to acceptance or rejection) MAY
+     * be provided in the statusInfo field, perhaps for auditing purposes at
+     * 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);
+    if (sinfo == NULL)
+        goto err;
+    certStatus->statusInfo = sinfo;
+
+    if (!ossl_cmp_msg_protect(ctx, msg))
+        goto err;
+
+    return msg;
+
+ err:
+    CMPerr(0, CMP_R_ERROR_CREATING_CERTCONF);
+    OSSL_CMP_MSG_free(msg);
+    return NULL;
+}
+
+OSSL_CMP_MSG *ossl_cmp_pollReq_new(OSSL_CMP_CTX *ctx, int crid)
+{
+    OSSL_CMP_MSG *msg = NULL;
+    OSSL_CMP_POLLREQ *preq = NULL;
+
+    if (!ossl_assert(ctx != NULL))
+        return NULL;
+
+    if ((msg = ossl_cmp_msg_create(ctx, OSSL_CMP_PKIBODY_POLLREQ)) == NULL)
+        goto err;
+
+    /* TODO: support multiple cert request IDs to poll */
+    if ((preq = OSSL_CMP_POLLREQ_new()) == NULL
+            || !ASN1_INTEGER_set(preq->certReqId, crid)
+            || !sk_OSSL_CMP_POLLREQ_push(msg->body->value.pollReq, preq))
+        goto err;
+
+    preq = NULL;
+    if (!ossl_cmp_msg_protect(ctx, msg))
+        goto err;
+
+    return msg;
+
+ err:
+    CMPerr(0, CMP_R_ERROR_CREATING_POLLREQ);
+    OSSL_CMP_POLLREQ_free(preq);
+    OSSL_CMP_MSG_free(msg);
+    return NULL;
+}
+
+OSSL_CMP_MSG *ossl_cmp_pollRep_new(OSSL_CMP_CTX *ctx, int crid,
+                                   int64_t poll_after)
+{
+    OSSL_CMP_MSG *msg;
+    OSSL_CMP_POLLREP *prep;
+
+    if (!ossl_assert(ctx != NULL))
+        return NULL;
+
+    if ((msg = ossl_cmp_msg_create(ctx, OSSL_CMP_PKIBODY_POLLREP)) == NULL)
+        goto err;
+    if ((prep = OSSL_CMP_POLLREP_new()) == NULL)
+        goto err;
+    if (!sk_OSSL_CMP_POLLREP_push(msg->body->value.pollRep, prep))
+        goto err;
+    if (!ASN1_INTEGER_set(prep->certReqId, crid))
+        goto err;
+    if (!ASN1_INTEGER_set_int64(prep->checkAfter, poll_after))
+        goto err;
+
+    if (!ossl_cmp_msg_protect(ctx, msg))
+        goto err;
+    return msg;
+
+ err:
+    CMPerr(0, CMP_R_ERROR_CREATING_POLLREP);
+    OSSL_CMP_MSG_free(msg);
+    return NULL;
+}
+
+/*-
+ * returns the status field of the RevRepContent with the given
+ * request/sequence id inside a revocation response.
+ * RevRepContent has the revocation statuses in same order as they were sent in
+ * RevReqContent.
+ * returns NULL on error
+ */
+OSSL_CMP_PKISI *
+ossl_cmp_revrepcontent_get_pkistatusinfo(OSSL_CMP_REVREPCONTENT *rrep, int rsid)
+{
+    OSSL_CMP_PKISI *status;
+
+    if (!ossl_assert(rrep != NULL))
+        return NULL;
+
+    if ((status = sk_OSSL_CMP_PKISI_value(rrep->status, rsid)) != NULL)
+        return status;
+
+    CMPerr(0, CMP_R_PKISTATUSINFO_NOT_FOUND);
+    return NULL;
+}
+
+/*
+ * returns the CertId field in the revCerts part of the RevRepContent
+ * with the given request/sequence id inside a revocation response.
+ * RevRepContent has the CertIds in same order as they were sent in
+ * RevReqContent.
+ * returns NULL on error
+ */
+OSSL_CRMF_CERTID *
+ossl_cmp_revrepcontent_get_CertId(OSSL_CMP_REVREPCONTENT *rrep, int rsid)
+{
+    OSSL_CRMF_CERTID *cid = NULL;
+
+    if (!ossl_assert(rrep != NULL))
+        return NULL;
+
+    if ((cid = sk_OSSL_CRMF_CERTID_value(rrep->revCerts, rsid)) != NULL)
+        return cid;
+
+    CMPerr(0, CMP_R_CERTID_NOT_FOUND);
+    return NULL;
+}
+
+static int suitable_rid(const ASN1_INTEGER *certReqId, int rid)
+{
+    int trid;
+
+    if (rid == -1)
+        return 1;
+
+    trid = ossl_cmp_asn1_get_int(certReqId);
+
+    if (trid == -1) {
+        CMPerr(0, CMP_R_BAD_REQUEST_ID);
+        return 0;
+    }
+    return rid == trid;
+}
+
+static void add_expected_rid(int rid)
+{
+    char str[DECIMAL_SIZE(rid) + 1];
+
+    BIO_snprintf(str, sizeof(str), "%d", rid);
+    ERR_add_error_data(2, "expected certReqId = ", str);
+}
+
+/*
+ * returns a pointer to the PollResponse with the given CertReqId
+ * (or the first one in case -1) inside a PollRepContent
+ * returns NULL on error or if no suitable PollResponse available
+ */
+OSSL_CMP_POLLREP *
+ossl_cmp_pollrepcontent_get0_pollrep(const OSSL_CMP_POLLREPCONTENT *prc,
+                                     int rid)
+{
+    OSSL_CMP_POLLREP *pollRep = NULL;
+    int i;
+
+    if (!ossl_assert(prc != NULL))
+        return NULL;
+
+    for (i = 0; i < sk_OSSL_CMP_POLLREP_num(prc); i++) {
+        pollRep = sk_OSSL_CMP_POLLREP_value(prc, i);
+        if (suitable_rid(pollRep->certReqId, rid))
+            return pollRep;
+    }
+
+    CMPerr(0, CMP_R_CERTRESPONSE_NOT_FOUND);
+    add_expected_rid(rid);
+    return NULL;
+}
+
+/*
+ * returns a pointer to the CertResponse with the given CertReqId
+ * (or the first one in case -1) inside a CertRepMessage
+ * returns NULL on error or if no suitable CertResponse available
+ */
+OSSL_CMP_CERTRESPONSE *
+ossl_cmp_certrepmessage_get0_certresponse(const OSSL_CMP_CERTREPMESSAGE *crm,
+                                          int rid)
+{
+    OSSL_CMP_CERTRESPONSE *crep = NULL;
+    int i;
+
+    if (!ossl_assert(crm != NULL && crm->response != NULL))
+        return NULL;
+
+    for (i = 0; i < sk_OSSL_CMP_CERTRESPONSE_num(crm->response); i++) {
+        crep = sk_OSSL_CMP_CERTRESPONSE_value(crm->response, i);
+        if (suitable_rid(crep->certReqId, rid))
+            return crep;
+    }
+
+    CMPerr(0, CMP_R_CERTRESPONSE_NOT_FOUND);
+    add_expected_rid(rid);
+    return NULL;
+}
+
+/*
+ * CMP_CERTRESPONSE_get1_certificate() attempts to retrieve the returned
+ * certificate from the given certResponse B<crep>.
+ * Uses the privkey in case of indirect POP from B<ctx>.
+ * Returns a pointer to a copy of the found certificate, or NULL if not found.
+ */
+X509 *ossl_cmp_certresponse_get1_certificate(EVP_PKEY *privkey,
+                                             const OSSL_CMP_CERTRESPONSE *crep)
+{
+    OSSL_CMP_CERTORENCCERT *coec;
+    X509 *crt = NULL;
+
+    if (!ossl_assert(crep != NULL))
+        return NULL;
+
+    if (crep->certifiedKeyPair
+            && (coec = crep->certifiedKeyPair->certOrEncCert) != NULL) {
+        switch (coec->type) {
+        case OSSL_CMP_CERTORENCCERT_CERTIFICATE:
+            crt = X509_dup(coec->value.certificate);
+            break;
+        case OSSL_CMP_CERTORENCCERT_ENCRYPTEDCERT:
+            /* cert encrypted for indirect PoP; RFC 4210, 5.2.8.2 */
+            if (privkey == NULL) {
+                CMPerr(0, CMP_R_MISSING_PRIVATE_KEY);
+                return NULL;
+            }
+            crt =
+                OSSL_CRMF_ENCRYPTEDVALUE_get1_encCert(coec->value.encryptedCert,
+                                                      privkey);
+            break;
+        default:
+            CMPerr(0, CMP_R_UNKNOWN_CERT_TYPE);
+            return NULL;
+        }
+    }
+    if (crt == NULL)
+        CMPerr(0, CMP_R_CERTIFICATE_NOT_FOUND);
+    return crt;
+}
+
+OSSL_CMP_MSG *ossl_cmp_msg_load(const char *file)
+{
+    OSSL_CMP_MSG *msg = NULL;
+    BIO *bio = NULL;
+
+    if (!ossl_assert(file != NULL))
+        return NULL;
+
+    if ((bio = BIO_new_file(file, "rb")) == NULL)
+        return NULL;
+    msg = OSSL_d2i_CMP_MSG_bio(bio, NULL);
+    BIO_free(bio);
+    return msg;
+}
diff --git a/crypto/cmp/cmp_protect.c b/crypto/cmp/cmp_protect.c
new file mode 100644
index 0000000000..7db3440f32
--- /dev/null
+++ b/crypto/cmp/cmp_protect.c
@@ -0,0 +1,313 @@
+/*
+ * 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
+ */
+
+#include "cmp_local.h"
+
+/* explicit #includes not strictly needed since implied by the above: */
+#include <openssl/asn1t.h>
+#include <openssl/cmp.h>
+#include <openssl/crmf.h>
+#include <openssl/err.h>
+#include <openssl/x509.h>
+
+/*
+ * This function is also used for verification from cmp_vfy.
+ *
+ * Calculate protection for given PKImessage utilizing the given credentials
+ * and the algorithm parameters set inside the message header's protectionAlg.
+ *
+ * Either secret or pkey must be set, the other must be NULL. Attempts doing
+ * PBMAC in case 'secret' is set and signature if 'pkey' is set - but will only
+ * do the protection already marked in msg->header->protectionAlg.
+ *
+ * returns ptr to ASN1_BIT_STRING containing protection on success, else NULL
+ */
+ASN1_BIT_STRING *ossl_cmp_calc_protection(const OSSL_CMP_MSG *msg,
+                                          const ASN1_OCTET_STRING *secret,
+                                          EVP_PKEY *pkey)
+{
+    ASN1_BIT_STRING *prot = NULL;
+    CMP_PROTECTEDPART prot_part;
+    const ASN1_OBJECT *algorOID = NULL;
+    int len;
+    size_t prot_part_der_len;
+    unsigned char *prot_part_der = NULL;
+    size_t sig_len;
+    unsigned char *protection = NULL;
+    const void *ppval = NULL;
+    int pptype = 0;
+    OSSL_CRMF_PBMPARAMETER *pbm = NULL;
+    ASN1_STRING *pbm_str = NULL;
+    const unsigned char *pbm_str_uc = NULL;
+    EVP_MD_CTX *evp_ctx = NULL;
+    int md_NID;
+    const EVP_MD *md = NULL;
+
+    if (!ossl_assert(msg != NULL))
+        return NULL;
+
+    /* construct data to be signed */
+    prot_part.header = msg->header;
+    prot_part.body = msg->body;
+
+    len = i2d_CMP_PROTECTEDPART(&prot_part, &prot_part_der);
+    if (len < 0 || prot_part_der == NULL) {
+        CMPerr(0, CMP_R_ERROR_CALCULATING_PROTECTION);
+        goto end;
+    }
+    prot_part_der_len = (size_t) len;
+
+    if (msg->header->protectionAlg == NULL) {
+        CMPerr(0, CMP_R_UNKNOWN_ALGORITHM_ID);
+        goto end;
+    }
+    X509_ALGOR_get0(&algorOID, &pptype, &ppval, msg->header->protectionAlg);
+
+    if (secret != NULL && pkey == NULL) {
+        if (ppval == NULL) {
+            CMPerr(0, CMP_R_ERROR_CALCULATING_PROTECTION);
+            goto end;
+        }
+        if (NID_id_PasswordBasedMAC != OBJ_obj2nid(algorOID)) {
+            CMPerr(0, CMP_R_WRONG_ALGORITHM_OID);
+            goto end;
+        }
+        pbm_str = (ASN1_STRING *)ppval;
+        pbm_str_uc = pbm_str->data;
+        pbm = d2i_OSSL_CRMF_PBMPARAMETER(NULL, &pbm_str_uc, pbm_str->length);
+        if (pbm == NULL) {
+            CMPerr(0, CMP_R_WRONG_ALGORITHM_OID);
+            goto end;
+        }
+
+        if (!OSSL_CRMF_pbm_new(pbm, prot_part_der, prot_part_der_len,
+                               secret->data, secret->length,
+                               &protection, &sig_len))
+            goto end;
+    } else if (secret == NULL && pkey != NULL) {
+        /* TODO combine this with large parts of CRMF_poposigningkey_init() */
+        /* EVP_DigestSignInit() checks that pkey type is correct for the alg */
+
+        if (!OBJ_find_sigid_algs(OBJ_obj2nid(algorOID), &md_NID, NULL)
+                || (md = EVP_get_digestbynid(md_NID)) == NULL
+                || (evp_ctx = EVP_MD_CTX_new()) == NULL) {
+            CMPerr(0, CMP_R_UNKNOWN_ALGORITHM_ID);
+            goto end;
+        }
+        if (EVP_DigestSignInit(evp_ctx, NULL, md, NULL, pkey) <= 0
+                || EVP_DigestSignUpdate(evp_ctx, prot_part_der,
+                                        prot_part_der_len) <= 0
+                || EVP_DigestSignFinal(evp_ctx, NULL, &sig_len) <= 0
+                || (protection = OPENSSL_malloc(sig_len)) == NULL
+                || EVP_DigestSignFinal(evp_ctx, protection, &sig_len) <= 0) {
+            CMPerr(0, CMP_R_ERROR_CALCULATING_PROTECTION);
+            goto end;
+        }
+    } else {
+        CMPerr(0, CMP_R_INVALID_ARGS);
+        goto end;
+    }
+
+    if ((prot = ASN1_BIT_STRING_new()) == NULL)
+        goto end;
+    /* OpenSSL defaults all bit strings to be encoded as ASN.1 NamedBitList */
+    prot->flags &= ~(ASN1_STRING_FLAG_BITS_LEFT | 0x07);
+    prot->flags |= ASN1_STRING_FLAG_BITS_LEFT;
+    if (!ASN1_BIT_STRING_set(prot, protection, sig_len)) {
+        ASN1_BIT_STRING_free(prot);
+        prot = NULL;
+    }
+
+ end:
+    OSSL_CRMF_PBMPARAMETER_free(pbm);
+    EVP_MD_CTX_free(evp_ctx);
+    OPENSSL_free(protection);
+    OPENSSL_free(prot_part_der);
+    return prot;
+}
+
+int ossl_cmp_msg_add_extraCerts(OSSL_CMP_CTX *ctx, OSSL_CMP_MSG *msg)
+{
+    if (!ossl_assert(ctx != NULL && msg != NULL))
+        return 0;
+
+    if (msg->extraCerts == NULL
+            && (msg->extraCerts = sk_X509_new_null()) == NULL)
+        return 0;
+
+    if (ctx->clCert != NULL) {
+        /* Make sure that our own cert gets sent, in the first position */
+        if (!X509_up_ref(ctx->clCert))
+            return 0;
+        if (!sk_X509_push(msg->extraCerts, ctx->clCert)) {
+            X509_free(ctx->clCert);
+            return 0;
+        }
+        /* if we have untrusted store, try to add intermediate certs */
+        if (ctx->untrusted_certs != NULL) {
+            STACK_OF(X509) *chain =
+                ossl_cmp_build_cert_chain(ctx->untrusted_certs, ctx->clCert);
+            int res = ossl_cmp_sk_X509_add1_certs(msg->extraCerts, chain,
+                                                  1 /* no self-signed */,
+                                                  1 /* no duplicates */, 0);
+            sk_X509_pop_free(chain, X509_free);
+            if (res == 0)
+                return 0;
+        }
+    }
+
+    /* add any additional certificates from ctx->extraCertsOut */
+    if (!ossl_cmp_sk_X509_add1_certs(msg->extraCerts, ctx->extraCertsOut, 0,
+                                     1 /* no duplicates */, 0))
+        return 0;
+
+    /* if none was found avoid empty ASN.1 sequence */
+    if (sk_X509_num(msg->extraCerts) == 0) {
+        sk_X509_free(msg->extraCerts);
+        msg->extraCerts = NULL;
+    }
+    return 1;
+}
+
+/*
+ * Create an X509_ALGOR structure for PasswordBasedMAC protection based on
+ * the pbm settings in the context
+ * returns pointer to X509_ALGOR on success, NULL on error
+ */
+static X509_ALGOR *create_pbmac_algor(OSSL_CMP_CTX *ctx)
+{
+    X509_ALGOR *alg = NULL;
+    OSSL_CRMF_PBMPARAMETER *pbm = NULL;
+    unsigned char *pbm_der = NULL;
+    int pbm_der_len;
+    ASN1_STRING *pbm_str = NULL;
+
+    if (!ossl_assert(ctx != NULL))
+        return NULL;
+
+    alg = X509_ALGOR_new();
+    pbm = OSSL_CRMF_pbmp_new(ctx->pbm_slen, ctx->pbm_owf, ctx->pbm_itercnt,
+                             ctx->pbm_mac);
+    pbm_str = ASN1_STRING_new();
+    if (alg == NULL || pbm == NULL || pbm_str == NULL)
+        goto err;
+
+    if ((pbm_der_len = i2d_OSSL_CRMF_PBMPARAMETER(pbm, &pbm_der)) < 0)
+        goto err;
+
+    if (!ASN1_STRING_set(pbm_str, pbm_der, pbm_der_len))
+        goto err;
+    OPENSSL_free(pbm_der);
+
+    X509_ALGOR_set0(alg, OBJ_nid2obj(NID_id_PasswordBasedMAC),
+                    V_ASN1_SEQUENCE, pbm_str);
+    OSSL_CRMF_PBMPARAMETER_free(pbm);
+    return alg;
+
+ err:
+    ASN1_STRING_free(pbm_str);
+    X509_ALGOR_free(alg);
+    OPENSSL_free(pbm_der);
+    OSSL_CRMF_PBMPARAMETER_free(pbm);
+    return NULL;
+}
+
+int ossl_cmp_msg_protect(OSSL_CMP_CTX *ctx, OSSL_CMP_MSG *msg)
+{
+    if (!ossl_assert(ctx != NULL && msg != NULL))
+        return 0;
+
+    if (ctx->unprotectedSend)
+        return 1;
+
+    /* use PasswordBasedMac according to 5.1.3.1 if secretValue is given */
+    if (ctx->secretValue != NULL) {
+        if ((msg->header->protectionAlg = create_pbmac_algor(ctx)) == NULL)
+            goto err;
+        if (ctx->referenceValue != NULL
+                && !ossl_cmp_hdr_set1_senderKID(msg->header,
+                                                ctx->referenceValue))
+            goto err;
+
+        /*
+         * add any additional certificates from ctx->extraCertsOut
+         * while not needed to validate the signing cert, the option to do
+         * this might be handy for certain use cases
+         */
+        if (!ossl_cmp_msg_add_extraCerts(ctx, msg))
+            goto err;
+
+        if ((msg->protection =
+             ossl_cmp_calc_protection(msg, ctx->secretValue, NULL)) == NULL)
+            goto err;
+    } else {
+        /*
+         * use MSG_SIG_ALG according to 5.1.3.3 if client Certificate and
+         * private key is given
+         */
+        if (ctx->clCert != NULL && ctx->pkey != NULL) {
+            const ASN1_OCTET_STRING *subjKeyIDStr = NULL;
+            int algNID = 0;
+            ASN1_OBJECT *alg = NULL;
+
+            /* make sure that key and certificate match */
+            if (!X509_check_private_key(ctx->clCert, ctx->pkey)) {
+                CMPerr(0, CMP_R_CERT_AND_KEY_DO_NOT_MATCH);
+                goto err;
+            }
+
+            if (msg->header->protectionAlg == NULL)
+                if ((msg->header->protectionAlg = X509_ALGOR_new()) == NULL)
+                    goto err;
+
+            if (!OBJ_find_sigid_by_algs(&algNID, ctx->digest,
+                                        EVP_PKEY_id(ctx->pkey))) {
+                CMPerr(0, CMP_R_UNSUPPORTED_KEY_TYPE);
+                goto err;
+            }
+            if ((alg = OBJ_nid2obj(algNID)) == NULL)
+                goto err;
+            if (!X509_ALGOR_set0(msg->header->protectionAlg,
+                                 alg, V_ASN1_UNDEF, NULL)) {
+                ASN1_OBJECT_free(alg);
+                goto err;
+            }
+
+            /*
+             * set senderKID to keyIdentifier of the used certificate according
+             * to section 5.1.1
+             */
+            subjKeyIDStr = X509_get0_subject_key_id(ctx->clCert);
+            if (subjKeyIDStr != NULL
+                    && !ossl_cmp_hdr_set1_senderKID(msg->header, subjKeyIDStr))
+                goto err;
+
+            /*
+             * Add ctx->clCert followed, if possible, by its chain built
+             * from ctx->untrusted_certs, and then ctx->extraCertsOut
+             */
+            if (!ossl_cmp_msg_add_extraCerts(ctx, msg))
+                goto err;
+
+            if ((msg->protection =
+                 ossl_cmp_calc_protection(msg, NULL, ctx->pkey)) == NULL)
+                goto err;
+        } else {
+            CMPerr(0, CMP_R_MISSING_KEY_INPUT_FOR_CREATING_PROTECTION);
+            goto err;
+        }
+    }
+
+    return 1;
+ err:
+    CMPerr(0, CMP_R_ERROR_PROTECTING_MESSAGE);
+    return 0;
+}
diff --git a/crypto/cmp/cmp_status.c b/crypto/cmp/cmp_status.c
index f6b7978a4f..a5f6b29490 100644
--- a/crypto/cmp/cmp_status.c
+++ b/crypto/cmp/cmp_status.c
@@ -56,7 +56,7 @@ const char *ossl_cmp_PKIStatus_to_string(int status)
         return "PKIStatus: revocation notification - a revocation of the cert has occurred";
     case OSSL_CMP_PKISTATUS_keyUpdateWarning:
         return "PKIStatus: key update warning - update already done for the cert";
-    default: 
+    default:
         {
             char buf[40];
             BIO_snprintf(buf, sizeof(buf), "PKIStatus: invalid=%d", status);
@@ -299,4 +299,3 @@ OSSL_CMP_PKISI *ossl_cmp_statusinfo_new(int status, int fail_info,
     ASN1_UTF8STRING_free(utf8_text);
     return NULL;
 }
-
diff --git a/crypto/crmf/crmf_asn.c b/crypto/crmf/crmf_asn.c
index 4380156795..8b6657f969 100644
--- a/crypto/crmf/crmf_asn.c
+++ b/crypto/crmf/crmf_asn.c
@@ -235,6 +235,5 @@ IMPLEMENT_ASN1_FUNCTIONS(OSSL_CRMF_MSG)
 ASN1_ITEM_TEMPLATE(OSSL_CRMF_MSGS) =
     ASN1_EX_TEMPLATE_TYPE(ASN1_TFLG_SEQUENCE_OF, 0,
                           OSSL_CRMF_MSGS, OSSL_CRMF_MSG)
-    ASN1_ITEM_TEMPLATE_END(OSSL_CRMF_MSGS)
+ASN1_ITEM_TEMPLATE_END(OSSL_CRMF_MSGS)
 IMPLEMENT_ASN1_FUNCTIONS(OSSL_CRMF_MSGS)
-
diff --git a/crypto/crmf/crmf_lib.c b/crypto/crmf/crmf_lib.c
index 6ba3f7ab3f..64dbf80978 100644
--- a/crypto/crmf/crmf_lib.c
+++ b/crypto/crmf/crmf_lib.c
@@ -97,10 +97,10 @@ static int OSSL_CRMF_MSG_push0_regCtrl(OSSL_CRMF_MSG *crm,
     return 0;
 }
 
- /* id-regCtrl-regToken Control (section 6.1) */
+/* id-regCtrl-regToken Control (section 6.1) */
 IMPLEMENT_CRMF_CTRL_FUNC(regToken, ASN1_STRING, regCtrl)
 
- /* id-regCtrl-authenticator Control (section 6.2) */
+/* id-regCtrl-authenticator Control (section 6.2) */
 #define ASN1_UTF8STRING_dup ASN1_STRING_dup
 IMPLEMENT_CRMF_CTRL_FUNC(authenticator, ASN1_UTF8STRING, regCtrl)
 
@@ -153,11 +153,11 @@ int OSSL_CRMF_MSG_set_PKIPublicationInfo_action(
     return ASN1_INTEGER_set(pi->action, action);
 }
 
- /* id-regCtrl-pkiPublicationInfo Control (section 6.3) */
+/* id-regCtrl-pkiPublicationInfo Control (section 6.3) */
 IMPLEMENT_CRMF_CTRL_FUNC(pkiPublicationInfo, OSSL_CRMF_PKIPUBLICATIONINFO,
                          regCtrl)
 
- /* id-regCtrl-oldCertID Control (section 6.5) from the given */
+/* id-regCtrl-oldCertID Control (section 6.5) from the given */
 IMPLEMENT_CRMF_CTRL_FUNC(oldCertID, OSSL_CRMF_CERTID, regCtrl)
 
 OSSL_CRMF_CERTID *OSSL_CRMF_CERTID_gen(const X509_NAME *issuer,
@@ -188,10 +188,9 @@ OSSL_CRMF_CERTID *OSSL_CRMF_CERTID_gen(const X509_NAME *issuer,
     return NULL;
 }
 
- /*
-  * id-regCtrl-protocolEncrKey Control (section 6.6)
-  *
-  */
+/*
+ * id-regCtrl-protocolEncrKey Control (section 6.6)
+ */
 IMPLEMENT_CRMF_CTRL_FUNC(protocolEncrKey, X509_PUBKEY, regCtrl)
 
 /*-
@@ -567,7 +566,7 @@ int OSSL_CRMF_MSGS_verify_popo(const OSSL_CRMF_MSGS *reqs,
          * return 1 if the type of req->popo->value.keyEncipherment
          * is OSSL_CRMF_POPOPRIVKEY_SUBSEQUENTMESSAGE and
          * its value.subsequentMessage == OSSL_CRMF_SUBSEQUENTMESSAGE_ENCRCERT
-        */
+         */
     case OSSL_CRMF_POPO_KEYAGREE:
     default:
         CRMFerr(CRMF_F_OSSL_CRMF_MSGS_VERIFY_POPO,
@@ -702,7 +701,7 @@ X509 *OSSL_CRMF_ENCRYPTEDVALUE_get1_encCert(OSSL_CRMF_ENCRYPTEDVALUE *ecert,
     if ((iv = OPENSSL_malloc(EVP_CIPHER_iv_length(cipher))) == NULL)
         goto end;
     if (ASN1_TYPE_get_octetstring(ecert->symmAlg->parameter, iv,
-                                   EVP_CIPHER_iv_length(cipher))
+                                  EVP_CIPHER_iv_length(cipher))
         != EVP_CIPHER_iv_length(cipher)) {
         CRMFerr(CRMF_F_OSSL_CRMF_ENCRYPTEDVALUE_GET1_ENCCERT,
                 CRMF_R_MALFORMED_IV);
diff --git a/crypto/crmf/crmf_local.h b/crypto/crmf/crmf_local.h
index 577187f55b..06b32b5378 100644
--- a/crypto/crmf/crmf_local.h
+++ b/crypto/crmf/crmf_local.h
@@ -217,7 +217,7 @@ struct ossl_crmf_pbmparameter_st {
     ASN1_INTEGER *iterationCount;
     X509_ALGOR *mac;
 } /* OSSL_CRMF_PBMPARAMETER */;
-#define OSSL_CRMF_PBM_MAX_ITERATION_COUNT 100000 /* if too large allows DoS */
+# define OSSL_CRMF_PBM_MAX_ITERATION_COUNT 100000 /* if too large allows DoS */
 
 /*-
  * POPOSigningKeyInput ::= SEQUENCE {
@@ -232,7 +232,7 @@ struct ossl_crmf_pbmparameter_st {
  *   -- on the DER-encoded value of publicKey
  * publicKey      SubjectPublicKeyInfo  -- from CertTemplate
  * }
-*/
+ */
 typedef struct ossl_crmf_poposigningkeyinput_authinfo_st {
     int type;
     union {
diff --git a/crypto/crmf/crmf_pbm.c b/crypto/crmf/crmf_pbm.c
index c5e08c47de..2dfa84e49b 100644
--- a/crypto/crmf/crmf_pbm.c
+++ b/crypto/crmf/crmf_pbm.c
@@ -133,8 +133,7 @@ int OSSL_CRMF_pbm_new(const OSSL_CRMF_PBMPARAMETER *pbmp,
     int ok = 0;
     EVP_MAC *mac = NULL;
     EVP_MAC_CTX *mctx = NULL;
-    OSSL_PARAM macparams[3] =
-        { OSSL_PARAM_END, OSSL_PARAM_END, OSSL_PARAM_END };
+    OSSL_PARAM macparams[3] = {OSSL_PARAM_END, OSSL_PARAM_END, OSSL_PARAM_END};
 
     if (out == NULL || pbmp == NULL || pbmp->mac == NULL
             || pbmp->mac->algorithm == NULL || msg == NULL || sec == NULL) {
@@ -193,16 +192,15 @@ int OSSL_CRMF_pbm_new(const OSSL_CRMF_PBMPARAMETER *pbmp,
     mac_nid = OBJ_obj2nid(pbmp->mac->algorithm);
 
     if (!EVP_PBE_find(EVP_PBE_TYPE_PRF, mac_nid, NULL, &hmac_md_nid, NULL)
-        || ((mdname = OBJ_nid2sn(hmac_md_nid)) == NULL)) {
+            || (mdname = OBJ_nid2sn(hmac_md_nid)) == NULL) {
         CRMFerr(CRMF_F_OSSL_CRMF_PBM_NEW, CRMF_R_UNSUPPORTED_ALGORITHM);
         goto err;
     }
 
-    macparams[0] =
-        OSSL_PARAM_construct_utf8_string(OSSL_MAC_PARAM_DIGEST,
-                                         (char *)mdname, 0);
-    macparams[1] =
-        OSSL_PARAM_construct_octet_string(OSSL_MAC_PARAM_KEY, basekey, bklen);
+    macparams[0] = OSSL_PARAM_construct_utf8_string(OSSL_MAC_PARAM_DIGEST,
+                                                    (char *)mdname, 0);
+    macparams[1] = OSSL_PARAM_construct_octet_string(OSSL_MAC_PARAM_KEY,
+                                                     basekey, bklen);
     if ((mac = EVP_MAC_fetch(NULL, "HMAC", NULL)) == NULL
             || (mctx = EVP_MAC_CTX_new(mac)) == NULL
             || !EVP_MAC_CTX_set_params(mctx, macparams)
diff --git a/crypto/err/openssl.txt b/crypto/err/openssl.txt
index a39b65382d..70dca14925 100644
--- a/crypto/err/openssl.txt
+++ b/crypto/err/openssl.txt
@@ -2066,13 +2066,43 @@ BN_R_PRIVATE_KEY_TOO_LARGE:117:private key too large
 BN_R_P_IS_NOT_PRIME:112:p is not prime
 BN_R_TOO_MANY_ITERATIONS:113:too many iterations
 BN_R_TOO_MANY_TEMPORARY_VARIABLES:109:too many temporary variables
+CMP_R_BAD_REQUEST_ID:108:bad request id
+CMP_R_CERTID_NOT_FOUND:109:certid not found
+CMP_R_CERTIFICATE_NOT_FOUND:112:certificate 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
+CMP_R_ERROR_CREATING_CERTCONF:116:error creating certconf
+CMP_R_ERROR_CREATING_CERTREP:117:error creating certrep
+CMP_R_ERROR_CREATING_ERROR:118:error creating error
+CMP_R_ERROR_CREATING_GENM:119:error creating genm
+CMP_R_ERROR_CREATING_GENP:120:error creating genp
+CMP_R_ERROR_CREATING_P10CR:121:error creating p10cr
+CMP_R_ERROR_CREATING_PKICONF:122:error creating pkiconf
+CMP_R_ERROR_CREATING_POLLREP:123:error creating pollrep
+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_PROTECTING_MESSAGE:127:error protecting message
+CMP_R_ERROR_SETTING_CERTHASH:128:error setting certhash
 CMP_R_FAILURE_OBTAINING_RANDOM:110:failure obtaining random
+CMP_R_FAIL_INFO_OUT_OF_RANGE:129:fail info out of range
 CMP_R_INVALID_ARGS:100:invalid args
-CMP_R_MULTIPLE_SAN_SOURCES:102:multiple san sources
+CMP_R_MISSING_KEY_INPUT_FOR_CREATING_PROTECTION:130:\
+	missing key input for creating protection
+CMP_R_MISSING_PRIVATE_KEY:131:missing private key
 CMP_R_MISSING_SENDER_IDENTIFICATION:111:missing sender identification
+CMP_R_MULTIPLE_SAN_SOURCES:102:multiple san sources
 CMP_R_NO_STDIO:194:no stdio
 CMP_R_NULL_ARGUMENT:103:null argument
+CMP_R_PKISTATUSINFO_NOT_FOUND:132:pkistatusinfo not found
+CMP_R_UNEXPECTED_PKIBODY:133:unexpected pkibody
+CMP_R_UNKNOWN_ALGORITHM_ID:134:unknown algorithm id
+CMP_R_UNKNOWN_CERT_TYPE:135:unknown cert type
+CMP_R_UNSUPPORTED_ALGORITHM:136:unsupported algorithm
+CMP_R_UNSUPPORTED_KEY_TYPE:137:unsupported key type
+CMP_R_WRONG_ALGORITHM_OID:138:wrong algorithm oid
 CMS_R_ADD_SIGNER_ERROR:99:add signer error
 CMS_R_ATTRIBUTE_ERROR:161:attribute error
 CMS_R_CERTIFICATE_ALREADY_PRESENT:175:certificate already present
diff --git a/doc/man3/OSSL_CMP_MSG_get0_header.pod b/doc/man3/OSSL_CMP_MSG_get0_header.pod
new file mode 100644
index 0000000000..3ed1140082
--- /dev/null
+++ b/doc/man3/OSSL_CMP_MSG_get0_header.pod
@@ -0,0 +1,40 @@
+=pod
+
+=head1 NAME
+
+OSSL_CMP_MSG_get0_header
+- function(s) manipulating CMP messages
+
+=head1 SYNOPSIS
+
+  #include <openssl/cmp.h>
+
+  OSSL_CMP_PKIHEADER *OSSL_CMP_MSG_get0_header(const OSSL_CMP_MSG *msg);
+
+=head1 DESCRIPTION
+
+OSSL_CMP_MSG_get0_header returns the header of the given CMP message.
+
+=head1 NOTES
+
+CMP is defined in RFC 4210.
+
+=head1 RETURN VALUES
+
+CMP_MSG_get0_header() returns the intended pointer value as described above
+or NULL if the respective entry does not exist and 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/include/openssl/cmp.h b/include/openssl/cmp.h
index 409d48515f..d778842b3b 100644
--- a/include/openssl/cmp.h
+++ b/include/openssl/cmp.h
@@ -264,7 +264,7 @@ int OSSL_CMP_CTX_set_option(OSSL_CMP_CTX *ctx, int opt, int val);
 int OSSL_CMP_CTX_get_option(const OSSL_CMP_CTX *ctx, int opt);
 /* CMP-specific callback for logging and outputting the error queue: */
 int OSSL_CMP_CTX_set_log_cb(OSSL_CMP_CTX *ctx, OSSL_cmp_log_cb_t cb);
-#define OSSL_CMP_CTX_set_log_verbosity(ctx, level) \
+#  define OSSL_CMP_CTX_set_log_verbosity(ctx, level) \
     OSSL_CMP_CTX_set_option(ctx, OSSL_CMP_OPT_LOG_VERBOSITY, level)
 void OSSL_CMP_CTX_print_errors(OSSL_CMP_CTX *ctx);
 /* message transfer: */
@@ -346,8 +346,12 @@ char *OSSL_CMP_CTX_snprint_PKIStatus(OSSL_CMP_CTX *ctx, char *buf,
 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);
 
-#   ifdef  __cplusplus
+/* 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);
+
+#  ifdef  __cplusplus
 }
-#   endif
+#  endif
 # 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 fa5cee5e0c..ee368afa60 100644
--- a/include/openssl/cmp_util.h
+++ b/include/openssl/cmp_util.h
@@ -26,13 +26,12 @@ extern "C" {
 /*
  * convenience functions for CMP-specific logging via the trace API
  */
-
 int  OSSL_CMP_log_open(void);
 void OSSL_CMP_log_close(void);
 #  define OSSL_CMP_LOG_PREFIX "CMP "
 /* in OSSL_CMP_LOG_START, cannot use OPENSSL_FUNC when expands to __func__ */
 #  define OSSL_CMP_LOG_START "%s:" OPENSSL_FILE ":" \
-                             OPENSSL_MSTR(OPENSSL_LINE) ":" OSSL_CMP_LOG_PREFIX
+    OPENSSL_MSTR(OPENSSL_LINE) ":" OSSL_CMP_LOG_PREFIX
 #  define OSSL_CMP_alert(msg) OSSL_CMP_log(ALERT, msg)
 #  define OSSL_CMP_err(msg)   OSSL_CMP_log(ERROR, msg)
 #  define OSSL_CMP_warn(msg)  OSSL_CMP_log(WARN, msg)
@@ -72,8 +71,8 @@ typedef int (*OSSL_cmp_log_cb_t)(const char *func, const char *file, int line,
 /* use of the logging callback for outputting error queue */
 void OSSL_CMP_print_errors_cb(OSSL_cmp_log_cb_t log_fn);
 
-#   ifdef  __cplusplus
+#  ifdef  __cplusplus
 }
-#   endif
+#  endif
 # endif /* !defined OPENSSL_NO_CMP */
 #endif /* !defined OPENSSL_CMP_UTIL_H */
diff --git a/include/openssl/cmperr.h b/include/openssl/cmperr.h
index 7da9a17829..b21db04ee8 100644
--- a/include/openssl/cmperr.h
+++ b/include/openssl/cmperr.h
@@ -33,13 +33,42 @@ int ERR_load_CMP_strings(void);
 /*
  * CMP reason codes.
  */
+#  define CMP_R_BAD_REQUEST_ID                             108
+#  define CMP_R_CERTID_NOT_FOUND                           109
+#  define CMP_R_CERTIFICATE_NOT_FOUND                      112
+#  define CMP_R_CERTRESPONSE_NOT_FOUND                     113
+#  define CMP_R_CERT_AND_KEY_DO_NOT_MATCH                  114
+#  define CMP_R_ERROR_CALCULATING_PROTECTION               115
+#  define CMP_R_ERROR_CREATING_CERTCONF                    116
+#  define CMP_R_ERROR_CREATING_CERTREP                     117
+#  define CMP_R_ERROR_CREATING_ERROR                       118
+#  define CMP_R_ERROR_CREATING_GENM                        119
+#  define CMP_R_ERROR_CREATING_GENP                        120
+#  define CMP_R_ERROR_CREATING_P10CR                       121
+#  define CMP_R_ERROR_CREATING_PKICONF                     122
+#  define CMP_R_ERROR_CREATING_POLLREP                     123
+#  define CMP_R_ERROR_CREATING_POLLREQ                     124
+#  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_PROTECTING_MESSAGE                   127
+#  define CMP_R_ERROR_SETTING_CERTHASH                     128
 #  define CMP_R_FAILURE_OBTAINING_RANDOM                   110
+#  define CMP_R_FAIL_INFO_OUT_OF_RANGE                     129
 #  define CMP_R_INVALID_ARGS                               100
-#  define CMP_R_MULTIPLE_SAN_SOURCES                       102
+#  define CMP_R_MISSING_KEY_INPUT_FOR_CREATING_PROTECTION  130
+#  define CMP_R_MISSING_PRIVATE_KEY                        131
 #  define CMP_R_MISSING_SENDER_IDENTIFICATION              111
+#  define CMP_R_MULTIPLE_SAN_SOURCES                       102
 #  define CMP_R_NO_STDIO                                   194
 #  define CMP_R_NULL_ARGUMENT                              103
+#  define CMP_R_PKISTATUSINFO_NOT_FOUND                    132
+#  define CMP_R_UNEXPECTED_PKIBODY                         133
+#  define CMP_R_UNKNOWN_ALGORITHM_ID                       134
+#  define CMP_R_UNKNOWN_CERT_TYPE                          135
+#  define CMP_R_UNSUPPORTED_ALGORITHM                      136
+#  define CMP_R_UNSUPPORTED_KEY_TYPE                       137
+#  define CMP_R_WRONG_ALGORITHM_OID                        138
 
 # endif
 #endif
diff --git a/test/build.info b/test/build.info
index df6cc713fe..0be3ee078c 100644
--- a/test/build.info
+++ b/test/build.info
@@ -481,7 +481,8 @@ IF[{- !$disabled{tests} -}]
   DEPEND[conf_include_test]=../libcrypto libtestutil.a
 
   IF[{- !$disabled{cmp} -}]
-    PROGRAMS{noinst}=cmp_asn_test cmp_ctx_test cmp_status_test cmp_hdr_test
+    PROGRAMS{noinst}=cmp_asn_test cmp_ctx_test cmp_status_test cmp_hdr_test \
+                     cmp_protect_test cmp_msg_test
   ENDIF
 
   SOURCE[cmp_asn_test]=cmp_asn_test.c cmp_testlib.c
@@ -500,6 +501,14 @@ IF[{- !$disabled{tests} -}]
   INCLUDE[cmp_status_test]=.. ../include ../apps/include
   DEPEND[cmp_status_test]=../libcrypto.a libtestutil.a
 
+  SOURCE[cmp_protect_test]=cmp_status_test.c cmp_testlib.c
+  INCLUDE[cmp_protect_test]=.. ../include ../apps/include
+  DEPEND[cmp_protect_test]=../libcrypto.a libtestutil.a
+
+  SOURCE[cmp_msg_test]=cmp_status_test.c cmp_testlib.c
+  INCLUDE[cmp_msg_test]=.. ../include ../apps/include
+  DEPEND[cmp_msg_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_asn_test.c b/test/cmp_asn_test.c
index 9a224f3a56..10661b3ff0 100644
--- a/test/cmp_asn_test.c
+++ b/test/cmp_asn_test.c
@@ -40,8 +40,7 @@ static void tear_down(CMP_ASN_TEST_FIXTURE *fixture)
     OPENSSL_free(fixture);
 }
 
-static int execute_cmp_asn1_get_int_test(CMP_ASN_TEST_FIXTURE *
-                                                   fixture)
+static int execute_cmp_asn1_get_int_test(CMP_ASN_TEST_FIXTURE *fixture)
 {
     ASN1_INTEGER *asn1integer = ASN1_INTEGER_new();
     ASN1_INTEGER_set(asn1integer, 77);
@@ -115,8 +114,10 @@ int setup_tests(void)
     ADD_TEST(test_cmp_asn1_get_int);
     ADD_TEST(test_ASN1_OCTET_STRING_set);
     ADD_TEST(test_ASN1_OCTET_STRING_set_tgt_is_src);
-    /* 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. */
+    /*
+     * 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.
+     */
 
     return 1;
 }
diff --git a/test/cmp_ctx_test.c b/test/cmp_ctx_test.c
index d7a3edb140..627df72182 100644
--- a/test/cmp_ctx_test.c
+++ b/test/cmp_ctx_test.c
@@ -39,7 +39,8 @@ static OSSL_CMP_CTX_TEST_FIXTURE *set_up(const char *const test_case_name)
     return fixture;
 }
 
-static STACK_OF(X509) *sk_X509_new_1(void) {
+static STACK_OF(X509) *sk_X509_new_1(void)
+{
     STACK_OF(X509) *sk = sk_X509_new_null();
     X509 *x = X509_new();
 
@@ -51,7 +52,8 @@ static STACK_OF(X509) *sk_X509_new_1(void) {
     return sk;
 }
 
-static void sk_X509_pop_X509_free(STACK_OF(X509) *sk) {
+static void sk_X509_pop_X509_free(STACK_OF(X509) *sk)
+{
     sk_X509_pop_free(sk, X509_free);
 }
 
@@ -75,7 +77,6 @@ static int execute_CTX_reinit_test(OSSL_CMP_CTX_TEST_FIXTURE *fixture)
             || !OSSL_CMP_CTX_set1_transactionID(ctx, bytes)
             || !OSSL_CMP_CTX_set1_senderNonce(ctx, bytes)
             || !ossl_cmp_ctx_set1_recipNonce(ctx, bytes))
-
         goto err;
 
     if (!TEST_true(OSSL_CMP_CTX_reinit(ctx)))
@@ -335,7 +336,7 @@ static int execute_CTX_##SETN##_##GETN##_##FIELD( \
     CMP_CTX *ctx = fixture->ctx; \
     int (*set_fn)(CMP_CTX *ctx, TYPE) = \
         (int (*)(CMP_CTX *ctx, TYPE))PREFIX##_##SETN##_##FIELD; \
- /* need type cast in above assignment because TYPE arg sometimes is const */ \
+    /* need type cast in above assignment because TYPE arg sometimes is const */ \
     TYPE (*get_fn)(const CMP_CTX *ctx) = OSSL_CMP_CTX_##GETN##_##FIELD; \
     TYPE val1_to_free = NEW; \
     TYPE val1 = val1_to_free; \
@@ -467,17 +468,20 @@ static int test_CTX_##SETN##_##GETN##_##FIELD(void) \
     return result; \
 }
 
-static char *char_new(void) {
+static char *char_new(void)
+{
     return OPENSSL_strdup("test");
 }
 
-static void char_free(char *val) {
+static void char_free(char *val)
+{
     OPENSSL_free(val);
 }
 
 #define EMPTY_SK_X509(x) ((x) == NULL || sk_X509_num(x) == 0)
 
-static X509_STORE *X509_STORE_new_1(void) {
+static X509_STORE *X509_STORE_new_1(void)
+{
     X509_STORE *store = X509_STORE_new();
 
     if (store != NULL)
@@ -497,24 +501,24 @@ static X509_STORE *X509_STORE_new_1(void) {
 
 #define DEFINE_SET_GET_TEST(OSSL_CMP, CTX, N, M, DUP, FIELD, TYPE) \
     DEFINE_SET_GET_BASE_TEST(OSSL_CMP##_##CTX, set##N, get##M, DUP, FIELD, \
-                              TYPE*, NULL, IS_0, TYPE##_new(), TYPE##_free)
+                             TYPE*, NULL, IS_0, TYPE##_new(), TYPE##_free)
 
 #define DEFINE_SET_GET_SK_TEST_DEFAULT(OSSL_CMP, CTX, N, M, FIELD, ELEM_TYPE, \
                                        DEFAULT, NEW, FREE) \
     DEFINE_SET_GET_BASE_TEST(OSSL_CMP##_##CTX, set##N, get##M, 1, FIELD, \
-                              STACK_OF(ELEM_TYPE)*, NULL, DEFAULT, NEW, FREE)
+                             STACK_OF(ELEM_TYPE)*, NULL, DEFAULT, NEW, FREE)
 #define DEFINE_SET_GET_SK_TEST(OSSL_CMP, CTX, N, M, FIELD, T) \
     DEFINE_SET_GET_SK_TEST_DEFAULT(OSSL_CMP, CTX, N, M, FIELD, T, \
-                                    IS_0, sk_##T##_new_null(), sk_##T##_free)
+                                   IS_0, sk_##T##_new_null(), sk_##T##_free)
 #define DEFINE_SET_GET_SK_X509_TEST(OSSL_CMP, CTX, N, M, FNAME) \
     DEFINE_SET_GET_SK_TEST_DEFAULT(OSSL_CMP, CTX, N, M, FNAME, X509, \
-                                    EMPTY_SK_X509, \
-                                    sk_X509_new_1(), sk_X509_pop_X509_free)
+                                   EMPTY_SK_X509, \
+                                   sk_X509_new_1(), sk_X509_pop_X509_free)
 
 #define DEFINE_SET_GET_TEST_DEFAULT(OSSL_CMP, CTX, N, M, DUP, FIELD, TYPE, \
                                     DEFAULT) \
     DEFINE_SET_GET_BASE_TEST(OSSL_CMP##_##CTX, set##N, get##M, DUP, FIELD, \
-                              TYPE*, NULL, DEFAULT, TYPE##_new(), TYPE##_free)
+                             TYPE*, NULL, DEFAULT, TYPE##_new(), TYPE##_free)
 #define DEFINE_SET_TEST_DEFAULT(OSSL_CMP, CTX, N, DUP, FIELD, TYPE, DEFAULT) \
     static TYPE *OSSL_CMP_CTX_get0_##FIELD(const CMP_CTX *ctx) \
     { \
@@ -530,27 +534,26 @@ static X509_STORE *X509_STORE_new_1(void) {
         return ctx == NULL ? ERR(NULL) : ctx->FIELD; \
     } \
     DEFINE_SET_GET_BASE_TEST(OSSL_CMP##_##CTX, set##N, get0, 1, FIELD, \
-                              STACK_OF(TYPE)*, NULL, IS_0, \
-                              sk_##TYPE##_new_null(), sk_##TYPE##_free)
+                             STACK_OF(TYPE)*, NULL, IS_0, \
+                             sk_##TYPE##_new_null(), sk_##TYPE##_free)
 
 #define DEFINE_SET_CB_TEST(FIELD) \
-    static OSSL_cmp_##FIELD##_t \
-        OSSL_CMP_CTX_get_##FIELD(const CMP_CTX *ctx) \
+    static OSSL_cmp_##FIELD##_t OSSL_CMP_CTX_get_##FIELD(const CMP_CTX *ctx) \
     { \
         if (ctx == NULL) \
             CMPerr(0, CMP_R_NULL_ARGUMENT); \
         return ctx == NULL ? NULL /* cannot use ERR(NULL) here */ : ctx->FIELD;\
     } \
     DEFINE_SET_GET_BASE_TEST(OSSL_CMP_CTX, set, get, 0, FIELD, \
-                              OSSL_cmp_##FIELD##_t, NULL, IS_0, \
-                              test_##FIELD, DROP)
+                             OSSL_cmp_##FIELD##_t, NULL, IS_0, \
+                             test_##FIELD, DROP)
 #define DEFINE_SET_GET_P_VOID_TEST(FIELD) \
     DEFINE_SET_GET_BASE_TEST(OSSL_CMP_CTX, set, get, 0, FIELD, void*, \
-                              NULL, IS_0, ((void *)1), DROP)
+                             NULL, IS_0, ((void *)1), DROP)
 
 #define DEFINE_SET_GET_INT_TEST_DEFAULT(OSSL_CMP, CTX, FIELD, DEFAULT) \
     DEFINE_SET_GET_BASE_TEST(OSSL_CMP##_##CTX, set, get, 0, FIELD, int, -1, \
-                              DEFAULT, 1, DROP)
+                             DEFAULT, 1, DROP)
 #define DEFINE_SET_GET_INT_TEST(OSSL_CMP, CTX, FIELD) \
     DEFINE_SET_GET_INT_TEST_DEFAULT(OSSL_CMP, CTX, FIELD, IS_NEG)
 #define DEFINE_SET_PORT_TEST(FIELD) \
@@ -590,8 +593,9 @@ static X509_STORE *X509_STORE_new_1(void) {
 #define push0 0
 #define push1 1
 #define DEFINE_PUSH_BASE_TEST(PUSHN, DUP, FIELD, ELEM, TYPE, T, \
-                               DEFAULT, NEW, FREE) \
-static TYPE sk_top_##FIELD(const CMP_CTX *ctx) { \
+                              DEFAULT, NEW, FREE) \
+static TYPE sk_top_##FIELD(const CMP_CTX *ctx) \
+{ \
     return sk_##T##_value(ctx->FIELD, sk_##T##_num(ctx->FIELD) - 1); \
 } \
 \
@@ -600,7 +604,9 @@ static int execute_CTX_##PUSHN##_##ELEM(OSSL_CMP_CTX_TEST_FIXTURE *fixture) \
     CMP_CTX *ctx = fixture->ctx; \
     int (*push_fn)(CMP_CTX *ctx, TYPE) = \
         (int (*)(CMP_CTX *ctx, TYPE))OSSL_CMP_CTX_##PUSHN##_##ELEM; \
- /* need type cast in above assignment because TYPE arg sometimes is const */ \
+    /* \
+     * need type cast in above assignment because TYPE arg sometimes is const \
+     */ \
     int n_elem = sk_##T##_num(ctx->FIELD); \
     STACK_OF(TYPE) field_read; \
     TYPE val1_to_free = NEW; \
@@ -696,7 +702,7 @@ static int test_CTX_##PUSHN##_##ELEM(void) \
 
 #define DEFINE_PUSH_TEST(N, DUP, FIELD, ELEM, TYPE) \
     DEFINE_PUSH_BASE_TEST(push##N, DUP, FIELD, ELEM, TYPE*, TYPE, \
-                           IS_0, TYPE##_new(), TYPE##_free)
+                          IS_0, TYPE##_new(), TYPE##_free)
 
 void cleanup_tests(void)
 {
@@ -704,9 +710,9 @@ void cleanup_tests(void)
 }
 
 DEFINE_SET_GET_ARG_FN(set, get, option, 16, int)
-                                    /* option == OSSL_CMP_OPT_IGNORE_KEYUSAGE */
+/* option == OSSL_CMP_OPT_IGNORE_KEYUSAGE */
 DEFINE_SET_GET_BASE_TEST(OSSL_CMP_CTX, set, get, 0, option_16, int, -1, IS_0, \
-                          1 /* true */, DROP)
+                         1 /* true */, DROP)
 
 #ifndef OPENSSL_NO_TRACE
 DEFINE_SET_CB_TEST(log_cb)
@@ -726,8 +732,8 @@ DEFINE_SET_TEST(OSSL_CMP, CTX, 1, 0, srvCert, X509)
 DEFINE_SET_TEST(ossl_cmp, ctx, 0, 0, validatedSrvCert, X509)
 DEFINE_SET_TEST(OSSL_CMP, CTX, 1, 1, expected_sender, X509_NAME)
 DEFINE_SET_GET_BASE_TEST(OSSL_CMP_CTX, set0, get0, 0, trustedStore,
-                          X509_STORE*, NULL,
-                          DEFAULT_STORE, X509_STORE_new_1(), X509_STORE_free)
+                         X509_STORE*, NULL,
+                         DEFAULT_STORE, X509_STORE_new_1(), X509_STORE_free)
 DEFINE_SET_GET_SK_X509_TEST(OSSL_CMP, CTX, 1, 0, untrusted_certs)
 
 DEFINE_SET_TEST(OSSL_CMP, CTX, 1, 0, clCert, X509)
@@ -741,11 +747,10 @@ DEFINE_SET_GET_TEST(OSSL_CMP, CTX, 0, 0, 0, newPkey_1, EVP_PKEY)
 DEFINE_SET_GET_ARG_FN(set0, get0, newPkey, 0, EVP_PKEY*) /* priv == 0 */
 DEFINE_SET_GET_TEST(OSSL_CMP, CTX, 0, 0, 0, newPkey_0, EVP_PKEY)
 DEFINE_SET_GET1_STR_FN(set1, referenceValue)
-DEFINE_SET_GET_TEST_DEFAULT(OSSL_CMP, CTX, 1, 1, 1, referenceValue_str,
-                             char, IS_0)
+DEFINE_SET_GET_TEST_DEFAULT(OSSL_CMP, CTX, 1, 1, 1, referenceValue_str, char,
+                            IS_0)
 DEFINE_SET_GET1_STR_FN(set1, secretValue)
-DEFINE_SET_GET_TEST_DEFAULT(OSSL_CMP, CTX, 1, 1, 1, secretValue_str,
-                             char, IS_0)
+DEFINE_SET_GET_TEST_DEFAULT(OSSL_CMP, CTX, 1, 1, 1, secretValue_str, char, IS_0)
 DEFINE_SET_TEST(OSSL_CMP, CTX, 1, 1, issuer, X509_NAME)
 DEFINE_SET_TEST(OSSL_CMP, CTX, 1, 1, subjectName, X509_NAME)
 #ifdef ISSUE_9504_RESOLVED
@@ -768,8 +773,8 @@ DEFINE_SET_GET_TEST(ossl_cmp, ctx, 0, 0, 0, newCert, X509)
 DEFINE_SET_GET_SK_X509_TEST(ossl_cmp, ctx, 1, 1, caPubs)
 DEFINE_SET_GET_SK_X509_TEST(ossl_cmp, ctx, 1, 1, extraCertsIn)
 
-DEFINE_SET_TEST_DEFAULT(OSSL_CMP, CTX, 1, 1, transactionID,
-                         ASN1_OCTET_STRING, IS_0)
+DEFINE_SET_TEST_DEFAULT(OSSL_CMP, CTX, 1, 1, transactionID, ASN1_OCTET_STRING,
+                        IS_0)
 DEFINE_SET_TEST(OSSL_CMP, CTX, 1, 1, senderNonce, ASN1_OCTET_STRING)
 DEFINE_SET_TEST(ossl_cmp, ctx, 1, 1, recipNonce, ASN1_OCTET_STRING)
 
@@ -779,9 +784,9 @@ int setup_tests(void)
     /* OSSL_CMP_CTX_free() is tested by tear_down() */
     ADD_TEST(test_CTX_reinit);
 
-/* various CMP options: */
+    /* various CMP options: */
     ADD_TEST(test_CTX_set_get_option_16);
-/* CMP-specific callback for logging and outputting the error queue: */
+    /* CMP-specific callback for logging and outputting the error queue: */
 #ifndef OPENSSL_NO_TRACE
     ADD_TEST(test_CTX_set_get_log_cb);
 #endif
@@ -793,13 +798,14 @@ int setup_tests(void)
      */
     ADD_TEST(test_cmp_ctx_log_cb);
 #if !defined(OPENSSL_NO_ERR) && !defined(OPENSSL_NO_AUTOERRINIT)
-    /* also tests OSSL_CMP_CTX_set_log_cb(), OSSL_CMP_print_errors_cb(),
-       ossl_cmp_add_error_txt(), and the macros
-       ossl_cmp_add_error_data and ossl_cmp_add_error_line:
-    */
+    /*
+     * also tests OSSL_CMP_CTX_set_log_cb(), OSSL_CMP_print_errors_cb(),
+     * ossl_cmp_add_error_txt(), and the macros
+     * ossl_cmp_add_error_data and ossl_cmp_add_error_line:
+     */
     ADD_TEST(test_CTX_print_errors);
 #endif
-/* message transfer: */
+    /* message transfer: */
     ADD_TEST(test_CTX_set1_get0_serverPath);
     ADD_TEST(test_CTX_set1_get0_serverName);
     ADD_TEST(test_CTX_set_get_serverPort);
@@ -809,29 +815,31 @@ int setup_tests(void)
     ADD_TEST(test_CTX_set_get_http_cb_arg);
     ADD_TEST(test_CTX_set_get_transfer_cb);
     ADD_TEST(test_CTX_set_get_transfer_cb_arg);
-/* server authentication: */
+    /* server authentication: */
     ADD_TEST(test_CTX_set1_get0_srvCert);
     ADD_TEST(test_CTX_set0_get0_validatedSrvCert);
     ADD_TEST(test_CTX_set1_get0_expected_sender);
     ADD_TEST(test_CTX_set0_get0_trustedStore);
     ADD_TEST(test_CTX_set1_get0_untrusted_certs);
-/* client authentication: */
+    /* client authentication: */
     ADD_TEST(test_CTX_set1_get0_clCert);
     ADD_TEST(test_CTX_set1_get0_pkey);
     /* the following two also test ossl_cmp_asn1_octet_string_set1_bytes(): */
     ADD_TEST(test_CTX_set1_get1_referenceValue_str);
     ADD_TEST(test_CTX_set1_get1_secretValue_str);
-/* CMP message header and extra certificates: */
+    /* CMP message header and extra certificates: */
     ADD_TEST(test_CTX_set1_get0_recipient);
     ADD_TEST(test_CTX_push0_geninfo_ITAV);
     ADD_TEST(test_CTX_set1_get0_extraCertsOut);
-/* certificate template: */
+    /* certificate template: */
     ADD_TEST(test_CTX_set0_get0_newPkey_1);
     ADD_TEST(test_CTX_set0_get0_newPkey_0);
     ADD_TEST(test_CTX_set1_get0_issuer);
     ADD_TEST(test_CTX_set1_get0_subjectName);
 #ifdef ISSUE_9504_RESOLVED
-/* test currently fails, see https://github.com/openssl/openssl/issues/9504 */
+    /*
+     * test currently fails, see https://github.com/openssl/openssl/issues/9504
+     */
     ADD_TEST(test_CTX_push1_subjectAltName);
 #endif
     ADD_TEST(test_CTX_set0_get0_reqExtensions);
@@ -839,28 +847,28 @@ int setup_tests(void)
     ADD_TEST(test_CTX_push0_policy);
     ADD_TEST(test_CTX_set1_get0_oldCert);
 #ifdef ISSUE_9504_RESOLVED
-/* test currently fails, see https://github.com/openssl/openssl/issues/9504 */
+    /*
+     * test currently fails, see https://github.com/openssl/openssl/issues/9504
+     */
     ADD_TEST(test_CTX_set1_get0_p10CSR);
 #endif
-/* misc body contents: */
+    /* misc body contents: */
     ADD_TEST(test_CTX_push0_genm_ITAV);
-/* certificate confirmation: */
+    /* certificate confirmation: */
     ADD_TEST(test_CTX_set_get_certConf_cb);
     ADD_TEST(test_CTX_set_get_certConf_cb_arg);
-/* result fetching: */
+    /* result fetching: */
     ADD_TEST(test_CTX_set_get_status);
     ADD_TEST(test_CTX_set0_get0_statusString);
     ADD_TEST(test_CTX_set_get_failInfoCode);
     ADD_TEST(test_CTX_set0_get0_newCert);
     ADD_TEST(test_CTX_set1_get1_caPubs);
     ADD_TEST(test_CTX_set1_get1_extraCertsIn);
-/* exported for testing and debugging purposes: */
+    /* exported for testing and debugging purposes: */
     /* the following three also test ossl_cmp_asn1_octet_string_set1(): */
     ADD_TEST(test_CTX_set1_get0_transactionID);
     ADD_TEST(test_CTX_set1_get0_senderNonce);
     ADD_TEST(test_CTX_set1_get0_recipNonce);
-
-    /* TODO ossl_cmp_build_cert_chain() will be tested with cmp_protect.c*/
-
+    /* ossl_cmp_build_cert_chain() is tested in cmp_protect.c */
     return 1;
 }
diff --git a/test/cmp_hdr_test.c b/test/cmp_hdr_test.c
index 4f1b4a5a79..a9b2aff79c 100644
--- a/test/cmp_hdr_test.c
+++ b/test/cmp_hdr_test.c
@@ -193,7 +193,9 @@ static int execute_HDR_set1_senderKID_test(CMP_HDR_TEST_FIXTURE *fixture)
     if (!TEST_ptr(senderKID))
         return 0;
 
-    ASN1_OCTET_STRING_set(senderKID, rand_data, sizeof(rand_data));
+    if (!TEST_int_eq(ASN1_OCTET_STRING_set(senderKID, rand_data,
+                                           sizeof(rand_data)), 1))
+        return 0;
     if (!TEST_int_eq(ossl_cmp_hdr_set1_senderKID(fixture->hdr, senderKID), 1))
         return 0;
     if (!TEST_int_eq(
@@ -372,7 +374,7 @@ static int execute_HDR_init_test(CMP_HDR_TEST_FIXTURE *fixture)
                 || !TEST_true(0 == ASN1_OCTET_STRING_cmp(
                         ossl_cmp_hdr_get0_senderNonce(fixture->hdr),
                         fixture->cmp_ctx->senderNonce))
-                || !TEST_true(0 ==  ASN1_OCTET_STRING_cmp(
+                || !TEST_true(0 == ASN1_OCTET_STRING_cmp(
                             OSSL_CMP_HDR_get0_transactionID(fixture->hdr),
                             fixture->cmp_ctx->transactionID)))
             goto err;
@@ -414,9 +416,9 @@ static int test_HDR_init_with_subject(void)
 
     fixture->expected = 1;
     if (!TEST_ptr(subject = X509_NAME_new())
-        || !TEST_true(X509_NAME_ADD(subject, "CN", "Common Name"))
-        || !TEST_true(OSSL_CMP_CTX_set1_subjectName(fixture->cmp_ctx,
-                                                    subject))) {
+            || !TEST_true(X509_NAME_ADD(subject, "CN", "Common Name"))
+            || !TEST_true(OSSL_CMP_CTX_set1_subjectName(fixture->cmp_ctx,
+                                                        subject))) {
         tear_down(fixture);
         fixture = NULL;
     }
@@ -461,8 +463,10 @@ int setup_tests(void)
     ADD_TEST(test_HDR_init);
     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. */
+    /*
+     *  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.
+     */
 
     return 1;
 }
diff --git a/test/cmp_msg_test.c b/test/cmp_msg_test.c
new file mode 100644
index 0000000000..103ff58af4
--- /dev/null
+++ b/test/cmp_msg_test.c
@@ -0,0 +1,577 @@
+/*
+ * 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
+ */
+
+#include "cmp_testlib.h"
+
+static const char *server_cert_f;
+static const char *pkcs10_f;
+
+typedef struct test_fixture {
+    const char *test_case_name;
+    OSSL_CMP_CTX *cmp_ctx;
+    /* for msg create tests */
+    int bodytype;
+    int err_code;
+    /* for certConf */
+    int fail_info;
+    /* for protection tests */
+    OSSL_CMP_MSG *msg;
+    int expected;
+    /* for error and response messages */
+    OSSL_CMP_PKISI *si;
+} CMP_MSG_TEST_FIXTURE;
+
+static unsigned char ref[CMP_TEST_REFVALUE_LENGTH];
+
+static void tear_down(CMP_MSG_TEST_FIXTURE *fixture)
+{
+    OSSL_CMP_CTX_free(fixture->cmp_ctx);
+    OSSL_CMP_MSG_free(fixture->msg);
+    OSSL_CMP_PKISI_free(fixture->si);
+    OPENSSL_free(fixture);
+}
+
+#define SET_OPT_UNPROTECTED_SEND(ctx, val) \
+    OSSL_CMP_CTX_set_option((ctx), OSSL_CMP_OPT_UNPROTECTED_SEND, (val))
+static CMP_MSG_TEST_FIXTURE *set_up(const char *const test_case_name)
+{
+    CMP_MSG_TEST_FIXTURE *fixture;
+
+    if (!TEST_ptr(fixture = OPENSSL_zalloc(sizeof(*fixture))))
+        return NULL;
+    fixture->test_case_name = test_case_name;
+
+    if (!TEST_ptr(fixture->cmp_ctx = OSSL_CMP_CTX_new())
+            || !TEST_true(SET_OPT_UNPROTECTED_SEND(fixture->cmp_ctx, 1))
+            || !TEST_true(OSSL_CMP_CTX_set1_referenceValue(fixture->cmp_ctx,
+                                                           ref, sizeof(ref)))) {
+        tear_down(fixture);
+        return NULL;
+    }
+    return fixture;
+}
+
+static EVP_PKEY *newkey = NULL;
+static X509 *cert = NULL;
+
+#define EXECUTE_MSG_CREATION_TEST(expr) \
+    do { \
+        OSSL_CMP_MSG *msg = NULL; \
+        int good = fixture->expected != 0 ? \
+            TEST_ptr(msg = (expr)) && TEST_true(valid_asn1_encoding(msg)) : \
+            TEST_ptr_null(msg = (expr)); \
+ \
+        OSSL_CMP_MSG_free(msg); \
+        return good; \
+    } while (0)
+
+/*-
+ * The following tests call a cmp message creation function.
+ * if fixture->expected != 0:
+ *         returns 1 if the message is created and syntactically correct.
+ * if fixture->expected == 0
+ *         returns 1 if message creation returns NULL
+ */
+static int execute_certreq_create_test(CMP_MSG_TEST_FIXTURE *fixture)
+{
+    EXECUTE_MSG_CREATION_TEST(ossl_cmp_certReq_new(fixture->cmp_ctx,
+                                                   fixture->bodytype,
+                                                   fixture->err_code));
+}
+
+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));
+}
+
+static int execute_rr_create_test(CMP_MSG_TEST_FIXTURE *fixture)
+{
+    EXECUTE_MSG_CREATION_TEST(ossl_cmp_rr_new(fixture->cmp_ctx));
+}
+
+static int execute_certconf_create_test(CMP_MSG_TEST_FIXTURE *fixture)
+{
+    EXECUTE_MSG_CREATION_TEST(ossl_cmp_certConf_new
+                              (fixture->cmp_ctx, fixture->fail_info, NULL));
+}
+
+static int execute_genm_create_test(CMP_MSG_TEST_FIXTURE *fixture)
+{
+    EXECUTE_MSG_CREATION_TEST(ossl_cmp_genm_new(fixture->cmp_ctx));
+}
+
+static int execute_pollreq_create_test(CMP_MSG_TEST_FIXTURE *fixture)
+{
+    EXECUTE_MSG_CREATION_TEST(ossl_cmp_pollReq_new(fixture->cmp_ctx, 4711));
+}
+
+static int execute_pkimessage_create_test(CMP_MSG_TEST_FIXTURE *fixture)
+{
+    EXECUTE_MSG_CREATION_TEST(ossl_cmp_msg_create
+                              (fixture->cmp_ctx, fixture->bodytype));
+}
+
+static int set1_newPkey(OSSL_CMP_CTX *ctx, EVP_PKEY* pkey)
+{
+    if (!EVP_PKEY_up_ref(pkey))
+        return 0;
+
+    if (!OSSL_CMP_CTX_set0_newPkey(ctx, 1, pkey)) {
+        EVP_PKEY_free(pkey);
+        return 0;
+    }
+    return 1;
+}
+
+static int test_cmp_create_ir_protection_set(void)
+{
+    SETUP_TEST_FIXTURE(CMP_MSG_TEST_FIXTURE, set_up);
+    OSSL_CMP_CTX *ctx = fixture->cmp_ctx;
+    unsigned char secret[16];
+
+    fixture->bodytype = OSSL_CMP_PKIBODY_IR;
+    fixture->err_code = CMP_R_ERROR_CREATING_IR;
+    fixture->expected = 1;
+    if (!TEST_int_eq(1, RAND_bytes(secret, sizeof(secret)))
+            || !TEST_true(SET_OPT_UNPROTECTED_SEND(ctx, 0))
+            || !TEST_true(set1_newPkey(ctx, newkey))
+            || !TEST_true(OSSL_CMP_CTX_set1_secretValue(ctx, secret,
+                                                        sizeof(secret)))) {
+        tear_down(fixture);
+        fixture = NULL;
+    }
+    EXECUTE_TEST(execute_certreq_create_test, tear_down);
+    return result;
+}
+
+static int test_cmp_create_ir_protection_fails(void)
+{
+    SETUP_TEST_FIXTURE(CMP_MSG_TEST_FIXTURE, set_up);
+    fixture->bodytype = OSSL_CMP_PKIBODY_IR;
+    fixture->err_code = CMP_R_ERROR_CREATING_IR;
+    fixture->expected = 0;
+    if (!TEST_true(OSSL_CMP_CTX_set1_pkey(fixture->cmp_ctx, newkey))
+            || !TEST_true(SET_OPT_UNPROTECTED_SEND(fixture->cmp_ctx, 0))
+            || !TEST_true(OSSL_CMP_CTX_set1_clCert(fixture->cmp_ctx, cert))) {
+        tear_down(fixture);
+        fixture = NULL;
+    }
+    EXECUTE_TEST(execute_certreq_create_test, tear_down);
+    return result;
+}
+
+static int test_cmp_create_cr_without_key(void)
+{
+    SETUP_TEST_FIXTURE(CMP_MSG_TEST_FIXTURE, set_up);
+    fixture->bodytype = OSSL_CMP_PKIBODY_CR;
+    fixture->err_code = CMP_R_ERROR_CREATING_CR;
+    fixture->expected = 0;
+    EXECUTE_TEST(execute_certreq_create_test, tear_down);
+    return result;
+}
+
+static int test_cmp_create_cr(void)
+{
+    SETUP_TEST_FIXTURE(CMP_MSG_TEST_FIXTURE, set_up);
+    fixture->bodytype = OSSL_CMP_PKIBODY_CR;
+    fixture->err_code = CMP_R_ERROR_CREATING_CR;
+    fixture->expected = 1;
+    if (!TEST_true(set1_newPkey(fixture->cmp_ctx, newkey))) {
+        tear_down(fixture);
+        fixture = NULL;
+    }
+    EXECUTE_TEST(execute_certreq_create_test, tear_down);
+    return result;
+}
+
+static int test_cmp_create_certreq_with_invalid_bodytype(void)
+{
+    SETUP_TEST_FIXTURE(CMP_MSG_TEST_FIXTURE, set_up);
+    fixture->bodytype = OSSL_CMP_PKIBODY_RR;
+    fixture->err_code = CMP_R_ERROR_CREATING_IR;
+    fixture->expected = 0;
+    if (!TEST_true(set1_newPkey(fixture->cmp_ctx, newkey))) {
+        tear_down(fixture);
+        fixture = NULL;
+    }
+    EXECUTE_TEST(execute_certreq_create_test, tear_down);
+    return result;
+}
+
+static int test_cmp_create_p10cr(void)
+{
+    SETUP_TEST_FIXTURE(CMP_MSG_TEST_FIXTURE, set_up);
+    OSSL_CMP_CTX *ctx = fixture->cmp_ctx;
+    X509_REQ *p10cr = NULL;
+
+    fixture->bodytype = OSSL_CMP_PKIBODY_P10CR;
+    fixture->err_code = CMP_R_ERROR_CREATING_P10CR;
+    fixture->expected = 1;
+    if (!TEST_ptr(p10cr = load_csr(pkcs10_f))
+            || !TEST_true(set1_newPkey(ctx, newkey))
+            || !TEST_true(OSSL_CMP_CTX_set1_p10CSR(ctx, p10cr))) {
+        tear_down(fixture);
+        fixture = NULL;
+    }
+    X509_REQ_free(p10cr);
+    EXECUTE_TEST(execute_certreq_create_test, tear_down);
+    return result;
+}
+
+static int test_cmp_create_p10cr_null(void)
+{
+    SETUP_TEST_FIXTURE(CMP_MSG_TEST_FIXTURE, set_up);
+    fixture->bodytype = OSSL_CMP_PKIBODY_P10CR;
+    fixture->err_code = CMP_R_ERROR_CREATING_P10CR;
+    fixture->expected = 0;
+    if (!TEST_true(set1_newPkey(fixture->cmp_ctx, newkey))) {
+        tear_down(fixture);
+        fixture = NULL;
+    }
+    EXECUTE_TEST(execute_certreq_create_test, tear_down);
+    return result;
+}
+
+static int test_cmp_create_kur(void)
+{
+    SETUP_TEST_FIXTURE(CMP_MSG_TEST_FIXTURE, set_up);
+    fixture->bodytype = OSSL_CMP_PKIBODY_KUR;
+    fixture->err_code = CMP_R_ERROR_CREATING_KUR;
+    fixture->expected = 1;
+    if (!TEST_true(set1_newPkey(fixture->cmp_ctx, newkey))
+            || !TEST_true(OSSL_CMP_CTX_set1_oldCert(fixture->cmp_ctx, cert))) {
+        tear_down(fixture);
+        fixture = NULL;
+    }
+    EXECUTE_TEST(execute_certreq_create_test, tear_down);
+    return result;
+}
+
+static int test_cmp_create_kur_without_oldcert(void)
+{
+    SETUP_TEST_FIXTURE(CMP_MSG_TEST_FIXTURE, set_up);
+    fixture->bodytype = OSSL_CMP_PKIBODY_KUR;
+    fixture->err_code = CMP_R_ERROR_CREATING_KUR;
+    fixture->expected = 0;
+    if (!TEST_true(set1_newPkey(fixture->cmp_ctx, newkey))) {
+        tear_down(fixture);
+        fixture = NULL;
+    }
+    EXECUTE_TEST(execute_certreq_create_test, tear_down);
+    return result;
+}
+
+static int test_cmp_create_certconf(void)
+{
+    SETUP_TEST_FIXTURE(CMP_MSG_TEST_FIXTURE, set_up);
+    fixture->fail_info = 0;
+    fixture->expected = 1;
+    if (!TEST_true(ossl_cmp_ctx_set0_newCert(fixture->cmp_ctx,
+                                             X509_dup(cert)))) {
+        tear_down(fixture);
+        fixture = NULL;
+    }
+    EXECUTE_TEST(execute_certconf_create_test, tear_down);
+    return result;
+}
+
+static int test_cmp_create_certconf_badAlg(void)
+{
+    SETUP_TEST_FIXTURE(CMP_MSG_TEST_FIXTURE, set_up);
+    fixture->fail_info = 1 << OSSL_CMP_PKIFAILUREINFO_badAlg;
+    fixture->expected = 1;
+    if (!TEST_true(ossl_cmp_ctx_set0_newCert(fixture->cmp_ctx,
+                                             X509_dup(cert)))) {
+        tear_down(fixture);
+        fixture = NULL;
+    }
+    EXECUTE_TEST(execute_certconf_create_test, tear_down);
+    return result;
+}
+
+static int test_cmp_create_certconf_fail_info_max(void)
+{
+    SETUP_TEST_FIXTURE(CMP_MSG_TEST_FIXTURE, set_up);
+    fixture->fail_info = 1 << OSSL_CMP_PKIFAILUREINFO_MAX;
+    fixture->expected = 1;
+    if (!TEST_true(ossl_cmp_ctx_set0_newCert(fixture->cmp_ctx,
+                                             X509_dup(cert)))) {
+        tear_down(fixture);
+        fixture = NULL;
+    }
+    EXECUTE_TEST(execute_certconf_create_test, tear_down);
+    return result;
+}
+
+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,
+                                          OSSL_CMP_PKIFAILUREINFO_systemFailure,
+                                          NULL);
+    fixture->err_code = -1;
+    fixture->expected = 1;      /* Expected: Message creation is successful */
+    if (!TEST_true(set1_newPkey(fixture->cmp_ctx, newkey))) {
+        tear_down(fixture);
+        fixture = NULL;
+    }
+    EXECUTE_TEST(execute_errormsg_create_test, tear_down);
+    return result;
+}
+
+
+static int test_cmp_create_pollreq(void)
+{
+    SETUP_TEST_FIXTURE(CMP_MSG_TEST_FIXTURE, set_up);
+    fixture->expected = 1;
+    EXECUTE_TEST(execute_pollreq_create_test, tear_down);
+    return result;
+}
+
+static int test_cmp_create_rr(void)
+{
+    SETUP_TEST_FIXTURE(CMP_MSG_TEST_FIXTURE, set_up);
+    fixture->expected = 1;
+    if (!TEST_true(OSSL_CMP_CTX_set1_oldCert(fixture->cmp_ctx, cert))) {
+        tear_down(fixture);
+        fixture = NULL;
+    }
+    EXECUTE_TEST(execute_rr_create_test, tear_down);
+    return result;
+}
+
+static int test_cmp_create_genm(void)
+{
+    OSSL_CMP_ITAV *iv = NULL;
+
+    SETUP_TEST_FIXTURE(CMP_MSG_TEST_FIXTURE, set_up);
+    fixture->expected = 1;
+    iv = OSSL_CMP_ITAV_create(OBJ_nid2obj(NID_id_it_implicitConfirm), NULL);
+    if (!TEST_true(SET_OPT_UNPROTECTED_SEND(fixture->cmp_ctx, 1))
+            || !TEST_ptr(iv)
+            || !TEST_true(OSSL_CMP_CTX_push0_genm_ITAV(fixture->cmp_ctx, iv))) {
+        OSSL_CMP_ITAV_free(iv);
+        tear_down(fixture);
+        fixture = NULL;
+    }
+
+    EXECUTE_TEST(execute_genm_create_test, tear_down);
+    return result;
+}
+
+static int execute_certrep_create(CMP_MSG_TEST_FIXTURE *fixture)
+{
+    OSSL_CMP_CERTREPMESSAGE *crepmsg = OSSL_CMP_CERTREPMESSAGE_new();
+    OSSL_CMP_CERTRESPONSE *read_cresp, *cresp = OSSL_CMP_CERTRESPONSE_new();
+    EVP_PKEY *privkey;
+    X509 *certfromresp = NULL;
+    int res = 0;
+
+    if (crepmsg == NULL || cresp == NULL)
+        goto err;
+    if (!ASN1_INTEGER_set(cresp->certReqId, 99))
+        goto err;
+    if ((cresp->certifiedKeyPair = OSSL_CMP_CERTIFIEDKEYPAIR_new()) == NULL)
+        goto err;
+    cresp->certifiedKeyPair->certOrEncCert->type =
+        OSSL_CMP_CERTORENCCERT_CERTIFICATE;
+    if ((cresp->certifiedKeyPair->certOrEncCert->value.certificate =
+         X509_dup(cert)) == NULL
+            || !sk_OSSL_CMP_CERTRESPONSE_push(crepmsg->response, cresp))
+        goto err;
+    cresp = NULL;
+    read_cresp = ossl_cmp_certrepmessage_get0_certresponse(crepmsg, 99);
+    if (!TEST_ptr(read_cresp))
+        goto err;
+    if (!TEST_ptr_null(ossl_cmp_certrepmessage_get0_certresponse(crepmsg, 88)))
+        goto err;
+    privkey = OSSL_CMP_CTX_get0_newPkey(fixture->cmp_ctx, 1); /* may be NULL */
+    certfromresp = ossl_cmp_certresponse_get1_certificate(privkey, read_cresp);
+    if (certfromresp == NULL || !TEST_int_eq(X509_cmp(cert, certfromresp), 0))
+        goto err;
+
+    res = 1;
+ err:
+    X509_free(certfromresp);
+    OSSL_CMP_CERTRESPONSE_free(cresp);
+    OSSL_CMP_CERTREPMESSAGE_free(crepmsg);
+    return res;
+}
+
+static int test_cmp_create_certrep(void)
+{
+    SETUP_TEST_FIXTURE(CMP_MSG_TEST_FIXTURE, set_up);
+    EXECUTE_TEST(execute_certrep_create, tear_down);
+    return result;
+}
+
+
+static int execute_rp_create(CMP_MSG_TEST_FIXTURE *fixture)
+{
+    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;
+    OSSL_CMP_MSG *rpmsg = NULL;
+    int res = 0;
+
+    if (si == NULL || issuer == NULL || serial == NULL)
+        goto err;
+
+    if (!X509_NAME_add_entry_by_txt(issuer, "CN", MBSTRING_ASC,
+                                    (unsigned char*)"The Issuer", -1, -1, 0)
+            || !ASN1_INTEGER_set(serial, 99)
+            || (cid = OSSL_CRMF_CERTID_gen(issuer, serial)) == NULL
+            || (rpmsg = ossl_cmp_rp_new(fixture->cmp_ctx, si, cid, 1)) == NULL)
+        goto err;
+
+    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)))
+        goto err;
+
+    res = 1;
+ err:
+    ASN1_INTEGER_free(serial);
+    X509_NAME_free(issuer);
+    OSSL_CRMF_CERTID_free(cid);
+    OSSL_CMP_PKISI_free(si);
+    OSSL_CMP_MSG_free(rpmsg);
+    return res;
+}
+
+static int test_cmp_create_rp(void)
+{
+    SETUP_TEST_FIXTURE(CMP_MSG_TEST_FIXTURE, set_up);
+    EXECUTE_TEST(execute_rp_create, tear_down);
+    return result;
+}
+
+static int execute_pollrep_create(CMP_MSG_TEST_FIXTURE *fixture)
+{
+    OSSL_CMP_MSG *pollrep;
+    int res = 0;
+
+    pollrep = ossl_cmp_pollRep_new(fixture->cmp_ctx, 77, 2000);
+    if (!TEST_ptr(pollrep))
+        return 0;
+    if (!TEST_ptr(ossl_cmp_pollrepcontent_get0_pollrep(
+            pollrep->body->value.pollRep, 77)))
+        goto err;
+    if (!TEST_ptr_null(ossl_cmp_pollrepcontent_get0_pollrep(
+            pollrep->body->value.pollRep, 88)))
+        goto err;
+
+    res = 1;
+ err:
+    OSSL_CMP_MSG_free(pollrep);
+    return res;
+}
+
+static int test_cmp_create_pollrep(void)
+{
+    SETUP_TEST_FIXTURE(CMP_MSG_TEST_FIXTURE, set_up);
+    EXECUTE_TEST(execute_pollrep_create, tear_down);
+    return result;
+}
+
+static int test_cmp_pkimessage_create(int bodytype)
+{
+    X509_REQ *p10cr = NULL;
+
+    SETUP_TEST_FIXTURE(CMP_MSG_TEST_FIXTURE, set_up);
+
+    switch (fixture->bodytype = bodytype) {
+    case OSSL_CMP_PKIBODY_P10CR:
+        fixture->expected = 1;
+        if (!TEST_true(OSSL_CMP_CTX_set1_p10CSR(fixture->cmp_ctx,
+                                                p10cr = load_csr(pkcs10_f)))) {
+            tear_down(fixture);
+            fixture = NULL;
+        }
+        X509_REQ_free(p10cr);
+        break;
+    case OSSL_CMP_PKIBODY_IR:
+    case OSSL_CMP_PKIBODY_IP:
+    case OSSL_CMP_PKIBODY_CR:
+    case OSSL_CMP_PKIBODY_CP:
+    case OSSL_CMP_PKIBODY_KUR:
+    case OSSL_CMP_PKIBODY_KUP:
+    case OSSL_CMP_PKIBODY_RR:
+    case OSSL_CMP_PKIBODY_RP:
+    case OSSL_CMP_PKIBODY_PKICONF:
+    case OSSL_CMP_PKIBODY_GENM:
+    case OSSL_CMP_PKIBODY_GENP:
+    case OSSL_CMP_PKIBODY_ERROR:
+    case OSSL_CMP_PKIBODY_CERTCONF:
+    case OSSL_CMP_PKIBODY_POLLREQ:
+    case OSSL_CMP_PKIBODY_POLLREP:
+        fixture->expected = 1;
+        break;
+    default:
+        fixture->expected = 0;
+        break;
+    }
+
+    EXECUTE_TEST(execute_pkimessage_create_test, tear_down);
+    return result;
+}
+
+void cleanup_tests(void)
+{
+    EVP_PKEY_free(newkey);
+    X509_free(cert);
+}
+
+int setup_tests(void)
+{
+    if (!TEST_ptr(server_cert_f = test_get_argument(0))
+            || !TEST_ptr(pkcs10_f = test_get_argument(1))) {
+        TEST_error("usage: cmp_msg_test server.crt pkcs10.der\n");
+        return 0;
+    }
+
+    if (!TEST_ptr(newkey = gen_rsa())
+            || !TEST_ptr(cert = load_pem_cert(server_cert_f))
+            || !TEST_int_eq(1, RAND_bytes(ref, sizeof(ref)))) {
+        cleanup_tests();
+        return 0;
+    }
+
+    /* Message creation tests */
+    ADD_TEST(test_cmp_create_certreq_with_invalid_bodytype);
+    ADD_TEST(test_cmp_create_ir_protection_fails);
+    ADD_TEST(test_cmp_create_ir_protection_set);
+    ADD_TEST(test_cmp_create_error_msg);
+    ADD_TEST(test_cmp_create_certconf);
+    ADD_TEST(test_cmp_create_certconf_badAlg);
+    ADD_TEST(test_cmp_create_certconf_fail_info_max);
+    ADD_TEST(test_cmp_create_kur);
+    ADD_TEST(test_cmp_create_kur_without_oldcert);
+    ADD_TEST(test_cmp_create_cr);
+    ADD_TEST(test_cmp_create_cr_without_key);
+    ADD_TEST(test_cmp_create_p10cr);
+    ADD_TEST(test_cmp_create_p10cr_null);
+    ADD_TEST(test_cmp_create_pollreq);
+    ADD_TEST(test_cmp_create_rr);
+    ADD_TEST(test_cmp_create_rp);
+    ADD_TEST(test_cmp_create_genm);
+    ADD_TEST(test_cmp_create_certrep);
+    ADD_TEST(test_cmp_create_pollrep);
+    ADD_ALL_TESTS_NOSUBTEST(test_cmp_pkimessage_create,
+                            OSSL_CMP_PKIBODY_POLLREP + 1);
+    return 1;
+}
diff --git a/test/cmp_protect_test.c b/test/cmp_protect_test.c
new file mode 100644
index 0000000000..89be39f7fc
--- /dev/null
+++ b/test/cmp_protect_test.c
@@ -0,0 +1,517 @@
+/*
+ * 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
+ */
+
+#include "cmp_testlib.h"
+
+static const char *ir_protected_f;
+static const char *ir_unprotected_f;
+static const char *ip_PBM_f;
+
+typedef struct test_fixture {
+    const char *test_case_name;
+    OSSL_CMP_CTX *cmp_ctx;
+    /* for protection tests */
+    OSSL_CMP_MSG *msg;
+    OSSL_CMP_PKISI *si;      /* for error and response messages */
+    ASN1_OCTET_STRING *secret;
+    EVP_PKEY *privkey;
+    EVP_PKEY *pubkey;
+    unsigned char *mem;
+    int memlen;
+    X509 *cert;
+    STACK_OF(X509) *certs;
+    STACK_OF(X509) *chain;
+    int callback_arg;
+    int expected;
+} CMP_PROTECT_TEST_FIXTURE;
+
+static void tear_down(CMP_PROTECT_TEST_FIXTURE *fixture)
+{
+    OSSL_CMP_CTX_free(fixture->cmp_ctx);
+    OSSL_CMP_MSG_free(fixture->msg);
+    ASN1_OCTET_STRING_free(fixture->secret);
+    OSSL_CMP_PKISI_free(fixture->si);
+
+    OPENSSL_free(fixture->mem);
+    sk_X509_free(fixture->certs);
+    sk_X509_free(fixture->chain);
+
+    OPENSSL_free(fixture);
+}
+
+static CMP_PROTECT_TEST_FIXTURE *set_up(const char *const test_case_name)
+{
+    CMP_PROTECT_TEST_FIXTURE *fixture;
+
+    if (!TEST_ptr(fixture = OPENSSL_zalloc(sizeof(*fixture))))
+        return NULL;
+    fixture->test_case_name = test_case_name;
+    if (!TEST_ptr(fixture->cmp_ctx = OSSL_CMP_CTX_new())) {
+        tear_down(fixture);
+        return NULL;
+    }
+    return fixture;
+}
+
+static EVP_PKEY *loadedprivkey = NULL;
+static EVP_PKEY *loadedpubkey = NULL;
+static EVP_PKEY *loadedkey = NULL;
+static X509 *cert = NULL;
+static unsigned char rand_data[OSSL_CMP_TRANSACTIONID_LENGTH];
+static OSSL_CMP_MSG *ir_unprotected, *ir_protected;
+static X509 *endentity1 = NULL, *endentity2 = NULL,
+    *root = NULL, *intermediate = NULL;
+
+static int execute_calc_protection_fails_test(CMP_PROTECT_TEST_FIXTURE *fixture)
+{
+    ASN1_BIT_STRING *protection =
+        ossl_cmp_calc_protection(fixture->msg, fixture->secret,
+                                 fixture->privkey);
+    int res = TEST_ptr_null(protection);
+
+    ASN1_BIT_STRING_free(protection);
+    return res;
+}
+
+static int execute_calc_protection_pbmac_test(CMP_PROTECT_TEST_FIXTURE *fixture)
+{
+    ASN1_BIT_STRING *protection =
+        ossl_cmp_calc_protection(fixture->msg, fixture->secret, NULL);
+    int res = TEST_ptr(protection)
+        && TEST_true(ASN1_STRING_cmp(protection, fixture->msg->protection) == 0);
+
+    ASN1_BIT_STRING_free(protection);
+    return res;
+}
+
+/*
+ * This function works similarly to parts of CMP_verify_signature in cmp_vfy.c,
+ * but without the need for a OSSL_CMP_CTX or a X509 certificate
+ */
+static int verify_signature(OSSL_CMP_MSG *msg,
+                            ASN1_BIT_STRING *protection,
+                            EVP_PKEY *pkey, int digest_nid)
+{
+    CMP_PROTECTEDPART prot_part;
+    unsigned char *prot_part_der = NULL;
+    int len;
+    EVP_MD_CTX *ctx = NULL;
+    const EVP_MD *digest = EVP_get_digestbynid(digest_nid);
+    int res;
+
+    prot_part.header = OSSL_CMP_MSG_get0_header(msg);
+    prot_part.body = msg->body;
+    res =
+        TEST_int_ge(len = i2d_CMP_PROTECTEDPART(&prot_part, &prot_part_der), 0)
+        && TEST_ptr(ctx = EVP_MD_CTX_new())
+        && TEST_true(EVP_DigestVerifyInit(ctx, NULL, digest, NULL, pkey))
+        && TEST_int_eq(EVP_DigestVerify(ctx, protection->data,
+                                        protection->length,
+                                        prot_part_der, len), 1);
+    /* cleanup */
+    EVP_MD_CTX_free(ctx);
+    OPENSSL_free(prot_part_der);
+    return res;
+}
+
+/* Calls OSSL_CMP_calc_protection and compares and verifies signature */
+static int execute_calc_protection_signature_test(CMP_PROTECT_TEST_FIXTURE *
+                                                  fixture)
+{
+    ASN1_BIT_STRING *protection =
+        ossl_cmp_calc_protection(fixture->msg, NULL, fixture->privkey);
+    int ret = (TEST_ptr(protection)
+                   && TEST_true(ASN1_STRING_cmp(protection,
+                                                fixture->msg->protection) == 0)
+                   && TEST_true(verify_signature(fixture->msg, protection,
+                                                 fixture->pubkey,
+                                                 fixture->cmp_ctx->digest)));
+
+    ASN1_BIT_STRING_free(protection);
+    return ret;
+}
+
+static int test_cmp_calc_protection_no_key_no_secret(void)
+{
+    SETUP_TEST_FIXTURE(CMP_PROTECT_TEST_FIXTURE, set_up);
+    if (!TEST_ptr(fixture->msg = load_pkimsg(ir_unprotected_f))
+            || !TEST_ptr(fixture->msg->header->protectionAlg =
+                         X509_ALGOR_new() /* no specific alg needed here */)) {
+        tear_down(fixture);
+        fixture = NULL;
+    }
+
+    EXECUTE_TEST(execute_calc_protection_fails_test, tear_down);
+    return result;
+}
+
+static int test_cmp_calc_protection_pkey(void)
+{
+    SETUP_TEST_FIXTURE(CMP_PROTECT_TEST_FIXTURE, set_up);
+    fixture->pubkey = loadedpubkey;
+    fixture->privkey = loadedprivkey;
+    if (!TEST_ptr(fixture->msg = load_pkimsg(ir_protected_f))) {
+        tear_down(fixture);
+        fixture = NULL;
+    }
+    EXECUTE_TEST(execute_calc_protection_signature_test, tear_down);
+    return result;
+}
+
+static int test_cmp_calc_protection_pbmac(void)
+{
+    unsigned char sec_insta[] = { 'i', 'n', 's', 't', 'a' };
+
+    SETUP_TEST_FIXTURE(CMP_PROTECT_TEST_FIXTURE, set_up);
+    if (!TEST_ptr(fixture->secret = ASN1_OCTET_STRING_new())
+            || !TEST_true(ASN1_OCTET_STRING_set
+                          (fixture->secret, sec_insta, sizeof(sec_insta)))
+            || !TEST_ptr(fixture->msg = load_pkimsg(ip_PBM_f))) {
+        tear_down(fixture);
+        fixture = NULL;
+    }
+    EXECUTE_TEST(execute_calc_protection_pbmac_test, tear_down);
+    return result;
+}
+static int execute_MSG_protect_test(CMP_PROTECT_TEST_FIXTURE *fixture)
+{
+    return TEST_int_eq(fixture->expected,
+                       ossl_cmp_msg_protect(fixture->cmp_ctx, fixture->msg));
+}
+
+#define SET_OPT_UNPROTECTED_SEND(ctx, val) \
+    OSSL_CMP_CTX_set_option((ctx), OSSL_CMP_OPT_UNPROTECTED_SEND, (val))
+static int test_MSG_protect_unprotected_request(void)
+{
+    SETUP_TEST_FIXTURE(CMP_PROTECT_TEST_FIXTURE, set_up);
+
+    fixture->expected = 1;
+    if (!TEST_ptr(fixture->msg = OSSL_CMP_MSG_dup(ir_unprotected))
+            || !TEST_true(SET_OPT_UNPROTECTED_SEND(fixture->cmp_ctx, 1))) {
+        tear_down(fixture);
+        fixture = NULL;
+    }
+    EXECUTE_TEST(execute_MSG_protect_test, tear_down);
+    return result;
+}
+
+static int test_MSG_protect_with_msg_sig_alg_protection_plus_rsa_key(void)
+{
+    const size_t size = sizeof(rand_data) / 2;
+
+    SETUP_TEST_FIXTURE(CMP_PROTECT_TEST_FIXTURE, set_up);
+    fixture->expected = 1;
+
+    if (!TEST_ptr(fixture->msg =
+                  OSSL_CMP_MSG_dup(ir_unprotected))
+            || !TEST_true(SET_OPT_UNPROTECTED_SEND(fixture->cmp_ctx, 0))
+            /*
+             * Use half of the 16 bytes of random input
+             * for each reference and secret value
+             */
+            || !TEST_true(OSSL_CMP_CTX_set1_referenceValue(fixture->cmp_ctx,
+                                                           rand_data, size))
+            || !TEST_true(OSSL_CMP_CTX_set1_secretValue(fixture->cmp_ctx,
+                                                        rand_data + size,
+                                                        size))) {
+        tear_down(fixture);
+        fixture = NULL;
+    }
+    EXECUTE_TEST(execute_MSG_protect_test, tear_down);
+    return result;
+}
+
+static int test_MSG_protect_with_certificate_and_key(void)
+{
+    SETUP_TEST_FIXTURE(CMP_PROTECT_TEST_FIXTURE, set_up);
+    fixture->expected = 1;
+
+    if (!TEST_ptr(fixture->msg =
+                  OSSL_CMP_MSG_dup(ir_unprotected))
+            || !TEST_true(SET_OPT_UNPROTECTED_SEND(fixture->cmp_ctx, 0))
+            || !TEST_true(OSSL_CMP_CTX_set1_pkey(fixture->cmp_ctx, loadedkey))
+            || !TEST_true(OSSL_CMP_CTX_set1_clCert(fixture->cmp_ctx, cert))) {
+        tear_down(fixture);
+        fixture = NULL;
+    }
+    EXECUTE_TEST(execute_MSG_protect_test, tear_down);
+    return result;
+}
+
+static int test_MSG_protect_certificate_based_without_cert(void)
+{
+    SETUP_TEST_FIXTURE(CMP_PROTECT_TEST_FIXTURE, set_up);
+    OSSL_CMP_CTX *ctx = fixture->cmp_ctx;
+
+    fixture->expected = 0;
+    if (!TEST_ptr(fixture->msg =
+                  OSSL_CMP_MSG_dup(ir_unprotected))
+            || !TEST_true(SET_OPT_UNPROTECTED_SEND(ctx, 0))
+            || !TEST_true(OSSL_CMP_CTX_set0_newPkey(ctx, 1, loadedkey))) {
+        tear_down(fixture);
+        fixture = NULL;
+    }
+    EVP_PKEY_up_ref(loadedkey);
+    EXECUTE_TEST(execute_MSG_protect_test, tear_down);
+    return result;
+}
+
+static int test_MSG_protect_no_key_no_secret(void)
+{
+    SETUP_TEST_FIXTURE(CMP_PROTECT_TEST_FIXTURE, set_up);
+    fixture->expected = 0;
+    if (!TEST_ptr(fixture->msg = OSSL_CMP_MSG_dup(ir_unprotected))
+            || !TEST_true(SET_OPT_UNPROTECTED_SEND(fixture->cmp_ctx, 0))) {
+        tear_down(fixture);
+        fixture = NULL;
+    }
+    EXECUTE_TEST(execute_MSG_protect_test, tear_down);
+    return result;
+}
+
+static int execute_MSG_add_extraCerts_test(CMP_PROTECT_TEST_FIXTURE *fixture)
+{
+    return TEST_true(ossl_cmp_msg_add_extraCerts(fixture->cmp_ctx,
+                                                 fixture->msg));
+}
+
+static int test_MSG_add_extraCerts(void)
+{
+    SETUP_TEST_FIXTURE(CMP_PROTECT_TEST_FIXTURE, set_up);
+    if (!TEST_ptr(fixture->msg = OSSL_CMP_MSG_dup(ir_protected))) {
+        tear_down(fixture);
+        fixture = NULL;
+    }
+    EXECUTE_TEST(execute_MSG_add_extraCerts_test, tear_down);
+    return result;
+}
+
+static int execute_cmp_build_cert_chain_test(CMP_PROTECT_TEST_FIXTURE *fixture)
+{
+    STACK_OF(X509) *result = NULL;
+    int ret = 0;
+
+    if (TEST_ptr(result = ossl_cmp_build_cert_chain(fixture->certs,
+                                                    fixture->cert))) {
+        /* Check whether chain built is equal to the expected one */
+        ret = TEST_int_eq(0, STACK_OF_X509_cmp(result, fixture->chain));
+        sk_X509_pop_free(result, X509_free);
+    }
+    return ret;
+}
+
+static int test_cmp_build_cert_chain(void)
+{
+    SETUP_TEST_FIXTURE(CMP_PROTECT_TEST_FIXTURE, set_up);
+    fixture->cert = endentity2;
+    if (!TEST_ptr(fixture->certs = sk_X509_new_null())
+            || !TEST_ptr(fixture->chain = sk_X509_new_null())
+            || !TEST_true(sk_X509_push(fixture->certs, endentity1))
+            || !TEST_true(sk_X509_push(fixture->certs, root))
+            || !TEST_true(sk_X509_push(fixture->certs, intermediate))
+            || !TEST_true(sk_X509_push(fixture->chain, endentity2))
+            || !TEST_true(sk_X509_push(fixture->chain, intermediate))) {
+        tear_down(fixture);
+        fixture = NULL;
+    }
+    EXECUTE_TEST(execute_cmp_build_cert_chain_test, tear_down);
+    return result;
+}
+
+static int test_cmp_build_cert_chain_missing_intermediate(void)
+{
+    SETUP_TEST_FIXTURE(CMP_PROTECT_TEST_FIXTURE, set_up);
+    fixture->cert = endentity2;
+    if (!TEST_ptr(fixture->certs = sk_X509_new_null())
+            || !TEST_ptr(fixture->chain = sk_X509_new_null())
+            || !TEST_true(sk_X509_push(fixture->certs, endentity1))
+            || !TEST_true(sk_X509_push(fixture->certs, root))
+            || !TEST_true(sk_X509_push(fixture->chain, endentity2))) {
+        tear_down(fixture);
+        fixture = NULL;
+    }
+    EXECUTE_TEST(execute_cmp_build_cert_chain_test, tear_down);
+    return result;
+}
+
+static int test_cmp_build_cert_chain_missing_root(void)
+{
+    SETUP_TEST_FIXTURE(CMP_PROTECT_TEST_FIXTURE, set_up);
+    fixture->cert = endentity2;
+    if (!TEST_ptr(fixture->certs = sk_X509_new_null())
+            || !TEST_ptr(fixture->chain = sk_X509_new_null())
+            || !TEST_true(sk_X509_push(fixture->certs, endentity1))
+            || !TEST_true(sk_X509_push(fixture->certs, intermediate))
+            || !TEST_true(sk_X509_push(fixture->chain, endentity2))
+            || !TEST_true(sk_X509_push(fixture->chain, intermediate))) {
+        tear_down(fixture);
+        fixture = NULL;
+    }
+    EXECUTE_TEST(execute_cmp_build_cert_chain_test, tear_down);
+    return result;
+}
+
+static int test_cmp_build_cert_chain_no_certs(void)
+{
+    SETUP_TEST_FIXTURE(CMP_PROTECT_TEST_FIXTURE, set_up);
+    fixture->cert = endentity2;
+    if (!TEST_ptr(fixture->certs = sk_X509_new_null())
+            || !TEST_ptr(fixture->chain = sk_X509_new_null())
+            || !TEST_true(sk_X509_push(fixture->chain, endentity2))) {
+        tear_down(fixture);
+        fixture = NULL;
+    }
+    EXECUTE_TEST(execute_cmp_build_cert_chain_test, tear_down);
+    return result;
+}
+
+static int execute_X509_STORE_test(CMP_PROTECT_TEST_FIXTURE *fixture)
+{
+    X509_STORE *store = X509_STORE_new();
+    STACK_OF(X509) *sk = NULL;
+    int res = 0;
+
+    if (!TEST_true(ossl_cmp_X509_STORE_add1_certs(store,
+                                                  fixture->certs,
+                                                  fixture->callback_arg)))
+        goto err;
+    sk = ossl_cmp_X509_STORE_get1_certs(store);
+    if (!TEST_int_eq(0, STACK_OF_X509_cmp(sk, fixture->chain)))
+        goto err;
+    res = 1;
+ err:
+    X509_STORE_free(store);
+    sk_X509_pop_free(sk, X509_free);
+    return res;
+
+}
+
+static int test_X509_STORE(void)
+{
+    SETUP_TEST_FIXTURE(CMP_PROTECT_TEST_FIXTURE, set_up);
+    fixture->callback_arg = 0;  /* self-signed allowed */
+    if (!TEST_ptr(fixture->certs = sk_X509_new_null())
+            || !sk_X509_push(fixture->certs, endentity1)
+            || !sk_X509_push(fixture->certs, endentity2)
+            || !sk_X509_push(fixture->certs, root)
+            || !sk_X509_push(fixture->certs, intermediate)
+            || !TEST_ptr(fixture->chain = sk_X509_dup(fixture->certs))) {
+        tear_down(fixture);
+        fixture = NULL;
+    }
+    EXECUTE_TEST(execute_X509_STORE_test, tear_down);
+    return result;
+}
+
+static int test_X509_STORE_only_self_signed(void)
+{
+    SETUP_TEST_FIXTURE(CMP_PROTECT_TEST_FIXTURE, set_up);
+    fixture->certs = sk_X509_new_null();
+    fixture->chain = sk_X509_new_null();
+    fixture->callback_arg = 1;  /* only self-signed */
+    if (!TEST_true(sk_X509_push(fixture->certs, endentity1))
+            || !TEST_true(sk_X509_push(fixture->certs, endentity2))
+            || !TEST_true(sk_X509_push(fixture->certs, root))
+            || !TEST_true(sk_X509_push(fixture->certs, intermediate))
+            || !TEST_true(sk_X509_push(fixture->chain, root))) {
+        tear_down(fixture);
+        fixture = NULL;
+    }
+    EXECUTE_TEST(execute_X509_STORE_test, tear_down);
+    return result;
+}
+
+
+void cleanup_tests(void)
+{
+    EVP_PKEY_free(loadedprivkey);
+    EVP_PKEY_free(loadedpubkey);
+    EVP_PKEY_free(loadedkey);
+    X509_free(cert);
+    X509_free(endentity1);
+    X509_free(endentity2);
+    X509_free(root);
+    X509_free(intermediate);
+    OSSL_CMP_MSG_free(ir_protected);
+    OSSL_CMP_MSG_free(ir_unprotected);
+
+}
+
+int setup_tests(void)
+{
+    char *server_f;
+    char *server_key_f;
+    char *server_cert_f;
+    char *endentity1_f;
+    char *endentity2_f;
+    char *root_f;
+    char *intermediate_f;
+
+    RAND_bytes(rand_data, OSSL_CMP_TRANSACTIONID_LENGTH);
+    if (!TEST_ptr(server_f = test_get_argument(0))
+            || !TEST_ptr(ir_protected_f = test_get_argument(1))
+            || !TEST_ptr(ir_unprotected_f = test_get_argument(2))
+            || !TEST_ptr(ip_PBM_f = test_get_argument(3))
+            || !TEST_ptr(server_cert_f = test_get_argument(4))
+            || !TEST_ptr(server_key_f = test_get_argument(5))
+            || !TEST_ptr(endentity1_f = test_get_argument(6))
+            || !TEST_ptr(endentity2_f = test_get_argument(7))
+            || !TEST_ptr(root_f = test_get_argument(8))
+            || !TEST_ptr(intermediate_f = test_get_argument(9))) {
+        TEST_error("usage: cmp_protect_test server.pem "
+                   "IR_protected.der IR_unprotected.der IP_PBM.der "
+                   "server.crt server.pem"
+                   "EndEntity1.crt EndEntity2.crt "
+                   "Root_CA.crt Intermediate_CA.crt\n");
+        return 0;
+    }
+    if (!TEST_ptr(loadedkey = load_pem_key(server_key_f))
+            || !TEST_ptr(cert = load_pem_cert(server_cert_f)))
+        return 0;
+
+    if (!TEST_ptr(loadedprivkey = load_pem_key(server_f)))
+        return 0;
+    if (TEST_true(EVP_PKEY_up_ref(loadedprivkey)))
+        loadedpubkey = loadedprivkey;
+    if (!TEST_ptr(ir_protected = load_pkimsg(ir_protected_f))
+            || !TEST_ptr(ir_unprotected = load_pkimsg(ir_unprotected_f)))
+        return 0;
+    if (!TEST_ptr(endentity1 = load_pem_cert(endentity1_f))
+            || !TEST_ptr(endentity2 = load_pem_cert(endentity2_f))
+            || !TEST_ptr(root = load_pem_cert(root_f))
+            || !TEST_ptr(intermediate = load_pem_cert(intermediate_f)))
+        return 0;
+    if (!TEST_int_eq(1, RAND_bytes(rand_data, OSSL_CMP_TRANSACTIONID_LENGTH)))
+        return 0;
+
+    /* Message protection tests */
+    ADD_TEST(test_cmp_calc_protection_no_key_no_secret);
+    ADD_TEST(test_cmp_calc_protection_pkey);
+    ADD_TEST(test_cmp_calc_protection_pbmac);
+
+    ADD_TEST(test_MSG_protect_with_msg_sig_alg_protection_plus_rsa_key);
+    ADD_TEST(test_MSG_protect_with_certificate_and_key);
+    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_add_extraCerts);
+
+    ADD_TEST(test_cmp_build_cert_chain);
+    ADD_TEST(test_cmp_build_cert_chain_missing_root);
+    ADD_TEST(test_cmp_build_cert_chain_missing_intermediate);
+    ADD_TEST(test_cmp_build_cert_chain_no_certs);
+
+    ADD_TEST(test_X509_STORE);
+    ADD_TEST(test_X509_STORE_only_self_signed);
+
+    return 1;
+}
diff --git a/test/cmp_testlib.h b/test/cmp_testlib.h
index 22b96bf113..96b577e46e 100644
--- a/test/cmp_testlib.h
+++ b/test/cmp_testlib.h
@@ -16,7 +16,7 @@
 # include <openssl/pem.h>
 # include <openssl/rand.h>
 
-#include "../crypto/cmp/cmp_local.h"
+# include "../crypto/cmp/cmp_local.h"
 
 # include "testutil.h"
 
diff --git a/test/recipes/65-test_cmp_msg.t b/test/recipes/65-test_cmp_msg.t
new file mode 100644
index 0000000000..e1b08ccfa2
--- /dev/null
+++ b/test/recipes/65-test_cmp_msg.t
@@ -0,0 +1,24 @@
+#! /usr/bin/env perl
+# 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
+
+use strict;
+use OpenSSL::Test qw/:DEFAULT data_file/;
+use OpenSSL::Test::Utils;
+
+setup("test_cmp_msg");
+
+plan skip_all => "This test is not supported in a no-cmp build"
+    if disabled("cmp");
+
+plan tests => 1;
+
+ok(run(test(["cmp_msg_test",
+             data_file("server.crt"),
+             data_file("pkcs10.der")])));
diff --git a/test/recipes/65-test_cmp_msg_data/pkcs10.der b/test/recipes/65-test_cmp_msg_data/pkcs10.der
new file mode 100644
index 0000000000..510a4fc5b0
Binary files /dev/null and b/test/recipes/65-test_cmp_msg_data/pkcs10.der differ
diff --git a/test/recipes/65-test_cmp_msg_data/server.crt b/test/recipes/65-test_cmp_msg_data/server.crt
new file mode 100644
index 0000000000..ed1d43333e
--- /dev/null
+++ b/test/recipes/65-test_cmp_msg_data/server.crt
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICpTCCAY2gAwIBAgIBATANBgkqhkiG9w0BAQUFADAWMRQwEgYDVQQKDAtvcGVu
+c3NsX2NtcDAeFw0xNzEyMjAxMzA0MDBaFw0xODEyMjAxMzA0MDBaMBYxFDASBgNV
+BAoMC29wZW5zc2xfY21wMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA
+4ckRrH0UWmIJFj99kBqvCipGjJRAaPkdvWjdDQLglTpI3eZAJHnq0ypW/PZccrWj
+o7mxuvAStEYWF+5Jx6ZFmAsC1K0NNebSAZQoLWYZqiOzkfVVpLicMnItNFElfCoh
+BzPCYmF5UlC5yp9PSUEfNwPJqDIRMtw+IlVUV3AJw9TJ3uuWq/vWW9r96/gBKKdd
+mj/q2gGT8RC6LxEaolTbhfPbHaA1DFpv1WQFb3oAV3Wq14SOZf9bH1olBVsmBMsU
+shFEw5MXVrNCv2moM4HtITMyjvZe7eIwHzSzf6dvQjERG6GvZ/i5KOhaqgJCnRKd
+HHzijz9cLec5p9NSOuC1OwIDAQABMA0GCSqGSIb3DQEBBQUAA4IBAQDGUXpFCBkV
+WgPrBfZyBwt6VCjWB/e67q4IdcKMfDa4hwSquah1AyXHI0PlC/qitnoSx2+7f7pY
+TEOay/3eEPUl1J5tdPF2Vg56Dw8jdhSkMwO7bXKDEE3R6o6jaa4ECgxwQtdGHmNU
+A41PgKX76yEXku803ptO39/UR7i7Ye3MbyAmWE+PvixJYUbxd3fqz5fsaJqTCzAy
+AT9hrr4uu8J7m3LYaYXo4LVL4jw5UsP5bIYtpmmEBfy9GhpUqH5/LzBNij7y3ziE
+T59wHkzawAQDHsBPuCe07DFtlzqWWvaih0TQAw9MZ2tbyK9jt7P80Rqt9CwpM/i9
+jQYqSl/ix5hn
+-----END CERTIFICATE-----
diff --git a/test/recipes/65-test_cmp_protect.t b/test/recipes/65-test_cmp_protect.t
new file mode 100644
index 0000000000..cc36d2674d
--- /dev/null
+++ b/test/recipes/65-test_cmp_protect.t
@@ -0,0 +1,35 @@
+#! /usr/bin/env perl
+# 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
+
+use strict;
+use OpenSSL::Test qw/:DEFAULT data_file/;
+use OpenSSL::Test::Utils;
+
+setup("test_cmp_protect");
+
+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 shared library build on Windows"
+    if $^O eq 'MSWin32' && !disabled("shared");
+
+plan tests => 1;
+
+ok(run(test(["cmp_protect_test",
+             data_file("server.pem"),
+             data_file("IR_protected.der"),
+             data_file("IR_unprotected.der"),
+             data_file("IP_PBM.der"),
+             data_file("server.crt"),
+             data_file("server.pem"),
+             data_file("EndEntity1.crt"),
+             data_file("EndEntity2.crt"),
+             data_file("Root_CA.crt"),
+             data_file("Intermediate_CA.crt")])));
diff --git a/test/recipes/65-test_cmp_protect_data/EndEntity1.crt b/test/recipes/65-test_cmp_protect_data/EndEntity1.crt
new file mode 100644
index 0000000000..4e05449889
--- /dev/null
+++ b/test/recipes/65-test_cmp_protect_data/EndEntity1.crt
@@ -0,0 +1,16 @@
+-----BEGIN CERTIFICATE-----
+MIICnDCCAYSgAwIBAgIBAzANBgkqhkiG9w0BAQUFADASMRAwDgYDVQQDEwdSb290
+IENBMB4XDTE3MTEwODE1NDgwMFoXDTE4MTEwODExMTkwMFowETEPMA0GA1UEAxMG
+Q2xpZW50MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtNiWJufEotHe
+p6E/4b0laX7K1NRamNoUokLIsq78RoBieBXaGxIdbT6zmhLnLmZdb0UN3v7FUP75
+rqPN2yyj3TbS4o5ilh5El8bDDAPhW5lthCddvH/uBziRAM5oIB4xxOumNbgHpLUT
+Clh49sdXd4ydYpCTWld5emRouBmMUeP/0EkyWMBIrHGSBxrqtFVRXhxvVHImQv6Z
+hIKql7dCVCZbhUtxw6sLxIGL4xlhKoM2o31k4I/9tjZrWSZZ7KAIOlOLrjxZc/bQ
+MwvxVUgS+C+iXzhCY8v+N/K37jwtAAk4C1aOGv/VygNcN0C/ynfKSzFmtnfei4+3
+6GC7HtFzewIDAQABMA0GCSqGSIb3DQEBBQUAA4IBAQB3GYpPSCCYsJM5owKcODr/
+I1aJ8jQ+u5jCKjvYLp6Cnbr4AbRXzvKuMyV6UfIAQbrGOxAClvX++5/ZQbhY+TxN
+iiUM3yr5yYCLqj4MeYHhJ3gOzcppAO9LQ9V7eA8C830giZMm3cpApFSLP8CpwNUD
+W/fgoQfaOae5IYPZdea88Gmt5RVNbtHgVqtm4ifTQo577kfxTeh20s+M6pgYW3/R
+vftXy2ITEtk/j3NcRvOyZ7Bu1mAg7wNeUjL+gDWAaxs16LsWsCsUGwfr/Z2Rq1CF
+zB0XwIyigkVLDLqDzUShcw0Eb/zYy2KXsxNWA2tb27mw+T+tmmOszpn7JjLrlVks
+-----END CERTIFICATE-----
diff --git a/test/recipes/65-test_cmp_protect_data/EndEntity2.crt b/test/recipes/65-test_cmp_protect_data/EndEntity2.crt
new file mode 100644
index 0000000000..ba06210794
--- /dev/null
+++ b/test/recipes/65-test_cmp_protect_data/EndEntity2.crt
@@ -0,0 +1,13 @@
+-----BEGIN CERTIFICATE-----
+MIIB3zCCAZSgAwIBAgIBBjAKBggqhkjOPQQDAzAVMRMwEQYDVQQDEwpad2lzY2hl
+bkNBMB4XDTE3MTEwODE2MDUwMFoXDTE4MTEwODExMTkwMFowEjEQMA4GA1UEAxMH
+Q2xpZW50MjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALTYlibnxKLR
+3qehP+G9JWl+ytTUWpjaFKJCyLKu/EaAYngV2hsSHW0+s5oS5y5mXW9FDd7+xVD+
++a6jzdsso9020uKOYpYeRJfGwwwD4VuZbYQnXbx/7gc4kQDOaCAeMcTrpjW4B6S1
+EwpYePbHV3eMnWKQk1pXeXpkaLgZjFHj/9BJMljASKxxkgca6rRVUV4cb1RyJkL+
+mYSCqpe3QlQmW4VLccOrC8SBi+MZYSqDNqN9ZOCP/bY2a1kmWeygCDpTi648WXP2
+0DML8VVIEvgvol84QmPL/jfyt+48LQAJOAtWjhr/1coDXDdAv8p3yksxZrZ33ouP
+t+hgux7Rc3sCAwEAAaMNMAswCQYDVR0TBAIwADAKBggqhkjOPQQDAwM5ADA2AhkA
+qASBLwTauET6FGp/EBe7b/99jTyGB861AhkA5ILGkLX4KmjRkTcNxJ3JKB1Sumya
+cbqF
+-----END CERTIFICATE-----
diff --git a/test/recipes/65-test_cmp_protect_data/IP_PBM.der b/test/recipes/65-test_cmp_protect_data/IP_PBM.der
new file mode 100644
index 0000000000..d0890712e6
Binary files /dev/null and b/test/recipes/65-test_cmp_protect_data/IP_PBM.der differ
diff --git a/test/recipes/65-test_cmp_protect_data/IP_PBM.txt b/test/recipes/65-test_cmp_protect_data/IP_PBM.txt
new file mode 100644
index 0000000000..177f2601a3
--- /dev/null
+++ b/test/recipes/65-test_cmp_protect_data/IP_PBM.txt
@@ -0,0 +1 @@
+Reference#:   3078Secret Value: insta
\ No newline at end of file
diff --git a/test/recipes/65-test_cmp_protect_data/IR_protected.der b/test/recipes/65-test_cmp_protect_data/IR_protected.der
new file mode 100644
index 0000000000..ce0a7a46dc
Binary files /dev/null and b/test/recipes/65-test_cmp_protect_data/IR_protected.der differ
diff --git a/test/recipes/65-test_cmp_protect_data/IR_unprotected.der b/test/recipes/65-test_cmp_protect_data/IR_unprotected.der
new file mode 100644
index 0000000000..41a649691f
Binary files /dev/null and b/test/recipes/65-test_cmp_protect_data/IR_unprotected.der differ
diff --git a/test/recipes/65-test_cmp_protect_data/Intermediate_CA.crt b/test/recipes/65-test_cmp_protect_data/Intermediate_CA.crt
new file mode 100644
index 0000000000..3416cdb959
--- /dev/null
+++ b/test/recipes/65-test_cmp_protect_data/Intermediate_CA.crt
@@ -0,0 +1,12 @@
+-----BEGIN CERTIFICATE-----
+MIIB1jCBv6ADAgECAgEFMA0GCSqGSIb3DQEBDQUAMBIxEDAOBgNVBAMTB1Jvb3Qg
+Q0EwHhcNMTcxMTA4MTYwNDAwWhcNMTgxMTA4MTExOTAwWjAVMRMwEQYDVQQDEwpa
+d2lzY2hlbkNBMEkwEwYHKoZIzj0CAQYIKoZIzj0DAQEDMgAE9bJcmZWj2CmO6aW8
+9Qylkj1WgPREf9/s4Z1VYqFODeJnebPXFBLVH/aoGxnds9E9oxAwDjAMBgNVHRME
+BTADAQH/MA0GCSqGSIb3DQEBDQUAA4IBAQBwQD4NTIWMMevEsSrBpKjjQEWc81Ct
+eXoyAXr/d8wgVyuIZe9C7ekxPQCwowcmONUyeYQv9N2eYpdhkAQuk6DS4+aDR4s7
+I6rg5R5CUGGla5NUxM0BKIS3ZIezvEGlP1NFN+HBgJI7ZIIYQ3zDr0EYgo4J7Xvm
+5p58pcCZSsbVyKwKs6T+rTzOVVmJ2L1bWzywZEDmzxMkPmA6fP9XtB4Kx/b4oviw
+TEQl3Jf9EkBvBkKX2rRJs7aMJo4MwOnE4HHOV5GAQqhGrXltsuXmVfIQPtRN4xlK
+oNf/FukI1NcBh4A/iY4PmbyxHYmKy6qjFjng2u2VFtH15HDT4XlLP5gq
+-----END CERTIFICATE-----
diff --git a/test/recipes/65-test_cmp_protect_data/Root_CA.crt b/test/recipes/65-test_cmp_protect_data/Root_CA.crt
new file mode 100644
index 0000000000..6ccf362546
--- /dev/null
+++ b/test/recipes/65-test_cmp_protect_data/Root_CA.crt
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICrzCCAZegAwIBAgIBATANBgkqhkiG9w0BAQUFADASMRAwDgYDVQQDEwdSb290
+IENBMB4XDTE3MTEwODE1NDUwMFoXDTE4MTEwODExMTkwMFowEjEQMA4GA1UEAxMH
+Um9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALiHdLAD2Wu+
+C5UDMK6WCL53Wz0CeU61RRRlGEVSqHrQOWnffgVutgftzsddxxgJJyGsqKo1B+nQ
+vapyJyugYJWYNQLN5+iffe4y1UBPnHMQFHiZ4cNR6PB0eHja2wpcN3QmJzOcpRYE
+xf+QQwJNFqhRi0cZGfd/JfFi/ybJalqClbnYMPcJo7g6S7M3lWbOnEOUWnbM2EBp
+h849mC+kd80vXcRcb7U/3MJKK3Ee72TDye5/kWFf9zcxj2ac0oCiS66JKYobiVJr
+NmbGM0I9U6T6ejXVUu2J3pGUFlcf3RCUYf1aWhkmzEzbm/FGMRJ7vVyCXm/OWIh9
+bqtwH5YfljsCAwEAAaMQMA4wDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOC
+AQEAF7tSa9oVan7kPR5/TXB330Ca1xQt5C38afaJbacR9mM8ZkL0HceQTuJGrnAR
+4kK7CaB5iraU6Lxyql7drq8aixz/7TXna6c172J6HxDeFhQMeSt1LAh7XN5Ir6Y6
+iO7XD5I5lw3Xv6qvhoD0ktkNk/WtF7aBw2ZAi+RcDMgWzWjoS4WqMbvWEHw10j9b
+s8R0YG4yi6wb89UNIMfQtC2XviHKcRS9MzIJQHw73r2EY2t6o9TO+5ukHYDB6/Zo
+/CLXu21MzsFvhupHgX6zdptU324tq2za1+4LvmOHSW+D36jEPT22SndXmHo5VmAn
+6bQ52MhBI0rrWwju9aBpVzsUUg==
+-----END CERTIFICATE-----
diff --git a/test/recipes/65-test_cmp_protect_data/server.crt b/test/recipes/65-test_cmp_protect_data/server.crt
new file mode 100644
index 0000000000..ed1d43333e
--- /dev/null
+++ b/test/recipes/65-test_cmp_protect_data/server.crt
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICpTCCAY2gAwIBAgIBATANBgkqhkiG9w0BAQUFADAWMRQwEgYDVQQKDAtvcGVu
+c3NsX2NtcDAeFw0xNzEyMjAxMzA0MDBaFw0xODEyMjAxMzA0MDBaMBYxFDASBgNV
+BAoMC29wZW5zc2xfY21wMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA
+4ckRrH0UWmIJFj99kBqvCipGjJRAaPkdvWjdDQLglTpI3eZAJHnq0ypW/PZccrWj
+o7mxuvAStEYWF+5Jx6ZFmAsC1K0NNebSAZQoLWYZqiOzkfVVpLicMnItNFElfCoh
+BzPCYmF5UlC5yp9PSUEfNwPJqDIRMtw+IlVUV3AJw9TJ3uuWq/vWW9r96/gBKKdd
+mj/q2gGT8RC6LxEaolTbhfPbHaA1DFpv1WQFb3oAV3Wq14SOZf9bH1olBVsmBMsU
+shFEw5MXVrNCv2moM4HtITMyjvZe7eIwHzSzf6dvQjERG6GvZ/i5KOhaqgJCnRKd
+HHzijz9cLec5p9NSOuC1OwIDAQABMA0GCSqGSIb3DQEBBQUAA4IBAQDGUXpFCBkV
+WgPrBfZyBwt6VCjWB/e67q4IdcKMfDa4hwSquah1AyXHI0PlC/qitnoSx2+7f7pY
+TEOay/3eEPUl1J5tdPF2Vg56Dw8jdhSkMwO7bXKDEE3R6o6jaa4ECgxwQtdGHmNU
+A41PgKX76yEXku803ptO39/UR7i7Ye3MbyAmWE+PvixJYUbxd3fqz5fsaJqTCzAy
+AT9hrr4uu8J7m3LYaYXo4LVL4jw5UsP5bIYtpmmEBfy9GhpUqH5/LzBNij7y3ziE
+T59wHkzawAQDHsBPuCe07DFtlzqWWvaih0TQAw9MZ2tbyK9jt7P80Rqt9CwpM/i9
+jQYqSl/ix5hn
+-----END CERTIFICATE-----
diff --git a/test/recipes/65-test_cmp_protect_data/server.pem b/test/recipes/65-test_cmp_protect_data/server.pem
new file mode 100644
index 0000000000..2324266798
--- /dev/null
+++ b/test/recipes/65-test_cmp_protect_data/server.pem
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEowIBAAKCAQEA4ckRrH0UWmIJFj99kBqvCipGjJRAaPkdvWjdDQLglTpI3eZA
+JHnq0ypW/PZccrWjo7mxuvAStEYWF+5Jx6ZFmAsC1K0NNebSAZQoLWYZqiOzkfVV
+pLicMnItNFElfCohBzPCYmF5UlC5yp9PSUEfNwPJqDIRMtw+IlVUV3AJw9TJ3uuW
+q/vWW9r96/gBKKddmj/q2gGT8RC6LxEaolTbhfPbHaA1DFpv1WQFb3oAV3Wq14SO
+Zf9bH1olBVsmBMsUshFEw5MXVrNCv2moM4HtITMyjvZe7eIwHzSzf6dvQjERG6Gv
+Z/i5KOhaqgJCnRKdHHzijz9cLec5p9NSOuC1OwIDAQABAoIBAGiYVO+rIfqc38jG
+sMxJED2NSBFnvE7k2LoeEgktBA0daxQgziYXtIkOXC3jkwAw1RXLuGH5RTDuJt3/
+LX6nsCW3NCCB6lTGERNaJyKg4dLHpzA+juY3/2P/MKHD1bGncpV7jNk2fpV7gBY1
+pu0wld1Oi+S3DPCaxs3w6Zl39Y4Z7oSNf6DRO5lGN3Asc8TSVjIOWpAl8LIg+P2B
+ZvFeHRANVXaV9YmF2uEi7iMgH4vGrK2svsmM9VThVO4ArGcTRTvGYn7aw3/H4Pt+
+lYuhERdpkKBT0tCgIpO5IJXMl4/5RSDTtcBwiJcReN5IHUAItBIPSHcMflNSKG/I
+aQf4u0ECgYEA8+PAyzn096Y2UrKzE75yuadCveLjsUWx2NN5ZMohQru99F4k7Pab
+/Te4qOe5zlxHAPK3LRwvbwUWo5mLfs45wFrSgZoRlYcCuL+JaX0y2oXMMF9E+UkY
+tljMt/HpLo1SfSjN2Sae4LVhC7rWJ43LtyRepptzBPGqd26eLPGAMr8CgYEA7P8u
+RGkMOrMzEKAb0A9smrzq2xW88T1VejqEt6R8mUcNt8PFHMgjuzVU4zDysrlb7G/0
+VSkQWnJxBh1yNGc1Av7YgwicIgApr4ty0hZhLcnKX2VrNw+L/sSe/cnwVAc6RtPK
+RR6xQubuLlrCGcbYXmyn5Jv+nlY0S3uCyDFHqIUCgYAwtpLxhJf7RwWeqva9wNJl
+ZpUcHE9iPwtwxXx/tyfBjoI4Zv11HyS1BQYrJm2kXCYKeHBB4FlREXEeKDMGluZO
+F1XocP+GIDtY71jg6xLXNtY76yt5pzH6ae4p53WtyKhrO1UyRFaDh3bkwuK3b8j6
+wZbuLCpjGGn2BPAvBeWXPQKBgEewKN6op/pZmmi9Bay5/bAQ1TnQKYcPdnuyl9K0
+/ruespeTsFw0bhqC11qhw8gsKZIri0z3TusNEwM2hQU08uQlEnkQcaoXQoTHOcQy
+4NJo575Tf0r4ePBnqXA7VWcViJtEFTszPYtvLzz2VyBU9b4aP+73AN4EVW0/vx+v
+SG3BAoGBAMzESFA2TXwUFmozK5zowIszc995Xqpi7mXKk77WESOpoS1dQ1wF1dSg
+XOwxzFoYovLxcc1K9lqOrod8BV+qGuEfc/PIJ2aiXjvEDeZYX2eWaANNmj4OSLoJ
+MNYj9tZxbq56slD7snf7AgUBnwKz0Pj6H6UsbE3gdJqZWCDyw/bB
+-----END RSA PRIVATE KEY-----
diff --git a/util/libcrypto.num b/util/libcrypto.num
index 0553f88859..c4f1b94cb8 100644
--- a/util/libcrypto.num
+++ b/util/libcrypto.num
@@ -4910,3 +4910,4 @@ d2i_X509_PUBKEY_bio                     ?	3_0_0	EXIST::FUNCTION:
 i2d_X509_PUBKEY_bio                     ?	3_0_0	EXIST::FUNCTION:
 RSA_get0_pss_params                     ?	3_0_0	EXIST::FUNCTION:RSA
 X509_cmp_timeframe                      ?	3_0_0	EXIST::FUNCTION:
+OSSL_CMP_MSG_get0_header                ?	3_0_0	EXIST::FUNCTION:CMP
diff --git a/util/other.syms b/util/other.syms
index e07471f9ab..51b4dfa255 100644
--- a/util/other.syms
+++ b/util/other.syms
@@ -348,6 +348,8 @@ OSSL_CMP_LOG_ERR                        define
 OSSL_CMP_LOG_INFO                       define
 OSSL_CMP_LOG_NOTICE                     define
 OSSL_CMP_LOG_WARNING                    define
+OSSL_CMP_MSTR_HELPER                    define
+OSSL_CMP_MSTR                           define
 OSSL_CMP_alert                          define
 OSSL_CMP_debug                          define
 OSSL_CMP_err                            define


More information about the openssl-commits mailing list