Parsec support for Windows uses bcrypt for deriving key from
hash value (using PBKDF2) and ma_crypto_sign from bundled ed25519
ref10 implementation for signing.
ed25519 ref10 implementation is now built as a separate object
library. Depending on the plugin configuration (dynamic or static)
it will be linked against plugin or against libmariadb.
This commit also fixes CONC-723 (CMake error when disabling
client_ed25519 plugin) and static build of client_ed25519
plugin.
- Fixed parsec plugin declaration (CONC-719)
- When using gnutls crypto, also link against libnettle and
libhogweed to avoid build error due to unresolved externals.
Replica server crashes with an invalid pointer when using a user created
with the PARSEC plugin for replication
realloc can't be done for mysql->passwd. There's also no pretty way to
pass the ext-salt into hash_password, so let's use _Thread_local instead.
* fix comments
* reorder errors to put hard errors on top
* report errors from openssl
* don't overwrite errors in C/C
* pass correct flags to gnutls_x509_crt_check_hostname2()
* use the same define name everywhere consistently
* don't recalculate fingerprint in openssl unnecessary
* misc
Use SCH_CREDENTIAL structure, to support TLSv1.3
Allow TLSv1.3 starting with Windows 11 / Server 2022, which are
first Windows releases to officially support latest TLS version
There is no real renegotiation in TLSv1.3 protocol, so it is
some internal schannel thing, that makes DecryptMessage() to return
SEC_I_RENEGOTIATE, to replay a handshake step.
This pops up when TLSv1.3 is enabled.
With normal client, statically linked plugin with be used
The DLL is for the obscure in-server client, which we never got rid off.
That client is used with mariabackup, replication, and some storage engines,
e.g connect and federated.
The bug happens only when connecting with SSL with client certificates.
Apparently if client certificates are used in TLS handshake,
private keys for cert should be loaded into named persistent
container.This is because AcquireCredentialsHandle is done partically
out-of-process in lsass.exe, and lsass wants to read private keys from disk
See discussion in https://github.com/dotnet/runtime/issues/23749
Schannel has legacy behavior for ephemeral keys, not involving lsass,
and this is why it worked for us so far, however there are limitations.
It appears to only use rsa_sha1 for signature verification, and newer
OpenSSL no longer allows SHA1 for it, and this ends up in
"algorithm mismatch" message from schannel.
The above is just my understanding of how it works, because there is no
real documentation, the conclusion is based on discussion in
https://github.com/dotnet/runtime/issues/23749
The fix:
So storing the key in persistent named container evidently fixes it,
and this is what is done in this patch. Care is takes to destroy
key container after key is no longer needed, to
avoid filling %AppData%\Roaming\Microsoft\Crypto\RSA with tiny encrypted
key files. Thus the "persistency window" of the key in container on disk
is only for duration of AcquireCredentialsHandle
- don't verify fingerprint twice
- pci->dwVersion (certificate version) needs to be increased by 1
- use MARIADB_TLS_VERIFY_UNKNOWN for unknown tls verification errors
Peer certificate validation:
Since version 3.4 peer certificate verification is enabled by default.
It can be disabled via `mysql_optionsv`, using option
MYSQL_OPT_SSL_VERIFY_SERVER_CERT:
my_bool verify= 0;
mysql_options(mariadb, MYSQL_OPT_SSL_VERIFY_SERVER_CERT, &verify);
Self signed certificates
If the client obtained a self signed peer certificate from MariaDB server
the verification will fail, with the following exceptions:
* If the connection between client and server is considered to be secure:, e.g.
* a unix_socket is used for client server communication
* hostname is localhost (Windows operating system), 127.0.0.1 or ::1
* a specified fingerprint matches the fingerprint of the peer certificate (see below)
* a client can verify the certificate using account password, it's possible if
* account has a password
* authentication plugin is "secure without TLS", that is, one of
mysql_native_password, ed25519 or parsec.
Fingerprint verification of the peer certificate
A fingerprint is a cryptographic hash (SHA-256, SHA-384 or SHA-512) of the peer
certificate's binary data. Even if the fingerprint matches, an expired or
revoked certificate will not be accepted.
For security reasons support for MD5 and SHA1 has been removed.
Technical details:
==================
- Peer certificate verification call was removed from ma_tls_connect, instead it
will be called directly after the handshake succeeded (my_auth.c)
- mysql->net.tls_self_signed_error was replaced by mysql->net.tls_verify_status which
contains the result of the peer certfificate verification:
The verification status can be obtained with mariadb_get_infov using new parameter
MARIADB_TLS_VERIFY_STATUS.
unsigned int tls_verify_status;
mariadb_get_infov(mysql, MARIADB_TLS_VERIFY_STATUS, &tls_verify_status);
The result is a combination of the following flags:
MARIADB_TLS_VERIFY_OK 0
MARIADB_TLS_VERIFY_TRUST 1
MARIADB_TLS_VERIFY_HOST 2
MARIADB_TLS_VERIFY_PERIOD 4
MARIADB_TLS_VERIFY_FINGERPRINT 8
MARIADB_TLS_VERIFY_REVOKED 16
MARIADB_TLS_VERIFY_UNKNOWN 32
- GnuTLS peer certificate verification callback was removed and replaced by
gnutls_verify_peers2() api function, so the peer certificate validation
will happen after handshake.
- OpenSSL implementation will no longer use SSL_verify_result to check the
validity of the peer certificate. Instead a callback function will be called
during the handshake, which collects all certificate validation errors.
- If the peer certificate is not trusted, hostname verification will be
skipped.
- Testing
Added new test tls, which implements a python based dummy server, which allows
to set different certificates and TLS options. Please note. that tests are
expected to fail, since the server doesn't support further steps like user
authentication etc. after the handshake. Prerequisite for running the tls test
is Python3.
wait_io_or_timeout() accepts milliseconds, while options has seconds,
since this is just plain MYSQL_OPT_READ_TIMEOUT/...
The one that has milliseconds are pvio->timeout[PVIO_*_TIMEOUT], so use
them.
Usually this is not a problem, but, in case of interrupt (i.e. signal -
EINTR) SSL_read() will return SSL_ERROR_WANT_READ/SSL_ERROR_WANT_WRITE,
and then wait_io_or_timeout() will be called, and timeout will be wrong,
may cause a failure.
realloc can't be done for mysql->passwd. There's also no pretty way to
pass the ext-salt into hash_password, so let's use thread_local instead.
For GCC < 4.9 (SLES 12, CentOS 7), which don't support _Thread_local,
pk will be recalculated instead
1) Fix check if end was reached (<= instead of <), so last parameter will
not be ignored in case it is an empty string.
2) Empty strings will be passed as NULL`in _mariadb_set_conf_option.
CHECK_INCLUDE_FILES failed during configuration phase, as applink.c
compiles with "warning C4996: 'fopen' was declared deprecated",
hence warning == error makes compile time check fail.
This happens at least when using OpenSSL 3.2, but not with older versions.
The consequence is that in some cases(e.g using SSL with client
certificates), client would exit with "Applink not found" at runtime.
Fix by defining HAVE_OPENSSL_APPLINK_C, if
${OPENSSL_INCLUDE_DIR}/include/openssl/applink.c merely exists, without
attempting to compile.