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. outjava9.log
          90 kB
        2. outjava8.log
          95 kB
        3. out1.log
          97 kB
        4. JI9028765.java
          2 kB

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

              Created:
              Updated:
              Resolved: