diff options
-rw-r--r-- | jstests/ssl/ssl_withhold_client_cert.js | 45 | ||||
-rw-r--r-- | src/mongo/util/net/ssl_manager.cpp | 6 | ||||
-rw-r--r-- | src/mongo/util/net/ssl_manager_apple.cpp | 4 | ||||
-rw-r--r-- | src/mongo/util/net/ssl_manager_openssl.cpp | 10 | ||||
-rw-r--r-- | src/mongo/util/net/ssl_manager_windows.cpp | 2 | ||||
-rw-r--r-- | src/mongo/util/net/ssl_options.h | 1 | ||||
-rw-r--r-- | src/mongo/util/net/ssl_options_server.cpp | 11 |
7 files changed, 69 insertions, 10 deletions
diff --git a/jstests/ssl/ssl_withhold_client_cert.js b/jstests/ssl/ssl_withhold_client_cert.js new file mode 100644 index 00000000000..3839e5d6aef --- /dev/null +++ b/jstests/ssl/ssl_withhold_client_cert.js @@ -0,0 +1,45 @@ +// Test setParameter tlsWithholdClientCertificate + +(function() { + "use strict"; + + function testRS(opts, expectWarning) { + const rsOpts = { + nodes: {node0: opts, node1: opts}, + }; + const rs = new ReplSetTest(rsOpts); + rs.startSet(); + rs.initiate(); + rs.awaitReplication(); + + const test = rs.getPrimary().getDB('test'); + test.foo.insert({bar: "baz"}); + rs.awaitReplication(); + + function checkWarning(member) { + const observed = + /no SSL certificate provided by peer/.test(cat(member.fullOptions.logFile)); + assert.eq(observed, expectWarning); + } + checkWarning(rs.getPrimary()); + checkWarning(rs.getSecondary()); + rs.stopSet(); + } + + const base_options = { + tlsMode: 'requireTLS', + tlsPEMKeyFile: 'jstests/libs/server.pem', + tlsCAFile: 'jstests/libs/ca.pem', + tlsAllowInvalidHostnames: '', + useLogFiles: true, + }; + testRS(base_options, false); + + const test_options = Object.extend({ + tlsAllowConnectionsWithoutCertificates: '', + setParameter: 'tlsWithholdClientCertificate=true', + }, + base_options); + + testRS(test_options, true); +}()); diff --git a/src/mongo/util/net/ssl_manager.cpp b/src/mongo/util/net/ssl_manager.cpp index c8346091346..a0a21e6923c 100644 --- a/src/mongo/util/net/ssl_manager.cpp +++ b/src/mongo/util/net/ssl_manager.cpp @@ -62,6 +62,12 @@ ExportedServerParameter<bool, ServerParameterType::kStartupOnly> suppressNoTLSPeerCertificateWarning(ServerParameterSet::getGlobal(), "suppressNoTLSPeerCertificateWarning", &sslGlobalParams.suppressNoTLSPeerCertificateWarning); + +ExportedServerParameter<bool, ServerParameterType::kStartupOnly> tlsWithholdClientCertificate( + ServerParameterSet::getGlobal(), + "tlsWithholdClientCertificate", + &sslGlobalParams.tlsWithholdClientCertificate); + } // namespace class OpenSSLCipherConfigParameter diff --git a/src/mongo/util/net/ssl_manager_apple.cpp b/src/mongo/util/net/ssl_manager_apple.cpp index 4f7cf85c3db..ac7b9d911da 100644 --- a/src/mongo/util/net/ssl_manager_apple.cpp +++ b/src/mongo/util/net/ssl_manager_apple.cpp @@ -1234,6 +1234,10 @@ Status SSLManagerApple::initSSLContext(asio::ssl::apple::Context* context, }; if (direction == ConnectionDirection::kOutgoing) { + if (params.tlsWithholdClientCertificate) { + return Status::OK(); + } + const auto status = selectCertificate( params.sslClusterCertificateSelector, params.sslClusterFile, params.sslClusterPassword); if (context->certs || !status.isOK()) { diff --git a/src/mongo/util/net/ssl_manager_openssl.cpp b/src/mongo/util/net/ssl_manager_openssl.cpp index 12d6f46d625..bf0ad8d5cca 100644 --- a/src/mongo/util/net/ssl_manager_openssl.cpp +++ b/src/mongo/util/net/ssl_manager_openssl.cpp @@ -746,13 +746,19 @@ Status SSLManagerOpenSSL::initSSLContext(SSL_CTX* context, << getSSLErrorMessage(ERR_get_error())); } - if (direction == ConnectionDirection::kOutgoing && !params.sslClusterFile.empty()) { + if (direction == ConnectionDirection::kOutgoing && params.tlsWithholdClientCertificate) { + // Do not send a client certificate if they have been suppressed. + + } else if (direction == ConnectionDirection::kOutgoing && !params.sslClusterFile.empty()) { + // Use the configured clusterFile as our client certificate. ::EVP_set_pw_prompt("Enter cluster certificate passphrase"); if (!_setupPEM(context, params.sslClusterFile, params.sslClusterPassword)) { return Status(ErrorCodes::InvalidSSLConfiguration, "Can not set up ssl clusterFile."); } + } else if (!params.sslPEMKeyFile.empty()) { - // Use the pemfile for everything else + // Use the base pemKeyFile for any other outgoing connections, + // as well as all incoming connections. ::EVP_set_pw_prompt("Enter PEM passphrase"); if (!_setupPEM(context, params.sslPEMKeyFile, params.sslPEMKeyPassword)) { return Status(ErrorCodes::InvalidSSLConfiguration, "Can not set up PEM key file."); diff --git a/src/mongo/util/net/ssl_manager_windows.cpp b/src/mongo/util/net/ssl_manager_windows.cpp index 7ac11406796..6ae5d567140 100644 --- a/src/mongo/util/net/ssl_manager_windows.cpp +++ b/src/mongo/util/net/ssl_manager_windows.cpp @@ -1301,7 +1301,7 @@ Status SSLManagerWindows::initSSLContext(SCHANNEL_CRED* cred, } if (direction == ConnectionDirection::kOutgoing) { - if (_clientCertificates[0]) { + if (_clientCertificates[0] && !params.tlsWithholdClientCertificate) { cred->cCreds = 1; cred->paCred = _clientCertificates.data(); } diff --git a/src/mongo/util/net/ssl_options.h b/src/mongo/util/net/ssl_options.h index 468073b2cbc..85b0bd44f64 100644 --- a/src/mongo/util/net/ssl_options.h +++ b/src/mongo/util/net/ssl_options.h @@ -81,6 +81,7 @@ struct SSLParams { bool disableNonSSLConnectionLoggingSet = false; bool suppressNoTLSPeerCertificateWarning = false; // --setParameter suppressNoTLSPeerCertificateWarning + bool tlsWithholdClientCertificate = false; // --setParameter tlsWithholdClientCertificate SSLParams() { sslMode.store(SSLMode_disabled); diff --git a/src/mongo/util/net/ssl_options_server.cpp b/src/mongo/util/net/ssl_options_server.cpp index a18856baaf8..8ccc3f30cc1 100644 --- a/src/mongo/util/net/ssl_options_server.cpp +++ b/src/mongo/util/net/ssl_options_server.cpp @@ -116,13 +116,10 @@ Status addSSLServerOptions(moe::OptionSection* options) { {"net.ssl.CAFile"}, {"sslCAFile"}); - options - ->addOptionChaining("net.tls.clusterCAFile", - "tlsClusterCAFile", - moe::String, - "CA used for verifying remotes during outbound connections") - .requires("net.tls.clusterFile") - .requires("net.tls.CAFile"); + options->addOptionChaining("net.tls.clusterCAFile", + "tlsClusterCAFile", + moe::String, + "CA used for verifying remotes during outbound connections"); options->addOptionChaining("net.tls.CRLFile", "tlsCRLFile", |