Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8163267

Inconsistent behavior when using SSL over socks proxy

XMLWordPrintable

      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 :
      Linux l-qfwrapper28.f.cn8 2.6.32-358.23.2.el6.x86_64 #1 SMP Wed Oct 16 18:37:12 UTC 2013 x86_64 x86_64 x86_64 GNU/Linux

      A DESCRIPTION OF THE PROBLEM :
      Some websites need server_name in Client Hello.

      I create SSLSocket over a socks proxyed socket and call SSLSocket.setHost(String) in following way:
              
              final Socket socket = new Socket(new Proxy(Proxy.Type.SOCKS, new InetSocketAddress(socksProxyHost, socksProxyPort)));
              socket.connect(new InetSocketAddress(hostname, port));
              final Socket sslSocket = ((SSLSocketFactory) SSLSocketFactory.getDefault()).createSocket(socket, socksProxyHost, socksProxyPort, true);
              final SSLSocketImpl impl = (SSLSocketImpl) sslSocket;
              impl.setHost(hostname);


      This works in jdk1.7.0_45, but fails in lastest jdk1.8.0_65.

      In jdk1.8, create SSLSocket using connected socket and then setHost don't modify serverNames in HandShaker, which will be used in handshake later.

      REGRESSION. Last worked in version 7u76

      ADDITIONAL REGRESSION INFORMATION:
      java version "1.7.0_45"
      Java(TM) SE Runtime Environment (build 1.7.0_45-b18)
      Java HotSpot(TM) 64-Bit Server VM (build 24.45-b08, mixed mode)

      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      Using source code in "Source code for an executable test case:"

      Compile and run with:
      java -Djavax.net.debug=all SSLOverSocksMain | grep server_name

      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      [tianyu.yang@l-qfwrapper28.f.cn8 ~]$ java -version
      java version "1.7.0_45"
      Java(TM) SE Runtime Environment (build 1.7.0_45-b18)
      Java HotSpot(TM) 64-Bit Server VM (build 24.45-b08, mixed mode)

      [tianyu.yang@l-qfwrapper28.f.cn8 ~]$ java -Djavax.net.debug=all SSLOverSocksMain | grep server_name
      Extension server_name, server_name: [host_name: www.baidu.com]

      [tianyu.yang@l-qfwrapper28.f.cn8 ~]$

      ACTUAL -
      [tianyu.yang@l-qfwrapper28.f.cn8 ~]$ java -versionjava 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)

      [tianyu.yang@l-qfwrapper28.f.cn8 ~]$ java -Djavax.net.debug=all SSLOverSocksMain | grep server_name

      [tianyu.yang@l-qfwrapper28.f.cn8 ~]$

      REPRODUCIBILITY :
      This bug can be reproduced always.

      ---------- BEGIN SOURCE ----------
      import sun.security.ssl.SSLSocketImpl;

      import javax.net.ssl.SNIHostName;
      import javax.net.ssl.SNIServerName;
      import javax.net.ssl.SSLParameters;
      import javax.net.ssl.SSLSocketFactory;
      import java.io.IOException;
      import java.net.InetSocketAddress;
      import java.net.Proxy;
      import java.net.Socket;
      import java.net.SocketTimeoutException;
      import java.util.Collections;

      /**
       * @author tianyu.yang
       */
      public class SSLOverSocksMain {
          public static void main(String[] args) throws IOException {
              final String socksProxyHost = "10.89.38.236"; // a socks proxy
              final int socksProxyPort = 16045;

              final String hostname = "www.baidu.com";
              final int port = 443;

              final Socket socket = new Socket(new Proxy(Proxy.Type.SOCKS, new InetSocketAddress(socksProxyHost, socksProxyPort)));
              socket.connect(new InetSocketAddress(hostname, port));
              final Socket sslSocket = ((SSLSocketFactory) SSLSocketFactory.getDefault()).createSocket(socket, socksProxyHost, socksProxyPort, true);

              try {
                  sslSocket.setSoTimeout(3000);
                  final SSLSocketImpl impl = (SSLSocketImpl) sslSocket;

                  // jdk 1.7 works
                  impl.setHost(hostname);

                  // jdk 1.8 works
                  // final SSLParameters sslParameters = impl.getSSLParameters();
                  // sslParameters.setServerNames(Collections.<SNIServerName>singletonList(new SNIHostName(hostname)));
                  // impl.setSSLParameters(sslParameters);

                  // request
                  String getRequest = "GET / HTTP/1.1\r\nHost: www.baidu.com\r\nAccept: */*\r\n\r\n";
                  sslSocket.getOutputStream().write(getRequest.getBytes());
                  sslSocket.getOutputStream().flush();

                  // consume response
                  final StringBuilder buf = new StringBuilder();
                  int read = sslSocket.getInputStream().read();
                  try {
                      while (read >= 0) {
                          buf.append((char)read);
                          read = sslSocket.getInputStream().read();
                      }
                  } catch (SocketTimeoutException e) {
                      // ignore
                  }

                  // System.out.println(buf.toString());
              } finally {
                  sslSocket.close();
              }
          }
      }

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

      CUSTOMER SUBMITTED WORKAROUND :
      Comment code below "jdk 1.7 works" and uncomment the code below "jdk 1.8 works". Then it works under jdk1.8.

        1. JI9028765.java
          2 kB
        2. out1.log
          97 kB
        3. outjava8.log
          95 kB
        4. outjava9.log
          90 kB

            rpatil Ramanand Patil (Inactive)
            webbuggrp Webbug Group
            Votes:
            0 Vote for this issue
            Watchers:
            4 Start watching this issue

              Created:
              Updated:
              Resolved: