Implemented initialisation of connection's GnuTLS data

This commit is contained in:
Evgeny Grin (Karlson2k)
2024-11-24 20:54:09 +03:00
parent 9cccdd11eb
commit ca88e99ffd
9 changed files with 396 additions and 64 deletions
+8 -3
View File
@@ -1284,7 +1284,12 @@ enum MHD_FIXED_ENUM_MHD_SET_ MHD_StatusCode
/**
* Failed to initialise TLS context for the daemon
*/
MHD_SC_DAEMON_TLS_INIT_FAILED = 51200
MHD_SC_TLS_DAEMON_INIT_FAILED = 51200
,
/**
* Failed to initialise TLS context for the new connection
*/
MHD_SC_TLS_CONNECTION_INIT_FAILED = 51201
,
/**
* Something wrong in the internal MHD logic.
@@ -4707,8 +4712,8 @@ MHD_FN_PAR_NONNULL_ (1);
* @param addrlen number of bytes in @a addr
* @param connection_cntx meta data the application wants to
* associate with the new connection object
* @return #MHD_SC_OK on success
* error on failure
* @return #MHD_SC_OK on success,
* error on failure (the @a client_socket is closed)
* @ingroup specialized
*/
MHD_EXTERN_ enum MHD_StatusCode
+2 -2
View File
@@ -259,8 +259,8 @@ MHD_FN_PAR_NONNULL_ (1);
* @param addrlen number of bytes in @a addr
* @param connection_cntx meta data the application wants to
* associate with the new connection object
* @return #MHD_SC_OK on success
* error on failure
* @return #MHD_SC_OK on success,
* error on failure (the @a client_socket is closed)
* @ingroup specialized
*/
MHD_EXTERN_ enum MHD_StatusCode
+6 -1
View File
@@ -1284,7 +1284,12 @@ enum MHD_FIXED_ENUM_MHD_SET_ MHD_StatusCode
/**
* Failed to initialise TLS context for the daemon
*/
MHD_SC_DAEMON_TLS_INIT_FAILED = 51200
MHD_SC_TLS_DAEMON_INIT_FAILED = 51200
,
/**
* Failed to initialise TLS context for the new connection
*/
MHD_SC_TLS_CONNECTION_INIT_FAILED = 51201
,
/**
* Something wrong in the internal MHD logic.
+130 -52
View File
@@ -67,6 +67,10 @@
#include "response_destroy.h"
#include "conn_mark_ready.h"
#ifdef MHD_ENABLE_HTTPS
# include "mhd_tls_funcs.h"
#endif
#include "mhd_public_api.h"
@@ -139,12 +143,14 @@ notify_app_conn (struct MHD_Daemon *restrict daemon,
* @param sk_spipe_supprs indicate that the @a client_socket has
* set SIGPIPE suppression
* @param sk_is_nonip _MHD_YES if this is not a TCP/IP socket
* @return pointer to the connection on success, NULL if this daemon could
* not handle the connection (i.e. malloc failed, etc).
* The socket will be closed in case of error; 'errno' is
* set to indicate further details about the error.
* @param[out] conn_out the pointer to variable to be set to the address
* of newly allocated connection structure
* @return #MHD_SC_OK on success,
* error on failure (the @a client_socket is closed)
*/
static enum MHD_StatusCode
static MHD_FN_MUST_CHECK_RESULT_
MHD_FN_PAR_NONNULL_ (1)
MHD_FN_PAR_NONNULL_ (9) MHD_FN_PAR_OUT_ (9) enum MHD_StatusCode
new_connection_prepare_ (struct MHD_Daemon *restrict daemon,
MHD_Socket client_socket,
const struct sockaddr_storage *restrict addr,
@@ -155,62 +161,117 @@ new_connection_prepare_ (struct MHD_Daemon *restrict daemon,
enum mhd_Tristate sk_is_nonip,
struct MHD_Connection **restrict conn_out)
{
struct MHD_Connection *connection;
struct MHD_Connection *c;
enum MHD_StatusCode ret;
size_t tls_data_size;
ret = MHD_SC_OK;
*conn_out = NULL;
if (NULL == (connection = mhd_calloc (1, sizeof (struct MHD_Connection))))
tls_data_size = 0;
#ifdef MHD_ENABLE_HTTPS
if (mhd_D_HAS_TLS (daemon))
tls_data_size = mhd_tls_conn_get_tls_size ();
#endif
c = mhd_calloc (1, sizeof (struct MHD_Connection) + tls_data_size);
if (NULL == c)
{
mhd_LOG_MSG (daemon, MHD_SC_CONNECTION_MALLOC_FAILURE,
mhd_LOG_MSG (daemon, \
MHD_SC_CONNECTION_MALLOC_FAILURE, \
"Failed to allocate memory for the new connection");
mhd_socket_close (client_socket);
return MHD_SC_CONNECTION_MALLOC_FAILURE;
}
if (! external_add)
{
connection->sk.state.corked = mhd_T_NO;
connection->sk.state.nodelay = mhd_T_NO;
ret = MHD_SC_CONNECTION_MALLOC_FAILURE;
}
else
{
connection->sk.state.corked = mhd_T_MAYBE;
connection->sk.state.nodelay = mhd_T_MAYBE;
}
#ifdef MHD_ENABLE_HTTPS
if (0 != tls_data_size)
c->tls = (struct mhd_TlsConnData *) (c + 1);
# ifndef HAVE_NULL_PTR_ALL_ZEROS
else
c->tls = NULL;
# endif
#endif
if (0 < addrlen)
{
if (NULL == (connection->sk.addr.data = malloc (addrlen)))
if (! external_add)
{
mhd_LOG_MSG (daemon, MHD_SC_CONNECTION_MALLOC_FAILURE,
"Failed to allocate memory for the new connection");
mhd_socket_close (client_socket);
free (connection);
return MHD_SC_CONNECTION_MALLOC_FAILURE;
c->sk.state.corked = mhd_T_NO;
c->sk.state.nodelay = mhd_T_NO;
}
memcpy (connection->sk.addr.data,
addr,
addrlen);
}
else
connection->sk.addr.data = NULL;
connection->sk.addr.size = addrlen;
connection->sk.fd = client_socket;
connection->sk.props.is_nonblck = non_blck;
connection->sk.props.is_nonip = sk_is_nonip;
connection->sk.props.has_spipe_supp = sk_spipe_supprs;
else
{
c->sk.state.corked = mhd_T_MAYBE;
c->sk.state.nodelay = mhd_T_MAYBE;
}
if (0 < addrlen)
{
c->sk.addr.data = (struct sockaddr_storage *) malloc (addrlen);
if (NULL == c->sk.addr.data)
{
mhd_LOG_MSG (daemon, \
MHD_SC_CONNECTION_MALLOC_FAILURE, \
"Failed to allocate memory for the new connection");
ret = MHD_SC_CONNECTION_MALLOC_FAILURE;
}
else
memcpy (c->sk.addr.data,
addr,
addrlen);
}
else
c->sk.addr.data = NULL;
if (MHD_SC_OK == ret)
{
c->sk.addr.size = addrlen;
c->sk.fd = client_socket;
c->sk.props.is_nonblck = non_blck;
c->sk.props.is_nonip = sk_is_nonip;
c->sk.props.has_spipe_supp = sk_spipe_supprs;
#ifdef MHD_USE_THREADS
mhd_thread_handle_ID_set_invalid (&connection->tid);
mhd_thread_handle_ID_set_invalid (&c->tid);
#endif /* MHD_USE_THREADS */
connection->daemon = daemon;
connection->connection_timeout_ms = daemon->conns.cfg.timeout;
connection->event_loop_info = MHD_EVENT_LOOP_INFO_RECV;
if (0 != connection->connection_timeout_ms)
connection->last_activity = mhd_monotonic_msec_counter ();
c->daemon = daemon;
c->connection_timeout_ms = daemon->conns.cfg.timeout;
c->event_loop_info = MHD_EVENT_LOOP_INFO_RECV;
// TODO: init TLS
*conn_out = connection;
if (0 != tls_data_size)
{
if (! mhd_tls_conn_init (daemon->tls,
&(c->sk),
c->tls))
{
mhd_LOG_MSG (daemon, \
MHD_SC_TLS_CONNECTION_INIT_FAILED, \
"Failed to initialise TLS context for " \
"the new connection");
ret = MHD_SC_TLS_CONNECTION_INIT_FAILED;
}
#ifndef NDEBUG
else
c->dbg.tls_inited = true;
#endif
}
return MHD_SC_OK;
if (MHD_SC_OK == ret)
{
if (0 != c->connection_timeout_ms)
c->last_activity = mhd_monotonic_msec_counter ();
*conn_out = c;
return MHD_SC_OK; /* Success exit point */
}
/* Below is a cleanup path */
if (NULL != c->sk.addr.data)
free (c->sk.addr.data);
}
free (c);
}
mhd_socket_close (client_socket);
mhd_assert (MHD_SC_OK != ret);
return ret; /* Failure exit point */
}
@@ -356,7 +417,10 @@ new_connection_process_ (struct MHD_Daemon *restrict daemon,
}
/* Free resources allocated before the call of this functions */
// TODO: TLS support
#ifdef MHD_ENABLE_HTTPS
if (mhd_C_HAS_TLS (connection))
mhd_tls_conn_deinit (connection->tls);
#endif
// TODO: per IP limit
@@ -385,10 +449,8 @@ new_connection_process_ (struct MHD_Daemon *restrict daemon,
* @param sk_spipe_supprs indicate that the @a client_socket has
* set SIGPIPE suppression
* @param sk_is_nonip _MHD_YES if this is not a TCP/IP socket
* @return #MHD_YES on success, #MHD_NO if this daemon could
* not handle the connection (i.e. malloc failed, etc).
* The socket will be closed in any case; 'errno' is
* set to indicate further details about the error.
* @return #MHD_SC_OK on success,
* error on failure (the @a client_socket is closed)
*/
static enum MHD_StatusCode
internal_add_connection (struct MHD_Daemon *daemon,
@@ -975,6 +1037,22 @@ mhd_conn_close_final (struct MHD_Connection *restrict c)
mhd_assert (c != mhd_DLINKEDL_GET_FIRST (&(c->daemon->conns), all_conn));
mhd_assert (c != mhd_DLINKEDL_GET_LAST (&(c->daemon->conns), all_conn));
#ifdef MHD_ENABLE_HTTPS
if (mhd_C_HAS_TLS (c))
{
mhd_assert (mhd_D_HAS_TLS (c->daemon));
mhd_assert (c->dbg.tls_inited);
mhd_tls_conn_deinit (c->tls);
}
# ifndef NDEBUG
else
{
mhd_assert (! mhd_D_HAS_TLS (c->daemon));
mhd_assert (! c->dbg.tls_inited);
}
# endif
#endif
if (NULL != c->sk.addr.data)
free (c->sk.addr.data);
mhd_socket_close (c->sk.fd);
+26
View File
@@ -56,6 +56,10 @@
#include "mhd_public_api.h"
#ifdef MHD_ENABLE_HTTPS
# include "mhd_tls_choice.h" /* For the TLS struct forward declaration */
#endif
/**
* Minimum reasonable size by which MHD tries to increment read/write buffers.
* We usually begin with half the available pool space for the
@@ -356,6 +360,7 @@ struct mhd_ConnDebugData
bool closing_started;
bool pre_cleaned;
bool removed_from_daemon;
bool tls_inited;
};
/**
@@ -400,6 +405,16 @@ struct MHD_Connection
*/
struct mhd_ConnSocket sk;
#ifdef MHD_ENABLE_HTTPS
/**
* Connection-specific TLS data.
* NULL if TLS is not used (plain HTTP connection).
* Allocated (and freed) together with struct MHD_Connection, cannot be
* deallocated separately.
*/
struct mhd_TlsConnData *tls;
#endif
/**
* 'true' if connection is in 'process ready' list,
* 'false' otherwise
@@ -596,5 +611,16 @@ struct MHD_Connection
#endif
};
#ifdef MHD_ENABLE_HTTPS
/**
* Returns non-zero if connection has TLS enabled or zero otherwise
*/
# define mhd_C_HAS_TLS(c) (((c)->tls) ? (! 0) : (0))
#else
/**
* Returns non-zero if connection has TLS enabled or zero otherwise
*/
# define mhd_C_HAS_TLS(c) (0)
#endif
#endif /* ! MHD_CONNECTION_H */
+31
View File
@@ -87,6 +87,37 @@
mhd_TLS_FUNC (_daemon_deinit)((d_tls))
/* ** Connection initialisation / de-initialisation ** */
/**
* Get size size of the connection's TLS settings
*/
#define mhd_tls_conn_get_tls_size() \
mhd_TLS_FUNC (_conn_get_tls_size)()
/**
* 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
*/
#define mhd_tls_conn_init(d_tls,sk,c_tls) \
mhd_TLS_FUNC (_conn_init)((d_tls),(sk),(c_tls))
/**
* De-initialise connection TLS settings.
* The provided pointer is not freed/deallocated.
* @param c_tls the initialised connection TLS settings
*/
#define mhd_tls_conn_deinit(c_tls) \
mhd_TLS_FUNC (_conn_deinit)((c_tls))
/* ** General information function ** */
/**
* Result of TLS backend availability check
*/
+133 -6
View File
@@ -31,7 +31,9 @@
#include <string.h>
#include "mhd_socket_type.h"
#include "mhd_str_types.h"
#include "mhd_str_macros.h"
#include "mhd_arr_num_elems.h"
@@ -39,9 +41,12 @@
#include "sys_malloc.h"
#include "mhd_assert.h"
#include "mhd_conn_socket.h"
#include "tls_gnu_tls_lib.h"
#include "tls_gnu_daemon_data.h"
#include "tls_gnu_conn_data.h"
#include "tls_gnu_funcs.h"
#include "daemon_options.h"
@@ -207,9 +212,9 @@ daemon_init_credentials (struct MHD_Daemon *restrict d,
if (GNUTLS_E_SUCCESS !=
gnutls_certificate_allocate_credentials (&(d_tls->cred)))
{
mhd_LOG_MSG (d, MHD_SC_DAEMON_TLS_INIT_FAILED, \
mhd_LOG_MSG (d, MHD_SC_TLS_DAEMON_INIT_FAILED, \
"Failed to initialise TLS credentials for the daemon");
return MHD_SC_DAEMON_TLS_INIT_FAILED;
return MHD_SC_TLS_DAEMON_INIT_FAILED;
}
// TODO: Support multiple certificates
@@ -247,10 +252,10 @@ daemon_init_credentials (struct MHD_Daemon *restrict d,
{
if (! daemon_init_dh_data (d_tls))
{
mhd_LOG_MSG (d, MHD_SC_DAEMON_TLS_INIT_FAILED, \
mhd_LOG_MSG (d, MHD_SC_TLS_DAEMON_INIT_FAILED, \
"Failed to initialise Diffie-Hellman parameters " \
"for the daemon");
ret = MHD_SC_DAEMON_TLS_INIT_FAILED;
ret = MHD_SC_TLS_DAEMON_INIT_FAILED;
}
else
return MHD_SC_OK;
@@ -337,9 +342,9 @@ daemon_init_priorities_cache (struct MHD_Daemon *restrict d,
if (i < mhd_ARR_NUM_ELEMS (tlsgnulib_base_priorities))
return MHD_SC_OK; /* Success exit point */
mhd_LOG_MSG (d, MHD_SC_DAEMON_TLS_INIT_FAILED, \
mhd_LOG_MSG (d, MHD_SC_TLS_DAEMON_INIT_FAILED, \
"Failed to initialise TLS priorities cache");
return MHD_SC_DAEMON_TLS_INIT_FAILED;
return MHD_SC_TLS_DAEMON_INIT_FAILED;
}
@@ -409,3 +414,125 @@ mhd_tls_gnu_daemon_deinit (struct mhd_TlsGnuDaemonData *restrict d_tls)
daemon_deinit_credentials (d_tls);
free (d_tls);
}
/* ** Connection initialisation ** */
MHD_INTERNAL size_t
mhd_tls_gnu_conn_get_tls_size (void)
{
return sizeof (struct mhd_TlsGnuConnData);
}
MHD_INTERNAL MHD_FN_MUST_CHECK_RESULT_ MHD_FN_PAR_NONNULL_ALL_
MHD_FN_PAR_OUT_ (3) bool
mhd_tls_gnu_conn_init (const struct mhd_TlsGnuDaemonData *restrict d_tls,
const struct mhd_ConnSocket *sk,
struct mhd_TlsGnuConnData *restrict c_tls)
{
unsigned int c_flags;
int res;
c_flags = GNUTLS_SERVER;
#if GNUTLS_VERSION_NUMBER >= 0x030000
/* Note: the proper support for the blocking sockets may require use of
gnutls_handshake_set_timeout() and
gnutls_transport_set_pull_timeout_function() (the latter is not actually
required for the modern GnuTLS versions at least) */
if (sk->props.is_nonblck)
c_flags |= GNUTLS_NONBLOCK;
#endif
#ifdef mhd_TLS_GNU_HAS_NO_SIGNAL
c_flags |= GNUTLS_NO_SIGNAL;
#endif
if (GNUTLS_E_SUCCESS !=
gnutls_init (&(c_tls->sess),
c_flags))
return false;
#if GNUTLS_VERSION_NUMBER >= 0x030100
if (! sk->props.is_nonblck)
gnutls_handshake_set_timeout (c_tls->sess,
GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT);
#endif
#if ! defined(mhd_TLS_GNU_NULL_PRIO_CACHE_MEANS_DEF_PRIORITY)
mhd_assert (NULL != d_tls->pri_cache);
#else
if (NULL == d_tls->pri_cache)
res = gnutls_set_default_priority (c_tls->sess);
else
#endif
res = gnutls_priority_set (c_tls->sess,
d_tls->pri_cache);
if (GNUTLS_E_SUCCESS == res)
{
if (GNUTLS_E_SUCCESS ==
gnutls_credentials_set (c_tls->sess,
GNUTLS_CRD_CERTIFICATE,
d_tls->cred))
{
#ifdef mhd_TLS_GNU_HAS_TRANSP_SET_INT
if (sizeof(int) == sizeof(MHD_Socket))
gnutls_transport_set_int (c_tls->sess,
(int) sk->fd);
#endif /* mhd_TLS_GNU_HAS_TRANSP_SET_INT */
gnutls_transport_set_ptr (c_tls->sess,
(void *) sk->fd);
/* The basic TLS session properties has been set.
The rest is optional settings. */
#ifdef mhd_TLS_GNU_HAS_ALPN
if (1)
{
static const char alpn_http_1_0[] = "http/1.0"; /* Registered value for HTTP/1.0 */
static const char alpn_http_1_1[] = "http/1.1"; /* Registered value for HTTP/1.1 */
# if 0 /* Disabled code */
static const char alpn_http_2[] = "h2"; /* Registered value for HTTP/2 over TLS */
static const char alpn_http_3[] = "h3"; /* Registered value for HTTP/3 */
# endif
gnutls_datum_t prots[] = {
{ mhd_DROP_CONST (alpn_http_1_1), mhd_SSTR_LEN (alpn_http_1_1) }
,
{ mhd_DROP_CONST (alpn_http_1_0), mhd_SSTR_LEN (alpn_http_1_0) }
};
unsigned int alpn_flags;
int alpn_res;
alpn_flags = 0;
# if 0
alpn_flags |= GNUTLS_ALPN_SERVER_PRECEDENCE;
# endif
alpn_res =
gnutls_alpn_set_protocols (c_tls->sess,
prots,
(unsigned int) mhd_ARR_NUM_ELEMS (prots),
alpn_flags);
(void) alpn_res; /* Ignore any possible ALPN set errors */
}
#endif /* mhd_TLS_GNU_HAS_ALPN */
return true; /* Success exit point */
}
/* Below is a clean-up code path */
}
gnutls_deinit (c_tls->sess);
return false; /* Failure exit point */
}
/**
* De-initialise connection TLS settings.
* The provided pointer is not freed/deallocated.
* @param c_tls the initialised connection TLS settings
*/
MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ void
mhd_tls_gnu_conn_deinit (struct mhd_TlsGnuConnData *restrict c_tls)
{
mhd_assert (NULL != c_tls->sess);
gnutls_deinit (c_tls->sess);
}
+38
View File
@@ -33,6 +33,9 @@
#error This header can be used only if GnuTLS is enabled
#endif
#include "sys_bool_type.h"
#include "sys_base_types.h"
#include "mhd_status_code_int.h"
/**
@@ -102,4 +105,39 @@ MHD_INTERNAL void
mhd_tls_gnu_daemon_deinit (struct mhd_TlsGnuDaemonData *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_gnu_conn_get_tls_size (void);
/**
* 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_gnu_conn_init (const struct mhd_TlsGnuDaemonData *restrict d_tls,
const struct mhd_ConnSocket *sk,
struct mhd_TlsGnuConnData *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_gnu_conn_deinit (struct mhd_TlsGnuConnData *restrict c_tls)
MHD_FN_PAR_NONNULL_ALL_;
#endif /* ! MHD_TLS_GNU_FUNCS_H */
+22
View File
@@ -100,4 +100,26 @@
# define mhd_TLS_GNU_SUPPORTS_MULTI_KEYWORDS_PRIORITY 1
#endif
#if GNUTLS_VERSION_NUMBER >= 0x030402
/**
* Defined if GNUTLS_NO_SIGNAL flag is available for gnutls_init() function
*/
# define mhd_TLS_GNU_HAS_NO_SIGNAL 1
#endif
#if GNUTLS_VERSION_NUMBER >= 0x030109
/**
* Defined if transport_set_int() function is available
*/
# define mhd_TLS_GNU_HAS_TRANSP_SET_INT 1
#endif
#if GNUTLS_VERSION_NUMBER >= 0x030200
/**
* Defined if gnutls_alpn_set_protocols() and
* gnutls_alpn_get_selected_protocol() function are available
*/
# define mhd_TLS_GNU_HAS_ALPN 1
#endif
#endif /* ! MHD_TLS_GNU_TLS_LIB_H */