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
881 lines
24 KiB
C
881 lines
24 KiB
C
/*
|
|
Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
|
|
|
|
The MySQL Connector/C is licensed under the terms of the GPLv2
|
|
<http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most
|
|
MySQL Connectors. There are special exceptions to the terms and
|
|
conditions of the GPLv2 as it is applied to this software, see the
|
|
FLOSS License Exception
|
|
<http://www.mysql.com/about/legal/licensing/foss-exception.html>.
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published
|
|
by the Free Software Foundation; version 2 of the License.
|
|
|
|
This program is distributed in the hope that it will be useful, but
|
|
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
|
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
for more details.
|
|
|
|
You should have received a copy of the GNU General Public License along
|
|
with this program; if not, write to the Free Software Foundation, Inc.,
|
|
51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
#include "my_test.h"
|
|
#include "ma_common.h"
|
|
#include "ma_pvio.h"
|
|
|
|
#include <mysql/client_plugin.h>
|
|
|
|
#ifdef HAVE_GNUTLS
|
|
#include <gnutls/gnutls.h>
|
|
#include <gnutls/x509.h>
|
|
#include <gnutls/abstract.h>
|
|
#elif HAVE_OPENSSL
|
|
#include <openssl/ssl.h>
|
|
#endif
|
|
|
|
static const char *strong_pwd= "!1_5rd_D%A1$f48Hk1$";
|
|
|
|
static void set_verify(MYSQL *mysql, my_bool onoff)
|
|
{
|
|
mysql_options(mysql, MYSQL_OPT_SSL_VERIFY_SERVER_CERT, &onoff);
|
|
return;
|
|
}
|
|
|
|
#define CHECK_TLS_FLAGS(m, flag, text) \
|
|
{\
|
|
unsigned int status;\
|
|
mariadb_get_infov(mysql, MARIADB_TLS_VERIFY_STATUS, &status);\
|
|
FAIL_IF(!(status & (flag)), (text));\
|
|
}
|
|
|
|
#define CHECK_NO_TLS_FLAG(m, flag, text)\
|
|
{\
|
|
unsigned int status;\
|
|
mariadb_get_infov(mysql, MARIADB_TLS_VERIFY_STATUS, &status);\
|
|
FAIL_IF((status & (flag)), (text));\
|
|
}
|
|
|
|
my_bool auto_generated_cert= 0;
|
|
my_bool ignore_self_signed= 0;
|
|
|
|
static char *tls_dummy_host= NULL;
|
|
static int tls_dummy_port= 0;
|
|
|
|
static my_bool ignore_self_signed_cert_error(MYSQL *mysql)
|
|
{
|
|
const char *hostname= mysql->host;
|
|
const char *local_host_names[]= {
|
|
#ifdef _WIN32
|
|
/*
|
|
On Unix, we consider TCP connections with "localhost"
|
|
an insecure transport, for the single reason to run tests for
|
|
insecure transport on CI.This is artificial, but should be ok.
|
|
Default client connections use unix sockets anyway, so it
|
|
would not hurt much.
|
|
|
|
On Windows, the situation is quite different.
|
|
Default connections type is TCP, default host name is "localhost",
|
|
non-password plugin gssapi is common (every installation)
|
|
In this environment, there would be a lot of faux/disruptive
|
|
"self-signed certificates" errors there. Thus, "localhost" TCP
|
|
needs to be considered secure transport.
|
|
*/
|
|
"localhost",
|
|
#endif
|
|
"127.0.0.1", "::1", NULL};
|
|
int i;
|
|
|
|
/* if CA or CAPath was specified, we don't ignore self signed
|
|
certificates */
|
|
if (mysql->options.ssl_ca ||
|
|
mysql->options.ssl_capath)
|
|
return FALSE;
|
|
|
|
if (mysql->net.pvio->type != PVIO_TYPE_SOCKET)
|
|
{
|
|
return TRUE;
|
|
}
|
|
if (!hostname)
|
|
return FALSE;
|
|
for (i= 0; local_host_names[i]; i++)
|
|
{
|
|
if (strcmp(hostname, local_host_names[i]) == 0)
|
|
{
|
|
return TRUE;
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
static int tls_abort_after_handshake(MARIADB_TLS *ctls, unsigned int flags)
|
|
{
|
|
MYSQL *mysql= ctls->pvio->mysql;
|
|
|
|
ma_pvio_tls_verify_server_cert(ctls, flags);
|
|
|
|
mysql->net.tls_verify_status|= MARIADB_TLS_VERIFY_ERROR;
|
|
my_set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN,
|
|
ER(CR_SSL_CONNECTION_ERROR),
|
|
"Certificate verification aborted.");
|
|
return 1;
|
|
}
|
|
|
|
static int test_start_tls_server(MYSQL *my __attribute__((unused)))
|
|
{
|
|
#ifdef WIN32
|
|
STARTUPINFO si;
|
|
PROCESS_INFORMATION pi;
|
|
char szCmdline[1024];
|
|
|
|
snprintf(szCmdline, sizeof(szCmdline), "%s @CC_SOURCE_DIR@/unittest/libmariadb/tls_server.py --host=%s --port=%d", "@Python3_EXECUTABLE@", tls_dummy_host, tls_dummy_port);
|
|
|
|
ZeroMemory(&si, sizeof(si));
|
|
ZeroMemory(&pi, sizeof(pi));
|
|
|
|
GetStartupInfo(&si);
|
|
si.cb = sizeof(STARTUPINFO);
|
|
si.wShowWindow = SW_SHOWDEFAULT;
|
|
|
|
if( !CreateProcessA(NULL,
|
|
szCmdline,
|
|
NULL,
|
|
NULL,
|
|
FALSE,
|
|
CREATE_NEW_CONSOLE,
|
|
NULL,
|
|
NULL,
|
|
&si,
|
|
&pi)
|
|
)
|
|
{
|
|
diag("couldn't start tls_server. Error %d", GetLastError());
|
|
return FAIL;
|
|
}
|
|
#else
|
|
pid_t tls_server_pid;
|
|
|
|
if (!(tls_server_pid= fork()))
|
|
{
|
|
char hostname[1024], port[128];
|
|
|
|
snprintf(hostname, sizeof(hostname), "--host=%s", tls_dummy_host);
|
|
snprintf(port, sizeof(port), "--port=%d", tls_dummy_port);
|
|
execlp("@Python3_EXECUTABLE@", "@Python3_EXECUTABLE@", "@CC_SOURCE_DIR@/unittest/libmariadb/tls_server.py", hostname, port, NULL);
|
|
}
|
|
|
|
#endif
|
|
sleep(10);
|
|
return OK;
|
|
}
|
|
|
|
|
|
static int set_tls_dummy_options(const char *options)
|
|
{
|
|
MA_PVIO_CINFO cinfo;
|
|
MARIADB_PVIO *pvio;
|
|
MYSQL *mysql= mysql_init(NULL);
|
|
char buffer[1024];
|
|
size_t len;
|
|
|
|
cinfo.type= PVIO_TYPE_SOCKET;
|
|
cinfo.host= tls_dummy_host;
|
|
cinfo.port= tls_dummy_port;
|
|
cinfo.mysql = mysql;
|
|
|
|
set_verify(mysql, 1);
|
|
|
|
if (!(pvio= ma_pvio_init(&cinfo)))
|
|
{
|
|
diag("pvio_init failed");
|
|
return 1;
|
|
}
|
|
if (ma_pvio_connect(pvio, &cinfo))
|
|
{
|
|
diag("connect failed: %s", mysql_error(mysql));
|
|
return 1;
|
|
}
|
|
|
|
if (!(len= ma_pvio_read(pvio, (uchar *)buffer, sizeof(buffer))))
|
|
{
|
|
diag("Error reading server packet");
|
|
return 1;
|
|
}
|
|
|
|
if (!ma_pvio_write(pvio, (uchar *)options, strlen(options)))
|
|
{
|
|
diag("Error writing configuration");
|
|
return 1;
|
|
}
|
|
|
|
ma_pvio_close(pvio);
|
|
mysql_close(mysql);
|
|
return OK;
|
|
}
|
|
|
|
|
|
static int test_init(MYSQL *my __attribute__((unused)))
|
|
{
|
|
MYSQL *mysql= mysql_init(NULL);
|
|
int rc;
|
|
int ret= FAIL;
|
|
MYSQL_RES *result;
|
|
MYSQL_ROW row;
|
|
|
|
diag("test_init");
|
|
|
|
/* Force use of TLS */
|
|
mysql_ssl_set(mysql, NULL, NULL, NULL, NULL, NULL);
|
|
|
|
/* Don't verify peer certificate */
|
|
set_verify(mysql, 0);
|
|
|
|
FAIL_IF(!my_test_connect(mysql, hostname, username, password, schema,
|
|
port, socketname, 0, 0), mysql_error(my));
|
|
|
|
rc= mysql_query(mysql, "SELECT @@ssl_cert");
|
|
check_mysql_rc(rc, mysql);
|
|
|
|
if ((result= mysql_store_result(mysql)))
|
|
{
|
|
row= mysql_fetch_row(result);
|
|
auto_generated_cert = (row[0] == NULL);
|
|
mysql_free_result(result);
|
|
}
|
|
|
|
diag("autogenerated: %d", auto_generated_cert);
|
|
ignore_self_signed= ignore_self_signed_cert_error(mysql);
|
|
diag("ignore self signed certificates: %d", ignore_self_signed);
|
|
|
|
ret= OK;
|
|
|
|
mysql_close(mysql);
|
|
return ret;
|
|
}
|
|
|
|
static int test_no_cert_check(MYSQL *my __attribute__((unused)))
|
|
{
|
|
MYSQL *mysql= mysql_init(NULL);
|
|
|
|
/* Force use of TLS */
|
|
mysql_ssl_set(mysql, NULL, NULL, NULL, NULL, NULL);
|
|
|
|
/* Don't verify peer certificate */
|
|
set_verify(mysql, 0);
|
|
|
|
FAIL_IF(!my_test_connect(mysql, hostname, username, password, schema,
|
|
port, socketname, 0, 0), mysql_error(my));
|
|
|
|
FAIL_IF(!mysql_get_ssl_cipher(mysql), "No TLS connection");
|
|
|
|
mysql_close(mysql);
|
|
return OK;
|
|
}
|
|
|
|
static int test_conc712(MYSQL *my __attribute__((unused)))
|
|
{
|
|
MYSQL *mysql= mysql_init(NULL);
|
|
int rc= FAIL;
|
|
|
|
if (set_tls_dummy_options("CMD:create_new=True"))
|
|
{
|
|
diag("Error when setting TLS options");
|
|
return FAIL;
|
|
}
|
|
/* Force use of TLS with faked ca, which contains the server
|
|
certificate */
|
|
set_verify(mysql, 1);
|
|
mysql_ssl_set(mysql, NULL, NULL, "./selfsigned.pem", NULL, NULL);
|
|
mysql_optionsv(mysql, MARIADB_OPT_TLS_VERIFICATION_CALLBACK, tls_abort_after_handshake);
|
|
|
|
if (my_test_connect(mysql, tls_dummy_host, username, password, schema,
|
|
tls_dummy_port, socketname, 0, 0))
|
|
{
|
|
diag("Error: %s", mysql_error(mysql));
|
|
goto end;
|
|
}
|
|
CHECK_NO_TLS_FLAG(mysql, MARIADB_TLS_VERIFY_HOST, "Hostname verification didn't pass");
|
|
rc= OK;
|
|
end:
|
|
mysql_close(mysql);
|
|
return rc;
|
|
}
|
|
|
|
static int test_fp(MYSQL *my __attribute__((unused)))
|
|
{
|
|
unsigned int hash_size[3] = {256, 384, 512};
|
|
int i;
|
|
MYSQL *mysql= mysql_init(NULL);
|
|
|
|
|
|
/* Force use of TLS */
|
|
mysql_ssl_set(mysql, NULL, NULL, NULL, NULL, NULL);
|
|
|
|
/* Don't verify peer certificate */
|
|
set_verify(mysql, 0);
|
|
|
|
FAIL_IF(!my_test_connect(mysql, hostname, username, password, schema,
|
|
port, socketname, 0, 1), mysql_error(my));
|
|
|
|
for (i=0; i < 3; i++)
|
|
{
|
|
MYSQL *mysql1= mysql_init(NULL);
|
|
MARIADB_X509_INFO *info;
|
|
|
|
diag("testing SHA%d fingerprint", hash_size[i]);
|
|
|
|
mariadb_get_infov(mysql, MARIADB_TLS_PEER_CERT_INFO, &info, hash_size[i]);
|
|
|
|
mysql_optionsv(mysql1, MARIADB_OPT_SSL_FP, info->fingerprint);
|
|
FAIL_IF(!my_test_connect(mysql1, hostname, username, password, schema,
|
|
port, socketname, 0, 0), mysql_error(my));
|
|
|
|
FAIL_IF(!mysql_get_ssl_cipher(mysql), "No TLS connection");
|
|
mysql_close(mysql1);
|
|
}
|
|
mysql_close(mysql);
|
|
return OK;
|
|
}
|
|
|
|
static int test_fp_colon(MYSQL *my __attribute__((unused)))
|
|
{
|
|
unsigned int hash_size[3] = {256, 384, 512};
|
|
int i;
|
|
MYSQL *mysql= mysql_init(NULL);
|
|
char fp[200];
|
|
|
|
|
|
/* Force use of TLS */
|
|
mysql_ssl_set(mysql, NULL, NULL, NULL, NULL, NULL);
|
|
|
|
/* Don't verify peer certificate */
|
|
set_verify(mysql, 0);
|
|
|
|
FAIL_IF(!my_test_connect(mysql, hostname, username, password, schema,
|
|
port, socketname, 0, 0), mysql_error(my));
|
|
|
|
for (i=0; i < 3; i++)
|
|
{
|
|
MYSQL *mysql1= mysql_init(NULL);
|
|
MARIADB_X509_INFO *info;
|
|
char *p= &fp[0];
|
|
size_t j;
|
|
|
|
diag("testing SHA%d fingerprint with colons", hash_size[i]);
|
|
|
|
memset(fp, 0, sizeof(fp));
|
|
|
|
mariadb_get_infov(mysql, MARIADB_TLS_PEER_CERT_INFO, &info, hash_size[i]);
|
|
|
|
for (j=0; j < strlen(info->fingerprint) / 2; j++)
|
|
{
|
|
memcpy(p, info->fingerprint + j * 2, 2);
|
|
p+= 2;
|
|
*p++= ':';
|
|
}
|
|
p--;
|
|
*p= 0;
|
|
|
|
|
|
diag ("fp: %s", fp);
|
|
mysql_optionsv(mysql1, MARIADB_OPT_SSL_FP, fp);
|
|
FAIL_IF(!my_test_connect(mysql1, hostname, username, password, schema,
|
|
port, socketname, 0, 0), mysql_error(my));
|
|
|
|
FAIL_IF(!mysql_get_ssl_cipher(mysql), "No TLS connection");
|
|
mysql_close(mysql1);
|
|
}
|
|
mysql_close(mysql);
|
|
return OK;
|
|
}
|
|
|
|
|
|
static int test_peer_cert_info_fp(MYSQL *my __attribute__((unused)))
|
|
{
|
|
MYSQL *mysql= mysql_init(NULL);
|
|
MARIADB_X509_INFO *info;
|
|
char old_fp[129] = {0};
|
|
int i;
|
|
unsigned int hash_size[3] = {256, 384, 512};
|
|
|
|
/* Force use of TLS */
|
|
mysql_ssl_set(mysql, NULL, NULL, NULL, NULL, NULL);
|
|
|
|
/* Don't verify peer certificate */
|
|
set_verify(mysql, 0);
|
|
|
|
FAIL_IF(!my_test_connect(mysql, hostname, username, password, schema,
|
|
port, socketname, 0, 0), mysql_error(my));
|
|
|
|
for (i=0; i < 3; i++)
|
|
{
|
|
mariadb_get_infov(mysql, MARIADB_TLS_PEER_CERT_INFO, &info, hash_size[i]);
|
|
FAIL_IF(!info->version, "Wrong certificate version=0");
|
|
|
|
FAIL_IF(!strcmp(old_fp, info->fingerprint), "Fingerprint was not updated");
|
|
if (strlen(info->fingerprint) != hash_size[i] / 4)
|
|
{
|
|
diag("Got fingerprint length %zu, expected %u", strlen(info->fingerprint), hash_size[i] / 4);
|
|
return FAIL;
|
|
}
|
|
strcpy(old_fp, info->fingerprint);
|
|
}
|
|
|
|
mysql_close(mysql);
|
|
return OK;
|
|
}
|
|
|
|
static int test_fp_garbage(MYSQL *my __attribute__((unused)))
|
|
{
|
|
MYSQL *mysql= mysql_init(NULL);
|
|
char fp[129];
|
|
|
|
mysql_ssl_set(mysql, NULL, NULL, NULL, NULL, NULL);
|
|
|
|
/* 1) use non hex chars */
|
|
strcpy(fp, "IJKLMNOPQRSTUVWXYZABCDEXXXXXX67IJKLMNOPQRSTUVWXYZABCDEXXXXXX679X");
|
|
if (mysql_optionsv(mysql, MARIADB_OPT_SSL_FP, fp))
|
|
return FAIL;
|
|
|
|
if (my_test_connect(mysql, hostname, username, password, schema,
|
|
port, socketname, 0, 0))
|
|
{
|
|
diag("Error expected");
|
|
diag("%s", mysql_get_ssl_cipher(mysql));
|
|
return FAIL;
|
|
}
|
|
CHECK_TLS_FLAGS(mysql, MARIADB_TLS_VERIFY_FINGERPRINT, "Fingerprint verification flag not set");
|
|
mysql_close(mysql);
|
|
return OK;
|
|
}
|
|
|
|
static int test_pw_check(MYSQL *my)
|
|
{
|
|
MYSQL *mysql= mysql_init(NULL);
|
|
int rc;
|
|
my_bool local_safe_connection= ignore_self_signed_cert_error(my);
|
|
char query[1024];
|
|
int ret= FAIL;
|
|
|
|
sprintf(query, "DROP USER IF EXISTS '%s'@'%s'", "tlsuser", this_host);
|
|
rc= mysql_query(my, query);
|
|
check_mysql_rc(rc, my);
|
|
|
|
/* connect with password */
|
|
sprintf(query, "CREATE USER '%s'@'%s' IDENTIFIED BY '%s'", "tlsuser", this_host, strong_pwd);
|
|
rc= mysql_query(my, query);
|
|
check_mysql_rc(rc, my);
|
|
|
|
set_verify(mysql, 1);
|
|
|
|
diag("expected to pass with self signed");
|
|
if (!my_test_connect(mysql, hostname, "tlsuser", strong_pwd, NULL, port, socketname, 0, 0))
|
|
{
|
|
/* We connected to a pre 11.4 server, so skip further tests */
|
|
CHECK_TLS_FLAGS(mysql, MARIADB_TLS_VERIFY_TRUST, "trust validation flag not set");
|
|
mysql_close(mysql);
|
|
diag("Test will not work with server < 11.4");
|
|
return SKIP;
|
|
}
|
|
CHECK_TLS_FLAGS(mysql, MARIADB_TLS_VERIFY_TRUST, "Trust verification flag not set");
|
|
|
|
mysql_close(mysql);
|
|
mysql= mysql_init(NULL);
|
|
|
|
/* connect without pasword */
|
|
if (!IS_ENTERPRISE() && !local_safe_connection)
|
|
{
|
|
sprintf(query, "DROP USER '%s'@'%s'", "tlsuser", this_host);
|
|
rc= mysql_query(my, query);
|
|
check_mysql_rc(rc, my);
|
|
|
|
sprintf(query, "CREATE USER '%s'@'%s'", "tlsuser", this_host);
|
|
rc= mysql_query(my, query);
|
|
check_mysql_rc(rc, my);
|
|
|
|
if (my_test_connect(mysql, hostname, "tlsuser", NULL, NULL, port, socketname, 0, 0))
|
|
{
|
|
diag("Error expected since no password was specified");
|
|
goto end;
|
|
}
|
|
|
|
CHECK_TLS_FLAGS(mysql, MARIADB_TLS_VERIFY_TRUST, "Not trusted flag not set")
|
|
|
|
mysql_close(mysql);
|
|
mysql = mysql_init(NULL);
|
|
mysql_optionsv(mysql, MARIADB_OPT_RESTRICTED_AUTH, "mysql_native_password, mysql_old_password");
|
|
|
|
diag("expected to fail with old_password plugin");
|
|
sprintf(query, "DROP USER '%s'@'%s'", "tlsuser", this_host);
|
|
rc= mysql_query(my, query);
|
|
check_mysql_rc(rc, my);
|
|
/* Test with an authentication plugin, which doesn't support hashing */
|
|
sprintf(query, "CREATE USER '%s'@'%s' IDENTIFIED VIA mysql_old_password USING '7c786c222596437b'", "tlsuser", this_host);
|
|
rc= mysql_query(my, query);
|
|
check_mysql_rc(rc, my);
|
|
rc= mysql_query(my, "SET GLOBAL secure_auth=0");
|
|
check_mysql_rc(rc, my);
|
|
|
|
if (my_test_connect(mysql, hostname, "tlsuser", "foo", NULL, port, socketname, 0, 0))
|
|
{
|
|
diag("Error expected since old_password was specified");
|
|
goto end;
|
|
}
|
|
diag("ok");
|
|
}
|
|
|
|
ret= OK;
|
|
end:
|
|
mysql_close(mysql);
|
|
return ret;
|
|
}
|
|
|
|
static int test_cert_expired(MYSQL *my __attribute__((unused)))
|
|
{
|
|
int ret= OK;
|
|
MYSQL *mysql;
|
|
|
|
/* Set validity in future */
|
|
if (set_tls_dummy_options("CMD:create_new=True validityStartInSeconds=10000 validityEndInSeconds=2000"))
|
|
{
|
|
diag("Error when setting TLS options");
|
|
return FAIL;
|
|
}
|
|
|
|
mysql= mysql_init(NULL);
|
|
|
|
mysql_ssl_set(mysql, NULL, NULL, NULL, NULL, NULL);
|
|
set_verify(mysql, 1);
|
|
|
|
if (my_test_connect(mysql, tls_dummy_host, "tlsuser", "foo", NULL, tls_dummy_port, NULL, 0, 0))
|
|
{
|
|
diag("Error expected since cert is not valid yet");
|
|
return FAIL;
|
|
}
|
|
mysql_close(mysql);
|
|
|
|
/* Set cert expired */
|
|
if (set_tls_dummy_options("CMD:create_new=True validityStartInSeconds=-20000 validityEndInSeconds=-10000"))
|
|
{
|
|
diag("Error when setting TLS options");
|
|
return FAIL;
|
|
}
|
|
|
|
mysql= mysql_init(NULL);
|
|
set_verify(mysql, 1);
|
|
|
|
mysql_ssl_set(mysql, NULL, NULL, NULL, NULL, NULL);
|
|
|
|
if (my_test_connect(mysql, tls_dummy_host, "tlsuser", "foo", NULL, tls_dummy_port, NULL, 0, 0))
|
|
{
|
|
diag("Error expected since cert is not valid yet");
|
|
return FAIL;
|
|
}
|
|
CHECK_TLS_FLAGS(mysql, MARIADB_TLS_VERIFY_PERIOD, "NotBefore/NotAfter flag not set")
|
|
mysql_close(mysql);
|
|
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int test_wrong_ca(MYSQL *my __attribute__((unused)))
|
|
{
|
|
MYSQL *mysql= mysql_init(NULL);
|
|
|
|
mysql_ssl_set(mysql, NULL, NULL, "selfsigned.pem", NULL, NULL);
|
|
set_verify(mysql, 1);
|
|
if (my_test_connect(mysql, hostname, "tlsuser", "foo", NULL, port, socketname, 0, 0))
|
|
{
|
|
diag("self signed error expected");
|
|
return FAIL;
|
|
}
|
|
CHECK_TLS_FLAGS(mysql, MARIADB_TLS_VERIFY_TRUST, "Not trusted flag not set")
|
|
mysql_close(mysql);
|
|
return OK;
|
|
}
|
|
|
|
static int test_crl(MYSQL *my __attribute__((unused)))
|
|
{
|
|
MYSQL *mysql;
|
|
|
|
/* Set validity in future */
|
|
if (set_tls_dummy_options("CMD:KEY_FILE='@CC_BINARY_DIR@/unittest/libmariadb/certs/server-key.pem' CERT_FILE='@CC_BINARY_DIR@/unittest/libmariadb/certs/server-cert.pem'"))
|
|
{
|
|
diag("Error when setting TLS options");
|
|
return FAIL;
|
|
}
|
|
|
|
mysql= mysql_init(NULL);
|
|
set_verify(mysql, 1);
|
|
|
|
mysql_optionsv(mysql, MYSQL_OPT_SSL_CRL, "@CC_BINARY_DIR@/unittest/libmariadb/certs/server-cert.crl");
|
|
mysql_ssl_set(mysql, NULL, NULL, "@CC_BINARY_DIR@/unittest/libmariadb/certs/cacert.pem", NULL, NULL);
|
|
|
|
if (my_test_connect(mysql, tls_dummy_host, "tlsuser", "foo", NULL, tls_dummy_port, NULL, 0, 0))
|
|
{
|
|
diag("Error expected since cert revoked");
|
|
return FAIL;
|
|
}
|
|
CHECK_TLS_FLAGS(mysql, MARIADB_TLS_VERIFY_REVOKED, "Revocation flag not set")
|
|
mysql_close(mysql);
|
|
return OK;
|
|
}
|
|
|
|
static int test_crl_with_fp(MYSQL *my __attribute__((unused)))
|
|
{
|
|
MYSQL *mysql;
|
|
/* hardcoded: openssl x509 -noout -fingerprint -sha256 -inform pem -in certs/server-cert.pem */
|
|
const char *fp= "4B:EE:BB:12:6D:30:1A:B2:2A:4A:F8:6D:82:7F:63:44:1F:8F:F4:6B:D3:F2:CA:68:0B:D5:E3:5D:1C:47:A7:16";
|
|
|
|
/* Set validity in future */
|
|
if (set_tls_dummy_options("CMD:KEY_FILE='@CC_BINARY_DIR@/unittest/libmariadb/certs/server-key.pem' CERT_FILE='@CC_BINARY_DIR@/unittest/libmariadb/certs/server-cert.pem'"))
|
|
{
|
|
diag("Error when setting TLS options");
|
|
return FAIL;
|
|
}
|
|
|
|
mysql= mysql_init(NULL);
|
|
mysql_optionsv(mysql, MARIADB_OPT_SSL_FP, fp);
|
|
|
|
mysql_optionsv(mysql, MYSQL_OPT_SSL_CRL, "@CC_BINARY_DIR@/unittest/libmariadb/certs/server-cert.crl");
|
|
mysql_ssl_set(mysql, NULL, NULL, "@CC_BINARY_DIR@/unittest/libmariadb/certs/cacert.pem", NULL, NULL);
|
|
|
|
if (my_test_connect(mysql, tls_dummy_host, "tlsuser", "foo", NULL, tls_dummy_port, NULL, 0, 0))
|
|
{
|
|
diag("Error expected since cert revoked");
|
|
return FAIL;
|
|
}
|
|
CHECK_TLS_FLAGS(mysql, MARIADB_TLS_VERIFY_REVOKED, "Revocation flag not set")
|
|
mysql_close(mysql);
|
|
return OK;
|
|
}
|
|
|
|
static int stop_tls_server(MYSQL *my __attribute__((unused)))
|
|
{
|
|
if (set_tls_dummy_options("QUIT"))
|
|
{
|
|
diag("Error when shutting down tls dummy server");
|
|
return FAIL;
|
|
}
|
|
return OK;
|
|
}
|
|
|
|
static int tls_wildcard_callback(MARIADB_TLS *ctls, unsigned int flags)
|
|
{
|
|
MYSQL *mysql= ctls->pvio->mysql;
|
|
|
|
free(mysql->host);
|
|
mysql->host= strdup("test.example.com");
|
|
flags= MARIADB_TLS_VERIFY_HOST;
|
|
|
|
ma_pvio_tls_verify_server_cert(ctls, flags);
|
|
|
|
/* Indicate error, since the dummy server can't handle further client server
|
|
communication after TLS handshake */
|
|
mysql->net.tls_verify_status|= MARIADB_TLS_VERIFY_ERROR;
|
|
my_set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN,
|
|
ER(CR_SSL_CONNECTION_ERROR),
|
|
"Certificate verification aborted.");
|
|
return 1;
|
|
}
|
|
|
|
static int test_cert_wildcard(MYSQL *my __attribute((unused)))
|
|
{
|
|
MYSQL *mysql= mysql_init(NULL);
|
|
if (set_tls_dummy_options("CMD:create_new=True commonName='*.example.com'"))
|
|
{
|
|
diag("Error when setting TLS options");
|
|
return FAIL;
|
|
}
|
|
mysql_ssl_set(mysql, NULL, NULL, NULL, NULL, NULL);
|
|
set_verify(mysql, 1);
|
|
mysql_optionsv(mysql, MARIADB_OPT_TLS_VERIFICATION_CALLBACK, tls_wildcard_callback);
|
|
|
|
if (!my_test_connect(mysql, tls_dummy_host, "tlsuser", "foo", NULL, tls_dummy_port, NULL, 0, 0))
|
|
{
|
|
CHECK_NO_TLS_FLAG(mysql, MARIADB_TLS_VERIFY_HOST, "Hostname verification didn't pass");
|
|
#ifndef HAVE_SCHANNEL
|
|
CHECK_TLS_FLAGS(mysql, MARIADB_TLS_VERIFY_TRUST, "Self signed certificate expected");
|
|
#endif
|
|
mysql_close(mysql);
|
|
} else {
|
|
mysql_close(mysql);
|
|
return FAIL;
|
|
}
|
|
|
|
mysql= mysql_init(NULL);
|
|
if (set_tls_dummy_options("CMD:create_new=True commonName='*.noexample.com'"))
|
|
{
|
|
diag("Error when setting TLS options");
|
|
return FAIL;
|
|
}
|
|
mysql_ssl_set(mysql, NULL, NULL, NULL, NULL, NULL);
|
|
set_verify(mysql, 1);
|
|
mysql_optionsv(mysql, MARIADB_OPT_TLS_VERIFICATION_CALLBACK, tls_wildcard_callback);
|
|
|
|
if (!my_test_connect(mysql, tls_dummy_host, "tlsuser", "foo", NULL, tls_dummy_port, NULL, 0, 0))
|
|
{
|
|
CHECK_TLS_FLAGS(mysql, MARIADB_TLS_VERIFY_HOST, "Hostname verification passed with wrong wildcard");
|
|
mysql_close(mysql);
|
|
} else {
|
|
mysql_close(mysql);
|
|
return FAIL;
|
|
}
|
|
return OK;
|
|
}
|
|
|
|
static int test_env_var(MYSQL *my __attribute__((unused)))
|
|
{
|
|
MYSQL *mysql= mysql_init(NULL);
|
|
int rc= FAIL;
|
|
|
|
if (mysql_get_server_version(my) < 110400)
|
|
{
|
|
diag("skipping for MySQL / mariadb before 11.4, because might not have ssl on");
|
|
rc = SKIP;
|
|
goto end;
|
|
}
|
|
|
|
#ifdef _WIN32
|
|
_putenv_s("MARIADB_TLS_DISABLE_PEER_VERIFICATION", "1");
|
|
#else
|
|
setenv("MARIADB_TLS_DISABLE_PEER_VERIFICATION", "1", 1);
|
|
#endif
|
|
set_verify(mysql, 1);
|
|
|
|
if (!my_test_connect(mysql, hostname, username, password, schema,
|
|
port, socketname, 0, 0))
|
|
{
|
|
diag("expected to pass, since environment variable was set");
|
|
goto end;
|
|
}
|
|
|
|
rc= OK;
|
|
|
|
end:
|
|
#ifdef _WIN32
|
|
_putenv_s("MARIADB_TLS_DISABLE_PEER_VERIFICATION", "");
|
|
#else
|
|
unsetenv("MARIADB_TLS_DISABLE_PEER_VERIFICATION");
|
|
#endif
|
|
mysql_close(mysql);
|
|
return rc;
|
|
}
|
|
|
|
static int test_fp_and_verify(MYSQL *my __attribute__((unused)))
|
|
{
|
|
MYSQL *mysql= mysql_init(NULL);
|
|
int rc= FAIL;
|
|
#ifndef HAVE_SCHANNEL
|
|
unsigned int status;
|
|
#endif
|
|
|
|
mysql_options(mysql, MARIADB_OPT_SSL_FP, fingerprint);
|
|
set_verify(mysql, 1);
|
|
|
|
if (!my_test_connect(mysql, hostname, username, password, schema,
|
|
port, socketname, 0, 0))
|
|
{
|
|
diag("expected to pass, since fingerprint was specified");
|
|
diag("error: %s", mysql_error(mysql));
|
|
goto end;
|
|
}
|
|
|
|
/* Schannel aborts on first error, if fingerprint was specified,
|
|
MARIADB_TLS_VERIFY_TRUST is unset */
|
|
#ifndef HAVE_SCHANNEL
|
|
mariadb_get_infov(mysql, MARIADB_TLS_VERIFY_STATUS, &status);
|
|
|
|
if (!status)
|
|
{
|
|
diag("expected status flag set (self signed)");
|
|
goto end;
|
|
}
|
|
#endif
|
|
rc= OK;
|
|
|
|
end:
|
|
mysql_close(mysql);
|
|
return rc;
|
|
}
|
|
|
|
static int test_cert_ip(MYSQL *my __attribute((unused)))
|
|
{
|
|
char dummy_options[128];
|
|
MYSQL *mysql= mysql_init(NULL);
|
|
|
|
snprintf(dummy_options, 128, "CMD:create_new=True SAN='IP.1:%s'", tls_dummy_host);
|
|
if (set_tls_dummy_options(dummy_options))
|
|
{
|
|
diag("Error when setting TLS options");
|
|
return FAIL;
|
|
}
|
|
mysql_ssl_set(mysql, NULL, NULL, NULL, NULL, NULL);
|
|
set_verify(mysql, 1);
|
|
mysql_optionsv(mysql, MARIADB_OPT_TLS_VERIFICATION_CALLBACK, tls_abort_after_handshake);
|
|
|
|
if (!my_test_connect(mysql, tls_dummy_host, "tlsuser", "foo", NULL, tls_dummy_port, NULL, 0, 0))
|
|
{
|
|
CHECK_NO_TLS_FLAG(mysql, MARIADB_TLS_VERIFY_HOST, "Hostname verification didn't pass");
|
|
mysql_close(mysql);
|
|
} else {
|
|
mysql_close(mysql);
|
|
return FAIL;
|
|
}
|
|
|
|
return OK;
|
|
}
|
|
|
|
|
|
struct my_tests_st my_tests[] = {
|
|
/* Don't add test above, test_init needs to be run first */
|
|
{"test_start_tls_server", test_start_tls_server, TEST_CONNECTION_NONE, 0, NULL, NULL},
|
|
{"test_init", test_init, TEST_CONNECTION_NONE, 0, NULL, NULL},
|
|
/* Here you can add more tests */
|
|
{"test_cert_ip", test_cert_ip, TEST_CONNECTION_NEW, 0, NULL, NULL},
|
|
{"test_fp_and_verify", test_fp_and_verify, TEST_CONNECTION_NEW, 0, NULL, NULL},
|
|
{"test_env_var", test_env_var, TEST_CONNECTION_NEW, 0, NULL, NULL},
|
|
{"test_cert_wildcard", test_cert_wildcard, TEST_CONNECTION_NEW, 0, NULL, NULL},
|
|
{"test_cert_expired", test_cert_expired, TEST_CONNECTION_NEW, 0, NULL, NULL},
|
|
{"test_pw_check", test_pw_check, TEST_CONNECTION_NEW, 0, NULL, NULL},
|
|
{"test_conc712", test_conc712, TEST_CONNECTION_NONE, 0, NULL, NULL},
|
|
{"test_fp_garbage", test_fp_garbage, TEST_CONNECTION_NONE, 0, NULL, NULL},
|
|
{"test_peer_cert_info_fp", test_peer_cert_info_fp, TEST_CONNECTION_NONE, 0, NULL, NULL},
|
|
{"test_no_cert_check", test_no_cert_check, TEST_CONNECTION_NONE, 0, NULL, NULL},
|
|
{"test_fp", test_fp, TEST_CONNECTION_NONE, 0, NULL, NULL},
|
|
{"test_fp_colon", test_fp_colon, TEST_CONNECTION_NONE, 0, NULL, NULL},
|
|
{"test_wrong_ca", test_wrong_ca, TEST_CONNECTION_NONE, 0, NULL, NULL},
|
|
{"test_crl", test_crl, TEST_CONNECTION_NONE, 0, NULL, NULL},
|
|
{"test_crl_with_fp", test_crl_with_fp, TEST_CONNECTION_NONE, 0, NULL, NULL},
|
|
{"stop_tls_server", stop_tls_server, TEST_CONNECTION_NONE, 0, NULL, NULL},
|
|
{NULL, NULL, 0, 0, NULL, 0}
|
|
};
|
|
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
char *dummy_port;
|
|
|
|
#ifdef HAVE_GNUTLS
|
|
diag("GnuTLS_config: %s", gnutls_get_system_config_file());
|
|
#endif
|
|
|
|
if (argc > 1)
|
|
get_options(argc, argv);
|
|
|
|
get_envvars();
|
|
|
|
if (!(tls_dummy_host= getenv("MARIADB_TLS_DUMMY_HOST")))
|
|
tls_dummy_host= (char *)"127.0.0.1";
|
|
if ((dummy_port= getenv("MARIADB_TLS_DUMMY_PORT")))
|
|
tls_dummy_port= atoi(dummy_port);
|
|
if (!tls_dummy_port)
|
|
tls_dummy_port= 50000;
|
|
|
|
|
|
run_tests(my_tests);
|
|
|
|
return(exit_status());
|
|
}
|