Skip to content

Commit e00a3c0

Browse files
Jérémie JourdinJérémie JourdinAmine EL AKKANIfrikilax
committed
Add support for TLS in omhiredis (#17)
* Add support for TLS in omhiredis * fix(omhiredis): Make redis SSL support user-configurable * fix(omhiredis): Adding SSL variables into conditinal compilation * fix(omhiredis): Ensure both client_cert and client_key are specified together * fix(omhiredis): fix SSL initialization for thread safety * fix(configure.ac): Need hiredis_ssl>=1.0.0 --------- Co-authored-by: Jérémie Jourdin <jeremie.jourdin@advens.fr> Co-authored-by: Amine EL AKKANI <aelakkani@P1564.myadvens.lan> Co-authored-by: frikilax <theo.bertin@advens.fr>
1 parent 7774541 commit e00a3c0

3 files changed

Lines changed: 141 additions & 2 deletions

File tree

configure.ac

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2860,6 +2860,16 @@ AC_ARG_ENABLE(redis_tests,
28602860
)
28612861
AM_CONDITIONAL(ENABLE_REDIS_TESTS, test x$enable_redis_tests = xyes)
28622862

2863+
AC_ARG_ENABLE(redis_ssl,
2864+
[AS_HELP_STRING([--enable-redis-ssl],[Enable redis ssl support @<:@default=no@:>@])],
2865+
[case "${enableval}" in
2866+
yes) enable_redis_ssl="yes" ;;
2867+
no) enable_redis_ssl="no" ;;
2868+
*) AC_MSG_ERROR(bad value ${enableval} for --enable-redis-ssl) ;;
2869+
esac],
2870+
[enable_redis_ssl=no]
2871+
)
2872+
28632873
if test "x$enable_omhiredis" = "xyes" -o "x$enable_imhiredis" = "xyes" ; then
28642874
PKG_CHECK_MODULES(HIREDIS, hiredis >= 0.10.1, [],
28652875
[AC_SEARCH_LIBS(redisConnectWithTimeout, hiredis,
@@ -2884,6 +2894,39 @@ if test "x$enable_omhiredis" = "xyes" -o "x$enable_imhiredis" = "xyes" ; then
28842894
[AC_MSG_ERROR([hiredis not found])]
28852895
)]
28862896
)
2897+
if test "x$enable_redis_ssl" = "xyes"; then
2898+
PKG_CHECK_MODULES(HIREDIS_SSL, hiredis_ssl >= 1.0.0,
2899+
# hiredis_ssl found using pkg-config
2900+
[
2901+
AC_DEFINE(HIREDIS_SSL, 1, [TLS support enabled in hiredis])
2902+
],
2903+
# hiredis_ssl not found with pkg-static, searching for it manually
2904+
[AC_SEARCH_LIBS(redisCreateSSLContext, hiredis_ssl,
2905+
[AC_COMPILE_IFELSE(
2906+
[AC_LANG_PROGRAM(
2907+
[[ #include <hiredis/hiredis.h>
2908+
#include <hiredis/hiredis_ssl.h>
2909+
]],
2910+
[[ #define major 1
2911+
#define minor 0
2912+
#define patch 0
2913+
#if (( HIREDIS_MAJOR > major ) || \
2914+
(( HIREDIS_MAJOR == major ) && ( HIREDIS_MINOR > minor )) || \
2915+
(( HIREDIS_MAJOR == major ) && ( HIREDIS_MINOR == minor ) && ( HIREDIS_PATCH >= patch ))) \
2916+
/* OK */
2917+
#else
2918+
# error Hiredis version must be >= major.minor.path for SSL support
2919+
#endif
2920+
]]
2921+
)],
2922+
[],
2923+
[AC_MSG_ERROR([hiredis version must be >= 1.0.0 for SSL support])]
2924+
)],
2925+
[AC_MSG_ERROR([hiredis_ssl not found, no TLS support in hiredis])]
2926+
)]
2927+
)
2928+
fi
2929+
28872930
fi
28882931

