From 1b92d6230fa6c1b22c39a95960b8d32ab9e6aac6 Mon Sep 17 00:00:00 2001 From: Marcel Poul Date: Mon, 5 Dec 2011 14:07:56 +0000 Subject: [PATCH] ssl close connection functions added; destroy ssl connection handler and BIO in canl_io_destroy --- emi.canl.canl-c/Makefile | 2 +- emi.canl.canl-c/src/canl.c | 80 +++++++++++++++++++++-------------------- emi.canl.canl-c/src/canl.h | 1 - emi.canl.canl-c/src/canl_cert.c | 2 +- emi.canl.canl-c/src/canl_err.c | 3 +- emi.canl.canl-c/src/canl_locl.h | 2 ++ emi.canl.canl-c/src/canl_ssl.c | 73 ++++++++++++++++++++++++++++++++++--- 7 files changed, 115 insertions(+), 48 deletions(-) diff --git a/emi.canl.canl-c/Makefile b/emi.canl.canl-c/Makefile index 3efd510..2ff8a06 100644 --- a/emi.canl.canl-c/Makefile +++ b/emi.canl.canl-c/Makefile @@ -16,7 +16,7 @@ COMPILE=libtool --mode=compile ${CC} ${CFLAGS} LINK=libtool --mode=link ${CC} ${LDFLAGS} INSTALL=libtool --mode=install install -CFLAGS_LIB=-Wall -fPIC -c -g -I${top_srcdir}/src ${LIBCARES_CFLAGS} ${LIBSSL_CFLAGS} +CFLAGS_LIB=-Wall -pedantic -fPIC -c -g -I${top_srcdir}/src ${LIBCARES_CFLAGS} ${LIBSSL_CFLAGS} LFLAGS_LIB=-shared ${LIBCARES_LIBS} ${LIBSSL_LIBS} CFLAGS_CLI=-Wall -g -I${top_srcdir}/src diff --git a/emi.canl.canl-c/src/canl.c b/emi.canl.canl-c/src/canl.c index 4a9986c..b9e1f42 100644 --- a/emi.canl.canl-c/src/canl.c +++ b/emi.canl.canl-c/src/canl.c @@ -8,7 +8,7 @@ #define BACKLOG 10 //TODO just for testing - max incoming connections -static int io_clear(glb_ctx *cc, io_handler *io); +static void io_destroy(glb_ctx *cc, io_handler *io); static int init_io_content(glb_ctx *cc, io_handler *io); canl_ctx canl_create_ctx() { @@ -139,7 +139,6 @@ int canl_io_connect(canl_ctx cc, canl_io_handler io, char * host, int port, int sock; struct sockaddr_in *sa_in = NULL; int i = 0; - int err_clear = 0; /*check cc and io*/ if (!glb_cc) { @@ -208,9 +207,6 @@ int canl_io_connect(canl_ctx cc, canl_io_handler io, char * host, int port, end: if (err) { update_error(cc, "failed to connect (canl_io_connect)"); - if ((err_clear = io_clear(glb_cc, io_cc))) - update_error(cc, "failed to clean io_handler" - " (canl_io_connect)"); } return err; } @@ -326,34 +322,25 @@ int canl_io_close(canl_ctx cc, canl_io_handler io) } if (!io) { - //set_error(ctx->err_msg); err = EINVAL; - goto end; + set_error(glb_cc, err, posix_error, "invalid io handler" + " canl_io_close)"); + return err; } + return err; + /*ssl close*/ /*set cc and io accordingly*/ - -end: - if (err) - update_error(glb_cc, "cannot close connection (canl_io_close)"); - return err; } -static int io_clear(glb_ctx *cc, io_handler *io) +static void io_destroy(glb_ctx *cc, io_handler *io) { io_handler *io_cc = (io_handler*) io; glb_ctx *glb_cc = (glb_ctx*) cc; int err = 0; - /*check cc and io*/ - if (!cc) { - return EINVAL; - } - - if (!io) { - err = EINVAL; - goto end; - } + unsigned long ssl_err; + CANL_ERROR_ORIGIN e_orig = unknown_error; // delete io_handler content if (io_cc->ar) { @@ -367,12 +354,26 @@ static int io_clear(glb_ctx *cc, io_handler *io) free (io_cc->s_addr); io_cc->s_addr = NULL; } - -end: - if (err) - update_error(glb_cc, "cannot clear io_handle (io_clear)"); - return err; - + if (io_cc->s_ctx) { + /*TODO maybe new function because of BIO_free and SSL_free*/ + if (io_cc->s_ctx->ssl_io) { + SSL_free(io_cc->s_ctx->ssl_io); + io_cc->s_ctx->ssl_io = NULL; + } + if (io_cc->s_ctx->bio_conn) { + err = BIO_free(io_cc->s_ctx->bio_conn); + /* TODO check it? + if (!err) { + ssl_err = ERR_peek_error(); + set_error(io_cc, err, ssl_error, "cannot free BIO" + " (io_destroy)"); + err = 1; + } */ + io_cc->s_ctx->bio_conn = NULL; + } + } + free (io_cc->s_ctx); + io_cc->s_ctx = NULL; } int canl_io_destroy(canl_ctx cc, canl_io_handler io) @@ -381,27 +382,28 @@ int canl_io_destroy(canl_ctx cc, canl_io_handler io) glb_ctx *glb_cc = (glb_ctx*) cc; io_handler *io_cc = (io_handler*) io; /*check cc and io*/ - if (!cc) { + if (!glb_cc) { return EINVAL; } - if (!io) { - //set_error(ctx->err_msg); + if (!io_cc) { err = EINVAL; - goto end; + set_error(glb_cc, err, posix_error, "invalid io handler" + " canl_io_destroy)"); + return err; } - err = io_clear(glb_cc, io_cc); - if (err) - goto end; + err = ssl_close(glb_cc, io_cc); + if (err <= 0) + return err; + + io_destroy(glb_cc, io_cc); // delete io itself if (io_cc) { free (io_cc); - io = NULL; + io_cc = NULL; } -end: - if (err) - update_error(glb_cc, "can't destroy io_handle (canl_io_destroy)"); + return err; } diff --git a/emi.canl.canl-c/src/canl.h b/emi.canl.canl-c/src/canl.h index b6ac2d0..4248a8b 100644 --- a/emi.canl.canl-c/src/canl.h +++ b/emi.canl.canl-c/src/canl.h @@ -1,7 +1,6 @@ #ifndef _CANL_H #define _CANL_H #include -#include "canl_err.h" typedef void *canl_io_handler; typedef void *canl_ctx; diff --git a/emi.canl.canl-c/src/canl_cert.c b/emi.canl.canl-c/src/canl_cert.c index 0fe0301..6cc9ac4 100644 --- a/emi.canl.canl-c/src/canl_cert.c +++ b/emi.canl.canl-c/src/canl_cert.c @@ -106,7 +106,7 @@ static int set_key_file(glb_ctx *cc, char *key) /*TODO NULL NULL, callback and user data*/ cc->cert_key->key = PEM_read_PrivateKey(key_file, NULL, NULL, NULL); if (!cc->cert_key->key) { - ssl_err = ERR_get_error(); + ssl_err = ERR_peek_error(); set_error(cc, ssl_err, ssl_error, "error while writing key to context" " (set_key_file)"); goto end; diff --git a/emi.canl.canl-c/src/canl_err.c b/emi.canl.canl-c/src/canl_err.c index 87b4b7e..f5db3f2 100644 --- a/emi.canl.canl-c/src/canl_err.c +++ b/emi.canl.canl-c/src/canl_err.c @@ -103,11 +103,10 @@ int canl_get_error(canl_ctx cc, char **reason) int separ_len = 0; const char *msg_pref = "[CANL:MSG] "; int msg_pref_len = 0; + glb_ctx *ctx = (glb_ctx*) cc; code_str[0] = '\0'; - glb_ctx *ctx = (glb_ctx*) cc; - /*check cc*/ if (!ctx) { return EINVAL; diff --git a/emi.canl.canl-c/src/canl_locl.h b/emi.canl.canl-c/src/canl_locl.h index 1cb81d1..68a06b2 100644 --- a/emi.canl.canl-c/src/canl_locl.h +++ b/emi.canl.canl-c/src/canl_locl.h @@ -13,6 +13,7 @@ #include #include #include +#include "canl_err.h" #include "canl.h" typedef struct _cert_key_store { @@ -65,6 +66,7 @@ int ssl_read(glb_ctx *cc, io_handler *io, void *buffer, size_t size, struct timeval *tout); int ssl_write(glb_ctx *cc, io_handler *io, void *buffer, size_t size, struct timeval *tout); +int ssl_close(glb_ctx *cc, io_handler *io); int do_set_ctx_own_cert(glb_ctx *cc, canl_x509 cert, canl_stack_of_x509 chain, canl_pkey key); diff --git a/emi.canl.canl-c/src/canl_ssl.c b/emi.canl.canl-c/src/canl_ssl.c index 78f8cd0..e7dac2c 100644 --- a/emi.canl.canl-c/src/canl_ssl.c +++ b/emi.canl.canl-c/src/canl_ssl.c @@ -1,7 +1,8 @@ #include "canl_locl.h" -#define SSL_SERVER_METH SSLv3_server_method() +#define SSL_SERVER_METH SSLv23_server_method() #define SSL_CLIENT_METH SSLv3_client_method() +#define DESTROY_TIMEOUT 10 static int do_ssl_connect( glb_ctx *cc, io_handler *io, struct timeval *timeout); static int do_ssl_accept( glb_ctx *cc, io_handler *io, struct timeval *timeout); @@ -23,8 +24,8 @@ int ssl_server_init(glb_ctx *cc, io_handler *io) goto end; } - SSL_load_error_strings(); SSL_library_init(); + SSL_load_error_strings(); //OpenSSL_add_all_algorithms(); //OpenSSL_add_all_ciphers(); ERR_clear_error(); @@ -281,6 +282,7 @@ end: */ int do_select(int fd, time_t starttime, int timeout, int wanted) { + int ret = 0; fd_set rset; fd_set wset; @@ -292,8 +294,6 @@ int do_select(int fd, time_t starttime, int timeout, int wanted) if (wanted == 0 || wanted == SSL_ERROR_WANT_WRITE) FD_SET(fd, &wset); - int ret = 0; - if (timeout != -1) { struct timeval endtime; @@ -595,6 +595,71 @@ int ssl_read(glb_ctx *cc, io_handler *io, void *buffer, size_t size, struct time return err; } +/* ret > 1 if connection does not exist or has been closed before + * ret = 0 connection closed successfully (one direction) + * ret = 1 connection closed successfully (both directions) + * ret < 0 error occured (e.g. timeout reached) */ +int ssl_close(glb_ctx *cc, io_handler *io) +{ + int timeout = DESTROY_TIMEOUT; + time_t starttime, curtime; + int expected = 0, error = 0, ret = 0, ret2 = 0; + int fd; + unsigned long ssl_err = 0; + + if (!io->s_ctx->ssl_io) { + return 2; + } + + fd = BIO_get_fd(SSL_get_rbio(io->s_ctx->ssl_io), NULL); + curtime = starttime = time(NULL); + + /* check the shutdown state*/ + ret = SSL_get_shutdown(io->s_ctx->ssl_io); + if (ret & SSL_SENT_SHUTDOWN) + if (ret & SSL_RECEIVED_SHUTDOWN) + return 1; + else + return 0; + /* TODO check the proper states, maybe also call SSL_shutdown + if (ret & SSL_RECEIVED_SHUTDOWN) { + return 0; + } */ + + do { + ret = do_select(fd, starttime, timeout, expected); + curtime = time(NULL); + + if (ret > 0) { + ret2 = SSL_shutdown(io->s_ctx->ssl_io); + if (ret2 < 0) { + ssl_err = ERR_peek_error(); + expected = error = SSL_get_error(io->s_ctx->ssl_io, ret2); + } + } + } while (TEST_SELECT(ret, ret2, timeout, curtime, starttime, error)); + + if (timeout != -1 && (curtime - starttime >= timeout)){ + set_error(cc, ETIMEDOUT, posix_error, "Connection stuck" + " during ssl shutdown : timeout reached. (ssl_close)"); + return -1; + } + /* TODO set_error*/ + if (ret < 0) { + set_error(cc, 0, unknown_error, "Error during SSL" + " shutdown: (ssl_close)"); + return -1; + } + /* successful shutdown (uni/bi directional)*/ + if (ret2 == 0 || ret2 == 1) + return ret2; + else { + set_error(cc, ssl_err, ssl_error, "Error during SSL" + " shutdown: (ssl_close)"); + return -1; + } +} + static void dbg_print_ssl_error(int errorcode) { printf("[DBG CANL] "); -- 1.8.2.3