summaryrefslogtreecommitdiffstats
path: root/apps/cmp.c
diff options
context:
space:
mode:
authorDr. David von Oheimb <David.von.Oheimb@siemens.com>2022-12-03 17:49:08 +0100
committerTomas Mraz <tomas@openssl.org>2024-05-01 14:58:35 +0200
commit40a200f9e781381d72d234c886e38bcfce36bbc8 (patch)
tree229fdb094d3a05485c504e66da8934a9d585648a /apps/cmp.c
parentFix intermittent sslapitest early data related failures (diff)
downloadopenssl-40a200f9e781381d72d234c886e38bcfce36bbc8.tar.xz
openssl-40a200f9e781381d72d234c886e38bcfce36bbc8.zip
CMP: add support for genm with crlStatusList and genp with crls
Introduce the capability to retrieve and update Certificate Revocation Lists (CRLs) in the CMP client, as specified in section 4.3.4 of RFC 9483. To request a CRL update, the CMP client can send a genm message with the option -infotype crlStatusList. The server will respond with a genp message containing the updated CRL, using the -infoType id-it-crls. The client can then save the CRL in a specified file using the -crlout parameter. Co-authored-by: Rajeev Ranjan <ranjan.rajeev@siemens.com> Reviewed-by: Todd Short <todd.short@me.com> Reviewed-by: Tomas Mraz <tomas@openssl.org> (Merged from https://github.com/openssl/openssl/pull/23768)
Diffstat (limited to 'apps/cmp.c')
-rw-r--r--apps/cmp.c163
1 files changed, 159 insertions, 4 deletions
diff --git a/apps/cmp.c b/apps/cmp.c
index 213596f723..407ee5ec32 100644
--- a/apps/cmp.c
+++ b/apps/cmp.c
@@ -94,6 +94,9 @@ static char *opt_oldwithold = NULL;
static char *opt_newwithnew = NULL;
static char *opt_newwithold = NULL;
static char *opt_oldwithnew = NULL;
+static char *opt_crlcert = NULL;
+static char *opt_oldcrl = NULL;
+static char *opt_crlout = NULL;
/* client authentication */
static char *opt_ref = NULL;
@@ -143,6 +146,8 @@ static int opt_revreason = CRL_REASON_NONE;
/* credentials format */
static char *opt_certform_s = "PEM";
static int opt_certform = FORMAT_PEM;
+static char *opt_crlform_s = "DER";
+static int opt_crlform = FORMAT_ASN1;
static char *opt_keyform_s = NULL;
static int opt_keyform = FORMAT_UNDEF;
static char *opt_otherpass = NULL;
@@ -187,6 +192,7 @@ static char *opt_srv_trusted = NULL;
static char *opt_srv_untrusted = NULL;
static char *opt_ref_cert = NULL;
static char *opt_rsp_cert = NULL;
+static char *opt_rsp_crl = NULL;
static char *opt_rsp_extracerts = NULL;
static char *opt_rsp_capubs = NULL;
static char *opt_rsp_newwithnew = NULL;
@@ -237,12 +243,13 @@ typedef enum OPTION_choice {
OPT_IGNORE_KEYUSAGE, OPT_UNPROTECTED_ERRORS, OPT_NO_CACHE_EXTRACERTS,
OPT_SRVCERTOUT, OPT_EXTRACERTSOUT, OPT_CACERTSOUT,
OPT_OLDWITHOLD, OPT_NEWWITHNEW, OPT_NEWWITHOLD, OPT_OLDWITHNEW,
+ OPT_CRLCERT, OPT_OLDCRL, OPT_CRLOUT,
OPT_REF, OPT_SECRET, OPT_CERT, OPT_OWN_TRUSTED, OPT_KEY, OPT_KEYPASS,
OPT_DIGEST, OPT_MAC, OPT_EXTRACERTS,
OPT_UNPROTECTED_REQUESTS,
- OPT_CERTFORM, OPT_KEYFORM,
+ OPT_CERTFORM, OPT_CRLFORM, OPT_KEYFORM,
OPT_OTHERPASS,
#ifndef OPENSSL_NO_ENGINE
OPT_ENGINE,
@@ -267,7 +274,7 @@ typedef enum OPTION_choice {
OPT_SRV_REF, OPT_SRV_SECRET,
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_REF_CERT, OPT_RSP_CERT, OPT_RSP_CRL, OPT_RSP_EXTRACERTS, OPT_RSP_CAPUBS,
OPT_RSP_NEWWITHNEW, OPT_RSP_NEWWITHOLD, OPT_RSP_OLDWITHNEW,
OPT_POLL_COUNT, OPT_CHECK_AFTER,
OPT_GRANT_IMPLICITCONF,
@@ -428,6 +435,12 @@ const OPTIONS cmp_options[] = {
"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"},
+ { "crlcert", OPT_CRLCERT, 's',
+ "certificate to request a CRL for in genm of type crlStatusList"},
+ { "oldcrl", OPT_OLDCRL, 's',
+ "CRL to request update for in genm of type crlStatusList"},
+ { "crlout", OPT_CRLOUT, 's',
+ "File to save new CRL received in genp of type 'crls'"},
OPT_SECTION("Client authentication"),
{"ref", OPT_REF, 's',
@@ -459,6 +472,8 @@ const OPTIONS cmp_options[] = {
OPT_SECTION("Credentials format"),
{"certform", OPT_CERTFORM, 's',
"Format (PEM or DER) to use when saving a certificate to a file. Default PEM"},
+ {"crlform", OPT_CRLFORM, 's',
+ "Format (PEM or DER) to use when saving a CRL to a file. Default DER"},
{"keyform", OPT_KEYFORM, 's',
"Format of the key input (ENGINE, other values ignored)"},
{"otherpass", OPT_OTHERPASS, 's',
@@ -544,6 +559,8 @@ const OPTIONS cmp_options[] = {
"Certificate to be expected for rr and any oldCertID in kur messages"},
{"rsp_cert", OPT_RSP_CERT, 's',
"Certificate to be returned as mock enrollment result"},
+ {"rsp_crl", OPT_RSP_CRL, 's',
+ "CRL to be returned in genp of type crls"},
{"rsp_extracerts", OPT_RSP_EXTRACERTS, 's',
"Extra certificates to be included in mock certification responses"},
{"rsp_capubs", OPT_RSP_CAPUBS, 's',
@@ -623,13 +640,14 @@ static varref cmp_vars[] = { /* must be in same order as enumerated above! */
{(char **)&opt_no_cache_extracerts},
{&opt_srvcertout}, {&opt_extracertsout}, {&opt_cacertsout},
{&opt_oldwithold}, {&opt_newwithnew}, {&opt_newwithold}, {&opt_oldwithnew},
+ {&opt_crlcert}, {&opt_oldcrl}, {&opt_crlout},
{&opt_ref}, {&opt_secret},
{&opt_cert}, {&opt_own_trusted}, {&opt_key}, {&opt_keypass},
{&opt_digest}, {&opt_mac}, {&opt_extracerts},
{(char **)&opt_unprotected_requests},
- {&opt_certform_s}, {&opt_keyform_s},
+ {&opt_certform_s}, {&opt_crlform_s}, {&opt_keyform_s},
{&opt_otherpass},
#ifndef OPENSSL_NO_ENGINE
{&opt_engine},
@@ -652,7 +670,8 @@ static varref cmp_vars[] = { /* must be in same order as enumerated above! */
{&opt_srv_ref}, {&opt_srv_secret},
{&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_ref_cert}, {&opt_rsp_cert}, {&opt_rsp_crl},
+ {&opt_rsp_extracerts}, {&opt_rsp_capubs},
{&opt_rsp_newwithnew}, {&opt_rsp_newwithold}, {&opt_rsp_oldwithnew},
{(char **)&opt_poll_count}, {(char **)&opt_check_after},
@@ -1010,6 +1029,19 @@ static int setup_certs(char *files, const char *desc, void *ctx,
return ok;
}
+static int setup_mock_crlout(void *ctx, const char *file, const char *desc)
+{
+ X509_CRL *crl;
+ int ok;
+
+ if (file == NULL)
+ return 1;
+ if ((crl = load_crl(file, FORMAT_UNDEF, 0, desc)) == NULL)
+ return 0;
+ ok = ossl_cmp_mock_srv_set1_crlOut(ctx, crl);
+ X509_CRL_free(crl);
+ return ok;
+}
/*
* parse and transform some options, checking their syntax.
* Returns 1 on success, 0 on error
@@ -1057,6 +1089,11 @@ static int transform_opts(void)
CMP_err("unknown option given for certificate storing format");
return 0;
}
+ if (opt_crlform_s != NULL
+ && !opt_format(opt_crlform_s, OPT_FMT_PEMDER, &opt_crlform)) {
+ CMP_err("unknown option given for CRL storing format");
+ return 0;
+ }
return 1;
}
@@ -1152,6 +1189,9 @@ static OSSL_CMP_SRV_CTX *setup_srv_ctx(ENGINE *engine)
(add_X509_fn_t)ossl_cmp_mock_srv_set1_certOut))
goto err;
}
+ if (!setup_mock_crlout(srv_ctx, opt_rsp_crl,
+ "CRL to be returned by the mock server"))
+ goto err;
if (!setup_certs(opt_rsp_extracerts,
"CMP extra certificates for mock server", srv_ctx,
(add_X509_stack_fn_t)ossl_cmp_mock_srv_set1_chainOut))
@@ -2248,6 +2288,18 @@ static int write_cert(BIO *bio, X509 *cert)
return 0;
}
+static int write_crl(BIO *bio, X509_CRL *crl)
+{
+ if (opt_crlform != FORMAT_PEM && opt_crlform != FORMAT_ASN1) {
+ BIO_printf(bio_err, "error: unsupported type '%s' for writing CRLs\n",
+ opt_crlform_s);
+ return 0;
+ }
+
+ return opt_crlform == FORMAT_PEM ? PEM_write_bio_X509_CRL(bio, crl)
+ : i2d_X509_CRL_bio(bio, crl);
+}
+
/*
* If file != NULL writes out a stack of certs to the given file.
* If certs is NULL, the file is emptied.
@@ -2295,6 +2347,35 @@ static int save_free_certs(STACK_OF(X509) *certs,
return n;
}
+static int save_crl(X509_CRL *crl,
+ const char *file, const char *desc)
+{
+ BIO *bio = NULL;
+ int res = 0;
+
+ if (file == NULL)
+ return 1;
+ if (crl != NULL)
+ CMP_info2("received %s, saving to file '%s'", desc, file);
+
+ if ((bio = BIO_new(BIO_s_file())) == NULL
+ || !BIO_write_filename(bio, (char *)file)) {
+ CMP_err2("could not open file '%s' for writing %s",
+ file, desc);
+ goto end;
+ }
+
+ if (!write_crl(bio, crl)) {
+ CMP_err2("cannot write %s to file '%s'", desc, file);
+ goto end;
+ }
+ res = 1;
+
+ end:
+ BIO_free(bio);
+ return res;
+}
+
static int delete_file(const char *file, const char *desc)
{
if (file == NULL)
@@ -2328,6 +2409,13 @@ static int save_cert_or_delete(X509 *cert, const char *file, const char *desc)
}
}
+static int save_crl_or_delete(X509_CRL *crl, const char *file, const char *desc)
+{
+ if (file == NULL)
+ return 1;
+ return (crl == NULL) ? delete_file(file, desc) : save_crl(crl, file, desc);
+}
+
static int print_itavs(const STACK_OF(OSSL_CMP_ITAV) *itavs)
{
int i, ret = 1;
@@ -2727,6 +2815,15 @@ static int get_opts(int argc, char **argv)
case OPT_OLDWITHNEW:
opt_oldwithnew = opt_str();
break;
+ case OPT_CRLCERT:
+ opt_crlcert = opt_str();
+ break;
+ case OPT_OLDCRL:
+ opt_oldcrl = opt_str();
+ break;
+ case OPT_CRLOUT:
+ opt_crlout = opt_str();
+ break;
case OPT_V_CASES:
if (!opt_verify(o, vpm))
@@ -2822,6 +2919,9 @@ static int get_opts(int argc, char **argv)
case OPT_CERTFORM:
opt_certform_s = opt_str();
break;
+ case OPT_CRLFORM:
+ opt_crlform_s = opt_str();
+ break;
case OPT_KEYFORM:
opt_keyform_s = opt_str();
break;
@@ -2905,6 +3005,9 @@ static int get_opts(int argc, char **argv)
case OPT_RSP_CERT:
opt_rsp_cert = opt_str();
break;
+ case OPT_RSP_CRL:
+ opt_rsp_crl = opt_str();
+ break;
case OPT_RSP_EXTRACERTS:
opt_rsp_extracerts = opt_str();
break;
@@ -3141,6 +3244,58 @@ static int do_genm(OSSL_CMP_CTX *ctx)
end_upd:
X509_free(oldwithold);
return res;
+ } else if (opt_infotype == NID_id_it_crlStatusList) {
+ X509_CRL *oldcrl = NULL, *crl = NULL;
+ X509 *crlcert = NULL;
+ int res = 0;
+ const char *desc = "CRL from genp of type 'crls'";
+
+ if (opt_oldcrl == NULL && opt_crlcert == NULL) {
+ CMP_err("Missing -oldcrl and no -crlcert given for -infotype crlStatusList");
+ return 0;
+ }
+ if (opt_crlout == NULL) {
+ CMP_err("Missing -crlout for -infotype crlStatusList");
+ return 0;
+ }
+
+ if (opt_crlcert != NULL) {
+ crlcert = load_cert_pwd(opt_crlcert, opt_otherpass,
+ "Cert for genm with -infotype crlStatusList");
+ if (crlcert == NULL)
+ goto end_crlupd;
+ }
+
+ if (opt_oldcrl != NULL) {
+ oldcrl = load_crl(opt_oldcrl, FORMAT_UNDEF, 0,
+ "CRL for genm with -infotype crlStatusList");
+ if (oldcrl == NULL)
+ goto end_crlupd;
+ }
+
+ if (opt_oldcrl != NULL && opt_crlcert != NULL) {
+ if (X509_NAME_cmp(X509_CRL_get_issuer(oldcrl),
+ X509_get_issuer_name(crlcert))
+ != 0)
+ CMP_warn("-oldcrl and -crlcert have different issuer");
+ }
+
+ if (!OSSL_CMP_get1_crlUpdate(ctx, crlcert, oldcrl, &crl))
+ goto end_crlupd;
+
+ if (crl == NULL)
+ CMP_info("no CRL update available");
+ if (!save_crl_or_delete(crl, opt_crlout, desc))
+ goto end_crlupd;
+
+ res = 1;
+
+ end_crlupd:
+ X509_free(crlcert);
+ X509_CRL_free(oldcrl);
+ X509_CRL_free(crl);
+ return res;
+
} else {
OSSL_CMP_ITAV *req;
STACK_OF(OSSL_CMP_ITAV) *itavs;