Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding TLS-PSK authentication method via function callback. #333

Open
wants to merge 18 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
96 changes: 75 additions & 21 deletions README.md

Large diffs are not rendered by default.

16 changes: 9 additions & 7 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ m4_define([libhttpserver_MINOR_VERSION],[19])dnl
m4_define([libhttpserver_REVISION],[0])dnl
m4_define([libhttpserver_PKG_VERSION],[libhttpserver_MAJOR_VERSION.libhttpserver_MINOR_VERSION.libhttpserver_REVISION])dnl
m4_define([libhttpserver_LDF_VERSION],[libhttpserver_MAJOR_VERSION:libhttpserver_MINOR_VERSION:libhttpserver_REVISION])dnl
AC_INIT([libhttpserver], libhttpserver_PKG_VERSION, [electrictwister2000@gmail.com])
AC_INIT([libhttpserver], libhttpserver_PKG_VERSION, electrictwister2000@gmail.com)
AM_INIT_AUTOMAKE([subdir-objects])
AC_CONFIG_HEADERS([config.h])
AC_CONFIG_MACRO_DIR([m4])
Expand Down Expand Up @@ -83,7 +83,6 @@ case "$host" in
esac

# Checks for header files.
AC_HEADER_STDC
AC_CHECK_HEADER([stdint.h],[],[AC_MSG_ERROR("stdint.h not found")])
AC_CHECK_HEADER([inttypes.h],[],[AC_MSG_ERROR("inttypes.h not found")])
AC_CHECK_HEADER([errno.h],[],[AC_MSG_ERROR("errno.h not found")])
Expand Down Expand Up @@ -245,11 +244,14 @@ AM_CONDITIONAL([BUILD_EXAMPLES], [test "x$enable_examples" = "xyes"])
AM_CONDITIONAL([COND_GCOV],[test x"$cond_gcov" = x"yes"])
AC_SUBST(COND_GCOV)

if test x"have_gnutls" = x"yes"; then
if test "x$have_gnutls" = "xyes"; then
AC_DEFINE([HAVE_GNUTLS],[1],[Uses GNU TLS])
AM_CXXFLAGS="$AM_CXXFLAGS -DHAVE_GNUTLS"
AM_CFLAGS="$AM_CXXFLAGS -DHAVE_GNUTLS"
AM_CFLAGS="$AM_CFLAGS -DHAVE_GNUTLS"
fi

AM_CONDITIONAL([HAVE_GNUTLS], [test "x$have_gnutls" = "xyes"])

DX_HTML_FEATURE(ON)
DX_CHM_FEATURE(OFF)
DX_CHI_FEATURE(OFF)
Expand Down Expand Up @@ -284,14 +286,14 @@ AC_CONFIG_FILES([examples/cert.pem:examples/cert.pem])
AC_CONFIG_FILES([examples/key.pem:examples/key.pem])
AC_CONFIG_FILES([examples/test_content:examples/test_content])

AC_OUTPUT(
libhttpserver.pc
AC_CONFIG_FILES([libhttpserver.pc
Makefile
doc/Makefile
src/Makefile
test/Makefile
examples/Makefile
)
])
AC_OUTPUT

