diff options
author | Dr. David von Oheimb <David.von.Oheimb@siemens.com> | 2022-09-17 10:56:21 +0200 |
---|---|---|
committer | Pauli <pauli@openssl.org> | 2023-07-17 08:48:36 +1000 |
commit | 01b048513153bdbee3efc82389d38d353352a7f1 (patch) | |
tree | f22d8f0a44aeb740bc8a7ab837605f82dc10d8f3 /apps/cmp.c | |
parent | 1a9e28607e29a1dc996024f03f445ca67b49a44f (diff) |
CMP: add support for genm with rootCaCert and genp with rootCaKeyUpdate
Reviewed-by: Tomas Mraz <tomas@openssl.org>
Reviewed-by: Paul Dale <pauli@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/21129)
Diffstat (limited to 'apps/cmp.c')
-rw-r--r-- | apps/cmp.c | 211 |
1 files changed, 154 insertions, 57 deletions
diff --git a/apps/cmp.c b/apps/cmp.c index d56a5e451c..dbc609a2e0 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; |