From fb57acd98f96b3d2684cd29c126b4904db81f84c Mon Sep 17 00:00:00 2001 From: Georg Richter Date: Wed, 8 Mar 2017 17:39:47 +0100 Subject: [PATCH 1/2] MDEV-10332 support for OpenSSL 1.1 and LibreSSL Initial support tested against OpenSSL 1.0.1, 1.0.2, 1.1.0, Yassl and LibreSSL not working on Windows with native SChannel support, due to wrong cipher mapping: Latter one requires push of CONC-241 fixes. Please note that OpenSSL 0.9.8 and OpenSSL 1.1.0 will not work: Even if the build succeeds, test cases will fail with various errors, especially when using different tls libraries or versions for client and server. Upstream commit: f8866f8f665ac26beb31842fef48ecee5feb346e --- extra/yassl/src/handshake.cpp | 10 +++ include/my_crypt.h | 15 ++++ include/violite.h | 9 +- mysql-test/include/require_openssl_client.inc | 5 ++ mysql-test/mysql-test-run.pl | 5 ++ mysql-test/r/openssl_1.result | 2 +- mysql-test/r/openssl_6975,tlsv10.result | 18 ++-- mysql-test/r/openssl_6975,tlsv12.result | 14 ++-- mysql-test/t/openssl_1.test | 4 +- mysql-test/t/openssl_6975.test | 19 +++-- mysql-test/t/ssl_7937.test | 1 + mysql-test/t/ssl_8k_key.test | 1 + mysys_ssl/my_crypt.cc | 115 ++++++++++++++++++-------- mysys_ssl/my_md5.cc | 39 ++++++--- mysys_ssl/yassl.cc | 15 ++++ sql-common/client.c | 6 +- sql/mysqld.cc | 14 +++- sql/slave.cc | 13 +++ vio/viosslfactories.c | 54 ++++++++---- 19 files changed, 263 insertions(+), 96 deletions(-) create mode 100644 mysql-test/include/require_openssl_client.inc diff --git a/extra/yassl/src/handshake.cpp b/extra/yassl/src/handshake.cpp index 407e4092ccc..6e181a997bd 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/my_crypt.h b/include/my_crypt.h index 719e349bfb9..e7dd9d80100 100644 --- a/include/my_crypt.h +++ b/include/my_crypt.h @@ -21,4 +21,19 @@ #include /* HAVE_EncryptAes128{Ctr,Gcm} */ #include +/* OpenSSL version specific definitions */ +#if !defined(HAVE_YASSL) && defined(OPENSSL_VERSION_NUMBER) +#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER) +#define ERR_remove_state(X) +#else +#define EVP_CIPHER_CTX_reset(X) EVP_CIPHER_CTX_cleanup(X) +#define RAND_OpenSSL() RAND_SSLeay(); +#if defined(HAVE_ERR_remove_thread_state) +#define ERR_remove_state(X) ERR_remove_thread_state(NULL) +#endif +#endif +#elif defined(HAVE_YASSL) +#define EVP_CIPHER_CTX_reset(X) EVP_CIPHER_CTX_cleanup(X) +#endif /* !defined(HAVE_YASSL) */ + #endif /* MY_CRYPT_INCLUDED */ diff --git a/include/violite.h b/include/violite.h index a7165ca91a9..23800696e5a 100644 --- a/include/violite.h +++ b/include/violite.h @@ -146,14 +146,15 @@ typedef my_socket YASSL_SOCKET_T; #include #include -#ifdef HAVE_ERR_remove_thread_state +#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER) +#define ERR_remove_state(X) +#elif defined(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 00000000000..9b19960041b --- /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 ef054fb2d3e..7241d2f2ea9 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -2304,6 +2304,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_1.result b/mysql-test/r/openssl_1.result index 294ddaf7884..9a9bc619377 100644 --- a/mysql-test/r/openssl_1.result +++ b/mysql-test/r/openssl_1.result @@ -198,7 +198,7 @@ DROP TABLE t1; Variable_name Value Ssl_cipher DHE-RSA-AES256-SHA Variable_name Value -Ssl_cipher EDH-RSA-DES-CBC3-SHA +Ssl_cipher AES128-SHA select 'is still running; no cipher request crashed the server' as result from dual; result is still running; no cipher request crashed the server diff --git a/mysql-test/r/openssl_6975,tlsv10.result b/mysql-test/r/openssl_6975,tlsv10.result index 6285faa0143..202e7f4268e 100644 --- a/mysql-test/r/openssl_6975,tlsv10.result +++ b/mysql-test/r/openssl_6975,tlsv10.result @@ -1,24 +1,24 @@ create user ssl_sslv3@localhost; -grant select on test.* to ssl_sslv3@localhost require cipher "RC4-SHA"; +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 -TLS1.2 ciphers: user requires SSLv3 cipher RC4-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 SSLv3 cipher AES128-SHA +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 SSLv3 ciphers: user is ok with any cipher Variable_name Value -Ssl_cipher RC4-SHA +Ssl_cipher AES256-SHA Variable_name Value Ssl_cipher DHE-RSA-AES256-SHA -SSLv3 ciphers: user requires SSLv3 cipher RC4-SHA +SSLv3 ciphers: user requires SSLv3 cipher AES128-SHA Variable_name Value -Ssl_cipher RC4-SHA +Ssl_cipher AES128-SHA ERROR 1045 (28000): Access denied for user 'ssl_sslv3'@'localhost' (using password: NO) SSLv3 ciphers: user requires TLSv1.2 cipher AES128-SHA256 ERROR 1045 (28000): Access denied for user 'ssl_tls12'@'localhost' (using password: NO) diff --git a/mysql-test/r/openssl_6975,tlsv12.result b/mysql-test/r/openssl_6975,tlsv12.result index 31d2658c829..e2cc28cca70 100644 --- a/mysql-test/r/openssl_6975,tlsv12.result +++ b/mysql-test/r/openssl_6975,tlsv12.result @@ -1,5 +1,5 @@ create user ssl_sslv3@localhost; -grant select on test.* to ssl_sslv3@localhost require cipher "RC4-SHA"; +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 @@ -7,7 +7,7 @@ Variable_name Value Ssl_cipher AES128-SHA256 Variable_name Value Ssl_cipher DHE-RSA-AES256-GCM-SHA384 -TLS1.2 ciphers: user requires SSLv3 cipher RC4-SHA +TLS1.2 ciphers: user requires SSLv3 cipher AES128-SHA ERROR 1045 (28000): Access denied for user 'ssl_sslv3'@'localhost' (using password: NO) ERROR 1045 (28000): Access denied for user 'ssl_sslv3'@'localhost' (using password: NO) TLS1.2 ciphers: user requires TLSv1.2 cipher AES128-SHA256 @@ -15,11 +15,11 @@ Variable_name Value Ssl_cipher AES128-SHA256 ERROR 1045 (28000): Access denied for user 'ssl_tls12'@'localhost' (using password: NO) SSLv3 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 -SSLv3 ciphers: user requires SSLv3 cipher RC4-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 +SSLv3 ciphers: user requires SSLv3 cipher AES128-SHA +ERROR 2026 (HY000): SSL connection error: sslv3 alert handshake failure +ERROR 2026 (HY000): SSL connection error: sslv3 alert handshake failure SSLv3 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_1.test b/mysql-test/t/openssl_1.test index eea74b5b012..28f666263d2 100644 --- a/mysql-test/t/openssl_1.test +++ b/mysql-test/t/openssl_1.test @@ -221,8 +221,8 @@ DROP TABLE t1; # # Common ciphers to openssl and yassl ---exec $MYSQL --host=localhost -e "SHOW STATUS LIKE 'Ssl_cipher';" --ssl-cipher=DHE-RSA-AES256-SHA ---exec $MYSQL --host=localhost -e "SHOW STATUS LIKE 'Ssl_cipher';" --ssl-cipher=EDH-RSA-DES-CBC3-SHA +--exec $MYSQL --host=localhost -e "SHOW STATUS LIKE 'Ssl_cipher';" --ssl-cipher=AES256-SHA +--exec $MYSQL --host=localhost -e "SHOW STATUS LIKE 'Ssl_cipher';" --ssl-cipher=AES128-SHA --disable_query_log --disable_result_log diff --git a/mysql-test/t/openssl_6975.test b/mysql-test/t/openssl_6975.test index 6e8e03a0a89..6cf5d82cf54 100644 --- a/mysql-test/t/openssl_6975.test +++ b/mysql-test/t/openssl_6975.test @@ -4,11 +4,13 @@ # 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. create user ssl_sslv3@localhost; -grant select on test.* to ssl_sslv3@localhost require cipher "RC4-SHA"; +# grant select on test.* to ssl_sslv3@localhost require cipher "AES128-SHA"; +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"; @@ -18,8 +20,9 @@ disable_abort_on_error; echo TLS1.2 ciphers: user is ok with any cipher; exec $mysql --ssl-cipher=AES128-SHA256; --replace_result DHE-RSA-CHACHA20-POLY1305 DHE-RSA-AES256-GCM-SHA384 -exec $mysql --ssl-cipher=TLSv1.2; -echo TLS1.2 ciphers: user requires SSLv3 cipher RC4-SHA; +--replace_result ECDHE-RSA-AES256-GCM-SHA384 DHE-RSA-AES256-GCM-SHA384 +exec $mysql --ssl-cipher=TLSv1.2 +echo TLS1.2 ciphers: user requires SSLv3 cipher AES128-SHA; exec $mysql --user ssl_sslv3 --ssl-cipher=AES128-SHA256; exec $mysql --user ssl_sslv3 --ssl-cipher=TLSv1.2; echo TLS1.2 ciphers: user requires TLSv1.2 cipher AES128-SHA256; @@ -27,13 +30,13 @@ exec $mysql --user ssl_tls12 --ssl-cipher=AES128-SHA256; exec $mysql --user ssl_tls12 --ssl-cipher=TLSv1.2; echo SSLv3 ciphers: user is ok with any cipher; -exec $mysql --ssl-cipher=RC4-SHA; -exec $mysql --ssl-cipher=SSLv3; -echo SSLv3 ciphers: user requires SSLv3 cipher RC4-SHA; -exec $mysql --user ssl_sslv3 --ssl-cipher=RC4-SHA; +exec $mysql --ssl-cipher=AES256-SHA; +exec $mysql --ssl-cipher=DHE-RSA-AES256-SHA +echo SSLv3 ciphers: user requires SSLv3 cipher AES128-SHA; +exec $mysql --user ssl_sslv3 --ssl-cipher=AES128-SHA; exec $mysql --user ssl_sslv3 --ssl-cipher=SSLv3; echo SSLv3 ciphers: user requires TLSv1.2 cipher AES128-SHA256; -exec $mysql --user ssl_tls12 --ssl-cipher=RC4-SHA; +exec $mysql --user ssl_tls12 --ssl-cipher=AES128-SHA; exec $mysql --user ssl_tls12 --ssl-cipher=SSLv3; drop user ssl_sslv3@localhost; diff --git a/mysql-test/t/ssl_7937.test b/mysql-test/t/ssl_7937.test index d593b9d936d..a76457906ec 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 27cffdce1f2..470d577edb8 100644 --- a/mysql-test/t/ssl_8k_key.test +++ b/mysql-test/t/ssl_8k_key.test @@ -1,4 +1,5 @@ # This test should work in embedded server after we fix mysqltest +-- source include/require_openssl_client.inc -- source include/not_embedded.inc -- source include/have_ssl_communication.inc diff --git a/mysys_ssl/my_crypt.cc b/mysys_ssl/my_crypt.cc index a0937a83e17..0ff49a2c427 100644 --- a/mysys_ssl/my_crypt.cc +++ b/mysys_ssl/my_crypt.cc @@ -17,7 +17,6 @@ #include #include -#include #ifdef HAVE_YASSL #include "yassl.cc" @@ -26,43 +25,51 @@ #include #include #include +#include -#ifdef HAVE_ERR_remove_thread_state -#define ERR_remove_state(X) ERR_remove_thread_state(NULL) #endif +#include -#endif +#define MY_CIPHER_CTX_SIZE 384 class MyCTX { public: - EVP_CIPHER_CTX ctx; - MyCTX() { EVP_CIPHER_CTX_init(&ctx); } - virtual ~MyCTX() { EVP_CIPHER_CTX_cleanup(&ctx); ERR_remove_state(0); } + EVP_CIPHER_CTX *ctx; + const uchar *key; + unsigned int klen; + MyCTX() { + ctx= EVP_CIPHER_CTX_new(); + } + virtual ~MyCTX() { + EVP_CIPHER_CTX_free(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; } @@ -71,11 +78,9 @@ class MyCTX class MyCTX_nopad : public MyCTX { public: - const uchar *key; - int klen; - MyCTX_nopad() : MyCTX() { } ~MyCTX_nopad() { } + unsigned int buf_len; int init(const EVP_CIPHER *cipher, int encrypt, const uchar *key, uint klen, const uchar *iv, uint ivlen) @@ -83,16 +88,39 @@ 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; + /* FIX-ME: + For the sake of backward compatibility we do some strange hack here: + Since ECB doesn't need an IV (and therefore is considered kind of + insecure) we need to store the specified iv. + The last nonpadding block will be encrypted with an additional + expensive crypt_call in ctr mode instead + of encrypting the entire plain text in ctr-mode */ +#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER) + const unsigned char *oiv= EVP_CIPHER_CTX_original_iv(ctx); +#else + const unsigned char *oiv= ctx->oiv; +#endif + memcpy((char *)oiv, iv, ivlen); + 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 % MY_AES_BLOCK_SIZE; + return MyCTX::update(src, slen, dst, dlen); + } + int finish(uchar *dst, uint *dlen) { - if (ctx.buf_len) + if (buf_len) { + const uchar *org_iv; + unsigned char *buf; /* Not much we can do, block ciphers cannot encrypt data that aren't a multiple of the block length. At least not without padding. @@ -101,14 +129,22 @@ class MyCTX_nopad : public MyCTX uchar mask[MY_AES_BLOCK_SIZE]; uint mlen; +#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER) + org_iv= EVP_CIPHER_CTX_original_iv(ctx); + buf= EVP_CIPHER_CTX_buf_noconst(ctx); +#else + org_iv= ctx->oiv; + buf= ctx->buf; +#endif + my_aes_crypt(MY_AES_ECB, ENCRYPTION_FLAG_ENCRYPT | ENCRYPTION_FLAG_NOPAD, - ctx.oiv, sizeof(mask), mask, &mlen, key, klen, 0, 0); + org_iv, 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; } }; @@ -142,8 +178,9 @@ make_aes_dispatcher(gcm) class MyCTX_gcm : public MyCTX { public: - const uchar *aad; + const uchar *aad= NULL; int aadlen; + my_bool encrypt; MyCTX_gcm() : MyCTX() { } ~MyCTX_gcm() { } @@ -152,9 +189,10 @@ 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; + this->encrypt= encrypt; return res; } @@ -166,15 +204,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 (!this->encrypt) { 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)) + int unused= 0; + if (aadlen && !EVP_CipherUpdate(ctx, NULL, &unused, aad, aadlen)) return MY_AES_OPENSSL_ERROR; aadlen= 0; return MyCTX::update(src, slen, dst, dlen); @@ -182,14 +220,14 @@ class MyCTX_gcm : public MyCTX int finish(uchar *dst, uint *dlen) { - int fin; - if (!EVP_CipherFinal_ex(&ctx, dst, &fin)) + int fin= 0; + if (!EVP_CipherFinal_ex(ctx, dst, &fin)) return MY_AES_BAD_DATA; DBUG_ASSERT(fin == 0); - if (ctx.encrypt) + if (this->encrypt) { - 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 +295,20 @@ 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= 0; 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; + /* in case of failure clear error queue */ +#ifndef HAVE_YASSL + /* since we don't check the crypto error messages we need to + clear the error queue - otherwise subsequent crypto or tls/ssl + calls will fail */ + if (!*dlen) + ERR_clear_error(); +#endif return res1 ? res1 : res2; } @@ -301,7 +347,6 @@ int my_random_bytes(uchar* buf, int num) return MY_AES_OK; } #else -#include int my_random_bytes(uchar *buf, int num) { @@ -311,7 +356,7 @@ int my_random_bytes(uchar *buf, int num) 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 7139ea9b6ff..02c01dd7148 100644 --- a/mysys_ssl/my_md5.cc +++ b/mysys_ssl/my_md5.cc @@ -27,6 +27,8 @@ #include #include +#define MA_HASH_CTX_SIZE 512 + #if defined(HAVE_YASSL) #include "md5.hpp" @@ -57,11 +59,18 @@ static void md5_result(MD5_CONTEXT *context, uchar digest[MD5_HASH_SIZE]) } #elif defined(HAVE_OPENSSL) + + #include + +#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER) +#define EVP_MD_CTX_reset(X) EVP_MD_CTX_cleanup(X) +#endif typedef EVP_MD_CTX MD5_CONTEXT; static void md5_init(MD5_CONTEXT *context) { + memset(context, 0, my_md5_context_size()); EVP_MD_CTX_init(context); #ifdef EVP_MD_CTX_FLAG_NON_FIPS_ALLOW /* Ok to ignore FIPS: MD5 is not used for crypto here */ @@ -83,7 +92,7 @@ static void md5_input(MD5_CONTEXT *context, const uchar *buf, unsigned len) static void md5_result(MD5_CONTEXT *context, uchar digest[MD5_HASH_SIZE]) { EVP_DigestFinal_ex(context, digest, NULL); - EVP_MD_CTX_cleanup(context); + EVP_MD_CTX_reset(context); } #endif /* HAVE_YASSL */ @@ -99,11 +108,14 @@ static void md5_result(MD5_CONTEXT *context, uchar digest[MD5_HASH_SIZE]) */ void my_md5(uchar *digest, const char *buf, size_t len) { +#ifdef HAVE_YASSL MD5_CONTEXT md5_context; - - md5_init_fast(&md5_context); - md5_input(&md5_context, (const uchar *)buf, len); - md5_result(&md5_context, digest); +#else + unsigned char md5_context[MA_HASH_CTX_SIZE]; +#endif + md5_init_fast((MD5_CONTEXT *)&md5_context); + md5_input((MD5_CONTEXT *)&md5_context, (const uchar *)buf, len); + md5_result((MD5_CONTEXT *)&md5_context, digest); } @@ -122,22 +134,25 @@ void my_md5(uchar *digest, const char *buf, size_t len) void my_md5_multi(uchar *digest, ...) { va_list args; - va_start(args, digest); - - MD5_CONTEXT md5_context; const uchar *str; +#ifdef HAVE_YASSL + MD5_CONTEXT md5_context; +#else + unsigned char md5_context[MA_HASH_CTX_SIZE]; +#endif + va_start(args, digest); - md5_init_fast(&md5_context); + md5_init_fast((MD5_CONTEXT *)&md5_context); 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((MD5_CONTEXT *)&md5_context, str, va_arg(args, size_t)); - md5_result(&md5_context, digest); + md5_result((MD5_CONTEXT *)&md5_context, digest); va_end(args); } size_t my_md5_context_size() { - return sizeof(MD5_CONTEXT); + return MA_HASH_CTX_SIZE; } void my_md5_init(void *context) diff --git a/mysys_ssl/yassl.cc b/mysys_ssl/yassl.cc index 9717870fe26..9e6f90d8d77 100644 --- a/mysys_ssl/yassl.cc +++ b/mysys_ssl/yassl.cc @@ -24,6 +24,7 @@ #include #include "aes.hpp" +#include using yaSSL::yaERR_remove_state; @@ -75,12 +76,26 @@ static void EVP_CIPHER_CTX_init(EVP_CIPHER_CTX *ctx) ctx->final_used= ctx->buf_len= ctx->flags= 0; } +static EVP_CIPHER_CTX *EVP_CIPHER_CTX_new() +{ + EVP_CIPHER_CTX *ctx= (EVP_CIPHER_CTX *)my_malloc(sizeof(EVP_CIPHER_CTX), MYF(0)); + if (ctx) + EVP_CIPHER_CTX_init(ctx); + return ctx; +} + static int EVP_CIPHER_CTX_cleanup(EVP_CIPHER_CTX *ctx) { TAO(ctx)->~AES(); return 1; } +static void EVP_CIPHER_CTX_free(EVP_CIPHER_CTX *ctx) +{ + EVP_CIPHER_CTX_cleanup(ctx); + my_free(ctx); +} + static int EVP_CIPHER_CTX_set_padding(EVP_CIPHER_CTX *ctx, int pad) { if (pad) diff --git a/sql-common/client.c b/sql-common/client.c index a918060a848..d881080b55a 100644 --- a/sql-common/client.c +++ b/sql-common/client.c @@ -104,6 +104,10 @@ my_bool net_flush(NET *net); #define CONNECT_TIMEOUT 0 #endif +#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER) || defined(HAVE_YASSL) +#define ASN1_STRING_get0_data(X) ASN1_STRING_data(X) +#endif + #include "client_settings.h" #include #include @@ -1842,7 +1846,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 0bf57d9543b..d6a7c6b4931 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -111,6 +111,7 @@ #endif #include +#include #define mysqld_charset &my_charset_latin1 @@ -120,6 +121,7 @@ #define HAVE_CLOSE_SERVER_SOCK 1 #endif + extern "C" { // Because of SCO 3.2V4.2 #include #ifndef __GNU_LIBRARY__ @@ -1456,6 +1458,8 @@ scheduler_functions *thread_scheduler= &thread_scheduler_struct, #ifdef HAVE_OPENSSL #include #ifndef HAVE_YASSL + +#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER) typedef struct CRYPTO_dynlock_value { mysql_rwlock_t lock; @@ -1467,6 +1471,7 @@ 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 char *des_key_file; #ifndef EMBEDDED_LIBRARY struct st_VioSSLFd *ssl_acceptor_fd; @@ -2243,9 +2248,11 @@ static void clean_up_mutexes() #ifdef HAVE_OPENSSL mysql_mutex_destroy(&LOCK_des_key_file); #ifndef HAVE_YASSL +#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER) for (int i= 0; i < CRYPTO_num_locks(); ++i) mysql_rwlock_destroy(&openssl_stdlocks[i].lock); OPENSSL_free(openssl_stdlocks); +#endif #endif /* HAVE_YASSL */ #endif /* HAVE_OPENSSL */ #ifdef HAVE_REPLICATION @@ -4595,6 +4602,7 @@ static int init_thread_environment() mysql_mutex_init(key_LOCK_des_key_file, &LOCK_des_key_file, MY_MUTEX_INIT_FAST); #ifndef HAVE_YASSL +#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER) openssl_stdlocks= (openssl_lock_t*) OPENSSL_malloc(CRYPTO_num_locks() * sizeof(openssl_lock_t)); for (int i= 0; i < CRYPTO_num_locks(); ++i) @@ -4605,6 +4613,7 @@ static int init_thread_environment() CRYPTO_set_locking_callback(openssl_lock_function); #endif #endif +#endif 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); @@ -4638,6 +4647,7 @@ static int init_thread_environment() #if defined(HAVE_OPENSSL) && !defined(HAVE_YASSL) +#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER) static openssl_lock_t *openssl_dynlock_create(const char *file, int line) { openssl_lock_t *lock= new openssl_lock_t; @@ -4697,6 +4707,7 @@ static void openssl_lock(int mode, openssl_lock_t *lock, const char *file, abort(); } } +#endif #endif /* HAVE_OPENSSL */ @@ -4726,8 +4737,9 @@ static void init_ssl() while ((err= ERR_get_error())) sql_print_warning("SSL error: %s", ERR_error_string(err, NULL)); } - else + else { ERR_remove_state(0); + } } else { diff --git a/sql/slave.cc b/sql/slave.cc index f95dd60287b..636965c4619 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -60,6 +60,11 @@ #include "debug_sync.h" #include "rpl_parallel.h" +#if OPENSSL_VERSION_NUMBER >= 0x10100000L +#define ERR_remove_state(X) +#elif defined(HAVE_ERR_remove_thread_state) +#define ERR_remove_state(X) ERR_remove_thread_state(NULL) +#endif #define FLAGSTR(V,F) ((V)&(F)?#F" ":"") @@ -4505,7 +4510,11 @@ log space"); DBUG_LEAVE; // Must match DBUG_ENTER() my_thread_end(); #ifdef HAVE_OPENSSL +#if OPENSSL_VERSION_NUMBER < 0x10000000L ERR_remove_state(0); +#elif OPENSSL_VERSION_NUMBER < 0x10100000L + ERR_remove_thread_state(0); +#endif #endif pthread_exit(0); return 0; // Avoid compiler warnings @@ -5166,7 +5175,11 @@ pthread_handler_t handle_slave_sql(void *arg) DBUG_LEAVE; // Must match DBUG_ENTER() my_thread_end(); #ifdef HAVE_OPENSSL +#if OPENSSL_VERSION_NUMBER < 0x10000000L ERR_remove_state(0); +#elif OPENSSL_VERSION_NUMBER < 0x10100000L + ERR_remove_thread_state(0); +#endif #endif pthread_exit(0); return 0; // Avoid compiler warnings diff --git a/vio/viosslfactories.c b/vio/viosslfactories.c index 52b624d3376..497047cac72 100644 --- a/vio/viosslfactories.c +++ b/vio/viosslfactories.c @@ -17,17 +17,27 @@ #include "vio_priv.h" #ifdef HAVE_OPENSSL -#ifndef HAVE_YASSL +#if defined(HAVE_YASSL) || defined(LIBRESSL_VERSION_NUMBER) +#define OPENSSL_init_ssl(X,Y) SSL_library_init() +#else #include #include + +#if OPENSSL_VERSION_NUMBER >= 0x10100000L +#define ERR_remove_state(X) +#else +#define OPENSSL_init_ssl(X,Y) SSL_library_init() +#endif + #endif 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() + +/* {{{ get_dh_2048 */ +static DH *get_dh_2048() { static unsigned char dh2048_p[]={ 0xA1,0xBB,0x7C,0x20,0xC5,0x5B,0xC0,0x7B,0x21,0x8B,0xD6,0xA8, @@ -57,18 +67,32 @@ DH *get_dh2048() 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); + if ((dh=DH_new()) == NULL) + return(NULL); +#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER) + (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; } +#else + { + BIGNUM *dhp_bn= BN_bin2bn(dh2048_p,sizeof(dh2048_p),NULL), + *dhg_bn= BN_bin2bn(dh2048_g,sizeof(dh2048_g),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; + } + } +#endif + return dh; } - static const char* -ssl_error_string[] = +ssl_error_string[] = { "No error", "Unable to get certificate", @@ -148,9 +172,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) @@ -265,7 +287,7 @@ new_VioSSLFd(const char *key_file, const char *cert_file, /* DH stuff */ if (!is_client_method) { - dh=get_dh2048(); + dh=get_dh_2048(); if (!SSL_CTX_set_tmp_dh(ssl_fd->ssl_context, dh)) { *error= SSL_INITERR_DH; From 1e73c46c82f65ef59485f4789cc0642a03bb2494 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Wed, 3 May 2017 21:22:59 +0200 Subject: [PATCH 2/2] MDEV-10332 support for OpenSSL 1.1 and LibreSSL post-review fixes: * move all ssl implementation related ifdefs/defines to one file (ssl_compat.h) * work around OpenSSL-1.1 desire to malloc every EVP context by run-time checking that context allocated on the stack is big enough (openssl.c) * use newer version of the AWS SDK for OpenSSL 1.1 * use get_dh2048() function as generated by openssl 1.1 (viosslfactories.c) Upstream commit: ccca4f43c92916c347210a7f9a8126f2aa3f6c31 --- include/my_crypt.h | 15 ----- include/ssl_compat.h | 75 +++++++++++++++++++++ include/violite.h | 12 ---- mysql-test/mysql-test-run.pl | 2 +- mysql-test/t/openssl_6975.test | 7 +- mysql-test/t/ssl_8k_key.test | 5 +- mysys_ssl/CMakeLists.txt | 1 + mysys_ssl/my_crypt.cc | 102 +++++++++++------------------ mysys_ssl/my_md5.cc | 85 +++++++++--------------- mysys_ssl/openssl.c | 71 ++++++++++++++++++++ mysys_ssl/yassl.cc | 19 ------ plugin/aws_key_management/CMakeLists.txt | 10 +++ sql-common/client.c | 8 +-- sql/mysqld.cc | 49 +++++++------- sql/slave.cc | 19 +----- vio/vio.c | 1 + vio/viosslfactories.c | 108 +++++++++++++------------------ 17 files changed, 305 insertions(+), 284 deletions(-) create mode 100644 include/ssl_compat.h create mode 100644 mysys_ssl/openssl.c diff --git a/include/my_crypt.h b/include/my_crypt.h index e7dd9d80100..719e349bfb9 100644 --- a/include/my_crypt.h +++ b/include/my_crypt.h @@ -21,19 +21,4 @@ #include /* HAVE_EncryptAes128{Ctr,Gcm} */ #include -/* OpenSSL version specific definitions */ -#if !defined(HAVE_YASSL) && defined(OPENSSL_VERSION_NUMBER) -#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER) -#define ERR_remove_state(X) -#else -#define EVP_CIPHER_CTX_reset(X) EVP_CIPHER_CTX_cleanup(X) -#define RAND_OpenSSL() RAND_SSLeay(); -#if defined(HAVE_ERR_remove_thread_state) -#define ERR_remove_state(X) ERR_remove_thread_state(NULL) -#endif -#endif -#elif defined(HAVE_YASSL) -#define EVP_CIPHER_CTX_reset(X) EVP_CIPHER_CTX_cleanup(X) -#endif /* !defined(HAVE_YASSL) */ - #endif /* MY_CRYPT_INCLUDED */ diff --git a/include/ssl_compat.h b/include/ssl_compat.h new file mode 100644 index 00000000000..b0e3ed497cd --- /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 23800696e5a..572d4741c80 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,11 +139,6 @@ typedef my_socket YASSL_SOCKET_T; #include #include -#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER) -#define ERR_remove_state(X) -#elif defined(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, diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index 7241d2f2ea9..21dff82736e 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -2304,7 +2304,7 @@ sub environment_setup { $ENV{'MYSQL_PLUGIN'}= $exe_mysql_plugin; $ENV{'MYSQL_EMBEDDED'}= $exe_mysql_embedded; - my $client_config_exe= + 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})= diff --git a/mysql-test/t/openssl_6975.test b/mysql-test/t/openssl_6975.test index 6cf5d82cf54..6a82d013fb6 100644 --- a/mysql-test/t/openssl_6975.test +++ b/mysql-test/t/openssl_6975.test @@ -19,9 +19,8 @@ let $mysql=$MYSQL --ssl-key=$MYSQL_TEST_DIR/std_data/client-key.pem --ssl-cert=$ disable_abort_on_error; echo TLS1.2 ciphers: user is ok with any cipher; exec $mysql --ssl-cipher=AES128-SHA256; ---replace_result DHE-RSA-CHACHA20-POLY1305 DHE-RSA-AES256-GCM-SHA384 ---replace_result ECDHE-RSA-AES256-GCM-SHA384 DHE-RSA-AES256-GCM-SHA384 -exec $mysql --ssl-cipher=TLSv1.2 +--replace_result DHE-RSA-CHACHA20-POLY1305 DHE-RSA-AES256-GCM-SHA384 ECDHE-RSA-AES256-GCM-SHA384 DHE-RSA-AES256-GCM-SHA384 +exec $mysql --ssl-cipher=TLSv1.2; echo TLS1.2 ciphers: user requires SSLv3 cipher AES128-SHA; exec $mysql --user ssl_sslv3 --ssl-cipher=AES128-SHA256; exec $mysql --user ssl_sslv3 --ssl-cipher=TLSv1.2; @@ -31,7 +30,7 @@ exec $mysql --user ssl_tls12 --ssl-cipher=TLSv1.2; echo SSLv3 ciphers: user is ok with any cipher; exec $mysql --ssl-cipher=AES256-SHA; -exec $mysql --ssl-cipher=DHE-RSA-AES256-SHA +exec $mysql --ssl-cipher=SSLv3; echo SSLv3 ciphers: user requires SSLv3 cipher AES128-SHA; exec $mysql --user ssl_sslv3 --ssl-cipher=AES128-SHA; exec $mysql --user ssl_sslv3 --ssl-cipher=SSLv3; diff --git a/mysql-test/t/ssl_8k_key.test b/mysql-test/t/ssl_8k_key.test index 470d577edb8..9d5b382726e 100644 --- a/mysql-test/t/ssl_8k_key.test +++ b/mysql-test/t/ssl_8k_key.test @@ -1,6 +1,5 @@ -# This test should work in embedded server after we fix mysqltest --- source include/require_openssl_client.inc --- 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 4f6f7458c5b..f8a767ed6f3 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 0ff49a2c427..ed1c82dbac6 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 @@ -21,30 +21,31 @@ #ifdef HAVE_YASSL #include "yassl.cc" #else - #include #include #include #include - #endif -#include -#define MY_CIPHER_CTX_SIZE 384 +#include +#include class MyCTX { public: + char ctx_buf[EVP_CIPHER_CTX_SIZE]; EVP_CIPHER_CTX *ctx; - const uchar *key; - unsigned int klen; - MyCTX() { - ctx= EVP_CIPHER_CTX_new(); - } - virtual ~MyCTX() { - EVP_CIPHER_CTX_free(ctx); - ERR_remove_state(0); - } + + 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) @@ -78,9 +79,12 @@ class MyCTX class MyCTX_nopad : public MyCTX { public: + const uchar *key; + uint klen, buf_len; + uchar oiv[MY_AES_BLOCK_SIZE]; + MyCTX_nopad() : MyCTX() { } ~MyCTX_nopad() { } - unsigned int buf_len; int init(const EVP_CIPHER *cipher, int encrypt, const uchar *key, uint klen, const uchar *iv, uint ivlen) @@ -89,19 +93,8 @@ class MyCTX_nopad : public MyCTX this->key= key; this->klen= klen; this->buf_len= 0; - /* FIX-ME: - For the sake of backward compatibility we do some strange hack here: - Since ECB doesn't need an IV (and therefore is considered kind of - insecure) we need to store the specified iv. - The last nonpadding block will be encrypted with an additional - expensive crypt_call in ctr mode instead - of encrypting the entire plain text in ctr-mode */ -#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER) - const unsigned char *oiv= EVP_CIPHER_CTX_original_iv(ctx); -#else - const unsigned char *oiv= ctx->oiv; -#endif - memcpy((char *)oiv, iv, ivlen); + memcpy(oiv, iv, ivlen); + DBUG_ASSERT(ivlen == 0 || ivlen == sizeof(oiv)); int res= MyCTX::init(cipher, encrypt, key, klen, iv, ivlen); @@ -111,34 +104,30 @@ class MyCTX_nopad : public MyCTX int update(const uchar *src, uint slen, uchar *dst, uint *dlen) { - buf_len= slen % MY_AES_BLOCK_SIZE; + buf_len+= slen; return MyCTX::update(src, slen, dst, dlen); } int finish(uchar *dst, uint *dlen) { + buf_len %= MY_AES_BLOCK_SIZE; if (buf_len) { - const uchar *org_iv; - unsigned char *buf; + 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; -#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER) - org_iv= EVP_CIPHER_CTX_original_iv(ctx); - buf= EVP_CIPHER_CTX_buf_noconst(ctx); -#else - org_iv= ctx->oiv; - buf= ctx->buf; -#endif - my_aes_crypt(MY_AES_ECB, ENCRYPTION_FLAG_ENCRYPT | ENCRYPTION_FLAG_NOPAD, - org_iv, sizeof(mask), mask, &mlen, key, klen, 0, 0); + oiv, sizeof(mask), mask, &mlen, key, klen, 0, 0); DBUG_ASSERT(mlen == sizeof(mask)); for (uint i=0; i < buf_len; i++) @@ -178,9 +167,8 @@ make_aes_dispatcher(gcm) class MyCTX_gcm : public MyCTX { public: - const uchar *aad= NULL; + const uchar *aad; int aadlen; - my_bool encrypt; MyCTX_gcm() : MyCTX() { } ~MyCTX_gcm() { } @@ -192,7 +180,6 @@ class MyCTX_gcm : public MyCTX int real_ivlen= EVP_CIPHER_CTX_iv_length(ctx); aad= iv + real_ivlen; aadlen= ivlen - real_ivlen; - this->encrypt= encrypt; return res; } @@ -204,14 +191,14 @@ 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 (!this->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, (void*)(src + slen))) return MY_AES_OPENSSL_ERROR; } - int unused= 0; + int unused; if (aadlen && !EVP_CipherUpdate(ctx, NULL, &unused, aad, aadlen)) return MY_AES_OPENSSL_ERROR; aadlen= 0; @@ -220,12 +207,12 @@ class MyCTX_gcm : public MyCTX int finish(uchar *dst, uint *dlen) { - int fin= 0; + int fin; if (!EVP_CipherFinal_ex(ctx, dst, &fin)) return MY_AES_BAD_DATA; DBUG_ASSERT(fin == 0); - if (this->encrypt) + if (EVP_CIPHER_CTX_encrypting(ctx)) { if(!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, MY_AES_BLOCK_SIZE, dst)) return MY_AES_OPENSSL_ERROR; @@ -295,20 +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= 0, d2= 0; + 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; - /* in case of failure clear error queue */ -#ifndef HAVE_YASSL - /* since we don't check the crypto error messages we need to - clear the error queue - otherwise subsequent crypto or tls/ssl - calls will fail */ - if (!*dlen) - ERR_clear_error(); -#endif + if (res1 || res2) + ERR_remove_state(0); /* in case of failure clear error queue */ + else + *dlen= d1 + d2; return res1 ? res1 : res2; } @@ -350,12 +332,6 @@ int my_random_bytes(uchar* buf, int num) 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_OpenSSL(); if (rand == NULL || rand->bytes(buf, num) != 1) return MY_AES_OPENSSL_ERROR; diff --git a/mysys_ssl/my_md5.cc b/mysys_ssl/my_md5.cc index 02c01dd7148..0105082b7e1 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 @@ -27,50 +27,34 @@ #include #include -#define MA_HASH_CTX_SIZE 512 - #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 +#include -#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER) -#define EVP_MD_CTX_reset(X) EVP_MD_CTX_cleanup(X) -#endif -typedef EVP_MD_CTX MD5_CONTEXT; - -static void md5_init(MD5_CONTEXT *context) +static void md5_init(EVP_MD_CTX *context) { - memset(context, 0, my_md5_context_size()); EVP_MD_CTX_init(context); #ifdef EVP_MD_CTX_FLAG_NON_FIPS_ALLOW /* Ok to ignore FIPS: MD5 is not used for crypto here */ @@ -79,20 +63,15 @@ 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_reset(context); + EVP_MD_CTX_cleanup(context); } #endif /* HAVE_YASSL */ @@ -108,26 +87,23 @@ static void md5_result(MD5_CONTEXT *context, uchar digest[MD5_HASH_SIZE]) */ void my_md5(uchar *digest, const char *buf, size_t len) { -#ifdef HAVE_YASSL - MD5_CONTEXT md5_context; -#else - unsigned char md5_context[MA_HASH_CTX_SIZE]; -#endif - md5_init_fast((MD5_CONTEXT *)&md5_context); - md5_input((MD5_CONTEXT *)&md5_context, (const uchar *)buf, len); - md5_result((MD5_CONTEXT *)&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 */ @@ -135,37 +111,34 @@ void my_md5_multi(uchar *digest, ...) { va_list args; const uchar *str; -#ifdef HAVE_YASSL - MD5_CONTEXT md5_context; -#else - unsigned char md5_context[MA_HASH_CTX_SIZE]; -#endif + 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_context); + md5_init(ctx); for (str= va_arg(args, const uchar*); str; str= va_arg(args, const uchar*)) - md5_input((MD5_CONTEXT *)&md5_context, str, va_arg(args, size_t)); + md5_input(ctx, str, va_arg(args, size_t)); - md5_result((MD5_CONTEXT *)&md5_context, digest); + md5_result(ctx, digest); va_end(args); } size_t my_md5_context_size() { - return MA_HASH_CTX_SIZE; + 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 00000000000..a3f1ca29ec1 --- /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 9e6f90d8d77..aa5631f2ab8 100644 --- a/mysys_ssl/yassl.cc +++ b/mysys_ssl/yassl.cc @@ -24,7 +24,6 @@ #include #include "aes.hpp" -#include using yaSSL::yaERR_remove_state; @@ -45,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; @@ -76,26 +74,12 @@ static void EVP_CIPHER_CTX_init(EVP_CIPHER_CTX *ctx) ctx->final_used= ctx->buf_len= ctx->flags= 0; } -static EVP_CIPHER_CTX *EVP_CIPHER_CTX_new() -{ - EVP_CIPHER_CTX *ctx= (EVP_CIPHER_CTX *)my_malloc(sizeof(EVP_CIPHER_CTX), MYF(0)); - if (ctx) - EVP_CIPHER_CTX_init(ctx); - return ctx; -} - static int EVP_CIPHER_CTX_cleanup(EVP_CIPHER_CTX *ctx) { TAO(ctx)->~AES(); return 1; } -static void EVP_CIPHER_CTX_free(EVP_CIPHER_CTX *ctx) -{ - EVP_CIPHER_CTX_cleanup(ctx); - my_free(ctx); -} - static int EVP_CIPHER_CTX_set_padding(EVP_CIPHER_CTX *ctx, int pad) { if (pad) @@ -112,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 d881080b55a..eb2899410d4 100644 --- a/sql-common/client.c +++ b/sql-common/client.c @@ -104,11 +104,8 @@ my_bool net_flush(NET *net); #define CONNECT_TIMEOUT 0 #endif -#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER) || defined(HAVE_YASSL) -#define ASN1_STRING_get0_data(X) ASN1_STRING_data(X) -#endif - #include "client_settings.h" +#include #include #include #include @@ -1772,9 +1769,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) diff --git a/sql/mysqld.cc b/sql/mysqld.cc index d6a7c6b4931..904695d8742 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -111,7 +111,6 @@ #endif #include -#include #define mysqld_charset &my_charset_latin1 @@ -121,7 +120,6 @@ #define HAVE_CLOSE_SERVER_SOCK 1 #endif - extern "C" { // Because of SCO 3.2V4.2 #include #ifndef __GNU_LIBRARY__ @@ -339,9 +337,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 +989,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,9 +1459,7 @@ scheduler_functions *thread_scheduler= &thread_scheduler_struct, #ifdef HAVE_OPENSSL #include -#ifndef HAVE_YASSL - -#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER) +#ifdef HAVE_OPENSSL10 typedef struct CRYPTO_dynlock_value { mysql_rwlock_t lock; @@ -1470,8 +1470,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 +#endif /* HAVE_OPENSSL10 */ char *des_key_file; #ifndef EMBEDDED_LIBRARY struct st_VioSSLFd *ssl_acceptor_fd; @@ -2247,13 +2246,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 -#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER) +#ifdef HAVE_OPENSSL10 for (int i= 0; i < CRYPTO_num_locks(); ++i) mysql_rwlock_destroy(&openssl_stdlocks[i].lock); OPENSSL_free(openssl_stdlocks); -#endif -#endif /* HAVE_YASSL */ +#endif /* HAVE_OPENSSL10 */ #endif /* HAVE_OPENSSL */ #ifdef HAVE_REPLICATION mysql_mutex_destroy(&LOCK_rpl_status); @@ -4055,6 +4052,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; @@ -4601,8 +4606,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 -#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER) +#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) @@ -4611,9 +4615,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 +#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,8 +4649,7 @@ static int init_thread_environment() } -#if defined(HAVE_OPENSSL) && !defined(HAVE_YASSL) -#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER) +#ifdef HAVE_OPENSSL10 static openssl_lock_t *openssl_dynlock_create(const char *file, int line) { openssl_lock_t *lock= new openssl_lock_t; @@ -4707,9 +4709,7 @@ static void openssl_lock(int mode, openssl_lock_t *lock, const char *file, abort(); } } -#endif -#endif /* HAVE_OPENSSL */ - +#endif /* HAVE_OPENSSL10 */ static void init_ssl() { @@ -4737,9 +4737,8 @@ static void init_ssl() while ((err= ERR_get_error())) sql_print_warning("SSL error: %s", ERR_error_string(err, NULL)); } - else { + else ERR_remove_state(0); - } } else { diff --git a/sql/slave.cc b/sql/slave.cc index 636965c4619..6882156564c 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -40,6 +40,7 @@ #include #include #include +#include #include #include #include "rpl_handler.h" @@ -60,12 +61,6 @@ #include "debug_sync.h" #include "rpl_parallel.h" -#if OPENSSL_VERSION_NUMBER >= 0x10100000L -#define ERR_remove_state(X) -#elif defined(HAVE_ERR_remove_thread_state) -#define ERR_remove_state(X) ERR_remove_thread_state(NULL) -#endif - #define FLAGSTR(V,F) ((V)&(F)?#F" ":"") #define MAX_SLAVE_RETRY_PAUSE 5 @@ -4509,13 +4504,7 @@ log space"); DBUG_LEAVE; // Must match DBUG_ENTER() my_thread_end(); -#ifdef HAVE_OPENSSL -#if OPENSSL_VERSION_NUMBER < 0x10000000L ERR_remove_state(0); -#elif OPENSSL_VERSION_NUMBER < 0x10100000L - ERR_remove_thread_state(0); -#endif -#endif pthread_exit(0); return 0; // Avoid compiler warnings } @@ -5174,13 +5163,7 @@ pthread_handler_t handle_slave_sql(void *arg) DBUG_LEAVE; // Must match DBUG_ENTER() my_thread_end(); -#ifdef HAVE_OPENSSL -#if OPENSSL_VERSION_NUMBER < 0x10000000L ERR_remove_state(0); -#elif OPENSSL_VERSION_NUMBER < 0x10100000L - ERR_remove_thread_state(0); -#endif -#endif pthread_exit(0); return 0; // Avoid compiler warnings } diff --git a/vio/vio.c b/vio/vio.c index e3bc8ca8ab8..44d06092184 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 497047cac72..71ef2879464 100644 --- a/vio/viosslfactories.c +++ b/vio/viosslfactories.c @@ -15,20 +15,12 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "vio_priv.h" +#include #ifdef HAVE_OPENSSL -#if defined(HAVE_YASSL) || defined(LIBRESSL_VERSION_NUMBER) -#define OPENSSL_init_ssl(X,Y) SSL_library_init() -#else +#ifndef HAVE_YASSL #include #include - -#if OPENSSL_VERSION_NUMBER >= 0x10100000L -#define ERR_remove_state(X) -#else -#define OPENSSL_init_ssl(X,Y) SSL_library_init() -#endif - #endif static my_bool ssl_algorithms_added = FALSE; @@ -36,59 +28,51 @@ static my_bool ssl_error_strings_loaded= FALSE; /* the function below was generated with "openssl dhparam -2 -C 2048" */ -/* {{{ get_dh_2048 */ -static DH *get_dh_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); -#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER) - (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; } -#else - { - BIGNUM *dhp_bn= BN_bin2bn(dh2048_p,sizeof(dh2048_p),NULL), - *dhg_bn= BN_bin2bn(dh2048_g,sizeof(dh2048_g),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; + 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; } - } -#endif - return dh; + return dh; } static const char* @@ -287,7 +271,7 @@ new_VioSSLFd(const char *key_file, const char *cert_file, /* DH stuff */ if (!is_client_method) { - dh=get_dh_2048(); + dh=get_dh2048(); if (!SSL_CTX_set_tmp_dh(ssl_fd->ssl_context, dh)) { *error= SSL_INITERR_DH;