jdk/src/share/classes/sun/security/ssl/OutputRecord.java
changeset 16067 36055e4b5305
parent 16045 9d08c3b9a6a0
child 16126 aad71cf676d7
--- a/jdk/src/share/classes/sun/security/ssl/OutputRecord.java	Tue Mar 12 10:35:44 2013 -0400
+++ b/jdk/src/share/classes/sun/security/ssl/OutputRecord.java	Tue Mar 12 15:31:49 2013 -0700
@@ -54,7 +54,6 @@
     private int                 lastHashed;
     private boolean             firstMessage;
     final private byte          contentType;
-    private int                 headerOffset;
 
     // current protocol version, sent as record version
     ProtocolVersion     protocolVersion;
@@ -71,23 +70,6 @@
      * Default constructor makes a record supporting the maximum
      * SSL record size.  It allocates the header bytes directly.
      *
-     * The structure of the byte buffer looks like:
-     *
-     *     |---------+--------+-------+---------------------------------|
-     *     | unused  | header |  IV   | content, MAC/TAG, padding, etc. |
-     *     |    headerPlusMaxIVSize   |
-     *
-     * unused: unused part of the buffer of size
-     *
-     *             headerPlusMaxIVSize - header size - IV size
-     *
-     *         When this object is created, we don't know the protocol
-     *         version number, IV length, etc., so reserve space in front
-     *         to avoid extra data movement (copies).
-     * header: the header of an SSL record
-     * IV:     the optional IV/nonce field, it is only required for block
-     *         (TLS 1.1 or later) and AEAD cipher suites.
-     *
      * @param type the content type for the record
      */
     OutputRecord(byte type, int size) {
@@ -95,10 +77,9 @@
         this.protocolVersion = ProtocolVersion.DEFAULT;
         this.helloVersion = ProtocolVersion.DEFAULT_HELLO;
         firstMessage = true;
-        count = headerPlusMaxIVSize;
+        count = headerSize;
         contentType = type;
         lastHashed = count;
-        headerOffset = headerPlusMaxIVSize - headerSize;
     }
 
     OutputRecord(byte type) {
@@ -138,9 +119,8 @@
     @Override
     public synchronized void reset() {
         super.reset();
-        count = headerPlusMaxIVSize;
+        count = headerSize;
         lastHashed = count;
-        headerOffset = headerPlusMaxIVSize - headerSize;
     }
 
     /*
@@ -193,84 +173,58 @@
      * of sending empty records over the network.
      */
     boolean isEmpty() {
-        return count == headerPlusMaxIVSize;
+        return count == headerSize;
     }
 
     /*
-     * Return true if the record is of an alert of the given description.
-     *
-     * Per SSL/TLS specifications, alert messages convey the severity of the
-     * message (warning or fatal) and a description of the alert. An alert
-     * is defined with a two bytes struct, {byte level, byte description},
-     * following after the header bytes.
+     * Return true if the record is of a given alert.
      */
     boolean isAlert(byte description) {
-        if ((count > (headerPlusMaxIVSize + 1)) && (contentType == ct_alert)) {
-            return buf[headerPlusMaxIVSize + 1] == description;
+        // An alert is defined with a two bytes struct,
+        // {byte level, byte description}, following after the header bytes.
+        if (count > (headerSize + 1) && contentType == ct_alert) {
+            return buf[headerSize + 1] == description;
         }
 
         return false;
     }
 
     /*
-     * Encrypt ... length may grow due to block cipher padding, or
-     * message authentication code or tag.
+     * Compute the MAC and append it to this record.  In case we
+     * are automatically flushing a handshake stream, make sure we
+     * have hashed the message first.
      */
-    void encrypt(Authenticator authenticator, CipherBox box)
-            throws IOException {
-
-        // In case we are automatically flushing a handshake stream, make
-        // sure we have hashed the message first.
+    void addMAC(MAC signer) throws IOException {
         //
         // when we support compression, hashing can't go here
         // since it'll need to be done on the uncompressed data,
         // and the MAC applies to the compressed data.
+        //
         if (contentType == ct_handshake) {
             doHashes();
         }
-
-        // Requires message authentication code for stream and block
-        // cipher suites.
-        if (authenticator instanceof MAC) {
-            MAC signer = (MAC)authenticator;
-            if (signer.MAClen() != 0) {
-                byte[] hash = signer.compute(contentType, buf,
-                    headerPlusMaxIVSize, count - headerPlusMaxIVSize);
-                write(hash);
-            }
-        }
-
-        if (!box.isNullCipher()) {
-            // Requires explicit IV/nonce for CBC/AEAD cipher suites for
-            // TLS 1.1 or later.
-            if ((protocolVersion.v >= ProtocolVersion.TLS11.v) &&
-                                    (box.isCBCMode() || box.isAEADMode())) {
-                byte[] nonce = box.createExplicitNonce(authenticator,
-                                    contentType, count - headerPlusMaxIVSize);
-                int offset = headerPlusMaxIVSize - nonce.length;
-                System.arraycopy(nonce, 0, buf, offset, nonce.length);
-                headerOffset = offset - headerSize;
-            } else {
-                headerOffset = headerPlusMaxIVSize - headerSize;
-            }
-
-            // encrypt the content
-            int offset = headerPlusMaxIVSize;
-            if (!box.isAEADMode()) {
-                // The explicit IV can be encrypted.
-                offset = headerOffset + headerSize;
-            }   // Otherwise, DON'T encrypt the nonce_explicit for AEAD mode
-
-            count = offset + box.encrypt(buf, offset, count - offset);
+        if (signer.MAClen() != 0) {
+            byte[] hash = signer.compute(contentType, buf,
+                    headerSize, count - headerSize);
+            write(hash);
         }
     }
 
     /*
+     * Encrypt ... length may grow due to block cipher padding
+     */
+    void encrypt(CipherBox box) {
+        int len = count - headerSize;
+        count = headerSize + box.encrypt(buf, headerSize, len);
+    }
+
+
+    /*
      * Tell how full the buffer is ... for filling it with application or
      * handshake data.
      */
     final int availableDataBytes() {
-        int dataSize = count - headerPlusMaxIVSize;
+        int dataSize = count - headerSize;
         return maxDataSize - dataSize;
     }
 
@@ -316,11 +270,11 @@
          * Don't emit content-free records.  (Even change cipher spec
          * messages have a byte of data!)
          */
-        if (count == headerPlusMaxIVSize) {
+        if (count == headerSize) {
             return;
         }
 
-        int length = count - headerOffset - headerSize;
+        int length = count - headerSize;
         // "should" really never write more than about 14 Kb...
         if (length < 0) {
             throw new SSLException("output record size too small: "
@@ -345,9 +299,7 @@
          */
          if (firstMessage && useV2Hello()) {
             byte[] v3Msg = new byte[length - 4];
-            System.arraycopy(buf, headerPlusMaxIVSize + 4,
-                                        v3Msg, 0, v3Msg.length);
-            headerOffset = 0;   // reset the header offset
+            System.arraycopy(buf, headerSize + 4, v3Msg, 0, v3Msg.length);
             V3toV2ClientHello(v3Msg);
             handshakeHash.reset();
             lastHashed = 2;
@@ -362,11 +314,11 @@
             /*
              * Fill out the header, write it and the message.
              */
-            buf[headerOffset + 0] = contentType;
-            buf[headerOffset + 1] = protocolVersion.major;
-            buf[headerOffset + 2] = protocolVersion.minor;
-            buf[headerOffset + 3] = (byte)(length >> 8);
-            buf[headerOffset + 4] = (byte)(length);
+            buf[0] = contentType;
+            buf[1] = protocolVersion.major;
+            buf[2] = protocolVersion.minor;
+            buf[3] = (byte)(length >> 8);
+            buf[4] = (byte)(length);
         }
         firstMessage = false;
 
@@ -386,8 +338,7 @@
              * when holdRecord is true, the implementation in this class
              * will be used.
              */
-            writeBuffer(heldRecordBuffer,
-                        buf, headerOffset, count - headerOffset, debugOffset);
+            writeBuffer(heldRecordBuffer, buf, 0, count, debugOffset);
         } else {
             // It's time to send, do we have buffered data?
             // May or may not have a heldRecordBuffer.
@@ -395,18 +346,15 @@
                 int heldLen = heldRecordBuffer.size();
 
                 // Ensure the capacity of this buffer.
-                int newCount = count + heldLen - headerOffset;
-                ensureCapacity(newCount);
+                ensureCapacity(count + heldLen);
 
                 // Slide everything in the buffer to the right.
-                System.arraycopy(buf, headerOffset,
-                                    buf, heldLen, count - headerOffset);
+                System.arraycopy(buf, 0, buf, heldLen, count);
 
                 // Prepend the held record to the buffer.
                 System.arraycopy(
                     heldRecordBuffer.toByteArray(), 0, buf, 0, heldLen);
-                count = newCount;
-                headerOffset = 0;
+                count += heldLen;
 
                 // Clear the held buffer.
                 heldRecordBuffer.reset();
@@ -414,8 +362,7 @@
                 // The held buffer has been dumped, set the debug dump offset.
                 debugOffset = heldLen;
             }
-            writeBuffer(s, buf, headerOffset,
-                        count - headerOffset, debugOffset);
+            writeBuffer(s, buf, 0, count, debugOffset);
         }
 
         reset();
@@ -435,11 +382,12 @@
         if (debug != null && Debug.isOn("packet")) {
             try {
                 HexDumpEncoder hd = new HexDumpEncoder();
+                ByteBuffer bb = ByteBuffer.wrap(
+                        buf, off + debugOffset, len - debugOffset);
 
                 System.out.println("[Raw write]: length = " +
-                                                    (len - debugOffset));
-                hd.encodeBuffer(new ByteArrayInputStream(buf,
-                    off + debugOffset, len - debugOffset), System.out);
+                    bb.remaining());
+                hd.encodeBuffer(bb, System.out);
             } catch (IOException e) { }
         }
     }
@@ -452,13 +400,8 @@
         return firstMessage
             && (helloVersion == ProtocolVersion.SSL20Hello)
             && (contentType == ct_handshake)
-            && (buf[headerOffset + 5] == HandshakeMessage.ht_client_hello)
-                                            //  5: recode header size
-            && (buf[headerPlusMaxIVSize + 4 + 2 + 32] == 0);
-                                            // V3 session ID is empty
-                                            //  4: handshake header size
-                                            //  2: client_version in ClientHello
-                                            // 32: random in ClientHello
+            && (buf[5] == HandshakeMessage.ht_client_hello)
+            && (buf[headerSize + 4+2+32] == 0); // V3 session ID is empty
     }
 
     /*