test/javax/net/ssl/DTLS/DTLSOverDatagram.java
Print this page
8167680 DTLS implementation bugs
@@ -46,14 +46,10 @@
/**
* An example to show the way to use SSLEngine in datagram connections.
*/
public class DTLSOverDatagram {
- static {
- System.setProperty("javax.net.debug", "ssl");
- }
-
private static int MAX_HANDSHAKE_LOOPS = 200;
private static int MAX_APP_READ_LOOPS = 60;
private static int SOCKET_TIMEOUT = 10 * 1000; // in millis
private static int BUFFER_SIZE = 1024;
private static int MAXIMUM_PACKET_SIZE = 1024;
@@ -158,10 +154,11 @@
throw new RuntimeException(
"Too much loops to produce handshake packets");
}
SSLEngineResult.HandshakeStatus hs = engine.getHandshakeStatus();
+ log(side, "=======handshake(" + loops + ", " + hs + ")=======");
if (hs == SSLEngineResult.HandshakeStatus.NEED_UNWRAP ||
hs == SSLEngineResult.HandshakeStatus.NEED_UNWRAP_AGAIN) {
log(side, "Receive DTLS records, handshake status is " + hs);
@@ -237,10 +234,11 @@
} else if (hs == SSLEngineResult.HandshakeStatus.NEED_WRAP) {
List<DatagramPacket> packets = new ArrayList<>();
boolean finished = produceHandshakePackets(
engine, peerAddr, side, packets);
+ log(side, "Produced " + packets.size() + " packets");
for (DatagramPacket p : packets) {
socket.send(p);
}
if (finished) {
@@ -250,18 +248,20 @@
endLoops = true;
}
} else if (hs == SSLEngineResult.HandshakeStatus.NEED_TASK) {
runDelegatedTasks(engine);
} else if (hs == SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING) {
- log(side, "Handshake status is NOT_HANDSHAKING, finish the loop");
+ log(side,
+ "Handshake status is NOT_HANDSHAKING, finish the loop");
endLoops = true;
} else if (hs == SSLEngineResult.HandshakeStatus.FINISHED) {
throw new Exception(
"Unexpected status, SSLEngine.getHandshakeStatus() "
+ "shouldn't return FINISHED");
} else {
- throw new Exception("Can't reach here, handshake status is " + hs);
+ throw new Exception(
+ "Can't reach here, handshake status is " + hs);
}
}
SSLEngineResult.HandshakeStatus hs = engine.getHandshakeStatus();
log(side, "Handshake finished, status is " + hs);
@@ -277,11 +277,13 @@
}
log(side, "Negotiated protocol is " + session.getProtocol());
log(side, "Negotiated cipher suite is " + session.getCipherSuite());
// handshake status should be NOT_HANDSHAKING
- // according to the spec, SSLEngine.getHandshakeStatus() can't return FINISHED
+ //
+ // According to the spec, SSLEngine.getHandshakeStatus() can't
+ // return FINISHED.
if (hs != SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING) {
throw new Exception("Unexpected handshake status " + hs);
}
}
@@ -346,17 +348,20 @@
SSLEngineResult r = engine.wrap(oApp, oNet);
oNet.flip();
SSLEngineResult.Status rs = r.getStatus();
SSLEngineResult.HandshakeStatus hs = r.getHandshakeStatus();
+ log(side, "====packet(" + loops + ", " + rs + ", " + hs + ")====");
if (rs == SSLEngineResult.Status.BUFFER_OVERFLOW) {
// the client maximum fragment size config does not work?
throw new Exception("Buffer overflow: " +
"incorrect server maximum fragment size");
} else if (rs == SSLEngineResult.Status.BUFFER_UNDERFLOW) {
- log(side, "Produce handshake packets: BUFFER_UNDERFLOW occured");
- log(side, "Produce handshake packets: Handshake status: " + hs);
+ log(side,
+ "Produce handshake packets: BUFFER_UNDERFLOW occured");
+ log(side,
+ "Produce handshake packets: Handshake status: " + hs);
// bad packet, or the client maximum fragment size
// config does not work?
if (hs != SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING) {
throw new Exception("Buffer underflow: " +
"incorrect server maximum fragment size");
@@ -451,10 +456,57 @@
}
return packets;
}
+ // Get a datagram packet for the specified handshake type.
+ static DatagramPacket getPacket(
+ List<DatagramPacket> packets, byte handshakeType) {
+ boolean matched = false;
+ for (DatagramPacket packet : packets) {
+ byte[] data = packet.getData();
+ int offset = packet.getOffset();
+ int length = packet.getLength();
+
+ // Normally, this pakcet should be a handshake message
+ // record. However, even if the underlying platform
+ // splits the record more, we don't really worry about
+ // the improper packet loss because DTLS implementation
+ // should be able to handle packet loss properly.
+ //
+ // See RFC 6347 for the detailed format of DTLS records.
+ if (handshakeType == -1) { // ChangeCipherSpec
+ // Is it a ChangeCipherSpec message?
+ matched = (length == 14) && (data[offset] == 0x14);
+ } else if ((length >= 25) && // 25: handshake mini size
+ (data[offset] == 0x16)) { // a handshake message
+
+ // check epoch number for initial handshake only
+ if (data[offset + 3] == 0x00) { // 3,4: epoch
+ if (data[offset + 4] == 0x00) { // plaintext
+ matched =
+ (data[offset + 13] == handshakeType);
+ } else { // cipherext
+ // The 1st ciphertext is a Finished message.
+ //
+ // If it is not proposed to loss the Finished
+ // message, it is not necessary to check the
+ // following packets any mroe as a Finished
+ // message is the last handshake message.
+ matched = (handshakeType == 20);
+ }
+ }
+ }
+
+ if (matched) {
+ return packet;
+ }
+ }
+
+ return null;
+ }
+
// run delegated tasks
void runDelegatedTasks(SSLEngine engine) throws Exception {
Runnable runnable;
while ((runnable = engine.getDelegatedTask()) != null) {
runnable.run();