Added more SSL tests for split boundary handshake and renegotiation in the middle of content.
This commit is contained in:
parent
324f2049f3
commit
9c804921de
|
@ -201,6 +201,115 @@ public class SslBytesServerTest
|
|||
closeClient(client);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHandshakeWithSplitBoundary() throws Exception
|
||||
{
|
||||
final SSLSocket client = newClient();
|
||||
|
||||
Future<Object> handshake = threadPool.submit(new Callable<Object>()
|
||||
{
|
||||
public Object call() throws Exception
|
||||
{
|
||||
client.startHandshake();
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
// Client Hello
|
||||
TLSRecord record = proxy.readFromClient();
|
||||
byte[] bytes = record.getBytes();
|
||||
byte[] chunk1 = new byte[2 * bytes.length / 3];
|
||||
System.arraycopy(bytes, 0, chunk1, 0, chunk1.length);
|
||||
byte[] chunk2 = new byte[bytes.length - chunk1.length];
|
||||
System.arraycopy(bytes, chunk1.length, chunk2, 0, chunk2.length);
|
||||
proxy.flushToServer(chunk1);
|
||||
TimeUnit.MILLISECONDS.sleep(100);
|
||||
proxy.flushToServer(chunk2);
|
||||
TimeUnit.MILLISECONDS.sleep(100);
|
||||
|
||||
// Server Hello + Certificate + Server Done
|
||||
record = proxy.readFromServer();
|
||||
proxy.flushToClient(record);
|
||||
|
||||
// Client Key Exchange
|
||||
record = proxy.readFromClient();
|
||||
bytes = record.getBytes();
|
||||
chunk1 = new byte[2 * bytes.length / 3];
|
||||
System.arraycopy(bytes, 0, chunk1, 0, chunk1.length);
|
||||
chunk2 = new byte[bytes.length - chunk1.length];
|
||||
System.arraycopy(bytes, chunk1.length, chunk2, 0, chunk2.length);
|
||||
proxy.flushToServer(chunk1);
|
||||
TimeUnit.MILLISECONDS.sleep(100);
|
||||
proxy.flushToServer(chunk2);
|
||||
TimeUnit.MILLISECONDS.sleep(100);
|
||||
|
||||
// Change Cipher Spec
|
||||
record = proxy.readFromClient();
|
||||
bytes = record.getBytes();
|
||||
chunk1 = new byte[2 * bytes.length / 3];
|
||||
System.arraycopy(bytes, 0, chunk1, 0, chunk1.length);
|
||||
chunk2 = new byte[bytes.length - chunk1.length];
|
||||
System.arraycopy(bytes, chunk1.length, chunk2, 0, chunk2.length);
|
||||
proxy.flushToServer(chunk1);
|
||||
TimeUnit.MILLISECONDS.sleep(100);
|
||||
proxy.flushToServer(chunk2);
|
||||
TimeUnit.MILLISECONDS.sleep(100);
|
||||
|
||||
// Client Done
|
||||
record = proxy.readFromClient();
|
||||
bytes = record.getBytes();
|
||||
chunk1 = new byte[2 * bytes.length / 3];
|
||||
System.arraycopy(bytes, 0, chunk1, 0, chunk1.length);
|
||||
chunk2 = new byte[bytes.length - chunk1.length];
|
||||
System.arraycopy(bytes, chunk1.length, chunk2, 0, chunk2.length);
|
||||
proxy.flushToServer(chunk1);
|
||||
TimeUnit.MILLISECONDS.sleep(100);
|
||||
proxy.flushToServer(chunk2);
|
||||
TimeUnit.MILLISECONDS.sleep(100);
|
||||
|
||||
// Change Cipher Spec
|
||||
record = proxy.readFromServer();
|
||||
Assert.assertNotNull(record);
|
||||
proxy.flushToClient(record);
|
||||
|
||||
// Server Done
|
||||
record = proxy.readFromServer();
|
||||
Assert.assertNotNull(record);
|
||||
proxy.flushToClient(record);
|
||||
|
||||
Assert.assertNull(handshake.get(5, TimeUnit.SECONDS));
|
||||
|
||||
// Check that we did not spin
|
||||
Assert.assertThat(sslHandles.get(), lessThan(20));
|
||||
Assert.assertThat(httpParses.get(), lessThan(50));
|
||||
|
||||
client.close();
|
||||
|
||||
// Close Alert
|
||||
record = proxy.readFromClient();
|
||||
bytes = record.getBytes();
|
||||
chunk1 = new byte[2 * bytes.length / 3];
|
||||
System.arraycopy(bytes, 0, chunk1, 0, chunk1.length);
|
||||
chunk2 = new byte[bytes.length - chunk1.length];
|
||||
System.arraycopy(bytes, chunk1.length, chunk2, 0, chunk2.length);
|
||||
proxy.flushToServer(chunk1);
|
||||
TimeUnit.MILLISECONDS.sleep(100);
|
||||
proxy.flushToServer(chunk2);
|
||||
TimeUnit.MILLISECONDS.sleep(100);
|
||||
// Socket close
|
||||
record = proxy.readFromClient();
|
||||
Assert.assertNull("" + record, record);
|
||||
proxy.flushToServer(record);
|
||||
|
||||
// Close Alert
|
||||
record = proxy.readFromServer();
|
||||
proxy.flushToClient(record);
|
||||
// Socket close
|
||||
record = proxy.readFromServer();
|
||||
Assert.assertNull("" + record, record);
|
||||
proxy.flushToClient(record);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRequestResponse() throws Exception
|
||||
{
|
||||
|
@ -237,7 +346,7 @@ public class SslBytesServerTest
|
|||
BufferedReader reader = new BufferedReader(new InputStreamReader(client.getInputStream(), "UTF-8"));
|
||||
String line = reader.readLine();
|
||||
Assert.assertNotNull(line);
|
||||
Assert.assertTrue(line.contains(" 200 "));
|
||||
Assert.assertTrue(line.startsWith("HTTP/1.1 200 "));
|
||||
while ((line = reader.readLine()) != null)
|
||||
{
|
||||
if (line.trim().length() == 0)
|
||||
|
@ -338,13 +447,17 @@ public class SslBytesServerTest
|
|||
BufferedReader reader = new BufferedReader(new InputStreamReader(client.getInputStream(), "UTF-8"));
|
||||
String line = reader.readLine();
|
||||
Assert.assertNotNull(line);
|
||||
Assert.assertTrue(line.contains(" 200 "));
|
||||
Assert.assertTrue(line.startsWith("HTTP/1.1 200 "));
|
||||
while ((line = reader.readLine()) != null)
|
||||
{
|
||||
if (line.trim().length() == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
// Check that we did not spin
|
||||
Assert.assertThat(sslHandles.get(), lessThan(500));
|
||||
Assert.assertThat(httpParses.get(), lessThan(150));
|
||||
|
||||
client.close();
|
||||
|
||||
// Close Alert
|
||||
|
@ -356,7 +469,7 @@ public class SslBytesServerTest
|
|||
}
|
||||
// Socket close
|
||||
record = proxy.readFromClient();
|
||||
Assert.assertNull(record);
|
||||
Assert.assertNull("" + record, record);
|
||||
proxy.flushToServer(record);
|
||||
|
||||
// Close Alert
|
||||
|
@ -364,7 +477,7 @@ public class SslBytesServerTest
|
|||
proxy.flushToClient(record);
|
||||
// Socket close
|
||||
record = proxy.readFromServer();
|
||||
Assert.assertNull(record);
|
||||
Assert.assertNull("" + record, record);
|
||||
proxy.flushToClient(record);
|
||||
}
|
||||
|
||||
|
@ -414,7 +527,7 @@ public class SslBytesServerTest
|
|||
proxy.flushToServer(record);
|
||||
// Socket close
|
||||
record = proxy.readFromClient();
|
||||
Assert.assertNull(record);
|
||||
Assert.assertNull("" + record, record);
|
||||
proxy.flushToServer(record);
|
||||
|
||||
// Expect response from server
|
||||
|
@ -433,12 +546,12 @@ public class SslBytesServerTest
|
|||
|
||||
// Socket close
|
||||
record = proxy.readFromClient();
|
||||
Assert.assertNull(record);
|
||||
Assert.assertNull("" + record, record);
|
||||
proxy.flushToServer(record);
|
||||
|
||||
// Socket close
|
||||
record = proxy.readFromServer();
|
||||
Assert.assertNull(record);
|
||||
Assert.assertNull("" + record, record);
|
||||
proxy.flushToClient(record);
|
||||
}
|
||||
|
||||
|
@ -494,12 +607,12 @@ public class SslBytesServerTest
|
|||
|
||||
// Socket close
|
||||
record = proxy.readFromClient();
|
||||
Assert.assertNull(record);
|
||||
Assert.assertNull("" + record, record);
|
||||
proxy.flushToServer(record);
|
||||
|
||||
// Socket close
|
||||
record = proxy.readFromServer();
|
||||
Assert.assertNull(record);
|
||||
Assert.assertNull("" + record, record);
|
||||
proxy.flushToClient(record);
|
||||
}
|
||||
|
||||
|
@ -538,7 +651,7 @@ public class SslBytesServerTest
|
|||
|
||||
// Expect raw close from server
|
||||
record = proxy.readFromServer();
|
||||
Assert.assertNull(record);
|
||||
Assert.assertNull("" + record, record);
|
||||
proxy.flushToClient(record);
|
||||
|
||||
client.close();
|
||||
|
@ -608,12 +721,12 @@ public class SslBytesServerTest
|
|||
|
||||
// Socket close
|
||||
record = proxy.readFromClient();
|
||||
Assert.assertNull(record);
|
||||
Assert.assertNull("" + record, record);
|
||||
proxy.flushToServer(record);
|
||||
|
||||
// Socket close
|
||||
record = proxy.readFromServer();
|
||||
Assert.assertNull(record);
|
||||
Assert.assertNull("" + record, record);
|
||||
proxy.flushToClient(record);
|
||||
}
|
||||
|
||||
|
@ -665,7 +778,7 @@ public class SslBytesServerTest
|
|||
BufferedReader reader = new BufferedReader(new InputStreamReader(client.getInputStream(), "UTF-8"));
|
||||
String line = reader.readLine();
|
||||
Assert.assertNotNull(line);
|
||||
Assert.assertTrue(line.contains(" 200 "));
|
||||
Assert.assertTrue(line.startsWith("HTTP/1.1 200 "));
|
||||
while ((line = reader.readLine()) != null)
|
||||
{
|
||||
if (line.trim().length() == 0)
|
||||
|
@ -706,8 +819,7 @@ public class SslBytesServerTest
|
|||
}
|
||||
});
|
||||
|
||||
// The data is 8 times bigger than the TLS record max length,
|
||||
// therefore there will be generated 9 TLSRecord
|
||||
// Nine TLSRecords will be generated for the request
|
||||
for (int i = 0; i < 9; ++i)
|
||||
{
|
||||
// Application data
|
||||
|
@ -715,21 +827,20 @@ public class SslBytesServerTest
|
|||
byte[] bytes = record.getBytes();
|
||||
byte[] chunk1 = new byte[2 * bytes.length / 3];
|
||||
System.arraycopy(bytes, 0, chunk1, 0, chunk1.length);
|
||||
proxy.flushToServer(chunk1);
|
||||
|
||||
TimeUnit.MILLISECONDS.sleep(100);
|
||||
|
||||
byte[] chunk2 = new byte[bytes.length - chunk1.length];
|
||||
System.arraycopy(bytes, chunk1.length, chunk2, 0, chunk2.length);
|
||||
proxy.flushToServer(chunk1);
|
||||
TimeUnit.MILLISECONDS.sleep(100);
|
||||
proxy.flushToServer(chunk2);
|
||||
|
||||
TimeUnit.MILLISECONDS.sleep(100);
|
||||
}
|
||||
|
||||
// Check that we did not spin
|
||||
Assert.assertThat(sslHandles.get(), lessThan(10));
|
||||
Assert.assertThat(sslHandles.get(), lessThan(20));
|
||||
Assert.assertThat(httpParses.get(), lessThan(50));
|
||||
|
||||
Assert.assertNull(request.get(5, TimeUnit.SECONDS));
|
||||
|
||||
TLSRecord record = proxy.readFromServer();
|
||||
Assert.assertEquals(TLSRecord.Type.APPLICATION, record.getType());
|
||||
proxy.flushToClient(record);
|
||||
|
@ -737,7 +848,127 @@ public class SslBytesServerTest
|
|||
BufferedReader reader = new BufferedReader(new InputStreamReader(client.getInputStream(), "UTF-8"));
|
||||
String line = reader.readLine();
|
||||
Assert.assertNotNull(line);
|
||||
Assert.assertTrue(line.contains(" 200 "));
|
||||
Assert.assertTrue(line.startsWith("HTTP/1.1 200 "));
|
||||
while ((line = reader.readLine()) != null)
|
||||
{
|
||||
if (line.trim().length() == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
closeClient(client);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRequestWithBigContentWithRenegotiationInMiddleOfContent() throws Exception
|
||||
{
|
||||
final SSLSocket client = newClient();
|
||||
final OutputStream clientOutput = client.getOutputStream();
|
||||
|
||||
SimpleProxy.AutomaticFlow automaticProxyFlow = proxy.startAutomaticFlow();
|
||||
client.startHandshake();
|
||||
Assert.assertTrue(automaticProxyFlow.stop(5, TimeUnit.SECONDS));
|
||||
|
||||
// Use a content that is larger than the TLS record which is 2^14 (around 16k)
|
||||
byte[] data1 = new byte[80 * 1024];
|
||||
Arrays.fill(data1, (byte)'X');
|
||||
String content1 = new String(data1, "UTF-8");
|
||||
byte[] data2 = new byte[48 * 1024];
|
||||
Arrays.fill(data2, (byte)'Y');
|
||||
final String content2 = new String(data2, "UTF-8");
|
||||
|
||||
// Write only part of the body
|
||||
automaticProxyFlow = proxy.startAutomaticFlow();
|
||||
clientOutput.write(("" +
|
||||
"POST / HTTP/1.1\r\n" +
|
||||
"Host: localhost\r\n" +
|
||||
"Content-Type: text/plain\r\n" +
|
||||
"Content-Length: " + (content1.length() + content2.length()) + "\r\n" +
|
||||
"\r\n" +
|
||||
content1).getBytes("UTF-8"));
|
||||
clientOutput.flush();
|
||||
Assert.assertTrue(automaticProxyFlow.stop(5, TimeUnit.SECONDS));
|
||||
|
||||
// Renegotiate
|
||||
Future<Object> renegotiation = threadPool.submit(new Callable<Object>()
|
||||
{
|
||||
public Object call() throws Exception
|
||||
{
|
||||
client.startHandshake();
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
// Renegotiation Handshake
|
||||
TLSRecord record = proxy.readFromClient();
|
||||
proxy.flushToServer(record);
|
||||
|
||||
// Renegotiation Handshake
|
||||
record = proxy.readFromServer();
|
||||
proxy.flushToClient(record);
|
||||
|
||||
// Renegotiation Change Cipher
|
||||
record = proxy.readFromServer();
|
||||
Assert.assertEquals(TLSRecord.Type.CHANGE_CIPHER_SPEC, record.getType());
|
||||
proxy.flushToClient(record);
|
||||
|
||||
// Renegotiation Handshake
|
||||
record = proxy.readFromServer();
|
||||
proxy.flushToClient(record);
|
||||
|
||||
// Trigger a read to have the client write the final renegotiation steps
|
||||
client.setSoTimeout(100);
|
||||
try
|
||||
{
|
||||
client.getInputStream().read();
|
||||
Assert.fail();
|
||||
}
|
||||
catch (SocketTimeoutException x)
|
||||
{
|
||||
// Expected
|
||||
}
|
||||
|
||||
// Renegotiation Change Cipher
|
||||
record = proxy.readFromClient();
|
||||
Assert.assertEquals(TLSRecord.Type.CHANGE_CIPHER_SPEC, record.getType());
|
||||
proxy.flushToServer(record);
|
||||
|
||||
// Renegotiation Handshake
|
||||
record = proxy.readFromClient();
|
||||
proxy.flushToServer(record);
|
||||
|
||||
Assert.assertNull(renegotiation.get(5, TimeUnit.SECONDS));
|
||||
|
||||
// Write the rest of the request
|
||||
Future<Object> request = threadPool.submit(new Callable<Object>()
|
||||
{
|
||||
public Object call() throws Exception
|
||||
{
|
||||
clientOutput.write(content2.getBytes("UTF-8"));
|
||||
clientOutput.flush();
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
// Three TLSRecords will be generated for the remainder of the content
|
||||
for (int i = 0; i < 3; ++i)
|
||||
{
|
||||
// Application data
|
||||
record = proxy.readFromClient();
|
||||
proxy.flushToServer(record);
|
||||
}
|
||||
|
||||
Assert.assertNull(request.get(5, TimeUnit.SECONDS));
|
||||
|
||||
// Read response
|
||||
// Application Data
|
||||
record = proxy.readFromServer();
|
||||
Assert.assertEquals(TLSRecord.Type.APPLICATION, record.getType());
|
||||
proxy.flushToClient(record);
|
||||
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(client.getInputStream(), "UTF-8"));
|
||||
String line = reader.readLine();
|
||||
Assert.assertNotNull(line);
|
||||
Assert.assertTrue(line.startsWith("HTTP/1.1 200 "));
|
||||
while ((line = reader.readLine()) != null)
|
||||
{
|
||||
if (line.trim().length() == 0)
|
||||
|
@ -764,7 +995,7 @@ public class SslBytesServerTest
|
|||
proxy.flushToServer(record);
|
||||
// Socket close
|
||||
record = proxy.readFromClient();
|
||||
Assert.assertNull(record);
|
||||
Assert.assertNull("" + record, record);
|
||||
proxy.flushToServer(record);
|
||||
|
||||
// Close Alert
|
||||
|
@ -772,7 +1003,7 @@ public class SslBytesServerTest
|
|||
proxy.flushToClient(record);
|
||||
// Socket close
|
||||
record = proxy.readFromServer();
|
||||
Assert.assertNull(record);
|
||||
Assert.assertNull("" + record, record);
|
||||
proxy.flushToClient(record);
|
||||
}
|
||||
|
||||
|
@ -833,7 +1064,7 @@ public class SslBytesServerTest
|
|||
{
|
||||
InputStream input = socket.getInputStream();
|
||||
int first = -2;
|
||||
while (!Thread.currentThread().isInterrupted())
|
||||
while (true)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
@ -843,7 +1074,8 @@ public class SslBytesServerTest
|
|||
}
|
||||
catch (SocketTimeoutException x)
|
||||
{
|
||||
// Ignore
|
||||
if (Thread.currentThread().isInterrupted())
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (first == -2)
|
||||
|
@ -910,9 +1142,9 @@ public class SslBytesServerTest
|
|||
}
|
||||
}
|
||||
|
||||
public void flushToServer(byte... datum) throws IOException
|
||||
public void flushToServer(byte... bytes) throws IOException
|
||||
{
|
||||
flush(server, datum);
|
||||
flush(server, bytes);
|
||||
}
|
||||
|
||||
private void flush(Socket socket, byte... bytes) throws IOException
|
||||
|
@ -1040,6 +1272,12 @@ public class SslBytesServerTest
|
|||
return bytes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return "TLSRecord [" + type + "] " + bytes.length + " bytes";
|
||||
}
|
||||
|
||||
public enum Type
|
||||
{
|
||||
CHANGE_CIPHER_SPEC(20), ALERT(21), HANDSHAKE(22), APPLICATION(23);
|
||||
|
|
Loading…
Reference in New Issue