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 | |
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)
-rw-r--r-- | apps/cmp.c | 94 | ||||
-rw-r--r-- | apps/lib/cmp_mock_srv.c | 18 | ||||
-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 | ||||
-rw-r--r-- | crypto/err/openssl.txt | 3 | ||||
-rw-r--r-- | doc/build.info | 6 | ||||
-rw-r--r-- | doc/internal/man3/ossl_cmp_mock_srv_new.pod | 7 | ||||
-rw-r--r-- | doc/man1/openssl-cmp.pod.in | 4 | ||||
-rw-r--r-- | doc/man3/OSSL_CMP_ITAV_new_caCerts.pod | 59 | ||||
-rw-r--r-- | doc/man3/OSSL_CMP_exec_certreq.pod | 15 | ||||
-rw-r--r-- | include/openssl/cmp.h.in | 14 | ||||
-rw-r--r-- | include/openssl/cmperr.h | 3 | ||||
-rw-r--r-- | test/recipes/80-test_cmp_http_data/test_commands.csv | 4 | ||||
-rw-r--r-- | util/libcrypto.num | 3 |
18 files changed, 409 insertions, 43 deletions
diff --git a/apps/cmp.c b/apps/cmp.c index a3d0c19dd3..aec56b4425 100644 --- a/apps/cmp.c +++ b/apps/cmp.c @@ -277,7 +277,7 @@ const OPTIONS cmp_options[] = { OPT_SECTION("Generic message"), {"cmd", OPT_CMD, 's', "CMP request to send: ir/cr/kur/p10cr/rr/genm"}, {"infotype", OPT_INFOTYPE, 's', - "InfoType name for requesting specific info in genm, e.g. 'signKeyPairTypes'"}, + "InfoType name for requesting specific info in genm, e.g. 'caCerts'"}, {"geninfo", OPT_GENINFO, 's', "generalInfo integer values to place in request PKIHeader with given OID"}, {OPT_MORE_STR, 0, 0, @@ -395,7 +395,7 @@ const OPTIONS cmp_options[] = { {"extracertsout", OPT_EXTRACERTSOUT, 's', "File to save extra certificates received in the extraCerts field"}, {"cacertsout", OPT_CACERTSOUT, 's', - "File to save CA certificates received in the caPubs field of 'ip' messages"}, + "File to save CA certs received in caPubs field or genp with id-it-caCerts"}, OPT_SECTION("Client authentication"), {"ref", OPT_REF, 's', @@ -1615,6 +1615,8 @@ static int setup_request_ctx(OSSL_CMP_CTX *ctx, ENGINE *engine) CMP_warn1("-days %s", msg); if (opt_popo != OSSL_CRMF_POPO_NONE - 1) CMP_warn1("-popo %s", msg); + if (opt_out_trusted != NULL) + CMP_warn1("-out_trusted %s", msg); } else if (opt_newkey != NULL) { const char *file = opt_newkey; const int format = opt_keyform; @@ -1873,8 +1875,9 @@ static int setup_client_ctx(OSSL_CMP_CTX *ctx, ENGINE *engine) } goto set_path; } - if (!OSSL_HTTP_parse_url(opt_server, &use_ssl, NULL /* user */, &host, &port, - &portnum, &path, NULL /* q */, NULL /* frag */)) { + if (!OSSL_HTTP_parse_url(opt_server, &use_ssl, NULL /* user */, + &host, &port, &portnum, + &path, NULL /* q */, NULL /* frag */)) { CMP_err1("cannot parse -server URL: %s", opt_server); goto err; } @@ -1909,7 +1912,12 @@ static int setup_client_ctx(OSSL_CMP_CTX *ctx, ENGINE *engine) if (!transform_opts()) goto err; - if (opt_infotype_s != NULL) { + if (opt_infotype_s == NULL) { + if (opt_cmd == CMP_GENM) + CMP_warn("no -infotype option given for genm"); + } else if (opt_cmd != CMP_GENM) { + CMP_warn("-infotype option is ignored for commands other than 'genm'"); + } else { char id_buf[100] = "id-it-"; strncat(id_buf, opt_infotype_s, sizeof(id_buf) - strlen(id_buf) - 1); @@ -2136,9 +2144,8 @@ static int print_itavs(const STACK_OF(OSSL_CMP_ITAV) *itavs) if (i2t_ASN1_OBJECT(name, sizeof(name), type) <= 0) { CMP_err1("error parsing type of ITAV #%d from genp", i); ret = 0; - } - else { - CMP_info2("ITAV #%d from genp type=%s", i, name); + } else { + CMP_info2("ITAV #%d from genp infoType=%s", i, name); } } return ret; @@ -2829,6 +2836,56 @@ static void print_status(void) OPENSSL_free(buf); } +static int do_genm(OSSL_CMP_CTX *ctx) +{ + if (opt_infotype == NID_id_it_caCerts) { + STACK_OF(X509) *cacerts = NULL; + + if (opt_cacertsout == NULL) { + CMP_err("Missing -cacertsout option for -infotype caCerts"); + return 0; + } + + if (!OSSL_CMP_get_caCerts(ctx, &cacerts)) + return 0; + + /* could check authorization of sender/origin at this point */ + if (cacerts == NULL) { + CMP_warn("no CA certificates provided by server"); + } else if (save_free_certs(cacerts, opt_cacertsout, "CA") < 0) { + CMP_err1("Failed to store CA certficates from genp in %s", + opt_cacertsout); + return 0; + } + return 1; + } else { + OSSL_CMP_ITAV *req; + STACK_OF(OSSL_CMP_ITAV) *itavs; + + if (opt_infotype != NID_undef) { + CMP_warn1("No specific support for -infotype %s available", + opt_infotype_s); + + req = OSSL_CMP_ITAV_create(OBJ_nid2obj(opt_infotype), NULL); + if (req == NULL || !OSSL_CMP_CTX_push0_genm_ITAV(ctx, req)) { + CMP_err1("Failed to create genm for -infotype %s", + opt_infotype_s); + return 0; + } + } + + if ((itavs = OSSL_CMP_exec_GENM_ses(ctx)) != NULL) { + int res = print_itavs(itavs); + + sk_OSSL_CMP_ITAV_pop_free(itavs, OSSL_CMP_ITAV_free); + return res; + } + if (OSSL_CMP_CTX_get_status(ctx) != OSSL_CMP_PKISTATUS_request) + CMP_err("Did not receive response on genm or genp is not valid"); + return 0; + } +} + int cmp_main(int argc, char **argv) { char *configfile = NULL; @@ -3041,26 +3098,7 @@ int cmp_main(int argc, char **argv) ret = OSSL_CMP_exec_RR_ses(cmp_ctx); break; case CMP_GENM: - { - STACK_OF(OSSL_CMP_ITAV) *itavs; - - if (opt_infotype != NID_undef) { - OSSL_CMP_ITAV *itav = - OSSL_CMP_ITAV_create(OBJ_nid2obj(opt_infotype), NULL); - - if (itav == NULL) - goto err; - OSSL_CMP_CTX_push0_genm_ITAV(cmp_ctx, itav); - } - - if ((itavs = OSSL_CMP_exec_GENM_ses(cmp_ctx)) != NULL) { - ret = print_itavs(itavs); - sk_OSSL_CMP_ITAV_pop_free(itavs, OSSL_CMP_ITAV_free); - } else { - CMP_err("could not obtain ITAVs from genp"); - } - break; - } + ret = do_genm(cmp_ctx); default: break; } diff --git a/apps/lib/cmp_mock_srv.c b/apps/lib/cmp_mock_srv.c index c19651221b..fac396bd2e 100644 --- a/apps/lib/cmp_mock_srv.c +++ b/apps/lib/cmp_mock_srv.c @@ -21,7 +21,7 @@ typedef struct X509 *refCert; /* cert to expect for oldCertID in kur/rr msg */ X509 *certOut; /* certificate to be returned in cp/ip/kup msg */ STACK_OF(X509) *chainOut; /* chain of certOut to add to extraCerts field */ - STACK_OF(X509) *caPubsOut; /* certs to return in caPubs field of ip msg */ + STACK_OF(X509) *caPubsOut; /* used in caPubs of ip and in caCerts of genp */ OSSL_CMP_PKISI *statusOut; /* status for ip/cp/kup/rp msg unless polling */ int sendError; /* send error response on given request type */ OSSL_CMP_MSG *certReq; /* ir/cr/p10cr/kur remembered while polling */ @@ -30,7 +30,6 @@ typedef struct int checkAfterTime; /* time the client should wait between polling */ } mock_srv_ctx; - static void mock_srv_ctx_free(mock_srv_ctx *ctx) { if (ctx == NULL) @@ -332,6 +331,21 @@ static int process_genm(OSSL_CMP_SRV_CTX *srv_ctx, ERR_raise(ERR_LIB_CMP, CMP_R_ERROR_PROCESSING_MESSAGE); return 0; } + if (sk_OSSL_CMP_ITAV_num(in) == 1) { + OSSL_CMP_ITAV *req = sk_OSSL_CMP_ITAV_value(in, 0), *rsp; + ASN1_OBJECT *obj = OSSL_CMP_ITAV_get0_type(req); + + if (OBJ_obj2nid(obj) == NID_id_it_caCerts) { + if ((*out = sk_OSSL_CMP_ITAV_new_reserve(NULL, 1)) == NULL) + return 0; + if ((rsp = OSSL_CMP_ITAV_new_caCerts(ctx->caPubsOut)) == NULL) { + sk_OSSL_CMP_ITAV_free(*out); + return 0; + } + (void)sk_OSSL_CMP_ITAV_push(*out, rsp); + return 1; + } + } *out = sk_OSSL_CMP_ITAV_deep_copy(in, OSSL_CMP_ITAV_dup, OSSL_CMP_ITAV_free); 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, diff --git a/crypto/err/openssl.txt b/crypto/err/openssl.txt index 753fb6557d..a3fac68232 100644 --- a/crypto/err/openssl.txt +++ b/crypto/err/openssl.txt @@ -231,7 +231,9 @@ CMP_R_FAILED_BUILDING_OWN_CHAIN:164:failed building own chain CMP_R_FAILED_EXTRACTING_PUBKEY:141:failed extracting pubkey CMP_R_FAILURE_OBTAINING_RANDOM:110:failure obtaining random CMP_R_FAIL_INFO_OUT_OF_RANGE:129:fail info out of range +CMP_R_GETTING_GENP:192:getting genp CMP_R_INVALID_ARGS:100:invalid args +CMP_R_INVALID_GENP:193:invalid genp CMP_R_INVALID_OPTION:174:invalid option CMP_R_MISSING_CERTID:165:missing certid CMP_R_MISSING_KEY_INPUT_FOR_CREATING_PROTECTION:130:\ @@ -268,6 +270,7 @@ CMP_R_SRVCERT_DOES_NOT_VALIDATE_MSG:151:srvcert does not validate msg CMP_R_TOTAL_TIMEOUT:184:total timeout CMP_R_TRANSACTIONID_UNMATCHED:152:transactionid unmatched CMP_R_TRANSFER_ERROR:159:transfer error +CMP_R_UNCLEAN_CTX:191:unclean ctx CMP_R_UNEXPECTED_PKIBODY:133:unexpected pkibody CMP_R_UNEXPECTED_PKISTATUS:185:unexpected pkistatus CMP_R_UNEXPECTED_PVNO:153:unexpected pvno diff --git a/doc/build.info b/doc/build.info index 52db908985..6031a85d4d 100644 --- a/doc/build.info +++ b/doc/build.info @@ -1591,6 +1591,10 @@ DEPEND[html/man3/OSSL_CMP_HDR_get0_transactionID.html]=man3/OSSL_CMP_HDR_get0_tr GENERATE[html/man3/OSSL_CMP_HDR_get0_transactionID.html]=man3/OSSL_CMP_HDR_get0_transactionID.pod DEPEND[man/man3/OSSL_CMP_HDR_get0_transactionID.3]=man3/OSSL_CMP_HDR_get0_transactionID.pod GENERATE[man/man3/OSSL_CMP_HDR_get0_transactionID.3]=man3/OSSL_CMP_HDR_get0_transactionID.pod +DEPEND[html/man3/OSSL_CMP_ITAV_new_caCerts.html]=man3/OSSL_CMP_ITAV_new_caCerts.pod +GENERATE[html/man3/OSSL_CMP_ITAV_new_caCerts.html]=man3/OSSL_CMP_ITAV_new_caCerts.pod +DEPEND[man/man3/OSSL_CMP_ITAV_new_caCerts.3]=man3/OSSL_CMP_ITAV_new_caCerts.pod +GENERATE[man/man3/OSSL_CMP_ITAV_new_caCerts.3]=man3/OSSL_CMP_ITAV_new_caCerts.pod DEPEND[html/man3/OSSL_CMP_ITAV_set0.html]=man3/OSSL_CMP_ITAV_set0.pod GENERATE[html/man3/OSSL_CMP_ITAV_set0.html]=man3/OSSL_CMP_ITAV_set0.pod DEPEND[man/man3/OSSL_CMP_ITAV_set0.3]=man3/OSSL_CMP_ITAV_set0.pod @@ -3289,6 +3293,7 @@ html/man3/OSSL_ALGORITHM.html \ html/man3/OSSL_CALLBACK.html \ html/man3/OSSL_CMP_CTX_new.html \ html/man3/OSSL_CMP_HDR_get0_transactionID.html \ +html/man3/OSSL_CMP_ITAV_new_caCerts.html \ html/man3/OSSL_CMP_ITAV_set0.html \ html/man3/OSSL_CMP_MSG_get0_header.html \ html/man3/OSSL_CMP_MSG_http_perform.html \ @@ -3924,6 +3929,7 @@ man/man3/OSSL_ALGORITHM.3 \ man/man3/OSSL_CALLBACK.3 \ man/man3/OSSL_CMP_CTX_new.3 \ man/man3/OSSL_CMP_HDR_get0_transactionID.3 \ +man/man3/OSSL_CMP_ITAV_new_caCerts.3 \ man/man3/OSSL_CMP_ITAV_set0.3 \ man/man3/OSSL_CMP_MSG_get0_header.3 \ man/man3/OSSL_CMP_MSG_http_perform.3 \ diff --git a/doc/internal/man3/ossl_cmp_mock_srv_new.pod b/doc/internal/man3/ossl_cmp_mock_srv_new.pod index 119077ea7c..59568c65fc 100644 --- a/doc/internal/man3/ossl_cmp_mock_srv_new.pod +++ b/doc/internal/man3/ossl_cmp_mock_srv_new.pod @@ -45,16 +45,17 @@ ossl_cmp_mock_srv_set1_refCert() sets the reference certificate to be expected for rr messages and for any oldCertID included in kur messages. ossl_cmp_mock_srv_set1_certOut() sets the certificate to be returned in -cp/ip/kup. +cp/ip/kup messages. Note that on each certificate request the mock server does not produce a fresh certificate but just returns the same pre-existing certificate. ossl_cmp_mock_srv_set1_chainOut() sets the certificate chain to be added to -the extraCerts in a cp/ip/kup. +the extraCerts in a cp/ip/kup message. It should be useful for the validation of the certificate given via ossl_cmp_mock_srv_set1_certOut(). -ossl_cmp_mock_srv_set1_caPubsOut() sets the caPubs to be returned in an ip. +ossl_cmp_mock_srv_set1_caPubsOut() sets the caPubs to be returned in an ip msg +and the list of certificates to be returned in a genp of infoType caCerts. ossl_cmp_mock_srv_set_statusInfo() sets the status info to be returned. diff --git a/doc/man1/openssl-cmp.pod.in b/doc/man1/openssl-cmp.pod.in index 76c4313bd5..2c8a8b2540 100644 --- a/doc/man1/openssl-cmp.pod.in +++ b/doc/man1/openssl-cmp.pod.in @@ -236,6 +236,7 @@ ITAV B<infoType>s is printed to stdout. Set InfoType name to use for requesting specific info in B<genm>, e.g., C<signKeyPairTypes>. +So far, there is specific support for C<caCerts>. =item B<-geninfo> I<OID:int:N> @@ -655,7 +656,8 @@ field of the last received response message that is not a pollRep nor PKIConf. =item B<-cacertsout> I<filename> The file where to save the list of CA certificates contained in the caPubs field -if a positive certificate response (i.e., IP, CP, or KUP) message was received. +if a positive certificate response (i.e., IP, CP, or KUP) message was received +or contained in a general response (genp) message with infoType C<caCerts>. =back diff --git a/doc/man3/OSSL_CMP_ITAV_new_caCerts.pod b/doc/man3/OSSL_CMP_ITAV_new_caCerts.pod new file mode 100644 index 0000000000..eb397388aa --- /dev/null +++ b/doc/man3/OSSL_CMP_ITAV_new_caCerts.pod @@ -0,0 +1,59 @@ +=pod + +=head1 NAME + +OSSL_CMP_ITAV_new_caCerts, +OSSL_CMP_ITAV_get0_caCerts +- CMP utility functions for handling specific genm and genp messages + +=head1 SYNOPSIS + + #include <openssl/cmp.h> + + OSSL_CMP_ITAV *OSSL_CMP_ITAV_new_caCerts(const STACK_OF(X509) *caCerts); + int OSSL_CMP_ITAV_get0_caCerts(const OSSL_CMP_ITAV *itav, STACK_OF(X509) **out); + +=head1 DESCRIPTION + +ITAV is short for InfoTypeAndValue. + +OSSL_CMP_ITAV_new_caCerts() creates an B<OSSL_CMP_ITAV> structure of type +B<caCerts> and fills it with a copy of the provided list of certificates. +The I<caCerts> argument may be NULL or contain any number of certificates. + +OSSL_CMP_ITAV_get0_caCerts() requires that I<itav> has type B<caCerts>. +It assigns NULL to I<*out> if there are no CA certificates in I<itav>, otherwise +the internal pointer of type B<STACK_OF(X509)> with the certificates present. + +=head1 NOTES + +CMP is defined in RFC 4210. + +=head1 RETURN VALUES + +OSSL_CMP_ITAV_new_caCerts() +returns a pointer to the new ITAV structure on success, or NULL on error. + +OSSL_CMP_ITAV_get0_caCerts() +returns 1 on success, 0 on error. + +=head1 SEE ALSO + +L<OSSL_CMP_ITAV_create(3)> and L<OSSL_CMP_ITAV_get0_type(3)> + +=head1 HISTORY + +OSSL_CMP_ITAV_new_caCerts() and +OSSL_CMP_ITAV_get0_rootCaCert() +were added in OpenSSL 3.2. + +=head1 COPYRIGHT + +Copyright 2022 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_exec_certreq.pod b/doc/man3/OSSL_CMP_exec_certreq.pod index b0d81c7c41..a418657e3c 100644 --- a/doc/man3/OSSL_CMP_exec_certreq.pod +++ b/doc/man3/OSSL_CMP_exec_certreq.pod @@ -13,7 +13,8 @@ OSSL_CMP_P10CR, OSSL_CMP_KUR, OSSL_CMP_try_certreq, OSSL_CMP_exec_RR_ses, -OSSL_CMP_exec_GENM_ses +OSSL_CMP_exec_GENM_ses, +OSSL_CMP_get_caCerts - functions implementing CMP client transactions =head1 SYNOPSIS @@ -34,6 +35,7 @@ OSSL_CMP_exec_GENM_ses const OSSL_CRMF_MSG *crm, int *checkAfter); int OSSL_CMP_exec_RR_ses(OSSL_CMP_CTX *ctx); STACK_OF(OSSL_CMP_ITAV) *OSSL_CMP_exec_GENM_ses(OSSL_CMP_CTX *ctx); + int OSSL_CMP_get_caCerts(OSSL_CMP_CTX *ctx, STACK_OF(X509) **out); =head1 DESCRIPTION @@ -115,6 +117,12 @@ and returns the list of B<ITAV>s received in the GENP message. This can be used, for instance, to poll for CRLs or CA Key Updates. See RFC 4210 section 5.3.19 and appendix E.5 for details. +OSSL_CMP_get_caCerts() uses a genm/gemp message exchange with infoType caCerts +to obtain a list of CA certificates from the CMP server referenced by I<ctx>. +On success it assigns to I<*out> the list of certificates received, +which must be freed by the caller. +NULL means that no CA certificate is available at the server. + =head1 NOTES CMP is defined in RFC 4210 (and CRMF in RFC 4211). @@ -138,7 +146,8 @@ In the latter case L<OSSL_CMP_CTX_get0_newCert(3)> yields NULL and the output parameter I<checkAfter> has been used to assign the received value unless I<checkAfter> is NULL. -OSSL_CMP_exec_RR_ses() returns 1 on success, 0 on error. +OSSL_CMP_exec_RR_ses() and OSSL_CMP_get_caCerts() +return 1 on success, 0 on error. OSSL_CMP_exec_GENM_ses() returns NULL on error, otherwise a pointer to the sequence of B<ITAV> received, which may be empty. @@ -161,6 +170,8 @@ L<OSSL_CMP_MSG_http_perform(3)> The OpenSSL CMP support was added in OpenSSL 3.0. +OSSL_CMP_get_caCerts() was added in OpenSSL 3.2. + =head1 COPYRIGHT Copyright 2007-2021 The OpenSSL Project Authors. All Rights Reserved. diff --git a/include/openssl/cmp.h.in b/include/openssl/cmp.h.in index 4e14200d82..c986674be2 100644 --- a/include/openssl/cmp.h.in +++ b/include/openssl/cmp.h.in @@ -140,7 +140,6 @@ extern "C" { # if OSSL_CMP_PKIFAILUREINFO_MAX_BIT_PATTERN > INT_MAX # error CMP_PKIFAILUREINFO_MAX bit pattern does not fit in type int # endif - typedef ASN1_BIT_STRING OSSL_CMP_PKIFAILUREINFO; # define OSSL_CMP_CTX_FAILINFO_badAlg (1 << 0) @@ -206,8 +205,8 @@ typedef ASN1_BIT_STRING OSSL_CMP_PKIFAILUREINFO; # define OSSL_CMP_PKISTATUS_revocationWarning 4 # define OSSL_CMP_PKISTATUS_revocationNotification 5 # define OSSL_CMP_PKISTATUS_keyUpdateWarning 6 - typedef ASN1_INTEGER OSSL_CMP_PKISTATUS; + DECLARE_ASN1_ITEM(OSSL_CMP_PKISTATUS) # define OSSL_CMP_CERTORENCCERT_CERTIFICATE 0 @@ -261,6 +260,10 @@ ASN1_TYPE *OSSL_CMP_ITAV_get0_value(const OSSL_CMP_ITAV *itav); int OSSL_CMP_ITAV_push0_stack_item(STACK_OF(OSSL_CMP_ITAV) **itav_sk_p, OSSL_CMP_ITAV *itav); void OSSL_CMP_ITAV_free(OSSL_CMP_ITAV *itav); + +OSSL_CMP_ITAV *OSSL_CMP_ITAV_new_caCerts(const STACK_OF(X509) *caCerts); +int OSSL_CMP_ITAV_get0_caCerts(const OSSL_CMP_ITAV *itav, STACK_OF(X509) **out); + void OSSL_CMP_MSG_free(OSSL_CMP_MSG *msg); /* from cmp_ctx.c */ @@ -317,9 +320,9 @@ void *OSSL_CMP_CTX_get_transfer_cb_arg(const OSSL_CMP_CTX *ctx); int OSSL_CMP_CTX_set1_srvCert(OSSL_CMP_CTX *ctx, X509 *cert); int OSSL_CMP_CTX_set1_expected_sender(OSSL_CMP_CTX *ctx, const X509_NAME *name); int OSSL_CMP_CTX_set0_trustedStore(OSSL_CMP_CTX *ctx, X509_STORE *store); -#define OSSL_CMP_CTX_set0_trusted OSSL_CMP_CTX_set0_trustedStore +# define OSSL_CMP_CTX_set0_trusted OSSL_CMP_CTX_set0_trustedStore X509_STORE *OSSL_CMP_CTX_get0_trustedStore(const OSSL_CMP_CTX *ctx); -#define OSSL_CMP_CTX_get0_trusted OSSL_CMP_CTX_get0_trustedStore +# define OSSL_CMP_CTX_get0_trusted OSSL_CMP_CTX_get0_trustedStore int OSSL_CMP_CTX_set1_untrusted(OSSL_CMP_CTX *ctx, STACK_OF(X509) *certs); STACK_OF(X509) *OSSL_CMP_CTX_get0_untrusted(const OSSL_CMP_CTX *ctx); /* client authentication: */ @@ -478,6 +481,9 @@ int OSSL_CMP_try_certreq(OSSL_CMP_CTX *ctx, int req_type, int OSSL_CMP_exec_RR_ses(OSSL_CMP_CTX *ctx); STACK_OF(OSSL_CMP_ITAV) *OSSL_CMP_exec_GENM_ses(OSSL_CMP_CTX *ctx); +/* from cmp_genm.c */ +int OSSL_CMP_get_caCerts(OSSL_CMP_CTX *ctx, STACK_OF(X509) **out); + # ifdef __cplusplus } # endif diff --git a/include/openssl/cmperr.h b/include/openssl/cmperr.h index 49fd5e392a..f44 |