diff --git a/native/com_wolfssl_WolfSSL.h b/native/com_wolfssl_WolfSSL.h
index a0d1436e..b3cd92ff 100644
--- a/native/com_wolfssl_WolfSSL.h
+++ b/native/com_wolfssl_WolfSSL.h
@@ -9,6 +9,8 @@ extern "C" {
#endif
#undef com_wolfssl_WolfSSL_JNI_SESSION_UNAVAILABLE
#define com_wolfssl_WolfSSL_JNI_SESSION_UNAVAILABLE -10001L
+#undef com_wolfssl_WolfSSL_WOLFJNI_TIMEOUT
+#define com_wolfssl_WolfSSL_WOLFJNI_TIMEOUT -11L
#undef com_wolfssl_WolfSSL_SSL_ERROR_NONE
#define com_wolfssl_WolfSSL_SSL_ERROR_NONE 0L
#undef com_wolfssl_WolfSSL_SSL_FAILURE
diff --git a/native/com_wolfssl_WolfSSLSession.c b/native/com_wolfssl_WolfSSLSession.c
index 2be2fc40..967f9cc8 100644
--- a/native/com_wolfssl_WolfSSLSession.c
+++ b/native/com_wolfssl_WolfSSLSession.c
@@ -554,7 +554,7 @@ JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_getFd
/* enum values used in socketSelect() */
enum {
WOLFJNI_SELECT_FAIL = -10,
- WOLFJNI_TIMEOUT = -11,
+ WOLFJNI_TIMEOUT = -11, /* also in WolfSSL.java */
WOLFJNI_RECV_READY = -12,
WOLFJNI_SEND_READY = -13,
WOLFJNI_ERROR_READY = -14
@@ -623,7 +623,7 @@ JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_connect
(void)jcl;
if (jenv == NULL || ssl == NULL) {
- return SSL_FATAL_ERROR;
+ return SSL_FAILURE;
}
/* make sure we don't have any outstanding exceptions pending */
@@ -674,8 +674,12 @@ JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_connect
if (ret == WOLFJNI_RECV_READY || ret == WOLFJNI_SEND_READY) {
/* I/O ready, continue handshake and try again */
continue;
+ } else if (ret == WOLFJNI_TIMEOUT) {
+ /* Java will throw SocketTimeoutException */
+ break;
} else {
- /* error or timeout */
+ /* error */
+ ret = SSL_FAILURE;
break;
}
}
@@ -745,6 +749,9 @@ JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_write
break;
}
+ if (ret >= 0) /* return if it is success */
+ break;
+
if (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE) {
sockfd = wolfSSL_get_fd(ssl);
diff --git a/src/java/com/wolfssl/WolfSSL.java b/src/java/com/wolfssl/WolfSSL.java
index 965f2704..92e300f5 100644
--- a/src/java/com/wolfssl/WolfSSL.java
+++ b/src/java/com/wolfssl/WolfSSL.java
@@ -56,6 +56,11 @@ public static enum TLS_VERSION {
/** Session unavailable */
public final static int JNI_SESSION_UNAVAILABLE = -10001;
+ /**
+ * Socket timed out, matches com_wolfssl_WolfSSLSession.c socketSelect()
+ * return value */
+ public final static int WOLFJNI_TIMEOUT = -11;
+
/* ----------------------- wolfSSL codes ---------------------------- */
/** Error code: no error */
diff --git a/src/java/com/wolfssl/WolfSSLSession.java b/src/java/com/wolfssl/WolfSSLSession.java
index 2c1b6eea..fdfb5d5a 100644
--- a/src/java/com/wolfssl/WolfSSLSession.java
+++ b/src/java/com/wolfssl/WolfSSLSession.java
@@ -65,6 +65,9 @@ public class WolfSSLSession {
private WolfSSLIORecvCallback internRecvSSLCb;
private WolfSSLIOSendCallback internSendSSLCb;
+ /* have session tickets been enabled for this session? */
+ private boolean sessionTicketsEnabled = true;
+
/* is this context active, or has it been freed? */
private boolean active = false;
@@ -508,16 +511,26 @@ public int getFd()
* before calling newSSL()
, though it's not recommended.
*
* @return SSL_SUCCESS
if successful, otherwise
- * SSL_FATAL_ERROR
if an error occurred. To get
+ * SSL_FAILURE
if an error occurred. To get
* a more detailed error code, call getError()
.
* @throws IllegalStateException WolfSSLContext has been freed
+ * @throws SocketTimeoutException if underlying socket timed out
*/
- public int connect() throws IllegalStateException {
+ public int connect() throws IllegalStateException, SocketTimeoutException {
+
+ int ret = 0;
if (this.active == false)
throw new IllegalStateException("Object has been freed");
- return connect(getSessionPtr(), 0);
+ ret = connect(getSessionPtr(), 0);
+
+ if (ret == WolfSSL.WOLFJNI_TIMEOUT) {
+ throw new SocketTimeoutException(
+ "Native socket timed out during SSL_connect()");
+ }
+
+ return ret;
}
/**
@@ -2710,10 +2723,33 @@ public int useSNI(byte type, byte[] data) throws IllegalStateException {
*/
public int useSessionTicket() throws IllegalStateException {
+ int ret;
+
+ if (this.active == false)
+ throw new IllegalStateException("Object has been freed");
+
+ ret = useSessionTicket(getSessionPtr());
+ if (ret == WolfSSL.SSL_SUCCESS) {
+ this.sessionTicketsEnabled = true;
+ }
+
+ return ret;
+ }
+
+ /**
+ * Determine if session tickets have been enabled for this session.
+ * Session tickets can be enabled for this session by calling
+ * WolfSSLSession.useSessionTicket().
+ *
+ * @return true if enabled, otherwise false.
+ * @throws IllegalStateException WolfSSLSession has been freed
+ */
+ public boolean sessionTicketsEnabled() throws IllegalStateException {
+
if (this.active == false)
throw new IllegalStateException("Object has been freed");
- return useSessionTicket(getSessionPtr());
+ return this.sessionTicketsEnabled;
}
/**
diff --git a/src/java/com/wolfssl/provider/jsse/WolfSSLEngine.java b/src/java/com/wolfssl/provider/jsse/WolfSSLEngine.java
index b3af26fb..1763256d 100644
--- a/src/java/com/wolfssl/provider/jsse/WolfSSLEngine.java
+++ b/src/java/com/wolfssl/provider/jsse/WolfSSLEngine.java
@@ -203,7 +203,11 @@ private int ClosingConnection() {
this.outBoundOpen = false;
hs = SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING;
}
- else if (ret == WolfSSL.SSL_SHUTDOWN_NOT_DONE) {
+ /* wolfSSL_shutdown() will return either SSL_SHUTDOWN_NOT_DONE (2), or
+ * will map that to 0 if WOLFSSL_ERROR_CODE_OPENSSL is defined. Either
+ * should indicate that the full bidirectional shutdown has not
+ * completed. */
+ else if (ret == WolfSSL.SSL_SHUTDOWN_NOT_DONE || ret == 0) {
hs = SSLEngineResult.HandshakeStatus.NEED_UNWRAP;
}
else {
diff --git a/src/java/com/wolfssl/provider/jsse/WolfSSLEngineHelper.java b/src/java/com/wolfssl/provider/jsse/WolfSSLEngineHelper.java
index 09c76514..ef691c75 100644
--- a/src/java/com/wolfssl/provider/jsse/WolfSSLEngineHelper.java
+++ b/src/java/com/wolfssl/provider/jsse/WolfSSLEngineHelper.java
@@ -697,6 +697,7 @@ protected int doHandshake(int isSSLEngine, int timeout)
if (this.clientMode) {
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"calling native wolfSSL_connect()");
+ /* may throw SocketTimeoutException on socket timeout */
ret = this.ssl.connect(timeout);
} else {
diff --git a/src/java/com/wolfssl/provider/jsse/WolfSSLImplementSSLSession.java b/src/java/com/wolfssl/provider/jsse/WolfSSLImplementSSLSession.java
index b5eacb3d..2b754a51 100644
--- a/src/java/com/wolfssl/provider/jsse/WolfSSLImplementSSLSession.java
+++ b/src/java/com/wolfssl/provider/jsse/WolfSSLImplementSSLSession.java
@@ -137,7 +137,9 @@ public synchronized byte[] getId() {
return new byte[0];
}
try {
- if (this.ssl.getVersion().equals("TLSv1.3")) {
+ /* use pseudo session ID if session tickets are being used */
+ if (this.ssl.getVersion().equals("TLSv1.3") ||
+ this.ssl.sessionTicketsEnabled()) {
return this.pseudoSessionID;
}
else {
diff --git a/src/java/com/wolfssl/provider/jsse/WolfSSLSocket.java b/src/java/com/wolfssl/provider/jsse/WolfSSLSocket.java
index 9009c322..378e2047 100644
--- a/src/java/com/wolfssl/provider/jsse/WolfSSLSocket.java
+++ b/src/java/com/wolfssl/provider/jsse/WolfSSLSocket.java
@@ -1130,25 +1130,29 @@ synchronized public void startHandshake() throws IOException {
"entered startHandshake()");
synchronized (handshakeLock) {
- if (handshakeInitCalled == true || handshakeComplete == true) {
- /* handshake already started or finished */
+ if (handshakeComplete == true) {
+ /* handshake already finished */
return;
}
+
+ if (handshakeInitCalled == false) {
+ /* will throw SSLHandshakeException if session creation is
+ not allowed */
+ EngineHelper.initHandshake();
+ handshakeInitCalled = true;
+ }
}
synchronized (ioLock) {
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"thread got ioLock (handshake)");
- /* will throw SSLHandshakeException if session creation is
- not allowed */
- EngineHelper.initHandshake();
- handshakeInitCalled = true;
-
try {
ret = EngineHelper.doHandshake(0, this.getSoTimeout());
} catch (SocketTimeoutException e) {
- throw new IOException(e);
+ WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
+ "got socket timeout in doHandshake()");
+ throw e;
}
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
@@ -1781,8 +1785,15 @@ public int read(byte[] b, int off, int len)
}
/* do handshake if not completed yet, handles synchronization */
- if (socket.handshakeComplete == false) {
- socket.startHandshake();
+ try {
+ /* do handshake if not completed yet, handles synchronization */
+ if (socket.handshakeComplete == false) {
+ socket.startHandshake();
+ }
+ } catch (SocketTimeoutException e) {
+ WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
+ "got socket timeout in read()");
+ throw e;
}
if (b.length == 0 || len == 0) {
@@ -1899,9 +1910,15 @@ public void write(byte[] b, int off, int len) throws IOException {
}
}
- /* do handshake if not completed yet, handles synchronization */
- if (socket.handshakeComplete == false) {
- socket.startHandshake();
+ try {
+ /* do handshake if not completed yet, handles synchronization */
+ if (socket.handshakeComplete == false) {
+ socket.startHandshake();
+ }
+ } catch (SocketTimeoutException e) {
+ WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
+ "got socket timeout in write()");
+ throw e;
}
if (off < 0 || len < 0 || (off + len) > b.length) {
diff --git a/src/test/com/wolfssl/provider/jsse/test/WolfSSLServerSocketTest.java b/src/test/com/wolfssl/provider/jsse/test/WolfSSLServerSocketTest.java
index b1dc3af0..8b424c3e 100644
--- a/src/test/com/wolfssl/provider/jsse/test/WolfSSLServerSocketTest.java
+++ b/src/test/com/wolfssl/provider/jsse/test/WolfSSLServerSocketTest.java
@@ -525,8 +525,10 @@ public Void call() throws Exception {
fail();
} catch (SSLHandshakeException e) {
- /* expected */
- if (!e.toString().contains("ASN no signer")) {
+ /* Expected. Different versions of wolfSSL can display
+ * varying error strings. Check for either here. */
+ if (!e.toString().contains("ASN no signer") &&
+ !e.toString().contains("certificate verify failed")) {
System.out.println("\t\t... failed");
fail();
}
diff --git a/src/test/com/wolfssl/provider/jsse/test/WolfSSLTestFactory.java b/src/test/com/wolfssl/provider/jsse/test/WolfSSLTestFactory.java
index 0cd781c2..1c9e13e2 100644
--- a/src/test/com/wolfssl/provider/jsse/test/WolfSSLTestFactory.java
+++ b/src/test/com/wolfssl/provider/jsse/test/WolfSSLTestFactory.java
@@ -466,8 +466,8 @@ protected int testConnection(SSLEngine server, SSLEngine client,
printHex(serToCli);
}
- System.out.println("cliToSer remaning = " + cliToSer.remaining());
- System.out.println("serToCli remaning = " + serToCli.remaining());
+ System.out.println("cliToSer remaining = " + cliToSer.remaining());
+ System.out.println("serToCli remaining = " + serToCli.remaining());
}
result = client.unwrap(serToCli, cliPlain);
if (extraDebug) {
diff --git a/src/test/com/wolfssl/test/WolfSSLSessionTest.java b/src/test/com/wolfssl/test/WolfSSLSessionTest.java
index 1879bb77..0a97b88c 100644
--- a/src/test/com/wolfssl/test/WolfSSLSessionTest.java
+++ b/src/test/com/wolfssl/test/WolfSSLSessionTest.java
@@ -29,6 +29,7 @@
import java.net.Socket;
import java.net.UnknownHostException;
import java.net.ConnectException;
+import java.net.SocketTimeoutException;
import com.wolfssl.WolfSSL;
import com.wolfssl.WolfSSLContext;
@@ -459,6 +460,10 @@ public void test_WolfSSLSession_UseAfterFree() {
} catch (IllegalStateException ise) {
System.out.println("\t\t... passed");
return;
+ } catch (SocketTimeoutException e) {
+ System.out.println("\t\t... failed");
+ e.printStackTrace();
+ return;
}
/* fail here means WolfSSLSession was used after free without