Merge branch 'gnutls_work'

This commit is contained in:
Jan Vidar Krey 2012-10-17 15:47:16 +02:00
commit 46d365cafe
14 changed files with 499 additions and 335 deletions

View File

@ -17,13 +17,21 @@ set (PROJECT_SOURCE_DIR "${CMAKE_SOURCE_DIR}/src")
option(RELEASE "Release build, debug build if disabled" ON) option(RELEASE "Release build, debug build if disabled" ON)
option(LINK_SUPPORT "Allow hub linking" OFF) option(LINK_SUPPORT "Allow hub linking" OFF)
option(SSL_SUPPORT "Enable SSL support" ON) option(SSL_SUPPORT "Enable SSL support" ON)
option(USE_OPENSSL "Use OpenSSL's SSL support" OFF)
option(SQLITE_SUPPORT "Enable SQLite support" ON) option(SQLITE_SUPPORT "Enable SQLite support" ON)
option(ADC_STRESS "Enable the stress tester client" OFF) option(ADC_STRESS "Enable the stress tester client" OFF)
find_package(Git) find_package(Git)
if (SSL_SUPPORT) 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() endif()
if (MSVC) if (MSVC)
@ -41,6 +49,7 @@ set (network_SOURCES
${PROJECT_SOURCE_DIR}/network/timeout.c ${PROJECT_SOURCE_DIR}/network/timeout.c
${PROJECT_SOURCE_DIR}/network/timer.c ${PROJECT_SOURCE_DIR}/network/timer.c
${PROJECT_SOURCE_DIR}/network/network.c ${PROJECT_SOURCE_DIR}/network/network.c
${PROJECT_SOURCE_DIR}/network/openssl.c
${PROJECT_SOURCE_DIR}/network/ipcalc.c ${PROJECT_SOURCE_DIR}/network/ipcalc.c
) )
@ -156,16 +165,26 @@ else()
endif() endif()
if(OPENSSL_FOUND) 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}) 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) if(UNIX)
target_link_libraries(uhub-admin ${OPENSSL_LIBRARIES}) target_link_libraries(uhub-admin ${SSL_LIBS})
endif() endif()
target_link_libraries(mod_welcome ${OPENSSL_LIBRARIES}) target_link_libraries(mod_welcome ${SSL_LIBS})
target_link_libraries(mod_logging ${OPENSSL_LIBRARIES}) target_link_libraries(mod_logging ${SSL_LIBS})
if (ADC_STRESS) if (ADC_STRESS)
target_link_libraries(adcrush ${OPENSSL_LIBRARIES}) target_link_libraries(adcrush ${SSL_LIBS})
endif() endif()
endif() endif()

View File

