From d786bf9fbfba7848ba917f393924de3b84cd8400 Mon Sep 17 00:00:00 2001 From: Paritosh Kumar Date: Wed, 13 Mar 2024 02:40:13 -0700 Subject: [PATCH] Consistently load OpenSSL libraries among different platforms As part of this pull request, these changes are performed: - Allow loading specific user-defined OpenSSL library using the -Djdk.native.openssl.lib option. - OpenSSL library loading is consolidated into a single file using ifdefs. - The platform-specific MD files are no longer needed and are thus deleted. - Additional traces are added to indicate the attempts and actual OpenSSL library loaded. - The location of the library loaded is printed. Moreover, the order of preference for loading a library is updated to follow this order: 1. Explicitly load what was specified via JVM property. Fail if loading fails. 2. Search within the Semeru directories for a bundled version. 3. Search the system for existing libraries and attempt to find the higher version. 4. If all of the previous steps fail, revert to original Java implementation for crypto. Co-authored by: Paritosh Kumar Co-authored by: Kostas Tsiounis Signed-off-by: Kostas Tsiounis --- .../aix/native/libjncrypto/NativeCrypto_md.c | 84 ---- .../native/libjncrypto/NativeCrypto_md.c | 75 --- .../jdk/crypto/jniprovider/NativeCrypto.java | 38 +- .../share/native/libjncrypto/NativeCrypto.c | 458 ++++++++++++++++-- .../native/libjncrypto/NativeCrypto_md.h | 35 -- .../unix/native/libjncrypto/NativeCrypto_md.c | 81 ---- .../native/libjncrypto/NativeCrypto_md.c | 67 --- 7 files changed, 436 insertions(+), 402 deletions(-) delete mode 100644 closed/src/java.base/aix/native/libjncrypto/NativeCrypto_md.c delete mode 100644 closed/src/java.base/macosx/native/libjncrypto/NativeCrypto_md.c delete mode 100644 closed/src/java.base/share/native/libjncrypto/NativeCrypto_md.h delete mode 100644 closed/src/java.base/unix/native/libjncrypto/NativeCrypto_md.c delete mode 100644 closed/src/java.base/windows/native/libjncrypto/NativeCrypto_md.c diff --git a/closed/src/java.base/aix/native/libjncrypto/NativeCrypto_md.c b/closed/src/java.base/aix/native/libjncrypto/NativeCrypto_md.c deleted file mode 100644 index 440fea8e0f5..00000000000 --- a/closed/src/java.base/aix/native/libjncrypto/NativeCrypto_md.c +++ /dev/null @@ -1,84 +0,0 @@ -/* - * =========================================================================== - * (c) Copyright IBM Corp. 2019, 2023 All Rights Reserved - * =========================================================================== - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * IBM designates this particular file as subject to the "Classpath" exception - * as provided by IBM in the LICENSE file that accompanied this code. - * - * This code 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 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, see . - * - * =========================================================================== - */ - -#include -#include -#include -#include -#include -#include "NativeCrypto_md.h" - -/* Load the crypto library (return NULL on error) */ -void * load_crypto_library(jboolean traceEnabled) { - void * result = NULL; - const char *libname3_a_64 = "libcrypto.a(libcrypto64.so.3)"; - const char *libname3_64 = "libcrypto64.so.3"; - const char *libname3_a = "libcrypto.a(libcrypto.so.3)"; - const char *libname3 = "libcrypto.so.3"; - const char *libname111 = "libcrypto.a(libcrypto64.so.1.1)"; - const char *libname110 = "libcrypto.so.1.1"; - const char *libname102 = "libcrypto.so.1.0.0"; - const char *symlink = "libcrypto.a(libcrypto64.so)"; - - result = dlopen (libname3_a_64, RTLD_NOW | RTLD_MEMBER); - if (result == NULL) { - result = dlopen (libname3_64, RTLD_NOW); - if (result == NULL) { - result = dlopen (libname3_a, RTLD_NOW | RTLD_MEMBER); - if (result == NULL) { - result = dlopen (libname3, RTLD_NOW); - if (result == NULL) { - result = dlopen (libname111, RTLD_NOW | RTLD_MEMBER); - if (result == NULL) { - result = dlopen (libname110, RTLD_NOW); - if (result == NULL) { - result = dlopen (libname102, RTLD_NOW); - if (result == NULL) { - result = dlopen (symlink, RTLD_NOW | RTLD_MEMBER); - } - } - } - } - } - } - } - return result; -} - -/* Unload the crypto library */ -void unload_crypto_library(void *handle) { - (void)dlclose(handle); -} - -/* Find the symbol in the crypto library (return NULL if not found) */ -void * find_crypto_symbol(void *handle, const char *symname) { - return dlsym(handle, symname); -} - -/* Find the path that the library was loaded from */ -void get_library_path(void * handle, char * library_path) { - /* There doesnt seem to be an easy way to find */ - /* the library path, so return "Unknown path" */ - strcpy(library_path, "Unknown path"); -} diff --git a/closed/src/java.base/macosx/native/libjncrypto/NativeCrypto_md.c b/closed/src/java.base/macosx/native/libjncrypto/NativeCrypto_md.c deleted file mode 100644 index d0e361760ec..00000000000 --- a/closed/src/java.base/macosx/native/libjncrypto/NativeCrypto_md.c +++ /dev/null @@ -1,75 +0,0 @@ -/* - * =========================================================================== - * (c) Copyright IBM Corp. 2019, 2023 All Rights Reserved - * =========================================================================== - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * IBM designates this particular file as subject to the "Classpath" exception - * as provided by IBM in the LICENSE file that accompanied this code. - * - * This code 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 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, see . - * - * =========================================================================== - */ - -#include -#include -#include -#include -#include -#include "NativeCrypto_md.h" - -/* Load the crypto library (return NULL on error) */ -void * load_crypto_library(jboolean traceEnabled) { - void * result = NULL; - - const char *libname3 = "libcrypto.3.dylib"; - const char *libname = "libcrypto.1.1.dylib"; - const char *oldname = "libcrypto.1.0.0.dylib"; - const char *symlink = "libcrypto.dylib"; - - result = dlopen (libname3, RTLD_NOW); - if (result == NULL) { - result = dlopen (libname, RTLD_NOW); - if (result == NULL) { - result = dlopen (oldname, RTLD_NOW); - if (result == NULL) { - result = dlopen (symlink, RTLD_NOW); - } - } - } - - return result; -} - -/* Unload the crypto library */ -void unload_crypto_library(void *handle) { - (void)dlclose(handle); -} - -/* Find the symbol in the crypto library (return NULL if not found) */ -void * find_crypto_symbol(void *handle, const char *symname) { - return dlsym(handle, symname); -} - -/* Find the path that the library was loaded from */ -void get_library_path(void * handle, char * library_path) { - Dl_info info; - // Load binary path information from dlinfo() API if available, - // else return "Unknown path" - if (dladdr(handle, &info)) { - strcpy(library_path, info.dli_fname); - } else { - strcpy(library_path, "Unknown path"); - } -} diff --git a/closed/src/java.base/share/classes/jdk/crypto/jniprovider/NativeCrypto.java b/closed/src/java.base/share/classes/jdk/crypto/jniprovider/NativeCrypto.java index 096af2951ed..59b3dd5c013 100644 --- a/closed/src/java.base/share/classes/jdk/crypto/jniprovider/NativeCrypto.java +++ b/closed/src/java.base/share/classes/jdk/crypto/jniprovider/NativeCrypto.java @@ -32,6 +32,7 @@ import jdk.internal.ref.CleanerFactory; import jdk.internal.reflect.Reflection; import jdk.internal.reflect.CallerSensitive; +import jdk.internal.util.StaticProperty; /*[IF CRIU_SUPPORT]*/ import openj9.internal.criu.InternalCRIUSupport; @@ -79,16 +80,30 @@ private static final class InstanceHolder { private final boolean isOpenSSLFIPS; + @SuppressWarnings("restricted") private static long loadCryptoLibraries() { long osslVersion; try { - // load jncrypto JNI library + // Load jncrypto JNI library. System.loadLibrary("jncrypto"); - // load OpenSSL crypto library dynamically - osslVersion = loadCrypto(traceEnabled); - if (traceEnabled && (osslVersion != -1)) { - System.err.println("Native crypto library load succeeded - using native crypto library."); + + // Get user-specified OpenSSL library to use, if available. + String nativeLibName = System.getProperty("jdk.native.openssl.lib", ""); + + // Get the JDK location. + String javaHome = StaticProperty.javaHome(); + + // Load OpenSSL crypto library dynamically. + osslVersion = loadCrypto(traceEnabled, nativeLibName, javaHome); + if (osslVersion != -1) { + if (traceEnabled) { + System.err.println("Native crypto library load succeeded - using native crypto library."); + } + } else { + if (!nativeLibName.isEmpty()) { + throw new RuntimeException(nativeLibName + " is not available, crypto libraries are not loaded"); + } } } catch (UnsatisfiedLinkError usle) { if (traceEnabled) { @@ -96,7 +111,7 @@ private static long loadCryptoLibraries() { System.err.println("Warning: Native crypto library load failed." + " Using Java crypto implementation."); } - // signal load failure + // Signal load failure. osslVersion = -1; } return osslVersion; @@ -157,8 +172,7 @@ public static final long getVersionIfAvailable() { public static final boolean isAlgorithmEnabled(String property, String name) { boolean useNativeAlgorithm = false; if (useNativeCrypto) { - useNativeAlgorithm = Boolean.parseBoolean( - System.getProperty(property, "true")); + useNativeAlgorithm = Boolean.parseBoolean(System.getProperty(property, "true")); } /* * User wants to use the native crypto implementation. Ensure that the native crypto library is enabled. @@ -251,14 +265,18 @@ public void run() { }); } - /* Native digest interfaces */ + /* OpenSSL utility interfaces */ - private static final native long loadCrypto(boolean trace); + private static final native long loadCrypto(boolean trace, + String libName, + String javaHome); public static final native boolean isMD5Available(); private static final native boolean isOpenSSLFIPS(); + /* Native digest interfaces */ + public final native long DigestCreateContext(long nativeBuffer, int algoIndex); diff --git a/closed/src/java.base/share/native/libjncrypto/NativeCrypto.c b/closed/src/java.base/share/native/libjncrypto/NativeCrypto.c index 2e53d0a8e1e..9d6af85ca64 100644 --- a/closed/src/java.base/share/native/libjncrypto/NativeCrypto.c +++ b/closed/src/java.base/share/native/libjncrypto/NativeCrypto.c @@ -22,6 +22,20 @@ * =========================================================================== */ +#if defined(_AIX) +#include +#include +#define DLFCN_LDINFO_SIZE (sizeof(struct ld_info) + _XOPEN_PATH_MAX + _XOPEN_NAME_MAX) +#elif defined(__APPLE__) /* defined(_AIX) */ +#include +#include +#elif defined(__linux__) /* defined(__APPLE__) */ +#include +#include +#elif defined(_WIN32) /* defined(__linux__) */ +#include +#endif /* defined(_AIX) */ + #include #include #include @@ -37,7 +51,6 @@ #include #include "jdk_crypto_jniprovider_NativeCrypto.h" -#include "NativeCrypto_md.h" #define OPENSSL_VERSION_CODE(major, minor, fix, patch) \ ((((jlong)(major)) << 28) | ((minor) << 20) | ((fix) << 12) | (patch)) @@ -64,6 +77,11 @@ # include #endif /* defined(WINDOWS) */ +/* Header for NativeCrypto loading methods. */ +static void * find_crypto_symbol(void *handle, const char *symname); +static void * find_crypto_library(jboolean traceEnabled, const char *chomepath); +static void unload_crypto_library(void *handle); + /* Header for RSA algorithm using 1.0.2 OpenSSL. */ int OSSL102_RSA_set0_key(RSA *, BIGNUM *, BIGNUM *, BIGNUM *); int OSSL102_RSA_set0_factors(RSA *, BIGNUM *, BIGNUM *); @@ -380,30 +398,114 @@ JNIEXPORT jboolean JNICALL Java_jdk_crypto_jniprovider_NativeCrypto_isOpenSSLFIP return OSSL_IS_FIPS; } -/* - * Class: jdk_crypto_jniprovider_NativeCrypto - * Method: loadCrypto - * Signature: (Z)J - */ -JNIEXPORT jlong JNICALL Java_jdk_crypto_jniprovider_NativeCrypto_loadCrypto - (JNIEnv *env, jclass thisObj, jboolean trace) +/* Unload the crypto library. */ +static void +unload_crypto_library(void *crypto_library) { - typedef const char* OSSL_version_t(int); +#if defined(_WIN32) + FreeLibrary(crypto_library); +#else /* defined(_WIN32) */ + (void)dlclose(crypto_library); +#endif /* defined(_WIN32) */ +} - /* Determine the version of OpenSSL. */ - OSSL_version_t* OSSL_version; - const char * openssl_version; - jlong ossl_ver = 0; +/* Find the symbol in the crypto library (return NULL if not found). */ +static void * +find_crypto_symbol(void *crypto_library, const char *symname) +{ +#if defined(_WIN32) + return GetProcAddress(crypto_library, symname); +#else /* defined(_WIN32) */ + return dlsym(crypto_library, symname); +#endif /* defined(_WIN32) */ +} - /* Load OpenSSL Crypto library */ - crypto_library = load_crypto_library(trace); - if (NULL == crypto_library) { - if (trace) { - fprintf(stderr, "Error loading OpenSSL: FAILED TO LOAD OPENSSL CRYPTO LIBRARY\n"); - fflush(stderr); +static void +log_crypto_library_path(jboolean traceEnabled, void *crypto_library, const char *message) +{ + if (traceEnabled && (NULL != crypto_library)) { +#if defined(_AIX) + int rc = 0; + /* Initialize the buffer with maximum size for L_GETINFO. */ + char *buffer = (char *)malloc(DLFCN_LDINFO_SIZE); + if (NULL == buffer) { + return; } - return -1; + /* Get the list of all object files loaded by this process. */ + rc = loadquery(L_GETINFO, buffer, DLFCN_LDINFO_SIZE); + + /* Parse the list of all object files and print the OPENSSL library path. */ + if (0 == rc) { + char *buf = buffer; + for (;;) { + struct ld_info *cur_info = (struct ld_info *)buf; + const char *path = cur_info->ldinfo_filename; + const char *member_name = path + strlen(cur_info->ldinfo_filename) + 1; + if (('\0' != *member_name) && (NULL != strstr(path, "/libcrypto"))) { + fprintf(stdout, "%s: %s(%s)\n", message, path, member_name); + fflush(stdout); + break; + } + if (0 == cur_info->ldinfo_next) { + break; + } + buf += cur_info->ldinfo_next; + } + } + free(buffer); +#elif defined(__APPLE__) /* defined(_AIX) */ + /* Since we know the image we want will always be near the end of the list, start there and go backwards. */ + uint32_t i = _dyld_image_count() - 1; + for (; i >= 0; i--) { + const char *image_name = _dyld_get_image_name(i); + void *probe_handle = NULL; + jboolean same_handle = JNI_FALSE; + if (NULL == image_name) { + continue; + } + + /* Why dlopen doesn't affect _dyld stuff: if an image is already loaded, it returns the existing handle. */ + probe_handle = dlopen(image_name, RTLD_LAZY); + if (NULL == probe_handle) { + continue; + } + if (crypto_library == probe_handle) { + same_handle = JNI_TRUE; + } + dlclose(probe_handle); + + if (same_handle) { + fprintf(stdout, "OpenSSL was loaded from - %s\n", image_name); + fflush(stdout); + break; + } + } +#elif defined(_WIN32) /* defined(__APPLE__) */ + char path[MAX_PATH]; + DWORD written = GetModuleFileName(crypto_library, path, MAX_PATH); + if (0 != written) { + fprintf(stdout, "OpenSSL was loaded from - %s\n", path); + fflush(stdout); + } +#else /* defined(_WIN32) */ + struct link_map *map = NULL; + int ret = dlinfo(crypto_library, RTLD_DI_LINKMAP, &map); + if ((0 == ret) && (NULL != map)) { + fprintf(stdout, "OpenSSL was loaded from - %s\n", map->l_name); + fflush(stdout); + } +#endif /* defined(_AIX) */ } +} + +/* Get the version for the crypto library. */ +static jlong +get_crypto_library_version(jboolean traceEnabled, void *crypto_library, const char *message) +{ + typedef const char *OSSL_version_t(int); + OSSL_version_t *OSSL_version = NULL; + const char *openssl_version = NULL; + jlong ossl_ver = 0; /* * Different symbols are used by OpenSSL with 1.0 and 1.1 and later. @@ -417,7 +519,7 @@ JNIEXPORT jlong JNICALL Java_jdk_crypto_jniprovider_NativeCrypto_loadCrypto OSSL_version = (OSSL_version_t*)find_crypto_symbol(crypto_library, "SSLeay_version"); if (NULL == OSSL_version) { - if (trace) { + if (traceEnabled) { fprintf(stderr, "Error loading OpenSSL: Error finding the OpenSSL version symbol in the crypto library\n"); fflush(stderr); } @@ -429,7 +531,7 @@ JNIEXPORT jlong JNICALL Java_jdk_crypto_jniprovider_NativeCrypto_loadCrypto /* Ensure the OpenSSL version is "OpenSSL 1.0.x" */ ossl_ver = extractVersionToJlong(openssl_version); if (!((OPENSSL_VERSION_1_0_0 <= ossl_ver) && (ossl_ver < OPENSSL_VERSION_1_1_0))) { - if (trace) { + if (traceEnabled) { fprintf(stderr, "Error loading OpenSSL: Incompatible OpenSSL version found: %s\n", openssl_version); fflush(stderr); } @@ -442,10 +544,10 @@ JNIEXPORT jlong JNICALL Java_jdk_crypto_jniprovider_NativeCrypto_loadCrypto openssl_version = (*OSSL_version)(0); /* get OPENSSL_VERSION */ /* Ensure the OpenSSL version is "OpenSSL 1.1.x" or "OpenSSL 3.x.x". */ ossl_ver = extractVersionToJlong(openssl_version); - if (!((OPENSSL_VERSION_1_1_0 <= ossl_ver) && (ossl_ver < OPENSSL_VERSION_2_0_0)) - && !((OPENSSL_VERSION_3_0_0 <= ossl_ver) && (ossl_ver < OPENSSL_VERSION_4_0_0)) + if (!(((OPENSSL_VERSION_1_1_0 <= ossl_ver) && (ossl_ver < OPENSSL_VERSION_2_0_0)) + || ((OPENSSL_VERSION_3_0_0 <= ossl_ver) && (ossl_ver < OPENSSL_VERSION_4_0_0))) ) { - if (trace) { + if (traceEnabled) { fprintf(stderr, "Error loading OpenSSL: Incompatible OpenSSL version found: %s\n", openssl_version); fflush(stderr); } @@ -474,12 +576,272 @@ JNIEXPORT jlong JNICALL Java_jdk_crypto_jniprovider_NativeCrypto_loadCrypto } } + if (traceEnabled) { + fprintf(stdout, "%s: %s\n", message, openssl_version); + fflush(stdout); + } + + return ossl_ver; +} + +static void * +load_crypto_library(jboolean traceEnabled, const char *libName) +{ + void *result = NULL; + if ((NULL != libName) && ('\0' != *libName)) { +#if defined(_AIX) + int flags = RTLD_NOW; + if (NULL != strrchr(libName, '(')) { + flags |= RTLD_MEMBER; + } + result = dlopen(libName, flags); +#elif defined(_WIN32) /* defined(_AIX) */ + result = LoadLibrary(libName); +#else /* defined(_WIN32) */ + result = dlopen(libName, RTLD_NOW); +#endif /* defined(_AIX) */ + } + return result; +} + +/* Look for a crypto library in java.home or the system. + * NULL is returned when an appropriate crypto library + * cannot be found. + */ +static void * +find_crypto_library(jboolean traceEnabled, const char *chomepath) +{ + void *result = NULL; + void *prevResult = NULL; + size_t numOfLibs = 0; + size_t i = 0; + long tempVersion = 0; + long previousVersion = 0; + size_t num_of_generic = 0; + +#if defined(_AIX) + num_of_generic = 4; +#elif defined(__linux__) /* defined(_AIX) */ + num_of_generic = 1; +#endif /* defined(_AIX) */ + + /* Library names for OpenSSL 1.1.1, 1.1.0 and symbolic links: + * It is important to preserve the order!!! + * + * Since there is no indication of the version of a symlink, + * they have to be loaded first, so as to compare with other + * available options. + * + * The rest of the libraries are listed in descending order, + * which allows us to do two things: + * - Stop if a general symlink is loaded and we then find a + * specific version that is higher. + * - Stop immediately if a specific version is loaded, as + * anything after that will be a lower version. + */ + static const char * const libNames[] = { +#if defined(_AIX) + "libcrypto.a(libcrypto64.so)", /* general symlink library name from archive file */ + "libcrypto64.so", /* general symlink library name */ + "libcrypto.a(libcrypto.so)", /* general symlink library name from archive file */ + "libcrypto.so", /* general symlink library name */ + "libcrypto.a(libcrypto64.so.3)", /* 3.x library name from archive file */ + "libcrypto64.so.3", /* 3.x library name */ + "libcrypto.a(libcrypto.so.3)", /* 3.x library name from archive file */ + "libcrypto.so.3", /* 3.x library name */ + "libcrypto.a(libcrypto64.so.1.1)", /* 1.1.x library name from archive file */ + "libcrypto.so.1.1", /* 1.1.x library name */ + "libcrypto.so.1.0.0", /* 1.0.x library name */ +#elif defined(__APPLE__) /* defined(_AIX) */ + "libcrypto.3.dylib", /* 3.x library name */ + "libcrypto.1.1.dylib", /* 1.1.x library name */ + "libcrypto.1.0.0.dylib", /* 1.0.x library name */ + /* "libcrypto.dylib" Apple no longer supports loading symlink. */ +#elif defined(_WIN32) /* defined(__APPLE__) */ + "libcrypto-3-x64.dll", /* 3.x library name */ + "libcrypto-1_1-x64.dll", /* 1.1.x library name */ + "libeay32.dll", /* old library name */ +#else /* defined(_WIN32) */ + "libcrypto.so", /* general symlink library name */ + "libcrypto.so.3", /* 3.x library name */ + "libcrypto.so.1.1", /* 1.1.x library name */ + "libcrypto.so.1.0.0", /* 1.0.x library name */ + "libcrypto.so.10", /* old library name */ +#endif /* defined(_AIX) */ + }; + + numOfLibs = sizeof(libNames) / sizeof(libNames[0]); + /* If JAVA_HOME is not null or empty and no library has been loaded yet, try there. */ + if ((NULL != chomepath) && ('\0' != *chomepath) && (NULL == crypto_library)) { + char **libNamesWithPath = malloc(size * sizeof(char *)); + size_t path_len = strlen(chomepath); + char *libPath = malloc(path_len + 16); + strcpy(libPath, chomepath); + /* Append the proper directory using a slash or backslash, depending on the operating system. */ +#if defined(_WIN32) + strcat(libPath, "\\bin\\"); +#else /* defined(_WIN32) */ + strcat(libPath, "/lib/"); +#endif /* defined(_WIN32) */ + if (traceEnabled) { + fprintf(stdout, "Attempting to load library bundled with JDK from: %s\n", libPath); + } + + for (i = 0; i < numOfLibs; i++) { + size_t file_len = strlen(libNames[i]); + /* Allocate memory for the new file name with the path. */ + libNamesWithPath[i] = (char *)malloc((path_len + file_len + 16)); + + if (NULL == libNamesWithPath[i]) { + if (traceEnabled) { + fprintf(stderr, "\tFailed to allocate memory for file name with path.\n"); + } + continue; + } + + strcpy(libNamesWithPath[i], libPath); + strcat(libNamesWithPath[i], libNames[i]); + + /* Load OpenSSL Crypto library bundled with JDK. */ + if (traceEnabled) { + fprintf(stdout, "\tAttempting to load: %s\n", libNames[i]); + } + result = load_crypto_library(traceEnabled, libNamesWithPath[i]); + + if (NULL == result) { + continue; + } + + /* Identify and load the latest version from the potential libraries. + * This logic depends upon the order in which libnames are defined. + * Libraries are listed in descending order w.r.t version. + * Since only one library is bundled with the JDK, once any library is + * loaded, this is the only available and we can stop. + */ + tempVersion = get_crypto_library_version(traceEnabled, result, "\t\tLoaded OpenSSL version"); + if (tempVersion > 0) { + return result; + } + } + } + + /* The attempt to load from property and OpenSSL bundled with JDK failed. + * Try loading the libraries in the order set out above, and retain the latest library. + */ + for (i = 0; i < numOfLibs; i++) { + if (traceEnabled) { + fprintf(stdout, "Attempting to load libname from OS: %s\n", libNames[i]); + } + result = load_crypto_library(traceEnabled, libNames[i]); + + if (NULL == result) { + continue; + } + + /* Identify and load the latest version from the available libraries. + * This logic depends upon the order in which libnames are defined. + * It only loads the libraries which can possibly be the latest versions. + */ + log_crypto_library_path(traceEnabled, result, "\tLibrary to be potentially used was loaded from"); + tempVersion = get_crypto_library_version(traceEnabled, result, "\tLoaded OpenSSL version"); + + if (tempVersion <= 0) { + continue; + } + + if (i >= num_of_generic) { + /* If library checked is not a generic one, there is no need to check further. */ + if (previousVersion > tempVersion) { + unload_crypto_library(result); + return prevResult; + } else { + if (previousVersion != 0) { + unload_crypto_library(prevResult); + } + return result; + } + } else { + /* If library checked is a generic one, we need to keep checking for higher versions. */ + if (tempVersion > previousVersion) { + previousVersion = tempVersion; + prevResult = result; + } + } + } + + /* If we reach here, it means that none of the non-generic libraries + * where found. However, a generic one might have been found in the + * process and, if so, it will be in the prevResult variable. + */ + return prevResult; +} + +/* + * Class: jdk_crypto_jniprovider_NativeCrypto + * Method: loadCrypto + * Signature: (ZLjava/lang/String;Ljava/lang/String;)J + */ +JNIEXPORT jlong JNICALL +Java_jdk_crypto_jniprovider_NativeCrypto_loadCrypto + (JNIEnv * env, jobject jobj, jboolean traceEnabled, jstring jlibname, jstring jhomepath) +{ + const char *clibname = ""; + const char *chomepath = ""; + jlong ossl_ver = 0; + + if (NULL != jlibname) { + clibname = (*env)->GetStringUTFChars(env, jlibname, NULL); + if ('\0' == clibname[0]) { + if (traceEnabled) { + fprintf(stderr, "The jdk.native.openssl.lib property is not set.\n"); + fflush(stderr); + } + } else { + crypto_library = load_crypto_library(traceEnabled, clibname); + if (NULL == crypto_library) { + if (traceEnabled) { + fprintf(stderr, "OpenSSL library specified in jdk.openssl.lib couldn't be loaded.\n"); + fflush(stderr); + } + return -1; + } + } + } + + if (NULL != jhomepath) { + chomepath = (*env)->GetStringUTFChars(env, jhomepath, NULL); + } + + /* If the jdk.native.openssl.lib property was not set, attempt + * to find an OpenSSL library from java.home or OS Library path. + */ + if (NULL == crypto_library) { + crypto_library = find_crypto_library(traceEnabled, chomepath); + } + + (*env)->ReleaseStringUTFChars(env, jlibname, clibname); + (*env)->ReleaseStringUTFChars(env, jhomepath, chomepath); + + /* If an OpenSSL library was not loaded from any of the potential + * sources, fail loading native crypto. + */ + if (NULL == crypto_library) { + if (traceEnabled) { + fprintf(stderr, "FAILED TO LOAD OPENSSL CRYPTO LIBRARY\n"); + fflush(stderr); + } + return -1; + } + + log_crypto_library_path(traceEnabled, crypto_library, "OpenSSL to be used was loaded from"); + ossl_ver = get_crypto_library_version(traceEnabled, crypto_library, "Version of OpenSSL library that is used"); + /* Load the function symbols for OpenSSL errors. */ OSSL_error_string_n = (OSSL_error_string_n_t*)find_crypto_symbol(crypto_library, "ERR_error_string_n"); OSSL_error_string = (OSSL_error_string_t*)find_crypto_symbol(crypto_library, "ERR_error_string"); OSSL_get_error = (OSSL_get_error_t*)find_crypto_symbol(crypto_library, "ERR_get_error"); - /* Load Threading routines for OpenSSL 1.0.2 */ + /* Load Threading routines for OpenSSL 1.0.2. */ if (ossl_ver < OPENSSL_VERSION_1_1_0) { OSSL_CRYPTO_num_locks = (OSSL_CRYPTO_num_locks_t*)find_crypto_symbol(crypto_library, "CRYPTO_num_locks"); OSSL_CRYPTO_THREADID_set_numeric = (OSSL_CRYPTO_THREADID_set_numeric_t*)find_crypto_symbol(crypto_library, "CRYPTO_THREADID_set_numeric"); @@ -763,30 +1125,26 @@ JNIEXPORT jlong JNICALL Java_jdk_crypto_jniprovider_NativeCrypto_loadCrypto ((NULL == OSSL_CRYPTO_THREADID_set_callback) && (ossl_ver < OPENSSL_VERSION_1_1_0)) || ((NULL == OSSL_CRYPTO_set_locking_callback) && (ossl_ver < OPENSSL_VERSION_1_1_0)) ) { - if (trace) { - fprintf(stderr, "Error loading OpenSSL: One or more of the required symbols are missing in the crypto library: %s\n", openssl_version); + if (traceEnabled) { + fprintf(stderr, "Error loading OpenSSL: One or more of the required symbols are missing."); } unload_crypto_library(crypto_library); crypto_library = NULL; return -1; } else { - if (trace) { - char *library_path = malloc(4096); - if (NULL == library_path) { - fprintf(stderr, "Using OpenSSL version: %s\n", openssl_version); - } else { - get_library_path(crypto_library, library_path); - fprintf(stderr, "Using OpenSSL version: %s (%s)\n", openssl_version, library_path); - free(library_path); - } - } if (ossl_ver < OPENSSL_VERSION_1_1_0) { if (0 != thread_setup()) { + if (traceEnabled) { + fprintf(stderr, "Error loading OpenSSL: Thread setup was unsuccessful."); + } unload_crypto_library(crypto_library); crypto_library = NULL; return -1; } } + if (traceEnabled) { + fprintf(stderr, "OpenSSL library loaded successfully.\n"); + } return ossl_ver; } } @@ -2015,7 +2373,7 @@ JNIEXPORT jint JNICALL Java_jdk_crypto_jniprovider_NativeCrypto_RSADP } } } - } else { // if verify == kLen + } else { /* if verify == kLen */ for (i = 0; i < verify; i++) { if (kNative[i] != k2[i]) { msg_len = -2; @@ -2531,7 +2889,7 @@ Java_jdk_crypto_jniprovider_NativeCrypto_ECGenerateKeyPair goto cleanup; } - // to translate the public key to java format, we need to extract the public key coordinates: xBN, yBN + /* to translate the public key to java format, we need to extract the public key coordinates: xBN, yBN */ ctx = (*OSSL_BN_CTX_new)(); if (NULL == ctx) { goto cleanup; @@ -2563,7 +2921,7 @@ Java_jdk_crypto_jniprovider_NativeCrypto_ECGenerateKeyPair goto cleanup; } - // to translate the private key to java format, we need the private key BIGNUM + /* to translate the private key to java format, we need the private key BIGNUM */ sBN = (*OSSL_EC_KEY_get0_private_key)(nativeKey); ret = getArrayFromBN(sBN, nativeS, sLen); @@ -3278,13 +3636,13 @@ Java_jdk_crypto_jniprovider_NativeCrypto_ECDSAVerify } if (NULL != signature) { - // The BIGNUM structs will be freed by the signature. + /* The BIGNUM structs will be freed by the signature. */ sBN = NULL; rBN = NULL; (*OSSL_ECDSA_SIG_free)(signature); } - // In case the BIGNUM structs weren't freed by the signature. + /* In case the BIGNUM structs weren't freed by the signature. */ if (NULL != sBN) { (*OSSL_BN_free)(sBN); } @@ -3320,7 +3678,7 @@ Java_jdk_crypto_jniprovider_NativeCrypto_XDHCreateKeys unsigned char *privateKeyArray = NULL; unsigned char *publicKeyArray = NULL; - // Create PKEY (public/private pair) based on curve type (X25519 or X448) + /* Create PKEY (public/private pair) based on curve type (X25519 or X448). */ pctx = (*OSSL_EVP_PKEY_CTX_new_id)(curveType, NULL); if (NULL == pctx) { @@ -3334,7 +3692,7 @@ Java_jdk_crypto_jniprovider_NativeCrypto_XDHCreateKeys goto cleanup; } - // Separate private and public and store into arrays + /* Separate private and public and store into arrays. */ privateKeyArray = (unsigned char *)((*env)->GetPrimitiveArrayCritical(env, privateKey, 0)); if (NULL == privateKeyArray) { goto cleanup; @@ -3403,7 +3761,7 @@ Java_jdk_crypto_jniprovider_NativeCrypto_XDHGenerateSecret goto cleanup; } - // Setup EVP_PKEY instances for user private and peer public keys + /* Setup EVP_PKEY instances for user private and peer public keys. */ pkey = (*OSSL_EVP_PKEY_new_raw_private_key)(curveType, NULL, privateKeyArray, privateKey_len); peerkey = (*OSSL_EVP_PKEY_new_raw_public_key)(curveType, NULL, publicKeyArray, publicKey_len); @@ -3411,23 +3769,23 @@ Java_jdk_crypto_jniprovider_NativeCrypto_XDHGenerateSecret goto cleanup; } - // Create key agreement context + /* Create key agreement context. */ pctx = (*OSSL_EVP_PKEY_CTX_new)(pkey, NULL); if (NULL == pctx) { goto cleanup; } - // Initialize with user private key + /* Initialize with user private key. */ if (0 >= (*OSSL_EVP_PKEY_derive_init)(pctx)) { goto cleanup; } - // Set peer's public key + /* Set peer's public key. */ if (0 >= (*OSSL_EVP_PKEY_derive_set_peer)(pctx, peerkey)) { goto cleanup; } - // Derive shared secret and save in sharedKeyArray + /* Derive shared secret and save in sharedKeyArray. */ sharedKeyArray = (unsigned char *)((*env)->GetPrimitiveArrayCritical(env, sharedKey, 0)); if (NULL == sharedKeyArray) { goto cleanup; diff --git a/closed/src/java.base/share/native/libjncrypto/NativeCrypto_md.h b/closed/src/java.base/share/native/libjncrypto/NativeCrypto_md.h deleted file mode 100644 index b01402ba4dd..00000000000 --- a/closed/src/java.base/share/native/libjncrypto/NativeCrypto_md.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * =========================================================================== - * (c) Copyright IBM Corp. 2019, 2022 All Rights Reserved - * =========================================================================== - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * IBM designates this particular file as subject to the "Classpath" exception - * as provided by IBM in the LICENSE file that accompanied this code. - * - * This code 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 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, see . - * - * =========================================================================== - */ - -#ifndef NATIVECRYPTO_MD_H -#define NATIVECRYPTO_MD_H - -#include - -void * load_crypto_library(jboolean traceEnabled); -void unload_crypto_library(void *handle); -void * find_crypto_symbol(void *handle, const char *symname); -void get_library_path(void * handle, char * library_path); - -#endif /* NATIVECRYPTO_MD_H */ diff --git a/closed/src/java.base/unix/native/libjncrypto/NativeCrypto_md.c b/closed/src/java.base/unix/native/libjncrypto/NativeCrypto_md.c deleted file mode 100644 index a5ed1459456..00000000000 --- a/closed/src/java.base/unix/native/libjncrypto/NativeCrypto_md.c +++ /dev/null @@ -1,81 +0,0 @@ -/* - * =========================================================================== - * (c) Copyright IBM Corp. 2019, 2022 All Rights Reserved - * =========================================================================== - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * IBM designates this particular file as subject to the "Classpath" exception - * as provided by IBM in the LICENSE file that accompanied this code. - * - * This code 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 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, see . - * - * =========================================================================== - */ - -#include -#include -#include -#include -#include -#include -#include "NativeCrypto_md.h" - -/* Load the crypto library (return NULL on error) */ -void * load_crypto_library(jboolean traceEnabled) -{ - void * result = NULL; - size_t i = 0; - - // Library names for OpenSSL 3.x, 1.1.1, 1.1.0, 1.0.2 and symbolic links - static const char * const libNames[] = { - "libcrypto.so.3", // 3.x library name - "libcrypto.so.1.1", // 1.1.x library name - "libcrypto.so.1.0.0", // 1.0.x library name - "libcrypto.so.10", // 1.0.x library name on RHEL - "libcrypto.so" // general symlink library name - }; - - // Check to see if we can load the libraries in the order set out above - for (i = 0; (NULL == result) && (i < sizeof(libNames) / sizeof(libNames[0])); i++) { - const char * libName = libNames[i]; - - // Check to see if we can load the library - result = dlopen (libName, RTLD_NOW); - } - - if (traceEnabled && (NULL != result)) { - struct link_map *map = NULL; - dlinfo(result, RTLD_DI_LINKMAP, &map); - fprintf(stderr, "Attempt to load OpenSSL %s\n", map->l_name); - fflush(stderr); - } - return result; -} - -/* Unload the crypto library */ -void unload_crypto_library(void *handle) { - (void)dlclose(handle); -} - -/* Find the symbol in the crypto library (return NULL if not found) */ -void * find_crypto_symbol(void *handle, const char *symname) { - return dlsym(handle, symname); -} - -/* Find the path that the library was loaded from */ -void get_library_path(void * handle, char * library_path) { - if (0 != dlinfo(handle, RTLD_DI_ORIGIN, library_path)) { - strcpy(library_path, "Unknown path"); - } - -} diff --git a/closed/src/java.base/windows/native/libjncrypto/NativeCrypto_md.c b/closed/src/java.base/windows/native/libjncrypto/NativeCrypto_md.c deleted file mode 100644 index e2f554203a0..00000000000 --- a/closed/src/java.base/windows/native/libjncrypto/NativeCrypto_md.c +++ /dev/null @@ -1,67 +0,0 @@ -/* - * =========================================================================== - * (c) Copyright IBM Corp. 2019, 2023 All Rights Reserved - * =========================================================================== - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * IBM designates this particular file as subject to the "Classpath" exception - * as provided by IBM in the LICENSE file that accompanied this code. - * - * This code 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 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, see . - * - * =========================================================================== - */ - -#include - -#include "NativeCrypto_md.h" - -/* Load the crypto library (return NULL on error) */ -void * load_crypto_library(jboolean traceEnabled) { - void * result = NULL; - const char *libname3 = "libcrypto-3-x64.dll"; - const char *libname = "libcrypto-1_1-x64.dll"; - const char *oldname = "libeay32.dll"; - - result = LoadLibrary(libname3); - if (result == NULL) { - result = LoadLibrary(libname); - if (result == NULL) { - result = LoadLibrary(oldname); - } - } - - return result; -} - -/* Unload the crypto library */ -void unload_crypto_library(void *handle) { - FreeLibrary(handle); -} - -/* Find the symbol in the crypto library (return NULL if not found) */ -void * find_crypto_symbol(void *handle, const char *symname) { - void * symptr; - - symptr = GetProcAddress(handle, symname); - - return symptr; -} - - -/* Find the path that the library was loaded from */ -void get_library_path(void * handle, char * library_path) { - if (0 == GetModuleFileName(handle, library_path, 4096)) { - strcpy(library_path, "Unknown path"); - } -}