libmicrohttpd2

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

tls_mbed_funcs.c (48978B)


      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   return MHD_SC_OK;
    449 }
    450 
    451 
    452 #if defined(mhd_TLS_MBED_INIT_TLS_REQ_RNG)
    453 /**
    454  * Set daemon TLS credentials.
    455  * This function puts error messages to the log if needed.
    456  * @param d the daemon handle
    457  * @param d_tls the daemon TLS settings
    458  * @param s the application-provided settings
    459  * @param rng_func the random generator function
    460  * @param rng_ctx the random generator function context
    461  * @return #MHD_SC_OK on success,
    462  *         error code otherwise
    463  */
    464 #else  /* ! 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  * @return #MHD_SC_OK on success,
    472  *         error code otherwise
    473  */
    474 #endif /* ! mhd_TLS_MBED_INIT_TLS_REQ_RNG */
    475 static MHD_FN_PAR_NONNULL_ (1) MHD_FN_PAR_NONNULL_ (2)
    476 MHD_FN_PAR_NONNULL_ (3) MHD_FN_MUST_CHECK_RESULT_ enum MHD_StatusCode
    477 daemon_init_credentials (
    478   struct MHD_Daemon *restrict d,
    479   struct mhd_TlsMbedDaemonData *restrict d_tls,
    480   struct DaemonOptions *restrict s
    481 #if defined(mhd_TLS_MBED_INIT_TLS_REQ_RNG)
    482   ,
    483   int (*rng_func)(void *ctx, unsigned char *out, size_t out_size),
    484   void *rng_ctx
    485 #endif /* mhd_TLS_MBED_INIT_TLS_REQ_RNG */
    486   )
    487 {
    488   enum MHD_StatusCode ret;
    489   size_t cert_len;
    490   size_t key_len;
    491   size_t pwd_len;
    492   int res;
    493 
    494   ret = MHD_SC_OK;
    495 
    496   // TODO: Support multiple certificates
    497   cert_len = strlen (s->tls_cert_key.v_mem_cert); // TODO: Reuse calculated length
    498   key_len = strlen (s->tls_cert_key.v_mem_key);   // TODO: Reuse calculated length
    499   pwd_len = (NULL == s->tls_cert_key.v_mem_pass) ?
    500             0u : strlen (s->tls_cert_key.v_mem_pass); // TODO: Reuse calculated length
    501 
    502   mhd_assert (0 != cert_len);
    503   mhd_assert (0 != key_len);
    504 
    505   mbedtls_x509_crt_init (&(d_tls->cert_chain));
    506 
    507   res = mbedtls_x509_crt_parse (&(d_tls->cert_chain),
    508                                 (const unsigned char *)
    509                                 s->tls_cert_key.v_mem_cert,
    510                                 cert_len + 1u /* Include terminating zero */);
    511   if (0 == res)
    512   {
    513     mbedtls_pk_init (&(d_tls->prv_key));
    514 #if defined(mhd_TLS_MBED_INIT_TLS_REQ_RNG)
    515     if (0 != mbedtls_pk_parse_key (&(d_tls->prv_key),
    516                                    (const unsigned char *)
    517                                    s->tls_cert_key.v_mem_key,
    518                                    key_len + 1u,
    519                                    (const unsigned char *)
    520                                    s->tls_cert_key.v_mem_pass,
    521                                    pwd_len,
    522                                    rng_func,
    523                                    rng_ctx))
    524       ret = MHD_SC_TLS_CONF_BAD_CERT;
    525 #else  /* ! mhd_TLS_MBED_INIT_TLS_REQ_RNG */
    526     if (0 != mbedtls_pk_parse_key (&(d_tls->prv_key),
    527                                    (const unsigned char *)
    528                                    s->tls_cert_key.v_mem_key,
    529                                    key_len + 1u,
    530                                    (const unsigned char *)
    531                                    s->tls_cert_key.v_mem_pass,
    532                                    pwd_len))
    533       ret = MHD_SC_TLS_CONF_BAD_CERT;
    534 #endif  /* ! mhd_TLS_MBED_INIT_TLS_REQ_RNG */
    535 
    536     if (MHD_SC_OK == ret)
    537     {
    538       /* The next macro can be defined at MHD build-time to skip potentially
    539          expensive check */
    540 #ifdef MHD_TLS_MBED_SKIP_CERT_KEY_MATCH_CHECK
    541       return MHD_SC_OK; /* Success exit point */
    542 #else  /* ! MHD_TLS_MBED_SKIP_CERT_KEY_MATCH_CHECK */
    543 #  if defined(mhd_TLS_MBED_INIT_TLS_REQ_RNG)
    544       res =  mbedtls_pk_check_pair (&(d_tls->cert_chain.pk),
    545                                     &(d_tls->prv_key),
    546                                     rng_func,
    547                                     rng_ctx);
    548 #  else  /* ! mhd_TLS_MBED_INIT_TLS_REQ_RNG */
    549       res =  mbedtls_pk_check_pair (&(d_tls->cert_chain.pk),
    550                                     &(d_tls->prv_key));
    551 #  endif  /* ! mhd_TLS_MBED_INIT_TLS_REQ_RNG */
    552       if ((0 == res) ||
    553           (MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE == res))
    554         return MHD_SC_OK; /* Success exit point */
    555 
    556       mhd_LOG_MSG (d, MHD_SC_TLS_CONF_BAD_CERT, \
    557                    "The private key data does not match the certificate");
    558       ret = MHD_SC_TLS_CONF_BAD_CERT;
    559 #endif /* ! MHD_TLS_MBED_SKIP_CERT_KEY_MATCH_CHECK */
    560     }
    561     else
    562     {
    563       mhd_LOG_MSG (d, MHD_SC_TLS_CONF_BAD_CERT, \
    564                    "The private key data cannot be decoded");
    565       ret = MHD_SC_TLS_CONF_BAD_CERT;
    566     }
    567 
    568     mbedtls_pk_free (&(d_tls->prv_key));
    569   }
    570   else
    571   {
    572     mhd_LOG_PRINT (d,
    573                    MHD_SC_TLS_CONF_BAD_CERT,
    574                    mhd_LOG_FMT ("Failed to parse certificates chain. "
    575                                 "Number of failed certificates: %i"),
    576                    res);
    577     ret = MHD_SC_TLS_CONF_BAD_CERT;
    578   }
    579   mbedtls_x509_crt_free (&(d_tls->cert_chain));
    580 
    581   mhd_assert (MHD_SC_OK != ret);
    582   return ret; /* Failure exit point */
    583 }
    584 
    585 
    586 /**
    587  * De-initialise daemon TLS credentials.
    588  * @param d_tls the daemon TLS settings
    589  */
    590 static MHD_FN_PAR_NONNULL_ALL_ void
    591 daemon_deinit_credentials (struct mhd_TlsMbedDaemonData *restrict d_tls)
    592 {
    593   mbedtls_pk_free (&(d_tls->prv_key));
    594 
    595   mbedtls_x509_crt_free (&(d_tls->cert_chain));
    596 }
    597 
    598 
    599 #ifdef MBEDTLS_SSL_ALPN
    600 /**
    601  * Initialise daemon ALPN data
    602  * This function puts error messages to the log if needed.
    603  * @param d the daemon handle
    604  * @param d_tls the daemon TLS settings
    605  * @param s the application-provided settings
    606  * @return #MHD_SC_OK on success,
    607  *         error code otherwise
    608  */
    609 static MHD_FN_PAR_NONNULL_ALL_ MHD_FN_MUST_CHECK_RESULT_ enum MHD_StatusCode
    610 daemon_set_alpn (struct MHD_Daemon *restrict d,
    611                  struct mhd_TlsMbedDaemonData *restrict d_tls,
    612                  struct DaemonOptions *restrict s)
    613 {
    614   static const char alpn_str_http1_0[] = mhd_ALPN_H1_0;
    615   static const char alpn_str_http1_1[] = mhd_ALPN_H1_1;
    616 #  ifdef MHD_SUPPORT_HTTP2
    617   static const char alpn_str_http2[] = mhd_ALPN_H2;
    618 #  endif
    619   size_t i;
    620 
    621   (void) s; /* Unused currently. Implement reading allowed HTTP versions */
    622 
    623   i = 0u;
    624   // TODO: implement reading protocol versions from settings */
    625 #ifdef MHD_SUPPORT_HTTP2
    626   if (1 /* enabled HTTP/2 ? */)
    627     d_tls->alpn_prots[i++] = alpn_str_http2;
    628 #endif /* MHD_SUPPORT_HTTP2 */
    629 
    630   if (1 /* enabled HTTP/1.x ? */)
    631   {
    632     d_tls->alpn_prots[i++] = alpn_str_http1_1;
    633     d_tls->alpn_prots[i++] = alpn_str_http1_0;
    634   }
    635 
    636   d_tls->alpn_prots[i] = NULL; /* NULL termination */
    637   mhd_assert (mhd_ARR_NUM_ELEMS (d_tls->alpn_prots) > i);
    638   mhd_assert (0u != i);
    639 
    640   if (0 == mbedtls_ssl_conf_alpn_protocols (&(d_tls->tls_conf),
    641                                             d_tls->alpn_prots))
    642     return MHD_SC_OK; /* Success exit point */
    643 
    644   mhd_LOG_MSG (d, MHD_SC_TLS_DAEMON_INIT_FAILED, \
    645                "Failed to set ALPN data");
    646   return MHD_SC_TLS_DAEMON_INIT_FAILED;
    647 }
    648 
    649 
    650 #else  /* ! MBEDTLS_SSL_ALPN */
    651 #  define daemon_set_alpn(d,d_tls,s) (MHD_SC_OK)
    652 #endif /* ! MBEDTLS_SSL_ALPN */
    653 
    654 /**
    655  * Set daemon TLS configuration.
    656  * This function puts error messages to the log if needed.
    657  * @param d the daemon handle
    658  * @param d_tls the daemon TLS settings
    659  * @param s the application-provided settings
    660  * @return #MHD_SC_OK on success,
    661  *         error code otherwise
    662  */
    663 static MHD_FN_PAR_NONNULL_ALL_ MHD_FN_MUST_CHECK_RESULT_ enum MHD_StatusCode
    664 daemon_init_config (struct MHD_Daemon *restrict d,
    665                     struct mhd_TlsMbedDaemonData *restrict d_tls,
    666                     struct DaemonOptions *restrict s)
    667 {
    668   enum MHD_StatusCode ret;
    669 #if defined(mhd_TLS_MBED_INIT_TLS_REQ_RNG)
    670   int (*rng_func)(void *ctx, unsigned char *out, size_t out_size);
    671   void *rng_ctx;
    672 
    673 #  if defined(MHD_TLS_MBED_PREF_RNG_CTR)
    674   rng_func = &mbedtls_ctr_drbg_random;
    675   rng_ctx = &mhd_mbed_ctr_drbg_ctx;
    676 #  elif defined(MHD_TLS_MBED_PREF_RNG_HMAC)
    677   rng_func = &mbedtls_hmac_drbg_random;
    678   rng_ctx = &mhd_mbed_hmac_drbg_ctx;
    679 #  elif defined(MHD_TLS_MBED_PREF_RNG_PSA)
    680   rng_func = &mbedtls_psa_get_random;
    681   rng_ctx = MBEDTLS_PSA_RANDOM_STATE;
    682 #  else  /* MHD_TLS_MBED_PREF_RNG_PSA */
    683   /* Support for external strong random generator could be added here */
    684 #error No random generator is enabled in MbedTLS
    685   return MHD_SC_INTERNAL_ERROR;
    686 #  endif /* MHD_TLS_MBED_PREF_RNG_PSA */
    687 
    688   ret = daemon_init_credentials (d,
    689                                  d_tls,
    690                                  s,
    691                                  rng_func,
    692                                  rng_ctx);
    693 #else  /* mhd_TLS_MBED_INIT_TLS_REQ_RNG */
    694   ret = daemon_init_credentials (d,
    695                                  d_tls,
    696                                  s);
    697 #endif /* mhd_TLS_MBED_INIT_TLS_REQ_RNG */
    698 
    699   if (MHD_SC_OK != ret)
    700     return ret;
    701 
    702   mbedtls_ssl_config_init (&(d_tls->tls_conf));
    703 
    704 #ifdef mhd_TLS_MBED_HAS_DEBUG_PRINT
    705   mbedtls_ssl_conf_dbg (&(d_tls->tls_conf),
    706                         mhd_tls_mbed_debug_print,
    707                         NULL);
    708   mbedtls_debug_set_threshold (mhd_DBG_PRINT_LEVEL);
    709 #endif /* mhd_TLS_MBED_HAS_DEBUG_PRINT */
    710 
    711   if (0 ==
    712       mbedtls_ssl_config_defaults (&(d_tls->tls_conf),
    713                                    MBEDTLS_SSL_IS_SERVER,
    714                                    MBEDTLS_SSL_TRANSPORT_STREAM,
    715                                    MBEDTLS_SSL_PRESET_DEFAULT))
    716   {
    717 #if defined(mhd_TLS_MBED_INIT_TLS_REQ_RNG)
    718     mbedtls_ssl_conf_rng (&(d_tls->tls_conf),
    719                           rng_func,
    720                           rng_ctx);
    721 #endif /* mhd_TLS_MBED_INIT_TLS_REQ_RNG */
    722 
    723     /* Client certificates are not implemented yet */
    724     mbedtls_ssl_conf_authmode (&(d_tls->tls_conf),
    725                                MBEDTLS_SSL_VERIFY_NONE);
    726 
    727     if (0 ==
    728         mbedtls_ssl_conf_own_cert (&(d_tls->tls_conf),
    729                                    &(d_tls->cert_chain),
    730                                    &(d_tls->prv_key)))
    731     {
    732       ret = daemon_set_alpn (d,
    733                              d_tls,
    734                              s);
    735       if (MHD_SC_OK == ret)
    736         return MHD_SC_OK; /* Success exit point */
    737 
    738       /* Below is a cleanup path */
    739     }
    740     else
    741       ret = MHD_SC_DAEMON_MEM_ALLOC_FAILURE; /* Do not waste binary space on the additional message */
    742   }
    743   else
    744     ret = MHD_SC_DAEMON_MEM_ALLOC_FAILURE; /* Do not waste binary space on the additional message */
    745 
    746   mbedtls_ssl_config_free (&(d_tls->tls_conf));
    747 
    748   daemon_deinit_credentials (d_tls);
    749 
    750   mhd_assert (MHD_SC_OK != ret);
    751   return ret; /* Failure exit point */
    752 }
    753 
    754 
    755 MHD_INTERNAL MHD_FN_MUST_CHECK_RESULT_ MHD_FN_PAR_NONNULL_ALL_
    756 MHD_FN_PAR_OUT_ (3) mhd_StatusCodeInt
    757 mhd_tls_mbed_daemon_init3 (struct MHD_Daemon *restrict d,
    758                            struct DaemonOptions *restrict s,
    759                            struct mhd_TlsMbedDaemonData **restrict p_d_tls)
    760 {
    761   mhd_StatusCodeInt res;
    762   struct mhd_TlsMbedDaemonData *restrict d_tls;
    763 
    764   /* Successful initialisation must be checked earlier */
    765   mhd_assert (mbedtls_lib_inited_once);
    766   mhd_assert (mbedtls_lib_inited_now);
    767 
    768   res = check_app_tls_settings (d,
    769                                 s);
    770   if (MHD_SC_OK != res)
    771     return res;
    772 
    773   d_tls = (struct mhd_TlsMbedDaemonData *)
    774           mhd_calloc (1, sizeof (struct mhd_TlsMbedDaemonData));
    775   *p_d_tls = d_tls;
    776   if (NULL == d_tls)
    777     return MHD_SC_DAEMON_MEM_ALLOC_FAILURE;
    778 
    779   res = daemon_init_config (d,
    780                             d_tls,
    781                             s);
    782   if (MHD_SC_OK == res)
    783   {
    784     return MHD_SC_OK; /* Success exit point */
    785   }
    786   /* Below is a clean-up code path */
    787   free (d_tls);
    788   *p_d_tls = NULL;
    789   mhd_assert (MHD_SC_OK != res);
    790   return res; /* Failure exit point */
    791 }
    792 
    793 
    794 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_
    795 MHD_FN_PAR_INOUT_ (1) void
    796 mhd_tls_mbed_daemon_deinit (struct mhd_TlsMbedDaemonData *restrict d_tls)
    797 {
    798   mhd_assert (NULL != d_tls);
    799 
    800   mbedtls_ssl_config_free (&(d_tls->tls_conf));
    801 
    802   daemon_deinit_credentials (d_tls);
    803 
    804   free (d_tls);
    805 }
    806 
    807 
    808 /* ** Connection initialisation / de-initialisation ** */
    809 
    810 MHD_INTERNAL size_t
    811 mhd_tls_mbed_conn_get_tls_size_v (void)
    812 {
    813   return sizeof (struct mhd_TlsMbedConnData);
    814 }
    815 
    816 
    817 /* Forward declarations of custom transport callbacks */
    818 static int
    819 mhd_mbed_cb_recv (void *ctx,
    820                   unsigned char *buf,
    821                   size_t size);
    822 
    823 static int
    824 mhd_mbed_cb_send (void *ctx,
    825                   const unsigned char *buf,
    826                   size_t size);
    827 
    828 MHD_INTERNAL MHD_FN_MUST_CHECK_RESULT_ MHD_FN_PAR_NONNULL_ALL_
    829 MHD_FN_PAR_OUT_ (3) bool
    830 mhd_tls_mbed_conn_init (const struct mhd_TlsMbedDaemonData *restrict d_tls,
    831                         struct mhd_ConnSocket *sk,
    832                         struct mhd_TlsMbedConnData *restrict c_tls)
    833 {
    834   c_tls->tr.sk = sk;
    835 
    836   mbedtls_ssl_init (&(c_tls->sess));
    837 
    838   if (0 == mbedtls_ssl_setup (&(c_tls->sess),
    839                               &(d_tls->tls_conf)))
    840   {
    841     mbedtls_ssl_set_bio (&(c_tls->sess),
    842                          c_tls,
    843                          &mhd_mbed_cb_send,
    844                          &mhd_mbed_cb_recv,
    845                          NULL /* no recv_timeout callback */);
    846 
    847 #ifndef NDEBUG
    848     c_tls->dbg.is_inited = true;
    849 #endif
    850     return true; /* Success exit point */
    851   }
    852 
    853   mbedtls_ssl_free (&(c_tls->sess));
    854   return false; /* Failure exit point */
    855 }
    856 
    857 
    858 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ void
    859 mhd_tls_mbed_conn_deinit (struct mhd_TlsMbedConnData *restrict c_tls)
    860 {
    861   mhd_assert (c_tls->dbg.is_inited);
    862   mbedtls_ssl_free (&(c_tls->sess));
    863 #ifndef NDEBUG
    864   c_tls->dbg.is_inited = false;
    865 #endif
    866 }
    867 
    868 
    869 /* ** Custom transport functions ** */
    870 
    871 /**
    872  * Prepare for network operation
    873  * @param c_tls the connection TLS data
    874  */
    875 mhd_static_inline MHD_FN_PAR_NONNULL_ALL_ void
    876 mhd_tls_mbed_sckt_comm_prep (struct mhd_TlsMbedConnData *restrict c_tls)
    877 {
    878   memset (&(c_tls->tr.state),
    879           0,
    880           sizeof(c_tls->tr.state));
    881 }
    882 
    883 
    884 /**
    885  * Prepare for send() network operation
    886  * @param c_tls the connection TLS data
    887  * @param unencr_size the size of the data to send before encryption
    888  * @param push_data set to 'false' if it is know that the data to be sent
    889  *                  is incomplete (message or chunk),
    890  *                  set to 'true' if the data is complete or the final part
    891  */
    892 mhd_static_inline MHD_FN_PAR_NONNULL_ALL_ void
    893 mhd_tls_mbed_sckt_comm_prep_send (struct mhd_TlsMbedConnData *restrict c_tls,
    894                                   size_t unencr_size,
    895                                   bool push_data)
    896 {
    897   mhd_tls_mbed_sckt_comm_prep (c_tls);
    898 
    899   if (push_data)
    900     c_tls->tr.state.send_unenc_size = unencr_size;
    901   else
    902     c_tls->tr.state.send_unenc_size = (size_t) (~((size_t) 0));
    903 }
    904 
    905 
    906 /**
    907  * The callback which called by MbedTLS to receive the data
    908  * @param ctx the context for the send callback
    909  * @param buf the buffer to put received data
    910  * @param size the size of the @a buf
    911  * @return the positive number of bytes received on success,
    912  *         0 if EOF received (peer closed write/send),
    913  *         #MBEDTLS_ERR_SSL_WANT_READ if receiving would block OR
    914  *                                    receiving was interrupted,
    915  *         #MBEDTLS_ERR_NET_CONN_RESET if connection was broken
    916  *         or #MBEDTLS_ERR_NET_RECV_FAILED in case of other errors
    917  */
    918 static int
    919 mhd_mbed_cb_recv (void *ctx,
    920                   unsigned char *buf,
    921                   size_t size)
    922 {
    923   struct mhd_TlsMbedConnData *const c_tls = (struct mhd_TlsMbedConnData *) ctx;
    924   struct mhd_TlsMbedConnCstmTrtState *const state = &(c_tls->tr.state);
    925   size_t received;
    926 
    927   /* MbedTLS may call recv() several times.
    928      This may result in unwanted extra syscalls, unfair connections
    929      processing or even blocking if socket is blocking.
    930      MHD limits to single send() syscall per operation to evenly distribute
    931      workload to all connections. */
    932   if (state->recv_called)
    933     return MBEDTLS_ERR_SSL_WANT_READ;
    934 
    935   /* MbedTLS may call blindly recv() after calling send() first.
    936      If send() was the first socket operation then the socket has been
    937      checked by MHD for 'send-ready' as receiving operation was expected.
    938      Do not use recv() if 'recv-ready' is not known and the socket is blocking.
    939    */
    940   if (state->send_called && ! c_tls->tr.sk->props.is_nonblck)
    941     return MBEDTLS_ERR_SSL_WANT_READ;
    942 
    943   if (1)
    944   {
    945     const int size_i = (int) size;
    946 
    947     if ((0 > size_i) ||
    948         (size != (size_t) size_i))
    949     {
    950       /* Return value limitation */
    951       size = (size_t) (((unsigned int) ~((unsigned int) 0)) >> 1u);
    952     }
    953   }
    954 
    955   state->recv_res = mhd_sckt_recv (c_tls->tr.sk,
    956                                    size,
    957                                    (char *) buf,
    958                                    &received);
    959   state->recv_called = true;
    960 
    961   if (mhd_SOCKET_ERR_NO_ERROR == state->recv_res)
    962   {
    963     mhd_ASSUME (size >= received);
    964     mhd_assert (0 <= (int) received);
    965     return (int) received;
    966   }
    967 
    968   if (mhd_SOCKET_ERR_INTR >= state->recv_res)
    969   {
    970     mhd_assert ((mhd_SOCKET_ERR_INTR == state->recv_res) ||
    971                 (mhd_SOCKET_ERR_AGAIN == state->recv_res));
    972     return MBEDTLS_ERR_SSL_WANT_READ;
    973   }
    974 
    975   if (mhd_SOCKET_ERR_IS_HARD (state->recv_res))
    976   {
    977     c_tls->tr.sk->state.discnt_err = state->recv_res;
    978     return MBEDTLS_ERR_NET_CONN_RESET;
    979   }
    980 
    981   return MBEDTLS_ERR_NET_RECV_FAILED;
    982 }
    983 
    984 
    985 /**
    986  * The callback called by MbedTLS to send the data
    987  * @param ctx the context for the send callback
    988  * @param buf the buffer with the data to send
    989  * @param size the size of the data in the @a buf
    990  * @return the positive number of bytes sent on success,
    991  *         #MBEDTLS_ERR_SSL_WANT_WRITE if sending would block OR
    992  *                                     sending was interrupted,
    993  *         #MBEDTLS_ERR_NET_CONN_RESET if connection was broken
    994  *         or #MBEDTLS_ERR_NET_SEND_FAILED in case of other errors
    995  */
    996 static int
    997 mhd_mbed_cb_send (void *ctx,
    998                   const unsigned char *buf,
    999                   size_t size)
   1000 {
   1001   struct mhd_TlsMbedConnData *const c_tls = (struct mhd_TlsMbedConnData *) ctx;
   1002   struct mhd_TlsMbedConnCstmTrtState *const state = &(c_tls->tr.state);
   1003   /* Check whether the complete data is sending.
   1004      The compression is not used so the data after the encryption must not
   1005      be smaller than before the encryption.
   1006      The check may result in false-positive (unlikely in practice), but
   1007      this should not hurt the performance. */
   1008   bool push_data = (size >= state->send_unenc_size);
   1009   size_t sent;
   1010 
   1011   /* MbedTLS may call send() several times in a loop, until all data is sent.
   1012      This may result in unwanted extra syscalls, unfair connections processing
   1013      or even blocking if socket is blocking.
   1014      MHD limits to single send() syscall per operation to evenly distribute
   1015      workload to all connections. */
   1016   if (state->send_called)
   1017     return MBEDTLS_ERR_SSL_WANT_WRITE;
   1018 
   1019   /* MbedTLS may call blindly send() after calling recv() first.
   1020      If recv() was the first socket operation then the socket has been
   1021      checked by MHD for 'recv-ready' as receiving operation was expected.
   1022      Do not use send() if 'send-ready' is not known and the socket is blocking.
   1023    */
   1024   if (state->recv_called && ! c_tls->tr.sk->props.is_nonblck)
   1025     return MBEDTLS_ERR_SSL_WANT_WRITE;
   1026 
   1027   if (1)
   1028   {
   1029     const int size_i = (int) size;
   1030 
   1031     if ((0 > size_i) ||
   1032         (size != (size_t) size_i))
   1033     {
   1034       /* Return value limitation */
   1035       size = (size_t) (((unsigned int) ~((unsigned int) 0)) >> 1u);
   1036       push_data = false;
   1037     }
   1038   }
   1039 
   1040   state->send_res = mhd_sckt_send (c_tls->tr.sk,
   1041                                    size,
   1042                                    (const char *) buf,
   1043                                    push_data,
   1044                                    &sent);
   1045   state->send_called = true;
   1046 
   1047   if (mhd_SOCKET_ERR_NO_ERROR == state->send_res)
   1048   {
   1049     mhd_ASSUME (size >= sent);
   1050     mhd_assert (0 < (int) sent);
   1051     return (int) sent;
   1052   }
   1053 
   1054   if (mhd_SOCKET_ERR_INTR >= state->send_res)
   1055   {
   1056     mhd_assert ((mhd_SOCKET_ERR_INTR == state->send_res) ||
   1057                 (mhd_SOCKET_ERR_AGAIN == state->send_res));
   1058     return MBEDTLS_ERR_SSL_WANT_WRITE;
   1059   }
   1060 
   1061   if (mhd_SOCKET_ERR_IS_HARD (state->send_res))
   1062   {
   1063     c_tls->tr.sk->state.discnt_err = state->send_res;
   1064     return MBEDTLS_ERR_NET_CONN_RESET;
   1065   }
   1066 
   1067   return MBEDTLS_ERR_NET_SEND_FAILED;
   1068 }
   1069 
   1070 
   1071 /* ** TLS connection establishing ** */
   1072 
   1073 MHD_INTERNAL MHD_FN_MUST_CHECK_RESULT_ MHD_FN_PAR_NONNULL_ALL_
   1074 enum mhd_TlsProcedureResult
   1075 mhd_tls_mbed_conn_handshake (struct mhd_TlsMbedConnData *c_tls)
   1076 {
   1077   int res;
   1078 
   1079   mhd_assert (c_tls->dbg.is_inited);
   1080   mhd_assert (! c_tls->dbg.is_tls_handshake_completed);
   1081   mhd_assert (! c_tls->shut_tls_wr_sent);
   1082   mhd_assert (! c_tls->shut_tls_wr_received);
   1083   mhd_assert (! c_tls->dbg.is_failed);
   1084 
   1085   mhd_tls_mbed_sckt_comm_prep (c_tls);
   1086 
   1087   res = mbedtls_ssl_handshake (&(c_tls->sess));
   1088 
   1089   mhd_assert ((c_tls->tr.state.recv_called) ||
   1090               (mhd_SOCKET_ERR_NO_ERROR == c_tls->tr.state.recv_res));
   1091   mhd_assert ((c_tls->tr.state.send_called) ||
   1092               (mhd_SOCKET_ERR_NO_ERROR == c_tls->tr.state.send_res));
   1093 
   1094   switch (res)
   1095   {
   1096   case 0:
   1097 #ifndef NDEBUG
   1098     c_tls->dbg.is_tls_handshake_completed = true;
   1099 #endif /* ! NDEBUG */
   1100     return mhd_TLS_PROCED_SUCCESS; /* Success exit point */
   1101 
   1102   case MBEDTLS_ERR_SSL_WANT_READ:
   1103     mhd_assert (! mhd_SOCKET_ERR_IS_HARD (c_tls->tr.state.recv_res));
   1104     mhd_assert (! mhd_SOCKET_ERR_IS_HARD (c_tls->tr.state.send_res));
   1105 
   1106     if (! c_tls->tr.state.recv_called)
   1107       return mhd_TLS_PROCED_RECV_INTERRUPTED; /* Do not clear 'recv-ready' flag */
   1108 
   1109     if (mhd_SOCKET_ERR_AGAIN == c_tls->tr.state.recv_res)
   1110       return mhd_TLS_PROCED_RECV_MORE_NEEDED; /* Clear 'recv-ready' flag */
   1111 
   1112     return mhd_TLS_PROCED_RECV_INTERRUPTED; /* Do not clear 'recv-ready' flag */
   1113 
   1114   case MBEDTLS_ERR_SSL_WANT_WRITE:
   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.send_called)
   1119       return mhd_TLS_PROCED_SEND_INTERRUPTED; /* Do not clear 'send-ready' flag */
   1120 
   1121     if (mhd_SOCKET_ERR_AGAIN == c_tls->tr.state.send_res)
   1122       return mhd_TLS_PROCED_SEND_MORE_NEEDED; /* Clear 'send-ready' flag */
   1123 
   1124     return mhd_TLS_PROCED_SEND_INTERRUPTED; /* Do not clear 'send-ready' flag */
   1125 
   1126   case MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS:
   1127     mhd_assert (0 && "MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS must not be returned");
   1128     break;
   1129 
   1130   case MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS:
   1131     /* The result means that mbedtls_ssl_handshake() must be called again
   1132        later.
   1133        As this result does not map directly to any of available flags,
   1134        so map it to "waiting for send-ready" as the socket should be already
   1135        'send-ready'. */
   1136 
   1137     return (c_tls->tr.state.send_called &&
   1138             (mhd_SOCKET_ERR_AGAIN == c_tls->tr.state.send_res)) ?
   1139            mhd_TLS_PROCED_SEND_MORE_NEEDED : mhd_TLS_PROCED_SEND_INTERRUPTED;
   1140 
   1141   case MBEDTLS_ERR_SSL_RECEIVED_EARLY_DATA:
   1142 #ifdef MBEDTLS_SSL_EARLY_DATA
   1143     /* Could be replaced with early data support is implemented */
   1144 #endif /* MBEDTLS_SSL_EARLY_DATA */
   1145     mhd_assert (0 &&
   1146                 "MBEDTLS_ERR_SSL_RECEIVED_EARLY_DATA must not be returned");
   1147     break;
   1148 
   1149   default:
   1150     break; /* Handle other values below */
   1151   }
   1152 
   1153   /* All other result codes must be interpreted as a hard error */
   1154 #ifndef NDEBUG
   1155   c_tls->dbg.is_failed = true;
   1156 #endif /* ! NDEBUG */
   1157 
   1158   return mhd_TLS_PROCED_FAILED;
   1159 }
   1160 
   1161 
   1162 MHD_INTERNAL MHD_FN_MUST_CHECK_RESULT_ MHD_FN_PAR_NONNULL_ALL_
   1163 enum mhd_TlsProcedureResult
   1164 mhd_tls_mbed_conn_shutdown (struct mhd_TlsMbedConnData *c_tls)
   1165 {
   1166   int res;
   1167 
   1168   mhd_assert (c_tls->dbg.is_inited);
   1169   mhd_assert (c_tls->dbg.is_tls_handshake_completed);
   1170   mhd_assert (! c_tls->dbg.is_failed);
   1171 
   1172   mhd_tls_mbed_sckt_comm_prep (c_tls);
   1173 
   1174   res = mbedtls_ssl_close_notify (&(c_tls->sess));
   1175 
   1176   switch (res)
   1177   {
   1178   case 0:
   1179     c_tls->shut_tls_wr_sent = true;
   1180     c_tls->shut_tls_wr_received = true;
   1181     return mhd_TLS_PROCED_SUCCESS; /* Success exit point */
   1182 
   1183   case MBEDTLS_ERR_SSL_WANT_READ:
   1184     mhd_assert (! mhd_SOCKET_ERR_IS_HARD (c_tls->tr.state.recv_res));
   1185     mhd_assert (! mhd_SOCKET_ERR_IS_HARD (c_tls->tr.state.send_res));
   1186 
   1187     if (! c_tls->tr.state.recv_called)
   1188       return mhd_TLS_PROCED_RECV_INTERRUPTED; /* Do not clear 'recv-ready' flag */
   1189 
   1190     if (mhd_SOCKET_ERR_AGAIN == c_tls->tr.state.recv_res)
   1191       return mhd_TLS_PROCED_RECV_MORE_NEEDED; /* Clear 'recv-ready' flag */
   1192 
   1193     return mhd_TLS_PROCED_RECV_INTERRUPTED; /* Do not clear 'recv-ready' flag */
   1194 
   1195   case MBEDTLS_ERR_SSL_WANT_WRITE:
   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.send_called)
   1200       return mhd_TLS_PROCED_SEND_INTERRUPTED; /* Do not clear 'send-ready' flag */
   1201 
   1202     if (mhd_SOCKET_ERR_AGAIN == c_tls->tr.state.send_res)
   1203       return mhd_TLS_PROCED_SEND_MORE_NEEDED; /* Clear 'send-ready' flag */
   1204 
   1205     return mhd_TLS_PROCED_SEND_INTERRUPTED; /* Do not clear 'send-ready' flag */
   1206 
   1207   default:
   1208     break; /* Handle other values below */
   1209   }
   1210 
   1211   /* All other result codes must be interpreted as a hard error */
   1212 #ifndef NDEBUG
   1213   c_tls->dbg.is_failed = true;
   1214 #endif /* ! NDEBUG */
   1215 
   1216   return mhd_TLS_PROCED_FAILED;
   1217 }
   1218 
   1219 
   1220 /* ** Data receiving and sending ** */
   1221 
   1222 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_
   1223 MHD_FN_PAR_OUT_SIZE_ (3,2)
   1224 MHD_FN_PAR_OUT_ (4) enum mhd_SocketError
   1225 mhd_tls_mbed_conn_recv (struct mhd_TlsMbedConnData *c_tls,
   1226                         size_t buf_size,
   1227                         char buf[MHD_FN_PAR_DYN_ARR_SIZE_ (buf_size)],
   1228                         size_t *restrict received)
   1229 {
   1230   int res;
   1231 
   1232   mhd_assert (0 != buf_size);
   1233 
   1234   mhd_assert (c_tls->dbg.is_inited);
   1235   mhd_assert (c_tls->dbg.is_tls_handshake_completed);
   1236   mhd_assert (! c_tls->shut_tls_wr_sent);
   1237   mhd_assert (! c_tls->dbg.is_failed);
   1238 
   1239   if (1)
   1240   {
   1241     const int buf_size_i = (int) buf_size;
   1242     if ((0 > buf_size_i) ||
   1243         (buf_size != (size_t) buf_size_i))
   1244     {
   1245       /* Called function return value limitation */
   1246       buf_size = (size_t) (((unsigned int) ~((unsigned int) 0)) >> 1u);
   1247     }
   1248   }
   1249 
   1250   c_tls->recv_data_in_buff = false;
   1251   mhd_tls_mbed_sckt_comm_prep (c_tls);
   1252 
   1253   res = mbedtls_ssl_read (&(c_tls->sess),
   1254                           (unsigned char *) buf,
   1255                           buf_size);
   1256 
   1257   if (0 <= res)
   1258   {
   1259     mhd_ASSUME (buf_size >= (size_t) res);
   1260     *received = (size_t) res;
   1261 
   1262     return mhd_SOCKET_ERR_NO_ERROR; /* Success exit point */
   1263   }
   1264 
   1265   switch (res)
   1266   {
   1267   case MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY:
   1268     c_tls->shut_tls_wr_received = true;
   1269     *received = 0u;
   1270 
   1271     return mhd_SOCKET_ERR_NO_ERROR; /* Success exit point */
   1272 
   1273   case MBEDTLS_ERR_SSL_WANT_READ:
   1274     mhd_assert (! mhd_SOCKET_ERR_IS_HARD (c_tls->tr.state.recv_res));
   1275     mhd_assert (! mhd_SOCKET_ERR_IS_HARD (c_tls->tr.state.send_res));
   1276 
   1277     if (! c_tls->tr.state.recv_called)
   1278       return mhd_SOCKET_ERR_INTR; /* Do not clear 'recv-ready' flag */
   1279 
   1280     if (mhd_SOCKET_ERR_NO_ERROR == c_tls->tr.state.recv_res)
   1281     {
   1282       /* recv() succeed for the first time and then called again */
   1283       return c_tls->tr.sk->props.is_nonblck ?
   1284              mhd_SOCKET_ERR_INTR : mhd_SOCKET_ERR_AGAIN;
   1285     }
   1286 
   1287     return c_tls->tr.state.recv_res;
   1288 
   1289   case MBEDTLS_ERR_SSL_WANT_WRITE:
   1290     mhd_assert (0 &&
   1291                 "The handshake must be fully completed earlier");
   1292     break;
   1293 
   1294   case MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS:
   1295     mhd_assert (0 && "MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS must not be returned");
   1296     break;
   1297 
   1298   case MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS:
   1299     /* MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS means that recv() should be called
   1300        again later. Pretend that data is already pending to not block on
   1301        waiting for the new incoming data. */
   1302     c_tls->recv_data_in_buff = true;
   1303     return mhd_SOCKET_ERR_INTR; /* Do not clear 'recv-ready' flag */
   1304 
   1305   case MBEDTLS_ERR_SSL_CLIENT_RECONNECT:
   1306     mhd_assert (0 &&
   1307                 "MBEDTLS_ERR_SSL_CLIENT_RECONNECT must not be "
   1308                 "returned for non-DTLS");
   1309     break;
   1310 
   1311   case MBEDTLS_ERR_SSL_RECEIVED_NEW_SESSION_TICKET:
   1312     mhd_assert (0 &&
   1313                 "MBEDTLS_ERR_SSL_RECEIVED_NEW_SESSION_TICKET must not be "
   1314                 "returned on the server side");
   1315     break;
   1316 
   1317   case MBEDTLS_ERR_SSL_RECEIVED_EARLY_DATA:
   1318 #ifdef MBEDTLS_SSL_EARLY_DATA
   1319     /* Could be replaced with early data support is implemented */
   1320 #endif /* MBEDTLS_SSL_EARLY_DATA */
   1321     mhd_assert (0 &&
   1322                 "MBEDTLS_ERR_SSL_RECEIVED_EARLY_DATA must not be returned");
   1323     break;
   1324 
   1325   default:
   1326     break; /* Handle other values below */
   1327   }
   1328 
   1329   /* Treat all other kinds of errors as hard errors */
   1330 #ifndef NDEBUG
   1331   c_tls->dbg.is_failed = true;
   1332 #endif /* ! NDEBUG */
   1333   return mhd_SOCKET_ERR_TLS;
   1334 }
   1335 
   1336 
   1337 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ bool
   1338 mhd_tls_mbed_conn_has_data_in (struct mhd_TlsMbedConnData *restrict c_tls)
   1339 {
   1340   return c_tls->recv_data_in_buff ||
   1341          (0 != mbedtls_ssl_check_pending (&(c_tls->sess)));
   1342 }
   1343 
   1344 
   1345 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_
   1346 MHD_FN_PAR_IN_SIZE_ (3,2)
   1347 MHD_FN_PAR_OUT_ (5) enum mhd_SocketError
   1348 mhd_tls_mbed_conn_send (struct mhd_TlsMbedConnData *c_tls,
   1349                         size_t buf_size,
   1350                         const char buf[MHD_FN_PAR_DYN_ARR_SIZE_ (buf_size)],
   1351                         bool push_data,
   1352                         size_t *restrict sent)
   1353 {
   1354   int res;
   1355 
   1356   mhd_assert (0 != buf_size);
   1357 
   1358   mhd_assert (c_tls->dbg.is_inited);
   1359   mhd_assert (c_tls->dbg.is_tls_handshake_completed);
   1360   mhd_assert (! c_tls->shut_tls_wr_sent);
   1361   mhd_assert (! c_tls->dbg.is_failed);
   1362 
   1363   if (1)
   1364   {
   1365     const int buf_size_i = (int) buf_size;
   1366     if ((0 > buf_size_i) ||
   1367         (buf_size != (size_t) buf_size_i))
   1368     {
   1369       /* Called function return value limitation */
   1370       buf_size = (size_t) (((unsigned int) ~((unsigned int) 0)) >> 1u);
   1371       push_data = false;
   1372     }
   1373   }
   1374 
   1375   mhd_tls_mbed_sckt_comm_prep_send (c_tls,
   1376                                     buf_size,
   1377                                     push_data);
   1378 
   1379   res = mbedtls_ssl_write (&(c_tls->sess),
   1380                            (const unsigned char *) buf,
   1381                            buf_size);
   1382 
   1383   if (0 < res)
   1384   {
   1385     mhd_ASSUME (buf_size >= (size_t) res);
   1386     *sent = (size_t) res;
   1387 
   1388     return mhd_SOCKET_ERR_NO_ERROR; /* Success exit point */
   1389   }
   1390 
   1391   switch (res)
   1392   {
   1393   case 0:
   1394     mhd_assert (0 &&
   1395                 "Zero must not be returned when sending non-zero size");
   1396     break;
   1397 
   1398   case MBEDTLS_ERR_SSL_WANT_WRITE:
   1399     mhd_assert (! mhd_SOCKET_ERR_IS_HARD (c_tls->tr.state.send_res));
   1400     mhd_assert (! mhd_SOCKET_ERR_IS_HARD (c_tls->tr.state.recv_res));
   1401 
   1402     if (! c_tls->tr.state.send_called)
   1403       return mhd_SOCKET_ERR_INTR; /* Do not clear 'recv-ready' flag */
   1404 
   1405     if (mhd_SOCKET_ERR_NO_ERROR == c_tls->tr.state.send_res)
   1406     {
   1407       /* send() succeed for the first time and then called again */
   1408       return c_tls->tr.sk->props.is_nonblck ?
   1409              mhd_SOCKET_ERR_INTR : mhd_SOCKET_ERR_AGAIN;
   1410     }
   1411 
   1412     return c_tls->tr.state.send_res;
   1413 
   1414   case MBEDTLS_ERR_SSL_WANT_READ:
   1415     mhd_assert (0 &&
   1416                 "The handshake must be fully completed earlier");
   1417     break;
   1418 
   1419   case MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS:
   1420     mhd_assert (0 && "MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS must not be returned");
   1421     break;
   1422 
   1423   case MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS:
   1424     /* MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS means that send() should be called
   1425        again later. Wait for 'send-ready' which should be already set or
   1426        will be set later, when OS pushed the data to the network. */
   1427     return mhd_SOCKET_ERR_INTR; /* Do not clear 'recv-ready' flag */
   1428 
   1429   case MBEDTLS_ERR_SSL_CLIENT_RECONNECT:
   1430     mhd_assert (0 &&
   1431                 "MBEDTLS_ERR_SSL_CLIENT_RECONNECT must not be "
   1432                 "returned for non-DTLS");
   1433     break;
   1434 
   1435   case MBEDTLS_ERR_SSL_RECEIVED_NEW_SESSION_TICKET:
   1436     mhd_assert (0 &&
   1437                 "MBEDTLS_ERR_SSL_RECEIVED_NEW_SESSION_TICKET must not be "
   1438                 "returned on the server side");
   1439     break;
   1440 
   1441   case MBEDTLS_ERR_SSL_RECEIVED_EARLY_DATA:
   1442 #ifdef MBEDTLS_SSL_EARLY_DATA
   1443     /* Could be replaced with early data support is implemented */
   1444 #endif /* MBEDTLS_SSL_EARLY_DATA */
   1445     mhd_assert (0 &&
   1446                 "MBEDTLS_ERR_SSL_RECEIVED_EARLY_DATA must not be returned");
   1447     break;
   1448 
   1449   default:
   1450     break; /* Handle other values below */
   1451   }
   1452 
   1453   /* Treat all other kinds of errors as hard errors */
   1454 #ifndef NDEBUG
   1455   c_tls->dbg.is_failed = true;
   1456 #endif /* ! NDEBUG */
   1457   return mhd_SOCKET_ERR_TLS;
   1458 }
   1459 
   1460 
   1461 /* ** TLS connection information ** */
   1462 
   1463 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_
   1464 MHD_FN_PAR_OUT_ (2) void
   1465 mhd_tls_mbed_conn_get_tls_sess (
   1466   struct mhd_TlsMbedConnData *restrict c_tls,
   1467   union MHD_ConnInfoDynamicTlsSess *restrict tls_sess_out)
   1468 {
   1469   tls_sess_out->v_mbedtls_session = &(c_tls->sess);
   1470 }
   1471 
   1472 
   1473 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_
   1474 MHD_FN_PAR_OUT_ (2) bool
   1475 mhd_tls_mbed_conn_get_tls_ver (struct mhd_TlsMbedConnData *restrict c_tls,
   1476                                struct mhd_StctTlsVersion *restrict tls_ver_out)
   1477 {
   1478   mhd_assert (c_tls->dbg.is_tls_handshake_completed);
   1479 
   1480 #ifndef MBEDTLS_VERSION_NUMBER
   1481   if (1)
   1482     return false; /* Need MbedTLS version number to implement */
   1483 #else  /* MBEDTLS_VERSION_NUMBER */
   1484   if (1)
   1485   {
   1486     uint_fast16_t tls_ver_num;
   1487 #if ((MBEDTLS_VERSION_NUMBER + 0) >= 0x03020000)
   1488     mbedtls_ssl_protocol_version mbedtls_tls_ver;
   1489 
   1490     mbedtls_tls_ver = mbedtls_ssl_get_version_number (&(c_tls->sess));
   1491 
   1492     tls_ver_num = (uint_fast16_t) mbedtls_tls_ver;
   1493 #else  /* MBEDTLS_VERSION_NUMBER < 0x03020000 */
   1494     tls_ver_num = (uint_fast16_t) c_tls->sess.MBEDTLS_PRIVATE (major_ver);
   1495     tls_ver_num <<= 8u;
   1496     tls_ver_num |= (uint_fast16_t) c_tls->sess.MBEDTLS_PRIVATE (minor_ver);
   1497 #endif /* MBEDTLS_VERSION_NUMBER < 0x03020000 */
   1498     /* Avoid MbedTLS helper macros and enum values in switch() as they are
   1499        unstable in MbedTLS. */
   1500     switch (tls_ver_num)
   1501     {
   1502     case 0u:
   1503       return false;
   1504 
   1505     case 0x0301u: /* Not really supported by MbedTLS >=3.0 */
   1506       tls_ver_out->tls_ver = MHD_TLS_VERSION_1_0;
   1507       break;
   1508 
   1509     case 0x0302u: /* Not really supported by MbedTLS >=3.0 */
   1510       tls_ver_out->tls_ver = MHD_TLS_VERSION_1_1;
   1511       break;
   1512 
   1513     case 0x0303u:
   1514       tls_ver_out->tls_ver = MHD_TLS_VERSION_1_2;
   1515       break;
   1516 
   1517     case 0x0304u:
   1518       tls_ver_out->tls_ver = MHD_TLS_VERSION_1_3;
   1519       break;
   1520 
   1521     default:
   1522       tls_ver_out->tls_ver = MHD_TLS_VERSION_UNKNOWN;
   1523       break;
   1524     }
   1525   }
   1526 #endif /* MBEDTLS_VERSION_NUMBER */
   1527 
   1528   return true;
   1529 }
   1530 
   1531 
   1532 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ enum mhd_TlsAlpnProt
   1533 mhd_tls_mbed_conn_get_alpn_prot (struct mhd_TlsMbedConnData *restrict c_tls)
   1534 {
   1535 #ifdef MBEDTLS_SSL_ALPN
   1536   const char *alpn_str;
   1537 
   1538   alpn_str = mbedtls_ssl_get_alpn_protocol (&(c_tls->sess));
   1539   if (NULL == alpn_str)
   1540     return mhd_TLS_ALPN_PROT_NOT_SELECTED;
   1541 
   1542   return mhd_tls_alpn_decode_n (strlen (alpn_str),
   1543                                 (const unsigned char *) alpn_str);
   1544 #else  /* ! MBEDTLS_SSL_ALPN */
   1545   return mhd_TLS_ALPN_PROT_NOT_SELECTED;
   1546 #endif /* ! MBEDTLS_SSL_ALPN */
   1547 }