1
0
mirror of https://github.com/mariadb-corporation/mariadb-connector-c.git synced 2025-08-08 14:02:17 +03:00
commit ffbdaaac2b was incomplete, changes from ma_pvio.c
were missing. Beside this fix, this commit also contains necessary changes for GnuTLS.
This commit is contained in:
Georg Richter
2020-01-22 11:08:18 +01:00
parent a1283d0b10
commit 8e9c311610
4 changed files with 68 additions and 75 deletions

View File

@@ -540,8 +540,7 @@ my_bool ma_pvio_start_ssl(MARIADB_PVIO *pvio)
2. verify CN (requires option ssl_verify_check)
3. verrify finger print
*/
if ((pvio->mysql->options.ssl_ca || pvio->mysql->options.ssl_capath) &&
(pvio->mysql->client_flag & CLIENT_SSL_VERIFY_SERVER_CERT) &&
if ((pvio->mysql->client_flag & CLIENT_SSL_VERIFY_SERVER_CERT) &&
ma_pvio_tls_verify_server_cert(pvio->ctls))
return 1;

View File

@@ -1080,6 +1080,23 @@ static int ma_tls_set_certs(MYSQL *mysql,
if (ssl_error < 0)
goto error;
}
if (mysql->options.ssl_capath)
{
ssl_error= gnutls_certificate_set_x509_trust_dir(ctx,
mysql->options.ssl_capath,
GNUTLS_X509_FMT_PEM);
if (ssl_error < 0)
goto error;
}
if (!mysql->options.ssl_ca && !mysql->options.ssl_capath)
{
ssl_error= gnutls_certificate_set_x509_system_trust(ctx);
if (ssl_error < 0)
goto error;
}
gnutls_certificate_set_verify_function(ctx,
my_verify_callback);
@@ -1211,7 +1228,11 @@ my_bool ma_tls_connect(MARIADB_TLS *ctls)
if (ret < 0)
{
ma_tls_set_error(mysql, ssl, ret);
/* If error message was not set while calling certification callback function,
use default error message (which is not very descriptive */
if (!mysql_errno(mysql))
ma_tls_set_error(mysql, ssl, ret);
/* restore blocking mode */
gnutls_deinit((gnutls_session_t )ctls->ssl);
free_gnutls_data(data);
@@ -1330,7 +1351,7 @@ my_bool ma_tls_close(MARIADB_TLS *ctls)
int ma_tls_verify_server_cert(MARIADB_TLS *ctls __attribute__((unused)))
{
/* server verification is already handled before */
/* server verification is already handled before during handshake */
return 0;
}
@@ -1352,77 +1373,44 @@ const char *ma_tls_get_cipher(MARIADB_TLS *ctls)
static int my_verify_callback(gnutls_session_t ssl)
{
unsigned int status= 0;
const gnutls_datum_t *cert_list;
unsigned int cert_list_size;
struct st_gnutls_data *data= (struct st_gnutls_data *)gnutls_session_get_ptr(ssl);
MYSQL *mysql;
MARIADB_PVIO *pvio;
gnutls_x509_crt_t cert;
const char *hostname;
mysql= data->mysql;
pvio= mysql->net.pvio;
/* read hostname */
hostname = mysql->host;
/* This verification function uses the trusted CAs in the credentials
* structure. So you must have installed one or more CA certificates.
*/
if ((mysql->client_flag & CLIENT_SSL_VERIFY_SERVER_CERT) &&
gnutls_certificate_verify_peers2 (ssl, &status) < 0)
{
pvio->set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, "CA verification failed");
return GNUTLS_E_CERTIFICATE_ERROR;
}
if (status & GNUTLS_CERT_INVALID)
{
char errbuf[100];
snprintf(errbuf, 99, "CA Verification failed (Status: %d)", status);
pvio->set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, errbuf);
return GNUTLS_E_CERTIFICATE_ERROR;
}
/* Up to here the process is the same for X.509 certificates and
* OpenPGP keys. From now on X.509 certificates are assumed. This can
* be easily extended to work with openpgp keys as well.
*/
if (gnutls_certificate_type_get (ssl) != GNUTLS_CRT_X509)
{
pvio->set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, "Expected X509 certificate");
return GNUTLS_E_CERTIFICATE_ERROR;
}
if (gnutls_x509_crt_init (&cert) < 0)
{
pvio->set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, "Error during certificate initialization");
return GNUTLS_E_CERTIFICATE_ERROR;
}
cert_list = gnutls_certificate_get_peers (ssl, &cert_list_size);
if (cert_list == NULL)
{
gnutls_x509_crt_deinit (cert);
pvio->set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, "No certificate found");
return GNUTLS_E_CERTIFICATE_ERROR;
}
if (gnutls_x509_crt_import (cert, &cert_list[0], GNUTLS_X509_FMT_DER) < 0)
{
gnutls_x509_crt_deinit (cert);
pvio->set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, "Unknown SSL error");
return GNUTLS_E_CERTIFICATE_ERROR;
}
if ((mysql->client_flag & CLIENT_SSL_VERIFY_SERVER_CERT) &&
!gnutls_x509_crt_check_hostname (cert, hostname))
{
gnutls_x509_crt_deinit (cert);
pvio->set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, "Hostname in certificate doesn't match");
return GNUTLS_E_CERTIFICATE_ERROR;
}
gnutls_x509_crt_deinit (cert);
/* notify gnutls to continue handshake normally */
CLEAR_CLIENT_ERROR(mysql);
if ((mysql->client_flag & CLIENT_SSL_VERIFY_SERVER_CERT))
{
const char *hostname= mysql->host;
if (gnutls_certificate_verify_peers3 (ssl, hostname, &status) < 0)
return GNUTLS_E_CERTIFICATE_ERROR;
} else {
if (gnutls_certificate_verify_peers2 (ssl, &status) < 0)
return GNUTLS_E_CERTIFICATE_ERROR;
}
if (status & GNUTLS_CERT_INVALID)
{
gnutls_datum_t out;
int type;
/* accept self signed certificates if we don't have to verify server cert */
if (!(mysql->client_flag & CLIENT_SSL_VERIFY_SERVER_CERT) &&
(status & GNUTLS_CERT_SIGNER_NOT_FOUND))
return 0;
/* gnutls default error mesage "certificate validation failed" isn't very
descriptive, so we provide more information about the error here */
type= gnutls_certificate_type_get(ssl);
gnutls_certificate_verification_status_print(status, type, &out, 0);
my_set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN,
ER(CR_SSL_CONNECTION_ERROR), out.data);
gnutls_free(out.data);
return GNUTLS_E_CERTIFICATE_ERROR;
}
return 0;
}

