From 76ac7784dec985d80b0ca3235e27a9d0ea7934b1 Mon Sep 17 00:00:00 2001 From: Chris Conlon Date: Mon, 22 Apr 2024 17:14:16 -0600 Subject: [PATCH 1/7] JNI: wrap wolfSSL_SessionIsSetup() in WolfSSLSession, needs wolfSSL > 5.7.0 or WOLFSSL_PR7430_PATCH_APPLIED defined --- native/com_wolfssl_WolfSSLSession.c | 28 ++++++++++++++++++++++++ native/com_wolfssl_WolfSSLSession.h | 8 +++++++ src/java/com/wolfssl/WolfSSLSession.java | 25 +++++++++++++++++++++ 3 files changed, 61 insertions(+) diff --git a/native/com_wolfssl_WolfSSLSession.c b/native/com_wolfssl_WolfSSLSession.c index 70028a92..a341bb1f 100644 --- a/native/com_wolfssl_WolfSSLSession.c +++ b/native/com_wolfssl_WolfSSLSession.c @@ -1420,6 +1420,34 @@ JNIEXPORT jlong JNICALL Java_com_wolfssl_WolfSSLSession_get1Session return (jlong)(uintptr_t)dup; } +JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_wolfsslSessionIsSetup + (JNIEnv* jenv, jclass jcl, jlong sessionPtr) +{ +#if (LIBWOLFSSL_VERSION_HEX > 0x05007000) || \ + defined(WOLFSSL_PR7430_PATCH_APPLIED) + int ret; + WOLFSSL_SESSION* session = (WOLFSSL_SESSION*)(uintptr_t)sessionPtr; + (void)jcl; + + if (jenv == NULL) { + return 0; + } + + /* wolfSSL_SessionIsSetup() was added after wolfSSL 5.7.0 in PR + * 7430. Version checked above must be greater than 5.7.0 or patch + * from this PR must be applied and WOLFSSL_PR7430_PATCH_APPLIED defined + * when compiling this JNI wrapper */ + ret = wolfSSL_SessionIsSetup(session); + + return (jint)ret; +#else + (void)jenv; + (void)jcl; + (void)sessionPtr; + return (jint)NOT_COMPILED_IN; +#endif +} + JNIEXPORT void JNICALL Java_com_wolfssl_WolfSSLSession_freeNativeSession (JNIEnv* jenv, jclass jcl, jlong sessionPtr) { diff --git a/native/com_wolfssl_WolfSSLSession.h b/native/com_wolfssl_WolfSSLSession.h index af739d94..52a58f54 100644 --- a/native/com_wolfssl_WolfSSLSession.h +++ b/native/com_wolfssl_WolfSSLSession.h @@ -159,6 +159,14 @@ JNIEXPORT jlong JNICALL Java_com_wolfssl_WolfSSLSession_getSession JNIEXPORT jlong JNICALL Java_com_wolfssl_WolfSSLSession_get1Session (JNIEnv *, jobject, jlong); +/* + * Class: com_wolfssl_WolfSSLSession + * Method: wolfsslSessionIsSetup + * Signature: (J)I + */ +JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_wolfsslSessionIsSetup + (JNIEnv *, jclass, jlong); + /* * Class: com_wolfssl_WolfSSLSession * Method: freeNativeSession diff --git a/src/java/com/wolfssl/WolfSSLSession.java b/src/java/com/wolfssl/WolfSSLSession.java index 3ecc4854..830afcd6 100644 --- a/src/java/com/wolfssl/WolfSSLSession.java +++ b/src/java/com/wolfssl/WolfSSLSession.java @@ -262,6 +262,7 @@ private native int read(long ssl, byte[] data, int offset, int sz, private native int setSession(long ssl, long session); private native long getSession(long ssl); private native long get1Session(long ssl); + private static native int wolfsslSessionIsSetup(long ssl); private static native void freeNativeSession(long session); private native byte[] getSessionID(long session); private native int setServerID(long ssl, byte[] id, int len, int newSess); @@ -1364,6 +1365,30 @@ public long getSession() throws IllegalStateException { } } + /** + * Check if native WOLFSSL_SESSION has been set up or not. + * + * This method is static and does not check active state since this + * takes a native pointer and has no interaction with the rest of this + * object. + * + * @param session pointer to native WOLFSSL_SESSION structure. May be + * obtained from getSession(). + * + * @return 1 if session has been set up, otherwise 0 if not set up. May + * return WolfSSL.NOT_COMPILED_IN if native wolfSSL does not have + * wolfSSL_SessionIsSetup() compiled in. This API was added + * after the wolfSSL 5.7.0 release. + */ + public static int sessionIsSetup(long session) { + + if (session == 0) { + return 0; + } + + return wolfsslSessionIsSetup(session); + } + /** * Free the native WOLFSSL_SESSION structure pointed to be session. * From 3c94939d3ddb627167825a551fe516360e324bb3 Mon Sep 17 00:00:00 2001 From: Chris Conlon Date: Wed, 24 Apr 2024 12:18:46 -0600 Subject: [PATCH 2/7] JNI: refactor WolfSSLSessionTest to use individual Junit Test annotation on methods, better cleanup --- .../com/wolfssl/test/WolfSSLSessionTest.java | 510 ++++++++++++------ 1 file changed, 346 insertions(+), 164 deletions(-) diff --git a/src/test/com/wolfssl/test/WolfSSLSessionTest.java b/src/test/com/wolfssl/test/WolfSSLSessionTest.java index bd798188..09dc6f09 100644 --- a/src/test/com/wolfssl/test/WolfSSLSessionTest.java +++ b/src/test/com/wolfssl/test/WolfSSLSessionTest.java @@ -44,78 +44,72 @@ public class WolfSSLSessionTest { - public final static int TEST_FAIL = -1; - public final static int TEST_SUCCESS = 0; + private final static int TEST_FAIL = -1; + private final static int TEST_SUCCESS = 0; - public static String cliCert = "./examples/certs/client-cert.pem"; - public static String cliKey = "./examples/certs/client-key.pem"; - public static String caCert = "./examples/certs/ca-cert.pem"; - public static String bogusFile = "/dev/null"; + private static String cliCert = "./examples/certs/client-cert.pem"; + private static String cliKey = "./examples/certs/client-key.pem"; + private static String caCert = "./examples/certs/ca-cert.pem"; + private static String bogusFile = "/dev/null"; - public final static String exampleHost = "www.example.com"; - public final static int examplePort = 443; + private final static String exampleHost = "www.example.com"; + private final static int examplePort = 443; - WolfSSLContext ctx; - WolfSSLSession ssl; + private static WolfSSLContext ctx = null; @BeforeClass - public static void loadLibrary() { + public static void loadLibrary() + throws WolfSSLException{ + + System.out.println("WolfSSLSession Class"); + try { WolfSSL.loadLibrary(); } catch (UnsatisfiedLinkError ule) { fail("failed to load native JNI library"); } - } - - @Test - public void testWolfSSLSession() throws WolfSSLException { + /* Create one WolfSSLContext */ ctx = new WolfSSLContext(WolfSSL.SSLv23_ClientMethod()); - System.out.println("WolfSSLSession Class"); - + /* Set cert/key paths */ cliCert = WolfSSLTestCommon.getPath(cliCert); cliKey = WolfSSLTestCommon.getPath(cliKey); caCert = WolfSSLTestCommon.getPath(caCert); - - test_WolfSSLSession_new(); - test_WolfSSLSession_useCertificateFile(); - test_WolfSSLSession_usePrivateKeyFile(); - test_WolfSSLSession_useCertificateChainFile(); - test_WolfSSLSession_setPskClientCb(); - test_WolfSSLSession_setPskServerCb(); - test_WolfSSLSession_usePskIdentityHint(); - test_WolfSSLSession_getPskIdentityHint(); - test_WolfSSLSession_getPskIdentity(); - test_WolfSSLSession_useSessionTicket(); - test_WolfSSLSession_timeout(); - test_WolfSSLSession_status(); - test_WolfSSLSession_useSNI(); - test_WolfSSLSession_useALPN(); - test_WolfSSLSession_freeSSL(); - test_WolfSSLSession_UseAfterFree(); - test_WolfSSLSession_getSessionID(); - test_WolfSSLSession_useSecureRenegotiation(); - test_WolfSSLSession_setTls13SecretCb(); } - public void test_WolfSSLSession_new() { + @Test + public void test_WolfSSLSession_new() + throws WolfSSLJNIException { + + WolfSSLSession sess = null; + + System.out.print("\tWolfSSLSession()"); try { - System.out.print("\tWolfSSLSession()"); - ssl = new WolfSSLSession(ctx); + sess = new WolfSSLSession(ctx); + } catch (WolfSSLException we) { System.out.println("\t... failed"); fail("failed to create WolfSSLSession object"); + + } finally { + if (sess != null) { + sess.freeSSL(); + } } System.out.println("\t\t... passed"); } - public void test_WolfSSLSession_useCertificateFile() { + @Test + public void test_WolfSSLSession_useCertificateFile() + throws WolfSSLJNIException, WolfSSLException { System.out.print("\tuseCertificateFile()"); + WolfSSLSession ssl = new WolfSSLSession(ctx); + test_ucf("useCertificateFile", null, null, 9999, WolfSSL.SSL_FAILURE, "useCertificateFile(null, null, 9999)"); @@ -132,13 +126,21 @@ public void test_WolfSSLSession_useCertificateFile() { WolfSSL.SSL_SUCCESS, "useCertificateFile(ssl, cliCert, SSL_FILETYPE_PEM)"); + if (ssl != null) { + ssl.freeSSL(); + } + System.out.println("\t\t... passed"); } - public void test_WolfSSLSession_useCertificateChainFile() { + @Test + public void test_WolfSSLSession_useCertificateChainFile() + throws WolfSSLJNIException, WolfSSLException { System.out.print("\tuseCertificateChainFile()"); + WolfSSLSession ssl = new WolfSSLSession(ctx); + test_ucf("useCertificateChainFile", null, null, 0, WolfSSL.SSL_FAILURE, "useCertificateChainFile(null, null)"); @@ -151,12 +153,16 @@ public void test_WolfSSLSession_useCertificateChainFile() { WolfSSL.SSL_SUCCESS, "useCertificateChainFile(ssl, cliCert)"); + if (ssl != null) { + ssl.freeSSL(); + } + System.out.println("\t... passed"); } /* helper for testing WolfSSLSession.useCertificateFile() */ - public void test_ucf(String func, WolfSSLSession ssl, String filePath, - int type, int cond, String name) { + private void test_ucf(String func, WolfSSLSession ssl, String filePath, + int type, int cond, String name) { int result = WolfSSL.SSL_FAILURE; @@ -191,10 +197,14 @@ public void test_ucf(String func, WolfSSLSession ssl, String filePath, return; } - public void test_WolfSSLSession_usePrivateKeyFile() { + @Test + public void test_WolfSSLSession_usePrivateKeyFile() + throws WolfSSLJNIException, WolfSSLException { System.out.print("\tusePrivateKeyFile()"); + WolfSSLSession ssl = new WolfSSLSession(ctx); + test_upkf(null, null, 9999, WolfSSL.SSL_FAILURE, "usePrivateKeyFile(null, null, 9999)"); @@ -208,12 +218,16 @@ public void test_WolfSSLSession_usePrivateKeyFile() { test_upkf(ssl, cliKey, WolfSSL.SSL_FILETYPE_PEM, WolfSSL.SSL_SUCCESS, "usePrivateKeyFile(ssl, cliKey, SSL_FILETYPE_PEM)"); + if (ssl != null) { + ssl.freeSSL(); + } + System.out.println("\t\t... passed"); } /* helper for testing WolfSSLSession.usePrivateKeyFile() */ - public void test_upkf(WolfSSLSession ssl, String filePath, int type, - int cond, String name) { + private void test_upkf(WolfSSLSession ssl, String filePath, int type, + int cond, String name) { int result; @@ -259,19 +273,38 @@ public long pskClientCallback(WolfSSLSession ssl, String hint, } } - public void test_WolfSSLSession_setPskClientCb() { + @Test + public void test_WolfSSLSession_setPskClientCb() + throws WolfSSLJNIException { + + WolfSSLSession ssl = null; + System.out.print("\tsetPskClientCb()"); + try { TestPskClientCb pskClientCb = new TestPskClientCb(); + ssl = new WolfSSLSession(ctx); ssl.setPskClientCb(pskClientCb); + } catch (Exception e) { - if (!e.getMessage().equals("wolfSSL not compiled with PSK " + - "support")) { + if (e.getMessage().equals("wolfSSL not compiled with PSK " + + "support")) { + /* Not compiled in, skip */ + System.out.println("\t\t... skipped"); + return; + } + else { System.out.println("\t\t... failed"); fail("Failed setPskClientCb test"); e.printStackTrace(); } + + } finally { + if (ssl != null) { + ssl.freeSSL(); + } } + System.out.println("\t\t... passed"); } @@ -295,122 +328,227 @@ public long pskServerCallback(WolfSSLSession ssl, String identity, } } - public void test_WolfSSLSession_setPskServerCb() { + @Test + public void test_WolfSSLSession_setPskServerCb() + throws WolfSSLJNIException { + + WolfSSLSession ssl = null; + System.out.print("\tsetPskServerCb()"); + try { TestPskServerCb pskServerCb = new TestPskServerCb(); + ssl = new WolfSSLSession(ctx); ssl.setPskServerCb(pskServerCb); + } catch (Exception e) { - if (!e.getMessage().equals("wolfSSL not compiled with PSK " + - "support")) { + if (e.getMessage().equals("wolfSSL not compiled with PSK " + + "support")) { + /* Not compiled in, skip */ + System.out.println("\t\t... skipped"); + return; + } + else { System.out.println("\t\t... failed"); fail("Failed setPskServerCb test"); e.printStackTrace(); } + + } finally { + if (ssl != null) { + ssl.freeSSL(); + } } + System.out.println("\t\t... passed"); } - public void test_WolfSSLSession_usePskIdentityHint() { - System.out.print("\tusePskIdentityHint()"); + @Test + public void test_WolfSSLSession_useGetPskIdentityHint() + throws WolfSSLJNIException, WolfSSLException { + + int ret = 0; + String hint = null; + WolfSSLSession ssl = null; + + System.out.print("\tuse/getPskIdentityHint()"); + + ssl = new WolfSSLSession(ctx); + try { - int ret = ssl.usePskIdentityHint("wolfssl hint"); + /* Set PSK identity hint */ + ret = ssl.usePskIdentityHint("wolfssl hint"); if (ret != WolfSSL.SSL_SUCCESS && ret != WolfSSL.NOT_COMPILED_IN) { - System.out.println("\t\t... failed"); + System.out.println("\t... failed"); fail("usePskIdentityHint failed"); } - } catch (IllegalStateException e) { - System.out.println("\t\t... failed"); - fail("Failed usePskIdentityHint test"); - e.printStackTrace(); - } - System.out.println("\t\t... passed"); - } - public void test_WolfSSLSession_getPskIdentityHint() { - System.out.print("\tgetPskIdentityHint()"); - try { - String hint = ssl.getPskIdentityHint(); + /* Get PSK identity hint */ + hint = ssl.getPskIdentityHint(); if (hint != null && !hint.equals("wolfssl hint")) { - System.out.println("\t\t... failed"); + System.out.println("\t... failed"); fail("getPskIdentityHint failed"); } + } catch (IllegalStateException e) { - System.out.println("\t\t... failed"); - fail("Failed getPskIdentityHint test"); + System.out.println("\t... failed"); e.printStackTrace(); + fail("Failed use/getPskIdentityHint test"); + + } finally { + if (ssl != null) { + ssl.freeSSL(); + } } - System.out.println("\t\t... passed"); + + System.out.println("\t... passed"); } - public void test_WolfSSLSession_useSessionTicket() { + @Test + public void test_WolfSSLSession_useSessionTicket() + throws WolfSSLJNIException, WolfSSLException { + + int ret = 0; + WolfSSLSession ssl = null; + System.out.print("\tuseSessionTicket()"); + try { - int ret = ssl.useSessionTicket(); + ssl = new WolfSSLSession(ctx); + + ret = ssl.useSessionTicket(); if (ret != WolfSSL.SSL_SUCCESS && ret != WolfSSL.NOT_COMPILED_IN) { System.out.println("\t\t... failed"); fail("useSessionTicket failed"); } + } catch (IllegalStateException e) { System.out.println("\t\t... failed"); e.printStackTrace(); + + } finally { + if (ssl != null) { + ssl.freeSSL(); + } } + System.out.println("\t\t... passed"); } - public void test_WolfSSLSession_getPskIdentity() { + @Test + public void test_WolfSSLSession_getPskIdentity() + throws WolfSSLJNIException, WolfSSLException { + + String identity = null; + WolfSSLSession ssl = null; + System.out.print("\tgetPskIdentity()"); + try { - String identity = ssl.getPskIdentity(); + ssl = new WolfSSLSession(ctx); + identity = ssl.getPskIdentity(); + } catch (IllegalStateException e) { System.out.println("\t\t... failed"); fail("Failed getPskIdentity test"); e.printStackTrace(); + + } finally { + if (ssl != null) { + ssl.freeSSL(); + } } + System.out.println("\t\t... passed"); } - public void test_WolfSSLSession_timeout() { + @Test + public void test_WolfSSLSession_timeout() + throws WolfSSLJNIException, WolfSSLException { + + WolfSSLSession ssl = null; System.out.print("\ttimeout()"); - ssl.setTimeout(5); - if (ssl.getTimeout() != 5) { - System.out.println("\t\t\t... failed"); - fail("Failed timeout test"); + + ssl = new WolfSSLSession(ctx); + + try { + ssl.setTimeout(5); + if (ssl.getTimeout() != 5) { + System.out.println("\t\t\t... failed"); + fail("Failed timeout test"); + } + + } finally { + if (ssl != null) { + ssl.freeSSL(); + } } + System.out.println("\t\t\t... passed"); } - public void test_WolfSSLSession_status() { + @Test + public void test_WolfSSLSession_status() + throws WolfSSLJNIException, WolfSSLException { + + WolfSSLSession ssl = null; System.out.print("\tstatus()"); - if (ssl.handshakeDone() == true) { - System.out.println("\t\t\t... failed"); - fail("Failed status test"); + + ssl = new WolfSSLSession(ctx); + + try { + if (ssl.handshakeDone() == true) { + System.out.println("\t\t\t... failed"); + fail("Failed status test"); + } + + } finally { + if (ssl != null) { + ssl.freeSSL(); + } } + System.out.println("\t\t\t... passed"); } - public void test_WolfSSLSession_useSNI() { + @Test + public void test_WolfSSLSession_useSNI() + throws WolfSSLJNIException, WolfSSLException { int ret; String sniHostName = "www.example.com"; + WolfSSLSession ssl = null; System.out.print("\tuseSNI()"); - ret = ssl.useSNI((byte)0, sniHostName.getBytes()); - if (ret == WolfSSL.NOT_COMPILED_IN) { - System.out.println("\t\t\t... skipped"); - } else if (ret != WolfSSL.SSL_SUCCESS) { - System.out.println("\t\t\t... failed"); - fail("Failed useSNI test"); - } else { - System.out.println("\t\t\t... passed"); + + ssl = new WolfSSLSession(ctx); + + try { + ret = ssl.useSNI((byte)0, sniHostName.getBytes()); + if (ret == WolfSSL.NOT_COMPILED_IN) { + System.out.println("\t\t\t... skipped"); + return; + } else if (ret != WolfSSL.SSL_SUCCESS) { + System.out.println("\t\t\t... failed"); + fail("Failed useSNI test"); + } + + } finally { + if (ssl != null) { + ssl.freeSSL(); + } } + + System.out.println("\t\t\t... passed"); } - public void test_WolfSSLSession_useALPN() { + @Test + public void test_WolfSSLSession_useALPN() + throws WolfSSLException, WolfSSLJNIException { int ret; String[] alpnProtos = new String[] { @@ -419,85 +557,109 @@ public void test_WolfSSLSession_useALPN() { String http11Alpn = "http/1.1"; byte[] alpnProtoBytes = http11Alpn.getBytes(); byte[] alpnProtoBytesPacked = new byte[1 + alpnProtoBytes.length]; + WolfSSLSession ssl = null; System.out.print("\tuseALPN()"); - /* Testing useALPN(String[], int) */ - ret = ssl.useALPN(alpnProtos, - WolfSSL.WOLFSSL_ALPN_CONTINUE_ON_MISMATCH); + ssl = new WolfSSLSession(ctx); - if (ret == WolfSSL.SSL_SUCCESS) { + try { + /* Testing useALPN(String[], int) */ ret = ssl.useALPN(alpnProtos, - WolfSSL.WOLFSSL_ALPN_FAILED_ON_MISMATCH); - } + WolfSSL.WOLFSSL_ALPN_CONTINUE_ON_MISMATCH); - if (ret == WolfSSL.SSL_SUCCESS) { - ret = ssl.useALPN(null, WolfSSL.WOLFSSL_ALPN_CONTINUE_ON_MISMATCH); - if (ret < 0) { - /* error expected, null input */ - ret = WolfSSL.SSL_SUCCESS; + if (ret == WolfSSL.SSL_SUCCESS) { + ret = ssl.useALPN(alpnProtos, + WolfSSL.WOLFSSL_ALPN_FAILED_ON_MISMATCH); } - } - if (ret == WolfSSL.SSL_SUCCESS) { - ret = ssl.useALPN(alpnProtos, 0); - if (ret < 0) { - /* error expected, no options */ - ret = WolfSSL.SSL_SUCCESS; + if (ret == WolfSSL.SSL_SUCCESS) { + ret = ssl.useALPN(null, + WolfSSL.WOLFSSL_ALPN_CONTINUE_ON_MISMATCH); + if (ret < 0) { + /* error expected, null input */ + ret = WolfSSL.SSL_SUCCESS; + } } - } - if (ret == WolfSSL.SSL_SUCCESS) { - ret = ssl.useALPN(alpnProtos, -123); - if (ret < 0) { - /* error expected, invalid options */ - ret = WolfSSL.SSL_SUCCESS; + if (ret == WolfSSL.SSL_SUCCESS) { + ret = ssl.useALPN(alpnProtos, 0); + if (ret < 0) { + /* error expected, no options */ + ret = WolfSSL.SSL_SUCCESS; + } } - } - /* Testing useALPN(byte[]) */ - if (ret == WolfSSL.SSL_SUCCESS) { + if (ret == WolfSSL.SSL_SUCCESS) { + ret = ssl.useALPN(alpnProtos, -123); + if (ret < 0) { + /* error expected, invalid options */ + ret = WolfSSL.SSL_SUCCESS; + } + } - alpnProtoBytesPacked[0] = (byte)http11Alpn.length(); - System.arraycopy(alpnProtoBytes, 0, alpnProtoBytesPacked, 1, - alpnProtoBytes.length); + /* Testing useALPN(byte[]) */ + if (ret == WolfSSL.SSL_SUCCESS) { - ret = ssl.useALPN(alpnProtoBytesPacked); - } + alpnProtoBytesPacked[0] = (byte)http11Alpn.length(); + System.arraycopy(alpnProtoBytes, 0, alpnProtoBytesPacked, 1, + alpnProtoBytes.length); - if (ret == WolfSSL.SSL_SUCCESS) { - ret = ssl.useALPN(null); - if (ret < 0) { - /* error expected, null input */ - ret = WolfSSL.SSL_SUCCESS; + ret = ssl.useALPN(alpnProtoBytesPacked); } - } - if (ret == WolfSSL.NOT_COMPILED_IN) { - System.out.println("\t\t\t... skipped"); - } else if (ret != WolfSSL.SSL_SUCCESS) { - System.out.println("\t\t\t... failed"); - fail("Failed useALPN test"); - } else { - System.out.println("\t\t\t... passed"); + if (ret == WolfSSL.SSL_SUCCESS) { + ret = ssl.useALPN(null); + if (ret < 0) { + /* error expected, null input */ + ret = WolfSSL.SSL_SUCCESS; + } + } + + if (ret == WolfSSL.NOT_COMPILED_IN) { + System.out.println("\t\t\t... skipped"); + return; + + } else if (ret != WolfSSL.SSL_SUCCESS) { + System.out.println("\t\t\t... failed"); + fail("Failed useALPN test"); + } + + } finally { + if (ssl != null) { + ssl.freeSSL(); + } } + + System.out.println("\t\t\t... passed"); } - public void test_WolfSSLSession_freeSSL() { + @Test + public void test_WolfSSLSession_freeSSL() + throws WolfSSLJNIException, WolfSSLException { + + WolfSSLSession ssl = null; System.out.print("\tfreeSSL()"); + ssl = new WolfSSLSession(ctx); + try { ssl.freeSSL(); + } catch (WolfSSLJNIException e) { System.out.println("\t\t\t... failed"); fail("Failed freeSSL test"); e.printStackTrace(); + } + System.out.println("\t\t\t... passed"); } - public void test_WolfSSLSession_UseAfterFree() { + @Test + public void test_WolfSSLSession_UseAfterFree() + throws WolfSSLJNIException { int ret, err; WolfSSL sslLib = null; @@ -532,14 +694,9 @@ public void test_WolfSSLSession_UseAfterFree() { err == WolfSSL.SSL_ERROR_WANT_WRITE)); if (ret != WolfSSL.SSL_SUCCESS) { - ssl.freeSSL(); - sslCtx.free(); fail("Failed WolfSSL.connect() to " + exampleHost); } - ssl.freeSSL(); - sslCtx.free(); - } catch (UnknownHostException | ConnectException e) { /* skip if no Internet connection */ System.out.println("\t\t... skipped"); @@ -550,14 +707,24 @@ public void test_WolfSSLSession_UseAfterFree() { fail("Failed UseAfterFree test"); e.printStackTrace(); return; + + } finally { + if (ssl != null) { + ssl.freeSSL(); + } + if (sslCtx != null) { + sslCtx.free(); + } } try { /* this should fail, use after free */ ret = ssl.connect(); + } catch (IllegalStateException ise) { System.out.println("\t\t... passed"); return; + } catch (SocketTimeoutException | SocketException e) { System.out.println("\t\t... failed"); fail("Failed UseAfterFree test"); @@ -571,7 +738,9 @@ public void test_WolfSSLSession_UseAfterFree() { fail("WolfSSLSession was able to be used after freed"); } - public void test_WolfSSLSession_getSessionID() { + @Test + public void test_WolfSSLSession_getSessionID() + throws WolfSSLJNIException { int ret, err; WolfSSL sslLib = null; @@ -593,16 +762,12 @@ public void test_WolfSSLSession_getSessionID() { sessionID = ssl.getSessionID(); if (sessionID == null || sessionID.length != 0) { /* sessionID array should not be null, but should be empty */ - ssl.freeSSL(); - sslCtx.free(); fail("Session ID should be empty array before connection"); } sock = new Socket(exampleHost, examplePort); ret = ssl.setFd(sock); if (ret != WolfSSL.SSL_SUCCESS) { - ssl.freeSSL(); - sslCtx.free(); fail("Failed to set file descriptor"); } @@ -615,21 +780,15 @@ public void test_WolfSSLSession_getSessionID() { err == WolfSSL.SSL_ERROR_WANT_WRITE)); if (ret != WolfSSL.SSL_SUCCESS) { - ssl.freeSSL(); - sslCtx.free(); fail("Failed WolfSSL.connect() to " + exampleHost); } sessionID = ssl.getSessionID(); if (sessionID == null || sessionID.length == 0) { /* session ID should not be null or zero length */ - ssl.freeSSL(); - sslCtx.free(); fail("Session ID should not be null or 0 length " + "after connection"); } - ssl.freeSSL(); - sslCtx.free(); } catch (UnknownHostException | ConnectException e) { /* skip if no Internet connection */ @@ -641,12 +800,22 @@ public void test_WolfSSLSession_getSessionID() { fail("Failed getSessionID test"); e.printStackTrace(); return; + + } finally { + if (ssl != null) { + ssl.freeSSL(); + } + if (sslCtx != null) { + sslCtx.free(); + } } System.out.println("\t\t... passed"); } - public void test_WolfSSLSession_useSecureRenegotiation() { + @Test + public void test_WolfSSLSession_useSecureRenegotiation() + throws WolfSSLJNIException { int ret, err; WolfSSL sslLib = null; @@ -670,19 +839,22 @@ public void test_WolfSSLSession_useSecureRenegotiation() { if (ret != WolfSSL.SSL_SUCCESS && ret != WolfSSL.NOT_COMPILED_IN) { System.out.println("... failed"); fail("Failed useSecureRenegotiation test"); - ssl.freeSSL(); - sslCtx.free(); return; } - ssl.freeSSL(); - sslCtx.free(); - } catch (Exception e) { System.out.println("... failed"); fail("Failed useSecureRenegotiation test"); e.printStackTrace(); return; + + } finally { + if (ssl != null) { + ssl.freeSSL(); + } + if (sslCtx != null) { + sslCtx.free(); + } } System.out.println("... passed"); @@ -697,7 +869,9 @@ public int tls13SecretCallback(WolfSSLSession ssl, int id, } } - public void test_WolfSSLSession_setTls13SecretCb() { + @Test + public void test_WolfSSLSession_setTls13SecretCb() + throws WolfSSLJNIException { int ret; WolfSSL sslLib = null; @@ -732,6 +906,14 @@ public void test_WolfSSLSession_setTls13SecretCb() { e.printStackTrace(); fail("failed setTls13SecretCb() test"); return; + + } finally { + if (ssl != null) { + ssl.freeSSL(); + } + if (sslCtx != null) { + sslCtx.free(); + } } System.out.println("\t... passed"); From 062dcc2d05c222630f03ceed0d1527fdd32e0ad9 Mon Sep 17 00:00:00 2001 From: Chris Conlon Date: Wed, 24 Apr 2024 15:04:58 -0600 Subject: [PATCH 3/7] JNI: add test method for WolfSSLSession.get/set/freeSession() --- .../com/wolfssl/test/WolfSSLSessionTest.java | 282 +++++++++++++++++- 1 file changed, 280 insertions(+), 2 deletions(-) diff --git a/src/test/com/wolfssl/test/WolfSSLSessionTest.java b/src/test/com/wolfssl/test/WolfSSLSessionTest.java index 09dc6f09..f47e677a 100644 --- a/src/test/com/wolfssl/test/WolfSSLSessionTest.java +++ b/src/test/com/wolfssl/test/WolfSSLSessionTest.java @@ -27,11 +27,18 @@ import org.junit.runners.JUnit4; import static org.junit.Assert.*; +import java.io.IOException; import java.net.Socket; +import java.net.ServerSocket; +import java.net.InetAddress; import java.net.UnknownHostException; import java.net.ConnectException; import java.net.SocketException; import java.net.SocketTimeoutException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.concurrent.Callable; import com.wolfssl.WolfSSL; import com.wolfssl.WolfSSLContext; @@ -49,6 +56,8 @@ public class WolfSSLSessionTest { private static String cliCert = "./examples/certs/client-cert.pem"; private static String cliKey = "./examples/certs/client-key.pem"; + private static String srvCert = "./examples/certs/server-cert.pem"; + private static String srvKey = "./examples/certs/server-key.pem"; private static String caCert = "./examples/certs/ca-cert.pem"; private static String bogusFile = "/dev/null"; @@ -74,8 +83,10 @@ public static void loadLibrary() /* Set cert/key paths */ cliCert = WolfSSLTestCommon.getPath(cliCert); - cliKey = WolfSSLTestCommon.getPath(cliKey); - caCert = WolfSSLTestCommon.getPath(caCert); + cliKey = WolfSSLTestCommon.getPath(cliKey); + srvCert = WolfSSLTestCommon.getPath(srvCert); + srvKey = WolfSSLTestCommon.getPath(srvKey); + caCert = WolfSSLTestCommon.getPath(caCert); } @Test @@ -918,5 +929,272 @@ public void test_WolfSSLSession_setTls13SecretCb() System.out.println("\t... passed"); } + + @Test + public void test_WolfSSLSession_getSetSession() + throws WolfSSLJNIException, WolfSSLException, + IOException { + + int ret = 0; + int err = 0; + long sessionPtr = 0; + Socket cliSock = null; + WolfSSLSession cliSes = null; + + System.out.print("\tTesting get/setSession()"); + + /* Create ServerSocket first to get ephemeral port */ + final ServerSocket srvSocket = new ServerSocket(0); + + /* Create client/server WolfSSLContext objects, Server context + * must be final since used inside inner class. */ + final WolfSSLContext srvCtx = + new WolfSSLContext(WolfSSL.SSLv23_ServerMethod()); + WolfSSLContext cliCtx = + new WolfSSLContext(WolfSSL.SSLv23_ClientMethod()); + + /* Load certificate/key files */ + ret = srvCtx.useCertificateChainFile(srvCert); + if (ret != WolfSSL.SSL_SUCCESS) { + srvCtx.free(); + cliCtx.free(); + System.out.println("\t... failed"); + fail("Failed to load server certificate!"); + } + + ret = srvCtx.usePrivateKeyFile(srvKey, + WolfSSL.SSL_FILETYPE_PEM); + if (ret != WolfSSL.SSL_SUCCESS) { + srvCtx.free(); + cliCtx.free(); + System.out.println("\t... failed"); + fail("Failed to load server private key!"); + } + + ret = cliCtx.useCertificateFile(cliCert, + WolfSSL.SSL_FILETYPE_PEM); + if (ret != WolfSSL.SSL_SUCCESS) { + srvCtx.free(); + cliCtx.free(); + System.out.println("\t... failed"); + fail("Failed to load client certificate!"); + } + + ret = cliCtx.usePrivateKeyFile(cliKey, + WolfSSL.SSL_FILETYPE_PEM); + if (ret != WolfSSL.SSL_SUCCESS) { + srvCtx.free(); + cliCtx.free(); + System.out.println("\t... failed"); + fail("Failed to load client private key!"); + } + + /* Load CA certs */ + ret = srvCtx.loadVerifyLocations(cliCert, null); + if (ret != WolfSSL.SSL_SUCCESS) { + srvCtx.free(); + cliCtx.free(); + System.out.println("\t... failed"); + fail("Failed to load CA certificates!"); + } + + ret = cliCtx.loadVerifyLocations(caCert, null); + if (ret != WolfSSL.SSL_SUCCESS) { + srvCtx.free(); + cliCtx.free(); + System.out.println("\t... failed"); + fail("Failed to load CA certificates!"); + } + + /* Start server, handles 1 resumption */ + try { + ExecutorService es = Executors.newSingleThreadExecutor(); + Future serverFuture = es.submit(new Callable() { + @Override + public Void call() throws Exception { + int ret; + int err; + Socket server = null; + WolfSSLSession srvSes = null; + + try { + /* Loop twice to allow handle one resumption */ + for (int i = 0; i < 2; i++) { + server = srvSocket.accept(); + srvSes = new WolfSSLSession(srvCtx); + + ret = srvSes.setFd(server); + if (ret != WolfSSL.SSL_SUCCESS) { + throw new Exception( + "WolfSSLSession.setFd() failed: " + ret); + } + + do { + ret = srvSes.accept(); + err = srvSes.getError(ret); + } while (ret != WolfSSL.SSL_SUCCESS && + (err == WolfSSL.SSL_ERROR_WANT_READ || + err == WolfSSL.SSL_ERROR_WANT_WRITE)); + + if (ret != WolfSSL.SSL_SUCCESS) { + throw new Exception( + "WolfSSLSession.accept() failed: " + ret); + } + + srvSes.shutdownSSL(); + srvSes.freeSSL(); + srvSes = null; + } + + } finally { + if (srvSes != null) { + srvSes.freeSSL(); + } + if (server != null) { + server.close(); + } + } + + return null; + } + }); + + } catch (Exception e) { + System.out.println("\t... failed"); + e.printStackTrace(); + fail(); + } + + try { + /* -------------------------------------------------------------- */ + /* Client connection #1 */ + /* -------------------------------------------------------------- */ + cliSock = new Socket(InetAddress.getLocalHost(), + srvSocket.getLocalPort()); + + cliSes = new WolfSSLSession(cliCtx); + + ret = cliSes.setFd(cliSock); + if (ret != WolfSSL.SSL_SUCCESS) { + throw new Exception( + "WolfSSLSession.setFd() failed, ret = " + ret); + } + + do { + ret = cliSes.connect(); + err = cliSes.getError(ret); + } while (ret != WolfSSL.SSL_SUCCESS && + (err == WolfSSL.SSL_ERROR_WANT_READ || + err == WolfSSL.SSL_ERROR_WANT_WRITE)); + + if (ret != WolfSSL.SSL_SUCCESS) { + throw new Exception( + "WolfSSLSession.connect() failed: " + err); + } + + /* Get WOLFSSL_SESSION pointer */ + sessionPtr = cliSes.getSession(); + if (sessionPtr == 0) { + throw new Exception( + "WolfSSLSession.getSession() failed, ptr == 0"); + } + + /* wolfSSL_SessionIsSetup() may not be available, don't treat + * NOT_COMPILED_IN as an error */ + ret = cliSes.sessionIsSetup(sessionPtr); + if ((ret != 1) && (ret != WolfSSL.NOT_COMPILED_IN)) { + throw new Exception( + "WolfSSLSession.sessionIsSetup() did not return 1: " + ret); + } + + cliSes.shutdownSSL(); + cliSes.freeSSL(); + cliSes = null; + cliSock.close(); + cliSock = null; + + /* -------------------------------------------------------------- */ + /* Client connection #2, set session and try resumption */ + /* -------------------------------------------------------------- */ + cliSock = new Socket(InetAddress.getLocalHost(), + srvSocket.getLocalPort()); + cliSes = new WolfSSLSession(cliCtx); + + ret = cliSes.setFd(cliSock); + if (ret != WolfSSL.SSL_SUCCESS) { + throw new Exception( + "WolfSSLSession.setFd() failed, ret = " + ret); + } + + /* Set session pointer from original connection */ + ret = cliSes.setSession(sessionPtr); + if (ret != WolfSSL.SSL_SUCCESS) { + throw new Exception( + "WolfSSLSession.setSession() failed: " + ret); + } + + do { + ret = cliSes.connect(); + err = cliSes.getError(ret); + } while (ret != WolfSSL.SSL_SUCCESS && + (err == WolfSSL.SSL_ERROR_WANT_READ || + err == WolfSSL.SSL_ERROR_WANT_WRITE)); + + if (ret != WolfSSL.SSL_SUCCESS) { + throw new Exception( + "WolfSSLSession.connect() failed: " + err); + } + + /* Get WOLFSSL_SESSION pointer, free original one first */ + cliSes.freeSession(sessionPtr); + sessionPtr = cliSes.getSession(); + if (sessionPtr == 0) { + throw new Exception( + "WolfSSLSession.getSession() failed, ptr == 0"); + } + + /* Free WOLFSSL_SESSION pointer */ + cliSes.freeSession(sessionPtr); + sessionPtr = 0; + + /* Session should be marked as resumed */ + if (cliSes.sessionReused() == 0) { + throw new Exception( + "Second connection not resumed"); + } + + cliSes.shutdownSSL(); + cliSes.freeSSL(); + cliSes = null; + cliSock.close(); + cliSock = null; + + } catch (Exception e) { + System.out.println("\t... failed"); + e.printStackTrace(); + fail(); + + } finally { + if (sessionPtr != 0) { + cliSes.freeSession(sessionPtr); + } + if (cliSes != null) { + cliSes.freeSSL(); + } + if (cliSock != null) { + cliSock.close(); + } + } + + /* Free resources */ + if (srvSocket != null) { + srvSocket.close(); + } + if (srvCtx != null) { + srvCtx.free(); + } + + System.out.println("\t... passed"); + } } From 7e1c0397fb7fdff9c944c862390fdc8d1bc9db4d Mon Sep 17 00:00:00 2001 From: Chris Conlon Date: Thu, 25 Apr 2024 09:51:10 -0600 Subject: [PATCH 4/7] JNI: check if session has ticket for TLS 1.3 before calling wolfSSL_peek() in WolfSSLSession.getSession() --- native/com_wolfssl_WolfSSLSession.c | 31 ++++++++++++++++++++++------- 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/native/com_wolfssl_WolfSSLSession.c b/native/com_wolfssl_WolfSSLSession.c index a341bb1f..976591ab 100644 --- a/native/com_wolfssl_WolfSSLSession.c +++ b/native/com_wolfssl_WolfSSLSession.c @@ -1331,20 +1331,28 @@ JNIEXPORT jlong JNICALL Java_com_wolfssl_WolfSSLSession_getSession JNIEXPORT jlong JNICALL Java_com_wolfssl_WolfSSLSession_get1Session (JNIEnv* jenv, jobject jcl, jlong sslPtr) { + int ret = 0; + int err = 0; + int sockfd = 0; + int version = 0; + int hasTicket = 0; WOLFSSL* ssl = (WOLFSSL*)(uintptr_t)sslPtr; WOLFSSL_SESSION* sess = NULL; WOLFSSL_SESSION* dup = NULL; wolfSSL_Mutex* jniSessLock = NULL; SSLAppData* appData = NULL; + /* tmpBuf is only 1 byte since wolfSSL_peek() doesn't need to read * any app data, only session ticket internally */ char tmpBuf[1]; - int ret = 0; - int err = 0; - int sockfd = 0; + (void)jenv; (void)jcl; + if (ssl == NULL) { + return (jlong)0; + } + /* get session mutex from SSL app data */ appData = (SSLAppData*)wolfSSL_get_app_data(ssl); if (appData == NULL) { @@ -1364,13 +1372,22 @@ JNIEXPORT jlong JNICALL Java_com_wolfssl_WolfSSLSession_get1Session return (jlong)0; } + /* get protocol version for this session */ + version = wolfSSL_version(ssl); + /* Use wolfSSL_get_session() only as an indicator if we need to call * wolfSSL_peek() for TLS 1.3 connections to potentially get the * session ticket message. */ sess = wolfSSL_get_session(ssl); - if (sess == NULL) { - /* session not available yet (TLS 1.3), try peeking to get ticket */ + /* Check if session has session ticket, checks sess for null internal */ + hasTicket = wolfSSL_SESSION_has_ticket((const WOLFSSL_SESSION*)sess); + + /* If session is not available yet, or if TLS 1.3 and we have a session + * pointer but no session ticket yet, try peeking to get ticket */ + if (sess == NULL || + ((sess != NULL) && (version == TLS1_3_VERSION) && (hasTicket == 0))) { + do { ret = wolfSSL_peek(ssl, tmpBuf, (int)sizeof(tmpBuf)); err = wolfSSL_get_error(ssl, ret); @@ -1397,12 +1414,12 @@ JNIEXPORT jlong JNICALL Java_com_wolfssl_WolfSSLSession_get1Session } while (err == SSL_ERROR_WANT_READ); sess = wolfSSL_get_session(ssl); + hasTicket = wolfSSL_SESSION_has_ticket((const WOLFSSL_SESSION*)sess); } /* Only duplicate / save session if not TLS 1.3 (will be using normal * session IDs), or is TLS 1.3 and we have a session ticket */ - if ((wolfSSL_version(ssl) != TLS1_3_VERSION) || - (wolfSSL_SESSION_has_ticket((const WOLFSSL_SESSION*)sess))) { + if (version != TLS1_3_VERSION || hasTicket == 1) { /* wolfSSL checks ssl for NULL, returns pointer to new WOLFSSL_SESSION, * Returns new duplicated WOLFSSL_SESSION. Needs to be freed with From 648bebadc87ff52b614a40655bff515e809bd612 Mon Sep 17 00:00:00 2001 From: Chris Conlon Date: Thu, 25 Apr 2024 11:27:43 -0600 Subject: [PATCH 5/7] JSSE: close client/server SSLSocket in WolfSSLSocketTest.protocolConnectionTestExtendedSocket() correctly after handshake --- .../com/wolfssl/provider/jsse/test/WolfSSLSocketTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/com/wolfssl/provider/jsse/test/WolfSSLSocketTest.java b/src/test/com/wolfssl/provider/jsse/test/WolfSSLSocketTest.java index 4cda7c8f..a661abaf 100644 --- a/src/test/com/wolfssl/provider/jsse/test/WolfSSLSocketTest.java +++ b/src/test/com/wolfssl/provider/jsse/test/WolfSSLSocketTest.java @@ -2023,6 +2023,7 @@ private void protocolConnectionTestExtendedSocket(String protocol) public Void call() throws Exception { try { server.startHandshake(); + server.close(); } catch (SSLException e) { System.out.println("\t... failed"); @@ -2034,6 +2035,7 @@ public Void call() throws Exception { try { cs.startHandshake(); + cs.close(); } catch (SSLHandshakeException e) { System.out.println("\t... failed"); @@ -2042,8 +2044,6 @@ public Void call() throws Exception { es.shutdown(); serverFuture.get(); - cs.close(); - server.close(); ss.close(); System.out.println("\t... passed"); From afeea367b90499ebe966be65abb21a9102640152 Mon Sep 17 00:00:00 2001 From: Chris Conlon Date: Thu, 25 Apr 2024 11:37:13 -0600 Subject: [PATCH 6/7] JNI/JSSE: fix Infer thread safety violation warnings in WolfSSLSession and WolfSSLSocket --- src/java/com/wolfssl/WolfSSLSession.java | 2 +- src/java/com/wolfssl/provider/jsse/WolfSSLSocket.java | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/java/com/wolfssl/WolfSSLSession.java b/src/java/com/wolfssl/WolfSSLSession.java index 830afcd6..2d3738e1 100644 --- a/src/java/com/wolfssl/WolfSSLSession.java +++ b/src/java/com/wolfssl/WolfSSLSession.java @@ -129,7 +129,7 @@ public WolfSSLSession(WolfSSLContext ctx) throws WolfSSLException { /* ------------------- private/protected methods -------------------- */ /* used from JNI code */ - WolfSSLContext getAssociatedContextPtr() { + synchronized WolfSSLContext getAssociatedContextPtr() { return ctx; } diff --git a/src/java/com/wolfssl/provider/jsse/WolfSSLSocket.java b/src/java/com/wolfssl/provider/jsse/WolfSSLSocket.java index c93e22aa..6341f6b7 100644 --- a/src/java/com/wolfssl/provider/jsse/WolfSSLSocket.java +++ b/src/java/com/wolfssl/provider/jsse/WolfSSLSocket.java @@ -975,7 +975,7 @@ private void setFd() throws IllegalArgumentException, WolfSSLException { * @return array of supported cipher suite Strings */ @Override - public String[] getSupportedCipherSuites() { + public synchronized String[] getSupportedCipherSuites() { WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO, "entered getSupportedCipherSuites()"); @@ -1197,7 +1197,7 @@ public int alpnSelectCallback(WolfSSLSession ssl, String[] out, * @return String array containing supported SSL/TLS protocols */ @Override - public String[] getSupportedProtocols() { + public synchronized String[] getSupportedProtocols() { WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO, "entered getSupportedProtocols()"); From 097ad70817608451c3822f3ce4bc32ca86f13450 Mon Sep 17 00:00:00 2001 From: Chris Conlon Date: Thu, 25 Apr 2024 11:44:43 -0600 Subject: [PATCH 7/7] GitHub Actions: remove Temurin JDK 8, not available on macos --- .github/workflows/main.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 53fb8dd8..3d7a4690 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -53,11 +53,13 @@ jobs: wolfssl_configure: ${{ matrix.wolfssl_configure }} # Temurin JDK (Linux, Mac) + # JDK 8 seems to have been removed from Temurin macos, with 8 we see the error + # Could not find satisfied version for SemVer '8' linux-temurin: strategy: matrix: os: [ 'ubuntu-latest', 'macos-latest' ] - jdk_version: [ '8', '11', '17', '21' ] + jdk_version: [ '11', '17', '21' ] wolfssl_configure: [ '--enable-jni' ] name: ${{ matrix.os }} (Temurin JDK ${{ matrix.jdk_version }}, ${{ matrix.wolfssl_configure}}) uses: ./.github/workflows/linux-common.yml