Merge pull request #365 from JeremiahM37/fenrir-fixes-4
unwrap bounds, CBIO error returns, key zeroizationpull/366/head
commit
1bea4bec2d
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ import java.nio.charset.Charset;
|
|||
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 @@ public class WolfSSLCRL implements Serializable {
|
|||
"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;
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ package com.wolfssl;
|
|||
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 class WolfSSLCertRequest {
|
|||
"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 @@ public class WolfSSLCertRequest {
|
|||
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) {
|
||||
|
|
|
|||
|
|
@ -1345,7 +1345,11 @@ public class WolfSSLCertificate implements Serializable {
|
|||
"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 @@ public class WolfSSLCertificate implements Serializable {
|
|||
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) {
|
||||
|
|
|
|||
|
|
@ -1276,7 +1276,7 @@ public class WolfSSLEngine extends SSLEngine {
|
|||
|
||||
/* 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 @@ public class WolfSSLEngine extends SSLEngine {
|
|||
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 @@ public class WolfSSLEngine extends SSLEngine {
|
|||
pos += sz2;
|
||||
if (pos < this.pendingAppDataLen) idx2++;
|
||||
}
|
||||
produced += this.pendingAppDataLen;
|
||||
produced += pos;
|
||||
/* Advance past previously consumed bytes */
|
||||
synchronized (netDataLock) {
|
||||
in.position(in.position() +
|
||||
|
|
|
|||
|
|
@ -3420,5 +3420,126 @@ public class WolfSSLEngineTest {
|
|||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue