TLS: Add different client cert support. (#8076)
This adds a new `tls-client-cert-file` and `tls-client-key-file` configuration directives which make it possible to use different certificates for the TLS-server and TLS-client functions of Redis. This is an optional directive. If it is not specified the `tls-cert-file` and `tls-key-file` directives are used for TLS client functions as well. Also, `utils/gen-test-certs.sh` now creates additional server-only and client-only certs and will skip intensive operations if target files already exist.
This commit is contained in:
parent
4e064fbab4
commit
8c291b97b9
12
redis.conf
12
redis.conf
@ -151,6 +151,18 @@ tcp-keepalive 300
|
|||||||
# tls-cert-file redis.crt
|
# tls-cert-file redis.crt
|
||||||
# tls-key-file redis.key
|
# tls-key-file redis.key
|
||||||
|
|
||||||
|
# Normally Redis uses the same certificate for both server functions (accepting
|
||||||
|
# connections) and client functions (replicating from a master, establishing
|
||||||
|
# cluster bus connections, etc.).
|
||||||
|
#
|
||||||
|
# Sometimes certificates are issued with attributes that designate them as
|
||||||
|
# client-only or server-only certificates. In that case it may be desired to use
|
||||||
|
# different certificates for incoming (server) and outgoing (client)
|
||||||
|
# connections. To do that, use the following directives:
|
||||||
|
#
|
||||||
|
# tls-client-cert-file client.crt
|
||||||
|
# tls-client-key-file client.key
|
||||||
|
|
||||||
# Configure a DH parameters file to enable Diffie-Hellman (DH) key exchange:
|
# Configure a DH parameters file to enable Diffie-Hellman (DH) key exchange:
|
||||||
#
|
#
|
||||||
# tls-dh-params-file redis.dh
|
# tls-dh-params-file redis.dh
|
||||||
|
@ -2450,6 +2450,8 @@ standardConfig configs[] = {
|
|||||||
createBoolConfig("tls-session-caching", NULL, MODIFIABLE_CONFIG, server.tls_ctx_config.session_caching, 1, NULL, updateTlsCfgBool),
|
createBoolConfig("tls-session-caching", NULL, MODIFIABLE_CONFIG, server.tls_ctx_config.session_caching, 1, NULL, updateTlsCfgBool),
|
||||||
createStringConfig("tls-cert-file", NULL, MODIFIABLE_CONFIG, EMPTY_STRING_IS_NULL, server.tls_ctx_config.cert_file, NULL, NULL, updateTlsCfg),
|
createStringConfig("tls-cert-file", NULL, MODIFIABLE_CONFIG, EMPTY_STRING_IS_NULL, server.tls_ctx_config.cert_file, NULL, NULL, updateTlsCfg),
|
||||||
createStringConfig("tls-key-file", NULL, MODIFIABLE_CONFIG, EMPTY_STRING_IS_NULL, server.tls_ctx_config.key_file, NULL, NULL, updateTlsCfg),
|
createStringConfig("tls-key-file", NULL, MODIFIABLE_CONFIG, EMPTY_STRING_IS_NULL, server.tls_ctx_config.key_file, NULL, NULL, updateTlsCfg),
|
||||||
|
createStringConfig("tls-client-cert-file", NULL, MODIFIABLE_CONFIG, EMPTY_STRING_IS_NULL, server.tls_ctx_config.client_cert_file, NULL, NULL, updateTlsCfg),
|
||||||
|
createStringConfig("tls-client-key-file", NULL, MODIFIABLE_CONFIG, EMPTY_STRING_IS_NULL, server.tls_ctx_config.client_key_file, NULL, NULL, updateTlsCfg),
|
||||||
createStringConfig("tls-dh-params-file", NULL, MODIFIABLE_CONFIG, EMPTY_STRING_IS_NULL, server.tls_ctx_config.dh_params_file, NULL, NULL, updateTlsCfg),
|
createStringConfig("tls-dh-params-file", NULL, MODIFIABLE_CONFIG, EMPTY_STRING_IS_NULL, server.tls_ctx_config.dh_params_file, NULL, NULL, updateTlsCfg),
|
||||||
createStringConfig("tls-ca-cert-file", NULL, MODIFIABLE_CONFIG, EMPTY_STRING_IS_NULL, server.tls_ctx_config.ca_cert_file, NULL, NULL, updateTlsCfg),
|
createStringConfig("tls-ca-cert-file", NULL, MODIFIABLE_CONFIG, EMPTY_STRING_IS_NULL, server.tls_ctx_config.ca_cert_file, NULL, NULL, updateTlsCfg),
|
||||||
createStringConfig("tls-ca-cert-dir", NULL, MODIFIABLE_CONFIG, EMPTY_STRING_IS_NULL, server.tls_ctx_config.ca_cert_dir, NULL, NULL, updateTlsCfg),
|
createStringConfig("tls-ca-cert-dir", NULL, MODIFIABLE_CONFIG, EMPTY_STRING_IS_NULL, server.tls_ctx_config.ca_cert_dir, NULL, NULL, updateTlsCfg),
|
||||||
|
@ -46,6 +46,7 @@ extern char **environ;
|
|||||||
|
|
||||||
#ifdef USE_OPENSSL
|
#ifdef USE_OPENSSL
|
||||||
extern SSL_CTX *redis_tls_ctx;
|
extern SSL_CTX *redis_tls_ctx;
|
||||||
|
extern SSL_CTX *redis_tls_client_ctx;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define REDIS_SENTINEL_PORT 26379
|
#define REDIS_SENTINEL_PORT 26379
|
||||||
@ -2077,7 +2078,7 @@ static int instanceLinkNegotiateTLS(redisAsyncContext *context) {
|
|||||||
(void) context;
|
(void) context;
|
||||||
#else
|
#else
|
||||||
if (!redis_tls_ctx) return C_ERR;
|
if (!redis_tls_ctx) return C_ERR;
|
||||||
SSL *ssl = SSL_new(redis_tls_ctx);
|
SSL *ssl = SSL_new(redis_tls_client_ctx ? redis_tls_client_ctx : redis_tls_ctx);
|
||||||
if (!ssl) return C_ERR;
|
if (!ssl) return C_ERR;
|
||||||
|
|
||||||
if (redisInitiateSSL(&context->c, ssl) == REDIS_ERR) return C_ERR;
|
if (redisInitiateSSL(&context->c, ssl) == REDIS_ERR) return C_ERR;
|
||||||
|
@ -1068,8 +1068,10 @@ struct malloc_stats {
|
|||||||
*----------------------------------------------------------------------------*/
|
*----------------------------------------------------------------------------*/
|
||||||
|
|
||||||
typedef struct redisTLSContextConfig {
|
typedef struct redisTLSContextConfig {
|
||||||
char *cert_file;
|
char *cert_file; /* Server side and optionally client side cert file name */
|
||||||
char *key_file;
|
char *key_file; /* Private key filename for cert_file */
|
||||||
|
char *client_cert_file; /* Certificate to use as a client; if none, use cert_file */
|
||||||
|
char *client_key_file; /* Private key filename for client_cert_file */
|
||||||
char *dh_params_file;
|
char *dh_params_file;
|
||||||
char *ca_cert_file;
|
char *ca_cert_file;
|
||||||
char *ca_cert_dir;
|
char *ca_cert_dir;
|
||||||
|
158
src/tls.c
158
src/tls.c
@ -54,7 +54,8 @@
|
|||||||
|
|
||||||
extern ConnectionType CT_Socket;
|
extern ConnectionType CT_Socket;
|
||||||
|
|
||||||
SSL_CTX *redis_tls_ctx;
|
SSL_CTX *redis_tls_ctx = NULL;
|
||||||
|
SSL_CTX *redis_tls_client_ctx = NULL;
|
||||||
|
|
||||||
static int parseProtocolsConfig(const char *str) {
|
static int parseProtocolsConfig(const char *str) {
|
||||||
int i, count = 0;
|
int i, count = 0;
|
||||||
@ -163,50 +164,22 @@ void tlsInit(void) {
|
|||||||
pending_list = listCreate();
|
pending_list = listCreate();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Attempt to configure/reconfigure TLS. This operation is atomic and will
|
/* Create a *base* SSL_CTX using the SSL configuration provided. The base context
|
||||||
* leave the SSL_CTX unchanged if fails.
|
* includes everything that's common for both client-side and server-side connections.
|
||||||
*/
|
*/
|
||||||
int tlsConfigure(redisTLSContextConfig *ctx_config) {
|
static SSL_CTX *createSSLContext(redisTLSContextConfig *ctx_config, int protocols,
|
||||||
|
const char *cert_file, const char *key_file) {
|
||||||
char errbuf[256];
|
char errbuf[256];
|
||||||
SSL_CTX *ctx = NULL;
|
SSL_CTX *ctx = NULL;
|
||||||
|
|
||||||
if (!ctx_config->cert_file) {
|
|
||||||
serverLog(LL_WARNING, "No tls-cert-file configured!");
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!ctx_config->key_file) {
|
|
||||||
serverLog(LL_WARNING, "No tls-key-file configured!");
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (((server.tls_auth_clients != TLS_CLIENT_AUTH_NO) || server.tls_cluster || server.tls_replication) &&
|
|
||||||
!ctx_config->ca_cert_file && !ctx_config->ca_cert_dir) {
|
|
||||||
serverLog(LL_WARNING, "Either tls-ca-cert-file or tls-ca-cert-dir must be specified when tls-cluster, tls-replication or tls-auth-clients are enabled!");
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx = SSL_CTX_new(SSLv23_method());
|
ctx = SSL_CTX_new(SSLv23_method());
|
||||||
|
|
||||||
SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2|SSL_OP_NO_SSLv3);
|
SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2|SSL_OP_NO_SSLv3);
|
||||||
SSL_CTX_set_options(ctx, SSL_OP_SINGLE_DH_USE);
|
|
||||||
|
|
||||||
#ifdef SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS
|
#ifdef SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS
|
||||||
SSL_CTX_set_options(ctx, SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS);
|
SSL_CTX_set_options(ctx, SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (ctx_config->session_caching) {
|
|
||||||
SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_SERVER);
|
|
||||||
SSL_CTX_sess_set_cache_size(ctx, ctx_config->session_cache_size);
|
|
||||||
SSL_CTX_set_timeout(ctx, ctx_config->session_cache_timeout);
|
|
||||||
SSL_CTX_set_session_id_context(ctx, (void *) "redis", 5);
|
|
||||||
} else {
|
|
||||||
SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_OFF);
|
|
||||||
}
|
|
||||||
|
|
||||||
int protocols = parseProtocolsConfig(ctx_config->protocols);
|
|
||||||
if (protocols == -1) goto error;
|
|
||||||
|
|
||||||
if (!(protocols & REDIS_TLS_PROTO_TLSv1))
|
if (!(protocols & REDIS_TLS_PROTO_TLSv1))
|
||||||
SSL_CTX_set_options(ctx, SSL_OP_NO_TLSv1);
|
SSL_CTX_set_options(ctx, SSL_OP_NO_TLSv1);
|
||||||
if (!(protocols & REDIS_TLS_PROTO_TLSv1_1))
|
if (!(protocols & REDIS_TLS_PROTO_TLSv1_1))
|
||||||
@ -224,28 +197,18 @@ int tlsConfigure(redisTLSContextConfig *ctx_config) {
|
|||||||
SSL_CTX_set_options(ctx, SSL_OP_NO_COMPRESSION);
|
SSL_CTX_set_options(ctx, SSL_OP_NO_COMPRESSION);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef SSL_OP_NO_CLIENT_RENEGOTIATION
|
|
||||||
SSL_CTX_set_options(ctx, SSL_OP_NO_CLIENT_RENEGOTIATION);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (ctx_config->prefer_server_ciphers)
|
|
||||||
SSL_CTX_set_options(ctx, SSL_OP_CIPHER_SERVER_PREFERENCE);
|
|
||||||
|
|
||||||
SSL_CTX_set_mode(ctx, SSL_MODE_ENABLE_PARTIAL_WRITE|SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
|
SSL_CTX_set_mode(ctx, SSL_MODE_ENABLE_PARTIAL_WRITE|SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
|
||||||
SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER|SSL_VERIFY_FAIL_IF_NO_PEER_CERT, NULL);
|
SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER|SSL_VERIFY_FAIL_IF_NO_PEER_CERT, NULL);
|
||||||
#if defined(SSL_CTX_set_ecdh_auto)
|
|
||||||
SSL_CTX_set_ecdh_auto(ctx, 1);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (SSL_CTX_use_certificate_chain_file(ctx, ctx_config->cert_file) <= 0) {
|
if (SSL_CTX_use_certificate_chain_file(ctx, cert_file) <= 0) {
|
||||||
ERR_error_string_n(ERR_get_error(), errbuf, sizeof(errbuf));
|
ERR_error_string_n(ERR_get_error(), errbuf, sizeof(errbuf));
|
||||||
serverLog(LL_WARNING, "Failed to load certificate: %s: %s", ctx_config->cert_file, errbuf);
|
serverLog(LL_WARNING, "Failed to load certificate: %s: %s", cert_file, errbuf);
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (SSL_CTX_use_PrivateKey_file(ctx, ctx_config->key_file, SSL_FILETYPE_PEM) <= 0) {
|
if (SSL_CTX_use_PrivateKey_file(ctx, key_file, SSL_FILETYPE_PEM) <= 0) {
|
||||||
ERR_error_string_n(ERR_get_error(), errbuf, sizeof(errbuf));
|
ERR_error_string_n(ERR_get_error(), errbuf, sizeof(errbuf));
|
||||||
serverLog(LL_WARNING, "Failed to load private key: %s: %s", ctx_config->key_file, errbuf);
|
serverLog(LL_WARNING, "Failed to load private key: %s: %s", key_file, errbuf);
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -256,6 +219,77 @@ int tlsConfigure(redisTLSContextConfig *ctx_config) {
|
|||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ctx_config->ciphers && !SSL_CTX_set_cipher_list(ctx, ctx_config->ciphers)) {
|
||||||
|
serverLog(LL_WARNING, "Failed to configure ciphers: %s", ctx_config->ciphers);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef TLS1_3_VERSION
|
||||||
|
if (ctx_config->ciphersuites && !SSL_CTX_set_ciphersuites(ctx, ctx_config->ciphersuites)) {
|
||||||
|
serverLog(LL_WARNING, "Failed to configure ciphersuites: %s", ctx_config->ciphersuites);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return ctx;
|
||||||
|
|
||||||
|
error:
|
||||||
|
if (ctx) SSL_CTX_free(ctx);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Attempt to configure/reconfigure TLS. This operation is atomic and will
|
||||||
|
* leave the SSL_CTX unchanged if fails.
|
||||||
|
*/
|
||||||
|
int tlsConfigure(redisTLSContextConfig *ctx_config) {
|
||||||
|
char errbuf[256];
|
||||||
|
SSL_CTX *ctx = NULL;
|
||||||
|
SSL_CTX *client_ctx = NULL;
|
||||||
|
|
||||||
|
if (!ctx_config->cert_file) {
|
||||||
|
serverLog(LL_WARNING, "No tls-cert-file configured!");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ctx_config->key_file) {
|
||||||
|
serverLog(LL_WARNING, "No tls-key-file configured!");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (((server.tls_auth_clients != TLS_CLIENT_AUTH_NO) || server.tls_cluster || server.tls_replication) &&
|
||||||
|
!ctx_config->ca_cert_file && !ctx_config->ca_cert_dir) {
|
||||||
|
serverLog(LL_WARNING, "Either tls-ca-cert-file or tls-ca-cert-dir must be specified when tls-cluster, tls-replication or tls-auth-clients are enabled!");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
int protocols = parseProtocolsConfig(ctx_config->protocols);
|
||||||
|
if (protocols == -1) goto error;
|
||||||
|
|
||||||
|
/* Create server side/generla context */
|
||||||
|
ctx = createSSLContext(ctx_config, protocols, ctx_config->cert_file, ctx_config->key_file);
|
||||||
|
if (!ctx) goto error;
|
||||||
|
|
||||||
|
if (ctx_config->session_caching) {
|
||||||
|
SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_SERVER);
|
||||||
|
SSL_CTX_sess_set_cache_size(ctx, ctx_config->session_cache_size);
|
||||||
|
SSL_CTX_set_timeout(ctx, ctx_config->session_cache_timeout);
|
||||||
|
SSL_CTX_set_session_id_context(ctx, (void *) "redis", 5);
|
||||||
|
} else {
|
||||||
|
SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_OFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef SSL_OP_NO_CLIENT_RENEGOTIATION
|
||||||
|
SSL_CTX_set_options(ctx, SSL_OP_NO_CLIENT_RENEGOTIATION);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (ctx_config->prefer_server_ciphers)
|
||||||
|
SSL_CTX_set_options(ctx, SSL_OP_CIPHER_SERVER_PREFERENCE);
|
||||||
|
|
||||||
|
#if defined(SSL_CTX_set_ecdh_auto)
|
||||||
|
SSL_CTX_set_ecdh_auto(ctx, 1);
|
||||||
|
#endif
|
||||||
|
SSL_CTX_set_options(ctx, SSL_OP_SINGLE_DH_USE);
|
||||||
|
|
||||||
if (ctx_config->dh_params_file) {
|
if (ctx_config->dh_params_file) {
|
||||||
FILE *dhfile = fopen(ctx_config->dh_params_file, "r");
|
FILE *dhfile = fopen(ctx_config->dh_params_file, "r");
|
||||||
DH *dh = NULL;
|
DH *dh = NULL;
|
||||||
@ -281,25 +315,22 @@ int tlsConfigure(redisTLSContextConfig *ctx_config) {
|
|||||||
DH_free(dh);
|
DH_free(dh);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ctx_config->ciphers && !SSL_CTX_set_cipher_list(ctx, ctx_config->ciphers)) {
|
/* If a client-side certificate is configured, create an explicit client context */
|
||||||
serverLog(LL_WARNING, "Failed to configure ciphers: %s", ctx_config->ciphers);
|
if (ctx_config->client_cert_file && ctx_config->client_key_file) {
|
||||||
goto error;
|
client_ctx = createSSLContext(ctx_config, protocols, ctx_config->client_cert_file, ctx_config->client_key_file);
|
||||||
|
if (!client_ctx) goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef TLS1_3_VERSION
|
|
||||||
if (ctx_config->ciphersuites && !SSL_CTX_set_ciphersuites(ctx, ctx_config->ciphersuites)) {
|
|
||||||
serverLog(LL_WARNING, "Failed to configure ciphersuites: %s", ctx_config->ciphersuites);
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
SSL_CTX_free(redis_tls_ctx);
|
SSL_CTX_free(redis_tls_ctx);
|
||||||
|
SSL_CTX_free(redis_tls_client_ctx);
|
||||||
redis_tls_ctx = ctx;
|
redis_tls_ctx = ctx;
|
||||||
|
redis_tls_client_ctx = client_ctx;
|
||||||
|
|
||||||
return C_OK;
|
return C_OK;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
if (ctx) SSL_CTX_free(ctx);
|
if (ctx) SSL_CTX_free(ctx);
|
||||||
|
if (client_ctx) SSL_CTX_free(client_ctx);
|
||||||
return C_ERR;
|
return C_ERR;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -344,14 +375,21 @@ typedef struct tls_connection {
|
|||||||
listNode *pending_list_node;
|
listNode *pending_list_node;
|
||||||
} tls_connection;
|
} tls_connection;
|
||||||
|
|
||||||
connection *connCreateTLS(void) {
|
static connection *createTLSConnection(bool client_side) {
|
||||||
|
SSL_CTX *ctx = redis_tls_ctx;
|
||||||
|
if (client_side && redis_tls_client_ctx)
|
||||||
|
ctx = redis_tls_client_ctx;
|
||||||
tls_connection *conn = zcalloc(sizeof(tls_connection));
|
tls_connection *conn = zcalloc(sizeof(tls_connection));
|
||||||
conn->c.type = &CT_TLS;
|
conn->c.type = &CT_TLS;
|
||||||
conn->c.fd = -1;
|
conn->c.fd = -1;
|
||||||
conn->ssl = SSL_new(redis_tls_ctx);
|
conn->ssl = SSL_new(ctx);
|
||||||
return (connection *) conn;
|
return (connection *) conn;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
connection *connCreateTLS(void) {
|
||||||
|
return createTLSConnection(true);
|
||||||
|
}
|
||||||
|
|
||||||
/* Fetch the latest OpenSSL error and store it in the connection */
|
/* Fetch the latest OpenSSL error and store it in the connection */
|
||||||
static void updateTLSError(tls_connection *conn) {
|
static void updateTLSError(tls_connection *conn) {
|
||||||
conn->c.last_errno = 0;
|
conn->c.last_errno = 0;
|
||||||
@ -370,7 +408,7 @@ static void updateTLSError(tls_connection *conn) {
|
|||||||
* is not in an error state.
|
* is not in an error state.
|
||||||
*/
|
*/
|
||||||
connection *connCreateAcceptedTLS(int fd, int require_auth) {
|
connection *connCreateAcceptedTLS(int fd, int require_auth) {
|
||||||
tls_connection *conn = (tls_connection *) connCreateTLS();
|
tls_connection *conn = (tls_connection *) createTLSConnection(false);
|
||||||
conn->c.fd = fd;
|
conn->c.fd = fd;
|
||||||
conn->c.state = CONN_STATE_ACCEPTING;
|
conn->c.state = CONN_STATE_ACCEPTING;
|
||||||
|
|
||||||
|
@ -76,8 +76,10 @@ proc spawn_instance {type base_port count {conf {}}} {
|
|||||||
puts $cfg "tls-replication yes"
|
puts $cfg "tls-replication yes"
|
||||||
puts $cfg "tls-cluster yes"
|
puts $cfg "tls-cluster yes"
|
||||||
puts $cfg "port 0"
|
puts $cfg "port 0"
|
||||||
puts $cfg [format "tls-cert-file %s/../../tls/redis.crt" [pwd]]
|
puts $cfg [format "tls-cert-file %s/../../tls/server.crt" [pwd]]
|
||||||
puts $cfg [format "tls-key-file %s/../../tls/redis.key" [pwd]]
|
puts $cfg [format "tls-key-file %s/../../tls/server.key" [pwd]]
|
||||||
|
puts $cfg [format "tls-client-cert-file %s/../../tls/client.crt" [pwd]]
|
||||||
|
puts $cfg [format "tls-client-key-file %s/../../tls/client.key" [pwd]]
|
||||||
puts $cfg [format "tls-dh-params-file %s/../../tls/redis.dh" [pwd]]
|
puts $cfg [format "tls-dh-params-file %s/../../tls/redis.dh" [pwd]]
|
||||||
puts $cfg [format "tls-ca-cert-file %s/../../tls/ca.crt" [pwd]]
|
puts $cfg [format "tls-ca-cert-file %s/../../tls/ca.crt" [pwd]]
|
||||||
puts $cfg "loglevel debug"
|
puts $cfg "loglevel debug"
|
||||||
@ -234,8 +236,8 @@ proc parse_options {} {
|
|||||||
package require tls 1.6
|
package require tls 1.6
|
||||||
::tls::init \
|
::tls::init \
|
||||||
-cafile "$::tlsdir/ca.crt" \
|
-cafile "$::tlsdir/ca.crt" \
|
||||||
-certfile "$::tlsdir/redis.crt" \
|
-certfile "$::tlsdir/client.crt" \
|
||||||
-keyfile "$::tlsdir/redis.key"
|
-keyfile "$::tlsdir/client.key"
|
||||||
set ::tls 1
|
set ::tls 1
|
||||||
} elseif {$opt eq "--help"} {
|
} elseif {$opt eq "--help"} {
|
||||||
puts "--single <pattern> Only runs tests specified by pattern."
|
puts "--single <pattern> Only runs tests specified by pattern."
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
proc redisbenchmark_tls_config {testsdir} {
|
proc redisbenchmark_tls_config {testsdir} {
|
||||||
set tlsdir [file join $testsdir tls]
|
set tlsdir [file join $testsdir tls]
|
||||||
set cert [file join $tlsdir redis.crt]
|
set cert [file join $tlsdir client.crt]
|
||||||
set key [file join $tlsdir redis.key]
|
set key [file join $tlsdir client.key]
|
||||||
set cacert [file join $tlsdir ca.crt]
|
set cacert [file join $tlsdir ca.crt]
|
||||||
|
|
||||||
if {$::tls} {
|
if {$::tls} {
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
proc rediscli_tls_config {testsdir} {
|
proc rediscli_tls_config {testsdir} {
|
||||||
set tlsdir [file join $testsdir tls]
|
set tlsdir [file join $testsdir tls]
|
||||||
set cert [file join $tlsdir redis.crt]
|
set cert [file join $tlsdir client.crt]
|
||||||
set key [file join $tlsdir redis.key]
|
set key [file join $tlsdir client.key]
|
||||||
set cacert [file join $tlsdir ca.crt]
|
set cacert [file join $tlsdir ca.crt]
|
||||||
|
|
||||||
if {$::tls} {
|
if {$::tls} {
|
||||||
|
@ -44,8 +44,8 @@ proc redis {{server 127.0.0.1} {port 6379} {defer 0} {tls 0} {tlsoptions {}}} {
|
|||||||
package require tls
|
package require tls
|
||||||
::tls::init \
|
::tls::init \
|
||||||
-cafile "$::tlsdir/ca.crt" \
|
-cafile "$::tlsdir/ca.crt" \
|
||||||
-certfile "$::tlsdir/redis.crt" \
|
-certfile "$::tlsdir/client.crt" \
|
||||||
-keyfile "$::tlsdir/redis.key" \
|
-keyfile "$::tlsdir/client.key" \
|
||||||
{*}$tlsoptions
|
{*}$tlsoptions
|
||||||
set fd [::tls::socket $server $port]
|
set fd [::tls::socket $server $port]
|
||||||
} else {
|
} else {
|
||||||
|
@ -229,6 +229,7 @@ proc start_server {options {code undefined}} {
|
|||||||
# setup defaults
|
# setup defaults
|
||||||
set baseconfig "default.conf"
|
set baseconfig "default.conf"
|
||||||
set overrides {}
|
set overrides {}
|
||||||
|
set omit {}
|
||||||
set tags {}
|
set tags {}
|
||||||
set keep_persistence false
|
set keep_persistence false
|
||||||
|
|
||||||
@ -241,6 +242,9 @@ proc start_server {options {code undefined}} {
|
|||||||
"overrides" {
|
"overrides" {
|
||||||
set overrides $value
|
set overrides $value
|
||||||
}
|
}
|
||||||
|
"omit" {
|
||||||
|
set omit $value
|
||||||
|
}
|
||||||
"tags" {
|
"tags" {
|
||||||
# If we 'tags' contain multiple tags, quoted and seperated by spaces,
|
# If we 'tags' contain multiple tags, quoted and seperated by spaces,
|
||||||
# we want to get rid of the quotes in order to have a proper list
|
# we want to get rid of the quotes in order to have a proper list
|
||||||
@ -306,8 +310,10 @@ proc start_server {options {code undefined}} {
|
|||||||
set data [split [exec cat "tests/assets/$baseconfig"] "\n"]
|
set data [split [exec cat "tests/assets/$baseconfig"] "\n"]
|
||||||
set config {}
|
set config {}
|
||||||
if {$::tls} {
|
if {$::tls} {
|
||||||
dict set config "tls-cert-file" [format "%s/tests/tls/redis.crt" [pwd]]
|
dict set config "tls-cert-file" [format "%s/tests/tls/server.crt" [pwd]]
|
||||||
dict set config "tls-key-file" [format "%s/tests/tls/redis.key" [pwd]]
|
dict set config "tls-key-file" [format "%s/tests/tls/server.key" [pwd]]
|
||||||
|
dict set config "tls-client-cert-file" [format "%s/tests/tls/client.crt" [pwd]]
|
||||||
|
dict set config "tls-client-key-file" [format "%s/tests/tls/client.key" [pwd]]
|
||||||
dict set config "tls-dh-params-file" [format "%s/tests/tls/redis.dh" [pwd]]
|
dict set config "tls-dh-params-file" [format "%s/tests/tls/redis.dh" [pwd]]
|
||||||
dict set config "tls-ca-cert-file" [format "%s/tests/tls/ca.crt" [pwd]]
|
dict set config "tls-ca-cert-file" [format "%s/tests/tls/ca.crt" [pwd]]
|
||||||
dict set config "loglevel" "debug"
|
dict set config "loglevel" "debug"
|
||||||
@ -343,6 +349,11 @@ proc start_server {options {code undefined}} {
|
|||||||
dict set config $directive $arguments
|
dict set config $directive $arguments
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# remove directives that are marked to be omitted
|
||||||
|
foreach directive $omit {
|
||||||
|
dict unset config $directive
|
||||||
|
}
|
||||||
|
|
||||||
# write new configuration to temporary file
|
# write new configuration to temporary file
|
||||||
set config_file [tmpfile redis.conf]
|
set config_file [tmpfile redis.conf]
|
||||||
create_server_config_file $config_file $config
|
create_server_config_file $config_file $config
|
||||||
|
@ -602,8 +602,8 @@ for {set j 0} {$j < [llength $argv]} {incr j} {
|
|||||||
set ::tls 1
|
set ::tls 1
|
||||||
::tls::init \
|
::tls::init \
|
||||||
-cafile "$::tlsdir/ca.crt" \
|
-cafile "$::tlsdir/ca.crt" \
|
||||||
-certfile "$::tlsdir/redis.crt" \
|
-certfile "$::tlsdir/client.crt" \
|
||||||
-keyfile "$::tlsdir/redis.key"
|
-keyfile "$::tlsdir/client.key"
|
||||||
} elseif {$opt eq {--host}} {
|
} elseif {$opt eq {--host}} {
|
||||||
set ::external 1
|
set ::external 1
|
||||||
set ::host $arg
|
set ::host $arg
|
||||||
|
@ -122,6 +122,8 @@ start_server {tags {"introspection"}} {
|
|||||||
tls-session-caching
|
tls-session-caching
|
||||||
tls-cert-file
|
tls-cert-file
|
||||||
tls-key-file
|
tls-key-file
|
||||||
|
tls-client-cert-file
|
||||||
|
tls-client-key-file
|
||||||
tls-dh-params-file
|
tls-dh-params-file
|
||||||
tls-ca-cert-file
|
tls-ca-cert-file
|
||||||
tls-ca-cert-dir
|
tls-ca-cert-dir
|
||||||
|
@ -93,5 +93,26 @@ start_server {tags {"tls"}} {
|
|||||||
r CONFIG SET tls-protocols ""
|
r CONFIG SET tls-protocols ""
|
||||||
r CONFIG SET tls-ciphers "DEFAULT"
|
r CONFIG SET tls-ciphers "DEFAULT"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test {TLS: Verify tls-cert-file is also used as a client cert if none specified} {
|
||||||
|
set master [srv 0 client]
|
||||||
|
set master_host [srv 0 host]
|
||||||
|
set master_port [srv 0 port]
|
||||||
|
|
||||||
|
# Use a non-restricted client/server cert for the replica
|
||||||
|
set redis_crt [format "%s/tests/tls/redis.crt" [pwd]]
|
||||||
|
set redis_key [format "%s/tests/tls/redis.key" [pwd]]
|
||||||
|
|
||||||
|
start_server [list overrides [list tls-cert-file $redis_crt tls-key-file $redis_key] \
|
||||||
|
omit [list tls-client-cert-file tls-client-key-file]] {
|
||||||
|
set replica [srv 0 client]
|
||||||
|
$replica replicaof $master_host $master_port
|
||||||
|
wait_for_condition 30 100 {
|
||||||
|
[string match {*master_link_status:up*} [$replica info replication]]
|
||||||
|
} else {
|
||||||
|
fail "Can't authenticate to master using just tls-cert-file!"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,23 +1,58 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Generate some test certificates which are used by the regression test suite:
|
||||||
|
#
|
||||||
|
# tests/tls/ca.{crt,key} Self signed CA certificate.
|
||||||
|
# tests/tls/redis.{crt,key} A certificate with no key usage/policy restrictions.
|
||||||
|
# tests/tls/client.{crt,key} A certificate restricted for SSL client usage.
|
||||||
|
# tests/tls/server.{crt,key} A certificate restricted fro SSL server usage.
|
||||||
|
# tests/tls/redis.dh DH Params file.
|
||||||
|
|
||||||
|
generate_cert() {
|
||||||
|
local name=$1
|
||||||
|
local cn="$2"
|
||||||
|
local opts="$3"
|
||||||
|
|
||||||
|
local keyfile=tests/tls/${name}.key
|
||||||
|
local certfile=tests/tls/${name}.crt
|
||||||
|
|
||||||
|
[ -f $keyfile ] || openssl genrsa -out $keyfile 2048
|
||||||
|
openssl req \
|
||||||
|
-new -sha256 \
|
||||||
|
-subj "/O=Redis Test/CN=$cn" \
|
||||||
|
-key $keyfile | \
|
||||||
|
openssl x509 \
|
||||||
|
-req -sha256 \
|
||||||
|
-CA tests/tls/ca.crt \
|
||||||
|
-CAkey tests/tls/ca.key \
|
||||||
|
-CAserial tests/tls/ca.txt \
|
||||||
|
-CAcreateserial \
|
||||||
|
-days 365 \
|
||||||
|
$opts \
|
||||||
|
-out $certfile
|
||||||
|
}
|
||||||
|
|
||||||
mkdir -p tests/tls
|
mkdir -p tests/tls
|
||||||
openssl genrsa -out tests/tls/ca.key 4096
|
[ -f tests/tls/ca.key ] || openssl genrsa -out tests/tls/ca.key 4096
|
||||||
openssl req \
|
openssl req \
|
||||||
-x509 -new -nodes -sha256 \
|
-x509 -new -nodes -sha256 \
|
||||||
-key tests/tls/ca.key \
|
-key tests/tls/ca.key \
|
||||||
-days 3650 \
|
-days 3650 \
|
||||||
-subj '/O=Redis Test/CN=Certificate Authority' \
|
-subj '/O=Redis Test/CN=Certificate Authority' \
|
||||||
-out tests/tls/ca.crt
|
-out tests/tls/ca.crt
|
||||||
openssl genrsa -out tests/tls/redis.key 2048
|
|
||||||
openssl req \
|
cat > tests/tls/openssl.cnf <<_END_
|
||||||
-new -sha256 \
|
[ server_cert ]
|
||||||
-key tests/tls/redis.key \
|
keyUsage = digitalSignature, keyEncipherment
|
||||||
-subj '/O=Redis Test/CN=Server' | \
|
nsCertType = server
|
||||||
openssl x509 \
|
|
||||||
-req -sha256 \
|
[ client_cert ]
|
||||||
-CA tests/tls/ca.crt \
|
keyUsage = digitalSignature, keyEncipherment
|
||||||
-CAkey tests/tls/ca.key \
|
nsCertType = client
|
||||||
-CAserial tests/tls/ca.txt \
|
_END_
|
||||||
-CAcreateserial \
|
|
||||||
-days 365 \
|
generate_cert server "Server-only" "-extfile tests/tls/openssl.cnf -extensions server_cert"
|
||||||
-out tests/tls/redis.crt
|
generate_cert client "Client-only" "-extfile tests/tls/openssl.cnf -extensions client_cert"
|
||||||
openssl dhparam -out tests/tls/redis.dh 2048
|
generate_cert redis "Generic-cert"
|
||||||
|
|
||||||
|
[ -f tests/tls/redis.dh ] || openssl dhparam -out tests/tls/redis.dh 2048
|
||||||
|
Loading…
x
Reference in New Issue
Block a user