diff --git a/native/com_wolfssl_WolfSSLContext.c b/native/com_wolfssl_WolfSSLContext.c index a1d8d7e1..f06912db 100644 --- a/native/com_wolfssl_WolfSSLContext.c +++ b/native/com_wolfssl_WolfSSLContext.c @@ -359,6 +359,11 @@ JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLContext_setTmpDH return (jint)SSL_FAILURE; } + if (pSz <= 0 || pSz > (*jenv)->GetArrayLength(jenv, p) || + gSz <= 0 || gSz > (*jenv)->GetArrayLength(jenv, g)) { + return (jint)BAD_FUNC_ARG; + } + pBuf = (unsigned char*)XMALLOC((int)pSz, NULL, DYNAMIC_TYPE_TMP_BUFFER); if (pBuf == NULL) { ret = MEMORY_E; diff --git a/native/com_wolfssl_WolfSSLSession.c b/native/com_wolfssl_WolfSSLSession.c index 52fe4d49..6178626d 100644 --- a/native/com_wolfssl_WolfSSLSession.c +++ b/native/com_wolfssl_WolfSSLSession.c @@ -3853,6 +3853,11 @@ JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_setTmpDH return SSL_FAILURE; } + if (pSz <= 0 || pSz > (*jenv)->GetArrayLength(jenv, p) || + gSz <= 0 || gSz > (*jenv)->GetArrayLength(jenv, g)) { + return BAD_FUNC_ARG; + } + pBuf = (unsigned char*)XMALLOC((int)pSz, NULL, DYNAMIC_TYPE_TMP_BUFFER); if (pBuf == NULL) { return MEMORY_E; @@ -7122,6 +7127,7 @@ JNIEXPORT jbyteArray JNICALL Java_com_wolfssl_WolfSSLSession_sessionToDerNative WOLFSSL_SESSION* session = (WOLFSSL_SESSION*)(uintptr_t)sessionPtr; unsigned char* buf = NULL; unsigned char* bufStart = NULL; + int bufSz = 0; int len = 0; jbyteArray result = NULL; (void)jcl; @@ -7131,13 +7137,13 @@ JNIEXPORT jbyteArray JNICALL Java_com_wolfssl_WolfSSLSession_sessionToDerNative } /* Get required buffer size */ - len = wolfSSL_i2d_SSL_SESSION(session, NULL); - if (len <= 0) { + bufSz = wolfSSL_i2d_SSL_SESSION(session, NULL); + if (bufSz <= 0) { printf("Length less than or equal to 0\n"); return NULL; } - buf = (unsigned char*)XMALLOC(len, NULL, DYNAMIC_TYPE_TMP_BUFFER); + buf = (unsigned char*)XMALLOC(bufSz, NULL, DYNAMIC_TYPE_TMP_BUFFER); if (buf == NULL) { return NULL; } @@ -7145,25 +7151,25 @@ JNIEXPORT jbyteArray JNICALL Java_com_wolfssl_WolfSSLSession_sessionToDerNative bufStart = buf; len = wolfSSL_i2d_SSL_SESSION(session, &buf); - if (len <= 0) { - XFREE(bufStart, NULL, DYNAMIC_TYPE_TMP_BUFFER); - return NULL; - } - - result = (*jenv)->NewByteArray(jenv, len); - if (result == NULL) { - XFREE(bufStart, NULL, DYNAMIC_TYPE_TMP_BUFFER); - return NULL; + if (len > 0 && len <= bufSz) { + result = (*jenv)->NewByteArray(jenv, len); } - (*jenv)->SetByteArrayRegion(jenv, result, 0, len, (jbyte*)bufStart); - if ((*jenv)->ExceptionOccurred(jenv)) { - (*jenv)->ExceptionDescribe(jenv); - (*jenv)->ExceptionClear(jenv); - XFREE(bufStart, NULL, DYNAMIC_TYPE_TMP_BUFFER); - return NULL; + if (result != NULL) { + (*jenv)->SetByteArrayRegion(jenv, result, 0, len, (jbyte*)bufStart); + if ((*jenv)->ExceptionOccurred(jenv)) { + (*jenv)->ExceptionDescribe(jenv); + (*jenv)->ExceptionClear(jenv); + result = NULL; + } } +#if (LIBWOLFSSL_VERSION_HEX >= 0x05008004) && \ + !defined(WOLFSSL_NO_FORCE_ZERO) + wc_ForceZero(bufStart, (word32)bufSz); +#else + XMEMSET(bufStart, 0, (word32)bufSz); +#endif XFREE(bufStart, NULL, DYNAMIC_TYPE_TMP_BUFFER); return result; #else diff --git a/src/java/com/wolfssl/WolfSSLContext.java b/src/java/com/wolfssl/WolfSSLContext.java index 6cf262c5..91d31a77 100644 --- a/src/java/com/wolfssl/WolfSSLContext.java +++ b/src/java/com/wolfssl/WolfSSLContext.java @@ -970,7 +970,9 @@ WolfSSLDebug.INFO, getContextPtr(), * @return SSL_SUCCESS on success. MEMORY_E * if a memory error was encountered. * SIDE_ERROR if this function is called on an - * SSL client instead of an SSL server. + * SSL client instead of an SSL server. BAD_FUNC_ARG + * if p or g is null, or + * a size is not positive or larger than its array. * @throws IllegalStateException WolfSSLContext has been freed * @throws WolfSSLJNIException Internal JNI error */ diff --git a/src/java/com/wolfssl/WolfSSLSession.java b/src/java/com/wolfssl/WolfSSLSession.java index 5f900071..6e1c2fc8 100644 --- a/src/java/com/wolfssl/WolfSSLSession.java +++ b/src/java/com/wolfssl/WolfSSLSession.java @@ -3796,7 +3796,9 @@ public int checkDomainName(String dn) * @return SSL_SUCCESS on success. MEMORY_E * if a memory error was encountered. * SIDE_ERROR if this function is called on an - * SSL client instead of an SSL server. + * SSL client instead of an SSL server. BAD_FUNC_ARG + * if p or g is null, or + * a size is not positive or larger than its array. * @throws IllegalStateException WolfSSLContext has been freed * @throws WolfSSLJNIException Internal JNI error * @see #accept() diff --git a/src/java/com/wolfssl/provider/jsse/WolfSSLX509.java b/src/java/com/wolfssl/provider/jsse/WolfSSLX509.java index 2c987de6..7801c58c 100644 --- a/src/java/com/wolfssl/provider/jsse/WolfSSLX509.java +++ b/src/java/com/wolfssl/provider/jsse/WolfSSLX509.java @@ -398,8 +398,9 @@ public int getBasicConstraints() { () -> "entered getBasicConstraints()"); if (this.cert == null) { - return 0; + return -1; } + if (this.cert.isCA() == 1) { int pLen = this.cert.getPathLen(); if (pLen == -1) { /* if not set then return max int value */ @@ -407,6 +408,7 @@ public int getBasicConstraints() { } return pLen; } + return -1; } diff --git a/src/test/com/wolfssl/provider/jsse/test/WolfSSLX509Test.java b/src/test/com/wolfssl/provider/jsse/test/WolfSSLX509Test.java index 7420b8d6..c900e912 100644 --- a/src/test/com/wolfssl/provider/jsse/test/WolfSSLX509Test.java +++ b/src/test/com/wolfssl/provider/jsse/test/WolfSSLX509Test.java @@ -222,6 +222,17 @@ public void run() { assertEquals(expected, result[1]); } + @Test + public void testFreedCertNotReportedAsCA() throws Exception { + + WolfSSLX509 ca = new WolfSSLX509(tf.getCert("ca")); + assertTrue("CA cert not reported as CA", + ca.getBasicConstraints() >= 0); + + ca.free(); + assertEquals(-1, ca.getBasicConstraints()); + } + @Test public void testServerParsing() { try { diff --git a/src/test/com/wolfssl/test/WolfSSLContextTest.java b/src/test/com/wolfssl/test/WolfSSLContextTest.java index bccbad12..62e27370 100644 --- a/src/test/com/wolfssl/test/WolfSSLContextTest.java +++ b/src/test/com/wolfssl/test/WolfSSLContextTest.java @@ -43,6 +43,7 @@ import java.security.KeyPairGenerator; import java.security.interfaces.ECPublicKey; import java.security.spec.X509EncodedKeySpec; +import java.util.Arrays; import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutionException; import java.util.concurrent.Executors; @@ -307,6 +308,37 @@ public void test_WolfSSLContext_loadBufferHonorsSz() WolfSSL.SSL_FILETYPE_PEM)); } + @Test + public void test_WolfSSLContext_setTmpDHRejectsBadSz() + throws WolfSSLException, WolfSSLJNIException { + + byte[][] dh = WolfSSLTestCommon.getFfdhe2048Params(); + byte[] p = dh[0]; + byte[] g = dh[1]; + + int ret = ctx.setTmpDH(p, -1, g, g.length); + Assume.assumeTrue("DH not compiled in", + ret != WolfSSL.NOT_COMPILED_IN); + + /* Non-positive and oversized lengths are rejected */ + assertEquals(WolfSSL.BAD_FUNC_ARG, ret); + assertEquals(WolfSSL.BAD_FUNC_ARG, + ctx.setTmpDH(p, 0, g, g.length)); + assertEquals(WolfSSL.BAD_FUNC_ARG, + ctx.setTmpDH(p, p.length + 1, g, g.length)); + assertEquals(WolfSSL.BAD_FUNC_ARG, + ctx.setTmpDH(p, p.length, g, 0)); + assertEquals(WolfSSL.BAD_FUNC_ARG, + ctx.setTmpDH(p, p.length, g, g.length + 1)); + + /* Exact lengths, and lengths shorter than the array, are accepted */ + assertEquals(WolfSSL.SSL_SUCCESS, + ctx.setTmpDH(p, p.length, g, g.length)); + assertEquals(WolfSSL.SSL_SUCCESS, + ctx.setTmpDH(Arrays.copyOf(p, p.length + 1), p.length, + Arrays.copyOf(g, g.length + 1), g.length)); + } + @Test public void test_WolfSSLContext_memsaveCertCache() throws WolfSSLException, WolfSSLJNIException { diff --git a/src/test/com/wolfssl/test/WolfSSLSessionTest.java b/src/test/com/wolfssl/test/WolfSSLSessionTest.java index 9b952a51..c3f80b12 100644 --- a/src/test/com/wolfssl/test/WolfSSLSessionTest.java +++ b/src/test/com/wolfssl/test/WolfSSLSessionTest.java @@ -349,6 +349,48 @@ public void test_WolfSSLSession_useBufferRejectsBadSz() ssl.freeSSL(); } + @Test + public void test_WolfSSLSession_setTmpDHRejectsBadSz() + throws Exception { + + byte[][] dh = WolfSSLTestCommon.getFfdhe2048Params(); + byte[] p = dh[0]; + byte[] g = dh[1]; + + /* Server side, clients get SIDE_ERROR for valid sizes. Load a cert + * and key, wolfSSL_new() rejects a server CTX without them. */ + WolfSSLContext srvCtx = createAndSetupWolfSSLContext(srvCert, srvKey, + WolfSSL.SSL_FILETYPE_PEM, cliCert, WolfSSL.SSLv23_ServerMethod()); + WolfSSLSession ssl = new WolfSSLSession(srvCtx); + + try { + int ret = ssl.setTmpDH(p, -1, g, g.length); + Assume.assumeTrue("DH not compiled in", + ret != WolfSSL.NOT_COMPILED_IN); + + /* Non-positive and oversized lengths are rejected */ + assertEquals(WolfSSL.BAD_FUNC_ARG, ret); + assertEquals(WolfSSL.BAD_FUNC_ARG, + ssl.setTmpDH(p, 0, g, g.length)); + assertEquals(WolfSSL.BAD_FUNC_ARG, + ssl.setTmpDH(p, p.length + 1, g, g.length)); + assertEquals(WolfSSL.BAD_FUNC_ARG, + ssl.setTmpDH(p, p.length, g, 0)); + assertEquals(WolfSSL.BAD_FUNC_ARG, + ssl.setTmpDH(p, p.length, g, g.length + 1)); + + /* Exact lengths, and lens shorter than the array, are accepted */ + assertEquals(WolfSSL.SSL_SUCCESS, + ssl.setTmpDH(p, p.length, g, g.length)); + assertEquals(WolfSSL.SSL_SUCCESS, + ssl.setTmpDH(Arrays.copyOf(p, p.length + 1), p.length, + Arrays.copyOf(g, g.length + 1), g.length)); + } finally { + ssl.freeSSL(); + srvCtx.free(); + } + } + class TestPskClientCb implements WolfSSLPskClientCallback { public long pskClientCallback(WolfSSLSession ssl, String hint, diff --git a/src/test/com/wolfssl/test/WolfSSLTestCommon.java b/src/test/com/wolfssl/test/WolfSSLTestCommon.java index 994701c4..d6fd2265 100644 --- a/src/test/com/wolfssl/test/WolfSSLTestCommon.java +++ b/src/test/com/wolfssl/test/WolfSSLTestCommon.java @@ -27,6 +27,17 @@ public class WolfSSLTestCommon { + /* RFC 7919 ffdhe2048 prime, generator is 2 */ + private static final String FFDHE2048_P = + "FFFFFFFFFFFFFFFFADF85458A2BB4A9AAFDC5620273D3CF1D8B9C583CE2D3695" + + "A9E13641146433FBCC939DCE249B3EF97D2FE363630C75D8F681B202AEC4617A" + + "D3DF1ED5D5FD65612433F51F5F066ED0856365553DED1AF3B557135E7F57C935" + + "984F0C70E0E68B77E2A689DAF3EFE8721DF158A136ADE73530ACCA4F483A797A" + + "BC0AB182B324FB61D108A94BB2C8E3FBB96ADAB760D7F4681D4F42A3DE394DF4" + + "AE56EDE76372BB190B07A7C8EE0A6D709E02FCE1CDF7E2ECC03404CD28342F61" + + "9172FE9CE98583FF8E4F1232EEF28183C3FE3B1B4C6FAD733BB5FCBC2EC22005" + + "C58EF1837D1683B2C6F34A26C1B2EFFA886B423861285C97FFFFFFFFFFFFFFFF"; + /** * Returns a string with the right path to use * @param in relative path from root wolfSSL JNI directory @@ -65,4 +76,17 @@ public static boolean isWindows() { String os = System.getProperty("os.name"); return (os != null && os.contains("Windows")); } + + /** + * Get RFC 7919 ffdhe2048 DH group parameters. + * @return two element array, prime p then generator g + */ + public static byte[][] getFfdhe2048Params() { + byte[] p = new byte[FFDHE2048_P.length() / 2]; + for (int i = 0; i < p.length; i++) { + p[i] = (byte)Integer.parseInt( + FFDHE2048_P.substring(i * 2, i * 2 + 2), 16); + } + return new byte[][] { p, new byte[] { 2 } }; + } }