diff options
author | sviatlana_zuiko <sviatlana.zuiko@mongodb.com> | 2020-11-13 10:20:02 +0300 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2020-11-13 10:39:59 +0000 |
commit | 796ee2ee8b8a7bb146bfa7a45eafb4b075a55372 (patch) | |
tree | 7b4337f39b4b8eb7186ef2bb2be645313fc9430b /src/mongo | |
parent | 6675536b77436eccddc54d6b3513ecb862cf381c (diff) | |
download | mongo-796ee2ee8b8a7bb146bfa7a45eafb4b075a55372.tar.gz |
Revert "SERVER-51599: Allow creating an SSLConnectionContext from in-memory certificates"
This reverts commit 8b195f11cbb144685baa20486b497528c8dde667.
Diffstat (limited to 'src/mongo')
-rw-r--r-- | src/mongo/transport/transport_layer_asio.cpp | 2 | ||||
-rw-r--r-- | src/mongo/transport/transport_layer_asio_test.cpp | 4 | ||||
-rw-r--r-- | src/mongo/util/net/SConscript | 1 | ||||
-rw-r--r-- | src/mongo/util/net/ssl_manager.cpp | 22 | ||||
-rw-r--r-- | src/mongo/util/net/ssl_manager.h | 55 | ||||
-rw-r--r-- | src/mongo/util/net/ssl_manager_apple.cpp | 10 | ||||
-rw-r--r-- | src/mongo/util/net/ssl_manager_openssl.cpp | 313 | ||||
-rw-r--r-- | src/mongo/util/net/ssl_manager_test.cpp | 186 | ||||
-rw-r--r-- | src/mongo/util/net/ssl_manager_windows.cpp | 11 | ||||
-rw-r--r-- | src/mongo/util/net/ssl_options.h | 1 |
10 files changed, 73 insertions, 532 deletions
diff --git a/src/mongo/transport/transport_layer_asio.cpp b/src/mongo/transport/transport_layer_asio.cpp index 4fd4df156bc..0517f8d9af3 100644 --- a/src/mongo/transport/transport_layer_asio.cpp +++ b/src/mongo/transport/transport_layer_asio.cpp @@ -1199,7 +1199,6 @@ Status TransportLayerASIO::rotateCertificates(std::shared_ptr<SSLManagerInterfac Status status = newSSLContext->manager->initSSLContext( newSSLContext->ingress->native_handle(), sslParams, - TransientSSLParams(), SSLManagerInterface::ConnectionDirection::kIncoming); if (!status.isOK()) { return status; @@ -1220,7 +1219,6 @@ Status TransportLayerASIO::rotateCertificates(std::shared_ptr<SSLManagerInterfac Status status = newSSLContext->manager->initSSLContext( newSSLContext->egress->native_handle(), sslParams, - TransientSSLParams(), SSLManagerInterface::ConnectionDirection::kOutgoing); if (!status.isOK()) { return status; diff --git a/src/mongo/transport/transport_layer_asio_test.cpp b/src/mongo/transport/transport_layer_asio_test.cpp index 9764e952b2e..a7938e031ba 100644 --- a/src/mongo/transport/transport_layer_asio_test.cpp +++ b/src/mongo/transport/transport_layer_asio_test.cpp @@ -50,12 +50,12 @@ public: void startSession(transport::SessionHandle session) override { stdx::unique_lock<Latch> lk(_mutex); _sessions.push_back(std::move(session)); - LOGV2(2303201, "started session"); + LOGV2(23032, "started session"); _cv.notify_one(); } void endAllSessions(transport::Session::TagMask tags) override { - LOGV2(2303301, "end all sessions"); + LOGV2(23033, "end all sessions"); std::vector<transport::SessionHandle> old_sessions; { stdx::unique_lock<Latch> lock(_mutex); diff --git a/src/mongo/util/net/SConscript b/src/mongo/util/net/SConscript index adf8b0ec033..ea81c6d254c 100644 --- a/src/mongo/util/net/SConscript +++ b/src/mongo/util/net/SConscript @@ -231,7 +231,6 @@ if get_option('ssl') == 'on': ], LIBDEPS=[ '$BUILD_DIR/mongo/db/server_options_servers', - '$BUILD_DIR/mongo/transport/transport_layer', '$BUILD_DIR/mongo/util/cmdline_utils/cmdline_utils', '$BUILD_DIR/mongo/util/fail_point', 'network', diff --git a/src/mongo/util/net/ssl_manager.cpp b/src/mongo/util/net/ssl_manager.cpp index 87772d303c8..73884cabae0 100644 --- a/src/mongo/util/net/ssl_manager.cpp +++ b/src/mongo/util/net/ssl_manager.cpp @@ -335,9 +335,14 @@ std::shared_ptr<SSLManagerInterface> SSLManagerCoordinator::getSSLManager() { } void logCert(const CertInformationToLog& cert, StringData certType, const int logNum) { - auto attrs = cert.getDynamicAttributes(); - attrs.add("type", certType); - LOGV2(logNum, "Certificate information", attrs); + LOGV2(logNum, + "Certificate information", + "type"_attr = certType, + "subject"_attr = cert.subject.toString(), + "issuer"_attr = cert.issuer.toString(), + "thumbprint"_attr = hexblob::encode(cert.thumbprint.data(), cert.thumbprint.size()), + "notValidBefore"_attr = cert.validityNotBefore.toString(), + "notValidAfter"_attr = cert.validityNotAfter.toString()); } void logCRL(const CRLInformationToLog& crl, const int logNum) { @@ -348,18 +353,15 @@ void logCRL(const CRLInformationToLog& crl, const int logNum) { "notValidAfter"_attr = crl.validityNotAfter.toString()); } -void logSSLInfo(const SSLInformationToLog& info, - const int logNumPEM, - const int logNumCluster, - const int logNumCrl) { +void logSSLInfo(const SSLInformationToLog& info) { if (!(sslGlobalParams.sslPEMKeyFile.empty())) { - logCert(info.server, "Server", logNumPEM); + logCert(info.server, "Server", 4913010); } if (info.cluster.has_value()) { - logCert(info.cluster.get(), "Cluster", logNumCluster); + logCert(info.cluster.get(), "Cluster", 4913011); } if (info.crl.has_value()) { - logCRL(info.crl.get(), logNumCrl); + logCRL(info.crl.get(), 4913012); } } diff --git a/src/mongo/util/net/ssl_manager.h b/src/mongo/util/net/ssl_manager.h index 7004ad4892c..ab8447c439f 100644 --- a/src/mongo/util/net/ssl_manager.h +++ b/src/mongo/util/net/ssl_manager.h @@ -40,7 +40,6 @@ #include "mongo/base/string_data.h" #include "mongo/bson/bsonobj.h" #include "mongo/db/service_context.h" -#include "mongo/logv2/attribute_storage.h" #include "mongo/platform/atomic_word.h" #include "mongo/util/decorable.h" #include "mongo/util/net/sock.h" @@ -78,7 +77,6 @@ Status validateDisableNonTLSConnectionLogging(const bool&); #ifdef MONGO_CONFIG_SSL namespace mongo { struct SSLParams; -struct TransientSSLParams; #if MONGO_CONFIG_SSL_PROVIDER == MONGO_CONFIG_SSL_PROVIDER_OPENSSL typedef SSL_CTX* SSLContextType; @@ -166,28 +164,6 @@ struct CertInformationToLog { std::vector<char> thumbprint; Date_t validityNotBefore; Date_t validityNotAfter; - // If the certificate was loaded from file, this is the file name. If empty, - // it means the certificate came from memory payload. - std::optional<std::string> keyFile; - // If the certificate targets a particular cluster, this is cluster URI. If empty, - // it means the certificate is the default one for the local cluster. - std::optional<std::string> targetClusterURI; - - logv2::DynamicAttributes getDynamicAttributes() const { - logv2::DynamicAttributes attrs; - attrs.add("subject", subject); - attrs.add("issuer", issuer); - attrs.add("thumbprint", StringData(hexblob::encode(thumbprint.data(), thumbprint.size()))); - attrs.add("notValidBefore", validityNotBefore); - attrs.add("notValidAfter", validityNotAfter); - if (keyFile) { - attrs.add("keyFile", StringData(*keyFile)); - } - if (targetClusterURI) { - attrs.add("targetClusterURI", StringData(*targetClusterURI)); - } - return attrs; - } }; struct CRLInformationToLog { @@ -204,10 +180,6 @@ struct SSLInformationToLog { class SSLManagerInterface : public Decorable<SSLManagerInterface> { public: - /** - * Creates an instance of SSLManagerInterface. - * Note: as we normally have one instance of the manager, it cannot take TransientSSLParams. - */ static std::shared_ptr<SSLManagerInterface> create(const SSLParams& params, bool isServer); virtual ~SSLManagerInterface(); @@ -260,17 +232,6 @@ public: ERR_error_string_n(code, msg, msglen); return msg; } - - /** - * Utility class to capture a temporary string with SSL error message in DynamicAttributes. - */ - struct CaptureSSLErrorInAttrs { - CaptureSSLErrorInAttrs(logv2::DynamicAttributes& attrs) - : _captured(getSSLErrorMessage(ERR_get_error())) { - attrs.add("error", _captured); - } - std::string _captured; - }; #endif /** @@ -291,7 +252,6 @@ public: */ virtual Status initSSLContext(SSLContextType context, const SSLParams& params, - const TransientSSLParams& transientParams, ConnectionDirection direction) = 0; /** @@ -430,20 +390,5 @@ void recordTLSVersion(TLSVersion version, const HostAndPort& hostForLogging); void tlsEmitWarningExpiringClientCertificate(const SSLX509Name& peer); void tlsEmitWarningExpiringClientCertificate(const SSLX509Name& peer, Days days); -/** - * Logs the SSL information by dispatching to either logCert() or logCRL(). - */ -void logSSLInfo(const SSLInformationToLog& info, - const int logNumPEM = 4913010, - const int logNumCluster = 4913011, - const int logNumCrl = 4913012); - -/** - * Logs the certificate. - * @param certType human-readable description of the certificate type. - */ -void logCert(const CertInformationToLog& cert, StringData certType, const int logNum); -void logCRL(const CRLInformationToLog& crl, const int logNum); - } // namespace mongo #endif // #ifdef MONGO_CONFIG_SSL diff --git a/src/mongo/util/net/ssl_manager_apple.cpp b/src/mongo/util/net/ssl_manager_apple.cpp index 32191e54b02..16af08cb0b9 100644 --- a/src/mongo/util/net/ssl_manager_apple.cpp +++ b/src/mongo/util/net/ssl_manager_apple.cpp @@ -1251,8 +1251,7 @@ public: Status initSSLContext(asio::ssl::apple::Context* context, const SSLParams& params, - const TransientSSLParams& transientParams, - ConnectionDirection direction) override final; + ConnectionDirection direction) final; SSLConnectionInterface* connect(Socket* socket) final; SSLConnectionInterface* accept(Socket* socket, const char* initialBytes, int len) final; @@ -1311,16 +1310,14 @@ SSLManagerApple::SSLManagerApple(const SSLParams& params, bool isServer) _allowInvalidHostnames(params.sslAllowInvalidHostnames), _suppressNoCertificateWarning(params.suppressNoTLSPeerCertificateWarning) { - uassertStatusOK( - initSSLContext(&_clientCtx, params, TransientSSLParams(), ConnectionDirection::kOutgoing)); + uassertStatusOK(initSSLContext(&_clientCtx, params, ConnectionDirection::kOutgoing)); if (_clientCtx.certs) { _sslConfiguration.clientSubjectName = uassertStatusOK(certificateGetSubject(_clientCtx.certs.get())); } if (isServer) { - uassertStatusOK(initSSLContext( - &_serverCtx, params, TransientSSLParams(), ConnectionDirection::kIncoming)); + uassertStatusOK(initSSLContext(&_serverCtx, params, ConnectionDirection::kIncoming)); if (_serverCtx.certs) { uassertStatusOK( _sslConfiguration.setServerSubjectName(uassertStatusOK(certificateGetSubject( @@ -1394,7 +1391,6 @@ StatusWith<std::pair<::SSLProtocol, ::SSLProtocol>> parseProtocolRange(const SSL Status SSLManagerApple::initSSLContext(asio::ssl::apple::Context* context, const SSLParams& params, - const TransientSSLParams& transientParams, ConnectionDirection direction) { // Protocol Version. const auto swProto = parseProtocolRange(params); diff --git a/src/mongo/util/net/ssl_manager_openssl.cpp b/src/mongo/util/net/ssl_manager_openssl.cpp index a2f7bcc73e1..9fb60e83f6e 100644 --- a/src/mongo/util/net/ssl_manager_openssl.cpp +++ b/src/mongo/util/net/ssl_manager_openssl.cpp @@ -1128,7 +1128,7 @@ class SSLManagerOpenSSL : public SSLManagerInterface, public std::enable_shared_from_this<SSLManagerOpenSSL> { public: explicit SSLManagerOpenSSL(const SSLParams& params, bool isServer); - ~SSLManagerOpenSSL() final { + ~SSLManagerOpenSSL() { stopJobs(); } @@ -1138,7 +1138,6 @@ public: */ Status initSSLContext(SSL_CTX* context, const SSLParams& params, - const TransientSSLParams& transientParams, ConnectionDirection direction) final; SSLConnectionInterface* connect(Socket* socket) final; @@ -1242,19 +1241,6 @@ private: return StringData(_password->c_str()); } - /** - * This method can only return a cached password and never prompts. - * @returns cached password if available, error if password is not cached. - */ - StatusWith<StringData> fetchCachedPasswordNoPrompt() { - stdx::lock_guard<Latch> lock(_mutex); - if (_password->size()) { - return StringData(_password->c_str()); - } - return Status(ErrorCodes::UnknownError, - "Failed to return a cached password, cannot prompt."); - } - private: Mutex _mutex = MONGO_MAKE_LATCH("PasswordFetcher::_mutex"); SecureString _password; // Protected by _mutex @@ -1313,10 +1299,7 @@ private: * @param info as a pointer to the CertInformationToLog struct to populate * with the information. */ - static void _getX509CertInfo(UniqueX509& x509, - CertInformationToLog* info, - std::optional<StringData> keyFile, - std::optional<StringData> targetClusterURI); + void _getX509CertInfo(UniqueX509& x509, CertInformationToLog* info) const; /* * Retrieve and store CRL information from the provided CRL filename. @@ -1333,42 +1316,6 @@ private: /** @return true if was successful, otherwise false */ bool _setupPEM(SSL_CTX* context, const std::string& keyFile, PasswordFetcher* password); - /** - * @param payload in-memory payload of a PEM file - * @return true if was successful, otherwise false - */ - bool _setupPEMFromMemoryPayload(SSL_CTX* context, - const std::string& payload, - PasswordFetcher* password, - StringData targetClusterURI); - - /** - * Setup PEM from BIO, which could be file or memory input abstraction. - * @param inBio input BIO, where smart pointer is created with a custom deleter to call - * 'BIO_free()'. - * @param keyFile if the certificate was loaded from file, this is the file name. If empty, - * it means the certificate came from memory payload. - * @param targetClusterURI If the certificate targets a particular cluster, this is cluster URI. - * If empty, it means the certificate is the default one for the local cluster. - * @return true if was successful, otherwise false - */ - bool _setupPEMFromBIO(SSL_CTX* context, - UniqueBIO inBio, - PasswordFetcher* password, - std::optional<StringData> keyFile, - std::optional<StringData> targetClusterURI); - - /** - * Loads a certificate chain from memory into context. - * This method is intended to be a repalcement of API call SSL_CTX_use_certificate_chain_file() - * but using memory instead of file. - * @return true if was successful, otherwise false - */ - static bool _readCertificateChainFromMemory(SSL_CTX* context, - const std::string& payload, - PasswordFetcher* password, - std::optional<StringData> targetClusterURI); - /* * Set up an SSL context for certificate validation by loading a CA */ @@ -1395,25 +1342,10 @@ private: */ void _flushNetworkBIO(SSLConnectionOpenSSL* conn); - /* - * Utility method to process the result returned by password Fetcher. - */ - static int _processPasswordFetcherOutput(StatusWith<StringData>* fetcherResult, - char* buf, - int num, - int rwflag); - /** * Callbacks for SSL functions. */ - static int password_cb(char* buf, int num, int rwflag, void* userdata); - - /** - * Special flawor of password callback, which always fails. - * @return -1. - */ - static int always_error_password_cb(char* buf, int num, int rwflag, void* userdata); static int servername_cb(SSL* s, int* al, void* arg); static int verify_cb(int ok, X509_STORE_CTX* ctx); }; @@ -1582,28 +1514,20 @@ SSLManagerOpenSSL::SSLManagerOpenSSL(const SSLParams& params, bool isServer) } int SSLManagerOpenSSL::password_cb(char* buf, int num, int rwflag, void* userdata) { - invariant(userdata); - auto pwFetcher = static_cast<PasswordFetcher*>(userdata); - auto swPassword = pwFetcher->fetchPassword(); - return _processPasswordFetcherOutput(&swPassword, buf, num, rwflag); -} - -int SSLManagerOpenSSL::always_error_password_cb(char* buf, int num, int rwflag, void* userdata) { - return -1; -} - -int SSLManagerOpenSSL::_processPasswordFetcherOutput(StatusWith<StringData>* swPassword, - char* buf, - int num, - int rwflag) { // Unless OpenSSL misbehaves, num should always be positive fassert(17314, num > 0); + invariant(userdata); - if (!swPassword->isOK()) { - LOGV2_ERROR(23239, "Unable to fetch password", "error"_attr = swPassword->getStatus()); + auto pwFetcher = static_cast<PasswordFetcher*>(userdata); + auto swPassword = pwFetcher->fetchPassword(); + if (!swPassword.isOK()) { + LOGV2_ERROR(23239, + "Unable to fetch password: {error}", + "Unable to fetch password", + "error"_attr = swPassword.getStatus()); return -1; } - StringData password = std::move(swPassword->getValue()); + StringData password = std::move(swPassword.getValue()); const size_t copyCount = std::min(password.size(), static_cast<size_t>(num)); std::copy_n(password.begin(), copyCount, buf); @@ -2112,7 +2036,6 @@ Milliseconds SSLManagerOpenSSL::updateOcspStaplingContextWithResponse( Status SSLManagerOpenSSL::initSSLContext(SSL_CTX* context, const SSLParams& params, - const TransientSSLParams& transientParams, ConnectionDirection direction) { // SSL_OP_ALL - Activate all bug workaround options, to support buggy client SSL's. // SSL_OP_NO_SSLv2 - Disable SSL v2 support @@ -2174,21 +2097,7 @@ Status SSLManagerOpenSSL::initSSLContext(SSL_CTX* context, << getSSLErrorMessage(ERR_get_error())); } - - if (direction == ConnectionDirection::kOutgoing && - !transientParams.sslClusterPEMPayload.empty()) { - - // Transient params for outgoing connection have priority over global params. - if (!_setupPEMFromMemoryPayload( - context, - transientParams.sslClusterPEMPayload, - &_clusterPEMPassword, - transientParams.targetedClusterConnectionString.toString())) { - return Status(ErrorCodes::InvalidSSLConfiguration, - str::stream() << "Can not set up transient ssl cluster certificate for " - << transientParams.targetedClusterConnectionString); - } - } else if (direction == ConnectionDirection::kOutgoing && params.tlsWithholdClientCertificate) { + if (direction == ConnectionDirection::kOutgoing && params.tlsWithholdClientCertificate) { // Do not send a client certificate if they have been suppressed. } else if (direction == ConnectionDirection::kOutgoing && !params.sslClusterFile.empty()) { @@ -2286,7 +2195,7 @@ bool SSLManagerOpenSSL::_initSynchronousSSLContext(UniqueSSLContext* contextPtr, ConnectionDirection direction) { *contextPtr = UniqueSSLContext(SSL_CTX_new(SSLv23_method())); - uassertStatusOK(initSSLContext(contextPtr->get(), params, TransientSSLParams(), direction)); + uassertStatusOK(initSSLContext(contextPtr->get(), params, direction)); // If renegotiation is needed, don't return from recv() or send() until it's successful. // Note: this is for blocking sockets only. @@ -2302,6 +2211,7 @@ bool SSLManagerOpenSSL::_parseAndValidateCertificate(const std::string& keyFile, BIO* inBIO = BIO_new(BIO_s_file()); if (inBIO == nullptr) { LOGV2_ERROR(23243, + "failed to allocate BIO object: {error}", "Failed to allocate BIO object", "error"_attr = getSSLErrorMessage(ERR_get_error())); return false; @@ -2310,6 +2220,7 @@ bool SSLManagerOpenSSL::_parseAndValidateCertificate(const std::string& keyFile, ON_BLOCK_EXIT([&] { BIO_free(inBIO); }); if (BIO_read_filename(inBIO, keyFile.c_str()) <= 0) { LOGV2_ERROR(23244, + "cannot read key file when setting subject name: {keyFile} {error}", "Cannot read key file when setting subject name", "keyFile"_attr = keyFile, "error"_attr = getSSLErrorMessage(ERR_get_error())); @@ -2320,6 +2231,7 @@ bool SSLManagerOpenSSL::_parseAndValidateCertificate(const std::string& keyFile, inBIO, nullptr, &SSLManagerOpenSSL::password_cb, static_cast<void*>(&keyPassword)); if (x509 == nullptr) { LOGV2_ERROR(23245, + "cannot retrieve certificate from keyfile: {keyFile} {error}", "Cannot retrieve certificate from keyfile", "keyFile"_attr = keyFile, "error"_attr = getSSLErrorMessage(ERR_get_error())); @@ -2351,177 +2263,66 @@ bool SSLManagerOpenSSL::_parseAndValidateCertificate(const std::string& keyFile, return true; } -// static -bool SSLManagerOpenSSL::_readCertificateChainFromMemory( - SSL_CTX* context, - const std::string& payload, - PasswordFetcher* password, - std::optional<StringData> targetClusterURI) { - - logv2::DynamicAttributes errorAttrs; - if (targetClusterURI) { - errorAttrs.add("targetClusterURI", *targetClusterURI); - } - - ERR_clear_error(); // Clear error stack for SSL_CTX_use_certificate(). - - // Note: old versions of SSL take (void*) here but it's still R/O. -#if OPENSSL_VERSION_NUMBER <= 0x1000114fL - UniqueBIO inBio(BIO_new_mem_buf(const_cast<char*>(payload.c_str()), payload.length())); -#else - UniqueBIO inBio(BIO_new_mem_buf(payload.c_str(), payload.length())); -#endif - - if (!inBio) { - CaptureSSLErrorInAttrs capture(errorAttrs); - LOGV2_ERROR(5159905, "Failed to allocate BIO from in memory payload", errorAttrs); - return false; - } - - auto password_cb = - &SSLManagerOpenSSL::always_error_password_cb; // We don't expect a password to be required. - void* userdata = static_cast<void*>(password); - UniqueX509 x509cert(PEM_read_bio_X509_AUX(inBio.get(), NULL, password_cb, userdata)); - - if (!x509cert) { - CaptureSSLErrorInAttrs capture(errorAttrs); - LOGV2_ERROR(5159906, "Failed to read the X509 certificate from memory", errorAttrs); - return false; - } - - CertInformationToLog debugInfo; - _getX509CertInfo(x509cert, &debugInfo, std::nullopt, targetClusterURI); - logCert(debugInfo, "", 5159903); - - // SSL_CTX_use_certificate increments the refcount on cert. - if (1 != SSL_CTX_use_certificate(context, x509cert.get())) { - CaptureSSLErrorInAttrs capture(errorAttrs); - LOGV2_ERROR(5159907, "Failed to use the X509 certificate loaded from memory", errorAttrs); - return false; - } - - // If we could set up our certificate, now proceed to the CA certificates. - UniqueX509 ca; -#if OPENSSL_VERSION_NUMBER >= 0x100010fFL - SSL_CTX_clear_chain_certs(context); -#else - SSL_CTX_clear_extra_chain_certs(context); -#endif - while ((ca = UniqueX509(PEM_read_bio_X509(inBio.get(), NULL, password_cb, userdata)))) { -#if OPENSSL_VERSION_NUMBER >= 0x100010fFL - if (1 != SSL_CTX_add1_chain_cert(context, ca.get())) { -#else - if (1 != SSL_CTX_add_extra_chain_cert(context, ca.release())) { -#endif - CaptureSSLErrorInAttrs capture(errorAttrs); - LOGV2_ERROR( - 5159908, "Failed to use the CA X509 certificate loaded from memory", errorAttrs); - return false; - } - _getX509CertInfo(ca, &debugInfo, std::nullopt, targetClusterURI); - logCert(debugInfo, "", 5159902); - } - // When the while loop ends, it's usually just EOF. - auto err = ERR_peek_last_error(); - if (ERR_GET_LIB(err) == ERR_LIB_PEM && ERR_GET_REASON(err) == PEM_R_NO_START_LINE) { - ERR_clear_error(); - } else { - CaptureSSLErrorInAttrs capture(errorAttrs); - LOGV2_ERROR( - 5159909, "Error remained after scanning all X509 certificates from memory", errorAttrs); - return false; // Some real error. - } - - return true; -} - bool SSLManagerOpenSSL::_setupPEM(SSL_CTX* context, const std::string& keyFile, PasswordFetcher* password) { - logv2::DynamicAttributes errorAttrs; - errorAttrs.add("keyFile", keyFile); - if (SSL_CTX_use_certificate_chain_file(context, keyFile.c_str()) != 1) { - CaptureSSLErrorInAttrs capture(errorAttrs); - LOGV2_ERROR(23248, "Cannot read certificate file", errorAttrs); + LOGV2_ERROR(23248, + "cannot read certificate file: {keyFile} {error}", + "Cannot read certificate file", + "keyFile"_attr = keyFile, + "error"_attr = getSSLErrorMessage(ERR_get_error())); return false; } - UniqueBIO inBio(BIO_new(BIO_s_file())); - + BIO* inBio = BIO_new(BIO_s_file()); if (!inBio) { - CaptureSSLErrorInAttrs capture(errorAttrs); - LOGV2_ERROR(23249, "Failed to allocate BIO object", errorAttrs); - return false; - } - - if (BIO_read_filename(inBio.get(), keyFile.c_str()) <= 0) { - CaptureSSLErrorInAttrs capture(errorAttrs); - LOGV2_ERROR(23250, "Cannot read PEM key file", errorAttrs); - return false; - } - return _setupPEMFromBIO(context, std::move(inBio), password, keyFile, std::nullopt); -} - -bool SSLManagerOpenSSL::_setupPEMFromMemoryPayload(SSL_CTX* context, - const std::string& payload, - PasswordFetcher* password, - StringData targetClusterURI) { - logv2::DynamicAttributes errorAttrs; - errorAttrs.add("targetClusterURI", targetClusterURI); - - if (!_readCertificateChainFromMemory(context, payload, password, targetClusterURI)) { + LOGV2_ERROR(23249, + "failed to allocate BIO object: {error}", + "Failed to allocate BIO object", + "error"_attr = getSSLErrorMessage(ERR_get_error())); return false; } -#if OPENSSL_VERSION_NUMBER <= 0x1000114fL - UniqueBIO inBio(BIO_new_mem_buf(const_cast<char*>(payload.c_str()), payload.length())); -#else - UniqueBIO inBio(BIO_new_mem_buf(payload.c_str(), payload.length())); -#endif + const auto bioGuard = makeGuard([&inBio]() { BIO_free(inBio); }); - if (!inBio) { - CaptureSSLErrorInAttrs capture(errorAttrs); - LOGV2_ERROR(5159901, "Failed to allocate BIO object from in-memory payload", errorAttrs); + if (BIO_read_filename(inBio, keyFile.c_str()) <= 0) { + LOGV2_ERROR(23250, + "cannot read PEM key file: {keyFile} {error}", + "Cannot read PEM key file", + "keyFile"_attr = keyFile, + "error"_attr = getSSLErrorMessage(ERR_get_error())); return false; } - return _setupPEMFromBIO(context, std::move(inBio), password, std::nullopt, targetClusterURI); -} - -bool SSLManagerOpenSSL::_setupPEMFromBIO(SSL_CTX* context, - UniqueBIO inBio, - PasswordFetcher* password, - std::optional<StringData> keyFile, - std::optional<StringData> targetClusterURI) { - logv2::DynamicAttributes errorAttrs; - if (keyFile) { - errorAttrs.add("keyFile", *keyFile); - } - if (targetClusterURI) { - errorAttrs.add("targetClusterURI", *targetClusterURI); - } - // Obtain the private key, using our callback to acquire a decryption password if necessary. - auto password_cb = &SSLManagerOpenSSL::password_cb; + decltype(&SSLManagerOpenSSL::password_cb) password_cb = &SSLManagerOpenSSL::password_cb; void* userdata = static_cast<void*>(password); - EVP_PKEY* privateKey = PEM_read_bio_PrivateKey(inBio.get(), nullptr, password_cb, userdata); + EVP_PKEY* privateKey = PEM_read_bio_PrivateKey(inBio, nullptr, password_cb, userdata); if (!privateKey) { - CaptureSSLErrorInAttrs capture(errorAttrs); - LOGV2_ERROR(23251, "Cannot read PEM key", errorAttrs); + LOGV2_ERROR(23251, + "cannot read PEM key file: {keyFile} {error}", + "Cannot read PEM key file", + "keyFile"_attr = keyFile, + "error"_attr = getSSLErrorMessage(ERR_get_error())); return false; } const auto privateKeyGuard = makeGuard([&privateKey]() { EVP_PKEY_free(privateKey); }); if (SSL_CTX_use_PrivateKey(context, privateKey) != 1) { - CaptureSSLErrorInAttrs capture(errorAttrs); - LOGV2_ERROR(23252, "Cannot use PEM key", errorAttrs); + LOGV2_ERROR(23252, + "cannot use PEM key file: {keyFile} {error}", + "Cannot use PEM key file", + "keyFile"_attr = keyFile, + "error"_attr = getSSLErrorMessage(ERR_get_error())); return false; } // Verify that the certificate and the key go together. if (SSL_CTX_check_private_key(context) != 1) { - CaptureSSLErrorInAttrs capture(errorAttrs); - LOGV2_ERROR(23253, "SSL certificate validation failed", errorAttrs); + LOGV2_ERROR(23253, + "SSL certificate validation failed: {error}", + "SSL certificate validation failed", + "error"_attr = getSSLErrorMessage(ERR_get_error())); return false; } @@ -3182,11 +2983,7 @@ UniqueX509 SSLManagerOpenSSL::_getX509Object(StringData keyFile, constexpr size_t kSHA1HashBytes = 20; -// static -void SSLManagerOpenSSL::_getX509CertInfo(UniqueX509& x509, - CertInformationToLog* info, - std::optional<StringData> keyFile, - std::optional<StringData> targetClusterURI) { +void SSLManagerOpenSSL::_getX509CertInfo(UniqueX509& x509, CertInformationToLog* info) const { info->subject = getCertificateSubjectX509Name(x509.get()); info->issuer = convertX509ToSSLX509Name(X509_get_issuer_name(x509.get())); @@ -3205,11 +3002,6 @@ void SSLManagerOpenSSL::_getX509CertInfo(UniqueX509& x509, info->validityNotAfter = notAfterMillis; uassert(4913004, "date conversion failed", notAfterMillis != Date_t()); - - if (keyFile) - info->keyFile = keyFile->toString(); - if (targetClusterURI) - info->targetClusterURI = targetClusterURI->toString(); } @@ -3260,15 +3052,14 @@ SSLInformationToLog SSLManagerOpenSSL::getSSLInformationToLog() const { if (!(sslGlobalParams.sslPEMKeyFile.empty())) { UniqueX509 serverX509Cert = _getX509Object(sslGlobalParams.sslPEMKeyFile, &_serverPEMPassword); - _getX509CertInfo(serverX509Cert, &info.server, sslGlobalParams.sslPEMKeyFile, std::nullopt); + _getX509CertInfo(serverX509Cert, &info.server); } if (!(sslGlobalParams.sslClusterFile.empty())) { CertInformationToLog clusterInfo; UniqueX509 clusterX509Cert = _getX509Object(sslGlobalParams.sslClusterFile, &_clusterPEMPassword); - _getX509CertInfo( - clusterX509Cert, &clusterInfo, sslGlobalParams.sslClusterFile, std::nullopt); + _getX509CertInfo(clusterX509Cert, &clusterInfo); info.cluster = clusterInfo; } else { info.cluster = boost::none; diff --git a/src/mongo/util/net/ssl_manager_test.cpp b/src/mongo/util/net/ssl_manager_test.cpp index b68713f4b1e..781707b14a9 100644 --- a/src/mongo/util/net/ssl_manager_test.cpp +++ b/src/mongo/util/net/ssl_manager_test.cpp @@ -29,15 +29,9 @@ #define MONGO_LOGV2_DEFAULT_COMPONENT ::mongo::logv2::LogComponent::kTest -#include <fstream> - #include "mongo/platform/basic.h" -#include "mongo/transport/service_entry_point.h" -#include "mongo/transport/transport_layer_asio.h" -#include "mongo/util/net/ssl/context_base.hpp" #include "mongo/util/net/ssl_manager.h" -#include "mongo/util/net/ssl_options.h" #include "mongo/config.h" #include "mongo/logv2/log.h" @@ -45,76 +39,11 @@ #if MONGO_CONFIG_SSL_PROVIDER == MONGO_CONFIG_SSL_PROVIDER_OPENSSL #include "mongo/util/net/dh_openssl.h" -#include "mongo/util/net/ssl/context_openssl.hpp" #endif namespace mongo { namespace { - - -// Test implementation needed by ASIO transport. -class ServiceEntryPointUtil : public ServiceEntryPoint { -public: - void startSession(transport::SessionHandle session) override { - stdx::unique_lock<Latch> lk(_mutex); - _sessions.push_back(std::move(session)); - LOGV2(2303202, "started session"); - _cv.notify_one(); - } - - void endAllSessions(transport::Session::TagMask tags) override { - LOGV2(2303302, "end all sessions"); - std::vector<transport::SessionHandle> old_sessions; - { - stdx::unique_lock<Latch> lock(_mutex); - old_sessions.swap(_sessions); - } - old_sessions.clear(); - } - - Status start() override { - return Status::OK(); - } - - bool shutdown(Milliseconds timeout) override { - return true; - } - - void appendStats(BSONObjBuilder*) const override {} - - size_t numOpenSessions() const override { - stdx::unique_lock<Latch> lock(_mutex); - return _sessions.size(); - } - - Future<DbResponse> handleRequest(OperationContext* opCtx, - const Message& request) noexcept override { - MONGO_UNREACHABLE; - } - - void setTransportLayer(transport::TransportLayer* tl) { - _transport = tl; - } - - void waitForConnect() { - stdx::unique_lock<Latch> lock(_mutex); - _cv.wait(lock, [&] { return !_sessions.empty(); }); - } - -private: - mutable Mutex _mutex = MONGO_MAKE_LATCH("::_mutex"); - stdx::condition_variable _cv; - std::vector<transport::SessionHandle> _sessions; - transport::TransportLayer* _transport = nullptr; -}; - -std::string LoadFile(const std::string& name) { - std::ifstream input(name); - std::string str((std::istreambuf_iterator<char>(input)), std::istreambuf_iterator<char>()); - return str; -} - TEST(SSLManager, matchHostname) { enum Expected : bool { match = true, mismatch = false }; const struct { @@ -486,120 +415,5 @@ TEST(SSLManager, BadDNParsing) { } } -TEST(SSLManager, RotateCertificatesFromFile) { - SSLParams params; - params.sslMode.store(::mongo::sslGlobalParams.SSLMode_requireSSL); - // Server is required to have the sslPEMKeyFile. - params.sslPEMKeyFile = "jstests/libs/server.pem"; - params.sslCAFile = "jstests/libs/ca.pem"; - params.sslClusterFile = "jstests/libs/client.pem"; - - std::shared_ptr<SSLManagerInterface> manager = - SSLManagerInterface::create(params, true /* isSSLServer */); - - ServiceEntryPointUtil sepu; - - auto options = [] { - ServerGlobalParams params; - params.noUnixSocket = true; - transport::TransportLayerASIO::Options opts(¶ms); - return opts; - }(); - transport::TransportLayerASIO tla(options, &sepu); - uassertStatusOK(tla.rotateCertificates(manager, false /* asyncOCSPStaple */)); -} - -TEST(SSLManager, InitContextFromFileShouldFail) { - SSLParams params; - params.sslMode.store(::mongo::sslGlobalParams.SSLMode_requireSSL); - // Server is required to have the sslPEMKeyFile. - // We force the initialization to fail by omitting this param. - params.sslCAFile = "jstests/libs/ca.pem"; - params.sslClusterFile = "jstests/libs/client.pem"; - - ASSERT_THROWS_CODE([¶ms] { SSLManagerInterface::create(params, true /* isSSLServer */); }(), - DBException, - 16942); -} - -TEST(SSLManager, RotateClusterCertificatesFromFile) { - SSLParams params; - params.sslMode.store(::mongo::sslGlobalParams.SSLMode_requireSSL); - // Client doesn't need params.sslPEMKeyFile. - params.sslCAFile = "jstests/libs/ca.pem"; - params.sslClusterFile = "jstests/libs/client.pem"; - - std::shared_ptr<SSLManagerInterface> manager = - SSLManagerInterface::create(params, false /* isSSLServer */); - - ServiceEntryPointUtil sepu; - - auto options = [] { - ServerGlobalParams params; - params.noUnixSocket = true; - transport::TransportLayerASIO::Options opts(¶ms); - return opts; - }(); - transport::TransportLayerASIO tla(options, &sepu); - uassertStatusOK(tla.rotateCertificates(manager, false /* asyncOCSPStaple */)); -} - -#if MONGO_CONFIG_SSL_PROVIDER != MONGO_CONFIG_SSL_PROVIDER_APPLE - -TEST(SSLManager, InitContextFromFile) { - SSLParams params; - params.sslMode.store(::mongo::sslGlobalParams.SSLMode_requireSSL); - // Client doesn't need params.sslPEMKeyFile. - params.sslClusterFile = "jstests/libs/client.pem"; - - std::shared_ptr<SSLManagerInterface> manager = - SSLManagerInterface::create(params, false /* isSSLServer */); - - auto egress = std::make_unique<asio::ssl::context>(asio::ssl::context::sslv23); - uassertStatusOK(manager->initSSLContext(egress->native_handle(), - params, - TransientSSLParams(), - SSLManagerInterface::ConnectionDirection::kOutgoing)); -} - -TEST(SSLManager, InitContextFromMemory) { - SSLParams params; - params.sslMode.store(::mongo::sslGlobalParams.SSLMode_requireSSL); - params.sslCAFile = "jstests/libs/ca.pem"; - - TransientSSLParams transientParams; - transientParams.sslClusterPEMPayload = LoadFile("jstests/libs/client.pem"); - - std::shared_ptr<SSLManagerInterface> manager = - SSLManagerInterface::create(params, false /* isSSLServer */); - - auto egress = std::make_unique<asio::ssl::context>(asio::ssl::context::sslv23); - uassertStatusOK(manager->initSSLContext(egress->native_handle(), - params, - transientParams, - SSLManagerInterface::ConnectionDirection::kOutgoing)); -} - -TEST(SSLManager, InitServerSideContextFromMemory) { - SSLParams params; - params.sslMode.store(::mongo::sslGlobalParams.SSLMode_requireSSL); - params.sslPEMKeyFile = "jstests/libs/server.pem"; - params.sslCAFile = "jstests/libs/ca.pem"; - - TransientSSLParams transientParams; - transientParams.sslClusterPEMPayload = LoadFile("jstests/libs/client.pem"); - - std::shared_ptr<SSLManagerInterface> manager = - SSLManagerInterface::create(params, true /* isSSLServer */); - - auto egress = std::make_unique<asio::ssl::context>(asio::ssl::context::sslv23); - uassertStatusOK(manager->initSSLContext(egress->native_handle(), - params, - transientParams, - SSLManagerInterface::ConnectionDirection::kOutgoing)); -} - -#endif - } // namespace } // namespace mongo diff --git a/src/mongo/util/net/ssl_manager_windows.cpp b/src/mongo/util/net/ssl_manager_windows.cpp index edaf395f139..ad938405d62 100644 --- a/src/mongo/util/net/ssl_manager_windows.cpp +++ b/src/mongo/util/net/ssl_manager_windows.cpp @@ -269,8 +269,7 @@ public: */ Status initSSLContext(SCHANNEL_CRED* cred, const SSLParams& params, - const TransientSSLParams& transientParams, - ConnectionDirection direction) override final; + ConnectionDirection direction) final; SSLConnectionInterface* connect(Socket* socket) final; @@ -416,8 +415,7 @@ SSLManagerWindows::SSLManagerWindows(const SSLParams& params, bool isServer) uassertStatusOK(_loadCertificates(params)); - uassertStatusOK( - initSSLContext(&_clientCred, params, TransientSSLParams(), ConnectionDirection::kOutgoing)); + uassertStatusOK(initSSLContext(&_clientCred, params, ConnectionDirection::kOutgoing)); // Certificates may not have been loaded. This typically occurs in unit tests. if (_clientCertificates[0] != nullptr) { @@ -427,8 +425,7 @@ SSLManagerWindows::SSLManagerWindows(const SSLParams& params, bool isServer) // SSL server specific initialization if (isServer) { - uassertStatusOK(initSSLContext( - &_serverCred, params, TransientSSLParams(), ConnectionDirection::kIncoming)); + uassertStatusOK(initSSLContext(&_serverCred, params, ConnectionDirection::kIncoming)); if (_serverCertificates[0] != nullptr) { SSLX509Name subjectName; @@ -1354,7 +1351,6 @@ Status SSLManagerWindows::_loadCertificates(const SSLParams& params) { Status SSLManagerWindows::initSSLContext(SCHANNEL_CRED* cred, const SSLParams& params, - const TransientSSLParams& transientParams, ConnectionDirection direction) { memset(cred, 0, sizeof(*cred)); @@ -1447,7 +1443,6 @@ SSLConnectionInterface* SSLManagerWindows::accept(Socket* socket, void SSLManagerWindows::_handshake(SSLConnectionWindows* conn, bool client) { initSSLContext(conn->_cred, getSSLGlobalParams(), - TransientSSLParams(), client ? SSLManagerInterface::ConnectionDirection::kOutgoing : SSLManagerInterface::ConnectionDirection::kIncoming); diff --git a/src/mongo/util/net/ssl_options.h b/src/mongo/util/net/ssl_options.h index e58bedcd076..755cfb030c3 100644 --- a/src/mongo/util/net/ssl_options.h +++ b/src/mongo/util/net/ssl_options.h @@ -134,6 +134,7 @@ struct SSLParams { extern SSLParams sslGlobalParams; + // Additional SSL Params that could be used to augment a particular connection // or have limited lifetime. In all cases, the fields stored here are not appropriate // to be part of sslGlobalParams. |