[MDEV-23772] Automate SSL connection tests for MariaDB Created: 2020-09-21  Updated: 2021-05-09  Resolved: 2021-05-09

Status: Closed
Project: MariaDB Server
Component/s: Platform Debian
Fix Version/s: 10.5.8

Type: Task Priority: Major
Reporter: Otto Kekäläinen Assignee: Otto Kekäläinen
Resolution: Fixed Votes: 0
Labels: None

Issue Links:
Relates
relates to MDEV-19268 TLS Setup Documentation Open

 Description   

There are various bugs open about TLS connection issues in Debian and Ubuntu:

https://bugs.launchpad.net/ubuntu/+source/mariadb-10.3/+bug/1885632

  • MariaDB 10.3 as provided by Ubuntu.org is compiled against YaSSL version 2.4.4, which supports a maximum TLS version of 1.1. The Ubuntu 20.04 release has a minimum TLS 1.2 requirement, rendering all MariaDB TLS connections unusable.

https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=921151

  • appears that the Debian client is only attempting to negotiate a connection with TLSv1.1, which is blacklisted

https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=927289

  • Apparently YaSSL (now WolfSSL) did not support any other certificate format than PEM, and the error message is uninformative

https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=956401

  • Option --ssl-verify-server-cert did not work. Possibly because of MDEV-12190: YaSSL's highest supported version is TLSv1.1 (=3.2) - if the client requests a higher version, it needs to be downgraded in Server Hello packet to TLSv1.1 instead of interrupting the handshake and closing the connection.

https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=956810

  • libmariadb3 compiled libdbd-mysql failed to connect to MySQL server that required TLS

https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=875457

  • clients could not connect using ssl (the error message was: ERROR 2026 (HY000): SSL connection error: protocol version mismatch)

The biggest problem right now is that we don't know the status of these issues.

We should extend the debian/salsa-ci.yml to do a simple TLS scenario and test the connection so we know if it even works in the most basic case.



 Comments   
Comment by Faustin Lammler [ 2020-09-22 ]

Hi otto!
Please find below the scenario to test TLS in the CI. I could eventually try to add it to gitlab-ci but I believe you will be faster than me in this task. Note that I am not testing different versions of TLS so this could be improved too. Regarding the documentation, I have found some error so I will update MDEV-19268 this afternoon

Tested with:

  • debian mariadb 10.1 (commented);
  • mdbf mariadb 10.5.

# create container
docker run --name tls-test --privileged -d -v /sys/fs/cgroup:/sys/fs/cgroup:ro fauust/docker-systemd:debian-10
 
# install mariadb (debian)
# docker exec -it tls-test bash -c "apt update && apt install -y mariadb-server"
 
# install mariadb (mdbf)
docker exec -it tls-test bash -c "apt update && apt install -y curl && \
  curl -sS https://downloads.mariadb.com/MariaDB/mariadb_repo_setup -o mariadb_repo_setup && bash mariadb_repo_setup --skip-maxscale --skip-tools && \
  apt update && apt install -y mariadb-server"
 
# setup server certs
docker exec -it tls-test bash -c "apt update && \
  apt install -y openssl && \
  systemctl start mariadb && \
  mkdir /etc/mysql/certs && cd /etc/mysql/certs && \
  openssl genrsa 2048 > ca-key.pem && \
  openssl req -new -x509 -nodes -days 365000 -key ca-key.pem -out ca.pem -subj \"/C=IT/ST=Venice/L=Venice/O=CI/OU=CI/CN=CA mariadb.org\" && \
  openssl req -newkey rsa:2048 -days 365000 -nodes -keyout server-key.pem -out server-req.pem -subj \"/C=IT/ST=Venice/L=Venice/O=CI/OU=CI/CN=mariadb.org\" && \
  openssl rsa -in server-key.pem -out server-key.pem && \
  openssl x509 -req -in server-req.pem -days 365000 -CA ca.pem -CAkey ca-key.pem -set_serial 01 -out server-cert.pem && \
  openssl verify -CAfile ca.pem server-cert.pem && \
  chown -Rv mysql:root /etc/mysql/certs && \
  echo -e \"[mariadb]\nssl_cert = /etc/mysql/certs/server-cert.pem\nssl_key = /etc/mysql/certs/server-key.pem\nssl_ca = /etc/mysql/certs/ca.pem\nssl = on\n\">> /etc/mysql/mariadb.cnf && \
  systemctl restart mariadb"
 
