libmicrohttpd2

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

tls_mbed_funcs.c (49365B)


      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) 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_mbed_funcs.c
     41  * @brief  The implementation of MbedTLS wrapper functions
     42  * @author Karlson2k (Evgeny Grin)
     43  */
     44 
     45 /* A few macros can be defined at MHD build-time to adjust code interfacing
     46    with MbedTLS library:
     47    - MHD_TLS_MBED_USE_PSA_FREE
     48    - MHD_TLS_MBED_PREF_RNG_PSA
     49    - MHD_TLS_MBED_PREF_RNG_HMAC
     50    - MHD_TLS_MBED_PREF_RNG_CTR
     51    - MHD_TLS_MBED_SKIP_PLATFORM_SETUP
     52    - MHD_TLS_MBED_USE_PLATFORM_TEARDOWN
     53    - MHD_TLS_MBED_SKIP_CERT_KEY_MATCH_CHECK
     54    - MHD_TLS_MBED_DBG_PRINT_LEVEL
     55    See macros use in this file and in tls_mbed_tls_lib.h.
     56    Macros can be defined, for example, by CPPFLAGS before run of the configure.
     57  */
     58 
     59 #include "mhd_sys_options.h"
     60 
     61 #include "sys_bool_type.h"
     62 #include "sys_base_types.h"
     63 
     64 #include "compat_calloc.h"
     65 #include "sys_malloc.h"
     66 #include <string.h>
     67 
     68 #ifdef mhd_USE_TLS_DEBUG_MESSAGES
     69 #  include <stdio.h> /* For TLS debug printing */
     70 #endif
     71 
     72 #include "mhd_assert.h"
     73 #include "mhd_unreachable.h"
     74 #include "mhd_assume.h"
     75 
     76 #include "mhd_constexpr.h"
     77 #include "mhd_arr_num_elems.h"
     78 
     79 #include "mhd_conn_socket.h"
     80 
     81 #include "mhd_tls_internal.h"
     82 
     83 #include "tls_mbed_tls_lib.h"
     84 
     85 #include "mhd_public_api.h"
     86 
     87 #include "mhd_tls_ver_stct.h"
     88 
     89 #include "daemon_logger.h"
     90 
     91 #include "daemon_options.h"
     92 
     93 #include "sckt_recv.h"
     94 #include "sckt_send.h"
     95 
     96 #include "tls_mbed_daemon_data.h"
     97 #include "tls_mbed_conn_data.h"
     98 #include "tls_mbed_funcs.h"
     99 
    100 #if defined(mhd_USE_TLS_DEBUG_MESSAGES) && defined(MBEDTLS_DEBUG_C)
    101 #  define mhd_TLS_MBED_HAS_DEBUG_PRINT  1
    102 
    103 /* MHD_TLS_MBED_DBG_PRINT_LEVEL can be defined to number in range 0..5,
    104    where 5 is the most detailed log */
    105 #  ifdef MHD_TLS_MBED_DBG_PRINT_LEVEL
    106 #    define mhd_DBG_PRINT_LEVEL (MHD_TLS_MBED_DBG_PRINT_LEVEL + 0)
    107 #  else
    108 #    define mhd_DBG_PRINT_LEVEL (2)
    109 #  endif
    110 
    111 static void
    112 mhd_tls_mbed_debug_print (void *ctx,
    113                           int level,
    114                           const char *filename,
    115                           int line_num,
    116                           const char *msg)
    117 {
    118   (void)ctx;  /* Unused */
    119   /* The level should be pre-filtred by MbedTLS, but it is filtered again
    120      here in case if something else changed it. */
    121   if (mhd_DBG_PRINT_LEVEL < level)
    122     return;
    123   (void)fprintf (stderr, "## MbedTLS %02i [%s:%d]: %s",
    124                  level,
    125                  filename,
    126                  line_num,
    127                  msg);
    128   (void)fflush (stderr);
    129 }
    130 
    131 
    132 #endif /* mhd_USE_TLS_DEBUG_MESSAGES && MBEDTLS_DEBUG_C */
    133 
    134 
    135 /* ** Global initialisation / de-initialisation ** */
    136 
    137 #ifdef MHD_TLS_MBED_PREF_RNG_HMAC
    138 static const mbedtls_md_info_t *
    139 mbed_get_md_for_drbg (void)
    140 {
    141   mhd_constexpr mbedtls_md_type_t mds[] = {
    142 #  ifdef mhd_TLS_MBED_HAS_SHA3_IDS
    143     MBEDTLS_MD_SHA3_256
    144     ,
    145 #  endif /* mhd_TLS_MBED_HAS_SHA3_IDS */
    146     MBEDTLS_MD_SHA256
    147 #  ifdef mhd_TLS_MBED_HAS_SHA3_IDS
    148     ,
    149     MBEDTLS_MD_SHA3_512
    150 #  endif /* mhd_TLS_MBED_HAS_SHA3_IDS */
    151     ,
    152     MBEDTLS_MD_SHA512
    153 #  ifdef mhd_TLS_MBED_HAS_SHA3_IDS
    154     ,
    155     MBEDTLS_MD_SHA3_384
    156 #  endif /* mhd_TLS_MBED_HAS_SHA3_IDS */
    157     ,
    158     MBEDTLS_MD_SHA384
    159 #  ifdef mhd_TLS_MBED_HAS_SHA3_IDS
    160     ,
    161     MBEDTLS_MD_SHA3_224
    162 #  endif /* mhd_TLS_MBED_HAS_SHA3_IDS */
    163     ,
    164     MBEDTLS_MD_SHA224
    165   };
    166   size_t i;
    167 
    168   for (i = 0; i < mhd_ARR_NUM_ELEMS (mds); ++i)
    169   {
    170     const mbedtls_md_info_t *const ret =
    171       mbedtls_md_info_from_type (mds[i]);
    172     if (NULL != ret)
    173       return ret;
    174   }
    175 
    176   return (const mbedtls_md_info_t *)NULL;
    177 }
    178 
    179 
    180 #endif /* MHD_TLS_MBED_PREF_RNG_HMAC */
    181 
    182 static bool mbedtls_lib_inited_now = false;
    183 /* Must be checked when MHD-internal random generator is used */
    184 static bool mbedtls_rng_inited_now = false;
    185 static bool mbedtls_lib_inited_once = false;
    186 
    187 #ifdef mhd_TLS_MBED_HAS_PLATFORM_SETUP
    188 static mbedtls_platform_context mhd_mbed_plat_ctx;
    189 #endif /* mhd_TLS_MBED_HAS_PLATFORM_SETUP */
    190 
    191 #if defined(mhd_TLS_MBED_USE_LIB_ENTROPY)
    192 static mbedtls_entropy_context mhd_mbed_entr_ctx;
    193 #endif /* mhd_TLS_MBED_USE_LIB_ENTROPY */
    194 
    195 #if defined(MHD_TLS_MBED_PREF_RNG_CTR)
    196 static mbedtls_ctr_drbg_context mhd_mbed_ctr_drbg_ctx;
    197 #elif defined(MHD_TLS_MBED_PREF_RNG_HMAC)
    198 static mbedtls_hmac_drbg_context mhd_mbed_hmac_drbg_ctx;
    199 #endif /* MHD_TLS_MBED_PREF_RNG_HMAC */
    200 
    201 static bool
    202 mbed_rng_init (void)
    203 {
    204 #ifdef mhd_TLS_MBED_RNG_PREF_NEEDS_ENTROPY
    205   int (*entropy_cb)(void *ctx, unsigned char *out, size_t out_size);
    206   void *entropy_cb_ctx;
    207 
    208 #  ifdef mhd_TLS_MBED_USE_LIB_ENTROPY
    209   mbedtls_entropy_init (&mhd_mbed_entr_ctx);
    210   entropy_cb = &mbedtls_entropy_func;
    211   entropy_cb_ctx = &mhd_mbed_entr_ctx;
    212 #  else  /* ! mhd_TLS_MBED_USE_LIB_ENTROPY */
    213   /* Seeding with system's entropy sources could be implemented here */
    214 #    error MbedTLS random generator needs entropy sources
    215 #  endif /* ! mhd_TLS_MBED_USE_LIB_ENTROPY */
    216 #endif /* mhd_TLS_MBED_RNG_PREF_NEEDS_ENTROPY */
    217 
    218   mhd_assert (!mbedtls_rng_inited_now);
    219 
    220   if (1) /* For local scope only */
    221   {
    222 #ifdef mhd_TLS_MBED_RNG_PREF_NEEDS_ENTROPY
    223     static const char id_str[] = "libmicrohttpd2";
    224     static uint_fast64_t init_cntr = 0u;
    225     static void *uniq_ptr1 = &init_cntr; /* Any address should be unique in the same address space */
    226     void *uniq_ptr2 = &uniq_ptr2; /* Any address should be unique in the same address space */
    227     unsigned char pers[sizeof(id_str)
    228                        + sizeof(uniq_ptr1)
    229                        + sizeof(uniq_ptr2)
    230                        + sizeof(init_cntr)];
    231 
    232     memcpy (pers,
    233             id_str,
    234             sizeof(id_str));
    235     memcpy (pers + sizeof(id_str),
    236             &uniq_ptr1,
    237             sizeof(uniq_ptr1));
    238     memcpy (pers + sizeof(id_str) + sizeof(uniq_ptr1),
    239             &uniq_ptr2,
    240             sizeof(uniq_ptr2));
    241     memcpy (pers + sizeof(id_str) + sizeof(uniq_ptr1) + sizeof(uniq_ptr2),
    242             &init_cntr,
    243             sizeof(init_cntr));
    244     ++init_cntr;
    245 #endif /* mhd_TLS_MBED_RNG_PREF_NEEDS_ENTROPY */
    246 
    247 #if defined(MHD_TLS_MBED_PREF_RNG_CTR)
    248     mbedtls_ctr_drbg_init (&mhd_mbed_ctr_drbg_ctx);
    249     mbedtls_rng_inited_now =
    250       (0 == mbedtls_ctr_drbg_seed (&mhd_mbed_ctr_drbg_ctx,
    251                                    entropy_cb,
    252                                    entropy_cb_ctx,
    253                                    pers,
    254                                    sizeof(pers)));
    255     if (!mbedtls_rng_inited_now)
    256       mbedtls_ctr_drbg_free (&mhd_mbed_ctr_drbg_ctx);
    257 #elif defined(MHD_TLS_MBED_PREF_RNG_HMAC)
    258     mbedtls_hmac_drbg_init (&mhd_mbed_hmac_drbg_ctx);
    259     mbedtls_rng_inited_now =
    260       (0 == mbedtls_hmac_drbg_seed (&mhd_mbed_hmac_drbg_ctx,
    261                                     mbed_get_md_for_drbg (), /* NULL is handled by mbedtls_hmac_drbg_seed() */
    262                                     entropy_cb,
    263                                     entropy_cb_ctx,
    264                                     pers,
    265                                     sizeof(pers)));
    266     if (!mbedtls_rng_inited_now)
    267       mbedtls_hmac_drbg_free (&mhd_mbed_hmac_drbg_ctx);
    268 #elif defined(MHD_TLS_MBED_PREF_RNG_PSA)
    269     mbedtls_rng_inited_now = true; /* No additional initialisation needed */
    270 #elif !defined(mhd_TLS_MBED_INIT_TLS_REQ_RNG)
    271     mbedtls_rng_inited_now = false;
    272 #else /* mhd_TLS_MBED_INIT_TLS_REQ_RNG */
    273 #  error MbedTLS backend requires random generator
    274     /* Support for external strong random generator could be added */
    275     mbedtls_rng_inited_now = false;
    276 #endif
    277     if (mbedtls_rng_inited_now)
    278       return true; /* Success exit point */
    279   }
    280 
    281 #ifdef mhd_TLS_MBED_USE_LIB_ENTROPY
    282   mbedtls_entropy_free (&mhd_mbed_entr_ctx);
    283 #endif /* mhd_TLS_MBED_USE_LIB_ENTROPY */
    284 
    285   return false;  /* Failure exit point */
    286 }
    287 
    288 
    289 static void
    290 mbed_rng_deinit (void)
    291 {
    292   if (!mbedtls_rng_inited_now)
    293     return;
    294 
    295 #if defined(MHD_TLS_MBED_PREF_RNG_CTR)
    296   mbedtls_ctr_drbg_free (&mhd_mbed_ctr_drbg_ctx);
    297 #elif defined(MHD_TLS_MBED_PREF_RNG_HMAC)
    298   mbedtls_hmac_drbg_free (&mhd_mbed_hmac_drbg_ctx);
    299 #endif
    300 
    301 #ifdef mhd_TLS_MBED_USE_LIB_ENTROPY
    302   mbedtls_entropy_free (&mhd_mbed_entr_ctx);
    303 #endif /* mhd_TLS_MBED_USE_LIB_ENTROPY */
    304 
    305   mbedtls_rng_inited_now = false;
    306 }
    307 
    308 
    309 MHD_INTERNAL void
    310 mhd_tls_mbed_global_init (void)
    311 {
    312 #ifdef MBEDTLS_VERSION_C
    313   if (1)
    314   {
    315     const unsigned int ver = mbedtls_version_get_number ();
    316     if (MBEDTLS_VERSION_NUMBER > ver)
    317       return; /* Run-time version is lower than build-time version */
    318     if (((MBEDTLS_VERSION_NUMBER) >> 24u) != (ver >> 24u))
    319       return; /* Run-time major version does not match build-time major version */
    320   }
    321 #endif /* MBEDTLS_VERSION_C */
    322 
    323 #ifdef mhd_TLS_MBED_HAS_PLATFORM_SETUP
    324 #  ifdef mhd_TLS_MBED_USE_PLATFORM_TEARDOWN
    325   /* 'setup' platform repeatedly only only if 'teardown' is called */
    326   if (mbedtls_lib_inited_once)
    327     (void)0;  /* Do not repeat 'setup' */
    328   else /* combined with tne next 'if()' */
    329 #  endif /* mhd_TLS_MBED_USE_PLATFORM_TEARDOWN */
    330   if (0 != mbedtls_platform_setup (&mhd_mbed_plat_ctx))
    331     return; /* Error platform initialising */
    332 #endif /* mhd_TLS_MBED_HAS_PLATFORM_SETUP */
    333 
    334 #ifdef mhd_TLS_MBED_USE_PSA
    335   /* It is safe to call psa_crypto_init() several times */
    336   if (PSA_SUCCESS != psa_crypto_init ())
    337   {
    338 #  ifdef mhd_TLS_MBED_USE_PLATFORM_TEARDOWN
    339     mbedtls_platform_teardown (&mhd_mbed_plat_ctx);
    340 #  endif /* mhd_TLS_MBED_USE_PLATFORM_TEARDOWN */
    341     return;
    342   }
    343 #endif /* mhd_TLS_MBED_USE_PSA */
    344   mbedtls_lib_inited_once = true;
    345 
    346 #if mhd_TLS_MBED_INIT_TLS_REQ_RNG
    347   mbedtls_lib_inited_now = mbed_rng_init ();
    348 #else  /* ! mhd_TLS_MBED_INIT_TLS_REQ_RNG */
    349   (void)mbed_rng_init ();
    350   mbedtls_lib_inited_now = true; /* MbedTLS could be used even without random generator */
    351 #endif /* ! mhd_TLS_MBED_INIT_TLS_REQ_RNG */
    352 
    353   if (!mbedtls_lib_inited_now)
    354   {
    355 #ifdef mhd_TLS_MBED_USE_PLATFORM_TEARDOWN
    356     mbedtls_platform_teardown (&mhd_mbed_plat_ctx);
    357 #endif /* mhd_TLS_MBED_USE_PLATFORM_TEARDOWN */
    358 
    359 #ifdef mhd_TLS_MBED_USE_PSA_FREE
    360     mbedtls_psa_crypto_free ();
    361 #endif /* mhd_TLS_MBED_USE_PLATFORM_TEARDOWN */
    362     (void)0;
    363   }
    364 }
    365 
    366 
    367 MHD_INTERNAL void
    368 mhd_tls_mbed_global_deinit (void)
    369 {
    370   if (!mbedtls_lib_inited_now)
    371     return;
    372 
    373   mbed_rng_deinit ();
    374 
    375 #ifdef mhd_TLS_MBED_USE_PSA_FREE
    376   /* Not used by default as it will break all calls to PSA performed
    377      directly by the application after closing all active MHD daemons */
    378   mbedtls_psa_crypto_free ();
    379 #endif /* mhd_TLS_MBED_USE_PLATFORM_TEARDOWN */
    380 
    381 #ifdef mhd_TLS_MBED_USE_PLATFORM_TEARDOWN
    382   /* Not used by default as it will break all calls to MbedTLS performed
    383      directly by the application after closing all active MHD daemons */
    384   mbedtls_platform_teardown (&mhd_mbed_plat_ctx);
    385 #endif /* mhd_TLS_MBED_USE_PLATFORM_TEARDOWN */
    386 
    387   mbedtls_lib_inited_now = false;
    388 }
    389 
    390 
    391 MHD_INTERNAL MHD_FN_PURE_ bool
    392 mhd_tls_mbed_is_inited_fine (void)
    393 {
    394   mhd_assert (!mbedtls_lib_inited_now || mbedtls_lib_inited_once);
    395   return mbedtls_lib_inited_now;
    396 }
    397 
    398 
    399 /* ** Daemon initialisation / de-initialisation ** */
    400 
    401 /**
    402  * Check application-provided daemon TLS settings
    403  * @param d the daemon handle
    404  * @param s the application-provided settings
    405  * @return #MHD_SC_OK on success,
    406  *         error code otherwise
    407  */
    408 static MHD_FN_PAR_NONNULL_ALL_ MHD_FN_MUST_CHECK_RESULT_ enum MHD_StatusCode
    409 check_app_tls_settings (struct MHD_Daemon *restrict d,
    410                         struct DaemonOptions *restrict s)
    411 {
    412   mhd_assert (MHD_TLS_BACKEND_NONE != s->tls);
    413   mhd_assert ((MHD_TLS_BACKEND_MBEDTLS == s->tls) \
    414               || (MHD_TLS_BACKEND_ANY == s->tls));
    415 
    416   if (NULL == s->tls_cert_key.v_mem_cert)
    417   {
    418     mhd_LOG_MSG (d, MHD_SC_TLS_CONF_BAD_CERT, \
    419                  "No valid TLS certificate is provided");
    420     return MHD_SC_TLS_CONF_BAD_CERT;
    421   }
    422   mhd_assert (NULL != s->tls_cert_key.v_mem_key);
    423 
    424   if ((MHD_WM_THREAD_PER_CONNECTION == s->work_mode.mode)
    425       || ((MHD_WM_WORKER_THREADS == s->work_mode.mode)
    426           && (1u < s->work_mode.params.num_worker_threads)))
    427   {
    428     bool threads_supported;
    429 #if !defined(MBEDTLS_THREADING_C)
    430     threads_supported = false;
    431 #else  /* MBEDTLS_THREADING_C */
    432 #  if defined(MBEDTLS_VERSION_FEATURES)
    433     threads_supported =
    434       (0 == mbedtls_version_check_feature ("MBEDTLS_THREADING_C"));
    435 #  else  /* ! MBEDTLS_VERSION_FEATURES */
    436     threads_supported = true;
    437 #  endif /* ! MBEDTLS_VERSION_FEATURES */
    438 #endif /* MBEDTLS_THREADING_C */
    439     if (!threads_supported)
    440     {
    441       mhd_LOG_MSG (d, MHD_SC_TLS_BACKEND_DAEMON_INCOMPATIBLE_SETTINGS, \
    442                    "MbedTLS built without threading support and cannot "
    443                    "be used in multi-threaded modes");
    444       return MHD_SC_TLS_BACKEND_DAEMON_INCOMPATIBLE_SETTINGS;
    445     }
    446   }
    447 
    448 #ifdef mhd_HAVE_TLS_ACME
    449   if (!mhd_tls_mbed_is_acme_alpn_supported (s)
    450       && s->acme_alpn_required)
    451   {
    452     mhd_LOG_MSG (d, MHD_SC_TLS_BACKEND_DAEMON_INCOMPATIBLE_SETTINGS,
    453                  "This build of MbedTLS backend does not support "
    454                  "ACME ALPN challenge protocol, but daemon settings "
    455                  "require it");
    456     return MHD_SC_TLS_BACKEND_DAEMON_INCOMPATIBLE_SETTINGS;
    457   }
    458 #endif
    459 
    460   return MHD_SC_OK;
    461 }
    462 
    463 
    464 #if defined(mhd_TLS_MBED_INIT_TLS_REQ_RNG)
    465 /**
    466  * Set daemon TLS credentials.
    467  * This function puts error messages to the log if needed.
    468  * @param d the daemon handle
    469  * @param d_tls the daemon TLS settings
    470  * @param s the application-provided settings
    471  * @param rng_func the random generator function
    472  * @param rng_ctx the random generator function context
    473  * @return #MHD_SC_OK on success,
    474  *         error code otherwise
    475  */
    476 #else  /* ! mhd_TLS_MBED_INIT_TLS_REQ_RNG */
    477 /**
    478  * Set daemon TLS credentials.
    479  * This function puts error messages to the log if needed.
    480  * @param d the daemon handle
    481  * @param d_tls the daemon TLS settings
    482  * @param s the application-provided settings
    483  * @return #MHD_SC_OK on success,
    484  *         error code otherwise
    485  */
    486 #endif /* ! mhd_TLS_MBED_INIT_TLS_REQ_RNG */
    487 static MHD_FN_PAR_NONNULL_ (1) MHD_FN_PAR_NONNULL_ (2)
    488 MHD_FN_PAR_NONNULL_ (3) MHD_FN_MUST_CHECK_RESULT_ enum MHD_StatusCode
    489 daemon_init_credentials (
    490   struct MHD_Daemon *restrict d,
    491   struct mhd_TlsMbedDaemonData *restrict d_tls,
    492   struct DaemonOptions *restrict s
    493 #if defined(mhd_TLS_MBED_INIT_TLS_REQ_RNG)
    494   ,
    495   int (*rng_func)(void *ctx, unsigned char *out, size_t out_size),
    496   void *rng_ctx
    497 #endif /* mhd_TLS_MBED_INIT_TLS_REQ_RNG */
    498   )
    499 {
    500   enum MHD_StatusCode ret;
    501   size_t cert_len;
    502   size_t key_len;
    503   size_t pwd_len;
    504   int res;
    505 
    506   ret = MHD_SC_OK;
    507 
    508   // TODO: Support multiple certificates
    509   cert_len = strlen (s->tls_cert_key.v_mem_cert); // TODO: Reuse calculated length
    510   key_len = strlen (s->tls_cert_key.v_mem_key);   // TODO: Reuse calculated length
    511   pwd_len = (NULL == s->tls_cert_key.v_mem_pass) ?
    512             0u : strlen (s->tls_cert_key.v_mem_pass); // TODO: Reuse calculated length
    513 
    514   mhd_assert (0 != cert_len);
    515   mhd_assert (0 != key_len);
    516 
    517   mbedtls_x509_crt_init (&(d_tls->cert_chain));
    518 
    519   res = mbedtls_x509_crt_parse (&(d_tls->cert_chain),
    520                                 (const unsigned char *)
    521                                 s->tls_cert_key.v_mem_cert,
    522                                 cert_len + 1u /* Include terminating zero */);
    523   if (0 == res)
    524   {
    525     mbedtls_pk_init (&(d_tls->prv_key));
    526 #if defined(mhd_TLS_MBED_INIT_TLS_REQ_RNG)
    527     if (0 != mbedtls_pk_parse_key (&(d_tls->prv_key),
    528                                    (const unsigned char *)
    529                                    s->tls_cert_key.v_mem_key,
    530                                    key_len + 1u,
    531                                    (const unsigned char *)
    532                                    s->tls_cert_key.v_mem_pass,
    533                                    pwd_len,
    534                                    rng_func,
    535                                    rng_ctx))
    536       ret = MHD_SC_TLS_CONF_BAD_CERT;
    537 #else  /* ! mhd_TLS_MBED_INIT_TLS_REQ_RNG */
    538     if (0 != mbedtls_pk_parse_key (&(d_tls->prv_key),
    539                                    (const unsigned char *)
    540                                    s->tls_cert_key.v_mem_key,
    541                                    key_len + 1u,
    542                                    (const unsigned char *)
    543                                    s->tls_cert_key.v_mem_pass,
    544                                    pwd_len))
    545       ret = MHD_SC_TLS_CONF_BAD_CERT;
    546 #endif  /* ! mhd_TLS_MBED_INIT_TLS_REQ_RNG */
    547 
    548     if (MHD_SC_OK == ret)
    549     {
    550       /* The next macro can be defined at MHD build-time to skip potentially
    551          expensive check */
    552 #ifdef MHD_TLS_MBED_SKIP_CERT_KEY_MATCH_CHECK
    553       return MHD_SC_OK; /* Success exit point */
    554 #else  /* ! MHD_TLS_MBED_SKIP_CERT_KEY_MATCH_CHECK */
    555 #  if defined(mhd_TLS_MBED_INIT_TLS_REQ_RNG)
    556       res =  mbedtls_pk_check_pair (&(d_tls->cert_chain.pk),
    557                                     &(d_tls->prv_key),
    558                                     rng_func,
    559                                     rng_ctx);
    560 #  else  /* ! mhd_TLS_MBED_INIT_TLS_REQ_RNG */
    561       res =  mbedtls_pk_check_pair (&(d_tls->cert_chain.pk),
    562                                     &(d_tls->prv_key));
    563 #  endif  /* ! mhd_TLS_MBED_INIT_TLS_REQ_RNG */
    564       if ((0 == res)
    565           || (MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE == res))
    566         return MHD_SC_OK; /* Success exit point */
    567 
    568       mhd_LOG_MSG (d, MHD_SC_TLS_CONF_BAD_CERT, \
    569                    "The private key data does not match the certificate");
    570       ret = MHD_SC_TLS_CONF_BAD_CERT;
    571 #endif /* ! MHD_TLS_MBED_SKIP_CERT_KEY_MATCH_CHECK */
    572     }
    573     else
    574     {
    575       mhd_LOG_MSG (d, MHD_SC_TLS_CONF_BAD_CERT, \
    576                    "The private key data cannot be decoded");
    577       ret = MHD_SC_TLS_CONF_BAD_CERT;
    578     }
    579 
    580     mbedtls_pk_free (&(d_tls->prv_key));
    581   }
    582   else
    583   {
    584     mhd_LOG_PRINT (d,
    585                    MHD_SC_TLS_CONF_BAD_CERT,
    586                    mhd_LOG_FMT ("Failed to parse certificates chain. "
    587                                 "Number of failed certificates: %i"),
    588                    res);
    589     ret = MHD_SC_TLS_CONF_BAD_CERT;
    590   }
    591   mbedtls_x509_crt_free (&(d_tls->cert_chain));
    592 
    593   mhd_assert (MHD_SC_OK != ret);
    594   return ret; /* Failure exit point */
    595 }
    596 
    597 
    598 /**
    599  * De-initialise daemon TLS credentials.
    600  * @param d_tls the daemon TLS settings
    601  */
    602 static MHD_FN_PAR_NONNULL_ALL_ void
    603 daemon_deinit_credentials (struct mhd_TlsMbedDaemonData *restrict d_tls)
    604 {
    605   mbedtls_pk_free (&(d_tls->prv_key));
    606 
    607   mbedtls_x509_crt_free (&(d_tls->cert_chain));
    608 }
    609 
    610 
    611 #ifdef MBEDTLS_SSL_ALPN
    612 /**
    613  * Initialise daemon ALPN data
    614  * This function puts error messages to the log if needed.
    615  * @param d the daemon handle
    616  * @param d_tls the daemon TLS settings
    617  * @param s the application-provided settings
    618  * @return #MHD_SC_OK on success,
    619  *         error code otherwise
    620  */
    621 static MHD_FN_PAR_NONNULL_ALL_ MHD_FN_MUST_CHECK_RESULT_ enum MHD_StatusCode
    622 daemon_set_alpn (struct MHD_Daemon *restrict d,
    623                  struct mhd_TlsMbedDaemonData *restrict d_tls,
    624                  struct DaemonOptions *restrict s)
    625 {
    626   static const char alpn_str_http1_0[] = mhd_ALPN_H1_0;
    627   static const char alpn_str_http1_1[] = mhd_ALPN_H1_1;
    628 #  ifdef MHD_SUPPORT_HTTP2
    629   static const char alpn_str_http2[] = mhd_ALPN_H2;
    630 #  endif
    631   size_t i;
    632 
    633   (void)s;  /* Unused currently. Implement reading allowed HTTP versions */
    634 
    635   i = 0u;
    636   // TODO: implement reading protocol versions from settings */
    637 #  ifdef MHD_SUPPORT_HTTP2
    638   if (1 /* enabled HTTP/2 ? */)
    639     d_tls->alpn_prots[i++] = alpn_str_http2;
    640 #  endif /* MHD_SUPPORT_HTTP2 */
    641 
    642   if (1 /* enabled HTTP/1.x ? */)
    643   {
    644     d_tls->alpn_prots[i++] = alpn_str_http1_1;
    645     d_tls->alpn_prots[i++] = alpn_str_http1_0;
    646   }
    647 
    648   d_tls->alpn_prots[i] = NULL; /* NULL termination */
    649   mhd_assert (mhd_ARR_NUM_ELEMS (d_tls->alpn_prots) > i);
    650   mhd_assert (0u != i);
    651 
    652   if (0 == mbedtls_ssl_conf_alpn_protocols (&(d_tls->tls_conf),
    653                                             d_tls->alpn_prots))
    654     return MHD_SC_OK; /* Success exit point */
    655 
    656   mhd_LOG_MSG (d, MHD_SC_TLS_DAEMON_INIT_FAILED, \
    657                "Failed to set ALPN data");
    658   return MHD_SC_TLS_DAEMON_INIT_FAILED;
    659 }
    660 
    661 
    662 #else  /* ! MBEDTLS_SSL_ALPN */
    663 #  define daemon_set_alpn(d, d_tls, s) (MHD_SC_OK)
    664 #endif /* ! MBEDTLS_SSL_ALPN */
    665 
    666 /**
    667  * Set daemon TLS configuration.
    668  * This function puts error messages to the log if needed.
    669  * @param d the daemon handle
    670  * @param d_tls the daemon TLS settings
    671  * @param s the application-provided settings
    672  * @return #MHD_SC_OK on success,
    673  *         error code otherwise
    674  */
    675 static MHD_FN_PAR_NONNULL_ALL_ MHD_FN_MUST_CHECK_RESULT_ enum MHD_StatusCode
    676 daemon_init_config (struct MHD_Daemon *restrict d,
    677                     struct mhd_TlsMbedDaemonData *restrict d_tls,
    678                     struct DaemonOptions *restrict s)
    679 {
    680   enum MHD_StatusCode ret;
    681 #if defined(mhd_TLS_MBED_INIT_TLS_REQ_RNG)
    682   int (*rng_func)(void *ctx, unsigned char *out, size_t out_size);
    683   void *rng_ctx;
    684 
    685 #  if defined(MHD_TLS_MBED_PREF_RNG_CTR)
    686   rng_func = &mbedtls_ctr_drbg_random;
    687   rng_ctx = &mhd_mbed_ctr_drbg_ctx;
    688 #  elif defined(MHD_TLS_MBED_PREF_RNG_HMAC)
    689   rng_func = &mbedtls_hmac_drbg_random;
    690   rng_ctx = &mhd_mbed_hmac_drbg_ctx;
    691 #  elif defined(MHD_TLS_MBED_PREF_RNG_PSA)
    692   rng_func = &mbedtls_psa_get_random;
    693   rng_ctx = MBEDTLS_PSA_RANDOM_STATE;
    694 #  else  /* MHD_TLS_MBED_PREF_RNG_PSA */
    695   /* Support for external strong random generator could be added here */
    696 #    error No random generator is enabled in MbedTLS
    697   return MHD_SC_INTERNAL_ERROR;
    698 #  endif /* MHD_TLS_MBED_PREF_RNG_PSA */
    699 
    700   ret = daemon_init_credentials (d,
    701                                  d_tls,
    702                                  s,
    703                                  rng_func,
    704                                  rng_ctx);
    705 #else  /* mhd_TLS_MBED_INIT_TLS_REQ_RNG */
    706   ret = daemon_init_credentials (d,
    707                                  d_tls,
    708                                  s);
    709 #endif /* mhd_TLS_MBED_INIT_TLS_REQ_RNG */
    710 
    711   if (MHD_SC_OK != ret)
    712     return ret;
    713 
    714   mbedtls_ssl_config_init (&(d_tls->tls_conf));
    715 
    716 #ifdef mhd_TLS_MBED_HAS_DEBUG_PRINT
    717   mbedtls_ssl_conf_dbg (&(d_tls->tls_conf),
    718                         mhd_tls_mbed_debug_print,
    719                         NULL);
    720   mbedtls_debug_set_threshold (mhd_DBG_PRINT_LEVEL);
    721 #endif /* mhd_TLS_MBED_HAS_DEBUG_PRINT */
    722 
    723   if (0 ==
    724       mbedtls_ssl_config_defaults (&(d_tls->tls_conf),
    725                                    MBEDTLS_SSL_IS_SERVER,
    726                                    MBEDTLS_SSL_TRANSPORT_STREAM,
    727                                    MBEDTLS_SSL_PRESET_DEFAULT))
    728   {
    729 #if defined(mhd_TLS_MBED_INIT_TLS_REQ_RNG)
    730     mbedtls_ssl_conf_rng (&(d_tls->tls_conf),
    731                           rng_func,
    732                           rng_ctx);
    733 #endif /* mhd_TLS_MBED_INIT_TLS_REQ_RNG */
    734 
    735     /* Client certificates are not implemented yet */
    736     mbedtls_ssl_conf_authmode (&(d_tls->tls_conf),
    737                                MBEDTLS_SSL_VERIFY_NONE);
    738 
    739     if (0 ==
    740         mbedtls_ssl_conf_own_cert (&(d_tls->tls_conf),
    741                                    &(d_tls->cert_chain),
    742                                    &(d_tls->prv_key)))
    743     {
    744       ret = daemon_set_alpn (d,
    745                              d_tls,
    746                              s);
    747       if (MHD_SC_OK == ret)
    748         return MHD_SC_OK; /* Success exit point */
    749 
    750       /* Below is a cleanup path */
    751     }
    752     else
    753       ret = MHD_SC_DAEMON_MEM_ALLOC_FAILURE; /* Do not waste binary space on the additional message */
    754   }
    755   else
    756     ret = MHD_SC_DAEMON_MEM_ALLOC_FAILURE; /* Do not waste binary space on the additional message */
    757 
    758   mbedtls_ssl_config_free (&(d_tls->tls_conf));
    759 
    760   daemon_deinit_credentials (d_tls);
    761 
    762   mhd_assert (MHD_SC_OK != ret);
    763   return ret; /* Failure exit point */
    764 }
    765 
    766 
    767 MHD_INTERNAL MHD_FN_MUST_CHECK_RESULT_ MHD_FN_PAR_NONNULL_ALL_
    768 MHD_FN_PAR_OUT_ (3) mhd_StatusCodeInt
    769 mhd_tls_mbed_daemon_init3 (struct MHD_Daemon *restrict d,
    770                            struct DaemonOptions *restrict s,
    771                            struct mhd_TlsMbedDaemonData **restrict p_d_tls)
    772 {
    773   mhd_StatusCodeInt res;
    774   struct mhd_TlsMbedDaemonData *restrict d_tls;
    775 
    776   /* Successful initialisation must be checked earlier */
    777   mhd_assert (mbedtls_lib_inited_once);
    778   mhd_assert (mbedtls_lib_inited_now);
    779 
    780   res = check_app_tls_settings (d,
    781                                 s);
    782   if (MHD_SC_OK != res)
    783     return res;
    784 
    785   d_tls = (struct mhd_TlsMbedDaemonData *)
    786           mhd_calloc (1, sizeof (struct mhd_TlsMbedDaemonData));
    787   *p_d_tls = d_tls;
    788   if (NULL == d_tls)
    789     return MHD_SC_DAEMON_MEM_ALLOC_FAILURE;
    790 
    791   res = daemon_init_config (d,
    792                             d_tls,
    793                             s);
    794   if (MHD_SC_OK == res)
    795   {
    796     return MHD_SC_OK; /* Success exit point */
    797   }
    798   /* Below is a clean-up code path */
    799   free (d_tls);
    800   *p_d_tls = NULL;
    801   mhd_assert (MHD_SC_OK != res);
    802   return res; /* Failure exit point */
    803 }
    804 
    805 
    806 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_
    807 MHD_FN_PAR_INOUT_ (1) void
    808 mhd_tls_mbed_daemon_deinit (struct mhd_TlsMbedDaemonData *restrict d_tls)
    809 {
    810   mhd_assert (NULL != d_tls);
    811 
    812   mbedtls_ssl_config_free (&(d_tls->tls_conf));
    813 
    814   daemon_deinit_credentials (d_tls);
    815 
    816   free (d_tls);
    817 }
    818 
    819 
    820 /* ** Connection initialisation / de-initialisation ** */
    821 
    822 MHD_INTERNAL size_t
    823 mhd_tls_mbed_conn_get_tls_size_v (void)
    824 {
    825   return sizeof (struct mhd_TlsMbedConnData);
    826 }
    827 
    828 
    829 /* Forward declarations of custom transport callbacks */
    830 static int
    831 mhd_mbed_cb_recv (void *ctx,
    832                   unsigned char *buf,
    833                   size_t size);
    834 
    835 static int
    836 mhd_mbed_cb_send (void *ctx,
    837                   const unsigned char *buf,
    838                   size_t size);
    839 
    840 MHD_INTERNAL MHD_FN_MUST_CHECK_RESULT_ MHD_FN_PAR_NONNULL_ALL_
    841 MHD_FN_PAR_OUT_ (3) bool
    842 mhd_tls_mbed_conn_init (const struct mhd_TlsMbedDaemonData *restrict d_tls,
    843                         struct mhd_ConnSocket *sk,
    844                         struct mhd_TlsMbedConnData *restrict c_tls)
    845 {
    846   c_tls->tr.sk = sk;
    847 
    848   mbedtls_ssl_init (&(c_tls->sess));
    849 
    850   if (0 == mbedtls_ssl_setup (&(c_tls->sess),
    851                               &(d_tls->tls_conf)))
    852   {
    853     mbedtls_ssl_set_bio (&(c_tls->sess),
    854                          c_tls,
    855                          &mhd_mbed_cb_send,
    856                          &mhd_mbed_cb_recv,
    857                          NULL /* no recv_timeout callback */);
    858 
    859 #ifndef NDEBUG
    860     c_tls->dbg.is_inited = true;
    861 #endif
    862     return true; /* Success exit point */
    863   }
    864 
    865   mbedtls_ssl_free (&(c_tls->sess));
    866   return false; /* Failure exit point */
    867 }
    868 
    869 
    870 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ void
    871 mhd_tls_mbed_conn_deinit (struct mhd_TlsMbedConnData *restrict c_tls)
    872 {
    873   mhd_assert (c_tls->dbg.is_inited);
    874   mbedtls_ssl_free (&(c_tls->sess));
    875 #ifndef NDEBUG
    876   c_tls->dbg.is_inited = false;
    877 #endif
    878 }
    879 
    880 
    881 /* ** Custom transport functions ** */
    882 
    883 /**
    884  * Prepare for network operation
    885  * @param c_tls the connection TLS data
    886  */
    887 mhd_static_inline MHD_FN_PAR_NONNULL_ALL_ void
    888 mhd_tls_mbed_sckt_comm_prep (struct mhd_TlsMbedConnData *restrict c_tls)
    889 {
    890   memset (&(c_tls->tr.state),
    891           0,
    892           sizeof(c_tls->tr.state));
    893 }
    894 
    895 
    896 /**
    897  * Prepare for send() network operation
    898  * @param c_tls the connection TLS data
    899  * @param unencr_size the size of the data to send before encryption
    900  * @param push_data set to 'false' if it is know that the data to be sent
    901  *                  is incomplete (message or chunk),
    902  *                  set to 'true' if the data is complete or the final part
    903  */
    904 mhd_static_inline MHD_FN_PAR_NONNULL_ALL_ void
    905 mhd_tls_mbed_sckt_comm_prep_send (struct mhd_TlsMbedConnData *restrict c_tls,
    906                                   size_t unencr_size,
    907                                   bool push_data)
    908 {
    909   mhd_tls_mbed_sckt_comm_prep (c_tls);
    910 
    911   if (push_data)
    912     c_tls->tr.state.send_unenc_size = unencr_size;
    913   else
    914     c_tls->tr.state.send_unenc_size = (size_t)(~((size_t)0));
    915 }
    916 
    917 
    918 /**
    919  * The callback which called by MbedTLS to receive the data
    920  * @param ctx the context for the send callback
    921  * @param buf the buffer to put received data
    922  * @param size the size of the @a buf
    923  * @return the positive number of bytes received on success,
    924  *         0 if EOF received (peer closed write/send),
    925  *         #MBEDTLS_ERR_SSL_WANT_READ if receiving would block OR
    926  *                                    receiving was interrupted,
    927  *         #MBEDTLS_ERR_NET_CONN_RESET if connection was broken
    928  *         or #MBEDTLS_ERR_NET_RECV_FAILED in case of other errors
    929  */
    930 static int
    931 mhd_mbed_cb_recv (void *ctx,
    932                   unsigned char *buf,
    933                   size_t size)
    934 {
    935   struct mhd_TlsMbedConnData *const c_tls = (struct mhd_TlsMbedConnData *)ctx;
    936   struct mhd_TlsMbedConnCstmTrtState *const state = &(c_tls->tr.state);
    937   size_t received;
    938 
    939   /* MbedTLS may call recv() several times.
    940      This may result in unwanted extra syscalls, unfair connections
    941      processing or even blocking if socket is blocking.
    942      MHD limits to single send() syscall per operation to evenly distribute
    943      workload to all connections. */
    944   if (state->recv_called)
    945     return MBEDTLS_ERR_SSL_WANT_READ;
    946 
    947   /* MbedTLS may call blindly recv() after calling send() first.
    948      If send() was the first socket operation then the socket has been
    949      checked by MHD for 'send-ready' as receiving operation was expected.
    950      Do not use recv() if 'recv-ready' is not known and the socket is blocking.
    951    */
    952   if (state->send_called && !c_tls->tr.sk->props.is_nonblck)
    953     return MBEDTLS_ERR_SSL_WANT_READ;
    954 
    955   if (1)
    956   {
    957     const int size_i = (int)size;
    958 
    959     if ((0 > size_i)
    960         || (size != (size_t)size_i))
    961     {
    962       /* Return value limitation */
    963       size = (size_t)(((unsigned int)~((unsigned int)0)) >> 1u);
    964     }
    965   }
    966 
    967   state->recv_res = mhd_sckt_recv (c_tls->tr.sk,
    968                                    size,
    969                                    (char *)buf,
    970                                    &received);
    971   state->recv_called = true;
    972 
    973   if (mhd_SOCKET_ERR_NO_ERROR == state->recv_res)
    974   {
    975     mhd_ASSUME (size >= received);
    976     mhd_assert (0 <= (int)received);
    977     return (int)received;
    978   }
    979 
    980   if (mhd_SOCKET_ERR_INTR >= state->recv_res)
    981   {
    982     mhd_assert ((mhd_SOCKET_ERR_INTR == state->recv_res)
    983                 || (mhd_SOCKET_ERR_AGAIN == state->recv_res));
    984     return MBEDTLS_ERR_SSL_WANT_READ;
    985   }
    986 
    987   if (mhd_SOCKET_ERR_IS_HARD (state->recv_res))
    988   {
    989     c_tls->tr.sk->state.discnt_err = state->recv_res;
    990     return MBEDTLS_ERR_NET_CONN_RESET;
    991   }
    992 
    993   return MBEDTLS_ERR_NET_RECV_FAILED;
    994 }
    995 
    996 
    997 /**
    998  * The callback called by MbedTLS to send the data
    999  * @param ctx the context for the send callback
   1000  * @param buf the buffer with the data to send
   1001  * @param size the size of the data in the @a buf
   1002  * @return the positive number of bytes sent on success,
   1003  *         #MBEDTLS_ERR_SSL_WANT_WRITE if sending would block OR
   1004  *                                     sending was interrupted,
   1005  *         #MBEDTLS_ERR_NET_CONN_RESET if connection was broken
   1006  *         or #MBEDTLS_ERR_NET_SEND_FAILED in case of other errors
   1007  */
   1008 static int
   1009 mhd_mbed_cb_send (void *ctx,
   1010                   const unsigned char *buf,
   1011                   size_t size)
   1012 {
   1013   struct mhd_TlsMbedConnData *const c_tls = (struct mhd_TlsMbedConnData *)ctx;
   1014   struct mhd_TlsMbedConnCstmTrtState *const state = &(c_tls->tr.state);
   1015   /* Check whether the complete data is sending.
   1016      The compression is not used so the data after the encryption must not
   1017      be smaller than before the encryption.
   1018      The check may result in false-positive (unlikely in practice), but
   1019      this should not hurt the performance. */
   1020   bool push_data = (size >= state->send_unenc_size);
   1021   size_t sent;
   1022 
   1023   /* MbedTLS may call send() several times in a loop, until all data is sent.
   1024      This may result in unwanted extra syscalls, unfair connections processing
   1025      or even blocking if socket is blocking.
   1026      MHD limits to single send() syscall per operation to evenly distribute
   1027      workload to all connections. */
   1028   if (state->send_called)
   1029     return MBEDTLS_ERR_SSL_WANT_WRITE;
   1030 
   1031   /* MbedTLS may call blindly send() after calling recv() first.
   1032      If recv() was the first socket operation then the socket has been
   1033      checked by MHD for 'recv-ready' as receiving operation was expected.
   1034      Do not use send() if 'send-ready' is not known and the socket is blocking.
   1035    */
   1036   if (state->recv_called && !c_tls->tr.sk->props.is_nonblck)
   1037     return MBEDTLS_ERR_SSL_WANT_WRITE;
   1038 
   1039   if (1)
   1040   {
   1041     const int size_i = (int)size;
   1042 
   1043     if ((0 > size_i)
   1044         || (size != (size_t)size_i))
   1045     {
   1046       /* Return value limitation */
   1047       size = (size_t)(((unsigned int)~((unsigned int)0)) >> 1u);
   1048       push_data = false;
   1049     }
   1050   }
   1051 
   1052   state->send_res = mhd_sckt_send (c_tls->tr.sk,
   1053                                    size,
   1054                                    (const char *)buf,
   1055                                    push_data,
   1056                                    &sent);
   1057   state->send_called = true;
   1058 
   1059   if (mhd_SOCKET_ERR_NO_ERROR == state->send_res)
   1060   {
   1061     mhd_ASSUME (size >= sent);
   1062     mhd_assert (0 < (int)sent);
   1063     return (int)sent;
   1064   }
   1065 
   1066   if (mhd_SOCKET_ERR_INTR >= state->send_res)
   1067   {
   1068     mhd_assert ((mhd_SOCKET_ERR_INTR == state->send_res)
   1069                 || (mhd_SOCKET_ERR_AGAIN == state->send_res));
   1070     return MBEDTLS_ERR_SSL_WANT_WRITE;
   1071   }
   1072 
   1073   if (mhd_SOCKET_ERR_IS_HARD (state->send_res))
   1074   {
   1075     c_tls->tr.sk->state.discnt_err = state->send_res;
   1076     return MBEDTLS_ERR_NET_CONN_RESET;
   1077   }
   1078 
   1079   return MBEDTLS_ERR_NET_SEND_FAILED;
   1080 }
   1081 
   1082 
   1083 /* ** TLS connection establishing ** */
   1084 
   1085 MHD_INTERNAL MHD_FN_MUST_CHECK_RESULT_ MHD_FN_PAR_NONNULL_ALL_
   1086 enum mhd_TlsProcedureResult
   1087 mhd_tls_mbed_conn_handshake (struct mhd_TlsMbedConnData *c_tls)
   1088 {
   1089   int res;
   1090 
   1091   mhd_assert (c_tls->dbg.is_inited);
   1092   mhd_assert (!c_tls->dbg.is_tls_handshake_completed);
   1093   mhd_assert (!c_tls->shut_tls_wr_sent);
   1094   mhd_assert (!c_tls->shut_tls_wr_received);
   1095   mhd_assert (!c_tls->dbg.is_failed);
   1096 
   1097   mhd_tls_mbed_sckt_comm_prep (c_tls);
   1098 
   1099   res = mbedtls_ssl_handshake (&(c_tls->sess));
   1100 
   1101   mhd_assert ((c_tls->tr.state.recv_called)
   1102               || (mhd_SOCKET_ERR_NO_ERROR == c_tls->tr.state.recv_res));
   1103   mhd_assert ((c_tls->tr.state.send_called)
   1104               || (mhd_SOCKET_ERR_NO_ERROR == c_tls->tr.state.send_res));
   1105 
   1106   switch (res)
   1107   {
   1108   case 0:
   1109 #ifndef NDEBUG
   1110     c_tls->dbg.is_tls_handshake_completed = true;
   1111 #endif /* ! NDEBUG */
   1112     return mhd_TLS_PROCED_SUCCESS; /* Success exit point */
   1113 
   1114   case MBEDTLS_ERR_SSL_WANT_READ:
   1115     mhd_assert (!mhd_SOCKET_ERR_IS_HARD (c_tls->tr.state.recv_res));
   1116     mhd_assert (!mhd_SOCKET_ERR_IS_HARD (c_tls->tr.state.send_res));
   1117 
   1118     if (!c_tls->tr.state.recv_called)
   1119       return mhd_TLS_PROCED_RECV_INTERRUPTED; /* Do not clear 'recv-ready' flag */
   1120 
   1121     if (mhd_SOCKET_ERR_AGAIN == c_tls->tr.state.recv_res)
   1122       return mhd_TLS_PROCED_RECV_MORE_NEEDED; /* Clear 'recv-ready' flag */
   1123 
   1124     return mhd_TLS_PROCED_RECV_INTERRUPTED; /* Do not clear 'recv-ready' flag */
   1125 
   1126   case MBEDTLS_ERR_SSL_WANT_WRITE:
   1127     mhd_assert (!mhd_SOCKET_ERR_IS_HARD (c_tls->tr.state.recv_res));
   1128     mhd_assert (!mhd_SOCKET_ERR_IS_HARD (c_tls->tr.state.send_res));
   1129 
   1130     if (!c_tls->tr.state.send_called)
   1131       return mhd_TLS_PROCED_SEND_INTERRUPTED; /* Do not clear 'send-ready' flag */
   1132 
   1133     if (mhd_SOCKET_ERR_AGAIN == c_tls->tr.state.send_res)
   1134       return mhd_TLS_PROCED_SEND_MORE_NEEDED; /* Clear 'send-ready' flag */
   1135 
   1136     return mhd_TLS_PROCED_SEND_INTERRUPTED; /* Do not clear 'send-ready' flag */
   1137 
   1138   case MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS:
   1139     mhd_assert (0 && "MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS must not be returned");
   1140     break;
   1141 
   1142   case MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS:
   1143     /* The result means that mbedtls_ssl_handshake() must be called again
   1144        later.
   1145        As this result does not map directly to any of available flags,
   1146        so map it to "waiting for send-ready" as the socket should be already
   1147        'send-ready'. */
   1148 
   1149     return (c_tls->tr.state.send_called
   1150             && (mhd_SOCKET_ERR_AGAIN == c_tls->tr.state.send_res)) ?
   1151            mhd_TLS_PROCED_SEND_MORE_NEEDED : mhd_TLS_PROCED_SEND_INTERRUPTED;
   1152 
   1153   case MBEDTLS_ERR_SSL_RECEIVED_EARLY_DATA:
   1154 #ifdef MBEDTLS_SSL_EARLY_DATA
   1155     /* Could be replaced with early data support is implemented */
   1156 #endif /* MBEDTLS_SSL_EARLY_DATA */
   1157     mhd_assert (0
   1158                 && "MBEDTLS_ERR_SSL_RECEIVED_EARLY_DATA must not be returned");
   1159     break;
   1160 
   1161   default:
   1162     break; /* Handle other values below */
   1163   }
   1164 
   1165   /* All other result codes must be interpreted as a hard error */
   1166 #ifndef NDEBUG
   1167   c_tls->dbg.is_failed = true;
   1168 #endif /* ! NDEBUG */
   1169 
   1170   return mhd_TLS_PROCED_FAILED;
   1171 }
   1172 
   1173 
   1174 MHD_INTERNAL MHD_FN_MUST_CHECK_RESULT_ MHD_FN_PAR_NONNULL_ALL_
   1175 enum mhd_TlsProcedureResult
   1176 mhd_tls_mbed_conn_shutdown (struct mhd_TlsMbedConnData *c_tls)
   1177 {
   1178   int res;
   1179 
   1180   mhd_assert (c_tls->dbg.is_inited);
   1181   mhd_assert (c_tls->dbg.is_tls_handshake_completed);
   1182   mhd_assert (!c_tls->dbg.is_failed);
   1183 
   1184   mhd_tls_mbed_sckt_comm_prep (c_tls);
   1185 
   1186   res = mbedtls_ssl_close_notify (&(c_tls->sess));
   1187 
   1188   switch (res)
   1189   {
   1190   case 0:
   1191     c_tls->shut_tls_wr_sent = true;
   1192     c_tls->shut_tls_wr_received = true;
   1193     return mhd_TLS_PROCED_SUCCESS; /* Success exit point */
   1194 
   1195   case MBEDTLS_ERR_SSL_WANT_READ:
   1196     mhd_assert (!mhd_SOCKET_ERR_IS_HARD (c_tls->tr.state.recv_res));
   1197     mhd_assert (!mhd_SOCKET_ERR_IS_HARD (c_tls->tr.state.send_res));
   1198 
   1199     if (!c_tls->tr.state.recv_called)
   1200       return mhd_TLS_PROCED_RECV_INTERRUPTED; /* Do not clear 'recv-ready' flag */
   1201 
   1202     if (mhd_SOCKET_ERR_AGAIN == c_tls->tr.state.recv_res)
   1203       return mhd_TLS_PROCED_RECV_MORE_NEEDED; /* Clear 'recv-ready' flag */
   1204 
   1205     return mhd_TLS_PROCED_RECV_INTERRUPTED; /* Do not clear 'recv-ready' flag */
   1206 
   1207   case MBEDTLS_ERR_SSL_WANT_WRITE:
   1208     mhd_assert (!mhd_SOCKET_ERR_IS_HARD (c_tls->tr.state.recv_res));
   1209     mhd_assert (!mhd_SOCKET_ERR_IS_HARD (c_tls->tr.state.send_res));
   1210 
   1211     if (!c_tls->tr.state.send_called)
   1212       return mhd_TLS_PROCED_SEND_INTERRUPTED; /* Do not clear 'send-ready' flag */
   1213 
   1214     if (mhd_SOCKET_ERR_AGAIN == c_tls->tr.state.send_res)
   1215       return mhd_TLS_PROCED_SEND_MORE_NEEDED; /* Clear 'send-ready' flag */
   1216 
   1217     return mhd_TLS_PROCED_SEND_INTERRUPTED; /* Do not clear 'send-ready' flag */
   1218 
   1219   default:
   1220     break; /* Handle other values below */
   1221   }
   1222 
   1223   /* All other result codes must be interpreted as a hard error */
   1224 #ifndef NDEBUG
   1225   c_tls->dbg.is_failed = true;
   1226 #endif /* ! NDEBUG */
   1227 
   1228   return mhd_TLS_PROCED_FAILED;
   1229 }
   1230 
   1231 
   1232 /* ** Data receiving and sending ** */
   1233 
   1234 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_
   1235 MHD_FN_PAR_OUT_SIZE_ (3, 2)
   1236 MHD_FN_PAR_OUT_ (4) enum mhd_SocketError
   1237 mhd_tls_mbed_conn_recv (struct mhd_TlsMbedConnData *c_tls,
   1238                         size_t buf_size,
   1239                         char buf[MHD_FN_PAR_DYN_ARR_SIZE_ (buf_size)],
   1240                         size_t *restrict received)
   1241 {
   1242   int res;
   1243 
   1244   mhd_assert (0 != buf_size);
   1245 
   1246   mhd_assert (c_tls->dbg.is_inited);
   1247   mhd_assert (c_tls->dbg.is_tls_handshake_completed);
   1248   mhd_assert (!c_tls->shut_tls_wr_sent);
   1249   mhd_assert (!c_tls->dbg.is_failed);
   1250 
   1251   if (1)
   1252   {
   1253     const int buf_size_i = (int)buf_size;
   1254     if ((0 > buf_size_i)
   1255         || (buf_size != (size_t)buf_size_i))
   1256     {
   1257       /* Called function return value limitation */
   1258       buf_size = (size_t)(((unsigned int)~((unsigned int)0)) >> 1u);
   1259     }
   1260   }
   1261 
   1262   c_tls->recv_data_in_buff = false;
   1263   mhd_tls_mbed_sckt_comm_prep (c_tls);
   1264 
   1265   res = mbedtls_ssl_read (&(c_tls->sess),
   1266                           (unsigned char *)buf,
   1267                           buf_size);
   1268 
   1269   if (0 <= res)
   1270   {
   1271     mhd_ASSUME (buf_size >= (size_t)res);
   1272     *received = (size_t)res;
   1273 
   1274     return mhd_SOCKET_ERR_NO_ERROR; /* Success exit point */
   1275   }
   1276 
   1277   switch (res)
   1278   {
   1279   case MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY:
   1280     c_tls->shut_tls_wr_received = true;
   1281     *received = 0u;
   1282 
   1283     return mhd_SOCKET_ERR_NO_ERROR; /* Success exit point */
   1284 
   1285   case MBEDTLS_ERR_SSL_WANT_READ:
   1286     mhd_assert (!mhd_SOCKET_ERR_IS_HARD (c_tls->tr.state.recv_res));
   1287     mhd_assert (!mhd_SOCKET_ERR_IS_HARD (c_tls->tr.state.send_res));
   1288 
   1289     if (!c_tls->tr.state.recv_called)
   1290       return mhd_SOCKET_ERR_INTR; /* Do not clear 'recv-ready' flag */
   1291 
   1292     if (mhd_SOCKET_ERR_NO_ERROR == c_tls->tr.state.recv_res)
   1293     {
   1294       /* recv() succeed for the first time and then called again */
   1295       return c_tls->tr.sk->props.is_nonblck ?
   1296              mhd_SOCKET_ERR_INTR : mhd_SOCKET_ERR_AGAIN;
   1297     }
   1298 
   1299     return c_tls->tr.state.recv_res;
   1300 
   1301   case MBEDTLS_ERR_SSL_WANT_WRITE:
   1302     mhd_assert (0
   1303                 && "The handshake must be fully completed earlier");
   1304     break;
   1305 
   1306   case MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS:
   1307     mhd_assert (0 && "MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS must not be returned");
   1308     break;
   1309 
   1310   case MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS:
   1311     /* MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS means that recv() should be called
   1312        again later. Pretend that data is already pending to not block on
   1313        waiting for the new incoming data. */
   1314     c_tls->recv_data_in_buff = true;
   1315     return mhd_SOCKET_ERR_INTR; /* Do not clear 'recv-ready' flag */
   1316 
   1317   case MBEDTLS_ERR_SSL_CLIENT_RECONNECT:
   1318     mhd_assert (0
   1319                 && "MBEDTLS_ERR_SSL_CLIENT_RECONNECT must not be "
   1320                 "returned for non-DTLS");
   1321     break;
   1322 
   1323   case MBEDTLS_ERR_SSL_RECEIVED_NEW_SESSION_TICKET:
   1324     mhd_assert (0
   1325                 && "MBEDTLS_ERR_SSL_RECEIVED_NEW_SESSION_TICKET must not be "
   1326                 "returned on the server side");
   1327     break;
   1328 
   1329   case MBEDTLS_ERR_SSL_RECEIVED_EARLY_DATA:
   1330 #ifdef MBEDTLS_SSL_EARLY_DATA
   1331     /* Could be replaced with early data support is implemented */
   1332 #endif /* MBEDTLS_SSL_EARLY_DATA */
   1333     mhd_assert (0
   1334                 && "MBEDTLS_ERR_SSL_RECEIVED_EARLY_DATA must not be returned");
   1335     break;
   1336 
   1337   default:
   1338     break; /* Handle other values below */
   1339   }
   1340 
   1341   /* Treat all other kinds of errors as hard errors */
   1342 #ifndef NDEBUG
   1343   c_tls->dbg.is_failed = true;
   1344 #endif /* ! NDEBUG */
   1345   return mhd_SOCKET_ERR_TLS;
   1346 }
   1347 
   1348 
   1349 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ bool
   1350 mhd_tls_mbed_conn_has_data_in (struct mhd_TlsMbedConnData *restrict c_tls)
   1351 {
   1352   return c_tls->recv_data_in_buff
   1353          || (0 != mbedtls_ssl_check_pending (&(c_tls->sess)));
   1354 }
   1355 
   1356 
   1357 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_
   1358 MHD_FN_PAR_IN_SIZE_ (3, 2)
   1359 MHD_FN_PAR_OUT_ (5) enum mhd_SocketError
   1360 mhd_tls_mbed_conn_send (struct mhd_TlsMbedConnData *c_tls,
   1361                         size_t buf_size,
   1362                         const char buf[MHD_FN_PAR_DYN_ARR_SIZE_ (buf_size)],
   1363                         bool push_data,
   1364                         size_t *restrict sent)
   1365 {
   1366   int res;
   1367 
   1368   mhd_assert (0 != buf_size);
   1369 
   1370   mhd_assert (c_tls->dbg.is_inited);
   1371   mhd_assert (c_tls->dbg.is_tls_handshake_completed);
   1372   mhd_assert (!c_tls->shut_tls_wr_sent);
   1373   mhd_assert (!c_tls->dbg.is_failed);
   1374 
   1375   if (1)
   1376   {
   1377     const int buf_size_i = (int)buf_size;
   1378     if ((0 > buf_size_i)
   1379         || (buf_size != (size_t)buf_size_i))
   1380     {
   1381       /* Called function return value limitation */
   1382       buf_size = (size_t)(((unsigned int)~((unsigned int)0)) >> 1u);
   1383       push_data = false;
   1384     }
   1385   }
   1386 
   1387   mhd_tls_mbed_sckt_comm_prep_send (c_tls,
   1388                                     buf_size,
   1389                                     push_data);
   1390 
   1391   res = mbedtls_ssl_write (&(c_tls->sess),
   1392                            (const unsigned char *)buf,
   1393                            buf_size);
   1394 
   1395   if (0 < res)
   1396   {
   1397     mhd_ASSUME (buf_size >= (size_t)res);
   1398     *sent = (size_t)res;
   1399 
   1400     return mhd_SOCKET_ERR_NO_ERROR; /* Success exit point */
   1401   }
   1402 
   1403   switch (res)
   1404   {
   1405   case 0:
   1406     mhd_assert (0
   1407                 && "Zero must not be returned when sending non-zero size");
   1408     break;
   1409 
   1410   case MBEDTLS_ERR_SSL_WANT_WRITE:
   1411     mhd_assert (!mhd_SOCKET_ERR_IS_HARD (c_tls->tr.state.send_res));
   1412     mhd_assert (!mhd_SOCKET_ERR_IS_HARD (c_tls->tr.state.recv_res));
   1413 
   1414     if (!c_tls->tr.state.send_called)
   1415       return mhd_SOCKET_ERR_INTR; /* Do not clear 'recv-ready' flag */
   1416 
   1417     if (mhd_SOCKET_ERR_NO_ERROR == c_tls->tr.state.send_res)
   1418     {
   1419       /* send() succeed for the first time and then called again */
   1420       return c_tls->tr.sk->props.is_nonblck ?
   1421              mhd_SOCKET_ERR_INTR : mhd_SOCKET_ERR_AGAIN;
   1422     }
   1423 
   1424     return c_tls->tr.state.send_res;
   1425 
   1426   case MBEDTLS_ERR_SSL_WANT_READ:
   1427     mhd_assert (0
   1428                 && "The handshake must be fully completed earlier");
   1429     break;
   1430 
   1431   case MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS:
   1432     mhd_assert (0 && "MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS must not be returned");
   1433     break;
   1434 
   1435   case MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS:
   1436     /* MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS means that send() should be called
   1437        again later. Wait for 'send-ready' which should be already set or
   1438        will be set later, when OS pushed the data to the network. */
   1439     return mhd_SOCKET_ERR_INTR; /* Do not clear 'recv-ready' flag */
   1440 
   1441   case MBEDTLS_ERR_SSL_CLIENT_RECONNECT:
   1442     mhd_assert (0
   1443                 && "MBEDTLS_ERR_SSL_CLIENT_RECONNECT must not be "
   1444                 "returned for non-DTLS");
   1445     break;
   1446 
   1447   case MBEDTLS_ERR_SSL_RECEIVED_NEW_SESSION_TICKET:
   1448     mhd_assert (0
   1449                 && "MBEDTLS_ERR_SSL_RECEIVED_NEW_SESSION_TICKET must not be "
   1450                 "returned on the server side");
   1451     break;
   1452 
   1453   case MBEDTLS_ERR_SSL_RECEIVED_EARLY_DATA:
   1454 #ifdef MBEDTLS_SSL_EARLY_DATA
   1455     /* Could be replaced with early data support is implemented */
   1456 #endif /* MBEDTLS_SSL_EARLY_DATA */
   1457     mhd_assert (0
   1458                 && "MBEDTLS_ERR_SSL_RECEIVED_EARLY_DATA must not be returned");
   1459     break;
   1460 
   1461   default:
   1462     break; /* Handle other values below */
   1463   }
   1464 
   1465   /* Treat all other kinds of errors as hard errors */
   1466 #ifndef NDEBUG
   1467   c_tls->dbg.is_failed = true;
   1468 #endif /* ! NDEBUG */
   1469   return mhd_SOCKET_ERR_TLS;
   1470 }
   1471 
   1472 
   1473 /* ** TLS connection information ** */
   1474 
   1475 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_
   1476 MHD_FN_PAR_OUT_ (2) void
   1477 mhd_tls_mbed_conn_get_tls_sess (
   1478   struct mhd_TlsMbedConnData *restrict c_tls,
   1479   union MHD_ConnInfoDynamicTlsSess *restrict tls_sess_out)
   1480 {
   1481   tls_sess_out->v_mbedtls_session = &(c_tls->sess);
   1482 }
   1483 
   1484 
   1485 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_
   1486 MHD_FN_PAR_OUT_ (2) bool
   1487 mhd_tls_mbed_conn_get_tls_ver (struct mhd_TlsMbedConnData *restrict c_tls,
   1488                                struct mhd_StctTlsVersion *restrict tls_ver_out)
   1489 {
   1490   mhd_assert (c_tls->dbg.is_tls_handshake_completed);
   1491 
   1492 #ifndef MBEDTLS_VERSION_NUMBER
   1493   if (1)
   1494     return false; /* Need MbedTLS version number to implement */
   1495 #else  /* MBEDTLS_VERSION_NUMBER */
   1496   if (1)
   1497   {
   1498     uint_fast16_t tls_ver_num;
   1499 #  if ((MBEDTLS_VERSION_NUMBER + 0) >= 0x03020000)
   1500     mbedtls_ssl_protocol_version mbedtls_tls_ver;
   1501 
   1502     mbedtls_tls_ver = mbedtls_ssl_get_version_number (&(c_tls->sess));
   1503 
   1504     tls_ver_num = (uint_fast16_t)mbedtls_tls_ver;
   1505 #  else  /* MBEDTLS_VERSION_NUMBER < 0x03020000 */
   1506     tls_ver_num = (uint_fast16_t)c_tls->sess.MBEDTLS_PRIVATE (major_ver);
   1507     tls_ver_num <<= 8u;
   1508     tls_ver_num |= (uint_fast16_t)c_tls->sess.MBEDTLS_PRIVATE (minor_ver);
   1509 #  endif /* MBEDTLS_VERSION_NUMBER < 0x03020000 */
   1510     /* Avoid MbedTLS helper macros and enum values in switch() as they are
   1511        unstable in MbedTLS. */
   1512     switch (tls_ver_num)
   1513     {
   1514     case 0u:
   1515       return false;
   1516 
   1517     case 0x0301u: /* Not really supported by MbedTLS >=3.0 */
   1518       tls_ver_out->tls_ver = MHD_TLS_VERSION_1_0;
   1519       break;
   1520 
   1521     case 0x0302u: /* Not really supported by MbedTLS >=3.0 */
   1522       tls_ver_out->tls_ver = MHD_TLS_VERSION_1_1;
   1523       break;
   1524 
   1525     case 0x0303u:
   1526       tls_ver_out->tls_ver = MHD_TLS_VERSION_1_2;
   1527       break;
   1528 
   1529     case 0x0304u:
   1530       tls_ver_out->tls_ver = MHD_TLS_VERSION_1_3;
   1531       break;
   1532 
   1533     default:
   1534       tls_ver_out->tls_ver = MHD_TLS_VERSION_UNKNOWN;
   1535       break;
   1536     }
   1537   }
   1538 #endif /* MBEDTLS_VERSION_NUMBER */
   1539 
   1540   return true;
   1541 }
   1542 
   1543 
   1544 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ enum mhd_TlsAlpnProt
   1545 mhd_tls_mbed_conn_get_alpn_prot (struct mhd_TlsMbedConnData *restrict c_tls)
   1546 {
   1547 #ifdef MBEDTLS_SSL_ALPN
   1548   const char *alpn_str;
   1549 
   1550   alpn_str = mbedtls_ssl_get_alpn_protocol (&(c_tls->sess));
   1551   if (NULL == alpn_str)
   1552     return mhd_TLS_ALPN_PROT_NOT_SELECTED;
   1553 
   1554   return mhd_tls_alpn_decode_n (strlen (alpn_str),
   1555                                 (const unsigned char *)alpn_str);
   1556 #else  /* ! MBEDTLS_SSL_ALPN */
   1557   return mhd_TLS_ALPN_PROT_NOT_SELECTED;
   1558 #endif /* ! MBEDTLS_SSL_ALPN */
   1559 }