Skip to content

Commit bc14d6c

Browse files
authored
CDRIVER-5998 share SCHANNEL_CRED (#2052)
* add `const` to `mongoc_ssl_opt_t` params * rename `mongoc_secure_channel_cred` to `mongoc_secure_channel_cred_handle` * share `SCHANNEL_CRED` Share `SCHANNEL_CRED` on all client/pool connections. This is intended to simplify future fix for CDRIVER-5998. As an added benefit, this reduces the repeated reading of PEM files for each connection. * fix X509 test Capture logs earlier to account for secure channel loading the PEM file when SSL options are set. This revealed the OpenSSL implementation also logs. * fix existing memory leak on failure
1 parent 352bc73 commit bc14d6c

16 files changed

+575
-149
lines changed

src/libmongoc/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1075,6 +1075,7 @@ set (test-libmongoc-sources
10751075
${PROJECT_SOURCE_DIR}/tests/test-mongoc-scram.c
10761076
${PROJECT_SOURCE_DIR}/tests/test-mongoc-sdam-monitoring.c
10771077
${PROJECT_SOURCE_DIR}/tests/test-mongoc-sdam.c
1078+
${PROJECT_SOURCE_DIR}/tests/test-mongoc-secure-channel.c
10781079
${PROJECT_SOURCE_DIR}/tests/test-mongoc-server-description.c
10791080
${PROJECT_SOURCE_DIR}/tests/test-mongoc-server-selection-errors.c
10801081
${PROJECT_SOURCE_DIR}/tests/test-mongoc-server-selection.c

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

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,10 @@
3939
#include <mongoc/mongoc-openssl-private.h>
4040
#endif
4141

42+
#if defined(MONGOC_ENABLE_SSL_SECURE_CHANNEL)
43+
#include <mongoc/mongoc-stream-tls-secure-channel-private.h>
44+
#endif
45+
4246
struct _mongoc_client_pool_t {
4347
bson_mutex_t mutex;
4448
mongoc_cond_t cond;
@@ -83,6 +87,13 @@ mongoc_client_pool_set_ssl_opts (mongoc_client_pool_t *pool, const mongoc_ssl_op
8387
#if defined(MONGOC_ENABLE_SSL_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x10100000L
8488
SSL_CTX_free (pool->topology->scanner->openssl_ctx);
8589
pool->topology->scanner->openssl_ctx = _mongoc_openssl_ctx_new (&pool->ssl_opts);
90+
#elif defined(MONGOC_ENABLE_SSL_SECURE_CHANNEL)
91+
// Access to secure_channel_cred_ptr does not need the thread-safe `mongoc_atomic_*` functions.
92+
// secure_channel_cred_ptr is not expected to be modified by multiple threads.
93+
// mongoc_client_pool_set_ssl_opts documentation prohibits calling after threads start.
94+
mongoc_shared_ptr_reset (&pool->topology->scanner->secure_channel_cred_ptr,
95+
mongoc_secure_channel_cred_new (&pool->ssl_opts),
96+
mongoc_secure_channel_cred_deleter);
8697
#endif
8798
}
8899

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
#include <mongoc/mongoc-topology-private.h>
3939
#include <mongoc/mongoc-write-concern.h>
4040
#include <mongoc/mongoc-crypt-private.h>
41+
#include <mongoc/mongoc-shared-private.h>
4142

4243
BSON_BEGIN_DECLS
4344

@@ -212,6 +213,7 @@ mongoc_client_connect (bool buffered,
212213
const mongoc_uri_t *uri,
213214
const mongoc_host_list_t *host,
214215
void *openssl_ctx_void,
216+
mongoc_shared_ptr secure_channel_cred_ptr,
215217
bson_error_t *error);
216218

217219

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

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,11 @@
7070
#include <mongoc/mongoc-stream-tls-private.h>
7171
#endif
7272

73+
#if defined(MONGOC_ENABLE_SSL_SECURE_CHANNEL)
74+
#include <mongoc/mongoc-stream-tls-secure-channel-private.h>
75+
#include <mongoc/mongoc-stream-tls-private.h>
76+
#endif
77+
7378
#include <common-string-private.h>
7479
#include <mlib/cmp.h>
7580

@@ -756,6 +761,7 @@ mongoc_client_connect (bool buffered,
756761
const mongoc_uri_t *uri,
757762
const mongoc_host_list_t *host,
758763
void *openssl_ctx_void,
764+
mongoc_shared_ptr secure_channel_cred_ptr,
759765
bson_error_t *error)
760766
{
761767
mongoc_stream_t *base_stream = NULL;
@@ -765,6 +771,7 @@ mongoc_client_connect (bool buffered,
765771
BSON_ASSERT (host);
766772

767773
BSON_UNUSED (openssl_ctx_void);
774+
BSON_UNUSED (secure_channel_cred_ptr);
768775

769776
#ifndef MONGOC_ENABLE_SSL
770777
if (ssl_opts_void || mongoc_uri_get_tls (uri)) {
@@ -814,6 +821,9 @@ mongoc_client_connect (bool buffered,
814821
// Use shared OpenSSL context.
815822
base_stream = mongoc_stream_tls_new_with_hostname_and_openssl_context (
816823
base_stream, host->host, ssl_opts, true, (SSL_CTX *) openssl_ctx_void);
824+
#elif defined(MONGOC_ENABLE_SSL_SECURE_CHANNEL)
825+
// Use shared Secure Channel credentials.
826+
base_stream = mongoc_stream_tls_new_with_secure_channel_cred (base_stream, ssl_opts, secure_channel_cred_ptr);
817827
#else
818828
base_stream = mongoc_stream_tls_new_with_hostname (base_stream, host->host, ssl_opts, true);
819829
#endif
@@ -881,9 +891,13 @@ mongoc_client_default_stream_initiator (const mongoc_uri_t *uri,
881891

882892
#if defined(MONGOC_ENABLE_SSL_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x10100000L
883893
SSL_CTX *ssl_ctx = client->topology->scanner->openssl_ctx;
884-
return mongoc_client_connect (true, use_ssl, ssl_opts_void, uri, host, (void *) ssl_ctx, error);
894+
return mongoc_client_connect (
895+
true, use_ssl, ssl_opts_void, uri, host, (void *) ssl_ctx, MONGOC_SHARED_PTR_NULL, error);
896+
#elif defined(MONGOC_ENABLE_SSL_SECURE_CHANNEL)
897+
return mongoc_client_connect (
898+
true, use_ssl, ssl_opts_void, uri, host, NULL, client->topology->scanner->secure_channel_cred_ptr, error);
885899
#else
886-
return mongoc_client_connect (true, use_ssl, ssl_opts_void, uri, host, NULL, error);
900+
return mongoc_client_connect (true, use_ssl, ssl_opts_void, uri, host, NULL, MONGOC_SHARED_PTR_NULL, error);
887901
#endif
888902
}
889903

@@ -1028,6 +1042,12 @@ _mongoc_client_set_ssl_opts_for_single_or_pooled (mongoc_client_t *client, const
10281042
SSL_CTX_free (client->topology->scanner->openssl_ctx);
10291043
client->topology->scanner->openssl_ctx = _mongoc_openssl_ctx_new (&client->ssl_opts);
10301044
#endif
1045+
1046+
#if defined(MONGOC_ENABLE_SSL_SECURE_CHANNEL)
1047+
mongoc_shared_ptr_reset (&client->topology->scanner->secure_channel_cred_ptr,
1048+
mongoc_secure_channel_cred_new (&client->ssl_opts),
1049+
mongoc_secure_channel_cred_deleter);
1050+
#endif
10311051
}
10321052
}
10331053
#endif // MONGOC_ENABLE_SSL

src/libmongoc/src/mongoc/mongoc-secure-channel-private.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,10 @@
3333
BSON_BEGIN_DECLS
3434

3535
bool
36-
mongoc_secure_channel_setup_ca (mongoc_ssl_opt_t *opt);
36+
mongoc_secure_channel_setup_ca (const mongoc_ssl_opt_t *opt);
3737

3838
bool
39-
mongoc_secure_channel_setup_crl (mongoc_ssl_opt_t *opt);
39+
mongoc_secure_channel_setup_crl (const mongoc_ssl_opt_t *opt);
4040

4141
// mongoc_secure_channel_load_crl is used in tests.
4242
PCCRL_CONTEXT
@@ -49,7 +49,7 @@ ssize_t
4949
mongoc_secure_channel_write (mongoc_stream_tls_t *tls, const void *data, size_t data_length);
5050

5151
PCCERT_CONTEXT
52-
mongoc_secure_channel_setup_certificate (mongoc_ssl_opt_t *opt);
52+
mongoc_secure_channel_setup_certificate (const mongoc_ssl_opt_t *opt);
5353

5454

5555
/* it may require 16k + some overhead to hold one decryptable block of data - do

src/libmongoc/src/mongoc/mongoc-secure-channel.c

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -379,14 +379,14 @@ mongoc_secure_channel_setup_certificate_from_file (const char *filename)
379379
}
380380

381381
PCCERT_CONTEXT
382-
mongoc_secure_channel_setup_certificate (mongoc_ssl_opt_t *opt)
382+
mongoc_secure_channel_setup_certificate (const mongoc_ssl_opt_t *opt)
383383
{
384384
return mongoc_secure_channel_setup_certificate_from_file (opt->pem_file);
385385
}
386386

387387

388388
bool
389-
mongoc_secure_channel_setup_ca (mongoc_ssl_opt_t *opt)
389+
mongoc_secure_channel_setup_ca (const mongoc_ssl_opt_t *opt)
390390
{
391391
bool ok = false;
392392
char *pem = NULL;
@@ -496,7 +496,7 @@ mongoc_secure_channel_load_crl (const char *crl_file)
496496
}
497497

498498
bool
499-
mongoc_secure_channel_setup_crl (mongoc_ssl_opt_t *opt)
499+
mongoc_secure_channel_setup_crl (const mongoc_ssl_opt_t *opt)
500500
{
501501
HCERTSTORE cert_store = NULL;
502502
bool ok = false;
@@ -671,18 +671,18 @@ mongoc_secure_channel_handshake_step_1 (mongoc_stream_tls_t *tls, char *hostname
671671
secure_channel->ctxt = (mongoc_secure_channel_ctxt *) bson_malloc0 (sizeof (mongoc_secure_channel_ctxt));
672672

673673
/* https://msdn.microsoft.com/en-us/library/windows/desktop/aa375924.aspx */
674-
sspi_status = InitializeSecurityContext (&secure_channel->cred->cred_handle, /* phCredential */
675-
NULL, /* phContext */
676-
hostname, /* pszTargetName */
677-
secure_channel->req_flags, /* fContextReq */
678-
0, /* Reserved1, must be 0 */
679-
0, /* TargetDataRep, unused */
680-
NULL, /* pInput */
681-
0, /* Reserved2, must be 0 */
682-
&secure_channel->ctxt->ctxt_handle, /* phNewContext OUT param */
683-
&outbuf_desc, /* pOutput OUT param */
684-
&secure_channel->ret_flags, /* pfContextAttr OUT param */
685-
&secure_channel->ctxt->time_stamp /* ptsExpiry OUT param */
674+
sspi_status = InitializeSecurityContext (&secure_channel->cred_handle->cred_handle, /* phCredential */
675+
NULL, /* phContext */
676+
hostname, /* pszTargetName */
677+
secure_channel->req_flags, /* fContextReq */
678+
0, /* Reserved1, must be 0 */
679+
0, /* TargetDataRep, unused */
680+
NULL, /* pInput */
681+
0, /* Reserved2, must be 0 */
682+
&secure_channel->ctxt->ctxt_handle, /* phNewContext OUT param */
683+
&outbuf_desc, /* pOutput OUT param */
684+
&secure_channel->ret_flags, /* pfContextAttr OUT param */
685+
&secure_channel->ctxt->time_stamp /* ptsExpiry OUT param */
686686
);
687687
if (sspi_status != SEC_I_CONTINUE_NEEDED) {
688688
// Cast signed SECURITY_STATUS to unsigned DWORD. FormatMessage expects DWORD.
@@ -739,7 +739,7 @@ mongoc_secure_channel_handshake_step_2 (mongoc_stream_tls_t *tls, char *hostname
739739

740740
TRACE ("%s", "SSL/TLS connection with endpoint (step 2/3)");
741741

742-
if (!secure_channel->cred || !secure_channel->ctxt) {
742+
if (!secure_channel->cred_handle || !secure_channel->ctxt) {
743743
MONGOC_LOG_AND_SET_ERROR (
744744
error, MONGOC_ERROR_STREAM, MONGOC_ERROR_STREAM_SOCKET, "required TLS credentials or context not provided");
745745

@@ -809,7 +809,7 @@ mongoc_secure_channel_handshake_step_2 (mongoc_stream_tls_t *tls, char *hostname
809809

810810
/* https://msdn.microsoft.com/en-us/library/windows/desktop/aa375924.aspx
811811
*/
812-
sspi_status = InitializeSecurityContext (&secure_channel->cred->cred_handle,
812+
sspi_status = InitializeSecurityContext (&secure_channel->cred_handle->cred_handle,
813813
&secure_channel->ctxt->ctxt_handle,
814814
hostname,
815815
secure_channel->req_flags,
@@ -989,7 +989,7 @@ mongoc_secure_channel_handshake_step_3 (mongoc_stream_tls_t *tls, char *hostname
989989

990990
TRACE ("SSL/TLS connection with %s (step 3/3)", hostname);
991991

992-
if (!secure_channel->cred) {
992+
if (!secure_channel->cred_handle) {
993993
MONGOC_LOG_AND_SET_ERROR (
994994
error, MONGOC_ERROR_STREAM, MONGOC_ERROR_STREAM_SOCKET, "required TLS credentials not provided");
995995
return false;

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -933,6 +933,7 @@ _server_monitor_setup_connection (mongoc_server_monitor_t *server_monitor,
933933
} else {
934934
void *ssl_opts_void = NULL;
935935
void *openssl_ctx_void = NULL;
936+
mongoc_shared_ptr secure_channel_cred_ptr = MONGOC_SHARED_PTR_NULL;
936937

937938
#ifdef MONGOC_ENABLE_SSL
938939
ssl_opts_void = server_monitor->ssl_opts;
@@ -942,12 +943,17 @@ _server_monitor_setup_connection (mongoc_server_monitor_t *server_monitor,
942943
openssl_ctx_void = server_monitor->topology->scanner->openssl_ctx;
943944
#endif
944945

946+
#if defined(MONGOC_ENABLE_SSL_SECURE_CHANNEL)
947+
secure_channel_cred_ptr = server_monitor->topology->scanner->secure_channel_cred_ptr;
948+
#endif
949+
945950
server_monitor->stream = mongoc_client_connect (false,
946951
ssl_opts_void != NULL,
947952
ssl_opts_void,
948953
server_monitor->uri,
949954
&server_monitor->description->host,
950955
openssl_ctx_void,
956+
secure_channel_cred_ptr,
951957
error);
952958
}
953959

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

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@
2828
#include <openssl/ssl.h>
2929
#endif
3030

31+
#include <mongoc/mongoc-shared-private.h>
32+
3133
BSON_BEGIN_DECLS
3234

3335
/**
@@ -53,7 +55,12 @@ mongoc_stream_tls_new_with_hostname_and_openssl_context (mongoc_stream_t *base_s
5355
mongoc_ssl_opt_t *opt,
5456
int client,
5557
SSL_CTX *ssl_ctx) BSON_GNUC_WARN_UNUSED_RESULT;
56-
#endif
58+
#elif defined(MONGOC_ENABLE_SSL_SECURE_CHANNEL)
59+
mongoc_stream_t *
60+
mongoc_stream_tls_new_with_secure_channel_cred (mongoc_stream_t *base_stream,
61+
mongoc_ssl_opt_t *opt,
62+
mongoc_shared_ptr secure_channel_cred_ptr) BSON_GNUC_WARN_UNUSED_RESULT;
63+
#endif // MONGOC_ENABLE_SSL_SECURE_CHANNEL
5764

5865
BSON_END_DECLS
5966

src/libmongoc/src/mongoc/mongoc-stream-tls-secure-channel-private.h

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,12 @@
2222
#ifdef MONGOC_ENABLE_SSL_SECURE_CHANNEL
2323
#include <bson/bson.h>
2424

25+
#include <mongoc/mongoc-shared-private.h>
26+
2527
/* Its mandatory to indicate to Windows who is compiling the code */
2628
#define SECURITY_WIN32
2729
#include <security.h>
30+
#include <schannel.h>
2831

2932

3033
BSON_BEGIN_DECLS
@@ -44,7 +47,12 @@ typedef enum {
4447
typedef struct {
4548
CredHandle cred_handle;
4649
TimeStamp time_stamp;
50+
} mongoc_secure_channel_cred_handle;
51+
52+
// `mongoc_secure_channel_cred` may be shared on multiple connections.
53+
typedef struct _mongoc_secure_channel_cred {
4754
PCCERT_CONTEXT cert; /* Owning. Optional client cert. */
55+
SCHANNEL_CRED cred; // TODO: switch to SCH_CREDENTIALS to support TLS v1.3
4856
} mongoc_secure_channel_cred;
4957

5058
typedef struct {
@@ -59,7 +67,8 @@ typedef struct {
5967
*/
6068
typedef struct {
6169
ssl_connect_state connecting_state;
62-
mongoc_secure_channel_cred *cred;
70+
mongoc_shared_ptr cred_ptr; // Manages a mongoc_secure_channel_cred.
71+
mongoc_secure_channel_cred_handle *cred_handle;
6372
mongoc_secure_channel_ctxt *ctxt;
6473
SecPkgContext_StreamSizes stream_sizes;
6574
size_t encdata_length, decdata_length;
@@ -72,6 +81,20 @@ typedef struct {
7281
bool recv_connection_closed; /* true if connection closed, regardless how */
7382
} mongoc_stream_tls_secure_channel_t;
7483

84+
struct _mongoc_ssl_opt_t; // Forward declare. Defined in mongoc-ssl.h.
85+
struct _mongoc_stream_t; // Forward declare. Defined in mongoc-stream.h.
86+
87+
mongoc_secure_channel_cred *
88+
mongoc_secure_channel_cred_new (const struct _mongoc_ssl_opt_t *opt);
89+
90+
// mongoc_secure_channel_cred_deleter is useful as a deleter for mongoc_shared_t.
91+
void
92+
mongoc_secure_channel_cred_deleter (void *cred_void);
93+
94+
struct _mongoc_stream_t *
95+
mongoc_stream_tls_secure_channel_new_with_creds (struct _mongoc_stream_t *base_stream,
96+
const struct _mongoc_ssl_opt_t *opt,
97+
mongoc_shared_ptr cred_ptr /* optional */);
7598

7699
BSON_END_DECLS
77100

0 commit comments

Comments
 (0)