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

Commit 22abc72

Browse files
aditya-jalanHerman Lee
authored andcommitted
Add libmysql option to specify the SNI servername for SSL connection
Summary: This change adds an option to specify the SNI server name to be used when the client does a sslConnect . Added a new mysql_option, MYSQL_OPT_TLS_SNI_SERVERNAME. It can be set with : `mysql_options(mysql, MYSQL_OPT_TLS_SNI_SERVERNAME, dbname);` If the server rejects the request for this sni servername, clients will get the new error code 2068 (SSL_R_TLSV1_UNRECOGNIZED_NAME) instead of the general 2026(CR_SSL_CONNECTION_ERROR). Reviewed By: lloyd Differential Revision: D24125968
1 parent 72570da commit 22abc72

9 files changed

Lines changed: 91 additions & 32 deletions

File tree

‎include/errmsg.h‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -261,7 +261,8 @@ extern const char *client_errors[]; /* Error messages */
261261
// Facebook client errors
262262
#define CR_NET_READ_INTERRUPTED 2200
263263
#define CR_NET_WRITE_INTERRUPTED 2201
264-
#define CR_ERROR_LAST /*Copy last error nr:*/ 2201
264+
#define CR_TLS_SERVER_NOT_FOUND 2202
265+
#define CR_ERROR_LAST /*Copy last error nr:*/ 2202
265266
/* Add error numbers before CR_ERROR_LAST and change it accordingly. */
266267

267268
#define CR_PLACEHOLDER_FIRST CR_PLACEHOLDER_2074

‎include/mysql.h‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,7 @@ enum mysql_option {
221221
MYSQL_OPT_CONNECT_TIMEOUT_MS,
222222
MYSQL_OPT_READ_TIMEOUT_MS,
223223
MYSQL_OPT_WRITE_TIMEOUT_MS,
224+
MYSQL_OPT_TLS_SNI_SERVERNAME,
224225
};
225226

226227
/**

‎include/mysql.h.pp‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -414,7 +414,7 @@
414414
client_errno <= 2199;
415415
}
416416
static inline const char *ER_CLIENT(int client_errno) {
417-
if (client_errno >= 2000 && client_errno <= 2201 &&
417+
if (client_errno >= 2000 && client_errno <= 2202 &&
418418
!isPlaceHolder(client_errno)) {
419419
return client_errors[client_errno - 2000];
420420
}
@@ -515,6 +515,7 @@
515515
MYSQL_OPT_CONNECT_TIMEOUT_MS,
516516
MYSQL_OPT_READ_TIMEOUT_MS,
517517
MYSQL_OPT_WRITE_TIMEOUT_MS,
518+
MYSQL_OPT_TLS_SNI_SERVERNAME,
518519
};
519520
struct st_mysql_options_extention;
520521
struct st_mysql_options {

‎include/sql_common.h‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,7 @@ struct st_mysql_options_extention {
188188
bool connection_compressed;
189189
char *load_data_dir;
190190
struct client_authentication_info client_auth_info[MAX_AUTHENTICATION_FACTOR];
191+
char *tls_sni_servername; /* TLS sni server name */
191192
void *ssl_session_data; /** the session serialization to use */
192193
void *ssl_context;
193194
};

‎include/violite.h‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -273,7 +273,8 @@ struct st_VioSSLFd {
273273
int sslaccept(struct st_VioSSLFd *, MYSQL_VIO, long timeout,
274274
unsigned long *errptr);
275275
int sslconnect(struct st_VioSSLFd *, MYSQL_VIO, long timeout,
276-
SSL_SESSION *session, unsigned long *errptr, SSL **ssl);
276+
SSL_SESSION *session, unsigned long *errptr, SSL **ssl,
277+
const char *sni_servername = nullptr);
277278

278279
struct st_VioSSLFd *new_VioSSLConnectorFdFromContext(
279280
SSL_CTX *context, enum enum_ssl_init_error *error);

‎libmysql/errmsg.cc‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,8 @@ const char *client_errors[] = {
247247
"Placeholder 2199",
248248
"Read timeout is reached",
249249
"Write timeout is reached",
250+
"Server rejected the ssl handshake for specified sni servername, sslerror: "
251+
"%-.100s",
250252
""};
251253

252254
static const char *get_client_errmsg(int nr) {

‎sql-common/client.cc‎

Lines changed: 57 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -3587,6 +3587,7 @@ static void mysql_ssl_free(MYSQL *mysql) {
35873587
my_free(mysql->options.extension->ssl_crlpath);
35883588
my_free(mysql->options.extension->tls_ciphersuites);
35893589
my_free(mysql->options.extension->load_data_dir);
3590+
my_free(mysql->options.extension->tls_sni_servername);
35903591
for (unsigned int idx = 0; idx < MAX_AUTHENTICATION_FACTOR; idx++) {
35913592
if (mysql->options.extension->client_auth_info[idx].plugin_name) {
35923593
my_free(mysql->options.extension->client_auth_info[idx].plugin_name);
@@ -3613,6 +3614,7 @@ static void mysql_ssl_free(MYSQL *mysql) {
36133614
mysql->options.extension->ssl_fips_mode = SSL_FIPS_MODE_OFF;
36143615
mysql->options.extension->tls_ciphersuites = nullptr;
36153616
mysql->options.extension->load_data_dir = nullptr;
3617+
mysql->options.extension->tls_sni_servername = nullptr;
36163618
}
36173619
mysql->connector_fd = nullptr;
36183620
}
@@ -4649,27 +4651,39 @@ static int cli_establish_ssl(MYSQL *mysql) {
46494651
/* Connect to the server */
46504652
DBUG_PRINT("info", ("IO layer change in progress..."));
46514653
MYSQL_TRACE(SSL_CONNECT, mysql, ());
4652-
ssize_t ret = sslconnect(ssl_fd, net->vio,
4653-
timeout_to_seconds(mysql->options.connect_timeout),
4654-
ssl_session, &ssl_error, nullptr);
4654+
ssize_t ret = sslconnect(
4655+
ssl_fd, net->vio, timeout_to_seconds(mysql->options.connect_timeout),
4656+
ssl_session, &ssl_error, nullptr,
4657+
options->extension ? options->extension->tls_sni_servername : nullptr);
46554658
if (ssl_session != nullptr) SSL_SESSION_free(ssl_session);
4656-
switch (ret) {
4657-
case VIO_SOCKET_ERROR:
4658-
char ssl_buf[512];
4659-
char buf[1025];
4660-
ERR_error_string_n(ssl_error, ssl_buf, 512);
4661-
ssl_buf[511] = 0;
4662-
snprintf(buf, sizeof(buf) - 1, "%s (errno %d)", ssl_buf, errno);
4659+
if (ret) {
4660+
switch (ret) {
4661+
case VIO_SOCKET_READ_TIMEOUT:
4662+
set_mysql_error(mysql, CR_NET_READ_INTERRUPTED, unknown_sqlstate);
4663+
goto error;
4664+
case VIO_SOCKET_WRITE_TIMEOUT:
4665+
set_mysql_error(mysql, CR_NET_WRITE_INTERRUPTED, unknown_sqlstate);
4666+
goto error;
4667+
default:
4668+
break;
4669+
/* continue for error handling */
4670+
}
4671+
char ssl_buf[512];
4672+
char buf[1025];
4673+
ERR_error_string_n(ssl_error, ssl_buf, 512);
4674+
ssl_buf[511] = 0;
4675+
snprintf(buf, sizeof(buf) - 1, "%s (errno %d)", ssl_buf, errno);
4676+
4677+
if (ERR_GET_REASON(ssl_error) == SSL_R_TLSV1_UNRECOGNIZED_NAME) {
4678+
set_mysql_extended_error(mysql, CR_TLS_SERVER_NOT_FOUND,
4679+
unknown_sqlstate,
4680+
ER_CLIENT(CR_TLS_SERVER_NOT_FOUND), buf);
4681+
} else {
46634682
set_mysql_extended_error(mysql, CR_SSL_CONNECTION_ERROR,
46644683
unknown_sqlstate,
46654684
ER_CLIENT(CR_SSL_CONNECTION_ERROR), buf);
4666-
goto error;
4667-
case VIO_SOCKET_READ_TIMEOUT:
4668-
set_mysql_error(mysql, CR_NET_READ_INTERRUPTED, unknown_sqlstate);
4669-
goto error;
4670-
case VIO_SOCKET_WRITE_TIMEOUT:
4671-
set_mysql_error(mysql, CR_NET_WRITE_INTERRUPTED, unknown_sqlstate);
4672-
goto error;
4685+
}
4686+
goto error;
46734687
}
46744688
DBUG_PRINT("info", ("IO layer change done!"));
46754689

@@ -4834,7 +4848,10 @@ static net_async_status cli_establish_ssl_nonblocking(MYSQL *mysql, int *res) {
48344848
MYSQL_TRACE(SSL_CONNECT, mysql, ());
48354849
if ((ret = sslconnect(ssl_fd, net->vio,
48364850
timeout_to_seconds(mysql->options.connect_timeout),
4837-
ssl_session, &ssl_error, &ctx->ssl))) {
4851+
ssl_session, &ssl_error, &ctx->ssl,
4852+
options->extension
4853+
? options->extension->tls_sni_servername
4854+
: nullptr))) {
48384855
if (ssl_session != nullptr) SSL_SESSION_free(ssl_session);
48394856
switch (ret) {
48404857
case VIO_SOCKET_WANT_READ:
@@ -4859,8 +4876,17 @@ static net_async_status cli_establish_ssl_nonblocking(MYSQL *mysql, int *res) {
48594876
ERR_error_string_n(ssl_error, ssl_buf, 512);
48604877
ssl_buf[511] = 0;
48614878
snprintf(buf, sizeof(buf) - 1, "%s (errno %d)", ssl_buf, errno);
4862-
set_mysql_extended_error(mysql, CR_SSL_CONNECTION_ERROR, unknown_sqlstate,
4863-
ER_CLIENT(CR_SSL_CONNECTION_ERROR), buf);
4879+
4880+
if (ERR_GET_REASON(ssl_error) == SSL_R_TLSV1_UNRECOGNIZED_NAME) {
4881+
set_mysql_extended_error(mysql, CR_TLS_SERVER_NOT_FOUND,
4882+
unknown_sqlstate,
4883+
ER_CLIENT(CR_TLS_SERVER_NOT_FOUND), buf);
4884+
} else {
4885+
set_mysql_extended_error(mysql, CR_SSL_CONNECTION_ERROR,
4886+
unknown_sqlstate,
4887+
ER_CLIENT(CR_SSL_CONNECTION_ERROR), buf);
4888+
}
4889+
48644890
goto error;
48654891
}
48664892
if (ssl_session != nullptr) SSL_SESSION_free(ssl_session);
@@ -8942,6 +8968,10 @@ int STDCALL mysql_options(MYSQL *mysql, enum mysql_option option,
89428968
EXTENSION_SET_STRING(&mysql->options, tls_ciphersuites,
89438969
static_cast<const char *>(arg));
89448970
break;
8971+
case MYSQL_OPT_TLS_SNI_SERVERNAME:
8972+
EXTENSION_SET_STRING(&mysql->options, tls_sni_servername,
8973+
static_cast<const char *>(arg));
8974+
break;
89458975
case MYSQL_OPT_SSL_CRL:
89468976
if (mysql->options.extension)
89478977
my_free(mysql->options.extension->ssl_crl);
@@ -9231,6 +9261,7 @@ int STDCALL mysql_options(MYSQL *mysql, enum mysql_option option,
92319261
MYSQL_OPT_SSL_CA, MYSQL_OPT_SSL_CAPATH, MYSQL_OPT_SSL_CIPHER,
92329262
MYSQL_OPT_TLS_CIPHERSUITES, MYSQL_OPT_SSL_CRL, MYSQL_OPT_SSL_CRLPATH,
92339263
MYSQL_OPT_TLS_VERSION, MYSQL_SERVER_PUBLIC_KEY, MYSQL_OPT_SSL_FIPS_MODE
9264+
MYSQL_OPT_TLS_SNI_SERVERNAME
92349265
92359266
<none, error returned>
92369267
MYSQL_OPT_NAMED_PIPE, MYSQL_OPT_CONNECT_ATTR_RESET,
@@ -9364,6 +9395,12 @@ int STDCALL mysql_get_option(MYSQL *mysql, enum mysql_option option,
93649395
mysql->options.extension ? mysql->options.extension->tls_ciphersuites
93659396
: nullptr;
93669397
break;
9398+
case MYSQL_OPT_TLS_SNI_SERVERNAME:
9399+
*(static_cast<char **>(const_cast<void *>(arg))) =
9400+
mysql->options.extension
9401+
? mysql->options.extension->tls_sni_servername
9402+
: nullptr;
9403+
break;
93679404
case MYSQL_OPT_RETRY_COUNT:
93689405
*(const_cast<uint *>(static_cast<const uint *>(arg))) =
93699406
mysql->options.extension ? mysql->options.extension->retry_count : 1;

‎testclients/mysql_client_test.cc‎

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19039,7 +19039,8 @@ static void test_wl6791() {
1903919039
MYSQL_OPT_CAN_HANDLE_EXPIRED_PASSWORDS,
1904019040
MYSQL_OPT_OPTIONAL_RESULTSET_METADATA},
1904119041
const_char_opts[] =
19042-
{ MYSQL_READ_DEFAULT_FILE,
19042+
{
19043+
MYSQL_READ_DEFAULT_FILE,
1904319044
MYSQL_READ_DEFAULT_GROUP,
1904419045
MYSQL_SET_CHARSET_DIR,
1904519046
MYSQL_SET_CHARSET_NAME,
@@ -19056,9 +19057,11 @@ static void test_wl6791() {
1905619057
MYSQL_OPT_SSL_CAPATH,
1905719058
MYSQL_OPT_SSL_CIPHER,
1905819059
MYSQL_OPT_TLS_CIPHERSUITES,
19060+
MYSQL_OPT_TLS_SNI_SERVERNAME,
1905919061
MYSQL_OPT_SSL_CRL,
1906019062
MYSQL_OPT_SSL_CRLPATH,
19061-
MYSQL_SERVER_PUBLIC_KEY },
19063+
MYSQL_SERVER_PUBLIC_KEY
19064+
},
1906219065
err_opts[] = {
1906319066
MYSQL_OPT_NAMED_PIPE, MYSQL_OPT_CONNECT_ATTR_RESET,
1906419067
MYSQL_OPT_CONNECT_ATTR_DELETE, MYSQL_INIT_COMMAND};

‎vio/viossl.cc‎

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -653,7 +653,8 @@ static void print_ssl_session_id(SSL_SESSION *sess, const char *action) {
653653

654654
static int ssl_do(struct st_VioSSLFd *ptr, Vio *vio, long timeout,
655655
SSL_SESSION *ssl_session, ssl_handshake_func_t func,
656-
unsigned long *ssl_errno_holder, SSL **sslptr) {
656+
unsigned long *ssl_errno_holder, SSL **sslptr,
657+
const char *sni_servername) {
657658
SSL *ssl = nullptr;
658659
my_socket sd = mysql_socket_getfd(vio->mysql_socket);
659660

@@ -691,6 +692,17 @@ static int ssl_do(struct st_VioSSLFd *ptr, Vio *vio, long timeout,
691692
}
692693
}
693694

695+
// Check if the openssl supports SNI, and only then set the tlsext_host_name
696+
#if OPENSSL_VERSION_NUMBER >= 0x00908070L && !defined(OPENSSL_NO_TLSEXT)
697+
if (sni_servername) {
698+
if (!SSL_set_tlsext_host_name(ssl, const_cast<char *>(sni_servername))) {
699+
DBUG_PRINT("error", ("SSL_set_tlsext_host_name failure"));
700+
*ssl_errno_holder = ERR_get_error();
701+
return 1;
702+
}
703+
}
704+
#endif /* OPENSSL_VERSION_NUMBER >= 0x00908070 && !def(OPENSSL_NO_TLSEXT) */
705+
694706
DBUG_PRINT("info", ("ssl: %p timeout: %ld", ssl, timeout));
695707
SSL_SESSION_set_timeout(SSL_get_session(ssl), timeout);
696708
SSL_set_fd(ssl, sd);
@@ -792,21 +804,21 @@ int sslaccept(struct st_VioSSLFd *ptr, Vio *vio, long timeout,
792804
unsigned long *ssl_errno_holder) {
793805
DBUG_TRACE;
794806
vio_set_blocking(vio, false);
795-
int ret =
796-
ssl_do(ptr, vio, timeout, nullptr, SSL_accept, ssl_errno_holder, nullptr);
807+
int ret = ssl_do(ptr, vio, timeout, nullptr, SSL_accept, ssl_errno_holder,
808+
nullptr, nullptr);
797809
return ret;
798810
}
799811

800812
int sslconnect(struct st_VioSSLFd *ptr, Vio *vio, long timeout,
801-
SSL_SESSION *session, unsigned long *ssl_errno_holder,
802-
SSL **ssl) {
813+
SSL_SESSION *session, unsigned long *ssl_errno_holder, SSL **ssl,
814+
const char *sni_servername) {
803815
DBUG_TRACE;
804816
// Setting non blocking mode since openssl/boringssl does not support
805817
// timeout with blocking mode on handshake
806818
vio_set_blocking(vio, false);
807819

808-
int ret =
809-
ssl_do(ptr, vio, timeout, session, SSL_connect, ssl_errno_holder, ssl);
820+
int ret = ssl_do(ptr, vio, timeout, session, SSL_connect, ssl_errno_holder,
821+
ssl, sni_servername);
810822
return ret;
811823
}
812824

0 commit comments

Comments
 (0)