Skip to content
Permalink
Browse files

Workaround for CONC-417, MDEV-13492

At irregular intervals older windows versions (prior Windows 10) fail to establish a secure (TLS)
connection and return errors SEC_E_INVALID_TOKEN, SEC_E_BUFFER_TOO_SMALL or SEC_E_MESSAGE_ALTERED.
This is a bug in windows schannel library and was only fixed in recent versions, also OpenSSL provided
a workaround (see openssl/openssl#1350).
Since we are unable to fix this, we introduced a workaround for this problem. In case of an error
during TLS handshake we check the errorcode and try to reconnect up to three times if the error code
was SEC_E_INVALID_TOKEN, SEC_E_BUFFER_TOO_SMALL or SEC_E_MESSAGE_ALTERED.
  • Loading branch information
9EOR9 committed Sep 19, 2019
1 parent 261a5c4 commit de04c2e01fef13cb4545b85f47fd90ec92f2c95e
Showing with 38 additions and 2 deletions.
  1. +1 −0 include/ma_common.h
  2. +1 −0 include/mysql.h
  3. +32 −2 libmariadb/mariadb_lib.c
  4. +4 −0 libmariadb/secure/ma_schannel.c
@@ -91,6 +91,7 @@ typedef struct st_connection_handler

struct st_mariadb_net_extension {
enum enum_multi_status multi_status;
int extended_errno;
};

struct st_mariadb_session_state
@@ -140,6 +140,7 @@ extern const char *SQLSTATE_UNKNOWN;
(a)->net.last_errno= 0;\
strcpy((a)->net.sqlstate, "00000");\
(a)->net.last_error[0]= '\0';\
(a)->net.extension->extended_errno= 0;\
}

#define MYSQL_COUNT_ERROR (~(unsigned long long) 0)
@@ -1020,7 +1020,7 @@ mysql_init(MYSQL *mysql)
mysql->charset= mysql_find_charset_name(MARIADB_DEFAULT_CHARSET);
mysql->methods= &MARIADB_DEFAULT_METHODS;
strcpy(mysql->net.sqlstate, "00000");
mysql->net.last_error[0]= mysql->net.last_errno= 0;
mysql->net.last_error[0]= mysql->net.last_errno= mysql->net.extension->extended_errno= 0;

if (ENABLED_LOCAL_INFILE != LOCAL_INFILE_MODE_OFF)
mysql->options.client_flag|= CLIENT_LOCAL_FILES;
@@ -1199,9 +1199,39 @@ mysql_real_connect(MYSQL *mysql, const char *host, const char *user,
return my;
}
}

#ifndef HAVE_SCHANNEL
return mysql->methods->db_connect(mysql, host, user, passwd,
db, port, unix_socket, client_flag);
#else
/*
With older windows versions (prior Win 10) TLS connections periodically
fail with SEC_E_INVALID_TOKEN, SEC_E_BUFFER_TOO_SMALL or SEC_E_MESSAGE_ALTERED
error (see MDEV-13492). If the connect attempt returns on of these error codes
in mysql->net.extended_errno we will try to connect again (max. 3 times)
*/
#define MAX_SCHANNEL_CONNECT_ATTEMPTS 3
{
int ssl_retry= (mysql->options.use_ssl) ? MAX_SCHANNEL_CONNECT_ATTEMPTS : 1;
MYSQL *my= NULL;
while (ssl_retry)
{
if ((my= mysql->methods->db_connect(mysql, host, user, passwd,
db, port, unix_socket, client_flag)))
return my;

switch (mysql->net.extension->extended_errno) {
case SEC_E_INVALID_TOKEN:
case SEC_E_BUFFER_TOO_SMALL:
case SEC_E_MESSAGE_ALTERED:
ssl_retry--;
break;
default:
return NULL;
}
}
return my;
}
#endif
}

MYSQL *mthd_my_real_connect(MYSQL *mysql, const char *host, const char *user,
@@ -32,6 +32,10 @@ void ma_schannel_set_win_error(MARIADB_PVIO *pvio);
void ma_schannel_set_sec_error(MARIADB_PVIO *pvio, DWORD ErrorNo)
{
MYSQL *mysql= pvio->mysql;

if (ErrorNo != SEC_E_OK)
mysql->net.extension->extended_errno= ErrorNo;

switch(ErrorNo) {
case SEC_E_ILLEGAL_MESSAGE:
pvio->set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, "SSL connection error: The message received was unexpected or badly formatted");

0 comments on commit de04c2e

Please sign in to comment.
You can’t perform that action at this time.