402666 - Improve handling of TLS exceptions due to raw socket close.
This commit is contained in:
parent
b921ed13c0
commit
b312fffd7e
|
@ -538,8 +538,10 @@ public class SslConnection extends AbstractConnection
|
|||
case NOT_HANDSHAKING:
|
||||
// we just didn't read anything.
|
||||
if (net_filled < 0)
|
||||
_sslEngine.closeInbound();
|
||||
|
||||
{
|
||||
closeInbound();
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
|
||||
case NEED_TASK:
|
||||
|
@ -568,14 +570,8 @@ public class SslConnection extends AbstractConnection
|
|||
// if we just filled some net data
|
||||
if (net_filled < 0)
|
||||
{
|
||||
// If we call closeInbound() before having read the SSL close
|
||||
// message an exception will be thrown (truncation attack).
|
||||
// The TLS specification says that the sender of the SSL close
|
||||
// message may just close and avoid to read the response.
|
||||
// If that is the case, we avoid calling closeInbound() because
|
||||
// will throw the truncation attack exception for nothing.
|
||||
if (isOpen())
|
||||
_sslEngine.closeInbound();
|
||||
closeInbound();
|
||||
return -1;
|
||||
}
|
||||
else if (net_filled > 0)
|
||||
{
|
||||
|
@ -625,6 +621,18 @@ public class SslConnection extends AbstractConnection
|
|||
}
|
||||
}
|
||||
|
||||
private void closeInbound()
|
||||
{
|
||||
try
|
||||
{
|
||||
_sslEngine.closeInbound();
|
||||
}
|
||||
catch (SSLException x)
|
||||
{
|
||||
LOG.ignore(x);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized boolean flush(ByteBuffer... appOuts) throws IOException
|
||||
{
|
||||
|
|
|
@ -26,6 +26,7 @@ import java.nio.channels.SocketChannel;
|
|||
import javax.net.ssl.SSLEngine;
|
||||
import javax.net.ssl.SSLEngineResult;
|
||||
import javax.net.ssl.SSLEngineResult.HandshakeStatus;
|
||||
import javax.net.ssl.SSLException;
|
||||
import javax.net.ssl.SSLSocket;
|
||||
|
||||
import org.eclipse.jetty.io.ssl.SslConnection;
|
||||
|
@ -197,10 +198,28 @@ public class SelectChannelEndPointSslTest extends SelectChannelEndPointTest
|
|||
|
||||
Assert.assertEquals("HelloWorld",reply);
|
||||
|
||||
if (debug) System.err.println("Shutting down output");
|
||||
client.socket().shutdownOutput();
|
||||
|
||||
filled=client.read(sslIn);
|
||||
if (debug) System.err.println("in="+filled);
|
||||
sslIn.flip();
|
||||
try
|
||||
{
|
||||
// Since the client closed abruptly, the server is sending a close alert with a failure
|
||||
engine.unwrap(sslIn, appIn);
|
||||
Assert.fail();
|
||||
}
|
||||
catch (SSLException x)
|
||||
{
|
||||
// Expected
|
||||
}
|
||||
|
||||
sslIn.clear();
|
||||
filled=client.read(sslIn);
|
||||
Assert.assertEquals(-1,filled);
|
||||
|
||||
Assert.assertFalse(server.isOpen());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -39,7 +39,6 @@ import java.util.concurrent.atomic.AtomicInteger;
|
|||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.net.ssl.SSLEngine;
|
||||
import javax.net.ssl.SSLSocket;
|
||||
|
@ -866,7 +865,62 @@ public class SslBytesServerTest extends SslBytesTest
|
|||
// Close the raw socket, this generates a truncation attack
|
||||
proxy.flushToServer(null);
|
||||
|
||||
// Expect raw close from server
|
||||
// Expect alert + raw close from server
|
||||
record = proxy.readFromServer();
|
||||
Assert.assertEquals(TLSRecord.Type.ALERT, record.getType());
|
||||
record = proxy.readFromServer();
|
||||
Assert.assertNull(String.valueOf(record), record);
|
||||
proxy.flushToClient(record);
|
||||
|
||||
// Check that we did not spin
|
||||
TimeUnit.MILLISECONDS.sleep(500);
|
||||
Assert.assertThat(sslFills.get(), Matchers.lessThan(20));
|
||||
Assert.assertThat(sslFlushes.get(), Matchers.lessThan(20));
|
||||
Assert.assertThat(httpParses.get(), Matchers.lessThan(20));
|
||||
|
||||
client.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRequestWithImmediateRawClose() throws Exception
|
||||
{
|
||||
final SSLSocket client = newClient();
|
||||
|
||||
SimpleProxy.AutomaticFlow automaticProxyFlow = proxy.startAutomaticFlow();
|
||||
client.startHandshake();
|
||||
Assert.assertTrue(automaticProxyFlow.stop(5, TimeUnit.SECONDS));
|
||||
|
||||
Future<Object> request = threadPool.submit(new Callable<Object>()
|
||||
{
|
||||
@Override
|
||||
public Object call() throws Exception
|
||||
{
|
||||
OutputStream clientOutput = client.getOutputStream();
|
||||
clientOutput.write(("" +
|
||||
"GET / HTTP/1.1\r\n" +
|
||||
"Host: localhost\r\n" +
|
||||
"\r\n").getBytes("UTF-8"));
|
||||
clientOutput.flush();
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
// Application data
|
||||
TLSRecord record = proxy.readFromClient();
|
||||
Assert.assertEquals(TLSRecord.Type.APPLICATION, record.getType());
|
||||
proxy.flushToServer(record, 0);
|
||||
// Close the raw socket, this generates a truncation attack
|
||||
proxy.flushToServer(null);
|
||||
Assert.assertNull(request.get(5, TimeUnit.SECONDS));
|
||||
|
||||
// Application data
|
||||
record = proxy.readFromServer();
|
||||
Assert.assertEquals(TLSRecord.Type.APPLICATION, record.getType());
|
||||
proxy.flushToClient(record);
|
||||
|
||||
// Expect alert + raw close from server
|
||||
record = proxy.readFromServer();
|
||||
Assert.assertEquals(TLSRecord.Type.ALERT, record.getType());
|
||||
record = proxy.readFromServer();
|
||||
Assert.assertNull(String.valueOf(record), record);
|
||||
proxy.flushToClient(record);
|
||||
|
|
Loading…
Reference in New Issue