libmicrohttpd2

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

tls_open_funcs.c (55736B)


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