src/java.base/share/classes/sun/security/ssl/OutputRecord.java

Print this page
8167680 DTLS implementation bugs

@@ -1,7 +1,7 @@
 /*
- * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License version 2 only, as
  * published by the Free Software Foundation.  Oracle designates this

@@ -192,10 +192,15 @@
     // apply to DTLS SSLEngine
     void initHandshaker() {
         // blank
     }
 
+    // apply to DTLS SSLEngine
+    void launchRetransmission() {
+        // blank
+    }
+
     @Override
     public synchronized void close() throws IOException {
         if (!isClosed) {
             isClosed = true;
             writeCipher.dispose();

@@ -222,10 +227,13 @@
         // Acquire the current sequence number before using.
         if (isDTLS) {
             sequenceNumber = authenticator.sequenceNumber();
         }
 
+        // The sequence number may be shared for different purpose. 
+        boolean sharedSequenceNumber = false;
+
         // "flip" but skip over header again, add MAC & encrypt
         if (authenticator instanceof MAC) {
             MAC signer = (MAC)authenticator;
             if (signer.MAClen() != 0) {
                 byte[] hash = signer.compute(contentType, destination, false);

@@ -241,12 +249,17 @@
                 destination.put(hash);
 
                 // reset the position and limit
                 destination.limit(destination.position());
                 destination.position(dstContent);
+
+                // The signer has used and increased the sequence number.
+                if (isDTLS) {
+                    sharedSequenceNumber = true;
             }
         }
+        }
 
         if (!encCipher.isNullCipher()) {
             if (protocolVersion.useTLS11PlusSpec() &&
                     (encCipher.isCBCMode() || encCipher.isAEADMode())) {
                 byte[] nonce = encCipher.createExplicitNonce(

@@ -259,10 +272,15 @@
                 destination.position(headerOffset + headerSize);
             }   // Otherwise, DON'T encrypt the nonce_explicit for AEAD mode
 
             // Encrypt may pad, so again the limit may be changed.
             encCipher.encrypt(destination, dstLim);
+
+            // The cipher has used and increased the sequence number.
+            if (isDTLS && encCipher.isAEADMode()) {
+                sharedSequenceNumber = true;
+            }
         } else {
             destination.position(destination.limit());
         }
 
         // Finish out the record header.

@@ -288,13 +306,15 @@
 
             // fragment length
             destination.put(headerOffset + 11, (byte)(fragLen >> 8));
             destination.put(headerOffset + 12, (byte)fragLen);
 
-            // Increase the sequence number for next use.
+            // Increase the sequence number for next use if it is not shared.
+            if (!sharedSequenceNumber) {
             authenticator.increaseSequenceNumber();
         }
+        }
 
         // Update destination position to reflect the amount of data produced.
         destination.position(destination.limit());
 
         return Authenticator.toLong(sequenceNumber);