Skip to content
This repository was archived by the owner on Mar 1, 2026. It is now read-only.

Commit 39c117b

Browse files
lthHerman Lee
authored andcommitted
Add facility to re-use SSL_CTX across connections
Summary: Every connection, MySQL recreates the SSL_CTX object. This is bad and unnecessary. This diff adds the ability to re-use an SSL context object between connections. This is roughly a 50% increase in throughput making SSL connections. In combination with re-using SSL sessions, the net speedup is roughly 7-8x. This facility can be used in one of two ways; one is to "take ownership" of the SSL_CTX in an existing MySQL connection (simple) or to create a context by hand, therefore bypassing many of the MySQL "options" fields relating to verification, certs, etc. This is not ideal but avoids a larger refactoring and public API change to support some kind of "initialize an OpenSSL context with these options" which would be complicated and potentially difficult to reconcile with yassl. Reference patch: 4c288ca Differential Revision: D6536123
1 parent fb15835 commit 39c117b

12 files changed

Lines changed: 136 additions & 42 deletions

File tree

‎CMakeLists.txt‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1623,6 +1623,7 @@ INCLUDE(configure.cmake)
16231623

16241624
# Common defines and includes
16251625
ADD_DEFINITIONS(-DHAVE_CONFIG_H)
1626+
ADD_DEFINITIONS(-DHAVE_OPENSSL) # Removed by Oracle in 8.0.20
16261627
ADD_DEFINITIONS(-D__STDC_LIMIT_MACROS) # Enable C99 limit macros
16271628
ADD_DEFINITIONS(-D__STDC_FORMAT_MACROS) # Enable C99 printf format macros
16281629
ADD_DEFINITIONS(-D_USE_MATH_DEFINES) # Get access to M_PI, M_E, etc. in math.h

‎client/mysql.cc‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,9 @@ static char *opt_oci_config_file = nullptr;
239239
#include "multi_factor_passwordopt-vars.h"
240240
#include "sslopt-vars.h"
241241

242+
/* The SSL context that will be reused across invocations. */
243+
static void *ssl_context = nullptr;
244+
242245
const char *default_dbug_option = "d:t:o,/tmp/mysql.trace";
243246
static void *ssl_session_data = nullptr;
244247

@@ -1511,6 +1514,9 @@ void mysql_end(int sig) {
15111514
delete global_attrs;
15121515
global_attrs = nullptr;
15131516
}
1517+
#if defined(HAVE_OPENSSL)
1518+
SSL_CTX_free((SSL_CTX *)ssl_context);
1519+
#endif
15141520
exit(status.exit_status);
15151521
}
15161522

