Relates :
|
|
Relates :
|
|
Relates :
|
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
|