/*
- * Copyright 2007-2019 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 2007-2020 The OpenSSL Project Authors. All Rights Reserved.
* Copyright Nokia 2007-2019
* Copyright Siemens AG 2015-2019
*
DEFINE_STACK_OF(X509_EXTENSION)
DEFINE_STACK_OF(OSSL_CMP_ITAV)
-/* start TODO remove when PR #11755 is merged */
-static char *get_passwd(const char *pass, const char *desc)
-{
- char *result = NULL;
-
- app_passwd(pass, NULL, &result, NULL);
- return result;
-}
-
-static void cleanse(char *str)
-{
- if (str != NULL)
- OPENSSL_cleanse(str, strlen(str));
-}
-
-static void clear_free(char *str)
-{
- if (str != NULL)
- OPENSSL_clear_free(str, strlen(str));
-}
-
-static int load_key_cert_crl(const char *uri, int maybe_stdin,
- const char *pass, const char *desc,
- EVP_PKEY **ppkey, X509 **pcert, X509_CRL **pcrl)
-{
- PW_CB_DATA uidata;
- OSSL_STORE_CTX *ctx = NULL;
- int ret = 0;
-
- if (ppkey != NULL)
- *ppkey = NULL;
- if (pcert != NULL)
- *pcert = NULL;
- if (pcrl != NULL)
- *pcrl = NULL;
-
- uidata.password = pass;
- uidata.prompt_info = uri;
-
- ctx = OSSL_STORE_open(uri, get_ui_method(), &uidata, NULL, NULL);
- if (ctx == NULL) {
- BIO_printf(bio_err, "Could not open file or uri %s for loading %s\n",
- uri, desc);
- goto end;
- }
-
- for (;;) {
- OSSL_STORE_INFO *info = OSSL_STORE_load(ctx);
- int type = info == NULL ? 0 : OSSL_STORE_INFO_get_type(info);
- const char *infostr =
- info == NULL ? NULL : OSSL_STORE_INFO_type_string(type);
- int err = 0;
-
- if (info == NULL) {
- if (OSSL_STORE_eof(ctx))
- ret = 1;
- break;
- }
-
- switch (type) {
- case OSSL_STORE_INFO_PKEY:
- if (ppkey != NULL && *ppkey == NULL)
- err = ((*ppkey = OSSL_STORE_INFO_get1_PKEY(info)) == NULL);
- break;
- case OSSL_STORE_INFO_CERT:
- if (pcert != NULL && *pcert == NULL)
- err = ((*pcert = OSSL_STORE_INFO_get1_CERT(info)) == NULL);
- break;
- case OSSL_STORE_INFO_CRL:
- if (pcrl != NULL && *pcrl == NULL)
- err = ((*pcrl = OSSL_STORE_INFO_get1_CRL(info)) == NULL);
- break;
- default:
- /* skip any other type */
- break;
- }
- OSSL_STORE_INFO_free(info);
- if (err) {
- BIO_printf(bio_err, "Could not read %s of %s from %s\n",
- infostr, desc, uri);
- break;
- }
- }
-
- end:
- if (ctx != NULL)
- OSSL_STORE_close(ctx);
- if (!ret)
- ERR_print_errors(bio_err);
- return ret;
-}
-
-static
-EVP_PKEY *load_key_preliminary(const char *uri, int format, int may_stdin,
- const char *pass, ENGINE *e, const char *desc)
-{
- EVP_PKEY *pkey = NULL;
-
- if (desc == NULL)
- desc = "private key";
-
- if (format == FORMAT_ENGINE) {
- if (e == NULL) {
- BIO_printf(bio_err, "No engine specified for loading %s\n", desc);
- } else {
-#ifndef OPENSSL_NO_ENGINE
- PW_CB_DATA cb_data;
-
- cb_data.password = pass;
- cb_data.prompt_info = uri;
- if (ENGINE_init(e)) {
- pkey = ENGINE_load_private_key(e, uri,
- (UI_METHOD *)get_ui_method(),
- &cb_data);
- ENGINE_finish(e);
- }
- if (pkey == NULL) {
- BIO_printf(bio_err, "Cannot load %s from engine\n", desc);
- ERR_print_errors(bio_err);
- }
-#else
- BIO_printf(bio_err, "Engines not supported for loading %s\n", desc);
-#endif
- }
- } else {
- (void)load_key_cert_crl(uri, may_stdin, pass, desc, &pkey, NULL, NULL);
- }
-
- if (pkey == NULL) {
- BIO_printf(bio_err, "Unable to load %s\n", desc);
- ERR_print_errors(bio_err);
- }
- return pkey;
-}
-
-static X509 *load_cert_pass(const char *uri, int maybe_stdin,
- const char *pass, const char *desc)
-{
- X509 *cert = NULL;
-
- if (desc == NULL)
- desc = "certificate";
- (void)load_key_cert_crl(uri, maybe_stdin, pass, desc, NULL, &cert, NULL);
- if (cert == NULL) {
- BIO_printf(bio_err, "Unable to load %s\n", desc);
- ERR_print_errors(bio_err);
- }
- return cert;
-}
-/* end TODO remove when PR #11755 is merged */
-
static char *opt_config = NULL;
#define CMP_SECTION "cmp"
#define SECTION_NAME_MAX 40 /* max length of section name */
static CONF *conf = NULL; /* OpenSSL config file context structure */
static OSSL_CMP_CTX *cmp_ctx = NULL; /* the client-side CMP context */
-/* TODO remove when new setup_engine_flags() is in apps/lib/apps.c (PR #4277) */
-static
-ENGINE *setup_engine_flags(const char *engine, unsigned int flags, int debug)
-{
- return setup_engine(engine, debug);
-}
-
/* the type of cmp command we want to send */
typedef enum {
CMP_IR,
static int opt_batch = 0;
static int opt_repeat = 1;
static char *opt_reqin = NULL;
+static int opt_reqin_new_tid = 0;
static char *opt_reqout = NULL;
static char *opt_rspin = NULL;
static char *opt_rspout = NULL;
OPT_TLS_EXTRA, OPT_TLS_TRUSTED, OPT_TLS_HOST,
OPT_BATCH, OPT_REPEAT,
- OPT_REQIN, OPT_REQOUT, OPT_RSPIN, OPT_RSPOUT,
+ OPT_REQIN, OPT_REQIN_NEW_TID, OPT_REQOUT, OPT_RSPIN, OPT_RSPOUT,
OPT_USE_MOCK_SRV, OPT_PORT, OPT_MAX_MSGS,
OPT_SRV_REF, OPT_SRV_SECRET,
OPT_SECTION("Server authentication"),
{"trusted", OPT_TRUSTED, 's',
- "Trusted certs used for CMP server authentication when verifying responses"},
+ "Certificates to trust as chain roots when verifying signed CMP responses"},
{OPT_MORE_STR, 0, 0, "unless -srvcert is given"},
{"untrusted", OPT_UNTRUSTED, 's',
- "Intermediate certs for chain construction verifying CMP/TLS/enrolled certs"},
+ "Intermediate CA certs for chain construction for CMP/TLS/enrolled certs"},
{"srvcert", OPT_SRVCERT, 's',
- "Specific CMP server cert to use and trust directly when verifying responses"},
+ "Server cert to pin and trust directly when verifying signed CMP responses"},
{"recipient", OPT_RECIPIENT, 's',
- "Distinguished Name (DN) of the recipient to use unless -srvcert is given"},
+ "Distinguished Name (DN) to use as msg recipient; see man page for defaults"},
{"expect_sender", OPT_EXPECT_SENDER, 's',
- "DN of expected response sender. Defaults to DN of -srvcert, if provided"},
+ "DN of expected sender of responses. Defaults to subject of -srvcert, if any"},
{"ignore_keyusage", OPT_IGNORE_KEYUSAGE, '-',
"Ignore CMP signer cert key usage, else 'digitalSignature' must be allowed"},
{"unprotected_errors", OPT_UNPROTECTED_ERRORS, '-',
{"repeat", OPT_REPEAT, 'n',
"Invoke the transaction the given number of times. Default 1"},
{"reqin", OPT_REQIN, 's', "Take sequence of CMP requests from file(s)"},
+ {"reqin_new_tid", OPT_REQIN_NEW_TID, '-',
+ "Use fresh transactionID for CMP requests read from -reqin"},
{"reqout", OPT_REQOUT, 's', "Save sequence of CMP requests to file(s)"},
{"rspin", OPT_RSPIN, 's',
"Process sequence of CMP responses provided in file(s), skipping server"},
{&opt_tls_extra}, {&opt_tls_trusted}, {&opt_tls_host},
{(char **)&opt_batch}, {(char **)&opt_repeat},
- {&opt_reqin}, {&opt_reqout}, {&opt_rspin}, {&opt_rspout},
+ {&opt_reqin}, {(char **)&opt_reqin_new_tid},
+ {&opt_reqout}, {&opt_rspin}, {&opt_rspout},
{(char **)&opt_use_mock_srv}, {&opt_port}, {(char **)&opt_max_msgs},
{&opt_srv_ref}, {&opt_srv_secret},
const char *pass, ENGINE *e, const char *desc)
{
char *pass_string = get_passwd(pass, desc);
- EVP_PKEY *pkey = load_key_preliminary(uri, format, 0, pass_string, e, desc);
+ EVP_PKEY *pkey = load_key(uri, format, 0, pass_string, e, desc);
clear_free(pass_string);
return pkey;
if (req != NULL && opt_reqout != NULL
&& !write_PKIMESSAGE(req, &opt_reqout))
goto err;
- if (opt_reqin != NULL) {
- if (opt_rspin != NULL) {
- CMP_warn("-reqin is ignored since -rspin is present");
- } else {
- if ((req_new = read_PKIMESSAGE(&opt_reqin)) == NULL)
- goto err;
- /*-
- * The transaction ID in req_new may not be fresh.
- * In this case the Insta Demo CA correctly complains:
- * "Transaction id already in use."
- * The following workaround unfortunately requires re-protection.
- * See also https://github.com/mpeylo/cmpossl/issues/8
- */
-#if defined(USE_TRANSACTIONID_WORKAROUND)
- hdr = OSSL_CMP_MSG_get0_header(req_new);
- if (!OSSL_CMP_CTX_set1_transactionID(hdr, NULL)
- || !ossl_cmp_msg_protect(ctx, req_new))
- goto err;
-#endif
- }
+ if (opt_reqin != NULL && opt_rspin == NULL) {
+ if ((req_new = read_PKIMESSAGE(&opt_reqin)) == NULL)
+ goto err;
+ /*-
+ * The transaction ID in req_new read from opt_reqin may not be fresh.
+ * In this case the server may complain "Transaction id already in use."
+ * The following workaround unfortunately requires re-protection.
+ */
+ if (opt_reqin_new_tid
+ && !OSSL_CMP_MSG_update_transactionID(ctx, req_new))
+ goto err;
}
if (opt_rspin != NULL) {
if (opt_srv_cert != NULL) {
X509 *srv_cert = load_cert_pwd(opt_srv_cert, opt_srv_keypass,
"certificate of the server");
- if (srv_cert == NULL || !OSSL_CMP_CTX_set1_clCert(ctx, srv_cert)) {
+
+ if (srv_cert == NULL || !OSSL_CMP_CTX_set1_cert(ctx, srv_cert)) {
X509_free(srv_cert);
goto err;
}
/*
* Any further certs and any untrusted certs are used for constructing
- * the client cert chain to be provided along with the TLS client cert
- * to the TLS server.
+ * the chain to be provided with the TLS client cert to the TLS server.
*/
if (!SSL_CTX_set0_chain(ssl_ctx, certs)) {
CMP_err("could not set TLS client cert chain");
}
if (opt_cert != NULL) {
- X509 *clcert;
+ X509 *cert;
STACK_OF(X509) *certs = NULL;
int ok;
/* opt_keypass is needed if opt_cert is an encrypted PKCS#12 file */
goto err;
- clcert = sk_X509_delete(certs, 0);
- if (clcert == NULL) {
+ cert = sk_X509_delete(certs, 0);
+ if (cert == NULL) {
CMP_err("no client certificate found");
sk_X509_pop_free(certs, X509_free);
goto err;
}
- ok = OSSL_CMP_CTX_set1_clCert(ctx, clcert);
- X509_free(clcert);
+ ok = OSSL_CMP_CTX_set1_cert(ctx, cert);
+ X509_free(cert);
if (ok) {
/* add any remaining certs to the list of untrusted certs */
}
}
- if (opt_days > 0)
- (void)OSSL_CMP_CTX_set_option(ctx, OSSL_CMP_OPT_VALIDITY_DAYS,
- opt_days);
+ if (opt_days > 0
+ && !OSSL_CMP_CTX_set_option(ctx, OSSL_CMP_OPT_VALIDITY_DAYS,
+ opt_days)) {
+ CMP_err("could to set requested cert validity period");
+ goto err;
+ }
if (opt_policies != NULL && opt_policy_oids != NULL) {
CMP_err("cannot have policies both via -policies and via -policy_oids");
goto oom;
if (opt_proxy != NULL && !OSSL_CMP_CTX_set1_proxy(ctx, opt_proxy))
goto oom;
+ if (opt_no_proxy != NULL && !OSSL_CMP_CTX_set1_no_proxy(ctx, opt_no_proxy))
+ goto oom;
(void)BIO_snprintf(server_buf, sizeof(server_buf), "http%s://%s%s%s/%s",
opt_tls_used ? "s" : "", opt_server,
server_port == 0 ? "" : ":", server_port_s,
+ opt_path == NULL ? "" :
opt_path[0] == '/' ? opt_path + 1 : opt_path);
if (opt_proxy != NULL)
(void)OSSL_CMP_CTX_set_option(ctx, OSSL_CMP_OPT_TOTAL_TIMEOUT,
opt_total_timeout);
+ if (opt_reqin != NULL && opt_rspin != NULL)
+ CMP_warn("-reqin is ignored since -rspin is present");
+ if (opt_reqin_new_tid && opt_reqin == NULL)
+ CMP_warn("-reqin_new_tid is ignored since -reqin is not present");
if (opt_reqin != NULL || opt_reqout != NULL
|| opt_rspin != NULL || opt_rspout != NULL || opt_use_mock_srv)
(void)OSSL_CMP_CTX_set_transfer_cb(ctx, read_write_req_resp);
if (!set_name(opt_recipient, OSSL_CMP_CTX_set1_recipient, ctx, "recipient")
|| !set_name(opt_expect_sender, OSSL_CMP_CTX_set1_expected_sender,
ctx, "expected sender"))
- goto oom;
+ goto err;
if (opt_geninfo != NULL && !handle_opt_geninfo(ctx))
goto err;
case OPT_REQIN:
opt_reqin = opt_str("reqin");
break;
+ case OPT_REQIN_NEW_TID:
+ opt_reqin_new_tid = 1;
+ break;
case OPT_REQOUT:
opt_reqout = opt_str("reqout");
break;
}
if (opt_engine != NULL)
- e = setup_engine_flags(opt_engine, 0 /* not: ENGINE_METHOD_ALL */, 0);
+ e = setup_engine_methods(opt_engine, 0 /* not: ENGINE_METHOD_ALL */, 0);
if (opt_port != NULL) {
if (opt_use_mock_srv) {
if ((acbio = http_server_init_bio(prog, opt_port)) == NULL)
goto err;
while (opt_max_msgs <= 0 || msgs < opt_max_msgs) {
+ char *path = NULL;
OSSL_CMP_MSG *req = NULL;
OSSL_CMP_MSG *resp = NULL;
ret = http_server_get_asn1_req(ASN1_ITEM_rptr(OSSL_CMP_MSG),
- (ASN1_VALUE **)&req, &cbio, acbio,
- prog, 0, 0);
+ (ASN1_VALUE **)&req, &path,
+ &cbio, acbio, prog, 0, 0);
if (ret == 0)
continue;
if (ret++ == -1)
ret = 0;
msgs++;
if (req != NULL) {
+ if (strcmp(path, "") != 0 && strcmp(path, "pkix/") != 0) {
+ (void)http_server_send_status(cbio, 404, "Not Found");
+ CMP_err1("Expecting empty path or 'pkix/' but got '%s'",
+ path);
+ OPENSSL_free(path);
+ OSSL_CMP_MSG_free(req);
+ goto cont;
+ }
+ OPENSSL_free(path);
resp = OSSL_CMP_CTX_server_perform(cmp_ctx, req);
OSSL_CMP_MSG_free(req);
- if (resp == NULL)
+ if (resp == NULL) {
+ (void)http_server_send_status(cbio,
+ 500, "Internal Server Error");
break; /* treated as fatal error */
+ }
ret = http_server_send_asn1_resp(cbio, "application/pkixcmp",
ASN1_ITEM_rptr(OSSL_CMP_MSG),
(const ASN1_VALUE *)resp);
OSSL_CMP_MSG_free(resp);
if (!ret)
break; /* treated as fatal error */
+ } else {
+ (void)http_server_send_status(cbio, 400, "Bad Request");
}
+ cont:
BIO_free_all(cbio);
cbio = NULL;
}