diff options
author | Sara Golemon <sara.golemon@mongodb.com> | 2018-07-26 16:15:41 +0000 |
---|---|---|
committer | Sara Golemon <sara.golemon@mongodb.com> | 2018-08-29 14:50:33 +0000 |
commit | 17ccef2b9f0c71b60d31b84b8824215ff87f03aa (patch) | |
tree | 8cc015711f93715bf1373703f3d2017f1d9d3678 /src/mongo/util | |
parent | d92fe6cd9242a22e8ae56f48e64a20770d9e8291 (diff) | |
download | mongo-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.cpp | 41 | ||||
-rw-r--r-- | src/mongo/util/net/ssl_manager_openssl.cpp | 10 | ||||
-rw-r--r-- | src/mongo/util/net/ssl_manager_windows.cpp | 69 | ||||
-rw-r--r-- | src/mongo/util/net/ssl_options.h | 17 | ||||
-rw-r--r-- | src/mongo/util/net/ssl_options_server.cpp | 14 |
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>()) |