28892932
if test "x$enable_imhiredis" = "xyes" ; then
@@ -2894,6 +2937,7 @@ if test "x$enable_imhiredis" = "xyes" ; then
28942937
],
28952938
# libevent not found
28962939
[AC_MSG_ERROR([no libevent >= 2.0 found with pthreads support, imhiredis cannot use pub/sub])])
2940+
28972941
fi
28982942

28992943
if test "x$enable_imhiredis" = "xyes" || test "x$enable_omhiredis" = "xyes"; then
@@ -3359,6 +3403,7 @@ echo " Mbed TLS network stream driver enabled: $enable_mbedtls"
33593403
echo " GSSAPI Kerberos 5 support enabled: $enable_gssapi_krb5"
33603404
echo " RELP support enabled: $enable_relp"
33613405
echo " SNMP support enabled: $enable_snmp"
3406+
echo " redis ssl support enabled: $enable_redis_ssl"
33623407
echo
33633408
echo "---{ function modules }---"
33643409
echo " fmhttp enabled: $enable_fmhttp"

contrib/omhiredis/Makefile.am

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
pkglib_LTLIBRARIES = omhiredis.la
22
omhiredis_la_SOURCES = omhiredis.c
3-
omhiredis_la_CPPFLAGS = $(RSRT_CFLAGS) $(PTHREADS_CFLAGS) $(HIREDIS_CFLAGS)
3+
omhiredis_la_CPPFLAGS = $(RSRT_CFLAGS) $(PTHREADS_CFLAGS) $(HIREDIS_CFLAGS) $(HIREDIS_SSL_CFLAGS)
44
omhiredis_la_LDFLAGS = -module -avoid-version
5-
omhiredis_la_LIBADD = $(HIREDIS_LIBS)
5+
omhiredis_la_LIBADD = $(HIREDIS_LIBS) $(HIREDIS_SSL_LIBS)
66

77
EXTRA_DIST =

contrib/omhiredis/omhiredis.c

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@
1818
*
1919
* Author: Brian Knox
2020
* <bknox@digitalocean.com>
21+
*
22+
* Author: Jérémie Jourdin (TLS support)
23+
* <jeremie.jourdin@advens.fr>
2124
*/
2225

2326

@@ -32,6 +35,9 @@
3235
#include <time.h>
3336
#include <math.h>
3437
#include <hiredis/hiredis.h>
38+
#ifdef HIREDIS_SSL
39+
#include <hiredis/hiredis_ssl.h>
40+
#endif
3541

3642
#include "rsyslog.h"
3743
#include "conf.h"
@@ -94,13 +100,25 @@ typedef struct _instanceData {
94100
- $.redis!index
95101
Those 2 infos can either be provided through usage of imhiredis
96102
or set manually with Rainerscript */
103+
#ifdef HIREDIS_SSL
104+
sbool use_tls; /* Should we use TLS to connect to redis ? */
105+
char *ca_cert_bundle; /* CA bundle file */
106+
char *ca_cert_dir; /* Path of trusted certificates */
107+
char *client_cert; /* Client certificate */
108+
char *client_key; /* Client private key */
109+
char *sni; /* TLS Server Name Indication */
110+
#endif
97111

98112
} instanceData;
99113

100114
typedef struct wrkrInstanceData {
101115
instanceData *pData; /* instanc data */
102116
redisContext *conn; /* redis connection */
103117
int count; /* count of command sent for current batch */
118+
#ifdef HIREDIS_SSL
119+
redisSSLContext *ssl_conn; /* redis ssl connection */
120+
redisSSLContextError ssl_error; /* ssl error handler */
121+
#endif
104122
} wrkrInstanceData_t;
105123