@@ -4635,6 +4641,8 @@ static int sql_real_connect(char *host, char *database, char *user, char *,
46354641
} else {
46364642
DBUG_PRINT("error", ("unable to save SSL session"));
46374643
}
4644+
ssl_context = mysql_take_ssl_context_ownership(&mysql);
4645+
46384646
#ifdef _WIN32
46394647
/* Convert --execute buffer from UTF8MB4 to connection character set */
46404648
if (!execute_buffer_conversion_done && status.line_buff &&
@@ -4707,6 +4715,10 @@ static bool init_connection_options(MYSQL *mysql) {
47074715
if (ssl_session_data)
47084716
mysql_options(mysql, MYSQL_OPT_SSL_SESSION_DATA, ssl_session_data);
47094717

4718+
if (ssl_context) {
4719+
mysql_options(mysql, MYSQL_OPT_SSL_CONTEXT, ssl_context);
4720+
}
4721+
47104722
if (opt_protocol)
47114723
mysql_options(mysql, MYSQL_OPT_PROTOCOL, (char *)&opt_protocol);
47124724

‎include/mysql.h‎

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,8 @@ enum mysql_option {
212212
MYSQL_OPT_ZSTD_COMPRESSION_LEVEL,
213213
MYSQL_OPT_LOAD_DATA_LOCAL_DIR,
214214
MYSQL_OPT_USER_PASSWORD,
215-
MYSQL_OPT_SSL_SESSION_DATA
215+
MYSQL_OPT_SSL_SESSION_DATA,
216+
MYSQL_OPT_SSL_CONTEXT,
216217
};
217218

218219
/**
@@ -465,6 +466,17 @@ bool STDCALL mysql_get_ssl_session_reused(MYSQL *mysql);
465466
void *STDCALL mysql_get_ssl_session_data(MYSQL *mysql, unsigned int n_ticket,
466467
unsigned int *out_len);
467468
bool STDCALL mysql_free_ssl_session_data(MYSQL *mysql, void *data);
469+
/*
470+
Take ownership of the OpenSSL SSL_CTX instance associated with this
471+
connection. In general, SSL_CTX objects should be re-used. Either one can
472+
be taken from an existing connection or created by hand (in which case the
473+
mysql SSL options such as MYSQL_OPT_SSL_KEY are ignored since they
474+
influence the SSL_CTX object).
475+
476+
The caller is responsible for freeing this via SSL_CTX_free. Note that this
477+
is a void* strictly to avoid including SSL headers in this file.
478+
*/
479+
void *STDCALL mysql_take_ssl_context_ownership(MYSQL *mysql);
468480
bool STDCALL mysql_change_user(MYSQL *mysql, const char *user,
469481
const char *passwd, const char *db);
470482
MYSQL *STDCALL mysql_real_connect(MYSQL *mysql, const char *host,

‎include/mysql.h.pp‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -460,7 +460,8 @@
460460
MYSQL_OPT_ZSTD_COMPRESSION_LEVEL,
461461
MYSQL_OPT_LOAD_DATA_LOCAL_DIR,
462462
MYSQL_OPT_USER_PASSWORD,
463-
MYSQL_OPT_SSL_SESSION_DATA
463+
MYSQL_OPT_SSL_SESSION_DATA,
464+
MYSQL_OPT_SSL_CONTEXT,
464465
};
465466
struct st_mysql_options_extention;
466467
struct st_mysql_options {
@@ -618,6 +619,7 @@
618619
void * mysql_get_ssl_session_data(MYSQL *mysql, unsigned int n_ticket,
619620
unsigned int *out_len);
620621
bool mysql_free_ssl_session_data(MYSQL *mysql, void *data);
622+
void * mysql_take_ssl_context_ownership(MYSQL *mysql);
621623
bool mysql_change_user(MYSQL *mysql, const char *user,
622624
const char *passwd, const char *db);
623625
MYSQL * mysql_real_connect(MYSQL *mysql, const char *host,

‎include/sql_common.h‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,7 @@ struct st_mysql_options_extention {
187187
char *load_data_dir;
188188
struct client_authentication_info client_auth_info[MAX_AUTHENTICATION_FACTOR];
189189
void *ssl_session_data; /** the session serialization to use */
190+
void *ssl_context;
190191
};
191192

192193
struct MYSQL_METHODS {

‎include/violite.h‎

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -253,13 +253,24 @@ const char *sslGetErrString(enum enum_ssl_init_error err);
253253

254254
struct st_VioSSLFd {
255255
SSL_CTX *ssl_context;
256+
/*
257+
"owned" indicates whether SSL_CTX_free should be called on this instance
258+
or not. If mysql_take_ssl_context_ownership is called, the context
259+
becomes owned by the application and not by the MySQL client library (ie,
260+
owned becomes false). Likewise, if a context is supplied by
261+
mysql_options(..., MYSQL_OPT_SSL_CONTEXT, ...) then it is also not owned
262+
by the client library.
263+
*/
264+
bool owned;
256265
};
257266

258267
int sslaccept(struct st_VioSSLFd *, MYSQL_VIO, long timeout,
259268
unsigned long *errptr);
260269
int sslconnect(struct st_VioSSLFd *, MYSQL_VIO, long timeout,
261270
SSL_SESSION *session, unsigned long *errptr, SSL **ssl);
262271

272+
struct st_VioSSLFd *new_VioSSLConnectorFdFromContext(
273+
SSL_CTX *context, enum enum_ssl_init_error *error);
263274
struct st_VioSSLFd *new_VioSSLConnectorFd(
264275
const char *key_file, const char *cert_file, const char *ca_file,
265276
const char *ca_path, const char *cipher, const char *ciphersuites,
@@ -273,7 +284,7 @@ struct st_VioSSLFd *new_VioSSLAcceptorFd(
273284
const char *ca_path, const char *cipher, const char *ciphersuites,
274285
enum enum_ssl_init_error *error, const char *crl_file, const char *crl_path,
275286
const long ssl_ctx_flags);
276-
void free_vio_ssl_acceptor_fd(struct st_VioSSLFd *fd);
287+
void free_vio_ssl_fd(struct st_VioSSLFd *fd);
277288

278289
void vio_ssl_end();
279290

‎libmysql/CMakeLists.txt‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,8 @@ SET(CLIENT_API_FUNCTIONS
145145
mysql_get_ssl_session_reused
146146
mysql_get_ssl_session_data
147147
mysql_free_ssl_session_data
148+
mysql_take_ssl_context_ownership
149+
148150
CACHE INTERNAL "Functions exported by client API"
149151
)
150152

‎plugin/x/client/xconnection_impl.cc‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -830,7 +830,7 @@ void Connection_impl::close() {
830830
}
831831

832832
if (m_vioSslFd) {
833-
free_vio_ssl_acceptor_fd(m_vioSslFd);
833+
free_vio_ssl_fd(m_vioSslFd);
834834
m_vioSslFd = nullptr;
835835
}
836836
}

‎plugin/x/src/ssl_context.cc‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ bool Ssl_context::setup(const Config &config) {
8787
}
8888

8989
Ssl_context::~Ssl_context() {
90-
if (m_ssl_acceptor) free_vio_ssl_acceptor_fd(m_ssl_acceptor);
90+
if (m_ssl_acceptor) free_vio_ssl_fd(m_ssl_acceptor);
9191
}
9292

9393
/** Start a TLS session in the connection.
@@ -107,7 +107,7 @@ bool Ssl_context::activate_tls(iface::Vio *conn,
107107

108108
void Ssl_context::reset() {
109109
if (!m_config || !m_ssl_acceptor) return;
110-
free_vio_ssl_acceptor_fd(m_ssl_acceptor);
110+
free_vio_ssl_fd(m_ssl_acceptor);
111111
setup(*m_config);
112112
}
113113

‎sql-common/client.cc‎

Lines changed: 67 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -3462,6 +3462,7 @@ static void mysql_ssl_free(MYSQL *mysql) {
34623462
mysql->options.extension->client_auth_info[idx].password = nullptr;
34633463
}
34643464
}
3465+
mysql->options.extension->ssl_context = nullptr;
34653466
}
34663467
mysql->options.ssl_key = nullptr;
34673468
mysql->options.ssl_cert = nullptr;
@@ -3628,6 +3629,19 @@ bool STDCALL mysql_get_ssl_session_reused(MYSQL *mysql) {
36283629
return false;
36293630
}
36303631

3632+
void *STDCALL
3633+
mysql_take_ssl_context_ownership(MYSQL *mysql MY_ATTRIBUTE((unused))) {
3634+
DBUG_ENTER("mysql_take_ssl_context_ownership");
3635+
#if defined(HAVE_OPENSSL)
3636+
if (mysql->connector_fd) {
3637+
struct st_VioSSLFd *ssl_fd = (struct st_VioSSLFd *)mysql->connector_fd;
3638+
ssl_fd->owned = false;
3639+
DBUG_RETURN(ssl_fd->ssl_context);
3640+
}
3641+
#endif
3642+
DBUG_RETURN(nullptr);
3643+
}
3644+
36313645
/*
36323646
Check the server's (subject) Common Name against the
36333647
hostname we connected to
@@ -4461,22 +4475,34 @@ static int cli_establish_ssl(MYSQL *mysql) {
44614475
MYSQL_TRACE_STAGE(mysql, SSL_NEGOTIATION);
44624476

44634477
/* Create the VioSSLConnectorFd - init SSL and load certs */
4464-
if (!(ssl_fd = new_VioSSLConnectorFd(
4465-
options->ssl_key, options->ssl_cert, options->ssl_ca,
4466-
options->ssl_capath, options->ssl_cipher,
4467-
options->extension ? options->extension->tls_ciphersuites
4468-
: nullptr,
4469-
&ssl_init_error,
4470-
options->extension ? options->extension->ssl_crl : nullptr,
4471-
options->extension ? options->extension->ssl_crlpath : nullptr,
4472-
options->extension ? options->extension->ssl_ctx_flags : 0,
4473-
verify_identity ? mysql->host : nullptr))) {
4474-
set_mysql_extended_error(mysql, CR_SSL_CONNECTION_ERROR, unknown_sqlstate,
4475-
ER_CLIENT(CR_SSL_CONNECTION_ERROR),
4476-
sslGetErrString(ssl_init_error));
4477-
goto error;
4478+
if (!mysql->connector_fd) {
4479+
/* Create the VioSSLConnectorFd - init SSL and load certs */
4480+
if (options->extension && options->extension->ssl_context) {
4481+
ssl_fd = new_VioSSLConnectorFdFromContext(
4482+
(SSL_CTX *)options->extension->ssl_context, &ssl_init_error);
4483+
} else {
4484+
if (!(ssl_fd = new_VioSSLConnectorFd(
4485+
options->ssl_key, options->ssl_cert, options->ssl_ca,
4486+
options->ssl_capath, options->ssl_cipher,
4487+
options->extension ? options->extension->tls_ciphersuites
4488+
: nullptr,
4489+
&ssl_init_error,
4490+
options->extension ? options->extension->ssl_crl : nullptr,
4491+
options->extension ? options->extension->ssl_crlpath
4492+
: nullptr,
4493+
options->extension ? options->extension->ssl_ctx_flags : 0,
4494+
verify_identity ? mysql->host : nullptr))) {
4495+
set_mysql_extended_error(mysql, CR_SSL_CONNECTION_ERROR,
4496+
unknown_sqlstate,
4497+
ER_CLIENT(CR_SSL_CONNECTION_ERROR),
4498+
sslGetErrString(ssl_init_error));
4499+
goto error;
4500+
}
4501+
}
4502+
mysql->connector_fd = (unsigned char *)ssl_fd;
4503+
} else {
4504+
ssl_fd = (struct st_VioSSLFd *)mysql->connector_fd;
44784505
}
4479-
mysql->connector_fd = (unsigned char *)ssl_fd;
44804506
SSL_SESSION *ssl_session = ssl_session_deserialize_from_data(mysql);
44814507

44824508
/* Connect to the server */
@@ -4624,20 +4650,26 @@ static net_async_status cli_establish_ssl_nonblocking(MYSQL *mysql, int *res) {
46244650
long flags = options->extension ? options->extension->ssl_ctx_flags : 0;
46254651

46264652
/* Create the VioSSLConnectorFd - init SSL and load certs */
4627-
if (!(ssl_fd = new_VioSSLConnectorFd(
4628-
options->ssl_key, options->ssl_cert, options->ssl_ca,
4629-
options->ssl_capath, options->ssl_cipher,
4630-
options->extension ? options->extension->tls_ciphersuites
4631-
: nullptr,
4632-
&ssl_init_error,
4633-
options->extension ? options->extension->ssl_crl : nullptr,
4634-
options->extension ? options->extension->ssl_crlpath : nullptr,
4635-
flags, verify_identity ? mysql->host : nullptr))) {
4636-
set_mysql_extended_error(mysql, CR_SSL_CONNECTION_ERROR,
4637-
unknown_sqlstate,
4638-
ER_CLIENT(CR_SSL_CONNECTION_ERROR),
4639-
sslGetErrString(ssl_init_error));
4640-
goto error;
4653+
if (options->extension && options->extension->ssl_context) {
4654+
ssl_fd = new_VioSSLConnectorFdFromContext(
4655+
(SSL_CTX *)options->extension->ssl_context, &ssl_init_error);
4656+
} else {
4657+
if (!(ssl_fd = new_VioSSLConnectorFd(
4658+
options->ssl_key, options->ssl_cert, options->ssl_ca,
4659+
options->ssl_capath, options->ssl_cipher,
4660+
options->extension ? options->extension->tls_ciphersuites
4661+
: nullptr,
4662+
&ssl_init_error,
4663+
options->extension ? options->extension->ssl_crl : nullptr,
4664+
options->extension ? options->extension->ssl_crlpath
4665+
: nullptr,
4666+
flags, verify_identity ? mysql->host : nullptr))) {
4667+
set_mysql_extended_error(mysql, CR_SSL_CONNECTION_ERROR,
4668+
unknown_sqlstate,
4669+
ER_CLIENT(CR_SSL_CONNECTION_ERROR),
4670+
sslGetErrString(ssl_init_error));
4671+
goto error;
4672+
}
46414673
}
46424674
mysql->connector_fd = (unsigned char *)ssl_fd;
46434675
} else {
@@ -7461,8 +7493,7 @@ void mysql_close_free(MYSQL *mysql) {
74617493
my_free(mysql->field_alloc);
74627494

74637495
if (mysql->connector_fd)
7464-
free_vio_ssl_acceptor_fd(
7465-
reinterpret_cast<st_VioSSLFd *>(mysql->connector_fd));
7496+
free_vio_ssl_fd(reinterpret_cast<st_VioSSLFd *>(mysql->connector_fd));
74667497
mysql->connector_fd = nullptr;
74677498

74687499
mysql->field_alloc = nullptr;
@@ -8727,6 +8758,11 @@ int STDCALL mysql_options(MYSQL *mysql, enum mysql_option option,
87278758
EXTENSION_SET_STRING(&mysql->options, ssl_session_data,
87288759
static_cast<const char *>(arg));
87298760
break;
8761+
case MYSQL_OPT_SSL_CONTEXT:
8762+
ENSURE_EXTENSIONS_PRESENT(&mysql->options);
8763+
mysql->options.extension->ssl_context = const_cast<void *>(arg);
8764+
break;
8765+
87308766
default:
87318767
return 1;
87328768
}

0 commit comments

Comments
 (0)