libmicrohttpd2

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

tls_multi_funcs.c (31001B)


      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_multi_funcs.c
     41  * @brief  The implementation of MultiTLS wrapper functions
     42  * @author Karlson2k (Evgeny Grin)
     43  */
     44 
     45 #include "mhd_sys_options.h"
     46 
     47 #include "sys_bool_type.h"
     48 
     49 #include "mhd_assert.h"
     50 #include "mhd_unreachable.h"
     51 
     52 #include "compat_calloc.h"
     53 #include "sys_malloc.h"
     54 
     55 #include "mhd_arr_num_elems.h"
     56 
     57 #include "tls_multi_tls_lib.h"
     58 
     59 #include "tls_multi_daemon_data.h"
     60 #include "tls_multi_conn_data.h"
     61 #include "tls_multi_funcs.h"
     62 
     63 /* Include all supported TLS backends headers */
     64 #if defined(MHD_SUPPORT_GNUTLS)
     65 #  include "tls_gnu_funcs.h"
     66 #endif
     67 #if defined(MHD_SUPPORT_OPENSSL)
     68 #  include "tls_open_funcs.h"
     69 #endif
     70 #if defined(MHD_SUPPORT_MBEDTLS)
     71 #  include "tls_mbed_funcs.h"
     72 #endif
     73 
     74 #include "daemon_options.h"
     75 #include "daemon_logger.h"
     76 
     77 #ifdef mhd_USE_TLS_DEBUG_MESSAGES
     78 #  include <stdio.h> /* For TLS debug printing */
     79 #endif
     80 
     81 #include "mhd_public_api.h"
     82 
     83 #ifdef mhd_USE_TLS_DEBUG_MESSAGES
     84 #  define mhd_M_DEBUG_PRINT(msg) \
     85           do { fprintf (stderr, "## MultiTLS: " msg "\n"); \
     86                fflush (stderr); } while (0)
     87 #  define mhd_M_DEBUG_PRINT1(msg, arg1) \
     88           do { fprintf (stderr, "## MultiTLS: " msg "\n", arg1); \
     89                fflush (stderr); } while (0)
     90 #else
     91 #  define mhd_M_DEBUG_PRINT(msg)        ((void) 0)
     92 #  define mhd_M_DEBUG_PRINT1(msg, arg1)  ((void) 0)
     93 #endif
     94 
     95 
     96 /* ** Global initialisation / de-initialisation ** */
     97 
     98 MHD_INTERNAL void
     99 mhd_tls_multi_global_init_once (void)
    100 {
    101 #if defined(MHD_SUPPORT_GNUTLS)
    102   mhd_tls_gnu_global_init_once ();
    103 #endif
    104 #if defined(MHD_SUPPORT_OPENSSL)
    105   mhd_tls_open_global_init_once ();
    106 #endif
    107 #if defined(MHD_SUPPORT_MBEDTLS)
    108   mhd_tls_mbed_global_init_once ();
    109 #endif
    110 }
    111 
    112 
    113 MHD_INTERNAL void
    114 mhd_tls_multi_global_deinit (void)
    115 {
    116   /* Note: the order is reversed to match the initialisation */
    117 #if defined(MHD_SUPPORT_OPENSSL)
    118   mhd_tls_open_global_deinit ();
    119 #endif
    120 #if defined(MHD_SUPPORT_GNUTLS)
    121   mhd_tls_gnu_global_deinit ();
    122 #endif
    123 #if defined(MHD_SUPPORT_MBEDTLS)
    124   mhd_tls_mbed_global_deinit ();
    125 #endif
    126 }
    127 
    128 
    129 MHD_INTERNAL void
    130 mhd_tls_multi_global_re_init (void)
    131 {
    132 #if defined(MHD_SUPPORT_GNUTLS)
    133   mhd_tls_gnu_global_re_init ();
    134 #endif
    135 #if defined(MHD_SUPPORT_OPENSSL)
    136   mhd_tls_open_global_re_init ();
    137 #endif
    138 #if defined(MHD_SUPPORT_MBEDTLS)
    139   mhd_tls_mbed_global_re_init ();
    140 #endif
    141 }
    142 
    143 
    144 /* ** Daemon initialisation / de-initialisation ** */
    145 
    146 MHD_INTERNAL MHD_FN_PURE_ bool
    147 mhd_tls_multi_is_edge_trigg_supported (struct DaemonOptions *s)
    148 {
    149   switch (s->tls)
    150   {
    151   case MHD_TLS_BACKEND_NONE:
    152     mhd_UNREACHABLE ();
    153     return false;
    154   case MHD_TLS_BACKEND_ANY:
    155 #ifdef MHD_SUPPORT_GNUTLS
    156     if (mhd_tls_gnu_is_edge_trigg_supported (s)
    157         && mhd_tls_gnu_is_inited_fine ())
    158 #  ifdef mhd_HAVE_TLS_ACME
    159       if (mhd_tls_gnu_is_acme_alpn_supported (s)
    160           || !s->acme_alpn_required)
    161 #  endif /* mhd_HAVE_TLS_ACME */
    162       return true;
    163 #endif
    164 #ifdef MHD_SUPPORT_OPENSSL
    165     if (mhd_tls_open_is_edge_trigg_supported (s)
    166         && mhd_tls_open_is_inited_fine ())
    167 #  ifdef mhd_HAVE_TLS_ACME
    168       if (mhd_tls_open_is_acme_alpn_supported (s)
    169           || !s->acme_alpn_required)
    170 #  endif /* mhd_HAVE_TLS_ACME */
    171       return true;
    172 #endif
    173 #ifdef MHD_SUPPORT_MBEDTLS
    174     if (mhd_tls_mbed_is_edge_trigg_supported (s)
    175         && mhd_tls_mbed_is_inited_fine ())
    176 #  ifdef mhd_HAVE_TLS_ACME
    177       if (mhd_tls_mbed_is_acme_alpn_supported (s)
    178           || !s->acme_alpn_required)
    179 #  endif /* mhd_HAVE_TLS_ACME */
    180       return true;
    181 #endif
    182     return false;
    183   case MHD_TLS_BACKEND_GNUTLS:
    184 #ifdef MHD_SUPPORT_GNUTLS
    185     /* Ignore "backend inited" status here,
    186        it will be checked on daemon TLS init */
    187     return mhd_tls_gnu_is_edge_trigg_supported (s);
    188 #endif
    189     break;
    190   case MHD_TLS_BACKEND_OPENSSL:
    191 #ifdef MHD_SUPPORT_OPENSSL
    192     /* Ignore "backend inited" status here,
    193        it will be checked on daemon TLS init */
    194     return mhd_tls_open_is_edge_trigg_supported (s);
    195 #endif
    196     break;
    197   case MHD_TLS_BACKEND_MBEDTLS:
    198 #ifdef MHD_SUPPORT_MBEDTLS
    199     /* Ignore "backend inited" status here,
    200        it will be checked on daemon TLS init */
    201     return mhd_tls_mbed_is_edge_trigg_supported (s);
    202 #endif
    203     break;
    204   default:
    205     mhd_UNREACHABLE ();
    206     break;
    207   }
    208   return false;
    209 }
    210 
    211 
    212 #ifdef mhd_HAVE_TLS_ACME
    213 MHD_INTERNAL MHD_FN_PURE_ bool
    214 mhd_tls_multi_is_acme_alpn_supported (struct DaemonOptions *s)
    215 {
    216   switch (s->tls)
    217   {
    218   case MHD_TLS_BACKEND_NONE:
    219     mhd_UNREACHABLE ();
    220     return false;
    221   case MHD_TLS_BACKEND_ANY:
    222 #  ifdef MHD_SUPPORT_GNUTLS
    223     if (mhd_tls_gnu_is_acme_alpn_supported (s)
    224         && mhd_tls_gnu_is_inited_fine ())
    225       return true;
    226 #  endif
    227 #  ifdef MHD_SUPPORT_OPENSSL
    228     if (mhd_tls_open_is_acme_alpn_supported (s)
    229         && mhd_tls_open_is_inited_fine ())
    230       return true;
    231 #  endif
    232 #  ifdef MHD_SUPPORT_MBEDTLS
    233     if (mhd_tls_mbed_is_acme_alpn_supported (s)
    234         && mhd_tls_mbed_is_inited_fine ())
    235       return true;
    236 #  endif
    237     return false;
    238   case MHD_TLS_BACKEND_GNUTLS:
    239 #  ifdef MHD_SUPPORT_GNUTLS
    240     /* Ignore "backend inited" status here,
    241        it will be checked on daemon TLS init */
    242     return mhd_tls_gnu_is_acme_alpn_supported (s);
    243 #  endif
    244     break;
    245   case MHD_TLS_BACKEND_OPENSSL:
    246 #  ifdef MHD_SUPPORT_OPENSSL
    247     /* Ignore "backend inited" status here,
    248        it will be checked on daemon TLS init */
    249     return mhd_tls_open_is_acme_alpn_supported (s);
    250 #  endif
    251     break;
    252   case MHD_TLS_BACKEND_MBEDTLS:
    253 #  ifdef MHD_SUPPORT_MBEDTLS
    254     /* Ignore "backend inited" status here,
    255        it will be checked on daemon TLS init */
    256     return mhd_tls_mbed_is_acme_alpn_supported (s);
    257 #  endif
    258     break;
    259   default:
    260     mhd_UNREACHABLE ();
    261     break;
    262   }
    263   return false;
    264 }
    265 
    266 
    267 #endif /* mhd_HAVE_TLS_ACME */
    268 
    269 /**
    270  * Initialise selected TLS backend for the daemon
    271  * @param route the selected TLS backend
    272  * @param d the daemon handle
    273  * @param s the daemon settings
    274  * @param d_tls the daemon's TLS settings, backend-specific data is allocated
    275  *              and initialised
    276  * @return #MHD_SC_OK on success (the backend-specific data is allocated),
    277  *         error code otherwise
    278  */
    279 static MHD_FN_MUST_CHECK_RESULT_ MHD_FN_PAR_NONNULL_ALL_
    280 MHD_FN_PAR_OUT_ (5) mhd_StatusCodeInt
    281 tls_daemon_init_try (enum mhd_TlsMultiRoute route,
    282                      struct MHD_Daemon *restrict d,
    283                      bool sk_edge_trigg,
    284                      struct DaemonOptions *restrict s,
    285                      struct mhd_TlsMultiDaemonData *restrict d_tls)
    286 {
    287   mhd_StatusCodeInt res;
    288 
    289 #ifndef MHD_SUPPORT_OPENSSL
    290   (void)sk_edge_trigg;  /* Unused, mute compiler warning */
    291 #endif /* ! MHD_SUPPORT_OPENSSL */
    292 
    293   switch (route)
    294   {
    295 #ifdef MHD_SUPPORT_GNUTLS
    296   case mhd_TLS_MULTI_ROUTE_GNU:
    297     if (!mhd_tls_gnu_is_inited_fine ())
    298       return MHD_SC_TLS_BACKEND_UNAVAILABLE;
    299     res = mhd_tls_gnu_daemon_init (d,
    300                                    sk_edge_trigg,
    301                                    s,
    302                                    &(d_tls->data.gnutls));
    303     if (MHD_SC_OK == res)
    304     {
    305       mhd_M_DEBUG_PRINT ("GnuTLS backend initialised successfully " \
    306                          "for the daemon");
    307       d_tls->choice = route;
    308       return MHD_SC_OK;
    309     }
    310     mhd_M_DEBUG_PRINT1 ("Failed to initialise GnuTLS backend for " \
    311                         "the daemon, error code: %u", (unsigned)res);
    312     return res;
    313 #endif
    314 #ifdef MHD_SUPPORT_OPENSSL
    315   case mhd_TLS_MULTI_ROUTE_OPEN:
    316     if (!mhd_tls_open_is_inited_fine ())
    317       return MHD_SC_TLS_BACKEND_UNAVAILABLE;
    318     res = mhd_tls_open_daemon_init (d,
    319                                     sk_edge_trigg,
    320                                     s,
    321                                     &(d_tls->data.openssl));
    322     if (MHD_SC_OK == res)
    323     {
    324       mhd_M_DEBUG_PRINT ("OpenSSL backend initialised successfully " \
    325                          "for the daemon");
    326       d_tls->choice = route;
    327       return MHD_SC_OK;
    328     }
    329     mhd_M_DEBUG_PRINT1 ("Failed to initialise OpenSSL backend for " \
    330                         "the daemon, error code: %u", (unsigned)res);
    331     return res;
    332 #endif
    333 #ifdef MHD_SUPPORT_MBEDTLS
    334   case mhd_TLS_MULTI_ROUTE_MBED:
    335     if (!mhd_tls_mbed_is_inited_fine ())
    336       return MHD_SC_TLS_BACKEND_UNAVAILABLE;
    337     res = mhd_tls_mbed_daemon_init (d,
    338                                     sk_edge_trigg,
    339                                     s,
    340                                     &(d_tls->data.mbedtls));
    341     if (MHD_SC_OK == res)
    342     {
    343       mhd_M_DEBUG_PRINT ("MbedTLS backend initialised successfully " \
    344                          "for the daemon");
    345       d_tls->choice = route;
    346       return MHD_SC_OK;
    347     }
    348     mhd_M_DEBUG_PRINT1 ("Failed to initialise MbedTLS backend for " \
    349                         "the daemon, error code: %u", (unsigned)res);
    350     return res;
    351 #endif
    352   case mhd_TLS_MULTI_ROUTE_NONE:
    353   default:
    354     break;
    355   }
    356   mhd_assert (0 && "Impossible value");
    357   mhd_UNREACHABLE ();
    358   return MHD_SC_INTERNAL_ERROR;
    359 }
    360 
    361 
    362 MHD_INTERNAL MHD_FN_MUST_CHECK_RESULT_ MHD_FN_PAR_NONNULL_ALL_
    363 MHD_FN_PAR_OUT_ (4) mhd_StatusCodeInt
    364 mhd_tls_multi_daemon_init (struct MHD_Daemon *restrict d,
    365                            bool sk_edge_trigg,
    366                            struct DaemonOptions *restrict s,
    367                            struct mhd_TlsMultiDaemonData **restrict p_d_tls)
    368 {
    369   mhd_StatusCodeInt res;
    370   struct mhd_TlsMultiDaemonData *restrict d_tls;
    371   d_tls = (struct mhd_TlsMultiDaemonData *)
    372           mhd_calloc (1,
    373                       sizeof (struct mhd_TlsMultiDaemonData));
    374   if (NULL == d_tls)
    375     return MHD_SC_DAEMON_MEM_ALLOC_FAILURE;
    376 
    377   d_tls->choice = mhd_TLS_MULTI_ROUTE_NONE;
    378 #ifndef HAVE_NULL_PTR_ALL_ZEROS
    379 #  ifdef MHD_SUPPORT_GNUTLS
    380   d_tls->data.gnutls = NULL;
    381 #  endif /* MHD_SUPPORT_GNUTLS */
    382 #  ifdef MHD_SUPPORT_OPENSSL
    383   d_tls->data.openssl = NULL;
    384 #  endif /* MHD_SUPPORT_OPENSSL */
    385 #  ifdef MHD_SUPPORT_MBEDTLS
    386   d_tls->data.mbedtls = NULL;
    387 #  endif /* MHD_SUPPORT_MBEDTLS */
    388 #endif /* ! HAVE_NULL_PTR_ALL_ZEROS */
    389 
    390   res = MHD_SC_INTERNAL_ERROR; /* Mute compiler warning, the value should not be used */
    391   switch (s->tls)
    392   {
    393   case MHD_TLS_BACKEND_ANY:
    394     if (1)
    395     {
    396       size_t i;
    397       enum mhd_TlsMultiRoute backends[] = {
    398 #ifdef MHD_SUPPORT_GNUTLS
    399         mhd_TLS_MULTI_ROUTE_GNU,
    400 #endif
    401 #ifdef MHD_SUPPORT_OPENSSL
    402         mhd_TLS_MULTI_ROUTE_OPEN,
    403 #endif
    404 #ifdef MHD_SUPPORT_MBEDTLS
    405         mhd_TLS_MULTI_ROUTE_MBED,
    406 #endif
    407         mhd_TLS_MULTI_ROUTE_NONE  /* Not used */
    408       };
    409       /* Try backends one-by-one */
    410       for (i = 0; i < mhd_ARR_NUM_ELEMS (backends) - 1; ++i)
    411       {
    412         res = tls_daemon_init_try (backends[i],
    413                                    d,
    414                                    sk_edge_trigg,
    415                                    s,
    416                                    d_tls);
    417         if (MHD_SC_OK == res)
    418           break;
    419       }
    420     }
    421     break;
    422 #ifdef MHD_SUPPORT_GNUTLS
    423   case MHD_TLS_BACKEND_GNUTLS:
    424     mhd_assert (mhd_tls_gnu_is_inited_fine ()); /* Must be checked earlier */
    425     res = tls_daemon_init_try (mhd_TLS_MULTI_ROUTE_GNU,
    426                                d,
    427                                sk_edge_trigg,
    428                                s,
    429                                d_tls);
    430     break;
    431 #endif /* MHD_SUPPORT_GNUTLS */
    432 #ifdef MHD_SUPPORT_OPENSSL
    433   case MHD_TLS_BACKEND_OPENSSL:
    434     mhd_assert (mhd_tls_open_is_inited_fine ()); /* Must be checked earlier */
    435     res = tls_daemon_init_try (mhd_TLS_MULTI_ROUTE_OPEN,
    436                                d,
    437                                sk_edge_trigg,
    438                                s,
    439                                d_tls);
    440 #endif /* MHD_SUPPORT_OPENSSL */
    441     break;
    442 #ifdef MHD_SUPPORT_MBEDTLS
    443   case MHD_TLS_BACKEND_MBEDTLS:
    444     mhd_assert (mhd_tls_mbed_is_inited_fine ()); /* Must be checked earlier */
    445     res = tls_daemon_init_try (mhd_TLS_MULTI_ROUTE_MBED,
    446                                d,
    447                                sk_edge_trigg,
    448                                s,
    449                                d_tls);
    450 #endif /* MHD_SUPPORT_MBEDTLS */
    451     break;
    452 
    453 #ifndef MHD_SUPPORT_GNUTLS
    454   case MHD_TLS_BACKEND_GNUTLS:
    455 #endif /* ! MHD_SUPPORT_GNUTLS */
    456 #ifndef MHD_SUPPORT_OPENSSL
    457   case MHD_TLS_BACKEND_OPENSSL:
    458 #endif /* ! MHD_SUPPORT_OPENSSL */
    459 #ifndef MHD_SUPPORT_MBEDTLS
    460   case MHD_TLS_BACKEND_MBEDTLS:
    461 #endif /* ! MHD_SUPPORT_MBEDTLS */
    462   case MHD_TLS_BACKEND_NONE:
    463   default:
    464     mhd_UNREACHABLE ();
    465     res = MHD_SC_TLS_BACKEND_UNSUPPORTED;
    466     break;
    467   }
    468   mhd_assert (NULL != d_tls);
    469   if (MHD_SC_OK == res)
    470   {
    471     *p_d_tls = d_tls;
    472     return MHD_SC_OK;
    473   }
    474   free (d_tls);
    475   return res;
    476 }
    477 
    478 
    479 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_
    480 MHD_FN_PAR_INOUT_ (1) void
    481 mhd_tls_multi_daemon_deinit (struct mhd_TlsMultiDaemonData *restrict d_tls)
    482 {
    483   switch (d_tls->choice)
    484   {
    485 #ifdef MHD_SUPPORT_GNUTLS
    486   case mhd_TLS_MULTI_ROUTE_GNU:
    487     mhd_tls_gnu_daemon_deinit (d_tls->data.gnutls);
    488     break;
    489 #endif
    490 #ifdef MHD_SUPPORT_OPENSSL
    491   case mhd_TLS_MULTI_ROUTE_OPEN:
    492     mhd_tls_open_daemon_deinit (d_tls->data.openssl);
    493     break;
    494 #endif
    495 #ifdef MHD_SUPPORT_MBEDTLS
    496   case mhd_TLS_MULTI_ROUTE_MBED:
    497     mhd_tls_mbed_daemon_deinit (d_tls->data.mbedtls);
    498     break;
    499 #endif
    500   case mhd_TLS_MULTI_ROUTE_NONE:
    501   default:
    502     mhd_UNREACHABLE ();
    503     break;
    504   }
    505   free (d_tls);
    506 }
    507 
    508 
    509 #ifdef mhd_HAVE_TLS_THREAD_CLEANUP
    510 /**
    511  * Perform clean-up of TLS resources before thread closing.
    512  * Must be called before thread is closed, after any use of TLS functions
    513  * in the thread, but before de-initialisation of daemon's TLS data.
    514  * @param d_tls the pointer to the daemon's TLS settings
    515  */
    516 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_
    517 MHD_FN_PAR_INOUT_ (1) void
    518 mhd_tls_multi_thread_cleanup (struct mhd_TlsMultiDaemonData *restrict d_tls)
    519 {
    520   switch (d_tls->choice)
    521   {
    522 #  ifdef MHD_SUPPORT_GNUTLS
    523   case mhd_TLS_MULTI_ROUTE_GNU:
    524     mhd_tls_gnu_thread_cleanup (d_tls->data.gnutls);
    525     break;
    526 #  endif
    527 #  ifdef MHD_SUPPORT_OPENSSL
    528   case mhd_TLS_MULTI_ROUTE_OPEN:
    529     mhd_tls_open_thread_cleanup (d_tls->data.openssl);
    530     break;
    531 #  endif
    532 #  ifdef MHD_SUPPORT_MBEDTLS
    533   case mhd_TLS_MULTI_ROUTE_MBED:
    534     mhd_tls_mbed_thread_cleanup (d_tls->data.mbedtls);
    535     break;
    536 #  endif
    537   case mhd_TLS_MULTI_ROUTE_NONE:
    538   default:
    539     mhd_UNREACHABLE ();
    540     break;
    541   }
    542 }
    543 
    544 
    545 #endif /* mhd_HAVE_TLS_THREAD_CLEANUP */
    546 
    547 /* ** Credentials creation / destruction ** */
    548 
    549 #ifdef mhd_HAVE_TLS_ACME
    550 
    551 MHD_INTERNAL MHD_FN_MUST_CHECK_RESULT_
    552 MHD_FN_PAR_NONNULL_ (1) MHD_FN_PAR_NONNULL_ (2)
    553 MHD_FN_PAR_NONNULL_ (4) MHD_FN_PAR_NONNULL_ (6)
    554 MHD_FN_PAR_NONNULL_IF_NONZERO_ (8, 7)
    555 MHD_FN_PAR_OUT_ (2)
    556 MHD_FN_PAR_IN_SIZE_ (4, 3) MHD_FN_PAR_IN_SIZE_ (6, 5)
    557 MHD_FN_PAR_IN_SIZE_ (8, 7)
    558 MHD_FN_PAR_CSTR_ (4) MHD_FN_PAR_CSTR_ (6) MHD_FN_PAR_CSTR_ (8)
    559 enum mhd_TlsCredCreateResult
    560 mhd_tls_multi_cred_create (struct mhd_TlsMultiDaemonData *restrict d_tls,
    561                            union mhd_TlsCredDataPtr *restrict pp_cred,
    562                            size_t cert_len,
    563                            const char *restrict cert,
    564                            size_t key_len,
    565                            const char *restrict key,
    566                            size_t pass_len,
    567                            const char *restrict pass)
    568 {
    569   switch (d_tls->choice)
    570   {
    571 #  ifdef MHD_SUPPORT_GNUTLS
    572   case mhd_TLS_MULTI_ROUTE_GNU:
    573     return mhd_tls_gnu_cred_create (d_tls->data.gnutls,
    574                                     pp_cred,
    575                                     cert_len,
    576                                     cert,
    577                                     key_len,
    578                                     key,
    579                                     pass_len,
    580                                     pass);
    581 #  endif
    582 #  ifdef MHD_SUPPORT_OPENSSL
    583   case mhd_TLS_MULTI_ROUTE_OPEN:
    584     return mhd_tls_open_cred_create (d_tls->data.openssl,
    585                                      pp_cred,
    586                                      cert_len,
    587                                      cert,
    588                                      key_len,
    589                                      key,
    590                                      pass_len,
    591                                      pass);
    592 #  endif
    593 #  ifdef MHD_SUPPORT_MBEDTLS
    594   case mhd_TLS_MULTI_ROUTE_MBED:
    595     return mhd_tls_mbed_cred_create (d_tls->data.mbedtls,
    596                                      pp_cred,
    597                                      cert_len,
    598                                      cert,
    599                                      key_len,
    600                                      key,
    601                                      pass_len,
    602                                      pass);
    603 #  endif
    604   case mhd_TLS_MULTI_ROUTE_NONE:
    605   default:
    606     mhd_UNREACHABLE ();
    607   }
    608 
    609   return mhd_TLS_CRED_CREATE_UNSUPPORTED;
    610 }
    611 
    612 
    613 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ void
    614 mhd_tls_multi_cred_destroy (struct mhd_TlsMultiDaemonData *restrict d_tls,
    615                             union mhd_TlsCredDataPtr cred)
    616 {
    617   switch (d_tls->choice)
    618   {
    619 #  ifdef MHD_SUPPORT_GNUTLS
    620   case mhd_TLS_MULTI_ROUTE_GNU:
    621     mhd_tls_gnu_cred_destroy (d_tls->data.gnutls,
    622                               cred);
    623     break;
    624 #  endif
    625 #  ifdef MHD_SUPPORT_OPENSSL
    626   case mhd_TLS_MULTI_ROUTE_OPEN:
    627     mhd_tls_open_cred_destroy (d_tls->data.openssl,
    628                                cred);
    629     break;
    630 #  endif
    631 #  ifdef MHD_SUPPORT_MBEDTLS
    632   case mhd_TLS_MULTI_ROUTE_MBED:
    633     mhd_tls_mbed_cred_destroy (d_tls->data.mbedtls,
    634                                cred);
    635     break;
    636 #  endif
    637   case mhd_TLS_MULTI_ROUTE_NONE:
    638   default:
    639     mhd_UNREACHABLE ();
    640   }
    641 }
    642 
    643 
    644 #endif /* mhd_HAVE_TLS_ACME */
    645 
    646 /* ** Connection initialisation / de-initialisation ** */
    647 
    648 MHD_INTERNAL size_t
    649 mhd_tls_multi_conn_get_tls_size (struct mhd_TlsMultiDaemonData *restrict d_tls)
    650 {
    651   size_t data_size;
    652 
    653   data_size = sizeof(struct mhd_TlsMultiConnData);
    654   switch (d_tls->choice)
    655   {
    656 #ifdef MHD_SUPPORT_GNUTLS
    657   case mhd_TLS_MULTI_ROUTE_GNU:
    658     data_size += mhd_tls_gnu_conn_get_tls_size (d_tls->data.gnutls);
    659     break;
    660 #endif
    661 #ifdef MHD_SUPPORT_OPENSSL
    662   case mhd_TLS_MULTI_ROUTE_OPEN:
    663     data_size += mhd_tls_open_conn_get_tls_size (d_tls->data.openssl);
    664     break;
    665 #endif
    666 #ifdef MHD_SUPPORT_MBEDTLS
    667   case mhd_TLS_MULTI_ROUTE_MBED:
    668     data_size += mhd_tls_mbed_conn_get_tls_size (d_tls->data.mbedtls);
    669     break;
    670 #endif
    671   case mhd_TLS_MULTI_ROUTE_NONE:
    672   default:
    673     mhd_UNREACHABLE ();
    674   }
    675 
    676   return data_size;
    677 }
    678 
    679 
    680 MHD_INTERNAL MHD_FN_MUST_CHECK_RESULT_ MHD_FN_PAR_NONNULL_ALL_
    681 MHD_FN_PAR_OUT_ (3) bool
    682 mhd_tls_multi_conn_init (const struct mhd_TlsMultiDaemonData *restrict d_tls,
    683                          struct mhd_ConnSocket *sk,
    684                          struct mhd_TlsMultiConnData *restrict c_tls)
    685 {
    686   c_tls->choice = d_tls->choice;
    687   switch (c_tls->choice)
    688   {
    689 #ifdef MHD_SUPPORT_GNUTLS
    690   case mhd_TLS_MULTI_ROUTE_GNU:
    691     /* Assume the same alignment requirements for both structures */
    692     c_tls->data.gnutls = (struct mhd_TlsGnuConnData *)(c_tls + 1);
    693     return mhd_tls_gnu_conn_init (d_tls->data.gnutls,
    694                                   sk,
    695                                   c_tls->data.gnutls);
    696 #endif
    697 #ifdef MHD_SUPPORT_OPENSSL
    698   case mhd_TLS_MULTI_ROUTE_OPEN:
    699     /* Assume the same alignment requirements for both structures */
    700     c_tls->data.openssl = (struct mhd_TlsOpenConnData *)(c_tls + 1);
    701     return mhd_tls_open_conn_init (d_tls->data.openssl,
    702                                    sk,
    703                                    c_tls->data.openssl);
    704 #endif
    705 #ifdef MHD_SUPPORT_MBEDTLS
    706   case mhd_TLS_MULTI_ROUTE_MBED:
    707     /* Assume the same alignment requirements for both structures */
    708     c_tls->data.mbedtls = (struct mhd_TlsMbedConnData *)(c_tls + 1);
    709     return mhd_tls_mbed_conn_init (d_tls->data.mbedtls,
    710                                    sk,
    711                                    c_tls->data.mbedtls);
    712 #endif
    713   case mhd_TLS_MULTI_ROUTE_NONE:
    714   default:
    715     mhd_UNREACHABLE ();
    716     break;
    717   }
    718 
    719   return false;
    720 }
    721 
    722 
    723 /**
    724  * De-initialise connection TLS settings.
    725  * The provided pointer is not freed/deallocated.
    726  * @param c_tls the initialised connection TLS settings
    727  */
    728 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ void
    729 mhd_tls_multi_conn_deinit (struct mhd_TlsMultiConnData *restrict c_tls)
    730 {
    731   switch (c_tls->choice)
    732   {
    733 #ifdef MHD_SUPPORT_GNUTLS
    734   case mhd_TLS_MULTI_ROUTE_GNU:
    735     mhd_tls_gnu_conn_deinit (c_tls->data.gnutls);
    736     break;
    737 #endif
    738 #ifdef MHD_SUPPORT_OPENSSL
    739   case mhd_TLS_MULTI_ROUTE_OPEN:
    740     mhd_tls_open_conn_deinit (c_tls->data.openssl);
    741     break;
    742 #endif
    743 #ifdef MHD_SUPPORT_MBEDTLS
    744   case mhd_TLS_MULTI_ROUTE_MBED:
    745     mhd_tls_mbed_conn_deinit (c_tls->data.mbedtls);
    746     break;
    747 #endif
    748   case mhd_TLS_MULTI_ROUTE_NONE:
    749   default:
    750     mhd_UNREACHABLE ();
    751   }
    752 }
    753 
    754 
    755 /* ** TLS connection establishing ** */
    756 
    757 MHD_INTERNAL MHD_FN_MUST_CHECK_RESULT_ MHD_FN_PAR_NONNULL_ALL_
    758 enum mhd_TlsProcedureResult
    759 mhd_tls_multi_conn_handshake (struct mhd_TlsMultiConnData *restrict c_tls)
    760 {
    761   switch (c_tls->choice)
    762   {
    763 #ifdef MHD_SUPPORT_GNUTLS
    764   case mhd_TLS_MULTI_ROUTE_GNU:
    765     return mhd_tls_gnu_conn_handshake (c_tls->data.gnutls);
    766 #endif
    767 #ifdef MHD_SUPPORT_OPENSSL
    768   case mhd_TLS_MULTI_ROUTE_OPEN:
    769     return mhd_tls_open_conn_handshake (c_tls->data.openssl);
    770 #endif
    771 #ifdef MHD_SUPPORT_MBEDTLS
    772   case mhd_TLS_MULTI_ROUTE_MBED:
    773     return mhd_tls_mbed_conn_handshake (c_tls->data.mbedtls);
    774 #endif
    775   case mhd_TLS_MULTI_ROUTE_NONE:
    776   default:
    777     mhd_UNREACHABLE ();
    778     break;
    779   }
    780   return mhd_TLS_PROCED_FAILED;
    781 }
    782 
    783 
    784 MHD_INTERNAL MHD_FN_MUST_CHECK_RESULT_ MHD_FN_PAR_NONNULL_ALL_
    785 enum mhd_TlsProcedureResult
    786 mhd_tls_multi_conn_shutdown (struct mhd_TlsMultiConnData *restrict c_tls)
    787 {
    788   switch (c_tls->choice)
    789   {
    790 #ifdef MHD_SUPPORT_GNUTLS
    791   case mhd_TLS_MULTI_ROUTE_GNU:
    792     return mhd_tls_gnu_conn_shutdown (c_tls->data.gnutls);
    793 #endif
    794 #ifdef MHD_SUPPORT_OPENSSL
    795   case mhd_TLS_MULTI_ROUTE_OPEN:
    796     return mhd_tls_open_conn_shutdown (c_tls->data.openssl);
    797 #endif
    798 #ifdef MHD_SUPPORT_MBEDTLS
    799   case mhd_TLS_MULTI_ROUTE_MBED:
    800     return mhd_tls_mbed_conn_shutdown (c_tls->data.mbedtls);
    801 #endif
    802   case mhd_TLS_MULTI_ROUTE_NONE:
    803   default:
    804     mhd_UNREACHABLE ();
    805     break;
    806   }
    807   return mhd_TLS_PROCED_FAILED;
    808 }
    809 
    810 
    811 /* ** Data receiving and sending ** */
    812 
    813 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_
    814 MHD_FN_PAR_OUT_SIZE_ (3, 2)
    815 MHD_FN_PAR_OUT_ (4) enum mhd_SocketError
    816 mhd_tls_multi_conn_recv (struct mhd_TlsMultiConnData *restrict c_tls,
    817                          size_t buf_size,
    818                          char buf[MHD_FN_PAR_DYN_ARR_SIZE_ (buf_size)],
    819                          size_t *restrict received)
    820 {
    821   switch (c_tls->choice)
    822   {
    823 #ifdef MHD_SUPPORT_GNUTLS
    824   case mhd_TLS_MULTI_ROUTE_GNU:
    825     return mhd_tls_gnu_conn_recv (c_tls->data.gnutls,
    826                                   buf_size,
    827                                   buf,
    828                                   received);
    829 #endif
    830 #ifdef MHD_SUPPORT_OPENSSL
    831   case mhd_TLS_MULTI_ROUTE_OPEN:
    832     return mhd_tls_open_conn_recv (c_tls->data.openssl,
    833                                    buf_size,
    834                                    buf,
    835                                    received);
    836 #endif
    837 #ifdef MHD_SUPPORT_MBEDTLS
    838   case mhd_TLS_MULTI_ROUTE_MBED:
    839     return mhd_tls_mbed_conn_recv (c_tls->data.mbedtls,
    840                                    buf_size,
    841                                    buf,
    842                                    received);
    843 #endif
    844   case mhd_TLS_MULTI_ROUTE_NONE:
    845   default:
    846     mhd_UNREACHABLE ();
    847     break;
    848   }
    849   return mhd_SOCKET_ERR_INTERNAL;
    850 }
    851 
    852 
    853 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PURE_ bool
    854 mhd_tls_multi_conn_has_cstm_tr (struct mhd_TlsMultiConnData *restrict c_tls)
    855 {
    856   (void)c_tls;  /* Could be unused if all underling functions are actually macros */
    857   switch (c_tls->choice)
    858   {
    859 #ifdef MHD_SUPPORT_GNUTLS
    860   case mhd_TLS_MULTI_ROUTE_GNU:
    861     return mhd_tls_gnu_conn_has_cstm_tr (c_tls->data.gnutls);
    862 #endif
    863 #ifdef MHD_SUPPORT_OPENSSL
    864   case mhd_TLS_MULTI_ROUTE_OPEN:
    865     return mhd_tls_open_conn_has_cstm_tr (c_tls->data.openssl);
    866 #endif
    867 #ifdef MHD_SUPPORT_MBEDTLS
    868   case mhd_TLS_MULTI_ROUTE_MBED:
    869     return mhd_tls_mbed_conn_has_cstm_tr (c_tls->data.mbedtls);
    870 #endif
    871   case mhd_TLS_MULTI_ROUTE_NONE:
    872   default:
    873     mhd_UNREACHABLE ();
    874     break;
    875   }
    876   return false;
    877 }
    878 
    879 
    880 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ bool
    881 mhd_tls_multi_conn_has_data_in (struct mhd_TlsMultiConnData *restrict c_tls)
    882 {
    883   switch (c_tls->choice)
    884   {
    885 #ifdef MHD_SUPPORT_GNUTLS
    886   case mhd_TLS_MULTI_ROUTE_GNU:
    887     return mhd_tls_gnu_conn_has_data_in (c_tls->data.gnutls);
    888 #endif
    889 #ifdef MHD_SUPPORT_OPENSSL
    890   case mhd_TLS_MULTI_ROUTE_OPEN:
    891     return mhd_tls_open_conn_has_data_in (c_tls->data.openssl);
    892 #endif
    893 #ifdef MHD_SUPPORT_MBEDTLS
    894   case mhd_TLS_MULTI_ROUTE_MBED:
    895     return mhd_tls_mbed_conn_has_data_in (c_tls->data.mbedtls);
    896 #endif
    897   case mhd_TLS_MULTI_ROUTE_NONE:
    898   default:
    899     mhd_UNREACHABLE ();
    900     break;
    901   }
    902   return false;
    903 }
    904 
    905 
    906 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_
    907 MHD_FN_PAR_IN_SIZE_ (3, 2)
    908 MHD_FN_PAR_OUT_ (5) enum mhd_SocketError
    909 mhd_tls_multi_conn_send (struct mhd_TlsMultiConnData *restrict c_tls,
    910                          size_t buf_size,
    911                          const char buf[MHD_FN_PAR_DYN_ARR_SIZE_ (buf_size)],
    912                          bool push_data,
    913                          size_t *restrict sent)
    914 {
    915   (void)push_data;  /* Could be unused if not supported by all backends */
    916   switch (c_tls->choice)
    917   {
    918 #ifdef MHD_SUPPORT_GNUTLS
    919   case mhd_TLS_MULTI_ROUTE_GNU:
    920     return mhd_tls_gnu_conn_send (c_tls->data.gnutls,
    921                                   buf_size,
    922                                   buf,
    923                                   push_data,
    924                                   sent);
    925 #endif
    926 #ifdef MHD_SUPPORT_OPENSSL
    927   case mhd_TLS_MULTI_ROUTE_OPEN:
    928     return mhd_tls_open_conn_send (c_tls->data.openssl,
    929                                    buf_size,
    930                                    buf,
    931                                    push_data,
    932                                    sent);
    933 #endif
    934 #ifdef MHD_SUPPORT_MBEDTLS
    935   case mhd_TLS_MULTI_ROUTE_MBED:
    936     return mhd_tls_mbed_conn_send (c_tls->data.mbedtls,
    937                                    buf_size,
    938                                    buf,
    939                                    push_data,
    940                                    sent);
    941 #endif
    942   case mhd_TLS_MULTI_ROUTE_NONE:
    943   default:
    944     mhd_UNREACHABLE ();
    945     break;
    946   }
    947   return mhd_SOCKET_ERR_INTERNAL;
    948 }
    949 
    950 
    951 /* ** TLS connection information ** */
    952 
    953 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_
    954 MHD_FN_PAR_OUT_ (2) void
    955 mhd_tls_multi_conn_get_tls_sess (
    956   struct mhd_TlsMultiConnData *restrict c_tls,
    957   union MHD_ConnInfoDynamicTlsSess *restrict tls_sess_out)
    958 {
    959   switch (c_tls->choice)
    960   {
    961 #ifdef MHD_SUPPORT_GNUTLS
    962   case mhd_TLS_MULTI_ROUTE_GNU:
    963     mhd_tls_gnu_conn_get_tls_sess (c_tls->data.gnutls,
    964                                    tls_sess_out);
    965     break;
    966 #endif
    967 #ifdef MHD_SUPPORT_OPENSSL
    968   case mhd_TLS_MULTI_ROUTE_OPEN:
    969     mhd_tls_open_conn_get_tls_sess (c_tls->data.openssl,
    970                                     tls_sess_out);
    971     break;
    972 #endif
    973 #ifdef MHD_SUPPORT_MBEDTLS
    974   case mhd_TLS_MULTI_ROUTE_MBED:
    975     mhd_tls_mbed_conn_get_tls_sess (c_tls->data.mbedtls,
    976                                     tls_sess_out);
    977     break;
    978 #endif
    979   case mhd_TLS_MULTI_ROUTE_NONE:
    980   default:
    981     mhd_UNREACHABLE ();
    982     break;
    983   }
    984 }
    985 
    986 
    987 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_
    988 MHD_FN_PAR_OUT_ (2) bool
    989 mhd_tls_multi_conn_get_tls_ver (struct mhd_TlsMultiConnData *restrict c_tls,
    990                                 struct mhd_StctTlsVersion *restrict tls_ver_out)
    991 {
    992   switch (c_tls->choice)
    993   {
    994 #ifdef MHD_SUPPORT_GNUTLS
    995   case mhd_TLS_MULTI_ROUTE_GNU:
    996     return mhd_tls_gnu_conn_get_tls_ver (c_tls->data.gnutls,
    997                                          tls_ver_out);
    998 #endif
    999 #ifdef MHD_SUPPORT_OPENSSL
   1000   case mhd_TLS_MULTI_ROUTE_OPEN:
   1001     return mhd_tls_open_conn_get_tls_ver (c_tls->data.openssl,
   1002                                           tls_ver_out);
   1003 #endif
   1004 #ifdef MHD_SUPPORT_MBEDTLS
   1005   case mhd_TLS_MULTI_ROUTE_MBED:
   1006     return mhd_tls_mbed_conn_get_tls_ver (c_tls->data.mbedtls,
   1007                                           tls_ver_out);
   1008 #endif
   1009   case mhd_TLS_MULTI_ROUTE_NONE:
   1010   default:
   1011     mhd_UNREACHABLE ();
   1012     break;
   1013   }
   1014   return false;
   1015 }
   1016 
   1017 
   1018 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ enum mhd_TlsAlpnProt
   1019 mhd_tls_multi_conn_get_alpn_prot (struct mhd_TlsMultiConnData *restrict c_tls)
   1020 {
   1021   switch (c_tls->choice)
   1022   {
   1023 #ifdef MHD_SUPPORT_GNUTLS
   1024   case mhd_TLS_MULTI_ROUTE_GNU:
   1025     return mhd_tls_gnu_conn_get_alpn_prot (c_tls->data.gnutls);
   1026 #endif
   1027 #ifdef MHD_SUPPORT_OPENSSL
   1028   case mhd_TLS_MULTI_ROUTE_OPEN:
   1029     return mhd_tls_open_conn_get_alpn_prot (c_tls->data.openssl);
   1030 #endif
   1031 #ifdef MHD_SUPPORT_MBEDTLS
   1032   case mhd_TLS_MULTI_ROUTE_MBED:
   1033     return mhd_tls_mbed_conn_get_alpn_prot (c_tls->data.mbedtls);
   1034 #endif
   1035   case mhd_TLS_MULTI_ROUTE_NONE:
   1036   default:
   1037     mhd_UNREACHABLE ();
   1038     break;
   1039   }
   1040   return mhd_TLS_ALPN_PROT_NOT_SELECTED;
   1041 }
   1042 
   1043 
   1044 #ifdef mhd_HAVE_TLS_ACME
   1045 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ bool
   1046 mhd_tls_multi_conn_is_acme (struct mhd_TlsMultiConnData *restrict c_tls)
   1047 {
   1048   switch (c_tls->choice)
   1049   {
   1050 #  ifdef MHD_SUPPORT_GNUTLS
   1051   case mhd_TLS_MULTI_ROUTE_GNU:
   1052     return mhd_tls_gnu_conn_is_acme (c_tls->data.gnutls);
   1053 #  endif
   1054 #  ifdef MHD_SUPPORT_OPENSSL
   1055   case mhd_TLS_MULTI_ROUTE_OPEN:
   1056     return mhd_tls_open_conn_is_acme (c_tls->data.openssl);
   1057 #  endif
   1058 #  ifdef MHD_SUPPORT_MBEDTLS
   1059   case mhd_TLS_MULTI_ROUTE_MBED:
   1060     return mhd_tls_mbed_conn_is_acme (c_tls->data.mbedtls);
   1061 #  endif
   1062   case mhd_TLS_MULTI_ROUTE_NONE:
   1063   default:
   1064     mhd_UNREACHABLE ();
   1065     break;
   1066   }
   1067   return false;
   1068 }
   1069 
   1070 
   1071 #endif /* mhd_HAVE_TLS_ACME */