# verify server has ssl enabled
docker exec -it tls-test bash -c "mariadb -Bse 'SHOW VARIABLES' | grep have_ssl"
 
# setup client certs
docker exec -it tls-test bash -c "cd /etc/mysql/certs
  openssl req -newkey rsa:2048 -days 365000 -nodes -keyout client-key.pem -out client-req.pem -subj \"/C=IT/ST=Venice/L=Venice/O=CI/OU=CI/CN=mariadb.org\" && \
  openssl rsa -in client-key.pem -out client-key.pem && \
  openssl x509 -req -in client-req.pem -days 365000 -CA ca.pem -CAkey ca-key.pem -set_serial 01 -out client-cert.pem && \
  openssl verify -CAfile ca.pem client-cert.pem"
 
# verify client TLS connexion
docker exec -it tls-test bash -c "cd /etc/mysql/certs && \
  mariadb --ssl-cert=client-cert.pem --ssl-key=client-key.pem --ssl-ca=ca.pem -Bse 'SHOW SESSION STATUS' | grep -w Ssl_cipher"

Comment by Otto Kekäläinen [ 2020-09-22 ]

As a side note, did you notice we have in `mysql-test/std_data/` already existing test certs the MTR uses? And inside the MTR there are already some existing test cases for testing TLS, maybe some of those can be recycled?

Comment by Faustin Lammler [ 2020-09-22 ]

No I didn't! So have I just reinvented the wheel?
I will take a look in the next days, the tests I am using are coming from the KB documentation:
https://mariadb.com/kb/en/securing-connections-for-client-and-server/

Comment by Faustin Lammler [ 2020-09-22 ]

Also FYI regarding the `ssl-verify-server-cert` option it needs a correct CN (should be hostname) of the client/server in the process of certificate generation.
But I was not able to use it so far see MDEV-20123.

But this option is now disabled by default so I don't know if it should be part of the CI test.

Comment by Otto Kekäläinen [ 2020-09-22 ]

Thanks for the research. With the help of this I was able to quickly verify that our documentation and the template configs in /etc/mysql/mariadb.conf.d are aligned.

I was also able to confirm that if server requires TLSv1.3, the client will fail to connect:

# mariadb
ERROR 2026 (HY000): SSL connection error: A packet with illegal or unsupported version was received.

If the client requires the certificate the be verified it will fail with (maybe because the cert is self-signed?):

# mariadb
ERROR 2026 (HY000): SSL connection error: The certificate is NOT trusted. The certificate issuer is unknown.

MariaDB [(none)]> status
--------------
mariadb  Ver 15.1 Distrib 10.5.5-MariaDB, for debian-linux-gnu (x86_64) using readline 5.2
 
Connection id:		70
Current database:	
Current user:		root@localhost
SSL:			Cipher in use is DHE-RSA-AES256-SHA
Current pager:		stdout
Using outfile:		''
Using delimiter:	;
Server:			MariaDB
Server version:		10.5.5-MariaDB-1 Debian 10
Protocol version:	10
Connection:		Localhost via UNIX socket
Server characterset:	utf8mb4
Db     characterset:	utf8mb4
Client characterset:	latin1
Conn.  characterset:	latin1
 
