diff --git a/native/com_wolfssl_WolfSSLCRL.c b/native/com_wolfssl_WolfSSLCRL.c index 86a02dbe..bce6e611 100644 --- a/native/com_wolfssl_WolfSSLCRL.c +++ b/native/com_wolfssl_WolfSSLCRL.c @@ -368,6 +368,7 @@ JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLCRL_X509_1CRL_1sign const WOLFSSL_EVP_MD* md = NULL; unsigned char* rsaPrivBuf = NULL; const char* mdName = NULL; + jboolean isCopy = JNI_FALSE; int ret = WOLFSSL_SUCCESS; (void)jcl; @@ -375,7 +376,7 @@ JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLCRL_X509_1CRL_1sign return WOLFSSL_FAILURE; } - keyBuf = (byte*)(*jenv)->GetByteArrayElements(jenv, keyBytes, NULL); + keyBuf = (byte*)(*jenv)->GetByteArrayElements(jenv, keyBytes, &isCopy); if ((*jenv)->ExceptionOccurred(jenv)) { (*jenv)->ExceptionClear(jenv); return WOLFSSL_FAILURE; @@ -471,6 +472,15 @@ JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLCRL_X509_1CRL_1sign (*jenv)->ReleaseStringUTFChars(jenv, digestAlg, mdName); } if (keyBuf != NULL) { + /* Only zero if JVM made a copy */ + if (isCopy == JNI_TRUE) { + #if (LIBWOLFSSL_VERSION_HEX >= 0x05008004) && \ + !defined(WOLFSSL_NO_FORCE_ZERO) + wc_ForceZero(keyBuf, keySz); + #else + XMEMSET(keyBuf, 0, keySz); + #endif + } (*jenv)->ReleaseByteArrayElements(jenv, keyBytes, (jbyte*)keyBuf, JNI_ABORT); } diff --git a/native/com_wolfssl_WolfSSLCertRequest.c b/native/com_wolfssl_WolfSSLCertRequest.c index d592fa89..d39337cd 100644 --- a/native/com_wolfssl_WolfSSLCertRequest.c +++ b/native/com_wolfssl_WolfSSLCertRequest.c @@ -247,6 +247,7 @@ JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLCertRequest_X509_1REQ_1sign const WOLFSSL_EVP_MD* md = NULL; unsigned char* rsaPrivBuf = NULL; const char* mdName = NULL; + jboolean isCopy = JNI_FALSE; int ret = WOLFSSL_SUCCESS; (void)jcl; @@ -255,7 +256,7 @@ JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLCertRequest_X509_1REQ_1sign return WOLFSSL_FAILURE; } - keyBuf = (byte*)(*jenv)->GetByteArrayElements(jenv, keyBytes, NULL); + keyBuf = (byte*)(*jenv)->GetByteArrayElements(jenv, keyBytes, &isCopy); keySz = (*jenv)->GetArrayLength(jenv, keyBytes); if (keyBuf == NULL || keySz == 0) { @@ -343,6 +344,15 @@ JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLCertRequest_X509_1REQ_1sign XFREE(derBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER); } if (keyBuf != NULL) { + /* Only zero if JVM made a copy */ + if (isCopy == JNI_TRUE) { + #if (LIBWOLFSSL_VERSION_HEX >= 0x05008004) && \ + !defined(WOLFSSL_NO_FORCE_ZERO) + wc_ForceZero(keyBuf, keySz); + #else + XMEMSET(keyBuf, 0, keySz); + #endif + } (*jenv)->ReleaseByteArrayElements(jenv, keyBytes, (jbyte*)keyBuf, JNI_ABORT); } diff --git a/native/com_wolfssl_WolfSSLCertificate.c b/native/com_wolfssl_WolfSSLCertificate.c index 5442f75d..365b4601 100644 --- a/native/com_wolfssl_WolfSSLCertificate.c +++ b/native/com_wolfssl_WolfSSLCertificate.c @@ -888,6 +888,7 @@ JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLCertificate_X509_1sign const WOLFSSL_EVP_MD* md = NULL; unsigned char* rsaPrivBuf = NULL; const char* mdName = NULL; + jboolean isCopy = JNI_FALSE; int ret = WOLFSSL_SUCCESS; (void)jcl; @@ -897,7 +898,7 @@ JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLCertificate_X509_1sign return WOLFSSL_FAILURE; } - fileBuf = (byte*)(*jenv)->GetByteArrayElements(jenv, fileBytes, NULL); + fileBuf = (byte*)(*jenv)->GetByteArrayElements(jenv, fileBytes, &isCopy); fileSz = (*jenv)->GetArrayLength(jenv, fileBytes); if (fileBuf == NULL || fileSz == 0) { @@ -990,6 +991,15 @@ JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLCertificate_X509_1sign XFREE(derBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER); } if (fileBuf != NULL) { + /* Only zero if JVM made a copy */ + if (isCopy == JNI_TRUE) { + #if (LIBWOLFSSL_VERSION_HEX >= 0x05008004) && \ + !defined(WOLFSSL_NO_FORCE_ZERO) + wc_ForceZero(fileBuf, fileSz); + #else + XMEMSET(fileBuf, 0, fileSz); + #endif + } (*jenv)->ReleaseByteArrayElements(jenv, fileBytes, (jbyte*)fileBuf, JNI_ABORT); } diff --git a/native/com_wolfssl_WolfSSLContext.c b/native/com_wolfssl_WolfSSLContext.c index 881e44fd..06c9a378 100644 --- a/native/com_wolfssl_WolfSSLContext.c +++ b/native/com_wolfssl_WolfSSLContext.c @@ -1117,7 +1117,7 @@ int NativeIORecvCb(WOLFSSL *ssl, char *buf, int sz, void *ctx) "NativeIORecvCb"); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); - return 0; + return WOLFSSL_CBIO_ERR_GENERAL; } /* lookup WolfSSLSession class from object */ @@ -1329,7 +1329,7 @@ int NativeIOSendCb(WOLFSSL *ssl, char *buf, int sz, void *ctx) "NativeIOSendCb"); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); - return 0; + return WOLFSSL_CBIO_ERR_GENERAL; } /* lookup WolfSSLSession class from object */ diff --git a/native/com_wolfssl_WolfSSLSession.c b/native/com_wolfssl_WolfSSLSession.c index 32bcda0a..a6b7b8c4 100644 --- a/native/com_wolfssl_WolfSSLSession.c +++ b/native/com_wolfssl_WolfSSLSession.c @@ -6613,7 +6613,7 @@ int NativeSSLIORecvCb(WOLFSSL *ssl, char *buf, int sz, void *ctx) if (needsDetach) { (*g_vm)->DetachCurrentThread(g_vm); } - return 0; + return WOLFSSL_CBIO_ERR_GENERAL; } /* Detect if we should use ByteBuffer or byte[] I/O callbacks */ @@ -6789,7 +6789,7 @@ int NativeSSLIOSendCb(WOLFSSL *ssl, char *buf, int sz, void *ctx) if (needsDetach) { (*g_vm)->DetachCurrentThread(g_vm); } - return 0; + return WOLFSSL_CBIO_ERR_GENERAL; } /* Detect if we should use ByteBuffer or byte[] I/O callbacks */ diff --git a/src/java/com/wolfssl/WolfSSLCRL.java b/src/java/com/wolfssl/WolfSSLCRL.java index 4222ff2a..4911304e 100644 --- a/src/java/com/wolfssl/WolfSSLCRL.java +++ b/src/java/com/wolfssl/WolfSSLCRL.java @@ -28,6 +28,7 @@ import java.nio.charset.StandardCharsets; import java.text.ParseException; import java.text.SimpleDateFormat; +import java.util.Arrays; import java.util.Calendar; import java.util.Date; import java.util.Locale; @@ -561,9 +562,13 @@ else if (key instanceof ECPrivateKey) { "PrivateKey does not support encoding"); } - synchronized (crlLock) { - ret = X509_CRL_sign(this.crlPtr, evpKeyType, encodedKey, - WolfSSL.SSL_FILETYPE_ASN1, digestAlg); + try { + synchronized (crlLock) { + ret = X509_CRL_sign(this.crlPtr, evpKeyType, encodedKey, + WolfSSL.SSL_FILETYPE_ASN1, digestAlg); + } + } finally { + Arrays.fill(encodedKey, (byte)0); } return ret; diff --git a/src/java/com/wolfssl/WolfSSLCertRequest.java b/src/java/com/wolfssl/WolfSSLCertRequest.java index 351e3343..d7468a5e 100644 --- a/src/java/com/wolfssl/WolfSSLCertRequest.java +++ b/src/java/com/wolfssl/WolfSSLCertRequest.java @@ -23,6 +23,7 @@ import java.io.File; import java.io.IOException; import java.nio.charset.Charset; +import java.util.Arrays; import java.security.PublicKey; import java.security.PrivateKey; import java.security.interfaces.RSAPublicKey; @@ -634,7 +635,11 @@ public void signRequest(String filePath, int keyType, int format, "Failed to read bytes from file: " + filePath); } - signRequest(fileBytes, keyType, format, digestAlg); + try { + signRequest(fileBytes, keyType, format, digestAlg); + } finally { + Arrays.fill(fileBytes, (byte)0); + } } /** @@ -751,9 +756,13 @@ else if (key instanceof ECPrivateKey) { throw new WolfSSLException("PrivateKey does not support encoding"); } - synchronized (x509ReqLock) { - ret = X509_REQ_sign(this.x509ReqPtr, evpKeyType, encodedKey, - WolfSSL.SSL_FILETYPE_ASN1, digestAlg); + try { + synchronized (x509ReqLock) { + ret = X509_REQ_sign(this.x509ReqPtr, evpKeyType, encodedKey, + WolfSSL.SSL_FILETYPE_ASN1, digestAlg); + } + } finally { + Arrays.fill(encodedKey, (byte)0); } if (ret != WolfSSL.SSL_SUCCESS) { diff --git a/src/java/com/wolfssl/WolfSSLCertificate.java b/src/java/com/wolfssl/WolfSSLCertificate.java index 7e4fee30..85e2bc82 100644 --- a/src/java/com/wolfssl/WolfSSLCertificate.java +++ b/src/java/com/wolfssl/WolfSSLCertificate.java @@ -1345,7 +1345,11 @@ public void signCert(String filePath, int keyType, int format, "Failed to read bytes from file: " + filePath); } - signCert(fileBytes, keyType, format, digestAlg); + try { + signCert(fileBytes, keyType, format, digestAlg); + } finally { + Arrays.fill(fileBytes, (byte)0); + } } /** @@ -1461,9 +1465,13 @@ else if (key instanceof ECPrivateKey) { throw new WolfSSLException("PrivateKey does not support encoding"); } - synchronized (x509Lock) { - ret = X509_sign(this.x509Ptr, evpKeyType, encodedKey, - WolfSSL.SSL_FILETYPE_ASN1, digestAlg); + try { + synchronized (x509Lock) { + ret = X509_sign(this.x509Ptr, evpKeyType, encodedKey, + WolfSSL.SSL_FILETYPE_ASN1, digestAlg); + } + } finally { + Arrays.fill(encodedKey, (byte)0); } if (ret != WolfSSL.SSL_SUCCESS) { diff --git a/src/java/com/wolfssl/provider/jsse/WolfSSLEngine.java b/src/java/com/wolfssl/provider/jsse/WolfSSLEngine.java index 819cda0f..1334e834 100644 --- a/src/java/com/wolfssl/provider/jsse/WolfSSLEngine.java +++ b/src/java/com/wolfssl/provider/jsse/WolfSSLEngine.java @@ -1276,7 +1276,7 @@ private synchronized int RecvAppData(ByteBuffer[] out, int ofst, int length) /* Copy from intermediate buffer to output bufs */ for (i = 0; i < ret;) { - if (idx + ofst >= length) { + if (idx >= length) { /* no more output buffers left */ break; } @@ -1585,9 +1585,9 @@ else if (hs == SSLEngineResult.HandshakeStatus.NEED_WRAP && if (outputSpace >= this.pendingAppDataLen) { /* Serve stashed data to output buffers */ int idx2 = 0; - for (int pos = 0; - pos < this.pendingAppDataLen;) { - if (idx2 + ofst >= length) break; + int pos = 0; + for (; pos < this.pendingAppDataLen;) { + if (idx2 >= length) break; int space = out[idx2 + ofst].remaining(); if (space == 0) { idx2++; continue; } int sz2 = Math.min(space, @@ -1597,7 +1597,7 @@ else if (hs == SSLEngineResult.HandshakeStatus.NEED_WRAP && pos += sz2; if (pos < this.pendingAppDataLen) idx2++; } - produced += this.pendingAppDataLen; + produced += pos; /* Advance past previously consumed bytes */ synchronized (netDataLock) { in.position(in.position() + diff --git a/src/test/com/wolfssl/provider/jsse/test/WolfSSLEngineTest.java b/src/test/com/wolfssl/provider/jsse/test/WolfSSLEngineTest.java index f6a2ceea..d8ea51ab 100644 --- a/src/test/com/wolfssl/provider/jsse/test/WolfSSLEngineTest.java +++ b/src/test/com/wolfssl/provider/jsse/test/WolfSSLEngineTest.java @@ -3419,5 +3419,126 @@ public void testUnwrapRejectsReadOnlyAtOffset() throws Exception { s.unwrap(ByteBuffer.allocateDirect( s.getSession().getPacketBufferSize()), out, 1, 1); } + + /* Verify unwrap() with ofst > 0 placed all `data` bytes into + * out[2] and out[3], and that bytesProduced matches. Regression + * for the `idx + ofst >= length` copy-loop bound in unwrap. */ + private void assertOffsetUnwrapOk(SSLEngineResult result, + ByteBuffer[] outArr, byte[] data) { + + assertEquals(data.length, result.bytesProduced()); + assertEquals(0, outArr[0].position()); + assertEquals(0, outArr[1].position()); + + outArr[2].flip(); + outArr[3].flip(); + int n2 = outArr[2].remaining(); + int n3 = outArr[3].remaining(); + assertEquals(data.length, n2 + n3); + + byte[] got = new byte[n2 + n3]; + outArr[2].get(got, 0, n2); + outArr[3].get(got, n2, n3); + assertTrue(java.util.Arrays.equals(got, data)); + } + + /* Wrap `data` from client and return server's network buffer + * positioned for unwrap(). */ + private ByteBuffer wrapForServer(SSLEngine client, byte[] data) + throws SSLException { + + ByteBuffer netBuf = ByteBuffer.allocateDirect( + client.getSession().getPacketBufferSize()); + SSLEngineResult r = client.wrap(ByteBuffer.wrap(data), netBuf); + assertEquals(SSLEngineResult.Status.OK, r.getStatus()); + netBuf.flip(); + return netBuf; + } + + @Test + public void testUnwrapOffsetMultipleBuffers() throws Exception { + + this.ctx = tf.createSSLContext("TLS", engineProvider); + SSLEngine server = this.ctx.createSSLEngine(); + SSLEngine client = this.ctx.createSSLEngine("wolfSSL test", 11111); + server.setUseClientMode(false); + client.setUseClientMode(true); + assertEquals(0, tf.testConnection(server, client, null, null, "x")); + + byte[] data = new byte[1024]; + new Random().nextBytes(data); + ByteBuffer netBuf = wrapForServer(client, data); + + ByteBuffer[] outArr = new ByteBuffer[] { + ByteBuffer.allocate(600), ByteBuffer.allocate(600), + ByteBuffer.allocate(600), ByteBuffer.allocate(600) + }; + SSLEngineResult r = server.unwrap(netBuf, outArr, 2, 2); + assertEquals(SSLEngineResult.Status.OK, r.getStatus()); + assertOffsetUnwrapOk(r, outArr, data); + } + + @Test + public void testUnwrapPendingAppDataWithOffset() throws Exception { + + this.ctx = tf.createSSLContext("TLS", engineProvider); + SSLEngine server = this.ctx.createSSLEngine(); + SSLEngine client = this.ctx.createSSLEngine("wolfSSL test", 11111); + server.setUseClientMode(false); + client.setUseClientMode(true); + assertEquals(0, tf.testConnection(server, client, null, null, "x")); + + byte[] data = new byte[1024]; + new Random().nextBytes(data); + ByteBuffer netBuf = wrapForServer(client, data); + + /* First unwrap into too-small output stashes pendingAppData */ + SSLEngineResult r = server.unwrap(netBuf, ByteBuffer.allocate(64)); + assertEquals(SSLEngineResult.Status.BUFFER_OVERFLOW, r.getStatus()); + + ByteBuffer[] outArr = new ByteBuffer[] { + ByteBuffer.allocate(600), ByteBuffer.allocate(600), + ByteBuffer.allocate(600), ByteBuffer.allocate(600) + }; + r = server.unwrap(netBuf, outArr, 2, 2); + assertOffsetUnwrapOk(r, outArr, data); + } + + @Test + public void testUnwrapPendingAppDataReStashWithOffset() + throws Exception { + + this.ctx = tf.createSSLContext("TLS", engineProvider); + SSLEngine server = this.ctx.createSSLEngine(); + SSLEngine client = this.ctx.createSSLEngine("wolfSSL test", 11111); + server.setUseClientMode(false); + client.setUseClientMode(true); + assertEquals(0, tf.testConnection(server, client, null, null, "x")); + + byte[] data = new byte[1024]; + new Random().nextBytes(data); + ByteBuffer netBuf = wrapForServer(client, data); + + /* First unwrap stashes pendingAppData */ + SSLEngineResult r = server.unwrap(netBuf, ByteBuffer.allocate(64)); + assertEquals(SSLEngineResult.Status.BUFFER_OVERFLOW, r.getStatus()); + + /* Second unwrap: ofst > 0 but total still too small; + * pendingAppData must survive intact for a later call */ + ByteBuffer[] tooSmall = new ByteBuffer[] { + ByteBuffer.allocate(200), ByteBuffer.allocate(200), + ByteBuffer.allocate(200), ByteBuffer.allocate(200) + }; + r = server.unwrap(netBuf, tooSmall, 2, 2); + assertEquals(SSLEngineResult.Status.BUFFER_OVERFLOW, r.getStatus()); + + /* Third unwrap: ofst > 0 with room drains the stash */ + ByteBuffer[] outArr = new ByteBuffer[] { + ByteBuffer.allocate(600), ByteBuffer.allocate(600), + ByteBuffer.allocate(600), ByteBuffer.allocate(600) + }; + r = server.unwrap(netBuf, outArr, 2, 2); + assertOffsetUnwrapOk(r, outArr, data); + } }