AC_MSG_NOTICE([Configuration Summary:
Operating System: ${host_os}
Expand Down
8 changes: 7 additions & 1 deletion examples/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,14 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA

LDADD = $(top_builddir)/src/libhttpserver.la

if HAVE_GNUTLS
LDADD += -lgnutls
endif

AM_CPPFLAGS = -I$(top_srcdir)/src -I$(top_srcdir)/src/httpserver/
METASOURCES = AUTO
noinst_PROGRAMS = hello_world service minimal_hello_world custom_error allowing_disallowing_methods handlers hello_with_get_arg setting_headers custom_access_log basic_authentication digest_authentication minimal_https minimal_file_response minimal_deferred url_registration minimal_ip_ban benchmark_select benchmark_threads benchmark_nodelay deferred_with_accumulator file_upload
noinst_PROGRAMS = hello_world service minimal_hello_world custom_error allowing_disallowing_methods handlers hello_with_get_arg setting_headers custom_access_log basic_authentication digest_authentication minimal_https minimal_https_psk minimal_file_response minimal_deferred url_registration minimal_ip_ban benchmark_select benchmark_threads benchmark_nodelay deferred_with_accumulator file_upload

hello_world_SOURCES = hello_world.cpp
service_SOURCES = service.cpp
Expand All @@ -33,6 +38,7 @@ custom_access_log_SOURCES = custom_access_log.cpp
basic_authentication_SOURCES = basic_authentication.cpp
digest_authentication_SOURCES = digest_authentication.cpp
minimal_https_SOURCES = minimal_https.cpp
minimal_https_psk_SOURCES = minimal_https_psk.cpp
minimal_file_response_SOURCES = minimal_file_response.cpp
minimal_deferred_SOURCES = minimal_deferred.cpp
deferred_with_accumulator_SOURCES = deferred_with_accumulator.cpp
Expand Down
58 changes: 58 additions & 0 deletions examples/minimal_https_psk.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/*
This file is part of libhttpserver
Copyright (C) 2011, 2012, 2013, 2014, 2015 Sebastiano Merlino

This library 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.

This library 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
*/

#include <httpserver.hpp>

class hello_world_resource : public httpserver::http_resource {
public:
std::shared_ptr<httpserver::http_response> render(const httpserver::http_request&) {
return std::shared_ptr<httpserver::http_response>(
new httpserver::string_response("Hello, World!"));
}
};

std::string psk_callback(const std::string& username) {
// Known identity from the database.
auto identity = std::string {"oFWv9Cv3N9tUsm"};

// Pre-shared key in hex-encoded format.
auto key = std::string {
"467427f5a4696f8e0ac285f36840efcbf6fd8da88703d26ff68c1faac7f4e2ae"};

return (username == identity) ? key : std::string {};
}

int main() {
#ifdef HAVE_GNUTLS
httpserver::webserver ws =
httpserver::create_webserver(8080)
.use_ssl()
.https_priorities("NORMAL:+PSK:+ECDHE-PSK:+DHE-PSK")
.cred_type(httpserver::http::http_utils::PSK)
.psk_cred_handler(psk_callback);

hello_world_resource hwr;
ws.register_resource("/hello", &hwr);
ws.start(true);

return 0;
#else
return -1;
#endif
}
9 changes: 9 additions & 0 deletions src/httpserver/create_webserver.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
#include <functional>
#include <limits>
#include <string>
#include <utility>

#include "httpserver/http_response.hpp"
#include "httpserver/http_utils.hpp"
Expand All @@ -42,6 +43,8 @@ namespace httpserver {
class webserver;
class http_request;

typedef std::function<std::string(const std::string&)> psk_cred_handler_callback;

typedef std::function<std::shared_ptr<http_response>(const http_request&)> render_ptr;
typedef std::function<bool(const std::string&)> validator_ptr;
typedef std::function<void(const std::string&)> log_access_ptr;
Expand Down Expand Up @@ -213,6 +216,11 @@ class create_webserver {
return *this;
}

create_webserver& psk_cred_handler(psk_cred_handler_callback handler) {
_psk_cred_handler = std::move(handler);
return *this;
}

create_webserver& https_priorities(const std::string& https_priorities) {
_https_priorities = https_priorities;
return *this;
Expand Down Expand Up @@ -383,6 +391,7 @@ class create_webserver {
std::string _https_mem_cert = "";
std::string _https_mem_trust = "";
std::string _https_priorities = "";
psk_cred_handler_callback _psk_cred_handler;
http::http_utils::cred_type_T _cred_type = http::http_utils::NONE;
std::string _digest_auth_random = "";
int _nonce_nc_size = 0;
Expand Down
3 changes: 3 additions & 0 deletions src/httpserver/webserver.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,7 @@ class webserver {
const std::string https_mem_cert;
const std::string https_mem_trust;
const std::string https_priorities;
const psk_cred_handler_callback psk_cred_handler;
const http::http_utils::cred_type_T cred_type;
const std::string digest_auth_random;
const int nonce_nc_size;
Expand Down Expand Up @@ -186,6 +187,8 @@ class webserver {
std::shared_ptr<http_response> internal_error_page(details::modded_request* mr, bool force_our = false) const;
std::shared_ptr<http_response> not_found_page(details::modded_request* mr) const;

static void psk_cred_handler_func(void* cls, const struct MHD_Connection* connection, const char* username, void** psk, size_t* psk_size);

static void request_completed(void *cls,
struct MHD_Connection *connection, void **con_cls,
enum MHD_RequestTerminationCode toe);
Expand Down
31 changes: 27 additions & 4 deletions src/webserver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,10 @@
#include <utility>
#include <vector>

#ifdef HAVE_GNUTLS
#include <gnutls/gnutls.h>
#endif

#include "httpserver/create_webserver.hpp"
#include "httpserver/details/http_endpoint.hpp"
#include "httpserver/details/modded_request.hpp"
Expand Down Expand Up @@ -141,6 +145,7 @@ webserver::webserver(const create_webserver& params):
https_mem_cert(params._https_mem_cert),
https_mem_trust(params._https_mem_trust),
https_priorities(params._https_priorities),
psk_cred_handler(params._psk_cred_handler),
cred_type(params._cred_type),
digest_auth_random(params._digest_auth_random),
nonce_nc_size(params._nonce_nc_size),
Expand Down Expand Up @@ -176,6 +181,18 @@ void webserver::sweet_kill() {
stop();
}

void webserver::psk_cred_handler_func(void* cls, const struct MHD_Connection*, const char* username, void** psk, size_t* psk_size) {
[[maybe_unused]] std::string key = std::invoke(static_cast<const webserver*>(cls)->psk_cred_handler, username);

#ifdef HAVE_GNUTLS
*psk_size = key.length();
*psk = malloc(*psk_size);

if (gnutls_hex2bin(key.data(), key.length(), *psk,psk_size) != GNUTLS_E_SUCCESS)
*psk_size = 0;
#endif
}

void webserver::request_completed(void *cls, struct MHD_Connection *connection, void **con_cls, enum MHD_RequestTerminationCode toe) {
// These parameters are passed to respect the MHD interface, but are not needed here.
std::ignore = cls;
Expand Down Expand Up @@ -210,9 +227,11 @@ bool webserver::start(bool blocking) {
} gen;
vector<struct MHD_OptionItem> iov;

// Must be assigned first to options to ensure that all output is handled by external logger!
iov.push_back(gen(MHD_OPTION_EXTERNAL_LOGGER, (intptr_t) &error_log, this));

iov.push_back(gen(MHD_OPTION_NOTIFY_COMPLETED, (intptr_t) &request_completed, nullptr));
iov.push_back(gen(MHD_OPTION_URI_LOG_CALLBACK, (intptr_t) &uri_log, this));
iov.push_back(gen(MHD_OPTION_EXTERNAL_LOGGER, (intptr_t) &error_log, this));
iov.push_back(gen(MHD_OPTION_UNESCAPE_CALLBACK, (intptr_t) &unescaper_func, this));
iov.push_back(gen(MHD_OPTION_CONNECTION_TIMEOUT, connection_timeout));
if (bind_socket != 0) {
Expand Down Expand Up @@ -247,12 +266,12 @@ bool webserver::start(bool blocking) {
iov.push_back(gen(MHD_OPTION_NONCE_NC_SIZE, nonce_nc_size));
}

if (use_ssl) {
if (https_mem_key != "" && use_ssl) {
// Need for const_cast to respect MHD interface that needs a void*
iov.push_back(gen(MHD_OPTION_HTTPS_MEM_KEY, 0, reinterpret_cast<void*>(const_cast<char*>(https_mem_key.c_str()))));
}

if (use_ssl) {
if (https_mem_cert != "" && use_ssl) {
// Need for const_cast to respect MHD interface that needs a void*
iov.push_back(gen(MHD_OPTION_HTTPS_MEM_CERT, 0, reinterpret_cast<void*>(const_cast<char*>(https_mem_cert.c_str()))));
}
Expand All @@ -273,9 +292,13 @@ bool webserver::start(bool blocking) {
}

#ifdef HAVE_GNUTLS
if (cred_type != http_utils::NONE) {
if (cred_type != http_utils::NONE && use_ssl) {
iov.push_back(gen(MHD_OPTION_HTTPS_CRED_TYPE, cred_type));
}

if (psk_cred_handler && use_ssl) {
iov.push_back(gen(MHD_OPTION_GNUTLS_PSK_CRED_HANDLER, (intptr_t) psk_cred_handler_func, this));
}
#endif // HAVE_GNUTLS

iov.push_back(gen(MHD_OPTION_END, 0, nullptr));
Expand Down
5 changes: 5 additions & 0 deletions test/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,11 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA

LDADD = $(top_builddir)/src/libhttpserver.la

if HAVE_GNUTLS
LDADD += -lgnutls
endif

AM_CPPFLAGS = -I$(top_srcdir)/src -I$(top_srcdir)/src/httpserver/
METASOURCES = AUTO
check_PROGRAMS = basic file_upload http_utils threaded nodelay string_utilities http_endpoint ban_system ws_start_stop authentication deferred http_resource
Expand Down
Loading