diff --git a/README.md b/README.md index 933a004c..f13c0a20 100644 --- a/README.md +++ b/README.md @@ -619,6 +619,34 @@ legacy behavior where SNI is automatically configured from hostname/peer informa even without explicit SSLParameters configuration. Default value is "false", where SNI is only set when explicitly configured through SSLParameters. +**wolfssl.skipLibraryLoad (boolean)** - When set to "true", `WolfSSL.loadLibrary()` +will skip the default `System.loadLibrary()` calls for native wolfSSL and +wolfSSL JNI libraries. This is useful when applications need to load the native +libraries themselves using custom logic, for example when bundling the native +library inside a JAR file and extracting it at runtime. The property must be set +before `WolfSSL.loadLibrary()` is called, either directly or via +`WolfSSLProvider()` constructor. Applications can check if library loading was +skipped by calling `WolfSSL.isLibraryLoadSkipped()`. + +Setting via command line: + +``` +java -Dwolfssl.skipLibraryLoad=true ... +``` + +Setting programmatically before library load: + +```java +System.setProperty("wolfssl.skipLibraryLoad", "true"); + +/* Load native libraries with custom logic here */ +System.load("/path/to/libwolfssl.so"); +System.load("/path/to/libwolfssljni.so"); + +/* Then use WolfSSL as normal */ +WolfSSL.loadLibrary(); +``` + If there are other System properties you would like to use with wolfJSSE, please contact support@wolfssl.com. diff --git a/native/com_wolfssl_WolfSSLCertificate.h b/native/com_wolfssl_WolfSSLCertificate.h index 64bbad36..1034c128 100644 --- a/native/com_wolfssl_WolfSSLCertificate.h +++ b/native/com_wolfssl_WolfSSLCertificate.h @@ -210,8 +210,7 @@ JNIEXPORT jobjectArray JNICALL Java_com_wolfssl_WolfSSLCertificate_X509_1get_1ex * Method: X509_get1_ocsp * Signature: (J)[Ljava/lang/String; */ -JNIEXPORT jobjectArray JNICALL -Java_com_wolfssl_WolfSSLCertificate_X509_1get1_1ocsp +JNIEXPORT jobjectArray JNICALL Java_com_wolfssl_WolfSSLCertificate_X509_1get1_1ocsp (JNIEnv *, jclass, jlong); /* @@ -219,8 +218,7 @@ Java_com_wolfssl_WolfSSLCertificate_X509_1get1_1ocsp * Method: X509_get_aia_overflow * Signature: (J)I */ -JNIEXPORT jint JNICALL -Java_com_wolfssl_WolfSSLCertificate_X509_1get_1aia_1overflow +JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLCertificate_X509_1get_1aia_1overflow (JNIEnv *, jclass, jlong); /* @@ -228,8 +226,7 @@ Java_com_wolfssl_WolfSSLCertificate_X509_1get_1aia_1overflow * Method: X509_get1_ca_issuers * Signature: (J)[Ljava/lang/String; */ -JNIEXPORT jobjectArray JNICALL -Java_com_wolfssl_WolfSSLCertificate_X509_1get1_1ca_1issuers +JNIEXPORT jobjectArray JNICALL Java_com_wolfssl_WolfSSLCertificate_X509_1get1_1ca_1issuers (JNIEnv *, jclass, jlong); /* diff --git a/src/java/com/wolfssl/WolfSSL.java b/src/java/com/wolfssl/WolfSSL.java index f495be20..0b535636 100644 --- a/src/java/com/wolfssl/WolfSSL.java +++ b/src/java/com/wolfssl/WolfSSL.java @@ -471,9 +471,6 @@ public enum TLS_VERSION { /** Domain name qualifier NID */ public static int NID_dnQualifier; - /* is this object active, or has it been cleaned up? */ - private boolean active = false; - /* -------------- Named Groups (from enum in ssl.h) ----------------- */ /** Invalid named group */ public static final int WOLFSSL_NAMED_GROUP_INVALID = 0; @@ -567,6 +564,14 @@ public enum TLS_VERSION { * position, used for LDAPS hostname verification. */ public static int WOLFSSL_LEFT_MOST_WILDCARD_ONLY = 0x40; + /* ------------------------ Internal state -------------------------- */ + + /* is this object active, or has it been cleaned up? */ + private boolean active = false; + + /* Track if library loading was skipped via system property */ + private static volatile boolean libraryLoadSkipped = false; + /* ---------------------------- locks ------------------------------- */ /* lock for cleanup */ @@ -720,14 +725,25 @@ public WolfSSL() throws WolfSSLException { /* ------------------------- Java methods --------------------------- */ /** - * Loads JNI library; must be called prior to any other calls in this class. + * Loads JNI library; must be called prior to any other calls in this + * class. + * + * The native library is expected to be called "wolfssljni", and + * must be on the system library search path. * - * The native library is expected to be be called "wolfssljni", and must be - * on the system library search path. + * "wolfssljni" links against the wolfSSL native C library + * ("wolfssl"), and for Windows compatibility "wolfssl" needs to be + * explicitly loaded first here. * - * "wolfssljni" links against the wolfSSL native C library ("wolfssl"), - * and for Windows compatibility "wolfssl" needs to be explicitly - * loaded first here. + * If the system property "wolfssl.skipLibraryLoad" is set to + * "true", this method will skip loading the native library. This + * allows applications to load the native library themselves using + * custom logic (for example extracting from a JAR at runtime). + * The property must be set before this method is called (either + * directly or via WolfSSLProvider constructor). + * + * Applications can check if library loading was skipped by calling + * WolfSSL.isLibraryLoadSkipped(). * * @throws UnsatisfiedLinkError if the library is not found. */ @@ -735,6 +751,19 @@ public static void loadLibrary() throws UnsatisfiedLinkError { int fipsLoaded = 0; + String skipLoad = + System.getProperty("wolfssl.skipLibraryLoad"); + if (skipLoad != null && skipLoad.equalsIgnoreCase("true")) { + /* User will load native libraries manually */ + libraryLoadSkipped = true; + + WolfSSLDebug.log(WolfSSL.class, WolfSSLDebug.Component.JNI, + WolfSSLDebug.INFO, () -> "skipping native library load, " + + "wolfssl.skipLibraryLoad system property set to true"); + + return; + } + WolfSSLDebug.log(WolfSSL.class, WolfSSLDebug.Component.JNI, WolfSSLDebug.INFO, () -> "loading native library: wolfssl"); @@ -769,6 +798,10 @@ public static void loadLibrary() throws UnsatisfiedLinkError { * The native library needs to be located on the system library search * path. * + * Note: this method does not check the + * "wolfssl.skipLibraryLoad" system property. That property is only + * respected by the no-argument {@link #loadLibrary()} method. + * * @param libName name of native JNI library * @throws UnsatisfiedLinkError if the library is not found. */ @@ -781,19 +814,24 @@ public static void loadLibrary(String libName) throws UnsatisfiedLinkError { } /** - * Loads dynamic JNI library from a specific path; must be called prior to - * any other calls in this package. + * Loads dynamic JNI library from a specific path; must be called + * prior to any other calls in this package. + * + * This function gives the application more control over the exact + * native library being loaded, as both WolfSSL.loadLibrary() and + * WolfSSL.loadLibrary(String libName) search for a library on the + * system library search path. This function allows the appliation + * to specify a specific absolute path to the native library file + * to load, thus guaranteeing the exact library loaded and helping + * to prevent against malicious attackers from attempting to + * override the library being loaded. * - * This function gives the application more control over the exact native - * library being loaded, as both WolfSSL.loadLibrary() and - * WolfSSL.loadLibrary(String libName) search for a library on the system - * library search path. This function allows the appliation to specify - * a specific absolute path to the native library file to load, thus - * guaranteeing the exact library loaded and helping to prevent against - * malicious attackers from attempting to override the library being - * loaded. + * Note: this method does not check the + * "wolfssl.skipLibraryLoad" system property. That property is only + * respected by the no-argument {@link #loadLibrary()} method. * - * @param libPath complete path name to the native dynamic JNI library + * @param libPath complete path name to the native dynamic JNI + * library * @throws UnsatisfiedLinkError if the library is not found. */ public static void loadLibraryAbsolute(String libPath) @@ -805,6 +843,19 @@ public static void loadLibraryAbsolute(String libPath) System.load(libPath); } + /** + * Check if native library loading was skipped. + * + * Library loading is skipped when the System property + * "wolfssl.skipLibraryLoad" is set to "true" and loadLibrary() has + * been called. + * + * @return true if library loading was skipped, false otherwise + */ + public static boolean isLibraryLoadSkipped() { + return libraryLoadSkipped; + } + /* ----------------- generic static helper functions ---------------- */ /** diff --git a/src/test/com/wolfssl/test/WolfSSLTest.java b/src/test/com/wolfssl/test/WolfSSLTest.java index f91cc974..a6e2d182 100644 --- a/src/test/com/wolfssl/test/WolfSSLTest.java +++ b/src/test/com/wolfssl/test/WolfSSLTest.java @@ -57,6 +57,9 @@ public void testWolfSSL() throws WolfSSLException { test_WolfSSL_getLibVersionHex(); test_WolfSSL_getErrno(); testGetCiphersAvailableIana(); + test_isLibraryLoadSkippedReturnsFalseByDefault(); + test_SystemPropertyNotSetByDefault(); + test_SettingPropertyAfterLoadHasNoEffect(); } public void test_WolfSSL_new(WolfSSL lib) { @@ -232,5 +235,58 @@ public void test_WolfSSL_getErrno() { System.out.println("\t\t\t... passed"); } + + public void test_isLibraryLoadSkippedReturnsFalseByDefault() { + + System.out.print( + "\tisLibraryLoadSkipped() default"); + + /* Library was loaded normally in @BeforeClass, so + * isLibraryLoadSkipped() should return false */ + assertFalse( + "isLibraryLoadSkipped() should be false when " + + "library was loaded normally", + WolfSSL.isLibraryLoadSkipped()); + + System.out.println("\t... passed"); + } + + public void test_SystemPropertyNotSetByDefault() { + + System.out.print( + "\twolfssl.skipLibraryLoad not set"); + + /* Verify property is not set by default in test env */ + String val = + System.getProperty("wolfssl.skipLibraryLoad"); + assertNull( + "wolfssl.skipLibraryLoad should not be set " + + "by default", val); + + System.out.println("\t... passed"); + } + + public void test_SettingPropertyAfterLoadHasNoEffect() { + + System.out.print( + "\tskipLibraryLoad after load"); + + /* Setting the property after library has already been + * loaded should not change isLibraryLoadSkipped() */ + try { + System.setProperty( + "wolfssl.skipLibraryLoad", "true"); + + assertFalse( + "isLibraryLoadSkipped() should still be " + + "false after setting property post-load", + WolfSSL.isLibraryLoadSkipped()); + + } finally { + System.clearProperty("wolfssl.skipLibraryLoad"); + } + + System.out.println("\t... passed"); + } }