From dcc450626c4fbe8553faf24a5030e6db276873da Mon Sep 17 00:00:00 2001 From: Michael Kaufmann Date: Wed, 12 Aug 2020 16:20:56 +0200 Subject: [PATCH] TLS: Validate the hostname of the server certificate Avoid MITM attacks by checking whether the server's certificate contains the server's hostname. Currently this works only with OpenSSL 1.1.0 or newer. --- hiredis_ssl.h | 5 +++-- ssl.c | 20 +++++++++++++++++++- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/hiredis_ssl.h b/hiredis_ssl.h index 604efe0c1..bf11b095f 100644 --- a/hiredis_ssl.h +++ b/hiredis_ssl.h @@ -88,8 +88,9 @@ int redisInitOpenSSL(void); * certificate and private key files to use for authentication. They need to * be both specified or omitted. * - * server_name is an optional and will be used as a server name indication - * (SNI) TLS extension. + * server_name is optional and will be used as a server name indication (SNI) + * TLS extension and to validate the hostname of the server's certificate + * (this requires OpenSSL 1.1.0 or newer). * * If error is non-null, it will be populated in case the context creation fails * (returning a NULL). diff --git a/ssl.c b/ssl.c index 7df58fbde..eaf39aedb 100644 --- a/ssl.c +++ b/ssl.c @@ -44,6 +44,7 @@ #include #include +#include #include "win32.h" #include "async_private.h" @@ -85,6 +86,14 @@ typedef struct redisSSL { /* Forward declaration */ redisContextFuncs redisContextSSLFuncs; +/** + * OpenSSL hostname validation for OpenSSL >= 1.1.0 + * Reference: https://wiki.openssl.org/index.php/Hostname_validation + */ +#if OPENSSL_VERSION_NUMBER >= 0x10100000L +#define HIREDIS_CHECK_SSL_SERVER_NAME +#endif + /** * OpenSSL global initialization and locking handling callbacks. * Note that this is only required for OpenSSL < 1.1.0. @@ -348,9 +357,18 @@ int redisInitiateSSLWithContext(redisContext *c, redisSSLContext *redis_ssl_ctx) if (redis_ssl_ctx->server_name) { if (!SSL_set_tlsext_host_name(ssl, redis_ssl_ctx->server_name)) { - __redisSetError(c, REDIS_ERR_OTHER, "Failed to set server_name/SNI"); + __redisSetError(c, REDIS_ERR_OTHER, + "Failed to set server name for SNI"); goto error; } +#ifdef HIREDIS_CHECK_SSL_SERVER_NAME + SSL_set_hostflags(ssl, X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS); + if (!SSL_set1_host(ssl, redis_ssl_ctx->server_name)) { + __redisSetError(c, REDIS_ERR_OTHER, + "Failed to set server name for certificate validation"); + goto error; + } +#endif } return redisSSLConnect(c, ssl);