mirror of
https://codeberg.org/redict/redict.git
synced 2025-01-22 08:08:53 -05:00
TLS: Improve CA certifiate configuration options.
This adds support for explicit configuration of a CA certs directory (in addition to the previously supported bundle file). For redis-cli, if no explicit CA configuration is supplied the system-wide default configuration will be adopted.
This commit is contained in:
parent
61733ded14
commit
d7f2681a0c
@ -148,10 +148,12 @@ tcp-keepalive 300
|
||||
#
|
||||
# tls-dh-params-file redis.dh
|
||||
|
||||
# Configure a CA certificate(s) bundle to authenticate TLS/SSL clients and
|
||||
# peers.
|
||||
# Configure a CA certificate(s) bundle or directory to authenticate TLS/SSL
|
||||
# clients and peers. Redis requires an explicit configuration of at least one
|
||||
# of these, and will not implicitly use the system wide configuration.
|
||||
#
|
||||
# tls-ca-cert-file ca.crt
|
||||
# tls-ca-cert-dir /etc/ssl/certs
|
||||
|
||||
# If TLS/SSL clients are required to authenticate using a client side
|
||||
# certificate, use this directive.
|
||||
|
15
src/config.c
15
src/config.c
@ -821,6 +821,9 @@ void loadServerConfigFromString(char *config) {
|
||||
} else if (!strcasecmp(argv[0],"tls-ca-cert-file") && argc == 2) {
|
||||
zfree(server.tls_ctx_config.ca_cert_file);
|
||||
server.tls_ctx_config.ca_cert_file = zstrdup(argv[1]);
|
||||
} else if (!strcasecmp(argv[0],"tls-ca-cert-dir") && argc == 2) {
|
||||
zfree(server.tls_ctx_config.ca_cert_dir);
|
||||
server.tls_ctx_config.ca_cert_dir = zstrdup(argv[1]);
|
||||
} else if (!strcasecmp(argv[0],"tls-protocols") && argc >= 2) {
|
||||
zfree(server.tls_ctx_config.protocols);
|
||||
server.tls_ctx_config.protocols = zstrdup(argv[1]);
|
||||
@ -1319,6 +1322,16 @@ void configSetCommand(client *c) {
|
||||
}
|
||||
zfree(server.tls_ctx_config.ca_cert_file);
|
||||
server.tls_ctx_config.ca_cert_file = zstrdup(o->ptr);
|
||||
} config_set_special_field("tls-ca-cert-dir") {
|
||||
redisTLSContextConfig tmpctx = server.tls_ctx_config;
|
||||
tmpctx.ca_cert_dir = (char *) o->ptr;
|
||||
if (tlsConfigure(&tmpctx) == C_ERR) {
|
||||
addReplyError(c,
|
||||
"Unable to configure tls-ca-cert-dir. Check server logs.");
|
||||
return;
|
||||
}
|
||||
zfree(server.tls_ctx_config.ca_cert_dir);
|
||||
server.tls_ctx_config.ca_cert_dir = zstrdup(o->ptr);
|
||||
} config_set_bool_field("tls-auth-clients", server.tls_auth_clients) {
|
||||
} config_set_bool_field("tls-replication", server.tls_replication) {
|
||||
} config_set_bool_field("tls-cluster", server.tls_cluster) {
|
||||
@ -1439,6 +1452,7 @@ void configGetCommand(client *c) {
|
||||
config_get_string_field("tls-key-file",server.tls_ctx_config.key_file);
|
||||
config_get_string_field("tls-dh-params-file",server.tls_ctx_config.dh_params_file);
|
||||
config_get_string_field("tls-ca-cert-file",server.tls_ctx_config.ca_cert_file);
|
||||
config_get_string_field("tls-ca-cert-dir",server.tls_ctx_config.ca_cert_dir);
|
||||
config_get_string_field("tls-protocols",server.tls_ctx_config.protocols);
|
||||
config_get_string_field("tls-ciphers",server.tls_ctx_config.ciphers);
|
||||
config_get_string_field("tls-ciphersuites",server.tls_ctx_config.ciphersuites);
|
||||
@ -2347,6 +2361,7 @@ int rewriteConfig(char *path) {
|
||||
rewriteConfigStringOption(state,"tls-key-file",server.tls_ctx_config.key_file,NULL);
|
||||
rewriteConfigStringOption(state,"tls-dh-params-file",server.tls_ctx_config.dh_params_file,NULL);
|
||||
rewriteConfigStringOption(state,"tls-ca-cert-file",server.tls_ctx_config.ca_cert_file,NULL);
|
||||
rewriteConfigStringOption(state,"tls-ca-cert-dir",server.tls_ctx_config.ca_cert_dir,NULL);
|
||||
rewriteConfigStringOption(state,"tls-protocols",server.tls_ctx_config.protocols,NULL);
|
||||
rewriteConfigStringOption(state,"tls-ciphers",server.tls_ctx_config.ciphers,NULL);
|
||||
rewriteConfigStringOption(state,"tls-ciphersuites",server.tls_ctx_config.ciphersuites,NULL);
|
||||
|
@ -48,6 +48,7 @@
|
||||
|
||||
#include <hiredis.h>
|
||||
#ifdef USE_OPENSSL
|
||||
#include <openssl/ssl.h>
|
||||
#include <hiredis_ssl.h>
|
||||
#endif
|
||||
#include <sds.h> /* use sds.h from hiredis, so that only one set of sds functions will be present in the binary */
|
||||
@ -194,6 +195,7 @@ static struct config {
|
||||
int tls;
|
||||
char *sni;
|
||||
char *cacert;
|
||||
char *cacertdir;
|
||||
char *cert;
|
||||
char *key;
|
||||
long repeat;
|
||||
@ -762,9 +764,61 @@ static int cliSelect(void) {
|
||||
/* Wrapper around redisSecureConnection to avoid hiredis_ssl dependencies if
|
||||
* not building with TLS support.
|
||||
*/
|
||||
static int cliSecureConnection(redisContext *c) {
|
||||
static int cliSecureConnection(redisContext *c, const char **err) {
|
||||
#ifdef USE_OPENSSL
|
||||
return redisSecureConnection(c, config.cacert, config.cert, config.key, config.sni);
|
||||
static SSL_CTX *ssl_ctx = NULL;
|
||||
|
||||
if (!ssl_ctx) {
|
||||
ssl_ctx = SSL_CTX_new(SSLv23_client_method());
|
||||
if (!ssl_ctx) {
|
||||
*err = "Failed to create SSL_CTX";
|
||||
goto error;
|
||||
}
|
||||
|
||||
SSL_CTX_set_options(ssl_ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3);
|
||||
SSL_CTX_set_verify(ssl_ctx, SSL_VERIFY_PEER, NULL);
|
||||
|
||||
if (config.cacert || config.cacertdir) {
|
||||
if (!SSL_CTX_load_verify_locations(ssl_ctx, config.cacert, config.cacertdir)) {
|
||||
*err = "Invalid CA Certificate File/Directory";
|
||||
goto error;
|
||||
}
|
||||
} else {
|
||||
if (!SSL_CTX_set_default_verify_paths(ssl_ctx)) {
|
||||
*err = "Failed to use default CA paths";
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
if (config.cert && !SSL_CTX_use_certificate_chain_file(ssl_ctx, config.cert)) {
|
||||
*err = "Invalid client certificate";
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (config.key && !SSL_CTX_use_PrivateKey_file(ssl_ctx, config.key, SSL_FILETYPE_PEM)) {
|
||||
*err = "Invalid private key";
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
SSL *ssl = SSL_new(ssl_ctx);
|
||||
if (!ssl) {
|
||||
*err = "Failed to create SSL object";
|
||||
return REDIS_ERR;
|
||||
}
|
||||
|
||||
if (config.sni && !SSL_set_tlsext_host_name(ssl, config.sni)) {
|
||||
*err = "Failed to configure SNI";
|
||||
SSL_free(ssl);
|
||||
return REDIS_ERR;
|
||||
}
|
||||
|
||||
return redisInitiateSSL(c, ssl);
|
||||
|
||||
error:
|
||||
SSL_CTX_free(ssl_ctx);
|
||||
ssl_ctx = NULL;
|
||||
return REDIS_ERR;
|
||||
#else
|
||||
(void) c;
|
||||
return REDIS_OK;
|
||||
@ -788,9 +842,9 @@ static int cliConnect(int flags) {
|
||||
}
|
||||
|
||||
if (!context->err && config.tls) {
|
||||
if (cliSecureConnection(context) == REDIS_ERR && !context->err) {
|
||||
/* TODO: this check should be redundant, redis-cli should set err=1 */
|
||||
fprintf(stderr, "Could not negotiate a TLS connection.\n");
|
||||
const char *err = NULL;
|
||||
if (cliSecureConnection(context, &err) == REDIS_ERR && err) {
|
||||
fprintf(stderr, "Could not negotiate a TLS connection: %s\n", err);
|
||||
context = NULL;
|
||||
redisFree(context);
|
||||
return REDIS_ERR;
|
||||
@ -1277,7 +1331,11 @@ static redisReply *reconnectingRedisCommand(redisContext *c, const char *fmt, ..
|
||||
redisFree(c);
|
||||
c = redisConnect(config.hostip,config.hostport);
|
||||
if (!c->err && config.tls) {
|
||||
cliSecureConnection(c);
|
||||
const char *err = NULL;
|
||||
if (cliSecureConnection(c, &err) == REDIS_ERR && err) {
|
||||
fprintf(stderr, "TLS Error: %s\n", err);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
usleep(1000000);
|
||||
}
|
||||
@ -1473,6 +1531,8 @@ static int parseOptions(int argc, char **argv) {
|
||||
config.tls = 1;
|
||||
} else if (!strcmp(argv[i],"--sni")) {
|
||||
config.sni = argv[++i];
|
||||
} else if (!strcmp(argv[i],"--cacertdir")) {
|
||||
config.cacertdir = argv[++i];
|
||||
} else if (!strcmp(argv[i],"--cacert")) {
|
||||
config.cacert = argv[++i];
|
||||
} else if (!strcmp(argv[i],"--cert")) {
|
||||
@ -1571,6 +1631,9 @@ static void usage(void) {
|
||||
#ifdef USE_OPENSSL
|
||||
" --tls Establish a secure TLS connection.\n"
|
||||
" --cacert CA Certificate file to verify with.\n"
|
||||
" --cacertdir Directory where trusted CA certificates are stored.\n"
|
||||
" If neither cacert nor cacertdir are specified, the default\n"
|
||||
" system-wide trusted root certs configuration will apply.\n"
|
||||
" --cert Client certificate to authenticate with.\n"
|
||||
" --key Private key file to authenticate with.\n"
|
||||
#endif
|
||||
@ -2390,7 +2453,13 @@ static int clusterManagerNodeConnect(clusterManagerNode *node) {
|
||||
if (node->context) redisFree(node->context);
|
||||
node->context = redisConnect(node->ip, node->port);
|
||||
if (!node->context->err && config.tls) {
|
||||
cliSecureConnection(node->context);
|
||||
const char *err = NULL;
|
||||
if (cliSecureConnection(node->context, &err) == REDIS_ERR && err) {
|
||||
fprintf(stderr,"TLS Error: %s\n", err);
|
||||
redisFree(node->context);
|
||||
node->context = NULL;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if (node->context->err) {
|
||||
fprintf(stderr,"Could not connect to Redis at ");
|
||||
|
@ -1038,6 +1038,7 @@ typedef struct redisTLSContextConfig {
|
||||
char *key_file;
|
||||
char *dh_params_file;
|
||||
char *ca_cert_file;
|
||||
char *ca_cert_dir;
|
||||
char *protocols;
|
||||
char *ciphers;
|
||||
char *ciphersuites;
|
||||
|
@ -125,8 +125,8 @@ int tlsConfigure(redisTLSContextConfig *ctx_config) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (!ctx_config->ca_cert_file) {
|
||||
serverLog(LL_WARNING, "No tls-ca-cert-file configured!");
|
||||
if (!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 configured!");
|
||||
goto error;
|
||||
}
|
||||
|
||||
@ -182,9 +182,9 @@ int tlsConfigure(redisTLSContextConfig *ctx_config) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (SSL_CTX_load_verify_locations(ctx, ctx_config->ca_cert_file, NULL) <= 0) {
|
||||
if (SSL_CTX_load_verify_locations(ctx, ctx_config->ca_cert_file, ctx_config->ca_cert_dir) <= 0) {
|
||||
ERR_error_string_n(ERR_get_error(), errbuf, sizeof(errbuf));
|
||||
serverLog(LL_WARNING, "Failed to load CA certificate(s) file: %s: %s", ctx_config->ca_cert_file, errbuf);
|
||||
serverLog(LL_WARNING, "Failed to configure CA certificate(s) file/directory: %s", errbuf);
|
||||
goto error;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user