@ -731,41 +731,25 @@ static int load_ssl_certificates(struct hub_info* hub, struct hub_config* config
{ {
if (config->tls_enable) if (config->tls_enable)
{ {
hub->ssl_method = (SSL_METHOD*) SSLv23_method(); /* TLSv1_method() */ hub->ctx = net_ssl_context_create();
hub->ssl_ctx = SSL_CTX_new(hub->ssl_method); if (ssl_load_certificate(hub->ctx, config->tls_certificate) &&
ssl_load_private_key(hub->ctx, config->tls_private_key) &&
/* Disable SSLv2 */ ssl_check_private_key(hub->ctx))
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)
{ {
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; return 0;
} }
LOG_INFO("Enabling TLS, using certificate: %s, private key: %s", config->tls_certificate, config->tls_private_key);
}
return 1; return 1;
} }
static void unload_ssl_certificates(struct hub_info* hub) static void unload_ssl_certificates(struct hub_info* hub)
{ {
if (hub->ssl_ctx) if (hub->ctx)
{ net_ssl_context_destroy(hub->ctx);
SSL_CTX_free(hub->ssl_ctx);
}
} }
#endif #endif /* SSL_SUPPORT */
struct hub_info* hub_start_service(struct hub_config* config) struct hub_info* hub_start_service(struct hub_config* config)
{ {

View File

@ -1,6 +1,6 @@
/* /*
* uhub - A tiny ADC p2p connection hub * 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 * 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 * 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. */ struct uhub_plugins* plugins; /* Plug-ins loaded for this hub instance. */
#ifdef SSL_SUPPORT #ifdef SSL_SUPPORT
SSL_METHOD* ssl_method; struct ssl_context_handle* ctx;
SSL_CTX* ssl_ctx;
#endif /* SSL_SUPPORT */ #endif /* SSL_SUPPORT */
}; };

View File

@ -85,7 +85,7 @@ static void probe_net_event(struct net_connection* con, int events, void *arg)
{ {
probe->connection = 0; 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 else
{ {

View File

@ -1,6 +1,6 @@
/* /*
* uhub - A tiny ADC p2p connection hub * 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 * 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 * 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 #ifdef SSL_SUPPORT
if (con->ssl) if (con->ssl)
{ net_ssl_shutdown(con);
SSL_shutdown(con->ssl); #endif /* SSL_SUPPORT */
SSL_clear(con->ssl);
}
#endif
net_close(con->sd); net_close(con->sd);
con->sd = -1; con->sd = -1;

View File

@ -1,6 +1,6 @@
/* /*
* uhub - A tiny ADC p2p connection hub * 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 * 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 * it under the terms of the GNU General Public License as published by

View File

@ -1,6 +1,6 @@
/* /*
* uhub - A tiny ADC p2p connection hub * 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 * 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 * 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_READ NET_EVENT_READ
#define NET_WANT_WRITE NET_EVENT_WRITE #define NET_WANT_WRITE NET_EVENT_WRITE
#define NET_WANT_ACCEPT NET_EVENT_READ #define NET_WANT_ACCEPT NET_EVENT_READ
#define NET_WANT_SSL_READ 0x0010
#define NET_WANT_SSL_WRITE 0x0020 #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
#define NET_WANT_SSL_ACCEPT 0x0040
#define NET_WANT_SSL_CONNECT 0x0080 struct ssl_handle; /* abstract type */
#define NET_WANT_SSL_X509_LOOKUP 0x0100
#define NET_CLEANUP 0x8000 #define NET_CLEANUP 0x8000
@ -36,9 +35,7 @@
struct timeout_evt* timeout; /** timeout event handler */ struct timeout_evt* timeout; /** timeout event handler */
#define NET_CON_STRUCT_SSL \ #define NET_CON_STRUCT_SSL \
SSL* ssl; /** SSL handle */ \ struct ssl_handle* 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. */ \
#ifdef SSL_SUPPORT #ifdef SSL_SUPPORT
#define NET_CON_STRUCT_COMMON \ #define NET_CON_STRUCT_COMMON \

View File

@ -1,6 +1,6 @@
/* /*
* uhub - A tiny ADC p2p connection hub * 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 * 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 * it under the terms of the GNU General Public License as published by
@ -20,132 +20,23 @@
#include "uhub.h" #include "uhub.h"
#include "network/common.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 #ifdef SSL_SUPPORT
void net_stats_add_tx(size_t bytes); void net_stats_add_tx(size_t bytes);
void net_stats_add_rx(size_t bytes); void net_stats_add_rx(size_t bytes);
#endif #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) ssize_t net_con_send(struct net_connection* con, const void* buf, size_t len)
{ {
int ret; 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); ret = net_send(con->sd, buf, len, UHUB_SEND_SIGNAL);
if (ret == -1) if (ret == -1)
{ {
if ( if (is_blocked_or_interrupted())
#ifdef WINSOCK
net_error() == WSAEWOULDBLOCK
#else
net_error() == EWOULDBLOCK
#endif
|| net_error() == EINTR)
return 0; return 0;
return -1; return -1;
} }
@ -170,19 +55,9 @@ ssize_t net_con_send(struct net_connection* con, const void* buf, size_t len)
} }
else else
{ {
con->write_len = len; ret = net_ssl_send(con, buf, 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 #endif /* SSL_SUPPORT */
{
net_stats_add_tx(ret);
}
}
#endif
return ret; return ret;
} }
@ -190,19 +65,13 @@ ssize_t net_con_recv(struct net_connection* con, void* buf, size_t len)
{ {
int ret; int ret;
#ifdef SSL_SUPPORT #ifdef SSL_SUPPORT
if (!net_con_is_ssl(con)) if (!con->ssl)
{ {
#endif #endif
ret = net_recv(con->sd, buf, len, 0); ret = net_recv(con->sd, buf, len, 0);
if (ret == -1) if (ret == -1)
{ {
if ( if (is_blocked_or_interrupted())
#ifdef WINSOCK
net_error() == WSAEWOULDBLOCK
#else
net_error() == EWOULDBLOCK
#endif
|| net_error() == EINTR)
return 0; return 0;
return -net_error(); return -net_error();
} }
@ -214,22 +83,9 @@ ssize_t net_con_recv(struct net_connection* con, void* buf, size_t len)
} }
else else
{ {
if (con->ssl_state == tls_st_error) ret = net_ssl_recv(con, buf, len);
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 #endif /* SSL_SUPPORT */
{
return handle_openssl_error(con, ret);
}
}
#endif
return ret; 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); int ret = net_recv(con->sd, buf, len, MSG_PEEK);
if (ret == -1) if (ret == -1)
{ {
if ( if (is_blocked_or_interrupted())
#ifdef WINSOCK
net_error() == WSAEWOULDBLOCK
#else
net_error() == EWOULDBLOCK
#endif
|| net_error() == EINTR)
return 0; return 0;
return -net_error(); return -net_error();
} }
@ -254,19 +104,10 @@ ssize_t net_con_peek(struct net_connection* con, void* buf, size_t len)
} }
#ifdef SSL_SUPPORT #ifdef SSL_SUPPORT
int net_con_is_ssl(struct net_connection* con) int net_con_is_ssl(struct net_connection* con)
{ {
return con->ssl != 0; return !!con->ssl;
}
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;
} }
#endif /* SSL_SUPPORT */ #endif /* SSL_SUPPORT */
@ -283,7 +124,8 @@ void* net_con_get_ptr(struct net_connection* con)
void net_con_destroy(struct net_connection* con) void net_con_destroy(struct net_connection* con)
{ {
#ifdef SSL_SUPPORT #ifdef SSL_SUPPORT
SSL_free(con->ssl); if (con->ssl)
net_ssl_destroy(con);
#endif #endif
hub_free(con); hub_free(con);
} }
@ -301,62 +143,10 @@ void net_con_callback(struct net_connection* con, int events)
} }
#ifdef SSL_SUPPORT #ifdef SSL_SUPPORT
if (!con->ssl) if (con->ssl)
{ net_ssl_callback(con, events);
#endif
con->callback(con, events, con->ptr);
#ifdef SSL_SUPPORT
}
else else
{
#ifdef NETWORK_DUMP_DEBUG
LOG_PROTO("net_con_event: events=%d, con=%p, state=%d", events, con, con->ssl_state);
#endif #endif
switch (con->ssl_state)
{
case tls_st_none:
con->callback(con, events, con->ptr); 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
} }

