Search code examples
javajakarta-eenettysni

Cannot enable SNI on Java 7


I'm trying to call a server using TLS accepting only clients with SNI support.

I'm running the client using Java 7:

$ java -version
java version "1.7.0_80"
Java(TM) SE Runtime Environment (build 1.7.0_80-b15)
Java HotSpot(TM) 64-Bit Server VM (build 24.80-b11, mixed mode)

It should be enabled by default but:

  • "it doesn't work"
  • I cannot see it as an extension in the logs

Eg from my logs:

Compression Methods:  { 0 }
Extension elliptic_curves, curve names: {secp256r1, sect163k1, sect163r2, secp192r1, secp224r1, sect233k1, sect233r1, sect283k1, sect283r1, secp384r1, sect409k1, sect409r1, secp521r1, sect571k1, sect571r1, secp160k1, secp160r1, secp160r2, sect163r1, secp192k1, sect193r1, sect193r2, secp224k1, sect239k1, secp256k1}
Extension ec_point_formats, formats: [uncompressed]
Extension signature_algorithms, signature_algorithms: SHA512withECDSA, SHA512withRSA, SHA384withECDSA, SHA384withRSA, SHA256withECDSA, SHA256withRSA, SHA256withDSA, SHA224withECDSA, SHA224withRSA, SHA224withDSA, SHA1withECDSA, SHA1withRSA, SHA1withDSA
Extension renegotiation_info, renegotiated_connection: <empty>
***

While I expect to find

Extension server_name, server_name: [host_name: my.servername.com]

I tried to add the flag -Djsse.enableSNIExtension=true to be sure, without success.

I'm doing the tests using Netty 4.0.37 and get this exception:

io.netty.handler.codec.DecoderException: javax.net.ssl.SSLException: Received fatal alert: handshake_failure
    at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:442)
    at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:248)

What is the trick to enable SNI on a Java 7 JVM?


Solution

  • The issue was on Netty/SSL engine configuration.

    It used to be configured likes this:

    public void initChannel(SocketChannel ch) throws Exception {
        SSLEngine sslEngine = SSLContext.getDefault().createSSLEngine();
        sslEngine.setUseClientMode(true);
        ch.pipeline()
          .addLast("ssl", new SslHandler(sslEngine));
    }
    

    Actually, it is working when configured like this, explicitly setting the target server name:

    public void initChannel(SocketChannel ch) throws Exception {
        SslContext sslContext = SslContextBuilder.forClient().build();
        ch.pipeline()
          .addLast(
              sslContext.newHandler(
                  ch.alloc(), 
                  host, 
                  port
              )
          );
    }
    

    With this configuration, there should be in the logs (with -Djavax.net.debug=all flag set):

    Extension server_name, server_name: [type=host_name (0), value=target.hostname.com]