From 1c0232b784bb25b18069bc487395ac3be5c7f9df Mon Sep 17 00:00:00 2001 From: Jeremy Cohen Date: Mon, 25 Feb 2019 15:15:01 +0000 Subject: [PATCH 1/6] Initial suport for SSL connections via hiredis --- R/config.R | 5 ++++- R/redis.R | 8 ++++++++ src/connection.c | 30 ++++++++++++++++++++++++++++++ src/connection.h | 2 ++ src/registration.c | 1 + 5 files changed, 45 insertions(+), 1 deletion(-) diff --git a/R/config.R b/R/config.R index 05f95c9..2612aa3 100644 --- a/R/config.R +++ b/R/config.R @@ -70,7 +70,10 @@ redis_config <- function(..., config = list(...)) { port = as.integer(Sys_getenv("REDIS_PORT", 6379L)), path = NULL, password = NULL, - db = NULL) + db = NULL, + CApath = Sys_getenv("REDIS_SSL_CA_PATH", NULL), + certPath = Sys_getenv("REDIS_SSL_CERT_PATH", NULL), + keyPath = Sys_getenv("REDIS_SSL_KEY_PATH", NULL)) dots <- list(...) if (length(dots) > 0L && !identical(dots, config)) { warning("Ignoring dots in favour of config") diff --git a/R/redis.R b/R/redis.R index 8fe2053..d715a00 100644 --- a/R/redis.R +++ b/R/redis.R @@ -5,6 +5,9 @@ redis_connect <- function(config) { if (config$scheme == "redis") { ptr <- redis_connect_tcp(config$host, config$port) + } else if (config$scheme == "rediss") { + ptr <- redis_connect_tcp_ssl(config$host, config$port, config$CApath, + config$certPath, config$keyPath) } else { ptr <- redis_connect_unix(config$path) } @@ -21,6 +24,11 @@ redis_connect_tcp <- function(host, port) { .Call(Credux_redis_connect, host, as.integer(port)) } +redis_connect_tcp_ssl <- function(host, port, CApath, certPath, keyPath) { + .Call(Credux_redis_connect_ssl, host, as.integer(port), + CApath, certPath, keyPath) +} + redis_connect_unix <- function(path) { .Call(Credux_redis_connect_unix, path) } diff --git a/src/connection.c b/src/connection.c index 3f285e1..6dc719f 100644 --- a/src/connection.c +++ b/src/connection.c @@ -22,6 +22,36 @@ SEXP redux_redis_connect(SEXP host, SEXP port) { return extPtr; } +SEXP redux_redis_connect_ssl(SEXP host, SEXP port, SEXP CApath, + SEXP CERTpath, SEXP KEYpath) { + redisContext *context = redisConnect(CHAR(STRING_ELT(host, 0)), + INTEGER(port)[0]); + if (context == NULL) { + error("Creating context failed catastrophically [tcp_ssl]"); // # nocov + } + if (context->err != 0) { + const char * errstr = string_duplicate(context->errstr); + redisFree(context); + error("Failed to create context: %s", errstr); + } + if (redisSecureConnection(context, + CHAR(STRING_ELT(CApath, 0)), + CHAR(STRING_ELT(CERTpath, 0)), + CHAR(STRING_ELT(KEYpath, 0)), + CHAR(STRING_ELT(host, 0))) != REDIS_OK) { + redisFree(context); + if (context->err != 0) { + const char * errstr_ssl = string_duplicate(context->errstr); + error("Failed to initialize SSL connection: %s\n", context->errstr); + } + error("Failed to initialize SSL connection\n"); +} + SEXP extPtr = PROTECT(R_MakeExternalPtr(context, host, R_NilValue)); + R_RegisterCFinalizer(extPtr, redis_finalize); + UNPROTECT(1); + return extPtr; +} + SEXP redux_redis_connect_unix(SEXP path) { redisContext *context = redisConnectUnix(CHAR(STRING_ELT(path, 0))); if (context == NULL) { diff --git a/src/connection.h b/src/connection.h index 290c88c..584819f 100644 --- a/src/connection.h +++ b/src/connection.h @@ -4,6 +4,8 @@ #include SEXP redux_redis_connect(SEXP host, SEXP port); +SEXP redux_redis_connect_ssl(SEXP host, SEXP port, + SEXP CApath, SEXP certPath, SEXP keyPath); SEXP redux_redis_connect_unix(SEXP path); SEXP redux_redis_command(SEXP extPtr, SEXP cmd); diff --git a/src/registration.c b/src/registration.c index 651b1d3..5e75268 100644 --- a/src/registration.c +++ b/src/registration.c @@ -6,6 +6,7 @@ static const R_CallMethodDef callMethods[] = { {"Credux_redis_connect", (DL_FUNC) &redux_redis_connect, 2}, + {"Credux_redis_connect_ssl", (DL_FUNC) &redux_redis_connect_ssl, 5}, {"Credux_redis_connect_unix", (DL_FUNC) &redux_redis_connect_unix, 1}, {"Credux_redis_command", (DL_FUNC) &redux_redis_command, 2}, From f2403b6aeaffdb415cb590ff7039b7de01b89750 Mon Sep 17 00:00:00 2001 From: Jeremy Cohen Date: Tue, 5 Mar 2019 15:21:25 +0000 Subject: [PATCH 2/6] Added support for REDIS_CONNECTION_SCHEME env var. --- R/config.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R/config.R b/R/config.R index 2612aa3..08fad2e 100644 --- a/R/config.R +++ b/R/config.R @@ -65,7 +65,7 @@ redis_config <- function(..., config = list(...)) { ## 2 arg and char/int, unnamed (assume host/port?) defaults <- list( url = Sys_getenv("REDIS_URL", NULL), - scheme = "redis", + scheme = Sys_getenv("REDIS_CONNECTION_SCHEME", "redis"), host = Sys_getenv("REDIS_HOST", "127.0.0.1"), port = as.integer(Sys_getenv("REDIS_PORT", 6379L)), path = NULL, From 7e51b05dc4fecc35ca2146bd4bafa7a8224d88e4 Mon Sep 17 00:00:00 2001 From: Jeremy Cohen Date: Sat, 24 Oct 2020 21:02:47 +0100 Subject: [PATCH 3/6] SSL connection updated for hiredis 1.0.0 API --- src/connection.c | 36 ++++++++++++++++++++++++++++++------ src/connection.h | 1 + 2 files changed, 31 insertions(+), 6 deletions(-) diff --git a/src/connection.c b/src/connection.c index 6dc719f..61e1a58 100644 --- a/src/connection.c +++ b/src/connection.c @@ -24,6 +24,30 @@ SEXP redux_redis_connect(SEXP host, SEXP port) { SEXP redux_redis_connect_ssl(SEXP host, SEXP port, SEXP CApath, SEXP CERTpath, SEXP KEYpath) { + + // hiredis SSL connection context and error var + redisSSLContext *redis_ssl_context; + redisSSLContextError *redis_ssl_error; + + // Initialise OpenSSL + redisInitOpenSSL(); + + // Set up the SSL connection parameters + redis_ssl_context = redisCreateSSLContext( + CHAR(STRING_ELT(CApath, 0)), + NULL, /* not providing path to trusted certs */ + CHAR(STRING_ELT(CERTpath, 0)), + CHAR(STRING_ELT(KEYpath, 0)), + CHAR(STRING_ELT(host, 0)), + &redis_ssl_error); + + if(redis_ssl_context != REDIS_OK) { + redisFree(redis_ssl_context); + error("Failed to create SSL context: %s\n", + redisSSLContextGetError(redis_ssl_error)); + } + + // Initiate a connection with redis redisContext *context = redisConnect(CHAR(STRING_ELT(host, 0)), INTEGER(port)[0]); if (context == NULL) { @@ -32,20 +56,20 @@ SEXP redux_redis_connect_ssl(SEXP host, SEXP port, SEXP CApath, if (context->err != 0) { const char * errstr = string_duplicate(context->errstr); redisFree(context); + error("Failed to create context: %s", errstr); } - if (redisSecureConnection(context, - CHAR(STRING_ELT(CApath, 0)), - CHAR(STRING_ELT(CERTpath, 0)), - CHAR(STRING_ELT(KEYpath, 0)), - CHAR(STRING_ELT(host, 0))) != REDIS_OK) { + + // Now we have a connection established, we can negotiate the SSL connection + if (redisInitiateSSLWithContext(context, redis_ssl_context) != REDIS_OK) { redisFree(context); + redisFree(redis_ssl_context); if (context->err != 0) { const char * errstr_ssl = string_duplicate(context->errstr); error("Failed to initialize SSL connection: %s\n", context->errstr); } error("Failed to initialize SSL connection\n"); -} + } SEXP extPtr = PROTECT(R_MakeExternalPtr(context, host, R_NilValue)); R_RegisterCFinalizer(extPtr, redis_finalize); UNPROTECT(1); diff --git a/src/connection.h b/src/connection.h index 584819f..9db729f 100644 --- a/src/connection.h +++ b/src/connection.h @@ -1,6 +1,7 @@ #include #include #include +#include #include SEXP redux_redis_connect(SEXP host, SEXP port); From 8c20a76c76b504b3bf84af6ce6e4f9b900909f2c Mon Sep 17 00:00:00 2001 From: Jeremy Cohen Date: Tue, 27 Oct 2020 19:51:10 +0000 Subject: [PATCH 4/6] Fixing use of new hiredis SSL API --- src/connection.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/connection.c b/src/connection.c index 61e1a58..31a3d63 100644 --- a/src/connection.c +++ b/src/connection.c @@ -27,24 +27,24 @@ SEXP redux_redis_connect_ssl(SEXP host, SEXP port, SEXP CApath, // hiredis SSL connection context and error var redisSSLContext *redis_ssl_context; - redisSSLContextError *redis_ssl_error; + redisSSLContextError redis_ssl_error; // Initialise OpenSSL redisInitOpenSSL(); // Set up the SSL connection parameters redis_ssl_context = redisCreateSSLContext( - CHAR(STRING_ELT(CApath, 0)), + CHAR(STRING_ELT(CApath, 0)), NULL, /* not providing path to trusted certs */ CHAR(STRING_ELT(CERTpath, 0)), CHAR(STRING_ELT(KEYpath, 0)), CHAR(STRING_ELT(host, 0)), &redis_ssl_error); - if(redis_ssl_context != REDIS_OK) { - redisFree(redis_ssl_context); + if(redis_ssl_context == NULL || redis_ssl_error != 0) { error("Failed to create SSL context: %s\n", - redisSSLContextGetError(redis_ssl_error)); + (redis_ssl_error != 0) ? + redisSSLContextGetError(redis_ssl_error) : "Unknown error"); } // Initiate a connection with redis @@ -62,12 +62,13 @@ SEXP redux_redis_connect_ssl(SEXP host, SEXP port, SEXP CApath, // Now we have a connection established, we can negotiate the SSL connection if (redisInitiateSSLWithContext(context, redis_ssl_context) != REDIS_OK) { - redisFree(context); - redisFree(redis_ssl_context); + redisFreeSSLContext(redis_ssl_context); if (context->err != 0) { const char * errstr_ssl = string_duplicate(context->errstr); - error("Failed to initialize SSL connection: %s\n", context->errstr); + redisFree(context); + error("Failed to initialize SSL connection: %s\n", errstr_ssl); } + redisFree(context); error("Failed to initialize SSL connection\n"); } SEXP extPtr = PROTECT(R_MakeExternalPtr(context, host, R_NilValue)); From d3dcead1d072b90d6fafa34e6bdcbc0408f71ab9 Mon Sep 17 00:00:00 2001 From: Jeremy Cohen Date: Tue, 27 Oct 2020 20:25:37 +0000 Subject: [PATCH 5/6] Updating windows build config to use hiredis-1.0.0 with SSL --- src/Makevars.win | 4 ++-- tools/winlibs.R | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Makevars.win b/src/Makevars.win index 7de62f4..5cb28c1 100644 --- a/src/Makevars.win +++ b/src/Makevars.win @@ -1,6 +1,6 @@ # -*- makefile -*- -PKG_CPPFLAGS=-I../windows/hiredis-0.9.2/include/hiredis -DSTRICT_R_HEADERS -PKG_LIBS=-L../windows/hiredis-0.9.2/lib${R_ARCH} -lhiredis -lws2_32 +PKG_CPPFLAGS=-I../windows/hiredis-1.0.0/include/hiredis -DSTRICT_R_HEADERS +PKG_LIBS=-L../windows/hiredis-1.0.0/lib${R_ARCH} -lhiredis -lhiredis_ssl -lssl -lcrypto -lcrypt32 -lws2_32 all: clean winlibs diff --git a/tools/winlibs.R b/tools/winlibs.R index 5f9997c..3f1b5b9 100644 --- a/tools/winlibs.R +++ b/tools/winlibs.R @@ -1,6 +1,6 @@ -if (!file.exists("../windows/hiredis-0.9.2/include/hiredis/hiredis.h")) { +if (!file.exists("../windows/hiredis-1.0.0/include/hiredis/hiredis.h")) { if (getRversion() < "3.3.0") setInternet2() - download.file("https://github.com/rwinlib/hiredis/archive/v0.9.2.zip", "lib.zip", quiet = TRUE) + download.file("https://github.com/rwinlib/hiredis/archive/v1.0.0.zip", "lib.zip", quiet = TRUE) dir.create("../windows", showWarnings = FALSE) unzip("lib.zip", exdir = "../windows") unlink("lib.zip") From f93316a5ec72267adb90d4259201a0a9fb5e6b35 Mon Sep 17 00:00:00 2001 From: Jeremy Cohen Date: Wed, 1 Sep 2021 13:28:35 +0100 Subject: [PATCH 6/6] Add pkg-config detection of SSL hiredis library --- configure | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/configure b/configure index 7885df8..9a8232d 100755 --- a/configure +++ b/configure @@ -7,6 +7,7 @@ # Library settings PKG_CONFIG_NAME="hiredis" +PKG_CONFIG_SSL_NAME="hiredis_ssl" PKG_DEB_NAME="libhiredis-dev" PKG_RPM_NAME="hiredis-devel" PKG_BREW_NAME="hiredis" @@ -20,6 +21,12 @@ if [ $(command -v pkg-config) ]; then PKGCONFIG_LIBS=$(pkg-config --libs ${PKG_CONFIG_NAME}) fi +# Use pkg-config to find hiredis_ssl lib if available +if [ $(command -v pkg-config) ]; then + PKGCONFIG_CFLAGS="${PKGCONFIG_CFLAGS} $(pkg-config --cflags --silence-errors ${PKG_CONFIG_SSL_NAME})" + PKGCONFIG_LIBS="${PKGCONFIG_LIBS} $(pkg-config --libs ${PKG_CONFIG_SSL_NAME})" +fi + # Note that cflags may be empty in case of success if [ "$INCLUDE_DIR" ] || [ "$LIB_DIR" ]; then echo "Found INCLUDE_DIR and/or LIB_DIR!"