View File

@ -1,6 +1,6 @@
/* /*
* uhub - A tiny ADC p2p connection hub * 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 * 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 * it under the terms of the GNU General Public License as published by
@ -23,6 +23,7 @@
#include "uhub.h" #include "uhub.h"
#include "network/common.h" #include "network/common.h"
#include "network/backend.h" #include "network/backend.h"
#include "network/tls.h"
#define NET_EVENT_TIMEOUT 0x0001 #define NET_EVENT_TIMEOUT 0x0001
#define NET_EVENT_READ 0x0002 #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_set_timeout(struct net_connection* con, int seconds);
extern void net_con_clear_timeout(struct net_connection* con); 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 */ #endif /* HAVE_UHUB_NETWORK_CONNECTION_H */

View File

@ -59,9 +59,11 @@ int net_initialize()
net_stats_initialize(); net_stats_initialize();
#ifdef SSL_SUPPORT #ifdef SSL_SUPPORT
#ifdef SSL_USE_OPENSSL
LOG_TRACE("Initializing OpenSSL..."); LOG_TRACE("Initializing OpenSSL...");
SSL_library_init(); SSL_library_init();
SSL_load_error_strings(); SSL_load_error_strings();
#endif /* SSL_USE_OPENSSL */
#endif /* SSL_SUPPORT */ #endif /* SSL_SUPPORT */
net_initialized = 1; net_initialized = 1;
@ -100,10 +102,12 @@ int net_destroy()
net_backend_shutdown(); net_backend_shutdown();
#ifdef SSL_SUPPORT #ifdef SSL_SUPPORT
#ifdef SSL_USE_OPENSSL
ERR_free_strings(); ERR_free_strings();
EVP_cleanup(); EVP_cleanup();
CRYPTO_cleanup_all_ex_data(); CRYPTO_cleanup_all_ex_data();
#endif #endif /* SSL_USE_OPENSSL */
#endif /* SSL_SUPPORT */
#ifdef WINSOCK #ifdef WINSOCK
WSACleanup(); WSACleanup();

