Fixes slow SSL handshakes in network-restricted environments. On Windows,
the verification process uses the CertGetCertificateChain API, which
may attempt to refresh the CA list or fetch CRLs/OCSP data from the
network. This can trigger slow network lookups when no CA or CRL is
explicitly specified.
This patch disables these unnecessary network calls by using flags
like CERT_CHAIN_CACHE_ONLY_URL_RETRIEVAL to prevent external requests
during certificate chain validation. Additionally, it applies
Microsoft-recommended optimizations to speed up certificate handling
and avoid delays in SSL handshakes.
Also, unless explicitly requested(via ca_cert or crl_file or similar),
do not bother to verify name, CA or CRL for local connections. It saves
time. The failures in verification were previously discarded anyway.
* 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
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.
- 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.
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
* 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
Since TLS errors might happen not only when connecting and SSL protocol
is not longer used, errormessage for CR_SSL_CONNECTION_ERROR was replaced
by TLS/SSL error.
Apparently, it complains about wild pointer freed in when using
ASAN_OPTIONS= windows_hook_rtl_allocators=true
while it seems like a false positive, take it as a good opportunity to
remove allocators from Win3.1 times, and replace with simple malloc/free
Implement proper verification for server certificate chain,
with refactoring of the certificate stuff.
If custom CA and CRL certs are given, load them into in-memory store, and
use CertVerifyCertificateChainPolicy() to verify the certificate chain.
There are minor errors fixed, such as
- now there is a support for private keys encoded as BEGIN/END PRIVATE KEY
in PEM, instead of only BEGIN/END RSA PRIVATE KEY
- memory leak around CryptAcquireContext() is fixed i.e when client loads
private key, it previously did never released it, not even when connection
ended.
The handling of certificates moved into schannel_certs.c from various places
Print error symbol (e.g S"EC_E_ILLEGAL_MESSAGE") in the error message
for some schannel errors, in addition to error message
Print error code for all errors coming from schannel.
Fix some whitespace.
SSL handshake
Bug:
The SECBUFFER_EXTRA returned by Schannel was incorrectly handled,
and unprocessed bytes were overriden by the new pvio read,
instead of being passed to InitializeSecurityContext().
Side note:
The code for ma_schannel_handshake_loop() was "inspired" (copied from)
http://www.coastrd.com/c-schannel-smtp did not have the bug,
it was introduced somehow by own modifications.
At irregular intervals older windows versions (prior Windows 10) fail to establish a secure (TLS)
connection and return errors SEC_E_INVALID_TOKEN, SEC_E_BUFFER_TOO_SMALL or SEC_E_MESSAGE_ALTERED.
This is a bug in windows schannel library and was only fixed in recent versions, also OpenSSL provided
a workaround (see https://github.com/openssl/openssl/pull/1350).
Since we are unable to fix this, we introduced a workaround for this problem. In case of an error
during TLS handshake we check the errorcode and try to reconnect up to three times if the error code
was SEC_E_INVALID_TOKEN, SEC_E_BUFFER_TOO_SMALL or SEC_E_MESSAGE_ALTERED.
Added support for pem files which contain certificate and private key.
In case the file will contain more than one certificate or key, the first
certificate or key found will be used.
- STDCALL is ignored for variable argument functions.
- __attribute__ does work for Clang (also if that pretends to be MSVC)
- remove unused function
- simplify ma_getopt, fixes some strange compile error in clang (about
SSE intrinsics)
- fix some clang warnings
Client part of MDEV-14101: Add support for tls-version, via
mysql_options(mysql, MARIADB_OPT_TLS_VERSION, value)
Accepted values are "TLSv1.1", "TLSv1.2" and "TLSv1.3".
Fixed testcase openssl_1 for schannel
The connection pointer mysql is now no longer part (and doesn't need to be updated) of schannel security context, since it can be obtained directly from tls container.
To obtain the correct cipher suite name, we use the (undocumented) flag
SECPKG_ATTR_CIPHER_INFO, which delivers cipher suite id and IANA cipher suite name.
Added more cipher suites and mappings between IANA and OpenSSL cipher suite names
between the calls.
State can be unread buffer from DecryptMessage (SECBUFFER_EXTRA)
or decrypted data that did not fit into callers buffer
- Fix error handling - SEC_I_RENEGOTIATE is handled as error,
we're not doing it yet. Stop reading at SEC_I_CONTEXT_EXPIRED.
- Fix buffer sizes pased to SSPI ( so that large buffers can be read or written
"SELECT REPEAT('a', 20000)"
- Fix unchecked memcpy into the output buffer (size of the output buffer
was not checked, so it is a potential memory overrun)
- remove global variables
- remove in memory certificate stores that cache all CRL and all CA
- verify certificate against ssl_ca and ssl_crl specified in
connection options (not against all CRL/CA in store)
In case handshake ended with Errorcode SEC_E_INTERNAL_ERROR we check
LastErrorCode (if it was set) and return system errormessage. For
timeout during SSL handshake we return the following error message:
ERROR 2026 (HY000): SSL connection error: A connection attempt failed
because the connected party did not properly respond after a period of time, or
established connection failed because connected host has failed to respond.
- Do not acquire a named context, because this might run
into permissions problem.
- Avoid sending TLS1.2 version by default. Yassl wrongfully rejects it
with a bad handshake (it should consider that 1.1 and 1.0 are supported too
but it does not)
changed type of length parameter in mysql_stmt_prepare,
mysql_real_query, mysql_stmt_send_long_data (incl. async _start
functions) from unsigned long to size_t.
Fixed warnings