From 721103eba15ec7bfb51bc9a70b52d35c91897a79 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20M=C3=A4kel=C3=A4?= Date: Sat, 26 Oct 2024 07:09:21 +0300 Subject: [PATCH 1/4] Fix zstd compression level bytes The MySQL protocol documentation as well as the comments in code state that the compression level is stored in one byte. The code, however, used four bytes. --- plugins/auth/my_auth.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/plugins/auth/my_auth.c b/plugins/auth/my_auth.c index 72773079..6c17259b 100644 --- a/plugins/auth/my_auth.c +++ b/plugins/auth/my_auth.c @@ -407,8 +407,7 @@ static int send_client_reply_packet(MCPVIO_EXT *mpvio, */ if (mysql->client_flag & CLIENT_ZSTD_COMPRESSION) { - int4store(end, (unsigned int)3); - end+= 4; + *end++= 3; } /* Write authentication package */ From fa987a3bc4df9db9e3aa646eee0ffccfe2b3b0b4 Mon Sep 17 00:00:00 2001 From: Georg Richter Date: Mon, 2 Dec 2024 06:36:56 +0100 Subject: [PATCH 2/4] Added test case for CONC-163 --- unittest/libmariadb/misc.c | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/unittest/libmariadb/misc.c b/unittest/libmariadb/misc.c index ccb5da8b..6f54d612 100644 --- a/unittest/libmariadb/misc.c +++ b/unittest/libmariadb/misc.c @@ -1522,8 +1522,44 @@ static int test_conc458(MYSQL *my __attribute__((unused))) return OK; } +static int test_conc163(MYSQL *mysql) +{ + int rc; + MYSQL_STMT *stmt; + + rc= mysql_query(mysql, "SET @a:=1"); + check_mysql_rc(rc, mysql); + + FAIL_IF(mysql_info(mysql) != NULL, "mysql_info: expected NULL"); + + rc= mysql_query(mysql, "CREATE OR REPLACE TABLE t1 AS SELECT 1"); + check_mysql_rc(rc, mysql); + + FAIL_IF(mysql_info(mysql) == NULL, "mysql_info: expected != NULL"); + + rc= mysql_query(mysql, "DROP TABLE t1"); + check_mysql_rc(rc, mysql); + + stmt= mysql_stmt_init(mysql); + rc= mariadb_stmt_execute_direct(stmt, SL("SET @a:=1")); + check_stmt_rc(rc, stmt); + FAIL_IF(mysql_info(mysql) != NULL, "mysql_info: expected NULL"); + + rc= mariadb_stmt_execute_direct(stmt, SL("CREATE OR REPLACE TABLE t1 AS SELECT 1")); + check_stmt_rc(rc, stmt); + FAIL_IF(mysql_info(mysql) == NULL, "mysql_info: expected != NULL"); + + mysql_stmt_close(stmt); + + rc= mysql_query(mysql, "DROP TABLE t1"); + check_mysql_rc(rc, mysql); + + return OK; +} + struct my_tests_st my_tests[] = { + {"test_conc163", test_conc163, TEST_CONNECTION_DEFAULT, 0, NULL, NULL}, {"test_conc458", test_conc458, TEST_CONNECTION_NONE, 0, NULL, NULL}, #if !__has_feature(memory_sanitizer) {"test_conc457", test_conc457, TEST_CONNECTION_DEFAULT, 0, NULL, NULL}, From 232e81f02138a3e6ef25fb0aaabd0d4abe364135 Mon Sep 17 00:00:00 2001 From: Georg Richter Date: Wed, 4 Dec 2024 10:13:21 +0100 Subject: [PATCH 3/4] Add test case for CONC-176 --- unittest/libmariadb/ps_bugs.c | 48 +++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/unittest/libmariadb/ps_bugs.c b/unittest/libmariadb/ps_bugs.c index f193e3af..0e3202d7 100644 --- a/unittest/libmariadb/ps_bugs.c +++ b/unittest/libmariadb/ps_bugs.c @@ -5620,7 +5620,55 @@ static int test_conc739(MYSQL *mysql) return OK; } +static int test_conc176(MYSQL *mysql) +{ + MYSQL_STMT *stmt; + MYSQL_BIND bind; + char buffer[9]; + + int rc; + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1"); + check_mysql_rc(rc, mysql); + + rc= mysql_query(mysql, "CREATE TABLE t1 (a int(8) zerofill)"); + check_mysql_rc(rc, mysql); + + rc= mysql_query(mysql, "INSERT INTO t1 VALUES (1)"); + check_mysql_rc(rc, mysql); + + stmt= mysql_stmt_init(mysql); + + rc= mysql_stmt_prepare(stmt, "SELECT a FROM t1", -1); + check_stmt_rc(rc, stmt); + + rc= mysql_stmt_execute(stmt); + + memset(&bind, 0, sizeof(MYSQL_BIND)); + + bind.buffer= buffer; + bind.buffer_type= MYSQL_TYPE_STRING; + bind.buffer_length= 9; + + rc= mysql_stmt_bind_result(stmt, &bind); + check_stmt_rc(rc, stmt); + + rc= mysql_stmt_fetch(stmt); + + diag("Buffer: %s", buffer); + FAIL_IF(strlen(buffer) == 1, "Expected zerofilled string"); + + rc= mysql_stmt_close(stmt); + + rc= mysql_query(mysql, "DROP TABLE t1"); + check_mysql_rc(rc, mysql); + + return OK; +} + + struct my_tests_st my_tests[] = { + {"test_conc176", test_conc176, TEST_CONNECTION_DEFAULT, 0, NULL, NULL}, {"test_conc739", test_conc739, TEST_CONNECTION_DEFAULT, 0, NULL, NULL}, {"test_conc633", test_conc633, TEST_CONNECTION_DEFAULT, 0, NULL, NULL}, {"test_conc627", test_conc627, TEST_CONNECTION_DEFAULT, 0, NULL, NULL}, From af44fc5c5ef55218e55eea0d75cd7b79e79519f4 Mon Sep 17 00:00:00 2001 From: Georg Richter Date: Sun, 8 Dec 2024 11:27:32 +0100 Subject: [PATCH 4/4] CONC-748: Allow to set TLSv1.3 ciphers in GnuTLS - Added TLSv1.3 ciphers to cipher map. - Fixed retrieval of cipher suite: Since gnutls_cipher_suite_get_name supports only TLSv1.2 (and lower) cipher suites, we have to call gnutls_ciphersuite_get() (requires GnuTLS 3.7.4 or newer). --- libmariadb/secure/gnutls.c | 59 +++++++++++++++++++++++++++++--- unittest/libmariadb/connection.c | 35 +++++++++++++++++++ 2 files changed, 90 insertions(+), 4 deletions(-) diff --git a/libmariadb/secure/gnutls.c b/libmariadb/secure/gnutls.c index 46650918..a7759497 100644 --- a/libmariadb/secure/gnutls.c +++ b/libmariadb/secure/gnutls.c @@ -723,6 +723,26 @@ const struct st_cipher_map tls_ciphers[]= "TLS_DH_anon_WITH_AES_256_GCM_SHA384", NULL, "TLS_DH_ANON_AES_256_GCM_SHA384"}, + { {0x13, 0x01}, + "TLS_AES_128_GCM_SHA256", + "TLS_AES_128_GCM_SHA256", + "TLS_AES_128_GCM_SHA256"}, + { {0x13, 0x02}, + "TLS_AES_256_GCM_SHA384", + "TLS_AES_256_GCM_SHA384", + "TLS_AES_256_GCM_SHA384"}, + { {0x13, 0x03}, + "TLS_CHACHA20_POLY1305_SHA256", + "TLS_CHACHA20_POLY1305_SHA256", + "TLS_CHACHA20_POLY1305_SHA256"}, + { {0x13, 0x04}, + "TLS_AES_128_CCM_SHA256", + "TLS_AES_128_CCM_SHA256", + "TLS_AES_128_CCM_SHA256"}, + { {0x13, 0x05}, + "TLS_AES_128_CCM_8_SHA256", + "TLS_AES_128_CCM_8_SHA256", + "TLS_AES_128_CCM_8_SHA256"}, { {0xC0, 0x84}, "TLS_DH_anon_WITH_CAMELLIA_128_GCM_SHA256", NULL, @@ -793,6 +813,7 @@ const struct st_cipher_map tls_ciphers[]= NULL} }; +#if GNUTLS_VERSION_NUMBER < 0x030704 /* map the gnutls cipher suite (defined by key exchange algorithm, cipher and mac algorithm) to the corresponding OpenSSL cipher name */ static const char *openssl_cipher_name(gnutls_kx_algorithm_t kx, @@ -829,6 +850,7 @@ static const char *openssl_cipher_name(gnutls_kx_algorithm_t kx, } return NULL; } +#endif /* get priority string for a given openssl cipher name */ static char *get_priority(const char *cipher_name, char *priority, size_t len) @@ -857,10 +879,20 @@ static char *get_priority(const char *cipher_name, char *priority, size_t len) { if (!strcmp(name, tls_ciphers[i].gnutls_name)) { - snprintf(priority, len - 1, ":+%s:+%s:+%s", - gnutls_cipher_get_name(cipher), - gnutls_mac_get_name(mac), - gnutls_kx_get_name(kx)); + const char *p; + + if ((p= gnutls_cipher_get_name(cipher))) + snprintf(priority, len - 1, ":+%s",p); + if ((p= gnutls_mac_get_name(mac))) + { + strncat(priority, ":+", len - 1); + strncat(priority, p, len - 1); + } + if ((p= gnutls_kx_get_name(kx))) + { + strncat(priority, ":+", len - 1); + strncat(priority, p, len - 1); + } return priority; } } @@ -1329,6 +1361,7 @@ int ma_tls_verify_server_cert(MARIADB_TLS *ctls __attribute__((unused))) const char *ma_tls_get_cipher(MARIADB_TLS *ctls) { +#if GNUTLS_VERSION_NUMBER < 0x030704 gnutls_kx_algorithm_t kx; gnutls_cipher_algorithm_t cipher; gnutls_mac_algorithm_t mac; @@ -1340,6 +1373,24 @@ const char *ma_tls_get_cipher(MARIADB_TLS *ctls) cipher= gnutls_cipher_get((gnutls_session_t)ctls->ssl); kx= gnutls_kx_get((gnutls_session_t)ctls->ssl); return openssl_cipher_name(kx, cipher, mac); +#else + const char *cs= gnutls_ciphersuite_get((gnutls_session_t)ctls->ssl); + int i=0; + + while (tls_ciphers[i].iana_name) + { + if (!strcmp(tls_ciphers[i].gnutls_name, cs)) + { + if (tls_ciphers[i].openssl_name) + return tls_ciphers[i].openssl_name; + if (tls_ciphers[i].gnutls_name) + return tls_ciphers[i].gnutls_name; + return tls_ciphers[i].iana_name; + } + i++; + } + return NULL; +#endif } static int my_verify_callback(gnutls_session_t ssl) diff --git a/unittest/libmariadb/connection.c b/unittest/libmariadb/connection.c index 9fa3212b..5574557c 100644 --- a/unittest/libmariadb/connection.c +++ b/unittest/libmariadb/connection.c @@ -1966,7 +1966,42 @@ static int test_conc632(MYSQL *my __attribute__((unused))) return OK; } +#if defined(HAVE_GNUTLS) || defined(HAVE_OPENSSL) +static int test_conc748(MYSQL *my __attribute__((unused))) +{ + MYSQL *mysql; + int i; + const char *ciphers[3]= {"TLS_AES_128_GCM_SHA256", "TLS_AES_256_GCM_SHA384", "TLS_CHACHA20_POLY1305_SHA256"}; + + for (i=0; i < 3; i++) + { + const char *tls_version; + mysql= mysql_init(NULL); + + mysql_ssl_set(mysql, NULL, NULL, NULL, NULL, NULL); + mysql_optionsv(mysql, MYSQL_OPT_SSL_CIPHER, ciphers[i]); + + if (!my_test_connect(mysql, hostname, NULL, + NULL, schema, port, socketname, 0)) + { + diag("error: %s", mysql_error(mysql)); + return FAIL; + } + + FAIL_IF(strcmp(ciphers[i], mysql_get_ssl_cipher(mysql)), "Cipher mismatch"); + mariadb_get_infov(mysql, MARIADB_CONNECTION_TLS_VERSION, &tls_version); + FAIL_IF(strcmp(tls_version, "TLSv1.3"), "TLS version mismatch"); + + mysql_close(mysql); + } + return OK; +} +#endif + struct my_tests_st my_tests[] = { +#if defined(HAVE_GNUTLS) || defined(HAVE_OPENSSL) + {"test_conc748", test_conc748, TEST_CONNECTION_NONE, 0, NULL, NULL}, +#endif {"test_conc632", test_conc632, TEST_CONNECTION_NONE, 0, NULL, NULL}, {"test_conc490", test_conc490, TEST_CONNECTION_NONE, 0, NULL, NULL}, {"test_gtid", test_gtid, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},