Added more SSL tests for split boundary handshake and renegotiation in the middle of content.

This commit is contained in:
Simone Bordet 2011-11-18 11:54:31 +01:00
parent 324f2049f3
commit 9c804921de
1 changed files with 266 additions and 28 deletions

View File

@ -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);