summaryrefslogtreecommitdiffstats
path: root/crypto
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 /crypto
parent0a4d6c67480a4d2fce514e08d3efe571f2ee99c9 (diff)
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)
Diffstat (limited to 'crypto')
-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
8 files changed, 726 insertions, 8 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