summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDr. David von Oheimb <David.von.Oheimb@siemens.com>2019-09-27 10:22:23 +0200
committerMatt Caswell <matt@openssl.org>2019-10-29 14:17:39 +0000
commit4dde554c6ae2375ce53b24cc535124355c339462 (patch)
treea60fc6631418823956f1553307f524f1017cbd16
parent0a4d6c67480a4d2fce514e08d3efe571f2ee99c9 (diff)
downloadopenssl-new-4dde554c6ae2375ce53b24cc535124355c339462.tar.gz
chunk 5 of CMP contribution to OpenSSL
Reviewed-by: Bernd Edlinger <bernd.edlinger@hotmail.de> Reviewed-by: Matt Caswell <matt@openssl.org> (Merged from https://github.com/openssl/openssl/pull/10036)
-rw-r--r--crypto/cmp/build.info3
-rw-r--r--crypto/cmp/cmp_asn.c9
-rw-r--r--crypto/cmp/cmp_ctx.c2
-rw-r--r--crypto/cmp/cmp_err.c6
-rw-r--r--crypto/cmp/cmp_hdr.c377
-rw-r--r--crypto/cmp/cmp_local.h32
-rw-r--r--crypto/cmp/cmp_status.c302
-rw-r--r--crypto/err/openssl.txt3
-rw-r--r--doc/internal/man3/ossl_cmp_hdr_init.pod127
-rw-r--r--doc/internal/man3/ossl_cmp_statusinfo_new.pod107
-rw-r--r--doc/man3/OSSL_CMP_CTX_snprint_PKIStatus.pod46
-rw-r--r--doc/man3/OSSL_CMP_HDR_get0_transactionID.pod47
-rw-r--r--include/openssl/cmp.h9
-rw-r--r--include/openssl/cmperr.h3
-rw-r--r--test/build.info10
-rw-r--r--test/cmp_asn_test.c14
-rw-r--r--test/cmp_ctx_test.c5
-rw-r--r--test/cmp_hdr_test.c468
-rw-r--r--test/cmp_status_test.c111
-rw-r--r--test/recipes/65-test_cmp_hdr.t22
-rw-r--r--test/recipes/65-test_cmp_status.t22
-rw-r--r--util/libcrypto.num3
22 files changed, 1705 insertions, 23 deletions
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