Search code examples
javasslhttpshttpurlconnectionconnection-reset

Java HttpsUrlConnection, connection reset


String url1 = "foo1.blabla.com";
String url2 = "foo2_bar.blabla.com";
URLConnection urlConnection = new URL(url1).openConnection();
urlConnection.setDoInput(true);

//Fails
InputStream in = urlConnection.getInputStream();

We were able to connect url1 without problems, but they recently changed their url to url2 and claim that they only changed their url and nothing else. But after the modification I got the following exceptions:

java.net.SocketException: Connection reset at java.net.SocketInputStream.read(SocketInputStream.java:210) at java.net.SocketInputStream.read(SocketInputStream.java:141) at sun.security.ssl.InputRecord.readFully(InputRecord.java:465) at sun.security.ssl.InputRecord.read(InputRecord.java:503) at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:975) at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1367) at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1395) at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1379) at sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:559)

  • I tried Java 1.8.181, 1.8.191.

  • I tried using customhostnameverifier such as

    class CustomHostNameVerifier implements HostnameVerifier {

      public CustomHostNameVerifier() {
    
      }
    
      @Override
      public boolean verify(String arg0, SSLSession arg1) {
    
          return true;
      }
    

    }

  • Both url1 and url2 have same certificate information, I also added their .cer into keystore using keytool.

  • There is not firewall or antivirus issue becasue on same computer I can connect to url2 with postman. I added same headers like postman to my java code.

  • I checked following so pages:

java.net.SocketException: Connection reset With HTTPConnection

What's causing my java.net.SocketException: Connection reset?

java.net.SocketException: Connection reset

connection reset on HttpsUrlConnection with valid URL

  • I run the program with -Djavax.net.debug=ssl:handshake:verbose:keymanager:trustmanager -Djava.security.debug=access:stack

and see the following differences:

for url1 (working fine)

SendHTTPTest.f9() connection opened Allow unsafe renegotiation: false Allow legacy hello messages: true Is initial handshake: true Is secure renegotiation: false main, the previous server name in SNI (type=host_name (0), value=foo1.blabla.com) was replaced with (type=host_name (0), value=foo1.blabla.com) Extension extended_master_secret Extension server_name, server_name: [type=host_name (0), value=foo1.blabla.com] *** main, WRITE: TLSv1.2 Handshake, length = 226 main, READ: TLSv1.2 Handshake, length = 2303 *** ServerHello, TLSv1.2

for url2 (connection reset problem)

SendHTTPTest.f9() connection opened main, "foo2_bar.blabla.com" is not a legal HostName for server name indication Allow unsafe renegotiation: false Allow legacy hello messages: true Is initial handshake: true Is secure renegotiation: false main, "foo2_bar.blabla.com" is not a legal HostName for server name indication main, WRITE: TLSv1.2 Handshake, length = 193 main, handling exception: java.net.SocketException: Connection reset main, SEND TLSv1.2 ALERT: fatal, description = unexpected_message main, WRITE: TLSv1.2 Alert, length = 2 main, Exception sending alert: java.net.SocketException: Connection reset by peer: socket write error main, called closeSocket() java.net.SocketException: Connection reset

Probably the message causes main, "foo2_bar.blabla.com" is not a legal HostName for server name indication the problem, it is SNI related? Underscore in url2 may cause problem?

SNI client-side mystery using Java8


Solution

  • (From comments for resolution, and search)

    Many things can cause reset on SSL/TLS handshake, depending on the server, but nowadays a common one is missing Server Name Indication (SNI).

    Aside from bugs in some older versions, Java (JSSE) fails to send SNI in several cases:

    • hostname is an IP address (v4 or v6)

    • hostname contains no dot, or has dot at end (i.e. doesn't 'look like' a DNS name)

    • hostname contains ASCII characters other than letters, digits, and hyphen (in the positions allowed by DNS and IDN) and dot (in the positions allowed by DNS); this restriction is apparently based on RFC952 as referenced in STD3=RFC1123. (NonASCII characters -- Unicode U+0080 and up -- are converted following IDN rules to punycode, which by design satisfies the restrictions.)

    In this case the problem was the third point; the hostname contained an ASCII underscore.