JDK-8144567 : SNI does not work with HTTPSUrlConnection and a custom HostnameVerifier
  • Type: Bug
  • Component: security-libs
  • Sub-Component: javax.net.ssl
  • Affected Version: 8u51,9
  • Priority: P4
  • Status: Closed
  • Resolution: Duplicate
  • OS: windows_7
  • CPU: x86_64
  • Submitted: 2015-10-26
  • Updated: 2015-12-06
  • Resolved: 2015-12-06
Related Reports
Duplicate :  
Duplicate :  
Description
FULL PRODUCT VERSION :
java version "1.8.0_65"
Java(TM) SE Runtime Environment (build 1.8.0_65-b17)
Java HotSpot(TM) 64-Bit Server VM (build 25.65-b01, mixed mode)

ADDITIONAL OS VERSION INFORMATION :
Microsoft Windows [Version 6.3.9600]

A DESCRIPTION OF THE PROBLEM :
When a custom HostnameVerifier is used, no Server Name Extension is included in the handshake of a HTTPSURLConnection.

The reason is that SSLSocketImpl.setHost is called in HttpsClient.afterConnect, but SSLSocket.setSSLParameters is not (because of the custom hostname verifier).
Without the call to setSSLParameters, the method Handshaker.setSNIServerNames is never called in the SSLSocketImpl, so the handshaker keeps using the serverNames it got when it was initialized (which are none).

Probably SSLSocketImpl.setHost should call Handshaker.setSNIServerNames - alternatively, SSLSocket.setSSLParameters has to be called in any case in HttpsClient.afterConnect. 

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1. set a custom hostnameVerifier with HttpsURLConnection.setDefaultHostnameVerifier()
2. Open a HTTPSURLConnection
3. No ServerName Extension is sent


(see the test case)




EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
The HttpsURLConnection should send a Server Name extension
ACTUAL -
The HttpsURLConnection did not send a Server Name extension

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
import java.io.*;
import java.net.*;
import javax.net.ssl.*;

public class TestSNI {
	public static void main(String[] args) throws Exception {
		HostnameVerifier defaultHostnameVerifier = HttpsURLConnection.getDefaultHostnameVerifier();
		HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {

			@Override
			public boolean verify(String hostname, SSLSession session) {
				return defaultHostnameVerifier.verify(hostname, session);
			}
		});

		URL url = new URL("https://server-that-needs-sni");

		URLConnection con = url.openConnection();
		try (BufferedReader reader = new BufferedReader(new InputStreamReader(con.getInputStream()))) {
			while (true) {
				String line = reader.readLine();
				if (line == null)
					break;
				System.out.println(line);
			}
		}
	}
}

---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
Set a custom SSLSocketFactory that does not return an SSLSocket in createSocket() - this will force creation of a new SSLSocket with a correctly initialized handshaker.


Comments
This is same as JDK-8144566. Closing as duplicate.
03-12-2015