From 83fe141f7eba70af8b3b7e0dda752c8e9e22cd1a Mon Sep 17 00:00:00 2001 From: Jessie Murray Date: Mon, 11 Oct 2021 21:36:24 -0700 Subject: [PATCH] Encrypt connections to Redis Initialize SSL, use SSL context with each connection, enable flags in Makefile. TODO: read config into s->cfg, still missing for now --- Makefile | 9 ++++++++- src/conf.h | 11 +++++++++++ src/pool.c | 13 +++++++++++++ src/server.c | 28 ++++++++++++++++++++++++++++ src/server.h | 13 ++++++++++++- 5 files changed, 72 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index eb28f49..29ebef0 100644 --- a/Makefile +++ b/Makefile @@ -60,7 +60,14 @@ CFLAGS += $(DEBUG_FLAGS) # if `make` is run with SSL=1, include hiredis SSL support ifeq ($(SSL),1) - HIREDIS_OBJ += " src/hiredis/ssl.o" + HIREDIS_OBJ += src/hiredis/ssl.o + CFLAGS += -DHAVE_SSL=1 + LDFLAGS += -lssl -lcrypto + ifneq (, $(shell which brew)) # Homebrew + CFLAGS += -I$(shell brew --prefix)/opt/openssl/include + LDFLAGS += -L$(shell brew --prefix)/opt/openssl/lib + endif + # On Ubuntu and Alpine, LDFLAGS are enough since the SSL headers are under /usr/include/openssl endif OBJS_DEPS=$(wildcard *.d) diff --git a/src/conf.h b/src/conf.h index 475d8e7..5d9f44a 100644 --- a/src/conf.h +++ b/src/conf.h @@ -52,6 +52,17 @@ struct conf { int period_millis; /* only used with LOG_FSYNC_MILLIS */ } log_fsync; +#ifdef HAVE_SSL + /* SSL */ + struct { + char *ca_cert_bundle; /* File name of trusted CA/ca bundle file, optional */ + char *path_to_certs; /* Path of trusted certificates, optional */ + char *client_cert_pem; /* File name of client certificate file, optional */ + char *client_key_pem; /* File name of client private key, optional */ + char *redis_sni; /* Server name to request (SNI), optional */ + } ssl; +#endif + /* Request to serve on “/” */ char *default_root; }; diff --git a/src/pool.c b/src/pool.c index f3e7b42..b439a36 100644 --- a/src/pool.c +++ b/src/pool.c @@ -46,6 +46,19 @@ pool_on_connect(const redisAsyncContext *ac, int status) { } /* connected to redis! */ +#ifdef HAVE_SSL +/* Negotiate SSL/TLS */ +if (redisInitiateSSLWithContext((redisContext*)&ac->c, p->w->s->ssl_context) != REDIS_OK) { + /* Handle error, in c->err / c->errstr */ + slog(p->w->s, WEBDIS_ERROR, "SSL negotiation failed", 0); + if (ac->c.err) { /* non-zero on error */ + slog(p->w->s, WEBDIS_ERROR, ac->c.errstr, 0); + } + pool_schedule_reconnect(p); + return; +} +#endif + /* add to pool */ for(i = 0; i < p->count; ++i) { if(p->ac[i] == NULL) { diff --git a/src/server.c b/src/server.c index 72432bd..b785f5e 100644 --- a/src/server.c +++ b/src/server.c @@ -91,6 +91,30 @@ socket_setup(struct server *s, const char *ip, int port) { return fd; } +#ifdef HAVE_SSL +static void +server_init_ssl(struct server *s) { + redisInitOpenSSL(); + + /* Create SSL context, see docs in cfg.h */ + s->ssl_context = redisCreateSSLContext( + s->cfg->ssl.ca_cert_bundle, + s->cfg->ssl.path_to_certs, + s->cfg->ssl.client_cert_pem, + s->cfg->ssl.client_key_pem, + s->cfg->ssl.redis_sni, + &s->ssl_error); + + if(s->ssl_context == NULL || s->ssl_error != 0) { + fprintf(stderr, "SSL error: %s\n", + (s->ssl_error != 0) + ? redisSSLContextGetError(s->ssl_error) + : "Unknown error"); + exit(EXIT_FAILURE); + } +} +#endif + struct server * server_new(const char *cfg_file) { @@ -100,6 +124,10 @@ server_new(const char *cfg_file) { s->log.fd = -1; s->cfg = conf_read(cfg_file); +#ifdef HAVE_SSL + server_init_ssl(s); +#endif + /* workers */ s->w = calloc(s->cfg->http_threads, sizeof(struct worker*)); for(i = 0; i < s->cfg->http_threads; ++i) { diff --git a/src/server.h b/src/server.h index 3eebd72..a62dac2 100644 --- a/src/server.h +++ b/src/server.h @@ -2,9 +2,14 @@ #define SERVER_H #include -#include #include +#include +#ifdef HAVE_SSL +#include +#include +#endif + struct worker; struct conf; @@ -16,6 +21,12 @@ struct server { struct conf *cfg; +#ifdef HAVE_SSL + /* SSL context & error code */ + redisSSLContext *ssl_context; + redisSSLContextError ssl_error; +#endif + /* worker threads */ struct worker **w; int next_worker;