diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/mongo/SConscript | 5 | ||||
-rw-r--r-- | src/mongo/db/SConscript | 3 | ||||
-rw-r--r-- | src/mongo/db/mongod_options.cpp | 19 | ||||
-rw-r--r-- | src/mongo/db/server_options_server_helpers.cpp | 14 | ||||
-rw-r--r-- | src/mongo/db/server_options_server_helpers.h | 2 | ||||
-rw-r--r-- | src/mongo/db/server_options_test.cpp | 323 | ||||
-rw-r--r-- | src/mongo/s/mongos_options.cpp | 21 | ||||
-rw-r--r-- | src/mongo/shell/shell_options.cpp | 25 | ||||
-rw-r--r-- | src/mongo/util/net/SConscript | 60 | ||||
-rw-r--r-- | src/mongo/util/net/ssl_options.cpp | 572 | ||||
-rw-r--r-- | src/mongo/util/net/ssl_options.h | 29 | ||||
-rw-r--r-- | src/mongo/util/net/ssl_options_client.cpp | 212 | ||||
-rw-r--r-- | src/mongo/util/net/ssl_options_server.cpp | 473 | ||||
-rw-r--r-- | src/mongo/util/net/ssl_options_test.cpp | 356 |
14 files changed, 1122 insertions, 992 deletions
diff --git a/src/mongo/SConscript b/src/mongo/SConscript index 2c5093dee1b..f00f59720b7 100644 --- a/src/mongo/SConscript +++ b/src/mongo/SConscript @@ -284,6 +284,7 @@ env.Library( ], LIBDEPS_PRIVATE=[ 'db/mongod_options', + '$BUILD_DIR/mongo/util/net/ssl_options_server' if has_option('ssl') else '', ] ) @@ -438,6 +439,9 @@ mongos = env.Program( 'util/options_parser/options_parser_init', 'util/version_impl', ], + LIBDEPS_PRIVATE=[ + '$BUILD_DIR/mongo/util/net/ssl_options_server' if has_option('ssl') else '', + ], INSTALL_ALIAS=[ 'servers', ], @@ -529,6 +533,7 @@ if not has_option('noshell') and usemozjs: ], LIBDEPS_PRIVATE=[ "$BUILD_DIR/mongo/client/connection_string", + '$BUILD_DIR/mongo/util/net/ssl_options_client' if has_option('ssl') else '', ], INSTALL_ALIAS=[ 'shell', diff --git a/src/mongo/db/SConscript b/src/mongo/db/SConscript index b28085d4de5..2cdce708cc4 100644 --- a/src/mongo/db/SConscript +++ b/src/mongo/db/SConscript @@ -426,8 +426,9 @@ env.CppUnitTest( source=[ 'server_options_test.cpp', ], - LIBDEPS=[ + LIBDEPS_PRIVATE=[ 'server_options_servers', + '$BUILD_DIR/mongo/util/net/ssl_options_server', ], ) diff --git a/src/mongo/db/mongod_options.cpp b/src/mongo/db/mongod_options.cpp index 85d50af141f..0376b73cee0 100644 --- a/src/mongo/db/mongod_options.cpp +++ b/src/mongo/db/mongod_options.cpp @@ -72,15 +72,6 @@ Status addMongodOptions(moe::OptionSection* options) { } #endif -#ifdef MONGO_CONFIG_SSL - moe::OptionSection ssl_options("SSL options"); - - ret = addSSLServerOptions(&ssl_options); - if (!ret.isOK()) { - return ret; - } -#endif - moe::OptionSection rs_options("Replica set options"); moe::OptionSection replication_options("Replication options"); moe::OptionSection sharding_options("Sharding options"); @@ -406,9 +397,6 @@ Status addMongodOptions(moe::OptionSection* options) { options->addSection(replication_options).transitional_ignore(); options->addSection(rs_options).transitional_ignore(); options->addSection(sharding_options).transitional_ignore(); -#ifdef MONGO_CONFIG_SSL - options->addSection(ssl_options).transitional_ignore(); -#endif options->addSection(storage_options).transitional_ignore(); // The following are legacy options that are disallowed in the JSON config file @@ -544,13 +532,6 @@ Status canonicalizeMongodOptions(moe::Environment* params) { return ret; } -#ifdef MONGO_CONFIG_SSL - ret = canonicalizeSSLServerOptions(params); - if (!ret.isOK()) { - return ret; - } -#endif - // "storage.journal.enabled" comes from the config file, so override it if any of "journal", // "nojournal", "dur", and "nodur" are set, since those come from the command line. if (params->count("journal")) { diff --git a/src/mongo/db/server_options_server_helpers.cpp b/src/mongo/db/server_options_server_helpers.cpp index 767ff3c2d61..e5b59443cbc 100644 --- a/src/mongo/db/server_options_server_helpers.cpp +++ b/src/mongo/db/server_options_server_helpers.cpp @@ -390,13 +390,6 @@ Status validateServerOptions(const moe::Environment& params) { } #endif -#ifdef MONGO_CONFIG_SSL - ret = validateSSLServerOptions(params); - if (!ret.isOK()) { - return ret; - } -#endif - bool haveAuthenticationMechanisms = true; bool hasAuthorizationEnabled = false; if (params.count("security.authenticationMechanisms") && @@ -664,13 +657,6 @@ Status storeServerOptions(const moe::Environment& params) { "--transitionToAuth must be used with keyFile or x509 authentication"); } -#ifdef MONGO_CONFIG_SSL - ret = storeSSLServerOptions(params); - if (!ret.isOK()) { - return ret; - } -#endif - ret = storeMessageCompressionOptions(params); if (!ret.isOK()) { return ret; diff --git a/src/mongo/db/server_options_server_helpers.h b/src/mongo/db/server_options_server_helpers.h index a22ff251edb..826795ce8dd 100644 --- a/src/mongo/db/server_options_server_helpers.h +++ b/src/mongo/db/server_options_server_helpers.h @@ -48,8 +48,6 @@ Status addGeneralServerOptions(moe::OptionSection* options); Status addWindowsServerOptions(moe::OptionSection* options); -Status addSSLServerOptions(moe::OptionSection* options); - /** * Handle custom validation of server options that can not currently be done by using * Constraints in the Environment. See the "validate" function in the Environment class for diff --git a/src/mongo/db/server_options_test.cpp b/src/mongo/db/server_options_test.cpp index 720265ab19b..badb6380e90 100644 --- a/src/mongo/db/server_options_test.cpp +++ b/src/mongo/db/server_options_test.cpp @@ -51,17 +51,16 @@ #include "mongo/logger/logger.h" #include "mongo/unittest/unittest.h" #include "mongo/util/log.h" -#include "mongo/util/net/ssl_options.h" #include "mongo/util/options_parser/environment.h" #include "mongo/util/options_parser/option_section.h" #include "mongo/util/options_parser/options_parser.h" #include "mongo/util/scopeguard.h" + namespace { using mongo::ErrorCodes; using mongo::Status; - namespace moe = mongo::optionenvironment; class OptionsParserTester : public moe::OptionsParser { @@ -779,326 +778,6 @@ TEST(SetupOptions, NonNumericSampleRateYAMLConfigOptionFailsToParse) { ASSERT_NOT_OK(parser.run(options, argv, env_map, &environment)); } -TEST(SetupOptions, tlsModeDisabled) { - OptionsParserTester parser; - moe::Environment environment; - moe::OptionSection options; - - ASSERT_OK(::mongo::addGeneralServerOptions(&options)); - - std::vector<std::string> argv; - argv.push_back("binaryname"); - argv.push_back("--tlsMode"); - argv.push_back("disabled"); - std::map<std::string, std::string> env_map; - - Status ret = ::mongo::addSSLServerOptions(&options); - - ASSERT_OK(parser.run(options, argv, env_map, &environment)); - ASSERT_EQ(::mongo::sslGlobalParams.sslMode.load(), ::mongo::sslGlobalParams.SSLMode_disabled); -} - -TEST(SetupOptions, sslModeDisabled) { - OptionsParserTester parser; - moe::Environment environment; - moe::OptionSection options; - - ASSERT_OK(::mongo::addGeneralServerOptions(&options)); - - std::vector<std::string> argv; - argv.push_back("binaryname"); - argv.push_back("--sslMode"); - argv.push_back("disabled"); - std::map<std::string, std::string> env_map; - - Status ret = ::mongo::addSSLServerOptions(&options); - - ASSERT_OK(parser.run(options, argv, env_map, &environment)); - ASSERT_EQ(::mongo::sslGlobalParams.sslMode.load(), ::mongo::sslGlobalParams.SSLMode_disabled); -} - -TEST(SetupOptions, tlsModeRequired) { - OptionsParserTester parser; - moe::Environment environment; - moe::OptionSection options; - - ASSERT_OK(::mongo::addGeneralServerOptions(&options)); - - std::string sslPEMKeyFile = "jstests/libs/server.pem"; - std::string sslCAFFile = "jstests/libs/ca.pem"; - std::string sslCRLFile = "jstests/libs/crl.pem"; - std::string sslClusterFile = "jstests/libs/cluster_cert.pem"; - - std::vector<std::string> argv; - argv.push_back("binaryname"); - argv.push_back("--tlsMode"); - argv.push_back("requireTLS"); - argv.push_back("--tlsPEMKeyFile"); - argv.push_back(sslPEMKeyFile); - argv.push_back("--tlsCAFile"); - argv.push_back(sslCAFFile); - argv.push_back("--tlsCRLFile"); - argv.push_back(sslCRLFile); - argv.push_back("--tlsClusterFile"); - argv.push_back(sslClusterFile); - argv.push_back("--tlsAllowInvalidHostnames"); - argv.push_back("--tlsAllowInvalidCertificates"); - argv.push_back("--tlsWeakCertificateValidation"); - argv.push_back("--tlsFIPSMode"); - argv.push_back("--tlsPEMKeyPassword"); - argv.push_back("pw1"); - argv.push_back("--tlsClusterPassword"); - argv.push_back("pw2"); - argv.push_back("--tlsDisabledProtocols"); - argv.push_back("TLS1_1"); - std::map<std::string, std::string> env_map; - - Status addRet = mongo::addSSLServerOptions(&options); - - ASSERT_OK(parser.run(options, argv, env_map, &environment)); - Status storeRet = mongo::storeSSLServerOptions(environment); - - ASSERT_EQ(::mongo::sslGlobalParams.sslMode.load(), ::mongo::sslGlobalParams.SSLMode_requireSSL); - ASSERT_EQ(::mongo::sslGlobalParams.sslPEMKeyFile.substr( - ::mongo::sslGlobalParams.sslPEMKeyFile.length() - sslPEMKeyFile.length()), - sslPEMKeyFile); - ASSERT_EQ(::mongo::sslGlobalParams.sslCAFile.substr( - ::mongo::sslGlobalParams.sslCAFile.length() - sslCAFFile.length()), - sslCAFFile); - ASSERT_EQ(::mongo::sslGlobalParams.sslCRLFile.substr( - ::mongo::sslGlobalParams.sslCRLFile.length() - sslCRLFile.length()), - sslCRLFile); - ASSERT_EQ(::mongo::sslGlobalParams.sslClusterFile.substr( - ::mongo::sslGlobalParams.sslClusterFile.length() - sslClusterFile.length()), - sslClusterFile); - ASSERT_EQ(::mongo::sslGlobalParams.sslAllowInvalidHostnames, true); - ASSERT_EQ(::mongo::sslGlobalParams.sslAllowInvalidCertificates, true); - ASSERT_EQ(::mongo::sslGlobalParams.sslWeakCertificateValidation, true); - ASSERT_EQ(::mongo::sslGlobalParams.sslFIPSMode, true); - ASSERT_EQ(::mongo::sslGlobalParams.sslPEMKeyPassword, "pw1"); - ASSERT_EQ(::mongo::sslGlobalParams.sslClusterPassword, "pw2"); - ASSERT_EQ(static_cast<int>(::mongo::sslGlobalParams.sslDisabledProtocols.back()), - static_cast<int>(::mongo::SSLParams::Protocols::TLS1_1)); -} - -TEST(SetupOptions, sslModeRequired) { - OptionsParserTester parser; - moe::Environment environment; - moe::OptionSection options; - - ASSERT_OK(::mongo::addGeneralServerOptions(&options)); - - std::string sslPEMKeyFile = "jstests/libs/server.pem"; - std::string sslCAFFile = "jstests/libs/ca.pem"; - std::string sslCRLFile = "jstests/libs/crl.pem"; - std::string sslClusterFile = "jstests/libs/cluster_cert.pem"; - - std::vector<std::string> argv; - argv.push_back("binaryname"); - argv.push_back("--sslMode"); - argv.push_back("requireSSL"); - argv.push_back("--sslPEMKeyFile"); - argv.push_back(sslPEMKeyFile); - argv.push_back("--sslCAFile"); - argv.push_back(sslCAFFile); - argv.push_back("--sslCRLFile"); - argv.push_back(sslCRLFile); - argv.push_back("--sslClusterFile"); - argv.push_back(sslClusterFile); - argv.push_back("--sslAllowInvalidHostnames"); - argv.push_back("--sslAllowInvalidCertificates"); - argv.push_back("--sslWeakCertificateValidation"); - argv.push_back("--sslFIPSMode"); - argv.push_back("--sslPEMKeyPassword"); - argv.push_back("pw1"); - argv.push_back("--sslClusterPassword"); - argv.push_back("pw2"); - argv.push_back("--sslDisabledProtocols"); - argv.push_back("TLS1_1"); - std::map<std::string, std::string> env_map; - - Status addRet = mongo::addSSLServerOptions(&options); - - ASSERT_OK(parser.run(options, argv, env_map, &environment)); - Status storeRet = mongo::storeSSLServerOptions(environment); - - ASSERT_EQ(::mongo::sslGlobalParams.sslMode.load(), ::mongo::sslGlobalParams.SSLMode_requireSSL); - ASSERT_EQ(::mongo::sslGlobalParams.sslPEMKeyFile.substr( - ::mongo::sslGlobalParams.sslPEMKeyFile.length() - sslPEMKeyFile.length()), - sslPEMKeyFile); - ASSERT_EQ(::mongo::sslGlobalParams.sslCAFile.substr( - ::mongo::sslGlobalParams.sslCAFile.length() - sslCAFFile.length()), - sslCAFFile); - ASSERT_EQ(::mongo::sslGlobalParams.sslCRLFile.substr( - ::mongo::sslGlobalParams.sslCRLFile.length() - sslCRLFile.length()), - sslCRLFile); - ASSERT_EQ(::mongo::sslGlobalParams.sslClusterFile.substr( - ::mongo::sslGlobalParams.sslClusterFile.length() - sslClusterFile.length()), - sslClusterFile); - ASSERT_EQ(::mongo::sslGlobalParams.sslAllowInvalidHostnames, true); - ASSERT_EQ(::mongo::sslGlobalParams.sslAllowInvalidCertificates, true); - ASSERT_EQ(::mongo::sslGlobalParams.sslWeakCertificateValidation, true); - ASSERT_EQ(::mongo::sslGlobalParams.sslFIPSMode, true); - ASSERT_EQ(::mongo::sslGlobalParams.sslPEMKeyPassword, "pw1"); - ASSERT_EQ(::mongo::sslGlobalParams.sslClusterPassword, "pw2"); - ASSERT_EQ(static_cast<int>(::mongo::sslGlobalParams.sslDisabledProtocols.back()), - static_cast<int>(::mongo::SSLParams::Protocols::TLS1_1)); -} - -#ifdef MONGO_CONFIG_SSL_CERTIFICATE_SELECTORS -TEST(SetupOptions, tlsModeRequiredCertificateSelector) { - OptionsParserTester parser; - moe::Environment environment; - moe::OptionSection options; - - ASSERT_OK(::mongo::addGeneralServerOptions(&options)); - - std::vector<std::string> argv; - argv.push_back("binaryname"); - argv.push_back("--tlsMode"); - argv.push_back("requireTLS"); - argv.push_back("--tlsCertificateSelector"); - argv.push_back("subject=Subject 1"); - argv.push_back("--tlsClusterCertificateSelector"); - argv.push_back("subject=Subject 2"); - std::map<std::string, std::string> env_map; - - Status addRet = mongo::addSSLServerOptions(&options); - - ASSERT_OK(parser.run(options, argv, env_map, &environment)); - Status storeRet = mongo::storeSSLServerOptions(environment); - - ASSERT_EQ(::mongo::sslGlobalParams.sslMode.load(), ::mongo::sslGlobalParams.SSLMode_requireSSL); - ASSERT_EQ(::mongo::sslGlobalParams.sslCertificateSelector.subject, "Subject 1"); - ASSERT_EQ(::mongo::sslGlobalParams.sslClusterCertificateSelector.subject, "Subject 2"); -} - -TEST(SetupOptions, sslModeRequiredCertificateSelector) { - OptionsParserTester parser; - moe::Environment environment; - moe::OptionSection options; - - ASSERT_OK(::mongo::addGeneralServerOptions(&options)); - - std::vector<std::string> argv; - argv.push_back("binaryname"); - argv.push_back("--sslMode"); - argv.push_back("requireSSL"); - argv.push_back("--sslCertificateSelector"); - argv.push_back("subject=Subject 1"); - argv.push_back("--sslClusterCertificateSelector"); - argv.push_back("subject=Subject 2"); - std::map<std::string, std::string> env_map; - - Status addRet = mongo::addSSLServerOptions(&options); - - ASSERT_OK(parser.run(options, argv, env_map, &environment)); - Status storeRet = mongo::storeSSLServerOptions(environment); - - ASSERT_EQ(::mongo::sslGlobalParams.sslMode.load(), ::mongo::sslGlobalParams.SSLMode_requireSSL); - ASSERT_EQ(::mongo::sslGlobalParams.sslCertificateSelector.subject, "Subject 1"); - ASSERT_EQ(::mongo::sslGlobalParams.sslClusterCertificateSelector.subject, "Subject 2"); -} - -TEST(SetupOptions, disableNonSSLConnectionLoggingFalse) { - OptionsParserTester parser; - moe::Environment environment; - moe::OptionSection options; - - ASSERT_OK(::mongo::addGeneralServerOptions(&options)); - - std::vector<std::string> argv; - argv.push_back("binaryname"); - argv.push_back("--setParameter"); - argv.push_back("disableNonSSLConnectionLogging=false"); - std::map<std::string, std::string> env_map; - - ASSERT_OK(parser.run(options, argv, env_map, &environment)); - Status storeRet = mongo::storeServerOptions(environment); - - ASSERT_EQ(::mongo::sslGlobalParams.disableNonSSLConnectionLogging, false); -} - -TEST(SetupOptions, disableNonTLSConnectionLoggingFalse) { - OptionsParserTester parser; - moe::Environment environment; - moe::OptionSection options; - - ::mongo::sslGlobalParams.disableNonSSLConnectionLoggingSet = false; - ASSERT_OK(::mongo::addGeneralServerOptions(&options)); - - std::vector<std::string> argv; - argv.push_back("binaryname"); - argv.push_back("--setParameter"); - argv.push_back("disableNonTLSConnectionLogging=false"); - std::map<std::string, std::string> env_map; - - ASSERT_OK(parser.run(options, argv, env_map, &environment)); - Status storeRet = mongo::storeServerOptions(environment); - - ASSERT_EQ(::mongo::sslGlobalParams.disableNonSSLConnectionLogging, false); -} - -TEST(SetupOptions, disableNonSSLConnectionLoggingTrue) { - OptionsParserTester parser; - moe::Environment environment; - moe::OptionSection options; - - ::mongo::sslGlobalParams.disableNonSSLConnectionLoggingSet = false; - ASSERT_OK(::mongo::addGeneralServerOptions(&options)); - - std::vector<std::string> argv; - argv.push_back("binaryname"); - argv.push_back("--setParameter"); - argv.push_back("disableNonSSLConnectionLogging=true"); - std::map<std::string, std::string> env_map; - - ASSERT_OK(parser.run(options, argv, env_map, &environment)); - Status storeRet = mongo::storeServerOptions(environment); - - ASSERT_EQ(::mongo::sslGlobalParams.disableNonSSLConnectionLogging, true); -} - -TEST(SetupOptions, disableNonTLSConnectionLoggingTrue) { - OptionsParserTester parser; - moe::Environment environment; - moe::OptionSection options; - - ::mongo::sslGlobalParams.disableNonSSLConnectionLoggingSet = false; - ASSERT_OK(::mongo::addGeneralServerOptions(&options)); - - std::vector<std::string> argv; - argv.push_back("binaryname"); - argv.push_back("--setParameter"); - argv.push_back("disableNonTLSConnectionLogging=true"); - std::map<std::string, std::string> env_map; - - ASSERT_OK(parser.run(options, argv, env_map, &environment)); - Status storeRet = mongo::storeServerOptions(environment); - - ASSERT_EQ(::mongo::sslGlobalParams.disableNonSSLConnectionLogging, true); -} - -TEST(SetupOptions, disableNonTLSConnectionLoggingInvalid) { - OptionsParserTester parser; - moe::Environment environment; - moe::OptionSection options; - - ASSERT_OK(::mongo::addGeneralServerOptions(&options)); - - std::vector<std::string> argv; - argv.push_back("binaryname"); - argv.push_back("--setParameter"); - argv.push_back("disableNonTLSConnectionLogging=false"); - argv.push_back("--setParameter"); - argv.push_back("disableNonSSLConnectionLogging=false"); - std::map<std::string, std::string> env_map; - - ASSERT_OK(parser.run(options, argv, env_map, &environment)); - ASSERT_NOT_OK(mongo::storeServerOptions(environment)); -} -#endif - #if !defined(_WIN32) && !(defined(__APPLE__) && TARGET_OS_TV) #define ASSERT_BOOST_SUCCESS(ec) ASSERT_FALSE(ec) << ec.message() diff --git a/src/mongo/s/mongos_options.cpp b/src/mongo/s/mongos_options.cpp index 32dccbf6f4c..ce112e8275f 100644 --- a/src/mongo/s/mongos_options.cpp +++ b/src/mongo/s/mongos_options.cpp @@ -46,7 +46,6 @@ #include "mongo/util/log.h" #include "mongo/util/mongoutils/str.h" #include "mongo/util/net/socket_utils.h" -#include "mongo/util/net/ssl_options.h" #include "mongo/util/options_parser/startup_options.h" #include "mongo/util/startup_test.h" #include "mongo/util/stringutils.h" @@ -72,15 +71,6 @@ Status addMongosOptions(moe::OptionSection* options) { } #endif -#ifdef MONGO_CONFIG_SSL - moe::OptionSection ssl_options("SSL options"); - - ret = addSSLServerOptions(&ssl_options); - if (!ret.isOK()) { - return ret; - } -#endif - moe::OptionSection sharding_options("Sharding options"); sharding_options.addOptionChaining("sharding.configDB", @@ -127,10 +117,6 @@ Status addMongosOptions(moe::OptionSection* options) { options->addSection(sharding_options).transitional_ignore(); -#ifdef MONGO_CONFIG_SSL - options->addSection(ssl_options).transitional_ignore(); -#endif - return Status::OK(); } @@ -173,13 +159,6 @@ Status canonicalizeMongosOptions(moe::Environment* params) { return ret; } -#ifdef MONGO_CONFIG_SSL - ret = canonicalizeSSLServerOptions(params); - if (!ret.isOK()) { - return ret; - } -#endif - return Status::OK(); } diff --git a/src/mongo/shell/shell_options.cpp b/src/mongo/shell/shell_options.cpp index 9fdab05d541..311d7a22a0d 100644 --- a/src/mongo/shell/shell_options.cpp +++ b/src/mongo/shell/shell_options.cpp @@ -48,7 +48,6 @@ #include "mongo/util/log.h" #include "mongo/util/mongoutils/str.h" #include "mongo/util/net/socket_utils.h" -#include "mongo/util/net/ssl_options.h" #include "mongo/util/options_parser/startup_options.h" #include "mongo/util/version.h" @@ -163,14 +162,6 @@ Status addMongoShellOptions(moe::OptionSection* options) { "allow automatic JavaScript function marshalling") .incompatibleWith("enableJavaScriptProtection"); - Status ret = Status::OK(); -#ifdef MONGO_CONFIG_SSL - ret = addSSLClientOptions(options); - if (!ret.isOK()) { - return ret; - } -#endif - options ->addOptionChaining("enableJavaScriptProtection", "enableJavaScriptProtection", @@ -228,9 +219,10 @@ Status addMongoShellOptions(moe::OptionSection* options) { "rpcProtocols", "rpcProtocols", moe::String, " none, opQueryOnly, opCommandOnly, all") .hidden(); - ret = addMessageCompressionOptions(options, true); - if (!ret.isOK()) + auto ret = addMessageCompressionOptions(options, true); + if (!ret.isOK()) { return ret; + } options->addOptionChaining( "jsHeapLimitMB", "jsHeapLimitMB", moe::Int, "set the js scope's heap size limit"); @@ -270,20 +262,15 @@ bool handlePreValidationMongoShellOptions(const moe::Environment& params, Status storeMongoShellOptions(const moe::Environment& params, const std::vector<std::string>& args) { - Status ret = Status::OK(); if (params.count("quiet")) { mongo::serverGlobalParams.quiet.store(true); } -#ifdef MONGO_CONFIG_SSL - ret = storeSSLClientOptions(params); - if (!ret.isOK()) { - return ret; - } -#endif + if (params.count("ipv6")) { mongo::enableIPv6(); shellGlobalParams.enableIPv6 = true; } + if (params.count("verbose")) { logger::globalLogDomain()->setMinimumLoggedSeverity(logger::LogSeverity::Debug(1)); } @@ -476,7 +463,7 @@ Status storeMongoShellOptions(const moe::Environment& params, return Status(ErrorCodes::InvalidOptions, sb.str()); } - ret = storeMessageCompressionOptions(params); + auto ret = storeMessageCompressionOptions(params); if (!ret.isOK()) return ret; diff --git a/src/mongo/util/net/SConscript b/src/mongo/util/net/SConscript index 15fcccca15c..ef110ccf555 100644 --- a/src/mongo/util/net/SConscript +++ b/src/mongo/util/net/SConscript @@ -42,6 +42,35 @@ env.Library( ) env.Library( + target='ssl_options_client', + source=[ + 'ssl_options_client.cpp', + ], + LIBDEPS=[ + '$BUILD_DIR/mongo/base', + 'ssl_options', + ], + LIBDEPS_PRIVATE=[ + '$BUILD_DIR/mongo/util/options_parser/options_parser', + ] +) + +env.Library( + target='ssl_options_server', + source=[ + 'ssl_options_server.cpp', + ], + LIBDEPS=[ + '$BUILD_DIR/mongo/base', + 'ssl_options', + ], + LIBDEPS_PRIVATE=[ + '$BUILD_DIR/mongo/db/server_options_core', + '$BUILD_DIR/mongo/util/options_parser/options_parser', + ] +) + +env.Library( target='socket', source=[ "private/socket_poll.cpp", @@ -131,17 +160,20 @@ env.CppUnitTest( ], ) -env.CppUnitTest( - target='ssl_manager_test', - source=[ - 'ssl_manager_test.cpp', - 'ssl_options_test.cpp', - 'sock_test.cpp', - ], - LIBDEPS=[ - '$BUILD_DIR/mongo/util/fail_point', - 'network', - 'socket', - 'ssl_manager', - ], -) +if has_option('ssl'): + env.CppUnitTest( + target='ssl_manager_test', + source=[ + 'ssl_manager_test.cpp', + 'ssl_options_test.cpp', + 'sock_test.cpp', + ], + LIBDEPS=[ + '$BUILD_DIR/mongo/util/fail_point', + 'network', + '$BUILD_DIR/mongo/db/server_options_servers', + 'socket', + 'ssl_manager', + 'ssl_options_server', + ], + ) diff --git a/src/mongo/util/net/ssl_options.cpp b/src/mongo/util/net/ssl_options.cpp index 5c33666362c..22c2744bf79 100644 --- a/src/mongo/util/net/ssl_options.cpp +++ b/src/mongo/util/net/ssl_options.cpp @@ -50,6 +50,8 @@ namespace mongo { namespace moe = mongo::optionenvironment; using std::string; +SSLParams sslGlobalParams; + namespace { StatusWith<std::vector<uint8_t>> hexToVector(StringData hex) { if (std::any_of(hex.begin(), hex.end(), [](char c) { return !isxdigit(c); })) { @@ -68,20 +70,10 @@ StatusWith<std::vector<uint8_t>> hexToVector(StringData hex) { }); return ret; } +} // namespace -/** - * Older versions of mongod/mongos accepted --sslDisabledProtocols values - * in the form 'noTLS1_0,noTLS1_1'. kAcceptNegativePrefix allows us to - * continue accepting this format on mongod/mongos while only supporting - * the "standard" TLS1_X format in the shell. - */ -enum DisabledProtocolsMode { - kStandardFormat, - kAcceptNegativePrefix, -}; - -Status storeDisabledProtocols(const std::string& disabledProtocols, - DisabledProtocolsMode mode = kStandardFormat) { +Status storeSSLDisabledProtocols(const std::string& disabledProtocols, + SSLDisabledProtocolsMode mode /* =kStandardFormat */) { if (disabledProtocols == "none") { // Allow overriding the default behavior below of implicitly disabling TLS 1.0. return Status::OK(); @@ -113,7 +105,7 @@ Status storeDisabledProtocols(const std::string& disabledProtocols, continue; } - if (mode == DisabledProtocolsMode::kAcceptNegativePrefix) { + if (mode == SSLDisabledProtocolsMode::kAcceptNegativePrefix) { auto mappedNoToken = validNoConfigs.find(token); if (mappedNoToken != validNoConfigs.end()) { sslGlobalParams.sslDisabledProtocols.push_back(mappedNoToken->second); @@ -126,9 +118,6 @@ Status storeDisabledProtocols(const std::string& disabledProtocols, return Status::OK(); } -} // nameapace - -SSLParams sslGlobalParams; Status parseCertificateSelector(SSLParams::CertificateSelector* selector, StringData name, @@ -168,553 +157,4 @@ Status parseCertificateSelector(SSLParams::CertificateSelector* selector, return Status::OK(); } -Status addSSLServerOptions(moe::OptionSection* options) { - options - ->addOptionChaining("net.tls.tlsOnNormalPorts", - "tlsOnNormalPorts", - moe::Switch, - "Use TLS on configured ports", - {"net.ssl.sslOnNormalPorts"}, - {"sslOnNormalPorts"}) - .setSources(moe::SourceAllLegacy) - .incompatibleWith("net.tls.mode") - .incompatibleWith("net.ssl.mode"); - - options - ->addOptionChaining("net.tls.mode", - "tlsMode", - moe::String, - "Set the TLS operation mode (disabled|allowTLS|preferTLS|requireTLS)") - .incompatibleWith("net.ssl.mode"); - options - ->addOptionChaining("net.ssl.mode", - "sslMode", - moe::String, - "Set the TLS operation mode (disabled|allowSSL|preferSSL|requireSSL)") - .incompatibleWith("net.tls.mode"); - - options->addOptionChaining("net.tls.PEMKeyFile", - "tlsPEMKeyFile", - moe::String, - "PEM file for TLS", - {"net.ssl.PEMKeyFile"}, - {"sslPEMKeyFile"}); - - options - ->addOptionChaining("net.tls.PEMKeyPassword", - "tlsPEMKeyPassword", - moe::String, - "PEM file password", - {"net.ssl.PEMKeyPassword"}, - {"sslPEMKeyPassword"}) - .setImplicit(moe::Value(std::string(""))); - - options->addOptionChaining("net.tls.clusterFile", - "tlsClusterFile", - moe::String, - "Key file for internal TLS authentication", - {"net.ssl.clusterFile"}, - {"sslClusterFile"}); - - options - ->addOptionChaining("net.tls.clusterPassword", - "tlsClusterPassword", - moe::String, - "Internal authentication key file password", - {"net.ssl.clusterPassword"}, - {"sslClusterPassword"}) - .setImplicit(moe::Value(std::string(""))); - - options->addOptionChaining("net.tls.CAFile", - "tlsCAFile", - moe::String, - "Certificate Authority file for TLS", - {"net.ssl.CAFile"}, - {"sslCAFile"}); - - options->addOptionChaining("net.tls.CRLFile", - "tlsCRLFile", - moe::String, - "Certificate Revocation List file for TLS", - {"net.ssl.CRLFile"}, - {"sslCRLFile"}); - - options - ->addOptionChaining("net.tls.tlsCipherConfig", - "tlsCipherConfig", - moe::String, - "OpenSSL cipher configuration string", - {"net.ssl.sslCipherConfig"}, - {"sslCipherConfig"}) - .hidden(); - - options->addOptionChaining( - "net.tls.disabledProtocols", - "tlsDisabledProtocols", - moe::String, - "Comma separated list of TLS protocols to disable [TLS1_0,TLS1_1,TLS1_2]", - {"net.ssl.disabledProtocols"}, - {"sslDisabledProtocols"}); - - options->addOptionChaining("net.tls.weakCertificateValidation", - "tlsWeakCertificateValidation", - moe::Switch, - "Allow client to connect without presenting a certificate", - {"net.ssl.weakCertificateValidation"}, - {"sslWeakCertificateValidation"}); - - // Alias for --tlsWeakCertificateValidation. - options->addOptionChaining("net.tls.allowConnectionsWithoutCertificates", - "tlsAllowConnectionsWithoutCertificates", - moe::Switch, - "Allow client to connect without presenting a certificate", - {"net.ssl.allowConnectionsWithoutCertificates"}, - {"sslAllowConnectionsWithoutCertificates"}); - - options->addOptionChaining("net.tls.allowInvalidHostnames", - "tlsAllowInvalidHostnames", - moe::Switch, - "Allow server certificates to provide non-matching hostnames", - {"net.ssl.allowInvalidHostnames"}, - {"sslAllowInvalidHostnames"}); - - options->addOptionChaining("net.tls.allowInvalidCertificates", - "tlsAllowInvalidCertificates", - moe::Switch, - "Allow connections to servers with invalid certificates", - {"net.ssl.allowInvalidCertificates"}, - {"sslAllowInvalidCertificates"}); - - options->addOptionChaining("net.tls.FIPSMode", - "tlsFIPSMode", - moe::Switch, - "Activate FIPS 140-2 mode at startup", - {"net.ssl.FIPSMode"}, - {"sslFIPSMode"}); - -#ifdef MONGO_CONFIG_SSL_CERTIFICATE_SELECTORS - options - ->addOptionChaining("net.tls.certificateSelector", - "tlsCertificateSelector", - moe::String, - "TLS Certificate in system store", - {"net.ssl.certificateSelector"}, - {"sslCertificateSelector"}) - .incompatibleWith("net.tls.PEMKeyFile") - .incompatibleWith("net.tls.PEMKeyPassword"); - - options - ->addOptionChaining("net.tls.clusterCertificateSelector", - "tlsClusterCertificateSelector", - moe::String, - "SSL/TLS Certificate in system store for internal TLS authentication", - {"net.ssl.clusterCertificateSelector"}, - {"sslClusterCertificateSelector"}) - .incompatibleWith("net.tls.clusterFile") - .incompatibleWith("net.tls.clusterFilePassword"); -#endif - - return Status::OK(); -} - -Status addSSLClientOptions(moe::OptionSection* options) { - options->addOptionChaining( - "tls", "tls", moe::Switch, "use TLS for all connections", {"ssl"}, {"ssl"}); - - options - ->addOptionChaining("tls.CAFile", - "tlsCAFile", - moe::String, - "Certificate Authority file for TLS", - {"ssl.CAFile"}, - {"sslCAFile"}) - .requires("tls"); - - options - ->addOptionChaining("tls.PEMKeyFile", - "tlsPEMKeyFile", - moe::String, - "PEM certificate/key file for TLS", - {"ssl.PEMKeyFile"}, - {"sslPEMKeyFile"}) - .requires("tls"); - - options - ->addOptionChaining("tls.PEMKeyPassword", - "tlsPEMKeyPassword", - moe::String, - "Password for key in PEM file for TLS", - {"ssl.PEMKeyPassword"}, - {"sslPEMKeyPassword"}) - .requires("tls"); - - options - ->addOptionChaining("tls.CRLFile", - "tlsCRLFile", - moe::String, - "Certificate Revocation List file for TLS", - {"ssl.CRLFile"}, - {"sslCRLFile"}) - .requires("tls") - .requires("tls.CAFile"); - - options - ->addOptionChaining("net.tls.allowInvalidHostnames", - "tlsAllowInvalidHostnames", - moe::Switch, - "Allow connections to servers with non-matching hostnames", - {"net.ssl.allowInvalidHostnames"}, - {"sslAllowInvalidHostnames"}) - .requires("tls"); - - options - ->addOptionChaining("tls.allowInvalidCertificates", - "tlsAllowInvalidCertificates", - moe::Switch, - "Allow connections to servers with invalid certificates", - {"ssl.allowInvalidCertificates"}, - {"sslAllowInvalidCertificates"}) - .requires("tls"); - - options->addOptionChaining("tls.FIPSMode", - "tlsFIPSMode", - moe::Switch, - "Activate FIPS 140-2 mode at startup", - {"ssl.FIPSMode"}, - {"sslFIPSMode"}); - -#ifdef MONGO_CONFIG_SSL_CERTIFICATE_SELECTORS - options - ->addOptionChaining("tls.certificateSelector", - "tlsCertificateSelector", - moe::String, - "TLS Certificate in system store", - {"ssl.certificateSelector"}, - {"sslCertificateSelector"}) - .incompatibleWith("tls.PEMKeyFile") - .incompatibleWith("tls.PEMKeyPassword"); -#endif - - options->addOptionChaining( - "tls.disabledProtocols", - "tlsDisabledProtocols", - moe::String, - "Comma separated list of TLS protocols to disable [TLS1_0,TLS1_1,TLS1_2]", - {"ssl.disabledProtocols"}, - {"sslDisabledProtocols"}); - - return Status::OK(); -} - -Status validateSSLServerOptions(const moe::Environment& params) { -#ifdef _WIN32 - if (params.count("install") || params.count("reinstall")) { - if (params.count("net.tls.PEMKeyFile") && - !boost::filesystem::path(params["net.tls.PEMKeyFile"].as<string>()).is_absolute()) { - return Status(ErrorCodes::BadValue, - "PEMKeyFile requires an absolute file path with Windows services"); - } - - if (params.count("net.tls.clusterFile") && - !boost::filesystem::path(params["net.tls.clusterFile"].as<string>()).is_absolute()) { - return Status(ErrorCodes::BadValue, - "clusterFile requires an absolute file path with Windows services"); - } - - if (params.count("net.tls.CAFile") && - !boost::filesystem::path(params["net.tls.CAFile"].as<string>()).is_absolute()) { - return Status(ErrorCodes::BadValue, - "CAFile requires an absolute file path with Windows services"); - } - - if (params.count("net.tls.CRLFile") && - !boost::filesystem::path(params["net.tls.CRLFile"].as<string>()).is_absolute()) { - return Status(ErrorCodes::BadValue, - "CRLFile requires an absolute file path with Windows services"); - } - } -#endif - - return Status::OK(); -} - -Status canonicalizeSSLServerOptions(moe::Environment* params) { - if (params->count("net.tls.tlsOnNormalPorts") && - (*params)["net.tls.tlsOnNormalPorts"].as<bool>() == true) { - Status ret = params->set("net.tls.mode", moe::Value(std::string("requireTLS"))); - if (!ret.isOK()) { - return ret; - } - ret = params->remove("net.tls.tlsOnNormalPorts"); - if (!ret.isOK()) { - return ret; - } - } - - return Status::OK(); -} - -Status storeSSLServerOptions(const moe::Environment& params) { - if (params.count("net.tls.mode")) { - std::string sslModeParam = params["net.tls.mode"].as<string>(); - if (sslModeParam == "disabled") { - sslGlobalParams.sslMode.store(SSLParams::SSLMode_disabled); - } else if (sslModeParam == "allowTLS") { - sslGlobalParams.sslMode.store(SSLParams::SSLMode_allowSSL); - } else if (sslModeParam == "preferTLS") { - sslGlobalParams.sslMode.store(SSLParams::SSLMode_preferSSL); - } else if (sslModeParam == "requireTLS") { - sslGlobalParams.sslMode.store(SSLParams::SSLMode_requireSSL); - } else { - return Status(ErrorCodes::BadValue, "unsupported value for tlsMode " + sslModeParam); - } - } else if (params.count("net.ssl.mode")) { - std::string sslModeParam = params["net.ssl.mode"].as<string>(); - if (sslModeParam == "disabled") { - sslGlobalParams.sslMode.store(SSLParams::SSLMode_disabled); - } else if (sslModeParam == "allowSSL") { - sslGlobalParams.sslMode.store(SSLParams::SSLMode_allowSSL); - } else if (sslModeParam == "preferSSL") { - sslGlobalParams.sslMode.store(SSLParams::SSLMode_preferSSL); - } else if (sslModeParam == "requireSSL") { - sslGlobalParams.sslMode.store(SSLParams::SSLMode_requireSSL); - } else { - return Status(ErrorCodes::BadValue, "unsupported value for sslMode " + sslModeParam); - } - } - - if (params.count("net.tls.PEMKeyFile")) { - sslGlobalParams.sslPEMKeyFile = - boost::filesystem::absolute(params["net.tls.PEMKeyFile"].as<string>()).generic_string(); - } - - if (params.count("net.tls.PEMKeyPassword")) { - sslGlobalParams.sslPEMKeyPassword = params["net.tls.PEMKeyPassword"].as<string>(); - } - - if (params.count("net.tls.clusterFile")) { - sslGlobalParams.sslClusterFile = - boost::filesystem::absolute(params["net.tls.clusterFile"].as<string>()) - .generic_string(); - } - - if (params.count("net.tls.clusterPassword")) { - sslGlobalParams.sslClusterPassword = params["net.tls.clusterPassword"].as<string>(); - } - - if (params.count("net.tls.CAFile")) { - sslGlobalParams.sslCAFile = - boost::filesystem::absolute(params["net.tls.CAFile"].as<std::string>()) - .generic_string(); - } - - if (params.count("net.tls.CRLFile")) { - sslGlobalParams.sslCRLFile = - boost::filesystem::absolute(params["net.tls.CRLFile"].as<std::string>()) - .generic_string(); - } - - if (params.count("net.tls.tlsCipherConfig")) { - warning() - << "net.tls.tlsCipherConfig is deprecated. It will be removed in a future release."; - if (!sslGlobalParams.sslCipherConfig.empty()) { - return Status(ErrorCodes::BadValue, - "net.tls.tlsCipherConfig is incompatible with the openTLSCipherConfig " - "setParameter"); - } - sslGlobalParams.sslCipherConfig = params["net.tls.tlsCipherConfig"].as<string>(); - } - - if (params.count("net.tls.disabledProtocols")) { - const auto status = storeDisabledProtocols(params["net.tls.disabledProtocols"].as<string>(), - DisabledProtocolsMode::kAcceptNegativePrefix); - if (!status.isOK()) { - return status; - } -#if (MONGO_CONFIG_SSL_PROVIDER != MONGO_CONFIG_SSL_PROVIDER_OPENSSL) || \ - (OPENSSL_VERSION_NUMBER >= 0x100000cf) /* 1.0.0l */ - } else { - /* Disable TLS 1.0 by default on all platforms - * except on mongod/mongos which were built with an - * old version of OpenSSL (pre 1.0.0l) - * which does not support TLS 1.1 or later. - */ - log() << "Automatically disabling TLS 1.0, to force-enable TLS 1.0 " - "specify --sslDisabledProtocols 'none'"; - sslGlobalParams.sslDisabledProtocols.push_back(SSLParams::Protocols::TLS1_0); -#endif - } - - if (params.count("net.tls.weakCertificateValidation")) { - sslGlobalParams.sslWeakCertificateValidation = - params["net.tls.weakCertificateValidation"].as<bool>(); - } else if (params.count("net.tls.allowConnectionsWithoutCertificates")) { - sslGlobalParams.sslWeakCertificateValidation = - params["net.tls.allowConnectionsWithoutCertificates"].as<bool>(); - } - - if (params.count("net.tls.allowInvalidHostnames")) { - sslGlobalParams.sslAllowInvalidHostnames = - params["net.tls.allowInvalidHostnames"].as<bool>(); - } - - if (params.count("net.tls.allowInvalidCertificates")) { - sslGlobalParams.sslAllowInvalidCertificates = - params["net.tls.allowInvalidCertificates"].as<bool>(); - } - - if (params.count("net.tls.FIPSMode")) { - sslGlobalParams.sslFIPSMode = params["net.tls.FIPSMode"].as<bool>(); - } - -#ifdef MONGO_CONFIG_SSL_CERTIFICATE_SELECTORS - if (params.count("net.tls.certificateSelector")) { - const auto status = - parseCertificateSelector(&sslGlobalParams.sslCertificateSelector, - "net.tls.certificateSelector", - params["net.tls.certificateSelector"].as<std::string>()); - if (!status.isOK()) { - return status; - } - } - - if (params.count("net.tls.clusterCertificateSelector")) { - const auto status = parseCertificateSelector( - &sslGlobalParams.sslClusterCertificateSelector, - "net.tls.clusterCertificateSelector", - params["net.tls.clusterCertificateSelector"].as<std::string>()); - if (!status.isOK()) { - return status; - } - } -#endif - - int clusterAuthMode = serverGlobalParams.clusterAuthMode.load(); - auto a = sslGlobalParams.sslMode.load(); - auto b = sslGlobalParams.sslMode.load(); - if (a == b) { - } - if (sslGlobalParams.sslMode.load() != SSLParams::SSLMode_disabled) { - bool usingCertifiateSelectors = params.count("net.tls.certificateSelector"); - if (sslGlobalParams.sslPEMKeyFile.size() == 0 && !usingCertifiateSelectors) { - return Status(ErrorCodes::BadValue, - "need tlsPEMKeyFile or certificateSelector when TLS is enabled"); - } - if (!sslGlobalParams.sslCRLFile.empty() && sslGlobalParams.sslCAFile.empty()) { - return Status(ErrorCodes::BadValue, "need tlsCAFile with tlsCRLFile"); - } - - std::string sslCANotFoundError( - "No TLS certificate validation can be performed since" - " no CA file has been provided; please specify an" - " tlsCAFile parameter"); - - // When using cetificate selectors, we use the local system certificate store for verifying - // X.509 certificates for auth instead of relying on a CA file. - if (sslGlobalParams.sslCAFile.empty() && !usingCertifiateSelectors && - clusterAuthMode == ServerGlobalParams::ClusterAuthMode_x509) { - return Status(ErrorCodes::BadValue, sslCANotFoundError); - } - } else if (sslGlobalParams.sslPEMKeyFile.size() || sslGlobalParams.sslPEMKeyPassword.size() || - sslGlobalParams.sslClusterFile.size() || sslGlobalParams.sslClusterPassword.size() || - sslGlobalParams.sslCAFile.size() || sslGlobalParams.sslCRLFile.size() || - sslGlobalParams.sslCipherConfig.size() || - params.count("net.tls.disabledProtocols") || -#ifdef MONGO_CONFIG_SSL_CERTIFICATE_SELECTORS - params.count("net.tls.certificateSelector") || - params.count("net.tls.clusterCertificateSelector") || -#endif - sslGlobalParams.sslWeakCertificateValidation) { - return Status(ErrorCodes::BadValue, - "need to enable TLS via the sslMode/tlsMode flag when " - "using TLS configuration parameters"); - } - if (clusterAuthMode == ServerGlobalParams::ClusterAuthMode_sendKeyFile || - clusterAuthMode == ServerGlobalParams::ClusterAuthMode_sendX509 || - clusterAuthMode == ServerGlobalParams::ClusterAuthMode_x509) { - if (sslGlobalParams.sslMode.load() == SSLParams::SSLMode_disabled) { - return Status(ErrorCodes::BadValue, "need to enable TLS via the tlsMode flag"); - } - } - if (sslGlobalParams.sslMode.load() == SSLParams::SSLMode_allowSSL) { - // allowSSL and x509 is valid only when we are transitioning to auth. - if (clusterAuthMode == ServerGlobalParams::ClusterAuthMode_sendX509 || - (clusterAuthMode == ServerGlobalParams::ClusterAuthMode_x509 && - !serverGlobalParams.transitionToAuth)) { - return Status(ErrorCodes::BadValue, - "cannot have x.509 cluster authentication in allowTLS mode"); - } - } - return Status::OK(); -} - -Status storeSSLClientOptions(const moe::Environment& params) { - if (params.count("tls") && params["tls"].as<bool>() == true) { - sslGlobalParams.sslMode.store(SSLParams::SSLMode_requireSSL); - } - - if (params.count("tls.PEMKeyFile")) { - sslGlobalParams.sslPEMKeyFile = params["tls.PEMKeyFile"].as<std::string>(); - } - - if (params.count("tls.PEMKeyPassword")) { - sslGlobalParams.sslPEMKeyPassword = params["tls.PEMKeyPassword"].as<std::string>(); - } - - if (params.count("tls.CAFile")) { - sslGlobalParams.sslCAFile = params["tls.CAFile"].as<std::string>(); - } - - if (params.count("tls.CRLFile")) { - sslGlobalParams.sslCRLFile = params["tls.CRLFile"].as<std::string>(); - } - - - if (params.count("net.tls.allowInvalidHostnames")) { - sslGlobalParams.sslAllowInvalidHostnames = - params["net.tls.allowInvalidHostnames"].as<bool>(); - } - - if (params.count("tls.allowInvalidCertificates")) { - sslGlobalParams.sslAllowInvalidCertificates = true; - } - - if (params.count("tls.FIPSMode")) { - sslGlobalParams.sslFIPSMode = true; - } - - if (params.count("tls.disabledProtocols")) { - const auto status = - storeDisabledProtocols(params["tls.disabledProtocols"].as<std::string>()); - if (!status.isOK()) { - return status; - } -#if ((MONGO_CONFIG_SSL_PROVIDER != MONGO_CONFIG_SSL_PROVIDER_OPENSSL) || \ - (OPENSSL_VERSION_NUMBER >= 0x100000cf)) /* 1.0.0l */ - } else { - /* Similar to the server setting above, we auto-disable TLS 1.0 - * for shell clients which support TLS 1.1 and later. - * Unlike above, we don't have a blanket exception for Apple, - * since the reason for supporting external tooling does not apply. - * - * We also skip logging to keep the spam away from the interactive client op. - */ - sslGlobalParams.sslDisabledProtocols.push_back(SSLParams::Protocols::TLS1_0); -#endif - } - -#ifdef MONGO_CONFIG_SSL_CERTIFICATE_SELECTORS - if (params.count("tls.certificateSelector")) { - const auto status = - parseCertificateSelector(&sslGlobalParams.sslCertificateSelector, - "tls.certificateSelector", - params["tls.certificateSelector"].as<std::string>()); - if (!status.isOK()) { - return status; - } - } -#endif - return Status::OK(); -} - } // namespace mongo diff --git a/src/mongo/util/net/ssl_options.h b/src/mongo/util/net/ssl_options.h index e7ba7656fe4..724a272c952 100644 --- a/src/mongo/util/net/ssl_options.h +++ b/src/mongo/util/net/ssl_options.h @@ -111,28 +111,29 @@ struct SSLParams { extern SSLParams sslGlobalParams; /** + * Older versions of mongod/mongos accepted --sslDisabledProtocols values + * in the form 'noTLS1_0,noTLS1_1'. kAcceptNegativePrefix allows us to + * continue accepting this format on mongod/mongos while only supporting + * the "standard" TLS1_X format in the shell. + */ +enum class SSLDisabledProtocolsMode { + kStandardFormat, + kAcceptNegativePrefix, +}; + +Status storeSSLDisabledProtocols( + const std::string& disabledProtocols, + SSLDisabledProtocolsMode mode = SSLDisabledProtocolsMode::kStandardFormat); + +/** * The global SSL configuration. This should be accessed only after global initialization has * completed. If it must be accessed in an initializer, the initializer should have * "EndStartupOptionStorage" as a prerequisite. */ const SSLParams& getSSLGlobalParams(); -Status addSSLServerOptions(mongo::optionenvironment::OptionSection* options); - -Status addSSLClientOptions(mongo::optionenvironment::OptionSection* options); - -Status storeSSLServerOptions(const mongo::optionenvironment::Environment& params); - Status parseCertificateSelector(SSLParams::CertificateSelector* selector, StringData name, StringData value); -/** - * Canonicalize SSL options for the given environment that have different representations with - * the same logical meaning. - */ -Status canonicalizeSSLServerOptions(mongo::optionenvironment::Environment* params); - -Status validateSSLServerOptions(const mongo::optionenvironment::Environment& params); -Status storeSSLClientOptions(const mongo::optionenvironment::Environment& params); } // namespace mongo diff --git a/src/mongo/util/net/ssl_options_client.cpp b/src/mongo/util/net/ssl_options_client.cpp new file mode 100644 index 00000000000..f69a57937be --- /dev/null +++ b/src/mongo/util/net/ssl_options_client.cpp @@ -0,0 +1,212 @@ +/** + * Copyright (C) 2018 MongoDB Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * As a special exception, the copyright holders give permission to link the + * code of portions of this program with the OpenSSL library under certain + * conditions as described in each individual source file and distribute + * linked combinations including the program with the OpenSSL library. You + * must comply with the GNU Affero General Public License in all respects + * for all of the code used other than as permitted herein. If you modify + * file(s) with this exception, you may extend this exception to your + * version of the file(s), but you are not obligated to do so. If you do not + * wish to do so, delete this exception statement from your version. If you + * delete this exception statement from all source files in the program, + * then also delete it in the license file. + */ + +#include "mongo/platform/basic.h" + +#include "mongo/util/net/ssl_options.h" + +#include <boost/filesystem/operations.hpp> + +#include "mongo/base/status.h" +#include "mongo/config.h" +#include "mongo/util/options_parser/startup_option_init.h" +#include "mongo/util/options_parser/startup_options.h" + +#if MONGO_CONFIG_SSL_PROVIDER == MONGO_CONFIG_SSL_PROVIDER_OPENSSL +#include <openssl/ssl.h> +#endif + +using namespace mongo; +namespace moe = mongo::optionenvironment; +using std::string; + +namespace { +MONGO_GENERAL_STARTUP_OPTIONS_REGISTER(SSLClientOptions)(InitializerContext*) { + auto& options = moe::startupOptions; + + options.addOptionChaining( + "tls", "tls", moe::Switch, "use TLS for all connections", {"ssl"}, {"ssl"}); + + options + .addOptionChaining("tls.CAFile", + "tlsCAFile", + moe::String, + "Certificate Authority file for TLS", + {"ssl.CAFile"}, + {"sslCAFile"}) + .requires("tls"); + + options + .addOptionChaining("tls.PEMKeyFile", + "tlsPEMKeyFile", + moe::String, + "PEM certificate/key file for TLS", + {"ssl.PEMKeyFile"}, + {"sslPEMKeyFile"}) + .requires("tls"); + + options + .addOptionChaining("tls.PEMKeyPassword", + "tlsPEMKeyPassword", + moe::String, + "Password for key in PEM file for TLS", + {"ssl.PEMKeyPassword"}, + {"sslPEMKeyPassword"}) + .requires("tls"); + + options + .addOptionChaining("tls.CRLFile", + "tlsCRLFile", + moe::String, + "Certificate Revocation List file for TLS", + {"ssl.CRLFile"}, + {"sslCRLFile"}) + .requires("tls") + .requires("tls.CAFile"); + + options + .addOptionChaining("net.tls.allowInvalidHostnames", + "tlsAllowInvalidHostnames", + moe::Switch, + "Allow connections to servers with non-matching hostnames", + {"net.ssl.allowInvalidHostnames"}, + {"sslAllowInvalidHostnames"}) + .requires("tls"); + + options + .addOptionChaining("tls.allowInvalidCertificates", + "tlsAllowInvalidCertificates", + moe::Switch, + "Allow connections to servers with invalid certificates", + {"ssl.allowInvalidCertificates"}, + {"sslAllowInvalidCertificates"}) + .requires("tls"); + + options.addOptionChaining("tls.FIPSMode", + "tlsFIPSMode", + moe::Switch, + "Activate FIPS 140-2 mode at startup", + {"ssl.FIPSMode"}, + {"sslFIPSMode"}); + +#ifdef MONGO_CONFIG_SSL_CERTIFICATE_SELECTORS + options + .addOptionChaining("tls.certificateSelector", + "tlsCertificateSelector", + moe::String, + "TLS Certificate in system store", + {"ssl.certificateSelector"}, + {"sslCertificateSelector"}) + .incompatibleWith("tls.PEMKeyFile") + .incompatibleWith("tls.PEMKeyPassword"); +#endif + + options.addOptionChaining( + "tls.disabledProtocols", + "tlsDisabledProtocols", + moe::String, + "Comma separated list of TLS protocols to disable [TLS1_0,TLS1_1,TLS1_2]", + {"ssl.disabledProtocols"}, + {"sslDisabledProtocols"}); + + return Status::OK(); +} + +MONGO_STARTUP_OPTIONS_STORE(SSLClientOptions)(InitializerContext*) { + const auto& params = moe::startupOptionsParsed; + + if (params.count("tls") && params["tls"].as<bool>() == true) { + sslGlobalParams.sslMode.store(SSLParams::SSLMode_requireSSL); + } + + if (params.count("tls.PEMKeyFile")) { + sslGlobalParams.sslPEMKeyFile = params["tls.PEMKeyFile"].as<std::string>(); + } + + if (params.count("tls.PEMKeyPassword")) { + sslGlobalParams.sslPEMKeyPassword = params["tls.PEMKeyPassword"].as<std::string>(); + } + + if (params.count("tls.CAFile")) { + sslGlobalParams.sslCAFile = params["tls.CAFile"].as<std::string>(); + } + + if (params.count("tls.CRLFile")) { + sslGlobalParams.sslCRLFile = params["tls.CRLFile"].as<std::string>(); + } + + + if (params.count("net.tls.allowInvalidHostnames")) { + sslGlobalParams.sslAllowInvalidHostnames = + params["net.tls.allowInvalidHostnames"].as<bool>(); + } + + if (params.count("tls.allowInvalidCertificates")) { + sslGlobalParams.sslAllowInvalidCertificates = true; + } + + if (params.count("tls.FIPSMode")) { + sslGlobalParams.sslFIPSMode = true; + } + + if (params.count("tls.disabledProtocols")) { + const auto status = + storeSSLDisabledProtocols(params["tls.disabledProtocols"].as<std::string>()); + if (!status.isOK()) { + return status; + } +#if ((MONGO_CONFIG_SSL_PROVIDER != MONGO_CONFIG_SSL_PROVIDER_OPENSSL) || \ + (OPENSSL_VERSION_NUMBER >= 0x100000cf)) /* 1.0.0l */ + } else { + /* Similar to the server setting above, we auto-disable TLS 1.0 + * for shell clients which support TLS 1.1 and later. + * Unlike above, we don't have a blanket exception for Apple, + * since the reason for supporting external tooling does not apply. + * + * We also skip logging to keep the spam away from the interactive client op. + */ + sslGlobalParams.sslDisabledProtocols.push_back(SSLParams::Protocols::TLS1_0); +#endif + } + +#ifdef MONGO_CONFIG_SSL_CERTIFICATE_SELECTORS + if (params.count("tls.certificateSelector")) { + const auto status = + parseCertificateSelector(&sslGlobalParams.sslCertificateSelector, + "tls.certificateSelector", + params["tls.certificateSelector"].as<std::string>()); + if (!status.isOK()) { + return status; + } + } +#endif + + return Status::OK(); +} + +} // namespace diff --git a/src/mongo/util/net/ssl_options_server.cpp b/src/mongo/util/net/ssl_options_server.cpp new file mode 100644 index 00000000000..930eccaf2c4 --- /dev/null +++ b/src/mongo/util/net/ssl_options_server.cpp @@ -0,0 +1,473 @@ +/** + * Copyright (C) 2018 MongoDB Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * As a special exception, the copyright holders give permission to link the + * code of portions of this program with the OpenSSL library under certain + * conditions as described in each individual source file and distribute + * linked combinations including the program with the OpenSSL library. You + * must comply with the GNU Affero General Public License in all respects + * for all of the code used other than as permitted herein. If you modify + * file(s) with this exception, you may extend this exception to your + * version of the file(s), but you are not obligated to do so. If you do not + * wish to do so, delete this exception statement from your version. If you + * delete this exception statement from all source files in the program, + * then also delete it in the license file. + */ + +#define MONGO_LOG_DEFAULT_COMPONENT ::mongo::logger::LogComponent::kControl + +#include "mongo/platform/basic.h" + +#include "mongo/util/net/ssl_options.h" + +#include <boost/filesystem/operations.hpp> + +#include "mongo/base/status.h" +#include "mongo/config.h" +#include "mongo/db/server_options.h" +#include "mongo/util/log.h" +#include "mongo/util/options_parser/startup_option_init.h" +#include "mongo/util/options_parser/startup_options.h" + +#if MONGO_CONFIG_SSL_PROVIDER == MONGO_CONFIG_SSL_PROVIDER_OPENSSL +#include <openssl/ssl.h> +#endif + +namespace moe = mongo::optionenvironment; +using std::string; + +// Export these to the process space for the sake of ssl_options_test.cpp +// but don't provide a header because we don't want to encourage use from elsewhere. +namespace mongo { +Status addSSLServerOptions(moe::OptionSection* options) { + options + ->addOptionChaining("net.tls.tlsOnNormalPorts", + "tlsOnNormalPorts", + moe::Switch, + "Use TLS on configured ports", + {"net.ssl.sslOnNormalPorts"}, + {"sslOnNormalPorts"}) + .setSources(moe::SourceAllLegacy) + .incompatibleWith("net.tls.mode") + .incompatibleWith("net.ssl.mode"); + + options + ->addOptionChaining("net.tls.mode", + "tlsMode", + moe::String, + "Set the TLS operation mode (disabled|allowTLS|preferTLS|requireTLS)") + .incompatibleWith("net.ssl.mode"); + options + ->addOptionChaining("net.ssl.mode", + "sslMode", + moe::String, + "Set the TLS operation mode (disabled|allowSSL|preferSSL|requireSSL)") + .incompatibleWith("net.tls.mode") + .hidden(); + + options->addOptionChaining("net.tls.PEMKeyFile", + "tlsPEMKeyFile", + moe::String, + "PEM file for TLS", + {"net.ssl.PEMKeyFile"}, + {"sslPEMKeyFile"}); + + options + ->addOptionChaining("net.tls.PEMKeyPassword", + "tlsPEMKeyPassword", + moe::String, + "PEM file password", + {"net.ssl.PEMKeyPassword"}, + {"sslPEMKeyPassword"}) + .setImplicit(moe::Value(std::string(""))); + + options->addOptionChaining("net.tls.clusterFile", + "tlsClusterFile", + moe::String, + "Key file for internal TLS authentication", + {"net.ssl.clusterFile"}, + {"sslClusterFile"}); + + options + ->addOptionChaining("net.tls.clusterPassword", + "tlsClusterPassword", + moe::String, + "Internal authentication key file password", + {"net.ssl.clusterPassword"}, + {"sslClusterPassword"}) + .setImplicit(moe::Value(std::string(""))); + + options->addOptionChaining("net.tls.CAFile", + "tlsCAFile", + moe::String, + "Certificate Authority file for TLS", + {"net.ssl.CAFile"}, + {"sslCAFile"}); + + options->addOptionChaining("net.tls.CRLFile", + "tlsCRLFile", + moe::String, + "Certificate Revocation List file for TLS", + {"net.ssl.CRLFile"}, + {"sslCRLFile"}); + + options + ->addOptionChaining("net.tls.tlsCipherConfig", + "tlsCipherConfig", + moe::String, + "OpenSSL cipher configuration string", + {"net.ssl.sslCipherConfig"}, + {"sslCipherConfig"}) + .hidden(); + + options->addOptionChaining( + "net.tls.disabledProtocols", + "tlsDisabledProtocols", + moe::String, + "Comma separated list of TLS protocols to disable [TLS1_0,TLS1_1,TLS1_2]", + {"net.ssl.disabledProtocols"}, + {"sslDisabledProtocols"}); + + options->addOptionChaining("net.tls.weakCertificateValidation", + "tlsWeakCertificateValidation", + moe::Switch, + "Allow client to connect without presenting a certificate", + {"net.ssl.weakCertificateValidation"}, + {"sslWeakCertificateValidation"}); + + // Alias for --tlsWeakCertificateValidation. + options->addOptionChaining("net.tls.allowConnectionsWithoutCertificates", + "tlsAllowConnectionsWithoutCertificates", + moe::Switch, + "Allow client to connect without presenting a certificate", + {"net.ssl.allowConnectionsWithoutCertificates"}, + {"sslAllowConnectionsWithoutCertificates"}); + + options->addOptionChaining("net.tls.allowInvalidHostnames", + "tlsAllowInvalidHostnames", + moe::Switch, + "Allow server certificates to provide non-matching hostnames", + {"net.ssl.allowInvalidHostnames"}, + {"sslAllowInvalidHostnames"}); + + options->addOptionChaining("net.tls.allowInvalidCertificates", + "tlsAllowInvalidCertificates", + moe::Switch, + "Allow connections to servers with invalid certificates", + {"net.ssl.allowInvalidCertificates"}, + {"sslAllowInvalidCertificates"}); + + options->addOptionChaining("net.tls.FIPSMode", + "tlsFIPSMode", + moe::Switch, + "Activate FIPS 140-2 mode at startup", + {"net.ssl.FIPSMode"}, + {"sslFIPSMode"}); + +#ifdef MONGO_CONFIG_SSL_CERTIFICATE_SELECTORS + options + ->addOptionChaining("net.tls.certificateSelector", + "tlsCertificateSelector", + moe::String, + "TLS Certificate in system store", + {"net.ssl.certificateSelector"}, + {"sslCertificateSelector"}) + .incompatibleWith("net.tls.PEMKeyFile") + .incompatibleWith("net.tls.PEMKeyPassword"); + + options + ->addOptionChaining("net.tls.clusterCertificateSelector", + "tlsClusterCertificateSelector", + moe::String, + "SSL/TLS Certificate in system store for internal TLS authentication", + {"net.ssl.clusterCertificateSelector"}, + {"sslClusterCertificateSelector"}) + .incompatibleWith("net.tls.clusterFile") + .incompatibleWith("net.tls.clusterFilePassword"); +#endif + + return Status::OK(); +} + +Status storeSSLServerOptions(const moe::Environment& params) { + if (params.count("net.tls.mode")) { + std::string sslModeParam = params["net.tls.mode"].as<string>(); + if (sslModeParam == "disabled") { + sslGlobalParams.sslMode.store(SSLParams::SSLMode_disabled); + } else if (sslModeParam == "allowTLS") { + sslGlobalParams.sslMode.store(SSLParams::SSLMode_allowSSL); + } else if (sslModeParam == "preferTLS") { + sslGlobalParams.sslMode.store(SSLParams::SSLMode_preferSSL); + } else if (sslModeParam == "requireTLS") { + sslGlobalParams.sslMode.store(SSLParams::SSLMode_requireSSL); + } else { + return {ErrorCodes::BadValue, "unsupported value for tlsMode " + sslModeParam}; + } + } else if (params.count("net.ssl.mode")) { + std::string sslModeParam = params["net.ssl.mode"].as<string>(); + if (sslModeParam == "disabled") { + sslGlobalParams.sslMode.store(SSLParams::SSLMode_disabled); + } else if (sslModeParam == "allowSSL") { + sslGlobalParams.sslMode.store(SSLParams::SSLMode_allowSSL); + } else if (sslModeParam == "preferSSL") { + sslGlobalParams.sslMode.store(SSLParams::SSLMode_preferSSL); + } else if (sslModeParam == "requireSSL") { + sslGlobalParams.sslMode.store(SSLParams::SSLMode_requireSSL); + } else { + return {ErrorCodes::BadValue, "unsupported value for sslMode " + sslModeParam}; + } + } + + if (params.count("net.tls.PEMKeyFile")) { + sslGlobalParams.sslPEMKeyFile = + boost::filesystem::absolute(params["net.tls.PEMKeyFile"].as<string>()).generic_string(); + } + + if (params.count("net.tls.PEMKeyPassword")) { + sslGlobalParams.sslPEMKeyPassword = params["net.tls.PEMKeyPassword"].as<string>(); + } + + if (params.count("net.tls.clusterFile")) { + sslGlobalParams.sslClusterFile = + boost::filesystem::absolute(params["net.tls.clusterFile"].as<string>()) + .generic_string(); + } + + if (params.count("net.tls.clusterPassword")) { + sslGlobalParams.sslClusterPassword = params["net.tls.clusterPassword"].as<string>(); + } + + if (params.count("net.tls.CAFile")) { + sslGlobalParams.sslCAFile = + boost::filesystem::absolute(params["net.tls.CAFile"].as<std::string>()) + .generic_string(); + } + + if (params.count("net.tls.CRLFile")) { + sslGlobalParams.sslCRLFile = + boost::filesystem::absolute(params["net.tls.CRLFile"].as<std::string>()) + .generic_string(); + } + + if (params.count("net.tls.tlsCipherConfig")) { + warning() + << "net.tls.tlsCipherConfig is deprecated. It will be removed in a future release."; + if (!sslGlobalParams.sslCipherConfig.empty()) { + return {ErrorCodes::BadValue, + "net.tls.tlsCipherConfig is incompatible with the openTLSCipherConfig " + "setParameter"}; + } + sslGlobalParams.sslCipherConfig = params["net.tls.tlsCipherConfig"].as<string>(); + } + + if (params.count("net.tls.disabledProtocols")) { + const auto status = + storeSSLDisabledProtocols(params["net.tls.disabledProtocols"].as<string>(), + SSLDisabledProtocolsMode::kAcceptNegativePrefix); + if (!status.isOK()) { + return status; + } +#if (MONGO_CONFIG_SSL_PROVIDER != MONGO_CONFIG_SSL_PROVIDER_OPENSSL) || \ + (OPENSSL_VERSION_NUMBER >= 0x100000cf) /* 1.0.0l */ + } else { + /* Disable TLS 1.0 by default on all platforms + * except on mongod/mongos which were built with an + * old version of OpenSSL (pre 1.0.0l) + * which does not support TLS 1.1 or later. + */ + log() << "Automatically disabling TLS 1.0, to force-enable TLS 1.0 " + "specify --sslDisabledProtocols 'none'"; + sslGlobalParams.sslDisabledProtocols.push_back(SSLParams::Protocols::TLS1_0); +#endif + } + + if (params.count("net.tls.weakCertificateValidation")) { + sslGlobalParams.sslWeakCertificateValidation = + params["net.tls.weakCertificateValidation"].as<bool>(); + } else if (params.count("net.tls.allowConnectionsWithoutCertificates")) { + sslGlobalParams.sslWeakCertificateValidation = + params["net.tls.allowConnectionsWithoutCertificates"].as<bool>(); + } + + if (params.count("net.tls.allowInvalidHostnames")) { + sslGlobalParams.sslAllowInvalidHostnames = + params["net.tls.allowInvalidHostnames"].as<bool>(); + } + + if (params.count("net.tls.allowInvalidCertificates")) { + sslGlobalParams.sslAllowInvalidCertificates = + params["net.tls.allowInvalidCertificates"].as<bool>(); + } + + if (params.count("net.tls.FIPSMode")) { + sslGlobalParams.sslFIPSMode = params["net.tls.FIPSMode"].as<bool>(); + } + +#ifdef MONGO_CONFIG_SSL_CERTIFICATE_SELECTORS + if (params.count("net.tls.certificateSelector")) { + const auto status = + parseCertificateSelector(&sslGlobalParams.sslCertificateSelector, + "net.tls.certificateSelector", + params["net.tls.certificateSelector"].as<std::string>()); + if (!status.isOK()) { + return status; + } + } + + if (params.count("net.tls.clusterCertificateSelector")) { + const auto status = parseCertificateSelector( + &sslGlobalParams.sslClusterCertificateSelector, + "net.tls.clusterCertificateSelector", + params["net.tls.clusterCertificateSelector"].as<std::string>()); + if (!status.isOK()) { + return status; + } + } +#endif + + const int clusterAuthMode = serverGlobalParams.clusterAuthMode.load(); + if (sslGlobalParams.sslMode.load() != SSLParams::SSLMode_disabled) { + bool usingCertifiateSelectors = params.count("net.tls.certificateSelector"); + if (sslGlobalParams.sslPEMKeyFile.size() == 0 && !usingCertifiateSelectors) { + return {ErrorCodes::BadValue, + "need tlsPEMKeyFile or certificateSelector when TLS is enabled"}; + } + if (!sslGlobalParams.sslCRLFile.empty() && sslGlobalParams.sslCAFile.empty()) { + return {ErrorCodes::BadValue, "need tlsCAFile with tlsCRLFile"}; + } + + std::string sslCANotFoundError( + "No TLS certificate validation can be performed since" + " no CA file has been provided; please specify an" + " tlsCAFile parameter"); + + // When using cetificate selectors, we use the local system certificate store for verifying + // X.509 certificates for auth instead of relying on a CA file. + if (sslGlobalParams.sslCAFile.empty() && !usingCertifiateSelectors && + clusterAuthMode == ServerGlobalParams::ClusterAuthMode_x509) { + return {ErrorCodes::BadValue, sslCANotFoundError}; + } + } else if (sslGlobalParams.sslPEMKeyFile.size() || sslGlobalParams.sslPEMKeyPassword.size() || + sslGlobalParams.sslClusterFile.size() || sslGlobalParams.sslClusterPassword.size() || + sslGlobalParams.sslCAFile.size() || sslGlobalParams.sslCRLFile.size() || + sslGlobalParams.sslCipherConfig.size() || + params.count("net.tls.disabledProtocols") || +#ifdef MONGO_CONFIG_SSL_CERTIFICATE_SELECTORS + params.count("net.tls.certificateSelector") || + params.count("net.tls.clusterCertificateSelector") || +#endif + sslGlobalParams.sslWeakCertificateValidation) { + return {ErrorCodes::BadValue, + "need to enable TLS via the sslMode/tlsMode flag when " + "using TLS configuration parameters"}; + } + + if (clusterAuthMode == ServerGlobalParams::ClusterAuthMode_sendKeyFile || + clusterAuthMode == ServerGlobalParams::ClusterAuthMode_sendX509 || + clusterAuthMode == ServerGlobalParams::ClusterAuthMode_x509) { + if (sslGlobalParams.sslMode.load() == SSLParams::SSLMode_disabled) { + return {ErrorCodes::BadValue, "need to enable TLS via the tlsMode flag"}; + } + } + + if (sslGlobalParams.sslMode.load() == SSLParams::SSLMode_allowSSL) { + // allowSSL and x509 is valid only when we are transitioning to auth. + if (clusterAuthMode == ServerGlobalParams::ClusterAuthMode_sendX509 || + (clusterAuthMode == ServerGlobalParams::ClusterAuthMode_x509 && + !serverGlobalParams.transitionToAuth)) { + return {ErrorCodes::BadValue, + "cannot have x.509 cluster authentication in allowTLS mode"}; + } + } + return Status::OK(); +} + +namespace { + +// Use module API to force this section to appear after core server options. +MONGO_MODULE_STARTUP_OPTIONS_REGISTER(SSLServerOptions)(InitializerContext*) { + moe::OptionSection options("SSL options"); + + auto status = addSSLServerOptions(&options); + if (!status.isOK()) { + return status; + } + + return moe::startupOptions.addSection(options); +} + +Status canonicalizeSSLServerOptions(moe::Environment* params) { + if (params->count("net.tls.tlsOnNormalPorts") && + (*params)["net.tls.tlsOnNormalPorts"].as<bool>() == true) { + Status ret = params->set("net.tls.mode", moe::Value(std::string("requireTLS"))); + if (!ret.isOK()) { + return ret; + } + ret = params->remove("net.tls.tlsOnNormalPorts"); + if (!ret.isOK()) { + return ret; + } + } + + return Status::OK(); +} + +MONGO_STARTUP_OPTIONS_VALIDATE(SSLServerOptions)(InitializerContext*) { + auto status = canonicalizeSSLServerOptions(&moe::startupOptionsParsed); + if (!status.isOK()) { + return status; + } + +#ifdef _WIN32 + const auto& params = moe::startupOptionsParsed; + + if (params.count("install") || params.count("reinstall")) { + if (params.count("net.tls.PEMKeyFile") && + !boost::filesystem::path(params["net.tls.PEMKeyFile"].as<string>()).is_absolute()) { + return {ErrorCodes::BadValue, + "PEMKeyFile requires an absolute file path with Windows services"}; + } + + if (params.count("net.tls.clusterFile") && + !boost::filesystem::path(params["net.tls.clusterFile"].as<string>()).is_absolute()) { + return {ErrorCodes::BadValue, + "clusterFile requires an absolute file path with Windows services"}; + } + + if (params.count("net.tls.CAFile") && + !boost::filesystem::path(params["net.tls.CAFile"].as<string>()).is_absolute()) { + return {ErrorCodes::BadValue, + "CAFile requires an absolute file path with Windows services"}; + } + + if (params.count("net.tls.CRLFile") && + !boost::filesystem::path(params["net.tls.CRLFile"].as<string>()).is_absolute()) { + return {ErrorCodes::BadValue, + "CRLFile requires an absolute file path with Windows services"}; + } + } +#endif + + return Status::OK(); +} + +// storeSSLServerOptions depends on serverGlobalParams.clusterAuthMode +// and therefore must run later. +MONGO_STARTUP_OPTIONS_POST(SSLServerOptions)(InitializerContext*) { + return storeSSLServerOptions(moe::startupOptionsParsed); +} + +} // namespace +} // namespace mongo diff --git a/src/mongo/util/net/ssl_options_test.cpp b/src/mongo/util/net/ssl_options_test.cpp index e9e3e51fdd6..048b6e5dc3d 100644 --- a/src/mongo/util/net/ssl_options_test.cpp +++ b/src/mongo/util/net/ssl_options_test.cpp @@ -28,13 +28,25 @@ #include "mongo/platform/basic.h" +#include "mongo/config.h" + #include "mongo/util/net/ssl_options.h" #include <ostream> +#include "mongo/db/server_options_server_helpers.h" #include "mongo/unittest/unittest.h" +#include "mongo/util/net/ssl_options.h" +#include "mongo/util/options_parser/environment.h" +#include "mongo/util/options_parser/option_section.h" +#include "mongo/util/options_parser/options_parser.h" + +namespace moe = mongo::optionenvironment; namespace mongo { +Status addSSLServerOptions(moe::OptionSection* options); +Status storeSSLServerOptions(const moe::Environment& params); + namespace { namespace test { @@ -81,5 +93,349 @@ TEST(SSLOptions, invalidCases) { "Invalid certificate selector value for 'option': Not a valid hex string"); } +class OptionsParserTester : public moe::OptionsParser { +public: + Status readConfigFile(const std::string& filename, std::string* config) { + if (filename != _filename) { + ::mongo::StringBuilder sb; + sb << "Parser using filename: " << filename + << " which does not match expected filename: " << _filename; + return Status(ErrorCodes::InternalError, sb.str()); + } + *config = _config; + return Status::OK(); + } + void setConfig(const std::string& filename, const std::string& config) { + _filename = filename; + _config = config; + } + +private: + std::string _filename; + std::string _config; +}; + +TEST(SetupOptions, tlsModeDisabled) { + OptionsParserTester parser; + moe::Environment environment; + moe::OptionSection options; + + ASSERT_OK(::mongo::addGeneralServerOptions(&options)); + + std::vector<std::string> argv; + argv.push_back("binaryname"); + argv.push_back("--tlsMode"); + argv.push_back("disabled"); + std::map<std::string, std::string> env_map; + + ASSERT_OK(::mongo::addSSLServerOptions(&options)); + + ASSERT_OK(parser.run(options, argv, env_map, &environment)); + ASSERT_OK(::mongo::storeSSLServerOptions(environment)); + ASSERT_EQ(::mongo::sslGlobalParams.sslMode.load(), ::mongo::sslGlobalParams.SSLMode_disabled); +} + +TEST(SetupOptions, sslModeDisabled) { + OptionsParserTester parser; + moe::Environment environment; + moe::OptionSection options; + + ASSERT_OK(::mongo::addGeneralServerOptions(&options)); + + std::vector<std::string> argv; + argv.push_back("binaryname"); + argv.push_back("--sslMode"); + argv.push_back("disabled"); + std::map<std::string, std::string> env_map; + + ASSERT_OK(::mongo::addSSLServerOptions(&options)); + + ASSERT_OK(parser.run(options, argv, env_map, &environment)); + ASSERT_OK(::mongo::storeSSLServerOptions(environment)); + ASSERT_EQ(::mongo::sslGlobalParams.sslMode.load(), ::mongo::sslGlobalParams.SSLMode_disabled); +} + +TEST(SetupOptions, tlsModeRequired) { + OptionsParserTester parser; + moe::Environment environment; + moe::OptionSection options; + + ASSERT_OK(::mongo::addGeneralServerOptions(&options)); + + std::string sslPEMKeyFile = "jstests/libs/server.pem"; + std::string sslCAFFile = "jstests/libs/ca.pem"; + std::string sslCRLFile = "jstests/libs/crl.pem"; + std::string sslClusterFile = "jstests/libs/cluster_cert.pem"; + + std::vector<std::string> argv; + argv.push_back("binaryname"); + argv.push_back("--tlsMode"); + argv.push_back("requireTLS"); + argv.push_back("--tlsPEMKeyFile"); + argv.push_back(sslPEMKeyFile); + argv.push_back("--tlsCAFile"); + argv.push_back(sslCAFFile); + argv.push_back("--tlsCRLFile"); + argv.push_back(sslCRLFile); + argv.push_back("--tlsClusterFile"); + argv.push_back(sslClusterFile); + argv.push_back("--tlsAllowInvalidHostnames"); + argv.push_back("--tlsAllowInvalidCertificates"); + argv.push_back("--tlsWeakCertificateValidation"); + argv.push_back("--tlsFIPSMode"); + argv.push_back("--tlsPEMKeyPassword"); + argv.push_back("pw1"); + argv.push_back("--tlsClusterPassword"); + argv.push_back("pw2"); + argv.push_back("--tlsDisabledProtocols"); + argv.push_back("TLS1_1"); + std::map<std::string, std::string> env_map; + + ASSERT_OK(mongo::addSSLServerOptions(&options)); + + ASSERT_OK(parser.run(options, argv, env_map, &environment)); + ASSERT_OK(mongo::storeSSLServerOptions(environment)); + + ASSERT_EQ(::mongo::sslGlobalParams.sslMode.load(), ::mongo::sslGlobalParams.SSLMode_requireSSL); + ASSERT_EQ(::mongo::sslGlobalParams.sslPEMKeyFile.substr( + ::mongo::sslGlobalParams.sslPEMKeyFile.length() - sslPEMKeyFile.length()), + sslPEMKeyFile); + ASSERT_EQ(::mongo::sslGlobalParams.sslCAFile.substr( + ::mongo::sslGlobalParams.sslCAFile.length() - sslCAFFile.length()), + sslCAFFile); + ASSERT_EQ(::mongo::sslGlobalParams.sslCRLFile.substr( + ::mongo::sslGlobalParams.sslCRLFile.length() - sslCRLFile.length()), + sslCRLFile); + ASSERT_EQ(::mongo::sslGlobalParams.sslClusterFile.substr( + ::mongo::sslGlobalParams.sslClusterFile.length() - sslClusterFile.length()), + sslClusterFile); + ASSERT_EQ(::mongo::sslGlobalParams.sslAllowInvalidHostnames, true); + ASSERT_EQ(::mongo::sslGlobalParams.sslAllowInvalidCertificates, true); + ASSERT_EQ(::mongo::sslGlobalParams.sslWeakCertificateValidation, true); + ASSERT_EQ(::mongo::sslGlobalParams.sslFIPSMode, true); + ASSERT_EQ(::mongo::sslGlobalParams.sslPEMKeyPassword, "pw1"); + ASSERT_EQ(::mongo::sslGlobalParams.sslClusterPassword, "pw2"); + ASSERT_EQ(static_cast<int>(::mongo::sslGlobalParams.sslDisabledProtocols.back()), + static_cast<int>(::mongo::SSLParams::Protocols::TLS1_1)); +} + +TEST(SetupOptions, sslModeRequired) { + OptionsParserTester parser; + moe::Environment environment; + moe::OptionSection options; + + ASSERT_OK(::mongo::addGeneralServerOptions(&options)); + + std::string sslPEMKeyFile = "jstests/libs/server.pem"; + std::string sslCAFFile = "jstests/libs/ca.pem"; + std::string sslCRLFile = "jstests/libs/crl.pem"; + std::string sslClusterFile = "jstests/libs/cluster_cert.pem"; + + std::vector<std::string> argv; + argv.push_back("binaryname"); + argv.push_back("--sslMode"); + argv.push_back("requireSSL"); + argv.push_back("--sslPEMKeyFile"); + argv.push_back(sslPEMKeyFile); + argv.push_back("--sslCAFile"); + argv.push_back(sslCAFFile); + argv.push_back("--sslCRLFile"); + argv.push_back(sslCRLFile); + argv.push_back("--sslClusterFile"); + argv.push_back(sslClusterFile); + argv.push_back("--sslAllowInvalidHostnames"); + argv.push_back("--sslAllowInvalidCertificates"); + argv.push_back("--sslWeakCertificateValidation"); + argv.push_back("--sslFIPSMode"); + argv.push_back("--sslPEMKeyPassword"); + argv.push_back("pw1"); + argv.push_back("--sslClusterPassword"); + argv.push_back("pw2"); + argv.push_back("--sslDisabledProtocols"); + argv.push_back("TLS1_1"); + std::map<std::string, std::string> env_map; + + ASSERT_OK(mongo::addSSLServerOptions(&options)); + + ASSERT_OK(parser.run(options, argv, env_map, &environment)); + ASSERT_OK(mongo::storeSSLServerOptions(environment)); + + ASSERT_EQ(::mongo::sslGlobalParams.sslMode.load(), ::mongo::sslGlobalParams.SSLMode_requireSSL); + ASSERT_EQ(::mongo::sslGlobalParams.sslPEMKeyFile.substr( + ::mongo::sslGlobalParams.sslPEMKeyFile.length() - sslPEMKeyFile.length()), + sslPEMKeyFile); + ASSERT_EQ(::mongo::sslGlobalParams.sslCAFile.substr( + ::mongo::sslGlobalParams.sslCAFile.length() - sslCAFFile.length()), + sslCAFFile); + ASSERT_EQ(::mongo::sslGlobalParams.sslCRLFile.substr( + ::mongo::sslGlobalParams.sslCRLFile.length() - sslCRLFile.length()), + sslCRLFile); + ASSERT_EQ(::mongo::sslGlobalParams.sslClusterFile.substr( + ::mongo::sslGlobalParams.sslClusterFile.length() - sslClusterFile.length()), + sslClusterFile); + ASSERT_EQ(::mongo::sslGlobalParams.sslAllowInvalidHostnames, true); + ASSERT_EQ(::mongo::sslGlobalParams.sslAllowInvalidCertificates, true); + ASSERT_EQ(::mongo::sslGlobalParams.sslWeakCertificateValidation, true); + ASSERT_EQ(::mongo::sslGlobalParams.sslFIPSMode, true); + ASSERT_EQ(::mongo::sslGlobalParams.sslPEMKeyPassword, "pw1"); + ASSERT_EQ(::mongo::sslGlobalParams.sslClusterPassword, "pw2"); + ASSERT_EQ(static_cast<int>(::mongo::sslGlobalParams.sslDisabledProtocols.back()), + static_cast<int>(::mongo::SSLParams::Protocols::TLS1_1)); +} + +#ifdef MONGO_CONFIG_SSL_CERTIFICATE_SELECTORS +TEST(SetupOptions, tlsModeRequiredCertificateSelector) { + OptionsParserTester parser; + moe::Environment environment; + moe::OptionSection options; + + ASSERT_OK(::mongo::addGeneralServerOptions(&options)); + + std::vector<std::string> argv; + argv.push_back("binaryname"); + argv.push_back("--tlsMode"); + argv.push_back("requireTLS"); + argv.push_back("--tlsCertificateSelector"); + argv.push_back("subject=Subject 1"); + argv.push_back("--tlsClusterCertificateSelector"); + argv.push_back("subject=Subject 2"); + std::map<std::string, std::string> env_map; + + ASSERT_OK(mongo::addSSLServerOptions(&options)); + + ASSERT_OK(parser.run(options, argv, env_map, &environment)); + ASSERT_OK(mongo::storeSSLServerOptions(environment)); + + ASSERT_EQ(::mongo::sslGlobalParams.sslMode.load(), ::mongo::sslGlobalParams.SSLMode_requireSSL); + ASSERT_EQ(::mongo::sslGlobalParams.sslCertificateSelector.subject, "Subject 1"); + ASSERT_EQ(::mongo::sslGlobalParams.sslClusterCertificateSelector.subject, "Subject 2"); +} + +TEST(SetupOptions, sslModeRequiredCertificateSelector) { + OptionsParserTester parser; + moe::Environment environment; + moe::OptionSection options; + + ASSERT_OK(::mongo::addGeneralServerOptions(&options)); + + std::vector<std::string> argv; + argv.push_back("binaryname"); + argv.push_back("--sslMode"); + argv.push_back("requireSSL"); + argv.push_back("--sslCertificateSelector"); + argv.push_back("subject=Subject 1"); + argv.push_back("--sslClusterCertificateSelector"); + argv.push_back("subject=Subject 2"); + std::map<std::string, std::string> env_map; + + ASSERT_OK(mongo::addSSLServerOptions(&options)); + + ASSERT_OK(parser.run(options, argv, env_map, &environment)); + ASSERT_OK(mongo::storeSSLServerOptions(environment)); + + ASSERT_EQ(::mongo::sslGlobalParams.sslMode.load(), ::mongo::sslGlobalParams.SSLMode_requireSSL); + ASSERT_EQ(::mongo::sslGlobalParams.sslCertificateSelector.subject, "Subject 1"); + ASSERT_EQ(::mongo::sslGlobalParams.sslClusterCertificateSelector.subject, "Subject 2"); +} + +TEST(SetupOptions, disableNonSSLConnectionLoggingFalse) { + OptionsParserTester parser; + moe::Environment environment; + moe::OptionSection options; + + ASSERT_OK(::mongo::addGeneralServerOptions(&options)); + + std::vector<std::string> argv; + argv.push_back("binaryname"); + argv.push_back("--setParameter"); + argv.push_back("disableNonSSLConnectionLogging=false"); + std::map<std::string, std::string> env_map; + + ASSERT_OK(parser.run(options, argv, env_map, &environment)); + Status storeRet = mongo::storeServerOptions(environment); + + ASSERT_EQ(::mongo::sslGlobalParams.disableNonSSLConnectionLogging, false); +} + +TEST(SetupOptions, disableNonTLSConnectionLoggingFalse) { + OptionsParserTester parser; + moe::Environment environment; + moe::OptionSection options; + + ::mongo::sslGlobalParams.disableNonSSLConnectionLoggingSet = false; + ASSERT_OK(::mongo::addGeneralServerOptions(&options)); + + std::vector<std::string> argv; + argv.push_back("binaryname"); + argv.push_back("--setParameter"); + argv.push_back("disableNonTLSConnectionLogging=false"); + std::map<std::string, std::string> env_map; + + ASSERT_OK(parser.run(options, argv, env_map, &environment)); + Status storeRet = mongo::storeServerOptions(environment); + + ASSERT_EQ(::mongo::sslGlobalParams.disableNonSSLConnectionLogging, false); +} + +TEST(SetupOptions, disableNonSSLConnectionLoggingTrue) { + OptionsParserTester parser; + moe::Environment environment; + moe::OptionSection options; + + ::mongo::sslGlobalParams.disableNonSSLConnectionLoggingSet = false; + ASSERT_OK(::mongo::addGeneralServerOptions(&options)); + + std::vector<std::string> argv; + argv.push_back("binaryname"); + argv.push_back("--setParameter"); + argv.push_back("disableNonSSLConnectionLogging=true"); + std::map<std::string, std::string> env_map; + + ASSERT_OK(parser.run(options, argv, env_map, &environment)); + Status storeRet = mongo::storeServerOptions(environment); + + ASSERT_EQ(::mongo::sslGlobalParams.disableNonSSLConnectionLogging, true); +} + +TEST(SetupOptions, disableNonTLSConnectionLoggingTrue) { + OptionsParserTester parser; + moe::Environment environment; + moe::OptionSection options; + + ::mongo::sslGlobalParams.disableNonSSLConnectionLoggingSet = false; + ASSERT_OK(::mongo::addGeneralServerOptions(&options)); + + std::vector<std::string> argv; + argv.push_back("binaryname"); + argv.push_back("--setParameter"); + argv.push_back("disableNonTLSConnectionLogging=true"); + std::map<std::string, std::string> env_map; + + ASSERT_OK(parser.run(options, argv, env_map, &environment)); + Status storeRet = mongo::storeServerOptions(environment); + + ASSERT_EQ(::mongo::sslGlobalParams.disableNonSSLConnectionLogging, true); +} + +TEST(SetupOptions, disableNonTLSConnectionLoggingInvalid) { + OptionsParserTester parser; + moe::Environment environment; + moe::OptionSection options; + + ASSERT_OK(::mongo::addGeneralServerOptions(&options)); + + std::vector<std::string> argv; + argv.push_back("binaryname"); + argv.push_back("--setParameter"); + argv.push_back("disableNonTLSConnectionLogging=false"); + argv.push_back("--setParameter"); + argv.push_back("disableNonSSLConnectionLogging=false"); + std::map<std::string, std::string> env_map; + + ASSERT_OK(parser.run(options, argv, env_map, &environment)); + ASSERT_NOT_OK(mongo::storeServerOptions(environment)); +} +#endif + } // namespace } // namespace mongo |