You've already forked mariadb-connector-c
mirror of
https://github.com/mariadb-corporation/mariadb-connector-c.git
synced 2025-08-08 14:02:17 +03:00
Follow up of ffbdaaac2b
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:
@@ -540,8 +540,7 @@ my_bool ma_pvio_start_ssl(MARIADB_PVIO *pvio)
|
|||||||
2. verify CN (requires option ssl_verify_check)
|
2. verify CN (requires option ssl_verify_check)
|
||||||
3. verrify finger print
|
3. verrify finger print
|
||||||
*/
|
*/
|
||||||
if ((pvio->mysql->options.ssl_ca || pvio->mysql->options.ssl_capath) &&
|
if ((pvio->mysql->client_flag & CLIENT_SSL_VERIFY_SERVER_CERT) &&
|
||||||
(pvio->mysql->client_flag & CLIENT_SSL_VERIFY_SERVER_CERT) &&
|
|
||||||
ma_pvio_tls_verify_server_cert(pvio->ctls))
|
ma_pvio_tls_verify_server_cert(pvio->ctls))
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
|
@@ -1080,6 +1080,23 @@ static int ma_tls_set_certs(MYSQL *mysql,
|
|||||||
if (ssl_error < 0)
|
if (ssl_error < 0)
|
||||||
goto error;
|
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,
|
gnutls_certificate_set_verify_function(ctx,
|
||||||
my_verify_callback);
|
my_verify_callback);
|
||||||
|
|
||||||
@@ -1211,7 +1228,11 @@ my_bool ma_tls_connect(MARIADB_TLS *ctls)
|
|||||||
|
|
||||||
if (ret < 0)
|
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 */
|
/* restore blocking mode */
|
||||||
gnutls_deinit((gnutls_session_t )ctls->ssl);
|
gnutls_deinit((gnutls_session_t )ctls->ssl);
|
||||||
free_gnutls_data(data);
|
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)))
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1352,77 +1373,44 @@ const char *ma_tls_get_cipher(MARIADB_TLS *ctls)
|
|||||||
static int my_verify_callback(gnutls_session_t ssl)
|
static int my_verify_callback(gnutls_session_t ssl)
|
||||||
{
|
{
|
||||||
unsigned int status= 0;
|
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);
|
struct st_gnutls_data *data= (struct st_gnutls_data *)gnutls_session_get_ptr(ssl);
|
||||||
MYSQL *mysql;
|
MYSQL *mysql;
|
||||||
MARIADB_PVIO *pvio;
|
|
||||||
|
|
||||||
gnutls_x509_crt_t cert;
|
|
||||||
const char *hostname;
|
|
||||||
|
|
||||||
mysql= data->mysql;
|
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);
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -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);
|
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) ||
|
SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL);
|
||||||
(mysql->client_flag & CLIENT_SSL_VERIFY_SERVER_CERT) ?
|
|
||||||
SSL_VERIFY_PEER : SSL_VERIFY_NONE, NULL);
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
@@ -648,7 +646,8 @@ my_bool ma_tls_connect(MARIADB_TLS *ctls)
|
|||||||
pvio->methods->blocking(pvio, FALSE, 0);
|
pvio->methods->blocking(pvio, FALSE, 0);
|
||||||
return 1;
|
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);
|
rc= SSL_get_verify_result(ssl);
|
||||||
if (rc != X509_V_OK)
|
if (rc != X509_V_OK)
|
||||||
|
@@ -1329,7 +1329,7 @@ static int test_conc386(MYSQL *mysql)
|
|||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_OPENSSL
|
#ifndef HAVE_SCHANNEL
|
||||||
static int test_ssl_verify(MYSQL *my __attribute__((unused)))
|
static int test_ssl_verify(MYSQL *my __attribute__((unused)))
|
||||||
{
|
{
|
||||||
MYSQL *mysql;
|
MYSQL *mysql;
|
||||||
@@ -1355,13 +1355,20 @@ static int test_ssl_verify(MYSQL *my __attribute__((unused)))
|
|||||||
port, socketname, 0), mysql_error(mysql));
|
port, socketname, 0), mysql_error(mysql));
|
||||||
mysql_close(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;
|
return OK;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
struct my_tests_st my_tests[] = {
|
struct my_tests_st my_tests[] = {
|
||||||
{"test_ssl", test_ssl, TEST_CONNECTION_NEW, 0, NULL, NULL},
|
{"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},
|
{"test_ssl_verify", test_ssl_verify, TEST_CONNECTION_NEW, 0, NULL, NULL},
|
||||||
#endif
|
#endif
|
||||||
{"test_mdev14101", test_mdev14101, TEST_CONNECTION_NEW, 0, NULL, NULL},
|
{"test_mdev14101", test_mdev14101, TEST_CONNECTION_NEW, 0, NULL, NULL},
|
||||||
|
Reference in New Issue
Block a user