diff --git a/CMakeLists.txt b/CMakeLists.txt
index 33b20e1..61ea77c 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -17,13 +17,21 @@ set (PROJECT_SOURCE_DIR "${CMAKE_SOURCE_DIR}/src")
option(RELEASE "Release build, debug build if disabled" ON)
option(LINK_SUPPORT "Allow hub linking" OFF)
option(SSL_SUPPORT "Enable SSL support" ON)
+option(USE_OPENSSL "Use OpenSSL's SSL support" OFF)
option(SQLITE_SUPPORT "Enable SQLite support" ON)
option(ADC_STRESS "Enable the stress tester client" OFF)
find_package(Git)
if (SSL_SUPPORT)
- find_package(OpenSSL REQUIRED)
+ if (USE_OPENSSL)
+ find_package(OpenSSL)
+ else()
+ find_package(GnuTLS)
+ endif()
+ if (NOT GNUTLS_FOUND AND NOT OPENSSL_FOUND)
+ message(FATAL_ERROR "Neither OpenSSL nor GnuTLS are not found!")
+ endif()
endif()
if (MSVC)
@@ -41,6 +49,7 @@ set (network_SOURCES
${PROJECT_SOURCE_DIR}/network/timeout.c
${PROJECT_SOURCE_DIR}/network/timer.c
${PROJECT_SOURCE_DIR}/network/network.c
+ ${PROJECT_SOURCE_DIR}/network/openssl.c
${PROJECT_SOURCE_DIR}/network/ipcalc.c
)
@@ -156,16 +165,26 @@ else()
endif()
if(OPENSSL_FOUND)
- add_definitions(-DSSL_SUPPORT=1)
+ set(SSL_LIBS ${OPENSSL_LIBRARIES})
+ add_definitions(-DSSL_SUPPORT=1 -DSSL_USE_OPENSSL=1)
include_directories(${OPENSSL_INCLUDE_DIR})
- target_link_libraries(uhub ${OPENSSL_LIBRARIES})
+endif()
+
+if (GNUTLS_FOUND)
+ set(SSL_LIBS ${GNUTLS_LIBRARIES})
+ add_definitions(-DSSL_SUPPORT=1 -DSSL_USE_GNUTLS=1 ${GNUTLS_DEFINITIONS})
+ include_directories(${GNUTLS_INCLUDE_DIR})
+endif()
+
+if(SSL_SUPPORT)
+ target_link_libraries(uhub ${SSL_LIBS})
if(UNIX)
- target_link_libraries(uhub-admin ${OPENSSL_LIBRARIES})
+ target_link_libraries(uhub-admin ${SSL_LIBS})
endif()
- target_link_libraries(mod_welcome ${OPENSSL_LIBRARIES})
- target_link_libraries(mod_logging ${OPENSSL_LIBRARIES})
+ target_link_libraries(mod_welcome ${SSL_LIBS})
+ target_link_libraries(mod_logging ${SSL_LIBS})
if (ADC_STRESS)
- target_link_libraries(adcrush ${OPENSSL_LIBRARIES})
+ target_link_libraries(adcrush ${SSL_LIBS})
endif()
endif()
diff --git a/src/core/hub.c b/src/core/hub.c
index 714f8ec..7eb6570 100644
--- a/src/core/hub.c
+++ b/src/core/hub.c
@@ -731,41 +731,25 @@ static int load_ssl_certificates(struct hub_info* hub, struct hub_config* config
{
if (config->tls_enable)
{
- hub->ssl_method = (SSL_METHOD*) SSLv23_method(); /* TLSv1_method() */
- hub->ssl_ctx = SSL_CTX_new(hub->ssl_method);
-
- /* Disable SSLv2 */
- SSL_CTX_set_options(hub->ssl_ctx, SSL_OP_NO_SSLv2);
- SSL_CTX_set_quiet_shutdown(hub->ssl_ctx, 1);
-
- if (SSL_CTX_use_certificate_file(hub->ssl_ctx, config->tls_certificate, SSL_FILETYPE_PEM) < 0)
+ hub->ctx = net_ssl_context_create();
+ if (ssl_load_certificate(hub->ctx, config->tls_certificate) &&
+ ssl_load_private_key(hub->ctx, config->tls_private_key) &&
+ ssl_check_private_key(hub->ctx))
{
- LOG_ERROR("SSL_CTX_use_certificate_file: %s", ERR_error_string(ERR_get_error(), NULL));
+ LOG_INFO("Enabling TLS (%s), using certificate: %s, private key: %s", net_ssl_get_provider(), config->tls_certificate, config->tls_private_key);
+ return 1;
}
-
- if (SSL_CTX_use_PrivateKey_file(hub->ssl_ctx, config->tls_private_key, SSL_FILETYPE_PEM) < 0)
- {
- LOG_ERROR("SSL_CTX_use_PrivateKey_file: %s", ERR_error_string(ERR_get_error(), NULL));
- }
-
- if (SSL_CTX_check_private_key(hub->ssl_ctx) != 1)
- {
- LOG_FATAL("SSL_CTX_check_private_key: Private key does not match the certificate public key: %s", ERR_error_string(ERR_get_error(), NULL));
- return 0;
- }
- LOG_INFO("Enabling TLS, using certificate: %s, private key: %s", config->tls_certificate, config->tls_private_key);
+ return 0;
}
return 1;
}
static void unload_ssl_certificates(struct hub_info* hub)
{
- if (hub->ssl_ctx)
- {
- SSL_CTX_free(hub->ssl_ctx);
- }
+ if (hub->ctx)
+ net_ssl_context_destroy(hub->ctx);
}
-#endif
+#endif /* SSL_SUPPORT */
struct hub_info* hub_start_service(struct hub_config* config)
{
diff --git a/src/core/hub.h b/src/core/hub.h
index b0edee0..cf1cd4b 100644
--- a/src/core/hub.h
+++ b/src/core/hub.h
@@ -1,6 +1,6 @@
/*
* uhub - A tiny ADC p2p connection hub
- * Copyright (C) 2007-2011, Jan Vidar Krey
+ * Copyright (C) 2007-2012, Jan Vidar Krey
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -116,8 +116,7 @@ struct hub_info
struct uhub_plugins* plugins; /* Plug-ins loaded for this hub instance. */
#ifdef SSL_SUPPORT
- SSL_METHOD* ssl_method;
- SSL_CTX* ssl_ctx;
+ struct ssl_context_handle* ctx;
#endif /* SSL_SUPPORT */
};
diff --git a/src/core/probe.c b/src/core/probe.c
index 293cf45..c217d34 100644
--- a/src/core/probe.c
+++ b/src/core/probe.c
@@ -85,7 +85,7 @@ static void probe_net_event(struct net_connection* con, int events, void *arg)
{
probe->connection = 0;
}
- net_con_ssl_handshake(con, net_con_ssl_mode_server, probe->hub->ssl_ctx);
+ net_con_ssl_handshake(con, net_con_ssl_mode_server, probe->hub->ctx);
}
else
{
diff --git a/src/network/backend.c b/src/network/backend.c
index b74d798..e347b3e 100644
--- a/src/network/backend.c
+++ b/src/network/backend.c
@@ -1,6 +1,6 @@
/*
* uhub - A tiny ADC p2p connection hub
- * Copyright (C) 2007-2010, Jan Vidar Krey
+ * Copyright (C) 2007-2012, Jan Vidar Krey
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -181,11 +181,8 @@ void net_con_close(struct net_connection* con)
#ifdef SSL_SUPPORT
if (con->ssl)
- {
- SSL_shutdown(con->ssl);
- SSL_clear(con->ssl);
- }
-#endif
+ net_ssl_shutdown(con);
+#endif /* SSL_SUPPORT */
net_close(con->sd);
con->sd = -1;
diff --git a/src/network/backend.h b/src/network/backend.h
index ba5febe..b908f28 100644
--- a/src/network/backend.h
+++ b/src/network/backend.h
@@ -1,6 +1,6 @@
/*
* uhub - A tiny ADC p2p connection hub
- * Copyright (C) 2007-2010, Jan Vidar Krey
+ * Copyright (C) 2007-2012, Jan Vidar Krey
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/src/network/common.h b/src/network/common.h
index 014ddfb..8270da2 100644
--- a/src/network/common.h
+++ b/src/network/common.h
@@ -1,6 +1,6 @@
/*
* uhub - A tiny ADC p2p connection hub
- * Copyright (C) 2007-2010, Jan Vidar Krey
+ * Copyright (C) 2007-2012, Jan Vidar Krey
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -20,11 +20,10 @@
#define NET_WANT_READ NET_EVENT_READ
#define NET_WANT_WRITE NET_EVENT_WRITE
#define NET_WANT_ACCEPT NET_EVENT_READ
-#define NET_WANT_SSL_READ 0x0010
-#define NET_WANT_SSL_WRITE 0x0020
-#define NET_WANT_SSL_ACCEPT 0x0040
-#define NET_WANT_SSL_CONNECT 0x0080
-#define NET_WANT_SSL_X509_LOOKUP 0x0100
+
+#define NET_SSL_ANY NET_WANT_SSL_READ | NET_WANT_SSL_WRITE | NET_WANT_SSL_ACCEPT | NET_WANT_SSL_CONNECT | NET_WANT_SSL_X509_LOOKUP
+
+struct ssl_handle; /* abstract type */
#define NET_CLEANUP 0x8000
@@ -36,9 +35,7 @@
struct timeout_evt* timeout; /** timeout event handler */
#define NET_CON_STRUCT_SSL \
- SSL* ssl; /** SSL handle */ \
- uint32_t ssl_state; /** SSL state */ \
- size_t write_len; /** Length of last SSL_write(), only used if flags is NET_WANT_SSL_READ. */ \
+ struct ssl_handle* ssl; /** SSL handle */
#ifdef SSL_SUPPORT
#define NET_CON_STRUCT_COMMON \
diff --git a/src/network/connection.c b/src/network/connection.c
index b30b46c..5f664cf 100644
--- a/src/network/connection.c
+++ b/src/network/connection.c
@@ -1,6 +1,6 @@
/*
* uhub - A tiny ADC p2p connection hub
- * Copyright (C) 2007-2010, Jan Vidar Krey
+ * Copyright (C) 2007-2012, Jan Vidar Krey
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -20,132 +20,23 @@
#include "uhub.h"
#include "network/common.h"
-#ifdef SSL_SUPPORT
-
-enum uhub_tls_state
-{
- tls_st_none,
- tls_st_error,
- tls_st_accepting,
- tls_st_connecting,
- tls_st_connected,
- tls_st_disconnecting,
-};
-
-static int handle_openssl_error(struct net_connection* con, int ret)
-{
- uhub_assert(con);
-
- int error = SSL_get_error(con->ssl, ret);
- switch (error)
- {
- case SSL_ERROR_ZERO_RETURN:
- LOG_PROTO("SSL_get_error: ret=%d, error=%d: SSL_ERROR_ZERO_RETURN", ret, error);
- con->ssl_state = tls_st_error;
- return -1;
-
- case SSL_ERROR_WANT_READ:
- LOG_PROTO("SSL_get_error: ret=%d, error=%d: SSL_ERROR_WANT_READ", ret, error);
- con->flags |= NET_WANT_SSL_READ;
- net_con_update(con, NET_EVENT_READ);
- return 0;
-
- case SSL_ERROR_WANT_WRITE:
- LOG_PROTO("SSL_get_error: ret=%d, error=%d: SSL_ERROR_WANT_WRITE", ret, error);
- con->flags |= NET_WANT_SSL_WRITE;
- net_con_update(con, NET_EVENT_READ | NET_EVENT_WRITE);
- return 0;
-
- case SSL_ERROR_SYSCALL:
- LOG_PROTO("SSL_get_error: ret=%d, error=%d: SSL_ERROR_SYSCALL", ret, error);
- /* if ret == 0, connection closed, if ret == -1, check with errno */
- if (ret == 0)
- return -1;
- else
- return -net_error();
-
- case SSL_ERROR_SSL:
- LOG_PROTO("SSL_get_error: ret=%d, error=%d: SSL_ERROR_SSL", ret, error);
- /* internal openssl error */
- con->ssl_state = tls_st_error;
- return -1;
- }
- return -1;
-}
-
-ssize_t net_con_ssl_accept(struct net_connection* con)
-{
- uhub_assert(con);
- con->ssl_state = tls_st_accepting;
- ssize_t ret = SSL_accept(con->ssl);
-#ifdef NETWORK_DUMP_DEBUG
- LOG_PROTO("SSL_accept() ret=%d", ret);
-#endif
- if (ret > 0)
- {
- net_con_update(con, NET_EVENT_READ);
- con->ssl_state = tls_st_connected;
- }
- else
- {
- return handle_openssl_error(con, ret);
- }
- return ret;
-}
-
-ssize_t net_con_ssl_connect(struct net_connection* con)
-{
- uhub_assert(con);
-
- con->ssl_state = tls_st_connecting;
- ssize_t ret = SSL_connect(con->ssl);
-#ifdef NETWORK_DUMP_DEBUG
- LOG_PROTO("SSL_connect() ret=%d", ret);
-#endif
- if (ret > 0)
- {
- con->ssl_state = tls_st_connected;
- net_con_update(con, NET_EVENT_READ);
- }
- else
- {
- return handle_openssl_error(con, ret);
- }
- return ret;
-}
-
-ssize_t net_con_ssl_handshake(struct net_connection* con, enum net_con_ssl_mode ssl_mode, SSL_CTX* ssl_ctx)
-{
- uhub_assert(con);
- SSL* ssl = 0;
-
- if (ssl_mode == net_con_ssl_mode_server)
- {
- ssl = SSL_new(ssl_ctx);
- if (!ssl)
- {
- LOG_ERROR("Unable to create new SSL stream\n");
- return -1;
- }
- SSL_set_fd(ssl, con->sd);
- net_con_set_ssl(con, ssl);
- return net_con_ssl_accept(con);
- }
- else
- {
- ssl = SSL_new(SSL_CTX_new(TLSv1_method()));
- SSL_set_fd(ssl, con->sd);
- net_con_set_ssl(con, ssl);
- return net_con_ssl_connect(con);
- }
-}
-#endif /* SSL_SUPPORT */
-
#ifdef SSL_SUPPORT
void net_stats_add_tx(size_t bytes);
void net_stats_add_rx(size_t bytes);
#endif
+static int is_blocked_or_interrupted()
+{
+ int err = net_error();
+ return
+#ifdef WINSOCK
+ err == WSAEWOULDBLOCK
+#else
+ err == EWOULDBLOCK
+#endif
+ || err == EINTR;
+}
+
ssize_t net_con_send(struct net_connection* con, const void* buf, size_t len)
{
int ret;
@@ -156,13 +47,7 @@ ssize_t net_con_send(struct net_connection* con, const void* buf, size_t len)
ret = net_send(con->sd, buf, len, UHUB_SEND_SIGNAL);
if (ret == -1)
{
- if (
-#ifdef WINSOCK
- net_error() == WSAEWOULDBLOCK
-#else
- net_error() == EWOULDBLOCK
-#endif
- || net_error() == EINTR)
+ if (is_blocked_or_interrupted())
return 0;
return -1;
}
@@ -170,19 +55,9 @@ ssize_t net_con_send(struct net_connection* con, const void* buf, size_t len)
}
else
{
- con->write_len = len;
- ret = SSL_write(con->ssl, buf, len);
- LOG_PROTO("SSL_write(con=%p, buf=%p, len=" PRINTF_SIZE_T ") => %d", con, buf, len, ret);
- if (ret <= 0)
- {
- return handle_openssl_error(con, ret);
- }
- else
- {
- net_stats_add_tx(ret);
- }
+ ret = net_ssl_send(con, buf, len);
}
-#endif
+#endif /* SSL_SUPPORT */
return ret;
}
@@ -190,19 +65,13 @@ ssize_t net_con_recv(struct net_connection* con, void* buf, size_t len)
{
int ret;
#ifdef SSL_SUPPORT
- if (!net_con_is_ssl(con))
+ if (!con->ssl)
{
#endif
ret = net_recv(con->sd, buf, len, 0);
if (ret == -1)
{
- if (
-#ifdef WINSOCK
- net_error() == WSAEWOULDBLOCK
-#else
- net_error() == EWOULDBLOCK
-#endif
- || net_error() == EINTR)
+ if (is_blocked_or_interrupted())
return 0;
return -net_error();
}
@@ -214,22 +83,9 @@ ssize_t net_con_recv(struct net_connection* con, void* buf, size_t len)
}
else
{
- if (con->ssl_state == tls_st_error)
- return -1;
-
- ret = SSL_read(con->ssl, buf, len);
- LOG_PROTO("SSL_read(con=%p, buf=%p, len=" PRINTF_SIZE_T ") => %d", con, buf, len, ret);
- if (ret > 0)
- {
- net_con_update(con, NET_EVENT_READ);
- net_stats_add_rx(ret);
- }
- else
- {
- return handle_openssl_error(con, ret);
- }
+ ret = net_ssl_recv(con, buf, len);
}
-#endif
+#endif /* SSL_SUPPORT */
return ret;
}
@@ -238,13 +94,7 @@ ssize_t net_con_peek(struct net_connection* con, void* buf, size_t len)
int ret = net_recv(con->sd, buf, len, MSG_PEEK);
if (ret == -1)
{
- if (
-#ifdef WINSOCK
- net_error() == WSAEWOULDBLOCK
-#else
- net_error() == EWOULDBLOCK
-#endif
- || net_error() == EINTR)
+ if (is_blocked_or_interrupted())
return 0;
return -net_error();
}
@@ -254,19 +104,10 @@ ssize_t net_con_peek(struct net_connection* con, void* buf, size_t len)
}
#ifdef SSL_SUPPORT
+
int net_con_is_ssl(struct net_connection* con)
{
- return con->ssl != 0;
-}
-
-SSL* net_con_get_ssl(struct net_connection* con)
-{
- return con->ssl;
-}
-
-void net_con_set_ssl(struct net_connection* con, SSL* ssl)
-{
- con->ssl = ssl;
+ return !!con->ssl;
}
#endif /* SSL_SUPPORT */
@@ -283,7 +124,8 @@ void* net_con_get_ptr(struct net_connection* con)
void net_con_destroy(struct net_connection* con)
{
#ifdef SSL_SUPPORT
- SSL_free(con->ssl);
+ if (con->ssl)
+ net_ssl_destroy(con);
#endif
hub_free(con);
}
@@ -301,62 +143,10 @@ void net_con_callback(struct net_connection* con, int events)
}
#ifdef SSL_SUPPORT
- if (!con->ssl)
- {
+ if (con->ssl)
+ net_ssl_callback(con, events);
+ else
#endif
con->callback(con, events, con->ptr);
-#ifdef SSL_SUPPORT
- }
- else
- {
-#ifdef NETWORK_DUMP_DEBUG
- LOG_PROTO("net_con_event: events=%d, con=%p, state=%d", events, con, con->ssl_state);
-#endif
- switch (con->ssl_state)
- {
- case tls_st_none:
- con->callback(con, events, con->ptr);
- break;
-
- case tls_st_error:
- con->callback(con, NET_EVENT_READ, con->ptr);
- break;
-
- case tls_st_accepting:
- if (net_con_ssl_accept(con) < 0)
- {
- con->callback(con, NET_EVENT_READ, con->ptr);
- }
- break;
-
- case tls_st_connecting:
- if (net_con_ssl_connect(con) < 0)
- {
- con->callback(con, NET_EVENT_READ, con->ptr);
- }
- break;
-
- case tls_st_connected:
- LOG_PROTO("tls_st_connected, events=%s%s, ssl_flags=%s%s", (events & NET_EVENT_READ ? "R" : ""), (events & NET_EVENT_WRITE ? "W" : ""), con->flags & NET_WANT_SSL_READ ? "R" : "", con->flags & NET_WANT_SSL_WRITE ? "W" : "");
- if (events & NET_EVENT_WRITE && con->flags & NET_WANT_SSL_READ)
- {
- con->callback(con, events & NET_EVENT_READ, con->ptr);
- return;
- }
-
- if (events & NET_EVENT_READ && con->flags & NET_WANT_SSL_WRITE)
- {
- con->callback(con, events & NET_EVENT_READ, con->ptr);
- return;
- }
-
- con->callback(con, events, con->ptr);
- break;
-
- case tls_st_disconnecting:
- return;
- }
- }
-#endif
}
diff --git a/src/network/connection.h b/src/network/connection.h
index ff69262..84cc96a 100644
--- a/src/network/connection.h
+++ b/src/network/connection.h
@@ -1,6 +1,6 @@
/*
* uhub - A tiny ADC p2p connection hub
- * Copyright (C) 2007-2010, Jan Vidar Krey
+ * Copyright (C) 2007-2012, Jan Vidar Krey
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -23,6 +23,7 @@
#include "uhub.h"
#include "network/common.h"
#include "network/backend.h"
+#include "network/tls.h"
#define NET_EVENT_TIMEOUT 0x0001
#define NET_EVENT_READ 0x0002
@@ -83,29 +84,5 @@ extern ssize_t net_con_peek(struct net_connection* con, void* buf, size_t len);
extern void net_con_set_timeout(struct net_connection* con, int seconds);
extern void net_con_clear_timeout(struct net_connection* con);
-#ifdef SSL_SUPPORT
-/**
- * Start SSL_accept()
- */
-extern ssize_t net_con_ssl_accept(struct net_connection*);
-
-/**
- * Start SSL_connect()
- */
-extern ssize_t net_con_ssl_connect(struct net_connection*);
-
-enum net_con_ssl_mode
-{
- net_con_ssl_mode_server,
- net_con_ssl_mode_client,
-};
-
-extern ssize_t net_con_ssl_handshake(struct net_connection* con, enum net_con_ssl_mode, SSL_CTX* ssl_ctx);
-
-extern int net_con_is_ssl(struct net_connection* con);
-extern SSL* net_con_get_ssl(struct net_connection* con);
-extern void net_con_set_ssl(struct net_connection* con, SSL*);
-#endif /* SSL_SUPPORT */
-
#endif /* HAVE_UHUB_NETWORK_CONNECTION_H */
diff --git a/src/network/network.c b/src/network/network.c
index a7164d6..8268934 100644
--- a/src/network/network.c
+++ b/src/network/network.c
@@ -59,9 +59,11 @@ int net_initialize()
net_stats_initialize();
#ifdef SSL_SUPPORT
+#ifdef SSL_USE_OPENSSL
LOG_TRACE("Initializing OpenSSL...");
SSL_library_init();
SSL_load_error_strings();
+#endif /* SSL_USE_OPENSSL */
#endif /* SSL_SUPPORT */
net_initialized = 1;
@@ -100,10 +102,12 @@ int net_destroy()
net_backend_shutdown();
#ifdef SSL_SUPPORT
+#ifdef SSL_USE_OPENSSL
ERR_free_strings();
EVP_cleanup();
CRYPTO_cleanup_all_ex_data();
-#endif
+#endif /* SSL_USE_OPENSSL */
+#endif /* SSL_SUPPORT */
#ifdef WINSOCK
WSACleanup();
diff --git a/src/network/openssl.c b/src/network/openssl.c
new file mode 100644
index 0000000..78f6a5d
--- /dev/null
+++ b/src/network/openssl.c
@@ -0,0 +1,305 @@
+/*
+ * uhub - A tiny ADC p2p connection hub
+ * Copyright (C) 2007-2012, Jan Vidar Krey
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+#include "uhub.h"
+#include "network/common.h"
+#include "network/tls.h"
+
+#ifdef SSL_SUPPORT
+#ifdef SSL_USE_OPENSSL
+
+#define NETWORK_DUMP_DEBUG
+
+struct net_ssl_openssl
+{
+ SSL* ssl;
+ enum ssl_state state;
+ uint32_t flags;
+ BIO* biow;
+ BIO* bior;
+};
+
+struct net_context_openssl
+{
+ SSL_METHOD* ssl_method;
+ SSL_CTX* ssl_ctx;
+};
+
+static struct net_ssl_openssl* get_handle(struct net_connection* con)
+{
+ uhub_assert(con);
+ return (struct net_ssl_openssl*) con->ssl;
+}
+
+const char* net_ssl_get_provider()
+{
+ return OPENSSL_VERSION_TEXT;
+}
+
+
+/**
+ * Create a new SSL context.
+ */
+struct ssl_context_handle* net_ssl_context_create()
+{
+
+ struct net_context_openssl* ctx = (struct net_context_openssl*) hub_malloc_zero(sizeof(struct net_context_openssl));
+ ctx->ssl_method = (SSL_METHOD*) SSLv23_method(); /* TLSv1_method() */
+ ctx->ssl_ctx = SSL_CTX_new(ctx->ssl_method);
+
+ /* Disable SSLv2 */
+ SSL_CTX_set_options(ctx->ssl_ctx, SSL_OP_NO_SSLv2);
+ SSL_CTX_set_quiet_shutdown(ctx->ssl_ctx, 1);
+
+ return (struct ssl_context_handle*) ctx;
+}
+
+extern void net_ssl_context_destroy(struct ssl_context_handle* ctx_)
+{
+ struct net_context_openssl* ctx = (struct net_context_openssl*) ctx_;
+ SSL_CTX_free(ctx->ssl_ctx);
+ hub_free(ctx);
+}
+
+int ssl_load_certificate(struct ssl_context_handle* ctx_, const char* pem_file)
+{
+ struct net_context_openssl* ctx = (struct net_context_openssl*) ctx_;
+ if (SSL_CTX_use_certificate_file(ctx->ssl_ctx, pem_file, SSL_FILETYPE_PEM) < 0)
+ {
+ LOG_ERROR("SSL_CTX_use_certificate_file: %s", ERR_error_string(ERR_get_error(), NULL));
+ return 0;
+ }
+
+ return 1;
+}
+
+int ssl_load_private_key(struct ssl_context_handle* ctx_, const char* pem_file)
+{
+ struct net_context_openssl* ctx = (struct net_context_openssl*) ctx_;
+ if (SSL_CTX_use_PrivateKey_file(ctx->ssl_ctx, pem_file, SSL_FILETYPE_PEM) < 0)
+ {
+ LOG_ERROR("SSL_CTX_use_PrivateKey_file: %s", ERR_error_string(ERR_get_error(), NULL));
+ return 0;
+ }
+ return 1;
+}
+
+int ssl_check_private_key(struct ssl_context_handle* ctx_)
+{
+ struct net_context_openssl* ctx = (struct net_context_openssl*) ctx_;
+ if (SSL_CTX_check_private_key(ctx->ssl_ctx) != 1)
+ {
+ LOG_FATAL("SSL_CTX_check_private_key: Private key does not match the certificate public key: %s", ERR_error_string(ERR_get_error(), NULL));
+ return 0;
+ }
+ return 1;
+}
+
+static int handle_openssl_error(struct net_connection* con, int ret, enum ssl_state forced_rwstate)
+{
+ struct net_ssl_openssl* handle = get_handle(con);
+ int err = SSL_get_error(handle->ssl, ret);
+ switch (err)
+ {
+ case SSL_ERROR_ZERO_RETURN:
+ // Not really an error, but SSL was shut down.
+ return -1;
+
+ case SSL_ERROR_WANT_READ:
+ handle->state = forced_rwstate;
+ net_con_update(con, NET_EVENT_READ);
+ return 0;
+
+ case SSL_ERROR_WANT_WRITE:
+ handle->state = forced_rwstate;
+ net_con_update(con, NET_EVENT_WRITE);
+ return 0;
+
+ case SSL_ERROR_SYSCALL:
+ handle->state = tls_st_error;
+ return -2;
+ }
+}
+
+ssize_t net_con_ssl_accept(struct net_connection* con)
+{
+ struct net_ssl_openssl* handle = get_handle(con);
+ handle->state = tls_st_accepting;
+ ssize_t ret;
+
+ ret = SSL_accept(handle->ssl);
+ LOG_PROTO("SSL_accept() ret=%d", ret);
+ if (ret > 0)
+ {
+ net_con_update(con, NET_EVENT_READ);
+ handle->state = tls_st_connected;
+ return ret;
+ }
+ return handle_openssl_error(con, ret, tls_st_accepting);
+}
+
+ssize_t net_con_ssl_connect(struct net_connection* con)
+{
+ struct net_ssl_openssl* handle = get_handle(con);
+ ssize_t ret;
+ handle->state = tls_st_connecting;
+
+ ret = SSL_connect(handle->ssl);
+#ifdef NETWORK_DUMP_DEBUG
+ LOG_PROTO("SSL_connect() ret=%d", ret);
+#endif /* NETWORK_DUMP_DEBUG */
+
+ if (ret > 0)
+ {
+ handle->state = tls_st_connected;
+ net_con_update(con, NET_EVENT_READ);
+ return ret;
+ }
+ return handle_openssl_error(con, ret, tls_st_connecting);
+}
+
+ssize_t net_con_ssl_handshake(struct net_connection* con, enum net_con_ssl_mode ssl_mode, struct ssl_context_handle* ssl_ctx)
+{
+ uhub_assert(con);
+
+ struct net_context_openssl* ctx = (struct net_context_openssl*) ssl_ctx;
+ struct net_ssl_openssl* handle = (struct net_ssl_openssl*) hub_malloc_zero(sizeof(struct net_ssl_openssl));
+
+ if (ssl_mode == net_con_ssl_mode_server)
+ {
+ handle->ssl = SSL_new(ctx->ssl_ctx);
+ if (!handle->ssl)
+ {
+ LOG_ERROR("Unable to create new SSL stream\n");
+ return -1;
+ }
+ SSL_set_fd(handle->ssl, con->sd);
+ handle->bior = SSL_get_rbio(handle->ssl);
+ handle->biow = SSL_get_wbio(handle->ssl);
+ con->ssl = (struct ssl_handle*) handle;
+ return net_con_ssl_accept(con);
+ }
+ else
+ {
+ handle->ssl = SSL_new(SSL_CTX_new(TLSv1_method()));
+ SSL_set_fd(handle->ssl, con->sd);
+ handle->bior = SSL_get_rbio(handle->ssl);
+ handle->biow = SSL_get_wbio(handle->ssl);
+ con->ssl = (struct ssl_handle*) handle;
+ return net_con_ssl_connect(con);
+ }
+
+}
+
+ssize_t net_ssl_send(struct net_connection* con, const void* buf, size_t len)
+{
+ struct net_ssl_openssl* handle = get_handle(con);
+
+ uhub_assert(handle->state == tls_st_connected || handle->state == tls_st_need_write);
+
+ ERR_clear_error();
+ ssize_t ret = SSL_write(handle->ssl, buf, len);
+ LOG_PROTO("SSL_write(con=%p, buf=%p, len=" PRINTF_SIZE_T ") => %d", con, buf, len, ret);
+ if (ret > 0)
+ {
+ handle->state = tls_st_connected;
+ return ret;
+ }
+ return handle_openssl_error(con, ret, tls_st_need_write);
+}
+
+ssize_t net_ssl_recv(struct net_connection* con, void* buf, size_t len)
+{
+ struct net_ssl_openssl* handle = get_handle(con);
+ ssize_t ret;
+
+ if (handle->state == tls_st_error)
+ return -2;
+
+ uhub_assert(handle->state == tls_st_connected || handle->state == tls_st_need_read);
+
+ ERR_clear_error();
+
+ ret = SSL_read(handle->ssl, buf, len);
+ LOG_PROTO("SSL_read(con=%p, buf=%p, len=" PRINTF_SIZE_T ") => %d", con, buf, len, ret);
+ if (ret > 0)
+ {
+ handle->state = tls_st_connected;
+ return ret;
+ }
+ return handle_openssl_error(con, ret, tls_st_need_read);
+}
+
+void net_ssl_shutdown(struct net_connection* con)
+{
+ struct net_ssl_openssl* handle = get_handle(con);
+ SSL_shutdown(handle->ssl);
+ SSL_clear(handle->ssl);
+}
+
+void net_ssl_destroy(struct net_connection* con)
+{
+ struct net_ssl_openssl* handle = get_handle(con);
+ SSL_free(handle->ssl);
+}
+
+void net_ssl_callback(struct net_connection* con, int events)
+{
+ struct net_ssl_openssl* handle = get_handle(con);
+
+ switch (handle->state)
+ {
+ case tls_st_none:
+ con->callback(con, events, con->ptr);
+ break;
+
+ case tls_st_error:
+ con->callback(con, NET_EVENT_READ, con->ptr);
+ break;
+
+ case tls_st_accepting:
+ if (net_con_ssl_accept(con) != 0)
+ con->callback(con, NET_EVENT_READ, con->ptr);
+ break;
+
+ case tls_st_connecting:
+ if (net_con_ssl_connect(con) != 0)
+ con->callback(con, NET_EVENT_READ, con->ptr);
+ break;
+
+ case tls_st_need_read:
+ con->callback(con, NET_EVENT_READ, con->ptr);
+ break;
+
+ case tls_st_need_write:
+ con->callback(con, NET_EVENT_WRITE, con->ptr);
+ break;
+
+ case tls_st_connected:
+ con->callback(con, events, con->ptr);
+ break;
+
+ case tls_st_disconnecting:
+ return;
+ }
+}
+
+
+#endif /* SSL_USE_OPENSSL */
+#endif /* SSL_SUPPORT */
\ No newline at end of file
diff --git a/src/network/tls.h b/src/network/tls.h
new file mode 100644
index 0000000..25391a4
--- /dev/null
+++ b/src/network/tls.h
@@ -0,0 +1,101 @@
+/*
+ * uhub - A tiny ADC p2p connection hub
+ * Copyright (C) 2007-2012, Jan Vidar Krey
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+#ifndef HAVE_UHUB_NETWORK_TLS_H
+#define HAVE_UHUB_NETWORK_TLS_H
+
+#include "uhub.h"
+
+#ifdef SSL_SUPPORT
+
+
+enum ssl_state
+{
+ tls_st_none,
+ tls_st_error,
+ tls_st_accepting,
+ tls_st_connecting,
+ tls_st_connected,
+ tls_st_need_read, /* special case of connected */
+ tls_st_need_write, /* special case of connected */
+ tls_st_disconnecting,
+};
+
+enum net_con_ssl_mode
+{
+ net_con_ssl_mode_server,
+ net_con_ssl_mode_client,
+};
+
+struct ssl_context_handle;
+
+/**
+ * Returns a string describing the TLS/SSL provider information
+ */
+extern const char* net_ssl_get_provider();
+
+/**
+ * Create a new SSL context.
+ */
+extern struct ssl_context_handle* net_ssl_context_create();
+extern void net_ssl_context_destroy(struct ssl_context_handle* ctx);
+
+/**
+ * Return 0 on error, 1 otherwise.
+ */
+extern int ssl_load_certificate(struct ssl_context_handle* ctx, const char* pem_file);
+
+/**
+ * Return 0 on error, 1 otherwise.
+ */
+extern int ssl_load_private_key(struct ssl_context_handle* ctx, const char* pem_file);
+
+/**
+ * Return 0 if private key does not match certificate, 1 if everything is OK.
+ */
+extern int ssl_check_private_key(struct ssl_context_handle* ctx);
+
+/**
+ * Start SSL_accept()
+ */
+extern ssize_t net_con_ssl_accept(struct net_connection*);
+
+/**
+ * Start SSL_connect()
+ */
+extern ssize_t net_con_ssl_connect(struct net_connection*);
+
+extern ssize_t net_ssl_send(struct net_connection* con, const void* buf, size_t len);
+extern ssize_t net_ssl_recv(struct net_connection* con, void* buf, size_t len);
+
+extern void net_ssl_shutdown(struct net_connection* con);
+extern void net_ssl_destroy(struct net_connection* con);
+extern void net_ssl_callback(struct net_connection* con, int events);
+
+
+
+extern ssize_t net_con_ssl_handshake(struct net_connection* con, enum net_con_ssl_mode, struct ssl_context_handle* ssl_ctx);
+extern SSL* net_con_get_ssl(struct net_connection* con);
+#ifdef SSL_USE_OPENSSL
+extern void net_con_set_ssl(struct net_connection* con, SSL*);
+#endif // SSL_USE_OPENSSL
+extern int net_con_is_ssl(struct net_connection* con);
+
+#endif /* SSL_SUPPORT */
+#endif /* HAVE_UHUB_NETWORK_TLS_H */
\ No newline at end of file
diff --git a/src/system.h b/src/system.h
index 12e5b3c..75542c1 100644
--- a/src/system.h
+++ b/src/system.h
@@ -99,8 +99,13 @@
#endif
#ifdef SSL_SUPPORT
+#ifdef SSL_USE_OPENSSL
#include
#include
+#endif /* SSL_USE_OPENSSL */
+#ifdef SSL_USE_GNUTLS
+#include
+#endif /* SSL_USE_GNUTLS */
#endif
#include "version.h"
diff --git a/src/tools/adcclient.c b/src/tools/adcclient.c
index 69bb8e4..a320da9 100644
--- a/src/tools/adcclient.c
+++ b/src/tools/adcclient.c
@@ -65,10 +65,6 @@ struct ADC_client
char* desc;
int flags;
void* ptr;
-#ifdef SSL_SUPPORT
- const SSL_METHOD* ssl_method;
- SSL_CTX* ssl_ctx;
-#endif /* SSL_SUPPORT */
};
@@ -522,15 +518,7 @@ struct ADC_client* ADC_client_create(const char* nickname, const char* descripti
if (sd == -1) return NULL;
client->con = net_con_create();
-#if 0
- /* FIXME */
- client->timer = 0; /* FIXME: hub_malloc(sizeof(struct net_timer)); */
-#endif
net_con_initialize(client->con, sd, event_callback, client, 0);
-#if 0
- /* FIXME */
- net_timer_initialize(client->timer, timer_callback, client);
-#endif
ADC_client_set_state(client, ps_none);
client->nick = hub_strdup(nickname);
@@ -547,10 +535,6 @@ void ADC_client_destroy(struct ADC_client* client)
{
ADC_TRACE;
ADC_client_disconnect(client);
-#if 0
- /* FIXME */
- net_timer_shutdown(client->timer);
-#endif
ioq_send_destroy(client->send_queue);
ioq_recv_destroy(client->recv_queue);
hub_free(client->timer);
@@ -598,6 +582,8 @@ static void ADC_client_on_connected(struct ADC_client* client)
net_con_update(client->con, NET_EVENT_READ | NET_EVENT_WRITE);
client->callback(client, ADC_CLIENT_SSL_HANDSHAKE, 0);
ADC_client_set_state(client, ps_conn_ssl);
+
+ net_con_ssl_handshake(client->con, net_con_ssl_mode_client, NULL);
}
else
#endif
@@ -613,9 +599,9 @@ static void ADC_client_on_connected(struct ADC_client* client)
static void ADC_client_on_connected_ssl(struct ADC_client* client)
{
ADC_TRACE;
- net_con_update(client->con, NET_EVENT_READ);
client->callback(client, ADC_CLIENT_SSL_OK, 0);
client->callback(client, ADC_CLIENT_CONNECTED, 0);
+ net_con_update(client->con, NET_EVENT_READ);
ADC_client_send(client, adc_msg_create(ADC_HANDSHAKE));
ADC_client_set_state(client, ps_protocol);
}
@@ -727,4 +713,4 @@ const char* ADC_client_get_description(const struct ADC_client* client)
void* ADC_client_get_ptr(const struct ADC_client* client)
{
return client->ptr;
-}
\ No newline at end of file
+}