diff options
author | Dr. David von Oheimb <David.von.Oheimb@siemens.com> | 2021-12-03 18:17:50 +0100 |
---|---|---|
committer | Dr. David von Oheimb <dev@ddvo.net> | 2023-06-01 09:39:12 +0200 |
commit | d477484d33b7b3572150e21562cf4209c8dd9ef5 (patch) | |
tree | 7f543025da8b4daa1815fcc33cb591b2e6442f93 /crypto/cmp | |
parent | 985429f4f4423de71cae270330586da990e6797f (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.info | 2 | ||||
-rw-r--r-- | crypto/cmp/cmp_asn.c | 34 | ||||
-rw-r--r-- | crypto/cmp/cmp_err.c | 3 | ||||
-rw-r--r-- | crypto/cmp/cmp_genm.c | 179 | ||||
-rw-r--r-- | crypto/cmp/cmp_local.h | 2 | ||||
-rw-r--r-- | crypto/cmp/cmp_msg.c | 2 |
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, |