IMPALA-5800: Configure Squeasel's cipher suite and TLS version * Import Squeasel as of https://github.com/cloudera/squeasel/commit/1e5f611, which adds TLS version and cipher suite configuration.
* Plumb through --ssl_minimum_version and --ssl_cipher_list to the Squeasel options in webserver.cc. Testing: manually confirm that webserver connections have desired protocol version and cipher suite. Add two tests to webserver-test to check that misconfiguration leads to a failure. Change-Id: I23fb17257098992c65e50c1e83a905c9a85db6a2 Reviewed-on: http://gerrit.cloudera.org:8080/7679 Reviewed-by: Sailesh Mukil <[email protected]> Reviewed-by: Henry Robinson <[email protected]> Tested-by: Impala Public Jenkins Project: http://git-wip-us.apache.org/repos/asf/incubator-impala/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-impala/commit/51ec6071 Tree: http://git-wip-us.apache.org/repos/asf/incubator-impala/tree/51ec6071 Diff: http://git-wip-us.apache.org/repos/asf/incubator-impala/diff/51ec6071 Branch: refs/heads/master Commit: 51ec60713980bd6e64e626f4476e843c49f5ea48 Parents: b660bd6 Author: Henry Robinson <[email protected]> Authored: Mon Aug 14 20:49:52 2017 -0700 Committer: Impala Public Jenkins <[email protected]> Committed: Thu Aug 17 01:51:15 2017 +0000 ---------------------------------------------------------------------- be/src/thirdparty/squeasel/squeasel.c | 34 ++++++++++++++++++++++--- be/src/util/webserver-test.cc | 40 ++++++++++++++++++++++++++++++ be/src/util/webserver.cc | 9 +++++++ 3 files changed, 80 insertions(+), 3 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-impala/blob/51ec6071/be/src/thirdparty/squeasel/squeasel.c ---------------------------------------------------------------------- diff --git a/be/src/thirdparty/squeasel/squeasel.c b/be/src/thirdparty/squeasel/squeasel.c index 3d27d2d..3f957de 100644 --- a/be/src/thirdparty/squeasel/squeasel.c +++ b/be/src/thirdparty/squeasel/squeasel.c @@ -212,7 +212,7 @@ enum { GLOBAL_PASSWORDS_FILE, INDEX_FILES, ENABLE_KEEP_ALIVE, ACCESS_CONTROL_LIST, EXTRA_MIME_TYPES, LISTENING_PORTS, DOCUMENT_ROOT, SSL_CERTIFICATE, SSL_PRIVATE_KEY, SSL_PRIVATE_KEY_PASSWORD, SSL_GLOBAL_INIT, NUM_THREADS, RUN_AS_USER, REWRITE, - HIDE_FILES, REQUEST_TIMEOUT, NUM_OPTIONS + HIDE_FILES, REQUEST_TIMEOUT, SSL_VERSION, SSL_CIPHERS, NUM_OPTIONS }; static const char *config_options[] = { @@ -244,6 +244,8 @@ static const char *config_options[] = { "url_rewrite_patterns", NULL, "hide_files_patterns", NULL, "request_timeout_ms", "30000", + "ssl_min_version", "tlsv1", + "ssl_ciphers", NULL, NULL }; @@ -4139,6 +4141,9 @@ static int set_uid_option(struct sq_context *ctx) { } #if !defined(NO_SSL) + +#define OPENSSL_VERSION_HAS_TLS_1_1 0x10001000L + static pthread_mutex_t *ssl_mutexes; static int sslize(struct sq_connection *conn, SSL_CTX *s, int (*func)(SSL *)) { @@ -4215,7 +4220,23 @@ static int set_ssl_option(struct sq_context *ctx) { CRYPTO_set_id_callback(&ssl_id_callback); } - if ((ctx->ssl_ctx = SSL_CTX_new(SSLv23_server_method())) == NULL) { + char* ssl_version = ctx->config[SSL_VERSION]; + int options = SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3; + if (sq_strcasecmp(ssl_version, "tlsv1") == 0) { + // No-op - don't exclude any TLS protocols. +#if OPENSSL_VERSION_NUMBER >= OPENSSL_VERSION_HAS_TLS_1_1 + } else if (sq_strcasecmp(ssl_version, "tlsv1_1") == 0) { + options |= SSL_OP_NO_TLSv1; + } else if (sq_strcasecmp(ssl_version, "tlsv1_2") == 0) { + options |= (SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1); +#endif + } else { + cry(fc(ctx), "%s: unknown SSL version: %s", __func__, ssl_version); + return 0; + } + + ctx->ssl_ctx = SSL_CTX_new(SSLv23_method()); + if (ctx->ssl_ctx == NULL) { unsigned long err_code = ERR_peek_error(); // If it looks like the error is due to SSL not being initialized, // provide a better error. @@ -4230,7 +4251,7 @@ static int set_ssl_option(struct sq_context *ctx) { return 0; } - SSL_CTX_set_options(ctx->ssl_ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3); + SSL_CTX_set_options(ctx->ssl_ctx, options); if (ctx->config[SSL_PRIVATE_KEY_PASSWORD] != NULL) { SSL_CTX_set_default_passwd_cb(ctx->ssl_ctx, ssl_password_callback); @@ -4251,6 +4272,13 @@ static int set_ssl_option(struct sq_context *ctx) { (void) SSL_CTX_use_certificate_chain_file(ctx->ssl_ctx, pem); } + if (ctx->config[SSL_CIPHERS] != NULL) { + if (SSL_CTX_set_cipher_list(ctx->ssl_ctx, ctx->config[SSL_CIPHERS]) == 0) { + cry(fc(ctx), "SSL_CTX_set_cipher_list: error setting ciphers (%s): %s", + ctx->config[SSL_CIPHERS], ssl_error()); + return 0; + } + } return 1; } http://git-wip-us.apache.org/repos/asf/incubator-impala/blob/51ec6071/be/src/util/webserver-test.cc ---------------------------------------------------------------------- diff --git a/be/src/util/webserver-test.cc b/be/src/util/webserver-test.cc index 1abbe42..7abaa37 100644 --- a/be/src/util/webserver-test.cc +++ b/be/src/util/webserver-test.cc @@ -33,6 +33,8 @@ DECLARE_string(webserver_certificate_file); DECLARE_string(webserver_private_key_file); DECLARE_string(webserver_private_key_password_cmd); DECLARE_string(webserver_x_frame_options); +DECLARE_string(ssl_cipher_list); +DECLARE_string(ssl_minimum_version); #include "common/names.h" @@ -246,6 +248,44 @@ TEST(Webserver, SslBadPrivateKeyPasswordTest) { ASSERT_FALSE(webserver.Start().ok()); } +TEST(Webserver, SslCipherSuite) { + auto cert = ScopedFlagSetter<string>::Make(&FLAGS_webserver_certificate_file, + Substitute("$0/be/src/testutil/server-cert.pem", getenv("IMPALA_HOME"))); + auto key = ScopedFlagSetter<string>::Make(&FLAGS_webserver_private_key_file, + Substitute("$0/be/src/testutil/server-key-password.pem", getenv("IMPALA_HOME"))); + auto cmd = ScopedFlagSetter<string>::Make( + &FLAGS_webserver_private_key_password_cmd, "echo password"); + + { + auto ciphers = ScopedFlagSetter<string>::Make( + &FLAGS_ssl_cipher_list, "not_a_cipher"); + Webserver webserver(FLAGS_webserver_port); + ASSERT_FALSE(webserver.Start().ok()); + } + + { + auto ciphers = ScopedFlagSetter<string>::Make( + &FLAGS_ssl_cipher_list, "RC4-SHA"); + Webserver webserver(FLAGS_webserver_port); + ASSERT_OK(webserver.Start()); + } +} + +TEST(Webserver, SslBadTlsVersion) { + auto cert = ScopedFlagSetter<string>::Make(&FLAGS_webserver_certificate_file, + Substitute("$0/be/src/testutil/server-cert.pem", getenv("IMPALA_HOME"))); + auto key = ScopedFlagSetter<string>::Make(&FLAGS_webserver_private_key_file, + Substitute("$0/be/src/testutil/server-key-password.pem", getenv("IMPALA_HOME"))); + auto cmd = ScopedFlagSetter<string>::Make( + &FLAGS_webserver_private_key_password_cmd, "echo password"); + + auto ssl_version = ScopedFlagSetter<string>::Make( + &FLAGS_ssl_minimum_version, "not_a_version"); + + Webserver webserver(FLAGS_webserver_port); + ASSERT_FALSE(webserver.Start().ok()); +} + TEST(Webserver, StartWithPasswordFileTest) { stringstream password_file; password_file << getenv("IMPALA_HOME") << "/be/src/testutil/htpasswd"; http://git-wip-us.apache.org/repos/asf/incubator-impala/blob/51ec6071/be/src/util/webserver.cc ---------------------------------------------------------------------- diff --git a/be/src/util/webserver.cc b/be/src/util/webserver.cc index ef96181..ea0a6e9 100644 --- a/be/src/util/webserver.cc +++ b/be/src/util/webserver.cc @@ -101,6 +101,8 @@ DEFINE_string(webserver_x_frame_options, "DENY", "webserver will add X-Frame-Options HTTP header with this value"); DECLARE_bool(is_coordinator); +DECLARE_string(ssl_minimum_version); +DECLARE_string(ssl_cipher_list); static const char* DOC_FOLDER = "/www/"; static const int DOC_FOLDER_LEN = strlen(DOC_FOLDER); @@ -261,6 +263,13 @@ Status Webserver::Start() { options.push_back(key_password.c_str()); } } + + options.push_back("ssl_min_version"); + options.push_back(FLAGS_ssl_minimum_version.c_str()); + if (!FLAGS_ssl_cipher_list.empty()) { + options.push_back("ssl_ciphers"); + options.push_back(FLAGS_ssl_cipher_list.c_str()); + } } if (!FLAGS_webserver_authentication_domain.empty()) {
