You've already forked mariadb-connector-c
mirror of
https://github.com/mariadb-corporation/mariadb-connector-c.git
synced 2025-08-08 14:02:17 +03:00
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);
|
||||
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_start_ssl(MARIADB_CIO *cio);
|
||||
|
||||
#endif /* _ma_ssl_h_ */
|
||||
|
@@ -1145,13 +1145,15 @@ int STDCALL
|
||||
mysql_ssl_set(MYSQL *mysql, const char *key, const char *cert,
|
||||
const char *ca, const char *capath, const char *cipher)
|
||||
{
|
||||
mysql->options.ssl_key = key==0 ? 0 : my_strdup(key,MYF(0));
|
||||
mysql->options.ssl_cert = cert==0 ? 0 : my_strdup(cert,MYF(0));
|
||||
mysql->options.ssl_ca = ca==0 ? 0 : my_strdup(ca,MYF(0));
|
||||
mysql->options.ssl_capath = capath==0 ? 0 : my_strdup(capath,MYF(0));
|
||||
mysql->options.ssl_cipher = cipher==0 ? 0 : my_strdup(cipher,MYF(0));
|
||||
/* todo: add crl stuff */
|
||||
#ifdef HAVE_SSL
|
||||
return (mysql_optionsv(mysql, MYSQL_OPT_SSL_KEY, key) |
|
||||
mysql_optionsv(mysql, MYSQL_OPT_SSL_CERT, cert) |
|
||||
mysql_optionsv(mysql, MYSQL_OPT_SSL_CA, ca) |
|
||||
mysql_optionsv(mysql, MYSQL_OPT_SSL_CAPATH, capath) |
|
||||
mysql_optionsv(mysql, MYSQL_OPT_SSL_CIPHER, cipher)) ? 1 : 0;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
@@ -2674,23 +2676,23 @@ mysql_optionsv(MYSQL *mysql,enum mysql_option option, ...)
|
||||
break;
|
||||
case MYSQL_OPT_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;
|
||||
case MYSQL_OPT_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;
|
||||
case MYSQL_OPT_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;
|
||||
case MYSQL_OPT_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;
|
||||
case MYSQL_OPT_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;
|
||||
case MYSQL_OPT_SSL_CRL:
|
||||
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);
|
||||
mysql->options.bind_address= my_strdup(arg1, MYF(MY_WME));
|
||||
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:
|
||||
va_end(ap);
|
||||
DBUG_RETURN(-1);
|
||||
|
@@ -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 */
|
||||
my_bool ma_ssl_initialized= FALSE;
|
||||
unsigned int mariadb_deinitialize_ssl= 1;
|
||||
|
||||
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,
|
||||
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);
|
||||
#ifdef WIN32
|
||||
if (strnicmp(hexstr, fp2, fp1_len) != 0)
|
||||
#else
|
||||
if (strncasecmp(hexstr, fp2, fp1_len) != 0)
|
||||
#endif
|
||||
return 1;
|
||||
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;
|
||||
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;
|
||||
|
||||
if (fp)
|
||||
rc= ma_cio_ssl_compare_fp(cert_fp, cert_fp_len, fp, strlen(fp));
|
||||
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)
|
||||
{
|
||||
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)
|
||||
memcpy((unsigned char*) ptr, (unsigned char*) from,(size_t) length);
|
||||
return((my_string) ptr);
|
||||
|
@@ -386,7 +386,7 @@ unsigned int ma_ssl_get_finger_print(MARIADB_SSL *cssl, unsigned char *fp, unsig
|
||||
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;
|
||||
else
|
||||
{
|
||||
|
@@ -20,8 +20,75 @@
|
||||
|
||||
*************************************************************************************/
|
||||
#include "ma_schannel.h"
|
||||
#include <assert.h>
|
||||
|
||||
#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) */
|
||||
/*
|
||||
@@ -44,7 +111,7 @@
|
||||
LPBYTE * a pointer to a 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;
|
||||
char *buffer= NULL;
|
||||
@@ -57,32 +124,53 @@ static LPBYTE ma_schannel_load_pem(const char *PemFileName, DWORD *buffer_len)
|
||||
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)
|
||||
{
|
||||
ma_schannel_set_win_error(cio);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!(*buffer_len = GetFileSize(hfile, NULL)))
|
||||
{
|
||||
cio->set_error(cio->mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, "Invalid pem format");
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (!(buffer= LocalAlloc(0, *buffer_len + 1)))
|
||||
{
|
||||
cio->set_error(cio->mysql, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, NULL);
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (!ReadFile(hfile, buffer, *buffer_len, &dwBytesRead, NULL))
|
||||
{
|
||||
ma_schannel_set_win_error(cio);
|
||||
goto end;
|
||||
}
|
||||
|
||||
CloseHandle(hfile);
|
||||
|
||||
/* calculate the length of DER binary */
|
||||
if (!CryptStringToBinaryA(buffer, *buffer_len, CRYPT_STRING_BASE64HEADER,
|
||||
NULL, &der_buffer_length, NULL, NULL))
|
||||
{
|
||||
ma_schannel_set_win_error(cio);
|
||||
goto end;
|
||||
}
|
||||
/* allocate DER binary buffer */
|
||||
if (!(der_buffer= (LPBYTE)LocalAlloc(0, der_buffer_length)))
|
||||
{
|
||||
cio->set_error(cio->mysql, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, NULL);
|
||||
goto end;
|
||||
}
|
||||
/* convert to DER binary */
|
||||
if (!CryptStringToBinaryA(buffer, *buffer_len, CRYPT_STRING_BASE64HEADER,
|
||||
der_buffer, &der_buffer_length, NULL, NULL))
|
||||
{
|
||||
ma_schannel_set_win_error(cio);
|
||||
goto end;
|
||||
}
|
||||
|
||||
*buffer_len= der_buffer_length;
|
||||
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
|
||||
|
||||
SYNOPSIS
|
||||
ma_schannel_create_cert_context()
|
||||
cio cio object
|
||||
pem_file name of certificate or ca file
|
||||
|
||||
DESCRIPTION
|
||||
@@ -119,7 +208,7 @@ end:
|
||||
NULL If loading of the file or creating context failed
|
||||
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;
|
||||
LPBYTE der_buffer= NULL;
|
||||
@@ -127,10 +216,12 @@ CERT_CONTEXT *ma_schannel_create_cert_context(const char *pem_file)
|
||||
CERT_CONTEXT *ctx= NULL;
|
||||
|
||||
/* 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;
|
||||
ctx= CertCreateCertificateContext(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
|
||||
der_buffer, der_buffer_length);
|
||||
if (!(ctx= CertCreateCertificateContext(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
|
||||
der_buffer, der_buffer_length)))
|
||||
ma_schannel_set_win_error(cio);
|
||||
|
||||
end:
|
||||
if (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
|
||||
|
||||
@@ -156,7 +247,7 @@ end:
|
||||
NULL If loading of the file or creating context failed
|
||||
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;
|
||||
LPBYTE der_buffer= NULL;
|
||||
@@ -164,10 +255,11 @@ PCCRL_CONTEXT ma_schannel_create_crl_context(const char *pem_file)
|
||||
PCCRL_CONTEXT ctx= NULL;
|
||||
|
||||
/* 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;
|
||||
ctx= CertCreateCRLContext(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
|
||||
der_buffer, der_buffer_length);
|
||||
if (!(ctx= CertCreateCRLContext(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
|
||||
der_buffer, der_buffer_length)))
|
||||
ma_schannel_set_win_error(cio);
|
||||
end:
|
||||
if (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
|
||||
|
||||
@@ -195,7 +287,7 @@ end:
|
||||
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;
|
||||
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;
|
||||
HCRYPTPROV crypt_prov= NULL;
|
||||
HCRYPTKEY crypt_key= NULL;
|
||||
CRYPT_KEY_PROV_INFO kpi;
|
||||
CERT_KEY_CONTEXT kpi;
|
||||
my_bool rc= 0;
|
||||
|
||||
/* 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;
|
||||
|
||||
/* 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,
|
||||
0, NULL,
|
||||
NULL, &priv_key_len))
|
||||
{
|
||||
ma_schannel_set_win_error(cio);
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* allocate buffer for decoded private key */
|
||||
if (!(priv_key= LocalAlloc(0, priv_key_len)))
|
||||
{
|
||||
cio->set_error(cio->mysql, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, NULL);
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* decode */
|
||||
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,
|
||||
0, NULL,
|
||||
priv_key, &priv_key_len))
|
||||
{
|
||||
ma_schannel_set_win_error(cio);
|
||||
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, CRYPT_NEWKEYSET))
|
||||
{
|
||||
ma_schannel_set_win_error(cio);
|
||||
goto end;
|
||||
|
||||
}
|
||||
/* ... and import the private key */
|
||||
if (!CryptImportKey(crypt_prov, priv_key, priv_key_len, NULL, 0, &crypt_key))
|
||||
{
|
||||
ma_schannel_set_win_error(cio);
|
||||
goto end;
|
||||
}
|
||||
|
||||
SecureZeroMemory(&kpi, sizeof(kpi));
|
||||
kpi.pwszContainerName = "cio-schanel";
|
||||
kpi.hCryptProv= crypt_prov;
|
||||
kpi.dwKeySpec = AT_KEYEXCHANGE;
|
||||
kpi.dwFlags = CRYPT_MACHINE_KEYSET;
|
||||
kpi.cbSize= sizeof(kpi);
|
||||
|
||||
/* 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;
|
||||
else
|
||||
ma_schannel_set_win_error(cio);
|
||||
|
||||
end:
|
||||
if (der_buffer)
|
||||
LocalFree(der_buffer);
|
||||
@@ -285,7 +396,7 @@ SECURITY_STATUS ma_schannel_handshake_loop(MARIADB_CIO *cio, my_bool InitialRead
|
||||
PUCHAR IoBuffer;
|
||||
BOOL fDoRead;
|
||||
MARIADB_SSL *cssl= cio->cssl;
|
||||
SC_CTX *sctx= (SC_CTX *)cssl->data;
|
||||
SC_CTX *sctx= (SC_CTX *)cssl->ssl;
|
||||
|
||||
|
||||
dwSSPIFlags = ISC_REQ_SEQUENCE_DETECT |
|
||||
@@ -416,6 +527,7 @@ SECURITY_STATUS ma_schannel_handshake_loop(MARIADB_CIO *cio, my_bool InitialRead
|
||||
pExtraData->cbBuffer= 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case SEC_I_INCOMPLETE_CREDENTIALS:
|
||||
/* Provided credentials didn't contain a valid client certificate.
|
||||
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;
|
||||
default:
|
||||
if (FAILED(rc))
|
||||
{
|
||||
ma_schannel_set_sec_error(cio, rc);
|
||||
goto loopend;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -472,22 +587,24 @@ SECURITY_STATUS ma_schannel_client_handshake(MARIADB_SSL *cssl)
|
||||
SecBuffer ExtraData;
|
||||
DWORD SFlags= ISC_REQ_SEQUENCE_DETECT | ISC_REQ_REPLAY_DETECT |
|
||||
ISC_REQ_CONFIDENTIALITY | ISC_RET_EXTENDED_ERROR |
|
||||
ISC_REQ_USE_SUPPLIED_CREDS |
|
||||
ISC_REQ_ALLOCATE_MEMORY | ISC_REQ_STREAM;
|
||||
|
||||
SecBufferDesc BufferIn, BufferOut;
|
||||
SecBuffer BuffersOut[1], BuffersIn[2];
|
||||
|
||||
if (!cssl || !cssl->cio || !cssl->data)
|
||||
if (!cssl || !cssl->cio)
|
||||
return 1;
|
||||
|
||||
cio= cssl->cio;
|
||||
sctx= (SC_CTX *)cssl->data;
|
||||
sctx= (SC_CTX *)cssl->ssl;
|
||||
|
||||
/* Initialie securifty context */
|
||||
BuffersOut[0].BufferType= SECBUFFER_TOKEN;
|
||||
BuffersOut[0].cbBuffer= 0;
|
||||
BuffersOut[0].pvBuffer= NULL;
|
||||
|
||||
|
||||
BufferOut.cBuffers= 1;
|
||||
BufferOut.pBuffers= BuffersOut;
|
||||
BufferOut.ulVersion= SECBUFFER_VERSION;
|
||||
@@ -506,7 +623,18 @@ SECURITY_STATUS ma_schannel_client_handshake(MARIADB_SSL *cssl)
|
||||
NULL);
|
||||
|
||||
if(sRet != SEC_I_CONTINUE_NEEDED)
|
||||
{
|
||||
ma_schannel_set_sec_error(cio, 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 */
|
||||
if(BuffersOut[0].cbBuffer != 0 && BuffersOut[0].pvBuffer != NULL)
|
||||
@@ -518,51 +646,26 @@ SECURITY_STATUS ma_schannel_client_handshake(MARIADB_SSL *cssl)
|
||||
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:
|
||||
LocalFree(sctx->IoBuffer);
|
||||
sctx->IoBufferSize= 0;
|
||||
FreeContextBuffer(BuffersOut[0].pvBuffer);
|
||||
DeleteSecurityContext(&sctx->ctxt);
|
||||
return sRet;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ static PUCHAR ma_schannel_alloc_iobuffer(CtxtHandle *Context, DWORD *BufferLength) */
|
||||
/*
|
||||
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) */
|
||||
/* {{{ SECURITY_STATUS ma_schannel_read_decrypt(MARIADB_CIO *cio, PCredHandle phCreds, CtxtHandle * phContext,
|
||||
DWORD DecryptLength, uchar *ReadBuffer, DWORD ReadBufferSize) */
|
||||
/*
|
||||
Reads encrypted data from a SSL stream and decrypts it.
|
||||
|
||||
@@ -583,7 +686,7 @@ static PUCHAR ma_schannel_alloc_iobuffer(CtxtHandle *Context, DWORD *BufferLengt
|
||||
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,
|
||||
CtxtHandle * phContext,
|
||||
DWORD *DecryptLength,
|
||||
@@ -594,33 +697,23 @@ SECURITY_STATUS ma_schannel_read(MARIADB_CIO *cio,
|
||||
DWORD dwOffset= 0;
|
||||
SC_CTX *sctx;
|
||||
SECURITY_STATUS sRet= 0;
|
||||
SecBuffersDesc Msg;
|
||||
SecBufferDesc Msg;
|
||||
SecBuffer Buffers[4],
|
||||
ExtraBuffer,
|
||||
*pData, *pExtra;
|
||||
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;
|
||||
|
||||
sctx= (SC_CTX *)cio->cssl->data;
|
||||
sctx= (SC_CTX *)cio->cssl->ssl;
|
||||
*DecryptLength= 0;
|
||||
|
||||
/* Allocate IoBuffer */
|
||||
if (!sctx->IoBuffer)
|
||||
{
|
||||
if (!(sctx->IoBuffer= ma_schannel_alloc_iobuffer(&sctx->ctxt, &sctx->IoBufferSize)))
|
||||
{
|
||||
/* todo: error */
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
/* server closed connection */
|
||||
@@ -633,8 +726,9 @@ SECURITY_STATUS ma_schannel_read(MARIADB_CIO *cio,
|
||||
printf("Socket error\n");
|
||||
return NULL;
|
||||
}
|
||||
dwOffset+= dwBytesRead;
|
||||
}
|
||||
ZeroMem(Buffers, sizeof(SecBuffer) * 4);
|
||||
ZeroMemory(Buffers, sizeof(SecBuffer) * 4);
|
||||
Buffers[0].pvBuffer= sctx->IoBuffer;
|
||||
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
|
||||
expired or renogitiation is required */
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -671,8 +765,9 @@ SECURITY_STATUS ma_schannel_read(MARIADB_CIO *cio,
|
||||
|
||||
if (pData && pData->cbBuffer)
|
||||
{
|
||||
memcpy(ReadBuffer + *DecrypthLength, pData->pvBuffer, pData->cbBuffer);
|
||||
memcpy(ReadBuffer + *DecryptLength, pData->pvBuffer, pData->cbBuffer);
|
||||
*DecryptLength+= pData->cbBuffer;
|
||||
return sRet;
|
||||
}
|
||||
|
||||
if (pExtra)
|
||||
@@ -684,4 +779,129 @@ SECURITY_STATUS ma_schannel_read(MARIADB_CIO *cio,
|
||||
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_cio.h>
|
||||
#include <errmsg.h>
|
||||
#include <mysql/client_plugin.h>
|
||||
|
||||
|
||||
typedef void VOID;
|
||||
|
||||
#include <wincrypt.h>
|
||||
#define SECURITY_WIN32
|
||||
#include <wintrust.h>
|
||||
|
||||
|
||||
#include <security.h>
|
||||
|
||||
#include <schnlsp.h>
|
||||
#undef SECURITY_WIN32
|
||||
#include <Windows.h>
|
||||
#include <sspi.h>
|
||||
|
||||
#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
|
||||
#define my_snprintf snprintf
|
||||
@@ -61,12 +61,35 @@ struct st_schannel {
|
||||
CredHandle CredHdl;
|
||||
PUCHAR IoBuffer;
|
||||
DWORD IoBufferSize;
|
||||
/* PUCHAR EncryptBuffer;
|
||||
DWORD EncryptBufferSize;
|
||||
DWORD EncryptBufferLength;
|
||||
PUCHAR DecryptBuffer;
|
||||
DWORD DecryptBufferSize;
|
||||
DWORD DecryptBufferLength;
|
||||
uchar thumbprint[21]; */
|
||||
SecPkgContext_StreamSizes Sizes;
|
||||
|
||||
CtxtHandle ctxt;
|
||||
MYSQL *mysql;
|
||||
};
|
||||
|
||||
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_ */
|
||||
|
@@ -287,10 +287,9 @@ static int ma_ssl_set_certs(MYSQL *mysql)
|
||||
|
||||
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)
|
||||
if (X509_STORE_load_locations(certstore, mysql->options.extension->ssl_crl,
|
||||
mysql->options.extension->ssl_crlpath) == 0 ||
|
||||
X509_STORE_set_flags(certstore, X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL) == 0)
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
@@ -24,77 +24,72 @@
|
||||
|
||||
#define VOID void
|
||||
|
||||
static my_bool my_schannel_initialized= FALSE;
|
||||
|
||||
#define MAX_SSL_ERR_LEN 100
|
||||
extern my_bool ma_ssl_initialized;
|
||||
|
||||
static pthread_mutex_t LOCK_schannel_config;
|
||||
static pthread_mutex_t *LOCK_crypto= NULL;
|
||||
|
||||
int cio_schannel_start(char *errmsg, size_t errmsg_len, int count, va_list);
|
||||
int cio_schannel_end();
|
||||
void *cio_schannel_init(MARIADB_SSL *cssl, MYSQL *mysql);
|
||||
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
|
||||
struct st_cipher_suite {
|
||||
DWORD aid;
|
||||
CHAR *cipher;
|
||||
};
|
||||
|
||||
#ifndef HAVE_SCHANNEL_DEFAULT
|
||||
MARIADB_CIO_PLUGIN _mysql_client_plugin_declaration_=
|
||||
#else
|
||||
MARIADB_CIO_PLUGIN cio_schannel_plugin=
|
||||
#endif
|
||||
void ma_schannel_set_sec_error(MARIADB_CIO *cio, DWORD ErrorNo);
|
||||
void ma_schannel_set_win_error(MYSQL *mysql);
|
||||
|
||||
const struct st_cipher_suite sc_ciphers[]=
|
||||
{
|
||||
MYSQL_CLIENT_CIO_PLUGIN,
|
||||
MYSQL_CLIENT_CIO_PLUGIN_INTERFACE_VERSION,
|
||||
"cio_schannel",
|
||||
"Georg Richter",
|
||||
"MariaDB communication IO plugin for Windows SSL/SChannel communication",
|
||||
{1, 0, 0},
|
||||
"LGPL",
|
||||
cio_schannel_start,
|
||||
cio_schannel_end,
|
||||
NULL,
|
||||
&cio_schannel_methods,
|
||||
NULL
|
||||
{CALG_3DES, "CALG_3DES"},
|
||||
{CALG_3DES_112, "CALG_3DES_112"},
|
||||
{CALG_AES, "CALG_AES"},
|
||||
{CALG_AES_128, "CALG_AES_128"},
|
||||
{CALG_AES_192, "CALG_AES_192"},
|
||||
{CALG_AES_256, "CALG_AES_256"},
|
||||
{CALG_AGREEDKEY_ANY, "CALG_AGREEDKEY_ANY"},
|
||||
{CALG_CYLINK_MEK, "CALG_CYLINK_MEK"},
|
||||
{CALG_DES, "CALG_DES"},
|
||||
{CALG_DESX, "CALG_DESX"},
|
||||
{CALG_DH_EPHEM, "CALG_DH_EPHEM"},
|
||||
{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()
|
||||
{
|
||||
return 0;
|
||||
@@ -106,22 +101,19 @@ static int ssl_thread_init()
|
||||
context SSL_context
|
||||
|
||||
SYNOPSIS
|
||||
cio_schannel_start
|
||||
ma_ssl_start
|
||||
|
||||
RETURN VALUES
|
||||
0 success
|
||||
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_lock(&LOCK_schannel_config);
|
||||
|
||||
// SecureZeroMemory(&SC_CTX, sizeof(struct st_schannel_global));
|
||||
|
||||
my_schannel_initialized= TRUE;
|
||||
ma_ssl_initialized= TRUE;
|
||||
}
|
||||
pthread_mutex_unlock(&LOCK_schannel_config);
|
||||
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
|
||||
|
||||
SYNOPSIS
|
||||
cio_schannel_end()
|
||||
ma_ssl_end()
|
||||
void
|
||||
|
||||
RETURN VALUES
|
||||
void
|
||||
*/
|
||||
int cio_schannel_end()
|
||||
void ma_ssl_end()
|
||||
{
|
||||
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_destroy(&LOCK_schannel_config);
|
||||
return 0;
|
||||
return;
|
||||
}
|
||||
|
||||
/* {{{ static int cio_schannel_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) */
|
||||
static int ma_ssl_set_client_certs(MARIADB_SSL *cssl)
|
||||
{
|
||||
MYSQL *mysql= cssl->cio->mysql;
|
||||
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;
|
||||
|
||||
SC_CTX *sctx= (SC_CTX *)cssl->ssl;
|
||||
MARIADB_CIO *cio= cssl->cio;
|
||||
|
||||
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;
|
||||
|
||||
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 ((myCS= CertOpenStore(CERT_STORE_PROV_SYSTEM,
|
||||
0, //X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
|
||||
0,
|
||||
CERT_SYSTEM_STORE_CURRENT_USER,
|
||||
L"CA")))
|
||||
{
|
||||
if (!(sctx->client_cert_ctx = ma_schannel_create_cert_context(certfile)))
|
||||
goto end;
|
||||
if (keyfile)
|
||||
if (!ma_schannel_load_private_key(sctx->client_cert_ctx, keyfile))
|
||||
CertAddCertificateContextToStore(myCS, sctx->client_ca_ctx, CERT_STORE_ADD_NEWER, NULL);
|
||||
CertCloseStore(myCS, 0);
|
||||
}
|
||||
else {
|
||||
ma_schannel_set_win_error(sctx->mysql);
|
||||
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)
|
||||
{
|
||||
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;
|
||||
|
||||
@@ -189,95 +207,207 @@ end:
|
||||
CertFreeCertificateContext(sctx->client_cert_ctx);
|
||||
if (sctx->client_crl_ctx)
|
||||
CertFreeCRLContext(sctx->client_crl_ctx);
|
||||
|
||||
cio_schannel_set_error(mysql);
|
||||
sctx->client_ca_ctx= sctx->client_cert_ctx= NULL;
|
||||
sctx->client_crl_ctx= NULL;
|
||||
return 1;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ void *cio_schannel_init(MARIADB_SSL *cssl, MYSQL *mysql) */
|
||||
void *cio_schannel_init(MARIADB_SSL *cssl, MYSQL *mysql)
|
||||
/* {{{ void *ma_ssl_init(MARIADB_SSL *cssl, MYSQL *mysql) */
|
||||
void *ma_ssl_init(MYSQL *mysql)
|
||||
{
|
||||
int verify;
|
||||
SC_CTX *sctx;
|
||||
|
||||
if (!(sctx= LocalAlloc(0, sizeof(SC_CTX))))
|
||||
return NULL;
|
||||
ZeroMemory(sctx, sizeof(SC_CTX));
|
||||
|
||||
cssl->data= (void *)sctx;
|
||||
SC_CTX *sctx= NULL;
|
||||
|
||||
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);
|
||||
return NULL;
|
||||
return sctx;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
|
||||
|
||||
|
||||
static my_bool VerifyServerCertificate(SC_CTX *sctx, PCCERT_CONTEXT pServerCert, PSTR pszServerName, DWORD dwCertFlags )
|
||||
my_bool ma_ssl_connect(MARIADB_SSL *cssl)
|
||||
{
|
||||
my_bool blocking;
|
||||
MYSQL *mysql;
|
||||
SCHANNEL_CRED Cred;
|
||||
MARIADB_CIO *cio;
|
||||
SC_CTX *sctx;
|
||||
SECURITY_STATUS sRet;
|
||||
DWORD flags;
|
||||
char *szName= NULL;
|
||||
int rc= 0;
|
||||
PCCERT_CONTEXT pRemoteCertContext = NULL,
|
||||
pLocalCertContext= NULL;
|
||||
ALG_ID AlgId[2]= {0, 0};
|
||||
|
||||
/* We perform a manually validation, as described at
|
||||
http://msdn.microsoft.com/en-us/library/windows/desktop/aa378740%28v=vs.85%29.aspx
|
||||
*/
|
||||
if (!cssl || !cssl->cio)
|
||||
return 1;;
|
||||
|
||||
/* Check if
|
||||
- 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.
|
||||
*/
|
||||
flags= CERT_STORE_SIGNATURE_FLAG |
|
||||
CERT_STORE_TIME_VALIDITY_FLAG;
|
||||
cio= cssl->cio;
|
||||
sctx= (SC_CTX *)cssl->ssl;
|
||||
|
||||
if (!(sRet= CertVerifySubjectCertificateContext(pServerCert,
|
||||
sctx->client_ca_ctx,
|
||||
&flags)))
|
||||
/* 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 (ma_ssl_set_client_certs(cssl))
|
||||
goto end;
|
||||
|
||||
/* Set cipher */
|
||||
if (mysql->options.ssl_cipher)
|
||||
{
|
||||
/* todo: error handling */
|
||||
return 0;
|
||||
DWORD i= 0;
|
||||
while (sc_ciphers[i].cipher) {
|
||||
if (!strcmp(sc_ciphers[i].cipher, mysql->options.ssl_cipher))
|
||||
{
|
||||
AlgId[0]= sc_ciphers[i].aid;
|
||||
break;
|
||||
}
|
||||
}
|
||||
Cred.palgSupportedAlgs= &AlgId;
|
||||
}
|
||||
|
||||
/* Check if none of the certificates in the certificate chain have been revoked. */
|
||||
|
||||
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)
|
||||
{
|
||||
PCRL_INFO Info[1];
|
||||
CertFreeCRLContext(sctx->client_crl_ctx);
|
||||
return 1;
|
||||
}
|
||||
|
||||
Info[0]= sctx->client_crl_ctx->pCrlInfo;
|
||||
if (!(CertVerifyCRLRevocation(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
|
||||
pServerCert->pCertInfo,
|
||||
1, Info)) )
|
||||
size_t ma_ssl_read(MARIADB_SSL *cssl, const uchar* buffer, size_t length)
|
||||
{
|
||||
/* todo: error handling */
|
||||
return 0;
|
||||
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 */
|
||||
if (pszServerName)
|
||||
if (pszServerName && (sctx->mysql->client_flag & CLIENT_SSL_VERIFY_SERVER_CERT))
|
||||
{
|
||||
PCCERT_CONTEXT pServerCert;
|
||||
DWORD NameSize= 0;
|
||||
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,
|
||||
&pServerCert->pCertInfo->Subject,
|
||||
CERT_X500_NAME_STR | CERT_NAME_STR_NO_PLUS_FLAG,
|
||||
NULL, 0)))
|
||||
{
|
||||
/* todo: error handling */
|
||||
return 0;
|
||||
cio->set_error(sctx->mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, "Can't retrieve name of server certificate");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!(szName= LocalAlloc(0, NameSize + 1)))
|
||||
{
|
||||
/* error handling */
|
||||
return 0;
|
||||
cio->set_error(sctx->mysql, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, NULL);
|
||||
goto end;
|
||||
}
|
||||
|
||||
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,
|
||||
szName, NameSize))
|
||||
{
|
||||
/* error handling */
|
||||
cio->set_error(sctx->mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, "Can't retrieve name of server certificate");
|
||||
goto end;
|
||||
}
|
||||
if ((p1 = strstr(szName, "CN=")))
|
||||
@@ -295,116 +425,50 @@ static my_bool VerifyServerCertificate(SC_CTX *sctx, PCCERT_CONTEXT pServerCert,
|
||||
*p2= 0;
|
||||
if (!strcmp(pszServerName, p1))
|
||||
{
|
||||
rc= 1;
|
||||
rc= 0;
|
||||
goto end;
|
||||
}
|
||||
|
||||
cio->set_error(cio->mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN,
|
||||
"Name of server certificate didn't match");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
end:
|
||||
if (szName)
|
||||
LocalFree(szName);
|
||||
return rc;
|
||||
|
||||
}
|
||||
|
||||
my_bool cio_schannel_connect(MARIADB_SSL *cssl)
|
||||
const char *ma_ssl_get_cipher(MARIADB_SSL *cssl)
|
||||
{
|
||||
my_bool blocking;
|
||||
MYSQL *mysql;
|
||||
SCHANNEL_CRED Cred;
|
||||
MARIADB_CIO *cio;
|
||||
SC_CTX *sctx;
|
||||
SecPkgContext_ConnectionInfo cinfo;
|
||||
SECURITY_STATUS sRet;
|
||||
PCCERT_CONTEXT pRemoteCertContext = NULL;
|
||||
SC_CTX *sctx;
|
||||
DWORD i= 0;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
int cio_schannel_verify_server_cert(MARIADB_SSL *cssl)
|
||||
{
|
||||
}
|
||||
|
||||
const char *cio_schannel_cipher(MARIADB_SSL *cssl)
|
||||
{
|
||||
if (!cssl || !cssl->ssl)
|
||||
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;
|
||||
{
|
||||
#ifndef _WIN32
|
||||
memset(&p_fd, 0, sizeof(p_fd));
|
||||
p_fd.fd= csock->socket;
|
||||
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",
|
||||
&trace_init,
|
||||
&trace_deinit,
|
||||
NULL
|
||||
mysql_end_client_plugin;
|
||||
|
||||
static char *commands[]= {
|
||||
|
Binary file not shown.
@@ -57,7 +57,7 @@ static int test_conc66(MYSQL *my)
|
||||
diag("Error: %s", mysql_error(mysql));
|
||||
return FAIL;
|
||||
}
|
||||
rc= mysql_query(my, "DROP USER conc66@localhost");
|
||||
rc= mysql_query(my, "DROP USER conc66@%");
|
||||
|
||||
check_mysql_rc(rc, my);
|
||||
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);
|
||||
diag("unpack: %d %d", rc, my_count);
|
||||
|
||||
diag("---------------__");
|
||||
for(i=0; i < 5; i++)
|
||||
{
|
||||
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++)
|
||||
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_vals);
|
||||
|
@@ -978,6 +978,7 @@ static int test_remote1(MYSQL *mysql)
|
||||
{
|
||||
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);
|
||||
if (!remote_plugin)
|
||||
{
|
||||
|
@@ -67,7 +67,8 @@ static int test_ssl(MYSQL *mysql)
|
||||
|
||||
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, "FLUSH PRVILEGES");
|
||||
}
|
||||
@@ -92,11 +93,7 @@ static int test_ssl_cipher(MYSQL *unused)
|
||||
port, socketname, 0), mysql_error(my));
|
||||
|
||||
cipher= (char *)mysql_get_ssl_cipher(my);
|
||||
#ifdef HAVE_OPENSSL
|
||||
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
|
||||
FAIL_IF(cipher == NULL, "used cipher is NULL");
|
||||
mysql_close(my);
|
||||
return OK;
|
||||
}
|
||||
@@ -109,7 +106,9 @@ static int test_conc95(MYSQL *my)
|
||||
if (check_skip_ssl())
|
||||
return SKIP;
|
||||
|
||||
rc= mysql_query(my, "DROP USER 'ssluser1'@'%'");
|
||||
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");
|
||||
check_mysql_rc(rc, my);
|
||||
rc= mysql_query(my, "FLUSH PRIVILEGES");
|
||||
@@ -117,8 +116,8 @@ static int test_conc95(MYSQL *my)
|
||||
|
||||
mysql= mysql_init(NULL);
|
||||
mysql_ssl_set(mysql,
|
||||
"@CMAKE_SOURCE_DIR@/unittest/libmariadb/certs/server-key.pem",
|
||||
"@CMAKE_SOURCE_DIR@/unittest/libmariadb/certs/server-cert.pem",
|
||||
"@CMAKE_SOURCE_DIR@/unittest/libmariadb/certs/client-key.pem",
|
||||
"@CMAKE_SOURCE_DIR@/unittest/libmariadb/certs/client-cert.pem",
|
||||
"@CMAKE_SOURCE_DIR@/unittest/libmariadb/certs/ca-cert.pem",
|
||||
NULL,
|
||||
NULL);
|
||||
@@ -126,6 +125,7 @@ static int test_conc95(MYSQL *my)
|
||||
if (!mysql_real_connect(mysql, hostname, "ssluser1", sslpw, schema,
|
||||
port, socketname, 0))
|
||||
{
|
||||
diag("Error: %s", mysql_error(mysql));
|
||||
mysql_close(mysql);
|
||||
diag("could not establish x509 connection");
|
||||
return FAIL;
|
||||
@@ -178,11 +178,7 @@ static int test_multi_ssl_connections(MYSQL *unused)
|
||||
}
|
||||
|
||||
cipher= (char *)mysql_get_ssl_cipher(mysql[i]);
|
||||
#ifdef HAVE_OPENSSL
|
||||
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
|
||||
FAIL_IF(cipher == NULL, "used cipher is NULL");
|
||||
}
|
||||
for (i=0; i < 50; i++)
|
||||
mysql_close(mysql[i]);
|
||||
@@ -404,8 +400,11 @@ static int test_conc50_3(MYSQL *my)
|
||||
if (check_skip_ssl())
|
||||
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 : "*");
|
||||
rc= mysql_query(my, query);
|
||||
check_mysql_rc(rc, my);
|
||||
@@ -489,7 +488,7 @@ static int test_bug62743(MYSQL *my)
|
||||
mysql= mysql_init(NULL);
|
||||
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,
|
||||
port, socketname, 0);
|
||||
@@ -596,6 +595,8 @@ static int test_conc_102(MYSQL *mysql)
|
||||
rc= mysql_query(mysql, "INSERT INTO t_conc102 VALUES (0)");
|
||||
check_mysql_rc(rc, mysql);
|
||||
|
||||
pthread_mutex_init(&LOCK_test, 0);
|
||||
|
||||
for (i=0; i < 50; i++)
|
||||
{
|
||||
#ifndef WIN32
|
||||
@@ -614,6 +615,7 @@ static int test_conc_102(MYSQL *mysql)
|
||||
WaitForSingleObject(hthreads[i], INFINITE);
|
||||
#endif
|
||||
}
|
||||
pthread_mutex_destroy(&LOCK_test);
|
||||
rc= mysql_query(mysql, "SELECT a FROM t_conc102");
|
||||
check_mysql_rc(rc, mysql);
|
||||
res= mysql_store_result(mysql);
|
||||
@@ -645,11 +647,7 @@ static int test_ssl_fp(MYSQL *unused)
|
||||
port, socketname, 0), mysql_error(my));
|
||||
|
||||
cipher= (char *)mysql_get_ssl_cipher(my);
|
||||
#ifdef HAVE_OPENSSL
|
||||
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
|
||||
FAIL_IF(cipher == NULL, "used cipher is NULL");
|
||||
mysql_close(my);
|
||||
return OK;
|
||||
}
|
||||
@@ -672,19 +670,43 @@ static int test_ssl_fp_list(MYSQL *unused)
|
||||
FAIL_IF(!mysql_real_connect(my, hostname, ssluser, sslpw, schema,
|
||||
port, socketname, 0), mysql_error(my));
|
||||
|
||||
#ifdef HAVE_OPENSSL
|
||||
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
|
||||
cipher= mysql_get_ssl_cipher(my);
|
||||
FAIL_IF(cipher == NULL, "used cipher is NULL");
|
||||
mysql_close(my);
|
||||
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[] = {
|
||||
{"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_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},
|
||||
|
Reference in New Issue
Block a user