src/java.base/share/classes/sun/security/ssl/SSLSocketOutputRecord.java
changeset 50768 68fa3d4026ea
parent 47216 71c04702a3d5
child 51407 910f7b56592f
--- a/src/java.base/share/classes/sun/security/ssl/SSLSocketOutputRecord.java	Mon Jun 25 21:22:16 2018 +0300
+++ b/src/java.base/share/classes/sun/security/ssl/SSLSocketOutputRecord.java	Mon Jun 25 13:41:39 2018 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 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
@@ -25,14 +25,14 @@
 
 package sun.security.ssl;
 
-import java.io.*;
-import java.nio.*;
-import java.util.Arrays;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.nio.ByteBuffer;
+import javax.net.ssl.SSLHandshakeException;
 
-import javax.net.ssl.SSLException;
-import javax.net.ssl.SSLHandshakeException;
-import sun.security.util.HexDumpEncoder;
-
+import sun.security.ssl.KeyUpdate.KeyUpdateMessage;
+import sun.security.ssl.KeyUpdate.KeyUpdateRequest;
 
 /**
  * {@code OutputRecord} implementation for {@code SSLSocket}.
@@ -40,11 +40,16 @@
 final class SSLSocketOutputRecord extends OutputRecord implements SSLRecord {
     private OutputStream deliverStream = null;
 
-    SSLSocketOutputRecord() {
-        this.writeAuthenticator = MAC.TLS_NULL;
+    SSLSocketOutputRecord(HandshakeHash handshakeHash) {
+        this(handshakeHash, null);
+    }
 
+    SSLSocketOutputRecord(HandshakeHash handshakeHash,
+            TransportContext tc) {
+        super(handshakeHash, SSLCipher.SSLWriteCipher.nullTlsWriteCipher());
+        this.tc = tc;
         this.packetSize = SSLRecord.maxRecordSize;
-        this.protocolVersion = ProtocolVersion.DEFAULT_TLS;
+        this.protocolVersion = ProtocolVersion.NONE;
     }
 
     @Override
@@ -55,25 +60,22 @@
 
         write(level);
         write(description);
-
-        if (debug != null && Debug.isOn("record")) {
-            System.out.println(Thread.currentThread().getName() +
-                    ", WRITE: " + protocolVersion +
-                    " " + Record.contentName(Record.ct_alert) +
+        if (SSLLogger.isOn && SSLLogger.isOn("record")) {
+            SSLLogger.fine("WRITE: " + protocolVersion +
+                    " " + ContentType.ALERT.name +
                     ", length = " + (count - headerSize));
         }
 
         // Encrypt the fragment and wrap up a record.
-        encrypt(writeAuthenticator, writeCipher,
-                Record.ct_alert, headerSize);
+        encrypt(writeCipher, ContentType.ALERT.id, headerSize);
 
         // deliver this message
         deliverStream.write(buf, 0, count);    // may throw IOException
         deliverStream.flush();                 // may throw IOException
 
-        if (debug != null && Debug.isOn("packet")) {
-             Debug.printHex(
-                    "[Raw write]: length = " + count, buf, 0, count);
+        if (SSLLogger.isOn && SSLLogger.isOn("packet")) {
+            SSLLogger.fine("Raw write",
+                    (new ByteArrayInputStream(buf, 0, count)));
         }
 
         // reset the internal buffer
@@ -83,12 +85,11 @@
     @Override
     void encodeHandshake(byte[] source,
             int offset, int length) throws IOException {
-
         if (firstMessage) {
             firstMessage = false;
 
             if ((helloVersion == ProtocolVersion.SSL20Hello) &&
-                (source[offset] == HandshakeMessage.ht_client_hello) &&
+                (source[offset] == SSLHandshake.CLIENT_HELLO.id) &&
                                             //  5: recode header size
                 (source[offset + 4 + 2 + 32] == 0)) {
                                             // V3 session ID is empty
@@ -101,12 +102,12 @@
 
                 byte[] record = v2ClientHello.array();  // array offset is zero
                 int limit = v2ClientHello.limit();
-                handshakeHash.update(record, 2, (limit - 2));
+                handshakeHash.deliver(record, 2, (limit - 2));
 
-                if (debug != null && Debug.isOn("record")) {
-                     System.out.println(Thread.currentThread().getName() +
-                        ", WRITE: SSLv2 ClientHello message" +
-                        ", length = " + limit);
+                if (SSLLogger.isOn && SSLLogger.isOn("record")) {
+                    SSLLogger.fine(
+                            "WRITE: SSLv2 ClientHello message" +
+                            ", length = " + limit);
                 }
 
                 // deliver this message
@@ -117,9 +118,9 @@
                 deliverStream.write(record, 0, limit);
                 deliverStream.flush();
 
-                if (debug != null && Debug.isOn("packet")) {
-                     Debug.printHex(
-                            "[Raw write]: length = " + count, record, 0, limit);
+                if (SSLLogger.isOn && SSLLogger.isOn("packet")) {
+                    SSLLogger.fine("Raw write",
+                            (new ByteArrayInputStream(record, 0, limit)));
                 }
 
                 return;
@@ -127,8 +128,8 @@
         }
 
         byte handshakeType = source[0];
-        if (handshakeType != HandshakeMessage.ht_hello_request) {
-            handshakeHash.update(source, offset, length);
+        if (handshakeHash.isHashable(handshakeType)) {
+            handshakeHash.deliver(source, offset, length);
         }
 
         int fragLimit = getFragLimit();
@@ -153,24 +154,23 @@
                 return;
             }
 
-            if (debug != null && Debug.isOn("record")) {
-                System.out.println(Thread.currentThread().getName() +
-                        ", WRITE: " + protocolVersion +
-                        " " + Record.contentName(Record.ct_handshake) +
+            if (SSLLogger.isOn && SSLLogger.isOn("record")) {
+                SSLLogger.fine(
+                        "WRITE: " + protocolVersion +
+                        " " + ContentType.HANDSHAKE.name +
                         ", length = " + (count - headerSize));
             }
 
             // Encrypt the fragment and wrap up a record.
-            encrypt(writeAuthenticator, writeCipher,
-                    Record.ct_handshake, headerSize);
+            encrypt(writeCipher, ContentType.HANDSHAKE.id, headerSize);
 
             // deliver this message
             deliverStream.write(buf, 0, count);    // may throw IOException
             deliverStream.flush();                 // may throw IOException
 
-            if (debug != null && Debug.isOn("packet")) {
-                 Debug.printHex(
-                        "[Raw write]: length = " + count, buf, 0, count);
+            if (SSLLogger.isOn && SSLLogger.isOn("packet")) {
+                SSLLogger.fine("Raw write",
+                        (new ByteArrayInputStream(buf, 0, count)));
             }
 
             // reset the offset
@@ -190,24 +190,16 @@
 
         write((byte)1);         // byte 1: change_cipher_spec(
 
-        if (debug != null && Debug.isOn("record")) {
-            System.out.println(Thread.currentThread().getName() +
-                    ", WRITE: " + protocolVersion +
-                    " " + Record.contentName(Record.ct_change_cipher_spec) +
-                    ", length = " + (count - headerSize));
-        }
-
         // Encrypt the fragment and wrap up a record.
-        encrypt(writeAuthenticator, writeCipher,
-                Record.ct_change_cipher_spec, headerSize);
+        encrypt(writeCipher, ContentType.CHANGE_CIPHER_SPEC.id, headerSize);
 
         // deliver this message
         deliverStream.write(buf, 0, count);        // may throw IOException
         // deliverStream.flush();                  // flush in Finished
 
-        if (debug != null && Debug.isOn("packet")) {
-             Debug.printHex(
-                    "[Raw write]: length = " + count, buf, 0, count);
+        if (SSLLogger.isOn && SSLLogger.isOn("packet")) {
+            SSLLogger.fine("Raw write",
+                    (new ByteArrayInputStream(buf, 0, count)));
         }
 
         // reset the internal buffer
@@ -221,24 +213,23 @@
             return;
         }
 
-        if (debug != null && Debug.isOn("record")) {
-            System.out.println(Thread.currentThread().getName() +
-                    ", WRITE: " + protocolVersion +
-                    " " + Record.contentName(Record.ct_handshake) +
+        if (SSLLogger.isOn && SSLLogger.isOn("record")) {
+            SSLLogger.fine(
+                    "WRITE: " + protocolVersion +
+                    " " + ContentType.HANDSHAKE.name +
                     ", length = " + (count - headerSize));
         }
 
         // Encrypt the fragment and wrap up a record.
-        encrypt(writeAuthenticator, writeCipher,
-                    Record.ct_handshake, headerSize);
+        encrypt(writeCipher, ContentType.HANDSHAKE.id, headerSize);
 
         // deliver this message
         deliverStream.write(buf, 0, count);    // may throw IOException
         deliverStream.flush();                 // may throw IOException
 
-        if (debug != null && Debug.isOn("packet")) {
-             Debug.printHex(
-                    "[Raw write]: length = " + count, buf, 0, count);
+        if (SSLLogger.isOn && SSLLogger.isOn("packet")) {
+            SSLLogger.fine("Raw write",
+                    (new ByteArrayInputStream(buf, 0, count)));
         }
 
         // reset the internal buffer
@@ -247,11 +238,10 @@
 
     @Override
     void deliver(byte[] source, int offset, int length) throws IOException {
-
-        if (writeAuthenticator.seqNumOverflow()) {
-            if (debug != null && Debug.isOn("ssl")) {
-                System.out.println(Thread.currentThread().getName() +
-                    ", sequence number extremely close to overflow " +
+        if (writeCipher.authenticator.seqNumOverflow()) {
+            if (SSLLogger.isOn && SSLLogger.isOn("ssl")) {
+                SSLLogger.fine(
+                    "sequence number extremely close to overflow " +
                     "(2^64-1 packets). Closing connection.");
             }
 
@@ -260,16 +250,11 @@
 
         boolean isFirstRecordOfThePayload = true;
         for (int limit = (offset + length); offset < limit;) {
-            int macLen = 0;
-            if (writeAuthenticator instanceof MAC) {
-                macLen = ((MAC)writeAuthenticator).MAClen();
-            }
-
             int fragLen;
             if (packetSize > 0) {
                 fragLen = Math.min(maxRecordSize, packetSize);
-                fragLen = writeCipher.calculateFragmentSize(
-                        fragLen, macLen, headerSize);
+                fragLen =
+                        writeCipher.calculateFragmentSize(fragLen, headerSize);
 
                 fragLen = Math.min(fragLen, Record.maxDataSize);
             } else {
@@ -292,24 +277,23 @@
             count = position;
             write(source, offset, fragLen);
 
-            if (debug != null && Debug.isOn("record")) {
-                System.out.println(Thread.currentThread().getName() +
-                        ", WRITE: " + protocolVersion +
-                        " " + Record.contentName(Record.ct_application_data) +
-                        ", length = " + (count - headerSize));
+            if (SSLLogger.isOn && SSLLogger.isOn("record")) {
+                SSLLogger.fine(
+                        "WRITE: " + protocolVersion +
+                        " " + ContentType.APPLICATION_DATA.name +
+                        ", length = " + (count - position));
             }
 
             // Encrypt the fragment and wrap up a record.
-            encrypt(writeAuthenticator, writeCipher,
-                    Record.ct_application_data, headerSize);
+            encrypt(writeCipher, ContentType.APPLICATION_DATA.id, headerSize);
 
             // deliver this message
             deliverStream.write(buf, 0, count);    // may throw IOException
             deliverStream.flush();                 // may throw IOException
 
-            if (debug != null && Debug.isOn("packet")) {
-                 Debug.printHex(
-                        "[Raw write]: length = " + count, buf, 0, count);
+            if (SSLLogger.isOn && SSLLogger.isOn("packet")) {
+                SSLLogger.fine("Raw write",
+                        (new ByteArrayInputStream(buf, 0, count)));
             }
 
             // reset the internal buffer
@@ -320,6 +304,18 @@
             }
 
             offset += fragLen;
+
+            // atKeyLimit() inactive when limits not checked, tc set when limits
+            // are active.
+            if (writeCipher.atKeyLimit()) {
+                if (SSLLogger.isOn && SSLLogger.isOn("ssl")) {
+                    SSLLogger.fine("KeyUpdate: triggered, write side.");
+                }
+
+                PostHandshakeContext p = new PostHandshakeContext(tc);
+                KeyUpdate.handshakeProducer.produce(p,
+                        new KeyUpdateMessage(p, KeyUpdateRequest.REQUESTED));
+            }
         }
     }
 
@@ -358,16 +354,11 @@
     }
 
     private int getFragLimit() {
-        int macLen = 0;
-        if (writeAuthenticator instanceof MAC) {
-            macLen = ((MAC)writeAuthenticator).MAClen();
-        }
-
         int fragLimit;
         if (packetSize > 0) {
             fragLimit = Math.min(maxRecordSize, packetSize);
-            fragLimit = writeCipher.calculateFragmentSize(
-                    fragLimit, macLen, headerSize);
+            fragLimit =
+                    writeCipher.calculateFragmentSize(fragLimit, headerSize);
 
             fragLimit = Math.min(fragLimit, Record.maxDataSize);
         } else {