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

Final CCS and Finished DTLS messages can't be re-transmitted

    XMLWordPrintable

    Details

      Description

      ADDITIONAL SYSTEM INFORMATION :
      Tested against jdk 9,14,15,17 with same result

      A DESCRIPTION OF THE PROBLEM :
      The final CCC and finished message cannot be retransmitted.
      It is an implementation bug. Every handshake message should be able to get retransmitted.

      The bug has been addressed, but not fixed by:

      "JDK-8167680 : DTLS implementation bugs" (https://bugs.java.com/bugdatabase/view_bug.do?bug_id=8167680) was implemented to address the issue of retransmitting Final CCS and Finished DTLS messages addressing "JDK-8163419 : Final CCS and Finished DTLS messages can't be re-transmitted" (https://bugs.java.com/bugdatabase/view_bug.do?bug_id=8163419)

      The implementation is now sending an extra set of CCS and Finished packets regardless if there is packet loss or not, which makes the test-case work (https://github.com/AdoptOpenJDK/openjdk-jdk/blob/master/test/jdk/javax/net/ssl/DTLS/PacketLossRetransmission.java) due to the test only dropping one packets, but it cannot recover if the extra set of CCS and Finished are also lost. In addition always sending an extra set of CCS and Finished is adding unnecessary overhead.

      Example

          Client Server
                     ....
             -- ClientKeyExchange -->
             -- ChangeCipherSpec -->
             -- Finished -->


             X <-- ChangeCipherSpec --
             X <-- Finished --
             X <-- ChangeCipherSpec --
             X <-- Finished --

      Client repeatedly sends last flight
             ----- ... --->
             -- ClientKeyExchange -->
             -- ChangeCipherSpec -->
             -- Finished -->

      Server ignores because handshake it complete

      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      A modified version of PacketLossRetransmission has been added, which takes the number of packets to drop as parameter. "Actual Result" shows the result of PacketLossRetransmission being run with scenario "drop finished packets 2 times"
      Params : -Djdk.tls.client.enableSessionTicketExtension=false server 20 2

      DTLSOverDatagram was modified (not included) to print content type and handshake types.
      Server socket timeout was increased from 10s to 20s to allow for client retransmission
      Line 565: serverSocket.setSoTimeout(SOCKET_TIMEOUT*2);

      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      After receiving the client retransmission the server sends:
      Server: ----produce handshake packet(99, OK, NEED_WRAP)----CHANGE_CIPHER_SPEC
      Server: ----produce handshake packet(98, OK, NEED_WRAP)----HANDSHAKE FINISHED
      ACTUAL -
      Server: =======handshake(199, NEED_UNWRAP)=======
      Server: Receive DTLS records, handshake status is NEED_UNWRAP
      Client: =======handshake(199, NEED_WRAP)=======
      Client: ----produce handshake packet(99, OK, NEED_UNWRAP)----HANDSHAKE CLIENT_HELLO
      Client: Produced 1 packets
      Client: =======handshake(198, NEED_UNWRAP)=======
      Client: Receive DTLS records, handshake status is NEED_UNWRAP
      Server: =======handshake(198, NEED_TASK)=======
      Server: =======handshake(197, NEED_WRAP)=======
      Server: ----produce handshake packet(99, OK, NEED_UNWRAP)----HANDSHAKE HELLO_VERIFY_REQUEST
      Server: Produced 1 packets
      Server: =======handshake(196, NEED_UNWRAP)=======
      Server: Receive DTLS records, handshake status is NEED_UNWRAP
      Client: =======handshake(197, NEED_TASK)=======
      Client: =======handshake(196, NEED_WRAP)=======
      Client: ----produce handshake packet(99, OK, NEED_UNWRAP)----HANDSHAKE CLIENT_HELLO
      Client: Produced 1 packets
      Client: =======handshake(195, NEED_UNWRAP)=======
      Client: Receive DTLS records, handshake status is NEED_UNWRAP
      Server: =======handshake(195, NEED_TASK)=======
      Server: =======handshake(194, NEED_WRAP)=======
      Server: ----produce handshake packet(99, OK, NEED_WRAP)----HANDSHAKE SERVER_HELLO
      Server: ----produce handshake packet(98, OK, NEED_WRAP)----HANDSHAKE CERTIFICATE
      Server: ----produce handshake packet(97, OK, NEED_WRAP)----HANDSHAKE SERVER_KEY_EXCHANGE
      Server: ----produce handshake packet(96, OK, NEED_UNWRAP)----HANDSHAKE SERVER_HELLO_DONE
      Server: Produced 4 packets
      Server: =======handshake(193, NEED_UNWRAP)=======
      Server: Receive DTLS records, handshake status is NEED_UNWRAP
      Client: =======handshake(194, NEED_UNWRAP)=======
      Client: Receive DTLS records, handshake status is NEED_UNWRAP
      Client: =======handshake(193, NEED_UNWRAP)=======
      Client: Receive DTLS records, handshake status is NEED_UNWRAP
      Client: =======handshake(192, NEED_UNWRAP)=======
      Client: Receive DTLS records, handshake status is NEED_UNWRAP
      Client: =======handshake(191, NEED_TASK)=======
      Client: =======handshake(190, NEED_UNWRAP_AGAIN)=======
      Client: Receive DTLS records, handshake status is NEED_UNWRAP_AGAIN
      Client: =======handshake(189, NEED_TASK)=======
      Client: =======handshake(188, NEED_UNWRAP_AGAIN)=======
      Client: Receive DTLS records, handshake status is NEED_UNWRAP_AGAIN
      Client: =======handshake(187, NEED_TASK)=======
      Client: =======handshake(186, NEED_UNWRAP_AGAIN)=======
      Client: Receive DTLS records, handshake status is NEED_UNWRAP_AGAIN
      Client: =======handshake(185, NEED_TASK)=======
      Client: =======handshake(184, NEED_WRAP)=======
      Client: ----produce handshake packet(99, OK, NEED_WRAP)----HANDSHAKE CLIENT_KEY_EXCHANGE
      Client: ----produce handshake packet(98, OK, NEED_WRAP)----CHANGE_CIPHER_SPEC
      Client: ----produce handshake packet(97, OK, NEED_UNWRAP)----HANDSHAKE FINISHED
      Client: Produced 3 packets
      Client: =======handshake(183, NEED_UNWRAP)=======
      Client: Receive DTLS records, handshake status is NEED_UNWRAP
      Server: =======handshake(192, NEED_UNWRAP)=======
      Server: Receive DTLS records, handshake status is NEED_UNWRAP
      Server: =======handshake(191, NEED_UNWRAP)=======
      Server: Receive DTLS records, handshake status is NEED_UNWRAP
      Server: =======handshake(190, NEED_TASK)=======
      Server: =======handshake(189, NEED_UNWRAP_AGAIN)=======
      Server: Receive DTLS records, handshake status is NEED_UNWRAP_AGAIN
      Server: =======handshake(188, NEED_UNWRAP_AGAIN)=======
      Server: Receive DTLS records, handshake status is NEED_UNWRAP_AGAIN
      Server: =======handshake(187, NEED_WRAP)=======
      Server: ----produce handshake packet(99, OK, NEED_WRAP)----CHANGE_CIPHER_SPEC
      Server: ----produce handshake packet(98, OK, NEED_WRAP)----HANDSHAKE FINISHED
      Server: ----produce handshake packet(97, OK, NEED_WRAP)----CHANGE_CIPHER_SPEC
      Server: ----produce handshake packet(96, OK, FINISHED)----HANDSHAKE FINISHED
      Server: Produce handshake packets: Handshake status is FINISHED, finish the loop
      Loss a packet of handshake message
      Loss a packet of handshake message
      Server: Produced 2 packets
      Server: Handshake status is FINISHED after producing handshake packets, finish the loop
      Server: Handshake finished, status is NOT_HANDSHAKING
      Client: =======handshake(182, NEED_UNWRAP)=======
      Client: Receive DTLS records, handshake status is NEED_UNWRAP
      Server: Negotiated protocol is DTLSv1.2
      Client: =======handshake(181, NEED_UNWRAP)=======
      Server: Negotiated cipher suite is TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
      Client: Receive DTLS records, handshake status is NEED_UNWRAP
      Client: Warning: java.net.SocketTimeoutException: Receive timed out
      Client: ----produce handshake packet(99, OK, NEED_WRAP)----HANDSHAKE CLIENT_KEY_EXCHANGE
      Client: ----produce handshake packet(98, OK, NEED_WRAP)----CHANGE_CIPHER_SPEC
      Client: ----produce handshake packet(97, OK, NEED_UNWRAP)----HANDSHAKE FINISHED
      Client: Reproduced 3 packets
      Reproduced packet
      Reproduced packet
      Reproduced packet
      Client: New handshake status is NEED_UNWRAP
      Client: =======handshake(180, NEED_UNWRAP)=======
      Client: Receive DTLS records, handshake status is NEED_UNWRAP
      Server: Received packet no data - Engine status is Status = OK HandshakeStatus = NOT_HANDSHAKING
      bytesConsumed = 58 bytesProduced = 0 packet type: HANDSHAKE
      Server: Received packet no data - Engine status is Status = OK HandshakeStatus = NOT_HANDSHAKING
      bytesConsumed = 14 bytesProduced = 0 packet type: CHANGE_CIPHER_SPEC
      Server: Received packet no data - Engine status is Status = OK HandshakeStatus = NOT_HANDSHAKING
      bytesConsumed = 61 bytesProduced = 0 packet type: HANDSHAKE
      Client: Warning: java.net.SocketTimeoutException: Receive timed out
      Client: ----produce handshake packet(99, OK, NEED_WRAP)----HANDSHAKE CLIENT_KEY_EXCHANGE
      Client: ----produce handshake packet(98, OK, NEED_WRAP)----CHANGE_CIPHER_SPEC
      Client: ----produce handshake packet(97, OK, NEED_UNWRAP)----HANDSHAKE FINISHED
      Client: Reproduced 3 packets
      Reproduced packet
      Reproduced packet
      Reproduced packet
      Client: New handshake status is NEED_UNWRAP
      Client: =======handshake(179, NEED_UNWRAP)=======
      Server: Received packet no data - Engine status is Status = OK HandshakeStatus = NOT_HANDSHAKING
      bytesConsumed = 58 bytesProduced = 0 packet type: HANDSHAKE
      Client: Receive DTLS records, handshake status is NEED_UNWRAP
      Server: Received packet no data - Engine status is Status = OK HandshakeStatus = NOT_HANDSHAKING
      bytesConsumed = 14 bytesProduced = 0 packet type: CHANGE_CIPHER_SPEC
      Server: Received packet no data - Engine status is Status = OK HandshakeStatus = NOT_HANDSHAKING
      bytesConsumed = 61 bytesProduced = 0 packet type: HANDSHAKE
      Client: Warning: java.net.SocketTimeoutException: Receive timed out
      Client: ----produce handshake packet(99, OK, NEED_WRAP)----HANDSHAKE CLIENT_KEY_EXCHANGE
      Client: ----produce handshake packet(98, OK, NEED_WRAP)----CHANGE_CIPHER_SPEC
      Client: ----produce handshake packet(97, OK, NEED_UNWRAP)----HANDSHAKE FINISHED
      Client: Reproduced 3 packets
      Reproduced packet
      Reproduced packet
      Reproduced packet
      Client: New handshake status is NEED_UNWRAP
      Server: Received packet no data - Engine status is Status = OK HandshakeStatus = NOT_HANDSHAKING
      bytesConsumed = 58 bytesProduced = 0 packet type: HANDSHAKE
      Client: =======handshake(178, NEED_UNWRAP)=======
      Client: Receive DTLS records, handshake status is NEED_UNWRAP
      Server: Received packet no data - Engine status is Status = OK HandshakeStatus = NOT_HANDSHAKING
      bytesConsumed = 14 bytesProduced = 0 packet type: CHANGE_CIPHER_SPEC
      Server: Received packet no data - Engine status is Status = OK HandshakeStatus = NOT_HANDSHAKING
      bytesConsumed = 61 bytesProduced = 0 packet type: HANDSHAKE


      ---------- BEGIN SOURCE ----------
      public class PacketLossRetransmission extends DTLSOverDatagram {
          private static boolean isClient;
          private static byte handshakeType;

          private static int packetsToDrop;

          public static void main(String[] args) throws Exception {
              isClient = args[0].equals("client");
              handshakeType = Byte.valueOf(args[1]);
              packetsToDrop = Integer.parseInt(args[2]);

              PacketLossRetransmission testCase = new PacketLossRetransmission();
              testCase.runTest(testCase);
          }

          @Override
          boolean produceHandshakePackets(SSLEngine engine, SocketAddress socketAddr,
                                          String side, List<DatagramPacket> packets) throws Exception {

              boolean finished = super.produceHandshakePackets(
                      engine, socketAddr, side, packets);

              Iterator<DatagramPacket> packetIterator = packets.iterator();
              while (packetIterator.hasNext()) {
                  DatagramPacket packet = packetIterator.next();
                  if ((packetsToDrop > 0) && (!(isClient ^ engine.getUseClientMode()))) {
                      packet = getPacket(Collections.singletonList(packet), handshakeType);
                      if (packet != null) {
                          packetsToDrop--;
                          System.out.println("Loss a packet of handshake message ");
                          packetIterator.remove();
                      }
                  }
              }

              return finished;
          }
      }
      ---------- END SOURCE ----------

      FREQUENCY : always


        Attachments

          Issue Links

            Activity

              People

              Assignee:
              xuelei Xue-Lei Fan
              Reporter:
              webbuggrp Webbug Group
              Votes:
              0 Vote for this issue
              Watchers:
              2 Start watching this issue

                Dates

                Created:
                Updated: