< prev index next >

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

Print this page

        

@@ -1,7 +1,7 @@
 /*
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2018, 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

@@ -16,68 +16,46 @@
  *
  * You should have received a copy of the GNU General Public License version
  * 2 along with this work; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 9406+5 USA
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
 
 package sun.security.ssl;
 
 import java.io.*;
 import java.nio.*;
+import java.security.GeneralSecurityException;
 import java.util.*;
 import javax.crypto.BadPaddingException;
-
 import javax.net.ssl.*;
-
-import sun.security.util.HexDumpEncoder;
-import static sun.security.ssl.HandshakeMessage.*;
+import sun.security.ssl.SSLCipher.SSLReadCipher;
 
 /**
  * DTLS {@code InputRecord} implementation for {@code SSLEngine}.
  */
 final class DTLSInputRecord extends InputRecord implements DTLSRecord {
-
     private DTLSReassembler reassembler = null;
+    private int             readEpoch;
 
-    int                 readEpoch;
-
-    int                 prevReadEpoch;
-    Authenticator       prevReadAuthenticator;
-    CipherBox           prevReadCipher;
-
-    DTLSInputRecord() {
+    DTLSInputRecord(HandshakeHash handshakeHash) {
+        super(handshakeHash, SSLReadCipher.nullDTlsReadCipher());
         this.readEpoch = 0;
-        this.readAuthenticator = new MAC(true);
-
-        this.prevReadEpoch = 0;
-        this.prevReadCipher = CipherBox.NULL;
-        this.prevReadAuthenticator = new MAC(true);
     }
 
     @Override
-    void changeReadCiphers(Authenticator readAuthenticator,
-            CipherBox readCipher) {
-
-        prevReadCipher.dispose();
-
-        this.prevReadAuthenticator = this.readAuthenticator;
-        this.prevReadCipher = this.readCipher;
-        this.prevReadEpoch = this.readEpoch;
-
-        this.readAuthenticator = readAuthenticator;
+    void changeReadCiphers(SSLReadCipher readCipher) {
         this.readCipher = readCipher;
         this.readEpoch++;
     }
 
     @Override
     public synchronized void close() throws IOException {
         if (!isClosed) {
-            prevReadCipher.dispose();
             super.close();
         }
     }
 
     @Override

@@ -85,18 +63,12 @@
         return ((reassembler == null) || reassembler.isEmpty());
     }
 
     @Override
     int estimateFragmentSize(int packetSize) {
-        int macLen = 0;
-        if (readAuthenticator instanceof MAC) {
-            macLen = ((MAC)readAuthenticator).MAClen();
-        }
-
         if (packetSize > 0) {
-            return readCipher.estimateFragmentSize(
-                    packetSize, macLen, headerSize);
+            return readCipher.estimateFragmentSize(packetSize, headerSize);
         } else {
             return Record.maxDataSize;
         }
     }
 

@@ -106,28 +78,45 @@
             reassembler.expectingFinishFlight();
         }
     }
 
     @Override
+    void finishHandshake() {
+        reassembler = null;
+    }
+
+    @Override
     Plaintext acquirePlaintext() {
         if (reassembler != null) {
             return reassembler.acquirePlaintext();
         }
 
         return null;
     }
 
     @Override