305
src/network/openssl.c Normal file
View File

@ -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 <http://www.gnu.org/licenses/>.
*
*/
#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 */

101
src/network/tls.h Normal file
View File

@ -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 <http://www.gnu.org/licenses/>.
*
*/
#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 */

View File

@ -99,8 +99,13 @@
#endif #endif
#ifdef SSL_SUPPORT #ifdef SSL_SUPPORT
#ifdef SSL_USE_OPENSSL
#include <openssl/ssl.h> #include <openssl/ssl.h>
#include <openssl/err.h> #include <openssl/err.h>
#endif /* SSL_USE_OPENSSL */
#ifdef SSL_USE_GNUTLS
#include <gnutls/gnutls.h>
#endif /* SSL_USE_GNUTLS */
#endif #endif
#include "version.h" #include "version.h"

View File

@ -65,10 +65,6 @@ struct ADC_client
char* desc; char* desc;
int flags; int flags;
void* ptr; 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; if (sd == -1) return NULL;
client->con = net_con_create(); 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); 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); ADC_client_set_state(client, ps_none);
client->nick = hub_strdup(nickname); client->nick = hub_strdup(nickname);
@ -547,10 +535,6 @@ void ADC_client_destroy(struct ADC_client* client)
{ {
ADC_TRACE; ADC_TRACE;
ADC_client_disconnect(client); ADC_client_disconnect(client);
#if 0
/* FIXME */
net_timer_shutdown(client->timer);
#endif
ioq_send_destroy(client->send_queue); ioq_send_destroy(client->send_queue);
ioq_recv_destroy(client->recv_queue); ioq_recv_destroy(client->recv_queue);
hub_free(client->timer); 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); net_con_update(client->con, NET_EVENT_READ | NET_EVENT_WRITE);
client->callback(client, ADC_CLIENT_SSL_HANDSHAKE, 0); client->callback(client, ADC_CLIENT_SSL_HANDSHAKE, 0);
ADC_client_set_state(client, ps_conn_ssl); ADC_client_set_state(client, ps_conn_ssl);
net_con_ssl_handshake(client->con, net_con_ssl_mode_client, NULL);
} }
else else
#endif #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) static void ADC_client_on_connected_ssl(struct ADC_client* client)
{ {
ADC_TRACE; ADC_TRACE;
net_con_update(client->con, NET_EVENT_READ);
client->callback(client, ADC_CLIENT_SSL_OK, 0); client->callback(client, ADC_CLIENT_SSL_OK, 0);
client->callback(client, ADC_CLIENT_CONNECTED, 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_send(client, adc_msg_create(ADC_HANDSHAKE));
ADC_client_set_state(client, ps_protocol); ADC_client_set_state(client, ps_protocol);
} }