View File

@@ -530,9 +530,7 @@ static int ma_tls_set_certs(MYSQL *mysql, SSL *ssl)
X509_STORE_set_flags(certstore, X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL);
}
}
SSL_CTX_set_verify(ctx, (mysql->options.ssl_ca || mysql->options.ssl_capath) ||
(mysql->client_flag & CLIENT_SSL_VERIFY_SERVER_CERT) ?
SSL_VERIFY_PEER : SSL_VERIFY_NONE, NULL);
SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL);
return 0;
error:
@@ -648,7 +646,8 @@ my_bool ma_tls_connect(MARIADB_TLS *ctls)
pvio->methods->blocking(pvio, FALSE, 0);
return 1;
}
if ((mysql->client_flag & CLIENT_SSL_VERIFY_SERVER_CERT))
if ((mysql->client_flag & CLIENT_SSL_VERIFY_SERVER_CERT) ||
(mysql->options.ssl_ca || mysql->options.ssl_capath))
{
rc= SSL_get_verify_result(ssl);
if (rc != X509_V_OK)

View File

@@ -1329,7 +1329,7 @@ static int test_conc386(MYSQL *mysql)
return OK;
}
#ifdef HAVE_OPENSSL
#ifndef HAVE_SCHANNEL
static int test_ssl_verify(MYSQL *my __attribute__((unused)))
{
MYSQL *mysql;
@@ -1355,13 +1355,20 @@ static int test_ssl_verify(MYSQL *my __attribute__((unused)))
port, socketname, 0), mysql_error(mysql));
mysql_close(mysql);
mysql= mysql_init(NULL);
mysql_options(mysql, MYSQL_OPT_SSL_ENFORCE, &enforce);
FAIL_IF(!mysql_real_connect(mysql, hostname, username, password, schema,
port, socketname, 0), mysql_error(mysql));
diag("cipher: %s", mysql_get_ssl_cipher(mysql));
mysql_close(mysql);
return OK;
}
#endif
struct my_tests_st my_tests[] = {
{"test_ssl", test_ssl, TEST_CONNECTION_NEW, 0, NULL, NULL},
#ifdef HAVE_OPENSSL
#ifndef HAVE_SCHANNEL
{"test_ssl_verify", test_ssl_verify, TEST_CONNECTION_NEW, 0, NULL, NULL},
#endif
{"test_mdev14101", test_mdev14101, TEST_CONNECTION_NEW, 0, NULL, NULL},