Commit 724ee2bc authored by jehan's avatar jehan

basic TLS implementation based on gnu-tls.

parent c9442a2a
......@@ -93,12 +93,24 @@ AC_SUBST(ANTLR_CFLAGS)
AC_SUBST(ANTLR_LIBS)
PKG_CHECK_MODULES(GNUTLS, gnutls, [found_gnutls=yes],foo=bar)
AM_CONDITIONAL([BUILD_TLS], [test "x$found_gnutls" = "xyes"])
PKG_CHECK_MODULES(OPENSSL, openssl, [found_openssl=yes],foo=bar)
AM_CONDITIONAL([BUILD_TLS], [test "x$found_gnutls" = "xyes" || test "x$found_openssl" = "xyes"])
TLS_CFLAGS=""
TLS_LIBS=""
if test "x$found_gnutls" = "xyes" ; then
GNUTLS_LIBS+="$GNUTLS_LIBS -lgnutls-openssl "
AC_DEFINE(HAVE_TLS,1,[Defined when tls api is available])
AC_DEFINE(HAVE_GNUTLS,1,[Defined when gnutls api is available])
TLS_CFLAGS=$GNUTLS_CFLAGS
TLS_LIBS=$GNUTLS_LIBS
elif test "x$found_openssl" = "xyes" ; then
AC_DEFINE(HAVE_OPENSSL,1,[Defined when openssl api is available])
TLS_CFLAGS=$OPENSSL_CFLAGS
TLS_LIBS=$OPENSSL_LIBS
fi
AC_SUBST(TLS_CFLAGS)
AC_SUBST(TLS_LIBS)
PKG_CHECK_MODULES(CUNIT, cunit, [found_cunit=yes],[found_cunit=no])
if test "$found_cunit" = "no" ; then
......
......@@ -58,9 +58,9 @@ if BUILD_TLS
libbellesip_la_SOURCES+=transports/tls_channel.c
endif
libbellesip_la_CFLAGS=$(STRICT_OPTIONS) $(ANTLR_CFLAGS) $(GNUTLS_CFLAGS)
libbellesip_la_CFLAGS=$(STRICT_OPTIONS) $(ANTLR_CFLAGS) $(TLS_CFLAGS)
libbellesip_la_LIBADD=libbellesip_generated.la $(ANTLR_LIBS) $(GNUTLS_LIBS)
libbellesip_la_LIBADD=libbellesip_generated.la $(ANTLR_LIBS) $(TLS_LIBS)
INCLUDES=-I$(top_srcdir)/include
......@@ -71,4 +71,4 @@ CLEANFILES=$(generated_src) *.tokens generated_src_stamp
discovery:
touch specs.cpp
$(CC) $(CFLAGS) -include $(top_builddir)/config.h $(ANTLR_CFLAGS) $(CUNIT_CFLAGS) $(GNUTLS_CFLAGS) -E -P -v -dD specs.cpp
$(CC) $(CFLAGS) -include $(top_builddir)/config.h $(ANTLR_CFLAGS) $(CUNIT_CFLAGS) $(TLS_CFLAGS) -E -P -v -dD specs.cpp
......@@ -64,12 +64,14 @@ belle_sip_listening_point_t * belle_sip_stream_listening_point_new(belle_sip_sta
/*tls*/
typedef struct belle_sip_tls_listening_point belle_sip_tls_listening_point_t;
#ifdef HAVE_TLS
struct belle_sip_tls_listening_point{
belle_sip_listening_point_t base;
#ifdef HAVE_OPENSSL
SSL_CTX *ssl_context;
};
#endif
};
BELLE_SIP_DECLARE_CUSTOM_VPTR_BEGIN(belle_sip_tls_listening_point_t,belle_sip_listening_point_t)
BELLE_SIP_DECLARE_CUSTOM_VPTR_END
#define BELLE_SIP_TLS_LISTENING_POINT(obj) BELLE_SIP_CAST(obj,belle_sip_tls_listening_point_t)
......
......@@ -26,6 +26,14 @@ static void belle_sip_provider_uninit(belle_sip_provider_t *p){
}
static void channel_state_changed(belle_sip_channel_listener_t *obj, belle_sip_channel_t *chan, belle_sip_channel_state_t state){
belle_sip_io_error_event_t ev;
if (state == BELLE_SIP_CHANNEL_ERROR) {
ev.transport=belle_sip_channel_get_transport_name(chan);
ev.source=(belle_sip_provider_t*)obj;
ev.port=chan->local_port;
ev.host=chan->local_ip;
BELLE_SIP_PROVIDER_INVOKE_LISTENERS(ev.source,process_io_error,&ev);
}
}
static void belle_sip_provider_dispatch_message(belle_sip_provider_t *prov, belle_sip_message_t *msg){
......
......@@ -18,25 +18,46 @@
#include "belle_sip_internal.h"
#include "listeningpoint_internal.h"
#ifdef HAVE_GNUTLS
#include <gnutls/gnutls.h>
#endif
static void belle_sip_stack_destroy(belle_sip_stack_t *stack){
belle_sip_object_unref(stack->ml);
}
BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(belle_sip_stack_t);
BELLE_SIP_INSTANCIATE_VPTR(belle_sip_stack_t,belle_sip_object_t,belle_sip_stack_destroy,NULL,NULL,FALSE);
#ifdef HAVE_GNUTLS
static void _gnutls_log_func( int level, const char* log) {
belle_sip_log_level belle_sip_level;
switch(level) {
case 1: belle_sip_level=BELLE_SIP_LOG_ERROR;break;
case 2: belle_sip_level=BELLE_SIP_LOG_WARNING;break;
case 3: belle_sip_level=BELLE_SIP_LOG_MESSAGE;break;
default:belle_sip_level=BELLE_SIP_LOG_MESSAGE;break;
}
belle_sip_log(belle_sip_level,"gnutls:%s",log);
}
#endif /*HAVE_GNUTLS*/
belle_sip_stack_t * belle_sip_stack_new(const char *properties){
int result;
belle_sip_stack_t *stack=belle_sip_object_new(belle_sip_stack_t);
stack->ml=belle_sip_main_loop_new ();
stack->timer_config.T1=500;
stack->timer_config.T2=4000;
stack->timer_config.T4=5000;
#ifdef HAVE_TLS
#ifdef HAVE_OPENSSL
SSL_library_init();
SSL_load_error_strings();
/*CRYPTO_set_id_callback(&threadid_cb);
CRYPTO_set_locking_callback(&locking_function);*/
#endif
#ifdef HAVE_GNUTLS
/*gnutls_global_set_log_level(9);*/
gnutls_global_set_log_function(_gnutls_log_func);
if ((result = gnutls_global_init ()) <0) {
belle_sip_fatal("Cannot initialize gnu tls vaused by [%s]",gnutls_strerror(result));
}
#endif
return stack;
}
......@@ -51,6 +72,8 @@ belle_sip_listening_point_t *belle_sip_stack_create_listening_point(belle_sip_st
lp=belle_sip_udp_listening_point_new(s,ipaddress,port);
} else if (strcasecmp(transport,"TCP") == 0) {
lp=belle_sip_stream_listening_point_new(s,ipaddress,port);
}else if (strcasecmp(transport,"TLS") == 0) {
lp=belle_sip_tls_listening_point_new(s,ipaddress,port);
} else {
belle_sip_fatal("Unsupported transport %s",transport);
}
......
......@@ -42,7 +42,7 @@ static void stream_channel_uninit(belle_sip_stream_channel_t *obj){
belle_sip_main_loop_remove_source(obj->base.stack->ml,(belle_sip_source_t*)obj);
}
static int stream_channel_send(belle_sip_channel_t *obj, const void *buf, size_t buflen){
int stream_channel_send(belle_sip_channel_t *obj, const void *buf, size_t buflen){
belle_sip_fd_t sock = belle_sip_source_get_fd((belle_sip_source_t*)obj);
int err;
err=send(sock,buf,buflen,0);
......@@ -53,7 +53,7 @@ static int stream_channel_send(belle_sip_channel_t *obj, const void *buf, size_t
return err;
}
static int stream_channel_recv(belle_sip_channel_t *obj, void *buf, size_t buflen){
int stream_channel_recv(belle_sip_channel_t *obj, void *buf, size_t buflen){
belle_sip_fd_t sock = belle_sip_source_get_fd((belle_sip_source_t*)obj);
int err;
err=recv(sock,buf,buflen,MSG_DONTWAIT);
......
......@@ -23,5 +23,6 @@
int stream_channel_connect(belle_sip_channel_t *obj, const struct sockaddr *addr, socklen_t socklen);
/*return 0 if succeed*/
int finalize_stream_connection (belle_sip_fd_t fd, struct sockaddr *addr, socklen_t* slen);
int stream_channel_send(belle_sip_channel_t *obj, const void *buf, size_t buflen);
int stream_channel_recv(belle_sip_channel_t *obj, void *buf, size_t buflen);
#endif /* STREAM_CHANNEL_H_ */
......@@ -23,44 +23,65 @@
#include "belle_sip_internal.h"
#include "belle-sip/mainloop.h"
#include "stream_channel.h"
#include "gnutls/openssl.h"
#ifdef HAVE_GNUTLS
#include <gnutls/gnutls.h>
#else if HAVE_OPENSSL
#include "openssl/ssl.h"
#endif
/*************tls********/
struct belle_sip_tls_channel{
belle_sip_channel_t base;
belle_sip_tls_listening_point_t* lp;
int socket_connected;
#ifdef HAVE_OPENSSL
SSL *ssl;
#endif
#ifdef HAVE_GNUTLS
gnutls_session_t session;
gnutls_certificate_credentials_t xcred;
#endif
struct sockaddr_storage ss;
};
static void tls_channel_uninit(belle_sip_tls_channel_t *obj){
belle_sip_fd_t sock = belle_sip_source_get_fd((belle_sip_source_t*)obj);
#ifdef HAVE_GNUTLS
gnutls_bye (obj->session, GNUTLS_SHUT_RDWR);
gnutls_deinit (obj->session);
gnutls_certificate_free_credentials (obj->xcred);
#endif
if (sock!=-1)
close_socket(sock);
belle_sip_main_loop_remove_source(obj->base.stack->ml,(belle_sip_source_t*)obj);
belle_sip_main_loop_remove_source(obj->base.stack->ml,(belle_sip_source_t*)obj);
belle_sip_object_unref(obj->lp);
}
static int tls_channel_send(belle_sip_channel_t *obj, const void *buf, size_t buflen){
belle_sip_fd_t sock = belle_sip_source_get_fd((belle_sip_source_t*)obj);
belle_sip_tls_channel_t* channel = (belle_sip_tls_channel_t*)obj;
int err;
err=send(sock,buf,buflen,0);
if (err==-1){
belle_sip_fatal("Could not send tls packet on channel [%p]: %s",obj,strerror(errno));
return -errno;
/*fix me, can block, see gnutls doc*/
err=gnutls_record_send (channel->session, buf, buflen);
if (err<0){
belle_sip_error("Could not send tls packet on channel [%p]: %s",obj,gnutls_strerror(err));
return err;
}
return err;
}
static ssize_t tls_channel_pull_func(gnutls_transport_ptr_t obj, void* buff, size_t bufflen) {
return stream_channel_recv((belle_sip_channel_t *)obj, buff,bufflen);
}
static int tls_channel_recv(belle_sip_channel_t *obj, void *buf, size_t buflen){
belle_sip_fd_t sock = belle_sip_source_get_fd((belle_sip_source_t*)obj);
belle_sip_tls_channel_t* channel = (belle_sip_tls_channel_t*)obj;
int err;
err=recv(sock,buf,buflen,MSG_DONTWAIT);
if (err==-1 && errno!=EWOULDBLOCK){
belle_sip_error("Could not receive tls packet: %s",strerror(errno));
return -errno;
err=gnutls_record_recv(channel->session,buf,buflen);
if (err<0 ){
belle_sip_error("Could not receive tls packet: %s",gnutls_strerror(err));
return err;
}
return err;
}
......@@ -94,15 +115,34 @@ BELLE_SIP_INSTANCIATE_CUSTOM_VPTR(belle_sip_tls_channel_t)=
static int process_data(belle_sip_channel_t *obj,unsigned int revents){
belle_sip_tls_channel_t* channel=(belle_sip_tls_channel_t*)obj;
socklen_t addrlen=sizeof(channel->ss);
char ssl_error_string[128];
int result;
#ifdef HAVE_OPENSSL
char ssl_error_string[128];
#endif /*HAVE_OPENSSL*/
belle_sip_fd_t fd=belle_sip_source_get_fd((belle_sip_source_t*)channel);
if (obj->state == BELLE_SIP_CHANNEL_CONNECTING && (revents&BELLE_SIP_EVENT_WRITE)) {
if (finalize_stream_connection(fd,(struct sockaddr*)&channel->ss,&addrlen)) {
goto process_error;
if (obj->state == BELLE_SIP_CHANNEL_CONNECTING) {
if (!channel->socket_connected) {
if (finalize_stream_connection(fd,(struct sockaddr*)&channel->ss,&addrlen)) {
goto process_error;
}
belle_sip_source_set_events((belle_sip_source_t*)channel,BELLE_SIP_EVENT_READ|BELLE_SIP_EVENT_ERROR);
channel->socket_connected=1;
}
/*connected, now etablishing TLS connection*/
#if HAVE_GNUTLS
gnutls_transport_set_ptr2(channel->session, (gnutls_transport_ptr_t)channel,(gnutls_transport_ptr_t) (0xFFFFFFFFULL&fd));
result = gnutls_handshake(channel->session);
if ((result < 0 && gnutls_error_is_fatal (result) == 0)) {
belle_sip_message("TLS connection in progress for channel [%p]",channel);
return BELLE_SIP_CONTINUE;
} else if (result<0) {
belle_sip_error("TLS Handshake failed caused by [%s]",gnutls_strerror(result));
goto process_error;
} else {
belle_sip_channel_set_ready(obj,(struct sockaddr*)&channel->ss,addrlen);
return BELLE_SIP_CONTINUE;
}
#else if HAVE_OPENSSL
if (!channel->ssl) {
channel->ssl=SSL_new(channel->lp->ssl_context);
if (!channel->ssl) {
......@@ -110,8 +150,9 @@ static int process_data(belle_sip_channel_t *obj,unsigned int revents){
goto process_error;
}
}
belle_sip_source_set_events((belle_sip_source_t*)channel,BELLE_SIP_EVENT_READ|BELLE_SIP_EVENT_ERROR);
#endif /*HAVE_OPENSSL*/
#ifdef HAVE_OPENSSL
if (!SSL_set_fd(channel->ssl,fd)) {
;
belle_sip_error("TLS connection failed to set fd caused by [%s]",ERR_error_string(ERR_get_error(),ssl_error_string));
......@@ -129,7 +170,7 @@ static int process_data(belle_sip_channel_t *obj,unsigned int revents){
belle_sip_error("TLS connection failed caused by [%s]",ERR_error_string(result,ssl_error_string));
goto process_error;
}
#endif /*HAVE_OPENSSL*/
} else if ( obj->state == BELLE_SIP_CHANNEL_READY) {
belle_sip_channel_process_data(obj,revents);
......@@ -138,20 +179,53 @@ static int process_data(belle_sip_channel_t *obj,unsigned int revents){
}
return BELLE_SIP_CONTINUE;
process_error:
belle_sip_error("Cannot connect to [%s://%s:%s]",belle_sip_channel_get_transport_name(obj),obj->peer_name,obj->peer_port);
belle_sip_error("Cannot connect to [%s://%s:%i]",belle_sip_channel_get_transport_name(obj),obj->peer_name,obj->peer_port);
channel_set_state(obj,BELLE_SIP_CHANNEL_ERROR);
channel_process_queue(obj);
return BELLE_SIP_STOP;
}
belle_sip_channel_t * belle_sip_channel_new_tls(belle_sip_tls_listening_point_t *lp,const char *bindip, int localport, const char *dest, int port){
belle_sip_tls_channel_t *obj=belle_sip_object_new(belle_sip_tls_channel_t);
belle_sip_channel_init((belle_sip_channel_t*)obj
belle_sip_channel_t* channel=(belle_sip_channel_t*)obj;
int result;
#ifdef HAVE_GNUTLS
const char* err_pos;
result = gnutls_init (&obj->session, GNUTLS_CLIENT);
if (result<0) {
belle_sip_error("Cannot initialize gnu tls session for channel [%p] caused by [%s]",obj,gnutls_strerror(result));
goto error;
}
result = gnutls_certificate_allocate_credentials (&obj->xcred);
if (result<0) {
belle_sip_error("Cannot allocate_client_credentials for channel [%p] caused by [%s]",obj,gnutls_strerror(result));
goto error;
}
/* Use default priorities */
result = gnutls_priority_set_direct (obj->session, "NORMAL"/*"PERFORMANCE:+ANON-DH:!ARCFOUR-128"*/,&err_pos);
if (result<0) {
belle_sip_error("Cannot set direct priority for channel [%p] caused by [%s] at position [%s]",obj,gnutls_strerror(result),err_pos);
goto error;
}
/* put the anonymous credentials to the current session
*/
result = gnutls_credentials_set (obj->session, GNUTLS_CRD_CERTIFICATE, obj->xcred);
if (result<0) {
belle_sip_error("Cannot set credential for channel [%p] caused by [%s]",obj,gnutls_strerror(result));
goto error;
}
gnutls_transport_set_pull_function(obj->session,tls_channel_pull_func);
#endif
belle_sip_channel_init(channel
,((belle_sip_listening_point_t*)lp)->stack
,socket(AF_INET, SOCK_STREAM, 0)
,(belle_sip_source_func_t)process_data
,bindip,localport,dest,port);
belle_sip_object_ref(obj->lp=lp);
return (belle_sip_channel_t*)obj;
error:
belle_sip_error("Cannot create tls channel to [%s://%s:%i]",belle_sip_channel_get_transport_name(channel),channel->peer_name,channel->peer_port);
belle_sip_object_unref(obj);
return NULL;
}
......
......@@ -18,9 +18,9 @@
#include "belle_sip_internal.h"
#include "listeningpoint_internal.h"
#ifdef HAVE_TLS
#ifdef HAVE_OPENSSL
#include "gnutls/openssl.h"
#endif
static void belle_sip_tls_listening_point_uninit(belle_sip_tls_listening_point_t *lp){
}
......@@ -43,12 +43,13 @@ BELLE_SIP_INSTANCIATE_CUSTOM_VPTR(belle_sip_tls_listening_point_t)={
}
};
#endif
belle_sip_listening_point_t * belle_sip_tls_listening_point_new(belle_sip_stack_t *s, const char *ipaddress, int port){
#ifdef HAVE_TLS
#ifdef HAVE_GNUTLS
belle_sip_tls_listening_point_t *lp=belle_sip_object_new(belle_sip_tls_listening_point_t);
belle_sip_listening_point_init((belle_sip_listening_point_t*)lp,s,ipaddress,port);
#ifdef HAVE_OPENSSL
char ssl_error_string[128]; /*see openssl doc for size*/
lp->ssl_context=SSL_CTX_new(TLSv1_client_method());
if (!lp->ssl_context) {
......@@ -57,6 +58,7 @@ belle_sip_listening_point_t * belle_sip_tls_listening_point_new(belle_sip_stack_
return NULL;
}
/*SSL_CTX_set_cipher_list(lp->ssl_context,"LOW");*/
#endif /**/
return BELLE_SIP_LISTENING_POINT(lp);
#else
belle_sip_error("Cannot create tls listening point because not compile with TLS support");
......
......@@ -31,7 +31,9 @@ static void process_dialog_terminated(belle_sip_listener_t *obj, const belle_sip
belle_sip_message("process_dialog_terminated called");
}
static void process_io_error(belle_sip_listener_t *obj, const belle_sip_io_error_event_t *event){
belle_sip_message("process_io_error");
belle_sip_warning("process_io_error");
belle_sip_main_loop_quit(belle_sip_stack_get_main_loop(stack));
/*CU_ASSERT(CU_FALSE);*/
}
static void process_request_event(belle_sip_listener_t *obj, const belle_sip_request_event_t *event){
belle_sip_message("process_request_event");
......@@ -90,6 +92,9 @@ static int init(void) {
lp=belle_sip_stack_create_listening_point(stack,"0.0.0.0",7060,"TCP");
belle_sip_provider_add_listening_point(prov,lp);
belle_sip_object_unref(lp);
lp=belle_sip_stack_create_listening_point(stack,"0.0.0.0",7061,"TLS");
belle_sip_provider_add_listening_point(prov,lp);
belle_sip_object_unref(lp);
listener=belle_sip_object_new(test_listener_t);
belle_sip_provider_add_sip_listener(prov,BELLE_SIP_LISTENER(listener));
return 0;
......@@ -155,6 +160,9 @@ static void stateful_register_udp(void){
static void stateful_register_tcp(void){
register_test("tcp",1);
}
static void stateful_register_tls(void){
register_test("tls",1);
}
int belle_sip_register_test_suite(){
CU_pSuite pSuite = CU_add_suite("Register test suite", init, uninit);
......@@ -165,7 +173,9 @@ int belle_sip_register_test_suite(){
if (NULL == CU_add_test(pSuite, "stateful tcp register", stateful_register_tcp)) {
return CU_get_error();
}
if (NULL == CU_add_test(pSuite, "stateful tls register", stateful_register_tls)) {
return CU_get_error();
}
if (NULL == CU_add_test(pSuite, "stateless udp register", stateless_register_udp)) {
return CU_get_error();
}
......
......@@ -37,12 +37,12 @@ static void cast_test(){
belle_sip_message_t *msg;
int tmp;
CU_ASSERT_PTR_NOT_NULL(stack);
CU_ASSERT_PTR_NOT_NULL(lp);
CU_ASSERT_PTR_NOT_NULL_FATAL(stack);
CU_ASSERT_PTR_NOT_NULL_FATAL(lp);
provider=belle_sip_stack_create_provider(stack,lp);
CU_ASSERT_PTR_NOT_NULL(provider);
CU_ASSERT_PTR_NOT_NULL(req);
CU_ASSERT_PTR_NOT_NULL(resp);
CU_ASSERT_PTR_NOT_NULL_FATAL(provider);
CU_ASSERT_PTR_NOT_NULL_FATAL(req);
CU_ASSERT_PTR_NOT_NULL_FATAL(resp);
belle_sip_message("Casting belle_sip_request_t to belle_sip_message_t");
msg=BELLE_SIP_MESSAGE(req);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment