diff options
-rw-r--r-- | jstests/ssl/tls1_0.js | 91 | ||||
-rw-r--r-- | src/mongo/util/net/ssl_manager_windows.cpp | 4 | ||||
-rw-r--r-- | src/mongo/util/net/ssl_options.cpp | 27 |
3 files changed, 120 insertions, 2 deletions
diff --git a/jstests/ssl/tls1_0.js b/jstests/ssl/tls1_0.js new file mode 100644 index 00000000000..e634244af15 --- /dev/null +++ b/jstests/ssl/tls1_0.js @@ -0,0 +1,91 @@ +// Make sure MongoD starts with TLS 1.0 disabled (except w/ old OpenSSL). + +(function() { + 'use strict'; + + const supportsTLS1_1 = (function() { + const openssl = getBuildInfo().openssl || {}; + if (openssl.compiled === undefined) { + // Native TLS build. + return true; + } + // OpenSSL 0.x.x => TLS 1.0 only. + if (/OpenSSL 0\./.test(openssl.compiled)) { + return false; + } + // OpenSSL 1.0.0-1.0.0k => TLS 1.0 only. + if (/OpenSSL 1\.0\.0[ a-k]/.test(openssl.compiled)) { + return false; + } + + // OpenSSL 1.0.0l and later include TLS 1.1 and 1.2 + return true; + })(); + + const defaultEnableTLS1_0 = (function() { + // If the build doesn't support TLS 1.1, then TLS 1.0 is left enabled. + if (!supportsTLS1_1) { + return true; + } + // If we're on Apple, then TLS 1.0 is left enabled regardless + // to support other tools on the system which may be TLS 1.0 only. + const buildEnv = getBuildInfo().buildEnvironment || {}; + return (buildEnv.target_os === 'macOS'); + })(); + + function test(disabledProtocols, shouldSucceed) { + const expectLogMessage = !defaultEnableTLS1_0 && (disabledProtocols === null); + let serverOpts = { + sslMode: 'allowSSL', + sslPEMKeyFile: 'jstests/libs/server.pem', + sslCAFile: 'jstests/libs/ca.pem', + waitForConnect: false + }; + if (disabledProtocols !== null) { + serverOpts.sslDisabledProtocols = disabledProtocols; + } + clearRawMongoProgramOutput(); + const mongod = MongoRunner.runMongod(serverOpts); + assert(mongod); + + const didSucceed = (function() { + try { + assert.soon(function() { + return 0 == runMongoProgram('mongo', + '--ssl', + '--port', + mongod.port, + '--sslPEMKeyFile', + 'jstests/libs/client.pem', + '--sslCAFile', + 'jstests/libs/ca.pem', + '--eval', + ';'); + }, "Connecting to mongod", 30 * 1000); + return true; + } catch (e) { + return false; + } + })(); + + // Exit code based success/failure. + assert.eq(didSucceed, + shouldSucceed, + "Running with disabledProtocols == " + tojson(disabledProtocols)); + + assert.eq(expectLogMessage, + rawMongoProgramOutput().search('Automatically disabling TLS 1.0') >= 0, + "TLS 1.0 was/wasn't automatically disabled"); + + const exitCode = + (didSucceed || !_isWindows()) ? MongoRunner.EXIT_CLEAN : MongoRunner.EXIT_SIGKILL; + MongoRunner.stopMongod(mongod, undefined, {allowedExitCode: exitCode}); + } + + test(null, true); + test('none', true); + test('TLS1_0', supportsTLS1_1); + test('TLS1_1,TLS1_2', true); + test('TLS1_0,TLS1_1', supportsTLS1_1); + test('TLS1_0,TLS1_1,TLS1_2', false); +})(); diff --git a/src/mongo/util/net/ssl_manager_windows.cpp b/src/mongo/util/net/ssl_manager_windows.cpp index 3e91df52fe9..51e85111828 100644 --- a/src/mongo/util/net/ssl_manager_windows.cpp +++ b/src/mongo/util/net/ssl_manager_windows.cpp @@ -1267,6 +1267,10 @@ Status SSLManagerWindows::initSSLContext(SCHANNEL_CRED* cred, } cred->grbitEnabledProtocols = supportedProtocols; + if (supportedProtocols == 0) { + return {ErrorCodes::InvalidSSLConfiguration, + "All supported TLS protocols have been disabled."}; + } if (!params.sslCipherConfig.empty()) { warning() diff --git a/src/mongo/util/net/ssl_options.cpp b/src/mongo/util/net/ssl_options.cpp index e6c0a8d21c9..ffca18fcc17 100644 --- a/src/mongo/util/net/ssl_options.cpp +++ b/src/mongo/util/net/ssl_options.cpp @@ -383,6 +383,15 @@ Status storeSSLServerOptions(const moe::Environment& params) { // Map the tokens to their enum values, and push them onto the list of disabled protocols. for (const std::string& token : tokens) { + if (token == "none") { + // Allow overriding the default behavior below of implicitly disabling TLS 1.0. + if (tokens.size() != 1) { + return {ErrorCodes::BadValue, + "'none' may not be specified with other values to disabledProtocols"}; + } + break; + } + auto mappedToken = validConfigs.find(token); if (mappedToken != validConfigs.end()) { sslGlobalParams.sslDisabledProtocols.push_back(mappedToken->second); @@ -391,6 +400,20 @@ Status storeSSLServerOptions(const moe::Environment& params) { "Unrecognized disabledProtocols '" + token + "'"); } } + +#if !defined(__APPLE__) && ((MONGO_CONFIG_SSL_PROVIDER != SSL_PROVIDER_OPENSSL) || \ + (OPENSSL_VERSION_NUMBER >= 0x100000cf)) /* 1.0.0l */ + } else { + /* Disable TLS 1.0 by default on non-Apple 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. + * TL;DR - Pretty much any Linux/Windows build. + */ + 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.ssl.weakCertificateValidation")) { @@ -438,7 +461,7 @@ Status storeSSLServerOptions(const moe::Environment& params) { bool usingCertifiateSelectors = params.count("net.ssl.certificateSelector"); if (sslGlobalParams.sslPEMKeyFile.size() == 0 && !usingCertifiateSelectors) { return Status(ErrorCodes::BadValue, - "need sslPEMKeyFileor certificateSelector when SSL is enabled"); + "need sslPEMKeyFile or certificateSelector when SSL is enabled"); } if (!sslGlobalParams.sslCRLFile.empty() && sslGlobalParams.sslCAFile.empty()) { return Status(ErrorCodes::BadValue, "need sslCAFile with sslCRLFile"); @@ -459,7 +482,7 @@ Status storeSSLServerOptions(const moe::Environment& params) { sslGlobalParams.sslClusterFile.size() || sslGlobalParams.sslClusterPassword.size() || sslGlobalParams.sslCAFile.size() || sslGlobalParams.sslCRLFile.size() || sslGlobalParams.sslCipherConfig.size() || - sslGlobalParams.sslDisabledProtocols.size() || + params.count("net.ssl.disabledProtocols") || #ifdef MONGO_CONFIG_SSL_CERTIFICATE_SELECTORS params.count("net.ssl.certificateSelector") || params.count("net.ssl.clusterCertificateSelector") || |