summaryrefslogtreecommitdiffstats
path: root/crypto/cmp
diff options
context:
space:
mode:
authorDr. David von Oheimb <David.von.Oheimb@siemens.com>2021-12-03 18:17:50 +0100
committerDr. David von Oheimb <dev@ddvo.net>2023-06-01 09:39:12 +0200
commitd477484d33b7b3572150e21562cf4209c8dd9ef5 (patch)
tree7f543025da8b4daa1815fcc33cb591b2e6442f93 /crypto/cmp
parent985429f4f4423de71cae270330586da990e6797f (diff)
CMP: add support for genm/genp messages with id-it-caCerts
Reviewed-by: Tomas Mraz <tomas@openssl.org> Reviewed-by: Paul Dale <pauli@openssl.org> Reviewed-by: David von Oheimb <david.von.oheimb@siemens.com> (Merged from https://github.com/openssl/openssl/pull/19231)
Diffstat (limited to 'crypto/cmp')
-rw-r--r--crypto/cmp/build.info2
-rw-r--r--crypto/cmp/cmp_asn.c34
-rw-r--r--crypto/cmp/cmp_err.c3
-rw-r--r--crypto/cmp/cmp_genm.c179
-rw-r--r--crypto/cmp/cmp_local.h2
-rw-r--r--crypto/cmp/cmp_msg.c2
6 files changed, 219 insertions, 3 deletions
diff --git a/crypto/cmp/build.info b/crypto/cmp/build.info
index a2a57c14ec..ad67c434cc 100644
--- a/crypto/cmp/build.info
+++ b/crypto/cmp/build.info
@@ -1,4 +1,4 @@
LIBS=../../libcrypto
SOURCE[../../libcrypto]= cmp_asn.c cmp_ctx.c cmp_err.c cmp_util.c \
cmp_status.c cmp_hdr.c cmp_protect.c cmp_msg.c cmp_vfy.c \
- cmp_server.c cmp_client.c cmp_http.c
+ cmp_server.c cmp_client.c cmp_genm.c cmp_http.c
diff --git a/crypto/cmp/cmp_asn.c b/crypto/cmp/cmp_asn.c
index e1ecc40838..b97c8323ff 100644
--- a/crypto/cmp/cmp_asn.c
+++ b/crypto/cmp/cmp_asn.c
@@ -114,10 +114,11 @@ ASN1_ADB(OSSL_CMP_ITAV) = {
ADB_ENTRY(NID_id_it_suppLangTags,
ASN1_SEQUENCE_OF_OPT(OSSL_CMP_ITAV, infoValue.suppLangTagsValue,
ASN1_UTF8STRING)),
+ ADB_ENTRY(NID_id_it_caCerts,
+ ASN1_SEQUENCE_OF_OPT(OSSL_CMP_ITAV, infoValue.caCerts, X509)),
} ASN1_ADB_END(OSSL_CMP_ITAV, 0, infoType, 0,
&infotypeandvalue_default_tt, NULL);
-
ASN1_SEQUENCE(OSSL_CMP_ITAV) = {
ASN1_SIMPLE(OSSL_CMP_ITAV, infoType, ASN1_OBJECT),
ASN1_ADB_OBJECT(OSSL_CMP_ITAV)
@@ -183,6 +184,37 @@ int OSSL_CMP_ITAV_push0_stack_item(STACK_OF(OSSL_CMP_ITAV) **itav_sk_p,
return 0;
}
+OSSL_CMP_ITAV *OSSL_CMP_ITAV_new_caCerts(const STACK_OF(X509) *caCerts)
+{
+ OSSL_CMP_ITAV *itav = OSSL_CMP_ITAV_new();
+
+ if (itav == NULL)
+ return NULL;
+ if (sk_X509_num(caCerts) > 0
+ && (itav->infoValue.caCerts =
+ sk_X509_deep_copy(caCerts, X509_dup, X509_free)) == NULL) {
+ OSSL_CMP_ITAV_free(itav);
+ return NULL;
+ }
+ itav->infoType = OBJ_nid2obj(NID_id_it_caCerts);
+ return itav;
+}
+
+int OSSL_CMP_ITAV_get0_caCerts(const OSSL_CMP_ITAV *itav, STACK_OF(X509) **out)
+{
+ if (itav == NULL || out == NULL) {
+ ERR_raise(ERR_LIB_CMP, ERR_R_PASSED_NULL_PARAMETER);
+ return 0;
+ }
+ if (OBJ_obj2nid(itav->infoType) != NID_id_it_caCerts) {
+ ERR_raise(ERR_LIB_CMP, ERR_R_PASSED_INVALID_ARGUMENT);
+ return 0;
+ }
+ *out = sk_X509_num(itav->infoValue.caCerts) > 0
+ ? itav->infoValue.caCerts : NULL;
+ return 1;
+}
+
/* get ASN.1 encoded integer, return -1 on error */
int ossl_cmp_asn1_get_int(const ASN1_INTEGER *a)
{
diff --git a/crypto/cmp/cmp_err.c b/crypto/cmp/cmp_err.c
index dfc6dfbede..9d0e968032 100644
--- a/crypto/cmp/cmp_err.c
+++ b/crypto/cmp/cmp_err.c
@@ -84,7 +84,9 @@ static const ERR_STRING_DATA CMP_str_reasons[] = {
"failure obtaining random"},
{ERR_PACK(ERR_LIB_CMP, 0, CMP_R_FAIL_INFO_OUT_OF_RANGE),
"fail info out of range"},
+ {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_GETTING_GENP), "getting genp"},
{ERR_PACK(ERR_LIB_CMP, 0, CMP_R_INVALID_ARGS), "invalid args"},
+ {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_INVALID_GENP), "invalid genp"},
{ERR_PACK(ERR_LIB_CMP, 0, CMP_R_INVALID_OPTION), "invalid option"},
{ERR_PACK(ERR_LIB_CMP, 0, CMP_R_MISSING_CERTID), "missing certid"},
{ERR_PACK(ERR_LIB_CMP, 0, CMP_R_MISSING_KEY_INPUT_FOR_CREATING_PROTECTION),
@@ -139,6 +141,7 @@ static const ERR_STRING_DATA CMP_str_reasons[] = {
{ERR_PACK(ERR_LIB_CMP, 0, CMP_R_TRANSACTIONID_UNMATCHED),
"transactionid unmatched"},
{ERR_PACK(ERR_LIB_CMP, 0, CMP_R_TRANSFER_ERROR), "transfer error"},
+ {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_UNCLEAN_CTX), "unclean ctx"},
{ERR_PACK(ERR_LIB_CMP, 0, CMP_R_UNEXPECTED_PKIBODY), "unexpected pkibody"},
{ERR_PACK(ERR_LIB_CMP, 0, CMP_R_UNEXPECTED_PKISTATUS),
"unexpected pkistatus"},
diff --git a/crypto/cmp/cmp_genm.c b/crypto/cmp/cmp_genm.c
new file mode 100644
index 0000000000..f4be997eb2
--- /dev/null
+++ b/crypto/cmp/cmp_genm.c
@@ -0,0 +1,179 @@
+/*
+ * Copyright 2022 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright Siemens AG 2022
+ *
+ * Licensed under the Apache License 2.0 (the "License"). You may not use
+ * this file except in compliance with the License. You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include "cmp_local.h"
+#include <openssl/cmp_util.h>
+
+static const X509_VERIFY_PARAM *get0_trustedStore_vpm(const OSSL_CMP_CTX *ctx)
+{
+ const X509_STORE *ts = OSSL_CMP_CTX_get0_trustedStore(ctx);
+
+ return ts == NULL ? NULL : X509_STORE_get0_param(ts);
+}
+
+static void cert_msg(const char *func, const char *file, int lineno,
+ OSSL_CMP_severity level, OSSL_CMP_CTX *ctx,
+ const char *source, X509 *cert, const char *msg)
+{
+ char *subj = X509_NAME_oneline(X509_get_subject_name(cert), NULL, 0);
+
+ ossl_cmp_print_log(level, ctx, func, file, lineno,
+ level == OSSL_CMP_LOG_WARNING ? "WARN" : "ERR",
+ "certificate from '%s' with subject '%s' %s",
+ source, subj, msg);
+ OPENSSL_free(subj);
+}
+
+/* use |type_CA| -1 (no CA type check) or 0 (must be EE) or 1 (must be CA) */
+static int ossl_X509_check(OSSL_CMP_CTX *ctx, const char *source, X509 *cert,
+ int type_CA, const X509_VERIFY_PARAM *vpm)
+{
+ uint32_t ex_flags = X509_get_extension_flags(cert);
+ int res = X509_cmp_timeframe(vpm, X509_get0_notBefore(cert),
+ X509_get0_notAfter(cert));
+ int ret = res == 0;
+ OSSL_CMP_severity level =
+ vpm == NULL ? OSSL_CMP_LOG_WARNING : OSSL_CMP_LOG_ERR;
+
+ if (!ret)
+ cert_msg(OPENSSL_FUNC, OPENSSL_FILE, OPENSSL_LINE, level, ctx,
+ source, cert, res > 0 ? "has expired" : "not yet valid");
+ if (type_CA >= 0 && (ex_flags & EXFLAG_V1) == 0) {
+ int is_CA = (ex_flags & EXFLAG_CA) != 0;
+
+ if ((type_CA != 0) != is_CA) {
+ cert_msg(OPENSSL_FUNC, OPENSSL_FILE, OPENSSL_LINE, level, ctx,
+ source, cert,
+ is_CA ? "is not an EE cert" : "is not a CA cert");
+ ret = 0;
+ }
+ }
+ return ret;
+}
+
+static int ossl_X509_check_all(OSSL_CMP_CTX *ctx, const char *source,
+ STACK_OF(X509) *certs,
+ int type_CA, const X509_VERIFY_PARAM *vpm)
+{
+ int i;
+ int ret = 1;
+
+ for (i = 0; i < sk_X509_num(certs /* may be NULL */); i++)
+ ret = ossl_X509_check(ctx, source,
+ sk_X509_value(certs, i), type_CA, vpm)
+ && ret; /* Having 'ret' after the '&&', all certs are checked. */
+ return ret;
+}
+
+static OSSL_CMP_ITAV *get_genm_itav(OSSL_CMP_CTX *ctx,
+ OSSL_CMP_ITAV *req, /* gets consumed */
+ int expected, const char *desc)
+{
+ STACK_OF(OSSL_CMP_ITAV) *itavs = NULL;
+ int i, n;
+
+ if (ctx == NULL) {
+ ERR_raise(ERR_LIB_CMP, CMP_R_NULL_ARGUMENT);
+ goto err;
+ }
+ if (OSSL_CMP_CTX_get_status(ctx) != OSSL_CMP_PKISTATUS_unspecified) {
+ ERR_raise_data(ERR_LIB_CMP, CMP_R_UNCLEAN_CTX,
+ "client context in unsuitable state; should call CMPclient_reinit() before");
+ goto err;
+ }
+
+ if (!OSSL_CMP_CTX_push0_genm_ITAV(ctx, req))
+ goto err;
+ req = NULL;
+ itavs = OSSL_CMP_exec_GENM_ses(ctx);
+ if (itavs == NULL) {
+ if (OSSL_CMP_CTX_get_status(ctx) != OSSL_CMP_PKISTATUS_request)
+ ERR_raise_data(ERR_LIB_CMP, CMP_R_GETTING_GENP,
+ "with infoType %s", desc);
+ return NULL;
+ }
+
+ if ((n = sk_OSSL_CMP_ITAV_num(itavs)) <= 0) {
+ ERR_raise_data(ERR_LIB_CMP, CMP_R_INVALID_GENP,
+ "response on genm requesting infoType %s does not include suitable value", desc);
+ sk_OSSL_CMP_ITAV_free(itavs);
+ return NULL;
+ }
+
+ if (n > 1)
+ ossl_cmp_log2(WARN, ctx,
+ "response on genm contains %d ITAVs; will use the first ITAV with infoType id-it-%s",
+ n, desc);
+ for (i = 0; i < n; i++) {
+ OSSL_CMP_ITAV *itav = sk_OSSL_CMP_ITAV_shift(itavs);
+ ASN1_OBJECT *obj = OSSL_CMP_ITAV_get0_type(itav);
+ char name[128] = "genp contains InfoType '";
+ size_t offset = strlen(name);
+
+ if (OBJ_obj2nid(obj) == expected) {
+ for (i++; i < n; i++)
+ OSSL_CMP_ITAV_free(sk_OSSL_CMP_ITAV_shift(itavs));
+ sk_OSSL_CMP_ITAV_free(itavs);
+ return itav;
+ }
+
+ if (OBJ_obj2txt(name + offset, sizeof(name) - offset, obj, 0) < 0)
+ strcat(name, "<unknown>");
+ ossl_cmp_log2(WARN, ctx, "%s' while expecting 'id-it-%s'", name, desc);
+ OSSL_CMP_ITAV_free(itav);
+ }
+ ERR_raise_data(ERR_LIB_CMP, CMP_R_INVALID_GENP,
+ "could not find any ITAV for %s", desc);
+
+ err:
+ sk_OSSL_CMP_ITAV_free(itavs);
+ OSSL_CMP_ITAV_free(req);
+ return NULL;
+}
+
+int OSSL_CMP_get_caCerts(OSSL_CMP_CTX *ctx, STACK_OF(X509) **out)
+{
+ OSSL_CMP_ITAV *req, *itav;
+ STACK_OF(X509) *certs = NULL;
+ int ret = 0;
+
+ if (out == NULL) {
+ ERR_raise(ERR_LIB_CMP, CMP_R_NULL_ARGUMENT);
+ return 0;
+ }
+ *out = NULL;
+
+ if ((req = OSSL_CMP_ITAV_new_caCerts(NULL)) == NULL)
+ return 0;
+ if ((itav = get_genm_itav(ctx, req, NID_id_it_caCerts, "caCerts")) == NULL)
+ return 0;
+ if (!OSSL_CMP_ITAV_get0_caCerts(itav, &certs))
+ goto end;
+ ret = 1;
+ if (certs == NULL) /* no CA certificate available */
+ goto end;
+
+ if (!ossl_X509_check_all(ctx, "genp", certs, 1 /* CA */,
+ get0_trustedStore_vpm(ctx))) {
+ ret = 0;
+ goto end;
+ }
+ *out = sk_X509_new_reserve(NULL, sk_X509_num(certs));
+ if (!X509_add_certs(*out, certs,
+ X509_ADD_FLAG_UP_REF | X509_ADD_FLAG_NO_DUP)) {
+ sk_X509_pop_free(*out, X509_free);
+ *out = NULL;
+ ret = 0;
+ }
+
+ end:
+ OSSL_CMP_ITAV_free(itav);
+ return ret;
+}
diff --git a/crypto/cmp/cmp_local.h b/crypto/cmp/cmp_local.h
index 507496e149..1a27d39abf 100644
--- a/crypto/cmp/cmp_local.h
+++ b/crypto/cmp/cmp_local.h
@@ -247,6 +247,8 @@ struct ossl_cmp_itav_st {
OSSL_CMP_MSGS *origPKIMessage;
/* NID_id_it_suppLangTags - Supported Language Tags */
STACK_OF(ASN1_UTF8STRING) *suppLangTagsValue;
+ /* NID_id_it_caCerts - CA Certificates */
+ STACK_OF(X509) *caCerts;
/* this is to be used for so far undeclared objects */
ASN1_TYPE *other;
} infoValue;
diff --git a/crypto/cmp/cmp_msg.c b/crypto/cmp/cmp_msg.c
index 689a31a767..806abe599d 100644
--- a/crypto/cmp/cmp_msg.c
+++ b/crypto/cmp/cmp_msg.c
@@ -672,7 +672,7 @@ int ossl_cmp_msg_gen_push1_ITAVs(OSSL_CMP_MSG *msg,
}
/*
- * Creates a new General Message/Response with an empty itav stack
+ * Creates a new General Message/Response with a copy of the given itav stack
* returns a pointer to the PKIMessage on success, NULL on error
*/
static OSSL_CMP_MSG *gen_new(OSSL_CMP_CTX *ctx,