libmicrohttpd2

HTTP server C library (MHD 2.x, alpha)
Log | Files | Refs | README | LICENSE

commit 04a3cfce206a341c836223c0161add5a9bf8cc22
parent 16e14b86de3d7f429efe9423f73c8b15bc42ea8f
Author: Evgeny Grin (Karlson2k) <k2k@drgrin.dev>
Date:   Wed, 17 Dec 2025 21:33:50 +0100

OpenSSL backend: implemented support for custom profile in the configuration file

Diffstat:
Msrc/include/d_options.rec | 70++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/include/microhttpd2.h | 52++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/include/microhttpd2_generated_daemon_options.h | 192+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/include/microhttpd2_preamble.h.in | 10++++++++++
Msrc/mhd2/daemon_options.h | 20++++++++++++++++++++
Msrc/mhd2/daemon_set_options.c | 38++++++++++++++++++++++++++++++++++++++
Msrc/mhd2/tls_open_funcs.c | 567+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------
7 files changed, 820 insertions(+), 129 deletions(-)

diff --git a/src/include/d_options.rec b/src/include/d_options.rec @@ -253,6 +253,76 @@ Comment: Control ALPN for TLS connection. + Silently ignored for non-TLS. + By default ALPN is automatically used for TLS connections. +Name: tls_app_name +Value: 142 +Type: struct MHD_DaemonOptionValueTlsAppName +Comment: Provide application name to load dedicated section in TLS backend's configuration file. ++ Search for "System-wide configuration of the library" for GnuTLS documentation or ++ for "config, OPENSSL LIBRARY CONFIGURATION" for OpenSSL documentation. ++ If not specified the default backend configuration is used: ++ "@LIBMICROHTTPD" (if available), then "@SYSTEM" (if available) then default priorities, then "NORMAL" for GnuTLS; ++ "libmicrohttpd" (if available), then default name ("openssl_conf") for OpenSSL. ++ Ignored when MbedTLS is used as daemon's TLS backend. +Argument1: char *app_name +Description1: the name of the application, used as converted to ++ uppercase (with '@'-prefixed) for GnuTLS and as converted to ++ lowercase for OpenSSL; must not be longer than 127 characters +Argument2: enum MHD_Bool disable_fallback +Description2: forbid use fallback/default configuration if specified ++ configuration is not found; also forbid ignoring errors in the ++ configuration on TLS backends, which may ignoring configuration ++ errors +CustomSetter: /* custom setter */ ++ settings->tls_app_name.v_disable_fallback = ++ option->val.tls_app_name.v_disable_fallback; ++ if (NULL == option->val.tls_app_name.v_app_name) ++ return MHD_SC_CONFIGURATION_PARAM_NULL; ++ else ++ { ++ size_t len; ++ len = strlen (option->val.tls_app_name.v_app_name); ++ if (128 <= len) ++ return MHD_SC_CONFIGURATION_PARAM_TOO_LARGE; ++ settings->tls_app_name.v_app_name = (char *) malloc (len + 1u); ++ if (NULL == settings->tls_app_name.v_app_name) ++ return MHD_SC_DAEMON_MEM_ALLOC_FAILURE; ++ memcpy (settings->tls_app_name.v_app_name, ++ option->val.tls_app_name.v_app_name, ++ len + 1u); ++ } + +Name: tls_openssl_def_file +Value: 144 +Type: struct MHD_DaemonOptionValueTlsOsslDefFile +Comment: Set the configuration pathname for OpenSSL configuration file ++ Ignored OpenSSL is not used as daemon's TLS backend. +Argument1: char *pathname +Description1: the path and the name of the OpenSSL configuration file, ++ if only the name is provided then standard path for ++ configuration files is used, ++ could be NULL to use default configuration file pathname ++ or an empty (zero-size) string to disable file loading +Argument2: enum MHD_Bool disable_fallback +Description2: forbid use of fallback/default location and name of ++ the OpenSSL configuration file; also forbid initialisation without ++ configuration file +CustomSetter: /* custom setter */ ++ settings->tls_openssl_def_file.v_disable_fallback = ++ option->val.tls_openssl_def_file.v_disable_fallback; ++ if (NULL == option->val.tls_openssl_def_file.v_pathname) ++ settings->tls_openssl_def_file.v_pathname = NULL; ++ else ++ { ++ size_t len; ++ len = strlen (option->val.tls_openssl_def_file.v_pathname); ++ settings->tls_openssl_def_file.v_pathname = (char *) malloc (len + 1u); ++ if (NULL == settings->tls_openssl_def_file.v_pathname) ++ return MHD_SC_DAEMON_MEM_ALLOC_FAILURE; ++ memcpy (settings->tls_openssl_def_file.v_pathname, ++ option->val.tls_openssl_def_file.v_pathname, ++ len + 1u); ++ } + # Connection handling Name: DEFAULT_TIMEOUT diff --git a/src/include/microhttpd2.h b/src/include/microhttpd2.h @@ -1577,6 +1577,16 @@ enum MHD_FIXED_ENUM_MHD_SET_ MHD_StatusCode MHD_SC_CONFIGURATION_CONN_LIMIT_TOO_SMALL = 60026 , /** + * The provided configuration parameter is NULL, but it must be non-NULL + */ + MHD_SC_CONFIGURATION_PARAM_NULL = 60027 + , + /** + * The size of the provided configuration parameter is too large + */ + MHD_SC_CONFIGURATION_PARAM_TOO_LARGE = 60028 + , + /** * The application requested an unsupported TLS backend to be used. */ MHD_SC_TLS_BACKEND_UNSUPPORTED = 60030 @@ -4383,6 +4393,48 @@ MHD_D_OPTION_NO_ALPN ( ); /** + * Provide application name to load dedicated section in TLS backend's configuration file. + * Search for "System-wide configuration of the library" for GnuTLS documentation or + * for "config, OPENSSL LIBRARY CONFIGURATION" for OpenSSL documentation. + * If not specified the default backend configuration is used: + * "@LIBMICROHTTPD" (if available), then "@SYSTEM" (if available) then default priorities, then "NORMAL" for GnuTLS; + * "libmicrohttpd" (if available), then default name ("openssl_conf") for OpenSSL. + * Ignored when MbedTLS is used as daemon's TLS backend. + * @param app_name the name of the application, used as converted to + * uppercase (with '@'-prefixed) for GnuTLS and as converted to + * lowercase for OpenSSL; must not be longer than 127 characters + * @param disable_fallback forbid use fallback/default configuration if specified + * configuration is not found; also forbid ignoring errors in the + * configuration on TLS backends, which may ignoring configuration + * errors + * @return structure with the requested setting + */ +struct MHD_DaemonOptionAndValue +MHD_D_OPTION_TLS_APP_NAME ( + char *app_name, + enum MHD_Bool disable_fallback + ); + +/** + * Set the configuration pathname for OpenSSL configuration file + * Ignored OpenSSL is not used as daemon's TLS backend. + * @param pathname the path and the name of the OpenSSL configuration file, + * if only the name is provided then standard path for + * configuration files is used, + * could be NULL to use default configuration file pathname + * or an empty (zero-size) string to disable file loading + * @param disable_fallback forbid use of fallback/default location and name of + * the OpenSSL configuration file; also forbid initialisation without + * configuration file + * @return structure with the requested setting + */ +struct MHD_DaemonOptionAndValue +MHD_D_OPTION_TLS_OPENSSL_DEF_FILE ( + char *pathname, + enum MHD_Bool disable_fallback + ); + +/** * Specify inactivity timeout for connection. * When no activity for specified time on connection, it is closed * automatically. diff --git a/src/include/microhttpd2_generated_daemon_options.h b/src/include/microhttpd2_generated_daemon_options.h @@ -149,6 +149,25 @@ Works only when #MHD_D_OPTION_BIND_PORT() or #MHD_D_OPTION_BIND_SA() are used. , /** + * Provide application name to load dedicated section in TLS backend's configuration file. + * Search for "System-wide configuration of the library" for GnuTLS documentation or + * for "config, OPENSSL LIBRARY CONFIGURATION" for OpenSSL documentation. + * If not specified the default backend configuration is used: + * "@LIBMICROHTTPD" (if available), then "@SYSTEM" (if available) then default priorities, then "NORMAL" for GnuTLS; + * "libmicrohttpd" (if available), then default name ("openssl_conf") for OpenSSL. + * Ignored when MbedTLS is used as daemon's TLS backend. + */ + MHD_D_O_TLS_APP_NAME = 142 + , + + /** + * Set the configuration pathname for OpenSSL configuration file + * Ignored OpenSSL is not used as daemon's TLS backend. + */ + MHD_D_O_TLS_OPENSSL_DEF_FILE = 144 + , + + /** * Specify inactivity timeout for connection. * When no activity for specified time on connection, it is closed * automatically. @@ -492,6 +511,51 @@ struct MHD_DaemonOptionValueTlsPskCB }; /** + * Data for #MHD_D_O_TLS_APP_NAME + */ +struct MHD_DaemonOptionValueTlsAppName +{ + /** + * the name of the application, used as converted to + * uppercase (with '@'-prefixed) for GnuTLS and as converted to + * lowercase for OpenSSL; must not be longer than 127 characters + */ + char *v_app_name; + + /** + * forbid use fallback/default configuration if specified + * configuration is not found; also forbid ignoring errors in the + * configuration on TLS backends, which may ignoring configuration + * errors + */ + enum MHD_Bool v_disable_fallback; + +}; + +/** + * Data for #MHD_D_O_TLS_OPENSSL_DEF_FILE + */ +struct MHD_DaemonOptionValueTlsOsslDefFile +{ + /** + * the path and the name of the OpenSSL configuration file, + * if only the name is provided then standard path for + * configuration files is used, + * could be NULL to use default configuration file pathname + * or an empty (zero-size) string to disable file loading + */ + char *v_pathname; + + /** + * forbid use of fallback/default location and name of + * the OpenSSL configuration file; also forbid initialisation without + * configuration file + */ + enum MHD_Bool v_disable_fallback; + +}; + +/** * Data for #MHD_D_O_ACCEPT_POLICY */ struct MHD_DaemonOptionValueAcceptPol @@ -715,6 +779,24 @@ union MHD_DaemonOptionValue enum MHD_Bool no_alpn; /** + * Value for #MHD_D_O_TLS_APP_NAME. + * the name of the application, used as converted to + * uppercase (with '@'-prefixed) for GnuTLS and as converted to + * lowercase for OpenSSL; must not be longer than 127 characters + */ + struct MHD_DaemonOptionValueTlsAppName tls_app_name; + + /** + * Value for #MHD_D_O_TLS_OPENSSL_DEF_FILE. + * the path and the name of the OpenSSL configuration file, + * if only the name is provided then standard path for + * configuration files is used, + * could be NULL to use default configuration file pathname + * or an empty (zero-size) string to disable file loading + */ + struct MHD_DaemonOptionValueTlsOsslDefFile tls_openssl_def_file; + + /** * Value for #MHD_D_O_DEFAULT_TIMEOUT. * the in seconds, zero for no timeout */ @@ -1149,6 +1231,54 @@ Works only when #MHD_D_OPTION_BIND_PORT() or #MHD_D_OPTION_BIND_SA() are used. } \ MHD_RESTORE_WARN_COMPOUND_LITERALS_ MHD_RESTORE_WARN_AGGR_DYN_INIT_ /** + * Provide application name to load dedicated section in TLS backend's configuration file. + * Search for "System-wide configuration of the library" for GnuTLS documentation or + * for "config, OPENSSL LIBRARY CONFIGURATION" for OpenSSL documentation. + * If not specified the default backend configuration is used: + * "@LIBMICROHTTPD" (if available), then "@SYSTEM" (if available) then default priorities, then "NORMAL" for GnuTLS; + * "libmicrohttpd" (if available), then default name ("openssl_conf") for OpenSSL. + * Ignored when MbedTLS is used as daemon's TLS backend. + * @param app_name the name of the application, used as converted to + * uppercase (with '@'-prefixed) for GnuTLS and as converted to + * lowercase for OpenSSL; must not be longer than 127 characters + * @param disable_fallback forbid use fallback/default configuration if specified + * configuration is not found; also forbid ignoring errors in the + * configuration on TLS backends, which may ignoring configuration + * errors + * @return structure with the requested setting + */ +# define MHD_D_OPTION_TLS_APP_NAME(app_name,disable_fallback) \ + MHD_NOWARN_COMPOUND_LITERALS_ MHD_NOWARN_AGGR_DYN_INIT_ \ + (const struct MHD_DaemonOptionAndValue) \ + { \ + .opt = MHD_D_O_TLS_APP_NAME, \ + .val.tls_app_name.v_app_name = (app_name), \ + .val.tls_app_name.v_disable_fallback = (disable_fallback) \ + } \ + MHD_RESTORE_WARN_COMPOUND_LITERALS_ MHD_RESTORE_WARN_AGGR_DYN_INIT_ +/** + * Set the configuration pathname for OpenSSL configuration file + * Ignored OpenSSL is not used as daemon's TLS backend. + * @param pathname the path and the name of the OpenSSL configuration file, + * if only the name is provided then standard path for + * configuration files is used, + * could be NULL to use default configuration file pathname + * or an empty (zero-size) string to disable file loading + * @param disable_fallback forbid use of fallback/default location and name of + * the OpenSSL configuration file; also forbid initialisation without + * configuration file + * @return structure with the requested setting + */ +# define MHD_D_OPTION_TLS_OPENSSL_DEF_FILE(pathname,disable_fallback) \ + MHD_NOWARN_COMPOUND_LITERALS_ MHD_NOWARN_AGGR_DYN_INIT_ \ + (const struct MHD_DaemonOptionAndValue) \ + { \ + .opt = MHD_D_O_TLS_OPENSSL_DEF_FILE, \ + .val.tls_openssl_def_file.v_pathname = (pathname), \ + .val.tls_openssl_def_file.v_disable_fallback = (disable_fallback) \ + } \ + MHD_RESTORE_WARN_COMPOUND_LITERALS_ MHD_RESTORE_WARN_AGGR_DYN_INIT_ +/** * Specify inactivity timeout for connection. * When no activity for specified time on connection, it is closed * automatically. @@ -1939,6 +2069,68 @@ MHD_D_OPTION_NO_ALPN ( /** + * Provide application name to load dedicated section in TLS backend's configuration file. + * Search for "System-wide configuration of the library" for GnuTLS documentation or + * for "config, OPENSSL LIBRARY CONFIGURATION" for OpenSSL documentation. + * If not specified the default backend configuration is used: + * "@LIBMICROHTTPD" (if available), then "@SYSTEM" (if available) then default priorities, then "NORMAL" for GnuTLS; + * "libmicrohttpd" (if available), then default name ("openssl_conf") for OpenSSL. + * Ignored when MbedTLS is used as daemon's TLS backend. + * @param app_name the name of the application, used as converted to + * uppercase (with '@'-prefixed) for GnuTLS and as converted to + * lowercase for OpenSSL; must not be longer than 127 characters + * @param disable_fallback forbid use fallback/default configuration if specified + * configuration is not found; also forbid ignoring errors in the + * configuration on TLS backends, which may ignoring configuration + * errors + * @return structure with the requested setting + */ +static MHD_INLINE struct MHD_DaemonOptionAndValue +MHD_D_OPTION_TLS_APP_NAME ( + char *app_name, + enum MHD_Bool disable_fallback + ) +{ + struct MHD_DaemonOptionAndValue opt_val; + + opt_val.opt = MHD_D_O_TLS_APP_NAME; + opt_val.val.tls_app_name.v_app_name = app_name; + opt_val.val.tls_app_name.v_disable_fallback = disable_fallback; + + return opt_val; +} + + +/** + * Set the configuration pathname for OpenSSL configuration file + * Ignored OpenSSL is not used as daemon's TLS backend. + * @param pathname the path and the name of the OpenSSL configuration file, + * if only the name is provided then standard path for + * configuration files is used, + * could be NULL to use default configuration file pathname + * or an empty (zero-size) string to disable file loading + * @param disable_fallback forbid use of fallback/default location and name of + * the OpenSSL configuration file; also forbid initialisation without + * configuration file + * @return structure with the requested setting + */ +static MHD_INLINE struct MHD_DaemonOptionAndValue +MHD_D_OPTION_TLS_OPENSSL_DEF_FILE ( + char *pathname, + enum MHD_Bool disable_fallback + ) +{ + struct MHD_DaemonOptionAndValue opt_val; + + opt_val.opt = MHD_D_O_TLS_OPENSSL_DEF_FILE; + opt_val.val.tls_openssl_def_file.v_pathname = pathname; + opt_val.val.tls_openssl_def_file.v_disable_fallback = disable_fallback; + + return opt_val; +} + + +/** * Specify inactivity timeout for connection. * When no activity for specified time on connection, it is closed * automatically. diff --git a/src/include/microhttpd2_preamble.h.in b/src/include/microhttpd2_preamble.h.in @@ -1577,6 +1577,16 @@ enum MHD_FIXED_ENUM_MHD_SET_ MHD_StatusCode MHD_SC_CONFIGURATION_CONN_LIMIT_TOO_SMALL = 60026 , /** + * The provided configuration parameter is NULL, but it must be non-NULL + */ + MHD_SC_CONFIGURATION_PARAM_NULL = 60027 + , + /** + * The size of the provided configuration parameter is too large + */ + MHD_SC_CONFIGURATION_PARAM_TOO_LARGE = 60028 + , + /** * The application requested an unsupported TLS backend to be used. */ MHD_SC_TLS_BACKEND_UNSUPPORTED = 60030 diff --git a/src/mhd2/daemon_options.h b/src/mhd2/daemon_options.h @@ -130,6 +130,26 @@ struct DaemonOptions /** + * Value for #MHD_D_O_TLS_APP_NAME. + * the name of the application, used as converted to + * uppercase (with '@'-prefixed) for GnuTLS and as converted to + * lowercase for OpenSSL; must not be longer than 127 characters + */ + struct MHD_DaemonOptionValueTlsAppName tls_app_name; + + + /** + * Value for #MHD_D_O_TLS_OPENSSL_DEF_FILE. + * the path and the name of the OpenSSL configuration file, + * if only the name is provided then standard path for + * configuration files is used, + * could be NULL to use default configuration file pathname + * or an empty (zero-size) string to disable file loading + */ + struct MHD_DaemonOptionValueTlsOsslDefFile tls_openssl_def_file; + + + /** * Value for #MHD_D_O_DEFAULT_TIMEOUT. * the in seconds, zero for no timeout */ diff --git a/src/mhd2/daemon_set_options.c b/src/mhd2/daemon_set_options.c @@ -150,6 +150,44 @@ MHD_daemon_set_options ( case MHD_D_O_NO_ALPN: settings->no_alpn = option->val.no_alpn; continue; + case MHD_D_O_TLS_APP_NAME: + /* custom setter */ + settings->tls_app_name.v_disable_fallback = + option->val.tls_app_name.v_disable_fallback; + if (NULL == option->val.tls_app_name.v_app_name) + return MHD_SC_CONFIGURATION_PARAM_NULL; + else + { + size_t len; + len = strlen (option->val.tls_app_name.v_app_name); + if (128 <= len) + return MHD_SC_CONFIGURATION_PARAM_TOO_LARGE; + settings->tls_app_name.v_app_name = (char *) malloc (len + 1u); + if (NULL == settings->tls_app_name.v_app_name) + return MHD_SC_DAEMON_MEM_ALLOC_FAILURE; + memcpy (settings->tls_app_name.v_app_name, + option->val.tls_app_name.v_app_name, + len + 1u); + } + continue; + case MHD_D_O_TLS_OPENSSL_DEF_FILE: + /* custom setter */ + settings->tls_openssl_def_file.v_disable_fallback = + option->val.tls_openssl_def_file.v_disable_fallback; + if (NULL == option->val.tls_openssl_def_file.v_pathname) + settings->tls_openssl_def_file.v_pathname = NULL; + else + { + size_t len; + len = strlen (option->val.tls_openssl_def_file.v_pathname); + settings->tls_openssl_def_file.v_pathname = (char *) malloc (len + 1u); + if (NULL == settings->tls_openssl_def_file.v_pathname) + return MHD_SC_DAEMON_MEM_ALLOC_FAILURE; + memcpy (settings->tls_openssl_def_file.v_pathname, + option->val.tls_openssl_def_file.v_pathname, + len + 1u); + } + continue; case MHD_D_O_DEFAULT_TIMEOUT: settings->default_timeout = option->val.default_timeout; continue; diff --git a/src/mhd2/tls_open_funcs.c b/src/mhd2/tls_open_funcs.c @@ -57,7 +57,9 @@ #include "mhd_assert.h" #include "mhd_unreachable.h" +#include "mhd_assume.h" +#include "mhd_str.h" #include "mhd_conn_socket.h" #include "mhd_tls_internal.h" @@ -112,8 +114,17 @@ mhd_tls_open_dbg_print_errs (const char *msg, # define mhd_DBG_PRINT_TLS_ERRS() \ ERR_print_errors_cb (&mhd_tls_open_dbg_print_errs, NULL) + +# define mhd_DBG_PRINT_TLS_INFO_MSG(message) \ + do { (void) fprintf (stderr, "## OpenSSL info: %s\n", (message)); \ + (void) fflush (stderr);} while (0) +# define mhd_DBG_PRINT_TLS_INFO_PARAM1(message,param) \ + do { (void) fprintf (stderr, "## OpenSSL info: " message "\n", (param)); \ + (void) fflush (stderr);} while (0) #else # define mhd_DBG_PRINT_TLS_ERRS() ERR_clear_error () +# define mhd_DBG_PRINT_TLS_INFO_MSG(message) ((void) 0) +# define mhd_DBG_PRINT_TLS_INFO_PARAM1(message,param) ((void) 0) #endif /* ** Global initialisation / de-initialisation ** */ @@ -191,15 +202,398 @@ null_passwd_cb (char *buf, void *cls) { (void) buf; (void) size; (void) rwflag; (void) cls; /* Unused */ -#ifdef mhd_USE_TLS_DEBUG_MESSAGES - fprintf (stderr, "## OpenSSL: the NULL passphrase callback is called\n"); - fflush (stderr); -#endif + mhd_DBG_PRINT_TLS_INFO_MSG ("The NULL passphrase callback is called\n"); return 0; } /** + * Get non-default pathname for OpenSSL configuration file + * @param s the application-provided settings + * @param[out] conf_pathname set to the pathname on success + * @return #MHD_SC_OK on success, + * error code otherwise + */ +static MHD_FN_PAR_NONNULL_ALL_ +MHD_FN_PAR_OUT_ (2) MHD_FN_MUST_CHECK_RESULT_ enum MHD_StatusCode +daemon_get_conf_file (struct DaemonOptions *restrict s, + char **restrict conf_pathname) +{ + size_t name_len; + bool has_path; + + mhd_assert (NULL != s->tls_openssl_def_file.v_pathname); + +#ifndef MHD_SUPPORT_LOG_FUNCTIONALITY + (void) d; /* Used only for logging */ +#endif + + /* Handle custom pathname */ + + name_len = strlen (s->tls_openssl_def_file.v_pathname); + has_path = (NULL != memchr (s->tls_openssl_def_file.v_pathname, + '/', + name_len)); +#ifdef _WIN32 + has_path = has_path || (NULL != memchr (s->tls_openssl_def_file, + '\\', + name_len)); +#endif /* _WIN32 */ + + if ((! has_path) && (0u != name_len)) + { + const char *def_path; + size_t def_path_len; + + def_path = X509_get_default_cert_area (); + if (NULL == def_path) + { + mhd_DBG_PRINT_TLS_ERRS (); + mhd_DBG_PRINT_TLS_INFO_MSG ("X509_get_default_cert_area() returned NULL"); + return MHD_SC_TLS_DAEMON_INIT_FAILED; /* Unrealistic */ + } + + def_path_len = strlen (def_path); + + *conf_pathname = + (char *) OPENSSL_malloc (def_path_len + 1u + name_len + 1u); + if (NULL == *conf_pathname) + return MHD_SC_DAEMON_MEM_ALLOC_FAILURE; + + memcpy (*conf_pathname, + def_path, + def_path_len); + (*conf_pathname)[def_path_len] = '/'; + memcpy ((*conf_pathname) + def_path_len + 1u, + s->tls_openssl_def_file.v_pathname, + name_len + 1u); + + return MHD_SC_OK; + } + + *conf_pathname = (char *) OPENSSL_malloc (name_len + 1u); + if (NULL == *conf_pathname) + return MHD_SC_DAEMON_MEM_ALLOC_FAILURE; + + memcpy (*conf_pathname, + s->tls_openssl_def_file.v_pathname, + name_len + 1u); + + return MHD_SC_OK; +} + + +#ifdef mhd_TLS_OPEN_HAS_CONF_DIAG +# define mhd_LIBCTX_FORBIDS_FALLBACKS(d_tls) \ + (0 != OSSL_LIB_CTX_get_conf_diagnostics (d_tls->libctx)) +#else +# define mhd_LIBCTX_FORBIDS_FALLBACKS(d_tls) ((void) (d_tls), ! ! 0) +#endif /* ! mhd_TLS_OPEN_HAS_CONF_DIAG */ + + +static MHD_FN_PAR_NONNULL_ (1) MHD_FN_PAR_NONNULL_ (2) +MHD_FN_PAR_NONNULL_ (4) bool +daemon_load_conf_from_cfg (struct MHD_Daemon *restrict d, + const char *restrict filename, + const char *restrict app_name, + CONF *restrict cfg, + unsigned long load_flags, + bool log_missing_app_name) +{ +#ifndef MHD_SUPPORT_LOG_FUNCTIONALITY + (void) d; /* Used for logging only */ +# ifndef mhd_USE_TLS_DEBUG_MESSAGES + (void) filename; /* Used for logs only */ +# endif /* mhd_USE_TLS_DEBUG_MESSAGES */ +#endif /* MHD_SUPPORT_LOG_FUNCTIONALITY */ + + if (NULL != app_name) + { + if (NULL == NCONF_get_string (cfg, + NULL, + app_name)) + { + if (log_missing_app_name) + mhd_LOG_PRINT (d, + MHD_SC_TLS_LIB_CONF_WARNING, + mhd_LOG_FMT ("TLS library configuration '%s' " + "was not found in file '%s'"), + app_name, + filename); + else + mhd_DBG_PRINT_TLS_INFO_PARAM1 ("TLS library configuration '%s' " + "was not found in the configuration " + "file", + app_name); + return false; + } + mhd_DBG_PRINT_TLS_INFO_PARAM1 ("Trying to load configuration section " + "pointed by '%s'", + app_name); + } + else + mhd_DBG_PRINT_TLS_INFO_MSG ("Trying to load configuration section " + "pointed by default OpenSSL configuration"); + + if (1 != CONF_modules_load (cfg, + app_name, + load_flags)) + { + mhd_DBG_PRINT_TLS_ERRS (); + + mhd_LOG_PRINT (d, + MHD_SC_TLS_LIB_CONF_WARNING, + mhd_LOG_FMT ("Error loading TLS library " + "configuration '%s' " + "from file '%s'"), + app_name, + filename); + + return false; + } + + mhd_DBG_PRINT_TLS_INFO_MSG ("Successfully loaded OpenSSL configuration " + "from the configuration file"); + + return true; +} + + +static inline MHD_FN_PAR_NONNULL_ALL_ bool +is_conf_file_fallback_allowed ( + const struct mhd_TlsOpenDaemonData *restrict d_tls, + const struct DaemonOptions *restrict s) +{ + mhd_assert (NULL != d_tls->libctx); + + if (! s->tls_openssl_def_file.v_disable_fallback) + return false; + if (mhd_LIBCTX_FORBIDS_FALLBACKS (d_tls)) + return false; + return true; +} + + +static inline MHD_FN_PAR_NONNULL_ALL_ bool +is_conf_fallback_allowed (const struct mhd_TlsOpenDaemonData *restrict d_tls, + const struct DaemonOptions *restrict s) +{ + if (! s->tls_app_name.v_disable_fallback) + return false; + + return is_conf_file_fallback_allowed (d_tls, + s); +} + + +/** + * Load OpenSSL configuration from OpenSSL configuration file + * @param d the daemon handle + * @param d_tls the daemon TLS settings + * @param s the application-provided settings + * @param use_custom_conf_pathname choose application-provided pathname or + * TLS backend default pathname + * @return #MHD_SC_OK on success, + * #MHD_SC_TLS_LIB_CONF_WARNING if configuration was not loaded due to + * non-fatal error, + * error code otherwise + */ +static MHD_FN_PAR_NONNULL_ (1) MHD_FN_PAR_NONNULL_ (2) MHD_FN_PAR_NONNULL_ (3) +MHD_FN_MUST_CHECK_RESULT_ enum MHD_StatusCode +daemon_load_lib_conf (struct MHD_Daemon *restrict d, + struct mhd_TlsOpenDaemonData *restrict d_tls, + struct DaemonOptions *restrict s, + bool use_custom_conf_pathname) +{ + char *conf_pathname; + CONF *conf; + enum MHD_StatusCode ret; + + if (! use_custom_conf_pathname) + { + /* Use default pathname */ + conf_pathname = CONF_get1_default_config_file (); + + if (NULL == conf_pathname) + { + mhd_DBG_PRINT_TLS_ERRS (); + + ret = is_conf_fallback_allowed (d_tls, + s) + ? MHD_SC_TLS_LIB_CONF_WARNING : MHD_SC_TLS_DAEMON_INIT_FAILED; + + mhd_LOG_MSG (d, ret, \ + "Failed to get default configuration file pathname"); + } + else + ret = MHD_SC_OK; + } + else + ret = daemon_get_conf_file (s, + &conf_pathname); + + if (MHD_SC_OK != ret) + { + mhd_DBG_PRINT_TLS_INFO_MSG ("Failed to get configuration file pathname"); + return ret; + } + + mhd_ASSUME (NULL != conf_pathname); + mhd_DBG_PRINT_TLS_INFO_PARAM1 ("Trying '%s' as OpenSSL configuration file", + conf_pathname); + + if ('\0' == conf_pathname[0]) + { + /* A short-cut */ + OPENSSL_free (conf_pathname); + + if (NULL == s->tls_app_name.v_app_name) + return MHD_SC_OK; /* No special "application name" profile is needed */ + + if (! s->tls_app_name.v_disable_fallback) + return MHD_SC_OK; /* Initialisation allowed with default values */ + + /* Load of special "application name" profile is required */ + if (! use_custom_conf_pathname) + return MHD_SC_TLS_DAEMON_INIT_FAILED; /* No fallback pathname */ + + mhd_assert (NULL != s->tls_openssl_def_file.v_pathname); + + if (s->tls_openssl_def_file.v_disable_fallback) + return MHD_SC_TLS_DAEMON_INIT_FAILED; /* Fallback pathname is disallowed */ + + /* Try to use fallback pathname to load special "application name" profile */ + return MHD_SC_TLS_LIB_CONF_WARNING; + } + + conf = NCONF_new_ex (d_tls->libctx, + NULL); + if (NULL == conf) + { + mhd_DBG_PRINT_TLS_ERRS (); + + ret = is_conf_fallback_allowed (d_tls, + s) + ? MHD_SC_TLS_LIB_CONF_WARNING : MHD_SC_TLS_DAEMON_INIT_FAILED; + mhd_LOG_MSG (d, ret, \ + "Failed to create OpenSSL empty configuration object"); + } + + if (MHD_SC_OK == ret) + { + long err_line_num; + mhd_DBG_PRINT_TLS_INFO_PARAM1 ("Trying to load configuration file '%s'", + conf_pathname); + + if (0 >= NCONF_load (conf, + conf_pathname, + &err_line_num)) + { + mhd_DBG_PRINT_TLS_ERRS (); + + if (use_custom_conf_pathname) + ret = is_conf_file_fallback_allowed (d_tls, + s) + ? MHD_SC_TLS_LIB_CONF_WARNING : MHD_SC_TLS_DAEMON_INIT_FAILED; + else + ret = is_conf_fallback_allowed (d_tls, + s) + ? MHD_SC_TLS_LIB_CONF_WARNING : MHD_SC_TLS_DAEMON_INIT_FAILED; + + mhd_LOG_PRINT (d, + ret, + mhd_LOG_FMT ("Error loading TLS library configuration " + "file '%s' at line %ld"), + conf_pathname, + err_line_num); + } + + if (MHD_SC_OK == ret) + { + bool conf_loaded; + unsigned long flags; + + flags = 0u; + if (! s->tls_app_name.v_disable_fallback) + flags |= CONF_MFLAGS_IGNORE_ERRORS; + + conf_loaded = false; + + if (NULL != s->tls_app_name.v_app_name) + { + char app_name_lc[128]; + const size_t app_name_len = strlen (s->tls_app_name.v_app_name); + + /* Checked at the parameter processing */ + mhd_ASSUME ((128u) > app_name_len); + + mhd_str_to_lowercase_bin_n (app_name_len + 1u, /* '+1' for zero termination */ + s->tls_app_name.v_app_name, + app_name_lc); + + mhd_ASSUME ('\0' == app_name_lc[app_name_len]); + + conf_loaded = + daemon_load_conf_from_cfg (d, + conf_pathname, + app_name_lc, + conf, + flags, + s->tls_app_name.v_disable_fallback || + mhd_LIBCTX_FORBIDS_FALLBACKS (d_tls)); + + if (! conf_loaded && + (s->tls_app_name.v_disable_fallback || + mhd_LIBCTX_FORBIDS_FALLBACKS (d_tls))) + ret = MHD_SC_TLS_DAEMON_INIT_FAILED; + } + + if (! conf_loaded && + (MHD_SC_OK == ret)) + { + + mhd_assert ((NULL == s->tls_app_name.v_app_name) || + ! s->tls_app_name.v_disable_fallback); + + conf_loaded = + daemon_load_conf_from_cfg (d, + conf_pathname, + "libmicrohttpd", + conf, + flags, + false); + } + + if (! conf_loaded && + (MHD_SC_OK == ret)) + { + + mhd_assert ((NULL == s->tls_app_name.v_app_name) || + ! s->tls_app_name.v_disable_fallback); + + conf_loaded = + daemon_load_conf_from_cfg (d, + conf_pathname, + NULL, + conf, + flags, + true); + } + + if (! conf_loaded) + ret = MHD_SC_TLS_LIB_CONF_WARNING; + } + + NCONF_free (conf); + } + + OPENSSL_free (conf_pathname); + + return ret; +} + + +/** * Initialise OpenSSL library context * @param d the daemon handle * @param d_tls the daemon TLS settings @@ -212,12 +606,9 @@ daemon_init_lib_ctx (struct MHD_Daemon *restrict d, struct mhd_TlsOpenDaemonData *restrict d_tls, struct DaemonOptions *restrict s) { - bool fallback_config; - bool prevent_fallbacks; - char *conf_filename; - d_tls->libctx = OSSL_LIB_CTX_new (); + enum MHD_StatusCode ret; - (void) s; // TODO: support app-defined name for TLS backend profile + d_tls->libctx = OSSL_LIB_CTX_new (); if (NULL == d_tls->libctx) { @@ -227,127 +618,50 @@ daemon_init_lib_ctx (struct MHD_Daemon *restrict d, return MHD_SC_TLS_DAEMON_INIT_FAILED; } - prevent_fallbacks = false; -#ifdef mhd_TLS_OPEN_HAS_CONF_DIAG - prevent_fallbacks = prevent_fallbacks || - (0 != OSSL_LIB_CTX_get_conf_diagnostics (d_tls->libctx)); -#endif - - fallback_config = false; - ERR_clear_error (); - - conf_filename = CONF_get1_default_config_file (); - if (NULL == conf_filename) - mhd_DBG_PRINT_TLS_ERRS (); - else + if (NULL != s->tls_openssl_def_file.v_pathname) { - bool libctx_inited; - CONF *conf; + ret = daemon_load_lib_conf (d, + d_tls, + s, + true); - libctx_inited = false; - conf = NCONF_new_ex (d_tls->libctx, - NULL); - if (NULL == conf) - mhd_DBG_PRINT_TLS_ERRS (); - else - { - if (0 >= NCONF_load (conf, - conf_filename, - NULL)) - { - unsigned long err; + if (MHD_SC_OK == ret) + return MHD_SC_OK; - err = ERR_peek_last_error (); - mhd_DBG_PRINT_TLS_ERRS (); - libctx_inited = true; /* Nothing to initialise */ + if (MHD_SC_TLS_LIB_CONF_WARNING == ret) + ret = s->tls_openssl_def_file.v_disable_fallback + ? MHD_SC_TLS_DAEMON_INIT_FAILED : MHD_SC_OK; + } + else + ret = MHD_SC_OK; - mhd_NOWARN_USED_UNUSED + mhd_assert (MHD_SC_TLS_LIB_CONF_WARNING != ret); - if ((ERR_LIB_CONF != ERR_GET_LIB (err)) || - (CONF_R_NO_SUCH_FILE != ERR_GET_REASON (err))) - { - fallback_config = true; - mhd_LOG_PRINT (d, MHD_SC_TLS_LIB_CONF_WARNING, \ - mhd_LOG_FMT ("Error in TLS library configuration " - "file '%s'"), \ - conf_filename); - } + if (MHD_SC_OK == ret) + { + mhd_assert ((NULL == s->tls_openssl_def_file.v_pathname) || + ! s->tls_openssl_def_file.v_disable_fallback); - mhd_RESTORE_WARN_USED_UNUSED - } - else /* NCONF_load() succeed */ - { - (void) s; // TODO: support app-defined name for TLS backend profile - - if (! libctx_inited) - { - if (NULL != NCONF_get_section (conf, - "libmicrohttpd")) - { - if (0 < - CONF_modules_load (conf, - "libmicrohttpd", - 0)) - libctx_inited = true; - else - { - mhd_DBG_PRINT_TLS_ERRS (); - fallback_config = true; - mhd_LOG_PRINT (d, MHD_SC_TLS_LIB_CONF_WARNING, \ - mhd_LOG_FMT ("Failed to load configuration file " \ - "section [%s]"), \ - "libmicrohttpd"); - - libctx_inited = - (0 < CONF_modules_load (conf, - "libmicrohttpd", - CONF_MFLAGS_IGNORE_ERRORS)); - if (! libctx_inited) - mhd_DBG_PRINT_TLS_ERRS (); - } - } - } - if (! libctx_inited) - { - if (0 < - CONF_modules_load (conf, - NULL, - 0)) - libctx_inited = true; - else - { - mhd_DBG_PRINT_TLS_ERRS (); - fallback_config = true; - mhd_LOG_MSG (d, MHD_SC_TLS_LIB_CONF_WARNING, \ - "Failed to load configuration file default section"); - - libctx_inited = - (0 < CONF_modules_load (conf, - NULL, - CONF_MFLAGS_IGNORE_ERRORS)); - if (! libctx_inited) - mhd_DBG_PRINT_TLS_ERRS (); - } - } -#ifdef mhd_TLS_OPEN_HAS_CONF_DIAG - if (fallback_config && libctx_inited && ! prevent_fallbacks) - prevent_fallbacks = - (0 != OSSL_LIB_CTX_get_conf_diagnostics (d_tls->libctx)); -#endif /* mhd_TLS_OPEN_HAS_CONF_DIAG */ - } - NCONF_free (conf); - } - OPENSSL_free (conf_filename); + ret = daemon_load_lib_conf (d, + d_tls, + s, + false); - if (fallback_config && prevent_fallbacks) - libctx_inited = true; + if (MHD_SC_OK == ret) + return MHD_SC_OK; - if (libctx_inited) + if (MHD_SC_TLS_LIB_CONF_WARNING == ret) { - return MHD_SC_OK; /* Success exit point */ + if ((! s->tls_app_name.v_disable_fallback) && + (! s->tls_openssl_def_file.v_disable_fallback)) + return MHD_SC_OK; /* Load without configuration file */ + + ret = MHD_SC_TLS_DAEMON_INIT_FAILED; } } + mhd_assert (MHD_SC_TLS_LIB_CONF_WARNING != ret); + OSSL_LIB_CTX_free (d_tls->libctx); mhd_LOG_MSG (d, MHD_SC_TLS_DAEMON_INIT_FAILED, \ "Failed to initialise TLS library context"); @@ -380,28 +694,23 @@ daemon_deinit_lib_ctx (struct mhd_TlsOpenDaemonData *restrict d_tls) 'h', '3' /* Registered value for HTTP/3 */ #endif /* Disabled code */ -#ifdef MHD_SUPPORT_HTTP2 -static const char alpn_code_http2[] = { mhd_ALPN_CODE_HTTP2 }; -#endif /* MHD_SUPPORT_HTTP2 */ -static const char alpn_code_http1_1[] = { mhd_ALPN_CODE_HTTP1_1 }; -static const char alpn_code_http1_0[] = { mhd_ALPN_CODE_HTTP1_0 }; #ifdef MHD_SUPPORT_HTTP2 static const unsigned char alpn_list_http2_1x[] = { - sizeof(alpn_code_http2), mhd_ALPN_CODE_HTTP2 + mhd_ALPN_H2_LEN, mhd_ALPN_CODE_HTTP2 , - sizeof(alpn_code_http1_1), mhd_ALPN_CODE_HTTP1_1 + mhd_ALPN_H1_1_LEN, mhd_ALPN_CODE_HTTP1_1 , - sizeof(alpn_code_http1_0), mhd_ALPN_CODE_HTTP1_0 + mhd_ALPN_H1_0_LEN, mhd_ALPN_CODE_HTTP1_0 }; static const unsigned char alpn_list_http2_only[] = { - sizeof(alpn_code_http2), mhd_ALPN_CODE_HTTP2 + mhd_ALPN_H2_LEN, mhd_ALPN_CODE_HTTP2 }; #endif /* MHD_SUPPORT_HTTP2 */ static const unsigned char alpn_list_http1x_only[] = { - sizeof(alpn_code_http1_1), mhd_ALPN_CODE_HTTP1_1 + mhd_ALPN_H1_1_LEN, mhd_ALPN_CODE_HTTP1_1 , - sizeof(alpn_code_http1_0), mhd_ALPN_CODE_HTTP1_0 + mhd_ALPN_H1_0_LEN, mhd_ALPN_CODE_HTTP1_0 }; #ifndef OPENSSL_NO_NEXTPROTONEG