diff options
| author | Lucas de Castro Borges <lucas@gnuabordo.com.br> | 2025-02-11 15:07:35 -0300 |
|---|---|---|
| committer | Lucas de Castro Borges <lucas@gnuabordo.com.br> | 2025-02-11 15:07:35 -0300 |
| commit | 4cb8841196d0625dfa3825aa326f071cd27c7b8b (patch) | |
| tree | 1682a647d4463397c119183369ae6f750d5fdcff /src/mongo/util/net | |
| parent | aa03c6362cbaa767638e6eed9b031d86dd2643d1 (diff) | |
| parent | 8f0827553e09872941945a093b647a4211a9db7f (diff) | |
Update upstream source from tag 'upstream/6.0.0'master
Update to upstream version '6.0.0'
with Debian dir 5604a80ec1c96ca76f25f40d78e6ef855abec322
Diffstat (limited to 'src/mongo/util/net')
20 files changed, 120 insertions, 375 deletions
diff --git a/src/mongo/util/net/SConscript b/src/mongo/util/net/SConscript index 272cd9740a1..9aec6ba3150 100644 --- a/src/mongo/util/net/SConscript +++ b/src/mongo/util/net/SConscript @@ -33,9 +33,11 @@ env.Library( source=[ "ssl_options.cpp", ], + LIBDEPS=[ + '$BUILD_DIR/mongo/base', + ], LIBDEPS_PRIVATE=[ '$BUILD_DIR/mongo/db/server_options_core', - '$BUILD_DIR/mongo/idl/server_parameter', '$BUILD_DIR/mongo/util/options_parser/options_parser', ] ) @@ -62,13 +64,13 @@ env.Library( 'ssl_options_server.idl', ], LIBDEPS=[ + '$BUILD_DIR/mongo/base', 'ssl_options', ], LIBDEPS_PRIVATE=[ '$BUILD_DIR/mongo/db/auth/auth_options', '$BUILD_DIR/mongo/db/auth/cluster_auth_mode', '$BUILD_DIR/mongo/db/server_options_core', - '$BUILD_DIR/mongo/idl/server_parameter', '$BUILD_DIR/mongo/util/options_parser/options_parser', ] ) @@ -207,8 +209,6 @@ else: env.Library( target='http_client_impl', source=[ - 'http_client_options.idl', - 'http_client_options.cpp', 'http_client_winhttp.cpp' if env.TargetOSIs('windows') else 'http_client_curl.cpp', ], LIBDEPS=[ diff --git a/src/mongo/util/net/hostandport.cpp b/src/mongo/util/net/hostandport.cpp index f351b51b9b9..eb22852a926 100644 --- a/src/mongo/util/net/hostandport.cpp +++ b/src/mongo/util/net/hostandport.cpp @@ -52,13 +52,6 @@ StatusWith<HostAndPort> HostAndPort::parse(StringData text) { return StatusWith<HostAndPort>(result); } -Status validateHostAndPort(const std::string& hostAndPortStr) { - if (hostAndPortStr.empty()) { - return Status::OK(); - } - return HostAndPort::parse(hostAndPortStr).getStatus(); -} - HostAndPort::HostAndPort() : _port(-1) {} HostAndPort::HostAndPort(StringData text) { diff --git a/src/mongo/util/net/hostandport.h b/src/mongo/util/net/hostandport.h index 3c05c5d0c53..369437fb621 100644 --- a/src/mongo/util/net/hostandport.h +++ b/src/mongo/util/net/hostandport.h @@ -45,12 +45,6 @@ class StatusWith; class StringData; /** - * Validate that a string is either empty or is parseable to a HostAndPort. This is intended for use - * as an IDL validator callback. - */ -Status validateHostAndPort(const std::string& hostAndPortStr); - -/** * Name of a process on the network. * * Composed of some name component, followed optionally by a colon and a numeric port. The name diff --git a/src/mongo/util/net/hostname_canonicalization.cpp b/src/mongo/util/net/hostname_canonicalization.cpp index dd31e4b7015..f11ee345480 100644 --- a/src/mongo/util/net/hostname_canonicalization.cpp +++ b/src/mongo/util/net/hostname_canonicalization.cpp @@ -111,6 +111,7 @@ StatusWith<std::vector<std::string>> getHostFQDNs(std::string hostName, std::vector<std::string> getNameInfoErrors; for (shim_addrinfo* p = info; p; p = p->ai_next) { + std::stringstream getNameInfoError; shim_char host[NI_MAXHOST] = {}; if ((err = shim_getnameinfo( p->ai_addr, p->ai_addrlen, host, sizeof(host), nullptr, 0, NI_NAMEREQD)) == 0) { @@ -129,7 +130,6 @@ StatusWith<std::vector<std::string>> getHostFQDNs(std::string hostName, sin_addr = reinterpret_cast<void*>(&addr_in6->sin6_addr); } - std::stringstream getNameInfoError; if (sin_addr) { invariant(inet_ntop(p->ai_family, sin_addr, ip_str, sizeof(ip_str)) != nullptr); getNameInfoError << ip_str; @@ -138,8 +138,8 @@ StatusWith<std::vector<std::string>> getHostFQDNs(std::string hostName, } getNameInfoError << ": \"" << getAddrInfoStrError(err); - getNameInfoErrors.push_back(getNameInfoError.str()); } + getNameInfoErrors.push_back(getNameInfoError.str()); } if (!getNameInfoErrors.empty()) { @@ -150,8 +150,6 @@ StatusWith<std::vector<std::string>> getHostFQDNs(std::string hostName, "errors"_attr = getNameInfoErrors); } - LOGV2_DEBUG(7317600, 4, "Name info: {results}", "Name info", "results"_attr = results); - // Deduplicate the results list std::sort(results.begin(), results.end()); results.erase(std::unique(results.begin(), results.end()), results.end()); diff --git a/src/mongo/util/net/http_client_curl.cpp b/src/mongo/util/net/http_client_curl.cpp index 9db3c06f73f..fa1834c8bde 100644 --- a/src/mongo/util/net/http_client_curl.cpp +++ b/src/mongo/util/net/http_client_curl.cpp @@ -27,8 +27,6 @@ * it in the license file. */ -#define MONGO_LOGV2_DEFAULT_COMPONENT ::mongo::logv2::LogComponent::kNetwork - #include "mongo/platform/basic.h" #include <cstddef> @@ -49,24 +47,22 @@ #include "mongo/db/commands/server_status.h" #include "mongo/executor/connection_pool.h" #include "mongo/executor/connection_pool_stats.h" -#include "mongo/logv2/log.h" #include "mongo/platform/mutex.h" #include "mongo/stdx/unordered_map.h" #include "mongo/transport/transport_layer.h" #include "mongo/util/alarm.h" #include "mongo/util/alarm_runner_background_thread.h" #include "mongo/util/assert_util.h" -#include "mongo/util/bufreader.h" #include "mongo/util/concurrency/thread_pool.h" #include "mongo/util/functional.h" #include "mongo/util/net/hostandport.h" #include "mongo/util/net/http_client.h" -#include "mongo/util/net/http_client_options.h" #include "mongo/util/processinfo.h" #include "mongo/util/strong_weak_finish_line.h" #include "mongo/util/system_clock_source.h" #include "mongo/util/timer.h" + namespace mongo { namespace { @@ -163,40 +159,20 @@ size_t WriteMemoryCallback(void* ptr, size_t size, size_t nmemb, void* data) { */ size_t ReadMemoryCallback(char* buffer, size_t size, size_t nitems, void* instream) { - auto* bufReader = reinterpret_cast<BufReader*>(instream); + auto* cdrc = reinterpret_cast<ConstDataRangeCursor*>(instream); size_t ret = 0; - if (bufReader->remaining() > 0) { - size_t readSize = - std::min(size * nitems, static_cast<unsigned long>(bufReader->remaining())); - auto buf = bufReader->readBytes(readSize); - memcpy(buffer, buf.rawData(), readSize); + if (cdrc->length() > 0) { + size_t readSize = std::min(size * nitems, cdrc->length()); + memcpy(buffer, cdrc->data(), readSize); + invariant(cdrc->advanceNoThrow(readSize).isOK()); ret = readSize; } return ret; } -/** - * Seek into for data to the remote side - */ -size_t SeekMemoryCallback(void* clientp, curl_off_t offset, int origin) { - - // Curl will call this in readrewind but only to reset the stream to the beginning - // In other protocols (like FTP, SSH) or HTTP resumption they may ask for partial buffers which - // we do not support. - if (offset != 0 || origin != SEEK_SET) { - return CURL_SEEKFUNC_CANTSEEK; - } - - auto* bufReader = reinterpret_cast<BufReader*>(clientp); - - bufReader->rewindToStart(); - - return CURL_SEEKFUNC_OK; -} - struct CurlEasyCleanup { void operator()(CURL* handle) { if (handle) { @@ -220,47 +196,6 @@ long longSeconds(Seconds tm) { return static_cast<long>(durationCount<Seconds>(tm)); } - -StringData enumToString(curl_infotype type) { - switch (type) { - case CURLINFO_TEXT: - return "TEXT"_sd; - case CURLINFO_HEADER_IN: - return "HEADER_IN"_sd; - case CURLINFO_HEADER_OUT: - return "HEADER_OUT"_sd; - case CURLINFO_DATA_IN: - return "DATA_IN"_sd; - case CURLINFO_DATA_OUT: - return "DATA_OUT"_sd; - case CURLINFO_SSL_DATA_IN: - return "SSL_DATA_IN"_sd; - case CURLINFO_SSL_DATA_OUT: - return "SSL_DATA_OUT"_sd; - default: - return "unknown"_sd; - } -} - -int curlDebugCallback(CURL* handle, curl_infotype type, char* data, size_t size, void* clientp) { - switch (type) { - case CURLINFO_TEXT: - case CURLINFO_HEADER_IN: - case CURLINFO_HEADER_OUT: - case CURLINFO_DATA_IN: - case CURLINFO_DATA_OUT: - LOGV2_DEBUG(7661901, - 1, - "Curl", - "type"_attr = enumToString(type), - "message"_attr = StringData(data, size)); - [[fallthrough]]; - - default: - return 0; - } -} - CurlEasyHandle createCurlEasyHandle(Protocols protocol) { CurlEasyHandle handle(curl_easy_init()); uassert(ErrorCodes::InternalError, "Curl initialization failed", handle); @@ -291,10 +226,9 @@ CurlEasyHandle createCurlEasyHandle(Protocols protocol) { } // TODO: CURLOPT_EXPECT_100_TIMEOUT_MS? - if (httpClientOptions.verboseLogging.loadRelaxed()) { - curl_easy_setopt(handle.get(), CURLOPT_VERBOSE, 1); - curl_easy_setopt(handle.get(), CURLOPT_DEBUGFUNCTION, curlDebugCallback); - } + // TODO: consider making this configurable, defaults to stderr + // curl_easy_setopt(handle.get(), CURLOPT_VERBOSE, 1); + // curl_easy_setopt(_handle.get(), CURLOPT_DEBUGFUNCTION , ???); return handle; } @@ -696,7 +630,7 @@ private: curl_easy_setopt(handle, CURLOPT_CONNECTTIMEOUT, longSeconds(_connectTimeout)); - BufReader bufReader(cdr.data(), cdr.length()); + ConstDataRangeCursor cdrc(cdr); switch (method) { case HttpMethod::kGET: uassert(ErrorCodes::BadValue, @@ -711,22 +645,16 @@ private: curl_easy_setopt(handle, CURLOPT_POST, 1); curl_easy_setopt(handle, CURLOPT_READFUNCTION, ReadMemoryCallback); - curl_easy_setopt(handle, CURLOPT_READDATA, &bufReader); - curl_easy_setopt(handle, CURLOPT_POSTFIELDSIZE, (long)bufReader.remaining()); - - curl_easy_setopt(handle, CURLOPT_SEEKFUNCTION, SeekMemoryCallback); - curl_easy_setopt(handle, CURLOPT_SEEKDATA, &bufReader); + curl_easy_setopt(handle, CURLOPT_READDATA, &cdrc); + curl_easy_setopt(handle, CURLOPT_POSTFIELDSIZE, (long)cdrc.length()); break; case HttpMethod::kPUT: curl_easy_setopt(handle, CURLOPT_POST, 0); curl_easy_setopt(handle, CURLOPT_PUT, 1); curl_easy_setopt(handle, CURLOPT_READFUNCTION, ReadMemoryCallback); - curl_easy_setopt(handle, CURLOPT_READDATA, &bufReader); - curl_easy_setopt(handle, CURLOPT_INFILESIZE_LARGE, (long)bufReader.remaining()); - - curl_easy_setopt(handle, CURLOPT_SEEKFUNCTION, SeekMemoryCallback); - curl_easy_setopt(handle, CURLOPT_SEEKDATA, &bufReader); + curl_easy_setopt(handle, CURLOPT_READDATA, &cdrc); + curl_easy_setopt(handle, CURLOPT_INFILESIZE_LARGE, (long)cdrc.length()); break; default: MONGO_UNREACHABLE; diff --git a/src/mongo/util/net/http_client_options.cpp b/src/mongo/util/net/http_client_options.cpp deleted file mode 100644 index 7e96be222ac..00000000000 --- a/src/mongo/util/net/http_client_options.cpp +++ /dev/null @@ -1,36 +0,0 @@ -/** - * Copyright (C) 2023-present MongoDB, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the Server Side Public License, version 1, - * as published by MongoDB, Inc. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * Server Side Public License for more details. - * - * You should have received a copy of the Server Side Public License - * along with this program. If not, see - * <http://www.mongodb.com/licensing/server-side-public-license>. - * - * As a special exception, the copyright holders give permission to link the - * code of portions of this program with the OpenSSL library under certain - * conditions as described in each individual source file and distribute - * linked combinations including the program with the OpenSSL library. You - * must comply with the Server Side Public License in all respects for - * all of the code used other than as permitted herein. If you modify file(s) - * with this exception, you may extend this exception to your version of the - * file(s), but you are not obligated to do so. If you do not wish to do so, - * delete this exception statement from your version. If you delete this - * exception statement from all source files in the program, then also delete - * it in the license file. - */ - -#include "mongo/util/net/http_client_options.h" - -namespace mongo { - -HttpClientOptions httpClientOptions; - -} diff --git a/src/mongo/util/net/http_client_options.h b/src/mongo/util/net/http_client_options.h deleted file mode 100644 index ebf4611677a..00000000000 --- a/src/mongo/util/net/http_client_options.h +++ /dev/null @@ -1,46 +0,0 @@ -/** - * Copyright (C) 2023-present MongoDB, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the Server Side Public License, version 1, - * as published by MongoDB, Inc. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * Server Side Public License for more details. - * - * You should have received a copy of the Server Side Public License - * along with this program. If not, see - * <http://www.mongodb.com/licensing/server-side-public-license>. - * - * As a special exception, the copyright holders give permission to link the - * code of portions of this program with the OpenSSL library under certain - * conditions as described in each individual source file and distribute - * linked combinations including the program with the OpenSSL library. You - * must comply with the Server Side Public License in all respects for - * all of the code used other than as permitted herein. If you modify file(s) - * with this exception, you may extend this exception to your version of the - * file(s), but you are not obligated to do so. If you do not wish to do so, - * delete this exception statement from your version. If you delete this - * exception statement from all source files in the program, then also delete - * it in the license file. - */ - -#pragma once - -#include "mongo/platform/atomic_word.h" - -namespace mongo { -struct HttpClientOptions { - /** - * Boolean flag that indicates whether verbose logging for http clients should be enabled. - * - * Note: only affects new handles. This means that if connection pooling is in use, this will - * not take affect on existing connections. - */ - AtomicWord<bool> verboseLogging; -}; - -extern HttpClientOptions httpClientOptions; -} // namespace mongo diff --git a/src/mongo/util/net/http_client_options.idl b/src/mongo/util/net/http_client_options.idl deleted file mode 100644 index b53b5e5541b..00000000000 --- a/src/mongo/util/net/http_client_options.idl +++ /dev/null @@ -1,38 +0,0 @@ -# Copyright (C) 2023-present MongoDB, Inc. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the Server Side Public License, version 1, -# as published by MongoDB, Inc. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# Server Side Public License for more details. -# -# You should have received a copy of the Server Side Public License -# along with this program. If not, see -# <http://www.mongodb.com/licensing/server-side-public-license>. -# -# As a special exception, the copyright holders give permission to link the -# code of portions of this program with the OpenSSL library under certain -# conditions as described in each individual source file and distribute -# linked combinations including the program with the OpenSSL library. You -# must comply with the Server Side Public License in all respects for -# all of the code used other than as permitted herein. If you modify file(s) -# with this exception, you may extend this exception to your version of the -# file(s), but you are not obligated to do so. If you do not wish to do so, -# delete this exception statement from your version. If you delete this -# exception statement from all source files in the program, then also delete -# it in the license file. - -global: - cpp_namespace: "mongo" - cpp_includes: - - "mongo/util/net/http_client_options.h" - -server_parameters: - httpVerboseLogging: - description: Boolean flag that indicates whether verbose logging for http clients should be enabled. - set_at: [ startup, runtime ] - default: false - cpp_varname: "httpClientOptions.verboseLogging" diff --git a/src/mongo/util/net/ocsp/ocsp_manager.cpp b/src/mongo/util/net/ocsp/ocsp_manager.cpp index b8d0b2683dd..1524d1da560 100644 --- a/src/mongo/util/net/ocsp/ocsp_manager.cpp +++ b/src/mongo/util/net/ocsp/ocsp_manager.cpp @@ -68,6 +68,7 @@ void OCSPManager::start(ServiceContext* service) { void OCSPManager::shutdown(ServiceContext* service) { get(service)->_pool->shutdown(); + getOCSPManager(service).reset(); } OCSPManager::OCSPManager() { diff --git a/src/mongo/util/net/openssl_init.cpp b/src/mongo/util/net/openssl_init.cpp index 5ef31f1212b..89e5a1c4498 100644 --- a/src/mongo/util/net/openssl_init.cpp +++ b/src/mongo/util/net/openssl_init.cpp @@ -46,12 +46,6 @@ #include <stack> #include <vector> -#if OPENSSL_VERSION_NUMBER > 0x30000000L -#include <openssl/provider.h> -#endif - -#define MONGO_LOGV2_DEFAULT_COMPONENT ::mongo::logv2::LogComponent::kNetwork - namespace mongo { namespace { @@ -150,54 +144,21 @@ private: } }; -#if OPENSSL_VERSION_NUMBER > 0x30000000L -#define _SUPPORT_FIPS 1 - -OSSL_PROVIDER* fipsProvider; -OSSL_PROVIDER* baseProvider; - -void initFIPS() { - // OpenSSL 3 has a different FIPS design then previous OpenSSL. To load FIPS, we use the FIPS - // algorithm provider which we load into the "default" library context. - fipsProvider = OSSL_PROVIDER_load(NULL, "fips"); - if (fipsProvider == NULL) { - LOGV2_FATAL_NOTRACE( - 7585801, - "Failed to load OpenSSL 3 FIPS provider. OpenSSL was not compiled with FIPS support.", - "error"_attr = SSLManagerInterface::getSSLErrorMessage(ERR_get_error())); - } - - // Base provide has non-cryptographic algorihms (like encoding/decoding keys) - baseProvider = OSSL_PROVIDER_load(NULL, "base"); - if (baseProvider == NULL) { - LOGV2_FATAL_NOTRACE(7585802, - "Failed to load OpenSSL 3 Base provider", - "error"_attr = - SSLManagerInterface::getSSLErrorMessage(ERR_get_error())); - } -} -#elif defined(MONGO_CONFIG_HAVE_FIPS_MODE_SET) - -#define _SUPPORT_FIPS 1 - -void initFIPS() { +void setupFIPS() { +// Turn on FIPS mode if requested, OPENSSL_FIPS must be defined by the OpenSSL headers +#if defined(MONGO_CONFIG_HAVE_FIPS_MODE_SET) int status = FIPS_mode_set(1); if (!status) { - LOGV2_FATAL_NOTRACE(23173, - "Can't activate FIPS mode", - "error"_attr = - SSLManagerInterface::getSSLErrorMessage(ERR_get_error())); + LOGV2_FATAL(23173, + "can't activate FIPS mode: {error}", + "Can't activate FIPS mode", + "error"_attr = SSLManagerInterface::getSSLErrorMessage(ERR_get_error())); + fassertFailedNoTrace(16703); } -} -#endif - -void setupFIPS() { -// Turn on FIPS mode if requested, OPENSSL_FIPS must be defined by the OpenSSL headers -#if defined(_SUPPORT_FIPS) - initFIPS(); LOGV2(23172, "FIPS 140-2 mode activated"); #else - LOGV2_FATAL_NOTRACE(23174, "this version of mongodb was not compiled with FIPS support"); + LOGV2_FATAL(23174, "this version of mongodb was not compiled with FIPS support"); + fassertFailedNoTrace(17089); #endif } diff --git a/src/mongo/util/net/ssl_manager.cpp b/src/mongo/util/net/ssl_manager.cpp index c784c3792d6..2f4a6fb713f 100644 --- a/src/mongo/util/net/ssl_manager.cpp +++ b/src/mongo/util/net/ssl_manager.cpp @@ -38,7 +38,6 @@ #include <string> #include <vector> -#include "mongo/base/data_view.h" #include "mongo/base/init.h" #include "mongo/bson/bsonobjbuilder.h" #include "mongo/client/internal_auth.h" @@ -780,6 +779,7 @@ bool SSLConfiguration::isClusterMember(StringData subjectName) const { void SSLConfiguration::getServerStatusBSON(BSONObjBuilder* security) const { security->append("SSLServerSubjectName", _serverSubjectName.toString()); + security->appendBool("SSLServerHasCertificateAuthority", hasCA); security->appendDate("SSLServerCertificateExpirationDate", serverCertificateExpirationDate); } @@ -1048,7 +1048,7 @@ StatusWith<DERToken> DERToken::parse(ConstDataRange cdr, size_t* outLength) { derLength = ConstDataView(lengthBuffer.data()).read<BigEndian<uint64_t>>(); } else { // Length is <= 127 bytes, i.e. short form of length - derLength = ConstDataView(&initialLengthByte).read<uint8_t>(); + derLength = initialLengthByte; } // This is the total length of the TLV and all data diff --git a/src/mongo/util/net/ssl_manager_apple.cpp b/src/mongo/util/net/ssl_manager_apple.cpp index f3e0f4d6652..ec77dc17722 100644 --- a/src/mongo/util/net/ssl_manager_apple.cpp +++ b/src/mongo/util/net/ssl_manager_apple.cpp @@ -1369,15 +1369,20 @@ SSLManagerApple::SSLManagerApple(const SSLParams& params, bool isServer) } } - // If the user has specified --setParameter tlsUseSystemCA=true, then no params.sslCAFile nor - // params.sslClusterCAFile will be defined, and the SSL Manager will fall back to the System CA. if (!params.sslCAFile.empty()) { auto ca = uassertStatusOK(loadPEM(params.sslCAFile, "", kLoadPEMStripKeys)); _clientCA = std::move(ca); + _sslConfiguration.hasCA = _clientCA && ::CFArrayGetCount(_clientCA.get()); + } + + if (!params.sslCertificateSelector.empty() || !params.sslClusterCertificateSelector.empty()) { + // By using the system keychain, we acknowledge it exists. + _sslConfiguration.hasCA = true; } if (!_clientCA) { - // No explicit CA was specified, use the Keychain CA explicitly + // 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)); _clientCA.reset(certs); @@ -1552,6 +1557,17 @@ Future<SSLPeerInfo> SSLManagerApple::parseAndValidatePeerCertificate( recordTLSVersion(tlsVersionStatus.getValue(), hostForLogging); + /* While we always have a system CA via the Keychain, + * we'll pretend not to in terms of validation if the server + * was started using a PEM file (legacy mode). + * + * When a certificate selector is used, we'll override hasCA to true + * so that the validation path runs anyway. + */ + if (!_sslConfiguration.hasCA && isSSLServer) { + return Future<SSLPeerInfo>::makeReady(SSLPeerInfo(sniName)); + } + const auto badCert = [&](StringData msg, bool warn = false) -> Future<SSLPeerInfo> { if (warn) { LOGV2_WARNING(23209, @@ -1576,7 +1592,7 @@ Future<SSLPeerInfo> SSLManagerApple::parseAndValidatePeerCertificate( return SSLPeerInfo(sniName); } else { if (status == ::errSecSuccess) { - return badCert(str::stream() << "No SSL certificate provided by peer: " + return badCert(str::stream() << "no SSL certificate provided by peer: " << stringFromOSStatus(status), _weakValidation); } else { @@ -1654,14 +1670,11 @@ Future<SSLPeerInfo> SSLManagerApple::parseAndValidatePeerCertificate( return swPeerSubjectName.getStatus(); } const auto peerSubjectName = std::move(swPeerSubjectName.getValue()); - // The cipher will be presented as a number. - ::SSLCipherSuite cipher; - uassertOSStatusOK(::SSLGetNegotiatedCipher(ssl, &cipher)); - - LOGV2_INFO(6723803, - "Accepted TLS connection from peer", - "peerSubjectName"_attr = peerSubjectName, - "cipher"_attr = cipher); + LOGV2_DEBUG(23207, + 2, + "Accepted TLS connection from peer: {peerSubjectName}", + "Accepted TLS connection from peer", + "peerSubjectName"_attr = peerSubjectName); // Server side. if (remoteHost.empty()) { @@ -1874,26 +1887,8 @@ MONGO_INITIALIZER_WITH_PREREQUISITES(SSLManager, ("EndStartupOptionHandling")) kMongoDBRolesOID = ::CFStringCreateWithCString( nullptr, mongodbRolesOID.identifier.c_str(), ::kCFStringEncodingUTF8); - // TODO SERVER-67419 This retry logic is a workaround; reconsider this approach after - // investigation. - constexpr int kMaxRetries = 10; if (!isSSLServer || (sslGlobalParams.sslMode.load() != SSLParams::SSLMode_disabled)) { - for (int i = 0; i < kMaxRetries; i++) { - try { - theSSLManagerCoordinator = new SSLManagerCoordinator(); - return; - } catch (const ExceptionFor<ErrorCodes::InvalidSSLConfiguration>& e) { - bool isRetriableError = nullptr != strstr(e.what(), "No keychain is available."); - if (!isRetriableError || i == kMaxRetries - 1) { - // Rethrow if a different error or we fail on final iteration - throw; - } - LOGV2_INFO(6741800, - "Caught exception during apple SSLManagerCoordinator creation, retrying", - "try"_attr = i, - "error"_attr = e.what()); - } - } + theSSLManagerCoordinator = new SSLManagerCoordinator(); } } diff --git a/src/mongo/util/net/ssl_manager_openssl.cpp b/src/mongo/util/net/ssl_manager_openssl.cpp index 48461e4120d..f2ddee148c7 100644 --- a/src/mongo/util/net/ssl_manager_openssl.cpp +++ b/src/mongo/util/net/ssl_manager_openssl.cpp @@ -123,7 +123,12 @@ struct X509StackDeleter { } } }; -using UniqueStackOfX509 = std::unique_ptr<STACK_OF(X509), X509StackDeleter>; + +// If we have an X509 Stack that is owned by an internal SSL Object, we need to use this +// deleter. +struct X509StackDeleterNoOp { + void operator()(STACK_OF(X509) * chain) {} +}; // Modulus for Diffie-Hellman parameter 'ffdhe3072' defined in RFC 7919 constexpr std::array<std::uint8_t, 384> ffdhe3072_p = { @@ -319,6 +324,25 @@ X509* X509_OBJECT_get0_X509(const X509_OBJECT* a) { return a->data.x509; } +using UniqueVerifiedChainPolyfill = std::unique_ptr<STACK_OF(X509), X509StackDeleter>; + +STACK_OF(X509) * SSL_get0_verified_chain(SSL* s) { + auto* store = SSL_CTX_get_cert_store(SSL_get_SSL_CTX(s)); + UniqueX509 peer(SSL_get_peer_certificate(s)); + auto* peerChain = SSL_get_peer_cert_chain(s); + + UniqueX509StoreCtx ctx(X509_STORE_CTX_new()); + if (!X509_STORE_CTX_init(ctx.get(), store, peer.get(), peerChain)) { + return nullptr; + } + + if (X509_verify_cert(ctx.get()) <= 0) { + return nullptr; + } + + return X509_STORE_CTX_get1_chain(ctx.get()); +} + const OCSP_CERTID* OCSP_SINGLERESP_get0_id(const OCSP_SINGLERESP* single) { return single->certId; } @@ -351,23 +375,14 @@ static ASN1OID tlsFeatureOID("1.3.6.1.5.5.7.1.24", "tlsfeature", "TLS Feature"); static int const NID_tlsfeature = OBJ_create(tlsFeatureOID.identifier.c_str(), tlsFeatureOID.shortDescription.c_str(), tlsFeatureOID.longDescription.c_str()); -#endif - -UniqueStackOfX509 SSLgetVerifiedChain(SSL* s) { - auto* store = SSL_CTX_get_cert_store(SSL_get_SSL_CTX(s)); - auto* peerChain = SSL_get_peer_cert_chain(s); - UniqueX509 peer(SSL_get_peer_certificate(s)); - UniqueX509StoreCtx ctx(X509_STORE_CTX_new()); - if (!X509_STORE_CTX_init(ctx.get(), store, peer.get(), peerChain)) { - return nullptr; - } +#else +using UniqueVerifiedChainPolyfill = std::unique_ptr<STACK_OF(X509), X509StackDeleterNoOp>; - if (X509_verify_cert(ctx.get()) <= 0) { - return nullptr; - } +#endif - return UniqueStackOfX509(X509_STORE_CTX_get1_chain(ctx.get())); +UniqueVerifiedChainPolyfill SSLgetVerifiedChain(SSL* s) { + return UniqueVerifiedChainPolyfill(SSL_get0_verified_chain(s)); } SSLX509Name convertX509ToSSLX509Name(X509_NAME* x509Name) { @@ -641,7 +656,7 @@ std::vector<std::vector<unsigned char>> convertStackOfX509ToDERVec(STACK_OF(X509 } struct OCSPCacheKey { - OCSPCacheKey(UniqueX509 cert, SSL_CTX* context, UniqueStackOfX509 intermediateCerts) + OCSPCacheKey(UniqueX509 cert, SSL_CTX* context, UniqueVerifiedChainPolyfill intermediateCerts) : peerCert(std::move(cert)), context(context), intermediateCerts(std::move(intermediateCerts)), @@ -2539,8 +2554,6 @@ Status SSLManagerOpenSSL::initSSLContext(SSL_CTX* context, } } - // If the user has specified --setParameter tlsUseSystemCA=true, then no params.sslCAFile nor - // params.sslClusterCAFile will be defined, and the SSL Manager will fall back to the System CA. std::string cafile = params.sslCAFile; if (direction == ConnectionDirection::kIncoming && !params.sslClusterCAFile.empty()) { cafile = params.sslClusterCAFile; @@ -2955,6 +2968,7 @@ Status SSLManagerOpenSSL::_setupCA(SSL_CTX* context, const std::string& caFile) // Set SSL to require peer (client) certificate verification // if a certificate is presented SSL_CTX_set_verify(context, SSL_VERIFY_PEER, &SSLManagerOpenSSL::verify_cb); + _sslConfiguration.hasCA = true; return Status::OK(); } @@ -2979,7 +2993,7 @@ Status SSLManagerOpenSSL::_setupSystemCA(SSL_CTX* context) { << "(default certificate file: " << X509_get_default_cert_file() << ", " << "default certificate path: " << X509_get_default_cert_dir() << ")"}; } - SSL_CTX_set_verify(context, SSL_VERIFY_PEER, &SSLManagerOpenSSL::verify_cb); + return Status::OK(); } @@ -3219,6 +3233,9 @@ Future<SSLPeerInfo> SSLManagerOpenSSL::parseAndValidatePeerCertificate( recordTLSVersion(tlsVersionStatus.getValue(), hostForLogging); + if (!_sslConfiguration.hasCA && isSSLServer) + return SSLPeerInfo(sni); + UniqueX509 peerCert(SSL_get_peer_certificate(conn)); if (nullptr == peerCert) { // no certificate presented by peer @@ -3271,11 +3288,11 @@ Future<SSLPeerInfo> SSLManagerOpenSSL::parseAndValidatePeerCertificate( // TODO: check optional cipher restriction, using cert. auto peerSubject = getCertificateSubjectX509Name(peerCert.get()); - const auto cipher = SSL_get_current_cipher(conn); - LOGV2_INFO(6723801, - "Accepted TLS connection from peer", - "peerSubject"_attr = peerSubject, - "cipher"_attr = SSL_CIPHER_get_name(cipher)); + LOGV2_DEBUG(23229, + 2, + "Accepted TLS connection from peer: {peerSubject}", + "Accepted TLS connection from peer", + "peerSubject"_attr = peerSubject); StatusWith<stdx::unordered_set<RoleName>> swPeerCertificateRoles = _parsePeerRoles(peerCert.get()); diff --git a/src/mongo/util/net/ssl_manager_test.cpp b/src/mongo/util/net/ssl_manager_test.cpp index 913c8ba983b..1dd6585f7c1 100644 --- a/src/mongo/util/net/ssl_manager_test.cpp +++ b/src/mongo/util/net/ssl_manager_test.cpp @@ -780,5 +780,6 @@ TEST(SSLManager, InitContextNoSanWarning) { ASSERT_FALSE(isSanWarningWritten(getCapturedTextFormatLogMessages())); } + } // namespace } // namespace mongo diff --git a/src/mongo/util/net/ssl_manager_windows.cpp b/src/mongo/util/net/ssl_manager_windows.cpp index 7169e1eef1f..adf86ae847f 100644 --- a/src/mongo/util/net/ssl_manager_windows.cpp +++ b/src/mongo/util/net/ssl_manager_windows.cpp @@ -1284,9 +1284,11 @@ Status SSLManagerWindows::_loadCertificates(const SSLParams& params) { _clientCertificates[0] = std::get<0>(_clusterPEMCertificate).get(); } - // If the user has specified --setParameter tlsUseSystemCA=true, then no params.sslCAFile nor - // params.sslClusterCAFile will be defined, and the SSL Manager will fall back to the System CA. if (!params.sslCAFile.empty()) { + // SChannel always has a CA even when the user does not specify one + // The openssl implementations uses this to decide if it wants to do certificate validation + // on the server side. + _sslConfiguration.hasCA = true; auto swChain = readCertChains(params.sslCAFile, params.sslCRLFile); if (!swChain.isOK()) { @@ -1349,8 +1351,10 @@ Status SSLManagerWindows::_loadCertificates(const SSLParams& params) { if (!params.sslCAFile.empty()) { LOGV2_WARNING(23271, "Mixing certs from the system certificate store and PEM files. This may " - "produce unexpected results."); + "produced unexpected results."); } + + _sslConfiguration.hasCA = true; } if (_sslCertificate) { @@ -2003,6 +2007,9 @@ Future<SSLPeerInfo> SSLManagerWindows::parseAndValidatePeerCertificate( recordTLSVersion(tlsVersionStatus.getValue(), hostForLogging); + if (!_sslConfiguration.hasCA && isSSLServer) + return Future<SSLPeerInfo>::makeReady(SSLPeerInfo(sni)); + SECURITY_STATUS ss = QueryContextAttributes(ssl, SECPKG_ATTR_REMOTE_CERT_CONTEXT, &cert); if (ss == SEC_E_NO_CREDENTIALS) { // no certificate presented by peer @@ -2062,19 +2069,10 @@ Future<SSLPeerInfo> SSLManagerWindows::parseAndValidatePeerCertificate( return Future<SSLPeerInfo>::makeReady(SSLPeerInfo(sni)); } - SecPkgContext_CipherInfo cipherInfo; - SECURITY_STATUS ssCipher = QueryContextAttributes(ssl, SECPKG_ATTR_CIPHER_INFO, &cipherInfo); - if (ssCipher != SEC_E_OK) { - return Status(ErrorCodes::SSLHandshakeFailed, - str::stream() - << "QueryContextAttributes for connection info failed with" << ssCipher); - } - const auto cipher = std::wstring(cipherInfo.szCipherSuite); - - LOGV2_INFO(6723802, - "Accepted TLS connection from peer", - "peerSubjectName"_attr = peerSubjectName, - "cipher"_attr = toUtf8String(cipher)); + LOGV2_DEBUG(23270, + 2, + "Accepted TLS connection from peer: {peerSubjectName}", + "peerSubjectName"_attr = peerSubjectName); // If this is a server and client and server certificate are the same, log a warning. if (remoteHost.empty() && _sslConfiguration.serverSubjectName() == peerSubjectName) { diff --git a/src/mongo/util/net/ssl_options.h b/src/mongo/util/net/ssl_options.h index 13f7303704e..e58bedcd076 100644 --- a/src/mongo/util/net/ssl_options.h +++ b/src/mongo/util/net/ssl_options.h @@ -93,7 +93,6 @@ struct SSLParams { bool sslFIPSMode = false; // --sslFIPSMode bool sslAllowInvalidCertificates = false; // --sslAllowInvalidCertificates bool sslAllowInvalidHostnames = false; // --sslAllowInvalidHostnames - bool sslUseSystemCA = false; // --setParameter tlsUseSystemCA bool disableNonSSLConnectionLogging = false; // --setParameter disableNonSSLConnectionLogging=true bool disableNonSSLConnectionLoggingSet = false; diff --git a/src/mongo/util/net/ssl_options_server.cpp b/src/mongo/util/net/ssl_options_server.cpp index eb67d49e2c3..4612993df07 100644 --- a/src/mongo/util/net/ssl_options_server.cpp +++ b/src/mongo/util/net/ssl_options_server.cpp @@ -29,7 +29,6 @@ #define MONGO_LOGV2_DEFAULT_COMPONENT ::mongo::logv2::LogComponent::kControl -#include "mongo/base/error_codes.h" #include "mongo/platform/basic.h" #include "mongo/util/net/ssl_options.h" @@ -193,27 +192,14 @@ MONGO_STARTUP_OPTIONS_POST(SSLServerOptions)(InitializerContext*) { const auto clusterAuthMode = serverGlobalParams.startupClusterAuthMode; if (sslGlobalParams.sslMode.load() != SSLParams::SSLMode_disabled) { - uassert(ErrorCodes::InvalidOptions, - "Specifying a tlsClusterCAFile requires a tlsCAFile also be specified. See " - "https://dochub.mongodb.org/core/mongod" - "#std-option-mongod.--tlsClusterCAFile for details.", - sslGlobalParams.sslClusterCAFile.empty() || !sslGlobalParams.sslCAFile.empty()); - uassert(ErrorCodes::InvalidOptions, - "The use of both a CA File and the System Certificate store is not supported.", - !sslGlobalParams.sslUseSystemCA || sslGlobalParams.sslCAFile.empty()); - uassert(ErrorCodes::InvalidOptions, - "The use of TLS without specifying a chain of trust is no longer supported. See " - "https://jira.mongodb.org/browse/SERVER-72839 for details.", - sslGlobalParams.sslUseSystemCA || !sslGlobalParams.sslCAFile.empty()); - if (!sslGlobalParams.sslCRLFile.empty() && sslGlobalParams.sslCAFile.empty()) { - uasserted(ErrorCodes::BadValue, - "Specifying a tlsCRLFile requires a tlsCAFile also be specified."); - } bool usingCertifiateSelectors = params.count("net.tls.certificateSelector"); if (sslGlobalParams.sslPEMKeyFile.size() == 0 && !usingCertifiateSelectors) { uasserted(ErrorCodes::BadValue, "need tlsCertificateKeyFile or certificateSelector when TLS is enabled"); } + if (!sslGlobalParams.sslCRLFile.empty() && sslGlobalParams.sslCAFile.empty()) { + uasserted(ErrorCodes::BadValue, "need tlsCAFile with tlsCRLFile"); + } std::string sslCANotFoundError( "No TLS certificate validation can be performed since" diff --git a/src/mongo/util/net/ssl_options_server.idl b/src/mongo/util/net/ssl_options_server.idl index d69af991a11..58b05893a36 100644 --- a/src/mongo/util/net/ssl_options_server.idl +++ b/src/mongo/util/net/ssl_options_server.idl @@ -40,13 +40,6 @@ global: imports: - "mongo/idl/basic_types.idl" -server_parameters: - tlsUseSystemCA: - description: "Use System CA for certificate verification" - set_at: startup - cpp_varname: "sslGlobalParams.sslUseSystemCA" - default: false - configs: "net.tls.tlsOnNormalPorts": description: "Use TLS on configured ports" diff --git a/src/mongo/util/net/ssl_parameters.idl b/src/mongo/util/net/ssl_parameters.idl index 9b3222159bb..c0cc5ca2c63 100644 --- a/src/mongo/util/net/ssl_parameters.idl +++ b/src/mongo/util/net/ssl_parameters.idl @@ -87,7 +87,7 @@ server_parameters: when fetching OCSP Responses for peer certificate set_at: startup cpp_vartype: int - default: 4 + default: 5 cpp_varname: "gTLSOCSPVerifyTimeoutSecs" validator: gte: 1 diff --git a/src/mongo/util/net/ssl_types.h b/src/mongo/util/net/ssl_types.h index e129b549056..6f859ee01aa 100644 --- a/src/mongo/util/net/ssl_types.h +++ b/src/mongo/util/net/ssl_types.h @@ -122,6 +122,7 @@ public: SSLX509Name clientSubjectName; Date_t serverCertificateExpirationDate; + bool hasCA = false; private: SSLX509Name _serverSubjectName; |
