mirror of
https://git.gnunet.org/libmicrohttpd.git
synced 2026-09-25 04:09:31 +03:00
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:
+274
-32
@@ -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" || \
|
||||
|
||||
@@ -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
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -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
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -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 = \
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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 ** */
|
||||
|
||||
/**
|
||||
|
||||
@@ -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 */
|
||||
@@ -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 */
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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 */
|
||||
@@ -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 */
|
||||
Reference in New Issue
Block a user