From 64b16f829695be16de67b5d0921e4a0e7f8b7927 Mon Sep 17 00:00:00 2001 From: Philipp Schafft Date: Thu, 20 Oct 2016 08:24:52 +0000 Subject: [PATCH] Update: Abstracted the TLS context code into tls.c --- src/Makefile.am | 2 +- src/connection.c | 55 ++++--------------- src/main.c | 2 + src/tls.c | 138 +++++++++++++++++++++++++++++++++++++++++++++++ src/tls.h | 30 +++++++++++ 5 files changed, 182 insertions(+), 45 deletions(-) create mode 100644 src/tls.c create mode 100644 src/tls.h diff --git a/src/Makefile.am b/src/Makefile.am index 59f4bdc4..e69c236c 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -16,7 +16,7 @@ noinst_HEADERS = admin.h cfgfile.h logging.h sighandler.h connection.h \ format_kate.h format_skeleton.h format_opus.h icecast_SOURCES = cfgfile.c main.c logging.c sighandler.c connection.c global.c \ util.c slave.c source.c stats.c refbuf.c client.c playlist.c \ - xslt.c fserve.c admin.c md5.c matchfile.c \ + xslt.c fserve.c admin.c md5.c matchfile.c tls.c \ format.c format_ogg.c format_mp3.c format_midi.c format_flac.c format_ebml.c \ format_kate.c format_skeleton.c format_opus.c \ event.c event_log.c event_exec.c \ diff --git a/src/connection.c b/src/connection.c index 9e5f95d2..782cf9f8 100644 --- a/src/connection.c +++ b/src/connection.c @@ -59,6 +59,7 @@ #include "admin.h" #include "auth.h" #include "matchfile.h" +#include "tls.h" #define CATMODULE "connection" @@ -98,9 +99,7 @@ static int _initialized = 0; static volatile client_queue_t *_req_queue = NULL, **_req_queue_tail = &_req_queue; static volatile client_queue_t *_con_queue = NULL, **_con_queue_tail = &_con_queue; static int ssl_ok; -#ifdef HAVE_OPENSSL -static SSL_CTX *ssl_ctx; -#endif +static tls_ctx_t *tls_ctx; /* filtering client connection based on IP */ static matchfile_t *banned_ip, *allowed_ip; @@ -131,9 +130,7 @@ void connection_shutdown(void) if (!_initialized) return; -#ifdef HAVE_OPENSSL - SSL_CTX_free (ssl_ctx); -#endif + tls_ctx_unref(tls_ctx); matchfile_release(banned_ip); matchfile_release(allowed_ip); @@ -160,46 +157,16 @@ static unsigned long _next_connection_id(void) #ifdef HAVE_OPENSSL static void get_ssl_certificate(ice_config_t *config) { - SSL_METHOD *method; - long ssl_opts; config->tls_ok = ssl_ok = 0; - SSL_load_error_strings(); /* readable error messages */ - SSL_library_init(); /* initialize library */ - - method = SSLv23_server_method(); - ssl_ctx = SSL_CTX_new(method); - ssl_opts = SSL_CTX_get_options(ssl_ctx); -#ifdef SSL_OP_NO_COMPRESSION - SSL_CTX_set_options(ssl_ctx, ssl_opts|SSL_OP_NO_SSLv2|SSL_OP_NO_SSLv3|SSL_OP_NO_COMPRESSION); -#else - SSL_CTX_set_options(ssl_ctx, ssl_opts|SSL_OP_NO_SSLv2|SSL_OP_NO_SSLv3); -#endif - - do { - if (config->cert_file == NULL) - break; - if (SSL_CTX_use_certificate_chain_file (ssl_ctx, config->cert_file) <= 0) { - ICECAST_LOG_WARN("Invalid cert file %s", config->cert_file); - break; - } - if (SSL_CTX_use_PrivateKey_file (ssl_ctx, config->cert_file, SSL_FILETYPE_PEM) <= 0) { - ICECAST_LOG_WARN("Invalid private key file %s", config->cert_file); - break; - } - if (!SSL_CTX_check_private_key (ssl_ctx)) { - ICECAST_LOG_ERROR("Invalid %s - Private key does not match cert public key", config->cert_file); - break; - } - if (SSL_CTX_set_cipher_list(ssl_ctx, config->cipher_list) <= 0) { - ICECAST_LOG_WARN("Invalid cipher list: %s", config->cipher_list); - } - config->tls_ok = ssl_ok = 1; - ICECAST_LOG_INFO("Certificate found at %s", config->cert_file); - ICECAST_LOG_INFO("Using ciphers %s", config->cipher_list); + tls_ctx_unref(tls_ctx); + tls_ctx = tls_ctx_new(config->cert_file, config->cert_file, config->cipher_list); + if (!tls_ctx) { + ICECAST_LOG_INFO("No TLS capability on any configured ports"); return; - } while (0); - ICECAST_LOG_INFO("No TLS capability on any configured ports"); + } + + config->tls_ok = ssl_ok = 1; } @@ -301,7 +268,7 @@ void connection_uses_ssl(connection_t *con) con->read = connection_read_ssl; con->send = connection_send_ssl; - con->ssl = SSL_new(ssl_ctx); + con->ssl = tls_ctx_SSL_new(tls_ctx); SSL_set_accept_state(con->ssl); SSL_set_fd(con->ssl, con->sock); #endif diff --git a/src/main.c b/src/main.c index 42759082..27b688f3 100644 --- a/src/main.c +++ b/src/main.c @@ -123,6 +123,7 @@ void initialize_subsystems(void) sock_initialize(); resolver_initialize(); config_initialize(); + tls_initialize(); connection_initialize(); global_initialize(); refbuf_initialize(); @@ -145,6 +146,7 @@ void shutdown_subsystems(void) global_shutdown(); connection_shutdown(); + tls_shutdown(); config_shutdown(); resolver_shutdown(); sock_shutdown(); diff --git a/src/tls.c b/src/tls.c new file mode 100644 index 00000000..e2b333f6 --- /dev/null +++ b/src/tls.c @@ -0,0 +1,138 @@ +/* Icecast + * + * This program is distributed under the GNU General Public License, version 2. + * A copy of this license is included with this source. + * + * Copyright 2016, Philipp "ph3-der-loewe" Schafft , + */ + +/** + * TLS support functions + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include "tls.h" + +#include "logging.h" +#define CATMODULE "tls" + +#ifdef HAVE_OPENSSL +struct tls_ctx_tag { + size_t refc; + SSL_CTX *ctx; +}; + +void tls_initialize(void) +{ + SSL_load_error_strings(); /* readable error messages */ + SSL_library_init(); /* initialize library */ +} +void tls_shutdown(void) +{ +} + +tls_ctx_t *tls_ctx_new(const char *cert_file, const char *key_file, const char *cipher_list) +{ + tls_ctx_t *ctx; + SSL_METHOD *method; + long ssl_opts; + + if (!cert_file || !key_file || !cipher_list) + return NULL; + + ctx = calloc(1, sizeof(*ctx)); + if (!ctx) + return NULL; + + method = SSLv23_server_method(); + + ctx->refc = 1; + ctx->ctx = SSL_CTX_new(method); + + ssl_opts = SSL_CTX_get_options(ctx->ctx); +#ifdef SSL_OP_NO_COMPRESSION + SSL_CTX_set_options(ctx->ctx, ssl_opts|SSL_OP_NO_SSLv2|SSL_OP_NO_SSLv3|SSL_OP_NO_COMPRESSION); +#else + SSL_CTX_set_options(ctx->ctx, ssl_opts|SSL_OP_NO_SSLv2|SSL_OP_NO_SSLv3); +#endif + + do { + if (SSL_CTX_use_certificate_chain_file(ctx->ctx, cert_file) <= 0) { + ICECAST_LOG_WARN("Invalid cert file %s", cert_file); + break; + } + if (SSL_CTX_use_PrivateKey_file(ctx->ctx, key_file, SSL_FILETYPE_PEM) <= 0) { + ICECAST_LOG_WARN("Invalid private key file %s", key_file); + break; + } + if (!SSL_CTX_check_private_key(ctx->ctx)) { + ICECAST_LOG_ERROR("Invalid %s - Private key does not match cert public key", key_file); + break; + } + if (SSL_CTX_set_cipher_list(ctx->ctx, cipher_list) <= 0) { + ICECAST_LOG_WARN("Invalid cipher list: %s", cipher_list); + } + ICECAST_LOG_INFO("Certificate found at %s", cert_file); + ICECAST_LOG_INFO("Using ciphers %s", cipher_list); + return ctx; + } while (0); + + ICECAST_LOG_INFO("Can not setup TLS."); + tls_ctx_unref(ctx); + return NULL; +} + +void tls_ctx_ref(tls_ctx_t *ctx) +{ + if (!ctx) + return; + + ctx->refc++; +} + +void tls_ctx_unref(tls_ctx_t *ctx) +{ + if (!ctx) + return; + + ctx->refc--; + + if (ctx->refc) + return; + + if (ctx->ctx) + SSL_CTX_free(ctx->ctx); + + free(ctx); +} + +SSL *tls_ctx_SSL_new(tls_ctx_t *ctx) +{ + if (!ctx) + return NULL; + return SSL_new(ctx->ctx); +} +#else +void tls_initialize(void) +{ +} +void tls_shutdown(void) +{ +} + +tls_ctx_t *tls_ctx_new(const char *cert_file, const char *key_file, const char *cipher_list) +{ + return NULL; +} +void tls_ctx_ref(tls_ctx_t *ctx) +{ +} +void tls_ctx_unref(tls_ctx_t *ctx) +{ +} +#endif diff --git a/src/tls.h b/src/tls.h new file mode 100644 index 00000000..43a66fea --- /dev/null +++ b/src/tls.h @@ -0,0 +1,30 @@ +/* Icecast + * + * This program is distributed under the GNU General Public License, version 2. + * A copy of this license is included with this source. + * + * Copyright 2016, Philipp "ph3-der-loewe" Schafft , + */ + +#ifndef __TLS_H__ +#define __TLS_H__ + +#ifdef HAVE_OPENSSL +#include +#include +#endif + +typedef struct tls_ctx_tag tls_ctx_t; + +void tls_initialize(void); +void tls_shutdown(void); + +tls_ctx_t *tls_ctx_new(const char *cert_file, const char *key_file, const char *cipher_list); +void tls_ctx_ref(tls_ctx_t *ctx); +void tls_ctx_unref(tls_ctx_t *ctx); + +#ifdef HAVE_OPENSSL +SSL *tls_ctx_SSL_new(tls_ctx_t *ctx); +#endif + +#endif