Work on splitting out OpenSSL cleanly.

This commit is contained in:
Jan Vidar Krey 2012-10-12 14:24:03 +02:00
parent f20c42d05f
commit f3922bb3e0
7 changed files with 341 additions and 280 deletions

View File

@ -49,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
)

View File

@ -182,10 +182,7 @@ void net_con_close(struct net_connection* con)
#ifdef SSL_SUPPORT
#ifdef SSL_USE_OPENSSL
if (con->ssl)
{
SSL_shutdown(con->ssl);
SSL_clear(con->ssl);
}
net_ssl_shutdown(con);
#endif /* SSL_USE_OPENSSL */
#endif /* SSL_SUPPORT */

View File

@ -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
@ -26,6 +26,10 @@
#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
#define NET_CON_STRUCT_BASIC \
@ -35,17 +39,8 @@
net_connection_cb callback; /** Callback function */ \
struct timeout_evt* timeout; /** timeout event handler */
#ifdef SSL_USE_OPENSSL
#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. */
#endif
#ifdef SSL_USE_GNUTLS
#define NET_CON_STRUCT_SSL \
uint32_t ssl_state; /** SSL state */
#endif
struct ssl_handle* ssl; /** SSL handle */
#ifdef SSL_SUPPORT
#define NET_CON_STRUCT_COMMON \

View File

@ -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,138 +20,6 @@
#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,
};
#ifdef SSL_USE_OPENSSL
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;
}
#endif /* SSL_USE_OPENSSL */
ssize_t net_con_ssl_accept(struct net_connection* con)
{
uhub_assert(con);
con->ssl_state = tls_st_accepting;
ssize_t ret;
#ifdef SSL_USE_OPENSSL
ret = SSL_accept(con->ssl);
#ifdef NETWORK_DUMP_DEBUG
LOG_PROTO("SSL_accept() ret=%d", ret);
#endif /* NETWORK_DUMP_DEBUG */
if (ret > 0)
{
net_con_update(con, NET_EVENT_READ);
con->ssl_state = tls_st_connected;
}
else
{
return handle_openssl_error(con, ret);
}
#endif /* SSL_USE_OPENSSL */
return ret;
}
ssize_t net_con_ssl_connect(struct net_connection* con)
{
uhub_assert(con);
ssize_t ret;
con->ssl_state = tls_st_connecting;
#ifdef SSL_USE_OPENSSL
ret = SSL_connect(con->ssl);
#ifdef NETWORK_DUMP_DEBUG
LOG_PROTO("SSL_connect() ret=%d", ret);
#endif /* NETWORK_DUMP_DEBUG */
if (ret > 0)
{
con->ssl_state = tls_st_connected;
net_con_update(con, NET_EVENT_READ);
}
else
{
return handle_openssl_error(con, ret);
}
#endif /* SSL_USE_OPENSSL */
return ret;
}
#ifdef SSL_USE_OPENSSL
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_USE_OPENSSL */
#endif /* SSL_SUPPORT */
#ifdef SSL_SUPPORT
void net_stats_add_tx(size_t bytes);
void net_stats_add_rx(size_t bytes);
@ -161,9 +29,7 @@ ssize_t net_con_send(struct net_connection* con, const void* buf, size_t len)
{
int ret;
#ifdef SSL_SUPPORT
#ifdef SSL_USE_OPENSSL
if (!con->ssl)
#endif /* SSL_USE_OPENSSL */
{
#endif
ret = net_send(con->sd, buf, len, UHUB_SEND_SIGNAL);
@ -181,22 +47,10 @@ ssize_t net_con_send(struct net_connection* con, const void* buf, size_t len)
}
#ifdef SSL_SUPPORT
}
#ifdef SSL_USE_OPENSSL
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 /* SSL_USE_OPENSSL */
#endif /* SSL_SUPPORT */
return ret;
}
@ -205,7 +59,7 @@ 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);
@ -229,22 +83,7 @@ ssize_t net_con_recv(struct net_connection* con, void* buf, size_t len)
}
else
{
#ifdef SSL_USE_OPENSSL
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);
}
#endif /* SSL_USE_OPENSSL */
ret = net_ssl_recv(con, buf, len);
}
#endif /* SSL_SUPPORT */
return ret;
@ -274,22 +113,8 @@ ssize_t net_con_peek(struct net_connection* con, void* buf, size_t len)
int net_con_is_ssl(struct net_connection* con)
{
#ifdef SSL_USE_OPENSSL
return con->ssl != 0;
#endif
return !!con->ssl;
}
#ifdef SSL_USE_OPENSSL
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_USE_OPENSSL */
#endif /* SSL_SUPPORT */
int net_con_get_sd(struct net_connection* con)
@ -305,9 +130,8 @@ void* net_con_get_ptr(struct net_connection* con)
void net_con_destroy(struct net_connection* con)
{
#ifdef SSL_SUPPORT
#ifdef SSL_USE_OPENSSL
SSL_free(con->ssl);
#endif /* SSL_USE_OPENSSL */
if (con->ssl)
net_ssl_destroy(con);
#endif
hub_free(con);
}
@ -325,66 +149,12 @@ void net_con_callback(struct net_connection* con, int events)
}
#ifdef SSL_SUPPORT
#ifdef SSL_USE_OPENSSL
if (!con->ssl)
#endif /* SSL_USE_OPENSSL */
{
#endif
con->callback(con, events, con->ptr);
#ifdef SSL_SUPPORT
}
#ifdef SSL_USE_OPENSSL
else
#endif /* SSL_USE_OPENSSL */
{
#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;
}
}
net_ssl_callback(con, events);
#endif
}

