Add support for reading encrypted keyfiles. (#8644)
This commit is contained in:
parent
c3df27d1ea
commit
c4ef1efdb7
10
redis.conf
10
redis.conf
@ -150,6 +150,11 @@ tcp-keepalive 300
|
||||
#
|
||||
# tls-cert-file redis.crt
|
||||
# tls-key-file redis.key
|
||||
#
|
||||
# If the key file is encrypted using a passphrase, it can be included here
|
||||
# as well.
|
||||
#
|
||||
# tls-key-file-pass secret
|
||||
|
||||
# Normally Redis uses the same certificate for both server functions (accepting
|
||||
# connections) and client functions (replicating from a master, establishing
|
||||
@ -162,6 +167,11 @@ tcp-keepalive 300
|
||||
#
|
||||
# tls-client-cert-file client.crt
|
||||
# tls-client-key-file client.key
|
||||
#
|
||||
# If the key file is encrypted using a passphrase, it can be included here
|
||||
# as well.
|
||||
#
|
||||
# tls-client-key-file-pass secret
|
||||
|
||||
# Configure a DH parameters file to enable Diffie-Hellman (DH) key exchange:
|
||||
#
|
||||
|
@ -2543,8 +2543,10 @@ standardConfig configs[] = {
|
||||
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-key-file", NULL, MODIFIABLE_CONFIG, EMPTY_STRING_IS_NULL, server.tls_ctx_config.key_file, NULL, NULL, updateTlsCfg),
|
||||
createStringConfig("tls-key-file-pass", NULL, MODIFIABLE_CONFIG, EMPTY_STRING_IS_NULL, server.tls_ctx_config.key_file_pass, 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-client-key-file-pass", NULL, MODIFIABLE_CONFIG, EMPTY_STRING_IS_NULL, server.tls_ctx_config.client_key_file_pass, 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-dir", NULL, MODIFIABLE_CONFIG, EMPTY_STRING_IS_NULL, server.tls_ctx_config.ca_cert_dir, NULL, NULL, updateTlsCfg),
|
||||
|
@ -1119,8 +1119,10 @@ typedef struct socketFds {
|
||||
typedef struct redisTLSContextConfig {
|
||||
char *cert_file; /* Server side and optionally client side cert file name */
|
||||
char *key_file; /* Private key filename for cert_file */
|
||||
char *key_file_pass; /* Optional password for key_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 *client_key_file_pass; /* Optional password for client_key_file */
|
||||
char *dh_params_file;
|
||||
char *ca_cert_file;
|
||||
char *ca_cert_dir;
|
||||
|
28
src/tls.c
28
src/tls.c
@ -179,11 +179,28 @@ void tlsCleanup(void) {
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Callback for passing a keyfile password stored as an sds to OpenSSL */
|
||||
static int tlsPasswordCallback(char *buf, int size, int rwflag, void *u) {
|
||||
UNUSED(rwflag);
|
||||
|
||||
const char *pass = u;
|
||||
size_t pass_len;
|
||||
|
||||
if (!pass) return -1;
|
||||
pass_len = strlen(pass);
|
||||
if (pass_len > (size_t) size) return -1;
|
||||
memcpy(buf, pass, pass_len);
|
||||
|
||||
return (int) pass_len;
|
||||
}
|
||||
|
||||
/* Create a *base* SSL_CTX using the SSL configuration provided. The base context
|
||||
* includes everything that's common for both client-side and server-side connections.
|
||||
*/
|
||||
static SSL_CTX *createSSLContext(redisTLSContextConfig *ctx_config, int protocols,
|
||||
const char *cert_file, const char *key_file) {
|
||||
static SSL_CTX *createSSLContext(redisTLSContextConfig *ctx_config, int protocols, int client) {
|
||||
const char *cert_file = client ? ctx_config->client_cert_file : ctx_config->cert_file;
|
||||
const char *key_file = client ? ctx_config->client_key_file : ctx_config->key_file;
|
||||
const char *key_file_pass = client ? ctx_config->client_key_file_pass : ctx_config->key_file_pass;
|
||||
char errbuf[256];
|
||||
SSL_CTX *ctx = NULL;
|
||||
|
||||
@ -215,6 +232,9 @@ static SSL_CTX *createSSLContext(redisTLSContextConfig *ctx_config, int protocol
|
||||
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_default_passwd_cb(ctx, tlsPasswordCallback);
|
||||
SSL_CTX_set_default_passwd_cb_userdata(ctx, (void *) key_file_pass);
|
||||
|
||||
if (SSL_CTX_use_certificate_chain_file(ctx, cert_file) <= 0) {
|
||||
ERR_error_string_n(ERR_get_error(), errbuf, sizeof(errbuf));
|
||||
serverLog(LL_WARNING, "Failed to load certificate: %s: %s", cert_file, errbuf);
|
||||
@ -281,7 +301,7 @@ int tlsConfigure(redisTLSContextConfig *ctx_config) {
|
||||
if (protocols == -1) goto error;
|
||||
|
||||
/* Create server side/generla context */
|
||||
ctx = createSSLContext(ctx_config, protocols, ctx_config->cert_file, ctx_config->key_file);
|
||||
ctx = createSSLContext(ctx_config, protocols, 0);
|
||||
if (!ctx) goto error;
|
||||
|
||||
if (ctx_config->session_caching) {
|
||||
@ -332,7 +352,7 @@ int tlsConfigure(redisTLSContextConfig *ctx_config) {
|
||||
|
||||
/* If a client-side certificate is configured, create an explicit client context */
|
||||
if (ctx_config->client_cert_file && ctx_config->client_key_file) {
|
||||
client_ctx = createSSLContext(ctx_config, protocols, ctx_config->client_cert_file, ctx_config->client_key_file);
|
||||
client_ctx = createSSLContext(ctx_config, protocols, 1);
|
||||
if (!client_ctx) goto error;
|
||||
}
|
||||
|
||||
|
@ -139,5 +139,20 @@ start_server {tags {"tls"}} {
|
||||
$rd PING
|
||||
$rd close
|
||||
}
|
||||
|
||||
test {TLS: Working with an encrypted keyfile} {
|
||||
# Create an encrypted version
|
||||
set keyfile [lindex [r config get tls-key-file] 1]
|
||||
set keyfile_encrypted "$keyfile.encrypted"
|
||||
exec -ignorestderr openssl rsa -in $keyfile -out $keyfile_encrypted -aes256 -passout pass:1234 2>/dev/null
|
||||
|
||||
# Using it without a password fails
|
||||
catch {r config set tls-key-file $keyfile_encrypted} e
|
||||
assert_match {*Unable to update TLS*} $e
|
||||
|
||||
# Now use a password
|
||||
r config set tls-key-file-pass 1234
|
||||
r config set tls-key-file $keyfile_encrypted
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user