X-Git-Url: https://git.openssl.org/?p=openssl.git;a=blobdiff_plain;f=apps%2Fcmp.c;h=7524930b8ffd5f9b120a08693bf14bb08d66cce2;hp=8565dc62aa1eb5d93eb5dd37ee8babf20a839555;hb=a0745e2be6635ffdf286ba5bc3bd867c8d4152a9;hpb=1a7cd250ad55a3c9d684a7259c20ea8075c2b08b diff --git a/apps/cmp.c b/apps/cmp.c index 8565dc62aa..7524930b8f 100644 --- a/apps/cmp.c +++ b/apps/cmp.c @@ -51,6 +51,7 @@ static char *opt_config = NULL; #define SECTION_NAME_MAX 40 /* max length of section name */ #define DEFAULT_SECTION "default" static char *opt_section = CMP_SECTION; +static int opt_verbosity = OSSL_CMP_LOG_INFO; #undef PROG #define PROG cmp_main @@ -73,11 +74,10 @@ typedef enum { /* message transfer */ static char *opt_server = NULL; -static char server_port_s[32] = { '\0' }; -static int server_port = 0; +static char server_port[32] = { '\0' }; static char *opt_proxy = NULL; static char *opt_no_proxy = NULL; -static char *opt_path = "/"; +static char *opt_path = NULL; static int opt_msg_timeout = -1; static int opt_total_timeout = -1; @@ -96,6 +96,7 @@ static char *opt_cacertsout = NULL; static char *opt_ref = NULL; static char *opt_secret = NULL; static char *opt_cert = NULL; +static char *opt_own_trusted = NULL; static char *opt_key = NULL; static char *opt_keypass = NULL; static char *opt_digest = NULL; @@ -128,6 +129,7 @@ static char *opt_out_trusted = NULL; static int opt_implicit_confirm = 0; static int opt_disable_confirm = 0; static char *opt_certout = NULL; +static char *opt_chainout = NULL; /* certificate enrollment and revocation */ static char *opt_oldcert = NULL; @@ -194,7 +196,7 @@ static X509_VERIFY_PARAM *vpm = NULL; typedef enum OPTION_choice { OPT_ERR = -1, OPT_EOF = 0, OPT_HELP, - OPT_CONFIG, OPT_SECTION, + OPT_CONFIG, OPT_SECTION, OPT_VERBOSITY, OPT_CMD, OPT_INFOTYPE, OPT_GENINFO, @@ -204,7 +206,7 @@ typedef enum OPTION_choice { OPT_POLICIES, OPT_POLICY_OIDS, OPT_POLICY_OIDS_CRITICAL, OPT_POPO, OPT_CSR, OPT_OUT_TRUSTED, OPT_IMPLICIT_CONFIRM, OPT_DISABLE_CONFIRM, - OPT_CERTOUT, + OPT_CERTOUT, OPT_CHAINOUT, OPT_OLDCERT, OPT_REVREASON, @@ -216,7 +218,7 @@ typedef enum OPTION_choice { OPT_IGNORE_KEYUSAGE, OPT_UNPROTECTED_ERRORS, OPT_EXTRACERTSOUT, OPT_CACERTSOUT, - OPT_REF, OPT_SECRET, OPT_CERT, OPT_KEY, OPT_KEYPASS, + OPT_REF, OPT_SECRET, OPT_CERT, OPT_OWN_TRUSTED, OPT_KEY, OPT_KEYPASS, OPT_DIGEST, OPT_MAC, OPT_EXTRACERTS, OPT_UNPROTECTED_REQUESTS, @@ -257,6 +259,8 @@ const OPTIONS cmp_options[] = { "Configuration file to use. \"\" = none. Default from env variable OPENSSL_CONF"}, {"section", OPT_SECTION, 's', "Section(s) in config file to get options from. \"\" = 'default'. Default 'cmp'"}, + {"verbosity", OPT_VERBOSITY, 'n', + "Log level; 3=ERR, 4=WARN, 6=INFO, 7=DEBUG, 8=TRACE. Default 6 = INFO"}, OPT_SECTION("Generic message"), {"cmd", OPT_CMD, 's', "CMP request to send: ir/cr/kur/p10cr/rr/genm"}, @@ -300,7 +304,7 @@ const OPTIONS cmp_options[] = { {OPT_MORE_STR, 0, 0, "-1 = NONE, 0 = RAVERIFIED, 1 = SIGNATURE (default), 2 = KEYENC"}, {"csr", OPT_CSR, 's', - "CSR file in PKCS#10 format to use in p10cr for legacy support"}, + "PKCS#10 CSR file in PEM or DER format to use in p10cr for legacy support"}, {"out_trusted", OPT_OUT_TRUSTED, 's', "Certificates to trust when verifying newly enrolled certificates"}, {"implicit_confirm", OPT_IMPLICIT_CONFIRM, '-', @@ -311,6 +315,8 @@ const OPTIONS cmp_options[] = { "confirmation. WARNING: This leads to behavior violating RFC 4210"}, {"certout", OPT_CERTOUT, 's', "File to save newly enrolled certificate"}, + {"chainout", OPT_CHAINOUT, 's', + "File to save the chain of newly enrolled certificate"}, OPT_SECTION("Certificate enrollment and revocation"), @@ -327,9 +333,9 @@ const OPTIONS cmp_options[] = { OPT_SECTION("Message transfer"), {"server", OPT_SERVER, 's', - "[http[s]://]address[:port] of CMP server. Default port 80 or 443."}, + "[http[s]://]address[:port][/path] of CMP server. Default port 80 or 443."}, {OPT_MORE_STR, 0, 0, - "The address may be a DNS name or an IP address"}, + "address may be a DNS name or an IP address; path can be overridden by -path"}, {"proxy", OPT_PROXY, 's', "[http[s]://]address[:port][/path] of HTTP(S) proxy to use; path is ignored"}, {"no_proxy", OPT_NO_PROXY, 's', @@ -337,7 +343,7 @@ const OPTIONS cmp_options[] = { {OPT_MORE_STR, 0, 0, "Default from environment variable 'no_proxy', else 'NO_PROXY', else none"}, {"path", OPT_PATH, 's', - "HTTP path (aka CMP alias) at the CMP server. Default \"/\""}, + "HTTP path (aka CMP alias) at the CMP server. Default from -server, else \"/\""}, {"msg_timeout", OPT_MSG_TIMEOUT, 'n', "Timeout per CMP message round trip (or 0 for none). Default 120 seconds"}, {"total_timeout", OPT_TOTAL_TIMEOUT, 'n', @@ -377,6 +383,8 @@ const OPTIONS cmp_options[] = { "Client's current certificate (needed unless using -secret for PBM);"}, {OPT_MORE_STR, 0, 0, "any further certs included are appended in extraCerts field"}, + {"own_trusted", OPT_OWN_TRUSTED, 's', + "Optional certs to verify chain building for own CMP signer cert"}, {"key", OPT_KEY, 's', "Private key for the client's current certificate"}, {"keypass", OPT_KEYPASS, 's', "Client private key (and cert and old cert file) pass phrase source"}, @@ -507,7 +515,7 @@ typedef union { long *num_long; } varref; static varref cmp_vars[] = { /* must be in same order as enumerated above! */ - {&opt_config}, {&opt_section}, + {&opt_config}, {&opt_section}, {(char **)&opt_verbosity}, {&opt_cmd_s}, {&opt_infotype_s}, {&opt_geninfo}, @@ -518,7 +526,7 @@ static varref cmp_vars[] = { /* must be in same order as enumerated above! */ {(char **)&opt_popo}, {&opt_csr}, {&opt_out_trusted}, {(char **)&opt_implicit_confirm}, {(char **)&opt_disable_confirm}, - {&opt_certout}, + {&opt_certout}, {&opt_chainout}, {&opt_oldcert}, {(char **)&opt_revreason}, @@ -530,7 +538,8 @@ static varref cmp_vars[] = { /* must be in same order as enumerated above! */ {(char **)&opt_ignore_keyusage}, {(char **)&opt_unprotected_errors}, {&opt_extracertsout}, {&opt_cacertsout}, - {&opt_ref}, {&opt_secret}, {&opt_cert}, {&opt_key}, {&opt_keypass}, + {&opt_ref}, {&opt_secret}, + {&opt_cert}, {&opt_own_trusted}, {&opt_key}, {&opt_keypass}, {&opt_digest}, {&opt_mac}, {&opt_extracerts}, {(char **)&opt_unprotected_requests}, @@ -564,28 +573,32 @@ static varref cmp_vars[] = { /* must be in same order as enumerated above! */ {NULL} }; -#ifndef NDEBUG -# define FUNC (strcmp(OPENSSL_FUNC, "(unknown function)") == 0 \ - ? "CMP" : "OPENSSL_FUNC") -# define PRINT_LOCATION(bio) BIO_printf(bio, "%s:%s:%d:", \ - FUNC, OPENSSL_FILE, OPENSSL_LINE) -#else -# define PRINT_LOCATION(bio) ((void)0) -#endif -#define CMP_print(bio, prefix, msg, a1, a2, a3) \ - (PRINT_LOCATION(bio), \ - BIO_printf(bio, "CMP %s: " msg "\n", prefix, a1, a2, a3)) -#define CMP_INFO(msg, a1, a2, a3) CMP_print(bio_out, "info", msg, a1, a2, a3) +#define FUNC (strcmp(OPENSSL_FUNC, "(unknown function)") == 0 \ + ? "CMP" : OPENSSL_FUNC) +#define CMP_print(bio, level, prefix, msg, a1, a2, a3) \ + ((void)(level > opt_verbosity ? 0 : \ + (BIO_printf(bio, "%s:%s:%d:CMP %s: " msg "\n", \ + FUNC, OPENSSL_FILE, OPENSSL_LINE, prefix, a1, a2, a3)))) +#define CMP_DEBUG(m, a1, a2, a3) \ + CMP_print(bio_out, OSSL_CMP_LOG_DEBUG, "debug", m, a1, a2, a3) +#define CMP_debug(msg) CMP_DEBUG(msg"%s%s%s", "", "", "") +#define CMP_debug1(msg, a1) CMP_DEBUG(msg"%s%s", a1, "", "") +#define CMP_debug2(msg, a1, a2) CMP_DEBUG(msg"%s", a1, a2, "") +#define CMP_debug3(msg, a1, a2, a3) CMP_DEBUG(msg, a1, a2, a3) +#define CMP_INFO(msg, a1, a2, a3) \ + CMP_print(bio_out, OSSL_CMP_LOG_INFO, "info", msg, a1, a2, a3) #define CMP_info(msg) CMP_INFO(msg"%s%s%s", "", "", "") #define CMP_info1(msg, a1) CMP_INFO(msg"%s%s", a1, "", "") #define CMP_info2(msg, a1, a2) CMP_INFO(msg"%s", a1, a2, "") #define CMP_info3(msg, a1, a2, a3) CMP_INFO(msg, a1, a2, a3) -#define CMP_WARN(m, a1, a2, a3) CMP_print(bio_out, "warning", m, a1, a2, a3) +#define CMP_WARN(m, a1, a2, a3) \ + CMP_print(bio_out, OSSL_CMP_LOG_WARNING, "warning", m, a1, a2, a3) #define CMP_warn(msg) CMP_WARN(msg"%s%s%s", "", "", "") #define CMP_warn1(msg, a1) CMP_WARN(msg"%s%s", a1, "", "") #define CMP_warn2(msg, a1, a2) CMP_WARN(msg"%s", a1, a2, "") #define CMP_warn3(msg, a1, a2, a3) CMP_WARN(msg, a1, a2, a3) -#define CMP_ERR(msg, a1, a2, a3) CMP_print(bio_err, "error", msg, a1, a2, a3) +#define CMP_ERR(msg, a1, a2, a3) \ + CMP_print(bio_err, OSSL_CMP_LOG_ERR, "error", msg, a1, a2, a3) #define CMP_err(msg) CMP_ERR(msg"%s%s%s", "", "", "") #define CMP_err1(msg, a1) CMP_ERR(msg"%s%s", a1, "", "") #define CMP_err2(msg, a1, a2) CMP_ERR(msg"%s", a1, a2, "") @@ -597,6 +610,16 @@ static int print_to_bio_out(const char *func, const char *file, int line, return OSSL_CMP_print_to_bio(bio_out, func, file, line, level, msg); } +static int set_verbosity(int level) +{ + if (level < OSSL_CMP_LOG_EMERG || level > OSSL_CMP_LOG_MAX) { + CMP_err1("Logging verbosity level %d out of range (0 .. 8)", level); + return 0; + } + opt_verbosity = level; + return 1; +} + static char *next_item(char *opt) /* in list separated by comma and/or space */ { /* advance to separator (comma or whitespace), if any */ @@ -636,42 +659,6 @@ static X509 *load_cert_pwd(const char *uri, const char *pass, const char *desc) return cert; } -/* TODO potentially move this and related functions to apps/lib/apps.c */ -static int adjust_format(const char **infile, int format, int engine_ok) -{ - if (!strncasecmp(*infile, "http://", 7) - || !strncasecmp(*infile, "https://", 8)) { - format = FORMAT_HTTP; - } else if (engine_ok && strncasecmp(*infile, "engine:", 7) == 0) { - *infile += 7; - format = FORMAT_ENGINE; - } else { - if (strncasecmp(*infile, "file:", 5) == 0) - *infile += 5; - /* - * the following is a heuristic whether first to try PEM or DER - * or PKCS12 as the input format for files - */ - if (strlen(*infile) >= 4) { - const char *extension = *infile + strlen(*infile) - 4; - - if (strncasecmp(extension, ".crt", 4) == 0 - || strncasecmp(extension, ".pem", 4) == 0) - /* weak recognition of PEM format */ - format = FORMAT_PEM; - else if (strncasecmp(extension, ".cer", 4) == 0 - || strncasecmp(extension, ".der", 4) == 0) - /* weak recognition of DER format */ - format = FORMAT_ASN1; - else if (strncasecmp(extension, ".p12", 4) == 0) - /* weak recognition of PKCS#12 format */ - format = FORMAT_PKCS12; - /* else retain given format */ - } - } - return format; -} - /* * TODO potentially move this and related functions to apps/lib/ * or even better extend OSSL_STORE with type OSSL_STORE_INFO_CRL @@ -680,18 +667,13 @@ static X509_REQ *load_csr_autofmt(const char *infile, const char *desc) { X509_REQ *csr; BIO *bio_bak = bio_err; - int can_retry; - int format = adjust_format(&infile, FORMAT_PEM, 0); - can_retry = format == FORMAT_PEM || format == FORMAT_ASN1; - if (can_retry) - bio_err = NULL; /* do not show errors on more than one try */ - csr = load_csr(infile, format, desc); + bio_err = NULL; /* do not show errors on more than one try */ + csr = load_csr(infile, FORMAT_PEM, desc); bio_err = bio_bak; - if (csr == NULL && can_retry) { + if (csr == NULL) { ERR_clear_error(); - format = (format == FORMAT_PEM ? FORMAT_ASN1 : FORMAT_PEM); - csr = load_csr(infile, format, desc); + csr = load_csr(infile, FORMAT_ASN1, desc); } if (csr == NULL) { ERR_print_errors(bio_err); @@ -701,43 +683,59 @@ static X509_REQ *load_csr_autofmt(const char *infile, const char *desc) return csr; } -static void warn_certs_expired(const char *file, STACK_OF(X509) **certs) +static void warn_cert_msg(const char *uri, X509 *cert, const char *msg) { - int i, res; - X509 *cert; - char *subj; + char *subj = X509_NAME_oneline(X509_get_subject_name(cert), NULL, 0); - for (i = 0; i < sk_X509_num(*certs); i++) { - cert = sk_X509_value(*certs, i); - res = X509_cmp_timeframe(vpm, X509_get0_notBefore(cert), + CMP_warn3("certificate from '%s' with subject '%s' %s", uri, subj, msg); + OPENSSL_free(subj); +} + +static void warn_cert(const char *uri, X509 *cert, int warn_EE) +{ + int res = X509_cmp_timeframe(vpm, X509_get0_notBefore(cert), X509_get0_notAfter(cert)); - if (res != 0) { - subj = X509_NAME_oneline(X509_get_subject_name(cert), NULL, 0); - CMP_warn3("certificate from '%s' with subject '%s' %s", file, subj, - res > 0 ? "has expired" : "not yet valid"); - OPENSSL_free(subj); - } - } + + if (res != 0) + warn_cert_msg(uri, cert, res > 0 ? "has expired" : "not yet valid"); + if (warn_EE && (X509_get_extension_flags(cert) & EXFLAG_CA) == 0) + warn_cert_msg(uri, cert, "is not a CA cert"); +} + +static void warn_certs(const char *uri, STACK_OF(X509) *certs, int warn_EE) +{ + int i; + + for (i = 0; i < sk_X509_num(certs); i++) + warn_cert(uri, sk_X509_value(certs, i), warn_EE); } -static int load_certs_pwd(const char *infile, STACK_OF(X509) **certs, - int exclude_http, const char *pass, - const char *desc) +/* TODO potentially move this and related functions to apps/lib/apps.c */ +static int load_cert_certs(const char *uri, + X509 **pcert, STACK_OF(X509) **pcerts, + int exclude_http, const char *pass, const char *desc) { int ret = 0; char *pass_string; - int format = adjust_format(&infile, FORMAT_PEM, 0); - if (exclude_http && format == FORMAT_HTTP) { + if (exclude_http && (strncasecmp(uri, "http://", 7) == 0 + || strncasecmp(uri, "https://", 8) == 0)) { BIO_printf(bio_err, "error: HTTP retrieval not allowed for %s\n", desc); return ret; } pass_string = get_passwd(pass, desc); - ret = load_certs(infile, certs, pass_string, desc); + ret = load_key_certs_crls(uri, 0, pass_string, desc, NULL, NULL, + pcert, pcerts, NULL, NULL); clear_free(pass_string); - if (ret) - warn_certs_expired(infile, certs); + if (ret) { + if (pcert != NULL) + warn_cert(uri, *pcert, 0); + warn_certs(uri, *pcerts, 1); + } else { + sk_X509_pop_free(*pcerts, X509_free); + *pcerts = NULL; + } return ret; } @@ -890,66 +888,6 @@ static OSSL_CMP_MSG *read_write_req_resp(OSSL_CMP_CTX *ctx, return res; } -/* - * parse string as integer value, not allowing trailing garbage, see also - * https://www.gnu.org/software/libc/manual/html_node/Parsing-of-Integers.html - * - * returns integer value, or INT_MIN on error - */ -static int atoint(const char *str) -{ - char *tailptr; - long res = strtol(str, &tailptr, 10); - - if ((*tailptr != '\0') || (res < INT_MIN) || (res > INT_MAX)) - return INT_MIN; - else - return (int)res; -} - -static int parse_addr(char **opt_string, int port, const char *name) -{ - char *port_string; - - if (strncasecmp(*opt_string, OSSL_HTTP_PREFIX, - strlen(OSSL_HTTP_PREFIX)) == 0) { - *opt_string += strlen(OSSL_HTTP_PREFIX); - } else if (strncasecmp(*opt_string, OSSL_HTTPS_PREFIX, - strlen(OSSL_HTTPS_PREFIX)) == 0) { - *opt_string += strlen(OSSL_HTTPS_PREFIX); - if (port == 0) - port = 443; /* == integer value of OSSL_HTTPS_PORT */ - } - - if ((port_string = strrchr(*opt_string, ':')) == NULL) - return port; /* using default */ - *(port_string++) = '\0'; - port = atoint(port_string); - if ((port <= 0) || (port > 65535)) { - CMP_err2("invalid %s port '%s' given, sane range 1-65535", - name, port_string); - return -1; - } - return port; -} - -static int set1_store_parameters(X509_STORE *ts) -{ - if (ts == NULL) - return 0; - - /* copy vpm to store */ - if (!X509_STORE_set1_param(ts, vpm /* may be NULL */)) { - BIO_printf(bio_err, "error setting verification parameters\n"); - OSSL_CMP_CTX_print_errors(cmp_ctx); - return 0; - } - - X509_STORE_set_verify_cb(ts, X509_STORE_CTX_print_verify_cb); - - return 1; -} - static int set_name(const char *str, int (*set_fn) (OSSL_CMP_CTX *ctx, const X509_NAME *name), OSSL_CMP_CTX *ctx, const char *desc) @@ -1017,28 +955,42 @@ static X509_STORE *load_certstore(char *input, const char *desc) X509_STORE *store = NULL; STACK_OF(X509) *certs = NULL; - if (input == NULL) - goto err; - while (input != NULL) { - char *next = next_item(input); \ + char *next = next_item(input); + int ok; - if (!load_certs_pwd(input, &certs, 1, opt_otherpass, desc) - || !(store = sk_X509_to_store(store, certs))) { - /* CMP_err("out of memory"); */ + if (!load_cert_certs(input, NULL, &certs, 1, opt_otherpass, desc)) { X509_STORE_free(store); - store = NULL; - goto err; + return NULL; } + ok = (store = sk_X509_to_store(store, certs)) != NULL; sk_X509_pop_free(certs, X509_free); certs = NULL; + if (!ok) + return NULL; input = next; } - err: - sk_X509_pop_free(certs, X509_free); return store; } +static X509_STORE *load_trusted(char *input, int for_new_cert, const char *desc) +{ + X509_STORE *ts = load_certstore(input, desc); + + if (ts == NULL) + return NULL; + X509_STORE_set_verify_cb(ts, X509_STORE_CTX_print_verify_cb); + + /* copy vpm to store */ + if (X509_STORE_set1_param(ts, vpm /* may be NULL */) + && (for_new_cert || truststore_set_host_etc(ts, NULL))) + return ts; + BIO_printf(bio_err, "error setting verification parameters\n"); + OSSL_CMP_CTX_print_errors(cmp_ctx); + X509_STORE_free(ts); + return NULL; +} + /* TODO potentially move to apps/lib/apps.c */ static STACK_OF(X509) *load_certs_multifile(char *files, const char *pass, const char *desc) @@ -1054,7 +1006,7 @@ static STACK_OF(X509) *load_certs_multifile(char *files, while (files != NULL) { char *next = next_item(files); - if (!load_certs_pwd(files, &certs, 0, pass, desc)) + if (!load_cert_certs(files, NULL, &certs, 0, pass, desc)) goto err; if (!X509_add_certs(result, certs, X509_ADD_FLAG_UP_REF | X509_ADD_FLAG_NO_DUP)) @@ -1074,31 +1026,20 @@ static STACK_OF(X509) *load_certs_multifile(char *files, } 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_certs(char *files, const char *desc, void *ctx, - add_X509_stack_fn_t addn_fn, add_X509_fn_t add1_fn) + add_X509_stack_fn_t set1_fn) { - int ret = 1; - - if (files != NULL) { - STACK_OF(X509) *certs = load_certs_multifile(files, opt_otherpass, - desc); - if (certs == NULL) { - ret = 0; - } else { - if (addn_fn != NULL) { - ret = (*addn_fn)(ctx, certs); - } else { - int i; + STACK_OF(X509) *certs; + int ok; - for (i = 0; i < sk_X509_num(certs /* may be NULL */); i++) - ret &= (*add1_fn)(ctx, sk_X509_value(certs, i)); - } - sk_X509_pop_free(certs, X509_free); - } - } - return ret; + if (files == NULL) + return 1; + if ((certs = load_certs_multifile(files, opt_otherpass, desc)) == NULL) + return 0; + ok = (*set1_fn)(ctx, certs); + sk_X509_pop_free(certs, X509_free); + return ok; } @@ -1224,22 +1165,18 @@ static OSSL_CMP_SRV_CTX *setup_srv_ctx(ENGINE *engine) if (opt_srv_trusted != NULL) { X509_STORE *ts = - load_certstore(opt_srv_trusted, "certificates trusted by server"); + load_trusted(opt_srv_trusted, 0, "certs trusted by server"); - if (ts == NULL) - goto err; - if (!set1_store_parameters(ts) - || !truststore_set_host_etc(ts, NULL) - || !OSSL_CMP_CTX_set0_trustedStore(ctx, ts)) { + if (ts == NULL || !OSSL_CMP_CTX_set0_trustedStore(ctx, ts)) { X509_STORE_free(ts); goto err; } } else { CMP_warn("server will not be able to handle signature-protected requests since -srv_trusted is not given"); } - if (!setup_certs(opt_srv_untrusted, "untrusted certificates", ctx, - (add_X509_stack_fn_t)OSSL_CMP_CTX_set1_untrusted_certs, - NULL)) + if (!setup_certs(opt_srv_untrusted, + "untrusted certificates for mock server", ctx, + (add_X509_stack_fn_t)OSSL_CMP_CTX_set1_untrusted)) goto err; if (opt_rsp_cert == NULL) { @@ -1261,12 +1198,10 @@ static OSSL_CMP_SRV_CTX *setup_srv_ctx(ENGINE *engine) /* TODO find a cleaner solution not requiring type casts */ 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, - NULL)) + (add_X509_stack_fn_t)ossl_cmp_mock_srv_set1_chainOut)) goto err; if (!setup_certs(opt_rsp_capubs, "caPubs for mock server", srv_ctx, - (add_X509_stack_fn_t)ossl_cmp_mock_srv_set1_caPubsOut, - NULL)) + (add_X509_stack_fn_t)ossl_cmp_mock_srv_set1_caPubsOut)) 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); @@ -1320,16 +1255,15 @@ static OSSL_CMP_SRV_CTX *setup_srv_ctx(ENGINE *engine) static int setup_verification_ctx(OSSL_CMP_CTX *ctx) { if (!setup_certs(opt_untrusted, "untrusted certificates", ctx, - (add_X509_stack_fn_t)OSSL_CMP_CTX_set1_untrusted_certs, - NULL)) - goto err; + (add_X509_stack_fn_t)OSSL_CMP_CTX_set1_untrusted)) + return 0; if (opt_srvcert != NULL || opt_trusted != NULL) { - X509_STORE *ts = NULL; + X509 *srvcert; + X509_STORE *ts; + int ok; if (opt_srvcert != NULL) { - X509 *srvcert; - if (opt_trusted != NULL) { CMP_warn("-trusted option is ignored since -srvcert option is present"); opt_trusted = NULL; @@ -1340,33 +1274,22 @@ static int setup_verification_ctx(OSSL_CMP_CTX *ctx) } srvcert = load_cert_pwd(opt_srvcert, opt_otherpass, "directly trusted CMP server certificate"); - if (srvcert == NULL) - /* - * opt_otherpass is needed in case - * opt_srvcert is an encrypted PKCS#12 file - */ - goto err; - if (!OSSL_CMP_CTX_set1_srvCert(ctx, srvcert)) { - X509_free(srvcert); - goto oom; - } + ok = srvcert != NULL && OSSL_CMP_CTX_set1_srvCert(ctx, srvcert); X509_free(srvcert); - if ((ts = X509_STORE_new()) == NULL) - goto oom; + if (!ok) + return 0; } - if (opt_trusted != NULL - && (ts = load_certstore(opt_trusted, "trusted certificates")) - == NULL) - goto err; - if (!set1_store_parameters(ts) /* also copies vpm */ - /* - * clear any expected host/ip/email address; - * opt_expect_sender is used instead - */ - || !truststore_set_host_etc(ts, NULL) - || !OSSL_CMP_CTX_set0_trustedStore(ctx, ts)) { - X509_STORE_free(ts); - goto oom; + if (opt_trusted != NULL) { + /* + * the 0 arg below clears any expected host/ip/email address; + * opt_expect_sender is used instead + */ + ts = load_trusted(opt_trusted, 0, "certs trusted by client"); + + if (ts == NULL || !OSSL_CMP_CTX_set0_trustedStore(ctx, ts)) { + X509_STORE_free(ts); + return 0; + } } } @@ -1379,14 +1302,11 @@ static int setup_verification_ctx(OSSL_CMP_CTX *ctx) if (opt_out_trusted != NULL) { /* for use in OSSL_CMP_certConf_cb() */ X509_VERIFY_PARAM *out_vpm = NULL; X509_STORE *out_trusted = - load_certstore(opt_out_trusted, - "trusted certs for verifying newly enrolled cert"); + load_trusted(opt_out_trusted, 1, + "trusted certs for verifying newly enrolled cert"); if (out_trusted == NULL) - goto err; - /* any -verify_hostname, -verify_ip, and -verify_email apply here */ - if (!set1_store_parameters(out_trusted)) - goto oom; + return 0; /* ignore any -attime here, new certs are current anyway */ out_vpm = X509_STORE_get0_param(out_trusted); X509_VERIFY_PARAM_clear_flags(out_vpm, X509_V_FLAG_USE_CHECK_TIME); @@ -1400,14 +1320,7 @@ static int setup_verification_ctx(OSSL_CMP_CTX *ctx) if (opt_implicit_confirm) (void)OSSL_CMP_CTX_set_option(ctx, OSSL_CMP_OPT_IMPLICIT_CONFIRM, 1); - (void)OSSL_CMP_CTX_set_certConf_cb(ctx, OSSL_CMP_certConf_cb); - return 1; - - oom: - CMP_err("out of memory"); - err: - return 0; } #ifndef OPENSSL_NO_SOCK @@ -1417,7 +1330,7 @@ static int setup_verification_ctx(OSSL_CMP_CTX *ctx) */ static SSL_CTX *setup_ssl_ctx(OSSL_CMP_CTX *ctx, ENGINE *engine) { - STACK_OF(X509) *untrusted_certs = OSSL_CMP_CTX_get0_untrusted_certs(ctx); + STACK_OF(X509) *untrusted = OSSL_CMP_CTX_get0_untrusted(ctx); EVP_PKEY *pkey = NULL; X509_STORE *trust_store = NULL; SSL_CTX *ssl_ctx; @@ -1441,46 +1354,57 @@ static SSL_CTX *setup_ssl_ctx(OSSL_CMP_CTX *ctx, ENGINE *engine) if (opt_tls_cert != NULL && opt_tls_key != NULL) { X509 *cert; STACK_OF(X509) *certs = NULL; + int ok; - if (!load_certs_pwd(opt_tls_cert, &certs, 0, opt_tls_keypass, - "TLS client certificate (optionally with chain)")) - /* - * opt_tls_keypass is needed in case opt_tls_cert is an encrypted - * PKCS#12 file - */ + if (!load_cert_certs(opt_tls_cert, &cert, &certs, 0, opt_tls_keypass, + "TLS client certificate (optionally with chain)")) + /* need opt_tls_keypass if opt_tls_cert is encrypted PKCS#12 file */ goto err; - cert = sk_X509_delete(certs, 0); - if (cert == NULL || SSL_CTX_use_certificate(ssl_ctx, cert) <= 0) { - CMP_err1("unable to use client TLS certificate file '%s'", - opt_tls_cert); - X509_free(cert); - sk_X509_pop_free(certs, X509_free); - goto err; - } - X509_free(cert); /* we do not need the handle any more */ + ok = SSL_CTX_use_certificate(ssl_ctx, cert) > 0; + X509_free(cert); /* * Any further certs and any untrusted certs are used for constructing * 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 (!ok || !SSL_CTX_set0_chain(ssl_ctx, certs)) { + CMP_err1("unable to use client TLS certificate file '%s'", + opt_tls_cert); sk_X509_pop_free(certs, X509_free); goto err; } - for (i = 0; i < sk_X509_num(untrusted_certs); i++) { - cert = sk_X509_value(untrusted_certs, i); + for (i = 0; i < sk_X509_num(untrusted); i++) { + cert = sk_X509_value(untrusted, i); if (!SSL_CTX_add1_chain_cert(ssl_ctx, cert)) { CMP_err("could not add untrusted cert to TLS client cert chain"); goto err; } } - if (!SSL_CTX_build_cert_chain(ssl_ctx, - SSL_BUILD_CHAIN_FLAG_UNTRUSTED | - SSL_BUILD_CHAIN_FLAG_NO_ROOT)) { - CMP_warn("could not build cert chain for own TLS cert"); - OSSL_CMP_CTX_print_errors(ctx); + + { + X509_VERIFY_PARAM *tls_vpm = NULL; + unsigned long bak_flags = 0; /* compiler warns without init */ + + if (trust_store != NULL) { + tls_vpm = X509_STORE_get0_param(trust_store); + bak_flags = X509_VERIFY_PARAM_get_flags(tls_vpm); + /* disable any cert status/revocation checking etc. */ + X509_VERIFY_PARAM_clear_flags(tls_vpm, + ~(X509_V_FLAG_USE_CHECK_TIME + | X509_V_FLAG_NO_CHECK_TIME)); + } + CMP_debug("trying to build cert chain for own TLS cert"); + if (SSL_CTX_build_cert_chain(ssl_ctx, + SSL_BUILD_CHAIN_FLAG_UNTRUSTED | + SSL_BUILD_CHAIN_FLAG_NO_ROOT)) { + CMP_debug("success building cert chain for own TLS cert"); + } else { + OSSL_CMP_CTX_print_errors(ctx); + CMP_warn("could not build cert chain for own TLS cert"); + } + if (trust_store != NULL) + X509_VERIFY_PARAM_set_flags(tls_vpm, bak_flags); } /* If present we append to the list also the certs from opt_tls_extra */ @@ -1557,17 +1481,17 @@ static int setup_protection_ctx(OSSL_CMP_CTX *ctx, ENGINE *engine) { if (!opt_unprotected_requests && opt_secret == NULL && opt_cert == NULL) { CMP_err("must give client credentials unless -unprotected_requests is set"); - goto err; + return 0; } if (opt_ref == NULL && opt_cert == NULL && opt_subject == NULL) { /* cert or subject should determine the sender */ CMP_err("must give -ref if no -cert and no -subject given"); - goto err; + return 0; } if (!opt_secret && ((opt_cert == NULL) != (opt_key == NULL))) { CMP_err("must give both -cert and -key options or neither"); - goto err; + return 0; } if (opt_secret != NULL) { char *pass_string = get_passwd(opt_secret, "PBMAC"); @@ -1580,7 +1504,7 @@ static int setup_protection_ctx(OSSL_CMP_CTX *ctx, ENGINE *engine) strlen(pass_string)); clear_free(pass_string); if (res == 0) - goto err; + return 0; } if (opt_cert != NULL || opt_key != NULL) CMP_warn("no signature-based protection used since -secret is given"); @@ -1588,7 +1512,7 @@ static int setup_protection_ctx(OSSL_CMP_CTX *ctx, ENGINE *engine) if (opt_ref != NULL && !OSSL_CMP_CTX_set1_referenceValue(ctx, (unsigned char *)opt_ref, strlen(opt_ref))) - goto err; + return 0; if (opt_key != NULL) { EVP_PKEY *pkey = load_key_pwd(opt_key, opt_keyform, opt_keypass, engine, @@ -1596,51 +1520,46 @@ static int setup_protection_ctx(OSSL_CMP_CTX *ctx, ENGINE *engine) if (pkey == NULL || !OSSL_CMP_CTX_set1_pkey(ctx, pkey)) { EVP_PKEY_free(pkey); - goto err; + return 0; } EVP_PKEY_free(pkey); } - if (opt_secret == NULL && opt_srvcert == NULL && opt_trusted == NULL) { - CMP_err("missing -secret or -srvcert or -trusted"); - goto err; - } + if (opt_secret == NULL && opt_srvcert == NULL && opt_trusted == NULL) + CMP_warn("will not authenticate server due to missing -secret, -trusted, or -srvcert"); if (opt_cert != NULL) { X509 *cert; STACK_OF(X509) *certs = NULL; + X509_STORE *own_trusted = NULL; int ok; - if (!load_certs_pwd(opt_cert, &certs, 0, opt_keypass, - "CMP client certificate (and optionally extra certs)")) + if (!load_cert_certs(opt_cert, &cert, &certs, 0, opt_keypass, + "CMP client certificate (optionally with chain)")) /* opt_keypass is needed if opt_cert is an encrypted PKCS#12 file */ - goto err; - - cert = sk_X509_delete(certs, 0); - if (cert == NULL) { - CMP_err("no client certificate found"); - sk_X509_pop_free(certs, X509_free); - goto err; - } + return 0; ok = OSSL_CMP_CTX_set1_cert(ctx, cert); X509_free(cert); - - if (ok) { - /* add any remaining certs to the list of untrusted certs */ - STACK_OF(X509) *untrusted = OSSL_CMP_CTX_get0_untrusted_certs(ctx); - ok = untrusted != NULL ? - X509_add_certs(untrusted, certs, - X509_ADD_FLAG_UP_REF | X509_ADD_FLAG_NO_DUP) - : OSSL_CMP_CTX_set1_untrusted_certs(ctx, certs); + if (!ok) { + CMP_err("out of memory"); + } else { + if (opt_own_trusted != NULL) { + own_trusted = load_trusted(opt_own_trusted, 0, + "trusted certs for verifying own CMP signer cert"); + ok = own_trusted != NULL; + } + ok = ok && OSSL_CMP_CTX_build_cert_chain(ctx, own_trusted, certs); } + X509_STORE_free(own_trusted); sk_X509_pop_free(certs, X509_free); if (!ok) - goto oom; + return 0; + } else if (opt_own_trusted != NULL) { + CMP_warn("-own_trusted option is ignored without -cert"); } if (!setup_certs(opt_extracerts, "extra certificates for CMP", ctx, - (add_X509_stack_fn_t)OSSL_CMP_CTX_set1_extraCertsOut, - NULL)) - goto err; + (add_X509_stack_fn_t)OSSL_CMP_CTX_set1_extraCertsOut)) + return 0; cleanse(opt_otherpass); if (opt_unprotected_requests) @@ -1651,26 +1570,24 @@ static int setup_protection_ctx(OSSL_CMP_CTX *ctx, ENGINE *engine) if (digest == NID_undef) { CMP_err1("digest algorithm name not recognized: '%s'", opt_digest); - goto err; + return 0; + } + if (!OSSL_CMP_CTX_set_option(ctx, OSSL_CMP_OPT_DIGEST_ALGNID, digest) + || !OSSL_CMP_CTX_set_option(ctx, OSSL_CMP_OPT_OWF_ALGNID, digest)) { + CMP_err1("digest algorithm name not supported: '%s'", opt_digest); + return 0; } - (void)OSSL_CMP_CTX_set_option(ctx, OSSL_CMP_OPT_DIGEST_ALGNID, digest); - (void)OSSL_CMP_CTX_set_option(ctx, OSSL_CMP_OPT_OWF_ALGNID, digest); } if (opt_mac != NULL) { int mac = OBJ_ln2nid(opt_mac); if (mac == NID_undef) { CMP_err1("MAC algorithm name not recognized: '%s'", opt_mac); - goto err; + return 0; } (void)OSSL_CMP_CTX_set_option(ctx, OSSL_CMP_OPT_MAC_ALGNID, mac); } return 1; - - oom: - CMP_err("out of memory"); - err: - return 0; } /* @@ -1684,7 +1601,7 @@ static int setup_request_ctx(OSSL_CMP_CTX *ctx, ENGINE *engine) CMP_warn("no -subject given, neither -oldcert nor -cert available as default"); if (!set_name(opt_subject, OSSL_CMP_CTX_set1_subjectName, ctx, "subject") || !set_name(opt_issuer, OSSL_CMP_CTX_set1_issuer, ctx, "issuer")) - goto err; + return 0; if (opt_newkey != NULL) { const char *file = opt_newkey; @@ -1702,7 +1619,7 @@ static int setup_request_ctx(OSSL_CMP_CTX *ctx, ENGINE *engine) cleanse(opt_newkeypass); if (pkey == NULL || !OSSL_CMP_CTX_set0_newPkey(ctx, priv, pkey)) { EVP_PKEY_free(pkey); - goto err; + return 0; } } @@ -1710,12 +1627,12 @@ static int setup_request_ctx(OSSL_CMP_CTX *ctx, ENGINE *engine) && !OSSL_CMP_CTX_set_option(ctx, OSSL_CMP_OPT_VALIDITY_DAYS, opt_days)) { CMP_err("could not set requested cert validity period"); - goto err; + return 0; } if (opt_policies != NULL && opt_policy_oids != NULL) { CMP_err("cannot have policies both via -policies and via -policy_oids"); - goto err; + return 0; } if (opt_reqexts != NULL || opt_policies != NULL) { @@ -1723,7 +1640,7 @@ static int setup_request_ctx(OSSL_CMP_CTX *ctx, ENGINE *engine) X509_EXTENSIONS *exts = sk_X509_EXTENSION_new_null(); if (exts == NULL) - goto err; + return 0; X509V3_set_ctx(&ext_ctx, NULL, NULL, NULL, NULL, 0); X509V3_set_nconf(&ext_ctx, conf); if (opt_reqexts != NULL @@ -1731,24 +1648,24 @@ static int setup_request_ctx(OSSL_CMP_CTX *ctx, ENGINE *engine) CMP_err1("cannot load certificate request extension section '%s'", opt_reqexts); sk_X509_EXTENSION_pop_free(exts, X509_EXTENSION_free); - goto err; + return 0; } if (opt_policies != NULL && !X509V3_EXT_add_nconf_sk(conf, &ext_ctx, opt_policies, &exts)) { CMP_err1("cannot load policy cert request extension section '%s'", opt_policies); sk_X509_EXTENSION_pop_free(exts, X509_EXTENSION_free); - goto err; + return 0; } OSSL_CMP_CTX_set0_reqExtensions(ctx, exts); } if (OSSL_CMP_CTX_reqExtensions_have_SAN(ctx) && opt_sans != NULL) { CMP_err("cannot have Subject Alternative Names both via -reqexts and via -sans"); - goto err; + return 0; } if (!set_gennames(ctx, opt_sans, "Subject Alternative Name")) - goto err; + return 0; if (opt_san_nodefault) { if (opt_sans != NULL) @@ -1770,19 +1687,19 @@ static int setup_request_ctx(OSSL_CMP_CTX *ctx, ENGINE *engine) if ((policy = OBJ_txt2obj(opt_policy_oids, 1)) == 0) { CMP_err1("unknown policy OID '%s'", opt_policy_oids); - goto err; + return 0; } if ((pinfo = POLICYINFO_new()) == NULL) { ASN1_OBJECT_free(policy); - goto err; + return 0; } pinfo->policyid = policy; if (!OSSL_CMP_CTX_push0_policy(ctx, pinfo)) { CMP_err1("cannot add policy with OID '%s'", opt_policy_oids); POLICYINFO_free(pinfo); - goto err; + return 0; } opt_policy_oids = next; } @@ -1798,7 +1715,7 @@ static int setup_request_ctx(OSSL_CMP_CTX *ctx, ENGINE *engine) load_csr_autofmt(opt_csr, "PKCS#10 CSR for p10cr"); if (csr == NULL) - goto err; + return 0; if (!OSSL_CMP_CTX_set1_p10CSR(ctx, csr)) { X509_REQ_free(csr); goto oom; @@ -1813,7 +1730,7 @@ static int setup_request_ctx(OSSL_CMP_CTX *ctx, ENGINE *engine) /* opt_keypass is needed if opt_oldcert is an encrypted PKCS#12 file */ if (oldcert == NULL) - goto err; + return 0; if (!OSSL_CMP_CTX_set1_oldCert(ctx, oldcert)) { X509_free(oldcert); goto oom; @@ -1829,7 +1746,6 @@ static int setup_request_ctx(OSSL_CMP_CTX *ctx, ENGINE *engine) oom: CMP_err("out of memory"); - err: return 0; } @@ -1905,33 +1821,36 @@ static int handle_opt_geninfo(OSSL_CMP_CTX *ctx) static int setup_client_ctx(OSSL_CMP_CTX *ctx, ENGINE *engine) { int ret = 0; + char *server = NULL, *port = NULL, *path = NULL, *used_path; + int portnum, ssl; char server_buf[200] = { '\0' }; char proxy_buf[200] = { '\0' }; char *proxy_host = NULL; char *proxy_port_str = NULL; if (opt_server == NULL) { - CMP_err("missing server address[:port]"); + CMP_err("missing -server option"); + goto err; + } + if (!OSSL_HTTP_parse_url(opt_server, &server, &port, &portnum, &path, &ssl)) goto err; - } else if ((server_port = - parse_addr(&opt_server, server_port, "server")) < 0) { + if (ssl && !opt_tls_used) { + CMP_err("missing -tls_used option since -server URL indicates https"); goto err; } - if (server_port != 0) - BIO_snprintf(server_port_s, sizeof(server_port_s), "%d", server_port); - if (!OSSL_CMP_CTX_set1_server(ctx, opt_server) - || !OSSL_CMP_CTX_set_serverPort(ctx, server_port) - || !OSSL_CMP_CTX_set1_serverPath(ctx, opt_path)) + strncpy(server_port, port, sizeof(server_port)); + used_path = opt_path != NULL ? opt_path : path; + if (!OSSL_CMP_CTX_set1_server(ctx, server) + || !OSSL_CMP_CTX_set_serverPort(ctx, portnum) + || !OSSL_CMP_CTX_set1_serverPath(ctx, used_path)) 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); + (void)BIO_snprintf(server_buf, sizeof(server_buf), "http%s://%s:%s/%s", + opt_tls_used ? "s" : "", server, port, + *used_path == '/' ? used_path + 1 : used_path); if (opt_proxy != NULL) (void)BIO_snprintf(proxy_buf, sizeof(proxy_buf), " via %s", opt_proxy); @@ -2032,7 +1951,7 @@ static int setup_client_ctx(OSSL_CMP_CTX *ctx, ENGINE *engine) (void)OSSL_CMP_CTX_set_http_cb_arg(ctx, info); /* info will be freed along with CMP ctx */ info->server = opt_server; - info->port = server_port_s; + info->port = server_port; info->use_proxy = opt_proxy != NULL; info->timeout = OSSL_CMP_CTX_get_option(ctx, OSSL_CMP_OPT_MSG_TIMEOUT); info->ssl_ctx = setup_ssl_ctx(ctx, engine); @@ -2062,6 +1981,9 @@ static int setup_client_ctx(OSSL_CMP_CTX *ctx, ENGINE *engine) ret = 1; err: + OPENSSL_free(server); + OPENSSL_free(port); + OPENSSL_free(path); OPENSSL_free(proxy_host); OPENSSL_free(proxy_port_str); return ret; @@ -2088,18 +2010,21 @@ static int write_cert(BIO *bio, X509 *cert) } /* - * writes out a stack of certs to the given file. + * If destFile != NULL writes out a stack of certs to the given file. + * In any case frees the certs. * Depending on options use either PEM or DER format, * where DER does not make much sense for writing more than one cert! - * Returns number of written certificates on success, 0 on error. + * Returns number of written certificates on success, -1 on error. */ -static int save_certs(OSSL_CMP_CTX *ctx, - STACK_OF(X509) *certs, char *destFile, char *desc) +static int save_free_certs(OSSL_CMP_CTX *ctx, + STACK_OF(X509) *certs, char *destFile, char *desc) { BIO *bio = NULL; int i; int n = sk_X509_num(certs); + if (destFile == NULL) + goto end; CMP_info3("received %d %s certificate(s), saving to file '%s'", n, desc, destFile); if (n > 1 && opt_certform != FORMAT_PEM) @@ -2109,19 +2034,20 @@ static int save_certs(OSSL_CMP_CTX *ctx, || !BIO_write_filename(bio, (char *)destFile)) { CMP_err1("could not open file '%s' for writing", destFile); n = -1; - goto err; + goto end; } for (i = 0; i < n; i++) { if (!write_cert(bio, sk_X509_value(certs, i))) { CMP_err1("cannot write certificate to file '%s'", destFile); n = -1; - goto err; + goto end; } } - err: + end: BIO_free(bio); + sk_X509_pop_free(certs, X509_free); return n; } @@ -2221,12 +2147,14 @@ static int read_config(void) const OPTIONS *opt; int provider_option; int verification_option; - + int start = OPT_VERBOSITY; /* - * starting with offset OPT_SECTION because OPT_CONFIG and OPT_SECTION would - * not make sense within the config file. They have already been handled. + * starting with offset OPT_VERBOSITY because OPT_CONFIG and OPT_SECTION + * would not make sense within the config file. + * Moreover, these two options and OPT_VERBOSITY have already been handled. */ - for (i = OPT_SECTION - OPT_HELP, opt = &cmp_options[OPT_SECTION]; + + for (i = start - OPT_HELP, opt = &cmp_options[start]; opt->name; i++, opt++) { if (!strcmp(opt->name, OPT_SECTION_STR) || !strcmp(opt->name, OPT_MORE_STR)) { @@ -2252,11 +2180,6 @@ static int read_config(void) continue; /* option not provided */ } break; - /* - * do not use '<' in cmp_options. Incorrect treatment - * somewhere in args_verify() can wrongly set badarg = 1 - */ - case '<': case 's': case 'M': txt = conf_get_string(conf, opt_section, opt->name); @@ -2365,8 +2288,8 @@ static int get_opts(int argc, char **argv) opt_help(cmp_options); return -1; case OPT_CONFIG: /* has already been handled */ - break; case OPT_SECTION: /* has already been handled */ + case OPT_VERBOSITY: /* has already been handled */ break; case OPT_SERVER: opt_server = opt_str("server"); @@ -2418,6 +2341,9 @@ static int get_opts(int argc, char **argv) case OPT_CERT: opt_cert = opt_str("cert"); break; + case OPT_OWN_TRUSTED: + opt_own_trusted = opt_str("own_trusted"); + break; case OPT_KEY: opt_key = opt_str("key"); break; @@ -2536,6 +2462,9 @@ static int get_opts(int argc, char **argv) case OPT_CERTOUT: opt_certout = opt_str("certout"); break; + case OPT_CHAINOUT: + opt_chainout = opt_str("chainout"); + break; case OPT_OLDCERT: opt_oldcert = opt_str("oldcert"); break; @@ -2697,15 +2626,20 @@ int cmp_main(int argc, char **argv) } /* - * handle OPT_CONFIG and OPT_SECTION upfront to take effect for other opts + * handle options -config, -section, and -verbosity upfront + * to take effect for other options */ for (i = 1; i < argc - 1; i++) { if (*argv[i] == '-') { if (!strcmp(argv[i] + 1, cmp_options[OPT_CONFIG - OPT_HELP].name)) - opt_config = argv[i + 1]; + opt_config = argv[++i]; else if (!strcmp(argv[i] + 1, cmp_options[OPT_SECTION - OPT_HELP].name)) - opt_section = argv[i + 1]; + opt_section = argv[++i]; + else if (strcmp(argv[i] + 1, + cmp_options[OPT_VERBOSITY - OPT_HELP].name) == 0 + && !set_verbosity(atoi(argv[++i]))) + goto err; } } if (opt_section[0] == '\0') /* empty string */ @@ -2780,6 +2714,7 @@ int cmp_main(int argc, char **argv) cmp_ctx = OSSL_CMP_CTX_new(app_get0_libctx(), app_get0_propq()); if (cmp_ctx == NULL) goto err; + OSSL_CMP_CTX_set_log_verbosity(cmp_ctx, opt_verbosity); if (!OSSL_CMP_CTX_set_log_cb(cmp_ctx, print_to_bio_out)) { CMP_err1("cannot set up error reporting and logging for %s", prog); goto err; @@ -2871,11 +2806,6 @@ int cmp_main(int argc, char **argv) } opt_server = mock_server; opt_proxy = "API"; - } else { - if (opt_server == NULL) { - CMP_err("missing -server option"); - goto err; - } } if (!setup_client_ctx(cmp_ctx, engine)) { @@ -2940,6 +2870,11 @@ int cmp_main(int argc, char **argv) OSSL_CMP_PKISI_BUFLEN); CMP_print(bio_err, + status == OSSL_CMP_PKISTATUS_accepted + ? OSSL_CMP_LOG_INFO : + status == OSSL_CMP_PKISTATUS_rejection + || status == OSSL_CMP_PKISTATUS_waiting + ? OSSL_CMP_LOG_ERR : OSSL_CMP_LOG_WARNING, status == OSSL_CMP_PKISTATUS_accepted ? "info" : status == OSSL_CMP_PKISTATUS_rejection ? "server error" : status == OSSL_CMP_PKISTATUS_waiting ? "internal error" @@ -2949,39 +2884,26 @@ int cmp_main(int argc, char **argv) OPENSSL_free(buf); } - if (opt_cacertsout != NULL) { - STACK_OF(X509) *certs = OSSL_CMP_CTX_get1_caPubs(cmp_ctx); - - if (sk_X509_num(certs) > 0 - && save_certs(cmp_ctx, certs, opt_cacertsout, "CA") < 0) { - sk_X509_pop_free(certs, X509_free); - goto err; - } - sk_X509_pop_free(certs, X509_free); - } - - if (opt_extracertsout != NULL) { - STACK_OF(X509) *certs = OSSL_CMP_CTX_get1_extraCertsIn(cmp_ctx); - if (sk_X509_num(certs) > 0 - && save_certs(cmp_ctx, certs, opt_extracertsout, - "extra") < 0) { - sk_X509_pop_free(certs, X509_free); - goto err; - } - sk_X509_pop_free(certs, X509_free); - } - - if (opt_certout != NULL && newcert != NULL) { + if (save_free_certs(cmp_ctx, OSSL_CMP_CTX_get1_caPubs(cmp_ctx), + opt_cacertsout, "CA") < 0) + goto err; + if (save_free_certs(cmp_ctx, OSSL_CMP_CTX_get1_extraCertsIn(cmp_ctx), + opt_extracertsout, "extra") < 0) + goto err; + if (newcert != NULL) { STACK_OF(X509) *certs = sk_X509_new_null(); - if (certs == NULL || !sk_X509_push(certs, newcert) - || save_certs(cmp_ctx, certs, opt_certout, - "enrolled") < 0) { + if (!X509_add_cert(certs, newcert, X509_ADD_FLAG_UP_REF)) { sk_X509_free(certs); goto err; } - sk_X509_free(certs); + if (save_free_certs(cmp_ctx, certs, opt_certout, "enrolled") < 0) + goto err; } + if (save_free_certs(cmp_ctx, OSSL_CMP_CTX_get1_newChain(cmp_ctx), + opt_chainout, "chain") < 0) + goto err; + if (!OSSL_CMP_CTX_reinit(cmp_ctx)) goto err; }