commit ed7ff26f38bf305e450f0b1dc7e9f72dc9bf174c
parent 2dbd077a69236f77bf4cc0067dea469cefbd5797
Author: Evgeny Grin (Karlson2k) <k2k@drgrin.dev>
Date: Thu, 11 Dec 2025 17:09:17 +0100
Added MbedTLS backend
Diffstat:
19 files changed, 2567 insertions(+), 4 deletions(-)
diff --git a/src/include/microhttpd2.h b/src/include/microhttpd2.h
@@ -3651,6 +3651,11 @@ enum MHD_FIXED_ENUM_APP_SET_ MHD_TlsBackend
* Use OpenSSL as TLS backend.
*/
MHD_TLS_BACKEND_OPENSSL = 3
+ ,
+ /**
+ * Use MbedTLS as TLS backend.
+ */
+ MHD_TLS_BACKEND_MBEDTLS = 4
};
/**
@@ -9058,6 +9063,10 @@ struct MHD_LibInfoTLSType
* The OpenSSL backend is supported/available/enabled.
*/
enum MHD_Bool backend_openssl;
+ /**
+ * The MbedTLS backend is supported/available/enabled.
+ */
+ enum MHD_Bool backend_mbedtls;
};
/**
@@ -10102,6 +10111,16 @@ union MHD_ConnInfoDynamicTlsSess
#else
void /* SSL */ *v_openssl_session;
#endif
+
+ /* Include <mbedtls/ssl.h> before this header to get a better type safety */
+ /**
+ * MbedTLS session handle, of type "mbedtls_ssl_context*".
+ */
+#if defined(MBEDTLS_SSL_H)
+ mbedtls_ssl_context *v_mbedtls_session;
+#else
+ void /* mbedtls_ssl_context */ *v_mbedtls_session;
+#endif
};
/**
diff --git a/src/include/microhttpd2_main.h.in b/src/include/microhttpd2_main.h.in
@@ -4241,6 +4241,10 @@ struct MHD_LibInfoTLSType
* The OpenSSL backend is supported/available/enabled.
*/
enum MHD_Bool backend_openssl;
+ /**
+ * The MbedTLS backend is supported/available/enabled.
+ */
+ enum MHD_Bool backend_mbedtls;
};
/**
@@ -5285,6 +5289,16 @@ union MHD_ConnInfoDynamicTlsSess
#else
void /* SSL */ *v_openssl_session;
#endif
+
+ /* Include <mbedtls/ssl.h> before this header to get a better type safety */
+ /**
+ * MbedTLS session handle, of type "mbedtls_ssl_context*".
+ */
+#if defined(MBEDTLS_SSL_H)
+ mbedtls_ssl_context *v_mbedtls_session;
+#else
+ void /* mbedtls_ssl_context */ *v_mbedtls_session;
+#endif
};
/**
diff --git a/src/include/microhttpd2_preamble.h.in b/src/include/microhttpd2_preamble.h.in
@@ -3651,6 +3651,11 @@ enum MHD_FIXED_ENUM_APP_SET_ MHD_TlsBackend
* Use OpenSSL as TLS backend.
*/
MHD_TLS_BACKEND_OPENSSL = 3
+ ,
+ /**
+ * Use MbedTLS as TLS backend.
+ */
+ MHD_TLS_BACKEND_MBEDTLS = 4
};
/**
diff --git a/src/mhd2/Makefile.am b/src/mhd2/Makefile.am
@@ -268,6 +268,10 @@ tls_open_OPTSOURCES = \
tls_open_tls_lib.h tls_open_daemon_data.h tls_open_conn_data.h \
tls_open_funcs.c tls_open_funcs.h
+tls_mbed_OPTSOURCES = \
+ tls_mbed_tls_lib.h tls_mbed_daemon_data.h tls_mbed_conn_data.h \
+ tls_mbed_funcs.c tls_mbed_funcs.h
+
if MHD_SUPPORT_HTTP2
libmicrohttpd2_la_SOURCES += $(httptwo_OPTSOURCES)
endif
@@ -310,6 +314,10 @@ endif
if MHD_SUPPORT_OPENSSL
libmicrohttpd2_la_SOURCES += $(tls_open_OPTSOURCES)
endif
+
+if MHD_SUPPORT_MBEDTLS
+ libmicrohttpd2_la_SOURCES += $(tls_mbed_OPTSOURCES)
+endif
endif
libmicrohttpd2_la_CPPFLAGS = \
diff --git a/src/mhd2/daemon_get_info.c b/src/mhd2/daemon_get_info.c
@@ -170,6 +170,11 @@ MHD_daemon_get_info_fixed_sz (
output_buf->v_tls_backend = MHD_TLS_BACKEND_OPENSSL;
break;
# endif
+# ifdef MHD_SUPPORT_MBEDTLS
+ case mhd_TLS_MULTI_ROUTE_MBED:
+ output_buf->v_tls_backend = MHD_TLS_BACKEND_MBEDTLS;
+ break;
+# endif
case mhd_TLS_MULTI_ROUTE_NONE:
default:
mhd_UNREACHABLE ();
@@ -179,6 +184,8 @@ MHD_daemon_get_info_fixed_sz (
output_buf->v_tls_backend = MHD_TLS_BACKEND_GNUTLS;
#elif defined(MHD_SUPPORT_OPENSSL)
output_buf->v_tls_backend = MHD_TLS_BACKEND_OPENSSL;
+#elif defined(MHD_SUPPORT_MBEDTLS)
+ output_buf->v_tls_backend = MHD_TLS_BACKEND_MBEDTLS;
#else
#error No TLS backends enabled, while TLS support is enabled
#endif
diff --git a/src/mhd2/lib_get_info.c b/src/mhd2/lib_get_info.c
@@ -76,6 +76,9 @@
# if defined(MHD_SUPPORT_OPENSSL)
# include "tls_open_funcs.h"
# endif
+# if defined(MHD_SUPPORT_MBEDTLS)
+# include "tls_mbed_funcs.h"
+# endif
#endif
#ifdef MHD_SUPPORT_MD5
@@ -528,15 +531,18 @@ MHD_lib_get_info_dynamic_sz (
output_buf->v_tls_backends.tls_supported = MHD_NO;
output_buf->v_tls_backends.backend_gnutls = MHD_NO;
output_buf->v_tls_backends.backend_openssl = MHD_NO;
+ output_buf->v_tls_backends.backend_mbedtls = MHD_NO;
#else
bool gnutls_avail;
bool openssl_avail;
+ bool mdedtls_avail;
if (! mhd_lib_init_global_if_needed ())
return MHD_SC_INFO_GET_TYPE_UNOBTAINABLE;
gnutls_avail = mhd_tls_gnu_is_inited_fine ();
openssl_avail = mhd_tls_open_is_inited_fine ();
+ mdedtls_avail = mhd_tls_mbed_is_inited_fine ();
output_buf->v_tls_backends.tls_supported =
(gnutls_avail || openssl_avail) ? MHD_YES : MHD_NO;
@@ -544,6 +550,8 @@ MHD_lib_get_info_dynamic_sz (
gnutls_avail ? MHD_YES : MHD_NO;
output_buf->v_tls_backends.backend_openssl =
openssl_avail ? MHD_YES : MHD_NO;
+ output_buf->v_tls_backends.backend_mbedtls =
+ mdedtls_avail ? MHD_YES : MHD_NO;
mhd_lib_deinit_global_if_needed ();
#endif
diff --git a/src/mhd2/mhd_tls_choice.h b/src/mhd2/mhd_tls_choice.h
@@ -103,11 +103,30 @@
*/
#define mhd_TLS_OPEN_IS_SUPPORTED() (! ! mhd_TLS_OPEN_ENABLED)
+/* * MbedTLS * */
+
+#ifdef MHD_SUPPORT_MBEDTLS
+/**
+ * Defined to one if MbedTLS is enabled at build time or to zero if not enabled
+ */
+# define mhd_TLS_MBED_ENABLED (1)
+#else
+/**
+ * Defined to one if MbedTLS is enabled at build time or to zero if not enabled
+ */
+# define mhd_TLS_MBED_ENABLED (0)
+#endif
+
+/**
+ * Return non-zero if OpenSSL is supported
+ */
+#define mhd_TLS_MBED_IS_SUPPORTED() (! ! mhd_TLS_MBED_ENABLED)
+
/**
* Defined to the number of enabled TLS backends
*/
#define mhd_TLS_NUM_BACKENDS \
- (mhd_TLS_GNU_ENABLED + mhd_TLS_OPEN_ENABLED)
+ (mhd_TLS_GNU_ENABLED + mhd_TLS_OPEN_ENABLED + mhd_TLS_MBED_ENABLED)
#if mhd_TLS_NUM_BACKENDS == 0
#error At least one TLS backend must be enabled if this header is included
@@ -186,6 +205,19 @@
* The TLS back-end identifier for macro names
*/
# define mhd_TLS_MACRO_NAME_ID OPEN
+#elif defined(MHD_SUPPORT_MBEDTLS)
+/**
+ * The TLS back-end identifier for function names
+ */
+# define mhd_TLS_FUNC_NAME_ID mbed
+/**
+ * The TLS back-end identifier for data names
+ */
+# define mhd_TLS_DATA_NAME_ID Mbed
+/**
+ * The TLS back-end identifier for macro names
+ */
+# define mhd_TLS_MACRO_NAME_ID MBED
#endif
@@ -205,6 +237,13 @@
# define mhd_tls_open_is_inited_fine() (! ! 0)
#endif
+#ifndef MHD_SUPPORT_MBEDTLS
+/**
+ * Check whether MbedTLS backend was successfully initialised globally
+ */
+# define mhd_tls_mbed_is_inited_fine() (! ! 0)
+#endif
+
/* ** Functions names and structures names macros ** */
diff --git a/src/mhd2/mhd_tls_common.c b/src/mhd2/mhd_tls_common.c
@@ -55,6 +55,9 @@
#if defined(MHD_SUPPORT_OPENSSL)
# include "tls_open_funcs.h"
#endif
+#if defined(MHD_SUPPORT_MBEDTLS)
+# include "tls_mbed_funcs.h"
+#endif
#include "daemon_options.h"
@@ -67,7 +70,8 @@ mhd_tls_is_backend_available (struct DaemonOptions *s)
mhd_assert (MHD_TLS_BACKEND_NONE != s->tls);
if (MHD_TLS_BACKEND_ANY == s->tls)
return (mhd_tls_gnu_is_inited_fine ()
- || mhd_tls_open_is_inited_fine ()) ?
+ || mhd_tls_open_is_inited_fine ()
+ || mhd_tls_mbed_is_inited_fine ()) ?
mhd_TLS_BACKEND_AVAIL_OK :
mhd_TLS_BACKEND_AVAIL_NOT_AVAILABLE;
#ifdef MHD_SUPPORT_GNUTLS
@@ -82,5 +86,11 @@ mhd_tls_is_backend_available (struct DaemonOptions *s)
mhd_TLS_BACKEND_AVAIL_OK :
mhd_TLS_BACKEND_AVAIL_NOT_AVAILABLE;
#endif
+#ifdef MHD_SUPPORT_MBEDTLS
+ if (MHD_TLS_BACKEND_MBEDTLS == s->tls)
+ return mhd_tls_mbed_is_inited_fine () ?
+ mhd_TLS_BACKEND_AVAIL_OK :
+ mhd_TLS_BACKEND_AVAIL_NOT_AVAILABLE;
+#endif
return mhd_TLS_BACKEND_AVAIL_NOT_SUPPORTED;
}
diff --git a/src/mhd2/mhd_tls_funcs.h b/src/mhd2/mhd_tls_funcs.h
@@ -61,6 +61,8 @@
# include "tls_gnu_funcs.h"
#elif defined(MHD_SUPPORT_OPENSSL)
# include "tls_open_funcs.h"
+#elif defined(MHD_SUPPORT_MBEDTLS)
+# include "tls_mbed_funcs.h"
#endif
/* ** Global initialisation / de-initialisation ** */
diff --git a/src/mhd2/tls_mbed_conn_data.h b/src/mhd2/tls_mbed_conn_data.h
@@ -0,0 +1,155 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later OR (GPL-2.0-or-later WITH eCos-exception-2.0) */
+/*
+ This file is part of GNU libmicrohttpd.
+ Copyright (C) 2025 Evgeny Grin (Karlson2k)
+
+ GNU libmicrohttpd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ GNU libmicrohttpd is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ Alternatively, you can redistribute GNU libmicrohttpd and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of
+ the License, or (at your option) any later version, together
+ with the eCos exception, as follows:
+
+ As a special exception, if other files instantiate templates or
+ use macros or inline functions from this file, or you compile this
+ file and link it with other works to produce a work based on this
+ file, this file does not by itself cause the resulting work to be
+ covered by the GNU General Public License. However the source code
+ for this file must still be made available in accordance with
+ section (3) of the GNU General Public License v2.
+
+ This exception does not invalidate any other reasons why a work
+ based on this file might be covered by the GNU General Public
+ License.
+
+ You should have received copies of the GNU Lesser General Public
+ License and the GNU General Public License along with this library;
+ if not, see <https://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @file src/mhd2/tls_mbed_conn_data.h
+ * @brief The definition of MbedTLS connection-specific data structures
+ * @author Karlson2k (Evgeny Grin)
+ */
+
+#ifndef MHD_TLS_MBED_CONN_DATA_H
+#define MHD_TLS_MBED_CONN_DATA_H 1
+
+#include "mhd_sys_options.h"
+
+#ifndef MHD_SUPPORT_MBEDTLS
+#error This header can be used only if MbedTLS is enabled
+#endif
+
+#include "sys_bool_type.h"
+#include "sys_sizet_type.h"
+
+#include "tls_mbed_tls_lib.h"
+
+#include "mhd_socket_error.h"
+
+struct mhd_ConnSocket; /* Forward declaration */
+
+#ifndef NDEBUG
+struct mhd_TlsMbedConnDebug
+{
+ bool is_inited;
+ bool is_tls_handshake_completed;
+ bool is_failed;
+};
+#endif /* ! NDEBUG */
+
+/**
+ * The state for the current "custom transport" operation
+ */
+struct mhd_TlsMbedConnCstmTrtState
+{
+ /**
+ * 'true' if recv() callback has been called
+ */
+ bool recv_called;
+ /**
+ * The result of last call of recv().
+ * #mhd_SOCKET_ERR_NO_ERROR if recv() has not been called.
+ */
+ enum mhd_SocketError recv_res;
+ /**
+ * 'true' if send() callback has been called
+ */
+ bool send_called;
+ /**
+ * The result of last call of send().
+ * #mhd_SOCKET_ERR_NO_ERROR if send() has not been called.
+ */
+ enum mhd_SocketError send_res;
+ /**
+ * The size of the send() data before TLS encryption.
+ * Zero if no application data is being sent.
+ */
+ size_t send_unenc_size;
+};
+
+/**
+ * Data for connection's "custom transport"
+ */
+struct mhd_TlsMbedConnCstmTrtData
+{
+ /**
+ * The pointer to the socket information data
+ */
+ struct mhd_ConnSocket *sk;
+ /**
+ * The state for the current "custom transport" operation
+ */
+ struct mhd_TlsMbedConnCstmTrtState state;
+};
+
+/**
+ * The structure with connection-specific MbedTLS data
+ *
+ * @note Unlike other TLS backends this struct contains MbedTLS data itself,
+ * not just pointers.
+ */
+struct mhd_TlsMbedConnData
+{
+ /**
+ * MbedTLS session data
+ */
+ mbedtls_ssl_context sess;
+
+ /**
+ * Data for connection's "custom transport"
+ */
+ struct mhd_TlsMbedConnCstmTrtData tr;
+ /**
+ * 'true' is already received data in waiting in TLS buffers
+ */
+ bool recv_data_in_buff;
+ /**
+ * 'true' if sent TLS shutdown "alert"
+ */
+ bool shut_tls_wr_sent;
+
+ /**
+ * 'true' if received EOF (the peer initiated TLS shut down)
+ */
+ bool shut_tls_wr_received;
+#ifndef NDEBUG
+ /**
+ * Debugging data
+ */
+ struct mhd_TlsMbedConnDebug dbg;
+#endif /* ! NDEBUG */
+};
+
+#endif /* ! MHD_TLS_MBED_CONN_DATA_H */
diff --git a/src/mhd2/tls_mbed_daemon_data.h b/src/mhd2/tls_mbed_daemon_data.h
@@ -0,0 +1,87 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later OR (GPL-2.0-or-later WITH eCos-exception-2.0) */
+/*
+ This file is part of GNU libmicrohttpd.
+ Copyright (C) 2025 Evgeny Grin (Karlson2k)
+
+ GNU libmicrohttpd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ GNU libmicrohttpd is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ Alternatively, you can redistribute GNU libmicrohttpd and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of
+ the License, or (at your option) any later version, together
+ with the eCos exception, as follows:
+
+ As a special exception, if other files instantiate templates or
+ use macros or inline functions from this file, or you compile this
+ file and link it with other works to produce a work based on this
+ file, this file does not by itself cause the resulting work to be
+ covered by the GNU General Public License. However the source code
+ for this file must still be made available in accordance with
+ section (3) of the GNU General Public License v2.
+
+ This exception does not invalidate any other reasons why a work
+ based on this file might be covered by the GNU General Public
+ License.
+
+ You should have received copies of the GNU Lesser General Public
+ License and the GNU General Public License along with this library;
+ if not, see <https://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @file src/mhd2/tls_mbed_daemon_data.h
+ * @brief The definition of MbedTLS daemon-specific data structures
+ * @author Karlson2k (Evgeny Grin)
+ */
+
+#ifndef MHD_TLS_MBED_DAEMON_DATA_H
+#define MHD_TLS_MBED_DAEMON_DATA_H 1
+
+#include "mhd_sys_options.h"
+
+#ifndef MHD_SUPPORT_MBEDTLS
+#error This header can be used only if MbedTLS is enabled
+#endif
+
+#include "tls_mbed_tls_lib.h"
+
+/**
+ * The structure with daemon-specific MbedTLS data.
+ *
+ * @note Unlike other TLS backends this struct contains MbedTLS data itself,
+ * not just pointers.
+ */
+struct mhd_TlsMbedDaemonData
+{
+ /**
+ * The daemon TLS configuration.
+ */
+ mbedtls_ssl_config tls_conf;
+
+ /**
+ * The certificates chain
+ */
+ mbedtls_x509_crt cert_chain;
+
+ /**
+ * The private key
+ */
+ mbedtls_pk_context prv_key;
+
+#ifdef MBEDTLS_SSL_ALPN
+ /**
+ * Enabled protocols for ALPN
+ */
+ const char *alpn_prots[4];
+#endif /* MBEDTLS_SSL_ALPN */
+};
+
+#endif /* ! MHD_TLS_MBED_DAEMON_DATA_H */
diff --git a/src/mhd2/tls_mbed_funcs.c b/src/mhd2/tls_mbed_funcs.c
@@ -0,0 +1,1541 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later OR (GPL-2.0-or-later WITH eCos-exception-2.0) */
+/*
+ This file is part of GNU libmicrohttpd.
+ Copyright (C) 2025 Evgeny Grin (Karlson2k)
+
+ GNU libmicrohttpd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ GNU libmicrohttpd is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ Alternatively, you can redistribute GNU libmicrohttpd and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of
+ the License, or (at your option) any later version, together
+ with the eCos exception, as follows:
+
+ As a special exception, if other files instantiate templates or
+ use macros or inline functions from this file, or you compile this
+ file and link it with other works to produce a work based on this
+ file, this file does not by itself cause the resulting work to be
+ covered by the GNU General Public License. However the source code
+ for this file must still be made available in accordance with
+ section (3) of the GNU General Public License v2.
+
+ This exception does not invalidate any other reasons why a work
+ based on this file might be covered by the GNU General Public
+ License.
+
+ You should have received copies of the GNU Lesser General Public
+ License and the GNU General Public License along with this library;
+ if not, see <https://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @file src/mhd2/tls_mbed_funcs.c
+ * @brief The implementation of MbedTLS wrapper functions
+ * @author Karlson2k (Evgeny Grin)
+ */
+
+/* A few macros can be defined at MHD build-time to adjust code interfacing
+ with MbedTLS library:
+ - MHD_TLS_MBED_USE_PSA_FREE
+ - MHD_TLS_MBED_PREF_RNG_PSA
+ - MHD_TLS_MBED_PREF_RNG_HMAC
+ - MHD_TLS_MBED_PREF_RNG_CTR
+ - MHD_TLS_MBED_SKIP_PLATFORM_SETUP
+ - MHD_TLS_MBED_USE_PLATFORM_TEARDOWN
+ - MHD_TLS_MBED_SKIP_CERT_KEY_MATCH_CHECK
+ - MHD_TLS_MBED_DBG_PRINT_LEVEL
+ See macros use in this file and in tls_mbed_tls_lib.h.
+ Macros can be defined, for example, by CPPFLAGS before run of the configure.
+ */
+
+#include "mhd_sys_options.h"
+
+#include "sys_bool_type.h"
+#include "sys_base_types.h"
+
+#include "compat_calloc.h"
+#include "sys_malloc.h"
+#include <string.h>
+
+#ifdef mhd_USE_TLS_DEBUG_MESSAGES
+# include <stdio.h> /* For TLS debug printing */
+#endif
+
+#include "mhd_assert.h"
+#include "mhd_unreachable.h"
+#include "mhd_assume.h"
+
+#include "mhd_constexpr.h"
+#include "mhd_arr_num_elems.h"
+
+#include "mhd_conn_socket.h"
+
+#include "mhd_tls_internal.h"
+
+#include "tls_mbed_tls_lib.h"
+
+#include "mhd_public_api.h"
+
+#include "mhd_tls_ver_stct.h"
+
+#include "daemon_logger.h"
+
+#include "daemon_options.h"
+
+#include "sckt_recv.h"
+#include "sckt_send.h"
+
+#include "tls_mbed_daemon_data.h"
+#include "tls_mbed_conn_data.h"
+#include "tls_mbed_funcs.h"
+
+#if defined(mhd_USE_TLS_DEBUG_MESSAGES) && defined(MBEDTLS_DEBUG_C)
+# define mhd_TLS_MBED_HAS_DEBUG_PRINT 1
+
+/* MHD_TLS_MBED_DBG_PRINT_LEVEL can be defined to number in range 0..5,
+ where 5 is the most detailed log */
+#ifdef MHD_TLS_MBED_DBG_PRINT_LEVEL
+# define mhd_DBG_PRINT_LEVEL (MHD_TLS_MBED_DBG_PRINT_LEVEL + 0)
+#else
+# define mhd_DBG_PRINT_LEVEL (2)
+#endif
+
+static void
+mhd_tls_mbed_debug_print (void *ctx,
+ int level,
+ const char *filename,
+ int line_num,
+ const char *msg)
+{
+ (void) ctx; /* Unused */
+ /* The level should be pre-filtred by MbedTLS, but it is filtered again
+ here in case if something else changed it. */
+ if (mhd_DBG_PRINT_LEVEL < level)
+ return;
+ (void) fprintf (stderr, "## MbedTLS %02i [%s:%d]: %s\n",
+ level,
+ filename,
+ line_num,
+ msg);
+ (void) fflush (stderr);
+}
+
+
+#endif /* mhd_USE_TLS_DEBUG_MESSAGES && MBEDTLS_DEBUG_C */
+
+
+/* ** Global initialisation / de-initialisation ** */
+
+#ifdef MHD_TLS_MBED_PREF_RNG_HMAC
+static const mbedtls_md_info_t *
+mbed_get_md_for_drbg (void)
+{
+ mhd_constexpr mbedtls_md_type_t mds[] = {
+#ifdef mhd_TLS_MBED_HAS_SHA3_IDS
+ MBEDTLS_MD_SHA3_256
+ ,
+#endif /* mhd_TLS_MBED_HAS_SHA3_IDS */
+ MBEDTLS_MD_SHA256
+#ifdef mhd_TLS_MBED_HAS_SHA3_IDS
+ ,
+ MBEDTLS_MD_SHA3_512
+#endif /* mhd_TLS_MBED_HAS_SHA3_IDS */
+ ,
+ MBEDTLS_MD_SHA512
+#ifdef mhd_TLS_MBED_HAS_SHA3_IDS
+ ,
+ MBEDTLS_MD_SHA3_384
+#endif /* mhd_TLS_MBED_HAS_SHA3_IDS */
+ ,
+ MBEDTLS_MD_SHA384
+#ifdef mhd_TLS_MBED_HAS_SHA3_IDS
+ ,
+ MBEDTLS_MD_SHA3_224
+#endif /* mhd_TLS_MBED_HAS_SHA3_IDS */
+ ,
+ MBEDTLS_MD_SHA224
+ };
+ size_t i;
+
+ for (i = 0; i < mhd_ARR_NUM_ELEMS (mds); ++i)
+ {
+ const mbedtls_md_info_t *const ret =
+ mbedtls_md_info_from_type (mds[i]);
+ if (NULL != ret)
+ return ret;
+ }
+
+ return (const mbedtls_md_info_t *) NULL;
+}
+
+
+#endif /* MHD_TLS_MBED_PREF_RNG_HMAC */
+
+static bool mbedtls_lib_inited_now = false;
+/* Must be checked when MHD-internal random generator is used */
+static bool mbedtls_rng_inited_now = false;
+static bool mbedtls_lib_inited_once = false;
+
+#ifdef mhd_TLS_MBED_HAS_PLATFORM_SETUP
+static mbedtls_platform_context mhd_mbed_plat_ctx;
+#endif /* mhd_TLS_MBED_HAS_PLATFORM_SETUP */
+
+#if defined(mhd_TLS_MBED_USE_LIB_ENTROPY)
+static mbedtls_entropy_context mhd_mbed_entr_ctx;
+#endif /* mhd_TLS_MBED_USE_LIB_ENTROPY */
+
+#if defined(MHD_TLS_MBED_PREF_RNG_CTR)
+static mbedtls_ctr_drbg_context mhd_mbed_ctr_drbg_ctx;
+#elif defined(MHD_TLS_MBED_PREF_RNG_HMAC)
+static mbedtls_hmac_drbg_context mhd_mbed_hmac_drbg_ctx;
+#endif /* MHD_TLS_MBED_PREF_RNG_HMAC */
+
+static bool
+mbed_rng_init (void)
+{
+#ifdef mhd_TLS_MBED_RNG_PREF_NEEDS_ENTROPY
+ int (*entropy_cb)(void *ctx, unsigned char *out, size_t out_size);
+ void *entropy_cb_ctx;
+
+# ifdef mhd_TLS_MBED_USE_LIB_ENTROPY
+ mbedtls_entropy_init (&mhd_mbed_entr_ctx);
+ entropy_cb = &mbedtls_entropy_func;
+ entropy_cb_ctx = &mhd_mbed_entr_ctx;
+# else /* ! mhd_TLS_MBED_USE_LIB_ENTROPY */
+ /* Seeding with system's entropy sources could be implemented here */
+#error MbedTLS random generator needs entropy sources
+# endif /* ! mhd_TLS_MBED_USE_LIB_ENTROPY */
+#endif /* mhd_TLS_MBED_RNG_PREF_NEEDS_ENTROPY */
+
+ mhd_assert (! mbedtls_rng_inited_now);
+
+ if (1) /* For local scope only */
+ {
+#ifdef mhd_TLS_MBED_RNG_PREF_NEEDS_ENTROPY
+ static const char id_str[] = "libmicrohttpd2";
+ static uint_fast64_t init_cntr = 0u;
+ static void *uniq_ptr1 = &init_cntr; /* Any address should be unique in the same address space */
+ void *uniq_ptr2 = &uniq_ptr2; /* Any address should be unique in the same address space */
+ unsigned char pers[sizeof(id_str)
+ + sizeof(uniq_ptr1)
+ + sizeof(uniq_ptr2)
+ + sizeof(init_cntr)];
+
+ memcpy (pers,
+ id_str,
+ sizeof(id_str));
+ memcpy (pers + sizeof(id_str),
+ &uniq_ptr1,
+ sizeof(uniq_ptr1));
+ memcpy (pers + sizeof(id_str) + sizeof(uniq_ptr1),
+ &uniq_ptr2,
+ sizeof(uniq_ptr2));
+ memcpy (pers + sizeof(id_str) + sizeof(uniq_ptr1) + sizeof(uniq_ptr2),
+ &init_cntr,
+ sizeof(init_cntr));
+ ++init_cntr;
+#endif /* mhd_TLS_MBED_RNG_PREF_NEEDS_ENTROPY */
+
+#if defined(MHD_TLS_MBED_PREF_RNG_CTR)
+ mbedtls_ctr_drbg_init (&mhd_mbed_ctr_drbg_ctx);
+ mbedtls_rng_inited_now =
+ (0 == mbedtls_ctr_drbg_seed (&mhd_mbed_ctr_drbg_ctx,
+ entropy_cb,
+ entropy_cb_ctx,
+ pers,
+ sizeof(pers)));
+ if (! mbedtls_rng_inited_now)
+ mbedtls_ctr_drbg_free (&mhd_mbed_ctr_drbg_ctx);
+#elif defined(MHD_TLS_MBED_PREF_RNG_HMAC)
+ mbedtls_hmac_drbg_init (&mhd_mbed_hmac_drbg_ctx);
+ mbedtls_rng_inited_now =
+ (0 == mbedtls_hmac_drbg_seed (&mhd_mbed_hmac_drbg_ctx,
+ mbed_get_md_for_drbg (), /* NULL is handled by mbedtls_hmac_drbg_seed() */
+ entropy_cb,
+ entropy_cb_ctx,
+ pers,
+ sizeof(pers)));
+ if (! mbedtls_rng_inited_now)
+ mbedtls_hmac_drbg_free (&mhd_mbed_hmac_drbg_ctx);
+#elif defined(MHD_TLS_MBED_PREF_RNG_PSA)
+ mbedtls_rng_inited_now = true; /* No additional initialisation needed */
+#elif ! defined(mhd_TLS_MBED_INIT_TLS_REQ_RNG)
+ mbedtls_rng_inited_now = false;
+#else /* mhd_TLS_MBED_INIT_TLS_REQ_RNG */
+#error MbedTLS backend requires random generator
+ /* Support for external strong random generator could be added */
+ mbedtls_rng_inited_now = false;
+#endif
+ if (mbedtls_rng_inited_now)
+ return true; /* Success exit point */
+ }
+
+#ifdef mhd_TLS_MBED_USE_LIB_ENTROPY
+ mbedtls_entropy_free (&mhd_mbed_entr_ctx);
+#endif /* mhd_TLS_MBED_USE_LIB_ENTROPY */
+
+ return false; /* Failure exit point */
+}
+
+
+static void
+mbed_rng_deinit (void)
+{
+ if (! mbedtls_rng_inited_now)
+ return;
+
+#if defined(MHD_TLS_MBED_PREF_RNG_CTR)
+ mbedtls_ctr_drbg_free (&mhd_mbed_ctr_drbg_ctx);
+#elif defined(MHD_TLS_MBED_PREF_RNG_HMAC)
+ mbedtls_hmac_drbg_free (&mhd_mbed_hmac_drbg_ctx);
+#endif
+
+#ifdef mhd_TLS_MBED_USE_LIB_ENTROPY
+ mbedtls_entropy_free (&mhd_mbed_entr_ctx);
+#endif /* mhd_TLS_MBED_USE_LIB_ENTROPY */
+
+ mbedtls_rng_inited_now = false;
+}
+
+
+MHD_INTERNAL void
+mhd_tls_mbed_global_init (void)
+{
+#ifdef MBEDTLS_VERSION_C
+ if (1)
+ {
+ const unsigned int ver = mbedtls_version_get_number ();
+ if (MBEDTLS_VERSION_NUMBER > ver)
+ return; /* Run-time version is lower than build-time version */
+ if (((MBEDTLS_VERSION_NUMBER) >> 24u) != (ver >> 24u))
+ return; /* Run-time major version does not match build-time major version */
+ }
+#endif /* MBEDTLS_VERSION_C */
+
+#ifdef mhd_TLS_MBED_HAS_PLATFORM_SETUP
+# ifdef mhd_TLS_MBED_USE_PLATFORM_TEARDOWN
+ /* 'setup' platform repeatedly only only if 'teardown' is called */
+ if (mbedtls_lib_inited_once)
+ (void) 0; /* Do not repeat 'setup' */
+ else /* combined with tne next 'if()' */
+# endif /* mhd_TLS_MBED_USE_PLATFORM_TEARDOWN */
+ if (0 != mbedtls_platform_setup (&mhd_mbed_plat_ctx))
+ return; /* Error platform initialising */
+#endif /* mhd_TLS_MBED_HAS_PLATFORM_SETUP */
+
+#ifdef mhd_TLS_MBED_USE_PSA
+ /* It is safe to call psa_crypto_init() several times */
+ if (PSA_SUCCESS != psa_crypto_init ())
+ {
+#ifdef mhd_TLS_MBED_USE_PLATFORM_TEARDOWN
+ mbedtls_platform_teardown (&mhd_mbed_plat_ctx);
+#endif /* mhd_TLS_MBED_USE_PLATFORM_TEARDOWN */
+ return;
+ }
+#endif /* mhd_TLS_MBED_USE_PSA */
+ mbedtls_lib_inited_once = true;
+
+#if mhd_TLS_MBED_INIT_TLS_REQ_RNG
+ mbedtls_lib_inited_now = mbed_rng_init ();
+#else /* ! mhd_TLS_MBED_INIT_TLS_REQ_RNG */
+ (void) mbed_rng_init ();
+ mbedtls_lib_inited_now = true; /* MbedTLS could be used even without random generator */
+#endif /* ! mhd_TLS_MBED_INIT_TLS_REQ_RNG */
+
+ if (! mbedtls_lib_inited_now)
+ {
+#ifdef mhd_TLS_MBED_USE_PLATFORM_TEARDOWN
+ mbedtls_platform_teardown (&mhd_mbed_plat_ctx);
+#endif /* mhd_TLS_MBED_USE_PLATFORM_TEARDOWN */
+
+#ifdef mhd_TLS_MBED_USE_PSA_FREE
+ mbedtls_psa_crypto_free ();
+#endif /* mhd_TLS_MBED_USE_PLATFORM_TEARDOWN */
+ (void) 0;
+ }
+}
+
+
+MHD_INTERNAL void
+mhd_tls_mbed_global_deinit (void)
+{
+ if (! mbedtls_lib_inited_now)
+ return;
+
+ mbed_rng_deinit ();
+
+#ifdef mhd_TLS_MBED_USE_PSA_FREE
+ /* Not used by default as it will break all calls to PSA performed
+ directly by the application after closing all active MHD daemons */
+ mbedtls_psa_crypto_free ();
+#endif /* mhd_TLS_MBED_USE_PLATFORM_TEARDOWN */
+
+#ifdef mhd_TLS_MBED_USE_PLATFORM_TEARDOWN
+ /* Not used by default as it will break all calls to MbedTLS performed
+ directly by the application after closing all active MHD daemons */
+ mbedtls_platform_teardown (&mhd_mbed_plat_ctx);
+#endif /* mhd_TLS_MBED_USE_PLATFORM_TEARDOWN */
+
+ mbedtls_lib_inited_now = false;
+}
+
+
+MHD_INTERNAL MHD_FN_PURE_ bool
+mhd_tls_mbed_is_inited_fine (void)
+{
+ mhd_assert (! mbedtls_lib_inited_now || mbedtls_lib_inited_once);
+ return mbedtls_lib_inited_now;
+}
+
+
+/* ** Daemon initialisation / de-initialisation ** */
+
+/**
+ * Check application-provided daemon TLS settings
+ * @param d the daemon handle
+ * @param sk_edge_trigg the sockets polling uses edge-triggering
+ * @param s the application-provided settings
+ * @return #MHD_SC_OK on success,
+ * error code otherwise
+ */
+static MHD_FN_PAR_NONNULL_ALL_ MHD_FN_MUST_CHECK_RESULT_ enum MHD_StatusCode
+check_app_tls_settings (struct MHD_Daemon *restrict d,
+ bool sk_edge_trigg,
+ struct DaemonOptions *restrict s)
+{
+ mhd_assert (MHD_TLS_BACKEND_NONE != s->tls);
+ mhd_assert ((MHD_TLS_BACKEND_MBEDTLS == s->tls) || \
+ (MHD_TLS_BACKEND_ANY == s->tls));
+
+ if (NULL == s->tls_cert_key.v_mem_cert)
+ {
+ mhd_LOG_MSG (d, MHD_SC_TLS_CONF_BAD_CERT, \
+ "No valid TLS certificate is provided");
+ return MHD_SC_TLS_CONF_BAD_CERT;
+ }
+ mhd_assert (NULL != s->tls_cert_key.v_mem_key);
+
+ if ((MHD_WM_THREAD_PER_CONNECTION == s->work_mode.mode) ||
+ ((MHD_WM_WORKER_THREADS == s->work_mode.mode)
+ && (1u < s->work_mode.params.num_worker_threads)))
+ {
+ bool threads_supported;
+#if ! defined(MBEDTLS_THREADING_C)
+ threads_supported = false;
+#else /* MBEDTLS_THREADING_C */
+# if defined(MBEDTLS_VERSION_FEATURES)
+ threads_supported =
+ (0 == mbedtls_version_check_feature ("MBEDTLS_THREADING_C"));
+# else /* ! MBEDTLS_VERSION_FEATURES */
+ threads_supported = true;
+# endif /* ! MBEDTLS_VERSION_FEATURES */
+#endif /* MBEDTLS_THREADING_C */
+ if (! threads_supported)
+ {
+ mhd_LOG_MSG (d, MHD_SC_TLS_BACKEND_DAEMON_INCOMPATIBLE_SETTINGS, \
+ "MbedTLS built without threading support and cannot "
+ "be used in multi-threaded modes");
+ return MHD_SC_TLS_BACKEND_DAEMON_INCOMPATIBLE_SETTINGS;
+ }
+ }
+
+ return MHD_SC_OK;
+}
+
+
+/**
+ * Set daemon TLS credentials.
+ * This function puts error messages to the log if needed.
+ * @param d the daemon handle
+ * @param d_tls the daemon TLS settings
+ * @param s the application-provided settings
+ * @param rng_func the random generator function
+ * @param rng_ctx the random generator function context
+ * @return #MHD_SC_OK on success,
+ * error code otherwise
+ */
+static MHD_FN_PAR_NONNULL_ (1) MHD_FN_PAR_NONNULL_ (2)
+MHD_FN_PAR_NONNULL_ (3) MHD_FN_MUST_CHECK_RESULT_ enum MHD_StatusCode
+daemon_init_credentials (
+ struct MHD_Daemon *restrict d,
+ struct mhd_TlsMbedDaemonData *restrict d_tls,
+ struct DaemonOptions *restrict s
+#if defined(mhd_TLS_MBED_INIT_TLS_REQ_RNG)
+ ,
+ int (*rng_func)(void *ctx, unsigned char *out, size_t out_size),
+ void *rng_ctx
+#endif /* mhd_TLS_MBED_INIT_TLS_REQ_RNG */
+ )
+{
+ enum MHD_StatusCode ret;
+ size_t cert_len;
+ size_t key_len;
+ size_t pwd_len;
+ int res;
+
+ ret = MHD_SC_OK;
+
+ // TODO: Support multiple certificates
+ cert_len = strlen (s->tls_cert_key.v_mem_cert); // TODO: Reuse calculated length
+ key_len = strlen (s->tls_cert_key.v_mem_key); // TODO: Reuse calculated length
+ pwd_len = (NULL == s->tls_cert_key.v_mem_pass) ?
+ 0u : strlen (s->tls_cert_key.v_mem_pass); // TODO: Reuse calculated length
+
+ mhd_assert (0 != cert_len);
+ mhd_assert (0 != key_len);
+
+ mbedtls_x509_crt_init (&(d_tls->cert_chain));
+
+ res = mbedtls_x509_crt_parse (&(d_tls->cert_chain),
+ (const unsigned char *)
+ s->tls_cert_key.v_mem_cert,
+ cert_len + 1u /* Include terminating zero */);
+ if (0 == res)
+ {
+ mbedtls_pk_init (&(d_tls->prv_key));
+#if defined(mhd_TLS_MBED_INIT_TLS_REQ_RNG)
+ if (0 != mbedtls_pk_parse_key (&(d_tls->prv_key),
+ (const unsigned char *)
+ s->tls_cert_key.v_mem_key,
+ key_len + 1u,
+ (const unsigned char *)
+ s->tls_cert_key.v_mem_pass,
+ pwd_len,
+ rng_func,
+ rng_ctx))
+ ret = MHD_SC_TLS_CONF_BAD_CERT;
+#else /* ! mhd_TLS_MBED_INIT_TLS_REQ_RNG */
+ if (0 != mbedtls_pk_parse_key (&(d_tls->prv_key),
+ (const unsigned char *)
+ s->tls_cert_key.v_mem_key,
+ key_len + 1u,
+ (const unsigned char *)
+ s->tls_cert_key.v_mem_pass,
+ pwd_len))
+ ret = MHD_SC_TLS_CONF_BAD_CERT;
+#endif /* ! mhd_TLS_MBED_INIT_TLS_REQ_RNG */
+
+ if (MHD_SC_OK == ret)
+ {
+ /* The next macro can be defined at MHD build-time to skip potentially
+ expensive check */
+#ifdef MHD_TLS_MBED_SKIP_CERT_KEY_MATCH_CHECK
+ return MHD_SC_OK; /* Success exit point */
+#else /* ! MHD_TLS_MBED_SKIP_CERT_KEY_MATCH_CHECK */
+# if defined(mhd_TLS_MBED_INIT_TLS_REQ_RNG)
+ res = mbedtls_pk_check_pair (&(d_tls->cert_chain.pk),
+ &(d_tls->prv_key),
+ rng_func,
+ rng_ctx);
+# else /* ! mhd_TLS_MBED_INIT_TLS_REQ_RNG */
+ res = mbedtls_pk_check_pair (&(d_tls->cert_chain.pk),
+ &(d_tls->prv_key));
+# endif /* ! mhd_TLS_MBED_INIT_TLS_REQ_RNG */
+ if ((0 == res) ||
+ (MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE == res))
+ return MHD_SC_OK; /* Success exit point */
+
+ mhd_LOG_MSG (d, MHD_SC_TLS_CONF_BAD_CERT, \
+ "The private key data does not match the certificate");
+ ret = MHD_SC_TLS_CONF_BAD_CERT;
+#endif /* ! MHD_TLS_MBED_SKIP_CERT_KEY_MATCH_CHECK */
+ }
+ else
+ {
+ mhd_LOG_MSG (d, MHD_SC_TLS_CONF_BAD_CERT, \
+ "The private key data cannot be decoded");
+ ret = MHD_SC_TLS_CONF_BAD_CERT;
+ }
+
+ mbedtls_pk_free (&(d_tls->prv_key));
+ }
+ else
+ {
+ mhd_LOG_PRINT (d,
+ MHD_SC_TLS_CONF_BAD_CERT,
+ mhd_LOG_FMT ("Failed to parse certificates chain. "
+ "Number of failed certificates: %i"),
+ res);
+ ret = MHD_SC_TLS_CONF_BAD_CERT;
+ }
+ mbedtls_x509_crt_free (&(d_tls->cert_chain));
+
+ mhd_assert (MHD_SC_OK != ret);
+ return ret; /* Failure exit point */
+}
+
+
+/**
+ * De-initialise daemon TLS credentials.
+ * @param d_tls the daemon TLS settings
+ */
+static MHD_FN_PAR_NONNULL_ALL_ void
+daemon_deinit_credentials (struct mhd_TlsMbedDaemonData *restrict d_tls)
+{
+ mbedtls_pk_free (&(d_tls->prv_key));
+
+ mbedtls_x509_crt_free (&(d_tls->cert_chain));
+}
+
+
+#ifdef MBEDTLS_SSL_ALPN
+/**
+ * Initialise daemon ALPN data
+ * This function puts error messages to the log if needed.
+ * @param d the daemon handle
+ * @param d_tls the daemon TLS settings
+ * @param s the application-provided settings
+ * @return #MHD_SC_OK on success,
+ * error code otherwise
+ */
+static MHD_FN_PAR_NONNULL_ALL_ MHD_FN_MUST_CHECK_RESULT_ enum MHD_StatusCode
+daemon_set_alpn (struct MHD_Daemon *restrict d,
+ struct mhd_TlsMbedDaemonData *restrict d_tls,
+ struct DaemonOptions *restrict s)
+{
+ static const char alpn_str_http1_0[] = mhd_ALPN_H1_0;
+ static const char alpn_str_http1_1[] = mhd_ALPN_H1_1;
+# ifdef MHD_SUPPORT_HTTP2
+ static const char alpn_str_http2[] = mhd_ALPN_H2;
+# endif
+ size_t i;
+
+ (void) s; /* Unused currently. Implement reading allowed HTTP versions */
+
+ i = 0u;
+ // TODO: implement reading protocol versions from settings */
+#ifdef MHD_SUPPORT_HTTP2
+ if (1 /* enabled HTTP/2 ? */)
+ d_tls->alpn_prots[i++] = alpn_str_http2;
+#endif /* MHD_SUPPORT_HTTP2 */
+
+ if (1 /* enabled HTTP/1.x ? */)
+ {
+ d_tls->alpn_prots[i++] = alpn_str_http1_1;
+ d_tls->alpn_prots[i++] = alpn_str_http1_0;
+ }
+
+ d_tls->alpn_prots[i] = NULL; /* NULL termination */
+ mhd_assert (mhd_ARR_NUM_ELEMS (d_tls->alpn_prots) > i);
+ mhd_assert (0u != i);
+
+ if (0 == mbedtls_ssl_conf_alpn_protocols (&(d_tls->tls_conf),
+ d_tls->alpn_prots))
+ return MHD_SC_OK; /* Success exit point */
+
+ mhd_LOG_MSG (d, MHD_SC_TLS_DAEMON_INIT_FAILED, \
+ "Failed to set ALPN data");
+ return MHD_SC_TLS_DAEMON_INIT_FAILED;
+}
+
+
+#else /* ! MBEDTLS_SSL_ALPN */
+# define daemon_set_alpn(d,d_tls,s) (MHD_SC_OK)
+#endif /* ! MBEDTLS_SSL_ALPN */
+
+/**
+ * Set daemon TLS configuration.
+ * This function puts error messages to the log if needed.
+ * @param d the daemon handle
+ * @param d_tls the daemon TLS settings
+ * @param s the application-provided settings
+ * @param rng_func the random generator function
+ * @param rng_ctx the random generator function context
+ * @return #MHD_SC_OK on success,
+ * error code otherwise
+ */
+static MHD_FN_PAR_NONNULL_ALL_ MHD_FN_MUST_CHECK_RESULT_ enum MHD_StatusCode
+daemon_init_config (struct MHD_Daemon *restrict d,
+ struct mhd_TlsMbedDaemonData *restrict d_tls,
+ struct DaemonOptions *restrict s)
+{
+ enum MHD_StatusCode ret;
+#if defined(mhd_TLS_MBED_INIT_TLS_REQ_RNG)
+ int (*rng_func)(void *ctx, unsigned char *out, size_t out_size);
+ void *rng_ctx;
+
+# if defined(MHD_TLS_MBED_PREF_RNG_CTR)
+ rng_func = &mbedtls_ctr_drbg_random;
+ rng_ctx = &mhd_mbed_ctr_drbg_ctx;
+# elif defined(MHD_TLS_MBED_PREF_RNG_HMAC)
+ rng_func = &mbedtls_hmac_drbg_random;
+ rng_ctx = &mhd_mbed_hmac_drbg_ctx;
+# elif defined(MHD_TLS_MBED_PREF_RNG_PSA)
+ rng_func = &mbedtls_psa_get_random;
+ rng_ctx = MBEDTLS_PSA_RANDOM_STATE;
+# else /* MHD_TLS_MBED_PREF_RNG_PSA */
+ /* Support for external strong random generator could be added here */
+#error No random generator is enabled in MbedTLS
+ return MHD_SC_INTERNAL_ERROR;
+# endif /* MHD_TLS_MBED_PREF_RNG_PSA */
+
+ ret = daemon_init_credentials (d,
+ d_tls,
+ s,
+ rng_func,
+ rng_ctx);
+#else /* mhd_TLS_MBED_INIT_TLS_REQ_RNG */
+ ret = daemon_init_credentials (d,
+ d_tls,
+ s);
+#endif /* mhd_TLS_MBED_INIT_TLS_REQ_RNG */
+
+ if (MHD_SC_OK != ret)
+ return ret;
+
+ mbedtls_ssl_config_init (&(d_tls->tls_conf));
+
+#ifdef mhd_TLS_MBED_HAS_DEBUG_PRINT
+ mbedtls_ssl_conf_dbg (&(d_tls->tls_conf),
+ mhd_tls_mbed_debug_print,
+ NULL);
+ mbedtls_debug_set_threshold (mhd_DBG_PRINT_LEVEL);
+#endif /* mhd_TLS_MBED_HAS_DEBUG_PRINT */
+
+ if (0 ==
+ mbedtls_ssl_config_defaults (&(d_tls->tls_conf),
+ MBEDTLS_SSL_IS_SERVER,
+ MBEDTLS_SSL_TRANSPORT_STREAM,
+ MBEDTLS_SSL_PRESET_DEFAULT))
+ {
+#if defined(mhd_TLS_MBED_INIT_TLS_REQ_RNG)
+ mbedtls_ssl_conf_rng (&(d_tls->tls_conf),
+ rng_func,
+ rng_ctx);
+#endif /* mhd_TLS_MBED_INIT_TLS_REQ_RNG */
+
+ /* Client certificates are not implemented yet */
+ mbedtls_ssl_conf_authmode (&(d_tls->tls_conf),
+ MBEDTLS_SSL_VERIFY_NONE);
+
+ if (0 ==
+ mbedtls_ssl_conf_own_cert (&(d_tls->tls_conf),
+ &(d_tls->cert_chain),
+ &(d_tls->prv_key)))
+ {
+ ret = daemon_set_alpn (d,
+ d_tls,
+ s);
+ if (MHD_SC_OK == ret)
+ return MHD_SC_OK; /* Success exit point */
+
+ /* Below is a cleanup path */
+ }
+ else
+ ret = MHD_SC_DAEMON_MEM_ALLOC_FAILURE; /* Do not waste binary space on the additional message */
+ }
+ else
+ ret = MHD_SC_DAEMON_MEM_ALLOC_FAILURE; /* Do not waste binary space on the additional message */
+
+ mbedtls_ssl_config_free (&(d_tls->tls_conf));
+
+ daemon_deinit_credentials (d_tls);
+
+ mhd_assert (MHD_SC_OK != ret);
+ return ret; /* Failure exit point */
+}
+
+
+MHD_INTERNAL MHD_FN_MUST_CHECK_RESULT_ MHD_FN_PAR_NONNULL_ALL_
+MHD_FN_PAR_OUT_ (4) mhd_StatusCodeInt
+mhd_tls_mbed_daemon_init (struct MHD_Daemon *restrict d,
+ bool sk_edge_trigg,
+ struct DaemonOptions *restrict s,
+ struct mhd_TlsMbedDaemonData **restrict p_d_tls)
+{
+ mhd_StatusCodeInt res;
+ struct mhd_TlsMbedDaemonData *restrict d_tls;
+
+ /* Successful initialisation must be checked earlier */
+ mhd_assert (mbedtls_lib_inited_once);
+ mhd_assert (mbedtls_lib_inited_now);
+
+ res = check_app_tls_settings (d,
+ sk_edge_trigg,
+ s);
+ if (MHD_SC_OK != res)
+ return res;
+
+ d_tls = (struct mhd_TlsMbedDaemonData *)
+ mhd_calloc (1, sizeof (struct mhd_TlsMbedDaemonData));
+ *p_d_tls = d_tls;
+ if (NULL == d_tls)
+ return MHD_SC_DAEMON_MEM_ALLOC_FAILURE;
+
+ res = daemon_init_config (d,
+ d_tls,
+ s);
+ if (MHD_SC_OK == res)
+ {
+ return MHD_SC_OK; /* Success exit point */
+ }
+ /* Below is a clean-up code path */
+ free (d_tls);
+ *p_d_tls = NULL;
+ mhd_assert (MHD_SC_OK != res);
+ return res; /* Failure exit point */
+}
+
+
+MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_
+MHD_FN_PAR_INOUT_ (1) void
+mhd_tls_mbed_daemon_deinit (struct mhd_TlsMbedDaemonData *restrict d_tls)
+{
+ mhd_assert (NULL != d_tls);
+
+ mbedtls_ssl_config_free (&(d_tls->tls_conf));
+
+ daemon_deinit_credentials (d_tls);
+
+ free (d_tls);
+}
+
+
+/* ** Connection initialisation / de-initialisation ** */
+
+MHD_INTERNAL size_t
+mhd_tls_mbed_conn_get_tls_size_v (void)
+{
+ return sizeof (struct mhd_TlsMbedConnData);
+}
+
+
+/* Forward declarations of custom transport callbacks */
+static int
+mhd_mbed_cb_recv (void *ctx,
+ unsigned char *buf,
+ size_t size);
+
+static int
+mhd_mbed_cb_send (void *ctx,
+ const unsigned char *buf,
+ size_t size);
+
+MHD_INTERNAL MHD_FN_MUST_CHECK_RESULT_ MHD_FN_PAR_NONNULL_ALL_
+MHD_FN_PAR_OUT_ (3) bool
+mhd_tls_mbed_conn_init (const struct mhd_TlsMbedDaemonData *restrict d_tls,
+ struct mhd_ConnSocket *sk,
+ struct mhd_TlsMbedConnData *restrict c_tls)
+{
+ c_tls->tr.sk = sk;
+
+ mbedtls_ssl_init (&(c_tls->sess));
+
+ if (0 == mbedtls_ssl_setup (&(c_tls->sess),
+ &(d_tls->tls_conf)))
+ {
+ mbedtls_ssl_set_bio (&(c_tls->sess),
+ c_tls,
+ &mhd_mbed_cb_send,
+ &mhd_mbed_cb_recv,
+ NULL /* no recv_timeout callback */);
+
+#ifndef NDEBUG
+ c_tls->dbg.is_inited = true;
+#endif
+ return true; /* Success exit point */
+ }
+
+ mbedtls_ssl_free (&(c_tls->sess));
+ return false; /* Failure exit point */
+}
+
+
+MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ void
+mhd_tls_mbed_conn_deinit (struct mhd_TlsMbedConnData *restrict c_tls)
+{
+ mhd_assert (c_tls->dbg.is_inited);
+ mbedtls_ssl_free (&(c_tls->sess));
+#ifndef NDEBUG
+ c_tls->dbg.is_inited = false;
+#endif
+}
+
+
+/* ** Custom transport functions ** */
+
+/**
+ * Prepare for network operation
+ * @param c_tls the connection TLS data
+ */
+mhd_static_inline MHD_FN_PAR_NONNULL_ALL_ void
+mhd_tls_mbed_sckt_comm_prep (struct mhd_TlsMbedConnData *restrict c_tls)
+{
+ memset (&(c_tls->tr.state),
+ 0,
+ sizeof(c_tls->tr.state));
+}
+
+
+/**
+ * Prepare for send() network operation
+ * @param c_tls the connection TLS data
+ * @param unencr_size the size of the data to send before encryption
+ * @param push_data set to 'false' if it is know that the data to be sent
+ * is incomplete (message or chunk),
+ * set to 'true' if the data is complete or the final part
+ */
+mhd_static_inline MHD_FN_PAR_NONNULL_ALL_ void
+mhd_tls_mbed_sckt_comm_prep_send (struct mhd_TlsMbedConnData *restrict c_tls,
+ size_t unencr_size,
+ bool push_data)
+{
+ mhd_tls_mbed_sckt_comm_prep (c_tls);
+
+ if (push_data)
+ c_tls->tr.state.send_unenc_size = unencr_size;
+ else
+ c_tls->tr.state.send_unenc_size = (size_t) (~((size_t) 0));
+}
+
+
+/**
+ * The callback which called by MbedTLS to receive the data
+ * @param ctx the context for the send callback
+ * @param buf the buffer to put received data
+ * @param size the size of the @a buf
+ * @return the positive number of bytes received on success,
+ * 0 if EOF received (peer closed write/send),
+ * #MBEDTLS_ERR_SSL_WANT_READ if receiving would block OR
+ * receiving was interrupted,
+ * #MBEDTLS_ERR_NET_CONN_RESET if connection was broken
+ * or #MBEDTLS_ERR_NET_RECV_FAILED in case of other errors
+ */
+static int
+mhd_mbed_cb_recv (void *ctx,
+ unsigned char *buf,
+ size_t size)
+{
+ struct mhd_TlsMbedConnData *const c_tls = (struct mhd_TlsMbedConnData *) ctx;
+ struct mhd_TlsMbedConnCstmTrtState *const state = &(c_tls->tr.state);
+ size_t received;
+
+ /* MbedTLS may call recv() several times.
+ This may result in unwanted extra syscalls, unfair connections
+ processing or even blocking if socket is blocking.
+ MHD limits to single send() syscall per operation to evenly distribute
+ workload to all connections. */
+ if (state->recv_called)
+ return MBEDTLS_ERR_SSL_WANT_READ;
+
+ /* MbedTLS may call blindly recv() after calling send() first.
+ If send() was the first socket operation then the socket has been
+ checked by MHD for 'send-ready' as receiving operation was expected.
+ Do not use recv() if 'recv-ready' is not known and the socket is blocking.
+ */
+ if (state->send_called && ! c_tls->tr.sk->props.is_nonblck)
+ return MBEDTLS_ERR_SSL_WANT_READ;
+
+ if (1)
+ {
+ const int size_i = (int) size;
+
+ if ((0 > size_i) ||
+ (size != (size_t) size_i))
+ {
+ /* Return value limitation */
+ size = (size_t) (((unsigned int) ~((unsigned int) 0)) >> 1u);
+ }
+ }
+
+ state->recv_res = mhd_sckt_recv (c_tls->tr.sk,
+ size,
+ (char *) buf,
+ &received);
+ state->recv_called = true;
+
+ if (mhd_SOCKET_ERR_NO_ERROR == state->recv_res)
+ {
+ mhd_ASSUME (size >= received);
+ mhd_assert (0 <= (int) received);
+ return (int) received;
+ }
+
+ if (mhd_SOCKET_ERR_INTR >= state->recv_res)
+ {
+ mhd_assert ((mhd_SOCKET_ERR_INTR == state->recv_res) ||
+ (mhd_SOCKET_ERR_AGAIN == state->recv_res));
+ return MBEDTLS_ERR_SSL_WANT_READ;
+ }
+
+ if (mhd_SOCKET_ERR_IS_HARD (state->recv_res))
+ {
+ c_tls->tr.sk->state.discnt_err = state->recv_res;
+ return MBEDTLS_ERR_NET_CONN_RESET;
+ }
+
+ return MBEDTLS_ERR_NET_RECV_FAILED;
+}
+
+
+/**
+ * The callback called by MbedTLS to send the data
+ * @param ctx the context for the send callback
+ * @param buf the buffer with the data to send
+ * @param size the size of the data in the @a buf
+ * @return the positive number of bytes sent on success,
+ * #MBEDTLS_ERR_SSL_WANT_WRITE if sending would block OR
+ * sending was interrupted,
+ * #MBEDTLS_ERR_NET_CONN_RESET if connection was broken
+ * or #MBEDTLS_ERR_NET_SEND_FAILED in case of other errors
+ */
+static int
+mhd_mbed_cb_send (void *ctx,
+ const unsigned char *buf,
+ size_t size)
+{
+ struct mhd_TlsMbedConnData *const c_tls = (struct mhd_TlsMbedConnData *) ctx;
+ struct mhd_TlsMbedConnCstmTrtState *const state = &(c_tls->tr.state);
+ /* Check whether the complete data is sending.
+ The compression is not used so the data after the encryption must not
+ be smaller than before the encryption.
+ The check may result in false-positive (unlikely in practice), but
+ this should not hurt the performance. */
+ bool push_data = (size >= state->send_unenc_size);
+ size_t sent;
+
+ /* MbedTLS may call send() several times in a loop, until all data is sent.
+ This may result in unwanted extra syscalls, unfair connections processing
+ or even blocking if socket is blocking.
+ MHD limits to single send() syscall per operation to evenly distribute
+ workload to all connections. */
+ if (state->send_called)
+ return MBEDTLS_ERR_SSL_WANT_WRITE;
+
+ /* MbedTLS may call blindly send() after calling recv() first.
+ If recv() was the first socket operation then the socket has been
+ checked by MHD for 'recv-ready' as receiving operation was expected.
+ Do not use send() if 'send-ready' is not known and the socket is blocking.
+ */
+ if (state->recv_called && ! c_tls->tr.sk->props.is_nonblck)
+ return MBEDTLS_ERR_SSL_WANT_WRITE;
+
+ if (1)
+ {
+ const int size_i = (int) size;
+
+ if ((0 > size_i) ||
+ (size != (size_t) size_i))
+ {
+ /* Return value limitation */
+ size = (size_t) (((unsigned int) ~((unsigned int) 0)) >> 1u);
+ push_data = false;
+ }
+ }
+
+ state->send_res = mhd_sckt_send (c_tls->tr.sk,
+ size,
+ (const char *) buf,
+ push_data,
+ &sent);
+ state->send_called = true;
+
+ if (mhd_SOCKET_ERR_NO_ERROR == state->send_res)
+ {
+ mhd_ASSUME (size >= sent);
+ mhd_assert (0 < (int) sent);
+ return (int) sent;
+ }
+
+ if (mhd_SOCKET_ERR_INTR >= state->send_res)
+ {
+ mhd_assert ((mhd_SOCKET_ERR_INTR == state->send_res) ||
+ (mhd_SOCKET_ERR_AGAIN == state->send_res));
+ return MBEDTLS_ERR_SSL_WANT_WRITE;
+ }
+
+ if (mhd_SOCKET_ERR_IS_HARD (state->send_res))
+ {
+ c_tls->tr.sk->state.discnt_err = state->send_res;
+ return MBEDTLS_ERR_NET_CONN_RESET;
+ }
+
+ return MBEDTLS_ERR_NET_SEND_FAILED;
+}
+
+
+/* ** TLS connection establishing ** */
+
+MHD_INTERNAL MHD_FN_MUST_CHECK_RESULT_ MHD_FN_PAR_NONNULL_ALL_
+enum mhd_TlsProcedureResult
+mhd_tls_mbed_conn_handshake (struct mhd_TlsMbedConnData *c_tls)
+{
+ int res;
+
+ mhd_assert (c_tls->dbg.is_inited);
+ mhd_assert (! c_tls->dbg.is_tls_handshake_completed);
+ mhd_assert (! c_tls->shut_tls_wr_sent);
+ mhd_assert (! c_tls->shut_tls_wr_received);
+ mhd_assert (! c_tls->dbg.is_failed);
+
+ mhd_tls_mbed_sckt_comm_prep (c_tls);
+
+ res = mbedtls_ssl_handshake (&(c_tls->sess));
+
+ mhd_assert ((c_tls->tr.state.recv_called) ||
+ (mhd_SOCKET_ERR_NO_ERROR == c_tls->tr.state.recv_res));
+ mhd_assert ((c_tls->tr.state.send_called) ||
+ (mhd_SOCKET_ERR_NO_ERROR == c_tls->tr.state.send_res));
+
+ switch (res)
+ {
+ case 0:
+#ifndef NDEBUG
+ c_tls->dbg.is_tls_handshake_completed = true;
+#endif /* ! NDEBUG */
+ return mhd_TLS_PROCED_SUCCESS; /* Success exit point */
+
+ case MBEDTLS_ERR_SSL_WANT_READ:
+ mhd_assert (! mhd_SOCKET_ERR_IS_HARD (c_tls->tr.state.recv_res));
+ mhd_assert (! mhd_SOCKET_ERR_IS_HARD (c_tls->tr.state.send_res));
+
+ if (! c_tls->tr.state.recv_called)
+ return mhd_TLS_PROCED_RECV_INTERRUPTED; /* Do not clear 'recv-ready' flag */
+
+ if (mhd_SOCKET_ERR_AGAIN == c_tls->tr.state.recv_res)
+ return mhd_TLS_PROCED_RECV_MORE_NEEDED; /* Clear 'recv-ready' flag */
+
+ return mhd_TLS_PROCED_RECV_INTERRUPTED; /* Do not clear 'recv-ready' flag */
+
+ case MBEDTLS_ERR_SSL_WANT_WRITE:
+ mhd_assert (! mhd_SOCKET_ERR_IS_HARD (c_tls->tr.state.recv_res));
+ mhd_assert (! mhd_SOCKET_ERR_IS_HARD (c_tls->tr.state.send_res));
+
+ if (! c_tls->tr.state.send_called)
+ return mhd_TLS_PROCED_SEND_INTERRUPTED; /* Do not clear 'send-ready' flag */
+
+ if (mhd_SOCKET_ERR_AGAIN == c_tls->tr.state.send_res)
+ return mhd_TLS_PROCED_SEND_MORE_NEEDED; /* Clear 'send-ready' flag */
+
+ return mhd_TLS_PROCED_SEND_INTERRUPTED; /* Do not clear 'send-ready' flag */
+
+ case MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS:
+ mhd_assert (0 && "MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS must not be returned");
+ break;
+
+ case MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS:
+ /* The result means that mbedtls_ssl_handshake() must be called again
+ later.
+ As this result does not map directly to any of available flags,
+ so map it to "waiting for send-ready" as the socket should be already
+ 'send-ready'. */
+
+ return (c_tls->tr.state.send_called &&
+ (mhd_SOCKET_ERR_AGAIN == c_tls->tr.state.send_res)) ?
+ mhd_TLS_PROCED_SEND_MORE_NEEDED : mhd_TLS_PROCED_SEND_INTERRUPTED;
+
+ case MBEDTLS_ERR_SSL_RECEIVED_EARLY_DATA:
+#ifdef MBEDTLS_SSL_EARLY_DATA
+ /* Could be replaced with early data support is implemented */
+#endif /* MBEDTLS_SSL_EARLY_DATA */
+ mhd_assert (0 &&
+ "MBEDTLS_ERR_SSL_RECEIVED_EARLY_DATA must not be returned");
+ break;
+
+ default:
+ break; /* Handle other values below */
+ }
+
+ /* All other result codes must be interpreted as a hard error */
+#ifndef NDEBUG
+ c_tls->dbg.is_failed = true;
+#endif /* ! NDEBUG */
+
+ return mhd_TLS_PROCED_FAILED;
+}
+
+
+MHD_INTERNAL MHD_FN_MUST_CHECK_RESULT_ MHD_FN_PAR_NONNULL_ALL_
+enum mhd_TlsProcedureResult
+mhd_tls_mbed_conn_shutdown (struct mhd_TlsMbedConnData *c_tls)
+{
+ int res;
+
+ mhd_assert (c_tls->dbg.is_inited);
+ mhd_assert (c_tls->dbg.is_tls_handshake_completed);
+ mhd_assert (! c_tls->dbg.is_failed);
+
+ mhd_tls_mbed_sckt_comm_prep (c_tls);
+
+ res = mbedtls_ssl_close_notify (&(c_tls->sess));
+
+ switch (res)
+ {
+ case 0:
+ c_tls->shut_tls_wr_sent = true;
+ c_tls->shut_tls_wr_received = true;
+ return mhd_TLS_PROCED_SUCCESS; /* Success exit point */
+
+ case MBEDTLS_ERR_SSL_WANT_READ:
+ mhd_assert (! mhd_SOCKET_ERR_IS_HARD (c_tls->tr.state.recv_res));
+ mhd_assert (! mhd_SOCKET_ERR_IS_HARD (c_tls->tr.state.send_res));
+
+ if (! c_tls->tr.state.recv_called)
+ return mhd_TLS_PROCED_RECV_INTERRUPTED; /* Do not clear 'recv-ready' flag */
+
+ if (mhd_SOCKET_ERR_AGAIN == c_tls->tr.state.recv_res)
+ return mhd_TLS_PROCED_RECV_MORE_NEEDED; /* Clear 'recv-ready' flag */
+
+ return mhd_TLS_PROCED_RECV_INTERRUPTED; /* Do not clear 'recv-ready' flag */
+
+ case MBEDTLS_ERR_SSL_WANT_WRITE:
+ mhd_assert (! mhd_SOCKET_ERR_IS_HARD (c_tls->tr.state.recv_res));
+ mhd_assert (! mhd_SOCKET_ERR_IS_HARD (c_tls->tr.state.send_res));
+
+ if (! c_tls->tr.state.send_called)
+ return mhd_TLS_PROCED_SEND_INTERRUPTED; /* Do not clear 'send-ready' flag */
+
+ if (mhd_SOCKET_ERR_AGAIN == c_tls->tr.state.send_res)
+ return mhd_TLS_PROCED_SEND_MORE_NEEDED; /* Clear 'send-ready' flag */
+
+ return mhd_TLS_PROCED_SEND_INTERRUPTED; /* Do not clear 'send-ready' flag */
+
+ default:
+ break; /* Handle other values below */
+ }
+
+ /* All other result codes must be interpreted as a hard error */
+#ifndef NDEBUG
+ c_tls->dbg.is_failed = true;
+#endif /* ! NDEBUG */
+
+ return mhd_TLS_PROCED_FAILED;
+}
+
+
+/* ** Data receiving and sending ** */
+
+MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_
+MHD_FN_PAR_OUT_SIZE_ (3,2)
+MHD_FN_PAR_OUT_ (4) enum mhd_SocketError
+mhd_tls_mbed_conn_recv (struct mhd_TlsMbedConnData *c_tls,
+ size_t buf_size,
+ char buf[MHD_FN_PAR_DYN_ARR_SIZE_ (buf_size)],
+ size_t *restrict received)
+{
+ int res;
+
+ mhd_assert (0 != buf_size);
+
+ mhd_assert (c_tls->dbg.is_inited);
+ mhd_assert (c_tls->dbg.is_tls_handshake_completed);
+ mhd_assert (! c_tls->shut_tls_wr_sent);
+ mhd_assert (! c_tls->dbg.is_failed);
+
+ if (1)
+ {
+ const int buf_size_i = (int) buf_size;
+ if ((0 > buf_size_i) ||
+ (buf_size != (size_t) buf_size_i))
+ {
+ /* Called function return value limitation */
+ buf_size = (size_t) (((unsigned int) ~((unsigned int) 0)) >> 1u);
+ }
+ }
+
+ c_tls->recv_data_in_buff = false;
+ mhd_tls_mbed_sckt_comm_prep (c_tls);
+
+ res = mbedtls_ssl_read (&(c_tls->sess),
+ (unsigned char *) buf,
+ buf_size);
+
+ if (0 <= res)
+ {
+ mhd_ASSUME (buf_size >= (size_t) res);
+ *received = (size_t) res;
+
+ return mhd_SOCKET_ERR_NO_ERROR; /* Success exit point */
+ }
+
+ switch (res)
+ {
+ case MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY:
+ c_tls->shut_tls_wr_received = true;
+ *received = 0u;
+
+ return mhd_SOCKET_ERR_NO_ERROR; /* Success exit point */
+
+ case MBEDTLS_ERR_SSL_WANT_READ:
+ mhd_assert (! mhd_SOCKET_ERR_IS_HARD (c_tls->tr.state.recv_res));
+ mhd_assert (! mhd_SOCKET_ERR_IS_HARD (c_tls->tr.state.send_res));
+
+ if (! c_tls->tr.state.recv_called)
+ return mhd_SOCKET_ERR_INTR; /* Do not clear 'recv-ready' flag */
+
+ if (mhd_SOCKET_ERR_NO_ERROR == c_tls->tr.state.recv_res)
+ {
+ /* recv() succeed for the first time and then called again */
+ return c_tls->tr.sk->props.is_nonblck ?
+ mhd_SOCKET_ERR_INTR : mhd_SOCKET_ERR_AGAIN;
+ }
+
+ return c_tls->tr.state.recv_res;
+
+ case MBEDTLS_ERR_SSL_WANT_WRITE:
+ mhd_assert (0 &&
+ "The handshake must be fully completed earlier");
+ break;
+
+ case MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS:
+ mhd_assert (0 && "MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS must not be returned");
+ break;
+
+ case MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS:
+ /* MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS means that recv() should be called
+ again later. Pretend that data is already pending to not block on
+ waiting for the new incoming data. */
+ c_tls->recv_data_in_buff = true;
+ return mhd_SOCKET_ERR_INTR; /* Do not clear 'recv-ready' flag */
+
+ case MBEDTLS_ERR_SSL_CLIENT_RECONNECT:
+ mhd_assert (0 &&
+ "MBEDTLS_ERR_SSL_CLIENT_RECONNECT must not be "
+ "returned for non-DTLS");
+ break;
+
+ case MBEDTLS_ERR_SSL_RECEIVED_NEW_SESSION_TICKET:
+ mhd_assert (0 &&
+ "MBEDTLS_ERR_SSL_RECEIVED_NEW_SESSION_TICKET must not be "
+ "returned on the server side");
+ break;
+
+ case MBEDTLS_ERR_SSL_RECEIVED_EARLY_DATA:
+#ifdef MBEDTLS_SSL_EARLY_DATA
+ /* Could be replaced with early data support is implemented */
+#endif /* MBEDTLS_SSL_EARLY_DATA */
+ mhd_assert (0 &&
+ "MBEDTLS_ERR_SSL_RECEIVED_EARLY_DATA must not be returned");
+ break;
+
+ default:
+ break; /* Handle other values below */
+ }
+
+ /* Treat all other kinds of errors as hard errors */
+#ifndef NDEBUG
+ c_tls->dbg.is_failed = true;
+#endif /* ! NDEBUG */
+ return mhd_SOCKET_ERR_TLS;
+}
+
+
+MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ bool
+mhd_tls_mbed_conn_has_data_in (struct mhd_TlsMbedConnData *restrict c_tls)
+{
+ return c_tls->recv_data_in_buff ||
+ (0 != mbedtls_ssl_check_pending (&(c_tls->sess)));
+}
+
+
+MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_
+MHD_FN_PAR_IN_SIZE_ (3,2)
+MHD_FN_PAR_OUT_ (5) enum mhd_SocketError
+mhd_tls_mbed_conn_send (struct mhd_TlsMbedConnData *c_tls,
+ size_t buf_size,
+ const char buf[MHD_FN_PAR_DYN_ARR_SIZE_ (buf_size)],
+ bool push_data,
+ size_t *restrict sent)
+{
+ int res;
+
+ mhd_assert (0 != buf_size);
+
+ mhd_assert (c_tls->dbg.is_inited);
+ mhd_assert (c_tls->dbg.is_tls_handshake_completed);
+ mhd_assert (! c_tls->shut_tls_wr_sent);
+ mhd_assert (! c_tls->dbg.is_failed);
+
+ if (1)
+ {
+ const int buf_size_i = (int) buf_size;
+ if ((0 > buf_size_i) ||
+ (buf_size != (size_t) buf_size_i))
+ {
+ /* Called function return value limitation */
+ buf_size = (size_t) (((unsigned int) ~((unsigned int) 0)) >> 1u);
+ push_data = false;
+ }
+ }
+
+ mhd_tls_mbed_sckt_comm_prep_send (c_tls,
+ buf_size,
+ push_data);
+
+ res = mbedtls_ssl_write (&(c_tls->sess),
+ (const unsigned char *) buf,
+ buf_size);
+
+ if (0 < res)
+ {
+ mhd_ASSUME (buf_size >= (size_t) res);
+ *sent = (size_t) res;
+
+ return mhd_SOCKET_ERR_NO_ERROR; /* Success exit point */
+ }
+
+ switch (res)
+ {
+ case 0:
+ mhd_assert (0 &&
+ "Zero must not be returned when sending non-zero size");
+ break;
+
+ case MBEDTLS_ERR_SSL_WANT_WRITE:
+ mhd_assert (! mhd_SOCKET_ERR_IS_HARD (c_tls->tr.state.send_res));
+ mhd_assert (! mhd_SOCKET_ERR_IS_HARD (c_tls->tr.state.recv_res));
+
+ if (! c_tls->tr.state.send_called)
+ return mhd_SOCKET_ERR_INTR; /* Do not clear 'recv-ready' flag */
+
+ if (mhd_SOCKET_ERR_NO_ERROR == c_tls->tr.state.send_res)
+ {
+ /* send() succeed for the first time and then called again */
+ return c_tls->tr.sk->props.is_nonblck ?
+ mhd_SOCKET_ERR_INTR : mhd_SOCKET_ERR_AGAIN;
+ }
+
+ return c_tls->tr.state.send_res;
+
+ case MBEDTLS_ERR_SSL_WANT_READ:
+ mhd_assert (0 &&
+ "The handshake must be fully completed earlier");
+ break;
+
+ case MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS:
+ mhd_assert (0 && "MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS must not be returned");
+ break;
+
+ case MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS:
+ /* MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS means that send() should be called
+ again later. Wait for 'send-ready' which should be already set or
+ will be set later, when OS pushed the data to the network. */
+ return mhd_SOCKET_ERR_INTR; /* Do not clear 'recv-ready' flag */
+
+ case MBEDTLS_ERR_SSL_CLIENT_RECONNECT:
+ mhd_assert (0 &&
+ "MBEDTLS_ERR_SSL_CLIENT_RECONNECT must not be "
+ "returned for non-DTLS");
+ break;
+
+ case MBEDTLS_ERR_SSL_RECEIVED_NEW_SESSION_TICKET:
+ mhd_assert (0 &&
+ "MBEDTLS_ERR_SSL_RECEIVED_NEW_SESSION_TICKET must not be "
+ "returned on the server side");
+ break;
+
+ case MBEDTLS_ERR_SSL_RECEIVED_EARLY_DATA:
+#ifdef MBEDTLS_SSL_EARLY_DATA
+ /* Could be replaced with early data support is implemented */
+#endif /* MBEDTLS_SSL_EARLY_DATA */
+ mhd_assert (0 &&
+ "MBEDTLS_ERR_SSL_RECEIVED_EARLY_DATA must not be returned");
+ break;
+
+ default:
+ break; /* Handle other values below */
+ }
+
+ /* Treat all other kinds of errors as hard errors */
+#ifndef NDEBUG
+ c_tls->dbg.is_failed = true;
+#endif /* ! NDEBUG */
+ return mhd_SOCKET_ERR_TLS;
+}
+
+
+/* ** TLS connection information ** */
+
+MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_
+MHD_FN_PAR_OUT_ (2) void
+mhd_tls_mbed_conn_get_tls_sess (
+ struct mhd_TlsMbedConnData *restrict c_tls,
+ union MHD_ConnInfoDynamicTlsSess *restrict tls_sess_out)
+{
+ tls_sess_out->v_mbedtls_session = &(c_tls->sess);
+}
+
+
+MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_
+MHD_FN_PAR_OUT_ (2) bool
+mhd_tls_mbed_conn_get_tls_ver (struct mhd_TlsMbedConnData *restrict c_tls,
+ struct mhd_StctTlsVersion *restrict tls_ver_out)
+{
+ mhd_assert (c_tls->dbg.is_tls_handshake_completed);
+
+#ifndef MBEDTLS_VERSION_NUMBER
+ if (1)
+ return false; /* Need MbedTLS version number to implement */
+#else /* MBEDTLS_VERSION_NUMBER */
+ if (1)
+ {
+ uint_fast16_t tls_ver_num;
+#if ((MBEDTLS_VERSION_NUMBER + 0) >= 0x03020000)
+ mbedtls_ssl_protocol_version mbedtls_tls_ver;
+
+ mbedtls_tls_ver = mbedtls_ssl_get_version_number (&(c_tls->sess));
+
+ tls_ver_num = (uint_fast16_t) mbedtls_tls_ver;
+#else /* MBEDTLS_VERSION_NUMBER < 0x03020000 */
+ tls_ver_num = (uint_fast16_t) c_tls->sess.MBEDTLS_PRIVATE (major_ver);
+ tls_ver_num <<= 8u;
+ tls_ver_num |= (uint_fast16_t) c_tls->sess.MBEDTLS_PRIVATE (minor_ver);
+#endif /* MBEDTLS_VERSION_NUMBER < 0x03020000 */
+ /* Avoid MbedTLS helper macros and enum values in switch() as they are
+ unstable in MbedTLS. */
+ switch (tls_ver_num)
+ {
+ case 0u:
+ return false;
+
+ case 0x0301u: /* Not really supported by MbedTLS >=3.0 */
+ tls_ver_out->tls_ver = MHD_TLS_VERSION_1_0;
+ break;
+
+ case 0x0302u: /* Not really supported by MbedTLS >=3.0 */
+ tls_ver_out->tls_ver = MHD_TLS_VERSION_1_1;
+ break;
+
+ case 0x0303u:
+ tls_ver_out->tls_ver = MHD_TLS_VERSION_1_2;
+ break;
+
+ case 0x0304u:
+ tls_ver_out->tls_ver = MHD_TLS_VERSION_1_3;
+ break;
+
+ default:
+ tls_ver_out->tls_ver = MHD_TLS_VERSION_UNKNOWN;
+ break;
+ }
+ }
+#endif /* MBEDTLS_VERSION_NUMBER */
+
+ return true;
+}
+
+
+MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ enum mhd_TlsAlpnProt
+mhd_tls_mbed_conn_get_alpn_prot (struct mhd_TlsMbedConnData *restrict c_tls)
+{
+#ifdef MBEDTLS_SSL_ALPN
+ const char *alpn_str;
+
+ alpn_str = mbedtls_ssl_get_alpn_protocol (&(c_tls->sess));
+ if (NULL == alpn_str)
+ return mhd_TLS_ALPN_PROT_NOT_SELECTED;
+
+ return mhd_tls_alpn_decode_n (strlen (alpn_str),
+ (const unsigned char *) alpn_str);
+#else /* ! MBEDTLS_SSL_ALPN */
+ return mhd_TLS_ALPN_PROT_NOT_SELECTED;
+#endif /* ! MBEDTLS_SSL_ALPN */
+}
diff --git a/src/mhd2/tls_mbed_funcs.h b/src/mhd2/tls_mbed_funcs.h
@@ -0,0 +1,318 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later OR (GPL-2.0-or-later WITH eCos-exception-2.0) */
+/*
+ This file is part of GNU libmicrohttpd.
+ Copyright (C) 2025 Evgeny Grin (Karlson2k)
+
+ GNU libmicrohttpd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ GNU libmicrohttpd is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ Alternatively, you can redistribute GNU libmicrohttpd and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of
+ the License, or (at your option) any later version, together
+ with the eCos exception, as follows:
+
+ As a special exception, if other files instantiate templates or
+ use macros or inline functions from this file, or you compile this
+ file and link it with other works to produce a work based on this
+ file, this file does not by itself cause the resulting work to be
+ covered by the GNU General Public License. However the source code
+ for this file must still be made available in accordance with
+ section (3) of the GNU General Public License v2.
+
+ This exception does not invalidate any other reasons why a work
+ based on this file might be covered by the GNU General Public
+ License.
+
+ You should have received copies of the GNU Lesser General Public
+ License and the GNU General Public License along with this library;
+ if not, see <https://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @file src/mhd2/tls_mbed_funcs.h
+ * @brief The declarations of MbedTLS wrapper functions
+ * @author Karlson2k (Evgeny Grin)
+ */
+
+#ifndef MHD_TLS_MBED_FUNCS_H
+#define MHD_TLS_MBED_FUNCS_H 1
+
+#include "mhd_sys_options.h"
+
+#ifndef MHD_SUPPORT_MBEDTLS
+#error This header can be used only if MbedTLS is enabled
+#endif
+
+#include "sys_bool_type.h"
+#include "sys_base_types.h"
+
+#include "mhd_status_code_int.h"
+
+#include "mhd_tls_enums.h"
+#include "mhd_socket_error.h"
+
+/**
+ * The structure with daemon-specific MbedTLS data
+ */
+struct mhd_TlsMbedDaemonData; /* Forward declaration */
+
+/**
+ * The structure with connection-specific MbedTLS data
+ */
+struct mhd_TlsMbedConnData; /* Forward declaration */
+
+union MHD_ConnInfoDynamicTlsSess; /* Forward declaration */
+
+struct mhd_StctTlsVersion; /* Forward declaration */
+
+/* ** Global initialisation / de-initialisation ** */
+
+/**
+ * Globally initialise MbedTLS backend
+ */
+MHD_INTERNAL void
+mhd_tls_mbed_global_init (void);
+
+/* An alias for mhd_tls_mbed_global_init() */
+#define mhd_tls_mbed_global_init_once() mhd_tls_mbed_global_init ()
+
+/* An alias for mhd_tls_mbed_global_init() */
+#define mhd_tls_mbed_global_re_init() mhd_tls_mbed_global_init ()
+
+/**
+ * Globally de-initialise MbedTLS backend
+ */
+MHD_INTERNAL void
+mhd_tls_mbed_global_deinit (void);
+
+/**
+ * Check whether MbedTLS backend was successfully initialised globally
+ * @return 'true' if backend has been successfully initialised,
+ * 'false' if backend cannot be used
+ */
+MHD_INTERNAL bool
+mhd_tls_mbed_is_inited_fine (void)
+MHD_FN_PURE_;
+
+
+/* ** Daemon initialisation / de-initialisation ** */
+
+struct MHD_Daemon; /* Forward declaration */
+struct DaemonOptions; /* Forward declaration */
+
+/**
+ * Check whether MbedTLS backend supports edge-triggered sockets polling
+ * @param s the daemon settings
+ * @return 'true' if the backend supports edge-triggered sockets polling,
+ * 'false' if edge-triggered sockets polling cannot be used
+ */
+#define mhd_tls_mbed_is_edge_trigg_supported(s) (! 0)
+
+
+/**
+ * Allocate and initialise daemon TLS parameters
+ * @param d the daemon handle
+ * @param et if 'true' then sockets polling uses edge-triggering
+ * @param s the daemon settings
+ * @param p_d_tls the pointer to variable to set the pointer to
+ * the daemon's TLS settings (allocated by this function)
+ * @return #MHD_SC_OK on success (p_d_tls set to the allocated settings),
+ * error code otherwise
+ */
+MHD_INTERNAL mhd_StatusCodeInt
+mhd_tls_mbed_daemon_init (struct MHD_Daemon *restrict d,
+ bool sk_edge_trigg,
+ struct DaemonOptions *restrict s,
+ struct mhd_TlsMbedDaemonData **restrict p_d_tls)
+MHD_FN_MUST_CHECK_RESULT_ MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_OUT_ (4);
+
+/**
+ * De-initialise daemon TLS parameters (and free memory allocated for TLS
+ * settings)
+ * @param d_tls the pointer to the daemon's TLS settings
+ */
+MHD_INTERNAL void
+mhd_tls_mbed_daemon_deinit (struct mhd_TlsMbedDaemonData *restrict d_tls)
+MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_INOUT_ (1);
+
+
+/* ** Connection initialisation / de-initialisation ** */
+
+struct mhd_ConnSocket; /* Forward declaration */
+
+/**
+ * Get size size of the connection's TLS settings
+ */
+MHD_INTERNAL size_t
+mhd_tls_mbed_conn_get_tls_size_v (void);
+
+/**
+ * Get size size of the connection's TLS settings
+ * @param d_tls the pointer to the daemon's TLS settings
+ */
+#define mhd_tls_mbed_conn_get_tls_size(d_tls) \
+ mhd_tls_mbed_conn_get_tls_size_v ()
+
+/**
+ * Initialise connection TLS settings
+ * @param d_tls the daemon TLS settings
+ * @param sk data about the socket for the connection
+ * @param[out] c_tls the pointer to the allocated space for
+ * the connection TLS settings
+ * @return 'true' on success,
+ * 'false' otherwise
+ */
+MHD_INTERNAL bool
+mhd_tls_mbed_conn_init (const struct mhd_TlsMbedDaemonData *restrict d_tls,
+ struct mhd_ConnSocket *sk,
+ struct mhd_TlsMbedConnData *restrict c_tls)
+MHD_FN_MUST_CHECK_RESULT_ MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_OUT_ (3);
+
+/**
+ * De-initialise connection TLS settings.
+ * The provided pointer is not freed/deallocated.
+ * @param c_tls the initialised connection TLS settings
+ */
+MHD_INTERNAL void
+mhd_tls_mbed_conn_deinit (struct mhd_TlsMbedConnData *restrict c_tls)
+MHD_FN_PAR_NONNULL_ALL_;
+
+
+/* ** TLS connection establishing ** */
+
+/**
+ * Perform TLS handshake
+ * @param c_tls the connection TLS handle
+ * @return #mhd_TLS_PROCED_SUCCESS if completed successfully
+ * or other enum mhd_TlsProcedureResult values
+ */
+MHD_INTERNAL enum mhd_TlsProcedureResult
+mhd_tls_mbed_conn_handshake (struct mhd_TlsMbedConnData *c_tls)
+MHD_FN_MUST_CHECK_RESULT_ MHD_FN_PAR_NONNULL_ALL_;
+
+/**
+ * Perform shutdown of TLS layer
+ * @param c_tls the connection TLS handle
+ * @return #mhd_TLS_PROCED_SUCCESS if completed successfully
+ * or other enum mhd_TlsProcedureResult values
+ */
+MHD_INTERNAL enum mhd_TlsProcedureResult
+mhd_tls_mbed_conn_shutdown (struct mhd_TlsMbedConnData *c_tls)
+MHD_FN_MUST_CHECK_RESULT_ MHD_FN_PAR_NONNULL_ALL_;
+
+
+/* ** Data sending and receiving over TLS connection ** */
+
+/**
+ * Receive the data from the remote side over TLS connection
+ *
+ * @param c_tls the connection TLS handle
+ * @param buf_size the size of the @a buf buffer
+ * @param[out] buf the buffer to fill with the received data
+ * @param[out] received the pointer to variable to get the size of the data
+ * actually put to the @a buffer
+ * @return mhd_SOCKET_ERR_NO_ERROR if receive succeed (the @a received gets
+ * the received size) or socket error
+ */
+MHD_INTERNAL enum mhd_SocketError
+mhd_tls_mbed_conn_recv (struct mhd_TlsMbedConnData *c_tls,
+ size_t buf_size,
+ char buf[MHD_FN_PAR_DYN_ARR_SIZE_ (buf_size)],
+ size_t *restrict received)
+MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_OUT_SIZE_ (3,2) MHD_FN_PAR_OUT_ (4);
+
+/**
+ * Check whether any incoming data is pending in the TLS buffers
+ *
+ * @param c_tls the connection TLS handle
+ * @return 'true' if any incoming remote data is already pending (the TLS recv()
+ * call can be performed),
+ * 'false' otherwise
+ */
+MHD_INTERNAL bool
+mhd_tls_mbed_conn_has_data_in (struct mhd_TlsMbedConnData *restrict c_tls)
+MHD_FN_PAR_NONNULL_ALL_;
+
+/**
+ * Send data to the remote side over TLS connection
+ *
+ * @param c_tls the connection TLS handle
+ * @param buf_size the size of the @a buf (in bytes)
+ * @param buf content of the buffer to send
+ * @param push_data set to 'false' if it is know that the data in the @a buf
+ * is incomplete (message or chunk),
+ * set to 'true' if the data is complete or the final part
+ * @param[out] sent the pointer to get amount of actually sent bytes
+ * @return mhd_SOCKET_ERR_NO_ERROR if send succeed (the @a sent gets
+ * the sent size) or socket error
+ */
+MHD_INTERNAL enum mhd_SocketError
+mhd_tls_mbed_conn_send (struct mhd_TlsMbedConnData *c_tls,
+ size_t buf_size,
+ const char buf[MHD_FN_PAR_DYN_ARR_SIZE_ (buf_size)],
+ bool push_data,
+ size_t *restrict sent)
+MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_IN_SIZE_ (3,2) MHD_FN_PAR_OUT_ (5);
+
+
+/* ** TLS connection information ** */
+
+/**
+ * Check whether the connection is using "custom transport" functions.
+ * "Custom transport" means that data sending and receiving over system
+ * sockets is performed by MHD callbacks.
+ * When "custom transport" is used, backend TLS send/recv functions are:
+ * * perform additional syscalls (socket options) for data pushing/buffering,
+ * * change socket states like corked, NO_DELAY, both by syscalls and in
+ * MHD socket metadata,
+ * * set disconnect error from the system reported socket error.
+ *
+ * @param c_tls the connection TLS handle
+ * @return boolean 'true' if custom transport is used,
+ * boolean 'false' otherwise
+ */
+#define mhd_tls_mbed_conn_has_cstm_tr(c_tls) (! 0)
+
+/**
+ * Get the TLS session used in connection
+ * @param c_tls the connection TLS handle
+ * @param tls_sess_out the pointer to variable to be set to the TLS session
+ * handle
+ */
+MHD_INTERNAL void
+mhd_tls_mbed_conn_get_tls_sess (
+ struct mhd_TlsMbedConnData *restrict c_tls,
+ union MHD_ConnInfoDynamicTlsSess *restrict tls_sess_out)
+MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_OUT_ (2);
+
+/**
+ * Get the TLS version used in connection
+ * @param c_tls the connection TLS handle
+ * @param tls_ver_out the pointer to variable to be set to the TLS version
+ * @return 'true' is TLS version information set successfully,
+ * 'false' if TLS version information cannot be obtained or mapped
+ */
+MHD_INTERNAL bool
+mhd_tls_mbed_conn_get_tls_ver (struct mhd_TlsMbedConnData *restrict c_tls,
+ struct mhd_StctTlsVersion *restrict tls_ver_out)
+MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_OUT_ (2);
+
+/**
+ * Get a protocol selected by ALPN
+ * @param c_tls the connection TLS handle
+ * @return the selected protocol code
+ */
+MHD_INTERNAL enum mhd_TlsAlpnProt
+mhd_tls_mbed_conn_get_alpn_prot (struct mhd_TlsMbedConnData *restrict c_tls)
+MHD_FN_PAR_NONNULL_ALL_;
+
+
+#endif /* ! MHD_TLS_MBED_FUNCS_H */
diff --git a/src/mhd2/tls_mbed_tls_lib.h b/src/mhd2/tls_mbed_tls_lib.h
@@ -0,0 +1,197 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later OR (GPL-2.0-or-later WITH eCos-exception-2.0) */
+/*
+ This file is part of GNU libmicrohttpd.
+ Copyright (C) 2025 Evgeny Grin (Karlson2k)
+
+ GNU libmicrohttpd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ GNU libmicrohttpd is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ Alternatively, you can redistribute GNU libmicrohttpd and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of
+ the License, or (at your option) any later version, together
+ with the eCos exception, as follows:
+
+ As a special exception, if other files instantiate templates or
+ use macros or inline functions from this file, or you compile this
+ file and link it with other works to produce a work based on this
+ file, this file does not by itself cause the resulting work to be
+ covered by the GNU General Public License. However the source code
+ for this file must still be made available in accordance with
+ section (3) of the GNU General Public License v2.
+
+ This exception does not invalidate any other reasons why a work
+ based on this file might be covered by the GNU General Public
+ License.
+
+ You should have received copies of the GNU Lesser General Public
+ License and the GNU General Public License along with this library;
+ if not, see <https://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @file src/mhd2/tls_mbed_tls_lib.h
+ * @brief The wrapper for MbedTLS headers
+ * @author Karlson2k (Evgeny Grin)
+ */
+
+#ifndef MHD_TLS_MBED_TLS_LIB_H
+#define MHD_TLS_MBED_TLS_LIB_H 1
+
+#include "mhd_sys_options.h"
+
+#ifndef MHD_SUPPORT_MBEDTLS
+#error This header can be used only if MbedTLS is enabled
+#endif
+
+#include <mbedtls/build_info.h>
+#include <mbedtls/platform.h>
+#ifdef MBEDTLS_VERSION_C
+# include <mbedtls/version.h>
+#endif /* MBEDTLS_VERSION_C */
+
+#if ((MBEDTLS_VERSION_MAJOR + 0) < 3)
+#error MbedTLS version 3.0 or later is required
+#endif
+#if ((MBEDTLS_VERSION_NUMBER + 0) < 0x03000000)
+#error MbedTLS version 3.0 or later is required
+#endif
+
+/* #mhd_TLS_MBED_USE_PSA_FREE is MHD build-time user-definable macro */
+#if defined(MBEDTLS_PSA_CRYPTO_CLIENT)
+# define mhd_TLS_MBED_USE_PSA 1
+# ifdef MHD_TLS_MBED_USE_PSA_FREE
+/* The application must not use MbedTLS directly */
+# define mhd_TLS_MBED_USE_PSA_FREE 1
+# endif
+#endif
+
+#ifdef mhd_TLS_MBED_USE_PSA
+# include <psa/crypto.h>
+#endif /* mhd_TLS_MBED_USE_PSA */
+
+#ifdef MBEDTLS_MD_C
+/* Actually MD must be available if TLS is enabled */
+# include <mbedtls/md.h>
+#endif
+
+#if ((MBEDTLS_VERSION_NUMBER + 0) >= 0x03050000)
+# define mhd_TLS_MBED_HAS_SHA3_IDS 1
+#endif
+
+#ifdef MBEDTLS_ENTROPY_C
+# include <mbedtls/entropy.h>
+#endif /* MBEDTLS_ENTROPY_C */
+
+#ifdef mhd_TLS_MBED_USE_PSA
+# include <mbedtls/psa_util.h>
+# define mhd_TLS_MBED_HAS_RNG_PSA 1
+#elif defined(MHD_TLS_MBED_PREF_RNG_PSA)
+# undef MHD_TLS_MBED_PREF_RNG_PSA
+#endif
+
+#ifdef MBEDTLS_HMAC_DRBG_C
+# include <mbedtls/hmac_drbg.h>
+# define mhd_TLS_MBED_HAS_RNG_HMAC 1
+#elif defined(MHD_TLS_MBED_PREF_RNG_HMAC)
+# undef MHD_TLS_MBED_PREF_RNG_HMAC
+#endif /* MBEDTLS_HMAC_DRBG_C */
+
+#ifdef MBEDTLS_CTR_DRBG_C
+# include <mbedtls/ctr_drbg.h>
+# define mhd_TLS_MBED_HAS_RNG_CTR 1
+#elif defined(MHD_TLS_MBED_PREF_RNG_CTR)
+# undef MHD_TLS_MBED_PREF_RNG_CTR
+#endif /* MBEDTLS_CTR_DRBG_C */
+
+#if ! defined(MHD_TLS_MBED_PREF_RNG_PSA) && \
+ ! defined(MHD_TLS_MBED_PREF_RNG_HMAC) && \
+ ! defined(MHD_TLS_MBED_PREF_RNG_CTR)
+# if defined(mhd_TLS_MBED_HAS_RNG_PSA)
+# define MHD_TLS_MBED_PREF_RNG_PSA 1
+# elif defined(mhd_TLS_MBED_HAS_RNG_HMAC) && \
+ defined(MBEDTLS_MD_C)
+# define MHD_TLS_MBED_PREF_RNG_HMAC 1
+# define mhd_TLS_MBED_RNG_PREF_NEEDS_ENTROPY 1
+# elif defined(mhd_TLS_MBED_HAS_RNG_CTR)
+# define MHD_TLS_MBED_PREF_RNG_CTR 1
+# define mhd_TLS_MBED_RNG_PREF_NEEDS_ENTROPY 1
+# endif
+#endif
+
+#if defined(mhd_TLS_MBED_RNG_PREF_NEEDS_ENTROPY) && \
+ defined(MBEDTLS_ENTROPY_C)
+# define mhd_TLS_MBED_USE_LIB_ENTROPY 1
+#endif
+
+#if ((MBEDTLS_VERSION_NUMBER + 0) < 0x04000000)
+/**
+ * TLS initialisation requires random generator
+ */
+# define mhd_TLS_MBED_INIT_TLS_REQ_RNG 1
+#endif
+
+#include <mbedtls/x509_crt.h>
+
+#if ! defined(MBEDTLS_X509_CRT_PARSE_C)
+#error X.509 certificate parsing functions are required
+#endif /* ! MBEDTLS_X509_CRT_PARSE_C */
+
+#include <mbedtls/pk.h>
+
+#if ! defined(MBEDTLS_PK_PARSE_C)
+#error Public key parser is required
+#endif /* ! MBEDTLS_PK_PARSE_C */
+
+#if ! defined(MBEDTLS_PEM_PARSE_C)
+#error PEM parser is required
+#endif /* ! MBEDTLS_PEM_PARSE_C */
+
+/* Required header, checked in 'configure' */
+#include <mbedtls/ssl.h>
+
+/* #MHD_TLS_MBED_SKIP_PLATFORM_SETUP and #MHD_TLS_MBED_USE_PLATFORM_TEARDOWN
+ are MHD build-time user-definable macros */
+/* User may set #MHD_TLS_MBED_SKIP_PLATFORM_SETUP and/or
+ #MHD_TLS_MBED_USE_PLATFORM_TEARDOWN when building MHD to control
+ automatic platform setup / teardown */
+#if defined(MBEDTLS_PLATFORM_SETUP_TEARDOWN_ALT) && \
+ ! defined(MHD_TLS_MBED_SKIP_PLATFORM_SETUP)
+# define mhd_TLS_MBED_HAS_PLATFORM_SETUP 1
+# ifdef MHD_TLS_MBED_USE_PLATFORM_TEARDOWN
+/* The application must not use MbedTLS directly */
+# define mhd_TLS_MBED_USE_PLATFORM_TEARDOWN 1
+# endif
+#endif
+
+#ifdef MBEDTLS_NET_C
+/* Actually, the header should be available unconditionally, but could be
+ accidently excluded if module is disabled. */
+# include <mbedtls/net_sockets.h>
+#endif
+
+#ifndef MBEDTLS_ERR_NET_RECV_FAILED
+/* Unknown error when receiving the data */
+# define MBEDTLS_ERR_NET_RECV_FAILED (-0x004C)
+#endif
+#ifndef MBEDTLS_ERR_NET_SEND_FAILED
+/* Unknown error when sending the data */
+# define MBEDTLS_ERR_NET_SEND_FAILED (-0x004E)
+#endif
+#ifndef MBEDTLS_ERR_NET_CONN_RESET
+/* The network connection is broken */
+# define MBEDTLS_ERR_NET_CONN_RESET (-0x0050)
+#endif
+
+#ifdef MBEDTLS_DEBUG_C
+# include <mbedtls/debug.h>
+#endif
+
+#endif /* ! MHD_TLS_MBED_TLS_LIB_H */
diff --git a/src/mhd2/tls_multi_conn_data.h b/src/mhd2/tls_multi_conn_data.h
@@ -59,6 +59,9 @@ struct mhd_TlsGnuConnData; /* forward declaration */
#ifdef MHD_SUPPORT_OPENSSL
struct mhd_TlsOpenConnData; /* forward declaration */
#endif
+#ifdef MHD_SUPPORT_MBEDTLS
+struct mhd_TlsMbedConnData; /* forward declaration */
+#endif
/**
* The pointer to the underlying TLS backend connection data
@@ -77,6 +80,12 @@ struct mhd_TlsMultiConnRoutePtr
*/
struct mhd_TlsOpenConnData *openssl;
#endif
+#ifdef MHD_SUPPORT_MBEDTLS
+ /**
+ * Pointer to OpenSSL connection-specific data
+ */
+ struct mhd_TlsMbedConnData *mbedtls;
+#endif
};
/**
diff --git a/src/mhd2/tls_multi_daemon_data.h b/src/mhd2/tls_multi_daemon_data.h
@@ -59,6 +59,9 @@ struct mhd_TlsGnuDaemonData; /* forward declaration */
#ifdef MHD_SUPPORT_OPENSSL
struct mhd_TlsOpenDaemonData; /* forward declaration */
#endif
+#ifdef MHD_SUPPORT_MBEDTLS
+struct mhd_TlsMbedDaemonData; /* forward declaration */
+#endif
/**
* The pointer to the underlying TLS backend daemon data
@@ -77,6 +80,12 @@ struct mhd_TlsMultiDaemonRoutePtr
*/
struct mhd_TlsOpenDaemonData *openssl;
#endif
+#ifdef MHD_SUPPORT_MBEDTLS
+ /**
+ * Pointer to OpenSSL daemon-specific data
+ */
+ struct mhd_TlsMbedDaemonData *mbedtls;
+#endif
};
/**
diff --git a/src/mhd2/tls_multi_funcs.c b/src/mhd2/tls_multi_funcs.c
@@ -67,6 +67,9 @@
#if defined(MHD_SUPPORT_OPENSSL)
# include "tls_open_funcs.h"
#endif
+#if defined(MHD_SUPPORT_MBEDTLS)
+# include "tls_mbed_funcs.h"
+#endif
#include "daemon_options.h"
#include "daemon_logger.h"
@@ -101,6 +104,9 @@ mhd_tls_multi_global_init_once (void)
#if defined(MHD_SUPPORT_OPENSSL)
mhd_tls_open_global_init_once ();
#endif
+#if defined(MHD_SUPPORT_MBEDTLS)
+ mhd_tls_mbed_global_init_once ();
+#endif
}
@@ -114,6 +120,9 @@ mhd_tls_multi_global_deinit (void)
#if defined(MHD_SUPPORT_GNUTLS)
mhd_tls_gnu_global_deinit ();
#endif
+#if defined(MHD_SUPPORT_MBEDTLS)
+ mhd_tls_mbed_global_deinit ();
+#endif
}
@@ -126,6 +135,9 @@ mhd_tls_multi_global_re_init (void)
#if defined(MHD_SUPPORT_OPENSSL)
mhd_tls_open_global_re_init ();
#endif
+#if defined(MHD_SUPPORT_MBEDTLS)
+ mhd_tls_mbed_global_re_init ();
+#endif
}
@@ -150,6 +162,11 @@ mhd_tls_multi_is_edge_trigg_supported (struct DaemonOptions *s)
&& mhd_tls_open_is_inited_fine ())
return true;
#endif
+#ifdef MHD_SUPPORT_MBEDTLS
+ if (mhd_tls_mbed_is_edge_trigg_supported (s)
+ && mhd_tls_mbed_is_inited_fine ())
+ return true;
+#endif
return false;
case MHD_TLS_BACKEND_GNUTLS:
#ifdef MHD_SUPPORT_GNUTLS
@@ -165,6 +182,13 @@ mhd_tls_multi_is_edge_trigg_supported (struct DaemonOptions *s)
return mhd_tls_open_is_edge_trigg_supported (s);
#endif
break;
+ case MHD_TLS_BACKEND_MBEDTLS:
+#ifdef MHD_SUPPORT_MBEDTLS
+ /* Ignore "backend inited" status here,
+ it will be checked on daemon TLS init */
+ return mhd_tls_mbed_is_edge_trigg_supported (s);
+#endif
+ break;
default:
mhd_UNREACHABLE ();
break;
@@ -237,6 +261,25 @@ tls_daemon_init_try (enum mhd_TlsMultiRoute route,
"the daemon, error code: %u", (unsigned) res);
return res;
#endif
+#ifdef MHD_SUPPORT_MBEDTLS
+ case mhd_TLS_MULTI_ROUTE_MBED:
+ if (! mhd_tls_mbed_is_inited_fine ())
+ return MHD_SC_TLS_BACKEND_UNAVAILABLE;
+ res = mhd_tls_mbed_daemon_init (d,
+ sk_edge_trigg,
+ s,
+ &(d_tls->data.mbedtls));
+ if (MHD_SC_OK == res)
+ {
+ mhd_M_DEBUG_PRINT ("MbedTLS backend initialised successfully " \
+ "for the daemon");
+ d_tls->choice = route;
+ return MHD_SC_OK;
+ }
+ mhd_M_DEBUG_PRINT1 ("Failed to initialise MbedTLS backend for " \
+ "the daemon, error code: %u", (unsigned) res);
+ return res;
+#endif
case mhd_TLS_MULTI_ROUTE_NONE:
default:
break;
@@ -276,6 +319,9 @@ mhd_tls_multi_daemon_init (struct MHD_Daemon *restrict d,
#ifdef MHD_SUPPORT_OPENSSL
mhd_TLS_MULTI_ROUTE_OPEN,
#endif
+#ifdef MHD_SUPPORT_MBEDTLS
+ mhd_TLS_MULTI_ROUTE_MBED,
+#endif
mhd_TLS_MULTI_ROUTE_NONE /* Not used */
};
/* Try backends one-by-one */
@@ -311,6 +357,16 @@ mhd_tls_multi_daemon_init (struct MHD_Daemon *restrict d,
d_tls);
#endif /* MHD_SUPPORT_OPENSSL */
break;
+#ifdef MHD_SUPPORT_MBEDTLS
+ case MHD_TLS_BACKEND_MBEDTLS:
+ mhd_assert (mhd_tls_mbed_is_inited_fine ()); /* Must be checked earlier */
+ res = tls_daemon_init_try (mhd_TLS_MULTI_ROUTE_MBED,
+ d,
+ sk_edge_trigg,
+ s,
+ d_tls);
+#endif /* MHD_SUPPORT_MBEDTLS */
+ break;
#ifndef MHD_SUPPORT_GNUTLS
case MHD_TLS_BACKEND_GNUTLS:
@@ -318,6 +374,9 @@ mhd_tls_multi_daemon_init (struct MHD_Daemon *restrict d,
#ifndef MHD_SUPPORT_OPENSSL
case MHD_TLS_BACKEND_OPENSSL:
#endif /* ! MHD_SUPPORT_OPENSSL */
+#ifndef MHD_SUPPORT_MBEDTLS
+ case MHD_TLS_BACKEND_MBEDTLS:
+#endif /* ! MHD_SUPPORT_MBEDTLS */
case MHD_TLS_BACKEND_NONE:
default:
mhd_UNREACHABLE ();
@@ -351,6 +410,11 @@ mhd_tls_multi_daemon_deinit (struct mhd_TlsMultiDaemonData *restrict d_tls)
mhd_tls_open_daemon_deinit (d_tls->data.openssl);
break;
#endif
+#ifdef MHD_SUPPORT_MBEDTLS
+ case mhd_TLS_MULTI_ROUTE_MBED:
+ mhd_tls_mbed_daemon_deinit (d_tls->data.mbedtls);
+ break;
+#endif
case mhd_TLS_MULTI_ROUTE_NONE:
default:
mhd_UNREACHABLE ();
@@ -380,6 +444,11 @@ mhd_tls_multi_conn_get_tls_size (struct mhd_TlsMultiDaemonData *restrict d_tls)
data_size += mhd_tls_open_conn_get_tls_size (d_tls->data.openssl);
break;
#endif
+#ifdef MHD_SUPPORT_MBEDTLS
+ case mhd_TLS_MULTI_ROUTE_MBED:
+ data_size += mhd_tls_mbed_conn_get_tls_size (d_tls->data.mbedtls);
+ break;
+#endif
case mhd_TLS_MULTI_ROUTE_NONE:
default:
mhd_UNREACHABLE ();
@@ -392,7 +461,7 @@ mhd_tls_multi_conn_get_tls_size (struct mhd_TlsMultiDaemonData *restrict d_tls)
MHD_INTERNAL MHD_FN_MUST_CHECK_RESULT_ MHD_FN_PAR_NONNULL_ALL_
MHD_FN_PAR_OUT_ (3) bool
mhd_tls_multi_conn_init (const struct mhd_TlsMultiDaemonData *restrict d_tls,
- const struct mhd_ConnSocket *sk,
+ struct mhd_ConnSocket *sk,
struct mhd_TlsMultiConnData *restrict c_tls)
{
c_tls->choice = d_tls->choice;
@@ -414,6 +483,14 @@ mhd_tls_multi_conn_init (const struct mhd_TlsMultiDaemonData *restrict d_tls,
sk,
c_tls->data.openssl);
#endif
+#ifdef MHD_SUPPORT_MBEDTLS
+ case mhd_TLS_MULTI_ROUTE_MBED:
+ /* Assume the same alignment requirements for both structures */
+ c_tls->data.mbedtls = (struct mhd_TlsMbedConnData *) (c_tls + 1);
+ return mhd_tls_mbed_conn_init (d_tls->data.mbedtls,
+ sk,
+ c_tls->data.mbedtls);
+#endif
case mhd_TLS_MULTI_ROUTE_NONE:
default:
mhd_UNREACHABLE ();
@@ -444,6 +521,11 @@ mhd_tls_multi_conn_deinit (struct mhd_TlsMultiConnData *restrict c_tls)
mhd_tls_open_conn_deinit (c_tls->data.openssl);
break;
#endif
+#ifdef MHD_SUPPORT_MBEDTLS
+ case mhd_TLS_MULTI_ROUTE_MBED:
+ mhd_tls_mbed_conn_deinit (c_tls->data.mbedtls);
+ break;
+#endif
case mhd_TLS_MULTI_ROUTE_NONE:
default:
mhd_UNREACHABLE ();
@@ -467,6 +549,10 @@ mhd_tls_multi_conn_handshake (struct mhd_TlsMultiConnData *restrict c_tls)
case mhd_TLS_MULTI_ROUTE_OPEN:
return mhd_tls_open_conn_handshake (c_tls->data.openssl);
#endif
+#ifdef MHD_SUPPORT_MBEDTLS
+ case mhd_TLS_MULTI_ROUTE_MBED:
+ return mhd_tls_mbed_conn_handshake (c_tls->data.mbedtls);
+#endif
case mhd_TLS_MULTI_ROUTE_NONE:
default:
mhd_UNREACHABLE ();
@@ -490,6 +576,10 @@ mhd_tls_multi_conn_shutdown (struct mhd_TlsMultiConnData *restrict c_tls)
case mhd_TLS_MULTI_ROUTE_OPEN:
return mhd_tls_open_conn_shutdown (c_tls->data.openssl);
#endif
+#ifdef MHD_SUPPORT_MBEDTLS
+ case mhd_TLS_MULTI_ROUTE_MBED:
+ return mhd_tls_mbed_conn_shutdown (c_tls->data.mbedtls);
+#endif
case mhd_TLS_MULTI_ROUTE_NONE:
default:
mhd_UNREACHABLE ();
@@ -525,6 +615,13 @@ mhd_tls_multi_conn_recv (struct mhd_TlsMultiConnData *restrict c_tls,
buf,
received);
#endif
+#ifdef MHD_SUPPORT_MBEDTLS
+ case mhd_TLS_MULTI_ROUTE_MBED:
+ return mhd_tls_mbed_conn_recv (c_tls->data.mbedtls,
+ buf_size,
+ buf,
+ received);
+#endif
case mhd_TLS_MULTI_ROUTE_NONE:
default:
mhd_UNREACHABLE ();
@@ -548,6 +645,10 @@ mhd_tls_multi_conn_has_cstm_tr (struct mhd_TlsMultiConnData *restrict c_tls)
case mhd_TLS_MULTI_ROUTE_OPEN:
return mhd_tls_open_conn_has_cstm_tr (c_tls->data.openssl);
#endif
+#ifdef MHD_SUPPORT_MBEDTLS
+ case mhd_TLS_MULTI_ROUTE_MBED:
+ return mhd_tls_mbed_conn_has_cstm_tr (c_tls->data.mbedtls);
+#endif
case mhd_TLS_MULTI_ROUTE_NONE:
default:
mhd_UNREACHABLE ();
@@ -570,6 +671,10 @@ mhd_tls_multi_conn_has_data_in (struct mhd_TlsMultiConnData *restrict c_tls)
case mhd_TLS_MULTI_ROUTE_OPEN:
return mhd_tls_open_conn_has_data_in (c_tls->data.openssl);
#endif
+#ifdef MHD_SUPPORT_MBEDTLS
+ case mhd_TLS_MULTI_ROUTE_MBED:
+ return mhd_tls_mbed_conn_has_data_in (c_tls->data.mbedtls);
+#endif
case mhd_TLS_MULTI_ROUTE_NONE:
default:
mhd_UNREACHABLE ();
@@ -607,6 +712,14 @@ mhd_tls_multi_conn_send (struct mhd_TlsMultiConnData *restrict c_tls,
push_data,
sent);
#endif
+#ifdef MHD_SUPPORT_MBEDTLS
+ case mhd_TLS_MULTI_ROUTE_MBED:
+ return mhd_tls_mbed_conn_send (c_tls->data.mbedtls,
+ buf_size,
+ buf,
+ push_data,
+ sent);
+#endif
case mhd_TLS_MULTI_ROUTE_NONE:
default:
mhd_UNREACHABLE ();
@@ -638,6 +751,12 @@ mhd_tls_multi_conn_get_tls_sess (
tls_sess_out);
break;
#endif
+#ifdef MHD_SUPPORT_MBEDTLS
+ case mhd_TLS_MULTI_ROUTE_MBED:
+ mhd_tls_mbed_conn_get_tls_sess (c_tls->data.mbedtls,
+ tls_sess_out);
+ break;
+#endif
case mhd_TLS_MULTI_ROUTE_NONE:
default:
mhd_UNREACHABLE ();
@@ -663,6 +782,11 @@ mhd_tls_multi_conn_get_tls_ver (struct mhd_TlsMultiConnData *restrict c_tls,
return mhd_tls_open_conn_get_tls_ver (c_tls->data.openssl,
tls_ver_out);
#endif
+#ifdef MHD_SUPPORT_MBEDTLS
+ case mhd_TLS_MULTI_ROUTE_MBED:
+ return mhd_tls_mbed_conn_get_tls_ver (c_tls->data.mbedtls,
+ tls_ver_out);
+#endif
case mhd_TLS_MULTI_ROUTE_NONE:
default:
mhd_UNREACHABLE ();
@@ -685,6 +809,10 @@ mhd_tls_multi_conn_get_alpn_prot (struct mhd_TlsMultiConnData *restrict c_tls)
case mhd_TLS_MULTI_ROUTE_OPEN:
return mhd_tls_open_conn_get_alpn_prot (c_tls->data.openssl);
#endif
+#ifdef MHD_SUPPORT_MBEDTLS
+ case mhd_TLS_MULTI_ROUTE_MBED:
+ return mhd_tls_mbed_conn_get_alpn_prot (c_tls->data.mbedtls);
+#endif
case mhd_TLS_MULTI_ROUTE_NONE:
default:
mhd_UNREACHABLE ();
diff --git a/src/mhd2/tls_multi_funcs.h b/src/mhd2/tls_multi_funcs.h
@@ -163,7 +163,7 @@ mhd_tls_multi_conn_get_tls_size (struct mhd_TlsMultiDaemonData *restrict d_tls);
*/
MHD_INTERNAL bool
mhd_tls_multi_conn_init (const struct mhd_TlsMultiDaemonData *restrict d_tls,
- const struct mhd_ConnSocket *sk,
+ struct mhd_ConnSocket *sk,
struct mhd_TlsMultiConnData *restrict c_tls)
MHD_FN_MUST_CHECK_RESULT_ MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_OUT_ (3);
diff --git a/src/mhd2/tls_multi_tls_lib.h b/src/mhd2/tls_multi_tls_lib.h
@@ -77,6 +77,13 @@ enum mhd_TlsMultiRoute
*/
mhd_TLS_MULTI_ROUTE_OPEN
#endif
+#ifdef MHD_SUPPORT_MBEDTLS
+ ,
+ /**
+ * Use OpenSSL backend
+ */
+ mhd_TLS_MULTI_ROUTE_MBED
+#endif
};
#endif /* ! MHD_TLS_MULTI_TLS_LIB_H */