Fix CMP -days option range checking and test failing with enable-ubsan
[openssl.git] / apps / cmp.c
index 9e40534995d152b4bcdee8aede5bd5aa209f5072..05fae77d38baa62c1acdceb1bbdc0da5fefc156a 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * 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
  *
@@ -46,157 +46,6 @@ DEFINE_STACK_OF(X509)
 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 */
@@ -212,13 +61,6 @@ static int read_config(void);
 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,
@@ -505,16 +347,16 @@ const OPTIONS cmp_options[] = {
 
     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, '-',
@@ -832,7 +674,7 @@ static EVP_PKEY *load_key_pwd(const char *uri, int format,
                               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;
@@ -1795,8 +1637,7 @@ static SSL_CTX *setup_ssl_ctx(OSSL_CMP_CTX *ctx, ENGINE *e)
 
         /*
          * 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");
@@ -2039,9 +1880,12 @@ static int setup_request_ctx(OSSL_CMP_CTX *ctx, ENGINE *e)
         }
     }
 
-    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");
@@ -2255,9 +2099,12 @@ static int setup_client_ctx(OSSL_CMP_CTX *ctx, ENGINE *e)
         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)
@@ -2379,7 +2226,7 @@ static int setup_client_ctx(OSSL_CMP_CTX *ctx, ENGINE *e)
     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;
@@ -3089,7 +2936,7 @@ int cmp_main(int argc, char **argv)
     }
 
     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) {
@@ -3135,12 +2982,13 @@ int cmp_main(int argc, char **argv)
         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)
@@ -3149,17 +2997,32 @@ int cmp_main(int argc, char **argv)
             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;
         }