Okhttp: unrecognized_name caused by sslSocket.startHandShake()

Created on 2 Sep 2017  路  3Comments  路  Source: square/okhttp

I'm trying to connect to a server which causes the following error: javax.net.ssl.SSLProtocolException: handshake alert: unrecognized_name.

Disabling SNI extension makes this server works but disables connections to others. I've created a couple of tests to reproduce this: https://gist.github.com/theotherp/4ba450c80d9cc82ddd1260cc81e05704 Please note that each test should be called alone because otherwise they will affect each other.

RealConnection#connectTls calls sslSocket.startHandshake(); which causes the exception. The hostname verifier is not yet involved at this time.

This is not a bug in your code but it makes me unable to connect to two different affected servers at the same time. Apache's HTTPClient discusses the problem here: https://issues.apache.org/jira/browse/HTTPCLIENT-1522

Thanks for your time.

Most helpful comment

Yuri, thanks for the quick response. It works flawlessly, thank you so much! Never would've thought of that.

All 3 comments

I don't have a fix that will work for Android, but for desktop or server java apps, you can disable SNI in your own project with a whitelist e.g.

    DelegatingSSLSocketFactory f = new DelegatingSSLSocketFactory(sslSocketFactory) {
      @Override
      public SSLSocket createSocket(Socket socket, String host, int port, boolean autoClose)
          throws IOException {
        if (host.equals("nzbgeek.info")) {
          host = null;
        }
        return super.createSocket(socket, host, port, autoClose);
      }
    };

I suspect on Android you could do it by returning a DelegatingSSLSocket for hosts in that whitelist. AndroidPlatform should silently fail if the setHostname isn't present.

Yuri, thanks for the quick response. It works flawlessly, thank you so much! Never would've thought of that.

Unfortunately this stopped working with JDK 11.

jdk-10.0.2 works as expected, jdk-11.0.2 throws the old exception.

This solution seems to work across all versions:

protected class SniWhitelistingSocketFactory extends DelegatingSSLSocketFactory {

        public SniWhitelistingSocketFactory(SSLSocketFactory delegate) {
            super(delegate);
        }

        @Override
        public SSLSocket createSocket(Socket socket, final String host, int port, boolean autoClose) throws IOException {
            SSLSocket newSocket = super.createSocket(socket, null, port, autoClose);
            SSLParameters sslParameters = newSocket.getSSLParameters();
            sslParameters.setServerNames(Collections.emptyList());
            newSocket.setSSLParameters(sslParameters);
            return newSocket;
        }
    }
Was this page helpful?
0 / 5 - 0 ratings