Skip to content

CDRIVER-5998 share SCHANNEL_CRED #2052

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 16 commits into from
Jul 3, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/libmongoc/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1075,6 +1075,7 @@ set (test-libmongoc-sources
${PROJECT_SOURCE_DIR}/tests/test-mongoc-scram.c
${PROJECT_SOURCE_DIR}/tests/test-mongoc-sdam-monitoring.c
${PROJECT_SOURCE_DIR}/tests/test-mongoc-sdam.c
${PROJECT_SOURCE_DIR}/tests/test-mongoc-secure-channel.c
${PROJECT_SOURCE_DIR}/tests/test-mongoc-server-description.c
${PROJECT_SOURCE_DIR}/tests/test-mongoc-server-selection-errors.c
${PROJECT_SOURCE_DIR}/tests/test-mongoc-server-selection.c
Expand Down
11 changes: 11 additions & 0 deletions src/libmongoc/src/mongoc/mongoc-client-pool.c
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@
#include <mongoc/mongoc-openssl-private.h>
#endif

#if defined(MONGOC_ENABLE_SSL_SECURE_CHANNEL)
#include <mongoc/mongoc-stream-tls-secure-channel-private.h>
#endif

struct _mongoc_client_pool_t {
bson_mutex_t mutex;
mongoc_cond_t cond;
Expand Down Expand Up @@ -83,6 +87,13 @@ mongoc_client_pool_set_ssl_opts (mongoc_client_pool_t *pool, const mongoc_ssl_op
#if defined(MONGOC_ENABLE_SSL_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x10100000L
SSL_CTX_free (pool->topology->scanner->openssl_ctx);
pool->topology->scanner->openssl_ctx = _mongoc_openssl_ctx_new (&pool->ssl_opts);
#elif defined(MONGOC_ENABLE_SSL_SECURE_CHANNEL)
// Access to secure_channel_cred_ptr does not need the thread-safe `mongoc_atomic_*` functions.
// secure_channel_cred_ptr is not expected to be modified by multiple threads.
// mongoc_client_pool_set_ssl_opts documentation prohibits calling after threads start.
mongoc_shared_ptr_reset (&pool->topology->scanner->secure_channel_cred_ptr,
mongoc_secure_channel_cred_new (&pool->ssl_opts),
mongoc_secure_channel_cred_deleter);
#endif
}

Expand Down
2 changes: 2 additions & 0 deletions src/libmongoc/src/mongoc/mongoc-client-private.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
#include <mongoc/mongoc-topology-private.h>
#include <mongoc/mongoc-write-concern.h>
#include <mongoc/mongoc-crypt-private.h>
#include <mongoc/mongoc-shared-private.h>

BSON_BEGIN_DECLS

Expand Down Expand Up @@ -212,6 +213,7 @@ mongoc_client_connect (bool buffered,
const mongoc_uri_t *uri,
const mongoc_host_list_t *host,
void *openssl_ctx_void,
mongoc_shared_ptr secure_channel_cred_ptr,
bson_error_t *error);


Expand Down
24 changes: 22 additions & 2 deletions src/libmongoc/src/mongoc/mongoc-client.c
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,11 @@
#include <mongoc/mongoc-stream-tls-private.h>
#endif

#if defined(MONGOC_ENABLE_SSL_SECURE_CHANNEL)
#include <mongoc/mongoc-stream-tls-secure-channel-private.h>
#include <mongoc/mongoc-stream-tls-private.h>
#endif

#include <common-string-private.h>
#include <mlib/cmp.h>

Expand Down Expand Up @@ -756,6 +761,7 @@ mongoc_client_connect (bool buffered,
const mongoc_uri_t *uri,
const mongoc_host_list_t *host,
void *openssl_ctx_void,
mongoc_shared_ptr secure_channel_cred_ptr,
bson_error_t *error)
{
mongoc_stream_t *base_stream = NULL;
Expand All @@ -765,6 +771,7 @@ mongoc_client_connect (bool buffered,
BSON_ASSERT (host);

BSON_UNUSED (openssl_ctx_void);
BSON_UNUSED (secure_channel_cred_ptr);

#ifndef MONGOC_ENABLE_SSL
if (ssl_opts_void || mongoc_uri_get_tls (uri)) {
Expand Down Expand Up @@ -814,6 +821,9 @@ mongoc_client_connect (bool buffered,
// Use shared OpenSSL context.
base_stream = mongoc_stream_tls_new_with_hostname_and_openssl_context (
base_stream, host->host, ssl_opts, true, (SSL_CTX *) openssl_ctx_void);
#elif defined(MONGOC_ENABLE_SSL_SECURE_CHANNEL)
// Use shared Secure Channel credentials.
base_stream = mongoc_stream_tls_new_with_secure_channel_cred (base_stream, ssl_opts, secure_channel_cred_ptr);
#else
base_stream = mongoc_stream_tls_new_with_hostname (base_stream, host->host, ssl_opts, true);
#endif
Expand Down Expand Up @@ -881,9 +891,13 @@ mongoc_client_default_stream_initiator (const mongoc_uri_t *uri,

#if defined(MONGOC_ENABLE_SSL_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x10100000L
SSL_CTX *ssl_ctx = client->topology->scanner->openssl_ctx;
return mongoc_client_connect (true, use_ssl, ssl_opts_void, uri, host, (void *) ssl_ctx, error);
return mongoc_client_connect (
true, use_ssl, ssl_opts_void, uri, host, (void *) ssl_ctx, MONGOC_SHARED_PTR_NULL, error);
#elif defined(MONGOC_ENABLE_SSL_SECURE_CHANNEL)
return mongoc_client_connect (
true, use_ssl, ssl_opts_void, uri, host, NULL, client->topology->scanner->secure_channel_cred_ptr, error);
#else
return mongoc_client_connect (true, use_ssl, ssl_opts_void, uri, host, NULL, error);
return mongoc_client_connect (true, use_ssl, ssl_opts_void, uri, host, NULL, MONGOC_SHARED_PTR_NULL, error);
#endif
}

Expand Down Expand Up @@ -1028,6 +1042,12 @@ _mongoc_client_set_ssl_opts_for_single_or_pooled (mongoc_client_t *client, const
SSL_CTX_free (client->topology->scanner->openssl_ctx);
client->topology->scanner->openssl_ctx = _mongoc_openssl_ctx_new (&client->ssl_opts);
#endif

#if defined(MONGOC_ENABLE_SSL_SECURE_CHANNEL)
mongoc_shared_ptr_reset (&client->topology->scanner->secure_channel_cred_ptr,
mongoc_secure_channel_cred_new (&client->ssl_opts),
mongoc_secure_channel_cred_deleter);
#endif
}
}
#endif // MONGOC_ENABLE_SSL
Expand Down
6 changes: 3 additions & 3 deletions src/libmongoc/src/mongoc/mongoc-secure-channel-private.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,10 @@
BSON_BEGIN_DECLS

bool
mongoc_secure_channel_setup_ca (mongoc_ssl_opt_t *opt);
mongoc_secure_channel_setup_ca (const mongoc_ssl_opt_t *opt);

bool
mongoc_secure_channel_setup_crl (mongoc_ssl_opt_t *opt);
mongoc_secure_channel_setup_crl (const mongoc_ssl_opt_t *opt);

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

PCCERT_CONTEXT
mongoc_secure_channel_setup_certificate (mongoc_ssl_opt_t *opt);
mongoc_secure_channel_setup_certificate (const mongoc_ssl_opt_t *opt);


/* it may require 16k + some overhead to hold one decryptable block of data - do
Expand Down
36 changes: 18 additions & 18 deletions src/libmongoc/src/mongoc/mongoc-secure-channel.c
Original file line number Diff line number Diff line change
Expand Up @@ -379,14 +379,14 @@ mongoc_secure_channel_setup_certificate_from_file (const char *filename)
}

PCCERT_CONTEXT
mongoc_secure_channel_setup_certificate (mongoc_ssl_opt_t *opt)
mongoc_secure_channel_setup_certificate (const mongoc_ssl_opt_t *opt)
{
return mongoc_secure_channel_setup_certificate_from_file (opt->pem_file);
}


bool
mongoc_secure_channel_setup_ca (mongoc_ssl_opt_t *opt)
mongoc_secure_channel_setup_ca (const mongoc_ssl_opt_t *opt)
{
bool ok = false;
char *pem = NULL;
Expand Down Expand Up @@ -496,7 +496,7 @@ mongoc_secure_channel_load_crl (const char *crl_file)
}

bool
mongoc_secure_channel_setup_crl (mongoc_ssl_opt_t *opt)
mongoc_secure_channel_setup_crl (const mongoc_ssl_opt_t *opt)
{
HCERTSTORE cert_store = NULL;
bool ok = false;
Expand Down Expand Up @@ -671,18 +671,18 @@ mongoc_secure_channel_handshake_step_1 (mongoc_stream_tls_t *tls, char *hostname
secure_channel->ctxt = (mongoc_secure_channel_ctxt *) bson_malloc0 (sizeof (mongoc_secure_channel_ctxt));

/* https://msdn.microsoft.com/en-us/library/windows/desktop/aa375924.aspx */
sspi_status = InitializeSecurityContext (&secure_channel->cred->cred_handle, /* phCredential */
NULL, /* phContext */
hostname, /* pszTargetName */
secure_channel->req_flags, /* fContextReq */
0, /* Reserved1, must be 0 */
0, /* TargetDataRep, unused */
NULL, /* pInput */
0, /* Reserved2, must be 0 */
&secure_channel->ctxt->ctxt_handle, /* phNewContext OUT param */
&outbuf_desc, /* pOutput OUT param */
&secure_channel->ret_flags, /* pfContextAttr OUT param */
&secure_channel->ctxt->time_stamp /* ptsExpiry OUT param */
sspi_status = InitializeSecurityContext (&secure_channel->cred_handle->cred_handle, /* phCredential */
NULL, /* phContext */
hostname, /* pszTargetName */
secure_channel->req_flags, /* fContextReq */
0, /* Reserved1, must be 0 */
0, /* TargetDataRep, unused */
NULL, /* pInput */
0, /* Reserved2, must be 0 */
&secure_channel->ctxt->ctxt_handle, /* phNewContext OUT param */
&outbuf_desc, /* pOutput OUT param */
&secure_channel->ret_flags, /* pfContextAttr OUT param */
&secure_channel->ctxt->time_stamp /* ptsExpiry OUT param */
);
if (sspi_status != SEC_I_CONTINUE_NEEDED) {
// Cast signed SECURITY_STATUS to unsigned DWORD. FormatMessage expects DWORD.
Expand Down Expand Up @@ -739,7 +739,7 @@ mongoc_secure_channel_handshake_step_2 (mongoc_stream_tls_t *tls, char *hostname

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

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

Expand Down Expand Up @@ -809,7 +809,7 @@ mongoc_secure_channel_handshake_step_2 (mongoc_stream_tls_t *tls, char *hostname

/* https://msdn.microsoft.com/en-us/library/windows/desktop/aa375924.aspx
*/
sspi_status = InitializeSecurityContext (&secure_channel->cred->cred_handle,
sspi_status = InitializeSecurityContext (&secure_channel->cred_handle->cred_handle,
&secure_channel->ctxt->ctxt_handle,
hostname,
secure_channel->req_flags,
Expand Down Expand Up @@ -989,7 +989,7 @@ mongoc_secure_channel_handshake_step_3 (mongoc_stream_tls_t *tls, char *hostname

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

if (!secure_channel->cred) {
if (!secure_channel->cred_handle) {
MONGOC_LOG_AND_SET_ERROR (
error, MONGOC_ERROR_STREAM, MONGOC_ERROR_STREAM_SOCKET, "required TLS credentials not provided");
return false;
Expand Down
6 changes: 6 additions & 0 deletions src/libmongoc/src/mongoc/mongoc-server-monitor.c
Original file line number Diff line number Diff line change
Expand Up @@ -933,6 +933,7 @@ _server_monitor_setup_connection (mongoc_server_monitor_t *server_monitor,
} else {
void *ssl_opts_void = NULL;
void *openssl_ctx_void = NULL;
mongoc_shared_ptr secure_channel_cred_ptr = MONGOC_SHARED_PTR_NULL;

#ifdef MONGOC_ENABLE_SSL
ssl_opts_void = server_monitor->ssl_opts;
Expand All @@ -942,12 +943,17 @@ _server_monitor_setup_connection (mongoc_server_monitor_t *server_monitor,
openssl_ctx_void = server_monitor->topology->scanner->openssl_ctx;
#endif

#if defined(MONGOC_ENABLE_SSL_SECURE_CHANNEL)
secure_channel_cred_ptr = server_monitor->topology->scanner->secure_channel_cred_ptr;
#endif

server_monitor->stream = mongoc_client_connect (false,
ssl_opts_void != NULL,
ssl_opts_void,
server_monitor->uri,
&server_monitor->description->host,
openssl_ctx_void,
secure_channel_cred_ptr,
error);
}

Expand Down
9 changes: 8 additions & 1 deletion src/libmongoc/src/mongoc/mongoc-stream-tls-private.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@
#include <openssl/ssl.h>
#endif

#include <mongoc/mongoc-shared-private.h>

BSON_BEGIN_DECLS

/**
Expand All @@ -53,7 +55,12 @@ mongoc_stream_tls_new_with_hostname_and_openssl_context (mongoc_stream_t *base_s
mongoc_ssl_opt_t *opt,
int client,
SSL_CTX *ssl_ctx) BSON_GNUC_WARN_UNUSED_RESULT;
#endif
#elif defined(MONGOC_ENABLE_SSL_SECURE_CHANNEL)
mongoc_stream_t *
mongoc_stream_tls_new_with_secure_channel_cred (mongoc_stream_t *base_stream,
mongoc_ssl_opt_t *opt,
mongoc_shared_ptr secure_channel_cred_ptr) BSON_GNUC_WARN_UNUSED_RESULT;
#endif // MONGOC_ENABLE_SSL_SECURE_CHANNEL

BSON_END_DECLS

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,12 @@
#ifdef MONGOC_ENABLE_SSL_SECURE_CHANNEL
#include <bson/bson.h>

#include <mongoc/mongoc-shared-private.h>

/* Its mandatory to indicate to Windows who is compiling the code */
#define SECURITY_WIN32
#include <security.h>
#include <schannel.h>


BSON_BEGIN_DECLS
Expand All @@ -44,7 +47,12 @@ typedef enum {
typedef struct {
CredHandle cred_handle;
TimeStamp time_stamp;
} mongoc_secure_channel_cred_handle;

// `mongoc_secure_channel_cred` may be shared on multiple connections.
typedef struct _mongoc_secure_channel_cred {
PCCERT_CONTEXT cert; /* Owning. Optional client cert. */
SCHANNEL_CRED cred; // TODO: switch to SCH_CREDENTIALS to support TLS v1.3
} mongoc_secure_channel_cred;

typedef struct {
Expand All @@ -59,7 +67,8 @@ typedef struct {
*/
typedef struct {
ssl_connect_state connecting_state;
mongoc_secure_channel_cred *cred;
mongoc_shared_ptr cred_ptr; // Manages a mongoc_secure_channel_cred.
mongoc_secure_channel_cred_handle *cred_handle;
mongoc_secure_channel_ctxt *ctxt;
SecPkgContext_StreamSizes stream_sizes;
size_t encdata_length, decdata_length;
Expand All @@ -72,6 +81,20 @@ typedef struct {
bool recv_connection_closed; /* true if connection closed, regardless how */
} mongoc_stream_tls_secure_channel_t;

struct _mongoc_ssl_opt_t; // Forward declare. Defined in mongoc-ssl.h.
struct _mongoc_stream_t; // Forward declare. Defined in mongoc-stream.h.

mongoc_secure_channel_cred *
mongoc_secure_channel_cred_new (const struct _mongoc_ssl_opt_t *opt);

// mongoc_secure_channel_cred_deleter is useful as a deleter for mongoc_shared_t.
void
mongoc_secure_channel_cred_deleter (void *cred_void);

struct _mongoc_stream_t *
mongoc_stream_tls_secure_channel_new_with_creds (struct _mongoc_stream_t *base_stream,
const struct _mongoc_ssl_opt_t *opt,
mongoc_shared_ptr cred_ptr /* optional */);

BSON_END_DECLS

Expand Down
Loading