Implemented OpenSSL TLS backend support

Multi-TLS is not implemented yet, so MHD works only when configured
--without-gnutls or --without-openssl.
Only single TLS backend is supported for now.
This commit is contained in:
Evgeny Grin (Karlson2k)
2024-11-28 15:26:24 +03:00
parent a13c8742f4
commit 455c083b56
12 changed files with 1891 additions and 41 deletions
+274 -32
View File
@@ -4867,6 +4867,13 @@ AM_CONDITIONAL([HAVE_POST_PARSER], [test "x$enable_postparser" != "xno"])
AC_MSG_RESULT([[$enable_postparser]])
have_gnutls=no
have_gnutls_pkgcfg=no
have_openssl=no
have_openssl_pkgcfg=no
AS_UNSET([MHD_TLS_LIB_CPPFLAGS])
AS_UNSET([MHD_TLS_LIB_LDFLAGS])
AS_UNSET([MHD_TLS_LIBDEPS])
MSG_TLS_BACKENDS="none"
# optional: HTTPS support. Enabled if GnuTLS is available.
AC_ARG_ENABLE([https],
@@ -4885,11 +4892,12 @@ AS_IF([test "x$enable_https" != "xno"],
[
AS_CASE([$with_gnutls],
[no],[
AC_MSG_RESULT([[GnuTLS disabled]])
have_gnutls="no"
AS_UNSET([GNUTLS_CPPFLAGS])
AS_UNSET([GNUTLS_CFLAGS])
AS_UNSET([GNUTLS_LDFLAGS])
AS_UNSET([GNUTLS_LIBS])
AC_MSG_RESULT([[GnuTLS disabled]])
],
[yes],[
AC_MSG_RESULT([[automatically, forced]])
@@ -4916,7 +4924,7 @@ AS_IF([test "x$enable_https" != "xno"],
GNUTLS_LDFLAGS="-L$with_gnutls/lib"
GNUTLS_LIBS="-lgnutls"
],
[AC_MSG_ERROR([can't find usable libgnutls at specified prefix $with_gnutls])],
[AC_MSG_ERROR([cannot find usable libgnutls at specified prefix $with_gnutls])],
[-lgnutls]
)
CPPFLAGS="${CPPFLAGS_ac} ${user_CPPFLAGS}"
@@ -4931,7 +4939,6 @@ AS_IF([test "x$enable_https" != "xno"],
[
PKG_CHECK_MODULES([GNUTLS], [[gnutls]],
[
have_gnutls_pkgcfg='yes'
CPPFLAGS="${CPPFLAGS_ac} $GNUTLS_CFLAGS ${user_CPPFLAGS}"
# A simple check for the working header and the library
MHD_CHECK_FUNC([gnutls_check_version],
@@ -4944,7 +4951,8 @@ AS_IF([test "x$enable_https" != "xno"],
return 3;
],
[
have_gnutls=yes
have_gnutls="yes"
have_gnutls_pkgcfg="yes"
# GNUTLS_CFLAGS is actually CPPFLAGS
GNUTLS_CPPFLAGS="$GNUTLS_CFLAGS"
AS_UNSET([GNUTLS_CFLAGS])
@@ -4953,9 +4961,9 @@ AS_IF([test "x$enable_https" != "xno"],
],
[
AS_VAR_IF([with_gnutls],["yes"],
[AC_MSG_ERROR([can't find usable libgnutls at specified prefix $with_gnutls])]
[AC_MSG_ERROR([cannot find usable libgnutls])]
)
AC_MSG_WARN([pkg-config reports that GnuTLS is present, but GnuTLS can't be used])
AC_MSG_WARN([pkg-config reports that GnuTLS is present, but GnuTLS cannot be used])
AS_UNSET([GNUTLS_CPPFLAGS])
AS_UNSET([GNUTLS_CFLAGS])
AS_UNSET([GNUTLS_LDFLAGS])
@@ -4966,7 +4974,7 @@ AS_IF([test "x$enable_https" != "xno"],
],
[
# check for GnuTLS at default paths
have_gnutls_pkgcfg='no'
have_gnutls_pkgcfg="no"
# A simple check for the working header and the library
MHD_CHECK_FUNC([gnutls_check_version],
[[
@@ -4986,7 +4994,7 @@ AS_IF([test "x$enable_https" != "xno"],
],
[
AS_VAR_IF([with_gnutls],["yes"],
[AC_MSG_ERROR([can't find usable libgnutls])]
[AC_MSG_ERROR([cannot find usable libgnutls])]
)
AS_UNSET([GNUTLS_CPPFLAGS])
AS_UNSET([GNUTLS_CFLAGS])
@@ -5003,10 +5011,7 @@ AS_IF([test "x$enable_https" != "xno"],
[
AC_CACHE_CHECK([[whether GnuTLS is modern enough]], [mhd_cv_gnutls_ver_ok],
[
SAVE_LIBS="$LIBS"
CPPFLAGS="${CPPFLAGS_ac} ${GNUTLS_CPPFLAGS} ${user_CPPFLAGS}"
LDFLAGS="${LDFLAGS_ac} ${GNUTLS_LDFLAGS} ${user_LDFLAGS}"
LIBS="$GNUTLS_LIBS $LIBS"
AC_COMPILE_IFELSE(
[
AC_LANG_PROGRAM(
@@ -5022,20 +5027,27 @@ choke me now
]]
)
],
[[mhd_cv_gnutls_ver_ok='yes']], [[mhd_cv_gnutls_ver_ok='no']]
[[mhd_cv_gnutls_ver_ok="yes"]], [[mhd_cv_gnutls_ver_ok="no"]]
)
LIBS="$SAVE_LIBS"
LDFLAGS="${LDFLAGS_ac} ${user_LDFLAGS}"
CPPFLAGS="${CPPFLAGS_ac} ${user_CPPFLAGS}"
]
)
AS_VAR_IF([mhd_cv_gnutls_ver_ok],["yes"],[:],[have_gnutls="no"])
AS_VAR_IF([mhd_cv_gnutls_ver_ok],["yes"],[:],
[
have_gnutls="no"
AS_VAR_IF([with_gnutls],["yes"],
[AC_MSG_ERROR([cannot find usable libgnutls])]
)
]
)
]
)
AS_VAR_IF([have_gnutls],["yes"],
[:],
[
have_gnutls="no"
have_gnutls_pkgcfg="no"
AS_UNSET([GNUTLS_CPPFLAGS])
AS_UNSET([GNUTLS_CFLAGS])
AS_UNSET([GNUTLS_LDFLAGS])
@@ -5044,23 +5056,222 @@ choke me now
)
AS_VAR_IF([have_gnutls],["yes"],
AC_MSG_CHECKING([[how to find OpenSSL library]])
AC_ARG_WITH([[openssl]],
[
AS_HELP_STRING([[--with-openssl[=PRFX]]],
[use OpenSSL for HTTPS support, optional PRFX overrides pkg-config data for OpenSSL headers (PRFX/include) and libs (PRFX/lib)])
],
[
AS_CASE([$with_openssl],
[no],[
have_openssl="no"
AC_MSG_RESULT([[OpenSSL disabled]])
AS_UNSET([OPENSSL_CPPFLAGS])
AS_UNSET([OPENSSL_CFLAGS])
AS_UNSET([OPENSSL_LDFLAGS])
AS_UNSET([OPENSSL_LIBS])
],
[yes],[
AC_MSG_RESULT([[automatically, forced]])
],
[
AC_MSG_RESULT([[-I$with_openssl/include -L$with_openssl/lib -lssl -lcrypto]])
LDFLAGS="${LDFLAGS_ac} -L$with_openssl/lib ${user_LDFLAGS}"
CPPFLAGS="${CPPFLAGS_ac} -I$with_openssl/include ${user_CPPFLAGS}"
have_openssl_pkgcfg="no"
# A simple check for the working header and the library
MHD_CHECK_FUNC([SSL_CTX_new],
[[
#include <openssl/ssl.h>
]],
[[
SSL_CTX_free(SSL_CTX_new(TLS_server_method()));
]],
[
have_openssl="yes"
OPENSSL_CPPFLAGS="-I$with_openssl/include"
AS_UNSET([OPENSSL_CFLAGS])
OPENSSL_LDFLAGS="-L$with_openssl/lib"
OPENSSL_LIBS="-lssl -lcrypto"
],
[AC_MSG_ERROR([cannot find usable OpenSSL library at specified prefix $with_openssl])],
[-lssl -lcrypto]
)
CPPFLAGS="${CPPFLAGS_ac} ${user_CPPFLAGS}"
CFLAGS="${CFLAGS_ac} ${user_CFLAGS}"
LDFLAGS="${LDFLAGS_ac} ${user_LDFLAGS}"
])
],
[AC_MSG_RESULT([[automatically]])]
)
AS_IF([test "x$with_openssl" != "xno" && test "x$have_openssl" != "xyes"],
[
PKG_CHECK_MODULES([OPENSSL], [[openssl >= 3.0]],
[
CPPFLAGS="${CPPFLAGS_ac} $OPENSSL_CFLAGS ${user_CPPFLAGS}"
# A simple check for the working header and the library
MHD_CHECK_FUNC([SSL_CTX_new],
[[
#include <openssl/ssl.h>
]],
[[
SSL_CTX_free(SSL_CTX_new(TLS_server_method()));
]],
[
have_openssl=yes
have_openssl_pkgcfg='yes'
# OPENSSL_CFLAGS is actually CPPFLAGS
OPENSSL_CPPFLAGS="$OPENSSL_CFLAGS"
AS_UNSET([OPENSSL_CFLAGS])
# OPENSSL_LIBS is a combination of LDFLAGS and LIBS
AS_UNSET([OPENSSL_LDFLAGS])
],
[
AS_VAR_IF([with_openssl],["yes"],
[AC_MSG_ERROR([cannot find usable OpenSSL library])]
)
AC_MSG_WARN([pkg-config reports that OpenSSL is present, but OpenSSL cannot be used])
AS_UNSET([OPENSSL_CPPFLAGS])
AS_UNSET([OPENSSL_CFLAGS])
AS_UNSET([OPENSSL_LDFLAGS])
AS_UNSET([OPENSSL_LIBS])
],
[$OPENSSL_LIBS]
)
],
[
# check for OpenSSL at default paths
have_openssl_pkgcfg="no"
# A simple check for the working header and the library
MHD_CHECK_FUNC([SSL_CTX_new],
[[
#include <openssl/ssl.h>
]],
[[
SSL_CTX_free(SSL_CTX_new(TLS_server_method()));
]],
[
have_openssl="yes"
AS_UNSET([OPENSSL_CPPFLAGS])
AS_UNSET([OPENSSL_CFLAGS])
AS_UNSET([OPENSSL_LDFLAGS])
OPENSSL_LIBS="-lssl -lcrypto"
],
[
AS_VAR_IF([with_openssl],["yes"],
[AC_MSG_ERROR([cannot find usable OpenSSL library])]
)
AS_UNSET([OPENSSL_CPPFLAGS])
AS_UNSET([OPENSSL_CFLAGS])
AS_UNSET([OPENSSL_LDFLAGS])
AS_UNSET([OPENSSL_LIBS])
],
[-lssl -lcrypto]
)
]
)
]
)
AS_VAR_IF([have_openssl],["yes"],
[
AC_CACHE_CHECK([[whether OpenSSL is modern enough]], [mhd_cv_openssl_ver_ok],
[
CPPFLAGS="${CPPFLAGS_ac} ${OPENSSL_CPPFLAGS} ${user_CPPFLAGS}"
AC_COMPILE_IFELSE(
[
AC_LANG_PROGRAM(
[[
#include <openssl/opensslv.h>
]],
[[
#ifndef OPENSSL_VERSION_PREREQ
#error OPENSSL_VERSION_PREREQ is not defined. OpenSSL is too old.
choke me now
#endif
#if !OPENSSL_VERSION_PREREQ(3,0)
#error OpenSSL version is too old and not suitable.
choke me now
#endif
]]
)
],
[[mhd_cv_openssl_ver_ok="yes"]], [[mhd_cv_openssl_ver_ok="no"]]
)
CPPFLAGS="${CPPFLAGS_ac} ${user_CPPFLAGS}"
]
)
AS_VAR_IF([mhd_cv_openssl_ver_ok],["yes"],[:],
[
have_openssl="no"
AS_VAR_IF([with_openssl],["yes"],
[AC_MSG_ERROR([cannot find usable OpenSSL library])]
)
]
)
]
)
AS_VAR_IF([have_openssl],["yes"],
[:],
[
have_openssl="no"
have_openssl_pkgcfg="no"
AS_UNSET([OPENSSL_CPPFLAGS])
AS_UNSET([OPENSSL_CFLAGS])
AS_UNSET([OPENSSL_LDFLAGS])
AS_UNSET([OPENSSL_LIBS])
]
)
AS_IF([test "x$have_gnutls" = "xyes" || test "x$have_openssl" = "xyes"],
[
enable_https="yes"
MSG_HTTPS="yes (using libgnutls)"
MSG_HTTPS="yes (single backend)"
MSG_TLS_BACKENDS=""
AS_VAR_IF([have_gnutls],["yes"],
[
AS_IF([test -n "${MSG_TLS_BACKENDS}"],
[
MSG_TLS_BACKENDS="${MSG_TLS_BACKENDS}, "
MSG_HTTPS="yes (multiple backends)"
]
)
AC_DEFINE([MHD_USE_GNUTLS],[1],[Define to '1' i][f GnuTLS library should be used])
MSG_TLS_BACKENDS="${MSG_TLS_BACKENDS}GnuTLS"
MHD_APPEND_FLAG_TO_VAR([MHD_TLS_LIB_CPPFLAGS],[$GNUTLS_CPPFLAGS])
MHD_APPEND_FLAG_TO_VAR([MHD_TLS_LIB_LDFLAGS],[$GNUTLS_LDFLAGS])
MHD_PREPEND_FLAG_TO_VAR([MHD_TLS_LIBDEPS],[$GNUTLS_LIBS])
]
)
AS_VAR_IF([have_openssl],["yes"],
[
AS_IF([test -n "${MSG_TLS_BACKENDS}"],
[
MSG_TLS_BACKENDS="${MSG_TLS_BACKENDS}, "
MSG_HTTPS="yes (multiple backends)"
]
)
AC_DEFINE([MHD_USE_OPENSSL],[1],[Define to '1' i][f OpenSSL library should be used])
MSG_TLS_BACKENDS="${MSG_TLS_BACKENDS}OpenSSL"
MHD_APPEND_FLAG_TO_VAR([MHD_TLS_LIB_CPPFLAGS],[$OPENSSL_CPPFLAGS])
MHD_APPEND_FLAG_TO_VAR([MHD_TLS_LIB_LDFLAGS],[$OPENSSL_LDFLAGS])
MHD_PREPEND_FLAG_TO_VAR([MHD_TLS_LIBDEPS],[$OPENSSL_LIBS])
]
)
AS_IF([test -z "$MSG_TLS_BACKENDS"],[AC_MSG_FAILURE([configure internal error: no TLS backends])])
AC_DEFINE([MHD_ENABLE_HTTPS],[1],[Define to '1' i][f HTTPS protocol should be enabled])
AC_DEFINE([MHD_USE_GNUTLS],[1],[Define to '1' i][f GnuTLS library should be used])
MHD_TLS_LIB_CPPFLAGS="$GNUTLS_CPPFLAGS"
MHD_TLS_LIB_LDFLAGS="$GNUTLS_LDFLAGS"
MHD_TLS_LIBDEPS="$GNUTLS_LIBS"
],
[
AS_VAR_IF([enable_https],["yes"],
[AC_MSG_ERROR([GniTLS library not found, HTTPS cannot be enabled])]
[AC_MSG_ERROR([no suitable TLS lib found, HTTPS cannot be enabled])]
)
enable_https="no"
MSG_HTTPS="no (lacking libgnutls)"
MSG_HTTPS="no (no suitable TLS lib found)"
MSG_TLS_BACKENDS="none"
]
)
],
@@ -5070,15 +5281,35 @@ choke me now
]
)
AC_MSG_CHECKING(whether to support HTTPS)
AS_VAR_IF([enable_https],["yes"],
[
AS_CASE([$MSG_HTTPS],[yes*],[:],
[AC_MSG_FAILURE([configure internal error: wrong MSG_HTTPS])]
)
],
[
enable_https="no"
MSG_TLS_BACKENDS="none"
AS_UNSET([MHD_TLS_LIB_CPPFLAGS])
AS_UNSET([MHD_TLS_LIB_LDFLAGS])
AS_UNSET([MHD_TLS_LIBDEPS])
AS_CASE([$MSG_HTTPS],[no*],[:],
[AC_MSG_FAILURE([configure internal error: wrong MSG_HTTPS])]
)
]
)
AC_MSG_RESULT([$MSG_HTTPS])
AM_CONDITIONAL([MHD_ENABLE_HTTPS], [test "x$enable_https" = "xyes"])
AM_CONDITIONAL([MHD_USE_GNUTLS], [[test "x$have_gnutls" = "xyes"]])
AC_SUBST([GNUTLS_CPPFLAGS])
AC_SUBST([GNUTLS_LDFLAGS])
AC_SUBST([GNUTLS_LIBS])
AM_CONDITIONAL([MHD_USE_OPENSSL], [[test "x$have_openssl" = "xyes"]])
AC_SUBST([OPENSSL_CPPFLAGS])
AC_SUBST([OPENSSL_LDFLAGS])
AC_SUBST([OPENSSL_LIBS])
AM_CONDITIONAL([MHD_ENABLE_HTTPS], [test "x$enable_https" = "xyes"])
AS_VAR_IF([have_gnutls], ["yes"],
[
@@ -7182,6 +7413,7 @@ AC_MSG_NOTICE([GNU libmicrohttpd ${PACKAGE_VERSION} Configuration Summary:
epoll support: ${enable_epoll=no}
sendfile used: ${found_sendfile}
HTTPS support: ${MSG_HTTPS}
TLS backends: ${MSG_TLS_BACKENDS}
Logging support: ${enable_log_messages}
Verbose auto replies: ${enable_http_messages}
Cookie parser: ${enable_cookie}
@@ -7207,13 +7439,23 @@ AC_MSG_NOTICE([GNU libmicrohttpd ${PACKAGE_VERSION} Configuration Summary:
Fuzzing tests: ${run_zzuf_tests_MSG=no}
])
AS_IF([test "x$enable_https" = "xyes"],
[AC_MSG_NOTICE([HTTPS subsystem configuration:
License : LGPL version 2.1 or any later version
])],
[AC_MSG_NOTICE([
License : LGPLv2.1+ or eCos
])])
licence_num="0"
AS_VAR_IF([have_gnutls],["yes"],
[AS_IF([test "2" -gt "$licence_num"],[licence_num="2"])]
)
AS_VAR_IF([have_openssl],["yes"],
[AS_IF([test "3" -gt "$licence_num"],[licence_num="3"])]
)
AS_CASE([$licence_num],
[0],[licence_descr="LGPLv2.1+ or eCos"],
[2],[licence_descr="LGPL version 2.1 or any later version"],
[3],[licence_descr="LGPL version 3.0 or any later version"],
[AC_MSG_ERROR(internal error: unexpected licence version)]
)
AC_MSG_NOTICE([
Licence: ${licence_descr}
])
AS_IF([test "x$enable_bauth" != "xyes" || \
test "x$enable_dauth" != "xyes" || \
+11 -3
View File
@@ -1296,6 +1296,11 @@ enum MHD_FIXED_ENUM_MHD_SET_ MHD_StatusCode
*/
MHD_SC_TLS_CONNECTION_INIT_FAILED = 51201
,
/**
* Warning about TLS backend configuration
*/
MHD_SC_TLS_LIB_CONF_WARNING = 51202
,
/**
* Failed to perform TLS handshake
*/
@@ -3345,14 +3350,12 @@ enum MHD_FIXED_ENUM_APP_SET_ MHD_UseStictLevel
enum MHD_FIXED_ENUM_APP_SET_ MHD_TlsBackend
{
/**
* Disable TLS, use plain TCP connections
* Disable TLS, use plain TCP connections (default)
*/
MHD_TLS_BACKEND_NONE = 0
,
/**
* Use best available TLS backend.
* Currently this is equivalent to GnuTLS (if TLS is enabled
* for MHD build).
*/
MHD_TLS_BACKEND_ANY = 1
,
@@ -3360,6 +3363,11 @@ enum MHD_FIXED_ENUM_APP_SET_ MHD_TlsBackend
* Use GnuTLS as TLS backend.
*/
MHD_TLS_BACKEND_GNUTLS = 2
,
/**
* Use OpenSSL as TLS backend.
*/
MHD_TLS_BACKEND_OPENSSL = 3
};
/**
+11 -3
View File
@@ -1296,6 +1296,11 @@ enum MHD_FIXED_ENUM_MHD_SET_ MHD_StatusCode
*/
MHD_SC_TLS_CONNECTION_INIT_FAILED = 51201
,
/**
* Warning about TLS backend configuration
*/
MHD_SC_TLS_LIB_CONF_WARNING = 51202
,
/**
* Failed to perform TLS handshake
*/
@@ -3345,14 +3350,12 @@ enum MHD_FIXED_ENUM_APP_SET_ MHD_UseStictLevel
enum MHD_FIXED_ENUM_APP_SET_ MHD_TlsBackend
{
/**
* Disable TLS, use plain TCP connections
* Disable TLS, use plain TCP connections (default)
*/
MHD_TLS_BACKEND_NONE = 0
,
/**
* Use best available TLS backend.
* Currently this is equivalent to GnuTLS (if TLS is enabled
* for MHD build).
*/
MHD_TLS_BACKEND_ANY = 1
,
@@ -3360,6 +3363,11 @@ enum MHD_FIXED_ENUM_APP_SET_ MHD_TlsBackend
* Use GnuTLS as TLS backend.
*/
MHD_TLS_BACKEND_GNUTLS = 2
,
/**
* Use OpenSSL as TLS backend.
*/
MHD_TLS_BACKEND_OPENSSL = 3
};
/**
+8
View File
@@ -117,6 +117,10 @@ tls_gnu_files = \
tls_gnu_tls_lib.h tls_gnu_daemon_data.h tls_gnu_conn_data.h \
tls_gnu_funcs.c tls_gnu_funcs.h
tls_open_files = \
tls_open_tls_lib.h tls_open_daemon_data.h tls_open_conn_data.h \
tls_open_funcs.c tls_open_funcs.h
if HAVE_POST_PARSER
libmicrohttpd2_la_SOURCES += $(post_parser_files)
endif
@@ -131,6 +135,10 @@ if MHD_ENABLE_HTTPS
if MHD_USE_GNUTLS
libmicrohttpd2_la_SOURCES += $(tls_gnu_files)
endif
if MHD_USE_OPENSSL
libmicrohttpd2_la_SOURCES += $(tls_open_files)
endif
endif
libmicrohttpd2_la_CPPFLAGS = \
+33 -1
View File
@@ -66,11 +66,30 @@
*/
#define mhd_TLS_GNU_IS_SUPPORTED() (! ! mhd_TLS_GNU_ENABLED)
/* * OpenSSL * */
#ifdef MHD_USE_OPENSSL
/**
* Defined to one if OpenSSL is enabled at build time or to zero if not enabled
*/
# define mhd_TLS_OPEN_ENABLED (1)
#else
/**
* Defined to one if GnuTLS is enabled at build time or to zero if not enabled
*/
# define mhd_TLS_OPEN_ENABLED (0)
#endif
/**
* Return non-zero if OpenSSL is supported
*/
#define mhd_TLS_OPEN_IS_SUPPORTED() (! ! mhd_TLS_GNU_ENABLED)
/**
* Defined to the number of enabled TLS backends
*/
#define mhd_TLS_NUM_BACKENDS \
(mhd_TLS_GNU_ENABLED /* + mhd_TLS_SOME_ENABLED */)
(mhd_TLS_GNU_ENABLED + mhd_TLS_OPEN_ENABLED)
#if mhd_TLS_NUM_BACKENDS == 0
#error At least one TLS backend must be enabled is this header is included
@@ -117,6 +136,19 @@
* The TLS back-end identifier for macro names
*/
# define mhd_TLS_MACRO_NAME_ID GNU
#elif defined(MHD_USE_OPENSSL)
/**
* The TLS back-end identifier for function names
*/
# define mhd_TLS_FUNC_NAME_ID open
/**
* The TLS back-end identifier for data names
*/
# define mhd_TLS_DATA_NAME_ID Open
/**
* The TLS back-end identifier for macro names
*/
# define mhd_TLS_MACRO_NAME_ID OPEN
#endif
+8 -2
View File
@@ -39,8 +39,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_other_is_inited_fine() */ ?
return (mhd_tls_gnu_is_inited_fine ()
|| mhd_tls_open_is_inited_fine ()) ?
mhd_TLS_BACKEND_AVAIL_OK :
mhd_TLS_BACKEND_AVAIL_NOT_AVAILABLE;
#ifdef MHD_USE_GNUTLS
@@ -48,6 +48,12 @@ mhd_tls_is_backend_available (struct DaemonOptions *s)
return mhd_tls_gnu_is_inited_fine () ?
mhd_TLS_BACKEND_AVAIL_OK :
mhd_TLS_BACKEND_AVAIL_NOT_AVAILABLE;
#endif
#ifdef MHD_USE_OPENSSL
if (MHD_TLS_BACKEND_OPENSSL == s->tls)
return mhd_tls_open_is_inited_fine () ?
mhd_TLS_BACKEND_AVAIL_OK :
mhd_TLS_BACKEND_AVAIL_NOT_AVAILABLE;
#endif
return mhd_TLS_BACKEND_AVAIL_NOT_SUPPORTED;
}
+9
View File
@@ -41,6 +41,8 @@
// TODO: Multi-TLS implementation
#elif defined(MHD_USE_GNUTLS)
# include "tls_gnu_funcs.h"
#elif defined(MHD_USE_OPENSSL)
# include "tls_open_funcs.h"
#endif
#ifndef MHD_USE_GNUTLS
@@ -50,6 +52,13 @@
# define mhd_tls_gnu_is_inited_fine() (0)
#endif
#ifndef MHD_USE_OPENSSL
/**
* Check whether OpenSSL backend was successfully initialised globally
*/
# define mhd_tls_open_is_inited_fine() (0)
#endif
/* ** Global initialisation / de-initialisation ** */
/**
+76
View File
@@ -0,0 +1,76 @@
/*
This file is part of GNU libmicrohttpd
Copyright (C) 2024 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.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/**
* @file src/mhd2/tls_open_conn_data.h
* @brief The definition of OpenSSL daemon-specific data structures
* @author Karlson2k (Evgeny Grin)
*/
#ifndef MHD_TLS_OPEN_CONN_DATA_H
#define MHD_TLS_OPEN_CONN_DATA_H 1
#include "mhd_sys_options.h"
#ifndef MHD_USE_OPENSSL
#error This header can be used only if GnuTLS is enabled
#endif
#include "tls_open_tls_lib.h"
#include "sys_bool_type.h"
#ifndef NDEBUG
struct mhd_TlsOpenConnDebug
{
unsigned int is_inited;
unsigned int is_tls_handshake_completed;
unsigned int is_failed;
};
#endif /* ! NDEBUG */
/**
* The structure with connection-specific GnuTLS data
*/
struct mhd_TlsOpenConnData
{
/**
* OpenSSL session data
*/
SSL *sess;
/**
* 'true' if sent TLS shutdown "alert"
*/
bool shut_tls_wr_sent;
/**
* 'true' if received EOF (the remote side initiated shutting down)
*/
bool shut_tls_wr_received;
#ifndef NDEBUG
/**
* Debugging data
*/
struct mhd_TlsOpenConnDebug dbg;
#endif /* ! NDEBUG */
};
#endif /* ! MHD_TLS_OPEN_CONN_DATA_H */
+56
View File
@@ -0,0 +1,56 @@
/*
This file is part of GNU libmicrohttpd
Copyright (C) 2024 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.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/**
* @file src/mhd2/tls_open_daemon_data.h
* @brief The definition of OpenSSL daemon-specific data structures
* @author Karlson2k (Evgeny Grin)
*/
#ifndef MHD_TLS_OPEN_DAEMON_DATA_H
#define MHD_TLS_OPEN_DAEMON_DATA_H 1
#include "mhd_sys_options.h"
#ifndef MHD_USE_OPENSSL
#error This header can be used only if GnuTLS is enabled
#endif
#include "tls_open_tls_lib.h"
/**
* The structure with daemon-specific GnuTLS data
*/
struct mhd_TlsOpenDaemonData
{
/**
* The library context.
* Thanks to the library context, daemons are isolated from each other and
* from any application context.
*/
OSSL_LIB_CTX *libctx;
/**
* The server context
*/
SSL_CTX *ctx;
};
#endif /* ! MHD_TLS_OPEN_DAEMON_DATA_H */
+1134
View File
@@ -0,0 +1,1134 @@
/*
This file is part of GNU libmicrohttpd
Copyright (C) 2024 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.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/**
* @file src/mhd2/tls_open_funcs.c
* @brief The implementation of GnuTLS wrapper functions
* @author Karlson2k (Evgeny Grin)
*/
#include "mhd_sys_options.h"
#include "sys_bool_type.h"
#include "sys_base_types.h"
#include <string.h>
#include "compat_calloc.h"
#include "sys_malloc.h"
#include "mhd_assert.h"
#include "mhd_conn_socket.h"
#include "tls_open_tls_lib.h"
#include "tls_open_daemon_data.h"
#include "tls_open_conn_data.h"
#include "tls_open_funcs.h"
#include "daemon_options.h"
#include "daemon_logger.h"
#include "mhd_public_api.h"
#ifdef mhd_TLS_OPEN_DH_PARAMS_NEEDS_PKCS3
# include "tls_dh_params.h"
#endif
#ifdef mhd_USE_TLS_DEBUG_MESSAGES
# include <stdio.h> /* For TLS debug printing */
#endif
#ifdef mhd_USE_TLS_DEBUG_MESSAGES
static MHD_FN_PAR_NONNULL_ (1) int
mhd_tls_open_dbg_print_errs (const char *msg,
size_t msg_len,
void *cls)
{
int ret;
int print_size = (int) msg_len;
(void) cls; /* Not used */
if ((print_size < 0) ||
(msg_len != (unsigned int) print_size))
print_size = (int) ((~((unsigned int) 0u)) >> 1);
ret = fprintf (stderr,
"## OpenSSL error: %.*s\n",
print_size, msg);
(void) fflush (stderr);
return ret;
}
# define mhd_DBG_PRINT_TLS_ERRS() \
ERR_print_errors_cb (&mhd_tls_open_dbg_print_errs, NULL)
#else
# define mhd_DBG_PRINT_TLS_ERRS() ERR_clear_error ()
#endif
/* ** Global initialisation / de-initialisation ** */
static bool openssl_lib_inited = false;
MHD_INTERNAL void
mhd_tls_open_global_init_once (void)
{
const unsigned long ver_num = OpenSSL_version_num ();
/* Make sure that used shared OpenSSL library has least the same version as
MHD was configured for. Fail if the version is earlier. */
openssl_lib_inited = ((0x900000UL < ver_num) /* Versions before 3.0 */
&& (OPENSSL_VERSION_NUMBER <= ver_num));
/* The call of OPENSSL_init_ssl() typically not needed, but it won't hurt
if library was initialised automatically.
In some exotic situations automatic initialisation could fail, and
this call would make sure that the library is initialised before used. */
openssl_lib_inited = openssl_lib_inited
&& (0 < OPENSSL_init_ssl (0, NULL));
}
MHD_INTERNAL bool
mhd_tls_open_is_inited_fine (void)
{
return openssl_lib_inited;
}
/* ** Daemon initialisation / de-initialisation ** */
/**
* Check application-provided daemon TLS settings
* @param d the daemon handle
* @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_sessings (struct MHD_Daemon *restrict d,
struct DaemonOptions *restrict s)
{
mhd_assert (MHD_TLS_BACKEND_NONE != s->tls);
mhd_assert ((MHD_TLS_BACKEND_GNUTLS == 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);
return MHD_SC_OK;
}
/* Helper to prevent password prompts in terminal */
static int
null_passwd_cb (char *buf,
int size,
int rwflag,
void *cls)
{
(void) buf; (void) size; (void) rwflag; (void) cls; /* Unused */
#ifdef mhd_USE_TLS_DEBUG_MESSAGES
fprintf (stderr, "## OpenSSL: the NULL passphrase callback is called\n");
fflush (stderr);
#endif
return 0;
}
/**
* Initialise OpenSSL library context
* @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_init_lib_ctx (struct MHD_Daemon *restrict d,
struct mhd_TlsOpenDaemonData *restrict d_tls,
struct DaemonOptions *restrict s)
{
bool fallback_config;
bool prevent_fallbacks;
char *conf_filename;
d_tls->libctx = OSSL_LIB_CTX_new ();
(void) s; // TODO: support app-defined name for TLS backend profile
if (NULL == d_tls->libctx)
{
mhd_DBG_PRINT_TLS_ERRS ();
mhd_LOG_MSG (d, MHD_SC_TLS_DAEMON_INIT_FAILED, \
"Failed to create TLS library context");
return MHD_SC_TLS_DAEMON_INIT_FAILED;
}
prevent_fallbacks = (0 != OSSL_LIB_CTX_get_conf_diagnostics (d_tls->libctx));
fallback_config = false;
ERR_clear_error ();
conf_filename = CONF_get1_default_config_file ();
if (NULL == conf_filename)
mhd_DBG_PRINT_TLS_ERRS ();
else
{
bool libctx_inited;
CONF *conf;
libctx_inited = false;
conf = NCONF_new_ex (d_tls->libctx,
NULL);
if (NULL == conf)
mhd_DBG_PRINT_TLS_ERRS ();
else
{
if (0 >= NCONF_load (conf,
conf_filename,
NULL))
{
unsigned long err;
err = ERR_peek_last_error ();
mhd_DBG_PRINT_TLS_ERRS ();
libctx_inited = true; /* Nothing to initialise */
if ((ERR_LIB_CONF != ERR_GET_LIB (err)) ||
(CONF_R_NO_SUCH_FILE != ERR_GET_REASON (err)))
{
fallback_config = true;
mhd_LOG_PRINT (d, MHD_SC_TLS_LIB_CONF_WARNING, \
mhd_LOG_FMT ("Error in TLS library configuration "
"file '%s'"), \
conf_filename);
}
}
else /* NCONF_load() succeed */
{
(void) s; // TODO: support app-defined name for TLS backend profile
if (! libctx_inited)
{
if (NULL != NCONF_get_section (conf,
"libmicrohttpd"))
{
if (0 <
CONF_modules_load (conf,
"libmicrohttpd",
0))
libctx_inited = true;
else
{
mhd_DBG_PRINT_TLS_ERRS ();
fallback_config = true;
mhd_LOG_PRINT (d, MHD_SC_TLS_LIB_CONF_WARNING, \
mhd_LOG_FMT ("Failed to load configuration file " \
"section [%s]"), \
"libmicrohttpd");
libctx_inited =
(0 < CONF_modules_load (conf,
"libmicrohttpd",
CONF_MFLAGS_IGNORE_ERRORS));
if (! libctx_inited)
mhd_DBG_PRINT_TLS_ERRS ();
}
}
}
if (! libctx_inited)
{
if (0 <
CONF_modules_load (conf,
NULL,
0))
libctx_inited = true;
else
{
mhd_DBG_PRINT_TLS_ERRS ();
fallback_config = true;
mhd_LOG_PRINT (d, MHD_SC_TLS_LIB_CONF_WARNING, \
mhd_LOG_FMT ("Failed to load configuration file " \
"default section"));
libctx_inited =
(0 < CONF_modules_load (conf,
NULL,
CONF_MFLAGS_IGNORE_ERRORS));
if (! libctx_inited)
mhd_DBG_PRINT_TLS_ERRS ();
}
}
if (fallback_config && libctx_inited && ! prevent_fallbacks)
prevent_fallbacks =
(0 != OSSL_LIB_CTX_get_conf_diagnostics (d_tls->libctx));
}
NCONF_free (conf);
}
OPENSSL_free (conf_filename);
if (fallback_config && prevent_fallbacks)
libctx_inited = true;
if (libctx_inited)
{
return MHD_SC_OK; /* Success exit point */
}
}
OSSL_LIB_CTX_free (d_tls->libctx);
mhd_LOG_MSG (d, MHD_SC_TLS_DAEMON_INIT_FAILED, \
"Failed to initialise TLS library context");
return MHD_SC_TLS_DAEMON_INIT_FAILED;
}
/**
* De-initialise OpenSSL library context
* @param d_tls the daemon TLS settings
*/
static MHD_FN_PAR_NONNULL_ALL_ void
daemon_deinit_lib_ctx (struct mhd_TlsOpenDaemonData *restrict d_tls)
{
mhd_assert (NULL != d_tls->libctx);
OSSL_LIB_CTX_free (d_tls->libctx);
}
static const unsigned char alpn_codes_list[] = {
#if 0 /* Disabled code */
2u, 'h', '3' /* Registered value for HTTP/3 */
,
2u, 'h', '2' /* Registered value for HTTP/2 over TLS */
,
#endif /* Disabled code */
8u, 'h', 't', 't', 'p', '/', '1', '.', '1' /* Registered value for HTTP/1.1 */
,
8u, 'h', 't', 't', 'p', '/', '1', '.', '0' /* Registered value for HTTP/1.0 */
};
/**
* Provide the list of supported protocols for NPN extension
* @param sess the TLS session (ignored)
* @param[out] out the pointer to get the location of the data
* @param[out] outlen the size of the data provided
* @param cls the closure (ignored)
* @return always SSL_TLSEXT_ERR_OK
*/
static int
get_npn_list (SSL *sess,
const unsigned char **out,
unsigned int *outlen,
void *cls)
{
(void) sess; (void) cls; /* Unused */
*out = alpn_codes_list;
*outlen = sizeof(alpn_codes_list);
return SSL_TLSEXT_ERR_OK;
}
/**
* Select protocol from the provided list for ALPN extension
* @param sess the TLS session (ignored)
* @param[out] out the pointer to get the location of selected protocol value
* @param[out] outlen the size of the selected protocol value
* @param in the list of protocols values provided by the client
* @param inlen the size of the list of protocols values provided by the client
* @param cls the closure (ignored)
* @return SSL_TLSEXT_ERR_OK if matching protocol found and selected,
* SSL_TLSEXT_ERR_ALERT_FATAL otherwise
*/
static int
select_alpn_prot (SSL *sess,
const unsigned char **out,
unsigned char *outlen,
const unsigned char *in,
unsigned int inlen,
void *cls)
{
(void) sess; (void) cls; /* Unused */
if (OPENSSL_NPN_NEGOTIATED ==
SSL_select_next_proto (mhd_DROP_CONST (out),
outlen,
in,
inlen,
alpn_codes_list,
sizeof(alpn_codes_list)))
return SSL_TLSEXT_ERR_OK; /* Success */
return SSL_TLSEXT_ERR_ALERT_FATAL; /* Failure */
}
/**
* Initialise TLS server context
* @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_init_ctx (struct MHD_Daemon *restrict d,
struct mhd_TlsOpenDaemonData *restrict d_tls,
struct DaemonOptions *restrict s)
{
uint64_t ctx_opts;
#ifndef HAVE_LOG_FUNCTIONALITY
(void) d; /* Mute compiler warning */
#endif
(void) s; // TODO: support configuration options
mhd_assert (NULL != d_tls->libctx);
ERR_clear_error ();
d_tls->ctx = SSL_CTX_new_ex (d_tls->libctx,
NULL,
TLS_server_method ());
if (NULL == d_tls->ctx)
{
mhd_DBG_PRINT_TLS_ERRS ();
mhd_LOG_MSG (d, MHD_SC_TLS_DAEMON_INIT_FAILED, \
"Failed to initialise TLS server context");
return MHD_SC_TLS_DAEMON_INIT_FAILED;
}
/* Enable some safe and useful workarounds */
ctx_opts = SSL_OP_SAFARI_ECDHE_ECDSA_BUG | SSL_OP_TLSEXT_PADDING;
// TODO: add configuration option
// ctx_opts |= SSL_OP_CIPHER_SERVER_PREFERENCE;
/* Enable kernel TLS */ // TODO: add configuration option
ctx_opts |= SSL_OP_ENABLE_KTLS;
#ifdef SSL_OP_ENABLE_KTLS_TX_ZEROCOPY_SENDFILE
ctx_opts |= SSL_OP_ENABLE_KTLS_TX_ZEROCOPY_SENDFILE;
#endif
/* HTTP defines strict framing for the client-side data,
no risk of attack on server on unexpected connection interruption */
/* ctx_opts |= SSL_OP_IGNORE_UNEXPECTED_EOF; */ // TODO: recheck
/* There is no reason to use re-negotiation with HTTP */
ctx_opts |= SSL_OP_NO_RENEGOTIATION;
/* Do not use session resumption for now */
ctx_opts |= SSL_OP_NO_TICKET;
(void) SSL_CTX_set_options (d_tls->ctx,
ctx_opts);
/* Prevent interactive password prompts */
SSL_CTX_set_default_passwd_cb (d_tls->ctx,
&null_passwd_cb);
// TODO: regenerate certificates
// TODO: make the setting configurable
// FIXME: this is a bad workaround!
SSL_CTX_set_security_level (d_tls->ctx, 0); /* Required to accept current test CA */
/* recv()- and send()-related options */
(void) SSL_CTX_set_mode (d_tls->ctx,
SSL_MODE_ENABLE_PARTIAL_WRITE
| SSL_MODE_AUTO_RETRY);
(void) SSL_CTX_clear_mode (d_tls->ctx,
SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER
| SSL_MODE_ASYNC);
SSL_CTX_set_read_ahead (d_tls->ctx,
! 0);
/* ALPN and NPN */
// TODO: use daemon option to disable them
SSL_CTX_set_alpn_select_cb (d_tls->ctx,
&select_alpn_prot,
NULL);
SSL_CTX_set_next_protos_advertised_cb (d_tls->ctx,
&get_npn_list,
NULL);
return MHD_SC_OK;
}
/**
* De-initialise TLS server context
* @param d_tls the daemon TLS settings
*/
static MHD_FN_PAR_NONNULL_ALL_ void
daemon_deinit_ctx (struct mhd_TlsOpenDaemonData *restrict d_tls)
{
mhd_assert (NULL != d_tls->ctx);
SSL_CTX_free (d_tls->ctx);
}
/**
* Load provided certificates chain
* @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_load_certs_chain (struct MHD_Daemon *restrict d,
struct mhd_TlsOpenDaemonData *restrict d_tls,
struct DaemonOptions *restrict s)
{
enum MHD_StatusCode ret;
BIO *m_bio;
X509 *cert;
mhd_assert (NULL != d_tls->libctx);
mhd_assert (NULL != d_tls->ctx);
ERR_clear_error ();
m_bio = BIO_new_mem_buf (s->tls_cert_key.v_mem_cert,
-1);
if (NULL == m_bio)
{
mhd_DBG_PRINT_TLS_ERRS ();
return MHD_SC_DAEMON_MALLOC_FAILURE;
}
ret = MHD_SC_OK;
/* The certificate object must be pre-allocated to associate it with
* the lib context */
cert = X509_new_ex (d_tls->libctx,
NULL);
if (NULL != cert)
{
if (NULL != PEM_read_bio_X509_AUX (m_bio,
&cert,
&null_passwd_cb,
NULL))
{
if (0 < SSL_CTX_use_certificate (d_tls->ctx,
cert))
{
if (0 != ERR_peek_error ())
mhd_DBG_PRINT_TLS_ERRS ();
/* The object successfully "copied" to CTX,
* the original object is not needed anymore. */
X509_free (cert);
cert = NULL;
do
{
X509 *c_cert; /* Certifying certificate */
c_cert = X509_new_ex (d_tls->libctx,
NULL);
if (NULL == c_cert)
{
mhd_DBG_PRINT_TLS_ERRS ();
mhd_LOG_MSG (d, MHD_SC_TLS_DAEMON_INIT_FAILED, \
"Failed to create new chain certificate object");
ret = MHD_SC_TLS_DAEMON_INIT_FAILED;
}
else
{
if (NULL == PEM_read_bio_X509 (m_bio,
&cert,
&null_passwd_cb,
NULL))
{
unsigned long err;
err = ERR_peek_last_error ();
if ((ERR_LIB_PEM == ERR_GET_LIB (err)) &&
(PEM_R_NO_START_LINE == ERR_GET_REASON (err)))
{
/* End of data */
ERR_clear_error ();
X509_free (c_cert); /* Empty, not needed */
mhd_assert (MHD_SC_OK == ret);
return MHD_SC_OK; /* Success exit point */
}
mhd_DBG_PRINT_TLS_ERRS ();
mhd_LOG_MSG (d, MHD_SC_TLS_DAEMON_INIT_FAILED, \
"Failed to load next object in the certificates " \
"chain");
ret = MHD_SC_TLS_DAEMON_INIT_FAILED;
}
else
{
if (SSL_CTX_add0_chain_cert (d_tls->ctx,
c_cert))
{
/* Success, do not free the certificate as
* function '_add0_' was used to add it. */
/* Read the next certificate in the chain. */
continue;
}
else
{
mhd_DBG_PRINT_TLS_ERRS ();
mhd_LOG_MSG (d, MHD_SC_TLS_DAEMON_INIT_FAILED, \
"Failed to add the new certificate object "
"to the chain");
ret = MHD_SC_TLS_DAEMON_INIT_FAILED;
}
}
X509_free (c_cert); /* Failed, the object is not needed */
mhd_assert (MHD_SC_OK != ret);
}
} while (MHD_SC_OK == ret);
}
else
{
mhd_DBG_PRINT_TLS_ERRS ();
mhd_LOG_MSG (d, MHD_SC_TLS_DAEMON_INIT_FAILED, \
"Failed to set the certificate");
ret = MHD_SC_TLS_DAEMON_INIT_FAILED;
}
}
else
{
mhd_DBG_PRINT_TLS_ERRS ();
mhd_LOG_MSG (d, MHD_SC_TLS_DAEMON_INIT_FAILED, \
"Failed to process the certificate");
ret = MHD_SC_TLS_DAEMON_INIT_FAILED;
}
if (NULL != cert)
X509_free (cert);
}
else
{
mhd_DBG_PRINT_TLS_ERRS ();
mhd_LOG_MSG (d, MHD_SC_TLS_DAEMON_INIT_FAILED, \
"Failed to create new certificate object");
ret = MHD_SC_TLS_DAEMON_INIT_FAILED;
}
BIO_free (m_bio);
mhd_assert (MHD_SC_OK != ret);
return ret;
}
/**
* Initialise TLS certificate
* The function loads the certificate chain and the private key.
* @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_init_cert (struct MHD_Daemon *restrict d,
struct mhd_TlsOpenDaemonData *restrict d_tls,
struct DaemonOptions *restrict s)
{
enum MHD_StatusCode ret;
BIO *m_bio;
EVP_PKEY *pr_key;
int res;
mhd_assert (NULL != d_tls->libctx);
mhd_assert (NULL != d_tls->ctx);
ERR_clear_error ();
ret = daemon_load_certs_chain (d,
d_tls,
s);
if (MHD_SC_OK != ret)
return ret;
/* Check and cache the certificates chain.
This also prevents automatic chain re-building for each session. */
res =
SSL_CTX_build_cert_chain (
d_tls->ctx,
SSL_BUILD_CHAIN_FLAG_CHECK /* Use only certificates in the chain */
| SSL_BUILD_CHAIN_FLAG_UNTRUSTED /* Intermediate certs does not need to be trusted */
| SSL_BUILD_CHAIN_FLAG_NO_ROOT /* The root should not be sent */
| SSL_BUILD_CHAIN_FLAG_IGNORE_ERROR /* Allow the root CA to be not trusted */
);
if (0 >= res)
{
mhd_DBG_PRINT_TLS_ERRS ();
mhd_LOG_MSG (d, MHD_SC_TLS_DAEMON_INIT_FAILED, \
"Failed rebuild certificate chain");
return MHD_SC_TLS_DAEMON_INIT_FAILED;
}
if (2 == res)
mhd_DBG_PRINT_TLS_ERRS ();
m_bio = BIO_new_mem_buf (s->tls_cert_key.v_mem_key,
-1);
if (NULL == m_bio)
{
mhd_DBG_PRINT_TLS_ERRS ();
return MHD_SC_DAEMON_MALLOC_FAILURE;
}
pr_key =
PEM_read_bio_PrivateKey_ex (m_bio,
NULL,
NULL == s->tls_cert_key.v_mem_pass ?
&null_passwd_cb : NULL,
mhd_DROP_CONST (s->tls_cert_key.v_mem_pass),
d_tls->libctx,
NULL);
BIO_free (m_bio);
if (NULL == pr_key)
{
mhd_DBG_PRINT_TLS_ERRS ();
mhd_LOG_MSG (d, MHD_SC_TLS_DAEMON_INIT_FAILED, \
"Failed to read the private key");
return MHD_SC_TLS_DAEMON_INIT_FAILED;
}
res = SSL_CTX_use_PrivateKey (d_tls->ctx,
pr_key);
EVP_PKEY_free (pr_key); /* The key has been "copied" or failed */
if (1 != res)
{
mhd_DBG_PRINT_TLS_ERRS ();
mhd_LOG_MSG (d, MHD_SC_TLS_DAEMON_INIT_FAILED, \
"Failed to set the private key");
return MHD_SC_TLS_DAEMON_INIT_FAILED;
}
/* This actually RE-checks the key.
The key should be already checked automatically when it was set after
setting the certificate. */
if (1 != SSL_CTX_check_private_key (d_tls->ctx))
{
mhd_DBG_PRINT_TLS_ERRS ();
mhd_LOG_MSG (d, MHD_SC_TLS_DAEMON_INIT_FAILED, \
"The private key does not match the certificate");
return MHD_SC_TLS_DAEMON_INIT_FAILED;
}
return MHD_SC_OK;
}
MHD_INTERNAL MHD_FN_MUST_CHECK_RESULT_ MHD_FN_PAR_NONNULL_ALL_
MHD_FN_PAR_OUT_ (3) mhd_StatusCodeInt
mhd_tls_open_daemon_init (struct MHD_Daemon *restrict d,
struct DaemonOptions *restrict s,
struct mhd_TlsOpenDaemonData **restrict p_d_tls)
{
mhd_StatusCodeInt res;
struct mhd_TlsOpenDaemonData *restrict d_tls;
res = check_app_tls_sessings (d, s);
if (MHD_SC_OK != res)
return res;
d_tls = (struct mhd_TlsOpenDaemonData *)
mhd_calloc (1, sizeof (struct mhd_TlsOpenDaemonData));
*p_d_tls = d_tls;
if (NULL == d_tls)
return MHD_SC_DAEMON_MALLOC_FAILURE;
res = daemon_init_lib_ctx (d,
d_tls,
s);
if (MHD_SC_OK == res)
{
res = daemon_init_ctx (d,
d_tls,
s);
if (MHD_SC_OK == res)
{
res = daemon_init_cert (d,
d_tls,
s);
if (MHD_SC_OK == res)
return MHD_SC_OK; /* Success exit point */
/* Below is a clean-up code path */
daemon_deinit_ctx (d_tls);
}
daemon_deinit_lib_ctx (d_tls);
}
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_open_daemon_deinit (struct mhd_TlsOpenDaemonData *restrict d_tls)
{
mhd_assert (NULL != d_tls);
daemon_deinit_ctx (d_tls);
daemon_deinit_lib_ctx (d_tls);
free (d_tls);
}
/* ** Connection initialisation / de-initialisation ** */
MHD_INTERNAL size_t
mhd_tls_open_conn_get_tls_size (void)
{
return sizeof (struct mhd_TlsOpenConnData);
}
MHD_INTERNAL MHD_FN_MUST_CHECK_RESULT_ MHD_FN_PAR_NONNULL_ALL_
MHD_FN_PAR_OUT_ (3) bool
mhd_tls_open_conn_init (const struct mhd_TlsOpenDaemonData *restrict d_tls,
const struct mhd_ConnSocket *sk,
struct mhd_TlsOpenConnData *restrict c_tls)
{
int fd;
ERR_clear_error ();
fd = (int) sk->fd;
if (sk->fd != (MHD_Socket) fd)
return false; /* OpenSSL docs clam that it should not be possible */
c_tls->sess = SSL_new (d_tls->ctx);
if (NULL == c_tls->sess)
{
mhd_DBG_PRINT_TLS_ERRS ();
return false;
}
if (0 < SSL_set_fd (c_tls->sess, fd))
{
SSL_set_accept_state (c_tls->sess); /* Force server mode */
#ifndef NDEBUG
c_tls->dbg.is_inited = true;
#endif
return true; /* Success exit point */
}
SSL_free (c_tls->sess);
c_tls->sess = NULL;
return false;
}
MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ void
mhd_tls_open_conn_deinit (struct mhd_TlsOpenConnData *restrict c_tls)
{
mhd_assert (NULL != c_tls->sess);
mhd_assert (c_tls->dbg.is_inited);
SSL_free (c_tls->sess);
}
/* ** TLS connection establishing ** */
MHD_INTERNAL MHD_FN_MUST_CHECK_RESULT_ MHD_FN_PAR_NONNULL_ALL_
enum mhd_TlsProcedureResult
mhd_tls_open_conn_handshake (struct mhd_TlsOpenConnData *restrict 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);
ERR_clear_error ();
res = SSL_do_handshake (c_tls->sess);
if (1 == res)
{
#ifndef NDEBUG
c_tls->dbg.is_tls_handshake_completed = true;
#endif /* ! NDEBUG */
return mhd_TLS_PROCED_SUCCESS; /* Success exit point */
}
switch (SSL_get_error (c_tls->sess, res))
{
case SSL_ERROR_WANT_READ:
/* OpenSSL does not distinguish between "interrupted" and "try again" codes.
This is very bad when edge triggered polling is used as is is not clear
whether the "recv-ready" flag should be cleared.
If the flag is cleared, but it should not (because the process has been
"interrupted") then already pending data could be never processed.
If the flag is not cleared, but it should be cleared (because all
received data has been processed) then it would create busy-waiting loop.
Use clear of "ready" flag as safer, but not ideal solution. */
// TODO: replace "BIO" with custom version and track returned errors.
return mhd_TLS_PROCED_SEND_MORE_NEEDED;
case SSL_ERROR_WANT_WRITE:
/* OpenSSL does not distinguish between "interrupted" and "try again" codes.
This is very bad when edge triggered polling is used as is is not clear
whether the "send-ready" flag should be cleared.
If the flag is cleared, but it should not (because the process has been
"interrupted") then already pending data could be never sent.
If the flag is not cleared, but it should be cleared (because the network
is busy) then it would create busy-waiting loop.
Use clear of "ready" flag as safer, but not ideal solution. */
// TODO: replace "BIO" with custom version and track returned errors.
return mhd_TLS_PROCED_RECV_MORE_NEEDED;
case SSL_ERROR_NONE:
mhd_assert (0 && "This should not be possible");
MHD_UNREACHABLE_;
break;
default: /* Handled with all other errors below */
break;
}
mhd_DBG_PRINT_TLS_ERRS ();
#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_open_conn_shutdown (struct mhd_TlsOpenConnData *restrict 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);
ERR_clear_error ();
res = SSL_shutdown (c_tls->sess);
if (1 == res)
{
c_tls->shut_tls_wr_sent = true;
c_tls->shut_tls_wr_received = true;
return mhd_TLS_PROCED_SUCCESS; /* Success exit point */
}
/* The OpenSSL documentation contradicts itself: there are two mutually
exclusive statements on a single page.
* https://docs.openssl.org/master/man3/SSL_shutdown/#shutdown-lifecycle
indicates that for nonblocking socket ZERO could be returned when
"close_notify" is GOING to be sent, but NOT sent yet.
It also suggests to CALL SSL_get_error(3) when ZERO is returned.
* https://docs.openssl.org/master/man3/SSL_shutdown/#return-values
indicates ZERO is returned ONLY when "close_notify" HAS BEEN sent.
It also suggests to NOT CALL SSL_get_error(3) when ZERO is returned.
*/
switch (SSL_get_error (c_tls->sess, res))
{
case SSL_ERROR_WANT_READ:
/* OpenSSL does not distinguish between "interrupted" and "try again" codes.
This is very bad when edge triggered polling is used as is is not clear
whether the "recv-ready" flag should be cleared.
If the flag is cleared, but it should not (because the process has been
"interrupted") then already pending data could be never processed.
If the flag is not cleared, but it should be cleared (because all
received data has been processed) then it would create busy-waiting loop.
Use clear of "ready" flag as safer, but not ideal solution. */
// TODO: replace "BIO" with custom version and track returned errors.
return mhd_TLS_PROCED_SEND_MORE_NEEDED;
case SSL_ERROR_WANT_WRITE:
c_tls->shut_tls_wr_sent = true;
/* OpenSSL does not distinguish between "interrupted" and "try again" codes.
This is very bad when edge triggered polling is used as is is not clear
whether the "send-ready" flag should be cleared.
If the flag is cleared, but it should not (because the process has been
"interrupted") then already pending data could be never sent.
If the flag is not cleared, but it should be cleared (because the network
is busy) then it would create busy-waiting loop.
Use clear of "ready" flag as safer, but not ideal solution. */
// TODO: replace "BIO" with custom version and track returned errors.
return mhd_TLS_PROCED_RECV_MORE_NEEDED;
case SSL_ERROR_NONE:
mhd_assert (res != 0 && "Should not be possible");
c_tls->shut_tls_wr_sent = true;
return mhd_TLS_PROCED_RECV_INTERRUPTED;
default: /* Handled with all other errors below */
break;
}
mhd_DBG_PRINT_TLS_ERRS ();
#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_open_conn_recv (struct mhd_TlsOpenConnData *restrict c_tls,
size_t buf_size,
char buf[MHD_FN_PAR_DYN_ARR_SIZE_ (buf_size)],
size_t *restrict received)
{
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->dbg.is_failed);
ERR_clear_error ();
res = SSL_read_ex (c_tls->sess,
buf,
buf_size,
received);
if (1 == res)
{
mhd_assert (0 != *received);
return mhd_SOCKET_ERR_NO_ERROR; /* Success exit point */
}
mhd_assert (0 == res);
*received = 0;
switch (SSL_get_error (c_tls->sess, res))
{
case SSL_ERROR_ZERO_RETURN: /* Not an error */
c_tls->shut_tls_wr_received = true;
return mhd_SOCKET_ERR_NO_ERROR; /* Success exit point */
case SSL_ERROR_WANT_READ:
/* OpenSSL does not distinguish between "interrupted" and "try again" codes.
This is very bad when edge triggered polling is used as is is not clear
whether the "recv-ready" flag should be cleared.
If the flag is cleared, but it should not (because the process has been
"interrupted") then already pending data could be never processed.
If the flag is not cleared, but it should be cleared (because all
received data has been processed) then it would create busy-waiting loop.
Use clear of "ready" flag as safer, but not ideal solution. */
// TODO: replace "BIO" with custom version and track returned errors.
return mhd_SOCKET_ERR_AGAIN;
case SSL_ERROR_NONE:
mhd_assert (0 && "Should not be possible");
break;
case SSL_ERROR_WANT_WRITE:
mhd_assert (0 && "Should not be possible as re-handshakes are disallowed");
break;
case SSL_ERROR_SYSCALL:
mhd_DBG_PRINT_TLS_ERRS ();
#ifndef NDEBUG
c_tls->dbg.is_failed = true;
#endif /* ! NDEBUG */
return mhd_SOCKET_ERR_CONN_BROKEN;
case SSL_ERROR_SSL:
default:
break;
}
/* Treat all other kinds of errors as hard errors */
mhd_DBG_PRINT_TLS_ERRS ();
#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_open_conn_has_data_in (struct mhd_TlsOpenConnData *restrict c_tls)
{
return 0 != SSL_pending (c_tls->sess);
}
MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_
MHD_FN_PAR_IN_SIZE_ (3,2)
MHD_FN_PAR_OUT_ (4) enum mhd_SocketError
mhd_tls_open_conn_send (struct mhd_TlsOpenConnData *restrict c_tls,
size_t buf_size,
const char buf[MHD_FN_PAR_DYN_ARR_SIZE_ (buf_size)],
size_t *restrict sent)
{
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->dbg.is_failed);
ERR_clear_error ();
res = SSL_write_ex (c_tls->sess,
buf,
buf_size,
sent);
if (1 == res)
{
mhd_assert (0 != *sent);
return mhd_SOCKET_ERR_NO_ERROR; /* Success exit point */
}
mhd_assert (0 == res);
*sent = 0;
switch (SSL_get_error (c_tls->sess, res))
{
case SSL_ERROR_WANT_WRITE:
/* OpenSSL does not distinguish between "interrupted" and "try again" codes.
This is very bad when edge triggered polling is used as is is not clear
whether the "send-ready" flag should be cleared.
If the flag is cleared, but it should not (because the process has been
"interrupted") then already pending data could be never sent.
If the flag is not cleared, but it should be cleared (because the network
is busy) then it would create busy-waiting loop.
Use clear of "ready" flag as safer, but not ideal solution. */
// TODO: replace "BIO" with custom version and track returned errors.
return mhd_SOCKET_ERR_AGAIN;
case SSL_ERROR_NONE:
mhd_assert (0 && "Should not be possible");
break;
case SSL_ERROR_WANT_READ:
mhd_assert (0 && "Should not be possible as re-handshakes are disallowed");
break;
case SSL_ERROR_ZERO_RETURN:
mhd_assert (0 && "Should not be possible when sending");
break;
case SSL_ERROR_SYSCALL:
mhd_DBG_PRINT_TLS_ERRS ();
#ifndef NDEBUG
c_tls->dbg.is_failed = true;
#endif /* ! NDEBUG */
return mhd_SOCKET_ERR_CONN_BROKEN;
case SSL_ERROR_SSL:
default:
break;
}
/* Treat all other kinds of errors as hard errors */
mhd_DBG_PRINT_TLS_ERRS ();
#ifndef NDEBUG
c_tls->dbg.is_failed = true;
#endif /* ! NDEBUG */
return mhd_SOCKET_ERR_TLS;
}
+214
View File
@@ -0,0 +1,214 @@
/*
This file is part of GNU libmicrohttpd
Copyright (C) 2024 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.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/**
* @file src/mhd2/tls_open_funcs.h
* @brief The declarations of OpenSSL interface wrapper functions
* @author Karlson2k (Evgeny Grin)
*/
#ifndef MHD_TLS_OPEN_FUNCS_H
#define MHD_TLS_OPEN_FUNCS_H 1
#include "mhd_sys_options.h"
#ifndef MHD_USE_OPENSSL
#error This header can be used only if OpenSSL 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 OpenSSL data
*/
struct mhd_TlsOpenDaemonData; /* Forward declaration */
/**
* The structure with connection-specific OpenSSL data
*/
struct mhd_TlsOpenConnData; /* Forward declaration */
/* ** Global initialisation / de-initialisation ** */
/**
* Globally initialise OpenSSL backend.
* Once initialised, this backend cannot be de-initialised.
*/
MHD_INTERNAL void
mhd_tls_open_global_init_once (void);
/* No-op for OpenSSL backend */
#define mhd_tls_open_global_re_init() ((void) 0)
/* No-op for OpenSSL backend */
#define mhd_tls_open_global_deinit() ((void) 0)
/**
* Check whether OpenSSL backend was successfully initialised globally
*/
MHD_INTERNAL bool
mhd_tls_open_is_inited_fine (void);
/* ** Daemon initialisation / de-initialisation ** */
struct MHD_Daemon; /* Forward declaration */
struct DaemonOptions; /* Forward declaration */
/**
* Allocate and initialise daemon TLS parameters
* @param d the daemon handle
* @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_open_daemon_init (struct MHD_Daemon *restrict d,
struct DaemonOptions *restrict s,
struct mhd_TlsOpenDaemonData **restrict p_d_tls)
MHD_FN_MUST_CHECK_RESULT_ MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_OUT_ (3);
/**
* 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_open_daemon_deinit (struct mhd_TlsOpenDaemonData *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_open_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_open_conn_init (const struct mhd_TlsOpenDaemonData *restrict d_tls,
const struct mhd_ConnSocket *sk,
struct mhd_TlsOpenConnData *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_open_conn_deinit (struct mhd_TlsOpenConnData *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_open_conn_handshake (struct mhd_TlsOpenConnData *restrict 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_open_conn_shutdown (struct mhd_TlsOpenConnData *restrict 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_open_conn_recv (struct mhd_TlsOpenConnData *restrict 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_open_conn_has_data_in (struct mhd_TlsOpenConnData *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 buffer_size the size of the @a buffer (in bytes)
* @param buffer content of the buffer to send
* @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_open_conn_send (struct mhd_TlsOpenConnData *restrict c_tls,
size_t buf_size,
const char buf[MHD_FN_PAR_DYN_ARR_SIZE_ (buf_size)],
size_t *restrict sent)
MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_IN_SIZE_ (3,2) MHD_FN_PAR_OUT_ (4);
#endif /* ! MHD_TLS_OPEN_FUNCS_H */
+57
View File
@@ -0,0 +1,57 @@
/*
This file is part of GNU libmicrohttpd
Copyright (C) 2024 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.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/**
* @file src/mhd2/tls_open_tls_lib.h
* @brief The MHD wrapper for OpenSSL headers
* @author Karlson2k (Evgeny Grin)
*/
#ifndef MHD_TLS_OPEN_TLS_LIB_H
#define MHD_TLS_OPEN_TLS_LIB_H 1
#include "mhd_sys_options.h"
#ifndef MHD_USE_OPENSSL
#error This header can be used only if GnuTLS is enabled
#endif
/* Declare compatibility with OpenSSL versions >= 3.0 */
#define OPENSSL_API_COMPAT 30000
/* Request to hide all symbols deprecated before OPENSSL_API_COMPAT version */
#define OPENSSL_NO_DEPRECATED 1
#include <openssl/opensslv.h>
#include <openssl/crypto.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <openssl/bio.h>
#include <openssl/conf.h>
#include <openssl/pem.h>
#ifndef OPENSSL_VERSION_NUMBER
#error OPENSSL_VERSION_NUMBER is not defined
#endif
#ifndef OPENSSL_VERSION_PREREQ
#error OPENSSL_VERSION_PREREQ is not defined
#endif
#endif /* ! MHD_TLS_OPEN_TLS_LIB_H */