106124
static struct cnfparamdescr actpdescr[] = {
@@ -124,6 +142,14 @@ static struct cnfparamdescr actpdescr[] = {
124142
{"stream.dynaKeyAck", eCmdHdlrBinary, 0},
125143
{"stream.dynaGroupAck", eCmdHdlrBinary, 0},
126144
{"stream.dynaIndexAck", eCmdHdlrBinary, 0},
145+
#ifdef HIREDIS_SSL
146+
{"use_tls", eCmdHdlrBinary, 0},
147+
{"ca_cert_bundle", eCmdHdlrGetWord, 0},
148+
{"ca_cert_dir", eCmdHdlrGetWord, 0},
149+
{"client_cert", eCmdHdlrGetWord, 0},
150+
{"client_key", eCmdHdlrGetWord, 0},
151+
{"sni", eCmdHdlrGetWord, 0},
152+
#endif
127153
};
128154

129155
static struct cnfparamblk actpblk = {CNFPARAMBLK_VERSION, sizeof(actpdescr) / sizeof(struct cnfparamdescr), actpdescr};
@@ -135,6 +161,10 @@ ENDcreateInstance
135161
BEGINcreateWrkrInstance
136162
CODESTARTcreateWrkrInstance;
137163
pWrkrData->conn = NULL; /* Connect later */
164+
#ifdef HIREDIS_SSL
165+
pWrkrData->ssl_conn = NULL; /* Connect later */
166+
pWrkrData->ssl_error = REDIS_SSL_CTX_NONE;
167+
#endif
138168
ENDcreateWrkrInstance
139169

140170
BEGINisCompatibleWithFeature
@@ -148,6 +178,12 @@ static void closeHiredis(wrkrInstanceData_t *pWrkrData) {
148178
redisFree(pWrkrData->conn);
149179
pWrkrData->conn = NULL;
150180
}
181+
#ifdef HIREDIS_SSL
182+
if (pWrkrData->ssl_conn != NULL) {
183+
redisFreeSSLContext(pWrkrData->ssl_conn);
184+
pWrkrData->ssl_conn = NULL;
185+
}
186+
#endif
151187
}
152188

153189
/* Free our instance data. */
@@ -167,6 +203,13 @@ BEGINfreeInstance
167203
free(pData->streamGroupAck);
168204
free(pData->streamIndexAck);
169205
free(pData->streamOutField);
206+
#ifdef HIREDIS_SSL
207+
free(pData->ca_cert_bundle);
208+
free(pData->ca_cert_dir);
209+
free(pData->client_cert);
210+
free(pData->client_key);
211+
free(pData->sni);
212+
#endif
170213
ENDfreeInstance
171214

172215
BEGINfreeWrkrInstance
@@ -220,6 +263,24 @@ static rsRetVal initHiredis(wrkrInstanceData_t *pWrkrData, int bSilent) {
220263
ABORT_FINALIZE(RS_RET_SUSPENDED);
221264
}
222265

266+
#ifdef HIREDIS_SSL
267+
if (pWrkrData->pData->use_tls) {
268+
pWrkrData->ssl_conn = redisCreateSSLContext(pWrkrData->pData->ca_cert_bundle, pWrkrData->pData->ca_cert_dir,
269+
pWrkrData->pData->client_cert, pWrkrData->pData->client_key,
270+
pWrkrData->pData->sni, &pWrkrData->ssl_error);
271+
if (!pWrkrData->ssl_conn || pWrkrData->ssl_error != REDIS_SSL_CTX_NONE) {
272+
LogError(0, NO_ERRCODE, "omhiredis: SSL Context error: %s", redisSSLContextGetError(pWrkrData->ssl_error));
273+
if (!bSilent) LogError(0, RS_RET_SUSPENDED, "[TLS] can not initialize redis handle");
274+
ABORT_FINALIZE(RS_RET_SUSPENDED);
275+
}
276+
if (redisInitiateSSLWithContext(pWrkrData->conn, pWrkrData->ssl_conn) != REDIS_OK) {
277+
LogError(0, NO_ERRCODE, "omhiredis: %s", pWrkrData->conn->errstr);
278+
if (!bSilent) LogError(0, RS_RET_SUSPENDED, "[TLS] can not initialize redis handle");
279+
ABORT_FINALIZE(RS_RET_SUSPENDED);
280+
}
281+
}
282+
#endif
283+
223284
if (pWrkrData->pData->serverpassword != NULL) {
224285
reply = redisCommand(pWrkrData->conn, "AUTH %s", (char *)pWrkrData->pData->serverpassword);
225286
if (reply == NULL) {
@@ -236,6 +297,12 @@ static rsRetVal initHiredis(wrkrInstanceData_t *pWrkrData, int bSilent) {
236297
redisFree(pWrkrData->conn);
237298
pWrkrData->conn = NULL;
238299
}
300+
#ifdef HIREDIS_SSL
301+
if (iRet != RS_RET_OK && pWrkrData->ssl_conn != NULL) {
302+
redisFreeSSLContext(pWrkrData->ssl_conn);
303+
pWrkrData->ssl_conn = NULL;
304+
}
305+
#endif
239306
if (reply != NULL) freeReplyObject(reply);
240307
RETiRet;
241308
}
@@ -476,6 +543,14 @@ static void setInstParamDefaults(instanceData *pData) {
476543
pData->streamCapacityLimit = 0;
477544
pData->streamAck = 0;
478545
pData->streamDel = 0;
546+
#ifdef HIREDIS_SSL
547+
pData->use_tls = 0;
548+
pData->ca_cert_bundle = NULL;
549+
pData->ca_cert_dir = NULL;
550+
pData->client_cert = NULL;
551+
pData->client_key = NULL;
552+
pData->sni = NULL;
553+
#endif
479554
}
480555

481556
/* here is where the work to set up a new instance
@@ -551,6 +626,20 @@ BEGINnewActInst
551626
} else if (!strcmp(actpblk.descr[i].name, "expiration")) {
552627
pData->expiration = pvals[i].val.d.n;
553628
dbgprintf("omhiredis: expiration set to %d\n", pData->expiration);
629+
#ifdef HIREDIS_SSL
630+
} else if (!strcmp(actpblk.descr[i].name, "use_tls")) {
631+
pData->use_tls = pvals[i].val.d.n;
632+
} else if (!strcmp(actpblk.descr[i].name, "ca_cert_bundle")) {
633+
pData->ca_cert_bundle = (char *)es_str2cstr(pvals[i].val.d.estr, NULL);
634+
} else if (!strcmp(actpblk.descr[i].name, "ca_cert_dir")) {
635+
pData->ca_cert_dir = (char *)es_str2cstr(pvals[i].val.d.estr, NULL);
636+
} else if (!strcmp(actpblk.descr[i].name, "client_cert")) {
637+
pData->client_cert = (char *)es_str2cstr(pvals[i].val.d.estr, NULL);
638+
} else if (!strcmp(actpblk.descr[i].name, "client_key")) {
639+
pData->client_key = (char *)es_str2cstr(pvals[i].val.d.estr, NULL);
640+
} else if (!strcmp(actpblk.descr[i].name, "sni")) {
641+
pData->sni = (char *)es_str2cstr(pvals[i].val.d.estr, NULL);
642+
#endif
554643
} else {
555644
dbgprintf(
556645
"omhiredis: program error, non-handled "
@@ -777,4 +866,9 @@ BEGINmodInit()
777866
ABORT_FINALIZE(RS_RET_ERR);
778867
}
779868
DBGPRINTF("omhiredis: module compiled with rsyslog version %s.\n", VERSION);
869+
870+
#ifdef HIREDIS_SSL
871+
// initialize OpenSSL
872+
redisInitOpenSSL();
873+
#endif
780874
ENDmodInit

0 commit comments

Comments
 (0)