Skip to content

Commit

Permalink
CRYPTO-174: Allow override of SSL library name (#269)
Browse files Browse the repository at this point in the history
Add code to allow override of default library name, and implement it for Windows builds
  • Loading branch information
sebbASF authored Nov 8, 2023
1 parent 6feb07d commit 085efe0
Show file tree
Hide file tree
Showing 7 changed files with 53 additions and 32 deletions.
16 changes: 7 additions & 9 deletions .github/workflows/maven.yml
Original file line number Diff line number Diff line change
Expand Up @@ -91,22 +91,20 @@ jobs:
- name: OpenSSL engine (windows)
# need to override the libarary on windows
if: ${{ matrix.os == 'windows-latest' }}
# e.g. ENGINESDIR: "C:\Program Files\OpenSSL\lib\engines-1_1"
# The code below extracts "C:\Program Files\OpenSSL\lib", as expected
# but this does not seem to be the correct setting to override system library
# To avoid failing tests unnecessarily, skip the check for OpenSSL in the library name
# To be resolved...
# N.B. This must *not* be run under the bash shell, as that changes the default openssl library
# e.g. NAME: "libcrypto-1_1-x64.dll"
# Not sure how to derive this automatically
run: |
openssl version -a
chcp 65001 #set code page to utf-8
echo ((openssl version -e) -replace ': "','=' -replace '\\engines-.*','') >> $env:GITHUB_ENV
echo "NAME=libcrypto-1_1-x64.dll" >> $env:GITHUB_ENV
echo "CHECK_SKIP=skip" >> $env:GITHUB_ENV
# N.B. '-V -B -ntp' is shorthand for '--show-version --batch-mode --no-transfer-progress'
#
# The bash shell under Windows changes the openssl default library, so is not used for running tests
# Unfortunately that means separate steps for Windows, as it uses a different syntax for referrring to
# environment variables: $env:VARNAME instead of $VARNAME
# Also, note that Windows stores all the DLLs in the same directory.
# Instead of defining jni.library.path and jna.library.path we need to define
# jni.library.name and commons.crypto.OpenSslNativeJna to override the file names
- name: Build with Maven (Windows)
if: ${{ matrix.os == 'windows-latest' }}
# OPENSSL_HOME is needed for Windows build to find some header files
Expand All @@ -119,7 +117,7 @@ jobs:
env:
OPENSSL_HOME: "C:\\Miniconda\\Library"
run: |
mvn -V -B -ntp -DtrimStackTrace=false -D"jni.library.path=$env:ENGINESDIR" -D"jna.library.path=$env:ENGINESDIR" -D"commons.crypto.openssl.check=$env:CHECK_SKIP"
mvn -V -B -ntp -DtrimStackTrace=false -D"jni.library.name=$env:NAME" -D"commons.crypto.OpenSslNativeJna=$env:NAME" -D"commons.crypto.openssl.check=$env:CHECK_SKIP"
- name: Build with Maven (not Windows)
if: ${{ matrix.os != 'windows-latest' }}
run: |
Expand Down
12 changes: 6 additions & 6 deletions .github/workflows/maven_adhoc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -63,18 +63,18 @@ jobs:
- name: Build with Maven
env:
OPENSSL_HOME: "C:\\Miniconda\\Library"
LIB: "C:\\Program Files\\OpenSSL\\lib"
NAME: "libcrypto-1_1-x64"
run: |
mvn clean test -B -V -ntp -DtrimStackTrace=false -D"jni.library.path=$env:LIB" -D"jna.library.path=$env:LIB" -D"commons.crypto.openssl.check=skip" -D"commons.crypto.debug=true"
mvn clean test -B -V -ntp -D"jna.debug_load=true" -DtrimStackTrace=false -D"jni.library.name=$env:NAME" -D"commons.crypto.OpenSslNativeJna=$env:NAME" -D"commons.crypto.openssl.check=skip" -D"commons.crypto.debug=true"
- name: JNA test
if: always()
env:
LIB: "C:\\Program Files\\OpenSSL\\lib"
NAME: "crypto-1_1-x64"
run: |
mvn -q exec:java -D"exec.mainClass=org.apache.commons.crypto.jna.OpenSslJna" -D"commons.crypto.debug=true" -D"jna.library.path=$env:LIB"
mvn -q exec:java -D"jna.debug_load=true" -D"exec.mainClass=org.apache.commons.crypto.jna.OpenSslJna" -D"commons.crypto.debug=true" -D"commons.crypto.OpenSslNativeJna=$env:NAME"
- name: JNI test
if: always()
env:
LIB: "C:\\Program Files\\OpenSSL\\lib"
NAME: "libcrypto-1_1-x64"
run: |
mvn -q exec:java -D"exec.mainClass=org.apache.commons.crypto.Crypto" -D"commons.crypto.debug=true" -D"jni.library.path=$env:LIB"
mvn -q exec:java -D"exec.mainClass=org.apache.commons.crypto.Crypto" -D"commons.crypto.debug=true" -D"jni.library.name=$env:NAME"
1 change: 1 addition & 0 deletions src/changes/changes.xml
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@
<action type="update" dev="ggregory" due-to="Gary Gregory">Bump com.sun.xml.bind:jaxb-impl from 2.3.7 to 2.3.8.</action>
<!-- ADD -->
<action type="add" dev="sebb" due-to="Ludovic Henry">CRYPTO-172: Add support for Linux-riscv64 #264</action>
<action type="add" dev="sebb">CRYPTO-174: Allow override of SSL library name for Windows</action>
</release>
<release version="1.2.0" date="2023-01-14" description="Minor release (Java 8, OpenSSL 1.1.1)">
<!-- FIX -->
Expand Down
1 change: 1 addition & 0 deletions src/main/java/org/apache/commons/crypto/Crypto.java
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,7 @@ public static boolean isNativeCodeLoaded() {
public static void main(final String[] args) throws Exception {
quiet = args.length == 1 && args[0].equals("-q");
info("jni.library.path=%s", System.getProperty("jni.library.path"));
info("jni.library.name=%s", System.getProperty("jni.library.name"));
info("%s %s", getComponentName(), getComponentVersion());
if (isNativeCodeLoaded()) {
info("Native code loaded OK: %s", OpenSslInfoNative.NativeVersion());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ public static void main(final String[] args) throws Throwable {
// These are used by JNA code if defined:
info("jna.library.path=%s", System.getProperty("jna.library.path"));
info("jna.platform.library.path=%s", System.getProperty("jna.platform.library.path"));
info("commons.crypto.OpenSslNativeJna=%s\n", System.getProperty("commons.crypto.OpenSslNativeJna"));
// can set jna.debug_load=true for loading info
info(Crypto.getComponentName() + " OpenSslJna: enabled = %s, version = 0x%08X", isEnabled(), OpenSslNativeJna.VERSION);
final Throwable initialisationError = initialisationError();
Expand Down
15 changes: 12 additions & 3 deletions src/main/java/org/apache/commons/crypto/utils/Utils.java
Original file line number Diff line number Diff line change
Expand Up @@ -190,22 +190,31 @@ public static Properties getProperties(final Properties newProp) {

/*
* Override the default DLL name if jni.library.path is a valid directory
* If jni.library.name is defined, this overrides the default name.
*
* @param name - the default name, passed from native code
* @return the updated library path
* This method is designed for use from the DynamicLoader native code.
* Although it could all be implemented in native code, this hook method
* makes maintenance easier.
* The code is intended for use with macOS where SIP makes it hard to override
* the environment variables needed to override the DLL search path. It also
* works for Linux, but is not (currently) used or needed for Windows.
* works for Linux.
* On both macOS and Linux, different versions of the library are stored in different directories.
* In each case, there is a link from the canonical name (libcrypto.xx) to the versioned name (libcrypto-1.2.3.xx)
* However on Windows, all the DLL versions seem to be stored in the same directory.
* This means that Windows code needs to be given the versioned name (e.g. libcrypto-1_1-x64)
* This is done by defining jni.library.name.
*
* Do not change the method name or its signature!
*/
static String libraryPath(final String name) {
final String overridename = System.getProperty("jni.library.name", name);
final String override = System.getProperty("jni.library.path");
if (override != null && new File(override).isDirectory()) {
return new File(override, name).getPath();
return new File(override, overridename).getPath();
}
return name;
return overridename;
}

/**
Expand Down
39 changes: 25 additions & 14 deletions src/main/native/org/apache/commons/crypto/DynamicLoader.c
Original file line number Diff line number Diff line change
Expand Up @@ -44,26 +44,37 @@ HMODULE open_library(JNIEnv *env)
#endif

#ifdef WINDOWS
// not necessary to provide override for Windows
openssl = LoadLibrary(TEXT(COMMONS_CRYPTO_OPENSSL_LIBRARY));
openssl = LoadLibraryA(libraryPath); // use the non-generic method; assume libraryPath is suitable
#endif

}
// Did we succeed?
if (!openssl)
{
char msg[1000];
// Did we succeed?
if (!openssl)
{
char msg[1000];
#ifdef UNIX
snprintf(msg, sizeof(msg), "Cannot load %s (%s)!", COMMONS_CRYPTO_OPENSSL_LIBRARY, \
dlerror()); // returns char*
snprintf(msg, sizeof(msg), "Cannot load '%s' (%s)!", libraryPath, dlerror()); // returns char*
#endif
#ifdef WINDOWS
// TODO: convert to string
snprintf(msg, sizeof(msg), "Cannot load %s (%d)!", COMMONS_CRYPTO_OPENSSL_LIBRARY, \
GetLastError()); // returns DWORD
// Crude method to convert most likely errors to string
DWORD lastError = GetLastError();
char *lastmsg;
if (lastError == 126)
{
lastmsg = "specified module cannot be found";
}
else if (lastError == 193)
{
lastmsg = "module is not a valid Win32 application";
}
else
{
lastmsg = "unknown error - check online Windows documentation";
}
snprintf(msg, sizeof(msg), "Cannot load '%s' (%d: %s)!", libraryPath, lastError, lastmsg);
#endif
THROW(env, "java/lang/UnsatisfiedLinkError", msg);
return 0;
THROW(env, "java/lang/UnsatisfiedLinkError", msg);
return 0;
}
}
return openssl;
}
Expand Down

0 comments on commit 085efe0

Please sign in to comment.