Sunday, 5 January 2014

Jetty Embedded Server Java 7 migration issue ( SSLv2Hello disabled )



Problem

If you have a Jetty embedded server running on Java 5 or 6 listening on SSL and which does not explicitly enable “SSLv2Hello” protocol; then Client having SSLv2 enabled have no issues connecting to the Server. But if you try to run the same server program in Java 7, then you will notice that the client will not able to communicate with Server.

The following program demonstrates the same issue:

Server Program

public class JettyServer {

public static void main(String[] args) throws Exception {

Server server = new Server();

SslSelectChannelConnector ssl_connector = new SslSelectChannelConnector();

ssl_connector.setPort(9999);

SslContextFactory cf = ssl_connector.getSslContextFactory();

cf.setIncludeProtocols(new String[] { "TLSv1" });

String jetty_home = System.getProperty("jetty.home","c:\\Programs\\jetty-distribution-7.6.12.v20130726");

cf.setKeyStore(jetty_home + "/etc/keystore");

cf.setKeyStorePassword("OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4");

cf.setKeyManagerPassword("OBF:1u2u1wml1z7s1z7a1wnl1u2g");

server.setConnectors(new Connector[] { ssl_connector });

server.setHandler(new ResponseHandler());

server.start();

server.join();

}

}


class ResponseHandler extends AbstractHandler {

public void handle(String target, Request baseRequest,

HttpServletRequest request, HttpServletResponse response)

throws IOException, ServletException {

System.out.println("message received");

}

}

Client Program

SslContextFactory cf = new SslContextFactory();

cf.setIncludeProtocols(new String[] { "SSLv2Hello","TLSv1"});

HttpClient httpClient = new HttpClient(cf);

httpClient.start();

ContentExchange exchange = new ContentExchange(true);

exchange.setURL("https://localhost:9999");

httpClient.send(exchange);

int exchangeState = exchange.waitForDone();

                 

if (exchangeState == HttpExchange.STATUS_COMPLETED)

    System.out.println("complete");

else if (exchangeState == HttpExchange.STATUS_EXCEPTED)

System.out.println("error");

else if (exchangeState == HttpExchange.STATUS_EXPIRED)

System.out.println("expired");

                               

httpClient.stop();

Observation

While running Server with Java 5 or 6, the client will be able to connect to Server, and by enabling ssl debug log (via -Djavax.net.debug=all VM argument) you can observe following log lines:
INFO:oejus.SslContextFactory:Enabled Protocols [TLSv1] of [SSLv2Hello, SSLv3, TLSv1]

READ:  SSL v2, contentType = Handshake, translated length = 73

If you run the same Server program in Java 7, the client will fail to connect to Server; and you can notice following logs:
INFO:oejus.SslContextFactory:Enabled Protocols [TLSv1] of [SSLv2Hello, SSLv3, TLSv1, TLSv1.1, TLSv1.2]

…..

qtp2094737972-17, fatal error: 10: General SSLEngine problem

javax.net.ssl.SSLHandshakeException: SSLv2Hello is disabled

Solution

The solution for Jetty server in Java 7 is to enable the SSLv2Hello protocol explicitly (since it is disabled by default in Java 7 http://docs.oracle.com/javase/7/docs/technotes/guides/security/enhancements-7.html); you can do this by replacing the existing line in Server program with following line:
cf.setIncludeProtocols(new String[] { "TLSv1","SSLv2Hello" });

Now the same client program should be able to connect to Server, and in the logs you can notice:
INFO:oejus.SslContextFactory:Enabled Protocols [SSLv2Hello, TLSv1] of [SSLv2Hello, SSLv3, TLSv1, TLSv1.1, TLSv1.2]
...

READ:  SSL v2, contentType = Handshake, translated length = 85