Skip to content

Commit d15a4bd

Browse files
committed
JSSE: add unit test for instance when multiple records are queued and partial drain of CopyOutPacket() is necesssary
1 parent 5cf3d75 commit d15a4bd

1 file changed

Lines changed: 112 additions & 0 deletions

File tree

src/test/com/wolfssl/provider/jsse/test/WolfSSLEngineTest.java

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import com.wolfssl.provider.jsse.WolfSSLProvider;
2727
import java.io.EOFException;
2828
import java.io.IOException;
29+
import java.lang.reflect.Field;
2930
import java.net.InetAddress;
3031
import java.nio.ByteBuffer;
3132
import java.nio.channels.ServerSocketChannel;
@@ -3508,4 +3509,115 @@ public void testBufferOverflowSmallOutput()
35083509

35093510
pass("\t\t... passed");
35103511
}
3512+
3513+
@Test
3514+
public void testWrapPartialDrainOffsetUpdate()
3515+
throws NoSuchProviderException, NoSuchAlgorithmException,
3516+
KeyManagementException, KeyStoreException,
3517+
CertificateException, IOException,
3518+
UnrecoverableKeyException,
3519+
NoSuchFieldException, IllegalAccessException {
3520+
3521+
/* CopyOutPacket() must decrement internalIOSendBufOffset after a
3522+
* partial drain, otherwise stale ciphertext gets re-emitted. */
3523+
System.out.print("\tTesting wrap() partial drain offset");
3524+
3525+
this.ctx = tf.createSSLContext("TLS", engineProvider);
3526+
SSLEngine server = this.ctx.createSSLEngine();
3527+
SSLEngine client = this.ctx.createSSLEngine("wolfSSL test", 11111);
3528+
3529+
server.setUseClientMode(false);
3530+
server.setNeedClientAuth(false);
3531+
client.setUseClientMode(true);
3532+
3533+
server.beginHandshake();
3534+
client.beginHandshake();
3535+
3536+
int ret = tf.testConnection(server, client, null, null,
3537+
"partial drain test");
3538+
if (ret != 0) {
3539+
error("\t... failed");
3540+
fail("failed to create connection");
3541+
}
3542+
3543+
/* Inject marker of size packetSz + 1000 so first drain copies
3544+
* packetSz bytes and leaves 1000 bytes queued. */
3545+
int packetSz = client.getSession().getPacketBufferSize();
3546+
int queuedSz = packetSz + 1000;
3547+
byte[] marker = new byte[queuedSz];
3548+
for (int i = 0; i < queuedSz; i++) {
3549+
marker[i] = (byte)((i * 31) & 0xFF);
3550+
}
3551+
3552+
Field bufField =
3553+
WolfSSLEngine.class.getDeclaredField("internalIOSendBuf");
3554+
Field bufSzField =
3555+
WolfSSLEngine.class.getDeclaredField("internalIOSendBufSz");
3556+
Field offField =
3557+
WolfSSLEngine.class.getDeclaredField(
3558+
"internalIOSendBufOffset");
3559+
bufField.setAccessible(true);
3560+
bufSzField.setAccessible(true);
3561+
offField.setAccessible(true);
3562+
3563+
bufField.set(client, marker);
3564+
bufSzField.setInt(client, queuedSz);
3565+
offField.setInt(client, queuedSz);
3566+
3567+
/* First wrap: out buffer sized exactly to packetBufferSize so
3568+
* the guard passes but CopyOutPacket partial-drains. */
3569+
ByteBuffer empty = ByteBuffer.allocate(0);
3570+
ByteBuffer firstOut = ByteBuffer.allocate(packetSz);
3571+
SSLEngineResult result = client.wrap(empty, firstOut);
3572+
3573+
if (result.bytesProduced() != packetSz) {
3574+
error("\t... failed");
3575+
fail("first wrap expected " + packetSz +
3576+
" produced, got " + result.bytesProduced());
3577+
}
3578+
3579+
/* Fix-sensitive check: unfixed code leaves offset at queuedSz. */
3580+
int offAfterFirst = offField.getInt(client);
3581+
if (offAfterFirst != queuedSz - packetSz) {
3582+
error("\t... failed");
3583+
fail("internalIOSendBufOffset not decremented after " +
3584+
"partial drain: expected " + (queuedSz - packetSz) +
3585+
", got " + offAfterFirst);
3586+
}
3587+
3588+
/* Second wrap: must drain only the remainder; unfixed code
3589+
* would re-emit packetSz stale bytes instead. */
3590+
ByteBuffer secondOut = ByteBuffer.allocate(packetSz);
3591+
result = client.wrap(empty, secondOut);
3592+
3593+
int expectedRemainder = queuedSz - packetSz;
3594+
if (result.bytesProduced() != expectedRemainder) {
3595+
error("\t... failed");
3596+
fail("second wrap expected " + expectedRemainder +
3597+
" produced (remainder only), got " +
3598+
result.bytesProduced() +
3599+
" — stale bytes re-sent after partial drain");
3600+
}
3601+
3602+
if (offField.getInt(client) != 0) {
3603+
error("\t... failed");
3604+
fail("internalIOSendBufOffset not reset to 0 after " +
3605+
"remainder drained");
3606+
}
3607+
3608+
/* Full integrity check: concatenated drained output must equal
3609+
* the original injected marker exactly. */
3610+
firstOut.flip();
3611+
secondOut.flip();
3612+
byte[] drained = new byte[queuedSz];
3613+
firstOut.get(drained, 0, packetSz);
3614+
secondOut.get(drained, packetSz, expectedRemainder);
3615+
if (!Arrays.equals(marker, drained)) {
3616+
error("\t... failed");
3617+
fail("drained output does not match injected queue");
3618+
}
3619+
3620+
pass("\t... passed");
3621+
}
3622+
35113623
}

0 commit comments

Comments
 (0)