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

Possible race condition in TLS 1.3 session resumption

    Details

    • Subcomponent:
    • Resolved In Build:
      b21
    • Verification:
      Not verified

      Backports

        Description

        A DESCRIPTION OF THE PROBLEM :
        Making multiple concurrent TLS 1.3 connections sometimes throws exception "No PSK available. Unable to resume.". I've encountered this when using Maven with TLS 1.3 enable server. Maven is making multiple HTTPS requests and very often it fails.

        I was able to reproduce this by making calls to Facebook, Cloudflare and personal servers running nginx and haproxy with OpenSSL 1.1.1. At least Facebook uses its own TLS 1.3 implementation so this seems like Java bug.

        STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
        Please use attached program. Do note that this seems to be a race condition. As such the problem occurs randomly, sometimes it works, sometimes not. On Linux, adding 100ms of delay to all packet on test machine seems to help reproduce the problem (i.e. tc qdisc add dev eth0 root netem delay 100ms). Or just choose some TLS 1.3 server with high ping instead of www.cloudflare.com from test program.


        EXPECTED VERSUS ACTUAL BEHAVIOR :
        EXPECTED -
        No Exception is thrown.
        ACTUAL -
        Following Exception occurs:

        javax.net.ssl.SSLException: No PSK available. Unable to resume.
        at java.base/sun.security.ssl.Alert.createSSLException(Alert.java:129)
        at java.base/sun.security.ssl.Alert.createSSLException(Alert.java:117)
        at java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:308)
        at java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:264)
        at java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:255)
        at java.base/sun.security.ssl.ServerHello$T13ServerHelloConsumer.consume(ServerHello.java:1224)
        at java.base/sun.security.ssl.ServerHello$ServerHelloConsumer.onServerHello(ServerHello.java:984)
        at java.base/sun.security.ssl.ServerHello$ServerHelloConsumer.consume(ServerHello.java:872)
        at java.base/sun.security.ssl.SSLHandshake.consume(SSLHandshake.java:392)
        at java.base/sun.security.ssl.HandshakeContext.dispatch(HandshakeContext.java:444)
        at java.base/sun.security.ssl.HandshakeContext.dispatch(HandshakeContext.java:421)
        at java.base/sun.security.ssl.TransportContext.dispatch(TransportContext.java:178)
        at java.base/sun.security.ssl.SSLTransport.decode(SSLTransport.java:164)
        at java.base/sun.security.ssl.SSLSocketImpl.decode(SSLSocketImpl.java:1152)
        at java.base/sun.security.ssl.SSLSocketImpl.readHandshakeRecord(SSLSocketImpl.java:1063)
        at java.base/sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:402)
        at java.base/sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:567)
        at java.base/sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:185)
        at java.base/sun.net.www.protocol.https.HttpsURLConnectionImpl.connect(HttpsURLConnectionImpl.java:163)
        at btest.NetHttp.get(NetHttp.java:12)
        at btest.NetHttp.lambda$0(NetHttp.java:30)
        at java.base/java.lang.Thread.run(Thread.java:834)

        ---------- BEGIN SOURCE ----------
        package btest;

        import java.io.InputStreamReader;
        import java.net.URL;

        public class NetHttp {

            private static void get(String u) {
                try {
                    var url = new URL(u);
                    var conn = url.openConnection();
                    conn.connect();
                    try (var in = conn.getInputStream(); var in2 = new InputStreamReader(in)) {
                        var buf = new char[100];
                        while(true) {
                            int read = in2.read(buf);
                            if(read < 100) break;
                        }
                        System.out.println("ok");
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }

            public static void main(String[] args) throws Exception {
                get("https://www.google.com"); // get the crypto stuff initialized, seems to increase changes of the problem appearing
                for (var i = 1; i <= 20; i++) {
                    var t = new Thread(() -> {
                        get("https://www.cloudflare.com");
                    });
                    t.start();
                    Thread.sleep(50);
                }
            }

        }

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

        CUSTOMER SUBMITTED WORKAROUND :
        Disabling TLS 1.3 completely with -Dhttps.protocols=TLSv1,TLSv1.1,TLSv1.2

        FREQUENCY : often


          Attachments

          1. HttpsConnectionTest.java
            4 kB
          2. JI9057881.java
            0.9 kB
          3. test.cer
            1 kB
          4. test.key
            2 kB

            Issue Links

              Activity

                People

                • Assignee:
                  apetcher Adam Petcher (Inactive)
                  Reporter:
                  webbuggrp Webbug Group
                • Votes:
                  0 Vote for this issue
                  Watchers:
                  12 Start watching this issue

                  Dates

                  • Created:
                    Updated:
                    Resolved: