Skip to content

Commit

Permalink
[CONC-654] Stop leaking client identifying information to the server …
Browse files Browse the repository at this point in the history
…before the TLS handshake

The server implementation here was incorrect as well, unnecessarily
reading—and TRUSTING—client identifying information sent before the TLS
handshake.  That's in MDEV-31585.

As a result of the server's mishandling of this information, it's not
possible for the client to fix this in a way that's backwards-compatible
with old servers.

We rely on the server sending a capability bit to indicate that the
server-side bug has been fixed:

    /* This capability is set if:
     *
     * - The CLIENT knows how to send a truncated 2-byte SSLRequest
     *   packet, containing no information other than the CLIENT_SSL flag
     *   which is necessary to trigger the TLS handshake, and to send its
     *   complete capability flags and other identifying information after
     *   the TLS handshake.
     * - The SERVER knows how to receive this truncated 2-byte SSLRequest
     *   packet, and to receive the client's complete capability bits
     *   after the TLS handshake.
     *
     */
    #define CLIENT_CAN_SSL_V2    (1ULL << 37)

All new code of the whole pull request, including one or several files
that are either new files or modified ones, are contributed under the
BSD-new license. I am contributing on behalf of my employer Amazon Web
Services, Inc.
  • Loading branch information
dlenski committed Jul 11, 2023
1 parent b090994 commit ea4282e
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 18 deletions.
16 changes: 15 additions & 1 deletion include/mariadb_com.h
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,19 @@ enum enum_server_command
#define CLIENT_CAN_HANDLE_EXPIRED_PASSWORDS (1UL << 22)
#define CLIENT_SESSION_TRACKING (1UL << 23)
#define CLIENT_ZSTD_COMPRESSION (1UL << 26)
/* This capability is set if:
*
* - The CLIENT knows how to send a truncated 2-byte SSLRequest
* packet, containing no information other than the CLIENT_SSL flag
* which is necessary to trigger the TLS handshake, and to send its
* complete capability flags and other identifying information after
* the TLS handshake.
* - The SERVER knows how to receive this truncated 2-byte SSLRequest
* packet, and to receive the client's complete capability bits
* after the TLS handshake.
*
*/
#define CLIENT_CAN_SSL_V2 (1ULL << 37)
#define CLIENT_PROGRESS (1UL << 29) /* client supports progress indicator */
#define CLIENT_PROGRESS_OBSOLETE CLIENT_PROGRESS
#define CLIENT_SSL_VERIFY_SERVER_CERT (1UL << 30)
Expand Down Expand Up @@ -219,7 +232,8 @@ enum enum_server_command
CLIENT_PLUGIN_AUTH |\
CLIENT_PLUGIN_AUTH_LENENC_CLIENT_DATA | \
CLIENT_SESSION_TRACKING |\
CLIENT_CONNECT_ATTRS)
CLIENT_CONNECT_ATTRS |\
CLIENT_CAN_SSL_V2)

#define CLIENT_DEFAULT_FLAGS ((CLIENT_SUPPORTED_FLAGS & ~CLIENT_COMPRESS)\
& ~CLIENT_SSL)
Expand Down
57 changes: 40 additions & 17 deletions plugins/auth/my_auth.c
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,11 @@ static int send_client_reply_packet(MCPVIO_EXT *mpvio,
size_t conn_attr_len= (mysql->options.extension) ?
mysql->options.extension->connect_attrs_len : 0;

#if defined(HAVE_TLS) && !defined(EMBEDDED_LIBRARY)
bool server_supports_ssl_v2=
mysql->extension->mariadb_server_capabilities & (MARIADB_CLIENT_CAN_SSL_V2 >> 32);
#endif

/* see end= buff+32 below, fixed size of the packet is 32 bytes */
buff= malloc(33 + USERNAME_LENGTH + data_len + NAME_LEN + NAME_LEN + conn_attr_len + 9);
end= buff;
Expand Down Expand Up @@ -320,26 +325,44 @@ static int send_client_reply_packet(MCPVIO_EXT *mpvio,
if (mysql->options.use_ssl &&
(mysql->client_flag & CLIENT_SSL))
{
/*
Send UNENCRYPTED "Login Request" packet with mysql->client_flag
and max_packet_size, but no username; without this, the server
does not know we want to switch to SSL/TLS
FIXME: Sending this packet is a very very VERY bad idea. It
contains the client's preferred charset and flags in plaintext;
this can be used for fingerprinting the client software version,
and probable geographic location.
This offers a glaring opportunity for pervasive attackers to
easily target, intercept, and exploit the client-server
connection (e.g. "MITM all connections from known-vulnerable
client versions originating from countries X, Y, and Z").
*/
if (ma_net_write(net, (unsigned char *)buff, (size_t) (end-buff)) || ma_net_flush(net))
int ret;
if (server_supports_ssl_v2)
{
/*
The server doesn't inadvisably rely on information send in the
pre-TLS-handshake packet. Send it a dummy packet that
contains NOTHING except for the 2-byte client capabilities
with the CLIENT_SSL bit.
*/
unsigned char dummy[2];
int2store(dummy, CLIENT_SSL);
ret= (ma_net_write(net, dummy, sizeof(dummy)) || ma_net_flush(net));
}
else
{
/*
Send UNENCRYPTED "Login Request" packet with mysql->client_flag
and max_packet_size, but no username; without this, the server
does not know we want to switch to SSL/TLS
FIXME: Sending this packet is a very very VERY bad idea. It
contains the client's preferred charset and flags in plaintext;
this can be used for fingerprinting the client software version,
and probable geographic location.
This offers a glaring opportunity for pervasive attackers to
easily target, intercept, and exploit the client-server
connection (e.g. "MITM all connections from known-vulnerable
client versions originating from countries X, Y, and Z").
*/
ret= (ma_net_write(net, (unsigned char *)buff, (size_t) (end-buff)) || ma_net_flush(net));
}

if (ret)
{
my_set_error(mysql, CR_SERVER_LOST, SQLSTATE_UNKNOWN,
ER(CR_SERVER_LOST_EXTENDED),
"sending connection information to server",
"sending SSLRequest packet to server",
errno);
goto error;
}
Expand Down

0 comments on commit ea4282e

Please sign in to comment.