Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to read SNI extension in Java?

I want to find host name from TLS Client Hello Message. I want to find host name before java does complete handshake for transparent ssl proxy.

Is there any way to find SNI extension value without writing whole ssl handshake logic ?

Is Java supports ssl handshake with initial memory buffer ? My Idea is:

  1. Read TLS client hello message, parse it and find SNI value
  2. Call sslSocket.startHandshake(initialBuffer) Initial buffer will contain TLS client hello packet data. So Java can do handshake.

Second Idea is to use SSLEngine class. But it seems a lot more implementation than requirement. I assume SSLEngine is used most of async in case which I don't require it.

Third idea is to implement complete TLS protocol.

Which idea is better ?

like image 413
Rajdip Patel Avatar asked Mar 19 '26 01:03

Rajdip Patel


2 Answers

Both SSLSocket and SSLEngine lack (quite inexplicable) proper SNI support for server connections.

I came across the same problem myself and ended up writing a library: TLS Channel. It does not only that, it is actually a complete abstraction for SSLEngine, exposed as a ByteChannel. Regarding SNI, the library does the parsing of the first bytes before creating the SSLEngine. The user can then supply a function to the server channel, to select SSLContexts depending on the received domain name.

like image 126
Mariano Barrios Avatar answered Mar 20 '26 13:03

Mariano Barrios


The accepted answer to this question is a bit old and does not really provide an answer to the question.

You should use a custom KeyManager when initializing the SSLContext and the trick is to use a javax.net.ssl.X509ExtendedKeyManager (note the Extended term). This will offer the possibility to expose the SSLEngine during the key alias selection process instead of the plain (useless) socket.

The method chooseEngineServerAlias(...) will be called during the SSL handshake process in order to select the proper alias (cert/key) from the KeyStore. And the SNI information is already populated and available in the SSLEngine. The trick here is to cast the SSLSession as an ExtendedSSLSession (note the Extended term) and then to getRequestedServerNames().

KeyManager[] km = new KeyManager[]
{
    new X509ExtendedKeyManager()
    {
        public String chooseEngineServerAlias(String keyType, Principal[] issuers, SSLEngine engine)
        {
            if( engine.getHandshakeSession() instanceof ExtendedSSLSession )
            {
               List<SNIServerName> sni = ((ExtendedSSLSession)engine.getHandshakeSession()).getRequestedServerNames();

                // select the proper certificate alias based on SNI here
            }
        }
    }
}

SSLContext context = SSLContext.getInstance("TLS");
context.init(km, null, null);
like image 31
Simon Avatar answered Mar 20 '26 14:03

Simon



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!