summaryrefslogtreecommitdiff
path: root/src/mongo/util/net/ssl_manager.cpp
diff options
context:
space:
mode:
authorADAM David Alan Martin <adam.martin@10gen.com>2017-11-28 17:08:19 -0500
committerADAM David Alan Martin <adam.martin@10gen.com>2017-11-28 17:08:19 -0500
commitc2d309d23cf918e1ded8fc241a1c2108dd0e31d3 (patch)
tree2b2243a3dffdd183c5024a9c637aad00a84d37fc /src/mongo/util/net/ssl_manager.cpp
parenta8ec0b2576f03db6792c6b953f86daba4a99a582 (diff)
downloadmongo-c2d309d23cf918e1ded8fc241a1c2108dd0e31d3.tar.gz
SERVER-31965 Correctly handle certificates for SRV URIs
The hostname provided by SRV records is a canonicalized FQDN ending in a '.' character. X.509 certificates use a canonical hostname with the trailing '.' removed. The comparison between these two forms needs to strip all trailing '.' characters. This is considered safe in all cases, as a DNS spoofing attack would still require forging or obtaining a certificate with a canonicalized name to make a redirection work.
Diffstat (limited to 'src/mongo/util/net/ssl_manager.cpp')
-rw-r--r--src/mongo/util/net/ssl_manager.cpp60
1 files changed, 36 insertions, 24 deletions
diff --git a/src/mongo/util/net/ssl_manager.cpp b/src/mongo/util/net/ssl_manager.cpp
index 6299e1336af..919c73a4239 100644
--- a/src/mongo/util/net/ssl_manager.cpp
+++ b/src/mongo/util/net/ssl_manager.cpp
@@ -142,8 +142,10 @@ public:
return Status::OK();
}
} openSSLCipherConfig;
+} // namespace mongo
#ifdef MONGO_CONFIG_SSL
+namespace mongo {
namespace {
// If the underlying SSL supports auto-configuration of ECDH parameters, this function will select
@@ -475,11 +477,6 @@ private:
*/
void _flushNetworkBIO(SSLConnection* conn);
- /*
- * match a remote host name to an x.509 host name
- */
- bool _hostNameMatch(const char* nameToMatch, const char* certHostName);
-
/**
* Callbacks for SSL functions.
*/
@@ -1314,22 +1311,6 @@ SSLConnection* SSLManager::accept(Socket* socket, const char* initialBytes, int
return sslConn.release();
}
-// TODO SERVER-11601 Use NFC Unicode canonicalization
-bool SSLManager::_hostNameMatch(const char* nameToMatch, const char* certHostName) {
- if (strlen(certHostName) < 2) {
- return false;
- }
-
- // match wildcard DNS names
- if (certHostName[0] == '*' && certHostName[1] == '.') {
- // allow name.example.com if the cert is *.example.com, '*' does not match '.'
- const char* subName = strchr(nameToMatch, '.');
- return subName && !strcasecmp(certHostName + 1, subName);
- } else {
- return !strcasecmp(nameToMatch, certHostName);
- }
-}
-
StatusWith<boost::optional<SSLPeerInfo>> SSLManager::parseAndValidatePeerCertificate(
SSL* conn, const std::string& remoteHost) {
if (!_sslConfiguration.hasCA && isSSLServer)
@@ -1399,7 +1380,7 @@ StatusWith<boost::optional<SSLPeerInfo>> SSLManager::parseAndValidatePeerCertifi
const GENERAL_NAME* currentName = sk_GENERAL_NAME_value(sanNames, i);
if (currentName && currentName->type == GEN_DNS) {
char* dnsName = reinterpret_cast<char*>(ASN1_STRING_data(currentName->d.dNSName));
- if (_hostNameMatch(remoteHost.c_str(), dnsName)) {
+ if (hostNameMatchForX509Certificates(remoteHost, dnsName)) {
sanMatch = true;
break;
}
@@ -1414,7 +1395,7 @@ StatusWith<boost::optional<SSLPeerInfo>> SSLManager::parseAndValidatePeerCertifi
int cnEnd = peerSubjectName.find(",", cnBegin);
std::string commonName = peerSubjectName.substr(cnBegin, cnEnd - cnBegin);
- if (_hostNameMatch(remoteHost.c_str(), commonName.c_str())) {
+ if (hostNameMatchForX509Certificates(remoteHost, commonName)) {
cnMatch = true;
}
certificateNames << "CN: " << commonName;
@@ -1619,13 +1600,44 @@ void SSLManager::_handleSSLError(int code, int ret) {
}
throw SocketException(SocketException::CONNECT_ERROR, "");
}
+} // namespace mongo
+
+// TODO SERVER-11601 Use NFC Unicode canonicalization
+bool mongo::hostNameMatchForX509Certificates(std::string nameToMatch, std::string certHostName) {
+ auto removeFQDNRoot = [](std::string name) -> std::string {
+ if (name.back() == '.') {
+ name.pop_back();
+ }
+ return name;
+ };
+
+ nameToMatch = removeFQDNRoot(std::move(nameToMatch));
+ certHostName = removeFQDNRoot(std::move(certHostName));
+
+ if (certHostName.size() < 2) {
+ return false;
+ }
+
+ // match wildcard DNS names
+ if (certHostName[0] == '*' && certHostName[1] == '.') {
+ // allow name.example.com if the cert is *.example.com, '*' does not match '.'
+ const char* subName = strchr(nameToMatch.c_str(), '.');
+ return subName && !strcasecmp(certHostName.c_str() + 1, subName);
+ } else {
+ return !strcasecmp(nameToMatch.c_str(), certHostName.c_str());
+ }
+}
+
#else
+namespace mongo {
+namespace {
MONGO_INITIALIZER(SSLManager)(InitializerContext*) {
// we need a no-op initializer so that we can depend on SSLManager as a prerequisite in
// non-SSL builds.
return Status::OK();
}
+} // namespace
+} // namespace mongo
#endif // #ifdef MONGO_CONFIG_SSL
-} // namespace mongo