# mariadb -Bse 'SHOW VARIABLES' | grep ssl
have_openssl	NO
have_ssl	YES
ssl_ca	/etc/mysql/cacert.pem
ssl_capath	
ssl_cert	/etc/mysql/server-cert.pem
ssl_cipher	
ssl_crl	
ssl_crlpath	
ssl_key	/etc/mysql/server-key.pem
version_ssl_library	WolfSSL 4.4.0
 
# mariadb -Bse 'SHOW VARIABLES' | grep tls
tls_version	TLSv1.1,TLSv1.2,TLSv1.3
 
# mariadb -Bse 'SHOW SESSION STATUS' | grep -i ssl
Com_show_processlist	0
Ssl_accept_renegotiates	0
Ssl_accepts	3
Ssl_callback_cache_hits	0
Ssl_cipher	DHE-RSA-AES256-SHA
Ssl_cipher_list	DHE-RSA-AES256-SHA
Ssl_client_connects	0
Ssl_connect_renegotiates	0
Ssl_ctx_verify_depth	9
Ssl_ctx_verify_mode	1
Ssl_default_timeout	500
Ssl_finished_accepts	3
Ssl_finished_connects	0
Ssl_server_not_after	Jan 22 10:11:10 2039 GMT
Ssl_server_not_before	Jan 27 10:11:10 2019 GMT
Ssl_session_cache_hits	0
Ssl_session_cache_misses	0
Ssl_session_cache_mode	OFF
Ssl_session_cache_overflows	0
Ssl_session_cache_size	33
Ssl_session_cache_timeouts	0
Ssl_sessions_reused	0
Ssl_used_session_cache_entries	0
Ssl_verify_depth	9
Ssl_verify_mode	0
Ssl_version	TLSv1.2
 
# dpkg -l | grep ssl
ii  libgnutls-openssl27:amd64              3.6.15-4                       amd64        GNU TLS library - OpenSSL wrapper
ii  libssl1.1:amd64                        1.1.1g-1                       amd64        Secure Sockets Layer toolkit - shared libraries
ii  libzstd1:amd64                         1.4.5+dfsg-3                   amd64        fast lossless compression algorithm
ii  openssl                                1.1.1g-1                       amd64        Secure Sockets Layer toolkit - cryptographic utility
# dpkg -l | grep tls
ii  libgnutls-dane0:amd64                  3.6.15-4                       amd64        GNU TLS library - DANE security support
ii  libgnutls-openssl27:amd64              3.6.15-4                       amd64        GNU TLS library - OpenSSL wrapper
ii  libgnutls28-dev:amd64                  3.6.15-4                       amd64        GNU TLS library - development files
ii  libgnutls30:amd64                      3.6.15-4                       amd64        GNU TLS library - main runtime library
ii  libgnutlsxx28:amd64                    3.6.15-4                       amd64        GNU TLS library - C++ runtime library

The problem is GnuTLS+MariaDB Connector C that does not support TLSv1.3. GnuTLS should support it since 2018: https://lists.gnupg.org/pipermail/gnutls-help/2018-December/004465.html

WolfSSL has supported TLS v1.3 since 3.15 (now in 4.4.0 in Debian): https://www.wolfssl.com/docs/tls13/

According to https://mariadb.com/kb/en/secure-connections-overview/#tls-protocol-version-support all versions should be supported by server+wolfssl and client+gnutls but results above don't support this..

Comment by Faustin Lammler [ 2020-09-23 ]

> If the client requires the certificate the be verified it will fail with (maybe because the cert is self-signed?)

