From 3bd5589e1a5a93f9c224badf983cd65c45215390 Mon Sep 17 00:00:00 2001 From: Georgi Kodinov Date: Thu, 31 Oct 2013 11:35:15 +0200 Subject: [PATCH] WL#6791 : Redefine client --ssl option to imply enforced encryption # Changed the meaning of the --ssl=1 option of all client binaries to mean force ssl, not try ssl and fail over to eunecrypted # Added a new MYSQL_OPT_SSL_ENFORCE mysql_options() option to specify that an ssl connection is required. # Added a new macro SSL_SET_OPTIONS() to the client SSL handling headers that sets all the relevant SSL options at once. # Revamped all of the current native clients to use the new macro # Removed some Windows line endings. # Added proper handling of the new option into the ssl helper headers. # If SSL is mandatory assume that the media is secure enough for the sha256 plugin to do unencrypted password exchange even before establishing a connection. # Set the default ssl cipher to DHE-RSA-AES256-SHA if none is specified. # updated test cases that require a non-default cipher to spawn a mysql command line tool binary since mysqltest has no support for specifying ciphers. # updated the replication slave connection code to always enforce SSL if any of the SSL config options is present. # test cases added and updated. # added a mysql_get_option() API to return mysql_options() values. Used the new API inside the sha256 plugin. # Fixed compilation warnings because of unused variables. # Fixed test failures (mysql_ssl and bug13115401) # Fixed whitespace issues. # Fully implemented the mysql_get_option() function. # Added a test case for mysql_get_option() # fixed some trailing whitespace issues # fixed some uint/int warnings in mysql_client_test.c # removed shared memory option from non-windows get_options tests # moved MYSQL_OPT_LOCAL_INFILE to the uint options --- client/mysql.cc | 12 +- client/mysql_secure_installation.cc | 12 +- client/mysql_upgrade.c | 2 +- client/mysqladmin.cc | 12 +- client/mysqlbinlog.cc | 12 +- client/mysqlcheck.c | 10 +- client/mysqldump.c | 12 +- client/mysqlimport.c | 12 +- client/mysqlshow.c | 12 +- client/mysqlslap.c | 14 +- client/mysqltest.cc | 36 ++- cmake/mysql_version.cmake | 2 +- include/mysql.h | 5 +- include/mysql.h.pp | 5 +- include/sql_common.h | 2 + include/sslopt-case.h | 13 +- include/sslopt-longopts.h | 18 +- include/sslopt-vars.h | 24 +- mysql-test/r/mysql_ssl.result | 5 + ...ugin_auth_sha256_server_default_tls.result | 7 +- mysql-test/r/ssl_cipher.result | 4 +- mysql-test/t/mysql_ssl-master.opt | 1 + mysql-test/t/mysql_ssl.test | 26 ++ ...plugin_auth_sha256_server_default_tls.test | 15 +- mysql-test/t/ssl_cipher.test | 14 +- sql-common/client.c | 258 +++++++++++++++++- sql-common/client_authentication.cc | 20 +- sql/rpl_slave.cc | 7 +- tests/mysql_client_test.c | 109 ++++++++ 29 files changed, 514 insertions(+), 167 deletions(-) create mode 100644 mysql-test/r/mysql_ssl.result create mode 100644 mysql-test/t/mysql_ssl-master.opt create mode 100644 mysql-test/t/mysql_ssl.test diff --git a/client/mysql.cc b/client/mysql.cc index e99fe6bd2d7e..a503b79f789b 100644 --- a/client/mysql.cc +++ b/client/mysql.cc @@ -4953,17 +4953,7 @@ init_connection_options(MYSQL *mysql) if (using_opt_local_infile) mysql_options(mysql, MYSQL_OPT_LOCAL_INFILE, (char*) &opt_local_infile); -#if defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY) - if (opt_use_ssl) - { - mysql_ssl_set(mysql, opt_ssl_key, opt_ssl_cert, opt_ssl_ca, - opt_ssl_capath, opt_ssl_cipher); - mysql_options(mysql, MYSQL_OPT_SSL_CRL, opt_ssl_crl); - mysql_options(mysql, MYSQL_OPT_SSL_CRLPATH, opt_ssl_crlpath); - } - mysql_options(mysql, MYSQL_OPT_SSL_VERIFY_SERVER_CERT, - (char*) &opt_ssl_verify_server_cert); -#endif + SSL_SET_OPTIONS(mysql); if (opt_protocol) mysql_options(mysql, MYSQL_OPT_PROTOCOL, (char*) &opt_protocol); diff --git a/client/mysql_secure_installation.cc b/client/mysql_secure_installation.cc index 3b4985fd9e8c..e5b4d82fa3f4 100644 --- a/client/mysql_secure_installation.cc +++ b/client/mysql_secure_installation.cc @@ -158,17 +158,7 @@ my_arguments_get_one_option(int optid, static void init_connection_options(MYSQL *mysql) { -#if defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY) - if (opt_use_ssl) - { - mysql_ssl_set(mysql, opt_ssl_key, opt_ssl_cert, opt_ssl_ca, - opt_ssl_capath, opt_ssl_cipher); - mysql_options(mysql, MYSQL_OPT_SSL_CRL, opt_ssl_crl); - mysql_options(mysql, MYSQL_OPT_SSL_CRLPATH, opt_ssl_crlpath); - } - mysql_options(mysql, MYSQL_OPT_SSL_VERIFY_SERVER_CERT, - (char*) &opt_ssl_verify_server_cert); -#endif + SSL_SET_OPTIONS(mysql); if (opt_protocol) mysql_options(mysql, MYSQL_OPT_PROTOCOL, (char*) &opt_protocol); diff --git a/client/mysql_upgrade.c b/client/mysql_upgrade.c index f5e689196d6e..51c4cfce013f 100644 --- a/client/mysql_upgrade.c +++ b/client/mysql_upgrade.c @@ -288,7 +288,7 @@ get_one_option(int optid, const struct my_option *opt, case OPT_WRITE_BINLOG: /* --write-binlog */ add_option= FALSE; break; - +#include case 'h': /* --host */ case 'W': /* --pipe */ case 'P': /* --port */ diff --git a/client/mysqladmin.cc b/client/mysqladmin.cc index 381e9c68ecc1..d70c8f742ef4 100644 --- a/client/mysqladmin.cc +++ b/client/mysqladmin.cc @@ -361,17 +361,7 @@ int main(int argc,char *argv[]) uint tmp=opt_connect_timeout; mysql_options(&mysql,MYSQL_OPT_CONNECT_TIMEOUT, (char*) &tmp); } -#ifdef HAVE_OPENSSL - if (opt_use_ssl) - { - mysql_ssl_set(&mysql, opt_ssl_key, opt_ssl_cert, opt_ssl_ca, - opt_ssl_capath, opt_ssl_cipher); - mysql_options(&mysql, MYSQL_OPT_SSL_CRL, opt_ssl_crl); - mysql_options(&mysql, MYSQL_OPT_SSL_CRLPATH, opt_ssl_crlpath); - } - mysql_options(&mysql,MYSQL_OPT_SSL_VERIFY_SERVER_CERT, - (char*)&opt_ssl_verify_server_cert); -#endif + SSL_SET_OPTIONS(&mysql); if (opt_protocol) mysql_options(&mysql,MYSQL_OPT_PROTOCOL,(char*)&opt_protocol); #if defined (_WIN32) && !defined (EMBEDDED_LIBRARY) diff --git a/client/mysqlbinlog.cc b/client/mysqlbinlog.cc index f89cb6234dd5..fdf795bfc7c6 100644 --- a/client/mysqlbinlog.cc +++ b/client/mysqlbinlog.cc @@ -1885,17 +1885,7 @@ static Exit_status safe_connect() return ERROR_STOP; } -#ifdef HAVE_OPENSSL - if (opt_use_ssl) - { - mysql_ssl_set(mysql, opt_ssl_key, opt_ssl_cert, opt_ssl_ca, - opt_ssl_capath, opt_ssl_cipher); - mysql_options(mysql, MYSQL_OPT_SSL_CRL, opt_ssl_crl); - mysql_options(mysql, MYSQL_OPT_SSL_CRLPATH, opt_ssl_crlpath); - } - mysql_options(mysql, MYSQL_OPT_SSL_VERIFY_SERVER_CERT, - (char*) &opt_ssl_verify_server_cert); -#endif + SSL_SET_OPTIONS(mysql); if (opt_plugin_dir && *opt_plugin_dir) mysql_options(mysql, MYSQL_PLUGIN_DIR, opt_plugin_dir); diff --git a/client/mysqlcheck.c b/client/mysqlcheck.c index cb4cdb84c920..15791fa8c76c 100644 --- a/client/mysqlcheck.c +++ b/client/mysqlcheck.c @@ -881,15 +881,7 @@ static int dbConnect(char *host, char *user, char *passwd) mysql_init(&mysql_connection); if (opt_compress) mysql_options(&mysql_connection, MYSQL_OPT_COMPRESS, NullS); -#ifdef HAVE_OPENSSL - if (opt_use_ssl) - { - mysql_ssl_set(&mysql_connection, opt_ssl_key, opt_ssl_cert, opt_ssl_ca, - opt_ssl_capath, opt_ssl_cipher); - mysql_options(&mysql_connection, MYSQL_OPT_SSL_CRL, opt_ssl_crl); - mysql_options(&mysql_connection, MYSQL_OPT_SSL_CRLPATH, opt_ssl_crlpath); - } -#endif + SSL_SET_OPTIONS(&mysql_connection); if (opt_protocol) mysql_options(&mysql_connection,MYSQL_OPT_PROTOCOL,(char*)&opt_protocol); if (opt_bind_addr) diff --git a/client/mysqldump.c b/client/mysqldump.c index 71160afde913..4b776014f143 100644 --- a/client/mysqldump.c +++ b/client/mysqldump.c @@ -1595,17 +1595,7 @@ static int connect_to_db(char *host, char *user,char *passwd) mysql_init(&mysql_connection); if (opt_compress) mysql_options(&mysql_connection,MYSQL_OPT_COMPRESS,NullS); -#ifdef HAVE_OPENSSL - if (opt_use_ssl) - { - mysql_ssl_set(&mysql_connection, opt_ssl_key, opt_ssl_cert, opt_ssl_ca, - opt_ssl_capath, opt_ssl_cipher); - mysql_options(&mysql_connection, MYSQL_OPT_SSL_CRL, opt_ssl_crl); - mysql_options(&mysql_connection, MYSQL_OPT_SSL_CRLPATH, opt_ssl_crlpath); - } - mysql_options(&mysql_connection,MYSQL_OPT_SSL_VERIFY_SERVER_CERT, - (char*)&opt_ssl_verify_server_cert); -#endif + SSL_SET_OPTIONS(&mysql_connection); if (opt_protocol) mysql_options(&mysql_connection,MYSQL_OPT_PROTOCOL,(char*)&opt_protocol); if (opt_bind_addr) diff --git a/client/mysqlimport.c b/client/mysqlimport.c index eebb89382d59..3748fc1731e3 100644 --- a/client/mysqlimport.c +++ b/client/mysqlimport.c @@ -420,17 +420,7 @@ static MYSQL *db_connect(char *host, char *database, if (opt_local_file) mysql_options(mysql,MYSQL_OPT_LOCAL_INFILE, (char*) &opt_local_file); -#ifdef HAVE_OPENSSL - if (opt_use_ssl) - { - mysql_ssl_set(mysql, opt_ssl_key, opt_ssl_cert, opt_ssl_ca, - opt_ssl_capath, opt_ssl_cipher); - mysql_options(mysql, MYSQL_OPT_SSL_CRL, opt_ssl_crl); - mysql_options(mysql, MYSQL_OPT_SSL_CRLPATH, opt_ssl_crlpath); - } - mysql_options(mysql,MYSQL_OPT_SSL_VERIFY_SERVER_CERT, - (char*)&opt_ssl_verify_server_cert); -#endif + SSL_SET_OPTIONS(mysql); if (opt_protocol) mysql_options(mysql,MYSQL_OPT_PROTOCOL,(char*)&opt_protocol); if (opt_bind_addr) diff --git a/client/mysqlshow.c b/client/mysqlshow.c index cf81588baffc..c7756d0d193b 100644 --- a/client/mysqlshow.c +++ b/client/mysqlshow.c @@ -117,17 +117,7 @@ int main(int argc, char **argv) mysql_init(&mysql); if (opt_compress) mysql_options(&mysql,MYSQL_OPT_COMPRESS,NullS); -#ifdef HAVE_OPENSSL - if (opt_use_ssl) - { - mysql_ssl_set(&mysql, opt_ssl_key, opt_ssl_cert, opt_ssl_ca, - opt_ssl_capath, opt_ssl_cipher); - mysql_options(&mysql, MYSQL_OPT_SSL_CRL, opt_ssl_crl); - mysql_options(&mysql, MYSQL_OPT_SSL_CRLPATH, opt_ssl_crlpath); - } - mysql_options(&mysql,MYSQL_OPT_SSL_VERIFY_SERVER_CERT, - (char*)&opt_ssl_verify_server_cert); -#endif + SSL_SET_OPTIONS(&mysql); if (opt_protocol) mysql_options(&mysql,MYSQL_OPT_PROTOCOL,(char*)&opt_protocol); if (opt_bind_addr) diff --git a/client/mysqlslap.c b/client/mysqlslap.c index a892806bc424..6cb9bb760e72 100644 --- a/client/mysqlslap.c +++ b/client/mysqlslap.c @@ -144,8 +144,8 @@ static my_bool opt_compress= FALSE, tty_password= FALSE, const char *auto_generate_sql_type= "mixed"; static unsigned long connect_flags= CLIENT_MULTI_RESULTS | - CLIENT_MULTI_STATEMENTS | - CLIENT_REMEMBER_OPTIONS; + CLIENT_MULTI_STATEMENTS | + CLIENT_REMEMBER_OPTIONS; static int verbose, delimiter_length; @@ -335,15 +335,7 @@ int main(int argc, char **argv) mysql_init(&mysql); if (opt_compress) mysql_options(&mysql,MYSQL_OPT_COMPRESS,NullS); -#ifdef HAVE_OPENSSL - if (opt_use_ssl) - { - mysql_ssl_set(&mysql, opt_ssl_key, opt_ssl_cert, opt_ssl_ca, - opt_ssl_capath, opt_ssl_cipher); - mysql_options(&mysql, MYSQL_OPT_SSL_CRL, opt_ssl_crl); - mysql_options(&mysql, MYSQL_OPT_SSL_CRLPATH, opt_ssl_crlpath); - } -#endif + SSL_SET_OPTIONS(&mysql); if (opt_protocol) mysql_options(&mysql,MYSQL_OPT_PROTOCOL,(char*)&opt_protocol); #if defined (_WIN32) && !defined (EMBEDDED_LIBRARY) diff --git a/client/mysqltest.cc b/client/mysqltest.cc index ff5aa9449e85..2844868543d6 100644 --- a/client/mysqltest.cc +++ b/client/mysqltest.cc @@ -5507,6 +5507,9 @@ void do_connect(struct st_command *command) my_bool con_pipe= 0, con_shm= 0, con_cleartext_enable= 0; my_bool con_secure_auth= 1; struct st_connection* con_slot; +#if defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY) + my_bool save_opt_use_ssl= opt_use_ssl; +#endif static DYNAMIC_STRING ds_connection_name; static DYNAMIC_STRING ds_host; @@ -5641,23 +5644,22 @@ void do_connect(struct st_command *command) #if defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY) if (opt_use_ssl) con_ssl= 1; -#endif - if (con_ssl) + opt_use_ssl= con_ssl; + + if (opt_use_ssl) { -#if defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY) - mysql_ssl_set(&con_slot->mysql, opt_ssl_key, opt_ssl_cert, opt_ssl_ca, - opt_ssl_capath, opt_ssl_cipher); - mysql_options(&con_slot->mysql, MYSQL_OPT_SSL_CRL, opt_ssl_crl); - mysql_options(&con_slot->mysql, MYSQL_OPT_SSL_CRLPATH, opt_ssl_crlpath); -#if MYSQL_VERSION_ID >= 50000 /* Turn on ssl_verify_server_cert only if host is "localhost" */ opt_ssl_verify_server_cert= !strcmp(ds_host.str, "localhost"); - mysql_options(&con_slot->mysql, MYSQL_OPT_SSL_VERIFY_SERVER_CERT, - &opt_ssl_verify_server_cert); + } +#else + /* keep the compiler happy about con_ssl */ + con_ssl = con_ssl ? TRUE : FALSE; #endif + SSL_SET_OPTIONS(&con_slot->mysql); +#if defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY) + opt_use_ssl= save_opt_use_ssl; #endif - } if (con_pipe) { @@ -8764,22 +8766,16 @@ int main(int argc, char **argv) mysql_options(&con->mysql,MYSQL_OPT_PROTOCOL,(char*)&opt_protocol); #endif -#if defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY) +#if defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY) if (opt_use_ssl) { - mysql_ssl_set(&con->mysql, opt_ssl_key, opt_ssl_cert, opt_ssl_ca, - opt_ssl_capath, opt_ssl_cipher); - mysql_options(&con->mysql, MYSQL_OPT_SSL_CRL, opt_ssl_crl); - mysql_options(&con->mysql, MYSQL_OPT_SSL_CRLPATH, opt_ssl_crlpath); -#if MYSQL_VERSION_ID >= 50000 /* Turn on ssl_verify_server_cert only if host is "localhost" */ opt_ssl_verify_server_cert= opt_host && !strcmp(opt_host, "localhost"); - mysql_options(&con->mysql, MYSQL_OPT_SSL_VERIFY_SERVER_CERT, - &opt_ssl_verify_server_cert); -#endif } #endif + SSL_SET_OPTIONS(&con->mysql); + #if defined (_WIN32) && !defined (EMBEDDED_LIBRARY) if (shared_memory_base_name) diff --git a/cmake/mysql_version.cmake b/cmake/mysql_version.cmake index c9631db1c210..0beab367fd4f 100644 --- a/cmake/mysql_version.cmake +++ b/cmake/mysql_version.cmake @@ -18,7 +18,7 @@ # SET(SHARED_LIB_MAJOR_VERSION "18") -SET(SHARED_LIB_MINOR_VERSION "1") +SET(SHARED_LIB_MINOR_VERSION "2") SET(PROTOCOL_VERSION "10") SET(DOT_FRM_VERSION "6") diff --git a/include/mysql.h b/include/mysql.h index 72b94b936cc5..689161cf7115 100644 --- a/include/mysql.h +++ b/include/mysql.h @@ -159,7 +159,8 @@ enum mysql_option MYSQL_OPT_CONNECT_ATTR_DELETE, MYSQL_SERVER_PUBLIC_KEY, MYSQL_ENABLE_CLEARTEXT_PLUGIN, - MYSQL_OPT_CAN_HANDLE_EXPIRED_PASSWORDS + MYSQL_OPT_CAN_HANDLE_EXPIRED_PASSWORDS, + MYSQL_OPT_SSL_ENFORCE }; /** @@ -451,6 +452,8 @@ int STDCALL mysql_options(MYSQL *mysql,enum mysql_option option, const void *arg); int STDCALL mysql_options4(MYSQL *mysql,enum mysql_option option, const void *arg1, const void *arg2); +int STDCALL mysql_get_option(MYSQL *mysql, enum mysql_option option, + const void *arg); void STDCALL mysql_free_result(MYSQL_RES *result); void STDCALL mysql_data_seek(MYSQL_RES *result, my_ulonglong offset); diff --git a/include/mysql.h.pp b/include/mysql.h.pp index 220f68ebc52f..82cb087e4377 100644 --- a/include/mysql.h.pp +++ b/include/mysql.h.pp @@ -316,7 +316,8 @@ MYSQL_OPT_CONNECT_ATTR_DELETE, MYSQL_SERVER_PUBLIC_KEY, MYSQL_ENABLE_CLEARTEXT_PLUGIN, - MYSQL_OPT_CAN_HANDLE_EXPIRED_PASSWORDS + MYSQL_OPT_CAN_HANDLE_EXPIRED_PASSWORDS, + MYSQL_OPT_SSL_ENFORCE }; struct st_mysql_options_extention; struct st_mysql_options { @@ -518,6 +519,8 @@ const void *arg); int mysql_options4(MYSQL *mysql,enum mysql_option option, const void *arg1, const void *arg2); +int mysql_get_option(MYSQL *mysql, enum mysql_option option, + const void *arg); void mysql_free_result(MYSQL_RES *result); void mysql_data_seek(MYSQL_RES *result, my_ulonglong offset); diff --git a/include/sql_common.h b/include/sql_common.h index f99df2a74ecf..6d7545bb954e 100644 --- a/include/sql_common.h +++ b/include/sql_common.h @@ -67,6 +67,8 @@ struct st_mysql_options_extention { char *server_public_key_path; size_t connection_attributes_length; my_bool enable_cleartext_plugin; + /** false if it is possible to fall back on unencrypted connections */ + my_bool ssl_enforce; }; typedef struct st_mysql_methods diff --git a/include/sslopt-case.h b/include/sslopt-case.h index 25817587aacf..fe2c42dd099d 100644 --- a/include/sslopt-case.h +++ b/include/sslopt-case.h @@ -17,6 +17,17 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #if defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY) +#ifdef MYSQL_CLIENT + case OPT_SSL_SSL: + /* + A client side --ssl option handling. + --ssl=1 means enforce (use=1, enforce=1) + --ssl=0 means can't enforce (use=0, enforce=0) + no --ssl means default : no enforce (use=1), just try (enforce=1) + */ + opt_ssl_enforce= opt_use_ssl; + break; +#endif case OPT_SSL_KEY: case OPT_SSL_CERT: case OPT_SSL_CA: @@ -28,7 +39,7 @@ Enable use of SSL if we are using any ssl option One can disable SSL later by using --skip-ssl or --ssl=0 */ - opt_use_ssl= 1; + opt_use_ssl= TRUE; /* crl has no effect in yaSSL */ #ifdef HAVE_YASSL opt_ssl_crl= NULL; diff --git a/include/sslopt-longopts.h b/include/sslopt-longopts.h index 8280f3b8f109..f295eea826c2 100644 --- a/include/sslopt-longopts.h +++ b/include/sslopt-longopts.h @@ -19,30 +19,32 @@ #if defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY) {"ssl", OPT_SSL_SSL, - "Enable SSL for connection (automatically enabled with other flags).", + "If set to ON, this option enforces that SSL is established before client " + "attempts to authenticate to the server. To disable client SSL capabilities " + "use --ssl=OFF.", &opt_use_ssl, &opt_use_ssl, 0, GET_BOOL, OPT_ARG, 0, 0, 0, 0, 0, 0}, {"ssl-ca", OPT_SSL_CA, - "CA file in PEM format (check OpenSSL docs, implies --ssl).", + "CA file in PEM format.", &opt_ssl_ca, &opt_ssl_ca, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"ssl-capath", OPT_SSL_CAPATH, - "CA directory (check OpenSSL docs, implies --ssl).", + "CA directory.", &opt_ssl_capath, &opt_ssl_capath, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, - {"ssl-cert", OPT_SSL_CERT, "X509 cert in PEM format (implies --ssl).", + {"ssl-cert", OPT_SSL_CERT, "X509 cert in PEM format.", &opt_ssl_cert, &opt_ssl_cert, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, - {"ssl-cipher", OPT_SSL_CIPHER, "SSL cipher to use (implies --ssl).", + {"ssl-cipher", OPT_SSL_CIPHER, "SSL cipher to use.", &opt_ssl_cipher, &opt_ssl_cipher, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, - {"ssl-key", OPT_SSL_KEY, "X509 key in PEM format (implies --ssl).", + {"ssl-key", OPT_SSL_KEY, "X509 key in PEM format.", &opt_ssl_key, &opt_ssl_key, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, - {"ssl-crl", OPT_SSL_CRL, "Certificate revocation list (implies --ssl).", + {"ssl-crl", OPT_SSL_CRL, "Certificate revocation list.", &opt_ssl_crl, &opt_ssl_crl, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"ssl-crlpath", OPT_SSL_CRLPATH, - "Certificate revocation list path (implies --ssl).", + "Certificate revocation list path.", &opt_ssl_crlpath, &opt_ssl_crlpath, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, #ifdef MYSQL_CLIENT diff --git a/include/sslopt-vars.h b/include/sslopt-vars.h index 05a5f507a3f2..43900a4c3d8e 100644 --- a/include/sslopt-vars.h +++ b/include/sslopt-vars.h @@ -17,7 +17,10 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #if defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY) -static my_bool opt_use_ssl = 0; +/* Always try to use SSL per default */ +static my_bool opt_use_ssl = TRUE; +/* Fall back on unencrypted connections per default */ +static my_bool opt_ssl_enforce= FALSE; static char *opt_ssl_ca = 0; static char *opt_ssl_capath = 0; static char *opt_ssl_cert = 0; @@ -25,8 +28,23 @@ static char *opt_ssl_cipher = 0; static char *opt_ssl_key = 0; static char *opt_ssl_crl = 0; static char *opt_ssl_crlpath = 0; -#ifdef MYSQL_CLIENT -static my_bool opt_ssl_verify_server_cert= 0; +#ifndef MYSQL_CLIENT +#error This header is supposed to be used only in the client #endif +#define SSL_SET_OPTIONS(mysql) \ + if (opt_use_ssl) \ + { \ + mysql_ssl_set(mysql, opt_ssl_key, opt_ssl_cert, opt_ssl_ca, \ + opt_ssl_capath, opt_ssl_cipher); \ + mysql_options(mysql, MYSQL_OPT_SSL_CRL, opt_ssl_crl); \ + mysql_options(mysql, MYSQL_OPT_SSL_CRLPATH, opt_ssl_crlpath); \ + mysql_options(mysql, MYSQL_OPT_SSL_ENFORCE, &opt_ssl_enforce); \ + } \ + mysql_options(mysql, MYSQL_OPT_SSL_VERIFY_SERVER_CERT, \ + (char*)&opt_ssl_verify_server_cert) + +static my_bool opt_ssl_verify_server_cert= 0; +#else +#define SSL_SET_OPTIONS(mysql) do { } while(0) #endif #endif /* SSLOPT_VARS_INCLUDED */ diff --git a/mysql-test/r/mysql_ssl.result b/mysql-test/r/mysql_ssl.result new file mode 100644 index 000000000000..4b87cc213565 --- /dev/null +++ b/mysql-test/r/mysql_ssl.result @@ -0,0 +1,5 @@ +# +# WL#6791 Redefine client --ssl option to imply enforced encryption +# +# verify that --ssl makes SSL required against a no-ssl server +End of 5.7 tests diff --git a/mysql-test/r/plugin_auth_sha256_server_default_tls.result b/mysql-test/r/plugin_auth_sha256_server_default_tls.result index 76ec29a1f69c..b14692fe16ff 100644 --- a/mysql-test/r/plugin_auth_sha256_server_default_tls.result +++ b/mysql-test/r/plugin_auth_sha256_server_default_tls.result @@ -27,11 +27,8 @@ SELECT USER(),CURRENT_USER(); USER() CURRENT_USER() kristofer2@localhost kristofer2@localhost **** Client default_auth=sha_256_password and server default auth=sha256_password -#### Test is disabled because it requires RSA-keys and this only works -#### with OpenSSL. The reason is that the current client library -#### framework can't know if SSL was attempted or not when the default -#### client auth is switched and hence it will only report that the -#### connection is unencrypted. +user() current_user() +kristofer@localhost kristofer@localhost **** Client default_auth=native and server default auth=sha256_password user() current_user() kristofer@localhost kristofer@localhost diff --git a/mysql-test/r/ssl_cipher.result b/mysql-test/r/ssl_cipher.result index 78081300b5b6..fb90fd4a4cac 100644 --- a/mysql-test/r/ssl_cipher.result +++ b/mysql-test/r/ssl_cipher.result @@ -1,9 +1,9 @@ # # BUG#11760210 - SSL_CIPHER_LIST NOT SET OR RETURNED FOR "SHOW STATUS LIKE 'SSL_CIPHER_LIST'" # -SHOW STATUS LIKE 'Ssl_cipher'; +# must return AES128-SHA Variable_name Value Ssl_cipher AES128-SHA -SHOW STATUS LIKE 'Ssl_cipher_list'; Variable_name Value Ssl_cipher_list AES128-SHA +# must fail since the default SSL cipher is not compatible diff --git a/mysql-test/t/mysql_ssl-master.opt b/mysql-test/t/mysql_ssl-master.opt new file mode 100644 index 000000000000..0ca403efdfb8 --- /dev/null +++ b/mysql-test/t/mysql_ssl-master.opt @@ -0,0 +1 @@ +--skip-ssl diff --git a/mysql-test/t/mysql_ssl.test b/mysql-test/t/mysql_ssl.test new file mode 100644 index 000000000000..dec815325a08 --- /dev/null +++ b/mysql-test/t/mysql_ssl.test @@ -0,0 +1,26 @@ +#Want to skip this test from daily Valgrind execution +--source include/no_valgrind_without_big.inc + +# This test should work in embedded server after we fix mysqltest +-- source include/not_embedded.inc + +# Save the initial number of concurrent sessions +--source include/count_sessions.inc + +--echo # +--echo # WL#6791 Redefine client --ssl option to imply enforced encryption +--echo # + +--echo # verify that --ssl makes SSL required against a no-ssl server +--error 1 +--exec $MYSQL --ssl -e "SHOW STATUS like 'Ssl_cipher'" + + +--echo End of 5.7 tests + + +# Wait till all disconnects are completed +--source include/wait_until_count_sessions.inc + +## This test file is for testing encrypted communication only, not other +## encryption routines that the SSL library happens to provide! diff --git a/mysql-test/t/plugin_auth_sha256_server_default_tls.test b/mysql-test/t/plugin_auth_sha256_server_default_tls.test index a23c97ae0dcd..7b0c7cf50044 100644 --- a/mysql-test/t/plugin_auth_sha256_server_default_tls.test +++ b/mysql-test/t/plugin_auth_sha256_server_default_tls.test @@ -36,12 +36,15 @@ SELECT USER(),CURRENT_USER(); connection default; disconnect con2; --echo **** Client default_auth=sha_256_password and server default auth=sha256_password ---echo #### Test is disabled because it requires RSA-keys and this only works ---echo #### with OpenSSL. The reason is that the current client library ---echo #### framework can't know if SSL was attempted or not when the default ---echo #### client auth is switched and hence it will only report that the ---echo #### connection is unencrypted. -# --exec xterm -e gdb --args $MYSQL -ukristofer -psecret2 --default_auth=sha256_password --ssl-ca=$MYSQL_TEST_DIR/std_data/cacert.pem --ssl-key=$MYSQL_TEST_DIR/std_data/client-key.pem --ssl-cert=$MYSQL_TEST_DIR/std_data/client-cert.pem -e "select user(), current_user()" +# Why using sha256_password requires --ssl=1 ? +# The current client library can't know if SSL was attempted or not +# when the default client auth is switched and hence it will only report +# that the connection is unencrypted forcing the client to ask for RSA keys. +# However, it is possible to inform the client library to enforce SSL using +# MYSQL_OPT_ENFORCE_SSL (or --ssl=1) and this will be enough for the +# sha256_password plugin to safely assume a secure connection despite it hasn't +# really been established yet. +--exec $MYSQL -ukristofer -psecret2 --default_auth=sha256_password --ssl-ca=$MYSQL_TEST_DIR/std_data/cacert.pem --ssl-key=$MYSQL_TEST_DIR/std_data/client-key.pem --ssl-cert=$MYSQL_TEST_DIR/std_data/client-cert.pem --ssl -e "select user(), current_user()" --echo **** Client default_auth=native and server default auth=sha256_password --exec $MYSQL -ukristofer -psecret2 --default_auth=mysql_native_password --ssl-ca=$MYSQL_TEST_DIR/std_data/cacert.pem --ssl-key=$MYSQL_TEST_DIR/std_data/client-key.pem --ssl-cert=$MYSQL_TEST_DIR/std_data/client-cert.pem -e "select user(), current_user()" diff --git a/mysql-test/t/ssl_cipher.test b/mysql-test/t/ssl_cipher.test index 5b54703a5279..7a6f1999bfcb 100644 --- a/mysql-test/t/ssl_cipher.test +++ b/mysql-test/t/ssl_cipher.test @@ -3,6 +3,8 @@ #but needs to be kept for tests that would need MyISAM in future. --source include/force_myisam_default.inc +--source include/not_embedded.inc + # Turn on ssl between the client and server # and run a number of tests @@ -15,14 +17,14 @@ # Save the initial number of concurrent sessions --source include/count_sessions.inc -connect (ssl_con,localhost,root,,,,,SSL); +--echo # must return AES128-SHA +# need to use mysql since mysqltest doesn't support --ssl-cipher +--exec $MYSQL --host=localhost -e "SHOW STATUS LIKE 'Ssl_cipher'; SHOW STATUS LIKE 'Ssl_cipher_list'" --ssl --ssl-cipher=AES128-SHA -# Check Cipher Name and Cipher List -SHOW STATUS LIKE 'Ssl_cipher'; -SHOW STATUS LIKE 'Ssl_cipher_list'; -connection default; -disconnect ssl_con; +--echo # must fail since the default SSL cipher is not compatible +--error 1 +--exec $MYSQL --host=localhost -e "SHOW STATUS LIKE 'Ssl_cipher'; SHOW STATUS LIKE 'Ssl_cipher_list'" --ssl # Wait till all disconnects are completed --source include/wait_until_count_sessions.inc diff --git a/sql-common/client.c b/sql-common/client.c index 0ce55c65a29c..d72ff199911c 100644 --- a/sql-common/client.c +++ b/sql-common/client.c @@ -145,6 +145,7 @@ void init_client_psi_keys(void) #endif /* HAVE_PSI_INTERFACE */ +const char *default_ssl_cipher= "DHE-RSA-AES256-SHA"; uint mysql_port=0; char *mysql_unix_port= 0; const char *unknown_sqlstate= "HY000"; @@ -1248,19 +1249,28 @@ static int add_init_command(struct st_mysql_options *options, const char *cmd) (STR), MYF(MY_WME)) : NULL; \ } while (0) -#if defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY) -#define SET_SSL_OPTION(opt_var,arg) \ +#define SET_OPTION(opt_var,arg) \ + do { \ if (mysql->options.opt_var) \ my_free(mysql->options.opt_var); \ - mysql->options.opt_var= arg ? my_strdup(key_memory_mysql_options, arg, MYF(MY_WME)) : NULL; \ + mysql->options.opt_var = arg ? my_strdup(key_memory_mysql_options, arg, MYF(MY_WME)) : NULL; \ + } while (0) + + +#if defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY) +#define SET_SSL_OPTION(opt_var,arg) \ + do { \ + SET_OPTION(opt_var, arg); \ if (mysql->options.opt_var) \ - mysql->options.use_ssl= 1 + mysql->options.use_ssl = TRUE; \ + } while (0) + #define EXTENSION_SET_SSL_STRING(OPTS, X, STR) \ + do { \ EXTENSION_SET_STRING(OPTS, X, STR); \ if ((OPTS)->extension->X) \ - (OPTS)->use_ssl= 1 - - + (OPTS)->use_ssl = TRUE; \ + } while (0) #else #define SET_SSL_OPTION(opt_var,arg) \ do { \ @@ -2808,14 +2818,16 @@ static int send_client_reply_packet(MCPVIO_EXT *mpvio, mysql->client_flag|= CLIENT_MULTI_RESULTS; #if defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY) + /* consider SSL if any of the SSL mysql_options() is issued */ if (mysql->options.ssl_key || mysql->options.ssl_cert || mysql->options.ssl_ca || mysql->options.ssl_capath || mysql->options.ssl_cipher || - (mysql->options.extension && mysql->options.extension->ssl_crl) || - (mysql->options.extension && mysql->options.extension->ssl_crlpath)) - mysql->options.use_ssl= 1; + (mysql->options.extension && mysql->options.extension->ssl_crl) || + (mysql->options.extension && mysql->options.extension->ssl_crlpath) || + (mysql->options.extension && mysql->options.extension->ssl_enforce)) + mysql->options.use_ssl = TRUE; if (mysql->options.use_ssl) - mysql->client_flag|= CLIENT_SSL; + mysql->client_flag |= CLIENT_SSL; #endif /* HAVE_OPENSSL && !EMBEDDED_LIBRARY*/ if (mpvio->db) mysql->client_flag|= CLIENT_CONNECT_WITH_DB; @@ -2847,7 +2859,37 @@ static int send_client_reply_packet(MCPVIO_EXT *mpvio, end= buff+5; } #ifdef HAVE_OPENSSL - if (mysql->client_flag & CLIENT_SSL) + + if (mysql->options.extension && mysql->options.extension->ssl_enforce) + { + /* + ssl_enforce=1 means enforce ssl + Don't fallback on unencrypted connection. + */ + /* can't turn enforce on without turning on use_ssl too */ + DBUG_ASSERT(mysql->options.use_ssl); + /* enforce=true takes precendence over use=false */ + if (!(mysql->server_capabilities & CLIENT_SSL)) + { + set_mysql_extended_error(mysql, CR_SSL_CONNECTION_ERROR, unknown_sqlstate, + ER(CR_SSL_CONNECTION_ERROR), + "SSL is required but the server doesn't " + "support it" + ); + goto error; + } + } + + /* + + use_ssl=0 => Disable ssl and connect using unencrypted channel if server + allows it + + use_ssl=1, ssl_enforce=0 (default) => attempt ssl connection if possible but + fallback on unencrypted connection if possible. + + */ + if ((mysql->server_capabilities & CLIENT_SSL) && mysql->options.use_ssl) { /* Do the SSL layering. */ struct st_mysql_options *options= &mysql->options; @@ -2856,6 +2898,11 @@ static int send_client_reply_packet(MCPVIO_EXT *mpvio, const char *cert_error; unsigned long ssl_error; + if (!mysql->options.ssl_cipher) + { + SET_OPTION(ssl_cipher, default_ssl_cipher); + } + /* Send mysql->client_flag, max_packet_size - unencrypted otherwise the server does not know we want to do SSL @@ -2918,6 +2965,7 @@ static int send_client_reply_packet(MCPVIO_EXT *mpvio, MYSQL_TRACE(SSL_CONNECTED, mysql, ()); MYSQL_TRACE_STAGE(mysql, AUTHENTICATE); } + #endif /* HAVE_OPENSSL */ DBUG_PRINT("info",("Server version = '%s' capabilites: %lu status: %u client_flag: %lu", @@ -4728,6 +4776,11 @@ mysql_options(MYSQL *mysql,enum mysql_option option, const void *arg) case MYSQL_OPT_SSL_CRLPATH: EXTENSION_SET_SSL_STRING(&mysql->options, ssl_crlpath, arg); break; + case MYSQL_OPT_SSL_ENFORCE: ENSURE_EXTENSIONS_PRESENT(&mysql->options); + mysql->options.extension->ssl_enforce= + (*(my_bool *) arg) ? TRUE : FALSE; + mysql->options.use_ssl= TRUE; + break; case MYSQL_SERVER_PUBLIC_KEY: EXTENSION_SET_STRING(&mysql->options, server_public_key_path, arg); break; @@ -4788,6 +4841,187 @@ mysql_options(MYSQL *mysql,enum mysql_option option, const void *arg) } +/** + Return the current values for the options settable through mysql_options() + + Returns the current values for all of the connection options. + Callers should not manipulate the returned data ! + Data are valid at the time of returning them until the next C API CALL + arg should always be a pointer to a variable of the appropriate type. + type of variable, based on the parameter: + + uint + MYSQL_OPT_CONNECT_TIMEOUT, MYSQL_OPT_READ_TIMEOUT, MYSQL_OPT_WRITE_TIMEOUT, + MYSQL_OPT_PROTOCOL + + my_bool + MYSQL_OPT_COMPRESS, MYSQL_OPT_LOCAL_INFILE, MYSQL_OPT_USE_REMOTE_CONNECTION, + MYSQL_OPT_USE_EMBEDDED_CONNECTION, MYSQL_OPT_GUESS_CONNECTION, + MYSQL_SECURE_AUTH, MYSQL_REPORT_DATA_TRUNCATION, MYSQL_OPT_RECONNECT, + MYSQL_OPT_SSL_VERIFY_SERVER_CERT, MYSQL_OPT_SSL_ENFORCE, + MYSQL_ENABLE_CLEARTEXT_PLUGIN, MYSQL_OPT_CAN_HANDLE_EXPIRED_PASSWORDS + + const char * + MYSQL_READ_DEFAULT_FILE, MYSQL_READ_DEFAULT_GROUP, + MYSQL_SET_CHARSET_DIR, MYSQL_SET_CHARSET_NAME, MYSQL_SHARED_MEMORY_BASE_NAME, + MYSQL_SET_CLIENT_IP, MYSQL_OPT_BIND, MYSQL_PLUGIN_DIR, MYSQL_DEFAULT_AUTH, + MYSQL_OPT_SSL_KEY, MYSQL_OPT_SSL_CERT, MYSQL_OPT_SSL_CA, MYSQL_OPT_SSL_CAPATH, + MYSQL_OPT_SSL_CIPHER, MYSQL_OPT_SSL_CRL, MYSQL_OPT_SSL_CRLPATH, + MYSQL_SERVER_PUBLIC_KEY + + + MYSQL_OPT_NAMED_PIPE, MYSQL_OPT_CONNECT_ATTR_RESET, + MYSQL_OPT_CONNECT_ATTR_DELETE, MYSQL_INIT_COMMAND + + @param mysql The MYSQL connection to operate on + @param option The option to return the value for + @param out arg Must be non-null. Receives the current value. + @return status + @retval 0 SUCCESS +*/ + +int STDCALL +mysql_get_option(MYSQL *mysql, enum mysql_option option, const void *arg) +{ + DBUG_ENTER("mysql_option"); + DBUG_PRINT("enter", ("option: %d", (int)option)); + + if (!arg) + DBUG_RETURN(1); + + switch (option) { + case MYSQL_OPT_CONNECT_TIMEOUT: + *((uint *)arg) = mysql->options.connect_timeout; + break; + case MYSQL_OPT_READ_TIMEOUT: + *((uint *)arg)= mysql->options.read_timeout; + break; + case MYSQL_OPT_WRITE_TIMEOUT: + *((uint *)arg)= mysql->options.write_timeout; + break; + case MYSQL_OPT_COMPRESS: + *((my_bool *)arg) = mysql->options.compress ? TRUE : FALSE; + break; + case MYSQL_OPT_LOCAL_INFILE: /* Allow LOAD DATA LOCAL ?*/ + *((uint *)arg)= (mysql->options.client_flag & CLIENT_LOCAL_FILES) ? + TRUE : FALSE; + break; + case MYSQL_READ_DEFAULT_FILE: + *((char **)arg)= mysql->options.my_cnf_file; + break; + case MYSQL_READ_DEFAULT_GROUP: + *((char **)arg)= mysql->options.my_cnf_group; + break; + case MYSQL_SET_CHARSET_DIR: + *((char **)arg)= mysql->options.charset_dir; + break; + case MYSQL_SET_CHARSET_NAME: + *((char **)arg)= mysql->options.charset_name; + break; + case MYSQL_OPT_PROTOCOL: + *((uint *)arg)= mysql->options.protocol; + break; + case MYSQL_SHARED_MEMORY_BASE_NAME: +#if defined (_WIN32) && !defined (EMBEDDED_LIBRARY) + *((char **)arg)= mysql->options.shared_memory_base_name; +#else + *((const char **)arg)= ""; +#endif + break; + case MYSQL_OPT_USE_REMOTE_CONNECTION: + *((my_bool *)arg)= + (mysql->options.methods_to_use == MYSQL_OPT_USE_REMOTE_CONNECTION) ? + TRUE : FALSE; + break; + case MYSQL_OPT_USE_EMBEDDED_CONNECTION: + *((my_bool *)arg) = + (mysql->options.methods_to_use == MYSQL_OPT_USE_EMBEDDED_CONNECTION) ? + TRUE : FALSE; + break; + case MYSQL_OPT_GUESS_CONNECTION: + *((my_bool *)arg) = + (mysql->options.methods_to_use == MYSQL_OPT_GUESS_CONNECTION) ? + TRUE : FALSE; + break; + case MYSQL_SET_CLIENT_IP: + *((char **)arg) = mysql->options.ci.client_ip; + break; + case MYSQL_SECURE_AUTH: + *((my_bool *)arg)= mysql->options.secure_auth; + break; + case MYSQL_REPORT_DATA_TRUNCATION: + *((my_bool *)arg)= mysql->options.report_data_truncation; + break; + case MYSQL_OPT_RECONNECT: + *((my_bool *)arg)= mysql->reconnect; + break; + case MYSQL_OPT_BIND: + *((char **)arg)= mysql->options.ci.bind_address; + break; + case MYSQL_OPT_SSL_VERIFY_SERVER_CERT: + *((my_bool *)arg) = (mysql->options.client_flag & + CLIENT_SSL_VERIFY_SERVER_CERT) ? TRUE : FALSE; + break; + case MYSQL_PLUGIN_DIR: + *((char **)arg)= mysql->options.extension ? + mysql->options.extension->plugin_dir : NULL; + break; + case MYSQL_DEFAULT_AUTH: + *((char **)arg)= mysql->options.extension ? + mysql->options.extension->default_auth : NULL; + break; + case MYSQL_OPT_SSL_KEY: + *((char **)arg)= mysql->options.ssl_key; + break; + case MYSQL_OPT_SSL_CERT: + *((char **)arg)= mysql->options.ssl_cert; + break; + case MYSQL_OPT_SSL_CA: + *((char **)arg)= mysql->options.ssl_ca; + break; + case MYSQL_OPT_SSL_CAPATH: + *((char **)arg)= mysql->options.ssl_capath; + break; + case MYSQL_OPT_SSL_CIPHER: + *((char **)arg)= mysql->options.ssl_cipher; + break; + case MYSQL_OPT_SSL_CRL: + *((char **)arg)= mysql->options.extension ? + mysql->options.extension->ssl_crl : NULL; + break; + case MYSQL_OPT_SSL_CRLPATH: + *((char **)arg)= mysql->options.extension ? + mysql->options.extension->ssl_crlpath : NULL; + break; + case MYSQL_OPT_SSL_ENFORCE: + *((my_bool *)arg)= (mysql->options.extension && + mysql->options.extension->ssl_enforce) ? TRUE : FALSE; + break; + case MYSQL_SERVER_PUBLIC_KEY: + *((char **)arg)= mysql->options.extension ? + mysql->options.extension->server_public_key_path : NULL; + break; + case MYSQL_ENABLE_CLEARTEXT_PLUGIN: + *((my_bool *)arg)= (mysql->options.extension && + mysql->options.extension->enable_cleartext_plugin) ? + TRUE : FALSE; + break; + case MYSQL_OPT_CAN_HANDLE_EXPIRED_PASSWORDS: + *((my_bool*)arg)= (mysql->options.client_flag & + CLIENT_CAN_HANDLE_EXPIRED_PASSWORDS) ? TRUE : FALSE; + break; + + case MYSQL_OPT_NAMED_PIPE: /* This option is depricated */ + case MYSQL_INIT_COMMAND: /* Cumulative */ + case MYSQL_OPT_CONNECT_ATTR_RESET: /* Cumulative */ + case MYSQL_OPT_CONNECT_ATTR_DELETE: /* Cumulative */ + default: + DBUG_RETURN(1); + } + DBUG_RETURN(0); +} + + /** A function to return the key from a connection attribute */ diff --git a/sql-common/client_authentication.cc b/sql-common/client_authentication.cc index 8a691078890a..2bd27c46f8d0 100644 --- a/sql-common/client_authentication.cc +++ b/sql-common/client_authentication.cc @@ -145,6 +145,7 @@ int sha256_password_auth_client(MYSQL_PLUGIN_VIO *vio, MYSQL *mysql) bool connection_is_secure= false; unsigned char scramble_pkt[20]; unsigned char *pkt; + my_bool ssl_enforce= FALSE; DBUG_ENTER("sha256_password_auth_client"); @@ -164,9 +165,26 @@ int sha256_password_auth_client(MYSQL_PLUGIN_VIO *vio, MYSQL *mysql) */ memcpy(scramble_pkt, pkt, SCRAMBLE_LENGTH); + if (mysql_get_option(mysql, MYSQL_OPT_SSL_ENFORCE, &ssl_enforce)) + ssl_enforce= FALSE; + if (mysql_get_ssl_cipher(mysql) != NULL) connection_is_secure= true; - + /* + If set to the default plugin, then the client and server haven't + attempted a SSL connection yet and there is no way of knowing if this will + be successful later on when encryption is needed. + + The only way to be sure that SSL will be established is to check if the + client enforce SSL. + + If MYSQL_OPT_ENFORCE_SSL flag isn't set then SSL might be established but + the client will still expect RSA keys from the server and fail if those + aren't available. + */ + else if (ssl_enforce) + connection_is_secure= true; // Safely assume connection will be encrypted + /* If connection isn't secure attempt to get the RSA public key file */ if (!connection_is_secure) { diff --git a/sql/rpl_slave.cc b/sql/rpl_slave.cc index b0c904ad7a0a..c8fbbdbfad6c 100644 --- a/sql/rpl_slave.cc +++ b/sql/rpl_slave.cc @@ -6966,18 +6966,21 @@ static int connect_to_master(THD* thd, MYSQL* mysql, Master_info* mi, #ifdef HAVE_OPENSSL if (mi->ssl) { + const static my_bool ssl_enforce_true= TRUE; mysql_ssl_set(mysql, mi->ssl_key[0]?mi->ssl_key:0, mi->ssl_cert[0]?mi->ssl_cert:0, mi->ssl_ca[0]?mi->ssl_ca:0, mi->ssl_capath[0]?mi->ssl_capath:0, mi->ssl_cipher[0]?mi->ssl_cipher:0); - mysql_options(mysql, MYSQL_OPT_SSL_CRL, + mysql_options(mysql, MYSQL_OPT_SSL_CRL, mi->ssl_crl[0] ? mi->ssl_crl : 0); - mysql_options(mysql, MYSQL_OPT_SSL_CRLPATH, + mysql_options(mysql, MYSQL_OPT_SSL_CRLPATH, mi->ssl_crlpath[0] ? mi->ssl_crlpath : 0); mysql_options(mysql, MYSQL_OPT_SSL_VERIFY_SERVER_CERT, &mi->ssl_verify_server_cert); + /* we always enforce SSL if SSL is turned on */ + mysql_options(mysql, MYSQL_OPT_SSL_ENFORCE, &ssl_enforce_true); } #endif diff --git a/tests/mysql_client_test.c b/tests/mysql_client_test.c index 677bb140a2c8..f05939e671a7 100644 --- a/tests/mysql_client_test.c +++ b/tests/mysql_client_test.c @@ -19514,6 +19514,114 @@ static void test_wl6797() mysql_stmt_close(stmt); } + +static void test_wl6791() +{ + int rc; + uint idx; + MYSQL *l_mysql; + enum mysql_option + uint_opts[] = { + MYSQL_OPT_CONNECT_TIMEOUT, MYSQL_OPT_READ_TIMEOUT, MYSQL_OPT_WRITE_TIMEOUT, + MYSQL_OPT_PROTOCOL, MYSQL_OPT_LOCAL_INFILE + }, + my_bool_opts[] = { + MYSQL_OPT_COMPRESS, MYSQL_OPT_USE_REMOTE_CONNECTION, + MYSQL_OPT_USE_EMBEDDED_CONNECTION, MYSQL_OPT_GUESS_CONNECTION, + MYSQL_SECURE_AUTH, MYSQL_REPORT_DATA_TRUNCATION, MYSQL_OPT_RECONNECT, + MYSQL_OPT_SSL_VERIFY_SERVER_CERT, MYSQL_OPT_SSL_ENFORCE, + MYSQL_ENABLE_CLEARTEXT_PLUGIN, MYSQL_OPT_CAN_HANDLE_EXPIRED_PASSWORDS + }, + const_char_opts[] = { + MYSQL_READ_DEFAULT_FILE, MYSQL_READ_DEFAULT_GROUP, + MYSQL_SET_CHARSET_DIR, MYSQL_SET_CHARSET_NAME, +#if defined (_WIN32) && !defined (EMBEDDED_LIBRARY) + /* mysql_options() is a no-op on non-supporting platforms. */ + MYSQL_SHARED_MEMORY_BASE_NAME, +#endif + MYSQL_SET_CLIENT_IP, MYSQL_OPT_BIND, MYSQL_PLUGIN_DIR, MYSQL_DEFAULT_AUTH, + MYSQL_OPT_SSL_KEY, MYSQL_OPT_SSL_CERT, MYSQL_OPT_SSL_CA, MYSQL_OPT_SSL_CAPATH, + MYSQL_OPT_SSL_CIPHER, MYSQL_OPT_SSL_CRL, MYSQL_OPT_SSL_CRLPATH, + MYSQL_SERVER_PUBLIC_KEY + }, + err_opts[] = { + MYSQL_OPT_NAMED_PIPE, MYSQL_OPT_CONNECT_ATTR_RESET, + MYSQL_OPT_CONNECT_ATTR_DELETE, MYSQL_INIT_COMMAND + }; + + myheader("test_wl6791"); + + /* prepare the connection */ + l_mysql = mysql_client_init(NULL); + DIE_UNLESS(l_mysql != NULL); + + for (idx= 0; idx < sizeof(uint_opts) / sizeof(enum mysql_option); idx++) + { + uint opt_before= 1, opt_after= 0; + + if (!opt_silent) + fprintf(stdout, "testing uint option #%d (%d)\n", idx, + (int) uint_opts[idx]); + rc= mysql_options(l_mysql, uint_opts[idx], &opt_before); + DIE_UNLESS(rc == 0); + + rc = mysql_get_option(l_mysql, uint_opts[idx], &opt_after); + DIE_UNLESS(rc == 0); + + DIE_UNLESS(opt_before == opt_after); + } + + for (idx= 0; idx < sizeof(my_bool_opts) / sizeof(enum mysql_option); idx++) + { + my_bool opt_before = TRUE, opt_after = FALSE; + + if (!opt_silent) + fprintf(stdout, "testing my_bool option #%d (%d)\n", idx, + (int)my_bool_opts[idx]); + + rc = mysql_options(l_mysql, my_bool_opts[idx], &opt_before); + DIE_UNLESS(rc == 0); + + rc = mysql_get_option(l_mysql, my_bool_opts[idx], &opt_after); + DIE_UNLESS(rc == 0); + + DIE_UNLESS(opt_before == opt_after); + } + + for (idx= 0; idx < sizeof(const_char_opts) / sizeof(enum mysql_option); idx++) + { + const char *opt_before = "TEST", *opt_after = NULL; + + if (!opt_silent) + fprintf(stdout, "testing const char * option #%d (%d)\n", idx, + (int)const_char_opts[idx]); + + rc = mysql_options(l_mysql, const_char_opts[idx], opt_before); + DIE_UNLESS(rc == 0); + + rc = mysql_get_option(l_mysql, const_char_opts[idx], &opt_after); + DIE_UNLESS(rc == 0); + + DIE_UNLESS(opt_before && opt_after && + 0 == strcmp(opt_before, opt_after)); + } + + for (idx= 0; idx < sizeof(err_opts) / sizeof(enum mysql_option); idx++) + { + void *dummy_arg; + if (!opt_silent) + fprintf(stdout, "testing invalid option #%d (%d)\n", idx, + (int)err_opts[idx]); + + rc = mysql_get_option(l_mysql, err_opts[idx], &dummy_arg); + DIE_UNLESS(rc != 0); + } + + /* clean up */ + mysql_close(l_mysql); +} + + static struct my_tests_st my_tests[]= { { "disable_query_logs", disable_query_logs }, { "test_view_sp_list_fields", test_view_sp_list_fields }, @@ -19785,6 +19893,7 @@ static struct my_tests_st my_tests[]= { { "test_wl6587", test_wl6587 }, { "test_wl5928", test_wl5928 }, { "test_wl6797", test_wl6797 }, + { "test_wl6791", test_wl6791 }, { 0, 0 } };