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

Support for "UseExtendedMasterSecret" in Class sun.security.ssl.ClientHandshaker breaks TLS-Session resumption with custom Hostnameverifier

XMLWordPrintable

      FULL PRODUCT VERSION :
      java version "1.8.0_162"
      Java(TM) SE Runtime Environment (build 1.8.0_162-b12)
      Java HotSpot(TM) 64-Bit Server VM (build 25.162-b12, mixed mode)


      ADDITIONAL OS VERSION INFORMATION :
      Linux 3.13.0-142-generic #191-Ubuntu SMP Fri Feb 2 12:13:35 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux


      A DESCRIPTION OF THE PROBLEM :
      Clients using TLS with client-auth do not resume existing TLS-Session if custom HostnameVerifier is used.


      JDK 1.8.0_162 introduced an extension for "Extended Master Secret" for TLS.

      This extension breaks the TLS-Session resume, if a custom HostnameVerifier is used.

      I was able to identify the commit in OpenJDK:

      changeset 12870:8d358ca3cfb8 jdk8u161-b11

      8148421: Transport Layer Security (TLS) Session Hash and Extended Master Secret Extension
      Reviewed-by: wetmore, xuelei, rhalade, coffeys, bgopularam
      Contributed-by: prasadarao.koppula@oracle.com

      REGRESSION. Last worked in version 8u152

      ADDITIONAL REGRESSION INFORMATION:
      java version "1.8.0_152"
      Java(TM) SE Runtime Environment (build 1.8.0_152-b16)
      Java HotSpot(TM) 64-Bit Server VM (build 25.152-b16, mixed mode)

      Remark: I did not test with 1.8.0_161


      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      If a custom HostnameVerifier is set, TLS-Sessions are not reused in class sun.security.ssl.ClientHandshaker.

      1) Set http-Keep-Alive-Time from server shorter than 10 sec (or edit Thread.sleep in test-case )
      2) Edit keystore-properties and server-url in test-case
      3) Run the testcase with custom HostnameVerifier: For every request, a new TLS-Session is negotiated
      4) Remove the line for setting the Hostnameverifier: TLS-Session are reused (Log: %% Server resumed [Session-2)

      I identified the following behavior in code:

      **************************************************************************
      sun.net.www.protocol.https.HttpsClient: SSLParameter "EndpointIdentificationAlgorithm" is only set if Hostnameverifier ist javax.net.ssl.HttpsURLConnection.DefaultHostnameVerifier
      {code}
                     boolean var7 = false;
                      if(this.hv != null) {
                          String var8 = this.hv.getClass().getCanonicalName();
                          if(var8 != null && var8.equalsIgnoreCase("javax.net.ssl.HttpsURLConnection.DefaultHostnameVerifier")) {
                              var7 = true;
                          }
                      } else {
                          var7 = true;
                      }

                      if(var7) {
                          SSLParameters var12 = var1.getSSLParameters();
                          var12.setEndpointIdentificationAlgorithm("HTTPS"); // Only set if Hostnameverifier is javax.net.ssl.HttpsURLConnection.DefaultHostnameVerifier. For custom HostnameVerifier "var7" is always false
                          var1.setSSLParameters(var12);
                          var5 = false;
                      }
      {/code}

      ***************************************************************************
      sun.security.ssl.ClientHandshaker: TLS-Session is only reused, if EndpointIdentificationAlgorithm is set:

      {code}

                      if(this.session != null && !allowUnsafeServerCertChange) {
                          String var6 = this.getEndpointIdentificationAlgorithmSE(); // Set by sun.net.www.protocol.https.HttpsClient: If javax.net.ssl.HttpsURLConnection.DefaultHostnameVerifier "HTTPS", if custom HostnameVerifier: null
                          if(var6 == null || var6.length() == 0) {
                              if(var5) {
                                  if(!this.session.getUseExtendedMasterSecret()) {
                                      this.session = null;
                                  }
                              } else {
                                  this.session = null;
                              }
                          }
                      }

      {/code}




      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      TLS-Session must be reused. The following line is expected in logfile:

      %% Server resumed [Session-2, TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384]
      ACTUAL -
      Existing TLS-Session is not used and a new TLS-Handshake is performed



      REPRODUCIBILITY :
      This bug can be reproduced always.

      ---------- BEGIN SOURCE ----------
      public class TLSTester {

          public static void main(String[] args) throws Exception {
              System.setProperty("javax.net.ssl.keyStore", "clientAuthKeystore.jks");
              System.setProperty("javax.net.ssl.keyStorePassword", "12345678");
              System.setProperty("javax.net.debug", "ssl:handshake");
              //System.setProperty("http.keepAlive", "false");
              HostnameVerifier hostnameVerifier = new MyDefaultHostnameVerifier();
              HttpsURLConnection.setDefaultHostnameVerifier(hostnameVerifier); //TODO: REMOVE THIS LINE FOR TLS-SESSION-REUSAGE

              for (int i = 0; i < 100; i++) {
                  System.out.println(">>> Run " + i);

                  URL url = new URL("https://myserver.com/test");
                  HttpsURLConnection con = (HttpsURLConnection) url.openConnection();

                  System.out.println(">>> Response Code: " + con.getResponseCode());

                  byte[] data = new byte[8192];
                  InputStream is = con.getInputStream();
                  for (int len = is.read(data); len >= 0; len = is.read(data)) {
                  }
                  is.close();
                  Thread.sleep(10000);
              }

          }

          private static class MyDefaultHostnameVerifier implements HostnameVerifier {
              private MyDefaultHostnameVerifier() {
              }

              public boolean verify(String var1, SSLSession var2) {
                  return true;
              }
          }
      ---------- END SOURCE ----------

            pkoppula Prasadarao Koppula (Inactive)
            webbuggrp Webbug Group
            Votes:
            0 Vote for this issue
            Watchers:
            4 Start watching this issue

              Created:
              Updated:
              Resolved: