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

Possible race condition in TLS 1.3 session resumption

    XMLWordPrintable

Details

    • b21
    • 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
            John Jiang
          2. JI9057881.java
            0.9 kB
            Pallavi Sonal
          3. test.cer
            1 kB
            John Jiang
          4. test.key
            2 kB
            John Jiang

          Issue Links

            Activity

              People

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

                Dates

                  Created:
                  Updated:
                  Resolved: