summaryrefslogtreecommitdiff
path: root/src/mongo/util
diff options
context:
space:
mode:
authorSara Golemon <sara.golemon@mongodb.com>2018-07-26 16:15:41 +0000
committerSara Golemon <sara.golemon@mongodb.com>2018-08-29 14:50:33 +0000
commit17ccef2b9f0c71b60d31b84b8824215ff87f03aa (patch)
tree8cc015711f93715bf1373703f3d2017f1d9d3678 /src/mongo/util
parentd92fe6cd9242a22e8ae56f48e64a20770d9e8291 (diff)
downloadmongo-17ccef2b9f0c71b60d31b84b8824215ff87f03aa.tar.gz
SERVER-35418 Allow specifying CAs for incoming and outgoing connections separately
Diffstat (limited to 'src/mongo/util')
-rw-r--r--src/mongo/util/net/ssl_manager_apple.cpp41
-rw-r--r--src/mongo/util/net/ssl_manager_openssl.cpp10
-rw-r--r--src/mongo/util/net/ssl_manager_windows.cpp69
-rw-r--r--src/mongo/util/net/ssl_options.h17
-rw-r--r--src/mongo/util/net/ssl_options_server.cpp14
5 files changed, 112 insertions, 39 deletions
diff --git a/src/mongo/util/net/ssl_manager_apple.cpp b/src/mongo/util/net/ssl_manager_apple.cpp
index ed7106c66d8..6191b201cf6 100644
--- a/src/mongo/util/net/ssl_manager_apple.cpp
+++ b/src/mongo/util/net/ssl_manager_apple.cpp
@@ -1096,7 +1096,20 @@ private:
bool _suppressNoCertificateWarning;
asio::ssl::apple::Context _clientCtx;
asio::ssl::apple::Context _serverCtx;
- CFUniquePtr<::CFArrayRef> _ca;
+
+ /* _clientCA represents the CA to use when acting as a client
+ * and validating remotes during outbound connections.
+ * This comes from, in order, --tlsCAFile, or the system CA.
+ */
+ CFUniquePtr<::CFArrayRef> _clientCA;
+
+ /* _serverCA represents the CA to use when acting as a server
+ * and validating remotes during inbound connections.
+ * This comes from --tlsClusterCAFile, if available,
+ * otherwise it inherits from _clientCA.
+ */
+ CFUniquePtr<::CFArrayRef> _serverCA;
+
SSLConfiguration _sslConfiguration;
};
@@ -1124,8 +1137,8 @@ SSLManagerApple::SSLManagerApple(const SSLParams& params, bool isServer)
if (!params.sslCAFile.empty()) {
auto ca = uassertStatusOK(loadPEM(params.sslCAFile, "", kLoadPEMStripKeys));
- _ca = std::move(ca);
- _sslConfiguration.hasCA = _ca && ::CFArrayGetCount(_ca.get());
+ _clientCA = std::move(ca);
+ _sslConfiguration.hasCA = _clientCA && ::CFArrayGetCount(_clientCA.get());
}
if (!params.sslCertificateSelector.empty() || !params.sslClusterCertificateSelector.empty()) {
@@ -1133,12 +1146,22 @@ SSLManagerApple::SSLManagerApple(const SSLParams& params, bool isServer)
_sslConfiguration.hasCA = true;
}
- if (!_ca) {
+ if (!_clientCA) {
// No explicit CA was specified, use the Keychain CA explicitly on client connects,
// even though we're going to pretend it doesn't exist on server.
::CFArrayRef certs = nullptr;
uassertOSStatusOK(SecTrustCopyAnchorCertificates(&certs));
- _ca.reset(certs);
+ _clientCA.reset(certs);
+ }
+
+ if (!params.sslClusterCAFile.empty()) {
+ auto ca = uassertStatusOK(loadPEM(params.sslClusterCAFile, "", kLoadPEMStripKeys));
+ _serverCA = std::move(ca);
+ } else {
+ // No inbound CA specified, share a reference with outbound CA.
+ auto ca = _clientCA.get();
+ ::CFRetain(ca);
+ _serverCA.reset(ca);
}
}
@@ -1325,8 +1348,12 @@ StatusWith<boost::optional<SSLPeerInfo>> SSLManagerApple::parseAndValidatePeerCe
}
}
- if (_ca) {
- auto status = ::SecTrustSetAnchorCertificates(cftrust.get(), _ca.get());
+ // When remoteHost is empty, it means we're handling an Inbound connection.
+ // In that case, we in a server role, so use the _serverCA,
+ // otherwise we're in a client role, so use that.
+ auto ca = remoteHost.empty() ? _serverCA.get() : _clientCA.get();
+ if (ca) {
+ auto status = ::SecTrustSetAnchorCertificates(cftrust.get(), ca);
if (status == ::errSecSuccess) {
status = ::SecTrustSetAnchorCertificatesOnly(cftrust.get(), true);
}
diff --git a/src/mongo/util/net/ssl_manager_openssl.cpp b/src/mongo/util/net/ssl_manager_openssl.cpp
index bc517a49fdf..12d6f46d625 100644
--- a/src/mongo/util/net/ssl_manager_openssl.cpp
+++ b/src/mongo/util/net/ssl_manager_openssl.cpp
@@ -759,10 +759,14 @@ Status SSLManagerOpenSSL::initSSLContext(SSL_CTX* context,
}
}
- const auto status =
- params.sslCAFile.empty() ? _setupSystemCA(context) : _setupCA(context, params.sslCAFile);
- if (!status.isOK())
+ std::string cafile = params.sslCAFile;
+ if (direction == ConnectionDirection::kIncoming && !params.sslClusterCAFile.empty()) {
+ cafile = params.sslClusterCAFile;
+ }
+ const auto status = cafile.empty() ? _setupSystemCA(context) : _setupCA(context, cafile);
+ if (!status.isOK()) {
return status;
+ }
if (!params.sslCRLFile.empty()) {
if (!_setupCRL(context, params.sslCRLFile)) {
diff --git a/src/mongo/util/net/ssl_manager_windows.cpp b/src/mongo/util/net/ssl_manager_windows.cpp
index c5dcc4c865e..7ac11406796 100644
--- a/src/mongo/util/net/ssl_manager_windows.cpp
+++ b/src/mongo/util/net/ssl_manager_windows.cpp
@@ -297,7 +297,15 @@ private:
SSLX509Name* subjectName,
Date_t* serverCertificateExpirationDate);
- Status _initChainEngines(bool hasCAFile);
+ struct CAEngine {
+ CERT_CHAIN_ENGINE_CONFIG machineConfig;
+ UniqueCertChainEngine machine;
+ CERT_CHAIN_ENGINE_CONFIG userConfig;
+ UniqueCertChainEngine user;
+ UniqueCertStore CAstore;
+ };
+
+ Status _initChainEngines(CAEngine* engine);
private:
bool _weakValidation;
@@ -314,17 +322,21 @@ private:
std::array<PCCERT_CONTEXT, 1> _clientCertificates;
std::array<PCCERT_CONTEXT, 1> _serverCertificates;
- UniqueCertificate _sslCertificate;
- UniqueCertificate _sslClusterCertificate;
-
- UniqueCertStore _certStore;
+ /* _clientEngine represents the CA to use when acting as a client
+ * and validating remotes during outbound connections.
+ * This comes from, in order, --tlsCAFile, or the system CA.
+ */
+ CAEngine _clientEngine;
- std::array<HCERTSTORE, 1> _additionalCertStores;
- CERT_CHAIN_ENGINE_CONFIG _chainEngineConfigMachine;
- UniqueCertChainEngine _chainEngineMachine;
+ /* _serverEngine represents the CA to use when acting as a server
+ * and validating remotes during inbound connections.
+ * This comes from --tlsClusterCAFile, if available,
+ * otherwise it inherits from _clientEngine.
+ */
+ CAEngine _serverEngine;
- CERT_CHAIN_ENGINE_CONFIG _chainEngineConfigUser;
- UniqueCertChainEngine _chainEngineUser;
+ UniqueCertificate _sslCertificate;
+ UniqueCertificate _sslClusterCertificate;
};
MONGO_INITIALIZER(SSLManager)(InitializerContext*) {
@@ -411,7 +423,8 @@ SSLManagerWindows::SSLManagerWindows(const SSLParams& params, bool isServer)
CertificateExpirationMonitor(_sslConfiguration.serverCertificateExpirationDate);
}
- uassertStatusOK(_initChainEngines(!params.sslCAFile.empty()));
+ uassertStatusOK(_initChainEngines(&_serverEngine));
+ uassertStatusOK(_initChainEngines(&_clientEngine));
}
StatusWith<UniqueCertChainEngine> initChainEngine(CERT_CHAIN_ENGINE_CONFIG* chainEngineConfig,
@@ -439,23 +452,23 @@ StatusWith<UniqueCertChainEngine> initChainEngine(CERT_CHAIN_ENGINE_CONFIG* chai
return {chainEngine};
}
-Status SSLManagerWindows::_initChainEngines(bool hasCAFile) {
- auto swMachine =
- initChainEngine(&_chainEngineConfigMachine, _certStore, CERT_CHAIN_USE_LOCAL_MACHINE_STORE);
+Status SSLManagerWindows::_initChainEngines(CAEngine* engine) {
+ auto swMachine = initChainEngine(
+ &engine->machineConfig, engine->CAstore, CERT_CHAIN_USE_LOCAL_MACHINE_STORE);
if (!swMachine.isOK()) {
return swMachine.getStatus();
}
- _chainEngineMachine = std::move(swMachine.getValue());
+ engine->machine = std::move(swMachine.getValue());
- auto swUser = initChainEngine(&_chainEngineConfigUser, _certStore, 0);
+ auto swUser = initChainEngine(&engine->userConfig, engine->CAstore, 0);
if (!swUser.isOK()) {
return swUser.getStatus();
}
- _chainEngineUser = std::move(swUser.getValue());
+ engine->user = std::move(swUser.getValue());
return Status::OK();
}
@@ -1180,7 +1193,18 @@ Status SSLManagerWindows::_loadCertificates(const SSLParams& params) {
return swChain.getStatus();
}
- _certStore = std::move(swChain.getValue());
+ _clientEngine.CAstore = std::move(swChain.getValue());
+ }
+
+ const auto serverCAFile =
+ params.sslClusterCAFile.empty() ? params.sslCAFile : params.sslClusterCAFile;
+ if (!serverCAFile.empty()) {
+ auto swChain = readCertChains(serverCAFile, params.sslCRLFile);
+ if (!swChain.isOK()) {
+ return swChain.getStatus();
+ }
+
+ _serverEngine.CAstore = std::move(swChain.getValue());
}
if (hasCertificateSelector(params.sslCertificateSelector)) {
@@ -1228,7 +1252,6 @@ Status SSLManagerWindows::initSSLContext(SCHANNEL_CRED* cred,
cred->dwVersion = SCHANNEL_CRED_VERSION;
cred->dwFlags = SCH_USE_STRONG_CRYPTO; // Use strong crypto;
- cred->hRootStore = _certStore;
uint32_t supportedProtocols = 0;
@@ -1236,6 +1259,7 @@ Status SSLManagerWindows::initSSLContext(SCHANNEL_CRED* cred,
supportedProtocols = SP_PROT_TLS1_SERVER | SP_PROT_TLS1_0_SERVER | SP_PROT_TLS1_1_SERVER |
SP_PROT_TLS1_2_SERVER;
+ cred->hRootStore = _serverEngine.CAstore;
cred->dwFlags = cred->dwFlags // flags
| SCH_CRED_REVOCATION_CHECK_CHAIN // Check certificate revocation
| SCH_CRED_SNI_CREDENTIAL // Pass along SNI creds
@@ -1246,6 +1270,7 @@ Status SSLManagerWindows::initSSLContext(SCHANNEL_CRED* cred,
supportedProtocols = SP_PROT_TLS1_CLIENT | SP_PROT_TLS1_0_CLIENT | SP_PROT_TLS1_1_CLIENT |
SP_PROT_TLS1_2_CLIENT;
+ cred->hRootStore = _clientEngine.CAstore;
cred->dwFlags = cred->dwFlags // Flags
| SCH_CRED_REVOCATION_CHECK_CHAIN // Check certificate revocation
| SCH_CRED_NO_SERVERNAME_CHECK // Do not validate server name against cert
@@ -1702,10 +1727,12 @@ StatusWith<boost::optional<SSLPeerInfo>> SSLManagerWindows::parseAndValidatePeer
UniqueCertificate certHolder(cert);
SSLX509Name peerSubjectName;
+ auto* engine = remoteHost.empty() ? &_serverEngine : &_clientEngine;
+
// Validate against the local machine store first since it is easier to manage programmatically.
Status validateCertMachine = validatePeerCertificate(remoteHost,
certHolder.get(),
- _chainEngineMachine,
+ engine->machine,
_allowInvalidCertificates,
_allowInvalidHostnames,
&peerSubjectName);
@@ -1714,7 +1741,7 @@ StatusWith<boost::optional<SSLPeerInfo>> SSLManagerWindows::parseAndValidatePeer
// manage.
Status validateCertUser = validatePeerCertificate(remoteHost,
certHolder.get(),
- _chainEngineUser,
+ engine->user,
_allowInvalidCertificates,
_allowInvalidHostnames,
&peerSubjectName);
diff --git a/src/mongo/util/net/ssl_options.h b/src/mongo/util/net/ssl_options.h
index 724a272c952..468073b2cbc 100644
--- a/src/mongo/util/net/ssl_options.h
+++ b/src/mongo/util/net/ssl_options.h
@@ -47,16 +47,17 @@ class Environment;
struct SSLParams {
enum class Protocols { TLS1_0, TLS1_1, TLS1_2 };
- AtomicInt32 sslMode; // --sslMode - the SSL operation mode, see enum SSLModes
+ AtomicInt32 sslMode; // --tlsMode - the TLS operation mode, see enum SSLModes
std::string sslPEMTempDHParam; // --setParameter OpenSSLDiffieHellmanParameters=file : PEM file
// with DH parameters.
- std::string sslPEMKeyFile; // --sslPEMKeyFile
- std::string sslPEMKeyPassword; // --sslPEMKeyPassword
- std::string sslClusterFile; // --sslInternalKeyFile
- std::string sslClusterPassword; // --sslInternalKeyPassword
- std::string sslCAFile; // --sslCAFile
- std::string sslCRLFile; // --sslCRLFile
- std::string sslCipherConfig; // --sslCipherConfig
+ std::string sslPEMKeyFile; // --tlsPEMKeyFile
+ std::string sslPEMKeyPassword; // --tlsPEMKeyPassword
+ std::string sslClusterFile; // --tlsInternalKeyFile
+ std::string sslClusterPassword; // --tlsInternalKeyPassword
+ std::string sslCAFile; // --tlsCAFile
+ std::string sslClusterCAFile; // --tlsClusterCAFile
+ std::string sslCRLFile; // --tlsCRLFile
+ std::string sslCipherConfig; // --tlsCipherConfig
struct CertificateSelector {
std::string subject;
diff --git a/src/mongo/util/net/ssl_options_server.cpp b/src/mongo/util/net/ssl_options_server.cpp
index 670f824ff19..a18856baaf8 100644
--- a/src/mongo/util/net/ssl_options_server.cpp
+++ b/src/mongo/util/net/ssl_options_server.cpp
@@ -116,6 +116,14 @@ 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.CRLFile",
"tlsCRLFile",
moe::String,
@@ -255,6 +263,12 @@ Status storeSSLServerOptions(const moe::Environment& params) {
.generic_string();
}
+ if (params.count("net.tls.clusterCAFile")) {
+ sslGlobalParams.sslClusterCAFile =
+ boost::filesystem::absolute(params["net.tls.clusterCAFile"].as<std::string>())
+ .generic_string();
+ }
+
if (params.count("net.tls.CRLFile")) {
sslGlobalParams.sslCRLFile =
boost::filesystem::absolute(params["net.tls.CRLFile"].as<std::string>())