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

Don't wrap SocketExceptions into SSLExceptions in SSLSocketImpl

XMLWordPrintable

    • behavioral
    • minimal
    • Hide
      The is no compatibility risk for JDK 8 because this change only restores the original behaviour before the downport of TLS 1.3.

      For JDK 11 and later the compatibility risk should be minimal and can only potentially impact applications which were specifically developed against JDK 11 and later. We think that there are much more applications out there which expect the original JDK 8 behaviour and that compatibility with JDK 8 outweighs potential problems with new applications.
      Show
      The is no compatibility risk for JDK 8 because this change only restores the original behaviour before the downport of TLS 1.3. For JDK 11 and later the compatibility risk should be minimal and can only potentially impact applications which were specifically developed against JDK 11 and later. We think that there are much more applications out there which expect the original JDK 8 behaviour and that compatibility with JDK 8 outweighs potential problems with new applications.
    • Other
    • Implementation

      Summary

      Change the behavior of the TLS stack to pass through SocketException instead of wrapping it into an SSLException.

      Problem

      OpenJDK 8 (up to 8u265 for OpenJDK and 8u251 for Oracle JDK), 9 and 10 imposed the following contract between the sun.security.ssl.SSLSocketImpl class and its clients (see SSLSocketImpl.java#l69):

           * ERROR HANDLING GUIDELINES
           * (which exceptions to throw and catch and which not to throw and catch)
           *
           * . if there is an IOException (SocketException) when accessing the     
           *   underlying Socket, pass it through     
           *     
           * . do not throw IOExceptions, throw SSLExceptions (or a subclass)     

      The TLS stack would pass through SocketExceptions unchanged but would wrap other IOExceptions into SSLExceptions.

      However, this contract was changed without notice in OpenJDK 11 by the new TLS1.3 stack JDK-8196584. The new implementation now started wrapping all IOExceptions including SocketExceptions into SSLExceptions.

      The error handling guidelines present in the OpenJDK implementations before 11 were used by the application layer to determine how to react to the exception. The application layer (e.g the popular Apache HTTPClient library) would consider SocketExceptions to be retry-able and retry the request. Starting with JDK 11, such applications started seeing unhandled "SSLException: Broken Pipe" exceptions because now SocketExceptions were converted to SSLExceptions. Apache HTTPClient for example reported this as "HTTPCLIENT-2032: Sometimes get a broken pipe error in Java 11..".

      The general problem with the new implementation is that application are now unable to determine if a failure was due to a retry-able SocketException or a more permanent SSLException. The blast radius of this behavioural change became a lot wider after the new TLS 1.3 stack was downported to jdk 8.

      "JDK-8214339: SSLSocketImpl erroneously wraps SocketException" attempted to fix this issue, however, it was still wrapping SocketExceptions and passing them to the application layer as SSLExceptions. Consequently, the new issue "JDK-8237578: JDK-8214339 (SSLSocketImpl wraps SocketException)" appears to not be fully fixed" was raised which was finally fixed for jdk 17 but unfortunately had to be backed out immediately because it had missed to update some tests. During the backout discussion the initial reviewers came to the conclusion that a CSR should have been raised for JDK-8237578. Finally, this CSR has been created for JDK-8259662 which is the redo of JDK-8237578.

      Solution

      • Change the implementation of SSLSocketImpl in the new TLS 1.3 stack back to the old error handling protocol defined in JDK 8 (see PR-2057).
      • Add a comment back to SSLSocketImpl class which documents this behaviour:
          /*
           * ERROR HANDLING GUIDELINES
           * (which exceptions to throw and catch and which not to throw and catch)
           *
           * - if there is an IOException (SocketException) when accessing the     
           *   underlying Socket, pass it through     
           *     
           * - do not throw IOExceptions, throw SSLExceptions (or a subclass)
           */

      Specification

      No specification change.

            cverghese Clive Verghese
            cverghese Clive Verghese
            Volker Simonis, Xuelei Fan
            Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

              Created:
              Updated:
              Resolved: