You've already forked mariadb-connector-c
mirror of
https://github.com/mariadb-corporation/mariadb-connector-c.git
synced 2025-08-07 02:42:49 +03:00
Various ssl and schannel fixes
This commit is contained in:
@@ -1,45 +0,0 @@
|
|||||||
/************************************************************************************
|
|
||||||
Copyright (C) 2012 Monty Program AB
|
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU Library General Public
|
|
||||||
License as published by the Free Software Foundation; either
|
|
||||||
version 2 of the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
This library 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
|
|
||||||
Library General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Library General Public
|
|
||||||
License along with this library; if not see <http://www.gnu.org/licenses>
|
|
||||||
or write to the Free Software Foundation, Inc.,
|
|
||||||
51 Franklin St., Fifth Floor, Boston, MA 02110, USA
|
|
||||||
|
|
||||||
Part of this code includes code from the PHP project which
|
|
||||||
is freely available from http://www.php.net
|
|
||||||
*************************************************************************************/
|
|
||||||
#ifndef _ma_secure_h_
|
|
||||||
#define _ma_secure_h_
|
|
||||||
|
|
||||||
#ifdef HAVE_OPENSSL
|
|
||||||
#include <mysql.h>
|
|
||||||
#include <openssl/ssl.h> /* SSL and SSL_CTX */
|
|
||||||
#include <openssl/err.h> /* error reporting */
|
|
||||||
#include <openssl/conf.h>
|
|
||||||
|
|
||||||
struct MYSQL;
|
|
||||||
|
|
||||||
size_t my_ssl_read(Vio *vio, uchar* buf, size_t size);
|
|
||||||
int my_ssl_close(Vio *vio);
|
|
||||||
size_t my_ssl_write(Vio *vio, const uchar* buf, size_t size);
|
|
||||||
SSL *my_ssl_init(MYSQL *mysql);
|
|
||||||
int my_ssl_connect(SSL *ssl);
|
|
||||||
int my_ssl_verify_server_cert(SSL *ssl);
|
|
||||||
int ma_ssl_verify_fingerprint(SSL *ssl);
|
|
||||||
|
|
||||||
int my_ssl_start(MYSQL *mysql);
|
|
||||||
void my_ssl_end(void);
|
|
||||||
|
|
||||||
#endif /* HAVE_OPENSSL */
|
|
||||||
#endif /* _ma_secure_h_ */
|
|
@@ -133,5 +133,6 @@ my_bool ma_cio_ssl_close(MARIADB_SSL *cssl);
|
|||||||
int ma_cio_ssl_verify_server_cert(MARIADB_SSL *cssl);
|
int ma_cio_ssl_verify_server_cert(MARIADB_SSL *cssl);
|
||||||
const char *ma_cio_ssl_cipher(MARIADB_SSL *cssl);
|
const char *ma_cio_ssl_cipher(MARIADB_SSL *cssl);
|
||||||
my_bool ma_cio_ssl_check_fp(MARIADB_SSL *cssl, const char *fp, const char *fp_list);
|
my_bool ma_cio_ssl_check_fp(MARIADB_SSL *cssl, const char *fp, const char *fp_list);
|
||||||
|
my_bool ma_cio_start_ssl(MARIADB_CIO *cio);
|
||||||
|
|
||||||
#endif /* _ma_ssl_h_ */
|
#endif /* _ma_ssl_h_ */
|
||||||
|
@@ -1145,13 +1145,15 @@ int STDCALL
|
|||||||
mysql_ssl_set(MYSQL *mysql, const char *key, const char *cert,
|
mysql_ssl_set(MYSQL *mysql, const char *key, const char *cert,
|
||||||
const char *ca, const char *capath, const char *cipher)
|
const char *ca, const char *capath, const char *cipher)
|
||||||
{
|
{
|
||||||
mysql->options.ssl_key = key==0 ? 0 : my_strdup(key,MYF(0));
|
#ifdef HAVE_SSL
|
||||||
mysql->options.ssl_cert = cert==0 ? 0 : my_strdup(cert,MYF(0));
|
return (mysql_optionsv(mysql, MYSQL_OPT_SSL_KEY, key) |
|
||||||
mysql->options.ssl_ca = ca==0 ? 0 : my_strdup(ca,MYF(0));
|
mysql_optionsv(mysql, MYSQL_OPT_SSL_CERT, cert) |
|
||||||
mysql->options.ssl_capath = capath==0 ? 0 : my_strdup(capath,MYF(0));
|
mysql_optionsv(mysql, MYSQL_OPT_SSL_CA, ca) |
|
||||||
mysql->options.ssl_cipher = cipher==0 ? 0 : my_strdup(cipher,MYF(0));
|
mysql_optionsv(mysql, MYSQL_OPT_SSL_CAPATH, capath) |
|
||||||
/* todo: add crl stuff */
|
mysql_optionsv(mysql, MYSQL_OPT_SSL_CIPHER, cipher)) ? 1 : 0;
|
||||||
|
#else
|
||||||
return 0;
|
return 0;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/**************************************************************************
|
/**************************************************************************
|
||||||
@@ -2674,23 +2676,23 @@ mysql_optionsv(MYSQL *mysql,enum mysql_option option, ...)
|
|||||||
break;
|
break;
|
||||||
case MYSQL_OPT_SSL_KEY:
|
case MYSQL_OPT_SSL_KEY:
|
||||||
my_free(mysql->options.ssl_key);
|
my_free(mysql->options.ssl_key);
|
||||||
mysql->options.ssl_key=my_strdup((char *)arg1,MYF(MY_WME));
|
mysql->options.ssl_key=my_strdup((char *)arg1,MYF(MY_WME | MY_ALLOW_ZERO_PTR));
|
||||||
break;
|
break;
|
||||||
case MYSQL_OPT_SSL_CERT:
|
case MYSQL_OPT_SSL_CERT:
|
||||||
my_free(mysql->options.ssl_cert);
|
my_free(mysql->options.ssl_cert);
|
||||||
mysql->options.ssl_cert=my_strdup((char *)arg1,MYF(MY_WME));
|
mysql->options.ssl_cert=my_strdup((char *)arg1,MYF(MY_WME | MY_ALLOW_ZERO_PTR));
|
||||||
break;
|
break;
|
||||||
case MYSQL_OPT_SSL_CA:
|
case MYSQL_OPT_SSL_CA:
|
||||||
my_free(mysql->options.ssl_ca);
|
my_free(mysql->options.ssl_ca);
|
||||||
mysql->options.ssl_ca=my_strdup((char *)arg1,MYF(MY_WME));
|
mysql->options.ssl_ca=my_strdup((char *)arg1,MYF(MY_WME | MY_ALLOW_ZERO_PTR));
|
||||||
break;
|
break;
|
||||||
case MYSQL_OPT_SSL_CAPATH:
|
case MYSQL_OPT_SSL_CAPATH:
|
||||||
my_free(mysql->options.ssl_capath);
|
my_free(mysql->options.ssl_capath);
|
||||||
mysql->options.ssl_capath=my_strdup((char *)arg1,MYF(MY_WME));
|
mysql->options.ssl_capath=my_strdup((char *)arg1,MYF(MY_WME | MY_ALLOW_ZERO_PTR));
|
||||||
break;
|
break;
|
||||||
case MYSQL_OPT_SSL_CIPHER:
|
case MYSQL_OPT_SSL_CIPHER:
|
||||||
my_free(mysql->options.ssl_cipher);
|
my_free(mysql->options.ssl_cipher);
|
||||||
mysql->options.ssl_cipher=my_strdup((char *)arg1,MYF(MY_WME));
|
mysql->options.ssl_cipher=my_strdup((char *)arg1,MYF(MY_WME | MY_ALLOW_ZERO_PTR));
|
||||||
break;
|
break;
|
||||||
case MYSQL_OPT_SSL_CRL:
|
case MYSQL_OPT_SSL_CRL:
|
||||||
OPT_SET_EXTENDED_VALUE_STR(&mysql->options, ssl_crl, (char *)arg1);
|
OPT_SET_EXTENDED_VALUE_STR(&mysql->options, ssl_crl, (char *)arg1);
|
||||||
@@ -2789,6 +2791,12 @@ mysql_optionsv(MYSQL *mysql,enum mysql_option option, ...)
|
|||||||
my_free(mysql->options.bind_address);
|
my_free(mysql->options.bind_address);
|
||||||
mysql->options.bind_address= my_strdup(arg1, MYF(MY_WME));
|
mysql->options.bind_address= my_strdup(arg1, MYF(MY_WME));
|
||||||
break;
|
break;
|
||||||
|
case MARIADB_OPT_SSL_FP:
|
||||||
|
OPT_SET_EXTENDED_VALUE_STR(&mysql->options, ssl_fp, (char *)arg1);
|
||||||
|
break;
|
||||||
|
case MARIADB_OPT_SSL_FP_LIST:
|
||||||
|
OPT_SET_EXTENDED_VALUE_STR(&mysql->options, ssl_fp_list, (char *)arg1);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
DBUG_RETURN(-1);
|
DBUG_RETURN(-1);
|
||||||
|
@@ -283,7 +283,7 @@ size_t ma_cio_cache_read(MARIADB_CIO *cio, uchar *buffer, size_t length)
|
|||||||
}
|
}
|
||||||
memcpy(buffer, cio->cache, r);
|
memcpy(buffer, cio->cache, r);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
/* }}} */
|
/* }}} */
|
||||||
|
@@ -1,688 +0,0 @@
|
|||||||
/************************************************************************************
|
|
||||||
Copyright (C) 2012 Monty Program AB
|
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU Library General Public
|
|
||||||
License as published by the Free Software Foundation; either
|
|
||||||
version 2 of the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
This library 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
|
|
||||||
Library General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Library General Public
|
|
||||||
License along with this library; if not see <http://www.gnu.org/licenses>
|
|
||||||
or write to the Free Software Foundation, Inc.,
|
|
||||||
51 Franklin St., Fifth Floor, Boston, MA 02110, USA
|
|
||||||
|
|
||||||
*************************************************************************************/
|
|
||||||
unsigned int mariadb_deinitialize_ssl= 1;
|
|
||||||
#ifdef HAVE_OPENSSL
|
|
||||||
|
|
||||||
#include <my_global.h>
|
|
||||||
#include <my_sys.h>
|
|
||||||
#include <ma_common.h>
|
|
||||||
#include <ma_secure.h>
|
|
||||||
#include <errmsg.h>
|
|
||||||
#include <violite.h>
|
|
||||||
#include <mysql_async.h>
|
|
||||||
#include <my_context.h>
|
|
||||||
|
|
||||||
static my_bool my_ssl_initialized= FALSE;
|
|
||||||
static SSL_CTX *SSL_context= NULL;
|
|
||||||
|
|
||||||
#define MAX_SSL_ERR_LEN 100
|
|
||||||
|
|
||||||
extern pthread_mutex_t LOCK_ssl_config;
|
|
||||||
static pthread_mutex_t *LOCK_crypto= NULL;
|
|
||||||
|
|
||||||
/*
|
|
||||||
SSL error handling
|
|
||||||
*/
|
|
||||||
static void my_SSL_error(MYSQL *mysql)
|
|
||||||
{
|
|
||||||
ulong ssl_errno= ERR_get_error();
|
|
||||||
char ssl_error[MAX_SSL_ERR_LEN];
|
|
||||||
const char *ssl_error_reason;
|
|
||||||
|
|
||||||
DBUG_ENTER("my_SSL_error");
|
|
||||||
|
|
||||||
if (mysql_errno(mysql))
|
|
||||||
DBUG_VOID_RETURN;
|
|
||||||
|
|
||||||
if (!ssl_errno)
|
|
||||||
{
|
|
||||||
my_set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, "Unknown SSL error");
|
|
||||||
DBUG_VOID_RETURN;
|
|
||||||
}
|
|
||||||
if ((ssl_error_reason= ERR_reason_error_string(ssl_errno)))
|
|
||||||
{
|
|
||||||
my_set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN,
|
|
||||||
ER(CR_SSL_CONNECTION_ERROR), ssl_error_reason);
|
|
||||||
DBUG_VOID_RETURN;
|
|
||||||
}
|
|
||||||
my_snprintf(ssl_error, MAX_SSL_ERR_LEN, "SSL errno=%lu", ssl_errno, mysql->charset);
|
|
||||||
my_set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN,
|
|
||||||
ER(CR_SSL_CONNECTION_ERROR), ssl_error);
|
|
||||||
DBUG_VOID_RETURN;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
thread safe callbacks for OpenSSL
|
|
||||||
Crypto call back functions will be
|
|
||||||
set during ssl_initialization
|
|
||||||
*/
|
|
||||||
#if (OPENSSL_VERSION_NUMBER < 0x10000000)
|
|
||||||
static unsigned long my_cb_threadid(void)
|
|
||||||
{
|
|
||||||
/* cast pthread_t to unsigned long */
|
|
||||||
return (unsigned long) pthread_self();
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
static void my_cb_threadid(CRYPTO_THREADID *id)
|
|
||||||
{
|
|
||||||
CRYPTO_THREADID_set_numeric(id, (unsigned long)pthread_self());
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static void my_cb_locking(int mode, int n, const char *file, int line)
|
|
||||||
{
|
|
||||||
if (mode & CRYPTO_LOCK)
|
|
||||||
pthread_mutex_lock(&LOCK_crypto[n]);
|
|
||||||
else
|
|
||||||
pthread_mutex_unlock(&LOCK_crypto[n]);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int ssl_crypto_init()
|
|
||||||
{
|
|
||||||
int i, rc= 1, max= CRYPTO_num_locks();
|
|
||||||
|
|
||||||
#if (OPENSSL_VERSION_NUMBER < 0x10000000)
|
|
||||||
CRYPTO_set_id_callback(my_cb_threadid);
|
|
||||||
#else
|
|
||||||
rc= CRYPTO_THREADID_set_callback(my_cb_threadid);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* if someone else already set callbacks
|
|
||||||
* there is nothing do */
|
|
||||||
if (!rc)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (LOCK_crypto == NULL)
|
|
||||||
{
|
|
||||||
if (!(LOCK_crypto=
|
|
||||||
(pthread_mutex_t *)my_malloc(sizeof(pthread_mutex_t) * max, MYF(0))))
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
for (i=0; i < max; i++)
|
|
||||||
pthread_mutex_init(&LOCK_crypto[i], NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
CRYPTO_set_locking_callback(my_cb_locking);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
Initializes SSL and allocate global
|
|
||||||
context SSL_context
|
|
||||||
|
|
||||||
SYNOPSIS
|
|
||||||
my_ssl_start
|
|
||||||
mysql connection handle
|
|
||||||
|
|
||||||
RETURN VALUES
|
|
||||||
0 success
|
|
||||||
1 error
|
|
||||||
*/
|
|
||||||
int my_ssl_start(MYSQL *mysql)
|
|
||||||
{
|
|
||||||
int rc= 0;
|
|
||||||
DBUG_ENTER("my_ssl_start");
|
|
||||||
/* lock mutex to prevent multiple initialization */
|
|
||||||
pthread_mutex_lock(&LOCK_ssl_config);
|
|
||||||
if (!my_ssl_initialized)
|
|
||||||
{
|
|
||||||
if (ssl_crypto_init())
|
|
||||||
goto end;
|
|
||||||
SSL_library_init();
|
|
||||||
|
|
||||||
#if SSLEAY_VERSION_NUMBER >= 0x00907000L
|
|
||||||
OPENSSL_config(NULL);
|
|
||||||
#endif
|
|
||||||
/* load errors */
|
|
||||||
SSL_load_error_strings();
|
|
||||||
/* digests and ciphers */
|
|
||||||
OpenSSL_add_all_algorithms();
|
|
||||||
|
|
||||||
if (!(SSL_context= SSL_CTX_new(TLSv1_client_method())))
|
|
||||||
{
|
|
||||||
my_SSL_error(mysql);
|
|
||||||
rc= 1;
|
|
||||||
goto end;
|
|
||||||
}
|
|
||||||
my_ssl_initialized= TRUE;
|
|
||||||
}
|
|
||||||
end:
|
|
||||||
pthread_mutex_unlock(&LOCK_ssl_config);
|
|
||||||
DBUG_RETURN(rc);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Release SSL and free resources
|
|
||||||
Will be automatically executed by
|
|
||||||
mysql_server_end() function
|
|
||||||
|
|
||||||
SYNOPSIS
|
|
||||||
my_ssl_end()
|
|
||||||
void
|
|
||||||
|
|
||||||
RETURN VALUES
|
|
||||||
void
|
|
||||||
*/
|
|
||||||
void my_ssl_end()
|
|
||||||
{
|
|
||||||
DBUG_ENTER("my_ssl_end");
|
|
||||||
pthread_mutex_lock(&LOCK_ssl_config);
|
|
||||||
if (my_ssl_initialized)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
if (LOCK_crypto)
|
|
||||||
{
|
|
||||||
CRYPTO_set_locking_callback(NULL);
|
|
||||||
CRYPTO_set_id_callback(NULL);
|
|
||||||
|
|
||||||
for (i=0; i < CRYPTO_num_locks(); i++)
|
|
||||||
pthread_mutex_destroy(&LOCK_crypto[i]);
|
|
||||||
|
|
||||||
my_free(LOCK_crypto);
|
|
||||||
LOCK_crypto= NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (SSL_context)
|
|
||||||
{
|
|
||||||
SSL_CTX_free(SSL_context);
|
|
||||||
SSL_context= FALSE;
|
|
||||||
}
|
|
||||||
if (mariadb_deinitialize_ssl)
|
|
||||||
{
|
|
||||||
ERR_remove_state(0);
|
|
||||||
EVP_cleanup();
|
|
||||||
CRYPTO_cleanup_all_ex_data();
|
|
||||||
ERR_free_strings();
|
|
||||||
CONF_modules_free();
|
|
||||||
CONF_modules_unload(1);
|
|
||||||
sk_SSL_COMP_free(SSL_COMP_get_compression_methods());
|
|
||||||
}
|
|
||||||
my_ssl_initialized= FALSE;
|
|
||||||
}
|
|
||||||
pthread_mutex_unlock(&LOCK_ssl_config);
|
|
||||||
pthread_mutex_destroy(&LOCK_ssl_config);
|
|
||||||
DBUG_VOID_RETURN;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Set certification stuff.
|
|
||||||
*/
|
|
||||||
static int my_ssl_set_certs(MYSQL *mysql)
|
|
||||||
{
|
|
||||||
char *certfile= mysql->options.ssl_cert,
|
|
||||||
*keyfile= mysql->options.ssl_key;
|
|
||||||
|
|
||||||
DBUG_ENTER("my_ssl_set_certs");
|
|
||||||
|
|
||||||
/* Make sure that ssl was allocated and
|
|
||||||
ssl_system was initialized */
|
|
||||||
DBUG_ASSERT(my_ssl_initialized == TRUE);
|
|
||||||
|
|
||||||
/* add cipher */
|
|
||||||
if ((mysql->options.ssl_cipher &&
|
|
||||||
mysql->options.ssl_cipher[0] != 0) &&
|
|
||||||
SSL_CTX_set_cipher_list(SSL_context, mysql->options.ssl_cipher) == 0)
|
|
||||||
goto error;
|
|
||||||
|
|
||||||
/* ca_file and ca_path */
|
|
||||||
if (SSL_CTX_load_verify_locations(SSL_context,
|
|
||||||
mysql->options.ssl_ca,
|
|
||||||
mysql->options.ssl_capath) == 0)
|
|
||||||
{
|
|
||||||
if (mysql->options.ssl_ca || mysql->options.ssl_capath)
|
|
||||||
goto error;
|
|
||||||
if (SSL_CTX_set_default_verify_paths(SSL_context) == 0)
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (keyfile && !certfile)
|
|
||||||
certfile= keyfile;
|
|
||||||
if (certfile && !keyfile)
|
|
||||||
keyfile= certfile;
|
|
||||||
|
|
||||||
/* set cert */
|
|
||||||
if (certfile && certfile[0] != 0)
|
|
||||||
if (SSL_CTX_use_certificate_file(SSL_context, certfile, SSL_FILETYPE_PEM) != 1)
|
|
||||||
goto error;
|
|
||||||
|
|
||||||
/* set key */
|
|
||||||
if (keyfile && keyfile[0])
|
|
||||||
{
|
|
||||||
if (SSL_CTX_use_PrivateKey_file(SSL_context, keyfile, SSL_FILETYPE_PEM) != 1)
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
/* verify key */
|
|
||||||
if (certfile && !SSL_CTX_check_private_key(SSL_context))
|
|
||||||
goto error;
|
|
||||||
|
|
||||||
if (mysql->options.extension &&
|
|
||||||
(mysql->options.extension->ssl_crl || mysql->options.extension->ssl_crlpath))
|
|
||||||
{
|
|
||||||
X509_STORE *certstore;
|
|
||||||
|
|
||||||
if ((certstore= SSL_CTX_get_cert_store(SSL_context)))
|
|
||||||
{
|
|
||||||
if (X509_STORE_load_locations(certstore, mysql->options.ssl_ca,
|
|
||||||
mysql->options.ssl_capath) == 0 ||
|
|
||||||
X509_STORE_set_flags(certstore, X509_V_FLAG_CRL_CHECK |
|
|
||||||
X509_V_FLAG_CRL_CHECK_ALL) == 0)
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
DBUG_RETURN(0);
|
|
||||||
|
|
||||||
error:
|
|
||||||
my_SSL_error(mysql);
|
|
||||||
DBUG_RETURN(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
static unsigned int ma_get_cert_fingerprint(X509 *cert, EVP_MD *digest,
|
|
||||||
unsigned char *fingerprint, unsigned int *fp_length)
|
|
||||||
{
|
|
||||||
if (*fp_length < EVP_MD_size(digest))
|
|
||||||
return 0;
|
|
||||||
if (!X509_digest(cert, digest, fingerprint, fp_length))
|
|
||||||
return 0;
|
|
||||||
return *fp_length;
|
|
||||||
}
|
|
||||||
|
|
||||||
static my_bool ma_check_fingerprint(char *fp1, unsigned int fp1_len,
|
|
||||||
char *fp2, unsigned int fp2_len)
|
|
||||||
{
|
|
||||||
char hexstr[fp1_len * 2 + 1];
|
|
||||||
|
|
||||||
fp1_len= (unsigned int)mysql_hex_string(hexstr, fp1, fp1_len);
|
|
||||||
if (strncasecmp(hexstr, fp2, fp1_len) != 0)
|
|
||||||
return 1;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int my_verify_callback(int ok, X509_STORE_CTX *ctx)
|
|
||||||
{
|
|
||||||
X509 *check_cert;
|
|
||||||
SSL *ssl;
|
|
||||||
MYSQL *mysql;
|
|
||||||
DBUG_ENTER("my_verify_callback");
|
|
||||||
|
|
||||||
ssl = X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx());
|
|
||||||
DBUG_ASSERT(ssl != NULL);
|
|
||||||
mysql= (MYSQL *)SSL_get_app_data(ssl);
|
|
||||||
DBUG_ASSERT(mysql != NULL);
|
|
||||||
|
|
||||||
/* skip verification if no ca_file/path was specified */
|
|
||||||
if (!mysql->options.ssl_ca && !mysql->options.ssl_capath)
|
|
||||||
{
|
|
||||||
ok= 1;
|
|
||||||
DBUG_RETURN(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!ok)
|
|
||||||
{
|
|
||||||
uint depth;
|
|
||||||
if (!(check_cert= X509_STORE_CTX_get_current_cert(ctx)))
|
|
||||||
DBUG_RETURN(0);
|
|
||||||
depth= X509_STORE_CTX_get_error_depth(ctx);
|
|
||||||
if (depth == 0)
|
|
||||||
ok= 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
my_set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN,
|
|
||||||
ER(CR_SSL_CONNECTION_ERROR),
|
|
||||||
X509_verify_cert_error_string(ctx->error));
|
|
||||||
*/
|
|
||||||
DBUG_RETURN(ok);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
allocates a new ssl object
|
|
||||||
|
|
||||||
SYNOPSIS
|
|
||||||
my_ssl_init
|
|
||||||
mysql connection object
|
|
||||||
|
|
||||||
RETURN VALUES
|
|
||||||
NULL on error
|
|
||||||
SSL new SSL object
|
|
||||||
*/
|
|
||||||
SSL *my_ssl_init(MYSQL *mysql)
|
|
||||||
{
|
|
||||||
int verify;
|
|
||||||
SSL *ssl= NULL;
|
|
||||||
|
|
||||||
DBUG_ENTER("my_ssl_init");
|
|
||||||
|
|
||||||
DBUG_ASSERT(mysql->net.vio->ssl == NULL);
|
|
||||||
|
|
||||||
if (!my_ssl_initialized)
|
|
||||||
my_ssl_start(mysql);
|
|
||||||
|
|
||||||
pthread_mutex_lock(&LOCK_ssl_config);
|
|
||||||
if (my_ssl_set_certs(mysql))
|
|
||||||
goto error;
|
|
||||||
|
|
||||||
if (!(ssl= SSL_new(SSL_context)))
|
|
||||||
goto error;
|
|
||||||
|
|
||||||
if (!SSL_set_app_data(ssl, mysql))
|
|
||||||
goto error;
|
|
||||||
|
|
||||||
verify= (!mysql->options.ssl_ca && !mysql->options.ssl_capath) ?
|
|
||||||
SSL_VERIFY_NONE : SSL_VERIFY_PEER;
|
|
||||||
|
|
||||||
SSL_CTX_set_verify(SSL_context, verify, my_verify_callback);
|
|
||||||
SSL_CTX_set_verify_depth(SSL_context, 1);
|
|
||||||
|
|
||||||
pthread_mutex_unlock(&LOCK_ssl_config);
|
|
||||||
DBUG_RETURN(ssl);
|
|
||||||
error:
|
|
||||||
pthread_mutex_unlock(&LOCK_ssl_config);
|
|
||||||
if (ssl)
|
|
||||||
SSL_free(ssl);
|
|
||||||
DBUG_RETURN(NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
establish SSL connection between client
|
|
||||||
and server
|
|
||||||
|
|
||||||
SYNOPSIS
|
|
||||||
my_ssl_connect
|
|
||||||
ssl ssl object
|
|
||||||
|
|
||||||
RETURN VALUES
|
|
||||||
0 success
|
|
||||||
1 error
|
|
||||||
*/
|
|
||||||
int my_ssl_connect(SSL *ssl)
|
|
||||||
{
|
|
||||||
my_bool blocking;
|
|
||||||
MYSQL *mysql;
|
|
||||||
long rc;
|
|
||||||
|
|
||||||
DBUG_ENTER("my_ssl_connect");
|
|
||||||
|
|
||||||
DBUG_ASSERT(ssl != NULL);
|
|
||||||
|
|
||||||
mysql= (MYSQL *)SSL_get_app_data(ssl);
|
|
||||||
CLEAR_CLIENT_ERROR(mysql);
|
|
||||||
|
|
||||||
/* Set socket to blocking if not already set */
|
|
||||||
if (!(blocking= vio_is_blocking(mysql->net.vio)))
|
|
||||||
vio_blocking(mysql->net.vio, TRUE, 0);
|
|
||||||
|
|
||||||
SSL_clear(ssl);
|
|
||||||
SSL_SESSION_set_timeout(SSL_get_session(ssl),
|
|
||||||
mysql->options.connect_timeout);
|
|
||||||
SSL_set_fd(ssl, mysql->net.vio->sd);
|
|
||||||
|
|
||||||
if (SSL_connect(ssl) != 1)
|
|
||||||
{
|
|
||||||
my_SSL_error(mysql);
|
|
||||||
/* restore blocking mode */
|
|
||||||
if (!blocking)
|
|
||||||
vio_blocking(mysql->net.vio, FALSE, 0);
|
|
||||||
DBUG_RETURN(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
rc= SSL_get_verify_result(ssl);
|
|
||||||
if (rc != X509_V_OK)
|
|
||||||
{
|
|
||||||
my_set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN,
|
|
||||||
ER(CR_SSL_CONNECTION_ERROR), X509_verify_cert_error_string(rc));
|
|
||||||
/* restore blocking mode */
|
|
||||||
if (!blocking)
|
|
||||||
vio_blocking(mysql->net.vio, FALSE, 0);
|
|
||||||
|
|
||||||
DBUG_RETURN(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
vio_reset(mysql->net.vio, VIO_TYPE_SSL, mysql->net.vio->sd, 0, 0);
|
|
||||||
mysql->net.vio->ssl= ssl;
|
|
||||||
DBUG_RETURN(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
int ma_ssl_verify_fingerprint(SSL *ssl)
|
|
||||||
{
|
|
||||||
X509 *cert= SSL_get_peer_certificate(ssl);
|
|
||||||
MYSQL *mysql= (MYSQL *)SSL_get_app_data(ssl);
|
|
||||||
unsigned char fingerprint[EVP_MAX_MD_SIZE];
|
|
||||||
EVP_MD *digest;
|
|
||||||
unsigned int fp_length;
|
|
||||||
|
|
||||||
DBUG_ENTER("ma_ssl_verify_fingerprint");
|
|
||||||
|
|
||||||
if (!cert)
|
|
||||||
{
|
|
||||||
my_set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN,
|
|
||||||
ER(CR_SSL_CONNECTION_ERROR),
|
|
||||||
"Unable to get server certificate");
|
|
||||||
DBUG_RETURN(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
digest= (EVP_MD *)EVP_sha1();
|
|
||||||
fp_length= sizeof(fingerprint);
|
|
||||||
|
|
||||||
if (!ma_get_cert_fingerprint(cert, digest, fingerprint, &fp_length))
|
|
||||||
{
|
|
||||||
my_set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN,
|
|
||||||
ER(CR_SSL_CONNECTION_ERROR),
|
|
||||||
"Unable to get finger print of server certificate");
|
|
||||||
DBUG_RETURN(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* single finger print was specified */
|
|
||||||
if (mysql->options.extension->ssl_fp)
|
|
||||||
{
|
|
||||||
if (ma_check_fingerprint(fingerprint, fp_length, mysql->options.extension->ssl_fp,
|
|
||||||
strlen(mysql->options.extension->ssl_fp)))
|
|
||||||
{
|
|
||||||
my_set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN,
|
|
||||||
ER(CR_SSL_CONNECTION_ERROR),
|
|
||||||
"invalid finger print of server certificate");
|
|
||||||
DBUG_RETURN(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* white list of finger prints was specified */
|
|
||||||
if (mysql->options.extension->ssl_fp_list)
|
|
||||||
{
|
|
||||||
FILE *fp;
|
|
||||||
char buff[255];
|
|
||||||
|
|
||||||
if (!(fp = my_fopen(mysql->options.extension->ssl_fp_list ,O_RDONLY, MYF(0))))
|
|
||||||
{
|
|
||||||
my_set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN,
|
|
||||||
ER(CR_SSL_CONNECTION_ERROR),
|
|
||||||
"Can't open finger print list");
|
|
||||||
DBUG_RETURN(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
while (fgets(buff, sizeof(buff)-1, fp))
|
|
||||||
{
|
|
||||||
/* remove trailing new line character */
|
|
||||||
char *pos= strchr(buff, '\r');
|
|
||||||
if (!pos)
|
|
||||||
pos= strchr(buff, '\n');
|
|
||||||
if (pos)
|
|
||||||
*pos= '\0';
|
|
||||||
|
|
||||||
if (!ma_check_fingerprint(fingerprint, fp_length, buff, strlen(buff)))
|
|
||||||
{
|
|
||||||
/* finger print is valid: close file and exit */
|
|
||||||
my_fclose(fp, MYF(0));
|
|
||||||
DBUG_RETURN(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* No finger print matched - close file and return error */
|
|
||||||
my_fclose(fp, MYF(0));
|
|
||||||
my_set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN,
|
|
||||||
ER(CR_SSL_CONNECTION_ERROR),
|
|
||||||
"invalid finger print of server certificate");
|
|
||||||
DBUG_RETURN(1);
|
|
||||||
}
|
|
||||||
DBUG_RETURN(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
verify server certificate
|
|
||||||
|
|
||||||
SYNOPSIS
|
|
||||||
my_ssl_verify_server_cert()
|
|
||||||
MYSQL mysql
|
|
||||||
mybool verify_server_cert;
|
|
||||||
|
|
||||||
RETURN VALUES
|
|
||||||
1 Error
|
|
||||||
0 OK
|
|
||||||
*/
|
|
||||||
|
|
||||||
int my_ssl_verify_server_cert(SSL *ssl)
|
|
||||||
{
|
|
||||||
X509 *cert;
|
|
||||||
MYSQL *mysql;
|
|
||||||
char *p1, *p2, buf[256];
|
|
||||||
|
|
||||||
DBUG_ENTER("my_ssl_verify_server_cert");
|
|
||||||
|
|
||||||
mysql= (MYSQL *)SSL_get_app_data(ssl);
|
|
||||||
|
|
||||||
if (!mysql->host)
|
|
||||||
{
|
|
||||||
my_set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN,
|
|
||||||
ER(CR_SSL_CONNECTION_ERROR),
|
|
||||||
"Invalid (empty) hostname");
|
|
||||||
DBUG_RETURN(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(cert= SSL_get_peer_certificate(ssl)))
|
|
||||||
{
|
|
||||||
my_set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN,
|
|
||||||
ER(CR_SSL_CONNECTION_ERROR),
|
|
||||||
"Unable to get server certificate");
|
|
||||||
DBUG_RETURN(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
X509_NAME_oneline(X509_get_subject_name(cert), buf, 256);
|
|
||||||
X509_free(cert);
|
|
||||||
|
|
||||||
/* Extract the server name from buffer:
|
|
||||||
Format: ....CN=/hostname/.... */
|
|
||||||
if ((p1= strstr(buf, "/CN=")))
|
|
||||||
{
|
|
||||||
p1+= 4;
|
|
||||||
if ((p2= strchr(p1, '/')))
|
|
||||||
*p2= 0;
|
|
||||||
if (!strcmp(mysql->host, p1))
|
|
||||||
DBUG_RETURN(0);
|
|
||||||
}
|
|
||||||
my_set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN,
|
|
||||||
ER(CR_SSL_CONNECTION_ERROR),
|
|
||||||
"Validation of SSL server certificate failed");
|
|
||||||
DBUG_RETURN(1);
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
write to ssl socket
|
|
||||||
|
|
||||||
SYNOPSIS
|
|
||||||
my_ssl_write()
|
|
||||||
vio vio
|
|
||||||
buf write buffer
|
|
||||||
size size of buffer
|
|
||||||
|
|
||||||
RETURN VALUES
|
|
||||||
bytes written
|
|
||||||
*/
|
|
||||||
size_t my_ssl_write(Vio *vio, const uchar* buf, size_t size)
|
|
||||||
{
|
|
||||||
size_t written;
|
|
||||||
DBUG_ENTER("my_ssl_write");
|
|
||||||
if (vio->async_context && vio->async_context->active)
|
|
||||||
written= my_ssl_write_async(vio->async_context, (SSL *)vio->ssl, buf,
|
|
||||||
size);
|
|
||||||
else
|
|
||||||
written= SSL_write((SSL*) vio->ssl, buf, size);
|
|
||||||
DBUG_RETURN(written);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
read from ssl socket
|
|
||||||
|
|
||||||
SYNOPSIS
|
|
||||||
my_ssl_read()
|
|
||||||
vio vio
|
|
||||||
buf read buffer
|
|
||||||
size_t max number of bytes to read
|
|
||||||
|
|
||||||
RETURN VALUES
|
|
||||||
number of bytes read
|
|
||||||
*/
|
|
||||||
size_t my_ssl_read(Vio *vio, uchar* buf, size_t size)
|
|
||||||
{
|
|
||||||
size_t read;
|
|
||||||
DBUG_ENTER("my_ssl_read");
|
|
||||||
|
|
||||||
if (vio->async_context && vio->async_context->active)
|
|
||||||
read= my_ssl_read_async(vio->async_context, (SSL *)vio->ssl, buf, size);
|
|
||||||
else
|
|
||||||
read= SSL_read((SSL*) vio->ssl, buf, size);
|
|
||||||
DBUG_RETURN(read);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
close ssl connection and free
|
|
||||||
ssl object
|
|
||||||
|
|
||||||
SYNOPSIS
|
|
||||||
my_ssl_close()
|
|
||||||
vio vio
|
|
||||||
|
|
||||||
RETURN VALUES
|
|
||||||
1 ok
|
|
||||||
0 or -1 on error
|
|
||||||
*/
|
|
||||||
int my_ssl_close(Vio *vio)
|
|
||||||
{
|
|
||||||
int i, rc;
|
|
||||||
DBUG_ENTER("my_ssl_close");
|
|
||||||
|
|
||||||
if (!vio || !vio->ssl)
|
|
||||||
DBUG_RETURN(1);
|
|
||||||
|
|
||||||
SSL_set_quiet_shutdown(vio->ssl, 1);
|
|
||||||
/* 2 x pending + 2 * data = 4 */
|
|
||||||
for (i=0; i < 4; i++)
|
|
||||||
if ((rc= SSL_shutdown(vio->ssl)))
|
|
||||||
break;
|
|
||||||
|
|
||||||
SSL_free(vio->ssl);
|
|
||||||
vio->ssl= NULL;
|
|
||||||
|
|
||||||
DBUG_RETURN(rc);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* HAVE_OPENSSL */
|
|
@@ -49,6 +49,7 @@
|
|||||||
|
|
||||||
/* Errors should be handled via cio callback function */
|
/* Errors should be handled via cio callback function */
|
||||||
my_bool ma_ssl_initialized= FALSE;
|
my_bool ma_ssl_initialized= FALSE;
|
||||||
|
unsigned int mariadb_deinitialize_ssl= 1;
|
||||||
|
|
||||||
MARIADB_SSL *ma_cio_ssl_init(MYSQL *mysql)
|
MARIADB_SSL *ma_cio_ssl_init(MYSQL *mysql)
|
||||||
{
|
{
|
||||||
@@ -106,10 +107,14 @@ const char *ma_cio_ssl_cipher(MARIADB_SSL *cssl)
|
|||||||
static my_bool ma_cio_ssl_compare_fp(char *fp1, unsigned int fp1_len,
|
static my_bool ma_cio_ssl_compare_fp(char *fp1, unsigned int fp1_len,
|
||||||
char *fp2, unsigned int fp2_len)
|
char *fp2, unsigned int fp2_len)
|
||||||
{
|
{
|
||||||
char hexstr[fp1_len * 2 + 1];
|
char hexstr[64];
|
||||||
|
|
||||||
fp1_len= (unsigned int)mysql_hex_string(hexstr, fp1, fp1_len);
|
fp1_len= (unsigned int)mysql_hex_string(hexstr, fp1, fp1_len);
|
||||||
|
#ifdef WIN32
|
||||||
|
if (strnicmp(hexstr, fp2, fp1_len) != 0)
|
||||||
|
#else
|
||||||
if (strncasecmp(hexstr, fp2, fp1_len) != 0)
|
if (strncasecmp(hexstr, fp2, fp1_len) != 0)
|
||||||
|
#endif
|
||||||
return 1;
|
return 1;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -121,9 +126,8 @@ my_bool ma_cio_ssl_check_fp(MARIADB_SSL *cssl, const char *fp, const char *fp_li
|
|||||||
MYSQL *mysql;
|
MYSQL *mysql;
|
||||||
my_bool rc=1;
|
my_bool rc=1;
|
||||||
|
|
||||||
if (ma_ssl_get_finger_print(cssl, cert_fp, cert_fp_len) < 1)
|
if ((cert_fp_len= ma_ssl_get_finger_print(cssl, cert_fp, cert_fp_len)) < 1)
|
||||||
goto end;
|
goto end;
|
||||||
|
|
||||||
if (fp)
|
if (fp)
|
||||||
rc= ma_cio_ssl_compare_fp(cert_fp, cert_fp_len, fp, strlen(fp));
|
rc= ma_cio_ssl_compare_fp(cert_fp, cert_fp_len, fp, strlen(fp));
|
||||||
else if (fp_list)
|
else if (fp_list)
|
||||||
|
@@ -77,7 +77,14 @@ gptr my_memdup(const unsigned char *from, size_t length, myf MyFlags)
|
|||||||
my_string my_strdup(const char *from, myf MyFlags)
|
my_string my_strdup(const char *from, myf MyFlags)
|
||||||
{
|
{
|
||||||
gptr ptr;
|
gptr ptr;
|
||||||
uint length=(uint) strlen(from)+1;
|
uint length;
|
||||||
|
|
||||||
|
if (MyFlags & MY_ALLOW_ZERO_PTR)
|
||||||
|
if (!from)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
length=(uint) strlen(from)+1;
|
||||||
|
|
||||||
if ((ptr=my_malloc(length,MyFlags)) != 0)
|
if ((ptr=my_malloc(length,MyFlags)) != 0)
|
||||||
memcpy((unsigned char*) ptr, (unsigned char*) from,(size_t) length);
|
memcpy((unsigned char*) ptr, (unsigned char*) from,(size_t) length);
|
||||||
return((my_string) ptr);
|
return((my_string) ptr);
|
||||||
|
@@ -386,7 +386,7 @@ unsigned int ma_ssl_get_finger_print(MARIADB_SSL *cssl, unsigned char *fp, unsig
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (gnutls_fingerprint(GNUTLS_DIG_MD5, &cert_list[0], fp, &fp_len) > 0)
|
if (gnutls_fingerprint(GNUTLS_DIG_SHA1, &cert_list[0], fp, &fp_len) == 0)
|
||||||
return fp_len;
|
return fp_len;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@@ -20,8 +20,75 @@
|
|||||||
|
|
||||||
*************************************************************************************/
|
*************************************************************************************/
|
||||||
#include "ma_schannel.h"
|
#include "ma_schannel.h"
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
#define SC_IO_BUFFER_SIZE 0x4000
|
#define SC_IO_BUFFER_SIZE 0x4000
|
||||||
|
#define MAX_SSL_ERR_LEN 100
|
||||||
|
|
||||||
|
#define SCHANNEL_PAYLOAD(A) (A).cbMaximumMessage - (A).cbHeader - (A).cbTrailer
|
||||||
|
|
||||||
|
/* {{{ void ma_schannel_set_sec_error */
|
||||||
|
void ma_schannel_set_sec_error(MARIADB_CIO *cio, DWORD ErrorNo)
|
||||||
|
{
|
||||||
|
MYSQL *mysql= cio->mysql;
|
||||||
|
switch(ErrorNo) {
|
||||||
|
case SEC_E_UNTRUSTED_ROOT:
|
||||||
|
cio->set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, "Untrusted root certificate");
|
||||||
|
break;
|
||||||
|
case SEC_E_BUFFER_TOO_SMALL:
|
||||||
|
cio->set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, "Buffer too small");
|
||||||
|
break;
|
||||||
|
case SEC_E_CRYPTO_SYSTEM_INVALID:
|
||||||
|
cio->set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, "Cipher is not supported");
|
||||||
|
break;
|
||||||
|
case SEC_E_INSUFFICIENT_MEMORY:
|
||||||
|
cio->set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, "Out of memory");
|
||||||
|
break;
|
||||||
|
case SEC_E_OUT_OF_SEQUENCE:
|
||||||
|
cio->set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, "Invalid message sequence");
|
||||||
|
break;
|
||||||
|
case SEC_E_DECRYPT_FAILURE:
|
||||||
|
cio->set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, "An error occured during decrypting data");
|
||||||
|
break;
|
||||||
|
case SEC_I_INCOMPLETE_CREDENTIALS:
|
||||||
|
cio->set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, "Incomplete credentials");
|
||||||
|
break;
|
||||||
|
case SEC_E_ENCRYPT_FAILURE:
|
||||||
|
cio->set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, "An error occured during encrypting data");
|
||||||
|
break;
|
||||||
|
case SEC_I_CONTEXT_EXPIRED:
|
||||||
|
cio->set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, "Context expired: ");
|
||||||
|
case SEC_E_OK:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
cio->set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, "Unknown SSL error (%d)", ErrorNo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* }}} */
|
||||||
|
|
||||||
|
/* {{{ void ma_schnnel_set_win_error */
|
||||||
|
void ma_schannel_set_win_error(MARIADB_CIO *cio)
|
||||||
|
{
|
||||||
|
ulong ssl_errno= GetLastError();
|
||||||
|
char ssl_error[MAX_SSL_ERR_LEN];
|
||||||
|
char *ssl_error_reason= NULL;
|
||||||
|
|
||||||
|
if (!ssl_errno)
|
||||||
|
{
|
||||||
|
cio->set_error(cio->mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, "Unknown SSL error");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
/* todo: obtain error messge */
|
||||||
|
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||||
|
NULL, ssl_errno, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||||||
|
(LPTSTR) &ssl_error_reason, 0, NULL );
|
||||||
|
cio->set_error(cio->mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, ssl_error_reason);
|
||||||
|
|
||||||
|
if (ssl_error_reason)
|
||||||
|
LocalFree(ssl_error_reason);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
/* }}} */
|
||||||
|
|
||||||
/* {{{ LPBYTE ma_schannel_load_pem(const char *PemFileName, DWORD *buffer_len) */
|
/* {{{ LPBYTE ma_schannel_load_pem(const char *PemFileName, DWORD *buffer_len) */
|
||||||
/*
|
/*
|
||||||
@@ -44,7 +111,7 @@
|
|||||||
LPBYTE * a pointer to a binary der object
|
LPBYTE * a pointer to a binary der object
|
||||||
buffer_len will contain the length of binary der object
|
buffer_len will contain the length of binary der object
|
||||||
*/
|
*/
|
||||||
static LPBYTE ma_schannel_load_pem(const char *PemFileName, DWORD *buffer_len)
|
static LPBYTE ma_schannel_load_pem(MARIADB_CIO *cio, const char *PemFileName, DWORD *buffer_len)
|
||||||
{
|
{
|
||||||
HANDLE hfile;
|
HANDLE hfile;
|
||||||
char *buffer= NULL;
|
char *buffer= NULL;
|
||||||
@@ -57,32 +124,53 @@ static LPBYTE ma_schannel_load_pem(const char *PemFileName, DWORD *buffer_len)
|
|||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
|
||||||
if ((hfile= CreateFile(PemFileName, GENERIC_READ, 0, NULL, OPEN_EXISTING,
|
if ((hfile= CreateFile(PemFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING,
|
||||||
FILE_ATTRIBUTE_NORMAL, NULL )) == INVALID_HANDLE_VALUE)
|
FILE_ATTRIBUTE_NORMAL, NULL )) == INVALID_HANDLE_VALUE)
|
||||||
|
{
|
||||||
|
ma_schannel_set_win_error(cio);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
if (!(*buffer_len = GetFileSize(hfile, NULL)))
|
if (!(*buffer_len = GetFileSize(hfile, NULL)))
|
||||||
|
{
|
||||||
|
cio->set_error(cio->mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, "Invalid pem format");
|
||||||
goto end;
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
if (!(buffer= LocalAlloc(0, *buffer_len + 1)))
|
if (!(buffer= LocalAlloc(0, *buffer_len + 1)))
|
||||||
|
{
|
||||||
|
cio->set_error(cio->mysql, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, NULL);
|
||||||
goto end;
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
if (!ReadFile(hfile, buffer, *buffer_len, &dwBytesRead, NULL))
|
if (!ReadFile(hfile, buffer, *buffer_len, &dwBytesRead, NULL))
|
||||||
|
{
|
||||||
|
ma_schannel_set_win_error(cio);
|
||||||
goto end;
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
CloseHandle(hfile);
|
CloseHandle(hfile);
|
||||||
|
|
||||||
/* calculate the length of DER binary */
|
/* calculate the length of DER binary */
|
||||||
if (!CryptStringToBinaryA(buffer, *buffer_len, CRYPT_STRING_BASE64HEADER,
|
if (!CryptStringToBinaryA(buffer, *buffer_len, CRYPT_STRING_BASE64HEADER,
|
||||||
NULL, &der_buffer_length, NULL, NULL))
|
NULL, &der_buffer_length, NULL, NULL))
|
||||||
|
{
|
||||||
|
ma_schannel_set_win_error(cio);
|
||||||
goto end;
|
goto end;
|
||||||
|
}
|
||||||
/* allocate DER binary buffer */
|
/* allocate DER binary buffer */
|
||||||
if (!(der_buffer= (LPBYTE)LocalAlloc(0, der_buffer_length)))
|
if (!(der_buffer= (LPBYTE)LocalAlloc(0, der_buffer_length)))
|
||||||
|
{
|
||||||
|
cio->set_error(cio->mysql, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, NULL);
|
||||||
goto end;
|
goto end;
|
||||||
|
}
|
||||||
/* convert to DER binary */
|
/* convert to DER binary */
|
||||||
if (!CryptStringToBinaryA(buffer, *buffer_len, CRYPT_STRING_BASE64HEADER,
|
if (!CryptStringToBinaryA(buffer, *buffer_len, CRYPT_STRING_BASE64HEADER,
|
||||||
der_buffer, &der_buffer_length, NULL, NULL))
|
der_buffer, &der_buffer_length, NULL, NULL))
|
||||||
|
{
|
||||||
|
ma_schannel_set_win_error(cio);
|
||||||
goto end;
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
*buffer_len= der_buffer_length;
|
*buffer_len= der_buffer_length;
|
||||||
LocalFree(buffer);
|
LocalFree(buffer);
|
||||||
@@ -101,12 +189,13 @@ end:
|
|||||||
}
|
}
|
||||||
/* }}} */
|
/* }}} */
|
||||||
|
|
||||||
/* {{{ CERT_CONTEXT *ma_schannel_create_cert_context(const char *pem_file) */
|
/* {{{ CERT_CONTEXT *ma_schannel_create_cert_context(MARIADB_CIO *cio, const char *pem_file) */
|
||||||
/*
|
/*
|
||||||
Create a certification context from ca or cert file
|
Create a certification context from ca or cert file
|
||||||
|
|
||||||
SYNOPSIS
|
SYNOPSIS
|
||||||
ma_schannel_create_cert_context()
|
ma_schannel_create_cert_context()
|
||||||
|
cio cio object
|
||||||
pem_file name of certificate or ca file
|
pem_file name of certificate or ca file
|
||||||
|
|
||||||
DESCRIPTION
|
DESCRIPTION
|
||||||
@@ -119,7 +208,7 @@ end:
|
|||||||
NULL If loading of the file or creating context failed
|
NULL If loading of the file or creating context failed
|
||||||
CERT_CONTEXT * A pointer to a certification context structure
|
CERT_CONTEXT * A pointer to a certification context structure
|
||||||
*/
|
*/
|
||||||
CERT_CONTEXT *ma_schannel_create_cert_context(const char *pem_file)
|
CERT_CONTEXT *ma_schannel_create_cert_context(MARIADB_CIO *cio, const char *pem_file)
|
||||||
{
|
{
|
||||||
DWORD der_buffer_length;
|
DWORD der_buffer_length;
|
||||||
LPBYTE der_buffer= NULL;
|
LPBYTE der_buffer= NULL;
|
||||||
@@ -127,10 +216,12 @@ CERT_CONTEXT *ma_schannel_create_cert_context(const char *pem_file)
|
|||||||
CERT_CONTEXT *ctx= NULL;
|
CERT_CONTEXT *ctx= NULL;
|
||||||
|
|
||||||
/* create DER binary object from ca/certification file */
|
/* create DER binary object from ca/certification file */
|
||||||
if (!(der_buffer= ma_schannel_load_pem(pem_file, (DWORD *)&der_buffer_length)))
|
if (!(der_buffer= ma_schannel_load_pem(cio, pem_file, (DWORD *)&der_buffer_length)))
|
||||||
goto end;
|
goto end;
|
||||||
ctx= CertCreateCertificateContext(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
|
if (!(ctx= CertCreateCertificateContext(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
|
||||||
der_buffer, der_buffer_length);
|
der_buffer, der_buffer_length)))
|
||||||
|
ma_schannel_set_win_error(cio);
|
||||||
|
|
||||||
end:
|
end:
|
||||||
if (der_buffer)
|
if (der_buffer)
|
||||||
LocalFree(der_buffer);
|
LocalFree(der_buffer);
|
||||||
@@ -138,7 +229,7 @@ end:
|
|||||||
}
|
}
|
||||||
/* }}} */
|
/* }}} */
|
||||||
|
|
||||||
/* {{{ PCCRL_CONTEXT ma_schannel_create_crl_context(const char *pem_file) */
|
/* {{{ PCCRL_CONTEXT ma_schannel_create_crl_context(MARIADB_CIO *cio, const char *pem_file) */
|
||||||
/*
|
/*
|
||||||
Create a crl context from crlfile
|
Create a crl context from crlfile
|
||||||
|
|
||||||
@@ -156,7 +247,7 @@ end:
|
|||||||
NULL If loading of the file or creating context failed
|
NULL If loading of the file or creating context failed
|
||||||
PCCRL_CONTEXT A pointer to a certification context structure
|
PCCRL_CONTEXT A pointer to a certification context structure
|
||||||
*/
|
*/
|
||||||
PCCRL_CONTEXT ma_schannel_create_crl_context(const char *pem_file)
|
PCCRL_CONTEXT ma_schannel_create_crl_context(MARIADB_CIO *cio, const char *pem_file)
|
||||||
{
|
{
|
||||||
DWORD der_buffer_length;
|
DWORD der_buffer_length;
|
||||||
LPBYTE der_buffer= NULL;
|
LPBYTE der_buffer= NULL;
|
||||||
@@ -164,10 +255,11 @@ PCCRL_CONTEXT ma_schannel_create_crl_context(const char *pem_file)
|
|||||||
PCCRL_CONTEXT ctx= NULL;
|
PCCRL_CONTEXT ctx= NULL;
|
||||||
|
|
||||||
/* load ca pem file into memory */
|
/* load ca pem file into memory */
|
||||||
if (!(der_buffer= ma_schannel_load_pem(pem_file, (DWORD *)&der_buffer_length)))
|
if (!(der_buffer= ma_schannel_load_pem(cio, pem_file, (DWORD *)&der_buffer_length)))
|
||||||
goto end;
|
goto end;
|
||||||
ctx= CertCreateCRLContext(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
|
if (!(ctx= CertCreateCRLContext(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
|
||||||
der_buffer, der_buffer_length);
|
der_buffer, der_buffer_length)))
|
||||||
|
ma_schannel_set_win_error(cio);
|
||||||
end:
|
end:
|
||||||
if (der_buffer)
|
if (der_buffer)
|
||||||
LocalFree(der_buffer);
|
LocalFree(der_buffer);
|
||||||
@@ -175,7 +267,7 @@ end:
|
|||||||
}
|
}
|
||||||
/* }}} */
|
/* }}} */
|
||||||
|
|
||||||
/* {{{ my_bool ma_schannel_load_private_key(CERT_CONTEXT *ctx, char *key_file) */
|
/* {{{ my_bool ma_schannel_load_private_key(MARIADB_CIO *cio, CERT_CONTEXT *ctx, char *key_file) */
|
||||||
/*
|
/*
|
||||||
Load privte key into context
|
Load privte key into context
|
||||||
|
|
||||||
@@ -195,7 +287,7 @@ end:
|
|||||||
PCCRL_CONTEXT A pointer to a certification context structure
|
PCCRL_CONTEXT A pointer to a certification context structure
|
||||||
*/
|
*/
|
||||||
|
|
||||||
my_bool ma_schannel_load_private_key(CERT_CONTEXT *ctx, char *key_file)
|
my_bool ma_schannel_load_private_key(MARIADB_CIO *cio, CERT_CONTEXT *ctx, char *key_file)
|
||||||
{
|
{
|
||||||
DWORD der_buffer_len= 0;
|
DWORD der_buffer_len= 0;
|
||||||
LPBYTE der_buffer= NULL;
|
LPBYTE der_buffer= NULL;
|
||||||
@@ -203,11 +295,11 @@ my_bool ma_schannel_load_private_key(CERT_CONTEXT *ctx, char *key_file)
|
|||||||
LPBYTE priv_key= NULL;
|
LPBYTE priv_key= NULL;
|
||||||
HCRYPTPROV crypt_prov= NULL;
|
HCRYPTPROV crypt_prov= NULL;
|
||||||
HCRYPTKEY crypt_key= NULL;
|
HCRYPTKEY crypt_key= NULL;
|
||||||
CRYPT_KEY_PROV_INFO kpi;
|
CERT_KEY_CONTEXT kpi;
|
||||||
my_bool rc= 0;
|
my_bool rc= 0;
|
||||||
|
|
||||||
/* load private key into der binary object */
|
/* load private key into der binary object */
|
||||||
if (!(der_buffer= ma_schannel_load_pem(key_file, &der_buffer_len)))
|
if (!(der_buffer= ma_schannel_load_pem(cio, key_file, &der_buffer_len)))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/* determine required buffer size for decoded private key */
|
/* determine required buffer size for decoded private key */
|
||||||
@@ -216,11 +308,17 @@ my_bool ma_schannel_load_private_key(CERT_CONTEXT *ctx, char *key_file)
|
|||||||
der_buffer, der_buffer_len,
|
der_buffer, der_buffer_len,
|
||||||
0, NULL,
|
0, NULL,
|
||||||
NULL, &priv_key_len))
|
NULL, &priv_key_len))
|
||||||
|
{
|
||||||
|
ma_schannel_set_win_error(cio);
|
||||||
goto end;
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
/* allocate buffer for decoded private key */
|
/* allocate buffer for decoded private key */
|
||||||
if (!(priv_key= LocalAlloc(0, priv_key_len)))
|
if (!(priv_key= LocalAlloc(0, priv_key_len)))
|
||||||
|
{
|
||||||
|
cio->set_error(cio->mysql, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, NULL);
|
||||||
goto end;
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
/* decode */
|
/* decode */
|
||||||
if (!CryptDecodeObjectEx(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
|
if (!CryptDecodeObjectEx(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
|
||||||
@@ -228,24 +326,37 @@ my_bool ma_schannel_load_private_key(CERT_CONTEXT *ctx, char *key_file)
|
|||||||
der_buffer, der_buffer_len,
|
der_buffer, der_buffer_len,
|
||||||
0, NULL,
|
0, NULL,
|
||||||
priv_key, &priv_key_len))
|
priv_key, &priv_key_len))
|
||||||
|
{
|
||||||
|
ma_schannel_set_win_error(cio);
|
||||||
goto end;
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
/* Acquire context */
|
/* Acquire context:
|
||||||
|
If cio_schannel context doesn't exist, create a new one */
|
||||||
if (!CryptAcquireContext(&crypt_prov, "cio_schannel", MS_ENHANCED_PROV, PROV_RSA_FULL, 0))
|
if (!CryptAcquireContext(&crypt_prov, "cio_schannel", MS_ENHANCED_PROV, PROV_RSA_FULL, 0))
|
||||||
|
if (!CryptAcquireContext(&crypt_prov, "cio_schannel", MS_ENHANCED_PROV, PROV_RSA_FULL, CRYPT_NEWKEYSET))
|
||||||
|
{
|
||||||
|
ma_schannel_set_win_error(cio);
|
||||||
goto end;
|
goto end;
|
||||||
|
}
|
||||||
/* ... and import the private key */
|
/* ... and import the private key */
|
||||||
if (!CryptImportKey(crypt_prov, priv_key, priv_key_len, NULL, 0, &crypt_key))
|
if (!CryptImportKey(crypt_prov, priv_key, priv_key_len, NULL, 0, &crypt_key))
|
||||||
|
{
|
||||||
|
ma_schannel_set_win_error(cio);
|
||||||
goto end;
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
SecureZeroMemory(&kpi, sizeof(kpi));
|
SecureZeroMemory(&kpi, sizeof(kpi));
|
||||||
kpi.pwszContainerName = "cio-schanel";
|
kpi.hCryptProv= crypt_prov;
|
||||||
kpi.dwKeySpec = AT_KEYEXCHANGE;
|
kpi.dwKeySpec = AT_KEYEXCHANGE;
|
||||||
kpi.dwFlags = CRYPT_MACHINE_KEYSET;
|
kpi.cbSize= sizeof(kpi);
|
||||||
|
|
||||||
/* assign private key to certificate context */
|
/* assign private key to certificate context */
|
||||||
if (CertSetCertificateContextProperty(ctx, CERT_KEY_PROV_INFO_PROP_ID, 0, &kpi))
|
if (CertSetCertificateContextProperty(ctx, CERT_KEY_CONTEXT_PROP_ID, 0, &kpi))
|
||||||
rc= 1;
|
rc= 1;
|
||||||
|
else
|
||||||
|
ma_schannel_set_win_error(cio);
|
||||||
|
|
||||||
end:
|
end:
|
||||||
if (der_buffer)
|
if (der_buffer)
|
||||||
LocalFree(der_buffer);
|
LocalFree(der_buffer);
|
||||||
@@ -285,7 +396,7 @@ SECURITY_STATUS ma_schannel_handshake_loop(MARIADB_CIO *cio, my_bool InitialRead
|
|||||||
PUCHAR IoBuffer;
|
PUCHAR IoBuffer;
|
||||||
BOOL fDoRead;
|
BOOL fDoRead;
|
||||||
MARIADB_SSL *cssl= cio->cssl;
|
MARIADB_SSL *cssl= cio->cssl;
|
||||||
SC_CTX *sctx= (SC_CTX *)cssl->data;
|
SC_CTX *sctx= (SC_CTX *)cssl->ssl;
|
||||||
|
|
||||||
|
|
||||||
dwSSPIFlags = ISC_REQ_SEQUENCE_DETECT |
|
dwSSPIFlags = ISC_REQ_SEQUENCE_DETECT |
|
||||||
@@ -416,6 +527,7 @@ SECURITY_STATUS ma_schannel_handshake_loop(MARIADB_CIO *cio, my_bool InitialRead
|
|||||||
pExtraData->cbBuffer= 0;
|
pExtraData->cbBuffer= 0;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SEC_I_INCOMPLETE_CREDENTIALS:
|
case SEC_I_INCOMPLETE_CREDENTIALS:
|
||||||
/* Provided credentials didn't contain a valid client certificate.
|
/* Provided credentials didn't contain a valid client certificate.
|
||||||
We will try to connect anonymously, using current credentials */
|
We will try to connect anonymously, using current credentials */
|
||||||
@@ -425,7 +537,10 @@ SECURITY_STATUS ma_schannel_handshake_loop(MARIADB_CIO *cio, my_bool InitialRead
|
|||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
if (FAILED(rc))
|
if (FAILED(rc))
|
||||||
|
{
|
||||||
|
ma_schannel_set_sec_error(cio, rc);
|
||||||
goto loopend;
|
goto loopend;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -472,22 +587,24 @@ SECURITY_STATUS ma_schannel_client_handshake(MARIADB_SSL *cssl)
|
|||||||
SecBuffer ExtraData;
|
SecBuffer ExtraData;
|
||||||
DWORD SFlags= ISC_REQ_SEQUENCE_DETECT | ISC_REQ_REPLAY_DETECT |
|
DWORD SFlags= ISC_REQ_SEQUENCE_DETECT | ISC_REQ_REPLAY_DETECT |
|
||||||
ISC_REQ_CONFIDENTIALITY | ISC_RET_EXTENDED_ERROR |
|
ISC_REQ_CONFIDENTIALITY | ISC_RET_EXTENDED_ERROR |
|
||||||
|
ISC_REQ_USE_SUPPLIED_CREDS |
|
||||||
ISC_REQ_ALLOCATE_MEMORY | ISC_REQ_STREAM;
|
ISC_REQ_ALLOCATE_MEMORY | ISC_REQ_STREAM;
|
||||||
|
|
||||||
SecBufferDesc BufferIn, BufferOut;
|
SecBufferDesc BufferIn, BufferOut;
|
||||||
SecBuffer BuffersOut[1], BuffersIn[2];
|
SecBuffer BuffersOut[1], BuffersIn[2];
|
||||||
|
|
||||||
if (!cssl || !cssl->cio || !cssl->data)
|
if (!cssl || !cssl->cio)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
cio= cssl->cio;
|
cio= cssl->cio;
|
||||||
sctx= (SC_CTX *)cssl->data;
|
sctx= (SC_CTX *)cssl->ssl;
|
||||||
|
|
||||||
/* Initialie securifty context */
|
/* Initialie securifty context */
|
||||||
BuffersOut[0].BufferType= SECBUFFER_TOKEN;
|
BuffersOut[0].BufferType= SECBUFFER_TOKEN;
|
||||||
BuffersOut[0].cbBuffer= 0;
|
BuffersOut[0].cbBuffer= 0;
|
||||||
BuffersOut[0].pvBuffer= NULL;
|
BuffersOut[0].pvBuffer= NULL;
|
||||||
|
|
||||||
|
|
||||||
BufferOut.cBuffers= 1;
|
BufferOut.cBuffers= 1;
|
||||||
BufferOut.pBuffers= BuffersOut;
|
BufferOut.pBuffers= BuffersOut;
|
||||||
BufferOut.ulVersion= SECBUFFER_VERSION;
|
BufferOut.ulVersion= SECBUFFER_VERSION;
|
||||||
@@ -506,7 +623,18 @@ SECURITY_STATUS ma_schannel_client_handshake(MARIADB_SSL *cssl)
|
|||||||
NULL);
|
NULL);
|
||||||
|
|
||||||
if(sRet != SEC_I_CONTINUE_NEEDED)
|
if(sRet != SEC_I_CONTINUE_NEEDED)
|
||||||
|
{
|
||||||
|
ma_schannel_set_sec_error(cio, sRet);
|
||||||
return sRet;
|
return sRet;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Allocate IO-Buffer */
|
||||||
|
sctx->IoBufferSize= 2 * net_buffer_length;
|
||||||
|
if (!(sctx->IoBuffer= (PUCHAR)LocalAlloc(LMEM_ZEROINIT, sctx->IoBufferSize)))
|
||||||
|
{
|
||||||
|
sRet= SEC_E_INSUFFICIENT_MEMORY;
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
/* send client hello packaet */
|
/* send client hello packaet */
|
||||||
if(BuffersOut[0].cbBuffer != 0 && BuffersOut[0].pvBuffer != NULL)
|
if(BuffersOut[0].cbBuffer != 0 && BuffersOut[0].pvBuffer != NULL)
|
||||||
@@ -518,51 +646,26 @@ SECURITY_STATUS ma_schannel_client_handshake(MARIADB_SSL *cssl)
|
|||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ma_schannel_handshake_loop(cio, TRUE, &ExtraData);
|
sRet= ma_schannel_handshake_loop(cio, TRUE, &ExtraData);
|
||||||
|
|
||||||
|
/* Reallocate IO-Buffer for write operations: After handshake
|
||||||
|
was successfull, we are able now to calculate payload */
|
||||||
|
QueryContextAttributes( &sctx->ctxt, SECPKG_ATTR_STREAM_SIZES, &sctx->Sizes );
|
||||||
|
sctx->IoBufferSize= SCHANNEL_PAYLOAD(sctx->Sizes);
|
||||||
|
sctx->IoBuffer= LocalReAlloc(sctx->IoBuffer, sctx->IoBufferSize, LMEM_ZEROINIT);
|
||||||
|
|
||||||
|
return sRet;
|
||||||
end:
|
end:
|
||||||
|
LocalFree(sctx->IoBuffer);
|
||||||
|
sctx->IoBufferSize= 0;
|
||||||
FreeContextBuffer(BuffersOut[0].pvBuffer);
|
FreeContextBuffer(BuffersOut[0].pvBuffer);
|
||||||
DeleteSecurityContext(&sctx->ctxt);
|
DeleteSecurityContext(&sctx->ctxt);
|
||||||
return sRet;
|
return sRet;
|
||||||
}
|
}
|
||||||
/* }}} */
|
/* }}} */
|
||||||
|
|
||||||
/* {{{ static PUCHAR ma_schannel_alloc_iobuffer(CtxtHandle *Context, DWORD *BufferLength) */
|
/* {{{ SECURITY_STATUS ma_schannel_read_decrypt(MARIADB_CIO *cio, PCredHandle phCreds, CtxtHandle * phContext,
|
||||||
/*
|
DWORD DecryptLength, uchar *ReadBuffer, DWORD ReadBufferSize) */
|
||||||
alloates an IO Buffer for ssl communication
|
|
||||||
|
|
||||||
SYNOPSUS
|
|
||||||
ma_schannel_alloc_iobuffer()
|
|
||||||
Context SChannel context handle
|
|
||||||
BufferLength a pointer for the buffer length
|
|
||||||
|
|
||||||
DESCRIPTION
|
|
||||||
calculates the required buffer length and allocates a memory buffer for en- and
|
|
||||||
decryption. The calculated buffer length will be returned in BufferLength pointer.
|
|
||||||
The allocated buffer needs to be freed at end of the connection.
|
|
||||||
|
|
||||||
RETURN
|
|
||||||
NULL if an error occured
|
|
||||||
PUCHAR an IO Buffer
|
|
||||||
*/
|
|
||||||
static PUCHAR ma_schannel_alloc_iobuffer(CtxtHandle *Context, DWORD *BufferLength)
|
|
||||||
{
|
|
||||||
SecPkgContext_StreamSizes StreamSizes;
|
|
||||||
|
|
||||||
PUCHAR Buffer= NULL;
|
|
||||||
|
|
||||||
if (!BufferLength || QueryContextAttributes(Context, SECPKG_ATTR_STREAM_SIZES, &StreamSizes) != SEC_E_OK)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
/* Calculate BufferLength */
|
|
||||||
*BufferLength= StreamSizes.cbHeader + StreamSizes.cbTrailer + StreamSizes.cbMaximumMessage;
|
|
||||||
|
|
||||||
Buffer= LocalAlloc(LMEM_FIXED, *BufferLength);
|
|
||||||
return Buffer;
|
|
||||||
}
|
|
||||||
/* }}} */
|
|
||||||
|
|
||||||
/* {{{ SECURITY_STATUS ma_schannel_read(MARIADB_CIO *cio, PCredHandle phCreds, CtxtHandle * phContext) */
|
|
||||||
/*
|
/*
|
||||||
Reads encrypted data from a SSL stream and decrypts it.
|
Reads encrypted data from a SSL stream and decrypts it.
|
||||||
|
|
||||||
@@ -583,44 +686,34 @@ static PUCHAR ma_schannel_alloc_iobuffer(CtxtHandle *Context, DWORD *BufferLengt
|
|||||||
SEC_E_* if an error occured
|
SEC_E_* if an error occured
|
||||||
*/
|
*/
|
||||||
|
|
||||||
SECURITY_STATUS ma_schannel_read(MARIADB_CIO *cio,
|
SECURITY_STATUS ma_schannel_read_decrypt(MARIADB_CIO *cio,
|
||||||
PCredHandle phCreds,
|
PCredHandle phCreds,
|
||||||
CtxtHandle * phContext,
|
CtxtHandle * phContext,
|
||||||
DWORD *DecryptLength,
|
DWORD *DecryptLength,
|
||||||
uchar *ReadBuffer,
|
uchar *ReadBuffer,
|
||||||
DWORD ReadBufferSize)
|
DWORD ReadBufferSize)
|
||||||
{
|
{
|
||||||
DWORD dwBytesRead= 0;
|
DWORD dwBytesRead= 0;
|
||||||
DWORD dwOffset= 0;
|
DWORD dwOffset= 0;
|
||||||
SC_CTX *sctx;
|
SC_CTX *sctx;
|
||||||
SECURITY_STATUS sRet= 0;
|
SECURITY_STATUS sRet= 0;
|
||||||
SecBuffersDesc Msg;
|
SecBufferDesc Msg;
|
||||||
SecBuffer Buffers[4],
|
SecBuffer Buffers[4],
|
||||||
ExtraBuffer,
|
ExtraBuffer,
|
||||||
*pData, *pExtra;
|
*pData, *pExtra;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (!cio || !cio->methods || !cio->methods->read || !cio->cssl || !cio->cssl->data | !DecryptLength)
|
if (!cio || !cio->methods || !cio->methods->read || !cio->cssl || !DecryptLength)
|
||||||
return SEC_E_INTERNAL_ERROR;
|
return SEC_E_INTERNAL_ERROR;
|
||||||
|
|
||||||
sctx= (SC_CTX *)cio->cssl->data;
|
sctx= (SC_CTX *)cio->cssl->ssl;
|
||||||
*DecryptLength= 0;
|
*DecryptLength= 0;
|
||||||
|
|
||||||
/* Allocate IoBuffer */
|
|
||||||
if (!sctx->IoBuffer)
|
|
||||||
{
|
|
||||||
if (!(sctx->IoBuffer= ma_schannel_alloc_iobuffer(&sctx->ctxt, &sctx->IoBufferSize)))
|
|
||||||
{
|
|
||||||
/* todo: error */
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
while (1)
|
while (1)
|
||||||
{
|
{
|
||||||
if (!dwOffset || sRet == SEC_E_INCOMPLETE_MESSAGE)
|
if (!dwBytesRead || sRet == SEC_E_INCOMPLETE_MESSAGE)
|
||||||
{
|
{
|
||||||
dwBytesRead= cio->methods->read(cio, sctx->IoBuffer + dwOffset, cbIoBufferLength - dwOffset);
|
dwBytesRead= cio->methods->read(cio, sctx->IoBuffer + dwOffset, sctx->IoBufferSize - dwOffset);
|
||||||
if (dwBytesRead == 0)
|
if (dwBytesRead == 0)
|
||||||
{
|
{
|
||||||
/* server closed connection */
|
/* server closed connection */
|
||||||
@@ -633,8 +726,9 @@ SECURITY_STATUS ma_schannel_read(MARIADB_CIO *cio,
|
|||||||
printf("Socket error\n");
|
printf("Socket error\n");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
dwOffset+= dwBytesRead;
|
||||||
}
|
}
|
||||||
ZeroMem(Buffers, sizeof(SecBuffer) * 4);
|
ZeroMemory(Buffers, sizeof(SecBuffer) * 4);
|
||||||
Buffers[0].pvBuffer= sctx->IoBuffer;
|
Buffers[0].pvBuffer= sctx->IoBuffer;
|
||||||
Buffers[0].cbBuffer= dwOffset;
|
Buffers[0].cbBuffer= dwOffset;
|
||||||
|
|
||||||
@@ -652,9 +746,9 @@ SECURITY_STATUS ma_schannel_read(MARIADB_CIO *cio,
|
|||||||
/* Check for possible errors: we continue in case context has
|
/* Check for possible errors: we continue in case context has
|
||||||
expired or renogitiation is required */
|
expired or renogitiation is required */
|
||||||
if (sRet != SEC_E_OK && sRet != SEC_I_CONTEXT_EXPIRED &&
|
if (sRet != SEC_E_OK && sRet != SEC_I_CONTEXT_EXPIRED &&
|
||||||
sRet != SEC_I_RENEGOTIARE)
|
sRet != SEC_I_RENEGOTIATE && sRet != SEC_E_INCOMPLETE_MESSAGE)
|
||||||
{
|
{
|
||||||
// set error
|
ma_schannel_set_sec_error(cio, sRet);
|
||||||
return sRet;
|
return sRet;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -668,11 +762,12 @@ SECURITY_STATUS ma_schannel_read(MARIADB_CIO *cio,
|
|||||||
if (pData && pExtra)
|
if (pData && pExtra)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pData && pData->cbBuffer)
|
if (pData && pData->cbBuffer)
|
||||||
{
|
{
|
||||||
memcpy(ReadBuffer + *DecrypthLength, pData->pvBuffer, pData->cbBuffer);
|
memcpy(ReadBuffer + *DecryptLength, pData->pvBuffer, pData->cbBuffer);
|
||||||
*DecryptLength+= pData->cbBuffer;
|
*DecryptLength+= pData->cbBuffer;
|
||||||
|
return sRet;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pExtra)
|
if (pExtra)
|
||||||
@@ -684,4 +779,129 @@ SECURITY_STATUS ma_schannel_read(MARIADB_CIO *cio,
|
|||||||
dwOffset= 0;
|
dwOffset= 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
my_bool ma_schannel_verify_certs(SC_CTX *sctx, DWORD dwCertFlags)
|
||||||
|
{
|
||||||
|
SECURITY_STATUS sRet;
|
||||||
|
DWORD flags;
|
||||||
|
MARIADB_CIO *cio= sctx->mysql->net.cio;
|
||||||
|
PCCERT_CONTEXT pServerCert= NULL;
|
||||||
|
|
||||||
|
if ((sRet= QueryContextAttributes(&sctx->ctxt, SECPKG_ATTR_REMOTE_CERT_CONTEXT, (PVOID)&pServerCert)) != SEC_E_OK)
|
||||||
|
{
|
||||||
|
ma_schannel_set_sec_error(cio, sRet);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
flags= CERT_STORE_SIGNATURE_FLAG |
|
||||||
|
CERT_STORE_TIME_VALIDITY_FLAG;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if (sctx->client_ca_ctx)
|
||||||
|
{
|
||||||
|
if (!(sRet= CertVerifySubjectCertificateContext(pServerCert,
|
||||||
|
sctx->client_ca_ctx,
|
||||||
|
&flags)))
|
||||||
|
{
|
||||||
|
ma_schannel_set_win_error(cio);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flags)
|
||||||
|
{
|
||||||
|
if ((flags & CERT_STORE_SIGNATURE_FLAG) != 0)
|
||||||
|
cio->set_error(sctx->mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, "Client certificate signature check failed");
|
||||||
|
else if ((flags & CERT_STORE_REVOCATION_FLAG) != 0)
|
||||||
|
cio->set_error(sctx->mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, "Client certificate was revoked");
|
||||||
|
else if ((flags & CERT_STORE_TIME_VALIDITY_FLAG) != 0)
|
||||||
|
cio->set_error(sctx->mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, "Client certificate has expired");
|
||||||
|
else
|
||||||
|
cio->set_error(sctx->mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, "Unknown error during client certificate validation");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check if none of the certificates in the certificate chain have been revoked. */
|
||||||
|
if (sctx->client_crl_ctx)
|
||||||
|
{
|
||||||
|
PCRL_INFO Info[1];
|
||||||
|
|
||||||
|
Info[0]= sctx->client_crl_ctx->pCrlInfo;
|
||||||
|
if (!(CertVerifyCRLRevocation(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
|
||||||
|
pServerCert->pCertInfo,
|
||||||
|
1, Info)) )
|
||||||
|
{
|
||||||
|
cio->set_error(cio->mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, "CRL Revocation failed");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* {{{ size_t ma_schannel_write_encrypt(MARIADB_CIO *cio, PCredHandle phCreds, CtxtHandle * phContext) */
|
||||||
|
/*
|
||||||
|
Decrypts data and write to SSL stream
|
||||||
|
SYNOPSIS
|
||||||
|
ma_schannel_write_decrypt
|
||||||
|
cio pointer to Communication IO structure
|
||||||
|
phContext a context handle
|
||||||
|
DecryptLength size of decrypted buffer
|
||||||
|
ReadBuffer Buffer for decrypted data
|
||||||
|
ReadBufferSize size of ReadBuffer
|
||||||
|
|
||||||
|
DESCRIPTION
|
||||||
|
Write encrypted data to SSL stream.
|
||||||
|
|
||||||
|
RETURN
|
||||||
|
SEC_E_OK on success
|
||||||
|
SEC_E_* if an error occured
|
||||||
|
*/
|
||||||
|
size_t ma_schannel_write_encrypt(MARIADB_CIO *cio,
|
||||||
|
uchar *WriteBuffer,
|
||||||
|
size_t WriteBufferSize)
|
||||||
|
{
|
||||||
|
SECURITY_STATUS scRet;
|
||||||
|
SecBufferDesc Message;
|
||||||
|
SecBuffer Buffers[4];
|
||||||
|
DWORD cbMessage, cbData;
|
||||||
|
PBYTE pbMessage;
|
||||||
|
SC_CTX *sctx= (SC_CTX *)cio->cssl->ssl;
|
||||||
|
size_t payload;
|
||||||
|
|
||||||
|
|
||||||
|
payload= MIN(WriteBufferSize, sctx->IoBufferSize);
|
||||||
|
|
||||||
|
memcpy(&sctx->IoBuffer[sctx->Sizes.cbHeader], WriteBuffer, payload);
|
||||||
|
pbMessage = sctx->IoBuffer + sctx->Sizes.cbHeader;
|
||||||
|
cbMessage = payload;
|
||||||
|
|
||||||
|
Buffers[0].pvBuffer = sctx->IoBuffer;
|
||||||
|
Buffers[0].cbBuffer = sctx->Sizes.cbHeader;
|
||||||
|
Buffers[0].BufferType = SECBUFFER_STREAM_HEADER; // Type of the buffer
|
||||||
|
|
||||||
|
Buffers[1].pvBuffer = &sctx->IoBuffer[sctx->Sizes.cbHeader];
|
||||||
|
Buffers[1].cbBuffer = payload;
|
||||||
|
Buffers[1].BufferType = SECBUFFER_DATA;
|
||||||
|
|
||||||
|
Buffers[2].pvBuffer = &sctx->IoBuffer[sctx->Sizes.cbHeader] + payload;
|
||||||
|
Buffers[2].cbBuffer = sctx->Sizes.cbTrailer;
|
||||||
|
Buffers[2].BufferType = SECBUFFER_STREAM_TRAILER;
|
||||||
|
|
||||||
|
Buffers[3].pvBuffer = SECBUFFER_EMPTY; // Pointer to buffer 4
|
||||||
|
Buffers[3].cbBuffer = SECBUFFER_EMPTY; // length of buffer 4
|
||||||
|
Buffers[3].BufferType = SECBUFFER_EMPTY; // Type of the buffer 4
|
||||||
|
|
||||||
|
|
||||||
|
Message.ulVersion = SECBUFFER_VERSION;
|
||||||
|
Message.cBuffers = 4;
|
||||||
|
Message.pBuffers = Buffers;
|
||||||
|
if ((scRet = EncryptMessage(&sctx->ctxt, 0, &Message, 0))!= SEC_E_OK)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (cio->methods->write(cio, sctx->IoBuffer, Buffers[0].cbBuffer + Buffers[1].cbBuffer + Buffers[2].cbBuffer))
|
||||||
|
return payload;
|
||||||
|
}
|
||||||
/* }}} */
|
/* }}} */
|
||||||
|
|
||||||
|
@@ -28,23 +28,23 @@
|
|||||||
#include <ma_common.h>
|
#include <ma_common.h>
|
||||||
#include <ma_cio.h>
|
#include <ma_cio.h>
|
||||||
#include <errmsg.h>
|
#include <errmsg.h>
|
||||||
#include <mysql/client_plugin.h>
|
|
||||||
|
|
||||||
typedef void VOID;
|
typedef void VOID;
|
||||||
|
|
||||||
#include <wincrypt.h>
|
#include <wincrypt.h>
|
||||||
#define SECURITY_WIN32
|
#include <wintrust.h>
|
||||||
|
|
||||||
|
|
||||||
#include <security.h>
|
#include <security.h>
|
||||||
|
|
||||||
#include <schnlsp.h>
|
#include <schnlsp.h>
|
||||||
#undef SECURITY_WIN32
|
#undef SECURITY_WIN32
|
||||||
#include <Windows.h>
|
#include <Windows.h>
|
||||||
|
#include <sspi.h>
|
||||||
|
|
||||||
#define SC_IO_BUFFER_SIZE 0x4000
|
#define SC_IO_BUFFER_SIZE 0x4000
|
||||||
|
|
||||||
CERT_CONTEXT *ma_schannel_create_cert_context(const char *pem_file);
|
|
||||||
SECURITY_STATUS ma_schannel_handshake_loop(MARIADB_CIO *cio, my_bool InitialRead, SecBuffer *pExtraData);
|
|
||||||
my_bool ma_schannel_load_private_key(CERT_CONTEXT *ctx, char *key_file);
|
|
||||||
PCCRL_CONTEXT ma_schannel_create_crl_context(const char *pem_file);
|
|
||||||
|
|
||||||
#ifndef HAVE_SCHANNEL_DEFAULT
|
#ifndef HAVE_SCHANNEL_DEFAULT
|
||||||
#define my_snprintf snprintf
|
#define my_snprintf snprintf
|
||||||
@@ -61,12 +61,35 @@ struct st_schannel {
|
|||||||
CredHandle CredHdl;
|
CredHandle CredHdl;
|
||||||
PUCHAR IoBuffer;
|
PUCHAR IoBuffer;
|
||||||
DWORD IoBufferSize;
|
DWORD IoBufferSize;
|
||||||
|
/* PUCHAR EncryptBuffer;
|
||||||
|
DWORD EncryptBufferSize;
|
||||||
|
DWORD EncryptBufferLength;
|
||||||
PUCHAR DecryptBuffer;
|
PUCHAR DecryptBuffer;
|
||||||
DWORD DecryptBufferSize;
|
DWORD DecryptBufferSize;
|
||||||
DWORD DecryptBufferLength;
|
DWORD DecryptBufferLength;
|
||||||
|
uchar thumbprint[21]; */
|
||||||
|
SecPkgContext_StreamSizes Sizes;
|
||||||
|
|
||||||
CtxtHandle ctxt;
|
CtxtHandle ctxt;
|
||||||
|
MYSQL *mysql;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct st_schannel SC_CTX;
|
typedef struct st_schannel SC_CTX;
|
||||||
|
|
||||||
|
CERT_CONTEXT *ma_schannel_create_cert_context(MARIADB_CIO *cio, const char *pem_file);
|
||||||
|
SECURITY_STATUS ma_schannel_handshake_loop(MARIADB_CIO *cio, my_bool InitialRead, SecBuffer *pExtraData);
|
||||||
|
my_bool ma_schannel_load_private_key(MARIADB_CIO *cio, CERT_CONTEXT *ctx, char *key_file);
|
||||||
|
PCCRL_CONTEXT ma_schannel_create_crl_context(MARIADB_CIO *cio, const char *pem_file);
|
||||||
|
my_bool ma_schannel_verify_certs(SC_CTX *sctx, DWORD dwCertFlags);
|
||||||
|
size_t ma_schannel_write_encrypt(MARIADB_CIO *cio,
|
||||||
|
uchar *WriteBuffer,
|
||||||
|
size_t WriteBufferSize);
|
||||||
|
size_t ma_schannel_read_decrypt(MARIADB_CIO *cio,
|
||||||
|
PCredHandle phCreds,
|
||||||
|
CtxtHandle * phContext,
|
||||||
|
DWORD *DecryptLength,
|
||||||
|
uchar *ReadBuffer,
|
||||||
|
DWORD ReadBufferSize);
|
||||||
|
|
||||||
|
|
||||||
#endif /* _ma_schannel_h_ */
|
#endif /* _ma_schannel_h_ */
|
||||||
|
@@ -287,10 +287,9 @@ static int ma_ssl_set_certs(MYSQL *mysql)
|
|||||||
|
|
||||||
if ((certstore= SSL_CTX_get_cert_store(SSL_context)))
|
if ((certstore= SSL_CTX_get_cert_store(SSL_context)))
|
||||||
{
|
{
|
||||||
if (X509_STORE_load_locations(certstore, mysql->options.ssl_ca,
|
if (X509_STORE_load_locations(certstore, mysql->options.extension->ssl_crl,
|
||||||
mysql->options.ssl_capath) == 0 ||
|
mysql->options.extension->ssl_crlpath) == 0 ||
|
||||||
X509_STORE_set_flags(certstore, X509_V_FLAG_CRL_CHECK |
|
X509_STORE_set_flags(certstore, X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL) == 0)
|
||||||
X509_V_FLAG_CRL_CHECK_ALL) == 0)
|
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -24,77 +24,72 @@
|
|||||||
|
|
||||||
#define VOID void
|
#define VOID void
|
||||||
|
|
||||||
static my_bool my_schannel_initialized= FALSE;
|
extern my_bool ma_ssl_initialized;
|
||||||
|
|
||||||
#define MAX_SSL_ERR_LEN 100
|
|
||||||
|
|
||||||
static pthread_mutex_t LOCK_schannel_config;
|
static pthread_mutex_t LOCK_schannel_config;
|
||||||
static pthread_mutex_t *LOCK_crypto= NULL;
|
static pthread_mutex_t *LOCK_crypto= NULL;
|
||||||
|
|
||||||
int cio_schannel_start(char *errmsg, size_t errmsg_len, int count, va_list);
|
struct st_cipher_suite {
|
||||||
int cio_schannel_end();
|
DWORD aid;
|
||||||
void *cio_schannel_init(MARIADB_SSL *cssl, MYSQL *mysql);
|
CHAR *cipher;
|
||||||
my_bool cio_schannel_connect(MARIADB_SSL *cssl);
|
|
||||||
size_t cio_schannel_read(MARIADB_SSL *cssl, const uchar* buffer, size_t length);
|
|
||||||
size_t cio_schannel_write(MARIADB_SSL *cssl, const uchar* buffer, size_t length);
|
|
||||||
my_bool cio_schannel_close(MARIADB_SSL *cssl);
|
|
||||||
int cio_schannel_verify_server_cert(MARIADB_SSL *cssl);
|
|
||||||
const char *cio_schannel_cipher(MARIADB_SSL *cssl);
|
|
||||||
|
|
||||||
struct st_ma_cio_ssl_methods cio_schannel_methods= {
|
|
||||||
cio_schannel_init,
|
|
||||||
cio_schannel_connect,
|
|
||||||
cio_schannel_read,
|
|
||||||
cio_schannel_write,
|
|
||||||
cio_schannel_close,
|
|
||||||
cio_schannel_verify_server_cert,
|
|
||||||
cio_schannel_cipher
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifndef HAVE_SCHANNEL_DEFAULT
|
void ma_schannel_set_sec_error(MARIADB_CIO *cio, DWORD ErrorNo);
|
||||||
MARIADB_CIO_PLUGIN _mysql_client_plugin_declaration_=
|
void ma_schannel_set_win_error(MYSQL *mysql);
|
||||||
#else
|
|
||||||
MARIADB_CIO_PLUGIN cio_schannel_plugin=
|
const struct st_cipher_suite sc_ciphers[]=
|
||||||
#endif
|
|
||||||
{
|
{
|
||||||
MYSQL_CLIENT_CIO_PLUGIN,
|
{CALG_3DES, "CALG_3DES"},
|
||||||
MYSQL_CLIENT_CIO_PLUGIN_INTERFACE_VERSION,
|
{CALG_3DES_112, "CALG_3DES_112"},
|
||||||
"cio_schannel",
|
{CALG_AES, "CALG_AES"},
|
||||||
"Georg Richter",
|
{CALG_AES_128, "CALG_AES_128"},
|
||||||
"MariaDB communication IO plugin for Windows SSL/SChannel communication",
|
{CALG_AES_192, "CALG_AES_192"},
|
||||||
{1, 0, 0},
|
{CALG_AES_256, "CALG_AES_256"},
|
||||||
"LGPL",
|
{CALG_AGREEDKEY_ANY, "CALG_AGREEDKEY_ANY"},
|
||||||
cio_schannel_start,
|
{CALG_CYLINK_MEK, "CALG_CYLINK_MEK"},
|
||||||
cio_schannel_end,
|
{CALG_DES, "CALG_DES"},
|
||||||
NULL,
|
{CALG_DESX, "CALG_DESX"},
|
||||||
&cio_schannel_methods,
|
{CALG_DH_EPHEM, "CALG_DH_EPHEM"},
|
||||||
NULL
|
{CALG_DH_SF, "CALG_DH_SF"},
|
||||||
|
{CALG_DSS_SIGN, "CALG_DSS_SIGN"},
|
||||||
|
{CALG_ECDH, "CALG_ECDH"},
|
||||||
|
{CALG_ECDSA, "CALG_ECDSA"},
|
||||||
|
{CALG_ECMQV, "CALG_ECMQV"},
|
||||||
|
{CALG_HASH_REPLACE_OWF, "CALG_HASH_REPLACE_OWF"},
|
||||||
|
{CALG_HUGHES_MD5, "CALG_HUGHES_MD5"},
|
||||||
|
{CALG_HMAC, "CALG_HMAC"},
|
||||||
|
{CALG_KEA_KEYX, "CALG_KEA_KEYX"},
|
||||||
|
{CALG_MAC, "CALG_MAC"},
|
||||||
|
{CALG_MD2, "CALG_MD2"},
|
||||||
|
{CALG_MD4, "CALG_MD4"},
|
||||||
|
{CALG_MD4, "CALG_MD5"},
|
||||||
|
{CALG_NO_SIGN, "CALG_NO_SIGN"},
|
||||||
|
{CALG_OID_INFO_CNG_ONLY, "CALG_OID_INFO_CNG_ONLY"},
|
||||||
|
{CALG_OID_INFO_PARAMETERS, "CALG_OID_INFO_PARAMETERS"},
|
||||||
|
{CALG_PCT1_MASTER, "CALG_PCT1_MASTER"},
|
||||||
|
{CALG_RC2, "CALG_RC2"},
|
||||||
|
{CALG_RC4, "CALG_RC4"},
|
||||||
|
{CALG_RC5, "CALG_RC5"},
|
||||||
|
{CALG_RSA_KEYX, "CALG_RSA_KEYX"},
|
||||||
|
{CALG_RSA_SIGN, "CALG_RSA_SIGN"},
|
||||||
|
{CALG_SCHANNEL_MAC_KEY, "CALG_SCHANNEL_MAC_KEY"},
|
||||||
|
{CALG_SCHANNEL_MASTER_HASH, "CALG_SCHANNEL_MASTER_HASH"},
|
||||||
|
{CALG_SEAL, "CALG_SEAL"},
|
||||||
|
{CALG_SHA, "CALG_SHA"},
|
||||||
|
{CALG_SHA1, "CALG_SHA1"},
|
||||||
|
{CALG_SHA_256, "CALG_SHA_256"},
|
||||||
|
{CALG_SHA_384, "CALG_SHA_384"},
|
||||||
|
{CALG_SHA_512, "CALG_SHA_512"},
|
||||||
|
{CALG_SKIPJACK, "CALG_SKIPJACK"},
|
||||||
|
{CALG_SSL2_MASTER, "CALG_SSL2_MASTER"},
|
||||||
|
{CALG_SSL3_MASTER, "CALG_SSL3_MASTER"},
|
||||||
|
{CALG_SSL3_SHAMD5, "CALG_SSL3_SHAMD5"},
|
||||||
|
{CALG_TEK, "CALG_TEK"},
|
||||||
|
{CALG_TLS1_MASTER, "CALG_TLS1_MASTER"},
|
||||||
|
{CALG_TLS1PRF, "CALG_TLS1PRF"},
|
||||||
|
{0, NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
static void cio_schannel_set_error(MYSQL *mysql)
|
|
||||||
{
|
|
||||||
ulong ssl_errno= GetLastError();
|
|
||||||
char ssl_error[MAX_SSL_ERR_LEN];
|
|
||||||
char *ssl_error_reason= NULL;
|
|
||||||
MARIADB_CIO *cio= mysql->net.cio;
|
|
||||||
|
|
||||||
if (!ssl_errno)
|
|
||||||
{
|
|
||||||
cio->set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, "Unknown SSL error");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
/* todo: obtain error messge */
|
|
||||||
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
|
|
||||||
NULL, ssl_errno, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
|
||||||
(LPTSTR) &ssl_error_reason, 0, NULL );
|
|
||||||
cio->set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, ssl_error_reason);
|
|
||||||
|
|
||||||
if (ssl_error_reason)
|
|
||||||
LocalFree(ssl_error_reason);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int ssl_thread_init()
|
static int ssl_thread_init()
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
@@ -106,22 +101,19 @@ static int ssl_thread_init()
|
|||||||
context SSL_context
|
context SSL_context
|
||||||
|
|
||||||
SYNOPSIS
|
SYNOPSIS
|
||||||
cio_schannel_start
|
ma_ssl_start
|
||||||
|
|
||||||
RETURN VALUES
|
RETURN VALUES
|
||||||
0 success
|
0 success
|
||||||
1 error
|
1 error
|
||||||
*/
|
*/
|
||||||
int cio_schannel_start(char *errmsg, size_t errmsg_len, int count, va_list list)
|
int ma_ssl_start(char *errmsg, size_t errmsg_len, int count, va_list list)
|
||||||
{
|
{
|
||||||
if (!my_schannel_initialized)
|
if (!ma_ssl_initialized)
|
||||||
{
|
{
|
||||||
pthread_mutex_init(&LOCK_schannel_config,MY_MUTEX_INIT_FAST);
|
pthread_mutex_init(&LOCK_schannel_config,MY_MUTEX_INIT_FAST);
|
||||||
pthread_mutex_lock(&LOCK_schannel_config);
|
pthread_mutex_lock(&LOCK_schannel_config);
|
||||||
|
ma_ssl_initialized= TRUE;
|
||||||
// SecureZeroMemory(&SC_CTX, sizeof(struct st_schannel_global));
|
|
||||||
|
|
||||||
my_schannel_initialized= TRUE;
|
|
||||||
}
|
}
|
||||||
pthread_mutex_unlock(&LOCK_schannel_config);
|
pthread_mutex_unlock(&LOCK_schannel_config);
|
||||||
return 0;
|
return 0;
|
||||||
@@ -133,27 +125,27 @@ int cio_schannel_start(char *errmsg, size_t errmsg_len, int count, va_list list)
|
|||||||
mysql_server_end() function
|
mysql_server_end() function
|
||||||
|
|
||||||
SYNOPSIS
|
SYNOPSIS
|
||||||
cio_schannel_end()
|
ma_ssl_end()
|
||||||
void
|
void
|
||||||
|
|
||||||
RETURN VALUES
|
RETURN VALUES
|
||||||
void
|
void
|
||||||
*/
|
*/
|
||||||
int cio_schannel_end()
|
void ma_ssl_end()
|
||||||
{
|
{
|
||||||
pthread_mutex_lock(&LOCK_schannel_config);
|
pthread_mutex_lock(&LOCK_schannel_config);
|
||||||
if (my_schannel_initialized)
|
if (ma_ssl_initialized)
|
||||||
{
|
{
|
||||||
|
|
||||||
my_schannel_initialized= FALSE;
|
ma_ssl_initialized= FALSE;
|
||||||
}
|
}
|
||||||
pthread_mutex_unlock(&LOCK_schannel_config);
|
pthread_mutex_unlock(&LOCK_schannel_config);
|
||||||
pthread_mutex_destroy(&LOCK_schannel_config);
|
pthread_mutex_destroy(&LOCK_schannel_config);
|
||||||
return 0;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* {{{ static int cio_schannel_set_client_certs(MARIADB_SSL *cssl) */
|
/* {{{ static int ma_ssl_set_client_certs(MARIADB_SSL *cssl) */
|
||||||
static int cio_schannel_set_client_certs(MARIADB_SSL *cssl)
|
static int ma_ssl_set_client_certs(MARIADB_SSL *cssl)
|
||||||
{
|
{
|
||||||
MYSQL *mysql= cssl->cio->mysql;
|
MYSQL *mysql= cssl->cio->mysql;
|
||||||
char *certfile= mysql->options.ssl_cert,
|
char *certfile= mysql->options.ssl_cert,
|
||||||
@@ -161,24 +153,50 @@ static int cio_schannel_set_client_certs(MARIADB_SSL *cssl)
|
|||||||
*cafile= mysql->options.ssl_ca;
|
*cafile= mysql->options.ssl_ca;
|
||||||
|
|
||||||
SC_CTX *sctx= (SC_CTX *)cssl->ssl;
|
SC_CTX *sctx= (SC_CTX *)cssl->ssl;
|
||||||
|
MARIADB_CIO *cio= cssl->cio;
|
||||||
|
|
||||||
if (cafile)
|
if (cafile)
|
||||||
if (!(sctx->client_ca_ctx = ma_schannel_create_cert_context(cafile)))
|
{
|
||||||
|
HCERTSTORE myCS= NULL;
|
||||||
|
char szName[64];
|
||||||
|
|
||||||
|
if (!(sctx->client_ca_ctx = ma_schannel_create_cert_context(cio, cafile)))
|
||||||
goto end;
|
goto end;
|
||||||
|
|
||||||
if (certfile)
|
/* For X509 authentication we need to add ca certificate to local MY store.
|
||||||
{
|
Schannel doesn't provide a callback to send ca to server during handshake */
|
||||||
if (!(sctx->client_cert_ctx = ma_schannel_create_cert_context(certfile)))
|
if ((myCS= CertOpenStore(CERT_STORE_PROV_SYSTEM,
|
||||||
|
0, //X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
|
||||||
|
0,
|
||||||
|
CERT_SYSTEM_STORE_CURRENT_USER,
|
||||||
|
L"CA")))
|
||||||
|
{
|
||||||
|
CertAddCertificateContextToStore(myCS, sctx->client_ca_ctx, CERT_STORE_ADD_NEWER, NULL);
|
||||||
|
CertCloseStore(myCS, 0);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ma_schannel_set_win_error(sctx->mysql);
|
||||||
goto end;
|
goto end;
|
||||||
if (keyfile)
|
}
|
||||||
if (!ma_schannel_load_private_key(sctx->client_cert_ctx, keyfile))
|
|
||||||
goto end;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!certfile && keyfile)
|
||||||
|
certfile= keyfile;
|
||||||
|
if (!keyfile && certfile)
|
||||||
|
keyfile= certfile;
|
||||||
|
|
||||||
|
if (certfile && certfile[0])
|
||||||
|
if (!(sctx->client_cert_ctx = ma_schannel_create_cert_context(cssl->cio, certfile)))
|
||||||
|
goto end;
|
||||||
|
|
||||||
|
if (sctx->client_cert_ctx && keyfile[0])
|
||||||
|
if (!ma_schannel_load_private_key(cio, sctx->client_cert_ctx, keyfile))
|
||||||
|
goto end;
|
||||||
|
|
||||||
if (mysql->options.extension && mysql->options.extension->ssl_crl)
|
if (mysql->options.extension && mysql->options.extension->ssl_crl)
|
||||||
{
|
{
|
||||||
sctx->client_crl_ctx= ma_schannel_create_crl_context(mysql->options.extension->ssl_crl);
|
if (!(sctx->client_crl_ctx= ma_schannel_create_crl_context(cio, mysql->options.extension->ssl_crl)))
|
||||||
|
goto end;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
@@ -189,95 +207,207 @@ end:
|
|||||||
CertFreeCertificateContext(sctx->client_cert_ctx);
|
CertFreeCertificateContext(sctx->client_cert_ctx);
|
||||||
if (sctx->client_crl_ctx)
|
if (sctx->client_crl_ctx)
|
||||||
CertFreeCRLContext(sctx->client_crl_ctx);
|
CertFreeCRLContext(sctx->client_crl_ctx);
|
||||||
|
sctx->client_ca_ctx= sctx->client_cert_ctx= NULL;
|
||||||
cio_schannel_set_error(mysql);
|
sctx->client_crl_ctx= NULL;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
/* }}} */
|
/* }}} */
|
||||||
|
|
||||||
/* {{{ void *cio_schannel_init(MARIADB_SSL *cssl, MYSQL *mysql) */
|
/* {{{ void *ma_ssl_init(MARIADB_SSL *cssl, MYSQL *mysql) */
|
||||||
void *cio_schannel_init(MARIADB_SSL *cssl, MYSQL *mysql)
|
void *ma_ssl_init(MYSQL *mysql)
|
||||||
{
|
{
|
||||||
int verify;
|
int verify;
|
||||||
SC_CTX *sctx;
|
SC_CTX *sctx= NULL;
|
||||||
|
|
||||||
if (!(sctx= LocalAlloc(0, sizeof(SC_CTX))))
|
|
||||||
return NULL;
|
|
||||||
ZeroMemory(sctx, sizeof(SC_CTX));
|
|
||||||
|
|
||||||
cssl->data= (void *)sctx;
|
|
||||||
|
|
||||||
pthread_mutex_lock(&LOCK_schannel_config);
|
pthread_mutex_lock(&LOCK_schannel_config);
|
||||||
return (void *)sctx;
|
|
||||||
error:
|
if ((sctx= LocalAlloc(0, sizeof(SC_CTX))))
|
||||||
|
{
|
||||||
|
ZeroMemory(sctx, sizeof(SC_CTX));
|
||||||
|
sctx->mysql= mysql;
|
||||||
|
}
|
||||||
|
|
||||||
pthread_mutex_unlock(&LOCK_schannel_config);
|
pthread_mutex_unlock(&LOCK_schannel_config);
|
||||||
return NULL;
|
return sctx;
|
||||||
}
|
}
|
||||||
/* }}} */
|
/* }}} */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
my_bool ma_ssl_connect(MARIADB_SSL *cssl)
|
||||||
static my_bool VerifyServerCertificate(SC_CTX *sctx, PCCERT_CONTEXT pServerCert, PSTR pszServerName, DWORD dwCertFlags )
|
|
||||||
{
|
{
|
||||||
|
my_bool blocking;
|
||||||
|
MYSQL *mysql;
|
||||||
|
SCHANNEL_CRED Cred;
|
||||||
|
MARIADB_CIO *cio;
|
||||||
|
SC_CTX *sctx;
|
||||||
SECURITY_STATUS sRet;
|
SECURITY_STATUS sRet;
|
||||||
DWORD flags;
|
PCCERT_CONTEXT pRemoteCertContext = NULL,
|
||||||
char *szName= NULL;
|
pLocalCertContext= NULL;
|
||||||
int rc= 0;
|
ALG_ID AlgId[2]= {0, 0};
|
||||||
|
|
||||||
|
if (!cssl || !cssl->cio)
|
||||||
|
return 1;;
|
||||||
|
|
||||||
|
cio= cssl->cio;
|
||||||
|
sctx= (SC_CTX *)cssl->ssl;
|
||||||
|
|
||||||
/* We perform a manually validation, as described at
|
/* Set socket to blocking if not already set */
|
||||||
http://msdn.microsoft.com/en-us/library/windows/desktop/aa378740%28v=vs.85%29.aspx
|
if (!(blocking= cio->methods->is_blocking(cio)))
|
||||||
*/
|
cio->methods->blocking(cio, TRUE, 0);
|
||||||
|
|
||||||
/* Check if
|
mysql= cio->mysql;
|
||||||
- The certificate chain is complete and the root is a certificate from a trusted certification authority (CA).
|
|
||||||
- The current time is not beyond the begin and end dates for each of the certificates in the certificate chain.
|
if (ma_ssl_set_client_certs(cssl))
|
||||||
*/
|
goto end;
|
||||||
flags= CERT_STORE_SIGNATURE_FLAG |
|
|
||||||
CERT_STORE_TIME_VALIDITY_FLAG;
|
/* Set cipher */
|
||||||
|
if (mysql->options.ssl_cipher)
|
||||||
if (!(sRet= CertVerifySubjectCertificateContext(pServerCert,
|
|
||||||
sctx->client_ca_ctx,
|
|
||||||
&flags)))
|
|
||||||
{
|
{
|
||||||
/* todo: error handling */
|
DWORD i= 0;
|
||||||
return 0;
|
while (sc_ciphers[i].cipher) {
|
||||||
}
|
if (!strcmp(sc_ciphers[i].cipher, mysql->options.ssl_cipher))
|
||||||
|
{
|
||||||
/* Check if none of the certificates in the certificate chain have been revoked. */
|
AlgId[0]= sc_ciphers[i].aid;
|
||||||
if (sctx->client_crl_ctx)
|
break;
|
||||||
{
|
}
|
||||||
PCRL_INFO Info[1];
|
|
||||||
|
|
||||||
Info[0]= sctx->client_crl_ctx->pCrlInfo;
|
|
||||||
if (!(CertVerifyCRLRevocation(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
|
|
||||||
pServerCert->pCertInfo,
|
|
||||||
1, Info)) )
|
|
||||||
{
|
|
||||||
/* todo: error handling */
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
Cred.palgSupportedAlgs= &AlgId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ZeroMemory(&Cred, sizeof(SCHANNEL_CRED));
|
||||||
|
Cred.dwVersion= SCHANNEL_CRED_VERSION;
|
||||||
|
Cred.dwFlags |= SCH_CRED_NO_SERVERNAME_CHECK | SCH_SEND_ROOT_CERT |
|
||||||
|
SCH_CRED_NO_DEFAULT_CREDS | SCH_CRED_MANUAL_CRED_VALIDATION;
|
||||||
|
if (sctx->client_cert_ctx)
|
||||||
|
{
|
||||||
|
Cred.cCreds = 1;
|
||||||
|
Cred.paCred = &sctx->client_cert_ctx;
|
||||||
|
}
|
||||||
|
Cred.grbitEnabledProtocols= SP_PROT_TLS1;
|
||||||
|
|
||||||
|
if ((sRet= AcquireCredentialsHandleA(NULL, UNISP_NAME_A, SECPKG_CRED_OUTBOUND,
|
||||||
|
NULL, &Cred, NULL, NULL, &sctx->CredHdl, NULL)) != SEC_E_OK)
|
||||||
|
{
|
||||||
|
ma_schannel_set_sec_error(cio, sRet);
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ma_schannel_client_handshake(cssl))
|
||||||
|
goto end;
|
||||||
|
|
||||||
|
sRet= QueryContextAttributes(&sctx->ctxt, SECPKG_ATTR_REMOTE_CERT_CONTEXT, (PVOID)&pRemoteCertContext);
|
||||||
|
if (sRet != SEC_E_OK)
|
||||||
|
{
|
||||||
|
ma_schannel_set_sec_error(cio, sRet);
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ma_schannel_verify_certs(sctx, 0))
|
||||||
|
goto end;
|
||||||
|
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
end:
|
||||||
|
/* todo: cleanup */
|
||||||
|
if (sctx->IoBufferSize)
|
||||||
|
LocalFree(sctx->IoBuffer);
|
||||||
|
if (sctx->client_ca_ctx)
|
||||||
|
CertFreeCertificateContext(sctx->client_ca_ctx);
|
||||||
|
if (sctx->client_cert_ctx)
|
||||||
|
CertFreeCertificateContext(sctx->client_cert_ctx);
|
||||||
|
if (sctx->client_crl_ctx)
|
||||||
|
CertFreeCRLContext(sctx->client_crl_ctx);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t ma_ssl_read(MARIADB_SSL *cssl, const uchar* buffer, size_t length)
|
||||||
|
{
|
||||||
|
SC_CTX *sctx= (SC_CTX *)cssl->ssl;
|
||||||
|
MARIADB_CIO *cio= sctx->mysql->net.cio;
|
||||||
|
size_t dlength= -1;
|
||||||
|
|
||||||
|
ma_schannel_read_decrypt(cio, &sctx->CredHdl, &sctx->ctxt, &dlength, buffer, length);
|
||||||
|
return dlength;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t ma_ssl_write(MARIADB_SSL *cssl, const uchar* buffer, size_t length)
|
||||||
|
{
|
||||||
|
SC_CTX *sctx= (SC_CTX *)cssl->ssl;
|
||||||
|
MARIADB_CIO *cio= sctx->mysql->net.cio;
|
||||||
|
size_t rc, wlength= 0;
|
||||||
|
size_t remain= length;
|
||||||
|
|
||||||
|
while (remain)
|
||||||
|
{
|
||||||
|
if ((rc= ma_schannel_write_encrypt(cio, (uchar *)buffer + wlength, remain)) <= 0)
|
||||||
|
return rc;
|
||||||
|
wlength+= rc;
|
||||||
|
remain-= rc;
|
||||||
|
}
|
||||||
|
return length;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* {{{ void ma_ssl_close(MARIADB_CIO *cio) */
|
||||||
|
void ma_ssl_close(MARIADB_CIO *cio)
|
||||||
|
{
|
||||||
|
SC_CTX *sctx;
|
||||||
|
if (!cio || !cio->cssl)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if ((sctx= (SC_CTX *)cio->cssl))
|
||||||
|
{
|
||||||
|
if (sctx->IoBufferSize)
|
||||||
|
LocalFree(sctx->IoBuffer);
|
||||||
|
if (sctx->client_ca_ctx)
|
||||||
|
CertFreeCertificateContext(sctx->client_ca_ctx);
|
||||||
|
if (sctx->client_cert_ctx)
|
||||||
|
CertFreeCertificateContext(sctx->client_cert_ctx);
|
||||||
|
if (sctx->client_crl_ctx)
|
||||||
|
CertFreeCRLContext(sctx->client_crl_ctx);
|
||||||
|
FreeCredentialHandle(&sctx->CredHdl);
|
||||||
|
DeleteSecurityContext(&sctx->ctxt);
|
||||||
|
}
|
||||||
|
LocalFree(sctx);
|
||||||
|
}
|
||||||
|
/* }}} */
|
||||||
|
|
||||||
|
int ma_ssl_verify_server_cert(MARIADB_SSL *cssl)
|
||||||
|
{
|
||||||
|
SC_CTX *sctx= (SC_CTX *)cssl->ssl;
|
||||||
|
MARIADB_CIO *cio= cssl->cio;
|
||||||
|
int rc= 1;
|
||||||
|
char *szName= NULL;
|
||||||
|
char *pszServerName= cio->mysql->host;
|
||||||
|
|
||||||
/* check server name */
|
/* check server name */
|
||||||
if (pszServerName)
|
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;
|
||||||
|
|
||||||
|
if ((sRet= QueryContextAttributes(&sctx->ctxt, SECPKG_ATTR_REMOTE_CERT_CONTEXT, (PVOID)&pServerCert)) != SEC_E_OK)
|
||||||
|
{
|
||||||
|
ma_schannel_set_sec_error(cio, sRet);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
if (!(NameSize= CertNameToStr(pServerCert->dwCertEncodingType,
|
if (!(NameSize= CertNameToStr(pServerCert->dwCertEncodingType,
|
||||||
&pServerCert->pCertInfo->Subject,
|
&pServerCert->pCertInfo->Subject,
|
||||||
CERT_X500_NAME_STR | CERT_NAME_STR_NO_PLUS_FLAG,
|
CERT_X500_NAME_STR | CERT_NAME_STR_NO_PLUS_FLAG,
|
||||||
NULL, 0)))
|
NULL, 0)))
|
||||||
{
|
{
|
||||||
/* todo: error handling */
|
cio->set_error(sctx->mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, "Can't retrieve name of server certificate");
|
||||||
return 0;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(szName= LocalAlloc(0, NameSize + 1)))
|
if (!(szName= LocalAlloc(0, NameSize + 1)))
|
||||||
{
|
{
|
||||||
/* error handling */
|
cio->set_error(sctx->mysql, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, NULL);
|
||||||
return 0;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!CertNameToStr(pServerCert->dwCertEncodingType,
|
if (!CertNameToStr(pServerCert->dwCertEncodingType,
|
||||||
@@ -285,7 +415,7 @@ static my_bool VerifyServerCertificate(SC_CTX *sctx, PCCERT_CONTEXT pServerCert,
|
|||||||
CERT_X500_NAME_STR | CERT_NAME_STR_NO_PLUS_FLAG,
|
CERT_X500_NAME_STR | CERT_NAME_STR_NO_PLUS_FLAG,
|
||||||
szName, NameSize))
|
szName, NameSize))
|
||||||
{
|
{
|
||||||
/* error handling */
|
cio->set_error(sctx->mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, "Can't retrieve name of server certificate");
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
if ((p1 = strstr(szName, "CN=")))
|
if ((p1 = strstr(szName, "CN=")))
|
||||||
@@ -295,116 +425,50 @@ static my_bool VerifyServerCertificate(SC_CTX *sctx, PCCERT_CONTEXT pServerCert,
|
|||||||
*p2= 0;
|
*p2= 0;
|
||||||
if (!strcmp(pszServerName, p1))
|
if (!strcmp(pszServerName, p1))
|
||||||
{
|
{
|
||||||
rc= 1;
|
rc= 0;
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
cio->set_error(cio->mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN,
|
||||||
|
"Name of server certificate didn't match");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
end:
|
end:
|
||||||
if (szName)
|
if (szName)
|
||||||
LocalFree(szName);
|
LocalFree(szName);
|
||||||
return rc;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
my_bool cio_schannel_connect(MARIADB_SSL *cssl)
|
|
||||||
{
|
|
||||||
my_bool blocking;
|
|
||||||
MYSQL *mysql;
|
|
||||||
SCHANNEL_CRED Cred;
|
|
||||||
MARIADB_CIO *cio;
|
|
||||||
SC_CTX *sctx;
|
|
||||||
SECURITY_STATUS sRet;
|
|
||||||
PCCERT_CONTEXT pRemoteCertContext = NULL;
|
|
||||||
|
|
||||||
if (!cssl || !cssl->cio || !cssl->data)
|
|
||||||
return 1;;
|
|
||||||
|
|
||||||
cio= cssl->cio;
|
|
||||||
sctx= (SC_CTX *)cssl->data;
|
|
||||||
|
|
||||||
/* Set socket to blocking if not already set */
|
|
||||||
if (!(blocking= cio->methods->is_blocking(cio)))
|
|
||||||
cio->methods->blocking(cio, TRUE, 0);
|
|
||||||
|
|
||||||
mysql= cio->mysql;
|
|
||||||
|
|
||||||
if (cio_schannel_set_client_certs(cssl))
|
|
||||||
{
|
|
||||||
cio_schannel_set_error(mysql);
|
|
||||||
goto end;
|
|
||||||
}
|
|
||||||
|
|
||||||
ZeroMemory(&Cred, sizeof(SCHANNEL_CRED));
|
|
||||||
Cred.dwVersion= SCHANNEL_CRED_VERSION;
|
|
||||||
Cred.dwFlags |= SCH_CRED_NO_SERVERNAME_CHECK |
|
|
||||||
SCH_CRED_NO_DEFAULT_CREDS |
|
|
||||||
SCH_CRED_MANUAL_CRED_VALIDATION;
|
|
||||||
if (sctx->client_cert_ctx)
|
|
||||||
{
|
|
||||||
Cred.cCreds = 1;
|
|
||||||
Cred.paCred = &sctx->client_cert_ctx;
|
|
||||||
}
|
|
||||||
Cred.grbitEnabledProtocols= SP_PROT_TLS1;
|
|
||||||
|
|
||||||
/* We allocate 2 x net_buffer_length */
|
|
||||||
if (!(sctx->IoBuffer= (PUCHAR)LocalAlloc(0, 0x4000)))
|
|
||||||
goto end;
|
|
||||||
|
|
||||||
if (AcquireCredentialsHandleA(NULL, UNISP_NAME_A, SECPKG_CRED_OUTBOUND,
|
|
||||||
NULL, &Cred, NULL, NULL, &sctx->CredHdl, NULL) != SEC_E_OK)
|
|
||||||
goto end;
|
|
||||||
|
|
||||||
if (ma_schannel_client_handshake(cssl))
|
|
||||||
goto end;
|
|
||||||
|
|
||||||
sRet= QueryContextAttributes(&sctx->ctxt, SECPKG_ATTR_REMOTE_CERT_CONTEXT, (PVOID)&pRemoteCertContext);
|
|
||||||
if (sRet != SEC_E_OK)
|
|
||||||
goto end;
|
|
||||||
|
|
||||||
if (!VerifyServerCertificate(sctx,
|
|
||||||
pRemoteCertContext,
|
|
||||||
mysql->host,
|
|
||||||
0 ))
|
|
||||||
goto end;
|
|
||||||
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
end:
|
|
||||||
/* todo: cleanup */
|
|
||||||
if (sctx->IoBuffer)
|
|
||||||
LocalFree(sctx->IoBuffer);
|
|
||||||
if (sctx->client_ca_ctx)
|
|
||||||
CertFreeCertificateContext(sctx->client_ca_ctx);
|
|
||||||
if (sctx->client_cert_ctx)
|
|
||||||
CertFreeCertificateContext(sctx->client_cert_ctx);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t cio_schannel_read(MARIADB_SSL *cssl, const uchar* buffer, size_t length)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t cio_schannel_write(MARIADB_SSL *cssl, const uchar* buffer, size_t length)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
my_bool cio_schannel_close(MARIADB_SSL *cssl)
|
|
||||||
{
|
|
||||||
int i, rc;
|
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
int cio_schannel_verify_server_cert(MARIADB_SSL *cssl)
|
const char *ma_ssl_get_cipher(MARIADB_SSL *cssl)
|
||||||
{
|
{
|
||||||
}
|
SecPkgContext_ConnectionInfo cinfo;
|
||||||
|
SECURITY_STATUS sRet;
|
||||||
|
SC_CTX *sctx;
|
||||||
|
DWORD i= 0;
|
||||||
|
|
||||||
const char *cio_schannel_cipher(MARIADB_SSL *cssl)
|
|
||||||
{
|
|
||||||
if (!cssl || !cssl->ssl)
|
if (!cssl || !cssl->ssl)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
sctx= (SC_CTX *)cssl->ssl;
|
||||||
|
|
||||||
|
sRet= QueryContextAttributes(&sctx->ctxt, SECPKG_ATTR_CONNECTION_INFO, (PVOID)&cinfo);
|
||||||
|
if (sRet != SEC_E_OK)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
while (sc_ciphers[i].cipher)
|
||||||
|
{
|
||||||
|
if (sc_ciphers[i].aid == cinfo.aiCipher)
|
||||||
|
return sc_ciphers[i].cipher;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsigned int ma_ssl_get_finger_print(MARIADB_SSL *cssl, unsigned char *fp, unsigned int len)
|
||||||
|
{
|
||||||
|
SC_CTX *sctx= (SC_CTX *)cssl->ssl;
|
||||||
|
PCCERT_CONTEXT pRemoteCertContext = NULL;
|
||||||
|
if (QueryContextAttributes(&sctx->ctxt, SECPKG_ATTR_REMOTE_CERT_CONTEXT, (PVOID)&pRemoteCertContext) != SEC_E_OK)
|
||||||
|
return NULL;
|
||||||
|
CertGetCertificateContextProperty(pRemoteCertContext, CERT_HASH_PROP_ID, fp, &len);
|
||||||
|
return len;
|
||||||
|
}
|
@@ -436,6 +436,7 @@ int cio_socket_wait_io_or_timeout(MARIADB_CIO *cio, my_bool is_read, int timeout
|
|||||||
csock= (struct st_cio_socket *)cio->data;
|
csock= (struct st_cio_socket *)cio->data;
|
||||||
{
|
{
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
|
memset(&p_fd, 0, sizeof(p_fd));
|
||||||
p_fd.fd= csock->socket;
|
p_fd.fd= csock->socket;
|
||||||
p_fd.events= (is_read) ? POLLIN : POLLOUT;
|
p_fd.events= (is_read) ? POLLIN : POLLOUT;
|
||||||
|
|
||||||
|
File diff suppressed because it is too large
Load Diff
@@ -52,7 +52,6 @@ mysql_declare_client_plugin(TRACE)
|
|||||||
"LGPL",
|
"LGPL",
|
||||||
&trace_init,
|
&trace_init,
|
||||||
&trace_deinit,
|
&trace_deinit,
|
||||||
NULL
|
|
||||||
mysql_end_client_plugin;
|
mysql_end_client_plugin;
|
||||||
|
|
||||||
static char *commands[]= {
|
static char *commands[]= {
|
||||||
|
Binary file not shown.
@@ -57,7 +57,7 @@ static int test_conc66(MYSQL *my)
|
|||||||
diag("Error: %s", mysql_error(mysql));
|
diag("Error: %s", mysql_error(mysql));
|
||||||
return FAIL;
|
return FAIL;
|
||||||
}
|
}
|
||||||
rc= mysql_query(my, "DROP USER conc66@localhost");
|
rc= mysql_query(my, "DROP USER conc66@%");
|
||||||
|
|
||||||
check_mysql_rc(rc, my);
|
check_mysql_rc(rc, my);
|
||||||
mysql_close(mysql);
|
mysql_close(mysql);
|
||||||
|
@@ -143,7 +143,6 @@ static int create_dyncol_num(MYSQL *mysql)
|
|||||||
rc= mariadb_dyncol_unpack(&dyncol, &my_count, &my_keys, &my_vals);
|
rc= mariadb_dyncol_unpack(&dyncol, &my_count, &my_keys, &my_vals);
|
||||||
diag("unpack: %d %d", rc, my_count);
|
diag("unpack: %d %d", rc, my_count);
|
||||||
|
|
||||||
diag("---------------__");
|
|
||||||
for(i=0; i < 5; i++)
|
for(i=0; i < 5; i++)
|
||||||
{
|
{
|
||||||
diag("%s %d", my_keys[i].str, my_keys[i].length);
|
diag("%s %d", my_keys[i].str, my_keys[i].length);
|
||||||
@@ -200,7 +199,7 @@ static int mdev_x1(MYSQL *mysql)
|
|||||||
|
|
||||||
for (i=0; i < unpack_columns; i++)
|
for (i=0; i < unpack_columns; i++)
|
||||||
if (memcmp(unpack_vals[i].x.string.value.str, vals[i].x.string.value.str, vals[i].x.string.value.length))
|
if (memcmp(unpack_vals[i].x.string.value.str, vals[i].x.string.value.str, vals[i].x.string.value.length))
|
||||||
printf("Error1: key: %1s val: %s %s\n", unpack_keys[i].str, unpack_vals[i].x.string.value.str, vals[i].x.string.value.str);
|
diag("Error1: key: %1s val: %s %s", unpack_keys[i].str, unpack_vals[i].x.string.value.str, vals[i].x.string.value.str);
|
||||||
|
|
||||||
free(unpack_keys);
|
free(unpack_keys);
|
||||||
free(unpack_vals);
|
free(unpack_vals);
|
||||||
|
@@ -978,6 +978,7 @@ static int test_remote1(MYSQL *mysql)
|
|||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
|
void *myplugin= (void *)mysql_client_find_plugin(mysql, "trace_example", MYSQL_CLIENT_TRACE_PLUGIN);
|
||||||
remote_plugin= (void *)mysql_client_find_plugin(mysql, "remote_io", MYSQL_CLIENT_REMOTEIO_PLUGIN);
|
remote_plugin= (void *)mysql_client_find_plugin(mysql, "remote_io", MYSQL_CLIENT_REMOTEIO_PLUGIN);
|
||||||
if (!remote_plugin)
|
if (!remote_plugin)
|
||||||
{
|
{
|
||||||
|
@@ -67,7 +67,8 @@ static int test_ssl(MYSQL *mysql)
|
|||||||
|
|
||||||
if (!skip_ssl)
|
if (!skip_ssl)
|
||||||
{
|
{
|
||||||
rc= mysql_query(mysql, "DROP USER 'ssluser'@'localhost'");
|
rc= mysql_query(mysql, "DROP USER 'ssluser'@'%'");
|
||||||
|
rc= mysql_query(mysql, "GRANT ALL ON test.* TO 'ssluser'@'%' IDENTIFIED BY 'sslpw' REQUIRE SSL");
|
||||||
rc= mysql_query(mysql, "GRANT ALL ON test.* TO 'ssluser'@'localhost' IDENTIFIED BY 'sslpw' REQUIRE SSL");
|
rc= mysql_query(mysql, "GRANT ALL ON test.* TO 'ssluser'@'localhost' IDENTIFIED BY 'sslpw' REQUIRE SSL");
|
||||||
rc= mysql_query(mysql, "FLUSH PRVILEGES");
|
rc= mysql_query(mysql, "FLUSH PRVILEGES");
|
||||||
}
|
}
|
||||||
@@ -92,11 +93,7 @@ static int test_ssl_cipher(MYSQL *unused)
|
|||||||
port, socketname, 0), mysql_error(my));
|
port, socketname, 0), mysql_error(my));
|
||||||
|
|
||||||
cipher= (char *)mysql_get_ssl_cipher(my);
|
cipher= (char *)mysql_get_ssl_cipher(my);
|
||||||
#ifdef HAVE_OPENSSL
|
FAIL_IF(cipher == NULL, "used cipher is NULL");
|
||||||
FAIL_IF(strcmp(cipher, "DHE-RSA-AES256-SHA") != 0, "Cipher != DHE-RSA-AES256-SHA");
|
|
||||||
#elif defined(HAVE_HNUTLS)
|
|
||||||
FAIL_IF(strcmp(cipher, "AES-256-CBC") != 0, "Cipher != AES-256-CBC");
|
|
||||||
#endif
|
|
||||||
mysql_close(my);
|
mysql_close(my);
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
@@ -109,7 +106,9 @@ static int test_conc95(MYSQL *my)
|
|||||||
if (check_skip_ssl())
|
if (check_skip_ssl())
|
||||||
return SKIP;
|
return SKIP;
|
||||||
|
|
||||||
|
rc= mysql_query(my, "DROP USER 'ssluser1'@'%'");
|
||||||
rc= mysql_query(my, "DROP USER 'ssluser1'@'localhost'");
|
rc= mysql_query(my, "DROP USER 'ssluser1'@'localhost'");
|
||||||
|
rc= mysql_query(my, "GRANT ALL ON test.* TO 'ssluser1'@'%' IDENTIFIED BY 'sslpw' REQUIRE X509");
|
||||||
rc= mysql_query(my, "GRANT ALL ON test.* TO 'ssluser1'@'localhost' IDENTIFIED BY 'sslpw' REQUIRE X509");
|
rc= mysql_query(my, "GRANT ALL ON test.* TO 'ssluser1'@'localhost' IDENTIFIED BY 'sslpw' REQUIRE X509");
|
||||||
check_mysql_rc(rc, my);
|
check_mysql_rc(rc, my);
|
||||||
rc= mysql_query(my, "FLUSH PRIVILEGES");
|
rc= mysql_query(my, "FLUSH PRIVILEGES");
|
||||||
@@ -117,8 +116,8 @@ static int test_conc95(MYSQL *my)
|
|||||||
|
|
||||||
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",
|
"@CMAKE_SOURCE_DIR@/unittest/libmariadb/certs/ca-cert.pem",
|
||||||
NULL,
|
NULL,
|
||||||
NULL);
|
NULL);
|
||||||
@@ -126,6 +125,7 @@ static int test_conc95(MYSQL *my)
|
|||||||
if (!mysql_real_connect(mysql, hostname, "ssluser1", sslpw, schema,
|
if (!mysql_real_connect(mysql, hostname, "ssluser1", sslpw, schema,
|
||||||
port, socketname, 0))
|
port, socketname, 0))
|
||||||
{
|
{
|
||||||
|
diag("Error: %s", mysql_error(mysql));
|
||||||
mysql_close(mysql);
|
mysql_close(mysql);
|
||||||
diag("could not establish x509 connection");
|
diag("could not establish x509 connection");
|
||||||
return FAIL;
|
return FAIL;
|
||||||
@@ -178,11 +178,7 @@ static int test_multi_ssl_connections(MYSQL *unused)
|
|||||||
}
|
}
|
||||||
|
|
||||||
cipher= (char *)mysql_get_ssl_cipher(mysql[i]);
|
cipher= (char *)mysql_get_ssl_cipher(mysql[i]);
|
||||||
#ifdef HAVE_OPENSSL
|
FAIL_IF(cipher == NULL, "used cipher is NULL");
|
||||||
FAIL_IF(strcmp(cipher, "DHE-RSA-AES256-SHA") != 0, "Cipher != DHE-RSA-AES256-SHA");
|
|
||||||
#elif defined(HAVE_HNUTLS)
|
|
||||||
FAIL_IF(strcmp(cipher, "AES-256-CBC") != 0, "Cipher != AES-256-CBC");
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
for (i=0; i < 50; i++)
|
for (i=0; i < 50; i++)
|
||||||
mysql_close(mysql[i]);
|
mysql_close(mysql[i]);
|
||||||
@@ -404,8 +400,11 @@ static int test_conc50_3(MYSQL *my)
|
|||||||
if (check_skip_ssl())
|
if (check_skip_ssl())
|
||||||
return SKIP;
|
return SKIP;
|
||||||
|
|
||||||
mysql_query(my, "DROP USER 'ssltest'@'localhost'");
|
mysql_query(my, "DROP USER 'ssltest'@'%'");
|
||||||
|
|
||||||
|
sprintf(query, "GRANT ALL ON %s.* TO 'ssltest'@'%' REQUIRE SSL", schema ? schema : "*");
|
||||||
|
rc= mysql_query(my, query);
|
||||||
|
check_mysql_rc(rc, my);
|
||||||
sprintf(query, "GRANT ALL ON %s.* TO 'ssltest'@'localhost' REQUIRE SSL", schema ? schema : "*");
|
sprintf(query, "GRANT ALL ON %s.* TO 'ssltest'@'localhost' REQUIRE SSL", schema ? schema : "*");
|
||||||
rc= mysql_query(my, query);
|
rc= mysql_query(my, query);
|
||||||
check_mysql_rc(rc, my);
|
check_mysql_rc(rc, my);
|
||||||
@@ -489,7 +488,7 @@ static int test_bug62743(MYSQL *my)
|
|||||||
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, "dummykey", NULL, NULL, NULL, NULL);
|
mysql_ssl_set(mysql, "dummykey", "@CMAKE_SOURCE_DIR@/unittest/libmariadb/certs/client-cert.pem", NULL, NULL, NULL);
|
||||||
|
|
||||||
mysql_real_connect(mysql, hostname, ssluser, sslpw, schema,
|
mysql_real_connect(mysql, hostname, ssluser, sslpw, schema,
|
||||||
port, socketname, 0);
|
port, socketname, 0);
|
||||||
@@ -596,6 +595,8 @@ static int test_conc_102(MYSQL *mysql)
|
|||||||
rc= mysql_query(mysql, "INSERT INTO t_conc102 VALUES (0)");
|
rc= mysql_query(mysql, "INSERT INTO t_conc102 VALUES (0)");
|
||||||
check_mysql_rc(rc, mysql);
|
check_mysql_rc(rc, mysql);
|
||||||
|
|
||||||
|
pthread_mutex_init(&LOCK_test, 0);
|
||||||
|
|
||||||
for (i=0; i < 50; i++)
|
for (i=0; i < 50; i++)
|
||||||
{
|
{
|
||||||
#ifndef WIN32
|
#ifndef WIN32
|
||||||
@@ -613,7 +614,8 @@ static int test_conc_102(MYSQL *mysql)
|
|||||||
#else
|
#else
|
||||||
WaitForSingleObject(hthreads[i], INFINITE);
|
WaitForSingleObject(hthreads[i], INFINITE);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
pthread_mutex_destroy(&LOCK_test);
|
||||||
rc= mysql_query(mysql, "SELECT a FROM t_conc102");
|
rc= mysql_query(mysql, "SELECT a FROM t_conc102");
|
||||||
check_mysql_rc(rc, mysql);
|
check_mysql_rc(rc, mysql);
|
||||||
res= mysql_store_result(mysql);
|
res= mysql_store_result(mysql);
|
||||||
@@ -645,11 +647,7 @@ static int test_ssl_fp(MYSQL *unused)
|
|||||||
port, socketname, 0), mysql_error(my));
|
port, socketname, 0), mysql_error(my));
|
||||||
|
|
||||||
cipher= (char *)mysql_get_ssl_cipher(my);
|
cipher= (char *)mysql_get_ssl_cipher(my);
|
||||||
#ifdef HAVE_OPENSSL
|
FAIL_IF(cipher == NULL, "used cipher is NULL");
|
||||||
FAIL_IF(strcmp(cipher, "DHE-RSA-AES256-SHA") != 0, "Cipher != DHE-RSA-AES256-SHA");
|
|
||||||
#elif defined(HAVE_HNUTLS)
|
|
||||||
FAIL_IF(strcmp(cipher, "AES-256-CBC") != 0, "Cipher != AES-256-CBC");
|
|
||||||
#endif
|
|
||||||
mysql_close(my);
|
mysql_close(my);
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
@@ -672,19 +670,43 @@ static int test_ssl_fp_list(MYSQL *unused)
|
|||||||
FAIL_IF(!mysql_real_connect(my, hostname, ssluser, sslpw, schema,
|
FAIL_IF(!mysql_real_connect(my, hostname, ssluser, sslpw, schema,
|
||||||
port, socketname, 0), mysql_error(my));
|
port, socketname, 0), mysql_error(my));
|
||||||
|
|
||||||
#ifdef HAVE_OPENSSL
|
cipher= mysql_get_ssl_cipher(my);
|
||||||
FAIL_IF(strcmp(cipher, "DHE-RSA-AES256-SHA") != 0, "Cipher != DHE-RSA-AES256-SHA");
|
FAIL_IF(cipher == NULL, "used cipher is NULL");
|
||||||
#elif defined(HAVE_HNUTLS)
|
|
||||||
FAIL_IF(strcmp(cipher, "AES-256-CBC") != 0, "Cipher != AES-256-CBC");
|
|
||||||
#endif
|
|
||||||
mysql_close(my);
|
mysql_close(my);
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int test_ssl_long_msg(MYSQL *unused)
|
||||||
|
{
|
||||||
|
MYSQL *my;
|
||||||
|
char buffer[20000];
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
if (check_skip_ssl())
|
||||||
|
return SKIP;
|
||||||
|
|
||||||
|
my= mysql_init(NULL);
|
||||||
|
FAIL_IF(!my, "mysql_init() failed");
|
||||||
|
|
||||||
|
mysql_ssl_set(my,0, 0, "@CMAKE_SOURCE_DIR@/unittest/libmariadb/certs/ca-cert.pem", 0, 0);
|
||||||
|
|
||||||
|
mysql_options(my, MARIADB_OPT_SSL_FP, ssl_cert_finger_print);
|
||||||
|
|
||||||
|
FAIL_IF(!mysql_real_connect(my, hostname, ssluser, sslpw, schema,
|
||||||
|
port, socketname, 0), mysql_error(my));
|
||||||
|
|
||||||
|
memset(buffer, 0, 20000);
|
||||||
|
strcpy(buffer, "SET @a:=");
|
||||||
|
memset(buffer + strlen(buffer), '0', 19000);
|
||||||
|
|
||||||
|
rc= mysql_query(my, buffer);
|
||||||
|
check_mysql_rc(rc, my);
|
||||||
|
mysql_close(my);
|
||||||
|
}
|
||||||
|
|
||||||
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},
|
||||||
|
{"test_ssl_long_msg", test_ssl_long_msg, TEST_CONNECTION_NEW, 0, NULL, NULL},
|
||||||
{"test_conc127", test_conc127, TEST_CONNECTION_NEW, 0, NULL, NULL},
|
{"test_conc127", test_conc127, TEST_CONNECTION_NEW, 0, NULL, NULL},
|
||||||
{"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},
|
||||||
|
Reference in New Issue
Block a user