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
Merge branch 'master' into serg-integr
This commit is contained in:
@@ -450,19 +450,7 @@ ma_real_read(NET *net, size_t *complen)
|
|||||||
if (i == 0)
|
if (i == 0)
|
||||||
{ /* First parts is packet length */
|
{ /* First parts is packet length */
|
||||||
ulong helping;
|
ulong helping;
|
||||||
if (net->buff[net->where_b + 3] != (uchar) net->pkt_nr)
|
net->pkt_nr= net->buff[net->where_b + 3];
|
||||||
{
|
|
||||||
if (net->buff[net->where_b] != (uchar) 255)
|
|
||||||
{
|
|
||||||
#ifdef EXTRA_DEBUG
|
|
||||||
fprintf(stderr,"Packets out of order (Found: %d, expected %d)\n",
|
|
||||||
(int) net->buff[net->where_b + 3],
|
|
||||||
(uint) (uchar) net->pkt_nr);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
len= packet_error;
|
|
||||||
goto end;
|
|
||||||
}
|
|
||||||
net->compress_pkt_nr= ++net->pkt_nr;
|
net->compress_pkt_nr= ++net->pkt_nr;
|
||||||
#ifdef HAVE_COMPRESS
|
#ifdef HAVE_COMPRESS
|
||||||
if (net->compress)
|
if (net->compress)
|
||||||
|
@@ -525,7 +525,6 @@ my_bool ma_pvio_start_ssl(MARIADB_PVIO *pvio)
|
|||||||
((pvio->mysql->options.extension->tls_fp && pvio->mysql->options.extension->tls_fp[0]) ||
|
((pvio->mysql->options.extension->tls_fp && pvio->mysql->options.extension->tls_fp[0]) ||
|
||||||
(pvio->mysql->options.extension->tls_fp_list && pvio->mysql->options.extension->tls_fp_list[0])))
|
(pvio->mysql->options.extension->tls_fp_list && pvio->mysql->options.extension->tls_fp_list[0])))
|
||||||
{
|
{
|
||||||
|
|
||||||
if (ma_pvio_tls_check_fp(pvio->ctls,
|
if (ma_pvio_tls_check_fp(pvio->ctls,
|
||||||
pvio->mysql->options.extension->tls_fp,
|
pvio->mysql->options.extension->tls_fp,
|
||||||
pvio->mysql->options.extension->tls_fp_list))
|
pvio->mysql->options.extension->tls_fp_list))
|
||||||
|
@@ -124,10 +124,10 @@ static my_bool ma_pvio_tls_compare_fp(const char *fp1, unsigned int fp1_len,
|
|||||||
{
|
{
|
||||||
char hexstr[64];
|
char hexstr[64];
|
||||||
|
|
||||||
|
fp1_len= (unsigned int)mysql_hex_string(hexstr, fp1, fp1_len);
|
||||||
if (fp1_len != fp2_len)
|
if (fp1_len != fp2_len)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
fp1_len= (unsigned int)mysql_hex_string(hexstr, fp1, fp1_len);
|
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
if (strnicmp(hexstr, fp2, fp1_len) != 0)
|
if (strnicmp(hexstr, fp2, fp1_len) != 0)
|
||||||
#else
|
#else
|
||||||
@@ -140,10 +140,12 @@ static my_bool ma_pvio_tls_compare_fp(const char *fp1, unsigned int fp1_len,
|
|||||||
my_bool ma_pvio_tls_check_fp(MARIADB_TLS *ctls, const char *fp, const char *fp_list)
|
my_bool ma_pvio_tls_check_fp(MARIADB_TLS *ctls, const char *fp, const char *fp_list)
|
||||||
{
|
{
|
||||||
unsigned int cert_fp_len= 64;
|
unsigned int cert_fp_len= 64;
|
||||||
char cert_fp[64];
|
char *cert_fp= NULL;
|
||||||
my_bool rc=1;
|
my_bool rc=1;
|
||||||
MYSQL *mysql= ctls->pvio->mysql;
|
MYSQL *mysql= ctls->pvio->mysql;
|
||||||
|
|
||||||
|
cert_fp= (char *)malloc(cert_fp_len);
|
||||||
|
|
||||||
if ((cert_fp_len= ma_tls_get_finger_print(ctls, cert_fp, cert_fp_len)) < 1)
|
if ((cert_fp_len= ma_tls_get_finger_print(ctls, cert_fp, cert_fp_len)) < 1)
|
||||||
goto end;
|
goto end;
|
||||||
if (fp)
|
if (fp)
|
||||||
@@ -154,9 +156,7 @@ my_bool ma_pvio_tls_check_fp(MARIADB_TLS *ctls, const char *fp, const char *fp_l
|
|||||||
char buff[255];
|
char buff[255];
|
||||||
|
|
||||||
if (!(fp = ma_open(fp_list, "r", mysql)))
|
if (!(fp = ma_open(fp_list, "r", mysql)))
|
||||||
{
|
goto end;
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (ma_gets(buff, sizeof(buff)-1, fp))
|
while (ma_gets(buff, sizeof(buff)-1, fp))
|
||||||
{
|
{
|
||||||
@@ -181,6 +181,8 @@ my_bool ma_pvio_tls_check_fp(MARIADB_TLS *ctls, const char *fp, const char *fp_l
|
|||||||
}
|
}
|
||||||
|
|
||||||
end:
|
end:
|
||||||
|
if (cert_fp)
|
||||||
|
free(cert_fp);
|
||||||
if (rc)
|
if (rc)
|
||||||
{
|
{
|
||||||
my_set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN,
|
my_set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN,
|
||||||
|
@@ -1696,22 +1696,18 @@ int stmt_read_execute_response(MYSQL_STMT *stmt)
|
|||||||
return(0);
|
return(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
int STDCALL mysql_stmt_execute(MYSQL_STMT *stmt)
|
|
||||||
|
int stmt_execute_send(MYSQL_STMT *stmt)
|
||||||
{
|
{
|
||||||
MYSQL *mysql= stmt->mysql;
|
MYSQL *mysql= stmt->mysql;
|
||||||
char *request;
|
char *request;
|
||||||
int ret;
|
int ret;
|
||||||
size_t request_len= 0;
|
size_t request_len= 0;
|
||||||
enum mariadb_com_multi multi= MARIADB_COM_MULTI_END;
|
|
||||||
|
|
||||||
if (!stmt->mysql)
|
if (!stmt->mysql)
|
||||||
{
|
{
|
||||||
SET_CLIENT_STMT_ERROR(stmt, CR_SERVER_LOST, SQLSTATE_UNKNOWN, 0);
|
SET_CLIENT_STMT_ERROR(stmt, CR_SERVER_LOST, SQLSTATE_UNKNOWN, 0);
|
||||||
return(1);
|
return(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
mysql_get_optionv(mysql, MARIADB_OPT_COM_MULTI, &multi);
|
|
||||||
|
|
||||||
if (stmt->state < MYSQL_STMT_PREPARED)
|
if (stmt->state < MYSQL_STMT_PREPARED)
|
||||||
{
|
{
|
||||||
SET_CLIENT_ERROR(mysql, CR_COMMANDS_OUT_OF_SYNC, SQLSTATE_UNKNOWN, 0);
|
SET_CLIENT_ERROR(mysql, CR_COMMANDS_OUT_OF_SYNC, SQLSTATE_UNKNOWN, 0);
|
||||||
@@ -1761,11 +1757,12 @@ int STDCALL mysql_stmt_execute(MYSQL_STMT *stmt)
|
|||||||
mysql->net.last_error);
|
mysql->net.last_error);
|
||||||
return(1);
|
return(1);
|
||||||
}
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (multi == MARIADB_COM_MULTI_BEGIN)
|
int STDCALL mysql_stmt_execute(MYSQL_STMT *stmt)
|
||||||
return(0);
|
{
|
||||||
|
return stmt_execute_send(stmt) || stmt_read_execute_response(stmt);
|
||||||
return(stmt_read_execute_response(stmt));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static my_bool madb_reset_stmt(MYSQL_STMT *stmt, unsigned int flags)
|
static my_bool madb_reset_stmt(MYSQL_STMT *stmt, unsigned int flags)
|
||||||
@@ -2074,7 +2071,6 @@ int STDCALL mariadb_stmt_execute_direct(MYSQL_STMT *stmt,
|
|||||||
const char *stmt_str,
|
const char *stmt_str,
|
||||||
size_t length)
|
size_t length)
|
||||||
{
|
{
|
||||||
enum mariadb_com_multi multi= MARIADB_COM_MULTI_BEGIN;
|
|
||||||
MYSQL *mysql= stmt->mysql;
|
MYSQL *mysql= stmt->mysql;
|
||||||
|
|
||||||
if (!mysql)
|
if (!mysql)
|
||||||
@@ -2083,9 +2079,6 @@ int STDCALL mariadb_stmt_execute_direct(MYSQL_STMT *stmt,
|
|||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mysql_optionsv(mysql, MARIADB_OPT_COM_MULTI, &multi))
|
|
||||||
goto fail;
|
|
||||||
|
|
||||||
if (!stmt->mysql)
|
if (!stmt->mysql)
|
||||||
{
|
{
|
||||||
SET_CLIENT_STMT_ERROR(stmt, CR_SERVER_LOST, SQLSTATE_UNKNOWN, 0);
|
SET_CLIENT_STMT_ERROR(stmt, CR_SERVER_LOST, SQLSTATE_UNKNOWN, 0);
|
||||||
@@ -2095,8 +2088,6 @@ int STDCALL mariadb_stmt_execute_direct(MYSQL_STMT *stmt,
|
|||||||
if (length == (size_t) -1)
|
if (length == (size_t) -1)
|
||||||
length= strlen(stmt_str);
|
length= strlen(stmt_str);
|
||||||
|
|
||||||
mysql_get_optionv(mysql, MARIADB_OPT_COM_MULTI, &multi);
|
|
||||||
|
|
||||||
/* clear flags */
|
/* clear flags */
|
||||||
CLEAR_CLIENT_STMT_ERROR(stmt);
|
CLEAR_CLIENT_STMT_ERROR(stmt);
|
||||||
CLEAR_CLIENT_ERROR(stmt->mysql);
|
CLEAR_CLIENT_ERROR(stmt->mysql);
|
||||||
@@ -2128,13 +2119,10 @@ int STDCALL mariadb_stmt_execute_direct(MYSQL_STMT *stmt,
|
|||||||
stmt->state= MYSQL_STMT_PREPARED;
|
stmt->state= MYSQL_STMT_PREPARED;
|
||||||
/* Since we can't determine stmt_id here, we need to set it to -1, so server will know that the
|
/* Since we can't determine stmt_id here, we need to set it to -1, so server will know that the
|
||||||
* execute command belongs to previous prepare */
|
* execute command belongs to previous prepare */
|
||||||
stmt->stmt_id= -1;
|
|
||||||
if (mysql_stmt_execute(stmt))
|
|
||||||
goto fail;
|
|
||||||
|
|
||||||
/* flush multi buffer */
|
stmt->stmt_id= -1;
|
||||||
multi= MARIADB_COM_MULTI_END;
|
ma_net_clear(&mysql->net);
|
||||||
if (mysql_optionsv(mysql, MARIADB_OPT_COM_MULTI, &multi))
|
if (stmt_execute_send(stmt))
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
/* read prepare response */
|
/* read prepare response */
|
||||||
|
@@ -21,6 +21,7 @@
|
|||||||
|
|
||||||
#include <gnutls/gnutls.h>
|
#include <gnutls/gnutls.h>
|
||||||
#include <gnutls/x509.h>
|
#include <gnutls/x509.h>
|
||||||
|
#include <gnutls/abstract.h>
|
||||||
#include <ma_global.h>
|
#include <ma_global.h>
|
||||||
#include <ma_sys.h>
|
#include <ma_sys.h>
|
||||||
#include <ma_common.h>
|
#include <ma_common.h>
|
||||||
@@ -39,6 +40,12 @@ extern unsigned int mariadb_deinitialize_ssl;
|
|||||||
|
|
||||||
static int my_verify_callback(gnutls_session_t ssl);
|
static int my_verify_callback(gnutls_session_t ssl);
|
||||||
|
|
||||||
|
struct st_gnutls_data {
|
||||||
|
MYSQL *mysql;
|
||||||
|
gnutls_privkey_t key;
|
||||||
|
gnutls_pcert_st cert;
|
||||||
|
};
|
||||||
|
|
||||||
struct st_cipher_map {
|
struct st_cipher_map {
|
||||||
const char *openssl_name;
|
const char *openssl_name;
|
||||||
const char *priority;
|
const char *priority;
|
||||||
@@ -96,6 +103,20 @@ const struct st_cipher_map gtls_ciphers[]=
|
|||||||
{NULL, NULL, 0, 0, 0}
|
{NULL, NULL, 0, 0, 0}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* free data assigned to the connection */
|
||||||
|
static void free_gnutls_data(struct st_gnutls_data *data)
|
||||||
|
{
|
||||||
|
if (data)
|
||||||
|
{
|
||||||
|
if (data->key)
|
||||||
|
gnutls_privkey_deinit(data->key);
|
||||||
|
gnutls_pcert_deinit(&data->cert);
|
||||||
|
free(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* map the gnutls cipher suite (defined by key exchange algorithm, cipher
|
||||||
|
and mac algorithm) to the corresponding OpenSSL cipher name */
|
||||||
static const char *openssl_cipher_name(gnutls_kx_algorithm_t kx,
|
static const char *openssl_cipher_name(gnutls_kx_algorithm_t kx,
|
||||||
gnutls_cipher_algorithm_t cipher,
|
gnutls_cipher_algorithm_t cipher,
|
||||||
gnutls_mac_algorithm_t mac)
|
gnutls_mac_algorithm_t mac)
|
||||||
@@ -112,6 +133,7 @@ static const char *openssl_cipher_name(gnutls_kx_algorithm_t kx,
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* get priority string for a given openssl cipher name */
|
||||||
static const char *get_priority(const char *cipher_name)
|
static const char *get_priority(const char *cipher_name)
|
||||||
{
|
{
|
||||||
unsigned int i= 0;
|
unsigned int i= 0;
|
||||||
@@ -126,7 +148,7 @@ static const char *get_priority(const char *cipher_name)
|
|||||||
|
|
||||||
#define MAX_SSL_ERR_LEN 100
|
#define MAX_SSL_ERR_LEN 100
|
||||||
|
|
||||||
static void ma_tls_set_error(MYSQL *mysql, int ssl_errno)
|
static void ma_tls_set_error(MYSQL *mysql, void *ssl, int ssl_errno)
|
||||||
{
|
{
|
||||||
char ssl_error[MAX_SSL_ERR_LEN];
|
char ssl_error[MAX_SSL_ERR_LEN];
|
||||||
const char *ssl_error_reason;
|
const char *ssl_error_reason;
|
||||||
@@ -137,6 +159,21 @@ static void ma_tls_set_error(MYSQL *mysql, int ssl_errno)
|
|||||||
pvio->set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, "Unknown SSL error");
|
pvio->set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, "Unknown SSL error");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* give a more descriptive error message for alerts */
|
||||||
|
if (ssl_errno == GNUTLS_E_FATAL_ALERT_RECEIVED)
|
||||||
|
{
|
||||||
|
gnutls_alert_description_t alert_desc;
|
||||||
|
const char *alert_name;
|
||||||
|
alert_desc= gnutls_alert_get((gnutls_session_t)ssl);
|
||||||
|
alert_name= gnutls_alert_get_name(alert_desc);
|
||||||
|
snprintf(ssl_error, MAX_SSL_ERR_LEN, "fatal alert received: %s",
|
||||||
|
alert_name);
|
||||||
|
pvio->set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, 0,
|
||||||
|
ssl_error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if ((ssl_error_reason= gnutls_strerror(ssl_errno)))
|
if ((ssl_error_reason= gnutls_strerror(ssl_errno)))
|
||||||
{
|
{
|
||||||
pvio->set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, 0,
|
pvio->set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, 0,
|
||||||
@@ -249,15 +286,7 @@ static int ma_gnutls_set_ciphers(gnutls_session_t ssl, char *cipher_str)
|
|||||||
while (token)
|
while (token)
|
||||||
{
|
{
|
||||||
const char *p= get_priority(token);
|
const char *p= get_priority(token);
|
||||||
/* if cipher was not found, we pass the original token to
|
if (p)
|
||||||
the priority string, this will allow to specify gnutls
|
|
||||||
specific settings via cipher */
|
|
||||||
if (!p)
|
|
||||||
{
|
|
||||||
strncat(prio, ":", PRIO_SIZE - strlen(prio) - 1);
|
|
||||||
strncat(prio, token, PRIO_SIZE - strlen(prio) - 1);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
strncat(prio, p, PRIO_SIZE - strlen(prio) - 1);
|
strncat(prio, p, PRIO_SIZE - strlen(prio) - 1);
|
||||||
token = strtok(NULL, ":");
|
token = strtok(NULL, ":");
|
||||||
}
|
}
|
||||||
@@ -266,8 +295,6 @@ static int ma_gnutls_set_ciphers(gnutls_session_t ssl, char *cipher_str)
|
|||||||
|
|
||||||
static int ma_tls_set_certs(MYSQL *mysql)
|
static int ma_tls_set_certs(MYSQL *mysql)
|
||||||
{
|
{
|
||||||
char *certfile= mysql->options.ssl_cert,
|
|
||||||
*keyfile= mysql->options.ssl_key;
|
|
||||||
int ssl_error= 0;
|
int ssl_error= 0;
|
||||||
|
|
||||||
if (mysql->options.ssl_ca)
|
if (mysql->options.ssl_ca)
|
||||||
@@ -282,32 +309,78 @@ static int ma_tls_set_certs(MYSQL *mysql)
|
|||||||
gnutls_certificate_set_verify_function(GNUTLS_xcred,
|
gnutls_certificate_set_verify_function(GNUTLS_xcred,
|
||||||
my_verify_callback);
|
my_verify_callback);
|
||||||
|
|
||||||
/* GNUTLS doesn't support ca_path */
|
|
||||||
|
|
||||||
if (keyfile && !certfile)
|
|
||||||
certfile= keyfile;
|
|
||||||
if (certfile && !keyfile)
|
|
||||||
keyfile= certfile;
|
|
||||||
|
|
||||||
/* set key */
|
|
||||||
if (certfile || keyfile)
|
|
||||||
{
|
|
||||||
if ((ssl_error= gnutls_certificate_set_x509_key_file2(GNUTLS_xcred,
|
|
||||||
certfile, keyfile, GNUTLS_X509_FMT_PEM,
|
|
||||||
OPT_HAS_EXT_VAL(mysql, tls_pw) ? mysql->options.extension->tls_pw : NULL,
|
|
||||||
0)) < 0)
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
return ssl_error;
|
return ssl_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
client_cert_callback(gnutls_session_t session,
|
||||||
|
const gnutls_datum_t * req_ca_rdn __attribute__((unused)),
|
||||||
|
int nreqs __attribute__((unused)),
|
||||||
|
const gnutls_pk_algorithm_t * sign_algos __attribute__((unused)),
|
||||||
|
int sign_algos_length __attribute__((unused)),
|
||||||
|
gnutls_pcert_st ** pcert,
|
||||||
|
unsigned int *pcert_length, gnutls_privkey_t * pkey)
|
||||||
|
{
|
||||||
|
struct st_gnutls_data *session_data;
|
||||||
|
char *certfile, *keyfile;
|
||||||
|
gnutls_datum_t data;
|
||||||
|
MYSQL *mysql;
|
||||||
|
gnutls_certificate_type_t type= gnutls_certificate_type_get(session);
|
||||||
|
|
||||||
|
session_data= (struct st_gnutls_data *)gnutls_session_get_ptr(session);
|
||||||
|
|
||||||
|
if (!session_data->mysql ||
|
||||||
|
type != GNUTLS_CRT_X509)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
mysql= session_data->mysql;
|
||||||
|
|
||||||
|
certfile= session_data->mysql->options.ssl_cert;
|
||||||
|
keyfile= session_data->mysql->options.ssl_key;
|
||||||
|
|
||||||
|
if (!certfile && !keyfile)
|
||||||
|
return 0;
|
||||||
|
if (keyfile && !certfile)
|
||||||
|
certfile= keyfile;
|
||||||
|
if (certfile && !keyfile)
|
||||||
|
keyfile= certfile;
|
||||||
|
|
||||||
|
if (gnutls_load_file(certfile, &data) < 0)
|
||||||
|
return -1;
|
||||||
|
if (gnutls_pcert_import_x509_raw(&session_data->cert, &data, GNUTLS_X509_FMT_PEM, 0) < 0)
|
||||||
|
{
|
||||||
|
gnutls_free(data.data);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
gnutls_free(data.data);
|
||||||
|
|
||||||
|
if (gnutls_load_file(keyfile, &data) < 0)
|
||||||
|
return -1;
|
||||||
|
gnutls_privkey_init(&session_data->key);
|
||||||
|
if (gnutls_privkey_import_x509_raw(session_data->key, &data,
|
||||||
|
GNUTLS_X509_FMT_PEM,
|
||||||
|
mysql->options.extension ? mysql->options.extension->tls_pw : NULL,
|
||||||
|
0) < 0)
|
||||||
|
{
|
||||||
|
gnutls_free(data.data);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
gnutls_free(data.data);
|
||||||
|
|
||||||
|
*pcert_length= 1;
|
||||||
|
*pcert= &session_data->cert;
|
||||||
|
*pkey= session_data->key;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
void *ma_tls_init(MYSQL *mysql)
|
void *ma_tls_init(MYSQL *mysql)
|
||||||
{
|
{
|
||||||
gnutls_session_t ssl= NULL;
|
gnutls_session_t ssl= NULL;
|
||||||
int ssl_error= 0;
|
int ssl_error= 0;
|
||||||
|
struct st_gnutls_data *data= NULL;
|
||||||
|
|
||||||
pthread_mutex_lock(&LOCK_gnutls_config);
|
pthread_mutex_lock(&LOCK_gnutls_config);
|
||||||
|
|
||||||
@@ -316,19 +389,28 @@ void *ma_tls_init(MYSQL *mysql)
|
|||||||
|
|
||||||
if ((ssl_error = gnutls_init(&ssl, GNUTLS_CLIENT & GNUTLS_NONBLOCK)) < 0)
|
if ((ssl_error = gnutls_init(&ssl, GNUTLS_CLIENT & GNUTLS_NONBLOCK)) < 0)
|
||||||
goto error;
|
goto error;
|
||||||
gnutls_session_set_ptr(ssl, (void *)mysql);
|
|
||||||
|
if (!(data= (struct st_gnutls_data *)calloc(1, sizeof(struct st_gnutls_data))))
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
data->mysql= mysql;
|
||||||
|
gnutls_certificate_set_retrieve_function2(GNUTLS_xcred, client_cert_callback);
|
||||||
|
gnutls_session_set_ptr(ssl, (void *)data);
|
||||||
|
|
||||||
ssl_error= ma_gnutls_set_ciphers(ssl, mysql->options.ssl_cipher);
|
ssl_error= ma_gnutls_set_ciphers(ssl, mysql->options.ssl_cipher);
|
||||||
if (ssl_error < 0)
|
if (ssl_error < 0)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
|
/* we don't load private key and cert by default - if the server requests
|
||||||
|
a client certificate we will send it via callback function */
|
||||||
if ((ssl_error= gnutls_credentials_set(ssl, GNUTLS_CRD_CERTIFICATE, GNUTLS_xcred)) < 0)
|
if ((ssl_error= gnutls_credentials_set(ssl, GNUTLS_CRD_CERTIFICATE, GNUTLS_xcred)) < 0)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
pthread_mutex_unlock(&LOCK_gnutls_config);
|
pthread_mutex_unlock(&LOCK_gnutls_config);
|
||||||
return (void *)ssl;
|
return (void *)ssl;
|
||||||
error:
|
error:
|
||||||
ma_tls_set_error(mysql, ssl_error);
|
free_gnutls_data(data);
|
||||||
|
ma_tls_set_error(mysql, ssl, ssl_error);
|
||||||
if (ssl)
|
if (ssl)
|
||||||
gnutls_deinit(ssl);
|
gnutls_deinit(ssl);
|
||||||
pthread_mutex_unlock(&LOCK_gnutls_config);
|
pthread_mutex_unlock(&LOCK_gnutls_config);
|
||||||
@@ -362,7 +444,9 @@ my_bool ma_tls_connect(MARIADB_TLS *ctls)
|
|||||||
MYSQL *mysql;
|
MYSQL *mysql;
|
||||||
MARIADB_PVIO *pvio;
|
MARIADB_PVIO *pvio;
|
||||||
int ret;
|
int ret;
|
||||||
mysql= (MYSQL *)gnutls_session_get_ptr(ssl);
|
struct st_gnutls_data *data;
|
||||||
|
data= (struct st_gnutls_data *)gnutls_session_get_ptr(ssl);
|
||||||
|
mysql= data->mysql;
|
||||||
|
|
||||||
if (!mysql)
|
if (!mysql)
|
||||||
return 1;
|
return 1;
|
||||||
@@ -386,16 +470,16 @@ my_bool ma_tls_connect(MARIADB_TLS *ctls)
|
|||||||
|
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
{
|
{
|
||||||
ma_tls_set_error(mysql, ret);
|
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);
|
||||||
ctls->ssl= NULL;
|
ctls->ssl= NULL;
|
||||||
if (!blocking)
|
if (!blocking)
|
||||||
pvio->methods->blocking(pvio, FALSE, 0);
|
pvio->methods->blocking(pvio, FALSE, 0);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
ctls->ssl= (void *)ssl;
|
ctls->ssl= (void *)ssl;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -413,7 +497,15 @@ my_bool ma_tls_close(MARIADB_TLS *ctls)
|
|||||||
{
|
{
|
||||||
if (ctls->ssl)
|
if (ctls->ssl)
|
||||||
{
|
{
|
||||||
gnutls_bye((gnutls_session_t )ctls->ssl, GNUTLS_SHUT_WR);
|
MARIADB_PVIO *pvio= ctls->pvio;
|
||||||
|
struct st_gnutls_data *data=
|
||||||
|
(struct st_gnutls_data *)gnutls_session_get_ptr(ctls->ssl);
|
||||||
|
/* this would be the correct way, however can't dectect afterwards
|
||||||
|
if the socket is closed or not, so we don't send encrypted
|
||||||
|
finish alert.
|
||||||
|
rc= gnutls_bye((gnutls_session_t )ctls->ssl, GNUTLS_SHUT_WR);
|
||||||
|
*/
|
||||||
|
free_gnutls_data(data);
|
||||||
gnutls_deinit((gnutls_session_t )ctls->ssl);
|
gnutls_deinit((gnutls_session_t )ctls->ssl);
|
||||||
ctls->ssl= NULL;
|
ctls->ssl= NULL;
|
||||||
}
|
}
|
||||||
@@ -443,14 +535,19 @@ 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;
|
unsigned int status= 0;
|
||||||
const gnutls_datum_t *cert_list;
|
const gnutls_datum_t *cert_list;
|
||||||
unsigned int cert_list_size;
|
unsigned int cert_list_size;
|
||||||
MYSQL *mysql= (MYSQL *)gnutls_session_get_ptr(ssl);
|
struct st_gnutls_data *data= (struct st_gnutls_data *)gnutls_session_get_ptr(ssl);
|
||||||
MARIADB_PVIO *pvio= mysql->net.pvio;
|
MYSQL *mysql;
|
||||||
|
MARIADB_PVIO *pvio;
|
||||||
|
|
||||||
gnutls_x509_crt_t cert;
|
gnutls_x509_crt_t cert;
|
||||||
const char *hostname;
|
const char *hostname;
|
||||||
|
|
||||||
|
mysql= data->mysql;
|
||||||
|
pvio= mysql->net.pvio;
|
||||||
|
|
||||||
/* read hostname */
|
/* read hostname */
|
||||||
hostname = mysql->host;
|
hostname = mysql->host;
|
||||||
|
|
||||||
@@ -518,11 +615,13 @@ unsigned int ma_tls_get_finger_print(MARIADB_TLS *ctls, char *fp, unsigned int l
|
|||||||
size_t fp_len= len;
|
size_t fp_len= len;
|
||||||
const gnutls_datum_t *cert_list;
|
const gnutls_datum_t *cert_list;
|
||||||
unsigned int cert_list_size;
|
unsigned int cert_list_size;
|
||||||
|
struct st_gnutls_data *data;
|
||||||
|
|
||||||
if (!ctls || !ctls->ssl)
|
if (!ctls || !ctls->ssl)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
mysql= (MYSQL *)gnutls_session_get_ptr(ctls->ssl);
|
data= (struct st_gnutls_data *)gnutls_session_get_ptr(ctls->ssl);
|
||||||
|
mysql= (MYSQL *)data->mysql;
|
||||||
|
|
||||||
cert_list = gnutls_certificate_get_peers (ctls->ssl, &cert_list_size);
|
cert_list = gnutls_certificate_get_peers (ctls->ssl, &cert_list_size);
|
||||||
if (cert_list == NULL)
|
if (cert_list == NULL)
|
||||||
|
@@ -78,7 +78,6 @@ void ma_schannel_set_sec_error(MARIADB_PVIO *pvio, DWORD ErrorNo)
|
|||||||
pvio->set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, "The Local Security Authority cannot be contacted");
|
pvio->set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, "The Local Security Authority cannot be contacted");
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
__debugbreak();
|
|
||||||
pvio->set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, "Unknown SSL error (0x%x)", ErrorNo);
|
pvio->set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, "Unknown SSL error (0x%x)", ErrorNo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -796,41 +795,41 @@ SECURITY_STATUS ma_schannel_read_decrypt(MARIADB_PVIO *pvio,
|
|||||||
}
|
}
|
||||||
/* }}} */
|
/* }}} */
|
||||||
|
|
||||||
my_bool ma_schannel_verify_certs(SC_CTX *sctx, DWORD dwCertFlags)
|
my_bool ma_schannel_verify_certs(SC_CTX *sctx)
|
||||||
{
|
{
|
||||||
SECURITY_STATUS sRet;
|
SECURITY_STATUS sRet;
|
||||||
DWORD flags;
|
MYSQL *mysql=sctx->mysql;
|
||||||
MARIADB_PVIO *pvio= sctx->mysql->net.pvio;
|
|
||||||
|
MARIADB_PVIO *pvio= mysql->net.pvio;
|
||||||
|
const char *ca_file= mysql->options.ssl_ca;
|
||||||
|
const char *crl_file= mysql->options.extension ? mysql->options.extension->ssl_crl : NULL;
|
||||||
PCCERT_CONTEXT pServerCert= NULL;
|
PCCERT_CONTEXT pServerCert= NULL;
|
||||||
PCCERT_CONTEXT ca_CTX = NULL;
|
CRL_CONTEXT *crl_ctx= NULL;
|
||||||
PCCRL_CONTEXT crl_CTX = NULL;
|
CERT_CONTEXT *ca_ctx= NULL;
|
||||||
my_bool is_Ok = 0;
|
int ret= 0;
|
||||||
|
|
||||||
|
if (!ca_file && !crl_file)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
if (ca_file && !(ca_ctx = ma_schannel_create_cert_context(pvio, ca_file)))
|
||||||
|
goto end;
|
||||||
|
|
||||||
|
if (crl_file && !(crl_ctx= (CRL_CONTEXT *)ma_schannel_create_crl_context(pvio, mysql->options.extension->ssl_crl)))
|
||||||
|
goto end;
|
||||||
|
|
||||||
if ((sRet= QueryContextAttributes(&sctx->ctxt, SECPKG_ATTR_REMOTE_CERT_CONTEXT, (PVOID)&pServerCert)) != SEC_E_OK)
|
if ((sRet= QueryContextAttributes(&sctx->ctxt, SECPKG_ATTR_REMOTE_CERT_CONTEXT, (PVOID)&pServerCert)) != SEC_E_OK)
|
||||||
{
|
{
|
||||||
ma_schannel_set_sec_error(pvio, sRet);
|
ma_schannel_set_sec_error(pvio, sRet);
|
||||||
return 0;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ca_Check)
|
if (ca_ctx)
|
||||||
{
|
{
|
||||||
flags = CERT_STORE_SIGNATURE_FLAG |
|
DWORD flags = CERT_STORE_SIGNATURE_FLAG | CERT_STORE_TIME_VALIDITY_FLAG;
|
||||||
CERT_STORE_TIME_VALIDITY_FLAG;
|
if (!CertVerifySubjectCertificateContext(pServerCert, ca_ctx, &flags))
|
||||||
|
|
||||||
while ((ca_CTX = CertFindCertificateInStore(ca_CertStore, PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
|
|
||||||
0, CERT_FIND_ANY, 0, ca_CTX)) && !is_Ok)
|
|
||||||
{
|
|
||||||
if (sRet = CertVerifySubjectCertificateContext(pServerCert, ca_CTX, &flags))
|
|
||||||
is_Ok = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ca_CTX)
|
|
||||||
CertFreeCertificateContext(ca_CTX);
|
|
||||||
|
|
||||||
if (!is_Ok)
|
|
||||||
{
|
{
|
||||||
ma_schannel_set_win_error(pvio);
|
ma_schannel_set_win_error(pvio);
|
||||||
return 0;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (flags)
|
if (flags)
|
||||||
@@ -843,30 +842,36 @@ my_bool ma_schannel_verify_certs(SC_CTX *sctx, DWORD dwCertFlags)
|
|||||||
pvio->set_error(sctx->mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, "SSL connection error: certificate has expired");
|
pvio->set_error(sctx->mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, "SSL connection error: certificate has expired");
|
||||||
else
|
else
|
||||||
pvio->set_error(sctx->mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, "SSL connection error: Unknown error during certificate validation");
|
pvio->set_error(sctx->mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, "SSL connection error: Unknown error during certificate validation");
|
||||||
return 0;
|
goto end;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check if none of the certificates in the certificate chain have been revoked. */
|
|
||||||
if (crl_Check)
|
|
||||||
{
|
|
||||||
while ((crl_CTX = CertEnumCRLsInStore(crl_CertStore, crl_CTX)))
|
|
||||||
{
|
|
||||||
PCRL_INFO Info[1];
|
|
||||||
|
|
||||||
Info[0] = crl_CTX->pCrlInfo;
|
/* Check certificates in the certificate chain have been revoked. */
|
||||||
if (!(CertVerifyCRLRevocation(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
|
if (crl_ctx)
|
||||||
pServerCert->pCertInfo,
|
|
||||||
1, Info)))
|
|
||||||
{
|
{
|
||||||
CertFreeCRLContext(crl_CTX);
|
if (!CertVerifyCRLRevocation(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, pServerCert->pCertInfo, 1, &crl_ctx->pCrlInfo))
|
||||||
pvio->set_error(pvio->mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, "CRL Revocation failed");
|
{
|
||||||
return 0;
|
pvio->set_error(pvio->mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, "SSL connection error: CRL Revocation test failed");
|
||||||
|
goto end;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
CertFreeCRLContext(crl_CTX);
|
ret= 1;
|
||||||
|
|
||||||
|
end:
|
||||||
|
if (crl_ctx)
|
||||||
|
{
|
||||||
|
CertFreeCRLContext(crl_ctx);
|
||||||
}
|
}
|
||||||
return 1;
|
if (ca_ctx)
|
||||||
|
{
|
||||||
|
CertFreeCertificateContext(ca_ctx);
|
||||||
|
}
|
||||||
|
if (pServerCert)
|
||||||
|
{
|
||||||
|
CertFreeCertificateContext(pServerCert);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@@ -68,7 +68,7 @@ SECURITY_STATUS ma_schannel_client_handshake(MARIADB_TLS *ctls);
|
|||||||
SECURITY_STATUS ma_schannel_handshake_loop(MARIADB_PVIO *pvio, my_bool InitialRead, SecBuffer *pExtraData);
|
SECURITY_STATUS ma_schannel_handshake_loop(MARIADB_PVIO *pvio, my_bool InitialRead, SecBuffer *pExtraData);
|
||||||
my_bool ma_schannel_load_private_key(MARIADB_PVIO *pvio, CERT_CONTEXT *ctx, char *key_file);
|
my_bool ma_schannel_load_private_key(MARIADB_PVIO *pvio, CERT_CONTEXT *ctx, char *key_file);
|
||||||
PCCRL_CONTEXT ma_schannel_create_crl_context(MARIADB_PVIO *pvio, const char *pem_file);
|
PCCRL_CONTEXT ma_schannel_create_crl_context(MARIADB_PVIO *pvio, const char *pem_file);
|
||||||
my_bool ma_schannel_verify_certs(SC_CTX *sctx, DWORD dwCertFlags);
|
my_bool ma_schannel_verify_certs(SC_CTX *sctx);
|
||||||
size_t ma_schannel_write_encrypt(MARIADB_PVIO *pvio,
|
size_t ma_schannel_write_encrypt(MARIADB_PVIO *pvio,
|
||||||
uchar *WriteBuffer,
|
uchar *WriteBuffer,
|
||||||
size_t WriteBufferSize);
|
size_t WriteBufferSize);
|
||||||
|
@@ -30,7 +30,12 @@
|
|||||||
#include <openssl/conf.h>
|
#include <openssl/conf.h>
|
||||||
#include <openssl/md4.h>
|
#include <openssl/md4.h>
|
||||||
|
|
||||||
#define HAVE_TLS_SESSION_CACHE 1
|
#ifdef HAVE_TLS_SESSION_CACHE
|
||||||
|
#undef HAVE_TLS_SESSION_CACHE
|
||||||
|
#endif
|
||||||
|
#if OPENSSL_USE_BIOMETHOD
|
||||||
|
#undef OPENSSL_USE_BIOMETHOD
|
||||||
|
#endif
|
||||||
#ifndef HAVE_OPENSSL_DEFAULT
|
#ifndef HAVE_OPENSSL_DEFAULT
|
||||||
#include <memory.h>
|
#include <memory.h>
|
||||||
#define ma_malloc(A,B) malloc((A))
|
#define ma_malloc(A,B) malloc((A))
|
||||||
@@ -329,6 +334,7 @@ int ma_tls_start(char *errmsg, size_t errmsg_len)
|
|||||||
ma_tls_get_error(errmsg, errmsg_len);
|
ma_tls_get_error(errmsg, errmsg_len);
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
SSL_CTX_set_options(SSL_context, SSL_OP_ALL);
|
||||||
#ifdef HAVE_TLS_SESSION_CACHE
|
#ifdef HAVE_TLS_SESSION_CACHE
|
||||||
SSL_CTX_set_session_cache_mode(SSL_context, SSL_SESS_CACHE_CLIENT);
|
SSL_CTX_set_session_cache_mode(SSL_context, SSL_SESS_CACHE_CLIENT);
|
||||||
ma_tls_sessions= (MA_SSL_SESSION *)calloc(1, sizeof(struct st_ma_tls_session) * ma_tls_session_cache_size);
|
ma_tls_sessions= (MA_SSL_SESSION *)calloc(1, sizeof(struct st_ma_tls_session) * ma_tls_session_cache_size);
|
||||||
@@ -411,15 +417,18 @@ int ma_tls_get_password(char *buf, int size,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int ma_tls_set_certs(MYSQL *mysql)
|
static int ma_tls_set_certs(MYSQL *mysql, SSL *ssl)
|
||||||
{
|
{
|
||||||
char *certfile= mysql->options.ssl_cert,
|
char *certfile= mysql->options.ssl_cert,
|
||||||
*keyfile= mysql->options.ssl_key;
|
*keyfile= mysql->options.ssl_key;
|
||||||
|
char *pw= (mysql->options.extension) ?
|
||||||
|
mysql->options.extension->tls_pw : NULL;
|
||||||
|
|
||||||
|
|
||||||
/* add cipher */
|
/* add cipher */
|
||||||
if ((mysql->options.ssl_cipher &&
|
if ((mysql->options.ssl_cipher &&
|
||||||
mysql->options.ssl_cipher[0] != 0) &&
|
mysql->options.ssl_cipher[0] != 0) &&
|
||||||
SSL_CTX_set_cipher_list(SSL_context, mysql->options.ssl_cipher) == 0)
|
SSL_set_cipher_list(ssl, mysql->options.ssl_cipher) == 0)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
/* ca_file and ca_path */
|
/* ca_file and ca_path */
|
||||||
@@ -440,34 +449,36 @@ static int ma_tls_set_certs(MYSQL *mysql)
|
|||||||
|
|
||||||
/* set cert */
|
/* set cert */
|
||||||
if (certfile && certfile[0] != 0)
|
if (certfile && certfile[0] != 0)
|
||||||
if (SSL_CTX_use_certificate_file(SSL_context, certfile, SSL_FILETYPE_PEM) != 1)
|
|
||||||
goto error;
|
|
||||||
|
|
||||||
/* If the private key file is encrypted, we need to register a callback function
|
|
||||||
* for providing password. */
|
|
||||||
if (OPT_HAS_EXT_VAL(mysql, tls_pw))
|
|
||||||
{
|
{
|
||||||
SSL_CTX_set_default_passwd_cb_userdata(SSL_context, (void *)mysql->options.extension->tls_pw);
|
if (SSL_CTX_use_certificate_chain_file(SSL_context, certfile) != 1 ||
|
||||||
SSL_CTX_set_default_passwd_cb(SSL_context, ma_tls_get_password);
|
SSL_use_certificate_file(ssl, certfile, SSL_FILETYPE_PEM) != 1)
|
||||||
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (keyfile && keyfile[0])
|
if (keyfile && keyfile[0])
|
||||||
{
|
{
|
||||||
if (SSL_CTX_use_PrivateKey_file(SSL_context, keyfile, SSL_FILETYPE_PEM) != 1)
|
FILE *fp;
|
||||||
|
if ((fp= fopen(keyfile, "rb")))
|
||||||
|
{
|
||||||
|
EVP_PKEY *key= EVP_PKEY_new();
|
||||||
|
PEM_read_PrivateKey(fp, &key, NULL, pw);
|
||||||
|
fclose(fp);
|
||||||
|
if (SSL_use_PrivateKey(ssl, key) != 1)
|
||||||
{
|
{
|
||||||
unsigned long err= ERR_peek_error();
|
unsigned long err= ERR_peek_error();
|
||||||
|
EVP_PKEY_free(key);
|
||||||
if (!(ERR_GET_LIB(err) == ERR_LIB_X509 &&
|
if (!(ERR_GET_LIB(err) == ERR_LIB_X509 &&
|
||||||
ERR_GET_REASON(err) == X509_R_CERT_ALREADY_IN_HASH_TABLE))
|
ERR_GET_REASON(err) == X509_R_CERT_ALREADY_IN_HASH_TABLE))
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
EVP_PKEY_free(key);
|
||||||
|
} else {
|
||||||
|
my_set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN,
|
||||||
|
CER(CR_FILE_NOT_FOUND), keyfile);
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
if (OPT_HAS_EXT_VAL(mysql, tls_pw))
|
|
||||||
{
|
|
||||||
SSL_CTX_set_default_passwd_cb_userdata(SSL_context, NULL);
|
|
||||||
SSL_CTX_set_default_passwd_cb(SSL_context, NULL);
|
|
||||||
}
|
}
|
||||||
/* verify key */
|
/* verify key */
|
||||||
if (certfile && !SSL_CTX_check_private_key(SSL_context))
|
if (certfile && !SSL_check_private_key(ssl))
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
if (mysql->options.extension &&
|
if (mysql->options.extension &&
|
||||||
@@ -499,14 +510,14 @@ void *ma_tls_init(MYSQL *mysql)
|
|||||||
#endif
|
#endif
|
||||||
pthread_mutex_lock(&LOCK_openssl_config);
|
pthread_mutex_lock(&LOCK_openssl_config);
|
||||||
|
|
||||||
if (ma_tls_set_certs(mysql))
|
if (!(ssl= SSL_new(SSL_context)))
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
if (ma_tls_set_certs(mysql, ssl))
|
||||||
{
|
{
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(ssl= SSL_new(SSL_context)))
|
|
||||||
goto error;
|
|
||||||
|
|
||||||
if (!SSL_set_app_data(ssl, mysql))
|
if (!SSL_set_app_data(ssl, mysql))
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
@@ -703,8 +714,7 @@ const char *ma_tls_get_cipher(MARIADB_TLS *ctls)
|
|||||||
|
|
||||||
unsigned int ma_tls_get_finger_print(MARIADB_TLS *ctls, char *fp, unsigned int len)
|
unsigned int ma_tls_get_finger_print(MARIADB_TLS *ctls, char *fp, unsigned int len)
|
||||||
{
|
{
|
||||||
EVP_MD *digest= (EVP_MD *)EVP_sha1();
|
X509 *cert= NULL;
|
||||||
X509 *cert;
|
|
||||||
MYSQL *mysql;
|
MYSQL *mysql;
|
||||||
unsigned int fp_len;
|
unsigned int fp_len;
|
||||||
|
|
||||||
@@ -718,7 +728,7 @@ unsigned int ma_tls_get_finger_print(MARIADB_TLS *ctls, char *fp, unsigned int l
|
|||||||
my_set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN,
|
my_set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN,
|
||||||
ER(CR_SSL_CONNECTION_ERROR),
|
ER(CR_SSL_CONNECTION_ERROR),
|
||||||
"Unable to get server certificate");
|
"Unable to get server certificate");
|
||||||
return 0;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (len < EVP_MAX_MD_SIZE)
|
if (len < EVP_MAX_MD_SIZE)
|
||||||
@@ -726,18 +736,21 @@ unsigned int ma_tls_get_finger_print(MARIADB_TLS *ctls, char *fp, unsigned int l
|
|||||||
my_set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN,
|
my_set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN,
|
||||||
ER(CR_SSL_CONNECTION_ERROR),
|
ER(CR_SSL_CONNECTION_ERROR),
|
||||||
"Finger print buffer too small");
|
"Finger print buffer too small");
|
||||||
return 0;
|
goto end;
|
||||||
}
|
}
|
||||||
fp_len= len;
|
if (!X509_digest(cert, EVP_sha1(), (unsigned char *)fp, &fp_len))
|
||||||
if (!X509_digest(cert, digest, (unsigned char *)fp, &fp_len))
|
|
||||||
{
|
{
|
||||||
ma_free(fp);
|
|
||||||
my_set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN,
|
my_set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN,
|
||||||
ER(CR_SSL_CONNECTION_ERROR),
|
ER(CR_SSL_CONNECTION_ERROR),
|
||||||
"invalid finger print of server certificate");
|
"invalid finger print of server certificate");
|
||||||
return 0;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
X509_free(cert);
|
||||||
return (fp_len);
|
return (fp_len);
|
||||||
|
end:
|
||||||
|
X509_free(cert);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@@ -26,9 +26,6 @@
|
|||||||
|
|
||||||
extern my_bool ma_tls_initialized;
|
extern my_bool ma_tls_initialized;
|
||||||
|
|
||||||
static pthread_mutex_t LOCK_schannel_config;
|
|
||||||
static pthread_mutex_t *LOCK_crypto= NULL;
|
|
||||||
|
|
||||||
struct st_cipher_suite {
|
struct st_cipher_suite {
|
||||||
DWORD aid;
|
DWORD aid;
|
||||||
CHAR *cipher;
|
CHAR *cipher;
|
||||||
@@ -81,17 +78,6 @@ const struct st_cipher_suite valid_ciphers[] =
|
|||||||
void ma_schannel_set_sec_error(MARIADB_PVIO *pvio, DWORD ErrorNo);
|
void ma_schannel_set_sec_error(MARIADB_PVIO *pvio, DWORD ErrorNo);
|
||||||
void ma_schannel_set_win_error(MYSQL *mysql);
|
void ma_schannel_set_win_error(MYSQL *mysql);
|
||||||
|
|
||||||
HCERTSTORE ca_CertStore= NULL,
|
|
||||||
crl_CertStore= NULL;
|
|
||||||
my_bool ca_Check = 1, crl_Check = 0;
|
|
||||||
|
|
||||||
|
|
||||||
static int ssl_thread_init()
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Initializes SSL and allocate global
|
Initializes SSL and allocate global
|
||||||
context SSL_context
|
context SSL_context
|
||||||
@@ -105,23 +91,8 @@ static int ssl_thread_init()
|
|||||||
*/
|
*/
|
||||||
int ma_tls_start(char *errmsg, size_t errmsg_len)
|
int ma_tls_start(char *errmsg, size_t errmsg_len)
|
||||||
{
|
{
|
||||||
if (!ma_tls_initialized)
|
|
||||||
{
|
|
||||||
pthread_mutex_init(&LOCK_schannel_config,MY_MUTEX_INIT_FAST);
|
|
||||||
pthread_mutex_lock(&LOCK_schannel_config);
|
|
||||||
if (!ca_CertStore)
|
|
||||||
{
|
|
||||||
if (!(ca_CertStore = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0, 0, NULL)) ||
|
|
||||||
!(crl_CertStore = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0, 0, NULL)))
|
|
||||||
{
|
|
||||||
snprintf(errmsg, errmsg_len, "Can't open in-memory certstore. Error=%d", GetLastError());
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
ma_tls_initialized = TRUE;
|
ma_tls_initialized = TRUE;
|
||||||
pthread_mutex_unlock(&LOCK_schannel_config);
|
|
||||||
}
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -139,23 +110,6 @@ int ma_tls_start(char *errmsg, size_t errmsg_len)
|
|||||||
*/
|
*/
|
||||||
void ma_tls_end()
|
void ma_tls_end()
|
||||||
{
|
{
|
||||||
if (ma_tls_initialized)
|
|
||||||
{
|
|
||||||
pthread_mutex_lock(&LOCK_schannel_config);
|
|
||||||
if (ca_CertStore)
|
|
||||||
{
|
|
||||||
CertCloseStore(ca_CertStore, 0);
|
|
||||||
ca_CertStore = 0;
|
|
||||||
}
|
|
||||||
if (crl_CertStore)
|
|
||||||
{
|
|
||||||
CertCloseStore(crl_CertStore, 0);
|
|
||||||
crl_CertStore = 0;
|
|
||||||
}
|
|
||||||
ma_tls_initialized= FALSE;
|
|
||||||
pthread_mutex_unlock(&LOCK_schannel_config);
|
|
||||||
pthread_mutex_destroy(&LOCK_schannel_config);
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -164,69 +118,30 @@ static int ma_tls_set_client_certs(MARIADB_TLS *ctls)
|
|||||||
{
|
{
|
||||||
MYSQL *mysql= ctls->pvio->mysql;
|
MYSQL *mysql= ctls->pvio->mysql;
|
||||||
char *certfile= mysql->options.ssl_cert,
|
char *certfile= mysql->options.ssl_cert,
|
||||||
*keyfile= mysql->options.ssl_key,
|
*keyfile= mysql->options.ssl_key;
|
||||||
*cafile= mysql->options.ssl_ca;
|
|
||||||
PCERT_CONTEXT ca_ctx= NULL;
|
|
||||||
PCRL_CONTEXT crl_ctx = NULL;
|
|
||||||
|
|
||||||
SC_CTX *sctx= (SC_CTX *)ctls->ssl;
|
SC_CTX *sctx= (SC_CTX *)ctls->ssl;
|
||||||
MARIADB_PVIO *pvio= ctls->pvio;
|
MARIADB_PVIO *pvio= ctls->pvio;
|
||||||
|
|
||||||
if (cafile)
|
sctx->client_cert_ctx= NULL;
|
||||||
{
|
|
||||||
if (!(ca_ctx = ma_schannel_create_cert_context(pvio, cafile)))
|
|
||||||
goto end;
|
|
||||||
|
|
||||||
/* Add ca to in-memory certificate store */
|
|
||||||
if (CertAddCertificateContextToStore(ca_CertStore, ca_ctx, CERT_STORE_ADD_NEWER, NULL) != TRUE &&
|
|
||||||
GetLastError() != CRYPT_E_EXISTS)
|
|
||||||
{
|
|
||||||
ma_schannel_set_win_error(sctx->mysql);
|
|
||||||
goto end;
|
|
||||||
}
|
|
||||||
CertFreeCertificateContext(ca_ctx);
|
|
||||||
ca_ctx = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!certfile && keyfile)
|
if (!certfile && keyfile)
|
||||||
certfile= keyfile;
|
certfile= keyfile;
|
||||||
if (!keyfile && certfile)
|
if (!keyfile && certfile)
|
||||||
keyfile= certfile;
|
keyfile= certfile;
|
||||||
|
|
||||||
if (certfile)
|
if (!certfile)
|
||||||
if (!(sctx->client_cert_ctx = ma_schannel_create_cert_context(ctls->pvio, certfile)))
|
|
||||||
goto end;
|
|
||||||
|
|
||||||
if (sctx->client_cert_ctx && keyfile)
|
|
||||||
if (!ma_schannel_load_private_key(pvio, sctx->client_cert_ctx, keyfile))
|
|
||||||
goto end;
|
|
||||||
|
|
||||||
if (mysql->options.extension && mysql->options.extension->ssl_crl)
|
|
||||||
{
|
|
||||||
if (!(crl_ctx= (CRL_CONTEXT *)ma_schannel_create_crl_context(pvio, mysql->options.extension->ssl_crl)))
|
|
||||||
goto end;
|
|
||||||
/* Add ca to in-memory certificate store */
|
|
||||||
if (CertAddCRLContextToStore(crl_CertStore, crl_ctx, CERT_STORE_ADD_NEWER, NULL) != TRUE &&
|
|
||||||
GetLastError() != CRYPT_E_EXISTS)
|
|
||||||
{
|
|
||||||
ma_schannel_set_win_error(sctx->mysql);
|
|
||||||
goto end;
|
|
||||||
}
|
|
||||||
crl_Check = 1;
|
|
||||||
CertFreeCertificateContext(ca_ctx);
|
|
||||||
ca_ctx = NULL;
|
|
||||||
}
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
end:
|
if (!(sctx->client_cert_ctx = ma_schannel_create_cert_context(ctls->pvio, certfile)))
|
||||||
if (ca_ctx)
|
return 1;
|
||||||
CertFreeCertificateContext(ca_ctx);
|
|
||||||
if (sctx->client_cert_ctx)
|
if (!ma_schannel_load_private_key(pvio, sctx->client_cert_ctx, keyfile))
|
||||||
|
{
|
||||||
CertFreeCertificateContext(sctx->client_cert_ctx);
|
CertFreeCertificateContext(sctx->client_cert_ctx);
|
||||||
if (crl_ctx)
|
|
||||||
CertFreeCRLContext(crl_ctx);
|
|
||||||
sctx->client_cert_ctx= NULL;
|
sctx->client_cert_ctx= NULL;
|
||||||
return 1;
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
/* }}} */
|
/* }}} */
|
||||||
|
|
||||||
@@ -234,16 +149,11 @@ end:
|
|||||||
void *ma_tls_init(MYSQL *mysql)
|
void *ma_tls_init(MYSQL *mysql)
|
||||||
{
|
{
|
||||||
SC_CTX *sctx= NULL;
|
SC_CTX *sctx= NULL;
|
||||||
|
|
||||||
pthread_mutex_lock(&LOCK_schannel_config);
|
|
||||||
|
|
||||||
if ((sctx= (SC_CTX *)LocalAlloc(0, sizeof(SC_CTX))))
|
if ((sctx= (SC_CTX *)LocalAlloc(0, sizeof(SC_CTX))))
|
||||||
{
|
{
|
||||||
ZeroMemory(sctx, sizeof(SC_CTX));
|
ZeroMemory(sctx, sizeof(SC_CTX));
|
||||||
sctx->mysql= mysql;
|
sctx->mysql= mysql;
|
||||||
}
|
}
|
||||||
|
|
||||||
pthread_mutex_unlock(&LOCK_schannel_config);
|
|
||||||
return sctx;
|
return sctx;
|
||||||
}
|
}
|
||||||
/* }}} */
|
/* }}} */
|
||||||
@@ -305,8 +215,6 @@ my_bool ma_tls_connect(MARIADB_TLS *ctls)
|
|||||||
my_bool rc= 1;
|
my_bool rc= 1;
|
||||||
SC_CTX *sctx;
|
SC_CTX *sctx;
|
||||||
SECURITY_STATUS sRet;
|
SECURITY_STATUS sRet;
|
||||||
PCCERT_CONTEXT pRemoteCertContext= NULL,
|
|
||||||
pLocalCertContext= NULL;
|
|
||||||
ALG_ID AlgId[MAX_ALG_ID];
|
ALG_ID AlgId[MAX_ALG_ID];
|
||||||
WORD validTokens = 0;
|
WORD validTokens = 0;
|
||||||
|
|
||||||
@@ -376,21 +284,14 @@ my_bool ma_tls_connect(MARIADB_TLS *ctls)
|
|||||||
if (ma_schannel_client_handshake(ctls) != SEC_E_OK)
|
if (ma_schannel_client_handshake(ctls) != SEC_E_OK)
|
||||||
goto end;
|
goto end;
|
||||||
|
|
||||||
sRet= QueryContextAttributes(&sctx->ctxt, SECPKG_ATTR_REMOTE_CERT_CONTEXT, (PVOID)&pRemoteCertContext);
|
|
||||||
if (sRet != SEC_E_OK)
|
|
||||||
{
|
|
||||||
ma_schannel_set_sec_error(pvio, sRet);
|
|
||||||
goto end;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mysql->options.ssl_ca && !ma_schannel_verify_certs(sctx, 0))
|
if (!ma_schannel_verify_certs(sctx))
|
||||||
goto end;
|
goto end;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
end:
|
end:
|
||||||
if (pRemoteCertContext)
|
|
||||||
CertFreeCertificateContext(pRemoteCertContext);
|
|
||||||
if (rc && sctx->IoBufferSize)
|
if (rc && sctx->IoBufferSize)
|
||||||
LocalFree(sctx->IoBuffer);
|
LocalFree(sctx->IoBuffer);
|
||||||
sctx->IoBufferSize= 0;
|
sctx->IoBufferSize= 0;
|
||||||
@@ -453,11 +354,11 @@ int ma_tls_verify_server_cert(MARIADB_TLS *ctls)
|
|||||||
int rc= 1;
|
int rc= 1;
|
||||||
char *szName= NULL;
|
char *szName= NULL;
|
||||||
char *pszServerName= pvio->mysql->host;
|
char *pszServerName= pvio->mysql->host;
|
||||||
|
PCCERT_CONTEXT pServerCert= NULL;
|
||||||
|
|
||||||
/* check server name */
|
/* check server name */
|
||||||
if (pszServerName && (sctx->mysql->client_flag & CLIENT_SSL_VERIFY_SERVER_CERT))
|
if (pszServerName && (sctx->mysql->client_flag & CLIENT_SSL_VERIFY_SERVER_CERT))
|
||||||
{
|
{
|
||||||
PCCERT_CONTEXT pServerCert;
|
|
||||||
DWORD NameSize= 0;
|
DWORD NameSize= 0;
|
||||||
char *p1, *p2;
|
char *p1, *p2;
|
||||||
SECURITY_STATUS sRet;
|
SECURITY_STATUS sRet;
|
||||||
@@ -465,7 +366,7 @@ int ma_tls_verify_server_cert(MARIADB_TLS *ctls)
|
|||||||
if ((sRet= QueryContextAttributes(&sctx->ctxt, SECPKG_ATTR_REMOTE_CERT_CONTEXT, (PVOID)&pServerCert)) != SEC_E_OK)
|
if ((sRet= QueryContextAttributes(&sctx->ctxt, SECPKG_ATTR_REMOTE_CERT_CONTEXT, (PVOID)&pServerCert)) != SEC_E_OK)
|
||||||
{
|
{
|
||||||
ma_schannel_set_sec_error(pvio, sRet);
|
ma_schannel_set_sec_error(pvio, sRet);
|
||||||
return 1;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(NameSize= CertNameToStr(pServerCert->dwCertEncodingType,
|
if (!(NameSize= CertNameToStr(pServerCert->dwCertEncodingType,
|
||||||
@@ -473,8 +374,8 @@ int ma_tls_verify_server_cert(MARIADB_TLS *ctls)
|
|||||||
CERT_X500_NAME_STR | CERT_NAME_STR_NO_PLUS_FLAG,
|
CERT_X500_NAME_STR | CERT_NAME_STR_NO_PLUS_FLAG,
|
||||||
NULL, 0)))
|
NULL, 0)))
|
||||||
{
|
{
|
||||||
pvio->set_error(sctx->mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, "Can't retrieve name of server certificate");
|
pvio->set_error(sctx->mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, "SSL connection error: Can't retrieve name of server certificate");
|
||||||
return 1;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(szName= (char *)LocalAlloc(0, NameSize + 1)))
|
if (!(szName= (char *)LocalAlloc(0, NameSize + 1)))
|
||||||
@@ -488,7 +389,7 @@ int ma_tls_verify_server_cert(MARIADB_TLS *ctls)
|
|||||||
CERT_X500_NAME_STR | CERT_NAME_STR_NO_PLUS_FLAG,
|
CERT_X500_NAME_STR | CERT_NAME_STR_NO_PLUS_FLAG,
|
||||||
szName, NameSize))
|
szName, NameSize))
|
||||||
{
|
{
|
||||||
pvio->set_error(sctx->mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, "Can't retrieve name of server certificate");
|
pvio->set_error(sctx->mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, "SSL connection error: Can't retrieve name of server certificate");
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
if ((p1 = strstr(szName, "CN=")))
|
if ((p1 = strstr(szName, "CN=")))
|
||||||
@@ -502,12 +403,14 @@ int ma_tls_verify_server_cert(MARIADB_TLS *ctls)
|
|||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
pvio->set_error(pvio->mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN,
|
pvio->set_error(pvio->mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN,
|
||||||
"Name of server certificate didn't match");
|
"SSL connection error: Name of server certificate didn't match");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
end:
|
end:
|
||||||
if (szName)
|
if (szName)
|
||||||
LocalFree(szName);
|
LocalFree(szName);
|
||||||
|
if (pServerCert)
|
||||||
|
CertFreeCertificateContext(pServerCert);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -543,5 +446,6 @@ unsigned int ma_tls_get_finger_print(MARIADB_TLS *ctls, char *fp, unsigned int l
|
|||||||
if (QueryContextAttributes(&sctx->ctxt, SECPKG_ATTR_REMOTE_CERT_CONTEXT, (PVOID)&pRemoteCertContext) != SEC_E_OK)
|
if (QueryContextAttributes(&sctx->ctxt, SECPKG_ATTR_REMOTE_CERT_CONTEXT, (PVOID)&pRemoteCertContext) != SEC_E_OK)
|
||||||
return 0;
|
return 0;
|
||||||
CertGetCertificateContextProperty(pRemoteCertContext, CERT_HASH_PROP_ID, fp, (DWORD *)&len);
|
CertGetCertificateContextProperty(pRemoteCertContext, CERT_HASH_PROP_ID, fp, (DWORD *)&len);
|
||||||
|
CertFreeCertificateContext(pRemoteCertContext);
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
@@ -238,7 +238,7 @@ int pvio_shm_fast_send(MARIADB_PVIO *pvio)
|
|||||||
|
|
||||||
my_bool pvio_shm_connect(MARIADB_PVIO *pvio, MA_PVIO_CINFO *cinfo)
|
my_bool pvio_shm_connect(MARIADB_PVIO *pvio, MA_PVIO_CINFO *cinfo)
|
||||||
{
|
{
|
||||||
char *base_memory_name;
|
const char *base_memory_name;
|
||||||
char *prefixes[]= {"", "Global\\", NULL};
|
char *prefixes[]= {"", "Global\\", NULL};
|
||||||
char *shm_name, *shm_suffix, *shm_prefix;
|
char *shm_name, *shm_suffix, *shm_prefix;
|
||||||
uchar i= 0;
|
uchar i= 0;
|
||||||
@@ -453,16 +453,16 @@ my_bool pvio_shm_is_alive(MARIADB_PVIO *pvio)
|
|||||||
if (!pvio || !pvio->data)
|
if (!pvio || !pvio->data)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
pvio_shm= (PVIO_SHM *)pvio->data;
|
pvio_shm= (PVIO_SHM *)pvio->data;
|
||||||
return WaitForSingleObject(pvio_shm->event[PVIO_SHM_CONNECTION_CLOSED], 0);
|
return WaitForSingleObject(pvio_shm->event[PVIO_SHM_CONNECTION_CLOSED], 0)!=WAIT_OBJECT_0;
|
||||||
}
|
}
|
||||||
|
|
||||||
my_bool pvio_shm_get_handle(MARIADB_PVIO *pvio, void *handle)
|
my_bool pvio_shm_get_handle(MARIADB_PVIO *pvio, void *handle)
|
||||||
{
|
{
|
||||||
PVIO_SHM *pvio_shm;
|
|
||||||
*(HANDLE **)handle= 0;
|
*(HANDLE **)handle= 0;
|
||||||
if (!pvio || !pvio->data)
|
if (!pvio || !pvio->data)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
*(HANDLE **)handle= (HANDLE **)((PVIO_SHM*)pvio->data)->event;
|
*(HANDLE **)handle= ((PVIO_SHM*)pvio->data)->event;
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@@ -60,13 +60,13 @@ IF(WITH_SSL)
|
|||||||
STRING(REPLACE "SHA1 Fingerprint=" "" FINGER_PRINT "${FINGER_PRINT}")
|
STRING(REPLACE "SHA1 Fingerprint=" "" FINGER_PRINT "${FINGER_PRINT}")
|
||||||
STRING(REPLACE "\n" "" FINGER_PRINT "${FINGER_PRINT}")
|
STRING(REPLACE "\n" "" FINGER_PRINT "${FINGER_PRINT}")
|
||||||
STRING(REPLACE ":" "" SSL_CERT_FINGER_PRINT "${FINGER_PRINT}")
|
STRING(REPLACE ":" "" SSL_CERT_FINGER_PRINT "${FINGER_PRINT}")
|
||||||
|
|
||||||
ENDIF()
|
|
||||||
CONFIGURE_FILE(${CC_SOURCE_DIR}/unittest/libmariadb/ssl.c.in
|
|
||||||
${CC_BINARY_DIR}/unittest/libmariadb/ssl.c)
|
|
||||||
CONFIGURE_FILE(${CC_SOURCE_DIR}/unittest/libmariadb/fingerprint.list.in
|
CONFIGURE_FILE(${CC_SOURCE_DIR}/unittest/libmariadb/fingerprint.list.in
|
||||||
${CC_BINARY_DIR}/unittest/libmariadb/fingerprint.list)
|
${CC_BINARY_DIR}/unittest/libmariadb/fingerprint.list)
|
||||||
|
|
||||||
|
ENDIF()
|
||||||
SET(API_TESTS ${API_TESTS} "ssl")
|
SET(API_TESTS ${API_TESTS} "ssl")
|
||||||
|
CONFIGURE_FILE(${CC_SOURCE_DIR}/unittest/libmariadb/ssl.c.in
|
||||||
|
${CC_BINARY_DIR}/unittest/libmariadb/ssl.c)
|
||||||
ADD_EXECUTABLE(ssl ${CC_BINARY_DIR}/unittest/libmariadb/ssl.c)
|
ADD_EXECUTABLE(ssl ${CC_BINARY_DIR}/unittest/libmariadb/ssl.c)
|
||||||
ENDIF()
|
ENDIF()
|
||||||
|
|
||||||
|
@@ -26,8 +26,7 @@ char *rand_str(size_t length) {
|
|||||||
char *dest= (char *)malloc(length+1);
|
char *dest= (char *)malloc(length+1);
|
||||||
char *p= dest;
|
char *p= dest;
|
||||||
while (length-- > 0) {
|
while (length-- > 0) {
|
||||||
size_t index = (double) rand() / RAND_MAX * (sizeof charset - 1);
|
*dest++ = charset[rand() % sizeof(charset)];
|
||||||
*dest++ = charset[index];
|
|
||||||
}
|
}
|
||||||
*dest = '\0';
|
*dest = '\0';
|
||||||
return p;
|
return p;
|
||||||
|
@@ -556,6 +556,5 @@ void run_tests(struct my_tests_st *test) {
|
|||||||
diag("close default");
|
diag("close default");
|
||||||
mysql_close(mysql_default);
|
mysql_close(mysql_default);
|
||||||
}
|
}
|
||||||
mysql_server_end();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -173,9 +173,9 @@ static int test_conc95(MYSQL *unused __attribute__((unused)))
|
|||||||
|
|
||||||
mysql= mysql_init(NULL);
|
mysql= mysql_init(NULL);
|
||||||
mysql_ssl_set(mysql,
|
mysql_ssl_set(mysql,
|
||||||
"@CMAKE_SOURCE_DIR@/unittest/libmariadb/certs/server-key.pem",
|
"@CMAKE_SOURCE_DIR@/unittest/libmariadb/certs/client-key.pem",
|
||||||
"@CMAKE_SOURCE_DIR@/unittest/libmariadb/certs/server-cert.pem",
|
"@CMAKE_SOURCE_DIR@/unittest/libmariadb/certs/client-cert.pem",
|
||||||
"@CMAKE_SOURCE_DIR@/unittest/libmariadb/certs/ca-cert.pem",
|
NULL,
|
||||||
NULL,
|
NULL,
|
||||||
NULL);
|
NULL);
|
||||||
|
|
||||||
@@ -541,13 +541,14 @@ static int verify_ssl_server_cert(MYSQL *unused __attribute__((unused)))
|
|||||||
mysql= mysql_init(NULL);
|
mysql= mysql_init(NULL);
|
||||||
FAIL_IF(!mysql, "Can't allocate memory");
|
FAIL_IF(!mysql, "Can't allocate memory");
|
||||||
|
|
||||||
mysql_ssl_set(mysql, NULL, NULL, "@CMAKE_SOURCE_DIR@/unittest/libmariadb/certs/ca-cert.pem", NULL, NULL);
|
mysql_ssl_set(mysql, NULL, NULL, "@CMAKE_SOURCE_DIR@/unittest/libmariadb/certs/cacert.pem", NULL, NULL);
|
||||||
mysql_options(mysql, MYSQL_OPT_SSL_VERIFY_SERVER_CERT, &verify);
|
mysql_options(mysql, MYSQL_OPT_SSL_VERIFY_SERVER_CERT, &verify);
|
||||||
|
|
||||||
mysql_real_connect(mysql, hostname, ssluser, sslpw, schema,
|
mysql_real_connect(mysql, hostname, ssluser, sslpw, schema,
|
||||||
port, socketname, 0);
|
port, socketname, 0);
|
||||||
|
|
||||||
FAIL_IF(!mysql_errno(mysql), "Expected error");
|
FAIL_IF(!mysql_errno(mysql), "Expected error");
|
||||||
|
diag("Error (expected): %s", mysql_error(mysql));
|
||||||
mysql_close(mysql);
|
mysql_close(mysql);
|
||||||
|
|
||||||
return OK;
|
return OK;
|
||||||
@@ -758,8 +759,13 @@ static int test_ssl_fp_list(MYSQL *unused __attribute__((unused)))
|
|||||||
|
|
||||||
mysql_options(my, MARIADB_OPT_SSL_FP_LIST, "./fingerprint.list");
|
mysql_options(my, MARIADB_OPT_SSL_FP_LIST, "./fingerprint.list");
|
||||||
|
|
||||||
FAIL_IF(!mysql_real_connect(my, hostname, ssluser, sslpw, schema,
|
if(!mysql_real_connect(my, hostname, ssluser, sslpw, schema,
|
||||||
port, socketname, 0), mysql_error(my));
|
port, socketname, 0))
|
||||||
|
{
|
||||||
|
diag("Error: %s", mysql_error(my));
|
||||||
|
mysql_close(my);
|
||||||
|
return FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
FAIL_IF(check_cipher(my) != 0, "Invalid cipher");
|
FAIL_IF(check_cipher(my) != 0, "Invalid cipher");
|
||||||
mysql_close(my);
|
mysql_close(my);
|
||||||
@@ -814,7 +820,6 @@ static int test_schannel_cipher(MYSQL *unused __attribute__((unused)))
|
|||||||
port, socketname, 0), mysql_error(my));
|
port, socketname, 0), mysql_error(my));
|
||||||
|
|
||||||
diag("cipher: %s", mysql_get_ssl_cipher(my));
|
diag("cipher: %s", mysql_get_ssl_cipher(my));
|
||||||
FAIL_IF(strcmp(mysql_get_ssl_cipher(my), "CALG_AES_256") != 0, "expected cipher with 256bit strength");
|
|
||||||
|
|
||||||
mysql_close(my);
|
mysql_close(my);
|
||||||
|
|
||||||
@@ -823,7 +828,7 @@ static int test_schannel_cipher(MYSQL *unused __attribute__((unused)))
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_GNUTLS
|
#if defined(HAVE_GNUTLS) || defined(HAVE_OPENSSL)
|
||||||
|
|
||||||
static int test_cipher_mapping(MYSQL *unused __attribute__((unused)))
|
static int test_cipher_mapping(MYSQL *unused __attribute__((unused)))
|
||||||
{
|
{
|
||||||
@@ -847,16 +852,22 @@ static int test_cipher_mapping(MYSQL *unused __attribute__((unused)))
|
|||||||
MYSQL_RES *res;
|
MYSQL_RES *res;
|
||||||
char c[100];
|
char c[100];
|
||||||
int rc;
|
int rc;
|
||||||
mysql_options(mysql, MYSQL_OPT_SSL_CIPHER, ciphers[i]);
|
|
||||||
|
mysql_ssl_set(mysql, NULL, NULL, NULL, NULL, ciphers[i]);
|
||||||
diag("%s", ciphers[i]);
|
diag("%s", ciphers[i]);
|
||||||
|
|
||||||
|
mysql->options.use_ssl= 1;
|
||||||
FAIL_IF(!mysql_real_connect(mysql, hostname, username, password, schema,
|
FAIL_IF(!mysql_real_connect(mysql, hostname, username, password, schema,
|
||||||
port, socketname, 0), mysql_error(mysql));
|
port, socketname, 0), mysql_error(mysql));
|
||||||
if (strcmp(ciphers[i], mysql_get_ssl_cipher(mysql)) != 0)
|
if (!mysql_get_ssl_cipher(mysql) ||
|
||||||
|
strcmp(ciphers[i], mysql_get_ssl_cipher(mysql)) != 0)
|
||||||
{
|
{
|
||||||
diag("expected: %s instead of %s", ciphers[i], mysql_get_ssl_cipher(mysql));
|
diag("cipher %s failed", ciphers[i]);
|
||||||
mysql_close(mysql);
|
mysql_close(mysql);
|
||||||
return FAIL;
|
return FAIL;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
rc= mysql_query(mysql, "SHOW STATUS LIKE 'ssl_cipher'");
|
rc= mysql_query(mysql, "SHOW STATUS LIKE 'ssl_cipher'");
|
||||||
check_mysql_rc(rc, mysql);
|
check_mysql_rc(rc, mysql);
|
||||||
res= mysql_store_result(mysql);
|
res= mysql_store_result(mysql);
|
||||||
@@ -869,22 +880,176 @@ static int test_cipher_mapping(MYSQL *unused __attribute__((unused)))
|
|||||||
diag("expected: %s instead of %s", ciphers[i], c);
|
diag("expected: %s instead of %s", ciphers[i], c);
|
||||||
return FAIL;
|
return FAIL;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static int test_openssl_1(MYSQL *mysql)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
MYSQL *my;
|
||||||
|
uchar val= 1;
|
||||||
|
char query[1024];
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (check_skip_ssl())
|
||||||
|
return SKIP;
|
||||||
|
|
||||||
|
for (i=1; i < 6; i++)
|
||||||
|
{
|
||||||
|
sprintf(query, "DROP USER IF EXISTS 'ssluser%d'@'%s'", i, sslhost);
|
||||||
|
rc= mysql_query(mysql, query);
|
||||||
|
check_mysql_rc(rc, mysql);
|
||||||
|
sprintf(query, "CREATE USER 'ssluser%d'@'%s'", i, sslhost);
|
||||||
|
rc= mysql_query(mysql, query);
|
||||||
|
check_mysql_rc(rc, mysql);
|
||||||
|
}
|
||||||
|
rc= mysql_query(mysql, "FLUSH PRIVILEGES");
|
||||||
|
check_mysql_rc(rc, mysql);
|
||||||
|
|
||||||
|
sprintf(query, "grant select on %s.* to 'ssluser1'@'%s' require ssl", schema, sslhost);
|
||||||
|
rc= mysql_query(mysql, query);
|
||||||
|
check_mysql_rc(rc, mysql);
|
||||||
|
|
||||||
|
|
||||||
|
my= mysql_init(NULL);
|
||||||
|
mysql_ssl_set(my, NULL, NULL, NULL, NULL, "AES128-SHA");
|
||||||
|
FAIL_IF(!mysql_real_connect(my, hostname, "ssluser1", NULL, schema,
|
||||||
|
port, socketname, 0), mysql_error(my));
|
||||||
|
FAIL_IF(!mysql_get_ssl_cipher(my), "No TLS connection");
|
||||||
|
mysql_close(my);
|
||||||
|
|
||||||
|
my= mysql_init(NULL);
|
||||||
|
mysql_options(my, MYSQL_OPT_SSL_ENFORCE, &val);
|
||||||
|
my->options.use_ssl= 1;
|
||||||
|
FAIL_IF(!mysql_real_connect(my, hostname, "ssluser1", NULL, schema,
|
||||||
|
port, socketname, 0), mysql_error(my));
|
||||||
|
FAIL_IF(!mysql_get_ssl_cipher(my), "No TLS connection");
|
||||||
|
mysql_close(my);
|
||||||
|
|
||||||
|
sprintf(query, "grant select on %s.* to 'ssluser2'@'%s' require cipher 'AES256-SHA'", schema, sslhost);
|
||||||
|
rc= mysql_query(mysql, query);
|
||||||
|
check_mysql_rc(rc, mysql);
|
||||||
|
|
||||||
|
/* ssl_user1: connect with enforce should work */
|
||||||
|
my= mysql_init(NULL);
|
||||||
|
mysql_options(my, MYSQL_OPT_SSL_ENFORCE, &val);
|
||||||
|
FAIL_IF(mysql_real_connect(my, hostname, "ssluser2", NULL, schema,
|
||||||
|
port, socketname, 0), "Error expected");
|
||||||
|
mysql_close(my);
|
||||||
|
|
||||||
|
/* ssl_user2: connect with cipher should work */
|
||||||
|
my= mysql_init(NULL);
|
||||||
|
mysql_ssl_set(my, NULL, NULL, NULL, NULL, "AES128-SHA");
|
||||||
|
FAIL_IF(mysql_real_connect(my, hostname, "ssluser2", NULL, schema,
|
||||||
|
port, socketname, 0), "Error expected");
|
||||||
|
mysql_close(my);
|
||||||
|
|
||||||
|
|
||||||
|
/* ssl_user2: connect with correct cipher */
|
||||||
|
my= mysql_init(NULL);
|
||||||
|
mysql_ssl_set(my, NULL, NULL, NULL, NULL, "AES256-SHA");
|
||||||
|
FAIL_IF(!mysql_real_connect(my, hostname, "ssluser2", NULL, schema,
|
||||||
|
port, socketname, 0), mysql_error(my));
|
||||||
|
FAIL_IF(strcmp("AES256-SHA", mysql_get_ssl_cipher(my)) != 0, "expected cipher AES256-SHA");
|
||||||
|
mysql_close(my);
|
||||||
|
|
||||||
|
|
||||||
|
sprintf(query, "grant select on %s.* to 'ssluser3'@'%s' require cipher 'AES256-SHA' AND "
|
||||||
|
" SUBJECT '/DC=com/DC=example/CN=client'", schema, sslhost);
|
||||||
|
rc= mysql_query(mysql, query);
|
||||||
|
check_mysql_rc(rc, mysql);
|
||||||
|
|
||||||
|
/* ssluser3: connect with cipher only */
|
||||||
|
my= mysql_init(NULL);
|
||||||
|
mysql_ssl_set(my, NULL, NULL, NULL, NULL, "AES256-SHA");
|
||||||
|
FAIL_IF(mysql_real_connect(my, hostname, "ssluser3", NULL, schema,
|
||||||
|
port, socketname, 0), "Error expected");
|
||||||
|
mysql_close(my);
|
||||||
|
|
||||||
|
/* ssluser3 connect with cipher and certs */
|
||||||
|
my= mysql_init(NULL);
|
||||||
|
mysql_ssl_set(my, "@CMAKE_SOURCE_DIR@/unittest/libmariadb/certs/client-key.pem",
|
||||||
|
"@CMAKE_SOURCE_DIR@/unittest/libmariadb/certs/client-cert.pem",
|
||||||
|
"@CMAKE_SOURCE_DIR@/unittest/libmariadb/certs/ca-cert.pem",
|
||||||
|
NULL,
|
||||||
|
"AES256-SHA");
|
||||||
|
FAIL_IF(!mysql_real_connect(my, hostname, "ssluser3", NULL, schema,
|
||||||
|
port, socketname, 0), mysql_error(my));
|
||||||
|
|
||||||
|
mysql_close(my);
|
||||||
|
|
||||||
|
sprintf(query, "grant select on %s.* to 'ssluser4'@'%s' require cipher 'AES256-SHA' AND "
|
||||||
|
" ISSUER '/DC=com/DC=example/CN=client'", schema, sslhost);
|
||||||
|
rc= mysql_query(mysql, query);
|
||||||
|
check_mysql_rc(rc, mysql);
|
||||||
|
|
||||||
|
/* ssluser4: connect with cipher only */
|
||||||
|
my= mysql_init(NULL);
|
||||||
|
mysql_ssl_set(my, NULL, NULL, NULL, NULL, "AES256-SHA");
|
||||||
|
FAIL_IF(mysql_real_connect(my, hostname, "ssluser4", NULL, schema,
|
||||||
|
port, socketname, 0), "Error expected");
|
||||||
|
mysql_close(my);
|
||||||
|
|
||||||
|
/* ssluser4 connect with cipher and certs */
|
||||||
|
my= mysql_init(NULL);
|
||||||
|
mysql_ssl_set(my, "@CMAKE_SOURCE_DIR@/unittest/libmariadb/certs/client-key.pem",
|
||||||
|
"@CMAKE_SOURCE_DIR@/unittest/libmariadb/certs/client-cert.pem",
|
||||||
|
"@CMAKE_SOURCE_DIR@/unittest/libmariadb/certs/ca-cert.pem",
|
||||||
|
NULL,
|
||||||
|
"AES256-SHA");
|
||||||
|
FAIL_IF(!mysql_real_connect(my, hostname, "ssluser4", NULL, schema,
|
||||||
|
port, socketname, 0), mysql_error(my));
|
||||||
|
|
||||||
|
mysql_close(my);
|
||||||
|
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int test_ssl_timeout(MYSQL *unused __attribute__((unused)))
|
||||||
|
{
|
||||||
|
MYSQL *mysql;
|
||||||
|
my_bool enforce= 1;
|
||||||
|
int read_timeout= 1;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
if (check_skip_ssl())
|
||||||
|
return SKIP;
|
||||||
|
|
||||||
|
mysql= mysql_init(NULL);
|
||||||
|
mysql_options(mysql, MYSQL_OPT_SSL_ENFORCE, &enforce);
|
||||||
|
mysql_options(mysql, MYSQL_OPT_READ_TIMEOUT, &read_timeout);
|
||||||
|
mysql->options.use_ssl= 1;
|
||||||
|
FAIL_IF(!mysql_real_connect(mysql, hostname, username, password, schema,
|
||||||
|
port, socketname, 0), mysql_error(mysql));
|
||||||
|
diag("cipher: %s\n", mysql_get_ssl_cipher(mysql));
|
||||||
|
rc= mysql_query(mysql, "SELECT SLEEP(600)");
|
||||||
|
if (!rc)
|
||||||
|
{
|
||||||
|
diag("error expected (timeout)");
|
||||||
|
return FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
mysql_close(mysql);
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
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_GNUTLS
|
{"test_ssl_timeout", test_ssl_timeout, TEST_CONNECTION_NEW, 0, NULL, NULL},
|
||||||
|
{"test_openssl_1", test_openssl_1, TEST_CONNECTION_NEW, 0, NULL, NULL},
|
||||||
|
#ifndef HAVE_SCHANNEL
|
||||||
{"test_cipher_mapping", test_cipher_mapping, TEST_CONNECTION_NONE, 0, NULL, NULL},
|
{"test_cipher_mapping", test_cipher_mapping, TEST_CONNECTION_NONE, 0, NULL, NULL},
|
||||||
#endif
|
#endif
|
||||||
{"test_conc127", test_conc127, TEST_CONNECTION_NEW, 0, NULL, NULL},
|
{"test_conc127", test_conc127, TEST_CONNECTION_NEW, 0, NULL, NULL},
|
||||||
|
/* Both tests work with GNU tls, however we can't create fingerprints with
|
||||||
|
gnutls-cli in CMakeLists.txt */
|
||||||
|
#ifdef HAVE_OPENSSL
|
||||||
{"test_ssl_fp", test_ssl_fp, TEST_CONNECTION_NEW, 0, NULL, NULL},
|
{"test_ssl_fp", test_ssl_fp, TEST_CONNECTION_NEW, 0, NULL, NULL},
|
||||||
{"test_ssl_fp_list", test_ssl_fp_list, TEST_CONNECTION_NEW, 0, NULL, NULL},
|
{"test_ssl_fp_list", test_ssl_fp_list, TEST_CONNECTION_NEW, 0, NULL, NULL},
|
||||||
|
#endif
|
||||||
{"test_conc50", test_conc50, TEST_CONNECTION_NEW, 0, NULL, NULL},
|
{"test_conc50", test_conc50, TEST_CONNECTION_NEW, 0, NULL, NULL},
|
||||||
{"test_conc50_1", test_conc50_1, TEST_CONNECTION_NEW, 0, NULL, NULL},
|
{"test_conc50_1", test_conc50_1, TEST_CONNECTION_NEW, 0, NULL, NULL},
|
||||||
{"test_conc50_2", test_conc50_2, TEST_CONNECTION_NEW, 0, NULL, NULL},
|
{"test_conc50_2", test_conc50_2, TEST_CONNECTION_NEW, 0, NULL, NULL},
|
||||||
@@ -914,7 +1079,6 @@ int main(int argc, char **argv)
|
|||||||
|
|
||||||
if (argc > 1)
|
if (argc > 1)
|
||||||
get_options(argc, argv);
|
get_options(argc, argv);
|
||||||
|
|
||||||
run_tests(my_tests);
|
run_tests(my_tests);
|
||||||
|
|
||||||
mysql_server_end();
|
mysql_server_end();
|
||||||
|
Reference in New Issue
Block a user