summaryrefslogtreecommitdiffstats
path: root/apps/cmp.c
diff options
context:
space:
mode:
authorDr. David von Oheimb <David.von.Oheimb@siemens.com>2022-09-17 10:56:21 +0200
committerPauli <pauli@openssl.org>2023-07-17 08:48:36 +1000
commit01b048513153bdbee3efc82389d38d353352a7f1 (patch)
treef22d8f0a44aeb740bc8a7ab837605f82dc10d8f3 /apps/cmp.c
parent1a9e28607e29a1dc996024f03f445ca67b49a44f (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.c211
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;