src/java.base/share/classes/sun/security/ssl/SSLSocketOutputRecord.java
changeset 50768 68fa3d4026ea
parent 47216 71c04702a3d5
child 51407 910f7b56592f
equal deleted inserted replaced
50767:356eaea05bf0 50768:68fa3d4026ea
     1 /*
     1 /*
     2  * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
     2  * Copyright (c) 1996, 2018, Oracle and/or its affiliates. All rights reserved.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     4  *
     4  *
     5  * This code is free software; you can redistribute it and/or modify it
     5  * This code is free software; you can redistribute it and/or modify it
     6  * under the terms of the GNU General Public License version 2 only, as
     6  * under the terms of the GNU General Public License version 2 only, as
     7  * published by the Free Software Foundation.  Oracle designates this
     7  * published by the Free Software Foundation.  Oracle designates this
    23  * questions.
    23  * questions.
    24  */
    24  */
    25 
    25 
    26 package sun.security.ssl;
    26 package sun.security.ssl;
    27 
    27 
    28 import java.io.*;
    28 import java.io.ByteArrayInputStream;
    29 import java.nio.*;
    29 import java.io.IOException;
    30 import java.util.Arrays;
    30 import java.io.OutputStream;
    31 
    31 import java.nio.ByteBuffer;
    32 import javax.net.ssl.SSLException;
       
    33 import javax.net.ssl.SSLHandshakeException;
    32 import javax.net.ssl.SSLHandshakeException;
    34 import sun.security.util.HexDumpEncoder;
    33 
    35 
    34 import sun.security.ssl.KeyUpdate.KeyUpdateMessage;
       
    35 import sun.security.ssl.KeyUpdate.KeyUpdateRequest;
    36 
    36 
    37 /**
    37 /**
    38  * {@code OutputRecord} implementation for {@code SSLSocket}.
    38  * {@code OutputRecord} implementation for {@code SSLSocket}.
    39  */
    39  */
    40 final class SSLSocketOutputRecord extends OutputRecord implements SSLRecord {
    40 final class SSLSocketOutputRecord extends OutputRecord implements SSLRecord {
    41     private OutputStream deliverStream = null;
    41     private OutputStream deliverStream = null;
    42 
    42 
    43     SSLSocketOutputRecord() {
    43     SSLSocketOutputRecord(HandshakeHash handshakeHash) {
    44         this.writeAuthenticator = MAC.TLS_NULL;
    44         this(handshakeHash, null);
    45 
    45     }
       
    46 
       
    47     SSLSocketOutputRecord(HandshakeHash handshakeHash,
       
    48             TransportContext tc) {
       
    49         super(handshakeHash, SSLCipher.SSLWriteCipher.nullTlsWriteCipher());
       
    50         this.tc = tc;
    46         this.packetSize = SSLRecord.maxRecordSize;
    51         this.packetSize = SSLRecord.maxRecordSize;
    47         this.protocolVersion = ProtocolVersion.DEFAULT_TLS;
    52         this.protocolVersion = ProtocolVersion.NONE;
    48     }
    53     }
    49 
    54 
    50     @Override
    55     @Override
    51     void encodeAlert(byte level, byte description) throws IOException {
    56     void encodeAlert(byte level, byte description) throws IOException {
    52         // use the buf of ByteArrayOutputStream
    57         // use the buf of ByteArrayOutputStream
    53         int position = headerSize + writeCipher.getExplicitNonceSize();
    58         int position = headerSize + writeCipher.getExplicitNonceSize();
    54         count = position;
    59         count = position;
    55 
    60 
    56         write(level);
    61         write(level);
    57         write(description);
    62         write(description);
    58 
    63         if (SSLLogger.isOn && SSLLogger.isOn("record")) {
    59         if (debug != null && Debug.isOn("record")) {
    64             SSLLogger.fine("WRITE: " + protocolVersion +
    60             System.out.println(Thread.currentThread().getName() +
    65                     " " + ContentType.ALERT.name +
    61                     ", WRITE: " + protocolVersion +
       
    62                     " " + Record.contentName(Record.ct_alert) +
       
    63                     ", length = " + (count - headerSize));
    66                     ", length = " + (count - headerSize));
    64         }
    67         }
    65 
    68 
    66         // Encrypt the fragment and wrap up a record.
    69         // Encrypt the fragment and wrap up a record.
    67         encrypt(writeAuthenticator, writeCipher,
    70         encrypt(writeCipher, ContentType.ALERT.id, headerSize);
    68                 Record.ct_alert, headerSize);
       
    69 
    71 
    70         // deliver this message
    72         // deliver this message
    71         deliverStream.write(buf, 0, count);    // may throw IOException
    73         deliverStream.write(buf, 0, count);    // may throw IOException
    72         deliverStream.flush();                 // may throw IOException
    74         deliverStream.flush();                 // may throw IOException
    73 
    75 
    74         if (debug != null && Debug.isOn("packet")) {
    76         if (SSLLogger.isOn && SSLLogger.isOn("packet")) {
    75              Debug.printHex(
    77             SSLLogger.fine("Raw write",
    76                     "[Raw write]: length = " + count, buf, 0, count);
    78                     (new ByteArrayInputStream(buf, 0, count)));
    77         }
    79         }
    78 
    80 
    79         // reset the internal buffer
    81         // reset the internal buffer
    80         count = 0;
    82         count = 0;
    81     }
    83     }
    82 
    84 
    83     @Override
    85     @Override
    84     void encodeHandshake(byte[] source,
    86     void encodeHandshake(byte[] source,
    85             int offset, int length) throws IOException {
    87             int offset, int length) throws IOException {
    86 
       
    87         if (firstMessage) {
    88         if (firstMessage) {
    88             firstMessage = false;
    89             firstMessage = false;
    89 
    90 
    90             if ((helloVersion == ProtocolVersion.SSL20Hello) &&
    91             if ((helloVersion == ProtocolVersion.SSL20Hello) &&
    91                 (source[offset] == HandshakeMessage.ht_client_hello) &&
    92                 (source[offset] == SSLHandshake.CLIENT_HELLO.id) &&
    92                                             //  5: recode header size
    93                                             //  5: recode header size
    93                 (source[offset + 4 + 2 + 32] == 0)) {
    94                 (source[offset + 4 + 2 + 32] == 0)) {
    94                                             // V3 session ID is empty
    95                                             // V3 session ID is empty
    95                                             //  4: handshake header size
    96                                             //  4: handshake header size
    96                                             //  2: client_version in ClientHello
    97                                             //  2: client_version in ClientHello
    99                 ByteBuffer v2ClientHello = encodeV2ClientHello(
   100                 ByteBuffer v2ClientHello = encodeV2ClientHello(
   100                         source, (offset + 4), (length - 4));
   101                         source, (offset + 4), (length - 4));
   101 
   102 
   102                 byte[] record = v2ClientHello.array();  // array offset is zero
   103                 byte[] record = v2ClientHello.array();  // array offset is zero
   103                 int limit = v2ClientHello.limit();
   104                 int limit = v2ClientHello.limit();
   104                 handshakeHash.update(record, 2, (limit - 2));
   105                 handshakeHash.deliver(record, 2, (limit - 2));
   105 
   106 
   106                 if (debug != null && Debug.isOn("record")) {
   107                 if (SSLLogger.isOn && SSLLogger.isOn("record")) {
   107                      System.out.println(Thread.currentThread().getName() +
   108                     SSLLogger.fine(
   108                         ", WRITE: SSLv2 ClientHello message" +
   109                             "WRITE: SSLv2 ClientHello message" +
   109                         ", length = " + limit);
   110                             ", length = " + limit);
   110                 }
   111                 }
   111 
   112 
   112                 // deliver this message
   113                 // deliver this message
   113                 //
   114                 //
   114                 // Version 2 ClientHello message should be plaintext.
   115                 // Version 2 ClientHello message should be plaintext.
   115                 //
   116                 //
   116                 // No max fragment length negotiation.
   117                 // No max fragment length negotiation.
   117                 deliverStream.write(record, 0, limit);
   118                 deliverStream.write(record, 0, limit);
   118                 deliverStream.flush();
   119                 deliverStream.flush();
   119 
   120 
   120                 if (debug != null && Debug.isOn("packet")) {
   121                 if (SSLLogger.isOn && SSLLogger.isOn("packet")) {
   121                      Debug.printHex(
   122                     SSLLogger.fine("Raw write",
   122                             "[Raw write]: length = " + count, record, 0, limit);
   123                             (new ByteArrayInputStream(record, 0, limit)));
   123                 }
   124                 }
   124 
   125 
   125                 return;
   126                 return;
   126             }
   127             }
   127         }
   128         }
   128 
   129 
   129         byte handshakeType = source[0];
   130         byte handshakeType = source[0];
   130         if (handshakeType != HandshakeMessage.ht_hello_request) {
   131         if (handshakeHash.isHashable(handshakeType)) {
   131             handshakeHash.update(source, offset, length);
   132             handshakeHash.deliver(source, offset, length);
   132         }
   133         }
   133 
   134 
   134         int fragLimit = getFragLimit();
   135         int fragLimit = getFragLimit();
   135         int position = headerSize + writeCipher.getExplicitNonceSize();
   136         int position = headerSize + writeCipher.getExplicitNonceSize();
   136         if (count == 0) {
   137         if (count == 0) {
   151             write(source, offset, fragLen);
   152             write(source, offset, fragLen);
   152             if (remains < fragLimit) {
   153             if (remains < fragLimit) {
   153                 return;
   154                 return;
   154             }
   155             }
   155 
   156 
   156             if (debug != null && Debug.isOn("record")) {
   157             if (SSLLogger.isOn && SSLLogger.isOn("record")) {
   157                 System.out.println(Thread.currentThread().getName() +
   158                 SSLLogger.fine(
   158                         ", WRITE: " + protocolVersion +
   159                         "WRITE: " + protocolVersion +
   159                         " " + Record.contentName(Record.ct_handshake) +
   160                         " " + ContentType.HANDSHAKE.name +
   160                         ", length = " + (count - headerSize));
   161                         ", length = " + (count - headerSize));
   161             }
   162             }
   162 
   163 
   163             // Encrypt the fragment and wrap up a record.
   164             // Encrypt the fragment and wrap up a record.
   164             encrypt(writeAuthenticator, writeCipher,
   165             encrypt(writeCipher, ContentType.HANDSHAKE.id, headerSize);
   165                     Record.ct_handshake, headerSize);
       
   166 
   166 
   167             // deliver this message
   167             // deliver this message
   168             deliverStream.write(buf, 0, count);    // may throw IOException
   168             deliverStream.write(buf, 0, count);    // may throw IOException
   169             deliverStream.flush();                 // may throw IOException
   169             deliverStream.flush();                 // may throw IOException
   170 
   170 
   171             if (debug != null && Debug.isOn("packet")) {
   171             if (SSLLogger.isOn && SSLLogger.isOn("packet")) {
   172                  Debug.printHex(
   172                 SSLLogger.fine("Raw write",
   173                         "[Raw write]: length = " + count, buf, 0, count);
   173                         (new ByteArrayInputStream(buf, 0, count)));
   174             }
   174             }
   175 
   175 
   176             // reset the offset
   176             // reset the offset
   177             offset += fragLen;
   177             offset += fragLen;
   178 
   178 
   188         int position = headerSize + writeCipher.getExplicitNonceSize();
   188         int position = headerSize + writeCipher.getExplicitNonceSize();
   189         count = position;
   189         count = position;
   190 
   190 
   191         write((byte)1);         // byte 1: change_cipher_spec(
   191         write((byte)1);         // byte 1: change_cipher_spec(
   192 
   192 
   193         if (debug != null && Debug.isOn("record")) {
       
   194             System.out.println(Thread.currentThread().getName() +
       
   195                     ", WRITE: " + protocolVersion +
       
   196                     " " + Record.contentName(Record.ct_change_cipher_spec) +
       
   197                     ", length = " + (count - headerSize));
       
   198         }
       
   199 
       
   200         // Encrypt the fragment and wrap up a record.
   193         // Encrypt the fragment and wrap up a record.
   201         encrypt(writeAuthenticator, writeCipher,
   194         encrypt(writeCipher, ContentType.CHANGE_CIPHER_SPEC.id, headerSize);
   202                 Record.ct_change_cipher_spec, headerSize);
       
   203 
   195 
   204         // deliver this message
   196         // deliver this message
   205         deliverStream.write(buf, 0, count);        // may throw IOException
   197         deliverStream.write(buf, 0, count);        // may throw IOException
   206         // deliverStream.flush();                  // flush in Finished
   198         // deliverStream.flush();                  // flush in Finished
   207 
   199 
   208         if (debug != null && Debug.isOn("packet")) {
   200         if (SSLLogger.isOn && SSLLogger.isOn("packet")) {
   209              Debug.printHex(
   201             SSLLogger.fine("Raw write",
   210                     "[Raw write]: length = " + count, buf, 0, count);
   202                     (new ByteArrayInputStream(buf, 0, count)));
   211         }
   203         }
   212 
   204 
   213         // reset the internal buffer
   205         // reset the internal buffer
   214         count = 0;
   206         count = 0;
   215     }
   207     }
   219         int position = headerSize + writeCipher.getExplicitNonceSize();
   211         int position = headerSize + writeCipher.getExplicitNonceSize();
   220         if (count <= position) {
   212         if (count <= position) {
   221             return;
   213             return;
   222         }
   214         }
   223 
   215 
   224         if (debug != null && Debug.isOn("record")) {
   216         if (SSLLogger.isOn && SSLLogger.isOn("record")) {
   225             System.out.println(Thread.currentThread().getName() +
   217             SSLLogger.fine(
   226                     ", WRITE: " + protocolVersion +
   218                     "WRITE: " + protocolVersion +
   227                     " " + Record.contentName(Record.ct_handshake) +
   219                     " " + ContentType.HANDSHAKE.name +
   228                     ", length = " + (count - headerSize));
   220                     ", length = " + (count - headerSize));
   229         }
   221         }
   230 
   222 
   231         // Encrypt the fragment and wrap up a record.
   223         // Encrypt the fragment and wrap up a record.
   232         encrypt(writeAuthenticator, writeCipher,
   224         encrypt(writeCipher, ContentType.HANDSHAKE.id, headerSize);
   233                     Record.ct_handshake, headerSize);
       
   234 
   225 
   235         // deliver this message
   226         // deliver this message
   236         deliverStream.write(buf, 0, count);    // may throw IOException
   227         deliverStream.write(buf, 0, count);    // may throw IOException
   237         deliverStream.flush();                 // may throw IOException
   228         deliverStream.flush();                 // may throw IOException
   238 
   229 
   239         if (debug != null && Debug.isOn("packet")) {
   230         if (SSLLogger.isOn && SSLLogger.isOn("packet")) {
   240              Debug.printHex(
   231             SSLLogger.fine("Raw write",
   241                     "[Raw write]: length = " + count, buf, 0, count);
   232                     (new ByteArrayInputStream(buf, 0, count)));
   242         }
   233         }
   243 
   234 
   244         // reset the internal buffer
   235         // reset the internal buffer
   245         count = 0;      // DON'T use position
   236         count = 0;      // DON'T use position
   246     }
   237     }
   247 
   238 
   248     @Override
   239     @Override
   249     void deliver(byte[] source, int offset, int length) throws IOException {
   240     void deliver(byte[] source, int offset, int length) throws IOException {
   250 
   241         if (writeCipher.authenticator.seqNumOverflow()) {
   251         if (writeAuthenticator.seqNumOverflow()) {
   242             if (SSLLogger.isOn && SSLLogger.isOn("ssl")) {
   252             if (debug != null && Debug.isOn("ssl")) {
   243                 SSLLogger.fine(
   253                 System.out.println(Thread.currentThread().getName() +
   244                     "sequence number extremely close to overflow " +
   254                     ", sequence number extremely close to overflow " +
       
   255                     "(2^64-1 packets). Closing connection.");
   245                     "(2^64-1 packets). Closing connection.");
   256             }
   246             }
   257 
   247 
   258             throw new SSLHandshakeException("sequence number overflow");
   248             throw new SSLHandshakeException("sequence number overflow");
   259         }
   249         }
   260 
   250 
   261         boolean isFirstRecordOfThePayload = true;
   251         boolean isFirstRecordOfThePayload = true;
   262         for (int limit = (offset + length); offset < limit;) {
   252         for (int limit = (offset + length); offset < limit;) {
   263             int macLen = 0;
       
   264             if (writeAuthenticator instanceof MAC) {
       
   265                 macLen = ((MAC)writeAuthenticator).MAClen();
       
   266             }
       
   267 
       
   268             int fragLen;
   253             int fragLen;
   269             if (packetSize > 0) {
   254             if (packetSize > 0) {
   270                 fragLen = Math.min(maxRecordSize, packetSize);
   255                 fragLen = Math.min(maxRecordSize, packetSize);
   271                 fragLen = writeCipher.calculateFragmentSize(
   256                 fragLen =
   272                         fragLen, macLen, headerSize);
   257                         writeCipher.calculateFragmentSize(fragLen, headerSize);
   273 
   258 
   274                 fragLen = Math.min(fragLen, Record.maxDataSize);
   259                 fragLen = Math.min(fragLen, Record.maxDataSize);
   275             } else {
   260             } else {
   276                 fragLen = Record.maxDataSize;
   261                 fragLen = Record.maxDataSize;
   277             }
   262             }
   290             // use the buf of ByteArrayOutputStream
   275             // use the buf of ByteArrayOutputStream
   291             int position = headerSize + writeCipher.getExplicitNonceSize();
   276             int position = headerSize + writeCipher.getExplicitNonceSize();
   292             count = position;
   277             count = position;
   293             write(source, offset, fragLen);
   278             write(source, offset, fragLen);
   294 
   279 
   295             if (debug != null && Debug.isOn("record")) {
   280             if (SSLLogger.isOn && SSLLogger.isOn("record")) {
   296                 System.out.println(Thread.currentThread().getName() +
   281                 SSLLogger.fine(
   297                         ", WRITE: " + protocolVersion +
   282                         "WRITE: " + protocolVersion +
   298                         " " + Record.contentName(Record.ct_application_data) +
   283                         " " + ContentType.APPLICATION_DATA.name +
   299                         ", length = " + (count - headerSize));
   284                         ", length = " + (count - position));
   300             }
   285             }
   301 
   286 
   302             // Encrypt the fragment and wrap up a record.
   287             // Encrypt the fragment and wrap up a record.
   303             encrypt(writeAuthenticator, writeCipher,
   288             encrypt(writeCipher, ContentType.APPLICATION_DATA.id, headerSize);
   304                     Record.ct_application_data, headerSize);
       
   305 
   289 
   306             // deliver this message
   290             // deliver this message
   307             deliverStream.write(buf, 0, count);    // may throw IOException
   291             deliverStream.write(buf, 0, count);    // may throw IOException
   308             deliverStream.flush();                 // may throw IOException
   292             deliverStream.flush();                 // may throw IOException
   309 
   293 
   310             if (debug != null && Debug.isOn("packet")) {
   294             if (SSLLogger.isOn && SSLLogger.isOn("packet")) {
   311                  Debug.printHex(
   295                 SSLLogger.fine("Raw write",
   312                         "[Raw write]: length = " + count, buf, 0, count);
   296                         (new ByteArrayInputStream(buf, 0, count)));
   313             }
   297             }
   314 
   298 
   315             // reset the internal buffer
   299             // reset the internal buffer
   316             count = 0;
   300             count = 0;
   317 
   301 
   318             if (isFirstAppOutputRecord) {
   302             if (isFirstAppOutputRecord) {
   319                 isFirstAppOutputRecord = false;
   303                 isFirstAppOutputRecord = false;
   320             }
   304             }
   321 
   305 
   322             offset += fragLen;
   306             offset += fragLen;
       
   307 
       
   308             // atKeyLimit() inactive when limits not checked, tc set when limits
       
   309             // are active.
       
   310             if (writeCipher.atKeyLimit()) {
       
   311                 if (SSLLogger.isOn && SSLLogger.isOn("ssl")) {
       
   312                     SSLLogger.fine("KeyUpdate: triggered, write side.");
       
   313                 }
       
   314 
       
   315                 PostHandshakeContext p = new PostHandshakeContext(tc);
       
   316                 KeyUpdate.handshakeProducer.produce(p,
       
   317                         new KeyUpdateMessage(p, KeyUpdateRequest.REQUESTED));
       
   318             }
   323         }
   319         }
   324     }
   320     }
   325 
   321 
   326     @Override
   322     @Override
   327     void setDeliverStream(OutputStream outputStream) {
   323     void setDeliverStream(OutputStream outputStream) {
   356                 writeCipher.isCBCMode() && !isFirstAppOutputRecord &&
   352                 writeCipher.isCBCMode() && !isFirstAppOutputRecord &&
   357                 Record.enableCBCProtection;
   353                 Record.enableCBCProtection;
   358     }
   354     }
   359 
   355 
   360     private int getFragLimit() {
   356     private int getFragLimit() {
   361         int macLen = 0;
       
   362         if (writeAuthenticator instanceof MAC) {
       
   363             macLen = ((MAC)writeAuthenticator).MAClen();
       
   364         }
       
   365 
       
   366         int fragLimit;
   357         int fragLimit;
   367         if (packetSize > 0) {
   358         if (packetSize > 0) {
   368             fragLimit = Math.min(maxRecordSize, packetSize);
   359             fragLimit = Math.min(maxRecordSize, packetSize);
   369             fragLimit = writeCipher.calculateFragmentSize(
   360             fragLimit =
   370                     fragLimit, macLen, headerSize);
   361                     writeCipher.calculateFragmentSize(fragLimit, headerSize);
   371 
   362 
   372             fragLimit = Math.min(fragLimit, Record.maxDataSize);
   363             fragLimit = Math.min(fragLimit, Record.maxDataSize);
   373         } else {
   364         } else {
   374             fragLimit = Record.maxDataSize;
   365             fragLimit = Record.maxDataSize;
   375         }
   366         }