[openssl] master update

Matt Caswell matt at openssl.org
Tue Oct 29 14:18:20 UTC 2019


The branch master has been updated
       via  4dde554c6ae2375ce53b24cc535124355c339462 (commit)
      from  0a4d6c67480a4d2fce514e08d3efe571f2ee99c9 (commit)


- Log -----------------------------------------------------------------
commit 4dde554c6ae2375ce53b24cc535124355c339462
Author: Dr. David von Oheimb <David.von.Oheimb at siemens.com>
Date:   Fri Sep 27 10:22:23 2019 +0200

    chunk 5 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/10036)

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

Summary of changes:
 crypto/cmp/build.info                         |   3 +-
 crypto/cmp/cmp_asn.c                          |   9 +-
 crypto/cmp/cmp_ctx.c                          |   2 +-
 crypto/cmp/cmp_err.c                          |   6 +
 crypto/cmp/cmp_hdr.c                          | 377 +++++++++++++++++++++
 crypto/cmp/cmp_local.h                        |  32 +-
 crypto/cmp/cmp_status.c                       | 302 +++++++++++++++++
 crypto/err/openssl.txt                        |   3 +
 doc/internal/man3/ossl_cmp_hdr_init.pod       | 127 +++++++
 doc/internal/man3/ossl_cmp_statusinfo_new.pod | 107 ++++++
 doc/man3/OSSL_CMP_CTX_snprint_PKIStatus.pod   |  46 +++
 doc/man3/OSSL_CMP_HDR_get0_transactionID.pod  |  47 +++
 include/openssl/cmp.h                         |   9 +
 include/openssl/cmperr.h                      |   3 +
 test/build.info                               |  10 +-
 test/cmp_asn_test.c                           |  14 +-
 test/cmp_ctx_test.c                           |   5 +-
 test/cmp_hdr_test.c                           | 468 ++++++++++++++++++++++++++
 test/cmp_status_test.c                        | 111 ++++++
 test/recipes/65-test_cmp_hdr.t                |  22 ++
 test/recipes/65-test_cmp_status.t             |  22 ++
 util/libcrypto.num                            |   3 +
 22 files changed, 1705 insertions(+), 23 deletions(-)
 create mode 100644 crypto/cmp/cmp_hdr.c
 create mode 100644 crypto/cmp/cmp_status.c
 create mode 100644 doc/internal/man3/ossl_cmp_hdr_init.pod
 create mode 100644 doc/internal/man3/ossl_cmp_statusinfo_new.pod
 create mode 100644 doc/man3/OSSL_CMP_CTX_snprint_PKIStatus.pod
 create mode 100644 doc/man3/OSSL_CMP_HDR_get0_transactionID.pod
 create mode 100644 test/cmp_hdr_test.c
 create mode 100644 test/cmp_status_test.c
 create mode 100644 test/recipes/65-test_cmp_hdr.t
 create mode 100644 test/recipes/65-test_cmp_status.t

diff --git a/crypto/cmp/build.info b/crypto/cmp/build.info
index d5ce60e040..154022762a 100644
--- a/crypto/cmp/build.info
+++ b/crypto/cmp/build.info
@@ -1,2 +1,3 @@
 LIBS=../../libcrypto
-SOURCE[../../libcrypto]= cmp_asn.c cmp_ctx.c cmp_err.c cmp_util.c
+SOURCE[../../libcrypto]= cmp_asn.c cmp_ctx.c cmp_err.c cmp_util.c \
+        cmp_status.c cmp_hdr.c
diff --git a/crypto/cmp/cmp_asn.c b/crypto/cmp/cmp_asn.c
index fa7c26d78e..ca121b068a 100644
--- a/crypto/cmp/cmp_asn.c
+++ b/crypto/cmp/cmp_asn.c
@@ -164,7 +164,7 @@ int OSSL_CMP_ITAV_push0_stack_item(STACK_OF(OSSL_CMP_ITAV) **itav_sk_p,
 {
     int created = 0;
 
-    if (itav_sk_p == NULL) {
+    if (itav_sk_p == NULL || itav == NULL) {
         CMPerr(0, CMP_R_NULL_ARGUMENT);
         goto err;
     }
@@ -174,11 +174,10 @@ int OSSL_CMP_ITAV_push0_stack_item(STACK_OF(OSSL_CMP_ITAV) **itav_sk_p,
             goto err;
         created = 1;
     }
-    if (itav != NULL) {
-        if (!sk_OSSL_CMP_ITAV_push(*itav_sk_p, itav))
-            goto err;
-    }
+    if (!sk_OSSL_CMP_ITAV_push(*itav_sk_p, itav))
+        goto err;
     return 1;
+
  err:
     if (created != 0) {
         sk_OSSL_CMP_ITAV_free(*itav_sk_p);
diff --git a/crypto/cmp/cmp_ctx.c b/crypto/cmp/cmp_ctx.c
index 6ec23ad877..4a70b33ee7 100644
--- a/crypto/cmp/cmp_ctx.c
+++ b/crypto/cmp/cmp_ctx.c
@@ -195,7 +195,7 @@ void OSSL_CMP_CTX_free(OSSL_CMP_CTX *ctx)
 int ossl_cmp_ctx_set_status(OSSL_CMP_CTX *ctx, int status)
 {
     if (!ossl_assert(ctx != NULL))
-         return 0;
+        return 0;
     ctx->status = status;
     return 1;
 }
diff --git a/crypto/cmp/cmp_err.c b/crypto/cmp/cmp_err.c
index 4086d5220b..683b8472d7 100644
--- a/crypto/cmp/cmp_err.c
+++ b/crypto/cmp/cmp_err.c
@@ -15,9 +15,15 @@
 #ifndef OPENSSL_NO_ERR
 
 static const ERR_STRING_DATA CMP_str_reasons[] = {
+    {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_ERROR_PARSING_PKISTATUS),
+    "error parsing pkistatus"},
+    {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_FAILURE_OBTAINING_RANDOM),
+    "failure obtaining random"},
     {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_SENDER_IDENTIFICATION),
+    "missing sender identification"},
     {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_NO_STDIO), "no stdio"},
     {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_NULL_ARGUMENT), "null argument"},
     {0, NULL}
