summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Benvenuto <mark.benvenuto@mongodb.com>2020-04-20 14:33:11 -0400
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2020-05-08 19:38:42 +0000
commitda437a3b9d4501cc1e9d278d2c7a82663fa051cf (patch)
tree3da4305cd7e46c801922d7a80a5fe21611fd53e7
parentf9ae69de6204289abc1702ba359fcd9b0387572c (diff)
downloadmongo-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.js16
-rw-r--r--src/mongo/util/net/ssl_manager_windows.cpp41
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