diff --git a/.github/workflows/linux-common.yml b/.github/workflows/linux-common.yml
index 75d987ea..05a9577a 100644
--- a/.github/workflows/linux-common.yml
+++ b/.github/workflows/linux-common.yml
@@ -15,6 +15,9 @@ on:
wolfssl_configure:
required: true
type: string
+ javash_cflags:
+ required: false
+ type: string
jobs:
build_wolfssljni:
@@ -51,7 +54,7 @@ jobs:
echo "LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$GITHUB_WORKSPACE/build-dir/lib" >> "$GITHUB_ENV"
- name: Build JNI library
- run: ./java.sh $GITHUB_WORKSPACE/build-dir
+ run: CFLAGS=${{ inputs.javah_cflags }} ./java.sh $GITHUB_WORKSPACE/build-dir
- name: Build JAR (ant)
run: ant
- name: Run Java tests (ant test)
diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index 64236be0..c255f186 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -120,6 +120,27 @@ jobs:
jdk_version: ${{ matrix.jdk_version }}
wolfssl_configure: ${{ matrix.wolfssl_configure }}
+ # -------------------- WOLFJNI_USE_IO_SELECT sanity check --------------------
+ # Only check one Linux and Mac JDK version as a sanity check.
+ # Using Zulu, but this can be expanded if needed.
+ linux-zulu-ioselect:
+ strategy:
+ matrix:
+ os: [ 'ubuntu-latest', 'macos-latest' ]
+ jdk_version: [ '11' ]
+ wolfssl_configure: [
+ '--enable-jni',
+ ]
+ javash_cflags: [ '-DWOLFJNI_USE_IO_SELECT' ]
+ name: ${{ matrix.os }} (Zulu JDK ${{ matrix.jdk_version }}, ${{ matrix.wolfssl_configure}}, ${{ matrix.javash_cflags }})
+ uses: ./.github/workflows/linux-common.yml
+ with:
+ os: ${{ matrix.os }}
+ jdk_distro: "zulu"
+ jdk_version: ${{ matrix.jdk_version }}
+ wolfssl_configure: ${{ matrix.wolfssl_configure }}
+ javash_cflags: ${{ matrix.javash_cflags }}
+
# ------------------ Facebook Infer static analysis -------------------
# Run Facebook infer over PR code, only running on Linux with one
# JDK/version for now.
diff --git a/README.md b/README.md
index 2336829a..d47efc42 100644
--- a/README.md
+++ b/README.md
@@ -108,6 +108,44 @@ $ ./examples/provider/ServerJSSE.sh
$ ./examples/provider/ClientJSSE.sh
```
+### java.sh Script Options
+
+The `java.sh` script compiles the native JNI sources into a shared library named
+either `libwolfssljni.so` (Linux/Unix) or `libwolfssljni.dylib` (MacOS).
+Compiling on Linux/Unix and Mac OSX are currently supported.
+
+This script will attempt to auto-detect the `JAVA_HOME` location if not set.
+To explicitly use a Java home location, set the `JAVA_HOME` environment variable
+prior to running this script.
+
+This script will try to link against a wolfSSL library installed to the
+default location of `/usr/local`. This script accepts two arguments on the
+command line. The first argument can point to a custom wolfSSL installation
+location. A custom install location would match the directory set at wolfSSL
+`./configure --prefix=
`.
+
+The second argument represents the wolfSSL library name that should be
+linked against. This is helpful if a non-standard library name has been
+used with wolfSSL, for example the `./configure --with-libsuffix` option
+has been used to add a suffix to the wolfSSL library name. Note that to
+use this argument, an installation location must be specified via the
+first argument.
+
+For example, if wolfSSL was configured with `--with-libsuffix=jsse`, then
+this script could be called like so using the default installation
+path of `/usr/local`:
+
+```
+java.sh /usr/local wolfssljsse
+```
+
+`java.sh` can use preset `CFLAGS` defines, if set in the environment variable
+prior to running the script, for example:
+
+```
+CFLAGS=-DWOLFJNI_USE_IO_SELECT java.sh
+```
+
## Building with Maven
wolfJSSE supports building and packaging with Maven, for those projects that
diff --git a/java.sh b/java.sh
index 1bfe18ed..aa07d8dc 100755
--- a/java.sh
+++ b/java.sh
@@ -75,7 +75,6 @@ if [ "$OS" == "Darwin" ] ; then
javaIncludes="-I$javaHome/include -I$javaHome/include/darwin -I$WOLFSSL_INSTALL_DIR/include"
javaLibs="-dynamiclib"
jniLibName="libwolfssljni.dylib"
- cflags=""
elif [ "$OS" == "Linux" ] ; then
echo " Detected Linux host OS"
if [ -z $javaHome ]; then
@@ -88,7 +87,6 @@ elif [ "$OS" == "Linux" ] ; then
javaIncludes="-I$javaHome/include -I$javaHome/include/linux -I$WOLFSSL_INSTALL_DIR/include"
javaLibs="-shared"
jniLibName="libwolfssljni.so"
- cflags=""
if [ "$ARCH" == "x86_64" ] ; then
fpic="-fPIC"
else
@@ -108,18 +106,18 @@ then
mkdir ./lib
fi
-gcc -Wall -c $fpic $cflags ./native/com_wolfssl_WolfSSL.c -o ./native/com_wolfssl_WolfSSL.o $javaIncludes
-gcc -Wall -c $fpic $cflags ./native/com_wolfssl_WolfSSLSession.c -o ./native/com_wolfssl_WolfSSLSession.o $javaIncludes
-gcc -Wall -c $fpic $cflags ./native/com_wolfssl_WolfSSLContext.c -o ./native/com_wolfssl_WolfSSLContext.o $javaIncludes
-gcc -Wall -c $fpic $cflags ./native/com_wolfssl_wolfcrypt_RSA.c -o ./native/com_wolfssl_wolfcrypt_RSA.o $javaIncludes
-gcc -Wall -c $fpic $cflags ./native/com_wolfssl_wolfcrypt_ECC.c -o ./native/com_wolfssl_wolfcrypt_ECC.o $javaIncludes
-gcc -Wall -c $fpic $cflags ./native/com_wolfssl_wolfcrypt_EccKey.c -o ./native/com_wolfssl_wolfcrypt_EccKey.o $javaIncludes
-gcc -Wall -c $fpic $cflags ./native/com_wolfssl_WolfSSLCertManager.c -o ./native/com_wolfssl_WolfSSLCertManager.o $javaIncludes
-gcc -Wall -c $fpic $cflags ./native/com_wolfssl_WolfSSLCertRequest.c -o ./native/com_wolfssl_WolfSSLCertRequest.o $javaIncludes
-gcc -Wall -c $fpic $cflags ./native/com_wolfssl_WolfSSLCertificate.c -o ./native/com_wolfssl_WolfSSLCertificate.o $javaIncludes
-gcc -Wall -c $fpic $cflags ./native/com_wolfssl_WolfSSLX509Name.c -o ./native/com_wolfssl_WolfSSLX509Name.o $javaIncludes
-gcc -Wall -c $fpic $cflags ./native/com_wolfssl_WolfSSLX509StoreCtx.c -o ./native/com_wolfssl_WolfSSLX509StoreCtx.o $javaIncludes
-gcc -Wall $javaLibs $cflags -o ./lib/$jniLibName ./native/com_wolfssl_WolfSSL.o ./native/com_wolfssl_WolfSSLSession.o ./native/com_wolfssl_WolfSSLContext.o ./native/com_wolfssl_wolfcrypt_RSA.o ./native/com_wolfssl_wolfcrypt_ECC.o ./native/com_wolfssl_wolfcrypt_EccKey.o ./native/com_wolfssl_WolfSSLCertManager.o ./native/com_wolfssl_WolfSSLCertRequest.o ./native/com_wolfssl_WolfSSLCertificate.o ./native/com_wolfssl_WolfSSLX509Name.o ./native/com_wolfssl_WolfSSLX509StoreCtx.o -L$WOLFSSL_INSTALL_DIR/lib -L$WOLFSSL_INSTALL_DIR/lib64 -l$WOLFSSL_LIBNAME
+gcc -Wall -c $fpic $CFLAGS ./native/com_wolfssl_WolfSSL.c -o ./native/com_wolfssl_WolfSSL.o $javaIncludes
+gcc -Wall -c $fpic $CFLAGS ./native/com_wolfssl_WolfSSLSession.c -o ./native/com_wolfssl_WolfSSLSession.o $javaIncludes
+gcc -Wall -c $fpic $CFLAGS ./native/com_wolfssl_WolfSSLContext.c -o ./native/com_wolfssl_WolfSSLContext.o $javaIncludes
+gcc -Wall -c $fpic $CFLAGS ./native/com_wolfssl_wolfcrypt_RSA.c -o ./native/com_wolfssl_wolfcrypt_RSA.o $javaIncludes
+gcc -Wall -c $fpic $CFLAGS ./native/com_wolfssl_wolfcrypt_ECC.c -o ./native/com_wolfssl_wolfcrypt_ECC.o $javaIncludes
+gcc -Wall -c $fpic $CFLAGS ./native/com_wolfssl_wolfcrypt_EccKey.c -o ./native/com_wolfssl_wolfcrypt_EccKey.o $javaIncludes
+gcc -Wall -c $fpic $CFLAGS ./native/com_wolfssl_WolfSSLCertManager.c -o ./native/com_wolfssl_WolfSSLCertManager.o $javaIncludes
+gcc -Wall -c $fpic $CFLAGS ./native/com_wolfssl_WolfSSLCertRequest.c -o ./native/com_wolfssl_WolfSSLCertRequest.o $javaIncludes
+gcc -Wall -c $fpic $CFLAGS ./native/com_wolfssl_WolfSSLCertificate.c -o ./native/com_wolfssl_WolfSSLCertificate.o $javaIncludes
+gcc -Wall -c $fpic $CFLAGS ./native/com_wolfssl_WolfSSLX509Name.c -o ./native/com_wolfssl_WolfSSLX509Name.o $javaIncludes
+gcc -Wall -c $fpic $CFLAGS ./native/com_wolfssl_WolfSSLX509StoreCtx.c -o ./native/com_wolfssl_WolfSSLX509StoreCtx.o $javaIncludes
+gcc -Wall $javaLibs $CFLAGS -o ./lib/$jniLibName ./native/com_wolfssl_WolfSSL.o ./native/com_wolfssl_WolfSSLSession.o ./native/com_wolfssl_WolfSSLContext.o ./native/com_wolfssl_wolfcrypt_RSA.o ./native/com_wolfssl_wolfcrypt_ECC.o ./native/com_wolfssl_wolfcrypt_EccKey.o ./native/com_wolfssl_WolfSSLCertManager.o ./native/com_wolfssl_WolfSSLCertRequest.o ./native/com_wolfssl_WolfSSLCertificate.o ./native/com_wolfssl_WolfSSLX509Name.o ./native/com_wolfssl_WolfSSLX509StoreCtx.o -L$WOLFSSL_INSTALL_DIR/lib -L$WOLFSSL_INSTALL_DIR/lib64 -l$WOLFSSL_LIBNAME
if [ $? != 0 ]; then
echo "Error creating native JNI library"
exit 1
diff --git a/native/com_wolfssl_WolfSSLSession.c b/native/com_wolfssl_WolfSSLSession.c
index a7216d72..3e88820d 100644
--- a/native/com_wolfssl_WolfSSLSession.c
+++ b/native/com_wolfssl_WolfSSLSession.c
@@ -72,8 +72,17 @@ static jobject g_crlCbIfaceObj;
* function calls. Stored inside WOLFSSL app data, set with
* wolfSSL_set_app_data(), retrieved with wolfSSL_get_app_data().
* Global callback objects are created with NewGlobalRef(), then freed
- * inside freeSSL() with DeleteGlobalRef(). */
+ * inside freeSSL() with DeleteGlobalRef().
+ *
+ * interruptFds[2] is a pipe() used for non-Windows platforms. This pipe is
+ * used to interrupt threads blocked inside select()/poll() when a separate
+ * Java thread calls close() on the SSLSocket. */
typedef struct SSLAppData {
+ int threadsInPoll; /* number of threads in poll/select() */
+#ifndef USE_WINDOWS_API
+ int interruptFds[2]; /* pipe for interrupting socketSelect() */
+ wolfSSL_Mutex* pollCountLock; /* lock around threadsInPoll */
+#endif
wolfSSL_Mutex* jniSessLock; /* WOLFSSL session lock */
jobject* g_verifySSLCbIfaceObj; /* Java verify callback [global ref] */
} SSLAppData;
@@ -191,13 +200,116 @@ int NativeSSLVerifyCallback(int preverify_ok, WOLFSSL_X509_STORE_CTX* store)
return retval;
}
+#ifndef USE_WINDOWS_API
+
+/* Close interrupt pipe() descriptors and reset back to -1. */
+static void closeInterruptPipe(SSLAppData* appData)
+{
+ if (appData != NULL) {
+ if (appData->interruptFds[0] != -1) {
+ close(appData->interruptFds[0]);
+ appData->interruptFds[0] = -1;
+ }
+ if (appData->interruptFds[1] != -1) {
+ close(appData->interruptFds[1]);
+ appData->interruptFds[1] = -1;
+ }
+ }
+}
+
+/* Signal to threads blocked in select() or poll() to wake up, by writing
+ * one byte to the appData.interruptFds[1] pipe. */
+static void writeToInterruptPipe(SSLAppData* appData)
+{
+ if (appData != NULL) {
+ if (appData->interruptFds[1] != -1) {
+ write(appData->interruptFds[1], "1", 1);
+ }
+ }
+}
+
+#endif /* !USE_WINDOWS_API */
+
+/* Return number of threads waiting in poll()/select() */
+static int threadsWaitingInPollSelect(SSLAppData* appData)
+{
+ int ret = 0;
+#ifndef USE_WINDOWS_API
+ wolfSSL_Mutex* pollCountLock = NULL;
+
+ if (appData != NULL) {
+ pollCountLock = appData->pollCountLock;
+ if (pollCountLock != NULL) {
+ if (wc_LockMutex(pollCountLock) == 0) {
+ ret = appData->threadsInPoll;
+ wc_UnLockMutex(pollCountLock);
+ }
+ }
+ }
+#endif
+ return ret;
+}
+
+static void incrementThreadPollCount(SSLAppData* appData)
+{
+#ifndef USE_WINDOWS_API
+ wolfSSL_Mutex* pollCountLock = NULL;
+
+ if (appData == NULL) {
+ return;
+ }
+
+ pollCountLock = appData->pollCountLock;
+ if (pollCountLock == NULL) {
+ return;
+ }
+
+ if (wc_LockMutex(pollCountLock) != 0) {
+ return;
+ }
+
+ appData->threadsInPoll++;
+
+ wc_UnLockMutex(pollCountLock);
+#endif
+}
+
+static void decrementThreadPollCount(SSLAppData* appData)
+{
+#ifndef USE_WINDOWS_API
+ wolfSSL_Mutex* pollCountLock = NULL;
+
+ if (appData == NULL) {
+ return;
+ }
+
+ pollCountLock = appData->pollCountLock;
+ if (pollCountLock == NULL) {
+ return;
+ }
+
+ if (wc_LockMutex(pollCountLock) != 0) {
+ return;
+ }
+
+ if (appData->threadsInPoll > 0) {
+ appData->threadsInPoll--;
+ }
+
+ wc_UnLockMutex(pollCountLock);
+#endif
+}
+
JNIEXPORT jlong JNICALL Java_com_wolfssl_WolfSSLSession_newSSL
- (JNIEnv* jenv, jobject jcl, jlong ctx)
+ (JNIEnv* jenv, jobject jcl, jlong ctx, jboolean withIOPipe)
{
int ret;
jlong sslPtr = 0;
jobject* g_cachedSSLObj = NULL;
wolfSSL_Mutex* jniSessLock = NULL;
+#ifndef USE_WINDOWS_API
+ wolfSSL_Mutex* pollCountLock = NULL;
+#endif
SSLAppData* appData = NULL;
if (jenv == NULL) {
@@ -251,11 +363,71 @@ JNIEXPORT jlong JNICALL Java_com_wolfssl_WolfSSLSession_newSSL
wc_InitMutex(jniSessLock);
appData->jniSessLock = jniSessLock;
+ /* set up interrupt pipe for SSLSocket.close() to use if/when needed.
+ * currently only non-Windows platforms supported due to Windows not
+ * supporting direct/same pipe() operation. Make read pipe non
+ * blocking since byte read from it could have already been taken
+ * out by either reader/writer thread before the other has a chance
+ * to read it. But, we only use it for waking us up and don't care
+ * much about actually reading the byte passed over the pipe. */
+ appData->threadsInPoll = 0;
+#ifndef USE_WINDOWS_API
+ pollCountLock = (wolfSSL_Mutex*)XMALLOC(sizeof(wolfSSL_Mutex), NULL,
+ DYNAMIC_TYPE_TMP_BUFFER);
+ if (pollCountLock == NULL) {
+ printf("error mallocing pollCountLock in newSSL for SSLAppData\n");
+ (*jenv)->DeleteGlobalRef(jenv, *g_cachedSSLObj);
+ XFREE(jniSessLock, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+ XFREE(appData, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+ XFREE(g_cachedSSLObj, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+ wolfSSL_free((WOLFSSL*)(uintptr_t)sslPtr);
+ return SSL_FAILURE;
+ }
+ wc_InitMutex(pollCountLock);
+ appData->pollCountLock = pollCountLock;
+
+ appData->interruptFds[0] = -1;
+ appData->interruptFds[1] = -1;
+
+ if (withIOPipe == JNI_TRUE) {
+ ret = pipe(appData->interruptFds);
+ if (ret == -1) {
+ printf("error setting up pipe() for interruptFds[] in newSSL\n");
+ (*jenv)->DeleteGlobalRef(jenv, *g_cachedSSLObj);
+ XFREE(pollCountLock, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+ XFREE(jniSessLock, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+ XFREE(appData, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+ XFREE(g_cachedSSLObj, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+ wolfSSL_free((WOLFSSL*)(uintptr_t)sslPtr);
+ return SSL_FAILURE;
+ }
+
+ ret = fcntl(appData->interruptFds[0], F_SETFL,
+ fcntl(appData->interruptFds[0], F_GETFL, 0) | O_NONBLOCK);
+ if (ret < 0) {
+ printf("error setting interruptFds[0] non-blocking in newSSL\n");
+ closeInterruptPipe(appData);
+ (*jenv)->DeleteGlobalRef(jenv, *g_cachedSSLObj);
+ XFREE(pollCountLock, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+ XFREE(jniSessLock, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+ XFREE(appData, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+ XFREE(g_cachedSSLObj, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+ wolfSSL_free((WOLFSSL*)(uintptr_t)sslPtr);
+ return SSL_FAILURE;
+ }
+ }
+#endif /* !USE_WINDOWS_API */
+
/* cache associated WolfSSLSession jobject in native WOLFSSL */
ret = wolfSSL_set_jobject((WOLFSSL*)(uintptr_t)sslPtr, g_cachedSSLObj);
if (ret != SSL_SUCCESS) {
printf("error storing jobject in wolfSSL native session\n");
(*jenv)->DeleteGlobalRef(jenv, *g_cachedSSLObj);
+ #ifndef USE_WINDOWS_API
+ closeInterruptPipe(appData);
+ XFREE(pollCountLock, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+ #endif
+ XFREE(jniSessLock, NULL, DYNAMIC_TYPE_TMP_BUFFER);
XFREE(appData, NULL, DYNAMIC_TYPE_TMP_BUFFER);
XFREE(g_cachedSSLObj, NULL, DYNAMIC_TYPE_TMP_BUFFER);
wolfSSL_free((WOLFSSL*)(uintptr_t)sslPtr);
@@ -267,6 +439,10 @@ JNIEXPORT jlong JNICALL Java_com_wolfssl_WolfSSLSession_newSSL
(WOLFSSL*)(uintptr_t)sslPtr, appData) != SSL_SUCCESS) {
printf("error setting WOLFSSL app data in newSSL\n");
(*jenv)->DeleteGlobalRef(jenv, *g_cachedSSLObj);
+ #ifndef USE_WINDOWS_API
+ closeInterruptPipe(appData);
+ XFREE(pollCountLock, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+ #endif
XFREE(jniSessLock, NULL, DYNAMIC_TYPE_TMP_BUFFER);
XFREE(appData, NULL, DYNAMIC_TYPE_TMP_BUFFER);
XFREE(g_cachedSSLObj, NULL, DYNAMIC_TYPE_TMP_BUFFER);
@@ -637,16 +813,21 @@ enum {
* supported, since not supported on Java Socket.
* @param rx set to 1 to monitor readability on socket descriptor,
* otherwise 0 to monitor writability
+ * @param shutdown Is this being called from shutdownSSL()? Don't select
+ * on interruptFds in that case, since we already know
+ * we are closing in that case.
*
* @return possible return values are:
* WOLFJNI_IO_EVENT_FAIL
* WOLFJNI_IO_EVENT_ERROR
+ * WOLFJNI_IO_EVENT_FD_CLOSED
* WOLFJNI_IO_EVENT_TIMEOUT
* WOLFJNI_IO_EVENT_RECV_READY
* WOLFJNI_IO_EVENT_SEND_READY
* WOLFJNI_IO_EVENT_INVALID_TIMEOUT
*/
-static int socketSelect(int sockfd, int timeout_ms, int rx)
+static int socketSelect(SSLAppData* appData, int sockfd, int timeout_ms, int rx,
+ int shutdown)
{
fd_set fds, errfds;
fd_set* recvfds = NULL;
@@ -654,20 +835,39 @@ static int socketSelect(int sockfd, int timeout_ms, int rx)
int nfds = sockfd + 1;
int result = 0;
struct timeval timeout;
+#ifndef USE_WINDOWS_API
+ char tmpBuf[1];
+#endif
/* Java Socket does not support negative timeouts, sanitize */
if (timeout_ms < 0) {
return WOLFJNI_IO_EVENT_INVALID_TIMEOUT;
}
+ if (appData == NULL) {
+ return WOLFJNI_IO_EVENT_ERROR;
+ }
+
#ifndef USE_WINDOWS_API
do {
#endif
timeout.tv_sec = timeout_ms / 1000;
timeout.tv_usec = (timeout_ms % 1000) * 1000;
+ /* file/socket descriptors */
FD_ZERO(&fds);
FD_SET(sockfd, &fds);
+#ifndef USE_WINDOWS_API
+ if ((shutdown == 0) && (appData->interruptFds[0] != -1)) {
+ FD_SET(appData->interruptFds[0], &fds);
+ /* nfds should be set to the highest number descriptor plus 1 */
+ if (appData->interruptFds[0] > sockfd) {
+ nfds = appData->interruptFds[0] + 1;
+ }
+ }
+#endif /* !USE_WINDOWS_API */
+
+ /* error descriptors */
FD_ZERO(&errfds);
FD_SET(sockfd, &errfds);
@@ -677,11 +877,13 @@ static int socketSelect(int sockfd, int timeout_ms, int rx)
sendfds = &fds;
}
+ incrementThreadPollCount(appData);
if (timeout_ms == 0) {
result = select(nfds, recvfds, sendfds, &errfds, NULL);
} else {
result = select(nfds, recvfds, sendfds, &errfds, &timeout);
}
+ decrementThreadPollCount(appData);
if (result == 0) {
return WOLFJNI_IO_EVENT_TIMEOUT;
@@ -692,9 +894,26 @@ static int socketSelect(int sockfd, int timeout_ms, int rx)
} else {
return WOLFJNI_IO_EVENT_SEND_READY;
}
- } else if (FD_ISSET(sockfd, &errfds)) {
+ }
+ else if (FD_ISSET(sockfd, &errfds)) {
return WOLFJNI_IO_EVENT_ERROR;
}
+#ifndef USE_WINDOWS_API
+ else if ((shutdown == 0) && (appData->interruptFds[0] != -1) &&
+ (FD_ISSET(appData->interruptFds[0], &fds))) {
+ /* We got interrupted by our interrupt fd, due to a Java
+ * thread calling SSLSocket.close(). Try to read byte that
+ * was placed on our interruptFds[0] descriptor, but not
+ * an error if not there. Another read/write() may have
+ * already read it off. We just want to be interrupted,
+ * byte value does not matter. */
+ do {
+ read(appData->interruptFds[0], tmpBuf, 1);
+ } while (errno == EINTR);
+
+ return WOLFJNI_IO_EVENT_FD_CLOSED;
+ }
+#endif /* !USE_WINDOWS_API */
}
#ifndef USE_WINDOWS_API
@@ -725,6 +944,9 @@ static int socketSelect(int sockfd, int timeout_ms, int rx)
* otherwise 0 to ignore readability events
* @param tx set to 1 to monitor writability on socket descriptor,
* otherwise 0 to ignore writability events
+ * @param shutdown Is this being called from shutdownSSL()? Don't poll
+ * on interruptFds in that case, since we already know
+ * we are closing in that case.
*
* @return possible return values are:
* WOLFJNI_IO_EVENT_FAIL
@@ -736,11 +958,18 @@ static int socketSelect(int sockfd, int timeout_ms, int rx)
* WOLFJNI_IO_EVENT_POLLHUP
* WOLFJNI_IO_EVENT_INVALID_TIMEOUT
*/
-static int socketPoll(int sockfd, int timeout_ms, int rx, int tx)
+static int socketPoll(SSLAppData* appData, int sockfd, int timeout_ms,
+ int rx, int tx, int shutdown)
{
int ret;
+ int nfds = 2;
int timeout;
- struct pollfd fds[1];
+ struct pollfd fds[2];
+ char tmpBuf[1];
+
+ if (appData == NULL) {
+ return WOLFJNI_IO_EVENT_ERROR;
+ }
/* Sanitize timeout and convert from Java to poll() expectations */
timeout = timeout_ms;
@@ -750,35 +979,62 @@ static int socketPoll(int sockfd, int timeout_ms, int rx, int tx)
timeout = -1;
}
+ /* fd for socket I/O */
fds[0].fd = sockfd;
fds[0].events = 0;
if (tx) {
- fds[0].events |= POLLOUT;
+ fds[0].events |= POLLOUT | POLLPRI;
}
if (rx) {
- fds[0].events |= POLLIN;
+ fds[0].events |= POLLIN | POLLPRI;
+ }
+
+ if ((shutdown == 0) && (appData->interruptFds[0] != -1)) {
+ /* fd for interrupt / signaling SSLSocket.close() */
+ fds[1].fd = appData->interruptFds[0];
+ fds[1].events = POLLIN | POLLPRI;
+ }
+ else {
+ nfds--;
}
do {
- ret = poll(fds, 1, timeout);
+ incrementThreadPollCount(appData);
+ ret = poll(fds, nfds, timeout);
+ decrementThreadPollCount(appData);
if (ret == 0) {
return WOLFJNI_IO_EVENT_TIMEOUT;
- } else if (ret > 0) {
- if (fds[0].revents & POLLIN ||
+ }
+ else if (ret > 0) {
+ if ((shutdown == 0) && (appData->interruptFds[0] != -1) &&
+ (fds[1].revents & POLLIN)) {
+ /* received data on interrupt pipe, read and return
+ * that descriptor is closed (closing) */
+ do {
+ read(appData->interruptFds[0], tmpBuf, 1);
+ } while (errno == EINTR);
+
+ return WOLFJNI_IO_EVENT_FD_CLOSED;
+ }
+ else if (fds[0].revents & POLLIN ||
fds[0].revents & POLLPRI) { /* read possible */
return WOLFJNI_IO_EVENT_RECV_READY;
- } else if (fds[0].revents & POLLOUT) { /* write possible */
+ }
+ else if (fds[0].revents & POLLOUT) { /* write possible */
return WOLFJNI_IO_EVENT_SEND_READY;
- } else if (fds[0].revents & POLLNVAL) { /* fd not open */
+ }
+ else if (fds[0].revents & POLLNVAL) { /* fd not open */
return WOLFJNI_IO_EVENT_FD_CLOSED;
- } else if (fds[0].revents & POLLERR) { /* exceptional error */
+ }
+ else if (fds[0].revents & POLLERR) { /* exceptional error */
return WOLFJNI_IO_EVENT_ERROR;
- } else if (fds[0].revents & POLLHUP) { /* sock disconnected */
+ }
+ else if (fds[0].revents & POLLHUP) { /* sock disconnected */
return WOLFJNI_IO_EVENT_POLLHUP;
}
}
@@ -795,7 +1051,9 @@ JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_connect
{
int ret = 0, err = 0, sockfd = 0;
int pollRx = 0;
+#if !defined(WOLFJNI_USE_IO_SELECT) && !defined(USE_WINDOWS_API)
int pollTx = 0;
+#endif
wolfSSL_Mutex* jniSessLock = NULL;
SSLAppData* appData = NULL;
WOLFSSL* ssl = (WOLFSSL*)(uintptr_t)sslPtr;
@@ -852,14 +1110,16 @@ JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_connect
if (err == SSL_ERROR_WANT_READ) {
pollRx = 1;
}
+ #if !defined(WOLFJNI_USE_IO_SELECT) && !defined(USE_WINDOWS_API)
else if (err == SSL_ERROR_WANT_WRITE) {
pollTx = 1;
}
+ #endif
#if defined(WOLFJNI_USE_IO_SELECT) || defined(USE_WINDOWS_API)
- ret = socketSelect(sockfd, (int)timeout, pollRx);
+ ret = socketSelect(appData, sockfd, (int)timeout, pollRx, 0);
#else
- ret = socketPoll(sockfd, (int)timeout, pollRx, pollTx);
+ ret = socketPoll(appData, sockfd, (int)timeout, pollRx, pollTx, 0);
#endif
if ((ret == WOLFJNI_IO_EVENT_RECV_READY) ||
(ret == WOLFJNI_IO_EVENT_SEND_READY)) {
@@ -898,7 +1158,9 @@ JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_write
byte* data = NULL;
int ret = SSL_FAILURE, err, sockfd;
int pollRx = 0;
+#if !defined(WOLFJNI_USE_IO_SELECT) && !defined(USE_WINDOWS_API)
int pollTx = 0;
+#endif
wolfSSL_Mutex* jniSessLock = NULL;
SSLAppData* appData = NULL;
WOLFSSL* ssl = (WOLFSSL*)(uintptr_t)sslPtr;
@@ -963,14 +1225,17 @@ JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_write
if (err == SSL_ERROR_WANT_READ) {
pollRx = 1;
}
+ #if !defined(WOLFJNI_USE_IO_SELECT) && !defined(USE_WINDOWS_API)
else if (err == SSL_ERROR_WANT_WRITE) {
pollTx = 1;
}
+ #endif
#if defined(WOLFJNI_USE_IO_SELECT) || defined(USE_WINDOWS_API)
- ret = socketSelect(sockfd, (int)timeout, pollRx);
+ ret = socketSelect(appData, sockfd, (int)timeout, pollRx, 0);
#else
- ret = socketPoll(sockfd, (int)timeout, pollRx, pollTx);
+ ret = socketPoll(appData, sockfd, (int)timeout, pollRx,
+ pollTx, 0);
#endif
if ((ret == WOLFJNI_IO_EVENT_RECV_READY) ||
(ret == WOLFJNI_IO_EVENT_SEND_READY)) {
@@ -1017,7 +1282,9 @@ static int SSLReadNonblockingWithSelectPoll(WOLFSSL* ssl, byte* out,
{
int size, ret, err, sockfd;
int pollRx = 0;
+#if !defined(WOLFJNI_USE_IO_SELECT) && !defined(USE_WINDOWS_API)
int pollTx = 0;
+#endif
wolfSSL_Mutex* jniSessLock = NULL;
SSLAppData* appData = NULL;
@@ -1065,14 +1332,16 @@ static int SSLReadNonblockingWithSelectPoll(WOLFSSL* ssl, byte* out,
if (err == SSL_ERROR_WANT_READ) {
pollRx = 1;
}
+ #if !defined(WOLFJNI_USE_IO_SELECT) && !defined(USE_WINDOWS_API)
else if (err == SSL_ERROR_WANT_WRITE) {
pollTx = 1;
}
+ #endif
#if defined(WOLFJNI_USE_IO_SELECT) || defined(USE_WINDOWS_API)
- ret = socketSelect(sockfd, timeout, pollRx);
+ ret = socketSelect(appData, sockfd, timeout, pollRx, 0);
#else
- ret = socketPoll(sockfd, timeout, pollRx, pollTx);
+ ret = socketPoll(appData, sockfd, timeout, pollRx, pollTx, 0);
#endif
if ((ret == WOLFJNI_IO_EVENT_RECV_READY) ||
(ret == WOLFJNI_IO_EVENT_SEND_READY)) {
@@ -1152,7 +1421,7 @@ JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_read__JLjava_nio_ByteBuff
jint position;
jint limit;
jboolean hasArray;
- jbyteArray bufArr;
+ jbyteArray bufArr = NULL;
(void)jcl;
@@ -1304,7 +1573,9 @@ JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_accept
{
int ret = 0, err, sockfd;
int pollRx = 0;
+#if !defined(WOLFJNI_USE_IO_SELECT) && !defined(USE_WINDOWS_API)
int pollTx = 0;
+#endif
wolfSSL_Mutex* jniSessLock = NULL;
SSLAppData* appData = NULL;
WOLFSSL* ssl = (WOLFSSL*)(uintptr_t)sslPtr;
@@ -1361,14 +1632,16 @@ JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_accept
if (err == SSL_ERROR_WANT_READ) {
pollRx = 1;
}
+ #if !defined(WOLFJNI_USE_IO_SELECT) && !defined(USE_WINDOWS_API)
else if (err == SSL_ERROR_WANT_WRITE) {
pollTx = 1;
}
+ #endif
#if defined(WOLFJNI_USE_IO_SELECT) || defined(USE_WINDOWS_API)
- ret = socketSelect(sockfd, (int)timeout, pollRx);
+ ret = socketSelect(appData, sockfd, (int)timeout, pollRx, 0);
#else
- ret = socketPoll(sockfd, (int)timeout, pollRx, pollTx);
+ ret = socketPoll(appData, sockfd, (int)timeout, pollRx, pollTx, 0);
#endif
if ((ret == WOLFJNI_IO_EVENT_RECV_READY) ||
(ret == WOLFJNI_IO_EVENT_SEND_READY)) {
@@ -1441,6 +1714,16 @@ JNIEXPORT void JNICALL Java_com_wolfssl_WolfSSLSession_freeSSL
XFREE(g_cachedVerifyCb, NULL, DYNAMIC_TYPE_TMP_BUFFER);
g_cachedVerifyCb = NULL;
}
+#ifndef USE_WINDOWS_API
+ if (appData->pollCountLock != NULL) {
+ wc_FreeMutex(appData->pollCountLock);
+ XFREE(appData->pollCountLock, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+ appData->pollCountLock = NULL;
+ }
+
+ /* close pipe() descriptors */
+ closeInterruptPipe(appData);
+#endif
/* free appData */
XFREE(appData, NULL, DYNAMIC_TYPE_TMP_BUFFER);
appData = NULL;
@@ -1553,7 +1836,9 @@ JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_shutdownSSL
{
int ret = 0, err, sockfd;
int pollRx = 0;
+#if !defined(WOLFJNI_USE_IO_SELECT) && !defined(USE_WINDOWS_API)
int pollTx = 0;
+#endif
wolfSSL_Mutex* jniSessLock;
SSLAppData* appData = NULL;
WOLFSSL* ssl = (WOLFSSL*)(uintptr_t)sslPtr;
@@ -1610,14 +1895,16 @@ JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_shutdownSSL
if (err == SSL_ERROR_WANT_READ) {
pollRx = 1;
}
+ #if !defined(WOLFJNI_USE_IO_SELECT) && !defined(USE_WINDOWS_API)
else if (err == SSL_ERROR_WANT_WRITE) {
pollTx = 1;
}
+ #endif
#if defined(WOLFJNI_USE_IO_SELECT) || defined(USE_WINDOWS_API)
- ret = socketSelect(sockfd, (int)timeout, pollRx);
+ ret = socketSelect(appData, sockfd, (int)timeout, pollRx, 1);
#else
- ret = socketPoll(sockfd, (int)timeout, pollRx, pollTx);
+ ret = socketPoll(appData, sockfd, (int)timeout, pollRx, pollTx, 1);
#endif
if ((ret == WOLFJNI_IO_EVENT_RECV_READY) ||
(ret == WOLFJNI_IO_EVENT_SEND_READY)) {
@@ -1822,11 +2109,11 @@ JNIEXPORT jlong JNICALL Java_com_wolfssl_WolfSSLSession_get1Session
#if defined(WOLFJNI_USE_IO_SELECT) || defined(USE_WINDOWS_API)
/* Default to select() on Windows or if WOLFJNI_USE_IO_SELECT */
- ret = socketSelect(sockfd,
- (int)WOLFSSL_JNI_DEFAULT_PEEK_TIMEOUT, 1);
- #else
- ret = socketPoll(sockfd,
+ ret = socketSelect(appData, sockfd,
(int)WOLFSSL_JNI_DEFAULT_PEEK_TIMEOUT, 1, 0);
+ #else
+ ret = socketPoll(appData, sockfd,
+ (int)WOLFSSL_JNI_DEFAULT_PEEK_TIMEOUT, 1, 0, 0);
#endif
if ((ret == WOLFJNI_IO_EVENT_RECV_READY) ||
(ret == WOLFJNI_IO_EVENT_SEND_READY)) {
@@ -3558,12 +3845,8 @@ JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_getSide
(void)jenv;
(void)jcl;
-#ifdef ATOMIC_USER
/* wolfSSL checks ssl for NULL */
return wolfSSL_GetSide((WOLFSSL*)(uintptr_t)ssl);
-#else
- return NOT_COMPILED_IN;
-#endif
}
JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_isTLSv1_11
@@ -5445,6 +5728,51 @@ JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_hasTicket
#endif
}
+JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_interruptBlockedIO
+ (JNIEnv* jenv, jobject jcl, jlong sslPtr)
+{
+#ifndef USE_WINDOWS_API
+ SSLAppData* appData = NULL;
+ WOLFSSL* ssl = (WOLFSSL*)(uintptr_t)sslPtr;
+#endif
+ (void)jenv;
+ (void)jcl;
+
+#ifndef USE_WINDOWS_API
+ /* get session mutex from SSL app data */
+ appData = (SSLAppData*)wolfSSL_get_app_data(ssl);
+ if (appData == NULL) {
+ return WOLFSSL_FAILURE;
+ }
+
+ /* signal any blocked threads in select()/poll() to wake up, so we
+ * don't have a deadlock when trying to lock jniSessLock next */
+ writeToInterruptPipe(appData);
+ writeToInterruptPipe(appData);
+
+#endif /* USE_WINDOWS_API */
+
+ return SSL_SUCCESS;
+}
+
+JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_getThreadsBlockedInPoll
+ (JNIEnv* jenv, jobject jcl, jlong sslPtr)
+{
+ SSLAppData* appData = NULL;
+ WOLFSSL* ssl = (WOLFSSL*)(uintptr_t)sslPtr;
+
+ (void)jenv;
+ (void)jcl;
+
+ /* get session mutex from SSL app data */
+ appData = (SSLAppData*)wolfSSL_get_app_data(ssl);
+ if (appData == NULL) {
+ return 0;
+ }
+
+ return (jint)threadsWaitingInPollSelect(appData);
+}
+
JNIEXPORT void JNICALL Java_com_wolfssl_WolfSSLSession_setSSLIORecv
(JNIEnv* jenv, jobject jcl, jlong sslPtr)
{
diff --git a/native/com_wolfssl_WolfSSLSession.h b/native/com_wolfssl_WolfSSLSession.h
index 639db768..260032ca 100644
--- a/native/com_wolfssl_WolfSSLSession.h
+++ b/native/com_wolfssl_WolfSSLSession.h
@@ -10,10 +10,10 @@ extern "C" {
/*
* Class: com_wolfssl_WolfSSLSession
* Method: newSSL
- * Signature: (J)J
+ * Signature: (JZ)J
*/
JNIEXPORT jlong JNICALL Java_com_wolfssl_WolfSSLSession_newSSL
- (JNIEnv *, jobject, jlong);
+ (JNIEnv *, jobject, jlong, jboolean);
/*
* Class: com_wolfssl_WolfSSLSession
@@ -879,6 +879,22 @@ JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_useSupportedCurve
JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_hasTicket
(JNIEnv *, jobject, jlong);
+/*
+ * Class: com_wolfssl_WolfSSLSession
+ * Method: interruptBlockedIO
+ * Signature: (J)I
+ */
+JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_interruptBlockedIO
+ (JNIEnv *, jobject, jlong);
+
+/*
+ * Class: com_wolfssl_WolfSSLSession
+ * Method: getThreadsBlockedInPoll
+ * Signature: (J)I
+ */
+JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_getThreadsBlockedInPoll
+ (JNIEnv *, jobject, jlong);
+
#ifdef __cplusplus
}
#endif
diff --git a/src/java/com/wolfssl/WolfSSLSession.java b/src/java/com/wolfssl/WolfSSLSession.java
index 8090a53d..e34891ec 100644
--- a/src/java/com/wolfssl/WolfSSLSession.java
+++ b/src/java/com/wolfssl/WolfSSLSession.java
@@ -102,6 +102,13 @@ public class WolfSSLSession {
/**
* Creates a new SSL/TLS session.
*
+ * Native session created also creates JNI SSLAppData for usage
+ * internal to wolfSSL JNI. This constructor creates a default
+ * pipe() to use for interrupting threads waiting in select()/poll()
+ * when close() is called. To skip creation of this pipe() use
+ * the WolfSSLSession(WolfSSLContext ctx, boolean setupIOPipe)
+ * constructor with 'setupIOPipe' set to false.
+ *
* @param ctx WolfSSLContext object used to create SSL session.
*
* @throws com.wolfssl.WolfSSLException if session object creation
@@ -109,13 +116,61 @@ public class WolfSSLSession {
*/
public WolfSSLSession(WolfSSLContext ctx) throws WolfSSLException {
- sslPtr = newSSL(ctx.getContextPtr());
+ sslPtr = newSSL(ctx.getContextPtr(), true);
if (sslPtr == 0) {
throw new WolfSSLException("Failed to create SSL Object");
}
WolfSSLDebug.log(getClass(), WolfSSLDebug.Component.JNI,
- WolfSSLDebug.INFO, sslPtr, "creating new WolfSSLSession");
+ WolfSSLDebug.INFO, sslPtr,
+ "creating new WolfSSLSession (with I/O pipe)");
+
+ synchronized (stateLock) {
+ this.active = true;
+ }
+
+ /* save context reference for I/O callbacks from JNI */
+ this.ctx = ctx;
+ }
+
+ /**
+ * Creates a new SSL/TLS session.
+ *
+ * Native session created also creates JNI SSLAppData for usage
+ * internal to wolfSSL JNI. A pipe() can be created internally to wolfSSL
+ * JNI to use for interrupting threads waiting in select()/poll()
+ * when close() is called. To skip creation of this pipe(), set
+ * 'setupIOPipe' to false.
+ *
+ * It is generally recommended to have wolfSSL JNI create the native
+ * pipe(), unless you will be operating over non-Socket I/O. For example,
+ * when this WolfSSLSession is being created from the JSSE level
+ * SSLEngine class.
+ *
+ * @param ctx WolfSSLContext object used to create SSL session.
+ * @param setupIOPipe true to create internal IO pipe(), otherwise
+ * false
+ *
+ * @throws com.wolfssl.WolfSSLException if session object creation
+ * failed.
+ */
+ public WolfSSLSession(WolfSSLContext ctx, boolean setupIOPipe)
+ throws WolfSSLException {
+
+ sslPtr = newSSL(ctx.getContextPtr(), false);
+ if (sslPtr == 0) {
+ throw new WolfSSLException("Failed to create SSL Object");
+ }
+
+ if (setupIOPipe) {
+ WolfSSLDebug.log(getClass(), WolfSSLDebug.Component.JNI,
+ WolfSSLDebug.INFO, sslPtr,
+ "creating new WolfSSLSession (with I/O pipe)");
+ } else {
+ WolfSSLDebug.log(getClass(), WolfSSLDebug.Component.JNI,
+ WolfSSLDebug.INFO, sslPtr,
+ "creating new WolfSSLSession (without I/O pipe)");
+ }
synchronized (stateLock) {
this.active = true;
@@ -240,7 +295,7 @@ private synchronized void confirmObjectIsActive()
/* ------------------ native method declarations -------------------- */
- private native long newSSL(long ctx);
+ private native long newSSL(long ctx, boolean withIOPipe);
private native int setFd(long ssl, Socket sd, int type);
private native int setFd(long ssl, DatagramSocket sd, int type);
private native int useCertificateFile(long ssl, String file, int format);
@@ -357,6 +412,8 @@ private native int setTlsHmacInner(long ssl, byte[] inner, long sz,
private native int set1SigAlgsList(long ssl, String list);
private native int useSupportedCurve(long ssl, int name);
private native int hasTicket(long session);
+ private native int interruptBlockedIO(long ssl);
+ private native int getThreadsBlockedInPoll(long ssl);
/* ------------------- session-specific methods --------------------- */
@@ -4125,6 +4182,49 @@ public synchronized void setIOSend(WolfSSLIOSendCallback callback)
}
}
+ /**
+ * Interrupt native I/O operations blocked inside select()/poll().
+ *
+ * This is used by wolfJSSE when SSLSocket.close() is called, to wake up
+ * threads that are blocked in select()/poll().
+ *
+ * @return WolfSSL.SSL_SUCCESS on success, negative on error.
+ *
+ * @throws IllegalStateException WolfSSLSession has been freed
+ */
+ public synchronized int interruptBlockedIO()
+ throws IllegalStateException {
+
+ confirmObjectIsActive();
+
+ /* Not synchronizing on sslLock, since we want to interrupt threads
+ * blocked on I/O operations, which will already hold sslLock */
+
+ WolfSSLDebug.log(getClass(), WolfSSLDebug.Component.JNI,
+ WolfSSLDebug.INFO, "entered interruptBlockedIO()");
+
+ return interruptBlockedIO(this.sslPtr);
+ }
+
+ /**
+ * Get count of threads currently blocked in select() or poll()
+ * at the native JNI level.
+ *
+ * @return count of threads waiting in select() or poll()
+ *
+ * @throws IllegalStateException WolfSSLSession has been freed
+ */
+ public synchronized int getThreadsBlockedInPoll()
+ throws IllegalStateException {
+
+ confirmObjectIsActive();
+
+ WolfSSLDebug.log(getClass(), WolfSSLDebug.Component.JNI,
+ WolfSSLDebug.INFO, "entered getThreadsBlockedInPoll()");
+
+ return getThreadsBlockedInPoll(this.sslPtr);
+ }
+
/**
* Use SNI name with this session.
*
diff --git a/src/java/com/wolfssl/provider/jsse/WolfSSLEngine.java b/src/java/com/wolfssl/provider/jsse/WolfSSLEngine.java
index 9b3f2305..b2699402 100644
--- a/src/java/com/wolfssl/provider/jsse/WolfSSLEngine.java
+++ b/src/java/com/wolfssl/provider/jsse/WolfSSLEngine.java
@@ -313,7 +313,7 @@ private void initSSL() throws WolfSSLException, WolfSSLJNIException {
}
/* will throw WolfSSLException if issue creating WOLFSSL */
- ssl = new WolfSSLSession(ctx);
+ ssl = new WolfSSLSession(ctx, false);
enableExtraDebug();
enableIODebug();
diff --git a/src/java/com/wolfssl/provider/jsse/WolfSSLSocket.java b/src/java/com/wolfssl/provider/jsse/WolfSSLSocket.java
index d29278ce..293d94dd 100644
--- a/src/java/com/wolfssl/provider/jsse/WolfSSLSocket.java
+++ b/src/java/com/wolfssl/provider/jsse/WolfSSLSocket.java
@@ -2011,6 +2011,10 @@ public synchronized void close() throws IOException {
handshakeFinished = this.handshakeComplete;
}
+ WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
+ "signaling any blocked I/O threads to wake up");
+ ssl.interruptBlockedIO();
+
/* Try TLS shutdown procedure, only if handshake has finished */
if (ssl != null && handshakeFinished) {
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
@@ -2036,12 +2040,15 @@ public synchronized void close() throws IOException {
}
try {
+ /* Use SO_LINGER value when calling
+ * shutdown here, since we are closing the
+ * socket */
if (this.socket != null) {
ret = ssl.shutdownSSL(
- this.socket.getSoTimeout());
+ this.socket.getSoLinger());
} else {
ret = ssl.shutdownSSL(
- super.getSoTimeout());
+ super.getSoLinger());
}
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
@@ -2065,9 +2072,7 @@ public synchronized void close() throws IOException {
/* Release native verify callback (JNI global) */
this.EngineHelper.unsetVerifyCallback();
- /* Connection is closed, free native WOLFSSL session
- * to release native memory earlier than garbage
- * collector might with finalize(). */
+ /* Close ConsumedRecvCtx data stream */
Object readCtx = this.ssl.getIOReadCtx();
if (readCtx != null &&
readCtx instanceof ConsumedRecvCtx) {
@@ -2076,14 +2081,6 @@ public synchronized void close() throws IOException {
"calling ConsumedRecvCtx.closeDataStreams()");
rctx.closeDataStreams();
}
- WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
- "calling this.ssl.freeSSL()");
- this.ssl.freeSSL();
- this.ssl = null;
-
- /* Reset internal WolfSSLEngineHelper to null */
- this.EngineHelper.clearObjectState();
- this.EngineHelper = null;
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"thread exiting handshakeLock (shutdown)");
@@ -2112,6 +2109,33 @@ public synchronized void close() throws IOException {
this.outStream = null;
}
}
+
+ /* Free this.ssl here instead of above for use cases
+ * where a SSLSocket is created then closed()'d before
+ * connected or handshake is done. freeSSL() will
+ * release interruptFds[] pipe() and free up descriptor. */
+ synchronized (ioLock) {
+ WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
+ "thread got ioLock (freeSSL)");
+
+ /* Connection is closed, free native WOLFSSL session
+ * to release native memory earlier than garbage
+ * collector might with finalize(), if we don't
+ * have any threads still waiting in poll/select. */
+ if (this.ssl.getThreadsBlockedInPoll() == 0) {
+ WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
+ "calling this.ssl.freeSSL()");
+ this.ssl.freeSSL();
+ this.ssl = null;
+ }
+
+ /* Reset internal WolfSSLEngineHelper to null */
+ this.EngineHelper.clearObjectState();
+ this.EngineHelper = null;
+
+ WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
+ "thread exiting ioLock (shutdown)");
+ } /* ioLock */
}
if (this.autoClose) {
@@ -2687,7 +2711,11 @@ public synchronized int read(byte[] b, int off, int len)
throw e;
} catch (IllegalStateException e) {
- throw new IOException(e);
+ /* SSLSocket.close() may have already called freeSSL(),
+ * thus causing a 'WolfSSLSession object has been freed'
+ * IllegalStateException to be thrown from
+ * WolfSSLSession.read(). Return as a SocketException here. */
+ throw new SocketException(e.getMessage());
}
/* return number of bytes read */
diff --git a/src/test/com/wolfssl/provider/jsse/test/WolfSSLSocketTest.java b/src/test/com/wolfssl/provider/jsse/test/WolfSSLSocketTest.java
index d21a83a7..9405ea19 100644
--- a/src/test/com/wolfssl/provider/jsse/test/WolfSSLSocketTest.java
+++ b/src/test/com/wolfssl/provider/jsse/test/WolfSSLSocketTest.java
@@ -59,6 +59,7 @@
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSessionContext;
import javax.net.ssl.SSLSocketFactory;
+import javax.net.ssl.SSLServerSocketFactory;
import javax.net.ssl.SSLParameters;
import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
@@ -116,6 +117,8 @@
public void testSessionResumptionWithTicketEnabled();
public void testDoubleSocketClose();
public void testSocketConnectException();
+ public void testSocketCloseInterruptsWrite();
+ public void testSocketCloseInterruptsRead();
*/
public class WolfSSLSocketTest {
@@ -465,6 +468,8 @@ public void testEnabledSupportedCurvesProperty() throws Exception {
TestClient client = null;
Exception srvException = null;
Exception cliException = null;
+ CountDownLatch sDoneLatch = null;
+ CountDownLatch cDoneLatch = null;
System.out.print("\twolfjsse.enabledSupportedCurves");
@@ -485,11 +490,19 @@ public void testEnabledSupportedCurvesProperty() throws Exception {
TestArgs sArgs = new TestArgs(null, null, true, true, true, null);
TestArgs cArgs = new TestArgs(null, null, false, false, true, null);
- server = new TestServer(this.ctx, ss, sArgs, 1);
+
+ sDoneLatch = new CountDownLatch(1);
+ cDoneLatch = new CountDownLatch(1);
+
+ server = new TestServer(this.ctx, ss, sArgs, 1, sDoneLatch);
server.start();
- client = new TestClient(this.ctx, ss.getLocalPort(), cArgs);
+ client = new TestClient(this.ctx, ss.getLocalPort(), cArgs,
+ cDoneLatch);
client.start();
+ cDoneLatch.await();
+ sDoneLatch.await();
+
srvException = server.getException();
if (srvException != null) {
Security.setProperty("wolfjsse.enabledSupportedCurves",
@@ -527,11 +540,19 @@ public void testEnabledSupportedCurvesProperty() throws Exception {
TestArgs sArgs = new TestArgs(null, null, true, true, true, null);
TestArgs cArgs = new TestArgs(null, null, false, false, true, null);
- server = new TestServer(this.ctx, ss, sArgs, 1);
+
+ sDoneLatch = new CountDownLatch(1);
+ cDoneLatch = new CountDownLatch(1);
+
+ server = new TestServer(this.ctx, ss, sArgs, 1, sDoneLatch);
server.start();
- client = new TestClient(this.ctx, ss.getLocalPort(), cArgs);
+ client = new TestClient(this.ctx, ss.getLocalPort(), cArgs,
+ cDoneLatch);
client.start();
+ cDoneLatch.await();
+ sDoneLatch.await();
+
srvException = server.getException();
if (srvException != null) {
Security.setProperty("wolfjsse.enabledSupportedCurves",
@@ -569,11 +590,19 @@ public void testEnabledSupportedCurvesProperty() throws Exception {
TestArgs sArgs = new TestArgs(null, null, true, true, true, null);
TestArgs cArgs = new TestArgs(null, null, false, false, true, null);
- server = new TestServer(this.ctx, ss, sArgs, 1);
+
+ sDoneLatch = new CountDownLatch(1);
+ cDoneLatch = new CountDownLatch(1);
+
+ server = new TestServer(this.ctx, ss, sArgs, 1, sDoneLatch);
server.start();
- client = new TestClient(this.ctx, ss.getLocalPort(), cArgs);
+ client = new TestClient(this.ctx, ss.getLocalPort(), cArgs,
+ cDoneLatch);
client.start();
+ cDoneLatch.await();
+ sDoneLatch.await();
+
srvException = server.getException();
if (srvException != null) {
Security.setProperty("wolfjsse.enabledSupportedCurves",
@@ -600,7 +629,9 @@ public void testEnabledSupportedCurvesProperty() throws Exception {
}
}
- /* Test with invalid property entries */
+ /* Test with invalid property entries.
+ * Only need to start client thread, since it throws exception
+ * before connecting to server. */
{
Security.setProperty("wolfjsse.enabledSupportedCurves",
"badone, badtwo");
@@ -609,19 +640,15 @@ public void testEnabledSupportedCurvesProperty() throws Exception {
ss = (SSLServerSocket)ctx.getServerSocketFactory()
.createServerSocket(0);
- TestArgs sArgs = new TestArgs(null, null, true, true, true, null);
TestArgs cArgs = new TestArgs(null, null, false, false, true, null);
- server = new TestServer(this.ctx, ss, sArgs, 1);
- server.start();
- client = new TestClient(this.ctx, ss.getLocalPort(), cArgs);
+
+ cDoneLatch = new CountDownLatch(1);
+
+ client = new TestClient(this.ctx, ss.getLocalPort(), cArgs,
+ cDoneLatch);
client.start();
- srvException = server.getException();
- if (srvException != null) {
- Security.setProperty("wolfjsse.enabledSupportedCurves",
- originalProperty);
- throw srvException;
- }
+ cDoneLatch.await();
cliException = client.getException();
if (cliException != null) {
@@ -630,7 +657,7 @@ public void testEnabledSupportedCurvesProperty() throws Exception {
try {
client.join(1000);
- server.join(1000);
+ //server.join(1000);
} catch (InterruptedException e) {
System.out.println("interrupt happened");
@@ -656,6 +683,9 @@ public void testEnabledSupportedCurvesProperty() throws Exception {
@Test
public void testClientServerThreaded() throws Exception {
+ CountDownLatch sDoneLatch = null;
+ CountDownLatch cDoneLatch = null;
+
System.out.print("\tTesting basic client/server");
/* create new CTX */
@@ -668,12 +698,18 @@ public void testClientServerThreaded() throws Exception {
TestArgs sArgs = new TestArgs(null, null, true, true, true, null);
TestArgs cArgs = new TestArgs(null, null, false, false, true, null);
- TestServer server = new TestServer(this.ctx, ss, sArgs, 1);
+ sDoneLatch = new CountDownLatch(1);
+ cDoneLatch = new CountDownLatch(1);
+
+ TestServer server = new TestServer(this.ctx, ss, sArgs, 1, sDoneLatch);
server.start();
- TestClient client = new TestClient(this.ctx, ss.getLocalPort(), cArgs);
+ TestClient client = new TestClient(this.ctx, ss.getLocalPort(), cArgs,
+ cDoneLatch);
client.start();
+ cDoneLatch.await();
+ sDoneLatch.await();
Exception srvException = server.getException();
if (srvException != null) {
@@ -700,6 +736,9 @@ public void testClientServerThreaded() throws Exception {
public void alpnClientServerRunner(TestArgs sArgs, TestArgs cArgs,
boolean expectingException) throws Exception {
+ CountDownLatch sDoneLatch = null;
+ CountDownLatch cDoneLatch = null;
+
if (sArgs == null || cArgs == null) {
throw new Exception("client/server TestArgs can not be null");
}
@@ -710,12 +749,19 @@ public void alpnClientServerRunner(TestArgs sArgs, TestArgs cArgs,
SSLServerSocket ss = (SSLServerSocket)ctx.getServerSocketFactory()
.createServerSocket(0);
- TestServer server = new TestServer(this.ctx, ss, sArgs, 1);
+ sDoneLatch = new CountDownLatch(1);
+ cDoneLatch = new CountDownLatch(1);
+
+ TestServer server = new TestServer(this.ctx, ss, sArgs, 1, sDoneLatch);
server.start();
- TestClient client = new TestClient(this.ctx, ss.getLocalPort(), cArgs);
+ TestClient client = new TestClient(this.ctx, ss.getLocalPort(), cArgs,
+ cDoneLatch);
client.start();
+ cDoneLatch.await();
+ sDoneLatch.await();
+
try {
client.join(1000);
server.join(1000);
@@ -988,7 +1034,7 @@ public void testExtendedThreadingUse()
/* This test hangs on Android, marking TODO for later investigation. Seems to be
* something specific to the test code, not library proper. */
- if (tf.isAndroid()) {
+ if (WolfSSLTestFactory.isAndroid()) {
System.out.println("\t... skipped");
return;
}
@@ -2746,6 +2792,271 @@ public Void call() throws Exception {
System.out.println("\t... passed");
}
+ /* Test timeout set to 10000 ms (10 sec) in case inerrupt code is not
+ * working as expected, we will see the timeout as a hard error that
+ * this test has failed */
+ @Test(timeout = 10000)
+ public void testSocketCloseInterruptsWrite() throws Exception {
+
+ String protocol = null;
+ SSLServerSocketFactory ssf = null;
+ SSLServerSocket ss = null;
+ SSLSocketFactory sf = null;
+ boolean passed = false;
+
+ System.out.print("\tTesting close/write interrupt");
+
+ /* pipe() interrupt mechamism not implemented for Windows yet since
+ * Windows does not support Unix/Linux pipe(). Re-enable this test
+ * for Windows when that support has been added */
+ if (WolfSSLTestFactory.isWindows()) {
+ System.out.println("\t... skipped");
+ return;
+ }
+
+ if (WolfSSL.TLSv12Enabled()) {
+ protocol = "TLSv1.2";
+ } else if (WolfSSL.TLSv11Enabled()) {
+ protocol = "TLSv1.1";
+ } else if (WolfSSL.TLSv1Enabled()) {
+ protocol = "TLSv1.0";
+ } else {
+ System.out.println("\t... skipped");
+ return;
+ }
+
+ /* create new CTX */
+ this.ctx = tf.createSSLContext(protocol, ctxProvider);
+
+ /* create SSLServerSocket first to get ephemeral port */
+ ss = (SSLServerSocket)ctx.getServerSocketFactory()
+ .createServerSocket(0);
+
+ final SSLSocket cs = (SSLSocket)ctx.getSocketFactory().createSocket();
+ cs.connect(new InetSocketAddress(ss.getLocalPort()));
+
+ final SSLSocket server = (SSLSocket)ss.accept();
+ final CountDownLatch closeLatch = new CountDownLatch(1);
+
+ ExecutorService es = Executors.newSingleThreadExecutor();
+ Future serverFuture = es.submit(new Callable() {
+ @Override
+ public Void call() throws Exception {
+ try {
+ server.startHandshake();
+
+ boolean doClose = closeLatch.await(90L, TimeUnit.SECONDS);
+ if (!doClose) {
+ /* Return without closing, latch not hit within
+ * time limit */
+ return null;
+ }
+
+ /* Sleep so write thread has a chance to do some
+ * writing before interrupt */
+ Thread.sleep(1000);
+ cs.setSoLinger(true, 5);
+ cs.close();
+
+ } catch (SSLException e) {
+ System.out.println("\t... failed");
+ e.printStackTrace();
+ fail("Server thread got SSLException when not expected");
+ }
+ return null;
+ }
+ });
+
+ byte[] tmpArr = new byte[1024];
+ Arrays.fill(tmpArr, (byte)0xA2);
+ OutputStream out = cs.getOutputStream();
+
+ try {
+ try {
+ cs.startHandshake();
+ out.write(tmpArr);
+ }
+ catch (Exception e) {
+ System.out.println("\t... failed");
+ e.printStackTrace();
+ fail("Exception from first out.write() when not expected");
+ }
+
+ try {
+ /* signal server thread to try and close socket */
+ closeLatch.countDown();
+
+ /* keep writing, we should get interrupted */
+ while (true) {
+ out.write(tmpArr);
+ }
+
+ } catch (SocketException e) {
+ /* We expect SocketException with this message, error if
+ * different than expected */
+ if (!e.getMessage().contains("Socket fd closed during poll")) {
+ System.out.println("\t... failed");
+ e.printStackTrace();
+ fail("Incorrect SocketException thrown by client");
+ throw e;
+ }
+
+ passed = true;
+ }
+ }
+ finally {
+ es.shutdown();
+ serverFuture.get();
+ if (!cs.isClosed()) {
+ cs.close();
+ }
+ if (!server.isClosed()) {
+ server.close();
+ }
+ if (!ss.isClosed()) {
+ ss.close();
+ }
+ }
+
+ if (passed) {
+ System.out.println("\t... passed");
+ }
+ }
+
+ /* Test timeout set to 10000 ms (10 sec) in case inerrupt code is not
+ * working as expected, we will see the timeout as a hard error that
+ * this test has failed */
+ @Test(timeout = 10000)
+ public void testSocketCloseInterruptsRead() throws Exception {
+
+ int ret = 0;
+ String protocol = null;
+ SSLServerSocketFactory ssf = null;
+ SSLServerSocket ss = null;
+ SSLSocketFactory sf = null;
+ boolean passed = false;
+
+ System.out.print("\tTesting close/read interrupt");
+
+ /* pipe() interrupt mechamism not implemented for Windows yet since
+ * Windows does not support Unix/Linux pipe(). Re-enable this test
+ * for Windows when that support has been added */
+ if (WolfSSLTestFactory.isWindows()) {
+ System.out.println("\t... skipped");
+ return;
+ }
+
+ if (WolfSSL.TLSv12Enabled()) {
+ protocol = "TLSv1.2";
+ } else if (WolfSSL.TLSv11Enabled()) {
+ protocol = "TLSv1.1";
+ } else if (WolfSSL.TLSv1Enabled()) {
+ protocol = "TLSv1.0";
+ } else {
+ System.out.println("\t... skipped");
+ return;
+ }
+
+ /* create new CTX */
+ this.ctx = tf.createSSLContext(protocol, ctxProvider);
+
+ /* create SSLServerSocket first to get ephemeral port */
+ ss = (SSLServerSocket)ctx.getServerSocketFactory()
+ .createServerSocket(0);
+
+ final SSLSocket cs = (SSLSocket)ctx.getSocketFactory().createSocket();
+ cs.connect(new InetSocketAddress(ss.getLocalPort()));
+
+ final SSLSocket server = (SSLSocket)ss.accept();
+ final CountDownLatch closeLatch = new CountDownLatch(1);
+
+ ExecutorService es = Executors.newSingleThreadExecutor();
+ Future serverFuture = es.submit(new Callable() {
+ @Override
+ public Void call() throws Exception {
+ try {
+ server.startHandshake();
+
+ boolean doClose = closeLatch.await(90L, TimeUnit.SECONDS);
+ if (!doClose) {
+ /* Return without closing, latch not hit within
+ * time limit */
+ return null;
+ }
+
+ /* Sleep to let client thread hit read call */
+ Thread.sleep(1000);
+ cs.setSoLinger(true, 5);
+ cs.close();
+
+ } catch (SSLException e) {
+ System.out.println("\t... failed");
+ e.printStackTrace();
+ fail("Server thread got SSLException when not expected");
+ }
+ return null;
+ }
+ });
+
+ byte[] tmpArr = new byte[1024];
+ InputStream in = cs.getInputStream();
+
+ try {
+ try {
+ cs.startHandshake();
+ }
+ catch (Exception e) {
+ System.out.println("\t... failed");
+ e.printStackTrace();
+ fail("Exception from startHandshake() when not expected");
+ }
+
+ try {
+ /* signal server thread to try and close socket */
+ closeLatch.countDown();
+
+ while (true) {
+ ret = in.read(tmpArr, 0, tmpArr.length);
+ if (ret == -1) {
+ /* end of stream */
+ break;
+ }
+ }
+
+ } catch (SocketException e) {
+ /* We expect SocketException with this message, error if
+ * different than expected */
+ if (!e.getMessage().contains("Socket is closed") &&
+ !e.getMessage().contains("Connection already shutdown") &&
+ !e.getMessage().contains("object has been freed")) {
+ System.out.println("\t... failed");
+ e.printStackTrace();
+ fail("Incorrect SocketException thrown by client");
+ throw e;
+ }
+ }
+
+ passed = true;
+ }
+ finally {
+ es.shutdown();
+ serverFuture.get();
+ if (!cs.isClosed()) {
+ cs.close();
+ }
+ if (!server.isClosed()) {
+ server.close();
+ }
+ if (!ss.isClosed()) {
+ ss.close();
+ }
+ }
+
+ if (passed) {
+ System.out.println("\t... passed");
+ }
+ }
+
@Test
public void testSocketMethodsAfterClose() throws Exception {
@@ -3089,13 +3400,15 @@ protected class TestServer extends Thread
private int numConnections = 1;
WolfSSLSocketTest wst;
SSLServerSocket ss = null;
+ CountDownLatch doneLatch = null;
public TestServer(SSLContext ctx, SSLServerSocket ss,
- TestArgs args, int numConnections) {
+ TestArgs args, int numConnections, CountDownLatch doneLatch) {
this.ctx = ctx;
this.ss = ss;
this.args = args;
this.numConnections = numConnections;
+ this.doneLatch = doneLatch;
}
@@ -3175,6 +3488,8 @@ public void run() {
} catch (Exception e) {
this.exception = e;
+ } finally {
+ this.doneLatch.countDown();
}
}
@@ -3202,11 +3517,14 @@ protected class TestClient extends Thread
private Exception exception = null;
private TestArgs args = null;
WolfSSLSocketTest wst;
+ CountDownLatch doneLatch = null;
- public TestClient(SSLContext ctx, int port, TestArgs args) {
+ public TestClient(SSLContext ctx, int port, TestArgs args,
+ CountDownLatch doneLatch) {
this.ctx = ctx;
this.srvPort = port;
this.args = args;
+ this.doneLatch = doneLatch;
}
@Override
@@ -3271,6 +3589,8 @@ public void run() {
} catch (Exception e) {
this.exception = e;
+ } finally {
+ this.doneLatch.countDown();
}
}
diff --git a/src/test/com/wolfssl/provider/jsse/test/WolfSSLTestFactory.java b/src/test/com/wolfssl/provider/jsse/test/WolfSSLTestFactory.java
index 5c4634e7..2b66c431 100644
--- a/src/test/com/wolfssl/provider/jsse/test/WolfSSLTestFactory.java
+++ b/src/test/com/wolfssl/provider/jsse/test/WolfSSLTestFactory.java
@@ -1052,13 +1052,24 @@ protected String[] getAlias() throws KeyStoreException, IOException,
* Test if the env is Android
* @return true if is Android system
*/
- protected boolean isAndroid() {
+ protected static boolean isAndroid() {
if (System.getProperty("java.runtime.name").contains("Android")) {
return true;
}
return false;
}
+ /**
+ * Test if the env is Windows.
+ * @return true if Windows, otherwise false
+ */
+ protected static boolean isWindows() {
+ if (System.getProperty("os.name").startsWith("Windows")) {
+ return true;
+ }
+ return false;
+ }
+
/**
* Check if Security property contains a specific value.
*
diff --git a/src/test/com/wolfssl/provider/jsse/test/WolfSSLTrustX509Test.java b/src/test/com/wolfssl/provider/jsse/test/WolfSSLTrustX509Test.java
index 2ef210b1..ec792054 100644
--- a/src/test/com/wolfssl/provider/jsse/test/WolfSSLTrustX509Test.java
+++ b/src/test/com/wolfssl/provider/jsse/test/WolfSSLTrustX509Test.java
@@ -121,7 +121,7 @@ public void testCAParsing()
System.out.print("\tTesting parse all.jks");
- if (tf.isAndroid()) {
+ if (WolfSSLTestFactory.isAndroid()) {
/* @TODO finding that BKS has different order of certs */
pass("\t... skipped");
return;
@@ -186,7 +186,7 @@ public void testUseBeforeInit()
System.out.print("\tTesting use before init()");
- if (tf.isAndroid()) {
+ if (WolfSSLTestFactory.isAndroid()) {
/* @TODO finding that BKS has different order of certs */
pass("\t... skipped");
return;
@@ -242,7 +242,7 @@ public void testServerParsing()
System.out.print("\tTesting parsing server.jks");
- if (tf.isAndroid()) {
+ if (WolfSSLTestFactory.isAndroid()) {
/* @TODO finding that BKS has different order of certs */
pass("\t... skipped");
return;
@@ -312,7 +312,7 @@ public void testCAParsingMixed()
System.out.print("\tTesting parse all_mixed.jks");
- if (tf.isAndroid()) {
+ if (WolfSSLTestFactory.isAndroid()) {
/* @TODO finding that BKS has different order of certs */
pass("\t... skipped");
return;
@@ -570,7 +570,7 @@ public void testCheckServerTrustedWithChain()
String eccInt1Cert = "examples/certs/intermediate/ca-int-ecc-cert.pem";
String eccInt2Cert = "examples/certs/intermediate/ca-int2-ecc-cert.pem";
- if (tf.isAndroid()) {
+ if (WolfSSLTestFactory.isAndroid()) {
rsaServerCert = "/sdcard/" + rsaServerCert;
rsaInt1Cert = "/sdcard/" + rsaInt1Cert;
rsaInt2Cert = "/sdcard/" + rsaInt2Cert;
@@ -697,7 +697,7 @@ public void testCheckServerTrustedWithBadChainCert()
"examples/certs/intermediate/ca-int-cert.pem";
String eccInt2Cert = "examples/certs/intermediate/ca-int2-ecc-cert.pem";
- if (tf.isAndroid()) {
+ if (WolfSSLTestFactory.isAndroid()) {
rsaServerCert = "/sdcard/" + rsaServerCert;
rsaInt1CertWrong = "/sdcard/" + rsaInt1CertWrong;
rsaInt2Cert = "/sdcard/" + rsaInt2Cert;
@@ -825,7 +825,7 @@ public void testCheckServerTrustedWithWrongChain()
String eccInt1Cert = "examples/certs/intermediate/ca-int-ecc-cert.pem";
String eccInt2Cert = "examples/certs/intermediate/ca-int2-ecc-cert.pem";
- if (tf.isAndroid()) {
+ if (WolfSSLTestFactory.isAndroid()) {
rsaServerCert = "/sdcard/" + rsaServerCert;
rsaInt1Cert = "/sdcard/" + rsaInt1Cert;
rsaInt2Cert = "/sdcard/" + rsaInt2Cert;
@@ -948,7 +948,7 @@ public void testCheckServerTrustedMissingChain()
"examples/certs/intermediate/server-int-ecc-cert.pem";
String eccInt2Cert = "examples/certs/intermediate/ca-int2-ecc-cert.pem";
- if (tf.isAndroid()) {
+ if (WolfSSLTestFactory.isAndroid()) {
rsaServerCert = "/sdcard/" + rsaServerCert;
rsaInt2Cert = "/sdcard/" + rsaInt2Cert;
@@ -1054,7 +1054,7 @@ public void testCheckServerTrustedWithChainWrongOrder()
String eccInt1Cert = "examples/certs/intermediate/ca-int-ecc-cert.pem";
String eccInt2Cert = "examples/certs/intermediate/ca-int2-ecc-cert.pem";
- if (tf.isAndroid()) {
+ if (WolfSSLTestFactory.isAndroid()) {
rsaServerCert = "/sdcard/" + rsaServerCert;
rsaInt1Cert = "/sdcard/" + rsaInt1Cert;
rsaInt2Cert = "/sdcard/" + rsaInt2Cert;
@@ -1180,7 +1180,7 @@ public void testCheckServerTrustedWithChainReturnsChain()
String eccInt1Cert = "examples/certs/intermediate/ca-int-ecc-cert.pem";
String eccInt2Cert = "examples/certs/intermediate/ca-int2-ecc-cert.pem";
- if (tf.isAndroid()) {
+ if (WolfSSLTestFactory.isAndroid()) {
rsaServerCert = "/sdcard/" + rsaServerCert;
rsaInt1Cert = "/sdcard/" + rsaInt1Cert;
rsaInt2Cert = "/sdcard/" + rsaInt2Cert;
@@ -1340,7 +1340,7 @@ public void testCheckServerTrustedWithDuplicatedRootInChain()
String eccInt1Cert = "examples/certs/intermediate/ca-int-ecc-cert.pem";
String eccRootCert = "examples/certs/ca-ecc-cert.pem";
- if (tf.isAndroid()) {
+ if (WolfSSLTestFactory.isAndroid()) {
rsaServerCert = "/sdcard/" + rsaServerCert;
rsaInt1Cert = "/sdcard/" + rsaInt1Cert;
rsaInt2Cert = "/sdcard/" + rsaInt2Cert;
diff --git a/src/test/com/wolfssl/provider/jsse/test/WolfSSLX509Test.java b/src/test/com/wolfssl/provider/jsse/test/WolfSSLX509Test.java
index 7cc255c1..fc5edd79 100644
--- a/src/test/com/wolfssl/provider/jsse/test/WolfSSLX509Test.java
+++ b/src/test/com/wolfssl/provider/jsse/test/WolfSSLX509Test.java
@@ -363,7 +363,7 @@ public void testVerifyProvider() {
break;
}
}
- if (sigProvider == null || tf.isAndroid()) {
+ if (sigProvider == null || WolfSSLTestFactory.isAndroid()) {
pass("\t\t\t... skipped");
return;
}
@@ -511,7 +511,7 @@ public void testGetters()
}
/* Android KeyStore formats x509 getName() differently than peer getName() */
- if (!tf.isAndroid()) {
+ if (!WolfSSLTestFactory.isAndroid()) {
if (!x509.getSubjectDN().getName().equals(
peer.getSubjectDN().getName())) {
error("\t\t... failed");