-    Plaintext decode(ByteBuffer packet) {
+    Plaintext[] decode(ByteBuffer[] srcs, int srcsOffset,
+            int srcsLength) throws IOException, BadPaddingException {
+        if (srcs == null || srcs.length == 0 || srcsLength == 0) {
+            Plaintext pt = acquirePlaintext();
+            return pt == null ? new Plaintext[0] : new Plaintext[] { pt };
+        } else if (srcsLength == 1) {
+            return decode(srcs[srcsOffset]);
+        } else {
+            ByteBuffer packet = extract(srcs,
+                    srcsOffset, srcsLength, DTLSRecord.headerSize);
+            return decode(packet);
+        }
+    }
 
+    Plaintext[] decode(ByteBuffer packet) {
         if (isClosed) {
             return null;
         }
 
-        if (debug != null && Debug.isOn("packet")) {
-             Debug.printHex(
-                    "[Raw read]: length = " + packet.remaining(), packet);
+        if (SSLLogger.isOn && SSLLogger.isOn("packet")) {
+            SSLLogger.fine("Raw read", packet);
         }
 
         // The caller should have validated the record.
         int srcPos = packet.position();
         int srcLim = packet.limit();

@@ -147,128 +136,116 @@
                            (recordEnS[7] & 0xFFL);         // pos: 5-10
 
         int contentLen = ((packet.get() & 0xFF) << 8) |
                           (packet.get() & 0xFF);           // pos: 11, 12
 
-        if (debug != null && Debug.isOn("record")) {
-            Debug.log("READ: " +
-                    ProtocolVersion.valueOf(majorVersion, minorVersion) +
-                    " " + Record.contentName(contentType) + ", length = " +
+        if (SSLLogger.isOn && SSLLogger.isOn("record")) {
+            SSLLogger.fine("READ: " +
+                    ProtocolVersion.nameOf(majorVersion, minorVersion) +
+                    " " + ContentType.nameOf(contentType) + ", length = " +
                     contentLen);
         }
 
         int recLim = srcPos + DTLSRecord.headerSize + contentLen;
 
-        if (this.prevReadEpoch > recordEpoch) {
+        if (this.readEpoch > recordEpoch) {
             // Reset the position of the packet buffer.
             packet.position(recLim);
-            if (debug != null && Debug.isOn("record")) {
-                Debug.printHex("READ: discard this old record", recordEnS);
+            if (SSLLogger.isOn && SSLLogger.isOn("record")) {
+                SSLLogger.fine("READ: discard this old record", recordEnS);
             }
             return null;
         }
 
         // Buffer next epoch message if necessary.
         if (this.readEpoch < recordEpoch) {
             // Discard the record younger than the current epcoh if:
             // 1. it is not a handshake message, or
-            // 2. it is not of next epoch.
-            if (((contentType != Record.ct_handshake) &&
-                    (contentType != Record.ct_change_cipher_spec)) ||
+            // 3. it is not of next epoch.
+            if ((contentType != ContentType.HANDSHAKE.id &&
+                    contentType != ContentType.CHANGE_CIPHER_SPEC.id) ||
+                (reassembler == null &&
+                    contentType != ContentType.HANDSHAKE.id) ||
                 (this.readEpoch < (recordEpoch - 1))) {
 
                 packet.position(recLim);
 
-                if (debug != null && Debug.isOn("verbose")) {
-                    Debug.log("Premature record (epoch), discard it.");
+                if (SSLLogger.isOn && SSLLogger.isOn("verbose")) {
+                    SSLLogger.fine("Premature record (epoch), discard it.");
                 }
 
                 return null;
             }
 
+
             // Not ready to decrypt this record, may be an encrypted Finished
             // message, need to buffer it.
             byte[] fragment = new byte[contentLen];
             packet.get(fragment);              // copy the fragment
             RecordFragment buffered = new RecordFragment(fragment, contentType,
                     majorVersion, minorVersion,
                     recordEnS, recordEpoch, recordSeq, true);
 
+            if (reassembler == null) {
+                reassembler = new DTLSReassembler(recordEpoch);
+            }
             reassembler.queueUpFragment(buffered);
 
             // consume the full record in the packet buffer.
             packet.position(recLim);
 
-            return reassembler.acquirePlaintext();
+            Plaintext pt = reassembler.acquirePlaintext();
+            return pt == null ? null : new Plaintext[] { pt };
         }
 
         //
-        // Now, the message is of this epoch or the previous epoch.
+        // Now, the message is of this epoch.
         //
-        Authenticator decodeAuthenticator;
-        CipherBox decodeCipher;
-        if (this.readEpoch == recordEpoch) {
-            decodeAuthenticator = readAuthenticator;
-            decodeCipher = readCipher;
-        } else {                        // prevReadEpoch == recordEpoch
-            decodeAuthenticator = prevReadAuthenticator;
-            decodeCipher = prevReadCipher;
-        }
-
         // decrypt the fragment
         packet.limit(recLim);
         packet.position(srcPos + DTLSRecord.headerSize);
 
         ByteBuffer plaintextFragment;
         try {
-            plaintextFragment = decrypt(decodeAuthenticator,
-                    decodeCipher, contentType, packet, recordEnS);
-        } catch (BadPaddingException bpe) {
-            if (debug != null && Debug.isOn("ssl")) {
-                Debug.log("Discard invalid record: " + bpe);
+            Plaintext plaintext =
+                    readCipher.decrypt(contentType, packet, recordEnS);
+            plaintextFragment = plaintext.fragment;
+            contentType = plaintext.contentType;
+        } catch (GeneralSecurityException gse) {
+            if (SSLLogger.isOn && SSLLogger.isOn("ssl")) {
+                SSLLogger.fine("Discard invalid record: " + gse);
             }
 
             // invalid, discard this record [section 4.1.2.7, RFC 6347]
             return null;
         } finally {
             // comsume a complete record
             packet.limit(srcLim);
             packet.position(recLim);
         }
 
-        if (contentType != Record.ct_change_cipher_spec &&
-            contentType != Record.ct_handshake) {   // app data or alert
+        if (contentType != ContentType.CHANGE_CIPHER_SPEC.id &&
+            contentType != ContentType.HANDSHAKE.id) {   // app data or alert
                                                     // no retransmission
             // Cleanup the handshake reassembler if necessary.
             if ((reassembler != null) &&
                     (reassembler.handshakeEpoch < recordEpoch)) {
-                if (debug != null && Debug.isOn("verbose")) {
-                    Debug.log("Cleanup the handshake reassembler");
+                if (SSLLogger.isOn && SSLLogger.isOn("verbose")) {
+                    SSLLogger.fine("Cleanup the handshake reassembler");
                 }
 
                 reassembler = null;
             }
 
-            return new Plaintext(contentType, majorVersion, minorVersion,
+            return new Plaintext[] {
+                    new Plaintext(contentType, majorVersion, minorVersion,
                     recordEpoch, Authenticator.toLong(recordEnS),
-                    plaintextFragment);
+                            plaintextFragment)};
         }
 
-        if (contentType == Record.ct_change_cipher_spec) {
+        if (contentType == ContentType.CHANGE_CIPHER_SPEC.id) {
             if (reassembler == null) {
-                if (this.readEpoch != recordEpoch) {
-                    // handshake has not started, should be an
-                    // old handshake message, discard it.
-
-                    if (debug != null && Debug.isOn("verbose")) {
-                        Debug.log(
-                                "Lagging behind ChangeCipherSpec, discard it.");
-                    }
-
-                    return null;
-                }
-
                 reassembler = new DTLSReassembler(recordEpoch);
             }
 
             reassembler.queueUpChangeCipherSpec(
                     new RecordFragment(plaintextFragment, contentType,

@@ -282,52 +259,48 @@
                     contentType, majorVersion, minorVersion,
                     recordEnS, recordEpoch, recordSeq, plaintextFragment);
 
                 if (hsFrag == null) {
                     // invalid, discard this record
-                    if (debug != null && Debug.isOn("verbose")) {
-                        Debug.log("Invalid handshake message, discard it.");
+                    if (SSLLogger.isOn && SSLLogger.isOn("verbose")) {
+                        SSLLogger.fine(
+                                "Invalid handshake message, discard it.");
                     }
 
                     return null;
                 }
 
                 if (reassembler == null) {
-                    if (this.readEpoch != recordEpoch) {
-                        // handshake has not started, should be an
-                        // old handshake message, discard it.
-
-                        if (debug != null && Debug.isOn("verbose")) {
-                            Debug.log(
-                                "Lagging behind handshake record, discard it.");
-                        }
-
-                        return null;
-                    }
-
                     reassembler = new DTLSReassembler(recordEpoch);
                 }
 
                 reassembler.queueUpHandshake(hsFrag);
             }
         }
 
         // Completed the read of the full record.  Acquire the reassembled
         // messages.
         if (reassembler != null) {
-            return reassembler.acquirePlaintext();
+            Plaintext pt = reassembler.acquirePlaintext();
+            return pt == null ? null : new Plaintext[] { pt };
         }
 
-        if (debug != null && Debug.isOn("verbose")) {
-            Debug.log("The reassembler is not initialized yet.");
+        if (SSLLogger.isOn && SSLLogger.isOn("verbose")) {
+             SSLLogger.fine("The reassembler is not initialized yet.");
         }
 
         return null;
     }
 
     @Override
-    int bytesInCompletePacket(ByteBuffer packet) throws SSLException {
+    int bytesInCompletePacket(
+        ByteBuffer[] srcs, int srcsOffset, int srcsLength) throws IOException {
+
+        return bytesInCompletePacket(srcs[srcsOffset]);
+    }
+
+    private int bytesInCompletePacket(ByteBuffer packet) throws SSLException {
 
         // DTLS length field is in bytes 11/12
         if (packet.remaining() < headerSize) {
             return -1;
         }

@@ -335,19 +308,24 @@
         // Last sanity check that it's not a wild record
         int pos = packet.position();
 
         // Check the content type of the record.
         byte contentType = packet.get(pos);
-        if (!Record.isValidContentType(contentType)) {
+        if (ContentType.valueOf(contentType) == null) {
             throw new SSLException(
                     "Unrecognized SSL message, plaintext connection?");
         }
 
         // Check the protocol version of the record.
-        ProtocolVersion recordVersion =
-            ProtocolVersion.valueOf(packet.get(pos + 1), packet.get(pos + 2));
-        checkRecordVersion(recordVersion, false);
+        byte majorVersion = packet.get(pos + 1);
+        byte minorVersion = packet.get(pos + 2);
+        if (!ProtocolVersion.isNegotiable(
+                majorVersion, minorVersion, true, false)) {
+            throw new SSLException("Unrecognized record version " +
+                    ProtocolVersion.nameOf(majorVersion, minorVersion) +
+                    " , plaintext connection?");
+        }
 
         // Get the fragment length of the record.
         int fragLen = ((packet.get(pos + 11) & 0xFF) << 8) +
                        (packet.get(pos + 12) & 0xFF) + headerSize;
         if (fragLen > Record.maxFragmentSize) {

@@ -357,30 +335,19 @@
         }
 
         return fragLen;
     }
 
-    @Override
-    void checkRecordVersion(ProtocolVersion recordVersion,
-            boolean allowSSL20Hello) throws SSLException {
-
-        if (!recordVersion.maybeDTLSProtocol()) {
-            throw new SSLException(
-                    "Unrecognized record version " + recordVersion +
-                    " , plaintext connection?");
-        }
-    }
-
     private static HandshakeFragment parseHandshakeMessage(
             byte contentType, byte majorVersion, byte minorVersion,
             byte[] recordEnS, int recordEpoch, long recordSeq,
             ByteBuffer plaintextFragment) {
 
         int remaining = plaintextFragment.remaining();
         if (remaining < handshakeHeaderSize) {
-            if (debug != null && Debug.isOn("ssl")) {
-                Debug.log("Discard invalid record: " +
+            if (SSLLogger.isOn && SSLLogger.isOn("ssl")) {
+                SSLLogger.fine("Discard invalid record: " +
                         "too small record to hold a handshake fragment");
             }
 
             // invalid, discard this record [section 4.1.2.7, RFC 6347]
             return null;

@@ -401,12 +368,12 @@
         int fragmentLength =
                 ((plaintextFragment.get() & 0xFF) << 16) |
                 ((plaintextFragment.get() & 0xFF) << 8) |
                  (plaintextFragment.get() & 0xFF);          // pos: 9-11
         if ((remaining - handshakeHeaderSize) < fragmentLength) {
-            if (debug != null && Debug.isOn("ssl")) {
-                Debug.log("Discard invalid record: " +
+            if (SSLLogger.isOn && SSLLogger.isOn("ssl")) {
+                SSLLogger.fine("Discard invalid record: " +
                         "not a complete handshake fragment in the record");
             }
 
             // invalid, discard this record [section 4.1.2.7, RFC 6347]
             return null;

@@ -459,24 +426,24 @@
                                             // the buffer if necessary.
         }
 
         @Override
         public int compareTo(RecordFragment o) {
-            if (this.contentType == Record.ct_change_cipher_spec) {
-                if (o.contentType == Record.ct_change_cipher_spec) {
+            if (this.contentType == ContentType.CHANGE_CIPHER_SPEC.id) {
+                if (o.contentType == ContentType.CHANGE_CIPHER_SPEC.id) {
                     // Only one incoming ChangeCipherSpec message for an epoch.
                     //
                     // Ignore duplicated ChangeCipherSpec messages.
                     return Integer.compare(this.recordEpoch, o.recordEpoch);
                 } else if ((this.recordEpoch == o.recordEpoch) &&
-                        (o.contentType == Record.ct_handshake)) {
+                        (o.contentType == ContentType.HANDSHAKE.id)) {
                     // ChangeCipherSpec is the latest message of an epoch.
                     return 1;
                 }
-            } else if (o.contentType == Record.ct_change_cipher_spec) {
+            } else if (o.contentType == ContentType.CHANGE_CIPHER_SPEC.id) {
                 if ((this.recordEpoch == o.recordEpoch) &&
-                        (this.contentType == Record.ct_handshake)) {
+                        (this.contentType == ContentType.HANDSHAKE.id)) {
                     // ChangeCipherSpec is the latest message of an epoch.
                     return -1;
                 } else {
                     // different epoch or this is not a handshake message
                     return compareToSequence(o.recordEpoch, o.recordSeq);

@@ -537,11 +504,11 @@
                     return 0;
                 }
 
                 // Should be repacked for suitable fragment length.
                 //
-                // Note that the acquiring processes will reassemble
+                // Note that the acquiring processes will reassemble the
                 // the fragments later.
                 return compareToSequence(o.recordEpoch, o.recordSeq);
             }
 
             return super.compareTo(o);

@@ -557,11 +524,11 @@
             this.limit = limit;
         }
     }
 
     private static final class HandshakeFlight implements Cloneable {
-        static final byte HF_UNKNOWN = HandshakeMessage.ht_not_applicable;
+        static final byte HF_UNKNOWN = SSLHandshake.NOT_APPLICABLE.id;
 
         byte        handshakeType;      // handshake type
         int         flightEpoch;        // the epoch of the first message
         int         minMessageSeq;      // minimal message sequence
 

@@ -663,19 +630,19 @@
                     (precedingFlight.minMessageSeq == hsf.messageSeq)) {
                 isMinimalFlightMessage = true;
             }
 
             if (isMinimalFlightMessage && (hsf.fragmentOffset == 0) &&
-                    (hsf.handshakeType != HandshakeMessage.ht_finished)) {
+                    (hsf.handshakeType != SSLHandshake.FINISHED.id)) {
 
                 // reset the handshake flight
                 handshakeFlight.handshakeType = hsf.handshakeType;
                 handshakeFlight.flightEpoch = hsf.recordEpoch;
                 handshakeFlight.minMessageSeq = hsf.messageSeq;
             }
 
-            if (hsf.handshakeType == HandshakeMessage.ht_finished) {
+            if (hsf.handshakeType == SSLHandshake.FINISHED.id) {
                 handshakeFlight.maxMessageSeq = hsf.messageSeq;
                 handshakeFlight.maxRecordEpoch = hsf.recordEpoch;
                 handshakeFlight.maxRecordSeq = hsf.recordSeq;
             } else {
                 if (handshakeFlight.maxMessageSeq < hsf.messageSeq) {

@@ -716,12 +683,12 @@
                 // a handshake message retransmission.  Discard this record.
                 //
                 // It's OK to discard retransmission as the handshake hash
                 // is computed as if each handshake message had been sent
                 // as a single fragment.
-                if (debug != null && Debug.isOn("verbose")) {
-                    Debug.log("Have got the full message, discard it.");
+                if (SSLLogger.isOn && SSLLogger.isOn("verbose")) {
+                    SSLLogger.fine("Have got the full message, discard it.");
                 }
 
                 return;
             }
 

@@ -740,12 +707,12 @@
                     if (((hole.offset > hsf.fragmentOffset) &&
                          (hole.offset < fragmentLimit)) ||
                         ((hole.limit > hsf.fragmentOffset) &&
                          (hole.limit < fragmentLimit))) {
 
-                        if (debug != null && Debug.isOn("ssl")) {
-                            Debug.log("Discard invalid record: " +
+                        if (SSLLogger.isOn && SSLLogger.isOn("ssl")) {
+                            SSLLogger.fine("Discard invalid record: " +
                                 "handshake fragment ranges are overlapping");
                         }
 
                         // invalid, discard it [section 4.1.2.7, RFC 6347]
                         return;

@@ -771,11 +738,11 @@
                     break;
                 }
             }
 
             // buffer this fragment
-            if (hsf.handshakeType == HandshakeMessage.ht_finished) {
+            if (hsf.handshakeType == SSLHandshake.FINISHED.id) {
                 // Need no status update.
                 bufferedFragments.add(hsf);
             } else {
                 bufferFragment(hsf);
             }

@@ -847,11 +814,13 @@
                     if (rf instanceof HandshakeFragment) {
                         HandshakeFragment hsf = (HandshakeFragment)rf;
                         if (precedingFlight.maxMessageSeq  < hsf.messageSeq) {
                             isNewFlight = true;
                         }
-                    } else if (rf.contentType != Record.ct_change_cipher_spec) {
+                    } else if (
+                        rf.contentType != ContentType.CHANGE_CIPHER_SPEC.id) {
+
                         // ciphertext
                         if (precedingFlight.maxRecordEpoch < rf.recordEpoch) {
                             isNewFlight = true;
                         }
                     }

@@ -902,12 +871,13 @@
             // Discard records old than the previous epoch.
             //
             int previousEpoch = nextRecordEpoch - 1;
             if (rf.recordEpoch < previousEpoch) {
                 // Too old to use, discard this record.
-                if (debug != null && Debug.isOn("verbose")) {
-                    Debug.log("Too old epoch to use this record, discard it.");
+                if (SSLLogger.isOn && SSLLogger.isOn("verbose")) {
+                    SSLLogger.fine(
+                            "Too old epoch to use this record, discard it.");
                 }
 
                 return false;
             }
 

@@ -930,11 +900,13 @@
                     if (rf instanceof HandshakeFragment) {
                         HandshakeFragment hsf = (HandshakeFragment)rf;
                         if (precedingFlight.minMessageSeq > hsf.messageSeq) {
                             isDesired = false;
                         }
-                    } else if (rf.contentType == Record.ct_change_cipher_spec) {
+                    } else if (
+                        rf.contentType == ContentType.CHANGE_CIPHER_SPEC.id) {
+
                         // ChangeCipherSpec
                         if (precedingFlight.flightEpoch != rf.recordEpoch) {
                             isDesired = false;
                         }
                     } else {        // ciphertext

@@ -946,24 +918,26 @@
                     }
                 }
 
                 if (!isDesired) {
                     // Too old to use, discard this retransmitted record
-                    if (debug != null && Debug.isOn("verbose")) {
-                        Debug.log("Too old retransmission to use, discard it.");
+                    if (SSLLogger.isOn && SSLLogger.isOn("verbose")) {
+                        SSLLogger.fine(
+                                "Too old retransmission to use, discard it.");
                     }
 
                     return false;
                 }
             } else if ((rf.recordEpoch == nextRecordEpoch) &&
                     (nextRecordSeq > rf.recordSeq)) {
 
                 // Previously disordered record for the current epoch.
                 //
                 // Should has been retransmitted. Discard this record.
-                if (debug != null && Debug.isOn("verbose")) {
-                    Debug.log("Lagging behind record (sequence), discard it.");
+                if (SSLLogger.isOn && SSLLogger.isOn("verbose")) {
+                    SSLLogger.fine(
+                            "Lagging behind record (sequence), discard it.");
                 }
 
                 return false;
             }
 

@@ -976,12 +950,12 @@
                     (needToCheckFlight && !flightIsReady()));
         }
 
         Plaintext acquirePlaintext() {
             if (bufferedFragments.isEmpty()) {
-                if (debug != null && Debug.isOn("verbose")) {
-                    Debug.log("No received handshake messages");
+                if (SSLLogger.isOn && SSLLogger.isOn("verbose")) {
+                    SSLLogger.fine("No received handshake messages");
                 }
                 return null;
             }
 
             if (!flightIsReady && needToCheckFlight) {

@@ -997,24 +971,25 @@
                         bufferedFragments.clear();
 
                         // Reset the next handshake flight.
                         resetHandshakeFlight(precedingFlight);
 
-                        if (debug != null && Debug.isOn("verbose")) {
-                            Debug.log("Received a retransmission flight.");
+                        if (SSLLogger.isOn && SSLLogger.isOn("verbose")) {
+                            SSLLogger.fine("Received a retransmission flight.");
                         }
 
                         return Plaintext.PLAINTEXT_NULL;
                     }
                 }
 
                 needToCheckFlight = false;
             }
 
             if (!flightIsReady) {
-                if (debug != null && Debug.isOn("verbose")) {
-                    Debug.log("The handshake flight is not ready to use: " +
+                if (SSLLogger.isOn && SSLLogger.isOn("verbose")) {
+                    SSLLogger.fine(
+                            "The handshake flight is not ready to use: " +
                                 handshakeFlight.handshakeType);
                 }
                 return null;
             }
 

@@ -1034,11 +1009,11 @@
 
                     // Reset the next handshake flight.
                     resetHandshakeFlight(precedingFlight);
 
                     if (expectCCSFlight &&
-                            (precedingFlight.flightEpoch ==
+                            (precedingFlight.handshakeType ==
                                     HandshakeFlight.HF_UNKNOWN)) {
                         expectCCSFlight = false;
                     }
                 }
             } else {

@@ -1086,64 +1061,67 @@
             flightIsReady = false;
             needToCheckFlight = false;
         }
 
         private Plaintext acquireCachedMessage() {
-
             RecordFragment rFrag = bufferedFragments.first();
             if (readEpoch != rFrag.recordEpoch) {
                 if (readEpoch > rFrag.recordEpoch) {
                     // discard old records
-                    if (debug != null && Debug.isOn("verbose")) {
-                        Debug.log("Discard old buffered ciphertext fragments.");
+                    if (SSLLogger.isOn && SSLLogger.isOn("verbose")) {
+                        SSLLogger.fine(
+                                "Discard old buffered ciphertext fragments.");
                     }
                     bufferedFragments.remove(rFrag);    // popup the fragment
                 }
 
                 // reset the flight
                 if (flightIsReady) {
                     flightIsReady = false;
                 }
 
-                if (debug != null && Debug.isOn("verbose")) {
-                    Debug.log("Not yet ready to decrypt the cached fragments.");
+                if (SSLLogger.isOn && SSLLogger.isOn("verbose")) {
+                    SSLLogger.fine(
+                            "Not yet ready to decrypt the cached fragments.");
                 }
                 return null;
             }
 
             bufferedFragments.remove(rFrag);    // popup the fragment
 
             ByteBuffer fragment = ByteBuffer.wrap(rFrag.fragment);
             ByteBuffer plaintextFragment = null;
             try {
-                plaintextFragment = decrypt(readAuthenticator, readCipher,
+                Plaintext plaintext = readCipher.decrypt(
                         rFrag.contentType, fragment, rFrag.recordEnS);
-            } catch (BadPaddingException bpe) {
-                if (debug != null && Debug.isOn("verbose")) {
-                    Debug.log("Discard invalid record: " + bpe);
+                plaintextFragment = plaintext.fragment;
+                rFrag.contentType = plaintext.contentType;
+            } catch (GeneralSecurityException gse) {
+                if (SSLLogger.isOn && SSLLogger.isOn("verbose")) {
+                    SSLLogger.fine("Discard invalid record: ", gse);
                 }
 
                 // invalid, discard this record [section 4.1.2.7, RFC 6347]
                 return null;
             }
 
             // The ciphtext handshake message can only be Finished (the
             // end of this flight), ClinetHello or HelloRequest (the
             // beginning of the next flight) message.  Need not to check
             // any ChangeCipherSpec message.
-            if (rFrag.contentType == Record.ct_handshake) {
+            if (rFrag.contentType == ContentType.HANDSHAKE.id) {
                 while (plaintextFragment.remaining() > 0) {
                     HandshakeFragment hsFrag = parseHandshakeMessage(
                             rFrag.contentType,
                             rFrag.majorVersion, rFrag.minorVersion,
                             rFrag.recordEnS, rFrag.recordEpoch, rFrag.recordSeq,
                             plaintextFragment);
 
                     if (hsFrag == null) {
                         // invalid, discard this record
-                        if (debug != null && Debug.isOn("verbose")) {
-                            Debug.printHex(
+                        if (SSLLogger.isOn && SSLLogger.isOn("verbose")) {
+                            SSLLogger.fine(
                                     "Invalid handshake fragment, discard it",
                                     plaintextFragment);
                         }
                         return null;
                     }

@@ -1151,11 +1129,11 @@
                     queueUpHandshake(hsFrag);
                     // The flight ready status (flightIsReady) should have
                     // been checked and updated for the Finished handshake
                     // message before the decryption.  Please don't update
                     // flightIsReady for Finished messages.
-                    if (hsFrag.handshakeType != HandshakeMessage.ht_finished) {
+                    if (hsFrag.handshakeType != SSLHandshake.FINISHED.id) {
                         flightIsReady = false;
                         needToCheckFlight = true;
                     }
                 }
 

@@ -1170,31 +1148,27 @@
         }
 
         private Plaintext acquireHandshakeMessage() {
 
             RecordFragment rFrag = bufferedFragments.first();
-            if (rFrag.contentType == Record.ct_change_cipher_spec) {
+            if (rFrag.contentType == ContentType.CHANGE_CIPHER_SPEC.id) {
                 this.nextRecordEpoch = rFrag.recordEpoch + 1;
 
                 // For retransmissions, the next record sequence number is a
                 // positive value.  Don't worry about it as the acquiring of
                 // the immediately followed Finished handshake message will
                 // reset the next record sequence number correctly.
                 this.nextRecordSeq = 0;
 
                 // Popup the fragment.
                 bufferedFragments.remove(rFrag);
-
-                // Reload if this message has been reserved for handshake hash.
-                handshakeHash.reload();
-
                 return new Plaintext(rFrag.contentType,
                         rFrag.majorVersion, rFrag.minorVersion,
                         rFrag.recordEpoch,
                         Authenticator.toLong(rFrag.recordEnS),
                         ByteBuffer.wrap(rFrag.fragment));
-            } else {    // rFrag.contentType == Record.ct_handshake
+            } else {    // rFrag.contentType == ContentType.HANDSHAKE.id
                 HandshakeFragment hsFrag = (HandshakeFragment)rFrag;
                 if ((hsFrag.messageLength == hsFrag.fragmentLength) &&
                     (hsFrag.fragmentOffset == 0)) {     // no fragmentation
 
                     bufferedFragments.remove(rFrag);    // popup the fragment

@@ -1202,11 +1176,12 @@
                     // this.nextRecordEpoch = hsFrag.recordEpoch;
                     this.nextRecordSeq = hsFrag.recordSeq + 1;
 
                     // Note: may try to avoid byte array copy in the future.
                     byte[] recordFrag = new byte[hsFrag.messageLength + 4];
-                    Plaintext plaintext = new Plaintext(hsFrag.contentType,
+                    Plaintext plaintext = new Plaintext(
+                            hsFrag.contentType,
                             hsFrag.majorVersion, hsFrag.minorVersion,
                             hsFrag.recordEpoch,
                             Authenticator.toLong(hsFrag.recordEnS),
                             ByteBuffer.wrap(recordFrag));
 

@@ -1228,11 +1203,12 @@
                 } else {                // fragmented handshake message
                     // the first record
                     //
                     // Note: may try to avoid byte array copy in the future.
                     byte[] recordFrag = new byte[hsFrag.messageLength + 4];
-                    Plaintext plaintext = new Plaintext(hsFrag.contentType,
+                    Plaintext plaintext = new Plaintext(
+                            hsFrag.contentType,
                             hsFrag.majorVersion, hsFrag.minorVersion,
                             hsFrag.recordEpoch,
                             Authenticator.toLong(hsFrag.recordEnS),
                             ByteBuffer.wrap(recordFrag));
 

@@ -1262,11 +1238,11 @@
                         // speed up the reassembly in the future.
 
                         // read the next buffered record
                         if (!bufferedFragments.isEmpty()) {
                             rFrag = bufferedFragments.first();
-                            if (rFrag.contentType != Record.ct_handshake) {
+                            if (rFrag.contentType != ContentType.HANDSHAKE.id) {
                                 break;
                             } else {
                                 hmFrag = (HandshakeFragment)rFrag;
                             }
                         }

@@ -1291,83 +1267,86 @@
                 // the ChangeCipherSpec/Finished flight
                 //
                 if (expectCCSFlight) {
                     // Have the ChangeCipherSpec/Finished flight been received?
                     boolean isReady = hasFinishedMessage(bufferedFragments);
-                    if (debug != null && Debug.isOn("verbose")) {
-                        Debug.log(
+                    if (SSLLogger.isOn && SSLLogger.isOn("verbose")) {
+                        SSLLogger.fine(
                             "Has the final flight been received? " + isReady);
                     }
 
                     return isReady;
                 }
 
-                if (debug != null && Debug.isOn("verbose")) {
-                    Debug.log("No flight is received yet.");
+                if (SSLLogger.isOn && SSLLogger.isOn("verbose")) {
+                    SSLLogger.fine("No flight is received yet.");
                 }
 
                 return false;
             }
 
-            if ((flightType == HandshakeMessage.ht_client_hello) ||
-                (flightType == HandshakeMessage.ht_hello_request) ||
-                (flightType == HandshakeMessage.ht_hello_verify_request)) {
+            if ((flightType == SSLHandshake.CLIENT_HELLO.id) ||
+                (flightType == SSLHandshake.HELLO_REQUEST.id) ||
+                (flightType == SSLHandshake.HELLO_VERIFY_REQUEST.id)) {
 
                 // single handshake message flight
                 boolean isReady = hasCompleted(flightType);
-                if (debug != null && Debug.isOn("verbose")) {
-                    Debug.log("Is the handshake message completed? " + isReady);
+                if (SSLLogger.isOn && SSLLogger.isOn("verbose")) {
+                    SSLLogger.fine(
+                            "Is the handshake message completed? " + isReady);
                 }
 
                 return isReady;
             }
 
             //
             // the ServerHello flight
             //
-            if (flightType == HandshakeMessage.ht_server_hello) {
+            if (flightType == SSLHandshake.SERVER_HELLO.id) {
                 // Firstly, check the first flight handshake message.
                 if (!hasCompleted(flightType)) {
-                    if (debug != null && Debug.isOn("verbose")) {
-                        Debug.log(
+                    if (SSLLogger.isOn && SSLLogger.isOn("verbose")) {
+                        SSLLogger.fine(
                             "The ServerHello message is not completed yet.");
                     }
 
                     return false;
                 }
 
                 //
                 // an abbreviated handshake
                 //
                 if (hasFinishedMessage(bufferedFragments)) {
-                    if (debug != null && Debug.isOn("verbose")) {
-                        Debug.log("It's an abbreviated handshake.");
+                    if (SSLLogger.isOn && SSLLogger.isOn("verbose")) {
+                        SSLLogger.fine("It's an abbreviated handshake.");
                     }
 
                     return true;
                 }
 
                 //
                 // a full handshake
                 //
                 List<HoleDescriptor> holes = handshakeFlight.holesMap.get(
-                        HandshakeMessage.ht_server_hello_done);
+                        SSLHandshake.SERVER_HELLO_DONE.id);
                 if ((holes == null) || !holes.isEmpty()) {
                     // Not yet got the final message of the flight.
-                    if (debug != null && Debug.isOn("verbose")) {
-                        Debug.log("Not yet got the ServerHelloDone message");
+                    if (SSLLogger.isOn && SSLLogger.isOn("verbose")) {
+                        SSLLogger.fine(
+                                "Not yet got the ServerHelloDone message");
                     }
 
                     return false;
                 }
 
                 // Have all handshake message been received?
                 boolean isReady = hasCompleted(bufferedFragments,
                             handshakeFlight.minMessageSeq,
                             handshakeFlight.maxMessageSeq);
-                if (debug != null && Debug.isOn("verbose")) {
-                    Debug.log("Is the ServerHello flight (message " +
+                if (SSLLogger.isOn && SSLLogger.isOn("verbose")) {
+                    SSLLogger.fine(
+                            "Is the ServerHello flight (message " +
                             handshakeFlight.minMessageSeq + "-" +
                             handshakeFlight.maxMessageSeq +
                             ") completed? " + isReady);
                 }
 

@@ -1379,42 +1358,42 @@
             //
             // Note: need to consider more messages in this flight if
             //       ht_supplemental_data and ht_certificate_url are
             //       suppported in the future.
             //
-            if ((flightType == HandshakeMessage.ht_certificate) ||
-                (flightType == HandshakeMessage.ht_client_key_exchange)) {
+            if ((flightType == SSLHandshake.CERTIFICATE.id) ||
+                (flightType == SSLHandshake.CLIENT_KEY_EXCHANGE.id)) {
 
                 // Firstly, check the first flight handshake message.
                 if (!hasCompleted(flightType)) {
-                    if (debug != null && Debug.isOn("verbose")) {
-                        Debug.log(
+                    if (SSLLogger.isOn && SSLLogger.isOn("verbose")) {
+                        SSLLogger.fine(
                             "The ClientKeyExchange or client Certificate " +
                             "message is not completed yet.");
                     }
 
                     return false;
                 }
 
                 // Is client CertificateVerify a mandatory message?
-                if (flightType == HandshakeMessage.ht_certificate) {
+                if (flightType == SSLHandshake.CERTIFICATE.id) {
                     if (needClientVerify(bufferedFragments) &&
-                        !hasCompleted(ht_certificate_verify)) {
+                        !hasCompleted(SSLHandshake.CERTIFICATE_VERIFY.id)) {
 
-                        if (debug != null && Debug.isOn("verbose")) {
-                            Debug.log(
+                        if (SSLLogger.isOn && SSLLogger.isOn("verbose")) {
+                            SSLLogger.fine(
                                 "Not yet have the CertificateVerify message");
                         }
 
                         return false;
                     }
                 }
 
                 if (!hasFinishedMessage(bufferedFragments)) {
                     // not yet have the ChangeCipherSpec/Finished messages
-                    if (debug != null && Debug.isOn("verbose")) {
-                        Debug.log(
+                    if (SSLLogger.isOn && SSLLogger.isOn("verbose")) {
+                        SSLLogger.fine(
                             "Not yet have the ChangeCipherSpec and " +
                             "Finished messages");
                     }
 
                     return false;

@@ -1422,12 +1401,13 @@
 
                 // Have all handshake message been received?
                 boolean isReady = hasCompleted(bufferedFragments,
                             handshakeFlight.minMessageSeq,
                             handshakeFlight.maxMessageSeq);
-                if (debug != null && Debug.isOn("verbose")) {
-                    Debug.log("Is the ClientKeyExchange flight (message " +
+                if (SSLLogger.isOn && SSLLogger.isOn("verbose")) {
+                    SSLLogger.fine(
+                            "Is the ClientKeyExchange flight (message " +
                             handshakeFlight.minMessageSeq + "-" +
                             handshakeFlight.maxMessageSeq +
                             ") completed? " + isReady);
                 }
 

@@ -1435,12 +1415,12 @@
             }
 
             //
             // Otherwise, need to receive more handshake messages.
             //
-            if (debug != null && Debug.isOn("verbose")) {
-                Debug.log("Need to receive more handshake messages");
+            if (SSLLogger.isOn && SSLLogger.isOn("verbose")) {
+                SSLLogger.fine("Need to receive more handshake messages");
             }
 
             return false;
         }
 

@@ -1454,16 +1434,16 @@
         private boolean hasFinishedMessage(Set<RecordFragment> fragments) {
 
             boolean hasCCS = false;
             boolean hasFin = false;
             for (RecordFragment fragment : fragments) {
-                if (fragment.contentType == Record.ct_change_cipher_spec) {
+                if (fragment.contentType == ContentType.CHANGE_CIPHER_SPEC.id) {
                     if (hasFin) {
                         return true;
                     }
                     hasCCS = true;
-                } else if (fragment.contentType == Record.ct_handshake) {
+                } else if (fragment.contentType == ContentType.HANDSHAKE.id) {
                     // Finished is the first expected message of a new epoch.
                     if (fragment.isCiphertext) {
                         if (hasCCS) {
                             return true;
                         }

@@ -1482,17 +1462,17 @@
         private boolean needClientVerify(Set<RecordFragment> fragments) {
 
             // The caller should have checked the completion of the first
             // present handshake message.  Need not to check it again.
             for (RecordFragment rFrag : fragments) {
-                if ((rFrag.contentType != Record.ct_handshake) ||
+                if ((rFrag.contentType != ContentType.HANDSHAKE.id) ||
                         rFrag.isCiphertext) {
                     break;
                 }
 
                 HandshakeFragment hsFrag = (HandshakeFragment)rFrag;
-                if (hsFrag.handshakeType != HandshakeMessage.ht_certificate) {
+                if (hsFrag.handshakeType != SSLHandshake.CERTIFICATE.id) {
                     continue;
                 }
 
                 return (rFrag.fragment != null) &&
                    (rFrag.fragment.length > DTLSRecord.minCertPlaintextSize);

@@ -1517,11 +1497,11 @@
                 int presentMsgSeq, int endMsgSeq) {
 
             // The caller should have checked the completion of the first
             // present handshake message.  Need not to check it again.
             for (RecordFragment rFrag : fragments) {
-                if ((rFrag.contentType != Record.ct_handshake) ||
+                if ((rFrag.contentType != ContentType.HANDSHAKE.id) ||
                         rFrag.isCiphertext) {
                     break;
                 }
 
                 HandshakeFragment hsFrag = (HandshakeFragment)rFrag;

@@ -1544,36 +1524,20 @@
                         // false: if not yet got all messages of the flight.
         }
 
         private void handshakeHashing(
                 HandshakeFragment hsFrag, Plaintext plaintext) {
-
             byte hsType = hsFrag.handshakeType;
-            if ((hsType == HandshakeMessage.ht_hello_request) ||
-                (hsType == HandshakeMessage.ht_hello_verify_request)) {
-
+            if (!handshakeHash.isHashable(hsType)) {
                 // omitted from handshake hash computation
                 return;
             }
 
-            if ((hsFrag.messageSeq == 0) &&
-                (hsType == HandshakeMessage.ht_client_hello)) {
-
-                // omit initial ClientHello message
-                //
-                //  4: handshake header
-                //  2: ClientHello.client_version
-                // 32: ClientHello.random
-                int sidLen = plaintext.fragment.get(38);
-
-                if (sidLen == 0) {      // empty session_id, initial handshake
-                    return;
-                }
-            }
-
-            // calculate the DTLS header
-            byte[] temporary = new byte[12];    // 12: handshake header size
+            // calculate the DTLS header and reserve the handshake message
+            plaintext.fragment.position(4);     // ignore the TLS header
+            byte[] temporary = new byte[plaintext.fragment.remaining() + 12];
+                                                // 12: handshake header size
 
             // Handshake.msg_type
             temporary[0] = hsFrag.handshakeType;
 
             // Handshake.length

@@ -1593,29 +1557,13 @@
             // Handshake.fragment_length
             temporary[9] = temporary[1];
             temporary[10] = temporary[2];
             temporary[11] = temporary[3];
 
-            plaintext.fragment.position(4);     // ignore the TLS header
-            if ((hsType != HandshakeMessage.ht_finished) &&
-                (hsType != HandshakeMessage.ht_certificate_verify)) {
-
-                if (handshakeHash == null) {
-                    // used for cache only
-                    handshakeHash = new HandshakeHash(false);
-                }
-                handshakeHash.update(temporary, 0, 12);
-                handshakeHash.update(plaintext.fragment);
-            } else {
-                // Reserve until this handshake message has been processed.
-                if (handshakeHash == null) {
-                    // used for cache only
-                    handshakeHash = new HandshakeHash(false);
-                }
-                handshakeHash.reserve(temporary, 0, 12);
-                handshakeHash.reserve(plaintext.fragment);
-            }
+            plaintext.fragment.get(temporary,
+                    12, plaintext.fragment.remaining());
+            handshakeHash.receive(temporary);
             plaintext.fragment.position(0);     // restore the position
         }
     }
 }
 
< prev index next >