Added a new structure MARIADB_X509_INFO, which
contains information about servers certificate.
The information can be obtained via mysql_get_infov API
function:
MARIADB_X509_INFO *info;
mariadb_get_infov(mysql, MARIADB_TLS_PEER_CERT_INFO, &info);
With MDEV-30366, server now permit to send a result-set containing generated id and Affected rows for each bulk operation. This feature can be enabled with option MARIADB_OPT_BULK_UNIT_RESULTS when server supports it.
This reverts 395641549ac7..536d9e2b9e5b, in particular:
8dffd56936 MDEV-31857 enable MYSQL_OPT_SSL_VERIFY_SERVER_CERT by default
a99570c118 MDEV-31855 SSL cert validation protocol extension
9aa15e72a7 TLS fingerprint
and related commits
because the default value of every option is 0
(option and option.extension are bzero-ed to reset),
tls_verify_server_cert was renamed to tls_allow_invalid_server_cert
with the default value of 0, "do not allow".
API didn't change, it's still MYSQL_OPT_SSL_VERIFY_SERVER_CERT
* extend the client auth plugin API with a new callback
* relax the plugin version check to allow load a plugin with the
same major version, even if the minor versions differ
* implement the protocol extension:
- don't abort at once if the certificate is self signed and
no CA was explicitly specified
- allow it if it passes fingerprint check
- allow it if plugin has hash_password_bin callback, password was
non-empty and the control hash matches server's
they cannot be sent by the server (ma_net_safe_read() guarantees that)
so they all should be safe and not forged
also, use existing macros to check for error ranges, they are
sufficiently parenthesized to avoid compiler warnings (errors with -Werror)
about "you might want to add parentheses here"
MariaDB Connector/C does not distinguish [application-layer error
packets](https://mariadb.com/kb/en/err_packet) that it receives prior to TLS
handshake completion from those that it receives immediately after.
(A trivially modified server built from
https://github.com/dlenski/mariadb-server/commit/demonstration_of_CONC-648_vulnerability
can easily be used to demonstrate this.)
Pre-TLS error packet received from this trivially modified server. This packet
should NOT be trusted to actually originate from the server:
$ mariadb --ssl --ssl-verify-server-cert -uUsername -pVerySecretPassword -h CONC-648.vuln.demo.server.com
ERROR 1815 (HY000): Internal error: Client will accept this error as genuine even if running with --ssl --ssl-verify-server-cert, and even though this error is sent in plaintext PRIOR TO TLS HANDSHAKE.
Post-(TLS handshake) error packet received from a normal MariaDB server upon
an attempt to connect with incorrect credentials. This error packet CAN be
trusted to actually originate from the server, assuming transitive trust in
the TLS protocol implementation and PKI-based certificate validation:
$ mariadb --ssl --ssl-verify-server-cert -uUsername -pWrongPassword -h $NORMAL_MARIADB10.6.14_SERVER
ERROR 1045 (28000): Access denied for user 'Username'@'A.B.C.D' (using password: YES)
This client behavior opens up MariaDB Connector/C clients to an extremely
straightforward [downgrade attack](https://en.wikipedia.org/wiki/Downgrade_attack).
An on-path or pervasive attacker can inject errors into MariaDB
client→server connections that are intended to be protected by TLS, and the
client has no clear mechanism to distinguish such errors from errors that
actually come from the server.
An attacker could easily use this to DOS a client, or even influence its
behavior. For example, consider a client application which is configured…
1. To use TLS with server certificate validation
(`--ssl --ssl-verify-server-cert`), and
2. To wait for a back-off period and then *retry* connection attempts if the server
responds with `ER_CON_COUNT_ERROR` ("Too many connections") from the
server, and
3. To give up and shut down if its connection attempts fail with
`ER_ACCESS_DENIED_ERROR` ("Access denied for user"), on the assumption
that this is due to an incorrect or expired password, and cannot be
resolved without human intervention.
An attacker could completely disable the retry mechanism of this application
by intercepting connection attempts and replying with
`ER_ACCESS_DENIED_ERROR` packets.
This patch modifies MariaDB Connector/C so that if the client is configured
to use TLS, error packets received prior to the completion of the TLS
handshake are untrusted, and are changed to a generic `CR_CONNECTION_ERROR`.
$ mariadb --ssl --ssl-verify-server-cert -uUsername -pVerySecretPassword -h CONC-648.vuln.demo.server.com
ERROR 2002 (HY000): Received error packet before completion of TLS handshake. The authenticity of the following error cannot be verified:
1815 - Internal error: Client will accept this error as genuine even if running with --ssl --ssl-verify-server-cert, and even though this error is sent in plaintext PRIOR TO TLS HANDSHAKE.
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.
Per @vuvova in
https://github.com/mariadb-corporation/mariadb-connector-c/pull/223#issuecomment-1854720364:
> I don't think the client should accept client-side errors from the server
> at all.
If the server sends an error packet with error codes in the ranges
`CR_{MIN,MAX}_ERROR` (codes [2000, 2999]) or `CER_{MIN,MAX}_ERROR` (codes
[5000, 5999]), we will replace these with `CR_MALFORMED_PACKET`, rather than
propagating them to the client user.
Since the server certification option is used by client
only, there is no need to have this flag in server and or
client capabilities. The server itself validates client
certificate depending on the user definition.
When resetting the connection with mysql reset_connection(), the
server_status must be checked and any other resultsets that mayi
exist must be removed.
- ER() macro now checks if the error code is known, if not it will return
"Unknown or undefined error code" (instead of crashing)
- SET_CLIENT_STMT_ERROR now maps to stmt_set_error and accepts variadic
arguments
This feature allows client applications to register a callback function,
which is called as soon as the server status changes or session_track
information was sent by the server.
Registration is handled via mysql_optionsv() API function:
mysql_optionsv(mysql, MARIADB_OPT_STATUS_CALLBACK, function, data)
The callback function must be defined as follws:
void status_callback(void *data, enum enum_mariadb_status_info type, ..)
Parameters:
- data Pointer passed with registration of callback function
(usually a connection handle)
- type Information type STATUS_TYPE or SESSION_TRACK_TYPE
Variadic Parameters:
if (type == STATUS_TYPE):
- server status (unsigned int)
if (type == SESSION_TRACK_TYPE)
- enum enum_session_state_type track_type - session track type
if (track_type == SESSION_TRACK_SYSTEM_VARIABLES)
- MARIADB_CONST_STRING *key
- MARIADB_CONST_STRING *value
else
- MARIADB_CONST_STRING *value
An example can be found in connection.c (test_status_callback)