diff --git a/crypto/cmp/cmp_hdr.c b/crypto/cmp/cmp_hdr.c
new file mode 100644
index 0000000000..29f477f1b5
--- /dev/null
+++ b/crypto/cmp/cmp_hdr.c
@@ -0,0 +1,377 @@
+/*
+ * 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 PKIHeader handling */
+
+#include "cmp_local.h"
+
+#include <openssl/rand.h>
+
+/* explicit #includes not strictly needed since implied by the above: */
+#include <openssl/asn1t.h>
+#include <openssl/cmp.h>
+#include <openssl/err.h>
+
+int ossl_cmp_hdr_set_pvno(OSSL_CMP_PKIHEADER *hdr, int pvno)
+{
+    if (!ossl_assert(hdr != NULL))
+        return 0;
+    return ASN1_INTEGER_set(hdr->pvno, pvno);
+}
+
+int ossl_cmp_hdr_get_pvno(const OSSL_CMP_PKIHEADER *hdr)
+{
+    int64_t pvno;
+
+    if (!ossl_assert(hdr != NULL))
+        return -1;
+    if (!ASN1_INTEGER_get_int64(&pvno, hdr->pvno) || pvno < 0 || pvno > INT_MAX)
+        return -1;
+    return (int)pvno;
+}
+
+ASN1_OCTET_STRING *OSSL_CMP_HDR_get0_transactionID(const OSSL_CMP_PKIHEADER *hdr)
+{
+    if (hdr == NULL) {
+        CMPerr(0, CMP_R_NULL_ARGUMENT);
+        return NULL;
+    }
+    return hdr->transactionID;
+}
+
+ASN1_OCTET_STRING *ossl_cmp_hdr_get0_senderNonce(const OSSL_CMP_PKIHEADER *hdr)
+{
+    if (!ossl_assert(hdr != NULL))
+        return NULL;
+    return hdr->senderNonce;
+}
+
+ASN1_OCTET_STRING *OSSL_CMP_HDR_get0_recipNonce(const OSSL_CMP_PKIHEADER *hdr)
+{
+    if (hdr == NULL) {
+        CMPerr(0, CMP_R_NULL_ARGUMENT);
+        return NULL;
+    }
+    return hdr->recipNonce;
+}
+
+/* assign to *tgt a copy of src (which may be NULL to indicate an empty DN) */
+static int set1_general_name(GENERAL_NAME **tgt, const X509_NAME *src)
+{
+    GENERAL_NAME *gen;
+
+    if (!ossl_assert(tgt != NULL))
+        return 0;
+    if ((gen = GENERAL_NAME_new()) == NULL)
+        goto err;
+    gen->type = GEN_DIRNAME;
+
+    if (src == NULL) { /* NULL-DN */
+        if ((gen->d.directoryName = X509_NAME_new()) == NULL)
+            goto err;
+    } else if (!X509_NAME_set(&gen->d.directoryName, src)) {
+        goto err;
+    }
+
+    GENERAL_NAME_free(*tgt);
+    *tgt = gen;
+
+    return 1;
+
+ err:
+    GENERAL_NAME_free(gen);
+    return 0;
+}
+
+/*
+ * Set the sender name in PKIHeader.
+ * when nm is NULL, sender is set to an empty string
+ * returns 1 on success, 0 on error
+ */
+int ossl_cmp_hdr_set1_sender(OSSL_CMP_PKIHEADER *hdr, const X509_NAME *nm)
+{
+    if (!ossl_assert(hdr != NULL))
+        return 0;
+    return set1_general_name(&hdr->sender, nm);
+}
+
+int ossl_cmp_hdr_set1_recipient(OSSL_CMP_PKIHEADER *hdr, const X509_NAME *nm)
+{
+    if (!ossl_assert(hdr != NULL))
+        return 0;
+    return set1_general_name(&hdr->recipient, nm);
+}
+
+int ossl_cmp_hdr_update_messageTime(OSSL_CMP_PKIHEADER *hdr)
+{
+    if (!ossl_assert(hdr != NULL))
+        return 0;
+    if (hdr->messageTime == NULL
+            && (hdr->messageTime = ASN1_GENERALIZEDTIME_new()) == NULL)
+        return 0;
+    return ASN1_GENERALIZEDTIME_set(hdr->messageTime, time(NULL)) != NULL;
+}
+
+/* assign to *tgt a copy of src (or if NULL a random byte array of given len) */
+static int set1_aostr_else_random(ASN1_OCTET_STRING **tgt,
+                                  const ASN1_OCTET_STRING *src, size_t len)
+{
+    unsigned char *bytes = NULL;
+    int res = 0;
+
+    if (src == NULL) { /* generate a random value if src == NULL */
+        if ((bytes = OPENSSL_malloc(len)) == NULL)
+            goto err;
+        if (RAND_bytes(bytes, len) <= 0) {
+            CMPerr(0, CMP_R_FAILURE_OBTAINING_RANDOM);
+            goto err;
+        }
+        res = ossl_cmp_asn1_octet_string_set1_bytes(tgt, bytes, len);
+    } else {
+        res = ossl_cmp_asn1_octet_string_set1(tgt, src);
+    }
+
+ err:
+    OPENSSL_free(bytes);
+    return res;
+}
+
+int ossl_cmp_hdr_set1_senderKID(OSSL_CMP_PKIHEADER *hdr,
+                                const ASN1_OCTET_STRING *senderKID)
+{
+    if (!ossl_assert(hdr != NULL))
+        return 0;
+    return ossl_cmp_asn1_octet_string_set1(&hdr->senderKID, senderKID);
+}
+
+/* push the given text string to the given PKIFREETEXT ft */
+int ossl_cmp_pkifreetext_push_str(OSSL_CMP_PKIFREETEXT *ft, const char *text)
+{
+    ASN1_UTF8STRING *utf8string;
+
+    if (!ossl_assert(ft != NULL && text != NULL))
+        return 0;
+    if ((utf8string = ASN1_UTF8STRING_new()) == NULL)
+        return 0;
+    if (!ASN1_STRING_set(utf8string, text, -1))
+        goto err;
+    if (!sk_ASN1_UTF8STRING_push(ft, utf8string))
+        goto err;
+    return 1;
+
+ err:
+    ASN1_UTF8STRING_free(utf8string);
+    return 0;
+}
+
+int ossl_cmp_hdr_push0_freeText(OSSL_CMP_PKIHEADER *hdr, ASN1_UTF8STRING *text)
+{
+    if (!ossl_assert(hdr != NULL && text != NULL))
+        return 0;
+
+    if (hdr->freeText == NULL
+            && (hdr->freeText = sk_ASN1_UTF8STRING_new_null()) == NULL)
+        return 0;
+
+    return sk_ASN1_UTF8STRING_push(hdr->freeText, text);
+}
+
+int ossl_cmp_hdr_push1_freeText(OSSL_CMP_PKIHEADER *hdr, ASN1_UTF8STRING *text)
+{
+    if (!ossl_assert(hdr != NULL && text != NULL))
+        return 0;
+
+    if (hdr->freeText == NULL
+            && (hdr->freeText = sk_ASN1_UTF8STRING_new_null()) == NULL)
+        return 0;
+
+    return ossl_cmp_pkifreetext_push_str(hdr->freeText, (char *)text->data);
+}
+
+int ossl_cmp_hdr_generalInfo_push0_item(OSSL_CMP_PKIHEADER *hdr,
+                                        OSSL_CMP_ITAV *itav)
+{
+    if (!ossl_assert(hdr != NULL && itav != NULL))
+        return 0;
+    return OSSL_CMP_ITAV_push0_stack_item(&hdr->generalInfo, itav);
+}
+
+int ossl_cmp_hdr_generalInfo_push1_items(OSSL_CMP_PKIHEADER *hdr,
+                                         STACK_OF(OSSL_CMP_ITAV) *itavs)
+{
+    int i;
+    OSSL_CMP_ITAV *itav;
+
+    if (!ossl_assert(hdr != NULL))
+        return 0;
+
+    for (i = 0; i < sk_OSSL_CMP_ITAV_num(itavs); i++) {
+        itav = OSSL_CMP_ITAV_dup(sk_OSSL_CMP_ITAV_value(itavs, i));
+        if (itav == NULL)
+            return 0;
+
+        if (!ossl_cmp_hdr_generalInfo_push0_item(hdr, itav)) {
+            OSSL_CMP_ITAV_free(itav);
+            return 0;
+        }
+    }
+    return 1;
+}
+
+int ossl_cmp_hdr_set_implicitConfirm(OSSL_CMP_PKIHEADER *hdr)
+{
+    OSSL_CMP_ITAV *itav;
+    ASN1_TYPE *asn1null;
+
+    if (!ossl_assert(hdr != NULL))
+        return 0;
+    asn1null = (ASN1_TYPE *)ASN1_NULL_new();
+    if (asn1null == NULL)
+        return 0;
+    if ((itav = OSSL_CMP_ITAV_create(OBJ_nid2obj(NID_id_it_implicitConfirm),
+                                     asn1null)) == NULL)
+        goto err;
+    if (!ossl_cmp_hdr_generalInfo_push0_item(hdr, itav))
+        goto err;
+    return 1;
+
+ err:
+    ASN1_TYPE_free(asn1null);
+    OSSL_CMP_ITAV_free(itav);
+    return 0;
+}
+
+/* return 1 if implicitConfirm in the generalInfo field of the header is set */
+int ossl_cmp_hdr_check_implicitConfirm(const OSSL_CMP_PKIHEADER *hdr)
+{
+    int itavCount;
+    int i;
+    OSSL_CMP_ITAV *itav;
+
+    if (!ossl_assert(hdr != NULL))
+        return 0;
+
+    itavCount = sk_OSSL_CMP_ITAV_num(hdr->generalInfo);
+    for (i = 0; i < itavCount; i++) {
+        itav = sk_OSSL_CMP_ITAV_value(hdr->generalInfo, i);
+        if (itav != NULL
+                && OBJ_obj2nid(itav->infoType) == NID_id_it_implicitConfirm)
+            return 1;
+    }
+
+    return 0;
+}
+
+/* fill in all fields of the hdr according to the info given in ctx */
+int ossl_cmp_hdr_init(OSSL_CMP_CTX *ctx, OSSL_CMP_PKIHEADER *hdr)
+{
+    X509_NAME *sender;
+    X509_NAME *rcp = NULL;
+
+    if (!ossl_assert(ctx != NULL && hdr != NULL))
+        return 0;
+
+    /* set the CMP version */
+    if (!ossl_cmp_hdr_set_pvno(hdr, OSSL_CMP_PVNO))
+        return 0;
+
+    sender = ctx->clCert != NULL ?
+        X509_get_subject_name(ctx->clCert) : ctx->subjectName;
+    /*
+     * The sender name is copied from the subject of the client cert, if any,
+     * or else from the the subject name provided for certification requests.
+     * As required by RFC 4210 section 5.1.1., if the sender name is not known
+     * to the client it set to NULL-DN. In this case for identification at least
+     * the senderKID must be set, which we take from any referenceValue given.
+     */
+    if (sender == NULL && ctx->referenceValue == NULL) {
+        CMPerr(0, CMP_R_MISSING_SENDER_IDENTIFICATION);
+        return 0;
+    }
+    if (!ossl_cmp_hdr_set1_sender(hdr, sender))
+        return 0;
+
+    /* determine recipient entry in PKIHeader */
+    if (ctx->srvCert != NULL) {
+        rcp = X509_get_subject_name(ctx->srvCert);
+        /* set also as expected_sender of responses unless set explicitly */
+        if (ctx->expected_sender == NULL && rcp != NULL
+                && !OSSL_CMP_CTX_set1_expected_sender(ctx, rcp))
+            return 0;
+    } else if (ctx->recipient != NULL) {
+        rcp = ctx->recipient;
+    } else if (ctx->issuer != NULL) {
+        rcp = ctx->issuer;
+    } else if (ctx->oldCert != NULL) {
+        rcp = X509_get_issuer_name(ctx->oldCert);
+    } else if (ctx->clCert != NULL) {
+        rcp = X509_get_issuer_name(ctx->clCert);
+    }
+    if (!ossl_cmp_hdr_set1_recipient(hdr, rcp))
+        return 0;
+
+    /* set current time as message time */
+    if (!ossl_cmp_hdr_update_messageTime(hdr))
+        return 0;
+
+    if (ctx->recipNonce != NULL
+            && !ossl_cmp_asn1_octet_string_set1(&hdr->recipNonce,
+                                                ctx->recipNonce))
+        return 0;
+
+    /*
+     * set ctx->transactionID in CMP header
+     * if ctx->transactionID is NULL, a random one is created with 128 bit
+     * according to section 5.1.1:
+     *
+     * It is RECOMMENDED that the clients fill the transactionID field with
+     * 128 bits of (pseudo-) random data for the start of a transaction to
+     * reduce the probability of having the transactionID in use at the server.
+     */
+    if (ctx->transactionID == NULL
+            && !set1_aostr_else_random(&ctx->transactionID, NULL,
+                                       OSSL_CMP_TRANSACTIONID_LENGTH))
+        return 0;
+    if (!ossl_cmp_asn1_octet_string_set1(&hdr->transactionID,
+                                         ctx->transactionID))
+        return 0;
+
+    /*-
+     * set random senderNonce
+     * according to section 5.1.1:
+     *
+     * senderNonce                  present
+     *         -- 128 (pseudo-)random bits
+     * The senderNonce and recipNonce fields protect the PKIMessage against
+     * replay attacks. The senderNonce will typically be 128 bits of
+     * (pseudo-) random data generated by the sender, whereas the recipNonce
+     * is copied from the senderNonce of the previous message in the
+     * transaction.
+     */
+    if (!set1_aostr_else_random(&hdr->senderNonce, NULL,
+                                OSSL_CMP_SENDERNONCE_LENGTH))
+        return 0;
+
+    /* store senderNonce - for cmp with recipNonce in next outgoing msg */
+    if (!OSSL_CMP_CTX_set1_senderNonce(ctx, hdr->senderNonce))
+        return 0;
+
+    /*-
+     * freeText                [7] PKIFreeText OPTIONAL,
+     * -- this may be used to indicate context-specific instructions
+     * -- (this field is intended for human consumption)
+     */
+    if (ctx->freeText != NULL
+            && !ossl_cmp_hdr_push1_freeText(hdr, ctx->freeText))
+        return 0;
+
+    return 1;
+}
diff --git a/crypto/cmp/cmp_local.h b/crypto/cmp/cmp_local.h
index 1a7dcca3bd..b49ead62df 100644
--- a/crypto/cmp/cmp_local.h
+++ b/crypto/cmp/cmp_local.h
@@ -77,6 +77,7 @@ struct ossl_cmp_ctx_st {
     ASN1_OCTET_STRING *transactionID; /* the current transaction ID */
     ASN1_OCTET_STRING *senderNonce; /* last nonce sent */
     ASN1_OCTET_STRING *recipNonce; /* last nonce received */
+    ASN1_UTF8STRING *freeText; /* optional string to include each msg */
     STACK_OF(OSSL_CMP_ITAV) *geninfo_ITAVs;
     int implicitConfirm; /* set implicitConfirm in IR/KUR/CR messages */
     int disableConfirm; /* disable certConf in IR/KUR/CR for broken servers */
@@ -720,6 +721,35 @@ int ossl_cmp_ctx_set1_extraCertsIn(OSSL_CMP_CTX *ctx,
 int ossl_cmp_ctx_set1_recipNonce(OSSL_CMP_CTX *ctx,
                                  const ASN1_OCTET_STRING *nonce);
 
-#  define OSSL_CMP_TRANSACTIONID_LENGTH 16
+/* from cmp_status.c */
+OSSL_CMP_PKISI *
+ossl_cmp_statusinfo_new(int status, int fail_info, const char *text);
+int ossl_cmp_pkisi_get_pkistatus(const OSSL_CMP_PKISI *statusInfo);
+const char *ossl_cmp_PKIStatus_to_string(int status);
+OSSL_CMP_PKIFREETEXT *ossl_cmp_pkisi_get0_statusstring(const OSSL_CMP_PKISI *si);
+int ossl_cmp_pkisi_get_pkifailureinfo(const OSSL_CMP_PKISI *si);
+int ossl_cmp_pkisi_pkifailureinfo_check(const OSSL_CMP_PKISI *si, int bit_index);
+
+/* from cmp_hdr.c */
+int ossl_cmp_hdr_set_pvno(OSSL_CMP_PKIHEADER *hdr, int pvno);
+int ossl_cmp_hdr_get_pvno(const OSSL_CMP_PKIHEADER *hdr);
+ASN1_OCTET_STRING *ossl_cmp_hdr_get0_senderNonce(const OSSL_CMP_PKIHEADER *hdr);
+int ossl_cmp_hdr_set1_sender(OSSL_CMP_PKIHEADER *hdr, const X509_NAME *nm);
+int ossl_cmp_hdr_set1_recipient(OSSL_CMP_PKIHEADER *hdr, const X509_NAME *nm);
+int ossl_cmp_hdr_update_messageTime(OSSL_CMP_PKIHEADER *hdr);
+int ossl_cmp_hdr_set1_senderKID(OSSL_CMP_PKIHEADER *hdr,
+                                const ASN1_OCTET_STRING *senderKID);
+int ossl_cmp_pkifreetext_push_str(OSSL_CMP_PKIFREETEXT *ft, const char *text);
+int ossl_cmp_hdr_push0_freeText(OSSL_CMP_PKIHEADER *hdr, ASN1_UTF8STRING *text);
+int ossl_cmp_hdr_push1_freeText(OSSL_CMP_PKIHEADER *hdr, ASN1_UTF8STRING *text);
+int ossl_cmp_hdr_generalInfo_push0_item(OSSL_CMP_PKIHEADER *hdr,
+                                        OSSL_CMP_ITAV *itav);
+int ossl_cmp_hdr_generalInfo_push1_items(OSSL_CMP_PKIHEADER *hdr,
+                                         STACK_OF(OSSL_CMP_ITAV) *itavs);
+int ossl_cmp_hdr_set_implicitConfirm(OSSL_CMP_PKIHEADER *hdr);
+int ossl_cmp_hdr_check_implicitConfirm(const OSSL_CMP_PKIHEADER *hdr);
+# define OSSL_CMP_TRANSACTIONID_LENGTH 16
+# define OSSL_CMP_SENDERNONCE_LENGTH 16
+int ossl_cmp_hdr_init(OSSL_CMP_CTX *ctx, OSSL_CMP_PKIHEADER *hdr);
 
 #endif /* !defined OSSL_CRYPTO_CMP_LOCAL_H */
diff --git a/crypto/cmp/cmp_status.c b/crypto/cmp/cmp_status.c
new file mode 100644
index 0000000000..f6b7978a4f
--- /dev/null
+++ b/crypto/cmp/cmp_status.c
@@ -0,0 +1,302 @@
+/*
+ * 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 PKIStatusInfo handling and PKIMessage decomposition */
+
+#include <string.h>
+
+#include "cmp_local.h"
+
+/* explicit #includes not strictly needed since implied by the above: */
+#include <time.h>
+#include <openssl/cmp.h>
+#include <openssl/crmf.h>
+#include <openssl/err.h> /* needed in case config no-deprecated */
+#include <openssl/engine.h>
+#include <openssl/evp.h>
+#include <openssl/objects.h>
+#include <openssl/x509.h>
+#include <openssl/asn1err.h> /* for ASN1_R_TOO_SMALL and ASN1_R_TOO_LARGE */
+
+/* CMP functions related to PKIStatus */
+
+int ossl_cmp_pkisi_get_pkistatus(const OSSL_CMP_PKISI *si)
+{
+    if (!ossl_assert(si != NULL && si->status != NULL))
+        return -1;
+    return ossl_cmp_asn1_get_int(si->status);
+}
+
+/*
+ * return the declared identifier and a short explanation for the PKIStatus
+ * value as specified in RFC4210, Appendix F.
+ */
+const char *ossl_cmp_PKIStatus_to_string(int status)
+{
+    switch (status) {
+    case OSSL_CMP_PKISTATUS_accepted:
+        return "PKIStatus: accepted";
+    case OSSL_CMP_PKISTATUS_grantedWithMods:
+        return "PKIStatus: granted with modifications";
+    case OSSL_CMP_PKISTATUS_rejection:
+        return "PKIStatus: rejection";
+    case OSSL_CMP_PKISTATUS_waiting:
+        return "PKIStatus: waiting";
+    case OSSL_CMP_PKISTATUS_revocationWarning:
+        return "PKIStatus: revocation warning - a revocation of the cert is imminent";
+    case OSSL_CMP_PKISTATUS_revocationNotification:
+        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: 
+        {
+            char buf[40];
+            BIO_snprintf(buf, sizeof(buf), "PKIStatus: invalid=%d", status);
+            CMPerr(0, CMP_R_ERROR_PARSING_PKISTATUS);
+            ossl_cmp_add_error_data(buf);
+            return NULL;
+        }
+    }
+}
+
+/*
+ * returns a pointer to the statusString contained in a PKIStatusInfo
+ * returns NULL on error
+ */
+OSSL_CMP_PKIFREETEXT *ossl_cmp_pkisi_get0_statusstring(const OSSL_CMP_PKISI *si)
+{
+    if (!ossl_assert(si != NULL))
+        return NULL;
+    return si->statusString;
+}
+
+/*
+ * returns the FailureInfo bits of the given PKIStatusInfo
+ * returns -1 on error
+ */
+int ossl_cmp_pkisi_get_pkifailureinfo(const OSSL_CMP_PKISI *si)
+{
+    int i;
+    int res = 0;
+
+    if (!ossl_assert(si != NULL && si->failInfo != NULL))
+        return -1;
+    for (i = 0; i <= OSSL_CMP_PKIFAILUREINFO_MAX; i++)
+        if (ASN1_BIT_STRING_get_bit(si->failInfo, i))
+            res |= 1 << i;
+    return res;
+}
+
+/*
+ * internal function
+ * convert PKIFailureInfo number to human-readable string
+ *
+ * returns pointer to static string
+ * returns NULL on error
+ */
+static const char *CMP_PKIFAILUREINFO_to_string(int number)
+{
+    switch (number) {
+    case OSSL_CMP_PKIFAILUREINFO_badAlg:
+        return "badAlg";
+    case OSSL_CMP_PKIFAILUREINFO_badMessageCheck:
+        return "badMessageCheck";
+    case OSSL_CMP_PKIFAILUREINFO_badRequest:
+        return "badRequest";
+    case OSSL_CMP_PKIFAILUREINFO_badTime:
+        return "badTime";
+    case OSSL_CMP_PKIFAILUREINFO_badCertId:
+        return "badCertId";
+    case OSSL_CMP_PKIFAILUREINFO_badDataFormat:
+        return "badDataFormat";
+    case OSSL_CMP_PKIFAILUREINFO_wrongAuthority:
+        return "wrongAuthority";
+    case OSSL_CMP_PKIFAILUREINFO_incorrectData:
+        return "incorrectData";
+    case OSSL_CMP_PKIFAILUREINFO_missingTimeStamp:
+        return "missingTimeStamp";
+    case OSSL_CMP_PKIFAILUREINFO_badPOP:
+        return "badPOP";
+    case OSSL_CMP_PKIFAILUREINFO_certRevoked:
+        return "certRevoked";
+    case OSSL_CMP_PKIFAILUREINFO_certConfirmed:
+        return "certConfirmed";
+    case OSSL_CMP_PKIFAILUREINFO_wrongIntegrity:
+        return "wrongIntegrity";
+    case OSSL_CMP_PKIFAILUREINFO_badRecipientNonce:
+        return "badRecipientNonce";
+    case OSSL_CMP_PKIFAILUREINFO_timeNotAvailable:
+        return "timeNotAvailable";
+    case OSSL_CMP_PKIFAILUREINFO_unacceptedPolicy:
+        return "unacceptedPolicy";
+    case OSSL_CMP_PKIFAILUREINFO_unacceptedExtension:
+        return "unacceptedExtension";
+    case OSSL_CMP_PKIFAILUREINFO_addInfoNotAvailable:
+        return "addInfoNotAvailable";
+    case OSSL_CMP_PKIFAILUREINFO_badSenderNonce:
+        return "badSenderNonce";
+    case OSSL_CMP_PKIFAILUREINFO_badCertTemplate:
+        return "badCertTemplate";
+    case OSSL_CMP_PKIFAILUREINFO_signerNotTrusted:
+        return "signerNotTrusted";
+    case OSSL_CMP_PKIFAILUREINFO_transactionIdInUse:
+        return "transactionIdInUse";
+    case OSSL_CMP_PKIFAILUREINFO_unsupportedVersion:
+        return "unsupportedVersion";
+    case OSSL_CMP_PKIFAILUREINFO_notAuthorized:
+        return "notAuthorized";
+    case OSSL_CMP_PKIFAILUREINFO_systemUnavail:
+        return "systemUnavail";
+    case OSSL_CMP_PKIFAILUREINFO_systemFailure:
+        return "systemFailure";
+    case OSSL_CMP_PKIFAILUREINFO_duplicateCertReq:
+        return "duplicateCertReq";
+    default:
+        return NULL; /* illegal failure number */
+    }
+}
+
+/*
+ * checks PKIFailureInfo bits in a given PKIStatusInfo
+ * returns 1 if a given bit is set, 0 if not, -1 on error
+ */
+int ossl_cmp_pkisi_pkifailureinfo_check(const OSSL_CMP_PKISI *si, int bit_index)
+{
+    if (!ossl_assert(si != NULL && si->failInfo != NULL))
+        return -1;
+    if (bit_index < 0 || bit_index > OSSL_CMP_PKIFAILUREINFO_MAX) {
+        CMPerr(0, CMP_R_INVALID_ARGS);
+        return -1;
+    }
+
+    return ASN1_BIT_STRING_get_bit(si->failInfo, bit_index);
+}
+
+/*
+ * place human-readable error string created from PKIStatusInfo in given buffer
+ * returns pointer to the same buffer containing the string, or NULL on error
+ */
+char *OSSL_CMP_CTX_snprint_PKIStatus(OSSL_CMP_CTX *ctx, char *buf,
+                                     size_t bufsize)
+{
+    int status, failure, fail_info;
+    const char *status_string, *failure_string;
+    OSSL_CMP_PKIFREETEXT *status_strings;
+    ASN1_UTF8STRING *text;
+    int i;
+    int printed_chars;
+    int failinfo_found = 0;
+    int n_status_strings;
+    char* write_ptr = buf;
+
+#define ADVANCE_BUFFER                                         \
+    if (printed_chars < 0 || (size_t)printed_chars >= bufsize) \
+        return NULL; \
+    write_ptr += printed_chars; \
+    bufsize -= printed_chars;
+
+    if (ctx == NULL
+            || buf == NULL
+            || (status = OSSL_CMP_CTX_get_status(ctx)) < 0
+            || (status_string = ossl_cmp_PKIStatus_to_string(status)) == NULL)
+        return NULL;
+    printed_chars = BIO_snprintf(write_ptr, bufsize, "%s", status_string);
+    ADVANCE_BUFFER;
+
+    /* failInfo is optional and may be empty */
+    if ((fail_info = OSSL_CMP_CTX_get_failInfoCode(ctx)) > 0) {
+        printed_chars = BIO_snprintf(write_ptr, bufsize, "; PKIFailureInfo: ");
+        ADVANCE_BUFFER;
+        for (failure = 0; failure <= OSSL_CMP_PKIFAILUREINFO_MAX; failure++) {
+            if ((fail_info & (1 << failure)) != 0) {
+                failure_string = CMP_PKIFAILUREINFO_to_string(failure);
+                if (failure_string != NULL) {
+                    printed_chars = BIO_snprintf(write_ptr, bufsize, "%s%s",
+                                                 failure > 0 ? ", " : "",
+                                                 failure_string);
+                    ADVANCE_BUFFER;
+                    failinfo_found = 1;
+                }
+            }
+        }
+    }
+    if (!failinfo_found && status != OSSL_CMP_PKISTATUS_accepted
+            && status != OSSL_CMP_PKISTATUS_grantedWithMods) {
+        printed_chars = BIO_snprintf(write_ptr, bufsize, "; <no failure info>");
+        ADVANCE_BUFFER;
+    }
+
+    /* statusString sequence is optional and may be empty */
+    status_strings = OSSL_CMP_CTX_get0_statusString(ctx);
+    n_status_strings = sk_ASN1_UTF8STRING_num(status_strings);
+    if (n_status_strings > 0) {
+        printed_chars = BIO_snprintf(write_ptr, bufsize, "; StatusString%s: ",
+                                     n_status_strings > 1 ? "s" : "");
+        ADVANCE_BUFFER;
+        for (i = 0; i < n_status_strings; i++) {
+            text = sk_ASN1_UTF8STRING_value(status_strings, i);
+            printed_chars = BIO_snprintf(write_ptr, bufsize, "\"%s\"%s",
+                                         ASN1_STRING_get0_data(text),
+                                         i < n_status_strings - 1 ? ", " : "");
+            ADVANCE_BUFFER;
+        }
+    }
+#undef ADVANCE_BUFFER
+    return buf;
+}
+
+/*
+ * Creates a new PKIStatusInfo structure and fills it in
+ * returns a pointer to the structure on success, NULL on error
+ * note: strongly overlaps with TS_RESP_CTX_set_status_info()
+ * and TS_RESP_CTX_add_failure_info() in ../ts/ts_rsp_sign.c
+ */
+OSSL_CMP_PKISI *ossl_cmp_statusinfo_new(int status, int fail_info,
+                                        const char *text)
+{
+    OSSL_CMP_PKISI *si = OSSL_CMP_PKISI_new();
+    ASN1_UTF8STRING *utf8_text = NULL;
+    int failure;
+
+    if (si == NULL)
+        goto err;
+    if (!ASN1_INTEGER_set(si->status, status))
+        goto err;
+
+    if (text != NULL) {
+        if ((utf8_text = ASN1_UTF8STRING_new()) == NULL
+                || !ASN1_STRING_set(utf8_text, text, -1))
+            goto err;
+        if ((si->statusString = sk_ASN1_UTF8STRING_new_null()) == NULL)
+            goto err;
+        if (!sk_ASN1_UTF8STRING_push(si->statusString, utf8_text))
+            goto err;
+        /* Ownership is lost. */
+        utf8_text = NULL;
+    }
+
+    for (failure = 0; failure <= OSSL_CMP_PKIFAILUREINFO_MAX; failure++) {
+        if ((fail_info & (1 << failure)) != 0) {
+            if (si->failInfo == NULL
+                    && (si->failInfo = ASN1_BIT_STRING_new()) == NULL)
+                goto err;
+            if (!ASN1_BIT_STRING_set_bit(si->failInfo, failure, 1))
+                goto err;
+        }
+    }
+    return si;
+
+ err:
+    OSSL_CMP_PKISI_free(si);
+    ASN1_UTF8STRING_free(utf8_text);
+    return NULL;
+}
+
diff --git a/crypto/err/openssl.txt b/crypto/err/openssl.txt
index 9f405018c4..27aad6a6ce 100644
--- a/crypto/err/openssl.txt
+++ b/crypto/err/openssl.txt
@@ -2063,8 +2063,11 @@ 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_ERROR_PARSING_PKISTATUS:107:error parsing pkistatus
+CMP_R_FAILURE_OBTAINING_RANDOM:110:failure obtaining random
 CMP_R_INVALID_ARGS:100:invalid args
 CMP_R_MULTIPLE_SAN_SOURCES:102:multiple san sources
+CMP_R_MISSING_SENDER_IDENTIFICATION:111:missing sender identification
 CMP_R_NO_STDIO:194:no stdio
 CMP_R_NULL_ARGUMENT:103:null argument
 CMS_R_ADD_SIGNER_ERROR:99:add signer error
diff --git a/doc/internal/man3/ossl_cmp_hdr_init.pod b/doc/internal/man3/ossl_cmp_hdr_init.pod
new file mode 100644
index 0000000000..a7a4d87f09
--- /dev/null
+++ b/doc/internal/man3/ossl_cmp_hdr_init.pod
@@ -0,0 +1,127 @@
+=pod
+
+=head1 NAME
+
+ossl_cmp_hdr_set_pvno,
+ossl_cmp_hdr_get_pvno,
+ossl_cmp_hdr_get0_sendernonce,
+ossl_cmp_hdr_set1_sender,
+ossl_cmp_hdr_set1_recipient,
+ossl_cmp_hdr_update_messagetime,
+ossl_cmp_hdr_set1_senderKID,
+ossl_cmp_hdr_push0_freeText,
+ossl_cmp_hdr_push1_freeText,
+ossl_cmp_hdr_generalinfo_item_push0,
+ossl_cmp_hdr_generalinfo_items_push1,
+ossl_cmp_hdr_set_implicitConfirm,
+ossl_cmp_hdr_check_implicitConfirm,
+ossl_cmp_hdr_init
+- functions manipulating CMP message headers
+
+=head1 SYNOPSIS
+
+  #include "cmp_int.h"
+
+  int ossl_cmp_hdr_set_pvno(OSSL_CMP_PKIHEADER *hdr, int pvno);
+  int ossl_cmp_hdr_get_pvno(const OSSL_CMP_PKIHEADER *hdr);
+  ASN1_OCTET_STRING
+     *ossl_cmp_hdr_get0_sendernonce(const OSSL_CMP_PKIHEADER *hdr);
+
+  int ossl_cmp_hdr_set1_sender(OSSL_CMP_PKIHEADER *hdr, const X509_NAME *nm);
+  int ossl_cmp_hdr_set1_recipient(OSSL_CMP_PKIHEADER *hdr, const X509_NAME *nm);
+  int ossl_cmp_hdr_update_messagetime(OSSL_CMP_PKIHEADER *hdr);
+  int ossl_cmp_hdr_set1_senderKID(OSSL_CMP_PKIHEADER *hdr,
+                                  const ASN1_OCTET_STRING *senderKID);
+  int ossl_cmp_hdr_generalinfo_item_push0(OSSL_CMP_PKIHEADER *hdr,
+                                          OSSL_CMP_ITAV *itav);
+  int ossl_cmp_hdr_generalinfo_items_push1(OSSL_CMP_PKIHEADER *hdr,
+                                           STACK_OF(OSSL_CMP_ITAV) *itavs);
+  int ossl_cmp_hdr_push0_freeText(OSSL_CMP_PKIHEADER *hdr,
+                                  ASN1_UTF8STRING *text);
+  int ossl_cmp_hdr_push1_freeText(OSSL_CMP_PKIHEADER *hdr,
+                                  ASN1_UTF8STRING *text);
+  int ossl_cmp_hdr_set_implicitConfirm(OSSL_CMP_PKIHEADER *hdr);
+  int ossl_cmp_hdr_check_implicitConfirm(OSSL_CMP_PKIHEADER *hdr);
+  int ossl_cmp_hdr_init(OSSL_CMP_CTX *ctx, OSSL_CMP_PKIHEADER *hdr);
+
+=head1 DESCRIPTION
+
+ossl_cmp_hdr_set_pvno() sets hdr->pvno to the given B<pvno>.
+
+ossl_cmp_hdr_get_pvno() returns the pvno of the given B<hdr> or -1 on error.
+
+ossl_cmp_hdr_get0_sendernonce() returns the sender nonce of the given PKIHeader.
+
+ossl_cmp_hdr_set1_sender() sets the sender field in the given PKIHeader
+to the given X509 Name value, without consuming the pointer.
+
+ossl_cmp_hdr_set1_recipient() sets the recipient field in the given
+PKIHeader to the given X509 Name value, without consuming the pointer.
+If B<nm> is NULL, recipient is set to the NULL DN (the empty list of strings).
+
+ossl_cmp_hdr_update_messagetime() (re-)sets the messageTime to the current
+system time. As written in RFC 4210, section 5.1.1:
+The messageTime field contains the time at which the sender created the message.
+This may be useful to allow end entities to correct/check their local time for
+consistency with the time on a central system.
+
+ossl_cmp_hdr_set1_senderKID() Sets hdr->senderKID to the given string.
+In an PBMAC-protected IR this usually is a reference number issued by the CA,
+else the subject key ID of the sender's protecting certificate.
+
+ossl_cmp_hdr_push0_freeText() pushes an ASN1_UTF8STRING to
+hdr->freeText and consumes the given pointer.
+
+ossl_cmp_hdr_push1_freeText() pushes an ASN1_UTF8STRING to
+hdr->freeText and does not consume the pointer.
+
+ossl_cmp_hdr_generalinfo_item_push0() adds the given InfoTypeAndValue
+item to the hdr->generalInfo stack. Consumes the B<itav> pointer.
+
+ossl_cmp_hdr_generalinfo_items_push1() adds a copy of the B<itavs> stack to
+the generalInfo field of PKIheader of the B<hdr>. Does not consume the B<itavs>
+pointer.
+
+ossl_cmp_hdr_set_implicitConfirm() sets implicitConfirm in the generalInfo field
+of the PKIMessage header.
+
+ossl_cmp_hdr_check_implicitConfirm() returns 1 if implicitConfirm is
+set int generalInfo field of the given PKIMessage header, 0 if not.
+
+ossl_cmp_hdr_init() initializes a PKIHeader structure based on the
+values in the given OSSL_CMP_CTX structure.
+This starts a new transaction in case ctx->transactionID is NULL.
+The sender name is copied from the subject of the client cert, if any,
+or else from the subject name provided for certification requests.
+As required by RFC 4210 section 5.1.1., if the sender name is not known
+to the client it set to the NULL-DN. In this case for identification at least
+the senderKID must be set, which we take from any referenceValue provided.
+
+=head1 NOTES
+
+CMP is defined in RFC 4210 (and CRMF in RFC 4211).
+
+=head1 RETURN VALUES
+
+ossl_cmp_hdr_get_pvno() returns the pvno of the given B<hdr> or -1 on error.
+
+ossl_cmp_hdr_get0_sendernonce() returns the respective nonce.
+
+All other functions return 1 on success, 0 on error.
+
+See the individual functions above.
+
+=head1 HISTORY
+
+The OpenSSL CMP support was added in OpenSSL 3.0.
+
+=head1 COPYRIGHT
+
+Copyright 2007-2019 The OpenSSL Project Authors. All Rights Reserved.
+
+Licensed under the Apache License 2.0 (the "License").  You may not use
+this file except in compliance with the License.  You can obtain a copy
+in the file LICENSE in the source distribution or at
+L<https://www.openssl.org/source/license.html>.
+
+=cut
diff --git a/doc/internal/man3/ossl_cmp_statusinfo_new.pod b/doc/internal/man3/ossl_cmp_statusinfo_new.pod
new file mode 100644
index 0000000000..6a72056455
--- /dev/null
+++ b/doc/internal/man3/ossl_cmp_statusinfo_new.pod
@@ -0,0 +1,107 @@
+=pod
+
+=head1 NAME
+
+ossl_cmp_statusinfo_new,
+ossl_cmp_pkisi_pkistatus_get,
+ossl_cmp_pkisi_pkifailureinfo_get,
+ossl_cmp_pkisi_pkifailureinfo_check,
+ossl_cmp_pkisi_failinfo_get0,
+ossl_cmp_pkisi_statusstring_get0,
+ossl_pkisi_snprint
+- functions for managing PKI status information
+
+=head1 SYNOPSIS
+
+  #include "cmp.h"
+
+# define OSSL_CMP_PKIFAILUREINFO_badAlg               0
+# define OSSL_CMP_PKIFAILUREINFO_badMessageCheck      1
+# define OSSL_CMP_PKIFAILUREINFO_badRequest           2
+# define OSSL_CMP_PKIFAILUREINFO_badTime              3
+# define OSSL_CMP_PKIFAILUREINFO_badCertId            4
+# define OSSL_CMP_PKIFAILUREINFO_badDataFormat        5
+# define OSSL_CMP_PKIFAILUREINFO_wrongAuthority       6
+# define OSSL_CMP_PKIFAILUREINFO_incorrectData        7
+# define OSSL_CMP_PKIFAILUREINFO_missingTimeStamp     8
+# define OSSL_CMP_PKIFAILUREINFO_badPOP               9
+# define OSSL_CMP_PKIFAILUREINFO_certRevoked         10
+# define OSSL_CMP_PKIFAILUREINFO_certConfirmed       11
+# define OSSL_CMP_PKIFAILUREINFO_wrongIntegrity      12
+# define OSSL_CMP_PKIFAILUREINFO_badRecipientNonce   13
+# define OSSL_CMP_PKIFAILUREINFO_timeNotAvailable    14
+# define OSSL_CMP_PKIFAILUREINFO_unacceptedPolicy    15
+# define OSSL_CMP_PKIFAILUREINFO_unacceptedExtension 16
+# define OSSL_CMP_PKIFAILUREINFO_addInfoNotAvailable 17
+# define OSSL_CMP_PKIFAILUREINFO_badSenderNonce      18
+# define OSSL_CMP_PKIFAILUREINFO_badCertTemplate     19
+# define OSSL_CMP_PKIFAILUREINFO_signerNotTrusted    20
+# define OSSL_CMP_PKIFAILUREINFO_transactionIdInUse  21
+# define OSSL_CMP_PKIFAILUREINFO_unsupportedVersion  22
+# define OSSL_CMP_PKIFAILUREINFO_notAuthorized       23
+# define OSSL_CMP_PKIFAILUREINFO_systemUnavail       24
+# define OSSL_CMP_PKIFAILUREINFO_systemFailure       25
+# define OSSL_CMP_PKIFAILUREINFO_duplicateCertReq    26
+# define OSSL_CMP_PKIFAILUREINFO_MAX                 26
+
+  OSSL_CMP_PKISI *ossl_cmp_statusinfo_new(int status, int fail_info,
+                                          const char *text);
+  int ossl_cmp_pkisi_pkistatus_get(OSSL_CMP_PKISI *si);
+  int ossl_cmp_pkisi_pkifailureinfo_get(OSSL_CMP_PKISI *si);
+  int ossl_cmp_pkisi_pkifailureinfo_check(OSSL_CMP_PKISI *si, int bit_index);
+  OSSL_CMP_PKIFAILUREINFO *ossl_cmp_pkisi_failinfo_get0(const OSSL_CMP_PKISI *si);
+  OSSL_CMP_PKIFREETEXT *ossl_cmp_pkisi_statusstring_get0(const OSSL_CMP_PKISI *si);
+  char *ossl_pkisi_snprint(OSSL_CMP_PKISI *si, char *buf, int bufsize);
+
+=head1 DESCRIPTION
+
+ossl_cmp_statusinfo_new() creates a new PKIStatusInfo structure and fills it
+with the given values. It sets the status field to B<status>.
+If B<text> is not NULL, it is copied to statusString.
+B<fail_info> is is interpreted as bit pattern for the failInfo field.
+Returns a pointer to the structure on success, or NULL on error.
+
+ossl_cmp_pkisi_pkistatus_get() returns the PKIStatus of B<si>, or -1 on error.
+
+ossl_cmp_pkisi_pkifailureinfo_get() returns the PKIFailureInfo bits
+of B<si>, encoded as integer, or -1 on error.
+
+ossl_cmp_pkisi_pkifailureinfo_check() returns the state of the bit (0 or 1)
+with index B<bit_index> in the PKIFailureInfo of the B<si>, or -1 on error.
+
+ossl_cmp_pkisi_failinfo_get0() returns a direct pointer to the failInfo
+field contained in B<si>, or NULL on error.
+
+ossl_cmp_pkisi_statusstring_get0() returns a direct pointer to the statusString
+field contained in B<si>.
+
+ossl_pkisi_snprint() places at max B<bufsize> characters of human-readable
+error string of B<si> in pre-allocated B<buf>. Returns pointer to the same
+B<buf> containing the string, or NULL on error.
+
+=head1 NOTES
+
+CMP is defined in RFC 4210 (and CRMF in RFC 4211).
+
+=head1 RETURN VALUES
+
+See the individual functions above.
+
+=head1 SEE ALSO
+
+L<OSSL_CMP_CTX_new(3)>, L<ossl_cmp_certreq_new(3)>
+
+=head1 HISTORY
+
+The OpenSSL CMP support was added in OpenSSL 3.0.
+
+=head1 COPYRIGHT
+
+Copyright 2007-2019 The OpenSSL Project Authors. All Rights Reserved.
+
+Licensed under the Apache License 2.0 (the "License").  You may not use
+this file except in compliance with the License.  You can obtain a copy
+in the file LICENSE in the source distribution or at
+L<https://www.openssl.org/source/license.html>.
+
+=cut
diff --git a/doc/man3/OSSL_CMP_CTX_snprint_PKIStatus.pod b/doc/man3/OSSL_CMP_CTX_snprint_PKIStatus.pod
new file mode 100644
index 0000000000..3ae6831ee2
--- /dev/null
+++ b/doc/man3/OSSL_CMP_CTX_snprint_PKIStatus.pod
@@ -0,0 +1,46 @@
+=pod
+
+=head1 NAME
+
+OSSL_CMP_CTX_snprint_PKIStatus
+- function(s) for managing the CMP PKIStatus
+
+=head1 SYNOPSIS
+
+ #include <openssl/cmp.h>
+
+ char *OSSL_CMP_CTX_snprint_PKIStatus(OSSL_CMP_CTX *ctx, char *buf, int bufsize);
+
+=head1 DESCRIPTION
+
+This is the PKIStatus API for using CMP (Certificate Management Protocol) with
+OpenSSL.
+
+OSSL_CMP_CTX_snprint_PKIStatus() takes the PKIStatusInfo components contained
+in the given CMP context and places a human-readable string created from them
+in the given buffer, with the given maximal length.
+On success it returns a copy of the buffer pointer containing the string.
+
+=head1 NOTES
+
+CMP is defined in RFC 4210 (and CRMF in RFC 4211).
+
+=head1 RETURN VALUES
+
+OSSL_CMP_CTX_snprint_PKIStatus()
+returns the intended pointer value as described above or NULL on error.
+
+=head1 HISTORY
+
+The OpenSSL CMP support was added in OpenSSL 3.0.
+
+=head1 COPYRIGHT
+
+Copyright 2007-2019 The OpenSSL Project Authors. All Rights Reserved.
+
+Licensed under the Apache License 2.0 (the "License").  You may not use
+this file except in compliance with the License.  You can obtain a copy
+in the file LICENSE in the source distribution or at
+L<https://www.openssl.org/source/license.html>.
+
+=cut
diff --git a/doc/man3/OSSL_CMP_HDR_get0_transactionID.pod b/doc/man3/OSSL_CMP_HDR_get0_transactionID.pod
new file mode 100644
index 0000000000..36bdf1917f
--- /dev/null
+++ b/doc/man3/OSSL_CMP_HDR_get0_transactionID.pod
@@ -0,0 +1,47 @@
+=pod
+
+=head1 NAME
+
+OSSL_CMP_HDR_get0_transactionID,
+OSSL_CMP_HDR_get0_recipNonce
+- functions manipulating CMP message headers
+
+=head1 SYNOPSIS
+
+  #include <openssl/cmp.h>
+
+  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);
+
+=head1 DESCRIPTION
+
+OSSL_CMP_HDR_get0_transactionID returns the transaction ID of the given
+PKIHeader.
+
+OSSL_CMP_HDR_get0_recipNonce returns the recipient nonce of the given PKIHeader.
+
+=head1 NOTES
+
+CMP is defined in RFC 4210.
+
+=head1 RETURN VALUES
+
+The functions return 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 fe138bd060..409d48515f 100644
--- a/include/openssl/cmp.h
+++ b/include/openssl/cmp.h
@@ -337,6 +337,15 @@ int OSSL_CMP_CTX_set1_transactionID(OSSL_CMP_CTX *ctx,
 int OSSL_CMP_CTX_set1_senderNonce(OSSL_CMP_CTX *ctx,
                                   const ASN1_OCTET_STRING *nonce);
 
+/* from cmp_status.c */
+char *OSSL_CMP_CTX_snprint_PKIStatus(OSSL_CMP_CTX *ctx, char *buf,
+                                     size_t bufsize);
+
+/* from cmp_hdr.c */
+/* support application-level CMP debugging in cmp.c: */
+ASN1_OCTET_STRING *OSSL_CMP_HDR_get0_transactionID(const OSSL_CMP_PKIHEADER *hdr);
+ASN1_OCTET_STRING *OSSL_CMP_HDR_get0_recipNonce(const OSSL_CMP_PKIHEADER *hdr);
+
 #   ifdef  __cplusplus
 }
 #   endif
diff --git a/include/openssl/cmperr.h b/include/openssl/cmperr.h
index 0c1ce259b6..02d0a36f94 100644
--- a/include/openssl/cmperr.h
+++ b/include/openssl/cmperr.h
@@ -33,8 +33,11 @@ int ERR_load_CMP_strings(void);
 /*
  * CMP reason codes.
  */
+#  define CMP_R_ERROR_PARSING_PKISTATUS                    107
+#  define CMP_R_FAILURE_OBTAINING_RANDOM                   110
 #  define CMP_R_INVALID_ARGS                               100
 #  define CMP_R_MULTIPLE_SAN_SOURCES                       102
+#  define CMP_R_MISSING_SENDER_IDENTIFICATION              111
 #  define CMP_R_NO_STDIO                                   194
 #  define CMP_R_NULL_ARGUMENT                              103
 
diff --git a/test/build.info b/test/build.info
index f50c2eaa40..7ec9bc9721 100644
--- a/test/build.info
+++ b/test/build.info
@@ -471,7 +471,7 @@ IF[{- !$disabled{tests} -}]
   DEPEND[conf_include_test]=../libcrypto libtestutil.a
 
   IF[{- !$disabled{cmp} -}]
-    PROGRAMS{noinst}=cmp_asn_test cmp_ctx_test
+    PROGRAMS{noinst}=cmp_asn_test cmp_ctx_test cmp_status_test cmp_hdr_test
   ENDIF
 
   SOURCE[cmp_asn_test]=cmp_asn_test.c cmp_testlib.c
@@ -482,6 +482,14 @@ IF[{- !$disabled{tests} -}]
   INCLUDE[cmp_ctx_test]=.. ../include ../apps/include
   DEPEND[cmp_ctx_test]=../libcrypto.a libtestutil.a
 
+  SOURCE[cmp_hdr_test]=cmp_hdr_test.c cmp_testlib.c
+  INCLUDE[cmp_hdr_test]=.. ../include ../apps/include
+  DEPEND[cmp_hdr_test]=../libcrypto.a libtestutil.a
+
+  SOURCE[cmp_status_test]=cmp_status_test.c cmp_testlib.c
+  INCLUDE[cmp_status_test]=.. ../include ../apps/include
+  DEPEND[cmp_status_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 70439bf0af..9a224f3a56 100644
--- a/test/cmp_asn_test.c
+++ b/test/cmp_asn_test.c
@@ -24,21 +24,10 @@ typedef struct test_fixture {
 static CMP_ASN_TEST_FIXTURE *set_up(const char *const test_case_name)
 {
     CMP_ASN_TEST_FIXTURE *fixture;
-    int setup_ok = 0;
 
-    /* Allocate memory owned by the fixture, exit on error */
     if (!TEST_ptr(fixture = OPENSSL_zalloc(sizeof(*fixture))))
-        goto err;
+        return NULL;
     fixture->test_case_name = test_case_name;
-    setup_ok = 1;
-
- err:
-    if (!setup_ok) {
-#ifndef OPENSSL_NO_STDIO
-        ERR_print_errors_fp(stderr);
-#endif
-        exit(EXIT_FAILURE);
-    }
     return fixture;
 }
 
@@ -121,6 +110,7 @@ void cleanup_tests(void)
 
 int setup_tests(void)
 {
+    RAND_bytes(rand_data, OSSL_CMP_TRANSACTIONID_LENGTH);
     /* ASN.1 related tests */
     ADD_TEST(test_cmp_asn1_get_int);
     ADD_TEST(test_ASN1_OCTET_STRING_set);
diff --git a/test/cmp_ctx_test.c b/test/cmp_ctx_test.c
index 3c8d75f4e0..d7a3edb140 100644
--- a/test/cmp_ctx_test.c
+++ b/test/cmp_ctx_test.c
@@ -29,8 +29,9 @@ static OSSL_CMP_CTX_TEST_FIXTURE *set_up(const char *const test_case_name)
 {
     OSSL_CMP_CTX_TEST_FIXTURE *fixture;
 
-    if (!TEST_ptr(fixture = OPENSSL_zalloc(sizeof(*fixture)))
-            || !TEST_ptr(fixture->ctx = OSSL_CMP_CTX_new())) {
+    if (!TEST_ptr(fixture = OPENSSL_zalloc(sizeof(*fixture))))
+        return NULL;
+    if (!TEST_ptr(fixture->ctx = OSSL_CMP_CTX_new())) {
         tear_down(fixture);
         return NULL;
     }
diff --git a/test/cmp_hdr_test.c b/test/cmp_hdr_test.c
new file mode 100644
index 0000000000..4f1b4a5a79
--- /dev/null
+++ b/test/cmp_hdr_test.c
@@ -0,0 +1,468 @@
+/*
+ * 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 unsigned char rand_data[OSSL_CMP_TRANSACTIONID_LENGTH];
+
+typedef struct test_fixture {
+    const char *test_case_name;
+    int expected;
+    OSSL_CMP_CTX *cmp_ctx;
+    OSSL_CMP_PKIHEADER *hdr;
+
+} CMP_HDR_TEST_FIXTURE;
+
+static void tear_down(CMP_HDR_TEST_FIXTURE *fixture)
+{
+    OSSL_CMP_PKIHEADER_free(fixture->hdr);
+    OSSL_CMP_CTX_free(fixture->cmp_ctx);
+    OPENSSL_free(fixture);
+}
+
+static CMP_HDR_TEST_FIXTURE *set_up(const char *const test_case_name)
+{
+    CMP_HDR_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()))
+        goto err;
+    if (!TEST_ptr(fixture->hdr = OSSL_CMP_PKIHEADER_new()))
+        goto err;
+    return fixture;
+
+ err:
+    tear_down(fixture);
+    return NULL;
+}
+
+static int execute_HDR_set_get_pvno_test(CMP_HDR_TEST_FIXTURE *fixture)
+{
+    int pvno = 77;
+
+    if (!TEST_int_eq(ossl_cmp_hdr_set_pvno(fixture->hdr, pvno), 1))
+        return 0;
+    if (!TEST_int_eq(ossl_cmp_hdr_get_pvno(fixture->hdr), pvno))
+        return 0;
+    return 1;
+}
+
+static int test_HDR_set_get_pvno(void)
+{
+    SETUP_TEST_FIXTURE(CMP_HDR_TEST_FIXTURE, set_up);
+    fixture->expected = 1;
+    EXECUTE_TEST(execute_HDR_set_get_pvno_test, tear_down);
+    return result;
+}
+
+#define X509_NAME_ADD(n, rd, s) X509_NAME_add_entry_by_txt((n), (rd),          \
+                                MBSTRING_ASC, (unsigned char *)(s), -1, -1, 0)
+
+static int execute_HDR_get0_senderNonce_test(CMP_HDR_TEST_FIXTURE *fixture)
+{
+    X509_NAME *sender = X509_NAME_new();
+    ASN1_OCTET_STRING *sn;
+
+    if (!TEST_ptr(sender))
+        return 0;
+
+    X509_NAME_ADD(sender, "CN", "A common sender name");
+    if (!TEST_int_eq(OSSL_CMP_CTX_set1_subjectName(fixture->cmp_ctx, sender),
+                     1))
+        return 0;
+    if (!TEST_int_eq(ossl_cmp_hdr_init(fixture->cmp_ctx, fixture->hdr),
+                     1))
+        return 0;
+    sn = ossl_cmp_hdr_get0_senderNonce(fixture->hdr);
+    if (!TEST_int_eq(ASN1_OCTET_STRING_cmp(fixture->cmp_ctx->senderNonce, sn),
+                     0))
+        return 0;
+    X509_NAME_free(sender);
+    return 1;
+}
+
+static int test_HDR_get0_senderNonce(void)
+{
+    SETUP_TEST_FIXTURE(CMP_HDR_TEST_FIXTURE, set_up);
+    fixture->expected = 1;
+    EXECUTE_TEST(execute_HDR_get0_senderNonce_test, tear_down);
+    return result;
+}
+
+static int execute_HDR_set1_sender_test(CMP_HDR_TEST_FIXTURE *fixture)
+{
+    X509_NAME *x509name = X509_NAME_new();
+
+    if (!TEST_ptr(x509name))
+        return 0;
+
+    X509_NAME_ADD(x509name, "CN", "A common sender name");
+    if (!TEST_int_eq(ossl_cmp_hdr_set1_sender(fixture->hdr, x509name), 1))
+        return 0;
+    if (!TEST_int_eq(fixture->hdr->sender->type, GEN_DIRNAME))
+        return 0;
+
+    if (!TEST_int_eq(
+            X509_NAME_cmp(fixture->hdr->sender->d.directoryName, x509name), 0))
+        return 0;
+
+    X509_NAME_free(x509name);
+    return 1;
+}
+
+static int test_HDR_set1_sender(void)
+{
+    SETUP_TEST_FIXTURE(CMP_HDR_TEST_FIXTURE, set_up);
+    fixture->expected = 1;
+    EXECUTE_TEST(execute_HDR_set1_sender_test, tear_down);
+    return result;
+}
+
+static int execute_HDR_set1_recipient_test(CMP_HDR_TEST_FIXTURE *fixture)
+{
+    X509_NAME *x509name = X509_NAME_new();
+
+    if (!TEST_ptr(x509name))
+        return 0;
+
+    X509_NAME_ADD(x509name, "CN", "A common recipient name");
+    if (!TEST_int_eq(ossl_cmp_hdr_set1_recipient(fixture->hdr, x509name), 1))
+        return 0;
+
+    if (!TEST_int_eq(fixture->hdr->recipient->type, GEN_DIRNAME))
+        return 0;
+
+    if (!TEST_int_eq(
+            X509_NAME_cmp(fixture->hdr->recipient->d.directoryName, x509name),0))
+        return 0;
+
+    X509_NAME_free(x509name);
+    return 1;
+}
+
+static int test_HDR_set1_recipient(void)
+{
+    SETUP_TEST_FIXTURE(CMP_HDR_TEST_FIXTURE, set_up);
+    fixture->expected = 1;
+    EXECUTE_TEST(execute_HDR_set1_recipient_test, tear_down);
+    return result;
+}
+
+static int execute_HDR_update_messageTime_test(CMP_HDR_TEST_FIXTURE *fixture)
+{
+    struct tm hdrtm;
+    time_t hdrtime, before, after, now;
+
+    now = time(NULL);
+    before = mktime(gmtime(&now));
+    if (!TEST_true(ossl_cmp_hdr_update_messageTime(fixture->hdr)))
+        return 0;
+    if (!TEST_true(ASN1_TIME_to_tm(fixture->hdr->messageTime, &hdrtm)))
+        return 0;
+
+    hdrtime = mktime(&hdrtm);
+    if (!TEST_true(before <= hdrtime))
+        return 0;
+    now = time(NULL);
+    after = mktime(gmtime(&now));
+    return TEST_true(hdrtime <= after);
+}
+
+static int test_HDR_update_messageTime(void)
+{
+    SETUP_TEST_FIXTURE(CMP_HDR_TEST_FIXTURE, set_up);
+    fixture->expected = 1;
+    EXECUTE_TEST(execute_HDR_update_messageTime_test, tear_down);
+    return result;
+}
+
+static int execute_HDR_set1_senderKID_test(CMP_HDR_TEST_FIXTURE *fixture)
+{
+    ASN1_OCTET_STRING* senderKID = ASN1_OCTET_STRING_new();
+
+    if (!TEST_ptr(senderKID))
+        return 0;
+
+    ASN1_OCTET_STRING_set(senderKID, rand_data, sizeof(rand_data));
+    if (!TEST_int_eq(ossl_cmp_hdr_set1_senderKID(fixture->hdr, senderKID), 1))
+        return 0;
+    if (!TEST_int_eq(
+            ASN1_OCTET_STRING_cmp(fixture->hdr->senderKID, senderKID), 0))
+        return 0;
+
+    ASN1_OCTET_STRING_free(senderKID);
+    return 1;
+}
+
+static int test_HDR_set1_senderKID(void)
+{
+    SETUP_TEST_FIXTURE(CMP_HDR_TEST_FIXTURE, set_up);
+    fixture->expected = 1;
+    EXECUTE_TEST(execute_HDR_set1_senderKID_test, tear_down);
+    return result;
+}
+
+static int execute_HDR_push0_freeText_test(CMP_HDR_TEST_FIXTURE *fixture)
+{
+    ASN1_UTF8STRING* text = ASN1_UTF8STRING_new();
+
+    if (!TEST_ptr(text))
+        return 0;
+
+    if (!ASN1_STRING_set(text, "A free text", -1))
+        return 0;
+
+    if (!TEST_int_eq(
+            ossl_cmp_hdr_push0_freeText(fixture->hdr, text), 1))
+        return 0;
+    if (!TEST_true(text == sk_ASN1_UTF8STRING_value(
+            fixture->hdr->freeText, 0)))
+        return 0;
+
+    return 1;
+}
+
+static int test_HDR_push0_freeText(void)
+{
+    SETUP_TEST_FIXTURE(CMP_HDR_TEST_FIXTURE, set_up);
+    fixture->expected = 1;
+    EXECUTE_TEST(execute_HDR_push0_freeText_test, tear_down);
+    return result;
+}
+
+static int execute_HDR_push1_freeText_test(CMP_HDR_TEST_FIXTURE *fixture)
+{
+    ASN1_UTF8STRING* text = ASN1_UTF8STRING_new();
+
+    if (!TEST_ptr(text))
+        return 0;
+
+    if (!ASN1_STRING_set(text, "A free text", -1))
+        return 0;
+
+    if (!TEST_int_eq(
+            ossl_cmp_hdr_push1_freeText(fixture->hdr, text), 1))
+        return 0;
+    if (!TEST_int_eq(ASN1_STRING_cmp(
+            sk_ASN1_UTF8STRING_value(fixture->hdr->freeText, 0), text), 0))
+        return 0;
+
+    ASN1_UTF8STRING_free(text);
+    return 1;
+}
+
+static int test_HDR_push1_freeText(void)
+{
+    SETUP_TEST_FIXTURE(CMP_HDR_TEST_FIXTURE, set_up);
+    fixture->expected = 1;
+    EXECUTE_TEST(execute_HDR_push1_freeText_test, tear_down);
+    return result;
+}
+
+static int
+execute_HDR_generalInfo_push0_item_test(CMP_HDR_TEST_FIXTURE *fixture)
+{
+    OSSL_CMP_ITAV *itav = OSSL_CMP_ITAV_new();
+
+    if (!TEST_ptr(itav))
+        return 0;
+
+    if (!TEST_int_eq(
+            ossl_cmp_hdr_generalInfo_push0_item(fixture->hdr, itav), 1))
+        return 0;
+    if (!TEST_true(itav == sk_OSSL_CMP_ITAV_value(
+            fixture->hdr->generalInfo, 0)))
+        return 0;
+
+    return 1;
+}
+
+static int test_HDR_generalInfo_push0_item(void)
+{
+    SETUP_TEST_FIXTURE(CMP_HDR_TEST_FIXTURE, set_up);
+    fixture->expected = 1;
+    EXECUTE_TEST(execute_HDR_generalInfo_push0_item_test, tear_down);
+    return result;
+}
+
+static int
+execute_HDR_generalInfo_push1_items_test(CMP_HDR_TEST_FIXTURE *fixture)
+{
+    const char oid[] = "1.2.3.4";
+    char buf[20];
+    OSSL_CMP_ITAV *itav;
+    STACK_OF(OSSL_CMP_ITAV) *itavs = NULL;
+    ASN1_INTEGER *asn1int = ASN1_INTEGER_new();
+    ASN1_TYPE *val = ASN1_TYPE_new();
+
+    if (!TEST_ptr(asn1int))
+        return 0;
+
+    if (!TEST_ptr(val))
+        return 0;
+
+    ASN1_INTEGER_set(asn1int, 88);
+    ASN1_TYPE_set(val, V_ASN1_INTEGER, asn1int);
+    itav = OSSL_CMP_ITAV_create(OBJ_txt2obj(oid, 1), val);
+    OSSL_CMP_ITAV_push0_stack_item(&itavs, itav);
+
+    if (!TEST_int_eq(
+        ossl_cmp_hdr_generalInfo_push1_items(fixture->hdr, itavs), 1))
+        return 0;
+    OBJ_obj2txt(buf, sizeof(buf), OSSL_CMP_ITAV_get0_type(
+            sk_OSSL_CMP_ITAV_value(fixture->hdr->generalInfo, 0)), 0);
+    if (!TEST_int_eq(memcmp(oid, buf, sizeof(oid)), 0))
+        return 0;
+
+    if (!TEST_int_eq(ASN1_TYPE_cmp(itav->infoValue.other,
+                                   OSSL_CMP_ITAV_get0_value(
+            sk_OSSL_CMP_ITAV_value(fixture->hdr->generalInfo, 0))), 0))
+        return 0;
+
+    sk_OSSL_CMP_ITAV_pop_free(itavs, OSSL_CMP_ITAV_free);
+    return 1;
+}
+
+static int test_HDR_generalInfo_push1_items(void)
+{
+    SETUP_TEST_FIXTURE(CMP_HDR_TEST_FIXTURE, set_up);
+    fixture->expected = 1;
+    EXECUTE_TEST(execute_HDR_generalInfo_push1_items_test, tear_down);
+    return result;
+}
+
+static int
+execute_HDR_set_and_check_implicitConfirm_test(CMP_HDR_TEST_FIXTURE
+                                               * fixture)
+{
+    return TEST_false(ossl_cmp_hdr_check_implicitConfirm(fixture->hdr))
+        && TEST_true(ossl_cmp_hdr_set_implicitConfirm(fixture->hdr))
+        && TEST_true(ossl_cmp_hdr_check_implicitConfirm(fixture->hdr));
+}
+
+static int test_HDR_set_and_check_implicit_confirm(void)
+{
+    SETUP_TEST_FIXTURE(CMP_HDR_TEST_FIXTURE, set_up);
+    EXECUTE_TEST(execute_HDR_set_and_check_implicitConfirm_test, tear_down);
+    return result;
+}
+
+
+static int execute_HDR_init_test(CMP_HDR_TEST_FIXTURE *fixture)
+{
+    ASN1_OCTET_STRING *header_nonce = NULL;
+    ASN1_OCTET_STRING *ctx_nonce = NULL;
+    int res = 0;
+
+    if (!TEST_int_eq(fixture->expected,
+                     ossl_cmp_hdr_init(fixture->cmp_ctx, fixture->hdr)))
+        goto err;
+    if (fixture->expected != 0) {
+        if (!TEST_int_eq(ossl_cmp_hdr_get_pvno(fixture->hdr), OSSL_CMP_PVNO)
+                || !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(
+                            OSSL_CMP_HDR_get0_transactionID(fixture->hdr),
+                            fixture->cmp_ctx->transactionID)))
+            goto err;
+        header_nonce = OSSL_CMP_HDR_get0_recipNonce(fixture->hdr);
+        ctx_nonce = fixture->cmp_ctx->recipNonce;
+        if (ctx_nonce != NULL
+                && (!TEST_ptr(header_nonce)
+                || !TEST_int_eq(0, ASN1_OCTET_STRING_cmp(header_nonce,
+                                                         ctx_nonce))))
+            goto err;
+    }
+
+    res = 1;
+
+ err:
+    return res;
+}
+
+static int test_HDR_init(void)
+{
+    SETUP_TEST_FIXTURE(CMP_HDR_TEST_FIXTURE, set_up);
+    unsigned char ref[CMP_TEST_REFVALUE_LENGTH];
+
+    fixture->expected = 1;
+    if (!TEST_int_eq(1, RAND_bytes(ref, sizeof(ref)))
+            || !TEST_true(OSSL_CMP_CTX_set1_referenceValue(fixture->cmp_ctx,
+                                                           ref, sizeof(ref)))) {
+        tear_down(fixture);
+        fixture = NULL;
+    }
+    EXECUTE_TEST(execute_HDR_init_test, tear_down);
+    return result;
+}
+
+static int test_HDR_init_with_subject(void)
+{
+    SETUP_TEST_FIXTURE(CMP_HDR_TEST_FIXTURE, set_up);
+    X509_NAME *subject = NULL;
+
+    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))) {
+        tear_down(fixture);
+        fixture = NULL;
+    }
+    X509_NAME_free(subject);
+    EXECUTE_TEST(execute_HDR_init_test, tear_down);
+    return result;
+}
+
+static int test_HDR_init_no_ref_no_subject(void)
+{
+    SETUP_TEST_FIXTURE(CMP_HDR_TEST_FIXTURE, set_up);
+    fixture->expected = 0;
+    EXECUTE_TEST(execute_HDR_init_test, tear_down);
+    return result;
+}
+
+
+void cleanup_tests(void)
+{
+    return;
+}
+
+int setup_tests(void)
+{
+    RAND_bytes(rand_data, OSSL_CMP_TRANSACTIONID_LENGTH);
+    /* Message header tests */
+    ADD_TEST(test_HDR_set_get_pvno);
+    ADD_TEST(test_HDR_get0_senderNonce);
+    ADD_TEST(test_HDR_set1_sender);
+    ADD_TEST(test_HDR_set1_recipient);
+    ADD_TEST(test_HDR_update_messageTime);
+    ADD_TEST(test_HDR_set1_senderKID);
+    ADD_TEST(test_HDR_push0_freeText);
+    /* indirectly tests ossl_cmp_pkifreetext_push_str(): */
+    ADD_TEST(test_HDR_push1_freeText);
+    ADD_TEST(test_HDR_generalInfo_push0_item);
+    ADD_TEST(test_HDR_generalInfo_push1_items);
+    ADD_TEST(test_HDR_set_and_check_implicit_confirm);
+    /* also tests public function OSSL_CMP_HDR_get0_transactionID(): */
+    /* also tests public function OSSL_CMP_HDR_get0_recipNonce(): */
+    /* also tests internal function ossl_cmp_hdr_get_pvno(): */
+    ADD_TEST(test_HDR_init);
+    ADD_TEST(test_HDR_init_with_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. */
+
+    return 1;
+}
diff --git a/test/cmp_status_test.c b/test/cmp_status_test.c
new file mode 100644
index 0000000000..7311c2e444
--- /dev/null
+++ b/test/cmp_status_test.c
@@ -0,0 +1,111 @@
+/*
+ * 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"
+
+typedef struct test_fixture {
+    const char *test_case_name;
+    int pkistatus;
+    const char *str;  /* Not freed by tear_down */
+    const char *text; /* Not freed by tear_down */
+    int pkifailure;
+} CMP_STATUS_TEST_FIXTURE;
+
+static CMP_STATUS_TEST_FIXTURE *set_up(const char *const test_case_name)
+{
+    CMP_STATUS_TEST_FIXTURE *fixture;
+
+    if (!TEST_ptr(fixture = OPENSSL_zalloc(sizeof(*fixture))))
+        return NULL;
+    fixture->test_case_name = test_case_name;
+    return fixture;
+}
+
+static void tear_down(CMP_STATUS_TEST_FIXTURE *fixture)
+{
+    OPENSSL_free(fixture);
+}
+
+
+/*
+ * Tests PKIStatusInfo creation and get-functions
+ */
+static int execute_PKISI_test(CMP_STATUS_TEST_FIXTURE *fixture)
+{
+    OSSL_CMP_PKISI *si = NULL;
+    int status;
+    ASN1_UTF8STRING *statusString = NULL;
+    int res = 0, i;
+
+    if (!TEST_ptr(si = ossl_cmp_statusinfo_new(fixture->pkistatus,
+                                               fixture->pkifailure,
+                                               fixture->text)))
+        goto end;
+
+    status = ossl_cmp_pkisi_get_pkistatus(si);
+    if (!TEST_int_eq(fixture->pkistatus, status)
+            || !TEST_str_eq(fixture->str, ossl_cmp_PKIStatus_to_string(status)))
+        goto end;
+
+    if (!TEST_ptr(statusString =
+                  sk_ASN1_UTF8STRING_value(ossl_cmp_pkisi_get0_statusstring(si),
+                                           0))
+            || !TEST_str_eq(fixture->text, (char *)statusString->data))
+        goto end;
+
+    if (!TEST_int_eq(fixture->pkifailure,
+                     ossl_cmp_pkisi_get_pkifailureinfo(si)))
+        goto end;
+    for (i = 0; i <= OSSL_CMP_PKIFAILUREINFO_MAX; i++)
+        if (!TEST_int_eq((fixture->pkifailure >> i) & 1,
+                         ossl_cmp_pkisi_pkifailureinfo_check(si, i)))
+            goto end;
+
+    res = 1;
+
+ end:
+    OSSL_CMP_PKISI_free(si);
+    return res;
+}
+
+static int test_PKISI(void)
+{
+    SETUP_TEST_FIXTURE(CMP_STATUS_TEST_FIXTURE, set_up);
+    fixture->pkistatus = OSSL_CMP_PKISTATUS_revocationNotification;
+    fixture->str = "PKIStatus: revocation notification - a revocation of the cert has occurred";
+    fixture->text = "this is an additional text describing the failure";
+    fixture->pkifailure = OSSL_CMP_CTX_FAILINFO_unsupportedVersion |
+        OSSL_CMP_CTX_FAILINFO_badDataFormat;
+    EXECUTE_TEST(execute_PKISI_test, tear_down);
+    return result;
+}
+
+
+
+void cleanup_tests(void)
+{
+    return;
+}
+
+int setup_tests(void)
+{
+    /*-
+     * this tests all of:
+     * ossl_cmp_statusinfo_new()
+     * ossl_cmp_pkisi_get_pkistatus()
+     * ossl_cmp_PKIStatus_to_string()
+     * ossl_cmp_pkisi_get0_statusstring()
+     * ossl_cmp_pkisi_get_pkifailureinfo()
+     * ossl_cmp_pkisi_pkifailureinfo_check()
+     */
+    ADD_TEST(test_PKISI);
+    return 1;
+}
diff --git a/test/recipes/65-test_cmp_hdr.t b/test/recipes/65-test_cmp_hdr.t
new file mode 100644
index 0000000000..e013a6d820
--- /dev/null
+++ b/test/recipes/65-test_cmp_hdr.t
@@ -0,0 +1,22 @@
+#! /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_lib");
+
+plan skip_all => "This test is not supported in a no-cmp build"
+    if disabled("cmp");
+
+plan tests => 1;
+
+ok(run(test(["cmp_hdr_test"])));
diff --git a/test/recipes/65-test_cmp_status.t b/test/recipes/65-test_cmp_status.t
new file mode 100644
index 0000000000..6a0a0c06b6
--- /dev/null
+++ b/test/recipes/65-test_cmp_status.t
@@ -0,0 +1,22 @@
+#! /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_lib");
+
+plan skip_all => "This test is not supported in a no-cmp build"
+    if disabled("cmp");
+
+plan tests => 1;
+
+ok(run(test(["cmp_status_test"])));
diff --git a/util/libcrypto.num b/util/libcrypto.num
index 644b27cdee..41ab92ac04 100644
--- a/util/libcrypto.num
+++ b/util/libcrypto.num
@@ -4850,3 +4850,6 @@ EVP_KEYMGMT_number                      4966	3_0_0	EXIST::FUNCTION:
 EVP_KEYEXCH_number                      4967	3_0_0	EXIST::FUNCTION:
 EVP_KDF_number                          4968	3_0_0	EXIST::FUNCTION:
 EVP_SIGNATURE_number                    4969	3_0_0	EXIST::FUNCTION:
+OSSL_CMP_CTX_snprint_PKIStatus          4970	3_0_0	EXIST::FUNCTION:CMP
+OSSL_CMP_HDR_get0_transactionID         4971	3_0_0	EXIST::FUNCTION:CMP
+OSSL_CMP_HDR_get0_recipNonce            4972	3_0_0	EXIST::FUNCTION:CMP


More information about the openssl-commits mailing list