I believe that as long as you provide the CA (ca.pem) to the client, the verification should work (even if it's a self signed cert).
So something is not working with that option IMO...

Comment by Otto Kekäläinen [ 2020-09-23 ]

Based on your commands above, I created this snipped. Tested for mariadb.org 10.5.5, and there TLS 1.3 for both server and client works, so the TLS 1.3 not working in Debian is a Debian-specific issue. Probably due to building with -DSSL=bundled

dpkg -l | grep -i -e tls -e ssl
export CERT_PATH=/usr/share/mysql/mysql-test/std_data
openssl verify -CAfile $CERT_PATH/cacert.pem $CERT_PATH/server-cert.pem
openssl x509 -subject -issuer -noout -in $CERT_PATH/cacert.pem $CERT_PATH/server-cert.pem
cat <<EOF > /etc/mysql/mariadb.conf.d/tls.cnf
[client-server]
ssl = on
ssl-ca = $CERT_PATH/cacert.pem
ssl-cert = $CERT_PATH/server-cert.pem
ssl-key = $CERT_PATH/server-key.pem
[server]
require-secure-transport = on
[client]
ssl-verify-server-cert = on
EOF
# Create user for TCP connection, must have password
maraidb -e "SET PASSWORD FOR 'mysql'@'localhost' = PASSWORD('asdf234');"
cat <<<EOF > /root/.my.cnf
[client]
user=mysql
password=asdf234
protocol=tcp
EOF
service mariadb restart
mariadb -Bse 'STATUS' | tee result
# Ensure important values present, otherwise fail job
grep --quiet "localhost via TCP/IP" result
mariadb -Bse 'SHOW VARIABLES' | grep -e tls -e ssl | tee result
grep --quiet "have_ssl	YES" result
grep --quiet TLSv1.3 result
mariadb -Bse 'SHOW SESSION STATUS' | grep -i -e tls -e ssl | tee result
grep --quiet TLSv1.3 result

root@913962e47af2:/etc/mysql/mariadb.conf.d# mariadb -Bse 'STATUS'
--------------
mariadb  Ver 15.1 Distrib 10.5.6-MariaDB, for debian-linux-gnu (x86_64) using readline 5.2
 
Connection id:		25
Current database:	
Current user:		root@localhost
SSL:			Cipher in use is TLS_AES_256_GCM_SHA384
Current pager:		stdout
Using outfile:		''
Using delimiter:	;
Server:			MariaDB
Server version:		10.5.6-MariaDB-1:10.5.0 mariadb.org binary distribution
Protocol version:	10
Connection:		Localhost via UNIX socket
Server characterset:	utf8mb4
Db     characterset:	utf8mb4
Client characterset:	latin1
Conn.  characterset:	latin1
UNIX socket:		/run/mysqld/mysqld.sock
Uptime:			2 sec
 
Threads: 22  Questions: 161  Slow queries: 0  Opens: 23  Open tables: 17  Queries per second avg: 80.500
--------------
 
root@913962e47af2:/etc/mysql/mariadb.conf.d# mariadb -Bse 'SHOW VARIABLES' | grep -e tls -e ssl
have_openssl	YES
have_ssl	YES
ssl_ca	/usr/share/mysql/mysql-test/std_data/cacert.pem
ssl_capath	
ssl_cert	/usr/share/mysql/mysql-test/std_data/server-cert.pem
ssl_cipher	
ssl_crl	
ssl_crlpath	
ssl_key	/usr/share/mysql/mysql-test/std_data/server-key.pem
tls_version	TLSv1.1,TLSv1.2,TLSv1.3
version_ssl_library	OpenSSL 1.1.1g  21 Apr 2020
root@913962e47af2:/etc/mysql/mariadb.conf.d# mariadb -Bse 'SHOW SESSION STATUS' | grep -i -e tls -e ssl
Com_show_processlist	0
Ssl_accept_renegotiates	0
Ssl_accepts	4
Ssl_callback_cache_hits	0
Ssl_cipher	TLS_AES_256_GCM_SHA384
Ssl_cipher_list	TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:DHE-RSA-AES256-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES256-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES128-SHA:RSA-PSK-AES256-GCM-SHA384:DHE-PSK-AES256-GCM-SHA384:RSA-PSK-CHACHA20-POLY1305:DHE-PSK-CHACHA20-POLY1305:ECDHE-PSK-CHACHA20-POLY1305:AES256-GCM-SHA384:PSK-AES256-GCM-SHA384:PSK-CHACHA20-POLY1305:RSA-PSK-AES128-GCM-SHA256:DHE-PSK-AES128-GCM-SHA256:AES128-GCM-SHA256:PSK-AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:ECDHE-PSK-AES256-CBC-SHA384:ECDHE-PSK-AES256-CBC-SHA:SRP-RSA-AES-256-CBC-SHA:SRP-AES-256-CBC-SHA:RSA-PSK-AES256-CBC-SHA384:DHE-PSK-AES256-CBC-SHA384:RSA-PSK-AES256-CBC-SHA:DHE-PSK-AES256-CBC-SHA:AES256-SHA:PSK-AES256-CBC-SHA384:PSK-AES256-CBC-SHA:ECDHE-PSK-AES128-CBC-SHA256:ECDHE-PSK-AES128-CBC-SHA:SRP-RSA-AES-128-CBC-SHA:SRP-AES-128-CBC-SHA:RSA-PSK-AES128-CBC-SHA256:DHE-PSK-AES128-CBC-SHA256:RSA-PSK-AES128-CBC-SHA:DHE-PSK-AES128-CBC-SHA:AES128-SHA:PSK-AES128-CBC-SHA256:PSK-AES128-CBC-SHA
Ssl_client_connects	0
Ssl_connect_renegotiates	0
Ssl_ctx_verify_depth	18446744073709551615
Ssl_ctx_verify_mode	5
Ssl_default_timeout	7200
Ssl_finished_accepts	4
Ssl_finished_connects	0
Ssl_server_not_after	Jan 22 10:11:10 2039 GMT
Ssl_server_not_before	Jan 27 10:11:10 2019 GMT
Ssl_session_cache_hits	0
Ssl_session_cache_misses	0
Ssl_session_cache_mode	SERVER
Ssl_session_cache_overflows	0
Ssl_session_cache_size	128
Ssl_session_cache_timeouts	0
Ssl_sessions_reused	0
Ssl_used_session_cache_entries	0
Ssl_verify_depth	18446744073709551615
Ssl_verify_mode	5
Ssl_version	TLSv1.3

Comment by Faustin Lammler [ 2020-09-24 ]

Very nice! Let me know when you have it in salsa ci, I am curious to see where you are going to insert it in the CI chain.
Regarding wolfssl, there maybe interesting progress in https://github.com/wolfSSL/wolfssl/issues/3329

Comment by Otto Kekäläinen [ 2020-09-24 ]

WIP at https://salsa.debian.org/mariadb-team/mariadb-10.5/-/compare/master...salsa-ci%2Ftls-1.3-testing

Comment by Otto Kekäläinen [ 2020-09-28 ]

Implemented downstream on mariadb-10.5 master https://salsa.debian.org/mariadb-team/mariadb-10.5/-/commit/23376b43714be4dbb53782b3ef1fa7b7eff24daf

Comment by Faustin Lammler [ 2020-09-29 ]

Great!

Comment by Otto Kekäläinen [ 2021-05-09 ]

All of the mentioned issues are fixed in Debian in the 10.5 series thanks to using OpenSSL:
https://salsa.debian.org/mariadb-team/mariadb-10.5/-/commit/ca2574aa88434d1c49456c677b7dcb904902daaf

And tested in Salsa-CI since:
https://salsa.debian.org/mariadb-team/mariadb-10.5/-/commit/23376b43714be4dbb53782b3ef1fa7b7eff24daf

And upstreamed in:
https://github.com/MariaDB/server/commit/ecb1b8721ba645ccb839fc1b7605483b794be4e1

Generated at Thu Feb 08 09:24:56 UTC 2024 using Jira 8.20.16#820016-sha1:9d11dbea5f4be3d4cc21f03a88dd11d8c8687422.