diff --git a/src/java/com/wolfssl/provider/jsse/WolfSSLAuthStore.java b/src/java/com/wolfssl/provider/jsse/WolfSSLAuthStore.java index ace3d528..c1def31f 100644 --- a/src/java/com/wolfssl/provider/jsse/WolfSSLAuthStore.java +++ b/src/java/com/wolfssl/provider/jsse/WolfSSLAuthStore.java @@ -326,7 +326,7 @@ protected synchronized WolfSSLImplementSSLSession getSession( /* Return new session if in server mode, or if host is null */ if (!clientMode || host == null) { - return this.getSession(ssl, clientMode); + return this.getSession(ssl, clientMode, host, port); } WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO, @@ -527,18 +527,22 @@ private void printSessionStoreStatus() { } /** Returns a new session, does not check/save for resumption + * * @param ssl WOLFSSL class to reference with new session * @param clientMode true if on client side, false if server + * @param host hostname of peer, or null if not available + * @param port port of peer + * * @return a new SSLSession on success */ protected synchronized WolfSSLImplementSSLSession getSession( - WolfSSLSession ssl, boolean clientMode) { + WolfSSLSession ssl, boolean clientMode, String host, int port) { WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO, "creating new session"); WolfSSLImplementSSLSession ses = - new WolfSSLImplementSSLSession(ssl, this); + new WolfSSLImplementSSLSession(ssl, this, host, port); ses.setValid(true); ses.isFromTable = false; diff --git a/src/java/com/wolfssl/provider/jsse/WolfSSLEngineHelper.java b/src/java/com/wolfssl/provider/jsse/WolfSSLEngineHelper.java index 1b979581..5a31cf8a 100644 --- a/src/java/com/wolfssl/provider/jsse/WolfSSLEngineHelper.java +++ b/src/java/com/wolfssl/provider/jsse/WolfSSLEngineHelper.java @@ -1262,6 +1262,7 @@ protected synchronized int doHandshake(int isSSLEngine, int timeout) int ret, err; byte[] serverId = null; String hostAddress = null; + String sessCacheHostname = this.hostname; if (!modeSet) { throw new SSLException("setUseClientMode has not been called"); @@ -1293,7 +1294,13 @@ protected synchronized int doHandshake(int isSSLEngine, int timeout) return WolfSSL.SSL_HANDSHAKE_FAILURE; } - this.session = this.authStore.getSession(ssl, this.clientMode); + + if (sessCacheHostname == null && this.peerAddr != null) { + sessCacheHostname = this.peerAddr.getHostAddress(); + } + + this.session = this.authStore.getSession(ssl, this.clientMode, + sessCacheHostname, this.port); } if (this.clientMode) { diff --git a/src/java/com/wolfssl/provider/jsse/WolfSSLImplementSSLSession.java b/src/java/com/wolfssl/provider/jsse/WolfSSLImplementSSLSession.java index 1496bcda..08746ef2 100644 --- a/src/java/com/wolfssl/provider/jsse/WolfSSLImplementSSLSession.java +++ b/src/java/com/wolfssl/provider/jsse/WolfSSLImplementSSLSession.java @@ -147,12 +147,13 @@ public WolfSSLImplementSSLSession (WolfSSLSession in, int port, String host, * * @param in WolfSSLSession to be used with this object * @param params WolfSSLAuthStore for this session + * @param host hostname of peer, or null if not available + * @param port port of peer */ public WolfSSLImplementSSLSession (WolfSSLSession in, - WolfSSLAuthStore params) { + WolfSSLAuthStore params, + String host, int port) { this.ssl = in; - this.port = -1; - this.host = null; this.authStore = params; this.valid = false; /* flag if joining or resuming session is allowed */ this.peerCerts = null; @@ -163,6 +164,18 @@ public WolfSSLImplementSSLSession (WolfSSLSession in, creation = new Date(); accessed = new Date(); + if (host != null) { + this.host = host; + } else { + this.host = null; + } + + if (port > 0) { + this.port = port; + } else { + this.port = -1; + } + WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO, "created new session (no host/port yet)"); } @@ -478,7 +491,9 @@ public synchronized Certificate[] getPeerCertificates() X509Certificate exportCert; if (ssl == null) { - throw new SSLPeerUnverifiedException("handshake not complete"); + throw new SSLPeerUnverifiedException( + "internal WolfSSLSession null, handshake not complete or " + + "SSLSocket/Engine closed"); } try { diff --git a/src/test/com/wolfssl/provider/jsse/test/WolfSSLSessionTest.java b/src/test/com/wolfssl/provider/jsse/test/WolfSSLSessionTest.java index 5d10de34..84ba4b91 100644 --- a/src/test/com/wolfssl/provider/jsse/test/WolfSSLSessionTest.java +++ b/src/test/com/wolfssl/provider/jsse/test/WolfSSLSessionTest.java @@ -24,6 +24,13 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.fail; +import java.util.concurrent.Callable; +import java.util.concurrent.Future; +import java.util.concurrent.Executors; +import java.util.concurrent.ExecutorService; + +import java.io.InputStream; +import java.io.OutputStream; import java.io.IOException; import java.security.cert.Certificate; import java.security.cert.X509Certificate; @@ -38,20 +45,25 @@ import java.security.cert.CertificateException; import java.util.ArrayList; +import java.net.InetSocketAddress; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLEngine; -import javax.net.ssl.SSLException; -import javax.net.ssl.SSLPeerUnverifiedException; +import javax.net.ssl.SSLSocket; +import javax.net.ssl.SSLServerSocket; import javax.net.ssl.SSLSession; import javax.net.ssl.SSLSessionBindingEvent; import javax.net.ssl.SSLSessionBindingListener; import javax.net.ssl.SSLSessionContext; +import javax.net.ssl.SSLException; +import javax.net.ssl.SSLPeerUnverifiedException; +import javax.net.ssl.SSLHandshakeException; import org.junit.BeforeClass; import org.junit.Test; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.fail; +import com.wolfssl.WolfSSL; import com.wolfssl.WolfSSLContext; import com.wolfssl.WolfSSLException; import com.wolfssl.provider.jsse.WolfSSLProvider; @@ -63,7 +75,7 @@ public class WolfSSLSessionTest { @BeforeClass public static void testProviderInstallationAtRuntime() - throws NoSuchProviderException { + throws NoSuchProviderException, WolfSSLException { System.out.println("WolfSSLImplementSSLSession Class"); @@ -73,12 +85,8 @@ public static void testProviderInstallationAtRuntime() Provider p = Security.getProvider("wolfJSSE"); assertNotNull(p); - try { - tf = new WolfSSLTestFactory(); - } catch (WolfSSLException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } + /* Can throw WolfSSLException on error */ + tf = new WolfSSLTestFactory(); } @@ -435,6 +443,162 @@ public void testSessionContext() pass("\t\t... passed"); } + @Test + public void testGetSessionInSocketConnection() throws Exception { + + String protocol = null; + SSLContext ctx = null; + + System.out.print("\tTesting SSLSocket.getSession"); + + 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 */ + ctx = tf.createSSLContext(protocol, engineProvider); + + /* create SSLServerSocket first to get ephemeral port */ + SSLServerSocket ss = (SSLServerSocket)ctx.getServerSocketFactory() + .createServerSocket(0); + + SSLSocket cs = (SSLSocket)ctx.getSocketFactory().createSocket(); + cs.connect(new InetSocketAddress(ss.getLocalPort())); + final SSLSocket server = (SSLSocket)ss.accept(); + server.setNeedClientAuth(true); + + ExecutorService es = Executors.newSingleThreadExecutor(); + Future serverFuture = es.submit(new Callable() { + @Override + public Void call() throws Exception { + try { + testSSLSession(server, false); + server.startHandshake(); + testSSLSession(server, true); + + } catch (SSLException e) { + error("\t... failed"); + fail(); + } + return null; + } + }); + + try { + testSSLSession(cs, false); + cs.startHandshake(); + testSSLSession(cs, true); + + } catch (SSLHandshakeException e) { + error("\t... failed"); + fail(); + } + + es.shutdown(); + serverFuture.get(); + testSSLSession(cs, true); + cs.close(); + testSSLSession(cs, true); + testSSLSession(server, true); + server.close(); + testSSLSession(server, true); + ss.close(); + + pass("\t... passed"); + } + + /** + * Test SSLSocket.getSession() and calling methods on the + * SSLSession retrieved. */ + private void testSSLSession(SSLSocket sock, boolean handshakeDone) + throws Exception { + + int ret; + String val; + Certificate[] certs; + byte[] id; + SSLSession session; + + if (sock == null) { + throw new Exception("SSLSocket was null in testSSLSession"); + } + + session = sock.getSession(); + if (session == null) { + throw new Exception("SSLSocket.getSession() returned null"); + } + + val = session.getCipherSuite(); + if (val == null || val.isEmpty()) { + throw new Exception( + "SSLSession.getCipherSuite() was null or empty"); + } + + val = session.getProtocol(); + if (val == null || val.isEmpty()) { + throw new Exception( + "SSLSession.getProtocol() was null or empty"); + } + + val = session.getPeerHost(); + if (handshakeDone && !sock.isClosed() && + (val == null || val.isEmpty())) { + throw new Exception( + "SSLSession.getPeerHost() was null or empty"); + } + + ret = session.getPeerPort(); + if (ret == 0) { + throw new Exception("SSLSession.getPeerPort() was 0"); + } + + certs = session.getLocalCertificates(); + if (certs == null || certs.length == 0) { + throw new Exception( + "SSLSession.getLocalCertificates() was null or 0 length"); + } + + try { + certs = session.getPeerCertificates(); + if (handshakeDone && (certs == null || certs.length == 0)) { + throw new Exception( + "SSLSession.getPeerCertificates was null or 0 length"); + } + } catch (SSLPeerUnverifiedException e) { + if (handshakeDone && !sock.isClosed()) { + throw new Exception( + "SSLSession.getPeerCertificates threw " + + "SSLPeerUnverifiedException when handshake was done: " + e); + } + } + + id = session.getId(); + if (!sock.isClosed() && (id == null || id.length == 0)) { + throw new Exception("SSLSession.getId() was null or 0 length"); + } + + if (!sock.isClosed() && !session.isValid()) { + throw new Exception("SSLSession.isValid() is false"); + } + + ret = session.getPacketBufferSize(); + if (ret == 0) { + throw new Exception("SSLSession.getPacketBufferSize() is 0"); + } + + ret = session.getApplicationBufferSize(); + if (ret == 0) { + throw new Exception("SSLSession.getApplicationBufferSize() is 0"); + } + } + private void pass(String msg) { WolfSSLTestFactory.pass(msg); diff --git a/src/test/com/wolfssl/test/WolfSSLSessionTest.java b/src/test/com/wolfssl/test/WolfSSLSessionTest.java index 966a4917..2ebaf869 100644 --- a/src/test/com/wolfssl/test/WolfSSLSessionTest.java +++ b/src/test/com/wolfssl/test/WolfSSLSessionTest.java @@ -41,6 +41,8 @@ import java.util.concurrent.Executors; import java.util.concurrent.Future; import java.util.concurrent.Callable; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.CountDownLatch; import com.wolfssl.WolfSSL; import com.wolfssl.WolfSSLDebug; @@ -991,6 +993,11 @@ public void test_WolfSSLSession_connectionWithDebug() throws Exception { final WolfSSLContext srvCtx; WolfSSLContext cliCtx; + /* Latch used to wait for server to finish handshake before + * test shuts down. Otherwise, we will sometimes miss debug + * messages from the server side. */ + final CountDownLatch latch = new CountDownLatch(1); + System.out.print("\tTesting wolfssljni.debug"); /* Save original property value, then enable debug. Make sure @@ -1063,6 +1070,8 @@ public Void call() throws Exception { if (server != null) { server.close(); } + + latch.countDown(); } return null; @@ -1129,6 +1138,10 @@ public Void call() throws Exception { } } finally { + + /* Wait for server to finish processing */ + latch.await(10, TimeUnit.SECONDS); + /* Restore original property value */ if (originalProp == null || originalProp.isEmpty()) { System.setProperty("wolfssljni.debug", "");