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

SSLException: bad_record_mac when connecting to SSLv3 only apache web server

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Cannot Reproduce
    • Icon: P3 P3
    • None
    • 7u45
    • security-libs

      FULL PRODUCT VERSION :
      Java(TM) SE Runtime Environment (build 1.7.0_45-b18)
      Java HotSpot(TM) Client VM (build 24.45-b08, mixed mode, sharing)

      ADDITIONAL OS VERSION INFORMATION :
      Microsoft Windows [Version 6.1.7601]

      A DESCRIPTION OF THE PROBLEM :
      This happens with jre 1.7.0_45.
      This *does not* happen with jre 1.7.0_05.
      This does happen with jre 1.6.0_35

      I'm using "Apache/2.2.24 (Unix) DAV/2 PHP/5.3.26 mod_ssl/2.2.24 OpenSSL/0.9.8y" on Mac OS X 10.8.5 as the webserver. My config file looks like this

      Listen 443
      <VirtualHost *:443>
          DocumentRoot /path/to/my_files/
          SSLEngine on
          SSLProtocol SSLv3
          SSLCertificateFile /path/to/test.cert
          SSLCertificateKeyFile /path/to/test.key
      </VirtualHost>

      This limits connections to be SSLv3 only. When run with jre 1.7.0_45 I get the following output:

      java HttpsConnectionExample https://192.168.0.6/
      Vendor 'Oracle Corporation' URL 'http://java.oracle.com/&#39; Version '1.7.0_45'
      javax.net.ssl.SSLException: Received fatal alert: bad_record_mac
              at sun.security.ssl.Alerts.getSSLException(Unknown Source)
              at sun.security.ssl.Alerts.getSSLException(Unknown Source)
              at sun.security.ssl.SSLSocketImpl.recvAlert(Unknown Source)
              at sun.security.ssl.SSLSocketImpl.readRecord(Unknown Source)
              at sun.security.ssl.SSLSocketImpl.performInitialHandshake(Unknown Source)
              at sun.security.ssl.SSLSocketImpl.startHandshake(Unknown Source)
              at sun.security.ssl.SSLSocketImpl.startHandshake(Unknown Source)
              at sun.net.www.protocol.https.HttpsClient.afterConnect(Unknown Source)
              at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(Unknown Source)
              at sun.net.www.protocol.http.HttpURLConnection.getInputStream(Unknown Source)
              at java.net.HttpURLConnection.getResponseCode(Unknown Source)
              at sun.net.www.protocol.https.HttpsURLConnectionImpl.getResponseCode(Unknown Source)
              at HttpsConnectionExample.main(HttpsConnectionExample.java:86)

      I get similar output from jre 1.6.0_35:

      java HttpsConnectionExample https://192.168.0.6/
      Vendor 'Sun Microsystems Inc.' URL 'http://java.sun.com/&#39; Version '1.6.0_35'
      javax.net.ssl.SSLException: Received fatal alert: bad_record_mac
              at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Unknown Source)
              at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Unknown Source)
              at com.sun.net.ssl.internal.ssl.SSLSocketImpl.recvAlert(Unknown Source)
              at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readRecord(Unknown Source)
              at com.sun.net.ssl.internal.ssl.SSLSocketImpl.performInitialHandshake(Unknown Source)
              at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(Unknown Source)
              at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(Unknown Source)
              at sun.net.www.protocol.https.HttpsClient.afterConnect(Unknown Source)
              at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(Unknown Source)
              at sun.net.www.protocol.http.HttpURLConnection.getInputStream(Unknown Source)
              at java.net.HttpURLConnection.getResponseCode(Unknown Source)
              at sun.net.www.protocol.https.HttpsURLConnectionImpl.getResponseCode(Unknown Source)
              at HttpsConnectionExample.main(HttpsConnectionExample.java:86)

      However this works with jre 1.7.0_05:

      java HttpsConnectionExample https://192.168.0.6:443/
      Vendor 'Oracle Corporation' URL 'http://java.oracle.com/&#39; Version '1.7.0_05'
      Response Code: 200

      I've taken and will try to attache wiresharks of the ssl traffic for each of the 3 jre versions I've run this against. I'm not an SSL expert, but I have noticed the version of the Client Hello seems to differ between jre versions:

      1.7.0_45 -> SSLv3.
      1.7.0_05 -> SSLv3.
      1.6.0_35 -> SSLv2.


      REGRESSION. Last worked in version 7u10

      ADDITIONAL REGRESSION INFORMATION:
      Java(TM) SE Runtime Environment (build 1.7.0_45-b18)
      Java HotSpot(TM) Client VM (build 24.45-b08, mixed mode, sharing)

      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      compile:

      javac HttpsConnectionExample.java

      run:

      java HttpsConnectionExample https://ip-of-sslv3-only-webserver/



      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      For my program to print:

      Response Code: 200
      ACTUAL -
      I get the following exception:

      javax.net.ssl.SSLException: Received fatal alert: bad_record_mac
              at sun.security.ssl.Alerts.getSSLException(Unknown Source)
              at sun.security.ssl.Alerts.getSSLException(Unknown Source)
              at sun.security.ssl.SSLSocketImpl.recvAlert(Unknown Source)
              at sun.security.ssl.SSLSocketImpl.readRecord(Unknown Source)
              at sun.security.ssl.SSLSocketImpl.performInitialHandshake(Unknown Source)
              at sun.security.ssl.SSLSocketImpl.startHandshake(Unknown Source)
              at sun.security.ssl.SSLSocketImpl.startHandshake(Unknown Source)
              at sun.net.www.protocol.https.HttpsClient.afterConnect(Unknown Source)
              at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(Unknown Source)
              at sun.net.www.protocol.http.HttpURLConnection.getInputStream(Unknown Source)
              at java.net.HttpURLConnection.getResponseCode(Unknown Source)
              at sun.net.www.protocol.https.HttpsURLConnectionImpl.getResponseCode(Unknown Source)
              at HttpsConnectionExample.main(HttpsConnectionExample.java:86)

      ERROR MESSAGES/STACK TRACES THAT OCCUR :
      javax.net.ssl.SSLException: Received fatal alert: bad_record_mac
              at sun.security.ssl.Alerts.getSSLException(Unknown Source)
              at sun.security.ssl.Alerts.getSSLException(Unknown Source)
              at sun.security.ssl.SSLSocketImpl.recvAlert(Unknown Source)
              at sun.security.ssl.SSLSocketImpl.readRecord(Unknown Source)
              at sun.security.ssl.SSLSocketImpl.performInitialHandshake(Unknown Source)
              at sun.security.ssl.SSLSocketImpl.startHandshake(Unknown Source)
              at sun.security.ssl.SSLSocketImpl.startHandshake(Unknown Source)
              at sun.net.www.protocol.https.HttpsClient.afterConnect(Unknown Source)
              at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(Unknown Source)
              at sun.net.www.protocol.http.HttpURLConnection.getInputStream(Unknown Source)
              at java.net.HttpURLConnection.getResponseCode(Unknown Source)
              at sun.net.www.protocol.https.HttpsURLConnectionImpl.getResponseCode(Unknown Source)
              at HttpsConnectionExample.main(HttpsConnectionExample.java:86)

      REPRODUCIBILITY :
      This bug can be reproduced always.

      ---------- BEGIN SOURCE ----------
      import java.net.URL;
      import java.security.SecureRandom;
      import java.security.cert.CertificateException;

      import javax.net.ssl.HostnameVerifier;
      import javax.net.ssl.HttpsURLConnection;
      import javax.net.ssl.SSLContext;
      import javax.net.ssl.SSLSession;
      import javax.net.ssl.TrustManager;
      import javax.net.ssl.X509TrustManager;

      public class HttpsConnectionExample
      {
          
          private static void trustAllCertficates()
          {
              TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {
                  public java.security.cert.X509Certificate[] getAcceptedIssuers()
                  {
                      return new java.security.cert.X509Certificate[0];
                  }

                  @Override
                  public void checkClientTrusted(java.security.cert.X509Certificate[] arg0, String arg1)
                          throws CertificateException
                  {

                  }

                  @Override
                  public void checkServerTrusted(java.security.cert.X509Certificate[] arg0, String arg1)
                          throws CertificateException
                  {

                  }
              } };

              try
              {
                  SSLContext sc = SSLContext.getInstance("SSL");
                  sc.init(null, trustAllCerts, new SecureRandom());
                  HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
              }
              catch (Exception e)
              {
                  e.printStackTrace();
              }
          }

          static void logJavaInfo()
          {

            System.out.println("Vendor '" + System.getProperty("java.vendor") + "' " + "URL '"
                      + System.getProperty("java.vendor.url") + "' " + "Version '"
                      + System.getProperty("java.version") + "'");
          }
          
          private static void disableHostNameVerification()
          {
              HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier()
              {
                  @Override
                  public boolean verify(String hostname, SSLSession session)
                  {
                      return true;
                  }
              });
              
          }
          
          public static void main(String[] args)
          {
              logJavaInfo();
              trustAllCertficates(); // Mine is self signed
              disableHostNameVerification(); // Mine is not for local host

              try
              {
                  if ( args.length > 1)
                  {
                      System.setProperty("https.protocols", "SSLv3");
                  }
                  final URL url = new URL(args[0]);
                  final HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
                  System.out.println("Response Code: " + conn.getResponseCode());
              }
              catch (Exception e)
              {
                  e.printStackTrace();
              }
          }

      }

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

      CUSTOMER SUBMITTED WORKAROUND :
      I think this could be worked around by doing:

      System.setProperty("https.protocols", "SSLv3");

      Unfortunately my program is making http requests from multiple threads, so I wouldn't want to change this globally.

      SUPPORT :
      YES

            mbankal Mala Bankal (Inactive)
            webbuggrp Webbug Group
            Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

              Created:
              Updated:
              Resolved: