From 0c1454490669f3c95e3c8b0ac6a83582d14e30e0 Mon Sep 17 00:00:00 2001 From: Mark Nunberg Date: Mon, 27 Nov 2017 13:10:21 +0000 Subject: Initial SSL (sync) implementation --- sslio.c | 197 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 197 insertions(+) create mode 100644 sslio.c (limited to 'sslio.c') diff --git a/sslio.c b/sslio.c new file mode 100644 index 0000000..9ee015b --- /dev/null +++ b/sslio.c @@ -0,0 +1,197 @@ +#include "hiredis.h" +#include "sslio.h" + +#include +#ifndef HIREDIS_NOSSL +#include + +void __redisSetError(redisContext *c, int type, const char *str); + +static void sslLogCallback(const SSL *ssl, int where, int ret) { + const char *retstr = ""; + int should_log = 1; + /* Ignore low-level SSL stuff */ + + if (where & SSL_CB_ALERT) { + should_log = 1; + } + if (where == SSL_CB_HANDSHAKE_START || where == SSL_CB_HANDSHAKE_DONE) { + should_log = 1; + } + if ((where & SSL_CB_EXIT) && ret == 0) { + should_log = 1; + } + + if (!should_log) { + return; + } + + retstr = SSL_alert_type_string(ret); + printf("ST(0x%x). %s. R(0x%x)%s\n", where, SSL_state_string_long(ssl), ret, retstr); + + if (where == SSL_CB_HANDSHAKE_DONE) { + printf("Using SSL version %s. Cipher=%s\n", SSL_get_version(ssl), SSL_get_cipher_name(ssl)); + } +} + +typedef pthread_mutex_t sslLockType; +static void sslLockInit(sslLockType *l) { + pthread_mutex_init(l, NULL); +} +static void sslLockAcquire(sslLockType *l) { + pthread_mutex_lock(l); +} +static void sslLockRelease(sslLockType *l) { + pthread_mutex_unlock(l); +} +static pthread_mutex_t *ossl_locks; + +static void opensslDoLock(int mode, int lkid, const char *f, int line) { + sslLockType *l = ossl_locks + lkid; + + if (mode & CRYPTO_LOCK) { + sslLockAcquire(l); + } else { + sslLockRelease(l); + } + + (void)f; + (void)line; +} + +static void initOpensslLocks(void) { + unsigned ii, nlocks; + if (CRYPTO_get_locking_callback() != NULL) { + /* Someone already set the callback before us. Don't destroy it! */ + return; + } + nlocks = CRYPTO_num_locks(); + ossl_locks = malloc(sizeof(*ossl_locks) * nlocks); + for (ii = 0; ii < nlocks; ii++) { + sslLockInit(ossl_locks + ii); + } + CRYPTO_set_locking_callback(opensslDoLock); +} + +void redisFreeSsl(redisSsl *ssl){ + if (ssl->ctx) { + SSL_CTX_free(ssl->ctx); + } + if (ssl->ssl) { + SSL_free(ssl->ssl); + } + free(ssl); +} + +int redisSslCreate(redisContext *c, const char *capath, const char *certpath, + const char *keypath) { + assert(!c->ssl); + c->ssl = calloc(1, sizeof(*c->ssl)); + static int isInit = 0; + if (!isInit) { + isInit = 1; + SSL_library_init(); + initOpensslLocks(); + } + + redisSsl *s = c->ssl; + s->ctx = SSL_CTX_new(SSLv23_client_method()); + SSL_CTX_set_info_callback(s->ctx, sslLogCallback); + SSL_CTX_set_mode(s->ctx, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); + SSL_CTX_set_options(s->ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3); + SSL_CTX_set_verify(s->ctx, SSL_VERIFY_PEER, NULL); + + if ((certpath != NULL && keypath == NULL) || (keypath != NULL && certpath == NULL)) { + __redisSetError(c, REDIS_ERR, "certpath and keypath must be specified together"); + return REDIS_ERR; + } + + if (capath) { + if (!SSL_CTX_load_verify_locations(s->ctx, capath, NULL)) { + __redisSetError(c, REDIS_ERR, "Invalid CA certificate"); + return REDIS_ERR; + } + } + if (certpath) { + if (!SSL_CTX_use_certificate_chain_file(s->ctx, certpath)) { + __redisSetError(c, REDIS_ERR, "Invalid client certificate"); + return REDIS_ERR; + } + if (!SSL_CTX_use_PrivateKey_file(s->ctx, keypath, SSL_FILETYPE_PEM)) { + __redisSetError(c, REDIS_ERR, "Invalid client key"); + return REDIS_ERR; + } + printf("Loaded certificate!\n"); + } + + s->ssl = SSL_new(s->ctx); + if (!s->ssl) { + __redisSetError(c, REDIS_ERR, "Couldn't create new SSL instance"); + return REDIS_ERR; + } + + SSL_set_fd(s->ssl, c->fd); + SSL_set_connect_state(s->ssl); + + c->flags |= REDIS_SSL; + printf("Before SSL_connect()\n"); + int rv = SSL_connect(c->ssl->ssl); + if (rv == 1) { + printf("SSL_connect() success!\n"); + return REDIS_OK; + } + printf("ConnectRV: %d\n", rv); + + rv = SSL_get_error(s->ssl, rv); + if (((c->flags & REDIS_BLOCK) == 0) && + (rv == SSL_ERROR_WANT_READ || rv == SSL_ERROR_WANT_WRITE)) { + return REDIS_OK; + } + + if (c->err == 0) { + __redisSetError(c, REDIS_ERR_IO, "SSL_connect() failed"); + printf("rv: %d\n", rv); + } + printf("ERROR!!!\n"); + return REDIS_ERR; +} + +int redisSslRead(redisContext *c, char *buf, size_t bufcap) { + int nread = SSL_read(c->ssl->ssl, buf, bufcap); + if (nread > 0) { + return nread; + } else if (nread == 0) { + __redisSetError(c, REDIS_ERR_EOF, "Server closed the connection"); + return -1; + } else { + int err = SSL_get_error(c->ssl->ssl, nread); + if (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE) { + return 0; + } else { + __redisSetError(c, REDIS_ERR_IO, NULL); + return -1; + } + } +} + +int redisSslWrite(redisContext *c) { + size_t len = c->ssl->lastLen ? c->ssl->lastLen : sdslen(c->obuf); + int rv = SSL_write(c->ssl->ssl, c->obuf, len); + + if (rv > 0) { + c->ssl->lastLen = 0; + } else if (rv < 0) { + c->ssl->lastLen = len; + + int err = SSL_get_error(c->ssl->ssl, rv); + if (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE) { + return 0; + } else { + __redisSetError(c, REDIS_ERR_IO, NULL); + return -1; + } + } + return rv; +} + +#endif -- cgit v1.2.3 From 5f50eb4131c98cb7c418c107317373292ad6ae6c Mon Sep 17 00:00:00 2001 From: Mark Nunberg Date: Mon, 27 Nov 2017 09:24:44 -0500 Subject: Remove extra printfs --- sslio.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) (limited to 'sslio.c') diff --git a/sslio.c b/sslio.c index 9ee015b..6958d37 100644 --- a/sslio.c +++ b/sslio.c @@ -7,6 +7,9 @@ void __redisSetError(redisContext *c, int type, const char *str); +/** + * Callback used for debugging + */ static void sslLogCallback(const SSL *ssl, int where, int ret) { const char *retstr = ""; int should_log = 1; @@ -96,7 +99,7 @@ int redisSslCreate(redisContext *c, const char *capath, const char *certpath, redisSsl *s = c->ssl; s->ctx = SSL_CTX_new(SSLv23_client_method()); - SSL_CTX_set_info_callback(s->ctx, sslLogCallback); + /* SSL_CTX_set_info_callback(s->ctx, sslLogCallback); */ SSL_CTX_set_mode(s->ctx, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); SSL_CTX_set_options(s->ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3); SSL_CTX_set_verify(s->ctx, SSL_VERIFY_PEER, NULL); @@ -121,7 +124,6 @@ int redisSslCreate(redisContext *c, const char *capath, const char *certpath, __redisSetError(c, REDIS_ERR, "Invalid client key"); return REDIS_ERR; } - printf("Loaded certificate!\n"); } s->ssl = SSL_new(s->ctx); @@ -134,13 +136,10 @@ int redisSslCreate(redisContext *c, const char *capath, const char *certpath, SSL_set_connect_state(s->ssl); c->flags |= REDIS_SSL; - printf("Before SSL_connect()\n"); int rv = SSL_connect(c->ssl->ssl); if (rv == 1) { - printf("SSL_connect() success!\n"); return REDIS_OK; } - printf("ConnectRV: %d\n", rv); rv = SSL_get_error(s->ssl, rv); if (((c->flags & REDIS_BLOCK) == 0) && @@ -150,9 +149,7 @@ int redisSslCreate(redisContext *c, const char *capath, const char *certpath, if (c->err == 0) { __redisSetError(c, REDIS_ERR_IO, "SSL_connect() failed"); - printf("rv: %d\n", rv); } - printf("ERROR!!!\n"); return REDIS_ERR; } -- cgit v1.2.3 From 08efa46599410e6b56ab19ed1c9a72c67476db9c Mon Sep 17 00:00:00 2001 From: Mark Nunberg Date: Mon, 27 Nov 2017 15:49:28 -0500 Subject: SSL for async I/O --- Makefile | 6 ++- async.c | 92 +++++++++++++++++++++++++++++++++++++++++ examples/example-libevent-ssl.c | 72 ++++++++++++++++++++++++++++++++ sslio.c | 22 ++++++++-- sslio.h | 9 ++++ 5 files changed, 197 insertions(+), 4 deletions(-) create mode 100644 examples/example-libevent-ssl.c (limited to 'sslio.c') diff --git a/Makefile b/Makefile index ea96419..b723245 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,8 @@ # This file is released under the BSD license, see the COPYING file OBJ=net.o hiredis.o sds.o async.o read.o sslio.o -EXAMPLES=hiredis-example hiredis-example-libevent hiredis-example-libev hiredis-example-glib hiredis-example-ssl +EXAMPLES=hiredis-example hiredis-example-libevent hiredis-example-libev hiredis-example-glib \ + hiredis-example-ssl hiredis-example-libevent-ssl TESTS=hiredis-test LIBNAME=libhiredis PKGCONFNAME=hiredis.pc @@ -94,6 +95,9 @@ static: $(STLIBNAME) hiredis-example-libevent: examples/example-libevent.c adapters/libevent.h $(STLIBNAME) $(CC) -o examples/$@ $(REAL_CFLAGS) $(REAL_LDFLAGS) -I. $< -levent $(STLIBNAME) +hiredis-example-libevent-ssl: examples/example-libevent-ssl.c adapters/libevent.h $(STLIBNAME) + $(CC) -o examples/$@ $(REAL_CFLAGS) $(REAL_LDFLAGS) -I. $< -levent $(STLIBNAME) + hiredis-example-libev: examples/example-libev.c adapters/libev.h $(STLIBNAME) $(CC) -o examples/$@ $(REAL_CFLAGS) $(REAL_LDFLAGS) -I. $< -lev $(STLIBNAME) diff --git a/async.c b/async.c index 0cecd30..5a14d45 100644 --- a/async.c +++ b/async.c @@ -40,6 +40,7 @@ #include "net.h" #include "dict.c" #include "sds.h" +#include "sslio.h" #define _EL_ADD_READ(ctx) do { \ if ((ctx)->ev.addRead) (ctx)->ev.addRead((ctx)->ev.data); \ @@ -524,6 +525,87 @@ static int __redisAsyncHandleConnect(redisAsyncContext *ac) { } } +#ifndef HIREDIS_NOSSL +/** + * Handle SSL when socket becomes available for reading. This also handles + * read-while-write and write-while-read + */ +static void asyncSslRead(redisAsyncContext *ac) { + int rv; + redisSsl *ssl = ac->c.ssl; + redisContext *c = &ac->c; + + ssl->wantRead = 0; + + if (ssl->pendingWrite) { + int done; + + /* This is probably just a write event */ + ssl->pendingWrite = 0; + rv = redisBufferWrite(c, &done); + if (rv == REDIS_ERR) { + __redisAsyncDisconnect(ac); + return; + } else if (!done) { + _EL_ADD_WRITE(ac); + } + } + + rv = redisBufferRead(c); + if (rv == REDIS_ERR) { + __redisAsyncDisconnect(ac); + } else { + _EL_ADD_READ(ac); + redisProcessCallbacks(ac); + } +} + +/** + * Handle SSL when socket becomes available for writing + */ +static void asyncSslWrite(redisAsyncContext *ac) { + int rv, done = 0; + redisSsl *ssl = ac->c.ssl; + redisContext *c = &ac->c; + + ssl->pendingWrite = 0; + rv = redisBufferWrite(c, &done); + if (rv == REDIS_ERR) { + __redisAsyncDisconnect(ac); + return; + } + + if (!done) { + if (ssl->wantRead) { + /* Need to read-before-write */ + ssl->pendingWrite = 1; + _EL_DEL_WRITE(ac); + } else { + /* No extra reads needed, just need to write more */ + _EL_ADD_WRITE(ac); + } + } else { + /* Already done! */ + _EL_DEL_WRITE(ac); + } + + /* Always reschedule a read */ + _EL_ADD_READ(ac); +} +#else + +/* Just so we're able to compile */ +static void asyncSslRead(redisAsyncContext *ac) { + abort(); + (void)ac; +} +static void asyncSslWrite(redisAsyncContext *ac) { + abort(); + (void)ac; +} + +#endif + /* This function should be called when the socket is readable. * It processes all replies that can be read and executes their callbacks. */ @@ -539,6 +621,11 @@ void redisAsyncHandleRead(redisAsyncContext *ac) { return; } + if (c->flags & REDIS_SSL) { + asyncSslRead(ac); + return; + } + if (redisBufferRead(c) == REDIS_ERR) { __redisAsyncDisconnect(ac); } else { @@ -561,6 +648,11 @@ void redisAsyncHandleWrite(redisAsyncContext *ac) { return; } + if (c->flags & REDIS_SSL) { + asyncSslWrite(ac); + return; + } + if (redisBufferWrite(c,&done) == REDIS_ERR) { __redisAsyncDisconnect(ac); } else { diff --git a/examples/example-libevent-ssl.c b/examples/example-libevent-ssl.c new file mode 100644 index 0000000..f780e3e --- /dev/null +++ b/examples/example-libevent-ssl.c @@ -0,0 +1,72 @@ +#include +#include +#include +#include + +#include +#include +#include + +void getCallback(redisAsyncContext *c, void *r, void *privdata) { + redisReply *reply = r; + if (reply == NULL) return; + printf("argv[%s]: %s\n", (char*)privdata, reply->str); + + /* Disconnect after receiving the reply to GET */ + redisAsyncDisconnect(c); +} + +void connectCallback(const redisAsyncContext *c, int status) { + if (status != REDIS_OK) { + printf("Error: %s\n", c->errstr); + return; + } + printf("Connected...\n"); +} + +void disconnectCallback(const redisAsyncContext *c, int status) { + if (status != REDIS_OK) { + printf("Error: %s\n", c->errstr); + return; + } + printf("Disconnected...\n"); +} + +int main (int argc, char **argv) { + signal(SIGPIPE, SIG_IGN); + struct event_base *base = event_base_new(); + if (argc < 5) { + fprintf(stderr, + "Usage: %s [ca]\n", argv[0]); + exit(1); + } + + const char *value = argv[1]; + size_t nvalue = strlen(value); + + const char *hostname = argv[2]; + int port = atoi(argv[3]); + + const char *cert = argv[4]; + const char *certKey = argv[5]; + const char *caCert = argc > 5 ? argv[6] : NULL; + + redisAsyncContext *c = redisAsyncConnect(hostname, port); + if (c->err) { + /* Let *c leak for now... */ + printf("Error: %s\n", c->errstr); + return 1; + } + if (redisSecureConnection(&c->c, caCert, cert, certKey) != REDIS_OK) { + printf("SSL Error!\n"); + exit(1); + } + + redisLibeventAttach(c,base); + redisAsyncSetConnectCallback(c,connectCallback); + redisAsyncSetDisconnectCallback(c,disconnectCallback); + redisAsyncCommand(c, NULL, NULL, "SET key %b", value, nvalue); + redisAsyncCommand(c, getCallback, (char*)"end-1", "GET key"); + event_base_dispatch(base); + return 0; +} diff --git a/sslio.c b/sslio.c index 6958d37..3b08140 100644 --- a/sslio.c +++ b/sslio.c @@ -99,7 +99,7 @@ int redisSslCreate(redisContext *c, const char *capath, const char *certpath, redisSsl *s = c->ssl; s->ctx = SSL_CTX_new(SSLv23_client_method()); - /* SSL_CTX_set_info_callback(s->ctx, sslLogCallback); */ + SSL_CTX_set_info_callback(s->ctx, sslLogCallback); SSL_CTX_set_mode(s->ctx, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); SSL_CTX_set_options(s->ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3); SSL_CTX_set_verify(s->ctx, SSL_VERIFY_PEER, NULL); @@ -153,6 +153,22 @@ int redisSslCreate(redisContext *c, const char *capath, const char *certpath, return REDIS_ERR; } +static int maybeCheckWant(redisSsl *rssl, int rv) { + /** + * If the error is WANT_READ or WANT_WRITE, the appropriate flags are set + * and true is returned. False is returned otherwise + */ + if (rv == SSL_ERROR_WANT_READ) { + rssl->wantRead = 1; + return 1; + } else if (rv == SSL_ERROR_WANT_WRITE) { + rssl->pendingWrite = 1; + return 1; + } else { + return 0; + } +} + int redisSslRead(redisContext *c, char *buf, size_t bufcap) { int nread = SSL_read(c->ssl->ssl, buf, bufcap); if (nread > 0) { @@ -162,7 +178,7 @@ int redisSslRead(redisContext *c, char *buf, size_t bufcap) { return -1; } else { int err = SSL_get_error(c->ssl->ssl, nread); - if (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE) { + if (maybeCheckWant(c->ssl, err)) { return 0; } else { __redisSetError(c, REDIS_ERR_IO, NULL); @@ -181,7 +197,7 @@ int redisSslWrite(redisContext *c) { c->ssl->lastLen = len; int err = SSL_get_error(c->ssl->ssl, rv); - if (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE) { + if (maybeCheckWant(c->ssl, err)) { return 0; } else { __redisSetError(c, REDIS_ERR_IO, NULL); diff --git a/sslio.h b/sslio.h index a410cb3..1f46b03 100644 --- a/sslio.h +++ b/sslio.h @@ -33,6 +33,15 @@ typedef struct redisSsl { * previously called with in the event of an SSL_read/SSL_write situation */ size_t lastLen; + + /** Whether the SSL layer requires read (possibly before a write) */ + int wantRead; + + /** + * Whether a write was requested prior to a read. If set, the write() + * should resume whenever a read takes place, if possible + */ + int pendingWrite; } redisSsl; struct redisContext; -- cgit v1.2.3 From 82549a53de4483b368008485d74028f302fd0e60 Mon Sep 17 00:00:00 2001 From: Mark Nunberg Date: Mon, 8 Jan 2018 16:07:10 -0500 Subject: Disable SSL by default --- Makefile | 8 +++++--- sslio.c | 2 +- sslio.h | 21 ++++++++++++++------- 3 files changed, 20 insertions(+), 11 deletions(-) (limited to 'sslio.c') diff --git a/Makefile b/Makefile index b723245..f7ed675 100644 --- a/Makefile +++ b/Makefile @@ -54,9 +54,11 @@ DYLIB_MAKE_CMD=$(CC) -shared -Wl,-soname,$(DYLIB_MINOR_NAME) -o $(DYLIBNAME) $(L STLIBNAME=$(LIBNAME).$(STLIBSUFFIX) STLIB_MAKE_CMD=$(AR) rcs $(STLIBNAME) -OPENSSL_PREFIX=/usr/local/opt/openssl -CFLAGS+=-I$(OPENSSL_PREFIX)/include -LDFLAGS+=-L$(OPENSSL_PREFIX)/lib -lssl -lcrypto +ifdef USE_SSL + OPENSSL_PREFIX=/usr/local/opt/openssl + CFLAGS+=-I$(OPENSSL_PREFIX)/include -DHIREDIS_SSL + LDFLAGS+=-L$(OPENSSL_PREFIX)/lib -lssl -lcrypto +endif # Platform-specific overrides uname_S := $(shell sh -c 'uname -s 2>/dev/null || echo not') diff --git a/sslio.c b/sslio.c index 3b08140..721a63a 100644 --- a/sslio.c +++ b/sslio.c @@ -2,7 +2,7 @@ #include "sslio.h" #include -#ifndef HIREDIS_NOSSL +#ifdef HIREDIS_SSL #include void __redisSetError(redisContext *c, int type, const char *str); diff --git a/sslio.h b/sslio.h index 1f46b03..9edac87 100644 --- a/sslio.h +++ b/sslio.h @@ -2,19 +2,26 @@ #define REDIS_SSLIO_H -#ifdef HIREDIS_NOSSL +#ifndef HIREDIS_SSL typedef struct redisSsl { - int dummy; + size_t lastLen; + int wantRead; + int pendingWrite; } redisSsl; -static void redisFreeSsl(redisSsl *) { +static inline void redisFreeSsl(redisSsl *ssl) { + (void)ssl; } -static int redisSslCreate(struct redisContext *c) { +static inline int redisSslCreate(struct redisContext *c, const char *ca, + const char *cert, const char *key) { + (void)c;(void)ca;(void)cert;(void)key; return REDIS_ERR; } -static int redisSslRead(struct redisContect *c, char *s, size_t, n) { +static inline int redisSslRead(struct redisContext *c, char *s, size_t n) { + (void)c;(void)s;(void)n; return -1; } -static int redisSslWrite(struct redisContext *c) { +static inline int redisSslWrite(struct redisContext *c) { + (void)c; return -1; } #else @@ -53,5 +60,5 @@ int redisSslCreate(struct redisContext *c, const char *caPath, int redisSslRead(struct redisContext *c, char *buf, size_t bufcap); int redisSslWrite(struct redisContext *c); -#endif /* !HIREDIS_NOSSL */ +#endif /* HIREDIS_SSL */ #endif /* HIREDIS_SSLIO_H */ -- cgit v1.2.3 From bc2a8f372a9f073e2fc00c34ba11cb3cb671f252 Mon Sep 17 00:00:00 2001 From: Mark Nunberg Date: Mon, 8 Jan 2018 16:09:53 -0500 Subject: Minor SSL-related fixes --- Makefile | 4 +++- sslio.c | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) (limited to 'sslio.c') diff --git a/Makefile b/Makefile index f7ed675..7e3e2bf 100644 --- a/Makefile +++ b/Makefile @@ -55,7 +55,9 @@ STLIBNAME=$(LIBNAME).$(STLIBSUFFIX) STLIB_MAKE_CMD=$(AR) rcs $(STLIBNAME) ifdef USE_SSL - OPENSSL_PREFIX=/usr/local/opt/openssl + # This is the prefix of openssl on my system. This should be the sane default + # based on the platform + OPENSSL_PREFIX?=/usr/local/opt/openssl CFLAGS+=-I$(OPENSSL_PREFIX)/include -DHIREDIS_SSL LDFLAGS+=-L$(OPENSSL_PREFIX)/lib -lssl -lcrypto endif diff --git a/sslio.c b/sslio.c index 721a63a..8933f95 100644 --- a/sslio.c +++ b/sslio.c @@ -57,7 +57,7 @@ static void opensslDoLock(int mode, int lkid, const char *f, int line) { } else { sslLockRelease(l); } - + (void)f; (void)line; } -- cgit v1.2.3 From 58222c26f4889c3f83c453bd7ec87e387459fd0c Mon Sep 17 00:00:00 2001 From: valentino Date: Thu, 20 Dec 2018 16:26:24 +0200 Subject: Support SNI --- examples/example-libevent-ssl.c | 2 +- examples/example-ssl.c | 2 +- hiredis.c | 4 ++-- hiredis.h | 2 +- sslio.c | 8 +++++++- sslio.h | 6 +++--- 6 files changed, 15 insertions(+), 9 deletions(-) (limited to 'sslio.c') diff --git a/examples/example-libevent-ssl.c b/examples/example-libevent-ssl.c index f780e3e..562e1a1 100644 --- a/examples/example-libevent-ssl.c +++ b/examples/example-libevent-ssl.c @@ -57,7 +57,7 @@ int main (int argc, char **argv) { printf("Error: %s\n", c->errstr); return 1; } - if (redisSecureConnection(&c->c, caCert, cert, certKey) != REDIS_OK) { + if (redisSecureConnection(&c->c, caCert, cert, certKey, "sni") != REDIS_OK) { printf("SSL Error!\n"); exit(1); } diff --git a/examples/example-ssl.c b/examples/example-ssl.c index 28489e4..a90b78a 100644 --- a/examples/example-ssl.c +++ b/examples/example-ssl.c @@ -30,7 +30,7 @@ int main(int argc, char **argv) { exit(1); } - if (redisSecureConnection(c, ca, cert, key) != REDIS_OK) { + if (redisSecureConnection(c, ca, cert, key, "sni") != REDIS_OK) { printf("Couldn't initialize SSL!\n"); printf("Error: %s\n", c->errstr); redisFree(c); diff --git a/hiredis.c b/hiredis.c index 7ba51f6..dd499b8 100644 --- a/hiredis.c +++ b/hiredis.c @@ -753,8 +753,8 @@ redisContext *redisConnectFd(int fd) { } int redisSecureConnection(redisContext *c, const char *caPath, - const char *certPath, const char *keyPath) { - return redisSslCreate(c, caPath, certPath, keyPath); + const char *certPath, const char *keyPath, const char *servername) { + return redisSslCreate(c, caPath, certPath, keyPath, servername); } /* Set read/write timeout on a blocking socket. */ diff --git a/hiredis.h b/hiredis.h index bb9b6a7..0d646f8 100644 --- a/hiredis.h +++ b/hiredis.h @@ -207,7 +207,7 @@ redisContext *redisConnectFd(int fd); * executed on the connection. */ int redisSecureConnection(redisContext *c, const char *capath, const char *certpath, - const char *keypath); + const char *keypath, const char *servername); /** * Reconnect the given context using the saved information. diff --git a/sslio.c b/sslio.c index 8933f95..efbf06e 100644 --- a/sslio.c +++ b/sslio.c @@ -87,7 +87,7 @@ void redisFreeSsl(redisSsl *ssl){ } int redisSslCreate(redisContext *c, const char *capath, const char *certpath, - const char *keypath) { + const char *keypath, const char *servername) { assert(!c->ssl); c->ssl = calloc(1, sizeof(*c->ssl)); static int isInit = 0; @@ -131,6 +131,12 @@ int redisSslCreate(redisContext *c, const char *capath, const char *certpath, __redisSetError(c, REDIS_ERR, "Couldn't create new SSL instance"); return REDIS_ERR; } + if (servername) { + if (!SSL_set_tlsext_host_name(s->ssl, servername)) { + __redisSetError(c, REDIS_ERR, "Couldn't set server name indication"); + return REDIS_ERR; + } + } SSL_set_fd(s->ssl, c->fd); SSL_set_connect_state(s->ssl); diff --git a/sslio.h b/sslio.h index 9edac87..e5493b7 100644 --- a/sslio.h +++ b/sslio.h @@ -12,8 +12,8 @@ static inline void redisFreeSsl(redisSsl *ssl) { (void)ssl; } static inline int redisSslCreate(struct redisContext *c, const char *ca, - const char *cert, const char *key) { - (void)c;(void)ca;(void)cert;(void)key; + const char *cert, const char *key, const char *servername) { + (void)c;(void)ca;(void)cert;(void)key;(void)servername; return REDIS_ERR; } static inline int redisSslRead(struct redisContext *c, char *s, size_t n) { @@ -55,7 +55,7 @@ struct redisContext; void redisFreeSsl(redisSsl *); int redisSslCreate(struct redisContext *c, const char *caPath, - const char *certPath, const char *keyPath); + const char *certPath, const char *keyPath, const char *servername); int redisSslRead(struct redisContext *c, char *buf, size_t bufcap); int redisSslWrite(struct redisContext *c); -- cgit v1.2.3