View File

@ -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,31 +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,
};
#ifdef SSL_USE_OPENSSL
extern ssize_t net_con_ssl_handshake(struct net_connection* con, enum net_con_ssl_mode, SSL_CTX* ssl_ctx);
extern SSL* net_con_get_ssl(struct net_connection* con);
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_CONNECTION_H */

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

@ -0,0 +1,252 @@
/*
* 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
struct net_ssl_openssl
{
SSL* ssl;
enum ssl_state state;
};
static struct net_ssl_openssl* get_handle(struct net_connection* con)
{
uhub_assert(con);
return (struct net_ssl_openssl*) con->ssl;
}
static int handle_openssl_error(struct net_connection* con, int ret)
{
struct net_ssl_openssl* handle = get_handle(con);
int error = SSL_get_error(handle->ssl, ret);
switch (error)
{
case SSL_ERROR_ZERO_RETURN:
LOG_PROTO("SSL_get_error: ret=%d, error=%d: SSL_ERROR_ZERO_RETURN", ret, error);
handle->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 */
handle->state = tls_st_error;
return -1;
}
return -1;
}
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;
}
else
{
return handle_openssl_error(con, ret);
}
return ret;
}
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);
}
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);
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(ssl_ctx);
if (!handle->ssl)
{
LOG_ERROR("Unable to create new SSL stream\n");
return -1;
}
SSL_set_fd(handle->ssl, con->sd);
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);
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);
// con->write_len = len;
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)
{
return handle_openssl_error(con, ret);
}
return ret;
}
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 -1;
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)
{
net_con_update(con, NET_EVENT_READ);
}
else
{
return handle_openssl_error(con, ret);
}
return ret;
}
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);
uint32_t flags = con->flags;
con->flags &= ~NET_SSL_ANY; /* reset the SSL related flags */
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_connected:
LOG_PROTO("tls_st_connected, events=%s%s, ssl_flags=%s%s", (events & NET_EVENT_READ ? "R" : ""), (events & NET_EVENT_WRITE ? "W" : ""), flags & NET_WANT_SSL_READ ? "R" : "", flags & NET_WANT_SSL_WRITE ? "W" : "");
if (events & NET_EVENT_WRITE && flags & NET_WANT_SSL_READ)
{
con->callback(con, events & NET_EVENT_READ, con->ptr);
return;
}
if (events & NET_EVENT_READ && 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 /* SSL_USE_OPENSSL */
#endif /* SSL_SUPPORT */

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

@ -0,0 +1,71 @@
/*
* 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_disconnecting,
};
enum net_con_ssl_mode
{
net_con_ssl_mode_server,
net_con_ssl_mode_client,
};
/**
* 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);
#ifdef SSL_USE_OPENSSL
extern ssize_t net_con_ssl_handshake(struct net_connection* con, enum net_con_ssl_mode, SSL_CTX* ssl_ctx);
extern SSL* net_con_get_ssl(struct net_connection* con);
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 */