Skip to content

Commit 963c682

Browse files
CDRIVER-4656 driver re-initializes openssl context on every new socket (#1673)
1 parent faabc9a commit 963c682

15 files changed

+416
-57
lines changed

src/libmongoc/CMakeLists.txt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1269,6 +1269,13 @@ if (ENABLE_EXAMPLES AND ENABLE_SHARED)
12691269
mongoc_add_example (appending ${PROJECT_SOURCE_DIR}/examples/tutorial/appending.c)
12701270
endif ()
12711271

1272+
if (ENABLE_TESTS AND ENABLE_SHARED AND MONGOC_ENABLE_SSL AND NOT WIN32)
1273+
# Add benchmarks to measure opening many TLS connections.
1274+
# Benchmarks require SSL, and do not build on Windows.
1275+
add_executable (benchmark-tls-pooled ${PROJECT_SOURCE_DIR}/tests/benchmark-tls-pooled.c)
1276+
target_link_libraries (benchmark-tls-pooled mongoc_shared ${LIBRARIES})
1277+
endif ()
1278+
12721279
file (COPY ${PROJECT_SOURCE_DIR}/tests/binary DESTINATION ${PROJECT_BINARY_DIR}/tests)
12731280
file (COPY ${PROJECT_SOURCE_DIR}/tests/json DESTINATION ${PROJECT_BINARY_DIR}/tests)
12741281
file (COPY ${PROJECT_SOURCE_DIR}/tests/x509gen DESTINATION ${PROJECT_BINARY_DIR}/tests)

src/libmongoc/src/mongoc/mongoc-client-pool.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,10 @@
3333
#include "mongoc-ssl-private.h"
3434
#endif
3535

36+
#if defined(MONGOC_ENABLE_SSL_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x10100000L
37+
#include "mongoc-openssl-private.h"
38+
#endif
39+
3640
struct _mongoc_client_pool_t {
3741
bson_mutex_t mutex;
3842
mongoc_cond_t cond;
@@ -73,6 +77,13 @@ mongoc_client_pool_set_ssl_opts (mongoc_client_pool_t *pool, const mongoc_ssl_op
7377
if (opts) {
7478
_mongoc_ssl_opts_copy_to (opts, &pool->ssl_opts, false /* don't overwrite internal opts. */);
7579
pool->ssl_opts_set = true;
80+
81+
/* Update the OpenSSL context associated with this client pool to match new ssl opts. */
82+
/* All future clients popped from pool inherit this OpenSSL context. */
83+
#if defined(MONGOC_ENABLE_SSL_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x10100000L
84+
SSL_CTX_free (pool->topology->scanner->openssl_ctx);
85+
pool->topology->scanner->openssl_ctx = _mongoc_openssl_ctx_new (&pool->ssl_opts);
86+
#endif
7687
}
7788

7889
mongoc_topology_scanner_set_ssl_opts (pool->topology->scanner, &pool->ssl_opts);

src/libmongoc/src/mongoc/mongoc-client-private.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,7 @@ mongoc_client_connect (bool buffered,
219219
void *ssl_opts_void,
220220
const mongoc_uri_t *uri,
221221
const mongoc_host_list_t *host,
222+
void *openssl_ctx_void,
222223
bson_error_t *error);
223224

224225

src/libmongoc/src/mongoc/mongoc-client.c

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,10 @@
6969
#include "mongoc-opts-private.h"
7070
#endif
7171

72+
#if defined(MONGOC_ENABLE_SSL_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x10100000L
73+
#include "mongoc-openssl-private.h"
74+
#include "mongoc-stream-tls-private.h"
75+
#endif
7276

7377
#undef MONGOC_LOG_DOMAIN
7478
#define MONGOC_LOG_DOMAIN "client"
@@ -748,6 +752,7 @@ mongoc_client_connect (bool buffered,
748752
void *ssl_opts_void,
749753
const mongoc_uri_t *uri,
750754
const mongoc_host_list_t *host,
755+
void *openssl_ctx_void,
751756
bson_error_t *error)
752757
{
753758
mongoc_stream_t *base_stream = NULL;
@@ -797,7 +802,13 @@ mongoc_client_connect (bool buffered,
797802
if (use_ssl || (mechanism && (0 == strcmp (mechanism, "MONGODB-X509")))) {
798803
mongoc_stream_t *original = base_stream;
799804

805+
#if defined(MONGOC_ENABLE_SSL_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x10100000L
806+
// Use shared OpenSSL context.
807+
base_stream = mongoc_stream_tls_new_with_hostname_and_openssl_context (
808+
base_stream, host->host, ssl_opts, true, (SSL_CTX *) openssl_ctx_void);
809+
#else
800810
base_stream = mongoc_stream_tls_new_with_hostname (base_stream, host->host, ssl_opts, true);
811+
#endif
801812

802813
if (!base_stream) {
803814
mongoc_stream_destroy (original);
@@ -830,6 +841,8 @@ mongoc_client_connect (bool buffered,
830841
* A mongoc_stream_initiator_t that will handle the various type
831842
* of supported sockets by MongoDB including TCP and UNIX.
832843
*
844+
* Also supports sharing of OpenSSL context owned by a client.
845+
*
833846
* Language binding authors may want to implement an alternate
834847
* version of this method to use their native stream format.
835848
*
@@ -858,7 +871,12 @@ mongoc_client_default_stream_initiator (const mongoc_uri_t *uri,
858871

859872
#endif
860873

861-
return mongoc_client_connect (true, use_ssl, ssl_opts_void, uri, host, error);
874+
#if defined(MONGOC_ENABLE_SSL_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x10100000L
875+
SSL_CTX *ssl_ctx = client->topology->scanner->openssl_ctx;
876+
return mongoc_client_connect (true, use_ssl, ssl_opts_void, uri, host, (void *) ssl_ctx, error);
877+
#else
878+
return mongoc_client_connect (true, use_ssl, ssl_opts_void, uri, host, NULL, error);
879+
#endif
862880
}
863881

864882
/*
@@ -980,6 +998,13 @@ mongoc_client_set_ssl_opts (mongoc_client_t *client, const mongoc_ssl_opt_t *opt
980998

981999
if (client->topology->single_threaded) {
9821000
mongoc_topology_scanner_set_ssl_opts (client->topology->scanner, &client->ssl_opts);
1001+
1002+
/* Update the OpenSSL context associated with this client to match new ssl opts. */
1003+
/* Active connections previously made by client can still access original OpenSSL context. */
1004+
#if defined(MONGOC_ENABLE_SSL_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x10100000L
1005+
SSL_CTX_free (client->topology->scanner->openssl_ctx);
1006+
client->topology->scanner->openssl_ctx = _mongoc_openssl_ctx_new (&client->ssl_opts);
1007+
#endif
9831008
}
9841009
}
9851010
#endif
@@ -1087,6 +1112,7 @@ _mongoc_client_new_from_topology (mongoc_topology_t *topology)
10871112

10881113
_mongoc_ssl_opts_from_uri (&ssl_opt, &internal_tls_opts, client->uri);
10891114
/* sets use_ssl = true */
1115+
/* this call creates an ssl ctx only if single-threaded, otherwise client inherits from pool */
10901116
mongoc_client_set_ssl_opts (client, &ssl_opt);
10911117
_mongoc_client_set_internal_tls_opts (client, &internal_tls_opts);
10921118
}

src/libmongoc/src/mongoc/mongoc-openssl.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1002,6 +1002,12 @@ _mongoc_openssl_ctx_new (mongoc_ssl_opt_t *opt)
10021002
return NULL;
10031003
}
10041004

1005+
if (opt->weak_cert_validation) {
1006+
SSL_CTX_set_verify (ctx, SSL_VERIFY_NONE, NULL);
1007+
} else {
1008+
SSL_CTX_set_verify (ctx, SSL_VERIFY_PEER, NULL);
1009+
}
1010+
10051011
return ctx;
10061012
}
10071013

src/libmongoc/src/mongoc/mongoc-server-monitor.c

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -855,12 +855,23 @@ _server_monitor_setup_connection (mongoc_server_monitor_t *server_monitor,
855855
server_monitor->uri, &server_monitor->description->host, server_monitor->initiator_context, error);
856856
} else {
857857
void *ssl_opts_void = NULL;
858+
void *openssl_ctx_void = NULL;
858859

859860
#ifdef MONGOC_ENABLE_SSL
860861
ssl_opts_void = server_monitor->ssl_opts;
861862
#endif
862-
server_monitor->stream = mongoc_client_connect (
863-
false, ssl_opts_void != NULL, ssl_opts_void, server_monitor->uri, &server_monitor->description->host, error);
863+
864+
#if defined(MONGOC_ENABLE_SSL_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x10100000L
865+
openssl_ctx_void = server_monitor->topology->scanner->openssl_ctx;
866+
#endif
867+
868+
server_monitor->stream = mongoc_client_connect (false,
869+
ssl_opts_void != NULL,
870+
ssl_opts_void,
871+
server_monitor->uri,
872+
&server_monitor->description->host,
873+
openssl_ctx_void,
874+
error);
864875
}
865876

866877
if (!server_monitor->stream) {

src/libmongoc/src/mongoc/mongoc-stream-tls-openssl-private.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@
2121

2222
#ifdef MONGOC_ENABLE_SSL_OPENSSL
2323
#include <bson/bson.h>
24+
#include <openssl/ssl.h>
25+
26+
#include "mongoc-stream-tls.h"
2427

2528
BSON_BEGIN_DECLS
2629

@@ -49,6 +52,14 @@ typedef struct {
4952
mongoc_openssl_ocsp_opt_t *ocsp_opts;
5053
} mongoc_stream_tls_openssl_t;
5154

55+
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
56+
MONGOC_EXPORT (mongoc_stream_t *)
57+
mongoc_stream_tls_openssl_new_with_context (mongoc_stream_t *base_stream,
58+
const char *host,
59+
mongoc_ssl_opt_t *opt,
60+
int client,
61+
SSL_CTX *ssl_ctx) BSON_GNUC_WARN_UNUSED_RESULT;
62+
#endif
5263

5364
BSON_END_DECLS
5465

src/libmongoc/src/mongoc/mongoc-stream-tls-openssl.c

Lines changed: 86 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -697,50 +697,35 @@ _mongoc_stream_tls_openssl_should_retry (mongoc_stream_t *stream)
697697
RETURN (mongoc_stream_should_retry (tls->base_stream));
698698
}
699699

700-
/*
701-
*--------------------------------------------------------------------------
702-
*
703-
* mongoc_stream_tls_openssl_new --
704-
*
705-
* Creates a new mongoc_stream_tls_openssl_t to communicate with a remote
706-
* server using a TLS stream.
707-
*
708-
* @base_stream should be a stream that will become owned by the
709-
* resulting tls stream. It will be used for raw I/O.
710-
*
711-
* @trust_store_dir should be a path to the SSL cert db to use for
712-
* verifying trust of the remote server.
713-
*
714-
* Returns:
715-
* NULL on failure, otherwise a mongoc_stream_t.
716-
*
717-
* Side effects:
718-
* None.
719-
*
720-
*--------------------------------------------------------------------------
721-
*/
722-
723-
mongoc_stream_t *
724-
mongoc_stream_tls_openssl_new (mongoc_stream_t *base_stream, const char *host, mongoc_ssl_opt_t *opt, int client)
700+
/* Creates a new mongoc_stream_tls_openssl_t with ssl_ctx. */
701+
static mongoc_stream_t *
702+
create_stream_with_ctx (
703+
mongoc_stream_t *base_stream, const char *host, mongoc_ssl_opt_t *opt, int client, SSL_CTX *ssl_ctx)
725704
{
726705
mongoc_stream_tls_t *tls;
727706
mongoc_stream_tls_openssl_t *openssl;
728707
mongoc_openssl_ocsp_opt_t *ocsp_opts = NULL;
729-
SSL_CTX *ssl_ctx = NULL;
730708
BIO *bio_ssl = NULL;
731709
BIO *bio_mongoc_shim = NULL;
732710
BIO_METHOD *meth;
711+
SSL *ssl;
733712

734713
BSON_ASSERT (base_stream);
735714
BSON_ASSERT (opt);
736715
ENTRY;
737716

738-
ssl_ctx = _mongoc_openssl_ctx_new (opt);
739-
740717
if (!ssl_ctx) {
741718
RETURN (NULL);
742719
}
743720

721+
bio_ssl = BIO_new_ssl (ssl_ctx, client);
722+
if (!bio_ssl) {
723+
SSL_CTX_free (ssl_ctx);
724+
RETURN (NULL);
725+
}
726+
727+
BIO_get_ssl (bio_ssl, &ssl);
728+
744729
#if OPENSSL_VERSION_NUMBER >= 0x10002000L && !defined(LIBRESSL_VERSION_NUMBER)
745730
if (!opt->allow_invalid_hostname) {
746731
struct in_addr addr;
@@ -753,30 +738,11 @@ mongoc_stream_tls_openssl_new (mongoc_stream_t *base_stream, const char *host, m
753738
} else {
754739
X509_VERIFY_PARAM_set1_host (param, host, 0);
755740
}
756-
SSL_CTX_set1_param (ssl_ctx, param);
741+
SSL_set1_param (ssl, param);
757742
X509_VERIFY_PARAM_free (param);
758743
}
759744
#endif
760745

761-
if (!client) {
762-
/* Only used by the Mock Server.
763-
* Set a callback to get the SNI, if provided */
764-
MC_DISABLE_CAST_FUNCTION_TYPE_STRICT_WARNING_BEGIN
765-
SSL_CTX_set_tlsext_servername_callback (ssl_ctx, _mongoc_stream_tls_openssl_sni);
766-
MC_DISABLE_CAST_FUNCTION_TYPE_STRICT_WARNING_END
767-
}
768-
769-
if (opt->weak_cert_validation) {
770-
SSL_CTX_set_verify (ssl_ctx, SSL_VERIFY_NONE, NULL);
771-
} else {
772-
SSL_CTX_set_verify (ssl_ctx, SSL_VERIFY_PEER, NULL);
773-
}
774-
775-
bio_ssl = BIO_new_ssl (ssl_ctx, client);
776-
if (!bio_ssl) {
777-
SSL_CTX_free (ssl_ctx);
778-
RETURN (NULL);
779-
}
780746
meth = mongoc_stream_tls_openssl_bio_meth_new ();
781747
bio_mongoc_shim = BIO_new (meth);
782748
if (!bio_mongoc_shim) {
@@ -789,9 +755,7 @@ mongoc_stream_tls_openssl_new (mongoc_stream_t *base_stream, const char *host, m
789755
/* Added in OpenSSL 0.9.8f, as a build time option */
790756
#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
791757
if (client) {
792-
SSL *ssl;
793758
/* Set the SNI hostname we are expecting certificate for */
794-
BIO_get_ssl (bio_ssl, &ssl);
795759
SSL_set_tlsext_host_name (ssl, host);
796760
#endif
797761
}
@@ -800,10 +764,6 @@ mongoc_stream_tls_openssl_new (mongoc_stream_t *base_stream, const char *host, m
800764

801765
#ifdef MONGOC_ENABLE_OCSP_OPENSSL
802766
if (client && !opt->weak_cert_validation && !_mongoc_ssl_opts_disable_certificate_revocation_check (opt)) {
803-
SSL *ssl;
804-
805-
BIO_get_ssl (bio_ssl, &ssl);
806-
807767
/* Set the status_request extension on the SSL object.
808768
* Do not use SSL_CTX_set_tlsext_status_type, since that requires OpenSSL
809769
* 1.1.0.
@@ -857,6 +817,78 @@ mongoc_stream_tls_openssl_new (mongoc_stream_t *base_stream, const char *host, m
857817
RETURN ((mongoc_stream_t *) tls);
858818
}
859819

820+
/*
821+
*--------------------------------------------------------------------------
822+
*
823+
* mongoc_stream_tls_openssl_new --
824+
*
825+
* Creates a new mongoc_stream_tls_openssl_t to communicate with a remote
826+
* server using a TLS stream.
827+
*
828+
* @base_stream should be a stream that will become owned by the
829+
* resulting tls stream. It will be used for raw I/O.
830+
*
831+
* Returns:
832+
* NULL on failure, otherwise a mongoc_stream_t.
833+
*
834+
* Side effects:
835+
* None.
836+
*
837+
*--------------------------------------------------------------------------
838+
*/
839+
840+
mongoc_stream_t *
841+
mongoc_stream_tls_openssl_new (mongoc_stream_t *base_stream, const char *host, mongoc_ssl_opt_t *opt, int client)
842+
{
843+
SSL_CTX *ssl_ctx = _mongoc_openssl_ctx_new (opt);
844+
845+
if (!ssl_ctx) {
846+
RETURN (NULL);
847+
}
848+
849+
if (!client) {
850+
/* Only used by the Mock Server.
851+
* Set a callback to get the SNI, if provided */
852+
SSL_CTX_set_tlsext_servername_callback (ssl_ctx, _mongoc_stream_tls_openssl_sni);
853+
}
854+
855+
return create_stream_with_ctx (base_stream, host, opt, client, ssl_ctx);
856+
}
857+
858+
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
859+
/*
860+
*--------------------------------------------------------------------------
861+
*
862+
* mongoc_stream_tls_openssl_new_with_context --
863+
*
864+
* Creates a new mongoc_stream_tls_openssl_t to communicate with a remote
865+
* server using a TLS stream, using an existing OpenSSL context.
866+
*
867+
* Only called by mongoc_stream_tls_new_with_hostname_and_openssl_context.
868+
*
869+
* @ssl_ctx is the shared OpenSSL context for the mongoc_client_t
870+
* associated with this function call.
871+
*
872+
* Returns:
873+
* NULL on failure, otherwise a mongoc_stream_t.
874+
*
875+
* Side effects:
876+
* None.
877+
*
878+
*--------------------------------------------------------------------------
879+
*/
880+
881+
mongoc_stream_t *
882+
mongoc_stream_tls_openssl_new_with_context (
883+
mongoc_stream_t *base_stream, const char *host, mongoc_ssl_opt_t *opt, int client, SSL_CTX *ssl_ctx)
884+
{
885+
BSON_ASSERT_PARAM (ssl_ctx);
886+
SSL_CTX_up_ref (ssl_ctx);
887+
888+
return create_stream_with_ctx (base_stream, host, opt, client, ssl_ctx);
889+
}
890+
#endif
891+
860892
void
861893
mongoc_openssl_ocsp_opt_destroy (void *ocsp_opt)
862894
{

0 commit comments

Comments
 (0)