diff options
author | Mark Benvenuto <mark.benvenuto@mongodb.com> | 2020-04-20 14:33:11 -0400 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2020-05-08 19:38:42 +0000 |
commit | da437a3b9d4501cc1e9d278d2c7a82663fa051cf (patch) | |
tree | 3da4305cd7e46c801922d7a80a5fe21611fd53e7 | |
parent | f9ae69de6204289abc1702ba359fcd9b0387572c (diff) | |
download | mongo-da437a3b9d4501cc1e9d278d2c7a82663fa051cf.tar.gz |
SERVER-46633 Windows TLS implementation may declare hostname mismatch on unrelated error
(cherry picked from commit 06f26fac35c7a3b82effbb9815ad9f7aedaf4dfb)
-rw-r--r-- | jstests/ssl/mongo_uri_secondaries.js | 16 | ||||
-rw-r--r-- | src/mongo/util/net/ssl_manager_windows.cpp | 41 |
2 files changed, 46 insertions, 11 deletions
diff --git a/jstests/ssl/mongo_uri_secondaries.js b/jstests/ssl/mongo_uri_secondaries.js index 9512a3c23c3..90c58cc358a 100644 --- a/jstests/ssl/mongo_uri_secondaries.js +++ b/jstests/ssl/mongo_uri_secondaries.js @@ -67,16 +67,14 @@ return command; }; - const subShellArgs = [ - "env", - "SSL_CERT_FILE=jstests/libs/trusted-ca.pem", - './mongo', - '--nodb', - '--eval', - subShellCommandFormatter(rst) - ]; + function runWithEnv(args, env) { + const pid = _startMongoProgram({args: args, env: env}); + return waitProgram(pid); + } + + const subShellArgs = ['mongo', '--nodb', '--eval', subShellCommandFormatter(rst)]; - const retVal = _runMongoProgram(...subShellArgs); + const retVal = runWithEnv(subShellArgs, {"SSL_CERT_FILE": "jstests/libs/trusted-ca.pem"}); assert.eq(retVal, 0, 'mongo shell did not succeed with exit code 0'); rst.stopSet(); diff --git a/src/mongo/util/net/ssl_manager_windows.cpp b/src/mongo/util/net/ssl_manager_windows.cpp index c322f21198a..3c59ab008ff 100644 --- a/src/mongo/util/net/ssl_manager_windows.cpp +++ b/src/mongo/util/net/ssl_manager_windows.cpp @@ -40,6 +40,7 @@ #include <string> #include <tuple> #include <vector> +#include <winhttp.h> #include "mongo/base/init.h" #include "mongo/base/initializer_context.h" @@ -312,6 +313,7 @@ private: CERT_CHAIN_ENGINE_CONFIG userConfig; UniqueCertChainEngine user; UniqueCertStore CAstore; + bool hasCRL; }; Status _initChainEngines(CAEngine* engine); @@ -1287,6 +1289,7 @@ Status SSLManagerWindows::_loadCertificates(const SSLParams& params) { } _clientEngine.CAstore = std::move(swChain.getValue()); + _clientEngine.hasCRL = !params.sslCRLFile.empty(); } const auto serverCAFile = @@ -1298,6 +1301,7 @@ Status SSLManagerWindows::_loadCertificates(const SSLParams& params) { } _serverEngine.CAstore = std::move(swChain.getValue()); + _serverEngine.hasCRL = !params.sslCRLFile.empty(); } if (hasCertificateSelector(params.sslCertificateSelector)) { @@ -1627,6 +1631,7 @@ Status validatePeerCertificate(const std::string& remoteHost, HCERTCHAINENGINE certChainEngine, bool allowInvalidCertificates, bool allowInvalidHostnames, + bool hasCRL, SSLX509Name* peerSubjectName) { CERT_CHAIN_PARA certChainPara; memset(&certChainPara, 0, sizeof(certChainPara)); @@ -1709,10 +1714,40 @@ Status validatePeerCertificate(const std::string& remoteHost, // This means the certificate chain is not valid. // Ignore CRYPT_E_NO_REVOCATION_CHECK since most CAs lack revocation information especially test - // certificates + // certificates. Either there needs to be a CRL, a CrlDistributionPoint in the Cert or OCSP and + // user-generated certs lack this information. if (certChainPolicyStatus.dwError != S_OK && certChainPolicyStatus.dwError != CRYPT_E_NO_REVOCATION_CHECK) { - if (certChainPolicyStatus.dwError == CERT_E_CN_NO_MATCH || allowInvalidCertificates) { + bool onlyCNError = false; + + // Try again to validate if the cert has any other errors besides a CN mismatch + if (certChainPolicyStatus.dwError == CERT_E_CN_NO_MATCH && !allowInvalidCertificates) { + + // We know the CNs do not match, are there any other issues? + sslCertChainPolicy.fdwChecks = SECURITY_FLAG_IGNORE_CERT_CN_INVALID; + + ret = CertVerifyCertificateChainPolicy(CERT_CHAIN_POLICY_SSL, + certChainHolder.get(), + &chain_policy_para, + &certChainPolicyStatus); + + // This means something really went wrong, this should not happen. + if (!ret) { + DWORD gle = GetLastError(); + return Status(ErrorCodes::InvalidSSLConfiguration, + str::stream() << "CertVerifyCertificateChainPolicy2 failed: " + << errnoWithDescription(gle)); + } + + if (certChainPolicyStatus.dwError == S_OK || + certChainPolicyStatus.dwError == CRYPT_E_NO_REVOCATION_CHECK) { + onlyCNError = true; + } + } + + // We need to check if the user has a cert where SANs have ip addresses label as DNS Name + // but only if a CN mismatch is the only error + if (onlyCNError || allowInvalidCertificates) { // Give the user a hint why the certificate validation failed. StringBuilder certificateNames; @@ -1831,6 +1866,7 @@ StatusWith<SSLPeerInfo> SSLManagerWindows::parseAndValidatePeerCertificate( engine->machine, _allowInvalidCertificates, _allowInvalidHostnames, + engine->hasCRL, &peerSubjectName); if (!validateCertMachine.isOK()) { // Validate against the current user store since this is easier for unprivileged users to @@ -1840,6 +1876,7 @@ StatusWith<SSLPeerInfo> SSLManagerWindows::parseAndValidatePeerCertificate( engine->user, _allowInvalidCertificates, _allowInvalidHostnames, + engine->hasCRL, &peerSubjectName); if (!validateCertUser.isOK()) { // Return the local machine status |