-1
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

benchpresser
  • 2,171
  • 2
  • 23
  • 41
  • I removed the domain name from u2 and replaced with ip address, the error message foo2 it not a legal HostName for server name indiction disappeared, but problem continues with *** 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() – benchpresser Sep 11 '20 at 23:28
  • 1
    Many HTTPS servers today require SNI, and if you use (a URL containing) an address or only a single-label name, not a DNS-format name with at least one dot, Java/JSSE does not send SNI, which causes the handshake to fail. Look at _all_ of the debug log and it shows this. (The name needn't actually be in DNS if you have other name resolution on your system like /etc/hosts or NIS or mDNS, it just must be in DNS format.) BTW if either hostname or cert validation was the problem it would produce very different symptoms, NEVER connection reset, so those just reduced your security for nothing. – dave_thompson_085 Sep 12 '20 at 01:59
  • Url1 is in format blabla.foo1 . com and url2 is in format blabla_nteapi.foo2 . com can the underscore cause problem? Or what is nte api they call it in their docs and there is also a tnt api and a swagger link i did not heard before. In old url i never heard them – benchpresser Sep 12 '20 at 06:35
  • 1
    **Indeed it can!** I didn't read far enough. The code in _JSSE_ directly forbids addresses and no-dot (and also dot _at end_ which I didn't mention but is rarely used). However it then calls `java.net.IDN` to handle 'internationalized' names (i.e. domain names containing non-ASCII graphics which are converted to 'punycode') and _that_ applies a rule that forbids all ASCII characters other than letters, digits, hyphen (not at beginning or end), and dot (as limited by DNS). It attributes these to STD3=RFC1123, but that actually references RFC952. You may be out of luck. Sorry :-( – dave_thompson_085 Sep 13 '20 at 06:48
  • Your answers are very heplful thank you. I will tell them to remove _ from subdmains if possible. In the question I did not mentioned about _ because did not think that might cause problem. By the way can you write your comments as answer and I accept so you get the points? – benchpresser Sep 13 '20 at 16:32
  • 1
    benchpresser - Unless you notify Dave using @dave_thompson_085 he would not get notification of your comment. You do not need to notify him anymore as he will get notified with this comment. – Arvind Kumar Avinash Sep 13 '20 at 16:47
  • @dave_thompson_085 the customer removed the _ and the problem resolved! Thank you. I think this post will be very helpful who encounters such a problem! By the way can you write your comments as answer and I accept so you get the points – benchpresser Sep 14 '20 at 08:25
  • Those aren't URLs, they are just hiostnames, and they cannot possibly have provoked the exception or the stack trace you provided. – user207421 Sep 15 '20 at 02:18

1 Answers1

2

(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.

dave_thompson_085
  • 34,712
  • 6
  • 50
  • 70