diff --git a/client/mysqltest.cc b/client/mysqltest.cc index 15e8ed55fb53..dbf6fa416e70 100644 --- a/client/mysqltest.cc +++ b/client/mysqltest.cc @@ -86,6 +86,7 @@ #include "my_dir.h" #include "my_inttypes.h" #include "my_macros.h" +#include "my_openssl_fips.h" #include "my_pointer_arithmetic.h" #include "my_stacktrace.h" #include "my_systime.h" // my_sleep() diff --git a/cmake/ssl.cmake b/cmake/ssl.cmake index 4ca92a1f8e18..819b7020b9b3 100644 --- a/cmake/ssl.cmake +++ b/cmake/ssl.cmake @@ -65,6 +65,8 @@ # pkg-config --cflags openssl11 # -I/usr/include/openssl11 +SET(MIN_OPENSSL_VERSION_REQUIRED "1.0.0") + SET(WITH_SSL_DOC "\nsystem (use the OS openssl library)") SET(WITH_SSL_DOC "\nopenssl[0-9]+ (use alternative system library)") STRING_APPEND(WITH_SSL_DOC "\nyes (synonym for system)") @@ -108,28 +110,55 @@ MACRO(RESET_SSL_VARIABLES) UNSET(HAVE_SHA512_DIGEST_LENGTH CACHE) ENDMACRO(RESET_SSL_VARIABLES) +# Fetch OpenSSL version number. +# OpenSSL < 3: +# #define OPENSSL_VERSION_NUMBER 0x1000103fL +# Encoded as MNNFFPPS: major minor fix patch status +# +# OpenSSL 3: +# #define OPENSSL_VERSION_NUMBER +# ( (OPENSSL_VERSION_MAJOR<<28) +# |(OPENSSL_VERSION_MINOR<<20) +# |(OPENSSL_VERSION_PATCH<<4) +# |_OPENSSL_VERSION_PRE_RELEASE ) MACRO(FIND_OPENSSL_VERSION) - # Verify version number. Version information looks like: - # #define OPENSSL_VERSION_NUMBER 0x1000103fL - # Encoded as MNNFFPPS: major minor fix patch status - FILE(STRINGS "${OPENSSL_INCLUDE_DIR}/openssl/opensslv.h" - OPENSSL_VERSION_NUMBER - REGEX "^#[ ]*define[\t ]+OPENSSL_VERSION_NUMBER[\t ]+0x[0-9].*" - ) - STRING(REGEX REPLACE - "^.*OPENSSL_VERSION_NUMBER[\t ]+0x([0-9]).*$" "\\1" - OPENSSL_MAJOR_VERSION "${OPENSSL_VERSION_NUMBER}" - ) - STRING(REGEX REPLACE - "^.*OPENSSL_VERSION_NUMBER[\t ]+0x[0-9]([0-9][0-9]).*$" "\\1" - OPENSSL_MINOR_VERSION "${OPENSSL_VERSION_NUMBER}" - ) - STRING(REGEX REPLACE - "^.*OPENSSL_VERSION_NUMBER[\t ]+0x[0-9][0-9][0-9]([0-9][0-9]).*$" "\\1" - OPENSSL_FIX_VERSION "${OPENSSL_VERSION_NUMBER}" - ) - SET(OPENSSL_MAJOR_MINOR_FIX_VERSION "${OPENSSL_MAJOR_VERSION}") - STRING_APPEND(OPENSSL_MAJOR_MINOR_FIX_VERSION ".${OPENSSL_MINOR_VERSION}") + FOREACH(version_part + OPENSSL_VERSION_MAJOR + OPENSSL_VERSION_MINOR + OPENSSL_VERSION_PATCH + ) + FILE(STRINGS "${OPENSSL_INCLUDE_DIR}/openssl/opensslv.h" ${version_part} + REGEX "^#[\t ]*define[\t ]+${version_part}[\t ]+([0-9]+).*") + STRING(REGEX REPLACE + "^.*${version_part}[\t ]+([0-9]+).*" "\\1" + ${version_part} "${${version_part}}") + ENDFOREACH() + IF(OPENSSL_VERSION_MAJOR VERSION_EQUAL 3) + # OpenSSL 3 + SET(OPENSSL_FIX_VERSION "${OPENSSL_VERSION_PATCH}") + ELSE() + # Verify version number. Version information looks like: + # #define OPENSSL_VERSION_NUMBER 0x1000103fL + # Encoded as MNNFFPPS: major minor fix patch status + FILE(STRINGS "${OPENSSL_INCLUDE_DIR}/openssl/opensslv.h" + OPENSSL_VERSION_NUMBER + REGEX "^#[ ]*define[\t ]+OPENSSL_VERSION_NUMBER[\t ]+0x[0-9].*" + ) + STRING(REGEX REPLACE + "^.*OPENSSL_VERSION_NUMBER[\t ]+0x([0-9]).*$" "\\1" + OPENSSL_VERSION_MAJOR "${OPENSSL_VERSION_NUMBER}" + ) + STRING(REGEX REPLACE + "^.*OPENSSL_VERSION_NUMBER[\t ]+0x[0-9]([0-9][0-9]).*$" "\\1" + OPENSSL_VERSION_MINOR "${OPENSSL_VERSION_NUMBER}" + ) + STRING(REGEX REPLACE + "^.*OPENSSL_VERSION_NUMBER[\t ]+0x[0-9][0-9][0-9]([0-9][0-9]).*$" "\\1" + OPENSSL_FIX_VERSION "${OPENSSL_VERSION_NUMBER}" + ) + ENDIF() + SET(OPENSSL_MAJOR_MINOR_FIX_VERSION "${OPENSSL_VERSION_MAJOR}") + STRING_APPEND(OPENSSL_MAJOR_MINOR_FIX_VERSION ".${OPENSSL_VERSION_MINOR}") STRING_APPEND(OPENSSL_MAJOR_MINOR_FIX_VERSION ".${OPENSSL_FIX_VERSION}") MESSAGE(STATUS "OPENSSL_VERSION (${WITH_SSL}) is ${OPENSSL_MAJOR_MINOR_FIX_VERSION}") @@ -327,25 +356,37 @@ MACRO (MYSQL_CHECK_SSL) HINTS ${OPENSSL_ROOT_DIR}/include ) MESSAGE(STATUS "OPENSSL_APPLINK_C ${OPENSSL_APPLINK_C}") + IF(NOT OPENSSL_APPLINK_C) + RESET_SSL_VARIABLES() + FATAL_SSL_NOT_FOUND_ERROR( + "Cannot find applink.c for WITH_SSL=${WITH_SSL}.") + ENDIF() ENDIF() FIND_LIBRARY(OPENSSL_LIBRARY NAMES ssl libssl ssleay32 ssleay32MD - HINTS ${OPENSSL_ROOT_DIR}/lib) + HINTS ${OPENSSL_ROOT_DIR}/lib ${OPENSSL_ROOT_DIR}/lib64) FIND_LIBRARY(CRYPTO_LIBRARY NAMES crypto libcrypto libeay32 - HINTS ${OPENSSL_ROOT_DIR}/lib) + HINTS ${OPENSSL_ROOT_DIR}/lib ${OPENSSL_ROOT_DIR}/lib64) IF(OPENSSL_INCLUDE_DIR) FIND_OPENSSL_VERSION() ENDIF() + IF (OPENSSL_MAJOR_MINOR_FIX_VERSION VERSION_LESS + ${MIN_OPENSSL_VERSION_REQUIRED}) + RESET_SSL_VARIABLES() + FATAL_SSL_NOT_FOUND_ERROR( + "Not a supported openssl version in WITH_SSL=${WITH_SSL}.") + ENDIF() + IF("${OPENSSL_MAJOR_MINOR_FIX_VERSION}" VERSION_GREATER "1.1.0") ADD_DEFINITIONS(-DHAVE_TLSv13) ENDIF() + IF(OPENSSL_INCLUDE_DIR AND - OPENSSL_LIBRARY AND - CRYPTO_LIBRARY AND - OPENSSL_MAJOR_VERSION STREQUAL "1" + OPENSSL_LIBRARY AND + CRYPTO_LIBRARY ) SET(OPENSSL_FOUND TRUE) IF(WITH_SSL_PATH) @@ -412,8 +453,8 @@ MACRO (MYSQL_CHECK_SSL) MESSAGE(STATUS "OPENSSL_LIBRARY = ${OPENSSL_LIBRARY}") MESSAGE(STATUS "CRYPTO_LIBRARY = ${CRYPTO_LIBRARY}") MESSAGE(STATUS "OPENSSL_LIB_DIR = ${OPENSSL_LIB_DIR}") - MESSAGE(STATUS "OPENSSL_MAJOR_VERSION = ${OPENSSL_MAJOR_VERSION}") - MESSAGE(STATUS "OPENSSL_MINOR_VERSION = ${OPENSSL_MINOR_VERSION}") + MESSAGE(STATUS "OPENSSL_VERSION_MAJOR = ${OPENSSL_VERSION_MAJOR}") + MESSAGE(STATUS "OPENSSL_VERSION_MINOR = ${OPENSSL_VERSION_MINOR}") MESSAGE(STATUS "OPENSSL_FIX_VERSION = ${OPENSSL_FIX_VERSION}") INCLUDE(CheckSymbolExists) @@ -669,15 +710,21 @@ MACRO(MYSQL_CHECK_SSL_DLLS) GET_FILENAME_COMPONENT(OPENSSL_NAME "${OPENSSL_LIBRARY}" NAME_WE) # Different naming scheme for the matching .dll as of SSL 1.1 + # OpenSSL 3.x Look for libcrypto-3-x64.dll or libcrypto-3.dll + # OpenSSL 1.1 Look for libcrypto-1_1-x64.dll or libcrypto-1_1.dll + # OpenSSL 1.0 Look for libeay32.dll SET(SSL_MSVC_VERSION_SUFFIX) SET(SSL_MSVC_ARCH_SUFFIX) - IF(OPENSSL_MINOR_VERSION VERSION_EQUAL 1) + IF(OPENSSL_VERSION_MAJOR VERSION_EQUAL 1 AND + OPENSSL_VERSION_MINOR VERSION_EQUAL 1) SET(SSL_MSVC_VERSION_SUFFIX "-1_1") SET(SSL_MSVC_ARCH_SUFFIX "-x64") ENDIF() + IF(OPENSSL_VERSION_MAJOR VERSION_EQUAL 3) + SET(SSL_MSVC_VERSION_SUFFIX "-3") + SET(SSL_MSVC_ARCH_SUFFIX "-x64") + ENDIF() - # OpenSSL 1.1 Look for libcrypto-1_1-x64.dll or libcrypto-1_1.dll - # OpenSSL 1.0 Look for libeay32.dll FIND_FILE(HAVE_CRYPTO_DLL NAMES "${CRYPTO_NAME}${SSL_MSVC_VERSION_SUFFIX}${SSL_MSVC_ARCH_SUFFIX}.dll" @@ -717,7 +764,8 @@ MACRO(MYSQL_CHECK_SSL_DLLS) ADD_DEPENDENCIES(${openssl_exe_target} copy_openssl_dlls) ELSE() MESSAGE(STATUS "Cannot find SSL dynamic libraries") - IF(OPENSSL_MINOR_VERSION VERSION_EQUAL 1) + IF(OPENSSL_VERSION_MAJOR VERSION_EQUAL 1 AND + OPENSSL_VERSION_MINOR VERSION_EQUAL 1) SET(SSL_LIBRARIES ${SSL_LIBRARIES} crypt32.lib) MESSAGE(STATUS "SSL_LIBRARIES ${SSL_LIBRARIES}") ENDIF() @@ -725,3 +773,16 @@ MACRO(MYSQL_CHECK_SSL_DLLS) ENDIF() ENDIF() ENDMACRO() + +# Downgrade OpenSSL 3 deprecation warnings. +MACRO(DOWNGRADE_OPENSSL3_DEPRECATION_WARNINGS) + IF(OPENSSL_VERSION_MAJOR VERSION_EQUAL 3) + IF(MY_COMPILER_IS_GNU_OR_CLANG) + ADD_COMPILE_FLAGS(${ARGV} + COMPILE_FLAGS "-Wno-error=deprecated-declarations") + ELSEIF(WIN32) + ADD_COMPILE_FLAGS(${ARGV} + COMPILE_FLAGS "/wd4996") + ENDIF() + ENDIF() +ENDMACRO() diff --git a/extra/libfido2/libfido2-1.8.0/src/CMakeLists.txt b/extra/libfido2/libfido2-1.8.0/src/CMakeLists.txt index 73d4ee9ff86c..ef69decaf610 100644 --- a/extra/libfido2/libfido2-1.8.0/src/CMakeLists.txt +++ b/extra/libfido2/libfido2-1.8.0/src/CMakeLists.txt @@ -85,6 +85,52 @@ list(APPEND COMPAT_SOURCES ../openbsd-compat/timingsafe_bcmp.c ) +DOWNGRADE_OPENSSL3_DEPRECATION_WARNINGS( + assert.c + cbor.c + cred.c + es256.c + rs256.c + ecdh.c + ) + +IF(OPENSSL_VERSION_MAJOR VERSION_EQUAL 3) + IF(MY_COMPILER_IS_GNU) + # Downgrade to warning, for now. + ADD_COMPILE_FLAGS( + assert.c + cbor.c + cred.c + es256.c + rs256.c + COMPILE_FLAGS "-Wno-error=discarded-qualifiers") + ADD_COMPILE_FLAGS( + ecdh.c + COMPILE_FLAGS "-Wno-error=pointer-sign") + ELSEIF(MY_COMPILER_IS_CLANG) + # Downgrade to warning, for now. + ADD_COMPILE_FLAGS( + assert.c + cbor.c + cred.c + es256.c + rs256.c + COMPILE_FLAGS + "-Wno-incompatible-pointer-types-discards-qualifiers") + ADD_COMPILE_FLAGS( + ecdh.c + COMPILE_FLAGS "-Wno-pointer-sign") + ELSEIF(MSVC) + ADD_COMPILE_FLAGS( + assert.c + cred.c + COMPILE_FLAGS "/wd4090") + ADD_COMPILE_FLAGS( + ecdh.c + COMPILE_FLAGS "/wd4057") + ENDIF() +ENDIF() + # Windows wants only major.minor IF(WIN32) diff --git a/include/my_openssl_fips.h b/include/my_openssl_fips.h new file mode 100644 index 000000000000..18be5711d037 --- /dev/null +++ b/include/my_openssl_fips.h @@ -0,0 +1,41 @@ +/* Copyright (c) 2022, Oracle and/or its affiliates. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License, version 2.0, + as published by the Free Software Foundation. + + This program is also distributed with certain software (including + but not limited to OpenSSL) that is licensed under separate terms, + as designated in a particular file or component or in included license + documentation. The authors of MySQL hereby grant you an additional + permission to link the program and your derivative works with the + separately licensed software that they have included with MySQL. + + Without limiting anything contained in the foregoing, this file, + which is part of C Driver for MySQL (Connector/C), is also subject to the + Universal FOSS Exception, version 1.0, a copy of which can be found at + http://oss.oracle.com/licenses/universal-foss-exception. + + 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, version 2.0, 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 */ + +#ifndef my_openssl_fips_h_ +#define my_openssl_fips_h_ + +constexpr int OPENSSL_ERROR_LENGTH{512}; /* Openssl error code max length */ + +bool set_fips_mode(const int fips_mode, char err_string[OPENSSL_ERROR_LENGTH]); +int get_fips_mode(); + +int test_ssl_fips_mode(char err_string[OPENSSL_ERROR_LENGTH]); + +void fips_deinit(); +void fips_init(); + +#endif /* ifndef my_openssl_fips_h_ */ diff --git a/include/violite.h b/include/violite.h index e0e5bd7f51f0..712c6227c1a6 100644 --- a/include/violite.h +++ b/include/violite.h @@ -140,7 +140,6 @@ enum enum_vio_io_event { #define VIO_LOCALHOST 1 /* a localhost connection */ #define VIO_BUFFERED_READ 2 /* use buffered read */ #define VIO_READ_BUFFER_SIZE 16384 /* size of read buffer */ -#define OPENSSL_ERROR_LENGTH 512 /* Openssl error code max length */ MYSQL_VIO vio_new(my_socket sd, enum enum_vio_type type, uint flags); MYSQL_VIO mysql_socket_vio_new(MYSQL_SOCKET mysql_socket, @@ -268,12 +267,6 @@ struct st_VioSSLFd *new_VioSSLConnectorFd( long process_tls_version(const char *tls_version); -int set_fips_mode(const uint fips_mode, char *err_string); - -uint get_fips_mode(); - -int test_ssl_fips_mode(char *err_string); - struct st_VioSSLFd *new_VioSSLAcceptorFd( const char *key_file, const char *cert_file, const char *ca_file, const char *ca_path, const char *cipher, const char *ciphersuites, diff --git a/libmysql/authentication_oci_client/CMakeLists.txt b/libmysql/authentication_oci_client/CMakeLists.txt index 8e520219b476..f7bfeb3e9700 100644 --- a/libmysql/authentication_oci_client/CMakeLists.txt +++ b/libmysql/authentication_oci_client/CMakeLists.txt @@ -52,3 +52,7 @@ MYSQL_ADD_PLUGIN( CLIENT_ONLY MODULE_ONLY MODULE_OUTPUT_NAME "authentication_oci_client" ) + +DOWNGRADE_OPENSSL3_DEPRECATION_WARNINGS( + src/oci_iam/request/ssl.cc + ) diff --git a/mysql-test/suite/auth_sec/r/openssl_without_fips.result b/mysql-test/suite/auth_sec/r/openssl_without_fips.result index 86a917d2c6c2..14620f3a65cb 100644 --- a/mysql-test/suite/auth_sec/r/openssl_without_fips.result +++ b/mysql-test/suite/auth_sec/r/openssl_without_fips.result @@ -17,7 +17,7 @@ c9f0f895fb98ab9159f51fd0297e236d # Bug #33082255: SERVER EXIT TRYING TO SET FIPS MODE # SET @@global.ssl_fips_mode = 'ON'; -ERROR HY000: SSL fips mode error: Openssl is not fips enabled +ERROR HY000: SSL fips mode error: Openssl is not fips enabled: openssl error ##Test: Start the server with SSL FIPS mode ON, server will throw error and abort. -Pattern "(FIPS_mode_set:fips mode not supported|FIPS_module_mode_set:fingerprint does not match)" found +Pattern "(FIPS_mode_set:fips mode not supported|FIPS_module_mode_set:fingerprint does not match|SSL fips mode error:)" found Restart server with FIPS mode OFF. diff --git a/mysql-test/suite/auth_sec/t/openssl_without_fips.test b/mysql-test/suite/auth_sec/t/openssl_without_fips.test index 18ce4ace0e3f..6a09f2dabe45 100644 --- a/mysql-test/suite/auth_sec/t/openssl_without_fips.test +++ b/mysql-test/suite/auth_sec/t/openssl_without_fips.test @@ -51,6 +51,7 @@ EOF --echo # Bug #33082255: SERVER EXIT TRYING TO SET FIPS MODE --echo # +--replace_regex /SSL fips mode error: Openssl is not fips enabled.*/SSL fips mode error: Openssl is not fips enabled: openssl error/ --error ER_DA_SSL_FIPS_MODE_ERROR SET @@global.ssl_fips_mode = 'ON'; @@ -65,7 +66,7 @@ let $restart_file = $MYSQLTEST_VARDIR/tmp/mysqld.1.expect; --source include/wait_until_disconnected.inc --error 1 --exec $MYSQLD_CMD --loose-console --ssl-fips-mode=ON > $error_log 2>&1 -let SEARCH_PATTERN = (FIPS_mode_set:fips mode not supported|FIPS_module_mode_set:fingerprint does not match); +let SEARCH_PATTERN = (FIPS_mode_set:fips mode not supported|FIPS_module_mode_set:fingerprint does not match|SSL fips mode error:); --source include/search_pattern.inc --remove_file $error_log diff --git a/mysys/CMakeLists.txt b/mysys/CMakeLists.txt index 596130dd2912..eee28900ff77 100644 --- a/mysys/CMakeLists.txt +++ b/mysys/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (c) 2006, 2021, Oracle and/or its affiliates. +# Copyright (c) 2006, 2022, Oracle and/or its affiliates. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License, version 2.0, @@ -119,6 +119,7 @@ SET(MYSYS_SOURCES my_sha2.cc my_md5.cc my_rnd.cc + my_openssl_fips.cc ) LIST(APPEND MYSYS_SOURCES my_aes_openssl.cc) diff --git a/mysys/my_md5.cc b/mysys/my_md5.cc index 86203619f135..ee6ea39097c9 100644 --- a/mysys/my_md5.cc +++ b/mysys/my_md5.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2012, 2021, Oracle and/or its affiliates. +/* Copyright (c) 2012, 2022, Oracle and/or its affiliates. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, version 2.0, @@ -33,14 +33,28 @@ #include "my_md5.h" #include + +#if OPENSSL_VERSION_NUMBER >= 0x30000000L +#include +#include +#else #include +#endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ static void my_md5_hash(unsigned char *digest, unsigned const char *buf, int len) { +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + /* + EVP_Digest() is a wrapper around the EVP_DigestInit_ex(), + EVP_Update() and EVP_Final_ex() functions. + */ + EVP_Digest(buf, len, digest, nullptr, EVP_md5(), nullptr); +#else /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ MD5_CTX ctx; MD5_Init(&ctx); MD5_Update(&ctx, buf, len); MD5_Final(digest, &ctx); +#endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ } /** @@ -55,8 +69,14 @@ static void my_md5_hash(unsigned char *digest, unsigned const char *buf, */ int compute_md5_hash(char *digest, const char *buf, int len) { int retval = 0; - int fips_mode = 0; - fips_mode = FIPS_mode(); + +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + int fips_mode = EVP_default_properties_is_fips_enabled(nullptr) && + OSSL_PROVIDER_available(nullptr, "fips"); +#else /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ + int fips_mode = FIPS_mode(); +#endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ + /* If fips mode is ON/STRICT restricted method calls will result into abort, * skipping call. */ if (fips_mode == 0) { diff --git a/mysys/my_openssl_fips.cc b/mysys/my_openssl_fips.cc new file mode 100644 index 000000000000..f8e7ad8d0bd5 --- /dev/null +++ b/mysys/my_openssl_fips.cc @@ -0,0 +1,145 @@ +/* Copyright (c) 2022, Oracle and/or its affiliates. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License, version 2.0, + as published by the Free Software Foundation. + + This program is also distributed with certain software (including + but not limited to OpenSSL) that is licensed under separate terms, + as designated in a particular file or component or in included license + documentation. The authors of MySQL hereby grant you an additional + permission to link the program and your derivative works with the + separately licensed software that they have included with MySQL. + + Without limiting anything contained in the foregoing, this file, + which is part of C Driver for MySQL (Connector/C), is also subject to the + Universal FOSS Exception, version 1.0, a copy of which can be found at + http://oss.oracle.com/licenses/universal-foss-exception. + + 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, version 2.0, 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 "my_openssl_fips.h" +#include +#include + +#if OPENSSL_VERSION_NUMBER < 0x10002000L +#include +#endif /* OPENSSL_VERSION_NUMBER < 0x10002000L */ + +#if OPENSSL_VERSION_NUMBER >= 0x30000000L +#include +#include +#endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ +/** + Get fips mode from openssl library, + + @returns openssl current fips mode +*/ +int get_fips_mode() { +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + return EVP_default_properties_is_fips_enabled(nullptr) && + OSSL_PROVIDER_available(nullptr, "fips"); +#else /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ + return FIPS_mode(); +#endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ +} + +#if OPENSSL_VERSION_NUMBER >= 0x30000000L +static OSSL_PROVIDER *ossl_provider_fips = nullptr; +#endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ + +/** + Sets fips mode. On error the error is in the openssl error stack + + @retval 0 failure + @retval non-0 success +*/ +static int set_fips_mode_inner(int fips_mode) { + int rc = -1; +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + /* Load FIPS provider when needed. */ + if (fips_mode > 0 && nullptr == ossl_provider_fips) { + ossl_provider_fips = OSSL_PROVIDER_load(nullptr, "fips"); + if (ossl_provider_fips == nullptr) rc = 0; + } + if (rc) rc = EVP_default_properties_enable_fips(nullptr, fips_mode); +#else /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ + rc = FIPS_mode_set(fips_mode); +#endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ + return rc; +} + +/** + Turns FIPs mode on or off + + @param [in] fips_mode 0 for fips mode off, non-zero for fips mode ON + @param [out] err_string If fips mode set fails, err_string will have detail + failure reason. + + @returns openssl set fips mode errors + @retval true for error + @retval false for success +*/ +bool set_fips_mode(const int fips_mode, char err_string[OPENSSL_ERROR_LENGTH]) { + int rc = -1; + int fips_mode_old = -1; + + if (fips_mode > 2) return true; + + fips_mode_old = get_fips_mode(); + if (fips_mode_old == fips_mode) return false; + rc = set_fips_mode_inner(fips_mode); + if (rc == 0) { + /* + For openssl libraries prior to 3.0 if OS doesn't have FIPS enabled openss + l library and user sets FIPS mode ON, It fails with proper error. + But in the same time it doesn't allow to + perform any cryptographic operation. Now if FIPS mode set fails with + error, setting old working FIPS mode value in the OpenSSL library. It will + allow successful cryptographic operation and will not abort the server. + For openssl 3.0 we turn the FIPs mode off for good measure. + */ + unsigned long err_library = ERR_get_error(); + set_fips_mode_inner(fips_mode_old); + ERR_error_string_n(err_library, err_string, OPENSSL_ERROR_LENGTH - 1); + err_string[OPENSSL_ERROR_LENGTH - 1] = '\0'; + + return true; + } + return false; +} + +/** + Toggle FIPS mode, to see whether it is available with the current SSL library. + @retval 0 FIPS is not supported. + @retval non-zero: FIPS is supported. +*/ +int test_ssl_fips_mode(char err_string[OPENSSL_ERROR_LENGTH]) { + unsigned test_fips_mode = get_fips_mode() == 0 ? 1 : 0; + int ret = set_fips_mode_inner(test_fips_mode); + unsigned long err = (ret == 0) ? ERR_get_error() : 0; + + if (err != 0) { + ERR_error_string_n(err, err_string, OPENSSL_ERROR_LENGTH - 1); + } + return ret; +} + +void fips_deinit() { +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + if (ossl_provider_fips) OSSL_PROVIDER_unload(ossl_provider_fips); +#endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ +} + +void fips_init() { +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + assert(ossl_provider_fips == nullptr); +#endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ +} diff --git a/mysys/my_sha2.cc b/mysys/my_sha2.cc index f2bfb5af40ea..c626660caa5d 100644 --- a/mysys/my_sha2.cc +++ b/mysys/my_sha2.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2007, 2021, Oracle and/or its affiliates. +/* Copyright (c) 2007, 2022, Oracle and/or its affiliates. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, version 2.0, @@ -33,8 +33,16 @@ #include "sha2.h" -/* Low level digest API's are not allowed to access when FIPS mode is ON. This - * wrapper will allow to call different sha256 methods directly.*/ +#if OPENSSL_VERSION_NUMBER >= 0x30000000L +#define GEN_OPENSSL_EVP_SHA2_BRIDGE(size) \ + unsigned char *SHA_EVP##size(const unsigned char *input_ptr, \ + size_t input_length, \ + char unsigned *output_ptr) { \ + EVP_Digest(input_ptr, input_length, output_ptr, nullptr, EVP_sha##size(), \ + nullptr); \ + return (output_ptr); \ + } +#else /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ #define GEN_OPENSSL_EVP_SHA2_BRIDGE(size) \ unsigned char *SHA_EVP##size(const unsigned char *input_ptr, \ size_t input_length, \ @@ -46,6 +54,7 @@ EVP_MD_CTX_destroy(md_ctx); \ return (output_ptr); \ } +#endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ /* @fn SHA_EVP512 diff --git a/plugin/group_replication/libmysqlgcs/src/bindings/xcom/xcom/network/xcom_network_provider_ssl_native_lib.cc b/plugin/group_replication/libmysqlgcs/src/bindings/xcom/xcom/network/xcom_network_provider_ssl_native_lib.cc index 6cf3146e7235..608f790c9fac 100644 --- a/plugin/group_replication/libmysqlgcs/src/bindings/xcom/xcom/network/xcom_network_provider_ssl_native_lib.cc +++ b/plugin/group_replication/libmysqlgcs/src/bindings/xcom/xcom/network/xcom_network_provider_ssl_native_lib.cc @@ -34,6 +34,8 @@ #include #include +#include + #ifndef XCOM_STANDALONE #include "my_compiler.h" #endif @@ -90,6 +92,7 @@ static const char *tls_cipher_blocked = "!ECDH-RSA-DES-CBC3-SHA:!ECDH-ECDSA-DES-CBC3-SHA:" "!ECDHE-RSA-DES-CBC3-SHA:!ECDHE-ECDSA-DES-CBC3-SHA:"; +#if OPENSSL_VERSION_NUMBER < 0x30000000L /* Diffie-Hellman key. Generated using: >openssl dhparam -5 -C 2048 @@ -150,6 +153,7 @@ static DH *get_dh2048(void) { } return (dh); } +#endif /* OPENSSL_VERSION_NUMBER < 0x30000000L */ static char *ssl_pw = nullptr; static int ssl_init_done = 0; @@ -226,7 +230,6 @@ static int configure_ssl_algorithms(SSL_CTX *ssl_ctx, const char *cipher, const char *tls_version, const char *tls_ciphersuites [[maybe_unused]]) { - DH *dh = nullptr; long ssl_ctx_options = SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1; char cipher_list[SSL_CIPHER_LIST_SIZE] = {0}; @@ -241,7 +244,7 @@ static int configure_ssl_algorithms(SSL_CTX *ssl_ctx, const char *cipher, ssl_ctx_flags = process_tls_version(tls_version); if (ssl_ctx_flags < 0) { G_ERROR("TLS version is invalid: %s", tls_version); - goto error; + return 1; } #ifdef HAVE_TLSv13 @@ -274,14 +277,14 @@ static int configure_ssl_algorithms(SSL_CTX *ssl_ctx, const char *cipher, "Failed to set the list of ciphersuites. Check if the values " "configured for ciphersuites are correct and valid and if the list " "is not empty"); - goto error; + return 1; } } } else { /* Disable OpenSSL TLS v1.3 ciphersuites. */ if (SSL_CTX_set_ciphersuites(ssl_ctx, "") == 0) { G_DEBUG("Failed to set empty ciphersuites with TLS v1.3 disabled."); - goto error; + return 1; } } #endif /* HAVE_TLSv13 */ @@ -299,44 +302,35 @@ static int configure_ssl_algorithms(SSL_CTX *ssl_ctx, const char *cipher, if (SSL_CTX_set_cipher_list(ssl_ctx, cipher_list) == 0) { G_ERROR("Failed to set the list of chipers."); - goto error; + return 1; } - dh = get_dh2048(); +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + if (SSL_CTX_set_dh_auto(ssl_ctx, 1) != 1) return true; +#else /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ + DH *dh = get_dh2048(); if (SSL_CTX_set_tmp_dh(ssl_ctx, dh) == 0) { G_ERROR("Error setting up Diffie-Hellman key exchange"); - goto error; + DH_free(dh); + return 1; } DH_free(dh); +#endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ return 0; - -error: - if (dh) DH_free(dh); - return 1; } -#define OPENSSL_ERROR_LENGTH 512 -static int configure_ssl_fips_mode(const int fips_mode) { - int rc = -1; - int fips_mode_old = -1; +/** + @retval true for error + @retval false for success +*/ +static bool configure_ssl_fips_mode(const int fips_mode) { + bool rc = false; char err_string[OPENSSL_ERROR_LENGTH] = {'\0'}; - unsigned long err_library = 0; - if (fips_mode > 2) { - goto EXIT; - } - fips_mode_old = FIPS_mode(); - if (fips_mode_old == fips_mode) { - rc = 1; - goto EXIT; - } - if (!(rc = FIPS_mode_set(fips_mode))) { - err_library = ERR_get_error(); - ERR_error_string_n(err_library, err_string, sizeof(err_string) - 1); - err_string[sizeof(err_string) - 1] = '\0'; + if (set_fips_mode(fips_mode, err_string)) { G_ERROR("openssl fips mode set failed: %s", err_string); + rc = true; } -EXIT: return rc; } @@ -479,8 +473,7 @@ int Xcom_network_provider_ssl_library::xcom_init_ssl( int verify_client = SSL_VERIFY_NONE; if (configure_ssl_fips_mode( - Network_provider_manager::getInstance().xcom_get_ssl_fips_mode()) != - 1) { + Network_provider_manager::getInstance().xcom_get_ssl_fips_mode())) { G_ERROR("Error setting the ssl fips mode"); goto error; } diff --git a/plugin/keyring/keyring.cc b/plugin/keyring/keyring.cc index 65e63be77550..5844df4f3f08 100644 --- a/plugin/keyring/keyring.cc +++ b/plugin/keyring/keyring.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2016, 2021, Oracle and/or its affiliates. +/* Copyright (c) 2016, 2022, Oracle and/or its affiliates. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, version 2.0, @@ -111,9 +111,11 @@ static int keyring_init(MYSQL_PLUGIN plugin_info [[maybe_unused]]) { try { SSL_library_init(); // always returns 1 +#if OPENSSL_VERSION_NUMBER < 0x30000000L ERR_load_BIO_strings(); SSL_load_error_strings(); OpenSSL_add_all_algorithms(); +#endif /* OPENSSL_VERSION_NUMBER < 0x30000000L */ #ifdef HAVE_PSI_INTERFACE keyring_init_psi_keys(); diff --git a/plugin/x/client/authentication/mysql41_hash.cc b/plugin/x/client/authentication/mysql41_hash.cc index b70bbaa05c5c..31ff5a10518d 100644 --- a/plugin/x/client/authentication/mysql41_hash.cc +++ b/plugin/x/client/authentication/mysql41_hash.cc @@ -25,7 +25,11 @@ #include "plugin/x/client/authentication/mysql41_hash.h" #include +#if OPENSSL_VERSION_NUMBER >= 0x30000000L +#include +#endif /* OPENSSL_VERSION_NUMBER < 0x30000000L */ +#if OPENSSL_VERSION_NUMBER < 0x30000000L int mysql_mysql41_hash_reset(SHA_CTX *context) { return SHA1_Init(context); } int mysql_mysql41_hash_input(SHA_CTX *context, const uint8_t *message_array, @@ -37,6 +41,7 @@ int mysql_mysql41_hash_result(SHA_CTX *context, uint8_t Message_Digest[MYSQL41_HASH_SIZE]) { return SHA1_Final(Message_Digest, context); } +#endif /* OPENSSL_VERSION_NUMBER < 0x30000000L */ /** Wrapper function to compute mysql41_hash message digest. @@ -46,11 +51,19 @@ int mysql_mysql41_hash_result(SHA_CTX *context, @param[in] len Length of the message */ void compute_mysql41_hash(uint8_t *digest, const char *buf, unsigned len) { +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + /* + EVP_Digest() is a wrapper around the EVP_DigestInit_ex(), + EVP_Update() and EVP_Final_ex() functions. + */ + EVP_Digest(buf, len, digest, nullptr, EVP_sha1(), nullptr); +#else /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ SHA_CTX mysql41_hash_context; mysql_mysql41_hash_reset(&mysql41_hash_context); mysql_mysql41_hash_input(&mysql41_hash_context, (const uint8_t *)buf, len); mysql_mysql41_hash_result(&mysql41_hash_context, digest); +#endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ } /** @@ -66,10 +79,19 @@ void compute_mysql41_hash(uint8_t *digest, const char *buf, unsigned len) { void compute_mysql41_hash_multi(uint8_t *digest, const char *buf1, unsigned len1, const char *buf2, unsigned len2) { +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + EVP_MD_CTX *md_ctx = EVP_MD_CTX_new(); + EVP_DigestInit_ex(md_ctx, EVP_sha1(), nullptr); + EVP_DigestUpdate(md_ctx, buf1, len1); + EVP_DigestUpdate(md_ctx, buf2, len2); + EVP_DigestFinal_ex(md_ctx, digest, nullptr); + EVP_MD_CTX_free(md_ctx); +#else /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ SHA_CTX mysql41_hash_context; mysql_mysql41_hash_reset(&mysql41_hash_context); mysql_mysql41_hash_input(&mysql41_hash_context, (const uint8_t *)buf1, len1); mysql_mysql41_hash_input(&mysql41_hash_context, (const uint8_t *)buf2, len2); mysql_mysql41_hash_result(&mysql41_hash_context, digest); +#endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ } diff --git a/plugin/x/client/xconnection_impl.cc b/plugin/x/client/xconnection_impl.cc index 20d37799bec4..aa775129e229 100644 --- a/plugin/x/client/xconnection_impl.cc +++ b/plugin/x/client/xconnection_impl.cc @@ -36,6 +36,8 @@ #include #include +#include "my_openssl_fips.h" + #include "errmsg.h" // NOLINT(build/include_subdir) #include "my_config.h" // NOLINT(build/include_subdir) #include "my_dbug.h" // NOLINT(build/include_subdir) @@ -618,46 +620,6 @@ XError Connection_impl::get_ssl_error(const int error_id) { return XError(CR_SSL_CONNECTION_ERROR, buffer); } -/** - Set fips mode in openssl library, - When we set fips mode ON/STRICT, it will perform following operations: - 1. Check integrity of openssl library - 2. Run fips related tests. - 3. Disable non fips complaint algorithms - 4. Should be set par process before openssl library initialization - 5. When FIPs mode ON(1/2), calling weak algorithms may results into process - abort. - - @param [in] fips_mode 0 for fips mode off, 1/2 for fips mode ON - @param [out] err_string If fips mode set fails, err_string will have detail - failure reason. - - @returns openssl set fips mode errors - @retval non 1 for Error - @retval 1 Success -*/ -int set_fips_mode(const uint32_t fips_mode, - char err_string[OPENSSL_ERROR_LENGTH]) { - int rc = -1; - unsigned int fips_mode_old = -1; - unsigned long err_library = 0; - if (fips_mode > 2) { - goto EXIT; - } - fips_mode_old = FIPS_mode(); - if (fips_mode_old == fips_mode) { - rc = 1; - goto EXIT; - } - if (!(rc = FIPS_mode_set(fips_mode))) { - err_library = ERR_get_error(); - ERR_error_string_n(err_library, err_string, OPENSSL_ERROR_LENGTH - 1); - err_string[OPENSSL_ERROR_LENGTH - 1] = '\0'; - } -EXIT: - return rc; -} - XError Connection_impl::activate_tls() { if (nullptr == m_vio) return get_socket_error(SOCKET_ECONNRESET); @@ -670,7 +632,7 @@ XError Connection_impl::activate_tls() { char err_string[OPENSSL_ERROR_LENGTH] = {'\0'}; if (set_fips_mode( static_cast(m_context->m_ssl_config.m_ssl_fips_mode), - err_string) != 1) { + err_string)) { return XError{CR_SSL_CONNECTION_ERROR, err_string, true}; } auto ssl_ctx_flags = process_tls_version( diff --git a/router/src/harness/src/CMakeLists.txt b/router/src/harness/src/CMakeLists.txt index dda6b05a87b8..b8bdc7cbac3b 100644 --- a/router/src/harness/src/CMakeLists.txt +++ b/router/src/harness/src/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (c) 2019, 2021, Oracle and/or its affiliates. +# Copyright (c) 2019, 2022, Oracle and/or its affiliates. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License, version 2.0, @@ -256,6 +256,10 @@ ADD_LIBRARY(harness_tls SHARED tls_server_context.cc ) +DOWNGRADE_OPENSSL3_DEPRECATION_WARNINGS( + tls_server_context.cc + ) + IF(TARGET copy_openssl_dlls) ADD_DEPENDENCIES(harness_tls copy_openssl_dlls) ENDIF() diff --git a/router/src/router/src/CMakeLists.txt b/router/src/router/src/CMakeLists.txt index df08223275e4..9ca737e574f1 100644 --- a/router/src/router/src/CMakeLists.txt +++ b/router/src/router/src/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (c) 2015, 2021, Oracle and/or its affiliates. +# Copyright (c) 2015, 2022, Oracle and/or its affiliates. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License, version 2.0, @@ -54,6 +54,12 @@ IF(WIN32) ) ENDIF() +DOWNGRADE_OPENSSL3_DEPRECATION_WARNINGS( + certificate_generator.cc + certificate_handler.cc + config_generator.cc + ) + SET(source_files main.cc) IF(WIN32) diff --git a/router/src/router/tests/CMakeLists.txt b/router/src/router/tests/CMakeLists.txt index 23da57798c1e..a301d97596e7 100644 --- a/router/src/router/tests/CMakeLists.txt +++ b/router/src/router/tests/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (c) 2015, 2021, Oracle and/or its affiliates. +# Copyright (c) 2015, 2022, Oracle and/or its affiliates. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License, version 2.0, @@ -292,6 +292,14 @@ IF(MY_COMPILER_IS_CLANG) STRING_APPEND(CMAKE_CXX_FLAGS " -Wno-deprecated") ENDIF() +DOWNGRADE_OPENSSL3_DEPRECATION_WARNINGS( + ../src/certificate_generator.cc + ../src/certificate_handler.cc + ../src/config_generator.cc + test_certificate_generator.cc + test_certificate_handler.cc + ) + # TODO(sgunders): Remove when all GMock tests use MOCK_METHOD(). STRING(REPLACE "-Wsuggest-override" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") diff --git a/router/tests/component/test_http_server.cc b/router/tests/component/test_http_server.cc index 41d557ae39b0..f27f475ed074 100644 --- a/router/tests/component/test_http_server.cc +++ b/router/tests/component/test_http_server.cc @@ -1195,7 +1195,11 @@ class HttpServerSecureTest mysql_harness::Path ssl_cert_data_dir_; }; +#if OPENSSL_VERSION_NUMBER >= 0x30000000L +constexpr const char kErrmsgRegexWeakSslKey[]{"ca md too weak"}; +#else constexpr const char kErrmsgRegexWeakSslKey[]{"key-size too small"}; +#endif TEST_P(HttpServerSecureTest, ensure) { // const size_t placeholder_length = strlen(kPlaceholder); @@ -1460,7 +1464,12 @@ const HttpServerSecureParams http_server_secure_params[]{ kPlaceholderDatadir + std::string("/") + kDhParams4File}, }, false, - "key size of DH param"}, +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + "check of DH params failed" +#else + "key size of DH param" +#endif + }, }; INSTANTIATE_TEST_SUITE_P( diff --git a/sql-common/client.cc b/sql-common/client.cc index d819ae907d5f..fd3bf6aa3c5b 100644 --- a/sql-common/client.cc +++ b/sql-common/client.cc @@ -76,6 +76,7 @@ #include "my_io.h" #include "my_loglevel.h" #include "my_macros.h" +#include "my_openssl_fips.h" // OPENSSL_ERROR_LENGTH, set_fips_mode #include "my_psi_config.h" #include "my_shm_defaults.h" #include "mysql.h" @@ -8488,7 +8489,7 @@ int STDCALL mysql_options(MYSQL *mysql, enum mysql_option option, mysql->options.extension->ssl_fips_mode = *static_cast(arg); if (set_fips_mode(mysql->options.extension->ssl_fips_mode, - ssl_err_string) != 1) { + ssl_err_string)) { DBUG_PRINT("error", ("fips mode set error %s:", ssl_err_string)); set_mysql_extended_error( mysql, CR_SSL_FIPS_MODE_ERR, unknown_sqlstate, diff --git a/sql-common/client_authentication.cc b/sql-common/client_authentication.cc index e65c4124119e..da00a31f2b6b 100644 --- a/sql-common/client_authentication.cc +++ b/sql-common/client_authentication.cc @@ -71,7 +71,11 @@ int sha256_password_deinit(void) { return 0; } +#if OPENSSL_VERSION_NUMBER >= 0x30000000L +static EVP_PKEY *g_public_key = nullptr; +#else /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ static RSA *g_public_key = nullptr; +#endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ /** Reads and parse RSA public key data from a file. @@ -80,8 +84,13 @@ static RSA *g_public_key = nullptr; @return Pointer to the RSA public key storage buffer */ +#if OPENSSL_VERSION_NUMBER >= 0x30000000L +static EVP_PKEY *rsa_init(MYSQL *mysql) { + EVP_PKEY *key = nullptr; +#else /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ static RSA *rsa_init(MYSQL *mysql) { RSA *key = nullptr; +#endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ mysql_mutex_lock(&g_public_key_mutex); key = g_public_key; @@ -114,7 +123,11 @@ static RSA *rsa_init(MYSQL *mysql) { mysql_mutex_lock(&g_public_key_mutex); key = g_public_key = +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + PEM_read_PUBKEY(pub_key_file, nullptr, nullptr, nullptr); +#else /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ PEM_read_RSA_PUBKEY(pub_key_file, nullptr, nullptr, nullptr); +#endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ mysql_mutex_unlock(&g_public_key_mutex); fclose(pub_key_file); if (g_public_key == nullptr) { @@ -127,6 +140,32 @@ static RSA *rsa_init(MYSQL *mysql) { return key; } +#if OPENSSL_VERSION_NUMBER >= 0x30000000L +static bool encrypt_RSA_public_key(const unsigned char *password, + int password_len, unsigned char *to, + size_t *to_len, EVP_PKEY *public_key) { + EVP_PKEY_CTX *key_ctx = EVP_PKEY_CTX_new(public_key, nullptr); + if (!key_ctx) return true; + if (EVP_PKEY_encrypt_init(key_ctx) <= 0 || + EVP_PKEY_CTX_set_rsa_padding(key_ctx, RSA_PKCS1_OAEP_PADDING) <= 0 || + EVP_PKEY_encrypt(key_ctx, to, to_len, password, password_len) <= 0) { + EVP_PKEY_CTX_free(key_ctx); + return true; + } + EVP_PKEY_CTX_free(key_ctx); + return false; +} +#else /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ +static bool encrypt_RSA_public_key(const unsigned char *password, + int password_len, unsigned char *to, + RSA *public_key) { + if (RSA_public_encrypt(password_len, password, to, public_key, + RSA_PKCS1_OAEP_PADDING) == -1) + return true; + return false; +} +#endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ + /** Authenticate the client using the RSA or TLS and a SHA256 salted password. @@ -142,7 +181,11 @@ int sha256_password_auth_client(MYSQL_PLUGIN_VIO *vio, MYSQL *mysql) { bool uses_password = mysql->passwd[0] != 0; unsigned char encrypted_password[MAX_CIPHER_LENGTH]; static char request_public_key = '\1'; +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + EVP_PKEY *public_key = nullptr; +#else /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ RSA *public_key = nullptr; +#endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ bool got_public_key_from_server = false; bool connection_is_secure = false; unsigned char scramble_pkt[SCRAMBLE_LENGTH]{}; @@ -197,7 +240,11 @@ int sha256_password_auth_client(MYSQL_PLUGIN_VIO *vio, MYSQL *mysql) { if ((packet_len = vio->read_packet(vio, &packet)) == -1) return CR_ERROR; BIO *bio = BIO_new_mem_buf(packet, packet_len); +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + public_key = PEM_read_bio_PUBKEY(bio, nullptr, nullptr, nullptr); +#else /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ public_key = PEM_read_bio_RSA_PUBKEY(bio, nullptr, nullptr, nullptr); +#endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ BIO_free(bio); if (public_key == nullptr) { ERR_clear_error(); @@ -218,8 +265,7 @@ int sha256_password_auth_client(MYSQL_PLUGIN_VIO *vio, MYSQL *mysql) { if (passwd_len > sizeof(passwd_scramble)) { /* password too long for the buffer */ - if (got_public_key_from_server) RSA_free(public_key); - return CR_ERROR; + goto err; } memmove(passwd_scramble, mysql->passwd, passwd_len); @@ -227,21 +273,37 @@ int sha256_password_auth_client(MYSQL_PLUGIN_VIO *vio, MYSQL *mysql) { xor_string(passwd_scramble, passwd_len - 1, (char *)scramble_pkt, SCRAMBLE_LENGTH); /* Encrypt the password and send it to the server */ +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + int cipher_length = EVP_PKEY_get_size(public_key); +#else /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ int cipher_length = RSA_size(public_key); +#endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ /* When using RSA_PKCS1_OAEP_PADDING the password length must be less than RSA_size(rsa) - 41. */ if (passwd_len + 41 >= (unsigned)cipher_length) { /* password message is to long */ - if (got_public_key_from_server) RSA_free(public_key); - return CR_ERROR; + goto err; } - RSA_public_encrypt(passwd_len, (unsigned char *)passwd_scramble, - encrypted_password, public_key, - RSA_PKCS1_OAEP_PADDING); - if (got_public_key_from_server) RSA_free(public_key); +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + { + size_t encrypted_password_len = sizeof(encrypted_password); + + if (encrypt_RSA_public_key((unsigned char *)passwd_scramble, passwd_len, + encrypted_password, &encrypted_password_len, + public_key)) + goto err; + + if (got_public_key_from_server) EVP_PKEY_free(public_key); + } +#else /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ + if (encrypt_RSA_public_key((unsigned char *)passwd_scramble, passwd_len, + encrypted_password, public_key)) + goto err; + if (got_public_key_from_server) RSA_free(public_key); +#endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ if (vio->write_packet(vio, (uchar *)encrypted_password, cipher_length)) return CR_ERROR; } else { @@ -252,6 +314,15 @@ int sha256_password_auth_client(MYSQL_PLUGIN_VIO *vio, MYSQL *mysql) { } return CR_OK; + +err: + if (got_public_key_from_server) +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + EVP_PKEY_free(public_key); +#else /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ + RSA_free(public_key); +#endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ + return CR_ERROR; } /** @@ -264,7 +335,11 @@ net_async_status sha256_password_auth_client_nonblocking(MYSQL_PLUGIN_VIO *vio, net_async_status status = NET_ASYNC_NOT_READY; unsigned char encrypted_password[MAX_CIPHER_LENGTH]; static char request_public_key = '\1'; +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + static EVP_PKEY *public_key = nullptr; +#else /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ static RSA *public_key = nullptr; +#endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ bool got_public_key_from_server = false; int io_result; bool connection_is_secure = (mysql_get_ssl_cipher(mysql) != nullptr); @@ -335,7 +410,11 @@ net_async_status sha256_password_auth_client_nonblocking(MYSQL_PLUGIN_VIO *vio, return NET_ASYNC_COMPLETE; } BIO *bio = BIO_new_mem_buf(pkt, io_result); +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + public_key = PEM_read_bio_PUBKEY(bio, nullptr, nullptr, nullptr); +#else /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ public_key = PEM_read_bio_RSA_PUBKEY(bio, nullptr, nullptr, nullptr); +#endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ BIO_free(bio); if (public_key == nullptr) { ERR_clear_error(); @@ -354,9 +433,7 @@ net_async_status sha256_password_auth_client_nonblocking(MYSQL_PLUGIN_VIO *vio, if (passwd_len > sizeof(passwd_scramble)) { /* password too long for the buffer */ - if (got_public_key_from_server) RSA_free(public_key); - *result = CR_ERROR; - return NET_ASYNC_COMPLETE; + goto err; } memmove(passwd_scramble, mysql->passwd, passwd_len); @@ -364,21 +441,34 @@ net_async_status sha256_password_auth_client_nonblocking(MYSQL_PLUGIN_VIO *vio, xor_string(passwd_scramble, passwd_len - 1, (char *)scramble_pkt, SCRAMBLE_LENGTH); /* Encrypt the password and send it to the server */ +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + int cipher_length = EVP_PKEY_get_size(public_key); +#else /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ int cipher_length = RSA_size(public_key); +#endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ /* When using RSA_PKCS1_OAEP_PADDING the password length must be less than RSA_size(rsa) - 41. */ if (passwd_len + 41 >= (unsigned)cipher_length) { /* password message is to long */ - if (got_public_key_from_server) RSA_free(public_key); - *result = CR_ERROR; - return NET_ASYNC_COMPLETE; + goto err; + } +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + { + size_t encrypted_password_len = sizeof(encrypted_password); + if (encrypt_RSA_public_key((unsigned char *)passwd_scramble, passwd_len, + encrypted_password, &encrypted_password_len, + public_key)) + goto err; + if (got_public_key_from_server) EVP_PKEY_free(public_key); } - RSA_public_encrypt(passwd_len, (unsigned char *)passwd_scramble, - encrypted_password, public_key, - RSA_PKCS1_OAEP_PADDING); +#else /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ + if (encrypt_RSA_public_key((unsigned char *)passwd_scramble, passwd_len, + encrypted_password, public_key)) + goto err; if (got_public_key_from_server) RSA_free(public_key); +#endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ status = vio->write_packet_nonblocking(vio, (uchar *)encrypted_password, cipher_length, &io_result); if (status == NET_ASYNC_NOT_READY) { @@ -406,6 +496,16 @@ net_async_status sha256_password_auth_client_nonblocking(MYSQL_PLUGIN_VIO *vio, } *result = CR_OK; return NET_ASYNC_COMPLETE; + +err: + if (got_public_key_from_server) +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + EVP_PKEY_free(public_key); +#else /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ + RSA_free(public_key); +#endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ + result = CR_ERROR; + return NET_ASYNC_COMPLETE; } /* caching_sha2_password */ @@ -448,7 +548,11 @@ int caching_sha2_password_auth_client(MYSQL_PLUGIN_VIO *vio, MYSQL *mysql) { bool uses_password = mysql->passwd[0] != 0; unsigned char encrypted_password[MAX_CIPHER_LENGTH]; // static char request_public_key= '\1'; +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + EVP_PKEY *public_key = nullptr; +#else /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ RSA *public_key = nullptr; +#endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ bool got_public_key_from_server = false; bool connection_is_secure = false; unsigned char scramble_pkt[SCRAMBLE_LENGTH]{}; @@ -528,7 +632,11 @@ int caching_sha2_password_auth_client(MYSQL_PLUGIN_VIO *vio, MYSQL *mysql) { if ((pkt_len = vio->read_packet(vio, &pkt)) <= 0) return CR_ERROR; BIO *bio = BIO_new_mem_buf(pkt, pkt_len); +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + public_key = PEM_read_bio_PUBKEY(bio, nullptr, nullptr, nullptr); +#else /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ public_key = PEM_read_bio_RSA_PUBKEY(bio, nullptr, nullptr, nullptr); +#endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ BIO_free(bio); if (public_key == nullptr) { ERR_clear_error(); @@ -551,9 +659,8 @@ int caching_sha2_password_auth_client(MYSQL_PLUGIN_VIO *vio, MYSQL *mysql) { if (passwd_len > sizeof(passwd_scramble)) { /* password too long for the buffer */ - if (got_public_key_from_server) RSA_free(public_key); DBUG_PRINT("info", ("Password is too long.")); - return CR_ERROR; + goto err; } memmove(passwd_scramble, mysql->passwd, passwd_len); @@ -561,22 +668,38 @@ int caching_sha2_password_auth_client(MYSQL_PLUGIN_VIO *vio, MYSQL *mysql) { xor_string(passwd_scramble, passwd_len - 1, (char *)scramble_pkt, SCRAMBLE_LENGTH); /* Encrypt the password and send it to the server */ +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + int cipher_length = EVP_PKEY_get_size(public_key); +#else /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ int cipher_length = RSA_size(public_key); +#endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ /* When using RSA_PKCS1_OAEP_PADDING the password length must be less than RSA_size(rsa) - 41. */ if (passwd_len + 41 >= (unsigned)cipher_length) { /* password message is to long */ - if (got_public_key_from_server) RSA_free(public_key); DBUG_PRINT("info", ("Password is too long to be encrypted using " "given public key.")); - return CR_ERROR; + goto err; } - RSA_public_encrypt(passwd_len, (unsigned char *)passwd_scramble, - encrypted_password, public_key, - RSA_PKCS1_OAEP_PADDING); +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + { + size_t encrypted_password_len = sizeof(encrypted_password); + if (encrypt_RSA_public_key((unsigned char *)passwd_scramble, + passwd_len, encrypted_password, + &encrypted_password_len, public_key)) + goto err; + + if (got_public_key_from_server) EVP_PKEY_free(public_key); + } +#else /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ + if (encrypt_RSA_public_key((unsigned char *)passwd_scramble, passwd_len, + encrypted_password, public_key)) + goto err; + if (got_public_key_from_server) RSA_free(public_key); +#endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ if (vio->write_packet(vio, (uchar *)encrypted_password, cipher_length)) return CR_ERROR; @@ -595,6 +718,15 @@ int caching_sha2_password_auth_client(MYSQL_PLUGIN_VIO *vio, MYSQL *mysql) { } return CR_OK; + +err: + if (got_public_key_from_server) +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + EVP_PKEY_free(public_key); +#else /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ + RSA_free(public_key); +#endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ + return CR_ERROR; } /** @@ -606,7 +738,11 @@ net_async_status caching_sha2_password_auth_client_nonblocking( int io_result; net_async_status status = NET_ASYNC_NOT_READY; static unsigned char encrypted_password[MAX_CIPHER_LENGTH]; +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + static EVP_PKEY *public_key = nullptr; +#else /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ static RSA *public_key = nullptr; +#endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ bool connection_is_secure = is_secure_transport(mysql); bool got_public_key_from_server = false; static unsigned char scramble_pkt[SCRAMBLE_LENGTH]{}; @@ -756,7 +892,11 @@ net_async_status caching_sha2_password_auth_client_nonblocking( } int pkt_len = 0; BIO *bio = BIO_new_mem_buf(pkt, pkt_len); +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + public_key = PEM_read_bio_PUBKEY(bio, nullptr, nullptr, nullptr); +#else /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ public_key = PEM_read_bio_RSA_PUBKEY(bio, nullptr, nullptr, nullptr); +#endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ BIO_free(bio); if (public_key == nullptr) { ERR_clear_error(); @@ -770,33 +910,52 @@ net_async_status caching_sha2_password_auth_client_nonblocking( char passwd_scramble[512]; if (passwd_len > sizeof(passwd_scramble)) { /* password too long for the buffer */ - if (got_public_key_from_server) RSA_free(public_key); DBUG_PRINT("info", ("Password is too long.")); - *result = CR_ERROR; - return NET_ASYNC_COMPLETE; + goto err; } memmove(passwd_scramble, mysql->passwd, passwd_len); /* Obfuscate the plain text password with the session scramble */ xor_string(passwd_scramble, passwd_len - 1, (char *)scramble_pkt, SCRAMBLE_LENGTH); /* Encrypt the password and send it to the server */ +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + cipher_length = EVP_PKEY_get_size(public_key); +#else /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ cipher_length = RSA_size(public_key); +#endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ /* When using RSA_PKCS1_OAEP_PADDING the password length must be less than RSA_size(rsa) - 41. */ if (passwd_len + 41 >= (unsigned)cipher_length) { /* password message is to long */ - if (got_public_key_from_server) RSA_free(public_key); DBUG_PRINT("info", ("Password is too long to be encrypted using " "given public key.")); - *result = CR_ERROR; - return NET_ASYNC_COMPLETE; + goto err; + } +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + { + size_t encrypted_password_len = sizeof(encrypted_password); + EVP_PKEY_CTX *key_ctx = EVP_PKEY_CTX_new(public_key, nullptr); + if (!key_ctx) goto err; + if (EVP_PKEY_encrypt_init(key_ctx) <= 0 || + EVP_PKEY_CTX_set_rsa_padding(key_ctx, RSA_PKCS1_OAEP_PADDING) <= + 0 || + EVP_PKEY_encrypt( + key_ctx, encrypted_password, &encrypted_password_len, + (unsigned char *)passwd_scramble, passwd_len) <= 0) { + EVP_PKEY_CTX_free(key_ctx); + goto err; + } + EVP_PKEY_CTX_free(key_ctx); + if (got_public_key_from_server) EVP_PKEY_free(public_key); } +#else /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ RSA_public_encrypt(passwd_len, (unsigned char *)passwd_scramble, encrypted_password, public_key, RSA_PKCS1_OAEP_PADDING); if (got_public_key_from_server) RSA_free(public_key); +#endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ } else { set_mysql_extended_error(mysql, CR_AUTH_PLUGIN_ERR, unknown_sqlstate, ER_CLIENT(CR_AUTH_PLUGIN_ERR), @@ -839,12 +998,27 @@ net_async_status caching_sha2_password_auth_client_nonblocking( } *result = CR_OK; return NET_ASYNC_COMPLETE; + +err: + if (got_public_key_from_server) +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + EVP_PKEY_free(public_key); +#else /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ + RSA_free(public_key); +#endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ + result = CR_ERROR; + return NET_ASYNC_COMPLETE; } void STDCALL mysql_reset_server_public_key(void) { DBUG_TRACE; mysql_mutex_lock(&g_public_key_mutex); - if (g_public_key) RSA_free(g_public_key); + if (g_public_key) +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + EVP_PKEY_free(g_public_key); +#else /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ + RSA_free(g_public_key); +#endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ g_public_key = nullptr; mysql_mutex_unlock(&g_public_key_mutex); } diff --git a/sql-common/oci/signing_key.cc b/sql-common/oci/signing_key.cc index cfe6ef27784e..733be03fd750 100644 --- a/sql-common/oci/signing_key.cc +++ b/sql-common/oci/signing_key.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2021, Oracle and/or its affiliates. +/* Copyright (c) 2021, 2022, Oracle and/or its affiliates. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, version 2.0, @@ -129,6 +129,7 @@ Signing_Key::Signing_Key(ssl::Key_Content key_content) { */ Signing_Key::Signing_Key() { // Generate a new RSA private key to be used for request signing. +#if OPENSSL_VERSION_NUMBER < 0x30000000L std::unique_ptr rsa(RSA_new(), ::RSA_free); std::unique_ptr bn(BN_new(), ::BN_free); @@ -149,6 +150,16 @@ Signing_Key::Signing_Key() { } } } +#else /* OPENSSL_VERSION_NUMBER */ + m_private_key = ssl::EVP_PKEY_ptr{EVP_RSA_gen(2048)}; + oci::ssl::BIO_ptr bio{BIO_new(BIO_s_mem())}; + if (PEM_write_bio_PUBKEY(bio.get(), m_private_key.get())) { + size_t len = BIO_pending(bio.get()); + std::vector read_buffer(len + 1, '\0'); + BIO_read(bio.get(), read_buffer.data(), len); + m_public_key = read_buffer.data(); + } +#endif /* OPENSSL_VERSION_NUMBER */ } } // namespace oci diff --git a/sql/CMakeLists.txt b/sql/CMakeLists.txt index 3f4035d5978e..b6cf7d451abd 100644 --- a/sql/CMakeLists.txt +++ b/sql/CMakeLists.txt @@ -1222,7 +1222,7 @@ IF(WITH_VALGRIND) SET(LINK_MYSQLD_LDAP_LIBRARY 1) ENDIF() IF(WITH_SSL STREQUAL "system" AND - "${OPENSSL_MAJOR_VERSION}.${OPENSSL_MINOR_VERSION}" VERSION_LESS "1.1") + "${OPENSSL_VERSION_MAJOR}.${OPENSSL_VERSION_MINOR}" VERSION_LESS "1.1") SET(LINK_MYSQLD_LDAP_LIBRARY 1) ENDIF() IF(WITH_AUTHENTICATION_LDAP AND LINK_MYSQLD_LDAP_LIBRARY) diff --git a/sql/auth/auth_common.cc b/sql/auth/auth_common.cc index f6c103e7f6d5..c89a2296fbf5 100644 --- a/sql/auth/auth_common.cc +++ b/sql/auth/auth_common.cc @@ -195,4 +195,43 @@ void set_connection_admin_flag(THD *thd, consts::connection_admin.length()) .first || sctx->check_access(SUPER_ACL)); -} \ No newline at end of file +} + +/** + Decrypt pkt data using RSA private key. + @param [in] pkt Data to decrypt. + @param [in] cipher_length Length of the data. + @param [in] plain_text Buffer to store result. + @param [in] plain_text_len size of buffer + @param [in] private_key Private key to use. + @return Error status. + @retval false Success. + @retval true Failure. +*/ +#if OPENSSL_VERSION_NUMBER >= 0x30000000L +bool decrypt_RSA_private_key(uchar *pkt, int cipher_length, + unsigned char *plain_text, size_t plain_text_len, + EVP_PKEY *private_key) { + EVP_PKEY_CTX *key_ctx = EVP_PKEY_CTX_new(private_key, nullptr); + if (!key_ctx) return true; + if (EVP_PKEY_decrypt_init(key_ctx) <= 0 || + EVP_PKEY_CTX_set_rsa_padding(key_ctx, RSA_PKCS1_OAEP_PADDING) <= 0 || + EVP_PKEY_decrypt(key_ctx, plain_text, &plain_text_len, pkt, + cipher_length) <= 0) { + EVP_PKEY_CTX_free(key_ctx); + return true; + } + EVP_PKEY_CTX_free(key_ctx); + return false; +} +#else /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ +bool decrypt_RSA_private_key(uchar *pkt, int cipher_length, + unsigned char *plain_text, + size_t plain_text_len [[maybe_unused]], + RSA *private_key) { + if (RSA_private_decrypt(cipher_length, pkt, plain_text, private_key, + RSA_PKCS1_OAEP_PADDING) == -1) + return true; + return false; +} +#endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ diff --git a/sql/auth/auth_common.h b/sql/auth/auth_common.h index 318eaa6a934a..ef5807cf8abb 100644 --- a/sql/auth/auth_common.h +++ b/sql/auth/auth_common.h @@ -42,6 +42,8 @@ #include "mysql_com.h" // USERNAME_LENGTH #include "template_utils.h" +#include + /* Forward Declarations */ class Alter_info; class Field_iterator_table_ref; @@ -1125,4 +1127,15 @@ bool mysql_alter_user_comment(THD *thd, const List *users, /* helper method to check if sandbox mode should be turned off or not */ bool turn_off_sandbox_mode(THD *thd, LEX_USER *user); + +#if OPENSSL_VERSION_NUMBER >= 0x30000000L +bool decrypt_RSA_private_key(uchar *pkt, int cipher_length, + unsigned char *plain_text, size_t plain_text_len, + EVP_PKEY *private_key); +#else /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ +bool decrypt_RSA_private_key(uchar *pkt, int cipher_length, + unsigned char *plain_text, size_t plain_text_len, + RSA *private_key); +#endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ + #endif /* AUTH_COMMON_INCLUDED */ diff --git a/sql/auth/sha2_password.cc b/sql/auth/sha2_password.cc index 4f5d8e3be1bb..acbc3952e969 100644 --- a/sql/auth/sha2_password.cc +++ b/sql/auth/sha2_password.cc @@ -927,8 +927,13 @@ static int caching_sha2_password_authenticate(MYSQL_PLUGIN_VIO *vio, char scramble[SCRAMBLE_LENGTH + 1]; int cipher_length = 0; unsigned char plain_text[MAX_CIPHER_LENGTH + 1]; +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + EVP_PKEY *private_key = nullptr; + EVP_PKEY *public_key = nullptr; +#else /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ RSA *private_key = nullptr; RSA *public_key = nullptr; +#endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ generate_user_salt(scramble, SCRAMBLE_LENGTH + 1); @@ -1064,8 +1069,9 @@ static int caching_sha2_password_authenticate(MYSQL_PLUGIN_VIO *vio, if (pkt_len != cipher_length) return CR_ERROR; /* Decrypt password */ - RSA_private_decrypt(cipher_length, pkt, plain_text, private_key, - RSA_PKCS1_OAEP_PADDING); + if (decrypt_RSA_private_key(pkt, cipher_length, plain_text, + sizeof(plain_text) - 1, private_key)) + return CR_ERROR; plain_text[cipher_length] = '\0'; // safety xor_string((char *)plain_text, cipher_length, (char *)scramble, diff --git a/sql/auth/sql_authentication.cc b/sql/auth/sql_authentication.cc index ecef214bd2c3..e78b39874106 100644 --- a/sql/auth/sql_authentication.cc +++ b/sql/auth/sql_authentication.cc @@ -1159,8 +1159,14 @@ void Rsa_authentication_keys::get_key_file_path(char *key, are. @retval true Failure : An appropriate error is raised. */ +#if OPENSSL_VERSION_NUMBER >= 0x30000000L +bool Rsa_authentication_keys::read_key_file(EVP_PKEY **key_ptr, + bool is_priv_key, + char **key_text_buffer) { +#else /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ bool Rsa_authentication_keys::read_key_file(RSA **key_ptr, bool is_priv_key, char **key_text_buffer) { +#endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ String key_file_path; char *key; const char *key_type; @@ -1180,8 +1186,13 @@ bool Rsa_authentication_keys::read_key_file(RSA **key_ptr, bool is_priv_key, key_file_path.c_ptr()); } else { *key_ptr = is_priv_key +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + ? PEM_read_PrivateKey(key_file, nullptr, nullptr, nullptr) + : PEM_read_PUBKEY(key_file, nullptr, nullptr, nullptr); +#else /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ ? PEM_read_RSAPrivateKey(key_file, nullptr, nullptr, nullptr) : PEM_read_RSA_PUBKEY(key_file, nullptr, nullptr, nullptr); +#endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ if (!(*key_ptr)) { char error_buf[MYSQL_ERRMSG_SIZE]; @@ -1222,10 +1233,19 @@ bool Rsa_authentication_keys::read_key_file(RSA **key_ptr, bool is_priv_key, } void Rsa_authentication_keys::free_memory() { - if (m_private_key) RSA_free(m_private_key); + if (m_private_key) +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + EVP_PKEY_free(m_private_key); +#else /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ + RSA_free(m_private_key); +#endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ if (m_public_key) { +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + EVP_PKEY_free(m_public_key); +#else /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ RSA_free(m_public_key); +#endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ m_cipher_len = 0; } @@ -1238,7 +1258,11 @@ void *Rsa_authentication_keys::allocate_pem_buffer(size_t buffer_len) { } int Rsa_authentication_keys::get_cipher_length() { +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + return (m_cipher_len = EVP_PKEY_get_size(m_public_key)); +#else /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ return (m_cipher_len = RSA_size(m_public_key)); +#endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ } /** @@ -1251,8 +1275,13 @@ int Rsa_authentication_keys::get_cipher_length() { @retval true Failure : An appropriate error is raised. */ bool Rsa_authentication_keys::read_rsa_keys() { +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + EVP_PKEY *rsa_private_key_ptr = nullptr; + EVP_PKEY *rsa_public_key_ptr = nullptr; +#else /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ RSA *rsa_private_key_ptr = nullptr; RSA *rsa_public_key_ptr = nullptr; +#endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ char *pub_key_buff = nullptr; if ((strlen(*m_private_key_path) == 0) && (strlen(*m_public_key_path) == 0)) { @@ -1269,7 +1298,12 @@ bool Rsa_authentication_keys::read_rsa_keys() { Read public key in RSA format. */ if (read_key_file(&rsa_public_key_ptr, false, &pub_key_buff)) { - if (rsa_private_key_ptr) RSA_free(rsa_private_key_ptr); + if (rsa_private_key_ptr) +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + EVP_PKEY_free(rsa_private_key_ptr); +#else /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ + RSA_free(rsa_private_key_ptr); +#endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ return true; } @@ -1293,11 +1327,19 @@ bool Rsa_authentication_keys::read_rsa_keys() { delete[] pub_key_buff; } else { - if (rsa_private_key_ptr) RSA_free(rsa_private_key_ptr); - + if (rsa_private_key_ptr) +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + EVP_PKEY_free(rsa_private_key_ptr); +#else /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ + RSA_free(rsa_private_key_ptr); +#endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ if (rsa_public_key_ptr) { delete[] pub_key_buff; +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + EVP_PKEY_free(rsa_public_key_ptr); +#else /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ RSA_free(rsa_public_key_ptr); +#endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ } } return false; @@ -4661,8 +4703,13 @@ static int sha256_password_authenticate(MYSQL_PLUGIN_VIO *vio, String scramble_response_packet; int cipher_length = 0; unsigned char plain_text[MAX_CIPHER_LENGTH + 1]; +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + EVP_PKEY *private_key = nullptr; + EVP_PKEY *public_key = nullptr; +#else /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ RSA *private_key = nullptr; RSA *public_key = nullptr; +#endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ DBUG_TRACE; @@ -4771,8 +4818,9 @@ static int sha256_password_authenticate(MYSQL_PLUGIN_VIO *vio, if (pkt_len != cipher_length) return CR_ERROR; /* Decrypt password */ - RSA_private_decrypt(cipher_length, pkt, plain_text, private_key, - RSA_PKCS1_OAEP_PADDING); + if (decrypt_RSA_private_key(pkt, cipher_length, plain_text, + sizeof(plain_text) - 1, private_key)) + return CR_ERROR; plain_text[cipher_length] = '\0'; // safety xor_string((char *)plain_text, cipher_length, (char *)scramble, @@ -5087,8 +5135,30 @@ class RSA_gen { but it at the same time increases usefulness of this class when used stand alone. */ + /* generate RSA keys */ +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + EVP_PKEY *operator()(void) { + EVP_PKEY *rsa = nullptr; + BIGNUM *exponent = BN_new(); + if (!exponent) return nullptr; + EVP_PKEY_CTX *rsa_ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, nullptr); + if (!rsa_ctx) { + BN_free(exponent); + return nullptr; + } + if (BN_set_word(exponent, m_exponent) != 1 || + EVP_PKEY_keygen_init(rsa_ctx) <= 0 || + EVP_PKEY_CTX_set_rsa_keygen_bits(rsa_ctx, m_key_size) <= 0 || + EVP_PKEY_CTX_set1_rsa_keygen_pubexp(rsa_ctx, exponent) <= 0 || + EVP_PKEY_keygen(rsa_ctx, &rsa) <= 0) { + BN_free(exponent); + EVP_PKEY_CTX_free(rsa_ctx); + return nullptr; + } + BN_free(exponent); + EVP_PKEY_CTX_free(rsa_ctx); +#else /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ RSA *operator()(void) { - /* generate RSA keys */ RSA *rsa = RSA_new(); if (!rsa) return nullptr; BIGNUM *e = BN_new(); @@ -5103,6 +5173,7 @@ class RSA_gen { return nullptr; } BN_free(e); +#endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ return rsa; // pass ownership } @@ -5112,6 +5183,7 @@ class RSA_gen { uint32_t m_exponent; }; +#if OPENSSL_VERSION_NUMBER < 0x30000000L static EVP_PKEY *evp_pkey_generate(RSA *rsa) { if (rsa) { EVP_PKEY *pkey = EVP_PKEY_new(); @@ -5120,6 +5192,7 @@ static EVP_PKEY *evp_pkey_generate(RSA *rsa) { } return nullptr; } +#endif /* OPENSSL_VERSION_NUMBER < 0x30000000L */ /** Write private key in a string buffer @@ -5128,12 +5201,22 @@ static EVP_PKEY *evp_pkey_generate(RSA *rsa) { @returns Sql_string_t object with private key stored in it. */ +#if OPENSSL_VERSION_NUMBER >= 0x30000000L +static Sql_string_t rsa_priv_key_write(EVP_PKEY *rsa) { +#else /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ static Sql_string_t rsa_priv_key_write(RSA *rsa) { +#endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ assert(rsa); BIO *buf = BIO_new(BIO_s_mem()); Sql_string_t read_buffer; + +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + if (PEM_write_bio_PrivateKey(buf, rsa, nullptr, nullptr, 0, nullptr, + nullptr)) { +#else /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ if (PEM_write_bio_RSAPrivateKey(buf, rsa, nullptr, nullptr, 0, nullptr, nullptr)) { +#endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ size_t len = BIO_pending(buf); if (resize_no_exception(read_buffer, len + 1) == true) { BIO_read(buf, const_cast(read_buffer.c_str()), len); @@ -5151,11 +5234,19 @@ static Sql_string_t rsa_priv_key_write(RSA *rsa) { @returns Sql_string_t object with public key stored in it. */ +#if OPENSSL_VERSION_NUMBER >= 0x30000000L +static Sql_string_t rsa_pub_key_write(EVP_PKEY *rsa) { +#else /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ static Sql_string_t rsa_pub_key_write(RSA *rsa) { +#endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ assert(rsa); BIO *buf = BIO_new(BIO_s_mem()); Sql_string_t read_buffer; +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + if (PEM_write_bio_PUBKEY(buf, rsa)) { +#else /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ if (PEM_write_bio_RSA_PUBKEY(buf, rsa)) { +#endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ size_t len = BIO_pending(buf); if (resize_no_exception(read_buffer, len + 1) == true) { BIO_read(buf, const_cast(read_buffer.c_str()), len); @@ -5295,14 +5386,17 @@ static Sql_string_t x509_cert_write(X509 *cert) { */ static EVP_PKEY *x509_key_read(const Sql_string_t &input_string) { EVP_PKEY *pkey = nullptr; - RSA *rsa = nullptr; if (!input_string.size()) return pkey; BIO *buf = BIO_new(BIO_s_mem()); BIO_write(buf, input_string.c_str(), input_string.size()); - rsa = PEM_read_bio_RSAPrivateKey(buf, nullptr, nullptr, nullptr); +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + pkey = PEM_read_bio_PrivateKey(buf, nullptr, nullptr, nullptr); +#else /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ + RSA *rsa = PEM_read_bio_RSAPrivateKey(buf, nullptr, nullptr, nullptr); pkey = evp_pkey_generate(rsa); +#endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ BIO_free(buf); return pkey; } @@ -5317,10 +5411,16 @@ static EVP_PKEY *x509_key_read(const Sql_string_t &input_string) { static Sql_string_t x509_key_write(EVP_PKEY *pkey) { assert(pkey); BIO *buf = BIO_new(BIO_s_mem()); - RSA *rsa = EVP_PKEY_get1_RSA(pkey); Sql_string_t read_buffer; + +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + if (PEM_write_bio_PrivateKey(buf, pkey, nullptr, nullptr, 10, nullptr, + nullptr)) { +#else /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ + RSA *rsa = EVP_PKEY_get1_RSA(pkey); if (PEM_write_bio_RSAPrivateKey(buf, rsa, nullptr, nullptr, 10, nullptr, nullptr)) { +#endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ size_t len = BIO_pending(buf); if (resize_no_exception(read_buffer, len + 1) == true) { BIO_read(buf, const_cast(read_buffer.c_str()), len); @@ -5328,7 +5428,9 @@ static Sql_string_t x509_key_write(EVP_PKEY *pkey) { } } BIO_free(buf); +#if OPENSSL_VERSION_NUMBER < 0x30000000L RSA_free(rsa); +#endif /* OPENSSL_VERSION_NUMBER < 0x30000000L */ return read_buffer; } @@ -5366,7 +5468,11 @@ bool create_x509_certificate(RSA_generator_func &rsa_gen, const Sql_string_t cn, bool self_sign = true; Sql_string_t ca_key_str; Sql_string_t ca_cert_str; +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + EVP_PKEY *rsa = nullptr; +#else /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ RSA *rsa = nullptr; +#endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ EVP_PKEY *pkey = nullptr; EVP_PKEY *ca_key = nullptr; X509 *x509 = nullptr; @@ -5382,10 +5488,17 @@ bool create_x509_certificate(RSA_generator_func &rsa_gen, const Sql_string_t cn, /* Generate private key for X509 certificate */ rsa = rsa_gen(); +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + DBUG_EXECUTE_IF("null_rsa_error", { + EVP_PKEY_free(rsa); + rsa = nullptr; + }); +#else /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ DBUG_EXECUTE_IF("null_rsa_error", { RSA_free(rsa); rsa = nullptr; }); +#endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ if (!rsa) { LogErr(ERROR_LEVEL, ER_X509_NEEDS_RSA_PRIVKEY); @@ -5394,7 +5507,11 @@ bool create_x509_certificate(RSA_generator_func &rsa_gen, const Sql_string_t cn, } /* Obtain EVP_PKEY */ +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + pkey = rsa; +#else /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ pkey = evp_pkey_generate(rsa); +#endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ /* Write private key information to file and set file permission */ (*x509_key_file_ostream) << x509_key_write(pkey); @@ -5511,11 +5628,24 @@ bool create_RSA_key_pair(RSA_generator_func &rsa_gen, assert(priv_key_filename.size() && pub_key_filename.size()); - RSA *rsa = rsa_gen(); +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + EVP_PKEY *rsa; +#else /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ + RSA *rsa; +#endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ + rsa = rsa_gen(); + +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + DBUG_EXECUTE_IF("null_rsa_error", { + EVP_PKEY_free(rsa); + rsa = nullptr; + }); +#else /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ DBUG_EXECUTE_IF("null_rsa_error", { RSA_free(rsa); rsa = nullptr; }); +#endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ if (!rsa) { LogErr(ERROR_LEVEL, ER_AUTH_CANT_CREATE_RSA_PAIR); @@ -5559,7 +5689,12 @@ bool create_RSA_key_pair(RSA_generator_func &rsa_gen, } end: - if (rsa) RSA_free(rsa); + if (rsa) +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + EVP_PKEY_free(rsa); +#else /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ + RSA_free(rsa); +#endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ umask(saved_umask); return ret_val; diff --git a/sql/auth/sql_authentication.h b/sql/auth/sql_authentication.h index 0b102944ec4b..09af0893afd3 100644 --- a/sql/auth/sql_authentication.h +++ b/sql/auth/sql_authentication.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2000, 2022, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, version 2.0, @@ -102,15 +102,26 @@ int show_rsa_public_key(THD *thd, SHOW_VAR *var, char *buff); typedef struct rsa_st RSA; class Rsa_authentication_keys { private: +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + EVP_PKEY *m_public_key; + EVP_PKEY *m_private_key; +#else /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ RSA *m_public_key; RSA *m_private_key; +#endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ int m_cipher_len; char *m_pem_public_key; char **m_private_key_path; char **m_public_key_path; void get_key_file_path(char *key, String *key_file_path); + +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + bool read_key_file(EVP_PKEY **key_ptr, bool is_priv_key, + char **key_text_buffer); +#else /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ bool read_key_file(RSA **key_ptr, bool is_priv_key, char **key_text_buffer); +#endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ public: Rsa_authentication_keys(char **private_key_path, char **public_key_path) @@ -124,9 +135,14 @@ class Rsa_authentication_keys { void free_memory(); void *allocate_pem_buffer(size_t buffer_len); - RSA *get_private_key() { return m_private_key; } +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + EVP_PKEY *get_private_key() { return m_private_key; } + EVP_PKEY *get_public_key() { return m_public_key; } +#else /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ + RSA *get_private_key() { return m_private_key; } RSA *get_public_key() { return m_public_key; } +#endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ int get_cipher_length(); bool read_rsa_keys(); diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 028bac97f212..a2a10309255e 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -876,6 +876,7 @@ MySQL clients support the protocol: #include "thr_mutex.h" #include "typelib.h" #include "violite.h" +#include "my_openssl_fips.h" // OPENSSL_ERROR_LENGTH, set_fips_mode #ifdef WITH_PERFSCHEMA_STORAGE_ENGINE #include "storage/perfschema/pfs_server.h" @@ -5328,8 +5329,7 @@ static void init_ssl() { static int init_ssl_communication() { char ssl_err_string[OPENSSL_ERROR_LENGTH] = {'\0'}; - int ret_fips_mode = set_fips_mode(opt_ssl_fips_mode, ssl_err_string); - if (ret_fips_mode != 1) { + if (set_fips_mode(opt_ssl_fips_mode, ssl_err_string)) { LogErr(ERROR_LEVEL, ER_SSL_FIPS_MODE_ERROR, ssl_err_string); return 1; } diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc index eb3f577fe073..0ad869ebc8cc 100644 --- a/sql/sys_vars.cc +++ b/sql/sys_vars.cc @@ -141,6 +141,7 @@ #ifdef _WIN32 #include "sql/named_pipe.h" #endif +#include "my_openssl_fips.h" #ifdef WITH_LOCK_ORDER #include "sql/debug_lock_order.h" @@ -4958,9 +4959,15 @@ static Sys_var_ulong Sys_max_execution_time( static bool update_fips_mode(sys_var *, THD *, enum_var_type) { char ssl_err_string[OPENSSL_ERROR_LENGTH] = {'\0'}; - if (set_fips_mode(opt_ssl_fips_mode, ssl_err_string) != 1) { + if (set_fips_mode(opt_ssl_fips_mode, ssl_err_string)) { opt_ssl_fips_mode = get_fips_mode(); - my_error(ER_DA_SSL_FIPS_MODE_ERROR, MYF(0), "Openssl is not fips enabled"); + std::string err; + if (ssl_err_string[0]) { + err.append("Openssl is not fips enabled. Error: "); + err.append(ssl_err_string); + } else + err.append("Openssl is not fips enabled"); + my_error(ER_DA_SSL_FIPS_MODE_ERROR, MYF(0), err.c_str()); return true; } else { return false; diff --git a/vio/viossl.cc b/vio/viossl.cc index 667f15465ae9..46d1eb28b8b2 100644 --- a/vio/viossl.cc +++ b/vio/viossl.cc @@ -129,7 +129,11 @@ static void report_errors(SSL *ssl) { DBUG_TRACE; +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + while ((l = ERR_get_error_all(&file, &line, nullptr, &data, &flags))) { +#else /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ while ((l = ERR_get_error_line_data(&file, &line, &data, &flags))) { +#endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ DBUG_PRINT("error", ("OpenSSL: %s:%s:%d:%s\n", ERR_error_string(l, buf), file, line, (flags & ERR_TXT_STRING) ? data : "")); } @@ -262,6 +266,11 @@ size_t vio_ssl_read(Vio *vio, uchar *buf, size_t size) { DBUG_TRACE; +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + // TODO: find out which of the openssl 3 functions makes this a requirement + ERR_clear_error(); +#endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ + while (true) { enum enum_vio_io_event event; @@ -304,6 +313,11 @@ size_t vio_ssl_write(Vio *vio, const uchar *buf, size_t size) { DBUG_TRACE; +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + // TODO: find out which of the openssl 3 functions makes this a requirement + ERR_clear_error(); +#endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ + while (true) { enum enum_vio_io_event event; @@ -416,6 +430,11 @@ static size_t ssl_handshake_loop(Vio *vio, SSL *ssl, ssl_handshake_func_t func, vio->ssl_arg = ssl; +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + // TODO: find out which of the openssl 3 functions makes this a requirement + ERR_clear_error(); +#endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ + /* Initiate the SSL handshake. */ while (true) { enum enum_vio_io_event event; diff --git a/vio/viosslfactories.cc b/vio/viosslfactories.cc index 4b2aeb42ad30..2a544b9a3b24 100644 --- a/vio/viosslfactories.cc +++ b/vio/viosslfactories.cc @@ -45,6 +45,7 @@ #include #endif /* OPENSSL_VERSION_NUMBER < 0x10002000L */ +#include "my_openssl_fips.h" #define TLS_VERSION_OPTION_SIZE 256 /* @@ -138,6 +139,7 @@ static const char tls_cipher_blocked[] = { static bool ssl_initialized = false; +#if OPENSSL_VERSION_NUMBER < 0x30000000L /* Diffie-Hellman key. Generated using: >openssl dhparam -5 -C 2048 @@ -201,6 +203,7 @@ static DH *get_dh2048() { } return (dh); } +#endif /* OPENSSL_VERSION_NUMBER < 0x30000000L */ static void report_errors() { unsigned long l; @@ -210,9 +213,13 @@ static void report_errors() { DBUG_TRACE; +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + while ((l = ERR_get_error_all(&file, &line, nullptr, &data, &flags))) { +#else /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ while ((l = ERR_get_error_line_data(&file, &line, &data, &flags)) > 0) { +#endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ #ifndef NDEBUG /* Avoid warning */ - char buf[200]; + char buf[512]; DBUG_PRINT("error", ("OpenSSL: %s:%s:%d:%s\n", ERR_error_string(l, buf), file, line, (flags & ERR_TXT_STRING) ? data : "")); #endif @@ -437,6 +444,7 @@ static void deinit_lock_callback_functions() { void vio_ssl_end() { if (ssl_initialized) { + fips_deinit(); #if OPENSSL_VERSION_NUMBER < 0x10100000L ERR_remove_thread_state(0); #endif /* OPENSSL_VERSION_NUMBER < 0x10100000L */ @@ -461,6 +469,7 @@ void ssl_start() { if (!ssl_initialized) { ssl_initialized = true; + fips_init(); SSL_library_init(); OpenSSL_add_all_algorithms(); SSL_load_error_strings(); @@ -472,75 +481,6 @@ void ssl_start() { } } -/** - Set fips mode in openssl library, - When we set fips mode ON/STRICT, it will perform following operations: - 1. Check integrity of openssl library - 2. Run fips related tests. - 3. Disable non fips complaint algorithms - 4. Should be set par process before openssl library initialization - 5. When FIPs mode ON(1/2), calling weak algorithms may results into process - abort. - - @param [in] fips_mode 0 for fips mode off, 1/2 for fips mode ON - @param [out] err_string If fips mode set fails, err_string will have detail - failure reason. - - @returns openssl set fips mode errors - @retval non 1 for Error - @retval 1 Success -*/ -int set_fips_mode(const uint fips_mode, char err_string[OPENSSL_ERROR_LENGTH]) { - int rc = -1; - unsigned int fips_mode_old = -1; - unsigned long err_library = 0; - if (fips_mode > 2) { - goto EXIT; - } - fips_mode_old = FIPS_mode(); - if (fips_mode_old == fips_mode) { - rc = 1; - goto EXIT; - } - if (!(rc = FIPS_mode_set(fips_mode))) { - /* - If OS doesn't have FIPS enabled openssl library and user sets FIPS mode - ON, It fails with proper error. But in the same time it doesn't allow to - perform any cryptographic operation. Now if FIPS mode set fails with - error, setting old working FIPS mode value in the OpenSSL library. It will - allow successful cryptographic operation and will not abort the server. - */ - FIPS_mode_set(fips_mode_old); - err_library = ERR_get_error(); - ERR_error_string_n(err_library, err_string, OPENSSL_ERROR_LENGTH - 1); - err_string[OPENSSL_ERROR_LENGTH - 1] = '\0'; - } -EXIT: - return rc; -} - -/** - Get fips mode from openssl library, - - @returns openssl current fips mode -*/ -uint get_fips_mode() { return FIPS_mode(); } - -/** - Toggle FIPS mode, to see whether it is available with the current SSL library. - @retval 0 FIPS is not supported. - @retval non-zero: FIPS is supported. -*/ -int test_ssl_fips_mode(char *err_string) { - int ret = FIPS_mode_set(FIPS_mode() == 0 ? 1 : 0); - unsigned long err = (ret == 0) ? ERR_get_error() : 0; - - if (err != 0) { - ERR_error_string_n(err, err_string, OPENSSL_ERROR_LENGTH - 1); - } - return ret; -} - long process_tls_version(const char *tls_version) { const char *separator = ","; char *token, *lasts = nullptr; @@ -592,7 +532,6 @@ static struct st_VioSSLFd *new_VioSSLFd( const char *ciphersuites [[maybe_unused]], bool is_client, enum enum_ssl_init_error *error, const char *crl_file, const char *crl_path, const long ssl_ctx_flags, const char *server_host [[maybe_unused]]) { - DH *dh; struct st_VioSSLFd *ssl_fd; long ssl_ctx_options = SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1; @@ -736,13 +675,23 @@ static struct st_VioSSLFd *new_VioSSLFd( } /* DH stuff */ - dh = get_dh2048(); - if (SSL_CTX_set_tmp_dh(ssl_fd->ssl_context, dh) == 0) { - DH_free(dh); +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + if (SSL_CTX_set_dh_auto(ssl_fd->ssl_context, 1) != 1) { *error = SSL_INITERR_DHFAIL; goto error; } - DH_free(dh); +#else /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ + { + DH *dh = get_dh2048(); + + if (SSL_CTX_set_tmp_dh(ssl_fd->ssl_context, dh) == 0) { + DH_free(dh); + *error = SSL_INITERR_DHFAIL; + goto error; + } + DH_free(dh); + } +#endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ /* ECDH stuff */ #if OPENSSL_VERSION_NUMBER < 0x10002000L @@ -786,7 +735,7 @@ static struct st_VioSSLFd *new_VioSSLFd( } } } -#endif +#endif /* OPENSSL_VERSION_NUMBER >= 0x10002000L */ SSL_CTX_set_options(ssl_fd->ssl_context, ssl_ctx_options);