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