From 10b50069344120c1d46418838bfc2de38b65ca4a Mon Sep 17 00:00:00 2001 From: filipe oliveira Date: Wed, 4 Nov 2020 12:49:15 +0000 Subject: [PATCH] Enable specifying TLS ciphers(suites) in redis-cli/redis-benchmark (#8005) Enable specifying the preferred ciphers and/or ciphersuites for redis-cli/redis-benchmark. Co-authored-by: Yossi Gottlieb --- src/cli_common.c | 11 ++++++- src/cli_common.h | 4 +++ src/redis-benchmark.c | 17 +++++++++++ src/redis-cli.c | 15 ++++++++++ tests/integration/redis-benchmark.tcl | 41 +++++++++++++++++++++++++++ 5 files changed, 87 insertions(+), 1 deletion(-) diff --git a/src/cli_common.c b/src/cli_common.c index c45e3de96..c2db9fffc 100644 --- a/src/cli_common.c +++ b/src/cli_common.c @@ -53,7 +53,6 @@ int cliSecureConnection(redisContext *c, cliSSLconfig config, const char **err) *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); @@ -78,6 +77,16 @@ int cliSecureConnection(redisContext *c, cliSSLconfig config, const char **err) *err = "Invalid private key"; goto error; } + if (config.ciphers && !SSL_CTX_set_cipher_list(ssl_ctx, config.ciphers)) { + *err = "Error while configuring ciphers"; + goto error; + } +#ifdef TLS1_3_VERSION + if (config.ciphersuites && !SSL_CTX_set_ciphersuites(ssl_ctx, config.ciphersuites)) { + *err = "Error while setting cypher suites"; + goto error; + } +#endif } SSL *ssl = SSL_new(ssl_ctx); diff --git a/src/cli_common.h b/src/cli_common.h index 700a834ce..f3a91e9db 100644 --- a/src/cli_common.h +++ b/src/cli_common.h @@ -14,6 +14,10 @@ typedef struct cliSSLconfig { char *cert; /* Private key file to authenticate with, or NULL */ char *key; + /* Prefered cipher list, or NULL (applies only to <= TLSv1.2) */ + char* ciphers; + /* Prefered ciphersuites list, or NULL (applies only to TLSv1.3) */ + char* ciphersuites; } cliSSLconfig; /* Wrapper around redisSecureConnection to avoid hiredis_ssl dependencies if diff --git a/src/redis-benchmark.c b/src/redis-benchmark.c index 9f27ad804..0ec9cb1eb 100644 --- a/src/redis-benchmark.c +++ b/src/redis-benchmark.c @@ -1520,6 +1520,14 @@ int parseOptions(int argc, const char **argv) { } else if (!strcmp(argv[i],"--key")) { if (lastarg) goto invalid; config.sslconfig.key = strdup(argv[++i]); + } else if (!strcmp(argv[i],"--tls-ciphers")) { + if (lastarg) goto invalid; + config.sslconfig.ciphers = strdup(argv[++i]); + #ifdef TLS1_3_VERSION + } else if (!strcmp(argv[i],"--tls-ciphersuites")) { + if (lastarg) goto invalid; + config.sslconfig.ciphersuites = strdup(argv[++i]); + #endif #endif } else { /* Assume the user meant to provide an option when the arg starts @@ -1577,6 +1585,15 @@ usage: " system-wide trusted root certs configuration will apply.\n" " --cert Client certificate to authenticate with.\n" " --key Private key file to authenticate with.\n" +" --tls-ciphers Sets the list of prefered ciphers (TLSv1.2 and below)\n" +" in order of preference from highest to lowest separated by colon (\":\").\n" +" See the ciphers(1ssl) manpage for more information about the syntax of this string.\n" +#ifdef TLS1_3_VERSION +" --tls-ciphersuites Sets the list of prefered ciphersuites (TLSv1.3)\n" +" in order of preference from highest to lowest separated by colon (\":\").\n" +" See the ciphers(1ssl) manpage for more information about the syntax of this string,\n" +" and specifically for TLSv1.3 ciphersuites.\n" +#endif #endif " --help Output this help and exit.\n" " --version Output version and exit.\n\n" diff --git a/src/redis-cli.c b/src/redis-cli.c index 8b5ab4136..9c8d0b063 100644 --- a/src/redis-cli.c +++ b/src/redis-cli.c @@ -1650,6 +1650,12 @@ static int parseOptions(int argc, char **argv) { config.sslconfig.cert = argv[++i]; } else if (!strcmp(argv[i],"--key") && !lastarg) { config.sslconfig.key = argv[++i]; + } else if (!strcmp(argv[i],"--tls-ciphers") && !lastarg) { + config.sslconfig.ciphers = argv[++i]; + #ifdef TLS1_3_VERSION + } else if (!strcmp(argv[i],"--tls-ciphersuites") && !lastarg) { + config.sslconfig.ciphersuites = argv[++i]; + #endif #endif } else if (!strcmp(argv[i],"-v") || !strcmp(argv[i], "--version")) { sds version = cliVersion(); @@ -1772,6 +1778,15 @@ static void usage(void) { " system-wide trusted root certs configuration will apply.\n" " --cert Client certificate to authenticate with.\n" " --key Private key file to authenticate with.\n" +" --tls-ciphers Sets the list of prefered ciphers (TLSv1.2 and below)\n" +" in order of preference from highest to lowest separated by colon (\":\").\n" +" See the ciphers(1ssl) manpage for more information about the syntax of this string.\n" +#ifdef TLS1_3_VERSION +" --tls-ciphersuites Sets the list of prefered ciphersuites (TLSv1.3)\n" +" in order of preference from highest to lowest separated by colon (\":\").\n" +" See the ciphers(1ssl) manpage for more information about the syntax of this string,\n" +" and specifically for TLSv1.3 ciphersuites.\n" +#endif #endif " --raw Use raw formatting for replies (default when STDOUT is\n" " not a tty).\n" diff --git a/tests/integration/redis-benchmark.tcl b/tests/integration/redis-benchmark.tcl index 8abeabf0b..4a4be2ebc 100644 --- a/tests/integration/redis-benchmark.tcl +++ b/tests/integration/redis-benchmark.tcl @@ -123,5 +123,46 @@ start_server {tags {"benchmark"}} { # ensure the keyspace has the desired size assert_match {50} [scan [regexp -inline {keys\=([\d]*)} [r info keyspace]] keys=%d] } + + # tls specific tests + if {$::tls} { + test {benchmark: specific tls-ciphers} { + r flushall + r config resetstat + set cmd [redisbenchmark $master_host $master_port "-r 50 -t set -n 1000 --tls-ciphers \"DEFAULT:-AES128-SHA256\""] + if {[catch { exec {*}$cmd } error]} { + set first_line [lindex [split $error "\n"] 0] + puts [colorstr red "redis-benchmark non zero code. first line: $first_line"] + fail "redis-benchmark non zero code. first line: $first_line" + } + assert_match {*calls=1000,*} [cmdstat set] + # assert one of the non benchmarked commands is not present + assert_match {} [cmdstat get] + } + + test {benchmark: specific tls-ciphersuites} { + r flushall + r config resetstat + set ciphersuites_supported 1 + set cmd [redisbenchmark $master_host $master_port "-r 50 -t set -n 1000 --tls-ciphersuites \"TLS_AES_128_GCM_SHA256\""] + if {[catch { exec {*}$cmd } error]} { + set first_line [lindex [split $error "\n"] 0] + if {[string match "*Invalid option*" $first_line]} { + set ciphersuites_supported 0 + if {$::verbose} { + puts "Skipping test, TLSv1.3 not supported." + } + } else { + puts [colorstr red "redis-benchmark non zero code. first line: $first_line"] + fail "redis-benchmark non zero code. first line: $first_line" + } + } + if {$ciphersuites_supported} { + assert_match {*calls=1000,*} [cmdstat set] + # assert one of the non benchmarked commands is not present + assert_match {} [cmdstat get] + } + } + } } }