diff --git a/include/ma_secure.h b/include/ma_secure.h deleted file mode 100644 index b380630a..00000000 --- a/include/ma_secure.h +++ /dev/null @@ -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 - 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 -#include /* SSL and SSL_CTX */ -#include /* error reporting */ -#include - -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_ */ diff --git a/include/ma_ssl.h b/include/ma_ssl.h index cdd33162..b9c84b77 100644 --- a/include/ma_ssl.h +++ b/include/ma_ssl.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_ */ diff --git a/libmariadb/libmariadb.c b/libmariadb/libmariadb.c index 4710f644..bbc03e18 100644 --- a/libmariadb/libmariadb.c +++ b/libmariadb/libmariadb.c @@ -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); diff --git a/libmariadb/ma_cio.c b/libmariadb/ma_cio.c index 0b234a48..fabb1417 100644 --- a/libmariadb/ma_cio.c +++ b/libmariadb/ma_cio.c @@ -283,7 +283,7 @@ size_t ma_cio_cache_read(MARIADB_CIO *cio, uchar *buffer, size_t length) } memcpy(buffer, cio->cache, r); } - } + } return r; } /* }}} */ diff --git a/libmariadb/ma_secure.c b/libmariadb/ma_secure.c deleted file mode 100644 index cda76f38..00000000 --- a/libmariadb/ma_secure.c +++ /dev/null @@ -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 - 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 -#include -#include -#include -#include -#include -#include -#include - -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 */ diff --git a/libmariadb/ma_ssl.c b/libmariadb/ma_ssl.c index 272df926..3e9708ee 100644 --- a/libmariadb/ma_ssl.c +++ b/libmariadb/ma_ssl.c @@ -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) diff --git a/libmariadb/my_malloc.c b/libmariadb/my_malloc.c index 0e681cae..429932d4 100644 --- a/libmariadb/my_malloc.c +++ b/libmariadb/my_malloc.c @@ -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); diff --git a/libmariadb/secure/gnutls.c b/libmariadb/secure/gnutls.c index bb22230b..ee48201d 100644 --- a/libmariadb/secure/gnutls.c +++ b/libmariadb/secure/gnutls.c @@ -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 { diff --git a/libmariadb/secure/ma_schannel.c b/libmariadb/secure/ma_schannel.c index c66684dd..d27d895f 100644 --- a/libmariadb/secure/ma_schannel.c +++ b/libmariadb/secure/ma_schannel.c @@ -20,8 +20,75 @@ *************************************************************************************/ #include "ma_schannel.h" +#include #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,44 +686,34 @@ static PUCHAR ma_schannel_alloc_iobuffer(CtxtHandle *Context, DWORD *BufferLengt SEC_E_* if an error occured */ -SECURITY_STATUS ma_schannel_read(MARIADB_CIO *cio, - PCredHandle phCreds, - CtxtHandle * phContext, - DWORD *DecryptLength, - uchar *ReadBuffer, - DWORD ReadBufferSize) +SECURITY_STATUS ma_schannel_read_decrypt(MARIADB_CIO *cio, + PCredHandle phCreds, + CtxtHandle * phContext, + DWORD *DecryptLength, + uchar *ReadBuffer, + DWORD ReadBufferSize) { DWORD dwBytesRead= 0; 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; } @@ -668,11 +762,12 @@ SECURITY_STATUS ma_schannel_read(MARIADB_CIO *cio, if (pData && pExtra) break; } - + 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; +} /* }}} */ + diff --git a/libmariadb/secure/ma_schannel.h b/libmariadb/secure/ma_schannel.h index 006613ef..6aa937c1 100644 --- a/libmariadb/secure/ma_schannel.h +++ b/libmariadb/secure/ma_schannel.h @@ -28,23 +28,23 @@ #include #include #include -#include + typedef void VOID; #include -#define SECURITY_WIN32 +#include + + #include + #include #undef SECURITY_WIN32 #include +#include #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_ */ diff --git a/libmariadb/secure/openssl.c b/libmariadb/secure/openssl.c index 18a140c6..26809b11 100644 --- a/libmariadb/secure/openssl.c +++ b/libmariadb/secure/openssl.c @@ -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; } } diff --git a/libmariadb/secure/schannel.c b/libmariadb/secure/schannel.c index 26b49f99..e77e661c 100644 --- a/libmariadb/secure/schannel.c +++ b/libmariadb/secure/schannel.c @@ -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) - { - if (!(sctx->client_cert_ctx = ma_schannel_create_cert_context(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"))) + { + 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 (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) { - 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}; + + if (!cssl || !cssl->cio) + return 1;; + + cio= cssl->cio; + sctx= (SC_CTX *)cssl->ssl; - /* We perform a manually validation, as described at - http://msdn.microsoft.com/en-us/library/windows/desktop/aa378740%28v=vs.85%29.aspx - */ + /* Set socket to blocking if not already set */ + if (!(blocking= cio->methods->is_blocking(cio))) + cio->methods->blocking(cio, TRUE, 0); - /* 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; - - if (!(sRet= CertVerifySubjectCertificateContext(pServerCert, - sctx->client_ca_ctx, - &flags))) + mysql= cio->mysql; + + if (ma_ssl_set_client_certs(cssl)) + goto end; + + /* Set cipher */ + if (mysql->options.ssl_cipher) { - /* todo: error handling */ - 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)) ) - { - /* 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; } + + 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 */ - 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) -{ - 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; - + if (szName) + LocalFree(szName); 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) 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; +} \ No newline at end of file diff --git a/plugins/builtin/cio_socket.c b/plugins/builtin/cio_socket.c index a4060ab7..485b1c2c 100644 --- a/plugins/builtin/cio_socket.c +++ b/plugins/builtin/cio_socket.c @@ -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; diff --git a/plugins/cio/tls_schannel.c b/plugins/cio/tls_schannel.c deleted file mode 100644 index 6fb27536..00000000 --- a/plugins/cio/tls_schannel.c +++ /dev/null @@ -1,1257 +0,0 @@ - * SSL/TLS interface functions for Microsoft Schannel - - * Copyright (c) 2005-2009, Jouni Malinen - - * - - * This program is free software; you can redistribute it and/or modify - - * it under the terms of the GNU General Public License version 2 as - - * published by the Free Software Foundation. - - * - - * Alternatively, this software may be distributed under the terms of BSD - - * license. - - * - - * See README and COPYING for more details. - - */ - -/* - - * FIX: Go through all SSPI functions and verify what needs to be freed - - * FIX: session resumption - - * TODO: add support for server cert chain validation - - * TODO: add support for CA cert validation - - * TODO: add support for EAP-TLS (client cert/key conf) - - */ - -#include "includes.h" - -#include - -#include - -#include - -#define SECURITY_WIN32 - -#include - -#include - -#include "common.h" - -#include "tls.h" - -struct tls_global { - - HMODULE hsecurity; - - PSecurityFunctionTable sspi; - - HCERTSTORE my_cert_store; - -}; - -struct tls_connection { - - int established, start; - - int failed, read_alerts, write_alerts; - - SCHANNEL_CRED schannel_cred; - - CredHandle creds; - - CtxtHandle context; - - u8 eap_tls_prf[128]; - - int eap_tls_prf_set; - -}; - -static int schannel_load_lib(struct tls_global *global) - -{ - - INIT_SECURITY_INTERFACE pInitSecurityInterface; - - global->hsecurity = LoadLibrary(TEXT("Secur32.dll")); - - if (global->hsecurity == NULL) { - - wpa_printf(MSG_ERROR, "%s: Could not load Secur32.dll - 0x%x", - - __func__, (unsigned int) GetLastError()); - - return -1; - - } - - pInitSecurityInterface = (INIT_SECURITY_INTERFACE) GetProcAddress( - - global->hsecurity, "InitSecurityInterfaceA"); - - if (pInitSecurityInterface == NULL) { - - wpa_printf(MSG_ERROR, "%s: Could not find " - - "InitSecurityInterfaceA from Secur32.dll", - - __func__); - - FreeLibrary(global->hsecurity); - - global->hsecurity = NULL; - - return -1; - - } - - global->sspi = pInitSecurityInterface(); - - if (global->sspi == NULL) { - - wpa_printf(MSG_ERROR, "%s: Could not read security " - - "interface - 0x%x", - - __func__, (unsigned int) GetLastError()); - - FreeLibrary(global->hsecurity); - - global->hsecurity = NULL; - - return -1; - - } - - return 0; - -} - -void * tls_init(const struct tls_config *conf) - -{ - - struct tls_global *global; - - global = os_zalloc(sizeof(*global)); - - if (global == NULL) - - return NULL; - - if (schannel_load_lib(global)) { - - os_free(global); - - return NULL; - - } - - return global; - -} - -void tls_deinit(void *ssl_ctx) - -{ - - struct tls_global *global = ssl_ctx; - - if (global->my_cert_store) - - CertCloseStore(global->my_cert_store, 0); - - FreeLibrary(global->hsecurity); - - os_free(global); - -} - -int tls_get_errors(void *ssl_ctx) - -{ - - return 0; - -} - -struct tls_connection * tls_connection_init(void *ssl_ctx) - -{ - - struct tls_connection *conn; - - conn = os_zalloc(sizeof(*conn)); - - if (conn == NULL) - - return NULL; - - conn->start = 1; - - return conn; - -} - -void tls_connection_deinit(void *ssl_ctx, struct tls_connection *conn) - -{ - - if (conn == NULL) - - return; - - os_free(conn); - -} - -int tls_connection_established(void *ssl_ctx, struct tls_connection *conn) - -{ - - return conn ? conn->established : 0; - -} - -int tls_connection_shutdown(void *ssl_ctx, struct tls_connection *conn) - -{ - - struct tls_global *global = ssl_ctx; - - if (conn == NULL) - - return -1; - - conn->eap_tls_prf_set = 0; - - conn->established = conn->failed = 0; - - conn->read_alerts = conn->write_alerts = 0; - - global->sspi->DeleteSecurityContext(&conn->context); - - /* FIX: what else needs to be reseted? */ - - return 0; - -} - -int tls_global_set_params(void *tls_ctx, - - const struct tls_connection_params *params) - -{ - - return -1; - -} - -int tls_global_set_verify(void *ssl_ctx, int check_crl) - -{ - - return -1; - -} - -int tls_connection_set_verify(void *ssl_ctx, struct tls_connection *conn, - - int verify_peer) - -{ - - return -1; - -} - -int tls_connection_get_keys(void *ssl_ctx, struct tls_connection *conn, - - struct tls_keys *keys) - -{ - - /* Schannel does not export master secret or client/server random. */ - - return -1; - -} - -int tls_connection_prf(void *tls_ctx, struct tls_connection *conn, - - const char *label, int server_random_first, - - u8 *out, size_t out_len) - -{ - - /* - - * Cannot get master_key from Schannel, but EapKeyBlock can be used to - - * generate session keys for EAP-TLS and EAP-PEAPv0. EAP-PEAPv2 and - - * EAP-TTLS cannot use this, though, since they are using different - - * labels. The only option could be to implement TLSv1 completely here - - * and just use Schannel or CryptoAPI for low-level crypto - - * functionality.. - - */ - - if (conn == NULL || !conn->eap_tls_prf_set || server_random_first || - - os_strcmp(label, "client EAP encryption") != 0 || - - out_len > sizeof(conn->eap_tls_prf)) - - return -1; - - os_memcpy(out, conn->eap_tls_prf, out_len); - - return 0; - -} - -static struct wpabuf * tls_conn_hs_clienthello(struct tls_global *global, - - struct tls_connection *conn) - -{ - - DWORD sspi_flags, sspi_flags_out; - - SecBufferDesc outbuf; - - SecBuffer outbufs[1]; - - SECURITY_STATUS status; - - TimeStamp ts_expiry; - - sspi_flags = ISC_REQ_REPLAY_DETECT | - - ISC_REQ_CONFIDENTIALITY | - - ISC_RET_EXTENDED_ERROR | - - ISC_REQ_ALLOCATE_MEMORY | - - ISC_REQ_MANUAL_CRED_VALIDATION; - - wpa_printf(MSG_DEBUG, "%s: Generating ClientHello", __func__); - - outbufs[0].pvBuffer = NULL; - - outbufs[0].BufferType = SECBUFFER_TOKEN; - - outbufs[0].cbBuffer = 0; - - outbuf.cBuffers = 1; - - outbuf.pBuffers = outbufs; - - outbuf.ulVersion = SECBUFFER_VERSION; - -#ifdef UNICODE - - status = global->sspi->InitializeSecurityContextW( - - &conn->creds, NULL, NULL /* server name */, sspi_flags, 0, - - SECURITY_NATIVE_DREP, NULL, 0, &conn->context, - - &outbuf, &sspi_flags_out, &ts_expiry); - -#else /* UNICODE */ - - status = global->sspi->InitializeSecurityContextA( - - &conn->creds, NULL, NULL /* server name */, sspi_flags, 0, - - SECURITY_NATIVE_DREP, NULL, 0, &conn->context, - - &outbuf, &sspi_flags_out, &ts_expiry); - -#endif /* UNICODE */ - - if (status != SEC_I_CONTINUE_NEEDED) { - - wpa_printf(MSG_ERROR, "%s: InitializeSecurityContextA " - - "failed - 0x%x", - - __func__, (unsigned int) status); - - return NULL; - - } - - if (outbufs[0].cbBuffer != 0 && outbufs[0].pvBuffer) { - - struct wpabuf *buf; - - wpa_hexdump(MSG_MSGDUMP, "SChannel - ClientHello", - - outbufs[0].pvBuffer, outbufs[0].cbBuffer); - - conn->start = 0; - - buf = wpabuf_alloc_copy(outbufs[0].pvBuffer, - - outbufs[0].cbBuffer); - - if (buf == NULL) - - return NULL; - - global->sspi->FreeContextBuffer(outbufs[0].pvBuffer); - - return buf; - - } - - wpa_printf(MSG_ERROR, "SChannel: Failed to generate ClientHello"); - - return NULL; - -} - -#ifndef SECPKG_ATTR_EAP_KEY_BLOCK - -#define SECPKG_ATTR_EAP_KEY_BLOCK 0x5b - -typedef struct _SecPkgContext_EapKeyBlock { - - BYTE rgbKeys[128]; - - BYTE rgbIVs[64]; - -} SecPkgContext_EapKeyBlock, *PSecPkgContext_EapKeyBlock; - -#endif /* !SECPKG_ATTR_EAP_KEY_BLOCK */ - -static int tls_get_eap(struct tls_global *global, struct tls_connection *conn) - -{ - - SECURITY_STATUS status; - - SecPkgContext_EapKeyBlock kb; - - /* Note: Windows NT and Windows Me/98/95 do not support getting - - * EapKeyBlock */ - - status = global->sspi->QueryContextAttributes( - - &conn->context, SECPKG_ATTR_EAP_KEY_BLOCK, &kb); - - if (status != SEC_E_OK) { - - wpa_printf(MSG_DEBUG, "%s: QueryContextAttributes(" - - "SECPKG_ATTR_EAP_KEY_BLOCK) failed (%d)", - - __func__, (int) status); - - return -1; - - } - - wpa_hexdump_key(MSG_MSGDUMP, "Schannel - EapKeyBlock - rgbKeys", - - kb.rgbKeys, sizeof(kb.rgbKeys)); - - wpa_hexdump_key(MSG_MSGDUMP, "Schannel - EapKeyBlock - rgbIVs", - - kb.rgbIVs, sizeof(kb.rgbIVs)); - - os_memcpy(conn->eap_tls_prf, kb.rgbKeys, sizeof(kb.rgbKeys)); - - conn->eap_tls_prf_set = 1; - - return 0; - -} - -struct wpabuf * tls_connection_handshake(void *tls_ctx, - - struct tls_connection *conn, - - const struct wpabuf *in_data, - - struct wpabuf **appl_data) - -{ - - struct tls_global *global = tls_ctx; - - DWORD sspi_flags, sspi_flags_out; - - SecBufferDesc inbuf, outbuf; - - SecBuffer inbufs[2], outbufs[1]; - - SECURITY_STATUS status; - - TimeStamp ts_expiry; - - struct wpabuf *out_buf = NULL; - - if (appl_data) - - *appl_data = NULL; - - if (conn->start) - - return tls_conn_hs_clienthello(global, conn); - - wpa_printf(MSG_DEBUG, "SChannel: %d bytes handshake data to process", - - (int) wpabuf_len(in_data)); - - sspi_flags = ISC_REQ_REPLAY_DETECT | - - ISC_REQ_CONFIDENTIALITY | - - ISC_RET_EXTENDED_ERROR | - - ISC_REQ_ALLOCATE_MEMORY | - - ISC_REQ_MANUAL_CRED_VALIDATION; - - /* Input buffer for Schannel */ - - inbufs[0].pvBuffer = (u8 *) wpabuf_head(in_data); - - inbufs[0].cbBuffer = wpabuf_len(in_data); - - inbufs[0].BufferType = SECBUFFER_TOKEN; - - /* Place for leftover data from Schannel */ - - inbufs[1].pvBuffer = NULL; - - inbufs[1].cbBuffer = 0; - - inbufs[1].BufferType = SECBUFFER_EMPTY; - - inbuf.cBuffers = 2; - - inbuf.pBuffers = inbufs; - - inbuf.ulVersion = SECBUFFER_VERSION; - - /* Output buffer for Schannel */ - - outbufs[0].pvBuffer = NULL; - - outbufs[0].cbBuffer = 0; - - outbufs[0].BufferType = SECBUFFER_TOKEN; - - outbuf.cBuffers = 1; - - outbuf.pBuffers = outbufs; - - outbuf.ulVersion = SECBUFFER_VERSION; - -#ifdef UNICODE - - status = global->sspi->InitializeSecurityContextW( - - &conn->creds, &conn->context, NULL, sspi_flags, 0, - - SECURITY_NATIVE_DREP, &inbuf, 0, NULL, - - &outbuf, &sspi_flags_out, &ts_expiry); - -#else /* UNICODE */ - - status = global->sspi->InitializeSecurityContextA( - - &conn->creds, &conn->context, NULL, sspi_flags, 0, - - SECURITY_NATIVE_DREP, &inbuf, 0, NULL, - - &outbuf, &sspi_flags_out, &ts_expiry); - -#endif /* UNICODE */ - - wpa_printf(MSG_MSGDUMP, "Schannel: InitializeSecurityContext -> " - - "status=%d inlen[0]=%d intype[0]=%d inlen[1]=%d " - - "intype[1]=%d outlen[0]=%d", - - (int) status, (int) inbufs[0].cbBuffer, - - (int) inbufs[0].BufferType, (int) inbufs[1].cbBuffer, - - (int) inbufs[1].BufferType, - - (int) outbufs[0].cbBuffer); - - if (status == SEC_E_OK || status == SEC_I_CONTINUE_NEEDED || - - (FAILED(status) && (sspi_flags_out & ISC_RET_EXTENDED_ERROR))) { - - if (outbufs[0].cbBuffer != 0 && outbufs[0].pvBuffer) { - - wpa_hexdump(MSG_MSGDUMP, "SChannel - output", - - outbufs[0].pvBuffer, outbufs[0].cbBuffer); - - out_buf = wpabuf_alloc_copy(outbufs[0].pvBuffer, - - outbufs[0].cbBuffer); - - global->sspi->FreeContextBuffer(outbufs[0].pvBuffer); - - outbufs[0].pvBuffer = NULL; - - if (out_buf == NULL) - - return NULL; - - } - - } - - switch (status) { - - case SEC_E_INCOMPLETE_MESSAGE: - - wpa_printf(MSG_DEBUG, "Schannel: SEC_E_INCOMPLETE_MESSAGE"); - - break; - - case SEC_I_CONTINUE_NEEDED: - - wpa_printf(MSG_DEBUG, "Schannel: SEC_I_CONTINUE_NEEDED"); - - break; - - case SEC_E_OK: - - /* TODO: verify server certificate chain */ - - wpa_printf(MSG_DEBUG, "Schannel: SEC_E_OK - Handshake " - - "completed successfully"); - - conn->established = 1; - - tls_get_eap(global, conn); - - /* Need to return something to get final TLS ACK. */ - - if (out_buf == NULL) - - out_buf = wpabuf_alloc(0); - - if (inbufs[1].BufferType == SECBUFFER_EXTRA) { - - wpa_hexdump(MSG_MSGDUMP, "SChannel - Encrypted " - - "application data", - - inbufs[1].pvBuffer, inbufs[1].cbBuffer); - - if (appl_data) { - - *appl_data = wpabuf_alloc_copy( - - outbufs[1].pvBuffer, - - outbufs[1].cbBuffer); - - } - - global->sspi->FreeContextBuffer(inbufs[1].pvBuffer); - - inbufs[1].pvBuffer = NULL; - - } - - break; - - case SEC_I_INCOMPLETE_CREDENTIALS: - - wpa_printf(MSG_DEBUG, - - "Schannel: SEC_I_INCOMPLETE_CREDENTIALS"); - - break; - - case SEC_E_WRONG_PRINCIPAL: - - wpa_printf(MSG_DEBUG, "Schannel: SEC_E_WRONG_PRINCIPAL"); - - break; - - case SEC_E_INTERNAL_ERROR: - - wpa_printf(MSG_DEBUG, "Schannel: SEC_E_INTERNAL_ERROR"); - - break; - - } - - if (FAILED(status)) { - - wpa_printf(MSG_DEBUG, "Schannel: Handshake failed " - - "(out_buf=%p)", out_buf); - - conn->failed++; - - global->sspi->DeleteSecurityContext(&conn->context); - - return out_buf; - - } - - if (inbufs[1].BufferType == SECBUFFER_EXTRA) { - - /* TODO: Can this happen? What to do with this data? */ - - wpa_hexdump(MSG_MSGDUMP, "SChannel - Leftover data", - - inbufs[1].pvBuffer, inbufs[1].cbBuffer); - - global->sspi->FreeContextBuffer(inbufs[1].pvBuffer); - - inbufs[1].pvBuffer = NULL; - - } - - return out_buf; - -} - -struct wpabuf * tls_connection_server_handshake(void *tls_ctx, - - struct tls_connection *conn, - - const struct wpabuf *in_data, - - struct wpabuf **appl_data) - -{ - - return NULL; - -} - -struct wpabuf * tls_connection_encrypt(void *tls_ctx, - - struct tls_connection *conn, - - const struct wpabuf *in_data) - -{ - - struct tls_global *global = tls_ctx; - - SECURITY_STATUS status; - - SecBufferDesc buf; - - SecBuffer bufs[4]; - - SecPkgContext_StreamSizes sizes; - - int i; - - struct wpabuf *out; - - status = global->sspi->QueryContextAttributes(&conn->context, - - SECPKG_ATTR_STREAM_SIZES, - - &sizes); - - if (status != SEC_E_OK) { - - wpa_printf(MSG_DEBUG, "%s: QueryContextAttributes failed", - - __func__); - - return NULL; - - } - - wpa_printf(MSG_DEBUG, "%s: Stream sizes: header=%u trailer=%u", - - __func__, - - (unsigned int) sizes.cbHeader, - - (unsigned int) sizes.cbTrailer); - - out = wpabuf_alloc(sizes.cbHeader + wpabuf_len(in_data) + - - sizes.cbTrailer); - - os_memset(&bufs, 0, sizeof(bufs)); - - bufs[0].pvBuffer = wpabuf_put(out, sizes.cbHeader); - - bufs[0].cbBuffer = sizes.cbHeader; - - bufs[0].BufferType = SECBUFFER_STREAM_HEADER; - - bufs[1].pvBuffer = wpabuf_put(out, 0); - - wpabuf_put_buf(out, in_data); - - bufs[1].cbBuffer = wpabuf_len(in_data); - - bufs[1].BufferType = SECBUFFER_DATA; - - bufs[2].pvBuffer = wpabuf_put(out, sizes.cbTrailer); - - bufs[2].cbBuffer = sizes.cbTrailer; - - bufs[2].BufferType = SECBUFFER_STREAM_TRAILER; - - buf.ulVersion = SECBUFFER_VERSION; - - buf.cBuffers = 3; - - buf.pBuffers = bufs; - - status = global->sspi->EncryptMessage(&conn->context, 0, &buf, 0); - - wpa_printf(MSG_MSGDUMP, "Schannel: EncryptMessage -> " - - "status=%d len[0]=%d type[0]=%d len[1]=%d type[1]=%d " - - "len[2]=%d type[2]=%d", - - (int) status, - - (int) bufs[0].cbBuffer, (int) bufs[0].BufferType, - - (int) bufs[1].cbBuffer, (int) bufs[1].BufferType, - - (int) bufs[2].cbBuffer, (int) bufs[2].BufferType); - - wpa_printf(MSG_MSGDUMP, "Schannel: EncryptMessage pointers: " - - "out_data=%p bufs %p %p %p", - - wpabuf_head(out), bufs[0].pvBuffer, bufs[1].pvBuffer, - - bufs[2].pvBuffer); - - for (i = 0; i < 3; i++) { - - if (bufs[i].pvBuffer && bufs[i].BufferType != SECBUFFER_EMPTY) - - { - - wpa_hexdump(MSG_MSGDUMP, "SChannel: bufs", - - bufs[i].pvBuffer, bufs[i].cbBuffer); - - } - - } - - if (status == SEC_E_OK) { - - wpa_printf(MSG_DEBUG, "%s: SEC_E_OK", __func__); - - wpa_hexdump_buf_key(MSG_MSGDUMP, "Schannel: Encrypted data " - - "from EncryptMessage", out); - - return out; - - } - - wpa_printf(MSG_DEBUG, "%s: Failed - status=%d", - - __func__, (int) status); - - wpabuf_free(out); - - return NULL; - -} - -struct wpabuf * tls_connection_decrypt(void *tls_ctx, - - struct tls_connection *conn, - - const struct wpabuf *in_data) - -{ - - struct tls_global *global = tls_ctx; - - SECURITY_STATUS status; - - SecBufferDesc buf; - - SecBuffer bufs[4]; - - int i; - - struct wpabuf *out, *tmp; - - wpa_hexdump_buf(MSG_MSGDUMP, - - "Schannel: Encrypted data to DecryptMessage", in_data); - - os_memset(&bufs, 0, sizeof(bufs)); - - tmp = wpabuf_dup(in_data); - - if (tmp == NULL) - - return NULL; - - bufs[0].pvBuffer = wpabuf_mhead(tmp); - - bufs[0].cbBuffer = wpabuf_len(in_data); - - bufs[0].BufferType = SECBUFFER_DATA; - - bufs[1].BufferType = SECBUFFER_EMPTY; - - bufs[2].BufferType = SECBUFFER_EMPTY; - - bufs[3].BufferType = SECBUFFER_EMPTY; - - buf.ulVersion = SECBUFFER_VERSION; - - buf.cBuffers = 4; - - buf.pBuffers = bufs; - - status = global->sspi->DecryptMessage(&conn->context, &buf, 0, - - NULL); - - wpa_printf(MSG_MSGDUMP, "Schannel: DecryptMessage -> " - - "status=%d len[0]=%d type[0]=%d len[1]=%d type[1]=%d " - - "len[2]=%d type[2]=%d len[3]=%d type[3]=%d", - - (int) status, - - (int) bufs[0].cbBuffer, (int) bufs[0].BufferType, - - (int) bufs[1].cbBuffer, (int) bufs[1].BufferType, - - (int) bufs[2].cbBuffer, (int) bufs[2].BufferType, - - (int) bufs[3].cbBuffer, (int) bufs[3].BufferType); - - wpa_printf(MSG_MSGDUMP, "Schannel: DecryptMessage pointers: " - - "out_data=%p bufs %p %p %p %p", - - wpabuf_head(tmp), bufs[0].pvBuffer, bufs[1].pvBuffer, - - bufs[2].pvBuffer, bufs[3].pvBuffer); - - switch (status) { - - case SEC_E_INCOMPLETE_MESSAGE: - - wpa_printf(MSG_DEBUG, "%s: SEC_E_INCOMPLETE_MESSAGE", - - __func__); - - break; - - case SEC_E_OK: - - wpa_printf(MSG_DEBUG, "%s: SEC_E_OK", __func__); - - for (i = 0; i < 4; i++) { - - if (bufs[i].BufferType == SECBUFFER_DATA) - - break; - - } - - if (i == 4) { - - wpa_printf(MSG_DEBUG, "%s: No output data from " - - "DecryptMessage", __func__); - - wpabuf_free(tmp); - - return NULL; - - } - - wpa_hexdump_key(MSG_MSGDUMP, "Schannel: Decrypted data from " - - "DecryptMessage", - - bufs[i].pvBuffer, bufs[i].cbBuffer); - - out = wpabuf_alloc_copy(bufs[i].pvBuffer, bufs[i].cbBuffer); - - wpabuf_free(tmp); - - return out; - - } - - wpa_printf(MSG_DEBUG, "%s: Failed - status=%d", - - __func__, (int) status); - - wpabuf_free(tmp); - - return NULL; - -} - -int tls_connection_resumed(void *ssl_ctx, struct tls_connection *conn) - -{ - - return 0; - -} - -int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn, - - u8 *ciphers) - -{ - - return -1; - -} - -int tls_get_cipher(void *ssl_ctx, struct tls_connection *conn, - - char *buf, size_t buflen) - -{ - - return -1; - -} - -int tls_connection_enable_workaround(void *ssl_ctx, - - struct tls_connection *conn) - -{ - - return 0; - -} - -int tls_connection_client_hello_ext(void *ssl_ctx, struct tls_connection *conn, - - int ext_type, const u8 *data, - - size_t data_len) - -{ - - return -1; - -} - -int tls_connection_get_failed(void *ssl_ctx, struct tls_connection *conn) - -{ - - if (conn == NULL) - - return -1; - - return conn->failed; - -} - -int tls_connection_get_read_alerts(void *ssl_ctx, struct tls_connection *conn) - -{ - - if (conn == NULL) - - return -1; - - return conn->read_alerts; - -} - -int tls_connection_get_write_alerts(void *ssl_ctx, struct tls_connection *conn) - -{ - - if (conn == NULL) - - return -1; - - return conn->write_alerts; - -} - -int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn, - - const struct tls_connection_params *params) - -{ - - struct tls_global *global = tls_ctx; - - ALG_ID algs[1]; - - SECURITY_STATUS status; - - TimeStamp ts_expiry; - - if (conn == NULL) - - return -1; - - if (global->my_cert_store == NULL && - - (global->my_cert_store = CertOpenSystemStore(0, TEXT("MY"))) == - - NULL) { - - wpa_printf(MSG_ERROR, "%s: CertOpenSystemStore failed - 0x%x", - - __func__, (unsigned int) GetLastError()); - - return -1; - - } - - os_memset(&conn->schannel_cred, 0, sizeof(conn->schannel_cred)); - - conn->schannel_cred.dwVersion = SCHANNEL_CRED_VERSION; - - conn->schannel_cred.grbitEnabledProtocols = SP_PROT_TLS1; - - algs[0] = CALG_RSA_KEYX; - - conn->schannel_cred.cSupportedAlgs = 1; - - conn->schannel_cred.palgSupportedAlgs = algs; - - conn->schannel_cred.dwFlags |= SCH_CRED_NO_DEFAULT_CREDS; - -#ifdef UNICODE - - status = global->sspi->AcquireCredentialsHandleW( - - NULL, UNISP_NAME_W, SECPKG_CRED_OUTBOUND, NULL, - - &conn->schannel_cred, NULL, NULL, &conn->creds, &ts_expiry); - -#else /* UNICODE */ - - status = global->sspi->AcquireCredentialsHandleA( - - NULL, UNISP_NAME_A, SECPKG_CRED_OUTBOUND, NULL, - - &conn->schannel_cred, NULL, NULL, &conn->creds, &ts_expiry); - -#endif /* UNICODE */ - - if (status != SEC_E_OK) { - - wpa_printf(MSG_DEBUG, "%s: AcquireCredentialsHandleA failed - " - - "0x%x", __func__, (unsigned int) status); - - return -1; - - } - - return 0; - -} - -unsigned int tls_capabilities(void *tls_ctx) - -{ - - return 0; - -} - -int tls_connection_set_ia(void *tls_ctx, struct tls_connection *conn, - - int tls_ia) - -{ - - return -1; - -} - -int tls_connection_ia_send_phase_finished(void *tls_ctx, - - struct tls_connection *conn, - - int final, - - u8 *out_data, size_t out_len) - -{ - - return -1; - -} - -int tls_connection_ia_final_phase_finished(void *tls_ctx, - - struct tls_connection *conn) - -{ - - return -1; - -} - -int tls_connection_ia_permute_inner_secret(void *tls_ctx, - - struct tls_connection *conn, - - const u8 *key, size_t key_len) - -{ - - return -1; - -} - - diff --git a/plugins/trace/trace_example.c b/plugins/trace/trace_example.c index 25854e48..1ce5d1b8 100644 --- a/plugins/trace/trace_example.c +++ b/plugins/trace/trace_example.c @@ -52,7 +52,6 @@ mysql_declare_client_plugin(TRACE) "LGPL", &trace_init, &trace_deinit, - NULL mysql_end_client_plugin; static char *commands[]= { diff --git a/plugins/trace/trace_example.so b/plugins/trace/trace_example.so index e92d7a54..c26ca826 100755 Binary files a/plugins/trace/trace_example.so and b/plugins/trace/trace_example.so differ diff --git a/unittest/libmariadb/connection.c b/unittest/libmariadb/connection.c index 5896b6d5..dc89d9c6 100644 --- a/unittest/libmariadb/connection.c +++ b/unittest/libmariadb/connection.c @@ -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); diff --git a/unittest/libmariadb/dyncol.c b/unittest/libmariadb/dyncol.c index 3da1cf22..bba1069d 100644 --- a/unittest/libmariadb/dyncol.c +++ b/unittest/libmariadb/dyncol.c @@ -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); diff --git a/unittest/libmariadb/misc.c b/unittest/libmariadb/misc.c index 2555514c..e704b1a3 100644 --- a/unittest/libmariadb/misc.c +++ b/unittest/libmariadb/misc.c @@ -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) { diff --git a/unittest/libmariadb/ssl.c.in b/unittest/libmariadb/ssl.c.in index 4866796c..cb02a3d5 100644 --- a/unittest/libmariadb/ssl.c.in +++ b/unittest/libmariadb/ssl.c.in @@ -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 @@ -613,7 +614,8 @@ static int test_conc_102(MYSQL *mysql) #else 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},