From: Dr. David von Oheimb Date: Sat, 17 Sep 2022 08:56:21 +0000 (+0200) Subject: CMP: add support for genm with rootCaCert and genp with rootCaKeyUpdate X-Git-Tag: openssl-3.2.0-alpha1~409 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=01b048513153bdbee3efc82389d38d353352a7f1;p=thirdparty%2Fopenssl.git CMP: add support for genm with rootCaCert and genp with rootCaKeyUpdate Reviewed-by: Tomas Mraz Reviewed-by: Paul Dale (Merged from https://github.com/openssl/openssl/pull/21129) --- diff --git a/apps/cmp.c b/apps/cmp.c index d56a5e451cb..dbc609a2e00 100644 --- a/apps/cmp.c +++ b/apps/cmp.c @@ -89,6 +89,10 @@ static int opt_unprotected_errors = 0; static char *opt_srvcertout = NULL; static char *opt_extracertsout = NULL; static char *opt_cacertsout = NULL; +static char *opt_oldwithold = NULL; +static char *opt_newwithnew = NULL; +static char *opt_newwithold = NULL; +static char *opt_oldwithnew = NULL; /* client authentication */ static char *opt_ref = NULL; @@ -181,6 +185,10 @@ static char *opt_ref_cert = NULL; static char *opt_rsp_cert = NULL; static char *opt_rsp_extracerts = NULL; static char *opt_rsp_capubs = NULL; +static char *opt_rsp_newwithnew = NULL; +static char *opt_rsp_newwithold = NULL; +static char *opt_rsp_oldwithnew = NULL; + static int opt_poll_count = 0; static int opt_check_after = 1; static int opt_grant_implicitconf = 0; @@ -224,6 +232,7 @@ typedef enum OPTION_choice { OPT_EXPECT_SENDER, OPT_IGNORE_KEYUSAGE, OPT_UNPROTECTED_ERRORS, OPT_SRVCERTOUT, OPT_EXTRACERTSOUT, OPT_CACERTSOUT, + OPT_OLDWITHOLD, OPT_NEWWITHNEW, OPT_NEWWITHOLD, OPT_OLDWITHNEW, OPT_REF, OPT_SECRET, OPT_CERT, OPT_OWN_TRUSTED, OPT_KEY, OPT_KEYPASS, OPT_DIGEST, OPT_MAC, OPT_EXTRACERTS, @@ -254,6 +263,7 @@ typedef enum OPTION_choice { OPT_SRV_CERT, OPT_SRV_KEY, OPT_SRV_KEYPASS, OPT_SRV_TRUSTED, OPT_SRV_UNTRUSTED, OPT_REF_CERT, OPT_RSP_CERT, OPT_RSP_EXTRACERTS, OPT_RSP_CAPUBS, + OPT_RSP_NEWWITHNEW, OPT_RSP_NEWWITHOLD, OPT_RSP_OLDWITHNEW, OPT_POLL_COUNT, OPT_CHECK_AFTER, OPT_GRANT_IMPLICITCONF, OPT_PKISTATUS, OPT_FAILURE, @@ -278,7 +288,9 @@ 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. 'caCerts'"}, + "InfoType name for requesting specific info in genm, with specific support"}, + {OPT_MORE_STR, 0, 0, + "for 'caCerts' and 'rootCaCert'"}, {"geninfo", OPT_GENINFO, 's', "generalInfo integer values to place in request PKIHeader with given OID"}, {OPT_MORE_STR, 0, 0, @@ -399,6 +411,14 @@ const OPTIONS cmp_options[] = { "File to save extra certificates received in the extraCerts field"}, {"cacertsout", OPT_CACERTSOUT, 's', "File to save CA certs received in caPubs field or genp with id-it-caCerts"}, + { "oldwithold", OPT_OLDWITHOLD, 's', + "Root CA certificate to request update for in genm of type rootCaCert"}, + { "newwithnew", OPT_NEWWITHNEW, 's', + "File to save NewWithNew cert received in genp of type rootCaKeyUpdate"}, + { "newwithold", OPT_NEWWITHOLD, 's', + "File to save NewWithOld cert received in genp of type rootCaKeyUpdate"}, + { "oldwithnew", OPT_OLDWITHNEW, 's', + "File to save OldWithNew cert received in genp of type rootCaKeyUpdate"}, OPT_SECTION("Client authentication"), {"ref", OPT_REF, 's', @@ -517,6 +537,12 @@ const OPTIONS cmp_options[] = { "Extra certificates to be included in mock certification responses"}, {"rsp_capubs", OPT_RSP_CAPUBS, 's', "CA certificates to be included in mock ip response"}, + {"rsp_newwithnew", OPT_RSP_NEWWITHNEW, 's', + "New root CA certificate to include in genp of type rootCaKeyUpdate"}, + {"rsp_newwithold", OPT_RSP_NEWWITHOLD, 's', + "NewWithOld transition cert to include in genp of type rootCaKeyUpdate"}, + {"rsp_oldwithnew", OPT_RSP_OLDWITHNEW, 's', + "OldWithNew transition cert to include in genp of type rootCaKeyUpdate"}, {"poll_count", OPT_POLL_COUNT, 'N', "Number of times the client must poll before receiving a certificate"}, {"check_after", OPT_CHECK_AFTER, 'N', @@ -584,6 +610,7 @@ static varref cmp_vars[] = { /* must be in same order as enumerated above! */ {&opt_expect_sender}, {(char **)&opt_ignore_keyusage}, {(char **)&opt_unprotected_errors}, {&opt_srvcertout}, {&opt_extracertsout}, {&opt_cacertsout}, + {&opt_oldwithold}, {&opt_newwithnew}, {&opt_newwithold}, {&opt_oldwithnew}, {&opt_ref}, {&opt_secret}, {&opt_cert}, {&opt_own_trusted}, {&opt_key}, {&opt_keypass}, @@ -614,6 +641,8 @@ static varref cmp_vars[] = { /* must be in same order as enumerated above! */ {&opt_srv_cert}, {&opt_srv_key}, {&opt_srv_keypass}, {&opt_srv_trusted}, {&opt_srv_untrusted}, {&opt_ref_cert}, {&opt_rsp_cert}, {&opt_rsp_extracerts}, {&opt_rsp_capubs}, + {&opt_rsp_newwithnew}, {&opt_rsp_newwithold}, {&opt_rsp_oldwithnew}, + {(char **)&opt_poll_count}, {(char **)&opt_check_after}, {(char **)&opt_grant_implicitconf}, {(char **)&opt_pkistatus}, {(char **)&opt_failure}, @@ -929,8 +958,23 @@ static X509_STORE *load_trusted(char *input, int for_new_cert, const char *desc) return NULL; } -typedef int (*add_X509_stack_fn_t)(void *ctx, const STACK_OF(X509) *certs); +typedef int (*add_X509_fn_t)(void *ctx, const X509 *cert); +static int setup_cert(void *ctx, const char *file, const char *pass, + const char *desc, add_X509_fn_t set1_fn) +{ + X509 *cert; + int ok; + + if (file == NULL) + return 1; + if ((cert = load_cert_pwd(file, pass, desc)) == NULL) + return 0; + ok = (*set1_fn)(ctx, cert); + X509_free(cert); + return ok; +} +typedef int (*add_X509_stack_fn_t)(void *ctx, const STACK_OF(X509) *certs); static int setup_certs(char *files, const char *desc, void *ctx, add_X509_stack_fn_t set1_fn) { @@ -1043,16 +1087,10 @@ static OSSL_CMP_SRV_CTX *setup_srv_ctx(ENGINE *engine) CMP_err("must give both -srv_cert and -srv_key options or neither"); goto err; } - if (opt_srv_cert != NULL) { - X509 *srv_cert = load_cert_pwd(opt_srv_cert, opt_srv_keypass, - "certificate of the mock server"); - - if (srv_cert == NULL || !OSSL_CMP_CTX_set1_cert(ctx, srv_cert)) { - X509_free(srv_cert); - goto err; - } - X509_free(srv_cert); - } + if (!setup_cert(ctx, opt_srv_cert, opt_srv_keypass, + "signer certificate of the mock server", + (add_X509_fn_t)OSSL_CMP_CTX_set1_cert)) + goto err; if (opt_srv_key != NULL) { EVP_PKEY *pkey = load_key_pwd(opt_srv_key, opt_keyform, opt_srv_keypass, @@ -1082,31 +1120,17 @@ static OSSL_CMP_SRV_CTX *setup_srv_ctx(ENGINE *engine) (add_X509_stack_fn_t)OSSL_CMP_CTX_set1_untrusted)) goto err; - if (opt_ref_cert != NULL) { - X509 *cert = load_cert_pwd(opt_ref_cert, opt_keypass, - "reference cert to be expected by the mock server"); - - if (cert == NULL) - goto err; - if (!ossl_cmp_mock_srv_set1_refCert(srv_ctx, cert)) { - X509_free(cert); + if (!setup_cert(srv_ctx, opt_ref_cert, opt_otherpass, + "reference cert to be expected by the mock server", + (add_X509_fn_t)ossl_cmp_mock_srv_set1_refCert)) goto err; - } - X509_free(cert); - } if (opt_rsp_cert == NULL) { CMP_warn("no -rsp_cert given for mock server"); } else { - X509 *cert = load_cert_pwd(opt_rsp_cert, opt_keypass, - "cert to be returned by the mock server"); - - if (cert == NULL) - goto err; - if (!ossl_cmp_mock_srv_set1_certOut(srv_ctx, cert)) { - X509_free(cert); + if (!setup_cert(srv_ctx, opt_rsp_cert, opt_keypass, + "cert the mock server returns on certificate requests", + (add_X509_fn_t)ossl_cmp_mock_srv_set1_certOut)) goto err; - } - X509_free(cert); } if (!setup_certs(opt_rsp_extracerts, "CMP extra certificates for mock server", srv_ctx, @@ -1115,6 +1139,16 @@ static OSSL_CMP_SRV_CTX *setup_srv_ctx(ENGINE *engine) if (!setup_certs(opt_rsp_capubs, "caPubs for mock server", srv_ctx, (add_X509_stack_fn_t)ossl_cmp_mock_srv_set1_caPubsOut)) goto err; + if (!setup_cert(srv_ctx, opt_rsp_newwithnew, opt_otherpass, + "NewWithNew cert the mock server returns in rootCaKeyUpdate", + (add_X509_fn_t)ossl_cmp_mock_srv_set1_newWithNew) + || !setup_cert(srv_ctx, opt_rsp_newwithold, opt_otherpass, + "NewWithOld cert the mock server returns in rootCaKeyUpdate", + (add_X509_fn_t)ossl_cmp_mock_srv_set1_newWithOld) + || !setup_cert(srv_ctx, opt_rsp_oldwithnew, opt_otherpass, + "OldWithNew cert the mock server returns in rootCaKeyUpdate", + (add_X509_fn_t)ossl_cmp_mock_srv_set1_oldWithNew)) + goto err; (void)ossl_cmp_mock_srv_set_pollCount(srv_ctx, opt_poll_count); (void)ossl_cmp_mock_srv_set_checkAfterTime(srv_ctx, opt_check_after); if (opt_grant_implicitconf) @@ -1171,10 +1205,6 @@ static int setup_verification_ctx(OSSL_CMP_CTX *ctx) return 0; if (opt_srvcert != NULL || opt_trusted != NULL) { - X509 *srvcert; - X509_STORE *ts; - int ok; - if (opt_srvcert != NULL) { if (opt_trusted != NULL) { CMP_warn("-trusted option is ignored since -srvcert option is present"); @@ -1184,14 +1214,14 @@ static int setup_verification_ctx(OSSL_CMP_CTX *ctx) CMP_warn("-recipient option is ignored since -srvcert option is present"); opt_recipient = NULL; } - srvcert = load_cert_pwd(opt_srvcert, opt_otherpass, - "directly trusted CMP server certificate"); - ok = srvcert != NULL && OSSL_CMP_CTX_set1_srvCert(ctx, srvcert); - X509_free(srvcert); - if (!ok) + if (!setup_cert(ctx, opt_srvcert, opt_otherpass, + "directly trusted CMP server certificate", + (add_X509_fn_t)OSSL_CMP_CTX_set1_srvCert)) return 0; } if (opt_trusted != NULL) { + X509_STORE *ts; + /* * the 0 arg below clears any expected host/ip/email address; * opt_expect_sender is used instead @@ -1408,7 +1438,7 @@ static int setup_protection_ctx(OSSL_CMP_CTX *ctx, ENGINE *engine) CMP_err("must give -ref if no -cert and no -subject given"); return 0; } - if (!opt_secret && ((opt_cert == NULL) != (opt_key == NULL))) { + if (opt_secret == NULL && ((opt_cert == NULL) != (opt_key == NULL))) { CMP_err("must give both -cert and -key options or neither"); return 0; } @@ -1786,22 +1816,13 @@ static int setup_request_ctx(OSSL_CMP_CTX *ctx, ENGINE *engine) if (opt_cmd == CMP_GENM) { CMP_warn("-oldcert option is ignored for 'genm' command"); } else { - X509 *oldcert = load_cert_pwd(opt_oldcert, opt_keypass, - opt_cmd == CMP_KUR ? - "certificate to be updated" : - opt_cmd == CMP_RR ? - "certificate to be revoked" : - "reference certificate (oldcert)"); - /* opt_keypass needed if opt_oldcert is an encrypted PKCS#12 file */ - - if (oldcert == NULL) - return 0; - if (!OSSL_CMP_CTX_set1_oldCert(ctx, oldcert)) { - X509_free(oldcert); - CMP_err("out of memory"); + if (!setup_cert(ctx, opt_oldcert, opt_keypass, + /* needed if opt_oldcert is encrypted PKCS12 file */ + opt_cmd == CMP_KUR ? "certificate to be updated" : + opt_cmd == CMP_RR ? "certificate to be revoked" : + "reference certificate (oldcert)", + (add_X509_fn_t)OSSL_CMP_CTX_set1_oldCert)) return 0; - } - X509_free(oldcert); } } cleanse(opt_keypass); @@ -1969,6 +1990,18 @@ static int setup_client_ctx(OSSL_CMP_CTX *ctx, ENGINE *engine) goto err; } } + if (opt_cmd != CMP_GENM || opt_infotype != NID_id_it_rootCaCert) { + const char *msg = "option is ignored unless -cmd 'genm' and -infotype rootCaCert is given"; + + if (opt_oldwithold != NULL) + CMP_warn1("-oldwithold %s", msg); + if (opt_newwithnew != NULL) + CMP_warn1("-newwithnew %s", msg); + if (opt_newwithold != NULL) + CMP_warn1("-newwithold %s", msg); + if (opt_oldwithnew != NULL) + CMP_warn1("-oldwithnew %s", msg); + } if (!setup_verification_ctx(ctx)) goto err; @@ -2549,6 +2582,18 @@ static int get_opts(int argc, char **argv) case OPT_CACERTSOUT: opt_cacertsout = opt_str(); break; + case OPT_OLDWITHOLD: + opt_oldwithold = opt_str(); + break; + case OPT_NEWWITHNEW: + opt_newwithnew = opt_str(); + break; + case OPT_NEWWITHOLD: + opt_newwithold = opt_str(); + break; + case OPT_OLDWITHNEW: + opt_oldwithnew = opt_str(); + break; case OPT_V_CASES: if (!opt_verify(o, vpm)) @@ -2727,6 +2772,15 @@ static int get_opts(int argc, char **argv) case OPT_RSP_CAPUBS: opt_rsp_capubs = opt_str(); break; + case OPT_RSP_NEWWITHNEW: + opt_rsp_newwithnew = opt_str(); + break; + case OPT_RSP_NEWWITHOLD: + opt_rsp_newwithold = opt_str(); + break; + case OPT_RSP_OLDWITHNEW: + opt_rsp_oldwithnew = opt_str(); + break; case OPT_POLL_COUNT: opt_poll_count = opt_int_arg(); break; @@ -2905,6 +2959,49 @@ static int do_genm(OSSL_CMP_CTX *ctx) return 0; } return 1; + } else if (opt_infotype == NID_id_it_rootCaCert) { + X509 *oldwithold = NULL; + X509 *newwithnew = NULL; + X509 *newwithold = NULL; + X509 *oldwithnew = NULL; + int res = 0; + + if (opt_newwithnew == NULL) { + CMP_err("Missing -newwithnew option for -infotype rootCaCert"); + return 0; + } + if (opt_oldwithold == NULL) { + CMP_warn("No -oldwithold given, will use all certs given with -trusted as trust anchors for verifying the newWithNew cert"); + } else { + oldwithold = load_cert_pwd(opt_oldwithold, opt_otherpass, + "OldWithOld cert for genm with -infotype rootCaCert"); + if (oldwithold == NULL) + goto end_upd; + } + if (!OSSL_CMP_get1_rootCaKeyUpdate(ctx, oldwithold, &newwithnew, + &newwithold, &oldwithnew)) + goto end_upd; + /* At this point might check authorization of response sender/origin */ + + if (newwithnew == NULL) + CMP_info("no root CA certificate update available"); + else if (oldwithold == NULL && oldwithnew != NULL) + CMP_warn("oldWithNew certificate received in genp for verifying oldWithOld, but oldWithOld was not provided"); + + if (save_cert_or_delete(newwithnew, opt_newwithnew, + "NewWithNew cert from genp") + && save_cert_or_delete(newwithold, opt_newwithold, + "NewWithOld cert from genp") + && save_cert_or_delete(oldwithnew, opt_oldwithnew, + "OldWithNew cert from genp")) + res = 1; + + X509_free(newwithnew); + X509_free(newwithold); + X509_free(oldwithnew); + end_upd: + X509_free(oldwithold); + return res; } else { OSSL_CMP_ITAV *req; STACK_OF(OSSL_CMP_ITAV) *itavs; diff --git a/apps/include/cmp_mock_srv.h b/apps/include/cmp_mock_srv.h index 68a83568570..6308ab93dac 100644 --- a/apps/include/cmp_mock_srv.h +++ b/apps/include/cmp_mock_srv.h @@ -26,6 +26,9 @@ int ossl_cmp_mock_srv_set1_chainOut(OSSL_CMP_SRV_CTX *srv_ctx, STACK_OF(X509) *chain); int ossl_cmp_mock_srv_set1_caPubsOut(OSSL_CMP_SRV_CTX *srv_ctx, STACK_OF(X509) *caPubs); +int ossl_cmp_mock_srv_set1_newWithNew(OSSL_CMP_SRV_CTX *srv_ctx, X509 *cert); +int ossl_cmp_mock_srv_set1_newWithOld(OSSL_CMP_SRV_CTX *srv_ctx, X509 *cert); +int ossl_cmp_mock_srv_set1_oldWithNew(OSSL_CMP_SRV_CTX *srv_ctx, X509 *cert); int ossl_cmp_mock_srv_set_statusInfo(OSSL_CMP_SRV_CTX *srv_ctx, int status, int fail_info, const char *text); int ossl_cmp_mock_srv_set_sendError(OSSL_CMP_SRV_CTX *srv_ctx, int bodytype); diff --git a/apps/lib/cmp_mock_srv.c b/apps/lib/cmp_mock_srv.c index e4c30e4438b..f0ef2317db8 100644 --- a/apps/lib/cmp_mock_srv.c +++ b/apps/lib/cmp_mock_srv.c @@ -22,6 +22,9 @@ typedef struct 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; /* used in caPubs of ip and in caCerts of genp */ + X509 *newWithNew; /* to return in newWithNew of rootKeyUpdate */ + X509 *newWithOld; /* to return in newWithOld of rootKeyUpdate */ + X509 *oldWithNew; /* to return in oldWithNew of rootKeyUpdate */ 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 */ @@ -63,37 +66,26 @@ static mock_srv_ctx *mock_srv_ctx_new(void) return NULL; } -int ossl_cmp_mock_srv_set1_refCert(OSSL_CMP_SRV_CTX *srv_ctx, X509 *cert) -{ - mock_srv_ctx *ctx = OSSL_CMP_SRV_CTX_get0_custom_ctx(srv_ctx); - - if (ctx == NULL) { - ERR_raise(ERR_LIB_CMP, CMP_R_NULL_ARGUMENT); - return 0; - } - if (cert == NULL || X509_up_ref(cert)) { - X509_free(ctx->refCert); - ctx->refCert = cert; - return 1; +#define DEFINE_OSSL_SET1_CERT(FIELD) \ + int ossl_cmp_mock_srv_set1_##FIELD(OSSL_CMP_SRV_CTX *srv_ctx, \ + X509 *cert) \ + { \ + mock_srv_ctx *ctx = OSSL_CMP_SRV_CTX_get0_custom_ctx(srv_ctx); \ + \ + if (ctx == NULL) { \ + ERR_raise(ERR_LIB_CMP, CMP_R_NULL_ARGUMENT); \ + return 0; \ + } \ + if (cert == NULL || X509_up_ref(cert)) { \ + X509_free(ctx->FIELD); \ + ctx->FIELD = cert; \ + return 1; \ + } \ + return 0; \ } - return 0; -} -int ossl_cmp_mock_srv_set1_certOut(OSSL_CMP_SRV_CTX *srv_ctx, X509 *cert) -{ - mock_srv_ctx *ctx = OSSL_CMP_SRV_CTX_get0_custom_ctx(srv_ctx); - - if (ctx == NULL) { - ERR_raise(ERR_LIB_CMP, CMP_R_NULL_ARGUMENT); - return 0; - } - if (cert == NULL || X509_up_ref(cert)) { - X509_free(ctx->certOut); - ctx->certOut = cert; - return 1; - } - return 0; -} +DEFINE_OSSL_SET1_CERT(refCert) +DEFINE_OSSL_SET1_CERT(certOut) int ossl_cmp_mock_srv_set1_chainOut(OSSL_CMP_SRV_CTX *srv_ctx, STACK_OF(X509) *chain) @@ -129,6 +121,10 @@ int ossl_cmp_mock_srv_set1_caPubsOut(OSSL_CMP_SRV_CTX *srv_ctx, return 1; } +DEFINE_OSSL_SET1_CERT(newWithNew) +DEFINE_OSSL_SET1_CERT(newWithOld) +DEFINE_OSSL_SET1_CERT(oldWithNew) + int ossl_cmp_mock_srv_set_statusInfo(OSSL_CMP_SRV_CTX *srv_ctx, int status, int fail_info, const char *text) { @@ -212,6 +208,7 @@ static OSSL_CMP_PKISI *process_cert_request(OSSL_CMP_SRV_CTX *srv_ctx, STACK_OF(X509) **caPubs) { mock_srv_ctx *ctx = OSSL_CMP_SRV_CTX_get0_custom_ctx(srv_ctx); + int bodytype; OSSL_CMP_PKISI *si = NULL; if (ctx == NULL || cert_req == NULL @@ -219,8 +216,8 @@ static OSSL_CMP_PKISI *process_cert_request(OSSL_CMP_SRV_CTX *srv_ctx, ERR_raise(ERR_LIB_CMP, CMP_R_NULL_ARGUMENT); return NULL; } - if (ctx->sendError == 1 - || ctx->sendError == OSSL_CMP_MSG_get_bodytype(cert_req)) { + bodytype = OSSL_CMP_MSG_get_bodytype(cert_req); + if (ctx->sendError == 1 || ctx->sendError == bodytype) { ERR_raise(ERR_LIB_CMP, CMP_R_ERROR_PROCESSING_MESSAGE); return NULL; } @@ -245,7 +242,7 @@ static OSSL_CMP_PKISI *process_cert_request(OSSL_CMP_SRV_CTX *srv_ctx, ctx->curr_pollCount = 0; /* accept cert update request only for the reference cert, if given */ - if (OSSL_CMP_MSG_get_bodytype(cert_req) == OSSL_CMP_KUR + if (bodytype == OSSL_CMP_KUR && crm != NULL /* thus not p10cr */ && ctx->refCert != NULL) { const OSSL_CRMF_CERTID *cid = OSSL_CRMF_MSG_get0_regCtrl_oldCertID(crm); @@ -268,7 +265,7 @@ static OSSL_CMP_PKISI *process_cert_request(OSSL_CMP_SRV_CTX *srv_ctx, if (ctx->chainOut != NULL && (*chainOut = X509_chain_up_ref(ctx->chainOut)) == NULL) goto err; - if (ctx->caPubsOut != NULL + if (ctx->caPubsOut != NULL /* OSSL_CMP_PKIBODY_IP not visible here */ && (*caPubs = X509_chain_up_ref(ctx->caPubsOut)) == NULL) goto err; if (ctx->statusOut != NULL @@ -314,6 +311,26 @@ static OSSL_CMP_PKISI *process_rr(OSSL_CMP_SRV_CTX *srv_ctx, return OSSL_CMP_PKISI_dup(ctx->statusOut); } +static OSSL_CMP_ITAV *process_genm_itav(mock_srv_ctx *ctx, int req_nid, + const OSSL_CMP_ITAV *req) +{ + OSSL_CMP_ITAV *rsp; + + switch (req_nid) { + case NID_id_it_caCerts: + rsp = OSSL_CMP_ITAV_new_caCerts(ctx->caPubsOut); + break; + case NID_id_it_rootCaCert: + rsp = OSSL_CMP_ITAV_new_rootCaKeyUpdate(ctx->newWithNew, + ctx->newWithOld, + ctx->oldWithNew); + break; + default: + rsp = OSSL_CMP_ITAV_dup(req); + } + return rsp; +} + static int process_genm(OSSL_CMP_SRV_CTX *srv_ctx, const OSSL_CMP_MSG *genm, const STACK_OF(OSSL_CMP_ITAV) *in, @@ -335,16 +352,13 @@ static int process_genm(OSSL_CMP_SRV_CTX *srv_ctx, 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); + if ((*out = sk_OSSL_CMP_ITAV_new_reserve(NULL, 1)) == NULL) + return 0; + rsp = process_genm_itav(ctx, OBJ_obj2nid(obj), req); + if (rsp != NULL && sk_OSSL_CMP_ITAV_push(*out, rsp)) return 1; - } + sk_OSSL_CMP_ITAV_free(*out); + return 0; } *out = sk_OSSL_CMP_ITAV_deep_copy(in, OSSL_CMP_ITAV_dup, diff --git a/crypto/cmp/cmp_asn.c b/crypto/cmp/cmp_asn.c index b97c8323ff6..73bc6363e02 100644 --- a/crypto/cmp/cmp_asn.c +++ b/crypto/cmp/cmp_asn.c @@ -116,6 +116,11 @@ ASN1_ADB(OSSL_CMP_ITAV) = { ASN1_UTF8STRING)), ADB_ENTRY(NID_id_it_caCerts, ASN1_SEQUENCE_OF_OPT(OSSL_CMP_ITAV, infoValue.caCerts, X509)), + ADB_ENTRY(NID_id_it_rootCaCert, + ASN1_OPT(OSSL_CMP_ITAV, infoValue.rootCaCert, X509)), + ADB_ENTRY(NID_id_it_rootCaKeyUpdate, + ASN1_OPT(OSSL_CMP_ITAV, infoValue.rootCaKeyUpdate, + OSSL_CMP_ROOTCAKEYUPDATE)), } ASN1_ADB_END(OSSL_CMP_ITAV, 0, infoType, 0, &infotypeandvalue_default_tt, NULL); @@ -126,6 +131,14 @@ ASN1_SEQUENCE(OSSL_CMP_ITAV) = { IMPLEMENT_ASN1_FUNCTIONS(OSSL_CMP_ITAV) IMPLEMENT_ASN1_DUP_FUNCTION(OSSL_CMP_ITAV) +ASN1_SEQUENCE(OSSL_CMP_ROOTCAKEYUPDATE) = { + /* OSSL_CMP_CMPCERTIFICATE is effectively X509 so it is used directly */ + ASN1_SIMPLE(OSSL_CMP_ROOTCAKEYUPDATE, newWithNew, X509), + ASN1_EXP_OPT(OSSL_CMP_ROOTCAKEYUPDATE, newWithOld, X509, 0), + ASN1_EXP_OPT(OSSL_CMP_ROOTCAKEYUPDATE, oldWithNew, X509, 1) +} ASN1_SEQUENCE_END(OSSL_CMP_ROOTCAKEYUPDATE) +IMPLEMENT_ASN1_FUNCTIONS(OSSL_CMP_ROOTCAKEYUPDATE) + OSSL_CMP_ITAV *OSSL_CMP_ITAV_create(ASN1_OBJECT *type, ASN1_TYPE *value) { OSSL_CMP_ITAV *itav; @@ -215,6 +228,84 @@ int OSSL_CMP_ITAV_get0_caCerts(const OSSL_CMP_ITAV *itav, STACK_OF(X509) **out) return 1; } +OSSL_CMP_ITAV *OSSL_CMP_ITAV_new_rootCaCert(const X509 *rootCaCert) +{ + OSSL_CMP_ITAV *itav = OSSL_CMP_ITAV_new(); + + if (itav == NULL) + return NULL; + if (rootCaCert != NULL + && (itav->infoValue.rootCaCert = X509_dup(rootCaCert)) == NULL) { + OSSL_CMP_ITAV_free(itav); + return NULL; + } + itav->infoType = OBJ_nid2obj(NID_id_it_rootCaCert); + return itav; +} + +int OSSL_CMP_ITAV_get0_rootCaCert(const OSSL_CMP_ITAV *itav, 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_rootCaCert) { + ERR_raise(ERR_LIB_CMP, ERR_R_PASSED_INVALID_ARGUMENT); + return 0; + } + *out = itav->infoValue.rootCaCert; + return 1; +} +OSSL_CMP_ITAV *OSSL_CMP_ITAV_new_rootCaKeyUpdate(const X509 *newWithNew, + const X509 *newWithOld, + const X509 *oldWithNew) +{ + OSSL_CMP_ITAV *itav; + OSSL_CMP_ROOTCAKEYUPDATE *upd = OSSL_CMP_ROOTCAKEYUPDATE_new(); + + if (upd == NULL) + return NULL; + if (newWithNew != NULL && (upd->newWithNew = X509_dup(newWithNew)) == NULL) + goto err; + if (newWithOld != NULL && (upd->newWithOld = X509_dup(newWithOld)) == NULL) + goto err; + if (oldWithNew != NULL && (upd->oldWithNew = X509_dup(oldWithNew)) == NULL) + goto err; + if ((itav = OSSL_CMP_ITAV_new()) == NULL) + goto err; + itav->infoType = OBJ_nid2obj(NID_id_it_rootCaKeyUpdate); + itav->infoValue.rootCaKeyUpdate = upd; + return itav; + + err: + OSSL_CMP_ROOTCAKEYUPDATE_free(upd); + return NULL; +} + +int OSSL_CMP_ITAV_get0_rootCaKeyUpdate(const OSSL_CMP_ITAV *itav, + X509 **newWithNew, + X509 **newWithOld, + X509 **oldWithNew) +{ + OSSL_CMP_ROOTCAKEYUPDATE *upd; + + if (itav == NULL || newWithNew == NULL) { + ERR_raise(ERR_LIB_CMP, ERR_R_PASSED_NULL_PARAMETER); + return 0; + } + if (OBJ_obj2nid(itav->infoType) != NID_id_it_rootCaKeyUpdate) { + ERR_raise(ERR_LIB_CMP, ERR_R_PASSED_INVALID_ARGUMENT); + return 0; + } + upd = itav->infoValue.rootCaKeyUpdate; + *newWithNew = upd->newWithNew; + if (newWithOld != NULL) + *newWithOld = upd->newWithOld; + if (oldWithNew != NULL) + *oldWithNew = upd->oldWithNew; + 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 9d0e9680329..3853e526059 100644 --- a/crypto/cmp/cmp_err.c +++ b/crypto/cmp/cmp_err.c @@ -88,6 +88,8 @@ static const ERR_STRING_DATA CMP_str_reasons[] = { {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_INVALID_ROOTCAKEYUPDATE), + "invalid rootcakeyupdate"}, {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), "missing key input for creating protection"}, diff --git a/crypto/cmp/cmp_genm.c b/crypto/cmp/cmp_genm.c index 2faeaf0d282..74ac1d4b051 100644 --- a/crypto/cmp/cmp_genm.c +++ b/crypto/cmp/cmp_genm.c @@ -177,3 +177,170 @@ int OSSL_CMP_get1_caCerts(OSSL_CMP_CTX *ctx, STACK_OF(X509) **out) OSSL_CMP_ITAV_free(itav); return ret; } + +static int selfsigned_verify_cb(int ok, X509_STORE_CTX *store_ctx) +{ + if (ok == 0 && store_ctx != NULL + && X509_STORE_CTX_get_error_depth(store_ctx) == 0 + && X509_STORE_CTX_get_error(store_ctx) + == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT) { + /* in this case, custom chain building */ + int i; + STACK_OF(X509) *trust; + STACK_OF(X509) *chain = X509_STORE_CTX_get0_chain(store_ctx); + STACK_OF(X509) *untrusted = X509_STORE_CTX_get0_untrusted(store_ctx); + X509_STORE_CTX_check_issued_fn check_issued = + X509_STORE_CTX_get_check_issued(store_ctx); + X509 *cert = sk_X509_value(chain, 0); /* target cert */ + X509 *issuer; + + for (i = 0; i < sk_X509_num(untrusted); i++) { + cert = sk_X509_value(untrusted, i); + if (!X509_add_cert(chain, cert, X509_ADD_FLAG_UP_REF)) + return 0; + } + + trust = X509_STORE_get1_all_certs(X509_STORE_CTX_get0_store(store_ctx)); + for (i = 0; i < sk_X509_num(trust); i++) { + issuer = sk_X509_value(trust, i); + if ((*check_issued)(store_ctx, cert, issuer)) { + if (X509_add_cert(chain, cert, X509_ADD_FLAG_UP_REF)) + ok = 1; + break; + } + } + sk_X509_pop_free(trust, X509_free); + return ok; + } else { + X509_STORE *ts = X509_STORE_CTX_get0_store(store_ctx); + X509_STORE_CTX_verify_cb verify_cb; + + if (ts == NULL || (verify_cb = X509_STORE_get_verify_cb(ts)) == NULL) + return ok; + return (*verify_cb)(ok, store_ctx); + } +} + +/* vanilla X509_verify_cert() does not support self-signed certs as target */ +static int verify_ss_cert(OSSL_LIB_CTX *libctx, const char *propq, + X509_STORE *ts, STACK_OF(X509) *untrusted, + X509 *target) +{ + X509_STORE_CTX *csc = NULL; + int ok = 0; + + if (ts == NULL || target == NULL) { + ERR_raise(ERR_LIB_CMP, ERR_R_PASSED_NULL_PARAMETER); + return 0; + } + + if ((csc = X509_STORE_CTX_new_ex(libctx, propq)) == NULL + || !X509_STORE_CTX_init(csc, ts, target, untrusted)) + goto err; + X509_STORE_CTX_set_verify_cb(csc, selfsigned_verify_cb); + ok = X509_verify_cert(csc) > 0; + + err: + X509_STORE_CTX_free(csc); + return ok; +} + +static int +verify_ss_cert_trans(OSSL_CMP_CTX *ctx, X509 *trusted /* may be NULL */, + X509 *trans /* the only untrusted cert, may be NULL */, + X509 *target, const char *desc) +{ + X509_STORE *ts = OSSL_CMP_CTX_get0_trusted(ctx); + STACK_OF(X509) *untrusted = NULL; + int res = 0; + + if (trusted != NULL) { + X509_VERIFY_PARAM *vpm = X509_STORE_get0_param(ts); + + if ((ts = X509_STORE_new()) == NULL) + return 0; + if (!X509_STORE_set1_param(ts, vpm) + || !X509_STORE_add_cert(ts, trusted)) + goto err; + } + + if (trans != NULL + && !ossl_x509_add_cert_new(&untrusted, trans, X509_ADD_FLAG_UP_REF)) + goto err; + + res = verify_ss_cert(OSSL_CMP_CTX_get0_libctx(ctx), + OSSL_CMP_CTX_get0_propq(ctx), + ts, untrusted, target); + if (!res) + ERR_raise_data(ERR_LIB_CMP, CMP_R_INVALID_ROOTCAKEYUPDATE, + "failed to validate %s certificate received in genp %s", + desc, trusted == NULL ? "using trust store" + : "with given certificate as trust anchor"); + + err: + sk_X509_pop_free(untrusted, X509_free); + if (trusted != NULL) + X509_STORE_free(ts); + return res; +} + +int OSSL_CMP_get1_rootCaKeyUpdate(OSSL_CMP_CTX *ctx, + const X509 *oldWithOld, X509 **newWithNew, + X509 **newWithOld, X509 **oldWithNew) +{ + X509 *oldWithOld_copy = NULL, *my_newWithOld, *my_oldWithNew; + OSSL_CMP_ITAV *req, *itav; + int res = 0; + + if (newWithNew == NULL) { + ERR_raise(ERR_LIB_CMP, ERR_R_PASSED_NULL_PARAMETER); + return 0; + } + *newWithNew = NULL; + + if ((req = OSSL_CMP_ITAV_new_rootCaCert(oldWithOld)) == NULL) + return 0; + itav = get_genm_itav(ctx, req, NID_id_it_rootCaKeyUpdate, "rootCaKeyUpdate"); + if (itav == NULL) + return 0; + + if (!OSSL_CMP_ITAV_get0_rootCaKeyUpdate(itav, newWithNew, + &my_newWithOld, &my_oldWithNew)) + goto end; + + if (*newWithNew == NULL) /* no root CA cert update available */ + goto end; + if ((oldWithOld_copy = X509_dup(oldWithOld)) == NULL && oldWithOld != NULL) + goto end; + if (!verify_ss_cert_trans(ctx, oldWithOld_copy, my_newWithOld, + *newWithNew, "newWithNew")) { + ERR_raise(ERR_LIB_CMP, CMP_R_INVALID_ROOTCAKEYUPDATE); + goto end; + } + if (oldWithOld != NULL && my_oldWithNew != NULL + && !verify_ss_cert_trans(ctx, *newWithNew, my_oldWithNew, + oldWithOld_copy, "oldWithOld")) { + ERR_raise(ERR_LIB_CMP, CMP_R_INVALID_ROOTCAKEYUPDATE); + goto end; + } + + if (!X509_up_ref(*newWithNew)) + goto end; + if (newWithOld != NULL && + (*newWithOld = my_newWithOld) != NULL && !X509_up_ref(*newWithOld)) + goto free; + if (oldWithNew == NULL || + (*oldWithNew = my_oldWithNew) == NULL || X509_up_ref(*oldWithNew)) { + res = 1; + goto end; + } + if (newWithOld != NULL) + X509_free(*newWithOld); + free: + X509_free(*newWithNew); + + end: + OSSL_CMP_ITAV_free(itav); + X509_free(oldWithOld_copy); + return res; +} diff --git a/crypto/cmp/cmp_local.h b/crypto/cmp/cmp_local.h index 18401ddb607..d1035c2da96 100644 --- a/crypto/cmp/cmp_local.h +++ b/crypto/cmp/cmp_local.h @@ -205,6 +205,9 @@ typedef struct ossl_cmp_cakeyupdanncontent_st { } OSSL_CMP_CAKEYUPDANNCONTENT; DECLARE_ASN1_FUNCTIONS(OSSL_CMP_CAKEYUPDANNCONTENT) +typedef struct ossl_cmp_rootcakeyupdate_st OSSL_CMP_ROOTCAKEYUPDATE; +DECLARE_ASN1_FUNCTIONS(OSSL_CMP_ROOTCAKEYUPDATE) + /*- * declared already here as it will be used in OSSL_CMP_MSG (nested) and * infoType and infoValue @@ -252,6 +255,10 @@ struct ossl_cmp_itav_st { STACK_OF(ASN1_UTF8STRING) *suppLangTagsValue; /* NID_id_it_caCerts - CA Certificates */ STACK_OF(X509) *caCerts; + /* NID_id_it_rootCaCert - Root CA Certificate */ + X509 *rootCaCert; + /* NID_id_it_rootCaKeyUpdate - Root CA Certificate Update */ + OSSL_CMP_ROOTCAKEYUPDATE *rootCaKeyUpdate; /* this is to be used for so far undeclared objects */ ASN1_TYPE *other; } infoValue; @@ -738,6 +745,21 @@ DECLARE_ASN1_FUNCTIONS(OSSL_CMP_PROTECTEDPART) * } */ +/* + * RootCaKeyUpdateContent ::= SEQUENCE { + * newWithNew CMPCertificate, + * newWithOld [0] CMPCertificate OPTIONAL, + * oldWithNew [1] CMPCertificate OPTIONAL + * } + */ + +struct ossl_cmp_rootcakeyupdate_st { + X509 *newWithNew; + X509 *newWithOld; + X509 *oldWithNew; +} /* OSSL_CMP_ROOTCAKEYUPDATE */; +DECLARE_ASN1_FUNCTIONS(OSSL_CMP_ROOTCAKEYUPDATE) + /* from cmp_asn.c */ int ossl_cmp_asn1_get_int(const ASN1_INTEGER *a); diff --git a/crypto/err/openssl.txt b/crypto/err/openssl.txt index cbb32969428..4b86dac5572 100644 --- a/crypto/err/openssl.txt +++ b/crypto/err/openssl.txt @@ -235,6 +235,7 @@ 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_INVALID_ROOTCAKEYUPDATE:195:invalid rootcakeyupdate CMP_R_MISSING_CERTID:165:missing certid CMP_R_MISSING_KEY_INPUT_FOR_CREATING_PROTECTION:130:\ missing key input for creating protection diff --git a/doc/internal/man3/ossl_cmp_mock_srv_new.pod b/doc/internal/man3/ossl_cmp_mock_srv_new.pod index 59568c65fcf..1789fad2754 100644 --- a/doc/internal/man3/ossl_cmp_mock_srv_new.pod +++ b/doc/internal/man3/ossl_cmp_mock_srv_new.pod @@ -8,6 +8,9 @@ ossl_cmp_mock_srv_set1_refCert, ossl_cmp_mock_srv_set1_certOut, ossl_cmp_mock_srv_set1_chainOut, ossl_cmp_mock_srv_set1_caPubsOut, +ossl_cmp_mock_srv_set1_newWithNew, +ossl_cmp_mock_srv_set1_newWithOld, +ossl_cmp_mock_srv_set1_oldWithNew, ossl_cmp_mock_srv_set_statusInfo, ossl_cmp_mock_srv_set_sendError, ossl_cmp_mock_srv_set_pollCount, @@ -21,12 +24,15 @@ ossl_cmp_mock_srv_set_checkAfterTime OSSL_CMP_SRV_CTX *ossl_cmp_mock_srv_new(OSSL_LIB_CTX *libctx, const char *propq); void ossl_cmp_mock_srv_free(OSSL_CMP_SRV_CTX *srv_ctx); - int ossl_cmp_mock_srv_set1_refCert(OSSL_CMP_SRV_CTX *srv_ctx, X509 *cert); - int ossl_cmp_mock_srv_set1_certOut(OSSL_CMP_SRV_CTX *srv_ctx, X509 *cert); + int ossl_cmp_mock_srv_set1_refCert(OSSL_CMP_SRV_CTX *ctx, const X509 *cert); + int ossl_cmp_mock_srv_set1_certOut(OSSL_CMP_SRV_CTX *ctx, const X509 *cert); int ossl_cmp_mock_srv_set1_chainOut(OSSL_CMP_SRV_CTX *srv_ctx, - STACK_OF(X509) *chain); + const STACK_OF(X509) *chain); int ossl_cmp_mock_srv_set1_caPubsOut(OSSL_CMP_SRV_CTX *srv_ctx, - STACK_OF(X509) *caPubs); + const STACK_OF(X509) *caPubs); + int ossl_cmp_mock_srv_set1_newWithNew(OSSL_CMP_SRV_CTX *ctx, const X509 *cert); + int ossl_cmp_mock_srv_set1_newWithOld(OSSL_CMP_SRV_CTX *ctx, const X509 *cert); + int ossl_cmp_mock_srv_set1_oldWithNew(OSSL_CMP_SRV_CTX *ctx, const X509 *cert); int ossl_cmp_mock_srv_set_statusInfo(OSSL_CMP_SRV_CTX *srv_ctx, int status, int fail_info, const char *text); int ossl_cmp_mock_srv_set_sendError(OSSL_CMP_SRV_CTX *srv_ctx, int bodytype); @@ -41,21 +47,30 @@ I, both of which may be NULL to select the defaults. ossl_cmp_mock_srv_free() deallocates the contexts for the CMP mock server. -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_refCert() sets the reference certificate (or NULL) +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 messages. +ossl_cmp_mock_srv_set1_certOut() sets the certificate (or NULL) +to be returned in 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 message. +ossl_cmp_mock_srv_set1_chainOut() sets the certificate chain (or NULL) +to be added to 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 msg -and the list of certificates to be returned in a genp of infoType caCerts. +ossl_cmp_mock_srv_set1_caPubsOut() sets list of certificates (or NULL) to be +returned in the caPubs field an ip message and in a genp of infoType caCerts. + +ossl_cmp_mock_srv_set1_newWithNew() sets the value (which may be NULL) +of the newWithNew field to be returned in a genp of infoType rootCaKeyUpdate. + +ossl_cmp_mock_srv_set1_newWithOld() sets the value (which may be NULL) +of the newWithOld field to be returned in a genp of infoType rootCaKeyUpdate. + +ossl_cmp_mock_srv_set1_oldWithNew() sets the value (which may be NULL) +of the oldWithNew field to be returned in a genp of infoType rootCaKeyUpdate. 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 4d077175537..7c68385f4b7 100644 --- a/doc/man1/openssl-cmp.pod.in +++ b/doc/man1/openssl-cmp.pod.in @@ -68,6 +68,10 @@ Server authentication options: [B<-srvcertout> I] [B<-extracertsout> I] [B<-cacertsout> I] +[B<-oldwithold> I] +[B<-newwithnew> I] +[B<-newwithold> I] +[B<-oldwithnew> I] Client authentication and protection options: @@ -129,6 +133,9 @@ Mock server options: [B<-rsp_cert> I|I] [B<-rsp_extracerts> I|I] [B<-rsp_capubs> I|I] +[B<-rsp_newwithnew> I|I] +[B<-rsp_newwithold> I|I] +[B<-rsp_oldwithnew> I|I] [B<-poll_count> I] [B<-check_after> I] [B<-grant_implicitconf>] @@ -237,7 +244,7 @@ ITAV Bs is printed to stdout. Set InfoType name to use for requesting specific info in B, e.g., C. -So far, there is specific support for C. +So far, there is specific support for C and C. =item B<-geninfo> I @@ -669,6 +676,43 @@ 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 or contained in a general response (genp) message with infoType C. +=item B<-oldwithold> I + +The root CA certificate to include in a genm request of infoType C. +If present and the optional oldWithNew certificate is received, +it is verified using the newWithNew certificate as the (only) trust anchor. + +=item B<-newwithnew> I + +This option must be provided when B<-infotype> I is given. +It specifies the file to save the newWithNew certificate +received in a genp message of type C. +If on success no such cert was received, this file (if present) is deleted +to indicate that the requested root CA certificate update is not available. + +Any received newWithNew certificate is verified +using any received newWithOld certificate as untrusted intermediate certificate +and the certificate provided with B<-oldwithold> as the (only) trust anchor, +or if not provided, using the certificates given with the B<-trusted> option. + +B +The newWithNew certificate is meant to be a certificate that will be trusted. +The trust placed in it cannot be stronger than the trust placed in +the B<-oldwithold> certificate if present, otherwise it cannot be stronger than +the weakest trust placed in any of the B<-trusted> certificates. + +=item B<-newwithold> I + +The file to save any newWithOld certificate +received in a genp message of infoType C. +If on success no such cert was received, this is indicated by deleting the file. + +=item B<-oldwithnew> I + +The file to save any oldWithNew certificate +received in a genp message of infoType C. +If on success no such cert was received, this is indicated by deleting the file. + =back =head2 Client authentication options @@ -803,7 +847,9 @@ See L for details. Pass phrase source for certificate given with the B<-trusted>, B<-untrusted>, B<-own_trusted>, B<-srvcert>, B<-out_trusted>, B<-extracerts>, -B<-srv_trusted>, B<-srv_untrusted>, B<-rsp_extracerts>, B<-rsp_capubs>, +B<-srv_trusted>, B<-srv_untrusted>, B<-ref_cert>, B<-rsp_cert>, +B<-rsp_extracerts>, B<-rsp_capubs>, +B<-rsp_newwithnew>, B<-rsp_newwithold>, B<-rsp_oldwithnew>, B<-tls_extra>, and B<-tls_trusted> options. If not given here, the password will be prompted for if needed. @@ -1054,6 +1100,18 @@ Extra certificates to be included in mock certification responses. CA certificates to be included in mock Initialization Response (IP) message. +=item B<-rsp_newwithnew> I|I + +Certificate to be returned in newWithNew field of genp of type rootCaKeyUpdate. + +=item B<-rsp_newwithold> I|I + +Certificate to be returned in newWithOld field of genp of type rootCaKeyUpdate. + +=item B<-rsp_oldwithnew> I|I + +Certificate to be returned in oldWithNew field of genp of type rootCaKeyUpdate. + =item B<-poll_count> I Number of times the client must poll before receiving a certificate. @@ -1127,9 +1185,9 @@ only affect the certificate verification enabled via the B<-out_trusted> option. =head1 NOTES -When a client obtains from a CMP server CA certificates that it is going to +When a client obtains, from a CMP server, CA certificates that it is going to trust, for instance via the C field of a certificate response -or using general messages with infoType C, +or using general messages with infoType C or C, authentication of the CMP server is particularly critical. So special care must be taken setting up server authentication using B<-trusted> and related options for certificate-based authentication diff --git a/doc/man3/OSSL_CMP_ITAV_new_caCerts.pod b/doc/man3/OSSL_CMP_ITAV_new_caCerts.pod index eb397388aa6..882103f4c3b 100644 --- a/doc/man3/OSSL_CMP_ITAV_new_caCerts.pod +++ b/doc/man3/OSSL_CMP_ITAV_new_caCerts.pod @@ -3,7 +3,11 @@ =head1 NAME OSSL_CMP_ITAV_new_caCerts, -OSSL_CMP_ITAV_get0_caCerts +OSSL_CMP_ITAV_get0_caCerts, +OSSL_CMP_ITAV_new_rootCaCert, +OSSL_CMP_ITAV_get0_rootCaCert, +OSSL_CMP_ITAV_new_rootCaKeyUpdate, +OSSL_CMP_ITAV_get0_rootCaKeyUpdate - CMP utility functions for handling specific genm and genp messages =head1 SYNOPSIS @@ -13,6 +17,16 @@ OSSL_CMP_ITAV_get0_caCerts 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); + OSSL_CMP_ITAV *OSSL_CMP_ITAV_new_rootCaCert(const X509 *rootCaCert); + int OSSL_CMP_ITAV_get0_rootCaCert(const OSSL_CMP_ITAV *itav, X509 **out); + OSSL_CMP_ITAV *OSSL_CMP_ITAV_new_rootCaKeyUpdate(const X509 *newWithNew, + const X509 *newWithOld, + const X509 *oldWithNew); + int OSSL_CMP_ITAV_get0_rootCaKeyUpdate(const OSSL_CMP_ITAV *itav, + X509 **newWithNew, + X509 **newWithOld, + X509 **oldWithNew); + =head1 DESCRIPTION ITAV is short for InfoTypeAndValue. @@ -25,17 +39,41 @@ OSSL_CMP_ITAV_get0_caCerts() requires that I has type B. It assigns NULL to I<*out> if there are no CA certificates in I, otherwise the internal pointer of type B with the certificates present. +OSSL_CMP_ITAV_new_rootCaCert() creates a new B structure +of type B that includes the optionally given certificate. + +OSSL_CMP_ITAV_get0_rootCaCert() requires that I has type B. +It assigns NULL to I<*out> if no certificate is included in I, otherwise +the internal pointer to the certificate contained in the infoValue field. + +OSSL_CMP_ITAV_new_rootCaKeyUpdate() creates a new B structure +of type B that includes an RootCaKeyUpdateContent structure +with the optional I, I, and I certificates. + +OSSL_CMP_ITAV_get0_rootCaKeyUpdate() requires that I has infoType +B. +If an update of a root CA certificate is included, +it assigns to I<*newWithNew> the internal pointer +to the certificate contained in the newWithNew infoValue sub-field of I. +If I is not NULL, it assigns to I<*newWithOld> the internal pointer +to the certificate contained in the newWithOld infoValue sub-field of I. +If I is not NULL, it assigns to I<*oldWithNew> the internal pointer +to the certificate contained in the oldWithNew infoValue sub-field of I. +Each of these pointers will be NULL if the respective sub-field is not set. + =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_new_caCerts(), +OSSL_CMP_ITAV_new_rootCaCert(), and OSSL_CMP_ITAV_new_rootCaKeyUpdate() +return 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. +OSSL_CMP_ITAV_get0_caCerts(), +OSSL_CMP_ITAV_get0_rootCaCert(), and OSSL_CMP_ITAV_get0_rootCaKeyUpdate() +return 1 on success, 0 on error. =head1 SEE ALSO @@ -43,8 +81,9 @@ L and L =head1 HISTORY -OSSL_CMP_ITAV_new_caCerts() and -OSSL_CMP_ITAV_get0_rootCaCert() +OSSL_CMP_ITAV_new_caCerts(), OSSL_CMP_ITAV_get0_caCerts(), +OSSL_CMP_ITAV_new_rootCaCert(), OSSL_CMP_ITAV_get0_rootCaCert(), +OSSL_CMP_ITAV_new_rootCaKeyUpdate(), and OSSL_CMP_ITAV_get0_rootCaKeyUpdate() were added in OpenSSL 3.2. =head1 COPYRIGHT diff --git a/doc/man3/OSSL_CMP_exec_certreq.pod b/doc/man3/OSSL_CMP_exec_certreq.pod index fbf118c2b16..e752b8e2706 100644 --- a/doc/man3/OSSL_CMP_exec_certreq.pod +++ b/doc/man3/OSSL_CMP_exec_certreq.pod @@ -14,7 +14,8 @@ OSSL_CMP_KUR, OSSL_CMP_try_certreq, OSSL_CMP_exec_RR_ses, OSSL_CMP_exec_GENM_ses, -OSSL_CMP_get1_caCerts +OSSL_CMP_get1_caCerts, +OSSL_CMP_get1_rootCaKeyUpdate - functions implementing CMP client transactions =head1 SYNOPSIS @@ -37,6 +38,9 @@ OSSL_CMP_get1_caCerts STACK_OF(OSSL_CMP_ITAV) *OSSL_CMP_exec_GENM_ses(OSSL_CMP_CTX *ctx); int OSSL_CMP_get1_caCerts(OSSL_CMP_CTX *ctx, STACK_OF(X509) **out); + int OSSL_CMP_get1_rootCaKeyUpdate(OSSL_CMP_CTX *ctx, + const X509 *oldWithOld, X509 **newWithNew, + X509 **newWithOld, X509 **oldWithNew); =head1 DESCRIPTION @@ -132,6 +136,23 @@ On success it assigns to I<*out> the list of certificates received, which must be freed by the caller. NULL output means that no CA certificates were provided by the server. +OSSL_CMP_get1_rootCaKeyUpdate() uses a genm request message +with infoType rootCaCert to obtain from the CMP server referenced by I +in a genp response message with infoType rootCaKeyUpdate any update of the +given root CA certificate I and verifies it as far as possible. +See RFC 4210 section 4.4 for details. +On success it assigns to I<*newWithNew> the root certificate received. +When the I and I output parameters are not NULL, +it assigns to them the corresponding transition certificates. +NULL means that the respective certificate was not provided by the server. +All certificates obtained this way must be freed by the caller. + +B +The I certificate is meant to be a certificate that will be trusted. +The trust placed in it cannot be stronger than the trust placed in +the I certificate if present, otherwise it cannot be stronger than +the weakest trust in any of the certificates in the trust store of I. + =head1 NOTES CMP is defined in RFC 4210 (and CRMF in RFC 4211). @@ -140,8 +161,8 @@ The CMP client implementation is limited to one request per CMP message (and consequently to at most one response component per CMP message). When a client obtains from a CMP server CA certificates that it is going to -trust, for instance via the caPubs field of a certificate response -or using functions like OSSL_CMP_get1_caCerts(), +trust, for instance via the caPubs field of a certificate response or using +functions like OSSL_CMP_get1_caCerts() and OSSL_CMP_get1_rootCaKeyUpdate(), authentication of the CMP server is particularly critical. So special care must be taken setting up server authentication in I using functions such as @@ -167,7 +188,8 @@ In the latter case L yields NULL and the output parameter I has been used to assign the received value unless I is NULL. -OSSL_CMP_exec_RR_ses() and OSSL_CMP_get1_caCerts() +OSSL_CMP_exec_RR_ses(), OSSL_CMP_get1_caCerts(), +and OSSL_CMP_get1_rootCaKeyUpdate() return 1 on success, 0 on error. OSSL_CMP_exec_GENM_ses() returns NULL on error, @@ -191,7 +213,8 @@ L The OpenSSL CMP support was added in OpenSSL 3.0. -OSSL_CMP_get1_caCerts() was added in OpenSSL 3.2. +OSSL_CMP_get1_caCerts() and OSSL_CMP_get1_rootCaKeyUpdate() +were added in OpenSSL 3.2. =head1 COPYRIGHT diff --git a/include/openssl/cmp.h.in b/include/openssl/cmp.h.in index 0e49ee9d519..d7f2354b3a9 100644 --- a/include/openssl/cmp.h.in +++ b/include/openssl/cmp.h.in @@ -264,6 +264,16 @@ 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); +OSSL_CMP_ITAV *OSSL_CMP_ITAV_new_rootCaCert(const X509 *rootCaCert); +int OSSL_CMP_ITAV_get0_rootCaCert(const OSSL_CMP_ITAV *itav, X509 **out); +OSSL_CMP_ITAV *OSSL_CMP_ITAV_new_rootCaKeyUpdate(const X509 *newWithNew, + const X509 *newWithOld, + const X509 *oldWithNew); +int OSSL_CMP_ITAV_get0_rootCaKeyUpdate(const OSSL_CMP_ITAV *itav, + X509 **newWithNew, + X509 **newWithOld, + X509 **oldWithNew); + void OSSL_CMP_MSG_free(OSSL_CMP_MSG *msg); /* from cmp_ctx.c */ @@ -488,6 +498,9 @@ STACK_OF(OSSL_CMP_ITAV) *OSSL_CMP_exec_GENM_ses(OSSL_CMP_CTX *ctx); /* from cmp_genm.c */ int OSSL_CMP_get1_caCerts(OSSL_CMP_CTX *ctx, STACK_OF(X509) **out); +int OSSL_CMP_get1_rootCaKeyUpdate(OSSL_CMP_CTX *ctx, + const X509 *oldWithOld, X509 **newWithNew, + X509 **newWithOld, X509 **oldWithNew); # ifdef __cplusplus } diff --git a/include/openssl/cmperr.h b/include/openssl/cmperr.h index f4435d825d0..57a6effbe3f 100644 --- a/include/openssl/cmperr.h +++ b/include/openssl/cmperr.h @@ -63,6 +63,7 @@ # define CMP_R_INVALID_ARGS 100 # define CMP_R_INVALID_GENP 193 # define CMP_R_INVALID_OPTION 174 +# define CMP_R_INVALID_ROOTCAKEYUPDATE 195 # define CMP_R_MISSING_CERTID 165 # define CMP_R_MISSING_KEY_INPUT_FOR_CREATING_PROTECTION 130 # define CMP_R_MISSING_KEY_USAGE_DIGITALSIGNATURE 142 diff --git a/test/recipes/80-test_cmp_http.t b/test/recipes/80-test_cmp_http.t index 4fd03e8b2d9..2695c0f28f3 100644 --- a/test/recipes/80-test_cmp_http.t +++ b/test/recipes/80-test_cmp_http.t @@ -26,8 +26,8 @@ plan skip_all => "These tests are not supported in a fuzz build" plan skip_all => "These tests are not supported in a no-cmp build" if disabled("cmp"); -plan skip_all => "These tests are not supported in a no-ec build" - if disabled("ec"); +plan skip_all => "These tests are not supported in a no-ecx build" + if disabled("ecx"); # EC and EDDSA test certs, e.g., in Mock/newWithNew.pem plan skip_all => "These tests are not supported in a no-sock build" if disabled("sock"); plan skip_all => "These tests are not supported in a no-http build" diff --git a/test/recipes/80-test_cmp_http_data/Mock/newWithNew.pem b/test/recipes/80-test_cmp_http_data/Mock/newWithNew.pem new file mode 100644 index 00000000000..1a02d1997f3 --- /dev/null +++ b/test/recipes/80-test_cmp_http_data/Mock/newWithNew.pem @@ -0,0 +1,11 @@ +-----BEGIN PRIVATE KEY----- +MC4CAQAwBQYDK2VwBCIEINTuctv5E1hK1bbY8fdp+K06/nwoy/HU++CXqI9EdVhC +-----END PRIVATE KEY----- +-----BEGIN CERTIFICATE----- +MIIBAzCBtqADAgECAgH+MAUGAytlcDASMRAwDgYDVQQDDAdSb290IENBMCAXDTIz +MDYwNTIwMjMwMFoYDzIxMjMwNjA1MjAyMzAwWjASMRAwDgYDVQQDDAdSb290IENB +MCowBQYDK2VwAyEAGb9ECWmEzf6FQbrBZ9w7lshQhqowtrbLDFw4rXAxZuGjLzAt +MAwGA1UdEwQFMAMBAf8wHQYDVR0OBBYEFKKMwfhuWWDT4DrnXJYsl6jUSCk8MAUG +AytlcANBAEG62N+3Go9h1ekWyQMf1hYFQMPQF/XVP2EH1euP7mVxJt0mquGpVsm+ +qLt/W4xBKiu08Jfcv4Gxi6CjgOekGww= +-----END CERTIFICATE----- diff --git a/test/recipes/80-test_cmp_http_data/Mock/newWithOld.pem b/test/recipes/80-test_cmp_http_data/Mock/newWithOld.pem new file mode 100644 index 00000000000..988496cd350 --- /dev/null +++ b/test/recipes/80-test_cmp_http_data/Mock/newWithOld.pem @@ -0,0 +1,13 @@ +-----BEGIN CERTIFICATE----- +MIICCTCB8qADAgECAhR+y2i70DQe9ryvJ8uPJO8qOMfX+zANBgkqhkiG9w0BAQsF +ADASMRAwDgYDVQQDDAdSb290IENBMCAXDTIzMDYwNTIwMjg1N1oYDzIxMjMwNjA1 +MjAyODU3WjASMRAwDgYDVQQDDAdSb290IENBMCowBQYDK2VwAyEAGb9ECWmEzf6F +QbrBZ9w7lshQhqowtrbLDFw4rXAxZuGjUDBOMAwGA1UdEwQFMAMBAf8wHQYDVR0O +BBYEFKKMwfhuWWDT4DrnXJYsl6jUSCk8MB8GA1UdIwQYMBaAFHB/Lq6DaFmYBCMq +zes+F80k3QFJMA0GCSqGSIb3DQEBCwUAA4IBAQB6Eg6lRxiUUXMGO8l7XYJ3d49x +YDqwt+fvaQcnwVN3kJ1GAb/0lcB6k4mt8jHizT2HKw1ZMHK7CGbHYAMKvtxML3px +GXqeEQO2IlWU23kEyPhX/yoOG0cp9QWm4tdTvr3xCr4E4rNZJUNbSqyOCdcAs39H +4dDBHBQrL530/XquKdXmq4fAwyKIGxNW1WTohKq9Yzd3NK+0Ku11Ny86FIzB3iks +a8NdsE88xfBQcQMo9omZZbPQBg7YMId4zRyDFplrLWZjhoNmStmTHTX/nOYUMGm3 +75iikSsNRJl4A/ZvnZrDA2am3ihvMghVIN4IVfXrk5tHiZ/XHZuu3vetK2jp +-----END CERTIFICATE----- diff --git a/test/recipes/80-test_cmp_http_data/Mock/oldWithNew.pem b/test/recipes/80-test_cmp_http_data/Mock/oldWithNew.pem new file mode 100644 index 00000000000..8fa15f89998 --- /dev/null +++ b/test/recipes/80-test_cmp_http_data/Mock/oldWithNew.pem @@ -0,0 +1,14 @@ +-----BEGIN CERTIFICATE----- +MIICMjCCAeSgAwIBAgIUcaAacl/D9rcbM5ytumMvdL3J+HIwBQYDK2VwMBIxEDAO +BgNVBAMMB1Jvb3QgQ0EwIBcNMjMwNjA1MjAyOTI0WhgPMjEyMzA2MDUyMDI5MjRa +MBIxEDAOBgNVBAMMB1Jvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK +AoIBAQC/mhXWzc26ztIg2Duia7kDG54SAr3uaHk9TeGBmmWJIVoRKYvaosZ4/rT2 +hez/rxcNdVbi61QsI6MuHSen7lfLeLcZENeAFnvZAN7bdaqpCqpoGVBVWbVbEb5q +ZG1kkRZ1IiyIUG2T7x0ESUeHZZAOEM5aocYdBqtCAk/EYH3sxGExKVtPArVPkoBY +6WqLmYlbkvq82tDtOtr9hx4fvR9TR8lg5eEHEz3Y3APVttV30Y9gVKqt2tWPX1u+ +jrdezFl257HlAetGRapPnDmaAAdoSAKpatL/rir1NH1QTCsHySJlmDeT3+Kb7MHA +RQtNm7SvygwSSmNtOVcua3wQwGrHAgMBAAGjUDBOMAwGA1UdEwQFMAMBAf8wHQYD +VR0OBBYEFHB/Lq6DaFmYBCMqzes+F80k3QFJMB8GA1UdIwQYMBaAFKKMwfhuWWDT +4DrnXJYsl6jUSCk8MAUGAytlcANBAHFKIp57/EisMF84ZvOFzxnS2o8/qKsRrrh5 +w1nBOmOvavZxbtFyO9batLEWikNV0LDFIHw9g3uYmgB1VUzhcw4= +-----END CERTIFICATE----- diff --git a/test/recipes/80-test_cmp_http_data/Mock/oldWithOld.pem b/test/recipes/80-test_cmp_http_data/Mock/oldWithOld.pem new file mode 100644 index 00000000000..7c6db11c445 --- /dev/null +++ b/test/recipes/80-test_cmp_http_data/Mock/oldWithOld.pem @@ -0,0 +1,46 @@ +-----BEGIN PRIVATE KEY----- +MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQC/mhXWzc26ztIg +2Duia7kDG54SAr3uaHk9TeGBmmWJIVoRKYvaosZ4/rT2hez/rxcNdVbi61QsI6Mu +HSen7lfLeLcZENeAFnvZAN7bdaqpCqpoGVBVWbVbEb5qZG1kkRZ1IiyIUG2T7x0E +SUeHZZAOEM5aocYdBqtCAk/EYH3sxGExKVtPArVPkoBY6WqLmYlbkvq82tDtOtr9 +hx4fvR9TR8lg5eEHEz3Y3APVttV30Y9gVKqt2tWPX1u+jrdezFl257HlAetGRapP +nDmaAAdoSAKpatL/rir1NH1QTCsHySJlmDeT3+Kb7MHARQtNm7SvygwSSmNtOVcu +a3wQwGrHAgMBAAECggEBAL4rWle8JuCuHGNbGz1nO9d41tg7fnYdnZAaN6OiMfr8 +bl+wY84aV3GKJOS2InfYOcIy340UU5QHvxOq/kwwRVV/uAOZ8rqAFmZY9djOnhdv +rZjq3xAHnPgJ0XvZt7XkR2z1AUw+v7Pf1WYGsYcSZ/t99MKB5Je0odA/aRqZRwLy +YflbsnAJtxdJ6fsiVCSJcU76V8sxfiCimw6ppLMEp3zCjveQ5Lv0eVoL2zNYeh+l +GiSwqTqaR+WJekkDiXRd9KYI19drf7OkTII1DtOd6bgvKX3zv2lNiere4J4k7cAP +rW6fBFgtSq2oklTpWUlXRH7XQAgDtDvldXdlKaj96dkCgYEA8KPSu5ywg8pjCofE +nLtJTfVyD2g9tgNLj9dI3kuSniZU51kOtk5rZZwL0S8piGczL908aV9DIWdXWsND +5hlXquKUTSjxPYEzZvaN+tvf9e0AcY/D/UaK0mKPjEbh7vg6pS77aZZz2EL2inOs +dam8famOOC9RUkxH5JWa3UV4UhsCgYEAy9T0wPQctjuvDkZQTqKEKsHrmrgY2PXT +Re8DDGI8hxjYb8l+NoFQ7eiwTHir/DULupxQoBBUQtS+idQzUu02tzLMnGcjHNwh +Tu+vZ4xlVnXxfgIRjDKkfQjiAC5SLzoNO9Jn8g4eS/1mEPXhQ0TXIsFonZDypp/n +RMp21DkvdMUCgYAIMgwjR5rbYjEtUqJnlBlTBmD0FWDEqigQpgxdRcWgjT2nA2l0 +3AbcVwwv+6M2eg1MPASqsgvfP13CQZQ2afaKY10Zo6NTrOrLPupm+MYP4hp5w6Ox +JI3lzGWHKYLYWKvmpEr7tZwMaXtsC7R77WP2A6hMUZA7dU2dg1ra3lrSsQKBgQDA +sPIsUtmtwOBtqzUSEXrGfQqA+larDEGNVDVaiKfVwzwg+aeyWS+rqRS5Rj64L2GG +KW3i020EvN/fplZap9vY9lIN7UZ5avSmDdqRFl1ajiccy1HRarKrbTFRoHibItMN +4YvYfVZQ2h2aHQe2Myb6OULv6e4qbPIRyyDo4aKmTQKBgQCadq2JfICFIP9Q1aQn +93oD7Z4WcYs+KsLYO+/uJxWMrn0/gv90cGrSfstJqDOHnRq4WKUcgK9ErxaE4LkW +sD0mBhRM3SMxnRJZRO+6roRdehtjHkvzKu75KjcsuwefoMs2sFa4CLQ1YU2vO3Tx +dgzpnKS2bH/i5yLwhelRfddZ6Q== +-----END PRIVATE KEY----- +-----BEGIN CERTIFICATE----- +MIIC8TCCAdmgAwIBAgIBATANBgkqhkiG9w0BAQsFADASMRAwDgYDVQQDDAdSb290 +IENBMCAXDTE2MDExNDIyMjkwNVoYDzIxMTYwMTE1MjIyOTA1WjASMRAwDgYDVQQD +DAdSb290IENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv5oV1s3N +us7SINg7omu5AxueEgK97mh5PU3hgZpliSFaESmL2qLGeP609oXs/68XDXVW4utU +LCOjLh0np+5Xy3i3GRDXgBZ72QDe23WqqQqqaBlQVVm1WxG+amRtZJEWdSIsiFBt +k+8dBElHh2WQDhDOWqHGHQarQgJPxGB97MRhMSlbTwK1T5KAWOlqi5mJW5L6vNrQ +7Tra/YceH70fU0fJYOXhBxM92NwD1bbVd9GPYFSqrdrVj19bvo63XsxZduex5QHr +RkWqT5w5mgAHaEgCqWrS/64q9TR9UEwrB8kiZZg3k9/im+zBwEULTZu0r8oMEkpj +bTlXLmt8EMBqxwIDAQABo1AwTjAdBgNVHQ4EFgQUcH8uroNoWZgEIyrN6z4XzSTd +AUkwHwYDVR0jBBgwFoAUcH8uroNoWZgEIyrN6z4XzSTdAUkwDAYDVR0TBAUwAwEB +/zANBgkqhkiG9w0BAQsFAAOCAQEAuiLq2lhcOJHrwUP0txbHk2vy6rmGTPxqmcCo +CUQFZ3KrvUQM+rtRqqQ0+LzU4wSTFogBz9KSMfT03gPegY3b/7L2TOaMmUFRzTdd +c9PNT0lP8V3pNQrxp0IjKir791QkGe2Ux45iMKf/SXpeTWASp4zeMiD6/LXFzzaK +BfNS5IrIWRDev41lFasDzudK5/kmVaMvDOFyW51KkKkqb64VS4UA81JIEzClvz+3 +Vp3k1AXup5+XnTvhqu2nRhrLpJR5w8OXQpcn6qjKlVc2BXtb3xwci1/ibHlZy3CZ +n70e2NYihU5yYKccReP+fjLgVFsuhsDs/0hRML1u9bLp9nUbYA== +-----END CERTIFICATE----- diff --git a/test/recipes/80-test_cmp_http_data/Mock/server.cnf b/test/recipes/80-test_cmp_http_data/Mock/server.cnf index 991c1cf525f..04b612cde2d 100644 --- a/test/recipes/80-test_cmp_http_data/Mock/server.cnf +++ b/test/recipes/80-test_cmp_http_data/Mock/server.cnf @@ -11,7 +11,11 @@ srv_trusted = signer_root.crt ref_cert = signer_only.crt rsp_cert = signer_only.crt -rsp_capubs = signer_root.crt +rsp_capubs = trusted.crt rsp_extracerts = signer_issuing.crt +rsp_newwithnew = newWithNew.pem +rsp_newwithold = newWithOld.pem +rsp_oldwithnew = oldWithNew.pem + verbosity = 7 diff --git a/test/recipes/80-test_cmp_http_data/test_commands.csv b/test/recipes/80-test_cmp_http_data/test_commands.csv index dc2e922aaaf..5ab2ca3fd7a 100644 --- a/test/recipes/80-test_cmp_http_data/test_commands.csv +++ b/test/recipes/80-test_cmp_http_data/test_commands.csv @@ -56,8 +56,26 @@ expected,description, -section,val, -cmd,val,val2, -cacertsout,val,val2, -infoty 0,genm with missing infotype value, -section,, -cmd,genm,,BLANK,,, -infotype,,,BLANK,,BLANK, 0,genm with invalid infotype value, -section,, -cmd,genm,,BLANK,,, -infotype,asdf,,BLANK,,BLANK, 1,genm with infotype signKeyPairTypes, -section,, -cmd,genm,,BLANK,,, -infotype,signKeyPairTypes,,BLANK,,BLANK, -0,genm with infotype caCerts but missing -cacertsout, -section,, -cmd,genm,,BLANK,,, -infotype,caCerts,,BLANK,,BLANK, -1,genm with infotype caCerts, -section,, -cmd,genm,, -cacertsout,_RESULT_DIR/test.cacerts.pem,, -infotype,caCerts,,BLANK,,BLANK, +,,,,,,,,,,,,,,,,,,,,,, +1,genm caCerts , -section,, -cmd,genm,, -cacertsout,_RESULT_DIR/test.cacerts.pem,, -infotype,caCerts,,BLANK,,BLANK, +0,genm caCerts missing cacertsout option , -section,, -cmd,genm,, BLANK , ,, -infotype,caCerts,,BLANK,,BLANK, +0,genm caCerts missing cacertsout arg , -section,, -cmd,genm,, -cacertsout,BLANK ,, -infotype,caCerts,,BLANK,,BLANK, +0,genm caCerts extra cacertsout arg , -section,, -cmd,genm,, -cacertsout,_RESULT_DIR/test.cacerts.pem,_RESULT_DIR/test.cacerts.pem, -infotype,caCerts,,BLANK,,BLANK, +,,,,,,,,,,,,,,,,,,,,,, +1,genm rootCaCert with oldwithold , -section,, -cmd,genm,, BLANK,,, -infotype,rootCaCert,, -oldwithold, oldWithOld.pem, -newwithnew, _RESULT_DIR/test.newwithnew0.pem +1,genm rootCaCert without oldwithold , -section,, -cmd,genm,, BLANK,,, -infotype,rootCaCert,, BLANK , , -newwithnew, _RESULT_DIR/test.newwithnew.pem +0,genm rootCaCert oldwithold missing arg , -section,, -cmd,genm,, BLANK,,, -infotype,rootCaCert,, -oldwithold, , -newwithnew, _RESULT_DIR/test.newwithnew.pem +0,genm rootCaCert oldwithold empty file , -section,, -cmd,genm,, BLANK,,, -infotype,rootCaCert,, -oldwithold, empty.txt , -newwithnew, _RESULT_DIR/test.newwithnew.pem +0,genm rootCaCert oldwithold random file , -section,, -cmd,genm,, BLANK,,, -infotype,rootCaCert,, -oldwithold, random.bin , -newwithnew, _RESULT_DIR/test.newwithnew.pem +0,genm rootCaCert oldwithold nonexistent , -section,, -cmd,genm,, BLANK,,, -infotype,rootCaCert,, -oldwithold, idontexist , -newwithnew, _RESULT_DIR/test.newwithnew.pem +0,genm rootCaCert oldwithold wrong , -section,, -cmd,genm,, BLANK,,, -infotype,rootCaCert,, -oldwithold, signer.crt , -newwithnew, _RESULT_DIR/test.newwithnew.pem +0,genm rootCaCert missing newwithnew , -section,, -cmd,genm,, BLANK,,, -infotype,rootCaCert,, -oldwithold, oldWithOld.pem, BLANK ,, +0,genm rootCaCert newwithnew missing arg , -section,, -cmd,genm,, BLANK,,, -infotype,rootCaCert,, -oldwithold, oldWithOld.pem, -newwithnew,, +1,genm rootCaCert with oldwithnew , -section,, -cmd,genm,, BLANK,,, -infotype,rootCaCert,, -oldwithold, oldWithOld.pem, -newwithnew, _RESULT_DIR/test.newwithnew1.pem, -oldwithnew, _RESULT_DIR/test.oldwithnew1.pem +0,genm rootCaCert oldwithnew missing arg , -section,, -cmd,genm,, BLANK,,, -infotype,rootCaCert,, -oldwithold, oldWithOld.pem, -newwithnew, _RESULT_DIR/test.newwithnew.pem, -oldwithnew,, +1,genm rootCaCert newwithnew oldwithnew newwithold , -section,, -cmd,genm,, BLANK,,, -infotype,rootCaCert,, -oldwithold, oldWithOld.pem, -newwithnew, _RESULT_DIR/test.newwithnew2.pem, -oldwithnew, _RESULT_DIR/test.oldwithnew2.pem, -newwithold, _RESULT_DIR/test.newwithold1.pem +0,genm rootCaCert newwithold missig arg , -section,, -cmd,genm,, BLANK,,, -infotype,rootCaCert,, -oldwithold, oldWithOld.pem, -newwithnew, _RESULT_DIR/test.newwithnew.pem, -oldwithnew, _RESULT_DIR/test.oldwithnew.pem, -newwithold,, +1,genm rootCaCert newwithnew newwithold , -section,, -cmd,genm,, BLANK,,, -infotype,rootCaCert,, -oldwithold, oldWithOld.pem, -newwithnew, _RESULT_DIR/test.newwithnew3.pem, -newwithold, _RESULT_DIR/test.newwithold2.pem ,,,,,,,,,,,,,,,,,,,,,, 1,geninfo, -section,, -cmd,cr,, -cert,signer.crt, -key,signer.p12, -keypass,pass:12345,BLANK,, -geninfo,1.2.3:int:987,BLANK,,BLANK, 0,geninfo missing argument, -section,, -cmd,cr,, -cert,signer.crt, -key,signer.p12, -keypass,pass:12345,BLANK,, -geninfo,,,,, diff --git a/util/libcrypto.num b/util/libcrypto.num index 24947c673f0..9871821a6f6 100644 --- a/util/libcrypto.num +++ b/util/libcrypto.num @@ -5448,6 +5448,11 @@ BIO_ADDR_dup ? 3_2_0 EXIST::FUNCTION:SOCK OSSL_CMP_ITAV_new_caCerts ? 3_2_0 EXIST::FUNCTION:CMP OSSL_CMP_ITAV_get0_caCerts ? 3_2_0 EXIST::FUNCTION:CMP OSSL_CMP_get1_caCerts ? 3_2_0 EXIST::FUNCTION:CMP +OSSL_CMP_ITAV_new_rootCaCert ? 3_2_0 EXIST::FUNCTION:CMP +OSSL_CMP_ITAV_get0_rootCaCert ? 3_2_0 EXIST::FUNCTION:CMP +OSSL_CMP_ITAV_new_rootCaKeyUpdate ? 3_2_0 EXIST::FUNCTION:CMP +OSSL_CMP_ITAV_get0_rootCaKeyUpdate ? 3_2_0 EXIST::FUNCTION:CMP +OSSL_CMP_get1_rootCaKeyUpdate ? 3_2_0 EXIST::FUNCTION:CMP OSSL_CMP_CTX_get0_libctx ? 3_2_0 EXIST::FUNCTION:CMP OSSL_CMP_CTX_get0_propq ? 3_2_0 EXIST::FUNCTION:CMP OSSL_CMP_CTX_reset_geninfo_ITAVs ? 3_0_8 EXIST::FUNCTION:CMP