< prev index next >

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

Print this page


   1 /*
   2  * Copyright (c) 1996, 2016, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   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
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package sun.security.ssl;
  27 
  28 import java.io.*;
  29 import java.nio.*;
  30 import java.util.Arrays;
  31 
  32 import javax.net.ssl.SSLException;
  33 import sun.security.util.HexDumpEncoder;
  34 
  35 
  36 /**
  37  * {@code OutputRecord} takes care of the management of SSL/TLS/DTLS output
  38  * records, including buffering, encryption, handshake messages marshal, etc.

  39  *
  40  * @author David Brownell
  41  */
  42 abstract class OutputRecord extends ByteArrayOutputStream
  43             implements Record, Closeable {
  44 
  45     /* Class and subclass dynamic debugging support */
  46     static final Debug          debug = Debug.getInstance("ssl");
  47 
  48     Authenticator               writeAuthenticator;
  49     CipherBox                   writeCipher;
  50 
  51     HandshakeHash               handshakeHash;
  52     boolean                     firstMessage;
  53 
  54     // current protocol version, sent as record version
  55     ProtocolVersion             protocolVersion;
  56 
  57     // version for the ClientHello message. Only relevant if this is a
  58     // client handshake record. If set to ProtocolVersion.SSL20Hello,
  59     // the V3 client hello is converted to V2 format.
  60     ProtocolVersion             helloVersion;
  61 
  62     // Is it the first application record to write?
  63     boolean                     isFirstAppOutputRecord = true;
  64 
  65     // packet size
  66     int                         packetSize;
  67 
  68     // fragment size
  69     int                         fragmentSize;
  70 
  71     // closed or not?
  72     boolean                     isClosed;
  73 
  74     /*
  75      * Mappings from V3 cipher suite encodings to their pure V2 equivalents.
  76      * This is taken from the SSL V3 specification, Appendix E.
  77      */
  78     private static int[] V3toV2CipherMap1 =
  79         {-1, -1, -1, 0x02, 0x01, -1, 0x04, 0x05, -1, 0x06, 0x07};
  80     private static int[] V3toV2CipherMap3 =
  81         {-1, -1, -1, 0x80, 0x80, -1, 0x80, 0x80, -1, 0x40, 0xC0};
  82 
  83     OutputRecord() {
  84         this.writeCipher = CipherBox.NULL;
  85         this.firstMessage = true;
  86         this.fragmentSize = Record.maxDataSize;
  87 


  88         // Please set packetSize and protocolVersion in the implementation.
  89     }
  90 
  91     void setVersion(ProtocolVersion protocolVersion) {
  92         this.protocolVersion = protocolVersion;
  93     }
  94 
  95     /*
  96      * Updates helloVersion of this record.
  97      */
  98     synchronized void setHelloVersion(ProtocolVersion helloVersion) {
  99         this.helloVersion = helloVersion;
 100     }
 101 
 102     /*
 103      * For handshaking, we need to be able to hash every byte above the
 104      * record marking layer.  This is where we're guaranteed to see those
 105      * bytes, so this is where we can hash them.
 106      */
 107     void setHandshakeHash(HandshakeHash handshakeHash) {
 108         this.handshakeHash = handshakeHash;
 109     }
 110 
 111     /*
 112      * Return true iff the record is empty -- to avoid doing the work
 113      * of sending empty records over the network.
 114      */
 115     boolean isEmpty() {
 116         return false;
 117     }
 118 
 119     boolean seqNumIsHuge() {
 120         return (writeAuthenticator != null) &&
 121                         writeAuthenticator.seqNumIsHuge();
 122     }
 123 
 124     // SSLEngine and SSLSocket
 125     abstract void encodeAlert(byte level, byte description) throws IOException;
 126 
 127     // SSLEngine and SSLSocket
 128     abstract void encodeHandshake(byte[] buffer,
 129             int offset, int length) throws IOException;
 130 
 131     // SSLEngine and SSLSocket
 132     abstract void encodeChangeCipherSpec() throws IOException;
 133 
 134     // apply to SSLEngine only
 135     Ciphertext encode(ByteBuffer[] sources, int offset, int length,
 136             ByteBuffer destination) throws IOException {


 137         throw new UnsupportedOperationException();
 138     }
 139 
 140     // apply to SSLEngine only
 141     void encodeV2NoCipher() throws IOException {
 142         throw new UnsupportedOperationException();
 143     }
 144 
 145     // apply to SSLSocket only
 146     void deliver(byte[] source, int offset, int length) throws IOException {

 147         throw new UnsupportedOperationException();
 148     }
 149 
 150     // apply to SSLSocket only
 151     void setDeliverStream(OutputStream outputStream) {
 152         throw new UnsupportedOperationException();
 153     }
 154 
 155     // apply to SSLEngine only
 156     Ciphertext acquireCiphertext(ByteBuffer destination) throws IOException {
 157         throw new UnsupportedOperationException();
 158     }
 159 
 160     void changeWriteCiphers(Authenticator writeAuthenticator,
 161             CipherBox writeCipher) throws IOException {
 162 
 163         encodeChangeCipherSpec();

 164 
 165         /*
 166          * Dispose of any intermediate state in the underlying cipher.
 167          * For PKCS11 ciphers, this will release any attached sessions,
 168          * and thus make finalization faster.
 169          *
 170          * Since MAC's doFinal() is called for every SSL/TLS packet, it's
 171          * not necessary to do the same with MAC's.
 172          */
 173         writeCipher.dispose();
 174 
 175         this.writeAuthenticator = writeAuthenticator;
 176         this.writeCipher = writeCipher;
 177         this.isFirstAppOutputRecord = true;
 178     }
 179 
 180     void changePacketSize(int packetSize) {
 181         this.packetSize = packetSize;
 182     }
 183 
 184     void changeFragmentSize(int fragmentSize) {
 185         this.fragmentSize = fragmentSize;
 186     }
 187 
 188     int getMaxPacketSize() {
 189         return packetSize;
 190     }
 191 
 192     // apply to DTLS SSLEngine
 193     void initHandshaker() {
 194         // blank
 195     }
 196 
 197     // apply to DTLS SSLEngine





 198     void launchRetransmission() {
 199         // blank
 200     }
 201 
 202     @Override
 203     public synchronized void close() throws IOException {
 204         if (!isClosed) {
 205             isClosed = true;
 206             writeCipher.dispose();
 207         }
 208     }
 209 




 210     //
 211     // shared helpers
 212     //
 213 
 214     // Encrypt a fragment and wrap up a record.
 215     //
 216     // To be consistent with the spec of SSLEngine.wrap() methods, the
 217     // destination ByteBuffer's position is updated to reflect the amount
 218     // of data produced.  The limit remains the same.
 219     static long encrypt(Authenticator authenticator,
 220             CipherBox encCipher, byte contentType, ByteBuffer destination,
 221             int headerOffset, int dstLim, int headerSize,
 222             ProtocolVersion protocolVersion, boolean isDTLS) {
 223 
 224         byte[] sequenceNumber = null;
 225         int dstContent = destination.position();
 226 
 227         // Acquire the current sequence number before using.
 228         if (isDTLS) {
 229             sequenceNumber = authenticator.sequenceNumber();







 230         }
 231 
 232         // The sequence number may be shared for different purpose.
 233         boolean sharedSequenceNumber = false;
 234 
 235         // "flip" but skip over header again, add MAC & encrypt
 236         if (authenticator instanceof MAC) {
 237             MAC signer = (MAC)authenticator;
 238             if (signer.MAClen() != 0) {
 239                 byte[] hash = signer.compute(contentType, destination, false);
 240 
 241                 /*
 242                  * position was advanced to limit in MAC compute above.
 243                  *
 244                  * Mark next area as writable (above layers should have
 245                  * established that we have plenty of room), then write
 246                  * out the hash.
 247                  */
 248                 destination.limit(destination.limit() + hash.length);
 249                 destination.put(hash);
 250 
 251                 // reset the position and limit
 252                 destination.limit(destination.position());
 253                 destination.position(dstContent);
 254 
 255                 // The signer has used and increased the sequence number.
 256                 if (isDTLS) {
 257                     sharedSequenceNumber = true;
 258                 }
 259             }
 260         }
 261 
 262         if (!encCipher.isNullCipher()) {
 263             if (protocolVersion.useTLS11PlusSpec() &&
 264                     (encCipher.isCBCMode() || encCipher.isAEADMode())) {
 265                 byte[] nonce = encCipher.createExplicitNonce(
 266                         authenticator, contentType, destination.remaining());
 267                 destination.position(headerOffset + headerSize);
 268                 destination.put(nonce);
 269             }
 270             if (!encCipher.isAEADMode()) {
 271                 // The explicit IV in TLS 1.1 and later can be encrypted.
 272                 destination.position(headerOffset + headerSize);
 273             }   // Otherwise, DON'T encrypt the nonce_explicit for AEAD mode
 274 
 275             // Encrypt may pad, so again the limit may be changed.
 276             encCipher.encrypt(destination, dstLim);
 277 
 278             // The cipher has used and increased the sequence number.
 279             if (isDTLS && encCipher.isAEADMode()) {
 280                 sharedSequenceNumber = true;
 281             }
 282         } else {
 283             destination.position(destination.limit());
 284         }
 285 







 286         // Finish out the record header.
 287         int fragLen = destination.limit() - headerOffset - headerSize;
 288 
 289         destination.put(headerOffset, contentType);         // content type
 290         destination.put(headerOffset + 1, protocolVersion.major);
 291         destination.put(headerOffset + 2, protocolVersion.minor);
 292         if (!isDTLS) {
 293             // fragment length
 294             destination.put(headerOffset + 3, (byte)(fragLen >> 8));
 295             destination.put(headerOffset + 4, (byte)fragLen);
 296         } else {
 297             // epoch and sequence_number
 298             destination.put(headerOffset + 3, sequenceNumber[0]);
 299             destination.put(headerOffset + 4, sequenceNumber[1]);
 300             destination.put(headerOffset + 5, sequenceNumber[2]);
 301             destination.put(headerOffset + 6, sequenceNumber[3]);
 302             destination.put(headerOffset + 7, sequenceNumber[4]);
 303             destination.put(headerOffset + 8, sequenceNumber[5]);
 304             destination.put(headerOffset + 9, sequenceNumber[6]);
 305             destination.put(headerOffset + 10, sequenceNumber[7]);
 306 
 307             // fragment length
 308             destination.put(headerOffset + 11, (byte)(fragLen >> 8));
 309             destination.put(headerOffset + 12, (byte)fragLen);
 310 
 311             // Increase the sequence number for next use if it is not shared.
 312             if (!sharedSequenceNumber) {
 313                 authenticator.increaseSequenceNumber();























 314             }


















 315         }
 316 


















 317         // Update destination position to reflect the amount of data produced.
 318         destination.position(destination.limit());
 319 
 320         return Authenticator.toLong(sequenceNumber);
 321     }
 322 
 323     // Encrypt a fragment and wrap up a record.
 324     //
 325     // Uses the internal expandable buf variable and the current
 326     // protocolVersion variable.
 327     void encrypt(Authenticator authenticator,
 328             CipherBox encCipher, byte contentType, int headerSize) {
 329 
 330         int position = headerSize + writeCipher.getExplicitNonceSize();
 331 
 332         // "flip" but skip over header again, add MAC & encrypt
 333         int macLen = 0;
 334         if (authenticator instanceof MAC) {
 335             MAC signer = (MAC)authenticator;
 336             macLen = signer.MAClen();
 337             if (macLen != 0) {
 338                 byte[] hash = signer.compute(contentType,
 339                         buf, position, (count - position), false);
 340 
 341                 write(hash, 0, hash.length);
 342             }
 343         }
 344 






 345         if (!encCipher.isNullCipher()) {
 346             // Requires explicit IV/nonce for CBC/AEAD cipher suites for
 347             // TLS 1.1 or later.
 348             if (protocolVersion.useTLS11PlusSpec() &&
 349                     (encCipher.isCBCMode() || encCipher.isAEADMode())) {
 350 
 351                 byte[] nonce = encCipher.createExplicitNonce(
 352                         authenticator, contentType, (count - position));
 353                 int noncePos = position - nonce.length;
 354                 System.arraycopy(nonce, 0, buf, noncePos, nonce.length);
 355             }
 356 
 357             if (!encCipher.isAEADMode()) {
 358                 // The explicit IV in TLS 1.1 and later can be encrypted.
 359                 position = headerSize;
 360             }   // Otherwise, DON'T encrypt the nonce_explicit for AEAD mode
 361 
 362             // increase buf capacity if necessary
 363             int fragSize = count - position;
 364             int packetSize =
 365                     encCipher.calculatePacketSize(fragSize, macLen, headerSize);
 366             if (packetSize > (buf.length - position)) {
 367                 byte[] newBuf = new byte[position + packetSize];
 368                 System.arraycopy(buf, 0, newBuf, 0, count);
 369                 buf = newBuf;
 370             }
 371 
 372             // Encrypt may pad, so again the count may be changed.
 373             count = position +
 374                     encCipher.encrypt(buf, position, (count - position));

































 375         }


 376 
 377         // Fill out the header, write it and the message.
 378         int fragLen = count - headerSize;
 379         buf[0] = contentType;
 380         buf[1] = protocolVersion.major;
 381         buf[2] = protocolVersion.minor;
 382         buf[3] = (byte)((fragLen >> 8) & 0xFF);
 383         buf[4] = (byte)(fragLen & 0xFF);


 384     }
 385 
 386     static ByteBuffer encodeV2ClientHello(
 387             byte[] fragment, int offset, int length) throws IOException {
 388 
 389         int v3SessIdLenOffset = offset + 34;      //  2: client_version
 390                                                   // 32: random
 391 
 392         int v3SessIdLen = fragment[v3SessIdLenOffset];
 393         int v3CSLenOffset = v3SessIdLenOffset + 1 + v3SessIdLen;
 394         int v3CSLen = ((fragment[v3CSLenOffset] & 0xff) << 8) +
 395                        (fragment[v3CSLenOffset + 1] & 0xff);
 396         int cipherSpecs = v3CSLen / 2;        // 2: cipher spec size
 397 
 398         // Estimate the max V2ClientHello message length
 399         //
 400         // 11: header size
 401         // (cipherSpecs * 6): cipher_specs
 402         //    6: one cipher suite may need 6 bytes, see V3toV2CipherSuite.
 403         // 3: placeholder for the TLS_EMPTY_RENEGOTIATION_INFO_SCSV
 404         //    signaling cipher suite
 405         // 32: challenge size
 406         int v2MaxMsgLen = 11 + (cipherSpecs * 6) + 3 + 32;
 407 
 408         // Create a ByteBuffer backed by an accessible byte array.


 432             }
 433         }
 434 
 435         if (!containsRenegoInfoSCSV) {
 436             v2CSLen += V3toV2CipherSuite(dstBuf, (byte)0x00, (byte)0xFF);
 437         }
 438 
 439         /*
 440          * Copy in the nonce.
 441          */
 442         dstBuf.put(fragment, (offset + 2), 32);
 443 
 444         /*
 445          * Build the first part of the V3 record header from the V2 one
 446          * that's now buffered up.  (Lengths are fixed up later).
 447          */
 448         int msgLen = dstBuf.position() - 2;   // Exclude the legth field itself
 449         dstBuf.position(0);
 450         dstBuf.put((byte)(0x80 | ((msgLen >>> 8) & 0xFF)));  // pos: 0
 451         dstBuf.put((byte)(msgLen & 0xFF));                   // pos: 1
 452         dstBuf.put(HandshakeMessage.ht_client_hello);        // pos: 2
 453         dstBuf.put(fragment[offset]);         // major version, pos: 3
 454         dstBuf.put(fragment[offset + 1]);     // minor version, pos: 4
 455         dstBuf.put((byte)(v2CSLen >>> 8));                   // pos: 5
 456         dstBuf.put((byte)(v2CSLen & 0xFF));                  // pos: 6
 457         dstBuf.put((byte)0x00);           // session_id_length, pos: 7
 458         dstBuf.put((byte)0x00);                              // pos: 8
 459         dstBuf.put((byte)0x00);           // challenge_length,  pos: 9
 460         dstBuf.put((byte)32);                                // pos: 10
 461 
 462         dstBuf.position(0);
 463         dstBuf.limit(msgLen + 2);
 464 
 465         return dstBuf;
 466     }
 467 
 468     private static int V3toV2CipherSuite(ByteBuffer dstBuf,
 469             byte byte1, byte byte2) {
 470         dstBuf.put((byte)0);
 471         dstBuf.put(byte1);
 472         dstBuf.put(byte2);
   1 /*
   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.
   4  *
   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
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package sun.security.ssl;
  27 
  28 import java.io.ByteArrayOutputStream;
  29 import java.io.Closeable;
  30 import java.io.IOException;
  31 import java.io.OutputStream;
  32 import java.nio.ByteBuffer;
  33 import sun.security.ssl.SSLCipher.SSLWriteCipher;

  34 
  35 /**
  36  * {@code OutputRecord} takes care of the management of SSL/(D)TLS
  37  * output records, including buffering, encryption, handshake
  38  * messages marshal, etc.
  39  *
  40  * @author David Brownell
  41  */
  42 abstract class OutputRecord
  43         extends ByteArrayOutputStream implements Record, Closeable {
  44     SSLWriteCipher              writeCipher;
  45     // Needed for KeyUpdate
  46     TransportContext            tc;



  47 
  48     final HandshakeHash         handshakeHash;
  49     boolean                     firstMessage;
  50 
  51     // current protocol version, sent as record version
  52     ProtocolVersion             protocolVersion;
  53 
  54     // version for the ClientHello message. Only relevant if this is a
  55     // client handshake record. If set to ProtocolVersion.SSL20Hello,
  56     // the V3 client hello is converted to V2 format.
  57     ProtocolVersion             helloVersion;
  58 
  59     // Is it the first application record to write?
  60     boolean                     isFirstAppOutputRecord = true;
  61 
  62     // packet size
  63     int                         packetSize;
  64 
  65     // fragment size
  66     int                         fragmentSize;
  67 
  68     // closed or not?
  69     boolean                     isClosed;
  70 
  71     /*
  72      * Mappings from V3 cipher suite encodings to their pure V2 equivalents.
  73      * This is taken from the SSL V3 specification, Appendix E.
  74      */
  75     private static final int[] V3toV2CipherMap1 =
  76         {-1, -1, -1, 0x02, 0x01, -1, 0x04, 0x05, -1, 0x06, 0x07};
  77     private static final int[] V3toV2CipherMap3 =
  78         {-1, -1, -1, 0x80, 0x80, -1, 0x80, 0x80, -1, 0x40, 0xC0};
  79 
  80     OutputRecord(HandshakeHash handshakeHash, SSLWriteCipher writeCipher) {
  81         this.writeCipher = writeCipher;
  82         this.firstMessage = true;
  83         this.fragmentSize = Record.maxDataSize;
  84 
  85         this.handshakeHash = handshakeHash;
  86 
  87         // Please set packetSize and protocolVersion in the implementation.
  88     }
  89 
  90     void setVersion(ProtocolVersion protocolVersion) {
  91         this.protocolVersion = protocolVersion;
  92     }
  93 
  94     /*
  95      * Updates helloVersion of this record.
  96      */
  97     synchronized void setHelloVersion(ProtocolVersion helloVersion) {
  98         this.helloVersion = helloVersion;
  99     }
 100 
 101     /*









 102      * Return true iff the record is empty -- to avoid doing the work
 103      * of sending empty records over the network.
 104      */
 105     boolean isEmpty() {
 106         return false;
 107     }
 108 
 109     boolean seqNumIsHuge() {
 110         return (writeCipher.authenticator != null) &&
 111                         writeCipher.authenticator.seqNumIsHuge();
 112     }
 113 
 114     // SSLEngine and SSLSocket
 115     abstract void encodeAlert(byte level, byte description) throws IOException;
 116 
 117     // SSLEngine and SSLSocket
 118     abstract void encodeHandshake(byte[] buffer,
 119             int offset, int length) throws IOException;
 120 
 121     // SSLEngine and SSLSocket
 122     abstract void encodeChangeCipherSpec() throws IOException;
 123 
 124     // apply to SSLEngine only
 125     Ciphertext encode(
 126         ByteBuffer[] srcs, int srcsOffset, int srcsLength,
 127         ByteBuffer[] dsts, int dstsOffset, int dstsLength) throws IOException {
 128 
 129         throw new UnsupportedOperationException();
 130     }
 131 
 132     // apply to SSLEngine only
 133     void encodeV2NoCipher() throws IOException {
 134         throw new UnsupportedOperationException();
 135     }
 136 
 137     // apply to SSLSocket only
 138     void deliver(
 139             byte[] source, int offset, int length) throws IOException {
 140         throw new UnsupportedOperationException();
 141     }
 142 
 143     // apply to SSLSocket only
 144     void setDeliverStream(OutputStream outputStream) {
 145         throw new UnsupportedOperationException();
 146     }
 147 
 148     void changeWriteCiphers(SSLWriteCipher writeCipher,
 149             boolean useChangeCipherSpec) throws IOException {
 150         if (useChangeCipherSpec) {





 151             encodeChangeCipherSpec();
 152         }
 153 
 154         /*
 155          * Dispose of any intermediate state in the underlying cipher.
 156          * For PKCS11 ciphers, this will release any attached sessions,
 157          * and thus make finalization faster.
 158          *
 159          * Since MAC's doFinal() is called for every SSL/TLS packet, it's
 160          * not necessary to do the same with MAC's.
 161          */
 162         writeCipher.dispose();
 163 

 164         this.writeCipher = writeCipher;
 165         this.isFirstAppOutputRecord = true;
 166     }
 167 
 168     void changePacketSize(int packetSize) {
 169         this.packetSize = packetSize;
 170     }
 171 
 172     void changeFragmentSize(int fragmentSize) {
 173         this.fragmentSize = fragmentSize;
 174     }
 175 
 176     int getMaxPacketSize() {
 177         return packetSize;
 178     }
 179 
 180     // apply to DTLS SSLEngine
 181     void initHandshaker() {
 182         // blank
 183     }
 184 
 185     // apply to DTLS SSLEngine
 186     void finishHandshake() {
 187         // blank
 188     }
 189 
 190     // apply to DTLS SSLEngine
 191     void launchRetransmission() {
 192         // blank
 193     }
 194 
 195     @Override
 196     public synchronized void close() throws IOException {
 197         if (!isClosed) {
 198             isClosed = true;
 199             writeCipher.dispose();
 200         }
 201     }
 202 
 203     synchronized boolean isClosed() {
 204         return isClosed;
 205     }
 206 
 207     //
 208     // shared helpers
 209     //
 210 
 211     // Encrypt a fragment and wrap up a record.
 212     //
 213     // To be consistent with the spec of SSLEngine.wrap() methods, the
 214     // destination ByteBuffer's position is updated to reflect the amount
 215     // of data produced.  The limit remains the same.
 216     static long encrypt(
 217             SSLWriteCipher encCipher, byte contentType, ByteBuffer destination,
 218             int headerOffset, int dstLim, int headerSize,
 219             ProtocolVersion protocolVersion) {
 220         boolean isDTLS = protocolVersion.isDTLS;




 221         if (isDTLS) {
 222             if (protocolVersion.useTLS13PlusSpec()) {
 223                 return d13Encrypt(encCipher,
 224                         contentType, destination, headerOffset,
 225                         dstLim, headerSize, protocolVersion);
 226             } else {
 227                 return d10Encrypt(encCipher,
 228                         contentType, destination, headerOffset,
 229                         dstLim, headerSize, protocolVersion);
 230             }
 231         } else {
 232             if (protocolVersion.useTLS13PlusSpec()) {
 233                 return t13Encrypt(encCipher,
 234                         contentType, destination, headerOffset,
 235                         dstLim, headerSize, protocolVersion);
 236             } else {
 237                 return t10Encrypt(encCipher,
 238                         contentType, destination, headerOffset,
 239                         dstLim, headerSize, protocolVersion);


















 240             }
 241         }
 242     }
 243 
 244     static long d13Encrypt(
 245             SSLWriteCipher encCipher, byte contentType, ByteBuffer destination,
 246             int headerOffset, int dstLim, int headerSize,
 247             ProtocolVersion protocolVersion) {
 248         throw new UnsupportedOperationException("Not supported yet.");

















 249     }
 250 
 251     private static long d10Encrypt(
 252             SSLWriteCipher encCipher, byte contentType, ByteBuffer destination,
 253             int headerOffset, int dstLim, int headerSize,
 254             ProtocolVersion protocolVersion) {
 255         byte[] sequenceNumber = encCipher.authenticator.sequenceNumber();
 256         encCipher.encrypt(contentType, destination);
 257 
 258         // Finish out the record header.
 259         int fragLen = destination.limit() - headerOffset - headerSize;
 260 
 261         destination.put(headerOffset, contentType);         // content type
 262         destination.put(headerOffset + 1, protocolVersion.major);
 263         destination.put(headerOffset + 2, protocolVersion.minor);
 264 




 265         // epoch and sequence_number
 266         destination.put(headerOffset + 3, sequenceNumber[0]);
 267         destination.put(headerOffset + 4, sequenceNumber[1]);
 268         destination.put(headerOffset + 5, sequenceNumber[2]);
 269         destination.put(headerOffset + 6, sequenceNumber[3]);
 270         destination.put(headerOffset + 7, sequenceNumber[4]);
 271         destination.put(headerOffset + 8, sequenceNumber[5]);
 272         destination.put(headerOffset + 9, sequenceNumber[6]);
 273         destination.put(headerOffset + 10, sequenceNumber[7]);
 274 
 275         // fragment length
 276         destination.put(headerOffset + 11, (byte)(fragLen >> 8));
 277         destination.put(headerOffset + 12, (byte)fragLen);
 278 
 279         // Update destination position to reflect the amount of data produced.
 280         destination.position(destination.limit());
 281 
 282         return Authenticator.toLong(sequenceNumber);
 283     }
 284 
 285     static long t13Encrypt(
 286             SSLWriteCipher encCipher, byte contentType, ByteBuffer destination,
 287             int headerOffset, int dstLim, int headerSize,
 288             ProtocolVersion protocolVersion) {
 289         if (!encCipher.isNullCipher()) {
 290             // inner plaintext, using zero length padding.
 291             int pos = destination.position();
 292             destination.position(destination.limit());
 293             destination.limit(destination.limit() + 1);
 294             destination.put(contentType);
 295             destination.position(pos);
 296         }
 297 
 298         // use the right TLSCiphertext.opaque_type and legacy_record_version
 299         ProtocolVersion pv = protocolVersion;
 300         if (!encCipher.isNullCipher()) {
 301             pv = ProtocolVersion.TLS12;
 302             contentType = ContentType.APPLICATION_DATA.id;
 303         } else if (protocolVersion.useTLS13PlusSpec()) {
 304             pv = ProtocolVersion.TLS12;
 305         }
 306 
 307         byte[] sequenceNumber = encCipher.authenticator.sequenceNumber();
 308         encCipher.encrypt(contentType, destination);
 309 
 310         // Finish out the record header.
 311         int fragLen = destination.limit() - headerOffset - headerSize;
 312         destination.put(headerOffset, contentType);
 313         destination.put(headerOffset + 1, pv.major);
 314         destination.put(headerOffset + 2, pv.minor);
 315 
 316         // fragment length
 317         destination.put(headerOffset + 3, (byte)(fragLen >> 8));
 318         destination.put(headerOffset + 4, (byte)fragLen);
 319 
 320         // Update destination position to reflect the amount of data produced.
 321         destination.position(destination.limit());
 322 
 323         return Authenticator.toLong(sequenceNumber);
 324     }
 325 
 326     static long t10Encrypt(
 327             SSLWriteCipher encCipher, byte contentType, ByteBuffer destination,
 328             int headerOffset, int dstLim, int headerSize,
 329             ProtocolVersion protocolVersion) {
 330         byte[] sequenceNumber = encCipher.authenticator.sequenceNumber();
 331         encCipher.encrypt(contentType, destination);
 332 
 333         // Finish out the record header.
 334         int fragLen = destination.limit() - headerOffset - headerSize;
 335 
 336         destination.put(headerOffset, contentType);         // content type
 337         destination.put(headerOffset + 1, protocolVersion.major);
 338         destination.put(headerOffset + 2, protocolVersion.minor);
 339 
 340         // fragment length
 341         destination.put(headerOffset + 3, (byte)(fragLen >> 8));
 342         destination.put(headerOffset + 4, (byte)fragLen);
 343 
 344         // Update destination position to reflect the amount of data produced.
 345         destination.position(destination.limit());
 346 
 347         return Authenticator.toLong(sequenceNumber);
 348     }
 349 
 350     // Encrypt a fragment and wrap up a record.
 351     //
 352     // Uses the internal expandable buf variable and the current
 353     // protocolVersion variable.
 354     long encrypt(
 355             SSLWriteCipher encCipher, byte contentType, int headerSize) {
 356         if (protocolVersion.useTLS13PlusSpec()) {
 357             return t13Encrypt(encCipher, contentType, headerSize);
 358         } else {
 359             return t10Encrypt(encCipher, contentType, headerSize);









 360         }
 361     }
 362 
 363     private static final class T13PaddingHolder {
 364         private static final byte[] zeros = new byte[16];
 365     }
 366 
 367     long t13Encrypt(
 368             SSLWriteCipher encCipher, byte contentType, int headerSize) {
 369         if (!encCipher.isNullCipher()) {
 370             // inner plaintext
 371             write(contentType);
 372             write(T13PaddingHolder.zeros, 0, T13PaddingHolder.zeros.length);
 373         }
 374 
 375         byte[] sequenceNumber = encCipher.authenticator.sequenceNumber();
 376         int position = headerSize;
 377         int contentLen = count - position;
 378 
 379         // ensure the capacity
 380         int packetSize = encCipher.calculatePacketSize(contentLen, headerSize);
 381         if (packetSize > buf.length) {
 382             byte[] newBuf = new byte[packetSize];









 383             System.arraycopy(buf, 0, newBuf, 0, count);
 384             buf = newBuf;
 385         }
 386 
 387         // use the right TLSCiphertext.opaque_type and legacy_record_version
 388         ProtocolVersion pv = protocolVersion;
 389         if (!encCipher.isNullCipher()) {
 390             pv = ProtocolVersion.TLS12;
 391             contentType = ContentType.APPLICATION_DATA.id;
 392         } else {
 393             pv = ProtocolVersion.TLS12;
 394         }
 395 
 396         ByteBuffer destination = ByteBuffer.wrap(buf, position, contentLen);
 397         count = headerSize + encCipher.encrypt(contentType, destination);
 398 
 399         // Fill out the header, write it and the message.
 400         int fragLen = count - headerSize;
 401 
 402         buf[0] = contentType;
 403         buf[1] = pv.major;
 404         buf[2] = pv.minor;
 405         buf[3] = (byte)((fragLen >> 8) & 0xFF);
 406         buf[4] = (byte)(fragLen & 0xFF);
 407 
 408         return Authenticator.toLong(sequenceNumber);
 409     }
 410 
 411     long t10Encrypt(
 412             SSLWriteCipher encCipher, byte contentType, int headerSize) {
 413         byte[] sequenceNumber = encCipher.authenticator.sequenceNumber();
 414         int position = headerSize + writeCipher.getExplicitNonceSize();
 415         int contentLen = count - position;
 416 
 417         // ensure the capacity
 418         int packetSize = encCipher.calculatePacketSize(contentLen, headerSize);
 419         if (packetSize > buf.length) {
 420             byte[] newBuf = new byte[packetSize];
 421             System.arraycopy(buf, 0, newBuf, 0, count);
 422             buf = newBuf;
 423         }
 424         ByteBuffer destination = ByteBuffer.wrap(buf, position, contentLen);
 425         count = headerSize + encCipher.encrypt(contentType, destination);
 426 
 427         // Fill out the header, write it and the message.
 428         int fragLen = count - headerSize;
 429         buf[0] = contentType;
 430         buf[1] = protocolVersion.major;
 431         buf[2] = protocolVersion.minor;
 432         buf[3] = (byte)((fragLen >> 8) & 0xFF);
 433         buf[4] = (byte)(fragLen & 0xFF);
 434 
 435         return Authenticator.toLong(sequenceNumber);
 436     }
 437 
 438     static ByteBuffer encodeV2ClientHello(
 439             byte[] fragment, int offset, int length) throws IOException {

 440         int v3SessIdLenOffset = offset + 34;      //  2: client_version
 441                                                   // 32: random
 442 
 443         int v3SessIdLen = fragment[v3SessIdLenOffset];
 444         int v3CSLenOffset = v3SessIdLenOffset + 1 + v3SessIdLen;
 445         int v3CSLen = ((fragment[v3CSLenOffset] & 0xff) << 8) +
 446                        (fragment[v3CSLenOffset + 1] & 0xff);
 447         int cipherSpecs = v3CSLen / 2;        // 2: cipher spec size
 448 
 449         // Estimate the max V2ClientHello message length
 450         //
 451         // 11: header size
 452         // (cipherSpecs * 6): cipher_specs
 453         //    6: one cipher suite may need 6 bytes, see V3toV2CipherSuite.
 454         // 3: placeholder for the TLS_EMPTY_RENEGOTIATION_INFO_SCSV
 455         //    signaling cipher suite
 456         // 32: challenge size
 457         int v2MaxMsgLen = 11 + (cipherSpecs * 6) + 3 + 32;
 458 
 459         // Create a ByteBuffer backed by an accessible byte array.


 483             }
 484         }
 485 
 486         if (!containsRenegoInfoSCSV) {
 487             v2CSLen += V3toV2CipherSuite(dstBuf, (byte)0x00, (byte)0xFF);
 488         }
 489 
 490         /*
 491          * Copy in the nonce.
 492          */
 493         dstBuf.put(fragment, (offset + 2), 32);
 494 
 495         /*
 496          * Build the first part of the V3 record header from the V2 one
 497          * that's now buffered up.  (Lengths are fixed up later).
 498          */
 499         int msgLen = dstBuf.position() - 2;   // Exclude the legth field itself
 500         dstBuf.position(0);
 501         dstBuf.put((byte)(0x80 | ((msgLen >>> 8) & 0xFF)));  // pos: 0
 502         dstBuf.put((byte)(msgLen & 0xFF));                   // pos: 1
 503         dstBuf.put(SSLHandshake.CLIENT_HELLO.id);            // pos: 2
 504         dstBuf.put(fragment[offset]);         // major version, pos: 3
 505         dstBuf.put(fragment[offset + 1]);     // minor version, pos: 4
 506         dstBuf.put((byte)(v2CSLen >>> 8));                   // pos: 5
 507         dstBuf.put((byte)(v2CSLen & 0xFF));                  // pos: 6
 508         dstBuf.put((byte)0x00);           // session_id_length, pos: 7
 509         dstBuf.put((byte)0x00);                              // pos: 8
 510         dstBuf.put((byte)0x00);           // challenge_length,  pos: 9
 511         dstBuf.put((byte)32);                                // pos: 10
 512 
 513         dstBuf.position(0);
 514         dstBuf.limit(msgLen + 2);
 515 
 516         return dstBuf;
 517     }
 518 
 519     private static int V3toV2CipherSuite(ByteBuffer dstBuf,
 520             byte byte1, byte byte2) {
 521         dstBuf.put((byte)0);
 522         dstBuf.put(byte1);
 523         dstBuf.put(byte2);
< prev index next >