libmicrohttpd2

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

tls_open_funcs.c (55729B)


      1 /* SPDX-License-Identifier: LGPL-2.1-or-later OR (GPL-2.0-or-later WITH eCos-exception-2.0) */
      2 /*
      3   This file is part of GNU libmicrohttpd.
      4   Copyright (C) 2024-2025 Evgeny Grin (Karlson2k)
      5 
      6   GNU libmicrohttpd is free software; you can redistribute it and/or
      7   modify it under the terms of the GNU Lesser General Public
      8   License as published by the Free Software Foundation; either
      9   version 2.1 of the License, or (at your option) any later version.
     10 
     11   GNU libmicrohttpd is distributed in the hope that it will be useful,
     12   but WITHOUT ANY WARRANTY; without even the implied warranty of
     13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     14   Lesser General Public License for more details.
     15 
     16   Alternatively, you can redistribute GNU libmicrohttpd and/or
     17   modify it under the terms of the GNU General Public License as
     18   published by the Free Software Foundation; either version 2 of
     19   the License, or (at your option) any later version, together
     20   with the eCos exception, as follows:
     21 
     22     As a special exception, if other files instantiate templates or
     23     use macros or inline functions from this file, or you compile this
     24     file and link it with other works to produce a work based on this
     25     file, this file does not by itself cause the resulting work to be
     26     covered by the GNU General Public License. However the source code
     27     for this file must still be made available in accordance with
     28     section (3) of the GNU General Public License v2.
     29 
     30     This exception does not invalidate any other reasons why a work
     31     based on this file might be covered by the GNU General Public
     32     License.
     33 
     34   You should have received copies of the GNU Lesser General Public
     35   License and the GNU General Public License along with this library;
     36   if not, see <https://www.gnu.org/licenses/>.
     37 */
     38 
     39 /**
     40  * @file src/mhd2/tls_open_funcs.c
     41  * @brief  The implementation of OpenSSL wrapper functions
     42  * @author Karlson2k (Evgeny Grin)
     43  */
     44 
     45 #include "mhd_sys_options.h"
     46 
     47 #include "sys_bool_type.h"
     48 #include "sys_base_types.h"
     49 
     50 #include "compat_calloc.h"
     51 #include "sys_malloc.h"
     52 #include <string.h>
     53 
     54 #ifdef mhd_USE_TLS_DEBUG_MESSAGES
     55 #  include <stdio.h> /* For TLS debug printing */
     56 #endif
     57 
     58 #include "mhd_assert.h"
     59 #include "mhd_unreachable.h"
     60 #include "mhd_assume.h"
     61 
     62 #include "mhd_str.h"
     63 #include "mhd_conn_socket.h"
     64 
     65 #include "mhd_tls_internal.h"
     66 
     67 #include "tls_open_tls_lib.h"
     68 
     69 #include "mhd_tls_ver_stct.h"
     70 
     71 #include "tls_open_daemon_data.h"
     72 #include "tls_open_conn_data.h"
     73 #include "tls_open_funcs.h"
     74 
     75 #include "daemon_options.h"
     76 
     77 #include "daemon_logger.h"
     78 
     79 #include "microhttpd2_portability.h"
     80 #include "mhd_public_api.h"
     81 
     82 #if defined(HAVE_WUSED_BUT_MARKED_UNUSED) && defined(MHD_WARN_IGNORE_STYLE_GCC)
     83 #  define mhd_NOWARN_USED_UNUSED   \
     84           MHD_WARN_PUSH_ MHD_WARN_IGNORE_ ("-Wused-but-marked-unused")
     85 #  define mhd_RESTORE_WARN_USED_UNUSED MHD_WARN_POP_
     86 #else
     87 #  define mhd_NOWARN_USED_UNUSED   /* empty */
     88 #  define mhd_RESTORE_WARN_USED_UNUSED   /* empty */
     89 #endif
     90 
     91 #ifdef mhd_USE_TLS_DEBUG_MESSAGES
     92 
     93 static MHD_FN_PAR_NONNULL_ (1) int
     94 mhd_tls_open_dbg_print_errs (const char *msg,
     95                              size_t msg_len,
     96                              void *cls)
     97 {
     98   int ret;
     99   int print_size = (int)msg_len;
    100 
    101   (void)cls;  /* Not used */
    102 
    103   if ((print_size < 0)
    104       || (msg_len != (unsigned int)print_size))
    105     print_size = (int)((~((unsigned int)0u)) >> 1);
    106 
    107   ret = fprintf (stderr,
    108                  "## OpenSSL error: %.*s\n",
    109                  print_size, msg);
    110   (void)fflush (stderr);
    111   return ret;
    112 }
    113 
    114 
    115 #  define mhd_DBG_PRINT_TLS_ERRS() \
    116           ERR_print_errors_cb (&mhd_tls_open_dbg_print_errs, NULL)
    117 
    118 #  define mhd_DBG_PRINT_TLS_INFO_MSG(message) \
    119           do { (void) fprintf (stderr, "## OpenSSL info: %s\n", (message)); \
    120                (void) fflush (stderr);} while (0)
    121 #  define mhd_DBG_PRINT_TLS_INFO_PARAM1(message, param) \
    122      do { (void) fprintf (stderr, "## OpenSSL info: " message "\n", (param)); \
    123           (void) fflush (stderr);} while (0)
    124 #else
    125 #  define mhd_DBG_PRINT_TLS_ERRS()      ERR_clear_error ()
    126 #  define mhd_DBG_PRINT_TLS_INFO_MSG(message)       ((void) 0)
    127 #  define mhd_DBG_PRINT_TLS_INFO_PARAM1(message, param)  ((void) 0)
    128 #endif
    129 
    130 /* ** Global initialisation / de-initialisation ** */
    131 
    132 static bool openssl_lib_inited = false;
    133 
    134 MHD_INTERNAL void
    135 mhd_tls_open_global_init_once (void)
    136 {
    137   const unsigned long ver_num = OpenSSL_version_num ();
    138   /* Make sure that used shared OpenSSL library has least the same version as
    139      MHD was configured for. Fail if the version is earlier. */
    140   openssl_lib_inited = ((0x900000UL < ver_num) /* Versions before 3.0 */
    141                         && (OPENSSL_VERSION_NUMBER <= ver_num));
    142 
    143   /* The call of OPENSSL_init_ssl() typically not needed, but it won't hurt
    144      if library was initialised automatically.
    145      In some exotic situations automatic initialisation could fail, and
    146      this call would make sure that the library is initialised before used. */
    147   openssl_lib_inited = openssl_lib_inited
    148                        && (0 < OPENSSL_init_ssl (0, NULL));
    149 }
    150 
    151 
    152 MHD_INTERNAL MHD_FN_PURE_ bool
    153 mhd_tls_open_is_inited_fine (void)
    154 {
    155   return openssl_lib_inited;
    156 }
    157 
    158 
    159 /* ** Daemon initialisation / de-initialisation ** */
    160 
    161 /**
    162  * Check application-provided daemon TLS settings
    163  * @param d the daemon handle
    164  * @param sk_edge_trigg the sockets polling uses edge-triggering
    165  * @param s the application-provided settings
    166  * @return #MHD_SC_OK on success,
    167  *         error code otherwise
    168  */
    169 static MHD_FN_PAR_NONNULL_ALL_ MHD_FN_MUST_CHECK_RESULT_ enum MHD_StatusCode
    170 check_app_tls_settings (struct MHD_Daemon *restrict d,
    171                         bool sk_edge_trigg,
    172                         struct DaemonOptions *restrict s)
    173 {
    174   mhd_assert (MHD_TLS_BACKEND_NONE != s->tls);
    175   mhd_assert ((MHD_TLS_BACKEND_OPENSSL == s->tls) \
    176               || (MHD_TLS_BACKEND_ANY == s->tls));
    177   if (NULL == s->tls_cert_key.v_mem_cert)
    178   {
    179     mhd_LOG_MSG (d, MHD_SC_TLS_CONF_BAD_CERT, \
    180                  "No valid TLS certificate is provided");
    181     return MHD_SC_TLS_CONF_BAD_CERT;
    182   }
    183   mhd_assert (NULL != s->tls_cert_key.v_mem_key);
    184 
    185   if (sk_edge_trigg)
    186   {
    187     mhd_LOG_MSG (d, MHD_SC_TLS_BACKEND_DAEMON_INCOMPATIBLE_SETTINGS, \
    188                  "Edge-triggered sockets polling cannot be used "
    189                  "with OpenSSL backend");
    190     return MHD_SC_TLS_BACKEND_DAEMON_INCOMPATIBLE_SETTINGS;
    191   }
    192 
    193   return MHD_SC_OK;
    194 }
    195 
    196 
    197 /* Helper to prevent password prompts in terminal */
    198 static int
    199 null_passwd_cb (char *buf,
    200                 int size,
    201                 int rwflag,
    202                 void *cls)
    203 {
    204   (void)buf;
    205   (void)size;
    206   (void)rwflag;
    207   (void)cls;                                          /* Unused */
    208   mhd_DBG_PRINT_TLS_INFO_MSG ("The NULL passphrase callback is called\n");
    209   return 0;
    210 }
    211 
    212 
    213 /**
    214  * Create new empty OpenSSL library context
    215  * @param d the daemon handle
    216  * @param d_tls the daemon TLS settings
    217  * @return 'true' on success,
    218  *         'false' otherwise
    219  */
    220 static MHD_FN_PAR_NONNULL_ALL_ MHD_FN_MUST_CHECK_RESULT_ bool
    221 create_lib_ctx (struct MHD_Daemon *restrict d,
    222                 struct mhd_TlsOpenDaemonData *restrict d_tls)
    223 {
    224 #ifndef MHD_SUPPORT_LOG_FUNCTIONALITY
    225   (void)d;  /* Used for logging only */
    226 #endif /* MHD_SUPPORT_LOG_FUNCTIONALITY */
    227   mhd_assert (NULL == d_tls->libctx);
    228 
    229   d_tls->libctx = OSSL_LIB_CTX_new ();
    230 
    231   if (NULL == d_tls->libctx)
    232   {
    233     mhd_DBG_PRINT_TLS_ERRS ();
    234     mhd_LOG_MSG (d, MHD_SC_TLS_DAEMON_INIT_FAILED, \
    235                  "Failed to create TLS library context");
    236     return false;
    237   }
    238   return true;
    239 }
    240 
    241 
    242 /**
    243  * Reset OpenSSL library context.
    244  *
    245  * This function must not be called if library context is being used.
    246  * @param d the daemon handle
    247  * @param d_tls the daemon TLS settings
    248  * @return 'true' on success,
    249  *         'false' otherwise
    250  */
    251 static MHD_FN_PAR_NONNULL_ALL_ MHD_FN_MUST_CHECK_RESULT_ bool
    252 reset_lib_ctx (struct MHD_Daemon *restrict d,
    253                struct mhd_TlsOpenDaemonData *restrict d_tls)
    254 {
    255   mhd_assert (NULL != d_tls->libctx);
    256 
    257   OSSL_LIB_CTX_free (d_tls->libctx);
    258   d_tls->libctx = NULL;
    259 
    260   return create_lib_ctx (d,
    261                          d_tls);
    262 }
    263 
    264 
    265 /**
    266  * Get non-default pathname for OpenSSL configuration file
    267  * @param s the application-provided settings
    268  * @param[out] conf_pathname set to the pathname on success
    269  * @return #MHD_SC_OK on success,
    270  *         error code otherwise
    271  */
    272 static MHD_FN_PAR_NONNULL_ALL_
    273 MHD_FN_PAR_OUT_ (2) MHD_FN_MUST_CHECK_RESULT_ enum MHD_StatusCode
    274 daemon_get_conf_file (struct DaemonOptions *restrict s,
    275                       char **restrict conf_pathname)
    276 {
    277   size_t name_len;
    278   bool has_path;
    279 
    280   mhd_assert (NULL != s->tls_openssl_def_file.v_pathname);
    281 
    282 #ifndef MHD_SUPPORT_LOG_FUNCTIONALITY
    283   (void)d;  /* Used only for logging */
    284 #endif
    285 
    286   /* Handle custom pathname */
    287 
    288   name_len = strlen (s->tls_openssl_def_file.v_pathname);
    289   has_path = (NULL != memchr (s->tls_openssl_def_file.v_pathname,
    290                               '/',
    291                               name_len));
    292 #ifdef _WIN32
    293   has_path = has_path || (NULL != memchr (s->tls_openssl_def_file,
    294                                           '\\',
    295                                           name_len));
    296 #endif /* _WIN32 */
    297 
    298   if ((!has_path) && (0u != name_len))
    299   {
    300     const char *def_path;
    301     size_t def_path_len;
    302 
    303     def_path = X509_get_default_cert_area ();
    304     if (NULL == def_path)
    305     {
    306       mhd_DBG_PRINT_TLS_ERRS ();
    307       mhd_DBG_PRINT_TLS_INFO_MSG ("X509_get_default_cert_area() returned NULL");
    308       return MHD_SC_TLS_DAEMON_INIT_FAILED; /* Unrealistic */
    309     }
    310 
    311     def_path_len = strlen (def_path);
    312 
    313     *conf_pathname =
    314       (char *)OPENSSL_malloc (def_path_len + 1u + name_len + 1u);
    315     if (NULL == *conf_pathname)
    316       return MHD_SC_DAEMON_MEM_ALLOC_FAILURE;
    317 
    318     memcpy (*conf_pathname,
    319             def_path,
    320             def_path_len);
    321     (*conf_pathname)[def_path_len] = '/';
    322     memcpy ((*conf_pathname) + def_path_len + 1u,
    323             s->tls_openssl_def_file.v_pathname,
    324             name_len + 1u);
    325 
    326     return MHD_SC_OK;
    327   }
    328 
    329   *conf_pathname = (char *)OPENSSL_malloc (name_len + 1u);
    330   if (NULL == *conf_pathname)
    331     return MHD_SC_DAEMON_MEM_ALLOC_FAILURE;
    332 
    333   memcpy (*conf_pathname,
    334           s->tls_openssl_def_file.v_pathname,
    335           name_len + 1u);
    336 
    337   return MHD_SC_OK;
    338 }
    339 
    340 
    341 #ifdef mhd_TLS_OPEN_HAS_CONF_DIAG
    342 #  define mhd_LIBCTX_FORBIDS_FALLBACKS(d_tls) \
    343           (0 != OSSL_LIB_CTX_get_conf_diagnostics (d_tls->libctx))
    344 #else
    345 #  define mhd_LIBCTX_FORBIDS_FALLBACKS(d_tls)   ((void) (d_tls), ! ! 0)
    346 #endif /* ! mhd_TLS_OPEN_HAS_CONF_DIAG */
    347 
    348 
    349 static MHD_FN_PAR_NONNULL_ (1) MHD_FN_PAR_NONNULL_ (2)
    350 MHD_FN_PAR_NONNULL_ (4) bool
    351 daemon_load_conf_from_cfg (struct MHD_Daemon *restrict d,
    352                            const char *restrict filename,
    353                            const char *restrict app_name,
    354                            CONF *restrict cfg,
    355                            unsigned long load_flags,
    356                            bool log_missing_app_name)
    357 {
    358 #ifndef MHD_SUPPORT_LOG_FUNCTIONALITY
    359   (void)d;  /* Used for logging only */
    360 #  ifndef mhd_USE_TLS_DEBUG_MESSAGES
    361   (void)filename;  /* Used for logs only */
    362 #  endif /* mhd_USE_TLS_DEBUG_MESSAGES */
    363 #endif /* MHD_SUPPORT_LOG_FUNCTIONALITY */
    364 
    365   if (NULL != app_name)
    366   {
    367     if (NULL == NCONF_get_string (cfg,
    368                                   NULL,
    369                                   app_name))
    370     {
    371       if (log_missing_app_name)
    372         mhd_LOG_PRINT (d,
    373                        MHD_SC_TLS_LIB_CONF_WARNING,
    374                        mhd_LOG_FMT ("TLS library configuration '%s' "
    375                                     "was not found in file '%s'"),
    376                        app_name,
    377                        filename);
    378       else
    379         mhd_DBG_PRINT_TLS_INFO_PARAM1 ("TLS library configuration '%s' "
    380                                        "was not found in the configuration "
    381                                        "file",
    382                                        app_name);
    383       return false;
    384     }
    385     mhd_DBG_PRINT_TLS_INFO_PARAM1 ("Trying to load configuration section "
    386                                    "pointed by '%s'",
    387                                    app_name);
    388   }
    389   else
    390     mhd_DBG_PRINT_TLS_INFO_MSG ("Trying to load configuration section "
    391                                 "pointed by default OpenSSL configuration");
    392 
    393   if (1 != CONF_modules_load (cfg,
    394                               app_name,
    395                               load_flags))
    396   {
    397     mhd_DBG_PRINT_TLS_ERRS ();
    398 
    399     mhd_LOG_PRINT (d,
    400                    MHD_SC_TLS_LIB_CONF_WARNING,
    401                    mhd_LOG_FMT ("Error loading TLS library "
    402                                 "configuration '%s' "
    403                                 "from file '%s'"),
    404                    app_name,
    405                    filename);
    406 
    407     return false;
    408   }
    409 
    410   mhd_DBG_PRINT_TLS_INFO_MSG ("Successfully loaded OpenSSL configuration "
    411                               "from the configuration file");
    412 
    413   return true;
    414 }
    415 
    416 
    417 static MHD_FN_PAR_NONNULL_ALL_
    418 MHD_FN_PAR_INOUT_ (2) MHD_FN_PAR_INOUT_ (4) bool
    419 cfg_reset_and_reload (struct MHD_Daemon *restrict d,
    420                       struct mhd_TlsOpenDaemonData *restrict d_tls,
    421                       const char *restrict filename,
    422                       CONF **restrict cfg_ptr)
    423 {
    424 #ifndef MHD_SUPPORT_LOG_FUNCTIONALITY
    425   (void)d;  /* Used for logging only */
    426 #endif /* MHD_SUPPORT_LOG_FUNCTIONALITY */
    427   mhd_assert (NULL != *cfg_ptr);
    428 
    429   mhd_DBG_PRINT_TLS_INFO_MSG ("Resetting library CTX, CONF and reloading "
    430                               "configuration file");
    431 
    432   /* Destroy old cfg, which is connected to the library CTX */
    433   NCONF_free (*cfg_ptr);
    434   *cfg_ptr = NULL;
    435 
    436   /* Reset OpenSSL library CTX, which may have partially applied configuration */
    437   if (!reset_lib_ctx (d,
    438                       d_tls))
    439     return false;
    440 
    441   /* Create a new cfg connected to the new CTX */
    442   *cfg_ptr = NCONF_new_ex (d_tls->libctx,
    443                            NULL);
    444   if (NULL == *cfg_ptr)
    445   {
    446     mhd_DBG_PRINT_TLS_ERRS ();
    447 
    448     mhd_DBG_PRINT_TLS_INFO_MSG ("Failed to create a new OpenSSL CONF");
    449     return false;
    450   }
    451 
    452   if (0 >= NCONF_load (*cfg_ptr,
    453                        filename,
    454                        NULL))
    455   {
    456     mhd_DBG_PRINT_TLS_ERRS ();
    457 
    458     mhd_DBG_PRINT_TLS_INFO_PARAM1 ("Failed to reload configuration file '%s'",
    459                                    filename);
    460     return false;
    461   }
    462 
    463   return true;
    464 }
    465 
    466 
    467 static inline MHD_FN_PAR_NONNULL_ALL_ bool
    468 is_conf_file_fallback_allowed (
    469   const struct mhd_TlsOpenDaemonData *restrict d_tls,
    470   const struct DaemonOptions *restrict s)
    471 {
    472   mhd_assert (NULL != d_tls->libctx);
    473 
    474   if (!s->tls_openssl_def_file.v_disable_fallback)
    475     return false;
    476   if (mhd_LIBCTX_FORBIDS_FALLBACKS (d_tls))
    477     return false;
    478   return true;
    479 }
    480 
    481 
    482 static inline MHD_FN_PAR_NONNULL_ALL_ bool
    483 is_conf_fallback_allowed (const struct mhd_TlsOpenDaemonData *restrict d_tls,
    484                           const struct DaemonOptions *restrict s)
    485 {
    486   if (!s->tls_app_name.v_disable_fallback)
    487     return false;
    488 
    489   return is_conf_file_fallback_allowed (d_tls,
    490                                         s);
    491 }
    492 
    493 
    494 /**
    495  * Load OpenSSL configuration from OpenSSL configuration file
    496  * @param d the daemon handle
    497  * @param d_tls the daemon TLS settings
    498  * @param s the application-provided settings
    499  * @param use_custom_conf_pathname choose application-provided pathname or
    500  *                                 TLS backend default pathname
    501  * @return #MHD_SC_OK on success,
    502  *         #MHD_SC_TLS_LIB_CONF_WARNING if configuration was not loaded due to
    503  *                                      non-fatal error,
    504  *         error code otherwise
    505  */
    506 static MHD_FN_PAR_NONNULL_ (1) MHD_FN_PAR_NONNULL_ (2) MHD_FN_PAR_NONNULL_ (3)
    507 MHD_FN_MUST_CHECK_RESULT_ enum MHD_StatusCode
    508 daemon_load_lib_conf (struct MHD_Daemon *restrict d,
    509                       struct mhd_TlsOpenDaemonData *restrict d_tls,
    510                       struct DaemonOptions *restrict s,
    511                       bool use_custom_conf_pathname)
    512 {
    513   char *conf_pathname;
    514   CONF *conf;
    515   enum MHD_StatusCode ret;
    516 
    517   if (!use_custom_conf_pathname)
    518   {
    519     /* Use default pathname */
    520     conf_pathname = CONF_get1_default_config_file ();
    521 
    522     if (NULL == conf_pathname)
    523     {
    524       mhd_DBG_PRINT_TLS_ERRS ();
    525 
    526       ret = is_conf_fallback_allowed (d_tls,
    527                                       s)
    528              ? MHD_SC_TLS_LIB_CONF_WARNING : MHD_SC_TLS_DAEMON_INIT_FAILED;
    529 
    530       mhd_LOG_MSG (d, ret, \
    531                    "Failed to get default configuration file pathname");
    532     }
    533     else
    534       ret = MHD_SC_OK;
    535   }
    536   else
    537     ret = daemon_get_conf_file (s,
    538                                 &conf_pathname);
    539 
    540   if (MHD_SC_OK != ret)
    541   {
    542     mhd_DBG_PRINT_TLS_INFO_MSG ("Failed to get configuration file pathname");
    543     return ret;
    544   }
    545 
    546   mhd_ASSUME (NULL != conf_pathname);
    547   mhd_DBG_PRINT_TLS_INFO_PARAM1 ("Trying '%s' as OpenSSL configuration file",
    548                                  conf_pathname);
    549 
    550   if ('\0' == conf_pathname[0])
    551   {
    552     OPENSSL_free (conf_pathname); /* A short-cut */
    553 
    554     if (NULL == s->tls_app_name.v_app_name)
    555       return MHD_SC_OK; /* No special "application name" profile is needed */
    556 
    557     if (!s->tls_app_name.v_disable_fallback)
    558       return MHD_SC_OK; /* Initialisation allowed with default values */
    559 
    560     /* Load of special "application name" profile is required */
    561 
    562     if (!use_custom_conf_pathname)
    563       return MHD_SC_TLS_DAEMON_INIT_FAILED; /* No fallback pathname */
    564 
    565     mhd_assert (NULL != s->tls_openssl_def_file.v_pathname);
    566 
    567     if (s->tls_openssl_def_file.v_disable_fallback)
    568       return MHD_SC_TLS_DAEMON_INIT_FAILED; /* Fallback pathname is disallowed */
    569 
    570     /* Try to use fallback pathname to load special "application name" profile */
    571     return MHD_SC_TLS_LIB_CONF_WARNING;
    572   }
    573 
    574   conf = NCONF_new_ex (d_tls->libctx,
    575                        NULL);
    576   if (NULL == conf)
    577   {
    578     mhd_DBG_PRINT_TLS_ERRS ();
    579 
    580     ret = is_conf_fallback_allowed (d_tls,
    581                                     s)
    582           ? MHD_SC_TLS_LIB_CONF_WARNING : MHD_SC_TLS_DAEMON_INIT_FAILED;
    583     mhd_LOG_MSG (d, ret, \
    584                  "Failed to create OpenSSL empty configuration object");
    585   }
    586 
    587   if (MHD_SC_OK == ret)
    588   {
    589     long err_line_num;
    590     mhd_DBG_PRINT_TLS_INFO_PARAM1 ("Trying to load configuration file '%s'",
    591                                    conf_pathname);
    592 
    593     if (0 >= NCONF_load (conf,
    594                          conf_pathname,
    595                          &err_line_num))
    596     {
    597       mhd_DBG_PRINT_TLS_ERRS ();
    598 
    599       if (use_custom_conf_pathname)
    600         ret = is_conf_file_fallback_allowed (d_tls,
    601                                              s)
    602               ? MHD_SC_TLS_LIB_CONF_WARNING : MHD_SC_TLS_DAEMON_INIT_FAILED;
    603       else
    604         ret = is_conf_fallback_allowed (d_tls,
    605                                         s)
    606               ? MHD_SC_TLS_LIB_CONF_WARNING : MHD_SC_TLS_DAEMON_INIT_FAILED;
    607 
    608       mhd_LOG_PRINT (d,
    609                      ret,
    610                      mhd_LOG_FMT ("Error loading TLS library configuration "
    611                                   "file '%s' at line %ld"),
    612                      conf_pathname,
    613                      err_line_num);
    614     }
    615 
    616     if (MHD_SC_OK == ret)
    617     {
    618       bool conf_loaded;
    619       unsigned long flags;
    620 
    621       flags = 0u;
    622       if (!s->tls_app_name.v_disable_fallback)
    623         flags |= CONF_MFLAGS_IGNORE_ERRORS;
    624 
    625       conf_loaded = false;
    626 
    627       if (NULL != s->tls_app_name.v_app_name)
    628       {
    629         char app_name_lc[128];
    630         const size_t app_name_len = strlen (s->tls_app_name.v_app_name);
    631 
    632         /* Checked at the parameter processing */
    633         mhd_ASSUME ((128u) > app_name_len);
    634 
    635         mhd_str_to_lowercase_bin_n (app_name_len + 1u, /* '+1' for zero termination */
    636                                     s->tls_app_name.v_app_name,
    637                                     app_name_lc);
    638 
    639         mhd_ASSUME ('\0' ==  app_name_lc[app_name_len]);
    640 
    641         conf_loaded =
    642           daemon_load_conf_from_cfg (d,
    643                                      conf_pathname,
    644                                      app_name_lc,
    645                                      conf,
    646                                      flags,
    647                                      s->tls_app_name.v_disable_fallback
    648                                      || mhd_LIBCTX_FORBIDS_FALLBACKS (d_tls));
    649 
    650         if (!conf_loaded)
    651         {
    652           if (s->tls_app_name.v_disable_fallback
    653               || mhd_LIBCTX_FORBIDS_FALLBACKS (d_tls))
    654             ret = MHD_SC_TLS_DAEMON_INIT_FAILED;
    655           else if (!cfg_reset_and_reload (d,
    656                                           d_tls,
    657                                           conf_pathname,
    658                                           &conf))
    659             ret = MHD_SC_TLS_DAEMON_INIT_FAILED;
    660         }
    661       }
    662 
    663       if (!conf_loaded
    664           && (MHD_SC_OK == ret))
    665       {
    666 
    667         mhd_assert ((NULL == s->tls_app_name.v_app_name)
    668                     || !s->tls_app_name.v_disable_fallback);
    669 
    670         conf_loaded =
    671           daemon_load_conf_from_cfg (d,
    672                                      conf_pathname,
    673                                      "libmicrohttpd",
    674                                      conf,
    675                                      flags,
    676                                      false);
    677         if ((!conf_loaded)
    678             && (!cfg_reset_and_reload (d,
    679                                        d_tls,
    680                                        conf_pathname,
    681                                        &conf)))
    682           ret = MHD_SC_TLS_DAEMON_INIT_FAILED;
    683       }
    684 
    685       if (!conf_loaded
    686           && (MHD_SC_OK == ret))
    687       {
    688 
    689         mhd_assert ((NULL == s->tls_app_name.v_app_name)
    690                     || !s->tls_app_name.v_disable_fallback);
    691 
    692         conf_loaded =
    693           daemon_load_conf_from_cfg (d,
    694                                      conf_pathname,
    695                                      NULL,
    696                                      conf,
    697                                      flags,
    698                                      true);
    699       }
    700 
    701       if (!conf_loaded)
    702         ret = MHD_SC_TLS_LIB_CONF_WARNING;
    703     }
    704 
    705     NCONF_free (conf); /* Explicitly safe with NULL */
    706   }
    707 
    708   OPENSSL_free (conf_pathname);
    709 
    710   return ret;
    711 }
    712 
    713 
    714 /**
    715  * Initialise OpenSSL library context
    716  * @param d the daemon handle
    717  * @param d_tls the daemon TLS settings
    718  * @param s the application-provided settings
    719  * @return #MHD_SC_OK on success,
    720  *         error code otherwise
    721  */
    722 static MHD_FN_PAR_NONNULL_ALL_ MHD_FN_MUST_CHECK_RESULT_ enum MHD_StatusCode
    723 daemon_init_lib_ctx (struct MHD_Daemon *restrict d,
    724                      struct mhd_TlsOpenDaemonData *restrict d_tls,
    725                      struct DaemonOptions *restrict s)
    726 {
    727   enum MHD_StatusCode ret;
    728 
    729 #ifndef HAVE_NULL_PTR_ALL_ZEROS
    730   d_tls->libctx = NULL;
    731 #endif /* HAVE_NULL_PTR_ALL_ZEROS */
    732 
    733   if (!create_lib_ctx (d, d_tls))
    734     return MHD_SC_TLS_DAEMON_INIT_FAILED;
    735 
    736   if (NULL != s->tls_openssl_def_file.v_pathname)
    737   {
    738     ret = daemon_load_lib_conf (d,
    739                                 d_tls,
    740                                 s,
    741                                 true);
    742 
    743     if (MHD_SC_OK == ret)
    744       return MHD_SC_OK;
    745 
    746     if (MHD_SC_TLS_LIB_CONF_WARNING == ret)
    747       ret = s->tls_openssl_def_file.v_disable_fallback
    748             ? MHD_SC_TLS_DAEMON_INIT_FAILED : MHD_SC_OK;
    749   }
    750   else
    751     ret = MHD_SC_OK;
    752 
    753   mhd_assert (MHD_SC_TLS_LIB_CONF_WARNING != ret);
    754 
    755   if (MHD_SC_OK == ret)
    756   {
    757     mhd_assert ((NULL == s->tls_openssl_def_file.v_pathname)
    758                 || !s->tls_openssl_def_file.v_disable_fallback);
    759 
    760     ret = daemon_load_lib_conf (d,
    761                                 d_tls,
    762                                 s,
    763                                 false);
    764 
    765     if (MHD_SC_OK == ret)
    766       return MHD_SC_OK;
    767 
    768     if (MHD_SC_TLS_LIB_CONF_WARNING == ret)
    769     {
    770       if ((!s->tls_app_name.v_disable_fallback)
    771           && (!s->tls_openssl_def_file.v_disable_fallback))
    772         return MHD_SC_OK; /* Load without configuration file */
    773 
    774       ret = MHD_SC_TLS_DAEMON_INIT_FAILED;
    775     }
    776   }
    777 
    778   mhd_assert (MHD_SC_TLS_LIB_CONF_WARNING != ret);
    779 
    780   OSSL_LIB_CTX_free (d_tls->libctx); /* Explicitly safe with NULL */
    781   mhd_LOG_MSG (d, MHD_SC_TLS_DAEMON_INIT_FAILED, \
    782                "Failed to initialise TLS library context");
    783   return MHD_SC_TLS_DAEMON_INIT_FAILED;
    784 }
    785 
    786 
    787 /**
    788  * De-initialise OpenSSL library context
    789  * @param d_tls the daemon TLS settings
    790  */
    791 static MHD_FN_PAR_NONNULL_ALL_ void
    792 daemon_deinit_lib_ctx (struct mhd_TlsOpenDaemonData *restrict d_tls)
    793 {
    794   mhd_assert (NULL != d_tls->libctx);
    795   OSSL_LIB_CTX_free (d_tls->libctx);
    796 }
    797 
    798 
    799 #define mhd_ALPN_CODE_HTTP1_0 \
    800    'h', 't', 't', 'p', '/', '1', '.', '0' /* Registered value for HTTP/1.0 */
    801 #define mhd_ALPN_CODE_HTTP1_1 \
    802    'h', 't', 't', 'p', '/', '1', '.', '1' /* Registered value for HTTP/1.1 */
    803 #ifdef MHD_SUPPORT_HTTP2
    804 #  define mhd_ALPN_CODE_HTTP2\
    805           'h', '2' /* Registered value for HTTP/2 over TLS */
    806 #endif /* MHD_SUPPORT_HTTP2 */
    807 #if 0  /* Disabled code */
    808 #  define mhd_ALPN_CODE_HTTP3\
    809           'h', '3' /* Registered value for HTTP/3 */
    810 #endif /* Disabled code */
    811 
    812 
    813 #ifdef MHD_SUPPORT_HTTP2
    814 static const unsigned char alpn_list_http2_1x[] = {
    815   mhd_ALPN_H2_LEN, mhd_ALPN_CODE_HTTP2
    816   ,
    817   mhd_ALPN_H1_1_LEN, mhd_ALPN_CODE_HTTP1_1
    818   ,
    819   mhd_ALPN_H1_0_LEN, mhd_ALPN_CODE_HTTP1_0
    820 };
    821 static const unsigned char alpn_list_http2_only[] = {
    822   mhd_ALPN_H2_LEN, mhd_ALPN_CODE_HTTP2
    823 };
    824 #endif /* MHD_SUPPORT_HTTP2 */
    825 static const unsigned char alpn_list_http1x_only[] = {
    826   mhd_ALPN_H1_1_LEN, mhd_ALPN_CODE_HTTP1_1
    827   ,
    828   mhd_ALPN_H1_0_LEN, mhd_ALPN_CODE_HTTP1_0
    829 };
    830 
    831 #ifndef OPENSSL_NO_NEXTPROTONEG
    832 /**
    833  * Provide the list of supported protocols for NPN extension
    834  * @param sess the TLS session (ignored)
    835  * @param[out] out the pointer to get the location of the data
    836  * @param[out] outlen the size of the data provided
    837  * @param cls the closure (ignored)
    838  * @return always SSL_TLSEXT_ERR_OK
    839  */
    840 static int
    841 get_npn_list (SSL *sess,
    842               const unsigned char **out,
    843               unsigned int *outlen,
    844               void *cls)
    845 {
    846   struct mhd_TlsOpenDaemonData *const d_tls =
    847     (struct mhd_TlsOpenDaemonData *)cls;
    848   (void)sess;  /* Unused */
    849   *out = d_tls->alpn_prots;
    850   *outlen = d_tls->alpn_prots_size;
    851   return SSL_TLSEXT_ERR_OK;
    852 }
    853 
    854 
    855 #endif /* ! OPENSSL_NO_NEXTPROTONEG */
    856 
    857 /**
    858  * Select protocol from the provided list for ALPN extension
    859  * @param sess the TLS session (ignored)
    860  * @param[out] out the pointer to get the location of selected protocol value
    861  * @param[out] outlen the size of the selected protocol value
    862  * @param in the list of protocols values provided by the client
    863  * @param inlen the size of the list of protocols values provided by the client
    864  * @param cls the closure (ignored)
    865  * @return SSL_TLSEXT_ERR_OK if matching protocol found and selected,
    866  *         SSL_TLSEXT_ERR_ALERT_FATAL otherwise
    867  */
    868 static int
    869 select_alpn_prot (SSL *sess,
    870                   const unsigned char **out,
    871                   unsigned char *outlen,
    872                   const unsigned char *in,
    873                   unsigned int inlen,
    874                   void *cls)
    875 {
    876   struct mhd_TlsOpenDaemonData *const d_tls =
    877     (struct mhd_TlsOpenDaemonData *)cls;
    878   (void)sess;  /* Unused */
    879   if (OPENSSL_NPN_NEGOTIATED ==
    880       SSL_select_next_proto ((unsigned char **)mhd_DROP_CONST (out),
    881                              outlen,
    882                              in,
    883                              inlen,
    884                              d_tls->alpn_prots,
    885                              d_tls->alpn_prots_size))
    886     return SSL_TLSEXT_ERR_OK; /* Success */
    887 
    888   return SSL_TLSEXT_ERR_ALERT_FATAL; /* Failure */
    889 }
    890 
    891 
    892 /**
    893  * Initialise TLS server context
    894  * @param d the daemon handle
    895  * @param d_tls the daemon TLS settings
    896  * @param s the application-provided settings
    897  * @return #MHD_SC_OK on success,
    898  *         error code otherwise
    899  */
    900 static MHD_FN_PAR_NONNULL_ALL_ MHD_FN_MUST_CHECK_RESULT_ enum MHD_StatusCode
    901 daemon_init_ctx (struct MHD_Daemon *restrict d,
    902                  struct mhd_TlsOpenDaemonData *restrict d_tls,
    903                  struct DaemonOptions *restrict s)
    904 {
    905   uint64_t ctx_opts;
    906 
    907 #ifndef MHD_SUPPORT_LOG_FUNCTIONALITY
    908   (void)d;  /* Mute compiler warning */
    909 #endif
    910   (void)s;  // TODO: support configuration options
    911 
    912   mhd_assert (NULL != d_tls->libctx);
    913 
    914   ERR_clear_error ();
    915 
    916   d_tls->ctx = SSL_CTX_new_ex (d_tls->libctx,
    917                                NULL,
    918                                TLS_server_method ());
    919   if (NULL == d_tls->ctx)
    920   {
    921     mhd_DBG_PRINT_TLS_ERRS ();
    922     mhd_LOG_MSG (d, MHD_SC_TLS_DAEMON_INIT_FAILED, \
    923                  "Failed to initialise TLS server context");
    924     return MHD_SC_TLS_DAEMON_INIT_FAILED;
    925   }
    926 
    927   /* Enable some safe and useful workarounds */
    928   ctx_opts = SSL_OP_SAFARI_ECDHE_ECDSA_BUG | SSL_OP_TLSEXT_PADDING;
    929 
    930   // TODO: add configuration option
    931   // ctx_opts |= SSL_OP_CIPHER_SERVER_PREFERENCE;
    932 
    933 #ifndef OPENSSL_NO_KTLS
    934   /* Enable kernel TLS */ // TODO: add configuration option
    935   ctx_opts |= SSL_OP_ENABLE_KTLS;
    936 #  ifdef SSL_OP_ENABLE_KTLS_TX_ZEROCOPY_SENDFILE
    937   ctx_opts |= SSL_OP_ENABLE_KTLS_TX_ZEROCOPY_SENDFILE;
    938 #  endif
    939 #endif
    940 
    941   /* HTTP defines strict framing for the client-side data,
    942      no risk of attack on server on unexpected connection interruption */
    943   /* ctx_opts |= SSL_OP_IGNORE_UNEXPECTED_EOF; */ // TODO: recheck
    944 
    945   /* There is no reason to use re-negotiation with HTTP */
    946   ctx_opts |= SSL_OP_NO_RENEGOTIATION;
    947 
    948   /* Do not use session resumption for now */
    949   ctx_opts |= SSL_OP_NO_TICKET;
    950 
    951   (void)SSL_CTX_set_options (d_tls->ctx,
    952                              ctx_opts);
    953 
    954   /* Prevent interactive password prompts */
    955   SSL_CTX_set_default_passwd_cb (d_tls->ctx,
    956                                  &null_passwd_cb);
    957 
    958   // TODO: make the setting configurable
    959   /* SSL_CTX_set_security_level (d_tls->ctx, 0); */
    960 
    961   /* recv()- and send()-related options */
    962   (void)SSL_CTX_set_mode (d_tls->ctx,
    963                           SSL_MODE_ENABLE_PARTIAL_WRITE
    964                           | SSL_MODE_AUTO_RETRY);
    965   (void)SSL_CTX_clear_mode (d_tls->ctx,
    966                             SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER
    967                             | SSL_MODE_ASYNC);
    968 
    969   SSL_CTX_set_read_ahead (d_tls->ctx,
    970                           !0);
    971 
    972   /* ALPN and NPN */
    973   // TODO: use daemon option to disable ALPN
    974   // TODO: use daemon option to select protocols for ALPN
    975 #ifdef MHD_SUPPORT_HTTP2
    976   if (1 /* enabled both HTTP/2 and HTTP/1.x */)
    977   {
    978     d_tls->alpn_prots = alpn_list_http2_1x;
    979     d_tls->alpn_prots_size = sizeof(alpn_list_http2_1x);
    980   }
    981   else if (0 /* HTTP/2 only */)
    982   {
    983     d_tls->alpn_prots = alpn_list_http2_only;
    984     d_tls->alpn_prots_size = sizeof(alpn_list_http2_only);
    985   }
    986   else
    987 #endif /* MHD_SUPPORT_HTTP2 */
    988   if (1 /* HTTP/1.x only */)
    989   {
    990     d_tls->alpn_prots = alpn_list_http1x_only;
    991     d_tls->alpn_prots_size = sizeof(alpn_list_http1x_only);
    992   }
    993   else
    994   {
    995     mhd_UNREACHABLE ();
    996   }
    997   SSL_CTX_set_alpn_select_cb (d_tls->ctx,
    998                               &select_alpn_prot,
    999                               d_tls);
   1000 #ifndef OPENSSL_NO_NEXTPROTONEG
   1001   SSL_CTX_set_next_protos_advertised_cb (d_tls->ctx,
   1002                                          &get_npn_list,
   1003                                          d_tls);
   1004 #endif /* ! OPENSSL_NO_NEXTPROTONEG */
   1005 
   1006   return MHD_SC_OK;
   1007 }
   1008 
   1009 
   1010 /**
   1011  * De-initialise TLS server context
   1012  * @param d_tls the daemon TLS settings
   1013  */
   1014 static MHD_FN_PAR_NONNULL_ALL_ void
   1015 daemon_deinit_ctx (struct mhd_TlsOpenDaemonData *restrict d_tls)
   1016 {
   1017   mhd_assert (NULL != d_tls->ctx);
   1018   SSL_CTX_free (d_tls->ctx);
   1019 }
   1020 
   1021 
   1022 /**
   1023  * Load the certificates chain from the OpenSSL BIO
   1024  * @param d the daemon handle
   1025  * @param d_tls the daemon TLS settings
   1026  * @param bio the certificates chain data opened in OpenSSL BIO
   1027  * @return #MHD_SC_OK on success,
   1028  *         error code otherwise
   1029  */
   1030 static MHD_FN_PAR_NONNULL_ALL_ MHD_FN_MUST_CHECK_RESULT_ enum MHD_StatusCode
   1031 daemon_load_certs_chain_obio (struct MHD_Daemon *restrict d,
   1032                               struct mhd_TlsOpenDaemonData *restrict d_tls,
   1033                               BIO *restrict bio)
   1034 {
   1035   enum MHD_StatusCode ret;
   1036   X509 *cert;
   1037 
   1038   ret = MHD_SC_OK;
   1039 
   1040   /* The certificate object must be pre-allocated to associate it with
   1041    * the lib context */
   1042   cert = X509_new_ex (d_tls->libctx,
   1043                       NULL);
   1044   if (NULL == cert)
   1045   {
   1046     mhd_DBG_PRINT_TLS_ERRS ();
   1047     mhd_LOG_MSG (d, MHD_SC_TLS_DAEMON_INIT_FAILED, \
   1048                  "Failed to create new certificate object");
   1049     return MHD_SC_TLS_DAEMON_INIT_FAILED;
   1050   }
   1051 
   1052   if (NULL == PEM_read_bio_X509_AUX (bio,
   1053                                      &cert,
   1054                                      &null_passwd_cb,
   1055                                      NULL))
   1056   {
   1057     mhd_DBG_PRINT_TLS_ERRS ();
   1058     mhd_LOG_MSG (d, MHD_SC_TLS_DAEMON_INIT_FAILED, \
   1059                  "Failed to process the certificate");
   1060     ret = MHD_SC_TLS_DAEMON_INIT_FAILED;
   1061   }
   1062   else
   1063   {
   1064     if (0 >= SSL_CTX_use_certificate (d_tls->ctx,
   1065                                       cert))
   1066     {
   1067       mhd_DBG_PRINT_TLS_ERRS ();
   1068       mhd_LOG_MSG (d, MHD_SC_TLS_DAEMON_INIT_FAILED, \
   1069                    "Failed to set the certificate");
   1070       ret = MHD_SC_TLS_DAEMON_INIT_FAILED;
   1071     }
   1072     else
   1073     {
   1074       if (0 != ERR_peek_error ())
   1075         mhd_DBG_PRINT_TLS_ERRS ();
   1076     }
   1077   }
   1078   /* Free certificate: if it was successfully read, it has been "copied" to CTX */
   1079   X509_free (cert);
   1080   if (MHD_SC_OK != ret)
   1081     return ret;
   1082 
   1083   do
   1084   {
   1085     X509 *inter_ca; /* Certifying certificate */
   1086     inter_ca = X509_new_ex (d_tls->libctx,
   1087                             NULL);
   1088     if (NULL == inter_ca)
   1089     {
   1090       mhd_DBG_PRINT_TLS_ERRS ();
   1091       mhd_LOG_MSG (d, MHD_SC_TLS_DAEMON_INIT_FAILED, \
   1092                    "Failed to create new chain certificate object");
   1093       return MHD_SC_TLS_DAEMON_INIT_FAILED;
   1094     }
   1095     if (NULL == PEM_read_bio_X509 (bio,
   1096                                    &inter_ca,
   1097                                    &null_passwd_cb,
   1098                                    NULL))
   1099     {
   1100       unsigned long err;
   1101       err = ERR_peek_last_error ();
   1102 
   1103       mhd_NOWARN_USED_UNUSED
   1104 
   1105       if ((ERR_LIB_PEM == ERR_GET_LIB (err))
   1106           && (PEM_R_NO_START_LINE == ERR_GET_REASON (err)))
   1107       {
   1108         /* End of data */
   1109         ERR_clear_error ();
   1110         X509_free (inter_ca); /* Empty, not needed */
   1111 
   1112         mhd_assert (MHD_SC_OK == ret);
   1113         return MHD_SC_OK; /* Success exit point */
   1114       }
   1115 
   1116       mhd_RESTORE_WARN_USED_UNUSED
   1117       mhd_DBG_PRINT_TLS_ERRS ();
   1118 
   1119       mhd_LOG_MSG (d, MHD_SC_TLS_DAEMON_INIT_FAILED, \
   1120                    "Failed to load next object in the certificates " \
   1121                    "chain");
   1122       ret = MHD_SC_TLS_DAEMON_INIT_FAILED;
   1123     }
   1124     else
   1125     {
   1126       if (SSL_CTX_add0_chain_cert (d_tls->ctx,
   1127                                    inter_ca))
   1128       {
   1129         /* Success, do not free the certificate as
   1130          * function '_add0_' was used to add it. */
   1131         /* Read the next certificate in the chain. */
   1132         continue;
   1133       }
   1134 
   1135       mhd_DBG_PRINT_TLS_ERRS ();
   1136       mhd_LOG_MSG (d, MHD_SC_TLS_DAEMON_INIT_FAILED, \
   1137                    "Failed to add the new certificate object "
   1138                    "to the chain");
   1139       ret = MHD_SC_TLS_DAEMON_INIT_FAILED;
   1140     }
   1141 
   1142     X509_free (inter_ca); /* Failed, the object is not needed */
   1143     mhd_assert (MHD_SC_OK != ret);
   1144   } while (MHD_SC_OK == ret);
   1145   mhd_assert (MHD_SC_OK != ret);
   1146   return ret;
   1147 }
   1148 
   1149 
   1150 /**
   1151  * Load the certificates chain based on application-provided settings
   1152  * @param d the daemon handle
   1153  * @param d_tls the daemon TLS settings
   1154  * @param s the application-provided settings
   1155  * @return #MHD_SC_OK on success,
   1156  *         error code otherwise
   1157  */
   1158 static MHD_FN_PAR_NONNULL_ALL_ MHD_FN_MUST_CHECK_RESULT_ enum MHD_StatusCode
   1159 daemon_load_certs_chain (struct MHD_Daemon *restrict d,
   1160                          struct mhd_TlsOpenDaemonData *restrict d_tls,
   1161                          struct DaemonOptions *restrict s)
   1162 {
   1163   enum MHD_StatusCode ret;
   1164   BIO *m_bio;
   1165 
   1166   mhd_assert (NULL != d_tls->libctx);
   1167   mhd_assert (NULL != d_tls->ctx);
   1168 
   1169   ERR_clear_error ();
   1170 
   1171   m_bio = BIO_new_mem_buf (s->tls_cert_key.v_mem_cert,
   1172                            -1);
   1173   if (NULL == m_bio)
   1174   {
   1175     mhd_DBG_PRINT_TLS_ERRS ();
   1176     return MHD_SC_DAEMON_MEM_ALLOC_FAILURE;
   1177   }
   1178   ret = daemon_load_certs_chain_obio (d,
   1179                                       d_tls,
   1180                                       m_bio);
   1181   BIO_free (m_bio);
   1182   return ret;
   1183 }
   1184 
   1185 
   1186 /**
   1187  * Initialise TLS certificate
   1188  * The function loads the certificate chain and the private key.
   1189  * @param d the daemon handle
   1190  * @param d_tls the daemon TLS settings
   1191  * @param s the application-provided settings
   1192  * @return #MHD_SC_OK on success,
   1193  *         error code otherwise
   1194  */
   1195 static MHD_FN_PAR_NONNULL_ALL_ MHD_FN_MUST_CHECK_RESULT_ enum MHD_StatusCode
   1196 daemon_init_cert (struct MHD_Daemon *restrict d,
   1197                   struct mhd_TlsOpenDaemonData *restrict d_tls,
   1198                   struct DaemonOptions *restrict s)
   1199 {
   1200   enum MHD_StatusCode ret;
   1201   BIO *m_bio;
   1202   EVP_PKEY *pr_key;
   1203   int res_i;
   1204   long res_l;
   1205 
   1206   mhd_assert (NULL != d_tls->libctx);
   1207   mhd_assert (NULL != d_tls->ctx);
   1208 
   1209   ERR_clear_error ();
   1210 
   1211   ret = daemon_load_certs_chain (d,
   1212                                  d_tls,
   1213                                  s);
   1214   if (MHD_SC_OK != ret)
   1215     return ret;
   1216 
   1217   /* Check and cache the certificates chain.
   1218      This also prevents automatic chain re-building for each session. */
   1219   res_l =
   1220     SSL_CTX_build_cert_chain (
   1221       d_tls->ctx,
   1222       SSL_BUILD_CHAIN_FLAG_CHECK /* Use only certificates in the chain */
   1223       | SSL_BUILD_CHAIN_FLAG_UNTRUSTED /* Intermediate CA certs does not need to be trusted */
   1224       | SSL_BUILD_CHAIN_FLAG_NO_ROOT /* The root CA should not be added to the chain */
   1225       | SSL_BUILD_CHAIN_FLAG_IGNORE_ERROR /* Allow the root CA to be not trusted */
   1226       );
   1227   if (0 >= res_l)
   1228   {
   1229     mhd_DBG_PRINT_TLS_ERRS ();
   1230     mhd_LOG_MSG (d, MHD_SC_TLS_DAEMON_INIT_FAILED, \
   1231                  "Failed rebuild certificate chain");
   1232     return MHD_SC_TLS_DAEMON_INIT_FAILED;
   1233   }
   1234   if (2 == res_l)
   1235     mhd_DBG_PRINT_TLS_ERRS ();
   1236 
   1237   m_bio = BIO_new_mem_buf (s->tls_cert_key.v_mem_key,
   1238                            -1);
   1239   if (NULL == m_bio)
   1240   {
   1241     mhd_DBG_PRINT_TLS_ERRS ();
   1242     return MHD_SC_DAEMON_MEM_ALLOC_FAILURE;
   1243   }
   1244   pr_key =
   1245     PEM_read_bio_PrivateKey_ex (m_bio,
   1246                                 NULL,
   1247                                 NULL == s->tls_cert_key.v_mem_pass ?
   1248                                 &null_passwd_cb : NULL,
   1249                                 mhd_DROP_CONST (s->tls_cert_key.v_mem_pass),
   1250                                 d_tls->libctx,
   1251                                 NULL);
   1252   BIO_free (m_bio);
   1253   if (NULL == pr_key)
   1254   {
   1255     mhd_DBG_PRINT_TLS_ERRS ();
   1256     mhd_LOG_MSG (d, MHD_SC_TLS_DAEMON_INIT_FAILED, \
   1257                  "Failed to read the private key");
   1258     return MHD_SC_TLS_DAEMON_INIT_FAILED;
   1259   }
   1260 
   1261   res_i = SSL_CTX_use_PrivateKey (d_tls->ctx,
   1262                                   pr_key);
   1263   EVP_PKEY_free (pr_key); /* The key has been "copied" or failed */
   1264   if (1 != res_i)
   1265   {
   1266     mhd_DBG_PRINT_TLS_ERRS ();
   1267     mhd_LOG_MSG (d, MHD_SC_TLS_DAEMON_INIT_FAILED, \
   1268                  "Failed to set the private key");
   1269     return MHD_SC_TLS_DAEMON_INIT_FAILED;
   1270   }
   1271   /* This actually RE-checks the key.
   1272      The key should be already checked automatically when it was set after
   1273      setting the certificate. */
   1274   if (1 != SSL_CTX_check_private_key (d_tls->ctx))
   1275   {
   1276     mhd_DBG_PRINT_TLS_ERRS ();
   1277     mhd_LOG_MSG (d, MHD_SC_TLS_DAEMON_INIT_FAILED, \
   1278                  "The private key does not match the certificate");
   1279     return MHD_SC_TLS_DAEMON_INIT_FAILED;
   1280   }
   1281 
   1282   return MHD_SC_OK;
   1283 }
   1284 
   1285 
   1286 MHD_INTERNAL MHD_FN_MUST_CHECK_RESULT_ MHD_FN_PAR_NONNULL_ALL_
   1287 MHD_FN_PAR_OUT_ (4) mhd_StatusCodeInt
   1288 mhd_tls_open_daemon_init (struct MHD_Daemon *restrict d,
   1289                           bool sk_edge_trigg,
   1290                           struct DaemonOptions *restrict s,
   1291                           struct mhd_TlsOpenDaemonData **restrict p_d_tls)
   1292 {
   1293   mhd_StatusCodeInt res;
   1294   struct mhd_TlsOpenDaemonData *restrict d_tls;
   1295 
   1296   /* Successful initialisation must be checked earlier */
   1297   mhd_assert (openssl_lib_inited);
   1298 
   1299   res = check_app_tls_settings (d, sk_edge_trigg, s);
   1300   if (MHD_SC_OK != res)
   1301     return res;
   1302 
   1303   d_tls = (struct mhd_TlsOpenDaemonData *)
   1304           mhd_calloc (1, sizeof (struct mhd_TlsOpenDaemonData));
   1305   *p_d_tls = d_tls;
   1306   if (NULL == d_tls)
   1307     return MHD_SC_DAEMON_MEM_ALLOC_FAILURE;
   1308 
   1309   res = daemon_init_lib_ctx (d,
   1310                              d_tls,
   1311                              s);
   1312   if (MHD_SC_OK == res)
   1313   {
   1314     res = daemon_init_ctx (d,
   1315                            d_tls,
   1316                            s);
   1317     if (MHD_SC_OK == res)
   1318     {
   1319       res = daemon_init_cert (d,
   1320                               d_tls,
   1321                               s);
   1322       if (MHD_SC_OK == res)
   1323         return MHD_SC_OK; /* Success exit point */
   1324 
   1325       /* Below is a clean-up code path */
   1326       daemon_deinit_ctx (d_tls);
   1327     }
   1328     daemon_deinit_lib_ctx (d_tls);
   1329   }
   1330   free (d_tls);
   1331   *p_d_tls = NULL;
   1332   mhd_assert (MHD_SC_OK != res);
   1333   return res; /* Failure exit point */
   1334 }
   1335 
   1336 
   1337 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_
   1338 MHD_FN_PAR_INOUT_ (1) void
   1339 mhd_tls_open_daemon_deinit (struct mhd_TlsOpenDaemonData *restrict d_tls)
   1340 {
   1341   mhd_assert (NULL != d_tls);
   1342   daemon_deinit_ctx (d_tls);
   1343   daemon_deinit_lib_ctx (d_tls);
   1344   free (d_tls);
   1345 }
   1346 
   1347 
   1348 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_
   1349 MHD_FN_PAR_INOUT_ (1) void
   1350 mhd_tls_open_thread_cleanup (struct mhd_TlsOpenDaemonData *restrict d_tls)
   1351 {
   1352   OPENSSL_thread_stop_ex (d_tls->libctx);
   1353 }
   1354 
   1355 
   1356 /* ** Connection initialisation / de-initialisation ** */
   1357 
   1358 MHD_INTERNAL size_t
   1359 mhd_tls_open_conn_get_tls_size_v (void)
   1360 {
   1361   return sizeof (struct mhd_TlsOpenConnData);
   1362 }
   1363 
   1364 
   1365 MHD_INTERNAL MHD_FN_MUST_CHECK_RESULT_ MHD_FN_PAR_NONNULL_ALL_
   1366 MHD_FN_PAR_OUT_ (3) bool
   1367 mhd_tls_open_conn_init (const struct mhd_TlsOpenDaemonData *restrict d_tls,
   1368                         const struct mhd_ConnSocket *sk,
   1369                         struct mhd_TlsOpenConnData *restrict c_tls)
   1370 {
   1371   int fd;
   1372 
   1373   ERR_clear_error ();
   1374 
   1375   fd = (int)sk->fd;
   1376   if (sk->fd != (MHD_Socket)fd)
   1377     return false; /* OpenSSL docs clam that it should not be possible */
   1378 
   1379   c_tls->sess = SSL_new (d_tls->ctx);
   1380 
   1381   if (NULL == c_tls->sess)
   1382   {
   1383     mhd_DBG_PRINT_TLS_ERRS ();
   1384     return false;
   1385   }
   1386 
   1387   if (0 < SSL_set_fd (c_tls->sess, fd))
   1388   {
   1389     SSL_set_accept_state (c_tls->sess); /* Force server mode */
   1390 
   1391 #ifndef NDEBUG
   1392     c_tls->dbg.is_inited = true;
   1393 #endif
   1394     return true; /* Success exit point */
   1395   }
   1396 
   1397   SSL_free (c_tls->sess);
   1398   c_tls->sess = NULL;
   1399   return false;
   1400 }
   1401 
   1402 
   1403 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ void
   1404 mhd_tls_open_conn_deinit (struct mhd_TlsOpenConnData *restrict c_tls)
   1405 {
   1406   mhd_assert (NULL != c_tls->sess);
   1407   mhd_assert (c_tls->dbg.is_inited);
   1408   SSL_free (c_tls->sess);
   1409 }
   1410 
   1411 
   1412 /* ** TLS connection establishing ** */
   1413 
   1414 MHD_INTERNAL MHD_FN_MUST_CHECK_RESULT_ MHD_FN_PAR_NONNULL_ALL_
   1415 enum mhd_TlsProcedureResult
   1416 mhd_tls_open_conn_handshake (struct mhd_TlsOpenConnData *restrict c_tls)
   1417 {
   1418   int res;
   1419 
   1420   mhd_assert (c_tls->dbg.is_inited);
   1421   mhd_assert (!c_tls->dbg.is_tls_handshake_completed);
   1422   mhd_assert (!c_tls->shut_tls_wr_sent);
   1423   mhd_assert (!c_tls->shut_tls_wr_received);
   1424   mhd_assert (!c_tls->dbg.is_failed);
   1425 
   1426   ERR_clear_error ();
   1427 
   1428   res = SSL_do_handshake (c_tls->sess);
   1429 
   1430   if (1 == res)
   1431   {
   1432 #ifndef NDEBUG
   1433     c_tls->dbg.is_tls_handshake_completed = true;
   1434 #endif /* ! NDEBUG */
   1435     return mhd_TLS_PROCED_SUCCESS; /* Success exit point */
   1436   }
   1437 
   1438   switch (SSL_get_error (c_tls->sess, res))
   1439   {
   1440   case SSL_ERROR_WANT_READ:
   1441     /* OpenSSL does not distinguish between "interrupted" and "try again" codes.
   1442        Based on OpenSSL result it is unclear whether the "recv-ready" flag
   1443        should be reset or not.
   1444        If edge-triggered sockets polling is used and the flag is cleared, but
   1445        it should not (because the process has been "interrupted") then already
   1446        pending data could be never processed.
   1447        If the flag is not cleared, but it should be cleared (because all
   1448        received data has been processed) then it would create busy-waiting loop
   1449        with edge-triggered sockets polling.
   1450        Temporal solution: disallow edge-triggered sockets polling with OpenSSL
   1451        backend and use clear of "ready" flag. */
   1452     // TODO: replace "BIO" with custom version and track returned errors.
   1453     return mhd_TLS_PROCED_SEND_MORE_NEEDED;
   1454   case SSL_ERROR_WANT_WRITE:
   1455     /* OpenSSL does not distinguish between "interrupted" and "try again" codes.
   1456        Based on OpenSSL result it is unclear whether the "send-ready" flag
   1457        should be reset or not.
   1458        If edge-triggered sockets polling is used and the flag is cleared, but
   1459        it should not (because the process has been "interrupted") then already
   1460        pending data could be never sent.
   1461        If the flag is not cleared, but it should be cleared (because all
   1462        received data has been processed) then it would create busy-waiting loop
   1463        with edge-triggered sockets polling.
   1464        Temporal solution: disallow edge-triggered sockets polling with OpenSSL
   1465        backend and use clear of "ready" flag. */
   1466     // TODO: replace "BIO" with custom version and track returned errors.
   1467     return mhd_TLS_PROCED_RECV_MORE_NEEDED;
   1468   case SSL_ERROR_NONE:
   1469     mhd_assert (0 && "This should not be possible");
   1470     mhd_UNREACHABLE ();
   1471     break;
   1472   default: /* Handled with all other errors below */
   1473     break;
   1474   }
   1475   mhd_DBG_PRINT_TLS_ERRS ();
   1476 #ifndef NDEBUG
   1477   c_tls->dbg.is_failed = true;
   1478 #endif /* ! NDEBUG */
   1479   return mhd_TLS_PROCED_FAILED;
   1480 }
   1481 
   1482 
   1483 MHD_INTERNAL MHD_FN_MUST_CHECK_RESULT_ MHD_FN_PAR_NONNULL_ALL_
   1484 enum mhd_TlsProcedureResult
   1485 mhd_tls_open_conn_shutdown (struct mhd_TlsOpenConnData *restrict c_tls)
   1486 {
   1487   int res;
   1488 
   1489   mhd_assert (c_tls->dbg.is_inited);
   1490   mhd_assert (c_tls->dbg.is_tls_handshake_completed);
   1491   mhd_assert (!c_tls->dbg.is_failed);
   1492 
   1493   ERR_clear_error ();
   1494 
   1495   res = SSL_shutdown (c_tls->sess);
   1496 
   1497   if (1 == res)
   1498   {
   1499     c_tls->shut_tls_wr_sent = true;
   1500     c_tls->shut_tls_wr_received = true;
   1501     return mhd_TLS_PROCED_SUCCESS; /* Success exit point */
   1502   }
   1503 
   1504   /* The OpenSSL documentation contradicts itself: there are two mutually
   1505      exclusive statements on a single page.
   1506    * https://docs.openssl.org/master/man3/SSL_shutdown/#shutdown-lifecycle
   1507      indicates that for nonblocking socket ZERO could be returned when
   1508      "close_notify" is GOING to be sent, but NOT sent yet.
   1509      It also suggests to CALL SSL_get_error(3) when ZERO is returned.
   1510    * https://docs.openssl.org/master/man3/SSL_shutdown/#return-values
   1511      indicates ZERO is returned ONLY when "close_notify" HAS BEEN sent.
   1512      It also suggests to NOT CALL SSL_get_error(3) when ZERO is returned.
   1513    */
   1514   switch (SSL_get_error (c_tls->sess, res))
   1515   {
   1516   case SSL_ERROR_WANT_READ:
   1517     /* OpenSSL does not distinguish between "interrupted" and "try again" codes.
   1518        Based on OpenSSL result it is unclear whether the "recv-ready" flag
   1519        should be reset or not.
   1520        If edge-triggered sockets polling is used and the flag is cleared, but
   1521        it should not (because the process has been "interrupted") then already
   1522        pending data could be never processed.
   1523        If the flag is not cleared, but it should be cleared (because all
   1524        received data has been processed) then it would create busy-waiting loop
   1525        with edge-triggered sockets polling.
   1526        Temporal solution: disallow edge-triggered sockets polling with OpenSSL
   1527        backend and use clear of "ready" flag. */
   1528     // TODO: replace "BIO" with custom version and track returned errors.
   1529     return mhd_TLS_PROCED_SEND_MORE_NEEDED;
   1530   case SSL_ERROR_WANT_WRITE:
   1531     c_tls->shut_tls_wr_sent = true;
   1532     /* OpenSSL does not distinguish between "interrupted" and "try again" codes.
   1533        Based on OpenSSL result it is unclear whether the "send-ready" flag
   1534        should be reset or not.
   1535        If edge-triggered sockets polling is used and the flag is cleared, but
   1536        it should not (because the process has been "interrupted") then already
   1537        pending data could be never sent.
   1538        If the flag is not cleared, but it should be cleared (because all
   1539        received data has been processed) then it would create busy-waiting loop
   1540        with edge-triggered sockets polling.
   1541        Temporal solution: disallow edge-triggered sockets polling with OpenSSL
   1542        backend and use clear of "ready" flag. */
   1543     // TODO: replace "BIO" with custom version and track returned errors.
   1544     return mhd_TLS_PROCED_RECV_MORE_NEEDED;
   1545   case SSL_ERROR_NONE:
   1546     mhd_assert (res != 0 && "Should not be possible");
   1547     c_tls->shut_tls_wr_sent = true;
   1548     return mhd_TLS_PROCED_RECV_INTERRUPTED;
   1549   default: /* Handled with all other errors below */
   1550     break;
   1551   }
   1552   mhd_DBG_PRINT_TLS_ERRS ();
   1553 #ifndef NDEBUG
   1554   c_tls->dbg.is_failed = true;
   1555 #endif /* ! NDEBUG */
   1556   return mhd_TLS_PROCED_FAILED;
   1557 }
   1558 
   1559 
   1560 /* ** Data receiving and sending ** */
   1561 
   1562 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_
   1563 MHD_FN_PAR_OUT_SIZE_ (3, 2)
   1564 MHD_FN_PAR_OUT_ (4) enum mhd_SocketError
   1565 mhd_tls_open_conn_recv (struct mhd_TlsOpenConnData *restrict c_tls,
   1566                         size_t buf_size,
   1567                         char buf[MHD_FN_PAR_DYN_ARR_SIZE_ (buf_size)],
   1568                         size_t *restrict received)
   1569 {
   1570   int res;
   1571 
   1572   mhd_assert (c_tls->dbg.is_inited);
   1573   mhd_assert (c_tls->dbg.is_tls_handshake_completed);
   1574   mhd_assert (!c_tls->shut_tls_wr_sent);
   1575   mhd_assert (!c_tls->dbg.is_failed);
   1576 
   1577   ERR_clear_error ();
   1578 
   1579   res = SSL_read_ex (c_tls->sess,
   1580                      buf,
   1581                      buf_size,
   1582                      received);
   1583   if (1 == res)
   1584   {
   1585     mhd_assert (0 != *received);
   1586     return mhd_SOCKET_ERR_NO_ERROR; /* Success exit point */
   1587   }
   1588 
   1589   mhd_assert (0 == res);
   1590   *received = 0;
   1591   switch (SSL_get_error (c_tls->sess, res))
   1592   {
   1593   case SSL_ERROR_ZERO_RETURN: /* Not an error */
   1594     c_tls->shut_tls_wr_received = true;
   1595     return mhd_SOCKET_ERR_NO_ERROR;   /* Success exit point */
   1596   case SSL_ERROR_WANT_READ:
   1597     /* OpenSSL does not distinguish between "interrupted" and "try again" codes.
   1598        Based on OpenSSL result it is unclear whether the "recv-ready" flag
   1599        should be reset or not.
   1600        If edge-triggered sockets polling is used and the flag is cleared, but
   1601        it should not (because the process has been "interrupted") then already
   1602        pending data could be never processed.
   1603        If the flag is not cleared, but it should be cleared (because all
   1604        received data has been processed) then it would create busy-waiting loop
   1605        with edge-triggered sockets polling.
   1606        Temporal solution: disallow edge-triggered sockets polling with OpenSSL
   1607        backend and use clear of "ready" flag. */
   1608     // TODO: replace "BIO" with custom version and track returned errors.
   1609     return mhd_SOCKET_ERR_AGAIN;
   1610   case SSL_ERROR_NONE:
   1611     mhd_assert (0 && "Should not be possible");
   1612     break;
   1613   case SSL_ERROR_WANT_WRITE:
   1614     mhd_assert (0 && "Should not be possible as re-handshakes are disallowed");
   1615     break;
   1616   case SSL_ERROR_SYSCALL:
   1617     mhd_DBG_PRINT_TLS_ERRS ();
   1618 #ifndef NDEBUG
   1619     c_tls->dbg.is_failed = true;
   1620 #endif /* ! NDEBUG */
   1621     return mhd_SOCKET_ERR_CONN_BROKEN;
   1622   case SSL_ERROR_SSL:
   1623   default:
   1624     break;
   1625   }
   1626   /* Treat all other kinds of errors as hard errors */
   1627   mhd_DBG_PRINT_TLS_ERRS ();
   1628 #ifndef NDEBUG
   1629   c_tls->dbg.is_failed = true;
   1630 #endif /* ! NDEBUG */
   1631   return mhd_SOCKET_ERR_TLS;
   1632 }
   1633 
   1634 
   1635 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ bool
   1636 mhd_tls_open_conn_has_data_in (struct mhd_TlsOpenConnData *restrict c_tls)
   1637 {
   1638   return 0 != SSL_pending (c_tls->sess);
   1639 }
   1640 
   1641 
   1642 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_
   1643 MHD_FN_PAR_IN_SIZE_ (3, 2)
   1644 MHD_FN_PAR_OUT_ (4) enum mhd_SocketError
   1645 mhd_tls_open_conn_send4 (struct mhd_TlsOpenConnData *restrict c_tls,
   1646                          size_t buf_size,
   1647                          const char buf[MHD_FN_PAR_DYN_ARR_SIZE_ (buf_size)],
   1648                          size_t *restrict sent)
   1649 {
   1650   int res;
   1651 
   1652   mhd_assert (c_tls->dbg.is_inited);
   1653   mhd_assert (c_tls->dbg.is_tls_handshake_completed);
   1654   mhd_assert (!c_tls->shut_tls_wr_sent);
   1655   mhd_assert (!c_tls->dbg.is_failed);
   1656 
   1657   ERR_clear_error ();
   1658 
   1659   res = SSL_write_ex (c_tls->sess,
   1660                       buf,
   1661                       buf_size,
   1662                       sent);
   1663   if (1 == res)
   1664   {
   1665     mhd_assert (0 != *sent);
   1666     return mhd_SOCKET_ERR_NO_ERROR; /* Success exit point */
   1667   }
   1668 
   1669   mhd_assert (0 == res);
   1670   *sent = 0;
   1671   switch (SSL_get_error (c_tls->sess, res))
   1672   {
   1673   case SSL_ERROR_WANT_WRITE:
   1674     /* OpenSSL does not distinguish between "interrupted" and "try again" codes.
   1675        Based on OpenSSL result it is unclear whether the "send-ready" flag
   1676        should be reset or not.
   1677        If edge-triggered sockets polling is used and the flag is cleared, but
   1678        it should not (because the process has been "interrupted") then already
   1679        pending data could be never sent.
   1680        If the flag is not cleared, but it should be cleared (because all
   1681        received data has been processed) then it would create busy-waiting loop
   1682        with edge-triggered sockets polling.
   1683        Temporal solution: disallow edge-triggered sockets polling with OpenSSL
   1684        backend and use clear of "ready" flag. */
   1685     // TODO: replace "BIO" with custom version and track returned errors.
   1686     return mhd_SOCKET_ERR_AGAIN;
   1687   case SSL_ERROR_NONE:
   1688     mhd_assert (0 && "Should not be possible");
   1689     break;
   1690   case SSL_ERROR_WANT_READ:
   1691     mhd_assert (0 && "Should not be possible as re-handshakes are disallowed");
   1692     break;
   1693   case SSL_ERROR_ZERO_RETURN:
   1694     c_tls->shut_tls_wr_received = true;
   1695     return mhd_SOCKET_ERR_AGAIN;
   1696   case SSL_ERROR_SYSCALL:
   1697     mhd_DBG_PRINT_TLS_ERRS ();
   1698 #ifndef NDEBUG
   1699     c_tls->dbg.is_failed = true;
   1700 #endif /* ! NDEBUG */
   1701     return mhd_SOCKET_ERR_CONN_BROKEN;
   1702   case SSL_ERROR_SSL:
   1703   default:
   1704     break;
   1705   }
   1706   /* Treat all other kinds of errors as hard errors */
   1707   mhd_DBG_PRINT_TLS_ERRS ();
   1708 #ifndef NDEBUG
   1709   c_tls->dbg.is_failed = true;
   1710 #endif /* ! NDEBUG */
   1711   return mhd_SOCKET_ERR_TLS;
   1712 }
   1713 
   1714 
   1715 /* ** TLS connection information ** */
   1716 
   1717 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_
   1718 MHD_FN_PAR_OUT_ (2) void
   1719 mhd_tls_open_conn_get_tls_sess (
   1720   struct mhd_TlsOpenConnData *restrict c_tls,
   1721   union MHD_ConnInfoDynamicTlsSess *restrict tls_sess_out)
   1722 {
   1723   tls_sess_out->v_openssl_session = c_tls->sess;
   1724 }
   1725 
   1726 
   1727 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_
   1728 MHD_FN_PAR_OUT_ (2) bool
   1729 mhd_tls_open_conn_get_tls_ver (struct mhd_TlsOpenConnData *restrict c_tls,
   1730                                struct mhd_StctTlsVersion *restrict tls_ver_out)
   1731 {
   1732   int openssl_tls_ver;
   1733 
   1734   mhd_assert (c_tls->dbg.is_tls_handshake_completed);
   1735 
   1736   openssl_tls_ver = SSL_version (c_tls->sess);
   1737   switch (openssl_tls_ver)
   1738   {
   1739   case TLS1_VERSION:
   1740     tls_ver_out->tls_ver = MHD_TLS_VERSION_1_0;
   1741     break;
   1742   case TLS1_1_VERSION:
   1743     tls_ver_out->tls_ver = MHD_TLS_VERSION_1_1;
   1744     break;
   1745   case TLS1_2_VERSION:
   1746     tls_ver_out->tls_ver = MHD_TLS_VERSION_1_2;
   1747     break;
   1748   case TLS1_3_VERSION:
   1749     tls_ver_out->tls_ver = MHD_TLS_VERSION_1_3;
   1750     break;
   1751   case SSL3_VERSION:
   1752   default:
   1753     tls_ver_out->tls_ver = MHD_TLS_VERSION_UNKNOWN;
   1754     break;
   1755   }
   1756 
   1757   return true;
   1758 }
   1759 
   1760 
   1761 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ enum mhd_TlsAlpnProt
   1762 mhd_tls_open_conn_get_alpn_prot (struct mhd_TlsOpenConnData *restrict c_tls)
   1763 {
   1764   const unsigned char *sel_prot;
   1765   unsigned int sel_prot_len;
   1766 
   1767   SSL_get0_alpn_selected (c_tls->sess,
   1768                           &sel_prot,
   1769                           &sel_prot_len);
   1770 
   1771 #ifndef OPENSSL_NO_NEXTPROTONEG
   1772   if ((NULL == sel_prot)
   1773       || (0 == sel_prot_len))
   1774   {
   1775     SSL_get0_next_proto_negotiated (c_tls->sess,
   1776                                     &sel_prot,
   1777                                     &sel_prot_len);
   1778   }
   1779 #endif /* ! OPENSSL_NO_NEXTPROTONEG */
   1780 
   1781   mhd_assert (sel_prot_len == (size_t)sel_prot_len);
   1782 
   1783   return mhd_tls_alpn_decode_n ((size_t)sel_prot_len,
   1784                                 sel_prot);
   1785 }