diff --git a/extra/yassl/src/handshake.cpp b/extra/yassl/src/handshake.cpp index 407e409..6e181a9 100644 --- a/extra/yassl/src/handshake.cpp +++ b/extra/yassl/src/handshake.cpp @@ -788,6 +788,16 @@ int DoProcessReply(SSL& ssl) needHdr = true; else { buffer >> hdr; + /* + According to RFC 4346 (see "7.4.1.3. Server Hello"), the Server Hello + packet needs to specify the highest supported TLS version, but not + higher than what client requests. YaSSL highest supported version is + TLSv1.1 (=3.2) - if the client requests a higher version, downgrade it + here to 3.2. + See also Appendix E of RFC 5246 (TLS 1.2) + */ + if (hdr.version_.major_ == 3 && hdr.version_.minor_ > 2) + hdr.version_.minor_ = 2; ssl.verifyState(hdr); } diff --git a/include/ssl_compat.h b/include/ssl_compat.h new file mode 100644 index 0000000..b0e3ed4 --- /dev/null +++ b/include/ssl_compat.h @@ -0,0 +1,75 @@ +/* + Copyright (c) 2016, 2017 MariaDB Corporation + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ + +#include + +/* OpenSSL version specific definitions */ +#if !defined(HAVE_YASSL) && defined(OPENSSL_VERSION_NUMBER) + +#if OPENSSL_VERSION_NUMBER >= 0x10002000L && !defined(LIBRESSL_VERSION_NUMBER) +#define HAVE_X509_check_host 1 +#endif + +#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER) +#define HAVE_OPENSSL11 1 +#define ERR_remove_state(X) ERR_clear_error() +#define EVP_MD_CTX_cleanup(X) EVP_MD_CTX_reset(X) +#define EVP_CIPHER_CTX_SIZE 168 +#define EVP_MD_CTX_SIZE 48 +#undef EVP_MD_CTX_init +#define EVP_MD_CTX_init(X) do { bzero((X), EVP_MD_CTX_SIZE); EVP_MD_CTX_reset(X); } while(0) +#undef EVP_CIPHER_CTX_init +#define EVP_CIPHER_CTX_init(X) do { bzero((X), EVP_CIPHER_CTX_SIZE); EVP_CIPHER_CTX_reset(X); } while(0) + +#else +#define HAVE_OPENSSL10 1 +/* + Unfortunately RAND_bytes manual page does not provide any guarantees + in relation to blocking behavior. Here we explicitly use SSLeay random + instead of whatever random engine is currently set in OpenSSL. That way + we are guaranteed to have a non-blocking random. +*/ +#define RAND_OpenSSL() RAND_SSLeay() + +#ifdef HAVE_ERR_remove_thread_state +#define ERR_remove_state(X) ERR_remove_thread_state(NULL) +#endif /* HAVE_ERR_remove_thread_state */ + +#endif /* HAVE_OPENSSL11 */ + +#elif defined(HAVE_YASSL) +#define BN_free(X) do { } while(0) +#endif /* !defined(HAVE_YASSL) */ + +#ifndef HAVE_OPENSSL11 +#define ASN1_STRING_get0_data(X) ASN1_STRING_data(X) +#define OPENSSL_init_ssl(X,Y) SSL_library_init() +#define DH_set0_pqg(D,P,Q,G) ((D)->p= (P), (D)->g= (G)) +#define EVP_CIPHER_CTX_buf_noconst(ctx) ((ctx)->buf) +#define EVP_CIPHER_CTX_encrypting(ctx) ((ctx)->encrypt) +#define EVP_CIPHER_CTX_SIZE sizeof(EVP_CIPHER_CTX) +#define EVP_MD_CTX_SIZE sizeof(EVP_MD_CTX) +#endif + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +int check_openssl_compatibility(); + +#ifdef __cplusplus +} +#endif diff --git a/include/violite.h b/include/violite.h index a7165ca..572d474 100644 --- a/include/violite.h +++ b/include/violite.h @@ -123,13 +123,6 @@ int vio_getnameinfo(const struct sockaddr *sa, int flags); #ifdef HAVE_OPENSSL -#include -#if OPENSSL_VERSION_NUMBER < 0x0090700f -#define DES_cblock des_cblock -#define DES_key_schedule des_key_schedule -#define DES_set_key_unchecked(k,ks) des_set_key_unchecked((k),*(ks)) -#define DES_ede3_cbc_encrypt(i,o,l,k1,k2,k3,iv,e) des_ede3_cbc_encrypt((i),(o),(l),*(k1),*(k2),*(k3),(iv),(e)) -#endif /* apple deprecated openssl in MacOSX Lion */ #ifdef __APPLE__ #pragma GCC diagnostic ignored "-Wdeprecated-declarations" @@ -146,14 +139,10 @@ typedef my_socket YASSL_SOCKET_T; #include #include -#ifdef HAVE_ERR_remove_thread_state -#define ERR_remove_state(X) ERR_remove_thread_state(NULL) -#endif - enum enum_ssl_init_error { - SSL_INITERR_NOERROR= 0, SSL_INITERR_CERT, SSL_INITERR_KEY, - SSL_INITERR_NOMATCH, SSL_INITERR_BAD_PATHS, SSL_INITERR_CIPHERS, + SSL_INITERR_NOERROR= 0, SSL_INITERR_CERT, SSL_INITERR_KEY, + SSL_INITERR_NOMATCH, SSL_INITERR_BAD_PATHS, SSL_INITERR_CIPHERS, SSL_INITERR_MEMFAIL, SSL_INITERR_DH, SSL_INITERR_LASTERR }; const char* sslGetErrString(enum enum_ssl_init_error err); diff --git a/mysql-test/include/require_openssl_client.inc b/mysql-test/include/require_openssl_client.inc new file mode 100644 index 0000000..9b19960 --- /dev/null +++ b/mysql-test/include/require_openssl_client.inc @@ -0,0 +1,5 @@ +if ($CLIENT_TLS_LIBRARY != "OpenSSL") { + if ($CLIENT_TLS_LIBRARY != "LibreSSL") { + skip "Test requires Connector/C with OpenSSL library"; + } +} diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index 2cd5d2a..22bcaba 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -2300,6 +2300,11 @@ sub environment_setup { $ENV{'MYSQL_PLUGIN'}= $exe_mysql_plugin; $ENV{'MYSQL_EMBEDDED'}= $exe_mysql_embedded; + my $client_config_exe= + native_path("$bindir/libmariadb/mariadb_config$opt_vs_config/mariadb_config"); + my $tls_info= `$client_config_exe --tlsinfo`; + ($ENV{CLIENT_TLS_LIBRARY},$ENV{CLIENT_TLS_LIBRARY_VERSION})= + split(/ /, $tls_info, 2); my $exe_mysqld= find_mysqld($basedir); $ENV{'MYSQLD'}= $exe_mysqld; my $extra_opts= join (" ", @opt_extra_mysqld_opt); diff --git a/mysql-test/r/openssl_6975,tlsv10.result b/mysql-test/r/openssl_6975,tlsv10.result index 7a4465f..202e7f4 100644 --- a/mysql-test/r/openssl_6975,tlsv10.result +++ b/mysql-test/r/openssl_6975,tlsv10.result @@ -3,11 +3,11 @@ grant select on test.* to ssl_sslv3@localhost require cipher "AES128-SHA"; create user ssl_tls12@localhost; grant select on test.* to ssl_tls12@localhost require cipher "AES128-SHA256"; TLS1.2 ciphers: user is ok with any cipher -ERROR 2026 (HY000): SSL connection error: error:14077410:SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure -ERROR 2026 (HY000): SSL connection error: error:14077410:SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure +ERROR 2026 (HY000): SSL connection error: sslv3 alert handshake failure +ERROR 2026 (HY000): SSL connection error: sslv3 alert handshake failure TLS1.2 ciphers: user requires SSLv3 cipher AES128-SHA -ERROR 2026 (HY000): SSL connection error: error:14077410:SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure -ERROR 2026 (HY000): SSL connection error: error:14077410:SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure +ERROR 2026 (HY000): SSL connection error: sslv3 alert handshake failure +ERROR 2026 (HY000): SSL connection error: sslv3 alert handshake failure TLS1.2 ciphers: user requires TLSv1.2 cipher AES128-SHA256 ERROR 2026 (HY000): SSL connection error: error:14077410:SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure ERROR 2026 (HY000): SSL connection error: error:14077410:SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure diff --git a/mysql-test/t/openssl_6975.test b/mysql-test/t/openssl_6975.test index 49889a3..6a82d01 100644 --- a/mysql-test/t/openssl_6975.test +++ b/mysql-test/t/openssl_6975.test @@ -4,6 +4,7 @@ # test SSLv3 and TLSv1.2 ciphers when OpenSSL is restricted to SSLv3 or TLSv1.2 # source include/have_ssl_communication.inc; +source include/require_openssl_client.inc; # this is OpenSSL test. diff --git a/mysql-test/t/ssl_7937.test b/mysql-test/t/ssl_7937.test index d593b9d..a764579 100644 --- a/mysql-test/t/ssl_7937.test +++ b/mysql-test/t/ssl_7937.test @@ -26,6 +26,7 @@ create procedure have_ssl() # we fake the test result for yassl let yassl=`select variable_value='Unknown' from information_schema.session_status where variable_name='Ssl_session_cache_mode'`; if (!$yassl) { + --replace_result "self signed certificate in certificate chain" "Failed to verify the server certificate" "Error in the certificate." "Failed to verify the server certificate" --exec $MYSQL --ssl --ssl-verify-server-cert -e "call test.have_ssl()" 2>&1 } if ($yassl) { diff --git a/mysql-test/t/ssl_8k_key.test b/mysql-test/t/ssl_8k_key.test index 27cffdc..9d5b382 100644 --- a/mysql-test/t/ssl_8k_key.test +++ b/mysql-test/t/ssl_8k_key.test @@ -1,5 +1,5 @@ -# This test should work in embedded server after we fix mysqltest --- source include/not_embedded.inc +# schannel does not support keys longer than 4k +-- source include/not_windows.inc -- source include/have_ssl_communication.inc # diff --git a/mysys_ssl/CMakeLists.txt b/mysys_ssl/CMakeLists.txt index 4f6f745..f8a767e 100644 --- a/mysys_ssl/CMakeLists.txt +++ b/mysys_ssl/CMakeLists.txt @@ -28,6 +28,7 @@ SET(MYSYS_SSL_HIDDEN_SOURCES my_sha384.cc my_sha512.cc my_md5.cc + openssl.c ) SET(MYSYS_SSL_SOURCES diff --git a/mysys_ssl/my_crypt.cc b/mysys_ssl/my_crypt.cc index a0937a8..ed1c82d 100644 --- a/mysys_ssl/my_crypt.cc +++ b/mysys_ssl/my_crypt.cc @@ -1,6 +1,6 @@ /* Copyright (c) 2014 Google Inc. - Copyright (c) 2014, 2015 MariaDB Corporation + Copyright (c) 2014, 2017 MariaDB Corporation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -17,52 +17,60 @@ #include #include -#include #ifdef HAVE_YASSL #include "yassl.cc" #else - #include #include #include - -#ifdef HAVE_ERR_remove_thread_state -#define ERR_remove_state(X) ERR_remove_thread_state(NULL) +#include #endif -#endif +#include +#include class MyCTX { public: - EVP_CIPHER_CTX ctx; - MyCTX() { EVP_CIPHER_CTX_init(&ctx); } - virtual ~MyCTX() { EVP_CIPHER_CTX_cleanup(&ctx); ERR_remove_state(0); } + char ctx_buf[EVP_CIPHER_CTX_SIZE]; + EVP_CIPHER_CTX *ctx; + + MyCTX() + { + ctx= (EVP_CIPHER_CTX *)ctx_buf; + EVP_CIPHER_CTX_init(ctx); + } + virtual ~MyCTX() + { + EVP_CIPHER_CTX_cleanup(ctx); + ERR_remove_state(0); + } virtual int init(const EVP_CIPHER *cipher, int encrypt, const uchar *key, uint klen, const uchar *iv, uint ivlen) { + compile_time_assert(MY_AES_CTX_SIZE >= sizeof(MyCTX)); if (unlikely(!cipher)) return MY_AES_BAD_KEYSIZE; - if (!EVP_CipherInit_ex(&ctx, cipher, NULL, key, iv, encrypt)) + if (!EVP_CipherInit_ex(ctx, cipher, NULL, key, iv, encrypt)) return MY_AES_OPENSSL_ERROR; - DBUG_ASSERT(EVP_CIPHER_CTX_key_length(&ctx) == (int)klen); - DBUG_ASSERT(EVP_CIPHER_CTX_iv_length(&ctx) <= (int)ivlen); + DBUG_ASSERT(EVP_CIPHER_CTX_key_length(ctx) == (int)klen); + DBUG_ASSERT(EVP_CIPHER_CTX_iv_length(ctx) <= (int)ivlen); return MY_AES_OK; } virtual int update(const uchar *src, uint slen, uchar *dst, uint *dlen) { - if (!EVP_CipherUpdate(&ctx, dst, (int*)dlen, src, slen)) + if (!EVP_CipherUpdate(ctx, dst, (int*)dlen, src, slen)) return MY_AES_OPENSSL_ERROR; return MY_AES_OK; } virtual int finish(uchar *dst, uint *dlen) { - if (!EVP_CipherFinal_ex(&ctx, dst, (int*)dlen)) + if (!EVP_CipherFinal_ex(ctx, dst, (int*)dlen)) return MY_AES_BAD_DATA; return MY_AES_OK; } @@ -72,7 +80,8 @@ class MyCTX_nopad : public MyCTX { public: const uchar *key; - int klen; + uint klen, buf_len; + uchar oiv[MY_AES_BLOCK_SIZE]; MyCTX_nopad() : MyCTX() { } ~MyCTX_nopad() { } @@ -83,32 +92,48 @@ class MyCTX_nopad : public MyCTX compile_time_assert(MY_AES_CTX_SIZE >= sizeof(MyCTX_nopad)); this->key= key; this->klen= klen; + this->buf_len= 0; + memcpy(oiv, iv, ivlen); + DBUG_ASSERT(ivlen == 0 || ivlen == sizeof(oiv)); + int res= MyCTX::init(cipher, encrypt, key, klen, iv, ivlen); - memcpy(ctx.oiv, iv, ivlen); // in ECB mode OpenSSL doesn't do that itself - EVP_CIPHER_CTX_set_padding(&ctx, 0); + + EVP_CIPHER_CTX_set_padding(ctx, 0); return res; } + int update(const uchar *src, uint slen, uchar *dst, uint *dlen) + { + buf_len+= slen; + return MyCTX::update(src, slen, dst, dlen); + } + int finish(uchar *dst, uint *dlen) { - if (ctx.buf_len) + buf_len %= MY_AES_BLOCK_SIZE; + if (buf_len) { + uchar *buf= EVP_CIPHER_CTX_buf_noconst(ctx); /* Not much we can do, block ciphers cannot encrypt data that aren't a multiple of the block length. At least not without padding. Let's do something CTR-like for the last partial block. + + NOTE this assumes that there are only buf_len bytes in the buf. + If OpenSSL will change that, we'll need to change the implementation + of this class too. */ uchar mask[MY_AES_BLOCK_SIZE]; uint mlen; my_aes_crypt(MY_AES_ECB, ENCRYPTION_FLAG_ENCRYPT | ENCRYPTION_FLAG_NOPAD, - ctx.oiv, sizeof(mask), mask, &mlen, key, klen, 0, 0); + oiv, sizeof(mask), mask, &mlen, key, klen, 0, 0); DBUG_ASSERT(mlen == sizeof(mask)); - for (int i=0; i < ctx.buf_len; i++) - dst[i]= ctx.buf[i] ^ mask[i]; + for (uint i=0; i < buf_len; i++) + dst[i]= buf[i] ^ mask[i]; } - *dlen= ctx.buf_len; + *dlen= buf_len; return MY_AES_OK; } }; @@ -152,7 +177,7 @@ class MyCTX_gcm : public MyCTX { compile_time_assert(MY_AES_CTX_SIZE >= sizeof(MyCTX_gcm)); int res= MyCTX::init(cipher, encrypt, key, klen, iv, ivlen); - int real_ivlen= EVP_CIPHER_CTX_iv_length(&ctx); + int real_ivlen= EVP_CIPHER_CTX_iv_length(ctx); aad= iv + real_ivlen; aadlen= ivlen - real_ivlen; return res; @@ -166,15 +191,15 @@ class MyCTX_gcm : public MyCTX before decrypting the data. it can encrypt data piecewise, like, first half, then the second half, but it must decrypt all at once */ - if (!ctx.encrypt) + if (!EVP_CIPHER_CTX_encrypting(ctx)) { slen-= MY_AES_BLOCK_SIZE; - if(!EVP_CIPHER_CTX_ctrl(&ctx, EVP_CTRL_GCM_SET_TAG, MY_AES_BLOCK_SIZE, + if(!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, MY_AES_BLOCK_SIZE, (void*)(src + slen))) return MY_AES_OPENSSL_ERROR; } int unused; - if (aadlen && !EVP_CipherUpdate(&ctx, NULL, &unused, aad, aadlen)) + if (aadlen && !EVP_CipherUpdate(ctx, NULL, &unused, aad, aadlen)) return MY_AES_OPENSSL_ERROR; aadlen= 0; return MyCTX::update(src, slen, dst, dlen); @@ -183,13 +208,13 @@ class MyCTX_gcm : public MyCTX int finish(uchar *dst, uint *dlen) { int fin; - if (!EVP_CipherFinal_ex(&ctx, dst, &fin)) + if (!EVP_CipherFinal_ex(ctx, dst, &fin)) return MY_AES_BAD_DATA; DBUG_ASSERT(fin == 0); - if (ctx.encrypt) + if (EVP_CIPHER_CTX_encrypting(ctx)) { - if(!EVP_CIPHER_CTX_ctrl(&ctx, EVP_CTRL_GCM_GET_TAG, MY_AES_BLOCK_SIZE, dst)) + if(!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, MY_AES_BLOCK_SIZE, dst)) return MY_AES_OPENSSL_ERROR; *dlen= MY_AES_BLOCK_SIZE; } @@ -257,12 +282,15 @@ int my_aes_crypt(enum my_aes_mode mode, int flags, { void *ctx= alloca(MY_AES_CTX_SIZE); int res1, res2; - uint d1, d2; + uint d1= 0, d2; if ((res1= my_aes_crypt_init(ctx, mode, flags, key, klen, iv, ivlen))) return res1; res1= my_aes_crypt_update(ctx, src, slen, dst, &d1); res2= my_aes_crypt_finish(ctx, dst + d1, &d2); - *dlen= d1 + d2; + if (res1 || res2) + ERR_remove_state(0); /* in case of failure clear error queue */ + else + *dlen= d1 + d2; return res1 ? res1 : res2; } @@ -301,17 +329,10 @@ int my_random_bytes(uchar* buf, int num) return MY_AES_OK; } #else -#include int my_random_bytes(uchar *buf, int num) { - /* - Unfortunately RAND_bytes manual page does not provide any guarantees - in relation to blocking behavior. Here we explicitly use SSLeay random - instead of whatever random engine is currently set in OpenSSL. That way - we are guaranteed to have a non-blocking random. - */ - RAND_METHOD *rand = RAND_SSLeay(); + RAND_METHOD *rand = RAND_OpenSSL(); if (rand == NULL || rand->bytes(buf, num) != 1) return MY_AES_OPENSSL_ERROR; return MY_AES_OK; diff --git a/mysys_ssl/my_md5.cc b/mysys_ssl/my_md5.cc index 7139ea9..0105082 100644 --- a/mysys_ssl/my_md5.cc +++ b/mysys_ssl/my_md5.cc @@ -1,5 +1,5 @@ /* Copyright (c) 2012, Oracle and/or its affiliates. - Copyright (c) 2014, SkySQL Ab. + Copyright (c) 2017, MariaDB Corporation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -29,38 +29,31 @@ #if defined(HAVE_YASSL) #include "md5.hpp" +#include -typedef TaoCrypt::MD5 MD5_CONTEXT; +typedef TaoCrypt::MD5 EVP_MD_CTX; -static void md5_init(MD5_CONTEXT *context) +static void md5_init(EVP_MD_CTX *context) { - context= new(context) MD5_CONTEXT; + context= new(context) EVP_MD_CTX; context->Init(); } -/* - this is a variant of md5_init to be used in this file only. - does nothing for yassl, because the context's constructor was called automatically. -*/ -static void md5_init_fast(MD5_CONTEXT *context) -{ -} - -static void md5_input(MD5_CONTEXT *context, const uchar *buf, unsigned len) +static void md5_input(EVP_MD_CTX *context, const uchar *buf, unsigned len) { context->Update((const TaoCrypt::byte *) buf, len); } -static void md5_result(MD5_CONTEXT *context, uchar digest[MD5_HASH_SIZE]) +static void md5_result(EVP_MD_CTX *context, uchar digest[MD5_HASH_SIZE]) { context->Final((TaoCrypt::byte *) digest); } #elif defined(HAVE_OPENSSL) #include -typedef EVP_MD_CTX MD5_CONTEXT; +#include -static void md5_init(MD5_CONTEXT *context) +static void md5_init(EVP_MD_CTX *context) { EVP_MD_CTX_init(context); #ifdef EVP_MD_CTX_FLAG_NON_FIPS_ALLOW @@ -70,17 +63,12 @@ static void md5_init(MD5_CONTEXT *context) EVP_DigestInit_ex(context, EVP_md5(), NULL); } -static void md5_init_fast(MD5_CONTEXT *context) -{ - md5_init(context); -} - -static void md5_input(MD5_CONTEXT *context, const uchar *buf, unsigned len) +static void md5_input(EVP_MD_CTX *context, const uchar *buf, unsigned len) { EVP_DigestUpdate(context, buf, len); } -static void md5_result(MD5_CONTEXT *context, uchar digest[MD5_HASH_SIZE]) +static void md5_result(EVP_MD_CTX *context, uchar digest[MD5_HASH_SIZE]) { EVP_DigestFinal_ex(context, digest, NULL); EVP_MD_CTX_cleanup(context); @@ -99,58 +87,58 @@ static void md5_result(MD5_CONTEXT *context, uchar digest[MD5_HASH_SIZE]) */ void my_md5(uchar *digest, const char *buf, size_t len) { - MD5_CONTEXT md5_context; - - md5_init_fast(&md5_context); - md5_input(&md5_context, (const uchar *)buf, len); - md5_result(&md5_context, digest); + char ctx_buf[EVP_MD_CTX_SIZE]; + EVP_MD_CTX * const ctx= (EVP_MD_CTX*)ctx_buf; + md5_init(ctx); + md5_input(ctx, (const uchar *)buf, len); + md5_result(ctx, digest); } /** Wrapper function to compute MD5 message digest for - two messages in order to emulate md5(msg1, msg2). + many messages, concatenated. @param digest [out] Computed MD5 digest @param buf1 [in] First message @param len1 [in] Length of first message - @param buf2 [in] Second message - @param len2 [in] Length of second message + ... + @param bufN [in] NULL terminates the list of buf,len pairs. @return void */ void my_md5_multi(uchar *digest, ...) { va_list args; - va_start(args, digest); - - MD5_CONTEXT md5_context; const uchar *str; + char ctx_buf[EVP_MD_CTX_SIZE]; + EVP_MD_CTX * const ctx= (EVP_MD_CTX*)ctx_buf; + va_start(args, digest); - md5_init_fast(&md5_context); + md5_init(ctx); for (str= va_arg(args, const uchar*); str; str= va_arg(args, const uchar*)) - md5_input(&md5_context, str, va_arg(args, size_t)); + md5_input(ctx, str, va_arg(args, size_t)); - md5_result(&md5_context, digest); + md5_result(ctx, digest); va_end(args); } size_t my_md5_context_size() { - return sizeof(MD5_CONTEXT); + return EVP_MD_CTX_SIZE; } void my_md5_init(void *context) { - md5_init((MD5_CONTEXT *)context); + md5_init((EVP_MD_CTX *)context); } void my_md5_input(void *context, const uchar *buf, size_t len) { - md5_input((MD5_CONTEXT *)context, buf, len); + md5_input((EVP_MD_CTX *)context, buf, len); } void my_md5_result(void *context, uchar *digest) { - md5_result((MD5_CONTEXT *)context, digest); + md5_result((EVP_MD_CTX *)context, digest); } diff --git a/mysys_ssl/openssl.c b/mysys_ssl/openssl.c new file mode 100644 index 0000000..a3f1ca2 --- /dev/null +++ b/mysys_ssl/openssl.c @@ -0,0 +1,71 @@ +/* + Copyright (c) 2017, MariaDB Corporation. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ + +#include +#include + +#ifdef HAVE_YASSL + +int check_openssl_compatibility() +{ + return 0; +} +#else +#include + +#ifdef HAVE_OPENSSL11 +typedef void *(*CRYPTO_malloc_t)(size_t, const char *, int); +#endif + +#ifdef HAVE_OPENSSL10 +typedef void *(*CRYPTO_malloc_t)(size_t); +#define CRYPTO_malloc malloc +#define CRYPTO_realloc realloc +#define CRYPTO_free free +#endif + +static uint allocated_size, allocated_count; + +static void *coc_malloc(size_t size) +{ + allocated_size+= size; + allocated_count++; + return malloc(size); +} + +int check_openssl_compatibility() +{ + EVP_CIPHER_CTX *evp_ctx; + EVP_MD_CTX *md5_ctx; + + CRYPTO_set_mem_functions((CRYPTO_malloc_t)coc_malloc, CRYPTO_realloc, CRYPTO_free); + + allocated_size= allocated_count= 0; + evp_ctx= EVP_CIPHER_CTX_new(); + EVP_CIPHER_CTX_free(evp_ctx); + if (allocated_count != 1 || allocated_size > EVP_CIPHER_CTX_SIZE) + return 1; + + allocated_size= allocated_count= 0; + md5_ctx= EVP_MD_CTX_create(); + EVP_MD_CTX_destroy(md5_ctx); + if (allocated_count != 1 || allocated_size > EVP_MD_CTX_SIZE) + return 1; + + CRYPTO_set_mem_functions(CRYPTO_malloc, CRYPTO_realloc, CRYPTO_free); + return 0; +} +#endif diff --git a/mysys_ssl/yassl.cc b/mysys_ssl/yassl.cc index 9717870..aa5631f 100644 --- a/mysys_ssl/yassl.cc +++ b/mysys_ssl/yassl.cc @@ -44,7 +44,6 @@ typedef struct int buf_len; int final_used; uchar tao_buf[sizeof(TaoCrypt::AES)]; // TaoCrypt::AES object - uchar oiv[TaoCrypt::AES::BLOCK_SIZE]; // original IV uchar buf[TaoCrypt::AES::BLOCK_SIZE]; // last partial input block uchar final[TaoCrypt::AES::BLOCK_SIZE]; // last decrypted (output) block } EVP_CIPHER_CTX; @@ -97,10 +96,7 @@ static int EVP_CipherInit_ex(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher, : TaoCrypt::DECRYPTION, cipher->mode); TAO(ctx)->SetKey(key, cipher->key_len); if (iv) - { TAO(ctx)->SetIV(iv); - memcpy(ctx->oiv, iv, TaoCrypt::AES::BLOCK_SIZE); - } ctx->encrypt= enc; ctx->key_len= cipher->key_len; ctx->flags|= cipher->mode == TaoCrypt::CBC ? EVP_CIPH_CBC_MODE : EVP_CIPH_ECB_MODE; diff --git a/sql-common/client.c b/sql-common/client.c index b7796ce..2518f66 100644 --- a/sql-common/client.c +++ b/sql-common/client.c @@ -105,6 +105,7 @@ my_bool net_flush(NET *net); #endif #include "client_settings.h" +#include #include #include #include @@ -1769,9 +1770,8 @@ mysql_get_ssl_cipher(MYSQL *mysql __attribute__((unused))) #if defined(HAVE_OPENSSL) -#if OPENSSL_VERSION_NUMBER >= 0x10002000L && !defined(HAVE_YASSL) +#ifdef HAVE_X509_check_host #include -#define HAVE_X509_check_host #endif static int ssl_verify_server_cert(Vio *vio, const char* server_hostname, const char **errptr) @@ -1843,7 +1843,7 @@ static int ssl_verify_server_cert(Vio *vio, const char* server_hostname, const c goto error; } - cn= (char *) ASN1_STRING_data(cn_asn1); + cn= (char *) ASN1_STRING_get0_data(cn_asn1); if ((size_t)ASN1_STRING_length(cn_asn1) != strlen(cn)) { diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 3af8750..cc64205 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -338,9 +338,13 @@ static PSI_thread_key key_thread_handle_con_sockets; static PSI_thread_key key_thread_handle_shutdown; #endif /* __WIN__ */ -#if defined (HAVE_OPENSSL) && !defined(HAVE_YASSL) +#ifdef HAVE_OPENSSL +#include + +#ifdef HAVE_OPENSSL10 static PSI_rwlock_key key_rwlock_openssl; #endif +#endif #endif /* HAVE_PSI_INTERFACE */ #ifdef HAVE_NPTL @@ -987,7 +991,7 @@ PSI_rwlock_key key_rwlock_LOCK_grant, key_rwlock_LOCK_logger, static PSI_rwlock_info all_server_rwlocks[]= { -#if defined (HAVE_OPENSSL) && !defined(HAVE_YASSL) +#ifdef HAVE_OPENSSL10 { &key_rwlock_openssl, "CRYPTO_dynlock_value::lock", 0}, #endif { &key_rwlock_LOCK_grant, "LOCK_grant", PSI_FLAG_GLOBAL}, @@ -1457,7 +1461,7 @@ scheduler_functions *thread_scheduler= &thread_scheduler_struct, #ifdef HAVE_OPENSSL #include -#ifndef HAVE_YASSL +#ifdef HAVE_OPENSSL10 typedef struct CRYPTO_dynlock_value { mysql_rwlock_t lock; @@ -1468,7 +1472,7 @@ static openssl_lock_t *openssl_dynlock_create(const char *, int); static void openssl_dynlock_destroy(openssl_lock_t *, const char *, int); static void openssl_lock_function(int, int, const char *, int); static void openssl_lock(int, openssl_lock_t *, const char *, int); -#endif +#endif /* HAVE_OPENSSL10 */ char *des_key_file; #ifndef EMBEDDED_LIBRARY struct st_VioSSLFd *ssl_acceptor_fd; @@ -2244,11 +2248,11 @@ static void clean_up_mutexes() mysql_mutex_destroy(&LOCK_global_index_stats); #ifdef HAVE_OPENSSL mysql_mutex_destroy(&LOCK_des_key_file); -#ifndef HAVE_YASSL +#ifdef HAVE_OPENSSL10 for (int i= 0; i < CRYPTO_num_locks(); ++i) mysql_rwlock_destroy(&openssl_stdlocks[i].lock); OPENSSL_free(openssl_stdlocks); -#endif /* HAVE_YASSL */ +#endif /* HAVE_OPENSSL10 */ #endif /* HAVE_OPENSSL */ #ifdef HAVE_REPLICATION mysql_mutex_destroy(&LOCK_rpl_status); @@ -4057,6 +4061,14 @@ static int init_common_variables() return 1; } +#ifdef HAVE_OPENSSL + if (check_openssl_compatibility()) + { + sql_print_error("Incompatible OpenSSL version. Cannot continue..."); + return 1; + } +#endif + if (init_thread_environment() || mysql_init_variables()) return 1; @@ -4603,7 +4615,7 @@ static int init_thread_environment() #ifdef HAVE_OPENSSL mysql_mutex_init(key_LOCK_des_key_file, &LOCK_des_key_file, MY_MUTEX_INIT_FAST); -#ifndef HAVE_YASSL +#ifdef HAVE_OPENSSL10 openssl_stdlocks= (openssl_lock_t*) OPENSSL_malloc(CRYPTO_num_locks() * sizeof(openssl_lock_t)); for (int i= 0; i < CRYPTO_num_locks(); ++i) @@ -4612,8 +4624,8 @@ static int init_thread_environment() CRYPTO_set_dynlock_destroy_callback(openssl_dynlock_destroy); CRYPTO_set_dynlock_lock_callback(openssl_lock); CRYPTO_set_locking_callback(openssl_lock_function); -#endif -#endif +#endif /* HAVE_OPENSSL10 */ +#endif /* HAVE_OPENSSL */ mysql_rwlock_init(key_rwlock_LOCK_sys_init_connect, &LOCK_sys_init_connect); mysql_rwlock_init(key_rwlock_LOCK_sys_init_slave, &LOCK_sys_init_slave); mysql_rwlock_init(key_rwlock_LOCK_grant, &LOCK_grant); @@ -4646,7 +4658,7 @@ static int init_thread_environment() } -#if defined(HAVE_OPENSSL) && !defined(HAVE_YASSL) +#ifdef HAVE_OPENSSL10 static openssl_lock_t *openssl_dynlock_create(const char *file, int line) { openssl_lock_t *lock= new openssl_lock_t; @@ -4706,8 +4718,7 @@ static void openssl_lock(int mode, openssl_lock_t *lock, const char *file, abort(); } } -#endif /* HAVE_OPENSSL */ - +#endif /* HAVE_OPENSSL10 */ static void init_ssl() { diff --git a/sql/slave.cc b/sql/slave.cc index db1c330..aec5143 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -40,6 +40,7 @@ #include #include #include +#include #include #include #include "rpl_handler.h" @@ -60,7 +61,6 @@ #include "debug_sync.h" #include "rpl_parallel.h" - #define FLAGSTR(V,F) ((V)&(F)?#F" ":"") #define MAX_SLAVE_RETRY_PAUSE 5 @@ -4507,9 +4507,7 @@ log space"); DBUG_LEAVE; // Must match DBUG_ENTER() my_thread_end(); -#ifdef HAVE_OPENSSL ERR_remove_state(0); -#endif pthread_exit(0); return 0; // Avoid compiler warnings } @@ -5168,9 +5166,7 @@ pthread_handler_t handle_slave_sql(void *arg) DBUG_LEAVE; // Must match DBUG_ENTER() my_thread_end(); -#ifdef HAVE_OPENSSL ERR_remove_state(0); -#endif pthread_exit(0); return 0; // Avoid compiler warnings } diff --git a/vio/vio.c b/vio/vio.c index e3bc8ca..44d0609 100644 --- a/vio/vio.c +++ b/vio/vio.c @@ -22,6 +22,7 @@ */ #include "vio_priv.h" +#include "ssl_compat.h" #ifdef _WIN32 diff --git a/vio/viosslfactories.c b/vio/viosslfactories.c index 52b624d..71ef287 100644 --- a/vio/viosslfactories.c +++ b/vio/viosslfactories.c @@ -15,6 +15,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "vio_priv.h" +#include #ifdef HAVE_OPENSSL #ifndef HAVE_YASSL @@ -26,49 +27,56 @@ static my_bool ssl_algorithms_added = FALSE; static my_bool ssl_error_strings_loaded= FALSE; /* the function below was generated with "openssl dhparam -2 -C 2048" */ + static DH *get_dh2048() { - static unsigned char dh2048_p[]={ - 0xA1,0xBB,0x7C,0x20,0xC5,0x5B,0xC0,0x7B,0x21,0x8B,0xD6,0xA8, - 0x15,0xFC,0x3B,0xBA,0xAB,0x9F,0xDF,0x68,0xC4,0x79,0x78,0x0D, - 0xC1,0x12,0x64,0xE4,0x15,0xC9,0x66,0xDB,0xF6,0xCB,0xB3,0x39, - 0x02,0x5B,0x78,0x62,0xFB,0x09,0xAE,0x09,0x6B,0xDD,0xD4,0x5D, - 0x97,0xBC,0xDC,0x7F,0xE6,0xD6,0xF1,0xCB,0xF5,0xEB,0xDA,0xA7, - 0x2E,0x5A,0x43,0x2B,0xE9,0x40,0xE2,0x85,0x00,0x1C,0xC0,0x0A, - 0x98,0x77,0xA9,0x31,0xDE,0x0B,0x75,0x4D,0x1E,0x1F,0x16,0x83, - 0xCA,0xDE,0xBD,0x21,0xFC,0xC1,0x82,0x37,0x36,0x33,0x0B,0x66, - 0x06,0x3C,0xF3,0xAF,0x21,0x57,0x57,0x80,0xF6,0x94,0x1B,0xA9, - 0xD4,0xF6,0x8F,0x18,0x62,0x0E,0xC4,0x22,0xF9,0x5B,0x62,0xCC, - 0x3F,0x19,0x95,0xCF,0x4B,0x00,0xA6,0x6C,0x0B,0xAF,0x9F,0xD5, - 0xFA,0x3D,0x6D,0xDA,0x30,0x83,0x07,0x91,0xAC,0x15,0xFF,0x8F, - 0x59,0x54,0xEA,0x25,0xBC,0x4E,0xEB,0x6A,0x54,0xDF,0x75,0x09, - 0x72,0x0F,0xEF,0x23,0x70,0xE0,0xA8,0x04,0xEA,0xFF,0x90,0x54, - 0xCD,0x84,0x18,0xC0,0x75,0x91,0x99,0x0F,0xA1,0x78,0x0C,0x07, - 0xB7,0xC5,0xDE,0x55,0x06,0x7B,0x95,0x68,0x2C,0x33,0x39,0xBC, - 0x2C,0xD0,0x6D,0xDD,0xFA,0xDC,0xB5,0x8F,0x82,0x39,0xF8,0x67, - 0x44,0xF1,0xD8,0xF7,0x78,0x11,0x9A,0x77,0x9B,0x53,0x47,0xD6, - 0x2B,0x5D,0x67,0xB8,0xB7,0xBC,0xC1,0xD7,0x79,0x62,0x15,0xC2, - 0xC5,0x83,0x97,0xA7,0xF8,0xB4,0x9C,0xF6,0x8F,0x9A,0xC7,0xDA, - 0x1B,0xBB,0x87,0x07,0xA7,0x71,0xAD,0xB2,0x8A,0x50,0xF8,0x26, - 0x12,0xB7,0x3E,0x0B, - }; - static unsigned char dh2048_g[]={ - 0x02, - }; - DH *dh; - - if ((dh=DH_new()) == NULL) return(NULL); - dh->p=BN_bin2bn(dh2048_p,sizeof(dh2048_p),NULL); - dh->g=BN_bin2bn(dh2048_g,sizeof(dh2048_g),NULL); - if ((dh->p == NULL) || (dh->g == NULL)) - { DH_free(dh); return(NULL); } - return(dh); + static unsigned char dhp_2048[] = { + 0xA1,0xBB,0x7C,0x20,0xC5,0x5B,0xC0,0x7B,0x21,0x8B,0xD6,0xA8, + 0x15,0xFC,0x3B,0xBA,0xAB,0x9F,0xDF,0x68,0xC4,0x79,0x78,0x0D, + 0xC1,0x12,0x64,0xE4,0x15,0xC9,0x66,0xDB,0xF6,0xCB,0xB3,0x39, + 0x02,0x5B,0x78,0x62,0xFB,0x09,0xAE,0x09,0x6B,0xDD,0xD4,0x5D, + 0x97,0xBC,0xDC,0x7F,0xE6,0xD6,0xF1,0xCB,0xF5,0xEB,0xDA,0xA7, + 0x2E,0x5A,0x43,0x2B,0xE9,0x40,0xE2,0x85,0x00,0x1C,0xC0,0x0A, + 0x98,0x77,0xA9,0x31,0xDE,0x0B,0x75,0x4D,0x1E,0x1F,0x16,0x83, + 0xCA,0xDE,0xBD,0x21,0xFC,0xC1,0x82,0x37,0x36,0x33,0x0B,0x66, + 0x06,0x3C,0xF3,0xAF,0x21,0x57,0x57,0x80,0xF6,0x94,0x1B,0xA9, + 0xD4,0xF6,0x8F,0x18,0x62,0x0E,0xC4,0x22,0xF9,0x5B,0x62,0xCC, + 0x3F,0x19,0x95,0xCF,0x4B,0x00,0xA6,0x6C,0x0B,0xAF,0x9F,0xD5, + 0xFA,0x3D,0x6D,0xDA,0x30,0x83,0x07,0x91,0xAC,0x15,0xFF,0x8F, + 0x59,0x54,0xEA,0x25,0xBC,0x4E,0xEB,0x6A,0x54,0xDF,0x75,0x09, + 0x72,0x0F,0xEF,0x23,0x70,0xE0,0xA8,0x04,0xEA,0xFF,0x90,0x54, + 0xCD,0x84,0x18,0xC0,0x75,0x91,0x99,0x0F,0xA1,0x78,0x0C,0x07, + 0xB7,0xC5,0xDE,0x55,0x06,0x7B,0x95,0x68,0x2C,0x33,0x39,0xBC, + 0x2C,0xD0,0x6D,0xDD,0xFA,0xDC,0xB5,0x8F,0x82,0x39,0xF8,0x67, + 0x44,0xF1,0xD8,0xF7,0x78,0x11,0x9A,0x77,0x9B,0x53,0x47,0xD6, + 0x2B,0x5D,0x67,0xB8,0xB7,0xBC,0xC1,0xD7,0x79,0x62,0x15,0xC2, + 0xC5,0x83,0x97,0xA7,0xF8,0xB4,0x9C,0xF6,0x8F,0x9A,0xC7,0xDA, + 0x1B,0xBB,0x87,0x07,0xA7,0x71,0xAD,0xB2,0x8A,0x50,0xF8,0x26, + 0x12,0xB7,0x3E,0x0B, + }; + static unsigned char dhg_2048[] = { + 0x02 + }; + DH *dh = DH_new(); + BIGNUM *dhp_bn, *dhg_bn; + + if (dh == NULL) + return NULL; + dhp_bn = BN_bin2bn(dhp_2048, sizeof (dhp_2048), NULL); + dhg_bn = BN_bin2bn(dhg_2048, sizeof (dhg_2048), NULL); + if (dhp_bn == NULL || dhg_bn == NULL + || !DH_set0_pqg(dh, dhp_bn, NULL, dhg_bn)) { + DH_free(dh); + BN_free(dhp_bn); + BN_free(dhg_bn); + return NULL; + } + return dh; } - static const char* -ssl_error_string[] = +ssl_error_string[] = { "No error", "Unable to get certificate", @@ -148,9 +156,7 @@ static void check_ssl_init() if (!ssl_algorithms_added) { ssl_algorithms_added= TRUE; - SSL_library_init(); - OpenSSL_add_all_algorithms(); - + OPENSSL_init_ssl(0, NULL); } if (!ssl_error_strings_loaded)